diff --git a/README.md b/README.md index 8a2345588..95638b324 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ These notes are for Java developers who want to convert their Java applets or Java applications to -JavaScript, allowing continued one-source development of both Java and JavaScript. +JavaScript, allowing continued, simultaneous one-source development of both Java and JavaScript. Developers of java2script/SwingJS itself should read README-developers.md @@ -32,9 +32,9 @@ See https://github.com/BobHanson/java2script/tree/master/dist and the README fil https://github.com/BobHanson/java2script (development master) -Current development "Version 3 development master" involving a completely rewritten transpiler (2017) that nearly perfectly emulates the Java Virtual Machine, including fully qualified methods, compile-time method binding, generic methods and classes, Java reflection for efficient modular just-in-time class loading, Java Swing components, modal and nonmodel dialogs, audio, jpdf, the AWT event thread, and many other added packages. Java applications and applets can both be run in JavaScript in a browser. +Current development "Version 3 development master" involve a completely rewritten transpiler (2017) “CompilationParticipant†that follows the Eclipse Java compiler. The implementation nearly perfectly emulates the Java Virtual Machine. It includes fully qualified methods, compile-time method binding, generic methods and classes, Java 8 lambda functions and streams, Java reflection and dynamic class loading for efficient modular just-in-time performance, Java Swing components, modal and nonmodel dialogs, audio, jpdf, the AWT event thread, and many other added packages. Java applications and applets can both be run in JavaScript in any browser. -Version 3 also implements real-time creation of HTML test files for immediate JavaScript testing of any changes made to the Java code. Basically, when the source file is saveed in Eclipse, the JavaScript updates automatically, and a reload of the page in the browser shows the changes directly. This makes for very easy side-by-side Java and JavaScript debugging. +Version 3 also implements real-time creation of HTML test files for immediate JavaScript testing of any changes made to the Java code. Basically, when the source file is saved in Eclipse (Photon), the JavaScript updates automatically, and a reload of the page in the browser shows the changes immediately. This makes for very easy side-by-side Java and JavaScript debugging. Unlike Version 2, Version 3 requires minimal reworking of Java classes - primarily just for performance and threading* reasons, maximizing JavaScript performance without compromising any Java performance and making Java-to-JavaScript conversion almost trivial. (Of course, we are still finding occasional bugs in the transpiler and run-time "JavaScript-JVM.") @@ -52,7 +52,7 @@ Varna https://github.com/BobHanson/VARNA and https://chemapps.stolaf.edu/swingjs https://github.com/java2script/java2script (stable master) -Ported from SourceForge by Zhou Renjian, developed further by Zhou Renjian and Udo Borkowski (primariy) as "Version 2.0". +Ported from SourceForge by Zhou Renjian, developed further by Zhou Renjian and Udo Borkowski (primarily) as "Version 2.0". Extensively used by Bob Hanson in 2012-2016 for the conversion of Jmol/java to JSmol/javascript (http://jmol.sourceforge.net/), leading to extensive distribution and widespread use on the web. As of 3/2018, still the only known widely-available java2sript application. @@ -61,7 +61,7 @@ Developed further in 2016 by zhou Renjian, Udo Borkowski, Bob Hanson, Andrew Rad dubbed "SwingJS". Used by Bob Hanson during 11/2016 for conversion of the PhET gas applications applets. Version 2 allowed extensive development of JavaScript versions of Java applets, including JSmol, Falstad applets, and PhET applets. -However, this version did not produce "fully qualified" method signatures, resulting in error-prone and performance-reducing run-time binding of methods. Java class loading procedures were not consistent with the seqence of events used by the Java class loader, and parameter and array typing was minimal. Thus, while functional, Version 2 was not fully generalizable and required extensive reworking of Java code to be "java2script compliant." +However, this version did not produce "fully qualified" method signatures, resulting in error-prone and performance-reducing run-time binding of methods. Java class loading procedures were not consistent with the sequence of events used by the Java class loader, and parameter and array typing was minimal. Thus, while functional, Version 2 was not fully generalizable and required extensive reworking of Java code to be "java2script compliant." Synchronized with https://github.com/BobHanson/java2script as the stable master version in 2018. diff --git a/sources/net.sf.j2s.core/dist/swingjs/SwingJS-site.zip b/sources/net.sf.j2s.core/dist/swingjs/SwingJS-site.zip index a3a179840..2e3639400 100644 Binary files a/sources/net.sf.j2s.core/dist/swingjs/SwingJS-site.zip and b/sources/net.sf.j2s.core/dist/swingjs/SwingJS-site.zip differ diff --git a/sources/net.sf.j2s.core/dist/swingjs/timestamp b/sources/net.sf.j2s.core/dist/swingjs/timestamp index a12c008fa..13da06302 100644 --- a/sources/net.sf.j2s.core/dist/swingjs/timestamp +++ b/sources/net.sf.j2s.core/dist/swingjs/timestamp @@ -1 +1 @@ -20180917232142 +20180918115722 diff --git a/sources/net.sf.j2s.core/dist/swingjs/ver/3.2.2/SwingJS-site.zip b/sources/net.sf.j2s.core/dist/swingjs/ver/3.2.2/SwingJS-site.zip index a3a179840..2e3639400 100644 Binary files a/sources/net.sf.j2s.core/dist/swingjs/ver/3.2.2/SwingJS-site.zip and b/sources/net.sf.j2s.core/dist/swingjs/ver/3.2.2/SwingJS-site.zip differ diff --git a/sources/net.sf.j2s.core/dist/swingjs/ver/3.2.2/timestamp b/sources/net.sf.j2s.core/dist/swingjs/ver/3.2.2/timestamp index a12c008fa..13da06302 100644 --- a/sources/net.sf.j2s.core/dist/swingjs/ver/3.2.2/timestamp +++ b/sources/net.sf.j2s.core/dist/swingjs/ver/3.2.2/timestamp @@ -1 +1 @@ -20180917232142 +20180918115722 diff --git a/sources/net.sf.j2s.java.core/dist/SwingJS-site.zip b/sources/net.sf.j2s.java.core/dist/SwingJS-site.zip index a3a179840..2e3639400 100644 Binary files a/sources/net.sf.j2s.java.core/dist/SwingJS-site.zip and b/sources/net.sf.j2s.java.core/dist/SwingJS-site.zip differ diff --git a/sources/net.sf.j2s.java.core/src/swingjs/JSGraphics2D.java b/sources/net.sf.j2s.java.core/src/swingjs/JSGraphics2D.java index 9082de062..b172cabbf 100644 --- a/sources/net.sf.j2s.java.core/src/swingjs/JSGraphics2D.java +++ b/sources/net.sf.j2s.java.core/src/swingjs/JSGraphics2D.java @@ -1,1029 +1,1030 @@ -package swingjs; - -import java.awt.AlphaComposite; -import java.awt.BasicStroke; -import java.awt.Color; -import java.awt.Composite; -import java.awt.Font; -import java.awt.FontMetrics; -import java.awt.Graphics; -import java.awt.GraphicsConfiguration; -import java.awt.Image; -import java.awt.Paint; -import java.awt.Polygon; -import java.awt.Rectangle; -import java.awt.RenderingHints; -import java.awt.RenderingHints.Key; -import java.awt.Shape; -import java.awt.Stroke; -import java.awt.Toolkit; -import java.awt.font.FontRenderContext; -import java.awt.geom.AffineTransform; -import java.awt.geom.Path2D; -import java.awt.geom.PathIterator; -import java.awt.image.BufferedImage; -import java.awt.image.BufferedImageOp; -import java.awt.image.ImageObserver; -import java.awt.image.RenderedImage; -import java.awt.image.renderable.RenderableImage; -import java.text.AttributedCharacterIterator; -import java.util.Hashtable; -import java.util.Map; -import java.util.Map.Entry; - -import swingjs.api.js.DOMNode; -import swingjs.api.js.HTML5Canvas; -import swingjs.api.js.HTML5CanvasContext2D; - -// BH 6/2018 adds g.copyArea(x,y,width,height,dx,dy) - -/** - * generic 2D drawing methods -- JavaScript version - * - * @author Bob Hanson hansonr@stolaf.edu - */ - -@SuppressWarnings({ "rawtypes", "unchecked", "deprecation" }) -public class JSGraphics2D // extends SunGraphics2D - implements Cloneable { - - private boolean backgroundPainted; - - public int constrainX; - public int constrainY; - - private int width; - private int height; - private HTML5Canvas canvas; - - private HTML5CanvasContext2D ctx; - private GraphicsConfiguration gc; - - private BasicStroke currentStroke; - private Shape currentClip; - - private AlphaComposite currentComposite; - private int initialState; - - // public int strokeState; - // public int transformState; - // public int clipState; - - // public Color foregroundColor; - boolean isShifted;// private, but only JavaScript - private Font font; - - private RenderingHints hints; - - private AffineTransform transform; - - private Color backgroundColor; - - // private Color currentColor; - - public JSGraphics2D(Object canvas) { // this must be Object, because we are - // passing an actual HTML5 canvas - hints = new RenderingHints(new Hashtable()); - this.canvas = (HTML5Canvas) canvas; - ctx = this.canvas.getContext("2d"); -// removed - caused blurriness 9/17/2018 -// // reduce antialiasing, thank you, -// // http://www.rgraph.net/docs/howto-get-crisp-lines-with-no- antialias.html -// if (!isShifted) -// ctx.translate(-0.5, -0.5); -// isShifted = true; - transform = new AffineTransform(); - setStroke(new BasicStroke()); - /** - * @j2sNative - * - * this.gc = SwingJS; this.width = canvas.width; this.height = - * canvas.height; - * - */ - { - } - } - - /** - * the SwingJS object - */ - - public GraphicsConfiguration getDeviceConfiguration() { - return gc; - } - - public void drawLine(int x0, int y0, int x1, int y1) { - boolean inPath = this.inPath; - if (!inPath) - ctx.beginPath(); - ctx.moveTo(x0, y0); - ctx.lineTo(x1, y1); - if (!inPath) - ctx.stroke(); - } - - public void drawOval(int left, int top, int width, int height) { - if (width == height) - doCirc(left, top, width, false); - else - doArc(left, top, width, height, 0, 360, false); - } - - public void fillOval(int left, int top, int width, int height) { - if (width == height) - doCirc(left, top, width, true); - else - doArc(left, top, width, height, 0, 360, true); - } - - public void drawArc(int x, int y, int width, int height, int startAngle, int arcAngle) { - doArc(x, y, width, height, startAngle, arcAngle, false); - } - - public void fillArc(int centerX, int centerY, int width, int height, int startAngle, int arcAngle) { - doArc(centerX, centerY, width, height, startAngle, arcAngle, true); - } - - private void doCirc(int left, int top, int diameter, boolean fill) { - if (diameter <= 0) - return; - double r = diameter / 2f; - ctx.beginPath(); - ctx.arc(left + r, top + r, r, 0, 2 * Math.PI, false); - ctx.closePath(); - if (fill) - ctx.fill(); - else - ctx.stroke(); - } - - private void doArc(double x, double y, double width, double height, double startAngle, double arcAngle, - boolean fill) { - if (width <= 0 || height <= 0) - return; - // boolean doClose = (arcAngle - startAngle == 360); - ctx.save(); - { - if (arcAngle < 0) { - startAngle += arcAngle; - arcAngle = -arcAngle; - } - ctx.translate(x, y); - ctx.scale(width / 2, height / 2); - ctx.beginPath(); - ctx.arc(1, 1, 1, toRad(360 - startAngle), toRad(360 - arcAngle - startAngle), true); - if (fill) - ctx.lineTo(1, 1); - } - ctx.restore(); - if (fill) - ctx.fill(); - else - ctx.stroke(); - } - - private double toRad(double a) { - return a * (Math.PI / 180); - } - - public void background(Color bgcolor) { - backgroundColor = bgcolor; - if (bgcolor == null) { - return; - } - clearRect(0, 0, width, height); - } - - public void drawPolygon(Polygon p) { - doPoly(p.xpoints, p.ypoints, p.npoints, false); - } - - public void drawPolygon(int[] axPoints, int[] ayPoints, int nPoints) { - doPoly(axPoints, ayPoints, nPoints, false); - } - - /** - * @param axPoints - * @param ayPoints - * @param nPoints - * @param doFill - */ - private void doPoly(int[] axPoints, int[] ayPoints, int nPoints, boolean doFill) { - ctx.beginPath(); - ctx.moveTo(axPoints[0], ayPoints[0]); - for (int i = 1; i < nPoints; i++) - ctx.lineTo(axPoints[i], ayPoints[i]); - if (doFill) { - ctx.fill(); - } else { - ctx.lineTo(axPoints[0], ayPoints[0]); - ctx.stroke(); - } - } - - public void drawRect(int x, int y, int width, int height) { - if (width <= 0 || height <= 0) - return; - ctx.beginPath(); - ctx.rect(x, y, width, height); - ctx.stroke(); - } - - public void fillPolygon(Polygon p) { - doPoly(p.xpoints, p.ypoints, p.npoints, true); - } - - public void fillPolygon(int[] axPoints, int[] ayPoints, int nPoints) { - doPoly(axPoints, ayPoints, nPoints, true); - } - - public void fillRect(int x, int y, int width, int height) { - if (width <= 0 || height <= 0) - return; - backgroundPainted = true; - ctx.translate(0.5, 0.5); - ctx.fillRect(x, y, width, height); - ctx.translate(-0.5, -0.5); -// -// if (width == 1) -// drawLine(x, y, x, y + height); -// else if (height == 1) -// drawLine(x, y, x + width, y); -// else - } - - public void draw3DRect(int x, int y, int width, int height, boolean raised) { - do3DRect(x, y, width, height, raised, false); - } - - public void fill3DRect(int x, int y, int width, int height, boolean raised) { - do3DRect(x, y, width, height, raised, true); - } - - private void do3DRect(int x, int y, int width2, int height2, boolean raised, boolean isFill) { - if (width <= 0 || height <= 0) - return; - Paint p = getPaint(); - Color c = getColor(); - Color brighter = c.brighter(); - Color darker = c.darker(); - - if (!raised) { - setColor(darker); - } else if (p != c) { - setColor(c); - } - if (isFill) { - fillRect(x + 1, y + 1, width - 2, height - 2); - } - setColor(raised ? brighter : darker); - // drawLine(x, y, x, y + height - 1); - fillRect(x, y, 1, height); - // drawLine(x + 1, y, x + width - 2, y); - fillRect(x + 1, y, width - 2, 1); - setColor(raised ? darker : brighter); - // drawLine(x + 1, y + height - 1, x + width - 1, y + height - 1); - fillRect(x + 1, y + height - 1, width - 1, 1); - // drawLine(x + width - 1, y, x + width - 1, y + height - 2); - fillRect(x + width - 1, y, 1, height - 1); - setPaint(p); - } - - public void setFont(Font font) { - // this equality check speeds mark/reset significantly - if (font == this.font) - return; - this.font = font; - if (font != null) - HTML5CanvasContext2D.setFont(ctx, JSToolkit.getCanvasFont(font)); - } - - public void setStrokeBold(boolean tf) { - setLineWidth(tf ? 2. : 1.); - } - - private void setLineWidth(double d) { - HTML5CanvasContext2D.setLineWidth(ctx, d); - } - - public boolean canDoLineTo() { - return true; - } - - boolean inPath; - - private Color foregroundColor; - - public void doStroke(boolean isBegin) { - inPath = isBegin; - if (isBegin) { - ctx.beginPath(); - } else { - ctx.stroke(); - } - } - - public void lineTo(int x2, int y2) { - ctx.lineTo(x2, y2); - } - - public void clip(Shape s) { - doShape(s); - currentClip = s; - ctx.clip(); - } - - public void draw(Shape s) { - doShape(s); - ctx.stroke(); - } - - private int doShape(Shape s) { - ctx.beginPath(); - double[] pts = new double[6]; - PathIterator pi = s.getPathIterator(null); - while (!pi.isDone()) { - switch (pi.currentSegment(pts)) { - case PathIterator.SEG_MOVETO: - ctx.moveTo(pts[0], pts[1]); - break; - case PathIterator.SEG_LINETO: - ctx.lineTo(pts[0], pts[1]); - break; - case PathIterator.SEG_QUADTO: - ctx.quadraticCurveTo(pts[0], pts[1], pts[2], pts[3]); - break; - case PathIterator.SEG_CUBICTO: - ctx.bezierCurveTo(pts[0], pts[1], pts[2], pts[3], pts[4], pts[5]); - break; - case PathIterator.SEG_CLOSE: - ctx.closePath(); - break; - } - pi.next(); - } - return pi.getWindingRule(); - // then fill or stroke or clip - } - - public void fill(Shape s) { - if (doShape(s) == Path2D.WIND_EVEN_ODD) - /** - * @j2sNative - * - * this.ctx.fill("evenodd"); - */ - { - } else - ctx.fill(); - } - - public boolean drawImage(Image img, int x, int y, ImageObserver observer) { - return drawImagePriv(img, x, y, observer); - } - - public boolean drawImage(Image img, int x, int y, int width, int height, ImageObserver observer) { - if (width <= 0 || height <= 0) - return true; - backgroundPainted = true; - if (img != null) { - DOMNode imgNode = getImageNode(img); - if (imgNode != null) - ctx.drawImage(imgNode, x, y, width, height); - if (observer != null) - observe(img, observer, imgNode != null); - } - return true; - } - - private DOMNode getImageNode(Image img) { - backgroundPainted = true; - DOMNode imgNode = DOMNode.getImageNode(img); - return (imgNode == null ? JSGraphicsCompositor.createImageNode(img) : imgNode); - } - - private void observe(Image img, ImageObserver observer, boolean isOK) { - observer.imageUpdate(img, (isOK ? 0 : ImageObserver.ABORT | ImageObserver.ERROR), -1, -1, -1, -1); - } - - public boolean drawImage(Image img, int x, int y, Color bgcolor, ImageObserver observer) { - backgroundPainted = true; - JSUtil.notImplemented(null); - return drawImage(img, x, y, observer); - } - - public boolean drawImage(Image img, int x, int y, int width, int height, Color bgcolor, ImageObserver observer) { - if (width <= 0 || height <= 0) - return false; - backgroundPainted = true; - JSUtil.notImplemented(null); - return drawImage(img, x, y, width, height, observer); - } - - @SuppressWarnings("unused") - - public boolean drawImage(Image img, int dx1, int dy1, int dx2, int dy2, int sx1, int sy1, int sx2, int sy2, - ImageObserver observer) { - backgroundPainted = true; - if (img != null) { - byte[] bytes = null; - DOMNode imgNode = getImageNode(img); - if (imgNode != null) - HTML5CanvasContext2D.stretchImage(ctx, imgNode, sx1, sy1, sx2 - sx1, sy2 - sy1, dx1, dy1, dx2 - dx1, - dy2 - dy1); - if (observer != null) - observe(img, observer, imgNode != null); - } - return true; - } - - public boolean drawImage(Image img, int dx1, int dy1, int dx2, int dy2, int sx1, int sy1, int sx2, int sy2, - Color bgcolor, ImageObserver observer) { - JSUtil.notImplemented(null); - return drawImage(img, dx1, dy1, dx2, dy2, sx1, sy1, sx2, sy2, observer); - } - - public boolean drawImage(Image img, AffineTransform xform, ImageObserver obs) { - return drawImageXT(img, xform, obs); - } - - public void drawRenderedImage(RenderedImage img, AffineTransform xform) { - drawImageXT((Image) img, xform, null); - } - - public void drawRenderableImage(RenderableImage img, AffineTransform xform) { - drawImageXT((Image) img, xform, null); - } - - private boolean drawImageXT(Image img, AffineTransform xform, ImageObserver obs) { - ctx.save(); - transformCTX(xform); - boolean ret = drawImagePriv(img, 0, 0, obs); - ctx.restore(); - return ret; - } - - private Object imageData; - private int[] buf8; - private int lastx, lasty, nx, ny; - - @SuppressWarnings("unused") - public boolean drawImagePriv(Image img, int x, int y, ImageObserver observer) { - backgroundPainted = true; - if (img != null) { - int[] pixels = null; - boolean isRGB = false; // usually RGBA - /** - * @j2sNative - * - * pixels = img._pix; isRGB = (img.imageType == 1); - * - */ - DOMNode imgNode = null; - int width = ((BufferedImage) img).getRaster().getWidth(); - int height = ((BufferedImage) img).getRaster().getHeight(); - - - if (pixels == null) { - if ((imgNode = getImageNode(img)) != null) - ctx.drawImage(imgNode, x, y, width, height); - } else { - drawDirect(pixels, x, y, width, height, isRGB); - } - if (observer != null) - observe(img, observer, imgNode != null); - } - return true; - } - - public void drawDirectRGBA(int[] pixels) { - // this can go VERY fast - for writing directly to the canvas context - backgroundPainted = true; - drawDirect(pixels, 0, 0, width, height, false); - } - - private void drawDirect(int[] pixels, int x, int y, int width, int height, boolean isRGB) { - if (buf8 == null || x != lastx || y != lasty || nx != width || ny != height) { - imageData = HTML5CanvasContext2D.getImageData(ctx, x, y, width, height); - buf8 = HTML5CanvasContext2D.getBuf8(imageData); - lastx = x; - lasty = y; - nx = width; - ny = height; - } - for (int pt = 0, i = 0, n = Math.min(buf8.length / 4, pixels.length); i < n; i++) { - int argb = pixels[i]; - buf8[pt++] = (argb >> 16) & 0xFF; - buf8[pt++] = (argb >> 8) & 0xFF; - buf8[pt++] = argb & 0xFF; - buf8[pt++] = (isRGB ? 0xFF : (argb >> 24) & 0xFF); - } - HTML5CanvasContext2D.putImageData(ctx, imageData, x, y); - } - - public boolean hit(Rectangle rect, Shape s, boolean onStroke) { - JSUtil.notImplemented(null); - return false; - } - - public Stroke getStroke() { - return currentStroke; - } - - @SuppressWarnings("unused") - - public void setStroke(Stroke s) { - if (!(s instanceof BasicStroke)) - return; - BasicStroke b = currentStroke = (BasicStroke) s; - float[] dash = b.getDashArray(); - int[] idash = new int[dash == null ? 0 : dash.length]; - for (int i = idash.length; --i >= 0;) - idash[i] = (int) dash[i]; - ctx.setLineDash(idash); - setLineWidth(b.getLineWidth()); - String lineCap, lineJoin; - float miterLimit = -1; - switch (b.getEndCap()) { - case BasicStroke.CAP_BUTT: - lineCap = "butt"; - break; - case BasicStroke.CAP_SQUARE: - lineCap = "square"; - break; - case BasicStroke.CAP_ROUND: - default: - lineCap = "round"; - } - switch (b.getLineJoin()) { - case BasicStroke.JOIN_BEVEL: - lineJoin = "bevel"; - break; - case BasicStroke.JOIN_MITER: - lineJoin = "miter"; - miterLimit = b.getMiterLimit(); - break; - case BasicStroke.JOIN_ROUND: - lineJoin = "round"; - } - /** - * @j2sNative - * - * this.ctx.lineCap = lineCap; this.ctx.lineJoin = lineJoin; if - * (miterLimit >= 0) this.ctx.miterLimit = miterLimit; - */ - { - } - // SwingJS TODO more here - } - - public void setRenderingHint(Key hintKey, Object hintValue) { - hints.put(hintKey, hintValue); - } - - public Object getRenderingHint(Key hintKey) { - return hints.get(hintKey); - } - - public void setRenderingHints(Map hints) { - this.hints = new RenderingHints((Map) hints); - } - - public void addRenderingHints(Map hints) { - for (Entry e : hints.entrySet()) - this.hints.put(e.getKey(), e.getValue()); - } - - public RenderingHints getRenderingHints() { - return hints; - } - - public void setBackground(Color color) { - background(color); - } - - public Color getBackground() { - return backgroundColor; - } - - public Color getColor() { - return foregroundColor; - } - - public void setColor(Color c) { - foregroundColor = c; - setGraphicsColor(c); - } - - public void setPaint(Paint paint) { - setColor((Color) paint); - } - - public Font getFont() { - if (font == null) - font = new Font("Arial", Font.PLAIN, 12); - return font; - } - - public FontMetrics getFontMetrics() { - return getFontMetrics(getFont()); - } - - public FontMetrics getFontMetrics(Font f) { - return Toolkit.getDefaultToolkit().getFontMetrics(f); - } - - public void clipRect(int x, int y, int width, int height) { - // SwingJS -- this is not quite right. Should ADD this to the clipping - // region - ctx.beginPath(); - ctx.rect(x, y, width, height); - setCurrentClip(x, y, width, height); - ctx.clip(); - } - - public void setClip(int x, int y, int width, int height) { - // clipping is disabled because for general component painting - // because it consumes so much processing. - // it is presumed that the user will clip when desired - setCurrentClip(x, y, width, height); - ctx.beginPath(); - ctx.rect(x, y, width, height); - ctx.clip(); - } - - private void setCurrentClip(int x, int y, int width, int height) { - Rectangle r = (currentClip instanceof Rectangle ? (Rectangle) currentClip : null); - if (r == null || r.x != x || r.y != y || r.width != width || r.height != height) - currentClip = new Rectangle(x, y, width, height); - } - - public void setClip(Shape clip) { - currentClip = clip; - ctx.beginPath(); - doShape(clip); - ctx.clip(); - } - - public void clearRect(int x, int y, int width, int height) { - ctx.clearRect(x, y, width, height); - setGraphicsColor(backgroundColor == null ? Color.WHITE : backgroundColor); - fillRect(x, y, width, height); - setGraphicsColor(foregroundColor); - } - - private void setGraphicsColor(Color c) { - if (c == null) - return; // this was the case with a JRootPanel graphic call - HTML5CanvasContext2D.setColor(ctx, JSToolkit.getCSSColor(c)); - } - - public void copyArea(int x, int y, int width, int height, int dx, int dy) { - HTML5CanvasContext2D.putImageData(ctx, HTML5CanvasContext2D.getImageData(ctx, x, y, width, height), x + dx, - y + dy); - } - - public void drawPolyline(int[] xPoints, int[] yPoints, int nPoints) { - if (nPoints < 2) - return; - ctx.moveTo(xPoints[0], yPoints[0]); - for (int i = 1; i < nPoints; i++) { - ctx.lineTo(xPoints[i], yPoints[i]); - } - ctx.stroke(); - } - - public void drawRoundRect(int x, int y, int width, int height, int arcWidth, int arcHeight) { - JSUtil.notImplemented(null); - drawRect(x, y, width, height); - } - - public void fillRoundRect(int x, int y, int width, int height, int arcWidth, int arcHeight) { - JSUtil.notImplemented(null); - fillRect(x, y, width, height); - } - - public Shape getClip() { - return currentClip == null ? getClipBoundsImpl() : currentClip; - } - - public void drawString(String s, int x, int y) { - fillText(s, x, y); - } - - public void drawString(String str, float x, float y) { - fillText(str, x, y); - } - - private void fillText(String str, float x, float y) { - ctx.fillText(str, x, y); - } - - public void drawString(AttributedCharacterIterator iterator, int x, int y) { - JSUtil.notImplemented(null); - } - - public void drawString(AttributedCharacterIterator iterator, float x, float y) { - JSUtil.notImplemented(null); - } - - public void translate(double tx, double ty) { - JSUtil.notImplemented(null); - } - - public void shear(double shx, double shy) { - JSUtil.notImplemented(null); - } - - public void translate(int x, int y) { - ctx.translate(x, y); - transform.translate(x, y); - } - - public void rotate(double radians) { - ctx.rotate(radians); - transform.rotate(radians); - } - - public void rotate(double theta, double x, double y) { - ctx.translate(x, y); - ctx.rotate(theta); - ctx.translate(-x, -y); - transform.rotate(theta, x, y); - } - - public void scale(double sx, double sy) { - ctx.scale(sx, sy); - transform.scale(sx, sy); - } - - /** - * concatenates the given transform matrix to the current transform - * - */ - - public void transform(AffineTransform t) { - transformCTX(t); - transform.concatenate(t); - } - - private void transformCTX(AffineTransform t) { - /** - * @j2sNative - * - * this.ctx.transform (t.m00, t.m10, t.m01, t.m11, t.m02, t.m12); - */ - { - } - } - - /** - * sets the transform matrix to the given one - */ - - public void setTransform(AffineTransform t) { - /** - * @j2sNative - * - * this.ctx.setTransform (t.m00, t.m10, t.m01, t.m11, t.m02, t.m12); - * - * - */ - { - } - transform.setTransform(t); - } - - /** - * Returns a copy of the current transform - */ - - public AffineTransform getTransform() { - return (AffineTransform) transform.clone(); - } - - // /** - // * Returns the current Transform ignoring the "constrain" - // * rectangle. - // */ - // public AffineTransform cloneTransform() { - // return (AffineTransform) transform.clone(); - // } - // - - public Paint getPaint() { - return getColor(); - } - - public FontRenderContext getFontRenderContext() { - return getFontMetrics(getFont()).getFontRenderContext(); - } - - public void setPaintMode() { - setComposite(AlphaComposite.SrcOver); - } - - public void setXORMode(Color c) { - if (c == null) - throw new IllegalArgumentException("null XORColor"); - setComposite(AlphaComposite.Xor); - } - - public Rectangle getClipBounds() { - return getClipBounds(null); - } - - public Rectangle getClipBounds(Rectangle r) { - Rectangle clipRect = getClipBoundsImpl(); - if (r == null) { - r = clipRect; - } else { - r.x = clipRect.x; - r.y = clipRect.y; - r.width = clipRect.width; - r.height = clipRect.height; - } - return r; - } - - private Rectangle getClipBoundsImpl() { - if (currentClip == null) { - currentClip = new Rectangle(0, 0, width, height); - } - return currentClip.getBounds(); - } - - public void setComposite(Composite comp) { - // this equality check speeds mark/reset significantly - if (comp == this.currentComposite) - return; - // alpha composite only here - int newRule = 0; - boolean isValid = (comp == null || currentComposite == null || (comp instanceof AlphaComposite) - && (newRule = ((AlphaComposite) comp).getRule()) != currentComposite.getRule()); - if (isValid && JSGraphicsCompositor.setGraphicsCompositeAlpha(this, newRule)) { - currentComposite = (AlphaComposite) comp; - } - setAlpha(comp == null ? 1 : ((AlphaComposite) comp).getAlpha()); - } - - public Composite getComposite() { - return currentComposite; - } - - public void drawImage(BufferedImage img, BufferedImageOp op, int x, int y) { - JSGraphicsCompositor.drawImageOp(this, img, op, x, y); - } - - public void setAlpha(float f) { - /** - * @j2sNative - * - * this.ctx.globalAlpha = f; - */ - { - } - } - - public HTML5Canvas getCanvas() { - return canvas; - } - - /** - * used to determine if it is likely that the background was painted - * - * @return background taint count - */ - public boolean isBackgroundPainted() { - return backgroundPainted; - } - - /////////////// saving of the state //////////////// - - private final static int SAVE_ALPHA = 0; - private final static int SAVE_COMPOSITE = 1; - private final static int SAVE_STROKE = 2; - private final static int SAVE_TRANSFORM = 3; - private final static int SAVE_FONT = 4; - private final static int SAVE_CLIP = 5; - private final static int SAVE_BACKGROUND_PAINTED = 6; - private final static int SAVE_MAX = 7; - - /** - * creates a save object to extend the capabilities of context2d.save() that - * brings that into line with Java's graphics2d .create() - * - * in development -- we need to identify all differences - * - * - * @return the length of the ctx._aSaved array after the push - */ - public int mark() { - ctx.save(); - Object[] map = new Object[SAVE_MAX]; - - float alpha = 0; - /** - * @j2sNative - * - * alpha = this.ctx.globalAlpha; - * - */ - { - } - map[SAVE_ALPHA] = Float.valueOf(alpha); - map[SAVE_COMPOSITE] = currentComposite; - map[SAVE_STROKE] = currentStroke; - map[SAVE_TRANSFORM] = transform; - map[SAVE_FONT] = font; - map[SAVE_CLIP] = currentClip; - map[SAVE_BACKGROUND_PAINTED] = (backgroundPainted ? Boolean.TRUE : Boolean.FALSE); - backgroundPainted = false; - return HTML5CanvasContext2D.push(ctx, map); - } - - /** - * try to equate g.dispose() with ctx.restore(). - * - * @param n0 - */ - public void reset(int n0) { - if (n0 < 1) - n0 = 1; - while (HTML5CanvasContext2D.getSavedLevel(ctx) >= n0) { - Object[] map = HTML5CanvasContext2D.pop(ctx); - setComposite((Composite) map[SAVE_COMPOSITE]); - Float alpha = (Float) map[SAVE_ALPHA]; - if (alpha != null) - setAlpha(alpha.floatValue()); - setStroke((Stroke) map[SAVE_STROKE]); - setTransform((AffineTransform) map[SAVE_TRANSFORM]); - setFont((Font) map[SAVE_FONT]); - currentClip = (Shape) map[SAVE_CLIP]; - backgroundPainted = ((Boolean) map[SAVE_BACKGROUND_PAINTED]).booleanValue(); - ctx.restore(); - } - } - - public Graphics create(int x, int y, int width, int height) { - // cell renderer pane and JComponent - Graphics g = create(); - if (g == null) - return null; - g.translate(x, y); - g.clipRect(0, 0, width, height); - return g; - } - - public Graphics create() { - return (Graphics) clone(); - } - - @Override - public Object clone() { - int n = mark(); - JSGraphics2D g = this; - /** - * avoid super call to Object.clone(); - * - * @j2sNative - * - * g = Clazz.clone(this); - * - */ - { - } - g.transform = new AffineTransform(transform); - if (hints != null) { - g.hints = (RenderingHints) hints.clone(); - } - /* - * FontInfos are re-used, so must be cloned too, if they are valid, and be - * nulled out if invalid. The implied trade-off is that there is more to be - * gained from re-using these objects than is lost by having to clone them when - * the SG2D is cloned. - */ - // if (this.fontInfo != null) { - // if (this.validFontInfo) { - // g.fontInfo = (FontInfo)this.fontInfo.clone(); - // } else { - // g.fontInfo = null; - // } - // } - // if (this.glyphVectorFontInfo != null) { - // g.glyphVectorFontInfo = - // (FontInfo)this.glyphVectorFontInfo.clone(); - // g.glyphVectorFRC = this.glyphVectorFRC; - // } - // g.invalidatePipe(); - g.setStroke((BasicStroke) currentStroke.clone()); - g.initialState = n; - return g; - } - - public void dispose() { - reset(initialState); - } - -} +package swingjs; + +import java.awt.AlphaComposite; +import java.awt.BasicStroke; +import java.awt.Color; +import java.awt.Composite; +import java.awt.Font; +import java.awt.FontMetrics; +import java.awt.Graphics; +import java.awt.GraphicsConfiguration; +import java.awt.Image; +import java.awt.Paint; +import java.awt.Polygon; +import java.awt.Rectangle; +import java.awt.RenderingHints; +import java.awt.RenderingHints.Key; +import java.awt.Shape; +import java.awt.Stroke; +import java.awt.Toolkit; +import java.awt.font.FontRenderContext; +import java.awt.geom.AffineTransform; +import java.awt.geom.Path2D; +import java.awt.geom.PathIterator; +import java.awt.image.BufferedImage; +import java.awt.image.BufferedImageOp; +import java.awt.image.ImageObserver; +import java.awt.image.RenderedImage; +import java.awt.image.renderable.RenderableImage; +import java.text.AttributedCharacterIterator; +import java.util.Hashtable; +import java.util.Map; +import java.util.Map.Entry; + +import swingjs.api.js.DOMNode; +import swingjs.api.js.HTML5Canvas; +import swingjs.api.js.HTML5CanvasContext2D; + +// BH 9/18/2018 fill3DRect fix +// BH 6/2018 adds g.copyArea(x,y,width,height,dx,dy) + +/** + * generic 2D drawing methods -- JavaScript version + * + * @author Bob Hanson hansonr@stolaf.edu + */ + +@SuppressWarnings({ "rawtypes", "unchecked", "deprecation" }) +public class JSGraphics2D // extends SunGraphics2D + implements Cloneable { + + private boolean backgroundPainted; + + public int constrainX; + public int constrainY; + + private int width; + private int height; + private HTML5Canvas canvas; + + private HTML5CanvasContext2D ctx; + private GraphicsConfiguration gc; + + private BasicStroke currentStroke; + private Shape currentClip; + + private AlphaComposite currentComposite; + private int initialState; + + // public int strokeState; + // public int transformState; + // public int clipState; + + // public Color foregroundColor; + boolean isShifted;// private, but only JavaScript + private Font font; + + private RenderingHints hints; + + private AffineTransform transform; + + private Color backgroundColor; + + // private Color currentColor; + + public JSGraphics2D(Object canvas) { // this must be Object, because we are + // passing an actual HTML5 canvas + hints = new RenderingHints(new Hashtable()); + this.canvas = (HTML5Canvas) canvas; + ctx = this.canvas.getContext("2d"); +// removed - caused blurriness 9/17/2018 +// // reduce antialiasing, thank you, +// // http://www.rgraph.net/docs/howto-get-crisp-lines-with-no- antialias.html +// if (!isShifted) +// ctx.translate(-0.5, -0.5); +// isShifted = true; + transform = new AffineTransform(); + setStroke(new BasicStroke()); + /** + * @j2sNative + * + * this.gc = SwingJS; this.width = canvas.width; this.height = + * canvas.height; + * + */ + { + } + } + + /** + * the SwingJS object + */ + + public GraphicsConfiguration getDeviceConfiguration() { + return gc; + } + + public void drawLine(int x0, int y0, int x1, int y1) { + boolean inPath = this.inPath; + if (!inPath) + ctx.beginPath(); + ctx.moveTo(x0, y0); + ctx.lineTo(x1, y1); + if (!inPath) + ctx.stroke(); + } + + public void drawOval(int left, int top, int width, int height) { + if (width == height) + doCirc(left, top, width, false); + else + doArc(left, top, width, height, 0, 360, false); + } + + public void fillOval(int left, int top, int width, int height) { + if (width == height) + doCirc(left, top, width, true); + else + doArc(left, top, width, height, 0, 360, true); + } + + public void drawArc(int x, int y, int width, int height, int startAngle, int arcAngle) { + doArc(x, y, width, height, startAngle, arcAngle, false); + } + + public void fillArc(int centerX, int centerY, int width, int height, int startAngle, int arcAngle) { + doArc(centerX, centerY, width, height, startAngle, arcAngle, true); + } + + private void doCirc(int left, int top, int diameter, boolean fill) { + if (diameter <= 0) + return; + double r = diameter / 2f; + ctx.beginPath(); + ctx.arc(left + r, top + r, r, 0, 2 * Math.PI, false); + ctx.closePath(); + if (fill) + ctx.fill(); + else + ctx.stroke(); + } + + private void doArc(double x, double y, double width, double height, double startAngle, double arcAngle, + boolean fill) { + if (width <= 0 || height <= 0) + return; + // boolean doClose = (arcAngle - startAngle == 360); + ctx.save(); + { + if (arcAngle < 0) { + startAngle += arcAngle; + arcAngle = -arcAngle; + } + ctx.translate(x, y); + ctx.scale(width / 2, height / 2); + ctx.beginPath(); + ctx.arc(1, 1, 1, toRad(360 - startAngle), toRad(360 - arcAngle - startAngle), true); + if (fill) + ctx.lineTo(1, 1); + } + ctx.restore(); + if (fill) + ctx.fill(); + else + ctx.stroke(); + } + + private double toRad(double a) { + return a * (Math.PI / 180); + } + + public void background(Color bgcolor) { + backgroundColor = bgcolor; + if (bgcolor == null) { + return; + } + clearRect(0, 0, width, height); + } + + public void drawPolygon(Polygon p) { + doPoly(p.xpoints, p.ypoints, p.npoints, false); + } + + public void drawPolygon(int[] axPoints, int[] ayPoints, int nPoints) { + doPoly(axPoints, ayPoints, nPoints, false); + } + + /** + * @param axPoints + * @param ayPoints + * @param nPoints + * @param doFill + */ + private void doPoly(int[] axPoints, int[] ayPoints, int nPoints, boolean doFill) { + ctx.beginPath(); + ctx.moveTo(axPoints[0], ayPoints[0]); + for (int i = 1; i < nPoints; i++) + ctx.lineTo(axPoints[i], ayPoints[i]); + if (doFill) { + ctx.fill(); + } else { + ctx.lineTo(axPoints[0], ayPoints[0]); + ctx.stroke(); + } + } + + public void drawRect(int x, int y, int width, int height) { + if (width <= 0 || height <= 0) + return; + ctx.beginPath(); + ctx.rect(x, y, width, height); + ctx.stroke(); + } + + public void fillPolygon(Polygon p) { + doPoly(p.xpoints, p.ypoints, p.npoints, true); + } + + public void fillPolygon(int[] axPoints, int[] ayPoints, int nPoints) { + doPoly(axPoints, ayPoints, nPoints, true); + } + + public void fillRect(int x, int y, int width, int height) { + if (width <= 0 || height <= 0) + return; + backgroundPainted = true; + ctx.translate(0.5, 0.5); + ctx.fillRect(x, y, width, height); + ctx.translate(-0.5, -0.5); +// +// if (width == 1) +// drawLine(x, y, x, y + height); +// else if (height == 1) +// drawLine(x, y, x + width, y); +// else + } + + public void draw3DRect(int x, int y, int width, int height, boolean raised) { + do3DRect(x, y, width, height, raised, false); + } + + public void fill3DRect(int x, int y, int width, int height, boolean raised) { + do3DRect(x, y, width, height, raised, true); + } + + private void do3DRect(int x, int y, int width, int height, boolean raised, boolean isFill) { + if (width <= 0 || height <= 0) + return; + Paint p = getPaint(); + Color c = getColor(); + Color brighter = c.brighter(); + Color darker = c.darker(); + + if (!raised) { + setColor(darker); + } else if (p != c) { + setColor(c); + } + if (isFill) { + fillRect(x + 1, y + 1, width - 2, height - 2); + } + setColor(raised ? brighter : darker); + // drawLine(x, y, x, y + height - 1); + fillRect(x, y, 1, height); + // drawLine(x + 1, y, x + width - 2, y); + fillRect(x + 1, y, width - 2, 1); + setColor(raised ? darker : brighter); + // drawLine(x + 1, y + height - 1, x + width - 1, y + height - 1); + fillRect(x + 1, y + height - 1, width - 1, 1); + // drawLine(x + width - 1, y, x + width - 1, y + height - 2); + fillRect(x + width - 1, y, 1, height - 1); + setPaint(p); + } + + public void setFont(Font font) { + // this equality check speeds mark/reset significantly + if (font == this.font) + return; + this.font = font; + if (font != null) + HTML5CanvasContext2D.setFont(ctx, JSToolkit.getCanvasFont(font)); + } + + public void setStrokeBold(boolean tf) { + setLineWidth(tf ? 2. : 1.); + } + + private void setLineWidth(double d) { + HTML5CanvasContext2D.setLineWidth(ctx, d); + } + + public boolean canDoLineTo() { + return true; + } + + boolean inPath; + + private Color foregroundColor; + + public void doStroke(boolean isBegin) { + inPath = isBegin; + if (isBegin) { + ctx.beginPath(); + } else { + ctx.stroke(); + } + } + + public void lineTo(int x2, int y2) { + ctx.lineTo(x2, y2); + } + + public void clip(Shape s) { + doShape(s); + currentClip = s; + ctx.clip(); + } + + public void draw(Shape s) { + doShape(s); + ctx.stroke(); + } + + private int doShape(Shape s) { + ctx.beginPath(); + double[] pts = new double[6]; + PathIterator pi = s.getPathIterator(null); + while (!pi.isDone()) { + switch (pi.currentSegment(pts)) { + case PathIterator.SEG_MOVETO: + ctx.moveTo(pts[0], pts[1]); + break; + case PathIterator.SEG_LINETO: + ctx.lineTo(pts[0], pts[1]); + break; + case PathIterator.SEG_QUADTO: + ctx.quadraticCurveTo(pts[0], pts[1], pts[2], pts[3]); + break; + case PathIterator.SEG_CUBICTO: + ctx.bezierCurveTo(pts[0], pts[1], pts[2], pts[3], pts[4], pts[5]); + break; + case PathIterator.SEG_CLOSE: + ctx.closePath(); + break; + } + pi.next(); + } + return pi.getWindingRule(); + // then fill or stroke or clip + } + + public void fill(Shape s) { + if (doShape(s) == Path2D.WIND_EVEN_ODD) + /** + * @j2sNative + * + * this.ctx.fill("evenodd"); + */ + { + } else + ctx.fill(); + } + + public boolean drawImage(Image img, int x, int y, ImageObserver observer) { + return drawImagePriv(img, x, y, observer); + } + + public boolean drawImage(Image img, int x, int y, int width, int height, ImageObserver observer) { + if (width <= 0 || height <= 0) + return true; + backgroundPainted = true; + if (img != null) { + DOMNode imgNode = getImageNode(img); + if (imgNode != null) + ctx.drawImage(imgNode, x, y, width, height); + if (observer != null) + observe(img, observer, imgNode != null); + } + return true; + } + + private DOMNode getImageNode(Image img) { + backgroundPainted = true; + DOMNode imgNode = DOMNode.getImageNode(img); + return (imgNode == null ? JSGraphicsCompositor.createImageNode(img) : imgNode); + } + + private void observe(Image img, ImageObserver observer, boolean isOK) { + observer.imageUpdate(img, (isOK ? 0 : ImageObserver.ABORT | ImageObserver.ERROR), -1, -1, -1, -1); + } + + public boolean drawImage(Image img, int x, int y, Color bgcolor, ImageObserver observer) { + backgroundPainted = true; + JSUtil.notImplemented(null); + return drawImage(img, x, y, observer); + } + + public boolean drawImage(Image img, int x, int y, int width, int height, Color bgcolor, ImageObserver observer) { + if (width <= 0 || height <= 0) + return false; + backgroundPainted = true; + JSUtil.notImplemented(null); + return drawImage(img, x, y, width, height, observer); + } + + @SuppressWarnings("unused") + + public boolean drawImage(Image img, int dx1, int dy1, int dx2, int dy2, int sx1, int sy1, int sx2, int sy2, + ImageObserver observer) { + backgroundPainted = true; + if (img != null) { + byte[] bytes = null; + DOMNode imgNode = getImageNode(img); + if (imgNode != null) + HTML5CanvasContext2D.stretchImage(ctx, imgNode, sx1, sy1, sx2 - sx1, sy2 - sy1, dx1, dy1, dx2 - dx1, + dy2 - dy1); + if (observer != null) + observe(img, observer, imgNode != null); + } + return true; + } + + public boolean drawImage(Image img, int dx1, int dy1, int dx2, int dy2, int sx1, int sy1, int sx2, int sy2, + Color bgcolor, ImageObserver observer) { + JSUtil.notImplemented(null); + return drawImage(img, dx1, dy1, dx2, dy2, sx1, sy1, sx2, sy2, observer); + } + + public boolean drawImage(Image img, AffineTransform xform, ImageObserver obs) { + return drawImageXT(img, xform, obs); + } + + public void drawRenderedImage(RenderedImage img, AffineTransform xform) { + drawImageXT((Image) img, xform, null); + } + + public void drawRenderableImage(RenderableImage img, AffineTransform xform) { + drawImageXT((Image) img, xform, null); + } + + private boolean drawImageXT(Image img, AffineTransform xform, ImageObserver obs) { + ctx.save(); + transformCTX(xform); + boolean ret = drawImagePriv(img, 0, 0, obs); + ctx.restore(); + return ret; + } + + private Object imageData; + private int[] buf8; + private int lastx, lasty, nx, ny; + + @SuppressWarnings("unused") + public boolean drawImagePriv(Image img, int x, int y, ImageObserver observer) { + backgroundPainted = true; + if (img != null) { + int[] pixels = null; + boolean isRGB = false; // usually RGBA + /** + * @j2sNative + * + * pixels = img._pix; isRGB = (img.imageType == 1); + * + */ + DOMNode imgNode = null; + int width = ((BufferedImage) img).getRaster().getWidth(); + int height = ((BufferedImage) img).getRaster().getHeight(); + + + if (pixels == null) { + if ((imgNode = getImageNode(img)) != null) + ctx.drawImage(imgNode, x, y, width, height); + } else { + drawDirect(pixels, x, y, width, height, isRGB); + } + if (observer != null) + observe(img, observer, imgNode != null); + } + return true; + } + + public void drawDirectRGBA(int[] pixels) { + // this can go VERY fast - for writing directly to the canvas context + backgroundPainted = true; + drawDirect(pixels, 0, 0, width, height, false); + } + + private void drawDirect(int[] pixels, int x, int y, int width, int height, boolean isRGB) { + if (buf8 == null || x != lastx || y != lasty || nx != width || ny != height) { + imageData = HTML5CanvasContext2D.getImageData(ctx, x, y, width, height); + buf8 = HTML5CanvasContext2D.getBuf8(imageData); + lastx = x; + lasty = y; + nx = width; + ny = height; + } + for (int pt = 0, i = 0, n = Math.min(buf8.length / 4, pixels.length); i < n; i++) { + int argb = pixels[i]; + buf8[pt++] = (argb >> 16) & 0xFF; + buf8[pt++] = (argb >> 8) & 0xFF; + buf8[pt++] = argb & 0xFF; + buf8[pt++] = (isRGB ? 0xFF : (argb >> 24) & 0xFF); + } + HTML5CanvasContext2D.putImageData(ctx, imageData, x, y); + } + + public boolean hit(Rectangle rect, Shape s, boolean onStroke) { + JSUtil.notImplemented(null); + return false; + } + + public Stroke getStroke() { + return currentStroke; + } + + @SuppressWarnings("unused") + + public void setStroke(Stroke s) { + if (!(s instanceof BasicStroke)) + return; + BasicStroke b = currentStroke = (BasicStroke) s; + float[] dash = b.getDashArray(); + int[] idash = new int[dash == null ? 0 : dash.length]; + for (int i = idash.length; --i >= 0;) + idash[i] = (int) dash[i]; + ctx.setLineDash(idash); + setLineWidth(b.getLineWidth()); + String lineCap, lineJoin; + float miterLimit = -1; + switch (b.getEndCap()) { + case BasicStroke.CAP_BUTT: + lineCap = "butt"; + break; + case BasicStroke.CAP_SQUARE: + lineCap = "square"; + break; + case BasicStroke.CAP_ROUND: + default: + lineCap = "round"; + } + switch (b.getLineJoin()) { + case BasicStroke.JOIN_BEVEL: + lineJoin = "bevel"; + break; + case BasicStroke.JOIN_MITER: + lineJoin = "miter"; + miterLimit = b.getMiterLimit(); + break; + case BasicStroke.JOIN_ROUND: + lineJoin = "round"; + } + /** + * @j2sNative + * + * this.ctx.lineCap = lineCap; this.ctx.lineJoin = lineJoin; if + * (miterLimit >= 0) this.ctx.miterLimit = miterLimit; + */ + { + } + // SwingJS TODO more here + } + + public void setRenderingHint(Key hintKey, Object hintValue) { + hints.put(hintKey, hintValue); + } + + public Object getRenderingHint(Key hintKey) { + return hints.get(hintKey); + } + + public void setRenderingHints(Map hints) { + this.hints = new RenderingHints((Map) hints); + } + + public void addRenderingHints(Map hints) { + for (Entry e : hints.entrySet()) + this.hints.put(e.getKey(), e.getValue()); + } + + public RenderingHints getRenderingHints() { + return hints; + } + + public void setBackground(Color color) { + background(color); + } + + public Color getBackground() { + return backgroundColor; + } + + public Color getColor() { + return foregroundColor; + } + + public void setColor(Color c) { + foregroundColor = c; + setGraphicsColor(c); + } + + public void setPaint(Paint paint) { + setColor((Color) paint); + } + + public Font getFont() { + if (font == null) + font = new Font("Arial", Font.PLAIN, 12); + return font; + } + + public FontMetrics getFontMetrics() { + return getFontMetrics(getFont()); + } + + public FontMetrics getFontMetrics(Font f) { + return Toolkit.getDefaultToolkit().getFontMetrics(f); + } + + public void clipRect(int x, int y, int width, int height) { + // SwingJS -- this is not quite right. Should ADD this to the clipping + // region + ctx.beginPath(); + ctx.rect(x, y, width, height); + setCurrentClip(x, y, width, height); + ctx.clip(); + } + + public void setClip(int x, int y, int width, int height) { + // clipping is disabled because for general component painting + // because it consumes so much processing. + // it is presumed that the user will clip when desired + setCurrentClip(x, y, width, height); + ctx.beginPath(); + ctx.rect(x, y, width, height); + ctx.clip(); + } + + private void setCurrentClip(int x, int y, int width, int height) { + Rectangle r = (currentClip instanceof Rectangle ? (Rectangle) currentClip : null); + if (r == null || r.x != x || r.y != y || r.width != width || r.height != height) + currentClip = new Rectangle(x, y, width, height); + } + + public void setClip(Shape clip) { + currentClip = clip; + ctx.beginPath(); + doShape(clip); + ctx.clip(); + } + + public void clearRect(int x, int y, int width, int height) { + ctx.clearRect(x, y, width, height); + setGraphicsColor(backgroundColor == null ? Color.WHITE : backgroundColor); + fillRect(x, y, width, height); + setGraphicsColor(foregroundColor); + } + + private void setGraphicsColor(Color c) { + if (c == null) + return; // this was the case with a JRootPanel graphic call + HTML5CanvasContext2D.setColor(ctx, JSToolkit.getCSSColor(c)); + } + + public void copyArea(int x, int y, int width, int height, int dx, int dy) { + HTML5CanvasContext2D.putImageData(ctx, HTML5CanvasContext2D.getImageData(ctx, x, y, width, height), x + dx, + y + dy); + } + + public void drawPolyline(int[] xPoints, int[] yPoints, int nPoints) { + if (nPoints < 2) + return; + ctx.moveTo(xPoints[0], yPoints[0]); + for (int i = 1; i < nPoints; i++) { + ctx.lineTo(xPoints[i], yPoints[i]); + } + ctx.stroke(); + } + + public void drawRoundRect(int x, int y, int width, int height, int arcWidth, int arcHeight) { + JSUtil.notImplemented(null); + drawRect(x, y, width, height); + } + + public void fillRoundRect(int x, int y, int width, int height, int arcWidth, int arcHeight) { + JSUtil.notImplemented(null); + fillRect(x, y, width, height); + } + + public Shape getClip() { + return currentClip == null ? getClipBoundsImpl() : currentClip; + } + + public void drawString(String s, int x, int y) { + fillText(s, x, y); + } + + public void drawString(String str, float x, float y) { + fillText(str, x, y); + } + + private void fillText(String str, float x, float y) { + ctx.fillText(str, x, y); + } + + public void drawString(AttributedCharacterIterator iterator, int x, int y) { + JSUtil.notImplemented(null); + } + + public void drawString(AttributedCharacterIterator iterator, float x, float y) { + JSUtil.notImplemented(null); + } + + public void translate(double tx, double ty) { + JSUtil.notImplemented(null); + } + + public void shear(double shx, double shy) { + JSUtil.notImplemented(null); + } + + public void translate(int x, int y) { + ctx.translate(x, y); + transform.translate(x, y); + } + + public void rotate(double radians) { + ctx.rotate(radians); + transform.rotate(radians); + } + + public void rotate(double theta, double x, double y) { + ctx.translate(x, y); + ctx.rotate(theta); + ctx.translate(-x, -y); + transform.rotate(theta, x, y); + } + + public void scale(double sx, double sy) { + ctx.scale(sx, sy); + transform.scale(sx, sy); + } + + /** + * concatenates the given transform matrix to the current transform + * + */ + + public void transform(AffineTransform t) { + transformCTX(t); + transform.concatenate(t); + } + + private void transformCTX(AffineTransform t) { + /** + * @j2sNative + * + * this.ctx.transform (t.m00, t.m10, t.m01, t.m11, t.m02, t.m12); + */ + { + } + } + + /** + * sets the transform matrix to the given one + */ + + public void setTransform(AffineTransform t) { + /** + * @j2sNative + * + * this.ctx.setTransform (t.m00, t.m10, t.m01, t.m11, t.m02, t.m12); + * + * + */ + { + } + transform.setTransform(t); + } + + /** + * Returns a copy of the current transform + */ + + public AffineTransform getTransform() { + return (AffineTransform) transform.clone(); + } + + // /** + // * Returns the current Transform ignoring the "constrain" + // * rectangle. + // */ + // public AffineTransform cloneTransform() { + // return (AffineTransform) transform.clone(); + // } + // + + public Paint getPaint() { + return getColor(); + } + + public FontRenderContext getFontRenderContext() { + return getFontMetrics(getFont()).getFontRenderContext(); + } + + public void setPaintMode() { + setComposite(AlphaComposite.SrcOver); + } + + public void setXORMode(Color c) { + if (c == null) + throw new IllegalArgumentException("null XORColor"); + setComposite(AlphaComposite.Xor); + } + + public Rectangle getClipBounds() { + return getClipBounds(null); + } + + public Rectangle getClipBounds(Rectangle r) { + Rectangle clipRect = getClipBoundsImpl(); + if (r == null) { + r = clipRect; + } else { + r.x = clipRect.x; + r.y = clipRect.y; + r.width = clipRect.width; + r.height = clipRect.height; + } + return r; + } + + private Rectangle getClipBoundsImpl() { + if (currentClip == null) { + currentClip = new Rectangle(0, 0, width, height); + } + return currentClip.getBounds(); + } + + public void setComposite(Composite comp) { + // this equality check speeds mark/reset significantly + if (comp == this.currentComposite) + return; + // alpha composite only here + int newRule = 0; + boolean isValid = (comp == null || currentComposite == null || (comp instanceof AlphaComposite) + && (newRule = ((AlphaComposite) comp).getRule()) != currentComposite.getRule()); + if (isValid && JSGraphicsCompositor.setGraphicsCompositeAlpha(this, newRule)) { + currentComposite = (AlphaComposite) comp; + } + setAlpha(comp == null ? 1 : ((AlphaComposite) comp).getAlpha()); + } + + public Composite getComposite() { + return currentComposite; + } + + public void drawImage(BufferedImage img, BufferedImageOp op, int x, int y) { + JSGraphicsCompositor.drawImageOp(this, img, op, x, y); + } + + public void setAlpha(float f) { + /** + * @j2sNative + * + * this.ctx.globalAlpha = f; + */ + { + } + } + + public HTML5Canvas getCanvas() { + return canvas; + } + + /** + * used to determine if it is likely that the background was painted + * + * @return background taint count + */ + public boolean isBackgroundPainted() { + return backgroundPainted; + } + + /////////////// saving of the state //////////////// + + private final static int SAVE_ALPHA = 0; + private final static int SAVE_COMPOSITE = 1; + private final static int SAVE_STROKE = 2; + private final static int SAVE_TRANSFORM = 3; + private final static int SAVE_FONT = 4; + private final static int SAVE_CLIP = 5; + private final static int SAVE_BACKGROUND_PAINTED = 6; + private final static int SAVE_MAX = 7; + + /** + * creates a save object to extend the capabilities of context2d.save() that + * brings that into line with Java's graphics2d .create() + * + * in development -- we need to identify all differences + * + * + * @return the length of the ctx._aSaved array after the push + */ + public int mark() { + ctx.save(); + Object[] map = new Object[SAVE_MAX]; + + float alpha = 0; + /** + * @j2sNative + * + * alpha = this.ctx.globalAlpha; + * + */ + { + } + map[SAVE_ALPHA] = Float.valueOf(alpha); + map[SAVE_COMPOSITE] = currentComposite; + map[SAVE_STROKE] = currentStroke; + map[SAVE_TRANSFORM] = transform; + map[SAVE_FONT] = font; + map[SAVE_CLIP] = currentClip; + map[SAVE_BACKGROUND_PAINTED] = (backgroundPainted ? Boolean.TRUE : Boolean.FALSE); + backgroundPainted = false; + return HTML5CanvasContext2D.push(ctx, map); + } + + /** + * try to equate g.dispose() with ctx.restore(). + * + * @param n0 + */ + public void reset(int n0) { + if (n0 < 1) + n0 = 1; + while (HTML5CanvasContext2D.getSavedLevel(ctx) >= n0) { + Object[] map = HTML5CanvasContext2D.pop(ctx); + setComposite((Composite) map[SAVE_COMPOSITE]); + Float alpha = (Float) map[SAVE_ALPHA]; + if (alpha != null) + setAlpha(alpha.floatValue()); + setStroke((Stroke) map[SAVE_STROKE]); + setTransform((AffineTransform) map[SAVE_TRANSFORM]); + setFont((Font) map[SAVE_FONT]); + currentClip = (Shape) map[SAVE_CLIP]; + backgroundPainted = ((Boolean) map[SAVE_BACKGROUND_PAINTED]).booleanValue(); + ctx.restore(); + } + } + + public Graphics create(int x, int y, int width, int height) { + // cell renderer pane and JComponent + Graphics g = create(); + if (g == null) + return null; + g.translate(x, y); + g.clipRect(0, 0, width, height); + return g; + } + + public Graphics create() { + return (Graphics) clone(); + } + + @Override + public Object clone() { + int n = mark(); + JSGraphics2D g = this; + /** + * avoid super call to Object.clone(); + * + * @j2sNative + * + * g = Clazz.clone(this); + * + */ + { + } + g.transform = new AffineTransform(transform); + if (hints != null) { + g.hints = (RenderingHints) hints.clone(); + } + /* + * FontInfos are re-used, so must be cloned too, if they are valid, and be + * nulled out if invalid. The implied trade-off is that there is more to be + * gained from re-using these objects than is lost by having to clone them when + * the SG2D is cloned. + */ + // if (this.fontInfo != null) { + // if (this.validFontInfo) { + // g.fontInfo = (FontInfo)this.fontInfo.clone(); + // } else { + // g.fontInfo = null; + // } + // } + // if (this.glyphVectorFontInfo != null) { + // g.glyphVectorFontInfo = + // (FontInfo)this.glyphVectorFontInfo.clone(); + // g.glyphVectorFRC = this.glyphVectorFRC; + // } + // g.invalidatePipe(); + g.setStroke((BasicStroke) currentStroke.clone()); + g.initialState = n; + return g; + } + + public void dispose() { + reset(initialState); + } + +} diff --git a/sources/net.sf.j2s.java.core/src/swingjs/plaf/JSComponentUI.java b/sources/net.sf.j2s.java.core/src/swingjs/plaf/JSComponentUI.java index 4ff30d8a8..b8329b992 100644 --- a/sources/net.sf.j2s.java.core/src/swingjs/plaf/JSComponentUI.java +++ b/sources/net.sf.j2s.java.core/src/swingjs/plaf/JSComponentUI.java @@ -1561,6 +1561,7 @@ protected void setHorizontalButtonAlignments(JComponent b, int pos, int align) { // DOMNode.setAttr(textNode, "innerHTML", pos); + int wIcon = Math.max(0, setHTMLSize1(iconNode, false, false).width - 1); int wText = setHTMLSize1(textNode, false, false).width - 1; @@ -1644,8 +1645,12 @@ protected void setHorizontalButtonAlignments(JComponent b, int pos, int align) { DOMNode.setPositionAbsolute(iconNode); DOMNode.setPositionAbsolute(textNode); - if (buttonNode != null) + if (buttonNode != null) { DOMNode.setPositionAbsolute(buttonNode); + } else if (centeringNode != null) { + // See test/Puzzle.java + DOMNode.setStyles(centeringNode, "width", "100%"); + } } diff --git a/sources/net.sf.j2s.java.core/src/test/Puzzle.java b/sources/net.sf.j2s.java.core/src/test/Puzzle.java new file mode 100644 index 000000000..ab230a7d1 --- /dev/null +++ b/sources/net.sf.j2s.java.core/src/test/Puzzle.java @@ -0,0 +1,960 @@ +package test; + +import java.awt.BorderLayout; +import java.awt.Color; +import java.awt.Dimension; +import java.awt.Font; +import java.awt.Graphics; +import java.awt.GridLayout; +import java.awt.Image; +import java.awt.MediaTracker; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.awt.event.MouseMotionAdapter; +import java.io.BufferedReader; +import java.io.InputStreamReader; +import java.net.MalformedURLException; +import java.net.URL; +import java.util.Random; +import a2s.*; +//import java.awt.*; + + +// ================================= +// Puzzle-Applet zu MathePrisma +// Autor: Stefanie Krivsky +// Stand: November 2003 +// www.MathePrisma.de +// MathePrisma@math.uni-wuppertal.de +// ================================= +// Appletpoints eingefügt von +// U. Schwebinghaus 2007 + +public class Puzzle extends Applet { +//===============================// + +int mpcount; //eingefügt U. Schwebinghaus +String par_antw="Welches Bild muss wohin?"; + +oben Kontrolle; +mitte Feld; +String Dateiname; + + +Matrix[] Felder; +String[] BilderNamen; +ZMatrix[] Zufaelle; +int AnzFelder; +int BilderAnz; +int ZufallAnz; +String PositionenString, LoesungenString; + + + + //für MathePrisma Points + //eingefügt U. Schwebinghaus + public int send_to_html() + { + int points=-1; + if (mpcount>0) points=mpcount; + return points; + } + + + public void InitBilder (String s) { + String sneu = ""; + int BildNr = 0; + for (int i=0; i ZufallAnz) { + Zufaelle[ZufallAnz] = new ZMatrix(FiW[0], FiW[1]); + ZufallAnz++; + } + if (FiW[2]==0) { + Felder[FeldNr] = new Matrix(FiW[0], FiW[1], true, FiW[3], + FiW[4], FiW[5], FiW[6], FiW[7], FiW[8]); + } + else { + Felder[FeldNr] = new Matrix(FiW[0], FiW[1], false, FiW[3], + FiW[4], FiW[5], FiW[6], FiW[7], FiW[8]); + } + FeldNr++; + Feldp = 0; + } + } + } + + + public void InitElemente (String s) { + String sneu = ""; + int FeldNr = 0; + int Feldpx = 0; + int Feldpy = 0; + for (int i=0; i -1) && + (Felder[z].Elem[i][j] != Felder[z].Lsg[i][j]) ){ + fehleranz++; + } // if + } // for + } // for + } // if + } // for + return fehleranz; + } // Ende TestFeld + + + + public void start() { + Feld.init(); + Feld.repaint(); + } + + + + +////////////////////////////////////////////////////////////// +//Die FeldMatrix und die Zufallsmatrix +////////////////////////////////////////////////////////////// + + + +class Matrix { +int dimX, dimY; +boolean fix; +int zufall; +int UrspX, UrspY; +int BildW, BildH, Rand; + +int[][] Elem; +int[][] Lsg; + + public Matrix( int dx, int dy, + boolean f, int z, int Ux, int Uy, + int w, int h, int r) { + dimX= dx; + dimY= dy; + fix = f; + zufall= z; + UrspX = Ux; + UrspY = Uy; + BildW = w; + BildH = h; + Rand= r; + + Elem = new int[dimX][dimY]; + if (fix == false) { + Lsg = new int[dimX][dimY]; + } + } // Matrix + +} // class Matrix + + + +class ZMatrix { +int dimX, dimY; +int[] ZufX, ZufY; + + public ZMatrix( int dx, int dy) { + dimX= dx; + dimY= dy; + ZufX = new int[dimX]; + ZufY = new int[dimY]; + } // ZMatrix + +} // class ZMatrix + + + +////////////////////////////////////////////////////////////// +// Die oberen Einstellungen // +////////////////////////////////////////////////////////////// + + +class oben extends Panel { +Puzzle theapplet; +Label Antwort = new Label(); +Panel buttons = new Panel(); +Button[] Knopfl = new Button[2]; + + + public oben (Puzzle a) { + theapplet = a; + setLayout(new GridLayout(2,1)); + setBackground(Color.white); + setFont(new Font("Helvetica",Font.PLAIN,14)); + buttons.setLayout(new GridLayout(1,2)); + Knopfl[0]=new Button("Neues Puzzle"); + Knopfl[1]=new Button("Kontrolle"); + Knopfl[0].setBackground(Color.lightGray); + Knopfl[1].setBackground(Color.lightGray); + buttons.add(Knopfl[0]); + buttons.add(Knopfl[1]); + add(buttons); + Antwort.setForeground(Color.black); + Antwort.setText(par_antw); // geändert U. Schwebinghaus + Antwort.setHorizontalAlignment(Label.CENTER); + add(Antwort); + + + ActionListener ActionButton0 = new ActionListener() { + public void actionPerformed(ActionEvent e){ + ResetFeld(); + Antwort.setForeground(Color.black); + Antwort.setText(par_antw); // geändert U. Schwebinghaus + Feld.repaint(); + } + }; // Ende ActionButton0 + + ActionListener ActionButton1 = new ActionListener() { + public void actionPerformed(ActionEvent e){ + int falsch = 0; + falsch = TestFeld(); + + mpcount=BilderAnz/2-falsch; + + if (falsch == 0) { + Antwort.setForeground(Color.green.darker()); + Antwort.setText("Klasse, alles richtig!"); + } + else { + if (falsch == 1) { + Antwort.setForeground(Color.red); + Antwort.setText("Ein Bild ist noch falsch."); + } + else { + Antwort.setForeground(Color.red); + Antwort.setText(falsch+" Bilder sind noch falsch."); + } + } + } + }; // Ende ActionButton1 + + + Knopfl[0].addActionListener(ActionButton0); + Knopfl[1].addActionListener(ActionButton1); + } // public oben + + +} // class oben + + + + +////////////////////////////////////////////////////////////// +//Das Feld// +////////////////////////////////////////////////////////////// + + + +class mitte extends Panel { + +Puzzle theapplet; +Image img, currentImage; +Graphics imggc; +int width,height; +Image[] Bilder; +MediaTracker ladekontrolle = new MediaTracker(this); + +int dragnr = -1; +int dragx = -1; +int dragy = -1; +int vx = 0; +int vy = 0; + +int merkeFN = -1; +int merkeFj = -1; +int merkeFi = -1; + + + public mitte(Puzzle a) { + theapplet = a; + addMouseListener( new meinMA()); + addMouseMotionListener( new meinMML()); + } + + + public void init(){ + if (img==null) { + Dimension d=getSize(); + width=d.width; height=d.height; + img=createImage(width,height); + imggc=img.getGraphics(); + imggc.setFont (new Font("Helvetica", Font.PLAIN, 14)); + + Bilder= new Image[BilderAnz]; + for (int i=0; i<(BilderAnz); i++) { + // Bilder[i] = getImage(getCodeBase(), (String)(BilderNamen[i])); + try + { + + URL url = new java.net.URL(getCodeBase(), (String)(BilderNamen[i])); + System.out.println(url); + + Bilder[i] = javax.imageio.ImageIO.read(url); + } + catch (Exception e) { + System.out.println(e); + } + + ladekontrolle.addImage(Bilder[i],i); + try {ladekontrolle.waitForID(i);} + catch (InterruptedException e) + {} + } + } + validate(); + } + + + public void paint(Graphics gc) { + if (img!=null) { malen(gc); } + } + + public void update(Graphics gc) { + if (img!=null) { paint(gc); } + } + + + void maleFeld (Matrix maleF) { +// Graphics gc = getGraphics(); + imggc.setColor(Color.lightGray); + for (int i=0; i<(maleF.dimX); i++) { + for (int j=0; j<(maleF.dimY); j++) { + if (maleF.Elem[i][j] == -1) { + imggc.fillRect(maleF.UrspX+i*(maleF.BildW+maleF.Rand), + maleF.UrspY+j*(maleF.BildH+maleF.Rand), + maleF.BildW, maleF.BildH);//;, false); + + } + else { + imggc.drawImage(Bilder[maleF.Elem[i][j]], + maleF.UrspX+i*(maleF.BildW+maleF.Rand), + maleF.UrspY+j*(maleF.BildH+maleF.Rand), + maleF.BildW, maleF.BildH, this); + } + } + } + } // Ende maleFeld + + + + + void malen (Graphics gc) { + imggc.setColor(Color.white); + imggc.fillRect( 0, 0, width, height); + for (int i=0; i<(AnzFelder); i++) { + maleFeld(Felder[i]); + } + if (dragnr != -1) { + imggc.setColor(Color.red); + imggc.drawImage(Bilder[dragnr], dragx, dragy, + Felder[merkeFN].BildW, Felder[merkeFN].BildH, this); + } + gc.drawImage(img,0,0,theapplet); + } // Ende malen + + + + + public boolean TesteFFrei (Matrix testF, int px, int py, boolean frei) { + // Teste ob px,py im Feld mit Wert uebereinstimmen + // falls ja, dann merke FeldNr und Koord und gebe true zurueck + int posx = testF.UrspX; + int posy = testF.UrspY; + int i = -1; + int j = -1; + boolean aktion = false; + + if ( (px >= posx) && (py >= posy) ) { + i = 0; + j = 0; + while ( ((posx+testF.BildW) <= px) && (i=testF.dimX) { + i = -1; + } + while ( ((posy+testF.BildH) <= py) && (j=testF.dimY) { + j = -1; + } + } + if ( (i>=0)&&(j>=0) ) { + if ( (posx < px) && (px <=posx+testF.BildW) && + (posy < py) && (py <=posy+testF.BildH) && + ( (testF.Elem[i][j]<0) == frei ) ) { + merkeFi = i; + merkeFj = j; + aktion = true; + } + } + return aktion; + } // Ende TesteFrei + + + + class meinMML extends MouseMotionAdapter { + + public void mouseDragged( MouseEvent me ) { + if (dragnr == -1) { // ehem. MouseDown + int mx = me.getX(); + int my = me.getY(); + merkeFN = -1; + merkeFi = -1; + merkeFj = -1; + vx = 0; + vy = 0; + boolean inFeld = false; + for (int i=0; i<(AnzFelder); i++) { + if ( !Felder[i].fix ) { + if ( TesteFFrei (Felder[i], mx, my, false) ) { + merkeFN = i; + } + } + } + if ( merkeFN != -1 ) { + dragnr = Felder[merkeFN].Elem[merkeFi][merkeFj]; + Felder[merkeFN].Elem[merkeFi][merkeFj] = -1; + dragx= Felder[merkeFN].UrspX+merkeFi*(Felder[merkeFN].BildW+Felder[merkeFN].Rand); + dragy= Felder[merkeFN].UrspY+merkeFj*(Felder[merkeFN].BildH+Felder[merkeFN].Rand); + vx = mx-dragx; + vy = my-dragy; + repaint(); + } + } + if (dragnr != -1) { // ehem. MouseMove + int mx = me.getX(); + int my = me.getY(); + dragx = mx-vx; + dragy = my-vy; + if ( dragx < 0 ){ + dragx = 0; + } + if ( dragx > (width-Felder[merkeFN].BildW) ) { + dragx = width-Felder[merkeFN].BildW; + } + if ( dragy < 0 ){ + dragy = 0; + } + if ( dragy > (height-Felder[merkeFN].BildH) ) { + dragy = height-Felder[merkeFN].BildH; + } + repaint(); + } + } // Ende MouseDragged + + } // Ende meinMML + + + class meinMA extends MouseAdapter { + + public void mouseReleased( MouseEvent me ) { + if (dragnr != -1) { + int mx = me.getX(); + int my = me.getY(); + for (int i=0; i<(AnzFelder); i++) { + if ( TesteFFrei (Felder[i], mx, my, true) ) { + merkeFN = i; + } + } + Felder[merkeFN].Elem[merkeFi][merkeFj] = dragnr; + dragnr = -1; + dragx= -1; + dragy= -1; + vx = 0; + vy = 0; + repaint(); + } + } // Ende mouseReleased + + } // Ende meinMA + + +} // Mitte + +} // class Puzzle