From 194c8e06068043628c36b04feaafb7c41b9a3928 Mon Sep 17 00:00:00 2001 From: Bane Stojkovic Date: Mon, 6 Apr 2026 21:04:55 +0200 Subject: [PATCH] Improved data model for storing transparency alpha and other properties that are edited using a slider widget; as a result, the editing is more precise and does not randomly change to neighboring values --- .../java/org/diylc/common/Percentage.java | 75 + .../components/AbstractCurvedComponent.java | 5 +- .../AbstractTransparentComponent.java | 40 +- .../diylc/core/annotations/PercentEditor.java | 4 +- .../org/diylc/presenter/DrawingManager.java | 2 +- .../diylc-core/src/main/resources/update.xml | 4 + .../org/diylc/presenter/CalcUtilsTest.java | 8 +- .../components/AbstractLeadedComponent.java | 15 +- .../components/boards/AbstractBoard.java | 7 +- .../diylc/components/boards/BlankBoard.java | 5 +- .../diylc/components/boards/EyeletBoard.java | 4 +- .../components/boards/MarshallPerfBoard.java | 4 +- .../diylc/components/boards/PerfBoard.java | 4 +- .../org/diylc/components/boards/TagStrip.java | 821 ++++++----- .../components/boards/TerminalStrip.java | 5 +- .../diylc/components/boards/TriPadBoard.java | 423 +++--- .../diylc/components/boards/VeroBoard.java | 307 ++-- .../components/chassis/ChassisPanel.java | 219 ++- .../components/chassis/EllipticalCutout.java | 147 +- .../components/chassis/PolygonalCutout.java | 249 ++-- .../components/chassis/RectangularCutout.java | 181 ++- .../components/connectivity/CurvedTrace.java | 3 +- .../components/connectivity/CutLine.java | 327 +++-- .../diylc/components/connectivity/Eyelet.java | 375 +++-- .../components/connectivity/GroundFill.java | 443 +++--- .../connectivity/MultimeterProbe.java | 9 +- .../connectivity/PCBTerminalBlock.java | 6 +- .../components/connectivity/SolderLug.java | 5 +- .../components/connectivity/SolderPad.java | 5 +- .../components/connectivity/TraceCut.java | 533 ++++--- .../diylc/components/connectivity/Turret.java | 365 +++-- .../electromechanical/BatterySnap9V.java | 547 ++++--- .../electromechanical/CliffJack1_4.java | 713 +++++----- .../electromechanical/CliffJack1_8.java | 5 +- .../electromechanical/ClosedJack1_4.java | 765 +++++----- .../electromechanical/DIPSwitch.java | 12 +- .../electromechanical/DrillHole.java | 5 +- .../electromechanical/FuseHolderPanel.java | 5 +- .../electromechanical/IECSocket.java | 5 +- .../electromechanical/MiniRelay.java | 951 +++++++------ .../electromechanical/MiniToggleSwitch.java | 1237 ++++++++-------- .../electromechanical/NeutrikJack1_4.java | 747 +++++----- .../electromechanical/OpenJack1_4.java | 922 ++++++------ .../electromechanical/OpenJack1_8.java | 10 +- .../electromechanical/PilotLampHolder.java | 10 +- .../electromechanical/PinHeader.java | 5 +- .../electromechanical/PlasticDCJack.java | 567 ++++---- .../components/electromechanical/RCAJack.java | 684 +++++---- .../RotarySelectorSwitch.java | 10 +- .../electromechanical/RotarySwitchOpen.java | 14 +- .../electromechanical/RotarySwitchSealed.java | 5 +- .../electromechanical/SlideSwitch.java | 6 +- .../electromechanical/TactileMicroSwitch.java | 5 +- .../components/guitar/Freeway3x3_03.java | 5 +- .../components/guitar/Freeway3x3_05.java | 5 +- .../components/guitar/HumbuckerPickup.java | 5 +- .../components/guitar/JazzBassPickup.java | 569 ++++---- .../org/diylc/components/guitar/LPSwitch.java | 881 ++++++------ .../diylc/components/guitar/LeverSwitch.java | 5 +- .../diylc/components/guitar/P90Pickup.java | 753 +++++----- .../diylc/components/guitar/PBassPickup.java | 543 ++++--- .../org/diylc/components/guitar/S1Switch.java | 5 +- .../components/guitar/SchallerMegaSwitch.java | 6 +- .../components/guitar/SingleCoilPickup.java | 917 ++++++------ .../components/guitar/StingrayBassPickup.java | 6 +- .../java/org/diylc/components/misc/Image.java | 7 +- .../org/diylc/components/misc/Loadline.java | 6 +- .../org/diylc/components/misc/SVGImage.java | 7 +- .../components/passive/AudioTransformer.java | 1059 +++++++------- .../diylc/components/passive/BoxTrimmer.java | 5 +- .../passive/MultiSectionCapacitor.java | 5 +- .../passive/PotentiometerPanel.java | 1251 ++++++++--------- .../passive/TrimmerPotentiometer.java | 5 +- .../semiconductors/BridgeRectifier.java | 14 +- .../components/semiconductors/DIL_IC.java | 5 +- .../components/semiconductors/ICSymbol.java | 593 ++++---- .../semiconductors/LogicGateSymbol.java | 5 +- .../semiconductors/MultiwattIC.java | 12 +- .../components/semiconductors/SIL_IC.java | 938 ++++++------ .../semiconductors/TransistorTO1.java | 558 ++++---- .../semiconductors/TransistorTO126.java | 754 +++++----- .../semiconductors/TransistorTO220.java | 880 ++++++------ .../semiconductors/TransistorTO3.java | 784 +++++------ .../semiconductors/TransistorTO92.java | 580 ++++---- .../org/diylc/components/shapes/Ellipse.java | 147 +- .../org/diylc/components/shapes/Polygon.java | 255 ++-- .../diylc/components/shapes/Rectangle.java | 183 ++- .../diylc/components/shapes/TapeMeasure.java | 3 +- .../components/smd/PassiveSMDComponent.java | 899 ++++++------ .../diylc/components/smd/SOT23Package.java | 8 +- .../components/tube/Jumbo4PinTubeSocket.java | 5 +- .../diylc/components/tube/SubminiTube.java | 5 +- .../org/diylc/components/tube/TubeSocket.java | 921 ++++++------ .../org/diylc/serialization/V1FileParser.java | 8 +- .../org/diylc/serialization/V2FileParser.java | 138 +- .../swing/gui/editor/FieldEditorFactory.java | 5 +- ...{ByteEditor.java => PercentageEditor.java} | 237 ++-- .../swing/loadline/LoadlineEditorFrame.java | 9 +- 98 files changed, 12813 insertions(+), 13008 deletions(-) create mode 100644 diylc/diylc-core/src/main/java/org/diylc/common/Percentage.java rename diylc/diylc-swing/src/main/java/org/diylc/swing/gui/editor/{ByteEditor.java => PercentageEditor.java} (65%) diff --git a/diylc/diylc-core/src/main/java/org/diylc/common/Percentage.java b/diylc/diylc-core/src/main/java/org/diylc/common/Percentage.java new file mode 100644 index 000000000..57370cfc5 --- /dev/null +++ b/diylc/diylc-core/src/main/java/org/diylc/common/Percentage.java @@ -0,0 +1,75 @@ +/* + + DIY Layout Creator (DIYLC). + Copyright (c) 2009-2025 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; + +import java.io.Serializable; + +public class Percentage implements Serializable, Cloneable { + + private static final long serialVersionUID = 1L; + + private int value; + + public Percentage(int value) { + this.value = value; + } + + public int getValue() { + return value; + } + + public void setValue(int value) { + this.value = value; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + value; + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + Percentage other = (Percentage) obj; + if (value != other.value) + return false; + return true; + } + + @Override + public String toString() { + return value + "%"; + } + + @Override + public Object clone() throws CloneNotSupportedException { + return super.clone(); + } +} diff --git a/diylc/diylc-core/src/main/java/org/diylc/components/AbstractCurvedComponent.java b/diylc/diylc-core/src/main/java/org/diylc/components/AbstractCurvedComponent.java index b6c181433..6233b1eb0 100644 --- a/diylc/diylc-core/src/main/java/org/diylc/components/AbstractCurvedComponent.java +++ b/diylc/diylc-core/src/main/java/org/diylc/components/AbstractCurvedComponent.java @@ -149,10 +149,7 @@ public abstract class AbstractCurvedComponent extends AbstractTransparentComp path.curveTo(p[4].getX(), p[4].getY(), p[5].getX(), p[5].getY(), p[6].getX(), p[6].getY()); } - Composite oldComposite = g2d.getComposite(); - if (alpha < MAX_ALPHA) { - g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1f * alpha / MAX_ALPHA)); - } + Composite oldComposite = applyAlpha(g2d, componentState); drawCurve(path, g2d, componentState, drawingObserver); diff --git a/diylc/diylc-core/src/main/java/org/diylc/components/AbstractTransparentComponent.java b/diylc/diylc-core/src/main/java/org/diylc/components/AbstractTransparentComponent.java index 46a3c3d17..1de45f740 100644 --- a/diylc/diylc-core/src/main/java/org/diylc/components/AbstractTransparentComponent.java +++ b/diylc/diylc-core/src/main/java/org/diylc/components/AbstractTransparentComponent.java @@ -22,24 +22,46 @@ package org.diylc.components; import org.diylc.core.annotations.EditableProperty; +import org.diylc.core.ComponentState; +import org.diylc.common.Percentage; + +import java.awt.*; public abstract class AbstractTransparentComponent extends AbstractComponent { private static final long serialVersionUID = 1L; - public static byte MAX_ALPHA = 127; + public static byte MAX_ALPHA_LEGACY = Byte.MAX_VALUE; + public static int MAX_ALPHA = 100; - protected Byte alpha = MAX_ALPHA; + @Deprecated + protected Byte alpha; - @EditableProperty - public Byte getAlpha() { - if (alpha == null) { - alpha = MAX_ALPHA; + protected Percentage alphaPercent = new Percentage(100); + + @EditableProperty(name = "Alpha") + public Percentage getAlpha() { + if (alphaPercent == null) { + if (alpha != null) { + alphaPercent = new Percentage(Math.round(100f * alpha / MAX_ALPHA_LEGACY)); + alpha = null; + } else { + alphaPercent = new Percentage(100); + } } - return alpha; + return alphaPercent; } - public void setAlpha(Byte alpha) { - this.alpha = alpha; + public void setAlpha(Percentage alphaPercent) { + this.alphaPercent = alphaPercent; + } + + public Composite applyAlpha(Graphics2D g2d, ComponentState componentState) { + Composite oldComposite = g2d.getComposite(); + int alpha = componentState == ComponentState.DRAGGING ? 0 : getAlpha().getValue(); + if (alpha < MAX_ALPHA) { + g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, alpha / 100f)); + } + return oldComposite; } } diff --git a/diylc/diylc-core/src/main/java/org/diylc/core/annotations/PercentEditor.java b/diylc/diylc-core/src/main/java/org/diylc/core/annotations/PercentEditor.java index 0961e073c..6ce553b93 100644 --- a/diylc/diylc-core/src/main/java/org/diylc/core/annotations/PercentEditor.java +++ b/diylc/diylc-core/src/main/java/org/diylc/core/annotations/PercentEditor.java @@ -27,5 +27,7 @@ import java.lang.annotation.RetentionPolicy; @Retention(RetentionPolicy.RUNTIME) public @interface PercentEditor { - public byte _100PercentValue(); + public int minValue() default 0; + + public int maxValue() default 100; } diff --git a/diylc/diylc-core/src/main/java/org/diylc/presenter/DrawingManager.java b/diylc/diylc-core/src/main/java/org/diylc/presenter/DrawingManager.java index 6cccc0766..936d2ffb1 100644 --- a/diylc/diylc-core/src/main/java/org/diylc/presenter/DrawingManager.java +++ b/diylc/diylc-core/src/main/java/org/diylc/presenter/DrawingManager.java @@ -68,7 +68,7 @@ import org.diylc.utils.Constants; public class DrawingManager { private static final Logger LOG = Logger.getLogger(DrawingManager.class); - public static final byte MIRROR_ALPHA = 64; + public static final Percentage MIRROR_ALPHA = new Percentage(50); public static int CONTROL_POINT_SIZE = 7; public static double EXTRA_SPACE = 0.25; diff --git a/diylc/diylc-core/src/main/resources/update.xml b/diylc/diylc-core/src/main/resources/update.xml index 3e2732e80..a5f02ad08 100644 --- a/diylc/diylc-core/src/main/resources/update.xml +++ b/diylc/diylc-core/src/main/resources/update.xml @@ -317,6 +317,10 @@ NEW_FEATURE Added more ceramic resistor variants to 'Resistor' component + + IMPROVEMENT + Improved data model for storing transparency alpha and other properties that are edited using a slider widget; as a result, the editing is more precise and does not randomly change to neighboring values + IMPROVEMENT Improved editing experience of integer properties (e.g. number of terminals on a tag strip) by using the spinner text field diff --git a/diylc/diylc-core/src/test/java/org/diylc/presenter/CalcUtilsTest.java b/diylc/diylc-core/src/test/java/org/diylc/presenter/CalcUtilsTest.java index f0542ff65..75c1c8c8c 100644 --- a/diylc/diylc-core/src/test/java/org/diylc/presenter/CalcUtilsTest.java +++ b/diylc/diylc-core/src/test/java/org/diylc/presenter/CalcUtilsTest.java @@ -235,7 +235,7 @@ public class CalcUtilsTest { assertEquals(Color.BLACK.getRed(), result.getRed()); assertEquals(Color.BLACK.getGreen(), result.getGreen()); assertEquals(Color.BLACK.getBlue(), result.getBlue()); - assertEquals(128, result.getAlpha()); + assertEquals(128, result.getAlpha().getValue()); // Test light color with alpha - should become WHITE Color transparentLight = new Color(255, 255, 200, 128); @@ -243,16 +243,16 @@ public class CalcUtilsTest { assertEquals(Color.WHITE.getRed(), result.getRed()); assertEquals(Color.WHITE.getGreen(), result.getGreen()); assertEquals(Color.WHITE.getBlue(), result.getBlue()); - assertEquals(128, result.getAlpha()); + assertEquals(128, result.getAlpha().getValue()); // Test fully transparent color Color transparent = new Color(100, 150, 200, 0); result = CalcUtils.convertToMonochrome(transparent); - assertEquals(0, result.getAlpha()); + assertEquals(0, result.getAlpha().getValue()); // Test opaque color - alpha should remain 255 Color opaque = new Color(50, 50, 50); result = CalcUtils.convertToMonochrome(opaque); - assertEquals(255, result.getAlpha()); + assertEquals(255, result.getAlpha().getValue()); } } diff --git a/diylc/diylc-library/src/main/java/org/diylc/components/AbstractLeadedComponent.java b/diylc/diylc-library/src/main/java/org/diylc/components/AbstractLeadedComponent.java index 62170423d..b17b9200b 100644 --- a/diylc/diylc-library/src/main/java/org/diylc/components/AbstractLeadedComponent.java +++ b/diylc/diylc-library/src/main/java/org/diylc/components/AbstractLeadedComponent.java @@ -165,10 +165,7 @@ public abstract class AbstractLeadedComponent extends AbstractLabeledComponen new Ellipse2D.Double((getFlipStanding() ? getPoints()[1] : getPoints()[0]).getX() - width / 2, (getFlipStanding() ? getPoints()[1] : getPoints()[0]).getY() - width / 2, width, width); shapeRect = body.getBounds(); - Composite oldComposite = g2d.getComposite(); - if (alpha < MAX_ALPHA) { - g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1f * alpha / MAX_ALPHA)); - } + Composite oldComposite = applyAlpha(g2d, componentState); g2d.setColor(outlineMode ? Constants.TRANSPARENT_COLOR : getStandingBodyColor()); g2d.fill(body); g2d.setComposite(oldComposite); @@ -255,10 +252,7 @@ public abstract class AbstractLeadedComponent extends AbstractLabeledComponen g2d.translate((getPoints()[0].getX() + getPoints()[1].getX() - length) / 2, (getPoints()[0].getY() + getPoints()[1].getY() - 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)); - } + Composite oldComposite = applyAlpha(g2d, componentState); if (getBodyColor() != null) { g2d.setColor(outlineMode ? Constants.TRANSPARENT_COLOR : getBodyColor()); @@ -440,10 +434,7 @@ public abstract class AbstractLeadedComponent extends AbstractLabeledComponen break; } - Composite oldComposite = g2d.getComposite(); - if (getAlpha() < MAX_ALPHA) { - g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1f * getAlpha() / MAX_ALPHA)); - } + Composite oldComposite = applyAlpha(g2d, componentState); if (shouldShadeLeads()) { Shape lineShape = stroke.createStrokedShape(line); diff --git a/diylc/diylc-library/src/main/java/org/diylc/components/boards/AbstractBoard.java b/diylc/diylc-library/src/main/java/org/diylc/components/boards/AbstractBoard.java index f52883ad8..a2f59a8e1 100644 --- a/diylc/diylc-library/src/main/java/org/diylc/components/boards/AbstractBoard.java +++ b/diylc/diylc-library/src/main/java/org/diylc/components/boards/AbstractBoard.java @@ -88,12 +88,7 @@ public abstract class AbstractBoard extends AbstractTransparentComponent Point2D finalSecondPoint = getFinalSecondPoint(); - Composite oldComposite = g2d.getComposite(); - // render as transparent when dragging - int alpha = componentState == ComponentState.DRAGGING ? 0 : this.alpha; - if (alpha < MAX_ALPHA) { - g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1f * alpha / MAX_ALPHA)); - } + Composite oldComposite = applyAlpha(g2d, componentState); g2d.setColor(boardColor); g2d.fillRect((int)firstPoint.getX(), (int)firstPoint.getY(), (int)(finalSecondPoint.getX() - firstPoint.getX()), (int)(finalSecondPoint.getY() - firstPoint.getY())); g2d.setComposite(oldComposite); diff --git a/diylc/diylc-library/src/main/java/org/diylc/components/boards/BlankBoard.java b/diylc/diylc-library/src/main/java/org/diylc/components/boards/BlankBoard.java index 7ee0a538c..f899ec5b0 100644 --- a/diylc/diylc-library/src/main/java/org/diylc/components/boards/BlankBoard.java +++ b/diylc/diylc-library/src/main/java/org/diylc/components/boards/BlankBoard.java @@ -70,10 +70,7 @@ public class BlankBoard extends AbstractBoard { g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(1)); // if (componentState != ComponentState.DRAGGING) { - Composite oldComposite = g2d.getComposite(); - if (alpha < MAX_ALPHA) { - g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1f * alpha / MAX_ALPHA)); - } + Composite oldComposite = applyAlpha(g2d, componentState); g2d.setColor(boardColor); if (getType() == Type.SQUARE) g2d.fillRect((int)firstPoint.getX(), (int)firstPoint.getY(), (int)(finalSecondPoint.getX() - firstPoint.getX()), (int)(finalSecondPoint.getY() - firstPoint.getY())); diff --git a/diylc/diylc-library/src/main/java/org/diylc/components/boards/EyeletBoard.java b/diylc/diylc-library/src/main/java/org/diylc/components/boards/EyeletBoard.java index 02efe9e8e..216570df6 100644 --- a/diylc/diylc-library/src/main/java/org/diylc/components/boards/EyeletBoard.java +++ b/diylc/diylc-library/src/main/java/org/diylc/components/boards/EyeletBoard.java @@ -78,9 +78,7 @@ public class EyeletBoard extends AbstractBoard { } super.draw(g2d, componentState, outlineMode, project, drawingObserver); if (componentState != ComponentState.DRAGGING) { - if (alpha < MAX_ALPHA) { - g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1f * alpha / MAX_ALPHA)); - } + applyAlpha(g2d, componentState); double x = firstPoint.getX(); double y = firstPoint.getY(); int diameter = getClosestOdd((int) EYELET_SIZE.convertToPixels()); diff --git a/diylc/diylc-library/src/main/java/org/diylc/components/boards/MarshallPerfBoard.java b/diylc/diylc-library/src/main/java/org/diylc/components/boards/MarshallPerfBoard.java index b494f45b2..fafb79760 100644 --- a/diylc/diylc-library/src/main/java/org/diylc/components/boards/MarshallPerfBoard.java +++ b/diylc/diylc-library/src/main/java/org/diylc/components/boards/MarshallPerfBoard.java @@ -76,9 +76,7 @@ public class MarshallPerfBoard extends AbstractBoard { } super.draw(g2d, componentState, outlineMode, project, drawingObserver); if (componentState != ComponentState.DRAGGING) { - if (alpha < MAX_ALPHA) { - g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1f * alpha / MAX_ALPHA)); - } + applyAlpha(g2d, componentState); double x = firstPoint.getX(); double y = firstPoint.getY(); int holeDiameter = getClosestOdd((int) HOLE_SIZE.convertToPixels()); diff --git a/diylc/diylc-library/src/main/java/org/diylc/components/boards/PerfBoard.java b/diylc/diylc-library/src/main/java/org/diylc/components/boards/PerfBoard.java index 1ba54c459..1780fe905 100644 --- a/diylc/diylc-library/src/main/java/org/diylc/components/boards/PerfBoard.java +++ b/diylc/diylc-library/src/main/java/org/diylc/components/boards/PerfBoard.java @@ -72,9 +72,7 @@ public class PerfBoard extends AbstractBoard implements ILayeredComponent { } super.draw(g2d, componentState, outlineMode, project, drawingObserver); if (componentState != ComponentState.DRAGGING) { - if (alpha < MAX_ALPHA) { - g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1f * alpha / MAX_ALPHA)); - } + applyAlpha(g2d, componentState); double x = firstPoint.getX(); double y = firstPoint.getY(); int diameter = getClosestOdd((int) PAD_SIZE.convertToPixels()); diff --git a/diylc/diylc-library/src/main/java/org/diylc/components/boards/TagStrip.java b/diylc/diylc-library/src/main/java/org/diylc/components/boards/TagStrip.java index 5bd1111fc..da01e2971 100644 --- a/diylc/diylc-library/src/main/java/org/diylc/components/boards/TagStrip.java +++ b/diylc/diylc-library/src/main/java/org/diylc/components/boards/TagStrip.java @@ -1,412 +1,409 @@ -/* - - DIY Layout Creator (DIYLC). - Copyright (c) 2009-2025 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.boards; - -import java.awt.AlphaComposite; -import java.awt.Color; -import java.awt.Composite; -import java.awt.Graphics2D; -import java.awt.geom.Area; -import java.awt.geom.Ellipse2D; -import java.awt.geom.Point2D; -import java.awt.geom.Rectangle2D; -import org.diylc.appframework.miscutils.ConfigurationManager; - -import org.diylc.common.IPlugInPort; -import org.diylc.common.ObjectCache; -import org.diylc.common.Orientation; -import org.diylc.components.AbstractTransparentComponent; -import org.diylc.components.transform.TagStripTransformer; -import org.diylc.core.ComponentState; -import org.diylc.core.IContinuity; -import org.diylc.core.IDIYComponent; -import org.diylc.core.IDrawingObserver; -import org.diylc.core.Project; -import org.diylc.core.Theme; -import org.diylc.core.VisibilityPolicy; -import org.diylc.core.annotations.ComponentDescriptor; -import org.diylc.core.annotations.EditableProperty; -import org.diylc.core.annotations.KeywordPolicy; -import org.diylc.core.annotations.PositiveNonZeroMeasureValidator; -import org.diylc.core.measures.Size; -import org.diylc.core.measures.SizeUnit; -import org.diylc.utils.Constants; - -@ComponentDescriptor(name = "Tag Strip", author = "Branislav Stojkovic", category = "Boards", - instanceNamePrefix = "TS", description = "Row of terminals for point-to-point construction", - zOrder = IDIYComponent.BOARD, keywordPolicy = KeywordPolicy.SHOW_TYPE_NAME, transformer = TagStripTransformer.class) -public class TagStrip extends AbstractTransparentComponent implements IContinuity { - - private static final long serialVersionUID = 1L; - - public static Color BOARD_COLOR = PHENOLIC_DARK_COLOR; - public static Color TERMINAL_COLOR = Color.lightGray; - public static Color TERMINAL_BORDER_COLOR = TERMINAL_COLOR.darker(); - public static int EDGE_RADIUS = 2; - public static Size MOUNTING_HOLE_SIZE = new Size(0.07d, SizeUnit.in); - public static Size MOUNTING_HOLE_DISTANCE = new Size(0.25d, SizeUnit.in); - public static Size TERMINAL_THICKNESS = new Size(0.04d, SizeUnit.in); - - private String value = ""; - private Orientation orientation = Orientation.DEFAULT; - private int terminalCount = 7; - private static Size BOARD_THICKNESS = new Size(0.05d, SizeUnit.in); - private Size terminalSpacing = new Size(0.375d, SizeUnit.in); - private Point2D[] controlPoints = new Point2D[] {new Point2D.Double(0, 0)}; - private Color boardColor = BOARD_COLOR; - - private TagStripMount mount = TagStripMount.Central; - - transient private Area[] body; - - public TagStrip() { - super(); - updateControlPoints(); - } - - @EditableProperty - public String getValue() { - return value; - } - - public void setValue(String value) { - this.value = value; - } - - @EditableProperty - public Orientation getOrientation() { - return orientation; - } - - public void setOrientation(Orientation orientation) { - this.orientation = orientation; - updateControlPoints(); - // Reset body shape. - body = null; - } - - @EditableProperty(name = "Terminals") - public int getTerminalCount() { - return terminalCount; - } - - public void setTerminalCount(int terminalCount) { - this.terminalCount = terminalCount; - updateControlPoints(); - // Reset body shape; - body = null; - } - - @EditableProperty(name = "Terminal Spacing", validatorClass = PositiveNonZeroMeasureValidator.class) - public Size getTerminalSpacing() { - return terminalSpacing; - } - - public void setTerminalSpacing(Size pinSpacing) { - this.terminalSpacing = pinSpacing; - updateControlPoints(); - // Reset body shape; - body = null; - } - - @Override - public int getControlPointCount() { - return controlPoints.length; - } - - @Override - public Point2D getControlPoint(int index) { - return controlPoints[index]; - } - - @Override - public boolean isControlPointSticky(int index) { - return true; - } - - @Override - public VisibilityPolicy getControlPointVisibilityPolicy(int index) { - return VisibilityPolicy.NEVER; - } - - @Override - public void setControlPoint(Point2D point, int index) { - controlPoints[index].setLocation(point); - body = null; - } - - private void updateControlPoints() { - Point2D firstPoint = controlPoints[0]; - controlPoints = new Point2D[getTerminalCount()]; - controlPoints[0] = firstPoint; - int pinSpacing = (int) this.terminalSpacing.convertToPixels(); - // Update control points. - int dx1; - int dy1; - for (int i = 0; i < getTerminalCount(); i++) { - switch (orientation) { - case DEFAULT: - dx1 = 0; - dy1 = i * pinSpacing; - break; - case _90: - dx1 = -i * pinSpacing; - dy1 = 0; - break; - case _180: - dx1 = 0; - dy1 = -i * pinSpacing; - break; - case _270: - dx1 = i * pinSpacing; - dy1 = 0; - break; - default: - throw new RuntimeException("Unexpected orientation: " + orientation); - } - controlPoints[i] = new Point2D.Double(firstPoint.getX() + dx1, firstPoint.getY() + dy1); - } - } - - public Area[] getBody() { - if (body == null) { - body = new Area[1 + getTerminalCount()]; - double x = controlPoints[0].getX(); - double y = controlPoints[0].getY(); - int width; - int height; - int terminalSpacing = (int) getTerminalSpacing().convertToPixels(); - int boardThickness = getClosestOdd(BOARD_THICKNESS.convertToPixels()); - int boardLength = (int) ((getTerminalCount() - 0.5) * terminalSpacing + 2 * boardThickness); - int holeSize = getClosestOdd(MOUNTING_HOLE_SIZE.convertToPixels()); - int terminalThickness = (int) TERMINAL_THICKNESS.convertToPixels(); - int terminalSize = terminalSpacing / 2; - int holeDistance = terminalSize / 2 + terminalThickness / 2 + 1; - int terminalWidth; - int terminalHeight; - int holeDx; - int holeDy; - switch (orientation) { - case DEFAULT: - width = boardThickness; - height = boardLength; - terminalWidth = terminalThickness; - terminalHeight = terminalSize; - x -= boardThickness + terminalThickness / 2; - y -= terminalSize / 2 + boardThickness; - holeDx = holeDistance; - holeDy = 0; - break; - case _90: - width = boardLength; - height = boardThickness; - terminalWidth = terminalSize; - terminalHeight = terminalThickness; - x += boardThickness - boardLength + terminalSize / 2; - y -= boardThickness + terminalThickness / 2; - holeDx = 0; - holeDy = holeDistance; - break; - case _180: - width = boardThickness; - height = boardLength; - terminalWidth = terminalThickness; - terminalHeight = terminalSize; - x += terminalThickness / 2; - y += boardThickness - boardLength + terminalSize / 2; - holeDx = -holeDistance; - holeDy = 0; - break; - case _270: - width = boardLength; - height = boardThickness; - terminalWidth = terminalSize; - terminalHeight = terminalThickness; - x -= terminalSize / 2 + boardThickness; - y -= -terminalThickness / 2; - holeDx = 0; - holeDy = -holeDistance; - break; - default: - throw new RuntimeException("Unexpected orientation: " + orientation); - } - Area bodyArea = new Area(new Rectangle2D.Double(x, y, width, height)); - body[0] = bodyArea; - - for (int i = 0; i < getTerminalCount(); i++) { - Point2D p1 = getControlPoint(i); - Area terminal = - new Area(new Rectangle2D.Double(p1.getX() - terminalWidth/ 2, p1.getY() - terminalHeight / 2, terminalWidth, terminalHeight)); - - body[1 + i] = terminal; - - if ((getMount() == TagStripMount.Central && i == getTerminalCount() / 2) || (getMount() == TagStripMount.Outside && (i == 0 || i == getTerminalCount() - 1))) { - Area mount = new Area(new Rectangle2D.Double(p1.getX() + holeDx - terminalSize / 2, p1.getY() + holeDy - terminalSize / 2, terminalSize, terminalSize)); - mount.subtract(new Area(new Ellipse2D.Double(p1.getX() + holeDx - holeSize / 2, p1.getY() + holeDy - holeSize / 2, holeSize, holeSize))); - body[1 + i].add(mount); - } - } - } - return body; - } - - @Override - public void draw(Graphics2D g2d, ComponentState componentState, boolean outlineMode, Project project, - IDrawingObserver drawingObserver) { - if (checkPointsClipped(g2d.getClip())) { - return; - } - Area[] area = getBody(); - Area mainArea = area[0]; - - 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 : getBoardColor()); - g2d.fill(mainArea); - - 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 - : getBoardColor().darker(); - } - g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(1)); - - g2d.setColor(finalBorderColor); - g2d.draw(mainArea); - - g2d.setColor(outlineMode ? Constants.TRANSPARENT_COLOR : TERMINAL_COLOR); - drawingObserver.startTrackingContinuityArea(true); - for (int i = 1; i < body.length; i++) - g2d.fill(body[i]); - drawingObserver.stopTrackingContinuityArea(); - - Color finalTerminalBorderColor; - if (outlineMode) { - Theme theme = - (Theme) ConfigurationManager.getInstance().readObject(IPlugInPort.THEME_KEY, Constants.DEFAULT_THEME); - finalTerminalBorderColor = - componentState == ComponentState.SELECTED || componentState == ComponentState.DRAGGING ? SELECTION_COLOR - : theme.getOutlineColor(); - } else { - finalTerminalBorderColor = - componentState == ComponentState.SELECTED || componentState == ComponentState.DRAGGING ? SELECTION_COLOR - : TERMINAL_BORDER_COLOR; - } - - g2d.setColor(finalTerminalBorderColor); - for (int i = 1; i < body.length; i++) - g2d.draw(body[i]); - - g2d.setComposite(oldComposite); - } - - @Override - public void drawIcon(Graphics2D g2d, int width, int height) { - g2d.rotate(-Math.PI / 4, width / 2, height / 2); - g2d.setColor(BOARD_COLOR); - int thickness = 2 * width / 32; - g2d.fillRect(0, height / 2 - thickness / 2, width, thickness); - g2d.setColor(TERMINAL_COLOR.darker()); - int terminalWidth = 7 * width / 32; - g2d.fillRect(2, height / 2 + thickness / 2, terminalWidth, thickness); - g2d.fillRect((int) (2 + terminalWidth * 1.5), height / 2 + thickness / 2, terminalWidth, thickness); - g2d.fillRect((int) (2 + terminalWidth * 3), height / 2 + thickness / 2, terminalWidth, thickness); - g2d.setColor(TERMINAL_COLOR); - g2d.fillRect((int) (2 + terminalWidth * 1.5), height / 2 + thickness / 2 + 1, terminalWidth, terminalWidth); - g2d.setColor(Color.white); - g2d.fillOval((int) (2 + terminalWidth * 1.75), height / 2 + thickness / 2 + 1 + terminalWidth / 2, terminalWidth / 2, terminalWidth / 2); -// int radius = 6 * width / 32; -// int holeSize = 3 * width / 32; -// g2d.setColor(BOARD_COLOR); -// g2d.fillRect(width / 4, 1, width / 2, height - 4); -// g2d.setColor(BORDER_COLOR); -// g2d.drawRect(width / 4, 1, width / 2, height - 4); -// int terminalSize = getClosestOdd(height / 5); -// Area terminal = -// new Area(new RoundRectangle2D.Double(2 * width / 32, height / 5, width - 4 * width / 32, terminalSize, radius, -// radius)); -// terminal.subtract(new Area(new Ellipse2D.Double(2 * width / 32 + holeSize, height * 3 / 10 - holeSize / 2, holeSize, holeSize))); -// terminal.subtract(new Area(new Ellipse2D.Double(width - 2 * width / 32 - holeSize * 2, height * 3 / 10 - holeSize / 2, holeSize, holeSize))); -// -// g2d.setColor(TERMINAL_COLOR); -// g2d.fill(terminal); -// g2d.setColor(TERMINAL_BORDER_COLOR); -// g2d.draw(terminal); -// g2d.translate(0, height * 2 / 5); -// g2d.setColor(TERMINAL_COLOR); -// g2d.fill(terminal); -// g2d.setColor(TERMINAL_BORDER_COLOR); -// g2d.draw(terminal); - } - - @EditableProperty(name = "Board") - public Color getBoardColor() { - if (boardColor == null) { - boardColor = BOARD_COLOR; - } - return boardColor; - } - - public void setBoardColor(Color bodyColor) { - this.boardColor = bodyColor; - } - - @Override - public String getControlPointNodeName(int index) { - return "TerminalStrip" + index; - } - - @EditableProperty(name = "Mounting Lugs") - public TagStripMount getMount() { - return mount; - } - - public void setMount(TagStripMount mount) { - this.mount = mount; - updateControlPoints(); - // Reset body shape; - body = null; - } - - @Override - public boolean arePointsConnected(int index1, int index2) { - return false; - } - - @Override - public boolean canPointMoveFreely(int pointIndex) { - return false; - } - - public enum TagStripMount { - Central, Outside; - } -} +/* + + DIY Layout Creator (DIYLC). + Copyright (c) 2009-2025 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.boards; + +import java.awt.AlphaComposite; +import java.awt.Color; +import java.awt.Composite; +import java.awt.Graphics2D; +import java.awt.geom.Area; +import java.awt.geom.Ellipse2D; +import java.awt.geom.Point2D; +import java.awt.geom.Rectangle2D; +import org.diylc.appframework.miscutils.ConfigurationManager; + +import org.diylc.common.IPlugInPort; +import org.diylc.common.ObjectCache; +import org.diylc.common.Orientation; +import org.diylc.components.AbstractTransparentComponent; +import org.diylc.components.transform.TagStripTransformer; +import org.diylc.core.ComponentState; +import org.diylc.core.IContinuity; +import org.diylc.core.IDIYComponent; +import org.diylc.core.IDrawingObserver; +import org.diylc.core.Project; +import org.diylc.core.Theme; +import org.diylc.core.VisibilityPolicy; +import org.diylc.core.annotations.ComponentDescriptor; +import org.diylc.core.annotations.EditableProperty; +import org.diylc.core.annotations.KeywordPolicy; +import org.diylc.core.annotations.PositiveNonZeroMeasureValidator; +import org.diylc.core.measures.Size; +import org.diylc.core.measures.SizeUnit; +import org.diylc.utils.Constants; + +@ComponentDescriptor(name = "Tag Strip", author = "Branislav Stojkovic", category = "Boards", + instanceNamePrefix = "TS", description = "Row of terminals for point-to-point construction", + zOrder = IDIYComponent.BOARD, keywordPolicy = KeywordPolicy.SHOW_TYPE_NAME, transformer = TagStripTransformer.class) +public class TagStrip extends AbstractTransparentComponent implements IContinuity { + + private static final long serialVersionUID = 1L; + + public static Color BOARD_COLOR = PHENOLIC_DARK_COLOR; + public static Color TERMINAL_COLOR = Color.lightGray; + public static Color TERMINAL_BORDER_COLOR = TERMINAL_COLOR.darker(); + public static int EDGE_RADIUS = 2; + public static Size MOUNTING_HOLE_SIZE = new Size(0.07d, SizeUnit.in); + public static Size MOUNTING_HOLE_DISTANCE = new Size(0.25d, SizeUnit.in); + public static Size TERMINAL_THICKNESS = new Size(0.04d, SizeUnit.in); + + private String value = ""; + private Orientation orientation = Orientation.DEFAULT; + private int terminalCount = 7; + private static Size BOARD_THICKNESS = new Size(0.05d, SizeUnit.in); + private Size terminalSpacing = new Size(0.375d, SizeUnit.in); + private Point2D[] controlPoints = new Point2D[] {new Point2D.Double(0, 0)}; + private Color boardColor = BOARD_COLOR; + + private TagStripMount mount = TagStripMount.Central; + + transient private Area[] body; + + public TagStrip() { + super(); + updateControlPoints(); + } + + @EditableProperty + public String getValue() { + return value; + } + + public void setValue(String value) { + this.value = value; + } + + @EditableProperty + public Orientation getOrientation() { + return orientation; + } + + public void setOrientation(Orientation orientation) { + this.orientation = orientation; + updateControlPoints(); + // Reset body shape. + body = null; + } + + @EditableProperty(name = "Terminals") + public int getTerminalCount() { + return terminalCount; + } + + public void setTerminalCount(int terminalCount) { + this.terminalCount = terminalCount; + updateControlPoints(); + // Reset body shape; + body = null; + } + + @EditableProperty(name = "Terminal Spacing", validatorClass = PositiveNonZeroMeasureValidator.class) + public Size getTerminalSpacing() { + return terminalSpacing; + } + + public void setTerminalSpacing(Size pinSpacing) { + this.terminalSpacing = pinSpacing; + updateControlPoints(); + // Reset body shape; + body = null; + } + + @Override + public int getControlPointCount() { + return controlPoints.length; + } + + @Override + public Point2D getControlPoint(int index) { + return controlPoints[index]; + } + + @Override + public boolean isControlPointSticky(int index) { + return true; + } + + @Override + public VisibilityPolicy getControlPointVisibilityPolicy(int index) { + return VisibilityPolicy.NEVER; + } + + @Override + public void setControlPoint(Point2D point, int index) { + controlPoints[index].setLocation(point); + body = null; + } + + private void updateControlPoints() { + Point2D firstPoint = controlPoints[0]; + controlPoints = new Point2D[getTerminalCount()]; + controlPoints[0] = firstPoint; + int pinSpacing = (int) this.terminalSpacing.convertToPixels(); + // Update control points. + int dx1; + int dy1; + for (int i = 0; i < getTerminalCount(); i++) { + switch (orientation) { + case DEFAULT: + dx1 = 0; + dy1 = i * pinSpacing; + break; + case _90: + dx1 = -i * pinSpacing; + dy1 = 0; + break; + case _180: + dx1 = 0; + dy1 = -i * pinSpacing; + break; + case _270: + dx1 = i * pinSpacing; + dy1 = 0; + break; + default: + throw new RuntimeException("Unexpected orientation: " + orientation); + } + controlPoints[i] = new Point2D.Double(firstPoint.getX() + dx1, firstPoint.getY() + dy1); + } + } + + public Area[] getBody() { + if (body == null) { + body = new Area[1 + getTerminalCount()]; + double x = controlPoints[0].getX(); + double y = controlPoints[0].getY(); + int width; + int height; + int terminalSpacing = (int) getTerminalSpacing().convertToPixels(); + int boardThickness = getClosestOdd(BOARD_THICKNESS.convertToPixels()); + int boardLength = (int) ((getTerminalCount() - 0.5) * terminalSpacing + 2 * boardThickness); + int holeSize = getClosestOdd(MOUNTING_HOLE_SIZE.convertToPixels()); + int terminalThickness = (int) TERMINAL_THICKNESS.convertToPixels(); + int terminalSize = terminalSpacing / 2; + int holeDistance = terminalSize / 2 + terminalThickness / 2 + 1; + int terminalWidth; + int terminalHeight; + int holeDx; + int holeDy; + switch (orientation) { + case DEFAULT: + width = boardThickness; + height = boardLength; + terminalWidth = terminalThickness; + terminalHeight = terminalSize; + x -= boardThickness + terminalThickness / 2; + y -= terminalSize / 2 + boardThickness; + holeDx = holeDistance; + holeDy = 0; + break; + case _90: + width = boardLength; + height = boardThickness; + terminalWidth = terminalSize; + terminalHeight = terminalThickness; + x += boardThickness - boardLength + terminalSize / 2; + y -= boardThickness + terminalThickness / 2; + holeDx = 0; + holeDy = holeDistance; + break; + case _180: + width = boardThickness; + height = boardLength; + terminalWidth = terminalThickness; + terminalHeight = terminalSize; + x += terminalThickness / 2; + y += boardThickness - boardLength + terminalSize / 2; + holeDx = -holeDistance; + holeDy = 0; + break; + case _270: + width = boardLength; + height = boardThickness; + terminalWidth = terminalSize; + terminalHeight = terminalThickness; + x -= terminalSize / 2 + boardThickness; + y -= -terminalThickness / 2; + holeDx = 0; + holeDy = -holeDistance; + break; + default: + throw new RuntimeException("Unexpected orientation: " + orientation); + } + Area bodyArea = new Area(new Rectangle2D.Double(x, y, width, height)); + body[0] = bodyArea; + + for (int i = 0; i < getTerminalCount(); i++) { + Point2D p1 = getControlPoint(i); + Area terminal = + new Area(new Rectangle2D.Double(p1.getX() - terminalWidth/ 2, p1.getY() - terminalHeight / 2, terminalWidth, terminalHeight)); + + body[1 + i] = terminal; + + if ((getMount() == TagStripMount.Central && i == getTerminalCount() / 2) || (getMount() == TagStripMount.Outside && (i == 0 || i == getTerminalCount() - 1))) { + Area mount = new Area(new Rectangle2D.Double(p1.getX() + holeDx - terminalSize / 2, p1.getY() + holeDy - terminalSize / 2, terminalSize, terminalSize)); + mount.subtract(new Area(new Ellipse2D.Double(p1.getX() + holeDx - holeSize / 2, p1.getY() + holeDy - holeSize / 2, holeSize, holeSize))); + body[1 + i].add(mount); + } + } + } + return body; + } + + @Override + public void draw(Graphics2D g2d, ComponentState componentState, boolean outlineMode, Project project, + IDrawingObserver drawingObserver) { + if (checkPointsClipped(g2d.getClip())) { + return; + } + Area[] area = getBody(); + Area mainArea = area[0]; + + Composite oldComposite = applyAlpha(g2d, componentState); + g2d.setColor(outlineMode ? Constants.TRANSPARENT_COLOR : getBoardColor()); + g2d.fill(mainArea); + + 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 + : getBoardColor().darker(); + } + g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(1)); + + g2d.setColor(finalBorderColor); + g2d.draw(mainArea); + + g2d.setColor(outlineMode ? Constants.TRANSPARENT_COLOR : TERMINAL_COLOR); + drawingObserver.startTrackingContinuityArea(true); + for (int i = 1; i < body.length; i++) + g2d.fill(body[i]); + drawingObserver.stopTrackingContinuityArea(); + + Color finalTerminalBorderColor; + if (outlineMode) { + Theme theme = + (Theme) ConfigurationManager.getInstance().readObject(IPlugInPort.THEME_KEY, Constants.DEFAULT_THEME); + finalTerminalBorderColor = + componentState == ComponentState.SELECTED || componentState == ComponentState.DRAGGING ? SELECTION_COLOR + : theme.getOutlineColor(); + } else { + finalTerminalBorderColor = + componentState == ComponentState.SELECTED || componentState == ComponentState.DRAGGING ? SELECTION_COLOR + : TERMINAL_BORDER_COLOR; + } + + g2d.setColor(finalTerminalBorderColor); + for (int i = 1; i < body.length; i++) + g2d.draw(body[i]); + + g2d.setComposite(oldComposite); + } + + @Override + public void drawIcon(Graphics2D g2d, int width, int height) { + g2d.rotate(-Math.PI / 4, width / 2, height / 2); + g2d.setColor(BOARD_COLOR); + int thickness = 2 * width / 32; + g2d.fillRect(0, height / 2 - thickness / 2, width, thickness); + g2d.setColor(TERMINAL_COLOR.darker()); + int terminalWidth = 7 * width / 32; + g2d.fillRect(2, height / 2 + thickness / 2, terminalWidth, thickness); + g2d.fillRect((int) (2 + terminalWidth * 1.5), height / 2 + thickness / 2, terminalWidth, thickness); + g2d.fillRect((int) (2 + terminalWidth * 3), height / 2 + thickness / 2, terminalWidth, thickness); + g2d.setColor(TERMINAL_COLOR); + g2d.fillRect((int) (2 + terminalWidth * 1.5), height / 2 + thickness / 2 + 1, terminalWidth, terminalWidth); + g2d.setColor(Color.white); + g2d.fillOval((int) (2 + terminalWidth * 1.75), height / 2 + thickness / 2 + 1 + terminalWidth / 2, terminalWidth / 2, terminalWidth / 2); +// int radius = 6 * width / 32; +// int holeSize = 3 * width / 32; +// g2d.setColor(BOARD_COLOR); +// g2d.fillRect(width / 4, 1, width / 2, height - 4); +// g2d.setColor(BORDER_COLOR); +// g2d.drawRect(width / 4, 1, width / 2, height - 4); +// int terminalSize = getClosestOdd(height / 5); +// Area terminal = +// new Area(new RoundRectangle2D.Double(2 * width / 32, height / 5, width - 4 * width / 32, terminalSize, radius, +// radius)); +// terminal.subtract(new Area(new Ellipse2D.Double(2 * width / 32 + holeSize, height * 3 / 10 - holeSize / 2, holeSize, holeSize))); +// terminal.subtract(new Area(new Ellipse2D.Double(width - 2 * width / 32 - holeSize * 2, height * 3 / 10 - holeSize / 2, holeSize, holeSize))); +// +// g2d.setColor(TERMINAL_COLOR); +// g2d.fill(terminal); +// g2d.setColor(TERMINAL_BORDER_COLOR); +// g2d.draw(terminal); +// g2d.translate(0, height * 2 / 5); +// g2d.setColor(TERMINAL_COLOR); +// g2d.fill(terminal); +// g2d.setColor(TERMINAL_BORDER_COLOR); +// g2d.draw(terminal); + } + + @EditableProperty(name = "Board") + public Color getBoardColor() { + if (boardColor == null) { + boardColor = BOARD_COLOR; + } + return boardColor; + } + + public void setBoardColor(Color bodyColor) { + this.boardColor = bodyColor; + } + + @Override + public String getControlPointNodeName(int index) { + return "TerminalStrip" + index; + } + + @EditableProperty(name = "Mounting Lugs") + public TagStripMount getMount() { + return mount; + } + + public void setMount(TagStripMount mount) { + this.mount = mount; + updateControlPoints(); + // Reset body shape; + body = null; + } + + @Override + public boolean arePointsConnected(int index1, int index2) { + return false; + } + + @Override + public boolean canPointMoveFreely(int pointIndex) { + return false; + } + + public enum TagStripMount { + Central, Outside; + } +} diff --git a/diylc/diylc-library/src/main/java/org/diylc/components/boards/TerminalStrip.java b/diylc/diylc-library/src/main/java/org/diylc/components/boards/TerminalStrip.java index 55ffd4a5f..4c689f24d 100644 --- a/diylc/diylc-library/src/main/java/org/diylc/components/boards/TerminalStrip.java +++ b/diylc/diylc-library/src/main/java/org/diylc/components/boards/TerminalStrip.java @@ -360,10 +360,7 @@ public class TerminalStrip extends AbstractTransparentComponent implemen Area[] body = getBody(); Area mainArea = getBody()[0]; - Composite oldComposite = g2d.getComposite(); - if (alpha < MAX_ALPHA) { - g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1f * alpha / MAX_ALPHA)); - } + Composite oldComposite = applyAlpha(g2d, componentState); g2d.setColor(outlineMode ? Constants.TRANSPARENT_COLOR : getBoardColor()); g2d.fill(mainArea); diff --git a/diylc/diylc-library/src/main/java/org/diylc/components/boards/TriPadBoard.java b/diylc/diylc-library/src/main/java/org/diylc/components/boards/TriPadBoard.java index abebdd5d1..6da376d54 100644 --- a/diylc/diylc-library/src/main/java/org/diylc/components/boards/TriPadBoard.java +++ b/diylc/diylc-library/src/main/java/org/diylc/components/boards/TriPadBoard.java @@ -1,213 +1,210 @@ -/* - - DIY Layout Creator (DIYLC). - Copyright (c) 2009-2025 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.boards; - -import java.awt.AlphaComposite; -import java.awt.Composite; -import java.awt.Graphics2D; -import java.awt.Shape; -import java.awt.geom.Point2D; - -import org.diylc.common.OrientationHV; -import org.diylc.components.transform.VeroBoardTransformer; -import org.diylc.core.ComponentState; -import org.diylc.core.IDIYComponent; -import org.diylc.core.IDrawingObserver; -import org.diylc.core.ILayeredComponent; -import org.diylc.core.Project; -import org.diylc.core.annotations.ComponentDescriptor; -import org.diylc.core.annotations.EditableProperty; -import org.diylc.core.annotations.KeywordPolicy; -import org.diylc.utils.Constants; - -@ComponentDescriptor(name = "TriPad Board", category = "Boards", author = "Hauke Juhls", zOrder = IDIYComponent.BOARD, - instanceNamePrefix = "Board", - description = "Perforated FR4 board with copper strips connecting 3 holes in a row (aka TriPad Board)", - keywordPolicy = KeywordPolicy.SHOW_TYPE_NAME, transformer = VeroBoardTransformer.class, enableCache = true) -public class TriPadBoard extends AbstractVeroBoard implements ILayeredComponent { - - private static final long serialVersionUID = 1L; - - protected int stripSpan = 3; // determines how many holes are covered by a - - @Override - public void draw(Graphics2D g2d, ComponentState componentState, boolean outlineMode, Project project, - IDrawingObserver drawingObserver) { - Point2D finalSecondPoint = getFinalSecondPoint(); - - Shape clip = g2d.getClip(); - if (checkPointsClipped(clip) && !clip.contains(firstPoint.getX(), finalSecondPoint.getY()) - && !clip.contains(finalSecondPoint.getX(), firstPoint.getY())) { - return; - } - super.draw(g2d, componentState, outlineMode, project, drawingObserver); - if (componentState != ComponentState.DRAGGING) { - Composite oldComposite = g2d.getComposite(); - if (alpha < MAX_ALPHA) { - g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1f * alpha / MAX_ALPHA)); - } - double x = firstPoint.getX(); - double y = firstPoint.getY(); - int stripSize = getClosestOdd((int) STRIP_SIZE.convertToPixels()); - int holeSize = getClosestOdd((int) HOLE_SIZE.convertToPixels()); - double spacing = this.spacing.convertToPixels(); - - if (orientation == OrientationHV.HORIZONTAL) { - while (y < finalSecondPoint.getY() - spacing - stripSize / 2) { - x = firstPoint.getX(); - y += spacing; - - while (x + spacing < finalSecondPoint.getX()) { - - double remainingSpace = finalSecondPoint.getX() - x; - double spacesToDraw = stripSpan; - - if (remainingSpace < (stripSize + (stripSpan * spacing))) { - spacesToDraw = (remainingSpace - stripSize) / spacing; - } - - g2d.setColor(stripColor); - drawingObserver.startTrackingContinuityArea(true); - g2d.fillRect((int)(x + spacing - stripSize / 2), (int)(y - stripSize / 2), (int)(spacing * (spacesToDraw - 1) + stripSize), - stripSize); - drawingObserver.stopTrackingContinuityArea(); - g2d.setColor(stripColor.darker()); - - g2d.drawRect((int)(x + spacing - stripSize / 2), (int)(y - stripSize / 2), (int)(spacing * (spacesToDraw - 1) + stripSize), - stripSize); - - x += spacing * spacesToDraw; - } - - // draw holes - x = firstPoint.getX(); - - while (x < finalSecondPoint.getX() - spacing - holeSize) { - x += spacing; - g2d.setColor(Constants.CANVAS_COLOR); - g2d.fillOval((int)(x - holeSize / 2), (int)(y - holeSize / 2), holeSize, holeSize); - g2d.setColor(stripColor.darker()); - g2d.drawOval((int)(x - holeSize / 2), (int)(y - holeSize / 2), holeSize, holeSize); - } - } - } else { - while (x < finalSecondPoint.getX() - spacing) { - x += spacing; - y = firstPoint.getY(); - - while (y + spacing < finalSecondPoint.getY()) { - - double remainingSpace = finalSecondPoint.getY() - y; - double spacesToDraw = stripSpan; - - if (remainingSpace < (stripSize + (stripSpan * spacing))) { - spacesToDraw = (remainingSpace - stripSize) / spacing; - } - - g2d.setColor(stripColor); - drawingObserver.startTrackingContinuityArea(true); - g2d.fillRect((int)(x - stripSize / 2), (int)(y + spacing - stripSize / 2), stripSize, (int)(spacing * (spacesToDraw - 1) - + stripSize)); - drawingObserver.stopTrackingContinuityArea(); - g2d.setColor(stripColor.darker()); - g2d.drawRect((int)(x - stripSize / 2), (int)(y + spacing - stripSize / 2), stripSize, (int)(spacing * (spacesToDraw - 1) - + stripSize)); - - y += spacing * spacesToDraw; - } - - // draw holes - y = firstPoint.getY(); - - while (y < finalSecondPoint.getY() - spacing - holeSize) { - y += spacing; - g2d.setColor(Constants.CANVAS_COLOR); - g2d.fillOval((int)(x - holeSize / 2), (int)(y - holeSize / 2), holeSize, holeSize); - g2d.setColor(stripColor.darker()); - g2d.drawOval((int)(x - holeSize / 2), (int)(y - holeSize / 2), holeSize, holeSize); - } - } - } - g2d.setComposite(oldComposite); - - super.drawCoordinates(g2d, spacing, project); - } - } - - @Override - public void drawIcon(Graphics2D g2d, int width, int height) { - g2d.setColor(PHENOLIC_COLOR); - g2d.fillRect(0, 0, width, height); - - final int horizontalSpacing = width / 5; - final int horizontalIndent = horizontalSpacing / 2; - - final int verticalSpacing = height / 5; - final int verticalIndent = verticalSpacing / 2; - - for (int row = 0; row < 5; row++) { - g2d.setColor(COPPER_COLOR); - g2d.fillRect(0, row * verticalSpacing + 2, horizontalIndent / 2 + horizontalSpacing, verticalSpacing - 1); - - g2d.setColor(COPPER_COLOR); - g2d.fillRect(horizontalSpacing + 2, row * verticalSpacing + 2, horizontalSpacing * 3 - 1, verticalSpacing - 1); - - g2d.fillRect(horizontalSpacing * 4 + 2, row * verticalSpacing + 2, horizontalIndent / 2 + horizontalSpacing, - verticalSpacing - 1); - } - - // draw dots - for (int row = 0; row < 5; row++) { - int y = (verticalSpacing * row) + verticalIndent; - for (int col = 0; col < 5; col++) { - int x = (horizontalSpacing * col) + horizontalIndent; - g2d.setColor(Constants.CANVAS_COLOR); - g2d.fillOval(x, y, 2, 2); - g2d.setColor(COPPER_COLOR.darker()); - g2d.drawOval(x, y, 2, 2); - } - } - } - - @EditableProperty(name = "Holes Per Strip") - public int getStripSpan() { - return stripSpan; - } - - public void setStripSpan(int stripSpan) { - if (stripSpan < 1) { - this.stripSpan = 1; - } else { - this.stripSpan = stripSpan; - } - } - - @Override - public String getControlPointNodeName(int index) { - return null; - } - - @Override - public int getLayerId() { - return 1; - } -} +/* + + DIY Layout Creator (DIYLC). + Copyright (c) 2009-2025 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.boards; + +import java.awt.AlphaComposite; +import java.awt.Composite; +import java.awt.Graphics2D; +import java.awt.Shape; +import java.awt.geom.Point2D; + +import org.diylc.common.OrientationHV; +import org.diylc.components.transform.VeroBoardTransformer; +import org.diylc.core.ComponentState; +import org.diylc.core.IDIYComponent; +import org.diylc.core.IDrawingObserver; +import org.diylc.core.ILayeredComponent; +import org.diylc.core.Project; +import org.diylc.core.annotations.ComponentDescriptor; +import org.diylc.core.annotations.EditableProperty; +import org.diylc.core.annotations.KeywordPolicy; +import org.diylc.utils.Constants; + +@ComponentDescriptor(name = "TriPad Board", category = "Boards", author = "Hauke Juhls", zOrder = IDIYComponent.BOARD, + instanceNamePrefix = "Board", + description = "Perforated FR4 board with copper strips connecting 3 holes in a row (aka TriPad Board)", + keywordPolicy = KeywordPolicy.SHOW_TYPE_NAME, transformer = VeroBoardTransformer.class, enableCache = true) +public class TriPadBoard extends AbstractVeroBoard implements ILayeredComponent { + + private static final long serialVersionUID = 1L; + + protected int stripSpan = 3; // determines how many holes are covered by a + + @Override + public void draw(Graphics2D g2d, ComponentState componentState, boolean outlineMode, Project project, + IDrawingObserver drawingObserver) { + Point2D finalSecondPoint = getFinalSecondPoint(); + + Shape clip = g2d.getClip(); + if (checkPointsClipped(clip) && !clip.contains(firstPoint.getX(), finalSecondPoint.getY()) + && !clip.contains(finalSecondPoint.getX(), firstPoint.getY())) { + return; + } + super.draw(g2d, componentState, outlineMode, project, drawingObserver); + if (componentState != ComponentState.DRAGGING) { + Composite oldComposite = applyAlpha(g2d, componentState); + double x = firstPoint.getX(); + double y = firstPoint.getY(); + int stripSize = getClosestOdd((int) STRIP_SIZE.convertToPixels()); + int holeSize = getClosestOdd((int) HOLE_SIZE.convertToPixels()); + double spacing = this.spacing.convertToPixels(); + + if (orientation == OrientationHV.HORIZONTAL) { + while (y < finalSecondPoint.getY() - spacing - stripSize / 2) { + x = firstPoint.getX(); + y += spacing; + + while (x + spacing < finalSecondPoint.getX()) { + + double remainingSpace = finalSecondPoint.getX() - x; + double spacesToDraw = stripSpan; + + if (remainingSpace < (stripSize + (stripSpan * spacing))) { + spacesToDraw = (remainingSpace - stripSize) / spacing; + } + + g2d.setColor(stripColor); + drawingObserver.startTrackingContinuityArea(true); + g2d.fillRect((int)(x + spacing - stripSize / 2), (int)(y - stripSize / 2), (int)(spacing * (spacesToDraw - 1) + stripSize), + stripSize); + drawingObserver.stopTrackingContinuityArea(); + g2d.setColor(stripColor.darker()); + + g2d.drawRect((int)(x + spacing - stripSize / 2), (int)(y - stripSize / 2), (int)(spacing * (spacesToDraw - 1) + stripSize), + stripSize); + + x += spacing * spacesToDraw; + } + + // draw holes + x = firstPoint.getX(); + + while (x < finalSecondPoint.getX() - spacing - holeSize) { + x += spacing; + g2d.setColor(Constants.CANVAS_COLOR); + g2d.fillOval((int)(x - holeSize / 2), (int)(y - holeSize / 2), holeSize, holeSize); + g2d.setColor(stripColor.darker()); + g2d.drawOval((int)(x - holeSize / 2), (int)(y - holeSize / 2), holeSize, holeSize); + } + } + } else { + while (x < finalSecondPoint.getX() - spacing) { + x += spacing; + y = firstPoint.getY(); + + while (y + spacing < finalSecondPoint.getY()) { + + double remainingSpace = finalSecondPoint.getY() - y; + double spacesToDraw = stripSpan; + + if (remainingSpace < (stripSize + (stripSpan * spacing))) { + spacesToDraw = (remainingSpace - stripSize) / spacing; + } + + g2d.setColor(stripColor); + drawingObserver.startTrackingContinuityArea(true); + g2d.fillRect((int)(x - stripSize / 2), (int)(y + spacing - stripSize / 2), stripSize, (int)(spacing * (spacesToDraw - 1) + + stripSize)); + drawingObserver.stopTrackingContinuityArea(); + g2d.setColor(stripColor.darker()); + g2d.drawRect((int)(x - stripSize / 2), (int)(y + spacing - stripSize / 2), stripSize, (int)(spacing * (spacesToDraw - 1) + + stripSize)); + + y += spacing * spacesToDraw; + } + + // draw holes + y = firstPoint.getY(); + + while (y < finalSecondPoint.getY() - spacing - holeSize) { + y += spacing; + g2d.setColor(Constants.CANVAS_COLOR); + g2d.fillOval((int)(x - holeSize / 2), (int)(y - holeSize / 2), holeSize, holeSize); + g2d.setColor(stripColor.darker()); + g2d.drawOval((int)(x - holeSize / 2), (int)(y - holeSize / 2), holeSize, holeSize); + } + } + } + g2d.setComposite(oldComposite); + + super.drawCoordinates(g2d, spacing, project); + } + } + + @Override + public void drawIcon(Graphics2D g2d, int width, int height) { + g2d.setColor(PHENOLIC_COLOR); + g2d.fillRect(0, 0, width, height); + + final int horizontalSpacing = width / 5; + final int horizontalIndent = horizontalSpacing / 2; + + final int verticalSpacing = height / 5; + final int verticalIndent = verticalSpacing / 2; + + for (int row = 0; row < 5; row++) { + g2d.setColor(COPPER_COLOR); + g2d.fillRect(0, row * verticalSpacing + 2, horizontalIndent / 2 + horizontalSpacing, verticalSpacing - 1); + + g2d.setColor(COPPER_COLOR); + g2d.fillRect(horizontalSpacing + 2, row * verticalSpacing + 2, horizontalSpacing * 3 - 1, verticalSpacing - 1); + + g2d.fillRect(horizontalSpacing * 4 + 2, row * verticalSpacing + 2, horizontalIndent / 2 + horizontalSpacing, + verticalSpacing - 1); + } + + // draw dots + for (int row = 0; row < 5; row++) { + int y = (verticalSpacing * row) + verticalIndent; + for (int col = 0; col < 5; col++) { + int x = (horizontalSpacing * col) + horizontalIndent; + g2d.setColor(Constants.CANVAS_COLOR); + g2d.fillOval(x, y, 2, 2); + g2d.setColor(COPPER_COLOR.darker()); + g2d.drawOval(x, y, 2, 2); + } + } + } + + @EditableProperty(name = "Holes Per Strip") + public int getStripSpan() { + return stripSpan; + } + + public void setStripSpan(int stripSpan) { + if (stripSpan < 1) { + this.stripSpan = 1; + } else { + this.stripSpan = stripSpan; + } + } + + @Override + public String getControlPointNodeName(int index) { + return null; + } + + @Override + public int getLayerId() { + return 1; + } +} diff --git a/diylc/diylc-library/src/main/java/org/diylc/components/boards/VeroBoard.java b/diylc/diylc-library/src/main/java/org/diylc/components/boards/VeroBoard.java index a2dece1f8..23cb85d72 100644 --- a/diylc/diylc-library/src/main/java/org/diylc/components/boards/VeroBoard.java +++ b/diylc/diylc-library/src/main/java/org/diylc/components/boards/VeroBoard.java @@ -1,155 +1,152 @@ -/* - - DIY Layout Creator (DIYLC). - Copyright (c) 2009-2025 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.boards; - -import java.awt.AlphaComposite; -import java.awt.Composite; -import java.awt.Graphics2D; -import java.awt.Shape; -import java.awt.geom.Point2D; - -import org.diylc.common.OrientationHV; -import org.diylc.components.transform.VeroBoardTransformer; -import org.diylc.core.ComponentState; -import org.diylc.core.IDIYComponent; -import org.diylc.core.IDrawingObserver; -import org.diylc.core.ILayeredComponent; -import org.diylc.core.Project; -import org.diylc.core.annotations.BomPolicy; -import org.diylc.core.annotations.ComponentDescriptor; -import org.diylc.core.annotations.KeywordPolicy; -import org.diylc.utils.Constants; - -@ComponentDescriptor(name = "Vero Board", category = "Boards", author = "Branislav Stojkovic", - zOrder = IDIYComponent.BOARD, instanceNamePrefix = "Board", - description = "Perforated FR4 board with copper strips connecting all holes in a row", - bomPolicy = BomPolicy.SHOW_ONLY_TYPE_NAME, keywordPolicy = KeywordPolicy.SHOW_TYPE_NAME, - transformer = VeroBoardTransformer.class, enableCache = true) -public class VeroBoard extends AbstractVeroBoard implements ILayeredComponent { - - private static final long serialVersionUID = 1L; - - @Override - public void draw(Graphics2D g2d, ComponentState componentState, boolean outlineMode, Project project, - IDrawingObserver drawingObserver) { - Point2D finalSecondPoint = getFinalSecondPoint(); - - Shape clip = g2d.getClip(); - if (checkPointsClipped(clip) && !clip.contains(firstPoint.getX(), finalSecondPoint.getY()) - && !clip.contains(finalSecondPoint.getX(), firstPoint.getY())) { - return; - } - super.draw(g2d, componentState, outlineMode, project, drawingObserver); - if (componentState != ComponentState.DRAGGING) { - Composite oldComposite = g2d.getComposite(); - if (alpha < MAX_ALPHA) { - g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1f * alpha / MAX_ALPHA)); - } - double x = firstPoint.getX(); - double y = firstPoint.getY(); - int stripSize = getClosestOdd((int) STRIP_SIZE.convertToPixels()); - int holeSize = getClosestOdd((int) HOLE_SIZE.convertToPixels()); - int spacing = (int) this.spacing.convertToPixels(); - - if (orientation == OrientationHV.HORIZONTAL) { - while (y < finalSecondPoint.getY() - spacing - stripSize / 2) { - x = firstPoint.getX(); - y += spacing; - g2d.setColor(stripColor); - drawingObserver.startTrackingContinuityArea(true); - g2d.fillRect((int)(x + spacing / 2), (int)(y - stripSize / 2), (int)(finalSecondPoint.getX() - spacing - x), stripSize); - drawingObserver.stopTrackingContinuityArea(); - g2d.setColor(stripColor.darker()); - g2d.drawRect((int)(x + spacing / 2), (int)(y - stripSize / 2), (int)(finalSecondPoint.getX() - spacing - x), stripSize); - while (x < finalSecondPoint.getX() - spacing - holeSize) { - x += spacing; - g2d.setColor(Constants.CANVAS_COLOR); - g2d.fillOval((int)(x - holeSize / 2), (int)(y - holeSize / 2), holeSize, holeSize); - g2d.setColor(stripColor.darker()); - g2d.drawOval((int)(x - holeSize / 2), (int)(y - holeSize / 2), holeSize, holeSize); - } - } - } else { - while (x < finalSecondPoint.getX() - spacing) { - x += spacing; - y = firstPoint.getY(); - g2d.setColor(stripColor); - drawingObserver.startTrackingContinuityArea(true); - g2d.fillRect((int)(x - stripSize / 2), (int)(y + spacing / 2), stripSize, (int)(finalSecondPoint.getY() - spacing - y)); - drawingObserver.stopTrackingContinuityArea(); - g2d.setColor(stripColor.darker()); - g2d.drawRect((int)(x - stripSize / 2), (int)(y + spacing / 2), stripSize, (int)(finalSecondPoint.getY() - spacing - y)); - while (y < finalSecondPoint.getY() - spacing - holeSize) { - y += spacing; - g2d.setColor(Constants.CANVAS_COLOR); - g2d.fillOval((int)(x - holeSize / 2), (int)(y - holeSize / 2), holeSize, holeSize); - g2d.setColor(stripColor.darker()); - g2d.drawOval((int)(x - holeSize / 2), (int)(y - holeSize / 2), holeSize, holeSize); - } - } - } - g2d.setComposite(oldComposite); - super.drawCoordinates(g2d, spacing, project); - } - } - - @Override - public int getLayerId() { - return 1; - } - - @Override - public String getControlPointNodeName(int index) { - return null; - } - - @Override - public void drawIcon(Graphics2D g2d, int width, int height) { - int factor = 32 / width; - g2d.setColor(PHENOLIC_COLOR); - g2d.fillRect(0, 2 / factor, width - 1, height - 4 / factor); - g2d.setColor(BORDER_COLOR); - g2d.drawRect(0, 2 / factor, width - 1, height - 4 / factor); - g2d.setColor(COPPER_COLOR); - g2d.fillRect(1 / factor, width / 4, width - 2 / factor, width / 2); - g2d.setColor(COPPER_COLOR.darker()); - g2d.drawRect(1 / factor, width / 4, width - 2 / factor, width / 2); - - g2d.setColor(COPPER_COLOR); - g2d.fillRect(1 / factor, 2 / factor, width - 2 / factor, 3 / factor); - g2d.fillRect(1 / factor, height - 5 / factor, width - 2 / factor, 3 / factor); - g2d.setColor(COPPER_COLOR.darker()); - g2d.drawRect(1 / factor, 2 / factor, width - 2 / factor, 3 / factor); - g2d.drawRect(1 / factor, height - 5 / factor, width - 2 / factor, 3 / factor); - - g2d.setColor(Constants.CANVAS_COLOR); - g2d.fillOval(width / 3 - 2 / factor, width / 2 - 2 / factor, getClosestOdd(5.0 / factor), - getClosestOdd(5.0 / factor)); - g2d.fillOval(2 * width / 3 - 2 / factor, width / 2 - 2 / factor, getClosestOdd(5.0 / factor), - getClosestOdd(5.0 / factor)); - g2d.setColor(COPPER_COLOR.darker()); - g2d.drawOval(width / 3 - 2 / factor, width / 2 - 2 / factor, getClosestOdd(5.0 / factor), - getClosestOdd(5.0 / factor)); - g2d.drawOval(2 * width / 3 - 2 / factor, width / 2 - 2 / factor, getClosestOdd(5.0 / factor), - getClosestOdd(5.0 / factor)); - } -} +/* + + DIY Layout Creator (DIYLC). + Copyright (c) 2009-2025 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.boards; + +import java.awt.AlphaComposite; +import java.awt.Composite; +import java.awt.Graphics2D; +import java.awt.Shape; +import java.awt.geom.Point2D; + +import org.diylc.common.OrientationHV; +import org.diylc.components.transform.VeroBoardTransformer; +import org.diylc.core.ComponentState; +import org.diylc.core.IDIYComponent; +import org.diylc.core.IDrawingObserver; +import org.diylc.core.ILayeredComponent; +import org.diylc.core.Project; +import org.diylc.core.annotations.BomPolicy; +import org.diylc.core.annotations.ComponentDescriptor; +import org.diylc.core.annotations.KeywordPolicy; +import org.diylc.utils.Constants; + +@ComponentDescriptor(name = "Vero Board", category = "Boards", author = "Branislav Stojkovic", + zOrder = IDIYComponent.BOARD, instanceNamePrefix = "Board", + description = "Perforated FR4 board with copper strips connecting all holes in a row", + bomPolicy = BomPolicy.SHOW_ONLY_TYPE_NAME, keywordPolicy = KeywordPolicy.SHOW_TYPE_NAME, + transformer = VeroBoardTransformer.class, enableCache = true) +public class VeroBoard extends AbstractVeroBoard implements ILayeredComponent { + + private static final long serialVersionUID = 1L; + + @Override + public void draw(Graphics2D g2d, ComponentState componentState, boolean outlineMode, Project project, + IDrawingObserver drawingObserver) { + Point2D finalSecondPoint = getFinalSecondPoint(); + + Shape clip = g2d.getClip(); + if (checkPointsClipped(clip) && !clip.contains(firstPoint.getX(), finalSecondPoint.getY()) + && !clip.contains(finalSecondPoint.getX(), firstPoint.getY())) { + return; + } + super.draw(g2d, componentState, outlineMode, project, drawingObserver); + if (componentState != ComponentState.DRAGGING) { + Composite oldComposite = applyAlpha(g2d, componentState); + double x = firstPoint.getX(); + double y = firstPoint.getY(); + int stripSize = getClosestOdd((int) STRIP_SIZE.convertToPixels()); + int holeSize = getClosestOdd((int) HOLE_SIZE.convertToPixels()); + int spacing = (int) this.spacing.convertToPixels(); + + if (orientation == OrientationHV.HORIZONTAL) { + while (y < finalSecondPoint.getY() - spacing - stripSize / 2) { + x = firstPoint.getX(); + y += spacing; + g2d.setColor(stripColor); + drawingObserver.startTrackingContinuityArea(true); + g2d.fillRect((int)(x + spacing / 2), (int)(y - stripSize / 2), (int)(finalSecondPoint.getX() - spacing - x), stripSize); + drawingObserver.stopTrackingContinuityArea(); + g2d.setColor(stripColor.darker()); + g2d.drawRect((int)(x + spacing / 2), (int)(y - stripSize / 2), (int)(finalSecondPoint.getX() - spacing - x), stripSize); + while (x < finalSecondPoint.getX() - spacing - holeSize) { + x += spacing; + g2d.setColor(Constants.CANVAS_COLOR); + g2d.fillOval((int)(x - holeSize / 2), (int)(y - holeSize / 2), holeSize, holeSize); + g2d.setColor(stripColor.darker()); + g2d.drawOval((int)(x - holeSize / 2), (int)(y - holeSize / 2), holeSize, holeSize); + } + } + } else { + while (x < finalSecondPoint.getX() - spacing) { + x += spacing; + y = firstPoint.getY(); + g2d.setColor(stripColor); + drawingObserver.startTrackingContinuityArea(true); + g2d.fillRect((int)(x - stripSize / 2), (int)(y + spacing / 2), stripSize, (int)(finalSecondPoint.getY() - spacing - y)); + drawingObserver.stopTrackingContinuityArea(); + g2d.setColor(stripColor.darker()); + g2d.drawRect((int)(x - stripSize / 2), (int)(y + spacing / 2), stripSize, (int)(finalSecondPoint.getY() - spacing - y)); + while (y < finalSecondPoint.getY() - spacing - holeSize) { + y += spacing; + g2d.setColor(Constants.CANVAS_COLOR); + g2d.fillOval((int)(x - holeSize / 2), (int)(y - holeSize / 2), holeSize, holeSize); + g2d.setColor(stripColor.darker()); + g2d.drawOval((int)(x - holeSize / 2), (int)(y - holeSize / 2), holeSize, holeSize); + } + } + } + g2d.setComposite(oldComposite); + super.drawCoordinates(g2d, spacing, project); + } + } + + @Override + public int getLayerId() { + return 1; + } + + @Override + public String getControlPointNodeName(int index) { + return null; + } + + @Override + public void drawIcon(Graphics2D g2d, int width, int height) { + int factor = 32 / width; + g2d.setColor(PHENOLIC_COLOR); + g2d.fillRect(0, 2 / factor, width - 1, height - 4 / factor); + g2d.setColor(BORDER_COLOR); + g2d.drawRect(0, 2 / factor, width - 1, height - 4 / factor); + g2d.setColor(COPPER_COLOR); + g2d.fillRect(1 / factor, width / 4, width - 2 / factor, width / 2); + g2d.setColor(COPPER_COLOR.darker()); + g2d.drawRect(1 / factor, width / 4, width - 2 / factor, width / 2); + + g2d.setColor(COPPER_COLOR); + g2d.fillRect(1 / factor, 2 / factor, width - 2 / factor, 3 / factor); + g2d.fillRect(1 / factor, height - 5 / factor, width - 2 / factor, 3 / factor); + g2d.setColor(COPPER_COLOR.darker()); + g2d.drawRect(1 / factor, 2 / factor, width - 2 / factor, 3 / factor); + g2d.drawRect(1 / factor, height - 5 / factor, width - 2 / factor, 3 / factor); + + g2d.setColor(Constants.CANVAS_COLOR); + g2d.fillOval(width / 3 - 2 / factor, width / 2 - 2 / factor, getClosestOdd(5.0 / factor), + getClosestOdd(5.0 / factor)); + g2d.fillOval(2 * width / 3 - 2 / factor, width / 2 - 2 / factor, getClosestOdd(5.0 / factor), + getClosestOdd(5.0 / factor)); + g2d.setColor(COPPER_COLOR.darker()); + g2d.drawOval(width / 3 - 2 / factor, width / 2 - 2 / factor, getClosestOdd(5.0 / factor), + getClosestOdd(5.0 / factor)); + g2d.drawOval(2 * width / 3 - 2 / factor, width / 2 - 2 / factor, getClosestOdd(5.0 / factor), + getClosestOdd(5.0 / factor)); + } +} diff --git a/diylc/diylc-library/src/main/java/org/diylc/components/chassis/ChassisPanel.java b/diylc/diylc-library/src/main/java/org/diylc/components/chassis/ChassisPanel.java index dc2f9f0ce..06457d0e2 100644 --- a/diylc/diylc-library/src/main/java/org/diylc/components/chassis/ChassisPanel.java +++ b/diylc/diylc-library/src/main/java/org/diylc/components/chassis/ChassisPanel.java @@ -1,111 +1,108 @@ -/* - - DIY Layout Creator (DIYLC). - Copyright (c) 2009-2025 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.chassis; - -import java.awt.AlphaComposite; -import java.awt.Composite; -import java.awt.Graphics2D; - -import org.diylc.common.ObjectCache; -import org.diylc.components.shapes.AbstractShape; -import org.diylc.components.transform.SimpleComponentTransformer; -import org.diylc.core.ComponentState; -import org.diylc.core.IDIYComponent; -import org.diylc.core.IDrawingObserver; -import org.diylc.core.Project; -import org.diylc.core.annotations.BomPolicy; -import org.diylc.core.annotations.ComponentDescriptor; -import org.diylc.core.annotations.EditableProperty; -import org.diylc.core.measures.Size; -import org.diylc.core.measures.SizeUnit; - -@ComponentDescriptor(name = "Chassis Panel", author = "Branislav Stojkovic", category = "Electro-Mechanical", - instanceNamePrefix = "CP", description = "One side of a chassis, with or withouth rounded edges", - zOrder = IDIYComponent.CHASSIS, bomPolicy = BomPolicy.SHOW_ONLY_TYPE_NAME, autoEdit = false, - transformer = SimpleComponentTransformer.class) -public class ChassisPanel extends AbstractShape { - - private static final long serialVersionUID = 1L; - - protected Size edgeRadius = new Size(0d, SizeUnit.mm); - - public ChassisPanel() { - this.color = LIGHT_METAL_COLOR; - this.borderColor = LIGHT_METAL_COLOR.darker(); - } - - @Override - public void draw(Graphics2D g2d, ComponentState componentState, boolean outlineMode, Project project, - IDrawingObserver drawingObserver) { - g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke((int) borderThickness.convertToPixels())); - int radius = (int) edgeRadius.convertToPixels(); - if (componentState != ComponentState.DRAGGING) { - Composite oldComposite = g2d.getComposite(); - if (alpha < MAX_ALPHA) { - g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1f * alpha / MAX_ALPHA)); - } - g2d.setColor(color); - if (radius == 0) { - g2d.fillRect((int) firstPoint.getX(), (int) firstPoint.getY(), - (int) (secondPoint.getX() - firstPoint.getX()), - (int) (secondPoint.getY() - firstPoint.getY())); - } else { - g2d.fillRoundRect((int) firstPoint.getX(), (int) firstPoint.getY(), - (int) (secondPoint.getX() - firstPoint.getX()), - (int) (secondPoint.getY() - firstPoint.getY()), radius, radius); - } - g2d.setComposite(oldComposite); - drawingObserver.stopTracking(); - } - // Do not track any changes that follow because the whole rect has been - // tracked so far. - g2d.setColor(componentState == ComponentState.SELECTED || componentState == ComponentState.DRAGGING ? SELECTION_COLOR - : borderColor); - if (radius == 0) { - g2d.drawRect((int) (firstPoint.getX()), (int) (firstPoint.getY()), - (int) (secondPoint.getX() - firstPoint.getX()), - (int) (secondPoint.getY() - firstPoint.getY())); - } else { - g2d.drawRoundRect((int) (firstPoint.getX()), (int) (firstPoint.getY()), - (int) (secondPoint.getX() - firstPoint.getX()), - (int) (secondPoint.getY() - firstPoint.getY()), radius, radius); - } - } - - @EditableProperty(name = "Radius") - public Size getEdgeRadius() { - return edgeRadius; - } - - public void setEdgeRadius(Size edgeRadius) { - this.edgeRadius = edgeRadius; - } - - @Override - public void drawIcon(Graphics2D g2d, int width, int height) { - int factor = 32 / width; - g2d.setColor(LIGHT_METAL_COLOR); - g2d.fillRect(2 / factor, 4 / factor, width - 4 / factor, height - 8 / factor); - g2d.setColor(LIGHT_METAL_COLOR.darker()); - g2d.drawRect(2 / factor, 4 / factor, width - 4 / factor, height - 8 / factor); - } -} +/* + + DIY Layout Creator (DIYLC). + Copyright (c) 2009-2025 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.chassis; + +import java.awt.AlphaComposite; +import java.awt.Composite; +import java.awt.Graphics2D; + +import org.diylc.common.ObjectCache; +import org.diylc.components.shapes.AbstractShape; +import org.diylc.components.transform.SimpleComponentTransformer; +import org.diylc.core.ComponentState; +import org.diylc.core.IDIYComponent; +import org.diylc.core.IDrawingObserver; +import org.diylc.core.Project; +import org.diylc.core.annotations.BomPolicy; +import org.diylc.core.annotations.ComponentDescriptor; +import org.diylc.core.annotations.EditableProperty; +import org.diylc.core.measures.Size; +import org.diylc.core.measures.SizeUnit; + +@ComponentDescriptor(name = "Chassis Panel", author = "Branislav Stojkovic", category = "Electro-Mechanical", + instanceNamePrefix = "CP", description = "One side of a chassis, with or withouth rounded edges", + zOrder = IDIYComponent.CHASSIS, bomPolicy = BomPolicy.SHOW_ONLY_TYPE_NAME, autoEdit = false, + transformer = SimpleComponentTransformer.class) +public class ChassisPanel extends AbstractShape { + + private static final long serialVersionUID = 1L; + + protected Size edgeRadius = new Size(0d, SizeUnit.mm); + + public ChassisPanel() { + this.color = LIGHT_METAL_COLOR; + this.borderColor = LIGHT_METAL_COLOR.darker(); + } + + @Override + public void draw(Graphics2D g2d, ComponentState componentState, boolean outlineMode, Project project, + IDrawingObserver drawingObserver) { + g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke((int) borderThickness.convertToPixels())); + int radius = (int) edgeRadius.convertToPixels(); + if (componentState != ComponentState.DRAGGING) { + Composite oldComposite = applyAlpha(g2d, componentState); + g2d.setColor(color); + if (radius == 0) { + g2d.fillRect((int) firstPoint.getX(), (int) firstPoint.getY(), + (int) (secondPoint.getX() - firstPoint.getX()), + (int) (secondPoint.getY() - firstPoint.getY())); + } else { + g2d.fillRoundRect((int) firstPoint.getX(), (int) firstPoint.getY(), + (int) (secondPoint.getX() - firstPoint.getX()), + (int) (secondPoint.getY() - firstPoint.getY()), radius, radius); + } + g2d.setComposite(oldComposite); + drawingObserver.stopTracking(); + } + // Do not track any changes that follow because the whole rect has been + // tracked so far. + g2d.setColor(componentState == ComponentState.SELECTED || componentState == ComponentState.DRAGGING ? SELECTION_COLOR + : borderColor); + if (radius == 0) { + g2d.drawRect((int) (firstPoint.getX()), (int) (firstPoint.getY()), + (int) (secondPoint.getX() - firstPoint.getX()), + (int) (secondPoint.getY() - firstPoint.getY())); + } else { + g2d.drawRoundRect((int) (firstPoint.getX()), (int) (firstPoint.getY()), + (int) (secondPoint.getX() - firstPoint.getX()), + (int) (secondPoint.getY() - firstPoint.getY()), radius, radius); + } + } + + @EditableProperty(name = "Radius") + public Size getEdgeRadius() { + return edgeRadius; + } + + public void setEdgeRadius(Size edgeRadius) { + this.edgeRadius = edgeRadius; + } + + @Override + public void drawIcon(Graphics2D g2d, int width, int height) { + int factor = 32 / width; + g2d.setColor(LIGHT_METAL_COLOR); + g2d.fillRect(2 / factor, 4 / factor, width - 4 / factor, height - 8 / factor); + g2d.setColor(LIGHT_METAL_COLOR.darker()); + g2d.drawRect(2 / factor, 4 / factor, width - 4 / factor, height - 8 / factor); + } +} diff --git a/diylc/diylc-library/src/main/java/org/diylc/components/chassis/EllipticalCutout.java b/diylc/diylc-library/src/main/java/org/diylc/components/chassis/EllipticalCutout.java index 9fa17e49d..5727c3aa4 100644 --- a/diylc/diylc-library/src/main/java/org/diylc/components/chassis/EllipticalCutout.java +++ b/diylc/diylc-library/src/main/java/org/diylc/components/chassis/EllipticalCutout.java @@ -1,75 +1,72 @@ -/* - * - * DIY Layout Creator (DIYLC). Copyright (c) 2009-2025 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.chassis; - -import java.awt.AlphaComposite; -import java.awt.Composite; -import java.awt.Graphics2D; - -import org.diylc.common.ObjectCache; -import org.diylc.components.shapes.AbstractShape; -import org.diylc.components.transform.SimpleComponentTransformer; -import org.diylc.core.ComponentState; -import org.diylc.core.IDIYComponent; -import org.diylc.core.IDrawingObserver; -import org.diylc.core.Project; -import org.diylc.core.annotations.BomPolicy; -import org.diylc.core.annotations.ComponentDescriptor; - -@ComponentDescriptor(name = "Elliptical Cutout", author = "Branislav Stojkovic", category = "Electro-Mechanical", - instanceNamePrefix = "ELC", description = "Elliptical chassis cutout", zOrder = IDIYComponent.CHASSIS + 0.1, - bomPolicy = BomPolicy.NEVER_SHOW, autoEdit = false, transformer = SimpleComponentTransformer.class) -public class EllipticalCutout extends AbstractShape { - - private static final long serialVersionUID = 1L; - - public EllipticalCutout() { - this.borderColor = LIGHT_METAL_COLOR.darker(); - } - - @Override - public void draw(Graphics2D g2d, ComponentState componentState, boolean outlineMode, Project project, - IDrawingObserver drawingObserver) { - g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke((int) borderThickness.convertToPixels())); - - if (componentState != ComponentState.DRAGGING) { - Composite oldComposite = g2d.getComposite(); - if (alpha < MAX_ALPHA) { - g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1f * alpha / MAX_ALPHA)); - } - g2d.setColor(color); - g2d.fillOval((int)firstPoint.getX(), (int)firstPoint.getY(), (int)(secondPoint.getX() - firstPoint.getX()), (int)(secondPoint.getY() - firstPoint.getY())); - g2d.setComposite(oldComposite); - } - // Do not track any changes that follow because the whole oval has been - // tracked so far. - drawingObserver.stopTracking(); - g2d.setColor(componentState == ComponentState.SELECTED || componentState == ComponentState.DRAGGING ? SELECTION_COLOR - : borderColor); - g2d.drawOval((int)firstPoint.getX(), (int)firstPoint.getY(), (int)(secondPoint.getX() - firstPoint.getX()), (int)(secondPoint.getY() - firstPoint.getY())); - } - - @Override - public void drawIcon(Graphics2D g2d, int width, int height) { - int factor = 32 / width; - g2d.setColor(COLOR); - g2d.fillOval(2 / factor, 2 / factor, width - 4 / factor, height - 4 / factor); - g2d.setColor(LIGHT_METAL_COLOR.darker()); - g2d.drawOval(2 / factor, 2 / factor, width - 4 / factor, height - 4 / factor); - } -} +/* + * + * DIY Layout Creator (DIYLC). Copyright (c) 2009-2025 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.chassis; + +import java.awt.AlphaComposite; +import java.awt.Composite; +import java.awt.Graphics2D; + +import org.diylc.common.ObjectCache; +import org.diylc.components.shapes.AbstractShape; +import org.diylc.components.transform.SimpleComponentTransformer; +import org.diylc.core.ComponentState; +import org.diylc.core.IDIYComponent; +import org.diylc.core.IDrawingObserver; +import org.diylc.core.Project; +import org.diylc.core.annotations.BomPolicy; +import org.diylc.core.annotations.ComponentDescriptor; + +@ComponentDescriptor(name = "Elliptical Cutout", author = "Branislav Stojkovic", category = "Electro-Mechanical", + instanceNamePrefix = "ELC", description = "Elliptical chassis cutout", zOrder = IDIYComponent.CHASSIS + 0.1, + bomPolicy = BomPolicy.NEVER_SHOW, autoEdit = false, transformer = SimpleComponentTransformer.class) +public class EllipticalCutout extends AbstractShape { + + private static final long serialVersionUID = 1L; + + public EllipticalCutout() { + this.borderColor = LIGHT_METAL_COLOR.darker(); + } + + @Override + public void draw(Graphics2D g2d, ComponentState componentState, boolean outlineMode, Project project, + IDrawingObserver drawingObserver) { + g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke((int) borderThickness.convertToPixels())); + + if (componentState != ComponentState.DRAGGING) { + Composite oldComposite = applyAlpha(g2d, componentState); + g2d.setColor(color); + g2d.fillOval((int)firstPoint.getX(), (int)firstPoint.getY(), (int)(secondPoint.getX() - firstPoint.getX()), (int)(secondPoint.getY() - firstPoint.getY())); + g2d.setComposite(oldComposite); + } + // Do not track any changes that follow because the whole oval has been + // tracked so far. + drawingObserver.stopTracking(); + g2d.setColor(componentState == ComponentState.SELECTED || componentState == ComponentState.DRAGGING ? SELECTION_COLOR + : borderColor); + g2d.drawOval((int)firstPoint.getX(), (int)firstPoint.getY(), (int)(secondPoint.getX() - firstPoint.getX()), (int)(secondPoint.getY() - firstPoint.getY())); + } + + @Override + public void drawIcon(Graphics2D g2d, int width, int height) { + int factor = 32 / width; + g2d.setColor(COLOR); + g2d.fillOval(2 / factor, 2 / factor, width - 4 / factor, height - 4 / factor); + g2d.setColor(LIGHT_METAL_COLOR.darker()); + g2d.drawOval(2 / factor, 2 / factor, width - 4 / factor, height - 4 / factor); + } +} diff --git a/diylc/diylc-library/src/main/java/org/diylc/components/chassis/PolygonalCutout.java b/diylc/diylc-library/src/main/java/org/diylc/components/chassis/PolygonalCutout.java index 8b74917bf..313c23bf6 100644 --- a/diylc/diylc-library/src/main/java/org/diylc/components/chassis/PolygonalCutout.java +++ b/diylc/diylc-library/src/main/java/org/diylc/components/chassis/PolygonalCutout.java @@ -1,126 +1,123 @@ -/* - * - * DIY Layout Creator (DIYLC). Copyright (c) 2009-2025 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.chassis; - -import java.awt.AlphaComposite; -import java.awt.Color; -import java.awt.Composite; -import java.awt.Graphics2D; -import java.awt.geom.Point2D; -import java.util.Arrays; - -import org.diylc.common.ObjectCache; -import org.diylc.components.shapes.AbstractShape; -import org.diylc.components.transform.SimpleComponentTransformer; -import org.diylc.core.ComponentState; -import org.diylc.core.IDIYComponent; -import org.diylc.core.IDrawingObserver; -import org.diylc.core.Project; -import org.diylc.core.annotations.BomPolicy; -import org.diylc.core.annotations.ComponentDescriptor; -import org.diylc.core.annotations.EditableProperty; - -@ComponentDescriptor(name = "Polygonal Cutout", author = "Branislav Stojkovic", category = "Electro-Mechanical", - instanceNamePrefix = "POLYC", description = "Polygonal chassis cutout", zOrder = IDIYComponent.CHASSIS + 0.1, - bomPolicy = BomPolicy.NEVER_SHOW, autoEdit = false, transformer = SimpleComponentTransformer.class) -public class PolygonalCutout extends AbstractShape { - - private static final long serialVersionUID = 1L; - - protected PointCount pointCount = PointCount._4; - - public PolygonalCutout() { - super(); - this.borderColor = LIGHT_METAL_COLOR.darker(); - this.controlPoints = - new Point2D[] {new Point2D.Double(0, 0), - new Point2D.Double(0, (int) DEFAULT_HEIGHT.convertToPixels()), - new Point2D.Double((int) DEFAULT_WIDTH.convertToPixels(), (int) DEFAULT_HEIGHT.convertToPixels()), - new Point2D.Double((int) DEFAULT_WIDTH.convertToPixels(), 0)}; - } - - @Override - public void draw(Graphics2D g2d, ComponentState componentState, boolean outlineMode, Project project, - IDrawingObserver drawingObserver) { - g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke((int) borderThickness.convertToPixels())); - g2d.setColor(color); - int[] xPoints = new int[controlPoints.length]; - int[] yPoints = new int[controlPoints.length]; - for (int i = 0; i < controlPoints.length; i++) { - xPoints[i] = (int)controlPoints[i].getX(); - yPoints[i] = (int)controlPoints[i].getY(); - } - - Composite oldComposite = g2d.getComposite(); - if (this.alpha < MAX_ALPHA) { - g2d.setComposite(AlphaComposite.getInstance(3, 1.0F * this.alpha / MAX_ALPHA)); - } - g2d.fillPolygon(xPoints, yPoints, controlPoints.length); - g2d.setComposite(oldComposite); - - // Do not track any changes that follow because the whole board has been - // tracked so far. - drawingObserver.stopTracking(); - Color lineColor = - componentState == ComponentState.SELECTED || componentState == ComponentState.DRAGGING ? SELECTION_COLOR - : borderColor; - g2d.setColor(lineColor); - g2d.drawPolygon(xPoints, yPoints, controlPoints.length); - } - - @EditableProperty(name = "Edges") - public PointCount getPointCount() { - return pointCount; - } - - public void setPointCount(PointCount pointCount) { - if (this.pointCount == pointCount) - return; - int oldPointCount = Integer.parseInt(this.pointCount.toString()); - int newPointCount = Integer.parseInt(pointCount.toString()); - this.controlPoints = Arrays.copyOf(this.controlPoints, newPointCount); - if (oldPointCount < newPointCount) { - this.controlPoints[newPointCount - 1] = this.controlPoints[oldPointCount - 1]; - for (int i = oldPointCount - 1; i < newPointCount - 1; i++) { - this.controlPoints[i] = - new Point2D.Double((this.controlPoints[i - 1].getX() + this.controlPoints[newPointCount - 1].getX()) / 2, - (this.controlPoints[i - 1].getY() + this.controlPoints[newPointCount - 1].getY()) / 2); - } - } - this.pointCount = pointCount; - } - - @Override - public void drawIcon(Graphics2D g2d, int width, int height) { - int factor = 32 / width; - g2d.setColor(COLOR); - int[] x = {2 / factor, width - 2 / factor, width - 4 / factor, 3 / factor}; - int[] y = {4 / factor, 2 / factor, height - 5 / factor, height - 2 / factor}; - g2d.fillPolygon(x, y, 4); - g2d.setColor(LIGHT_METAL_COLOR.darker()); - g2d.drawPolygon(x, y, 4); - } - - public enum PointCount { - _3, _4, _5, _6, _7, _8; - - public String toString() { - return name().substring(1); - }; - } -} +/* + * + * DIY Layout Creator (DIYLC). Copyright (c) 2009-2025 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.chassis; + +import java.awt.AlphaComposite; +import java.awt.Color; +import java.awt.Composite; +import java.awt.Graphics2D; +import java.awt.geom.Point2D; +import java.util.Arrays; + +import org.diylc.common.ObjectCache; +import org.diylc.components.shapes.AbstractShape; +import org.diylc.components.transform.SimpleComponentTransformer; +import org.diylc.core.ComponentState; +import org.diylc.core.IDIYComponent; +import org.diylc.core.IDrawingObserver; +import org.diylc.core.Project; +import org.diylc.core.annotations.BomPolicy; +import org.diylc.core.annotations.ComponentDescriptor; +import org.diylc.core.annotations.EditableProperty; + +@ComponentDescriptor(name = "Polygonal Cutout", author = "Branislav Stojkovic", category = "Electro-Mechanical", + instanceNamePrefix = "POLYC", description = "Polygonal chassis cutout", zOrder = IDIYComponent.CHASSIS + 0.1, + bomPolicy = BomPolicy.NEVER_SHOW, autoEdit = false, transformer = SimpleComponentTransformer.class) +public class PolygonalCutout extends AbstractShape { + + private static final long serialVersionUID = 1L; + + protected PointCount pointCount = PointCount._4; + + public PolygonalCutout() { + super(); + this.borderColor = LIGHT_METAL_COLOR.darker(); + this.controlPoints = + new Point2D[] {new Point2D.Double(0, 0), + new Point2D.Double(0, (int) DEFAULT_HEIGHT.convertToPixels()), + new Point2D.Double((int) DEFAULT_WIDTH.convertToPixels(), (int) DEFAULT_HEIGHT.convertToPixels()), + new Point2D.Double((int) DEFAULT_WIDTH.convertToPixels(), 0)}; + } + + @Override + public void draw(Graphics2D g2d, ComponentState componentState, boolean outlineMode, Project project, + IDrawingObserver drawingObserver) { + g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke((int) borderThickness.convertToPixels())); + g2d.setColor(color); + int[] xPoints = new int[controlPoints.length]; + int[] yPoints = new int[controlPoints.length]; + for (int i = 0; i < controlPoints.length; i++) { + xPoints[i] = (int)controlPoints[i].getX(); + yPoints[i] = (int)controlPoints[i].getY(); + } + + Composite oldComposite = applyAlpha(g2d, componentState); + g2d.fillPolygon(xPoints, yPoints, controlPoints.length); + g2d.setComposite(oldComposite); + + // Do not track any changes that follow because the whole board has been + // tracked so far. + drawingObserver.stopTracking(); + Color lineColor = + componentState == ComponentState.SELECTED || componentState == ComponentState.DRAGGING ? SELECTION_COLOR + : borderColor; + g2d.setColor(lineColor); + g2d.drawPolygon(xPoints, yPoints, controlPoints.length); + } + + @EditableProperty(name = "Edges") + public PointCount getPointCount() { + return pointCount; + } + + public void setPointCount(PointCount pointCount) { + if (this.pointCount == pointCount) + return; + int oldPointCount = Integer.parseInt(this.pointCount.toString()); + int newPointCount = Integer.parseInt(pointCount.toString()); + this.controlPoints = Arrays.copyOf(this.controlPoints, newPointCount); + if (oldPointCount < newPointCount) { + this.controlPoints[newPointCount - 1] = this.controlPoints[oldPointCount - 1]; + for (int i = oldPointCount - 1; i < newPointCount - 1; i++) { + this.controlPoints[i] = + new Point2D.Double((this.controlPoints[i - 1].getX() + this.controlPoints[newPointCount - 1].getX()) / 2, + (this.controlPoints[i - 1].getY() + this.controlPoints[newPointCount - 1].getY()) / 2); + } + } + this.pointCount = pointCount; + } + + @Override + public void drawIcon(Graphics2D g2d, int width, int height) { + int factor = 32 / width; + g2d.setColor(COLOR); + int[] x = {2 / factor, width - 2 / factor, width - 4 / factor, 3 / factor}; + int[] y = {4 / factor, 2 / factor, height - 5 / factor, height - 2 / factor}; + g2d.fillPolygon(x, y, 4); + g2d.setColor(LIGHT_METAL_COLOR.darker()); + g2d.drawPolygon(x, y, 4); + } + + public enum PointCount { + _3, _4, _5, _6, _7, _8; + + public String toString() { + return name().substring(1); + }; + } +} diff --git a/diylc/diylc-library/src/main/java/org/diylc/components/chassis/RectangularCutout.java b/diylc/diylc-library/src/main/java/org/diylc/components/chassis/RectangularCutout.java index a57f8902c..7a8bd35bf 100644 --- a/diylc/diylc-library/src/main/java/org/diylc/components/chassis/RectangularCutout.java +++ b/diylc/diylc-library/src/main/java/org/diylc/components/chassis/RectangularCutout.java @@ -1,92 +1,89 @@ -/* - * - * DIY Layout Creator (DIYLC). Copyright (c) 2009-2025 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.chassis; - -import java.awt.AlphaComposite; -import java.awt.Composite; -import java.awt.Graphics2D; - -import org.diylc.common.ObjectCache; -import org.diylc.components.shapes.AbstractShape; -import org.diylc.components.transform.SimpleComponentTransformer; -import org.diylc.core.ComponentState; -import org.diylc.core.IDIYComponent; -import org.diylc.core.IDrawingObserver; -import org.diylc.core.Project; -import org.diylc.core.annotations.BomPolicy; -import org.diylc.core.annotations.ComponentDescriptor; -import org.diylc.core.annotations.EditableProperty; -import org.diylc.core.measures.Size; -import org.diylc.core.measures.SizeUnit; - -@ComponentDescriptor(name = "Rectangular Cutout", author = "Branislav Stojkovic", category = "Electro-Mechanical", - instanceNamePrefix = "RECTC", description = "Rectangular chassis cutout, with or without rounded edges", - zOrder = IDIYComponent.CHASSIS + 0.1, bomPolicy = BomPolicy.NEVER_SHOW, autoEdit = false, - transformer = SimpleComponentTransformer.class) -public class RectangularCutout extends AbstractShape { - - private static final long serialVersionUID = 1L; - - protected Size edgeRadius = new Size(0d, SizeUnit.mm); - - public RectangularCutout() { - this.borderColor = LIGHT_METAL_COLOR.darker(); - } - - @Override - public void draw(Graphics2D g2d, ComponentState componentState, boolean outlineMode, Project project, - IDrawingObserver drawingObserver) { - g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke((int) borderThickness.convertToPixels())); - int radius = (int) edgeRadius.convertToPixels(); - if (componentState != ComponentState.DRAGGING) { - Composite oldComposite = g2d.getComposite(); - if (alpha < MAX_ALPHA) { - g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1f * alpha / MAX_ALPHA)); - } - g2d.setColor(color); - g2d.fillRoundRect((int)firstPoint.getX(), (int)firstPoint.getY(), (int)(secondPoint.getX() - firstPoint.getX()), (int)(secondPoint.getY() - firstPoint.getY()), radius, - radius); - g2d.setComposite(oldComposite); - } - // Do not track any changes that follow because the whole rect has been - // tracked so far. - drawingObserver.stopTracking(); - g2d.setColor(componentState == ComponentState.SELECTED || componentState == ComponentState.DRAGGING ? SELECTION_COLOR - : borderColor); - g2d.drawRoundRect((int)firstPoint.getX(), (int)firstPoint.getY(), (int)(secondPoint.getX() - firstPoint.getX()), (int)(secondPoint.getY() - firstPoint.getY()), radius, - radius); - } - - @EditableProperty(name = "Radius") - public Size getEdgeRadius() { - return edgeRadius; - } - - public void setEdgeRadius(Size edgeRadius) { - this.edgeRadius = edgeRadius; - } - - @Override - public void drawIcon(Graphics2D g2d, int width, int height) { - int factor = 32 / width; - g2d.setColor(COLOR); - g2d.fillRect(2 / factor, 4 / factor, width - 4 / factor, height - 8 / factor); - g2d.setColor(LIGHT_METAL_COLOR.darker()); - g2d.drawRect(2 / factor, 4 / factor, width - 4 / factor, height - 8 / factor); - } -} +/* + * + * DIY Layout Creator (DIYLC). Copyright (c) 2009-2025 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.chassis; + +import java.awt.AlphaComposite; +import java.awt.Composite; +import java.awt.Graphics2D; + +import org.diylc.common.ObjectCache; +import org.diylc.components.shapes.AbstractShape; +import org.diylc.components.transform.SimpleComponentTransformer; +import org.diylc.core.ComponentState; +import org.diylc.core.IDIYComponent; +import org.diylc.core.IDrawingObserver; +import org.diylc.core.Project; +import org.diylc.core.annotations.BomPolicy; +import org.diylc.core.annotations.ComponentDescriptor; +import org.diylc.core.annotations.EditableProperty; +import org.diylc.core.measures.Size; +import org.diylc.core.measures.SizeUnit; + +@ComponentDescriptor(name = "Rectangular Cutout", author = "Branislav Stojkovic", category = "Electro-Mechanical", + instanceNamePrefix = "RECTC", description = "Rectangular chassis cutout, with or without rounded edges", + zOrder = IDIYComponent.CHASSIS + 0.1, bomPolicy = BomPolicy.NEVER_SHOW, autoEdit = false, + transformer = SimpleComponentTransformer.class) +public class RectangularCutout extends AbstractShape { + + private static final long serialVersionUID = 1L; + + protected Size edgeRadius = new Size(0d, SizeUnit.mm); + + public RectangularCutout() { + this.borderColor = LIGHT_METAL_COLOR.darker(); + } + + @Override + public void draw(Graphics2D g2d, ComponentState componentState, boolean outlineMode, Project project, + IDrawingObserver drawingObserver) { + g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke((int) borderThickness.convertToPixels())); + int radius = (int) edgeRadius.convertToPixels(); + if (componentState != ComponentState.DRAGGING) { + Composite oldComposite = applyAlpha(g2d, componentState); + g2d.setColor(color); + g2d.fillRoundRect((int)firstPoint.getX(), (int)firstPoint.getY(), (int)(secondPoint.getX() - firstPoint.getX()), (int)(secondPoint.getY() - firstPoint.getY()), radius, + radius); + g2d.setComposite(oldComposite); + } + // Do not track any changes that follow because the whole rect has been + // tracked so far. + drawingObserver.stopTracking(); + g2d.setColor(componentState == ComponentState.SELECTED || componentState == ComponentState.DRAGGING ? SELECTION_COLOR + : borderColor); + g2d.drawRoundRect((int)firstPoint.getX(), (int)firstPoint.getY(), (int)(secondPoint.getX() - firstPoint.getX()), (int)(secondPoint.getY() - firstPoint.getY()), radius, + radius); + } + + @EditableProperty(name = "Radius") + public Size getEdgeRadius() { + return edgeRadius; + } + + public void setEdgeRadius(Size edgeRadius) { + this.edgeRadius = edgeRadius; + } + + @Override + public void drawIcon(Graphics2D g2d, int width, int height) { + int factor = 32 / width; + g2d.setColor(COLOR); + g2d.fillRect(2 / factor, 4 / factor, width - 4 / factor, height - 8 / factor); + g2d.setColor(LIGHT_METAL_COLOR.darker()); + g2d.drawRect(2 / factor, 4 / factor, width - 4 / factor, height - 8 / factor); + } +} diff --git a/diylc/diylc-library/src/main/java/org/diylc/components/connectivity/CurvedTrace.java b/diylc/diylc-library/src/main/java/org/diylc/components/connectivity/CurvedTrace.java index 59471bd47..e8521f83c 100644 --- a/diylc/diylc-library/src/main/java/org/diylc/components/connectivity/CurvedTrace.java +++ b/diylc/diylc-library/src/main/java/org/diylc/components/connectivity/CurvedTrace.java @@ -27,6 +27,7 @@ import com.bancika.gerberwriter.GerberFunctions; import org.diylc.common.LineStyle; import org.diylc.common.ObjectCache; import org.diylc.common.PCBLayer; +import org.diylc.common.Percentage; import org.diylc.components.AbstractCurvedComponent; import org.diylc.components.AbstractLeadedComponent; import org.diylc.components.LineEndingStyle; @@ -126,7 +127,7 @@ public class CurvedTrace extends AbstractCurvedComponent implements ILayer public void setValue(Void value) {} @Override - public void setAlpha(Byte alpha) { + public void setAlpha(Percentage alpha) { super.setAlpha(alpha); } diff --git a/diylc/diylc-library/src/main/java/org/diylc/components/connectivity/CutLine.java b/diylc/diylc-library/src/main/java/org/diylc/components/connectivity/CutLine.java index 915ea6764..8c6622516 100644 --- a/diylc/diylc-library/src/main/java/org/diylc/components/connectivity/CutLine.java +++ b/diylc/diylc-library/src/main/java/org/diylc/components/connectivity/CutLine.java @@ -1,165 +1,162 @@ -/* - * - * DIY Layout Creator (DIYLC). Copyright (c) 2009-2025 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; - -import java.awt.AlphaComposite; -import java.awt.Color; -import java.awt.Composite; -import java.awt.Graphics2D; -import java.awt.geom.Point2D; - -import org.diylc.common.ObjectCache; -import org.diylc.common.OrientationHV; -import org.diylc.components.AbstractTransparentComponent; -import org.diylc.components.transform.SimpleComponentTransformer; -import org.diylc.core.ComponentState; -import org.diylc.core.IDIYComponent; -import org.diylc.core.IDrawingObserver; -import org.diylc.core.Project; -import org.diylc.core.VisibilityPolicy; -import org.diylc.core.annotations.BomPolicy; -import org.diylc.core.annotations.ComponentDescriptor; -import org.diylc.core.annotations.EditableProperty; -import org.diylc.core.measures.Size; -import org.diylc.core.measures.SizeUnit; - -@ComponentDescriptor(name = "Cut Line", category = "Connectivity", author = "Branislav Stojkovic", - description = "Cut line", instanceNamePrefix = "CL", zOrder = IDIYComponent.COMPONENT, - bomPolicy = BomPolicy.NEVER_SHOW, autoEdit = false, transformer = SimpleComponentTransformer.class) -public class CutLine extends AbstractTransparentComponent { - - private static final long serialVersionUID = 1L; - - public static Size WIDTH = new Size(0.125d, SizeUnit.in); - public static Size LENGTH = new Size(3.125d, SizeUnit.in); - public static Color COLOR = Color.black; - - private Size width = WIDTH; - private Size length = LENGTH; - private Color color = COLOR; - private Point2D.Double point = new Point2D.Double(0, 0); - private OrientationHV orientation = OrientationHV.VERTICAL; - - @Override - public void draw(Graphics2D g2d, ComponentState componentState, boolean outlineMode, Project project, - IDrawingObserver drawingObserver) { - int w = getClosestOdd((int) getWidth().convertToPixels()); - int l = getClosestOdd((int) getLength().convertToPixels()); - g2d.setColor(componentState == ComponentState.SELECTED || componentState == ComponentState.DRAGGING ? SELECTION_COLOR - : color); - g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(w)); - - Composite oldComposite = g2d.getComposite(); - if (alpha < MAX_ALPHA) { - g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1f * alpha / MAX_ALPHA)); - } - - if (getOrientation() == OrientationHV.HORIZONTAL) - g2d.drawLine((int)point.getX(), (int)point.getY(), (int)point.getX() + l, (int)point.getY()); - else - g2d.drawLine((int)point.getX(), (int)point.getY(), (int)point.getX(), (int)point.getY() + l); - - g2d.setComposite(oldComposite); - } - - @Override - public void drawIcon(Graphics2D g2d, int width, int height) { - g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(2)); - g2d.setColor(COLOR); - g2d.drawLine(width / 2, height - 2, width / 2, 1); - } - - @EditableProperty - public Size getWidth() { - return width; - } - - public void setWidth(Size width) { - this.width = width; - } - - @EditableProperty - public Size getLength() { - return length; - } - - public void setLength(Size length) { - this.length = length; - } - - @EditableProperty - public OrientationHV getOrientation() { - return orientation; - } - - public void setOrientation(OrientationHV orientation) { - this.orientation = orientation; - } - - @Override - public String getName() { - return super.getName(); - } - - @Override - public int getControlPointCount() { - return 1; - } - - @Override - public boolean isControlPointSticky(int index) { - return false; - } - - @Override - public VisibilityPolicy getControlPointVisibilityPolicy(int index) { - return VisibilityPolicy.NEVER; - } - - @Override - public Point2D getControlPoint(int index) { - return point; - } - - @Override - public void setControlPoint(Point2D point, int index) { - this.point.setLocation(point); - } - - @EditableProperty(name = "Color") - public Color getColor() { - return color; - } - - public void setColor(Color color) { - this.color = color; - } - - @Override - public Void getValue() { - return null; - } - - @Override - public void setValue(Void value) {} - - @Override - public String getControlPointNodeName(int index) { - return null; - } -} +/* + * + * DIY Layout Creator (DIYLC). Copyright (c) 2009-2025 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; + +import java.awt.AlphaComposite; +import java.awt.Color; +import java.awt.Composite; +import java.awt.Graphics2D; +import java.awt.geom.Point2D; + +import org.diylc.common.ObjectCache; +import org.diylc.common.OrientationHV; +import org.diylc.components.AbstractTransparentComponent; +import org.diylc.components.transform.SimpleComponentTransformer; +import org.diylc.core.ComponentState; +import org.diylc.core.IDIYComponent; +import org.diylc.core.IDrawingObserver; +import org.diylc.core.Project; +import org.diylc.core.VisibilityPolicy; +import org.diylc.core.annotations.BomPolicy; +import org.diylc.core.annotations.ComponentDescriptor; +import org.diylc.core.annotations.EditableProperty; +import org.diylc.core.measures.Size; +import org.diylc.core.measures.SizeUnit; + +@ComponentDescriptor(name = "Cut Line", category = "Connectivity", author = "Branislav Stojkovic", + description = "Cut line", instanceNamePrefix = "CL", zOrder = IDIYComponent.COMPONENT, + bomPolicy = BomPolicy.NEVER_SHOW, autoEdit = false, transformer = SimpleComponentTransformer.class) +public class CutLine extends AbstractTransparentComponent { + + private static final long serialVersionUID = 1L; + + public static Size WIDTH = new Size(0.125d, SizeUnit.in); + public static Size LENGTH = new Size(3.125d, SizeUnit.in); + public static Color COLOR = Color.black; + + private Size width = WIDTH; + private Size length = LENGTH; + private Color color = COLOR; + private Point2D.Double point = new Point2D.Double(0, 0); + private OrientationHV orientation = OrientationHV.VERTICAL; + + @Override + public void draw(Graphics2D g2d, ComponentState componentState, boolean outlineMode, Project project, + IDrawingObserver drawingObserver) { + int w = getClosestOdd((int) getWidth().convertToPixels()); + int l = getClosestOdd((int) getLength().convertToPixels()); + g2d.setColor(componentState == ComponentState.SELECTED || componentState == ComponentState.DRAGGING ? SELECTION_COLOR + : color); + g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(w)); + + Composite oldComposite = applyAlpha(g2d, componentState); + + if (getOrientation() == OrientationHV.HORIZONTAL) + g2d.drawLine((int)point.getX(), (int)point.getY(), (int)point.getX() + l, (int)point.getY()); + else + g2d.drawLine((int)point.getX(), (int)point.getY(), (int)point.getX(), (int)point.getY() + l); + + g2d.setComposite(oldComposite); + } + + @Override + public void drawIcon(Graphics2D g2d, int width, int height) { + g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(2)); + g2d.setColor(COLOR); + g2d.drawLine(width / 2, height - 2, width / 2, 1); + } + + @EditableProperty + public Size getWidth() { + return width; + } + + public void setWidth(Size width) { + this.width = width; + } + + @EditableProperty + public Size getLength() { + return length; + } + + public void setLength(Size length) { + this.length = length; + } + + @EditableProperty + public OrientationHV getOrientation() { + return orientation; + } + + public void setOrientation(OrientationHV orientation) { + this.orientation = orientation; + } + + @Override + public String getName() { + return super.getName(); + } + + @Override + public int getControlPointCount() { + return 1; + } + + @Override + public boolean isControlPointSticky(int index) { + return false; + } + + @Override + public VisibilityPolicy getControlPointVisibilityPolicy(int index) { + return VisibilityPolicy.NEVER; + } + + @Override + public Point2D getControlPoint(int index) { + return point; + } + + @Override + public void setControlPoint(Point2D point, int index) { + this.point.setLocation(point); + } + + @EditableProperty(name = "Color") + public Color getColor() { + return color; + } + + public void setColor(Color color) { + this.color = color; + } + + @Override + public Void getValue() { + return null; + } + + @Override + public void setValue(Void value) {} + + @Override + public String getControlPointNodeName(int index) { + return null; + } +} diff --git a/diylc/diylc-library/src/main/java/org/diylc/components/connectivity/Eyelet.java b/diylc/diylc-library/src/main/java/org/diylc/components/connectivity/Eyelet.java index e7fdd111b..253f0bccb 100644 --- a/diylc/diylc-library/src/main/java/org/diylc/components/connectivity/Eyelet.java +++ b/diylc/diylc-library/src/main/java/org/diylc/components/connectivity/Eyelet.java @@ -1,189 +1,186 @@ -/* - - DIY Layout Creator (DIYLC). - Copyright (c) 2009-2025 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; - -import java.awt.*; -import java.awt.geom.Point2D; -import java.awt.geom.Rectangle2D; - -import org.diylc.common.ObjectCache; -import org.diylc.components.AbstractComponent; -import org.diylc.components.AbstractTransparentComponent; -import org.diylc.components.transform.SimpleComponentTransformer; -import org.diylc.core.ComponentState; -import org.diylc.core.IDIYComponent; -import org.diylc.core.IDrawingObserver; -import org.diylc.core.Project; -import org.diylc.core.VisibilityPolicy; -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.annotations.PositiveMeasureValidator; -import org.diylc.core.annotations.PositiveNonZeroMeasureValidator; -import org.diylc.core.measures.Size; -import org.diylc.core.measures.SizeUnit; -import org.diylc.utils.Constants; - -@ComponentDescriptor(name = "Eyelet", category = "Connectivity", author = "Branislav Stojkovic", - description = "Eyelet or turret terminal", instanceNamePrefix = "Eyelet", - zOrder = IDIYComponent.TRACE + 0.1, bomPolicy = BomPolicy.SHOW_ONLY_TYPE_NAME, autoEdit = false, - keywordPolicy = KeywordPolicy.SHOW_TYPE_NAME, transformer = SimpleComponentTransformer.class, - enableCache = true) -public class Eyelet extends AbstractTransparentComponent { - - private static final long serialVersionUID = 1L; - - public static Size SIZE = new Size(0.2d, SizeUnit.in); - public static Size HOLE_SIZE = new Size(0.1d, SizeUnit.in); - public static Color COLOR = Color.decode("#C3E4ED"); - - private Size size = SIZE; - private Size holeSize = HOLE_SIZE; - private Color color = COLOR; - private Point2D.Double point = new Point2D.Double(0, 0); - private String value = ""; - - @Override - public void draw(Graphics2D g2d, ComponentState componentState, boolean outlineMode, Project project, - IDrawingObserver drawingObserver) { - if (checkPointsClipped(g2d.getClip())) { - return; - } - int diameter = getClosestOdd((int) size.convertToPixels()); - int holeDiameter = getClosestOdd((int) holeSize.convertToPixels()); - - Composite oldComposite = g2d.getComposite(); - if (getAlpha() < MAX_ALPHA) { - g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1f * getAlpha() / MAX_ALPHA)); - } - - g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(1f)); - g2d.setColor(color); - drawingObserver.startTrackingContinuityArea(true); - g2d.fillOval((int)(point.getX() - diameter / 2), (int)(point.getY() - diameter / 2), diameter, diameter); - drawingObserver.stopTrackingContinuityArea(); - g2d.setColor(componentState == ComponentState.SELECTED || componentState == ComponentState.DRAGGING ? SELECTION_COLOR - : color.darker()); - g2d.drawOval((int)(point.getX() - diameter / 2), (int)(point.getY() - diameter / 2), diameter, diameter); - g2d.setColor(Constants.CANVAS_COLOR); - g2d.fillOval((int)(point.getX() - holeDiameter / 2), (int)(point.getY() - holeDiameter / 2), holeDiameter, holeDiameter); - g2d.setColor(componentState == ComponentState.SELECTED || componentState == ComponentState.DRAGGING ? SELECTION_COLOR - : color.darker()); - g2d.drawOval((int)(point.getX() - holeDiameter / 2), (int)(point.getY() - holeDiameter / 2), holeDiameter, holeDiameter); - - g2d.setComposite(oldComposite); - } - - @Override - public void drawIcon(Graphics2D g2d, int width, int height) { - int diameter = getClosestOdd(width / 2); - int holeDiameter = 5; - g2d.setColor(COLOR); - g2d.fillOval((width - diameter) / 2, (height - diameter) / 2, diameter, diameter); - g2d.setColor(COLOR.darker()); - g2d.drawOval((width - diameter) / 2, (height - diameter) / 2, diameter, diameter); - g2d.setColor(Constants.CANVAS_COLOR); - g2d.fillOval((width - holeDiameter) / 2, (height - holeDiameter) / 2, holeDiameter, holeDiameter); - g2d.setColor(COLOR.darker()); - g2d.drawOval((width - holeDiameter) / 2, (height - holeDiameter) / 2, holeDiameter, holeDiameter); - } - - @EditableProperty(validatorClass = PositiveNonZeroMeasureValidator.class) - public Size getSize() { - return size; - } - - public void setSize(Size size) { - this.size = size; - } - - @EditableProperty(name = "Hole Size", validatorClass = PositiveMeasureValidator.class) - public Size getHoleSize() { - return holeSize; - } - - public void setHoleSize(Size holeSize) { - this.holeSize = holeSize; - } - - @Override - public String getName() { - return super.getName(); - } - - @Override - public int getControlPointCount() { - return 1; - } - - @Override - public boolean isControlPointSticky(int index) { - return true; - } - - @Override - public VisibilityPolicy getControlPointVisibilityPolicy(int index) { - return VisibilityPolicy.NEVER; - } - - @Override - public Point2D getControlPoint(int index) { - return point; - } - - @Override - public void setControlPoint(Point2D point, int index) { - this.point.setLocation(point); - } - - @EditableProperty(name = "Color") - public Color getColor() { - return color; - } - - public void setColor(Color color) { - this.color = color; - } - - @Override - @EditableProperty - public String getValue() { - return value; - } - - @Override - public void setValue(String value) { - this.value = value; - } - - @Override - public String getControlPointNodeName(int index) { - return null; - } - - @Override - public Rectangle2D getCachingBounds() { - double size = getSize().convertToPixels(); - return new Rectangle2D.Double(point.getX() - size, point.getY() - size, size * 2, size * 2); - } -} +/* + + DIY Layout Creator (DIYLC). + Copyright (c) 2009-2025 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; + +import java.awt.*; +import java.awt.geom.Point2D; +import java.awt.geom.Rectangle2D; + +import org.diylc.common.ObjectCache; +import org.diylc.components.AbstractComponent; +import org.diylc.components.AbstractTransparentComponent; +import org.diylc.components.transform.SimpleComponentTransformer; +import org.diylc.core.ComponentState; +import org.diylc.core.IDIYComponent; +import org.diylc.core.IDrawingObserver; +import org.diylc.core.Project; +import org.diylc.core.VisibilityPolicy; +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.annotations.PositiveMeasureValidator; +import org.diylc.core.annotations.PositiveNonZeroMeasureValidator; +import org.diylc.core.measures.Size; +import org.diylc.core.measures.SizeUnit; +import org.diylc.utils.Constants; + +@ComponentDescriptor(name = "Eyelet", category = "Connectivity", author = "Branislav Stojkovic", + description = "Eyelet or turret terminal", instanceNamePrefix = "Eyelet", + zOrder = IDIYComponent.TRACE + 0.1, bomPolicy = BomPolicy.SHOW_ONLY_TYPE_NAME, autoEdit = false, + keywordPolicy = KeywordPolicy.SHOW_TYPE_NAME, transformer = SimpleComponentTransformer.class, + enableCache = true) +public class Eyelet extends AbstractTransparentComponent { + + private static final long serialVersionUID = 1L; + + public static Size SIZE = new Size(0.2d, SizeUnit.in); + public static Size HOLE_SIZE = new Size(0.1d, SizeUnit.in); + public static Color COLOR = Color.decode("#C3E4ED"); + + private Size size = SIZE; + private Size holeSize = HOLE_SIZE; + private Color color = COLOR; + private Point2D.Double point = new Point2D.Double(0, 0); + private String value = ""; + + @Override + public void draw(Graphics2D g2d, ComponentState componentState, boolean outlineMode, Project project, + IDrawingObserver drawingObserver) { + if (checkPointsClipped(g2d.getClip())) { + return; + } + int diameter = getClosestOdd((int) size.convertToPixels()); + int holeDiameter = getClosestOdd((int) holeSize.convertToPixels()); + + Composite oldComposite = applyAlpha(g2d, componentState); + + g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(1f)); + g2d.setColor(color); + drawingObserver.startTrackingContinuityArea(true); + g2d.fillOval((int)(point.getX() - diameter / 2), (int)(point.getY() - diameter / 2), diameter, diameter); + drawingObserver.stopTrackingContinuityArea(); + g2d.setColor(componentState == ComponentState.SELECTED || componentState == ComponentState.DRAGGING ? SELECTION_COLOR + : color.darker()); + g2d.drawOval((int)(point.getX() - diameter / 2), (int)(point.getY() - diameter / 2), diameter, diameter); + g2d.setColor(Constants.CANVAS_COLOR); + g2d.fillOval((int)(point.getX() - holeDiameter / 2), (int)(point.getY() - holeDiameter / 2), holeDiameter, holeDiameter); + g2d.setColor(componentState == ComponentState.SELECTED || componentState == ComponentState.DRAGGING ? SELECTION_COLOR + : color.darker()); + g2d.drawOval((int)(point.getX() - holeDiameter / 2), (int)(point.getY() - holeDiameter / 2), holeDiameter, holeDiameter); + + g2d.setComposite(oldComposite); + } + + @Override + public void drawIcon(Graphics2D g2d, int width, int height) { + int diameter = getClosestOdd(width / 2); + int holeDiameter = 5; + g2d.setColor(COLOR); + g2d.fillOval((width - diameter) / 2, (height - diameter) / 2, diameter, diameter); + g2d.setColor(COLOR.darker()); + g2d.drawOval((width - diameter) / 2, (height - diameter) / 2, diameter, diameter); + g2d.setColor(Constants.CANVAS_COLOR); + g2d.fillOval((width - holeDiameter) / 2, (height - holeDiameter) / 2, holeDiameter, holeDiameter); + g2d.setColor(COLOR.darker()); + g2d.drawOval((width - holeDiameter) / 2, (height - holeDiameter) / 2, holeDiameter, holeDiameter); + } + + @EditableProperty(validatorClass = PositiveNonZeroMeasureValidator.class) + public Size getSize() { + return size; + } + + public void setSize(Size size) { + this.size = size; + } + + @EditableProperty(name = "Hole Size", validatorClass = PositiveMeasureValidator.class) + public Size getHoleSize() { + return holeSize; + } + + public void setHoleSize(Size holeSize) { + this.holeSize = holeSize; + } + + @Override + public String getName() { + return super.getName(); + } + + @Override + public int getControlPointCount() { + return 1; + } + + @Override + public boolean isControlPointSticky(int index) { + return true; + } + + @Override + public VisibilityPolicy getControlPointVisibilityPolicy(int index) { + return VisibilityPolicy.NEVER; + } + + @Override + public Point2D getControlPoint(int index) { + return point; + } + + @Override + public void setControlPoint(Point2D point, int index) { + this.point.setLocation(point); + } + + @EditableProperty(name = "Color") + public Color getColor() { + return color; + } + + public void setColor(Color color) { + this.color = color; + } + + @Override + @EditableProperty + public String getValue() { + return value; + } + + @Override + public void setValue(String value) { + this.value = value; + } + + @Override + public String getControlPointNodeName(int index) { + return null; + } + + @Override + public Rectangle2D getCachingBounds() { + double size = getSize().convertToPixels(); + return new Rectangle2D.Double(point.getX() - size, point.getY() - size, size * 2, size * 2); + } +} diff --git a/diylc/diylc-library/src/main/java/org/diylc/components/connectivity/GroundFill.java b/diylc/diylc-library/src/main/java/org/diylc/components/connectivity/GroundFill.java index 49fdb1d31..b0f6eb24d 100644 --- a/diylc/diylc-library/src/main/java/org/diylc/components/connectivity/GroundFill.java +++ b/diylc/diylc-library/src/main/java/org/diylc/components/connectivity/GroundFill.java @@ -1,223 +1,220 @@ -/* - - DIY Layout Creator (DIYLC). - Copyright (c) 2009-2025 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; - -import java.awt.*; -import java.awt.geom.Point2D; -import java.util.Arrays; -import java.util.EnumSet; -import java.util.Set; - -import com.bancika.gerberwriter.GerberFunctions; - -import org.diylc.common.ObjectCache; -import org.diylc.common.PCBLayer; -import org.diylc.components.AbstractComponent; -import org.diylc.components.AbstractTransparentComponent; -import org.diylc.components.transform.SimpleComponentTransformer; -import org.diylc.core.ComponentState; -import org.diylc.core.IDIYComponent; -import org.diylc.core.IDrawingObserver; -import org.diylc.core.ILayeredComponent; -import org.diylc.core.Project; -import org.diylc.core.VisibilityPolicy; -import org.diylc.core.annotations.BomPolicy; -import org.diylc.core.annotations.ComponentDescriptor; -import org.diylc.core.annotations.EditableProperty; -import org.diylc.core.gerber.GerberLayer; -import org.diylc.core.gerber.GerberRenderMode; -import org.diylc.core.gerber.IGerberComponentSimple; -import org.diylc.core.measures.Size; -import org.diylc.core.measures.SizeUnit; - -@ComponentDescriptor(name = "Ground Fill", author = "Branislav Stojkovic", category = "Connectivity", - instanceNamePrefix = "GF", description = "Polygonal ground fill area", zOrder = IDIYComponent.TRACE, - bomPolicy = BomPolicy.NEVER_SHOW, autoEdit = false, transformer = SimpleComponentTransformer.class) -public class GroundFill extends AbstractTransparentComponent - implements ILayeredComponent, IGerberComponentSimple { - - private static final long serialVersionUID = 1L; - - public static Color COLOR = Color.black; - public static Size DEFAULT_WIDTH = new Size(1.5d, SizeUnit.in); - public static Size DEFAULT_HEIGHT = new Size(1.2d, SizeUnit.in); - - protected Point2D[] controlPoints = new Point2D[] {new Point2D.Double(0, 0), new Point2D.Double(0, (int) DEFAULT_HEIGHT.convertToPixels()), - new Point2D.Double((int) DEFAULT_WIDTH.convertToPixels(), (int) DEFAULT_HEIGHT.convertToPixels()), - new Point2D.Double((int) DEFAULT_WIDTH.convertToPixels(), 0)}; - - protected Color color = COLOR; - protected PointCount pointCount = PointCount._4; - private PCBLayer layer = PCBLayer._1; - - @Override - public void draw(Graphics2D g2d, ComponentState componentState, boolean outlineMode, - Project project, IDrawingObserver drawingObserver) { - g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(1)); - Color fillColor = - componentState == ComponentState.SELECTED || componentState == ComponentState.DRAGGING ? SELECTION_COLOR - : color; - g2d.setColor(fillColor); - int[] xPoints = new int[controlPoints.length]; - int[] yPoints = new int[controlPoints.length]; - for (int i = 0; i < controlPoints.length; i++) { - xPoints[i] = (int)controlPoints[i].getX(); - yPoints[i] = (int)controlPoints[i].getY(); - } - drawingObserver.startTrackingContinuityArea(true); - Composite oldComposite = g2d.getComposite(); - if (getAlpha() < MAX_ALPHA) { - g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1f * getAlpha() / MAX_ALPHA)); - } - g2d.fillPolygon(xPoints, yPoints, controlPoints.length); - g2d.setComposite(oldComposite); - drawingObserver.stopTrackingContinuityArea(); - // Do not track any changes that follow because the whole board has been - // tracked so far. - drawingObserver.stopTracking(); - } - - @EditableProperty(name = "Color") - public Color getColor() { - return color; - } - - public void setColor(Color color) { - this.color = color; - } - - @Override - public int getControlPointCount() { - return controlPoints.length; - } - - @Override - public Point2D getControlPoint(int index) { - return controlPoints[index]; - } - - @Override - public boolean isControlPointSticky(int index) { - return false; - } - - @Override - public VisibilityPolicy getControlPointVisibilityPolicy(int index) { - return VisibilityPolicy.WHEN_SELECTED; - } - - @Override - public void setControlPoint(Point2D point, int index) { - controlPoints[index].setLocation(point); - } - - @EditableProperty(name = "Edges") - public PointCount getPointCount() { - return pointCount; - } - - public void setPointCount(PointCount pointCount) { - if (this.pointCount == pointCount) - return; - int oldPointCount = Integer.parseInt(this.pointCount.toString()); - int newPointCount = Integer.parseInt(pointCount.toString()); - this.controlPoints = Arrays.copyOf(this.controlPoints, newPointCount); - if (oldPointCount < newPointCount) { - this.controlPoints[newPointCount - 1] = this.controlPoints[oldPointCount - 1]; - for (int i = oldPointCount - 1; i < newPointCount - 1; i++) { - this.controlPoints[i] = - new Point2D.Double((this.controlPoints[i - 1].getX() + this.controlPoints[newPointCount - 1].getX()) / 2, - (this.controlPoints[i - 1].getY() + this.controlPoints[newPointCount - 1].getY()) / 2); - } - } - this.pointCount = pointCount; - } - - @EditableProperty - public PCBLayer getLayer() { - if (layer == null) { - layer = PCBLayer._1; - } - return layer; - } - - public void setLayer(PCBLayer layer) { - this.layer = layer; - } - - @Override - public int getLayerId() { - return getLayer().getId(); - } - - @Deprecated - @Override - public Void getValue() { - return null; - } - - @Deprecated - @Override - public void setValue(Void value) {} - - @Override - public String getControlPointNodeName(int index) { - return null; - } - - @Override - public void drawIcon(Graphics2D g2d, int width, int height) { - int factor = 32 / width; - g2d.setColor(COLOR); - int[] x = {2 / factor, width - 2 / factor, width - 4 / factor, 3 / factor}; - int[] y = {4 / factor, 2 / factor, height - 5 / factor, height - 2 / factor}; - g2d.fillPolygon(x, y, 4); - } - - public enum PointCount { - _3, _4, _5, _6, _7, _8; - - public String toString() { - return name().substring(1); - }; - } - - @Override - public Set getGerberRenderModes() { - return EnumSet.of(GerberRenderMode.Normal); - } - - @Override - public GerberLayer getGerberLayer() { - return getLayer().toGerberCopperLayer(); - } - - @Override - public String getGerberFunction() { - return GerberFunctions.CONDUCTOR; - } - - @Override - public boolean isGerberNegative() { - return false; - } -} +/* + + DIY Layout Creator (DIYLC). + Copyright (c) 2009-2025 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; + +import java.awt.*; +import java.awt.geom.Point2D; +import java.util.Arrays; +import java.util.EnumSet; +import java.util.Set; + +import com.bancika.gerberwriter.GerberFunctions; + +import org.diylc.common.ObjectCache; +import org.diylc.common.PCBLayer; +import org.diylc.components.AbstractComponent; +import org.diylc.components.AbstractTransparentComponent; +import org.diylc.components.transform.SimpleComponentTransformer; +import org.diylc.core.ComponentState; +import org.diylc.core.IDIYComponent; +import org.diylc.core.IDrawingObserver; +import org.diylc.core.ILayeredComponent; +import org.diylc.core.Project; +import org.diylc.core.VisibilityPolicy; +import org.diylc.core.annotations.BomPolicy; +import org.diylc.core.annotations.ComponentDescriptor; +import org.diylc.core.annotations.EditableProperty; +import org.diylc.core.gerber.GerberLayer; +import org.diylc.core.gerber.GerberRenderMode; +import org.diylc.core.gerber.IGerberComponentSimple; +import org.diylc.core.measures.Size; +import org.diylc.core.measures.SizeUnit; + +@ComponentDescriptor(name = "Ground Fill", author = "Branislav Stojkovic", category = "Connectivity", + instanceNamePrefix = "GF", description = "Polygonal ground fill area", zOrder = IDIYComponent.TRACE, + bomPolicy = BomPolicy.NEVER_SHOW, autoEdit = false, transformer = SimpleComponentTransformer.class) +public class GroundFill extends AbstractTransparentComponent + implements ILayeredComponent, IGerberComponentSimple { + + private static final long serialVersionUID = 1L; + + public static Color COLOR = Color.black; + public static Size DEFAULT_WIDTH = new Size(1.5d, SizeUnit.in); + public static Size DEFAULT_HEIGHT = new Size(1.2d, SizeUnit.in); + + protected Point2D[] controlPoints = new Point2D[] {new Point2D.Double(0, 0), new Point2D.Double(0, (int) DEFAULT_HEIGHT.convertToPixels()), + new Point2D.Double((int) DEFAULT_WIDTH.convertToPixels(), (int) DEFAULT_HEIGHT.convertToPixels()), + new Point2D.Double((int) DEFAULT_WIDTH.convertToPixels(), 0)}; + + protected Color color = COLOR; + protected PointCount pointCount = PointCount._4; + private PCBLayer layer = PCBLayer._1; + + @Override + public void draw(Graphics2D g2d, ComponentState componentState, boolean outlineMode, + Project project, IDrawingObserver drawingObserver) { + g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(1)); + Color fillColor = + componentState == ComponentState.SELECTED || componentState == ComponentState.DRAGGING ? SELECTION_COLOR + : color; + g2d.setColor(fillColor); + int[] xPoints = new int[controlPoints.length]; + int[] yPoints = new int[controlPoints.length]; + for (int i = 0; i < controlPoints.length; i++) { + xPoints[i] = (int)controlPoints[i].getX(); + yPoints[i] = (int)controlPoints[i].getY(); + } + drawingObserver.startTrackingContinuityArea(true); + Composite oldComposite = applyAlpha(g2d, componentState); + g2d.fillPolygon(xPoints, yPoints, controlPoints.length); + g2d.setComposite(oldComposite); + drawingObserver.stopTrackingContinuityArea(); + // Do not track any changes that follow because the whole board has been + // tracked so far. + drawingObserver.stopTracking(); + } + + @EditableProperty(name = "Color") + public Color getColor() { + return color; + } + + public void setColor(Color color) { + this.color = color; + } + + @Override + public int getControlPointCount() { + return controlPoints.length; + } + + @Override + public Point2D getControlPoint(int index) { + return controlPoints[index]; + } + + @Override + public boolean isControlPointSticky(int index) { + return false; + } + + @Override + public VisibilityPolicy getControlPointVisibilityPolicy(int index) { + return VisibilityPolicy.WHEN_SELECTED; + } + + @Override + public void setControlPoint(Point2D point, int index) { + controlPoints[index].setLocation(point); + } + + @EditableProperty(name = "Edges") + public PointCount getPointCount() { + return pointCount; + } + + public void setPointCount(PointCount pointCount) { + if (this.pointCount == pointCount) + return; + int oldPointCount = Integer.parseInt(this.pointCount.toString()); + int newPointCount = Integer.parseInt(pointCount.toString()); + this.controlPoints = Arrays.copyOf(this.controlPoints, newPointCount); + if (oldPointCount < newPointCount) { + this.controlPoints[newPointCount - 1] = this.controlPoints[oldPointCount - 1]; + for (int i = oldPointCount - 1; i < newPointCount - 1; i++) { + this.controlPoints[i] = + new Point2D.Double((this.controlPoints[i - 1].getX() + this.controlPoints[newPointCount - 1].getX()) / 2, + (this.controlPoints[i - 1].getY() + this.controlPoints[newPointCount - 1].getY()) / 2); + } + } + this.pointCount = pointCount; + } + + @EditableProperty + public PCBLayer getLayer() { + if (layer == null) { + layer = PCBLayer._1; + } + return layer; + } + + public void setLayer(PCBLayer layer) { + this.layer = layer; + } + + @Override + public int getLayerId() { + return getLayer().getId(); + } + + @Deprecated + @Override + public Void getValue() { + return null; + } + + @Deprecated + @Override + public void setValue(Void value) {} + + @Override + public String getControlPointNodeName(int index) { + return null; + } + + @Override + public void drawIcon(Graphics2D g2d, int width, int height) { + int factor = 32 / width; + g2d.setColor(COLOR); + int[] x = {2 / factor, width - 2 / factor, width - 4 / factor, 3 / factor}; + int[] y = {4 / factor, 2 / factor, height - 5 / factor, height - 2 / factor}; + g2d.fillPolygon(x, y, 4); + } + + public enum PointCount { + _3, _4, _5, _6, _7, _8; + + public String toString() { + return name().substring(1); + }; + } + + @Override + public Set getGerberRenderModes() { + return EnumSet.of(GerberRenderMode.Normal); + } + + @Override + public GerberLayer getGerberLayer() { + return getLayer().toGerberCopperLayer(); + } + + @Override + public String getGerberFunction() { + return GerberFunctions.CONDUCTOR; + } + + @Override + public boolean isGerberNegative() { + return false; + } +} diff --git a/diylc/diylc-library/src/main/java/org/diylc/components/connectivity/MultimeterProbe.java b/diylc/diylc-library/src/main/java/org/diylc/components/connectivity/MultimeterProbe.java index db68a6b0d..0d4dfd2b1 100644 --- a/diylc/diylc-library/src/main/java/org/diylc/components/connectivity/MultimeterProbe.java +++ b/diylc/diylc-library/src/main/java/org/diylc/components/connectivity/MultimeterProbe.java @@ -32,6 +32,7 @@ import org.diylc.appframework.miscutils.ConfigurationManager; import org.diylc.common.IPlugInPort; import org.diylc.common.ObjectCache; import org.diylc.common.Orientation45; +import org.diylc.common.Percentage; import org.diylc.components.AbstractTransparentComponent; import org.diylc.components.transform.SimpleComponentTransformer; import org.diylc.core.*; @@ -67,7 +68,7 @@ public class MultimeterProbe extends AbstractTransparentComponent { private transient Shape[] body = null; public MultimeterProbe() { - this.alpha = (byte) (MAX_ALPHA / 2); + this.alphaPercent = new Percentage(50); } @Override @@ -85,11 +86,7 @@ public class MultimeterProbe extends AbstractTransparentComponent { (int) (sensitivity * 2), (int) (sensitivity * 2)); drawingObserver.stopTrackingContinuityArea(); - Composite oldComposite = g2d.getComposite(); - if (alpha < MAX_ALPHA) { - g2d.setComposite( - AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1f * alpha / MAX_ALPHA)); - } + Composite oldComposite = applyAlpha(g2d, componentState); g2d.setColor(outlineMode ? Constants.TRANSPARENT_COLOR : PROBE_COLOR); g2d.fill(shapes[0]); g2d.setColor(outlineMode ? Constants.TRANSPARENT_COLOR : handleColor); diff --git a/diylc/diylc-library/src/main/java/org/diylc/components/connectivity/PCBTerminalBlock.java b/diylc/diylc-library/src/main/java/org/diylc/components/connectivity/PCBTerminalBlock.java index 06301310a..34d19888c 100644 --- a/diylc/diylc-library/src/main/java/org/diylc/components/connectivity/PCBTerminalBlock.java +++ b/diylc/diylc-library/src/main/java/org/diylc/components/connectivity/PCBTerminalBlock.java @@ -206,11 +206,7 @@ public class PCBTerminalBlock extends AbstractTransparentComponent { Shape[] body = getBody(); g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(1)); - Composite oldComposite = g2d.getComposite(); - if (alpha < MAX_ALPHA) { - g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1f * alpha / MAX_ALPHA)); - } + Composite oldComposite = applyAlpha(g2d, componentState); g2d.setColor(outlineMode ? Constants.TRANSPARENT_COLOR : BASE_COLOR); g2d.fill(body[0]); diff --git a/diylc/diylc-library/src/main/java/org/diylc/components/connectivity/SolderPad.java b/diylc/diylc-library/src/main/java/org/diylc/components/connectivity/SolderPad.java index 93fdae945..42cdf6a9e 100644 --- a/diylc/diylc-library/src/main/java/org/diylc/components/connectivity/SolderPad.java +++ b/diylc/diylc-library/src/main/java/org/diylc/components/connectivity/SolderPad.java @@ -91,10 +91,7 @@ public class SolderPad extends AbstractTransparentComponent gerberDrawingObserver.startGerberOutput(gerberCopperLayer, GerberFunctions.CONNECTOR_PAD, false); gerberDrawingObserver.startGerberOutput(org.diylc.core.gerber.GerberLayer.SolderMaskBot, "Material", false); } - Composite oldComposite = g2d.getComposite(); - if (getAlpha() < MAX_ALPHA) { - g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1f * getAlpha() / MAX_ALPHA)); - } + Composite oldComposite = applyAlpha(g2d, componentState); if (type == Type.ROUND) { g2d.fill(new Ellipse2D.Double(point.getX() - diameter / 2, point.getY() - diameter / 2, diff --git a/diylc/diylc-library/src/main/java/org/diylc/components/connectivity/TraceCut.java b/diylc/diylc-library/src/main/java/org/diylc/components/connectivity/TraceCut.java index 53aa737d0..a020216b1 100644 --- a/diylc/diylc-library/src/main/java/org/diylc/components/connectivity/TraceCut.java +++ b/diylc/diylc-library/src/main/java/org/diylc/components/connectivity/TraceCut.java @@ -1,268 +1,265 @@ -/* - - DIY Layout Creator (DIYLC). - Copyright (c) 2009-2025 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; - -import java.awt.*; -import java.awt.geom.Point2D; -import java.awt.geom.Rectangle2D; - -import org.diylc.common.ObjectCache; -import org.diylc.common.OrientationHV; -import org.diylc.components.AbstractComponent; -import org.diylc.components.AbstractTransparentComponent; -import org.diylc.components.boards.AbstractBoard; -import org.diylc.components.boards.VeroBoard; -import org.diylc.components.transform.SimpleComponentTransformer; -import org.diylc.core.ComponentState; -import org.diylc.core.IDIYComponent; -import org.diylc.core.IDrawingObserver; -import org.diylc.core.ILayeredComponent; -import org.diylc.core.Project; -import org.diylc.core.VisibilityPolicy; -import org.diylc.core.annotations.BomPolicy; -import org.diylc.core.annotations.ComponentDescriptor; -import org.diylc.core.annotations.EditableProperty; -import org.diylc.core.measures.Size; -import org.diylc.core.measures.SizeUnit; -import org.diylc.utils.Constants; - -@ComponentDescriptor(name = "Trace Cut", category = "Connectivity", author = "Branislav Stojkovic", - description = "Designates the place where a trace on the vero board needs to be cut", instanceNamePrefix = "Cut", - zOrder = IDIYComponent.BOARD + 1, bomPolicy = BomPolicy.NEVER_SHOW, autoEdit = false, - transformer = SimpleComponentTransformer.class, enableCache = true) -public class TraceCut extends AbstractTransparentComponent implements ILayeredComponent { - - private static final long serialVersionUID = 1L; - - public static Size SIZE = new Size(0.08d, SizeUnit.in); - public static Size CUT_WIDTH = new Size(0.5d, SizeUnit.mm); - public static Color FILL_COLOR = Color.white; - public static Color BORDER_COLOR = Color.red; - public static Color SELECTION_COLOR = Color.red; - public static Size HOLE_SIZE = new Size(0.7d, SizeUnit.mm); - - private Size size = SIZE; - @SuppressWarnings("unused") - @Deprecated - private Color fillColor = FILL_COLOR; - @Deprecated - private Color borderColor = BORDER_COLOR; - private Color boardColor = AbstractBoard.PHENOLIC_COLOR; - private Boolean cutBetweenHoles = false; - private OrientationHV orientation = OrientationHV.VERTICAL; - private Size holeSpacing = VeroBoard.SPACING; - - protected Point2D.Double point = new Point2D.Double(0, 0); - - @Override - public void draw(Graphics2D g2d, ComponentState componentState, boolean outlineMode, Project project, - IDrawingObserver drawingObserver) { - if (checkPointsClipped(g2d.getClip())) { - return; - } - Composite oldComposite = g2d.getComposite(); - if (getAlpha() < MAX_ALPHA) { - g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1f * getAlpha() / MAX_ALPHA)); - } - g2d.setStroke(ObjectCache.getInstance().fetchZoomableStroke(1f)); - int size = getClosestOdd((int) this.size.convertToPixels()); - int cutWidth = getClosestOdd((int) CUT_WIDTH.convertToPixels()); - if (getCutBetweenHoles()) { - int holeSpacing = getClosestOdd(getHoleSpacing().convertToPixels()); - g2d.setColor(componentState == ComponentState.SELECTED || componentState == ComponentState.DRAGGING ? SELECTION_COLOR - : getBoardColor()); - drawingObserver.startTrackingContinuityArea(false); - if (getOrientation() == OrientationHV.VERTICAL) - g2d.fillRect((int)(point.getX() - holeSpacing / 2 - cutWidth / 2), (int)(point.getY() - size / 2 - 1), cutWidth, size + 2); - else - g2d.fillRect((int)(point.getX() - size / 2 - 1), (int)(point.getY() - holeSpacing / 2 - cutWidth / 2), size + 2, cutWidth); - drawingObserver.stopTrackingContinuityArea(); - } else { - g2d.setColor(componentState == ComponentState.SELECTED || componentState == ComponentState.DRAGGING ? SELECTION_COLOR - : getBoardColor()); - drawingObserver.startTrackingContinuityArea(false); - g2d.fillRoundRect((int)(point.getX() - size / 2), (int)(point.getY() - size / 2), size, size, size, size); - drawingObserver.stopTrackingContinuityArea(); - - g2d.setColor(Constants.CANVAS_COLOR); - int holeSize = getClosestOdd((int) HOLE_SIZE.convertToPixels()); - g2d.fillOval((int)(point.getX() - holeSize / 2), (int)(point.getY() - holeSize / 2), holeSize, holeSize); - g2d.setColor(getBoardColor().darker()); - g2d.drawOval((int)(point.getX() - holeSize / 2), (int)(point.getY() - holeSize / 2), holeSize, holeSize); - } - g2d.setComposite(oldComposite); - } - - @Override - public void drawIcon(Graphics2D g2d, int width, int height) { - int factor = 32 / width; - g2d.setColor(AbstractBoard.PHENOLIC_COLOR); - g2d.fillRect(0, 2 / factor, width - 1, height - 4 / factor); - g2d.setColor(AbstractBoard.BORDER_COLOR); - g2d.drawRect(0, 2 / factor, width - 1, height - 4 / factor); - g2d.setColor(COPPER_COLOR); - g2d.fillRect(1 / factor, width / 3, width - 2 / factor, getClosestOdd(width / 3) + 1); - g2d.setColor(COPPER_COLOR.darker()); - g2d.drawRect(1 / factor, width / 3, width - 2 / factor, getClosestOdd(width / 3) + 1); - - g2d.setColor(AbstractBoard.PHENOLIC_COLOR); - g2d.fillRoundRect(width / 3, width / 3, getClosestOdd(width / 3) + 2, getClosestOdd(width / 3) + 2, width / 3, - width / 3); - - g2d.setColor(COPPER_COLOR); - g2d.fillRect(1 / factor, 2 / factor, width - 2 / factor, 4 / factor); - g2d.fillRect(1 / factor, height - 6 / factor, width - 2 / factor, 4 / factor); - g2d.setColor(COPPER_COLOR.darker()); - g2d.drawRect(1 / factor, 2 / factor, width - 2 / factor, 4 / factor); - g2d.drawRect(1 / factor, height - 6 / factor, width - 2 / factor, 4 / factor); - - g2d.setColor(Constants.CANVAS_COLOR); - g2d.fillOval(width / 6 - 1, width / 2 - 1, getClosestOdd(3.0 / factor), getClosestOdd(3.0 / factor)); - g2d.fillOval(width / 2 - 1, width / 2 - 1, getClosestOdd(3.0 / factor), getClosestOdd(3.0 / factor)); - g2d.fillOval(5 * width / 6 - 1, width / 2 - 1, getClosestOdd(3.0 / factor), getClosestOdd(3.0 / factor)); - g2d.setColor(COPPER_COLOR.darker()); - g2d.drawOval(width / 6 - 1, width / 2 - 1, getClosestOdd(3.0 / factor), getClosestOdd(3.0 / factor)); - g2d.drawOval(width / 2 - 1, width / 2 - 1, getClosestOdd(3.0 / factor), getClosestOdd(3.0 / factor)); - g2d.drawOval(5 * width / 6 - 1, width / 2 - 1, getClosestOdd(3.0 / factor), getClosestOdd(3.0 / factor)); - } - - @Override - public int getControlPointCount() { - return 1; - } - - @Override - public Point2D getControlPoint(int index) { - return point; - } - - @Override - public boolean isControlPointSticky(int index) { - return false; - } - - @Override - public VisibilityPolicy getControlPointVisibilityPolicy(int index) { - return VisibilityPolicy.NEVER; - } - - @Override - public void setControlPoint(Point2D point, int index) { - this.point.setLocation(point); - } - - @Override - public Void getValue() { - return null; - } - - @Override - public void setValue(Void value) {} - - @EditableProperty - public Size getSize() { - return size; - } - - public void setSize(Size size) { - this.size = size; - } - - @Deprecated - public Color getBorderColor() { - return borderColor; - } - - @Deprecated - public void setBorderColor(Color borderColor) { - this.borderColor = borderColor; - } - - @EditableProperty(name = "Cut Between Holes") - public boolean getCutBetweenHoles() { - if (cutBetweenHoles == null) { - cutBetweenHoles = false; - } - return cutBetweenHoles; - } - - public void setCutBetweenHoles(boolean cutBetweenHoles) { - this.cutBetweenHoles = cutBetweenHoles; - } - - @EditableProperty(name = "Board") - public Color getBoardColor() { - if (boardColor == null) { - boardColor = AbstractBoard.PHENOLIC_COLOR; - } - return boardColor; - } - - public void setBoardColor(Color boardColor) { - this.boardColor = boardColor; - } - - @EditableProperty(name = "Hole Spacing") - public Size getHoleSpacing() { - if (holeSpacing == null) { - holeSpacing = VeroBoard.SPACING; - } - return holeSpacing; - } - - public void setHoleSpacing(Size holeSpacing) { - this.holeSpacing = holeSpacing; - } - - @EditableProperty(name = "Cut Orientation") - public OrientationHV getOrientation() { - if (orientation == null) - orientation = OrientationHV.VERTICAL; - return orientation; - } - - public void setOrientation(OrientationHV orientation) { - this.orientation = orientation; - } - - @Deprecated - @Override - public String getName() { - return super.getName(); - } - - @Override - public String getControlPointNodeName(int index) { - return null; - } - - @Override - public Rectangle2D getCachingBounds() { - double size = getSize().convertToPixels(); - return new Rectangle2D.Double(point.getX() - size, point.getY() - size, size * 2, size * 2); - } - - @Override - public int getLayerId() { - return 1; - } -} +/* + + DIY Layout Creator (DIYLC). + Copyright (c) 2009-2025 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; + +import java.awt.*; +import java.awt.geom.Point2D; +import java.awt.geom.Rectangle2D; + +import org.diylc.common.ObjectCache; +import org.diylc.common.OrientationHV; +import org.diylc.components.AbstractComponent; +import org.diylc.components.AbstractTransparentComponent; +import org.diylc.components.boards.AbstractBoard; +import org.diylc.components.boards.VeroBoard; +import org.diylc.components.transform.SimpleComponentTransformer; +import org.diylc.core.ComponentState; +import org.diylc.core.IDIYComponent; +import org.diylc.core.IDrawingObserver; +import org.diylc.core.ILayeredComponent; +import org.diylc.core.Project; +import org.diylc.core.VisibilityPolicy; +import org.diylc.core.annotations.BomPolicy; +import org.diylc.core.annotations.ComponentDescriptor; +import org.diylc.core.annotations.EditableProperty; +import org.diylc.core.measures.Size; +import org.diylc.core.measures.SizeUnit; +import org.diylc.utils.Constants; + +@ComponentDescriptor(name = "Trace Cut", category = "Connectivity", author = "Branislav Stojkovic", + description = "Designates the place where a trace on the vero board needs to be cut", instanceNamePrefix = "Cut", + zOrder = IDIYComponent.BOARD + 1, bomPolicy = BomPolicy.NEVER_SHOW, autoEdit = false, + transformer = SimpleComponentTransformer.class, enableCache = true) +public class TraceCut extends AbstractTransparentComponent implements ILayeredComponent { + + private static final long serialVersionUID = 1L; + + public static Size SIZE = new Size(0.08d, SizeUnit.in); + public static Size CUT_WIDTH = new Size(0.5d, SizeUnit.mm); + public static Color FILL_COLOR = Color.white; + public static Color BORDER_COLOR = Color.red; + public static Color SELECTION_COLOR = Color.red; + public static Size HOLE_SIZE = new Size(0.7d, SizeUnit.mm); + + private Size size = SIZE; + @SuppressWarnings("unused") + @Deprecated + private Color fillColor = FILL_COLOR; + @Deprecated + private Color borderColor = BORDER_COLOR; + private Color boardColor = AbstractBoard.PHENOLIC_COLOR; + private Boolean cutBetweenHoles = false; + private OrientationHV orientation = OrientationHV.VERTICAL; + private Size holeSpacing = VeroBoard.SPACING; + + protected Point2D.Double point = new Point2D.Double(0, 0); + + @Override + public void draw(Graphics2D g2d, ComponentState componentState, boolean outlineMode, Project project, + IDrawingObserver drawingObserver) { + if (checkPointsClipped(g2d.getClip())) { + return; + } + Composite oldComposite = applyAlpha(g2d, componentState); + g2d.setStroke(ObjectCache.getInstance().fetchZoomableStroke(1f)); + int size = getClosestOdd((int) this.size.convertToPixels()); + int cutWidth = getClosestOdd((int) CUT_WIDTH.convertToPixels()); + if (getCutBetweenHoles()) { + int holeSpacing = getClosestOdd(getHoleSpacing().convertToPixels()); + g2d.setColor(componentState == ComponentState.SELECTED || componentState == ComponentState.DRAGGING ? SELECTION_COLOR + : getBoardColor()); + drawingObserver.startTrackingContinuityArea(false); + if (getOrientation() == OrientationHV.VERTICAL) + g2d.fillRect((int)(point.getX() - holeSpacing / 2 - cutWidth / 2), (int)(point.getY() - size / 2 - 1), cutWidth, size + 2); + else + g2d.fillRect((int)(point.getX() - size / 2 - 1), (int)(point.getY() - holeSpacing / 2 - cutWidth / 2), size + 2, cutWidth); + drawingObserver.stopTrackingContinuityArea(); + } else { + g2d.setColor(componentState == ComponentState.SELECTED || componentState == ComponentState.DRAGGING ? SELECTION_COLOR + : getBoardColor()); + drawingObserver.startTrackingContinuityArea(false); + g2d.fillRoundRect((int)(point.getX() - size / 2), (int)(point.getY() - size / 2), size, size, size, size); + drawingObserver.stopTrackingContinuityArea(); + + g2d.setColor(Constants.CANVAS_COLOR); + int holeSize = getClosestOdd((int) HOLE_SIZE.convertToPixels()); + g2d.fillOval((int)(point.getX() - holeSize / 2), (int)(point.getY() - holeSize / 2), holeSize, holeSize); + g2d.setColor(getBoardColor().darker()); + g2d.drawOval((int)(point.getX() - holeSize / 2), (int)(point.getY() - holeSize / 2), holeSize, holeSize); + } + g2d.setComposite(oldComposite); + } + + @Override + public void drawIcon(Graphics2D g2d, int width, int height) { + int factor = 32 / width; + g2d.setColor(AbstractBoard.PHENOLIC_COLOR); + g2d.fillRect(0, 2 / factor, width - 1, height - 4 / factor); + g2d.setColor(AbstractBoard.BORDER_COLOR); + g2d.drawRect(0, 2 / factor, width - 1, height - 4 / factor); + g2d.setColor(COPPER_COLOR); + g2d.fillRect(1 / factor, width / 3, width - 2 / factor, getClosestOdd(width / 3) + 1); + g2d.setColor(COPPER_COLOR.darker()); + g2d.drawRect(1 / factor, width / 3, width - 2 / factor, getClosestOdd(width / 3) + 1); + + g2d.setColor(AbstractBoard.PHENOLIC_COLOR); + g2d.fillRoundRect(width / 3, width / 3, getClosestOdd(width / 3) + 2, getClosestOdd(width / 3) + 2, width / 3, + width / 3); + + g2d.setColor(COPPER_COLOR); + g2d.fillRect(1 / factor, 2 / factor, width - 2 / factor, 4 / factor); + g2d.fillRect(1 / factor, height - 6 / factor, width - 2 / factor, 4 / factor); + g2d.setColor(COPPER_COLOR.darker()); + g2d.drawRect(1 / factor, 2 / factor, width - 2 / factor, 4 / factor); + g2d.drawRect(1 / factor, height - 6 / factor, width - 2 / factor, 4 / factor); + + g2d.setColor(Constants.CANVAS_COLOR); + g2d.fillOval(width / 6 - 1, width / 2 - 1, getClosestOdd(3.0 / factor), getClosestOdd(3.0 / factor)); + g2d.fillOval(width / 2 - 1, width / 2 - 1, getClosestOdd(3.0 / factor), getClosestOdd(3.0 / factor)); + g2d.fillOval(5 * width / 6 - 1, width / 2 - 1, getClosestOdd(3.0 / factor), getClosestOdd(3.0 / factor)); + g2d.setColor(COPPER_COLOR.darker()); + g2d.drawOval(width / 6 - 1, width / 2 - 1, getClosestOdd(3.0 / factor), getClosestOdd(3.0 / factor)); + g2d.drawOval(width / 2 - 1, width / 2 - 1, getClosestOdd(3.0 / factor), getClosestOdd(3.0 / factor)); + g2d.drawOval(5 * width / 6 - 1, width / 2 - 1, getClosestOdd(3.0 / factor), getClosestOdd(3.0 / factor)); + } + + @Override + public int getControlPointCount() { + return 1; + } + + @Override + public Point2D getControlPoint(int index) { + return point; + } + + @Override + public boolean isControlPointSticky(int index) { + return false; + } + + @Override + public VisibilityPolicy getControlPointVisibilityPolicy(int index) { + return VisibilityPolicy.NEVER; + } + + @Override + public void setControlPoint(Point2D point, int index) { + this.point.setLocation(point); + } + + @Override + public Void getValue() { + return null; + } + + @Override + public void setValue(Void value) {} + + @EditableProperty + public Size getSize() { + return size; + } + + public void setSize(Size size) { + this.size = size; + } + + @Deprecated + public Color getBorderColor() { + return borderColor; + } + + @Deprecated + public void setBorderColor(Color borderColor) { + this.borderColor = borderColor; + } + + @EditableProperty(name = "Cut Between Holes") + public boolean getCutBetweenHoles() { + if (cutBetweenHoles == null) { + cutBetweenHoles = false; + } + return cutBetweenHoles; + } + + public void setCutBetweenHoles(boolean cutBetweenHoles) { + this.cutBetweenHoles = cutBetweenHoles; + } + + @EditableProperty(name = "Board") + public Color getBoardColor() { + if (boardColor == null) { + boardColor = AbstractBoard.PHENOLIC_COLOR; + } + return boardColor; + } + + public void setBoardColor(Color boardColor) { + this.boardColor = boardColor; + } + + @EditableProperty(name = "Hole Spacing") + public Size getHoleSpacing() { + if (holeSpacing == null) { + holeSpacing = VeroBoard.SPACING; + } + return holeSpacing; + } + + public void setHoleSpacing(Size holeSpacing) { + this.holeSpacing = holeSpacing; + } + + @EditableProperty(name = "Cut Orientation") + public OrientationHV getOrientation() { + if (orientation == null) + orientation = OrientationHV.VERTICAL; + return orientation; + } + + public void setOrientation(OrientationHV orientation) { + this.orientation = orientation; + } + + @Deprecated + @Override + public String getName() { + return super.getName(); + } + + @Override + public String getControlPointNodeName(int index) { + return null; + } + + @Override + public Rectangle2D getCachingBounds() { + double size = getSize().convertToPixels(); + return new Rectangle2D.Double(point.getX() - size, point.getY() - size, size * 2, size * 2); + } + + @Override + public int getLayerId() { + return 1; + } +} diff --git a/diylc/diylc-library/src/main/java/org/diylc/components/connectivity/Turret.java b/diylc/diylc-library/src/main/java/org/diylc/components/connectivity/Turret.java index a1849bbca..7ec2ea440 100644 --- a/diylc/diylc-library/src/main/java/org/diylc/components/connectivity/Turret.java +++ b/diylc/diylc-library/src/main/java/org/diylc/components/connectivity/Turret.java @@ -1,184 +1,181 @@ -/* - - DIY Layout Creator (DIYLC). - Copyright (c) 2009-2025 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; - -import java.awt.*; -import java.awt.geom.Point2D; -import java.awt.geom.Rectangle2D; - -import org.diylc.common.ObjectCache; -import org.diylc.components.AbstractComponent; -import org.diylc.components.AbstractTransparentComponent; -import org.diylc.components.transform.SimpleComponentTransformer; -import org.diylc.core.ComponentState; -import org.diylc.core.IDIYComponent; -import org.diylc.core.IDrawingObserver; -import org.diylc.core.Project; -import org.diylc.core.VisibilityPolicy; -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; -import org.diylc.utils.Constants; - -@ComponentDescriptor(name = "Turret Lug", category = "Connectivity", author = "Branislav Stojkovic", - description = "Turret terminal lug", instanceNamePrefix = "Turret", - zOrder = IDIYComponent.TRACE + 0.1, bomPolicy = BomPolicy.SHOW_ONLY_TYPE_NAME, autoEdit = false, - keywordPolicy = KeywordPolicy.SHOW_TYPE_NAME, transformer = SimpleComponentTransformer.class, - enableCache = true) -public class Turret extends AbstractTransparentComponent { - - private static final long serialVersionUID = 1L; - - public static Size SIZE = new Size(0.16d, SizeUnit.in); - public static Size HOLE_SIZE = new Size(0.0625d, SizeUnit.in); - public static Color COLOR = Color.decode("#E0C04C"); - - private Size size = SIZE; - private Size holeSize = HOLE_SIZE; - private Color color = COLOR; - private Point2D.Double point = new Point2D.Double(0, 0); - private String value = ""; - - @Override - public void draw(Graphics2D g2d, ComponentState componentState, boolean outlineMode, Project project, - IDrawingObserver drawingObserver) { - if (checkPointsClipped(g2d.getClip())) { - return; - } - Composite oldComposite = g2d.getComposite(); - if (getAlpha() < MAX_ALPHA) { - g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1f * getAlpha() / MAX_ALPHA)); - } - int diameter = getClosestOdd((int) size.convertToPixels()); - int holeDiameter = getClosestOdd((int) holeSize.convertToPixels()); - g2d.setColor(color); - g2d.setStroke(ObjectCache.getInstance().fetchZoomableStroke(1f)); - drawingObserver.startTrackingContinuityArea(true); - g2d.fillOval((int)(point.getX() - diameter / 2), (int)(point.getY() - diameter / 2), diameter, diameter); - drawingObserver.stopTrackingContinuityArea(); - g2d.setColor(componentState == ComponentState.SELECTED || componentState == ComponentState.DRAGGING ? SELECTION_COLOR - : color.darker()); - g2d.drawOval((int)(point.getX() - diameter / 2), (int)(point.getY() - diameter / 2), diameter, diameter); - g2d.setColor(Constants.CANVAS_COLOR); - g2d.fillOval((int)(point.getX() - holeDiameter / 2), (int)(point.getY() - holeDiameter / 2), holeDiameter, holeDiameter); - g2d.setColor(componentState == ComponentState.SELECTED || componentState == ComponentState.DRAGGING ? SELECTION_COLOR - : color.darker()); - g2d.drawOval((int)(point.getX() - holeDiameter / 2), (int)(point.getY() - holeDiameter / 2), holeDiameter, holeDiameter); - g2d.setComposite(oldComposite); - } - - @Override - public void drawIcon(Graphics2D g2d, int width, int height) { - int diameter = getClosestOdd(width / 2); - int holeDiameter = 5; - g2d.setColor(COLOR); - g2d.fillOval((width - diameter) / 2, (height - diameter) / 2, diameter, diameter); - g2d.setColor(COLOR.darker()); - g2d.drawOval((width - diameter) / 2, (height - diameter) / 2, diameter, diameter); - g2d.setColor(Constants.CANVAS_COLOR); - g2d.fillOval((width - holeDiameter) / 2, (height - holeDiameter) / 2, holeDiameter, holeDiameter); - g2d.setColor(COLOR.darker()); - g2d.drawOval((width - holeDiameter) / 2, (height - holeDiameter) / 2, holeDiameter, holeDiameter); - } - - @EditableProperty - public Size getSize() { - return size; - } - - public void setSize(Size size) { - this.size = size; - } - - @EditableProperty(name = "Hole Size") - public Size getHoleSize() { - return holeSize; - } - - public void setHoleSize(Size holeSize) { - this.holeSize = holeSize; - } - - @Override - public String getName() { - return super.getName(); - } - - @Override - public int getControlPointCount() { - return 1; - } - - @Override - public boolean isControlPointSticky(int index) { - return true; - } - - @Override - public VisibilityPolicy getControlPointVisibilityPolicy(int index) { - return VisibilityPolicy.NEVER; - } - - @Override - public Point2D getControlPoint(int index) { - return point; - } - - @Override - public void setControlPoint(Point2D point, int index) { - this.point.setLocation(point); - } - - @EditableProperty(name = "Color") - public Color getColor() { - return color; - } - - public void setColor(Color color) { - this.color = color; - } - - @Override - @EditableProperty - public String getValue() { - return value; - } - - @Override - public void setValue(String value) { - this.value = value; - } - - @Override - public String getControlPointNodeName(int index) { - return null; - } - - @Override - public Rectangle2D getCachingBounds() { - double size = getSize().convertToPixels(); - return new Rectangle2D.Double(point.getX() - size, point.getY() - size, size * 2, size * 2); - } -} +/* + + DIY Layout Creator (DIYLC). + Copyright (c) 2009-2025 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; + +import java.awt.*; +import java.awt.geom.Point2D; +import java.awt.geom.Rectangle2D; + +import org.diylc.common.ObjectCache; +import org.diylc.components.AbstractComponent; +import org.diylc.components.AbstractTransparentComponent; +import org.diylc.components.transform.SimpleComponentTransformer; +import org.diylc.core.ComponentState; +import org.diylc.core.IDIYComponent; +import org.diylc.core.IDrawingObserver; +import org.diylc.core.Project; +import org.diylc.core.VisibilityPolicy; +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; +import org.diylc.utils.Constants; + +@ComponentDescriptor(name = "Turret Lug", category = "Connectivity", author = "Branislav Stojkovic", + description = "Turret terminal lug", instanceNamePrefix = "Turret", + zOrder = IDIYComponent.TRACE + 0.1, bomPolicy = BomPolicy.SHOW_ONLY_TYPE_NAME, autoEdit = false, + keywordPolicy = KeywordPolicy.SHOW_TYPE_NAME, transformer = SimpleComponentTransformer.class, + enableCache = true) +public class Turret extends AbstractTransparentComponent { + + private static final long serialVersionUID = 1L; + + public static Size SIZE = new Size(0.16d, SizeUnit.in); + public static Size HOLE_SIZE = new Size(0.0625d, SizeUnit.in); + public static Color COLOR = Color.decode("#E0C04C"); + + private Size size = SIZE; + private Size holeSize = HOLE_SIZE; + private Color color = COLOR; + private Point2D.Double point = new Point2D.Double(0, 0); + private String value = ""; + + @Override + public void draw(Graphics2D g2d, ComponentState componentState, boolean outlineMode, Project project, + IDrawingObserver drawingObserver) { + if (checkPointsClipped(g2d.getClip())) { + return; + } + Composite oldComposite = applyAlpha(g2d, componentState); + int diameter = getClosestOdd((int) size.convertToPixels()); + int holeDiameter = getClosestOdd((int) holeSize.convertToPixels()); + g2d.setColor(color); + g2d.setStroke(ObjectCache.getInstance().fetchZoomableStroke(1f)); + drawingObserver.startTrackingContinuityArea(true); + g2d.fillOval((int)(point.getX() - diameter / 2), (int)(point.getY() - diameter / 2), diameter, diameter); + drawingObserver.stopTrackingContinuityArea(); + g2d.setColor(componentState == ComponentState.SELECTED || componentState == ComponentState.DRAGGING ? SELECTION_COLOR + : color.darker()); + g2d.drawOval((int)(point.getX() - diameter / 2), (int)(point.getY() - diameter / 2), diameter, diameter); + g2d.setColor(Constants.CANVAS_COLOR); + g2d.fillOval((int)(point.getX() - holeDiameter / 2), (int)(point.getY() - holeDiameter / 2), holeDiameter, holeDiameter); + g2d.setColor(componentState == ComponentState.SELECTED || componentState == ComponentState.DRAGGING ? SELECTION_COLOR + : color.darker()); + g2d.drawOval((int)(point.getX() - holeDiameter / 2), (int)(point.getY() - holeDiameter / 2), holeDiameter, holeDiameter); + g2d.setComposite(oldComposite); + } + + @Override + public void drawIcon(Graphics2D g2d, int width, int height) { + int diameter = getClosestOdd(width / 2); + int holeDiameter = 5; + g2d.setColor(COLOR); + g2d.fillOval((width - diameter) / 2, (height - diameter) / 2, diameter, diameter); + g2d.setColor(COLOR.darker()); + g2d.drawOval((width - diameter) / 2, (height - diameter) / 2, diameter, diameter); + g2d.setColor(Constants.CANVAS_COLOR); + g2d.fillOval((width - holeDiameter) / 2, (height - holeDiameter) / 2, holeDiameter, holeDiameter); + g2d.setColor(COLOR.darker()); + g2d.drawOval((width - holeDiameter) / 2, (height - holeDiameter) / 2, holeDiameter, holeDiameter); + } + + @EditableProperty + public Size getSize() { + return size; + } + + public void setSize(Size size) { + this.size = size; + } + + @EditableProperty(name = "Hole Size") + public Size getHoleSize() { + return holeSize; + } + + public void setHoleSize(Size holeSize) { + this.holeSize = holeSize; + } + + @Override + public String getName() { + return super.getName(); + } + + @Override + public int getControlPointCount() { + return 1; + } + + @Override + public boolean isControlPointSticky(int index) { + return true; + } + + @Override + public VisibilityPolicy getControlPointVisibilityPolicy(int index) { + return VisibilityPolicy.NEVER; + } + + @Override + public Point2D getControlPoint(int index) { + return point; + } + + @Override + public void setControlPoint(Point2D point, int index) { + this.point.setLocation(point); + } + + @EditableProperty(name = "Color") + public Color getColor() { + return color; + } + + public void setColor(Color color) { + this.color = color; + } + + @Override + @EditableProperty + public String getValue() { + return value; + } + + @Override + public void setValue(String value) { + this.value = value; + } + + @Override + public String getControlPointNodeName(int index) { + return null; + } + + @Override + public Rectangle2D getCachingBounds() { + double size = getSize().convertToPixels(); + return new Rectangle2D.Double(point.getX() - size, point.getY() - size, size * 2, size * 2); + } +} diff --git a/diylc/diylc-library/src/main/java/org/diylc/components/electromechanical/BatterySnap9V.java b/diylc/diylc-library/src/main/java/org/diylc/components/electromechanical/BatterySnap9V.java index b31f8f79d..a256a76c0 100644 --- a/diylc/diylc-library/src/main/java/org/diylc/components/electromechanical/BatterySnap9V.java +++ b/diylc/diylc-library/src/main/java/org/diylc/components/electromechanical/BatterySnap9V.java @@ -1,275 +1,272 @@ -/* - - DIY Layout Creator (DIYLC). - Copyright (c) 2009-2025 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.electromechanical; - -import java.awt.AlphaComposite; -import java.awt.Color; -import java.awt.Composite; -import java.awt.Graphics2D; -import java.awt.Polygon; -import java.awt.Shape; -import java.awt.geom.AffineTransform; -import java.awt.geom.Area; -import java.awt.geom.Ellipse2D; -import java.awt.geom.Point2D; -import java.awt.geom.Rectangle2D; -import org.diylc.appframework.miscutils.ConfigurationManager; - -import org.diylc.common.IPlugInPort; -import org.diylc.common.ObjectCache; -import org.diylc.common.Orientation; -import org.diylc.components.AbstractTransparentComponent; -import org.diylc.components.transform.BatterySnapTransformer; -import org.diylc.core.ComponentState; -import org.diylc.core.IDIYComponent; -import org.diylc.core.IDrawingObserver; -import org.diylc.core.Project; -import org.diylc.core.Theme; -import org.diylc.core.VisibilityPolicy; -import org.diylc.core.annotations.ComponentDescriptor; -import org.diylc.core.annotations.EditableProperty; -import org.diylc.core.measures.Size; -import org.diylc.core.measures.SizeUnit; -import org.diylc.utils.Constants; - -@ComponentDescriptor(name = "9V Battery Snap", category = "Electro-Mechanical", author = "Branislav Stojkovic", - description = "", zOrder = IDIYComponent.COMPONENT, instanceNamePrefix = "BTR", - transformer = BatterySnapTransformer.class) -public class BatterySnap9V extends AbstractTransparentComponent { - - private static final long serialVersionUID = 1L; - - private static Color BODY_COLOR = Color.darkGray; - private static Size WIDTH = new Size(0.5d, SizeUnit.in); - private static Size LENGTH = new Size(0.75d, SizeUnit.in); - private static Size TERMINAL_DIAMETER = new Size(0.3d, SizeUnit.in); - private static Size TERMINAL_SPACING = new Size(0.5d, SizeUnit.in); - private static Size TERMINAL_BORDER = new Size(0.7d, SizeUnit.mm); - - private String value = ""; - private Point2D controlPoint = new Point2D.Double(0, 0); - transient Shape[] body; - private Orientation orientation = Orientation.DEFAULT; - private Color color = BODY_COLOR; - - @Override - public void draw(Graphics2D g2d, ComponentState componentState, boolean outlineMode, Project project, - IDrawingObserver drawingObserver) { - Shape[] body = getBody(); - - g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(1)); - if (componentState != ComponentState.DRAGGING) { - 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 : color); - g2d.fill(body[0]); - g2d.setColor(outlineMode ? Constants.TRANSPARENT_COLOR : METAL_COLOR); - g2d.fill(body[1]); - g2d.fill(body[2]); - 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 - : color.brighter(); - } - - drawingObserver.stopTracking(); - - g2d.setColor(finalBorderColor); - g2d.draw(body[0]); - g2d.setColor(METAL_COLOR.darker()); - g2d.draw(body[1]); - g2d.setColor(METAL_COLOR.darker()); - g2d.draw(body[2]); - } - - @SuppressWarnings("incomplete-switch") - public Shape[] getBody() { - if (body == null) { - body = new Shape[3]; - - double x = controlPoint.getX(); - double y = controlPoint.getY(); - int width = (int) WIDTH.convertToPixels(); - int length = (int) LENGTH.convertToPixels(); - int totalLength = length + width / 2; - int terminalDiameter = (int) TERMINAL_DIAMETER.convertToPixels(); - int terminalSpacing = (int) TERMINAL_SPACING.convertToPixels(); - int terminalBorder = (int) TERMINAL_BORDER.convertToPixels(); - - Area mainArea = new Area(new Rectangle2D.Double(x, y - width / 2, length, width)); - mainArea.add(new Area(new Ellipse2D.Double(x + length - width / 2, y - width / 2, width, width))); - - body[0] = mainArea; - - Area terminalArea = - new Area(new Ellipse2D.Double(x + (totalLength - terminalSpacing) / 2 - terminalDiameter / 2, y - - terminalDiameter / 2, terminalDiameter, terminalDiameter)); - - double centerX = x + (totalLength + terminalSpacing) / 2; - int[] terminalX = new int[6]; - int[] terminalY = new int[6]; - - for (int i = 0; i < 6; i++) { - terminalX[i] = (int) (centerX + Math.cos(Math.PI / 3 * i) * terminalDiameter / 2); - terminalY[i] = (int) (y + Math.sin(Math.PI / 3 * i) * terminalDiameter / 2); - } - terminalArea.add(new Area(new Polygon(terminalX, terminalY, 6))); - - body[1] = terminalArea; - - terminalArea = - new Area(new Ellipse2D.Double( - x + (totalLength - terminalSpacing) / 2 - terminalDiameter / 2 + terminalBorder, y - terminalDiameter / 2 - + terminalBorder, terminalDiameter - 2 * terminalBorder, terminalDiameter - 2 * terminalBorder)); - - for (int i = 0; i < 6; i++) { - terminalX[i] = (int) (centerX + Math.cos(Math.PI / 3 * i) * (terminalDiameter / 2 + terminalBorder)); - terminalY[i] = (int) (y + Math.sin(Math.PI / 3 * i) * (terminalDiameter / 2 + terminalBorder)); - } - terminalArea.add(new Area(new Polygon(terminalX, terminalY, 6))); - - body[2] = terminalArea; - - // Rotate if needed - if (orientation != Orientation.DEFAULT) { - double theta = 0; - switch (orientation) { - case _90: - theta = Math.PI / 2; - break; - case _180: - theta = Math.PI; - break; - case _270: - theta = Math.PI * 3 / 2; - break; - } - AffineTransform rotation = AffineTransform.getRotateInstance(theta, x, y); - for (Shape shape : body) { - Area area = (Area) shape; - area.transform(rotation); - } - } - } - return body; - } - - @Override - public void drawIcon(Graphics2D g2d, int width, int height) { - g2d.setColor(BODY_COLOR); - g2d.fillOval(width / 4, width / 32, width / 2, width / 2); - g2d.setColor(BODY_COLOR.darker()); - g2d.drawOval(width / 4, width / 32, width / 2, width / 2); - g2d.setColor(BODY_COLOR); - g2d.fillRect(width / 4, width / 32 + width / 4, width / 2, width * 3 / 4 - 2 * width / 32); - g2d.setColor(BODY_COLOR.darker()); - g2d.drawRect(width / 4, width / 32 + width / 4, width / 2, width * 3 / 4 - 2 * width / 32); - g2d.setColor(METAL_COLOR); - g2d.fillOval(width / 4 + 3 * width / 32, width / 32 + 3 * width / 32, width / 2 - 6 * width / 32, width / 2 - 6 - * width / 32); - - int centerX = width / 2; - int centerY = height * 7 / 9; - int terminalDiameter = width / 2 - 4 * width / 32; - int[] terminalX = new int[6]; - int[] terminalY = new int[6]; - - for (int i = 0; i < 6; i++) { - terminalX[i] = (int) (centerX + Math.cos(Math.PI / 3 * i) * terminalDiameter / 2); - terminalY[i] = (int) (centerY + Math.sin(Math.PI / 3 * i) * terminalDiameter / 2); - } - g2d.fillPolygon(terminalX, terminalY, 6); - g2d.setColor(METAL_COLOR.darker()); - g2d.drawOval(width / 4 + 3 * width / 32, width / 32 + 3 * width / 32, width / 2 - 6 * width / 32, width / 2 - 6 - * width / 32); - g2d.drawPolygon(terminalX, terminalY, 6); - } - - @Override - public int getControlPointCount() { - return 1; - } - - @Override - public VisibilityPolicy getControlPointVisibilityPolicy(int index) { - return VisibilityPolicy.WHEN_SELECTED; - } - - @Override - public boolean isControlPointSticky(int index) { - return true; - } - - @Override - public Point2D getControlPoint(int index) { - return controlPoint; - } - - @Override - public void setControlPoint(Point2D point, int index) { - this.controlPoint.setLocation(point); - // Invalidate the body - body = null; - } - - @Override - public String getValue() { - return value; - } - - @Override - public void setValue(String value) { - this.value = value; - } - - @EditableProperty - public Orientation getOrientation() { - return orientation; - } - - public void setOrientation(Orientation orientation) { - this.orientation = orientation; - // Invalidate the body - body = null; - } - - @EditableProperty - public Color getColor() { - return color; - } - - public void setColor(Color color) { - this.color = color; - } -} +/* + + DIY Layout Creator (DIYLC). + Copyright (c) 2009-2025 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.electromechanical; + +import java.awt.AlphaComposite; +import java.awt.Color; +import java.awt.Composite; +import java.awt.Graphics2D; +import java.awt.Polygon; +import java.awt.Shape; +import java.awt.geom.AffineTransform; +import java.awt.geom.Area; +import java.awt.geom.Ellipse2D; +import java.awt.geom.Point2D; +import java.awt.geom.Rectangle2D; +import org.diylc.appframework.miscutils.ConfigurationManager; + +import org.diylc.common.IPlugInPort; +import org.diylc.common.ObjectCache; +import org.diylc.common.Orientation; +import org.diylc.components.AbstractTransparentComponent; +import org.diylc.components.transform.BatterySnapTransformer; +import org.diylc.core.ComponentState; +import org.diylc.core.IDIYComponent; +import org.diylc.core.IDrawingObserver; +import org.diylc.core.Project; +import org.diylc.core.Theme; +import org.diylc.core.VisibilityPolicy; +import org.diylc.core.annotations.ComponentDescriptor; +import org.diylc.core.annotations.EditableProperty; +import org.diylc.core.measures.Size; +import org.diylc.core.measures.SizeUnit; +import org.diylc.utils.Constants; + +@ComponentDescriptor(name = "9V Battery Snap", category = "Electro-Mechanical", author = "Branislav Stojkovic", + description = "", zOrder = IDIYComponent.COMPONENT, instanceNamePrefix = "BTR", + transformer = BatterySnapTransformer.class) +public class BatterySnap9V extends AbstractTransparentComponent { + + private static final long serialVersionUID = 1L; + + private static Color BODY_COLOR = Color.darkGray; + private static Size WIDTH = new Size(0.5d, SizeUnit.in); + private static Size LENGTH = new Size(0.75d, SizeUnit.in); + private static Size TERMINAL_DIAMETER = new Size(0.3d, SizeUnit.in); + private static Size TERMINAL_SPACING = new Size(0.5d, SizeUnit.in); + private static Size TERMINAL_BORDER = new Size(0.7d, SizeUnit.mm); + + private String value = ""; + private Point2D controlPoint = new Point2D.Double(0, 0); + transient Shape[] body; + private Orientation orientation = Orientation.DEFAULT; + private Color color = BODY_COLOR; + + @Override + public void draw(Graphics2D g2d, ComponentState componentState, boolean outlineMode, Project project, + IDrawingObserver drawingObserver) { + Shape[] body = getBody(); + + g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(1)); + if (componentState != ComponentState.DRAGGING) { + Composite oldComposite = applyAlpha(g2d, componentState); + g2d.setColor(outlineMode ? Constants.TRANSPARENT_COLOR : color); + g2d.fill(body[0]); + g2d.setColor(outlineMode ? Constants.TRANSPARENT_COLOR : METAL_COLOR); + g2d.fill(body[1]); + g2d.fill(body[2]); + 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 + : color.brighter(); + } + + drawingObserver.stopTracking(); + + g2d.setColor(finalBorderColor); + g2d.draw(body[0]); + g2d.setColor(METAL_COLOR.darker()); + g2d.draw(body[1]); + g2d.setColor(METAL_COLOR.darker()); + g2d.draw(body[2]); + } + + @SuppressWarnings("incomplete-switch") + public Shape[] getBody() { + if (body == null) { + body = new Shape[3]; + + double x = controlPoint.getX(); + double y = controlPoint.getY(); + int width = (int) WIDTH.convertToPixels(); + int length = (int) LENGTH.convertToPixels(); + int totalLength = length + width / 2; + int terminalDiameter = (int) TERMINAL_DIAMETER.convertToPixels(); + int terminalSpacing = (int) TERMINAL_SPACING.convertToPixels(); + int terminalBorder = (int) TERMINAL_BORDER.convertToPixels(); + + Area mainArea = new Area(new Rectangle2D.Double(x, y - width / 2, length, width)); + mainArea.add(new Area(new Ellipse2D.Double(x + length - width / 2, y - width / 2, width, width))); + + body[0] = mainArea; + + Area terminalArea = + new Area(new Ellipse2D.Double(x + (totalLength - terminalSpacing) / 2 - terminalDiameter / 2, y + - terminalDiameter / 2, terminalDiameter, terminalDiameter)); + + double centerX = x + (totalLength + terminalSpacing) / 2; + int[] terminalX = new int[6]; + int[] terminalY = new int[6]; + + for (int i = 0; i < 6; i++) { + terminalX[i] = (int) (centerX + Math.cos(Math.PI / 3 * i) * terminalDiameter / 2); + terminalY[i] = (int) (y + Math.sin(Math.PI / 3 * i) * terminalDiameter / 2); + } + terminalArea.add(new Area(new Polygon(terminalX, terminalY, 6))); + + body[1] = terminalArea; + + terminalArea = + new Area(new Ellipse2D.Double( + x + (totalLength - terminalSpacing) / 2 - terminalDiameter / 2 + terminalBorder, y - terminalDiameter / 2 + + terminalBorder, terminalDiameter - 2 * terminalBorder, terminalDiameter - 2 * terminalBorder)); + + for (int i = 0; i < 6; i++) { + terminalX[i] = (int) (centerX + Math.cos(Math.PI / 3 * i) * (terminalDiameter / 2 + terminalBorder)); + terminalY[i] = (int) (y + Math.sin(Math.PI / 3 * i) * (terminalDiameter / 2 + terminalBorder)); + } + terminalArea.add(new Area(new Polygon(terminalX, terminalY, 6))); + + body[2] = terminalArea; + + // Rotate if needed + if (orientation != Orientation.DEFAULT) { + double theta = 0; + switch (orientation) { + case _90: + theta = Math.PI / 2; + break; + case _180: + theta = Math.PI; + break; + case _270: + theta = Math.PI * 3 / 2; + break; + } + AffineTransform rotation = AffineTransform.getRotateInstance(theta, x, y); + for (Shape shape : body) { + Area area = (Area) shape; + area.transform(rotation); + } + } + } + return body; + } + + @Override + public void drawIcon(Graphics2D g2d, int width, int height) { + g2d.setColor(BODY_COLOR); + g2d.fillOval(width / 4, width / 32, width / 2, width / 2); + g2d.setColor(BODY_COLOR.darker()); + g2d.drawOval(width / 4, width / 32, width / 2, width / 2); + g2d.setColor(BODY_COLOR); + g2d.fillRect(width / 4, width / 32 + width / 4, width / 2, width * 3 / 4 - 2 * width / 32); + g2d.setColor(BODY_COLOR.darker()); + g2d.drawRect(width / 4, width / 32 + width / 4, width / 2, width * 3 / 4 - 2 * width / 32); + g2d.setColor(METAL_COLOR); + g2d.fillOval(width / 4 + 3 * width / 32, width / 32 + 3 * width / 32, width / 2 - 6 * width / 32, width / 2 - 6 + * width / 32); + + int centerX = width / 2; + int centerY = height * 7 / 9; + int terminalDiameter = width / 2 - 4 * width / 32; + int[] terminalX = new int[6]; + int[] terminalY = new int[6]; + + for (int i = 0; i < 6; i++) { + terminalX[i] = (int) (centerX + Math.cos(Math.PI / 3 * i) * terminalDiameter / 2); + terminalY[i] = (int) (centerY + Math.sin(Math.PI / 3 * i) * terminalDiameter / 2); + } + g2d.fillPolygon(terminalX, terminalY, 6); + g2d.setColor(METAL_COLOR.darker()); + g2d.drawOval(width / 4 + 3 * width / 32, width / 32 + 3 * width / 32, width / 2 - 6 * width / 32, width / 2 - 6 + * width / 32); + g2d.drawPolygon(terminalX, terminalY, 6); + } + + @Override + public int getControlPointCount() { + return 1; + } + + @Override + public VisibilityPolicy getControlPointVisibilityPolicy(int index) { + return VisibilityPolicy.WHEN_SELECTED; + } + + @Override + public boolean isControlPointSticky(int index) { + return true; + } + + @Override + public Point2D getControlPoint(int index) { + return controlPoint; + } + + @Override + public void setControlPoint(Point2D point, int index) { + this.controlPoint.setLocation(point); + // Invalidate the body + body = null; + } + + @Override + public String getValue() { + return value; + } + + @Override + public void setValue(String value) { + this.value = value; + } + + @EditableProperty + public Orientation getOrientation() { + return orientation; + } + + public void setOrientation(Orientation orientation) { + this.orientation = orientation; + // Invalidate the body + body = null; + } + + @EditableProperty + public Color getColor() { + return color; + } + + public void setColor(Color color) { + this.color = color; + } +} diff --git a/diylc/diylc-library/src/main/java/org/diylc/components/electromechanical/CliffJack1_4.java b/diylc/diylc-library/src/main/java/org/diylc/components/electromechanical/CliffJack1_4.java index 76ded26f6..c08defcba 100644 --- a/diylc/diylc-library/src/main/java/org/diylc/components/electromechanical/CliffJack1_4.java +++ b/diylc/diylc-library/src/main/java/org/diylc/components/electromechanical/CliffJack1_4.java @@ -1,358 +1,355 @@ -/* - - DIY Layout Creator (DIYLC). - Copyright (c) 2009-2025 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.electromechanical; - -import java.awt.AlphaComposite; -import java.awt.Color; -import java.awt.Composite; -import java.awt.Graphics2D; -import java.awt.RenderingHints; -import java.awt.Shape; -import java.awt.geom.AffineTransform; -import java.awt.geom.Area; -import java.awt.geom.Ellipse2D; -import java.awt.geom.Point2D; -import java.awt.geom.Rectangle2D; -import java.awt.geom.RoundRectangle2D; -import org.diylc.appframework.miscutils.ConfigurationManager; - -import org.diylc.awt.StringUtils; -import org.diylc.common.HorizontalAlignment; -import org.diylc.common.IPlugInPort; -import org.diylc.common.ObjectCache; -import org.diylc.common.Orientation; -import org.diylc.common.VerticalAlignment; -import org.diylc.components.AbstractMultiPartComponent; -import org.diylc.components.transform.CliffJackTransformer; -import org.diylc.core.ComponentState; -import org.diylc.core.IDIYComponent; -import org.diylc.core.IDrawingObserver; -import org.diylc.core.Project; -import org.diylc.core.Theme; -import org.diylc.core.VisibilityPolicy; -import org.diylc.core.annotations.ComponentDescriptor; -import org.diylc.core.annotations.EditableProperty; -import org.diylc.core.gerber.IGerberComponentSimple; -import org.diylc.core.measures.Size; -import org.diylc.core.measures.SizeUnit; -import org.diylc.utils.Constants; - -@ComponentDescriptor(name = "Cliff 1/4\" Jack", category = "Electro-Mechanical", author = "Branislav Stojkovic", - description = "Cliff-style closed panel mount 1/4\" phono jack", - zOrder = IDIYComponent.COMPONENT, instanceNamePrefix = "J", transformer = CliffJackTransformer.class, - enableCache = true) -public class CliffJack1_4 extends AbstractMultiPartComponent implements IGerberComponentSimple { - - private static final long serialVersionUID = 1L; - - private static Size SPACING = new Size(0.3d, SizeUnit.in); - private static Size PIN_WIDTH = new Size(0.1d, SizeUnit.in); - private static Size PIN_THICKNESS = new Size(0.02d, SizeUnit.in); - private static Color BODY_COLOR = Color.decode("#666666"); - private static Color NUT_COLOR = Color.decode("#999999"); - private static Color BORDER_COLOR = Color.black; - private static Color LABEL_COLOR = Color.white; - private static Size BODY_WIDTH = new Size(3 / 4d, SizeUnit.in); - private static Size BODY_LENGTH = new Size(0.9d, SizeUnit.in); - private static Size TAIL_LENGTH = new Size(0.1d, SizeUnit.in); - - private Point2D[] controlPoints = new Point2D[] {new Point2D.Double(0, 0)}; - private JackType type = JackType.MONO; - private Orientation orientation = Orientation.DEFAULT; - transient private Area[] body; - @SuppressWarnings("unused") - @Deprecated - private transient String value = ""; - - public CliffJack1_4() { - super(); - updateControlPoints(); - } - - private void updateControlPoints() { - // invalidate body shape - body = null; - double x = controlPoints[0].getX(); - double y = controlPoints[0].getY(); - int spacing = (int) SPACING.convertToPixels(); - controlPoints = new Point2D[type == JackType.STEREO ? 6 : 4]; - - controlPoints[0] = new Point2D.Double(x, y); - controlPoints[1] = new Point2D.Double(x, y + 2 * spacing); - controlPoints[2] = new Point2D.Double(x + 2 * spacing, y); - controlPoints[3] = new Point2D.Double(x + 2 * spacing, y + 2 * spacing); - if (type == JackType.STEREO) { - controlPoints[4] = new Point2D.Double(x + spacing, y); - controlPoints[5] = new Point2D.Double(x + spacing, y + 2 * spacing); - } - - // Apply rotation if necessary - double angle = getAngle(); - if (angle != 0) { - AffineTransform rotation = AffineTransform.getRotateInstance(angle, x, y); - for (int i = 1; i < controlPoints.length; i++) { - rotation.transform(controlPoints[i], controlPoints[i]); - } - } - } - - private double getAngle() { - // Apply rotation if necessary - double angle; - switch (orientation) { - case _90: - angle = Math.PI / 2; - break; - case _180: - angle = Math.PI; - break; - case _270: - angle = Math.PI * 3 / 2; - break; - default: - angle = 0; - } - - return angle; - } - - public Area[] getBody() { - if (body == null) { - body = new Area[5]; - - // Create body. - int bodyLength = (int) BODY_LENGTH.convertToPixels(); - int bodyWidth = (int) BODY_WIDTH.convertToPixels(); - double centerX = (controlPoints[0].getX() + controlPoints[3].getX()) / 2; - double centerY = (controlPoints[0].getY() + controlPoints[3].getY()) / 2; - body[0] = new Area(new Rectangle2D.Double(centerX - bodyLength / 2, centerY - bodyWidth / 2, bodyLength, bodyWidth)); - - int tailLength = (int) TAIL_LENGTH.convertToPixels(); - body[1] = new Area(new RoundRectangle2D.Double(centerX - bodyLength / 2 - tailLength, centerY - bodyWidth / 4, tailLength * 2, - bodyWidth / 2, tailLength, tailLength)); - Area tailArea = new Area(body[1]); - tailArea.subtract(new Area(body[0])); - body[1] = tailArea; - - body[2] = new Area(new Rectangle2D.Double(centerX + bodyLength / 2, centerY - bodyWidth / 4, tailLength, bodyWidth / 2)); - - body[3] = new Area(new Rectangle2D.Double(centerX + bodyLength / 2 + tailLength, centerY - bodyWidth / 4, tailLength, bodyWidth / 2)); - tailArea = new Area(body[3]); - int radius = bodyLength / 2 + tailLength * 2; - tailArea.intersect(new Area(new Ellipse2D.Double(centerX - radius, centerY - radius, radius * 2, radius * 2))); - body[3] = tailArea; - - // Apply rotation if necessary - double angle = getAngle(); - if (angle != 0) { - AffineTransform rotation = AffineTransform.getRotateInstance(angle, centerX, centerY); - for (int i = 0; i < body.length; i++) { - if (body[i] != null) { - Area area = new Area(body[i]); - area.transform(rotation); - body[i] = area; - } - } - } - - // Create pins. - Area pins = new Area(); - - int pinWidth = (int) PIN_WIDTH.convertToPixels(); - int pinThickness = (int) PIN_THICKNESS.convertToPixels(); - for (int i = 0; i < getControlPointCount(); i++) { - Point2D point = getControlPoint(i); - Rectangle2D pin; - if (orientation == Orientation.DEFAULT || orientation == Orientation._180) { - pin = new Rectangle2D.Double(point.getX() - pinWidth / 2, point.getY() - pinThickness / 2, pinWidth, pinThickness); - } else { - pin = new Rectangle2D.Double(point.getX() - pinThickness / 2, point.getY() - pinWidth / 2, pinThickness, pinWidth); - } - pins.add(new Area(pin)); - } - - body[4] = pins; - } - return body; - } - - @Override - public void draw(Graphics2D g2d, ComponentState componentState, boolean outlineMode, Project project, - IDrawingObserver drawingObserver) { - Shape[] body = getBody(); - - g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(1)); -// if (componentState != ComponentState.DRAGGING) { - 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 : BODY_COLOR); - for (int i = 0; i < body.length - 1; i++) { - // Nut is brighter colored. - if (i == body.length - 2) - g2d.setColor(outlineMode ? Constants.TRANSPARENT_COLOR : NUT_COLOR); - g2d.fill(body[i]); - } - g2d.setComposite(oldComposite); -// } - - Color finalBorderColor; - Theme theme = (Theme) ConfigurationManager.getInstance().readObject(IPlugInPort.THEME_KEY, Constants.DEFAULT_THEME); - if (outlineMode) { - finalBorderColor = theme.getOutlineColor(); - } else { - finalBorderColor = BORDER_COLOR; - } - - drawingObserver.stopTracking(); - - g2d.setColor(finalBorderColor); - for (int i = 0; i < body.length - 1; i++) { - g2d.draw(body[i]); - } - - // Pins are the last piece. - Shape pins = body[body.length - 1]; - if (!outlineMode) { - g2d.setColor(METAL_COLOR); - g2d.fill(pins); - } - g2d.setColor(outlineMode ? theme.getOutlineColor() : METAL_COLOR.darker()); - g2d.draw(pins); - - Color finalLabelColor; - if (outlineMode) { - finalLabelColor = - componentState == ComponentState.SELECTED || componentState == ComponentState.DRAGGING ? LABEL_COLOR_SELECTED - : theme.getOutlineColor(); - } else { - finalLabelColor = - componentState == ComponentState.SELECTED || componentState == ComponentState.DRAGGING ? LABEL_COLOR_SELECTED - : LABEL_COLOR; - } - g2d.setColor(finalLabelColor); - g2d.setFont(project.getFont()); - - // Override font size - if (getFontSizeOverride() != null) - g2d.setFont(g2d.getFont().deriveFont(1f * getFontSizeOverride())); - - double centerX = (controlPoints[0].getX() + controlPoints[3].getX()) / 2; - double centerY = (controlPoints[0].getY() + controlPoints[3].getY()) / 2; - StringUtils.drawCenteredText(g2d, name, centerX, centerY, HorizontalAlignment.CENTER, VerticalAlignment.CENTER); - - drawSelectionOutline(g2d, componentState, outlineMode, project, drawingObserver); - } - - @Override - public void drawIcon(Graphics2D g2d, int width, int height) { - int bodyWidth = getClosestOdd(width * 3 / 5); - int tailWidth = getClosestOdd(width * 3 / 9); - - g2d.setColor(BODY_COLOR); - g2d.fillRoundRect((width - tailWidth) / 2, height / 2, tailWidth, height / 2 - 2 * 32 / height, 4 * 32 / width, - 4 * 32 / width); - g2d.setColor(BORDER_COLOR); - g2d.drawRoundRect((width - tailWidth) / 2, height / 2, tailWidth, height / 2 - 2 * 32 / height, 4 * 32 / width, - 4 * 32 / width); - - g2d.setColor(NUT_COLOR); - g2d.fillRoundRect((width - tailWidth) / 2, 2 * 32 / height, tailWidth, height / 2, 4 * 32 / width, 4 * 32 / width); - g2d.setColor(BORDER_COLOR); - g2d.drawRoundRect((width - tailWidth) / 2, 2 * 32 / height, tailWidth, height / 2, 4 * 32 / width, 4 * 32 / width); - - g2d.setColor(BODY_COLOR); - g2d.fillRect((width - bodyWidth) / 2, height / 7 + 1, bodyWidth, height * 5 / 7); - g2d.setColor(BORDER_COLOR); - g2d.drawRect((width - bodyWidth) / 2, height / 7 + 1, bodyWidth, height * 5 / 7); - - g2d.setColor(METAL_COLOR); - int pinX1 = getClosestOdd((width - bodyWidth * 3 / 4) / 2); - int pinX2 = getClosestOdd((width + bodyWidth * 3 / 4) / 2) - 1; - g2d.drawLine(pinX1, width * 2 / 8, pinX1, width * 3 / 8); - g2d.drawLine(pinX1, width * 5 / 8, pinX1, width * 6 / 8); - g2d.drawLine(pinX2, width * 2 / 8, pinX2, width * 3 / 8); - g2d.drawLine(pinX2, width * 5 / 8, pinX2, width * 6 / 8); - - g2d.setColor(LABEL_COLOR); - g2d.setFont(LABEL_FONT.deriveFont(width / 3.5f)); - - RenderingHints rh = new RenderingHints( - RenderingHints.KEY_TEXT_ANTIALIASING, - RenderingHints.VALUE_TEXT_ANTIALIAS_OFF); - g2d.setRenderingHints(rh); - - StringUtils.drawCenteredText(g2d, "6.3", width / 2 - 1, height / 2, HorizontalAlignment.CENTER, VerticalAlignment.CENTER); - } - - @Override - public int getControlPointCount() { - return controlPoints.length; - } - - @Override - public Point2D getControlPoint(int index) { - return controlPoints[index]; - } - - @Override - public void setControlPoint(Point2D point, int index) { - controlPoints[index].setLocation(point); - body = null; - } - - @Override - public boolean isControlPointSticky(int index) { - return true; - } - - @Override - public VisibilityPolicy getControlPointVisibilityPolicy(int index) { - return VisibilityPolicy.NEVER; - } - - @EditableProperty(name = "Type") - public JackType getValue() { - return type; - } - - public void setValue(JackType type) { - this.type = type; - updateControlPoints(); - } - - @EditableProperty - public Orientation getOrientation() { - return orientation; - } - - public void setOrientation(Orientation orientation) { - this.orientation = orientation; - updateControlPoints(); - } - - @Override - public boolean canPointMoveFreely(int pointIndex) { - return false; - } -} +/* + + DIY Layout Creator (DIYLC). + Copyright (c) 2009-2025 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.electromechanical; + +import java.awt.AlphaComposite; +import java.awt.Color; +import java.awt.Composite; +import java.awt.Graphics2D; +import java.awt.RenderingHints; +import java.awt.Shape; +import java.awt.geom.AffineTransform; +import java.awt.geom.Area; +import java.awt.geom.Ellipse2D; +import java.awt.geom.Point2D; +import java.awt.geom.Rectangle2D; +import java.awt.geom.RoundRectangle2D; +import org.diylc.appframework.miscutils.ConfigurationManager; + +import org.diylc.awt.StringUtils; +import org.diylc.common.HorizontalAlignment; +import org.diylc.common.IPlugInPort; +import org.diylc.common.ObjectCache; +import org.diylc.common.Orientation; +import org.diylc.common.VerticalAlignment; +import org.diylc.components.AbstractMultiPartComponent; +import org.diylc.components.transform.CliffJackTransformer; +import org.diylc.core.ComponentState; +import org.diylc.core.IDIYComponent; +import org.diylc.core.IDrawingObserver; +import org.diylc.core.Project; +import org.diylc.core.Theme; +import org.diylc.core.VisibilityPolicy; +import org.diylc.core.annotations.ComponentDescriptor; +import org.diylc.core.annotations.EditableProperty; +import org.diylc.core.gerber.IGerberComponentSimple; +import org.diylc.core.measures.Size; +import org.diylc.core.measures.SizeUnit; +import org.diylc.utils.Constants; + +@ComponentDescriptor(name = "Cliff 1/4\" Jack", category = "Electro-Mechanical", author = "Branislav Stojkovic", + description = "Cliff-style closed panel mount 1/4\" phono jack", + zOrder = IDIYComponent.COMPONENT, instanceNamePrefix = "J", transformer = CliffJackTransformer.class, + enableCache = true) +public class CliffJack1_4 extends AbstractMultiPartComponent implements IGerberComponentSimple { + + private static final long serialVersionUID = 1L; + + private static Size SPACING = new Size(0.3d, SizeUnit.in); + private static Size PIN_WIDTH = new Size(0.1d, SizeUnit.in); + private static Size PIN_THICKNESS = new Size(0.02d, SizeUnit.in); + private static Color BODY_COLOR = Color.decode("#666666"); + private static Color NUT_COLOR = Color.decode("#999999"); + private static Color BORDER_COLOR = Color.black; + private static Color LABEL_COLOR = Color.white; + private static Size BODY_WIDTH = new Size(3 / 4d, SizeUnit.in); + private static Size BODY_LENGTH = new Size(0.9d, SizeUnit.in); + private static Size TAIL_LENGTH = new Size(0.1d, SizeUnit.in); + + private Point2D[] controlPoints = new Point2D[] {new Point2D.Double(0, 0)}; + private JackType type = JackType.MONO; + private Orientation orientation = Orientation.DEFAULT; + transient private Area[] body; + @SuppressWarnings("unused") + @Deprecated + private transient String value = ""; + + public CliffJack1_4() { + super(); + updateControlPoints(); + } + + private void updateControlPoints() { + // invalidate body shape + body = null; + double x = controlPoints[0].getX(); + double y = controlPoints[0].getY(); + int spacing = (int) SPACING.convertToPixels(); + controlPoints = new Point2D[type == JackType.STEREO ? 6 : 4]; + + controlPoints[0] = new Point2D.Double(x, y); + controlPoints[1] = new Point2D.Double(x, y + 2 * spacing); + controlPoints[2] = new Point2D.Double(x + 2 * spacing, y); + controlPoints[3] = new Point2D.Double(x + 2 * spacing, y + 2 * spacing); + if (type == JackType.STEREO) { + controlPoints[4] = new Point2D.Double(x + spacing, y); + controlPoints[5] = new Point2D.Double(x + spacing, y + 2 * spacing); + } + + // Apply rotation if necessary + double angle = getAngle(); + if (angle != 0) { + AffineTransform rotation = AffineTransform.getRotateInstance(angle, x, y); + for (int i = 1; i < controlPoints.length; i++) { + rotation.transform(controlPoints[i], controlPoints[i]); + } + } + } + + private double getAngle() { + // Apply rotation if necessary + double angle; + switch (orientation) { + case _90: + angle = Math.PI / 2; + break; + case _180: + angle = Math.PI; + break; + case _270: + angle = Math.PI * 3 / 2; + break; + default: + angle = 0; + } + + return angle; + } + + public Area[] getBody() { + if (body == null) { + body = new Area[5]; + + // Create body. + int bodyLength = (int) BODY_LENGTH.convertToPixels(); + int bodyWidth = (int) BODY_WIDTH.convertToPixels(); + double centerX = (controlPoints[0].getX() + controlPoints[3].getX()) / 2; + double centerY = (controlPoints[0].getY() + controlPoints[3].getY()) / 2; + body[0] = new Area(new Rectangle2D.Double(centerX - bodyLength / 2, centerY - bodyWidth / 2, bodyLength, bodyWidth)); + + int tailLength = (int) TAIL_LENGTH.convertToPixels(); + body[1] = new Area(new RoundRectangle2D.Double(centerX - bodyLength / 2 - tailLength, centerY - bodyWidth / 4, tailLength * 2, + bodyWidth / 2, tailLength, tailLength)); + Area tailArea = new Area(body[1]); + tailArea.subtract(new Area(body[0])); + body[1] = tailArea; + + body[2] = new Area(new Rectangle2D.Double(centerX + bodyLength / 2, centerY - bodyWidth / 4, tailLength, bodyWidth / 2)); + + body[3] = new Area(new Rectangle2D.Double(centerX + bodyLength / 2 + tailLength, centerY - bodyWidth / 4, tailLength, bodyWidth / 2)); + tailArea = new Area(body[3]); + int radius = bodyLength / 2 + tailLength * 2; + tailArea.intersect(new Area(new Ellipse2D.Double(centerX - radius, centerY - radius, radius * 2, radius * 2))); + body[3] = tailArea; + + // Apply rotation if necessary + double angle = getAngle(); + if (angle != 0) { + AffineTransform rotation = AffineTransform.getRotateInstance(angle, centerX, centerY); + for (int i = 0; i < body.length; i++) { + if (body[i] != null) { + Area area = new Area(body[i]); + area.transform(rotation); + body[i] = area; + } + } + } + + // Create pins. + Area pins = new Area(); + + int pinWidth = (int) PIN_WIDTH.convertToPixels(); + int pinThickness = (int) PIN_THICKNESS.convertToPixels(); + for (int i = 0; i < getControlPointCount(); i++) { + Point2D point = getControlPoint(i); + Rectangle2D pin; + if (orientation == Orientation.DEFAULT || orientation == Orientation._180) { + pin = new Rectangle2D.Double(point.getX() - pinWidth / 2, point.getY() - pinThickness / 2, pinWidth, pinThickness); + } else { + pin = new Rectangle2D.Double(point.getX() - pinThickness / 2, point.getY() - pinWidth / 2, pinThickness, pinWidth); + } + pins.add(new Area(pin)); + } + + body[4] = pins; + } + return body; + } + + @Override + public void draw(Graphics2D g2d, ComponentState componentState, boolean outlineMode, Project project, + IDrawingObserver drawingObserver) { + Shape[] body = getBody(); + + g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(1)); +// if (componentState != ComponentState.DRAGGING) { + Composite oldComposite = applyAlpha(g2d, componentState); + g2d.setColor(outlineMode ? Constants.TRANSPARENT_COLOR : BODY_COLOR); + for (int i = 0; i < body.length - 1; i++) { + // Nut is brighter colored. + if (i == body.length - 2) + g2d.setColor(outlineMode ? Constants.TRANSPARENT_COLOR : NUT_COLOR); + g2d.fill(body[i]); + } + g2d.setComposite(oldComposite); +// } + + Color finalBorderColor; + Theme theme = (Theme) ConfigurationManager.getInstance().readObject(IPlugInPort.THEME_KEY, Constants.DEFAULT_THEME); + if (outlineMode) { + finalBorderColor = theme.getOutlineColor(); + } else { + finalBorderColor = BORDER_COLOR; + } + + drawingObserver.stopTracking(); + + g2d.setColor(finalBorderColor); + for (int i = 0; i < body.length - 1; i++) { + g2d.draw(body[i]); + } + + // Pins are the last piece. + Shape pins = body[body.length - 1]; + if (!outlineMode) { + g2d.setColor(METAL_COLOR); + g2d.fill(pins); + } + g2d.setColor(outlineMode ? theme.getOutlineColor() : METAL_COLOR.darker()); + g2d.draw(pins); + + Color finalLabelColor; + if (outlineMode) { + finalLabelColor = + componentState == ComponentState.SELECTED || componentState == ComponentState.DRAGGING ? LABEL_COLOR_SELECTED + : theme.getOutlineColor(); + } else { + finalLabelColor = + componentState == ComponentState.SELECTED || componentState == ComponentState.DRAGGING ? LABEL_COLOR_SELECTED + : LABEL_COLOR; + } + g2d.setColor(finalLabelColor); + g2d.setFont(project.getFont()); + + // Override font size + if (getFontSizeOverride() != null) + g2d.setFont(g2d.getFont().deriveFont(1f * getFontSizeOverride())); + + double centerX = (controlPoints[0].getX() + controlPoints[3].getX()) / 2; + double centerY = (controlPoints[0].getY() + controlPoints[3].getY()) / 2; + StringUtils.drawCenteredText(g2d, name, centerX, centerY, HorizontalAlignment.CENTER, VerticalAlignment.CENTER); + + drawSelectionOutline(g2d, componentState, outlineMode, project, drawingObserver); + } + + @Override + public void drawIcon(Graphics2D g2d, int width, int height) { + int bodyWidth = getClosestOdd(width * 3 / 5); + int tailWidth = getClosestOdd(width * 3 / 9); + + g2d.setColor(BODY_COLOR); + g2d.fillRoundRect((width - tailWidth) / 2, height / 2, tailWidth, height / 2 - 2 * 32 / height, 4 * 32 / width, + 4 * 32 / width); + g2d.setColor(BORDER_COLOR); + g2d.drawRoundRect((width - tailWidth) / 2, height / 2, tailWidth, height / 2 - 2 * 32 / height, 4 * 32 / width, + 4 * 32 / width); + + g2d.setColor(NUT_COLOR); + g2d.fillRoundRect((width - tailWidth) / 2, 2 * 32 / height, tailWidth, height / 2, 4 * 32 / width, 4 * 32 / width); + g2d.setColor(BORDER_COLOR); + g2d.drawRoundRect((width - tailWidth) / 2, 2 * 32 / height, tailWidth, height / 2, 4 * 32 / width, 4 * 32 / width); + + g2d.setColor(BODY_COLOR); + g2d.fillRect((width - bodyWidth) / 2, height / 7 + 1, bodyWidth, height * 5 / 7); + g2d.setColor(BORDER_COLOR); + g2d.drawRect((width - bodyWidth) / 2, height / 7 + 1, bodyWidth, height * 5 / 7); + + g2d.setColor(METAL_COLOR); + int pinX1 = getClosestOdd((width - bodyWidth * 3 / 4) / 2); + int pinX2 = getClosestOdd((width + bodyWidth * 3 / 4) / 2) - 1; + g2d.drawLine(pinX1, width * 2 / 8, pinX1, width * 3 / 8); + g2d.drawLine(pinX1, width * 5 / 8, pinX1, width * 6 / 8); + g2d.drawLine(pinX2, width * 2 / 8, pinX2, width * 3 / 8); + g2d.drawLine(pinX2, width * 5 / 8, pinX2, width * 6 / 8); + + g2d.setColor(LABEL_COLOR); + g2d.setFont(LABEL_FONT.deriveFont(width / 3.5f)); + + RenderingHints rh = new RenderingHints( + RenderingHints.KEY_TEXT_ANTIALIASING, + RenderingHints.VALUE_TEXT_ANTIALIAS_OFF); + g2d.setRenderingHints(rh); + + StringUtils.drawCenteredText(g2d, "6.3", width / 2 - 1, height / 2, HorizontalAlignment.CENTER, VerticalAlignment.CENTER); + } + + @Override + public int getControlPointCount() { + return controlPoints.length; + } + + @Override + public Point2D getControlPoint(int index) { + return controlPoints[index]; + } + + @Override + public void setControlPoint(Point2D point, int index) { + controlPoints[index].setLocation(point); + body = null; + } + + @Override + public boolean isControlPointSticky(int index) { + return true; + } + + @Override + public VisibilityPolicy getControlPointVisibilityPolicy(int index) { + return VisibilityPolicy.NEVER; + } + + @EditableProperty(name = "Type") + public JackType getValue() { + return type; + } + + public void setValue(JackType type) { + this.type = type; + updateControlPoints(); + } + + @EditableProperty + public Orientation getOrientation() { + return orientation; + } + + public void setOrientation(Orientation orientation) { + this.orientation = orientation; + updateControlPoints(); + } + + @Override + public boolean canPointMoveFreely(int pointIndex) { + return false; + } +} diff --git a/diylc/diylc-library/src/main/java/org/diylc/components/electromechanical/CliffJack1_8.java b/diylc/diylc-library/src/main/java/org/diylc/components/electromechanical/CliffJack1_8.java index 5939b15c7..3c204c7d4 100644 --- a/diylc/diylc-library/src/main/java/org/diylc/components/electromechanical/CliffJack1_8.java +++ b/diylc/diylc-library/src/main/java/org/diylc/components/electromechanical/CliffJack1_8.java @@ -216,10 +216,7 @@ public class CliffJack1_8 extends AbstractMultiPartComponent implement g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(1)); // if (componentState != ComponentState.DRAGGING) { - Composite oldComposite = g2d.getComposite(); - if (alpha < MAX_ALPHA) { - g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1f * alpha / MAX_ALPHA)); - } + Composite oldComposite = applyAlpha(g2d, componentState); g2d.setColor(outlineMode ? Constants.TRANSPARENT_COLOR : BODY_COLOR); for (int i = 0; i < 2; i++) { g2d.fill(body[i]); diff --git a/diylc/diylc-library/src/main/java/org/diylc/components/electromechanical/ClosedJack1_4.java b/diylc/diylc-library/src/main/java/org/diylc/components/electromechanical/ClosedJack1_4.java index 1dd2c9dc0..1a61147a8 100644 --- a/diylc/diylc-library/src/main/java/org/diylc/components/electromechanical/ClosedJack1_4.java +++ b/diylc/diylc-library/src/main/java/org/diylc/components/electromechanical/ClosedJack1_4.java @@ -1,384 +1,381 @@ -/* - - DIY Layout Creator (DIYLC). - Copyright (c) 2009-2025 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.electromechanical; - -import java.awt.AlphaComposite; -import java.awt.Color; -import java.awt.Composite; -import java.awt.Graphics2D; -import java.awt.Rectangle; -import java.awt.RenderingHints; -import java.awt.Shape; -import java.awt.geom.AffineTransform; -import java.awt.geom.Area; -import java.awt.geom.Ellipse2D; -import java.awt.geom.GeneralPath; -import java.awt.geom.Point2D; -import java.awt.geom.Rectangle2D; -import org.diylc.appframework.miscutils.ConfigurationManager; - -import org.diylc.awt.StringUtils; -import org.diylc.common.HorizontalAlignment; -import org.diylc.common.IPlugInPort; -import org.diylc.common.ObjectCache; -import org.diylc.common.Orientation; -import org.diylc.common.VerticalAlignment; -import org.diylc.components.AbstractMultiPartComponent; -import org.diylc.components.transform.ClosedJackTransformer; -import org.diylc.core.ComponentState; -import org.diylc.core.IDIYComponent; -import org.diylc.core.IDrawingObserver; -import org.diylc.core.Project; -import org.diylc.core.Theme; -import org.diylc.core.VisibilityPolicy; -import org.diylc.core.annotations.ComponentDescriptor; -import org.diylc.core.annotations.EditableProperty; -import org.diylc.core.gerber.IGerberComponentSimple; -import org.diylc.core.measures.Size; -import org.diylc.core.measures.SizeUnit; -import org.diylc.utils.Constants; - -@ComponentDescriptor(name = "Closed 1/4\" Jack", category = "Electro-Mechanical", author = "Branislav Stojkovic", - description = "Enclosed panel mount 1/4\" phono jack", zOrder = IDIYComponent.COMPONENT, - instanceNamePrefix = "J", transformer = ClosedJackTransformer.class, enableCache = true) -public class ClosedJack1_4 extends AbstractMultiPartComponent implements IGerberComponentSimple { - - private static final long serialVersionUID = 1L; - - private static Size SPACING = new Size(0.1d, SizeUnit.in); - private static Size LUG_WIDTH = new Size(0.1d, SizeUnit.in); - private static Size LUG_LENGTH = new Size(0.12d, SizeUnit.in); - private static Size LUG_HOLE_SIZE = new Size(1d, SizeUnit.mm); - private static Color BODY_COLOR = Color.decode("#666666"); - private static Color SHAFT_COLOR = Color.decode("#AAAAAA"); - private static Size SHAFT_LENGTH = new Size(0.25d, SizeUnit.in); - private static Size SHAFT_WIDTH = new Size(3d / 8, SizeUnit.in); - private static Color BORDER_COLOR = Color.black; - private static Color LABEL_COLOR = Color.white; - private static Size BODY_WIDTH = new Size(0.65d, SizeUnit.in); - private static Size BODY_LENGTH = new Size(0.8d, SizeUnit.in); - - private Point2D[] controlPoints = new Point2D[] {new Point2D.Double(0, 0)}; - private JackType type = JackType.MONO; - private Orientation orientation = Orientation.DEFAULT; - transient private Shape[] body; - @SuppressWarnings("unused") - @Deprecated - private transient String value = ""; - - public ClosedJack1_4() { - super(); - updateControlPoints(); - } - - private void updateControlPoints() { - // invalidate body shape - body = null; - double x = controlPoints[0].getX(); - double y = controlPoints[0].getY(); - int spacing = (int) SPACING.convertToPixels(); - int bodyLength = (int) BODY_LENGTH.convertToPixels(); - controlPoints = new Point2D[type == JackType.STEREO ? 3 : 2]; - - controlPoints[0] = new Point2D.Double(x, y); - controlPoints[1] = new Point2D.Double(x + bodyLength, y); - if (type == JackType.STEREO) { - controlPoints[2] = new Point2D.Double(x, y + 2 * spacing); - } - - // Apply rotation if necessary - double angle = getAngle(); - if (angle != 0) { - AffineTransform rotation = AffineTransform.getRotateInstance(angle, x, y); - for (int i = 1; i < controlPoints.length; i++) { - rotation.transform(controlPoints[i], controlPoints[i]); - } - } - } - - private double getAngle() { - // Apply rotation if necessary - double angle; - switch (orientation) { - case _90: - angle = Math.PI / 2; - break; - case _180: - angle = Math.PI; - break; - case _270: - angle = Math.PI * 3 / 2; - break; - default: - angle = 0; - } - - return angle; - } - - public Shape[] getBody() { - if (body == null) { - body = new Shape[5]; - - // Create body. - double x = controlPoints[0].getX(); - double y = controlPoints[0].getY(); - int lugWidth = (int) LUG_WIDTH.convertToPixels(); - int lugLength = (int) LUG_LENGTH.convertToPixels(); - int lugHoleSize = (int) LUG_HOLE_SIZE.convertToPixels(); - int bodyLength = (int) BODY_LENGTH.convertToPixels(); - int bodyWidth = (int) BODY_WIDTH.convertToPixels(); - body[0] = new Area(new Rectangle2D.Double(x + lugLength, y - bodyWidth / 2, bodyLength, bodyWidth)); - - int shaftLength = (int) SHAFT_LENGTH.convertToPixels(); - int shaftWidth = (int) SHAFT_WIDTH.convertToPixels(); - Area shaft = new Area(new Rectangle2D.Double(x + lugLength + bodyLength, y - shaftWidth / 2, shaftLength, shaftWidth)); - body[1] = shaft; - - double angle = getAngle(); - AffineTransform rotation = null; - if (angle != 0) { - rotation = AffineTransform.getRotateInstance(angle, x, y); - } - - GeneralPath path = new GeneralPath(); - int step = 4; - for (double i = x + lugLength + bodyLength + step; i <= x + lugLength + bodyLength + shaftLength; i += step) { - Point2D p = new Point2D.Double(i, y - shaftWidth / 2 + 1); - if (rotation != null) { - rotation.transform(p, p); - } - path.moveTo(p.getX(), p.getY()); - p = new Point2D.Double(i - step, y + shaftWidth / 2 - 1); - if (rotation != null) { - rotation.transform(p, p); - } - path.lineTo(p.getX(), p.getY()); - } -// Area pathArea = new Area(path); -// pathArea.intersect(shaft); - body[2] = path; - - // Create lugs. - Area lugs = new Area(); - - int spacing = (int) SPACING.convertToPixels(); - Point2D[] untransformedControlPoints = new Point2D[type == JackType.STEREO ? 3 : 2]; - - untransformedControlPoints[0] = new Point2D.Double(x, y); - untransformedControlPoints[1] = new Point2D.Double(x + bodyLength, y); - if (type == JackType.STEREO) { - untransformedControlPoints[2] = new Point2D.Double(x, y + 2 * spacing); - } - - for (int i = 0; i < untransformedControlPoints.length; i++) { - Point2D point = untransformedControlPoints[i]; - Area lug = new Area(new Ellipse2D.Double(point.getX() - lugWidth / 2, point.getY() - lugWidth / 2, lugWidth, lugWidth)); - lug.add(new Area(new Rectangle2D.Double(point.getX(), point.getY() - lugWidth / 2, lugLength, lugWidth))); - lug.subtract(new Area(new Ellipse2D.Double(point.getX() - lugHoleSize / 2, point.getY() - lugHoleSize / 2, lugHoleSize, - lugHoleSize))); - lugs.add(lug); - } - - body[3] = lugs; - - // Rotate everything that's of Area type, e.g. everything but lines. - if (rotation != null) { - for (Shape shape : body) { - if (shape instanceof Area) { - Area area = (Area) shape; - area.transform(rotation); - } - } - } - } - return body; - } - - @Override - public void draw(Graphics2D g2d, ComponentState componentState, boolean outlineMode, Project project, - IDrawingObserver drawingObserver) { - Shape[] body = getBody(); - - // Rectangle bounds = body.getBounds(); - - g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(1)); -// if (componentState != ComponentState.DRAGGING) { - 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 : BODY_COLOR); - g2d.fill(body[0]); - g2d.setColor(outlineMode ? Constants.TRANSPARENT_COLOR : SHAFT_COLOR); - g2d.fill(body[1]); - g2d.setColor(outlineMode ? Constants.TRANSPARENT_COLOR : METAL_COLOR); - g2d.fill(body[3]); - g2d.setComposite(oldComposite); -// } - - drawingObserver.stopTracking(); - - Color finalBorderColor; - if (outlineMode) { - Theme theme = - (Theme) ConfigurationManager.getInstance().readObject(IPlugInPort.THEME_KEY, Constants.DEFAULT_THEME); - finalBorderColor = theme.getOutlineColor(); - } else { - finalBorderColor = BORDER_COLOR; - } - - g2d.setColor(finalBorderColor); - g2d.draw(body[0]); - g2d.draw(body[1]); - if (!outlineMode) { - g2d.setColor(SHAFT_COLOR.darker()); -// g2d.fill(body[2]); - g2d.draw(body[2]); - } - - // Pins are the last piece. - g2d.setColor(outlineMode ? finalBorderColor : METAL_COLOR.darker()); - g2d.draw(body[3]); - - 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 - : LABEL_COLOR; - } - g2d.setColor(finalLabelColor); - g2d.setFont(project.getFont()); - - // Override font size - if (getFontSizeOverride() != null) - g2d.setFont(g2d.getFont().deriveFont(1f * getFontSizeOverride())); - - Rectangle bounds = body[0].getBounds(); - double centerX = bounds.getX() + bounds.width / 2; - double centerY = bounds.getY() + bounds.height / 2; - StringUtils.drawCenteredText(g2d, name, centerX, centerY, HorizontalAlignment.CENTER, VerticalAlignment.CENTER); - - drawSelectionOutline(g2d, componentState, outlineMode, project, drawingObserver); - } - - @Override - public void drawIcon(Graphics2D g2d, int width, int height) { - int bodyWidth = getClosestOdd(width * 3 / 5); - int tailWidth = getClosestOdd(width * 3 / 10); - - g2d.setColor(SHAFT_COLOR); - g2d.fillRect((width - tailWidth) / 2, 1, tailWidth, height / 2); - g2d.setColor(BORDER_COLOR); - g2d.drawRect((width - tailWidth) / 2, 1, tailWidth, height / 2); - - g2d.setColor(BODY_COLOR); - g2d.fillRect((width - bodyWidth) / 2, height / 7 + 1, bodyWidth, height * 5 / 7); - g2d.setColor(BORDER_COLOR); - g2d.drawRect((width - bodyWidth) / 2, height / 7 + 1, bodyWidth, height * 5 / 7); - - g2d.setColor(METAL_COLOR); - - g2d.fillRect(width * 7 / 16, height * 6 / 7 + 1, width / 8, height / 7 - 1); - g2d.fillRect(width * 7 / 16, height / 7 + 2, width / 8, height / 7 - 1); - - g2d.setColor(LABEL_COLOR); - g2d.setFont(LABEL_FONT.deriveFont(width / 3.5f)); - - RenderingHints rh = new RenderingHints( - RenderingHints.KEY_TEXT_ANTIALIASING, - RenderingHints.VALUE_TEXT_ANTIALIAS_OFF); - g2d.setRenderingHints(rh); - - StringUtils.drawCenteredText(g2d, "6.3", width / 2 - 1, height / 2, HorizontalAlignment.CENTER, VerticalAlignment.CENTER); - } - - @Override - public int getControlPointCount() { - return controlPoints.length; - } - - @Override - public Point2D getControlPoint(int index) { - return controlPoints[index]; - } - - @Override - public void setControlPoint(Point2D point, int index) { - controlPoints[index].setLocation(point); - body = null; - } - - @Override - public boolean isControlPointSticky(int index) { - return true; - } - - @Override - public VisibilityPolicy getControlPointVisibilityPolicy(int index) { - return VisibilityPolicy.NEVER; - } - - @EditableProperty(name = "Type") - public JackType getValue() { - return type; - } - - public void setValue(JackType type) { - this.type = type; - updateControlPoints(); - } - - @EditableProperty - public Orientation getOrientation() { - return orientation; - } - - public void setOrientation(Orientation orientation) { - this.orientation = orientation; - updateControlPoints(); - } - - @Override - public String getControlPointNodeName(int index) { - switch (index) { - case 0: - return "Tip"; - case 1: - return "Sleeve"; - case 2: - return "Ring"; - } - return null; - } - - @Override - public boolean canPointMoveFreely(int pointIndex) { - return false; - } -} +/* + + DIY Layout Creator (DIYLC). + Copyright (c) 2009-2025 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.electromechanical; + +import java.awt.AlphaComposite; +import java.awt.Color; +import java.awt.Composite; +import java.awt.Graphics2D; +import java.awt.Rectangle; +import java.awt.RenderingHints; +import java.awt.Shape; +import java.awt.geom.AffineTransform; +import java.awt.geom.Area; +import java.awt.geom.Ellipse2D; +import java.awt.geom.GeneralPath; +import java.awt.geom.Point2D; +import java.awt.geom.Rectangle2D; +import org.diylc.appframework.miscutils.ConfigurationManager; + +import org.diylc.awt.StringUtils; +import org.diylc.common.HorizontalAlignment; +import org.diylc.common.IPlugInPort; +import org.diylc.common.ObjectCache; +import org.diylc.common.Orientation; +import org.diylc.common.VerticalAlignment; +import org.diylc.components.AbstractMultiPartComponent; +import org.diylc.components.transform.ClosedJackTransformer; +import org.diylc.core.ComponentState; +import org.diylc.core.IDIYComponent; +import org.diylc.core.IDrawingObserver; +import org.diylc.core.Project; +import org.diylc.core.Theme; +import org.diylc.core.VisibilityPolicy; +import org.diylc.core.annotations.ComponentDescriptor; +import org.diylc.core.annotations.EditableProperty; +import org.diylc.core.gerber.IGerberComponentSimple; +import org.diylc.core.measures.Size; +import org.diylc.core.measures.SizeUnit; +import org.diylc.utils.Constants; + +@ComponentDescriptor(name = "Closed 1/4\" Jack", category = "Electro-Mechanical", author = "Branislav Stojkovic", + description = "Enclosed panel mount 1/4\" phono jack", zOrder = IDIYComponent.COMPONENT, + instanceNamePrefix = "J", transformer = ClosedJackTransformer.class, enableCache = true) +public class ClosedJack1_4 extends AbstractMultiPartComponent implements IGerberComponentSimple { + + private static final long serialVersionUID = 1L; + + private static Size SPACING = new Size(0.1d, SizeUnit.in); + private static Size LUG_WIDTH = new Size(0.1d, SizeUnit.in); + private static Size LUG_LENGTH = new Size(0.12d, SizeUnit.in); + private static Size LUG_HOLE_SIZE = new Size(1d, SizeUnit.mm); + private static Color BODY_COLOR = Color.decode("#666666"); + private static Color SHAFT_COLOR = Color.decode("#AAAAAA"); + private static Size SHAFT_LENGTH = new Size(0.25d, SizeUnit.in); + private static Size SHAFT_WIDTH = new Size(3d / 8, SizeUnit.in); + private static Color BORDER_COLOR = Color.black; + private static Color LABEL_COLOR = Color.white; + private static Size BODY_WIDTH = new Size(0.65d, SizeUnit.in); + private static Size BODY_LENGTH = new Size(0.8d, SizeUnit.in); + + private Point2D[] controlPoints = new Point2D[] {new Point2D.Double(0, 0)}; + private JackType type = JackType.MONO; + private Orientation orientation = Orientation.DEFAULT; + transient private Shape[] body; + @SuppressWarnings("unused") + @Deprecated + private transient String value = ""; + + public ClosedJack1_4() { + super(); + updateControlPoints(); + } + + private void updateControlPoints() { + // invalidate body shape + body = null; + double x = controlPoints[0].getX(); + double y = controlPoints[0].getY(); + int spacing = (int) SPACING.convertToPixels(); + int bodyLength = (int) BODY_LENGTH.convertToPixels(); + controlPoints = new Point2D[type == JackType.STEREO ? 3 : 2]; + + controlPoints[0] = new Point2D.Double(x, y); + controlPoints[1] = new Point2D.Double(x + bodyLength, y); + if (type == JackType.STEREO) { + controlPoints[2] = new Point2D.Double(x, y + 2 * spacing); + } + + // Apply rotation if necessary + double angle = getAngle(); + if (angle != 0) { + AffineTransform rotation = AffineTransform.getRotateInstance(angle, x, y); + for (int i = 1; i < controlPoints.length; i++) { + rotation.transform(controlPoints[i], controlPoints[i]); + } + } + } + + private double getAngle() { + // Apply rotation if necessary + double angle; + switch (orientation) { + case _90: + angle = Math.PI / 2; + break; + case _180: + angle = Math.PI; + break; + case _270: + angle = Math.PI * 3 / 2; + break; + default: + angle = 0; + } + + return angle; + } + + public Shape[] getBody() { + if (body == null) { + body = new Shape[5]; + + // Create body. + double x = controlPoints[0].getX(); + double y = controlPoints[0].getY(); + int lugWidth = (int) LUG_WIDTH.convertToPixels(); + int lugLength = (int) LUG_LENGTH.convertToPixels(); + int lugHoleSize = (int) LUG_HOLE_SIZE.convertToPixels(); + int bodyLength = (int) BODY_LENGTH.convertToPixels(); + int bodyWidth = (int) BODY_WIDTH.convertToPixels(); + body[0] = new Area(new Rectangle2D.Double(x + lugLength, y - bodyWidth / 2, bodyLength, bodyWidth)); + + int shaftLength = (int) SHAFT_LENGTH.convertToPixels(); + int shaftWidth = (int) SHAFT_WIDTH.convertToPixels(); + Area shaft = new Area(new Rectangle2D.Double(x + lugLength + bodyLength, y - shaftWidth / 2, shaftLength, shaftWidth)); + body[1] = shaft; + + double angle = getAngle(); + AffineTransform rotation = null; + if (angle != 0) { + rotation = AffineTransform.getRotateInstance(angle, x, y); + } + + GeneralPath path = new GeneralPath(); + int step = 4; + for (double i = x + lugLength + bodyLength + step; i <= x + lugLength + bodyLength + shaftLength; i += step) { + Point2D p = new Point2D.Double(i, y - shaftWidth / 2 + 1); + if (rotation != null) { + rotation.transform(p, p); + } + path.moveTo(p.getX(), p.getY()); + p = new Point2D.Double(i - step, y + shaftWidth / 2 - 1); + if (rotation != null) { + rotation.transform(p, p); + } + path.lineTo(p.getX(), p.getY()); + } +// Area pathArea = new Area(path); +// pathArea.intersect(shaft); + body[2] = path; + + // Create lugs. + Area lugs = new Area(); + + int spacing = (int) SPACING.convertToPixels(); + Point2D[] untransformedControlPoints = new Point2D[type == JackType.STEREO ? 3 : 2]; + + untransformedControlPoints[0] = new Point2D.Double(x, y); + untransformedControlPoints[1] = new Point2D.Double(x + bodyLength, y); + if (type == JackType.STEREO) { + untransformedControlPoints[2] = new Point2D.Double(x, y + 2 * spacing); + } + + for (int i = 0; i < untransformedControlPoints.length; i++) { + Point2D point = untransformedControlPoints[i]; + Area lug = new Area(new Ellipse2D.Double(point.getX() - lugWidth / 2, point.getY() - lugWidth / 2, lugWidth, lugWidth)); + lug.add(new Area(new Rectangle2D.Double(point.getX(), point.getY() - lugWidth / 2, lugLength, lugWidth))); + lug.subtract(new Area(new Ellipse2D.Double(point.getX() - lugHoleSize / 2, point.getY() - lugHoleSize / 2, lugHoleSize, + lugHoleSize))); + lugs.add(lug); + } + + body[3] = lugs; + + // Rotate everything that's of Area type, e.g. everything but lines. + if (rotation != null) { + for (Shape shape : body) { + if (shape instanceof Area) { + Area area = (Area) shape; + area.transform(rotation); + } + } + } + } + return body; + } + + @Override + public void draw(Graphics2D g2d, ComponentState componentState, boolean outlineMode, Project project, + IDrawingObserver drawingObserver) { + Shape[] body = getBody(); + + // Rectangle bounds = body.getBounds(); + + g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(1)); +// if (componentState != ComponentState.DRAGGING) { + Composite oldComposite = applyAlpha(g2d, componentState); + g2d.setColor(outlineMode ? Constants.TRANSPARENT_COLOR : BODY_COLOR); + g2d.fill(body[0]); + g2d.setColor(outlineMode ? Constants.TRANSPARENT_COLOR : SHAFT_COLOR); + g2d.fill(body[1]); + g2d.setColor(outlineMode ? Constants.TRANSPARENT_COLOR : METAL_COLOR); + g2d.fill(body[3]); + g2d.setComposite(oldComposite); +// } + + drawingObserver.stopTracking(); + + Color finalBorderColor; + if (outlineMode) { + Theme theme = + (Theme) ConfigurationManager.getInstance().readObject(IPlugInPort.THEME_KEY, Constants.DEFAULT_THEME); + finalBorderColor = theme.getOutlineColor(); + } else { + finalBorderColor = BORDER_COLOR; + } + + g2d.setColor(finalBorderColor); + g2d.draw(body[0]); + g2d.draw(body[1]); + if (!outlineMode) { + g2d.setColor(SHAFT_COLOR.darker()); +// g2d.fill(body[2]); + g2d.draw(body[2]); + } + + // Pins are the last piece. + g2d.setColor(outlineMode ? finalBorderColor : METAL_COLOR.darker()); + g2d.draw(body[3]); + + 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 + : LABEL_COLOR; + } + g2d.setColor(finalLabelColor); + g2d.setFont(project.getFont()); + + // Override font size + if (getFontSizeOverride() != null) + g2d.setFont(g2d.getFont().deriveFont(1f * getFontSizeOverride())); + + Rectangle bounds = body[0].getBounds(); + double centerX = bounds.getX() + bounds.width / 2; + double centerY = bounds.getY() + bounds.height / 2; + StringUtils.drawCenteredText(g2d, name, centerX, centerY, HorizontalAlignment.CENTER, VerticalAlignment.CENTER); + + drawSelectionOutline(g2d, componentState, outlineMode, project, drawingObserver); + } + + @Override + public void drawIcon(Graphics2D g2d, int width, int height) { + int bodyWidth = getClosestOdd(width * 3 / 5); + int tailWidth = getClosestOdd(width * 3 / 10); + + g2d.setColor(SHAFT_COLOR); + g2d.fillRect((width - tailWidth) / 2, 1, tailWidth, height / 2); + g2d.setColor(BORDER_COLOR); + g2d.drawRect((width - tailWidth) / 2, 1, tailWidth, height / 2); + + g2d.setColor(BODY_COLOR); + g2d.fillRect((width - bodyWidth) / 2, height / 7 + 1, bodyWidth, height * 5 / 7); + g2d.setColor(BORDER_COLOR); + g2d.drawRect((width - bodyWidth) / 2, height / 7 + 1, bodyWidth, height * 5 / 7); + + g2d.setColor(METAL_COLOR); + + g2d.fillRect(width * 7 / 16, height * 6 / 7 + 1, width / 8, height / 7 - 1); + g2d.fillRect(width * 7 / 16, height / 7 + 2, width / 8, height / 7 - 1); + + g2d.setColor(LABEL_COLOR); + g2d.setFont(LABEL_FONT.deriveFont(width / 3.5f)); + + RenderingHints rh = new RenderingHints( + RenderingHints.KEY_TEXT_ANTIALIASING, + RenderingHints.VALUE_TEXT_ANTIALIAS_OFF); + g2d.setRenderingHints(rh); + + StringUtils.drawCenteredText(g2d, "6.3", width / 2 - 1, height / 2, HorizontalAlignment.CENTER, VerticalAlignment.CENTER); + } + + @Override + public int getControlPointCount() { + return controlPoints.length; + } + + @Override + public Point2D getControlPoint(int index) { + return controlPoints[index]; + } + + @Override + public void setControlPoint(Point2D point, int index) { + controlPoints[index].setLocation(point); + body = null; + } + + @Override + public boolean isControlPointSticky(int index) { + return true; + } + + @Override + public VisibilityPolicy getControlPointVisibilityPolicy(int index) { + return VisibilityPolicy.NEVER; + } + + @EditableProperty(name = "Type") + public JackType getValue() { + return type; + } + + public void setValue(JackType type) { + this.type = type; + updateControlPoints(); + } + + @EditableProperty + public Orientation getOrientation() { + return orientation; + } + + public void setOrientation(Orientation orientation) { + this.orientation = orientation; + updateControlPoints(); + } + + @Override + public String getControlPointNodeName(int index) { + switch (index) { + case 0: + return "Tip"; + case 1: + return "Sleeve"; + case 2: + return "Ring"; + } + return null; + } + + @Override + public boolean canPointMoveFreely(int pointIndex) { + return false; + } +} diff --git a/diylc/diylc-library/src/main/java/org/diylc/components/electromechanical/DIPSwitch.java b/diylc/diylc-library/src/main/java/org/diylc/components/electromechanical/DIPSwitch.java index 342be275f..b7feef337 100644 --- a/diylc/diylc-library/src/main/java/org/diylc/components/electromechanical/DIPSwitch.java +++ b/diylc/diylc-library/src/main/java/org/diylc/components/electromechanical/DIPSwitch.java @@ -31,10 +31,7 @@ import java.awt.geom.Rectangle2D; import java.awt.geom.RoundRectangle2D; import org.diylc.appframework.miscutils.ConfigurationManager; -import org.diylc.common.Display; -import org.diylc.common.IPlugInPort; -import org.diylc.common.ObjectCache; -import org.diylc.common.Orientation; +import org.diylc.common.*; import org.diylc.components.AbstractTransparentComponent; import org.diylc.core.ComponentState; import org.diylc.core.IDIYComponent; @@ -97,7 +94,7 @@ public class DIPSwitch extends AbstractTransparentComponent implements I public DIPSwitch() { super(); updateControlPoints(); - alpha = (byte) 100; + this.alphaPercent = new Percentage(100); } @EditableProperty @@ -348,10 +345,7 @@ public class DIPSwitch extends AbstractTransparentComponent implements I pinWidth, pinHeight); } } - Composite oldComposite = g2d.getComposite(); - if (alpha < MAX_ALPHA) { - g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1f * alpha / MAX_ALPHA)); - } + Composite oldComposite = applyAlpha(g2d, componentState); g2d.setColor(outlineMode ? Constants.TRANSPARENT_COLOR : getBodyColor()); g2d.fill(mainArea); g2d.setComposite(oldComposite); diff --git a/diylc/diylc-library/src/main/java/org/diylc/components/electromechanical/DrillHole.java b/diylc/diylc-library/src/main/java/org/diylc/components/electromechanical/DrillHole.java index b39a79bbd..4e494e708 100644 --- a/diylc/diylc-library/src/main/java/org/diylc/components/electromechanical/DrillHole.java +++ b/diylc/diylc-library/src/main/java/org/diylc/components/electromechanical/DrillHole.java @@ -79,10 +79,7 @@ public class DrillHole extends AbstractTransparentComponent gerberDrawingObserver.startGerberOutput(drillLayer, GerberFunctions.COMPONENT_DRILL, false); } - Composite oldComposite = g2d.getComposite(); - if (getAlpha() < MAX_ALPHA) { - g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1f * getAlpha() / MAX_ALPHA)); - } + Composite oldComposite = applyAlpha(g2d, componentState); // Draw white circle (hole) g2d.setColor(Color.white); diff --git a/diylc/diylc-library/src/main/java/org/diylc/components/electromechanical/FuseHolderPanel.java b/diylc/diylc-library/src/main/java/org/diylc/components/electromechanical/FuseHolderPanel.java index e115957ad..87c697a73 100644 --- a/diylc/diylc-library/src/main/java/org/diylc/components/electromechanical/FuseHolderPanel.java +++ b/diylc/diylc-library/src/main/java/org/diylc/components/electromechanical/FuseHolderPanel.java @@ -174,10 +174,7 @@ public class FuseHolderPanel extends AbstractMultiPartComponent { Theme theme = (Theme) ConfigurationManager.getInstance().readObject(IPlugInPort.THEME_KEY, Constants.DEFAULT_THEME); // Draw body if available. if (body != null) { - Composite oldComposite = g2d.getComposite(); - if (alpha < MAX_ALPHA) { - g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1f * alpha / MAX_ALPHA)); - } + Composite oldComposite = applyAlpha(g2d, componentState); g2d.setColor(outlineMode ? Constants.TRANSPARENT_COLOR : getBodyColor()); for (Area a : body) if (a != null) { diff --git a/diylc/diylc-library/src/main/java/org/diylc/components/electromechanical/IECSocket.java b/diylc/diylc-library/src/main/java/org/diylc/components/electromechanical/IECSocket.java index e87ea5014..52f018ea0 100644 --- a/diylc/diylc-library/src/main/java/org/diylc/components/electromechanical/IECSocket.java +++ b/diylc/diylc-library/src/main/java/org/diylc/components/electromechanical/IECSocket.java @@ -197,10 +197,7 @@ public class IECSocket extends AbstractMultiPartComponent { Theme theme = (Theme) ConfigurationManager.getInstance().readObject(IPlugInPort.THEME_KEY, Constants.DEFAULT_THEME); // Draw body if available. if (body != null) { - Composite oldComposite = g2d.getComposite(); - if (alpha < MAX_ALPHA) { - g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1f * alpha / MAX_ALPHA)); - } + Composite oldComposite = applyAlpha(g2d, componentState); g2d.setColor(outlineMode ? Constants.TRANSPARENT_COLOR : getBodyColor()); for (Area a : body) if (a != null) { diff --git a/diylc/diylc-library/src/main/java/org/diylc/components/electromechanical/MiniRelay.java b/diylc/diylc-library/src/main/java/org/diylc/components/electromechanical/MiniRelay.java index 7a3e6bef4..61ccb7ec1 100644 --- a/diylc/diylc-library/src/main/java/org/diylc/components/electromechanical/MiniRelay.java +++ b/diylc/diylc-library/src/main/java/org/diylc/components/electromechanical/MiniRelay.java @@ -1,477 +1,474 @@ -/* - - DIY Layout Creator (DIYLC). - Copyright (c) 2009-2025 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.electromechanical; - -import java.awt.AlphaComposite; -import java.awt.Color; -import java.awt.Composite; -import java.awt.FontMetrics; -import java.awt.Graphics2D; -import java.awt.Rectangle; -import java.awt.geom.Area; -import java.awt.geom.Point2D; -import java.awt.geom.Rectangle2D; -import java.awt.geom.RoundRectangle2D; -import org.diylc.appframework.miscutils.ConfigurationManager; - -import org.diylc.common.Display; -import org.diylc.common.IPlugInPort; -import org.diylc.common.ObjectCache; -import org.diylc.common.Orientation; -import org.diylc.components.AbstractLabeledComponent; -import org.diylc.core.ComponentState; -import org.diylc.core.IDIYComponent; -import org.diylc.core.IDrawingObserver; -import org.diylc.core.Project; -import org.diylc.core.Theme; -import org.diylc.core.VisibilityPolicy; -import org.diylc.core.annotations.ComponentDescriptor; -import org.diylc.core.annotations.EditableProperty; -import org.diylc.core.gerber.IGerberComponentSimple; -import org.diylc.core.measures.Size; -import org.diylc.core.measures.SizeUnit; -import org.diylc.core.measures.Voltage; -import org.diylc.core.measures.VoltageUnit; -import org.diylc.utils.Constants; - -@ComponentDescriptor(name = "Mini Relay", author = "Branislav Stojkovic", category = "Electro-Mechanical", - instanceNamePrefix = "RY", description = "Miniature PCB mount relay, like Omron G5V-1 or G5V-2", - zOrder = IDIYComponent.COMPONENT, enableCache = true) -public class MiniRelay extends AbstractLabeledComponent implements IGerberComponentSimple { - - private static final long serialVersionUID = 1L; - - public static Color BODY_COLOR = Color.gray; - public static Color BORDER_COLOR = Color.gray.darker(); - public static Color PIN_COLOR = Color.decode("#00B2EE"); - public static Color PIN_BORDER_COLOR = PIN_COLOR.darker(); - public static Color INDENT_COLOR = Color.gray.darker(); - public static Color LABEL_COLOR = Color.white; - public static int EDGE_RADIUS = 6; - public static Size PIN_SIZE = new Size(0.03d, SizeUnit.in); - public static Size INDENT_SIZE = new Size(0.07d, SizeUnit.in); - public static Size BODY_MARGIN = new Size(0.05d, SizeUnit.in); - - public static Size MINI_PIN_SPACING = new Size(0.2d, SizeUnit.in); - public static Size MINI_ROW_SPACING = new Size(0.3d, SizeUnit.in); - public static Size MINI_WIDTH = new Size(20.1d, SizeUnit.mm); - public static Size MINI_HEIGHT = new Size(9.9d, SizeUnit.mm); - public static Size MINI_GAP = new Size(0.1d, SizeUnit.in); - - public static Size ULTRA_PIN_SPACING = new Size(0.1d, SizeUnit.in); - public static Size ULTRA_ROW_SPACING = new Size(0.2d, SizeUnit.in); - public static Size ULTRA_WIDTH = new Size(12.2d, SizeUnit.mm); - public static Size ULTRA_HEIGHT = new Size(7.2d, SizeUnit.mm); - public static Size ULTRA_GAP = new Size(0.1d, SizeUnit.in); - - private String value = ""; - private Orientation orientation = Orientation.DEFAULT; - - private Point2D[] controlPoints = new Point2D[] {new Point2D.Double(0, 0)}; - protected Display display = Display.NAME; - private RelayType type = RelayType.DPDT; - private RelaySize size = RelaySize.Miniature; - private Voltage voltage = new Voltage(12d, VoltageUnit.V); - transient private Area[] body; - - public MiniRelay() { - super(); - updateControlPoints(); - } - - @EditableProperty - public String getValue() { - return value; - } - - public void setValue(String value) { - this.value = value; - } - - @EditableProperty - public Orientation getOrientation() { - return orientation; - } - - public void setOrientation(Orientation orientation) { - this.orientation = orientation; - updateControlPoints(); - // Reset body shape. - body = null; - } - - @EditableProperty - public Display getDisplay() { - if (display == null) { - display = Display.VALUE; - } - return display; - } - - public void setDisplay(Display display) { - this.display = display; - } - - @Override - public int getControlPointCount() { - return controlPoints.length; - } - - @Override - public Point2D getControlPoint(int index) { - return controlPoints[index]; - } - - @Override - public boolean isControlPointSticky(int index) { - return true; - } - - @Override - public VisibilityPolicy getControlPointVisibilityPolicy(int index) { - return VisibilityPolicy.NEVER; - } - - @Override - public void setControlPoint(Point2D point, int index) { - controlPoints[index].setLocation(point); - body = null; - } - - private void updateControlPoints() { - Point2D firstPoint = controlPoints[0]; - int pinCount = 0; - switch (type) { - case DPDT: - pinCount = 8; - break; - case SPDT: - pinCount = 6; - break; - default: - throw new RuntimeException("Unexpected type: " + type); - } - controlPoints = new Point2D[pinCount]; - controlPoints[0] = firstPoint; - int pinSpacing = - size == RelaySize.Miniature ? (int) MINI_PIN_SPACING.convertToPixels() : (int) ULTRA_PIN_SPACING - .convertToPixels(); - int rowSpacing = - size == RelaySize.Miniature ? (int) MINI_ROW_SPACING.convertToPixels() : (int) ULTRA_ROW_SPACING - .convertToPixels(); - // Update control points. - int dx1; - int dy1; - int dx2; - int dy2; - int delta = 0; - for (int i = 0; i < pinCount / 2; i++) { - if (i == 1) { - delta = size == RelaySize.Miniature ? (int) MINI_GAP.convertToPixels() : (int) ULTRA_GAP.convertToPixels(); - if (type == RelayType.SPDT) { - delta += pinSpacing; - } - } - switch (orientation) { - case DEFAULT: - dx1 = 0; - dy1 = i * pinSpacing + delta; - dx2 = rowSpacing; - dy2 = i * pinSpacing + delta; - break; - case _90: - dx1 = -(i * pinSpacing + delta); - dy1 = 0; - dx2 = -(i * pinSpacing + delta); - dy2 = rowSpacing; - break; - case _180: - dx1 = 0; - dy1 = -(i * pinSpacing + delta); - dx2 = -rowSpacing; - dy2 = -(i * pinSpacing + delta); - break; - case _270: - dx1 = i * pinSpacing + delta; - dy1 = 0; - dx2 = i * pinSpacing + delta; - dy2 = -rowSpacing; - break; - default: - throw new RuntimeException("Unexpected orientation: " + orientation); - } - controlPoints[i] = new Point2D.Double(firstPoint.getX() + dx1, firstPoint.getY() + dy1); - controlPoints[i + pinCount / 2] = new Point2D.Double(firstPoint.getX() + dx2, firstPoint.getY() + dy2); - } - } - - public Area[] getBody() { - if (body == null) { - body = new Area[2]; - double x = controlPoints[0].getX(); - double y = controlPoints[0].getY(); - double centerX = (controlPoints[0].getX() + controlPoints[controlPoints.length - 1].getX()) / 2; - double centerY = (controlPoints[0].getY() + controlPoints[controlPoints.length - 1].getY()) / 2; - int bodyMargin = getClosestOdd(BODY_MARGIN.convertToPixels()); - int width = 0; - int height = 0; - int rowSpacing = - size == RelaySize.Miniature ? (int) MINI_ROW_SPACING.convertToPixels() : (int) ULTRA_ROW_SPACING - .convertToPixels(); - Area indentation = null; - int indentationSize = getClosestOdd(INDENT_SIZE.convertToPixels()); - switch (orientation) { - case DEFAULT: - width = (int) (size == RelaySize.Miniature ? MINI_HEIGHT.convertToPixels() : ULTRA_HEIGHT.convertToPixels()); - height = (int) (size == RelaySize.Miniature ? MINI_WIDTH.convertToPixels() : ULTRA_WIDTH.convertToPixels()); - x -= bodyMargin; - y -= bodyMargin; - indentation = - new Area(new Rectangle2D.Double(centerX - indentationSize / 2, y - indentationSize / 2, indentationSize, - indentationSize)); - break; - case _90: - width = (int) (size == RelaySize.Miniature ? MINI_WIDTH.convertToPixels() : ULTRA_WIDTH.convertToPixels()); - height = (int) (size == RelaySize.Miniature ? MINI_HEIGHT.convertToPixels() : ULTRA_HEIGHT.convertToPixels()); - x -= -bodyMargin + width; - y -= bodyMargin; - indentation = - new Area(new Rectangle2D.Double(x + width - indentationSize / 2, centerY - indentationSize / 2, - indentationSize, indentationSize)); - break; - case _180: - width = (int) (size == RelaySize.Miniature ? MINI_HEIGHT.convertToPixels() : ULTRA_HEIGHT.convertToPixels()); - height = (int) (size == RelaySize.Miniature ? MINI_WIDTH.convertToPixels() : ULTRA_WIDTH.convertToPixels()); - x -= rowSpacing + bodyMargin; - y -= -bodyMargin + height; - indentation = - new Area(new Rectangle2D.Double(centerX - indentationSize / 2, y + height - indentationSize / 2, - indentationSize, indentationSize)); - break; - case _270: - width = (int) (size == RelaySize.Miniature ? MINI_WIDTH.convertToPixels() : ULTRA_WIDTH.convertToPixels()); - height = (int) (size == RelaySize.Miniature ? MINI_HEIGHT.convertToPixels() : ULTRA_HEIGHT.convertToPixels()); - x -= bodyMargin; - y -= bodyMargin + rowSpacing; - indentation = - new Area(new Rectangle2D.Double(x - indentationSize / 2, centerY - indentationSize / 2, indentationSize, - indentationSize)); - break; - default: - throw new RuntimeException("Unexpected orientation: " + orientation); - } - body[0] = - new Area(new RoundRectangle2D.Double(centerX - width / 2, centerY - height / 2, width, height, EDGE_RADIUS, - EDGE_RADIUS)); - body[1] = indentation; - if (indentation != null) { - indentation.intersect(body[0]); - } - } - return body; - } - - @Override - public void draw(Graphics2D g2d, ComponentState componentState, boolean outlineMode, Project project, - IDrawingObserver drawingObserver) { - if (checkPointsClipped(g2d.getClip())) { - return; - } - Area mainArea = getBody()[0]; - 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 : BODY_COLOR); - g2d.fill(mainArea); - g2d.setComposite(oldComposite); - - drawingObserver.stopTracking(); - - g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(1)); - - Theme theme = (Theme) ConfigurationManager.getInstance().readObject(IPlugInPort.THEME_KEY, Constants.DEFAULT_THEME); - int pinSize = (int) PIN_SIZE.convertToPixels() / 2 * 2; - for (Point2D point : controlPoints) { - if (!outlineMode) { - g2d.setColor(PIN_COLOR); - g2d.fillOval((int)(point.getX() - pinSize / 2), (int)(point.getY() - pinSize / 2), pinSize, pinSize); - } - g2d.setColor(outlineMode ? theme.getOutlineColor() : PIN_BORDER_COLOR); - g2d.drawOval((int)(point.getX() - pinSize / 2), (int)(point.getY() - pinSize / 2), pinSize, pinSize); - } - - Color finalBorderColor; - if (outlineMode) { - finalBorderColor = - componentState == ComponentState.SELECTED || componentState == ComponentState.DRAGGING ? SELECTION_COLOR - : theme.getOutlineColor(); - } else { - finalBorderColor = - componentState == ComponentState.SELECTED || componentState == ComponentState.DRAGGING ? SELECTION_COLOR - : BORDER_COLOR; - } - g2d.setColor(finalBorderColor); - g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(1)); - if (outlineMode) { - Area area = new Area(mainArea); - area.subtract(getBody()[1]); - g2d.draw(area); - } else { - g2d.draw(mainArea); - if (getBody()[1] != null) { - g2d.setColor(INDENT_COLOR); - g2d.fill(getBody()[1]); - } - } - // Draw label. - g2d.setFont(project.getFont()); - - // Override font size - if (getFontSizeOverride() != null) - g2d.setFont(g2d.getFont().deriveFont(1f * getFontSizeOverride())); - - Color finalLabelColor; - if (outlineMode) { - finalLabelColor = - componentState == ComponentState.SELECTED || componentState == ComponentState.DRAGGING ? LABEL_COLOR_SELECTED - : theme.getOutlineColor(); - } else { - finalLabelColor = - componentState == ComponentState.SELECTED || componentState == ComponentState.DRAGGING ? LABEL_COLOR_SELECTED - : LABEL_COLOR; - } - g2d.setColor(finalLabelColor); - FontMetrics fontMetrics = g2d.getFontMetrics(g2d.getFont()); - String label = ""; - label = display == Display.VALUE ? getValue() : getName(); - if (display == Display.NONE) { - label = ""; - } - if (display == Display.BOTH) { - label = getName() + " " + (getValue() == null ? "" : getValue().toString()); - } - Rectangle2D rect = fontMetrics.getStringBounds(label, g2d); - int textHeight = (int) (rect.getHeight()); - int textWidth = (int) (rect.getWidth()); - // Center text horizontally and vertically - Rectangle bounds = mainArea.getBounds(); - double x = bounds.getX() + (bounds.width - textWidth) / 2; - double y = bounds.getY() + (bounds.height - textHeight) / 2 + fontMetrics.getAscent(); - g2d.drawString(label, (int)x, (int)y); - } - - @Override - public void drawIcon(Graphics2D g2d, int width, int height) { - int radius = 6 * width / 32; - g2d.setColor(BODY_COLOR); - g2d.fillRoundRect(width / 6, 1, 4 * width / 6, height - 4, radius, radius); - g2d.setColor(BORDER_COLOR); - g2d.drawRoundRect(width / 6, 1, 4 * width / 6, height - 4, radius, radius); - int pinSize = 2 * width / 32; - g2d.setColor(PIN_COLOR); - for (int i = 0; i < 4; i++) { - if (i == 1) - continue; - g2d.fillOval(width / 4, (height / 5) * (i + 1) - 1, pinSize, pinSize); - g2d.fillOval(3 * width / 4 - pinSize, (height / 5) * (i + 1) - 1, pinSize, pinSize); - } - } - - @Override - public String getValueForDisplay() { - return getValue() + " " + getType() + " " + getVoltage(); - } - - @EditableProperty - public RelayType getType() { - return type; - } - - public void setType(RelayType type) { - this.type = type; - updateControlPoints(); - // Invalidate body - this.body = null; - } - - @EditableProperty - public Voltage getVoltage() { - return voltage; - } - - public void setVoltage(Voltage voltage) { - this.voltage = voltage; - } - - @EditableProperty - public RelaySize getSize() { - return size; - } - - public void setSize(RelaySize size) { - this.size = size; - updateControlPoints(); - // Invalidate body - this.body = null; - } - - @Override - public boolean canPointMoveFreely(int pointIndex) { - return false; - } - - @Override - public Rectangle2D getCachingBounds() { - double minX = Integer.MAX_VALUE; - double maxX = Integer.MIN_VALUE; - double minY = Integer.MAX_VALUE; - double maxY = Integer.MIN_VALUE; - double margin = 50; - for (int i = 0; i < getControlPointCount(); i++) { - Point2D p = getControlPoint(i); - if (p.getX() < minX) - minX = p.getX(); - if (p.getX() > maxX) - maxX = p.getX(); - if (p.getY() < minY) - minY = p.getY(); - if (p.getY() > maxY) - maxY = p.getY(); - } - - return new Rectangle2D.Double(minX - margin, minY - margin, maxX - minX + 2 * margin, maxY - minY + 2 * margin); - } - - public static enum RelayType { - SPDT, DPDT; - } - - public static enum RelaySize { - - Miniature, Ultra_miniature; - - public String toString() { - return name().replace('_', '-'); - }; - } -} +/* + + DIY Layout Creator (DIYLC). + Copyright (c) 2009-2025 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.electromechanical; + +import java.awt.AlphaComposite; +import java.awt.Color; +import java.awt.Composite; +import java.awt.FontMetrics; +import java.awt.Graphics2D; +import java.awt.Rectangle; +import java.awt.geom.Area; +import java.awt.geom.Point2D; +import java.awt.geom.Rectangle2D; +import java.awt.geom.RoundRectangle2D; +import org.diylc.appframework.miscutils.ConfigurationManager; + +import org.diylc.common.Display; +import org.diylc.common.IPlugInPort; +import org.diylc.common.ObjectCache; +import org.diylc.common.Orientation; +import org.diylc.components.AbstractLabeledComponent; +import org.diylc.core.ComponentState; +import org.diylc.core.IDIYComponent; +import org.diylc.core.IDrawingObserver; +import org.diylc.core.Project; +import org.diylc.core.Theme; +import org.diylc.core.VisibilityPolicy; +import org.diylc.core.annotations.ComponentDescriptor; +import org.diylc.core.annotations.EditableProperty; +import org.diylc.core.gerber.IGerberComponentSimple; +import org.diylc.core.measures.Size; +import org.diylc.core.measures.SizeUnit; +import org.diylc.core.measures.Voltage; +import org.diylc.core.measures.VoltageUnit; +import org.diylc.utils.Constants; + +@ComponentDescriptor(name = "Mini Relay", author = "Branislav Stojkovic", category = "Electro-Mechanical", + instanceNamePrefix = "RY", description = "Miniature PCB mount relay, like Omron G5V-1 or G5V-2", + zOrder = IDIYComponent.COMPONENT, enableCache = true) +public class MiniRelay extends AbstractLabeledComponent implements IGerberComponentSimple { + + private static final long serialVersionUID = 1L; + + public static Color BODY_COLOR = Color.gray; + public static Color BORDER_COLOR = Color.gray.darker(); + public static Color PIN_COLOR = Color.decode("#00B2EE"); + public static Color PIN_BORDER_COLOR = PIN_COLOR.darker(); + public static Color INDENT_COLOR = Color.gray.darker(); + public static Color LABEL_COLOR = Color.white; + public static int EDGE_RADIUS = 6; + public static Size PIN_SIZE = new Size(0.03d, SizeUnit.in); + public static Size INDENT_SIZE = new Size(0.07d, SizeUnit.in); + public static Size BODY_MARGIN = new Size(0.05d, SizeUnit.in); + + public static Size MINI_PIN_SPACING = new Size(0.2d, SizeUnit.in); + public static Size MINI_ROW_SPACING = new Size(0.3d, SizeUnit.in); + public static Size MINI_WIDTH = new Size(20.1d, SizeUnit.mm); + public static Size MINI_HEIGHT = new Size(9.9d, SizeUnit.mm); + public static Size MINI_GAP = new Size(0.1d, SizeUnit.in); + + public static Size ULTRA_PIN_SPACING = new Size(0.1d, SizeUnit.in); + public static Size ULTRA_ROW_SPACING = new Size(0.2d, SizeUnit.in); + public static Size ULTRA_WIDTH = new Size(12.2d, SizeUnit.mm); + public static Size ULTRA_HEIGHT = new Size(7.2d, SizeUnit.mm); + public static Size ULTRA_GAP = new Size(0.1d, SizeUnit.in); + + private String value = ""; + private Orientation orientation = Orientation.DEFAULT; + + private Point2D[] controlPoints = new Point2D[] {new Point2D.Double(0, 0)}; + protected Display display = Display.NAME; + private RelayType type = RelayType.DPDT; + private RelaySize size = RelaySize.Miniature; + private Voltage voltage = new Voltage(12d, VoltageUnit.V); + transient private Area[] body; + + public MiniRelay() { + super(); + updateControlPoints(); + } + + @EditableProperty + public String getValue() { + return value; + } + + public void setValue(String value) { + this.value = value; + } + + @EditableProperty + public Orientation getOrientation() { + return orientation; + } + + public void setOrientation(Orientation orientation) { + this.orientation = orientation; + updateControlPoints(); + // Reset body shape. + body = null; + } + + @EditableProperty + public Display getDisplay() { + if (display == null) { + display = Display.VALUE; + } + return display; + } + + public void setDisplay(Display display) { + this.display = display; + } + + @Override + public int getControlPointCount() { + return controlPoints.length; + } + + @Override + public Point2D getControlPoint(int index) { + return controlPoints[index]; + } + + @Override + public boolean isControlPointSticky(int index) { + return true; + } + + @Override + public VisibilityPolicy getControlPointVisibilityPolicy(int index) { + return VisibilityPolicy.NEVER; + } + + @Override + public void setControlPoint(Point2D point, int index) { + controlPoints[index].setLocation(point); + body = null; + } + + private void updateControlPoints() { + Point2D firstPoint = controlPoints[0]; + int pinCount = 0; + switch (type) { + case DPDT: + pinCount = 8; + break; + case SPDT: + pinCount = 6; + break; + default: + throw new RuntimeException("Unexpected type: " + type); + } + controlPoints = new Point2D[pinCount]; + controlPoints[0] = firstPoint; + int pinSpacing = + size == RelaySize.Miniature ? (int) MINI_PIN_SPACING.convertToPixels() : (int) ULTRA_PIN_SPACING + .convertToPixels(); + int rowSpacing = + size == RelaySize.Miniature ? (int) MINI_ROW_SPACING.convertToPixels() : (int) ULTRA_ROW_SPACING + .convertToPixels(); + // Update control points. + int dx1; + int dy1; + int dx2; + int dy2; + int delta = 0; + for (int i = 0; i < pinCount / 2; i++) { + if (i == 1) { + delta = size == RelaySize.Miniature ? (int) MINI_GAP.convertToPixels() : (int) ULTRA_GAP.convertToPixels(); + if (type == RelayType.SPDT) { + delta += pinSpacing; + } + } + switch (orientation) { + case DEFAULT: + dx1 = 0; + dy1 = i * pinSpacing + delta; + dx2 = rowSpacing; + dy2 = i * pinSpacing + delta; + break; + case _90: + dx1 = -(i * pinSpacing + delta); + dy1 = 0; + dx2 = -(i * pinSpacing + delta); + dy2 = rowSpacing; + break; + case _180: + dx1 = 0; + dy1 = -(i * pinSpacing + delta); + dx2 = -rowSpacing; + dy2 = -(i * pinSpacing + delta); + break; + case _270: + dx1 = i * pinSpacing + delta; + dy1 = 0; + dx2 = i * pinSpacing + delta; + dy2 = -rowSpacing; + break; + default: + throw new RuntimeException("Unexpected orientation: " + orientation); + } + controlPoints[i] = new Point2D.Double(firstPoint.getX() + dx1, firstPoint.getY() + dy1); + controlPoints[i + pinCount / 2] = new Point2D.Double(firstPoint.getX() + dx2, firstPoint.getY() + dy2); + } + } + + public Area[] getBody() { + if (body == null) { + body = new Area[2]; + double x = controlPoints[0].getX(); + double y = controlPoints[0].getY(); + double centerX = (controlPoints[0].getX() + controlPoints[controlPoints.length - 1].getX()) / 2; + double centerY = (controlPoints[0].getY() + controlPoints[controlPoints.length - 1].getY()) / 2; + int bodyMargin = getClosestOdd(BODY_MARGIN.convertToPixels()); + int width = 0; + int height = 0; + int rowSpacing = + size == RelaySize.Miniature ? (int) MINI_ROW_SPACING.convertToPixels() : (int) ULTRA_ROW_SPACING + .convertToPixels(); + Area indentation = null; + int indentationSize = getClosestOdd(INDENT_SIZE.convertToPixels()); + switch (orientation) { + case DEFAULT: + width = (int) (size == RelaySize.Miniature ? MINI_HEIGHT.convertToPixels() : ULTRA_HEIGHT.convertToPixels()); + height = (int) (size == RelaySize.Miniature ? MINI_WIDTH.convertToPixels() : ULTRA_WIDTH.convertToPixels()); + x -= bodyMargin; + y -= bodyMargin; + indentation = + new Area(new Rectangle2D.Double(centerX - indentationSize / 2, y - indentationSize / 2, indentationSize, + indentationSize)); + break; + case _90: + width = (int) (size == RelaySize.Miniature ? MINI_WIDTH.convertToPixels() : ULTRA_WIDTH.convertToPixels()); + height = (int) (size == RelaySize.Miniature ? MINI_HEIGHT.convertToPixels() : ULTRA_HEIGHT.convertToPixels()); + x -= -bodyMargin + width; + y -= bodyMargin; + indentation = + new Area(new Rectangle2D.Double(x + width - indentationSize / 2, centerY - indentationSize / 2, + indentationSize, indentationSize)); + break; + case _180: + width = (int) (size == RelaySize.Miniature ? MINI_HEIGHT.convertToPixels() : ULTRA_HEIGHT.convertToPixels()); + height = (int) (size == RelaySize.Miniature ? MINI_WIDTH.convertToPixels() : ULTRA_WIDTH.convertToPixels()); + x -= rowSpacing + bodyMargin; + y -= -bodyMargin + height; + indentation = + new Area(new Rectangle2D.Double(centerX - indentationSize / 2, y + height - indentationSize / 2, + indentationSize, indentationSize)); + break; + case _270: + width = (int) (size == RelaySize.Miniature ? MINI_WIDTH.convertToPixels() : ULTRA_WIDTH.convertToPixels()); + height = (int) (size == RelaySize.Miniature ? MINI_HEIGHT.convertToPixels() : ULTRA_HEIGHT.convertToPixels()); + x -= bodyMargin; + y -= bodyMargin + rowSpacing; + indentation = + new Area(new Rectangle2D.Double(x - indentationSize / 2, centerY - indentationSize / 2, indentationSize, + indentationSize)); + break; + default: + throw new RuntimeException("Unexpected orientation: " + orientation); + } + body[0] = + new Area(new RoundRectangle2D.Double(centerX - width / 2, centerY - height / 2, width, height, EDGE_RADIUS, + EDGE_RADIUS)); + body[1] = indentation; + if (indentation != null) { + indentation.intersect(body[0]); + } + } + return body; + } + + @Override + public void draw(Graphics2D g2d, ComponentState componentState, boolean outlineMode, Project project, + IDrawingObserver drawingObserver) { + if (checkPointsClipped(g2d.getClip())) { + return; + } + Area mainArea = getBody()[0]; + Composite oldComposite = applyAlpha(g2d, componentState); + g2d.setColor(outlineMode ? Constants.TRANSPARENT_COLOR : BODY_COLOR); + g2d.fill(mainArea); + g2d.setComposite(oldComposite); + + drawingObserver.stopTracking(); + + g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(1)); + + Theme theme = (Theme) ConfigurationManager.getInstance().readObject(IPlugInPort.THEME_KEY, Constants.DEFAULT_THEME); + int pinSize = (int) PIN_SIZE.convertToPixels() / 2 * 2; + for (Point2D point : controlPoints) { + if (!outlineMode) { + g2d.setColor(PIN_COLOR); + g2d.fillOval((int)(point.getX() - pinSize / 2), (int)(point.getY() - pinSize / 2), pinSize, pinSize); + } + g2d.setColor(outlineMode ? theme.getOutlineColor() : PIN_BORDER_COLOR); + g2d.drawOval((int)(point.getX() - pinSize / 2), (int)(point.getY() - pinSize / 2), pinSize, pinSize); + } + + Color finalBorderColor; + if (outlineMode) { + finalBorderColor = + componentState == ComponentState.SELECTED || componentState == ComponentState.DRAGGING ? SELECTION_COLOR + : theme.getOutlineColor(); + } else { + finalBorderColor = + componentState == ComponentState.SELECTED || componentState == ComponentState.DRAGGING ? SELECTION_COLOR + : BORDER_COLOR; + } + g2d.setColor(finalBorderColor); + g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(1)); + if (outlineMode) { + Area area = new Area(mainArea); + area.subtract(getBody()[1]); + g2d.draw(area); + } else { + g2d.draw(mainArea); + if (getBody()[1] != null) { + g2d.setColor(INDENT_COLOR); + g2d.fill(getBody()[1]); + } + } + // Draw label. + g2d.setFont(project.getFont()); + + // Override font size + if (getFontSizeOverride() != null) + g2d.setFont(g2d.getFont().deriveFont(1f * getFontSizeOverride())); + + Color finalLabelColor; + if (outlineMode) { + finalLabelColor = + componentState == ComponentState.SELECTED || componentState == ComponentState.DRAGGING ? LABEL_COLOR_SELECTED + : theme.getOutlineColor(); + } else { + finalLabelColor = + componentState == ComponentState.SELECTED || componentState == ComponentState.DRAGGING ? LABEL_COLOR_SELECTED + : LABEL_COLOR; + } + g2d.setColor(finalLabelColor); + FontMetrics fontMetrics = g2d.getFontMetrics(g2d.getFont()); + String label = ""; + label = display == Display.VALUE ? getValue() : getName(); + if (display == Display.NONE) { + label = ""; + } + if (display == Display.BOTH) { + label = getName() + " " + (getValue() == null ? "" : getValue().toString()); + } + Rectangle2D rect = fontMetrics.getStringBounds(label, g2d); + int textHeight = (int) (rect.getHeight()); + int textWidth = (int) (rect.getWidth()); + // Center text horizontally and vertically + Rectangle bounds = mainArea.getBounds(); + double x = bounds.getX() + (bounds.width - textWidth) / 2; + double y = bounds.getY() + (bounds.height - textHeight) / 2 + fontMetrics.getAscent(); + g2d.drawString(label, (int)x, (int)y); + } + + @Override + public void drawIcon(Graphics2D g2d, int width, int height) { + int radius = 6 * width / 32; + g2d.setColor(BODY_COLOR); + g2d.fillRoundRect(width / 6, 1, 4 * width / 6, height - 4, radius, radius); + g2d.setColor(BORDER_COLOR); + g2d.drawRoundRect(width / 6, 1, 4 * width / 6, height - 4, radius, radius); + int pinSize = 2 * width / 32; + g2d.setColor(PIN_COLOR); + for (int i = 0; i < 4; i++) { + if (i == 1) + continue; + g2d.fillOval(width / 4, (height / 5) * (i + 1) - 1, pinSize, pinSize); + g2d.fillOval(3 * width / 4 - pinSize, (height / 5) * (i + 1) - 1, pinSize, pinSize); + } + } + + @Override + public String getValueForDisplay() { + return getValue() + " " + getType() + " " + getVoltage(); + } + + @EditableProperty + public RelayType getType() { + return type; + } + + public void setType(RelayType type) { + this.type = type; + updateControlPoints(); + // Invalidate body + this.body = null; + } + + @EditableProperty + public Voltage getVoltage() { + return voltage; + } + + public void setVoltage(Voltage voltage) { + this.voltage = voltage; + } + + @EditableProperty + public RelaySize getSize() { + return size; + } + + public void setSize(RelaySize size) { + this.size = size; + updateControlPoints(); + // Invalidate body + this.body = null; + } + + @Override + public boolean canPointMoveFreely(int pointIndex) { + return false; + } + + @Override + public Rectangle2D getCachingBounds() { + double minX = Integer.MAX_VALUE; + double maxX = Integer.MIN_VALUE; + double minY = Integer.MAX_VALUE; + double maxY = Integer.MIN_VALUE; + double margin = 50; + for (int i = 0; i < getControlPointCount(); i++) { + Point2D p = getControlPoint(i); + if (p.getX() < minX) + minX = p.getX(); + if (p.getX() > maxX) + maxX = p.getX(); + if (p.getY() < minY) + minY = p.getY(); + if (p.getY() > maxY) + maxY = p.getY(); + } + + return new Rectangle2D.Double(minX - margin, minY - margin, maxX - minX + 2 * margin, maxY - minY + 2 * margin); + } + + public static enum RelayType { + SPDT, DPDT; + } + + public static enum RelaySize { + + Miniature, Ultra_miniature; + + public String toString() { + return name().replace('_', '-'); + }; + } +} diff --git a/diylc/diylc-library/src/main/java/org/diylc/components/electromechanical/MiniToggleSwitch.java b/diylc/diylc-library/src/main/java/org/diylc/components/electromechanical/MiniToggleSwitch.java index b88db6d1d..48e0e2ea3 100644 --- a/diylc/diylc-library/src/main/java/org/diylc/components/electromechanical/MiniToggleSwitch.java +++ b/diylc/diylc-library/src/main/java/org/diylc/components/electromechanical/MiniToggleSwitch.java @@ -1,620 +1,617 @@ -/* - - DIY Layout Creator (DIYLC). - Copyright (c) 2009-2025 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.electromechanical; - -import java.awt.AlphaComposite; -import java.awt.Color; -import java.awt.Composite; -import java.awt.Graphics2D; -import java.awt.Shape; -import java.awt.geom.AffineTransform; -import java.awt.geom.Area; -import java.awt.geom.Point2D; -import java.awt.geom.Rectangle2D; -import java.awt.geom.RoundRectangle2D; - -import org.diylc.appframework.miscutils.ConfigurationManager; - -import org.diylc.awt.StringUtils; -import org.diylc.common.*; -import org.diylc.components.AbstractTransparentComponent; -import org.diylc.components.guitar.ToggleSwitchPositionPropertyValueSource; -import org.diylc.components.transform.MiniToggleSwitchTransformer; -import org.diylc.core.ComponentState; -import org.diylc.core.IDIYComponent; -import org.diylc.core.IDrawingObserver; -import org.diylc.core.ILayeredComponent; -import org.diylc.core.ISwitch; -import org.diylc.core.Project; -import org.diylc.core.Theme; -import org.diylc.core.VisibilityPolicy; -import org.diylc.core.annotations.ComponentDescriptor; -import org.diylc.core.annotations.DynamicEditableProperty; -import org.diylc.core.annotations.EditableProperty; -import org.diylc.core.annotations.PositiveNonZeroMeasureValidator; -import org.diylc.core.gerber.IGerberComponentSimple; -import org.diylc.core.measures.Size; -import org.diylc.core.measures.SizeUnit; -import org.diylc.utils.Constants; -import org.diylc.utils.SwitchUtils; - -@ComponentDescriptor(name = "Mini Toggle Switch", category = "Electro-Mechanical", author = "Branislav Stojkovic", - description = "Panel mounted mini toggle switch", zOrder = IDIYComponent.COMPONENT, - instanceNamePrefix = "SW", enableCache = true, transformer = MiniToggleSwitchTransformer.class) -public class MiniToggleSwitch extends AbstractTransparentComponent implements ISwitch, ILayeredComponent, IGerberComponentSimple { - - private static final long serialVersionUID = 1L; - - private static Size SPACING = new Size(0.2d, SizeUnit.in); - private static Size MARGIN = new Size(0.08d, SizeUnit.in); - private static Size CIRCLE_SIZE = new Size(0.09d, SizeUnit.in); - private static Size LUG_WIDTH = new Size(0.060d, SizeUnit.in); - private static Size LUG_THICKNESS = new Size(0.02d, SizeUnit.in); - private static Size MARKER_OFFSET = new Size(0.07d, SizeUnit.in); - - private static Color BODY_COLOR = Color.decode("#3299CC"); - private static Color BORDER_COLOR = BODY_COLOR.darker(); - private static Color CIRCLE_COLOR = Color.decode("#287ba4"); - private static Color TERMINAL_COLOR = LIGHT_METAL_COLOR; - private static Color MARKER_COLOR = LIGHT_METAL_COLOR; - - - protected Point2D[] controlPoints = new Point2D[] {new Point2D.Double(0, 0)}; - transient protected Shape body; - protected ToggleSwitchType switchType = ToggleSwitchType.DPDT; - private OrientationHV orientation = OrientationHV.VERTICAL; - private Size spacing = SPACING; - - private Color bodyColor = BODY_COLOR; - private Color borderColor = BORDER_COLOR; - private Color terminalPadColor = CIRCLE_COLOR; - private Color terminalColor = TERMINAL_COLOR; - - private Integer selectedPosition; - private Boolean showMarkers; - - @Deprecated - protected String name; - - public MiniToggleSwitch() { - super(); - updateControlPoints(); - } - - private void updateControlPoints() { - Point2D firstPoint = controlPoints[0]; - int spacing = (int) getSpacing().convertToPixels(); - switch (switchType) { - case SPST: - controlPoints = new Point2D[] {firstPoint, new Point2D.Double(firstPoint.getX(), firstPoint.getY() + spacing)}; - break; - case SPDT: - case SPDT_off: - controlPoints = - new Point2D[] {firstPoint, new Point2D.Double(firstPoint.getX(), firstPoint.getY() + spacing), - new Point2D.Double(firstPoint.getX(), firstPoint.getY() + 2 * spacing)}; - break; - case DPDT: - case DPDT_off: - case DPDT_ononon_1: - case DPDT_ononon_2: - controlPoints = - new Point2D[] {firstPoint, new Point2D.Double(firstPoint.getX(), firstPoint.getY() + spacing), - new Point2D.Double(firstPoint.getX(), firstPoint.getY() + 2 * spacing), - new Point2D.Double(firstPoint.getX() + spacing, firstPoint.getY()), - new Point2D.Double(firstPoint.getX() + spacing, firstPoint.getY() + spacing), - new Point2D.Double(firstPoint.getX() + spacing, firstPoint.getY() + 2 * spacing)}; - break; - case _3PDT: - case _3PDT_off: - controlPoints = - new Point2D[] {firstPoint, new Point2D.Double(firstPoint.getX(), firstPoint.getY() + spacing), - new Point2D.Double(firstPoint.getX(), firstPoint.getY() + 2 * spacing), - new Point2D.Double(firstPoint.getX() + spacing, firstPoint.getY()), - new Point2D.Double(firstPoint.getX() + spacing, firstPoint.getY() + spacing), - new Point2D.Double(firstPoint.getX() + spacing, firstPoint.getY() + 2 * spacing), - new Point2D.Double(firstPoint.getX() + 2 * spacing, firstPoint.getY()), - new Point2D.Double(firstPoint.getX() + 2 * spacing, firstPoint.getY() + spacing), - new Point2D.Double(firstPoint.getX() + 2 * spacing, firstPoint.getY() + 2 * spacing)}; - break; - case _4PDT: - case _4PDT_off: - case _4PDT_ononon_1: - case _4PDT_ononon_2: - controlPoints = - new Point2D[] {firstPoint, new Point2D.Double(firstPoint.getX(), firstPoint.getY() + spacing), - new Point2D.Double(firstPoint.getX(), firstPoint.getY() + 2 * spacing), - new Point2D.Double(firstPoint.getX() + spacing, firstPoint.getY()), - new Point2D.Double(firstPoint.getX() + spacing, firstPoint.getY() + spacing), - new Point2D.Double(firstPoint.getX() + spacing, firstPoint.getY() + 2 * spacing), - new Point2D.Double(firstPoint.getX() + 2 * spacing, firstPoint.getY()), - new Point2D.Double(firstPoint.getX() + 2 * spacing, firstPoint.getY() + spacing), - new Point2D.Double(firstPoint.getX() + 2 * spacing, firstPoint.getY() + 2 * spacing), - new Point2D.Double(firstPoint.getX() + 3 * spacing, firstPoint.getY()), - new Point2D.Double(firstPoint.getX() + 3 * spacing, firstPoint.getY() + spacing), - new Point2D.Double(firstPoint.getX() + 3 * spacing, firstPoint.getY() + 2 * spacing)}; - break; - case _5PDT: - case _5PDT_off: - controlPoints = - new Point2D[] {firstPoint, new Point2D.Double(firstPoint.getX(), firstPoint.getY() + spacing), - new Point2D.Double(firstPoint.getX(), firstPoint.getY() + 2 * spacing), - new Point2D.Double(firstPoint.getX() + spacing, firstPoint.getY()), - new Point2D.Double(firstPoint.getX() + spacing, firstPoint.getY() + spacing), - new Point2D.Double(firstPoint.getX() + spacing, firstPoint.getY() + 2 * spacing), - new Point2D.Double(firstPoint.getX() + 2 * spacing, firstPoint.getY()), - new Point2D.Double(firstPoint.getX() + 2 * spacing, firstPoint.getY() + spacing), - new Point2D.Double(firstPoint.getX() + 2 * spacing, firstPoint.getY() + 2 * spacing), - new Point2D.Double(firstPoint.getX() + 3 * spacing, firstPoint.getY()), - new Point2D.Double(firstPoint.getX() + 3 * spacing, firstPoint.getY() + spacing), - new Point2D.Double(firstPoint.getX() + 3 * spacing, firstPoint.getY() + 2 * spacing), - new Point2D.Double(firstPoint.getX() + 4 * spacing, firstPoint.getY()), - new Point2D.Double(firstPoint.getX() + 4 * spacing, firstPoint.getY() + spacing), - new Point2D.Double(firstPoint.getX() + 4 * spacing, firstPoint.getY() + 2 * spacing)}; - break; - } - AffineTransform xform = AffineTransform.getRotateInstance(-Math.PI / 2, firstPoint.getX(), firstPoint.getY()); - if (getOrientation() == OrientationHV.HORIZONTAL) { - for (int i = 1; i < controlPoints.length; i++) { - xform.transform(controlPoints[i], controlPoints[i]); - } - } - } - - @Override - public Point2D getControlPoint(int index) { - return controlPoints[index]; - } - - @Override - public boolean isControlPointSticky(int index) { - return true; - } - - @Override - public VisibilityPolicy getControlPointVisibilityPolicy(int index) { - return VisibilityPolicy.NEVER; - } - - @Override - public int getControlPointCount() { - return controlPoints.length; - } - - @Override - public void setControlPoint(Point2D point, int index) { - controlPoints[index].setLocation(point); - // Reset body shape. - body = null; - } - - @EditableProperty(defaultable = false) - @Override - public String getName() { - if (super.name == null || super.name.trim().isEmpty()) { - super.name = name; - name = null; - } - return super.name; - } - - @Override - public void setName(String name) { - super.name = name; - this.name = null; - } - - @EditableProperty(name = "Type") - @Override - public ToggleSwitchType getValue() { - return switchType; - } - - @Override - public void setValue(ToggleSwitchType value) { - this.switchType = value; - updateControlPoints(); - // Reset body shape. - body = null; - } - - @EditableProperty - public OrientationHV getOrientation() { - if (orientation == null) { - orientation = OrientationHV.VERTICAL; - } - return orientation; - } - - public void setOrientation(OrientationHV orientation) { - this.orientation = orientation; - updateControlPoints(); - // Reset body shape. - body = null; - } - - @EditableProperty(validatorClass = PositiveNonZeroMeasureValidator.class) - public Size getSpacing() { - if (spacing == null) { - spacing = SPACING; - } - return spacing; - } - - public void setSpacing(Size spacing) { - this.spacing = spacing; - updateControlPoints(); - // Reset body shape. - body = null; - } - - @Override - public void draw(Graphics2D g2d, ComponentState componentState, boolean outlineMode, Project project, - IDrawingObserver drawingObserver) { - if (checkPointsClipped(g2d.getClip())) { - return; - } - Shape body = getBody(); - Theme theme = (Theme) ConfigurationManager.getInstance().readObject(IPlugInPort.THEME_KEY, Constants.DEFAULT_THEME); - // Draw body if available. - if (body != null) { - 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 : getBodyColor()); - g2d.fill(body); - g2d.setComposite(oldComposite); - g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(1)); - Color finalBorderColor; - if (outlineMode) { - finalBorderColor = - componentState == ComponentState.SELECTED || componentState == ComponentState.DRAGGING ? SELECTION_COLOR - : theme.getOutlineColor(); - } else { - finalBorderColor = - componentState == ComponentState.SELECTED || componentState == ComponentState.DRAGGING ? SELECTION_COLOR - : getBorderColor(); - } - g2d.setColor(finalBorderColor); - g2d.draw(body); - } - // Do not track these changes because the whole switch has been tracked - // so far. - drawingObserver.stopTracking(); - // Draw lugs. - int circleDiameter = getClosestOdd((int) CIRCLE_SIZE.convertToPixels()); - - int lugWidth; - int lugHeight; - - if (getOrientation() == OrientationHV.HORIZONTAL) { - lugHeight = getClosestOdd((int) LUG_WIDTH.convertToPixels()); - lugWidth = getClosestOdd((int) LUG_THICKNESS.convertToPixels()); - } else { - lugWidth = getClosestOdd((int) LUG_WIDTH.convertToPixels()); - lugHeight = getClosestOdd((int) LUG_THICKNESS.convertToPixels()); - } - - for (int i = 0; i < controlPoints.length; i++) { - Point2D p = controlPoints[i]; - if (outlineMode) { -// g2d.setColor(Constants.TRANSPARENT_COLOR); -// drawingObserver.startTrackingContinuityArea(true); -// g2d.fillRect((int)(p.getX() - lugWidth / 2), (int)(p.getY() - lugHeight / 2), lugWidth, lugHeight); -// drawingObserver.stopTrackingContinuityArea(); - - g2d.setColor(theme.getOutlineColor()); - g2d.drawRect((int)(p.getX() - lugWidth / 2d), (int)(p.getY() - lugHeight / 2d), lugWidth, lugHeight); - } else { - g2d.setColor(getTerminalPadColor().darker()); - - g2d.drawOval((int)(p.getX() - circleDiameter / 2d), (int)(p.getY() - circleDiameter / 2d), circleDiameter, circleDiameter); - - g2d.setColor(getTerminalPadColor()); - g2d.fillOval((int)(p.getX() - circleDiameter / 2d), (int)(p.getY() - circleDiameter / 2d), circleDiameter, circleDiameter); - g2d.setColor(getTerminalColor()); -// drawingObserver.startTrackingContinuityArea(true); - g2d.fillRect((int)(p.getX() - lugWidth / 2d), (int)(p.getY() - lugHeight / 2d), lugWidth, lugHeight); -// drawingObserver.stopTrackingContinuityArea(); - } - } - - if (getShowMarkers()) { - String[] markers = - SwitchUtils.getSwitchingMarkers(this, getControlPointCount(), false); - - g2d.setColor(MARKER_COLOR); - - double offset = MARKER_OFFSET.convertToPixels(); - for (int i = 0; i < getControlPointCount(); i++) { - if (markers[i] == null) - continue; - - Point2D p = getControlPoint(i); - Point2D labelPoint = new Point2D.Double(offset, 0); - - AffineTransform tx = null; - if (getOrientation() == OrientationHV.HORIZONTAL) { - tx = AffineTransform.getRotateInstance(-Math.PI / 2, 0, 0); - } - if (tx != null) { - tx.transform(labelPoint, labelPoint); - } - StringUtils.drawCenteredText(g2d, markers[i], p.getX() + labelPoint.getX(), p.getY() + labelPoint.getY(), - HorizontalAlignment.CENTER, VerticalAlignment.CENTER); - } - } - } - - public Shape getBody() { - if (body == null) { - Point2D firstPoint = controlPoints[0]; - int margin = (int) MARGIN.convertToPixels(); - int spacing = (int) getSpacing().convertToPixels(); - switch (switchType) { - case SPST: - body = - new RoundRectangle2D.Double(firstPoint.getX() - margin, firstPoint.getY() - margin, 2 * margin, 2 * margin - + spacing, margin, margin); - break; - case SPDT: - case SPDT_off: - body = - new RoundRectangle2D.Double(firstPoint.getX() - margin, firstPoint.getY() - margin, 2 * margin, 2 * margin + 2 - * spacing, margin, margin); - break; - case DPDT: - case DPDT_off: - case DPDT_ononon_1: - case DPDT_ononon_2: - body = - new RoundRectangle2D.Double(firstPoint.getX() - margin, firstPoint.getY() - margin, 2 * margin + spacing, 2 - * margin + 2 * spacing, margin, margin); - break; - case _3PDT: - case _3PDT_off: - body = - new RoundRectangle2D.Double(firstPoint.getX() - margin, firstPoint.getY() - margin, 2 * margin + 2 * spacing, 2 - * margin + 2 * spacing, margin, margin); - break; - case _4PDT: - case _4PDT_off: - case _4PDT_ononon_1: - case _4PDT_ononon_2: - body = - new RoundRectangle2D.Double(firstPoint.getX() - margin, firstPoint.getY() - margin, 2 * margin + 3 * spacing, 2 - * margin + 2 * spacing, margin, margin); - break; - case _5PDT: - case _5PDT_off: - body = - new RoundRectangle2D.Double(firstPoint.getX() - margin, firstPoint.getY() - margin, 2 * margin + 4 * spacing, 2 - * margin + 2 * spacing, margin, margin); - break; - } - if (getOrientation() == OrientationHV.HORIZONTAL) { - AffineTransform xform = AffineTransform.getRotateInstance(-Math.PI / 2, firstPoint.getX(), firstPoint.getY()); - body = new Area(body); - ((Area) body).transform(xform); - } - } - return body; - } - - @Override - public void drawIcon(Graphics2D g2d, int width, int height) { - int circleSize = 5 * width / 32; - g2d.setColor(BODY_COLOR); - g2d.fillRoundRect(width / 4, 1, width / 2, height - 2, circleSize, circleSize); - g2d.setColor(BORDER_COLOR); - g2d.drawRoundRect(width / 4, 1, width / 2, height - 2, circleSize, circleSize); - for (int i = 1; i <= 3; i++) { - g2d.setColor(LIGHT_METAL_COLOR); - g2d.fillOval(width / 2 - circleSize / 2, i * height / 4 - 3, circleSize, circleSize); - g2d.setColor(METAL_COLOR); - g2d.drawLine(width / 2 - circleSize / 2 + 1, i * height / 4 - 1, width / 2 + circleSize / 2 - 1, i * height / 4 - - 1); - } - } - - @EditableProperty(name = "Body") - public Color getBodyColor() { - if (bodyColor == null) - bodyColor = BODY_COLOR; - return bodyColor; - } - - public void setBodyColor(Color bodyColor) { - this.bodyColor = bodyColor; - } - - @EditableProperty(name = "Border") - public Color getBorderColor() { - if (borderColor == null) - borderColor = BORDER_COLOR; - return borderColor; - } - - public void setBorderColor(Color borderColor) { - this.borderColor = borderColor; - } - - @EditableProperty(name = "Pad") - public Color getTerminalPadColor() { - if (terminalPadColor == null) { - terminalPadColor = CIRCLE_COLOR; - } - return terminalPadColor; - } - - public void setTerminalPadColor(Color terminalPadColor) { - this.terminalPadColor = terminalPadColor; - } - - @EditableProperty(name = "Terminal") - public Color getTerminalColor() { - if (terminalColor == null) { - terminalColor = TERMINAL_COLOR; - } - return terminalColor; - } - - public void setTerminalColor(Color terminalColor) { - this.terminalColor = terminalColor; - } - - // switch stuff -// -// @Override -// public String getControlPointNodeName(int index) { -// // we don't want the switch to produce any nodes, it just makes connections -// return null; -// } - - @Override - public boolean canPointMoveFreely(int pointIndex) { - return false; - } - - @Override - public int getPositionCount() { - return switchType.getPositionCount(); - } - - @Override - public String getPositionName(int position) { - int pos = position; - if (switchType.name().endsWith("_off")) { - int midPosition = (getPositionCount() - 1) / 2; - if (position == midPosition) { - return "OFF"; - } else if (position > midPosition) { - --pos; - } - } - return "ON" + Integer.toString(pos + 1); - } - - @DynamicEditableProperty(source = ToggleSwitchPositionPropertyValueSource.class) - @EditableProperty(name = "Selected Position") - @Override - public Integer getSelectedPosition() { - return selectedPosition; - } - - public void setSelectedPosition(Integer selectedPosition) { - this.selectedPosition = selectedPosition; - } - - @EditableProperty(name = "Markers") - public Boolean getShowMarkers() { - if (showMarkers == null) { - showMarkers = false; - } - return showMarkers; - } - - public void setShowMarkers(Boolean showMarkers) { - this.showMarkers = showMarkers; - } - - @Override - public boolean arePointsConnected(int index1, int index2, int position) { - if (index1 >= index2) - return false; - - switch (switchType) { - case SPST: - return position == 0; - case SPDT: - case DPDT: - case _3PDT: - case _4PDT: - case _5PDT: - return (index2 - index1) < 3 && index1 % 3 == position && index2 % 3 == position + 1; - case SPDT_off: - case DPDT_off: - case _3PDT_off: - case _4PDT_off: - case _5PDT_off: - if (position == 1) - return false; - if (position == 2) - position = 1; - return (index2 - index1) < 3 && index1 % 3 == position && index2 % 3 == position + 1; - case DPDT_ononon_1: - switch (position) { - case 0: - return (index1 == 0 && index2 == 1) || (index1 == 3 && index2 == 4); - case 1: - return (index1 == 0 && index2 == 1) || (index1 == 4 && index2 == 5); - case 2: - return (index1 == 1 && index2 == 2) || (index1 == 4 && index2 == 5); - default: return false; - } - case DPDT_ononon_2: - switch (position) { - case 0: - return (index1 == 0 && index2 == 1) || (index1 == 3 && index2 == 4); - case 1: - return (index1 == 1 && index2 == 2) || (index1 == 3 && index2 == 4); - case 2: - return (index1 == 1 && index2 == 2) || (index1 == 4 && index2 == 5); - default: return false; - } - case _4PDT_ononon_1: - switch (position) { - case 0: - return (index1 == 0 && index2 == 1) || (index1 == 3 && index2 == 4) || (index1 == 6 && index2 == 7) || (index1 == 9 && index2 == 10); - case 1: - return (index1 == 0 && index2 == 1) || (index1 == 4 && index2 == 5) || (index1 == 6 && index2 == 7) || (index1 == 10 && index2 == 11); - case 2: - return (index1 == 1 && index2 == 2) || (index1 == 4 && index2 == 5) || (index1 == 7 && index2 == 8) || (index1 == 10 && index2 == 11); - default: return false; - } - case _4PDT_ononon_2: - switch (position) { - case 0: - return (index1 == 0 && index2 == 1) || (index1 == 3 && index2 == 4) || (index1 == 6 && index2 == 7) || (index1 == 9 && index2 == 10); - case 1: - return (index1 == 1 && index2 == 2) || (index1 == 3 && index2 == 4) || (index1 == 7 && index2 == 8) || (index1 == 9 && index2 == 10); - case 2: - return (index1 == 1 && index2 == 2) || (index1 == 4 && index2 == 5) || (index1 == 7 && index2 == 8) || (index1 == 10 && index2 == 11); - default: return false; - } - } - return false; - } - - @Override - public Rectangle2D getCachingBounds() { - int margin = 20; - Rectangle2D bounds = getBody().getBounds2D(); - return new Rectangle2D.Double(bounds.getX() - margin, bounds.getY() - margin, bounds.getWidth() + 2 * margin, bounds.getHeight() + 2 * margin); - } - - @Override - public int getLayerId() { - return hashCode(); - } -} +/* + + DIY Layout Creator (DIYLC). + Copyright (c) 2009-2025 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.electromechanical; + +import java.awt.AlphaComposite; +import java.awt.Color; +import java.awt.Composite; +import java.awt.Graphics2D; +import java.awt.Shape; +import java.awt.geom.AffineTransform; +import java.awt.geom.Area; +import java.awt.geom.Point2D; +import java.awt.geom.Rectangle2D; +import java.awt.geom.RoundRectangle2D; + +import org.diylc.appframework.miscutils.ConfigurationManager; + +import org.diylc.awt.StringUtils; +import org.diylc.common.*; +import org.diylc.components.AbstractTransparentComponent; +import org.diylc.components.guitar.ToggleSwitchPositionPropertyValueSource; +import org.diylc.components.transform.MiniToggleSwitchTransformer; +import org.diylc.core.ComponentState; +import org.diylc.core.IDIYComponent; +import org.diylc.core.IDrawingObserver; +import org.diylc.core.ILayeredComponent; +import org.diylc.core.ISwitch; +import org.diylc.core.Project; +import org.diylc.core.Theme; +import org.diylc.core.VisibilityPolicy; +import org.diylc.core.annotations.ComponentDescriptor; +import org.diylc.core.annotations.DynamicEditableProperty; +import org.diylc.core.annotations.EditableProperty; +import org.diylc.core.annotations.PositiveNonZeroMeasureValidator; +import org.diylc.core.gerber.IGerberComponentSimple; +import org.diylc.core.measures.Size; +import org.diylc.core.measures.SizeUnit; +import org.diylc.utils.Constants; +import org.diylc.utils.SwitchUtils; + +@ComponentDescriptor(name = "Mini Toggle Switch", category = "Electro-Mechanical", author = "Branislav Stojkovic", + description = "Panel mounted mini toggle switch", zOrder = IDIYComponent.COMPONENT, + instanceNamePrefix = "SW", enableCache = true, transformer = MiniToggleSwitchTransformer.class) +public class MiniToggleSwitch extends AbstractTransparentComponent implements ISwitch, ILayeredComponent, IGerberComponentSimple { + + private static final long serialVersionUID = 1L; + + private static Size SPACING = new Size(0.2d, SizeUnit.in); + private static Size MARGIN = new Size(0.08d, SizeUnit.in); + private static Size CIRCLE_SIZE = new Size(0.09d, SizeUnit.in); + private static Size LUG_WIDTH = new Size(0.060d, SizeUnit.in); + private static Size LUG_THICKNESS = new Size(0.02d, SizeUnit.in); + private static Size MARKER_OFFSET = new Size(0.07d, SizeUnit.in); + + private static Color BODY_COLOR = Color.decode("#3299CC"); + private static Color BORDER_COLOR = BODY_COLOR.darker(); + private static Color CIRCLE_COLOR = Color.decode("#287ba4"); + private static Color TERMINAL_COLOR = LIGHT_METAL_COLOR; + private static Color MARKER_COLOR = LIGHT_METAL_COLOR; + + + protected Point2D[] controlPoints = new Point2D[] {new Point2D.Double(0, 0)}; + transient protected Shape body; + protected ToggleSwitchType switchType = ToggleSwitchType.DPDT; + private OrientationHV orientation = OrientationHV.VERTICAL; + private Size spacing = SPACING; + + private Color bodyColor = BODY_COLOR; + private Color borderColor = BORDER_COLOR; + private Color terminalPadColor = CIRCLE_COLOR; + private Color terminalColor = TERMINAL_COLOR; + + private Integer selectedPosition; + private Boolean showMarkers; + + @Deprecated + protected String name; + + public MiniToggleSwitch() { + super(); + updateControlPoints(); + } + + private void updateControlPoints() { + Point2D firstPoint = controlPoints[0]; + int spacing = (int) getSpacing().convertToPixels(); + switch (switchType) { + case SPST: + controlPoints = new Point2D[] {firstPoint, new Point2D.Double(firstPoint.getX(), firstPoint.getY() + spacing)}; + break; + case SPDT: + case SPDT_off: + controlPoints = + new Point2D[] {firstPoint, new Point2D.Double(firstPoint.getX(), firstPoint.getY() + spacing), + new Point2D.Double(firstPoint.getX(), firstPoint.getY() + 2 * spacing)}; + break; + case DPDT: + case DPDT_off: + case DPDT_ononon_1: + case DPDT_ononon_2: + controlPoints = + new Point2D[] {firstPoint, new Point2D.Double(firstPoint.getX(), firstPoint.getY() + spacing), + new Point2D.Double(firstPoint.getX(), firstPoint.getY() + 2 * spacing), + new Point2D.Double(firstPoint.getX() + spacing, firstPoint.getY()), + new Point2D.Double(firstPoint.getX() + spacing, firstPoint.getY() + spacing), + new Point2D.Double(firstPoint.getX() + spacing, firstPoint.getY() + 2 * spacing)}; + break; + case _3PDT: + case _3PDT_off: + controlPoints = + new Point2D[] {firstPoint, new Point2D.Double(firstPoint.getX(), firstPoint.getY() + spacing), + new Point2D.Double(firstPoint.getX(), firstPoint.getY() + 2 * spacing), + new Point2D.Double(firstPoint.getX() + spacing, firstPoint.getY()), + new Point2D.Double(firstPoint.getX() + spacing, firstPoint.getY() + spacing), + new Point2D.Double(firstPoint.getX() + spacing, firstPoint.getY() + 2 * spacing), + new Point2D.Double(firstPoint.getX() + 2 * spacing, firstPoint.getY()), + new Point2D.Double(firstPoint.getX() + 2 * spacing, firstPoint.getY() + spacing), + new Point2D.Double(firstPoint.getX() + 2 * spacing, firstPoint.getY() + 2 * spacing)}; + break; + case _4PDT: + case _4PDT_off: + case _4PDT_ononon_1: + case _4PDT_ononon_2: + controlPoints = + new Point2D[] {firstPoint, new Point2D.Double(firstPoint.getX(), firstPoint.getY() + spacing), + new Point2D.Double(firstPoint.getX(), firstPoint.getY() + 2 * spacing), + new Point2D.Double(firstPoint.getX() + spacing, firstPoint.getY()), + new Point2D.Double(firstPoint.getX() + spacing, firstPoint.getY() + spacing), + new Point2D.Double(firstPoint.getX() + spacing, firstPoint.getY() + 2 * spacing), + new Point2D.Double(firstPoint.getX() + 2 * spacing, firstPoint.getY()), + new Point2D.Double(firstPoint.getX() + 2 * spacing, firstPoint.getY() + spacing), + new Point2D.Double(firstPoint.getX() + 2 * spacing, firstPoint.getY() + 2 * spacing), + new Point2D.Double(firstPoint.getX() + 3 * spacing, firstPoint.getY()), + new Point2D.Double(firstPoint.getX() + 3 * spacing, firstPoint.getY() + spacing), + new Point2D.Double(firstPoint.getX() + 3 * spacing, firstPoint.getY() + 2 * spacing)}; + break; + case _5PDT: + case _5PDT_off: + controlPoints = + new Point2D[] {firstPoint, new Point2D.Double(firstPoint.getX(), firstPoint.getY() + spacing), + new Point2D.Double(firstPoint.getX(), firstPoint.getY() + 2 * spacing), + new Point2D.Double(firstPoint.getX() + spacing, firstPoint.getY()), + new Point2D.Double(firstPoint.getX() + spacing, firstPoint.getY() + spacing), + new Point2D.Double(firstPoint.getX() + spacing, firstPoint.getY() + 2 * spacing), + new Point2D.Double(firstPoint.getX() + 2 * spacing, firstPoint.getY()), + new Point2D.Double(firstPoint.getX() + 2 * spacing, firstPoint.getY() + spacing), + new Point2D.Double(firstPoint.getX() + 2 * spacing, firstPoint.getY() + 2 * spacing), + new Point2D.Double(firstPoint.getX() + 3 * spacing, firstPoint.getY()), + new Point2D.Double(firstPoint.getX() + 3 * spacing, firstPoint.getY() + spacing), + new Point2D.Double(firstPoint.getX() + 3 * spacing, firstPoint.getY() + 2 * spacing), + new Point2D.Double(firstPoint.getX() + 4 * spacing, firstPoint.getY()), + new Point2D.Double(firstPoint.getX() + 4 * spacing, firstPoint.getY() + spacing), + new Point2D.Double(firstPoint.getX() + 4 * spacing, firstPoint.getY() + 2 * spacing)}; + break; + } + AffineTransform xform = AffineTransform.getRotateInstance(-Math.PI / 2, firstPoint.getX(), firstPoint.getY()); + if (getOrientation() == OrientationHV.HORIZONTAL) { + for (int i = 1; i < controlPoints.length; i++) { + xform.transform(controlPoints[i], controlPoints[i]); + } + } + } + + @Override + public Point2D getControlPoint(int index) { + return controlPoints[index]; + } + + @Override + public boolean isControlPointSticky(int index) { + return true; + } + + @Override + public VisibilityPolicy getControlPointVisibilityPolicy(int index) { + return VisibilityPolicy.NEVER; + } + + @Override + public int getControlPointCount() { + return controlPoints.length; + } + + @Override + public void setControlPoint(Point2D point, int index) { + controlPoints[index].setLocation(point); + // Reset body shape. + body = null; + } + + @EditableProperty(defaultable = false) + @Override + public String getName() { + if (super.name == null || super.name.trim().isEmpty()) { + super.name = name; + name = null; + } + return super.name; + } + + @Override + public void setName(String name) { + super.name = name; + this.name = null; + } + + @EditableProperty(name = "Type") + @Override + public ToggleSwitchType getValue() { + return switchType; + } + + @Override + public void setValue(ToggleSwitchType value) { + this.switchType = value; + updateControlPoints(); + // Reset body shape. + body = null; + } + + @EditableProperty + public OrientationHV getOrientation() { + if (orientation == null) { + orientation = OrientationHV.VERTICAL; + } + return orientation; + } + + public void setOrientation(OrientationHV orientation) { + this.orientation = orientation; + updateControlPoints(); + // Reset body shape. + body = null; + } + + @EditableProperty(validatorClass = PositiveNonZeroMeasureValidator.class) + public Size getSpacing() { + if (spacing == null) { + spacing = SPACING; + } + return spacing; + } + + public void setSpacing(Size spacing) { + this.spacing = spacing; + updateControlPoints(); + // Reset body shape. + body = null; + } + + @Override + public void draw(Graphics2D g2d, ComponentState componentState, boolean outlineMode, Project project, + IDrawingObserver drawingObserver) { + if (checkPointsClipped(g2d.getClip())) { + return; + } + Shape body = getBody(); + Theme theme = (Theme) ConfigurationManager.getInstance().readObject(IPlugInPort.THEME_KEY, Constants.DEFAULT_THEME); + // Draw body if available. + if (body != null) { + Composite oldComposite = applyAlpha(g2d, componentState); + g2d.setColor(outlineMode ? Constants.TRANSPARENT_COLOR : getBodyColor()); + g2d.fill(body); + g2d.setComposite(oldComposite); + g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(1)); + Color finalBorderColor; + if (outlineMode) { + finalBorderColor = + componentState == ComponentState.SELECTED || componentState == ComponentState.DRAGGING ? SELECTION_COLOR + : theme.getOutlineColor(); + } else { + finalBorderColor = + componentState == ComponentState.SELECTED || componentState == ComponentState.DRAGGING ? SELECTION_COLOR + : getBorderColor(); + } + g2d.setColor(finalBorderColor); + g2d.draw(body); + } + // Do not track these changes because the whole switch has been tracked + // so far. + drawingObserver.stopTracking(); + // Draw lugs. + int circleDiameter = getClosestOdd((int) CIRCLE_SIZE.convertToPixels()); + + int lugWidth; + int lugHeight; + + if (getOrientation() == OrientationHV.HORIZONTAL) { + lugHeight = getClosestOdd((int) LUG_WIDTH.convertToPixels()); + lugWidth = getClosestOdd((int) LUG_THICKNESS.convertToPixels()); + } else { + lugWidth = getClosestOdd((int) LUG_WIDTH.convertToPixels()); + lugHeight = getClosestOdd((int) LUG_THICKNESS.convertToPixels()); + } + + for (int i = 0; i < controlPoints.length; i++) { + Point2D p = controlPoints[i]; + if (outlineMode) { +// g2d.setColor(Constants.TRANSPARENT_COLOR); +// drawingObserver.startTrackingContinuityArea(true); +// g2d.fillRect((int)(p.getX() - lugWidth / 2), (int)(p.getY() - lugHeight / 2), lugWidth, lugHeight); +// drawingObserver.stopTrackingContinuityArea(); + + g2d.setColor(theme.getOutlineColor()); + g2d.drawRect((int)(p.getX() - lugWidth / 2d), (int)(p.getY() - lugHeight / 2d), lugWidth, lugHeight); + } else { + g2d.setColor(getTerminalPadColor().darker()); + + g2d.drawOval((int)(p.getX() - circleDiameter / 2d), (int)(p.getY() - circleDiameter / 2d), circleDiameter, circleDiameter); + + g2d.setColor(getTerminalPadColor()); + g2d.fillOval((int)(p.getX() - circleDiameter / 2d), (int)(p.getY() - circleDiameter / 2d), circleDiameter, circleDiameter); + g2d.setColor(getTerminalColor()); +// drawingObserver.startTrackingContinuityArea(true); + g2d.fillRect((int)(p.getX() - lugWidth / 2d), (int)(p.getY() - lugHeight / 2d), lugWidth, lugHeight); +// drawingObserver.stopTrackingContinuityArea(); + } + } + + if (getShowMarkers()) { + String[] markers = + SwitchUtils.getSwitchingMarkers(this, getControlPointCount(), false); + + g2d.setColor(MARKER_COLOR); + + double offset = MARKER_OFFSET.convertToPixels(); + for (int i = 0; i < getControlPointCount(); i++) { + if (markers[i] == null) + continue; + + Point2D p = getControlPoint(i); + Point2D labelPoint = new Point2D.Double(offset, 0); + + AffineTransform tx = null; + if (getOrientation() == OrientationHV.HORIZONTAL) { + tx = AffineTransform.getRotateInstance(-Math.PI / 2, 0, 0); + } + if (tx != null) { + tx.transform(labelPoint, labelPoint); + } + StringUtils.drawCenteredText(g2d, markers[i], p.getX() + labelPoint.getX(), p.getY() + labelPoint.getY(), + HorizontalAlignment.CENTER, VerticalAlignment.CENTER); + } + } + } + + public Shape getBody() { + if (body == null) { + Point2D firstPoint = controlPoints[0]; + int margin = (int) MARGIN.convertToPixels(); + int spacing = (int) getSpacing().convertToPixels(); + switch (switchType) { + case SPST: + body = + new RoundRectangle2D.Double(firstPoint.getX() - margin, firstPoint.getY() - margin, 2 * margin, 2 * margin + + spacing, margin, margin); + break; + case SPDT: + case SPDT_off: + body = + new RoundRectangle2D.Double(firstPoint.getX() - margin, firstPoint.getY() - margin, 2 * margin, 2 * margin + 2 + * spacing, margin, margin); + break; + case DPDT: + case DPDT_off: + case DPDT_ononon_1: + case DPDT_ononon_2: + body = + new RoundRectangle2D.Double(firstPoint.getX() - margin, firstPoint.getY() - margin, 2 * margin + spacing, 2 + * margin + 2 * spacing, margin, margin); + break; + case _3PDT: + case _3PDT_off: + body = + new RoundRectangle2D.Double(firstPoint.getX() - margin, firstPoint.getY() - margin, 2 * margin + 2 * spacing, 2 + * margin + 2 * spacing, margin, margin); + break; + case _4PDT: + case _4PDT_off: + case _4PDT_ononon_1: + case _4PDT_ononon_2: + body = + new RoundRectangle2D.Double(firstPoint.getX() - margin, firstPoint.getY() - margin, 2 * margin + 3 * spacing, 2 + * margin + 2 * spacing, margin, margin); + break; + case _5PDT: + case _5PDT_off: + body = + new RoundRectangle2D.Double(firstPoint.getX() - margin, firstPoint.getY() - margin, 2 * margin + 4 * spacing, 2 + * margin + 2 * spacing, margin, margin); + break; + } + if (getOrientation() == OrientationHV.HORIZONTAL) { + AffineTransform xform = AffineTransform.getRotateInstance(-Math.PI / 2, firstPoint.getX(), firstPoint.getY()); + body = new Area(body); + ((Area) body).transform(xform); + } + } + return body; + } + + @Override + public void drawIcon(Graphics2D g2d, int width, int height) { + int circleSize = 5 * width / 32; + g2d.setColor(BODY_COLOR); + g2d.fillRoundRect(width / 4, 1, width / 2, height - 2, circleSize, circleSize); + g2d.setColor(BORDER_COLOR); + g2d.drawRoundRect(width / 4, 1, width / 2, height - 2, circleSize, circleSize); + for (int i = 1; i <= 3; i++) { + g2d.setColor(LIGHT_METAL_COLOR); + g2d.fillOval(width / 2 - circleSize / 2, i * height / 4 - 3, circleSize, circleSize); + g2d.setColor(METAL_COLOR); + g2d.drawLine(width / 2 - circleSize / 2 + 1, i * height / 4 - 1, width / 2 + circleSize / 2 - 1, i * height / 4 + - 1); + } + } + + @EditableProperty(name = "Body") + public Color getBodyColor() { + if (bodyColor == null) + bodyColor = BODY_COLOR; + return bodyColor; + } + + public void setBodyColor(Color bodyColor) { + this.bodyColor = bodyColor; + } + + @EditableProperty(name = "Border") + public Color getBorderColor() { + if (borderColor == null) + borderColor = BORDER_COLOR; + return borderColor; + } + + public void setBorderColor(Color borderColor) { + this.borderColor = borderColor; + } + + @EditableProperty(name = "Pad") + public Color getTerminalPadColor() { + if (terminalPadColor == null) { + terminalPadColor = CIRCLE_COLOR; + } + return terminalPadColor; + } + + public void setTerminalPadColor(Color terminalPadColor) { + this.terminalPadColor = terminalPadColor; + } + + @EditableProperty(name = "Terminal") + public Color getTerminalColor() { + if (terminalColor == null) { + terminalColor = TERMINAL_COLOR; + } + return terminalColor; + } + + public void setTerminalColor(Color terminalColor) { + this.terminalColor = terminalColor; + } + + // switch stuff +// +// @Override +// public String getControlPointNodeName(int index) { +// // we don't want the switch to produce any nodes, it just makes connections +// return null; +// } + + @Override + public boolean canPointMoveFreely(int pointIndex) { + return false; + } + + @Override + public int getPositionCount() { + return switchType.getPositionCount(); + } + + @Override + public String getPositionName(int position) { + int pos = position; + if (switchType.name().endsWith("_off")) { + int midPosition = (getPositionCount() - 1) / 2; + if (position == midPosition) { + return "OFF"; + } else if (position > midPosition) { + --pos; + } + } + return "ON" + Integer.toString(pos + 1); + } + + @DynamicEditableProperty(source = ToggleSwitchPositionPropertyValueSource.class) + @EditableProperty(name = "Selected Position") + @Override + public Integer getSelectedPosition() { + return selectedPosition; + } + + public void setSelectedPosition(Integer selectedPosition) { + this.selectedPosition = selectedPosition; + } + + @EditableProperty(name = "Markers") + public Boolean getShowMarkers() { + if (showMarkers == null) { + showMarkers = false; + } + return showMarkers; + } + + public void setShowMarkers(Boolean showMarkers) { + this.showMarkers = showMarkers; + } + + @Override + public boolean arePointsConnected(int index1, int index2, int position) { + if (index1 >= index2) + return false; + + switch (switchType) { + case SPST: + return position == 0; + case SPDT: + case DPDT: + case _3PDT: + case _4PDT: + case _5PDT: + return (index2 - index1) < 3 && index1 % 3 == position && index2 % 3 == position + 1; + case SPDT_off: + case DPDT_off: + case _3PDT_off: + case _4PDT_off: + case _5PDT_off: + if (position == 1) + return false; + if (position == 2) + position = 1; + return (index2 - index1) < 3 && index1 % 3 == position && index2 % 3 == position + 1; + case DPDT_ononon_1: + switch (position) { + case 0: + return (index1 == 0 && index2 == 1) || (index1 == 3 && index2 == 4); + case 1: + return (index1 == 0 && index2 == 1) || (index1 == 4 && index2 == 5); + case 2: + return (index1 == 1 && index2 == 2) || (index1 == 4 && index2 == 5); + default: return false; + } + case DPDT_ononon_2: + switch (position) { + case 0: + return (index1 == 0 && index2 == 1) || (index1 == 3 && index2 == 4); + case 1: + return (index1 == 1 && index2 == 2) || (index1 == 3 && index2 == 4); + case 2: + return (index1 == 1 && index2 == 2) || (index1 == 4 && index2 == 5); + default: return false; + } + case _4PDT_ononon_1: + switch (position) { + case 0: + return (index1 == 0 && index2 == 1) || (index1 == 3 && index2 == 4) || (index1 == 6 && index2 == 7) || (index1 == 9 && index2 == 10); + case 1: + return (index1 == 0 && index2 == 1) || (index1 == 4 && index2 == 5) || (index1 == 6 && index2 == 7) || (index1 == 10 && index2 == 11); + case 2: + return (index1 == 1 && index2 == 2) || (index1 == 4 && index2 == 5) || (index1 == 7 && index2 == 8) || (index1 == 10 && index2 == 11); + default: return false; + } + case _4PDT_ononon_2: + switch (position) { + case 0: + return (index1 == 0 && index2 == 1) || (index1 == 3 && index2 == 4) || (index1 == 6 && index2 == 7) || (index1 == 9 && index2 == 10); + case 1: + return (index1 == 1 && index2 == 2) || (index1 == 3 && index2 == 4) || (index1 == 7 && index2 == 8) || (index1 == 9 && index2 == 10); + case 2: + return (index1 == 1 && index2 == 2) || (index1 == 4 && index2 == 5) || (index1 == 7 && index2 == 8) || (index1 == 10 && index2 == 11); + default: return false; + } + } + return false; + } + + @Override + public Rectangle2D getCachingBounds() { + int margin = 20; + Rectangle2D bounds = getBody().getBounds2D(); + return new Rectangle2D.Double(bounds.getX() - margin, bounds.getY() - margin, bounds.getWidth() + 2 * margin, bounds.getHeight() + 2 * margin); + } + + @Override + public int getLayerId() { + return hashCode(); + } +} diff --git a/diylc/diylc-library/src/main/java/org/diylc/components/electromechanical/NeutrikJack1_4.java b/diylc/diylc-library/src/main/java/org/diylc/components/electromechanical/NeutrikJack1_4.java index 9dac807ef..0eb895e21 100644 --- a/diylc/diylc-library/src/main/java/org/diylc/components/electromechanical/NeutrikJack1_4.java +++ b/diylc/diylc-library/src/main/java/org/diylc/components/electromechanical/NeutrikJack1_4.java @@ -1,375 +1,372 @@ -/* - - DIY Layout Creator (DIYLC). - Copyright (c) 2009-2025 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.electromechanical; - -import java.awt.AlphaComposite; -import java.awt.Color; -import java.awt.Composite; -import java.awt.Graphics2D; -import java.awt.Shape; -import java.awt.geom.AffineTransform; -import java.awt.geom.Area; -import java.awt.geom.Ellipse2D; -import java.awt.geom.Point2D; -import java.awt.geom.Rectangle2D; -import java.awt.geom.RoundRectangle2D; -import org.diylc.appframework.miscutils.ConfigurationManager; - -import org.diylc.awt.StringUtils; -import org.diylc.common.HorizontalAlignment; -import org.diylc.common.IPlugInPort; -import org.diylc.common.ObjectCache; -import org.diylc.common.Orientation; -import org.diylc.common.VerticalAlignment; -import org.diylc.components.AbstractMultiPartComponent; -import org.diylc.components.transform.NeutrikJack1_4Transformer; -import org.diylc.core.ComponentState; -import org.diylc.core.IDIYComponent; -import org.diylc.core.IDrawingObserver; -import org.diylc.core.Project; -import org.diylc.core.Theme; -import org.diylc.core.VisibilityPolicy; -import org.diylc.core.annotations.ComponentDescriptor; -import org.diylc.core.annotations.EditableProperty; -import org.diylc.core.measures.Size; -import org.diylc.core.measures.SizeUnit; -import org.diylc.utils.Constants; - -@ComponentDescriptor(name = "Neutrik 1/4\" Jack", category = "Electro-Mechanical", author = "Branislav Stojkovic", - description = "1/4\" mono/stereo phono jack based on Neutrik NMJx series, PCB or Panel-mount", - zOrder = IDIYComponent.COMPONENT, instanceNamePrefix = "J", transformer = NeutrikJack1_4Transformer.class, - enableCache = true) -public class NeutrikJack1_4 extends AbstractMultiPartComponent { - - private static final long serialVersionUID = 1L; - - private static Size X_SPACING = new Size(0.25d, SizeUnit.in); - private static Size Y_SPACING = new Size(16.23d, SizeUnit.mm); - private static Size PIN_WIDTH = new Size(0.1d, SizeUnit.in); - private static Size PIN_THICKNESS = new Size(0.02d, SizeUnit.in); - private static Size PIN_DIAMETER = new Size(1.4d, SizeUnit.mm); - private static Size PIN_OFFSET_MONO = new Size(-6.27d, SizeUnit.mm); - private static Size PIN_OFFSET_STEREO = new Size(-7.72d, SizeUnit.mm); - private static Color BODY_COLOR = Color.decode("#666666"); - private static Color NUT_COLOR = Color.decode("#999999"); - private static Color BORDER_COLOR = Color.black; - private static Color LABEL_COLOR = Color.white; - private static Size BODY_WIDTH = new Size(18.2, SizeUnit.mm); - private static Size BODY_LENGTH = new Size(20.6d, SizeUnit.mm); - private static Size TAIL_LENGTH = new Size(0.1d, SizeUnit.in); - - private Point2D[] controlPoints = new Point2D[] {new Point2D.Double(0, 0)}; - private JackType type = JackType.MONO; - private Mount mount = Mount.Panel; - private Orientation orientation = Orientation.DEFAULT; - transient private Area[] body; - @SuppressWarnings("unused") - @Deprecated - private transient String value = ""; - - - public NeutrikJack1_4() { - super(); - updateControlPoints(); - } - - private void updateControlPoints() { - // invalidate body shape - body = null; - double x = controlPoints[0].getX(); - double y = controlPoints[0].getY(); - int xSpacing = (int) X_SPACING.convertToPixels(); - int ySpacing = (int) Y_SPACING.convertToPixels(); - controlPoints = new Point2D[type == JackType.STEREO ? 6 : 4]; - - controlPoints[0] = new Point2D.Double(x, y); - controlPoints[1] = new Point2D.Double(x, y + ySpacing); - controlPoints[2] = new Point2D.Double(x + 2 * xSpacing, y); - controlPoints[3] = new Point2D.Double(x + 2 * xSpacing, y + ySpacing); - if (type == JackType.STEREO) { - controlPoints[4] = new Point2D.Double(x + xSpacing, y); - controlPoints[5] = new Point2D.Double(x + xSpacing, y + ySpacing); - } - - // Apply rotation if necessary - double angle = getAngle(); - if (angle != 0) { - AffineTransform rotation = AffineTransform.getRotateInstance(angle, x, y); - for (int i = 1; i < controlPoints.length; i++) { - rotation.transform(controlPoints[i], controlPoints[i]); - } - } - } - - private double getAngle() { - // Apply rotation if necessary - double angle; - switch (orientation) { - case _90: - angle = Math.PI / 2; - break; - case _180: - angle = Math.PI; - break; - case _270: - angle = Math.PI * 3 / 2; - break; - default: - angle = 0; - } - - return angle; - } - - public Area[] getBody() { - if (body == null) { - body = new Area[5]; - - // Create body. - int bodyLength = (int) BODY_LENGTH.convertToPixels(); - int bodyWidth = (int) BODY_WIDTH.convertToPixels(); - int offset = (int)(type == JackType.MONO ? PIN_OFFSET_MONO : PIN_OFFSET_STEREO).convertToPixels(); - int xSpacing = (int) X_SPACING.convertToPixels(); - int ySpacing = (int) Y_SPACING.convertToPixels(); - double centerX = controlPoints[0].getX() + 2 * xSpacing + offset; - double centerY = controlPoints[0].getY() + ySpacing / 2; - body[0] = new Area(new Rectangle2D.Double(centerX - bodyLength / 2, centerY - bodyWidth / 2, bodyLength, bodyWidth)); - - int tailLength = (int) TAIL_LENGTH.convertToPixels(); - body[1] = new Area(new RoundRectangle2D.Double(centerX - bodyLength / 2 - tailLength, centerY - bodyWidth / 4, tailLength * 2, - bodyWidth / 2, tailLength, tailLength)); - Area tailArea = new Area(body[1]); - tailArea.subtract(new Area(body[0])); - body[1] = tailArea; - - body[2] = new Area(new Rectangle2D.Double(centerX + bodyLength / 2, centerY - bodyWidth / 4, tailLength, bodyWidth / 2)); - - body[3] = new Area(new Rectangle2D.Double(centerX + bodyLength / 2 + tailLength, centerY - bodyWidth / 4, tailLength, bodyWidth / 2)); - tailArea = new Area(body[3]); - int radius = bodyLength / 2 + tailLength * 2; - tailArea.intersect(new Area(new Ellipse2D.Double(centerX - radius, centerY - radius, radius * 2, radius * 2))); - body[3] = tailArea; - - // Apply rotation if necessary - double angle = getAngle(); - if (angle != 0) { - AffineTransform rotation = AffineTransform.getRotateInstance(angle, controlPoints[0].getX(), controlPoints[0].getY()); - for (int i = 0; i < body.length; i++) { - if (body[i] != null) { - Area area = new Area(body[i]); - area.transform(rotation); - body[i] = area; - } - } - } - - // Create pins. - Area pins = new Area(); - - int pinWidth = (int) PIN_WIDTH.convertToPixels(); - int pinThickness = (int) PIN_THICKNESS.convertToPixels(); - int pinDiameter = (int) PIN_DIAMETER.convertToPixels(); - for (int i = 0; i < getControlPointCount(); i++) { - Point2D point = getControlPoint(i); - Shape pin; - if (mount == Mount.PCB) { - pin = new Ellipse2D.Double(point.getX() - pinDiameter / 2, point.getY() - pinDiameter / 2, pinDiameter, pinDiameter); - } else { - if (orientation == Orientation.DEFAULT || orientation == Orientation._180) { - pin = new Rectangle2D.Double(point.getX() - pinWidth / 2, point.getY() - pinThickness / 2, pinWidth, pinThickness); - } else { - pin = new Rectangle2D.Double(point.getX() - pinThickness / 2, point.getY() - pinWidth / 2, pinThickness, pinWidth); - } - } - pins.add(new Area(pin)); - } - - body[4] = pins; - } - return body; - } - - @Override - public void draw(Graphics2D g2d, ComponentState componentState, boolean outlineMode, Project project, - IDrawingObserver drawingObserver) { - Shape[] body = getBody(); - - g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(1)); -// if (componentState != ComponentState.DRAGGING) { - 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 : BODY_COLOR); - for (int i = 0; i < body.length - 1; i++) { - // Nut is brighter colored. - if (i == body.length - 2) - g2d.setColor(outlineMode ? Constants.TRANSPARENT_COLOR : NUT_COLOR); - g2d.fill(body[i]); - } - g2d.setComposite(oldComposite); -// } - - Color finalBorderColor; - Theme theme = (Theme) ConfigurationManager.getInstance().readObject(IPlugInPort.THEME_KEY, Constants.DEFAULT_THEME); - if (outlineMode) { - finalBorderColor = theme.getOutlineColor(); - } else { - finalBorderColor = BORDER_COLOR; - } - - drawingObserver.stopTracking(); - - g2d.setColor(finalBorderColor); - for (int i = 0; i < body.length - 1; i++) { - g2d.draw(body[i]); - } - - // Pins are the last piece. - Shape pins = body[body.length - 1]; - if (!outlineMode) { - g2d.setColor(METAL_COLOR); - g2d.fill(pins); - } - g2d.setColor(outlineMode ? theme.getOutlineColor() : METAL_COLOR.darker()); - g2d.draw(pins); - - Color finalLabelColor; - if (outlineMode) { - finalLabelColor = - componentState == ComponentState.SELECTED || componentState == ComponentState.DRAGGING ? LABEL_COLOR_SELECTED - : theme.getOutlineColor(); - } else { - finalLabelColor = - componentState == ComponentState.SELECTED || componentState == ComponentState.DRAGGING ? LABEL_COLOR_SELECTED - : LABEL_COLOR; - } - g2d.setColor(finalLabelColor); - g2d.setFont(project.getFont()); - - // Override font size - if (getFontSizeOverride() != null) - g2d.setFont(g2d.getFont().deriveFont(1f * getFontSizeOverride())); - - double centerX = (controlPoints[0].getX() + controlPoints[3].getX()) / 2; - double centerY = (controlPoints[0].getY() + controlPoints[3].getY()) / 2; - StringUtils.drawCenteredText(g2d, name, centerX, centerY, HorizontalAlignment.CENTER, VerticalAlignment.CENTER); - - drawSelectionOutline(g2d, componentState, outlineMode, project, drawingObserver); - } - - @Override - public void drawIcon(Graphics2D g2d, int width, int height) { - int bodyWidth = getClosestOdd(width * 3 / 5); - int tailWidth = getClosestOdd(width * 3 / 9); - - g2d.setColor(BODY_COLOR); - g2d.fillRoundRect((width - tailWidth) / 2, height / 2, tailWidth, height / 2 - 2 * 32 / height, 4 * 32 / width, - 4 * 32 / width); - g2d.setColor(BORDER_COLOR); - g2d.drawRoundRect((width - tailWidth) / 2, height / 2, tailWidth, height / 2 - 2 * 32 / height, 4 * 32 / width, - 4 * 32 / width); - - g2d.setColor(NUT_COLOR); - g2d.fillRoundRect((width - tailWidth) / 2, 2 * 32 / height, tailWidth, height / 2, 4 * 32 / width, 4 * 32 / width); - g2d.setColor(BORDER_COLOR); - g2d.drawRoundRect((width - tailWidth) / 2, 2 * 32 / height, tailWidth, height / 2, 4 * 32 / width, 4 * 32 / width); - - g2d.setColor(BODY_COLOR); - g2d.fillRect((width - bodyWidth) / 2, height / 7 + 1, bodyWidth, height * 5 / 7); - g2d.setColor(BORDER_COLOR); - g2d.drawRect((width - bodyWidth) / 2, height / 7 + 1, bodyWidth, height * 5 / 7); - - g2d.setColor(METAL_COLOR); - int pinX1 = getClosestOdd((width - bodyWidth * 3 / 4) / 2); - int pinX2 = getClosestOdd((width + bodyWidth * 3 / 4) / 2) - 1; - g2d.drawLine(pinX1, width * 2 / 8, pinX1, width * 3 / 8); - g2d.drawLine(pinX1, width * 5 / 8, pinX1, width * 6 / 8); - g2d.drawLine(pinX2, width * 2 / 8, pinX2, width * 3 / 8); - g2d.drawLine(pinX2, width * 5 / 8, pinX2, width * 6 / 8); - } - - @Override - public int getControlPointCount() { - return controlPoints.length; - } - - @Override - public Point2D getControlPoint(int index) { - return controlPoints[index]; - } - - @Override - public void setControlPoint(Point2D point, int index) { - controlPoints[index].setLocation(point); - body = null; - } - - @Override - public boolean isControlPointSticky(int index) { - return true; - } - - @Override - public VisibilityPolicy getControlPointVisibilityPolicy(int index) { - return VisibilityPolicy.NEVER; - } - - @EditableProperty(name = "Type") - public JackType getValue() { - return type; - } - - public void setValue(JackType type) { - this.type = type; - updateControlPoints(); - } - - @EditableProperty - public Orientation getOrientation() { - return orientation; - } - - public void setOrientation(Orientation orientation) { - this.orientation = orientation; - updateControlPoints(); - } - - @EditableProperty - public Mount getMount() { - return mount; - } - - public void setMount(Mount mount) { - this.mount = mount; - body = null; - } - - @Override - public boolean canPointMoveFreely(int pointIndex) { - return false; - } - - enum Mount { - PCB, Panel - } -} +/* + + DIY Layout Creator (DIYLC). + Copyright (c) 2009-2025 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.electromechanical; + +import java.awt.AlphaComposite; +import java.awt.Color; +import java.awt.Composite; +import java.awt.Graphics2D; +import java.awt.Shape; +import java.awt.geom.AffineTransform; +import java.awt.geom.Area; +import java.awt.geom.Ellipse2D; +import java.awt.geom.Point2D; +import java.awt.geom.Rectangle2D; +import java.awt.geom.RoundRectangle2D; +import org.diylc.appframework.miscutils.ConfigurationManager; + +import org.diylc.awt.StringUtils; +import org.diylc.common.HorizontalAlignment; +import org.diylc.common.IPlugInPort; +import org.diylc.common.ObjectCache; +import org.diylc.common.Orientation; +import org.diylc.common.VerticalAlignment; +import org.diylc.components.AbstractMultiPartComponent; +import org.diylc.components.transform.NeutrikJack1_4Transformer; +import org.diylc.core.ComponentState; +import org.diylc.core.IDIYComponent; +import org.diylc.core.IDrawingObserver; +import org.diylc.core.Project; +import org.diylc.core.Theme; +import org.diylc.core.VisibilityPolicy; +import org.diylc.core.annotations.ComponentDescriptor; +import org.diylc.core.annotations.EditableProperty; +import org.diylc.core.measures.Size; +import org.diylc.core.measures.SizeUnit; +import org.diylc.utils.Constants; + +@ComponentDescriptor(name = "Neutrik 1/4\" Jack", category = "Electro-Mechanical", author = "Branislav Stojkovic", + description = "1/4\" mono/stereo phono jack based on Neutrik NMJx series, PCB or Panel-mount", + zOrder = IDIYComponent.COMPONENT, instanceNamePrefix = "J", transformer = NeutrikJack1_4Transformer.class, + enableCache = true) +public class NeutrikJack1_4 extends AbstractMultiPartComponent { + + private static final long serialVersionUID = 1L; + + private static Size X_SPACING = new Size(0.25d, SizeUnit.in); + private static Size Y_SPACING = new Size(16.23d, SizeUnit.mm); + private static Size PIN_WIDTH = new Size(0.1d, SizeUnit.in); + private static Size PIN_THICKNESS = new Size(0.02d, SizeUnit.in); + private static Size PIN_DIAMETER = new Size(1.4d, SizeUnit.mm); + private static Size PIN_OFFSET_MONO = new Size(-6.27d, SizeUnit.mm); + private static Size PIN_OFFSET_STEREO = new Size(-7.72d, SizeUnit.mm); + private static Color BODY_COLOR = Color.decode("#666666"); + private static Color NUT_COLOR = Color.decode("#999999"); + private static Color BORDER_COLOR = Color.black; + private static Color LABEL_COLOR = Color.white; + private static Size BODY_WIDTH = new Size(18.2, SizeUnit.mm); + private static Size BODY_LENGTH = new Size(20.6d, SizeUnit.mm); + private static Size TAIL_LENGTH = new Size(0.1d, SizeUnit.in); + + private Point2D[] controlPoints = new Point2D[] {new Point2D.Double(0, 0)}; + private JackType type = JackType.MONO; + private Mount mount = Mount.Panel; + private Orientation orientation = Orientation.DEFAULT; + transient private Area[] body; + @SuppressWarnings("unused") + @Deprecated + private transient String value = ""; + + + public NeutrikJack1_4() { + super(); + updateControlPoints(); + } + + private void updateControlPoints() { + // invalidate body shape + body = null; + double x = controlPoints[0].getX(); + double y = controlPoints[0].getY(); + int xSpacing = (int) X_SPACING.convertToPixels(); + int ySpacing = (int) Y_SPACING.convertToPixels(); + controlPoints = new Point2D[type == JackType.STEREO ? 6 : 4]; + + controlPoints[0] = new Point2D.Double(x, y); + controlPoints[1] = new Point2D.Double(x, y + ySpacing); + controlPoints[2] = new Point2D.Double(x + 2 * xSpacing, y); + controlPoints[3] = new Point2D.Double(x + 2 * xSpacing, y + ySpacing); + if (type == JackType.STEREO) { + controlPoints[4] = new Point2D.Double(x + xSpacing, y); + controlPoints[5] = new Point2D.Double(x + xSpacing, y + ySpacing); + } + + // Apply rotation if necessary + double angle = getAngle(); + if (angle != 0) { + AffineTransform rotation = AffineTransform.getRotateInstance(angle, x, y); + for (int i = 1; i < controlPoints.length; i++) { + rotation.transform(controlPoints[i], controlPoints[i]); + } + } + } + + private double getAngle() { + // Apply rotation if necessary + double angle; + switch (orientation) { + case _90: + angle = Math.PI / 2; + break; + case _180: + angle = Math.PI; + break; + case _270: + angle = Math.PI * 3 / 2; + break; + default: + angle = 0; + } + + return angle; + } + + public Area[] getBody() { + if (body == null) { + body = new Area[5]; + + // Create body. + int bodyLength = (int) BODY_LENGTH.convertToPixels(); + int bodyWidth = (int) BODY_WIDTH.convertToPixels(); + int offset = (int)(type == JackType.MONO ? PIN_OFFSET_MONO : PIN_OFFSET_STEREO).convertToPixels(); + int xSpacing = (int) X_SPACING.convertToPixels(); + int ySpacing = (int) Y_SPACING.convertToPixels(); + double centerX = controlPoints[0].getX() + 2 * xSpacing + offset; + double centerY = controlPoints[0].getY() + ySpacing / 2; + body[0] = new Area(new Rectangle2D.Double(centerX - bodyLength / 2, centerY - bodyWidth / 2, bodyLength, bodyWidth)); + + int tailLength = (int) TAIL_LENGTH.convertToPixels(); + body[1] = new Area(new RoundRectangle2D.Double(centerX - bodyLength / 2 - tailLength, centerY - bodyWidth / 4, tailLength * 2, + bodyWidth / 2, tailLength, tailLength)); + Area tailArea = new Area(body[1]); + tailArea.subtract(new Area(body[0])); + body[1] = tailArea; + + body[2] = new Area(new Rectangle2D.Double(centerX + bodyLength / 2, centerY - bodyWidth / 4, tailLength, bodyWidth / 2)); + + body[3] = new Area(new Rectangle2D.Double(centerX + bodyLength / 2 + tailLength, centerY - bodyWidth / 4, tailLength, bodyWidth / 2)); + tailArea = new Area(body[3]); + int radius = bodyLength / 2 + tailLength * 2; + tailArea.intersect(new Area(new Ellipse2D.Double(centerX - radius, centerY - radius, radius * 2, radius * 2))); + body[3] = tailArea; + + // Apply rotation if necessary + double angle = getAngle(); + if (angle != 0) { + AffineTransform rotation = AffineTransform.getRotateInstance(angle, controlPoints[0].getX(), controlPoints[0].getY()); + for (int i = 0; i < body.length; i++) { + if (body[i] != null) { + Area area = new Area(body[i]); + area.transform(rotation); + body[i] = area; + } + } + } + + // Create pins. + Area pins = new Area(); + + int pinWidth = (int) PIN_WIDTH.convertToPixels(); + int pinThickness = (int) PIN_THICKNESS.convertToPixels(); + int pinDiameter = (int) PIN_DIAMETER.convertToPixels(); + for (int i = 0; i < getControlPointCount(); i++) { + Point2D point = getControlPoint(i); + Shape pin; + if (mount == Mount.PCB) { + pin = new Ellipse2D.Double(point.getX() - pinDiameter / 2, point.getY() - pinDiameter / 2, pinDiameter, pinDiameter); + } else { + if (orientation == Orientation.DEFAULT || orientation == Orientation._180) { + pin = new Rectangle2D.Double(point.getX() - pinWidth / 2, point.getY() - pinThickness / 2, pinWidth, pinThickness); + } else { + pin = new Rectangle2D.Double(point.getX() - pinThickness / 2, point.getY() - pinWidth / 2, pinThickness, pinWidth); + } + } + pins.add(new Area(pin)); + } + + body[4] = pins; + } + return body; + } + + @Override + public void draw(Graphics2D g2d, ComponentState componentState, boolean outlineMode, Project project, + IDrawingObserver drawingObserver) { + Shape[] body = getBody(); + + g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(1)); +// if (componentState != ComponentState.DRAGGING) { + Composite oldComposite = applyAlpha(g2d, componentState); + g2d.setColor(outlineMode ? Constants.TRANSPARENT_COLOR : BODY_COLOR); + for (int i = 0; i < body.length - 1; i++) { + // Nut is brighter colored. + if (i == body.length - 2) + g2d.setColor(outlineMode ? Constants.TRANSPARENT_COLOR : NUT_COLOR); + g2d.fill(body[i]); + } + g2d.setComposite(oldComposite); +// } + + Color finalBorderColor; + Theme theme = (Theme) ConfigurationManager.getInstance().readObject(IPlugInPort.THEME_KEY, Constants.DEFAULT_THEME); + if (outlineMode) { + finalBorderColor = theme.getOutlineColor(); + } else { + finalBorderColor = BORDER_COLOR; + } + + drawingObserver.stopTracking(); + + g2d.setColor(finalBorderColor); + for (int i = 0; i < body.length - 1; i++) { + g2d.draw(body[i]); + } + + // Pins are the last piece. + Shape pins = body[body.length - 1]; + if (!outlineMode) { + g2d.setColor(METAL_COLOR); + g2d.fill(pins); + } + g2d.setColor(outlineMode ? theme.getOutlineColor() : METAL_COLOR.darker()); + g2d.draw(pins); + + Color finalLabelColor; + if (outlineMode) { + finalLabelColor = + componentState == ComponentState.SELECTED || componentState == ComponentState.DRAGGING ? LABEL_COLOR_SELECTED + : theme.getOutlineColor(); + } else { + finalLabelColor = + componentState == ComponentState.SELECTED || componentState == ComponentState.DRAGGING ? LABEL_COLOR_SELECTED + : LABEL_COLOR; + } + g2d.setColor(finalLabelColor); + g2d.setFont(project.getFont()); + + // Override font size + if (getFontSizeOverride() != null) + g2d.setFont(g2d.getFont().deriveFont(1f * getFontSizeOverride())); + + double centerX = (controlPoints[0].getX() + controlPoints[3].getX()) / 2; + double centerY = (controlPoints[0].getY() + controlPoints[3].getY()) / 2; + StringUtils.drawCenteredText(g2d, name, centerX, centerY, HorizontalAlignment.CENTER, VerticalAlignment.CENTER); + + drawSelectionOutline(g2d, componentState, outlineMode, project, drawingObserver); + } + + @Override + public void drawIcon(Graphics2D g2d, int width, int height) { + int bodyWidth = getClosestOdd(width * 3 / 5); + int tailWidth = getClosestOdd(width * 3 / 9); + + g2d.setColor(BODY_COLOR); + g2d.fillRoundRect((width - tailWidth) / 2, height / 2, tailWidth, height / 2 - 2 * 32 / height, 4 * 32 / width, + 4 * 32 / width); + g2d.setColor(BORDER_COLOR); + g2d.drawRoundRect((width - tailWidth) / 2, height / 2, tailWidth, height / 2 - 2 * 32 / height, 4 * 32 / width, + 4 * 32 / width); + + g2d.setColor(NUT_COLOR); + g2d.fillRoundRect((width - tailWidth) / 2, 2 * 32 / height, tailWidth, height / 2, 4 * 32 / width, 4 * 32 / width); + g2d.setColor(BORDER_COLOR); + g2d.drawRoundRect((width - tailWidth) / 2, 2 * 32 / height, tailWidth, height / 2, 4 * 32 / width, 4 * 32 / width); + + g2d.setColor(BODY_COLOR); + g2d.fillRect((width - bodyWidth) / 2, height / 7 + 1, bodyWidth, height * 5 / 7); + g2d.setColor(BORDER_COLOR); + g2d.drawRect((width - bodyWidth) / 2, height / 7 + 1, bodyWidth, height * 5 / 7); + + g2d.setColor(METAL_COLOR); + int pinX1 = getClosestOdd((width - bodyWidth * 3 / 4) / 2); + int pinX2 = getClosestOdd((width + bodyWidth * 3 / 4) / 2) - 1; + g2d.drawLine(pinX1, width * 2 / 8, pinX1, width * 3 / 8); + g2d.drawLine(pinX1, width * 5 / 8, pinX1, width * 6 / 8); + g2d.drawLine(pinX2, width * 2 / 8, pinX2, width * 3 / 8); + g2d.drawLine(pinX2, width * 5 / 8, pinX2, width * 6 / 8); + } + + @Override + public int getControlPointCount() { + return controlPoints.length; + } + + @Override + public Point2D getControlPoint(int index) { + return controlPoints[index]; + } + + @Override + public void setControlPoint(Point2D point, int index) { + controlPoints[index].setLocation(point); + body = null; + } + + @Override + public boolean isControlPointSticky(int index) { + return true; + } + + @Override + public VisibilityPolicy getControlPointVisibilityPolicy(int index) { + return VisibilityPolicy.NEVER; + } + + @EditableProperty(name = "Type") + public JackType getValue() { + return type; + } + + public void setValue(JackType type) { + this.type = type; + updateControlPoints(); + } + + @EditableProperty + public Orientation getOrientation() { + return orientation; + } + + public void setOrientation(Orientation orientation) { + this.orientation = orientation; + updateControlPoints(); + } + + @EditableProperty + public Mount getMount() { + return mount; + } + + public void setMount(Mount mount) { + this.mount = mount; + body = null; + } + + @Override + public boolean canPointMoveFreely(int pointIndex) { + return false; + } + + enum Mount { + PCB, Panel + } +} diff --git a/diylc/diylc-library/src/main/java/org/diylc/components/electromechanical/OpenJack1_4.java b/diylc/diylc-library/src/main/java/org/diylc/components/electromechanical/OpenJack1_4.java index 6a57d056e..9440045b3 100644 --- a/diylc/diylc-library/src/main/java/org/diylc/components/electromechanical/OpenJack1_4.java +++ b/diylc/diylc-library/src/main/java/org/diylc/components/electromechanical/OpenJack1_4.java @@ -1,464 +1,458 @@ -/* - - DIY Layout Creator (DIYLC). - Copyright (c) 2009-2025 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.electromechanical; - -import java.awt.AlphaComposite; -import java.awt.Color; -import java.awt.Composite; -import java.awt.Graphics2D; -import java.awt.RenderingHints; -import java.awt.Shape; -import java.awt.geom.AffineTransform; -import java.awt.geom.Area; -import java.awt.geom.Ellipse2D; -import java.awt.geom.Point2D; -import java.awt.geom.RoundRectangle2D; -import org.diylc.appframework.miscutils.ConfigurationManager; - -import org.diylc.awt.StringUtils; -import org.diylc.common.HorizontalAlignment; -import org.diylc.common.IPlugInPort; -import org.diylc.common.ObjectCache; -import org.diylc.common.Orientation; -import org.diylc.common.VerticalAlignment; -import org.diylc.components.AbstractMultiPartComponent; -import org.diylc.components.electromechanical.OpenJack1_4.OpenJackType; -import org.diylc.components.transform.OpenJackTransformer; -import org.diylc.core.ComponentState; -import org.diylc.core.IDIYComponent; -import org.diylc.core.IDrawingObserver; -import org.diylc.core.Project; -import org.diylc.core.Theme; -import org.diylc.core.VisibilityPolicy; -import org.diylc.core.annotations.ComponentDescriptor; -import org.diylc.core.annotations.EditableProperty; -import org.diylc.core.measures.Size; -import org.diylc.core.measures.SizeUnit; -import org.diylc.utils.Constants; - -@ComponentDescriptor(name = "Open 1/4\" Jack", category = "Electro-Mechanical", author = "Branislav Stojkovic", - description = "Switchcraft-style open panel mount 1/4\" phono jack, stereo and mono", - zOrder = IDIYComponent.COMPONENT, instanceNamePrefix = "J", transformer = OpenJackTransformer.class, enableCache = true) -public class OpenJack1_4 extends AbstractMultiPartComponent { - - private static final float FONT_SCALE = 0.8f; - private static final double RING_THETA = Math.PI * 0.795; - private static final double SLEEVE_THETA = Math.PI * 0.29444444444; - private static final double SLEEVE_SWITCHED_THETA = Math.PI * 4 / 3; - private static final double SWITCH_THETA = Math.PI * 5 / 3; - - private static final long serialVersionUID = 1L; - - private static Color BASE_COLOR = Color.lightGray; - private static Color WAFER_COLOR = PHENOLIC_DARK_COLOR; - - private static Size OUTER_DIAMETER = new Size(0.75d, SizeUnit.in); - private static Size INNER_DIAMETER = new Size(0.25d, SizeUnit.in); - private static Size RING_DIAMETER = new Size(0.33d, SizeUnit.in); - private static Size SPRING_LENGTH = new Size(0.563d, SizeUnit.in); - private static Size SPRING_WIDTH = new Size(0.12d, SizeUnit.in); - private static Size HOLE_DIAMETER = new Size(0.05d, SizeUnit.in); - private static Size HOLE_TO_EDGE = new Size(0.063d, SizeUnit.in); - - @SuppressWarnings("unused") - @Deprecated - private transient String value = ""; - private Point2D[] controlPoints = new Point2D[] {new Point2D.Double(0, 0), new Point2D.Double(0, 0), new Point2D.Double(0, 0)}; - transient Area[] body; - @Deprecated - private Orientation orientation = Orientation.DEFAULT; - private Integer angle = 0; - private OpenJackType type = OpenJackType.MONO; - private boolean showLabels = true; - - public OpenJack1_4() { - super(); - updateControlPoints(); - } - - @Override - public void draw(Graphics2D g2d, ComponentState componentState, boolean outlineMode, Project project, - IDrawingObserver drawingObserver) { - Shape[] body = getBody(); - - g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(1)); -// if (componentState != ComponentState.DRAGGING) { - 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 : WAFER_COLOR); - g2d.fill(body[0]); - - g2d.setComposite(oldComposite); -// } - - Color finalBorderColor; - - if (outlineMode) { - Theme theme = - (Theme) ConfigurationManager.getInstance().readObject(IPlugInPort.THEME_KEY, Constants.DEFAULT_THEME); - finalBorderColor = theme.getOutlineColor(); - } else { - finalBorderColor = WAFER_COLOR.darker(); - } - - g2d.setColor(finalBorderColor); - g2d.draw(body[0]); - -// if (componentState != ComponentState.DRAGGING) { - oldComposite = g2d.getComposite(); - if (alpha < MAX_ALPHA) { - g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1f * alpha / MAX_ALPHA)); - } - - g2d.setColor(Constants.TRANSPARENT_COLOR); - drawingObserver.startTrackingContinuityArea(true); - g2d.fill(body[4]); - g2d.fill(body[5]); - if (body[6] != null) - g2d.fill(body[6]); - drawingObserver.stopTrackingContinuityArea(); - - if (!outlineMode) { - g2d.setColor(BASE_COLOR); - - g2d.fill(body[1]); - g2d.fill(body[2]); - if (body[3] != null) - g2d.fill(body[3]); - } - - g2d.setComposite(oldComposite); -// } - - drawingObserver.stopTracking(); - - if (outlineMode) { - Theme theme = - (Theme) ConfigurationManager.getInstance().readObject(IPlugInPort.THEME_KEY, Constants.DEFAULT_THEME); - finalBorderColor = theme.getOutlineColor(); - } else { - finalBorderColor = BASE_COLOR.darker(); - } - - g2d.setColor(finalBorderColor); - g2d.draw(body[1]); - g2d.draw(body[2]); - if (body[3] != null) - g2d.draw(body[3]); - - // draw labels - if (showLabels) { - g2d.setColor(BASE_COLOR.darker()); - g2d.setFont(project.getFont().deriveFont(project.getFont().getSize2D() * FONT_SCALE)); - int springLength = (int) SPRING_LENGTH.convertToPixels(); - int holeToEdge = (int) HOLE_TO_EDGE.convertToPixels(); - double centerY = controlPoints[0].getY() + springLength - holeToEdge; - Point2D tipLabel = new Point2D.Double(controlPoints[0].getX(), (int) (controlPoints[0].getY() + holeToEdge * 1.25)); - AffineTransform ringTransform = AffineTransform.getRotateInstance(getValue() == OpenJackType.SWITCHED ? SWITCH_THETA : RING_THETA, controlPoints[0].getX(), centerY); - AffineTransform sleeveTransform = AffineTransform.getRotateInstance(getValue() == OpenJackType.SWITCHED ? SLEEVE_SWITCHED_THETA : SLEEVE_THETA, controlPoints[0].getX(), centerY); - Point2D ringOrSwitchLabel = new Point2D.Double(0, 0); - Point2D sleeveLabel = new Point2D.Double(0, 0); - ringTransform.transform(tipLabel, ringOrSwitchLabel); - sleeveTransform.transform(tipLabel, sleeveLabel); - - if (getTheta() != 0) { - AffineTransform rotation = AffineTransform.getRotateInstance(getTheta(), controlPoints[0].getX(), controlPoints[0].getY()); - rotation.transform(tipLabel, tipLabel); - rotation.transform(ringOrSwitchLabel, ringOrSwitchLabel); - rotation.transform(sleeveLabel, sleeveLabel); - } - StringUtils.drawCenteredText(g2d, "T", tipLabel.getX(), tipLabel.getY(), HorizontalAlignment.CENTER, VerticalAlignment.CENTER); - StringUtils.drawCenteredText(g2d, "S", sleeveLabel.getX(), sleeveLabel.getY(), HorizontalAlignment.CENTER, VerticalAlignment.CENTER); - if (getValue() == OpenJackType.STEREO) - StringUtils.drawCenteredText(g2d, "R", ringOrSwitchLabel.getX(), ringOrSwitchLabel.getY(), HorizontalAlignment.CENTER, VerticalAlignment.CENTER); - if (getValue() == OpenJackType.SWITCHED) - StringUtils.drawCenteredText(g2d, "Sw", ringOrSwitchLabel.getX(), ringOrSwitchLabel.getY(), HorizontalAlignment.CENTER, VerticalAlignment.CENTER); - } - - drawSelectionOutline(g2d, componentState, outlineMode, project, drawingObserver); - } - - public Area[] getBody() { - if (body == null) { - body = new Area[7]; - - double x = controlPoints[0].getX(); - double y = controlPoints[0].getY(); - int outerDiameter = getClosestOdd(OUTER_DIAMETER.convertToPixels()); - int innerDiameter = getClosestOdd(INNER_DIAMETER.convertToPixels()); - int ringDiameter = getClosestOdd(RING_DIAMETER.convertToPixels()); - int springLength = (int) SPRING_LENGTH.convertToPixels(); - int springWidth = (int) SPRING_WIDTH.convertToPixels(); - int holeDiameter = getClosestOdd(HOLE_DIAMETER.convertToPixels()); - int holeToEdge = (int) HOLE_TO_EDGE.convertToPixels(); - - double centerY = y + springLength - holeToEdge; - - Area wafer = - new Area(new Ellipse2D.Double(x - outerDiameter / 2, centerY - outerDiameter / 2, outerDiameter, - outerDiameter)); - wafer.subtract(new Area(new Ellipse2D.Double(x - ringDiameter / 2, centerY - ringDiameter / 2, ringDiameter, - ringDiameter))); - - body[0] = wafer; - - Area tip = - new Area(new RoundRectangle2D.Double(x - springWidth / 2, y - holeToEdge, springWidth, springLength - - ringDiameter / 2, springWidth, springWidth)); - tip.subtract(new Area( - new Ellipse2D.Double(x - holeDiameter / 2, y - holeDiameter / 2, holeDiameter, holeDiameter))); - tip.subtract(wafer); - - body[1] = tip; - - // no-hole tip for continuity - tip = - new Area(new RoundRectangle2D.Double(x - springWidth / 2, y - holeToEdge, springWidth, springLength - - ringDiameter / 2, springWidth, springWidth)); - tip.subtract(wafer); - body[4] = tip; - - Area sleeve = - new Area(new RoundRectangle2D.Double(x - springWidth / 2, y - holeToEdge, springWidth, springLength, - springWidth, springWidth)); - sleeve.subtract(new Area(new Ellipse2D.Double(x - holeDiameter / 2, y - holeDiameter / 2, holeDiameter, - holeDiameter))); - sleeve.transform(AffineTransform.getRotateInstance(getValue() == OpenJackType.SWITCHED ? SLEEVE_SWITCHED_THETA : SLEEVE_THETA, x, centerY)); - sleeve.add(new Area(new Ellipse2D.Double(x - ringDiameter / 2, centerY - ringDiameter / 2, ringDiameter, - ringDiameter))); - sleeve.subtract(new Area(new Ellipse2D.Double(x - innerDiameter / 2, centerY - innerDiameter / 2, innerDiameter, - innerDiameter))); - - body[2] = sleeve; - - // no-hole sleeve for continuity - sleeve = - new Area(new RoundRectangle2D.Double(x - springWidth / 2, y - holeToEdge, springWidth, springLength, - springWidth, springWidth)); - sleeve.transform(AffineTransform.getRotateInstance(getValue() == OpenJackType.SWITCHED ? SLEEVE_SWITCHED_THETA : SLEEVE_THETA, x, centerY)); - sleeve.add(new Area(new Ellipse2D.Double(x - ringDiameter / 2, centerY - ringDiameter / 2, ringDiameter, - ringDiameter))); - sleeve.subtract(new Area(new Ellipse2D.Double(x - innerDiameter / 2, centerY - innerDiameter / 2, innerDiameter, - innerDiameter))); - body[5] = sleeve; - - if (getValue() != OpenJackType.MONO) { - Area ringOrSwitch = - new Area(new RoundRectangle2D.Double(x - springWidth / 2, y - holeToEdge, springWidth, springLength, - springWidth, springWidth)); - ringOrSwitch.subtract(new Area(new Ellipse2D.Double(x - holeDiameter / 2, y - holeDiameter / 2, holeDiameter, - holeDiameter))); - ringOrSwitch.transform(AffineTransform.getRotateInstance(getValue() == OpenJackType.SWITCHED ? SWITCH_THETA : RING_THETA, x, centerY)); - ringOrSwitch.subtract(new Area(new Ellipse2D.Double(x - outerDiameter / 2, centerY - outerDiameter / 2, outerDiameter, - outerDiameter))); - - body[3] = ringOrSwitch; - - ringOrSwitch = - new Area(new RoundRectangle2D.Double(x - springWidth / 2, y - holeToEdge, springWidth, springLength, - springWidth, springWidth)); - ringOrSwitch.transform(AffineTransform.getRotateInstance(getValue() == OpenJackType.SWITCHED ? SWITCH_THETA : RING_THETA, x, centerY)); - ringOrSwitch.subtract(new Area(new Ellipse2D.Double(x - outerDiameter / 2, centerY - outerDiameter / 2, outerDiameter, - outerDiameter))); - - body[6] = ringOrSwitch; - } - - // Rotate if needed - if (getTheta() != 0) { - AffineTransform rotation = AffineTransform.getRotateInstance(getTheta(), x, y); - // Skip the last one because it's already rotated - for (int i = 0; i < body.length; i++) { - Shape shape = body[i]; - Area area = (Area) shape; - if (area != null) { - area.transform(rotation); - } - } - } - } - - return body; - } - - private void updateControlPoints() { - double x = controlPoints[0].getX(); - double y = controlPoints[0].getY(); - - int springLength = (int) SPRING_LENGTH.convertToPixels(); - int holeToEdge = (int) HOLE_TO_EDGE.convertToPixels(); - - double centerY = y + springLength - holeToEdge; - - AffineTransform.getRotateInstance(getValue() == OpenJackType.SWITCHED ? SLEEVE_SWITCHED_THETA : SLEEVE_THETA, x, centerY).transform(controlPoints[0], controlPoints[1]); - AffineTransform.getRotateInstance(getValue() == OpenJackType.SWITCHED ? SWITCH_THETA : RING_THETA, x, centerY).transform(controlPoints[0], controlPoints[2]); - - // Rotate if needed - if (getTheta() != 0) { - AffineTransform rotation = AffineTransform.getRotateInstance(getTheta(), x, y); - for (Point2D point : controlPoints) { - rotation.transform(point, point); - } - } - } - - @Override - public void drawIcon(Graphics2D g2d, int width, int height) { - int waferDiameter = 15 * width / 32; - int sleeveDiameter = 9 * width / 32; - - AffineTransform tx = g2d.getTransform(); - - g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(6f * width / 32)); - g2d.setColor(BASE_COLOR); - g2d.drawLine(width / 2, 4 * width / 32, width / 2, width / 4); - - g2d.rotate(RING_THETA, width / 2, height / 2); - - g2d.drawLine(width / 2, 4 * width / 32, width / 2, width / 4); - - g2d.setColor(WAFER_COLOR); - g2d.draw(new Ellipse2D.Double(width / 2 - waferDiameter / 2, height / 2 - waferDiameter / 2, waferDiameter, - waferDiameter)); - - g2d.setColor(BASE_COLOR); - g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(2f * width / 32)); - g2d.draw(new Ellipse2D.Double(width / 2 - sleeveDiameter / 2, height / 2 - sleeveDiameter / 2, sleeveDiameter, - sleeveDiameter)); - - g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(6f * width / 32)); - g2d.rotate(-Math.PI / 2, width / 2, height / 2); - - g2d.drawLine(width / 2, 4 * width / 32, width / 2, width / 3); - - g2d.setTransform(tx); - g2d.setColor(LABEL_COLOR); - g2d.setFont(LABEL_FONT.deriveFont(width / 3.5f)); - - RenderingHints rh = new RenderingHints( - RenderingHints.KEY_TEXT_ANTIALIASING, - RenderingHints.VALUE_TEXT_ANTIALIAS_OFF); - g2d.setRenderingHints(rh); - - StringUtils.drawCenteredText(g2d, "6.3", width / 2 - 1, height / 2, HorizontalAlignment.CENTER, VerticalAlignment.CENTER); - } - - @Override - public int getControlPointCount() { - return controlPoints.length; - } - - @Override - public VisibilityPolicy getControlPointVisibilityPolicy(int index) { - return VisibilityPolicy.NEVER; - } - - @Override - public boolean isControlPointSticky(int index) { - return index < 2 || (getValue() == OpenJackType.STEREO || getValue() == OpenJackType.SWITCHED); - } - - @Override - public Point2D getControlPoint(int index) { - return controlPoints[index]; - } - - @Override - public void setControlPoint(Point2D point, int index) { - this.controlPoints[index].setLocation(point); - // Invalidate the body - body = null; - } - - @EditableProperty - public Integer getAngle() { - if (angle == null || (orientation != null && orientation != Orientation.DEFAULT)) { - if (orientation != null && orientation != Orientation.DEFAULT) - angle = Integer.parseInt(orientation.name().replace("_", "")); - else - angle = 0; - } - return angle; - } - - public void setAngle(Integer angle) { - this.angle = angle; - updateControlPoints(); - // Invalidate the body - body = null; - } - - protected double getTheta() { - return Math.toRadians(getAngle()); - } - - @EditableProperty(name = "Type") - public OpenJackType getValue() { - return type; - } - - public void setValue(OpenJackType type) { - this.type = type; - updateControlPoints(); - // Invalidate the body - body = null; - } - - @EditableProperty(name = "Labels") - public boolean getShowLabels() { - return showLabels; - } - - public void setShowLabels(boolean showLabels) { - this.showLabels = showLabels; - } - - @Override - public String getControlPointNodeName(int index) { - if (index == 0) - return "Tip"; - if (index == 1) - return "Sleeve"; - if (index == 2 && getValue() == OpenJackType.STEREO) - return "Ring"; - if (index == 2 && getValue() == OpenJackType.SWITCHED) - return "Shunt"; - return null; - } - - @Override - public boolean canPointMoveFreely(int pointIndex) { - return false; - } - - public static enum OpenJackType { - - MONO, STEREO, SWITCHED; - - @Override - public String toString() { - return name().substring(0, 1) + name().substring(1).toLowerCase(); - } - } -} +/* + + DIY Layout Creator (DIYLC). + Copyright (c) 2009-2025 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.electromechanical; + +import java.awt.AlphaComposite; +import java.awt.Color; +import java.awt.Composite; +import java.awt.Graphics2D; +import java.awt.RenderingHints; +import java.awt.Shape; +import java.awt.geom.AffineTransform; +import java.awt.geom.Area; +import java.awt.geom.Ellipse2D; +import java.awt.geom.Point2D; +import java.awt.geom.RoundRectangle2D; +import org.diylc.appframework.miscutils.ConfigurationManager; + +import org.diylc.awt.StringUtils; +import org.diylc.common.HorizontalAlignment; +import org.diylc.common.IPlugInPort; +import org.diylc.common.ObjectCache; +import org.diylc.common.Orientation; +import org.diylc.common.VerticalAlignment; +import org.diylc.components.AbstractMultiPartComponent; +import org.diylc.components.electromechanical.OpenJack1_4.OpenJackType; +import org.diylc.components.transform.OpenJackTransformer; +import org.diylc.core.ComponentState; +import org.diylc.core.IDIYComponent; +import org.diylc.core.IDrawingObserver; +import org.diylc.core.Project; +import org.diylc.core.Theme; +import org.diylc.core.VisibilityPolicy; +import org.diylc.core.annotations.ComponentDescriptor; +import org.diylc.core.annotations.EditableProperty; +import org.diylc.core.measures.Size; +import org.diylc.core.measures.SizeUnit; +import org.diylc.utils.Constants; + +@ComponentDescriptor(name = "Open 1/4\" Jack", category = "Electro-Mechanical", author = "Branislav Stojkovic", + description = "Switchcraft-style open panel mount 1/4\" phono jack, stereo and mono", + zOrder = IDIYComponent.COMPONENT, instanceNamePrefix = "J", transformer = OpenJackTransformer.class, enableCache = true) +public class OpenJack1_4 extends AbstractMultiPartComponent { + + private static final float FONT_SCALE = 0.8f; + private static final double RING_THETA = Math.PI * 0.795; + private static final double SLEEVE_THETA = Math.PI * 0.29444444444; + private static final double SLEEVE_SWITCHED_THETA = Math.PI * 4 / 3; + private static final double SWITCH_THETA = Math.PI * 5 / 3; + + private static final long serialVersionUID = 1L; + + private static Color BASE_COLOR = Color.lightGray; + private static Color WAFER_COLOR = PHENOLIC_DARK_COLOR; + + private static Size OUTER_DIAMETER = new Size(0.75d, SizeUnit.in); + private static Size INNER_DIAMETER = new Size(0.25d, SizeUnit.in); + private static Size RING_DIAMETER = new Size(0.33d, SizeUnit.in); + private static Size SPRING_LENGTH = new Size(0.563d, SizeUnit.in); + private static Size SPRING_WIDTH = new Size(0.12d, SizeUnit.in); + private static Size HOLE_DIAMETER = new Size(0.05d, SizeUnit.in); + private static Size HOLE_TO_EDGE = new Size(0.063d, SizeUnit.in); + + @SuppressWarnings("unused") + @Deprecated + private transient String value = ""; + private Point2D[] controlPoints = new Point2D[] {new Point2D.Double(0, 0), new Point2D.Double(0, 0), new Point2D.Double(0, 0)}; + transient Area[] body; + @Deprecated + private Orientation orientation = Orientation.DEFAULT; + private Integer angle = 0; + private OpenJackType type = OpenJackType.MONO; + private boolean showLabels = true; + + public OpenJack1_4() { + super(); + updateControlPoints(); + } + + @Override + public void draw(Graphics2D g2d, ComponentState componentState, boolean outlineMode, Project project, + IDrawingObserver drawingObserver) { + Shape[] body = getBody(); + + g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(1)); +// if (componentState != ComponentState.DRAGGING) { + Composite oldComposite = applyAlpha(g2d, componentState); + g2d.setColor(outlineMode ? Constants.TRANSPARENT_COLOR : WAFER_COLOR); + g2d.fill(body[0]); + + g2d.setComposite(oldComposite); +// } + + Color finalBorderColor; + + if (outlineMode) { + Theme theme = + (Theme) ConfigurationManager.getInstance().readObject(IPlugInPort.THEME_KEY, Constants.DEFAULT_THEME); + finalBorderColor = theme.getOutlineColor(); + } else { + finalBorderColor = WAFER_COLOR.darker(); + } + + g2d.setColor(finalBorderColor); + g2d.draw(body[0]); + +// if (componentState != ComponentState.DRAGGING) { + oldComposite = applyAlpha(g2d, componentState); + + g2d.setColor(Constants.TRANSPARENT_COLOR); + drawingObserver.startTrackingContinuityArea(true); + g2d.fill(body[4]); + g2d.fill(body[5]); + if (body[6] != null) + g2d.fill(body[6]); + drawingObserver.stopTrackingContinuityArea(); + + if (!outlineMode) { + g2d.setColor(BASE_COLOR); + + g2d.fill(body[1]); + g2d.fill(body[2]); + if (body[3] != null) + g2d.fill(body[3]); + } + + g2d.setComposite(oldComposite); +// } + + drawingObserver.stopTracking(); + + if (outlineMode) { + Theme theme = + (Theme) ConfigurationManager.getInstance().readObject(IPlugInPort.THEME_KEY, Constants.DEFAULT_THEME); + finalBorderColor = theme.getOutlineColor(); + } else { + finalBorderColor = BASE_COLOR.darker(); + } + + g2d.setColor(finalBorderColor); + g2d.draw(body[1]); + g2d.draw(body[2]); + if (body[3] != null) + g2d.draw(body[3]); + + // draw labels + if (showLabels) { + g2d.setColor(BASE_COLOR.darker()); + g2d.setFont(project.getFont().deriveFont(project.getFont().getSize2D() * FONT_SCALE)); + int springLength = (int) SPRING_LENGTH.convertToPixels(); + int holeToEdge = (int) HOLE_TO_EDGE.convertToPixels(); + double centerY = controlPoints[0].getY() + springLength - holeToEdge; + Point2D tipLabel = new Point2D.Double(controlPoints[0].getX(), (int) (controlPoints[0].getY() + holeToEdge * 1.25)); + AffineTransform ringTransform = AffineTransform.getRotateInstance(getValue() == OpenJackType.SWITCHED ? SWITCH_THETA : RING_THETA, controlPoints[0].getX(), centerY); + AffineTransform sleeveTransform = AffineTransform.getRotateInstance(getValue() == OpenJackType.SWITCHED ? SLEEVE_SWITCHED_THETA : SLEEVE_THETA, controlPoints[0].getX(), centerY); + Point2D ringOrSwitchLabel = new Point2D.Double(0, 0); + Point2D sleeveLabel = new Point2D.Double(0, 0); + ringTransform.transform(tipLabel, ringOrSwitchLabel); + sleeveTransform.transform(tipLabel, sleeveLabel); + + if (getTheta() != 0) { + AffineTransform rotation = AffineTransform.getRotateInstance(getTheta(), controlPoints[0].getX(), controlPoints[0].getY()); + rotation.transform(tipLabel, tipLabel); + rotation.transform(ringOrSwitchLabel, ringOrSwitchLabel); + rotation.transform(sleeveLabel, sleeveLabel); + } + StringUtils.drawCenteredText(g2d, "T", tipLabel.getX(), tipLabel.getY(), HorizontalAlignment.CENTER, VerticalAlignment.CENTER); + StringUtils.drawCenteredText(g2d, "S", sleeveLabel.getX(), sleeveLabel.getY(), HorizontalAlignment.CENTER, VerticalAlignment.CENTER); + if (getValue() == OpenJackType.STEREO) + StringUtils.drawCenteredText(g2d, "R", ringOrSwitchLabel.getX(), ringOrSwitchLabel.getY(), HorizontalAlignment.CENTER, VerticalAlignment.CENTER); + if (getValue() == OpenJackType.SWITCHED) + StringUtils.drawCenteredText(g2d, "Sw", ringOrSwitchLabel.getX(), ringOrSwitchLabel.getY(), HorizontalAlignment.CENTER, VerticalAlignment.CENTER); + } + + drawSelectionOutline(g2d, componentState, outlineMode, project, drawingObserver); + } + + public Area[] getBody() { + if (body == null) { + body = new Area[7]; + + double x = controlPoints[0].getX(); + double y = controlPoints[0].getY(); + int outerDiameter = getClosestOdd(OUTER_DIAMETER.convertToPixels()); + int innerDiameter = getClosestOdd(INNER_DIAMETER.convertToPixels()); + int ringDiameter = getClosestOdd(RING_DIAMETER.convertToPixels()); + int springLength = (int) SPRING_LENGTH.convertToPixels(); + int springWidth = (int) SPRING_WIDTH.convertToPixels(); + int holeDiameter = getClosestOdd(HOLE_DIAMETER.convertToPixels()); + int holeToEdge = (int) HOLE_TO_EDGE.convertToPixels(); + + double centerY = y + springLength - holeToEdge; + + Area wafer = + new Area(new Ellipse2D.Double(x - outerDiameter / 2, centerY - outerDiameter / 2, outerDiameter, + outerDiameter)); + wafer.subtract(new Area(new Ellipse2D.Double(x - ringDiameter / 2, centerY - ringDiameter / 2, ringDiameter, + ringDiameter))); + + body[0] = wafer; + + Area tip = + new Area(new RoundRectangle2D.Double(x - springWidth / 2, y - holeToEdge, springWidth, springLength + - ringDiameter / 2, springWidth, springWidth)); + tip.subtract(new Area( + new Ellipse2D.Double(x - holeDiameter / 2, y - holeDiameter / 2, holeDiameter, holeDiameter))); + tip.subtract(wafer); + + body[1] = tip; + + // no-hole tip for continuity + tip = + new Area(new RoundRectangle2D.Double(x - springWidth / 2, y - holeToEdge, springWidth, springLength + - ringDiameter / 2, springWidth, springWidth)); + tip.subtract(wafer); + body[4] = tip; + + Area sleeve = + new Area(new RoundRectangle2D.Double(x - springWidth / 2, y - holeToEdge, springWidth, springLength, + springWidth, springWidth)); + sleeve.subtract(new Area(new Ellipse2D.Double(x - holeDiameter / 2, y - holeDiameter / 2, holeDiameter, + holeDiameter))); + sleeve.transform(AffineTransform.getRotateInstance(getValue() == OpenJackType.SWITCHED ? SLEEVE_SWITCHED_THETA : SLEEVE_THETA, x, centerY)); + sleeve.add(new Area(new Ellipse2D.Double(x - ringDiameter / 2, centerY - ringDiameter / 2, ringDiameter, + ringDiameter))); + sleeve.subtract(new Area(new Ellipse2D.Double(x - innerDiameter / 2, centerY - innerDiameter / 2, innerDiameter, + innerDiameter))); + + body[2] = sleeve; + + // no-hole sleeve for continuity + sleeve = + new Area(new RoundRectangle2D.Double(x - springWidth / 2, y - holeToEdge, springWidth, springLength, + springWidth, springWidth)); + sleeve.transform(AffineTransform.getRotateInstance(getValue() == OpenJackType.SWITCHED ? SLEEVE_SWITCHED_THETA : SLEEVE_THETA, x, centerY)); + sleeve.add(new Area(new Ellipse2D.Double(x - ringDiameter / 2, centerY - ringDiameter / 2, ringDiameter, + ringDiameter))); + sleeve.subtract(new Area(new Ellipse2D.Double(x - innerDiameter / 2, centerY - innerDiameter / 2, innerDiameter, + innerDiameter))); + body[5] = sleeve; + + if (getValue() != OpenJackType.MONO) { + Area ringOrSwitch = + new Area(new RoundRectangle2D.Double(x - springWidth / 2, y - holeToEdge, springWidth, springLength, + springWidth, springWidth)); + ringOrSwitch.subtract(new Area(new Ellipse2D.Double(x - holeDiameter / 2, y - holeDiameter / 2, holeDiameter, + holeDiameter))); + ringOrSwitch.transform(AffineTransform.getRotateInstance(getValue() == OpenJackType.SWITCHED ? SWITCH_THETA : RING_THETA, x, centerY)); + ringOrSwitch.subtract(new Area(new Ellipse2D.Double(x - outerDiameter / 2, centerY - outerDiameter / 2, outerDiameter, + outerDiameter))); + + body[3] = ringOrSwitch; + + ringOrSwitch = + new Area(new RoundRectangle2D.Double(x - springWidth / 2, y - holeToEdge, springWidth, springLength, + springWidth, springWidth)); + ringOrSwitch.transform(AffineTransform.getRotateInstance(getValue() == OpenJackType.SWITCHED ? SWITCH_THETA : RING_THETA, x, centerY)); + ringOrSwitch.subtract(new Area(new Ellipse2D.Double(x - outerDiameter / 2, centerY - outerDiameter / 2, outerDiameter, + outerDiameter))); + + body[6] = ringOrSwitch; + } + + // Rotate if needed + if (getTheta() != 0) { + AffineTransform rotation = AffineTransform.getRotateInstance(getTheta(), x, y); + // Skip the last one because it's already rotated + for (int i = 0; i < body.length; i++) { + Shape shape = body[i]; + Area area = (Area) shape; + if (area != null) { + area.transform(rotation); + } + } + } + } + + return body; + } + + private void updateControlPoints() { + double x = controlPoints[0].getX(); + double y = controlPoints[0].getY(); + + int springLength = (int) SPRING_LENGTH.convertToPixels(); + int holeToEdge = (int) HOLE_TO_EDGE.convertToPixels(); + + double centerY = y + springLength - holeToEdge; + + AffineTransform.getRotateInstance(getValue() == OpenJackType.SWITCHED ? SLEEVE_SWITCHED_THETA : SLEEVE_THETA, x, centerY).transform(controlPoints[0], controlPoints[1]); + AffineTransform.getRotateInstance(getValue() == OpenJackType.SWITCHED ? SWITCH_THETA : RING_THETA, x, centerY).transform(controlPoints[0], controlPoints[2]); + + // Rotate if needed + if (getTheta() != 0) { + AffineTransform rotation = AffineTransform.getRotateInstance(getTheta(), x, y); + for (Point2D point : controlPoints) { + rotation.transform(point, point); + } + } + } + + @Override + public void drawIcon(Graphics2D g2d, int width, int height) { + int waferDiameter = 15 * width / 32; + int sleeveDiameter = 9 * width / 32; + + AffineTransform tx = g2d.getTransform(); + + g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(6f * width / 32)); + g2d.setColor(BASE_COLOR); + g2d.drawLine(width / 2, 4 * width / 32, width / 2, width / 4); + + g2d.rotate(RING_THETA, width / 2, height / 2); + + g2d.drawLine(width / 2, 4 * width / 32, width / 2, width / 4); + + g2d.setColor(WAFER_COLOR); + g2d.draw(new Ellipse2D.Double(width / 2 - waferDiameter / 2, height / 2 - waferDiameter / 2, waferDiameter, + waferDiameter)); + + g2d.setColor(BASE_COLOR); + g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(2f * width / 32)); + g2d.draw(new Ellipse2D.Double(width / 2 - sleeveDiameter / 2, height / 2 - sleeveDiameter / 2, sleeveDiameter, + sleeveDiameter)); + + g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(6f * width / 32)); + g2d.rotate(-Math.PI / 2, width / 2, height / 2); + + g2d.drawLine(width / 2, 4 * width / 32, width / 2, width / 3); + + g2d.setTransform(tx); + g2d.setColor(LABEL_COLOR); + g2d.setFont(LABEL_FONT.deriveFont(width / 3.5f)); + + RenderingHints rh = new RenderingHints( + RenderingHints.KEY_TEXT_ANTIALIASING, + RenderingHints.VALUE_TEXT_ANTIALIAS_OFF); + g2d.setRenderingHints(rh); + + StringUtils.drawCenteredText(g2d, "6.3", width / 2 - 1, height / 2, HorizontalAlignment.CENTER, VerticalAlignment.CENTER); + } + + @Override + public int getControlPointCount() { + return controlPoints.length; + } + + @Override + public VisibilityPolicy getControlPointVisibilityPolicy(int index) { + return VisibilityPolicy.NEVER; + } + + @Override + public boolean isControlPointSticky(int index) { + return index < 2 || (getValue() == OpenJackType.STEREO || getValue() == OpenJackType.SWITCHED); + } + + @Override + public Point2D getControlPoint(int index) { + return controlPoints[index]; + } + + @Override + public void setControlPoint(Point2D point, int index) { + this.controlPoints[index].setLocation(point); + // Invalidate the body + body = null; + } + + @EditableProperty + public Integer getAngle() { + if (angle == null || (orientation != null && orientation != Orientation.DEFAULT)) { + if (orientation != null && orientation != Orientation.DEFAULT) + angle = Integer.parseInt(orientation.name().replace("_", "")); + else + angle = 0; + } + return angle; + } + + public void setAngle(Integer angle) { + this.angle = angle; + updateControlPoints(); + // Invalidate the body + body = null; + } + + protected double getTheta() { + return Math.toRadians(getAngle()); + } + + @EditableProperty(name = "Type") + public OpenJackType getValue() { + return type; + } + + public void setValue(OpenJackType type) { + this.type = type; + updateControlPoints(); + // Invalidate the body + body = null; + } + + @EditableProperty(name = "Labels") + public boolean getShowLabels() { + return showLabels; + } + + public void setShowLabels(boolean showLabels) { + this.showLabels = showLabels; + } + + @Override + public String getControlPointNodeName(int index) { + if (index == 0) + return "Tip"; + if (index == 1) + return "Sleeve"; + if (index == 2 && getValue() == OpenJackType.STEREO) + return "Ring"; + if (index == 2 && getValue() == OpenJackType.SWITCHED) + return "Shunt"; + return null; + } + + @Override + public boolean canPointMoveFreely(int pointIndex) { + return false; + } + + public static enum OpenJackType { + + MONO, STEREO, SWITCHED; + + @Override + public String toString() { + return name().substring(0, 1) + name().substring(1).toLowerCase(); + } + } +} diff --git a/diylc/diylc-library/src/main/java/org/diylc/components/electromechanical/OpenJack1_8.java b/diylc/diylc-library/src/main/java/org/diylc/components/electromechanical/OpenJack1_8.java index 34b47f317..ec05aa0c3 100644 --- a/diylc/diylc-library/src/main/java/org/diylc/components/electromechanical/OpenJack1_8.java +++ b/diylc/diylc-library/src/main/java/org/diylc/components/electromechanical/OpenJack1_8.java @@ -102,10 +102,7 @@ public class OpenJack1_8 extends AbstractMultiPartComponent { g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(1)); // if (componentState != ComponentState.DRAGGING) { - Composite oldComposite = g2d.getComposite(); - if (alpha < MAX_ALPHA) { - g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1f * alpha / MAX_ALPHA)); - } + Composite oldComposite = applyAlpha(g2d, componentState); g2d.setColor(outlineMode ? Constants.TRANSPARENT_COLOR : WAFER_COLOR); g2d.fill(body[0]); @@ -126,10 +123,7 @@ public class OpenJack1_8 extends AbstractMultiPartComponent { g2d.draw(body[0]); // if (componentState != ComponentState.DRAGGING) { - oldComposite = g2d.getComposite(); - if (alpha < MAX_ALPHA) { - g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1f * alpha / MAX_ALPHA)); - } + oldComposite = applyAlpha(g2d, componentState); g2d.setColor(outlineMode ? Constants.TRANSPARENT_COLOR : BASE_COLOR); drawingObserver.startTrackingContinuityArea(true); diff --git a/diylc/diylc-library/src/main/java/org/diylc/components/electromechanical/PilotLampHolder.java b/diylc/diylc-library/src/main/java/org/diylc/components/electromechanical/PilotLampHolder.java index a0f15e032..5bc55f0e2 100644 --- a/diylc/diylc-library/src/main/java/org/diylc/components/electromechanical/PilotLampHolder.java +++ b/diylc/diylc-library/src/main/java/org/diylc/components/electromechanical/PilotLampHolder.java @@ -94,10 +94,7 @@ public class PilotLampHolder extends AbstractMultiPartComponent { g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(1)); // if (componentState != ComponentState.DRAGGING) { - Composite oldComposite = g2d.getComposite(); - if (alpha < MAX_ALPHA) { - g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1f * alpha / MAX_ALPHA)); - } + Composite oldComposite = applyAlpha(g2d, componentState); g2d.setColor(outlineMode ? Constants.TRANSPARENT_COLOR : WAFER_COLOR); g2d.fill(body[0]); @@ -118,10 +115,7 @@ public class PilotLampHolder extends AbstractMultiPartComponent { g2d.draw(body[0]); // if (componentState != ComponentState.DRAGGING) { - oldComposite = g2d.getComposite(); - if (alpha < MAX_ALPHA) { - g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1f * alpha / MAX_ALPHA)); - } + oldComposite = applyAlpha(g2d, componentState); g2d.setColor(outlineMode ? Constants.TRANSPARENT_COLOR : BASE_COLOR); drawingObserver.startTrackingContinuityArea(true); diff --git a/diylc/diylc-library/src/main/java/org/diylc/components/electromechanical/PinHeader.java b/diylc/diylc-library/src/main/java/org/diylc/components/electromechanical/PinHeader.java index 958bd203d..5240b69bc 100644 --- a/diylc/diylc-library/src/main/java/org/diylc/components/electromechanical/PinHeader.java +++ b/diylc/diylc-library/src/main/java/org/diylc/components/electromechanical/PinHeader.java @@ -222,10 +222,7 @@ public class PinHeader extends AbstractTransparentComponent { Area[] body = getBody(); Area mainArea = body[0]; Area shroudArea = body[1]; - Composite oldComposite = g2d.getComposite(); - if (alpha < MAX_ALPHA) { - g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1f * alpha / MAX_ALPHA)); - } + Composite oldComposite = applyAlpha(g2d, componentState); g2d.setColor(outlineMode ? Constants.TRANSPARENT_COLOR : bodyColor); g2d.fill(mainArea); if (shroudArea != null) { diff --git a/diylc/diylc-library/src/main/java/org/diylc/components/electromechanical/PlasticDCJack.java b/diylc/diylc-library/src/main/java/org/diylc/components/electromechanical/PlasticDCJack.java index 03178237b..8d6a0cb21 100644 --- a/diylc/diylc-library/src/main/java/org/diylc/components/electromechanical/PlasticDCJack.java +++ b/diylc/diylc-library/src/main/java/org/diylc/components/electromechanical/PlasticDCJack.java @@ -1,285 +1,282 @@ -/* - - DIY Layout Creator (DIYLC). - Copyright (c) 2009-2025 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.electromechanical; - -import java.awt.AlphaComposite; -import java.awt.Color; -import java.awt.Composite; -import java.awt.Graphics2D; -import java.awt.Shape; -import java.awt.geom.Area; -import java.awt.geom.Ellipse2D; -import java.awt.geom.Point2D; -import java.awt.geom.Rectangle2D; -import org.diylc.appframework.miscutils.ConfigurationManager; - -import org.diylc.awt.StringUtils; -import org.diylc.common.HorizontalAlignment; -import org.diylc.common.IPlugInPort; -import org.diylc.common.ObjectCache; -import org.diylc.common.VerticalAlignment; -import org.diylc.components.AbstractMultiPartComponent; -import org.diylc.core.ComponentState; -import org.diylc.core.IDIYComponent; -import org.diylc.core.IDrawingObserver; -import org.diylc.core.Project; -import org.diylc.core.Theme; -import org.diylc.core.VisibilityPolicy; -import org.diylc.core.annotations.ComponentDescriptor; -import org.diylc.core.annotations.EditableProperty; -import org.diylc.core.gerber.IGerberComponentSimple; -import org.diylc.core.measures.Size; -import org.diylc.core.measures.SizeUnit; -import org.diylc.utils.Constants; - -@ComponentDescriptor(name = "Plastic DC Jack", category = "Electro-Mechanical", author = "Branislav Stojkovic", - description = "Panel mount plastic DC jack", zOrder = IDIYComponent.COMPONENT, - instanceNamePrefix = "J", autoEdit = false, enableCache = true) -public class PlasticDCJack extends AbstractMultiPartComponent implements IGerberComponentSimple { - - private static final long serialVersionUID = 1L; - - private static Size LUG_WIDTH = new Size(0.08d, SizeUnit.in); - private static Size LUG_THICKNESS = new Size(0.02d, SizeUnit.in); - private static Size SPACING = new Size(0.1d, SizeUnit.in); - private static Size DIAMETER = new Size(0.5d, SizeUnit.in); - private static Color BODY_COLOR = Color.decode("#666666"); - private static Color BORDER_COLOR = Color.black; - private static Color MARKING_COLOR = Color.lightGray; - - private Point2D[] controlPoints = new Point2D[] {new Point2D.Double(0, 0), new Point2D.Double(0, 0), new Point2D.Double(0, 0)}; - private String value = ""; - private DCPolarity polarity = DCPolarity.CENTER_NEGATIVE; - transient private Area[] body; - - public PlasticDCJack() { - updateControlPoints(); - } - - private void updateControlPoints() { - // invalidate body shape - body = null; - - double x = controlPoints[0].getX(); - double y = controlPoints[0].getY(); - - int spacing = (int) SPACING.convertToPixels(); - controlPoints[1] = new Point2D.Double(x + spacing, y + spacing); - controlPoints[2] = new Point2D.Double(x - spacing, y + spacing * 2); - } - - @Override - public Area[] getBody() { - if (body == null) { - body = new Area[4]; - - double x = controlPoints[0].getX(); - double y = controlPoints[0].getY(); - int spacing = (int) SPACING.convertToPixels(); - int diameter = getClosestOdd(DIAMETER.convertToPixels()); - body[0] = new Area(new Ellipse2D.Double(x - diameter / 2, y + spacing - diameter / 2, diameter, diameter)); - - int rectWidth = (int) (diameter / Math.sqrt(2)) - 2; - body[1] = new Area(new Rectangle2D.Double(x - rectWidth / 2, y + spacing - rectWidth / 2, rectWidth, rectWidth)); - - int lugWidth = getClosestOdd(LUG_WIDTH.convertToPixels()); - int lugThickness = getClosestOdd(LUG_THICKNESS.convertToPixels()); - - Point2D groundPoint = controlPoints[controlPoints.length - 1]; - Area groundLug = - new Area(new Ellipse2D.Double(groundPoint.getX() + spacing - lugWidth / 2, groundPoint.getY() - lugWidth / 2, lugWidth, - lugWidth)); - groundLug.add(new Area(new Rectangle2D.Double(groundPoint.getX(), groundPoint.getY() - lugWidth / 2, spacing, lugWidth))); - groundLug.subtract(new Area(new Ellipse2D.Double(groundPoint.getX() + spacing - lugWidth / 6, groundPoint.getY() - lugWidth - / 6, lugWidth / 3, lugWidth / 3))); - body[2] = groundLug; - - Area lugArea = new Area(); - for (int i = 0; i < controlPoints.length; i++) { - Point2D point = controlPoints[i]; - if (i == getControlPointCount() - 1) { - lugArea.add(new Area( - new Rectangle2D.Double(point.getX() - lugThickness / 2, point.getY() - lugWidth / 2, lugThickness, lugWidth))); - } else { - lugArea.add(new Area( - new Rectangle2D.Double(point.getX() - lugWidth / 2, point.getY() - lugThickness / 2, lugWidth, lugThickness))); - } - } - body[3] = lugArea; - } - return body; - } - - @Override - public void draw(Graphics2D g2d, ComponentState componentState, boolean outlineMode, Project project, - IDrawingObserver drawingObserver) { - Shape[] body = getBody(); - - g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(1)); -// if (componentState != ComponentState.DRAGGING) { - 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 : BODY_COLOR); - g2d.fill(body[0]); - drawingObserver.stopTracking(); - if (!outlineMode) { - g2d.setColor(PHENOLIC_DARK_COLOR); - g2d.fill(body[1]); - } - g2d.setComposite(oldComposite); -// } - - Theme theme = (Theme) ConfigurationManager.getInstance().readObject(IPlugInPort.THEME_KEY, Constants.DEFAULT_THEME); - Color finalBorderColor; - if (outlineMode) { - finalBorderColor = - componentState == ComponentState.SELECTED || componentState == ComponentState.DRAGGING ? SELECTION_COLOR - : theme.getOutlineColor(); - } else { - finalBorderColor = - componentState == ComponentState.SELECTED || componentState == ComponentState.DRAGGING ? SELECTION_COLOR - : BORDER_COLOR; - } - - g2d.setColor(finalBorderColor); - g2d.draw(body[0]); - if (!outlineMode) { - g2d.setColor(PHENOLIC_DARK_COLOR.darker()); - g2d.draw(body[1]); - - g2d.setColor(METAL_COLOR); - g2d.fill(body[2]); - g2d.setColor(METAL_COLOR.darker()); - g2d.draw(body[2]); - - g2d.setColor(METAL_COLOR); - g2d.fill(body[3]); - } - - g2d.setColor(outlineMode ? theme.getOutlineColor() : METAL_COLOR.darker()); - g2d.draw(body[3]); - - if (!outlineMode && getPolarity() != DCPolarity.NONE) { - int spacing = (int) SPACING.convertToPixels(); - g2d.setColor(MARKING_COLOR); - g2d.setFont(project.getFont().deriveFont(12f)); - StringUtils.drawCenteredText(g2d, getPolarity() == DCPolarity.CENTER_NEGATIVE ? "+" : "-", controlPoints[0].getX(), - controlPoints[0].getY() - spacing * 7 / 16, HorizontalAlignment.CENTER, VerticalAlignment.CENTER); - StringUtils.drawCenteredText(g2d, getPolarity() == DCPolarity.CENTER_NEGATIVE ? "_" : "+", controlPoints[2].getX(), - controlPoints[2].getY() - spacing * 3 / 4, HorizontalAlignment.CENTER, VerticalAlignment.CENTER); - } - - drawSelectionOutline(g2d, componentState, outlineMode, project, drawingObserver); - } - - @Override - public void drawIcon(Graphics2D g2d, int width, int height) { - int margin = 2 * 32 / width; - int diameter = getClosestOdd(width - margin); - g2d.setColor(BODY_COLOR); - g2d.fillOval((width - diameter) / 2, (height - diameter) / 2, diameter, diameter); - g2d.setColor(BORDER_COLOR); - g2d.drawOval((width - diameter) / 2, (height - diameter) / 2, diameter, diameter); - int rectWidth = getClosestOdd(((width - 2 * margin) / Math.sqrt(2)) - margin / 2); - g2d.setColor(PHENOLIC_DARK_COLOR); - g2d.fillRect((width - rectWidth) / 2, (height - rectWidth) / 2, rectWidth, rectWidth); - g2d.setColor(PHENOLIC_DARK_COLOR.darker()); - g2d.drawRect((width - rectWidth) / 2, (height - rectWidth) / 2, rectWidth, rectWidth); - int lugWidth = 4 * 32 / width; - g2d.setColor(METAL_COLOR); - g2d.drawLine((width - lugWidth) / 2, height / 3, (width + lugWidth) / 2, height / 3); - g2d.drawLine(width * 2 / 3, (height - lugWidth) / 2, width * 2 / 3, (height + lugWidth) / 2); - g2d.fillOval((width - lugWidth) / 2, height * 2 / 3 - lugWidth / 2, lugWidth, lugWidth); - g2d.fillRect(width / 2 - lugWidth * 3 / 2, height * 2 / 3 - lugWidth / 2, lugWidth * 3 / 2, lugWidth); - g2d.setColor(PHENOLIC_DARK_COLOR); - g2d.fillOval((width - margin) / 2, height * 2 / 3 - margin / 2, margin, margin); - } - - @Override - public int getControlPointCount() { - return controlPoints.length; - } - - @Override - public Point2D getControlPoint(int index) { - return controlPoints[index]; - } - - @Override - public void setControlPoint(Point2D point, int index) { - controlPoints[index].setLocation(point); - this.body = null; - } - - @Override - public VisibilityPolicy getControlPointVisibilityPolicy(int index) { - return VisibilityPolicy.NEVER; - } - - @Override - public boolean isControlPointSticky(int index) { - return true; - } - - @EditableProperty - @Override - public String getValue() { - return value; - } - - @Override - public void setValue(String value) { - this.value = value; - } - - @EditableProperty - public DCPolarity getPolarity() { - if (polarity == null) { - polarity = DCPolarity.CENTER_NEGATIVE; - } - return polarity; - } - - public void setPolarity(DCPolarity polarity) { - this.polarity = polarity; - } - - @Override - public boolean canPointMoveFreely(int pointIndex) { - return false; - } - - @Override - public Rectangle2D getCachingBounds() { - int margin = 20; - Rectangle2D bounds = getBody()[0].getBounds2D(); - return new Rectangle2D.Double(bounds.getX() - margin, bounds.getY() - margin, bounds.getWidth() + 2 * margin, bounds.getHeight() + 2 * margin); - } - - @Deprecated - @Override - public Integer getFontSizeOverride() { - return super.getFontSizeOverride(); - } -} +/* + + DIY Layout Creator (DIYLC). + Copyright (c) 2009-2025 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.electromechanical; + +import java.awt.AlphaComposite; +import java.awt.Color; +import java.awt.Composite; +import java.awt.Graphics2D; +import java.awt.Shape; +import java.awt.geom.Area; +import java.awt.geom.Ellipse2D; +import java.awt.geom.Point2D; +import java.awt.geom.Rectangle2D; +import org.diylc.appframework.miscutils.ConfigurationManager; + +import org.diylc.awt.StringUtils; +import org.diylc.common.HorizontalAlignment; +import org.diylc.common.IPlugInPort; +import org.diylc.common.ObjectCache; +import org.diylc.common.VerticalAlignment; +import org.diylc.components.AbstractMultiPartComponent; +import org.diylc.core.ComponentState; +import org.diylc.core.IDIYComponent; +import org.diylc.core.IDrawingObserver; +import org.diylc.core.Project; +import org.diylc.core.Theme; +import org.diylc.core.VisibilityPolicy; +import org.diylc.core.annotations.ComponentDescriptor; +import org.diylc.core.annotations.EditableProperty; +import org.diylc.core.gerber.IGerberComponentSimple; +import org.diylc.core.measures.Size; +import org.diylc.core.measures.SizeUnit; +import org.diylc.utils.Constants; + +@ComponentDescriptor(name = "Plastic DC Jack", category = "Electro-Mechanical", author = "Branislav Stojkovic", + description = "Panel mount plastic DC jack", zOrder = IDIYComponent.COMPONENT, + instanceNamePrefix = "J", autoEdit = false, enableCache = true) +public class PlasticDCJack extends AbstractMultiPartComponent implements IGerberComponentSimple { + + private static final long serialVersionUID = 1L; + + private static Size LUG_WIDTH = new Size(0.08d, SizeUnit.in); + private static Size LUG_THICKNESS = new Size(0.02d, SizeUnit.in); + private static Size SPACING = new Size(0.1d, SizeUnit.in); + private static Size DIAMETER = new Size(0.5d, SizeUnit.in); + private static Color BODY_COLOR = Color.decode("#666666"); + private static Color BORDER_COLOR = Color.black; + private static Color MARKING_COLOR = Color.lightGray; + + private Point2D[] controlPoints = new Point2D[] {new Point2D.Double(0, 0), new Point2D.Double(0, 0), new Point2D.Double(0, 0)}; + private String value = ""; + private DCPolarity polarity = DCPolarity.CENTER_NEGATIVE; + transient private Area[] body; + + public PlasticDCJack() { + updateControlPoints(); + } + + private void updateControlPoints() { + // invalidate body shape + body = null; + + double x = controlPoints[0].getX(); + double y = controlPoints[0].getY(); + + int spacing = (int) SPACING.convertToPixels(); + controlPoints[1] = new Point2D.Double(x + spacing, y + spacing); + controlPoints[2] = new Point2D.Double(x - spacing, y + spacing * 2); + } + + @Override + public Area[] getBody() { + if (body == null) { + body = new Area[4]; + + double x = controlPoints[0].getX(); + double y = controlPoints[0].getY(); + int spacing = (int) SPACING.convertToPixels(); + int diameter = getClosestOdd(DIAMETER.convertToPixels()); + body[0] = new Area(new Ellipse2D.Double(x - diameter / 2, y + spacing - diameter / 2, diameter, diameter)); + + int rectWidth = (int) (diameter / Math.sqrt(2)) - 2; + body[1] = new Area(new Rectangle2D.Double(x - rectWidth / 2, y + spacing - rectWidth / 2, rectWidth, rectWidth)); + + int lugWidth = getClosestOdd(LUG_WIDTH.convertToPixels()); + int lugThickness = getClosestOdd(LUG_THICKNESS.convertToPixels()); + + Point2D groundPoint = controlPoints[controlPoints.length - 1]; + Area groundLug = + new Area(new Ellipse2D.Double(groundPoint.getX() + spacing - lugWidth / 2, groundPoint.getY() - lugWidth / 2, lugWidth, + lugWidth)); + groundLug.add(new Area(new Rectangle2D.Double(groundPoint.getX(), groundPoint.getY() - lugWidth / 2, spacing, lugWidth))); + groundLug.subtract(new Area(new Ellipse2D.Double(groundPoint.getX() + spacing - lugWidth / 6, groundPoint.getY() - lugWidth + / 6, lugWidth / 3, lugWidth / 3))); + body[2] = groundLug; + + Area lugArea = new Area(); + for (int i = 0; i < controlPoints.length; i++) { + Point2D point = controlPoints[i]; + if (i == getControlPointCount() - 1) { + lugArea.add(new Area( + new Rectangle2D.Double(point.getX() - lugThickness / 2, point.getY() - lugWidth / 2, lugThickness, lugWidth))); + } else { + lugArea.add(new Area( + new Rectangle2D.Double(point.getX() - lugWidth / 2, point.getY() - lugThickness / 2, lugWidth, lugThickness))); + } + } + body[3] = lugArea; + } + return body; + } + + @Override + public void draw(Graphics2D g2d, ComponentState componentState, boolean outlineMode, Project project, + IDrawingObserver drawingObserver) { + Shape[] body = getBody(); + + g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(1)); +// if (componentState != ComponentState.DRAGGING) { + Composite oldComposite = applyAlpha(g2d, componentState); + g2d.setColor(outlineMode ? Constants.TRANSPARENT_COLOR : BODY_COLOR); + g2d.fill(body[0]); + drawingObserver.stopTracking(); + if (!outlineMode) { + g2d.setColor(PHENOLIC_DARK_COLOR); + g2d.fill(body[1]); + } + g2d.setComposite(oldComposite); +// } + + Theme theme = (Theme) ConfigurationManager.getInstance().readObject(IPlugInPort.THEME_KEY, Constants.DEFAULT_THEME); + Color finalBorderColor; + if (outlineMode) { + finalBorderColor = + componentState == ComponentState.SELECTED || componentState == ComponentState.DRAGGING ? SELECTION_COLOR + : theme.getOutlineColor(); + } else { + finalBorderColor = + componentState == ComponentState.SELECTED || componentState == ComponentState.DRAGGING ? SELECTION_COLOR + : BORDER_COLOR; + } + + g2d.setColor(finalBorderColor); + g2d.draw(body[0]); + if (!outlineMode) { + g2d.setColor(PHENOLIC_DARK_COLOR.darker()); + g2d.draw(body[1]); + + g2d.setColor(METAL_COLOR); + g2d.fill(body[2]); + g2d.setColor(METAL_COLOR.darker()); + g2d.draw(body[2]); + + g2d.setColor(METAL_COLOR); + g2d.fill(body[3]); + } + + g2d.setColor(outlineMode ? theme.getOutlineColor() : METAL_COLOR.darker()); + g2d.draw(body[3]); + + if (!outlineMode && getPolarity() != DCPolarity.NONE) { + int spacing = (int) SPACING.convertToPixels(); + g2d.setColor(MARKING_COLOR); + g2d.setFont(project.getFont().deriveFont(12f)); + StringUtils.drawCenteredText(g2d, getPolarity() == DCPolarity.CENTER_NEGATIVE ? "+" : "-", controlPoints[0].getX(), + controlPoints[0].getY() - spacing * 7 / 16, HorizontalAlignment.CENTER, VerticalAlignment.CENTER); + StringUtils.drawCenteredText(g2d, getPolarity() == DCPolarity.CENTER_NEGATIVE ? "_" : "+", controlPoints[2].getX(), + controlPoints[2].getY() - spacing * 3 / 4, HorizontalAlignment.CENTER, VerticalAlignment.CENTER); + } + + drawSelectionOutline(g2d, componentState, outlineMode, project, drawingObserver); + } + + @Override + public void drawIcon(Graphics2D g2d, int width, int height) { + int margin = 2 * 32 / width; + int diameter = getClosestOdd(width - margin); + g2d.setColor(BODY_COLOR); + g2d.fillOval((width - diameter) / 2, (height - diameter) / 2, diameter, diameter); + g2d.setColor(BORDER_COLOR); + g2d.drawOval((width - diameter) / 2, (height - diameter) / 2, diameter, diameter); + int rectWidth = getClosestOdd(((width - 2 * margin) / Math.sqrt(2)) - margin / 2); + g2d.setColor(PHENOLIC_DARK_COLOR); + g2d.fillRect((width - rectWidth) / 2, (height - rectWidth) / 2, rectWidth, rectWidth); + g2d.setColor(PHENOLIC_DARK_COLOR.darker()); + g2d.drawRect((width - rectWidth) / 2, (height - rectWidth) / 2, rectWidth, rectWidth); + int lugWidth = 4 * 32 / width; + g2d.setColor(METAL_COLOR); + g2d.drawLine((width - lugWidth) / 2, height / 3, (width + lugWidth) / 2, height / 3); + g2d.drawLine(width * 2 / 3, (height - lugWidth) / 2, width * 2 / 3, (height + lugWidth) / 2); + g2d.fillOval((width - lugWidth) / 2, height * 2 / 3 - lugWidth / 2, lugWidth, lugWidth); + g2d.fillRect(width / 2 - lugWidth * 3 / 2, height * 2 / 3 - lugWidth / 2, lugWidth * 3 / 2, lugWidth); + g2d.setColor(PHENOLIC_DARK_COLOR); + g2d.fillOval((width - margin) / 2, height * 2 / 3 - margin / 2, margin, margin); + } + + @Override + public int getControlPointCount() { + return controlPoints.length; + } + + @Override + public Point2D getControlPoint(int index) { + return controlPoints[index]; + } + + @Override + public void setControlPoint(Point2D point, int index) { + controlPoints[index].setLocation(point); + this.body = null; + } + + @Override + public VisibilityPolicy getControlPointVisibilityPolicy(int index) { + return VisibilityPolicy.NEVER; + } + + @Override + public boolean isControlPointSticky(int index) { + return true; + } + + @EditableProperty + @Override + public String getValue() { + return value; + } + + @Override + public void setValue(String value) { + this.value = value; + } + + @EditableProperty + public DCPolarity getPolarity() { + if (polarity == null) { + polarity = DCPolarity.CENTER_NEGATIVE; + } + return polarity; + } + + public void setPolarity(DCPolarity polarity) { + this.polarity = polarity; + } + + @Override + public boolean canPointMoveFreely(int pointIndex) { + return false; + } + + @Override + public Rectangle2D getCachingBounds() { + int margin = 20; + Rectangle2D bounds = getBody()[0].getBounds2D(); + return new Rectangle2D.Double(bounds.getX() - margin, bounds.getY() - margin, bounds.getWidth() + 2 * margin, bounds.getHeight() + 2 * margin); + } + + @Deprecated + @Override + public Integer getFontSizeOverride() { + return super.getFontSizeOverride(); + } +} diff --git a/diylc/diylc-library/src/main/java/org/diylc/components/electromechanical/RCAJack.java b/diylc/diylc-library/src/main/java/org/diylc/components/electromechanical/RCAJack.java index 28f86a253..b3d08bc2d 100644 --- a/diylc/diylc-library/src/main/java/org/diylc/components/electromechanical/RCAJack.java +++ b/diylc/diylc-library/src/main/java/org/diylc/components/electromechanical/RCAJack.java @@ -1,345 +1,339 @@ -/* - - DIY Layout Creator (DIYLC). - Copyright (c) 2009-2025 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.electromechanical; - -import java.awt.AlphaComposite; -import java.awt.Color; -import java.awt.Composite; -import java.awt.Graphics2D; -import java.awt.Shape; -import java.awt.geom.AffineTransform; -import java.awt.geom.Area; -import java.awt.geom.Ellipse2D; -import java.awt.geom.Path2D; -import java.awt.geom.Point2D; -import java.awt.geom.Rectangle2D; -import org.diylc.appframework.miscutils.ConfigurationManager; - -import org.diylc.awt.TwoCircleTangent; -import org.diylc.common.IPlugInPort; -import org.diylc.common.ObjectCache; -import org.diylc.common.Orientation; -import org.diylc.components.AbstractMultiPartComponent; -import org.diylc.core.ComponentState; -import org.diylc.core.IDIYComponent; -import org.diylc.core.IDrawingObserver; -import org.diylc.core.Project; -import org.diylc.core.Theme; -import org.diylc.core.VisibilityPolicy; -import org.diylc.core.annotations.ComponentDescriptor; -import org.diylc.core.annotations.EditableProperty; -import org.diylc.core.measures.Size; -import org.diylc.core.measures.SizeUnit; -import org.diylc.utils.Constants; - -@ComponentDescriptor(name = "RCA Jack", category = "Electro-Mechanical", author = "Branislav Stojkovic", - description = "Panel mount RCA phono jack socket", zOrder = IDIYComponent.COMPONENT, instanceNamePrefix = "J", - enableCache = true) -public class RCAJack extends AbstractMultiPartComponent { - - private static final long serialVersionUID = 1L; - - private static Color BASE_COLOR = Color.lightGray; - private static Color WAFER_COLOR = Color.black; - - private static Size BODY_DIAMETER = new Size(0.52d, SizeUnit.in); - private static Size WAFER_DIAMETER = new Size(0.2d, SizeUnit.in); - private static Size HEX_DIAMETER = new Size(0.44d, SizeUnit.in); - private static Size SPRING_LENGTH = new Size(0.563d, SizeUnit.in); - private static Size SPRING_WIDTH = new Size(0.12d, SizeUnit.in); - private static Size HOLE_DIAMETER = new Size(0.05d, SizeUnit.in); - private static Size HOLE_TO_EDGE = new Size(0.063d, SizeUnit.in); - - private String value = ""; - private Point2D[] controlPoints = new Point2D[] {new Point2D.Double(0, 0), new Point2D.Double(0, 0) }; - transient Area[] body; - private Orientation orientation = Orientation.DEFAULT; - - public RCAJack() { - super(); - updateControlPoints(); - } - - @Override - public void draw(Graphics2D g2d, ComponentState componentState, boolean outlineMode, Project project, - IDrawingObserver drawingObserver) { - Shape[] body = getBody(); - - g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(1)); -// if (componentState != ComponentState.DRAGGING) { - 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 : WAFER_COLOR); - g2d.fill(body[0]); - - drawingObserver.stopTracking(); - - g2d.setComposite(oldComposite); -// } - - Color finalBorderColor; - - if (outlineMode) { - Theme theme = - (Theme) ConfigurationManager.getInstance().readObject(IPlugInPort.THEME_KEY, Constants.DEFAULT_THEME); - finalBorderColor = theme.getOutlineColor(); - } else { - finalBorderColor = WAFER_COLOR.darker(); - } - - g2d.setColor(finalBorderColor); - g2d.draw(body[0]); - - oldComposite = g2d.getComposite(); - if (alpha < MAX_ALPHA) { - g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1f * alpha / MAX_ALPHA)); - } - g2d.setColor(outlineMode ? Constants.TRANSPARENT_COLOR : BASE_COLOR); - - drawingObserver.startTrackingContinuityArea(true); - drawingObserver.startTracking(); - g2d.fill(body[1]); - g2d.fill(body[2]); - drawingObserver.stopTracking(); - drawingObserver.stopTrackingContinuityArea(); - - if (body[3] != null) - g2d.fill(body[3]); - - g2d.setComposite(oldComposite); - - if (outlineMode) { - Theme theme = - (Theme) ConfigurationManager.getInstance().readObject(IPlugInPort.THEME_KEY, Constants.DEFAULT_THEME); - finalBorderColor = theme.getOutlineColor(); - } else { - finalBorderColor = BASE_COLOR.darker(); - } - - g2d.setColor(finalBorderColor); - g2d.draw(body[1]); - g2d.draw(body[2]); - if (body[3] != null) - g2d.draw(body[3]); - - drawSelectionOutline(g2d, componentState, outlineMode, project, drawingObserver); - } - - public Area[] getBody() { - if (body == null) { - body = new Area[4]; - - double x0 = controlPoints[0].getX(); - double y0 = controlPoints[0].getY(); - double x1 = controlPoints[1].getX(); - double y1 = controlPoints[1].getY(); - int bodyDiameter = getClosestOdd(BODY_DIAMETER.convertToPixels()); - int waferDiameter = getClosestOdd(WAFER_DIAMETER.convertToPixels()); - int springWidth = (int) SPRING_WIDTH.convertToPixels(); - int holeDiameter = getClosestOdd(HOLE_DIAMETER.convertToPixels()); - double hexDiameter = HEX_DIAMETER.convertToPixels(); - - Area wafer = - new Area(new Ellipse2D.Double(x0 - waferDiameter / 2, y0 - waferDiameter / 2, waferDiameter, - waferDiameter)); - wafer.subtract(new Area(new Ellipse2D.Double(x0 - holeDiameter / 2, y0 - holeDiameter / 2, holeDiameter, - holeDiameter))); - - body[0] = wafer; - - Area tip = new TwoCircleTangent(controlPoints[0], controlPoints[1], bodyDiameter / 2, springWidth / 2); - tip.subtract(new Area( - new Ellipse2D.Double(x1 - holeDiameter / 2, y1 - holeDiameter / 2, holeDiameter, holeDiameter))); - tip.subtract(new Area(new Ellipse2D.Double(x0 - waferDiameter / 2, y0 - waferDiameter / 2, waferDiameter, - waferDiameter))); - - body[1] = tip; - - Area sleeve = - new Area(new Ellipse2D.Double(x0 - springWidth / 2, y0 - springWidth / 2, - springWidth, springWidth)); - sleeve.subtract(new Area(new Ellipse2D.Double(x0 - holeDiameter / 2, y0 - holeDiameter / 2, holeDiameter, - holeDiameter))); - - body[2] = sleeve; - - Path2D hex = new Path2D.Double(); - for (int i = 0; i < 6; i++) { - double x = x0 + Math.cos(Math.PI / 3 * i) * hexDiameter / 2; - double y = y0 + Math.sin(Math.PI / 3 * i) * hexDiameter / 2; - if (i == 0) - hex.moveTo(x, y); - else - hex.lineTo(x, y); - } - hex.closePath(); - Area hexArea = new Area(hex); - hexArea.subtract(new Area(new Ellipse2D.Double(x0 - waferDiameter / 2, y0 - waferDiameter / 2, waferDiameter, - waferDiameter))); - body[3] = hexArea; - } - - return body; - } - - @SuppressWarnings("incomplete-switch") - private void updateControlPoints() { - double x = controlPoints[0].getX(); - double y = controlPoints[0].getY(); - - int springLength = (int) SPRING_LENGTH.convertToPixels(); - int holeToEdge = (int) HOLE_TO_EDGE.convertToPixels(); - - double centerY = y + springLength - holeToEdge; - - controlPoints[1].setLocation(x, centerY); - - // Rotate if needed - if (orientation != Orientation.DEFAULT) { - double theta = 0; - switch (orientation) { - case _90: - theta = Math.PI / 2; - break; - case _180: - theta = Math.PI; - break; - case _270: - theta = Math.PI * 3 / 2; - break; - } - - AffineTransform rotation = AffineTransform.getRotateInstance(theta, x, y); - rotation.transform(controlPoints[1], controlPoints[1]); - } - } - - @Override - public void drawIcon(Graphics2D g2d, int width, int height) { - double x0 = width * 0.35; - double y0 = height * 0.65; - double x1 = width * 0.75; - double y1 = height * 0.25; - TwoCircleTangent main = new TwoCircleTangent(new Point2D.Double(width * 0.35, height * 0.65), new Point2D.Double(x1, y1), width * 0.3, width * 0.1); - main.subtract(new Area(new Ellipse2D.Double(x0 - 1, y0 - 1, 3, 3))); - main.subtract(new Area(new Ellipse2D.Double(x1 - 1, y1 - 1, 2, 2))); - - g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(1f)); - g2d.setColor(BASE_COLOR); - g2d.fill(main); - g2d.setColor(BASE_COLOR.darker()); - g2d.draw(main); - - double hexDiameter = width * 0.48; - - Path2D hex = new Path2D.Double(); - for (int i = 0; i < 6; i++) { - double x = x0 + Math.cos(Math.PI / 3 * i) * hexDiameter / 2; - double y = y0 + Math.sin(Math.PI / 3 * i) * hexDiameter / 2; - if (i == 0) - hex.moveTo(x, y); - else - hex.lineTo(x, y); - } - hex.closePath(); - g2d.draw(hex); - - double waferDiameter = width * 0.22; -// g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(2f)); - g2d.setColor(WAFER_COLOR); - g2d.draw(new Ellipse2D.Double(x0 - waferDiameter / 2, y0 - waferDiameter / 2, waferDiameter, waferDiameter)); - } - - @Override - public int getControlPointCount() { - return controlPoints.length; - } - - @Override - public VisibilityPolicy getControlPointVisibilityPolicy(int index) { - return VisibilityPolicy.NEVER; - } - - @Override - public boolean isControlPointSticky(int index) { - return true; - } - - @Override - public Point2D getControlPoint(int index) { - return controlPoints[index]; - } - - @Override - public void setControlPoint(Point2D point, int index) { - this.controlPoints[index].setLocation(point); - // Invalidate the body - body = null; - } - - @Override - public String getValue() { - return value; - } - - @Override - public void setValue(String value) { - this.value = value; - } - - @EditableProperty - public Orientation getOrientation() { - return orientation; - } - - public void setOrientation(Orientation orientation) { - this.orientation = orientation; - updateControlPoints(); - // Invalidate the body - body = null; - } - - @Override - public String getControlPointNodeName(int index) { - return getName() + (index == 0 ? "Tip" : "Sleeve"); - } - - @Override - public boolean canPointMoveFreely(int pointIndex) { - return false; - } - - @Override - public Rectangle2D getCachingBounds() { - int margin = 20; - Rectangle2D bounds = getBody()[1].getBounds2D(); - return new Rectangle2D.Double(bounds.getX() - margin, bounds.getY() - margin, bounds.getWidth() + 2 * margin, bounds.getHeight() + 2 * margin); - } - - @Deprecated - @Override - public Integer getFontSizeOverride() { - return super.getFontSizeOverride(); - } -} +/* + + DIY Layout Creator (DIYLC). + Copyright (c) 2009-2025 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.electromechanical; + +import java.awt.AlphaComposite; +import java.awt.Color; +import java.awt.Composite; +import java.awt.Graphics2D; +import java.awt.Shape; +import java.awt.geom.AffineTransform; +import java.awt.geom.Area; +import java.awt.geom.Ellipse2D; +import java.awt.geom.Path2D; +import java.awt.geom.Point2D; +import java.awt.geom.Rectangle2D; +import org.diylc.appframework.miscutils.ConfigurationManager; + +import org.diylc.awt.TwoCircleTangent; +import org.diylc.common.IPlugInPort; +import org.diylc.common.ObjectCache; +import org.diylc.common.Orientation; +import org.diylc.components.AbstractMultiPartComponent; +import org.diylc.core.ComponentState; +import org.diylc.core.IDIYComponent; +import org.diylc.core.IDrawingObserver; +import org.diylc.core.Project; +import org.diylc.core.Theme; +import org.diylc.core.VisibilityPolicy; +import org.diylc.core.annotations.ComponentDescriptor; +import org.diylc.core.annotations.EditableProperty; +import org.diylc.core.measures.Size; +import org.diylc.core.measures.SizeUnit; +import org.diylc.utils.Constants; + +@ComponentDescriptor(name = "RCA Jack", category = "Electro-Mechanical", author = "Branislav Stojkovic", + description = "Panel mount RCA phono jack socket", zOrder = IDIYComponent.COMPONENT, instanceNamePrefix = "J", + enableCache = true) +public class RCAJack extends AbstractMultiPartComponent { + + private static final long serialVersionUID = 1L; + + private static Color BASE_COLOR = Color.lightGray; + private static Color WAFER_COLOR = Color.black; + + private static Size BODY_DIAMETER = new Size(0.52d, SizeUnit.in); + private static Size WAFER_DIAMETER = new Size(0.2d, SizeUnit.in); + private static Size HEX_DIAMETER = new Size(0.44d, SizeUnit.in); + private static Size SPRING_LENGTH = new Size(0.563d, SizeUnit.in); + private static Size SPRING_WIDTH = new Size(0.12d, SizeUnit.in); + private static Size HOLE_DIAMETER = new Size(0.05d, SizeUnit.in); + private static Size HOLE_TO_EDGE = new Size(0.063d, SizeUnit.in); + + private String value = ""; + private Point2D[] controlPoints = new Point2D[] {new Point2D.Double(0, 0), new Point2D.Double(0, 0) }; + transient Area[] body; + private Orientation orientation = Orientation.DEFAULT; + + public RCAJack() { + super(); + updateControlPoints(); + } + + @Override + public void draw(Graphics2D g2d, ComponentState componentState, boolean outlineMode, Project project, + IDrawingObserver drawingObserver) { + Shape[] body = getBody(); + + g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(1)); +// if (componentState != ComponentState.DRAGGING) { + Composite oldComposite = applyAlpha(g2d, componentState); + g2d.setColor(outlineMode ? Constants.TRANSPARENT_COLOR : WAFER_COLOR); + g2d.fill(body[0]); + + drawingObserver.stopTracking(); + + g2d.setComposite(oldComposite); +// } + + Color finalBorderColor; + + if (outlineMode) { + Theme theme = + (Theme) ConfigurationManager.getInstance().readObject(IPlugInPort.THEME_KEY, Constants.DEFAULT_THEME); + finalBorderColor = theme.getOutlineColor(); + } else { + finalBorderColor = WAFER_COLOR.darker(); + } + + g2d.setColor(finalBorderColor); + g2d.draw(body[0]); + + oldComposite = applyAlpha(g2d, componentState); + g2d.setColor(outlineMode ? Constants.TRANSPARENT_COLOR : BASE_COLOR); + + drawingObserver.startTrackingContinuityArea(true); + drawingObserver.startTracking(); + g2d.fill(body[1]); + g2d.fill(body[2]); + drawingObserver.stopTracking(); + drawingObserver.stopTrackingContinuityArea(); + + if (body[3] != null) + g2d.fill(body[3]); + + g2d.setComposite(oldComposite); + + if (outlineMode) { + Theme theme = + (Theme) ConfigurationManager.getInstance().readObject(IPlugInPort.THEME_KEY, Constants.DEFAULT_THEME); + finalBorderColor = theme.getOutlineColor(); + } else { + finalBorderColor = BASE_COLOR.darker(); + } + + g2d.setColor(finalBorderColor); + g2d.draw(body[1]); + g2d.draw(body[2]); + if (body[3] != null) + g2d.draw(body[3]); + + drawSelectionOutline(g2d, componentState, outlineMode, project, drawingObserver); + } + + public Area[] getBody() { + if (body == null) { + body = new Area[4]; + + double x0 = controlPoints[0].getX(); + double y0 = controlPoints[0].getY(); + double x1 = controlPoints[1].getX(); + double y1 = controlPoints[1].getY(); + int bodyDiameter = getClosestOdd(BODY_DIAMETER.convertToPixels()); + int waferDiameter = getClosestOdd(WAFER_DIAMETER.convertToPixels()); + int springWidth = (int) SPRING_WIDTH.convertToPixels(); + int holeDiameter = getClosestOdd(HOLE_DIAMETER.convertToPixels()); + double hexDiameter = HEX_DIAMETER.convertToPixels(); + + Area wafer = + new Area(new Ellipse2D.Double(x0 - waferDiameter / 2, y0 - waferDiameter / 2, waferDiameter, + waferDiameter)); + wafer.subtract(new Area(new Ellipse2D.Double(x0 - holeDiameter / 2, y0 - holeDiameter / 2, holeDiameter, + holeDiameter))); + + body[0] = wafer; + + Area tip = new TwoCircleTangent(controlPoints[0], controlPoints[1], bodyDiameter / 2, springWidth / 2); + tip.subtract(new Area( + new Ellipse2D.Double(x1 - holeDiameter / 2, y1 - holeDiameter / 2, holeDiameter, holeDiameter))); + tip.subtract(new Area(new Ellipse2D.Double(x0 - waferDiameter / 2, y0 - waferDiameter / 2, waferDiameter, + waferDiameter))); + + body[1] = tip; + + Area sleeve = + new Area(new Ellipse2D.Double(x0 - springWidth / 2, y0 - springWidth / 2, + springWidth, springWidth)); + sleeve.subtract(new Area(new Ellipse2D.Double(x0 - holeDiameter / 2, y0 - holeDiameter / 2, holeDiameter, + holeDiameter))); + + body[2] = sleeve; + + Path2D hex = new Path2D.Double(); + for (int i = 0; i < 6; i++) { + double x = x0 + Math.cos(Math.PI / 3 * i) * hexDiameter / 2; + double y = y0 + Math.sin(Math.PI / 3 * i) * hexDiameter / 2; + if (i == 0) + hex.moveTo(x, y); + else + hex.lineTo(x, y); + } + hex.closePath(); + Area hexArea = new Area(hex); + hexArea.subtract(new Area(new Ellipse2D.Double(x0 - waferDiameter / 2, y0 - waferDiameter / 2, waferDiameter, + waferDiameter))); + body[3] = hexArea; + } + + return body; + } + + @SuppressWarnings("incomplete-switch") + private void updateControlPoints() { + double x = controlPoints[0].getX(); + double y = controlPoints[0].getY(); + + int springLength = (int) SPRING_LENGTH.convertToPixels(); + int holeToEdge = (int) HOLE_TO_EDGE.convertToPixels(); + + double centerY = y + springLength - holeToEdge; + + controlPoints[1].setLocation(x, centerY); + + // Rotate if needed + if (orientation != Orientation.DEFAULT) { + double theta = 0; + switch (orientation) { + case _90: + theta = Math.PI / 2; + break; + case _180: + theta = Math.PI; + break; + case _270: + theta = Math.PI * 3 / 2; + break; + } + + AffineTransform rotation = AffineTransform.getRotateInstance(theta, x, y); + rotation.transform(controlPoints[1], controlPoints[1]); + } + } + + @Override + public void drawIcon(Graphics2D g2d, int width, int height) { + double x0 = width * 0.35; + double y0 = height * 0.65; + double x1 = width * 0.75; + double y1 = height * 0.25; + TwoCircleTangent main = new TwoCircleTangent(new Point2D.Double(width * 0.35, height * 0.65), new Point2D.Double(x1, y1), width * 0.3, width * 0.1); + main.subtract(new Area(new Ellipse2D.Double(x0 - 1, y0 - 1, 3, 3))); + main.subtract(new Area(new Ellipse2D.Double(x1 - 1, y1 - 1, 2, 2))); + + g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(1f)); + g2d.setColor(BASE_COLOR); + g2d.fill(main); + g2d.setColor(BASE_COLOR.darker()); + g2d.draw(main); + + double hexDiameter = width * 0.48; + + Path2D hex = new Path2D.Double(); + for (int i = 0; i < 6; i++) { + double x = x0 + Math.cos(Math.PI / 3 * i) * hexDiameter / 2; + double y = y0 + Math.sin(Math.PI / 3 * i) * hexDiameter / 2; + if (i == 0) + hex.moveTo(x, y); + else + hex.lineTo(x, y); + } + hex.closePath(); + g2d.draw(hex); + + double waferDiameter = width * 0.22; +// g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(2f)); + g2d.setColor(WAFER_COLOR); + g2d.draw(new Ellipse2D.Double(x0 - waferDiameter / 2, y0 - waferDiameter / 2, waferDiameter, waferDiameter)); + } + + @Override + public int getControlPointCount() { + return controlPoints.length; + } + + @Override + public VisibilityPolicy getControlPointVisibilityPolicy(int index) { + return VisibilityPolicy.NEVER; + } + + @Override + public boolean isControlPointSticky(int index) { + return true; + } + + @Override + public Point2D getControlPoint(int index) { + return controlPoints[index]; + } + + @Override + public void setControlPoint(Point2D point, int index) { + this.controlPoints[index].setLocation(point); + // Invalidate the body + body = null; + } + + @Override + public String getValue() { + return value; + } + + @Override + public void setValue(String value) { + this.value = value; + } + + @EditableProperty + public Orientation getOrientation() { + return orientation; + } + + public void setOrientation(Orientation orientation) { + this.orientation = orientation; + updateControlPoints(); + // Invalidate the body + body = null; + } + + @Override + public String getControlPointNodeName(int index) { + return getName() + (index == 0 ? "Tip" : "Sleeve"); + } + + @Override + public boolean canPointMoveFreely(int pointIndex) { + return false; + } + + @Override + public Rectangle2D getCachingBounds() { + int margin = 20; + Rectangle2D bounds = getBody()[1].getBounds2D(); + return new Rectangle2D.Double(bounds.getX() - margin, bounds.getY() - margin, bounds.getWidth() + 2 * margin, bounds.getHeight() + 2 * margin); + } + + @Deprecated + @Override + public Integer getFontSizeOverride() { + return super.getFontSizeOverride(); + } +} diff --git a/diylc/diylc-library/src/main/java/org/diylc/components/electromechanical/RotarySelectorSwitch.java b/diylc/diylc-library/src/main/java/org/diylc/components/electromechanical/RotarySelectorSwitch.java index b9b75b2e8..1a7481af3 100644 --- a/diylc/diylc-library/src/main/java/org/diylc/components/electromechanical/RotarySelectorSwitch.java +++ b/diylc/diylc-library/src/main/java/org/diylc/components/electromechanical/RotarySelectorSwitch.java @@ -94,10 +94,7 @@ public class RotarySelectorSwitch extends AbstractMultiPartComponent imp g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(1)); // if (componentState != ComponentState.DRAGGING) { - Composite oldComposite = g2d.getComposite(); - if (alpha < MAX_ALPHA) { - g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1f * alpha / MAX_ALPHA)); - } + Composite oldComposite = applyAlpha(g2d, componentState); g2d.setColor(outlineMode ? Constants.TRANSPARENT_COLOR : BODY_COLOR); g2d.fill(body[0]); @@ -117,10 +114,7 @@ public class RotarySelectorSwitch extends AbstractMultiPartComponent imp g2d.setColor(finalBorderColor); g2d.draw(body[0]); - oldComposite = g2d.getComposite(); - if (alpha < MAX_ALPHA) { - g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1f * alpha / MAX_ALPHA)); - } + oldComposite = applyAlpha(g2d, componentState); g2d.setColor(outlineMode ? Constants.TRANSPARENT_COLOR : TERMINAL_COLOR); drawingObserver.startTrackingContinuityArea(true); diff --git a/diylc/diylc-library/src/main/java/org/diylc/components/electromechanical/RotarySwitchOpen.java b/diylc/diylc-library/src/main/java/org/diylc/components/electromechanical/RotarySwitchOpen.java index 3c4ebc05d..a2f2719bd 100644 --- a/diylc/diylc-library/src/main/java/org/diylc/components/electromechanical/RotarySwitchOpen.java +++ b/diylc/diylc-library/src/main/java/org/diylc/components/electromechanical/RotarySwitchOpen.java @@ -349,10 +349,8 @@ public class RotarySwitchOpen extends AbstractAngledComponent i Constants.DEFAULT_THEME); // Draw body if available. if (body != null) { - Composite oldComposite = g2d.getComposite(); - if (alpha < MAX_ALPHA) { - g2d.setComposite( - AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1f * alpha / MAX_ALPHA)); - } + Composite oldComposite = applyAlpha(g2d, componentState); if (getShowBracket()) { g2d.setColor(getBracketColor()); diff --git a/diylc/diylc-library/src/main/java/org/diylc/components/electromechanical/TactileMicroSwitch.java b/diylc/diylc-library/src/main/java/org/diylc/components/electromechanical/TactileMicroSwitch.java index 1f73d5876..024e92630 100644 --- a/diylc/diylc-library/src/main/java/org/diylc/components/electromechanical/TactileMicroSwitch.java +++ b/diylc/diylc-library/src/main/java/org/diylc/components/electromechanical/TactileMicroSwitch.java @@ -242,10 +242,7 @@ public class TactileMicroSwitch extends AbstractLabeledComponent impleme g2d.draw(rect); } } - Composite oldComposite = g2d.getComposite(); - if (alpha < MAX_ALPHA) { - g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1f * alpha / MAX_ALPHA)); - } + Composite oldComposite = applyAlpha(g2d, componentState); g2d.setColor(outlineMode ? Constants.TRANSPARENT_COLOR : getBodyColor()); drawingObserver.startTracking(); g2d.fill(mainArea); diff --git a/diylc/diylc-library/src/main/java/org/diylc/components/guitar/Freeway3x3_03.java b/diylc/diylc-library/src/main/java/org/diylc/components/guitar/Freeway3x3_03.java index 65682c528..4625767f5 100644 --- a/diylc/diylc-library/src/main/java/org/diylc/components/guitar/Freeway3x3_03.java +++ b/diylc/diylc-library/src/main/java/org/diylc/components/guitar/Freeway3x3_03.java @@ -146,10 +146,7 @@ public class Freeway3x3_03 extends AbstractTransparentComponent implements List labels = getLabels(); Shape caseShape = getCase(); - Composite oldComposite = g2d.getComposite(); - if (alpha < MAX_ALPHA) { - g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1f * alpha / MAX_ALPHA)); - } + Composite oldComposite = applyAlpha(g2d, componentState); AffineTransform oldTx = new AffineTransform(g2d.getTransform()); diff --git a/diylc/diylc-library/src/main/java/org/diylc/components/guitar/Freeway3x3_05.java b/diylc/diylc-library/src/main/java/org/diylc/components/guitar/Freeway3x3_05.java index cf0806694..2f2c83eef 100644 --- a/diylc/diylc-library/src/main/java/org/diylc/components/guitar/Freeway3x3_05.java +++ b/diylc/diylc-library/src/main/java/org/diylc/components/guitar/Freeway3x3_05.java @@ -121,10 +121,7 @@ public class Freeway3x3_05 extends AbstractTransparentComponent implements g2d.rotate(theta, x, y); } - Composite oldComposite = g2d.getComposite(); - if (alpha < MAX_ALPHA) { - g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1f * alpha / MAX_ALPHA)); - } + Composite oldComposite = applyAlpha(g2d, componentState); double offsetX = getXOffsetsPx()[0]; double offsetY = getYOffsetsPx()[0]; diff --git a/diylc/diylc-library/src/main/java/org/diylc/components/guitar/HumbuckerPickup.java b/diylc/diylc-library/src/main/java/org/diylc/components/guitar/HumbuckerPickup.java index 0549941da..32032eff9 100644 --- a/diylc/diylc-library/src/main/java/org/diylc/components/guitar/HumbuckerPickup.java +++ b/diylc/diylc-library/src/main/java/org/diylc/components/guitar/HumbuckerPickup.java @@ -98,10 +98,7 @@ public class HumbuckerPickup extends AbstractGuitarPickup { g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(1)); - Composite oldComposite = g2d.getComposite(); - if (alpha < MAX_ALPHA) { - g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1f * alpha / MAX_ALPHA)); - } + Composite oldComposite = applyAlpha(g2d, componentState); g2d.setColor(outlineMode ? Constants.TRANSPARENT_COLOR : color); if (getType() != HumbuckerType.Filtertron) { drawingObserver.startTracking(); diff --git a/diylc/diylc-library/src/main/java/org/diylc/components/guitar/JazzBassPickup.java b/diylc/diylc-library/src/main/java/org/diylc/components/guitar/JazzBassPickup.java index b1e8db1df..d0e4298a1 100644 --- a/diylc/diylc-library/src/main/java/org/diylc/components/guitar/JazzBassPickup.java +++ b/diylc/diylc-library/src/main/java/org/diylc/components/guitar/JazzBassPickup.java @@ -1,286 +1,283 @@ -/* - - DIY Layout Creator (DIYLC). - Copyright (c) 2009-2025 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.guitar; - -import java.awt.AlphaComposite; -import java.awt.Color; -import java.awt.Composite; -import java.awt.Graphics2D; -import java.awt.Shape; -import java.awt.geom.AffineTransform; -import java.awt.geom.Area; -import java.awt.geom.Ellipse2D; -import java.awt.geom.Point2D; -import java.awt.geom.RoundRectangle2D; -import org.diylc.appframework.miscutils.ConfigurationManager; - -import org.diylc.common.IPlugInPort; -import org.diylc.common.ObjectCache; -import org.diylc.common.Orientation; -import org.diylc.common.OrientationHV; -import org.diylc.components.transform.GuitarPickupTransformer; -import org.diylc.core.ComponentState; -import org.diylc.core.IDIYComponent; -import org.diylc.core.IDrawingObserver; -import org.diylc.core.Project; -import org.diylc.core.Theme; -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; -import org.diylc.utils.Constants; - -@ComponentDescriptor(name = "Jazz Bass Pickup", category = "Guitar", author = "Branislav Stojkovic", - description = "Single coil pickup for Jazz Bass and similar guitars", - zOrder = IDIYComponent.COMPONENT, instanceNamePrefix = "PKP", - keywordPolicy = KeywordPolicy.SHOW_TAG, keywordTag = "Guitar Wiring Diagram", enableCache = true, - transformer = GuitarPickupTransformer.class) -public class JazzBassPickup extends AbstractSingleOrHumbuckerPickup { - - private static final long serialVersionUID = 1L; - - private static Color BODY_COLOR = Color.decode("#333333"); - - private static Size WIDTH = new Size(0.73, SizeUnit.in); - private static Size LENGTH = new Size(4.1, SizeUnit.in); - private static Size EDGE_RADIUS = new Size(0.08d, SizeUnit.in); - private static Size LIP_RADIUS = new Size(0.45d, SizeUnit.in); - private static Size LIP_SPACING = new Size(1.92d, SizeUnit.in); - private static Size LIP_HOLE_SIZE = new Size(0.1d, SizeUnit.in); - private static Size LIP_HOLE_SPACING = new Size(0.1d, SizeUnit.in); - - private static Size POINT_MARGIN = new Size(1.5d, SizeUnit.mm); - private static Size POLE_SIZE = new Size(4d, SizeUnit.mm); - private static Size POLE_SPACING = new Size(0.85d, SizeUnit.in); - private static Size POLE_SPACING_MINOR = new Size(0.28d, SizeUnit.in); - - private Color color = BODY_COLOR; - private Color poleColor = METAL_COLOR; - - @Override - public void draw(Graphics2D g2d, ComponentState componentState, boolean outlineMode, Project project, - IDrawingObserver drawingObserver) { - - Shape[] body = getBody(); - - g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(1)); - - 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 : color); - g2d.fill(body[0]); - g2d.fill(body[1]); - drawingObserver.stopTracking(); - g2d.setComposite(oldComposite); - - markContactPoints(g2d, drawingObserver); - - 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 - : color.darker(); - } - - g2d.setColor(finalBorderColor); - g2d.draw(body[0]); - g2d.draw(body[1]); - - if (!outlineMode) { - g2d.setColor(getPoleColor()); - g2d.fill(body[3]); - g2d.setColor(darkerOrLighter(getPoleColor())); - g2d.draw(body[3]); - } - -// 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 -// : LABEL_COLOR; -// } -// g2d.setColor(finalLabelColor); -// g2d.setFont(project.getFont()); -// Rectangle bounds = body[0].getBounds(); -// drawCenteredText(g2d, value, bounds.x + bounds.width / 2, bounds.y + bounds.height / 2, HorizontalAlignment.CENTER, -// VerticalAlignment.CENTER); - drawMainLabel(g2d, project, outlineMode, componentState); - - drawTerminalLabels(g2d, finalBorderColor, project); - } - - @SuppressWarnings("incomplete-switch") - @Override - public Shape[] getBody() { - if (body == null) { - body = new Shape[4]; - - Point2D[] points = getControlPoints(); - double x = points[0].getX(); - double y = points[0].getY(); - int width = (int) WIDTH.convertToPixels(); - int length = (int) LENGTH.convertToPixels(); - int edgeRadius = (int) EDGE_RADIUS.convertToPixels(); - int pointMargin = (int) POINT_MARGIN.convertToPixels(); - int lipRadius = (int) LIP_RADIUS.convertToPixels(); - int lipSpacing = (int) LIP_SPACING.convertToPixels(); - int lipHoleSize = getClosestOdd(LIP_HOLE_SIZE.convertToPixels()); - int lipHoleSpacing = getClosestOdd(LIP_HOLE_SPACING.convertToPixels()); - - body[0] = - new Area(new RoundRectangle2D.Double(x - length, y - pointMargin, length, width, edgeRadius, - edgeRadius)); - - Area lip = new Area(new Ellipse2D.Double(-lipRadius / 2, -lipRadius / 2, lipRadius, lipRadius)); - lip.subtract(new Area(new Ellipse2D.Double(-lipHoleSize / 2, -lipHoleSpacing - lipHoleSize / 2, lipHoleSize, lipHoleSize))); - lip.transform(AffineTransform.getTranslateInstance(x - length / 2 - lipSpacing / 2, y - pointMargin)); - - body[1] = new Area(lip); - lip.transform(AffineTransform.getTranslateInstance(lipSpacing, 0)); - ((Area)body[1]).add(lip); - lip = new Area(body[1]); - double y1 = lip.getBounds2D().getY(); - lip.transform(AffineTransform.getScaleInstance(1, -1)); - lip.transform(AffineTransform.getTranslateInstance(0, 2 * y1 + width + lipRadius)); - ((Area)body[1]).add(lip); - - ((Area)body[1]).subtract((Area)body[0]); - - int poleSize = (int) POLE_SIZE.convertToPixels(); - int poleSpacing = (int) POLE_SPACING.convertToPixels(); - int poleSpacingMinor = (int) POLE_SPACING_MINOR.convertToPixels(); - int poleMargin = (length - poleSpacing * 3) / 2; - Area poleArea = new Area(); - for (int i = 0; i < 4; i++) { - Ellipse2D pole = - new Ellipse2D.Double(x - length + poleMargin + i * poleSpacing - poleSize / 2 - poleSpacingMinor / 2, y - - pointMargin - poleSize / 2 + width / 2, poleSize, poleSize); - poleArea.add(new Area(pole)); - pole = - new Ellipse2D.Double(x - length + poleMargin + i * poleSpacing - poleSize / 2 + poleSpacingMinor / 2, y - - pointMargin - poleSize / 2 + width / 2, poleSize, poleSize); - poleArea.add(new Area(pole)); - } - body[3] = poleArea; - - // Rotate if needed - if (orientation != Orientation.DEFAULT) { - double theta = 0; - switch (orientation) { - case _90: - theta = Math.PI / 2; - break; - case _180: - theta = Math.PI; - break; - case _270: - theta = Math.PI * 3 / 2; - break; - } - AffineTransform rotation = AffineTransform.getRotateInstance(theta, x, y); - for (Shape shape : body) { - Area area = (Area) shape; - if (shape != null) - area.transform(rotation); - } - } - } - return body; - } - - @Override - protected int getMainLabelYOffset() { - return (int) (WIDTH.convertToPixels() / 2 - 20); - } - - @Override - protected OrientationHV getControlPointDirection() { - return OrientationHV.VERTICAL; - } - - @Override - public void drawIcon(Graphics2D g2d, int width, int height) { - g2d.rotate(Math.PI / 4, width / 2, height / 2); - - int bodyWidth = (int) (5f * width / 32); - int bodyLength = (int) (30f * width / 32); - - g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(1f)); - g2d.setColor(BODY_COLOR); - g2d.fillRoundRect((width - bodyWidth) / 2, (height - bodyLength) / 2, bodyWidth, bodyLength, 3, 3); - - int lipSpacing = (int) (14f * width / 32); - int lipSize = (int) (3f * width / 32); - - g2d.fillRoundRect((width - bodyWidth) / 2 - lipSize, (height - lipSpacing - lipSize) / 2 , bodyWidth + 2 * lipSize, lipSize, lipSize, lipSize); - g2d.fillRoundRect((width - bodyWidth) / 2 - lipSize, (height + lipSpacing - lipSize) / 2 , bodyWidth + 2 * lipSize, lipSize, lipSize, lipSize); - - g2d.setColor(BODY_COLOR.darker()); - g2d.drawRoundRect((width - bodyWidth) / 2, (height - bodyLength) / 2, bodyWidth, bodyLength, 3, 3); - - // g2d.setColor(Color.gray); - // g2d.drawLine(width / 2, 4 * width / 32, width / 2, 4 * width / 32); - // g2d.drawLine(width / 2, height - 4 * width / 32, width / 2, height - 4 * width / 32); - - g2d.setColor(METAL_COLOR); - int poleSize = 2; - int poleSpacing = (int) (15d * width / 32); - for (int i = 0; i < 4; i++) { - g2d.fillOval((width - poleSize) / 2, (height - poleSpacing) / 2 + (i * poleSpacing / 3), poleSize, poleSize); - } - } - - @EditableProperty - public Color getColor() { - return color; - } - - public void setColor(Color color) { - this.color = color; - } - - @EditableProperty(name = "Pole Color") - public Color getPoleColor() { - if (poleColor == null) - poleColor = METAL_COLOR; - return poleColor; - } - - public void setPoleColor(Color poleColor) { - this.poleColor = poleColor; - } -} +/* + + DIY Layout Creator (DIYLC). + Copyright (c) 2009-2025 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.guitar; + +import java.awt.AlphaComposite; +import java.awt.Color; +import java.awt.Composite; +import java.awt.Graphics2D; +import java.awt.Shape; +import java.awt.geom.AffineTransform; +import java.awt.geom.Area; +import java.awt.geom.Ellipse2D; +import java.awt.geom.Point2D; +import java.awt.geom.RoundRectangle2D; +import org.diylc.appframework.miscutils.ConfigurationManager; + +import org.diylc.common.IPlugInPort; +import org.diylc.common.ObjectCache; +import org.diylc.common.Orientation; +import org.diylc.common.OrientationHV; +import org.diylc.components.transform.GuitarPickupTransformer; +import org.diylc.core.ComponentState; +import org.diylc.core.IDIYComponent; +import org.diylc.core.IDrawingObserver; +import org.diylc.core.Project; +import org.diylc.core.Theme; +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; +import org.diylc.utils.Constants; + +@ComponentDescriptor(name = "Jazz Bass Pickup", category = "Guitar", author = "Branislav Stojkovic", + description = "Single coil pickup for Jazz Bass and similar guitars", + zOrder = IDIYComponent.COMPONENT, instanceNamePrefix = "PKP", + keywordPolicy = KeywordPolicy.SHOW_TAG, keywordTag = "Guitar Wiring Diagram", enableCache = true, + transformer = GuitarPickupTransformer.class) +public class JazzBassPickup extends AbstractSingleOrHumbuckerPickup { + + private static final long serialVersionUID = 1L; + + private static Color BODY_COLOR = Color.decode("#333333"); + + private static Size WIDTH = new Size(0.73, SizeUnit.in); + private static Size LENGTH = new Size(4.1, SizeUnit.in); + private static Size EDGE_RADIUS = new Size(0.08d, SizeUnit.in); + private static Size LIP_RADIUS = new Size(0.45d, SizeUnit.in); + private static Size LIP_SPACING = new Size(1.92d, SizeUnit.in); + private static Size LIP_HOLE_SIZE = new Size(0.1d, SizeUnit.in); + private static Size LIP_HOLE_SPACING = new Size(0.1d, SizeUnit.in); + + private static Size POINT_MARGIN = new Size(1.5d, SizeUnit.mm); + private static Size POLE_SIZE = new Size(4d, SizeUnit.mm); + private static Size POLE_SPACING = new Size(0.85d, SizeUnit.in); + private static Size POLE_SPACING_MINOR = new Size(0.28d, SizeUnit.in); + + private Color color = BODY_COLOR; + private Color poleColor = METAL_COLOR; + + @Override + public void draw(Graphics2D g2d, ComponentState componentState, boolean outlineMode, Project project, + IDrawingObserver drawingObserver) { + + Shape[] body = getBody(); + + g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(1)); + + Composite oldComposite = applyAlpha(g2d, componentState); + g2d.setColor(outlineMode ? Constants.TRANSPARENT_COLOR : color); + g2d.fill(body[0]); + g2d.fill(body[1]); + drawingObserver.stopTracking(); + g2d.setComposite(oldComposite); + + markContactPoints(g2d, drawingObserver); + + 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 + : color.darker(); + } + + g2d.setColor(finalBorderColor); + g2d.draw(body[0]); + g2d.draw(body[1]); + + if (!outlineMode) { + g2d.setColor(getPoleColor()); + g2d.fill(body[3]); + g2d.setColor(darkerOrLighter(getPoleColor())); + g2d.draw(body[3]); + } + +// 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 +// : LABEL_COLOR; +// } +// g2d.setColor(finalLabelColor); +// g2d.setFont(project.getFont()); +// Rectangle bounds = body[0].getBounds(); +// drawCenteredText(g2d, value, bounds.x + bounds.width / 2, bounds.y + bounds.height / 2, HorizontalAlignment.CENTER, +// VerticalAlignment.CENTER); + drawMainLabel(g2d, project, outlineMode, componentState); + + drawTerminalLabels(g2d, finalBorderColor, project); + } + + @SuppressWarnings("incomplete-switch") + @Override + public Shape[] getBody() { + if (body == null) { + body = new Shape[4]; + + Point2D[] points = getControlPoints(); + double x = points[0].getX(); + double y = points[0].getY(); + int width = (int) WIDTH.convertToPixels(); + int length = (int) LENGTH.convertToPixels(); + int edgeRadius = (int) EDGE_RADIUS.convertToPixels(); + int pointMargin = (int) POINT_MARGIN.convertToPixels(); + int lipRadius = (int) LIP_RADIUS.convertToPixels(); + int lipSpacing = (int) LIP_SPACING.convertToPixels(); + int lipHoleSize = getClosestOdd(LIP_HOLE_SIZE.convertToPixels()); + int lipHoleSpacing = getClosestOdd(LIP_HOLE_SPACING.convertToPixels()); + + body[0] = + new Area(new RoundRectangle2D.Double(x - length, y - pointMargin, length, width, edgeRadius, + edgeRadius)); + + Area lip = new Area(new Ellipse2D.Double(-lipRadius / 2, -lipRadius / 2, lipRadius, lipRadius)); + lip.subtract(new Area(new Ellipse2D.Double(-lipHoleSize / 2, -lipHoleSpacing - lipHoleSize / 2, lipHoleSize, lipHoleSize))); + lip.transform(AffineTransform.getTranslateInstance(x - length / 2 - lipSpacing / 2, y - pointMargin)); + + body[1] = new Area(lip); + lip.transform(AffineTransform.getTranslateInstance(lipSpacing, 0)); + ((Area)body[1]).add(lip); + lip = new Area(body[1]); + double y1 = lip.getBounds2D().getY(); + lip.transform(AffineTransform.getScaleInstance(1, -1)); + lip.transform(AffineTransform.getTranslateInstance(0, 2 * y1 + width + lipRadius)); + ((Area)body[1]).add(lip); + + ((Area)body[1]).subtract((Area)body[0]); + + int poleSize = (int) POLE_SIZE.convertToPixels(); + int poleSpacing = (int) POLE_SPACING.convertToPixels(); + int poleSpacingMinor = (int) POLE_SPACING_MINOR.convertToPixels(); + int poleMargin = (length - poleSpacing * 3) / 2; + Area poleArea = new Area(); + for (int i = 0; i < 4; i++) { + Ellipse2D pole = + new Ellipse2D.Double(x - length + poleMargin + i * poleSpacing - poleSize / 2 - poleSpacingMinor / 2, y + - pointMargin - poleSize / 2 + width / 2, poleSize, poleSize); + poleArea.add(new Area(pole)); + pole = + new Ellipse2D.Double(x - length + poleMargin + i * poleSpacing - poleSize / 2 + poleSpacingMinor / 2, y + - pointMargin - poleSize / 2 + width / 2, poleSize, poleSize); + poleArea.add(new Area(pole)); + } + body[3] = poleArea; + + // Rotate if needed + if (orientation != Orientation.DEFAULT) { + double theta = 0; + switch (orientation) { + case _90: + theta = Math.PI / 2; + break; + case _180: + theta = Math.PI; + break; + case _270: + theta = Math.PI * 3 / 2; + break; + } + AffineTransform rotation = AffineTransform.getRotateInstance(theta, x, y); + for (Shape shape : body) { + Area area = (Area) shape; + if (shape != null) + area.transform(rotation); + } + } + } + return body; + } + + @Override + protected int getMainLabelYOffset() { + return (int) (WIDTH.convertToPixels() / 2 - 20); + } + + @Override + protected OrientationHV getControlPointDirection() { + return OrientationHV.VERTICAL; + } + + @Override + public void drawIcon(Graphics2D g2d, int width, int height) { + g2d.rotate(Math.PI / 4, width / 2, height / 2); + + int bodyWidth = (int) (5f * width / 32); + int bodyLength = (int) (30f * width / 32); + + g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(1f)); + g2d.setColor(BODY_COLOR); + g2d.fillRoundRect((width - bodyWidth) / 2, (height - bodyLength) / 2, bodyWidth, bodyLength, 3, 3); + + int lipSpacing = (int) (14f * width / 32); + int lipSize = (int) (3f * width / 32); + + g2d.fillRoundRect((width - bodyWidth) / 2 - lipSize, (height - lipSpacing - lipSize) / 2 , bodyWidth + 2 * lipSize, lipSize, lipSize, lipSize); + g2d.fillRoundRect((width - bodyWidth) / 2 - lipSize, (height + lipSpacing - lipSize) / 2 , bodyWidth + 2 * lipSize, lipSize, lipSize, lipSize); + + g2d.setColor(BODY_COLOR.darker()); + g2d.drawRoundRect((width - bodyWidth) / 2, (height - bodyLength) / 2, bodyWidth, bodyLength, 3, 3); + + // g2d.setColor(Color.gray); + // g2d.drawLine(width / 2, 4 * width / 32, width / 2, 4 * width / 32); + // g2d.drawLine(width / 2, height - 4 * width / 32, width / 2, height - 4 * width / 32); + + g2d.setColor(METAL_COLOR); + int poleSize = 2; + int poleSpacing = (int) (15d * width / 32); + for (int i = 0; i < 4; i++) { + g2d.fillOval((width - poleSize) / 2, (height - poleSpacing) / 2 + (i * poleSpacing / 3), poleSize, poleSize); + } + } + + @EditableProperty + public Color getColor() { + return color; + } + + public void setColor(Color color) { + this.color = color; + } + + @EditableProperty(name = "Pole Color") + public Color getPoleColor() { + if (poleColor == null) + poleColor = METAL_COLOR; + return poleColor; + } + + public void setPoleColor(Color poleColor) { + this.poleColor = poleColor; + } +} diff --git a/diylc/diylc-library/src/main/java/org/diylc/components/guitar/LPSwitch.java b/diylc/diylc-library/src/main/java/org/diylc/components/guitar/LPSwitch.java index 0c0f3a203..e2ae2e5bd 100644 --- a/diylc/diylc-library/src/main/java/org/diylc/components/guitar/LPSwitch.java +++ b/diylc/diylc-library/src/main/java/org/diylc/components/guitar/LPSwitch.java @@ -1,442 +1,439 @@ -/* - - DIY Layout Creator (DIYLC). - Copyright (c) 2009-2025 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.guitar; - -import java.awt.AlphaComposite; -import java.awt.Color; -import java.awt.Composite; -import java.awt.Graphics2D; -import java.awt.Shape; -import java.awt.geom.AffineTransform; -import java.awt.geom.Area; -import java.awt.geom.GeneralPath; -import java.awt.geom.Point2D; -import java.awt.geom.Rectangle2D; -import org.diylc.appframework.miscutils.ConfigurationManager; - -import org.diylc.common.IPlugInPort; -import org.diylc.common.ObjectCache; -import org.diylc.common.Orientation; -import org.diylc.components.AbstractTransparentComponent; -import org.diylc.core.ComponentState; -import org.diylc.core.IDIYComponent; -import org.diylc.core.IDrawingObserver; -import org.diylc.core.ISwitch; -import org.diylc.core.Project; -import org.diylc.core.Theme; -import org.diylc.core.VisibilityPolicy; -import org.diylc.core.annotations.ComponentDescriptor; -import org.diylc.core.annotations.EditableProperty; -import org.diylc.core.measures.Size; -import org.diylc.core.measures.SizeUnit; -import org.diylc.utils.Constants; - -@ComponentDescriptor(name = "LP Toggle Switch", category = "Guitar", author = "Branislav Stojkovic", - description = "Les Paul style 3 position toggle switch", zOrder = IDIYComponent.COMPONENT, - instanceNamePrefix = "SW") -public class LPSwitch extends AbstractTransparentComponent implements ISwitch { - - private static final long serialVersionUID = 1L; - - private static Color BASE_COLOR = Color.lightGray; - private static Color WAFER_COLOR = PHENOLIC_DARK_COLOR; - - private static Size LENGTH = new Size(1.3d, SizeUnit.in); - private static Size BASE_LENGTH = new Size(18d, SizeUnit.mm); - private static Size WAFER_THICKNESS = new Size(0.05d, SizeUnit.in); - private static Size TERMINAL_SPACING_CONNECTED = new Size(0.2d, SizeUnit.in); - private static Size TERMINAL_SPACING_DISCONNECTED = new Size(0.1d, SizeUnit.in); - - private String value = ""; - private Point2D[] controlPoints = new Point2D[] {new Point2D.Double(0, 0), new Point2D.Double(0, 0), new Point2D.Double(0, 0), new Point2D.Double(0, 0)}; - transient Shape[] body; - private Orientation orientation = Orientation.DEFAULT; - private MiddleTerminalConfiguration middleTerminalConfiguration; - - public LPSwitch() { - super(); - middleTerminalConfiguration = MiddleTerminalConfiguration.Connected; - updateControlPoints(); - } - - @Override - public void draw(Graphics2D g2d, ComponentState componentState, boolean outlineMode, Project project, - IDrawingObserver drawingObserver) { - Shape[] body = getBody(); - - g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(1)); - if (componentState != ComponentState.DRAGGING) { - 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 : WAFER_COLOR); - g2d.fill(body[1]); - g2d.setColor(outlineMode ? Constants.TRANSPARENT_COLOR : BASE_COLOR); - g2d.fill(body[0]); - g2d.setComposite(oldComposite); - } - - drawingObserver.stopTracking(); - - 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 - : WAFER_COLOR.darker(); - } - - g2d.setColor(finalBorderColor); - g2d.draw(body[0]); - - 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 - : BASE_COLOR.darker(); - } - - g2d.setColor(finalBorderColor); - g2d.draw(body[1]); - - g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(3)); - g2d.setColor(METAL_COLOR); - drawingObserver.startTracking(); - g2d.draw(body[2]); - drawingObserver.stopTracking(); - } - - @SuppressWarnings("incomplete-switch") - public Shape[] getBody() { - if (body == null) { - body = new Shape[3]; - - double x = controlPoints[0].getX(); - double y = controlPoints[0].getY(); - int baseLength = (int) BASE_LENGTH.convertToPixels(); - int length = (int) LENGTH.convertToPixels(); - int waferThickness = getClosestOdd(WAFER_THICKNESS.convertToPixels()); - - Rectangle2D ground = - new Rectangle2D.Double(x - waferThickness / 2, y, waferThickness - 1, baseLength + (length - baseLength) / 2); - body[0] = new Area(ground); - - double bodyY = y + (length - baseLength) / 2; - - Area waferArea = new Area();//new Area(new Rectangle2D.Double(x - waferThickness * 3 / 2, bodyY, waferThickness, baseLength)); - waferArea.add(new Area(new Rectangle2D.Double(x + waferThickness / 2, bodyY, waferThickness *3, baseLength))); - - waferArea.add(new Area(new Rectangle2D.Double(x - waferThickness * 5 / 2, bodyY, waferThickness, baseLength))); - waferArea.add(new Area(new Rectangle2D.Double(x + waferThickness * 3 / 2, bodyY, waferThickness, baseLength))); - - waferArea.add(new Area(new Rectangle2D.Double(x - waferThickness * 7 / 2, bodyY, waferThickness * 3, baseLength))); -// waferArea.add(new Area(new Rectangle2D.Double(x + waferThickness * 5 / 2, bodyY, waferThickness, baseLength))); - - body[1] = waferArea; - - double theta = 0; - // Rotate if needed - if (orientation != Orientation.DEFAULT) { - switch (orientation) { - case _90: - theta = Math.PI / 2; - break; - case _180: - theta = Math.PI; - break; - case _270: - theta = Math.PI * 3 / 2; - break; - } - } - - - GeneralPath terminalPath = new GeneralPath(GeneralPath.WIND_EVEN_ODD); - - if (getMiddleTerminalConfiguration() == MiddleTerminalConfiguration.Connected) { - int terminalSpacing = (int) TERMINAL_SPACING_CONNECTED.convertToPixels(); - terminalPath.moveTo(x - waferThickness * 3 / 2, bodyY + 1); - terminalPath.lineTo(x - waferThickness * 3 / 2, bodyY + baseLength); - terminalPath.lineTo(x, y + length); - - terminalPath.moveTo(x + waferThickness * 3 / 2, bodyY + 1); - terminalPath.lineTo(x + waferThickness * 3 / 2, bodyY + baseLength); - terminalPath.lineTo(x, y + length); - - terminalPath.moveTo(x - waferThickness * 5 / 2, bodyY + 1); - terminalPath.lineTo(x - waferThickness * 5 / 2, bodyY + baseLength); - terminalPath.lineTo(x - terminalSpacing, y + length); - - terminalPath.moveTo(x + waferThickness * 5 / 2, bodyY + 1); - terminalPath.lineTo(x + waferThickness * 5 / 2, bodyY + baseLength); - terminalPath.lineTo(x + terminalSpacing, y + length); - } else { - int terminalSpacing = (int) TERMINAL_SPACING_DISCONNECTED.convertToPixels(); - terminalPath.moveTo(x - waferThickness * 3 / 2, bodyY + 1); - terminalPath.lineTo(x - waferThickness * 3 / 2, bodyY + baseLength); - terminalPath.lineTo(x- terminalSpacing, y + length); - - terminalPath.moveTo(x + waferThickness * 3 / 2, bodyY + 1); - terminalPath.lineTo(x + waferThickness * 3 / 2, bodyY + baseLength); - terminalPath.lineTo(x + terminalSpacing, y + length); - - terminalPath.moveTo(x - waferThickness * 5 / 2, bodyY + 1); - terminalPath.lineTo(x - waferThickness * 5 / 2, bodyY + baseLength); - terminalPath.lineTo(x - terminalSpacing * 2, y + length); - - terminalPath.moveTo(x + waferThickness * 5 / 2, bodyY + 1); - terminalPath.lineTo(x + waferThickness * 5 / 2, bodyY + baseLength); - terminalPath.lineTo(x + terminalSpacing * 2, y + length); - } - body[2] = terminalPath; - - // Rotate if needed - if (theta != 0) { - AffineTransform rotation = AffineTransform.getRotateInstance(theta, x, y); - // Skip the last one because it's already rotated - for (int i = 0; i < body.length; i++) { - Shape shape = body[i]; - if (shape instanceof Area) { - Area area = (Area) shape; - area.transform(rotation); - } else if (shape instanceof GeneralPath) { - GeneralPath path = (GeneralPath) shape; - path.transform(rotation); - } - } - } - } - return body; - } - - @SuppressWarnings("incomplete-switch") - private void updateControlPoints() { - - Point2D[] newControlPoints = null; - if (getMiddleTerminalConfiguration() == MiddleTerminalConfiguration.Connected && controlPoints.length == 5) { - newControlPoints = new Point2D[4]; - } else if (getMiddleTerminalConfiguration() == MiddleTerminalConfiguration.Disconnected && controlPoints.length == 4) { - newControlPoints = new Point2D[5]; - newControlPoints[4] = new Point2D.Double(); - } - if (newControlPoints != null) { - for (int i = 0; i < newControlPoints.length && i < controlPoints.length; i++) { - newControlPoints[i] = controlPoints[i]; - } - controlPoints = newControlPoints; - } - - double x = controlPoints[0].getX(); - double y = controlPoints[0].getY(); - int length = (int) LENGTH.convertToPixels(); - - if (getMiddleTerminalConfiguration() == MiddleTerminalConfiguration.Connected) { - int terminalSpacing = (int) TERMINAL_SPACING_CONNECTED.convertToPixels(); - controlPoints[1].setLocation(x - terminalSpacing, y + length); - controlPoints[2].setLocation(x, y + length); - controlPoints[3].setLocation(x + terminalSpacing, y + length); - } else { - int terminalSpacing = (int) TERMINAL_SPACING_DISCONNECTED.convertToPixels(); - controlPoints[1].setLocation(x - terminalSpacing * 2, y + length); - controlPoints[2].setLocation(x - terminalSpacing, y + length); - controlPoints[3].setLocation(x + terminalSpacing, y + length); - controlPoints[4].setLocation(x + terminalSpacing * 2, y + length); - } - - // Rotate if needed - if (orientation != Orientation.DEFAULT) { - double theta = 0; - switch (orientation) { - case _90: - theta = Math.PI / 2; - break; - case _180: - theta = Math.PI; - break; - case _270: - theta = Math.PI * 3 / 2; - break; - } - AffineTransform rotation = AffineTransform.getRotateInstance(theta, x, y); - for (Point2D point : controlPoints) { - rotation.transform(point, point); - } - } - } - - @Override - public void drawIcon(Graphics2D g2d, int width, int height) { - g2d.rotate(Math.PI / 4, width / 2, height / 2); - int baseLength = 20 * width / 32; - - g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(3f)); - g2d.setColor(BASE_COLOR); - g2d.drawLine(width / 2, 0, width / 2, baseLength + (width - baseLength) / 2); - g2d.setColor(WAFER_COLOR); - g2d.fillRect(8 * width / 32, (width - baseLength) / 2, 16 * width / 32, baseLength); - g2d.setColor(METAL_COLOR); - g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(1f)); - g2d.drawLine(width / 2 - 2, (width - baseLength) / 2, width / 2 - 2, baseLength + (width - baseLength) / 2); - g2d.drawLine(width / 2 + 2, (width - baseLength) / 2, width / 2 + 2, baseLength + (width - baseLength) / 2); - g2d.drawLine(width / 2 - 5, (width - baseLength) / 2, width / 2 - 5, baseLength + (width - baseLength) / 2); - g2d.drawLine(width / 2 + 5, (width - baseLength) / 2, width / 2 + 5, baseLength + (width - baseLength) / 2); - int dx = 2 * width / 32; - int dy = 4 * width / 32; - g2d.drawLine(width / 2 - 2, baseLength + (width - baseLength) / 2, width / 2 - 2 + dx, baseLength - + (width - baseLength) / 2 + dy); - g2d.drawLine(width / 2 + 2, baseLength + (width - baseLength) / 2, width / 2 + 2 - dx, baseLength - + (width - baseLength) / 2 + dy); - - g2d.drawLine(width / 2 - 5, baseLength + (width - baseLength) / 2, width / 2 - 5 - dx, baseLength - + (width - baseLength) / 2 + dy); - g2d.drawLine(width / 2 + 5, baseLength + (width - baseLength) / 2, width / 2 + 5 + dx, baseLength - + (width - baseLength) / 2 + dy); - } - - @Override - public int getControlPointCount() { - return controlPoints.length; - } - - @Override - public VisibilityPolicy getControlPointVisibilityPolicy(int index) { - return VisibilityPolicy.ALWAYS; - } - - @Override - public boolean isControlPointSticky(int index) { - return true; - } - - @Override - public Point2D getControlPoint(int index) { - return controlPoints[index]; - } - - @Override - public void setControlPoint(Point2D point, int index) { - this.controlPoints[index].setLocation(point); - // Invalidate the body - body = null; - } - - @Override - public boolean canPointMoveFreely(int pointIndex) { - return false; - } - - @Override - public String getValue() { - return value; - } - - @Override - public void setValue(String value) { - this.value = value; - } - - @EditableProperty - public Orientation getOrientation() { - return orientation; - } - - public void setOrientation(Orientation orientation) { - this.orientation = orientation; - updateControlPoints(); - // Invalidate the body - body = null; - } - - @EditableProperty(name = "Middle Terminals") - public MiddleTerminalConfiguration getMiddleTerminalConfiguration() { - if (middleTerminalConfiguration == null) { - middleTerminalConfiguration = MiddleTerminalConfiguration.Connected; - } - return middleTerminalConfiguration; - } - - public void setMiddleTerminalConfiguration( - MiddleTerminalConfiguration middleTerminalConfiguration) { - this.middleTerminalConfiguration = middleTerminalConfiguration; - updateControlPoints(); - // Invalidate the body - body = null; - } - - // @Override -// public String getControlPointNodeName(int index) { -// // we don't want the switch to produce any nodes, it just makes connections -// return null; -// } -// - // switch stuff - - @Override - public int getPositionCount() { - return 3; - } - - @Override - public String getPositionName(int position) { - return switch (position) { - case 0 -> "Treble"; - case 1 -> "Middle"; - case 2 -> "Rhythm"; - default -> null; - }; - } - - @Override - public boolean arePointsConnected(int index1, int index2, int position) { - if (getMiddleTerminalConfiguration() == MiddleTerminalConfiguration.Connected) { - return switch (position) { - case 0 -> index1 == 1 && index2 == 2; - case 1 -> index1 > 0 && index2 > 0 && index1 < index2; - case 2 -> index1 == 2 && index2 == 3; - default -> false; - }; - } else { - return switch (position) { - case 0 -> index1 == 1 && index2 == 2; - case 1 -> (index1 == 1 && index2 == 2) || (index1 == 3 && index2 == 4); - case 2 -> index1 == 3 && index2 == 4; - default -> false; - }; - } - } - - public enum MiddleTerminalConfiguration { - Connected, Disconnected - } -} +/* + + DIY Layout Creator (DIYLC). + Copyright (c) 2009-2025 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.guitar; + +import java.awt.AlphaComposite; +import java.awt.Color; +import java.awt.Composite; +import java.awt.Graphics2D; +import java.awt.Shape; +import java.awt.geom.AffineTransform; +import java.awt.geom.Area; +import java.awt.geom.GeneralPath; +import java.awt.geom.Point2D; +import java.awt.geom.Rectangle2D; +import org.diylc.appframework.miscutils.ConfigurationManager; + +import org.diylc.common.IPlugInPort; +import org.diylc.common.ObjectCache; +import org.diylc.common.Orientation; +import org.diylc.components.AbstractTransparentComponent; +import org.diylc.core.ComponentState; +import org.diylc.core.IDIYComponent; +import org.diylc.core.IDrawingObserver; +import org.diylc.core.ISwitch; +import org.diylc.core.Project; +import org.diylc.core.Theme; +import org.diylc.core.VisibilityPolicy; +import org.diylc.core.annotations.ComponentDescriptor; +import org.diylc.core.annotations.EditableProperty; +import org.diylc.core.measures.Size; +import org.diylc.core.measures.SizeUnit; +import org.diylc.utils.Constants; + +@ComponentDescriptor(name = "LP Toggle Switch", category = "Guitar", author = "Branislav Stojkovic", + description = "Les Paul style 3 position toggle switch", zOrder = IDIYComponent.COMPONENT, + instanceNamePrefix = "SW") +public class LPSwitch extends AbstractTransparentComponent implements ISwitch { + + private static final long serialVersionUID = 1L; + + private static Color BASE_COLOR = Color.lightGray; + private static Color WAFER_COLOR = PHENOLIC_DARK_COLOR; + + private static Size LENGTH = new Size(1.3d, SizeUnit.in); + private static Size BASE_LENGTH = new Size(18d, SizeUnit.mm); + private static Size WAFER_THICKNESS = new Size(0.05d, SizeUnit.in); + private static Size TERMINAL_SPACING_CONNECTED = new Size(0.2d, SizeUnit.in); + private static Size TERMINAL_SPACING_DISCONNECTED = new Size(0.1d, SizeUnit.in); + + private String value = ""; + private Point2D[] controlPoints = new Point2D[] {new Point2D.Double(0, 0), new Point2D.Double(0, 0), new Point2D.Double(0, 0), new Point2D.Double(0, 0)}; + transient Shape[] body; + private Orientation orientation = Orientation.DEFAULT; + private MiddleTerminalConfiguration middleTerminalConfiguration; + + public LPSwitch() { + super(); + middleTerminalConfiguration = MiddleTerminalConfiguration.Connected; + updateControlPoints(); + } + + @Override + public void draw(Graphics2D g2d, ComponentState componentState, boolean outlineMode, Project project, + IDrawingObserver drawingObserver) { + Shape[] body = getBody(); + + g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(1)); + if (componentState != ComponentState.DRAGGING) { + Composite oldComposite = applyAlpha(g2d, componentState); + g2d.setColor(outlineMode ? Constants.TRANSPARENT_COLOR : WAFER_COLOR); + g2d.fill(body[1]); + g2d.setColor(outlineMode ? Constants.TRANSPARENT_COLOR : BASE_COLOR); + g2d.fill(body[0]); + g2d.setComposite(oldComposite); + } + + drawingObserver.stopTracking(); + + 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 + : WAFER_COLOR.darker(); + } + + g2d.setColor(finalBorderColor); + g2d.draw(body[0]); + + 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 + : BASE_COLOR.darker(); + } + + g2d.setColor(finalBorderColor); + g2d.draw(body[1]); + + g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(3)); + g2d.setColor(METAL_COLOR); + drawingObserver.startTracking(); + g2d.draw(body[2]); + drawingObserver.stopTracking(); + } + + @SuppressWarnings("incomplete-switch") + public Shape[] getBody() { + if (body == null) { + body = new Shape[3]; + + double x = controlPoints[0].getX(); + double y = controlPoints[0].getY(); + int baseLength = (int) BASE_LENGTH.convertToPixels(); + int length = (int) LENGTH.convertToPixels(); + int waferThickness = getClosestOdd(WAFER_THICKNESS.convertToPixels()); + + Rectangle2D ground = + new Rectangle2D.Double(x - waferThickness / 2, y, waferThickness - 1, baseLength + (length - baseLength) / 2); + body[0] = new Area(ground); + + double bodyY = y + (length - baseLength) / 2; + + Area waferArea = new Area();//new Area(new Rectangle2D.Double(x - waferThickness * 3 / 2, bodyY, waferThickness, baseLength)); + waferArea.add(new Area(new Rectangle2D.Double(x + waferThickness / 2, bodyY, waferThickness *3, baseLength))); + + waferArea.add(new Area(new Rectangle2D.Double(x - waferThickness * 5 / 2, bodyY, waferThickness, baseLength))); + waferArea.add(new Area(new Rectangle2D.Double(x + waferThickness * 3 / 2, bodyY, waferThickness, baseLength))); + + waferArea.add(new Area(new Rectangle2D.Double(x - waferThickness * 7 / 2, bodyY, waferThickness * 3, baseLength))); +// waferArea.add(new Area(new Rectangle2D.Double(x + waferThickness * 5 / 2, bodyY, waferThickness, baseLength))); + + body[1] = waferArea; + + double theta = 0; + // Rotate if needed + if (orientation != Orientation.DEFAULT) { + switch (orientation) { + case _90: + theta = Math.PI / 2; + break; + case _180: + theta = Math.PI; + break; + case _270: + theta = Math.PI * 3 / 2; + break; + } + } + + + GeneralPath terminalPath = new GeneralPath(GeneralPath.WIND_EVEN_ODD); + + if (getMiddleTerminalConfiguration() == MiddleTerminalConfiguration.Connected) { + int terminalSpacing = (int) TERMINAL_SPACING_CONNECTED.convertToPixels(); + terminalPath.moveTo(x - waferThickness * 3 / 2, bodyY + 1); + terminalPath.lineTo(x - waferThickness * 3 / 2, bodyY + baseLength); + terminalPath.lineTo(x, y + length); + + terminalPath.moveTo(x + waferThickness * 3 / 2, bodyY + 1); + terminalPath.lineTo(x + waferThickness * 3 / 2, bodyY + baseLength); + terminalPath.lineTo(x, y + length); + + terminalPath.moveTo(x - waferThickness * 5 / 2, bodyY + 1); + terminalPath.lineTo(x - waferThickness * 5 / 2, bodyY + baseLength); + terminalPath.lineTo(x - terminalSpacing, y + length); + + terminalPath.moveTo(x + waferThickness * 5 / 2, bodyY + 1); + terminalPath.lineTo(x + waferThickness * 5 / 2, bodyY + baseLength); + terminalPath.lineTo(x + terminalSpacing, y + length); + } else { + int terminalSpacing = (int) TERMINAL_SPACING_DISCONNECTED.convertToPixels(); + terminalPath.moveTo(x - waferThickness * 3 / 2, bodyY + 1); + terminalPath.lineTo(x - waferThickness * 3 / 2, bodyY + baseLength); + terminalPath.lineTo(x- terminalSpacing, y + length); + + terminalPath.moveTo(x + waferThickness * 3 / 2, bodyY + 1); + terminalPath.lineTo(x + waferThickness * 3 / 2, bodyY + baseLength); + terminalPath.lineTo(x + terminalSpacing, y + length); + + terminalPath.moveTo(x - waferThickness * 5 / 2, bodyY + 1); + terminalPath.lineTo(x - waferThickness * 5 / 2, bodyY + baseLength); + terminalPath.lineTo(x - terminalSpacing * 2, y + length); + + terminalPath.moveTo(x + waferThickness * 5 / 2, bodyY + 1); + terminalPath.lineTo(x + waferThickness * 5 / 2, bodyY + baseLength); + terminalPath.lineTo(x + terminalSpacing * 2, y + length); + } + body[2] = terminalPath; + + // Rotate if needed + if (theta != 0) { + AffineTransform rotation = AffineTransform.getRotateInstance(theta, x, y); + // Skip the last one because it's already rotated + for (int i = 0; i < body.length; i++) { + Shape shape = body[i]; + if (shape instanceof Area) { + Area area = (Area) shape; + area.transform(rotation); + } else if (shape instanceof GeneralPath) { + GeneralPath path = (GeneralPath) shape; + path.transform(rotation); + } + } + } + } + return body; + } + + @SuppressWarnings("incomplete-switch") + private void updateControlPoints() { + + Point2D[] newControlPoints = null; + if (getMiddleTerminalConfiguration() == MiddleTerminalConfiguration.Connected && controlPoints.length == 5) { + newControlPoints = new Point2D[4]; + } else if (getMiddleTerminalConfiguration() == MiddleTerminalConfiguration.Disconnected && controlPoints.length == 4) { + newControlPoints = new Point2D[5]; + newControlPoints[4] = new Point2D.Double(); + } + if (newControlPoints != null) { + for (int i = 0; i < newControlPoints.length && i < controlPoints.length; i++) { + newControlPoints[i] = controlPoints[i]; + } + controlPoints = newControlPoints; + } + + double x = controlPoints[0].getX(); + double y = controlPoints[0].getY(); + int length = (int) LENGTH.convertToPixels(); + + if (getMiddleTerminalConfiguration() == MiddleTerminalConfiguration.Connected) { + int terminalSpacing = (int) TERMINAL_SPACING_CONNECTED.convertToPixels(); + controlPoints[1].setLocation(x - terminalSpacing, y + length); + controlPoints[2].setLocation(x, y + length); + controlPoints[3].setLocation(x + terminalSpacing, y + length); + } else { + int terminalSpacing = (int) TERMINAL_SPACING_DISCONNECTED.convertToPixels(); + controlPoints[1].setLocation(x - terminalSpacing * 2, y + length); + controlPoints[2].setLocation(x - terminalSpacing, y + length); + controlPoints[3].setLocation(x + terminalSpacing, y + length); + controlPoints[4].setLocation(x + terminalSpacing * 2, y + length); + } + + // Rotate if needed + if (orientation != Orientation.DEFAULT) { + double theta = 0; + switch (orientation) { + case _90: + theta = Math.PI / 2; + break; + case _180: + theta = Math.PI; + break; + case _270: + theta = Math.PI * 3 / 2; + break; + } + AffineTransform rotation = AffineTransform.getRotateInstance(theta, x, y); + for (Point2D point : controlPoints) { + rotation.transform(point, point); + } + } + } + + @Override + public void drawIcon(Graphics2D g2d, int width, int height) { + g2d.rotate(Math.PI / 4, width / 2, height / 2); + int baseLength = 20 * width / 32; + + g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(3f)); + g2d.setColor(BASE_COLOR); + g2d.drawLine(width / 2, 0, width / 2, baseLength + (width - baseLength) / 2); + g2d.setColor(WAFER_COLOR); + g2d.fillRect(8 * width / 32, (width - baseLength) / 2, 16 * width / 32, baseLength); + g2d.setColor(METAL_COLOR); + g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(1f)); + g2d.drawLine(width / 2 - 2, (width - baseLength) / 2, width / 2 - 2, baseLength + (width - baseLength) / 2); + g2d.drawLine(width / 2 + 2, (width - baseLength) / 2, width / 2 + 2, baseLength + (width - baseLength) / 2); + g2d.drawLine(width / 2 - 5, (width - baseLength) / 2, width / 2 - 5, baseLength + (width - baseLength) / 2); + g2d.drawLine(width / 2 + 5, (width - baseLength) / 2, width / 2 + 5, baseLength + (width - baseLength) / 2); + int dx = 2 * width / 32; + int dy = 4 * width / 32; + g2d.drawLine(width / 2 - 2, baseLength + (width - baseLength) / 2, width / 2 - 2 + dx, baseLength + + (width - baseLength) / 2 + dy); + g2d.drawLine(width / 2 + 2, baseLength + (width - baseLength) / 2, width / 2 + 2 - dx, baseLength + + (width - baseLength) / 2 + dy); + + g2d.drawLine(width / 2 - 5, baseLength + (width - baseLength) / 2, width / 2 - 5 - dx, baseLength + + (width - baseLength) / 2 + dy); + g2d.drawLine(width / 2 + 5, baseLength + (width - baseLength) / 2, width / 2 + 5 + dx, baseLength + + (width - baseLength) / 2 + dy); + } + + @Override + public int getControlPointCount() { + return controlPoints.length; + } + + @Override + public VisibilityPolicy getControlPointVisibilityPolicy(int index) { + return VisibilityPolicy.ALWAYS; + } + + @Override + public boolean isControlPointSticky(int index) { + return true; + } + + @Override + public Point2D getControlPoint(int index) { + return controlPoints[index]; + } + + @Override + public void setControlPoint(Point2D point, int index) { + this.controlPoints[index].setLocation(point); + // Invalidate the body + body = null; + } + + @Override + public boolean canPointMoveFreely(int pointIndex) { + return false; + } + + @Override + public String getValue() { + return value; + } + + @Override + public void setValue(String value) { + this.value = value; + } + + @EditableProperty + public Orientation getOrientation() { + return orientation; + } + + public void setOrientation(Orientation orientation) { + this.orientation = orientation; + updateControlPoints(); + // Invalidate the body + body = null; + } + + @EditableProperty(name = "Middle Terminals") + public MiddleTerminalConfiguration getMiddleTerminalConfiguration() { + if (middleTerminalConfiguration == null) { + middleTerminalConfiguration = MiddleTerminalConfiguration.Connected; + } + return middleTerminalConfiguration; + } + + public void setMiddleTerminalConfiguration( + MiddleTerminalConfiguration middleTerminalConfiguration) { + this.middleTerminalConfiguration = middleTerminalConfiguration; + updateControlPoints(); + // Invalidate the body + body = null; + } + + // @Override +// public String getControlPointNodeName(int index) { +// // we don't want the switch to produce any nodes, it just makes connections +// return null; +// } +// + // switch stuff + + @Override + public int getPositionCount() { + return 3; + } + + @Override + public String getPositionName(int position) { + return switch (position) { + case 0 -> "Treble"; + case 1 -> "Middle"; + case 2 -> "Rhythm"; + default -> null; + }; + } + + @Override + public boolean arePointsConnected(int index1, int index2, int position) { + if (getMiddleTerminalConfiguration() == MiddleTerminalConfiguration.Connected) { + return switch (position) { + case 0 -> index1 == 1 && index2 == 2; + case 1 -> index1 > 0 && index2 > 0 && index1 < index2; + case 2 -> index1 == 2 && index2 == 3; + default -> false; + }; + } else { + return switch (position) { + case 0 -> index1 == 1 && index2 == 2; + case 1 -> (index1 == 1 && index2 == 2) || (index1 == 3 && index2 == 4); + case 2 -> index1 == 3 && index2 == 4; + default -> false; + }; + } + } + + public enum MiddleTerminalConfiguration { + Connected, Disconnected + } +} diff --git a/diylc/diylc-library/src/main/java/org/diylc/components/guitar/LeverSwitch.java b/diylc/diylc-library/src/main/java/org/diylc/components/guitar/LeverSwitch.java index cf9fb958b..d1d59df68 100644 --- a/diylc/diylc-library/src/main/java/org/diylc/components/guitar/LeverSwitch.java +++ b/diylc/diylc-library/src/main/java/org/diylc/components/guitar/LeverSwitch.java @@ -100,10 +100,7 @@ public class LeverSwitch extends AbstractAngledComponent. - -*/ -package org.diylc.components.guitar; - -import java.awt.AlphaComposite; -import java.awt.Color; -import java.awt.Composite; -import java.awt.Graphics2D; -import java.awt.Polygon; -import java.awt.Rectangle; -import java.awt.Shape; -import java.awt.geom.AffineTransform; -import java.awt.geom.Area; -import java.awt.geom.Ellipse2D; -import java.awt.geom.Point2D; -import java.awt.geom.RoundRectangle2D; -import org.diylc.appframework.miscutils.ConfigurationManager; - -import org.diylc.common.IPlugInPort; -import org.diylc.common.ObjectCache; -import org.diylc.common.Orientation; -import org.diylc.common.OrientationHV; -import org.diylc.core.ComponentState; -import org.diylc.core.IDIYComponent; -import org.diylc.core.IDrawingObserver; -import org.diylc.core.Project; -import org.diylc.core.Theme; -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; -import org.diylc.utils.Constants; - -@ComponentDescriptor(name = "P-90 Single Coil Pickup", category = "Guitar", author = "Branislav Stojkovic", - description = "Single coil P-90 guitar pickup, both \"dog ear\" and \"soap bar\"", - zOrder = IDIYComponent.COMPONENT, instanceNamePrefix = "PKP", - keywordPolicy = KeywordPolicy.SHOW_TAG, keywordTag = "Guitar Wiring Diagram", enableCache = true) -public class P90Pickup extends AbstractSingleOrHumbuckerPickup { - - private static final long serialVersionUID = 1L; - - private static Color BODY_COLOR = Color.decode("#D8C989");; -// private static Color POINT_COLOR = Color.darkGray; - - // dog ear - private static Size DOG_EAR_WIDTH = new Size(41d, SizeUnit.mm); - private static Size DOG_EAR_LENGTH = new Size(86.9d, SizeUnit.mm); - private static Size TOTAL_LENGTH = new Size(118.7d, SizeUnit.mm); - private static Size DOG_EAR_EDGE_RADIUS = new Size(4d, SizeUnit.mm); - - // soap bar - private static Size SOAP_BAR_WIDTH = new Size(35.3d, SizeUnit.mm); - private static Size SOAP_BAR_LENGTH = new Size(85.6d, SizeUnit.mm); - private static Size SOAP_BAR_EDGE_RADIUS = new Size(8d, SizeUnit.mm); - - private static Size LIP_RADIUS = new Size(10d, SizeUnit.mm); - private static Size POINT_MARGIN = new Size(3.5d, SizeUnit.mm); - private static Size LIP_HOLE_SIZE = new Size(2.5d, SizeUnit.mm); - private static Size LIP_HOLE_SPACING = new Size(97d, SizeUnit.mm); - private static Size POLE_SIZE = new Size(4d, SizeUnit.mm); - private static Size POLE_SPACING = new Size(11.68d, SizeUnit.mm); - - private Color color = BODY_COLOR; - private P90Type type = P90Type.DOG_EAR; - private Color poleColor = METAL_COLOR; - - @Override - protected OrientationHV getControlPointDirection() { - return OrientationHV.VERTICAL; - } - - @Override - public void draw(Graphics2D g2d, ComponentState componentState, boolean outlineMode, Project project, - IDrawingObserver drawingObserver) { - Shape[] body = getBody(); - - g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(1)); - - 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 : color); - g2d.fill(body[0]); - if (body[1] != null) - g2d.fill(body[1]); -// g2d.setColor(outlineMode ? Constants.TRANSPARENT_COLOR : POINT_COLOR); -// g2d.fill(body[2]); - drawingObserver.stopTracking(); - 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 - : color.darker(); - } - - g2d.setColor(finalBorderColor); - g2d.draw(body[0]); - if (body[1] != null) - g2d.draw(body[1]); - - markContactPoints(g2d, drawingObserver); - - if (!outlineMode) { - g2d.setColor(getPoleColor()); - g2d.fill(body[3]); - g2d.setColor(darkerOrLighter(getPoleColor())); - g2d.draw(body[3]); - } - -// 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 -// : LABEL_COLOR; -// } -// g2d.setColor(finalLabelColor); -// g2d.setFont(project.getFont()); -// Rectangle bounds = body[0].getBounds(); -// drawCenteredText(g2d, value, bounds.x + bounds.width / 2, bounds.y + bounds.height / 2, HorizontalAlignment.CENTER, -// VerticalAlignment.CENTER); - drawMainLabel(g2d, project, outlineMode, componentState); - - drawTerminalLabels(g2d, finalBorderColor, project); - // terminal labels -// Point[] points = getControlPoints(); -// g2d.setColor(finalBorderColor); -// -// g2d.setFont(project.getFont().deriveFont(TERMINAL_FONT_SIZE * 1f)); -// int dx = 0; -// int dy = 0; -// switch (orientation) { -// case DEFAULT: -// dx = (int) (TERMINAL_FONT_SIZE * 0.8); -// dy = 0; -// break; -// case _90: -// dx = 0; -// dy = (int) (TERMINAL_FONT_SIZE * 0.8); -// break; -// case _180: -// dx = -(int) (TERMINAL_FONT_SIZE * 0.8); -// dy = 0; -// break; -// case _270: -// dx = 0; -// dy = -(int) (TERMINAL_FONT_SIZE * 0.8); -// break; -// } -// -// if (getPolarity() == Polarity.North || getPolarity() == Polarity.South) { -// drawCenteredText(g2d, getPolarity().name().substring(0, 1), (points[1].x + points[2].x) / 2 + dx, (points[1].y + points[2].y) / 2 + dy, HorizontalAlignment.CENTER, -// VerticalAlignment.CENTER); -// } else { -// drawCenteredText(g2d, "N", (points[0].x + points[1].x) / 2 + dx, (points[0].y + points[1].y) / 2 + dy, HorizontalAlignment.CENTER, VerticalAlignment.CENTER); -// drawCenteredText(g2d, "S", (points[2].x + points[3].x) / 2 + dx, (points[2].y + points[3].y) / 2 + dy, HorizontalAlignment.CENTER, VerticalAlignment.CENTER); -// } - } - - @SuppressWarnings("incomplete-switch") - @Override - public Shape[] getBody() { - if (body == null) { - body = new Shape[4]; - - Point2D[] points = getControlPoints(); - double x = points[0].getX(); - double y = points[0].getY(); - int width = (int) getType().getWidth().convertToPixels(); - int length = (int) getType().getLength().convertToPixels(); - int edgeRadius = (int) getType().getEdgeRadius().convertToPixels(); - int pointMargin = (int) POINT_MARGIN.convertToPixels(); - int totalLength = (int) TOTAL_LENGTH.convertToPixels(); - int lipRadius = (int) LIP_RADIUS.convertToPixels(); - int lipHoleSize = getClosestOdd(LIP_HOLE_SIZE.convertToPixels()); - int lipHoleSpacing = getClosestOdd(LIP_HOLE_SPACING.convertToPixels()); - - body[0] = - new Area(new RoundRectangle2D.Double(x /*+ pointMargin*/ - length, y - pointMargin, length, width, edgeRadius, - edgeRadius)); - - if (getType() == P90Type.DOG_EAR) { - double rectWidth = (totalLength - length) / Math.sqrt(2); - RoundRectangle2D roundRect = - new RoundRectangle2D.Double(-rectWidth / 2, -rectWidth / 2, rectWidth, rectWidth, lipRadius, lipRadius); - Area leftEar = new Area(roundRect); - leftEar.transform(AffineTransform.getRotateInstance(Math.PI / 4)); - leftEar.transform(AffineTransform.getScaleInstance(1.1, 1.45)); - leftEar.transform(AffineTransform.getTranslateInstance(x /*+ pointMargin*/ - length, y - pointMargin + width / 2)); - leftEar.subtract((Area) body[0]); - Area rightEar = new Area(roundRect); - rightEar.transform(AffineTransform.getRotateInstance(Math.PI / 4)); - rightEar.transform(AffineTransform.getScaleInstance(1.1, 1.45)); - rightEar.transform(AffineTransform.getTranslateInstance(x /*+ pointMargin*/, y - pointMargin + width / 2)); - rightEar.subtract((Area) body[0]); - Area lipArea = leftEar; - lipArea.add(rightEar); - lipArea.subtract(new Area(new Ellipse2D.Double(x /*+ pointMargin*/ - length / 2 - lipHoleSpacing / 2 - lipHoleSize - / 2, y - pointMargin + width / 2 - lipHoleSize / 2, lipHoleSize, lipHoleSize))); - lipArea.subtract(new Area(new Ellipse2D.Double(x /*+ pointMargin*/ - length / 2 + lipHoleSpacing / 2 - lipHoleSize - / 2, y - pointMargin + width / 2 - lipHoleSize / 2, lipHoleSize, lipHoleSize))); - - body[1] = lipArea; - } - - int poleSize = (int) POLE_SIZE.convertToPixels(); - int poleSpacing = (int) POLE_SPACING.convertToPixels(); - int poleMargin = (length - poleSpacing * 5) / 2; - Area poleArea = new Area(); - for (int i = 0; i < 6; i++) { - Ellipse2D pole = - new Ellipse2D.Double(x /*+ pointMargin*/ - length + poleMargin + i * poleSpacing - poleSize / 2, y - - pointMargin - poleSize / 2 + width / 2, poleSize, poleSize); - poleArea.add(new Area(pole)); - } - body[3] = poleArea; - - // Rotate if needed - if (orientation != Orientation.DEFAULT) { - double theta = 0; - switch (orientation) { - case _90: - theta = Math.PI / 2; - break; - case _180: - theta = Math.PI; - break; - case _270: - theta = Math.PI * 3 / 2; - break; - } - AffineTransform rotation = AffineTransform.getRotateInstance(theta, x, y); - for (Shape shape : body) { - Area area = (Area) shape; - if (shape != null) - area.transform(rotation); - } - } - } - return body; - } - - @Override - protected int getMainLabelYOffset() { - return (int) (getType().getWidth().convertToPixels() / 2 - 20); - } - - @Override - public void drawIcon(Graphics2D g2d, int width, int height) { - g2d.rotate(Math.PI / 4, width / 2, height / 2); - - int baseWidth = 13 * width / 32; - int baseLength = 27 * width / 32; - int radius = 6 * width / 32; - - g2d.setColor(BODY_COLOR); - Polygon base = - new Polygon(new int[] {width / 2, (width + baseWidth) / 2, (width + baseWidth) / 2, width / 2, - (width - baseWidth) / 2, (width - baseWidth) / 2}, new int[] {-2, (height - baseLength) / 2, - (height + baseLength) / 2, height + 1, (height + baseLength) / 2, (height - baseLength) / 2}, 6); - Area baseArea = new Area(base); - baseArea.intersect(new Area(new Rectangle(0, -1, width, height + 1))); - g2d.fill(baseArea); - g2d.setColor(BODY_COLOR.darker()); - g2d.draw(baseArea); - - g2d.setColor(BODY_COLOR); - g2d.fillRoundRect((width - baseWidth) / 2, (height - baseLength) / 2, baseWidth, baseLength, radius, radius); - g2d.setColor(BODY_COLOR.darker()); - g2d.drawRoundRect((width - baseWidth) / 2, (height - baseLength) / 2, baseWidth, baseLength, radius, radius); - - g2d.setColor(METAL_COLOR); - int poleSize = 2; - int poleSpacing = 17 * width / 32; - for (int i = 0; i < 6; i++) { - g2d.fillOval((width - poleSize) / 2, (height - poleSpacing) / 2 + (i * poleSpacing / 5), poleSize, poleSize); - } - } - - @EditableProperty(name = "Type") - public P90Type getType() { - return type; - } - - public void setType(P90Type type) { - this.type = type; - // Invalidate the body - body = null; - } - - @EditableProperty - public Color getColor() { - return color; - } - - public void setColor(Color color) { - this.color = color; - } - - @EditableProperty(name = "Pole Color") - public Color getPoleColor() { - if (poleColor == null) - poleColor = METAL_COLOR; - return poleColor; - } - - public void setPoleColor(Color poleColor) { - this.poleColor = poleColor; - } - - public enum P90Type { - DOG_EAR("Dog Ear", DOG_EAR_LENGTH, DOG_EAR_WIDTH, DOG_EAR_EDGE_RADIUS), SOAP_BAR("Soap Bar", SOAP_BAR_LENGTH, - SOAP_BAR_WIDTH, SOAP_BAR_EDGE_RADIUS); - - private String label; - private Size length; - private Size width; - private Size edgeRadius; - - private P90Type(String label, Size length, Size width, Size edgeRadius) { - this.label = label; - this.length = length; - this.width = width; - this.edgeRadius = edgeRadius; - } - - public Size getLength() { - return length; - } - - public Size getWidth() { - return width; - } - - public Size getEdgeRadius() { - return edgeRadius; - } - - @Override - public String toString() { - return label; - } - } -} +/* + + DIY Layout Creator (DIYLC). + Copyright (c) 2009-2025 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.guitar; + +import java.awt.AlphaComposite; +import java.awt.Color; +import java.awt.Composite; +import java.awt.Graphics2D; +import java.awt.Polygon; +import java.awt.Rectangle; +import java.awt.Shape; +import java.awt.geom.AffineTransform; +import java.awt.geom.Area; +import java.awt.geom.Ellipse2D; +import java.awt.geom.Point2D; +import java.awt.geom.RoundRectangle2D; +import org.diylc.appframework.miscutils.ConfigurationManager; + +import org.diylc.common.IPlugInPort; +import org.diylc.common.ObjectCache; +import org.diylc.common.Orientation; +import org.diylc.common.OrientationHV; +import org.diylc.core.ComponentState; +import org.diylc.core.IDIYComponent; +import org.diylc.core.IDrawingObserver; +import org.diylc.core.Project; +import org.diylc.core.Theme; +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; +import org.diylc.utils.Constants; + +@ComponentDescriptor(name = "P-90 Single Coil Pickup", category = "Guitar", author = "Branislav Stojkovic", + description = "Single coil P-90 guitar pickup, both \"dog ear\" and \"soap bar\"", + zOrder = IDIYComponent.COMPONENT, instanceNamePrefix = "PKP", + keywordPolicy = KeywordPolicy.SHOW_TAG, keywordTag = "Guitar Wiring Diagram", enableCache = true) +public class P90Pickup extends AbstractSingleOrHumbuckerPickup { + + private static final long serialVersionUID = 1L; + + private static Color BODY_COLOR = Color.decode("#D8C989");; +// private static Color POINT_COLOR = Color.darkGray; + + // dog ear + private static Size DOG_EAR_WIDTH = new Size(41d, SizeUnit.mm); + private static Size DOG_EAR_LENGTH = new Size(86.9d, SizeUnit.mm); + private static Size TOTAL_LENGTH = new Size(118.7d, SizeUnit.mm); + private static Size DOG_EAR_EDGE_RADIUS = new Size(4d, SizeUnit.mm); + + // soap bar + private static Size SOAP_BAR_WIDTH = new Size(35.3d, SizeUnit.mm); + private static Size SOAP_BAR_LENGTH = new Size(85.6d, SizeUnit.mm); + private static Size SOAP_BAR_EDGE_RADIUS = new Size(8d, SizeUnit.mm); + + private static Size LIP_RADIUS = new Size(10d, SizeUnit.mm); + private static Size POINT_MARGIN = new Size(3.5d, SizeUnit.mm); + private static Size LIP_HOLE_SIZE = new Size(2.5d, SizeUnit.mm); + private static Size LIP_HOLE_SPACING = new Size(97d, SizeUnit.mm); + private static Size POLE_SIZE = new Size(4d, SizeUnit.mm); + private static Size POLE_SPACING = new Size(11.68d, SizeUnit.mm); + + private Color color = BODY_COLOR; + private P90Type type = P90Type.DOG_EAR; + private Color poleColor = METAL_COLOR; + + @Override + protected OrientationHV getControlPointDirection() { + return OrientationHV.VERTICAL; + } + + @Override + public void draw(Graphics2D g2d, ComponentState componentState, boolean outlineMode, Project project, + IDrawingObserver drawingObserver) { + Shape[] body = getBody(); + + g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(1)); + + Composite oldComposite = applyAlpha(g2d, componentState); + g2d.setColor(outlineMode ? Constants.TRANSPARENT_COLOR : color); + g2d.fill(body[0]); + if (body[1] != null) + g2d.fill(body[1]); +// g2d.setColor(outlineMode ? Constants.TRANSPARENT_COLOR : POINT_COLOR); +// g2d.fill(body[2]); + drawingObserver.stopTracking(); + 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 + : color.darker(); + } + + g2d.setColor(finalBorderColor); + g2d.draw(body[0]); + if (body[1] != null) + g2d.draw(body[1]); + + markContactPoints(g2d, drawingObserver); + + if (!outlineMode) { + g2d.setColor(getPoleColor()); + g2d.fill(body[3]); + g2d.setColor(darkerOrLighter(getPoleColor())); + g2d.draw(body[3]); + } + +// 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 +// : LABEL_COLOR; +// } +// g2d.setColor(finalLabelColor); +// g2d.setFont(project.getFont()); +// Rectangle bounds = body[0].getBounds(); +// drawCenteredText(g2d, value, bounds.x + bounds.width / 2, bounds.y + bounds.height / 2, HorizontalAlignment.CENTER, +// VerticalAlignment.CENTER); + drawMainLabel(g2d, project, outlineMode, componentState); + + drawTerminalLabels(g2d, finalBorderColor, project); + // terminal labels +// Point[] points = getControlPoints(); +// g2d.setColor(finalBorderColor); +// +// g2d.setFont(project.getFont().deriveFont(TERMINAL_FONT_SIZE * 1f)); +// int dx = 0; +// int dy = 0; +// switch (orientation) { +// case DEFAULT: +// dx = (int) (TERMINAL_FONT_SIZE * 0.8); +// dy = 0; +// break; +// case _90: +// dx = 0; +// dy = (int) (TERMINAL_FONT_SIZE * 0.8); +// break; +// case _180: +// dx = -(int) (TERMINAL_FONT_SIZE * 0.8); +// dy = 0; +// break; +// case _270: +// dx = 0; +// dy = -(int) (TERMINAL_FONT_SIZE * 0.8); +// break; +// } +// +// if (getPolarity() == Polarity.North || getPolarity() == Polarity.South) { +// drawCenteredText(g2d, getPolarity().name().substring(0, 1), (points[1].x + points[2].x) / 2 + dx, (points[1].y + points[2].y) / 2 + dy, HorizontalAlignment.CENTER, +// VerticalAlignment.CENTER); +// } else { +// drawCenteredText(g2d, "N", (points[0].x + points[1].x) / 2 + dx, (points[0].y + points[1].y) / 2 + dy, HorizontalAlignment.CENTER, VerticalAlignment.CENTER); +// drawCenteredText(g2d, "S", (points[2].x + points[3].x) / 2 + dx, (points[2].y + points[3].y) / 2 + dy, HorizontalAlignment.CENTER, VerticalAlignment.CENTER); +// } + } + + @SuppressWarnings("incomplete-switch") + @Override + public Shape[] getBody() { + if (body == null) { + body = new Shape[4]; + + Point2D[] points = getControlPoints(); + double x = points[0].getX(); + double y = points[0].getY(); + int width = (int) getType().getWidth().convertToPixels(); + int length = (int) getType().getLength().convertToPixels(); + int edgeRadius = (int) getType().getEdgeRadius().convertToPixels(); + int pointMargin = (int) POINT_MARGIN.convertToPixels(); + int totalLength = (int) TOTAL_LENGTH.convertToPixels(); + int lipRadius = (int) LIP_RADIUS.convertToPixels(); + int lipHoleSize = getClosestOdd(LIP_HOLE_SIZE.convertToPixels()); + int lipHoleSpacing = getClosestOdd(LIP_HOLE_SPACING.convertToPixels()); + + body[0] = + new Area(new RoundRectangle2D.Double(x /*+ pointMargin*/ - length, y - pointMargin, length, width, edgeRadius, + edgeRadius)); + + if (getType() == P90Type.DOG_EAR) { + double rectWidth = (totalLength - length) / Math.sqrt(2); + RoundRectangle2D roundRect = + new RoundRectangle2D.Double(-rectWidth / 2, -rectWidth / 2, rectWidth, rectWidth, lipRadius, lipRadius); + Area leftEar = new Area(roundRect); + leftEar.transform(AffineTransform.getRotateInstance(Math.PI / 4)); + leftEar.transform(AffineTransform.getScaleInstance(1.1, 1.45)); + leftEar.transform(AffineTransform.getTranslateInstance(x /*+ pointMargin*/ - length, y - pointMargin + width / 2)); + leftEar.subtract((Area) body[0]); + Area rightEar = new Area(roundRect); + rightEar.transform(AffineTransform.getRotateInstance(Math.PI / 4)); + rightEar.transform(AffineTransform.getScaleInstance(1.1, 1.45)); + rightEar.transform(AffineTransform.getTranslateInstance(x /*+ pointMargin*/, y - pointMargin + width / 2)); + rightEar.subtract((Area) body[0]); + Area lipArea = leftEar; + lipArea.add(rightEar); + lipArea.subtract(new Area(new Ellipse2D.Double(x /*+ pointMargin*/ - length / 2 - lipHoleSpacing / 2 - lipHoleSize + / 2, y - pointMargin + width / 2 - lipHoleSize / 2, lipHoleSize, lipHoleSize))); + lipArea.subtract(new Area(new Ellipse2D.Double(x /*+ pointMargin*/ - length / 2 + lipHoleSpacing / 2 - lipHoleSize + / 2, y - pointMargin + width / 2 - lipHoleSize / 2, lipHoleSize, lipHoleSize))); + + body[1] = lipArea; + } + + int poleSize = (int) POLE_SIZE.convertToPixels(); + int poleSpacing = (int) POLE_SPACING.convertToPixels(); + int poleMargin = (length - poleSpacing * 5) / 2; + Area poleArea = new Area(); + for (int i = 0; i < 6; i++) { + Ellipse2D pole = + new Ellipse2D.Double(x /*+ pointMargin*/ - length + poleMargin + i * poleSpacing - poleSize / 2, y + - pointMargin - poleSize / 2 + width / 2, poleSize, poleSize); + poleArea.add(new Area(pole)); + } + body[3] = poleArea; + + // Rotate if needed + if (orientation != Orientation.DEFAULT) { + double theta = 0; + switch (orientation) { + case _90: + theta = Math.PI / 2; + break; + case _180: + theta = Math.PI; + break; + case _270: + theta = Math.PI * 3 / 2; + break; + } + AffineTransform rotation = AffineTransform.getRotateInstance(theta, x, y); + for (Shape shape : body) { + Area area = (Area) shape; + if (shape != null) + area.transform(rotation); + } + } + } + return body; + } + + @Override + protected int getMainLabelYOffset() { + return (int) (getType().getWidth().convertToPixels() / 2 - 20); + } + + @Override + public void drawIcon(Graphics2D g2d, int width, int height) { + g2d.rotate(Math.PI / 4, width / 2, height / 2); + + int baseWidth = 13 * width / 32; + int baseLength = 27 * width / 32; + int radius = 6 * width / 32; + + g2d.setColor(BODY_COLOR); + Polygon base = + new Polygon(new int[] {width / 2, (width + baseWidth) / 2, (width + baseWidth) / 2, width / 2, + (width - baseWidth) / 2, (width - baseWidth) / 2}, new int[] {-2, (height - baseLength) / 2, + (height + baseLength) / 2, height + 1, (height + baseLength) / 2, (height - baseLength) / 2}, 6); + Area baseArea = new Area(base); + baseArea.intersect(new Area(new Rectangle(0, -1, width, height + 1))); + g2d.fill(baseArea); + g2d.setColor(BODY_COLOR.darker()); + g2d.draw(baseArea); + + g2d.setColor(BODY_COLOR); + g2d.fillRoundRect((width - baseWidth) / 2, (height - baseLength) / 2, baseWidth, baseLength, radius, radius); + g2d.setColor(BODY_COLOR.darker()); + g2d.drawRoundRect((width - baseWidth) / 2, (height - baseLength) / 2, baseWidth, baseLength, radius, radius); + + g2d.setColor(METAL_COLOR); + int poleSize = 2; + int poleSpacing = 17 * width / 32; + for (int i = 0; i < 6; i++) { + g2d.fillOval((width - poleSize) / 2, (height - poleSpacing) / 2 + (i * poleSpacing / 5), poleSize, poleSize); + } + } + + @EditableProperty(name = "Type") + public P90Type getType() { + return type; + } + + public void setType(P90Type type) { + this.type = type; + // Invalidate the body + body = null; + } + + @EditableProperty + public Color getColor() { + return color; + } + + public void setColor(Color color) { + this.color = color; + } + + @EditableProperty(name = "Pole Color") + public Color getPoleColor() { + if (poleColor == null) + poleColor = METAL_COLOR; + return poleColor; + } + + public void setPoleColor(Color poleColor) { + this.poleColor = poleColor; + } + + public enum P90Type { + DOG_EAR("Dog Ear", DOG_EAR_LENGTH, DOG_EAR_WIDTH, DOG_EAR_EDGE_RADIUS), SOAP_BAR("Soap Bar", SOAP_BAR_LENGTH, + SOAP_BAR_WIDTH, SOAP_BAR_EDGE_RADIUS); + + private String label; + private Size length; + private Size width; + private Size edgeRadius; + + private P90Type(String label, Size length, Size width, Size edgeRadius) { + this.label = label; + this.length = length; + this.width = width; + this.edgeRadius = edgeRadius; + } + + public Size getLength() { + return length; + } + + public Size getWidth() { + return width; + } + + public Size getEdgeRadius() { + return edgeRadius; + } + + @Override + public String toString() { + return label; + } + } +} diff --git a/diylc/diylc-library/src/main/java/org/diylc/components/guitar/PBassPickup.java b/diylc/diylc-library/src/main/java/org/diylc/components/guitar/PBassPickup.java index 3c4bad366..92f384559 100644 --- a/diylc/diylc-library/src/main/java/org/diylc/components/guitar/PBassPickup.java +++ b/diylc/diylc-library/src/main/java/org/diylc/components/guitar/PBassPickup.java @@ -1,273 +1,270 @@ -/* - - DIY Layout Creator (DIYLC). - Copyright (c) 2009-2025 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.guitar; - -import java.awt.AlphaComposite; -import java.awt.Color; -import java.awt.Composite; -import java.awt.Graphics2D; -import java.awt.Shape; -import java.awt.geom.AffineTransform; -import java.awt.geom.Area; -import java.awt.geom.Ellipse2D; -import java.awt.geom.Point2D; -import java.awt.geom.RoundRectangle2D; -import org.diylc.appframework.miscutils.ConfigurationManager; - -import org.diylc.common.IPlugInPort; -import org.diylc.common.ObjectCache; -import org.diylc.common.Orientation; -import org.diylc.common.OrientationHV; -import org.diylc.components.transform.GuitarPickupTransformer; -import org.diylc.core.ComponentState; -import org.diylc.core.IDIYComponent; -import org.diylc.core.IDrawingObserver; -import org.diylc.core.Project; -import org.diylc.core.Theme; -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; -import org.diylc.utils.Constants; - -@ComponentDescriptor(name = "P- Bass Pickup", category = "Guitar", author = "Branislav Stojkovic", - description = "Split-coil pickup for P-Bass and similar guitars", - zOrder = IDIYComponent.COMPONENT, instanceNamePrefix = "PKP", - keywordPolicy = KeywordPolicy.SHOW_TAG, keywordTag = "Guitar Wiring Diagram", enableCache = true, - transformer = GuitarPickupTransformer.class) -public class PBassPickup extends AbstractSingleOrHumbuckerPickup { - - private static final long serialVersionUID = 1L; - - private static Color BODY_COLOR = Color.decode("#333333");; - - private static Size WIDTH = new Size(1.1, SizeUnit.in); - private static Size LENGTH = new Size(2.2, SizeUnit.in); - private static Size EDGE_RADIUS = new Size(0.08d, SizeUnit.in); - private static Size LIP_RADIUS = new Size(0.45d, SizeUnit.in); - private static Size LIP_HOLE_SIZE = new Size(0.1d, SizeUnit.in); - private static Size LIP_HOLE_SPACING = new Size(0.1d, SizeUnit.in); - - private static Size POINT_MARGIN = new Size(1.5d, SizeUnit.mm); - private static Size POLE_SIZE = new Size(4d, SizeUnit.mm); - private static Size POLE_SPACING = new Size(0.38d, SizeUnit.in); - - private Color color = BODY_COLOR; - private Color poleColor = METAL_COLOR; - - @Override - public void draw(Graphics2D g2d, ComponentState componentState, boolean outlineMode, Project project, - IDrawingObserver drawingObserver) { - Shape[] body = getBody(); - - g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(1)); - - 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 : color); - g2d.fill(body[0]); - g2d.fill(body[1]); - drawingObserver.stopTracking(); - g2d.setComposite(oldComposite); - - markContactPoints(g2d, drawingObserver); - - 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 - : color.darker(); - } - - g2d.setColor(finalBorderColor); - g2d.draw(body[0]); - g2d.draw(body[1]); - - if (!outlineMode) { - g2d.setColor(getPoleColor()); - g2d.fill(body[3]); - g2d.setColor(darkerOrLighter(getPoleColor())); - g2d.draw(body[3]); - } - -// 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 -// : LABEL_COLOR; -// } -// g2d.setColor(finalLabelColor); -// g2d.setFont(project.getFont()); -// Rectangle bounds = body[0].getBounds(); -// drawCenteredText(g2d, value, bounds.x + bounds.width / 2, bounds.y + bounds.height / 2, HorizontalAlignment.CENTER, -// VerticalAlignment.CENTER); - drawMainLabel(g2d, project, outlineMode, componentState); - - drawTerminalLabels(g2d, finalBorderColor, project); - } - - @SuppressWarnings("incomplete-switch") - @Override - public Shape[] getBody() { - if (body == null) { - body = new Shape[4]; - - Point2D[] points = getControlPoints(); - double x = points[0].getX(); - double y = points[0].getY(); - int width = (int) WIDTH.convertToPixels(); - int length = (int) LENGTH.convertToPixels(); - int edgeRadius = (int) EDGE_RADIUS.convertToPixels(); - int pointMargin = (int) POINT_MARGIN.convertToPixels(); - int lipRadius = (int) LIP_RADIUS.convertToPixels(); - int lipHoleSize = getClosestOdd(LIP_HOLE_SIZE.convertToPixels()); - int lipHoleSpacing = getClosestOdd(LIP_HOLE_SPACING.convertToPixels()); - - body[0] = - new Area(new RoundRectangle2D.Double(x - length, y - pointMargin, length, width, edgeRadius, - edgeRadius)); - - Area lip = new Area(new Ellipse2D.Double(-lipRadius / 2, -lipRadius / 2, lipRadius, lipRadius)); - lip.subtract(new Area(new Ellipse2D.Double(-lipHoleSize / 2 + lipHoleSpacing, -lipHoleSize / 2, lipHoleSize, lipHoleSize))); - lip.transform(AffineTransform.getTranslateInstance(x, y - pointMargin + width / 2)); - Area lip2 = new Area(new Ellipse2D.Double(-lipRadius / 2, -lipRadius / 2, lipRadius, lipRadius)); - lip2 = new Area(new Ellipse2D.Double(-lipRadius / 2, -lipRadius / 2, lipRadius, lipRadius)); - lip2.subtract(new Area(new Ellipse2D.Double(-lipHoleSize / 2 - lipHoleSpacing, -lipHoleSize / 2, lipHoleSize, lipHoleSize))); - lip2.transform(AffineTransform.getTranslateInstance(x - length, y - pointMargin + width / 2)); - lip.add(lip2); - - body[1] = new Area(lip); - - ((Area)body[1]).subtract((Area)body[0]); - - int poleSize = (int) POLE_SIZE.convertToPixels(); - int poleSpacing = (int) POLE_SPACING.convertToPixels(); - int poleMargin = (length - poleSpacing * 3) / 2; - Area poleArea = new Area(); - for (int i = 0; i < 4; i++) { - Ellipse2D pole = - new Ellipse2D.Double(x - length + poleMargin + i * poleSpacing - poleSize / 2, y - - pointMargin - poleSize / 2 + width / 2, poleSize, poleSize); - poleArea.add(new Area(pole)); - } - body[3] = poleArea; - - // Rotate if needed - if (orientation != Orientation.DEFAULT) { - double theta = 0; - switch (orientation) { - case _90: - theta = Math.PI / 2; - break; - case _180: - theta = Math.PI; - break; - case _270: - theta = Math.PI * 3 / 2; - break; - } - AffineTransform rotation = AffineTransform.getRotateInstance(theta, x, y); - for (Shape shape : body) { - Area area = (Area) shape; - if (shape != null) - area.transform(rotation); - } - } - } - return body; - } - - @Override - protected int getMainLabelYOffset() { - return (int) (WIDTH.convertToPixels() / 2 - 20); - } - - @Override - public void drawIcon(Graphics2D g2d, int width, int height) { - g2d.rotate(Math.PI / 4, width / 2, height / 2); - - int bodyWidth = (int) (13f * width / 32); - int bodyLength = (int) (30f * width / 32); - - g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(1f)); - g2d.setColor(BODY_COLOR); - g2d.fillRoundRect((width - bodyWidth) / 2, (height - bodyLength) / 2, bodyWidth, bodyLength, 3, 3); - - int lipSize = (int) (5f * width / 32); - - g2d.fillRoundRect((width - lipSize) / 2, (height - bodyLength) / 2 - lipSize + 1, lipSize, bodyLength + 2 * lipSize - 2, lipSize, lipSize); - - g2d.setColor(BODY_COLOR.darker()); - g2d.drawRoundRect((width - bodyWidth) / 2, (height - bodyLength) / 2, bodyWidth, bodyLength, 3, 3); - - // g2d.setColor(Color.gray); - // g2d.drawLine(width / 2, 4 * width / 32, width / 2, 4 * width / 32); - // g2d.drawLine(width / 2, height - 4 * width / 32, width / 2, height - 4 * width / 32); - - g2d.setColor(METAL_COLOR); - int poleSize = 2; - int poleSpacing = (int) (15d * width / 32); - for (int i = 0; i < 4; i++) { - g2d.fillOval((width - poleSize) / 2, (height - poleSpacing) / 2 + (i * poleSpacing / 3), poleSize, poleSize); - } - } - - @Override - protected OrientationHV getControlPointDirection() { - return OrientationHV.VERTICAL; - } - - @EditableProperty - public Color getColor() { - return color; - } - - public void setColor(Color color) { - this.color = color; - } - - @EditableProperty(name = "Pole Color") - public Color getPoleColor() { - if (poleColor == null) - poleColor = METAL_COLOR; - return poleColor; - } - - public void setPoleColor(Color poleColor) { - this.poleColor = poleColor; - } -} +/* + + DIY Layout Creator (DIYLC). + Copyright (c) 2009-2025 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.guitar; + +import java.awt.AlphaComposite; +import java.awt.Color; +import java.awt.Composite; +import java.awt.Graphics2D; +import java.awt.Shape; +import java.awt.geom.AffineTransform; +import java.awt.geom.Area; +import java.awt.geom.Ellipse2D; +import java.awt.geom.Point2D; +import java.awt.geom.RoundRectangle2D; +import org.diylc.appframework.miscutils.ConfigurationManager; + +import org.diylc.common.IPlugInPort; +import org.diylc.common.ObjectCache; +import org.diylc.common.Orientation; +import org.diylc.common.OrientationHV; +import org.diylc.components.transform.GuitarPickupTransformer; +import org.diylc.core.ComponentState; +import org.diylc.core.IDIYComponent; +import org.diylc.core.IDrawingObserver; +import org.diylc.core.Project; +import org.diylc.core.Theme; +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; +import org.diylc.utils.Constants; + +@ComponentDescriptor(name = "P- Bass Pickup", category = "Guitar", author = "Branislav Stojkovic", + description = "Split-coil pickup for P-Bass and similar guitars", + zOrder = IDIYComponent.COMPONENT, instanceNamePrefix = "PKP", + keywordPolicy = KeywordPolicy.SHOW_TAG, keywordTag = "Guitar Wiring Diagram", enableCache = true, + transformer = GuitarPickupTransformer.class) +public class PBassPickup extends AbstractSingleOrHumbuckerPickup { + + private static final long serialVersionUID = 1L; + + private static Color BODY_COLOR = Color.decode("#333333");; + + private static Size WIDTH = new Size(1.1, SizeUnit.in); + private static Size LENGTH = new Size(2.2, SizeUnit.in); + private static Size EDGE_RADIUS = new Size(0.08d, SizeUnit.in); + private static Size LIP_RADIUS = new Size(0.45d, SizeUnit.in); + private static Size LIP_HOLE_SIZE = new Size(0.1d, SizeUnit.in); + private static Size LIP_HOLE_SPACING = new Size(0.1d, SizeUnit.in); + + private static Size POINT_MARGIN = new Size(1.5d, SizeUnit.mm); + private static Size POLE_SIZE = new Size(4d, SizeUnit.mm); + private static Size POLE_SPACING = new Size(0.38d, SizeUnit.in); + + private Color color = BODY_COLOR; + private Color poleColor = METAL_COLOR; + + @Override + public void draw(Graphics2D g2d, ComponentState componentState, boolean outlineMode, Project project, + IDrawingObserver drawingObserver) { + Shape[] body = getBody(); + + g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(1)); + + Composite oldComposite = applyAlpha(g2d, componentState); + g2d.setColor(outlineMode ? Constants.TRANSPARENT_COLOR : color); + g2d.fill(body[0]); + g2d.fill(body[1]); + drawingObserver.stopTracking(); + g2d.setComposite(oldComposite); + + markContactPoints(g2d, drawingObserver); + + 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 + : color.darker(); + } + + g2d.setColor(finalBorderColor); + g2d.draw(body[0]); + g2d.draw(body[1]); + + if (!outlineMode) { + g2d.setColor(getPoleColor()); + g2d.fill(body[3]); + g2d.setColor(darkerOrLighter(getPoleColor())); + g2d.draw(body[3]); + } + +// 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 +// : LABEL_COLOR; +// } +// g2d.setColor(finalLabelColor); +// g2d.setFont(project.getFont()); +// Rectangle bounds = body[0].getBounds(); +// drawCenteredText(g2d, value, bounds.x + bounds.width / 2, bounds.y + bounds.height / 2, HorizontalAlignment.CENTER, +// VerticalAlignment.CENTER); + drawMainLabel(g2d, project, outlineMode, componentState); + + drawTerminalLabels(g2d, finalBorderColor, project); + } + + @SuppressWarnings("incomplete-switch") + @Override + public Shape[] getBody() { + if (body == null) { + body = new Shape[4]; + + Point2D[] points = getControlPoints(); + double x = points[0].getX(); + double y = points[0].getY(); + int width = (int) WIDTH.convertToPixels(); + int length = (int) LENGTH.convertToPixels(); + int edgeRadius = (int) EDGE_RADIUS.convertToPixels(); + int pointMargin = (int) POINT_MARGIN.convertToPixels(); + int lipRadius = (int) LIP_RADIUS.convertToPixels(); + int lipHoleSize = getClosestOdd(LIP_HOLE_SIZE.convertToPixels()); + int lipHoleSpacing = getClosestOdd(LIP_HOLE_SPACING.convertToPixels()); + + body[0] = + new Area(new RoundRectangle2D.Double(x - length, y - pointMargin, length, width, edgeRadius, + edgeRadius)); + + Area lip = new Area(new Ellipse2D.Double(-lipRadius / 2, -lipRadius / 2, lipRadius, lipRadius)); + lip.subtract(new Area(new Ellipse2D.Double(-lipHoleSize / 2 + lipHoleSpacing, -lipHoleSize / 2, lipHoleSize, lipHoleSize))); + lip.transform(AffineTransform.getTranslateInstance(x, y - pointMargin + width / 2)); + Area lip2 = new Area(new Ellipse2D.Double(-lipRadius / 2, -lipRadius / 2, lipRadius, lipRadius)); + lip2 = new Area(new Ellipse2D.Double(-lipRadius / 2, -lipRadius / 2, lipRadius, lipRadius)); + lip2.subtract(new Area(new Ellipse2D.Double(-lipHoleSize / 2 - lipHoleSpacing, -lipHoleSize / 2, lipHoleSize, lipHoleSize))); + lip2.transform(AffineTransform.getTranslateInstance(x - length, y - pointMargin + width / 2)); + lip.add(lip2); + + body[1] = new Area(lip); + + ((Area)body[1]).subtract((Area)body[0]); + + int poleSize = (int) POLE_SIZE.convertToPixels(); + int poleSpacing = (int) POLE_SPACING.convertToPixels(); + int poleMargin = (length - poleSpacing * 3) / 2; + Area poleArea = new Area(); + for (int i = 0; i < 4; i++) { + Ellipse2D pole = + new Ellipse2D.Double(x - length + poleMargin + i * poleSpacing - poleSize / 2, y + - pointMargin - poleSize / 2 + width / 2, poleSize, poleSize); + poleArea.add(new Area(pole)); + } + body[3] = poleArea; + + // Rotate if needed + if (orientation != Orientation.DEFAULT) { + double theta = 0; + switch (orientation) { + case _90: + theta = Math.PI / 2; + break; + case _180: + theta = Math.PI; + break; + case _270: + theta = Math.PI * 3 / 2; + break; + } + AffineTransform rotation = AffineTransform.getRotateInstance(theta, x, y); + for (Shape shape : body) { + Area area = (Area) shape; + if (shape != null) + area.transform(rotation); + } + } + } + return body; + } + + @Override + protected int getMainLabelYOffset() { + return (int) (WIDTH.convertToPixels() / 2 - 20); + } + + @Override + public void drawIcon(Graphics2D g2d, int width, int height) { + g2d.rotate(Math.PI / 4, width / 2, height / 2); + + int bodyWidth = (int) (13f * width / 32); + int bodyLength = (int) (30f * width / 32); + + g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(1f)); + g2d.setColor(BODY_COLOR); + g2d.fillRoundRect((width - bodyWidth) / 2, (height - bodyLength) / 2, bodyWidth, bodyLength, 3, 3); + + int lipSize = (int) (5f * width / 32); + + g2d.fillRoundRect((width - lipSize) / 2, (height - bodyLength) / 2 - lipSize + 1, lipSize, bodyLength + 2 * lipSize - 2, lipSize, lipSize); + + g2d.setColor(BODY_COLOR.darker()); + g2d.drawRoundRect((width - bodyWidth) / 2, (height - bodyLength) / 2, bodyWidth, bodyLength, 3, 3); + + // g2d.setColor(Color.gray); + // g2d.drawLine(width / 2, 4 * width / 32, width / 2, 4 * width / 32); + // g2d.drawLine(width / 2, height - 4 * width / 32, width / 2, height - 4 * width / 32); + + g2d.setColor(METAL_COLOR); + int poleSize = 2; + int poleSpacing = (int) (15d * width / 32); + for (int i = 0; i < 4; i++) { + g2d.fillOval((width - poleSize) / 2, (height - poleSpacing) / 2 + (i * poleSpacing / 3), poleSize, poleSize); + } + } + + @Override + protected OrientationHV getControlPointDirection() { + return OrientationHV.VERTICAL; + } + + @EditableProperty + public Color getColor() { + return color; + } + + public void setColor(Color color) { + this.color = color; + } + + @EditableProperty(name = "Pole Color") + public Color getPoleColor() { + if (poleColor == null) + poleColor = METAL_COLOR; + return poleColor; + } + + public void setPoleColor(Color poleColor) { + this.poleColor = poleColor; + } +} diff --git a/diylc/diylc-library/src/main/java/org/diylc/components/guitar/S1Switch.java b/diylc/diylc-library/src/main/java/org/diylc/components/guitar/S1Switch.java index 519d9f1c4..275e51221 100644 --- a/diylc/diylc-library/src/main/java/org/diylc/components/guitar/S1Switch.java +++ b/diylc/diylc-library/src/main/java/org/diylc/components/guitar/S1Switch.java @@ -156,10 +156,7 @@ public class S1Switch extends AbstractTransparentComponent implements ISwi Theme theme = (Theme) ConfigurationManager.getInstance().readObject(IPlugInPort.THEME_KEY, Constants.DEFAULT_THEME); // Draw body if available. if (body != null) { - Composite oldComposite = g2d.getComposite(); - if (alpha < MAX_ALPHA) { - g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1f * alpha / MAX_ALPHA)); - } + Composite oldComposite = applyAlpha(g2d, componentState); g2d.setColor(outlineMode ? Constants.TRANSPARENT_COLOR : BODY_COLOR); g2d.fill(body); drawingObserver.stopTracking(); diff --git a/diylc/diylc-library/src/main/java/org/diylc/components/guitar/SchallerMegaSwitch.java b/diylc/diylc-library/src/main/java/org/diylc/components/guitar/SchallerMegaSwitch.java index 9c3e6fb25..b38942dce 100644 --- a/diylc/diylc-library/src/main/java/org/diylc/components/guitar/SchallerMegaSwitch.java +++ b/diylc/diylc-library/src/main/java/org/diylc/components/guitar/SchallerMegaSwitch.java @@ -103,11 +103,7 @@ public class SchallerMegaSwitch extends AbstractAngledComponent implemen g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(1)); if (componentState != ComponentState.DRAGGING) { - Composite oldComposite = g2d.getComposite(); - if (alpha < MAX_ALPHA) { - g2d.setComposite( - AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1f * alpha / MAX_ALPHA)); - } + Composite oldComposite = applyAlpha(g2d, componentState); g2d.setColor(outlineMode ? Constants.TRANSPARENT_COLOR : BASE_COLOR); g2d.fill(body[0]); drawingObserver.stopTracking(); diff --git a/diylc/diylc-library/src/main/java/org/diylc/components/guitar/SingleCoilPickup.java b/diylc/diylc-library/src/main/java/org/diylc/components/guitar/SingleCoilPickup.java index bce655d34..d29fefd2a 100644 --- a/diylc/diylc-library/src/main/java/org/diylc/components/guitar/SingleCoilPickup.java +++ b/diylc/diylc-library/src/main/java/org/diylc/components/guitar/SingleCoilPickup.java @@ -1,460 +1,457 @@ -/* - - DIY Layout Creator (DIYLC). - Copyright (c) 2009-2025 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.guitar; - -import java.awt.AlphaComposite; -import java.awt.Color; -import java.awt.Composite; -import java.awt.Graphics2D; -import java.awt.Shape; -import java.awt.geom.AffineTransform; -import java.awt.geom.Area; -import java.awt.geom.Ellipse2D; -import java.awt.geom.Point2D; -import java.awt.geom.Rectangle2D; -import java.awt.geom.RoundRectangle2D; -import org.diylc.appframework.miscutils.ConfigurationManager; - -import org.diylc.common.IPlugInPort; -import org.diylc.common.ObjectCache; -import org.diylc.common.Orientation; -import org.diylc.common.OrientationHV; -import org.diylc.components.RoundedPath; -import org.diylc.components.transform.GuitarPickupTransformer; -import org.diylc.core.ComponentState; -import org.diylc.core.IDIYComponent; -import org.diylc.core.IDrawingObserver; -import org.diylc.core.Project; -import org.diylc.core.Theme; -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; -import org.diylc.utils.Constants; - -@ComponentDescriptor(name = "Single Coil Pickup", category = "Guitar", author = "Branislav Stojkovic", - description = "Single coil guitar pickup, both Strat and Tele style", - zOrder = IDIYComponent.COMPONENT, instanceNamePrefix = "PKP", - keywordPolicy = KeywordPolicy.SHOW_TAG, keywordTag = "Guitar Wiring Diagram", enableCache = true, - transformer = GuitarPickupTransformer.class) -public class SingleCoilPickup extends AbstractSingleOrHumbuckerPickup { - - private static final long serialVersionUID = 1L; - - private static Color BODY_COLOR = Color.white; - private static Color BASE_COLOR = Color.gray; - public static Color LUG_COLOR = Color.decode("#E0C04C"); -// private static Color POINT_COLOR = Color.lightGray; - private static Size WIDTH = new Size(15.5d, SizeUnit.mm); - private static Size LENGTH = new Size(83d, SizeUnit.mm); - private static Size BASE_RADIUS = new Size(0.15d, SizeUnit.in); - private static Size LUG_DIAMETER = new Size(0.06d, SizeUnit.in); - - // strat-specific - private static Size STRAT_LIP_WIDTH = new Size(5d, SizeUnit.mm); - private static Size STRAT_LIP_LENGTH = new Size(20d, SizeUnit.mm); - private static Size STRAT_INNER_LENGTH = new Size(70d, SizeUnit.mm); - - // tele-specific - private static Size TELE_BASE_WIDTH = new Size(1.5d, SizeUnit.in); - private static Size TELE_LIP_LENGTH = new Size(1.735d, SizeUnit.in); - private static Size TELE_LENGTH = new Size(2.87d, SizeUnit.in); - private static Size TELE_HOLE_SPACING = new Size(1.135d, SizeUnit.in); - - private static Size HOLE_SIZE = new Size(2d, SizeUnit.mm); - private static Size HOLE_MARGIN = new Size(4d, SizeUnit.mm); - private static Size POLE_SIZE = new Size(4d, SizeUnit.mm); - private static Size POLE_SPACING = new Size(11.68d, SizeUnit.mm); - - private static Size RAIL_WIDTH = new Size(1.5d, SizeUnit.mm); - private static Size RAIL_LENGTH = new Size(60d, SizeUnit.mm); - private static Size COIL_SPACING = new Size(7.5d, SizeUnit.mm); - - private Color color = BODY_COLOR; - private Color poleColor = METAL_COLOR; - private Color baseColor = BASE_COLOR; - private SingleCoilType type = SingleCoilType.Stratocaster; - private PolePieceType polePieceType = PolePieceType.Rods; - private Color lugColor = LUG_COLOR; - - @Override - protected OrientationHV getControlPointDirection() { - return OrientationHV.HORIZONTAL; - } - - @Override - public void draw(Graphics2D g2d, ComponentState componentState, boolean outlineMode, Project project, - IDrawingObserver drawingObserver) { - Shape[] body = getBody(); - - g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(1)); - - Composite oldComposite = g2d.getComposite(); - if (alpha < MAX_ALPHA) { - g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1f * alpha / MAX_ALPHA)); - } - - Theme theme = - (Theme) ConfigurationManager.getInstance().readObject(IPlugInPort.THEME_KEY, Constants.DEFAULT_THEME); - - g2d.setColor(outlineMode ? Constants.TRANSPARENT_COLOR : getBaseColor()); - g2d.fill(body[4]); - g2d.setColor(outlineMode ? Constants.TRANSPARENT_COLOR : getColor()); - if (body[3] == null) - g2d.fill(body[0]); - else - g2d.fill(body[3]); - - drawingObserver.stopTracking(); - - markContactPoints(g2d, drawingObserver); - - g2d.setColor(outlineMode ? Constants.TRANSPARENT_COLOR : getLugColor()); - g2d.fill(body[1]); - g2d.setColor(outlineMode ? theme.getOutlineColor() : darkerOrLighter(LUG_COLOR)); - g2d.draw(body[1]); - - // g2d.setColor(outlineMode ? Constants.TRANSPARENT_COLOR : color); - // g2d.fill(body[3]); - g2d.setComposite(oldComposite); - - Color finalBorderColor; - if (outlineMode) { - finalBorderColor = - componentState == ComponentState.SELECTED || componentState == ComponentState.DRAGGING ? SELECTION_COLOR - : theme.getOutlineColor(); - } else { - finalBorderColor = - componentState == ComponentState.SELECTED || componentState == ComponentState.DRAGGING ? SELECTION_COLOR - : darkerOrLighter(getBaseColor()); - } - - g2d.setColor(finalBorderColor); - g2d.draw(body[4]); - - if (outlineMode) { - finalBorderColor = - componentState == ComponentState.SELECTED || componentState == ComponentState.DRAGGING ? SELECTION_COLOR - : theme.getOutlineColor(); - } else { - finalBorderColor = - componentState == ComponentState.SELECTED || componentState == ComponentState.DRAGGING ? SELECTION_COLOR - : darkerOrLighter(color); - } - - g2d.setColor(finalBorderColor); - g2d.draw(body[0]); - if (body[3] != null) - g2d.draw(body[3]); - - if (!outlineMode) { - g2d.setColor(getPoleColor()); - g2d.fill(body[2]); - g2d.setColor(darkerOrLighter(getPoleColor())); - g2d.draw(body[2]); - } - - drawMainLabel(g2d, project, outlineMode, componentState); - - drawTerminalLabels(g2d, finalBorderColor, project); - } - - @Override - protected int getMainLabelYOffset() { - if (getPolePieceType() == PolePieceType.RailHumbucker || getPolePieceType() == PolePieceType.RodHumbucker || getPolePieceType() == PolePieceType.None) - return 0; - return (int) (WIDTH.convertToPixels() / 2 - 20); - } - - @SuppressWarnings("incomplete-switch") - @Override - public Shape[] getBody() { - if (body == null) { - body = new Shape[5]; - - Point2D[] points = getControlPoints(); - double x = (points[0].getX() + points[3].getX()) / 2; - double y = (points[0].getY() + points[3].getY()) / 2;; - int width = (int) WIDTH.convertToPixels(); - int length = (int) LENGTH.convertToPixels(); - int stratInnerLength = (int) STRAT_INNER_LENGTH.convertToPixels(); - int teleLength = (int) TELE_LENGTH.convertToPixels(); - int teleBaseWidth = (int) TELE_BASE_WIDTH.convertToPixels(); - int teleLipLength = getClosestOdd(TELE_LIP_LENGTH.convertToPixels()); - int teleHoleSpacing = (int) TELE_HOLE_SPACING.convertToPixels(); - int coilLength = getType() == SingleCoilType.Stratocaster ? stratInnerLength : teleLength; - int lipWidth = (int) STRAT_LIP_WIDTH.convertToPixels(); - int lipLength = (int) STRAT_LIP_LENGTH.convertToPixels(); - int lugDiameter = getClosestOdd(LUG_DIAMETER.convertToPixels()); - int holeSize = getClosestOdd(HOLE_SIZE.convertToPixels()); - int holeMargin = getClosestOdd(HOLE_MARGIN.convertToPixels()); - int baseRadius = (int) BASE_RADIUS.convertToPixels(); - int coilOffset = 0; - - if (getType() == SingleCoilType.Stratocaster) { - coilOffset = lipWidth / 2; - - Area mainArea = - new Area(new RoundRectangle2D.Double(x - length / 2, y - lipWidth / 2 - width, length, width, width, width)); - // Cutout holes - mainArea.subtract(new Area(new Ellipse2D.Double(x - length / 2 + holeMargin - holeSize / 2, y - lipWidth / 2 - - width / 2 - holeSize / 2, holeSize, holeSize))); - mainArea.subtract(new Area(new Ellipse2D.Double(x + length / 2 - holeMargin - holeSize / 2, y - lipWidth / 2 - - width / 2 - holeSize / 2, holeSize, holeSize))); - - body[3] = mainArea; - RoundedPath basePath = new RoundedPath(baseRadius); - basePath.moveTo(x, y + lipWidth / 2); - basePath.lineTo(x + lipLength / 2, y + lipWidth / 2); - basePath.lineTo(x + length / 2, y - lipWidth); - basePath.lineTo(x - length / 2, y - lipWidth); - basePath.lineTo(x - lipLength / 2, y + lipWidth / 2); - basePath.lineTo(x, y + lipWidth / 2); - - Area base = new Area(basePath.getPath()); - base.subtract(mainArea); - - body[4] = base; - } else if (getType() == SingleCoilType.Telecaster) { - coilOffset = (teleBaseWidth - width) / 4; - - RoundedPath basePath = new RoundedPath(baseRadius); - basePath.moveTo(x, y + coilOffset); - basePath.lineTo(x + teleLipLength / 2, y + coilOffset); - basePath.lineTo(x + coilLength * 0.53, y - coilOffset - width / 2); - basePath.lineTo(x + coilLength / 2 - width * 0.45, y - coilOffset - width); - basePath.lineTo(x, y - 3 * coilOffset - width); - basePath.lineTo(x - coilLength / 2 + width * 0.45, y - coilOffset - width); - basePath.lineTo(x - coilLength * 0.53, y - coilOffset - width / 2); - basePath.lineTo(x - teleLipLength / 2, y + coilOffset); - basePath.lineTo(x, y + coilOffset); - - Area base = new Area(basePath.getPath()); - base.intersect(new Area(new Rectangle2D.Double(x - coilLength * 0.48, y - teleBaseWidth, coilLength * 0.96, - teleBaseWidth * 2))); - - // Cutout holes - base.subtract(new Area(new Ellipse2D.Double(x - teleLipLength / 2 - holeSize / 2, y, holeSize, holeSize))); - base.subtract(new Area(new Ellipse2D.Double(x + teleLipLength / 2 - holeSize / 2, y, holeSize, holeSize))); - base.subtract(new Area(new Ellipse2D.Double(x - holeSize / 2, y - teleHoleSpacing, holeSize, holeSize))); - - body[4] = base; - } - - Area poleArea = new Area(); - if (getPolePieceType() == PolePieceType.Rods) { - int poleSize = (int) POLE_SIZE.convertToPixels(); - int poleSpacing = (int) POLE_SPACING.convertToPixels(); - int poleMargin = (length - poleSpacing * 5) / 2; - for (int i = 0; i < 6; i++) { - Ellipse2D pole = - new Ellipse2D.Double(x - length / 2 + poleMargin + i * poleSpacing - poleSize / 2, y - coilOffset - width - / 2 - poleSize / 2, poleSize, poleSize); - poleArea.add(new Area(pole)); - } - } else if (getPolePieceType() == PolePieceType.RodHumbucker) { - int poleSize = (int) POLE_SIZE.convertToPixels() / 2; - int poleSpacing = (int) POLE_SPACING.convertToPixels(); - int poleMargin = (length - poleSpacing * 5) / 2; - int coilSpacing = (int) COIL_SPACING.convertToPixels(); - for (int i = 0; i < 6; i++) { - poleArea.add(new Area(new Ellipse2D.Double(x - length / 2 + poleMargin + i * poleSpacing - poleSize / 2, y - - coilOffset - width / 2 - poleSize / 2 - coilSpacing / 2, poleSize, poleSize))); - poleArea.add(new Area(new Ellipse2D.Double(x - length / 2 + poleMargin + i * poleSpacing - poleSize / 2, y - - coilOffset - width / 2 - poleSize / 2 + coilSpacing / 2, poleSize, poleSize))); - } - } else if (getPolePieceType() == PolePieceType.RailHumbucker) { - int railWidth = (int) RAIL_WIDTH.convertToPixels(); - int railSpacing = (int) COIL_SPACING.convertToPixels(); - int railLength = (int) RAIL_LENGTH.convertToPixels(); - poleArea.add(new Area(new Rectangle2D.Double(x - railLength / 2, y - coilOffset - width / 2 - railSpacing / 2 - - railWidth / 2, railLength, railWidth))); - poleArea.add(new Area(new Rectangle2D.Double(x - railLength / 2, y - coilOffset - width / 2 + railSpacing / 2 - - railWidth / 2, railLength, railWidth))); - } else if (getPolePieceType() == PolePieceType.Rail) { - int railWidth = 2 * (int) RAIL_WIDTH.convertToPixels(); - int railLength = (int) RAIL_LENGTH.convertToPixels(); - poleArea.add(new Area(new RoundRectangle2D.Double(x - railLength / 2, y - coilOffset - width / 2 - railWidth - / 2, railLength, railWidth, railWidth / 2, railWidth / 2))); - } - - body[0] = - new Area(new RoundRectangle2D.Double(x - coilLength / 2, y - coilOffset - width, coilLength, width, width, - width)); - - body[2] = poleArea; - - if (body[3] == null) { - ((Area)body[4]).subtract((Area) body[0]); - } - - // Rotate if needed - if (orientation != Orientation.DEFAULT) { - double theta = 0; - switch (orientation) { - case _90: - theta = Math.PI / 2; - break; - case _180: - theta = Math.PI; - break; - case _270: - theta = Math.PI * 3 / 2; - break; - } - AffineTransform rotation = AffineTransform.getRotateInstance(theta, x, y); - for (Shape shape : body) { - Area area = (Area) shape; - if (area != null) - area.transform(rotation); - } - } - - body[1] = new Area(); - double lugHole = getClosestOdd(lugDiameter * 0.4); - for (int i = getPolarity() == Polarity.Humbucking ? 0 : 1; i < (getPolarity() == Polarity.Humbucking ? 4 : 3); i++) { - Point2D p = points[i]; - ((Area)body[1]).add(new Area(new Ellipse2D.Double(p.getX() - lugDiameter / 2, p.getY() - lugDiameter / 2, lugDiameter, lugDiameter))); - ((Area)body[1]).subtract(new Area(new Ellipse2D.Double(p.getX() - lugHole / 2, p.getY() - lugHole / 2, lugHole, lugHole))); - } - } - return body; - } - - @Override - public void drawIcon(Graphics2D g2d, int width, int height) { - g2d.rotate(Math.PI / 4, width / 2, height / 2); - - int bodyWidth = 8 * width / 32; - int bodyLength = 30 * width / 32; - - g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(1f)); - g2d.setColor(BASE_COLOR); - g2d.fillPolygon(new int[] {width * 9 / 16, width * 9 / 16, width * 11 / 16, width * 11 / 16}, new int[] { - (height - bodyLength) / 2, (height + bodyLength) / 2, height * 5 / 8, height * 3 / 8}, 4); - g2d.setColor(BODY_COLOR); - g2d.fillRoundRect((width - bodyWidth) / 2, (height - bodyLength) / 2, bodyWidth, bodyLength, bodyWidth, bodyWidth); - - g2d.setColor(Color.gray); - g2d.drawRoundRect((width - bodyWidth) / 2, (height - bodyLength) / 2, bodyWidth, bodyLength, bodyWidth, bodyWidth); - - // g2d.setColor(Color.gray); - // g2d.drawLine(width / 2, 4 * width / 32, width / 2, 4 * width / 32); - // g2d.drawLine(width / 2, height - 4 * width / 32, width / 2, height - 4 * width / 32); - - g2d.setColor(METAL_COLOR); - int poleSize = 2; - int poleSpacing = 17 * width / 32; - for (int i = 0; i < 6; i++) { - g2d.fillOval((width - poleSize) / 2, (height - poleSpacing) / 2 + (i * poleSpacing / 5), poleSize, poleSize); - } - } - - @EditableProperty - public SingleCoilType getType() { - if (type == null) - type = SingleCoilType.Stratocaster; - return type; - } - - public void setType(SingleCoilType type) { - this.type = type; - // Invalidate the body - body = null; - } - - @EditableProperty(name = "Pole Pieces") - public PolePieceType getPolePieceType() { - if (polePieceType == null) - polePieceType = PolePieceType.Rods; - return polePieceType; - } - - public void setPolePieceType(PolePieceType polePieceType) { - this.polePieceType = polePieceType; - // Invalidate the body - body = null; - } - - @EditableProperty - public Color getColor() { - return color; - } - - public void setColor(Color color) { - this.color = color; - } - - @EditableProperty(name = "Base") - public Color getBaseColor() { - if (baseColor == null) - baseColor = BASE_COLOR; - return baseColor; - } - - public void setBaseColor(Color baseColor) { - this.baseColor = baseColor; - } - - @EditableProperty(name = "Pole Color") - public Color getPoleColor() { - if (poleColor == null) - poleColor = METAL_COLOR; - return poleColor; - } - - public void setPoleColor(Color poleColor) { - this.poleColor = poleColor; - } - - @EditableProperty(name = "Lugs") - public Color getLugColor() { - if (lugColor == null) { - lugColor = LUG_COLOR; - } - return lugColor; - } - - public void setLugColor(Color lugColor) { - this.lugColor = lugColor; - } - - public enum SingleCoilType { - Stratocaster, Telecaster; - } - - public enum PolePieceType { - Rods("Single Rods"), Rail("Single Rail"), RodHumbucker("Double Rods"), RailHumbucker("Double Rails"), None("None"); - - private String label; - - private PolePieceType(String label) { - this.label = label; - } - - @Override - public String toString() { - return label; - } - } -} +/* + + DIY Layout Creator (DIYLC). + Copyright (c) 2009-2025 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.guitar; + +import java.awt.AlphaComposite; +import java.awt.Color; +import java.awt.Composite; +import java.awt.Graphics2D; +import java.awt.Shape; +import java.awt.geom.AffineTransform; +import java.awt.geom.Area; +import java.awt.geom.Ellipse2D; +import java.awt.geom.Point2D; +import java.awt.geom.Rectangle2D; +import java.awt.geom.RoundRectangle2D; +import org.diylc.appframework.miscutils.ConfigurationManager; + +import org.diylc.common.IPlugInPort; +import org.diylc.common.ObjectCache; +import org.diylc.common.Orientation; +import org.diylc.common.OrientationHV; +import org.diylc.components.RoundedPath; +import org.diylc.components.transform.GuitarPickupTransformer; +import org.diylc.core.ComponentState; +import org.diylc.core.IDIYComponent; +import org.diylc.core.IDrawingObserver; +import org.diylc.core.Project; +import org.diylc.core.Theme; +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; +import org.diylc.utils.Constants; + +@ComponentDescriptor(name = "Single Coil Pickup", category = "Guitar", author = "Branislav Stojkovic", + description = "Single coil guitar pickup, both Strat and Tele style", + zOrder = IDIYComponent.COMPONENT, instanceNamePrefix = "PKP", + keywordPolicy = KeywordPolicy.SHOW_TAG, keywordTag = "Guitar Wiring Diagram", enableCache = true, + transformer = GuitarPickupTransformer.class) +public class SingleCoilPickup extends AbstractSingleOrHumbuckerPickup { + + private static final long serialVersionUID = 1L; + + private static Color BODY_COLOR = Color.white; + private static Color BASE_COLOR = Color.gray; + public static Color LUG_COLOR = Color.decode("#E0C04C"); +// private static Color POINT_COLOR = Color.lightGray; + private static Size WIDTH = new Size(15.5d, SizeUnit.mm); + private static Size LENGTH = new Size(83d, SizeUnit.mm); + private static Size BASE_RADIUS = new Size(0.15d, SizeUnit.in); + private static Size LUG_DIAMETER = new Size(0.06d, SizeUnit.in); + + // strat-specific + private static Size STRAT_LIP_WIDTH = new Size(5d, SizeUnit.mm); + private static Size STRAT_LIP_LENGTH = new Size(20d, SizeUnit.mm); + private static Size STRAT_INNER_LENGTH = new Size(70d, SizeUnit.mm); + + // tele-specific + private static Size TELE_BASE_WIDTH = new Size(1.5d, SizeUnit.in); + private static Size TELE_LIP_LENGTH = new Size(1.735d, SizeUnit.in); + private static Size TELE_LENGTH = new Size(2.87d, SizeUnit.in); + private static Size TELE_HOLE_SPACING = new Size(1.135d, SizeUnit.in); + + private static Size HOLE_SIZE = new Size(2d, SizeUnit.mm); + private static Size HOLE_MARGIN = new Size(4d, SizeUnit.mm); + private static Size POLE_SIZE = new Size(4d, SizeUnit.mm); + private static Size POLE_SPACING = new Size(11.68d, SizeUnit.mm); + + private static Size RAIL_WIDTH = new Size(1.5d, SizeUnit.mm); + private static Size RAIL_LENGTH = new Size(60d, SizeUnit.mm); + private static Size COIL_SPACING = new Size(7.5d, SizeUnit.mm); + + private Color color = BODY_COLOR; + private Color poleColor = METAL_COLOR; + private Color baseColor = BASE_COLOR; + private SingleCoilType type = SingleCoilType.Stratocaster; + private PolePieceType polePieceType = PolePieceType.Rods; + private Color lugColor = LUG_COLOR; + + @Override + protected OrientationHV getControlPointDirection() { + return OrientationHV.HORIZONTAL; + } + + @Override + public void draw(Graphics2D g2d, ComponentState componentState, boolean outlineMode, Project project, + IDrawingObserver drawingObserver) { + Shape[] body = getBody(); + + g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(1)); + + Composite oldComposite = applyAlpha(g2d, componentState); + + Theme theme = + (Theme) ConfigurationManager.getInstance().readObject(IPlugInPort.THEME_KEY, Constants.DEFAULT_THEME); + + g2d.setColor(outlineMode ? Constants.TRANSPARENT_COLOR : getBaseColor()); + g2d.fill(body[4]); + g2d.setColor(outlineMode ? Constants.TRANSPARENT_COLOR : getColor()); + if (body[3] == null) + g2d.fill(body[0]); + else + g2d.fill(body[3]); + + drawingObserver.stopTracking(); + + markContactPoints(g2d, drawingObserver); + + g2d.setColor(outlineMode ? Constants.TRANSPARENT_COLOR : getLugColor()); + g2d.fill(body[1]); + g2d.setColor(outlineMode ? theme.getOutlineColor() : darkerOrLighter(LUG_COLOR)); + g2d.draw(body[1]); + + // g2d.setColor(outlineMode ? Constants.TRANSPARENT_COLOR : color); + // g2d.fill(body[3]); + g2d.setComposite(oldComposite); + + Color finalBorderColor; + if (outlineMode) { + finalBorderColor = + componentState == ComponentState.SELECTED || componentState == ComponentState.DRAGGING ? SELECTION_COLOR + : theme.getOutlineColor(); + } else { + finalBorderColor = + componentState == ComponentState.SELECTED || componentState == ComponentState.DRAGGING ? SELECTION_COLOR + : darkerOrLighter(getBaseColor()); + } + + g2d.setColor(finalBorderColor); + g2d.draw(body[4]); + + if (outlineMode) { + finalBorderColor = + componentState == ComponentState.SELECTED || componentState == ComponentState.DRAGGING ? SELECTION_COLOR + : theme.getOutlineColor(); + } else { + finalBorderColor = + componentState == ComponentState.SELECTED || componentState == ComponentState.DRAGGING ? SELECTION_COLOR + : darkerOrLighter(color); + } + + g2d.setColor(finalBorderColor); + g2d.draw(body[0]); + if (body[3] != null) + g2d.draw(body[3]); + + if (!outlineMode) { + g2d.setColor(getPoleColor()); + g2d.fill(body[2]); + g2d.setColor(darkerOrLighter(getPoleColor())); + g2d.draw(body[2]); + } + + drawMainLabel(g2d, project, outlineMode, componentState); + + drawTerminalLabels(g2d, finalBorderColor, project); + } + + @Override + protected int getMainLabelYOffset() { + if (getPolePieceType() == PolePieceType.RailHumbucker || getPolePieceType() == PolePieceType.RodHumbucker || getPolePieceType() == PolePieceType.None) + return 0; + return (int) (WIDTH.convertToPixels() / 2 - 20); + } + + @SuppressWarnings("incomplete-switch") + @Override + public Shape[] getBody() { + if (body == null) { + body = new Shape[5]; + + Point2D[] points = getControlPoints(); + double x = (points[0].getX() + points[3].getX()) / 2; + double y = (points[0].getY() + points[3].getY()) / 2;; + int width = (int) WIDTH.convertToPixels(); + int length = (int) LENGTH.convertToPixels(); + int stratInnerLength = (int) STRAT_INNER_LENGTH.convertToPixels(); + int teleLength = (int) TELE_LENGTH.convertToPixels(); + int teleBaseWidth = (int) TELE_BASE_WIDTH.convertToPixels(); + int teleLipLength = getClosestOdd(TELE_LIP_LENGTH.convertToPixels()); + int teleHoleSpacing = (int) TELE_HOLE_SPACING.convertToPixels(); + int coilLength = getType() == SingleCoilType.Stratocaster ? stratInnerLength : teleLength; + int lipWidth = (int) STRAT_LIP_WIDTH.convertToPixels(); + int lipLength = (int) STRAT_LIP_LENGTH.convertToPixels(); + int lugDiameter = getClosestOdd(LUG_DIAMETER.convertToPixels()); + int holeSize = getClosestOdd(HOLE_SIZE.convertToPixels()); + int holeMargin = getClosestOdd(HOLE_MARGIN.convertToPixels()); + int baseRadius = (int) BASE_RADIUS.convertToPixels(); + int coilOffset = 0; + + if (getType() == SingleCoilType.Stratocaster) { + coilOffset = lipWidth / 2; + + Area mainArea = + new Area(new RoundRectangle2D.Double(x - length / 2, y - lipWidth / 2 - width, length, width, width, width)); + // Cutout holes + mainArea.subtract(new Area(new Ellipse2D.Double(x - length / 2 + holeMargin - holeSize / 2, y - lipWidth / 2 + - width / 2 - holeSize / 2, holeSize, holeSize))); + mainArea.subtract(new Area(new Ellipse2D.Double(x + length / 2 - holeMargin - holeSize / 2, y - lipWidth / 2 + - width / 2 - holeSize / 2, holeSize, holeSize))); + + body[3] = mainArea; + RoundedPath basePath = new RoundedPath(baseRadius); + basePath.moveTo(x, y + lipWidth / 2); + basePath.lineTo(x + lipLength / 2, y + lipWidth / 2); + basePath.lineTo(x + length / 2, y - lipWidth); + basePath.lineTo(x - length / 2, y - lipWidth); + basePath.lineTo(x - lipLength / 2, y + lipWidth / 2); + basePath.lineTo(x, y + lipWidth / 2); + + Area base = new Area(basePath.getPath()); + base.subtract(mainArea); + + body[4] = base; + } else if (getType() == SingleCoilType.Telecaster) { + coilOffset = (teleBaseWidth - width) / 4; + + RoundedPath basePath = new RoundedPath(baseRadius); + basePath.moveTo(x, y + coilOffset); + basePath.lineTo(x + teleLipLength / 2, y + coilOffset); + basePath.lineTo(x + coilLength * 0.53, y - coilOffset - width / 2); + basePath.lineTo(x + coilLength / 2 - width * 0.45, y - coilOffset - width); + basePath.lineTo(x, y - 3 * coilOffset - width); + basePath.lineTo(x - coilLength / 2 + width * 0.45, y - coilOffset - width); + basePath.lineTo(x - coilLength * 0.53, y - coilOffset - width / 2); + basePath.lineTo(x - teleLipLength / 2, y + coilOffset); + basePath.lineTo(x, y + coilOffset); + + Area base = new Area(basePath.getPath()); + base.intersect(new Area(new Rectangle2D.Double(x - coilLength * 0.48, y - teleBaseWidth, coilLength * 0.96, + teleBaseWidth * 2))); + + // Cutout holes + base.subtract(new Area(new Ellipse2D.Double(x - teleLipLength / 2 - holeSize / 2, y, holeSize, holeSize))); + base.subtract(new Area(new Ellipse2D.Double(x + teleLipLength / 2 - holeSize / 2, y, holeSize, holeSize))); + base.subtract(new Area(new Ellipse2D.Double(x - holeSize / 2, y - teleHoleSpacing, holeSize, holeSize))); + + body[4] = base; + } + + Area poleArea = new Area(); + if (getPolePieceType() == PolePieceType.Rods) { + int poleSize = (int) POLE_SIZE.convertToPixels(); + int poleSpacing = (int) POLE_SPACING.convertToPixels(); + int poleMargin = (length - poleSpacing * 5) / 2; + for (int i = 0; i < 6; i++) { + Ellipse2D pole = + new Ellipse2D.Double(x - length / 2 + poleMargin + i * poleSpacing - poleSize / 2, y - coilOffset - width + / 2 - poleSize / 2, poleSize, poleSize); + poleArea.add(new Area(pole)); + } + } else if (getPolePieceType() == PolePieceType.RodHumbucker) { + int poleSize = (int) POLE_SIZE.convertToPixels() / 2; + int poleSpacing = (int) POLE_SPACING.convertToPixels(); + int poleMargin = (length - poleSpacing * 5) / 2; + int coilSpacing = (int) COIL_SPACING.convertToPixels(); + for (int i = 0; i < 6; i++) { + poleArea.add(new Area(new Ellipse2D.Double(x - length / 2 + poleMargin + i * poleSpacing - poleSize / 2, y + - coilOffset - width / 2 - poleSize / 2 - coilSpacing / 2, poleSize, poleSize))); + poleArea.add(new Area(new Ellipse2D.Double(x - length / 2 + poleMargin + i * poleSpacing - poleSize / 2, y + - coilOffset - width / 2 - poleSize / 2 + coilSpacing / 2, poleSize, poleSize))); + } + } else if (getPolePieceType() == PolePieceType.RailHumbucker) { + int railWidth = (int) RAIL_WIDTH.convertToPixels(); + int railSpacing = (int) COIL_SPACING.convertToPixels(); + int railLength = (int) RAIL_LENGTH.convertToPixels(); + poleArea.add(new Area(new Rectangle2D.Double(x - railLength / 2, y - coilOffset - width / 2 - railSpacing / 2 + - railWidth / 2, railLength, railWidth))); + poleArea.add(new Area(new Rectangle2D.Double(x - railLength / 2, y - coilOffset - width / 2 + railSpacing / 2 + - railWidth / 2, railLength, railWidth))); + } else if (getPolePieceType() == PolePieceType.Rail) { + int railWidth = 2 * (int) RAIL_WIDTH.convertToPixels(); + int railLength = (int) RAIL_LENGTH.convertToPixels(); + poleArea.add(new Area(new RoundRectangle2D.Double(x - railLength / 2, y - coilOffset - width / 2 - railWidth + / 2, railLength, railWidth, railWidth / 2, railWidth / 2))); + } + + body[0] = + new Area(new RoundRectangle2D.Double(x - coilLength / 2, y - coilOffset - width, coilLength, width, width, + width)); + + body[2] = poleArea; + + if (body[3] == null) { + ((Area)body[4]).subtract((Area) body[0]); + } + + // Rotate if needed + if (orientation != Orientation.DEFAULT) { + double theta = 0; + switch (orientation) { + case _90: + theta = Math.PI / 2; + break; + case _180: + theta = Math.PI; + break; + case _270: + theta = Math.PI * 3 / 2; + break; + } + AffineTransform rotation = AffineTransform.getRotateInstance(theta, x, y); + for (Shape shape : body) { + Area area = (Area) shape; + if (area != null) + area.transform(rotation); + } + } + + body[1] = new Area(); + double lugHole = getClosestOdd(lugDiameter * 0.4); + for (int i = getPolarity() == Polarity.Humbucking ? 0 : 1; i < (getPolarity() == Polarity.Humbucking ? 4 : 3); i++) { + Point2D p = points[i]; + ((Area)body[1]).add(new Area(new Ellipse2D.Double(p.getX() - lugDiameter / 2, p.getY() - lugDiameter / 2, lugDiameter, lugDiameter))); + ((Area)body[1]).subtract(new Area(new Ellipse2D.Double(p.getX() - lugHole / 2, p.getY() - lugHole / 2, lugHole, lugHole))); + } + } + return body; + } + + @Override + public void drawIcon(Graphics2D g2d, int width, int height) { + g2d.rotate(Math.PI / 4, width / 2, height / 2); + + int bodyWidth = 8 * width / 32; + int bodyLength = 30 * width / 32; + + g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(1f)); + g2d.setColor(BASE_COLOR); + g2d.fillPolygon(new int[] {width * 9 / 16, width * 9 / 16, width * 11 / 16, width * 11 / 16}, new int[] { + (height - bodyLength) / 2, (height + bodyLength) / 2, height * 5 / 8, height * 3 / 8}, 4); + g2d.setColor(BODY_COLOR); + g2d.fillRoundRect((width - bodyWidth) / 2, (height - bodyLength) / 2, bodyWidth, bodyLength, bodyWidth, bodyWidth); + + g2d.setColor(Color.gray); + g2d.drawRoundRect((width - bodyWidth) / 2, (height - bodyLength) / 2, bodyWidth, bodyLength, bodyWidth, bodyWidth); + + // g2d.setColor(Color.gray); + // g2d.drawLine(width / 2, 4 * width / 32, width / 2, 4 * width / 32); + // g2d.drawLine(width / 2, height - 4 * width / 32, width / 2, height - 4 * width / 32); + + g2d.setColor(METAL_COLOR); + int poleSize = 2; + int poleSpacing = 17 * width / 32; + for (int i = 0; i < 6; i++) { + g2d.fillOval((width - poleSize) / 2, (height - poleSpacing) / 2 + (i * poleSpacing / 5), poleSize, poleSize); + } + } + + @EditableProperty + public SingleCoilType getType() { + if (type == null) + type = SingleCoilType.Stratocaster; + return type; + } + + public void setType(SingleCoilType type) { + this.type = type; + // Invalidate the body + body = null; + } + + @EditableProperty(name = "Pole Pieces") + public PolePieceType getPolePieceType() { + if (polePieceType == null) + polePieceType = PolePieceType.Rods; + return polePieceType; + } + + public void setPolePieceType(PolePieceType polePieceType) { + this.polePieceType = polePieceType; + // Invalidate the body + body = null; + } + + @EditableProperty + public Color getColor() { + return color; + } + + public void setColor(Color color) { + this.color = color; + } + + @EditableProperty(name = "Base") + public Color getBaseColor() { + if (baseColor == null) + baseColor = BASE_COLOR; + return baseColor; + } + + public void setBaseColor(Color baseColor) { + this.baseColor = baseColor; + } + + @EditableProperty(name = "Pole Color") + public Color getPoleColor() { + if (poleColor == null) + poleColor = METAL_COLOR; + return poleColor; + } + + public void setPoleColor(Color poleColor) { + this.poleColor = poleColor; + } + + @EditableProperty(name = "Lugs") + public Color getLugColor() { + if (lugColor == null) { + lugColor = LUG_COLOR; + } + return lugColor; + } + + public void setLugColor(Color lugColor) { + this.lugColor = lugColor; + } + + public enum SingleCoilType { + Stratocaster, Telecaster; + } + + public enum PolePieceType { + Rods("Single Rods"), Rail("Single Rail"), RodHumbucker("Double Rods"), RailHumbucker("Double Rails"), None("None"); + + private String label; + + private PolePieceType(String label) { + this.label = label; + } + + @Override + public String toString() { + return label; + } + } +} diff --git a/diylc/diylc-library/src/main/java/org/diylc/components/guitar/StingrayBassPickup.java b/diylc/diylc-library/src/main/java/org/diylc/components/guitar/StingrayBassPickup.java index 8b4442fe9..ed11263ef 100644 --- a/diylc/diylc-library/src/main/java/org/diylc/components/guitar/StingrayBassPickup.java +++ b/diylc/diylc-library/src/main/java/org/diylc/components/guitar/StingrayBassPickup.java @@ -82,11 +82,7 @@ import java.awt.geom.*; Shape[] body = getBody(); g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(1)); - Composite oldComposite = g2d.getComposite(); - - if (alpha < MAX_ALPHA) { - g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1f * alpha / MAX_ALPHA)); - } + Composite oldComposite = applyAlpha(g2d, componentState); g2d.setColor(outlineMode ? Constants.TRANSPARENT_COLOR : color); g2d.fill(body[0]); diff --git a/diylc/diylc-library/src/main/java/org/diylc/components/misc/Image.java b/diylc/diylc-library/src/main/java/org/diylc/components/misc/Image.java index 540432439..318f307c9 100644 --- a/diylc/diylc-library/src/main/java/org/diylc/components/misc/Image.java +++ b/diylc/diylc-library/src/main/java/org/diylc/components/misc/Image.java @@ -128,10 +128,7 @@ public class Image extends AbstractTransparentComponent { .getIconHeight() * scaleY))) { return; } - Composite oldComposite = g2d.getComposite(); - if (alpha < MAX_ALPHA) { - g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1f * alpha / MAX_ALPHA)); - } + Composite oldComposite = applyAlpha(g2d, componentState); double x; double y; @@ -242,7 +239,7 @@ public class Image extends AbstractTransparentComponent { } } - @PercentEditor(_100PercentValue = 25) + @PercentEditor(minValue = 1, maxValue = 1000) @EditableProperty(defaultable = false) public byte getScale() { if (scale != null) { diff --git a/diylc/diylc-library/src/main/java/org/diylc/components/misc/Loadline.java b/diylc/diylc-library/src/main/java/org/diylc/components/misc/Loadline.java index 60abcbd9f..0eb3196cc 100644 --- a/diylc/diylc-library/src/main/java/org/diylc/components/misc/Loadline.java +++ b/diylc/diylc-library/src/main/java/org/diylc/components/misc/Loadline.java @@ -72,11 +72,7 @@ public class Loadline extends AbstractBoard { g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(1)); if (componentState != ComponentState.DRAGGING) { - Composite oldComposite = g2d.getComposite(); - if (alpha < MAX_ALPHA) { - g2d.setComposite( - AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1f * alpha / MAX_ALPHA)); - } + Composite oldComposite = applyAlpha(g2d, componentState); g2d.setColor(boardColor); g2d.fillRect((int)firstPoint.getX(), (int)firstPoint.getY(), (int)(finalSecondPoint.getX() - firstPoint.getX()), diff --git a/diylc/diylc-library/src/main/java/org/diylc/components/misc/SVGImage.java b/diylc/diylc-library/src/main/java/org/diylc/components/misc/SVGImage.java index 394587a66..f8d9a8ed6 100644 --- a/diylc/diylc-library/src/main/java/org/diylc/components/misc/SVGImage.java +++ b/diylc/diylc-library/src/main/java/org/diylc/components/misc/SVGImage.java @@ -107,10 +107,7 @@ public class SVGImage extends AbstractTransparentComponent { svgDiagram.getWidth() * scaleX, svgDiagram.getHeight() * scaleY))) { return; } - Composite oldComposite = g2d.getComposite(); - if (alpha < MAX_ALPHA) { - g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1f * alpha / MAX_ALPHA)); - } + Composite oldComposite = applyAlpha(g2d, componentState); double x; double y; @@ -229,7 +226,7 @@ public class SVGImage extends AbstractTransparentComponent { this.svgDiagram = null; } - @PercentEditor(_100PercentValue = 25) + @PercentEditor(minValue = 0, maxValue = 1000) @EditableProperty(defaultable = false) public byte getScale() { if (scale != null) { diff --git a/diylc/diylc-library/src/main/java/org/diylc/components/passive/AudioTransformer.java b/diylc/diylc-library/src/main/java/org/diylc/components/passive/AudioTransformer.java index c1229b839..ac51c89cb 100644 --- a/diylc/diylc-library/src/main/java/org/diylc/components/passive/AudioTransformer.java +++ b/diylc/diylc-library/src/main/java/org/diylc/components/passive/AudioTransformer.java @@ -1,531 +1,528 @@ -/* - - DIY Layout Creator (DIYLC). - Copyright (c) 2009-2025 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.passive; - -import java.awt.AlphaComposite; -import java.awt.Color; -import java.awt.Composite; -import java.awt.FontMetrics; -import java.awt.Graphics2D; -import java.awt.Rectangle; -import java.awt.geom.AffineTransform; -import java.awt.geom.Area; -import java.awt.geom.Point2D; -import java.awt.geom.Rectangle2D; -import java.awt.geom.RoundRectangle2D; -import org.diylc.appframework.miscutils.ConfigurationManager; - -import org.diylc.awt.StringUtils; -import org.diylc.common.Display; -import org.diylc.common.HorizontalAlignment; -import org.diylc.common.IPlugInPort; -import org.diylc.common.ObjectCache; -import org.diylc.common.Orientation; -import org.diylc.common.VerticalAlignment; -import org.diylc.components.AbstractMultiPartComponent; -import org.diylc.core.ComponentState; -import org.diylc.core.IDIYComponent; -import org.diylc.core.IDrawingObserver; -import org.diylc.core.Project; -import org.diylc.core.Theme; -import org.diylc.core.VisibilityPolicy; -import org.diylc.core.annotations.ComponentDescriptor; -import org.diylc.core.annotations.EditableProperty; -import org.diylc.core.annotations.KeywordPolicy; -import org.diylc.core.annotations.PositiveNonZeroMeasureValidator; -import org.diylc.core.gerber.IGerberComponentSimple; -import org.diylc.core.measures.Size; -import org.diylc.core.measures.SizeUnit; -import org.diylc.utils.Constants; - -@ComponentDescriptor(name = "Mini Signal Transformer", author = "Branislav Stojkovic", category = "Passive", - instanceNamePrefix = "TR", description = "Miniature PCB-mount signal transformer with EI core", - zOrder = IDIYComponent.COMPONENT, keywordPolicy = KeywordPolicy.SHOW_VALUE) -public class AudioTransformer extends AbstractMultiPartComponent implements IGerberComponentSimple { - - private static final long serialVersionUID = 1L; - - public static Color CORE_COLOR = METAL_COLOR; - public static Color CORE_BORDER_COLOR = CORE_COLOR.darker(); - public static Color COIL_COLOR = Color.decode("#DDDDDD"); - public static Color COIL_BORDER_COLOR = COIL_COLOR.darker(); - public static Color PIN_COLOR = Color.decode("#00B2EE"); - public static Color PIN_BORDER_COLOR = PIN_COLOR.darker(); - public static Color LABEL_COLOR = Color.white; - public static int EDGE_RADIUS = 6; - public static Size PIN_SIZE = new Size(0.03d, SizeUnit.in); - - private String value = ""; - private Orientation orientation = Orientation.DEFAULT; - private Size leadSpacing = new Size(0.1d, SizeUnit.in); - private Size windingSpacing = new Size(0.5d, SizeUnit.in); - private Size coreThickness = new Size(0.15d, SizeUnit.in); - private Size coreWidth = new Size(0.6, SizeUnit.in); - private Size coilWidth = new Size(0.5, SizeUnit.in); - private Size coilLength = new Size(0.6, SizeUnit.in); - private Point2D[] controlPoints = new Point2D[] {new Point2D.Double(0, 0)}; - protected Display display = Display.BOTH; - private Color coreColor = CORE_COLOR; - private Color coreBorderColor = CORE_BORDER_COLOR; - private Color coilColor = COIL_COLOR; - private Color coilBorderColor = COIL_BORDER_COLOR; - private Color labelColor = LABEL_COLOR; - private boolean primaryCT = true; - private boolean secondaryCT = true; - - transient private Area[] body; - - public AudioTransformer() { - super(); - updateControlPoints(); - alpha = 100; - } - - @EditableProperty - public String getValue() { - return value; - } - - public void setValue(String value) { - this.value = value; - } - - @EditableProperty - public Orientation getOrientation() { - return orientation; - } - - public void setOrientation(Orientation orientation) { - this.orientation = orientation; - updateControlPoints(); - // Reset body shape. - body = null; - } - - @EditableProperty(name = "Lead Spacing", validatorClass = PositiveNonZeroMeasureValidator.class) - public Size getLeadSpacing() { - return leadSpacing; - } - - public void setLeadSpacing(Size leadSpacing) { - this.leadSpacing = leadSpacing; - updateControlPoints(); - // Reset body shape; - body = null; - } - - @EditableProperty(name = "Winding Spacing", validatorClass = PositiveNonZeroMeasureValidator.class) - public Size getWindingSpacing() { - return windingSpacing; - } - - public void setWindingSpacing(Size rowSpacing) { - this.windingSpacing = rowSpacing; - updateControlPoints(); - // Reset body shape; - body = null; - } - - @EditableProperty - public Display getDisplay() { - if (display == null) { - display = Display.VALUE; - } - return display; - } - - public void setDisplay(Display display) { - this.display = display; - } - - @Override - public int getControlPointCount() { - return controlPoints.length; - } - - @Override - public Point2D getControlPoint(int index) { - return controlPoints[index]; - } - - @Override - public boolean isControlPointSticky(int index) { - return true; - } - - @Override - public VisibilityPolicy getControlPointVisibilityPolicy(int index) { - return VisibilityPolicy.NEVER; - } - - @Override - public void setControlPoint(Point2D point, int index) { - controlPoints[index].setLocation(point); - body = null; - } - - private void updateControlPoints() { - Point2D firstPoint = controlPoints[0]; - int pinCount = 4 + (primaryCT ? 1 : 0) + (secondaryCT ? 1 : 0); - controlPoints = new Point2D[pinCount]; - controlPoints[0] = firstPoint; - double leadSpacing = this.leadSpacing.convertToPixels(); - double windingSpacing = this.windingSpacing.convertToPixels(); - - // Update control points. - for (int i = 1; i < 2 + (primaryCT ? 1 : 0); i++) - controlPoints[i] = new Point2D.Double(firstPoint.getX(), firstPoint.getY() + i * leadSpacing * (primaryCT ? 1 : 2)); - for (int i = 0; i < 2 + (secondaryCT ? 1 : 0); i++) - controlPoints[2 + (primaryCT ? 1 : 0) + i] = new Point2D.Double(firstPoint.getX() + windingSpacing, firstPoint.getY() + i * leadSpacing * (secondaryCT ? 1 : 2)); - - AffineTransform tx = getTx(); - - if (tx != null) { - for (int i = 1; i < controlPoints.length; i++) { - tx.transform(controlPoints[i], controlPoints[i]); - } - } - } - - @Override - public Area[] getBody() { - if (body == null) { - body = new Area[2]; - double leadSpacing = this.leadSpacing.convertToPixels(); - double windingSpacing = this.windingSpacing.convertToPixels(); - double centerX = (int) (controlPoints[0].getX() + windingSpacing / 2); - double centerY = (int) (controlPoints[0].getY() + leadSpacing); - int coreWidth = getClosestOdd(this.coreWidth.convertToPixels()); - int coreThickness = getClosestOdd(this.coreThickness.convertToPixels()); - int coilWidth = getClosestOdd(this.coilWidth.convertToPixels()); - int coilLength = getClosestOdd(this.coilLength.convertToPixels()); - - body[0] = new Area(new Rectangle2D.Double(centerX - coreThickness / 2, centerY - coreWidth / 2, coreThickness, coreWidth)); - body[1] = new Area(new RoundRectangle2D.Double(centerX - coilLength / 2, centerY - coilWidth / 2, coilLength, coilWidth, coilWidth / 3, coilWidth / 3)); - body[1].subtract(body[0]); - - AffineTransform tx = getTx(); - if (tx != null) - for (Area b : body) { - if (b != null) - b.transform(tx); - } - } - return body; - } - - @SuppressWarnings("incomplete-switch") - private AffineTransform getTx() { - double x = controlPoints[0].getX(); - double y = controlPoints[0].getY(); - if (orientation == Orientation.DEFAULT) - return null; - - double theta = 0; - switch (orientation) { - case _90: - theta = Math.PI / 2; - break; - case _180: - theta = Math.PI; - break; - case _270: - theta = Math.PI * 3 / 2; - break; - } - AffineTransform rotation = AffineTransform.getRotateInstance(theta, x, y); - - return rotation; - } - - @Override - public void draw(Graphics2D g2d, ComponentState componentState, boolean outlineMode, Project project, - IDrawingObserver drawingObserver) { - if (checkPointsClipped(g2d.getClip())) { - return; - } - Area[] body = getBody(); - Area coreArea = body[0]; - Area coilArea = body[1]; - - if (!outlineMode) { - int pinSize = (int) PIN_SIZE.convertToPixels() / 2 * 2; - for (Point2D point : controlPoints) { - g2d.setColor(PIN_COLOR); - g2d.fillOval((int)(point.getX() - pinSize / 2), (int)(point.getY() - pinSize / 2), pinSize, pinSize); - g2d.setColor(PIN_BORDER_COLOR); - g2d.drawOval((int)(point.getX() - pinSize / 2), (int)(point.getY() - pinSize / 2), pinSize, pinSize); - } - } - Composite oldComposite = g2d.getComposite(); - if (alpha < MAX_ALPHA) { - g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1f * alpha / MAX_ALPHA)); - } - - // render coil - g2d.setColor(outlineMode ? Constants.TRANSPARENT_COLOR : getCoilColor()); - g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(1)); - g2d.fill(coilArea); - Color finalBorderColor; - if (outlineMode) { - Theme theme = - (Theme) ConfigurationManager.getInstance().readObject(IPlugInPort.THEME_KEY, Constants.DEFAULT_THEME); - finalBorderColor = theme.getOutlineColor(); - } else { - finalBorderColor = getCoilBorderColor(); - } - g2d.setColor(finalBorderColor); - g2d.draw(coilArea); - - // render core - g2d.setColor(outlineMode ? Constants.TRANSPARENT_COLOR : getCoreColor()); - g2d.fill(coreArea); - g2d.setComposite(oldComposite); - - if (!outlineMode) - finalBorderColor = getCoreBorderColor(); - - g2d.setColor(finalBorderColor); - g2d.draw(coreArea); - - drawingObserver.stopTracking(); - - g2d.setFont(project.getFont()); - - // Override font size - if (getFontSizeOverride() != null) - g2d.setFont(g2d.getFont().deriveFont(1f * getFontSizeOverride())); - - // Draw winding designations - Point2D wPoint = new Point2D.Double((int) (controlPoints[0].getX() + project.getFontSize()), (int) (controlPoints[0].getY() + leadSpacing.convertToPixels())); - AffineTransform tx = getTx(); - if (tx != null) - tx.transform(wPoint, wPoint); - StringUtils.drawCenteredText(g2d, "P", wPoint.getX(), wPoint.getY(), HorizontalAlignment.CENTER, VerticalAlignment.CENTER); - wPoint = new Point2D.Double((int) (controlPoints[0].getX() + windingSpacing.convertToPixels() - project.getFontSize()), (int) (controlPoints[0].getY() + leadSpacing.convertToPixels())); - if (tx != null) - tx.transform(wPoint, wPoint); - StringUtils.drawCenteredText(g2d, "S", wPoint.getX(), wPoint.getY(), HorizontalAlignment.CENTER, VerticalAlignment.CENTER); - - // Draw label. - 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 - : getLabelColor(); - } - g2d.setColor(finalLabelColor); - FontMetrics fontMetrics = g2d.getFontMetrics(g2d.getFont()); - String[] label = null; - - if (getDisplay() == Display.NAME) { - label = new String[] {getName()}; - } else if (getDisplay() == Display.VALUE) { - label = new String[] {getValue().toString()}; - } else if (getDisplay() == Display.BOTH) { - String value = getValue().toString(); - label = value.isEmpty() ? new String[] {getName()} : new String[] {getName(), value}; - } - - if (label != null) { - for (int i = 0; i < label.length; i++) { - String l = label[i]; - Rectangle2D rect = fontMetrics.getStringBounds(l, g2d); - int textHeight = (int) (rect.getHeight()); - int textWidth = (int) (rect.getWidth()); - // Center text horizontally and vertically - Rectangle bounds = coreArea.getBounds(); - double x = bounds.getX() + (bounds.width - textWidth) / 2; - double y = bounds.getY() + (bounds.height - textHeight) / 2 + fontMetrics.getAscent(); - - AffineTransform oldTransform = g2d.getTransform(); - - if (getOrientation() == Orientation.DEFAULT || getOrientation() == Orientation._180) { - double centerX = bounds.getX() + bounds.width / 2; - double centerY = bounds.getY() + bounds.height / 2; - g2d.rotate(-Math.PI / 2, centerX, centerY); - } - - if (label.length == 2) { - if (i == 0) - g2d.translate(0, -textHeight / 2); - else if (i == 1) - g2d.translate(0, textHeight / 2); - } - - g2d.drawString(l, (int)x, (int)y); - - g2d.setTransform(oldTransform); - } - } - - drawSelectionOutline(g2d, componentState, outlineMode, project, drawingObserver); - } - - @Override - public void drawIcon(Graphics2D g2d, int width, int height) { - int radius = (int) (12f * width / 32); - g2d.setColor(COIL_COLOR); - g2d.fillRoundRect(1, (int) (height / 8f), width - 2, (int) (height * 6 / 8f), radius, radius); - g2d.setColor(COIL_BORDER_COLOR); - g2d.drawRoundRect(1, (int) (height / 8f), width - 2, (int) (height * 6 / 8f), radius, radius); - - g2d.setColor(CORE_COLOR); - g2d.fillRect(width * 3 / 8, 1, width / 4, height - 2); - g2d.setColor(CORE_BORDER_COLOR); - g2d.drawRect(width * 3 / 8, 1, width / 4, height - 2); - - g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.5f)); - - int pinSize = (int) (2f * width / 32); - g2d.setColor(PIN_COLOR); - for (int i = 0; i < 3; i++) { - g2d.fillOval(width / 5 - pinSize + 1, (height / 6) * (i + 2), pinSize, pinSize); - g2d.fillOval(4 * width / 5 + 1, (height / 6) * (i + 2), pinSize, pinSize); - } - } - - @EditableProperty(name = "Core") - public Color getCoreColor() { - if (coreColor == null) { - coreColor = CORE_COLOR; - } - return coreColor; - } - - public void setCoreColor(Color coreColor) { - this.coreColor = coreColor; - } - - @EditableProperty(name = "Core Border") - public Color getCoreBorderColor() { - if (coreBorderColor == null) { - coreBorderColor = CORE_BORDER_COLOR; - } - return coreBorderColor; - } - - public void setCoreBorderColor(Color coreBorderColor) { - this.coreBorderColor = coreBorderColor; - } - - @EditableProperty(name = "Label") - public Color getLabelColor() { - if (labelColor == null) { - labelColor = LABEL_COLOR; - } - return labelColor; - } - - public void setLabelColor(Color labelColor) { - this.labelColor = labelColor; - } - - @EditableProperty(name = "Core Thickness") - public Size getCoreThickness() { - return coreThickness; - } - - public void setCoreThickness(Size coreThickness) { - this.coreThickness = coreThickness; - body = null; - } - - @EditableProperty(name = "Core Width") - public Size getCoreWidth() { - return coreWidth; - } - - public void setCoreWidth(Size coreWidth) { - this.coreWidth = coreWidth; - body = null; - } - - @EditableProperty(name = "Coil Width") - public Size getCoilWidth() { - return coilWidth; - } - - public void setCoilWidth(Size coilWidth) { - this.coilWidth = coilWidth; - body = null; - } - - @EditableProperty(name = "Coil Length") - public Size getCoilLength() { - return coilLength; - } - - public void setCoilLength(Size coilLength) { - this.coilLength = coilLength; - body = null; - } - - @EditableProperty(name = "Coil") - public Color getCoilColor() { - return coilColor; - } - - public void setCoilColor(Color coilColor) { - this.coilColor = coilColor; - } - - @EditableProperty(name = "Coil Border") - public Color getCoilBorderColor() { - return coilBorderColor; - } - - public void setCoilBorderColor(Color coilBorderColor) { - this.coilBorderColor = coilBorderColor; - } - - @EditableProperty(name = "Primary CT") - public boolean getPrimaryCT() { - return primaryCT; - } - - public void setPrimaryCT(boolean primaryCT) { - this.primaryCT = primaryCT; - updateControlPoints(); - } - - @EditableProperty(name = "Secondary CT") - public boolean getSecondaryCT() { - return secondaryCT; - } - - public void setSecondaryCT(boolean secondaryCT) { - this.secondaryCT = secondaryCT; - updateControlPoints(); - } - - @Override - public boolean canPointMoveFreely(int pointIndex) { - return false; - } -} +/* + + DIY Layout Creator (DIYLC). + Copyright (c) 2009-2025 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.passive; + +import java.awt.AlphaComposite; +import java.awt.Color; +import java.awt.Composite; +import java.awt.FontMetrics; +import java.awt.Graphics2D; +import java.awt.Rectangle; +import java.awt.geom.AffineTransform; +import java.awt.geom.Area; +import java.awt.geom.Point2D; +import java.awt.geom.Rectangle2D; +import java.awt.geom.RoundRectangle2D; +import org.diylc.appframework.miscutils.ConfigurationManager; + +import org.diylc.awt.StringUtils; +import org.diylc.common.Display; +import org.diylc.common.HorizontalAlignment; +import org.diylc.common.IPlugInPort; +import org.diylc.common.ObjectCache; +import org.diylc.common.Orientation; +import org.diylc.common.VerticalAlignment; +import org.diylc.components.AbstractMultiPartComponent; +import org.diylc.core.ComponentState; +import org.diylc.core.IDIYComponent; +import org.diylc.core.IDrawingObserver; +import org.diylc.core.Project; +import org.diylc.core.Theme; +import org.diylc.core.VisibilityPolicy; +import org.diylc.core.annotations.ComponentDescriptor; +import org.diylc.core.annotations.EditableProperty; +import org.diylc.core.annotations.KeywordPolicy; +import org.diylc.core.annotations.PositiveNonZeroMeasureValidator; +import org.diylc.core.gerber.IGerberComponentSimple; +import org.diylc.core.measures.Size; +import org.diylc.core.measures.SizeUnit; +import org.diylc.utils.Constants; + +@ComponentDescriptor(name = "Mini Signal Transformer", author = "Branislav Stojkovic", category = "Passive", + instanceNamePrefix = "TR", description = "Miniature PCB-mount signal transformer with EI core", + zOrder = IDIYComponent.COMPONENT, keywordPolicy = KeywordPolicy.SHOW_VALUE) +public class AudioTransformer extends AbstractMultiPartComponent implements IGerberComponentSimple { + + private static final long serialVersionUID = 1L; + + public static Color CORE_COLOR = METAL_COLOR; + public static Color CORE_BORDER_COLOR = CORE_COLOR.darker(); + public static Color COIL_COLOR = Color.decode("#DDDDDD"); + public static Color COIL_BORDER_COLOR = COIL_COLOR.darker(); + public static Color PIN_COLOR = Color.decode("#00B2EE"); + public static Color PIN_BORDER_COLOR = PIN_COLOR.darker(); + public static Color LABEL_COLOR = Color.white; + public static int EDGE_RADIUS = 6; + public static Size PIN_SIZE = new Size(0.03d, SizeUnit.in); + + private String value = ""; + private Orientation orientation = Orientation.DEFAULT; + private Size leadSpacing = new Size(0.1d, SizeUnit.in); + private Size windingSpacing = new Size(0.5d, SizeUnit.in); + private Size coreThickness = new Size(0.15d, SizeUnit.in); + private Size coreWidth = new Size(0.6, SizeUnit.in); + private Size coilWidth = new Size(0.5, SizeUnit.in); + private Size coilLength = new Size(0.6, SizeUnit.in); + private Point2D[] controlPoints = new Point2D[] {new Point2D.Double(0, 0)}; + protected Display display = Display.BOTH; + private Color coreColor = CORE_COLOR; + private Color coreBorderColor = CORE_BORDER_COLOR; + private Color coilColor = COIL_COLOR; + private Color coilBorderColor = COIL_BORDER_COLOR; + private Color labelColor = LABEL_COLOR; + private boolean primaryCT = true; + private boolean secondaryCT = true; + + transient private Area[] body; + + public AudioTransformer() { + super(); + updateControlPoints(); +// alpha = 100; + } + + @EditableProperty + public String getValue() { + return value; + } + + public void setValue(String value) { + this.value = value; + } + + @EditableProperty + public Orientation getOrientation() { + return orientation; + } + + public void setOrientation(Orientation orientation) { + this.orientation = orientation; + updateControlPoints(); + // Reset body shape. + body = null; + } + + @EditableProperty(name = "Lead Spacing", validatorClass = PositiveNonZeroMeasureValidator.class) + public Size getLeadSpacing() { + return leadSpacing; + } + + public void setLeadSpacing(Size leadSpacing) { + this.leadSpacing = leadSpacing; + updateControlPoints(); + // Reset body shape; + body = null; + } + + @EditableProperty(name = "Winding Spacing", validatorClass = PositiveNonZeroMeasureValidator.class) + public Size getWindingSpacing() { + return windingSpacing; + } + + public void setWindingSpacing(Size rowSpacing) { + this.windingSpacing = rowSpacing; + updateControlPoints(); + // Reset body shape; + body = null; + } + + @EditableProperty + public Display getDisplay() { + if (display == null) { + display = Display.VALUE; + } + return display; + } + + public void setDisplay(Display display) { + this.display = display; + } + + @Override + public int getControlPointCount() { + return controlPoints.length; + } + + @Override + public Point2D getControlPoint(int index) { + return controlPoints[index]; + } + + @Override + public boolean isControlPointSticky(int index) { + return true; + } + + @Override + public VisibilityPolicy getControlPointVisibilityPolicy(int index) { + return VisibilityPolicy.NEVER; + } + + @Override + public void setControlPoint(Point2D point, int index) { + controlPoints[index].setLocation(point); + body = null; + } + + private void updateControlPoints() { + Point2D firstPoint = controlPoints[0]; + int pinCount = 4 + (primaryCT ? 1 : 0) + (secondaryCT ? 1 : 0); + controlPoints = new Point2D[pinCount]; + controlPoints[0] = firstPoint; + double leadSpacing = this.leadSpacing.convertToPixels(); + double windingSpacing = this.windingSpacing.convertToPixels(); + + // Update control points. + for (int i = 1; i < 2 + (primaryCT ? 1 : 0); i++) + controlPoints[i] = new Point2D.Double(firstPoint.getX(), firstPoint.getY() + i * leadSpacing * (primaryCT ? 1 : 2)); + for (int i = 0; i < 2 + (secondaryCT ? 1 : 0); i++) + controlPoints[2 + (primaryCT ? 1 : 0) + i] = new Point2D.Double(firstPoint.getX() + windingSpacing, firstPoint.getY() + i * leadSpacing * (secondaryCT ? 1 : 2)); + + AffineTransform tx = getTx(); + + if (tx != null) { + for (int i = 1; i < controlPoints.length; i++) { + tx.transform(controlPoints[i], controlPoints[i]); + } + } + } + + @Override + public Area[] getBody() { + if (body == null) { + body = new Area[2]; + double leadSpacing = this.leadSpacing.convertToPixels(); + double windingSpacing = this.windingSpacing.convertToPixels(); + double centerX = (int) (controlPoints[0].getX() + windingSpacing / 2); + double centerY = (int) (controlPoints[0].getY() + leadSpacing); + int coreWidth = getClosestOdd(this.coreWidth.convertToPixels()); + int coreThickness = getClosestOdd(this.coreThickness.convertToPixels()); + int coilWidth = getClosestOdd(this.coilWidth.convertToPixels()); + int coilLength = getClosestOdd(this.coilLength.convertToPixels()); + + body[0] = new Area(new Rectangle2D.Double(centerX - coreThickness / 2, centerY - coreWidth / 2, coreThickness, coreWidth)); + body[1] = new Area(new RoundRectangle2D.Double(centerX - coilLength / 2, centerY - coilWidth / 2, coilLength, coilWidth, coilWidth / 3, coilWidth / 3)); + body[1].subtract(body[0]); + + AffineTransform tx = getTx(); + if (tx != null) + for (Area b : body) { + if (b != null) + b.transform(tx); + } + } + return body; + } + + @SuppressWarnings("incomplete-switch") + private AffineTransform getTx() { + double x = controlPoints[0].getX(); + double y = controlPoints[0].getY(); + if (orientation == Orientation.DEFAULT) + return null; + + double theta = 0; + switch (orientation) { + case _90: + theta = Math.PI / 2; + break; + case _180: + theta = Math.PI; + break; + case _270: + theta = Math.PI * 3 / 2; + break; + } + AffineTransform rotation = AffineTransform.getRotateInstance(theta, x, y); + + return rotation; + } + + @Override + public void draw(Graphics2D g2d, ComponentState componentState, boolean outlineMode, Project project, + IDrawingObserver drawingObserver) { + if (checkPointsClipped(g2d.getClip())) { + return; + } + Area[] body = getBody(); + Area coreArea = body[0]; + Area coilArea = body[1]; + + if (!outlineMode) { + int pinSize = (int) PIN_SIZE.convertToPixels() / 2 * 2; + for (Point2D point : controlPoints) { + g2d.setColor(PIN_COLOR); + g2d.fillOval((int)(point.getX() - pinSize / 2), (int)(point.getY() - pinSize / 2), pinSize, pinSize); + g2d.setColor(PIN_BORDER_COLOR); + g2d.drawOval((int)(point.getX() - pinSize / 2), (int)(point.getY() - pinSize / 2), pinSize, pinSize); + } + } + Composite oldComposite = applyAlpha(g2d, componentState); + + // render coil + g2d.setColor(outlineMode ? Constants.TRANSPARENT_COLOR : getCoilColor()); + g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(1)); + g2d.fill(coilArea); + Color finalBorderColor; + if (outlineMode) { + Theme theme = + (Theme) ConfigurationManager.getInstance().readObject(IPlugInPort.THEME_KEY, Constants.DEFAULT_THEME); + finalBorderColor = theme.getOutlineColor(); + } else { + finalBorderColor = getCoilBorderColor(); + } + g2d.setColor(finalBorderColor); + g2d.draw(coilArea); + + // render core + g2d.setColor(outlineMode ? Constants.TRANSPARENT_COLOR : getCoreColor()); + g2d.fill(coreArea); + g2d.setComposite(oldComposite); + + if (!outlineMode) + finalBorderColor = getCoreBorderColor(); + + g2d.setColor(finalBorderColor); + g2d.draw(coreArea); + + drawingObserver.stopTracking(); + + g2d.setFont(project.getFont()); + + // Override font size + if (getFontSizeOverride() != null) + g2d.setFont(g2d.getFont().deriveFont(1f * getFontSizeOverride())); + + // Draw winding designations + Point2D wPoint = new Point2D.Double((int) (controlPoints[0].getX() + project.getFontSize()), (int) (controlPoints[0].getY() + leadSpacing.convertToPixels())); + AffineTransform tx = getTx(); + if (tx != null) + tx.transform(wPoint, wPoint); + StringUtils.drawCenteredText(g2d, "P", wPoint.getX(), wPoint.getY(), HorizontalAlignment.CENTER, VerticalAlignment.CENTER); + wPoint = new Point2D.Double((int) (controlPoints[0].getX() + windingSpacing.convertToPixels() - project.getFontSize()), (int) (controlPoints[0].getY() + leadSpacing.convertToPixels())); + if (tx != null) + tx.transform(wPoint, wPoint); + StringUtils.drawCenteredText(g2d, "S", wPoint.getX(), wPoint.getY(), HorizontalAlignment.CENTER, VerticalAlignment.CENTER); + + // Draw label. + 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 + : getLabelColor(); + } + g2d.setColor(finalLabelColor); + FontMetrics fontMetrics = g2d.getFontMetrics(g2d.getFont()); + String[] label = null; + + if (getDisplay() == Display.NAME) { + label = new String[] {getName()}; + } else if (getDisplay() == Display.VALUE) { + label = new String[] {getValue().toString()}; + } else if (getDisplay() == Display.BOTH) { + String value = getValue().toString(); + label = value.isEmpty() ? new String[] {getName()} : new String[] {getName(), value}; + } + + if (label != null) { + for (int i = 0; i < label.length; i++) { + String l = label[i]; + Rectangle2D rect = fontMetrics.getStringBounds(l, g2d); + int textHeight = (int) (rect.getHeight()); + int textWidth = (int) (rect.getWidth()); + // Center text horizontally and vertically + Rectangle bounds = coreArea.getBounds(); + double x = bounds.getX() + (bounds.width - textWidth) / 2; + double y = bounds.getY() + (bounds.height - textHeight) / 2 + fontMetrics.getAscent(); + + AffineTransform oldTransform = g2d.getTransform(); + + if (getOrientation() == Orientation.DEFAULT || getOrientation() == Orientation._180) { + double centerX = bounds.getX() + bounds.width / 2; + double centerY = bounds.getY() + bounds.height / 2; + g2d.rotate(-Math.PI / 2, centerX, centerY); + } + + if (label.length == 2) { + if (i == 0) + g2d.translate(0, -textHeight / 2); + else if (i == 1) + g2d.translate(0, textHeight / 2); + } + + g2d.drawString(l, (int)x, (int)y); + + g2d.setTransform(oldTransform); + } + } + + drawSelectionOutline(g2d, componentState, outlineMode, project, drawingObserver); + } + + @Override + public void drawIcon(Graphics2D g2d, int width, int height) { + int radius = (int) (12f * width / 32); + g2d.setColor(COIL_COLOR); + g2d.fillRoundRect(1, (int) (height / 8f), width - 2, (int) (height * 6 / 8f), radius, radius); + g2d.setColor(COIL_BORDER_COLOR); + g2d.drawRoundRect(1, (int) (height / 8f), width - 2, (int) (height * 6 / 8f), radius, radius); + + g2d.setColor(CORE_COLOR); + g2d.fillRect(width * 3 / 8, 1, width / 4, height - 2); + g2d.setColor(CORE_BORDER_COLOR); + g2d.drawRect(width * 3 / 8, 1, width / 4, height - 2); + + g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.5f)); + + int pinSize = (int) (2f * width / 32); + g2d.setColor(PIN_COLOR); + for (int i = 0; i < 3; i++) { + g2d.fillOval(width / 5 - pinSize + 1, (height / 6) * (i + 2), pinSize, pinSize); + g2d.fillOval(4 * width / 5 + 1, (height / 6) * (i + 2), pinSize, pinSize); + } + } + + @EditableProperty(name = "Core") + public Color getCoreColor() { + if (coreColor == null) { + coreColor = CORE_COLOR; + } + return coreColor; + } + + public void setCoreColor(Color coreColor) { + this.coreColor = coreColor; + } + + @EditableProperty(name = "Core Border") + public Color getCoreBorderColor() { + if (coreBorderColor == null) { + coreBorderColor = CORE_BORDER_COLOR; + } + return coreBorderColor; + } + + public void setCoreBorderColor(Color coreBorderColor) { + this.coreBorderColor = coreBorderColor; + } + + @EditableProperty(name = "Label") + public Color getLabelColor() { + if (labelColor == null) { + labelColor = LABEL_COLOR; + } + return labelColor; + } + + public void setLabelColor(Color labelColor) { + this.labelColor = labelColor; + } + + @EditableProperty(name = "Core Thickness") + public Size getCoreThickness() { + return coreThickness; + } + + public void setCoreThickness(Size coreThickness) { + this.coreThickness = coreThickness; + body = null; + } + + @EditableProperty(name = "Core Width") + public Size getCoreWidth() { + return coreWidth; + } + + public void setCoreWidth(Size coreWidth) { + this.coreWidth = coreWidth; + body = null; + } + + @EditableProperty(name = "Coil Width") + public Size getCoilWidth() { + return coilWidth; + } + + public void setCoilWidth(Size coilWidth) { + this.coilWidth = coilWidth; + body = null; + } + + @EditableProperty(name = "Coil Length") + public Size getCoilLength() { + return coilLength; + } + + public void setCoilLength(Size coilLength) { + this.coilLength = coilLength; + body = null; + } + + @EditableProperty(name = "Coil") + public Color getCoilColor() { + return coilColor; + } + + public void setCoilColor(Color coilColor) { + this.coilColor = coilColor; + } + + @EditableProperty(name = "Coil Border") + public Color getCoilBorderColor() { + return coilBorderColor; + } + + public void setCoilBorderColor(Color coilBorderColor) { + this.coilBorderColor = coilBorderColor; + } + + @EditableProperty(name = "Primary CT") + public boolean getPrimaryCT() { + return primaryCT; + } + + public void setPrimaryCT(boolean primaryCT) { + this.primaryCT = primaryCT; + updateControlPoints(); + } + + @EditableProperty(name = "Secondary CT") + public boolean getSecondaryCT() { + return secondaryCT; + } + + public void setSecondaryCT(boolean secondaryCT) { + this.secondaryCT = secondaryCT; + updateControlPoints(); + } + + @Override + public boolean canPointMoveFreely(int pointIndex) { + return false; + } +} diff --git a/diylc/diylc-library/src/main/java/org/diylc/components/passive/BoxTrimmer.java b/diylc/diylc-library/src/main/java/org/diylc/components/passive/BoxTrimmer.java index a3b4d042a..07f63252e 100644 --- a/diylc/diylc-library/src/main/java/org/diylc/components/passive/BoxTrimmer.java +++ b/diylc/diylc-library/src/main/java/org/diylc/components/passive/BoxTrimmer.java @@ -110,10 +110,7 @@ public class BoxTrimmer extends AbstractTransparentComponent { } // Draw body - Composite oldComposite = g2d.getComposite(); - if (alpha < MAX_ALPHA) { - g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1f * alpha / MAX_ALPHA)); - } + Composite oldComposite = applyAlpha(g2d, componentState); g2d.setColor(outlineMode ? Constants.TRANSPARENT_COLOR : bodyColor); g2d.fillRoundRect(bodyX, bodyY, bodyW, bodyH, bodyW / 10, bodyH / 10); g2d.setComposite(oldComposite); diff --git a/diylc/diylc-library/src/main/java/org/diylc/components/passive/MultiSectionCapacitor.java b/diylc/diylc-library/src/main/java/org/diylc/components/passive/MultiSectionCapacitor.java index 5f93cddab..50203577b 100644 --- a/diylc/diylc-library/src/main/java/org/diylc/components/passive/MultiSectionCapacitor.java +++ b/diylc/diylc-library/src/main/java/org/diylc/components/passive/MultiSectionCapacitor.java @@ -351,10 +351,7 @@ public class MultiSectionCapacitor extends AbstractLabeledComponent. - -*/ -package org.diylc.components.passive; - -import java.awt.AlphaComposite; -import java.awt.Color; -import java.awt.Composite; -import java.awt.FontMetrics; -import java.awt.Graphics2D; -import java.awt.Polygon; -import java.awt.Shape; -import java.awt.geom.Area; -import java.awt.geom.Ellipse2D; -import java.awt.geom.Point2D; -import java.awt.geom.Rectangle2D; -import java.awt.geom.RoundRectangle2D; -import org.diylc.appframework.miscutils.ConfigurationManager; - -import org.diylc.awt.StringUtils; -import org.diylc.common.HorizontalAlignment; -import org.diylc.common.IPlugInPort; -import org.diylc.common.ObjectCache; -import org.diylc.common.Orientation; -import org.diylc.common.VerticalAlignment; -import org.diylc.components.transform.PotentiometerTransformer; -import org.diylc.core.ComponentState; -import org.diylc.core.CreationMethod; -import org.diylc.core.IDIYComponent; -import org.diylc.core.IDrawingObserver; -import org.diylc.core.ILayeredComponent; -import org.diylc.core.Project; -import org.diylc.core.Theme; -import org.diylc.core.annotations.ComponentDescriptor; -import org.diylc.core.annotations.EditableProperty; -import org.diylc.core.measures.Size; -import org.diylc.core.measures.SizeUnit; -import org.diylc.utils.Constants; - -@ComponentDescriptor(name = "Potentiometer", author = "Branislav Stojkovic", category = "Passive", - creationMethod = CreationMethod.SINGLE_CLICK, instanceNamePrefix = "VR", - description = "Panel mount potentiometer with solder lugs", zOrder = IDIYComponent.COMPONENT, - transformer = PotentiometerTransformer.class, enableCache = true) -public class PotentiometerPanel extends AbstractPotentiometer implements ILayeredComponent { - - private static final long serialVersionUID = 1L; - - protected static Size BODY_DIAMETER = new Size(1d, SizeUnit.in); - protected static Size SPACING = new Size(0.3d, SizeUnit.in); - protected static Size LUG_DIAMETER = new Size(0.15d, SizeUnit.in); - protected static Size PIN_SIZE = new Size(0.05d, SizeUnit.in); - protected static Size NUT_SIZE = new Size(0.4d, SizeUnit.in); - protected static Size SHAFT_SIZE = new Size(1 / 4d, SizeUnit.in); - protected static Size MARKER_OFFSET = new Size(0.05d, SizeUnit.in); - protected static Color BODY_COLOR = Color.lightGray; - protected static Color WAFER_COLOR = Color.decode("#CD8500"); - protected static Color BORDER_COLOR = Color.gray; - protected static Color NUT_COLOR = Color.decode("#CBD5DB"); - protected static Color MARKER_COLOR_DEFAULT = Color.gray; - - - protected Size bodyDiameter = BODY_DIAMETER; - protected Size spacing = SPACING; - protected Size lugDiameter = LUG_DIAMETER; - protected Color bodyColor = BODY_COLOR; - protected Color borderColor = BORDER_COLOR; - protected Color nutColor = NUT_COLOR; - protected Color waferColor = WAFER_COLOR; - protected Type type = Type.ThroughHole; - @Deprecated - protected boolean showShaft = false; - protected View view; - private Boolean showMarkers; - private Color markerColor; - // Array of 7 elements: 3 lug connectors, 1 pot body and 3 lugs - transient protected Area[] body = null; - - public PotentiometerPanel() { - controlPoints = new Point2D[] {new Point2D.Double(0, 0), new Point2D.Double(0, 0), new Point2D.Double(0, 0)}; - updateControlPoints(); - } - - protected void updateControlPoints() { - int spacing = (int) this.spacing.convertToPixels(); - switch (orientation) { - case DEFAULT: - controlPoints[1].setLocation(controlPoints[0].getX() + spacing, controlPoints[0].getY()); - controlPoints[2].setLocation(controlPoints[0].getX() + 2 * spacing, controlPoints[0].getY()); - break; - case _90: - controlPoints[1].setLocation(controlPoints[0].getX(), controlPoints[0].getY() + spacing); - controlPoints[2].setLocation(controlPoints[0].getX(), controlPoints[0].getY() + 2 * spacing); - break; - case _180: - controlPoints[1].setLocation(controlPoints[0].getX() - spacing, controlPoints[0].getY()); - controlPoints[2].setLocation(controlPoints[0].getX() - 2 * spacing, controlPoints[0].getY()); - break; - case _270: - controlPoints[1].setLocation(controlPoints[0].getX(), controlPoints[0].getY() - spacing); - controlPoints[2].setLocation(controlPoints[0].getX(), controlPoints[0].getY() - 2 * spacing); - break; - default: - break; - } - } - - public Area[] getBody() { - int spacing = (int) this.spacing.convertToPixels(); - int diameter = getClosestOdd(bodyDiameter.convertToPixels()); - if (body == null) { - // mandatory: 0, 1, 2 pins, 3 body, 9 wafer - // optional: 4, 5, 6 lugs, 7 nut, 8 shaft - body = new Area[13]; - - // Add lugs. - int pinWidth = (int) PIN_SIZE.convertToPixels(); - - double centerX = 0; - double centerY = 0; - - double waferWidth = 2.5 * spacing; - double waferHeight = spacing; - - switch (orientation) { - case DEFAULT: - centerX = controlPoints[0].getX() + spacing; - centerY = controlPoints[0].getY() - spacing / 2 - diameter / 2; - - body[9] = - new Area(new RoundRectangle2D.Double(centerX - waferWidth / 2, controlPoints[0].getY() - waferHeight - spacing - / 2, waferWidth, waferHeight, spacing / 4, spacing / 4)); - - for (int i = 0; i < 3; i++) { - body[i] = - new Area(new Rectangle2D.Double(controlPoints[i].getX() - pinWidth / 2, controlPoints[i].getY() - - (spacing + diameter) / 2, pinWidth, (spacing + diameter) / 2)); - } - break; - case _90: - centerX = controlPoints[0].getX() + spacing / 2 + diameter / 2; - centerY = controlPoints[0].getY() + spacing; - - body[9] = - new Area(new RoundRectangle2D.Double(controlPoints[0].getX() + spacing / 2, centerY - waferWidth / 2, - waferHeight, waferWidth, spacing / 4, spacing / 4)); - - for (int i = 0; i < 3; i++) { - body[i] = - new Area(new Rectangle2D.Double(controlPoints[i].getX(), controlPoints[i].getY() - pinWidth / 2, - (spacing + diameter) / 2, pinWidth)); - } - break; - case _180: - centerX = controlPoints[0].getX() - spacing; - centerY = controlPoints[0].getY() + spacing / 2 + diameter / 2; - - body[9] = - new Area(new RoundRectangle2D.Double(centerX - waferWidth / 2, controlPoints[0].getY() + spacing / 2, - waferWidth, waferHeight, spacing / 4, spacing / 4)); - - for (int i = 0; i < 3; i++) { - body[i] = - new Area(new Rectangle2D.Double(controlPoints[i].getX() - pinWidth / 2, controlPoints[i].getY(), pinWidth, - (spacing + diameter) / 2)); - } - break; - case _270: - centerX = controlPoints[0].getX() - spacing / 2 - diameter / 2; - centerY = controlPoints[0].getY() - spacing; - - body[9] = - new Area(new RoundRectangle2D.Double(controlPoints[0].getX() - waferHeight - spacing / 2, centerY - waferWidth - / 2, waferHeight, waferWidth, spacing / 4, spacing / 4)); - - for (int i = 0; i < 3; i++) { - body[i] = - new Area(new Rectangle2D.Double(controlPoints[i].getX() - (spacing + diameter) / 2, controlPoints[i].getY() - - pinWidth / 2, (spacing + diameter) / 2, pinWidth)); - } - break; - default: - break; - } - - body[3] = new Area(new Ellipse2D.Double(centerX - diameter / 2, centerY - diameter / 2, diameter, diameter)); - - body[9].subtract(body[3]); - - for (int i = 0; i < 3; i++) { - body[i].subtract(body[3]); - } - - if (getType() == Type.ThroughHole) { - int lugDiameter = getClosestOdd(this.lugDiameter.convertToPixels()); - int holeDiameter = getClosestOdd(this.lugDiameter.convertToPixels() / 2); - - for (int i = 0; i < 3; i++) { - Area area = - new Area(new Ellipse2D.Double(controlPoints[i].getX() - lugDiameter / 2, controlPoints[i].getY() - lugDiameter / 2, - lugDiameter, lugDiameter)); - body[4 + i] = area; - body[10 + i] = new Area(area); - } - - for (int i = 0; i < 3; i++) { - for (int j = 0; j < 3; j++) { - body[i].subtract(body[4 + j]); - } - } - // Make holes in the lugs. - for (int i = 0; i < 3; i++) { - body[4 + i].subtract(new Area(new Ellipse2D.Double(controlPoints[i].getX() - holeDiameter / 2, controlPoints[i].getY() - - holeDiameter / 2, holeDiameter, holeDiameter))); - } - } - - if (getView() == View.ShaftUp) { - int nutSize = (int) NUT_SIZE.convertToPixels(); - int shaftSize = (int) SHAFT_SIZE.convertToPixels(); - int[] xPoints = new int[6]; - int[] yPoints = new int[6]; - for (int i = 0; i < 6; i++) { - double alpha = Math.toRadians(60 * i); - xPoints[i] = (int) (centerX + Math.cos(alpha) * nutSize / 2); - yPoints[i] = (int) (centerY + Math.sin(alpha) * nutSize / 2); - } - body[7] = new Area(new Polygon(xPoints, yPoints, 6)); - body[8] = - new Area(new Ellipse2D.Double(centerX - shaftSize / 2, centerY - shaftSize / 2, shaftSize, shaftSize)); - } - } - return body; - } - - @Override - public void setControlPoint(Point2D point, int index) { - super.setControlPoint(point, index); - body = null; - } - - @Override - public void setOrientation(Orientation orientation) { - super.setOrientation(orientation); - updateControlPoints(); - body = null; - } - - @Override - public void draw(Graphics2D g2d, ComponentState componentState, boolean outlineMode, Project project, - IDrawingObserver drawingObserver) { - g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(1)); - Theme theme = (Theme) ConfigurationManager.getInstance().readObject(IPlugInPort.THEME_KEY, Constants.DEFAULT_THEME); - Area[] body = getBody(); - for (int i = 0; i < body.length; i++) { - Area shape = body[i]; - // determine color - if (shape != null) { - switch (i) { - case 7: - g2d.setColor(getNutColor()); - break; - case 9: - g2d.setColor(getWaferColor()); - break; - case 10: - case 11: - case 12: - g2d.setColor(Constants.TRANSPARENT_COLOR); - break; - default: - g2d.setColor(getBodyColor()); - } - - Composite oldComposite = g2d.getComposite(); - if (alpha < MAX_ALPHA) { - g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1f * alpha / MAX_ALPHA)); - } - if (!outlineMode) { - if (i >= 10) - drawingObserver.startTrackingContinuityArea(true); - g2d.fill(shape); - if (i >= 10) - drawingObserver.stopTrackingContinuityArea(); - } - g2d.setComposite(oldComposite); - Color finalBorderColor; - if (outlineMode) { - finalBorderColor = - componentState == ComponentState.SELECTED || componentState == ComponentState.DRAGGING ? SELECTION_COLOR - : theme.getOutlineColor(); - } else { - finalBorderColor = - componentState == ComponentState.SELECTED || componentState == ComponentState.DRAGGING ? SELECTION_COLOR - : getBorderColor(); - } - g2d.setColor(finalBorderColor); - g2d.draw(shape); - } - } - - drawingObserver.stopTracking(); - - // Draw caption. - g2d.setFont(project.getFont()); - - // Override font size - if (getFontSizeOverride() != null) - g2d.setFont(g2d.getFont().deriveFont(1f * getFontSizeOverride())); - - Color finalLabelColor; - if (outlineMode) { - finalLabelColor = - componentState == ComponentState.SELECTED || componentState == ComponentState.DRAGGING ? LABEL_COLOR_SELECTED - : theme.getOutlineColor(); - } else { - finalLabelColor = - componentState == ComponentState.SELECTED || componentState == ComponentState.DRAGGING ? LABEL_COLOR_SELECTED - : LABEL_COLOR; - } - g2d.setColor(finalLabelColor); - FontMetrics fontMetrics = g2d.getFontMetrics(); - Rectangle2D bodyRect = getBody()[3].getBounds2D(); - Rectangle2D rect = fontMetrics.getStringBounds(getName(), g2d); - - int textHeight = (int) rect.getHeight(); - int textWidth = (int) rect.getWidth(); - int panelHeight = (int) bodyRect.getHeight(); - int panelWidth = (int) bodyRect.getWidth(); - - int x = (panelWidth - textWidth) / 2; - int y = panelHeight / 2 - textHeight + fontMetrics.getAscent(); - - g2d.drawString(getName(), (int) (bodyRect.getX() + x), (int) (bodyRect.getY() + y)); - - // Draw value. - rect = fontMetrics.getStringBounds(getValueForDisplay(), g2d); - - textHeight = (int) rect.getHeight(); - textWidth = (int) rect.getWidth(); - - x = (panelWidth - textWidth) / 2; - y = panelHeight / 2 + fontMetrics.getAscent(); - - g2d.drawString(getValueForDisplay(), (int) (bodyRect.getX() + x), (int) (bodyRect.getY() + y)); - - // Draw markers if enabled. - if (getShowMarkers()) { - g2d.setColor(outlineMode ? theme.getOutlineColor() : getMarkerColor()); - - // Get circle center and radius - Rectangle2D circleBounds = body[3].getBounds2D(); - double centerX = circleBounds.getCenterX(); - double centerY = circleBounds.getCenterY(); - double radius = getBodyDiameter().convertToPixels() / 2; - - // Fixed distance from circle edge (inside the circle) - double markerOffset = MARKER_OFFSET.convertToPixels() + 2; - double markerDistance = radius - markerOffset; - - // Draw markers "1", "2", "3" along radial line from center to each lug, close to circle edge - // Reverse numbering when view is ShaftDown - boolean reverseOrder = getView() == View.ShaftDown; - - for (int i = 0; i < 3; i++) { - Point2D lugPoint = controlPoints[i]; - - // Calculate direction from center to lug - double dx = lugPoint.getX() - centerX; - double dy = lugPoint.getY() - centerY; - double distance = Math.sqrt(dx * dx + dy * dy); - - if (distance > 0) { - // Normalize direction vector - double unitX = dx / distance; - double unitY = dy / distance; - - // Position marker at fixed distance from circle edge along radial line - double markerX = centerX + unitX * markerDistance; - double markerY = centerY + unitY * markerDistance; - - // Determine marker number based on view - int markerNumber = reverseOrder ? (3 - i) : (i + 1); - - StringUtils.drawCenteredText(g2d, Integer.toString(markerNumber), markerX, markerY, - HorizontalAlignment.CENTER, VerticalAlignment.CENTER); - } - } - } - } - - @Override - public void drawIcon(Graphics2D g2d, int width, int height) { - int margin = 4 * width / 32; - int waferMargin = 5 * width / 32; - int spacing = width / 3 - 1; - g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(1 * width / 32)); - g2d.setColor(WAFER_COLOR); - g2d.fillRect(waferMargin, height / 2, width - 2 * waferMargin, height / 3); - g2d.setColor(BORDER_COLOR); - g2d.drawRoundRect(waferMargin, height / 2, width - 2 * waferMargin, height / 3, 2 * width / 32, 2 * width / 32); - g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(2 * width / 32)); - g2d.drawLine(width / 2 - spacing, height / 2, width / 2 - spacing, height - margin); - g2d.drawLine(width / 2 + spacing, height / 2, width / 2 + spacing, height - margin); - g2d.drawLine(width / 2, height / 2, width / 2, height - margin); - g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(4 * width / 32)); - g2d.drawLine(width / 2 - spacing, height - margin, width / 2 - spacing, height - margin); - g2d.drawLine(width / 2 + spacing, height - margin, width / 2 + spacing, height - margin); - g2d.drawLine(width / 2, height - margin, width / 2, height - margin); - g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(1)); - g2d.setColor(BODY_COLOR); - g2d.fillOval(margin, margin / 2, width - 2 * margin, height - 2 * margin); - g2d.setColor(BORDER_COLOR); - g2d.drawOval(margin, margin / 2, width - 2 * margin, height - 2 * margin); - } - - @EditableProperty - public Size getSpacing() { - return spacing; - } - - public void setSpacing(Size spacing) { - this.spacing = spacing; - updateControlPoints(); - body = null; - } - - @EditableProperty - public Type getType() { - if (type == null) - type = Type.ThroughHole; - return type; - } - - public void setType(Type type) { - this.type = type; - body = null; - } - - @EditableProperty(name = "Nut") - public Color getNutColor() { - if (nutColor == null) - nutColor = NUT_COLOR; - return nutColor; - } - - public void setNutColor(Color nutColor) { - this.nutColor = nutColor; - } - - @EditableProperty(name = "Diameter") - public Size getBodyDiameter() { - return bodyDiameter; - } - - public void setBodyDiameter(Size bodyDiameter) { - this.bodyDiameter = bodyDiameter; - body = null; - } - - @EditableProperty(name = "Lug Size") - public Size getLugDiameter() { - return lugDiameter; - } - - public void setLugDiameter(Size lugDiameter) { - this.lugDiameter = lugDiameter; - body = null; - } - - @EditableProperty(name = "Body") - public Color getBodyColor() { - return bodyColor; - } - - public void setBodyColor(Color bodyColor) { - this.bodyColor = bodyColor; - } - - @EditableProperty(name = "Border") - public Color getBorderColor() { - return borderColor; - } - - public void setBorderColor(Color borderColor) { - this.borderColor = borderColor; - } - - @EditableProperty(name = "View") - public View getView() { - if (view == null) - view = showShaft ? View.ShaftUp : View.ShaftDown; - return view; - } - - public void setView(View view) { - this.view = view; - body = null; - } - - @EditableProperty(name = "Wafer") - public Color getWaferColor() { - if (waferColor == null) - waferColor = WAFER_COLOR; - return waferColor; - } - - public void setWaferColor(Color waferColor) { - this.waferColor = waferColor; - } - - @EditableProperty(name = "Markers") - public Boolean getShowMarkers() { - if (showMarkers == null) { - showMarkers = false; - } - return showMarkers; - } - - public void setShowMarkers(Boolean showMarkers) { - this.showMarkers = showMarkers; - } - - @EditableProperty(name = "Marker Color") - public Color getMarkerColor() { - if (markerColor == null) { - markerColor = MARKER_COLOR_DEFAULT; - } - return markerColor; - } - - public void setMarkerColor(Color markerColor) { - this.markerColor = markerColor; - } - - @Override - public String getInternalLinkName(int index1, int index2) { - if (index1 > index2) - return getInternalLinkName(index2, index1); - - if (index2 - index1 == 1) - return (index1 + 1) + "-" + (index2 + 1); - - return null; - } - - @Override - public Rectangle2D getCachingBounds() { - Shape[] body = getBody(); - int margin = 20; - double minX = 0; - double minY = 0; - double maxX = 0; - double maxY = 0; - for (Shape a : body) { - if (a != null) { - Rectangle2D bounds2d = a.getBounds2D(); - if (bounds2d.getMinX() < minX) - minX = bounds2d.getMinX(); - if (bounds2d.getMinY() < minY) - minY = bounds2d.getMinY(); - if (bounds2d.getMaxX() > maxX) - maxX = bounds2d.getMaxX(); - if (bounds2d.getMaxY() > maxY) - maxY = bounds2d.getMaxY(); - } - } - return new Rectangle2D.Double(minX - margin, minY - margin, maxX - minX + 2 * margin, maxY - minY + 2 * margin); - } - - @Override - public boolean canPointMoveFreely(int pointIndex) { - return false; - } - - @Override - public int getLayerId() { - return hashCode(); - } - - public enum Type { - ThroughHole("Through Hole"), PCB("PCB"); - - private String value; - - private Type(String value) { - this.value = value; - } - - @Override - public String toString() { - return value; - } - } - - public enum View { - ShaftDown("Shaft Down"), ShaftUp("Shaft Up");//, TerminalsDown, TerminalsUp; - - private String value; - - private View(String value) { - this.value = value; - } - - @Override - public String toString() { - return value; - } - } -} +/* + + DIY Layout Creator (DIYLC). + Copyright (c) 2009-2025 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.passive; + +import java.awt.AlphaComposite; +import java.awt.Color; +import java.awt.Composite; +import java.awt.FontMetrics; +import java.awt.Graphics2D; +import java.awt.Polygon; +import java.awt.Shape; +import java.awt.geom.Area; +import java.awt.geom.Ellipse2D; +import java.awt.geom.Point2D; +import java.awt.geom.Rectangle2D; +import java.awt.geom.RoundRectangle2D; +import org.diylc.appframework.miscutils.ConfigurationManager; + +import org.diylc.awt.StringUtils; +import org.diylc.common.HorizontalAlignment; +import org.diylc.common.IPlugInPort; +import org.diylc.common.ObjectCache; +import org.diylc.common.Orientation; +import org.diylc.common.VerticalAlignment; +import org.diylc.components.transform.PotentiometerTransformer; +import org.diylc.core.ComponentState; +import org.diylc.core.CreationMethod; +import org.diylc.core.IDIYComponent; +import org.diylc.core.IDrawingObserver; +import org.diylc.core.ILayeredComponent; +import org.diylc.core.Project; +import org.diylc.core.Theme; +import org.diylc.core.annotations.ComponentDescriptor; +import org.diylc.core.annotations.EditableProperty; +import org.diylc.core.measures.Size; +import org.diylc.core.measures.SizeUnit; +import org.diylc.utils.Constants; + +@ComponentDescriptor(name = "Potentiometer", author = "Branislav Stojkovic", category = "Passive", + creationMethod = CreationMethod.SINGLE_CLICK, instanceNamePrefix = "VR", + description = "Panel mount potentiometer with solder lugs", zOrder = IDIYComponent.COMPONENT, + transformer = PotentiometerTransformer.class, enableCache = true) +public class PotentiometerPanel extends AbstractPotentiometer implements ILayeredComponent { + + private static final long serialVersionUID = 1L; + + protected static Size BODY_DIAMETER = new Size(1d, SizeUnit.in); + protected static Size SPACING = new Size(0.3d, SizeUnit.in); + protected static Size LUG_DIAMETER = new Size(0.15d, SizeUnit.in); + protected static Size PIN_SIZE = new Size(0.05d, SizeUnit.in); + protected static Size NUT_SIZE = new Size(0.4d, SizeUnit.in); + protected static Size SHAFT_SIZE = new Size(1 / 4d, SizeUnit.in); + protected static Size MARKER_OFFSET = new Size(0.05d, SizeUnit.in); + protected static Color BODY_COLOR = Color.lightGray; + protected static Color WAFER_COLOR = Color.decode("#CD8500"); + protected static Color BORDER_COLOR = Color.gray; + protected static Color NUT_COLOR = Color.decode("#CBD5DB"); + protected static Color MARKER_COLOR_DEFAULT = Color.gray; + + + protected Size bodyDiameter = BODY_DIAMETER; + protected Size spacing = SPACING; + protected Size lugDiameter = LUG_DIAMETER; + protected Color bodyColor = BODY_COLOR; + protected Color borderColor = BORDER_COLOR; + protected Color nutColor = NUT_COLOR; + protected Color waferColor = WAFER_COLOR; + protected Type type = Type.ThroughHole; + @Deprecated + protected boolean showShaft = false; + protected View view; + private Boolean showMarkers; + private Color markerColor; + // Array of 7 elements: 3 lug connectors, 1 pot body and 3 lugs + transient protected Area[] body = null; + + public PotentiometerPanel() { + controlPoints = new Point2D[] {new Point2D.Double(0, 0), new Point2D.Double(0, 0), new Point2D.Double(0, 0)}; + updateControlPoints(); + } + + protected void updateControlPoints() { + int spacing = (int) this.spacing.convertToPixels(); + switch (orientation) { + case DEFAULT: + controlPoints[1].setLocation(controlPoints[0].getX() + spacing, controlPoints[0].getY()); + controlPoints[2].setLocation(controlPoints[0].getX() + 2 * spacing, controlPoints[0].getY()); + break; + case _90: + controlPoints[1].setLocation(controlPoints[0].getX(), controlPoints[0].getY() + spacing); + controlPoints[2].setLocation(controlPoints[0].getX(), controlPoints[0].getY() + 2 * spacing); + break; + case _180: + controlPoints[1].setLocation(controlPoints[0].getX() - spacing, controlPoints[0].getY()); + controlPoints[2].setLocation(controlPoints[0].getX() - 2 * spacing, controlPoints[0].getY()); + break; + case _270: + controlPoints[1].setLocation(controlPoints[0].getX(), controlPoints[0].getY() - spacing); + controlPoints[2].setLocation(controlPoints[0].getX(), controlPoints[0].getY() - 2 * spacing); + break; + default: + break; + } + } + + public Area[] getBody() { + int spacing = (int) this.spacing.convertToPixels(); + int diameter = getClosestOdd(bodyDiameter.convertToPixels()); + if (body == null) { + // mandatory: 0, 1, 2 pins, 3 body, 9 wafer + // optional: 4, 5, 6 lugs, 7 nut, 8 shaft + body = new Area[13]; + + // Add lugs. + int pinWidth = (int) PIN_SIZE.convertToPixels(); + + double centerX = 0; + double centerY = 0; + + double waferWidth = 2.5 * spacing; + double waferHeight = spacing; + + switch (orientation) { + case DEFAULT: + centerX = controlPoints[0].getX() + spacing; + centerY = controlPoints[0].getY() - spacing / 2 - diameter / 2; + + body[9] = + new Area(new RoundRectangle2D.Double(centerX - waferWidth / 2, controlPoints[0].getY() - waferHeight - spacing + / 2, waferWidth, waferHeight, spacing / 4, spacing / 4)); + + for (int i = 0; i < 3; i++) { + body[i] = + new Area(new Rectangle2D.Double(controlPoints[i].getX() - pinWidth / 2, controlPoints[i].getY() + - (spacing + diameter) / 2, pinWidth, (spacing + diameter) / 2)); + } + break; + case _90: + centerX = controlPoints[0].getX() + spacing / 2 + diameter / 2; + centerY = controlPoints[0].getY() + spacing; + + body[9] = + new Area(new RoundRectangle2D.Double(controlPoints[0].getX() + spacing / 2, centerY - waferWidth / 2, + waferHeight, waferWidth, spacing / 4, spacing / 4)); + + for (int i = 0; i < 3; i++) { + body[i] = + new Area(new Rectangle2D.Double(controlPoints[i].getX(), controlPoints[i].getY() - pinWidth / 2, + (spacing + diameter) / 2, pinWidth)); + } + break; + case _180: + centerX = controlPoints[0].getX() - spacing; + centerY = controlPoints[0].getY() + spacing / 2 + diameter / 2; + + body[9] = + new Area(new RoundRectangle2D.Double(centerX - waferWidth / 2, controlPoints[0].getY() + spacing / 2, + waferWidth, waferHeight, spacing / 4, spacing / 4)); + + for (int i = 0; i < 3; i++) { + body[i] = + new Area(new Rectangle2D.Double(controlPoints[i].getX() - pinWidth / 2, controlPoints[i].getY(), pinWidth, + (spacing + diameter) / 2)); + } + break; + case _270: + centerX = controlPoints[0].getX() - spacing / 2 - diameter / 2; + centerY = controlPoints[0].getY() - spacing; + + body[9] = + new Area(new RoundRectangle2D.Double(controlPoints[0].getX() - waferHeight - spacing / 2, centerY - waferWidth + / 2, waferHeight, waferWidth, spacing / 4, spacing / 4)); + + for (int i = 0; i < 3; i++) { + body[i] = + new Area(new Rectangle2D.Double(controlPoints[i].getX() - (spacing + diameter) / 2, controlPoints[i].getY() + - pinWidth / 2, (spacing + diameter) / 2, pinWidth)); + } + break; + default: + break; + } + + body[3] = new Area(new Ellipse2D.Double(centerX - diameter / 2, centerY - diameter / 2, diameter, diameter)); + + body[9].subtract(body[3]); + + for (int i = 0; i < 3; i++) { + body[i].subtract(body[3]); + } + + if (getType() == Type.ThroughHole) { + int lugDiameter = getClosestOdd(this.lugDiameter.convertToPixels()); + int holeDiameter = getClosestOdd(this.lugDiameter.convertToPixels() / 2); + + for (int i = 0; i < 3; i++) { + Area area = + new Area(new Ellipse2D.Double(controlPoints[i].getX() - lugDiameter / 2, controlPoints[i].getY() - lugDiameter / 2, + lugDiameter, lugDiameter)); + body[4 + i] = area; + body[10 + i] = new Area(area); + } + + for (int i = 0; i < 3; i++) { + for (int j = 0; j < 3; j++) { + body[i].subtract(body[4 + j]); + } + } + // Make holes in the lugs. + for (int i = 0; i < 3; i++) { + body[4 + i].subtract(new Area(new Ellipse2D.Double(controlPoints[i].getX() - holeDiameter / 2, controlPoints[i].getY() + - holeDiameter / 2, holeDiameter, holeDiameter))); + } + } + + if (getView() == View.ShaftUp) { + int nutSize = (int) NUT_SIZE.convertToPixels(); + int shaftSize = (int) SHAFT_SIZE.convertToPixels(); + int[] xPoints = new int[6]; + int[] yPoints = new int[6]; + for (int i = 0; i < 6; i++) { + double alpha = Math.toRadians(60 * i); + xPoints[i] = (int) (centerX + Math.cos(alpha) * nutSize / 2); + yPoints[i] = (int) (centerY + Math.sin(alpha) * nutSize / 2); + } + body[7] = new Area(new Polygon(xPoints, yPoints, 6)); + body[8] = + new Area(new Ellipse2D.Double(centerX - shaftSize / 2, centerY - shaftSize / 2, shaftSize, shaftSize)); + } + } + return body; + } + + @Override + public void setControlPoint(Point2D point, int index) { + super.setControlPoint(point, index); + body = null; + } + + @Override + public void setOrientation(Orientation orientation) { + super.setOrientation(orientation); + updateControlPoints(); + body = null; + } + + @Override + public void draw(Graphics2D g2d, ComponentState componentState, boolean outlineMode, Project project, + IDrawingObserver drawingObserver) { + g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(1)); + Theme theme = (Theme) ConfigurationManager.getInstance().readObject(IPlugInPort.THEME_KEY, Constants.DEFAULT_THEME); + Area[] body = getBody(); + for (int i = 0; i < body.length; i++) { + Area shape = body[i]; + // determine color + if (shape != null) { + switch (i) { + case 7: + g2d.setColor(getNutColor()); + break; + case 9: + g2d.setColor(getWaferColor()); + break; + case 10: + case 11: + case 12: + g2d.setColor(Constants.TRANSPARENT_COLOR); + break; + default: + g2d.setColor(getBodyColor()); + } + + Composite oldComposite = applyAlpha(g2d, componentState); + if (!outlineMode) { + if (i >= 10) + drawingObserver.startTrackingContinuityArea(true); + g2d.fill(shape); + if (i >= 10) + drawingObserver.stopTrackingContinuityArea(); + } + g2d.setComposite(oldComposite); + Color finalBorderColor; + if (outlineMode) { + finalBorderColor = + componentState == ComponentState.SELECTED || componentState == ComponentState.DRAGGING ? SELECTION_COLOR + : theme.getOutlineColor(); + } else { + finalBorderColor = + componentState == ComponentState.SELECTED || componentState == ComponentState.DRAGGING ? SELECTION_COLOR + : getBorderColor(); + } + g2d.setColor(finalBorderColor); + g2d.draw(shape); + } + } + + drawingObserver.stopTracking(); + + // Draw caption. + g2d.setFont(project.getFont()); + + // Override font size + if (getFontSizeOverride() != null) + g2d.setFont(g2d.getFont().deriveFont(1f * getFontSizeOverride())); + + Color finalLabelColor; + if (outlineMode) { + finalLabelColor = + componentState == ComponentState.SELECTED || componentState == ComponentState.DRAGGING ? LABEL_COLOR_SELECTED + : theme.getOutlineColor(); + } else { + finalLabelColor = + componentState == ComponentState.SELECTED || componentState == ComponentState.DRAGGING ? LABEL_COLOR_SELECTED + : LABEL_COLOR; + } + g2d.setColor(finalLabelColor); + FontMetrics fontMetrics = g2d.getFontMetrics(); + Rectangle2D bodyRect = getBody()[3].getBounds2D(); + Rectangle2D rect = fontMetrics.getStringBounds(getName(), g2d); + + int textHeight = (int) rect.getHeight(); + int textWidth = (int) rect.getWidth(); + int panelHeight = (int) bodyRect.getHeight(); + int panelWidth = (int) bodyRect.getWidth(); + + int x = (panelWidth - textWidth) / 2; + int y = panelHeight / 2 - textHeight + fontMetrics.getAscent(); + + g2d.drawString(getName(), (int) (bodyRect.getX() + x), (int) (bodyRect.getY() + y)); + + // Draw value. + rect = fontMetrics.getStringBounds(getValueForDisplay(), g2d); + + textHeight = (int) rect.getHeight(); + textWidth = (int) rect.getWidth(); + + x = (panelWidth - textWidth) / 2; + y = panelHeight / 2 + fontMetrics.getAscent(); + + g2d.drawString(getValueForDisplay(), (int) (bodyRect.getX() + x), (int) (bodyRect.getY() + y)); + + // Draw markers if enabled. + if (getShowMarkers()) { + g2d.setColor(outlineMode ? theme.getOutlineColor() : getMarkerColor()); + + // Get circle center and radius + Rectangle2D circleBounds = body[3].getBounds2D(); + double centerX = circleBounds.getCenterX(); + double centerY = circleBounds.getCenterY(); + double radius = getBodyDiameter().convertToPixels() / 2; + + // Fixed distance from circle edge (inside the circle) + double markerOffset = MARKER_OFFSET.convertToPixels() + 2; + double markerDistance = radius - markerOffset; + + // Draw markers "1", "2", "3" along radial line from center to each lug, close to circle edge + // Reverse numbering when view is ShaftDown + boolean reverseOrder = getView() == View.ShaftDown; + + for (int i = 0; i < 3; i++) { + Point2D lugPoint = controlPoints[i]; + + // Calculate direction from center to lug + double dx = lugPoint.getX() - centerX; + double dy = lugPoint.getY() - centerY; + double distance = Math.sqrt(dx * dx + dy * dy); + + if (distance > 0) { + // Normalize direction vector + double unitX = dx / distance; + double unitY = dy / distance; + + // Position marker at fixed distance from circle edge along radial line + double markerX = centerX + unitX * markerDistance; + double markerY = centerY + unitY * markerDistance; + + // Determine marker number based on view + int markerNumber = reverseOrder ? (3 - i) : (i + 1); + + StringUtils.drawCenteredText(g2d, Integer.toString(markerNumber), markerX, markerY, + HorizontalAlignment.CENTER, VerticalAlignment.CENTER); + } + } + } + } + + @Override + public void drawIcon(Graphics2D g2d, int width, int height) { + int margin = 4 * width / 32; + int waferMargin = 5 * width / 32; + int spacing = width / 3 - 1; + g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(1 * width / 32)); + g2d.setColor(WAFER_COLOR); + g2d.fillRect(waferMargin, height / 2, width - 2 * waferMargin, height / 3); + g2d.setColor(BORDER_COLOR); + g2d.drawRoundRect(waferMargin, height / 2, width - 2 * waferMargin, height / 3, 2 * width / 32, 2 * width / 32); + g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(2 * width / 32)); + g2d.drawLine(width / 2 - spacing, height / 2, width / 2 - spacing, height - margin); + g2d.drawLine(width / 2 + spacing, height / 2, width / 2 + spacing, height - margin); + g2d.drawLine(width / 2, height / 2, width / 2, height - margin); + g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(4 * width / 32)); + g2d.drawLine(width / 2 - spacing, height - margin, width / 2 - spacing, height - margin); + g2d.drawLine(width / 2 + spacing, height - margin, width / 2 + spacing, height - margin); + g2d.drawLine(width / 2, height - margin, width / 2, height - margin); + g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(1)); + g2d.setColor(BODY_COLOR); + g2d.fillOval(margin, margin / 2, width - 2 * margin, height - 2 * margin); + g2d.setColor(BORDER_COLOR); + g2d.drawOval(margin, margin / 2, width - 2 * margin, height - 2 * margin); + } + + @EditableProperty + public Size getSpacing() { + return spacing; + } + + public void setSpacing(Size spacing) { + this.spacing = spacing; + updateControlPoints(); + body = null; + } + + @EditableProperty + public Type getType() { + if (type == null) + type = Type.ThroughHole; + return type; + } + + public void setType(Type type) { + this.type = type; + body = null; + } + + @EditableProperty(name = "Nut") + public Color getNutColor() { + if (nutColor == null) + nutColor = NUT_COLOR; + return nutColor; + } + + public void setNutColor(Color nutColor) { + this.nutColor = nutColor; + } + + @EditableProperty(name = "Diameter") + public Size getBodyDiameter() { + return bodyDiameter; + } + + public void setBodyDiameter(Size bodyDiameter) { + this.bodyDiameter = bodyDiameter; + body = null; + } + + @EditableProperty(name = "Lug Size") + public Size getLugDiameter() { + return lugDiameter; + } + + public void setLugDiameter(Size lugDiameter) { + this.lugDiameter = lugDiameter; + body = null; + } + + @EditableProperty(name = "Body") + public Color getBodyColor() { + return bodyColor; + } + + public void setBodyColor(Color bodyColor) { + this.bodyColor = bodyColor; + } + + @EditableProperty(name = "Border") + public Color getBorderColor() { + return borderColor; + } + + public void setBorderColor(Color borderColor) { + this.borderColor = borderColor; + } + + @EditableProperty(name = "View") + public View getView() { + if (view == null) + view = showShaft ? View.ShaftUp : View.ShaftDown; + return view; + } + + public void setView(View view) { + this.view = view; + body = null; + } + + @EditableProperty(name = "Wafer") + public Color getWaferColor() { + if (waferColor == null) + waferColor = WAFER_COLOR; + return waferColor; + } + + public void setWaferColor(Color waferColor) { + this.waferColor = waferColor; + } + + @EditableProperty(name = "Markers") + public Boolean getShowMarkers() { + if (showMarkers == null) { + showMarkers = false; + } + return showMarkers; + } + + public void setShowMarkers(Boolean showMarkers) { + this.showMarkers = showMarkers; + } + + @EditableProperty(name = "Marker Color") + public Color getMarkerColor() { + if (markerColor == null) { + markerColor = MARKER_COLOR_DEFAULT; + } + return markerColor; + } + + public void setMarkerColor(Color markerColor) { + this.markerColor = markerColor; + } + + @Override + public String getInternalLinkName(int index1, int index2) { + if (index1 > index2) + return getInternalLinkName(index2, index1); + + if (index2 - index1 == 1) + return (index1 + 1) + "-" + (index2 + 1); + + return null; + } + + @Override + public Rectangle2D getCachingBounds() { + Shape[] body = getBody(); + int margin = 20; + double minX = 0; + double minY = 0; + double maxX = 0; + double maxY = 0; + for (Shape a : body) { + if (a != null) { + Rectangle2D bounds2d = a.getBounds2D(); + if (bounds2d.getMinX() < minX) + minX = bounds2d.getMinX(); + if (bounds2d.getMinY() < minY) + minY = bounds2d.getMinY(); + if (bounds2d.getMaxX() > maxX) + maxX = bounds2d.getMaxX(); + if (bounds2d.getMaxY() > maxY) + maxY = bounds2d.getMaxY(); + } + } + return new Rectangle2D.Double(minX - margin, minY - margin, maxX - minX + 2 * margin, maxY - minY + 2 * margin); + } + + @Override + public boolean canPointMoveFreely(int pointIndex) { + return false; + } + + @Override + public int getLayerId() { + return hashCode(); + } + + public enum Type { + ThroughHole("Through Hole"), PCB("PCB"); + + private String value; + + private Type(String value) { + this.value = value; + } + + @Override + public String toString() { + return value; + } + } + + public enum View { + ShaftDown("Shaft Down"), ShaftUp("Shaft Up");//, TerminalsDown, TerminalsUp; + + private String value; + + private View(String value) { + this.value = value; + } + + @Override + public String toString() { + return value; + } + } +} diff --git a/diylc/diylc-library/src/main/java/org/diylc/components/passive/TrimmerPotentiometer.java b/diylc/diylc-library/src/main/java/org/diylc/components/passive/TrimmerPotentiometer.java index bf62f8b62..903b1db1d 100644 --- a/diylc/diylc-library/src/main/java/org/diylc/components/passive/TrimmerPotentiometer.java +++ b/diylc/diylc-library/src/main/java/org/diylc/components/passive/TrimmerPotentiometer.java @@ -376,10 +376,7 @@ public class TrimmerPotentiometer extends AbstractPotentiometer { Theme theme = (Theme) ConfigurationManager.getInstance().readObject(IPlugInPort.THEME_KEY, Constants.DEFAULT_THEME); if (mainShape != null) { g2d.setColor(outlineMode ? Constants.TRANSPARENT_COLOR : bodyColor); - Composite oldComposite = g2d.getComposite(); - if (alpha < MAX_ALPHA) { - g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1f * alpha / MAX_ALPHA)); - } + Composite oldComposite = applyAlpha(g2d, componentState); g2d.fill(mainShape); drawingObserver.stopTracking(); if (!outlineMode && shaftShape != null) { diff --git a/diylc/diylc-library/src/main/java/org/diylc/components/semiconductors/BridgeRectifier.java b/diylc/diylc-library/src/main/java/org/diylc/components/semiconductors/BridgeRectifier.java index cf2d7630a..e4c8296b1 100644 --- a/diylc/diylc-library/src/main/java/org/diylc/components/semiconductors/BridgeRectifier.java +++ b/diylc/diylc-library/src/main/java/org/diylc/components/semiconductors/BridgeRectifier.java @@ -34,12 +34,7 @@ import java.awt.geom.RoundRectangle2D; import org.diylc.appframework.miscutils.ConfigurationManager; import org.diylc.awt.StringUtils; -import org.diylc.common.Display; -import org.diylc.common.HorizontalAlignment; -import org.diylc.common.IPlugInPort; -import org.diylc.common.ObjectCache; -import org.diylc.common.Orientation; -import org.diylc.common.VerticalAlignment; +import org.diylc.common.*; import org.diylc.components.AbstractLabeledComponent; import org.diylc.components.RoundedPolygon; import org.diylc.components.AbstractLeadedComponent.LabelOriantation; @@ -117,7 +112,7 @@ public class BridgeRectifier extends AbstractLabeledComponent implements public BridgeRectifier() { super(); updateControlPoints(); - alpha = 100; + this.alphaPercent = new Percentage(100); } @EditableProperty @@ -380,10 +375,7 @@ public class BridgeRectifier extends AbstractLabeledComponent implements } } - Composite oldComposite = g2d.getComposite(); - if (alpha < MAX_ALPHA) { - g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1f * alpha / MAX_ALPHA)); - } + Composite oldComposite = applyAlpha(g2d, componentState); g2d.setColor(outlineMode ? Constants.TRANSPARENT_COLOR : getBodyColor()); g2d.fill(mainArea); g2d.setComposite(oldComposite); diff --git a/diylc/diylc-library/src/main/java/org/diylc/components/semiconductors/DIL_IC.java b/diylc/diylc-library/src/main/java/org/diylc/components/semiconductors/DIL_IC.java index 09e2cfb58..c40425214 100644 --- a/diylc/diylc-library/src/main/java/org/diylc/components/semiconductors/DIL_IC.java +++ b/diylc/diylc-library/src/main/java/org/diylc/components/semiconductors/DIL_IC.java @@ -322,10 +322,7 @@ public class DIL_IC extends AbstractLabeledComponent implements IGerberC g2d.draw(rect); } } - Composite oldComposite = g2d.getComposite(); - if (alpha < MAX_ALPHA) { - g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1f * alpha / MAX_ALPHA)); - } + Composite oldComposite = applyAlpha(g2d, componentState); g2d.setColor(outlineMode ? Constants.TRANSPARENT_COLOR : getBodyColor()); drawingObserver.startTracking(); g2d.fill(mainArea); diff --git a/diylc/diylc-library/src/main/java/org/diylc/components/semiconductors/ICSymbol.java b/diylc/diylc-library/src/main/java/org/diylc/components/semiconductors/ICSymbol.java index 4958b70b1..c10e570a2 100644 --- a/diylc/diylc-library/src/main/java/org/diylc/components/semiconductors/ICSymbol.java +++ b/diylc/diylc-library/src/main/java/org/diylc/components/semiconductors/ICSymbol.java @@ -1,298 +1,295 @@ -/* - - DIY Layout Creator (DIYLC). - Copyright (c) 2009-2025 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.semiconductors; - -import java.awt.AlphaComposite; -import java.awt.Color; -import java.awt.Composite; -import java.awt.Graphics2D; -import java.awt.Polygon; -import java.awt.Shape; -import java.awt.geom.Area; -import java.awt.geom.GeneralPath; -import java.awt.geom.Point2D; -import java.awt.geom.Rectangle2D; -import org.diylc.appframework.miscutils.ConfigurationManager; - -import org.diylc.awt.StringUtils; -import org.diylc.common.Display; -import org.diylc.common.HorizontalAlignment; -import org.diylc.common.IPlugInPort; -import org.diylc.common.ObjectCache; -import org.diylc.common.VerticalAlignment; -import org.diylc.components.AbstractTransparentComponent; -import org.diylc.core.ComponentState; -import org.diylc.core.IDIYComponent; -import org.diylc.core.IDrawingObserver; -import org.diylc.core.Project; -import org.diylc.core.Theme; -import org.diylc.core.VisibilityPolicy; -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; -import org.diylc.utils.Constants; - -@ComponentDescriptor(name = "IC", author = "Branislav Stojkovic", category = "Schematic Symbols", - instanceNamePrefix = "IC", description = "IC symbol with 3 or 5 contacts", - zOrder = IDIYComponent.COMPONENT, keywordPolicy = KeywordPolicy.SHOW_TAG_AND_VALUE, keywordTag = "Schematic") -public class ICSymbol extends AbstractTransparentComponent { - - private static final long serialVersionUID = 1L; - - public static Size PIN_SPACING = new Size(0.1d, SizeUnit.in); - public static Color BODY_COLOR = Color.white; - public static Color BORDER_COLOR = Color.black; - - protected ICPointCount icPointCount = ICPointCount._5; - protected String value = ""; - protected Point2D[] controlPoints = new Point2D[] {new Point2D.Double(0, 0), new Point2D.Double(0, 0), new Point2D.Double(0, 0), new Point2D.Double(0, 0), - new Point2D.Double(0, 0)}; - protected Color bodyColor = BODY_COLOR; - protected Color borderColor = BORDER_COLOR; - protected Display display = Display.NAME; - transient private Shape[] body; - private Boolean flip; - - public ICSymbol() { - super(); - updateControlPoints(); - } - - @Override - public void draw(Graphics2D g2d, ComponentState componentState, boolean outlineMode, Project project, - IDrawingObserver drawingObserver) { - if (checkPointsClipped(g2d.getClip())) { - return; - } - int pinSpacing = (int) PIN_SPACING.convertToPixels(); - Composite oldComposite = g2d.getComposite(); - if (alpha < MAX_ALPHA) { - g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1f * alpha / MAX_ALPHA)); - } - - Shape[] body = getBody(); - - g2d.setColor(outlineMode ? Constants.TRANSPARENT_COLOR : bodyColor); - g2d.fill(body[0]); - g2d.setComposite(oldComposite); - Color finalBorderColor; - if (outlineMode) { - Theme theme = - (Theme) ConfigurationManager.getInstance().readObject(IPlugInPort.THEME_KEY, Constants.DEFAULT_THEME); - finalBorderColor = theme.getOutlineColor(); - } else { - finalBorderColor = borderColor; - } - g2d.setColor(finalBorderColor); - // Draw contacts - g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(1)); - g2d.draw(body[1]); - // Draw triangle - g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(2)); - g2d.draw(body[0]); - // Draw label - g2d.setFont(project.getFont()); - 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 - : LABEL_COLOR; - } - g2d.setColor(finalLabelColor); - double x = (controlPoints[0].getX() + controlPoints[2].getX()) / 2; - String label = ""; - label = display == Display.VALUE ? getValue() : getName(); - if (display == Display.NONE) { - label = ""; - } - if (display == Display.BOTH) { - label = getName() + " " + (getValue() == null ? "" : getValue().toString()); - } - StringUtils.drawCenteredText(g2d, label, x, controlPoints[0].getY() + pinSpacing, HorizontalAlignment.CENTER, - VerticalAlignment.CENTER); - // Draw +/- markers - StringUtils.drawCenteredText(g2d, getFlip() ? "+" : "-", controlPoints[0].getX() + pinSpacing, controlPoints[0].getY(), HorizontalAlignment.CENTER, - VerticalAlignment.CENTER); - StringUtils.drawCenteredText(g2d, getFlip() ? "-" : "+", controlPoints[1].getX() + pinSpacing, controlPoints[1].getY(), HorizontalAlignment.CENTER, - VerticalAlignment.CENTER); - } - - @Override - public void drawIcon(Graphics2D g2d, int width, int height) { - int margin = 3 * width / 32; - Area area = - new Area(new Polygon(new int[] {margin, margin, width - margin}, - new int[] {margin, height - margin, height / 2}, 3)); - // area.subtract(new Area(new Rectangle2D.Double(0, 0, 2 * margin, - // height))); - area.intersect(new Area(new Rectangle2D.Double(2 * margin, 0, width, height))); - g2d.setColor(BODY_COLOR); - g2d.fill(area); - g2d.setColor(BORDER_COLOR); - g2d.setFont(LABEL_FONT.deriveFont(8f)); - StringUtils.drawCenteredText(g2d, "-", 3 * margin, height / 3, HorizontalAlignment.CENTER, VerticalAlignment.CENTER); - StringUtils.drawCenteredText(g2d, "+", 3 * margin + 1, height * 2 / 3, HorizontalAlignment.CENTER, VerticalAlignment.CENTER); - // g2d.setStroke(new BasicStroke(1f, BasicStroke.CAP_ROUND, - // BasicStroke.JOIN_ROUND)); - g2d.draw(area); - } - - @Override - public Point2D getControlPoint(int index) { - return controlPoints[index]; - } - - @Override - public int getControlPointCount() { - return icPointCount.getValue(); - } - - private void updateControlPoints() { - int pinSpacing = (int) PIN_SPACING.convertToPixels(); - // Update control points. - double x = controlPoints[0].getX(); - double y = controlPoints[0].getY(); - - controlPoints[1].setLocation(x, y + pinSpacing * 2); - controlPoints[2].setLocation(x + pinSpacing * 6, y + pinSpacing); - controlPoints[3].setLocation(x + pinSpacing * 3, y - pinSpacing); - controlPoints[4].setLocation(x + pinSpacing * 3, y + pinSpacing * 3); - } - - public Shape[] getBody() { - if (body == null) { - body = new Shape[2]; - int pinSpacing = (int) PIN_SPACING.convertToPixels(); - int x = (int) controlPoints[0].getX(); - int y = (int) controlPoints[0].getY(); - Shape triangle = - new Polygon(new int[] {x + pinSpacing / 2, x + pinSpacing * 11 / 2, x + pinSpacing / 2}, new int[] { - y - pinSpacing * 3 / 2, y + pinSpacing, y + pinSpacing * 7 / 2}, 3); - body[0] = triangle; - - GeneralPath polyline = new GeneralPath(); - polyline.moveTo(controlPoints[0].getX(), controlPoints[0].getY()); - polyline.lineTo(controlPoints[0].getX() + pinSpacing / 2, controlPoints[0].getY()); - polyline.moveTo(controlPoints[1].getX(), controlPoints[1].getY()); - polyline.lineTo(controlPoints[1].getX() + pinSpacing / 2, controlPoints[1].getY()); - polyline.moveTo(controlPoints[2].getX(), controlPoints[2].getY()); - polyline.lineTo(controlPoints[2].getX() - pinSpacing / 2, controlPoints[2].getY()); - if (icPointCount == ICPointCount._5) { - polyline.moveTo(controlPoints[3].getX(), controlPoints[3].getY()); - polyline.lineTo(controlPoints[3].getX(), controlPoints[3].getY() + pinSpacing * 3 / 4); - polyline.moveTo(controlPoints[4].getX(), controlPoints[4].getY()); - polyline.lineTo(controlPoints[4].getX(), controlPoints[4].getY() - pinSpacing * 3 / 4); - } - body[1] = polyline; - } - return body; - } - - @Override - public VisibilityPolicy getControlPointVisibilityPolicy(int index) { - return VisibilityPolicy.WHEN_SELECTED; - } - - @EditableProperty - @Override - public String getValue() { - return this.value; - } - - @Override - public void setValue(String value) { - this.value = value; - } - - @Override - public boolean isControlPointSticky(int index) { - return true; - } - - @Override - public void setControlPoint(Point2D point, int index) { - controlPoints[index].setLocation(point); - body = null; - } - - @EditableProperty(name = "Contacts") - public ICPointCount getIcPointCount() { - return icPointCount; - } - - public void setIcPointCount(ICPointCount icPointCount) { - this.icPointCount = icPointCount; - updateControlPoints(); - body = null; - } - - @EditableProperty(name = "Body") - public Color getBodyColor() { - return bodyColor; - } - - public void setBodyColor(Color bodyColor) { - this.bodyColor = bodyColor; - } - - @EditableProperty(name = "Border") - public Color getBorderColor() { - return borderColor; - } - - public void setBorderColor(Color borderColor) { - this.borderColor = borderColor; - } - - @EditableProperty - public Boolean getFlip() { - if (flip == null) - flip = false; - return flip; - } - - public void setFlip(Boolean flip) { - this.flip = flip; - } - - @EditableProperty - public Display getDisplay() { - return display; - } - - public void setDisplay(Display display) { - this.display = display; - } - - @Override - public boolean canPointMoveFreely(int pointIndex) { - return false; - } -} +/* + + DIY Layout Creator (DIYLC). + Copyright (c) 2009-2025 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.semiconductors; + +import java.awt.AlphaComposite; +import java.awt.Color; +import java.awt.Composite; +import java.awt.Graphics2D; +import java.awt.Polygon; +import java.awt.Shape; +import java.awt.geom.Area; +import java.awt.geom.GeneralPath; +import java.awt.geom.Point2D; +import java.awt.geom.Rectangle2D; +import org.diylc.appframework.miscutils.ConfigurationManager; + +import org.diylc.awt.StringUtils; +import org.diylc.common.Display; +import org.diylc.common.HorizontalAlignment; +import org.diylc.common.IPlugInPort; +import org.diylc.common.ObjectCache; +import org.diylc.common.VerticalAlignment; +import org.diylc.components.AbstractTransparentComponent; +import org.diylc.core.ComponentState; +import org.diylc.core.IDIYComponent; +import org.diylc.core.IDrawingObserver; +import org.diylc.core.Project; +import org.diylc.core.Theme; +import org.diylc.core.VisibilityPolicy; +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; +import org.diylc.utils.Constants; + +@ComponentDescriptor(name = "IC", author = "Branislav Stojkovic", category = "Schematic Symbols", + instanceNamePrefix = "IC", description = "IC symbol with 3 or 5 contacts", + zOrder = IDIYComponent.COMPONENT, keywordPolicy = KeywordPolicy.SHOW_TAG_AND_VALUE, keywordTag = "Schematic") +public class ICSymbol extends AbstractTransparentComponent { + + private static final long serialVersionUID = 1L; + + public static Size PIN_SPACING = new Size(0.1d, SizeUnit.in); + public static Color BODY_COLOR = Color.white; + public static Color BORDER_COLOR = Color.black; + + protected ICPointCount icPointCount = ICPointCount._5; + protected String value = ""; + protected Point2D[] controlPoints = new Point2D[] {new Point2D.Double(0, 0), new Point2D.Double(0, 0), new Point2D.Double(0, 0), new Point2D.Double(0, 0), + new Point2D.Double(0, 0)}; + protected Color bodyColor = BODY_COLOR; + protected Color borderColor = BORDER_COLOR; + protected Display display = Display.NAME; + transient private Shape[] body; + private Boolean flip; + + public ICSymbol() { + super(); + updateControlPoints(); + } + + @Override + public void draw(Graphics2D g2d, ComponentState componentState, boolean outlineMode, Project project, + IDrawingObserver drawingObserver) { + if (checkPointsClipped(g2d.getClip())) { + return; + } + int pinSpacing = (int) PIN_SPACING.convertToPixels(); + Composite oldComposite = applyAlpha(g2d, componentState); + + Shape[] body = getBody(); + + g2d.setColor(outlineMode ? Constants.TRANSPARENT_COLOR : bodyColor); + g2d.fill(body[0]); + g2d.setComposite(oldComposite); + Color finalBorderColor; + if (outlineMode) { + Theme theme = + (Theme) ConfigurationManager.getInstance().readObject(IPlugInPort.THEME_KEY, Constants.DEFAULT_THEME); + finalBorderColor = theme.getOutlineColor(); + } else { + finalBorderColor = borderColor; + } + g2d.setColor(finalBorderColor); + // Draw contacts + g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(1)); + g2d.draw(body[1]); + // Draw triangle + g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(2)); + g2d.draw(body[0]); + // Draw label + g2d.setFont(project.getFont()); + 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 + : LABEL_COLOR; + } + g2d.setColor(finalLabelColor); + double x = (controlPoints[0].getX() + controlPoints[2].getX()) / 2; + String label = ""; + label = display == Display.VALUE ? getValue() : getName(); + if (display == Display.NONE) { + label = ""; + } + if (display == Display.BOTH) { + label = getName() + " " + (getValue() == null ? "" : getValue().toString()); + } + StringUtils.drawCenteredText(g2d, label, x, controlPoints[0].getY() + pinSpacing, HorizontalAlignment.CENTER, + VerticalAlignment.CENTER); + // Draw +/- markers + StringUtils.drawCenteredText(g2d, getFlip() ? "+" : "-", controlPoints[0].getX() + pinSpacing, controlPoints[0].getY(), HorizontalAlignment.CENTER, + VerticalAlignment.CENTER); + StringUtils.drawCenteredText(g2d, getFlip() ? "-" : "+", controlPoints[1].getX() + pinSpacing, controlPoints[1].getY(), HorizontalAlignment.CENTER, + VerticalAlignment.CENTER); + } + + @Override + public void drawIcon(Graphics2D g2d, int width, int height) { + int margin = 3 * width / 32; + Area area = + new Area(new Polygon(new int[] {margin, margin, width - margin}, + new int[] {margin, height - margin, height / 2}, 3)); + // area.subtract(new Area(new Rectangle2D.Double(0, 0, 2 * margin, + // height))); + area.intersect(new Area(new Rectangle2D.Double(2 * margin, 0, width, height))); + g2d.setColor(BODY_COLOR); + g2d.fill(area); + g2d.setColor(BORDER_COLOR); + g2d.setFont(LABEL_FONT.deriveFont(8f)); + StringUtils.drawCenteredText(g2d, "-", 3 * margin, height / 3, HorizontalAlignment.CENTER, VerticalAlignment.CENTER); + StringUtils.drawCenteredText(g2d, "+", 3 * margin + 1, height * 2 / 3, HorizontalAlignment.CENTER, VerticalAlignment.CENTER); + // g2d.setStroke(new BasicStroke(1f, BasicStroke.CAP_ROUND, + // BasicStroke.JOIN_ROUND)); + g2d.draw(area); + } + + @Override + public Point2D getControlPoint(int index) { + return controlPoints[index]; + } + + @Override + public int getControlPointCount() { + return icPointCount.getValue(); + } + + private void updateControlPoints() { + int pinSpacing = (int) PIN_SPACING.convertToPixels(); + // Update control points. + double x = controlPoints[0].getX(); + double y = controlPoints[0].getY(); + + controlPoints[1].setLocation(x, y + pinSpacing * 2); + controlPoints[2].setLocation(x + pinSpacing * 6, y + pinSpacing); + controlPoints[3].setLocation(x + pinSpacing * 3, y - pinSpacing); + controlPoints[4].setLocation(x + pinSpacing * 3, y + pinSpacing * 3); + } + + public Shape[] getBody() { + if (body == null) { + body = new Shape[2]; + int pinSpacing = (int) PIN_SPACING.convertToPixels(); + int x = (int) controlPoints[0].getX(); + int y = (int) controlPoints[0].getY(); + Shape triangle = + new Polygon(new int[] {x + pinSpacing / 2, x + pinSpacing * 11 / 2, x + pinSpacing / 2}, new int[] { + y - pinSpacing * 3 / 2, y + pinSpacing, y + pinSpacing * 7 / 2}, 3); + body[0] = triangle; + + GeneralPath polyline = new GeneralPath(); + polyline.moveTo(controlPoints[0].getX(), controlPoints[0].getY()); + polyline.lineTo(controlPoints[0].getX() + pinSpacing / 2, controlPoints[0].getY()); + polyline.moveTo(controlPoints[1].getX(), controlPoints[1].getY()); + polyline.lineTo(controlPoints[1].getX() + pinSpacing / 2, controlPoints[1].getY()); + polyline.moveTo(controlPoints[2].getX(), controlPoints[2].getY()); + polyline.lineTo(controlPoints[2].getX() - pinSpacing / 2, controlPoints[2].getY()); + if (icPointCount == ICPointCount._5) { + polyline.moveTo(controlPoints[3].getX(), controlPoints[3].getY()); + polyline.lineTo(controlPoints[3].getX(), controlPoints[3].getY() + pinSpacing * 3 / 4); + polyline.moveTo(controlPoints[4].getX(), controlPoints[4].getY()); + polyline.lineTo(controlPoints[4].getX(), controlPoints[4].getY() - pinSpacing * 3 / 4); + } + body[1] = polyline; + } + return body; + } + + @Override + public VisibilityPolicy getControlPointVisibilityPolicy(int index) { + return VisibilityPolicy.WHEN_SELECTED; + } + + @EditableProperty + @Override + public String getValue() { + return this.value; + } + + @Override + public void setValue(String value) { + this.value = value; + } + + @Override + public boolean isControlPointSticky(int index) { + return true; + } + + @Override + public void setControlPoint(Point2D point, int index) { + controlPoints[index].setLocation(point); + body = null; + } + + @EditableProperty(name = "Contacts") + public ICPointCount getIcPointCount() { + return icPointCount; + } + + public void setIcPointCount(ICPointCount icPointCount) { + this.icPointCount = icPointCount; + updateControlPoints(); + body = null; + } + + @EditableProperty(name = "Body") + public Color getBodyColor() { + return bodyColor; + } + + public void setBodyColor(Color bodyColor) { + this.bodyColor = bodyColor; + } + + @EditableProperty(name = "Border") + public Color getBorderColor() { + return borderColor; + } + + public void setBorderColor(Color borderColor) { + this.borderColor = borderColor; + } + + @EditableProperty + public Boolean getFlip() { + if (flip == null) + flip = false; + return flip; + } + + public void setFlip(Boolean flip) { + this.flip = flip; + } + + @EditableProperty + public Display getDisplay() { + return display; + } + + public void setDisplay(Display display) { + this.display = display; + } + + @Override + public boolean canPointMoveFreely(int pointIndex) { + return false; + } +} diff --git a/diylc/diylc-library/src/main/java/org/diylc/components/semiconductors/LogicGateSymbol.java b/diylc/diylc-library/src/main/java/org/diylc/components/semiconductors/LogicGateSymbol.java index 7fe767d55..0d00c9913 100644 --- a/diylc/diylc-library/src/main/java/org/diylc/components/semiconductors/LogicGateSymbol.java +++ b/diylc/diylc-library/src/main/java/org/diylc/components/semiconductors/LogicGateSymbol.java @@ -82,10 +82,7 @@ public class LogicGateSymbol extends AbstractTransparentComponent { return; } int pinSpacing = (int) PIN_SPACING.convertToPixels(); - Composite oldComposite = g2d.getComposite(); - if (alpha < MAX_ALPHA) { - g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1f * alpha / MAX_ALPHA)); - } + Composite oldComposite = applyAlpha(g2d, componentState); Shape[] body = getBody(); diff --git a/diylc/diylc-library/src/main/java/org/diylc/components/semiconductors/MultiwattIC.java b/diylc/diylc-library/src/main/java/org/diylc/components/semiconductors/MultiwattIC.java index 1da245569..3f574d092 100644 --- a/diylc/diylc-library/src/main/java/org/diylc/components/semiconductors/MultiwattIC.java +++ b/diylc/diylc-library/src/main/java/org/diylc/components/semiconductors/MultiwattIC.java @@ -32,10 +32,7 @@ import java.awt.geom.Point2D; 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.ObjectCache; -import org.diylc.common.Orientation; +import org.diylc.common.*; import org.diylc.components.AbstractTransparentComponent; import org.diylc.core.ComponentState; import org.diylc.core.IDIYComponent; @@ -92,7 +89,7 @@ public class MultiwattIC extends AbstractTransparentComponent implements public MultiwattIC() { super(); updateControlPoints(); - alpha = 100; + this.alphaPercent = new Percentage(100); } @EditableProperty @@ -421,10 +418,7 @@ public class MultiwattIC extends AbstractTransparentComponent implements } drawingObserver.startTracking(); - Composite oldComposite = g2d.getComposite(); - if (alpha < MAX_ALPHA) { - g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1f * alpha / MAX_ALPHA)); - } + Composite oldComposite = applyAlpha(g2d, componentState); g2d.setColor(outlineMode ? Constants.TRANSPARENT_COLOR : getBodyColor()); g2d.fill(mainArea); drawingObserver.stopTracking(); diff --git a/diylc/diylc-library/src/main/java/org/diylc/components/semiconductors/SIL_IC.java b/diylc/diylc-library/src/main/java/org/diylc/components/semiconductors/SIL_IC.java index 7e727344e..bc3be000d 100644 --- a/diylc/diylc-library/src/main/java/org/diylc/components/semiconductors/SIL_IC.java +++ b/diylc/diylc-library/src/main/java/org/diylc/components/semiconductors/SIL_IC.java @@ -1,472 +1,466 @@ -/* - - DIY Layout Creator (DIYLC). - Copyright (c) 2009-2025 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.semiconductors; - -import java.awt.AlphaComposite; -import java.awt.Color; -import java.awt.Composite; -import java.awt.FontMetrics; -import java.awt.Graphics2D; -import java.awt.Rectangle; -import java.awt.geom.Area; -import java.awt.geom.Ellipse2D; -import java.awt.geom.Point2D; -import java.awt.geom.Rectangle2D; -import java.awt.geom.RoundRectangle2D; -import org.diylc.appframework.miscutils.ConfigurationManager; - -import org.diylc.common.Display; -import org.diylc.common.IPlugInPort; -import org.diylc.common.ObjectCache; -import org.diylc.common.Orientation; -import org.diylc.components.AbstractTransparentComponent; -import org.diylc.components.transform.SIL_ICTransformer; -import org.diylc.core.ComponentState; -import org.diylc.core.IDIYComponent; -import org.diylc.core.IDrawingObserver; -import org.diylc.core.Project; -import org.diylc.core.Theme; -import org.diylc.core.VisibilityPolicy; -import org.diylc.core.annotations.ComponentDescriptor; -import org.diylc.core.annotations.EditableProperty; -import org.diylc.core.annotations.KeywordPolicy; -import org.diylc.core.annotations.PositiveNonZeroMeasureValidator; -import org.diylc.core.gerber.IGerberComponentSimple; -import org.diylc.core.measures.Size; -import org.diylc.core.measures.SizeUnit; -import org.diylc.utils.Constants; - -@ComponentDescriptor(name = "SIP IC", author = "Branislav Stojkovic", category = "Semiconductors", - instanceNamePrefix = "IC", description = "Single-in-line package IC", - zOrder = IDIYComponent.COMPONENT, keywordPolicy = KeywordPolicy.SHOW_VALUE, transformer = SIL_ICTransformer.class, - enableCache = true) -public class SIL_IC extends AbstractTransparentComponent implements IGerberComponentSimple { - - private static final long serialVersionUID = 1L; - - public static Color BODY_COLOR = Color.gray; - public static Color BORDER_COLOR = Color.gray.darker(); - public static Color PIN_COLOR = Color.decode("#00B2EE"); - public static Color PIN_BORDER_COLOR = PIN_COLOR.darker(); - public static Color INDENT_COLOR = Color.gray.darker(); - public static Color LABEL_COLOR = Color.white; - public static int EDGE_RADIUS = 6; - public static Size PIN_SIZE = new Size(0.8d, SizeUnit.mm); - public static Size INDENT_SIZE = new Size(0.07d, SizeUnit.in); - public static Size THICKNESS = new Size(0.13d, SizeUnit.in); - - private String value = ""; - private Orientation orientation = Orientation.DEFAULT; - private PinCount pinCount = PinCount._8; - private Size pinSpacing = new Size(0.1d, SizeUnit.in); - private Point2D[] controlPoints = new Point2D[] {new Point2D.Double(0, 0)}; - protected Display display = Display.NAME; - private Color bodyColor = BODY_COLOR; - private Color borderColor = BORDER_COLOR; - private Color labelColor = LABEL_COLOR; - private Color indentColor = INDENT_COLOR; - // new Point(0, pinSpacing.convertToPixels()), - // new Point(0, 2 * pinSpacing.convertToPixels()), - // new Point(0, 3 * pinSpacing.convertToPixels()), - // new Point(3 * pinSpacing.convertToPixels(), 0), - // new Point(3 * pinSpacing.convertToPixels(), - // pinSpacing.convertToPixels()), - // new Point(3 * pinSpacing.convertToPixels(), 2 * - // pinSpacing.convertToPixels()), - // new Point(3 * pinSpacing.convertToPixels(), 3 * - // pinSpacing.convertToPixels()) }; - transient private Area[] body; - - public SIL_IC() { - super(); - updateControlPoints(); - alpha = 100; - } - - @EditableProperty - public String getValue() { - return value; - } - - public void setValue(String value) { - this.value = value; - } - - @EditableProperty - public Orientation getOrientation() { - return orientation; - } - - public void setOrientation(Orientation orientation) { - this.orientation = orientation; - updateControlPoints(); - // Reset body shape. - body = null; - } - - @EditableProperty(name = "Pins") - public PinCount getPinCount() { - return pinCount; - } - - public void setPinCount(PinCount pinCount) { - this.pinCount = pinCount; - updateControlPoints(); - // Reset body shape; - body = null; - } - - @EditableProperty(name = "Pin Spacing", validatorClass = PositiveNonZeroMeasureValidator.class) - public Size getPinSpacing() { - return pinSpacing; - } - - public void setPinSpacing(Size pinSpacing) { - this.pinSpacing = pinSpacing; - updateControlPoints(); - // Reset body shape; - body = null; - } - - @Override - public boolean canPointMoveFreely(int pointIndex) { - return false; - } - - @EditableProperty - public Display getDisplay() { - if (display == null) { - display = Display.VALUE; - } - return display; - } - - public void setDisplay(Display display) { - this.display = display; - } - - @Override - public int getControlPointCount() { - return controlPoints.length; - } - - @Override - public Point2D getControlPoint(int index) { - return controlPoints[index]; - } - - @Override - public boolean isControlPointSticky(int index) { - return true; - } - - @Override - public VisibilityPolicy getControlPointVisibilityPolicy(int index) { - return VisibilityPolicy.NEVER; - } - - @Override - public void setControlPoint(Point2D point, int index) { - controlPoints[index].setLocation(point); - body = null; - } - - private void updateControlPoints() { - Point2D firstPoint = controlPoints[0]; - controlPoints = new Point2D.Double[pinCount.getValue()]; - controlPoints[0] = firstPoint; - double pinSpacing = this.pinSpacing.convertToPixels(); - // Update control points. - double dx1; - double dy1; - for (int i = 0; i < pinCount.getValue(); i++) { - switch (orientation) { - case DEFAULT: - dx1 = 0; - dy1 = i * pinSpacing; - break; - case _90: - dx1 = -i * pinSpacing; - dy1 = 0; - break; - case _180: - dx1 = 0; - dy1 = -i * pinSpacing; - break; - case _270: - dx1 = i * pinSpacing; - dy1 = 0; - break; - default: - throw new RuntimeException("Unexpected orientation: " + orientation); - } - controlPoints[i] = new Point2D.Double((int) (firstPoint.getX() + dx1), (int) (firstPoint.getY() + dy1)); - } - } - - public Area[] getBody() { - if (body == null) { - body = new Area[2]; - double x = controlPoints[0].getX(); - double y = controlPoints[0].getY(); - int thickness = getClosestOdd(THICKNESS.convertToPixels()); - double width; - double height; - double pinSpacing = (int) this.pinSpacing.convertToPixels(); - Area indentation = null; - int indentationSize = getClosestOdd(INDENT_SIZE.convertToPixels()); - switch (orientation) { - case DEFAULT: - width = thickness; - height = pinCount.getValue() * pinSpacing; - x -= thickness / 2; - y -= pinSpacing / 2; - indentation = - new Area(new Ellipse2D.Double(x + width / 2 - indentationSize / 2, y - indentationSize / 2, - indentationSize, indentationSize)); - break; - case _90: - width = pinCount.getValue() * pinSpacing; - height = thickness; - x -= (pinSpacing / 2) + width - pinSpacing; - y -= thickness / 2; - indentation = - new Area(new Ellipse2D.Double(x + width - indentationSize / 2, y + height / 2 - indentationSize / 2, - indentationSize, indentationSize)); - break; - case _180: - width = thickness; - height = pinCount.getValue() * pinSpacing; - x -= thickness / 2; - y -= (pinSpacing / 2) + height - pinSpacing; - indentation = - new Area(new Ellipse2D.Double(x + width / 2 - indentationSize / 2, y + height - indentationSize / 2, - indentationSize, indentationSize)); - break; - case _270: - width = pinCount.getValue() * pinSpacing; - height = thickness; - x -= pinSpacing / 2; - y -= thickness / 2; - indentation = - new Area(new Ellipse2D.Double(x - indentationSize / 2, y + height / 2 - indentationSize / 2, - indentationSize, indentationSize)); - break; - default: - throw new RuntimeException("Unexpected orientation: " + orientation); - } - body[0] = new Area(new RoundRectangle2D.Double(x, y, width, height, EDGE_RADIUS, EDGE_RADIUS)); - body[1] = indentation; - if (indentation != null) { - indentation.intersect(body[0]); - } - } - return body; - } - - @Override - public void draw(Graphics2D g2d, ComponentState componentState, boolean outlineMode, Project project, - IDrawingObserver drawingObserver) { - if (checkPointsClipped(g2d.getClip())) { - return; - } - Area mainArea = getBody()[0]; - - g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(1f)); - if (!outlineMode) { - int pinSize = (int) PIN_SIZE.convertToPixels() / 2 * 2; - for (Point2D point : controlPoints) { - g2d.setColor(PIN_COLOR); - g2d.fillOval((int)(point.getX() - pinSize / 2), (int)(point.getY() - pinSize / 2), pinSize, pinSize); - g2d.setColor(PIN_BORDER_COLOR); - g2d.drawOval((int)(point.getX() - pinSize / 2), (int)(point.getY() - pinSize / 2), pinSize, pinSize); - } - } - - 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 : getBodyColor()); - g2d.fill(mainArea); - drawingObserver.stopTracking(); - 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 - : getBorderColor(); - } - g2d.setColor(finalBorderColor); - g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(1)); - if (outlineMode) { - Area area = new Area(mainArea); - area.subtract(getBody()[1]); - g2d.draw(area); - } else { - g2d.draw(mainArea); - if (getBody()[1] != null) { - g2d.setColor(getIndentColor()); - g2d.fill(getBody()[1]); - } - } - // Draw label. - g2d.setFont(project.getFont()); - 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 - : getLabelColor(); - } - g2d.setColor(finalLabelColor); - FontMetrics fontMetrics = g2d.getFontMetrics(g2d.getFont()); - String label = ""; - label = (getDisplay() == Display.NAME) ? getName() : getValue(); - if (getDisplay() == Display.NONE) { - label = ""; - } - if (getDisplay() == Display.BOTH) { - label = getName() + " " + (getValue() == null ? "" : getValue().toString()); - } - Rectangle2D rect = fontMetrics.getStringBounds(label, g2d); - int textHeight = (int) (rect.getHeight()); - int textWidth = (int) (rect.getWidth()); - // Center text horizontally and vertically - Rectangle bounds = mainArea.getBounds(); - int x = (int) (bounds.getX() + (bounds.width - textWidth) / 2); - int y = (int) (bounds.getY() + (bounds.height - textHeight) / 2 + fontMetrics.getAscent()); - g2d.drawString(label, x, y); - } - - @Override - public void drawIcon(Graphics2D g2d, int width, int height) { - int radius = 6 * width / 32; - int thickness = getClosestOdd(width / 3); - g2d.rotate(Math.PI / 4, width / 2, height / 2); - g2d.setColor(BODY_COLOR); - g2d.fillRoundRect((width - thickness) / 2, 0, thickness, height, radius, radius); - g2d.setColor(BORDER_COLOR); - g2d.drawRoundRect((width - thickness) / 2, 0, thickness, height, radius, radius); - int pinSize = 2 * width / 32; - g2d.setColor(PIN_COLOR); - for (int i = 0; i < 4; i++) { - g2d.fillOval(width / 2 - pinSize / 2, (height / 5) * (i + 1), pinSize, pinSize); - } - } - - @EditableProperty(name = "Body") - public Color getBodyColor() { - if (bodyColor == null) { - bodyColor = BODY_COLOR; - } - return bodyColor; - } - - public void setBodyColor(Color bodyColor) { - this.bodyColor = bodyColor; - } - - @EditableProperty(name = "Border") - public Color getBorderColor() { - if (borderColor == null) { - borderColor = BORDER_COLOR; - } - return borderColor; - } - - public void setBorderColor(Color borderColor) { - this.borderColor = borderColor; - } - - @EditableProperty(name = "Label") - public Color getLabelColor() { - if (labelColor == null) { - labelColor = LABEL_COLOR; - } - return labelColor; - } - - public void setLabelColor(Color labelColor) { - this.labelColor = labelColor; - } - - @EditableProperty(name = "Indent") - public Color getIndentColor() { - if (indentColor == null) { - indentColor = INDENT_COLOR; - } - return indentColor; - } - - public void setIndentColor(Color indentColor) { - this.indentColor = indentColor; - } - - @Override - public Rectangle2D getCachingBounds() { - double minX = Integer.MAX_VALUE; - double maxX = Integer.MIN_VALUE; - double minY = Integer.MAX_VALUE; - double maxY = Integer.MIN_VALUE; - int margin = 50; - for (int i = 0; i < getControlPointCount(); i++) { - Point2D p = getControlPoint(i); - if (p.getX() < minX) - minX = p.getX(); - if (p.getX() > maxX) - maxX = p.getX(); - if (p.getY() < minY) - minY = p.getY(); - if (p.getY() > maxY) - maxY = p.getY(); - } - - return new Rectangle2D.Double(minX - margin, minY - margin, maxX - minX + 2 * margin, maxY - minY + 2 * margin); - } - - public static enum PinCount { - - _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20; - - @Override - public String toString() { - return name().replace("_", ""); - } - - public int getValue() { - return Integer.parseInt(toString()); - } - } -} +/* + + DIY Layout Creator (DIYLC). + Copyright (c) 2009-2025 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.semiconductors; + +import java.awt.AlphaComposite; +import java.awt.Color; +import java.awt.Composite; +import java.awt.FontMetrics; +import java.awt.Graphics2D; +import java.awt.Rectangle; +import java.awt.geom.Area; +import java.awt.geom.Ellipse2D; +import java.awt.geom.Point2D; +import java.awt.geom.Rectangle2D; +import java.awt.geom.RoundRectangle2D; +import org.diylc.appframework.miscutils.ConfigurationManager; + +import org.diylc.common.*; +import org.diylc.components.AbstractTransparentComponent; +import org.diylc.components.transform.SIL_ICTransformer; +import org.diylc.core.ComponentState; +import org.diylc.core.IDIYComponent; +import org.diylc.core.IDrawingObserver; +import org.diylc.core.Project; +import org.diylc.core.Theme; +import org.diylc.core.VisibilityPolicy; +import org.diylc.core.annotations.ComponentDescriptor; +import org.diylc.core.annotations.EditableProperty; +import org.diylc.core.annotations.KeywordPolicy; +import org.diylc.core.annotations.PositiveNonZeroMeasureValidator; +import org.diylc.core.gerber.IGerberComponentSimple; +import org.diylc.core.measures.Size; +import org.diylc.core.measures.SizeUnit; +import org.diylc.utils.Constants; + +@ComponentDescriptor(name = "SIP IC", author = "Branislav Stojkovic", category = "Semiconductors", + instanceNamePrefix = "IC", description = "Single-in-line package IC", + zOrder = IDIYComponent.COMPONENT, keywordPolicy = KeywordPolicy.SHOW_VALUE, transformer = SIL_ICTransformer.class, + enableCache = true) +public class SIL_IC extends AbstractTransparentComponent implements IGerberComponentSimple { + + private static final long serialVersionUID = 1L; + + public static Color BODY_COLOR = Color.gray; + public static Color BORDER_COLOR = Color.gray.darker(); + public static Color PIN_COLOR = Color.decode("#00B2EE"); + public static Color PIN_BORDER_COLOR = PIN_COLOR.darker(); + public static Color INDENT_COLOR = Color.gray.darker(); + public static Color LABEL_COLOR = Color.white; + public static int EDGE_RADIUS = 6; + public static Size PIN_SIZE = new Size(0.8d, SizeUnit.mm); + public static Size INDENT_SIZE = new Size(0.07d, SizeUnit.in); + public static Size THICKNESS = new Size(0.13d, SizeUnit.in); + + private String value = ""; + private Orientation orientation = Orientation.DEFAULT; + private PinCount pinCount = PinCount._8; + private Size pinSpacing = new Size(0.1d, SizeUnit.in); + private Point2D[] controlPoints = new Point2D[] {new Point2D.Double(0, 0)}; + protected Display display = Display.NAME; + private Color bodyColor = BODY_COLOR; + private Color borderColor = BORDER_COLOR; + private Color labelColor = LABEL_COLOR; + private Color indentColor = INDENT_COLOR; + // new Point(0, pinSpacing.convertToPixels()), + // new Point(0, 2 * pinSpacing.convertToPixels()), + // new Point(0, 3 * pinSpacing.convertToPixels()), + // new Point(3 * pinSpacing.convertToPixels(), 0), + // new Point(3 * pinSpacing.convertToPixels(), + // pinSpacing.convertToPixels()), + // new Point(3 * pinSpacing.convertToPixels(), 2 * + // pinSpacing.convertToPixels()), + // new Point(3 * pinSpacing.convertToPixels(), 3 * + // pinSpacing.convertToPixels()) }; + transient private Area[] body; + + public SIL_IC() { + super(); + updateControlPoints(); + this.alphaPercent = new Percentage(100); + } + + @EditableProperty + public String getValue() { + return value; + } + + public void setValue(String value) { + this.value = value; + } + + @EditableProperty + public Orientation getOrientation() { + return orientation; + } + + public void setOrientation(Orientation orientation) { + this.orientation = orientation; + updateControlPoints(); + // Reset body shape. + body = null; + } + + @EditableProperty(name = "Pins") + public PinCount getPinCount() { + return pinCount; + } + + public void setPinCount(PinCount pinCount) { + this.pinCount = pinCount; + updateControlPoints(); + // Reset body shape; + body = null; + } + + @EditableProperty(name = "Pin Spacing", validatorClass = PositiveNonZeroMeasureValidator.class) + public Size getPinSpacing() { + return pinSpacing; + } + + public void setPinSpacing(Size pinSpacing) { + this.pinSpacing = pinSpacing; + updateControlPoints(); + // Reset body shape; + body = null; + } + + @Override + public boolean canPointMoveFreely(int pointIndex) { + return false; + } + + @EditableProperty + public Display getDisplay() { + if (display == null) { + display = Display.VALUE; + } + return display; + } + + public void setDisplay(Display display) { + this.display = display; + } + + @Override + public int getControlPointCount() { + return controlPoints.length; + } + + @Override + public Point2D getControlPoint(int index) { + return controlPoints[index]; + } + + @Override + public boolean isControlPointSticky(int index) { + return true; + } + + @Override + public VisibilityPolicy getControlPointVisibilityPolicy(int index) { + return VisibilityPolicy.NEVER; + } + + @Override + public void setControlPoint(Point2D point, int index) { + controlPoints[index].setLocation(point); + body = null; + } + + private void updateControlPoints() { + Point2D firstPoint = controlPoints[0]; + controlPoints = new Point2D.Double[pinCount.getValue()]; + controlPoints[0] = firstPoint; + double pinSpacing = this.pinSpacing.convertToPixels(); + // Update control points. + double dx1; + double dy1; + for (int i = 0; i < pinCount.getValue(); i++) { + switch (orientation) { + case DEFAULT: + dx1 = 0; + dy1 = i * pinSpacing; + break; + case _90: + dx1 = -i * pinSpacing; + dy1 = 0; + break; + case _180: + dx1 = 0; + dy1 = -i * pinSpacing; + break; + case _270: + dx1 = i * pinSpacing; + dy1 = 0; + break; + default: + throw new RuntimeException("Unexpected orientation: " + orientation); + } + controlPoints[i] = new Point2D.Double((int) (firstPoint.getX() + dx1), (int) (firstPoint.getY() + dy1)); + } + } + + public Area[] getBody() { + if (body == null) { + body = new Area[2]; + double x = controlPoints[0].getX(); + double y = controlPoints[0].getY(); + int thickness = getClosestOdd(THICKNESS.convertToPixels()); + double width; + double height; + double pinSpacing = (int) this.pinSpacing.convertToPixels(); + Area indentation = null; + int indentationSize = getClosestOdd(INDENT_SIZE.convertToPixels()); + switch (orientation) { + case DEFAULT: + width = thickness; + height = pinCount.getValue() * pinSpacing; + x -= thickness / 2; + y -= pinSpacing / 2; + indentation = + new Area(new Ellipse2D.Double(x + width / 2 - indentationSize / 2, y - indentationSize / 2, + indentationSize, indentationSize)); + break; + case _90: + width = pinCount.getValue() * pinSpacing; + height = thickness; + x -= (pinSpacing / 2) + width - pinSpacing; + y -= thickness / 2; + indentation = + new Area(new Ellipse2D.Double(x + width - indentationSize / 2, y + height / 2 - indentationSize / 2, + indentationSize, indentationSize)); + break; + case _180: + width = thickness; + height = pinCount.getValue() * pinSpacing; + x -= thickness / 2; + y -= (pinSpacing / 2) + height - pinSpacing; + indentation = + new Area(new Ellipse2D.Double(x + width / 2 - indentationSize / 2, y + height - indentationSize / 2, + indentationSize, indentationSize)); + break; + case _270: + width = pinCount.getValue() * pinSpacing; + height = thickness; + x -= pinSpacing / 2; + y -= thickness / 2; + indentation = + new Area(new Ellipse2D.Double(x - indentationSize / 2, y + height / 2 - indentationSize / 2, + indentationSize, indentationSize)); + break; + default: + throw new RuntimeException("Unexpected orientation: " + orientation); + } + body[0] = new Area(new RoundRectangle2D.Double(x, y, width, height, EDGE_RADIUS, EDGE_RADIUS)); + body[1] = indentation; + if (indentation != null) { + indentation.intersect(body[0]); + } + } + return body; + } + + @Override + public void draw(Graphics2D g2d, ComponentState componentState, boolean outlineMode, Project project, + IDrawingObserver drawingObserver) { + if (checkPointsClipped(g2d.getClip())) { + return; + } + Area mainArea = getBody()[0]; + + g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(1f)); + if (!outlineMode) { + int pinSize = (int) PIN_SIZE.convertToPixels() / 2 * 2; + for (Point2D point : controlPoints) { + g2d.setColor(PIN_COLOR); + g2d.fillOval((int)(point.getX() - pinSize / 2), (int)(point.getY() - pinSize / 2), pinSize, pinSize); + g2d.setColor(PIN_BORDER_COLOR); + g2d.drawOval((int)(point.getX() - pinSize / 2), (int)(point.getY() - pinSize / 2), pinSize, pinSize); + } + } + + Composite oldComposite = applyAlpha(g2d, componentState); + g2d.setColor(outlineMode ? Constants.TRANSPARENT_COLOR : getBodyColor()); + g2d.fill(mainArea); + drawingObserver.stopTracking(); + 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 + : getBorderColor(); + } + g2d.setColor(finalBorderColor); + g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(1)); + if (outlineMode) { + Area area = new Area(mainArea); + area.subtract(getBody()[1]); + g2d.draw(area); + } else { + g2d.draw(mainArea); + if (getBody()[1] != null) { + g2d.setColor(getIndentColor()); + g2d.fill(getBody()[1]); + } + } + // Draw label. + g2d.setFont(project.getFont()); + 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 + : getLabelColor(); + } + g2d.setColor(finalLabelColor); + FontMetrics fontMetrics = g2d.getFontMetrics(g2d.getFont()); + String label = ""; + label = (getDisplay() == Display.NAME) ? getName() : getValue(); + if (getDisplay() == Display.NONE) { + label = ""; + } + if (getDisplay() == Display.BOTH) { + label = getName() + " " + (getValue() == null ? "" : getValue().toString()); + } + Rectangle2D rect = fontMetrics.getStringBounds(label, g2d); + int textHeight = (int) (rect.getHeight()); + int textWidth = (int) (rect.getWidth()); + // Center text horizontally and vertically + Rectangle bounds = mainArea.getBounds(); + int x = (int) (bounds.getX() + (bounds.width - textWidth) / 2); + int y = (int) (bounds.getY() + (bounds.height - textHeight) / 2 + fontMetrics.getAscent()); + g2d.drawString(label, x, y); + } + + @Override + public void drawIcon(Graphics2D g2d, int width, int height) { + int radius = 6 * width / 32; + int thickness = getClosestOdd(width / 3); + g2d.rotate(Math.PI / 4, width / 2, height / 2); + g2d.setColor(BODY_COLOR); + g2d.fillRoundRect((width - thickness) / 2, 0, thickness, height, radius, radius); + g2d.setColor(BORDER_COLOR); + g2d.drawRoundRect((width - thickness) / 2, 0, thickness, height, radius, radius); + int pinSize = 2 * width / 32; + g2d.setColor(PIN_COLOR); + for (int i = 0; i < 4; i++) { + g2d.fillOval(width / 2 - pinSize / 2, (height / 5) * (i + 1), pinSize, pinSize); + } + } + + @EditableProperty(name = "Body") + public Color getBodyColor() { + if (bodyColor == null) { + bodyColor = BODY_COLOR; + } + return bodyColor; + } + + public void setBodyColor(Color bodyColor) { + this.bodyColor = bodyColor; + } + + @EditableProperty(name = "Border") + public Color getBorderColor() { + if (borderColor == null) { + borderColor = BORDER_COLOR; + } + return borderColor; + } + + public void setBorderColor(Color borderColor) { + this.borderColor = borderColor; + } + + @EditableProperty(name = "Label") + public Color getLabelColor() { + if (labelColor == null) { + labelColor = LABEL_COLOR; + } + return labelColor; + } + + public void setLabelColor(Color labelColor) { + this.labelColor = labelColor; + } + + @EditableProperty(name = "Indent") + public Color getIndentColor() { + if (indentColor == null) { + indentColor = INDENT_COLOR; + } + return indentColor; + } + + public void setIndentColor(Color indentColor) { + this.indentColor = indentColor; + } + + @Override + public Rectangle2D getCachingBounds() { + double minX = Integer.MAX_VALUE; + double maxX = Integer.MIN_VALUE; + double minY = Integer.MAX_VALUE; + double maxY = Integer.MIN_VALUE; + int margin = 50; + for (int i = 0; i < getControlPointCount(); i++) { + Point2D p = getControlPoint(i); + if (p.getX() < minX) + minX = p.getX(); + if (p.getX() > maxX) + maxX = p.getX(); + if (p.getY() < minY) + minY = p.getY(); + if (p.getY() > maxY) + maxY = p.getY(); + } + + return new Rectangle2D.Double(minX - margin, minY - margin, maxX - minX + 2 * margin, maxY - minY + 2 * margin); + } + + public static enum PinCount { + + _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20; + + @Override + public String toString() { + return name().replace("_", ""); + } + + public int getValue() { + return Integer.parseInt(toString()); + } + } +} diff --git a/diylc/diylc-library/src/main/java/org/diylc/components/semiconductors/TransistorTO1.java b/diylc/diylc-library/src/main/java/org/diylc/components/semiconductors/TransistorTO1.java index 4a1b01900..4d9631ea5 100644 --- a/diylc/diylc-library/src/main/java/org/diylc/components/semiconductors/TransistorTO1.java +++ b/diylc/diylc-library/src/main/java/org/diylc/components/semiconductors/TransistorTO1.java @@ -1,280 +1,278 @@ -/* - - DIY Layout Creator (DIYLC). - Copyright (c) 2009-2025 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.semiconductors; - -import java.awt.AlphaComposite; -import java.awt.Color; -import java.awt.Composite; -import java.awt.FontMetrics; -import java.awt.Graphics2D; -import java.awt.Rectangle; -import java.awt.Shape; -import java.awt.geom.Area; -import java.awt.geom.Ellipse2D; -import java.awt.geom.Point2D; -import java.awt.geom.Rectangle2D; -import java.awt.geom.RoundRectangle2D; -import org.diylc.appframework.miscutils.ConfigurationManager; - -import org.diylc.common.IPlugInPort; -import org.diylc.common.ObjectCache; -import org.diylc.components.transform.TO1Transformer; -import org.diylc.core.ComponentState; -import org.diylc.core.IDIYComponent; -import org.diylc.core.IDrawingObserver; -import org.diylc.core.Project; -import org.diylc.core.Theme; -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; -import org.diylc.utils.Constants; - -@ComponentDescriptor(name = "Transistor (TO-1)", author = "Branislav Stojkovic", category = "Semiconductors", - instanceNamePrefix = "Q", description = "Transistor with small metal body", - zOrder = IDIYComponent.COMPONENT, keywordPolicy = KeywordPolicy.SHOW_VALUE, transformer = TO1Transformer.class, - enableCache = true) -public class TransistorTO1 extends AbstractTransistorPackage { - - private static final long serialVersionUID = 1L; - - public static Color BODY_COLOR = Color.lightGray; - public static Color BORDER_COLOR = BODY_COLOR.darker(); - public static Color PIN_COLOR = Color.decode("#00B2EE"); - public static Color PIN_BORDER_COLOR = PIN_COLOR.darker(); - public static Color LABEL_COLOR = Color.black; - public static Size PIN_SIZE = new Size(0.03d, SizeUnit.in); - public static Size PIN_SPACING = new Size(0.05d, SizeUnit.in); - public static Size BODY_DIAMETER = new Size(0.24d, SizeUnit.in); - public static Size BODY_LENGTH = new Size(0.4d, SizeUnit.in); - public static Size EDGE_RADIUS = new Size(2d, SizeUnit.mm); - - private Size pinSpacing = PIN_SPACING; - - public TransistorTO1() { - super(); - updateControlPoints(); - alpha = (byte) 100; - bodyColor = BODY_COLOR; - borderColor = BORDER_COLOR; - } - - @Override - protected void updateControlPoints() { - int pinSpacing = (int) getPinSpacing().convertToPixels(); - // Update control points. - double x = controlPoints[0].getX(); - double y = controlPoints[0].getY(); - switch (orientation) { - case DEFAULT: - controlPoints[1].setLocation(x - (folded ? 0 : pinSpacing), y + pinSpacing); - controlPoints[2].setLocation(x, y + 2 * pinSpacing); - break; - case _90: - controlPoints[1].setLocation(x - pinSpacing, y - (folded ? 0 : pinSpacing)); - controlPoints[2].setLocation(x - 2 * pinSpacing, y); - break; - case _180: - controlPoints[1].setLocation(x + (folded ? 0 : pinSpacing), y - pinSpacing); - controlPoints[2].setLocation(x, y - 2 * pinSpacing); - break; - case _270: - controlPoints[1].setLocation(x + pinSpacing, y + (folded ? 0 : pinSpacing)); - controlPoints[2].setLocation(x + 2 * pinSpacing, y); - break; - default: - throw new RuntimeException("Unexpected orientation: " + orientation); - } - } - - public Area[] getBody() { - if (body == null) { - double x = (controlPoints[0].getX() + controlPoints[1].getX() + controlPoints[2].getX()) / 3; - double y = (controlPoints[0].getY() + controlPoints[1].getY() + controlPoints[2].getY()) / 3; - int bodyDiameter = getClosestOdd(BODY_DIAMETER.convertToPixels()); - int bodyLength = getClosestOdd(BODY_LENGTH.convertToPixels()); - int edgeRadius = (int) EDGE_RADIUS.convertToPixels(); - - Area newBody = null; - - if (folded) { - switch (orientation) { - case DEFAULT: - newBody = - new Area(new RoundRectangle2D.Double(x, y - bodyDiameter / 2, bodyLength, bodyDiameter, edgeRadius, - edgeRadius)); - newBody.add(new Area(new Rectangle2D.Double(x, y - bodyDiameter / 2, bodyLength / 2, bodyDiameter))); - break; - case _90: - newBody = - new Area(new RoundRectangle2D.Double(x - bodyDiameter / 2, y, bodyDiameter, bodyLength, edgeRadius, - edgeRadius)); - newBody.add(new Area(new Rectangle2D.Double(x - bodyDiameter / 2, y, bodyDiameter, bodyLength / 2))); - break; - case _180: - newBody = - new Area(new RoundRectangle2D.Double(x - bodyLength, y - bodyDiameter / 2, bodyLength, bodyDiameter, - edgeRadius, edgeRadius)); - newBody.add(new Area(new Rectangle2D.Double(x - bodyLength / 2, y - bodyDiameter / 2, bodyLength / 2, - bodyDiameter))); - - break; - case _270: - newBody = - new Area(new RoundRectangle2D.Double(x - bodyDiameter / 2, y - bodyLength, bodyDiameter, bodyLength, - edgeRadius, edgeRadius)); - newBody.add(new Area(new Rectangle2D.Double(x - bodyDiameter / 2, y - bodyLength / 2, bodyDiameter, - bodyLength / 2))); - break; - default: - throw new RuntimeException("Unexpected orientation: " + orientation); - } - } else { - newBody = new Area(new Ellipse2D.Double(x - bodyDiameter / 2, y - bodyDiameter / 2, bodyDiameter, bodyDiameter)); - } - - body = new Area[] { newBody }; - } - return body; - } - - @Override - public void draw(Graphics2D g2d, ComponentState componentState, boolean outlineMode, Project project, - IDrawingObserver drawingObserver) { - - drawingObserver.stopTracking(); - if (checkPointsClipped(g2d.getClip())) { - return; - } - int pinSize = (int) PIN_SIZE.convertToPixels() / 2 * 2; - Theme theme = (Theme) ConfigurationManager.getInstance().readObject(IPlugInPort.THEME_KEY, Constants.DEFAULT_THEME); - - g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(1f)); - for (Point2D point : controlPoints) { - Shape shape = new Ellipse2D.Double(point.getX() - pinSize / 2, point.getY() - pinSize / 2, pinSize, pinSize); - if (!outlineMode) { - g2d.setColor(PIN_COLOR); - g2d.fill(shape); - } - g2d.setColor(outlineMode ? theme.getOutlineColor() : PIN_BORDER_COLOR); - g2d.draw(shape); - } - - Area mainArea = getBody()[0]; - 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 : bodyColor); - drawingObserver.startTracking(); - g2d.fill(mainArea); - drawingObserver.stopTracking(); - g2d.setComposite(oldComposite); - Color finalBorderColor; - - if (outlineMode) { - 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.setStroke(ObjectCache.getInstance().fetchBasicStroke(1)); - g2d.draw(mainArea); - - // Draw label. - g2d.setFont(project.getFont()); - - // Override font size - if (getFontSizeOverride() != null) - g2d.setFont(g2d.getFont().deriveFont(1f * getFontSizeOverride())); - - Color finalLabelColor; - if (outlineMode) { - finalLabelColor = - componentState == ComponentState.SELECTED || componentState == ComponentState.DRAGGING ? LABEL_COLOR_SELECTED - : theme.getOutlineColor(); - } else { - finalLabelColor = - componentState == ComponentState.SELECTED || componentState == ComponentState.DRAGGING ? LABEL_COLOR_SELECTED - : getLabelColor(); - } - g2d.setColor(finalLabelColor); - if (getDisplay() == TransistorDisplay.PINOUT) { - drawPinout(g2d); - } else { - String label = ""; - label = (getDisplay() == TransistorDisplay.NAME) ? getName() : getValue(); - if (getDisplay() == TransistorDisplay.NONE) { - label = ""; - } - if (getDisplay() == TransistorDisplay.BOTH) { - label = getName() + " " + (getValue() == null ? "" : getValue().toString()); - } - FontMetrics fontMetrics = g2d.getFontMetrics(g2d.getFont()); - Rectangle2D rect = fontMetrics.getStringBounds(label, g2d); - int textHeight = (int) (rect.getHeight()); - int textWidth = (int) (rect.getWidth()); - // Center text horizontally and vertically - Rectangle bounds = mainArea.getBounds(); - int x = (int) (bounds.getX() + (bounds.width - textWidth) / 2); - int y = (int) (bounds.getY() + (bounds.height - textHeight) / 2 + fontMetrics.getAscent()); - g2d.drawString(label, x, y); - } - } - - @Override - public void drawIcon(Graphics2D g2d, int width, int height) { - int margin = (int) (2f * width / 32); - Area area = new Area(new Ellipse2D.Double(margin / 2, margin, width - 2 * margin, width - 2 * margin)); - g2d.setColor(BODY_COLOR); - g2d.fill(area); - g2d.setColor(BORDER_COLOR); - g2d.draw(area); - g2d.setColor(PIN_COLOR); - int pinSize = 2 * width / 32; - for (int i = 0; i < 3; i++) { - g2d.fillOval((i == 1 ? width * 3 / 8 : width / 2) - pinSize / 2, (height / 4) * (i + 1), pinSize, pinSize); - } - } - - @EditableProperty(name = "Pin spacing") - public Size getPinSpacing() { - return pinSpacing; - } - - public void setPinSpacing(Size pinSpacing) { - this.pinSpacing = pinSpacing; - updateControlPoints(); - // Reset body shape; - body = null; - } - - @Override - protected boolean flipPinoutLabel() { - return true; - } -} +/* + + DIY Layout Creator (DIYLC). + Copyright (c) 2009-2025 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.semiconductors; + +import java.awt.AlphaComposite; +import java.awt.Color; +import java.awt.Composite; +import java.awt.FontMetrics; +import java.awt.Graphics2D; +import java.awt.Rectangle; +import java.awt.Shape; +import java.awt.geom.Area; +import java.awt.geom.Ellipse2D; +import java.awt.geom.Point2D; +import java.awt.geom.Rectangle2D; +import java.awt.geom.RoundRectangle2D; +import org.diylc.appframework.miscutils.ConfigurationManager; + +import org.diylc.common.IPlugInPort; +import org.diylc.common.ObjectCache; +import org.diylc.common.Percentage; +import org.diylc.components.transform.TO1Transformer; +import org.diylc.core.ComponentState; +import org.diylc.core.IDIYComponent; +import org.diylc.core.IDrawingObserver; +import org.diylc.core.Project; +import org.diylc.core.Theme; +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; +import org.diylc.utils.Constants; + +@ComponentDescriptor(name = "Transistor (TO-1)", author = "Branislav Stojkovic", category = "Semiconductors", + instanceNamePrefix = "Q", description = "Transistor with small metal body", + zOrder = IDIYComponent.COMPONENT, keywordPolicy = KeywordPolicy.SHOW_VALUE, transformer = TO1Transformer.class, + enableCache = true) +public class TransistorTO1 extends AbstractTransistorPackage { + + private static final long serialVersionUID = 1L; + + public static Color BODY_COLOR = Color.lightGray; + public static Color BORDER_COLOR = BODY_COLOR.darker(); + public static Color PIN_COLOR = Color.decode("#00B2EE"); + public static Color PIN_BORDER_COLOR = PIN_COLOR.darker(); + public static Color LABEL_COLOR = Color.black; + public static Size PIN_SIZE = new Size(0.03d, SizeUnit.in); + public static Size PIN_SPACING = new Size(0.05d, SizeUnit.in); + public static Size BODY_DIAMETER = new Size(0.24d, SizeUnit.in); + public static Size BODY_LENGTH = new Size(0.4d, SizeUnit.in); + public static Size EDGE_RADIUS = new Size(2d, SizeUnit.mm); + + private Size pinSpacing = PIN_SPACING; + + public TransistorTO1() { + super(); + updateControlPoints(); + this.alphaPercent = new Percentage(100); + bodyColor = BODY_COLOR; + borderColor = BORDER_COLOR; + } + + @Override + protected void updateControlPoints() { + int pinSpacing = (int) getPinSpacing().convertToPixels(); + // Update control points. + double x = controlPoints[0].getX(); + double y = controlPoints[0].getY(); + switch (orientation) { + case DEFAULT: + controlPoints[1].setLocation(x - (folded ? 0 : pinSpacing), y + pinSpacing); + controlPoints[2].setLocation(x, y + 2 * pinSpacing); + break; + case _90: + controlPoints[1].setLocation(x - pinSpacing, y - (folded ? 0 : pinSpacing)); + controlPoints[2].setLocation(x - 2 * pinSpacing, y); + break; + case _180: + controlPoints[1].setLocation(x + (folded ? 0 : pinSpacing), y - pinSpacing); + controlPoints[2].setLocation(x, y - 2 * pinSpacing); + break; + case _270: + controlPoints[1].setLocation(x + pinSpacing, y + (folded ? 0 : pinSpacing)); + controlPoints[2].setLocation(x + 2 * pinSpacing, y); + break; + default: + throw new RuntimeException("Unexpected orientation: " + orientation); + } + } + + public Area[] getBody() { + if (body == null) { + double x = (controlPoints[0].getX() + controlPoints[1].getX() + controlPoints[2].getX()) / 3; + double y = (controlPoints[0].getY() + controlPoints[1].getY() + controlPoints[2].getY()) / 3; + int bodyDiameter = getClosestOdd(BODY_DIAMETER.convertToPixels()); + int bodyLength = getClosestOdd(BODY_LENGTH.convertToPixels()); + int edgeRadius = (int) EDGE_RADIUS.convertToPixels(); + + Area newBody = null; + + if (folded) { + switch (orientation) { + case DEFAULT: + newBody = + new Area(new RoundRectangle2D.Double(x, y - bodyDiameter / 2, bodyLength, bodyDiameter, edgeRadius, + edgeRadius)); + newBody.add(new Area(new Rectangle2D.Double(x, y - bodyDiameter / 2, bodyLength / 2, bodyDiameter))); + break; + case _90: + newBody = + new Area(new RoundRectangle2D.Double(x - bodyDiameter / 2, y, bodyDiameter, bodyLength, edgeRadius, + edgeRadius)); + newBody.add(new Area(new Rectangle2D.Double(x - bodyDiameter / 2, y, bodyDiameter, bodyLength / 2))); + break; + case _180: + newBody = + new Area(new RoundRectangle2D.Double(x - bodyLength, y - bodyDiameter / 2, bodyLength, bodyDiameter, + edgeRadius, edgeRadius)); + newBody.add(new Area(new Rectangle2D.Double(x - bodyLength / 2, y - bodyDiameter / 2, bodyLength / 2, + bodyDiameter))); + + break; + case _270: + newBody = + new Area(new RoundRectangle2D.Double(x - bodyDiameter / 2, y - bodyLength, bodyDiameter, bodyLength, + edgeRadius, edgeRadius)); + newBody.add(new Area(new Rectangle2D.Double(x - bodyDiameter / 2, y - bodyLength / 2, bodyDiameter, + bodyLength / 2))); + break; + default: + throw new RuntimeException("Unexpected orientation: " + orientation); + } + } else { + newBody = new Area(new Ellipse2D.Double(x - bodyDiameter / 2, y - bodyDiameter / 2, bodyDiameter, bodyDiameter)); + } + + body = new Area[] { newBody }; + } + return body; + } + + @Override + public void draw(Graphics2D g2d, ComponentState componentState, boolean outlineMode, Project project, + IDrawingObserver drawingObserver) { + + drawingObserver.stopTracking(); + if (checkPointsClipped(g2d.getClip())) { + return; + } + int pinSize = (int) PIN_SIZE.convertToPixels() / 2 * 2; + Theme theme = (Theme) ConfigurationManager.getInstance().readObject(IPlugInPort.THEME_KEY, Constants.DEFAULT_THEME); + + g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(1f)); + for (Point2D point : controlPoints) { + Shape shape = new Ellipse2D.Double(point.getX() - pinSize / 2, point.getY() - pinSize / 2, pinSize, pinSize); + if (!outlineMode) { + g2d.setColor(PIN_COLOR); + g2d.fill(shape); + } + g2d.setColor(outlineMode ? theme.getOutlineColor() : PIN_BORDER_COLOR); + g2d.draw(shape); + } + + Area mainArea = getBody()[0]; + Composite oldComposite = applyAlpha(g2d, componentState); + g2d.setColor(outlineMode ? Constants.TRANSPARENT_COLOR : bodyColor); + drawingObserver.startTracking(); + g2d.fill(mainArea); + drawingObserver.stopTracking(); + g2d.setComposite(oldComposite); + Color finalBorderColor; + + if (outlineMode) { + 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.setStroke(ObjectCache.getInstance().fetchBasicStroke(1)); + g2d.draw(mainArea); + + // Draw label. + g2d.setFont(project.getFont()); + + // Override font size + if (getFontSizeOverride() != null) + g2d.setFont(g2d.getFont().deriveFont(1f * getFontSizeOverride())); + + Color finalLabelColor; + if (outlineMode) { + finalLabelColor = + componentState == ComponentState.SELECTED || componentState == ComponentState.DRAGGING ? LABEL_COLOR_SELECTED + : theme.getOutlineColor(); + } else { + finalLabelColor = + componentState == ComponentState.SELECTED || componentState == ComponentState.DRAGGING ? LABEL_COLOR_SELECTED + : getLabelColor(); + } + g2d.setColor(finalLabelColor); + if (getDisplay() == TransistorDisplay.PINOUT) { + drawPinout(g2d); + } else { + String label = ""; + label = (getDisplay() == TransistorDisplay.NAME) ? getName() : getValue(); + if (getDisplay() == TransistorDisplay.NONE) { + label = ""; + } + if (getDisplay() == TransistorDisplay.BOTH) { + label = getName() + " " + (getValue() == null ? "" : getValue().toString()); + } + FontMetrics fontMetrics = g2d.getFontMetrics(g2d.getFont()); + Rectangle2D rect = fontMetrics.getStringBounds(label, g2d); + int textHeight = (int) (rect.getHeight()); + int textWidth = (int) (rect.getWidth()); + // Center text horizontally and vertically + Rectangle bounds = mainArea.getBounds(); + int x = (int) (bounds.getX() + (bounds.width - textWidth) / 2); + int y = (int) (bounds.getY() + (bounds.height - textHeight) / 2 + fontMetrics.getAscent()); + g2d.drawString(label, x, y); + } + } + + @Override + public void drawIcon(Graphics2D g2d, int width, int height) { + int margin = (int) (2f * width / 32); + Area area = new Area(new Ellipse2D.Double(margin / 2, margin, width - 2 * margin, width - 2 * margin)); + g2d.setColor(BODY_COLOR); + g2d.fill(area); + g2d.setColor(BORDER_COLOR); + g2d.draw(area); + g2d.setColor(PIN_COLOR); + int pinSize = 2 * width / 32; + for (int i = 0; i < 3; i++) { + g2d.fillOval((i == 1 ? width * 3 / 8 : width / 2) - pinSize / 2, (height / 4) * (i + 1), pinSize, pinSize); + } + } + + @EditableProperty(name = "Pin spacing") + public Size getPinSpacing() { + return pinSpacing; + } + + public void setPinSpacing(Size pinSpacing) { + this.pinSpacing = pinSpacing; + updateControlPoints(); + // Reset body shape; + body = null; + } + + @Override + protected boolean flipPinoutLabel() { + return true; + } +} diff --git a/diylc/diylc-library/src/main/java/org/diylc/components/semiconductors/TransistorTO126.java b/diylc/diylc-library/src/main/java/org/diylc/components/semiconductors/TransistorTO126.java index 506441cd2..1a4e275b9 100644 --- a/diylc/diylc-library/src/main/java/org/diylc/components/semiconductors/TransistorTO126.java +++ b/diylc/diylc-library/src/main/java/org/diylc/components/semiconductors/TransistorTO126.java @@ -1,378 +1,376 @@ -/* - - DIY Layout Creator (DIYLC). - Copyright (c) 2009-2025 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.semiconductors; - -import java.awt.AlphaComposite; -import java.awt.Color; -import java.awt.Composite; -import java.awt.FontMetrics; -import java.awt.Graphics2D; -import java.awt.Rectangle; -import java.awt.Shape; -import java.awt.geom.Area; -import java.awt.geom.Ellipse2D; -import java.awt.geom.Line2D; -import java.awt.geom.Point2D; -import java.awt.geom.Rectangle2D; -import org.diylc.appframework.miscutils.ConfigurationManager; - -import org.diylc.common.IPlugInPort; -import org.diylc.common.ObjectCache; -import org.diylc.components.transform.TO220Transformer; -import org.diylc.core.ComponentState; -import org.diylc.core.IDIYComponent; -import org.diylc.core.IDrawingObserver; -import org.diylc.core.Project; -import org.diylc.core.Theme; -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; -import org.diylc.utils.Constants; - -@ComponentDescriptor(name = "Transistor (TO-126)", author = "Branislav Stojkovic", category = "Semiconductors", - instanceNamePrefix = "Q", description = "Transistors with a hole for heat sink mounting", - zOrder = IDIYComponent.COMPONENT, keywordPolicy = KeywordPolicy.SHOW_VALUE, transformer = TO220Transformer.class, - enableCache = true) -public class TransistorTO126 extends AbstractTransistorPackage { - - private static final long serialVersionUID = 1L; - - public static Color BODY_COLOR = Color.gray; - public static Color BORDER_COLOR = Color.gray.darker(); - public static Color PIN_COLOR = Color.decode("#00B2EE"); - public static Color PIN_BORDER_COLOR = PIN_COLOR.darker(); - public static Color LABEL_COLOR = Color.white; - public static Size PIN_SIZE = new Size(0.8d, SizeUnit.mm); - public static Size PIN_SPACING = new Size(0.1d, SizeUnit.in); - public static Size BODY_WIDTH = new Size(8d, SizeUnit.mm); - public static Size BODY_THICKNESS = new Size(3.25d, SizeUnit.mm); - public static Size BODY_HEIGHT = new Size(11d, SizeUnit.mm); - public static Size HOLE_DIAMETER = new Size(3.2d, SizeUnit.mm); - public static Size HOLE_OFFSET = new Size(8.1d, SizeUnit.mm); - public static Size LEAD_LENGTH = new Size(3.5d, SizeUnit.mm); - public static Size LEAD_THICKNESS = new Size(0.8d, SizeUnit.mm); - - private Size leadLength = LEAD_LENGTH; - - public TransistorTO126() { - super(); - updateControlPoints(); - alpha = (byte) 100; - bodyColor = BODY_COLOR; - borderColor = BORDER_COLOR; - } - - @Override - protected void updateControlPoints() { - int pinSpacing = (int) PIN_SPACING.convertToPixels(); - // Update control points. - double x = controlPoints[0].getX(); - double y = controlPoints[0].getY(); - switch (orientation) { - case DEFAULT: - controlPoints[1].setLocation(x, y + pinSpacing); - controlPoints[2].setLocation(x, y + 2 * pinSpacing); - break; - case _90: - controlPoints[1].setLocation(x - pinSpacing, y); - controlPoints[2].setLocation(x - 2 * pinSpacing, y); - break; - case _180: - controlPoints[1].setLocation(x, y - pinSpacing); - controlPoints[2].setLocation(x, y - 2 * pinSpacing); - break; - case _270: - controlPoints[1].setLocation(x + pinSpacing, y); - controlPoints[2].setLocation(x + 2 * pinSpacing, y); - break; - default: - throw new RuntimeException("Unexpected orientation: " + orientation); - } - } - - public Area[] getBody() { - if (body == null) { - body = new Area[2]; - double x = controlPoints[0].getX(); - double y = controlPoints[0].getY(); - int pinSpacing = (int) PIN_SPACING.convertToPixels(); - int bodyWidth = getClosestOdd(BODY_WIDTH.convertToPixels()); - int bodyThickness = getClosestOdd(BODY_THICKNESS.convertToPixels()); - int bodyHeight = getClosestOdd(BODY_HEIGHT.convertToPixels()); - - int tabHoleDiameter = (int) HOLE_DIAMETER.convertToPixels(); - int holeOffset = (int) HOLE_OFFSET.convertToPixels(); - double leadLength = getLeadLength().convertToPixels(); - - switch (orientation) { - case DEFAULT: - if (folded) { - body[0] = new Area(new Rectangle2D.Double(x + leadLength, y + pinSpacing - bodyWidth / 2, bodyHeight, bodyWidth)); - ((Area) body[0]).subtract(new Area(new Ellipse2D.Double(x + leadLength + holeOffset - - tabHoleDiameter / 2, y + pinSpacing - tabHoleDiameter / 2, tabHoleDiameter, tabHoleDiameter))); - } else { - body[0] = new Area( - new Rectangle2D.Double(x - bodyThickness / 2, y + pinSpacing - bodyWidth / 2, bodyThickness, bodyWidth)); - } - break; - case _90: - if (folded) { - body[0] = new Area(new Rectangle2D.Double(x - pinSpacing - bodyWidth / 2, y + leadLength, bodyWidth, bodyHeight)); - ((Area) body[0]).subtract(new Area(new Ellipse2D.Double(x - pinSpacing - tabHoleDiameter / 2, y - + leadLength + holeOffset - tabHoleDiameter / 2, tabHoleDiameter, tabHoleDiameter))); - } else { - body[0] = new Area( - new Rectangle2D.Double(x - pinSpacing - bodyWidth / 2, y - bodyThickness / 2, bodyWidth, bodyThickness)); - } - break; - case _180: - if (folded) { - body[0] = new Area( - new Rectangle2D.Double(x - leadLength - bodyHeight, y - pinSpacing - bodyWidth / 2, bodyHeight, - bodyWidth)); - ((Area) body[0]).subtract(new Area(new Ellipse2D.Double(x - leadLength - holeOffset - - tabHoleDiameter / 2, y - pinSpacing - tabHoleDiameter / 2, tabHoleDiameter, tabHoleDiameter))); - } else { - body[0] = new Area( - new Rectangle2D.Double(x - bodyThickness / 2, y - pinSpacing - bodyWidth / 2, bodyThickness, bodyWidth)); - } - break; - case _270: - if (folded) { - body[0] = new Area( - new Rectangle2D.Double(x + pinSpacing - bodyWidth / 2, y - leadLength - bodyHeight, bodyWidth, - bodyHeight)); - ((Area) body[0]).subtract(new Area(new Ellipse2D.Double(x + pinSpacing - tabHoleDiameter / 2, y - - leadLength - holeOffset - tabHoleDiameter / 2, tabHoleDiameter, tabHoleDiameter))); - } else { - body[0] = new Area( - new Rectangle2D.Double(x + pinSpacing - bodyWidth / 2, y - bodyThickness / 2, bodyWidth, bodyThickness)); - } - break; - default: - throw new RuntimeException("Unexpected orientation: " + orientation); - } - } - return body; - } - - @Override - public void draw(Graphics2D g2d, ComponentState componentState, boolean outlineMode, Project project, - IDrawingObserver drawingObserver) { - if (checkPointsClipped(g2d.getClip())) { - return; - } - drawingObserver.stopTracking(); - int pinSize = (int) PIN_SIZE.convertToPixels() / 2 * 2; - - Theme theme = (Theme) ConfigurationManager.getInstance().readObject(IPlugInPort.THEME_KEY, Constants.DEFAULT_THEME); - - // Draw pins. - - if (folded) { - if (getLeadLength().getValue() > 0) { - int leadThickness = getClosestOdd(LEAD_THICKNESS.convertToPixels()); - int leadLength = (int) getLeadLength().convertToPixels(); - Color finalPinColor; - Color finalPinBorderColor; - if (outlineMode) { - finalPinColor = new Color(0, 0, 0, 0); - finalPinBorderColor = - componentState == ComponentState.SELECTED || componentState == ComponentState.DRAGGING ? SELECTION_COLOR - : theme.getOutlineColor(); - } else { - finalPinColor = METAL_COLOR; - finalPinBorderColor = METAL_COLOR.darker(); - } - Line2D line; - for (Point2D point : controlPoints) { - switch (orientation) { - case DEFAULT: - g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(leadThickness)); - g2d.setColor(finalPinBorderColor); - line = new Line2D.Double(point.getX(), point.getY(), point.getX() + leadLength - leadThickness / 2, point.getY()); - drawingObserver.startTracking(); - g2d.draw(line); - drawingObserver.stopTracking(); - g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(leadThickness - 2)); - g2d.setColor(finalPinColor); - g2d.draw(line); - break; - case _90: - g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(leadThickness)); - g2d.setColor(finalPinBorderColor); - line = new Line2D.Double(point.getX(), point.getY(), point.getX(), point.getY() + leadLength - leadThickness / 2); - drawingObserver.startTracking(); - g2d.draw(line); - drawingObserver.stopTracking(); - g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(leadThickness - 2)); - g2d.setColor(finalPinColor); - g2d.draw(line); - break; - case _180: - g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(leadThickness)); - g2d.setColor(finalPinBorderColor); - line = new Line2D.Double(point.getX(), point.getY(), point.getX() - leadLength - leadThickness / 2, point.getY()); - drawingObserver.startTracking(); - g2d.draw(line); - drawingObserver.stopTracking(); - g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(leadThickness - 2)); - g2d.setColor(finalPinColor); - g2d.draw(line); - break; - case _270: - g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(leadThickness)); - g2d.setColor(finalPinBorderColor); - line = new Line2D.Double(point.getX(), point.getY(), point.getX(), point.getY() - leadLength); - drawingObserver.startTracking(); - g2d.draw(line); - drawingObserver.stopTracking(); - g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(leadThickness - 2)); - g2d.setColor(finalPinColor); - g2d.draw(line); - break; - } - } - } - } else { - if (!outlineMode) { - for (Point2D point : controlPoints) { - - g2d.setColor(PIN_COLOR); - Shape pin = new Ellipse2D.Double(point.getX() - pinSize / 2, point.getY() - pinSize / 2, pinSize, pinSize); - g2d.fill(pin); - g2d.setColor(outlineMode ? theme.getOutlineColor() : PIN_BORDER_COLOR); - g2d.draw(pin); - } - } - } - - - Shape mainArea = getBody()[0]; - 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 : bodyColor); - drawingObserver.startTracking(); - g2d.fill(mainArea); - drawingObserver.stopTracking(); - - g2d.setComposite(oldComposite); - if (!outlineMode) { - g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(1)); - } - - Color finalBorderColor; - - if (outlineMode) { - 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(mainArea); - - g2d.setComposite(oldComposite); - - // Draw label. - g2d.setFont(project.getFont()); - - // Override font size - if (getFontSizeOverride() != null) - g2d.setFont(g2d.getFont().deriveFont(1f * getFontSizeOverride())); - - Color finalLabelColor; - if (outlineMode) { - finalLabelColor = - componentState == ComponentState.SELECTED || componentState == ComponentState.DRAGGING ? LABEL_COLOR_SELECTED - : theme.getOutlineColor(); - } else { - finalLabelColor = - componentState == ComponentState.SELECTED || componentState == ComponentState.DRAGGING ? LABEL_COLOR_SELECTED - : getLabelColor(); - } - g2d.setColor(finalLabelColor); - if (getDisplay() == TransistorDisplay.PINOUT) { - drawPinout(g2d); - } else { - String label = ""; - label = (getDisplay() == TransistorDisplay.NAME) ? getName() : getValue(); - if (getDisplay() == TransistorDisplay.NONE) { - label = ""; - } - if (getDisplay() == TransistorDisplay.BOTH) { - label = getName() + " " + (getValue() == null ? "" : getValue().toString()); - } - FontMetrics fontMetrics = g2d.getFontMetrics(g2d.getFont()); - Rectangle2D rect = fontMetrics.getStringBounds(label, g2d); - int textHeight = (int) (rect.getHeight()); - int textWidth = (int) (rect.getWidth()); - // Center text horizontally and vertically - Rectangle bounds = mainArea.getBounds(); - int x = (int) (bounds.getX() + (bounds.width - textWidth) / 2); - int y = (int) (bounds.getY() + (bounds.height - textHeight) / 2 + fontMetrics.getAscent()); - g2d.drawString(label, x, y); - } - } - - @Override - public void drawIcon(Graphics2D g2d, int width, int height) { - int margin = 2 * width / 32; - int bodyWidth = width * 5 / 10; - int bodyHeight = width * 7 / 10; - int holeSize = 6 * width / 32; - Area a = new Area(new Rectangle2D.Double((width - bodyWidth) / 2, margin, bodyWidth, bodyHeight)); - a.subtract(new Area(new Ellipse2D.Double(width / 2 - holeSize / 2, margin + bodyHeight / 3 - holeSize / 2, holeSize, - holeSize))); - g2d.setColor(BODY_COLOR); - g2d.fill(a); - g2d.setColor(BORDER_COLOR); - g2d.draw(a); - - g2d.setColor(METAL_COLOR); - g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(2)); - g2d.drawLine(width / 2, margin + bodyHeight, width / 2, height - margin); - g2d.drawLine(width / 2 - bodyWidth / 3, margin + bodyHeight + 1, width / 2 - bodyWidth / 3, height - margin); - g2d.drawLine(width / 2 + bodyWidth / 3, margin + bodyHeight + 1, width / 2 + bodyWidth / 3, height - margin); - } - - @EditableProperty(name = "Lead Length") - public Size getLeadLength() { - if (leadLength == null) { - leadLength = LEAD_LENGTH; - } - return leadLength; - } - - public void setLeadLength(Size leadLength) { - this.leadLength = leadLength; - // Invalidate the body - this.body = null; - } -} +/* + + DIY Layout Creator (DIYLC). + Copyright (c) 2009-2025 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.semiconductors; + +import java.awt.AlphaComposite; +import java.awt.Color; +import java.awt.Composite; +import java.awt.FontMetrics; +import java.awt.Graphics2D; +import java.awt.Rectangle; +import java.awt.Shape; +import java.awt.geom.Area; +import java.awt.geom.Ellipse2D; +import java.awt.geom.Line2D; +import java.awt.geom.Point2D; +import java.awt.geom.Rectangle2D; +import org.diylc.appframework.miscutils.ConfigurationManager; + +import org.diylc.common.IPlugInPort; +import org.diylc.common.ObjectCache; +import org.diylc.common.Percentage; +import org.diylc.components.transform.TO220Transformer; +import org.diylc.core.ComponentState; +import org.diylc.core.IDIYComponent; +import org.diylc.core.IDrawingObserver; +import org.diylc.core.Project; +import org.diylc.core.Theme; +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; +import org.diylc.utils.Constants; + +@ComponentDescriptor(name = "Transistor (TO-126)", author = "Branislav Stojkovic", category = "Semiconductors", + instanceNamePrefix = "Q", description = "Transistors with a hole for heat sink mounting", + zOrder = IDIYComponent.COMPONENT, keywordPolicy = KeywordPolicy.SHOW_VALUE, transformer = TO220Transformer.class, + enableCache = true) +public class TransistorTO126 extends AbstractTransistorPackage { + + private static final long serialVersionUID = 1L; + + public static Color BODY_COLOR = Color.gray; + public static Color BORDER_COLOR = Color.gray.darker(); + public static Color PIN_COLOR = Color.decode("#00B2EE"); + public static Color PIN_BORDER_COLOR = PIN_COLOR.darker(); + public static Color LABEL_COLOR = Color.white; + public static Size PIN_SIZE = new Size(0.8d, SizeUnit.mm); + public static Size PIN_SPACING = new Size(0.1d, SizeUnit.in); + public static Size BODY_WIDTH = new Size(8d, SizeUnit.mm); + public static Size BODY_THICKNESS = new Size(3.25d, SizeUnit.mm); + public static Size BODY_HEIGHT = new Size(11d, SizeUnit.mm); + public static Size HOLE_DIAMETER = new Size(3.2d, SizeUnit.mm); + public static Size HOLE_OFFSET = new Size(8.1d, SizeUnit.mm); + public static Size LEAD_LENGTH = new Size(3.5d, SizeUnit.mm); + public static Size LEAD_THICKNESS = new Size(0.8d, SizeUnit.mm); + + private Size leadLength = LEAD_LENGTH; + + public TransistorTO126() { + super(); + updateControlPoints(); + this.alphaPercent = new Percentage(100); + bodyColor = BODY_COLOR; + borderColor = BORDER_COLOR; + } + + @Override + protected void updateControlPoints() { + int pinSpacing = (int) PIN_SPACING.convertToPixels(); + // Update control points. + double x = controlPoints[0].getX(); + double y = controlPoints[0].getY(); + switch (orientation) { + case DEFAULT: + controlPoints[1].setLocation(x, y + pinSpacing); + controlPoints[2].setLocation(x, y + 2 * pinSpacing); + break; + case _90: + controlPoints[1].setLocation(x - pinSpacing, y); + controlPoints[2].setLocation(x - 2 * pinSpacing, y); + break; + case _180: + controlPoints[1].setLocation(x, y - pinSpacing); + controlPoints[2].setLocation(x, y - 2 * pinSpacing); + break; + case _270: + controlPoints[1].setLocation(x + pinSpacing, y); + controlPoints[2].setLocation(x + 2 * pinSpacing, y); + break; + default: + throw new RuntimeException("Unexpected orientation: " + orientation); + } + } + + public Area[] getBody() { + if (body == null) { + body = new Area[2]; + double x = controlPoints[0].getX(); + double y = controlPoints[0].getY(); + int pinSpacing = (int) PIN_SPACING.convertToPixels(); + int bodyWidth = getClosestOdd(BODY_WIDTH.convertToPixels()); + int bodyThickness = getClosestOdd(BODY_THICKNESS.convertToPixels()); + int bodyHeight = getClosestOdd(BODY_HEIGHT.convertToPixels()); + + int tabHoleDiameter = (int) HOLE_DIAMETER.convertToPixels(); + int holeOffset = (int) HOLE_OFFSET.convertToPixels(); + double leadLength = getLeadLength().convertToPixels(); + + switch (orientation) { + case DEFAULT: + if (folded) { + body[0] = new Area(new Rectangle2D.Double(x + leadLength, y + pinSpacing - bodyWidth / 2, bodyHeight, bodyWidth)); + ((Area) body[0]).subtract(new Area(new Ellipse2D.Double(x + leadLength + holeOffset + - tabHoleDiameter / 2, y + pinSpacing - tabHoleDiameter / 2, tabHoleDiameter, tabHoleDiameter))); + } else { + body[0] = new Area( + new Rectangle2D.Double(x - bodyThickness / 2, y + pinSpacing - bodyWidth / 2, bodyThickness, bodyWidth)); + } + break; + case _90: + if (folded) { + body[0] = new Area(new Rectangle2D.Double(x - pinSpacing - bodyWidth / 2, y + leadLength, bodyWidth, bodyHeight)); + ((Area) body[0]).subtract(new Area(new Ellipse2D.Double(x - pinSpacing - tabHoleDiameter / 2, y + + leadLength + holeOffset - tabHoleDiameter / 2, tabHoleDiameter, tabHoleDiameter))); + } else { + body[0] = new Area( + new Rectangle2D.Double(x - pinSpacing - bodyWidth / 2, y - bodyThickness / 2, bodyWidth, bodyThickness)); + } + break; + case _180: + if (folded) { + body[0] = new Area( + new Rectangle2D.Double(x - leadLength - bodyHeight, y - pinSpacing - bodyWidth / 2, bodyHeight, + bodyWidth)); + ((Area) body[0]).subtract(new Area(new Ellipse2D.Double(x - leadLength - holeOffset + - tabHoleDiameter / 2, y - pinSpacing - tabHoleDiameter / 2, tabHoleDiameter, tabHoleDiameter))); + } else { + body[0] = new Area( + new Rectangle2D.Double(x - bodyThickness / 2, y - pinSpacing - bodyWidth / 2, bodyThickness, bodyWidth)); + } + break; + case _270: + if (folded) { + body[0] = new Area( + new Rectangle2D.Double(x + pinSpacing - bodyWidth / 2, y - leadLength - bodyHeight, bodyWidth, + bodyHeight)); + ((Area) body[0]).subtract(new Area(new Ellipse2D.Double(x + pinSpacing - tabHoleDiameter / 2, y + - leadLength - holeOffset - tabHoleDiameter / 2, tabHoleDiameter, tabHoleDiameter))); + } else { + body[0] = new Area( + new Rectangle2D.Double(x + pinSpacing - bodyWidth / 2, y - bodyThickness / 2, bodyWidth, bodyThickness)); + } + break; + default: + throw new RuntimeException("Unexpected orientation: " + orientation); + } + } + return body; + } + + @Override + public void draw(Graphics2D g2d, ComponentState componentState, boolean outlineMode, Project project, + IDrawingObserver drawingObserver) { + if (checkPointsClipped(g2d.getClip())) { + return; + } + drawingObserver.stopTracking(); + int pinSize = (int) PIN_SIZE.convertToPixels() / 2 * 2; + + Theme theme = (Theme) ConfigurationManager.getInstance().readObject(IPlugInPort.THEME_KEY, Constants.DEFAULT_THEME); + + // Draw pins. + + if (folded) { + if (getLeadLength().getValue() > 0) { + int leadThickness = getClosestOdd(LEAD_THICKNESS.convertToPixels()); + int leadLength = (int) getLeadLength().convertToPixels(); + Color finalPinColor; + Color finalPinBorderColor; + if (outlineMode) { + finalPinColor = new Color(0, 0, 0, 0); + finalPinBorderColor = + componentState == ComponentState.SELECTED || componentState == ComponentState.DRAGGING ? SELECTION_COLOR + : theme.getOutlineColor(); + } else { + finalPinColor = METAL_COLOR; + finalPinBorderColor = METAL_COLOR.darker(); + } + Line2D line; + for (Point2D point : controlPoints) { + switch (orientation) { + case DEFAULT: + g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(leadThickness)); + g2d.setColor(finalPinBorderColor); + line = new Line2D.Double(point.getX(), point.getY(), point.getX() + leadLength - leadThickness / 2, point.getY()); + drawingObserver.startTracking(); + g2d.draw(line); + drawingObserver.stopTracking(); + g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(leadThickness - 2)); + g2d.setColor(finalPinColor); + g2d.draw(line); + break; + case _90: + g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(leadThickness)); + g2d.setColor(finalPinBorderColor); + line = new Line2D.Double(point.getX(), point.getY(), point.getX(), point.getY() + leadLength - leadThickness / 2); + drawingObserver.startTracking(); + g2d.draw(line); + drawingObserver.stopTracking(); + g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(leadThickness - 2)); + g2d.setColor(finalPinColor); + g2d.draw(line); + break; + case _180: + g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(leadThickness)); + g2d.setColor(finalPinBorderColor); + line = new Line2D.Double(point.getX(), point.getY(), point.getX() - leadLength - leadThickness / 2, point.getY()); + drawingObserver.startTracking(); + g2d.draw(line); + drawingObserver.stopTracking(); + g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(leadThickness - 2)); + g2d.setColor(finalPinColor); + g2d.draw(line); + break; + case _270: + g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(leadThickness)); + g2d.setColor(finalPinBorderColor); + line = new Line2D.Double(point.getX(), point.getY(), point.getX(), point.getY() - leadLength); + drawingObserver.startTracking(); + g2d.draw(line); + drawingObserver.stopTracking(); + g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(leadThickness - 2)); + g2d.setColor(finalPinColor); + g2d.draw(line); + break; + } + } + } + } else { + if (!outlineMode) { + for (Point2D point : controlPoints) { + + g2d.setColor(PIN_COLOR); + Shape pin = new Ellipse2D.Double(point.getX() - pinSize / 2, point.getY() - pinSize / 2, pinSize, pinSize); + g2d.fill(pin); + g2d.setColor(outlineMode ? theme.getOutlineColor() : PIN_BORDER_COLOR); + g2d.draw(pin); + } + } + } + + + Shape mainArea = getBody()[0]; + Composite oldComposite = applyAlpha(g2d, componentState); + g2d.setColor(outlineMode ? Constants.TRANSPARENT_COLOR : bodyColor); + drawingObserver.startTracking(); + g2d.fill(mainArea); + drawingObserver.stopTracking(); + + g2d.setComposite(oldComposite); + if (!outlineMode) { + g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(1)); + } + + Color finalBorderColor; + + if (outlineMode) { + 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(mainArea); + + g2d.setComposite(oldComposite); + + // Draw label. + g2d.setFont(project.getFont()); + + // Override font size + if (getFontSizeOverride() != null) + g2d.setFont(g2d.getFont().deriveFont(1f * getFontSizeOverride())); + + Color finalLabelColor; + if (outlineMode) { + finalLabelColor = + componentState == ComponentState.SELECTED || componentState == ComponentState.DRAGGING ? LABEL_COLOR_SELECTED + : theme.getOutlineColor(); + } else { + finalLabelColor = + componentState == ComponentState.SELECTED || componentState == ComponentState.DRAGGING ? LABEL_COLOR_SELECTED + : getLabelColor(); + } + g2d.setColor(finalLabelColor); + if (getDisplay() == TransistorDisplay.PINOUT) { + drawPinout(g2d); + } else { + String label = ""; + label = (getDisplay() == TransistorDisplay.NAME) ? getName() : getValue(); + if (getDisplay() == TransistorDisplay.NONE) { + label = ""; + } + if (getDisplay() == TransistorDisplay.BOTH) { + label = getName() + " " + (getValue() == null ? "" : getValue().toString()); + } + FontMetrics fontMetrics = g2d.getFontMetrics(g2d.getFont()); + Rectangle2D rect = fontMetrics.getStringBounds(label, g2d); + int textHeight = (int) (rect.getHeight()); + int textWidth = (int) (rect.getWidth()); + // Center text horizontally and vertically + Rectangle bounds = mainArea.getBounds(); + int x = (int) (bounds.getX() + (bounds.width - textWidth) / 2); + int y = (int) (bounds.getY() + (bounds.height - textHeight) / 2 + fontMetrics.getAscent()); + g2d.drawString(label, x, y); + } + } + + @Override + public void drawIcon(Graphics2D g2d, int width, int height) { + int margin = 2 * width / 32; + int bodyWidth = width * 5 / 10; + int bodyHeight = width * 7 / 10; + int holeSize = 6 * width / 32; + Area a = new Area(new Rectangle2D.Double((width - bodyWidth) / 2, margin, bodyWidth, bodyHeight)); + a.subtract(new Area(new Ellipse2D.Double(width / 2 - holeSize / 2, margin + bodyHeight / 3 - holeSize / 2, holeSize, + holeSize))); + g2d.setColor(BODY_COLOR); + g2d.fill(a); + g2d.setColor(BORDER_COLOR); + g2d.draw(a); + + g2d.setColor(METAL_COLOR); + g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(2)); + g2d.drawLine(width / 2, margin + bodyHeight, width / 2, height - margin); + g2d.drawLine(width / 2 - bodyWidth / 3, margin + bodyHeight + 1, width / 2 - bodyWidth / 3, height - margin); + g2d.drawLine(width / 2 + bodyWidth / 3, margin + bodyHeight + 1, width / 2 + bodyWidth / 3, height - margin); + } + + @EditableProperty(name = "Lead Length") + public Size getLeadLength() { + if (leadLength == null) { + leadLength = LEAD_LENGTH; + } + return leadLength; + } + + public void setLeadLength(Size leadLength) { + this.leadLength = leadLength; + // Invalidate the body + this.body = null; + } +} diff --git a/diylc/diylc-library/src/main/java/org/diylc/components/semiconductors/TransistorTO220.java b/diylc/diylc-library/src/main/java/org/diylc/components/semiconductors/TransistorTO220.java index 4313dc216..a6f9345c8 100644 --- a/diylc/diylc-library/src/main/java/org/diylc/components/semiconductors/TransistorTO220.java +++ b/diylc/diylc-library/src/main/java/org/diylc/components/semiconductors/TransistorTO220.java @@ -1,441 +1,439 @@ -/* - - DIY Layout Creator (DIYLC). - Copyright (c) 2009-2025 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.semiconductors; - -import java.awt.AlphaComposite; -import java.awt.Color; -import java.awt.Composite; -import java.awt.FontMetrics; -import java.awt.Graphics2D; -import java.awt.Rectangle; -import java.awt.Shape; -import java.awt.geom.Area; -import java.awt.geom.Ellipse2D; -import java.awt.geom.Line2D; -import java.awt.geom.Point2D; -import java.awt.geom.Rectangle2D; -import org.diylc.appframework.miscutils.ConfigurationManager; - -import org.diylc.common.IPlugInPort; -import org.diylc.common.ObjectCache; -import org.diylc.components.transform.TO220Transformer; -import org.diylc.core.ComponentState; -import org.diylc.core.IDIYComponent; -import org.diylc.core.IDrawingObserver; -import org.diylc.core.Project; -import org.diylc.core.Theme; -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; -import org.diylc.utils.Constants; - -@ComponentDescriptor(name = "Transistor (TO-220)", author = "Branislav Stojkovic", category = "Semiconductors", - instanceNamePrefix = "Q", description = "Transistors with metal tab for heat sink mounting", - zOrder = IDIYComponent.COMPONENT, keywordPolicy = KeywordPolicy.SHOW_VALUE, transformer = TO220Transformer.class, - enableCache = true) -public class TransistorTO220 extends AbstractTransistorPackage { - - private static final long serialVersionUID = 1L; - - public static Color BODY_COLOR = Color.gray; - public static Color BORDER_COLOR = Color.gray.darker(); - public static Color PIN_COLOR = Color.decode("#00B2EE"); - public static Color PIN_BORDER_COLOR = PIN_COLOR.darker(); - public static Color TAB_COLOR = Color.lightGray; - public static Color TAB_BORDER_COLOR = TAB_COLOR.darker(); - public static Color LABEL_COLOR = Color.white; - public static Size PIN_SIZE = new Size(0.03d, SizeUnit.in); - public static Size PIN_SPACING = new Size(0.1d, SizeUnit.in); - public static Size BODY_WIDTH = new Size(0.4d, SizeUnit.in); - public static Size BODY_THICKNESS = new Size(4.5d, SizeUnit.mm); - public static Size BODY_HEIGHT = new Size(9d, SizeUnit.mm); - public static Size TAB_THICKNESS = new Size(1d, SizeUnit.mm); - public static Size TAB_HEIGHT = new Size(6.2d, SizeUnit.mm); - public static Size TAB_HOLE_DIAMETER = new Size(3.6d, SizeUnit.mm); - public static Size LEAD_LENGTH = new Size(3.5d, SizeUnit.mm); - public static Size LEAD_THICKNESS = new Size(0.8d, SizeUnit.mm); - - private Color tabColor = TAB_COLOR; - private Color tabBorderColor = TAB_BORDER_COLOR; - private Size leadLength = LEAD_LENGTH; - - public TransistorTO220() { - super(); - updateControlPoints(); - alpha = (byte) 100; - bodyColor = BODY_COLOR; - borderColor = BORDER_COLOR; - } - - @Override - protected void updateControlPoints() { - int pinSpacing = (int) PIN_SPACING.convertToPixels(); - // Update control points. - double x = controlPoints[0].getX(); - double y = controlPoints[0].getY(); - switch (orientation) { - case DEFAULT: - controlPoints[1].setLocation(x, y + pinSpacing); - controlPoints[2].setLocation(x, y + 2 * pinSpacing); - break; - case _90: - controlPoints[1].setLocation(x - pinSpacing, y); - controlPoints[2].setLocation(x - 2 * pinSpacing, y); - break; - case _180: - controlPoints[1].setLocation(x, y - pinSpacing); - controlPoints[2].setLocation(x, y - 2 * pinSpacing); - break; - case _270: - controlPoints[1].setLocation(x + pinSpacing, y); - controlPoints[2].setLocation(x + 2 * pinSpacing, y); - break; - default: - throw new RuntimeException("Unexpected orientation: " + orientation); - } - } - - public Area[] getBody() { - if (body == null) { - body = new Area[2]; - double x = controlPoints[0].getX(); - double y = controlPoints[0].getY(); - int pinSpacing = (int) PIN_SPACING.convertToPixels(); - int bodyWidth = getClosestOdd(BODY_WIDTH.convertToPixels()); - int bodyThickness = getClosestOdd(BODY_THICKNESS.convertToPixels()); - int bodyHeight = getClosestOdd(BODY_HEIGHT.convertToPixels()); - int tabThickness = (int) TAB_THICKNESS.convertToPixels(); - int tabHeight = (int) TAB_HEIGHT.convertToPixels(); - int tabHoleDiameter = (int) TAB_HOLE_DIAMETER.convertToPixels(); - double leadLength = getLeadLength().convertToPixels(); - - switch (orientation) { - case DEFAULT: - if (folded) { - body[0] = new Area(new Rectangle2D.Double(x + leadLength, y + pinSpacing - bodyWidth / 2, bodyHeight, bodyWidth)); - body[1] = - new Area(new Rectangle2D.Double(x + leadLength + bodyHeight, y + pinSpacing - bodyWidth / 2, tabHeight, - bodyWidth)); - ((Area) body[1]).subtract(new Area(new Ellipse2D.Double(x + leadLength + bodyHeight + tabHeight / 2 - - tabHoleDiameter / 2, y + pinSpacing - tabHoleDiameter / 2, tabHoleDiameter, tabHoleDiameter))); - } else { - body[0] = new Area( - new Rectangle2D.Double(x - bodyThickness / 2, y + pinSpacing - bodyWidth / 2, bodyThickness, bodyWidth)); - body[1] = new Area( - new Rectangle2D.Double(x + bodyThickness / 2 - tabThickness, y + pinSpacing - bodyWidth / 2, - tabThickness, bodyWidth)); - } - break; - case _90: - if (folded) { - body[0] = new Area(new Rectangle2D.Double(x - pinSpacing - bodyWidth / 2, y + leadLength, bodyWidth, bodyHeight)); - body[1] = - new Area(new Rectangle2D.Double(x - pinSpacing - bodyWidth / 2, y + leadLength + bodyHeight, bodyWidth, - tabHeight)); - ((Area) body[1]).subtract(new Area(new Ellipse2D.Double(x - pinSpacing - tabHoleDiameter / 2, y - + leadLength + bodyHeight + tabHeight / 2 - tabHoleDiameter / 2, tabHoleDiameter, tabHoleDiameter))); - } else { - body[0] = new Area( - new Rectangle2D.Double(x - pinSpacing - bodyWidth / 2, y - bodyThickness / 2, bodyWidth, bodyThickness)); - body[1] = new Area( - new Rectangle2D.Double(x - pinSpacing - bodyWidth / 2, y + bodyThickness / 2 - tabThickness, bodyWidth, - tabThickness)); - } - break; - case _180: - if (folded) { - body[0] = new Area( - new Rectangle2D.Double(x - leadLength - bodyHeight, y - pinSpacing - bodyWidth / 2, bodyHeight, - bodyWidth)); - body[1] = - new Area(new Rectangle2D.Double(x - leadLength - bodyHeight - tabHeight, - y - pinSpacing - bodyWidth / 2, tabHeight, bodyWidth)); - ((Area) body[1]).subtract(new Area(new Ellipse2D.Double(x - leadLength - bodyHeight - tabHeight / 2 - - tabHoleDiameter / 2, y - pinSpacing - tabHoleDiameter / 2, tabHoleDiameter, tabHoleDiameter))); - } else { - body[0] = new Area( - new Rectangle2D.Double(x - bodyThickness / 2, y - pinSpacing - bodyWidth / 2, bodyThickness, bodyWidth)); - body[1] = new Area( - new Rectangle2D.Double(x - bodyThickness / 2, y - pinSpacing - bodyWidth / 2, tabThickness, bodyWidth)); - } - break; - case _270: - if (folded) { - body[0] = new Area( - new Rectangle2D.Double(x + pinSpacing - bodyWidth / 2, y - leadLength - bodyHeight, bodyWidth, - bodyHeight)); - body[1] = - new Area(new Rectangle2D.Double(x + pinSpacing - bodyWidth / 2, - y - leadLength - bodyHeight - tabHeight, bodyWidth, tabHeight)); - ((Area) body[1]).subtract(new Area(new Ellipse2D.Double(x + pinSpacing - tabHoleDiameter / 2, y - - leadLength - bodyHeight - tabHeight / 2 - tabHoleDiameter / 2, tabHoleDiameter, tabHoleDiameter))); - } else { - body[0] = new Area( - new Rectangle2D.Double(x + pinSpacing - bodyWidth / 2, y - bodyThickness / 2, bodyWidth, bodyThickness)); - body[1] = new Area( - new Rectangle2D.Double(x + pinSpacing - bodyWidth / 2, y - bodyThickness / 2, bodyWidth, tabThickness)); - } - break; - default: - throw new RuntimeException("Unexpected orientation: " + orientation); - } - } - return body; - } - - @Override - public void draw(Graphics2D g2d, ComponentState componentState, boolean outlineMode, Project project, - IDrawingObserver drawingObserver) { - if (checkPointsClipped(g2d.getClip())) { - return; - } - drawingObserver.stopTracking(); - int pinSize = (int) PIN_SIZE.convertToPixels() / 2 * 2; - - Theme theme = (Theme) ConfigurationManager.getInstance().readObject(IPlugInPort.THEME_KEY, Constants.DEFAULT_THEME); - - // Draw pins. - - if (folded) { - if (getLeadLength().getValue() > 0) { - int leadThickness = getClosestOdd(LEAD_THICKNESS.convertToPixels()); - int leadLength = (int) getLeadLength().convertToPixels(); - Color finalPinColor; - Color finalPinBorderColor; - if (outlineMode) { - finalPinColor = new Color(0, 0, 0, 0); - finalPinBorderColor = - componentState == ComponentState.SELECTED || componentState == ComponentState.DRAGGING ? SELECTION_COLOR - : theme.getOutlineColor(); - } else { - finalPinColor = METAL_COLOR; - finalPinBorderColor = METAL_COLOR.darker(); - } - Line2D line; - for (Point2D point : controlPoints) { - switch (orientation) { - case DEFAULT: - g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(leadThickness)); - g2d.setColor(finalPinBorderColor); - line = new Line2D.Double(point.getX(), point.getY(), point.getX() + leadLength - leadThickness / 2, point.getY()); - drawingObserver.startTracking(); - g2d.draw(line); - drawingObserver.stopTracking(); - g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(leadThickness - 2)); - g2d.setColor(finalPinColor); - g2d.draw(line); - break; - case _90: - g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(leadThickness)); - g2d.setColor(finalPinBorderColor); - line = new Line2D.Double(point.getX(), point.getY(), point.getX(), point.getY() + leadLength - leadThickness / 2); - drawingObserver.startTracking(); - g2d.draw(line); - drawingObserver.stopTracking(); - g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(leadThickness - 2)); - g2d.setColor(finalPinColor); - g2d.draw(line); - break; - case _180: - g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(leadThickness)); - g2d.setColor(finalPinBorderColor); - line = new Line2D.Double(point.getX(), point.getY(), point.getX() - leadLength - leadThickness / 2, point.getY()); - drawingObserver.startTracking(); - g2d.draw(line); - drawingObserver.stopTracking(); - g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(leadThickness - 2)); - g2d.setColor(finalPinColor); - g2d.draw(line); - break; - case _270: - g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(leadThickness)); - g2d.setColor(finalPinBorderColor); - line = new Line2D.Double(point.getX(), point.getY(), point.getX(), point.getY() - leadLength); - drawingObserver.startTracking(); - g2d.draw(line); - drawingObserver.stopTracking(); - g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(leadThickness - 2)); - g2d.setColor(finalPinColor); - g2d.draw(line); - break; - } - } - } - } else { - if (!outlineMode) { - for (Point2D point : controlPoints) { - - g2d.setColor(PIN_COLOR); - Shape pin = new Ellipse2D.Double(point.getX() - pinSize / 2, point.getY() - pinSize / 2, pinSize, pinSize); - g2d.fill(pin); - g2d.setColor(outlineMode ? theme.getOutlineColor() : PIN_BORDER_COLOR); - g2d.draw(pin); - } - } - } - - - Shape mainArea = getBody()[0]; - Shape tabArea = getBody()[1]; - 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 : bodyColor); - drawingObserver.startTracking(); - g2d.fill(mainArea); - drawingObserver.stopTracking(); - Color finalTabColor; - if (outlineMode) { - finalTabColor = theme.getOutlineColor(); - } else { - finalTabColor = tabColor; - } - g2d.setColor(finalTabColor); - g2d.fill(tabArea); - g2d.setComposite(oldComposite); - if (!outlineMode) { - g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(1)); - g2d.setColor(tabBorderColor); - g2d.draw(tabArea); - } - Color finalBorderColor; - - if (outlineMode) { - 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(mainArea); - if (folded) { - g2d.draw(tabArea); - } - - // Draw label. - g2d.setFont(project.getFont()); - - // Override font size - if (getFontSizeOverride() != null) - g2d.setFont(g2d.getFont().deriveFont(1f * getFontSizeOverride())); - - Color finalLabelColor; - if (outlineMode) { - finalLabelColor = - componentState == ComponentState.SELECTED || componentState == ComponentState.DRAGGING ? LABEL_COLOR_SELECTED - : theme.getOutlineColor(); - } else { - finalLabelColor = - componentState == ComponentState.SELECTED || componentState == ComponentState.DRAGGING ? LABEL_COLOR_SELECTED - : getLabelColor(); - } - g2d.setColor(finalLabelColor); - if (getDisplay() == TransistorDisplay.PINOUT) { - drawPinout(g2d); - } else { - String label = ""; - label = (getDisplay() == TransistorDisplay.NAME) ? getName() : getValue(); - if (getDisplay() == TransistorDisplay.NONE) { - label = ""; - } - if (getDisplay() == TransistorDisplay.BOTH) { - label = getName() + " " + (getValue() == null ? "" : getValue().toString()); - } - FontMetrics fontMetrics = g2d.getFontMetrics(g2d.getFont()); - Rectangle2D rect = fontMetrics.getStringBounds(label, g2d); - int textHeight = (int) (rect.getHeight()); - int textWidth = (int) (rect.getWidth()); - // Center text horizontally and vertically - Rectangle bounds = mainArea.getBounds(); - int x = (int) (bounds.getX() + (bounds.width - textWidth) / 2); - int y = (int) (bounds.getY() + (bounds.height - textHeight) / 2 + fontMetrics.getAscent()); - g2d.drawString(label, x, y); - } - } - - @Override - public void drawIcon(Graphics2D g2d, int width, int height) { - int margin = 2 * width / 32; - int bodySize = width * 5 / 10; - int tabSize = bodySize * 6 / 10; - int holeSize = 5 * width / 32; - Area a = new Area(new Rectangle2D.Double((width - bodySize) / 2, margin, bodySize, tabSize)); - a.subtract(new Area(new Ellipse2D.Double(width / 2 - holeSize / 2, margin + tabSize / 2 - holeSize / 2, holeSize, - holeSize))); - g2d.setColor(TAB_COLOR); - g2d.fill(a); - g2d.setColor(BORDER_COLOR); - g2d.draw(a); - g2d.setColor(BODY_COLOR); - g2d.fillRect((width - bodySize) / 2, margin + tabSize, bodySize, bodySize); - g2d.setColor(BORDER_COLOR); - g2d.drawRect((width - bodySize) / 2, margin + tabSize, bodySize, bodySize); - g2d.setColor(METAL_COLOR); - g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(2)); - g2d.drawLine(width / 2, margin + tabSize + bodySize + 1, width / 2, height - margin); - g2d.drawLine(width / 2 - bodySize / 3, margin + tabSize + bodySize + 1, width / 2 - bodySize / 3, height - margin); - g2d.drawLine(width / 2 + bodySize / 3, margin + tabSize + bodySize + 1, width / 2 + bodySize / 3, height - margin); - } - - @EditableProperty(name = "Tab") - public Color getTabColor() { - return tabColor; - } - - public void setTabColor(Color tabColor) { - this.tabColor = tabColor; - } - - @EditableProperty(name = "Lead Length") - public Size getLeadLength() { - if (leadLength == null) { - leadLength = LEAD_LENGTH; - } - return leadLength; - } - - public void setLeadLength(Size leadLength) { - this.leadLength = leadLength; - // Invalidate the body - this.body = null; - } - - @EditableProperty(name = "Tab Border") - public Color getTabBorderColor() { - return tabBorderColor; - } - - public void setTabBorderColor(Color tabBorderColor) { - this.tabBorderColor = tabBorderColor; - } - - @Override - protected boolean flipPinoutLabel() { - return true; - } -} +/* + + DIY Layout Creator (DIYLC). + Copyright (c) 2009-2025 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.semiconductors; + +import java.awt.AlphaComposite; +import java.awt.Color; +import java.awt.Composite; +import java.awt.FontMetrics; +import java.awt.Graphics2D; +import java.awt.Rectangle; +import java.awt.Shape; +import java.awt.geom.Area; +import java.awt.geom.Ellipse2D; +import java.awt.geom.Line2D; +import java.awt.geom.Point2D; +import java.awt.geom.Rectangle2D; +import org.diylc.appframework.miscutils.ConfigurationManager; + +import org.diylc.common.IPlugInPort; +import org.diylc.common.ObjectCache; +import org.diylc.common.Percentage; +import org.diylc.components.transform.TO220Transformer; +import org.diylc.core.ComponentState; +import org.diylc.core.IDIYComponent; +import org.diylc.core.IDrawingObserver; +import org.diylc.core.Project; +import org.diylc.core.Theme; +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; +import org.diylc.utils.Constants; + +@ComponentDescriptor(name = "Transistor (TO-220)", author = "Branislav Stojkovic", category = "Semiconductors", + instanceNamePrefix = "Q", description = "Transistors with metal tab for heat sink mounting", + zOrder = IDIYComponent.COMPONENT, keywordPolicy = KeywordPolicy.SHOW_VALUE, transformer = TO220Transformer.class, + enableCache = true) +public class TransistorTO220 extends AbstractTransistorPackage { + + private static final long serialVersionUID = 1L; + + public static Color BODY_COLOR = Color.gray; + public static Color BORDER_COLOR = Color.gray.darker(); + public static Color PIN_COLOR = Color.decode("#00B2EE"); + public static Color PIN_BORDER_COLOR = PIN_COLOR.darker(); + public static Color TAB_COLOR = Color.lightGray; + public static Color TAB_BORDER_COLOR = TAB_COLOR.darker(); + public static Color LABEL_COLOR = Color.white; + public static Size PIN_SIZE = new Size(0.03d, SizeUnit.in); + public static Size PIN_SPACING = new Size(0.1d, SizeUnit.in); + public static Size BODY_WIDTH = new Size(0.4d, SizeUnit.in); + public static Size BODY_THICKNESS = new Size(4.5d, SizeUnit.mm); + public static Size BODY_HEIGHT = new Size(9d, SizeUnit.mm); + public static Size TAB_THICKNESS = new Size(1d, SizeUnit.mm); + public static Size TAB_HEIGHT = new Size(6.2d, SizeUnit.mm); + public static Size TAB_HOLE_DIAMETER = new Size(3.6d, SizeUnit.mm); + public static Size LEAD_LENGTH = new Size(3.5d, SizeUnit.mm); + public static Size LEAD_THICKNESS = new Size(0.8d, SizeUnit.mm); + + private Color tabColor = TAB_COLOR; + private Color tabBorderColor = TAB_BORDER_COLOR; + private Size leadLength = LEAD_LENGTH; + + public TransistorTO220() { + super(); + updateControlPoints(); + this.alphaPercent = new Percentage(100); + bodyColor = BODY_COLOR; + borderColor = BORDER_COLOR; + } + + @Override + protected void updateControlPoints() { + int pinSpacing = (int) PIN_SPACING.convertToPixels(); + // Update control points. + double x = controlPoints[0].getX(); + double y = controlPoints[0].getY(); + switch (orientation) { + case DEFAULT: + controlPoints[1].setLocation(x, y + pinSpacing); + controlPoints[2].setLocation(x, y + 2 * pinSpacing); + break; + case _90: + controlPoints[1].setLocation(x - pinSpacing, y); + controlPoints[2].setLocation(x - 2 * pinSpacing, y); + break; + case _180: + controlPoints[1].setLocation(x, y - pinSpacing); + controlPoints[2].setLocation(x, y - 2 * pinSpacing); + break; + case _270: + controlPoints[1].setLocation(x + pinSpacing, y); + controlPoints[2].setLocation(x + 2 * pinSpacing, y); + break; + default: + throw new RuntimeException("Unexpected orientation: " + orientation); + } + } + + public Area[] getBody() { + if (body == null) { + body = new Area[2]; + double x = controlPoints[0].getX(); + double y = controlPoints[0].getY(); + int pinSpacing = (int) PIN_SPACING.convertToPixels(); + int bodyWidth = getClosestOdd(BODY_WIDTH.convertToPixels()); + int bodyThickness = getClosestOdd(BODY_THICKNESS.convertToPixels()); + int bodyHeight = getClosestOdd(BODY_HEIGHT.convertToPixels()); + int tabThickness = (int) TAB_THICKNESS.convertToPixels(); + int tabHeight = (int) TAB_HEIGHT.convertToPixels(); + int tabHoleDiameter = (int) TAB_HOLE_DIAMETER.convertToPixels(); + double leadLength = getLeadLength().convertToPixels(); + + switch (orientation) { + case DEFAULT: + if (folded) { + body[0] = new Area(new Rectangle2D.Double(x + leadLength, y + pinSpacing - bodyWidth / 2, bodyHeight, bodyWidth)); + body[1] = + new Area(new Rectangle2D.Double(x + leadLength + bodyHeight, y + pinSpacing - bodyWidth / 2, tabHeight, + bodyWidth)); + ((Area) body[1]).subtract(new Area(new Ellipse2D.Double(x + leadLength + bodyHeight + tabHeight / 2 + - tabHoleDiameter / 2, y + pinSpacing - tabHoleDiameter / 2, tabHoleDiameter, tabHoleDiameter))); + } else { + body[0] = new Area( + new Rectangle2D.Double(x - bodyThickness / 2, y + pinSpacing - bodyWidth / 2, bodyThickness, bodyWidth)); + body[1] = new Area( + new Rectangle2D.Double(x + bodyThickness / 2 - tabThickness, y + pinSpacing - bodyWidth / 2, + tabThickness, bodyWidth)); + } + break; + case _90: + if (folded) { + body[0] = new Area(new Rectangle2D.Double(x - pinSpacing - bodyWidth / 2, y + leadLength, bodyWidth, bodyHeight)); + body[1] = + new Area(new Rectangle2D.Double(x - pinSpacing - bodyWidth / 2, y + leadLength + bodyHeight, bodyWidth, + tabHeight)); + ((Area) body[1]).subtract(new Area(new Ellipse2D.Double(x - pinSpacing - tabHoleDiameter / 2, y + + leadLength + bodyHeight + tabHeight / 2 - tabHoleDiameter / 2, tabHoleDiameter, tabHoleDiameter))); + } else { + body[0] = new Area( + new Rectangle2D.Double(x - pinSpacing - bodyWidth / 2, y - bodyThickness / 2, bodyWidth, bodyThickness)); + body[1] = new Area( + new Rectangle2D.Double(x - pinSpacing - bodyWidth / 2, y + bodyThickness / 2 - tabThickness, bodyWidth, + tabThickness)); + } + break; + case _180: + if (folded) { + body[0] = new Area( + new Rectangle2D.Double(x - leadLength - bodyHeight, y - pinSpacing - bodyWidth / 2, bodyHeight, + bodyWidth)); + body[1] = + new Area(new Rectangle2D.Double(x - leadLength - bodyHeight - tabHeight, + y - pinSpacing - bodyWidth / 2, tabHeight, bodyWidth)); + ((Area) body[1]).subtract(new Area(new Ellipse2D.Double(x - leadLength - bodyHeight - tabHeight / 2 + - tabHoleDiameter / 2, y - pinSpacing - tabHoleDiameter / 2, tabHoleDiameter, tabHoleDiameter))); + } else { + body[0] = new Area( + new Rectangle2D.Double(x - bodyThickness / 2, y - pinSpacing - bodyWidth / 2, bodyThickness, bodyWidth)); + body[1] = new Area( + new Rectangle2D.Double(x - bodyThickness / 2, y - pinSpacing - bodyWidth / 2, tabThickness, bodyWidth)); + } + break; + case _270: + if (folded) { + body[0] = new Area( + new Rectangle2D.Double(x + pinSpacing - bodyWidth / 2, y - leadLength - bodyHeight, bodyWidth, + bodyHeight)); + body[1] = + new Area(new Rectangle2D.Double(x + pinSpacing - bodyWidth / 2, + y - leadLength - bodyHeight - tabHeight, bodyWidth, tabHeight)); + ((Area) body[1]).subtract(new Area(new Ellipse2D.Double(x + pinSpacing - tabHoleDiameter / 2, y + - leadLength - bodyHeight - tabHeight / 2 - tabHoleDiameter / 2, tabHoleDiameter, tabHoleDiameter))); + } else { + body[0] = new Area( + new Rectangle2D.Double(x + pinSpacing - bodyWidth / 2, y - bodyThickness / 2, bodyWidth, bodyThickness)); + body[1] = new Area( + new Rectangle2D.Double(x + pinSpacing - bodyWidth / 2, y - bodyThickness / 2, bodyWidth, tabThickness)); + } + break; + default: + throw new RuntimeException("Unexpected orientation: " + orientation); + } + } + return body; + } + + @Override + public void draw(Graphics2D g2d, ComponentState componentState, boolean outlineMode, Project project, + IDrawingObserver drawingObserver) { + if (checkPointsClipped(g2d.getClip())) { + return; + } + drawingObserver.stopTracking(); + int pinSize = (int) PIN_SIZE.convertToPixels() / 2 * 2; + + Theme theme = (Theme) ConfigurationManager.getInstance().readObject(IPlugInPort.THEME_KEY, Constants.DEFAULT_THEME); + + // Draw pins. + + if (folded) { + if (getLeadLength().getValue() > 0) { + int leadThickness = getClosestOdd(LEAD_THICKNESS.convertToPixels()); + int leadLength = (int) getLeadLength().convertToPixels(); + Color finalPinColor; + Color finalPinBorderColor; + if (outlineMode) { + finalPinColor = new Color(0, 0, 0, 0); + finalPinBorderColor = + componentState == ComponentState.SELECTED || componentState == ComponentState.DRAGGING ? SELECTION_COLOR + : theme.getOutlineColor(); + } else { + finalPinColor = METAL_COLOR; + finalPinBorderColor = METAL_COLOR.darker(); + } + Line2D line; + for (Point2D point : controlPoints) { + switch (orientation) { + case DEFAULT: + g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(leadThickness)); + g2d.setColor(finalPinBorderColor); + line = new Line2D.Double(point.getX(), point.getY(), point.getX() + leadLength - leadThickness / 2, point.getY()); + drawingObserver.startTracking(); + g2d.draw(line); + drawingObserver.stopTracking(); + g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(leadThickness - 2)); + g2d.setColor(finalPinColor); + g2d.draw(line); + break; + case _90: + g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(leadThickness)); + g2d.setColor(finalPinBorderColor); + line = new Line2D.Double(point.getX(), point.getY(), point.getX(), point.getY() + leadLength - leadThickness / 2); + drawingObserver.startTracking(); + g2d.draw(line); + drawingObserver.stopTracking(); + g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(leadThickness - 2)); + g2d.setColor(finalPinColor); + g2d.draw(line); + break; + case _180: + g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(leadThickness)); + g2d.setColor(finalPinBorderColor); + line = new Line2D.Double(point.getX(), point.getY(), point.getX() - leadLength - leadThickness / 2, point.getY()); + drawingObserver.startTracking(); + g2d.draw(line); + drawingObserver.stopTracking(); + g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(leadThickness - 2)); + g2d.setColor(finalPinColor); + g2d.draw(line); + break; + case _270: + g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(leadThickness)); + g2d.setColor(finalPinBorderColor); + line = new Line2D.Double(point.getX(), point.getY(), point.getX(), point.getY() - leadLength); + drawingObserver.startTracking(); + g2d.draw(line); + drawingObserver.stopTracking(); + g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(leadThickness - 2)); + g2d.setColor(finalPinColor); + g2d.draw(line); + break; + } + } + } + } else { + if (!outlineMode) { + for (Point2D point : controlPoints) { + + g2d.setColor(PIN_COLOR); + Shape pin = new Ellipse2D.Double(point.getX() - pinSize / 2, point.getY() - pinSize / 2, pinSize, pinSize); + g2d.fill(pin); + g2d.setColor(outlineMode ? theme.getOutlineColor() : PIN_BORDER_COLOR); + g2d.draw(pin); + } + } + } + + + Shape mainArea = getBody()[0]; + Shape tabArea = getBody()[1]; + Composite oldComposite = applyAlpha(g2d, componentState); + g2d.setColor(outlineMode ? Constants.TRANSPARENT_COLOR : bodyColor); + drawingObserver.startTracking(); + g2d.fill(mainArea); + drawingObserver.stopTracking(); + Color finalTabColor; + if (outlineMode) { + finalTabColor = theme.getOutlineColor(); + } else { + finalTabColor = tabColor; + } + g2d.setColor(finalTabColor); + g2d.fill(tabArea); + g2d.setComposite(oldComposite); + if (!outlineMode) { + g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(1)); + g2d.setColor(tabBorderColor); + g2d.draw(tabArea); + } + Color finalBorderColor; + + if (outlineMode) { + 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(mainArea); + if (folded) { + g2d.draw(tabArea); + } + + // Draw label. + g2d.setFont(project.getFont()); + + // Override font size + if (getFontSizeOverride() != null) + g2d.setFont(g2d.getFont().deriveFont(1f * getFontSizeOverride())); + + Color finalLabelColor; + if (outlineMode) { + finalLabelColor = + componentState == ComponentState.SELECTED || componentState == ComponentState.DRAGGING ? LABEL_COLOR_SELECTED + : theme.getOutlineColor(); + } else { + finalLabelColor = + componentState == ComponentState.SELECTED || componentState == ComponentState.DRAGGING ? LABEL_COLOR_SELECTED + : getLabelColor(); + } + g2d.setColor(finalLabelColor); + if (getDisplay() == TransistorDisplay.PINOUT) { + drawPinout(g2d); + } else { + String label = ""; + label = (getDisplay() == TransistorDisplay.NAME) ? getName() : getValue(); + if (getDisplay() == TransistorDisplay.NONE) { + label = ""; + } + if (getDisplay() == TransistorDisplay.BOTH) { + label = getName() + " " + (getValue() == null ? "" : getValue().toString()); + } + FontMetrics fontMetrics = g2d.getFontMetrics(g2d.getFont()); + Rectangle2D rect = fontMetrics.getStringBounds(label, g2d); + int textHeight = (int) (rect.getHeight()); + int textWidth = (int) (rect.getWidth()); + // Center text horizontally and vertically + Rectangle bounds = mainArea.getBounds(); + int x = (int) (bounds.getX() + (bounds.width - textWidth) / 2); + int y = (int) (bounds.getY() + (bounds.height - textHeight) / 2 + fontMetrics.getAscent()); + g2d.drawString(label, x, y); + } + } + + @Override + public void drawIcon(Graphics2D g2d, int width, int height) { + int margin = 2 * width / 32; + int bodySize = width * 5 / 10; + int tabSize = bodySize * 6 / 10; + int holeSize = 5 * width / 32; + Area a = new Area(new Rectangle2D.Double((width - bodySize) / 2, margin, bodySize, tabSize)); + a.subtract(new Area(new Ellipse2D.Double(width / 2 - holeSize / 2, margin + tabSize / 2 - holeSize / 2, holeSize, + holeSize))); + g2d.setColor(TAB_COLOR); + g2d.fill(a); + g2d.setColor(BORDER_COLOR); + g2d.draw(a); + g2d.setColor(BODY_COLOR); + g2d.fillRect((width - bodySize) / 2, margin + tabSize, bodySize, bodySize); + g2d.setColor(BORDER_COLOR); + g2d.drawRect((width - bodySize) / 2, margin + tabSize, bodySize, bodySize); + g2d.setColor(METAL_COLOR); + g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(2)); + g2d.drawLine(width / 2, margin + tabSize + bodySize + 1, width / 2, height - margin); + g2d.drawLine(width / 2 - bodySize / 3, margin + tabSize + bodySize + 1, width / 2 - bodySize / 3, height - margin); + g2d.drawLine(width / 2 + bodySize / 3, margin + tabSize + bodySize + 1, width / 2 + bodySize / 3, height - margin); + } + + @EditableProperty(name = "Tab") + public Color getTabColor() { + return tabColor; + } + + public void setTabColor(Color tabColor) { + this.tabColor = tabColor; + } + + @EditableProperty(name = "Lead Length") + public Size getLeadLength() { + if (leadLength == null) { + leadLength = LEAD_LENGTH; + } + return leadLength; + } + + public void setLeadLength(Size leadLength) { + this.leadLength = leadLength; + // Invalidate the body + this.body = null; + } + + @EditableProperty(name = "Tab Border") + public Color getTabBorderColor() { + return tabBorderColor; + } + + public void setTabBorderColor(Color tabBorderColor) { + this.tabBorderColor = tabBorderColor; + } + + @Override + protected boolean flipPinoutLabel() { + return true; + } +} diff --git a/diylc/diylc-library/src/main/java/org/diylc/components/semiconductors/TransistorTO3.java b/diylc/diylc-library/src/main/java/org/diylc/components/semiconductors/TransistorTO3.java index e6be5fd09..357ab3b4c 100644 --- a/diylc/diylc-library/src/main/java/org/diylc/components/semiconductors/TransistorTO3.java +++ b/diylc/diylc-library/src/main/java/org/diylc/components/semiconductors/TransistorTO3.java @@ -1,395 +1,389 @@ -/* - - DIY Layout Creator (DIYLC). - Copyright (c) 2009-2025 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.semiconductors; - -import java.awt.AlphaComposite; -import java.awt.Color; -import java.awt.Composite; -import java.awt.FontMetrics; -import java.awt.Graphics2D; -import java.awt.Rectangle; -import java.awt.RenderingHints; -import java.awt.Shape; -import java.awt.geom.AffineTransform; -import java.awt.geom.Area; -import java.awt.geom.Ellipse2D; -import java.awt.geom.Point2D; -import java.awt.geom.Rectangle2D; -import org.diylc.appframework.miscutils.ConfigurationManager; - -import org.diylc.awt.TwoCircleTangent; -import org.diylc.common.Display; -import org.diylc.common.IPlugInPort; -import org.diylc.common.ObjectCache; -import org.diylc.common.Orientation; -import org.diylc.components.AbstractLabeledComponent; -import org.diylc.core.ComponentState; -import org.diylc.core.IDIYComponent; -import org.diylc.core.IDrawingObserver; -import org.diylc.core.Project; -import org.diylc.core.Theme; -import org.diylc.core.VisibilityPolicy; -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; -import org.diylc.utils.Constants; - -@ComponentDescriptor(name = "Transistor (TO-3)", author = "Branislav Stojkovic", category = "Semiconductors", - instanceNamePrefix = "Q", description = "Transistor with large metal body", - zOrder = IDIYComponent.COMPONENT, keywordPolicy = KeywordPolicy.SHOW_VALUE, enableCache = true) -public class TransistorTO3 extends AbstractLabeledComponent { - - private static final long serialVersionUID = 1L; - - public static Color BODY_COLOR = Color.lightGray; - public static Color BORDER_COLOR = BODY_COLOR.darker(); - public static Color PIN_COLOR = Color.decode("#00B2EE"); - public static Color PIN_BORDER_COLOR = PIN_COLOR.darker(); - public static Color LABEL_COLOR = Color.black; - - public static Size LARGE_DIAMETER = new Size(26.2d, SizeUnit.mm); - public static Size INNER_DIAMETER = new Size(21.3d, SizeUnit.mm); - public static Size SMALL_DIAMETER = new Size(8d, SizeUnit.mm); - public static Size HOLE_DISTANCE = new Size(30.1d, SizeUnit.mm); - public static Size HOLE_SIZE = new Size(4.1d, SizeUnit.mm); - public static Size PIN_SPACING = new Size(10.9d, SizeUnit.mm); - public static Size PIN_OFFSET = new Size(1.85d, SizeUnit.mm); - public static Size PIN_DIAMETER = new Size(1d, SizeUnit.mm); - - private String value = ""; - private Orientation orientation = Orientation.DEFAULT; - private Point2D[] controlPoints = new Point2D[] {new Point2D.Double(0, 0), new Point2D.Double(0, 0)}; - transient private Area[] body; - private Color bodyColor = BODY_COLOR; - private Color borderColor = BORDER_COLOR; - private Color labelColor = LABEL_COLOR; - protected Display display = Display.NAME; - - public TransistorTO3() { - super(); - updateControlPoints(); - alpha = (byte) 100; - } - - @EditableProperty - public String getValue() { - return value; - } - - public void setValue(String value) { - this.value = value; - } - - @EditableProperty - public Orientation getOrientation() { - return orientation; - } - - public void setOrientation(Orientation orientation) { - this.orientation = orientation; - updateControlPoints(); - // Reset body shape; - body = null; - } - - @Override - public int getControlPointCount() { - return controlPoints.length; - } - - @Override - public Point2D getControlPoint(int index) { - return controlPoints[index]; - } - - @Override - public boolean isControlPointSticky(int index) { - return true; - } - - @Override - public VisibilityPolicy getControlPointVisibilityPolicy(int index) { - return VisibilityPolicy.NEVER; - } - - @Override - public void setControlPoint(Point2D point, int index) { - controlPoints[index].setLocation(point); - body = null; - } - - private void updateControlPoints() { - int pinSpacing = (int) PIN_SPACING.convertToPixels(); - // Update control points. - double x = controlPoints[0].getX(); - double y = controlPoints[0].getY(); - switch (orientation) { - case DEFAULT: - controlPoints[1].setLocation(x, y + pinSpacing); - break; - case _90: - controlPoints[1].setLocation(x - pinSpacing, y); - break; - case _180: - controlPoints[1].setLocation(x, y - pinSpacing); - break; - case _270: - controlPoints[1].setLocation(x + pinSpacing, y); - break; - default: - throw new RuntimeException("Unexpected orientation: " + orientation); - } - } - - public Area[] getBody() { - if (body == null) { - body = new Area[2]; - int pinOffset = (int) PIN_OFFSET.convertToPixels(); - double x = (controlPoints[0].getX() + controlPoints[1].getX()) / 2; - double y = (controlPoints[0].getY() + controlPoints[1].getY()) / 2; - - switch (orientation) { - case DEFAULT: - x += pinOffset; - break; - case _90: - y += pinOffset; - break; - case _180: - x -= pinOffset; - break; - case _270: - y -= pinOffset; - break; - default: - throw new RuntimeException("Unexpected orientation: " + orientation); - } - - int largeDiameter = getClosestOdd(LARGE_DIAMETER.convertToPixels()); - int innerDiameter = getClosestOdd(INNER_DIAMETER.convertToPixels()); - int smallDiameter = getClosestOdd(SMALL_DIAMETER.convertToPixels()); - int holeDistance = getClosestOdd(HOLE_DISTANCE.convertToPixels()); - int holeSize = getClosestOdd(HOLE_SIZE.convertToPixels()); - - TwoCircleTangent left = new TwoCircleTangent(new Point2D.Double(x, y), new Point2D.Double(x - holeDistance / 2, y), largeDiameter / 2, smallDiameter / 2); - TwoCircleTangent right = new TwoCircleTangent(new Point2D.Double(x, y), new Point2D.Double(x + holeDistance / 2, y), largeDiameter / 2, smallDiameter / 2); - - body[0] = left; - body[0].add(right); - - body[0].subtract(new Area(new Ellipse2D.Double(x - holeDistance / 2 - holeSize / 2, y - holeSize / 2, holeSize, - holeSize))); - body[0].subtract(new Area(new Ellipse2D.Double(x + holeDistance / 2 - holeSize / 2, y - holeSize / 2, holeSize, - holeSize))); - - switch (orientation) { - case DEFAULT: - break; - case _90: - body[0].transform(AffineTransform.getRotateInstance(Math.PI / 2, x, y)); - break; - case _180: - body[0].transform(AffineTransform.getRotateInstance(Math.PI, x, y)); - break; - case _270: - body[0].transform(AffineTransform.getRotateInstance(Math.PI * 3 / 2, x, y)); - break; - default: - throw new RuntimeException("Unexpected orientation: " + orientation); - } - - body[1] = - new Area(new Ellipse2D.Double(x - innerDiameter / 2, y - innerDiameter / 2, innerDiameter, innerDiameter)); - } - return body; - } - - @Override - public void draw(Graphics2D g2d, ComponentState componentState, boolean outlineMode, Project project, - IDrawingObserver drawingObserver) { - if (checkPointsClipped(g2d.getClip())) { - return; - } - drawingObserver.stopTracking(); - int pinSize = (int) PIN_DIAMETER.convertToPixels() / 2 * 2; - Theme theme = (Theme) ConfigurationManager.getInstance().readObject(IPlugInPort.THEME_KEY, Constants.DEFAULT_THEME); - g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(1f)); - - for (Point2D point : controlPoints) { - if (!outlineMode) { - g2d.setColor(PIN_COLOR); - g2d.fillOval((int)(point.getX() - pinSize / 2), (int)(point.getY() - pinSize / 2), pinSize, pinSize); - } - g2d.setColor(outlineMode ? theme.getOutlineColor() : PIN_BORDER_COLOR); - g2d.drawOval((int)(point.getX() - pinSize / 2), (int)(point.getY() - pinSize / 2), pinSize, pinSize); - } - - Area mainArea = getBody()[0]; - Area innerArea = getBody()[1]; - 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 : bodyColor); - drawingObserver.startTracking(); - g2d.fill(mainArea); - drawingObserver.stopTracking(); - g2d.setComposite(oldComposite); - Color finalBorderColor; - - if (outlineMode) { - 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.setStroke(ObjectCache.getInstance().fetchBasicStroke(1)); - g2d.draw(mainArea); - g2d.draw(innerArea); - - // Draw label. - g2d.setFont(project.getFont()); - - // Override font size - if (getFontSizeOverride() != null) - g2d.setFont(g2d.getFont().deriveFont(1f * getFontSizeOverride())); - - Color finalLabelColor; - if (outlineMode) { - finalLabelColor = - componentState == ComponentState.SELECTED || componentState == ComponentState.DRAGGING ? LABEL_COLOR_SELECTED - : theme.getOutlineColor(); - } else { - finalLabelColor = - componentState == ComponentState.SELECTED || componentState == ComponentState.DRAGGING ? LABEL_COLOR_SELECTED - : getLabelColor(); - } - g2d.setColor(finalLabelColor); - String label = ""; - label = (getDisplay() == Display.NAME) ? getName() : getValue(); - if (getDisplay() == Display.NONE) { - label = ""; - } - if (getDisplay() == Display.BOTH) { - label = getName() + " " + (getValue() == null ? "" : getValue().toString()); - } - FontMetrics fontMetrics = g2d.getFontMetrics(g2d.getFont()); - Rectangle2D rect = fontMetrics.getStringBounds(label, g2d); - int textHeight = (int) (rect.getHeight()); - int textWidth = (int) (rect.getWidth()); - // Center text horizontally and vertically - Rectangle bounds = mainArea.getBounds(); - int x = (int) (bounds.getX() + (bounds.width - textWidth) / 2); - int y = (int) (bounds.getY() + (bounds.height - textHeight) / 2 + fontMetrics.getAscent()); - g2d.drawString(label, x, y); - } - - @Override - public void drawIcon(Graphics2D g2d, int width, int height) { - g2d.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_PURE); - int largeR = getClosestOdd(width * 3d / 8); - int smallR = getClosestOdd(width / 6d); - int innerD = getClosestOdd(width / 2d); - int hole = 4 * width / 32; - - Area area = new TwoCircleTangent(new Point2D.Double(width * 0.5, height * 0.5), new Point2D.Double(width / 2, height / 8d), largeR, smallR); - area.add((Area)new TwoCircleTangent(new Point2D.Double(width * 0.5, height * 0.5), new Point2D.Double(width / 2, height * 7 / 8d), largeR, smallR)); - - area.subtract(new Area(new Ellipse2D.Double((width - hole) / 2, height / 8 - hole / 2, hole, hole))); - area.subtract(new Area(new Ellipse2D.Double((width - hole) / 2, height * 7 / 8 - hole / 2, hole, hole))); - area.transform(AffineTransform.getRotateInstance(Math.PI / 4, width / 2, height / 2)); - g2d.setColor(BODY_COLOR); - g2d.fill(area); - g2d.setColor(BORDER_COLOR); - g2d.draw(area); - g2d.drawOval((width - innerD) / 2, (height - innerD) / 2, innerD, innerD); - } - - @EditableProperty(name = "Body") - public Color getBodyColor() { - return bodyColor; - } - - public void setBodyColor(Color bodyColor) { - this.bodyColor = bodyColor; - } - - @EditableProperty(name = "Border") - public Color getBorderColor() { - return borderColor; - } - - public void setBorderColor(Color borderColor) { - this.borderColor = borderColor; - } - - @EditableProperty(name = "Label") - public Color getLabelColor() { - return labelColor; - } - - public void setLabelColor(Color labelColor) { - this.labelColor = labelColor; - } - - @EditableProperty - public Display getDisplay() { - if (display == null) { - display = Display.NAME; - } - return display; - } - - public void setDisplay(Display display) { - this.display = display; - } - - @Override - public Rectangle2D getCachingBounds() { - Shape[] body = getBody(); - int margin = 20; - double minX = 0; - double minY = 0; - double maxX = 0; - double maxY = 0; - for (Shape a : body) { - if (a != null) { - Rectangle2D bounds2d = a.getBounds2D(); - if (bounds2d.getMinX() < minX) - minX = bounds2d.getMinX(); - if (bounds2d.getMinY() < minY) - minY = bounds2d.getMinY(); - if (bounds2d.getMaxX() > maxX) - maxX = bounds2d.getMaxX(); - if (bounds2d.getMaxY() > maxY) - maxY = bounds2d.getMaxY(); - } - } - return new Rectangle2D.Double(minX - margin, minY - margin, maxX - minX + 2 * margin, maxY - minY + 2 * margin); - } -} +/* + + DIY Layout Creator (DIYLC). + Copyright (c) 2009-2025 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.semiconductors; + +import java.awt.AlphaComposite; +import java.awt.Color; +import java.awt.Composite; +import java.awt.FontMetrics; +import java.awt.Graphics2D; +import java.awt.Rectangle; +import java.awt.RenderingHints; +import java.awt.Shape; +import java.awt.geom.AffineTransform; +import java.awt.geom.Area; +import java.awt.geom.Ellipse2D; +import java.awt.geom.Point2D; +import java.awt.geom.Rectangle2D; +import org.diylc.appframework.miscutils.ConfigurationManager; + +import org.diylc.awt.TwoCircleTangent; +import org.diylc.common.*; +import org.diylc.components.AbstractLabeledComponent; +import org.diylc.core.ComponentState; +import org.diylc.core.IDIYComponent; +import org.diylc.core.IDrawingObserver; +import org.diylc.core.Project; +import org.diylc.core.Theme; +import org.diylc.core.VisibilityPolicy; +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; +import org.diylc.utils.Constants; + +@ComponentDescriptor(name = "Transistor (TO-3)", author = "Branislav Stojkovic", category = "Semiconductors", + instanceNamePrefix = "Q", description = "Transistor with large metal body", + zOrder = IDIYComponent.COMPONENT, keywordPolicy = KeywordPolicy.SHOW_VALUE, enableCache = true) +public class TransistorTO3 extends AbstractLabeledComponent { + + private static final long serialVersionUID = 1L; + + public static Color BODY_COLOR = Color.lightGray; + public static Color BORDER_COLOR = BODY_COLOR.darker(); + public static Color PIN_COLOR = Color.decode("#00B2EE"); + public static Color PIN_BORDER_COLOR = PIN_COLOR.darker(); + public static Color LABEL_COLOR = Color.black; + + public static Size LARGE_DIAMETER = new Size(26.2d, SizeUnit.mm); + public static Size INNER_DIAMETER = new Size(21.3d, SizeUnit.mm); + public static Size SMALL_DIAMETER = new Size(8d, SizeUnit.mm); + public static Size HOLE_DISTANCE = new Size(30.1d, SizeUnit.mm); + public static Size HOLE_SIZE = new Size(4.1d, SizeUnit.mm); + public static Size PIN_SPACING = new Size(10.9d, SizeUnit.mm); + public static Size PIN_OFFSET = new Size(1.85d, SizeUnit.mm); + public static Size PIN_DIAMETER = new Size(1d, SizeUnit.mm); + + private String value = ""; + private Orientation orientation = Orientation.DEFAULT; + private Point2D[] controlPoints = new Point2D[] {new Point2D.Double(0, 0), new Point2D.Double(0, 0)}; + transient private Area[] body; + private Color bodyColor = BODY_COLOR; + private Color borderColor = BORDER_COLOR; + private Color labelColor = LABEL_COLOR; + protected Display display = Display.NAME; + + public TransistorTO3() { + super(); + updateControlPoints(); + this.alphaPercent = new Percentage(100); + } + + @EditableProperty + public String getValue() { + return value; + } + + public void setValue(String value) { + this.value = value; + } + + @EditableProperty + public Orientation getOrientation() { + return orientation; + } + + public void setOrientation(Orientation orientation) { + this.orientation = orientation; + updateControlPoints(); + // Reset body shape; + body = null; + } + + @Override + public int getControlPointCount() { + return controlPoints.length; + } + + @Override + public Point2D getControlPoint(int index) { + return controlPoints[index]; + } + + @Override + public boolean isControlPointSticky(int index) { + return true; + } + + @Override + public VisibilityPolicy getControlPointVisibilityPolicy(int index) { + return VisibilityPolicy.NEVER; + } + + @Override + public void setControlPoint(Point2D point, int index) { + controlPoints[index].setLocation(point); + body = null; + } + + private void updateControlPoints() { + int pinSpacing = (int) PIN_SPACING.convertToPixels(); + // Update control points. + double x = controlPoints[0].getX(); + double y = controlPoints[0].getY(); + switch (orientation) { + case DEFAULT: + controlPoints[1].setLocation(x, y + pinSpacing); + break; + case _90: + controlPoints[1].setLocation(x - pinSpacing, y); + break; + case _180: + controlPoints[1].setLocation(x, y - pinSpacing); + break; + case _270: + controlPoints[1].setLocation(x + pinSpacing, y); + break; + default: + throw new RuntimeException("Unexpected orientation: " + orientation); + } + } + + public Area[] getBody() { + if (body == null) { + body = new Area[2]; + int pinOffset = (int) PIN_OFFSET.convertToPixels(); + double x = (controlPoints[0].getX() + controlPoints[1].getX()) / 2; + double y = (controlPoints[0].getY() + controlPoints[1].getY()) / 2; + + switch (orientation) { + case DEFAULT: + x += pinOffset; + break; + case _90: + y += pinOffset; + break; + case _180: + x -= pinOffset; + break; + case _270: + y -= pinOffset; + break; + default: + throw new RuntimeException("Unexpected orientation: " + orientation); + } + + int largeDiameter = getClosestOdd(LARGE_DIAMETER.convertToPixels()); + int innerDiameter = getClosestOdd(INNER_DIAMETER.convertToPixels()); + int smallDiameter = getClosestOdd(SMALL_DIAMETER.convertToPixels()); + int holeDistance = getClosestOdd(HOLE_DISTANCE.convertToPixels()); + int holeSize = getClosestOdd(HOLE_SIZE.convertToPixels()); + + TwoCircleTangent left = new TwoCircleTangent(new Point2D.Double(x, y), new Point2D.Double(x - holeDistance / 2, y), largeDiameter / 2, smallDiameter / 2); + TwoCircleTangent right = new TwoCircleTangent(new Point2D.Double(x, y), new Point2D.Double(x + holeDistance / 2, y), largeDiameter / 2, smallDiameter / 2); + + body[0] = left; + body[0].add(right); + + body[0].subtract(new Area(new Ellipse2D.Double(x - holeDistance / 2 - holeSize / 2, y - holeSize / 2, holeSize, + holeSize))); + body[0].subtract(new Area(new Ellipse2D.Double(x + holeDistance / 2 - holeSize / 2, y - holeSize / 2, holeSize, + holeSize))); + + switch (orientation) { + case DEFAULT: + break; + case _90: + body[0].transform(AffineTransform.getRotateInstance(Math.PI / 2, x, y)); + break; + case _180: + body[0].transform(AffineTransform.getRotateInstance(Math.PI, x, y)); + break; + case _270: + body[0].transform(AffineTransform.getRotateInstance(Math.PI * 3 / 2, x, y)); + break; + default: + throw new RuntimeException("Unexpected orientation: " + orientation); + } + + body[1] = + new Area(new Ellipse2D.Double(x - innerDiameter / 2, y - innerDiameter / 2, innerDiameter, innerDiameter)); + } + return body; + } + + @Override + public void draw(Graphics2D g2d, ComponentState componentState, boolean outlineMode, Project project, + IDrawingObserver drawingObserver) { + if (checkPointsClipped(g2d.getClip())) { + return; + } + drawingObserver.stopTracking(); + int pinSize = (int) PIN_DIAMETER.convertToPixels() / 2 * 2; + Theme theme = (Theme) ConfigurationManager.getInstance().readObject(IPlugInPort.THEME_KEY, Constants.DEFAULT_THEME); + g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(1f)); + + for (Point2D point : controlPoints) { + if (!outlineMode) { + g2d.setColor(PIN_COLOR); + g2d.fillOval((int)(point.getX() - pinSize / 2), (int)(point.getY() - pinSize / 2), pinSize, pinSize); + } + g2d.setColor(outlineMode ? theme.getOutlineColor() : PIN_BORDER_COLOR); + g2d.drawOval((int)(point.getX() - pinSize / 2), (int)(point.getY() - pinSize / 2), pinSize, pinSize); + } + + Area mainArea = getBody()[0]; + Area innerArea = getBody()[1]; + Composite oldComposite = applyAlpha(g2d, componentState); + g2d.setColor(outlineMode ? Constants.TRANSPARENT_COLOR : bodyColor); + drawingObserver.startTracking(); + g2d.fill(mainArea); + drawingObserver.stopTracking(); + g2d.setComposite(oldComposite); + Color finalBorderColor; + + if (outlineMode) { + 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.setStroke(ObjectCache.getInstance().fetchBasicStroke(1)); + g2d.draw(mainArea); + g2d.draw(innerArea); + + // Draw label. + g2d.setFont(project.getFont()); + + // Override font size + if (getFontSizeOverride() != null) + g2d.setFont(g2d.getFont().deriveFont(1f * getFontSizeOverride())); + + Color finalLabelColor; + if (outlineMode) { + finalLabelColor = + componentState == ComponentState.SELECTED || componentState == ComponentState.DRAGGING ? LABEL_COLOR_SELECTED + : theme.getOutlineColor(); + } else { + finalLabelColor = + componentState == ComponentState.SELECTED || componentState == ComponentState.DRAGGING ? LABEL_COLOR_SELECTED + : getLabelColor(); + } + g2d.setColor(finalLabelColor); + String label = ""; + label = (getDisplay() == Display.NAME) ? getName() : getValue(); + if (getDisplay() == Display.NONE) { + label = ""; + } + if (getDisplay() == Display.BOTH) { + label = getName() + " " + (getValue() == null ? "" : getValue().toString()); + } + FontMetrics fontMetrics = g2d.getFontMetrics(g2d.getFont()); + Rectangle2D rect = fontMetrics.getStringBounds(label, g2d); + int textHeight = (int) (rect.getHeight()); + int textWidth = (int) (rect.getWidth()); + // Center text horizontally and vertically + Rectangle bounds = mainArea.getBounds(); + int x = (int) (bounds.getX() + (bounds.width - textWidth) / 2); + int y = (int) (bounds.getY() + (bounds.height - textHeight) / 2 + fontMetrics.getAscent()); + g2d.drawString(label, x, y); + } + + @Override + public void drawIcon(Graphics2D g2d, int width, int height) { + g2d.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_PURE); + int largeR = getClosestOdd(width * 3d / 8); + int smallR = getClosestOdd(width / 6d); + int innerD = getClosestOdd(width / 2d); + int hole = 4 * width / 32; + + Area area = new TwoCircleTangent(new Point2D.Double(width * 0.5, height * 0.5), new Point2D.Double(width / 2, height / 8d), largeR, smallR); + area.add((Area)new TwoCircleTangent(new Point2D.Double(width * 0.5, height * 0.5), new Point2D.Double(width / 2, height * 7 / 8d), largeR, smallR)); + + area.subtract(new Area(new Ellipse2D.Double((width - hole) / 2, height / 8 - hole / 2, hole, hole))); + area.subtract(new Area(new Ellipse2D.Double((width - hole) / 2, height * 7 / 8 - hole / 2, hole, hole))); + area.transform(AffineTransform.getRotateInstance(Math.PI / 4, width / 2, height / 2)); + g2d.setColor(BODY_COLOR); + g2d.fill(area); + g2d.setColor(BORDER_COLOR); + g2d.draw(area); + g2d.drawOval((width - innerD) / 2, (height - innerD) / 2, innerD, innerD); + } + + @EditableProperty(name = "Body") + public Color getBodyColor() { + return bodyColor; + } + + public void setBodyColor(Color bodyColor) { + this.bodyColor = bodyColor; + } + + @EditableProperty(name = "Border") + public Color getBorderColor() { + return borderColor; + } + + public void setBorderColor(Color borderColor) { + this.borderColor = borderColor; + } + + @EditableProperty(name = "Label") + public Color getLabelColor() { + return labelColor; + } + + public void setLabelColor(Color labelColor) { + this.labelColor = labelColor; + } + + @EditableProperty + public Display getDisplay() { + if (display == null) { + display = Display.NAME; + } + return display; + } + + public void setDisplay(Display display) { + this.display = display; + } + + @Override + public Rectangle2D getCachingBounds() { + Shape[] body = getBody(); + int margin = 20; + double minX = 0; + double minY = 0; + double maxX = 0; + double maxY = 0; + for (Shape a : body) { + if (a != null) { + Rectangle2D bounds2d = a.getBounds2D(); + if (bounds2d.getMinX() < minX) + minX = bounds2d.getMinX(); + if (bounds2d.getMinY() < minY) + minY = bounds2d.getMinY(); + if (bounds2d.getMaxX() > maxX) + maxX = bounds2d.getMaxX(); + if (bounds2d.getMaxY() > maxY) + maxY = bounds2d.getMaxY(); + } + } + return new Rectangle2D.Double(minX - margin, minY - margin, maxX - minX + 2 * margin, maxY - minY + 2 * margin); + } +} diff --git a/diylc/diylc-library/src/main/java/org/diylc/components/semiconductors/TransistorTO92.java b/diylc/diylc-library/src/main/java/org/diylc/components/semiconductors/TransistorTO92.java index 0454f139f..c126a6b63 100644 --- a/diylc/diylc-library/src/main/java/org/diylc/components/semiconductors/TransistorTO92.java +++ b/diylc/diylc-library/src/main/java/org/diylc/components/semiconductors/TransistorTO92.java @@ -1,291 +1,289 @@ -/* - - DIY Layout Creator (DIYLC). - Copyright (c) 2009-2025 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.semiconductors; - -import java.awt.AlphaComposite; -import java.awt.Color; -import java.awt.Composite; -import java.awt.FontMetrics; -import java.awt.Graphics2D; -import java.awt.Rectangle; -import java.awt.RenderingHints; -import java.awt.Shape; -import java.awt.geom.Area; -import java.awt.geom.Ellipse2D; -import java.awt.geom.Point2D; -import java.awt.geom.Rectangle2D; -import org.diylc.appframework.miscutils.ConfigurationManager; - -import org.diylc.common.IPlugInPort; -import org.diylc.common.ObjectCache; -import org.diylc.components.transform.TO92Transformer; -import org.diylc.core.ComponentState; -import org.diylc.core.IDIYComponent; -import org.diylc.core.IDrawingObserver; -import org.diylc.core.Project; -import org.diylc.core.Theme; -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; -import org.diylc.utils.Constants; - -@ComponentDescriptor(name = "Transistor (TO-92)", author = "Branislav Stojkovic", category = "Semiconductors", - instanceNamePrefix = "Q", description = "Transistor with small plastic or epoxy body", - zOrder = IDIYComponent.COMPONENT, keywordPolicy = KeywordPolicy.SHOW_VALUE, transformer = TO92Transformer.class, - enableCache = true) -public class TransistorTO92 extends AbstractTransistorPackage { - - private static final long serialVersionUID = 1L; - - public static Color BODY_COLOR = Color.gray; - public static Color BORDER_COLOR = Color.gray.darker(); - public static Color PIN_COLOR = Color.decode("#00B2EE"); - public static Color PIN_BORDER_COLOR = PIN_COLOR.darker(); - public static Color LABEL_COLOR = Color.white; - public static Size PIN_SIZE = new Size(0.03d, SizeUnit.in); - public static Size PIN_SPACING = new Size(0.05d, SizeUnit.in); - public static Size BODY_DIAMETER = new Size(0.2d, SizeUnit.in); - - private Size pinSpacing = PIN_SPACING; - - public TransistorTO92() { - super(); - updateControlPoints(); - alpha = (byte) 100; - bodyColor = BODY_COLOR; - borderColor = BORDER_COLOR; - } - - @EditableProperty(name = "Pin spacing") - public Size getPinSpacing() { - if (pinSpacing == null) { - pinSpacing = new Size(0.1, SizeUnit.in); - } - return pinSpacing; - } - - public void setPinSpacing(Size pinSpacing) { - this.pinSpacing = pinSpacing; - updateControlPoints(); - // Reset body shape; - body = null; - } - - @Override - protected void updateControlPoints() { - int pinSpacing = (int) getPinSpacing().convertToPixels(); - // Update control points. - double x = controlPoints[0].getX(); - double y = controlPoints[0].getY(); - switch (orientation) { - case DEFAULT: - controlPoints[1].setLocation(x, y + pinSpacing); - controlPoints[2].setLocation(x, y + 2 * pinSpacing); - break; - case _90: - controlPoints[1].setLocation(x - pinSpacing, y); - controlPoints[2].setLocation(x - 2 * pinSpacing, y); - break; - case _180: - controlPoints[1].setLocation(x, y - pinSpacing); - controlPoints[2].setLocation(x, y - 2 * pinSpacing); - break; - case _270: - controlPoints[1].setLocation(x + pinSpacing, y); - controlPoints[2].setLocation(x + 2 * pinSpacing, y); - break; - default: - throw new RuntimeException("Unexpected orientation: " + orientation); - } - } - - public Area[] getBody() { - if (body == null) { - double x = (controlPoints[0].getX() + controlPoints[1].getX() + controlPoints[2].getX()) / 3; - double y = (controlPoints[0].getY() + controlPoints[1].getY() + controlPoints[2].getY()) / 3; - int bodyDiameter = getClosestOdd(BODY_DIAMETER.convertToPixels()); - - Area newBody = null; - - if (folded) { - switch (orientation) { - case DEFAULT: - newBody = new Area(new Rectangle2D.Double(x, y - bodyDiameter / 2, bodyDiameter, bodyDiameter)); - break; - case _90: - newBody = new Area(new Rectangle2D.Double(x - bodyDiameter / 2, y, bodyDiameter, bodyDiameter)); - break; - case _180: - newBody = new Area(new Rectangle2D.Double(x - bodyDiameter, y - bodyDiameter / 2, bodyDiameter, bodyDiameter)); - break; - case _270: - newBody = new Area(new Rectangle2D.Double(x - bodyDiameter / 2, y - bodyDiameter, bodyDiameter, bodyDiameter)); - break; - default: - throw new RuntimeException("Unexpected orientation: " + orientation); - } - } else { - switch (orientation) { - case DEFAULT: - newBody = - new Area(new Ellipse2D.Double(x - bodyDiameter / 2, y - bodyDiameter / 2, bodyDiameter, bodyDiameter)); - newBody.subtract(new Area(new Rectangle2D.Double(x - bodyDiameter, y - bodyDiameter / 2, 3 * bodyDiameter / 4, - bodyDiameter))); - break; - case _90: - newBody = - new Area(new Ellipse2D.Double(x - bodyDiameter / 2, y - bodyDiameter / 2, bodyDiameter, bodyDiameter)); - newBody.subtract(new Area(new Rectangle2D.Double(x - bodyDiameter / 2, y - bodyDiameter, bodyDiameter, - 3 * bodyDiameter / 4))); - break; - case _180: - newBody = - new Area(new Ellipse2D.Double(x - bodyDiameter / 2, y - bodyDiameter / 2, bodyDiameter, bodyDiameter)); - newBody.subtract(new Area(new Rectangle2D.Double(x + bodyDiameter / 4, y - bodyDiameter / 2, - 3 * bodyDiameter / 4, bodyDiameter))); - break; - case _270: - newBody = - new Area(new Ellipse2D.Double(x - bodyDiameter / 2, y - bodyDiameter / 2, bodyDiameter, bodyDiameter)); - newBody.subtract(new Area(new Rectangle2D.Double(x - bodyDiameter / 2, y + bodyDiameter / 4, bodyDiameter, - 3 * bodyDiameter / 4))); - break; - default: - throw new RuntimeException("Unexpected orientation: " + orientation); - } - } - - body = new Area[] { newBody }; - } - return body; - } - - @Override - public void draw(Graphics2D g2d, ComponentState componentState, boolean outlineMode, Project project, - IDrawingObserver drawingObserver) { - if (checkPointsClipped(g2d.getClip())) { - return; - } - drawingObserver.stopTracking(); - int pinSize = (int) PIN_SIZE.convertToPixels() / 2 * 2; - g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(1f)); - - if (!outlineMode) { - for (Point2D point : controlPoints) { - Shape pin = new Ellipse2D.Double(point.getX() - pinSize / 2, point.getY() - pinSize / 2, pinSize, pinSize); - g2d.setColor(PIN_COLOR); - g2d.fill(pin); - g2d.setColor(PIN_BORDER_COLOR); - g2d.draw(pin); - } - } - - Area mainArea = getBody()[0]; - 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 : bodyColor); - drawingObserver.startTracking(); - g2d.fill(mainArea); - drawingObserver.stopTracking(); - 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.setStroke(ObjectCache.getInstance().fetchBasicStroke(1)); - g2d.draw(mainArea); - - // Draw label. - g2d.setFont(project.getFont()); - - // Override font size - if (getFontSizeOverride() != null) - g2d.setFont(g2d.getFont().deriveFont(1f * getFontSizeOverride())); - - 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 - : getLabelColor(); - } - g2d.setColor(finalLabelColor); - if (getDisplay() == TransistorDisplay.PINOUT) { - drawPinout(g2d); - } else { - String label = ""; - label = (getDisplay() == TransistorDisplay.NAME) ? getName() : getValue(); - if (display == TransistorDisplay.NONE) { - label = ""; - } - if (display == TransistorDisplay.BOTH) { - label = getName() + " " + getValue(); - } - FontMetrics fontMetrics = g2d.getFontMetrics(g2d.getFont()); - Rectangle2D rect = fontMetrics.getStringBounds(label, g2d); - int textHeight = (int) (rect.getHeight()); - int textWidth = (int) (rect.getWidth()); - // Center text horizontally and vertically - Rectangle bounds = mainArea.getBounds(); - int x = (int) (bounds.getX() + (bounds.width - textWidth) / 2); - int y = (int) (bounds.getY() + (bounds.height - textHeight) / 2 + fontMetrics.getAscent()); - g2d.drawString(label, x, y); - } - } - - @Override - public void drawIcon(Graphics2D g2d, int width, int height) { - g2d.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_PURE); - int margin = 3 * width / 32; - Area area = new Area(new Ellipse2D.Double(margin / 2, margin, width - 2 * margin, width - 2 * margin)); - // area.subtract(new Area(new Rectangle2D.Double(0, 0, 2 * margin, - // height))); - area.intersect(new Area(new Rectangle2D.Double(2 * margin, 0, width, height))); - g2d.setColor(BODY_COLOR); - g2d.fill(area); - g2d.setColor(BORDER_COLOR); - g2d.draw(area); - g2d.setColor(PIN_COLOR); - int pinSize = 2 * width / 32; - for (int i = 0; i < 3; i++) { - g2d.fillOval(width / 2 - pinSize / 2, (height / 4) * (i + 1), pinSize, pinSize); - } - } -} +/* + + DIY Layout Creator (DIYLC). + Copyright (c) 2009-2025 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.semiconductors; + +import java.awt.AlphaComposite; +import java.awt.Color; +import java.awt.Composite; +import java.awt.FontMetrics; +import java.awt.Graphics2D; +import java.awt.Rectangle; +import java.awt.RenderingHints; +import java.awt.Shape; +import java.awt.geom.Area; +import java.awt.geom.Ellipse2D; +import java.awt.geom.Point2D; +import java.awt.geom.Rectangle2D; +import org.diylc.appframework.miscutils.ConfigurationManager; + +import org.diylc.common.IPlugInPort; +import org.diylc.common.ObjectCache; +import org.diylc.common.Percentage; +import org.diylc.components.transform.TO92Transformer; +import org.diylc.core.ComponentState; +import org.diylc.core.IDIYComponent; +import org.diylc.core.IDrawingObserver; +import org.diylc.core.Project; +import org.diylc.core.Theme; +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; +import org.diylc.utils.Constants; + +@ComponentDescriptor(name = "Transistor (TO-92)", author = "Branislav Stojkovic", category = "Semiconductors", + instanceNamePrefix = "Q", description = "Transistor with small plastic or epoxy body", + zOrder = IDIYComponent.COMPONENT, keywordPolicy = KeywordPolicy.SHOW_VALUE, transformer = TO92Transformer.class, + enableCache = true) +public class TransistorTO92 extends AbstractTransistorPackage { + + private static final long serialVersionUID = 1L; + + public static Color BODY_COLOR = Color.gray; + public static Color BORDER_COLOR = Color.gray.darker(); + public static Color PIN_COLOR = Color.decode("#00B2EE"); + public static Color PIN_BORDER_COLOR = PIN_COLOR.darker(); + public static Color LABEL_COLOR = Color.white; + public static Size PIN_SIZE = new Size(0.03d, SizeUnit.in); + public static Size PIN_SPACING = new Size(0.05d, SizeUnit.in); + public static Size BODY_DIAMETER = new Size(0.2d, SizeUnit.in); + + private Size pinSpacing = PIN_SPACING; + + public TransistorTO92() { + super(); + updateControlPoints(); + this.alphaPercent = new Percentage(100); + bodyColor = BODY_COLOR; + borderColor = BORDER_COLOR; + } + + @EditableProperty(name = "Pin spacing") + public Size getPinSpacing() { + if (pinSpacing == null) { + pinSpacing = new Size(0.1, SizeUnit.in); + } + return pinSpacing; + } + + public void setPinSpacing(Size pinSpacing) { + this.pinSpacing = pinSpacing; + updateControlPoints(); + // Reset body shape; + body = null; + } + + @Override + protected void updateControlPoints() { + int pinSpacing = (int) getPinSpacing().convertToPixels(); + // Update control points. + double x = controlPoints[0].getX(); + double y = controlPoints[0].getY(); + switch (orientation) { + case DEFAULT: + controlPoints[1].setLocation(x, y + pinSpacing); + controlPoints[2].setLocation(x, y + 2 * pinSpacing); + break; + case _90: + controlPoints[1].setLocation(x - pinSpacing, y); + controlPoints[2].setLocation(x - 2 * pinSpacing, y); + break; + case _180: + controlPoints[1].setLocation(x, y - pinSpacing); + controlPoints[2].setLocation(x, y - 2 * pinSpacing); + break; + case _270: + controlPoints[1].setLocation(x + pinSpacing, y); + controlPoints[2].setLocation(x + 2 * pinSpacing, y); + break; + default: + throw new RuntimeException("Unexpected orientation: " + orientation); + } + } + + public Area[] getBody() { + if (body == null) { + double x = (controlPoints[0].getX() + controlPoints[1].getX() + controlPoints[2].getX()) / 3; + double y = (controlPoints[0].getY() + controlPoints[1].getY() + controlPoints[2].getY()) / 3; + int bodyDiameter = getClosestOdd(BODY_DIAMETER.convertToPixels()); + + Area newBody = null; + + if (folded) { + switch (orientation) { + case DEFAULT: + newBody = new Area(new Rectangle2D.Double(x, y - bodyDiameter / 2, bodyDiameter, bodyDiameter)); + break; + case _90: + newBody = new Area(new Rectangle2D.Double(x - bodyDiameter / 2, y, bodyDiameter, bodyDiameter)); + break; + case _180: + newBody = new Area(new Rectangle2D.Double(x - bodyDiameter, y - bodyDiameter / 2, bodyDiameter, bodyDiameter)); + break; + case _270: + newBody = new Area(new Rectangle2D.Double(x - bodyDiameter / 2, y - bodyDiameter, bodyDiameter, bodyDiameter)); + break; + default: + throw new RuntimeException("Unexpected orientation: " + orientation); + } + } else { + switch (orientation) { + case DEFAULT: + newBody = + new Area(new Ellipse2D.Double(x - bodyDiameter / 2, y - bodyDiameter / 2, bodyDiameter, bodyDiameter)); + newBody.subtract(new Area(new Rectangle2D.Double(x - bodyDiameter, y - bodyDiameter / 2, 3 * bodyDiameter / 4, + bodyDiameter))); + break; + case _90: + newBody = + new Area(new Ellipse2D.Double(x - bodyDiameter / 2, y - bodyDiameter / 2, bodyDiameter, bodyDiameter)); + newBody.subtract(new Area(new Rectangle2D.Double(x - bodyDiameter / 2, y - bodyDiameter, bodyDiameter, + 3 * bodyDiameter / 4))); + break; + case _180: + newBody = + new Area(new Ellipse2D.Double(x - bodyDiameter / 2, y - bodyDiameter / 2, bodyDiameter, bodyDiameter)); + newBody.subtract(new Area(new Rectangle2D.Double(x + bodyDiameter / 4, y - bodyDiameter / 2, + 3 * bodyDiameter / 4, bodyDiameter))); + break; + case _270: + newBody = + new Area(new Ellipse2D.Double(x - bodyDiameter / 2, y - bodyDiameter / 2, bodyDiameter, bodyDiameter)); + newBody.subtract(new Area(new Rectangle2D.Double(x - bodyDiameter / 2, y + bodyDiameter / 4, bodyDiameter, + 3 * bodyDiameter / 4))); + break; + default: + throw new RuntimeException("Unexpected orientation: " + orientation); + } + } + + body = new Area[] { newBody }; + } + return body; + } + + @Override + public void draw(Graphics2D g2d, ComponentState componentState, boolean outlineMode, Project project, + IDrawingObserver drawingObserver) { + if (checkPointsClipped(g2d.getClip())) { + return; + } + drawingObserver.stopTracking(); + int pinSize = (int) PIN_SIZE.convertToPixels() / 2 * 2; + g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(1f)); + + if (!outlineMode) { + for (Point2D point : controlPoints) { + Shape pin = new Ellipse2D.Double(point.getX() - pinSize / 2, point.getY() - pinSize / 2, pinSize, pinSize); + g2d.setColor(PIN_COLOR); + g2d.fill(pin); + g2d.setColor(PIN_BORDER_COLOR); + g2d.draw(pin); + } + } + + Area mainArea = getBody()[0]; + Composite oldComposite = applyAlpha(g2d, componentState); + g2d.setColor(outlineMode ? Constants.TRANSPARENT_COLOR : bodyColor); + drawingObserver.startTracking(); + g2d.fill(mainArea); + drawingObserver.stopTracking(); + 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.setStroke(ObjectCache.getInstance().fetchBasicStroke(1)); + g2d.draw(mainArea); + + // Draw label. + g2d.setFont(project.getFont()); + + // Override font size + if (getFontSizeOverride() != null) + g2d.setFont(g2d.getFont().deriveFont(1f * getFontSizeOverride())); + + 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 + : getLabelColor(); + } + g2d.setColor(finalLabelColor); + if (getDisplay() == TransistorDisplay.PINOUT) { + drawPinout(g2d); + } else { + String label = ""; + label = (getDisplay() == TransistorDisplay.NAME) ? getName() : getValue(); + if (display == TransistorDisplay.NONE) { + label = ""; + } + if (display == TransistorDisplay.BOTH) { + label = getName() + " " + getValue(); + } + FontMetrics fontMetrics = g2d.getFontMetrics(g2d.getFont()); + Rectangle2D rect = fontMetrics.getStringBounds(label, g2d); + int textHeight = (int) (rect.getHeight()); + int textWidth = (int) (rect.getWidth()); + // Center text horizontally and vertically + Rectangle bounds = mainArea.getBounds(); + int x = (int) (bounds.getX() + (bounds.width - textWidth) / 2); + int y = (int) (bounds.getY() + (bounds.height - textHeight) / 2 + fontMetrics.getAscent()); + g2d.drawString(label, x, y); + } + } + + @Override + public void drawIcon(Graphics2D g2d, int width, int height) { + g2d.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_PURE); + int margin = 3 * width / 32; + Area area = new Area(new Ellipse2D.Double(margin / 2, margin, width - 2 * margin, width - 2 * margin)); + // area.subtract(new Area(new Rectangle2D.Double(0, 0, 2 * margin, + // height))); + area.intersect(new Area(new Rectangle2D.Double(2 * margin, 0, width, height))); + g2d.setColor(BODY_COLOR); + g2d.fill(area); + g2d.setColor(BORDER_COLOR); + g2d.draw(area); + g2d.setColor(PIN_COLOR); + int pinSize = 2 * width / 32; + for (int i = 0; i < 3; i++) { + g2d.fillOval(width / 2 - pinSize / 2, (height / 4) * (i + 1), pinSize, pinSize); + } + } +} diff --git a/diylc/diylc-library/src/main/java/org/diylc/components/shapes/Ellipse.java b/diylc/diylc-library/src/main/java/org/diylc/components/shapes/Ellipse.java index 0c992eef5..2a2bdf968 100644 --- a/diylc/diylc-library/src/main/java/org/diylc/components/shapes/Ellipse.java +++ b/diylc/diylc-library/src/main/java/org/diylc/components/shapes/Ellipse.java @@ -1,76 +1,71 @@ -/* - - DIY Layout Creator (DIYLC). - Copyright (c) 2009-2025 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.shapes; - -import java.awt.AlphaComposite; -import java.awt.Composite; -import java.awt.Graphics2D; - -import org.diylc.common.ObjectCache; -import org.diylc.components.transform.SimpleComponentTransformer; -import org.diylc.core.ComponentState; -import org.diylc.core.IDIYComponent; -import org.diylc.core.IDrawingObserver; -import org.diylc.core.Project; -import org.diylc.core.annotations.BomPolicy; -import org.diylc.core.annotations.ComponentDescriptor; - -@ComponentDescriptor(name = "Ellipse", author = "Branislav Stojkovic", category = "Shapes", instanceNamePrefix = "ELL", - description = "Elliptical area", zOrder = IDIYComponent.COMPONENT, flexibleZOrder = true, - bomPolicy = BomPolicy.NEVER_SHOW, transformer = SimpleComponentTransformer.class) -public class Ellipse extends AbstractShapeWithDimensions { - - private static final long serialVersionUID = 1L; - - @Override - public void draw(Graphics2D g2d, ComponentState componentState, boolean outlineMode, Project project, - IDrawingObserver drawingObserver) { - g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke((int) borderThickness.convertToPixels())); - - float alpha = this.alpha; - if (componentState == ComponentState.DRAGGING) - alpha = 0; - Composite oldComposite = g2d.getComposite(); - if (alpha < MAX_ALPHA) { - g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1f * alpha / MAX_ALPHA)); - } - g2d.setColor(color); - g2d.fillOval((int)firstPoint.getX(), (int)firstPoint.getY(), (int)(secondPoint.getX() - firstPoint.getX()), (int)(secondPoint.getY() - firstPoint.getY())); - g2d.setComposite(oldComposite); - - // Do not track any changes that follow because the whole oval has been - // tracked so far. - drawingObserver.stopTracking(); - g2d.setColor(componentState == ComponentState.SELECTED || componentState == ComponentState.DRAGGING ? SELECTION_COLOR - : borderColor); - g2d.drawOval((int)firstPoint.getX(), (int)firstPoint.getY(), (int)(secondPoint.getX() - firstPoint.getX()), (int)(secondPoint.getY() - firstPoint.getY())); - } - - @Override - public void drawIcon(Graphics2D g2d, int width, int height) { - int factor = 32 / width; - g2d.setColor(COLOR); - g2d.fillOval(2 / factor, 2 / factor, width - 4 / factor, height - 4 / factor); - g2d.setColor(BORDER_COLOR); - g2d.drawOval(2 / factor, 2 / factor, width - 4 / factor, height - 4 / factor); - } -} +/* + + DIY Layout Creator (DIYLC). + Copyright (c) 2009-2025 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.shapes; + +import java.awt.AlphaComposite; +import java.awt.Composite; +import java.awt.Graphics2D; + +import org.diylc.common.ObjectCache; +import org.diylc.common.Percentage; +import org.diylc.components.transform.SimpleComponentTransformer; +import org.diylc.core.ComponentState; +import org.diylc.core.IDIYComponent; +import org.diylc.core.IDrawingObserver; +import org.diylc.core.Project; +import org.diylc.core.annotations.BomPolicy; +import org.diylc.core.annotations.ComponentDescriptor; + +@ComponentDescriptor(name = "Ellipse", author = "Branislav Stojkovic", category = "Shapes", instanceNamePrefix = "ELL", + description = "Elliptical area", zOrder = IDIYComponent.COMPONENT, flexibleZOrder = true, + bomPolicy = BomPolicy.NEVER_SHOW, transformer = SimpleComponentTransformer.class) +public class Ellipse extends AbstractShapeWithDimensions { + + private static final long serialVersionUID = 1L; + + @Override + public void draw(Graphics2D g2d, ComponentState componentState, boolean outlineMode, Project project, + IDrawingObserver drawingObserver) { + g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke((int) borderThickness.convertToPixels())); + + Composite oldComposite = applyAlpha(g2d, componentState); + g2d.setColor(color); + g2d.fillOval((int)firstPoint.getX(), (int)firstPoint.getY(), (int)(secondPoint.getX() - firstPoint.getX()), (int)(secondPoint.getY() - firstPoint.getY())); + g2d.setComposite(oldComposite); + + // Do not track any changes that follow because the whole oval has been + // tracked so far. + drawingObserver.stopTracking(); + g2d.setColor(componentState == ComponentState.SELECTED || componentState == ComponentState.DRAGGING ? SELECTION_COLOR + : borderColor); + g2d.drawOval((int)firstPoint.getX(), (int)firstPoint.getY(), (int)(secondPoint.getX() - firstPoint.getX()), (int)(secondPoint.getY() - firstPoint.getY())); + } + + @Override + public void drawIcon(Graphics2D g2d, int width, int height) { + int factor = 32 / width; + g2d.setColor(COLOR); + g2d.fillOval(2 / factor, 2 / factor, width - 4 / factor, height - 4 / factor); + g2d.setColor(BORDER_COLOR); + g2d.drawOval(2 / factor, 2 / factor, width - 4 / factor, height - 4 / factor); + } +} diff --git a/diylc/diylc-library/src/main/java/org/diylc/components/shapes/Polygon.java b/diylc/diylc-library/src/main/java/org/diylc/components/shapes/Polygon.java index f770b46d0..75175ca41 100644 --- a/diylc/diylc-library/src/main/java/org/diylc/components/shapes/Polygon.java +++ b/diylc/diylc-library/src/main/java/org/diylc/components/shapes/Polygon.java @@ -1,129 +1,126 @@ -/* - - DIY Layout Creator (DIYLC). - Copyright (c) 2009-2025 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.shapes; - -import java.awt.AlphaComposite; -import java.awt.Color; -import java.awt.Composite; -import java.awt.Graphics2D; -import java.awt.geom.Point2D; -import java.util.Arrays; - -import org.diylc.common.ObjectCache; -import org.diylc.components.transform.SimpleComponentTransformer; -import org.diylc.core.ComponentState; -import org.diylc.core.IDIYComponent; -import org.diylc.core.IDrawingObserver; -import org.diylc.core.Project; -import org.diylc.core.annotations.BomPolicy; -import org.diylc.core.annotations.ComponentDescriptor; -import org.diylc.core.annotations.EditableProperty; - -@ComponentDescriptor(name = "Polygon", author = "Branislav Stojkovic", category = "Shapes", - instanceNamePrefix = "POLY", description = "Polygonal area", zOrder = IDIYComponent.COMPONENT, - flexibleZOrder = true, bomPolicy = BomPolicy.NEVER_SHOW, - transformer = SimpleComponentTransformer.class) -public class Polygon extends AbstractShape { - - private static final long serialVersionUID = 1L; - - protected PointCount pointCount = PointCount._4; - - public Polygon() { - super(); - this.controlPoints = - new Point2D[] {new Point2D.Double(0, 0), - new Point2D.Double(0, (int) DEFAULT_HEIGHT.convertToPixels()), - new Point2D.Double((int) DEFAULT_WIDTH.convertToPixels(), (int) DEFAULT_HEIGHT.convertToPixels()), - new Point2D.Double((int) DEFAULT_WIDTH.convertToPixels(), 0)}; - } - - @Override - public void draw(Graphics2D g2d, ComponentState componentState, boolean outlineMode, Project project, - IDrawingObserver drawingObserver) { - g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke((int) borderThickness.convertToPixels())); - g2d.setColor(color); - int[] xPoints = new int[controlPoints.length]; - int[] yPoints = new int[controlPoints.length]; - for (int i = 0; i < controlPoints.length; i++) { - xPoints[i] = (int)controlPoints[i].getX(); - yPoints[i] = (int)controlPoints[i].getY(); - } - - Composite oldComposite = g2d.getComposite(); - if (this.alpha < MAX_ALPHA) { - g2d.setComposite(AlphaComposite.getInstance(3, 1.0F * this.alpha / MAX_ALPHA)); - } - g2d.fillPolygon(xPoints, yPoints, controlPoints.length); - g2d.setComposite(oldComposite); - - // Do not track any changes that follow because the whole board has been - // tracked so far. - drawingObserver.stopTracking(); - Color lineColor = - componentState == ComponentState.SELECTED || componentState == ComponentState.DRAGGING ? SELECTION_COLOR - : borderColor; - g2d.setColor(lineColor); - g2d.drawPolygon(xPoints, yPoints, controlPoints.length); - } - - @EditableProperty(name = "Edges") - public PointCount getPointCount() { - return pointCount; - } - - public void setPointCount(PointCount pointCount) { - if (this.pointCount == pointCount) - return; - int oldPointCount = Integer.parseInt(this.pointCount.toString()); - int newPointCount = Integer.parseInt(pointCount.toString()); - this.controlPoints = Arrays.copyOf(this.controlPoints, newPointCount); - if (oldPointCount < newPointCount) { - this.controlPoints[newPointCount - 1] = this.controlPoints[oldPointCount - 1]; - for (int i = oldPointCount - 1; i < newPointCount - 1; i++) { - this.controlPoints[i] = - new Point2D.Double((this.controlPoints[i - 1].getX() + this.controlPoints[newPointCount - 1].getX()) / 2, - (this.controlPoints[i - 1].getY() + this.controlPoints[newPointCount - 1].getY()) / 2); - } - } - this.pointCount = pointCount; - } - - @Override - public void drawIcon(Graphics2D g2d, int width, int height) { - int factor = 32 / width; - g2d.setColor(COLOR); - int[] x = {2 / factor, width - 2 / factor, width - 4 / factor, 3 / factor}; - int[] y = {4 / factor, 2 / factor, height - 5 / factor, height - 2 / factor}; - g2d.fillPolygon(x, y, 4); - g2d.setColor(BORDER_COLOR); - g2d.drawPolygon(x, y, 4); - } - - public enum PointCount { - _3, _4, _5, _6, _7, _8; - - public String toString() { - return name().substring(1); - }; - } -} +/* + + DIY Layout Creator (DIYLC). + Copyright (c) 2009-2025 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.shapes; + +import java.awt.AlphaComposite; +import java.awt.Color; +import java.awt.Composite; +import java.awt.Graphics2D; +import java.awt.geom.Point2D; +import java.util.Arrays; + +import org.diylc.common.ObjectCache; +import org.diylc.components.transform.SimpleComponentTransformer; +import org.diylc.core.ComponentState; +import org.diylc.core.IDIYComponent; +import org.diylc.core.IDrawingObserver; +import org.diylc.core.Project; +import org.diylc.core.annotations.BomPolicy; +import org.diylc.core.annotations.ComponentDescriptor; +import org.diylc.core.annotations.EditableProperty; + +@ComponentDescriptor(name = "Polygon", author = "Branislav Stojkovic", category = "Shapes", + instanceNamePrefix = "POLY", description = "Polygonal area", zOrder = IDIYComponent.COMPONENT, + flexibleZOrder = true, bomPolicy = BomPolicy.NEVER_SHOW, + transformer = SimpleComponentTransformer.class) +public class Polygon extends AbstractShape { + + private static final long serialVersionUID = 1L; + + protected PointCount pointCount = PointCount._4; + + public Polygon() { + super(); + this.controlPoints = + new Point2D[] {new Point2D.Double(0, 0), + new Point2D.Double(0, (int) DEFAULT_HEIGHT.convertToPixels()), + new Point2D.Double((int) DEFAULT_WIDTH.convertToPixels(), (int) DEFAULT_HEIGHT.convertToPixels()), + new Point2D.Double((int) DEFAULT_WIDTH.convertToPixels(), 0)}; + } + + @Override + public void draw(Graphics2D g2d, ComponentState componentState, boolean outlineMode, Project project, + IDrawingObserver drawingObserver) { + g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke((int) borderThickness.convertToPixels())); + g2d.setColor(color); + int[] xPoints = new int[controlPoints.length]; + int[] yPoints = new int[controlPoints.length]; + for (int i = 0; i < controlPoints.length; i++) { + xPoints[i] = (int)controlPoints[i].getX(); + yPoints[i] = (int)controlPoints[i].getY(); + } + + Composite oldComposite = applyAlpha(g2d, componentState); + g2d.fillPolygon(xPoints, yPoints, controlPoints.length); + g2d.setComposite(oldComposite); + + // Do not track any changes that follow because the whole board has been + // tracked so far. + drawingObserver.stopTracking(); + Color lineColor = + componentState == ComponentState.SELECTED || componentState == ComponentState.DRAGGING ? SELECTION_COLOR + : borderColor; + g2d.setColor(lineColor); + g2d.drawPolygon(xPoints, yPoints, controlPoints.length); + } + + @EditableProperty(name = "Edges") + public PointCount getPointCount() { + return pointCount; + } + + public void setPointCount(PointCount pointCount) { + if (this.pointCount == pointCount) + return; + int oldPointCount = Integer.parseInt(this.pointCount.toString()); + int newPointCount = Integer.parseInt(pointCount.toString()); + this.controlPoints = Arrays.copyOf(this.controlPoints, newPointCount); + if (oldPointCount < newPointCount) { + this.controlPoints[newPointCount - 1] = this.controlPoints[oldPointCount - 1]; + for (int i = oldPointCount - 1; i < newPointCount - 1; i++) { + this.controlPoints[i] = + new Point2D.Double((this.controlPoints[i - 1].getX() + this.controlPoints[newPointCount - 1].getX()) / 2, + (this.controlPoints[i - 1].getY() + this.controlPoints[newPointCount - 1].getY()) / 2); + } + } + this.pointCount = pointCount; + } + + @Override + public void drawIcon(Graphics2D g2d, int width, int height) { + int factor = 32 / width; + g2d.setColor(COLOR); + int[] x = {2 / factor, width - 2 / factor, width - 4 / factor, 3 / factor}; + int[] y = {4 / factor, 2 / factor, height - 5 / factor, height - 2 / factor}; + g2d.fillPolygon(x, y, 4); + g2d.setColor(BORDER_COLOR); + g2d.drawPolygon(x, y, 4); + } + + public enum PointCount { + _3, _4, _5, _6, _7, _8; + + public String toString() { + return name().substring(1); + }; + } +} diff --git a/diylc/diylc-library/src/main/java/org/diylc/components/shapes/Rectangle.java b/diylc/diylc-library/src/main/java/org/diylc/components/shapes/Rectangle.java index 1a5cc7e38..ace2cff16 100644 --- a/diylc/diylc-library/src/main/java/org/diylc/components/shapes/Rectangle.java +++ b/diylc/diylc-library/src/main/java/org/diylc/components/shapes/Rectangle.java @@ -1,95 +1,88 @@ -/* - - DIY Layout Creator (DIYLC). - Copyright (c) 2009-2025 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.shapes; - -import java.awt.AlphaComposite; -import java.awt.Composite; -import java.awt.Graphics2D; - -import org.diylc.common.ObjectCache; -import org.diylc.components.transform.SimpleComponentTransformer; -import org.diylc.core.ComponentState; -import org.diylc.core.IDIYComponent; -import org.diylc.core.IDrawingObserver; -import org.diylc.core.Project; -import org.diylc.core.annotations.BomPolicy; -import org.diylc.core.annotations.ComponentDescriptor; -import org.diylc.core.annotations.EditableProperty; -import org.diylc.core.measures.Size; -import org.diylc.core.measures.SizeUnit; - -@ComponentDescriptor(name = "Rectangle", author = "Branislav Stojkovic", category = "Shapes", - instanceNamePrefix = "RECT", description = "Rectangular area, with or without rounded edges", - zOrder = IDIYComponent.COMPONENT, flexibleZOrder = true, bomPolicy = BomPolicy.NEVER_SHOW, - transformer = SimpleComponentTransformer.class) -public class Rectangle extends AbstractShapeWithDimensions { - - private static final long serialVersionUID = 1L; - - protected Size edgeRadius = new Size(0d, SizeUnit.mm); - - @Override - public void draw(Graphics2D g2d, ComponentState componentState, boolean outlineMode, Project project, - IDrawingObserver drawingObserver) { - g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke((int) borderThickness.convertToPixels())); - int radius = (int) edgeRadius.convertToPixels(); - - float alpha = this.alpha; - if (componentState == ComponentState.DRAGGING) - alpha = 0; - - Composite oldComposite = g2d.getComposite(); - if (alpha < MAX_ALPHA) { - g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1f * alpha / MAX_ALPHA)); - } - g2d.setColor(color); - g2d.fillRoundRect((int)firstPoint.getX(), (int)firstPoint.getY(), (int)(secondPoint.getX() - firstPoint.getX()), (int)(secondPoint.getY() - firstPoint.getY()), radius, - radius); - g2d.setComposite(oldComposite); - - // Do not track any changes that follow because the whole rect has been - // tracked so far. - drawingObserver.stopTracking(); - g2d.setColor(componentState == ComponentState.SELECTED || componentState == ComponentState.DRAGGING ? SELECTION_COLOR - : borderColor); - g2d.drawRoundRect((int)firstPoint.getX(), (int)firstPoint.getY(), (int)(secondPoint.getX() - firstPoint.getX()), (int)(secondPoint.getY() - firstPoint.getY()), radius, - radius); - } - - @EditableProperty(name = "Radius") - public Size getEdgeRadius() { - return edgeRadius; - } - - public void setEdgeRadius(Size edgeRadius) { - this.edgeRadius = edgeRadius; - } - - @Override - public void drawIcon(Graphics2D g2d, int width, int height) { - int factor = 32 / width; - g2d.setColor(COLOR); - g2d.fillRect(2 / factor, 2 / factor, width - 4 / factor, height - 4 / factor); - g2d.setColor(BORDER_COLOR); - g2d.drawRect(2 / factor, 2 / factor, width - 4 / factor, height - 4 / factor); - } -} +/* + + DIY Layout Creator (DIYLC). + Copyright (c) 2009-2025 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.shapes; + +import java.awt.AlphaComposite; +import java.awt.Composite; +import java.awt.Graphics2D; + +import org.diylc.common.ObjectCache; +import org.diylc.components.transform.SimpleComponentTransformer; +import org.diylc.core.ComponentState; +import org.diylc.core.IDIYComponent; +import org.diylc.core.IDrawingObserver; +import org.diylc.core.Project; +import org.diylc.core.annotations.BomPolicy; +import org.diylc.core.annotations.ComponentDescriptor; +import org.diylc.core.annotations.EditableProperty; +import org.diylc.core.measures.Size; +import org.diylc.core.measures.SizeUnit; + +@ComponentDescriptor(name = "Rectangle", author = "Branislav Stojkovic", category = "Shapes", + instanceNamePrefix = "RECT", description = "Rectangular area, with or without rounded edges", + zOrder = IDIYComponent.COMPONENT, flexibleZOrder = true, bomPolicy = BomPolicy.NEVER_SHOW, + transformer = SimpleComponentTransformer.class) +public class Rectangle extends AbstractShapeWithDimensions { + + private static final long serialVersionUID = 1L; + + protected Size edgeRadius = new Size(0d, SizeUnit.mm); + + @Override + public void draw(Graphics2D g2d, ComponentState componentState, boolean outlineMode, Project project, + IDrawingObserver drawingObserver) { + g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke((int) borderThickness.convertToPixels())); + int radius = (int) edgeRadius.convertToPixels(); + + Composite oldComposite = applyAlpha(g2d, componentState); + g2d.setColor(color); + g2d.fillRoundRect((int)firstPoint.getX(), (int)firstPoint.getY(), (int)(secondPoint.getX() - firstPoint.getX()), (int)(secondPoint.getY() - firstPoint.getY()), radius, + radius); + g2d.setComposite(oldComposite); + + // Do not track any changes that follow because the whole rect has been + // tracked so far. + drawingObserver.stopTracking(); + g2d.setColor(componentState == ComponentState.SELECTED || componentState == ComponentState.DRAGGING ? SELECTION_COLOR + : borderColor); + g2d.drawRoundRect((int)firstPoint.getX(), (int)firstPoint.getY(), (int)(secondPoint.getX() - firstPoint.getX()), (int)(secondPoint.getY() - firstPoint.getY()), radius, + radius); + } + + @EditableProperty(name = "Radius") + public Size getEdgeRadius() { + return edgeRadius; + } + + public void setEdgeRadius(Size edgeRadius) { + this.edgeRadius = edgeRadius; + } + + @Override + public void drawIcon(Graphics2D g2d, int width, int height) { + int factor = 32 / width; + g2d.setColor(COLOR); + g2d.fillRect(2 / factor, 2 / factor, width - 4 / factor, height - 4 / factor); + g2d.setColor(BORDER_COLOR); + g2d.drawRect(2 / factor, 2 / factor, width - 4 / factor, height - 4 / factor); + } +} diff --git a/diylc/diylc-library/src/main/java/org/diylc/components/shapes/TapeMeasure.java b/diylc/diylc-library/src/main/java/org/diylc/components/shapes/TapeMeasure.java index 2a85cc230..67b93b5c7 100644 --- a/diylc/diylc-library/src/main/java/org/diylc/components/shapes/TapeMeasure.java +++ b/diylc/diylc-library/src/main/java/org/diylc/components/shapes/TapeMeasure.java @@ -38,6 +38,7 @@ import java.text.DecimalFormat; import org.diylc.common.Display; import org.diylc.common.LineStyle; import org.diylc.common.ObjectCache; +import org.diylc.common.Percentage; import org.diylc.components.AbstractLeadedComponent; import org.diylc.components.transform.SimpleComponentTransformer; import org.diylc.core.ComponentState; @@ -276,7 +277,7 @@ public class TapeMeasure extends AbstractLeadedComponent { } @Override - public Byte getAlpha() { + public Percentage getAlpha() { return super.getAlpha(); } diff --git a/diylc/diylc-library/src/main/java/org/diylc/components/smd/PassiveSMDComponent.java b/diylc/diylc-library/src/main/java/org/diylc/components/smd/PassiveSMDComponent.java index 229700280..86d4bd542 100644 --- a/diylc/diylc-library/src/main/java/org/diylc/components/smd/PassiveSMDComponent.java +++ b/diylc/diylc-library/src/main/java/org/diylc/components/smd/PassiveSMDComponent.java @@ -1,452 +1,447 @@ -/* - - DIY Layout Creator (DIYLC). - Copyright (c) 2009-2025 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.smd; - -import java.awt.AlphaComposite; -import java.awt.Color; -import java.awt.Composite; -import java.awt.FontMetrics; -import java.awt.Graphics2D; -import java.awt.Rectangle; -import java.awt.geom.Area; -import java.awt.geom.Point2D; -import java.awt.geom.Rectangle2D; -import java.awt.geom.RoundRectangle2D; -import org.diylc.appframework.miscutils.ConfigurationManager; - -import org.diylc.common.Display; -import org.diylc.common.IPlugInPort; -import org.diylc.common.ObjectCache; -import org.diylc.common.Orientation; -import org.diylc.components.AbstractLabeledComponent; -import org.diylc.core.ComponentState; -import org.diylc.core.IDrawingObserver; -import org.diylc.core.Project; -import org.diylc.core.Theme; -import org.diylc.core.VisibilityPolicy; -import org.diylc.core.annotations.EditableProperty; -import org.diylc.core.gerber.IGerberComponentSimple; -import org.diylc.core.measures.Size; -import org.diylc.core.measures.SizeUnit; -import org.diylc.utils.Constants; - -public abstract class PassiveSMDComponent extends AbstractLabeledComponent implements IGerberComponentSimple { - - private static final long serialVersionUID = 1L; - - public static Color PIN_COLOR = METAL_COLOR; - public static Color PIN_BORDER_COLOR = PIN_COLOR.darker(); - public static Color LABEL_COLOR = Color.white; - public static int EDGE_RADIUS = 4; - public static Size PIN_SIZE = new Size(0.8d, SizeUnit.mm); - - protected T value; - private Orientation orientation = Orientation.DEFAULT; - - private SMDSize size = SMDSize._1206; - private Point2D[] controlPoints = new Point2D[] {new Point2D.Double(0, 0), new Point2D.Double(0, 0)}; - protected Display display = Display.NAME; - protected Color bodyColor; - protected Color borderColor; - private Color labelColor = LABEL_COLOR; - transient private Area[] body; - - public PassiveSMDComponent() { - super(); - updateControlPoints(); - } - - @EditableProperty - public Orientation getOrientation() { - return orientation; - } - - public void setOrientation(Orientation orientation) { - this.orientation = orientation; - updateControlPoints(); - // Reset body shape. - body = null; - } - - @EditableProperty - public Display getDisplay() { - if (display == null) { - display = Display.VALUE; - } - return display; - } - - public void setDisplay(Display display) { - this.display = display; - } - - @EditableProperty - public SMDSize getSize() { - return size; - } - - public void setSize(SMDSize size) { - this.size = size; - updateControlPoints(); - // Reset body shape. - body = null; - } - - @Override - public int getControlPointCount() { - return controlPoints.length; - } - - @Override - public Point2D getControlPoint(int index) { - return controlPoints[index]; - } - - @Override - public boolean isControlPointSticky(int index) { - return true; - } - - @Override - public VisibilityPolicy getControlPointVisibilityPolicy(int index) { - return VisibilityPolicy.NEVER; - } - - @Override - public void setControlPoint(Point2D point, int index) { - controlPoints[index].setLocation(point); - body = null; - } - - private void updateControlPoints() { - Point2D firstPoint = controlPoints[0]; - controlPoints[0] = firstPoint; - double pinSize = PIN_SIZE.convertToPixels(); - double smdLength = getSize().getLength().convertToPixels(); - double pinSpacing = smdLength - pinSize; - - // Update control points. - double dx1; - double dy1; - switch (orientation) { - case DEFAULT: - dx1 = 0; - dy1 = pinSpacing; - break; - case _90: - dx1 = -pinSpacing; - dy1 = 0; - break; - case _180: - dx1 = 0; - dy1 = -pinSpacing; - break; - case _270: - dx1 = pinSpacing; - dy1 = 0; - break; - default: - throw new RuntimeException("Unexpected orientation: " + orientation); - } - controlPoints[1] = new Point2D.Double(firstPoint.getX() + dx1, firstPoint.getY() + dy1); - } - - public Area[] getBody() { - if (body == null) { - body = new Area[2]; - double x = controlPoints[0].getX(); - double y = controlPoints[0].getY(); - double smdWidth = getSize().getWidth().convertToPixels(); - double smdLength = getSize().getLength().convertToPixels(); - double pinSize = PIN_SIZE.convertToPixels(); - double width; - double height; - - // create main body - switch (orientation) { - case DEFAULT: - width = smdWidth; - height = smdLength; - x = controlPoints[0].getX() - smdWidth / 2; - y = controlPoints[0].getY() - pinSize / 2; - break; - case _90: - width = smdLength; - height = smdWidth; - x = controlPoints[1].getX() - pinSize / 2; - y = controlPoints[1].getY() - smdWidth / 2; - break; - case _180: - width = smdWidth; - height = smdLength; - x = controlPoints[1].getX() - smdWidth / 2; - y = controlPoints[1].getY() - pinSize / 2; - break; - case _270: - width = smdLength; - height = smdWidth; - x = controlPoints[0].getX() - pinSize / 2; - y = controlPoints[0].getY() - smdWidth / 2; - break; - default: - throw new RuntimeException("Unexpected orientation: " + orientation); - } - Area mainArea = new Area(new RoundRectangle2D.Double(x, y, width, height, EDGE_RADIUS, EDGE_RADIUS)); - - // create contact area - Area contactArea = new Area(); - if (width > height) { - contactArea.add(new Area(new Rectangle2D.Double(x, y, pinSize, height))); - contactArea.add(new Area(new Rectangle2D.Double(x + width - pinSize, y, pinSize, height))); - } else { - contactArea.add(new Area(new Rectangle2D.Double(x, y, width, pinSize))); - contactArea.add(new Area(new Rectangle2D.Double(x, y + height - pinSize, width, pinSize))); - } - contactArea.intersect(mainArea); - - mainArea.subtract(contactArea); - body[0] = mainArea; - body[1] = contactArea; - - } - return body; - } - - @Override - public void draw(Graphics2D g2d, ComponentState componentState, boolean outlineMode, Project project, - IDrawingObserver drawingObserver) { - if (checkPointsClipped(g2d.getClip())) { - return; - } - - // draw main area - Area mainArea = getBody()[0]; - 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 : getBodyColor()); - g2d.fill(mainArea); - 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 - : getBorderColor(); - } - g2d.setColor(finalBorderColor); - g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(1)); - g2d.draw(mainArea); - - - // draw contact area - Area contactArea = getBody()[1]; - if (!outlineMode) { - g2d.setColor(PIN_COLOR); - if (alpha < MAX_ALPHA) { - g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1f * alpha / MAX_ALPHA)); - } - g2d.fill(contactArea); - g2d.setComposite(oldComposite); - } - - 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 - : PIN_BORDER_COLOR; - } - g2d.setColor(finalBorderColor); - g2d.draw(contactArea); - - // Draw label. - g2d.setFont(project.getFont()); - - // Override font size - if (getFontSizeOverride() != null) - g2d.setFont(g2d.getFont().deriveFont(1f * getFontSizeOverride())); - - 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 - : getLabelColor(); - } - g2d.setColor(finalLabelColor); - FontMetrics fontMetrics = g2d.getFontMetrics(g2d.getFont()); - String label = ""; - label = (getDisplay() == Display.NAME) ? getName() : getValue().toString(); - if (getDisplay() == Display.NONE) { - label = ""; - } - if (getDisplay() == Display.BOTH) { - label = getName() + " " + (getValue() == null ? "" : getValue().toString()); - } - - Rectangle textTarget = mainArea.getBounds(); - int length = textTarget.height > textTarget.width ? textTarget.height : textTarget.width; - - Rectangle2D rect = fontMetrics.getStringBounds(label, g2d); - int textHeight = (int) (rect.getHeight()); - int textWidth = (int) (rect.getWidth()); - - do { - g2d.setFont(g2d.getFont().deriveFont(g2d.getFont().getSize2D() - 1)); - fontMetrics = g2d.getFontMetrics(g2d.getFont()); - rect = fontMetrics.getStringBounds(label, g2d); - textHeight = (int) (rect.getHeight()); - textWidth = (int) (rect.getWidth()); - } while (textWidth > length && g2d.getFont().getSize2D() > 2); - - double centerX = textTarget.getX() + textTarget.getWidth() / 2; - double centerY = textTarget.getY() + textTarget.getHeight() / 2; - g2d.translate(centerX, centerY); - - switch (orientation) { - case DEFAULT: - g2d.rotate(Math.PI / 2); - break; - case _90: - g2d.rotate(Math.PI); - break; - case _180: - g2d.rotate(Math.PI * 3 / 2); - break; - case _270: - break; - default: - throw new RuntimeException("Unexpected orientation: " + orientation); - } - - // Center text horizontally and vertically - int x = -textWidth / 2; - int y = -textHeight / 2 + fontMetrics.getAscent() - 1; - g2d.drawString(label, x, y); - } - - @Override - public void drawIcon(Graphics2D g2d, int width, int height) { - int radius = 4 * width / 32; - int contactSize = 4 * width / 32; - int thickness = getClosestOdd(width / 2); - g2d.rotate(Math.PI / 4, width / 2, height / 2); - RoundRectangle2D rect = - new RoundRectangle2D.Double((width - thickness) / 2, 4 * width / 32, thickness, height - 8 * width / 32, - radius, radius); - g2d.setColor(getBodyColor()); - g2d.fill(rect); - g2d.setColor(getBorderColor()); - g2d.draw(rect); - Area contactArea = new Area(); - contactArea.add(new Area(new Rectangle2D.Double((width - thickness) / 2, 4 * width / 32, thickness, contactSize))); - contactArea.add(new Area(new Rectangle2D.Double((width - thickness) / 2, height - 8 * width / 32, thickness, - contactSize))); - contactArea.intersect(new Area(rect)); - g2d.setColor(PIN_COLOR); - g2d.fill(contactArea); - } - - @EditableProperty(name = "Body") - public Color getBodyColor() { - return bodyColor; - } - - public void setBodyColor(Color bodyColor) { - this.bodyColor = bodyColor; - } - - @EditableProperty(name = "Border") - public Color getBorderColor() { - return borderColor; - } - - public void setBorderColor(Color borderColor) { - this.borderColor = borderColor; - } - - @EditableProperty(name = "Label") - public Color getLabelColor() { - if (labelColor == null) { - labelColor = LABEL_COLOR; - } - return labelColor; - } - - public void setLabelColor(Color labelColor) { - this.labelColor = labelColor; - } - - @Override - public boolean canPointMoveFreely(int pointIndex) { - return false; - } - - public static enum SMDSize { - - _0805(new Size(0.05d, SizeUnit.in), new Size(0.08d, SizeUnit.in)), _1206(new Size(1.6d, SizeUnit.mm), new Size(3.2d, - SizeUnit.mm)), _1210(new Size(2.5d, SizeUnit.mm), new Size(3.2d, SizeUnit.mm)), _1806(new Size(1.6d, - SizeUnit.mm), new Size(4.5d, SizeUnit.mm)), _1812(new Size(3.2d, SizeUnit.mm), new Size(4.5d, SizeUnit.mm)); - - private Size width; - private Size length; - - private SMDSize(Size width, Size length) { - this.width = width; - this.length = length; - } - - public Size getWidth() { - return width; - } - - public Size getLength() { - return length; - } - - @Override - public String toString() { - return name().replace("_", ""); - } - - public int getValue() { - return Integer.parseInt(toString()); - } - } -} +/* + + DIY Layout Creator (DIYLC). + Copyright (c) 2009-2025 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.smd; + +import java.awt.AlphaComposite; +import java.awt.Color; +import java.awt.Composite; +import java.awt.FontMetrics; +import java.awt.Graphics2D; +import java.awt.Rectangle; +import java.awt.geom.Area; +import java.awt.geom.Point2D; +import java.awt.geom.Rectangle2D; +import java.awt.geom.RoundRectangle2D; +import org.diylc.appframework.miscutils.ConfigurationManager; + +import org.diylc.common.Display; +import org.diylc.common.IPlugInPort; +import org.diylc.common.ObjectCache; +import org.diylc.common.Orientation; +import org.diylc.components.AbstractLabeledComponent; +import org.diylc.core.ComponentState; +import org.diylc.core.IDrawingObserver; +import org.diylc.core.Project; +import org.diylc.core.Theme; +import org.diylc.core.VisibilityPolicy; +import org.diylc.core.annotations.EditableProperty; +import org.diylc.core.gerber.IGerberComponentSimple; +import org.diylc.core.measures.Size; +import org.diylc.core.measures.SizeUnit; +import org.diylc.utils.Constants; + +public abstract class PassiveSMDComponent extends AbstractLabeledComponent implements IGerberComponentSimple { + + private static final long serialVersionUID = 1L; + + public static Color PIN_COLOR = METAL_COLOR; + public static Color PIN_BORDER_COLOR = PIN_COLOR.darker(); + public static Color LABEL_COLOR = Color.white; + public static int EDGE_RADIUS = 4; + public static Size PIN_SIZE = new Size(0.8d, SizeUnit.mm); + + protected T value; + private Orientation orientation = Orientation.DEFAULT; + + private SMDSize size = SMDSize._1206; + private Point2D[] controlPoints = new Point2D[] {new Point2D.Double(0, 0), new Point2D.Double(0, 0)}; + protected Display display = Display.NAME; + protected Color bodyColor; + protected Color borderColor; + private Color labelColor = LABEL_COLOR; + transient private Area[] body; + + public PassiveSMDComponent() { + super(); + updateControlPoints(); + } + + @EditableProperty + public Orientation getOrientation() { + return orientation; + } + + public void setOrientation(Orientation orientation) { + this.orientation = orientation; + updateControlPoints(); + // Reset body shape. + body = null; + } + + @EditableProperty + public Display getDisplay() { + if (display == null) { + display = Display.VALUE; + } + return display; + } + + public void setDisplay(Display display) { + this.display = display; + } + + @EditableProperty + public SMDSize getSize() { + return size; + } + + public void setSize(SMDSize size) { + this.size = size; + updateControlPoints(); + // Reset body shape. + body = null; + } + + @Override + public int getControlPointCount() { + return controlPoints.length; + } + + @Override + public Point2D getControlPoint(int index) { + return controlPoints[index]; + } + + @Override + public boolean isControlPointSticky(int index) { + return true; + } + + @Override + public VisibilityPolicy getControlPointVisibilityPolicy(int index) { + return VisibilityPolicy.NEVER; + } + + @Override + public void setControlPoint(Point2D point, int index) { + controlPoints[index].setLocation(point); + body = null; + } + + private void updateControlPoints() { + Point2D firstPoint = controlPoints[0]; + controlPoints[0] = firstPoint; + double pinSize = PIN_SIZE.convertToPixels(); + double smdLength = getSize().getLength().convertToPixels(); + double pinSpacing = smdLength - pinSize; + + // Update control points. + double dx1; + double dy1; + switch (orientation) { + case DEFAULT: + dx1 = 0; + dy1 = pinSpacing; + break; + case _90: + dx1 = -pinSpacing; + dy1 = 0; + break; + case _180: + dx1 = 0; + dy1 = -pinSpacing; + break; + case _270: + dx1 = pinSpacing; + dy1 = 0; + break; + default: + throw new RuntimeException("Unexpected orientation: " + orientation); + } + controlPoints[1] = new Point2D.Double(firstPoint.getX() + dx1, firstPoint.getY() + dy1); + } + + public Area[] getBody() { + if (body == null) { + body = new Area[2]; + double x = controlPoints[0].getX(); + double y = controlPoints[0].getY(); + double smdWidth = getSize().getWidth().convertToPixels(); + double smdLength = getSize().getLength().convertToPixels(); + double pinSize = PIN_SIZE.convertToPixels(); + double width; + double height; + + // create main body + switch (orientation) { + case DEFAULT: + width = smdWidth; + height = smdLength; + x = controlPoints[0].getX() - smdWidth / 2; + y = controlPoints[0].getY() - pinSize / 2; + break; + case _90: + width = smdLength; + height = smdWidth; + x = controlPoints[1].getX() - pinSize / 2; + y = controlPoints[1].getY() - smdWidth / 2; + break; + case _180: + width = smdWidth; + height = smdLength; + x = controlPoints[1].getX() - smdWidth / 2; + y = controlPoints[1].getY() - pinSize / 2; + break; + case _270: + width = smdLength; + height = smdWidth; + x = controlPoints[0].getX() - pinSize / 2; + y = controlPoints[0].getY() - smdWidth / 2; + break; + default: + throw new RuntimeException("Unexpected orientation: " + orientation); + } + Area mainArea = new Area(new RoundRectangle2D.Double(x, y, width, height, EDGE_RADIUS, EDGE_RADIUS)); + + // create contact area + Area contactArea = new Area(); + if (width > height) { + contactArea.add(new Area(new Rectangle2D.Double(x, y, pinSize, height))); + contactArea.add(new Area(new Rectangle2D.Double(x + width - pinSize, y, pinSize, height))); + } else { + contactArea.add(new Area(new Rectangle2D.Double(x, y, width, pinSize))); + contactArea.add(new Area(new Rectangle2D.Double(x, y + height - pinSize, width, pinSize))); + } + contactArea.intersect(mainArea); + + mainArea.subtract(contactArea); + body[0] = mainArea; + body[1] = contactArea; + + } + return body; + } + + @Override + public void draw(Graphics2D g2d, ComponentState componentState, boolean outlineMode, Project project, + IDrawingObserver drawingObserver) { + if (checkPointsClipped(g2d.getClip())) { + return; + } + + // draw main area + Area mainArea = getBody()[0]; + Composite oldComposite = applyAlpha(g2d, componentState); + g2d.setColor(outlineMode ? Constants.TRANSPARENT_COLOR : getBodyColor()); + g2d.fill(mainArea); + 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 + : getBorderColor(); + } + g2d.setColor(finalBorderColor); + g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(1)); + g2d.draw(mainArea); + + + // draw contact area + Area contactArea = getBody()[1]; + if (!outlineMode) { + g2d.setColor(PIN_COLOR); + applyAlpha(g2d, componentState); + g2d.fill(contactArea); + g2d.setComposite(oldComposite); + } + + 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 + : PIN_BORDER_COLOR; + } + g2d.setColor(finalBorderColor); + g2d.draw(contactArea); + + // Draw label. + g2d.setFont(project.getFont()); + + // Override font size + if (getFontSizeOverride() != null) + g2d.setFont(g2d.getFont().deriveFont(1f * getFontSizeOverride())); + + 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 + : getLabelColor(); + } + g2d.setColor(finalLabelColor); + FontMetrics fontMetrics = g2d.getFontMetrics(g2d.getFont()); + String label = ""; + label = (getDisplay() == Display.NAME) ? getName() : getValue().toString(); + if (getDisplay() == Display.NONE) { + label = ""; + } + if (getDisplay() == Display.BOTH) { + label = getName() + " " + (getValue() == null ? "" : getValue().toString()); + } + + Rectangle textTarget = mainArea.getBounds(); + int length = textTarget.height > textTarget.width ? textTarget.height : textTarget.width; + + Rectangle2D rect = fontMetrics.getStringBounds(label, g2d); + int textHeight = (int) (rect.getHeight()); + int textWidth = (int) (rect.getWidth()); + + do { + g2d.setFont(g2d.getFont().deriveFont(g2d.getFont().getSize2D() - 1)); + fontMetrics = g2d.getFontMetrics(g2d.getFont()); + rect = fontMetrics.getStringBounds(label, g2d); + textHeight = (int) (rect.getHeight()); + textWidth = (int) (rect.getWidth()); + } while (textWidth > length && g2d.getFont().getSize2D() > 2); + + double centerX = textTarget.getX() + textTarget.getWidth() / 2; + double centerY = textTarget.getY() + textTarget.getHeight() / 2; + g2d.translate(centerX, centerY); + + switch (orientation) { + case DEFAULT: + g2d.rotate(Math.PI / 2); + break; + case _90: + g2d.rotate(Math.PI); + break; + case _180: + g2d.rotate(Math.PI * 3 / 2); + break; + case _270: + break; + default: + throw new RuntimeException("Unexpected orientation: " + orientation); + } + + // Center text horizontally and vertically + int x = -textWidth / 2; + int y = -textHeight / 2 + fontMetrics.getAscent() - 1; + g2d.drawString(label, x, y); + } + + @Override + public void drawIcon(Graphics2D g2d, int width, int height) { + int radius = 4 * width / 32; + int contactSize = 4 * width / 32; + int thickness = getClosestOdd(width / 2); + g2d.rotate(Math.PI / 4, width / 2, height / 2); + RoundRectangle2D rect = + new RoundRectangle2D.Double((width - thickness) / 2, 4 * width / 32, thickness, height - 8 * width / 32, + radius, radius); + g2d.setColor(getBodyColor()); + g2d.fill(rect); + g2d.setColor(getBorderColor()); + g2d.draw(rect); + Area contactArea = new Area(); + contactArea.add(new Area(new Rectangle2D.Double((width - thickness) / 2, 4 * width / 32, thickness, contactSize))); + contactArea.add(new Area(new Rectangle2D.Double((width - thickness) / 2, height - 8 * width / 32, thickness, + contactSize))); + contactArea.intersect(new Area(rect)); + g2d.setColor(PIN_COLOR); + g2d.fill(contactArea); + } + + @EditableProperty(name = "Body") + public Color getBodyColor() { + return bodyColor; + } + + public void setBodyColor(Color bodyColor) { + this.bodyColor = bodyColor; + } + + @EditableProperty(name = "Border") + public Color getBorderColor() { + return borderColor; + } + + public void setBorderColor(Color borderColor) { + this.borderColor = borderColor; + } + + @EditableProperty(name = "Label") + public Color getLabelColor() { + if (labelColor == null) { + labelColor = LABEL_COLOR; + } + return labelColor; + } + + public void setLabelColor(Color labelColor) { + this.labelColor = labelColor; + } + + @Override + public boolean canPointMoveFreely(int pointIndex) { + return false; + } + + public static enum SMDSize { + + _0805(new Size(0.05d, SizeUnit.in), new Size(0.08d, SizeUnit.in)), _1206(new Size(1.6d, SizeUnit.mm), new Size(3.2d, + SizeUnit.mm)), _1210(new Size(2.5d, SizeUnit.mm), new Size(3.2d, SizeUnit.mm)), _1806(new Size(1.6d, + SizeUnit.mm), new Size(4.5d, SizeUnit.mm)), _1812(new Size(3.2d, SizeUnit.mm), new Size(4.5d, SizeUnit.mm)); + + private Size width; + private Size length; + + private SMDSize(Size width, Size length) { + this.width = width; + this.length = length; + } + + public Size getWidth() { + return width; + } + + public Size getLength() { + return length; + } + + @Override + public String toString() { + return name().replace("_", ""); + } + + public int getValue() { + return Integer.parseInt(toString()); + } + } +} diff --git a/diylc/diylc-library/src/main/java/org/diylc/components/smd/SOT23Package.java b/diylc/diylc-library/src/main/java/org/diylc/components/smd/SOT23Package.java index a114e51b4..55f1990d2 100644 --- a/diylc/diylc-library/src/main/java/org/diylc/components/smd/SOT23Package.java +++ b/diylc/diylc-library/src/main/java/org/diylc/components/smd/SOT23Package.java @@ -266,8 +266,8 @@ package org.diylc.components.smd; // // draw main area // Area mainArea = getBody()[0]; // Composite oldComposite = g2d.getComposite(); -// if (alpha < MAX_ALPHA) { -// g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1f * alpha / MAX_ALPHA)); +// if (getAlpha().getValue() < MAX_ALPHA) { +// g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, getAlpha().getValue() / 100f)); // } // g2d.setColor(outlineMode ? Constants.TRANSPARENT_COLOR : getBodyColor()); // g2d.fill(mainArea); @@ -294,8 +294,8 @@ package org.diylc.components.smd; // Area contactArea = getBody()[1]; // if (!outlineMode) { // g2d.setColor(PIN_COLOR); -// if (alpha < MAX_ALPHA) { -// g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1f * alpha / MAX_ALPHA)); +// if (getAlpha().getValue() < MAX_ALPHA) { +// g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, getAlpha().getValue() / 100f)); // } // g2d.fill(contactArea); // g2d.setComposite(oldComposite); diff --git a/diylc/diylc-library/src/main/java/org/diylc/components/tube/Jumbo4PinTubeSocket.java b/diylc/diylc-library/src/main/java/org/diylc/components/tube/Jumbo4PinTubeSocket.java index 880b1054f..0cceeba0f 100644 --- a/diylc/diylc-library/src/main/java/org/diylc/components/tube/Jumbo4PinTubeSocket.java +++ b/diylc/diylc-library/src/main/java/org/diylc/components/tube/Jumbo4PinTubeSocket.java @@ -206,10 +206,7 @@ public class Jumbo4PinTubeSocket extends AbstractAngledComponent { Shape baseShape = body[0]; - Composite oldComposite = g2d.getComposite(); - if (alpha < MAX_ALPHA) { - g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1f * alpha / MAX_ALPHA)); - } + Composite oldComposite = applyAlpha(g2d, componentState); if (componentState != ComponentState.DRAGGING) { g2d.setColor(outlineMode ? Constants.TRANSPARENT_COLOR : getColor()); g2d.fill(baseShape); diff --git a/diylc/diylc-library/src/main/java/org/diylc/components/tube/SubminiTube.java b/diylc/diylc-library/src/main/java/org/diylc/components/tube/SubminiTube.java index 4c6f77acb..82659260b 100644 --- a/diylc/diylc-library/src/main/java/org/diylc/components/tube/SubminiTube.java +++ b/diylc/diylc-library/src/main/java/org/diylc/components/tube/SubminiTube.java @@ -306,10 +306,7 @@ public class SubminiTube extends AbstractLabeledComponent { } int pinSize = (int) LEAD_THICKNESS.convertToPixels() / 2 * 2; Shape mainArea = getBody()[0]; - Composite oldComposite = g2d.getComposite(); - if (alpha < MAX_ALPHA) { - g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1f * alpha / MAX_ALPHA)); - } + Composite oldComposite = applyAlpha(g2d, componentState); g2d.setColor(outlineMode ? Constants.TRANSPARENT_COLOR : bodyColor); g2d.fill(mainArea); diff --git a/diylc/diylc-library/src/main/java/org/diylc/components/tube/TubeSocket.java b/diylc/diylc-library/src/main/java/org/diylc/components/tube/TubeSocket.java index e3e00da45..c8edb4b13 100644 --- a/diylc/diylc-library/src/main/java/org/diylc/components/tube/TubeSocket.java +++ b/diylc/diylc-library/src/main/java/org/diylc/components/tube/TubeSocket.java @@ -1,462 +1,459 @@ -/* - - DIY Layout Creator (DIYLC). - Copyright (c) 2009-2025 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.tube; - -import java.awt.AlphaComposite; -import java.awt.Color; -import java.awt.Composite; -import java.awt.Graphics2D; -import java.awt.Shape; -import java.awt.geom.AffineTransform; -import java.awt.geom.Area; -import java.awt.geom.Ellipse2D; -import java.awt.geom.Point2D; -import java.awt.geom.Rectangle2D; -import org.diylc.appframework.miscutils.ConfigurationManager; - -import org.diylc.awt.StringUtils; -import org.diylc.common.HorizontalAlignment; -import org.diylc.common.IPlugInPort; -import org.diylc.common.ObjectCache; -import org.diylc.common.VerticalAlignment; -import org.diylc.components.AbstractAngledComponent; -import org.diylc.components.transform.AngledComponentTransformer; -import org.diylc.core.ComponentState; -import org.diylc.core.IDIYComponent; -import org.diylc.core.IDrawingObserver; -import org.diylc.core.Project; -import org.diylc.core.Theme; -import org.diylc.core.VisibilityPolicy; -import org.diylc.core.annotations.ComponentDescriptor; -import org.diylc.core.annotations.EditableProperty; -import org.diylc.core.annotations.KeywordPolicy; -import org.diylc.core.gerber.IGerberComponentSimple; -import org.diylc.core.measures.Size; -import org.diylc.core.measures.SizeUnit; -import org.diylc.utils.Constants; - -@ComponentDescriptor(name = "Tube Socket", author = "Branislav Stojkovic", category = "Tubes", - instanceNamePrefix = "V", description = "Various types of tube/valve sockets", - zOrder = IDIYComponent.COMPONENT, keywordPolicy = KeywordPolicy.SHOW_VALUE, enableCache = true, - transformer = AngledComponentTransformer.class) -public class TubeSocket extends AbstractAngledComponent implements IGerberComponentSimple { - - private static final Size B9A_PIN_SPACING_CHASSIS = new Size(12.5d, SizeUnit.mm); - private static final Size B9A_PIN_SPACING_PCB = new Size(21d, SizeUnit.mm); - private static final Size OCTAL_PIN_SPACING = new Size(17.5d, SizeUnit.mm); - private static final Size B7G_PIN_SPACING = new Size(12d, SizeUnit.mm); - private static final Size B7G_CUTOUT_DIAMETER = new Size(4d, SizeUnit.mm); - private static final Size B9A_CUTOUT_DIAMETER = new Size(5.5d, SizeUnit.mm); - private static final Size B12C_HOLE_SIZE = new Size(10d, SizeUnit.mm); - private static final Size B12C_CUTOUT_DIAMETER = new Size(5.5d, SizeUnit.mm); - private static final Size B12C_PIN_SPACING_PCB = new Size(25d, SizeUnit.mm); - private static final Size B12C_PIN_SPACING_CHASSIS = new Size(22d, SizeUnit.mm); - - private static final Size OCTAL_DIAMETER = new Size(25d, SizeUnit.mm); - private static final Size B9A_DIAMETER = new Size(3 / 4d, SizeUnit.in); - private static final Size B7G_DIAMETER = new Size(17d, SizeUnit.mm); - private static final Size B12C_DIAMETER = new Size(30d, SizeUnit.mm); - - private static final long serialVersionUID = 1L; - - private static Color BODY_COLOR = Color.decode("#F7F7EF"); - private static Color LABEL_COLOR = BODY_COLOR.darker(); - public static Color PIN_COLOR = METAL_COLOR; - public static Color PIN_BORDER_COLOR = PIN_COLOR.darker(); - public static Size PIN_DIAMETER = new Size(1d, SizeUnit.mm); - private static Size PIN_WIDTH = new Size(0.08d, SizeUnit.in); - private static Size PIN_THICKNESS = new Size(0.02d, SizeUnit.in); - public static Size HOLE_SIZE = new Size(5d, SizeUnit.mm); - public static Size OCTAL_TICK_SIZE = new Size(2d, SizeUnit.mm); - - private Base base = Base.B9A; - private String type = ""; - private Color color = BODY_COLOR; - private String electrodeLabels = null; - private Mount mount = Mount.CHASSIS; - private Color labelColor = LABEL_COLOR; - - private Point2D[] controlPoints = new Point2D[] {new Point2D.Double(0, 0)}; - - public TubeSocket() { - super(); - updateControlPoints(); - } - - @EditableProperty - public Base getBase() { - return base; - } - - public void setBase(Base base) { - this.base = base; - updateControlPoints(); - // Reset body shape - body = null; - } - - @EditableProperty - public Color getColor() { - if (color == null) { - color = BODY_COLOR; - } - return color; - } - - public void setColor(Color color) { - this.color = color; - } - - // @EditableProperty - // public Mount getMount() { - // return mount; - // } - // - // public void setMount(Mount mount) { - // this.mount = mount; - // } - - @Override - protected void updateControlPoints() { - Point2D firstPoint = controlPoints[0]; - int pinCount; - int pinSpacing; - boolean hasEmptySpace; - switch (base) { - case B7G: - pinCount = 7; - pinSpacing = getClosestOdd(B7G_PIN_SPACING.convertToPixels()); - hasEmptySpace = true; - break; - case OCTAL: - pinCount = 8; - pinSpacing = getClosestOdd(OCTAL_PIN_SPACING.convertToPixels()); - hasEmptySpace = false; - break; - case B9A: - pinCount = 9; - pinSpacing = getClosestOdd(getMount() == Mount.PCB ? B9A_PIN_SPACING_PCB.convertToPixels() : B9A_PIN_SPACING_CHASSIS.convertToPixels()); - hasEmptySpace = true; - break; - case B12C: - pinCount = 12; - pinSpacing = getClosestOdd(getMount() == Mount.PCB ? B12C_PIN_SPACING_PCB.convertToPixels() : B12C_PIN_SPACING_CHASSIS.convertToPixels()); - hasEmptySpace = true; - break; - default: - throw new RuntimeException("Unexpected base: " + base); - } - double angleIncrement = Math.PI * 2 / (hasEmptySpace ? (pinCount + 1) : pinCount); - double initialAngleOffset = hasEmptySpace ? angleIncrement : (angleIncrement / 2); - - controlPoints = new Point2D[pinCount + 1]; - double theta = initialAngleOffset + getAngle().getValueRad(); - controlPoints[0] = firstPoint; - for (int i = 0; i < pinCount; i++) { - controlPoints[i + 1] = - new Point2D.Double(firstPoint.getX() + Math.cos(theta) * pinSpacing / 2, - firstPoint.getY() + Math.sin(theta) * pinSpacing / 2); - theta += angleIncrement; - } - } - - public Shape[] getBody() { - if (body == null) { - int bodyDiameter; - switch (base) { - case B7G: - bodyDiameter = getClosestOdd(B7G_DIAMETER.convertToPixels()); - break; - case B9A: - bodyDiameter = getClosestOdd(B9A_DIAMETER.convertToPixels()); - break; - case OCTAL: - bodyDiameter = getClosestOdd(OCTAL_DIAMETER.convertToPixels()); - break; - case B12C: - bodyDiameter = getClosestOdd(B12C_DIAMETER.convertToPixels()); - break; - default: - throw new RuntimeException("Unexpected base: " + base); - } - - Ellipse2D baseShape = - new Ellipse2D.Double(controlPoints[0].getX() - bodyDiameter / 2, controlPoints[0].getY() - bodyDiameter / 2, - bodyDiameter, bodyDiameter); - Area bodyArea = new Area(baseShape); - int holeSize = getClosestOdd(base == Base.B12C ? B12C_HOLE_SIZE.convertToPixels() : HOLE_SIZE.convertToPixels()); - bodyArea.subtract(new Area(new Ellipse2D.Double(controlPoints[0].getX() - holeSize / 2, controlPoints[0].getY() - holeSize - / 2, holeSize, holeSize))); - - if (base == Base.OCTAL) { - int tickSize = getClosestOdd(OCTAL_TICK_SIZE.convertToPixels()); - double theta = getAngle().getValueRad(); - int centerX = (int) (controlPoints[0].getX() + Math.cos(theta) * holeSize / 2); - int centerY = (int) (controlPoints[0].getY() + Math.sin(theta) * holeSize / 2); - bodyArea.subtract(new Area(new Ellipse2D.Double(centerX - tickSize / 2, centerY - tickSize / 2, tickSize, - tickSize))); - } else if (base == Base.B9A && getMount() == Mount.CHASSIS) { - double cutoutDiameter = getClosestOdd(B9A_CUTOUT_DIAMETER.convertToPixels()); - bodyArea.subtract(new Area(new Ellipse2D.Double(controlPoints[0].getX() - cutoutDiameter / 2, controlPoints[0].getY() - bodyDiameter / 2 - cutoutDiameter * 3 / 4, cutoutDiameter, cutoutDiameter))); - bodyArea.subtract(new Area(new Ellipse2D.Double(controlPoints[0].getX() - cutoutDiameter / 2, controlPoints[0].getY() + bodyDiameter / 2 - cutoutDiameter / 4, cutoutDiameter, cutoutDiameter))); - } else if (base == Base.B7G && getMount() == Mount.CHASSIS) { - double cutoutDiameter = getClosestOdd(B7G_CUTOUT_DIAMETER.convertToPixels()); - bodyArea.subtract(new Area(new Ellipse2D.Double(controlPoints[0].getX() - cutoutDiameter / 2, controlPoints[0].getY() - bodyDiameter / 2 - cutoutDiameter * 3 / 4, cutoutDiameter, cutoutDiameter))); - bodyArea.subtract(new Area(new Ellipse2D.Double(controlPoints[0].getX() - cutoutDiameter / 2, controlPoints[0].getY() + bodyDiameter / 2 - cutoutDiameter / 4, cutoutDiameter, cutoutDiameter))); - } else if (base == Base.B12C && getMount() == Mount.CHASSIS) { - double cutoutDiameter = getClosestOdd(B12C_CUTOUT_DIAMETER.convertToPixels()); - bodyArea.subtract(new Area(new Ellipse2D.Double(controlPoints[0].getX() - cutoutDiameter / 2, controlPoints[0].getY() - bodyDiameter / 2 - cutoutDiameter * 3 / 4, cutoutDiameter, cutoutDiameter))); - bodyArea.subtract(new Area(new Ellipse2D.Double(controlPoints[0].getX() - cutoutDiameter / 2, controlPoints[0].getY() + bodyDiameter / 2 - cutoutDiameter / 4, cutoutDiameter, cutoutDiameter))); - } - - body = new Shape[] { bodyArea }; - } - return body; - } - - @Override - public void draw(Graphics2D g2d, ComponentState componentState, boolean outlineMode, Project project, - IDrawingObserver drawingObserver) { - - g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(1)); - - // Draw body - Shape[] body = getBody(); - Composite oldComposite = g2d.getComposite(); - if (alpha < MAX_ALPHA) { - g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1f * alpha / MAX_ALPHA)); - } - if (componentState != ComponentState.DRAGGING) { - g2d.setColor(outlineMode ? Constants.TRANSPARENT_COLOR : getColor()); - g2d.fill(body[0]); - } - 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 - : getColor().darker(); - } - g2d.setColor(finalBorderColor); - g2d.draw(body[0]); - - drawingObserver.stopTracking(); - - // Draw pins - - for (int i = 1; i < controlPoints.length; i++) { - Shape pinShape; - if (getMount() == Mount.PCB) { - int pinSize = getClosestOdd(PIN_DIAMETER.convertToPixels()); - pinShape = new Ellipse2D.Double(controlPoints[i].getX() - pinSize / 2, - controlPoints[i].getY() - pinSize / 2, pinSize, pinSize); - } else { - int pinWidth = getClosestOdd(PIN_WIDTH.convertToPixels()); - int pinThickness = getClosestOdd(PIN_THICKNESS.convertToPixels()); - pinShape = new Rectangle2D.Double(controlPoints[i].getX() - pinWidth / 2, - controlPoints[i].getY() - pinThickness / 2, pinWidth, pinThickness); - double theta = Math.atan2(controlPoints[i].getY() - controlPoints[0].getY(), - controlPoints[i].getX() - controlPoints[0].getX()) + Math.PI / 2; - Area rotatedPin = new Area(pinShape); - rotatedPin.transform(AffineTransform.getRotateInstance(theta, controlPoints[i].getX(), - controlPoints[i].getY())); - pinShape = rotatedPin; - } - g2d.setColor(outlineMode ? Constants.TRANSPARENT_COLOR : PIN_COLOR); - if (getMount() == Mount.CHASSIS) - drawingObserver.startTrackingContinuityArea(true); - g2d.fill(pinShape); - drawingObserver.stopTrackingContinuityArea(); - if (!outlineMode) { - g2d.setColor(PIN_BORDER_COLOR); - g2d.draw(pinShape); - } - } - - // draw electrode labels - if (getElectrodeLabels() != null) { - g2d.setColor(getLabelColor()); - g2d.setFont(project.getFont().deriveFont((float) (project.getFont().getSize2D() * 0.8))); - String[] labels = getElectrodeLabels().split(","); - double electrodeLabelOffset = project.getFont().getSize2D() * (getBase() == Base.B9A && getMount() == Mount.PCB ? 1.5 : 1); - for (int i = 0; i < labels.length; i++) { - if (i < controlPoints.length - 1) { - String label = labels[i]; - double theta = Math.atan2(controlPoints[i + 1].getY() - controlPoints[0].getY(), controlPoints[i + 1].getX() - controlPoints[0].getX()); - double x = controlPoints[i + 1].getX() - Math.cos(theta) * electrodeLabelOffset; - double y = controlPoints[i + 1].getY() - Math.sin(theta) * electrodeLabelOffset; - StringUtils.drawCenteredText(g2d, label, (int)x, (int)y, HorizontalAlignment.CENTER, VerticalAlignment.CENTER); - } - } - } - } - - @Override - public void drawIcon(Graphics2D g2d, int width, int height) { - Area area = new Area(new Ellipse2D.Double(1, 1, width - 2, width - 2)); - int center = width / 2; - area.subtract(new Area(new Ellipse2D.Double(center - 2, center - 2, 5, 5))); - g2d.setColor(BODY_COLOR); - g2d.fill(area); - g2d.setColor(BODY_COLOR.darker()); - g2d.draw(area); - - int radius = width / 2 - 6; - for (int i = 0; i < 8; i++) { - int x = (int) (center + Math.cos(i * Math.PI / 4) * radius); - int y = (int) (center + Math.sin(i * Math.PI / 4) * radius); - g2d.setColor(PIN_COLOR); - g2d.fillOval(x - 1, y - 1, 3, 3); - g2d.setColor(PIN_BORDER_COLOR); - g2d.drawOval(x - 1, y - 1, 3, 3); - } - } - - @Override - public Point2D getControlPoint(int index) { - return controlPoints[index]; - } - - @Override - public int getControlPointCount() { - return controlPoints.length; - } - - @Override - public VisibilityPolicy getControlPointVisibilityPolicy(int index) { - return VisibilityPolicy.NEVER; - } - - @Override - @EditableProperty(name = "Designation") - public String getValue() { - return type; - } - - @Override - public void setValue(String value) { - this.type = value; - } - - @Override - public boolean isControlPointSticky(int index) { - return index > 0; - } - - @Override - public void setControlPoint(Point2D point, int index) { - controlPoints[index].setLocation(point); - - body = null; - } - - @Override - public boolean canPointMoveFreely(int pointIndex) { - return false; - } - - @EditableProperty(name = "Electrode Labels") - public String getElectrodeLabels() { - if (electrodeLabels == null) - electrodeLabels = "1,2,3,4,5,6,7,8,9,10,11,12"; - return electrodeLabels; - } - - public void setElectrodeLabels(String electrodeLabels) { - this.electrodeLabels = electrodeLabels; - } - - @EditableProperty(name = "Label") - public Color getLabelColor() { - if (labelColor == null) - labelColor = LABEL_COLOR; - return labelColor; - } - - public void setLabelColor(Color labelColor) { - this.labelColor = labelColor; - } - - @EditableProperty(name = "Mount") - public Mount getMount() { - if (mount == null) - mount = Mount.CHASSIS; - return mount; - } - - public void setMount(Mount mount) { - this.mount = mount; - - updateControlPoints(); - // Reset body shape - body = null; - } - - @Override - public String getControlPointNodeName(int index) { - String[] labels = getElectrodeLabels().split(","); - return index > 0 && index <= labels.length ? labels[index - 1] : null; - } - - @Override - public Rectangle2D getCachingBounds() { - Rectangle2D rect = getBody()[0].getBounds2D(); - int margin = 40; // to catch the pins that are outside the body, if needed - return new Rectangle2D.Double(rect.getX() - margin, rect.getY() - margin, rect.getWidth() + 2 * margin, rect.getHeight() + 2 * margin); - } - - public static enum Base { - B9A("Noval B9A"), OCTAL("Octal"), B7G("Small-button B7G"), B12C("Duodecar B12C"); - - String name; - - private Base(String name) { - this.name = name; - } - - @Override - public String toString() { - return name; - } - } - - public static enum Mount { - CHASSIS("Chassis"), PCB("PCB"); - - String name; - - private Mount(String name) { - this.name = name; - } - - @Override - public String toString() { - return name; - } - } -} +/* + + DIY Layout Creator (DIYLC). + Copyright (c) 2009-2025 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.tube; + +import java.awt.AlphaComposite; +import java.awt.Color; +import java.awt.Composite; +import java.awt.Graphics2D; +import java.awt.Shape; +import java.awt.geom.AffineTransform; +import java.awt.geom.Area; +import java.awt.geom.Ellipse2D; +import java.awt.geom.Point2D; +import java.awt.geom.Rectangle2D; +import org.diylc.appframework.miscutils.ConfigurationManager; + +import org.diylc.awt.StringUtils; +import org.diylc.common.HorizontalAlignment; +import org.diylc.common.IPlugInPort; +import org.diylc.common.ObjectCache; +import org.diylc.common.VerticalAlignment; +import org.diylc.components.AbstractAngledComponent; +import org.diylc.components.transform.AngledComponentTransformer; +import org.diylc.core.ComponentState; +import org.diylc.core.IDIYComponent; +import org.diylc.core.IDrawingObserver; +import org.diylc.core.Project; +import org.diylc.core.Theme; +import org.diylc.core.VisibilityPolicy; +import org.diylc.core.annotations.ComponentDescriptor; +import org.diylc.core.annotations.EditableProperty; +import org.diylc.core.annotations.KeywordPolicy; +import org.diylc.core.gerber.IGerberComponentSimple; +import org.diylc.core.measures.Size; +import org.diylc.core.measures.SizeUnit; +import org.diylc.utils.Constants; + +@ComponentDescriptor(name = "Tube Socket", author = "Branislav Stojkovic", category = "Tubes", + instanceNamePrefix = "V", description = "Various types of tube/valve sockets", + zOrder = IDIYComponent.COMPONENT, keywordPolicy = KeywordPolicy.SHOW_VALUE, enableCache = true, + transformer = AngledComponentTransformer.class) +public class TubeSocket extends AbstractAngledComponent implements IGerberComponentSimple { + + private static final Size B9A_PIN_SPACING_CHASSIS = new Size(12.5d, SizeUnit.mm); + private static final Size B9A_PIN_SPACING_PCB = new Size(21d, SizeUnit.mm); + private static final Size OCTAL_PIN_SPACING = new Size(17.5d, SizeUnit.mm); + private static final Size B7G_PIN_SPACING = new Size(12d, SizeUnit.mm); + private static final Size B7G_CUTOUT_DIAMETER = new Size(4d, SizeUnit.mm); + private static final Size B9A_CUTOUT_DIAMETER = new Size(5.5d, SizeUnit.mm); + private static final Size B12C_HOLE_SIZE = new Size(10d, SizeUnit.mm); + private static final Size B12C_CUTOUT_DIAMETER = new Size(5.5d, SizeUnit.mm); + private static final Size B12C_PIN_SPACING_PCB = new Size(25d, SizeUnit.mm); + private static final Size B12C_PIN_SPACING_CHASSIS = new Size(22d, SizeUnit.mm); + + private static final Size OCTAL_DIAMETER = new Size(25d, SizeUnit.mm); + private static final Size B9A_DIAMETER = new Size(3 / 4d, SizeUnit.in); + private static final Size B7G_DIAMETER = new Size(17d, SizeUnit.mm); + private static final Size B12C_DIAMETER = new Size(30d, SizeUnit.mm); + + private static final long serialVersionUID = 1L; + + private static Color BODY_COLOR = Color.decode("#F7F7EF"); + private static Color LABEL_COLOR = BODY_COLOR.darker(); + public static Color PIN_COLOR = METAL_COLOR; + public static Color PIN_BORDER_COLOR = PIN_COLOR.darker(); + public static Size PIN_DIAMETER = new Size(1d, SizeUnit.mm); + private static Size PIN_WIDTH = new Size(0.08d, SizeUnit.in); + private static Size PIN_THICKNESS = new Size(0.02d, SizeUnit.in); + public static Size HOLE_SIZE = new Size(5d, SizeUnit.mm); + public static Size OCTAL_TICK_SIZE = new Size(2d, SizeUnit.mm); + + private Base base = Base.B9A; + private String type = ""; + private Color color = BODY_COLOR; + private String electrodeLabels = null; + private Mount mount = Mount.CHASSIS; + private Color labelColor = LABEL_COLOR; + + private Point2D[] controlPoints = new Point2D[] {new Point2D.Double(0, 0)}; + + public TubeSocket() { + super(); + updateControlPoints(); + } + + @EditableProperty + public Base getBase() { + return base; + } + + public void setBase(Base base) { + this.base = base; + updateControlPoints(); + // Reset body shape + body = null; + } + + @EditableProperty + public Color getColor() { + if (color == null) { + color = BODY_COLOR; + } + return color; + } + + public void setColor(Color color) { + this.color = color; + } + + // @EditableProperty + // public Mount getMount() { + // return mount; + // } + // + // public void setMount(Mount mount) { + // this.mount = mount; + // } + + @Override + protected void updateControlPoints() { + Point2D firstPoint = controlPoints[0]; + int pinCount; + int pinSpacing; + boolean hasEmptySpace; + switch (base) { + case B7G: + pinCount = 7; + pinSpacing = getClosestOdd(B7G_PIN_SPACING.convertToPixels()); + hasEmptySpace = true; + break; + case OCTAL: + pinCount = 8; + pinSpacing = getClosestOdd(OCTAL_PIN_SPACING.convertToPixels()); + hasEmptySpace = false; + break; + case B9A: + pinCount = 9; + pinSpacing = getClosestOdd(getMount() == Mount.PCB ? B9A_PIN_SPACING_PCB.convertToPixels() : B9A_PIN_SPACING_CHASSIS.convertToPixels()); + hasEmptySpace = true; + break; + case B12C: + pinCount = 12; + pinSpacing = getClosestOdd(getMount() == Mount.PCB ? B12C_PIN_SPACING_PCB.convertToPixels() : B12C_PIN_SPACING_CHASSIS.convertToPixels()); + hasEmptySpace = true; + break; + default: + throw new RuntimeException("Unexpected base: " + base); + } + double angleIncrement = Math.PI * 2 / (hasEmptySpace ? (pinCount + 1) : pinCount); + double initialAngleOffset = hasEmptySpace ? angleIncrement : (angleIncrement / 2); + + controlPoints = new Point2D[pinCount + 1]; + double theta = initialAngleOffset + getAngle().getValueRad(); + controlPoints[0] = firstPoint; + for (int i = 0; i < pinCount; i++) { + controlPoints[i + 1] = + new Point2D.Double(firstPoint.getX() + Math.cos(theta) * pinSpacing / 2, + firstPoint.getY() + Math.sin(theta) * pinSpacing / 2); + theta += angleIncrement; + } + } + + public Shape[] getBody() { + if (body == null) { + int bodyDiameter; + switch (base) { + case B7G: + bodyDiameter = getClosestOdd(B7G_DIAMETER.convertToPixels()); + break; + case B9A: + bodyDiameter = getClosestOdd(B9A_DIAMETER.convertToPixels()); + break; + case OCTAL: + bodyDiameter = getClosestOdd(OCTAL_DIAMETER.convertToPixels()); + break; + case B12C: + bodyDiameter = getClosestOdd(B12C_DIAMETER.convertToPixels()); + break; + default: + throw new RuntimeException("Unexpected base: " + base); + } + + Ellipse2D baseShape = + new Ellipse2D.Double(controlPoints[0].getX() - bodyDiameter / 2, controlPoints[0].getY() - bodyDiameter / 2, + bodyDiameter, bodyDiameter); + Area bodyArea = new Area(baseShape); + int holeSize = getClosestOdd(base == Base.B12C ? B12C_HOLE_SIZE.convertToPixels() : HOLE_SIZE.convertToPixels()); + bodyArea.subtract(new Area(new Ellipse2D.Double(controlPoints[0].getX() - holeSize / 2, controlPoints[0].getY() - holeSize + / 2, holeSize, holeSize))); + + if (base == Base.OCTAL) { + int tickSize = getClosestOdd(OCTAL_TICK_SIZE.convertToPixels()); + double theta = getAngle().getValueRad(); + int centerX = (int) (controlPoints[0].getX() + Math.cos(theta) * holeSize / 2); + int centerY = (int) (controlPoints[0].getY() + Math.sin(theta) * holeSize / 2); + bodyArea.subtract(new Area(new Ellipse2D.Double(centerX - tickSize / 2, centerY - tickSize / 2, tickSize, + tickSize))); + } else if (base == Base.B9A && getMount() == Mount.CHASSIS) { + double cutoutDiameter = getClosestOdd(B9A_CUTOUT_DIAMETER.convertToPixels()); + bodyArea.subtract(new Area(new Ellipse2D.Double(controlPoints[0].getX() - cutoutDiameter / 2, controlPoints[0].getY() - bodyDiameter / 2 - cutoutDiameter * 3 / 4, cutoutDiameter, cutoutDiameter))); + bodyArea.subtract(new Area(new Ellipse2D.Double(controlPoints[0].getX() - cutoutDiameter / 2, controlPoints[0].getY() + bodyDiameter / 2 - cutoutDiameter / 4, cutoutDiameter, cutoutDiameter))); + } else if (base == Base.B7G && getMount() == Mount.CHASSIS) { + double cutoutDiameter = getClosestOdd(B7G_CUTOUT_DIAMETER.convertToPixels()); + bodyArea.subtract(new Area(new Ellipse2D.Double(controlPoints[0].getX() - cutoutDiameter / 2, controlPoints[0].getY() - bodyDiameter / 2 - cutoutDiameter * 3 / 4, cutoutDiameter, cutoutDiameter))); + bodyArea.subtract(new Area(new Ellipse2D.Double(controlPoints[0].getX() - cutoutDiameter / 2, controlPoints[0].getY() + bodyDiameter / 2 - cutoutDiameter / 4, cutoutDiameter, cutoutDiameter))); + } else if (base == Base.B12C && getMount() == Mount.CHASSIS) { + double cutoutDiameter = getClosestOdd(B12C_CUTOUT_DIAMETER.convertToPixels()); + bodyArea.subtract(new Area(new Ellipse2D.Double(controlPoints[0].getX() - cutoutDiameter / 2, controlPoints[0].getY() - bodyDiameter / 2 - cutoutDiameter * 3 / 4, cutoutDiameter, cutoutDiameter))); + bodyArea.subtract(new Area(new Ellipse2D.Double(controlPoints[0].getX() - cutoutDiameter / 2, controlPoints[0].getY() + bodyDiameter / 2 - cutoutDiameter / 4, cutoutDiameter, cutoutDiameter))); + } + + body = new Shape[] { bodyArea }; + } + return body; + } + + @Override + public void draw(Graphics2D g2d, ComponentState componentState, boolean outlineMode, Project project, + IDrawingObserver drawingObserver) { + + g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(1)); + + // Draw body + Shape[] body = getBody(); + Composite oldComposite = applyAlpha(g2d, componentState); + if (componentState != ComponentState.DRAGGING) { + g2d.setColor(outlineMode ? Constants.TRANSPARENT_COLOR : getColor()); + g2d.fill(body[0]); + } + 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 + : getColor().darker(); + } + g2d.setColor(finalBorderColor); + g2d.draw(body[0]); + + drawingObserver.stopTracking(); + + // Draw pins + + for (int i = 1; i < controlPoints.length; i++) { + Shape pinShape; + if (getMount() == Mount.PCB) { + int pinSize = getClosestOdd(PIN_DIAMETER.convertToPixels()); + pinShape = new Ellipse2D.Double(controlPoints[i].getX() - pinSize / 2, + controlPoints[i].getY() - pinSize / 2, pinSize, pinSize); + } else { + int pinWidth = getClosestOdd(PIN_WIDTH.convertToPixels()); + int pinThickness = getClosestOdd(PIN_THICKNESS.convertToPixels()); + pinShape = new Rectangle2D.Double(controlPoints[i].getX() - pinWidth / 2, + controlPoints[i].getY() - pinThickness / 2, pinWidth, pinThickness); + double theta = Math.atan2(controlPoints[i].getY() - controlPoints[0].getY(), + controlPoints[i].getX() - controlPoints[0].getX()) + Math.PI / 2; + Area rotatedPin = new Area(pinShape); + rotatedPin.transform(AffineTransform.getRotateInstance(theta, controlPoints[i].getX(), + controlPoints[i].getY())); + pinShape = rotatedPin; + } + g2d.setColor(outlineMode ? Constants.TRANSPARENT_COLOR : PIN_COLOR); + if (getMount() == Mount.CHASSIS) + drawingObserver.startTrackingContinuityArea(true); + g2d.fill(pinShape); + drawingObserver.stopTrackingContinuityArea(); + if (!outlineMode) { + g2d.setColor(PIN_BORDER_COLOR); + g2d.draw(pinShape); + } + } + + // draw electrode labels + if (getElectrodeLabels() != null) { + g2d.setColor(getLabelColor()); + g2d.setFont(project.getFont().deriveFont((float) (project.getFont().getSize2D() * 0.8))); + String[] labels = getElectrodeLabels().split(","); + double electrodeLabelOffset = project.getFont().getSize2D() * (getBase() == Base.B9A && getMount() == Mount.PCB ? 1.5 : 1); + for (int i = 0; i < labels.length; i++) { + if (i < controlPoints.length - 1) { + String label = labels[i]; + double theta = Math.atan2(controlPoints[i + 1].getY() - controlPoints[0].getY(), controlPoints[i + 1].getX() - controlPoints[0].getX()); + double x = controlPoints[i + 1].getX() - Math.cos(theta) * electrodeLabelOffset; + double y = controlPoints[i + 1].getY() - Math.sin(theta) * electrodeLabelOffset; + StringUtils.drawCenteredText(g2d, label, (int)x, (int)y, HorizontalAlignment.CENTER, VerticalAlignment.CENTER); + } + } + } + } + + @Override + public void drawIcon(Graphics2D g2d, int width, int height) { + Area area = new Area(new Ellipse2D.Double(1, 1, width - 2, width - 2)); + int center = width / 2; + area.subtract(new Area(new Ellipse2D.Double(center - 2, center - 2, 5, 5))); + g2d.setColor(BODY_COLOR); + g2d.fill(area); + g2d.setColor(BODY_COLOR.darker()); + g2d.draw(area); + + int radius = width / 2 - 6; + for (int i = 0; i < 8; i++) { + int x = (int) (center + Math.cos(i * Math.PI / 4) * radius); + int y = (int) (center + Math.sin(i * Math.PI / 4) * radius); + g2d.setColor(PIN_COLOR); + g2d.fillOval(x - 1, y - 1, 3, 3); + g2d.setColor(PIN_BORDER_COLOR); + g2d.drawOval(x - 1, y - 1, 3, 3); + } + } + + @Override + public Point2D getControlPoint(int index) { + return controlPoints[index]; + } + + @Override + public int getControlPointCount() { + return controlPoints.length; + } + + @Override + public VisibilityPolicy getControlPointVisibilityPolicy(int index) { + return VisibilityPolicy.NEVER; + } + + @Override + @EditableProperty(name = "Designation") + public String getValue() { + return type; + } + + @Override + public void setValue(String value) { + this.type = value; + } + + @Override + public boolean isControlPointSticky(int index) { + return index > 0; + } + + @Override + public void setControlPoint(Point2D point, int index) { + controlPoints[index].setLocation(point); + + body = null; + } + + @Override + public boolean canPointMoveFreely(int pointIndex) { + return false; + } + + @EditableProperty(name = "Electrode Labels") + public String getElectrodeLabels() { + if (electrodeLabels == null) + electrodeLabels = "1,2,3,4,5,6,7,8,9,10,11,12"; + return electrodeLabels; + } + + public void setElectrodeLabels(String electrodeLabels) { + this.electrodeLabels = electrodeLabels; + } + + @EditableProperty(name = "Label") + public Color getLabelColor() { + if (labelColor == null) + labelColor = LABEL_COLOR; + return labelColor; + } + + public void setLabelColor(Color labelColor) { + this.labelColor = labelColor; + } + + @EditableProperty(name = "Mount") + public Mount getMount() { + if (mount == null) + mount = Mount.CHASSIS; + return mount; + } + + public void setMount(Mount mount) { + this.mount = mount; + + updateControlPoints(); + // Reset body shape + body = null; + } + + @Override + public String getControlPointNodeName(int index) { + String[] labels = getElectrodeLabels().split(","); + return index > 0 && index <= labels.length ? labels[index - 1] : null; + } + + @Override + public Rectangle2D getCachingBounds() { + Rectangle2D rect = getBody()[0].getBounds2D(); + int margin = 40; // to catch the pins that are outside the body, if needed + return new Rectangle2D.Double(rect.getX() - margin, rect.getY() - margin, rect.getWidth() + 2 * margin, rect.getHeight() + 2 * margin); + } + + public static enum Base { + B9A("Noval B9A"), OCTAL("Octal"), B7G("Small-button B7G"), B12C("Duodecar B12C"); + + String name; + + private Base(String name) { + this.name = name; + } + + @Override + public String toString() { + return name; + } + } + + public static enum Mount { + CHASSIS("Chassis"), PCB("PCB"); + + String name; + + private Mount(String name) { + this.name = name; + } + + @Override + public String toString() { + return name; + } + } +} diff --git a/diylc/diylc-library/src/main/java/org/diylc/serialization/V1FileParser.java b/diylc/diylc-library/src/main/java/org/diylc/serialization/V1FileParser.java index 2e16f7dc4..f8fc0bfec 100644 --- a/diylc/diylc-library/src/main/java/org/diylc/serialization/V1FileParser.java +++ b/diylc/diylc-library/src/main/java/org/diylc/serialization/V1FileParser.java @@ -31,15 +31,11 @@ import java.util.List; import java.util.Map; import java.util.Random; import org.apache.log4j.Logger; +import org.diylc.common.*; import org.w3c.dom.Element; import org.w3c.dom.Node; import org.w3c.dom.NodeList; -import org.diylc.common.Display; -import org.diylc.common.HorizontalAlignment; -import org.diylc.common.Orientation; -import org.diylc.common.OrientationHV; -import org.diylc.common.VerticalAlignment; import org.diylc.components.AbstractLeadedComponent; import org.diylc.components.AbstractTransparentComponent; import org.diylc.components.boards.AbstractBoard; @@ -673,7 +669,7 @@ public class V1FileParser implements IOldFileParser { ((AbstractLeadedComponent) component).setDisplay(Display.NAME); } if (component instanceof AbstractTransparentComponent) { - ((AbstractTransparentComponent) component).setAlpha((byte) 100); + ((AbstractTransparentComponent) component).setAlpha(new Percentage(100)); } project.getComponents().add(component); } diff --git a/diylc/diylc-library/src/main/java/org/diylc/serialization/V2FileParser.java b/diylc/diylc-library/src/main/java/org/diylc/serialization/V2FileParser.java index 3d9cc20d6..d9c94801d 100644 --- a/diylc/diylc-library/src/main/java/org/diylc/serialization/V2FileParser.java +++ b/diylc/diylc-library/src/main/java/org/diylc/serialization/V2FileParser.java @@ -27,6 +27,7 @@ import java.util.ArrayList; import java.util.List; import org.apache.log4j.Logger; import org.diylc.appframework.miscutils.ConfigurationManager; +import org.diylc.common.Percentage; import org.nfunk.jep.JEP; import org.w3c.dom.Element; import org.w3c.dom.Node; @@ -83,10 +84,8 @@ import org.diylc.core.measures.ResistanceUnit; import org.diylc.core.measures.Size; import org.diylc.core.measures.SizeUnit; import org.diylc.presenter.Presenter; -import org.diylc.serialization.IOldFileParser; import org.diylc.utils.Constants; - public class V2FileParser implements IOldFileParser { private static final Logger LOG = Logger.getLogger(V2FileParser.class); @@ -142,9 +141,9 @@ public class V2FileParser implements IOldFileParser { if (node.getNodeType() == Node.ELEMENT_NODE) { if (node.getNodeName().equalsIgnoreCase("component")) { LOG.debug(node.getAttributes().getNamedItem("name").getNodeValue()); - NodeList unuci = node.getChildNodes(); - Node properties = unuci.item(1); - Node points = unuci.item(3); + NodeList grandchildNodes = node.getChildNodes(); + Node properties = grandchildNodes.item(1); + Node points = grandchildNodes.item(3); NodeList propertyList = properties.getChildNodes(); NodeList pointList = points.getChildNodes(); @@ -174,7 +173,6 @@ public class V2FileParser implements IOldFileParser { // // gives Name Part# Thickness Color Group if (propertyList.item(j).getAttributes().getNamedItem("name").getNodeValue().equalsIgnoreCase("color")) { String color = propertyList.item(j).getAttributes().getNamedItem("value").getNodeValue(); - System.out.println(color); String hex_r = color.substring(0, 2); int value_r = Integer.parseInt(hex_r, 16); String hex_g = color.substring(2, 4); @@ -234,7 +232,7 @@ public class V2FileParser implements IOldFileParser { } else if (propertyList.item(j).getAttributes().getNamedItem("name").getNodeValue() .equalsIgnoreCase("Value")) { String pr8 = propertyList.item(j).getAttributes().getNamedItem("value").getNodeValue(); - if (pr8 != "") { + if (!pr8.isEmpty()) { value_s = pr8; String pr9 = pr8.replaceAll("[^0-9.]", ""); String pr10 = pr8.replaceAll("[^a-zA-Z]", ""); @@ -287,7 +285,7 @@ public class V2FileParser implements IOldFileParser { if (cl != null) { board.setBoardColor(cl); } - if (com_name != "") { + if (!com_name.isEmpty()) { board.setName(com_name); } else { board.setName("Main board"); @@ -298,7 +296,7 @@ public class V2FileParser implements IOldFileParser { } else if (node.getAttributes().getNamedItem("name").getNodeValue().equalsIgnoreCase("Perfboard")) { PerfBoard board = new PerfBoard(); board.setBoardColor(Color.white); - if (com_name != "") { + if (!com_name.isEmpty()) { board.setName(com_name); } else { board.setName("Main board"); @@ -309,7 +307,7 @@ public class V2FileParser implements IOldFileParser { project.getComponents().add(board); } else if (node.getAttributes().getNamedItem("name").getNodeValue().equalsIgnoreCase("Copper Trace")) { CopperTrace trace = new CopperTrace(); - if (com_name != "") { + if (!com_name.isEmpty()) { trace.setName(com_name); } else { trace.setName("t"); @@ -324,7 +322,7 @@ public class V2FileParser implements IOldFileParser { } else if (node.getAttributes().getNamedItem("name").getNodeValue().equalsIgnoreCase("Copper Trace Curved")) { CurvedTrace trace = new CurvedTrace(); - if (com_name != "") { + if (!com_name.isEmpty()) { trace.setName(com_name); } else { trace.setName("t"); @@ -340,7 +338,7 @@ public class V2FileParser implements IOldFileParser { project.getComponents().add(trace); } else if (node.getAttributes().getNamedItem("name").getNodeValue().equalsIgnoreCase("Eyelet")) { Eyelet eyelet = new Eyelet(); - if (com_name != "") { + if (!com_name.isEmpty()) { eyelet.setName(com_name); } else { eyelet.setName("eyelet"); @@ -350,7 +348,7 @@ public class V2FileParser implements IOldFileParser { project.getComponents().add(eyelet); } else if (node.getAttributes().getNamedItem("name").getNodeValue().equalsIgnoreCase("Solder pad")) { SolderPad pad = new SolderPad(); - if (com_name != "") { + if (!com_name.isEmpty()) { pad.setName(com_name); } else pad.setName("pad"); @@ -363,7 +361,7 @@ public class V2FileParser implements IOldFileParser { project.getComponents().add(pad); } else if (node.getAttributes().getNamedItem("name").getNodeValue().equalsIgnoreCase("Stripboard")) { VeroBoard board = new VeroBoard(); - if (com_name != "") { + if (!com_name.isEmpty()) { board.setName(com_name); } else { board.setName("Main board"); @@ -374,7 +372,7 @@ public class V2FileParser implements IOldFileParser { project.getComponents().add(board); } else if (node.getAttributes().getNamedItem("name").getNodeValue().equalsIgnoreCase("Trace Cut")) { TraceCut cut = new TraceCut(); - if (com_name != "") { + if (!com_name.isEmpty()) { cut.setName(com_name); } else cut.setName("cut"); @@ -383,7 +381,7 @@ public class V2FileParser implements IOldFileParser { } else if (node.getAttributes().getNamedItem("name").getNodeValue().equalsIgnoreCase("Switch")) { MiniToggleSwitch sw = new MiniToggleSwitch(); sw.setValue(ToggleSwitchType.DPDT); - if (com_name != "") { + if (!com_name.isEmpty()) { sw.setName(com_name); } else sw.setName("sw"); @@ -416,7 +414,7 @@ public class V2FileParser implements IOldFileParser { project.getComponents().add(sw); } else if (node.getAttributes().getNamedItem("name").getNodeValue().equalsIgnoreCase("Wire")) { HookupWire hw = new HookupWire(); - if (com_name != "") { + if (!com_name.isEmpty()) { hw.setName(com_name); } else hw.setName("hookup_wire"); @@ -472,11 +470,11 @@ public class V2FileParser implements IOldFileParser { project.getComponents().add(hw); } else if (node.getAttributes().getNamedItem("name").getNodeValue().equalsIgnoreCase("Electrolytic (Axial)")) { AxialElectrolyticCapacitor capacitor = new AxialElectrolyticCapacitor(); - if (com_name != "") { + if (!com_name.isEmpty()) { capacitor.setName(com_name); } else capacitor.setName("A_E_C"); - capacitor.setAlpha((byte) transparency); + capacitor.setAlpha(new Percentage(transparency)); if (value != -9999) { capacitor.setValue(new Capacitance(value, cp)); } @@ -492,10 +490,10 @@ public class V2FileParser implements IOldFileParser { project.getComponents().add(capacitor); } else if (node.getAttributes().getNamedItem("name").getNodeValue().equalsIgnoreCase("Capacitor (Axial)")) { AxialFilmCapacitor capacitor = new AxialFilmCapacitor(); - if (com_name != "") { + if (!com_name.isEmpty()) { capacitor.setName(com_name); } - capacitor.setAlpha((byte) transparency); + capacitor.setAlpha(new Percentage(transparency)); if (value != -9999) { capacitor.setValue(new Capacitance(value, cp)); } else @@ -512,11 +510,11 @@ public class V2FileParser implements IOldFileParser { project.getComponents().add(capacitor); } else if (node.getAttributes().getNamedItem("name").getNodeValue().equalsIgnoreCase("Capacitor (Ceramic)")) { RadialCeramicDiskCapacitor capacitor = new RadialCeramicDiskCapacitor(); - if (com_name != "") { + if (!com_name.isEmpty()) { capacitor.setName(com_name); } else capacitor.setName("Radial_Ceramic_Capacitor"); - capacitor.setAlpha((byte) transparency); + capacitor.setAlpha(new Percentage(transparency)); if (value != -9999) { capacitor.setValue(new Capacitance(value, cp)); } @@ -532,11 +530,11 @@ public class V2FileParser implements IOldFileParser { project.getComponents().add(capacitor); } else if (node.getAttributes().getNamedItem("name").getNodeValue().equalsIgnoreCase("Capacitor (Radial)")) { RadialFilmCapacitor capacitor = new RadialFilmCapacitor(); - if (com_name != "") { + if (!com_name.isEmpty()) { capacitor.setName(com_name); } else capacitor.setName("Radial_Film_Capacitor"); - capacitor.setAlpha((byte) transparency); + capacitor.setAlpha(new Percentage(transparency)); if (value != -9999) { capacitor.setValue(new Capacitance(value, cp)); } @@ -552,28 +550,28 @@ public class V2FileParser implements IOldFileParser { project.getComponents().add(capacitor); } else if (node.getAttributes().getNamedItem("name").getNodeValue().equalsIgnoreCase("Electrolytic (Radial)")) { RadialElectrolytic capacitor = new RadialElectrolytic(); - if (com_name != "") { + if (!com_name.isEmpty()) { capacitor.setName(com_name); } else capacitor.setName("Radial_Electrolytic_Capacitor"); if (value != -9999) { capacitor.setValue(new Capacitance(value, cp)); } - capacitor.setAlpha((byte) transparency); + capacitor.setAlpha(new Percentage(transparency)); capacitor.setLength(diameterPro); capacitor.setControlPoint(tacke.get(0), 0); capacitor.setControlPoint(tacke.get(1), 1); project.getComponents().add(capacitor); } else if (node.getAttributes().getNamedItem("name").getNodeValue().equalsIgnoreCase("Potentiometer Lug")) { PotentiometerPanel panel = new PotentiometerPanel(); - if (com_name != "") { + if (!com_name.isEmpty()) { panel.setName(com_name); } else panel.setName("potentiometer_panel"); if (value != -9999) { panel.setValue(new Resistance(value, ru)); } - panel.setAlpha((byte) transparency); + panel.setAlpha(new Percentage(transparency)); if (angle > 45 && angle <= 135) panel.setOrientation(Orientation._90); else if (angle > 135 && angle <= 225) @@ -592,14 +590,14 @@ public class V2FileParser implements IOldFileParser { } else if (node.getAttributes().getNamedItem("name").getNodeValue().equalsIgnoreCase("Resistor") || node.getAttributes().getNamedItem("name").getNodeValue().equalsIgnoreCase("Resistor Standing")) { Resistor resistor = new Resistor(); - if (com_name != "") { + if (!com_name.isEmpty()) { resistor.setName(com_name); } else resistor.setName("resistor"); if (value != -9999) { resistor.setValue(new Resistance(value, ru)); } - resistor.setAlpha((byte) transparency); + resistor.setAlpha(new Percentage(transparency)); resistor.setWidth(diameterPro); if (lengthPro.getValue() != 0) { resistor.setLength(lengthPro); @@ -609,7 +607,7 @@ public class V2FileParser implements IOldFileParser { project.getComponents().add(resistor); } else if (node.getAttributes().getNamedItem("name").getNodeValue().equalsIgnoreCase("Capacitor Symbol")) { CapacitorSymbol cap = new CapacitorSymbol(); - if (com_name != "") { + if (!com_name.isEmpty()) { cap.setName(com_name); } else cap.setName("cap_simbol"); @@ -625,7 +623,7 @@ public class V2FileParser implements IOldFileParser { project.getComponents().add(cap); } else if (node.getAttributes().getNamedItem("name").getNodeValue().equalsIgnoreCase("Diode Symbol")) { DiodeSymbol dio = new DiodeSymbol(); - if (com_name != "") { + if (!com_name.isEmpty()) { dio.setName(com_name); } else dio.setName("dp"); @@ -639,7 +637,7 @@ public class V2FileParser implements IOldFileParser { project.getComponents().add(dio); } else if (node.getAttributes().getNamedItem("name").getNodeValue().equalsIgnoreCase("Ground Symbol")) { GroundSymbol gs = new GroundSymbol(); - if (com_name != "") { + if (!com_name.isEmpty()) { gs.setName(com_name); } else gs.setName("gs"); @@ -648,11 +646,11 @@ public class V2FileParser implements IOldFileParser { project.getComponents().add(gs); } else if (node.getAttributes().getNamedItem("name").getNodeValue().equalsIgnoreCase("LED Symbol")) { LEDSymbol ls = new LEDSymbol(); - if (com_name != "") { + if (!com_name.isEmpty()) { ls.setName(com_name); } else ls.setName("ls"); - if (value_s != "") { + if (!value_s.isEmpty()) { ls.setValue(value_s); } ls.setBodyColor(cl); @@ -662,12 +660,12 @@ public class V2FileParser implements IOldFileParser { project.getComponents().add(ls); } else if (node.getAttributes().getNamedItem("name").getNodeValue().equalsIgnoreCase("Pentode")) { PentodeSymbol ps = new PentodeSymbol(); - if (com_name != "") { + if (!com_name.isEmpty()) { ps.setName(com_name); } else ps.setName("ps"); ps.setColor(cl); - if (value_s != "") + if (!value_s.isEmpty()) ps.setValue(value_s); Point point; @@ -678,7 +676,7 @@ public class V2FileParser implements IOldFileParser { project.getComponents().add(ps); } else if (node.getAttributes().getNamedItem("name").getNodeValue().equalsIgnoreCase("Electrolytic Symbol")) { CapacitorSymbol cs = new CapacitorSymbol(); - if (com_name != "") { + if (!com_name.isEmpty()) { cs.setName(com_name); } else cs.setName("cs"); @@ -694,13 +692,13 @@ public class V2FileParser implements IOldFileParser { project.getComponents().add(cs); } else if (node.getAttributes().getNamedItem("name").getNodeValue().equalsIgnoreCase("Opamp Symbol")) { ICSymbol ic = new ICSymbol(); - if (com_name != "") { + if (!com_name.isEmpty()) { ic.setName(com_name); } else ic.setName("ics"); - if (value_s != "") + if (!value_s.isEmpty()) ic.setValue(value_s); - ic.setAlpha((byte) transparency); + ic.setAlpha(new Percentage(transparency)); Point point; int x = (int) (tacke.get(0).getX() - 70); int y = (int) tacke.get(0).getY() - 20; @@ -710,12 +708,12 @@ public class V2FileParser implements IOldFileParser { project.getComponents().add(ic); } else if (node.getAttributes().getNamedItem("name").getNodeValue().equalsIgnoreCase("Potentiometer Symbol")) { PotentiometerSymbol ps = new PotentiometerSymbol(); - if (com_name != "") { + if (!com_name.isEmpty()) { ps.setName(com_name); } else ps.setName("ps"); ps.setOrientation(Orientation._270); - if (value_s != "") + if (!value_s.isEmpty()) ps.setValue(value_s); ps.setColor(cl); Point point; @@ -730,7 +728,7 @@ public class V2FileParser implements IOldFileParser { project.getComponents().add(ps); } else if (node.getAttributes().getNamedItem("name").getNodeValue().equalsIgnoreCase("Resistor Symbol")) { ResistorSymbol rs = new ResistorSymbol(); - if (com_name != "") { + if (!com_name.isEmpty()) { rs.setName(com_name); } else rs.setName("rs"); @@ -746,11 +744,11 @@ public class V2FileParser implements IOldFileParser { project.getComponents().add(rs); } else if (node.getAttributes().getNamedItem("name").getNodeValue().equalsIgnoreCase("Triode")) { TriodeSymbol ts = new TriodeSymbol(); - if (com_name != "") { + if (!com_name.isEmpty()) { ts.setName(com_name); } else ts.setName("ts"); - if (value_s != "") { + if (!value_s.isEmpty()) { ts.setValue(value_s); } ts.setColor(cl); @@ -762,14 +760,14 @@ public class V2FileParser implements IOldFileParser { project.getComponents().add(ts); } else if (node.getAttributes().getNamedItem("name").getNodeValue().equalsIgnoreCase("Diode")) { DiodePlastic dp = new DiodePlastic(); - if (com_name != "") { + if (!com_name.isEmpty()) { dp.setName(com_name); } else dp.setName("dp"); - if (value_s != "") { + if (!value_s.isEmpty()) { dp.setValue(value_s); } - dp.setAlpha((byte) transparency); + dp.setAlpha(new Percentage(transparency)); if (display.equals("Name")) dp.setDisplay(Display.NAME); else @@ -781,7 +779,7 @@ public class V2FileParser implements IOldFileParser { project.getComponents().add(dp); } else if (node.getAttributes().getNamedItem("name").getNodeValue().equalsIgnoreCase("IC DIL")) { DIL_IC dil = new DIL_IC(); - if (com_name != "") { + if (!com_name.isEmpty()) { dil.setName(com_name); } else dil.setName("dil"); @@ -795,8 +793,6 @@ public class V2FileParser implements IOldFileParser { dil.setPinCount(PinCount._10); else if (pins == 12) dil.setPinCount(PinCount._12); - else if (pins == 12) - dil.setPinCount(PinCount._12); else if (pins == 14) dil.setPinCount(PinCount._14); else if (pins == 16) @@ -835,8 +831,8 @@ public class V2FileParser implements IOldFileParser { dil.setPinCount(PinCount._48); else if (pins == 50) dil.setPinCount(PinCount._50); - dil.setAlpha((byte) transparency); - if (value_s != "") + dil.setAlpha(new Percentage(transparency)); + if (!value_s.isEmpty()) dil.setValue(value_s); dil.setRowSpacing(spacingPro); dil.setControlPoint(tacke.get(0), 0); @@ -844,12 +840,12 @@ public class V2FileParser implements IOldFileParser { project.getComponents().add(dil); } else if (node.getAttributes().getNamedItem("name").getNodeValue().equalsIgnoreCase("Transistor")) { TransistorTO92 trans = new TransistorTO92(); - if (com_name != "") { + if (!com_name.isEmpty()) { trans.setName(com_name); } else trans.setName("tr"); - trans.setAlpha((byte) transparency); - if (value_s != "") { + trans.setAlpha(new Percentage(transparency)); + if (!value_s.isEmpty()) { trans.setValue(value_s); } trans.setPinSpacing(new Size(0.1, SizeUnit.in)); @@ -898,7 +894,7 @@ public class V2FileParser implements IOldFileParser { } else if (node.getAttributes().getNamedItem("name").getNodeValue().equalsIgnoreCase("Ellipse")) { Ellipse el = new Ellipse(); el.setName("elipse"); - el.setAlpha((byte) transparency); + el.setAlpha(new Percentage(transparency)); el.setColor(cl); el.setControlPoint(tacke.get(0), 0); el.setControlPoint(tacke.get(1), 1); @@ -915,19 +911,19 @@ public class V2FileParser implements IOldFileParser { Rectangle rec = new Rectangle(); rec.setName("rec"); rec.setColor(cl); - rec.setAlpha((byte) transparency); + rec.setAlpha(new Percentage(transparency)); rec.setEdgeRadius(radiusPro); rec.setControlPoint(tacke.get(0), 0); rec.setControlPoint(tacke.get(1), 1); project.getComponents().add(rec); } else if (node.getAttributes().getNamedItem("name").getNodeValue().equalsIgnoreCase("Noval Tube Socket")) { TubeSocket ts = new TubeSocket(); - if (com_name != "") { + if (!com_name.isEmpty()) { ts.setName(com_name); } else ts.setName("ts"); - ts.setAlpha((byte) transparency); - if (value_s != "") + ts.setAlpha(new Percentage(transparency)); + if (!value_s.isEmpty()) ts.setValue(value_s); ts.setAngle(Angle.of((int) angle)); ts.setControlPoint(tacke.get(0), 0); @@ -935,12 +931,12 @@ public class V2FileParser implements IOldFileParser { project.getComponents().add(ts); } else if (node.getAttributes().getNamedItem("name").getNodeValue().equalsIgnoreCase("BJT Transistor")) { BJTSymbol bjt = new BJTSymbol(); - if (com_name != "") { + if (!com_name.isEmpty()) { bjt.setName(com_name); } else bjt.setName("bjt"); bjt.setColor(cl); - if (value_s != "") + if (!value_s.isEmpty()) bjt.setValue(value_s); if (angle <= 45 || angle > 315) bjt.setOrientation(Orientation.DEFAULT); @@ -958,12 +954,12 @@ public class V2FileParser implements IOldFileParser { project.getComponents().add(bjt); } else if (node.getAttributes().getNamedItem("name").getNodeValue().equalsIgnoreCase("Octal Tube Socket")) { TubeSocket ts = new TubeSocket(); - if (com_name != "") { + if (!com_name.isEmpty()) { ts.setName(com_name); } else ts.setName("ts"); - ts.setAlpha((byte) transparency); - if (value_s != "") + ts.setAlpha(new Percentage(transparency)); + if (!value_s.isEmpty()) ts.setValue(value_s); ts.setAngle(Angle.of((int) angle)); ts.setControlPoint(tacke.get(0), 0); @@ -971,12 +967,12 @@ public class V2FileParser implements IOldFileParser { project.getComponents().add(ts); } else if (node.getAttributes().getNamedItem("name").getNodeValue().equalsIgnoreCase("7-pin Tube Socket")) { TubeSocket ts = new TubeSocket(); - if (com_name != "") { + if (!com_name.isEmpty()) { ts.setName(com_name); } else ts.setName("ts"); - ts.setAlpha((byte) transparency); - if (value_s != "") + ts.setAlpha(new Percentage(transparency)); + if (!value_s.isEmpty()) ts.setValue(value_s); ts.setAngle(Angle.of((int)angle)); diff --git a/diylc/diylc-swing/src/main/java/org/diylc/swing/gui/editor/FieldEditorFactory.java b/diylc/diylc-swing/src/main/java/org/diylc/swing/gui/editor/FieldEditorFactory.java index 3ef102417..7bd3cf5d0 100644 --- a/diylc/diylc-swing/src/main/java/org/diylc/swing/gui/editor/FieldEditorFactory.java +++ b/diylc/diylc-swing/src/main/java/org/diylc/swing/gui/editor/FieldEditorFactory.java @@ -26,6 +26,7 @@ import java.awt.Component; import java.awt.Font; import javax.swing.JLabel; import org.apache.log4j.Logger; +import org.diylc.common.Percentage; import org.diylc.components.misc.LoadlineEntity; import org.diylc.common.PropertyWrapper; @@ -99,8 +100,8 @@ public class FieldEditorFactory { DynamicValueEditor editor = new DynamicValueEditor(property); return editor; } - if (Byte.class.isAssignableFrom(property.getType()) || byte.class.isAssignableFrom(property.getType())) { - ByteEditor editor = new ByteEditor(property); + if (Percentage.class.isAssignableFrom(property.getType())) { + PercentageEditor editor = new PercentageEditor(property); return editor; } if (Boolean.class.isAssignableFrom(property.getType()) || boolean.class.isAssignableFrom(property.getType())) { diff --git a/diylc/diylc-swing/src/main/java/org/diylc/swing/gui/editor/ByteEditor.java b/diylc/diylc-swing/src/main/java/org/diylc/swing/gui/editor/PercentageEditor.java similarity index 65% rename from diylc/diylc-swing/src/main/java/org/diylc/swing/gui/editor/ByteEditor.java rename to diylc/diylc-swing/src/main/java/org/diylc/swing/gui/editor/PercentageEditor.java index 44008a191..361f04062 100644 --- a/diylc/diylc-swing/src/main/java/org/diylc/swing/gui/editor/ByteEditor.java +++ b/diylc/diylc-swing/src/main/java/org/diylc/swing/gui/editor/PercentageEditor.java @@ -1,117 +1,120 @@ -/* - - DIY Layout Creator (DIYLC). - Copyright (c) 2009-2025 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.swing.gui.editor; - -import java.awt.Color; -import java.awt.FlowLayout; -import java.awt.event.KeyAdapter; -import java.awt.event.KeyEvent; -import javax.swing.JLabel; -import javax.swing.JPanel; -import javax.swing.JSlider; -import javax.swing.event.ChangeEvent; -import javax.swing.event.ChangeListener; - -import org.diylc.swingframework.DoubleTextField; - -import org.diylc.common.PropertyWrapper; -import org.diylc.core.annotations.PercentEditor; -import org.diylc.utils.Constants; - -public class ByteEditor extends JPanel { - - private static final long serialVersionUID = 1L; - - private Color oldBg = getBackground(); - - private static final byte default100Percent = 127; - - private byte _100PercentValue; - - public ByteEditor(final PropertyWrapper property) { - super(); - - setLayout(new FlowLayout()); - - try { - PercentEditor percentEditor = property.getGetter().getAnnotation(PercentEditor.class); - if (percentEditor == null) - _100PercentValue = default100Percent; - else - _100PercentValue = percentEditor._100PercentValue(); - } catch (Exception e) { - _100PercentValue = default100Percent; - } - - final JSlider slider = new JSlider(); - final DoubleTextField valueField = new DoubleTextField(); - - if (property.isReadOnly()) { - slider.setEnabled(false); - valueField.setEnabled(false); - } - - final double percentFactor = (double) default100Percent / _100PercentValue; - - slider.setMinimum(0); - slider.setMaximum(default100Percent * 100); - - slider.addChangeListener(new ChangeListener() { - - @Override - public void stateChanged(ChangeEvent e) { - property.setChanged(true); - setBackground(oldBg); - slider.setBackground(oldBg); - property.setValue(Integer.valueOf(slider.getValue() / 100).byteValue()); - valueField.setText(Integer.toString((int) Math.round(percentFactor * (double) slider.getValue() - / default100Percent))); - } - }); - slider.setValue((Byte) property.getValue() * 100); - - valueField - .setText(Integer.toString((int) Math.round(percentFactor * (double) slider.getValue() / default100Percent))); - valueField.setColumns(3); - valueField.addKeyListener(new KeyAdapter() { - - @Override - public void keyReleased(KeyEvent e) { - try { - int newPosition = (int) (Double.parseDouble(valueField.getText()) * default100Percent / percentFactor); - System.out.println("keyReleased, pos: " + newPosition); - slider.setValue(newPosition); - } catch (Exception ex) { - } - } - }); - - if (!property.isUnique()) { - setBackground(Constants.MULTI_VALUE_COLOR); - slider.setBackground(Constants.MULTI_VALUE_COLOR); - } - - add(slider); - add(valueField); - add(new JLabel("%")); - } -} +/* + + DIY Layout Creator (DIYLC). + Copyright (c) 2009-2025 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.swing.gui.editor; + +import java.awt.Color; +import java.awt.FlowLayout; +import java.awt.event.KeyAdapter; +import java.awt.event.KeyEvent; +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.JSlider; +import javax.swing.event.ChangeEvent; +import javax.swing.event.ChangeListener; + +import org.diylc.swingframework.DoubleTextField; + +import org.diylc.common.Percentage; +import org.diylc.common.PropertyWrapper; +import org.diylc.core.annotations.PercentEditor; +import org.diylc.utils.Constants; + +public class PercentageEditor extends JPanel { + + private static final long serialVersionUID = 1L; + + private Color oldBg = getBackground(); + + private int minValue = 0; + private int maxValue = 100; + + public PercentageEditor(final PropertyWrapper property) { + super(); + + setLayout(new FlowLayout()); + + try { + PercentEditor percentEditor = property.getGetter().getAnnotation(PercentEditor.class); + if (percentEditor != null) { + minValue = percentEditor.minValue(); + maxValue = percentEditor.maxValue(); + } + } catch (Exception e) { + } + + final JSlider slider = new JSlider(); + final DoubleTextField valueField = new DoubleTextField(); + + if (property.isReadOnly()) { + slider.setEnabled(false); + valueField.setEnabled(false); + } + + slider.setMinimum(minValue); + slider.setMaximum(maxValue); + + slider.addChangeListener(new ChangeListener() { + + @Override + public void stateChanged(ChangeEvent e) { + property.setChanged(true); + setBackground(oldBg); + slider.setBackground(oldBg); + + property.setValue(new Percentage(slider.getValue())); + valueField.setText(Integer.toString(slider.getValue())); + } + }); + + Object val = property.getValue(); + if (val != null) { + slider.setValue(((Percentage) val).getValue()); + } else { + slider.setValue(minValue); + } + + valueField.setText(Integer.toString(slider.getValue())); + valueField.setColumns(3); + valueField.addKeyListener(new KeyAdapter() { + + @Override + public void keyReleased(KeyEvent e) { + try { + int newPosition = (int) Double.parseDouble(valueField.getText()); + if (newPosition >= minValue && newPosition <= maxValue) { + slider.setValue(newPosition); + } + } catch (Exception ex) { + } + } + }); + + if (!property.isUnique()) { + setBackground(Constants.MULTI_VALUE_COLOR); + slider.setBackground(Constants.MULTI_VALUE_COLOR); + } + + add(slider); + add(valueField); + add(new JLabel("%")); + } +} diff --git a/diylc/diylc-swing/src/main/java/org/diylc/swing/loadline/LoadlineEditorFrame.java b/diylc/diylc-swing/src/main/java/org/diylc/swing/loadline/LoadlineEditorFrame.java index d3c956fcf..f1c8bab5d 100644 --- a/diylc/diylc-swing/src/main/java/org/diylc/swing/loadline/LoadlineEditorFrame.java +++ b/diylc/diylc-swing/src/main/java/org/diylc/swing/loadline/LoadlineEditorFrame.java @@ -35,6 +35,7 @@ import org.apache.poi.util.IOUtils; import org.diylc.appframework.miscutils.IConfigurationManager; import org.diylc.appframework.miscutils.InMemoryConfigurationManager; import org.diylc.appframework.miscutils.Utils; +import org.diylc.common.*; import org.diylc.components.connectivity.Dot; import org.diylc.components.connectivity.Line; import org.diylc.components.misc.Image; @@ -47,12 +48,6 @@ import org.diylc.swingframework.DoubleTextField; import com.thoughtworks.xstream.XStream; import com.thoughtworks.xstream.io.xml.DomDriver; -import org.diylc.common.EventType; -import org.diylc.common.HorizontalAlignment; -import org.diylc.common.IPlugIn; -import org.diylc.common.IPlugInPort; -import org.diylc.common.PropertyWrapper; -import org.diylc.common.VerticalAlignment; import org.diylc.components.AbstractCurvedComponent.PointCount; import org.diylc.core.IDIYComponent; import org.diylc.core.IView; @@ -687,7 +682,7 @@ public class LoadlineEditorFrame extends JFrame implements IView { image.setControlPoint(new Point((int) spacing, (int) spacing), 0); image.setControlPoint(new Point((int) (canvasDimensions.width - spacing), (int) (canvasDimensions.height - spacing)), 1); - image.setAlpha((byte) 50); // make it transparent + image.setAlpha(new Percentage(50)); // make it transparent fis.close(); // add to the bottom project.getComponents().add(0, image);