* initial * more components * fixes * Update TreePanel.java * fix boost converter * Improve wrapping of component names * Update ULN2003Driver.java * Update NRF24L01Transceiver.java * imp * updates * improvements * more components * arduino * uno * icon * cleanup * mega * mega * improveent * nano * esp boards * esp * esp32 * esp32 * Update ESP8266NodeMCU.java * d1 * Update WemosD1Mini.java * pi * consolidate esp32 * pi pico updates * pi zero * Update RaspberryPiZero.java * pi pico * cleanup * pi improvements * consolidate pins * antenna consolidation * improve solder pads * teensy * headers * teensy fix, test cleanup * s3 * Update ESP32DevKit.java * usb standardization * pico w * button standardization * arduino improvements * Update AbstractMakerBoard.java * Update RaspberryPiZero.java * Update RaspberryPi.java * pi 3 * pi 5 improvements * Update RaspberryPiZero.java * fix tests * esp pinout fix * Update ESP32DevKit.java * pin name improvements * Create tier-1-modern-boards.md * new versions * pinouts * nano improvements * sanitize node names * label improvements * minima fixes * arduino uno labels * nano labels * Update ArduinoNano.java * mega * mega * comment out future stuff * release prep * Update RaspberryPiPico.java * Refactor abstract class * labeling improvement * label offset fixes * Update Teensy.java * consolidate tests * micro variants * Update RaspberryPi.java * displays tweaks * display improvements * neopix * displays * improvements * led matrix * strip * led bar graph * jewel * tft * tft * Update maker-peripherals.md * nokia * led bar * labels * tft * cleanup * oled * cleanup * display enhancement * displays * neopixel * displays * displays * new tft * displays * icon * variants * 2-digit 0.56 inch 7 segment * Added ability to hide component categories in the component tree and toolbar from the Config menu * led bar * Update variants.xml * color selection for bar graph * Added 1.8" sd * tft fixes * Update WS2812BRing.java * neopixel improvements * netlist and node name improvements * oled tweak * cleanup * mockito fix --------- Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
8.7 KiB
name, description
| name | description |
|---|---|
| add-component | Add a new component type to the DIYLC library, or substantially modify an existing one. Use when asked to create a new part (resistor variant, board, jack, switch, pickup, symbol, shape), add editable properties to a component, change how a component draws or reports connectivity, or make a component rotatable/mirrorable. |
Adding a component to DIYLC
Components live in diylc-library/src/main/java/org/diylc/components/. They are discovered at
runtime by Reflections scanning org.diylc — there is no registry to update. A class becomes a
component by carrying @ComponentDescriptor and implementing IDIYComponent (in practice, by
extending one of the abstract bases).
Before writing anything
- Find the closest existing component and read it end to end. A new axial part follows
passive/Resistor.java; a new board followsboards/VeroBoard.java; a new schematic symbol followsAbstractSchematicLeadedSymbolsubclasses; a new jack followselectromechanical/. The new class should read like a sibling of that file. - Ask whether it is really a new class. If the request is a revision or size variant of
something that already exists, prefer adding a
Version(or similar enum) property to the existing class over creating a parallel class. That keeps old project files loading and keeps the toolbox from sprawling. - Pick the right package —
passive,semiconductors,electromechanical,boards,guitar,tube,chassis,shapes,smd,connectivity,misc,autocreate. The package should match thecategoryin the descriptor.
Choosing a base class
| Base | Use for |
|---|---|
AbstractComponent<T> |
Anything that fits nothing else |
AbstractLabeledComponent<T> |
Adds name/value label rendering |
AbstractTransparentComponent<T> |
Anything with an alpha/transparency property |
AbstractLeadedComponent<T> |
Two-lead axial parts drawn between two points; implement getDefaultLength(), getDefaultWidth(), getBodyShape() |
AbstractRadialComponent<T> |
Radial (two leads out the same side) parts |
AbstractCurvedComponent<T> |
Curves and traces defined by control points |
AbstractAngledComponent<T> |
Parts placed by point and angle |
AbstractBoard / AbstractProtoBoard / AbstractVeroBoard |
Boards |
AbstractMultiPartComponent<T> |
Components made of several independently drawn sections |
Abstract3LegSymbol, AbstractDiodeSymbol, AbstractTubeSymbol, AbstractGuitarPickup, AbstractShape |
The obvious specialisations |
Extend the most specific base that fits. Do not reimplement behaviour a base already provides.
The class
/* ... GPL header copied verbatim from HEADER.txt ... */
package org.diylc.components.passive;
import ... // java.*, then third-party, then org.diylc.*
@ComponentDescriptor(name = "My Part", author = "Branislav Stojkovic", category = "Passive",
creationMethod = CreationMethod.POINT_BY_POINT, instanceNamePrefix = "X",
description = "Short sentence shown in the toolbox tooltip", zOrder = IDIYComponent.COMPONENT,
transformer = SimpleComponentTransformer.class, enableCache = true)
public class MyPart extends AbstractLeadedComponent<Resistance> {
private static final long serialVersionUID = 1L;
public static Size DEFAULT_WIDTH = new Size(1d / 2, SizeUnit.in);
public static Color BODY_COLOR = Color.decode("#82CFFD");
private Resistance value = null;
public MyPart() {
super();
this.bodyColor = BODY_COLOR;
}
@EditableProperty(validatorClass = PositiveMeasureValidator.class)
public Resistance getValue() {
return value;
}
public void setValue(Resistance value) {
this.value = value;
}
@Override
public void drawIcon(Graphics2D g2d, int width, int height) { ... }
public enum Version { // nested types last, just before the closing brace
...
}
}
Requirements the framework enforces:
- No-argument public constructor, and the class must be serializable with a
private static final long serialVersionUID = 1L;. @ComponentDescriptorneedsname,description,category,author,instanceNamePrefixandzOrderat minimum. SetenableCache = truefor anything whose drawing is expensive and does not depend on neighbouring components.- Appearance constants are
public staticand deliberately not final, so they can be overridden at runtime. Follow that. - Nested types — a
Versionenum, a package or size enum, a small helper class — go at the bottom of the file, after every method, so the outer class reads top to bottom without a block of enum declarations in the middle of it.
Editable properties
- Annotate the getter with
@EditableProperty; a matchingsetXYZmust exist. The property name comes from the getter unless you passname. - Use
sortOrderwhen the order in the editor matters,defaultable = falsefor properties that must not be remembered as a user default, andvalidatorClass(e.g.PositiveMeasureValidator,PositiveNonZeroMeasureValidator) where a raw value would be invalid. - Use the measure types from
org.diylc.core.measures(Size,Resistance,Capacitance,Voltage,Power,Percentage) rather than raw numbers — they carry units and format themselves. - For a runtime-computed list of allowed values, add
@DynamicList(availableValueFunction = "getXyz")alongside@EditableProperty. (TheadditionalOptionsexample inEditableProperty's own Javadoc is stale — that attribute no longer exists.) - Override
getValueForDisplay()when the canvas label should combine several properties.
Drawing
draw(Graphics2D, ComponentState, boolean outlineMode, Project, IDrawingObserver) runs on every
repaint, for every instance. Treat it as a hot path.
- Fetch strokes from
ObjectCache.getInstance().fetchBasicStroke(w),fetchZoomableStroke(w)orfetchStroke(w, dash, phase, cap). Do not allocatenew BasicStroke(...)indraw(). - Honour
outlineModeand everyComponentState(NORMAL,SELECTED,DRAGGING) the way the neighbouring components do. drawIcon(g2d, width, height)is a separate, hand-drawn miniature for the toolbox — it is not a scaled call intodraw().
Connectivity
If the component conducts, wrap the conductive drawing in
drawingObserver.startTrackingContinuityArea(true) / stopTrackingContinuityArea(), exactly as the
comparable component does. Getting this wrong silently corrupts continuity checks and the netlist
without any visible rendering difference. startTracking() / stopTracking() control whether
drawing contributes to the component's clickable area.
Also implement, where relevant:
getControlPointCount(),getControlPoint(int),setControlPoint(Point2D, int),isControlPointSticky(int),getControlPointNodeName(int)— the connection points.getInternalLinkName(int, int)andgetSectionNames(int)— internal conduction between points, needed by the netlist and analyzers.IGerberComponentSimpleorIGerberComponentCustomif the part should appear in Gerber output.
Rotation and mirroring
These live in an IComponentTransformer under
diylc-library/src/main/java/org/diylc/components/transform/, referenced from the transformer
attribute of @ComponentDescriptor — never inside the component itself. Reuse
SimpleComponentTransformer or an existing transformer where the behaviour matches; write a new one
only when the part rotates or mirrors differently from everything that exists.
Datasheets and variants
If the part has a catalogue of real-world values and sizes, set enableDatasheet = true and
datasheetCreationStepCount, and add the file under
diylc-library/src/main/resources/datasheets/. Follow the format of an existing .datasheet file
and add a spot-check to DatasheetServiceTest.
Backward compatibility
Once a component ships, its serialized shape is a contract:
- Never rename, remove, or retype a serialized field, and never rename or move the class.
- To replace a property, keep the old field, mark the old accessors
@Deprecated, add the new field, and migrate lazily in the new getter — seeAbstractTransparentComponent.getAlpha(),Resistor.getPowerNew(),AbstractFilmCapacitor.getVoltageNew(). - Fields added later arrive as
nullfrom old files; default them in the getter, not the constructor.
Verify
mvn -q -pl diylc-library -am test
Then state plainly that the component still needs a visual check in the running app — automated tests
do not cover component appearance. Offer a regression-suite run (see the regression-test skill) for
any change to an existing component's drawing or serialization.