diff --git a/diylc/diylc-core/src/org/diylc/common/LineStyle.java b/diylc/diylc-core/src/org/diylc/common/LineStyle.java new file mode 100644 index 00000000..ae19e84e --- /dev/null +++ b/diylc/diylc-core/src/org/diylc/common/LineStyle.java @@ -0,0 +1,32 @@ +/* + + DIY Layout Creator (DIYLC). + Copyright (c) 2009-2018 held jointly by the individual authors. + + This file is part of DIYLC. + + DIYLC is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + DIYLC is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with DIYLC. If not, see . + +*/ +package org.diylc.common; + +public enum LineStyle { + + SOLID, DASHED, DOTTED; + + @Override + public String toString() { + return name().substring(0, 1) + name().substring(1).toLowerCase(); + } +} diff --git a/diylc/diylc-core/src/org/diylc/common/ObjectCache.java b/diylc/diylc-core/src/org/diylc/common/ObjectCache.java index 6ea25d57..f6a67504 100644 --- a/diylc/diylc-core/src/org/diylc/common/ObjectCache.java +++ b/diylc/diylc-core/src/org/diylc/common/ObjectCache.java @@ -1,58 +1,66 @@ /* + * + * DIY Layout Creator (DIYLC). Copyright (c) 2009-2018 held jointly by the individual authors. + * + * This file is part of DIYLC. + * + * DIYLC is free software: you can redistribute it and/or modify it under the terms of the GNU + * General Public License as published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * DIYLC is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even + * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General + * Public License for more details. + * + * You should have received a copy of the GNU General Public License along with DIYLC. If not, see + * . + */ +package org.diylc.common; - DIY Layout Creator (DIYLC). - Copyright (c) 2009-2018 held jointly by the individual authors. +import java.awt.AlphaComposite; +import java.awt.BasicStroke; +import java.awt.Stroke; +import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; - This file is part of DIYLC. +/** + * Repository for object that may be reused, such as {@link Stroke} or {@link AlphaComposite}. + * + * @author Branislav Stojkovic + */ +public class ObjectCache { - DIYLC is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. + private static ObjectCache instance; - DIYLC is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. + public static ObjectCache getInstance() { + if (instance == null) { + instance = new ObjectCache(); + } + return instance; + } - You should have received a copy of the GNU General Public License - along with DIYLC. If not, see . + private ObjectCache() {} -*/ -package org.diylc.common; - -import java.awt.AlphaComposite; -import java.awt.BasicStroke; -import java.awt.Stroke; -import java.util.HashMap; -import java.util.Map; - -/** - * Repository for object that may be reused, such as {@link Stroke} or {@link AlphaComposite}. - * - * @author Branislav Stojkovic - */ -public class ObjectCache { - - private static ObjectCache instance; - - public static ObjectCache getInstance() { - if (instance == null) { - instance = new ObjectCache(); - } - return instance; - } - - private ObjectCache() {} - - private Map basicStrokeMap = new HashMap(); - - public Stroke fetchBasicStroke(float width) { - if (basicStrokeMap.containsKey(width)) { - return basicStrokeMap.get(width); - } - Stroke stroke = new BasicStroke(width, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND); - basicStrokeMap.put(width, stroke); - return stroke; - } -} + private Map basicStrokeMap = new HashMap(); + private Map dashStrokeMap = new HashMap(); + + public Stroke fetchBasicStroke(float width) { + if (basicStrokeMap.containsKey(width)) { + return basicStrokeMap.get(width); + } + Stroke stroke = new BasicStroke(width, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND); + basicStrokeMap.put(width, stroke); + return stroke; + } + + public Stroke fetchStroke(float width, float[] dash, float phase) { + String key = width + "|" + Arrays.toString(dash) + "|" + phase; + if (dashStrokeMap.containsKey(key)) { + return dashStrokeMap.get(key); + } + Stroke stroke = new BasicStroke(width, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND, 0, dash, phase); + dashStrokeMap.put(key, stroke); + return stroke; + } +} diff --git a/diylc/diylc-core/src/org/diylc/components/AbstractCurvedComponent.java b/diylc/diylc-core/src/org/diylc/components/AbstractCurvedComponent.java index 1d5b040f..58c27a0c 100644 --- a/diylc/diylc-core/src/org/diylc/components/AbstractCurvedComponent.java +++ b/diylc/diylc-core/src/org/diylc/components/AbstractCurvedComponent.java @@ -1,262 +1,339 @@ /* + * + * DIY Layout Creator (DIYLC). Copyright (c) 2009-2018 held jointly by the individual authors. + * + * This file is part of DIYLC. + * + * DIYLC is free software: you can redistribute it and/or modify it under the terms of the GNU + * General Public License as published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * DIYLC is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even + * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General + * Public License for more details. + * + * You should have received a copy of the GNU General Public License along with DIYLC. If not, see + * . + */ +package org.diylc.components; - DIY Layout Creator (DIYLC). - Copyright (c) 2009-2018 held jointly by the individual authors. +import java.awt.AlphaComposite; +import java.awt.Color; +import java.awt.Composite; +import java.awt.Graphics2D; +import java.awt.Point; +import java.awt.geom.CubicCurve2D; +import java.awt.geom.Path2D; - This file is part of DIYLC. +import org.diylc.common.LineStyle; +import org.diylc.common.ObjectCache; +import org.diylc.core.ComponentState; +import org.diylc.core.IDrawingObserver; +import org.diylc.core.Project; +import org.diylc.core.VisibilityPolicy; +import org.diylc.core.annotations.EditableProperty; +import org.diylc.core.measures.Size; +import org.diylc.core.measures.SizeUnit; +import org.diylc.utils.Constants; - DIYLC is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. +public abstract class AbstractCurvedComponent extends AbstractTransparentComponent { - DIYLC is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. + private static final long serialVersionUID = 1L; - You should have received a copy of the GNU General Public License - along with DIYLC. If not, see . + public static Color GUIDELINE_COLOR = Color.blue; + public static Size DEFAULT_SIZE = new Size(1d, SizeUnit.in); -*/ -package org.diylc.components; - -import java.awt.AlphaComposite; -import java.awt.Color; -import java.awt.Composite; -import java.awt.Graphics2D; -import java.awt.Point; -import java.awt.geom.CubicCurve2D; - -import org.diylc.common.ObjectCache; -import org.diylc.core.ComponentState; -import org.diylc.core.IDrawingObserver; -import org.diylc.core.Project; -import org.diylc.core.VisibilityPolicy; -import org.diylc.core.annotations.EditableProperty; -import org.diylc.core.measures.Size; -import org.diylc.core.measures.SizeUnit; -import org.diylc.utils.Constants; - -public abstract class AbstractCurvedComponent extends AbstractTransparentComponent { - - private static final long serialVersionUID = 1L; - - public static Color GUIDELINE_COLOR = Color.blue; - public static Size DEFAULT_SIZE = new Size(1d, SizeUnit.in); - - protected Point[] controlPoints = new Point[] {new Point(0, 0), - new Point((int) (DEFAULT_SIZE.convertToPixels() / 2), 0), - new Point((int) (DEFAULT_SIZE.convertToPixels() / 2), (int) (DEFAULT_SIZE.convertToPixels())), - new Point((int) DEFAULT_SIZE.convertToPixels(), (int) DEFAULT_SIZE.convertToPixels())}; - - protected Color color = getDefaultColor(); - protected PointCount pointCount = PointCount.FOUR; - - /** - * Draws the specified curve onto graphics. - * - * @param curve - * @param g2d - * @param componentState - * @param theme - */ - protected abstract void drawCurve(CubicCurve2D curve, Graphics2D g2d, ComponentState componentState, IDrawingObserver drawingObserver); - - /** - * @return default color. - */ - protected abstract Color getDefaultColor(); - - @Override - public void drawIcon(Graphics2D g2d, int width, int height) { - g2d.setColor(getDefaultColor().darker()); - g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(3)); - CubicCurve2D curve = - new CubicCurve2D.Double(1, height - 1, width / 4, height / 3, 3 * width / 4, 2 * height / 3, width - 1, 1); - g2d.draw(curve); - g2d.setColor(getDefaultColor()); - g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(1)); - g2d.draw(curve); - } - - @Override - public void draw(Graphics2D g2d, ComponentState componentState, boolean outlineMode, Project project, - IDrawingObserver drawingObserver) { - if (checkPointsClipped(g2d.getClip())) { - return; - } - if (componentState == ComponentState.SELECTED || componentState == ComponentState.DRAGGING) { - // Do not track guidelines. - drawingObserver.stopTracking(); - g2d.setStroke(Constants.DASHED_STROKE); - g2d.setColor(GUIDELINE_COLOR); - g2d.drawLine(controlPoints[0].x, controlPoints[0].y, controlPoints[1].x, controlPoints[1].y); - g2d.drawLine(controlPoints[1].x, controlPoints[1].y, controlPoints[2].x, controlPoints[2].y); - g2d.drawLine(controlPoints[2].x, controlPoints[2].y, controlPoints[3].x, controlPoints[3].y); - drawingObserver.startTracking(); - } - CubicCurve2D curve = - new CubicCurve2D.Double(controlPoints[0].x, controlPoints[0].y, controlPoints[1].x, controlPoints[1].y, - controlPoints[2].x, controlPoints[2].y, controlPoints[3].x, controlPoints[3].y); - - Composite oldComposite = g2d.getComposite(); - if (alpha < MAX_ALPHA) { - g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1f * alpha / MAX_ALPHA)); - } - // g2d.setColor(color.darker()); - // g2d.setStroke(new BasicStroke(thickness)); - // g2d.draw(path); - // g2d.setColor(color); - // g2d.setStroke(new BasicStroke(thickness - 2)); - // g2d.draw(path); - drawCurve(curve, g2d, componentState, drawingObserver); - g2d.setComposite(oldComposite); - } - - @EditableProperty(name = "Point Count") - public PointCount getPointCount() { - if (pointCount == null) { - pointCount = PointCount.FOUR; - } - return pointCount; - } - - public void setPointCount(PointCount pointCount) { - this.pointCount = pointCount; - // Reset control points. - for (int i = 0; i < getControlPointCount(); i++) { - setControlPoint(getControlPoint(i), i); - } - } - - @Override - public int getControlPointCount() { - switch (getPointCount()) { - case TWO: - return 2; - case THREE: - return 3; - case FOUR: - return 4; - } - return 0; - } - - @Override - public boolean isControlPointSticky(int index) { - return index == 0 || index == getControlPointCount() - 1; - } - - @Override - public VisibilityPolicy getControlPointVisibilityPolicy(int index) { - return VisibilityPolicy.WHEN_SELECTED; - } - - @Override - public boolean canControlPointOverlap(int index) { - // Only shape control points may overlap. - switch (getPointCount()) { - case TWO: - return false; - case THREE: - return index == 1; - case FOUR: - return index == 1 || index == 2; - } - return false; - } - - @Override - public Point getControlPoint(int index) { - if (index == 0) { - return controlPoints[0]; - } - switch (getPointCount()) { - case TWO: - switch (index) { - case 1: - return controlPoints[3]; - } - case THREE: - switch (index) { - case 1: - return controlPoints[1]; - case 2: - return controlPoints[3]; - } - case FOUR: - switch (index) { - case 1: - return controlPoints[1]; - case 2: - return controlPoints[2]; - case 3: - return controlPoints[3]; - } - } - return controlPoints[index]; - } - - @Override - public void setControlPoint(Point point, int index) { - if (index == 0) { - controlPoints[0].setLocation(point); - } else { - switch (getPointCount()) { - case TWO: - switch (index) { - case 1: - Point center = new Point((point.x + controlPoints[0].x) / 2, (point.y + controlPoints[0].y) / 2); - controlPoints[1].setLocation(center); - controlPoints[2].setLocation(center); - controlPoints[3].setLocation(point); - break; - } - break; - case THREE: - switch (index) { - case 1: - controlPoints[1].setLocation(point); - controlPoints[2].setLocation(point); - break; - case 2: - controlPoints[3].setLocation(point); - break; - } - break; - case FOUR: - switch (index) { - case 1: - controlPoints[1].setLocation(point); - break; - case 2: - controlPoints[2].setLocation(point); - break; - case 3: - controlPoints[3].setLocation(point); - break; - } - break; - } - } - } - - @EditableProperty(name="Color") - public Color getLeadColor() { - return color; - } - - public void setLeadColor(Color color) { - this.color = color; - } - - enum PointCount { - TWO, THREE, FOUR; - - @Override - public String toString() { - return name().substring(0, 1) + name().substring(1).toLowerCase(); - } - } -} + // for backward compatibility + protected Point[] controlPoints = null; + + protected Point[] controlPoints2 = new Point[] {new Point(0, 0), + new Point((int) (DEFAULT_SIZE.convertToPixels() / 2), 0), + new Point((int) (DEFAULT_SIZE.convertToPixels() / 2), (int) (DEFAULT_SIZE.convertToPixels())), + new Point((int) DEFAULT_SIZE.convertToPixels(), (int) DEFAULT_SIZE.convertToPixels())}; + + protected Color color = getDefaultColor(); + protected PointCount pointCount = PointCount.FOUR; + protected LineStyle style = LineStyle.SOLID; + protected Boolean smooth = true; + + private int lastUpdatePointIndex = -1; + + /** + * Draws the specified curve onto graphics. + * + * @param curve + * @param g2d + * @param componentState + * @param theme + */ + protected abstract void drawCurve(Path2D curve, Graphics2D g2d, ComponentState componentState, + IDrawingObserver drawingObserver); + + /** + * @return default color. + */ + protected abstract Color getDefaultColor(); + + @Override + public void drawIcon(Graphics2D g2d, int width, int height) { + g2d.setColor(getDefaultColor().darker()); + g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(3)); + CubicCurve2D curve = + new CubicCurve2D.Double(1, height - 1, width / 4, height / 3, 3 * width / 4, 2 * height / 3, width - 1, 1); + g2d.draw(curve); + g2d.setColor(getDefaultColor()); + g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(1)); + g2d.draw(curve); + } + + @Override + public void draw(Graphics2D g2d, ComponentState componentState, boolean outlineMode, Project project, + IDrawingObserver drawingObserver) { + if (checkPointsClipped(g2d.getClip())) { + return; + } + + Point[] p = getControlPoints(); + + // smoothen the curve if needed + if (getSmooth() && lastUpdatePointIndex >= 0) { + if (getPointCount() == PointCount.FIVE && (lastUpdatePointIndex == 1 || lastUpdatePointIndex == 2)) { + p[3] = findThirdPoint(p[2], p[1]); + } + if (getPointCount() == PointCount.FIVE && lastUpdatePointIndex == 3) { + p[1] = findThirdPoint(p[2], p[3]); + } + if (getPointCount() == PointCount.SEVEN && (lastUpdatePointIndex == 2 || lastUpdatePointIndex == 3)) { + p[4] = findThirdPoint(p[3], p[2]); + } + if (getPointCount() == PointCount.SEVEN && lastUpdatePointIndex == 4) { + p[2] = findThirdPoint(p[3], p[4]); + } + lastUpdatePointIndex = -1; + } + + if (componentState == ComponentState.SELECTED || componentState == ComponentState.DRAGGING) { + // Do not track guidelines. + drawingObserver.stopTracking(); + g2d.setStroke(Constants.DASHED_STROKE); + g2d.setColor(GUIDELINE_COLOR); + for (int i = 0; i < p.length - 1; i++) { + g2d.drawLine(p[i].x, p[i].y, p[i + 1].x, p[i + 1].y); + } + drawingObserver.startTracking(); + } + + Path2D path = new Path2D.Double(); + path.moveTo(p[0].x, p[0].y); + if (getPointCount() == PointCount.TWO) { + path.lineTo(p[1].x, p[1].y); + } else if (getPointCount() == PointCount.THREE) { + path.quadTo(p[1].x, p[1].y, p[2].x, p[2].y); + } else if (getPointCount() == PointCount.FOUR) { + path.curveTo(p[1].x, p[1].y, p[2].x, p[2].y, p[3].x, p[3].y); + } else if (getPointCount() == PointCount.FIVE) { + path.quadTo(p[1].x, p[1].y, p[2].x, p[2].y); + path.quadTo(p[3].x, p[3].y, p[4].x, p[4].y); + } else if (getPointCount() == PointCount.SEVEN) { + path.curveTo(p[1].x, p[1].y, p[2].x, p[2].y, p[3].x, p[3].y); + path.curveTo(p[4].x, p[4].y, p[5].x, p[5].y, p[6].x, p[6].y); + } + + Composite oldComposite = g2d.getComposite(); + if (alpha < MAX_ALPHA) { + g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1f * alpha / MAX_ALPHA)); + } + + drawCurve(path, g2d, componentState, drawingObserver); + + g2d.setComposite(oldComposite); + } + + @EditableProperty(name = "Point Count") + public PointCount getPointCount() { + if (pointCount == null) { + pointCount = PointCount.FOUR; + } + return pointCount; + } + + protected Point[] getControlPoints() { + if (this.controlPoints != null) { + // ensure backward compatibility by copying points from the old structure to the new one + switch (getPointCount()) { + case TWO: + this.controlPoints2 = new Point[2]; + this.controlPoints2[0] = this.controlPoints[0]; + this.controlPoints2[1] = this.controlPoints[3]; + break; + case THREE: + this.controlPoints2 = new Point[3]; + this.controlPoints2[0] = this.controlPoints[0]; + this.controlPoints2[1] = this.controlPoints[1]; + this.controlPoints2[2] = this.controlPoints[3]; + break; + case FOUR: + this.controlPoints2 = new Point[4]; + this.controlPoints2[0] = this.controlPoints[0]; + this.controlPoints2[1] = this.controlPoints[1]; + this.controlPoints2[2] = this.controlPoints[2]; + this.controlPoints2[3] = this.controlPoints[3]; + break; + default: // shouldn't happen + this.controlPoints2 = this.controlPoints; + } + // we don't need old points anymore + this.controlPoints = null; + } + return this.controlPoints2; + } + + public void setPointCount(PointCount pointCount) { + Point[] p = getControlPoints(); + Point[] newPoints = new Point[pointCount.count]; + newPoints[0] = p[0]; + newPoints[pointCount.count - 1] = p[p.length - 1]; + + if (pointCount == PointCount.THREE) { + newPoints[1] = + new Point((newPoints[pointCount.count - 1].x + newPoints[0].x) / 2, + (newPoints[pointCount.count - 1].y + newPoints[0].y) / 2); + } else if (pointCount == PointCount.FOUR) { + newPoints[1] = + new Point((newPoints[pointCount.count - 1].x + newPoints[0].x) / 2, + (newPoints[pointCount.count - 1].y + newPoints[0].y) / 2); + newPoints[2] = + new Point((newPoints[pointCount.count - 1].x + newPoints[0].x) / 2, + (newPoints[pointCount.count - 1].y + newPoints[0].y) / 2); + } else if (pointCount == PointCount.FIVE) { + newPoints[2] = + new Point((newPoints[pointCount.count - 1].x + newPoints[0].x) / 2, + (newPoints[pointCount.count - 1].y + newPoints[0].y) / 2); + newPoints[1] = new Point((newPoints[2].x + newPoints[0].x) / 2, (newPoints[2].y + newPoints[0].y) / 2); + newPoints[3] = + new Point((newPoints[pointCount.count - 1].x + newPoints[2].x) / 2, + (newPoints[pointCount.count - 1].y + newPoints[2].y) / 2); + } else if (pointCount == PointCount.SEVEN) { + newPoints[3] = + new Point((newPoints[pointCount.count - 1].x + newPoints[0].x) / 2, + (newPoints[pointCount.count - 1].y + newPoints[0].y) / 2); + newPoints[2] = new Point((newPoints[3].x + newPoints[0].x) / 2, (newPoints[3].y + newPoints[0].y) / 2); + newPoints[1] = new Point((newPoints[3].x + newPoints[0].x) / 2, (newPoints[3].y + newPoints[0].y) / 2); + newPoints[4] = + new Point((newPoints[pointCount.count - 1].x + newPoints[3].x) / 2, + (newPoints[pointCount.count - 1].y + newPoints[3].y) / 2); + newPoints[5] = + new Point((newPoints[pointCount.count - 1].x + newPoints[3].x) / 2, + (newPoints[pointCount.count - 1].y + newPoints[3].y) / 2); + } + + this.controlPoints2 = newPoints; + this.pointCount = pointCount; + } + + @Override + public int getControlPointCount() { + return getControlPoints().length; + } + + @Override + public boolean isControlPointSticky(int index) { + return index == 0 || index == getControlPointCount() - 1; + } + + @Override + public VisibilityPolicy getControlPointVisibilityPolicy(int index) { + return VisibilityPolicy.WHEN_SELECTED; + } + + @Override + public boolean canControlPointOverlap(int index) { + return index > 0 && index < getControlPointCount() - 1; + } + + @Override + public Point getControlPoint(int index) { + return getControlPoints()[index]; + } + + @Override + public void setControlPoint(Point point, int index) { + Point[] p = getControlPoints(); + p[index].setLocation(point); + this.lastUpdatePointIndex = index; + // if (getSmooth()) { + // if (getPointCount() == PointCount.FIVE && (index == 1 || index == 2)) { + // p[3] = findThirdPoint(p[2], p[1]); + // } + // if (getPointCount() == PointCount.FIVE && index == 3) { + // p[1] = findThirdPoint(p[2], p[3]); + // } + // if (getPointCount() == PointCount.SEVEN && (index == 2 || index == 3)) { + // p[4] = findThirdPoint(p[3], p[2]); + // } + // if (getPointCount() == PointCount.SEVEN && index == 4) { + // p[2] = findThirdPoint(p[3], p[4]); + // } + // } + } + + private Point findThirdPoint(Point p0, Point p) { + return new Point(2 * p0.x - p.x, 2 * p0.y - p.y); + } + + @EditableProperty(name = "Color") + public Color getLeadColor() { + return color; + } + + public void setLeadColor(Color color) { + this.color = color; + } + + @EditableProperty(name = "Style") + public LineStyle getStyle() { + if (style == null) + style = LineStyle.SOLID; + return style; + } + + public void setStyle(LineStyle style) { + this.style = style; + } + + @EditableProperty + public Boolean getSmooth() { + if (smooth == null) + this.smooth = true; + return this.smooth; + } + + public void setSmooth(Boolean smooth) { + this.smooth = smooth; + // make the current curve smooth if needed + // Point[] p = getControlPoints(); + // if (smooth) { + // if (getPointCount() == PointCount.FIVE) { + // p[3] = findThirdPoint(p[2], p[1]); + // } + // if (getPointCount() == PointCount.SEVEN) { + // p[4] = findThirdPoint(p[3], p[2]); + // } + // } + } + + enum PointCount { + TWO(2), THREE(3), FOUR(4), FIVE(5), SEVEN(7); + + private int count; + + private PointCount(int count) { + this.count = count; + } + + @Override + public String toString() { + return name().substring(0, 1) + name().substring(1).toLowerCase(); + } + } +} diff --git a/diylc/diylc-core/src/org/diylc/components/AbstractLeadedComponent.java b/diylc/diylc-core/src/org/diylc/components/AbstractLeadedComponent.java index f1202ae6..9dd8c536 100644 --- a/diylc/diylc-core/src/org/diylc/components/AbstractLeadedComponent.java +++ b/diylc/diylc-core/src/org/diylc/components/AbstractLeadedComponent.java @@ -1,26 +1,22 @@ /* + * + * DIY Layout Creator (DIYLC). Copyright (c) 2009-2018 held jointly by the individual authors. + * + * This file is part of DIYLC. + * + * DIYLC is free software: you can redistribute it and/or modify it under the terms of the GNU + * General Public License as published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * DIYLC is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even + * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General + * Public License for more details. + * + * You should have received a copy of the GNU General Public License along with DIYLC. If not, see + * . + */ +package org.diylc.components; - DIY Layout Creator (DIYLC). - Copyright (c) 2009-2018 held jointly by the individual authors. - - This file is part of DIYLC. - - DIYLC is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - DIYLC is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with DIYLC. If not, see . - -*/ -package org.diylc.components; - import java.awt.AlphaComposite; import java.awt.Color; import java.awt.Composite; @@ -29,6 +25,7 @@ import java.awt.Graphics2D; import java.awt.Point; import java.awt.Rectangle; import java.awt.Shape; +import java.awt.Stroke; import java.awt.geom.AffineTransform; import java.awt.geom.Ellipse2D; import java.awt.geom.Rectangle2D; @@ -36,6 +33,7 @@ import java.awt.geom.Rectangle2D; import org.diylc.appframework.miscutils.ConfigurationManager; import org.diylc.common.Display; import org.diylc.common.IPlugInPort; +import org.diylc.common.LineStyle; import org.diylc.common.ObjectCache; import org.diylc.core.ComponentState; import org.diylc.core.IDrawingObserver; @@ -46,450 +44,439 @@ import org.diylc.core.annotations.EditableProperty; import org.diylc.core.measures.Size; import org.diylc.core.measures.SizeUnit; import org.diylc.utils.Constants; - -/** - * Base class for all leaded components such as resistors or capacitors. Has two control points and - * draws leads between them. Also, it positions and draws the shape of the component as specified by - * a child class. - * - * @author Branislav Stojkovic - */ -public abstract class AbstractLeadedComponent extends AbstractTransparentComponent { - - private static final long serialVersionUID = 1L; - - public static Color LEAD_COLOR = Color.decode("#CCCCCC"); - public static Color LEAD_COLOR_ICON = LEAD_COLOR.darker().darker(); - public static Size LEAD_THICKNESS = new Size(0.6d, SizeUnit.mm); - public static Size DEFAULT_SIZE = new Size(1d, SizeUnit.in); - - protected Size length; - protected Size width; - protected Point[] points = new Point[] {new Point((int) (-DEFAULT_SIZE.convertToPixels() / 2), 0), - new Point((int) (DEFAULT_SIZE.convertToPixels() / 2), 0)}; - protected Color bodyColor = Color.white; - protected Color borderColor = Color.black; - protected Color labelColor = LABEL_COLOR; - protected Color leadColor = LEAD_COLOR; - protected Display display = Display.NAME; - private boolean flipStanding = false; - - protected AbstractLeadedComponent() { - super(); - try { - this.length = getDefaultLength().clone(); - this.width = getDefaultWidth().clone(); - } catch (CloneNotSupportedException e) { - // This should never happen because Size supports cloning. - } catch (NullPointerException e) { - // This will happen if components do not have any shape. - } + +/** + * Base class for all leaded components such as resistors or capacitors. Has two control points and + * draws leads between them. Also, it positions and draws the shape of the component as specified by + * a child class. + * + * @author Branislav Stojkovic + */ +public abstract class AbstractLeadedComponent extends AbstractTransparentComponent { + + private static final long serialVersionUID = 1L; + + public static Color LEAD_COLOR = Color.decode("#CCCCCC"); + public static Color LEAD_COLOR_ICON = LEAD_COLOR.darker().darker(); + public static Size LEAD_THICKNESS = new Size(0.6d, SizeUnit.mm); + public static Size DEFAULT_SIZE = new Size(1d, SizeUnit.in); + + protected Size length; + protected Size width; + protected Point[] points = new Point[] {new Point((int) (-DEFAULT_SIZE.convertToPixels() / 2), 0), + new Point((int) (DEFAULT_SIZE.convertToPixels() / 2), 0)}; + protected Color bodyColor = Color.white; + protected Color borderColor = Color.black; + protected Color labelColor = LABEL_COLOR; + protected Color leadColor = LEAD_COLOR; + protected Display display = Display.NAME; + private boolean flipStanding = false; + + protected AbstractLeadedComponent() { + super(); + try { + this.length = getDefaultLength().clone(); + this.width = getDefaultWidth().clone(); + } catch (CloneNotSupportedException e) { + // This should never happen because Size supports cloning. + } catch (NullPointerException e) { + // This will happen if components do not have any shape. + } } - + protected boolean IsCopperArea() { return false; - } - - @Override - public void draw(Graphics2D g2d, ComponentState componentState, boolean outlineMode, Project project, - IDrawingObserver drawingObserver) { - double distance = points[0].distance(points[1]); - Shape shape = getBodyShape(); - // If there's no body, just draw the line connecting the ending points. - if (shape == null) { - drawLead(g2d, componentState, drawingObserver, IsCopperArea()); - } else if (supportsStandingMode() && length.convertToPixels() > points[0].distance(points[1])) { - // When ending points are too close draw the component in standing - // mode. - int width = getClosestOdd(this.width.convertToPixels()); - Shape body = - new Ellipse2D.Double((getFlipStanding() ? points[1] : points[0]).x - width / 2, - (getFlipStanding() ? points[1] : points[0]).y - width / 2, width, width); - Composite oldComposite = g2d.getComposite(); - if (alpha < MAX_ALPHA) { - g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1f * alpha / MAX_ALPHA)); - } - g2d.setColor(outlineMode ? Constants.TRANSPARENT_COLOR : getStandingBodyColor()); - g2d.fill(body); - g2d.setComposite(oldComposite); - Color finalBorderColor; - if (outlineMode) { - Theme theme = - (Theme) ConfigurationManager.getInstance().readObject(IPlugInPort.THEME_KEY, Constants.DEFAULT_THEME); - finalBorderColor = - componentState == ComponentState.SELECTED || componentState == ComponentState.DRAGGING ? SELECTION_COLOR - : theme.getOutlineColor(); - } else { - finalBorderColor = - componentState == ComponentState.SELECTED || componentState == ComponentState.DRAGGING ? SELECTION_COLOR - : borderColor; - } - - g2d.setColor(finalBorderColor); - g2d.draw(body); - if (!outlineMode) { - drawLead(g2d, componentState, drawingObserver, false); - } - } else { - // Normal mode with component body in the center and two lead parts. - Rectangle shapeRect = shape.getBounds(); - double theta = Math.atan2(points[1].y - points[0].y, points[1].x - points[0].x); - // Go back to the original transformation to draw leads. - if (!outlineMode) { - AffineTransform textTransform = g2d.getTransform(); - // if (length.convertToPixels() > points[0].distance(points[1])) - // { - // g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, - // 0.5f)); - // } - float leadThickness = getLeadThickness(); - double leadLength = (distance - calculatePinSpacing(shapeRect)) / 2; - - g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(leadThickness)); - Color leadColor = shouldShadeLeads() ? - getLeadColorForPainting(componentState).darker() : - getLeadColorForPainting(componentState); - g2d.setColor(leadColor); - drawLeads(g2d, theta, leadLength); - - if (shouldShadeLeads()) { - g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(leadThickness - 2)); - leadColor = getLeadColorForPainting(componentState); - g2d.setColor(leadColor); - drawLeads(g2d, theta, leadLength); - } - g2d.setTransform(textTransform); - } - // Transform graphics to draw the body in the right place and at the - // right angle. - AffineTransform oldTransform = null; - double width; - double length; - if (useShapeRectAsPosition()) { - width = shapeRect.getHeight(); - length = shapeRect.getWidth(); - } else { - width = getWidth().convertToPixels(); - length = getLength().convertToPixels(); - } - oldTransform = g2d.getTransform(); - g2d.translate((points[0].x + points[1].x - length) / 2, (points[0].y + points[1].y - width) / 2); - g2d.rotate(theta, length / 2, width / 2); - // Draw body. - Composite oldComposite = g2d.getComposite(); - if (alpha < MAX_ALPHA) { - g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1f * alpha / MAX_ALPHA)); - } - if (bodyColor != null) { - g2d.setColor(outlineMode ? Constants.TRANSPARENT_COLOR : bodyColor); - g2d.fill(shape); - } - decorateComponentBody(g2d, outlineMode); - g2d.setComposite(oldComposite); - g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(1)); - Color finalBorderColor; - if (outlineMode) { - Theme theme = - (Theme) ConfigurationManager.getInstance().readObject(IPlugInPort.THEME_KEY, Constants.DEFAULT_THEME); - finalBorderColor = - componentState == ComponentState.SELECTED || componentState == ComponentState.DRAGGING ? SELECTION_COLOR - : theme.getOutlineColor(); - } else { - finalBorderColor = - componentState == ComponentState.SELECTED || componentState == ComponentState.DRAGGING ? SELECTION_COLOR - : borderColor; - } - g2d.setColor(finalBorderColor); - g2d.draw(shape); - - // // Go back to the original transformation to draw leads. - // if (!outlineMode) { - // AffineTransform textTransform = g2d.getTransform(); - // g2d.setTransform(oldTransform); - // if (length.convertToPixels() > points[0].distance(points[1])) { - // g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, - // 0.5f)); - // } - // int leadThickness = getClosestOdd(getLeadThickness()); - // double leadLength = (distance - calculatePinSpacing(shapeRect)) / - // 2 - leadThickness / 2; - // g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(leadThickness)); - // Color leadColor = shouldShadeLeads() ? - // getLeadColor(componentState).darker() - // : getLeadColor(componentState); - // g2d.setColor(leadColor); - // int endX = (int) (points[0].x + Math.cos(theta) * leadLength); - // int endY = (int) Math.round(points[0].y + Math.sin(theta) * - // leadLength); - // g2d.drawLine(points[0].x, points[0].y, endX, endY); - // endX = (int) (points[1].x + Math.cos(theta - Math.PI) * - // leadLength); - // endY = (int) Math.round(points[1].y + Math.sin(theta - Math.PI) * - // leadLength); - // g2d.drawLine(points[1].x, points[1].y, endX, endY); - // if (shouldShadeLeads()) { - // g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(leadThickness - // - 2)); - // leadColor = getLeadColor(componentState); - // g2d.setColor(leadColor); - // g2d.drawLine(points[0].x, points[0].y, (int) (points[0].x + - // Math.cos(theta) - // * leadLength), (int) (points[0].y + Math.sin(theta) * - // leadLength)); - // g2d.drawLine(points[1].x, points[1].y, (int) (points[1].x + - // Math.cos(theta - // - Math.PI) - // * leadLength), (int) (points[1].y + Math.sin(theta - Math.PI) - // * leadLength)); - // } - // g2d.setComposite(oldComposite); - // g2d.setTransform(textTransform); - // } - - // Draw label. - g2d.setFont(project.getFont()); - if (useShapeRectAsPosition()) { - g2d.translate(shapeRect.x, shapeRect.y); - } - Color finalLabelColor; - if (outlineMode) { - Theme theme = - (Theme) ConfigurationManager.getInstance().readObject(IPlugInPort.THEME_KEY, Constants.DEFAULT_THEME); - finalLabelColor = - componentState == ComponentState.SELECTED || componentState == ComponentState.DRAGGING ? LABEL_COLOR_SELECTED - : theme.getOutlineColor(); - } else { - finalLabelColor = - componentState == ComponentState.SELECTED || componentState == ComponentState.DRAGGING ? LABEL_COLOR_SELECTED - : labelColor; - } - g2d.setColor(finalLabelColor); - FontMetrics fontMetrics = g2d.getFontMetrics(); - String label = ""; - label = display == Display.NAME ? getName() : (getValue() == null ? "" : getValue().toString()); - if (display == Display.NONE) { - label = ""; - } - if (display == Display.BOTH) { - label = getName() + " " + (getValue() == null ? "" : getValue().toString()); - } - Rectangle2D textRect = fontMetrics.getStringBounds(label, g2d); - // Don't offset in outline mode. - int offset = outlineMode ? 0 : getLabelOffset((int) length, (int) textRect.getWidth()); - // Adjust label angle if needed to make sure that it's readable. - if ((theta >= Math.PI / 2 && theta <= Math.PI) || (theta < -Math.PI / 2 && theta > -Math.PI)) { - g2d.rotate(Math.PI, length / 2, width / 2); - offset = -offset; - } - g2d.drawString(label, (int) (length - textRect.getWidth()) / 2 + offset, - calculateLabelYCoordinate(shapeRect, textRect, fontMetrics)); - g2d.setTransform(oldTransform); - } - } - - private void drawLeads(Graphics2D g2d, double theta, double leadLength) { - int endX = (int) (points[0].x + Math.cos(theta) * leadLength); - int endY = (int) (points[0].y + Math.sin(theta) * leadLength); - g2d.drawLine(points[0].x, points[0].y, endX, endY); - - endX = (int) (points[1].x + Math.cos(theta - Math.PI) * leadLength); - endY = (int) (points[1].y + Math.sin(theta - Math.PI) * leadLength); - g2d.drawLine(points[1].x, points[1].y, endX, endY); - } - + } + + @Override + public void draw(Graphics2D g2d, ComponentState componentState, boolean outlineMode, Project project, + IDrawingObserver drawingObserver) { + double distance = points[0].distance(points[1]); + Shape shape = getBodyShape(); + // If there's no body, just draw the line connecting the ending points. + if (shape == null) { + drawLead(g2d, componentState, drawingObserver, IsCopperArea()); + } else if (supportsStandingMode() && length.convertToPixels() > points[0].distance(points[1])) { + // When ending points are too close draw the component in standing + // mode. + int width = getClosestOdd(this.width.convertToPixels()); + Shape body = + new Ellipse2D.Double((getFlipStanding() ? points[1] : points[0]).x - width / 2, + (getFlipStanding() ? points[1] : points[0]).y - width / 2, width, width); + Composite oldComposite = g2d.getComposite(); + if (alpha < MAX_ALPHA) { + g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1f * alpha / MAX_ALPHA)); + } + g2d.setColor(outlineMode ? Constants.TRANSPARENT_COLOR : getStandingBodyColor()); + g2d.fill(body); + g2d.setComposite(oldComposite); + Color finalBorderColor; + if (outlineMode) { + Theme theme = + (Theme) ConfigurationManager.getInstance().readObject(IPlugInPort.THEME_KEY, Constants.DEFAULT_THEME); + finalBorderColor = + componentState == ComponentState.SELECTED || componentState == ComponentState.DRAGGING ? SELECTION_COLOR + : theme.getOutlineColor(); + } else { + finalBorderColor = + componentState == ComponentState.SELECTED || componentState == ComponentState.DRAGGING ? SELECTION_COLOR + : borderColor; + } + + g2d.setColor(finalBorderColor); + g2d.draw(body); + if (!outlineMode) { + drawLead(g2d, componentState, drawingObserver, false); + } + } else { + // Normal mode with component body in the center and two lead parts. + Rectangle shapeRect = shape.getBounds(); + double theta = Math.atan2(points[1].y - points[0].y, points[1].x - points[0].x); + // Go back to the original transformation to draw leads. + if (!outlineMode) { + AffineTransform textTransform = g2d.getTransform(); + // if (length.convertToPixels() > points[0].distance(points[1])) + // { + // g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, + // 0.5f)); + // } + float leadThickness = getLeadThickness(); + double leadLength = (distance - calculatePinSpacing(shapeRect)) / 2; + + g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(leadThickness)); + Color leadColor = + shouldShadeLeads() ? getLeadColorForPainting(componentState).darker() + : getLeadColorForPainting(componentState); + g2d.setColor(leadColor); + drawLeads(g2d, theta, leadLength); + + if (shouldShadeLeads()) { + g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(leadThickness - 2)); + leadColor = getLeadColorForPainting(componentState); + g2d.setColor(leadColor); + drawLeads(g2d, theta, leadLength); + } + g2d.setTransform(textTransform); + } + // Transform graphics to draw the body in the right place and at the + // right angle. + AffineTransform oldTransform = null; + double width; + double length; + if (useShapeRectAsPosition()) { + width = shapeRect.getHeight(); + length = shapeRect.getWidth(); + } else { + width = getWidth().convertToPixels(); + length = getLength().convertToPixels(); + } + oldTransform = g2d.getTransform(); + g2d.translate((points[0].x + points[1].x - length) / 2, (points[0].y + points[1].y - width) / 2); + g2d.rotate(theta, length / 2, width / 2); + // Draw body. + Composite oldComposite = g2d.getComposite(); + if (alpha < MAX_ALPHA) { + g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1f * alpha / MAX_ALPHA)); + } + if (bodyColor != null) { + g2d.setColor(outlineMode ? Constants.TRANSPARENT_COLOR : bodyColor); + g2d.fill(shape); + } + decorateComponentBody(g2d, outlineMode); + g2d.setComposite(oldComposite); + g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(1)); + Color finalBorderColor; + if (outlineMode) { + Theme theme = + (Theme) ConfigurationManager.getInstance().readObject(IPlugInPort.THEME_KEY, Constants.DEFAULT_THEME); + finalBorderColor = + componentState == ComponentState.SELECTED || componentState == ComponentState.DRAGGING ? SELECTION_COLOR + : theme.getOutlineColor(); + } else { + finalBorderColor = + componentState == ComponentState.SELECTED || componentState == ComponentState.DRAGGING ? SELECTION_COLOR + : borderColor; + } + g2d.setColor(finalBorderColor); + g2d.draw(shape); + + // Draw label. + g2d.setFont(project.getFont()); + if (useShapeRectAsPosition()) { + g2d.translate(shapeRect.x, shapeRect.y); + } + Color finalLabelColor; + if (outlineMode) { + Theme theme = + (Theme) ConfigurationManager.getInstance().readObject(IPlugInPort.THEME_KEY, Constants.DEFAULT_THEME); + finalLabelColor = + componentState == ComponentState.SELECTED || componentState == ComponentState.DRAGGING ? LABEL_COLOR_SELECTED + : theme.getOutlineColor(); + } else { + finalLabelColor = + componentState == ComponentState.SELECTED || componentState == ComponentState.DRAGGING ? LABEL_COLOR_SELECTED + : labelColor; + } + g2d.setColor(finalLabelColor); + FontMetrics fontMetrics = g2d.getFontMetrics(); + String label = ""; + label = display == Display.NAME ? getName() : (getValue() == null ? "" : getValue().toString()); + if (display == Display.NONE) { + label = ""; + } + if (display == Display.BOTH) { + label = getName() + " " + (getValue() == null ? "" : getValue().toString()); + } + Rectangle2D textRect = fontMetrics.getStringBounds(label, g2d); + // Don't offset in outline mode. + int offset = outlineMode ? 0 : getLabelOffset((int) length, (int) textRect.getWidth()); + // Adjust label angle if needed to make sure that it's readable. + if ((theta >= Math.PI / 2 && theta <= Math.PI) || (theta < -Math.PI / 2 && theta > -Math.PI)) { + g2d.rotate(Math.PI, length / 2, width / 2); + offset = -offset; + } + g2d.drawString(label, (int) (length - textRect.getWidth()) / 2 + offset, + calculateLabelYCoordinate(shapeRect, textRect, fontMetrics)); + g2d.setTransform(oldTransform); + } + } + + private void drawLeads(Graphics2D g2d, double theta, double leadLength) { + int endX = (int) (points[0].x + Math.cos(theta) * leadLength); + int endY = (int) (points[0].y + Math.sin(theta) * leadLength); + g2d.drawLine(points[0].x, points[0].y, endX, endY); + + endX = (int) (points[1].x + Math.cos(theta - Math.PI) * leadLength); + endY = (int) (points[1].y + Math.sin(theta - Math.PI) * leadLength); + g2d.drawLine(points[1].x, points[1].y, endX, endY); + } + private void drawLead(Graphics2D g2d, ComponentState componentState, IDrawingObserver observer, boolean isCopperArea) { if (isCopperArea) - observer.startTrackingContinuityArea(true); - g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(getLeadThickness())); - Color leadColor = - shouldShadeLeads() ? getLeadColorForPainting(componentState).darker() : getLeadColorForPainting(componentState); - g2d.setColor(leadColor); + observer.startTrackingContinuityArea(true); + + float thickness = getLeadThickness(); + Stroke stroke = null; + switch (getStyle()) { + case SOLID: + stroke = ObjectCache.getInstance().fetchBasicStroke(thickness); + break; + case DASHED: + stroke = + ObjectCache.getInstance().fetchStroke(thickness, new float[] {thickness * 2, thickness * 4}, thickness * 4); + break; + case DOTTED: + stroke = ObjectCache.getInstance().fetchStroke(thickness, new float[] {thickness / 4, thickness * 4}, 0); + break; + } + + g2d.setStroke(stroke); + Color leadColor = + shouldShadeLeads() ? getLeadColorForPainting(componentState).darker() : getLeadColorForPainting(componentState); + g2d.setColor(leadColor); g2d.drawLine(points[0].x, points[0].y, points[1].x, points[1].y); - + if (isCopperArea) - observer.stopTrackingContinuityArea(); - - if (shouldShadeLeads()) { - g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(getLeadThickness() - 2)); - leadColor = getLeadColorForPainting(componentState); - g2d.setColor(leadColor); - g2d.drawLine(points[0].x, points[0].y, points[1].x, points[1].y); - } - } - - protected void decorateComponentBody(Graphics2D g2d, boolean outlineMode) { - // Do nothing. - } - - protected int calculateLabelYCoordinate(Rectangle2D shapeRect, Rectangle2D textRect, FontMetrics fontMetrics) { - return (int) (shapeRect.getHeight() - textRect.getHeight()) / 2 + fontMetrics.getAscent(); - } - - protected boolean shouldShadeLeads() { - return true; - } - - protected boolean supportsStandingMode() { - return false; - } - - protected int getLabelOffset(int bodyWidth, int labelWidth) { - return 0; - } - - /** - * @return default component length. - */ - protected abstract Size getDefaultLength(); - - /** - * Returns default component width. - * - * @return - */ - protected abstract Size getDefaultWidth(); - - /** - * @return shape that represents component body. Shape should not be transformed and should be - * referenced to (0, 0). - */ - protected abstract Shape getBodyShape(); - - /** - * Controls how component shape should be placed relative to start and end point. - * - * @return true if shape rect should be used to center the component or false - * to place the component relative to length and width values. - */ - protected boolean useShapeRectAsPosition() { - return true; - } - - /** - * @return default lead thickness. Override this method to change it. - */ - protected float getLeadThickness() { - return getClosestOdd(LEAD_THICKNESS.convertToPixels()); - } - - /** - * @return default lead color. Override this method to change it. - */ - protected Color getLeadColorForPainting(ComponentState componentState) { - return componentState == ComponentState.SELECTED || componentState == ComponentState.DRAGGING ? SELECTION_COLOR - : getLeadColor(); - } - - @EditableProperty(name = "Lead color") - public Color getLeadColor() { - if (leadColor == null) { - leadColor = LEAD_COLOR_ICON; - } - return leadColor; - } - - public void setLeadColor(Color leadColor) { - this.leadColor = leadColor; - } - - protected int calculatePinSpacing(Rectangle shapeRect) { - return shapeRect.width; - } - - @Override - public int getControlPointCount() { - return points.length; - } - - @Override - public Point getControlPoint(int index) { - return (Point) points[index]; - } - - @Override - public boolean isControlPointSticky(int index) { - return true; - } - - @Override - public VisibilityPolicy getControlPointVisibilityPolicy(int index) { - return VisibilityPolicy.ALWAYS; - } - - @Override - public void setControlPoint(Point point, int index) { - points[index].setLocation(point); - } - - @EditableProperty(name = "Color") - public Color getBodyColor() { - return bodyColor; - } - - public void setBodyColor(Color bodyColor) { - this.bodyColor = bodyColor; - } - - public Color getStandingBodyColor() { - return bodyColor; - } - - @EditableProperty(name = "Border") - public Color getBorderColor() { - return borderColor; - } - - public void setBorderColor(Color borderColor) { - this.borderColor = borderColor; - } - - @EditableProperty(name = "Length", defaultable = true) - public Size getLength() { - return length; - } - - public void setLength(Size length) { - this.length = length; - } - - @EditableProperty(name = "Width", defaultable = true) - public Size getWidth() { - return width; - } - - public void setWidth(Size width) { - this.width = width; - } - - @EditableProperty - public Display getDisplay() { - return display; - } - - public void setDisplay(Display display) { - this.display = display; - } - - @EditableProperty(name = "Label color") - public Color getLabelColor() { - return labelColor; - } - - public void setLabelColor(Color labelColor) { - this.labelColor = labelColor; - } - - /** - * Override this method with @EditableProperty annotation in child classes where standing mode is - * supported - * - * @return - */ - public boolean getFlipStanding() { - return flipStanding; - } - - public void setFlipStanding(boolean flipStanding) { - this.flipStanding = flipStanding; - } -} + observer.stopTrackingContinuityArea(); + + if (shouldShadeLeads()) { + switch (getStyle()) { + case SOLID: + stroke = ObjectCache.getInstance().fetchBasicStroke(thickness - 2); + break; + case DASHED: + stroke = + ObjectCache.getInstance().fetchStroke(thickness - 2, new float[] {thickness * 2, thickness * 4}, + thickness * 4); + break; + case DOTTED: + stroke = ObjectCache.getInstance().fetchStroke(thickness - 2, new float[] {thickness / 4, thickness * 4}, 0); + break; + } + g2d.setStroke(stroke); + leadColor = getLeadColorForPainting(componentState); + g2d.setColor(leadColor); + g2d.drawLine(points[0].x, points[0].y, points[1].x, points[1].y); + } + } + + protected LineStyle getStyle() { + return LineStyle.SOLID; + } + + protected void decorateComponentBody(Graphics2D g2d, boolean outlineMode) { + // Do nothing. + } + + protected int calculateLabelYCoordinate(Rectangle2D shapeRect, Rectangle2D textRect, FontMetrics fontMetrics) { + return (int) (shapeRect.getHeight() - textRect.getHeight()) / 2 + fontMetrics.getAscent(); + } + + protected boolean shouldShadeLeads() { + return true; + } + + protected boolean supportsStandingMode() { + return false; + } + + protected int getLabelOffset(int bodyWidth, int labelWidth) { + return 0; + } + + /** + * @return default component length. + */ + protected abstract Size getDefaultLength(); + + /** + * Returns default component width. + * + * @return + */ + protected abstract Size getDefaultWidth(); + + /** + * @return shape that represents component body. Shape should not be transformed and should be + * referenced to (0, 0). + */ + protected abstract Shape getBodyShape(); + + /** + * Controls how component shape should be placed relative to start and end point. + * + * @return true if shape rect should be used to center the component or false + * to place the component relative to length and width values. + */ + protected boolean useShapeRectAsPosition() { + return true; + } + + /** + * @return default lead thickness. Override this method to change it. + */ + protected float getLeadThickness() { + return getClosestOdd(LEAD_THICKNESS.convertToPixels()); + } + + /** + * @return default lead color. Override this method to change it. + */ + protected Color getLeadColorForPainting(ComponentState componentState) { + return componentState == ComponentState.SELECTED || componentState == ComponentState.DRAGGING ? SELECTION_COLOR + : getLeadColor(); + } + + @EditableProperty(name = "Lead color") + public Color getLeadColor() { + if (leadColor == null) { + leadColor = LEAD_COLOR_ICON; + } + return leadColor; + } + + public void setLeadColor(Color leadColor) { + this.leadColor = leadColor; + } + + protected int calculatePinSpacing(Rectangle shapeRect) { + return shapeRect.width; + } + + @Override + public int getControlPointCount() { + return points.length; + } + + @Override + public Point getControlPoint(int index) { + return (Point) points[index]; + } + + @Override + public boolean isControlPointSticky(int index) { + return true; + } + + @Override + public VisibilityPolicy getControlPointVisibilityPolicy(int index) { + return VisibilityPolicy.ALWAYS; + } + + @Override + public void setControlPoint(Point point, int index) { + points[index].setLocation(point); + } + + @EditableProperty(name = "Color") + public Color getBodyColor() { + return bodyColor; + } + + public void setBodyColor(Color bodyColor) { + this.bodyColor = bodyColor; + } + + public Color getStandingBodyColor() { + return bodyColor; + } + + @EditableProperty(name = "Border") + public Color getBorderColor() { + return borderColor; + } + + public void setBorderColor(Color borderColor) { + this.borderColor = borderColor; + } + + @EditableProperty(name = "Length", defaultable = true) + public Size getLength() { + return length; + } + + public void setLength(Size length) { + this.length = length; + } + + @EditableProperty(name = "Width", defaultable = true) + public Size getWidth() { + return width; + } + + public void setWidth(Size width) { + this.width = width; + } + + @EditableProperty + public Display getDisplay() { + return display; + } + + public void setDisplay(Display display) { + this.display = display; + } + + @EditableProperty(name = "Label color") + public Color getLabelColor() { + return labelColor; + } + + public void setLabelColor(Color labelColor) { + this.labelColor = labelColor; + } + + /** + * Override this method with @EditableProperty annotation in child classes where standing mode is + * supported + * + * @return + */ + public boolean getFlipStanding() { + return flipStanding; + } + + public void setFlipStanding(boolean flipStanding) { + this.flipStanding = flipStanding; + } +} diff --git a/diylc/diylc-core/src/org/diylc/presenter/G2DWrapper.java b/diylc/diylc-core/src/org/diylc/presenter/G2DWrapper.java index a3c1515e..81e267c2 100644 --- a/diylc/diylc-core/src/org/diylc/presenter/G2DWrapper.java +++ b/diylc/diylc-core/src/org/diylc/presenter/G2DWrapper.java @@ -200,8 +200,17 @@ class G2DWrapper extends Graphics2D implements IDrawingObserver { if (!drawingComponent || !trackingAllowed || s.equals(lastShape)) { return; } - - appendShape(getStroke().createStrokedShape(s)); + Stroke stroke = getStroke(); + if (stroke instanceof BasicStroke) { + BasicStroke bstroke = (BasicStroke) stroke; + if (bstroke.getLineWidth() < 3) { + appendShape(ObjectCache.getInstance().fetchBasicStroke(3).createStrokedShape(s)); + } else { + appendShape(getStroke().createStrokedShape(s)); + } + } else { + appendShape(getStroke().createStrokedShape(s)); + } } @Override diff --git a/diylc/diylc-library/lib/diylc-core.jar b/diylc/diylc-library/lib/diylc-core.jar index be9d92c8..3dfcd2f7 100644 Binary files a/diylc/diylc-library/lib/diylc-core.jar and b/diylc/diylc-library/lib/diylc-core.jar differ diff --git a/diylc/diylc-library/src/org/diylc/components/boards/EyeletBoard.java b/diylc/diylc-library/src/org/diylc/components/boards/EyeletBoard.java index 6da1220e..a1a9fab0 100644 --- a/diylc/diylc-library/src/org/diylc/components/boards/EyeletBoard.java +++ b/diylc/diylc-library/src/org/diylc/components/boards/EyeletBoard.java @@ -48,7 +48,7 @@ public class EyeletBoard extends AbstractBoard { private static final long serialVersionUID = 1L; - public static Color BOARD_COLOR = Color.decode("#CCFFCC"); + public static Color BOARD_COLOR = Color.decode("#E3EAB4"); public static Color BORDER_COLOR = BOARD_COLOR.darker(); public static Color EYELET_COLOR = Color.decode("#C3E4ED"); diff --git a/diylc/diylc-library/src/org/diylc/components/connectivity/CurvedTrace.java b/diylc/diylc-library/src/org/diylc/components/connectivity/CurvedTrace.java index 9d5f8388..59419ed8 100644 --- a/diylc/diylc-library/src/org/diylc/components/connectivity/CurvedTrace.java +++ b/diylc/diylc-library/src/org/diylc/components/connectivity/CurvedTrace.java @@ -1,112 +1,108 @@ /* + * + * DIY Layout Creator (DIYLC). Copyright (c) 2009-2018 held jointly by the individual authors. + * + * This file is part of DIYLC. + * + * DIYLC is free software: you can redistribute it and/or modify it under the terms of the GNU + * General Public License as published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * DIYLC is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even + * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General + * Public License for more details. + * + * You should have received a copy of the GNU General Public License along with DIYLC. If not, see + * . + */ +package org.diylc.components.connectivity; - DIY Layout Creator (DIYLC). - Copyright (c) 2009-2018 held jointly by the individual authors. +import java.awt.Color; +import java.awt.Graphics2D; +import java.awt.geom.Path2D; - This file is part of DIYLC. - - DIYLC is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - DIYLC is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with DIYLC. If not, see . - -*/ -package org.diylc.components.connectivity; - -import java.awt.Color; -import java.awt.Graphics2D; -import java.awt.geom.CubicCurve2D; - -import org.diylc.common.SimpleComponentTransformer; -import org.diylc.common.ObjectCache; -import org.diylc.common.PCBLayer; -import org.diylc.components.AbstractCurvedComponent; -import org.diylc.core.ComponentState; -import org.diylc.core.IDIYComponent; +import org.diylc.common.ObjectCache; +import org.diylc.common.PCBLayer; +import org.diylc.common.SimpleComponentTransformer; +import org.diylc.components.AbstractCurvedComponent; +import org.diylc.core.ComponentState; +import org.diylc.core.IDIYComponent; import org.diylc.core.IDrawingObserver; -import org.diylc.core.annotations.BomPolicy; -import org.diylc.core.annotations.ComponentDescriptor; -import org.diylc.core.annotations.EditableProperty; -import org.diylc.core.annotations.KeywordPolicy; -import org.diylc.core.measures.Size; -import org.diylc.core.measures.SizeUnit; - -@ComponentDescriptor(name = "Curved Trace", author = "Branislav Stojkovic", category = "Connectivity", - instanceNamePrefix = "Trace", description = "Curved copper trace with two control points", - zOrder = IDIYComponent.TRACE, bomPolicy = BomPolicy.NEVER_SHOW, autoEdit = false, - keywordPolicy = KeywordPolicy.SHOW_TAG, keywordTag = "PCB", transformer = SimpleComponentTransformer.class) -public class CurvedTrace extends AbstractCurvedComponent { - - private static final long serialVersionUID = 1L; - - public static Color COLOR = Color.black; - public static Size SIZE = new Size(1d, SizeUnit.mm); - - protected Size size = SIZE; - private PCBLayer layer = PCBLayer._1; - - @Override - protected Color getDefaultColor() { - return COLOR; - } - - @Override - protected void drawCurve(CubicCurve2D curve, Graphics2D g2d, ComponentState componentState, IDrawingObserver drawingObserver) { - float thickness = (float) size.convertToPixels(); - g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(thickness)); - Color curveColor = - componentState == ComponentState.SELECTED || componentState == ComponentState.DRAGGING ? SELECTION_COLOR - : color; +import org.diylc.core.annotations.BomPolicy; +import org.diylc.core.annotations.ComponentDescriptor; +import org.diylc.core.annotations.EditableProperty; +import org.diylc.core.annotations.KeywordPolicy; +import org.diylc.core.measures.Size; +import org.diylc.core.measures.SizeUnit; + +@ComponentDescriptor(name = "Curved Trace", author = "Branislav Stojkovic", category = "Connectivity", + instanceNamePrefix = "Trace", description = "Curved copper trace with two control points", + zOrder = IDIYComponent.TRACE, bomPolicy = BomPolicy.NEVER_SHOW, autoEdit = false, + keywordPolicy = KeywordPolicy.SHOW_TAG, keywordTag = "PCB", transformer = SimpleComponentTransformer.class) +public class CurvedTrace extends AbstractCurvedComponent { + + private static final long serialVersionUID = 1L; + + public static Color COLOR = Color.black; + public static Size SIZE = new Size(1d, SizeUnit.mm); + + protected Size size = SIZE; + private PCBLayer layer = PCBLayer._1; + + @Override + protected Color getDefaultColor() { + return COLOR; + } + + @Override + protected void drawCurve(Path2D curve, Graphics2D g2d, ComponentState componentState, IDrawingObserver drawingObserver) { + float thickness = (float) size.convertToPixels(); + g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(thickness)); + Color curveColor = + componentState == ComponentState.SELECTED || componentState == ComponentState.DRAGGING ? SELECTION_COLOR + : color; g2d.setColor(curveColor); - drawingObserver.startTrackingContinuityArea(true); + drawingObserver.startTrackingContinuityArea(true); g2d.draw(curve); - drawingObserver.stopTrackingContinuityArea(); - } - - @EditableProperty(name = "Width") - public Size getThickness() { - return size; - } - - public void setThickness(Size size) { - this.size = size; - } - - @EditableProperty - public PCBLayer getLayer() { - if (layer == null) { - layer = PCBLayer._1; - } - return layer; - } - - public void setLayer(PCBLayer layer) { - this.layer = layer; - } - - @Override - public Void getValue() { - return null; - } - - @Override - public void setValue(Void value) {} - - @Override - public Byte getAlpha() { - return super.getAlpha(); - } - - @Override - public void setAlpha(Byte alpha) { - super.setAlpha(alpha); - } -} + drawingObserver.stopTrackingContinuityArea(); + } + + @EditableProperty(name = "Width") + public Size getThickness() { + return size; + } + + public void setThickness(Size size) { + this.size = size; + } + + @EditableProperty + public PCBLayer getLayer() { + if (layer == null) { + layer = PCBLayer._1; + } + return layer; + } + + public void setLayer(PCBLayer layer) { + this.layer = layer; + } + + @Override + public Void getValue() { + return null; + } + + @Override + public void setValue(Void value) {} + + @Override + public Byte getAlpha() { + return super.getAlpha(); + } + + @Override + public void setAlpha(Byte alpha) { + super.setAlpha(alpha); + } +} diff --git a/diylc/diylc-library/src/org/diylc/components/connectivity/HookupWire.java b/diylc/diylc-library/src/org/diylc/components/connectivity/HookupWire.java index b1d6dd9c..f5fa2d07 100644 --- a/diylc/diylc-library/src/org/diylc/components/connectivity/HookupWire.java +++ b/diylc/diylc-library/src/org/diylc/components/connectivity/HookupWire.java @@ -1,90 +1,112 @@ /* + * + * DIY Layout Creator (DIYLC). Copyright (c) 2009-2018 held jointly by the individual authors. + * + * This file is part of DIYLC. + * + * DIYLC is free software: you can redistribute it and/or modify it under the terms of the GNU + * General Public License as published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * DIYLC is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even + * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General + * Public License for more details. + * + * You should have received a copy of the GNU General Public License along with DIYLC. If not, see + * . + */ +package org.diylc.components.connectivity; - DIY Layout Creator (DIYLC). - Copyright (c) 2009-2018 held jointly by the individual authors. +import java.awt.Color; +import java.awt.Graphics2D; +import java.awt.Stroke; +import java.awt.geom.Path2D; - This file is part of DIYLC. - - DIYLC is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - DIYLC is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with DIYLC. If not, see . - -*/ -package org.diylc.components.connectivity; - -import java.awt.Color; -import java.awt.Graphics2D; -import java.awt.geom.CubicCurve2D; - -import org.diylc.common.ObjectCache; -import org.diylc.common.SimpleComponentTransformer; -import org.diylc.components.AbstractCurvedComponent; -import org.diylc.core.ComponentState; -import org.diylc.core.IDIYComponent; +import org.diylc.common.ObjectCache; +import org.diylc.common.SimpleComponentTransformer; +import org.diylc.components.AbstractCurvedComponent; +import org.diylc.core.ComponentState; +import org.diylc.core.IDIYComponent; import org.diylc.core.IDrawingObserver; -import org.diylc.core.annotations.BomPolicy; -import org.diylc.core.annotations.ComponentDescriptor; -import org.diylc.core.annotations.EditableProperty; -import org.diylc.utils.Constants; - -@ComponentDescriptor(name = "Hookup Wire", author = "Branislav Stojkovic", category = "Connectivity", - instanceNamePrefix = "W", description = "Flexible wire with two control points", zOrder = IDIYComponent.COMPONENT, - flexibleZOrder = true, bomPolicy = BomPolicy.NEVER_SHOW, autoEdit = false, - transformer = SimpleComponentTransformer.class, continuity = true) -public class HookupWire extends AbstractCurvedComponent { - - private static final long serialVersionUID = 1L; - - public static Color COLOR = Color.green; - public static double INSULATION_THICKNESS_PCT = 0.3; - - protected AWG gauge = AWG._22; - - @Override - protected Color getDefaultColor() { - return COLOR; - } - - @Override - protected void drawCurve(CubicCurve2D curve, Graphics2D g2d, ComponentState componentState, IDrawingObserver drawingObserver) { - int thickness = - (int) (Math.pow(Math.E, -1.12436 - 0.11594 * gauge.getValue()) * Constants.PIXELS_PER_INCH * (1 + 2 * INSULATION_THICKNESS_PCT)); - Color curveColor = - componentState == ComponentState.SELECTED || componentState == ComponentState.DRAGGING ? SELECTION_COLOR - : color.darker(); - g2d.setColor(curveColor); - g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(thickness)); - g2d.draw(curve); - if (componentState == ComponentState.NORMAL) { - g2d.setColor(color); - g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(thickness - 2)); - g2d.draw(curve); - } - } - - @EditableProperty(name = "AWG") - public AWG getGauge() { - return gauge; - } - - public void setGauge(AWG gauge) { - this.gauge = gauge; - } - - @Override - public Void getValue() { - return null; - } - - @Override - public void setValue(Void value) {} -} +import org.diylc.core.annotations.BomPolicy; +import org.diylc.core.annotations.ComponentDescriptor; +import org.diylc.core.annotations.EditableProperty; +import org.diylc.utils.Constants; + +@ComponentDescriptor(name = "Hookup Wire", author = "Branislav Stojkovic", category = "Connectivity", + instanceNamePrefix = "W", description = "Flexible wire with two control points", zOrder = IDIYComponent.COMPONENT, + flexibleZOrder = true, bomPolicy = BomPolicy.NEVER_SHOW, autoEdit = false, + transformer = SimpleComponentTransformer.class, continuity = true) +public class HookupWire extends AbstractCurvedComponent { + + private static final long serialVersionUID = 1L; + + public static Color COLOR = Color.green; + public static double INSULATION_THICKNESS_PCT = 0.3; + + protected AWG gauge = AWG._22; + + @Override + protected Color getDefaultColor() { + return COLOR; + } + + @Override + protected void drawCurve(Path2D curve, Graphics2D g2d, ComponentState componentState, IDrawingObserver drawingObserver) { + int thickness = + (int) (Math.pow(Math.E, -1.12436 - 0.11594 * gauge.getValue()) * Constants.PIXELS_PER_INCH * (1 + 2 * INSULATION_THICKNESS_PCT)); + Color curveColor = + componentState == ComponentState.SELECTED || componentState == ComponentState.DRAGGING ? SELECTION_COLOR + : color.darker(); + g2d.setColor(curveColor); + Stroke stroke = null; + switch (getStyle()) { + case SOLID: + stroke = ObjectCache.getInstance().fetchBasicStroke(thickness); + break; + case DASHED: + stroke = + ObjectCache.getInstance().fetchStroke(thickness, new float[] {thickness * 2, thickness * 3}, thickness * 4); + break; + case DOTTED: + stroke = ObjectCache.getInstance().fetchStroke(thickness, new float[] {thickness / 4, thickness * 3}, 0); + break; + } + g2d.setStroke(stroke); + g2d.draw(curve); + if (componentState == ComponentState.NORMAL) { + g2d.setColor(color); + switch (getStyle()) { + case SOLID: + stroke = ObjectCache.getInstance().fetchBasicStroke(thickness - 2); + break; + case DASHED: + stroke = + ObjectCache.getInstance().fetchStroke(thickness - 2, new float[] {thickness * 2, thickness * 3}, + thickness * 4); + break; + case DOTTED: + stroke = ObjectCache.getInstance().fetchStroke(thickness - 2, new float[] {thickness / 4, thickness * 3}, 0); + } + g2d.setStroke(stroke); + g2d.draw(curve); + } + } + + @EditableProperty(name = "AWG") + public AWG getGauge() { + return gauge; + } + + public void setGauge(AWG gauge) { + this.gauge = gauge; + } + + @Override + public Void getValue() { + return null; + } + + @Override + public void setValue(Void value) {} +} diff --git a/diylc/diylc-library/src/org/diylc/components/connectivity/Jumper.java b/diylc/diylc-library/src/org/diylc/components/connectivity/Jumper.java index 95670911..c2c6b64d 100644 --- a/diylc/diylc-library/src/org/diylc/components/connectivity/Jumper.java +++ b/diylc/diylc-library/src/org/diylc/components/connectivity/Jumper.java @@ -24,8 +24,9 @@ package org.diylc.components.connectivity; import java.awt.Color; import java.awt.Graphics2D; import java.awt.Shape; - + import org.diylc.common.Display; +import org.diylc.common.LineStyle; import org.diylc.common.ObjectCache; import org.diylc.common.SimpleComponentTransformer; import org.diylc.components.AbstractLeadedComponent; @@ -48,7 +49,8 @@ public class Jumper extends AbstractLeadedComponent { public static Color COLOR = Color.blue; @Deprecated - private Color color; + private Color color; + protected LineStyle style = LineStyle.SOLID; public Jumper() { super(); @@ -78,6 +80,17 @@ public class Jumper extends AbstractLeadedComponent { this.leadColor = color; } return super.getLeadColor(); + } + + @EditableProperty(name = "Style") + public LineStyle getStyle() { + if (style == null) + style = LineStyle.SOLID; + return style; + } + + public void setStyle(LineStyle style) { + this.style = style; } public Color getBodyColor() { diff --git a/diylc/diylc-library/src/org/diylc/components/connectivity/Line.java b/diylc/diylc-library/src/org/diylc/components/connectivity/Line.java index 2d8427fc..0fc799a2 100644 --- a/diylc/diylc-library/src/org/diylc/components/connectivity/Line.java +++ b/diylc/diylc-library/src/org/diylc/components/connectivity/Line.java @@ -24,8 +24,10 @@ package org.diylc.components.connectivity; import java.awt.Color; import java.awt.Graphics2D; import java.awt.Shape; - +import java.awt.Stroke; + import org.diylc.common.Display; +import org.diylc.common.LineStyle; import org.diylc.common.ObjectCache; import org.diylc.common.SimpleComponentTransformer; import org.diylc.components.AbstractLeadedComponent; @@ -49,7 +51,8 @@ public class Line extends AbstractLeadedComponent { public static Color COLOR = Color.black; - private Color color = COLOR; + private Color color = COLOR; + protected LineStyle style = LineStyle.SOLID; @Override public void drawIcon(Graphics2D g2d, int width, int height) { @@ -60,8 +63,21 @@ public class Line extends AbstractLeadedComponent { @Override public void draw(Graphics2D g2d, ComponentState componentState, boolean outlineMode, Project project, - IDrawingObserver drawingObserver) { - g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(1)); + IDrawingObserver drawingObserver) { + float thickness = 1f; + Stroke stroke = null; + switch (getStyle()) { + case SOLID: + stroke = ObjectCache.getInstance().fetchBasicStroke(thickness); + break; + case DASHED: + stroke = ObjectCache.getInstance().fetchStroke(thickness, new float[] {thickness * 2}, thickness * 4); + break; + case DOTTED: + stroke = ObjectCache.getInstance().fetchStroke(thickness, new float[] {thickness / 4, thickness * 3}, 0); + break; + } + g2d.setStroke(stroke); g2d.setColor(color); g2d.drawLine(getControlPoint(0).x, getControlPoint(0).y, getControlPoint(1).x, getControlPoint(1).y); } @@ -84,6 +100,17 @@ public class Line extends AbstractLeadedComponent { public void setColor(Color color) { this.color = color; + } + + @EditableProperty(name = "Style") + public LineStyle getStyle() { + if (style == null) + style = LineStyle.SOLID; + return style; + } + + public void setStyle(LineStyle style) { + this.style = style; } public Color getBodyColor() { diff --git a/diylc/diylc-swing/build.xml b/diylc/diylc-swing/build.xml index 0cf3f168..9c64b72c 100644 --- a/diylc/diylc-swing/build.xml +++ b/diylc/diylc-swing/build.xml @@ -7,7 +7,7 @@ - + diff --git a/diylc/diylc-swing/lib/diylc-core.jar b/diylc/diylc-swing/lib/diylc-core.jar index be9d92c8..3dfcd2f7 100644 Binary files a/diylc/diylc-swing/lib/diylc-core.jar and b/diylc/diylc-swing/lib/diylc-core.jar differ diff --git a/diylc/diylc-swing/library/main.jar b/diylc/diylc-swing/library/main.jar index e970987c..d6548915 100644 Binary files a/diylc/diylc-swing/library/main.jar and b/diylc/diylc-swing/library/main.jar differ diff --git a/diylc/diylc-swing/update.xml b/diylc/diylc-swing/update.xml index f0c793cc..99834eb1 100644 --- a/diylc/diylc-swing/update.xml +++ b/diylc/diylc-swing/update.xml @@ -1932,12 +1932,20 @@ 3 - 42 - 2 + 43 + 0 2018-12-17 00:00:00.000 CET + + NEW_FEATURE + Added "Dashed" and "Dotted" style to "Hookup Wire", "Jumper" and "Line" components + + + NEW_FEATURE + Added five and seven control point options to curved components for more flexibility (literally) + NEW_FEATURE Added "Turret Lug" component