Mercurial > projects > dwt-addons
diff dwtx/draw2d/SWTGraphics.d @ 98:95307ad235d9
Added Draw2d code, still work in progress
author | Frank Benoit <benoit@tionex.de> |
---|---|
date | Sun, 03 Aug 2008 00:52:14 +0200 |
parents | |
children | 1082a0fc2bb8 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dwtx/draw2d/SWTGraphics.d Sun Aug 03 00:52:14 2008 +0200 @@ -0,0 +1,1220 @@ +/******************************************************************************* + * Copyright (c) 2000, 2007 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Port to the D programming language: + * Frank Benoit <benoit@tionex.de> + *******************************************************************************/ +module dwtx.draw2d.SWTGraphics; + +import dwt.dwthelper.utils; +import dwtx.dwtxhelper.Collection; +static import dwt.graphics.Rectangle; +import dwt.DWT; +import dwt.graphics.Color; +import dwt.graphics.Font; +import dwt.graphics.FontMetrics; +import dwt.graphics.GC; +import dwt.graphics.Image; +import dwt.graphics.Path; +import dwt.graphics.Pattern; +import dwt.graphics.TextLayout; +import dwt.graphics.Transform; +import dwt.widgets.Display; +import dwtx.draw2d.geometry.PointList; +import dwtx.draw2d.geometry.Rectangle; +import dwtx.draw2d.Graphics; + +/** + * A concrete implementation of <code>Graphics</code> using an DWT + * <code>GC</code>. There are 2 states contained in this graphics class -- the + * applied state which is the actual state of the GC and the current state which + * is the current state of this graphics object. Certain properties can be + * changed multiple times and the GC won't be updated until it's actually used. + * <P> + * WARNING: This class is not intended to be subclassed. + */ +public class SWTGraphics + : Graphics +{ + +/** + * An internal type used to represent and update the GC's clipping. + * @since 3.1 + */ +interface Clipping { + /** + * Sets the clip's bounding rectangle into the provided argument and returns it for convenince. + * @param rect the rect + * @return the given rect + * @since 3.1 + */ + Rectangle getBoundingBox(Rectangle rect); + Clipping getCopy(); + void intersect(int left, int top, int right, int bottom); + void scale(float horizontal, float vertical); + void setOn(GC gc, int translateX, int translateY); + void translate(float dx, float dy); +} + +/** + * Any state stored in this class is only applied when it is needed by a + * specific graphics call. + * @since 3.1 + */ +static class LazyState { + Color bgColor; + Color fgColor; + Font font; + int graphicHints; + int lineWidth; + Clipping relativeClip; +} + +static class RectangleClipping : Clipping { + private float top, left, bottom, right; + + this(float left, float top, float right, float bottom) { + this.left = left; + this.right = right; + this.bottom = bottom; + this.top = top; + } + + this(dwt.graphics.Rectangle.Rectangle rect) { + left = rect.x; + top = rect.y; + right = rect.x + rect.width; + bottom = rect.y + rect.height; + } + + this(Rectangle rect) { + left = rect.x; + top = rect.y; + right = rect.right(); + bottom = rect.bottom(); + } + + public Rectangle getBoundingBox(Rectangle rect) { + rect.x = cast(int)left; + rect.y = cast(int)top; + rect.width = cast(int)Math.ceil(right) - rect.x; + rect.height = cast(int)Math.ceil(bottom) - rect.y; + return rect; + } + + public Clipping getCopy() { + return new RectangleClipping(left, top, right, bottom); + } + + public void intersect(int left, int top, int right, int bottom) { + this.left = Math.max(this.left, left); + this.right = Math.min(this.right, right); + this.top = Math.max(this.top, top); + this.bottom = Math.min(this.bottom, bottom); + if (right < left || bottom < top) { + //width and height of -1 to avoid ceiling function from re-adding a pixel. + this.right = left - 1; + this.bottom = top - 1; + } + } + + public void scale(float horz, float vert) { + left /= horz; + right /= horz; + top /= vert; + bottom /= vert; + } + + public void setOn(GC gc, int translateX, int translateY) { + int xInt = cast(int)Math.floor(left); + int yInt = cast(int)Math.floor(top); + gc.setClipping(xInt + translateX, yInt + translateY, + cast(int)Math.ceil(right) - xInt, + cast(int)Math.ceil(bottom) - yInt); + } + + public void translate(float dx, float dy) { + left += dx; + right += dx; + top += dy; + bottom += dy; + } +} + +/** + * Contains the entire state of the Graphics. + */ +static class State + : LazyState + , Cloneable +{ + float affineMatrix[]; + int alpha; + Pattern bgPattern; + int dx, dy; + + Pattern fgPattern; + int lineDash[]; + + this(){ + } + + public Object clone() { + auto res = new State; + res.affineMatrix = this.affineMatrix.dup; + res.alpha = this.alpha; + res.bgPattern = this.bgPattern; + res.dx = this.dx; + res.dy = this.dy; + res.fgPattern = this.fgPattern; + res.lineDash = this.lineDash.dup; + return res; + } + + /** + * Copies all state information from the given State to this State + * @param state The State to copy from + */ + public void copyFrom(State state) { + bgColor = state.bgColor; + fgColor = state.fgColor; + lineWidth = state.lineWidth; + dx = state.dx; + dy = state.dy; + bgPattern = state.bgPattern; + fgPattern = state.fgPattern; + font = state.font; + lineDash = state.lineDash; + graphicHints = state.graphicHints; + affineMatrix = state.affineMatrix; + relativeClip = state.relativeClip; + alpha = state.alpha; + } +} + +static const int AA_MASK; +static const int AA_SHIFT; +static const int AA_WHOLE_NUMBER = 1; +static const int ADVANCED_GRAPHICS_MASK; +static const int ADVANCED_HINTS_DEFAULTS; +static const int ADVANCED_HINTS_MASK; +static const int ADVANCED_SHIFT; +static const int CAP_MASK; +static const int CAP_SHIFT; +static const int FILL_RULE_MASK; +static const int FILL_RULE_SHIFT; +static const int FILL_RULE_WHOLE_NUMBER = -1; +static const int INTERPOLATION_MASK; +static const int INTERPOLATION_SHIFT; +static const int INTERPOLATION_WHOLE_NUMBER = 1; +static const int JOIN_MASK; +static const int JOIN_SHIFT; +static const int LINE_STYLE_MASK; + +static const int TEXT_AA_MASK; +static const int TEXT_AA_SHIFT; +static const int XOR_MASK; +static const int XOR_SHIFT; + +static this() { + XOR_SHIFT = 3; + CAP_SHIFT = 4; + JOIN_SHIFT = 6; + AA_SHIFT = 8; + TEXT_AA_SHIFT = 10; + INTERPOLATION_SHIFT = 12; + FILL_RULE_SHIFT = 14; + ADVANCED_SHIFT = 15; + + LINE_STYLE_MASK = 7; + AA_MASK = 3 << AA_SHIFT; + CAP_MASK = 3 << CAP_SHIFT; + FILL_RULE_MASK = 1 << FILL_RULE_SHIFT; + INTERPOLATION_MASK = 3 << INTERPOLATION_SHIFT; + JOIN_MASK = 3 << JOIN_SHIFT; + TEXT_AA_MASK = 3 << TEXT_AA_SHIFT; + XOR_MASK = 1 << XOR_SHIFT; + ADVANCED_GRAPHICS_MASK = 1 << ADVANCED_SHIFT; + + ADVANCED_HINTS_MASK = TEXT_AA_MASK | AA_MASK | INTERPOLATION_MASK; + ADVANCED_HINTS_DEFAULTS = ((DWT.DEFAULT + AA_WHOLE_NUMBER) << TEXT_AA_SHIFT) + | ((DWT.DEFAULT + AA_WHOLE_NUMBER) << AA_SHIFT) + | ((DWT.DEFAULT + INTERPOLATION_WHOLE_NUMBER) << INTERPOLATION_SHIFT); +} + +private const LazyState appliedState; +private const State currentState; + +private bool elementsNeedUpdate; +private GC gc; + +private bool sharedClipping; +private List stack; + +private int stackPointer = 0; +Transform transform; +private int translateX = 0; +private int translateY = 0; + +/** + * Constructs a new SWTGraphics that draws to the Canvas using the given GC. + * @param gc the GC + */ +public this(GC gc) { + appliedState = new LazyState(); + currentState = new State(); + stack = new ArrayList(); + this.gc = gc; + init(); +} + +/** + * If the background color has changed, this change will be pushed to the GC. Also calls + * {@link #checkGC()}. + */ +protected final void checkFill() { + if (!currentState.bgColor.opEquals(appliedState.bgColor) && currentState.bgPattern is null) + gc.setBackground(appliedState.bgColor = currentState.bgColor); + checkGC(); +} + +/** + * If the rendering hints or the clip region has changed, these changes will be pushed to + * the GC. Rendering hints include anti-alias, xor, join, cap, line style, fill rule, + * interpolation, and other settings. + */ +protected /+final+/ void checkGC() { + if (appliedState.relativeClip !is currentState.relativeClip) { + appliedState.relativeClip = currentState.relativeClip; + currentState.relativeClip.setOn(gc, translateX, translateY); + } + if (appliedState.graphicHints !is currentState.graphicHints) { + reconcileHints(appliedState.graphicHints, currentState.graphicHints); + appliedState.graphicHints = currentState.graphicHints; + } +} + +/** + * If the line width, line style, foreground or background colors have changed, these + * changes will be pushed to the GC. Also calls {@link #checkGC()}. + */ +protected /+final+/ void checkPaint() { + checkGC(); + if (!currentState.fgColor.opEquals(appliedState.fgColor) && currentState.fgPattern is null) + gc.setForeground(appliedState.fgColor = currentState.fgColor); + if (appliedState.lineWidth !is currentState.lineWidth) + gc.setLineWidth(appliedState.lineWidth = currentState.lineWidth); + if (!currentState.bgColor.opEquals(appliedState.bgColor) && currentState.bgPattern is null) + gc.setBackground(appliedState.bgColor = currentState.bgColor); +} + +/** + * @since 3.1 + */ +private void checkSharedClipping() { + if (sharedClipping) { + sharedClipping = false; + + bool previouslyApplied = (appliedState is currentState.relativeClip); + currentState.relativeClip = currentState.relativeClip.getCopy(); + if (previouslyApplied) + appliedState.relativeClip = currentState.relativeClip; + } +} + +/** + * If the font has changed, this change will be pushed to the GC. Also calls + * {@link #checkPaint()} and {@link #checkFill()}. + */ +protected /+final+/ void checkText() { + checkPaint(); + if (!appliedState.font.opEquals(currentState.font)) + gc.setFont(appliedState.font = currentState.font); +} + +/** + * @see Graphics#clipRect(Rectangle) + */ +public void clipRect(Rectangle rect) { + if (currentState.relativeClip is null) + throw new IllegalStateException("The current clipping area does not " //$NON-NLS-1$ + "support intersection."); //$NON-NLS-1$ + checkSharedClipping(); + currentState.relativeClip.intersect(rect.x, rect.y, rect.right(), rect.bottom()); + appliedState.relativeClip = null; +} + +/** + * @see Graphics#dispose() + */ +public void dispose() { + while (stackPointer > 0) + popState(); + if (transform !is null) + transform.dispose(); +} + +/** + * @see Graphics#drawArc(int, int, int, int, int, int) + */ +public void drawArc(int x, int y, int width, int height, int offset, int length) { + checkPaint(); + gc.drawArc(x + translateX, y + translateY, width, height, offset, length); +} + +/** + * @see Graphics#drawFocus(int, int, int, int) + */ +public void drawFocus(int x, int y, int w, int h) { + checkPaint(); + gc.drawFocus(x + translateX, y + translateY, w + 1, h + 1); +} + +/** + * @see Graphics#drawImage(Image, int, int) + */ +public void drawImage(Image srcImage, int x, int y) { + checkGC(); + gc.drawImage(srcImage, x + translateX, y + translateY); +} + +/** + * @see Graphics#drawImage(Image, int, int, int, int, int, int, int, int) + */ +public void drawImage(Image srcImage, + int x1, int y1, int w1, int h1, + int x2, int y2, int w2, int h2) { + checkGC(); + gc.drawImage(srcImage, x1, y1, w1, h1, x2 + translateX, y2 + translateY, w2, h2); +} + +/** + * @see Graphics#drawLine(int, int, int, int) + */ +public void drawLine(int x1, int y1, int x2, int y2) { + checkPaint(); + gc.drawLine(x1 + translateX, y1 + translateY, x2 + translateX, y2 + translateY); +} + +/** + * @see Graphics#drawOval(int, int, int, int) + */ +public void drawOval(int x, int y, int width, int height) { + checkPaint(); + gc.drawOval(x + translateX, y + translateY, width, height); +} + +/** + * This method requires advanced graphics support. A check should be made to + * ensure advanced graphics is supported in the user's environment before + * calling this method. See {@link GC#getAdvanced()}. + * + * @see Graphics#drawPath(Path) + */ +public void drawPath(Path path) { + checkPaint(); + initTransform(false); + gc.drawPath(path); +} + +/** + * @see Graphics#drawPoint(int, int) + */ +public void drawPoint(int x, int y) { + checkPaint(); + gc.drawPoint(x + translateX, y + translateY); +} + +/** + * @see Graphics#drawPolygon(int[]) + */ +public void drawPolygon(int[] points) { + checkPaint(); + try { + translatePointArray(points, translateX, translateY); + gc.drawPolygon(points); + } finally { + translatePointArray(points, -translateX, -translateY); + } +} + +/** + * @see Graphics#drawPolygon(PointList) + */ +public void drawPolygon(PointList points) { + drawPolygon(points.toIntArray()); +} + +/** + * @see Graphics#drawPolyline(int[]) + */ +public void drawPolyline(int[] points) { + checkPaint(); + try { + translatePointArray(points, translateX, translateY); + gc.drawPolyline(points); + } finally { + translatePointArray(points, -translateX, -translateY); + } +} + +/** + * @see Graphics#drawPolyline(PointList) + */ +public void drawPolyline(PointList points) { + drawPolyline(points.toIntArray()); +} + +/** + * @see Graphics#drawRectangle(int, int, int, int) + */ +public void drawRectangle(int x, int y, int width, int height) { + checkPaint(); + gc.drawRectangle(x + translateX, y + translateY, width, height); +} + +/** + * @see Graphics#drawRoundRectangle(Rectangle, int, int) + */ +public void drawRoundRectangle(Rectangle r, int arcWidth, int arcHeight) { + checkPaint(); + gc.drawRoundRectangle(r.x + translateX, r.y + translateY, r.width, r.height, + arcWidth, arcHeight); +} + +/** + * @see Graphics#drawString(String, int, int) + */ +public void drawString(String s, int x, int y) { + checkText(); + gc.drawString(s, x + translateX, y + translateY, true); +} + +/** + * @see Graphics#drawText(String, int, int) + */ +public void drawText(String s, int x, int y) { + checkText(); + gc.drawText(s, x + translateX, y + translateY, true); +} + +/** + * @see Graphics#drawTextLayout(TextLayout, int, int, int, int, Color, Color) + */ +public void drawTextLayout(TextLayout layout, int x, int y, int selectionStart, + int selectionEnd, Color selectionForeground, Color selectionBackground) { + //$TODO probably just call checkPaint since Font and BG color don't apply + checkText(); + layout.draw(gc, x + translateX, y + translateY, selectionStart, selectionEnd, + selectionForeground, selectionBackground); +} + +/** + * @see Graphics#fillArc(int, int, int, int, int, int) + */ +public void fillArc(int x, int y, int width, int height, int offset, int length) { + checkFill(); + gc.fillArc(x + translateX, y + translateY, width, height, offset, length); +} + +/** + * @see Graphics#fillGradient(int, int, int, int, bool) + */ +public void fillGradient(int x, int y, int w, int h, bool vertical) { + checkPaint(); + gc.fillGradientRectangle(x + translateX, y + translateY, w, h, vertical); +} + +/** + * @see Graphics#fillOval(int, int, int, int) + */ +public void fillOval(int x, int y, int width, int height) { + checkFill(); + gc.fillOval(x + translateX, y + translateY, width, height); +} + +/** + * This method requires advanced graphics support. A check should be made to + * ensure advanced graphics is supported in the user's environment before + * calling this method. See {@link GC#getAdvanced()}. + * + * @see Graphics#fillPath(Path) + */ +public void fillPath(Path path) { + checkFill(); + initTransform(false); + gc.fillPath(path); +} + +/** + * @see Graphics#fillPolygon(int[]) + */ +public void fillPolygon(int[] points) { + checkFill(); + try { + translatePointArray(points, translateX, translateY); + gc.fillPolygon(points); + } finally { + translatePointArray(points, -translateX, -translateY); + } +} + +/** + * @see Graphics#fillPolygon(PointList) + */ +public void fillPolygon(PointList points) { + fillPolygon(points.toIntArray()); +} + +/** + * @see Graphics#fillRectangle(int, int, int, int) + */ +public void fillRectangle(int x, int y, int width, int height) { + checkFill(); + gc.fillRectangle(x + translateX, y + translateY, width, height); +} + +/** + * @see Graphics#fillRoundRectangle(Rectangle, int, int) + */ +public void fillRoundRectangle(Rectangle r, int arcWidth, int arcHeight) { + checkFill(); + gc.fillRoundRectangle(r.x + translateX, r.y + translateY, r.width, r.height, + arcWidth, arcHeight); +} + +/** + * @see Graphics#fillString(String, int, int) + */ +public void fillString(String s, int x, int y) { + checkText(); + gc.drawString(s, x + translateX, y + translateY, false); +} + +/** + * @see Graphics#fillText(String, int, int) + */ +public void fillText(String s, int x, int y) { + checkText(); + gc.drawText(s, x + translateX, y + translateY, false); +} + +/** + * @see Graphics#getAlpha() + */ +public int getAlpha() { + return currentState.alpha; +} + +/** + * @see Graphics#getAntialias() + */ +public int getAntialias() { + return ((currentState.graphicHints & AA_MASK) >> AA_SHIFT) - AA_WHOLE_NUMBER; +} + +/** + * @see Graphics#getBackgroundColor() + */ +public Color getBackgroundColor() { + return currentState.bgColor; +} + +/** + * @see Graphics#getClip(Rectangle) + */ +public Rectangle getClip(Rectangle rect) { + if (currentState.relativeClip !is null) { + currentState.relativeClip.getBoundingBox(rect); + return rect; + } + throw new IllegalStateException( + "Clipping can no longer be queried due to transformations"); //$NON-NLS-1$ +} + +/** + * @see Graphics#getFillRule() + */ +public int getFillRule() { + return ((currentState.graphicHints & FILL_RULE_MASK) >> FILL_RULE_SHIFT) - FILL_RULE_WHOLE_NUMBER; +} + +/** + * @see Graphics#getFont() + */ +public Font getFont() { + return currentState.font; +} + +/** + * @see Graphics#getFontMetrics() + */ +public FontMetrics getFontMetrics() { + checkText(); + return gc.getFontMetrics(); +} + +/** + * @see Graphics#getForegroundColor() + */ +public Color getForegroundColor() { + return currentState.fgColor; +} + +/** + * @see Graphics#getInterpolation() + */ +public int getInterpolation() { + return ((currentState.graphicHints & INTERPOLATION_MASK) >> INTERPOLATION_SHIFT) + - INTERPOLATION_WHOLE_NUMBER; +} + +/** + * @see Graphics#getLineCap() + */ +public int getLineCap() { + return (currentState.graphicHints & CAP_MASK) >> CAP_SHIFT; +} + +/** + * @see Graphics#getLineJoin() + */ +public int getLineJoin() { + return (currentState.graphicHints & JOIN_MASK) >> JOIN_SHIFT; +} + +/** + * @see Graphics#getLineStyle() + */ +public int getLineStyle() { + return currentState.graphicHints & LINE_STYLE_MASK; +} + +/** + * @see Graphics#getLineWidth() + */ +public int getLineWidth() { + return currentState.lineWidth; +} + +/** + * @see Graphics#getTextAntialias() + */ +public int getTextAntialias() { + return ((currentState.graphicHints & TEXT_AA_MASK) >> TEXT_AA_SHIFT) - AA_WHOLE_NUMBER; +} + +/** + * @see Graphics#getXORMode() + */ +public bool getXORMode() { + return (currentState.graphicHints & XOR_MASK) !is 0; +} + +/** + * Called by constructor, initializes all State information for currentState + */ +protected void init() { + currentState.bgColor = appliedState.bgColor = gc.getBackground(); + currentState.fgColor = appliedState.fgColor = gc.getForeground(); + currentState.font = appliedState.font = gc.getFont(); + currentState.lineWidth = appliedState.lineWidth = gc.getLineWidth(); + currentState.graphicHints |= gc.getLineStyle(); + currentState.graphicHints |= gc.getLineCap() << CAP_SHIFT; + currentState.graphicHints |= gc.getLineJoin() << JOIN_SHIFT; + currentState.graphicHints |= gc.getAdvanced() ? ADVANCED_GRAPHICS_MASK : 0; + currentState.graphicHints |= gc.getXORMode() ? XOR_MASK : 0; + + appliedState.graphicHints = currentState.graphicHints; + + currentState.relativeClip = new RectangleClipping(gc.getClipping()); + currentState.lineDash = gc.getLineDash(); + currentState.alpha = gc.getAlpha(); +} + +private void initTransform(bool force) { + if (!force && translateX is 0 && translateY is 0) + return; + if (transform is null) { + transform = new Transform(Display.getCurrent()); + elementsNeedUpdate = true; + transform.translate(translateX, translateY); + translateX = 0; + translateY = 0; + gc.setTransform(transform); + currentState.graphicHints |= ADVANCED_GRAPHICS_MASK; + } +} + +/** + * @see Graphics#popState() + */ +public void popState() { + stackPointer--; + restoreState(cast(State)stack.get(stackPointer)); +} + +/** + * @see Graphics#pushState() + */ +public void pushState() { + if (currentState.relativeClip is null) + throw new IllegalStateException("The clipping has been modified in" //$NON-NLS-1$ + "a way that cannot be saved and restored."); //$NON-NLS-1$ +// try { + State s; + currentState.dx = translateX; + currentState.dy = translateY; + + if (elementsNeedUpdate) { + elementsNeedUpdate = false; + transform.getElements(currentState.affineMatrix = new float[6]); + } + if (stack.size() > stackPointer) { + s = cast(State)stack.get(stackPointer); + s.copyFrom(currentState); + } else { + stack.add(currentState.clone()); + } + sharedClipping = true; + stackPointer++; +// } catch (CloneNotSupportedException e) { +// throw new RuntimeException(e); +// } +} + +private void reconcileHints(int applied, int hints) { + if (applied !is hints) { + int changes = hints ^ applied; + + if ((changes & LINE_STYLE_MASK) !is 0) + gc.setLineStyle(hints & LINE_STYLE_MASK); + + if ((changes & XOR_MASK) !is 0) + gc.setXORMode((hints & XOR_MASK) !is 0); + + //Check to see if there is anything remaining + changes &= ~(XOR_MASK | LINE_STYLE_MASK); + if (changes is 0) + return; + + if ((changes & JOIN_MASK) !is 0) + gc.setLineJoin((hints & JOIN_MASK) >> JOIN_SHIFT); + if ((changes & CAP_MASK) !is 0) + gc.setLineCap((hints & CAP_MASK) >> CAP_SHIFT); + + if ((changes & INTERPOLATION_MASK) !is 0) + gc.setInterpolation(((hints & INTERPOLATION_MASK) >> INTERPOLATION_SHIFT) - INTERPOLATION_WHOLE_NUMBER); + + if ((changes & FILL_RULE_MASK) !is 0) + gc.setFillRule(((hints & FILL_RULE_MASK) >> FILL_RULE_SHIFT) - FILL_RULE_WHOLE_NUMBER); + + if ((changes & AA_MASK) !is 0) + gc.setAntialias(((hints & AA_MASK) >> AA_SHIFT) - AA_WHOLE_NUMBER); + if ((changes & TEXT_AA_MASK) !is 0) + gc.setTextAntialias(((hints & TEXT_AA_MASK) >> TEXT_AA_SHIFT) - AA_WHOLE_NUMBER); + + // If advanced was flagged, but none of the conditions which trigger advanced + // actually got applied, force advanced graphics on. + if ((changes & ADVANCED_GRAPHICS_MASK) !is 0) { + if ((hints & ADVANCED_GRAPHICS_MASK) !is 0 && !gc.getAdvanced()) + gc.setAdvanced(true); + } + } +} + +/** + * @see Graphics#restoreState() + */ +public void restoreState() { + restoreState(cast(State)stack.get(stackPointer - 1)); +} + +/** + * Sets all State information to that of the given State, called by restoreState() + * @param s the State + */ +protected void restoreState(State s) { + /* + * We must set the transformation matrix first since it affects things like clipping + * regions and patterns. + */ + setAffineMatrix(s.affineMatrix); + currentState.relativeClip = s.relativeClip; + sharedClipping = true; + + //If the GC is currently advanced, but it was not when pushed, revert + if (gc.getAdvanced() && (s.graphicHints & ADVANCED_GRAPHICS_MASK) is 0) { + //Set applied clip to null to force a re-setting of the clipping. + appliedState.relativeClip = null; + gc.setAdvanced(false); + appliedState.graphicHints &= ~ADVANCED_HINTS_MASK; + appliedState.graphicHints |= ADVANCED_HINTS_DEFAULTS; + } + + setBackgroundColor(s.bgColor); + setBackgroundPattern(s.bgPattern); + + setForegroundColor(s.fgColor); + setForegroundPattern(s.fgPattern); + + setAlpha(s.alpha); + setLineWidth(s.lineWidth); + setFont(s.font); + //This method must come last because above methods will incorrectly set advanced state + setGraphicHints(s.graphicHints); + + translateX = currentState.dx = s.dx; + translateY = currentState.dy = s.dy; +} + +/** + * This method requires advanced graphics support. A check should be made to + * ensure advanced graphics is supported in the user's environment before + * calling this method. See {@link GC#getAdvanced()}. + * + * @see Graphics#rotate(float) + */ +public void rotate(float degrees) { + //Flush clipping, patter, etc., before applying transform + checkGC(); + initTransform(true); + transform.rotate(degrees); + gc.setTransform(transform); + elementsNeedUpdate = true; + + //Can no longer operate or maintain clipping + appliedState.relativeClip = currentState.relativeClip = null; +} + +/** + * @see Graphics#scale(double) + */ +public void scale(double factor) { + scale(cast(float)factor, cast(float)factor); +} + +/** + * This method requires advanced graphics support. A check should be made to + * ensure advanced graphics is supported in the user's environment before + * calling this method. See {@link GC#getAdvanced()}. + * + * @see dwtx.draw2d.Graphics#scale(float, float) + */ +public void scale(float horizontal, float vertical) { + //Flush any clipping before scaling + checkGC(); + + initTransform(true); + transform.scale(horizontal, vertical); + gc.setTransform(transform); + elementsNeedUpdate = true; + + checkSharedClipping(); + if (currentState.relativeClip !is null) + currentState.relativeClip.scale(horizontal, vertical); +} + +private void setAffineMatrix(float[] m) { + if (!elementsNeedUpdate && currentState.affineMatrix is m) + return; + currentState.affineMatrix = m; + if (m !is null) + transform.setElements(m[0], m[1], m[2], m[3], m[4], m[5]); + else if (transform !is null) { + transform.dispose(); + transform = null; + elementsNeedUpdate = false; + } + gc.setTransform(transform); +} + +/** + * This method requires advanced graphics support. A check should be made to + * ensure advanced graphics is supported in the user's environment before + * calling this method. See {@link GC#getAdvanced()}. + * + * @see Graphics#setAlpha(int) + */ +public void setAlpha(int alpha) { + currentState.graphicHints |= ADVANCED_GRAPHICS_MASK; + if (currentState.alpha !is alpha) + gc.setAlpha(this.currentState.alpha = alpha); +} + +/** + * This method requires advanced graphics support. A check should be made to + * ensure advanced graphics is supported in the user's environment before + * calling this method. See {@link GC#getAdvanced()}. + * + * @see Graphics#setAntialias(int) + */ +public void setAntialias(int value) { + currentState.graphicHints &= ~AA_MASK; + currentState.graphicHints |= ADVANCED_GRAPHICS_MASK | (value + AA_WHOLE_NUMBER) << AA_SHIFT; +} + +/** + * @see Graphics#setBackgroundColor(Color) + */ +public void setBackgroundColor(Color color) { + currentState.bgColor = color; + if (currentState.bgPattern !is null) { + currentState.bgPattern = null; + //Force the BG color to be stale + appliedState.bgColor = null; + } +} + +/** + * @see Graphics#setBackgroundPattern(Pattern) + */ +public void setBackgroundPattern(Pattern pattern) { + currentState.graphicHints |= ADVANCED_GRAPHICS_MASK; + if (currentState.bgPattern is pattern) + return; + currentState.bgPattern = pattern; + + if (pattern !is null) + initTransform(true); + gc.setBackgroundPattern(pattern); +} + +/** + * This method requires advanced graphics support. A check should be made to + * ensure advanced graphics is supported in the user's environment before + * calling this method. See {@link GC#getAdvanced()}. + * + * @see Graphics#setClip(Path) + */ +public void setClip(Path path) { + initTransform(false); + gc.setClipping(path); + appliedState.relativeClip = currentState.relativeClip = null; +} + +/** + * @see Graphics#setClip(Rectangle) + */ +public void setClip(Rectangle rect) { + currentState.relativeClip = new RectangleClipping(rect); +} + +/** + * @see Graphics#setFillRule(int) + */ +public void setFillRule(int rule) { + currentState.graphicHints &= ~FILL_RULE_MASK; + currentState.graphicHints |= (rule + FILL_RULE_WHOLE_NUMBER) << FILL_RULE_SHIFT; +} + +/** + * @see Graphics#setFont(Font) + */ +public void setFont(Font f) { + currentState.font = f; +} + +/** + * @see Graphics#setForegroundColor(Color) + */ +public void setForegroundColor(Color color) { + currentState.fgColor = color; + if (currentState.fgPattern !is null) { + currentState.fgPattern = null; + //Force fgColor to be stale + appliedState.fgColor = null; + } +} + +/** + * @see Graphics#setForegroundPattern(Pattern) + */ +public void setForegroundPattern(Pattern pattern) { + currentState.graphicHints |= ADVANCED_GRAPHICS_MASK; + if (currentState.fgPattern is pattern) + return; + currentState.fgPattern = pattern; + + if (pattern !is null) + initTransform(true); + gc.setForegroundPattern(pattern); +} + +private void setGraphicHints(int hints) { + currentState.graphicHints = hints; +} + +/** + * This method requires advanced graphics support. A check should be made to + * ensure advanced graphics is supported in the user's environment before + * calling this method. See {@link GC#getAdvanced()}. + * + * @see Graphics#setInterpolation(int) + */ +public void setInterpolation(int interpolation) { + //values range [-1, 3] + currentState.graphicHints &= ~INTERPOLATION_MASK; + currentState.graphicHints |= ADVANCED_GRAPHICS_MASK | (interpolation + INTERPOLATION_WHOLE_NUMBER) << INTERPOLATION_SHIFT; +} + +/** + * @see Graphics#setLineCap(int) + */ +public void setLineCap(int cap) { + currentState.graphicHints &= ~CAP_MASK; + currentState.graphicHints |= cap << CAP_SHIFT; +} + +/** + * @see Graphics#setLineDash(int[]) + */ +public void setLineDash(int[] dashes) { + if (dashes !is null) { + int copy[] = new int[dashes.length]; + for (int i = 0; i < dashes.length; i++) { + int dash = dashes[i]; + if (dash <= 0) + DWT.error(DWT.ERROR_INVALID_ARGUMENT); + copy[i] = dash; + } + currentState.lineDash = copy; + setLineStyle(DWT.LINE_CUSTOM); + gc.setLineDash(copy); + } else { + currentState.lineDash = null; + setLineStyle(DWT.LINE_SOLID); + } +} + +/** + * @see Graphics#setLineJoin(int) + */ +public void setLineJoin(int join) { + currentState.graphicHints &= ~JOIN_MASK; + currentState.graphicHints |= join << JOIN_SHIFT; +} + +/** + * @see Graphics#setLineStyle(int) + */ +public void setLineStyle(int style) { + currentState.graphicHints &= ~LINE_STYLE_MASK; + currentState.graphicHints |= style; +} + +/** + * @see Graphics#setLineWidth(int) + */ +public void setLineWidth(int width) { + currentState.lineWidth = width; +} + +/** + * This method requires advanced graphics support. A check should be made to + * ensure advanced graphics is supported in the user's environment before + * calling this method. See {@link GC#getAdvanced()}. + * + * @see Graphics#setTextAntialias(int) + */ +public void setTextAntialias(int value) { + currentState.graphicHints &= ~TEXT_AA_MASK; + currentState.graphicHints |= ADVANCED_GRAPHICS_MASK | (value + AA_WHOLE_NUMBER) << TEXT_AA_SHIFT; +} + +/** + * @see Graphics#setXORMode(bool) + */ +public void setXORMode(bool xor) { + currentState.graphicHints &= ~XOR_MASK; + if (xor) + currentState.graphicHints |= XOR_MASK; +} + +/** + * This method requires advanced graphics support. A check should be made to + * ensure advanced graphics is supported in the user's environment before + * calling this method. See {@link GC#getAdvanced()}. + * + * @see Graphics#shear(float, float) + */ +public void shear(float horz, float vert) { + //Flush any clipping changes before shearing + checkGC(); + initTransform(true); + float matrix[] = new float[6]; + transform.getElements(matrix); + transform.setElements( + matrix[0] + matrix[2] * vert, + matrix[1] + matrix[3] * vert, + matrix[0] * horz + matrix[2], + matrix[1] * horz + matrix[3], + matrix[4], + matrix[5]); + + gc.setTransform(transform); + elementsNeedUpdate = true; + //Can no longer track clipping changes + appliedState.relativeClip = currentState.relativeClip = null; +} + +/** + * This method may require advanced graphics support if using a transform, + * in this case, a check should be made to ensure advanced graphics is + * supported in the user's environment before calling this method. See + * {@link GC#getAdvanced()}. + * + * @see Graphics#translate(int, int) + */ +public void translate(int dx, int dy) { + if (dx is 0 && dy is 0) + return; + if (transform !is null) { + //Flush clipping, pattern, etc. before applying transform + checkGC(); + transform.translate(dx, dy); + elementsNeedUpdate = true; + gc.setTransform(transform); + } else { + translateX += dx; + translateY += dy; + } + checkSharedClipping(); + if (currentState.relativeClip !is null) + currentState.relativeClip.translate(-dx, -dy); +} + +/** + * This method requires advanced graphics support. A check should be made to + * ensure advanced graphics is supported in the user's environment before + * calling this method. See {@link GC#getAdvanced()}. + * + * @see Graphics#translate(float, float) + */ +public void translate(float dx, float dy) { + initTransform(true); + checkGC(); + transform.translate(dx, dy); + elementsNeedUpdate = true; + gc.setTransform(transform); + checkSharedClipping(); + if (currentState.relativeClip !is null) + currentState.relativeClip.translate(-dx, -dy); +} + +private void translatePointArray(int[] points, int translateX, int translateY) { + if (translateX is 0 && translateY is 0) + return; + for (int i = 0; (i + 1) < points.length; i += 2) { + points[i] += translateX; + points[i + 1] += translateY; + } +} + +}