package com.baselet.diagram.draw.swing; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.Rectangle; import java.awt.Shape; import java.awt.geom.Arc2D; import java.awt.geom.Ellipse2D; import java.awt.geom.Path2D; import java.awt.geom.RoundRectangle2D; import com.baselet.control.StringStyle; import com.baselet.control.basics.Converter; import com.baselet.control.basics.geom.DimensionDouble; import com.baselet.control.basics.geom.PointDouble; import com.baselet.control.constants.Constants; import com.baselet.control.enums.AlignHorizontal; import com.baselet.control.util.Utils; import com.baselet.diagram.DiagramHandler; import com.baselet.diagram.draw.DrawFunction; import com.baselet.diagram.draw.DrawHandler; import com.baselet.diagram.draw.helper.ColorOwn; import com.baselet.diagram.draw.helper.Style; import com.baselet.element.interfaces.GridElement; public class DrawHandlerSwing extends DrawHandler { private Graphics2D g2; protected DiagramHandler handler; private boolean translate; // is used because pdf and svg export cut lines if they are drawn at (0,0) private final GridElement gridElement; public DrawHandlerSwing(GridElement gridElement) { super(); this.gridElement = gridElement; } /** * Java Swing JComponents have a width of w, but only w-1 pixels are drawable * Therefore to draw a rectangle around the whole element, you must call g.drawRect(0,0,w-1,h-1) * To avoid this displacement pixel at every draw method, this method ensures you can never draw outside of the right component border * x is also important for width drawings which don't start at 0 (e.g. Deployment "3-dimensional" Rectangle) */ private double inBorderHorizontal(double width, double x) { return Math.min(gridElement.getRectangle().getWidth() - x - 1, width); } /** * same as above but for vertical points */ private double inBorderVertical(double height, double y) { return Math.min(gridElement.getRectangle().getHeight() - y - 1, height); } public void setHandler(DiagramHandler handler) { this.handler = handler; style = new Style(); resetStyle(); } public void setGraphics(Graphics g) { g2 = (Graphics2D) g; } private double getZoom() { return handler.getZoomFactor(); } @Override public DimensionDouble textDimensionHelper(StringStyle singleLine) { boolean specialFontSize = style.getFontSize() != getDefaultFontSize(); if (specialFontSize) { handler.getFontHandler().setFontSize(style.getFontSize()); } DimensionDouble returnVal = handler.getFontHandler().getTextSize(singleLine, false); if (specialFontSize) { handler.getFontHandler().resetFontSize(); } return returnVal; } @Override public double getDefaultFontSize() { return handler.getFontHandler().getFontSize(false); } /* DRAW METHODS */ @Override public void drawArc(double x, double y, double width, double height, double start, double extent, boolean open) { double xZoomed = x * getZoom() + HALF_PX; double yZoomed = y * getZoom() + HALF_PX; int arcType = open ? Arc2D.OPEN : Arc2D.PIE; addShape(new Arc2D.Double(xZoomed, yZoomed, inBorderHorizontal(width * getZoom(), xZoomed), inBorderVertical(height * getZoom(), yZoomed), start, extent, arcType)); } @Override public void drawCircle(double x, double y, double radius) { double widthAndHeight = radius * 2; drawEllipse(x - radius, y - radius, widthAndHeight, widthAndHeight); } @Override public void drawEllipse(double x, double y, double width, double height) { double xZoomed = x * getZoom() + HALF_PX; double yZoomed = y * getZoom() + HALF_PX; addShape(new Ellipse2D.Double(xZoomed, yZoomed, inBorderHorizontal(width * getZoom(), xZoomed), inBorderVertical(height * getZoom(), yZoomed))); } @Override public void drawLines(PointDouble... points) { if (points.length > 0) { Path2D.Double path = new Path2D.Double(); boolean first = true; boolean fillShape = false; int lastIdx = points.length - 1; for (int i = 0; i < points.length; i++) { PointDouble p = points[i]; Double x = inBorderHorizontal(Double.valueOf(p.getX() * getZoom() + HALF_PX), 0); Double y = inBorderVertical(Double.valueOf(p.getY() * getZoom() + HALF_PX), 0); if (first) { path.moveTo(x, y); first = false; } // if this is the last point AND the first and last points are equal, close the path and fill the shape else if (i == lastIdx && points[0].equals(points[lastIdx])) { path.closePath(); fillShape = true; } else { path.lineTo(x, y); } } addShape(path, fillShape); } } @Override public void drawRectangle(double x, double y, double width, double height) { double xZoomed = x * getZoom() + HALF_PX; double yZoomed = y * getZoom() + HALF_PX; addShape(new Rectangle.Double(xZoomed, yZoomed, inBorderHorizontal(width * getZoom(), xZoomed), inBorderVertical(height * getZoom(), yZoomed))); } @Override public void drawRectangleRound(double x, double y, double width, double height, double radius) { double rad = radius * 2 * getZoom(); double xZoomed = x * getZoom() + HALF_PX; double yZoomed = y * getZoom() + HALF_PX; addShape(new RoundRectangle2D.Double(xZoomed, yZoomed, inBorderHorizontal(width * getZoom(), xZoomed), inBorderVertical(height * getZoom(), yZoomed), rad, rad)); } @Override public void printHelper(StringStyle[] text, PointDouble point, AlignHorizontal align) { addText(new Text(text, point.x * getZoom(), point.y * getZoom(), align)); } protected void addShape(final Shape s) { addShape(s, true); } protected void addShape(final Shape s, final boolean fillShape) { final Style styleAtDrawingCall = style.cloneFromMe(); addDrawable(new DrawFunction() { @Override public void run() { drawShape(styleAtDrawingCall, s, fillShape); } }); } private void drawShape(Style style, Shape s, boolean fillShape) { if (fillShape) { // Shapes Background g2.setColor(Converter.convert(style.getBackgroundColor())); g2.fill(s); } if (translate) { double xTranslation = s.getBounds().x == 0 ? Constants.EXPORT_DISPLACEMENT : 0; double yTranslation = s.getBounds().y == 0 ? Constants.EXPORT_DISPLACEMENT : 0; g2.translate(xTranslation, yTranslation); } if (style.getLineWidth() > 0) { // Shapes Foreground ColorOwn colOwn = getOverlay().getForegroundColor() != null ? getOverlay().getForegroundColor() : style.getForegroundColor(); g2.setColor(Converter.convert(colOwn)); g2.setStroke(Utils.getStroke(style.getLineType(), (float) style.getLineWidth())); g2.draw(s); } } protected void addText(final Text t) { final Style styleAtDrawingCall = style.cloneFromMe(); addDrawable(new DrawFunction() { @Override public void run() { drawText(styleAtDrawingCall, t); } }); } private void drawText(Style style, Text t) { ColorOwn col = getOverlay().getForegroundColor() != null ? getOverlay().getForegroundColor() : style.getForegroundColor(); g2.setColor(Converter.convert(col)); handler.getFontHandler().setFontSize(style.getFontSize()); g2.setFont(handler.getFontHandler().getFont()); handler.getFontHandler().writeText(g2, t.getText(), t.getX(), t.getY(), t.getHorizontalAlignment()); handler.getFontHandler().resetFontSize(); } public void setTranslate(boolean translate) { this.translate = translate; } }