consolidate pin color and pin rendering

This commit is contained in:
Bane Stojkovic
2026-11-03 12:08:33 +01:00
parent 1a4b40d36c
commit 732281f3d7
27 changed files with 448 additions and 464 deletions
@@ -1,357 +1,359 @@
/*
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 <http://www.gnu.org/licenses/>.
*/
package org.diylc.components;
import java.awt.Color;
import java.awt.Font;
import java.awt.Shape;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.Arrays;
import java.util.UUID;
import java.util.stream.Collectors;
import org.diylc.core.IDIYComponent;
import org.diylc.core.Project;
import org.diylc.core.annotations.EditableProperty;
import org.diylc.core.measures.Size;
/**
* Abstract implementation of {@link IDIYComponent} that contains component name and toString.
*
* IMPORTANT: to improve performance, all fields except for <code>Point</code> and
* <code>Point</code> arrays should be immutable. Failing to comply with this can result in annoying
* and hard to trace bugs.
*
* @author Branislav Stojkovic
*
* @param <T>
*/
public abstract class AbstractComponent<T> implements IDIYComponent<T> {
private static final long serialVersionUID = 1L;
protected UUID id = UUID.randomUUID();
protected String name = "";
public static Color SELECTION_COLOR = Color.red;
public static Color LABEL_COLOR = Color.black;
public static Color LABEL_COLOR_SELECTED = Color.red;
public static Font LABEL_FONT = new Font("Square721 BT", Font.PLAIN, 14);
public static Color METAL_COLOR = Color.decode("#759DAF");
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");
public static Color PHENOLIC_DARK_COLOR = Color.decode("#CD8500");
@EditableProperty(defaultable = false)
@Override
public String getName() {
return name;
}
@Override
public void setName(String name) {
this.name = name;
}
@Override
public UUID getId() {
if (id == null) {
id = UUID.randomUUID();
}
return id;
}
@Override
public void setId(UUID id) {
this.id = id;
}
@Override
public boolean canControlPointOverlap(int index) {
return false;
}
@Override
public String toString() {
return name == null ? "(null)" : name;
}
@Override
public String getValueForDisplay() {
if (getValue() == null)
return "";
Object val = getValue();
if (val.getClass().isArray()) {
return String.join(" / ", Arrays.stream((Object[])val).map(x -> x == null ? "" : x.toString()).collect(Collectors.toList()));
}
return val.toString();
}
/**
* Returns the closest odd number, i.e. x when x is odd, or x + 1 when x is even.
*
* @param x
* @return
*/
protected int getClosestOdd(double x) {
return ((int) x / 2) * 2 + 1;
}
/**
* Returns the closest odd number, i.e. x when x is odd, or x + 1 when x is even.
*
* @param x
* @return
*/
protected int getClosestOdd(Size s) {
double x = s.convertToPixels();
return ((int) x / 2) * 2 + 1;
}
/**
* Returns darker color if possible, or lighter if it's already dark
*
* @param color
* @return
*/
protected Color darkerOrLighter(Color color) {
float[] hsb = new float[3];
Color.RGBtoHSB(color.getRed(), color.getGreen(), color.getBlue(), hsb);
return new Color(Color.HSBtoRGB(hsb[0], hsb[1], hsb[2] > 0.5 ? hsb[2] - 0.25f : hsb[2] + 0.25f));
}
/**
* @param clip
* @return true if none of the control points lie in the clip rectangle.
*/
protected boolean checkPointsClipped(Shape clip) {
if (clip == null) {
return false;
}
for (int i = 0; i < getControlPointCount(); i++) {
if (clip.contains(getControlPoint(i))) {
return false;
}
}
double minX = Integer.MAX_VALUE;
double minY = Integer.MAX_VALUE;
double maxX = Integer.MIN_VALUE;
double maxY = Integer.MIN_VALUE;
for (int i = 0; i < getControlPointCount(); i++) {
Point2D p = getControlPoint(i);
if (minX > p.getX()) {
minX = p.getX();
}
if (maxX < p.getX()) {
maxX = p.getX();
}
if (minY > p.getY()) {
minY = p.getY();
}
if (maxY < p.getY()) {
maxY = p.getY();
}
}
double margin = getClipMargin();
Rectangle2D rect = new Rectangle2D.Double(minX - margin, minY - margin,
maxX - minX + 2 * margin, maxY - minY + 2 * margin);
return !clip.intersects(rect);
}
/**
* Distance in pixels that the drawing may reach beyond the bounding box of the control points,
* such as half the width of a stroke running through them. {@link #checkPointsClipped(Shape)}
* widens the box by this much before testing it against the clip. The margin must stay positive,
* because {@link Shape#intersects(Rectangle2D)} reports a box with no width or height as disjoint
* from everything, which would hide a straight horizontal or vertical component whose control
* points all lie outside the clip.
*
* @return margin around the control points.
*/
protected double getClipMargin() {
return 1;
}
@SuppressWarnings("unchecked")
public IDIYComponent<T> clone() throws CloneNotSupportedException {
try {
// Instantiate object of the same type
Class<?> clazz = this.getClass();
AbstractComponent<T> newInstance = (AbstractComponent<T>) clazz.getDeclaredConstructor().newInstance();
while (AbstractComponent.class.isAssignableFrom(clazz)) {
Field[] fields = clazz.getDeclaredFields();
clazz = clazz.getSuperclass();
// fields = this.getClass().getDeclaredFields();
// Copy over all non-static, non-final fields that are declared
// in AbstractComponent or one of it's child classes
for (Field field : fields) {
if (!Modifier.isStatic(field.getModifiers()) && !Modifier.isFinal(field.getModifiers())) {
field.setAccessible(true);
Object value = field.get(this);
if (field.getName().equalsIgnoreCase("id")) {
value = getId();
}
// Deep copy point arrays.
// TODO: something nicer
if (value != null && value.getClass().isArray()
&& Point2D.class.isAssignableFrom(value.getClass().getComponentType())) {
Object newArray = Array.newInstance(value.getClass().getComponentType(), Array.getLength(value));
for (int i = 0; i < Array.getLength(value); i++) {
Point2D p = (Point2D) Array.get(value, i);
if (p != null)
Array.set(newArray, i, new Point2D.Double(p.getX(), p.getY()));
}
value = newArray;
}
// Deep copy points.
// TODO: something nicer
if (value != null && value instanceof Point2D) {
Point2D p = (Point2D) value;
value = new Point2D.Double(p.getX(), p.getY());
}
field.set(newInstance, value);
}
}
}
return newInstance;
} catch (Exception e) {
throw new CloneNotSupportedException("Could not clone the component. Reason: " + e.getMessage());
}
}
@Override
public boolean equalsTo(IDIYComponent<?> other) {
if (other == null)
return false;
if (!other.getClass().equals(this.getClass()))
return false;
Class<?> clazz = this.getClass();
while (AbstractComponent.class.isAssignableFrom(clazz)) {
Field[] fields = clazz.getDeclaredFields();
clazz = clazz.getSuperclass();
// fields = this.getClass().getDeclaredFields();
// Copy over all non-static, non-final and non-transient fields that are declared
// in
// AbstractComponent or one of it's child classes
for (Field field : fields) {
if (!Modifier.isStatic(field.getModifiers()) && !Modifier.isFinal(field.getModifiers()) &&
!Modifier.isTransient(field.getModifiers())) {
field.setAccessible(true);
try {
Object value = field.get(this);
Object otherValue = field.get(other);
if (!compareObjects(value, otherValue))
return false;
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
}
return true;
}
private boolean compareObjects(Object o1, Object o2) {
if (o1 == null && o2 == null)
return true;
if (o1 == null || o2 == null)
return false;
if (o1.getClass().isArray()) {
if (o1.getClass().getComponentType() == byte.class)
return Arrays.equals((byte[]) o1, (byte[]) o2);
if (o1.getClass().getComponentType() == double.class)
return Arrays.equals((double[]) o1, (double[]) o2);
if (o1.getClass().getComponentType() == int.class)
return Arrays.equals((int[]) o1, (int[]) o2);
return Arrays.equals((Object[]) o1, (Object[]) o2);
}
return o1.equals(o2);
}
@Override
public String getControlPointNodeName(int index) {
return Integer.toString(index + 1);
}
@Override
public String getInternalLinkName(int index1, int index2) {
return null;
}
@Override
public boolean canPointMoveFreely(int pointIndex) {
return true;
}
@Override
public void stretchBetween(Point2D first, Point2D second) {
int count = getControlPointCount();
// fresh instances because implementations are free to keep the point objects they are handed
setControlPoint(new Point2D.Double(first.getX(), first.getY()), 0);
if (count > 1) {
setControlPoint(new Point2D.Double(second.getX(), second.getY()), count - 1);
}
for (int i = 1; i < count - 1; i++) {
setControlPoint(getStretchedPoint(first, second, i), i);
}
}
/**
* Decides where a control point that is neither of the two ends lands when the component is
* stretched between them, see {@link #stretchBetween(Point2D, Point2D)}. The default spaces the
* points evenly along the straight line joining the ends. Override to place a point that carries
* a meaning of its own, such as one that positions a label.
*
* @param first
* @param second
* @param index
* @return position of the control point at the specified index.
*/
protected Point2D getStretchedPoint(Point2D first, Point2D second, int index) {
double t = (double) index / (getControlPointCount() - 1);
return new Point2D.Double(first.getX() + t * (second.getX() - first.getX()),
first.getY() + t * (second.getY() - first.getY()));
}
@Override
public Rectangle2D getCachingBounds() {
return null;
}
@Override
public void createdIn(Project project) {
// TODO Auto-generated method stub
}
}
/*
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 <http://www.gnu.org/licenses/>.
*/
package org.diylc.components;
import java.awt.Color;
import java.awt.Font;
import java.awt.Shape;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.Arrays;
import java.util.UUID;
import java.util.stream.Collectors;
import org.diylc.core.IDIYComponent;
import org.diylc.core.Project;
import org.diylc.core.annotations.EditableProperty;
import org.diylc.core.measures.Size;
/**
* Abstract implementation of {@link IDIYComponent} that contains component name and toString.
*
* IMPORTANT: to improve performance, all fields except for <code>Point</code> and
* <code>Point</code> arrays should be immutable. Failing to comply with this can result in annoying
* and hard to trace bugs.
*
* @author Branislav Stojkovic
*
* @param <T>
*/
public abstract class AbstractComponent<T> implements IDIYComponent<T> {
private static final long serialVersionUID = 1L;
protected UUID id = UUID.randomUUID();
protected String name = "";
public static Color SELECTION_COLOR = Color.red;
public static Color LABEL_COLOR = Color.black;
public static Color LABEL_COLOR_SELECTED = Color.red;
public static Font LABEL_FONT = new Font("Square721 BT", Font.PLAIN, 14);
public static Color METAL_COLOR = Color.decode("#759DAF");
public static Color LIGHT_METAL_COLOR = Color.decode("#EEEEEE");
public static Color PIN_COLOR = Color.decode("#00B2EE");
public static Color PIN_BORDER_COLOR = PIN_COLOR.darker();
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");
public static Color PHENOLIC_DARK_COLOR = Color.decode("#CD8500");
@EditableProperty(defaultable = false)
@Override
public String getName() {
return name;
}
@Override
public void setName(String name) {
this.name = name;
}
@Override
public UUID getId() {
if (id == null) {
id = UUID.randomUUID();
}
return id;
}
@Override
public void setId(UUID id) {
this.id = id;
}
@Override
public boolean canControlPointOverlap(int index) {
return false;
}
@Override
public String toString() {
return name == null ? "(null)" : name;
}
@Override
public String getValueForDisplay() {
if (getValue() == null)
return "";
Object val = getValue();
if (val.getClass().isArray()) {
return String.join(" / ", Arrays.stream((Object[])val).map(x -> x == null ? "" : x.toString()).collect(Collectors.toList()));
}
return val.toString();
}
/**
* Returns the closest odd number, i.e. x when x is odd, or x + 1 when x is even.
*
* @param x
* @return
*/
protected int getClosestOdd(double x) {
return ((int) x / 2) * 2 + 1;
}
/**
* Returns the closest odd number, i.e. x when x is odd, or x + 1 when x is even.
*
* @param x
* @return
*/
protected int getClosestOdd(Size s) {
double x = s.convertToPixels();
return ((int) x / 2) * 2 + 1;
}
/**
* Returns darker color if possible, or lighter if it's already dark
*
* @param color
* @return
*/
protected Color darkerOrLighter(Color color) {
float[] hsb = new float[3];
Color.RGBtoHSB(color.getRed(), color.getGreen(), color.getBlue(), hsb);
return new Color(Color.HSBtoRGB(hsb[0], hsb[1], hsb[2] > 0.5 ? hsb[2] - 0.25f : hsb[2] + 0.25f));
}
/**
* @param clip
* @return true if none of the control points lie in the clip rectangle.
*/
protected boolean checkPointsClipped(Shape clip) {
if (clip == null) {
return false;
}
for (int i = 0; i < getControlPointCount(); i++) {
if (clip.contains(getControlPoint(i))) {
return false;
}
}
double minX = Integer.MAX_VALUE;
double minY = Integer.MAX_VALUE;
double maxX = Integer.MIN_VALUE;
double maxY = Integer.MIN_VALUE;
for (int i = 0; i < getControlPointCount(); i++) {
Point2D p = getControlPoint(i);
if (minX > p.getX()) {
minX = p.getX();
}
if (maxX < p.getX()) {
maxX = p.getX();
}
if (minY > p.getY()) {
minY = p.getY();
}
if (maxY < p.getY()) {
maxY = p.getY();
}
}
double margin = getClipMargin();
Rectangle2D rect = new Rectangle2D.Double(minX - margin, minY - margin,
maxX - minX + 2 * margin, maxY - minY + 2 * margin);
return !clip.intersects(rect);
}
/**
* Distance in pixels that the drawing may reach beyond the bounding box of the control points,
* such as half the width of a stroke running through them. {@link #checkPointsClipped(Shape)}
* widens the box by this much before testing it against the clip. The margin must stay positive,
* because {@link Shape#intersects(Rectangle2D)} reports a box with no width or height as disjoint
* from everything, which would hide a straight horizontal or vertical component whose control
* points all lie outside the clip.
*
* @return margin around the control points.
*/
protected double getClipMargin() {
return 1;
}
@SuppressWarnings("unchecked")
public IDIYComponent<T> clone() throws CloneNotSupportedException {
try {
// Instantiate object of the same type
Class<?> clazz = this.getClass();
AbstractComponent<T> newInstance = (AbstractComponent<T>) clazz.getDeclaredConstructor().newInstance();
while (AbstractComponent.class.isAssignableFrom(clazz)) {
Field[] fields = clazz.getDeclaredFields();
clazz = clazz.getSuperclass();
// fields = this.getClass().getDeclaredFields();
// Copy over all non-static, non-final fields that are declared
// in AbstractComponent or one of it's child classes
for (Field field : fields) {
if (!Modifier.isStatic(field.getModifiers()) && !Modifier.isFinal(field.getModifiers())) {
field.setAccessible(true);
Object value = field.get(this);
if (field.getName().equalsIgnoreCase("id")) {
value = getId();
}
// Deep copy point arrays.
// TODO: something nicer
if (value != null && value.getClass().isArray()
&& Point2D.class.isAssignableFrom(value.getClass().getComponentType())) {
Object newArray = Array.newInstance(value.getClass().getComponentType(), Array.getLength(value));
for (int i = 0; i < Array.getLength(value); i++) {
Point2D p = (Point2D) Array.get(value, i);
if (p != null)
Array.set(newArray, i, new Point2D.Double(p.getX(), p.getY()));
}
value = newArray;
}
// Deep copy points.
// TODO: something nicer
if (value != null && value instanceof Point2D) {
Point2D p = (Point2D) value;
value = new Point2D.Double(p.getX(), p.getY());
}
field.set(newInstance, value);
}
}
}
return newInstance;
} catch (Exception e) {
throw new CloneNotSupportedException("Could not clone the component. Reason: " + e.getMessage());
}
}
@Override
public boolean equalsTo(IDIYComponent<?> other) {
if (other == null)
return false;
if (!other.getClass().equals(this.getClass()))
return false;
Class<?> clazz = this.getClass();
while (AbstractComponent.class.isAssignableFrom(clazz)) {
Field[] fields = clazz.getDeclaredFields();
clazz = clazz.getSuperclass();
// fields = this.getClass().getDeclaredFields();
// Copy over all non-static, non-final and non-transient fields that are declared
// in
// AbstractComponent or one of it's child classes
for (Field field : fields) {
if (!Modifier.isStatic(field.getModifiers()) && !Modifier.isFinal(field.getModifiers()) &&
!Modifier.isTransient(field.getModifiers())) {
field.setAccessible(true);
try {
Object value = field.get(this);
Object otherValue = field.get(other);
if (!compareObjects(value, otherValue))
return false;
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
}
return true;
}
private boolean compareObjects(Object o1, Object o2) {
if (o1 == null && o2 == null)
return true;
if (o1 == null || o2 == null)
return false;
if (o1.getClass().isArray()) {
if (o1.getClass().getComponentType() == byte.class)
return Arrays.equals((byte[]) o1, (byte[]) o2);
if (o1.getClass().getComponentType() == double.class)
return Arrays.equals((double[]) o1, (double[]) o2);
if (o1.getClass().getComponentType() == int.class)
return Arrays.equals((int[]) o1, (int[]) o2);
return Arrays.equals((Object[]) o1, (Object[]) o2);
}
return o1.equals(o2);
}
@Override
public String getControlPointNodeName(int index) {
return Integer.toString(index + 1);
}
@Override
public String getInternalLinkName(int index1, int index2) {
return null;
}
@Override
public boolean canPointMoveFreely(int pointIndex) {
return true;
}
@Override
public void stretchBetween(Point2D first, Point2D second) {
int count = getControlPointCount();
// fresh instances because implementations are free to keep the point objects they are handed
setControlPoint(new Point2D.Double(first.getX(), first.getY()), 0);
if (count > 1) {
setControlPoint(new Point2D.Double(second.getX(), second.getY()), count - 1);
}
for (int i = 1; i < count - 1; i++) {
setControlPoint(getStretchedPoint(first, second, i), i);
}
}
/**
* Decides where a control point that is neither of the two ends lands when the component is
* stretched between them, see {@link #stretchBetween(Point2D, Point2D)}. The default spaces the
* points evenly along the straight line joining the ends. Override to place a point that carries
* a meaning of its own, such as one that positions a label.
*
* @param first
* @param second
* @param index
* @return position of the control point at the specified index.
*/
protected Point2D getStretchedPoint(Point2D first, Point2D second, int index) {
double t = (double) index / (getControlPointCount() - 1);
return new Point2D.Double(first.getX() + t * (second.getX() - first.getX()),
first.getY() + t * (second.getY() - first.getY()));
}
@Override
public Rectangle2D getCachingBounds() {
return null;
}
@Override
public void createdIn(Project project) {
// TODO Auto-generated method stub
}
}
@@ -563,7 +563,7 @@
</org.diylc.appframework.update.Change>
<org.diylc.appframework.update.Change>
<changeType>IMPROVEMENT</changeType>
<description>Transistor pins are now drawn on top of the body in the same color on every package, so they stay visible whatever the body transparency</description>
<description>Pins of transistors, 'SIP IC', 'DIP Switch' and 'Bridge Rectifier' are now drawn on top of the body, so they stay visible whatever the body transparency, and pins are drawn in the same color on every component, including 'DIP IC', 'Bridge Rectifier', 'LED Bar Graph', trimmers and PCB-mounted 'Tube Socket'</description>
</org.diylc.appframework.update.Change>
<org.diylc.appframework.update.Change>
<changeType>IMPROVEMENT</changeType>
@@ -64,8 +64,6 @@ public abstract class AbstractMakerBoard extends AbstractTransparentComponent<Vo
public static final Color ESP_BLACK = Color.decode("#3E3E3E");
public static final Color WEMOS_BLUE = Color.decode("#006699");
public static Color PIN_COLOR = Color.decode("#00B2EE");
public static Color PIN_BORDER_COLOR = PIN_COLOR.darker();
public static Color HEADER_BODY_COLOR = Color.decode("#222222");
public static Color HEADER_BORDER_COLOR = Color.decode("#111111");
public static Color MOUNTING_HOLE_COLOR = Color.decode("#B8860B");
@@ -74,8 +74,6 @@ public class LEDBarGraph extends AbstractLabeledComponent<String> {
public static Color BODY_COLOR = Color.decode("#2B2B2B");
public static Color BORDER_COLOR = Color.decode("#1A1A1A");
public static Color PIN_COLOR = METAL_COLOR;
public static Color PIN_BORDER_COLOR = PIN_COLOR.darker();
// A bar graph is a scale, not a lamp: green most of the way up, yellow for the last two and
// red for the topmost, as on a level or VU meter.
public static Color SEGMENT_GREEN = Color.decode("#43A047");
@@ -59,8 +59,6 @@ public class DIPSwitch extends AbstractTransparentComponent<String> implements I
public static Color BODY_COLOR = Color.decode("#E84E46");
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 TICK_COLOR = Color.white;
public static Color LABEL_COLOR = Color.white;
public static int EDGE_RADIUS = 2;
@@ -330,23 +328,6 @@ public class DIPSwitch extends AbstractTransparentComponent<String> implements I
}
g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(1));
Area mainArea = getBody()[0];
if (!outlineMode) {
int pinSize = (int) PIN_SIZE.convertToPixels() / 2 * 2;
for (Point2D point : controlPoints) {
g2d.setColor(PIN_COLOR);
int pinWidth = getClosestOdd(pinSize
/ (getOrientation() == Orientation.DEFAULT || getOrientation() == Orientation._180 ? 2f
: 1f));
int pinHeight = getClosestOdd(pinSize
/ (getOrientation() == Orientation.DEFAULT || getOrientation() == Orientation._180 ? 1f
: 2f));
g2d.fillRect((int) Math.round(point.getX() - pinWidth / 2), (int) Math.round(point.getY() - pinHeight / 2),
pinWidth, pinHeight);
g2d.setColor(PIN_BORDER_COLOR);
g2d.drawRect((int) Math.round(point.getX() - pinWidth / 2), (int) Math.round(point.getY() - pinHeight / 2),
pinWidth, pinHeight);
}
}
Composite oldComposite = applyAlpha(g2d, componentState);
g2d.setColor(outlineMode ? Constants.TRANSPARENT_COLOR : getBodyColor());
g2d.fill(mainArea);
@@ -390,6 +371,30 @@ public class DIPSwitch extends AbstractTransparentComponent<String> implements I
}
}
// the pins sit under the body, so they are drawn over it to stay visible whatever its alpha
int pinSize = (int) PIN_SIZE.convertToPixels() / 2 * 2;
int pinWidth = getClosestOdd(pinSize
/ (getOrientation() == Orientation.DEFAULT || getOrientation() == Orientation._180 ? 2f
: 1f));
int pinHeight = getClosestOdd(pinSize
/ (getOrientation() == Orientation.DEFAULT || getOrientation() == Orientation._180 ? 1f
: 2f));
Color pinBorderColor = outlineMode ? ((Theme) ConfigurationManager.getInstance()
.readObject(IPlugInPort.THEME_KEY, Constants.DEFAULT_THEME)).getOutlineColor()
: PIN_BORDER_COLOR;
for (Point2D point : controlPoints) {
int pinX = (int) Math.round(point.getX() - pinWidth / 2);
int pinY = (int) Math.round(point.getY() - pinHeight / 2);
if (!outlineMode) {
g2d.setColor(PIN_COLOR);
drawingObserver.startTracking();
g2d.fillRect(pinX, pinY, pinWidth, pinHeight);
drawingObserver.stopTracking();
}
g2d.setColor(pinBorderColor);
g2d.drawRect(pinX, pinY, pinWidth, pinHeight);
}
// Draw label.
g2d.setFont(project.getFont());
Color finalLabelColor;
@@ -64,8 +64,6 @@ public class MiniRelay extends AbstractLabeledComponent<String> implements IGerb
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;
@@ -60,8 +60,6 @@ public class PinHeader extends AbstractTransparentComponent<Void> {
private static final long serialVersionUID = 1L;
public static Color BODY_COLOR = Color.gray;
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 Size PIN_SIZE = new Size(0.03d, SizeUnit.in);
public static Size INDENT_SIZE = new Size(0.1d, SizeUnit.in);
@@ -57,8 +57,6 @@ public class TactileMicroSwitch extends AbstractLabeledComponent<String> impleme
private static final Color BODY_COLOR = Color.lightGray;
private static final Color BORDER_COLOR = Color.gray.darker();
private static final Color PIN_COLOR = METAL_COLOR;
private static final Color PIN_BORDER_COLOR = PIN_COLOR.darker();
private static final Color INDENT_COLOR = Color.gray.darker();
private static final Color LABEL_COLOR = Color.white;
private static final Size PIN_SIZE = new Size(0.04d, SizeUnit.in);
@@ -56,8 +56,6 @@ public class ThonkJack3_5 extends AbstractTransparentComponent<String> {
private static Color SHAFT_COLOR = Color.lightGray;
private static Color SHAFT_BORDER_COLOR = SHAFT_COLOR.darker();
private static Color HOLE_COLOR = Color.decode("#111111");
public static Color PIN_COLOR = METAL_COLOR;
public static Color PIN_BORDER_COLOR = PIN_COLOR.darker();
public static Size PIN_SIZE = new Size(0.03d, SizeUnit.in);
protected static Display DISPLAY = Display.NAME;
@@ -70,8 +70,6 @@ public class AudioTransformer extends AbstractMultiPartComponent<String> impleme
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);
@@ -59,7 +59,6 @@ public class BoxTrimmer extends AbstractTransparentComponent<Resistance> {
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 = METAL_COLOR;
public static Color SCREW_COLOR = BRASS_COLOR;
protected String name;
private Resistance value = new Resistance(10d, ResistanceUnit.K);
@@ -245,7 +244,7 @@ public class BoxTrimmer extends AbstractTransparentComponent<Resistance> {
g2d.drawLine(bodyX + 2 + screwSize / 2 - slotLen / 2, bodyY,
bodyX + 2 + screwSize / 2 + slotLen / 2, bodyY);
// Draw three pins at bottom (light gray)
// Draw three pins at bottom
g2d.setColor(PIN_COLOR);
int pinSpacing = bodyWidth / 4;
for (int i = 0; i < 3; i++) {
@@ -59,8 +59,6 @@ public class MiniaturePotentiometer extends AbstractPotentiometer {
private static Color BORDER_COLOR = BODY_COLOR.darker();
private static Color SHAFT_COLOR = Color.lightGray;
private static Color SHAFT_BORDER_COLOR = SHAFT_COLOR.darker();
public static Color PIN_COLOR = METAL_COLOR;
public static Color PIN_BORDER_COLOR = PIN_COLOR.darker();
public static Size PIN_SIZE = new Size(0.03d, SizeUnit.in);
protected static Display DISPLAY = Display.NAME;
@@ -319,9 +317,9 @@ public class MiniaturePotentiometer extends AbstractPotentiometer {
if (!outlineMode) {
if (bracket != null) {
g2d.setColor(PIN_COLOR);
g2d.setColor(METAL_COLOR);
g2d.fill(bracket);
g2d.setColor(PIN_BORDER_COLOR);
g2d.setColor(METAL_COLOR.darker());
g2d.draw(bracket);
}
if (rivet1 != null) {
@@ -70,8 +70,7 @@ public class MultiSectionCapacitor extends AbstractLabeledComponent<Capacitance[
public static Color BODY_COLOR = Color.decode("#6B6DCE");
public static Color BASE_COLOR = Color.decode("#333333");
public static Color BORDER_COLOR = BODY_COLOR.darker();
public static Color PIN_COLOR = METAL_COLOR;// Color.decode("#00B2EE");
// public static Color PIN_BORDER_COLOR = PIN_COLOR.darker();
public static Color TERMINAL_COLOR = METAL_COLOR;
public static Color LABEL_COLOR = Color.white;
public static Size PIN_SIZE = new Size(0.08d, SizeUnit.in);
// public static Size PIN_SPACING = new Size(0.05d, SizeUnit.in);
@@ -89,7 +88,7 @@ public class MultiSectionCapacitor extends AbstractLabeledComponent<Capacitance[
private Color baseColor = BASE_COLOR;
private Color borderColor = BORDER_COLOR;
private Color labelColor = LABEL_COLOR;
private Color pinColor = PIN_COLOR;
private Color pinColor = TERMINAL_COLOR;
protected Display display = Display.NAME;
// private Size pinSpacing = PIN_SPACING;
private Size diameter = BODY_DIAMETER;
@@ -455,7 +454,7 @@ public class MultiSectionCapacitor extends AbstractLabeledComponent<Capacitance[
margin = 6 * width / 32;
area = new Area(new Ellipse2D.Double(margin, margin, width - 2 * margin + 1, width - 2 * margin + 1));
g2d.fill(area);
g2d.setColor(PIN_COLOR);
g2d.setColor(TERMINAL_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 / 2 + (i - 1) * (height / 5), pinSize, pinSize);
@@ -71,8 +71,6 @@ public class TrimmerPotentiometer extends AbstractPotentiometer {
private static Color BORDER_COLOR = Color.decode("#8E8E38");
private static Color SHAFT_COLOR = Color.decode("#FFFFE0");
private static Color SHAFT_BORDER_COLOR = Color.decode("#8E8E38");
public static Color PIN_COLOR = Color.decode("#00B2EE");
public static Color PIN_BORDER_COLOR = PIN_COLOR.darker();
public static Size PIN_SIZE = new Size(0.03d, SizeUnit.in);
protected static Display DISPLAY = Display.NAME;
@@ -55,8 +55,6 @@ public abstract class AbstractMotor extends AbstractTransparentComponent<Void> {
public static Color SHAFT_BORDER_COLOR = Color.decode("#A0A0A0");
public static Color METAL_BODY_COLOR = Color.decode("#8899A6");
public static Color BRASS_COLOR = Color.decode("#D4AF37");
public static Color PIN_COLOR = Color.decode("#00B2EE");
public static Color PIN_BORDER_COLOR = PIN_COLOR.darker();
public static Size PIN_SIZE = new Size(0.04d, SizeUnit.in);
public static Size PIN_SPACING = new Size(0.1d, SizeUnit.in);
@@ -86,8 +86,6 @@ public class BridgeRectifier extends AbstractLabeledComponent<String> implements
public static Color BODY_COLOR = Color.gray;
public static Color BORDER_COLOR = Color.gray.darker();
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 = 6;
public static Size SQUARE_PIN_SIZE = new Size(0.04d, SizeUnit.in);
@@ -361,21 +359,6 @@ public class BridgeRectifier extends AbstractLabeledComponent<String> implements
: SQUARE_PIN_SIZE.convertToPixels()) / 2 * 2;
g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(1f));
if (!outlineMode) {
for (Point2D point : controlPoints) {
g2d.setColor(PIN_COLOR);
Shape shape;
if (pinShape == PinShape.Round)
shape = new Ellipse2D.Double(point.getX() - pinSize / 2, point.getY() - pinSize / 2,
pinSize, pinSize);
else
shape = new Rectangle2D.Double(point.getX() - pinSize / 2, point.getY() - pinSize / 2,
pinSize, pinSize);
g2d.fill(shape);
g2d.setColor(PIN_BORDER_COLOR);
g2d.draw(shape);
}
}
Composite oldComposite = applyAlpha(g2d, componentState);
g2d.setColor(outlineMode ? Constants.TRANSPARENT_COLOR : getBodyColor());
@@ -400,7 +383,9 @@ public class BridgeRectifier extends AbstractLabeledComponent<String> implements
g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(1));
if (outlineMode) {
Area area = new Area(mainArea);
area.subtract(getBody()[1]);
if (getBody()[1] != null) {
area.subtract(getBody()[1]);
}
g2d.draw(area);
} else {
g2d.draw(mainArea);
@@ -410,6 +395,28 @@ public class BridgeRectifier extends AbstractLabeledComponent<String> implements
// }
}
// round, in-line and BR-3 packages have their pins under the body, so pins are drawn over it
// to stay visible whatever its alpha
Color pinBorderColor = outlineMode ? ((Theme) ConfigurationManager.getInstance()
.readObject(IPlugInPort.THEME_KEY, Constants.DEFAULT_THEME)).getOutlineColor()
: PIN_BORDER_COLOR;
for (Point2D point : controlPoints) {
Shape shape;
if (pinShape == PinShape.Round) {
shape = new Ellipse2D.Double(point.getX() - pinSize / 2, point.getY() - pinSize / 2,
pinSize, pinSize);
} else {
shape = new Rectangle2D.Double(point.getX() - pinSize / 2, point.getY() - pinSize / 2,
pinSize, pinSize);
}
if (!outlineMode) {
g2d.setColor(PIN_COLOR);
g2d.fill(shape);
}
g2d.setColor(pinBorderColor);
g2d.draw(shape);
}
drawingObserver.stopTracking();
// Draw label.
@@ -75,8 +75,6 @@ public class DIL_IC extends AbstractLabeledComponent<String>
public static Color BODY_COLOR = Color.gray;
public static Color BORDER_COLOR = Color.gray.darker();
public static Color PIN_COLOR = METAL_COLOR;
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;
@@ -67,8 +67,6 @@ public class MultiwattIC extends AbstractTransparentComponent<String>
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 Color TAB_COLOR = Color.lightGray;
public static Color TAB_BORDER_COLOR = TAB_COLOR.darker();
@@ -71,8 +71,6 @@ public class SIL_IC extends AbstractTransparentComponent<String>
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;
@@ -315,18 +313,7 @@ public class SIL_IC extends AbstractTransparentComponent<String>
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) Math.round(point.getX() - pinSize / 2), (int) Math.round(point.getY() - pinSize / 2), pinSize, pinSize);
g2d.setColor(PIN_BORDER_COLOR);
g2d.drawOval((int) Math.round(point.getX() - pinSize / 2), (int) Math.round(point.getY() - pinSize / 2), pinSize, pinSize);
}
}
Composite oldComposite = applyAlpha(g2d, componentState);
g2d.setColor(outlineMode ? Constants.TRANSPARENT_COLOR : getBodyColor());
g2d.fill(mainArea);
@@ -358,6 +345,25 @@ public class SIL_IC extends AbstractTransparentComponent<String>
g2d.fill(getBody()[1]);
}
}
// the pins sit under the body, so they are drawn over it to stay visible whatever its alpha
int pinSize = (int) PIN_SIZE.convertToPixels() / 2 * 2;
Color pinBorderColor = outlineMode ? ((Theme) ConfigurationManager.getInstance()
.readObject(IPlugInPort.THEME_KEY, Constants.DEFAULT_THEME)).getOutlineColor()
: PIN_BORDER_COLOR;
for (Point2D point : controlPoints) {
int pinX = (int) Math.round(point.getX() - pinSize / 2);
int pinY = (int) Math.round(point.getY() - pinSize / 2);
if (!outlineMode) {
g2d.setColor(PIN_COLOR);
drawingObserver.startTracking();
g2d.fillOval(pinX, pinY, pinSize, pinSize);
drawingObserver.stopTracking();
}
g2d.setColor(pinBorderColor);
g2d.drawOval(pinX, pinY, pinSize, pinSize);
}
// Draw label.
g2d.setFont(project.getFont());
Color finalLabelColor;
@@ -65,8 +65,6 @@ public class TransistorTO1 extends AbstractTransistorPackage {
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);
@@ -65,8 +65,6 @@ public class TransistorTO126 extends AbstractTransistorPackage {
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);
@@ -66,8 +66,6 @@ public class TransistorTO220 extends AbstractTransistorPackage {
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;
@@ -70,8 +70,6 @@ public class TransistorTO3 extends AbstractLabeledComponent<String>
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);
@@ -66,8 +66,6 @@ public class TransistorTO92 extends AbstractTransistorPackage {
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);
@@ -53,8 +53,8 @@ public abstract class PassiveSMDComponent<T> extends AbstractLabeledComponent<T>
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 END_CAP_COLOR = METAL_COLOR;
public static Color END_CAP_BORDER_COLOR = END_CAP_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);
@@ -265,7 +265,7 @@ public abstract class PassiveSMDComponent<T> extends AbstractLabeledComponent<T>
// draw contact area
Area contactArea = getBody()[1];
if (!outlineMode) {
g2d.setColor(PIN_COLOR);
g2d.setColor(END_CAP_COLOR);
applyAlpha(g2d, componentState);
g2d.fill(contactArea);
g2d.setComposite(oldComposite);
@@ -280,7 +280,7 @@ public abstract class PassiveSMDComponent<T> extends AbstractLabeledComponent<T>
} else {
finalBorderColor =
componentState == ComponentState.SELECTED || componentState == ComponentState.DRAGGING ? SELECTION_COLOR
: PIN_BORDER_COLOR;
: END_CAP_BORDER_COLOR;
}
g2d.setColor(finalBorderColor);
g2d.draw(contactArea);
@@ -374,7 +374,7 @@ public abstract class PassiveSMDComponent<T> extends AbstractLabeledComponent<T>
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.setColor(END_CAP_COLOR);
g2d.fill(contactArea);
}
@@ -74,8 +74,6 @@ public class SubminiTube extends AbstractLabeledComponent<String> implements IDa
public static Color BODY_COLOR = Color.decode("#DDDDDD");
public static Color BORDER_COLOR = Color.gray;
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 LEAD_SPACING = new Size(0.1d, SizeUnit.in);
public static Size BODY_WIDTH = new Size(0.4d, SizeUnit.in);
@@ -92,8 +92,8 @@ public class TubeSocket extends AbstractAngledComponent<String>
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 Color LUG_COLOR = METAL_COLOR;
public static Color LUG_BORDER_COLOR = LUG_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);
@@ -327,13 +327,15 @@ public class TubeSocket extends AbstractAngledComponent<String>
controlPoints[i].getY()));
pinShape = rotatedPin;
}
g2d.setColor(outlineMode ? Constants.TRANSPARENT_COLOR : PIN_COLOR);
// chassis sockets show their metal solder lugs; PCB pins are drawn like the pins of ICs
boolean pcb = getMount() == Mount.PCB;
g2d.setColor(outlineMode ? Constants.TRANSPARENT_COLOR : pcb ? PIN_COLOR : LUG_COLOR);
if (getMount() == Mount.CHASSIS)
drawingObserver.startTrackingContinuityArea(true);
g2d.fill(pinShape);
drawingObserver.stopTrackingContinuityArea();
if (!outlineMode) {
g2d.setColor(PIN_BORDER_COLOR);
g2d.setColor(pcb ? PIN_BORDER_COLOR : LUG_BORDER_COLOR);
g2d.draw(pinShape);
}
}
@@ -370,9 +372,9 @@ public class TubeSocket extends AbstractAngledComponent<String>
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.setColor(LUG_COLOR);
g2d.fillOval(x - 1, y - 1, 3, 3);
g2d.setColor(PIN_BORDER_COLOR);
g2d.setColor(LUG_BORDER_COLOR);
g2d.drawOval(x - 1, y - 1, 3, 3);
}
}