/* * Copyright (c) 2014 tabletoptool.com team. * All rights reserved. This program and the accompanying materials * are made available under the terms of the GNU Public License v3.0 * which accompanies this distribution, and is available at * http://www.gnu.org/licenses/gpl.html * * Contributors: * rptools.com team - initial implementation * tabletoptool.com team - further development */ package com.t3.client.tool.drawing; import java.awt.Graphics2D; import java.awt.Paint; import java.awt.event.MouseEvent; import java.awt.geom.AffineTransform; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.io.IOException; import javax.imageio.ImageIO; import javax.swing.ImageIcon; import javax.swing.SwingUtilities; import com.t3.client.AppState; import com.t3.client.ScreenPoint; import com.t3.client.ui.zone.ZoneRenderer; import com.t3.model.ZonePoint; import com.t3.model.drawing.AbstractTemplate; import com.t3.model.drawing.AbstractTemplate.Quadrant; import com.t3.model.drawing.LineTemplate; import com.t3.model.drawing.Pen; import com.t3.swing.SwingUtil; /** * Draw the effected area of a spell area type of line. * * @author jgorrell * @version $Revision: 5945 $ $Date: 2013-06-02 21:05:50 +0200 (Sun, 02 Jun 2013) $ $Author: azhrei_fje $ */ public class LineTemplateTool extends RadiusTemplateTool implements PropertyChangeListener { /*--------------------------------------------------------------------------------------------- * Instance Variables *-------------------------------------------------------------------------------------------*/ /** * Has the anchoring point been set? When false, the anchor point is being placed. When true, the area of effect is * being drawn on the display. */ private boolean pathAnchorSet; /*--------------------------------------------------------------------------------------------- * Constructor *-------------------------------------------------------------------------------------------*/ /** * Add the icon to the toggle button. */ public LineTemplateTool() { try { setIcon(new ImageIcon(ImageIO.read(getClass().getClassLoader().getResourceAsStream( "com/t3/client/image/tool/temp-blue-line.png")))); } catch (IOException ioe) { ioe.printStackTrace(); } // endtry AppState.addPropertyChangeListener(AppState.USE_DOUBLE_WIDE_PROP_NAME, this); } /*--------------------------------------------------------------------------------------------- * Overidden RadiusTemplateTool Methods *-------------------------------------------------------------------------------------------*/ /** * @see com.t3.client.tool.drawing.RadiusTemplateTool#getTooltip() */ @Override public String getTooltip() { return "tool.linetemplate.tooltip"; } /** * @see com.t3.client.ui.Tool#getInstructions() */ @Override public String getInstructions() { return "tool.linetemplate.instructions"; } /** * @see com.t3.client.tool.drawing.RadiusTemplateTool#createBaseTemplate() */ @Override protected AbstractTemplate createBaseTemplate() { return new LineTemplate(); } /** * @see com.t3.client.tool.drawing.RadiusTemplateTool#resetTool(com.t3.model.ZonePoint) */ @Override protected void resetTool(ZonePoint aVertex) { super.resetTool(aVertex); pathAnchorSet = false; ((LineTemplate) template).setDoubleWide(AppState.useDoubleWideLine()); } /*--------------------------------------------------------------------------------------------- * Overridden AbstractDrawingTool Methods *-------------------------------------------------------------------------------------------*/ /** * @see com.t3.client.ui.zone.ZoneOverlay#paintOverlay(com.t3.client.ui.zone.ZoneRenderer, * java.awt.Graphics2D) */ @Override public void paintOverlay(ZoneRenderer renderer, Graphics2D g) { if (painting && renderer != null) { Pen pen = getPenForOverlay(); AffineTransform old = g.getTransform(); g.setTransform(getPaintTransform(renderer)); ZonePoint vertex = template.getVertex(); ZonePoint pathVertex = ((LineTemplate) template).getPathVertex(); template.draw(g, pen); Paint paint = pen.getPaint() != null ? pen.getPaint().getPaint() : null; paintCursor(g, paint, pen.getThickness(), vertex); if (pathVertex != null) { paintCursor(g, paint, pen.getThickness(), pathVertex); } g.setTransform(old); if (pathVertex != null) { paintRadius(g, vertex); } } } /** * @see com.t3.client.tool.drawing.RadiusTemplateTool#getRadiusAtMouse(java.awt.event.MouseEvent) */ @Override protected int getRadiusAtMouse(MouseEvent aE) { int radius = super.getRadiusAtMouse(aE); return Math.max(0, radius - 1); } /** * @see com.t3.client.tool.drawing.RadiusTemplateTool#mousePressed(java.awt.event.MouseEvent) */ @Override public void mousePressed(MouseEvent aE) { if (!painting) return; if (SwingUtilities.isLeftMouseButton(aE)) { // Need to set the anchor? controlOffset = null; if (!anchorSet) { anchorSet = true; return; } // endif if (!pathAnchorSet) { LineTemplate lt = (LineTemplate) template; ZonePoint pathVertex = lt.getPathVertex(); ZonePoint vertex = lt.getVertex(); // If the anchor vertex and path anchor vertex are the same, the line is invalid, so do not allow. if ((vertex != null) && !vertex.equals(pathVertex)) { pathAnchorSet = true; } return; } // endif } // endif // Let the radius code finish the template super.mousePressed(aE); } /** * @see com.t3.client.tool.drawing.RadiusTemplateTool#handleMouseMovement(java.awt.event.MouseEvent) */ @Override protected void handleMouseMovement(MouseEvent e) { // Setting anchor point? LineTemplate lt = (LineTemplate) template; ZonePoint pathVertex = lt.getPathVertex(); ZonePoint vertex = lt.getVertex(); if (!anchorSet) { setCellAtMouse(e, vertex); controlOffset = null; // Let control move the anchor } else if (!pathAnchorSet && SwingUtil.isControlDown(e)) { handleControlOffset(e, vertex); // Setting path anchor? } else if (!pathAnchorSet) { template.setRadius(getRadiusAtMouse(e)); controlOffset = null; // The path vertex remains null until it is set the first time. if (pathVertex == null) { pathVertex = new ZonePoint(vertex.x, vertex.y); lt.setPathVertex(pathVertex); } // endif if (pathVertex != null && setCellAtMouse(e, pathVertex)) lt.clearPath(); // Determine which of the extra squares are used on diagonals if (pathVertex != null) { double dx = pathVertex.x - vertex.x; double dy = pathVertex.y - vertex.y; if (dx != 0 && dy != 0) { // Ignore straight lines boolean mouseSlopeGreater = false; double m = Math.abs(dy / dx); double edx = e.getX() - vertex.x; double edy = e.getY() - vertex.y; if (edx != 0 && edy != 0) { // Handle straight lines differently double em = Math.abs(edy / edx); mouseSlopeGreater = em > m; } else if (edx == 0) { mouseSlopeGreater = true; } // endif if (mouseSlopeGreater != lt.isMouseSlopeGreater()) { lt.setMouseSlopeGreater(mouseSlopeGreater); renderer.repaint(); } // endif } // endif } // endif // Let control move the path anchor } else if (SwingUtil.isControlDown(e)) { handleControlOffset(e, pathVertex); // Set the final radius } else { template.setRadius(getRadiusAtMouse(e)); renderer.repaint(); controlOffset = null; return; } // endif // Quadrant change? if (pathVertex != null) { ZonePoint mouse = new ScreenPoint(e.getX(), e.getY()).convertToZone(renderer); int dx = mouse.x - vertex.x; int dy = mouse.y - vertex.y; AbstractTemplate.Quadrant quadrant = (dx < 0) ? (dy < 0 ? Quadrant.NORTH_WEST : Quadrant.SOUTH_WEST) : (dy < 0 ? Quadrant.NORTH_EAST : Quadrant.SOUTH_EAST); if (quadrant != lt.getQuadrant()) { lt.setQuadrant(quadrant); renderer.repaint(); } // endif } // endif } /*--------------------------------------------------------------------------------------------- * PropertyChangeListener Interface Methods *-------------------------------------------------------------------------------------------*/ /** * @see java.beans.PropertyChangeListener#propertyChange(java.beans.PropertyChangeEvent) */ @Override public void propertyChange(PropertyChangeEvent aEvt) { ((LineTemplate) template).setDoubleWide(((Boolean) aEvt.getNewValue()).booleanValue()); } }