Trimmer improvements

This commit is contained in:
Bane Stojkovic
2026-01-16 20:37:21 +01:00
parent a88d8f5e03
commit b69729c14f
3 changed files with 95 additions and 89 deletions
@@ -64,6 +64,7 @@ public abstract class AbstractComponent<T> implements IDIYComponent<T> {
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");
@@ -561,6 +561,10 @@
<releaseDate>2026-01-10 00:00:00.000 CET</releaseDate>
<name></name>
<changes>
<org.diylc.appframework.update.Change>
<changeType>NEW_FEATURE</changeType>
<description>Added Box style multi-turn potentiometer component (thank you chayward)</description>
</org.diylc.appframework.update.Change>
<org.diylc.appframework.update.Change>
<changeType>NEW_FEATURE</changeType>
<description>Added 'M' and 'N' potentiometer taper options (thank you mm-rnd)</description>
@@ -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<Resistance> {
@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<Resistance> {
@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<Resistance> {
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<Resistance> {
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<Resistance> {
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<Resistance> {
this.display = display;
}
@EditableProperty
@EditableProperty(name = "Body")
public Color getBodyColor() {
return bodyColor;
}
@@ -306,7 +307,7 @@ public class BoxTrimmer extends AbstractTransparentComponent<Resistance> {
this.bodyColor = color;
}
@EditableProperty
@EditableProperty(name = "Border")
public Color getBorderColor() {
return borderColor;
}
@@ -343,9 +344,9 @@ public class BoxTrimmer extends AbstractTransparentComponent<Resistance> {
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) {