From b69729c14f5e51278116f3ddc0150f4b0efb6690 Mon Sep 17 00:00:00 2001 From: Bane Stojkovic Date: Fri, 16 Jan 2026 20:37:21 +0100 Subject: [PATCH] Trimmer improvements --- .../diylc/components/AbstractComponent.java | 1 + .../diylc-core/src/main/resources/update.xml | 4 + .../diylc/components/passive/BoxTrimmer.java | 179 +++++++++--------- 3 files changed, 95 insertions(+), 89 deletions(-) diff --git a/diylc/diylc-core/src/main/java/org/diylc/components/AbstractComponent.java b/diylc/diylc-core/src/main/java/org/diylc/components/AbstractComponent.java index a980c67a..202d78cf 100644 --- a/diylc/diylc-core/src/main/java/org/diylc/components/AbstractComponent.java +++ b/diylc/diylc-core/src/main/java/org/diylc/components/AbstractComponent.java @@ -64,6 +64,7 @@ public abstract class AbstractComponent implements IDIYComponent { public static Color LIGHT_METAL_COLOR = Color.decode("#EEEEEE"); public static Color COPPER_COLOR = Color.decode("#DA8A67"); public static Color GOLD_COLOR = Color.decode("#F4B301"); + public static Color BRASS_COLOR = Color.decode("#B8860B"); public static Color FR4_COLOR = Color.decode("#6B9B6B"); public static Color FR4_LIGHT_COLOR = Color.decode("#BABE71"); public static Color PHENOLIC_COLOR = Color.decode("#F8EBB3"); diff --git a/diylc/diylc-core/src/main/resources/update.xml b/diylc/diylc-core/src/main/resources/update.xml index de6559cc..b64c52da 100644 --- a/diylc/diylc-core/src/main/resources/update.xml +++ b/diylc/diylc-core/src/main/resources/update.xml @@ -561,6 +561,10 @@ 2026-01-10 00:00:00.000 CET + + NEW_FEATURE + Added Box style multi-turn potentiometer component (thank you chayward) + NEW_FEATURE Added 'M' and 'N' potentiometer taper options (thank you mm-rnd) 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 d791ea44..2f8a8d28 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 @@ -21,25 +21,13 @@ */ package org.diylc.components.passive; -import java.awt.AlphaComposite; -import java.awt.Color; -import java.awt.Composite; -import java.awt.Graphics2D; -import java.awt.geom.Point2D; -import java.io.Serial; - 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.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.*; import org.diylc.core.annotations.ComponentDescriptor; import org.diylc.core.annotations.EditableProperty; import org.diylc.core.measures.Resistance; @@ -48,30 +36,36 @@ import org.diylc.core.measures.Size; import org.diylc.core.measures.SizeUnit; import org.diylc.utils.Constants; +import java.awt.*; +import java.awt.geom.Point2D; +import java.io.Serial; + @ComponentDescriptor(name = "Box Multi-Turn Pot", author = "Clive", category = "Passive", - instanceNamePrefix = "VR", description = "Box style multi-turn potentiometer (e.g. Bourns PV36)", - zOrder = IDIYComponent.COMPONENT, transformer = org.diylc.components.transform.BoxTrimmerTransformer.class) + instanceNamePrefix = "VR", + description = "Box style multi-turn potentiometer (e.g. Bourns PV36)", + zOrder = IDIYComponent.COMPONENT, + transformer = org.diylc.components.transform.BoxTrimmerTransformer.class) public class BoxTrimmer extends AbstractTransparentComponent { @Serial private static final long serialVersionUID = 1L; - + public static Size PIN_SPACING = new Size(0.1d, SizeUnit.in); public static Size BODY_WIDTH = new Size(0.19d, SizeUnit.in); // 2x 2.41mm = 4.82mm ≈ 0.19" public static Size BODY_LENGTH = new Size(0.375d, SizeUnit.in); // 9.53mm from datasheet public static Color BODY_COLOR = Color.decode("#4477BB"); public static Color BORDER_COLOR = BODY_COLOR.darker(); - public static Color PIN_COLOR = Color.decode("#CCCCCC"); - + public static Color PIN_COLOR = METAL_COLOR; + public static Color SCREW_COLOR = BRASS_COLOR; + protected String name; private Resistance value = new Resistance(10d, ResistanceUnit.K); private Orientation orientation = Orientation._90; // Default to vertical (90 degrees) private Display display = Display.NAME; private Color bodyColor = BODY_COLOR; private Color borderColor = BORDER_COLOR; - protected String name; private boolean screwFlippedHorizontally = false; // Track if screw flipped left-right private boolean screwFlippedVertically = false; // Track if screw flipped top-bottom - + private Point2D[] controlPoints = new Point2D[3]; public BoxTrimmer() { @@ -82,20 +76,20 @@ public class BoxTrimmer extends AbstractTransparentComponent { @Override public void draw(Graphics2D g2d, ComponentState componentState, boolean outlineMode, Project project, IDrawingObserver drawingObserver) { - - Theme theme = (Theme) ConfigurationManager.getInstance().readObject( - IPlugInPort.THEME_KEY, Constants.DEFAULT_THEME); - + + Theme theme = (Theme) ConfigurationManager.getInstance() + .readObject(IPlugInPort.THEME_KEY, Constants.DEFAULT_THEME); + int pinSpacing = (int) PIN_SPACING.convertToPixels(); int bodyWidth = (int) BODY_WIDTH.convertToPixels(); int bodyLength = (int) BODY_LENGTH.convertToPixels(); - + // Calculate positions - body is centered on the middle pin int centerX = (int) controlPoints[1].getX(); int centerY = (int) controlPoints[1].getY(); - + int bodyX, bodyY, bodyW, bodyH; - + // Position body based on orientation - fits tightly around pins if (orientation == Orientation.DEFAULT || orientation == Orientation._180) { // Horizontal - body is wide, pins are below/above @@ -110,92 +104,99 @@ public class BoxTrimmer extends AbstractTransparentComponent { bodyX = centerX - bodyWidth / 2; bodyY = centerY - bodyLength / 2; } - + // Draw body Composite oldComposite = g2d.getComposite(); if (alpha < MAX_ALPHA) { - g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, - 1f * alpha / MAX_ALPHA)); + g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1f * alpha / MAX_ALPHA)); } g2d.setColor(outlineMode ? Constants.TRANSPARENT_COLOR : bodyColor); g2d.fillRoundRect(bodyX, bodyY, bodyW, bodyH, bodyW / 10, bodyH / 10); g2d.setComposite(oldComposite); - + // Draw border - Color finalBorderColor = componentState == ComponentState.SELECTED || - componentState == ComponentState.DRAGGING ? SELECTION_COLOR : - (outlineMode ? theme.getOutlineColor() : borderColor); + Color finalBorderColor = + componentState == ComponentState.SELECTED || componentState == ComponentState.DRAGGING ? + SELECTION_COLOR : + (outlineMode ? theme.getOutlineColor() : borderColor); g2d.setColor(finalBorderColor); g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(1)); g2d.drawRoundRect(bodyX, bodyY, bodyW, bodyH, bodyW / 10, bodyH / 10); - + // Draw adjustment screw (slotted screw head) - position based on orientation if (!outlineMode) { // Brass/gold color for screw head - Color brassColor = new Color(184, 134, 11); // Dark goldenrod - + // Color brassColor = new Color(184, 134, 11); // Dark goldenrod + int screwDiameter = Math.min(bodyW, bodyH) / 3; int screwX, screwY; - + // Position screw based on orientation and flip state // The screw should be in the corner near pin 0, but can flip horizontally or vertically - screwY = switch (orientation) { - case DEFAULT -> { - screwX = screwFlippedHorizontally ? bodyX + bodyW - screwDiameter : bodyX; - yield screwFlippedVertically ? bodyY : bodyY + bodyH - screwDiameter; - } - case _90 -> { - screwX = screwFlippedHorizontally ? bodyX + bodyW - screwDiameter : bodyX; - yield screwFlippedVertically ? bodyY : bodyY + bodyH - screwDiameter; - } - case _180 -> { - screwX = screwFlippedHorizontally ? bodyX : bodyX + bodyW - screwDiameter; - yield screwFlippedVertically ? bodyY : bodyY + bodyH - screwDiameter; - } - case _270 -> { - screwX = screwFlippedHorizontally ? bodyX + bodyW - screwDiameter : bodyX; - yield screwFlippedVertically ? bodyY + bodyH - screwDiameter : bodyY; - } - default -> { - screwX = bodyX; - yield bodyY + bodyH - screwDiameter; - } - }; - + screwY = switch (orientation) { + case DEFAULT -> { + screwX = screwFlippedHorizontally ? bodyX + bodyW - screwDiameter : bodyX; + yield screwFlippedVertically ? bodyY : bodyY + bodyH - screwDiameter; + } + case _90 -> { + screwX = screwFlippedHorizontally ? bodyX + bodyW - screwDiameter : bodyX; + yield screwFlippedVertically ? bodyY : bodyY + bodyH - screwDiameter; + } + case _180 -> { + screwX = screwFlippedHorizontally ? bodyX : bodyX + bodyW - screwDiameter; + yield screwFlippedVertically ? bodyY : bodyY + bodyH - screwDiameter; + } + case _270 -> { + screwX = screwFlippedHorizontally ? bodyX + bodyW - screwDiameter : bodyX; + yield screwFlippedVertically ? bodyY + bodyH - screwDiameter : bodyY; + } + default -> { + screwX = bodyX; + yield bodyY + bodyH - screwDiameter; + } + }; + // Draw screw head circle - g2d.setColor(brassColor); + g2d.setColor(SCREW_COLOR); g2d.fillOval(screwX, screwY, screwDiameter, screwDiameter); - + // Draw slot in screw - centered horizontally through the circle - g2d.setColor(new Color(80, 80, 80)); // Dark gray for slot - int slotLength = (int)(screwDiameter * 0.7); + g2d.setColor(SCREW_COLOR.darker()); + g2d.drawOval(screwX, screwY, screwDiameter, screwDiameter); + + int slotLength = (int) (screwDiameter * 0.7); int slotThickness = Math.max(1, screwDiameter / 10); int slotCenterX = screwX + screwDiameter / 2; int slotCenterY = screwY + screwDiameter / 2; - g2d.fillRect(slotCenterX - slotLength / 2, slotCenterY - slotThickness / 2, slotLength, slotThickness); + g2d.fillRect(slotCenterX - slotLength / 2, slotCenterY - slotThickness / 2, slotLength, + slotThickness); } - + // Draw pins g2d.setColor(outlineMode ? theme.getOutlineColor() : PIN_COLOR); for (Point2D p : controlPoints) { - g2d.fillOval((int)p.getX() - 2, (int)p.getY() - 2, 4, 4); + g2d.fillOval((int) p.getX() - 2, (int) p.getY() - 2, 4, 4); } - + // Draw label - position outside body for readability - Color labelColor = componentState == ComponentState.SELECTED || - componentState == ComponentState.DRAGGING ? LABEL_COLOR_SELECTED : LABEL_COLOR; + Color labelColor = + componentState == ComponentState.SELECTED || componentState == ComponentState.DRAGGING ? + LABEL_COLOR_SELECTED : + LABEL_COLOR; g2d.setColor(labelColor); g2d.setFont(project.getFont()); - - String label = display == Display.NAME ? getName() : - display == Display.VALUE ? getValue().toString() : - display == Display.BOTH ? getName() + " " + getValue() : ""; - + + String label = display == Display.NAME ? + getName() : + display == Display.VALUE ? + getValue().toString() : + display == Display.BOTH ? getName() + " " + getValue() : ""; + if (!label.isEmpty()) { // Position label outside the component body based on orientation int labelX, labelY; java.awt.FontMetrics fm = g2d.getFontMetrics(); - + if (orientation == Orientation.DEFAULT || orientation == Orientation._180) { // Horizontal orientation - label below body labelX = bodyX + bodyW / 2; @@ -205,7 +206,7 @@ public class BoxTrimmer extends AbstractTransparentComponent { labelX = bodyX + bodyW + fm.stringWidth(label) / 2 + 5; // 5 pixel gap labelY = bodyY + bodyH / 2; } - + drawCenteredText(g2d, label, labelX, labelY); } } @@ -224,25 +225,25 @@ public class BoxTrimmer extends AbstractTransparentComponent { int bodyHeight = height - 10; int bodyX = 4; int bodyY = 2; - + // Draw blue body (side profile - rectangular) g2d.setColor(BODY_COLOR); g2d.fillRect(bodyX, bodyY, bodyWidth, bodyHeight); g2d.setColor(BORDER_COLOR); g2d.drawRect(bodyX, bodyY, bodyWidth, bodyHeight); - + // Draw brass adjustment screw on top left Color brassColor = new Color(184, 134, 11); int screwSize = Math.min(bodyWidth, bodyHeight) / 3; g2d.setColor(brassColor); g2d.fillOval(bodyX + 2, bodyY - screwSize / 2, screwSize, screwSize); - + // Draw slot in screw g2d.setColor(new Color(80, 80, 80)); - int slotLen = (int)(screwSize * 0.6); - g2d.drawLine(bodyX + 2 + screwSize / 2 - slotLen / 2, bodyY, - bodyX + 2 + screwSize / 2 + slotLen / 2, bodyY); - + int slotLen = (int) (screwSize * 0.6); + g2d.drawLine(bodyX + 2 + screwSize / 2 - slotLen / 2, bodyY, + bodyX + 2 + screwSize / 2 + slotLen / 2, bodyY); + // Draw three pins at bottom (light gray) g2d.setColor(PIN_COLOR); int pinSpacing = bodyWidth / 4; @@ -297,7 +298,7 @@ public class BoxTrimmer extends AbstractTransparentComponent { this.display = display; } - @EditableProperty + @EditableProperty(name = "Body") public Color getBodyColor() { return bodyColor; } @@ -306,7 +307,7 @@ public class BoxTrimmer extends AbstractTransparentComponent { this.bodyColor = color; } - @EditableProperty + @EditableProperty(name = "Border") public Color getBorderColor() { return borderColor; } @@ -343,9 +344,9 @@ public class BoxTrimmer extends AbstractTransparentComponent { int pinSpacing = (int) PIN_SPACING.convertToPixels(); double x = controlPoints[0] != null ? controlPoints[0].getX() : 0; double y = controlPoints[0] != null ? controlPoints[0].getY() : 0; - + controlPoints[0] = new Point2D.Double(x, y); - + // Pin arrangement depends on orientation // Pin 0 is always CCW, Pin 1 is Wiper, Pin 2 is CW switch (orientation) {