package com.kreative.paint; import java.awt.Color; import java.awt.Cursor; import java.awt.Font; import java.awt.FontMetrics; import java.awt.Graphics2D; import java.awt.Image; import java.awt.image.BufferedImage; import java.math.BigDecimal; import java.math.BigInteger; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Random; import com.kreative.paint.material.MaterialList; import com.kreative.paint.material.MaterialManager; import com.kreative.paint.material.alphabet.Alphabet; import com.kreative.paint.material.frame.Frame; import com.kreative.paint.material.shape.PowerShape; import com.kreative.paint.material.shape.PowerShapeList; import com.kreative.paint.material.sprite.Sprite; import com.kreative.paint.material.sprite.SpriteSheet; import com.kreative.paint.powerbrush.BrushSettings; import com.kreative.paint.powerbrush.BrushShape; import com.kreative.paint.tool.Tool; import com.kreative.paint.util.CursorUtils; public class ToolContext implements ToolContextConstants { // tool private boolean drawMode; private Tool tool; // general draw options private boolean drawPerpendicular; private boolean drawSquare; private boolean drawFromCenter; private boolean drawFilled; private boolean drawMultiple; // corner radius private float cornerRadiusX; private float cornerRadiusY; // QuickShadow private int shadowType; private int shadowOpacity; private int shadowXOffset; private int shadowYOffset; // PowerBrush private BrushSettings powerBrushSettings; private BrushShape powerBrushShape; private float powerBrushOuterWidth; private float powerBrushOuterHeight; private float powerBrushInnerWidth; private float powerBrushInnerHeight; private int powerBrushFlowRate; // curl private double curlRadius; private double curlSpacing; // polygon private int polygonSides; private int polygonStellation; // alphabets private MaterialList<Alphabet> alphabets; private int alphabetIndex; private Alphabet alphabet; private int letterIndex; private int letter; private BufferedImage letterImage; private Cursor letterCursor; // brushes private MaterialList<SpriteSheet> brushSets; private int brushSetIndex; private List<Sprite> brushes; private int brushIndex; private Sprite brush; // calligraphy brushes private List<Sprite> calligraphyBrushes; private int calligraphyBrushIndex; private Sprite calligraphyBrush; private boolean calligraphyContinuous; // charcoal brushes private List<Sprite> charcoalBrushes; private int charcoalBrushIndex; private Sprite charcoalBrush; // frames private MaterialList<Frame> frames; private int frameIndex; private Frame frame; // rubber stamps private MaterialList<SpriteSheet> rubberStampSets; private int rubberStampSetIndex; private List<Sprite> rubberStamps; private int rubberStampIndex; private Sprite rubberStamp; // PowerShapes private MaterialList<PowerShapeList> powerShapeSets; private int powerShapeSetIndex; private PowerShapeList powerShapes; private int powerShapeIndex; private PowerShape powerShape; // sprinkles private List<Sprite> sprinkleSets; private int sprinkleSetIndex; private Sprite sprinkles; private int sprinkleIndex; private Sprite sprinkle; private boolean sprinkleBrushMode; // custom private HashMap<String,Object> custom; // listeners private Random random; private HashSet<ToolContextListener> listeners; public ToolContext(MaterialManager mm) { // tool this.drawMode = false; this.tool = null; // general draw options this.drawPerpendicular = false; this.drawSquare = false; this.drawFromCenter = false; this.drawFilled = false; this.drawMultiple = false; // corner radius this.cornerRadiusX = 16f; this.cornerRadiusY = 16f; // QuickShadow this.shadowType = 0; this.shadowOpacity = 255; this.shadowXOffset = 5; this.shadowYOffset = 5; // PowerBrush this.powerBrushSettings = new BrushSettings(); this.powerBrushShape = this.powerBrushSettings.getBrushShape(); this.powerBrushOuterWidth = this.powerBrushSettings.getOuterWidth(); this.powerBrushOuterHeight = this.powerBrushSettings.getOuterHeight(); this.powerBrushInnerWidth = this.powerBrushSettings.getInnerWidth(); this.powerBrushInnerHeight = this.powerBrushSettings.getInnerHeight(); this.powerBrushFlowRate = this.powerBrushSettings.getFlowRate(); // curl this.curlRadius = 10.0; this.curlSpacing = 20.0; // polygon this.polygonSides = 6; this.polygonStellation = 1; // alphabets this.alphabets = mm.alphabetLoader().getAlphabets(); this.alphabetIndex = 0; this.alphabet = this.alphabets.getValue(0); this.letterIndex = 0; this.letter = this.alphabet.letters[0]; setLetterImageAndCursor(); // brushes this.brushSets = mm.spriteLoader().getBrushes(); this.brushSetIndex = 0; this.brushes = this.brushSets.getValue(0).getSprites(); this.brushIndex = 0; this.brush = this.brushes.get(0); // calligraphy brushes this.calligraphyBrushes = new ArrayList<Sprite>(); for (SpriteSheet ss : mm.spriteLoader().getCalligraphyBrushes().valueList()) { this.calligraphyBrushes.addAll(ss.getSprites()); } this.calligraphyBrushIndex = 0; this.calligraphyBrush = this.calligraphyBrushes.get(0); this.calligraphyContinuous = false; // charcoal brushes this.charcoalBrushes = new ArrayList<Sprite>(); for (SpriteSheet ss : mm.spriteLoader().getCharcoalBrushes().valueList()) { this.charcoalBrushes.addAll(ss.getSprites()); } this.charcoalBrushIndex = 0; this.charcoalBrush = this.charcoalBrushes.get(0); // frames this.frames = mm.frameLoader().getFrames(); this.frameIndex = 0; this.frame = frames.getValue(0); // rubber stamps this.rubberStampSets = mm.spriteLoader().getRubberStamps(); this.rubberStampSetIndex = 0; this.rubberStamps = this.rubberStampSets.getValue(0).getSprites(); this.rubberStampIndex = 0; this.rubberStamp = this.rubberStamps.get(0); // PowerShapes this.powerShapeSets = mm.shapeLoader().getShapes(); this.powerShapeSetIndex = 0; this.powerShapes = this.powerShapeSets.getValue(0); this.powerShapeIndex = 0; this.powerShape = this.powerShapes.get(0); // sprinkles this.sprinkleSets = new ArrayList<Sprite>(); for (SpriteSheet ss : mm.spriteLoader().getSprinkles().valueList()) { this.sprinkleSets.addAll(ss.getSprites()); } this.sprinkleSetIndex = 0; this.sprinkles = this.sprinkleSets.get(0); this.sprinkleIndex = 0; this.sprinkle = this.sprinkles.getChild(0); this.sprinkleBrushMode = false; // custom this.custom = new HashMap<String,Object>(); // listeners this.random = new Random(); this.listeners = new HashSet<ToolContextListener>(); } // tool public boolean isInPaintMode() { return !drawMode; } public boolean isInDrawMode() { return drawMode; } public Tool getTool() { return tool; } public void setPaintMode(boolean paintMode) { this.drawMode = !paintMode; for (ToolContextListener l : listeners) { l.modeChanged(this, !paintMode); } } public void setDrawMode(boolean drawMode) { this.drawMode = drawMode; for (ToolContextListener l : listeners) { l.modeChanged(this, drawMode); } } public void setTool(Tool tool) { Tool prevtool = this.tool; this.tool = tool; for (ToolContextListener l : listeners) { l.toolChanged(this, prevtool, tool); } } public void doubleClickTool(Tool tool) { for (ToolContextListener l : listeners) { l.toolDoubleClicked(this, tool); } } // general draw options public boolean drawPerpendicular() { return drawPerpendicular; } public boolean drawSquare() { return drawSquare; } public boolean drawFromCenter() { return drawFromCenter; } public boolean drawFilled() { return drawFilled; } public boolean drawMultiple() { return drawMultiple; } public void setDrawPerpendicular(boolean drawPerpendicular) { this.drawPerpendicular = drawPerpendicular; notifyToolContextListeners(CHANGED_DRAW_PERPENDICULAR); } public void setDrawSquare(boolean drawSquare) { this.drawSquare = drawSquare; notifyToolContextListeners(CHANGED_DRAW_SQUARE); } public void setDrawFromCenter(boolean drawFromCenter) { this.drawFromCenter = drawFromCenter; notifyToolContextListeners(CHANGED_DRAW_CENTER); } public void setDrawFilled(boolean drawFilled) { this.drawFilled = drawFilled; notifyToolContextListeners(CHANGED_DRAW_FILLED); } public void setDrawMultiple(boolean drawMultiple) { this.drawMultiple = drawMultiple; notifyToolContextListeners(CHANGED_DRAW_MULTIPLE); } // corner radius public float getCornerRadiusX() { return cornerRadiusX; } public float getCornerRadiusY() { return cornerRadiusY; } public void setCornerRadiusX(float cornerRadiusX) { this.cornerRadiusX = cornerRadiusX; notifyToolContextListeners(CHANGED_CORNER_RADIUS_X); } public void setCornerRadiusY(float cornerRadiusY) { this.cornerRadiusY = cornerRadiusY; notifyToolContextListeners(CHANGED_CORNER_RADIUS_Y); } // QuickShadow public boolean useShadow() { return (shadowType != 0 && shadowOpacity != 0 && (shadowXOffset != 0 || shadowYOffset != 0)); } public int getShadowType() { return shadowType; } public int getShadowOpacity() { return shadowOpacity; } public int getShadowXOffset() { return shadowXOffset; } public int getShadowYOffset() { return shadowYOffset; } public void setShadowType(int shadowType) { this.shadowType = shadowType; notifyToolContextListeners(CHANGED_QUICKSHADOW_TYPE); } public void setShadowOpacity(int shadowOpacity) { this.shadowOpacity = shadowOpacity; notifyToolContextListeners(CHANGED_QUICKSHADOW_OPACITY); } public void setShadowXOffset(int shadowXOffset) { this.shadowXOffset = shadowXOffset; notifyToolContextListeners(CHANGED_QUICKSHADOW_X); } public void setShadowYOffset(int shadowYOffset) { this.shadowYOffset = shadowYOffset; notifyToolContextListeners(CHANGED_QUICKSHADOW_Y); } // PowerBrush public BrushSettings getPowerBrushSettings() { return powerBrushSettings; } public BrushShape getPowerBrushShape() { return powerBrushShape; } public float getPowerBrushOuterWidth() { return powerBrushOuterWidth; } public float getPowerBrushOuterHeight() { return powerBrushOuterHeight; } public float getPowerBrushInnerWidth() { return powerBrushInnerWidth; } public float getPowerBrushInnerHeight() { return powerBrushInnerHeight; } public int getPowerBrushFlowRate() { return powerBrushFlowRate; } public void setPowerBrushSettings(BrushSettings powerBrushSettings) { this.powerBrushSettings = powerBrushSettings; this.powerBrushShape = powerBrushSettings.getBrushShape(); this.powerBrushOuterWidth = powerBrushSettings.getOuterWidth(); this.powerBrushOuterHeight = powerBrushSettings.getOuterHeight(); this.powerBrushInnerWidth = powerBrushSettings.getInnerWidth(); this.powerBrushInnerHeight = powerBrushSettings.getInnerHeight(); this.powerBrushFlowRate = powerBrushSettings.getFlowRate(); notifyToolContextListeners(CHANGED_POWERBRUSH_SHAPE | CHANGED_POWERBRUSH_OUTER_SIZE | CHANGED_POWERBRUSH_INNER_SIZE | CHANGED_POWERBRUSH_FLOW_RATE); } public void setPowerBrushShape(BrushShape powerBrushShape) { this.powerBrushSettings = new BrushSettings(powerBrushShape, powerBrushOuterWidth, powerBrushOuterHeight, powerBrushInnerWidth, powerBrushInnerHeight, powerBrushFlowRate); this.powerBrushShape = powerBrushShape; notifyToolContextListeners(CHANGED_POWERBRUSH_SHAPE); } public void setPowerBrushOuterWidth(float powerBrushOuterWidth) { this.powerBrushSettings = new BrushSettings(powerBrushShape, powerBrushOuterWidth, powerBrushOuterHeight, powerBrushInnerWidth, powerBrushInnerHeight, powerBrushFlowRate); this.powerBrushOuterWidth = powerBrushOuterWidth; notifyToolContextListeners(CHANGED_POWERBRUSH_OUTER_SIZE); } public void setPowerBrushOuterHeight(float powerBrushOuterHeight) { this.powerBrushSettings = new BrushSettings(powerBrushShape, powerBrushOuterWidth, powerBrushOuterHeight, powerBrushInnerWidth, powerBrushInnerHeight, powerBrushFlowRate); this.powerBrushOuterHeight = powerBrushOuterHeight; notifyToolContextListeners(CHANGED_POWERBRUSH_OUTER_SIZE); } public void setPowerBrushInnerWidth(float powerBrushInnerWidth) { this.powerBrushSettings = new BrushSettings(powerBrushShape, powerBrushOuterWidth, powerBrushOuterHeight, powerBrushInnerWidth, powerBrushInnerHeight, powerBrushFlowRate); this.powerBrushInnerWidth = powerBrushInnerWidth; notifyToolContextListeners(CHANGED_POWERBRUSH_INNER_SIZE); } public void setPowerBrushInnerHeight(float powerBrushInnerHeight) { this.powerBrushSettings = new BrushSettings(powerBrushShape, powerBrushOuterWidth, powerBrushOuterHeight, powerBrushInnerWidth, powerBrushInnerHeight, powerBrushFlowRate); this.powerBrushInnerHeight = powerBrushInnerHeight; notifyToolContextListeners(CHANGED_POWERBRUSH_INNER_SIZE); } public void setPowerBrushFlowRate(int powerBrushFlowRate) { this.powerBrushSettings = new BrushSettings(powerBrushShape, powerBrushOuterWidth, powerBrushOuterHeight, powerBrushInnerWidth, powerBrushInnerHeight, powerBrushFlowRate); this.powerBrushFlowRate = powerBrushFlowRate; notifyToolContextListeners(CHANGED_POWERBRUSH_FLOW_RATE); } public void decrementPowerBrush() { if (powerBrushOuterWidth >= 2.0 && powerBrushOuterHeight >= 2.0 && powerBrushInnerWidth >= 1.0 && powerBrushInnerHeight >= 1.0) { powerBrushOuterWidth--; powerBrushOuterHeight--; powerBrushInnerWidth--; powerBrushInnerHeight--; powerBrushSettings = new BrushSettings(powerBrushShape, powerBrushOuterWidth, powerBrushOuterHeight, powerBrushInnerWidth, powerBrushInnerHeight, powerBrushFlowRate); notifyToolContextListeners(CHANGED_POWERBRUSH_OUTER_SIZE | CHANGED_POWERBRUSH_INNER_SIZE); } } public void incrementPowerBrush() { powerBrushOuterWidth++; powerBrushOuterHeight++; powerBrushInnerWidth++; powerBrushInnerHeight++; powerBrushSettings = new BrushSettings(powerBrushShape, powerBrushOuterWidth, powerBrushOuterHeight, powerBrushInnerWidth, powerBrushInnerHeight, powerBrushFlowRate); notifyToolContextListeners(CHANGED_POWERBRUSH_OUTER_SIZE | CHANGED_POWERBRUSH_INNER_SIZE); } public void decrementPowerBrushOuterOnly() { if (powerBrushOuterWidth >= 2.0 && powerBrushOuterHeight >= 2.0) { powerBrushOuterWidth--; powerBrushOuterHeight--; powerBrushInnerWidth = powerBrushOuterWidth; powerBrushInnerHeight = powerBrushOuterHeight; powerBrushSettings = new BrushSettings(powerBrushShape, powerBrushOuterWidth, powerBrushOuterHeight, powerBrushInnerWidth, powerBrushInnerHeight, powerBrushFlowRate); notifyToolContextListeners(CHANGED_POWERBRUSH_OUTER_SIZE | CHANGED_POWERBRUSH_INNER_SIZE); } } public void incrementPowerBrushOuterOnly() { powerBrushOuterWidth++; powerBrushOuterHeight++; powerBrushInnerWidth = powerBrushOuterWidth; powerBrushInnerHeight = powerBrushOuterHeight; powerBrushSettings = new BrushSettings(powerBrushShape, powerBrushOuterWidth, powerBrushOuterHeight, powerBrushInnerWidth, powerBrushInnerHeight, powerBrushFlowRate); notifyToolContextListeners(CHANGED_POWERBRUSH_OUTER_SIZE | CHANGED_POWERBRUSH_INNER_SIZE); } // curl public double getCurlRadius() { return Math.abs(curlRadius); } public double getCurlSpacing() { return Math.abs(curlSpacing); } public boolean getCurlCCW() { return (curlRadius < 0) != (curlSpacing < 0); } public double getRawCurlRadius() { return curlRadius; } public double getRawCurlSpacing() { return curlSpacing; } public void setCurlRadius(double curlRadius) { this.curlRadius = (this.curlRadius < 0) ? -Math.abs(curlRadius) : Math.abs(curlRadius); notifyToolContextListeners(CHANGED_CURL_RADIUS); } public void decrementCurlRadius() { if (curlRadius <= -2) curlRadius++; else if (curlRadius >= 2) curlRadius--; notifyToolContextListeners(CHANGED_CURL_RADIUS); } public void incrementCurlRadius() { if (curlRadius < 0) curlRadius--; else if (curlRadius > 0) curlRadius++; notifyToolContextListeners(CHANGED_CURL_RADIUS); } public void setCurlSpacing(double curlSpacing) { this.curlSpacing = (this.curlSpacing < 0) ? -Math.abs(curlSpacing) : Math.abs(curlSpacing); notifyToolContextListeners(CHANGED_CURL_SPACING); } public void decrementCurlSpacing() { if (curlSpacing <= -2) curlSpacing++; else if (curlSpacing >= 2) curlSpacing--; notifyToolContextListeners(CHANGED_CURL_SPACING); } public void incrementCurlSpacing() { if (curlSpacing < 0) curlSpacing--; else if (curlSpacing > 0) curlSpacing++; notifyToolContextListeners(CHANGED_CURL_SPACING); } public void setCurlCCW(boolean curlCCW) { this.curlRadius = Math.abs(this.curlRadius); this.curlSpacing = curlCCW ? -Math.abs(this.curlSpacing) : Math.abs(this.curlSpacing); notifyToolContextListeners(CHANGED_CURL_RADIUS | CHANGED_CURL_SPACING); } public void toggleCurlCCW() { curlSpacing =- curlSpacing; notifyToolContextListeners(CHANGED_CURL_RADIUS | CHANGED_CURL_SPACING); } // polygon public int getPolygonSides() { return polygonSides; } public int getPolygonStellation() { return polygonStellation; } public void setPolygonSides(int polygonSides) { this.polygonSides = (polygonSides < 3) ? 3 : polygonSides; this.polygonStellation = (polygonStellation < 1) ? 1 : (polygonStellation > ((polygonSides-1)/2)) ? ((polygonSides-1)/2) : polygonStellation; notifyToolContextListeners(CHANGED_POLYGON_SIDES | CHANGED_POLYGON_STELLATION); } public void decrementPolygonSides() { if (polygonSides > 3) { polygonSides--; if (polygonStellation > (polygonSides-1)/2) { polygonStellation = (polygonSides-1)/2; } notifyToolContextListeners(CHANGED_POLYGON_SIDES | CHANGED_POLYGON_STELLATION); } } public void incrementPolygonSides() { polygonSides++; notifyToolContextListeners(CHANGED_POLYGON_SIDES); } public void setPolygonStellation(int polygonStellation) { this.polygonStellation = (polygonStellation < 1) ? 1 : (polygonStellation > ((polygonSides-1)/2)) ? ((polygonSides-1)/2) : polygonStellation; notifyToolContextListeners(CHANGED_POLYGON_STELLATION); } public void decrementPolygonStellation() { if (polygonStellation > 1) { polygonStellation--; notifyToolContextListeners(CHANGED_POLYGON_STELLATION); } } public void incrementPolygonStellation() { if (polygonStellation < (polygonSides-1)/2) { polygonStellation++; notifyToolContextListeners(CHANGED_POLYGON_STELLATION); } } // alphabets public MaterialList<Alphabet> getAlphabets() { return alphabets; } public String getAlphabetName() { return alphabet.name; } public int getAlphabetIndex() { return alphabetIndex; } public Alphabet getAlphabet() { return alphabet; } public int getLetterIndex() { return letterIndex; } public int getLetter() { return letter; } public Font getLetterFont() { return alphabet.font; } public Image getLetterImage() { return letterImage; } public Cursor getLetterCursor() { return letterCursor; } public void setAlphabetName(String alphabetName) { if (alphabets.containsName(alphabetName)) { this.alphabetIndex = alphabets.indexOfName(alphabetName); this.alphabet = alphabets.getValue(alphabetIndex); this.letterIndex = 0; this.letter = this.alphabet.letters[0]; setLetterImageAndCursor(); notifyToolContextListeners(CHANGED_ALPHABET_SET | CHANGED_ALPHABET_LETTER); } } public void setAlphabetIndex(int alphabetIndex) { while (alphabetIndex < 0) alphabetIndex += alphabets.size(); while (alphabetIndex >= alphabets.size()) alphabetIndex -= alphabets.size(); this.alphabetIndex = alphabetIndex; this.alphabet = alphabets.getValue(alphabetIndex); this.letterIndex = 0; this.letter = this.alphabet.letters[0]; setLetterImageAndCursor(); notifyToolContextListeners(CHANGED_ALPHABET_SET | CHANGED_ALPHABET_LETTER); } public void prevAlphabet() { setAlphabetIndex(alphabetIndex - 1); } public void nextAlphabet() { setAlphabetIndex(alphabetIndex + 1); } public void setLetterIndex(int letterIndex) { while (letterIndex < 0) letterIndex += alphabet.letters.length; while (letterIndex >= alphabet.letters.length) letterIndex -= alphabet.letters.length; this.letterIndex = letterIndex; this.letter = this.alphabet.letters[letterIndex]; setLetterImageAndCursor(); notifyToolContextListeners(CHANGED_ALPHABET_LETTER); } public void prevLetter() { setLetterIndex(letterIndex - 1); } public void nextLetter() { setLetterIndex(letterIndex + 1); } public void setLetter(int letter) { for (int i = 0; i < alphabet.letters.length; i++) { if (alphabet.letters[i] == letter) { this.letterIndex = i; break; } } this.letter = letter; setLetterImageAndCursor(); notifyToolContextListeners(CHANGED_ALPHABET_LETTER); } // brushes public MaterialList<SpriteSheet> getBrushSets() { return brushSets; } public String getBrushSetName() { return brushSets.getName(brushSetIndex); } public int getBrushSetIndex() { return brushSetIndex; } public List<Sprite> getBrushes() { return brushes; } public int getBrushIndex() { return brushIndex; } public Sprite getBrush() { return brush; } public void setBrushSetName(String brushSetName) { if (brushSets.containsName(brushSetName)) { this.brushSetIndex = brushSets.indexOfName(brushSetName); this.brushes = brushSets.getValue(brushSetIndex).getSprites(); this.brushIndex = 0; this.brush = this.brushes.get(0); notifyToolContextListeners(CHANGED_BRUSH_SET | CHANGED_BRUSH); } } public void setBrushSetIndex(int brushSetIndex) { while (brushSetIndex < 0) brushSetIndex += brushSets.size(); while (brushSetIndex >= brushSets.size()) brushSetIndex -= brushSets.size(); this.brushSetIndex = brushSetIndex; this.brushes = brushSets.getValue(brushSetIndex).getSprites(); this.brushIndex = 0; this.brush = this.brushes.get(0); notifyToolContextListeners(CHANGED_BRUSH_SET | CHANGED_BRUSH); } public void prevBrushSet() { setBrushSetIndex(brushSetIndex-1); } public void nextBrushSet() { setBrushSetIndex(brushSetIndex+1); } public void setBrushes(List<Sprite> brushes) { this.brushes = brushes; this.brushIndex = 0; this.brush = this.brushes.get(0); notifyToolContextListeners(CHANGED_BRUSH_SET | CHANGED_BRUSH); } public void setBrushIndex(int brushIndex) { while (brushIndex < 0) brushIndex += brushes.size(); while (brushIndex >= brushes.size()) brushIndex -= brushes.size(); this.brushIndex = brushIndex; this.brush = this.brushes.get(brushIndex); notifyToolContextListeners(CHANGED_BRUSH); } public void prevBrush() { setBrushIndex(brushIndex-1); } public void nextBrush() { setBrushIndex(brushIndex+1); } public void setBrush(Sprite brush) { if (brushes.contains(brush)) { this.brushIndex = brushes.indexOf(brush); } this.brush = brush; notifyToolContextListeners(CHANGED_BRUSH); } // calligraphy brushes public List<Sprite> getCalligraphyBrushes() { return calligraphyBrushes; } public int getCalligraphyBrushIndex() { return calligraphyBrushIndex; } public Sprite getCalligraphyBrush() { return calligraphyBrush; } public boolean calligraphyContinuous() { return calligraphyContinuous; } public void setCalligraphyBrushIndex(int calligraphyBrushIndex) { while (calligraphyBrushIndex < 0) calligraphyBrushIndex += calligraphyBrushes.size(); while (calligraphyBrushIndex >= calligraphyBrushes.size()) calligraphyBrushIndex -= calligraphyBrushes.size(); this.calligraphyBrushIndex = calligraphyBrushIndex; this.calligraphyBrush = calligraphyBrushes.get(calligraphyBrushIndex); notifyToolContextListeners(CHANGED_CALLIGRAPHY_BRUSH); } public void prevCalligraphyBrush() { setCalligraphyBrushIndex(calligraphyBrushIndex-1); } public void nextCalligraphyBrush() { setCalligraphyBrushIndex(calligraphyBrushIndex+1); } public void setCalligraphyBrush(Sprite calligraphyBrush) { if (this.calligraphyBrushes.contains(calligraphyBrush)) { this.calligraphyBrushIndex = this.calligraphyBrushes.indexOf(calligraphyBrush); } this.calligraphyBrush = calligraphyBrush; notifyToolContextListeners(CHANGED_CALLIGRAPHY_BRUSH); } public void setCalligraphyContinuous(boolean calligraphyContinuous) { this.calligraphyContinuous = calligraphyContinuous; notifyToolContextListeners(CHANGED_CALLIGRAPHY_CONTINUOUS); } public void toggleCalligraphyContinuous() { calligraphyContinuous = !calligraphyContinuous; notifyToolContextListeners(CHANGED_CALLIGRAPHY_CONTINUOUS); } // charcoal brushes public List<Sprite> getCharcoalBrushes() { return charcoalBrushes; } public int getCharcoalBrushIndex() { return charcoalBrushIndex; } public Sprite getCharcoalBrush() { return charcoalBrush; } public void setCharcoalBrushIndex(int charcoalBrushIndex) { while (charcoalBrushIndex < 0) charcoalBrushIndex += charcoalBrushes.size(); while (charcoalBrushIndex >= charcoalBrushes.size()) charcoalBrushIndex -= charcoalBrushes.size(); this.charcoalBrushIndex = charcoalBrushIndex; this.charcoalBrush = charcoalBrushes.get(charcoalBrushIndex); notifyToolContextListeners(CHANGED_CHARCOAL_BRUSH); } public void prevCharcoalBrush() { setCharcoalBrushIndex(charcoalBrushIndex-1); } public void nextCharcoalBrush() { setCharcoalBrushIndex(charcoalBrushIndex+1); } public void setCharcoalBrush(Sprite charcoalBrush) { if (charcoalBrushes.contains(charcoalBrush)) { this.charcoalBrushIndex = charcoalBrushes.indexOf(charcoalBrush); } this.charcoalBrush = charcoalBrush; notifyToolContextListeners(CHANGED_CHARCOAL_BRUSH); } // frames public MaterialList<Frame> getFrames() { return frames; } public String getFrameName() { return frames.getName(frameIndex); } public int getFrameIndex() { return frameIndex; } public Frame getFrame() { return frame; } public void setFrameName(String frameName) { if (frames.containsName(frameName)) { this.frameIndex = frames.indexOfName(frameName); this.frame = frames.getValue(frameIndex); notifyToolContextListeners(CHANGED_FRAME); } } public void setFrameIndex(int frameIndex) { while (frameIndex < 0) frameIndex += frames.size(); while (frameIndex >= frames.size()) frameIndex -= frames.size(); this.frameIndex = frameIndex; this.frame = frames.getValue(frameIndex); notifyToolContextListeners(CHANGED_FRAME); } public void prevFrame() { setFrameIndex(frameIndex-1); } public void nextFrame() { setFrameIndex(frameIndex+1); } public void setFrame(Frame frame) { if (frames.containsValue(frame)) { this.frameIndex = frames.indexOfValue(frame); } this.frame = frame; notifyToolContextListeners(CHANGED_FRAME); } // rubber stamps public MaterialList<SpriteSheet> getRubberStampSets() { return rubberStampSets; } public String getRubberStampSetName() { return rubberStampSets.getName(rubberStampSetIndex); } public int getRubberStampSetIndex() { return rubberStampSetIndex; } public List<Sprite> getRubberStamps() { return rubberStamps; } public int getRubberStampIndex() { return rubberStampIndex; } public Sprite getRubberStamp() { return rubberStamp; } public void setRubberStampSetName(String rubberStampSetName) { if (rubberStampSets.containsName(rubberStampSetName)) { this.rubberStampSetIndex = rubberStampSets.indexOfName(rubberStampSetName); this.rubberStamps = rubberStampSets.getValue(rubberStampSetIndex).getSprites(); this.rubberStampIndex = 0; this.rubberStamp = this.rubberStamps.get(0); notifyToolContextListeners(CHANGED_STAMP_SET | CHANGED_STAMP); } } public void setRubberStampSetIndex(int rubberStampSetIndex) { while (rubberStampSetIndex < 0) rubberStampSetIndex += rubberStampSets.size(); while (rubberStampSetIndex >= rubberStampSets.size()) rubberStampSetIndex -= rubberStampSets.size(); this.rubberStampSetIndex = rubberStampSetIndex; this.rubberStamps = rubberStampSets.getValue(rubberStampSetIndex).getSprites(); this.rubberStampIndex = 0; this.rubberStamp = this.rubberStamps.get(0); notifyToolContextListeners(CHANGED_STAMP_SET | CHANGED_STAMP); } public void prevRubberStampSet() { setRubberStampSetIndex(rubberStampSetIndex-1); } public void nextRubberStampSet() { setRubberStampSetIndex(rubberStampSetIndex+1); } public void setRubberStamps(List<Sprite> rubberStamps) { this.rubberStamps = rubberStamps; this.rubberStampIndex = 0; this.rubberStamp = this.rubberStamps.get(0); notifyToolContextListeners(CHANGED_STAMP_SET | CHANGED_STAMP); } public void setRubberStampIndex(int rubberStampIndex) { while (rubberStampIndex < 0) rubberStampIndex += rubberStamps.size(); while (rubberStampIndex >= rubberStamps.size()) rubberStampIndex -= rubberStamps.size(); this.rubberStampIndex = rubberStampIndex; this.rubberStamp = this.rubberStamps.get(rubberStampIndex); notifyToolContextListeners(CHANGED_STAMP); } public void prevRubberStamp() { setRubberStampIndex(rubberStampIndex-1); } public void nextRubberStamp() { setRubberStampIndex(rubberStampIndex+1); } public void setRubberStamp(Sprite rubberStamp) { if (rubberStamps.contains(rubberStamp)) { this.rubberStampIndex = rubberStamps.indexOf(rubberStamp); } this.rubberStamp = rubberStamp; notifyToolContextListeners(CHANGED_STAMP); } // PowerShapes public MaterialList<PowerShapeList> getPowerShapeSets() { return powerShapeSets; } public String getPowerShapeSetName() { return powerShapeSets.getName(powerShapeSetIndex); } public int getPowerShapeSetIndex() { return powerShapeSetIndex; } public PowerShapeList getPowerShapes() { return powerShapes; } public String getPowerShapeName() { return powerShape.name; } public int getPowerShapeIndex() { return powerShapeIndex; } public PowerShape getPowerShape() { return powerShape; } public void setPowerShapeSetName(String powerShapeSetName) { if (powerShapeSets.containsName(powerShapeSetName)) { this.powerShapeSetIndex = powerShapeSets.indexOfName(powerShapeSetName); this.powerShapes = powerShapeSets.getValue(powerShapeSetIndex); this.powerShapeIndex = 0; this.powerShape = this.powerShapes.get(0); notifyToolContextListeners(CHANGED_SHAPE_SET | CHANGED_SHAPE); } } public void setPowerShapeSetIndex(int powerShapeSetIndex) { while (powerShapeSetIndex < 0) powerShapeSetIndex += powerShapeSets.size(); while (powerShapeSetIndex >= powerShapeSets.size()) powerShapeSetIndex -= powerShapeSets.size(); this.powerShapeSetIndex = powerShapeSetIndex; this.powerShapes = powerShapeSets.getValue(powerShapeSetIndex); this.powerShapeIndex = 0; this.powerShape = this.powerShapes.get(0); notifyToolContextListeners(CHANGED_SHAPE_SET | CHANGED_SHAPE); } public void prevPowerShapeSet() { setPowerShapeSetIndex(powerShapeSetIndex-1); } public void nextPowerShapeSet() { setPowerShapeSetIndex(powerShapeSetIndex+1); } public void setPowerShapes(PowerShapeList powerShapes) { if (powerShapeSets.containsValue(powerShapes)) { this.powerShapeSetIndex = powerShapeSets.indexOfValue(powerShapes); } this.powerShapes = powerShapes; this.powerShapeIndex = 0; this.powerShape = this.powerShapes.get(0); notifyToolContextListeners(CHANGED_SHAPE_SET | CHANGED_SHAPE); } public void setPowerShapeName(String powerShapeName) { for (int i = 0; i < powerShapes.size(); i++) { if (powerShapes.get(i).name.equals(powerShapeName)) { this.powerShapeIndex = i; this.powerShape = powerShapes.get(i); notifyToolContextListeners(CHANGED_SHAPE); break; } } } public void setPowerShapeIndex(int powerShapeIndex) { while (powerShapeIndex < 0) powerShapeIndex += powerShapes.size(); while (powerShapeIndex >= powerShapes.size()) powerShapeIndex -= powerShapes.size(); this.powerShapeIndex = powerShapeIndex; this.powerShape = this.powerShapes.get(powerShapeIndex); notifyToolContextListeners(CHANGED_SHAPE); } public void prevPowerShape() { setPowerShapeIndex(powerShapeIndex-1); } public void nextPowerShape() { setPowerShapeIndex(powerShapeIndex+1); } public void setPowerShape(PowerShape powerShape) { if (powerShapes.contains(powerShape)) { this.powerShapeIndex = powerShapes.indexOf(powerShape); } this.powerShape = powerShape; notifyToolContextListeners(CHANGED_SHAPE); } // sprinkles public List<Sprite> getSprinkleSets() { return sprinkleSets; } public int getSprinkleSetIndex() { return sprinkleSetIndex; } public Sprite getSprinkles() { return sprinkles; } public int getSprinkleIndex() { return sprinkleIndex; } public Sprite getSprinkle() { return sprinkle; } public boolean sprinkleBrushMode() { return sprinkleBrushMode; } public void setSprinkleSetIndex(int sprinkleSetIndex) { while (sprinkleSetIndex < 0) sprinkleSetIndex += sprinkleSets.size(); while (sprinkleSetIndex >= sprinkleSets.size()) sprinkleSetIndex -= sprinkleSets.size(); this.sprinkleSetIndex = sprinkleSetIndex; this.sprinkles = sprinkleSets.get(sprinkleSetIndex); this.sprinkleIndex = random.nextInt(this.sprinkles.getChildCount()); this.sprinkle = this.sprinkles.getChild(this.sprinkleIndex); notifyToolContextListeners(CHANGED_SPRINKLE_SET | CHANGED_SPRINKLE); } public void prevSprinkleSet() { setSprinkleSetIndex(sprinkleSetIndex-1); } public void nextSprinkleSet() { setSprinkleSetIndex(sprinkleSetIndex+1); } public void setSprinkles(Sprite sprinkles) { if (sprinkleSets.contains(sprinkles)) { this.sprinkleSetIndex = sprinkleSets.indexOf(sprinkles); } this.sprinkles = sprinkles; this.sprinkleIndex = random.nextInt(this.sprinkles.getChildCount()); this.sprinkle = this.sprinkles.getChild(this.sprinkleIndex); notifyToolContextListeners(CHANGED_SPRINKLE_SET | CHANGED_SPRINKLE); } public void setSprinkleIndex(int sprinkleIndex) { int n = sprinkles.getChildCount(); while (sprinkleIndex < 0) sprinkleIndex += n; while (sprinkleIndex >= n) sprinkleIndex -= n; this.sprinkleIndex = sprinkleIndex; this.sprinkle = this.sprinkles.getChild(this.sprinkleIndex); notifyToolContextListeners(CHANGED_SPRINKLE); } public void prevSprinkle() { setSprinkleIndex(sprinkleIndex-1); } public void nextSprinkle() { setSprinkleIndex(sprinkleIndex+1); } public void randomSprinkle() { this.sprinkleIndex = random.nextInt(this.sprinkles.getChildCount()); this.sprinkle = this.sprinkles.getChild(this.sprinkleIndex); notifyToolContextListeners(CHANGED_SPRINKLE); } public void setSprinkle(Sprite sprinkle) { this.sprinkle = sprinkle; notifyToolContextListeners(CHANGED_SPRINKLE); } public void setSprinkleBrushMode(boolean sprinkleBrushMode) { this.sprinkleBrushMode = sprinkleBrushMode; notifyToolContextListeners(CHANGED_SPRINKLE_BRUSH_MODE); } public void toggleSprinkleBrushMode() { sprinkleBrushMode = !sprinkleBrushMode; notifyToolContextListeners(CHANGED_SPRINKLE_BRUSH_MODE); } // custom public <T> T getCustom(Class<? extends Tool> t, String k, Class<T> type, T def) { k = t.getSimpleName() + "." + k; if (custom.containsKey(k)) { Object v = custom.get(k); if (type.isAssignableFrom(v.getClass())) { return type.cast(v); } else { custom.put(k, def); return def; } } else { custom.put(k, def); return def; } } public void setCustom(Class<? extends Tool> t, String k, Object v) { custom.put(t.getSimpleName() + "." + k, v); notifyToolContextListeners(CHANGED_CUSTOM); } public <T extends Number> void decrementCustom(Class<? extends Tool> t, String k, Class<T> type, T def) { Number n = getCustom(t, k, type, def); if (n instanceof Double) n = n.doubleValue()-1.0; else if (n instanceof Float) n = n.floatValue()-1f; else if (n instanceof Long) n = n.longValue()-1L; else if (n instanceof Integer) n = n.intValue()-1; else if (n instanceof Short) n = n.shortValue()-(short)1; else if (n instanceof Byte) n = n.byteValue()-(byte)1; else if (n instanceof BigDecimal) n = ((BigDecimal)n).subtract(BigDecimal.ONE); else if (n instanceof BigInteger) n = ((BigInteger)n).subtract(BigInteger.ONE); else throw new RuntimeException("Unknown Number subclass in ToolContext.decrementCustom."); setCustom(t, k, n); } public <T extends Number> void decrementCustom(Class<? extends Tool> t, String k, Class<T> type, T def, T min) { Number n = getCustom(t, k, type, def); if (n instanceof Double) n = Math.max(min.doubleValue(), n.doubleValue()-1.0); else if (n instanceof Float) n = Math.max(min.floatValue(), n.floatValue()-1f); else if (n instanceof Long) n = Math.max(min.longValue(), n.longValue()-1L); else if (n instanceof Integer) n = Math.max(min.intValue(), n.intValue()-1); else if (n instanceof Short) n = Math.max(min.shortValue(), n.shortValue()-(short)1); else if (n instanceof Byte) n = Math.max(min.byteValue(), n.byteValue()-(byte)1); else if (n instanceof BigDecimal) n = max((BigDecimal)min, ((BigDecimal)n).subtract(BigDecimal.ONE)); else if (n instanceof BigInteger) n = max((BigInteger)min, ((BigInteger)n).subtract(BigInteger.ONE)); else throw new RuntimeException("Unknown Number subclass in ToolContext.decrementCustom."); setCustom(t, k, n); } public <T extends Number> void incrementCustom(Class<? extends Tool> t, String k, Class<T> type, T def) { Number n = getCustom(t, k, type, def); if (n instanceof Double) n = n.doubleValue()+1.0; else if (n instanceof Float) n = n.floatValue()+1f; else if (n instanceof Long) n = n.longValue()+1L; else if (n instanceof Integer) n = n.intValue()+1; else if (n instanceof Short) n = n.shortValue()+(short)1; else if (n instanceof Byte) n = n.byteValue()+(byte)1; else if (n instanceof BigDecimal) n = ((BigDecimal)n).add(BigDecimal.ONE); else if (n instanceof BigInteger) n = ((BigInteger)n).add(BigInteger.ONE); else throw new RuntimeException("Unknown Number subclass in ToolContext.incrementCustom."); setCustom(t, k, n); } public <T extends Number> void incrementCustom(Class<? extends Tool> t, String k, Class<T> type, T def, T max) { Number n = getCustom(t, k, type, def); if (n instanceof Double) n = Math.min(max.doubleValue(), n.doubleValue()+1.0); else if (n instanceof Float) n = Math.min(max.floatValue(), n.floatValue()+1f); else if (n instanceof Long) n = Math.min(max.longValue(), n.longValue()+1L); else if (n instanceof Integer) n = Math.min(max.intValue(), n.intValue()+1); else if (n instanceof Short) n = Math.min(max.shortValue(), n.shortValue()+(short)1); else if (n instanceof Byte) n = Math.min(max.byteValue(), n.byteValue()+(byte)1); else if (n instanceof BigDecimal) n = min((BigDecimal)max, ((BigDecimal)n).add(BigDecimal.ONE)); else if (n instanceof BigInteger) n = min((BigInteger)max, ((BigInteger)n).add(BigInteger.ONE)); else throw new RuntimeException("Unknown Number subclass in ToolContext.incrementCustom."); setCustom(t, k, n); } public void toggleCustom(Class<? extends Tool> t, String k, boolean def) { setCustom(t, k, !getCustom(t, k, Boolean.class, def)); } // listeners public void addToolContextListener(ToolContextListener l) { listeners.add(l); } public void removeToolContextListener(ToolContextListener l) { listeners.remove(l); } public ToolContextListener[] getToolContextListeners() { return listeners.toArray(new ToolContextListener[0]); } protected void notifyToolContextListeners(long delta) { for (ToolContextListener l : listeners) { l.toolSettingsChanged(this, delta); } } // private interface private BigDecimal max(BigDecimal a, BigDecimal b) { return (a.compareTo(b) > 0) ? a : b; } private BigInteger max(BigInteger a, BigInteger b) { return (a.compareTo(b) > 0) ? a : b; } private BigDecimal min(BigDecimal a, BigDecimal b) { return (a.compareTo(b) < 0) ? a : b; } private BigInteger min(BigInteger a, BigInteger b) { return (a.compareTo(b) < 0) ? a : b; } private void setLetterImageAndCursor() { // calculate font metrics this.letterImage = new BufferedImage(8, 8, BufferedImage.TYPE_INT_ARGB); Graphics2D g = this.letterImage.createGraphics(); Font f = this.alphabet.font; FontMetrics fm = g.getFontMetrics(f); int w = fm.charWidth(this.letter); int h = fm.getHeight(); int a = fm.getAscent(); g.dispose(); // create temporary image that is larger than necessary this.letterImage = new BufferedImage(w+w, h+h, BufferedImage.TYPE_INT_ARGB); g = this.letterImage.createGraphics(); g.setFont(f); g.setColor(Color.black); g.drawString(String.valueOf(Character.toChars(this.letter)), w/2, h/2+a); g.dispose(); // calculate bounding box and final hot spot using the temporary image int hsx = w; int hsy = h/2+a; int xmin = 0, ymin = 0; int xmax = this.letterImage.getWidth(); int ymax = this.letterImage.getHeight(); // find topmost row containing pixels or hotspot while (ymin < ymax && hsy > 0) { int[] rgb = new int[w+w]; this.letterImage.getRGB(0, ymin, w+w, 1, rgb, 0, w+w); boolean containsPixels = false; for (int i : rgb) { if (i < 0 || i >= 0x01000000) { containsPixels = true; break; } } if (containsPixels) break; else { ymin++; hsy--; } } // find bottommost row containing pixels or hotspot while (ymax > ymin && hsy < ymax-ymin-1) { int[] rgb = new int[w+w]; this.letterImage.getRGB(0, ymax-1, w+w, 1, rgb, 0, w+w); boolean containsPixels = false; for (int i : rgb) { if (i < 0 || i >= 0x01000000) { containsPixels = true; break; } } if (containsPixels) break; else ymax--; } // find leftmost column containing pixels or hotspot while (xmin < xmax && hsx > 0) { int[] rgb = new int[h+h]; this.letterImage.getRGB(xmin, 0, 1, h+h, rgb, 0, 1); boolean containsPixels = false; for (int i : rgb) { if (i < 0 || i >= 0x01000000) { containsPixels = true; break; } } if (containsPixels) break; else { xmin++; hsx--; } } // find rightmost column containing pixels or hotspot while (xmax > xmin && hsx < xmax-xmin-1) { int[] rgb = new int[h+h]; this.letterImage.getRGB(xmax-1, 0, 1, h+h, rgb, 0, 1); boolean containsPixels = false; for (int i : rgb) { if (i < 0 || i >= 0x01000000) { containsPixels = true; break; } } if (containsPixels) break; else xmax--; } // create final image trimmed from temporary image int[] rgb = new int[(xmax-xmin) * (ymax-ymin)]; this.letterImage.getRGB(xmin, ymin, xmax-xmin, ymax-ymin, rgb, 0, xmax-xmin); this.letterImage = new BufferedImage(xmax-xmin, ymax-ymin, BufferedImage.TYPE_INT_ARGB); this.letterImage.setRGB(0, 0, xmax-xmin, ymax-ymin, rgb, 0, xmax-xmin); // set cursor this.letterCursor = CursorUtils.makeCursor(this.letterImage, hsx, hsy, "AStamp"); } }