/*
* Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores
* CA 94065 USA or visit www.oracle.com if you need additional information or
* have any questions.
*/
package com.sun.lwuit.awtport;
import com.sun.lwuit.Component;
import com.sun.lwuit.Display;
import com.sun.lwuit.Font;
import com.sun.lwuit.Form;
import com.sun.lwuit.impl.LWUITImplementation;
import java.awt.AlphaComposite;
import java.awt.Color;
import java.awt.Desktop;
import java.awt.Frame;
import java.awt.Graphics2D;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import java.awt.event.HierarchyBoundsListener;
import java.awt.event.HierarchyEvent;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.awt.event.WindowEvent;
import java.awt.event.WindowListener;
import java.awt.event.WindowStateListener;
import java.awt.font.FontRenderContext;
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.lang.ref.SoftReference;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URL;
import javax.imageio.ImageIO;
import javax.imageio.stream.MemoryCacheImageInputStream;
import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.Clip;
/**
* An implementation of LWUIT based on AWT
*
* @author Shai Almog
*/
public class AwtImpl extends LWUITImplementation {
private static int medianFontSize = 15;
private static int smallFontSize = 11;
private static int largeFontSize = 19;
private static boolean useNativeInput = true;
static final int GAME_KEY_CODE_FIRE = -90;
static final int GAME_KEY_CODE_UP = -91;
static final int GAME_KEY_CODE_DOWN = -92;
static final int GAME_KEY_CODE_LEFT = -93;
static final int GAME_KEY_CODE_RIGHT = -94;
private static int softkeyCount = 1;
private static boolean tablet;
private static String DEFAULT_FONT = "Arial-plain-11";
public static void setFontSize(int medium, int small, int large) {
medianFontSize = medium;
smallFontSize = small;
largeFontSize = large;
DEFAULT_FONT = "Arial-plain-" + medium;
}
/**
* @return the useNativeInput
*/
public static boolean isUseNativeInput() {
return useNativeInput;
}
/**
* @param aUseNativeInput the useNativeInput to set
*/
public static void setUseNativeInput(boolean aUseNativeInput) {
useNativeInput = aUseNativeInput;
}
/**
* @param aSoftkeyCount the softkeyCount to set
*/
public static void setSoftkeyCount(int aSoftkeyCount) {
softkeyCount = aSoftkeyCount;
}
private class C extends java.awt.Container implements KeyListener, MouseListener, MouseMotionListener, HierarchyBoundsListener {
private BufferedImage buffer;
boolean painted;
private Graphics2D g2dInstance;
C() {
addKeyListener(this);
addMouseListener(this);
addMouseMotionListener(this);
addHierarchyBoundsListener(this);
setFocusable(true);
requestFocus();
}
public boolean isDoubleBuffered() {
return true;
}
public boolean isOpaque() {
return true;
}
public void update(java.awt.Graphics g) {
paint(g);
}
public void blit() {
if(buffer != null) {
java.awt.Graphics g = getGraphics();
if(g == null) {
return;
}
g.drawImage(buffer, 0, 0, this);
java.awt.Dimension d = getSize();
if(buffer.getWidth() != d.width || buffer.getHeight() != d.height) {
buffer = createBufferedImage();
}
}
}
public void blit(int x, int y, int w, int h) {
if(buffer != null) {
java.awt.Graphics g = getGraphics();
if(g == null) {
return;
}
g.setClip(x, y, w, h);
getGraphics().drawImage(buffer, 0, 0, this);
java.awt.Dimension d = getSize();
if(buffer.getWidth() != d.width || buffer.getHeight() != d.height) {
buffer = createBufferedImage();
}
}
}
public void paint(java.awt.Graphics g) {
if(buffer != null) {
getGraphics().drawImage(buffer, 0, 0, this);
java.awt.Dimension d = getSize();
if(buffer.getWidth() != d.width || buffer.getHeight() != d.height) {
buffer = createBufferedImage();
}
}
}
public java.awt.Dimension getPreferredSize() {
Form f = Display.getInstance().getCurrent();
if(f != null) {
return new java.awt.Dimension(f.getPreferredW(), f.getPreferredH());
}
return new java.awt.Dimension(800, 480);
}
public FontRenderContext getFRC() {
return getGraphics2D().getFontRenderContext();
}
public Graphics2D getGraphics2D() {
if(buffer == null || buffer.getWidth() != getWidth() || buffer.getHeight() != getHeight()) {
buffer = createBufferedImage();
}
if(g2dInstance == null) {
g2dInstance = buffer.createGraphics();
}
return g2dInstance;
}
private BufferedImage createBufferedImage() {
g2dInstance = null;
return new BufferedImage(Math.max(20, getWidth()), Math.max(20, getHeight()), BufferedImage.TYPE_INT_RGB);
}
public void validate() {
super.validate();
java.awt.Dimension d = getPreferredSize();
if(buffer == null || d.width != buffer.getWidth() || d.height != buffer.getHeight()) {
buffer = createBufferedImage();
}
Form current = getCurrentForm();
if(current == null) {
return;
}
}
private int getCode(java.awt.event.KeyEvent evt) {
switch(evt.getKeyCode()) {
case KeyEvent.VK_UP:
return GAME_KEY_CODE_UP;
case KeyEvent.VK_DOWN:
return GAME_KEY_CODE_DOWN;
case KeyEvent.VK_LEFT:
return GAME_KEY_CODE_LEFT;
case KeyEvent.VK_RIGHT:
return GAME_KEY_CODE_RIGHT;
case KeyEvent.VK_SPACE:
case KeyEvent.VK_ENTER:
return GAME_KEY_CODE_FIRE;
}
return evt.getKeyCode();
}
public void keyTyped(KeyEvent e) {
}
public void keyPressed(KeyEvent e) {
// block key combos that might generate unreadable events
if(e.isAltDown() || e.isControlDown() || e.isMetaDown() || e.isAltGraphDown()) {
return;
}
AwtImpl.this.keyPressed(getCode(e));
}
public void keyReleased(KeyEvent e) {
// block key combos that might generate unreadable events
if(e.isAltDown() || e.isControlDown() || e.isMetaDown() || e.isAltGraphDown()) {
return;
}
AwtImpl.this.keyReleased(getCode(e));
}
public void mouseClicked(MouseEvent e) {
e.consume();
}
private int scaleCoordinate(int coordinate) {
return coordinate;
}
public void mousePressed(MouseEvent e) {
e.consume();
if((e.getModifiers() & MouseEvent.BUTTON1_MASK) != 0) {
AwtImpl.this.pointerPressed(scaleCoordinate(e.getX()), scaleCoordinate(e.getY()));
requestFocus();
}
}
public void mouseReleased(MouseEvent e) {
e.consume();
if((e.getModifiers() & MouseEvent.BUTTON1_MASK) != 0) {
AwtImpl.this.pointerReleased(scaleCoordinate(e.getX()), scaleCoordinate(e.getY()));
}
}
public void mouseEntered(MouseEvent e) {
e.consume();
}
public void mouseExited(MouseEvent e) {
e.consume();
}
public void mouseDragged(MouseEvent e) {
e.consume();
if((e.getModifiers() & MouseEvent.BUTTON1_MASK) != 0) {
AwtImpl.this.pointerDragged(scaleCoordinate(e.getX()), scaleCoordinate(e.getY()));
}
}
public void mouseMoved(MouseEvent e) {
e.consume();
}
public void ancestorMoved(HierarchyEvent e) {
}
public void ancestorResized(HierarchyEvent e) {
AwtImpl.this.sizeChanged(getWidth(), getHeight());
}
}
private C canvas;
public AwtImpl() {
canvas = new C();
}
public void paintDirty() {
super.paintDirty();
}
/**
* @inheritDoc
*/
public void deinitialize() {
if(canvas.getParent() != null) {
canvas.getParent().remove(canvas);
}
}
/**
* @inheritDoc
*/
public void init(Object m) {
if(canvas.getParent() != null) {
canvas.getParent().remove(canvas);
}
if(m != null && m instanceof java.awt.Container) {
java.awt.Container cnt = (java.awt.Container)m;
if(cnt.getLayout() instanceof java.awt.BorderLayout) {
cnt.add(java.awt.BorderLayout.CENTER, canvas);
} else {
cnt.add(canvas);
}
} else {
Frame frm = new Frame();
frm.setUndecorated(true);
frm.setLayout(new java.awt.BorderLayout());
frm.add(java.awt.BorderLayout.CENTER, canvas);
frm.addWindowListener(new WindowListener() {
public void windowOpened(WindowEvent e) {
}
public void windowClosing(WindowEvent e) {
Display.getInstance().exitApplication();
}
public void windowClosed(WindowEvent e) {
}
public void windowIconified(WindowEvent e) {
}
public void windowDeiconified(WindowEvent e) {
}
public void windowActivated(WindowEvent e) {
}
public void windowDeactivated(WindowEvent e) {
}
});
frm.pack();
frm.setExtendedState(Frame.MAXIMIZED_BOTH);
frm.setVisible(true);
}
if(useNativeInput) {
Display.getInstance().setDefaultVirtualKeyboard(null);
}
float factor = ((float)getDisplayHeight()) / 480.0f;
// set a reasonable default font size
setFontSize((int)(15.0f * factor), (int)(11.0f * factor), (int)(19.0f * factor));
}
/**
* @inheritDoc
*/
public void vibrate(int duration) {
}
/**
* @inheritDoc
*/
public void flashBacklight(int duration) {
}
/**
* @inheritDoc
*/
public int getDisplayWidth() {
int w = canvas.getWidth();
if(w < 10 && canvas.getParent() != null) {
return canvas.getParent().getWidth();
}
return Math.max(w, 100);
}
/**
* @inheritDoc
*/
public int getDisplayHeight() {
int h = canvas.getHeight();
if(h < 10 && canvas.getParent() != null) {
return canvas.getParent().getHeight();
}
return Math.max(h, 100);
}
/**
* Creates a soft/weak reference to an object that allows it to be collected
* yet caches it. This method is in the porting layer since CLDC only includes
* weak references while some platforms include nothing at all and some include
* the superior soft references.
*
* @param o object to cache
* @return a caching object or null if caching isn't supported
*/
public Object createSoftWeakRef(Object o) {
return new SoftReference(o);
}
/**
* Extracts the hard reference from the soft/weak reference given
*
* @param o the reference returned by createSoftWeakRef
* @return the original object submitted or null
*/
public Object extractHardRef(Object o) {
SoftReference w = (SoftReference)o;
if(w != null) {
return w.get();
}
return null;
}
/**
* @inheritDoc
*/
public boolean isNativeInputSupported() {
return useNativeInput;
}
/**
* @inheritDoc
*/
public void editString(final Component cmp, int maxSize, int constraint, String text, int keyCode) {
java.awt.TextComponent awtTf;
if(cmp instanceof com.sun.lwuit.TextField) {
awtTf = new java.awt.TextField();
} else {
awtTf = new java.awt.TextArea("",0 , 0, java.awt.TextArea.SCROLLBARS_NONE);
}
final java.awt.TextComponent tf =awtTf;
if(keyCode > 0) {
text += ((char)keyCode);
tf.setText(text);
tf.setCaretPosition(text.length());
} else {
tf.setText(text);
}
canvas.add(tf);
tf.setBounds(cmp.getAbsoluteX(), cmp.getAbsoluteY(), cmp.getWidth(), cmp.getHeight());
tf.requestFocus();
class Listener implements ActionListener, FocusListener, KeyListener {
public void actionPerformed(ActionEvent e) {
Display.getInstance().onEditingComplete(cmp, tf.getText());
if(tf instanceof java.awt.TextField) {
((java.awt.TextField)tf).removeActionListener(this);
}
tf.removeFocusListener(this);
canvas.remove(tf);
canvas.repaint();
}
public void focusGained(FocusEvent e) {
}
public void focusLost(FocusEvent e) {
actionPerformed(null);
}
public void keyTyped(KeyEvent e) {
}
public void keyPressed(KeyEvent e) {
}
public void keyReleased(KeyEvent e) {
if(e.getKeyCode() == KeyEvent.VK_DOWN) {
if(tf instanceof java.awt.TextField) {
actionPerformed(null);
} else {
if(tf.getCaretPosition() >= tf.getText().length() - 1) {
actionPerformed(null);
}
}
return;
}
if(e.getKeyCode() == KeyEvent.VK_UP) {
if(tf instanceof java.awt.TextField) {
actionPerformed(null);
} else {
if(tf.getCaretPosition() <= 2) {
actionPerformed(null);
}
}
return;
}
}
};
final Listener l = new Listener();
if(tf instanceof java.awt.TextField) {
((java.awt.TextField)tf).addActionListener(l);
}
tf.addKeyListener(l);
tf.addFocusListener(l);
}
/**
* @inheritDoc
*/
public void saveTextEditingState() {
}
/**
* @inheritDoc
*/
public void flushGraphics(int x, int y, int width, int height) {
canvas.blit(x, y, width, height);
}
/**
* @inheritDoc
*/
public void flushGraphics() {
canvas.blit();
}
/**
* @inheritDoc
*/
public void getRGB(Object nativeImage, int[] arr, int offset, int x, int y, int width, int height) {
((BufferedImage)nativeImage).getRGB(x, y, width, height, arr, offset, width);
}
/**
* @inheritDoc
*/
public Object createImage(int[] rgb, int width, int height) {
BufferedImage i = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
i.setRGB(0, 0, width, height, rgb, 0, width);
return i;
}
/**
* @inheritDoc
*/
public Object createImage(String path) throws IOException {
try {
InputStream i = getClass().getResourceAsStream(path);
// prevents a security exception due to a JDK bug which for some stupid reason chooses
// to create a temporary file in the spi of Image IO
return ImageIO.read(new MemoryCacheImageInputStream(i));
} catch(Throwable t) {
t.printStackTrace();
throw new IOException(t.toString());
}
}
/**
* @inheritDoc
*/
public Object createImage(InputStream i) throws IOException {
try {
return ImageIO.read(i);
} catch(Throwable t) {
t.printStackTrace();
throw new IOException(t.toString());
}
}
/**
* @inheritDoc
*/
public Object createMutableImage(int width, int height, int fillColor) {
int a = (fillColor >> 24) & 0xff;
if(a == 0xff) {
BufferedImage b = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
Graphics2D g = b.createGraphics();
g.setColor(new Color(fillColor));
g.fillRect(0, 0, width, height);
g.dispose();
return b;
}
BufferedImage b = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
if(a != 0) {
Graphics2D g = b.createGraphics();
g.setColor(new Color(fillColor));
g.fillRect(0, 0, width, height);
g.dispose();
}
return b;
}
/**
* @inheritDoc
*/
public boolean isAlphaMutableImageSupported() {
return true;
}
/**
* @inheritDoc
*/
public Object createImage(byte[] bytes, int offset, int len) {
try {
return ImageIO.read(new ByteArrayInputStream(bytes, offset, len));
} catch (IOException ex) {
// never happens
ex.printStackTrace();
return null;
}
}
/**
* @inheritDoc
*/
public int getImageWidth(Object i) {
return ((BufferedImage)i).getWidth();
}
/**
* @inheritDoc
*/
public int getImageHeight(Object i) {
return ((BufferedImage)i).getHeight();
}
/**
* @inheritDoc
*/
public Object scale(Object nativeImage, int width, int height) {
BufferedImage image = (BufferedImage)nativeImage;
int srcWidth = image.getWidth();
int srcHeight = image.getHeight();
// no need to scale
if(srcWidth == width && srcHeight == height){
return image;
}
int[] currentArray = new int[srcWidth];
int[] destinationArray = new int[width * height];
scaleArray(image, srcWidth, srcHeight, height, width, currentArray, destinationArray);
return createImage(destinationArray, width, height);
}
private void scaleArray(BufferedImage currentImage, int srcWidth, int srcHeight, int height, int width, int[] currentArray, int[] destinationArray) {
// Horizontal Resize
int yRatio = (srcHeight << 16) / height;
int xRatio = (srcWidth << 16) / width;
int xPos = xRatio / 2;
int yPos = yRatio / 2;
// if there is more than 16bit color there is no point in using mutable
// images since they won't save any memory
for (int y = 0; y < height; y++) {
int srcY = yPos >> 16;
getRGB(currentImage, currentArray, 0, 0, srcY, srcWidth, 1);
for (int x = 0; x < width; x++) {
int srcX = xPos >> 16;
int destPixel = x + y * width;
if ((destPixel >= 0 && destPixel < destinationArray.length) && (srcX < currentArray.length)) {
destinationArray[destPixel] = currentArray[srcX];
}
xPos += xRatio;
}
yPos += yRatio;
xPos = xRatio / 2;
}
}
private static int round(double d) {
double f = Math.floor(d);
double c = Math.ceil(d);
if(c - d < d - f) {
return (int)c;
}
return (int)f;
}
/**
* @inheritDoc
*/
public Object rotate(Object image, int degrees) {
int width = getImageWidth(image);
int height = getImageHeight(image);
int[] arr = new int[width * height];
int[] dest = new int[arr.length];
getRGB(image, arr, 0, 0, 0, width, height);
int centerX = width / 2;
int centerY = height / 2;
double radians = Math.toRadians(-degrees);
double cosDeg = Math.cos(radians);
double sinDeg = Math.sin(radians);
for(int x = 0 ; x < width ; x++) {
for(int y = 0 ; y < height ; y++) {
int x2 = round(cosDeg * (x - centerX) - sinDeg * (y - centerY) + centerX);
int y2 = round(sinDeg * (x - centerX) + cosDeg * (y - centerY) + centerY);
if(!(x2 < 0 || y2 < 0 || x2 >= width || y2 >= height)) {
int destOffset = x2 + y2 * width;
if(destOffset >= 0 && destOffset < dest.length) {
dest[x + y * width] = arr[destOffset];
}
}
}
}
return createImage(dest, width, height);
}
/**
* @inheritDoc
*/
public int getSoftkeyCount() {
return softkeyCount;
}
/**
* @inheritDoc
*/
public int[] getSoftkeyCode(int index) {
switch(softkeyCount) {
case 0:
return null;
case 2:
if(index == 0) {
return new int[] {KeyEvent.VK_F1};
} else {
return new int[] {KeyEvent.VK_F2};
}
default:
return new int[] {KeyEvent.VK_F1};
}
}
/**
* @inheritDoc
*/
public int getClearKeyCode() {
return KeyEvent.VK_DELETE;
}
/**
* @inheritDoc
*/
public int getBackspaceKeyCode() {
return KeyEvent.VK_BACK_SPACE;
}
/**
* @inheritDoc
*/
public int getBackKeyCode() {
return KeyEvent.VK_ESCAPE;
}
/**
* @inheritDoc
*/
public int getGameAction(int keyCode) {
switch(keyCode) {
case GAME_KEY_CODE_UP:
return Display.GAME_UP;
case GAME_KEY_CODE_DOWN:
return Display.GAME_DOWN;
case GAME_KEY_CODE_RIGHT:
return Display.GAME_RIGHT;
case GAME_KEY_CODE_LEFT:
return Display.GAME_LEFT;
case GAME_KEY_CODE_FIRE:
return Display.GAME_FIRE;
}
return 0;
}
/**
* @inheritDoc
*/
public int getKeyCode(int gameAction) {
switch(gameAction) {
case Display.GAME_UP:
return GAME_KEY_CODE_UP;
case Display.GAME_DOWN:
return GAME_KEY_CODE_DOWN;
case Display.GAME_RIGHT:
return GAME_KEY_CODE_RIGHT;
case Display.GAME_LEFT:
return GAME_KEY_CODE_LEFT;
case Display.GAME_FIRE:
return GAME_KEY_CODE_FIRE;
}
return 0;
}
/**
* @inheritDoc
*/
public boolean isTouchDevice() {
return true;
}
/**
* @inheritDoc
*/
public void setNativeFont(Object graphics, Object font) {
Graphics2D nativeGraphics = getGraphics(graphics);
nativeGraphics.setFont(font(font));
}
/**
* @inheritDoc
*/
public int getClipX(Object graphics) {
Graphics2D nativeGraphics = getGraphics(graphics);
java.awt.Rectangle r = nativeGraphics.getClipBounds();
if(r == null) {
return 0;
}
return r.x;
}
/**
* @inheritDoc
*/
public int getClipY(Object graphics) {
Graphics2D nativeGraphics = getGraphics(graphics);
java.awt.Rectangle r = nativeGraphics.getClipBounds();
if(r == null) {
return 0;
}
return r.y;
}
/**
* @inheritDoc
*/
public int getClipWidth(Object graphics) {
Graphics2D nativeGraphics = getGraphics(graphics);
java.awt.Rectangle r = nativeGraphics.getClipBounds();
if(r == null) {
if(graphics instanceof NativeScreenGraphics) {
NativeScreenGraphics ng = (NativeScreenGraphics)graphics;
if(ng.sourceImage != null) {
return ng.sourceImage.getWidth();
}
}
return getDisplayWidth();
}
return r.width;
}
/**
* @inheritDoc
*/
public int getClipHeight(Object graphics) {
Graphics2D nativeGraphics = getGraphics(graphics);
java.awt.Rectangle r = nativeGraphics.getClipBounds();
if(r == null) {
if(graphics instanceof NativeScreenGraphics) {
NativeScreenGraphics ng = (NativeScreenGraphics)graphics;
if(ng.sourceImage != null) {
return ng.sourceImage.getHeight();
}
}
return getDisplayHeight();
}
return r.height;
}
/**
* @inheritDoc
*/
public void setClip(Object graphics, int x, int y, int width, int height) {
Graphics2D nativeGraphics = getGraphics(graphics);
nativeGraphics.setClip(x, y, width, height);
}
/**
* @inheritDoc
*/
public void clipRect(Object graphics, int x, int y, int width, int height) {
Graphics2D nativeGraphics = getGraphics(graphics);
nativeGraphics.clipRect(x, y, width, height);
}
/**
* @inheritDoc
*/
public void drawLine(Object graphics, int x1, int y1, int x2, int y2) {
Graphics2D nativeGraphics = getGraphics(graphics);
nativeGraphics.drawLine(x1, y1, x2, y2);
}
/**
* @inheritDoc
*/
public void fillRect(Object graphics, int x, int y, int w, int h) {
Graphics2D nativeGraphics = getGraphics(graphics);
nativeGraphics.fillRect(x, y, w, h);
}
/**
* @inheritDoc
*/
public boolean isAlphaGlobal() {
return true;
}
/**
* @inheritDoc
*/
public void drawRect(Object graphics, int x, int y, int width, int height) {
Graphics2D nativeGraphics = getGraphics(graphics);
nativeGraphics.drawRect(x, y, width, height);
}
/**
* @inheritDoc
*/
public void drawRoundRect(Object graphics, int x, int y, int width, int height, int arcWidth, int arcHeight) {
Graphics2D nativeGraphics = getGraphics(graphics);
nativeGraphics.drawRoundRect(x, y, width, height, arcWidth, arcHeight);
}
/**
* @inheritDoc
*/
public void fillRoundRect(Object graphics, int x, int y, int width, int height, int arcWidth, int arcHeight) {
Graphics2D nativeGraphics = getGraphics(graphics);
nativeGraphics.fillRoundRect(x, y, width, height, arcWidth, arcHeight);
}
/**
* @inheritDoc
*/
public void fillArc(Object graphics, int x, int y, int width, int height, int startAngle, int arcAngle) {
Graphics2D nativeGraphics = getGraphics(graphics);
nativeGraphics.fillArc(x, y, width, height, startAngle, arcAngle);
}
/**
* @inheritDoc
*/
public void drawArc(Object graphics, int x, int y, int width, int height, int startAngle, int arcAngle) {
Graphics2D nativeGraphics = getGraphics(graphics);
nativeGraphics.drawArc(x, y, width, height, startAngle, arcAngle);
}
/**
* @inheritDoc
*/
public void setColor(Object graphics, int RGB) {
Graphics2D nativeGraphics = getGraphics(graphics);
nativeGraphics.setColor(new Color(RGB));
}
/**
* @inheritDoc
*/
public int getColor(Object graphics) {
Graphics2D nativeGraphics = getGraphics(graphics);
return nativeGraphics.getColor().getRGB();
}
/**
* @inheritDoc
*/
public void setAlpha(Object graphics, int alpha) {
Graphics2D nativeGraphics = getGraphics(graphics);
float a = ((float)alpha) / 255.0f;
nativeGraphics.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, a));
}
/**
* @inheritDoc
*/
public int getAlpha(Object graphics) {
Graphics2D nativeGraphics = getGraphics(graphics);
Object c = nativeGraphics.getComposite();
if(c != null && c instanceof AlphaComposite) {
return (int)(((AlphaComposite)c).getAlpha() * 255);
}
return 255;
}
/**
* @inheritDoc
*/
public void drawString(Object graphics, String str, int x, int y) {
Graphics2D nativeGraphics = getGraphics(graphics);
nativeGraphics.drawString(str, x, y + nativeGraphics.getFontMetrics().getAscent());
}
/**
* @inheritDoc
*/
public void drawImage(Object graphics, Object img, int x, int y) {
Graphics2D nativeGraphics = getGraphics(graphics);
nativeGraphics.drawImage((BufferedImage)img, x, y, null);
}
/**
* @inheritDoc
*/
public void fillTriangle(Object graphics, int x1, int y1, int x2, int y2, int x3, int y3) {
Graphics2D nativeGraphics = getGraphics(graphics);
nativeGraphics.fillPolygon(new int[] {x1, x2, x3}, new int[] {y1, y2, y3}, 3);
}
private BufferedImage cache;
/**
* @inheritDoc
*/
public void drawRGB(Object graphics, int[] rgbData, int offset, int x, int y, int w, int h, boolean processAlpha) {
Graphics2D nativeGraphics = getGraphics(graphics);
if(cache == null || cache.getWidth() != w || cache.getHeight() != h) {
cache = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB);
}
cache.setRGB(0, 0, w, h, rgbData, offset, w);
nativeGraphics.drawImage(cache, x, y, null);
}
/**
* @inheritDoc
*/
public Object getNativeGraphics() {
return new NativeScreenGraphics();
}
/**
* @inheritDoc
*/
public Object getNativeGraphics(Object image) {
/*NativeScreenGraphics n = new NativeScreenGraphics();
n.sourceImage = (BufferedImage)image;
return n;*/
return ((BufferedImage)image).getGraphics();
}
/**
* @inheritDoc
*/
public void translate(Object graphics, int x, int y) {
// does nothing, we expect translate to occur in the graphics for
// better device portability
}
/**
* @inheritDoc
*/
public int getTranslateX(Object graphics) {
return 0;
}
/**
* @inheritDoc
*/
public int getTranslateY(Object graphics) {
return 0;
}
/**
* @inheritDoc
*/
public int charsWidth(Object nativeFont, char[] ch, int offset, int length) {
return stringWidth(nativeFont, new String(ch, offset, length));
}
/**
* @inheritDoc
*/
public int stringWidth(Object nativeFont, String str) {
return (int)Math.ceil(font(nativeFont).getStringBounds(str, canvas.getFRC()).getWidth());
}
/**
* @inheritDoc
*/
public int charWidth(Object nativeFont, char ch) {
return (int)Math.ceil(font(nativeFont).getStringBounds("" + ch, canvas.getFRC()).getWidth());
}
/**
* @inheritDoc
*/
public int getHeight(Object nativeFont) {
return font(nativeFont).getSize() + 1;
}
/**
* @inheritDoc
*/
public Object createFont(int face, int style, int size) {
return new int[] {face, style, size};
}
private java.awt.Font createAWTFont(int[] i) {
int face = i[0];
int style = i[1];
int size = i[2];
String fontName;
switch(face) {
case Font.FACE_MONOSPACE:
fontName = "Monospaced-";
break;
case Font.FACE_PROPORTIONAL:
fontName = "SansSerif-";
break;
default: //Font.FACE_SYSTEM:
fontName = "Arial-";
break;
}
switch(style) {
case Font.STYLE_BOLD:
fontName += "bold-";
break;
case Font.STYLE_ITALIC:
fontName += "italic-";
break;
case Font.STYLE_PLAIN:
fontName += "plain-";
break;
case Font.STYLE_UNDERLINED:
// unsupported...
fontName += "plain-";
break;
default:
// probably bold/italic
fontName += "bold-";
break;
}
switch(size) {
case Font.SIZE_LARGE:
fontName += largeFontSize;
break;
case Font.SIZE_SMALL:
fontName += smallFontSize;
break;
default:
fontName += medianFontSize;
break;
}
return java.awt.Font.decode(fontName);
}
/**
* @inheritDoc
*/
public Object getDefaultFont() {
return DEFAULT_FONT;
}
/**
* @inheritDoc
*/
public int getFace(Object nativeFont) {
if(font(nativeFont).getFamily().equals("Monospaced")) {
return Font.FACE_MONOSPACE;
}
if(font(nativeFont).getFamily().equals("SansSerif")) {
return Font.FACE_PROPORTIONAL;
}
if(font(nativeFont).getFamily().equals("Arial")) {
return Font.FACE_SYSTEM;
}
return Font.FACE_SYSTEM;
}
/**
* @inheritDoc
*/
public int getSize(Object nativeFont) {
if(nativeFont == null) {
return Font.SIZE_MEDIUM;
}
if(nativeFont instanceof int[]) {
return ((int[])nativeFont)[2];
}
int size = font(nativeFont).getSize();
if(size == largeFontSize) {
return Font.SIZE_LARGE;
}
if(size == smallFontSize) {
return Font.SIZE_SMALL;
}
return Font.SIZE_MEDIUM;
}
/**
* @inheritDoc
*/
public int getStyle(Object nativeFont) {
if(font(nativeFont).isBold()) {
if(font(nativeFont).isItalic()) {
return Font.STYLE_BOLD | Font.STYLE_ITALIC;
} else {
return Font.STYLE_BOLD;
}
}
if(font(nativeFont).isItalic()) {
return Font.STYLE_ITALIC;
}
return Font.STYLE_PLAIN;
}
private java.awt.Font font(Object f) {
if(f == null) {
return java.awt.Font.decode(DEFAULT_FONT);
}
// for bitmap fonts
if(f instanceof java.awt.Font) {
return (java.awt.Font)f;
}
return createAWTFont((int[])f);
}
/**
* @inheritDoc
*/
public Object loadNativeFont(String lookup) {
return java.awt.Font.decode(lookup.split(";")[0]);
}
/**
* @inheritDoc
*/
public void fillPolygon(Object graphics, int[] xPoints, int[] yPoints, int nPoints) {
Graphics2D nativeGraphics = getGraphics(graphics);
nativeGraphics.fillPolygon(xPoints, yPoints, nPoints);
}
/**
* @inheritDoc
*/
public void drawPolygon(Object graphics, int[] xPoints, int[] yPoints, int nPoints) {
Graphics2D nativeGraphics = getGraphics(graphics);
nativeGraphics.drawPolygon(xPoints, yPoints, nPoints);
}
@Override
public boolean animateImage(Object nativeImage, long lastFrame) {
return false;
}
@Override
public Object createSVGImage(String baseURL, byte[] data) throws IOException {
return null;
}
@Override
public boolean isSVGSupported() {
return false;
}
/**
* @inheritDoc
*/
public Object getSVGDocument(Object svgImage) {
return svgImage;
}
/**
* @inheritDoc
*/
public void exitApplication() {
try {
System.exit(0);
} catch(Throwable t) {
System.out.println("Can't exit from applet");
}
}
/**
* @inheritDoc
*/
public String getProperty(String key, String defaultValue) {
if("OS".equals(key)) {
return "SE";
}
String s = System.getProperty(key);
if(s == null) {
return defaultValue;
}
return s;
}
/**
* @inheritDoc
*/
public void execute(String url) {
try {
Desktop.getDesktop().browse(new URI(url));
} catch (Exception ex) {
ex.printStackTrace();
}
}
private Graphics2D getGraphics(Object nativeG) {
if(nativeG instanceof Graphics2D) {
return (Graphics2D)nativeG;
}
NativeScreenGraphics ng = (NativeScreenGraphics)nativeG;
if(ng.sourceImage != null) {
return ng.sourceImage.createGraphics();
}
return canvas.getGraphics2D();
}
/**
* @inheritDoc
*/
protected void playNativeBuiltinSound(Object data) {
Toolkit.getDefaultToolkit().beep();
}
/**
* @inheritDoc
*/
public boolean isBuiltinSoundAvailable(String soundIdentifier) {
if(soundIdentifier.equals(Display.SOUND_TYPE_ALARM)) {
return true;
}
if(soundIdentifier.equals(Display.SOUND_TYPE_CONFIRMATION)) {
return true;
}
if(soundIdentifier.equals(Display.SOUND_TYPE_ERROR)) {
return true;
}
if(soundIdentifier.equals(Display.SOUND_TYPE_INFO)) {
return true;
}
if(soundIdentifier.equals(Display.SOUND_TYPE_WARNING)) {
return true;
}
return super.isBuiltinSoundAvailable(soundIdentifier);
}
/**
* @inheritDoc
*/
public Object createAudio(String uri, Runnable onCompletion) throws IOException {
return new AudioPlayer(uri, onCompletion);
}
/**
* @inheritDoc
*/
public Object createAudio(InputStream stream, String mimeType, Runnable onCompletion) throws IOException {
return new AudioPlayer(stream, onCompletion);
}
/**
* @inheritDoc
*/
public void cleanupAudio(Object handle) {
((AudioPlayer)handle).cleanupAudio();
}
/**
* @inheritDoc
*/
public void playAudio(Object handle) {
((AudioPlayer)handle).playAudio();
}
/**
* @inheritDoc
*/
public void pauseAudio(Object handle) {
((AudioPlayer)handle).pauseAudio();
}
/**
* @inheritDoc
*/
public int getAudioTime(Object handle) {
return ((AudioPlayer)handle).getAudioTime();
}
/**
* @inheritDoc
*/
public void setAudioTime(Object handle, int time) {
((AudioPlayer)handle).setAudioTime(time);
}
/**
* @inheritDoc
*/
public int getAudioDuration(Object handle) {
return ((AudioPlayer)handle).getAudioDuration();
}
/**
* @inheritDoc
*/
public void setVolume(int vol) {
}
/**
* @inheritDoc
*/
public int getVolume() {
return 100;
}
static class AudioPlayer {
private Clip c;
private Runnable onCompletion;
public AudioPlayer(String uri, Runnable onCompletion) throws IOException {
this.onCompletion = onCompletion;
AudioInputStream is = null;
try {
try {
is = AudioSystem.getAudioInputStream(new URL(uri));
} catch(MalformedURLException mal) {
is = AudioSystem.getAudioInputStream(new File(uri));
}
is = decode(is);
c = AudioSystem.getClip();
c.open(is);
} catch(IOException ioErr) {
throw ioErr;
} catch(RuntimeException re) {
throw re;
} catch (Exception ex) {
ex.printStackTrace();
throw new RuntimeException(ex);
}
}
private AudioInputStream decode(AudioInputStream in) {
AudioInputStream din = null;
AudioFormat baseFormat = in.getFormat();
AudioFormat decodedFormat = new AudioFormat(AudioFormat.Encoding.PCM_SIGNED,
baseFormat.getSampleRate(),
16,
baseFormat.getChannels(),
baseFormat.getChannels() * 2,
baseFormat.getSampleRate(),
false);
return AudioSystem.getAudioInputStream(decodedFormat, in);
}
public AudioPlayer(InputStream stream, Runnable onCompletion) throws IOException {
this.onCompletion = onCompletion;
try {
AudioInputStream is = AudioSystem.getAudioInputStream(stream);
is = decode(is);
c = AudioSystem.getClip();
c.open(is);
} catch(IOException ioErr) {
throw ioErr;
} catch(RuntimeException re) {
throw re;
} catch (Exception ex) {
ex.printStackTrace();
throw new RuntimeException(ex);
}
}
public void cleanupAudio() {
c.close();
}
public void playAudio() {
c.start();
}
public void pauseAudio() {
c.stop();
}
public int getAudioTime() {
return (int)(c.getMicrosecondPosition() / 1000);
}
public void setAudioTime(int time) {
if(c.isRunning()) {
c.stop();
c.setMicrosecondPosition(time * 1000);
c.start();
} else {
c.setMicrosecondPosition(time * 1000);
}
}
public int getAudioDuration() {
return (int)(c.getMicrosecondLength() / 1000);
}
public void setVolume(int vol) {
// ???
}
public int getVolume() {
return (int)(c.getLevel() * 100);
}
}
private class NativeScreenGraphics {
BufferedImage sourceImage;
Graphics2D cachedGraphics;
}
public boolean isAffineSupported() {
return true;
}
public void resetAffine(Object nativeGraphics) {
Graphics2D g = getGraphics(nativeGraphics);
g.setTransform(new AffineTransform());
}
public void scale(Object nativeGraphics, float x, float y) {
Graphics2D g = getGraphics(nativeGraphics);
g.scale(x, y);
}
public void rotate(Object nativeGraphics, float angle) {
Graphics2D g = getGraphics(nativeGraphics);
g.rotate(angle);
}
public void shear(Object nativeGraphics, float x, float y) {
Graphics2D g = getGraphics(nativeGraphics);
g.shear(x, y);
}
public boolean isTablet() {
return tablet;
}
public static void setTablet(boolean b) {
tablet = b;
}
}