mirror of
https://github.com/bancika/diy-layout-creator
synced 2026-11-07 12:24:58 +10:00
Compare commits
32 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 4d8bf5471a | |||
| 6fa0e7d56a | |||
| 12726338ef | |||
| f3a8e3cfb1 | |||
| 1ac8ba8a24 | |||
| 7b5bb3a152 | |||
| ce7753744a | |||
| 3adaa16537 | |||
| aa4f4c9c66 | |||
| ef01d52905 | |||
| 892de712b2 | |||
| 79aa25f14c | |||
| 165b61329c | |||
| c251e5ace2 | |||
| 550e221265 | |||
| 7110897e9d | |||
| 74badd8a01 | |||
| 95eccffa4a | |||
| 35a190b02f | |||
| 92457ae0fb | |||
| 73d3dd1cd4 | |||
| cb9cd46261 | |||
| 4bd3943345 | |||
| 30bdc7fc3d | |||
| a1d31c1ae2 | |||
| 90fb3095bd | |||
| 0c468369cd | |||
| f88b0c642a | |||
| 1b8bdbe7ed | |||
| 185b5da4d5 | |||
| cd92464467 | |||
| 59e18c6be2 |
@@ -7,7 +7,7 @@
|
||||
<parent>
|
||||
<groupId>org.diylc</groupId>
|
||||
<artifactId>diylc-parent</artifactId>
|
||||
<version>5.4.0</version>
|
||||
<version>5.7.0</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>diylc-core</artifactId>
|
||||
|
||||
@@ -300,7 +300,7 @@ public class GerberG2DWrapper extends Graphics2D
|
||||
|
||||
@Override
|
||||
public AffineTransform getTransform() {
|
||||
return tx;
|
||||
return new AffineTransform(tx);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -101,23 +101,7 @@ public class NetlistBuilder {
|
||||
|
||||
// if there are no switches, make one with 1 position so we get 1 result back
|
||||
if (switches.isEmpty())
|
||||
switches.add(new ISwitch() {
|
||||
|
||||
@Override
|
||||
public String getPositionName(int position) {
|
||||
return "Default";
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getPositionCount() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean arePointsConnected(int index1, int index2, int position) {
|
||||
return false;
|
||||
}
|
||||
});
|
||||
switches.add(new TrivialSwitch());
|
||||
|
||||
// construct all possible combinations
|
||||
int[] positions = new int[switches.size()];
|
||||
@@ -418,7 +402,9 @@ public class NetlistBuilder {
|
||||
// handle direct connections or connections through a switch
|
||||
// when not using "includeSwitches" flag
|
||||
if (c instanceof IContinuity &&
|
||||
(!(c instanceof ISwitch) || switchPositions.isEmpty())) {
|
||||
// ugly way to check if running in "exclude switches" mode.
|
||||
(!(c instanceof ISwitch) || (switchPositions.size() == 1 &&
|
||||
switchPositions.keySet().stream().findFirst().get() instanceof TrivialSwitch))) {
|
||||
for (int i = 0; i < c.getControlPointCount() - 1; i++)
|
||||
for (int j = i + 1; j < c.getControlPointCount(); j++)
|
||||
if (((IContinuity) c).arePointsConnected(i, j))
|
||||
@@ -493,4 +479,23 @@ public class NetlistBuilder {
|
||||
return area;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private static class TrivialSwitch implements ISwitch {
|
||||
|
||||
@Override
|
||||
public String getPositionName(int position) {
|
||||
return "Default";
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getPositionCount() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean arePointsConnected(int index1, int index2, int position) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -290,7 +290,7 @@
|
||||
<minor>5</minor>
|
||||
<build>0</build>
|
||||
</versionNumber>
|
||||
<releaseDate>2025-05-13 00:00:00.000 CET</releaseDate>
|
||||
<releaseDate>2025-05-26 00:00:00.000 CET</releaseDate>
|
||||
<name></name>
|
||||
<changes>
|
||||
<org.diylc.appframework.update.Change>
|
||||
@@ -313,6 +313,10 @@
|
||||
<changeType>BUG_FIX</changeType>
|
||||
<description>X or Q keys sometimes do not register in secondary dialogs</description>
|
||||
</org.diylc.appframework.update.Change>
|
||||
<org.diylc.appframework.update.Change>
|
||||
<changeType>BUG_FIX</changeType>
|
||||
<description>'Auto-Edit Mode' doesn't do what it's supposed to</description>
|
||||
</org.diylc.appframework.update.Change>
|
||||
<org.diylc.appframework.update.Change>
|
||||
<changeType>BUG_FIX</changeType>
|
||||
<description>If the internet connection is present, but unstable, the application starts but nothing can be clicked until the connection restores</description>
|
||||
@@ -320,5 +324,117 @@
|
||||
</changes>
|
||||
<url>https://github.com/bancika/diy-layout-creator/releases</url>
|
||||
</org.diylc.appframework.update.Version>
|
||||
<org.diylc.appframework.update.Version>
|
||||
<versionNumber>
|
||||
<major>5</major>
|
||||
<minor>6</minor>
|
||||
<build>0</build>
|
||||
</versionNumber>
|
||||
<releaseDate>2025-08-11 00:00:00.000 CET</releaseDate>
|
||||
<name></name>
|
||||
<changes>
|
||||
<org.diylc.appframework.update.Change>
|
||||
<changeType>NEW_FEATURE</changeType>
|
||||
<description>Added 'Drill Hole' component that can be used for board mounting holes, chassis holes, faceplace holes, etc</description>
|
||||
</org.diylc.appframework.update.Change>
|
||||
<org.diylc.appframework.update.Change>
|
||||
<changeType>IMPROVEMENT</changeType>
|
||||
<description>Simplify zoom in/out keyboard shortcuts to only plus/minus keys and zero numerical key for zoom reset to 100</description>
|
||||
</org.diylc.appframework.update.Change>
|
||||
<org.diylc.appframework.update.Change>
|
||||
<changeType>IMPROVEMENT</changeType>
|
||||
<description>Bundle Java JRE with Linux AppImage to avoid having to install it</description>
|
||||
</org.diylc.appframework.update.Change>
|
||||
<org.diylc.appframework.update.Change>
|
||||
<changeType>IMPROVEMENT</changeType>
|
||||
<description>Updated naming conventions Mac build packages to replace 'arm' with 'silicon' and 'x86' to 'intel' for clarity</description>
|
||||
</org.diylc.appframework.update.Change>
|
||||
<org.diylc.appframework.update.Change>
|
||||
<changeType>IMPROVEMENT</changeType>
|
||||
<description>Allow Windows 64 bit installer to run on ARM-based Windows machine (through emulation)</description>
|
||||
</org.diylc.appframework.update.Change>
|
||||
<org.diylc.appframework.update.Change>
|
||||
<changeType>IMPROVEMENT</changeType>
|
||||
<description>More intuitive user account creation dialog for DIYLC Cloud - showing exact requirements for password and marking optional entries</description>
|
||||
</org.diylc.appframework.update.Change>
|
||||
<org.diylc.appframework.update.Change>
|
||||
<changeType>IMPROVEMENT</changeType>
|
||||
<description>Improved project search algorithm in DIYLC cloud</description>
|
||||
</org.diylc.appframework.update.Change>
|
||||
<org.diylc.appframework.update.Change>
|
||||
<changeType>IMPROVEMENT</changeType>
|
||||
<description>When a switch position is selected (i.e. set to a value other than None), DIYLC will treat the terminals that are internally connected in that switching logic as connected in analysis tools</description>
|
||||
</org.diylc.appframework.update.Change>
|
||||
<org.diylc.appframework.update.Change>
|
||||
<changeType>IMPROVEMENT</changeType>
|
||||
<description>Increase maximum size of the backup folder from 64MB to 1GB for deeper history</description>
|
||||
</org.diylc.appframework.update.Change>
|
||||
<org.diylc.appframework.update.Change>
|
||||
<changeType>BUG_FIX</changeType>
|
||||
<description>Alignment issues of some visual elements in the resulting Gerber files, e.g. DIL IC pin designators</description>
|
||||
</org.diylc.appframework.update.Change>
|
||||
<org.diylc.appframework.update.Change>
|
||||
<changeType>BUG_FIX</changeType>
|
||||
<description>'Connect to Patreon' option says that it connected account with username 'a b c' but doesn't do anything</description>
|
||||
</org.diylc.appframework.update.Change>
|
||||
</changes>
|
||||
<url>https://github.com/bancika/diy-layout-creator/releases</url>
|
||||
</org.diylc.appframework.update.Version>
|
||||
<org.diylc.appframework.update.Version>
|
||||
<versionNumber>
|
||||
<major>5</major>
|
||||
<minor>7</minor>
|
||||
<build>0</build>
|
||||
</versionNumber>
|
||||
<releaseDate>2025-12-21 00:00:00.000 CET</releaseDate>
|
||||
<name></name>
|
||||
<changes>
|
||||
<org.diylc.appframework.update.Change>
|
||||
<changeType>NEW_FEATURE</changeType>
|
||||
<description>Added '6P5T (5-Position 6 Pole AxLabs)' lever switch type (thank you mm-rnd)</description>
|
||||
</org.diylc.appframework.update.Change>
|
||||
<org.diylc.appframework.update.Change>
|
||||
<changeType>NEW_FEATURE</changeType>
|
||||
<description>Added '4P3T (3-Position 4 Pole AxLabs)' lever switch type (thank you mm-rnd)</description>
|
||||
</org.diylc.appframework.update.Change>
|
||||
<org.diylc.appframework.update.Change>
|
||||
<changeType>NEW_FEATURE</changeType>
|
||||
<description>Added 'DP3T (Import 5-Position 2502N)' lever switch type (thank you mm-rnd)</description>
|
||||
</org.diylc.appframework.update.Change>
|
||||
<org.diylc.appframework.update.Change>
|
||||
<changeType>IMPROVEMENT</changeType>
|
||||
<description>Corrected 'S1 Switch' up/down position designators (thank you mm-rnd)</description>
|
||||
</org.diylc.appframework.update.Change>
|
||||
<org.diylc.appframework.update.Change>
|
||||
<changeType>IMPROVEMENT</changeType>
|
||||
<description>Corrected 'Mini Toggle Switch' position names for center-OFF variants to be in the correct order (thank you mm-rnd)</description>
|
||||
</org.diylc.appframework.update.Change>
|
||||
<org.diylc.appframework.update.Change>
|
||||
<changeType>IMPROVEMENT</changeType>
|
||||
<description>'Drill Hole' changes color to red when selected</description>
|
||||
</org.diylc.appframework.update.Change>
|
||||
</changes>
|
||||
<url>https://github.com/bancika/diy-layout-creator/releases</url>
|
||||
</org.diylc.appframework.update.Version>
|
||||
<org.diylc.appframework.update.Version>
|
||||
<versionNumber>
|
||||
<major>5</major>
|
||||
<minor>8</minor>
|
||||
<build>0</build>
|
||||
</versionNumber>
|
||||
<releaseDate>2025-12-21 00:00:00.000 CET</releaseDate>
|
||||
<name></name>
|
||||
<changes>
|
||||
<org.diylc.appframework.update.Change>
|
||||
<changeType>IMPROVEMENT</changeType>
|
||||
<description>Improved sensitivity of 'Multimeter Probe' that required pixel-level precision to detect connectivity; improved rendering of the probe in outline mode</description>
|
||||
</org.diylc.appframework.update.Change>
|
||||
<org.diylc.appframework.update.Change>
|
||||
<changeType>BUG_FIX</changeType>
|
||||
<description>Fixed underside rendering and mirroring position issues that affected only SPDT 'Mini Toggle Switch' types</description>
|
||||
</org.diylc.appframework.update.Change>
|
||||
</changes>
|
||||
<url>https://github.com/bancika/diy-layout-creator/releases</url>
|
||||
</org.diylc.appframework.update.Version>
|
||||
</a>
|
||||
</java.util.Arrays_-ArrayList>
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
<parent>
|
||||
<groupId>org.diylc</groupId>
|
||||
<artifactId>diylc-parent</artifactId>
|
||||
<version>5.4.0</version>
|
||||
<version>5.7.0</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>diylc-library</artifactId>
|
||||
|
||||
@@ -41,7 +41,7 @@ import org.diylc.core.annotations.EditableProperty;
|
||||
|
||||
@ComponentDescriptor(name = "Blank Board", category = "Boards", author = "Branislav Stojkovic",
|
||||
zOrder = IDIYComponent.BOARD, instanceNamePrefix = "Board", description = "Blank circuit board",
|
||||
bomPolicy = BomPolicy.SHOW_ONLY_TYPE_NAME, autoEdit = false, transformer = SimpleComponentTransformer.class)
|
||||
bomPolicy = BomPolicy.SHOW_ONLY_TYPE_NAME, transformer = SimpleComponentTransformer.class)
|
||||
public class BlankBoard extends AbstractBoard {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@@ -50,7 +50,7 @@ import org.diylc.core.measures.SizeUnit;
|
||||
|
||||
@ComponentDescriptor(name = "Breadboard", category = "Boards", author = "Branislav Stojkovic",
|
||||
description = "Prototyping solderless breadboard", instanceNamePrefix = "BB",
|
||||
zOrder = IDIYComponent.BOARD, bomPolicy = BomPolicy.SHOW_ONLY_TYPE_NAME, autoEdit = false,
|
||||
zOrder = IDIYComponent.BOARD, bomPolicy = BomPolicy.SHOW_ONLY_TYPE_NAME,
|
||||
keywordPolicy = KeywordPolicy.SHOW_TYPE_NAME, enableCache = true, transformer = ProtoBoardTransformer.class)
|
||||
public class Breadboard extends AbstractProtoBoard {
|
||||
|
||||
|
||||
+1
-1
@@ -52,7 +52,7 @@ import org.diylc.core.measures.SizeUnit;
|
||||
author = "Branislav Stojkovic",
|
||||
description = "David Haillant's eurorack format stripboard for prototyping and building simple modules",
|
||||
instanceNamePrefix = "BB", zOrder = IDIYComponent.BOARD,
|
||||
bomPolicy = BomPolicy.SHOW_ONLY_TYPE_NAME, autoEdit = false,
|
||||
bomPolicy = BomPolicy.SHOW_ONLY_TYPE_NAME,
|
||||
keywordPolicy = KeywordPolicy.SHOW_TYPE_NAME, enableCache = true,
|
||||
transformer = ProtoBoardTransformer.class)
|
||||
public class EurorackStripboard extends AbstractProtoBoard {
|
||||
|
||||
@@ -42,7 +42,7 @@ import org.diylc.utils.Constants;
|
||||
|
||||
@ComponentDescriptor(name = "Eyelet Board", category = "Boards", author = "Branislav Stojkovic",
|
||||
zOrder = IDIYComponent.BOARD, instanceNamePrefix = "Board", description = "Perforated board with eyelets",
|
||||
bomPolicy = BomPolicy.SHOW_ONLY_TYPE_NAME, autoEdit = false, keywordPolicy = KeywordPolicy.SHOW_TYPE_NAME,
|
||||
bomPolicy = BomPolicy.SHOW_ONLY_TYPE_NAME, keywordPolicy = KeywordPolicy.SHOW_TYPE_NAME,
|
||||
transformer = AbstractBoardTransformer.class, enableCache = true)
|
||||
public class EyeletBoard extends AbstractBoard {
|
||||
|
||||
|
||||
+1
-1
@@ -44,7 +44,7 @@ import org.diylc.utils.Constants;
|
||||
@ComponentDescriptor(name = "Marshall Style Perf Board", category = "Boards", author = "Branislav Stojkovic",
|
||||
zOrder = IDIYComponent.BOARD, instanceNamePrefix = "Board",
|
||||
description = "Perforated board as found on some Marshall and Trainwreck amps",
|
||||
bomPolicy = BomPolicy.SHOW_ONLY_TYPE_NAME, autoEdit = false, keywordPolicy = KeywordPolicy.SHOW_TAG,
|
||||
bomPolicy = BomPolicy.SHOW_ONLY_TYPE_NAME, keywordPolicy = KeywordPolicy.SHOW_TAG,
|
||||
keywordTag = "Perf Board", transformer = AbstractBoardTransformer.class)
|
||||
public class MarshallPerfBoard extends AbstractBoard {
|
||||
|
||||
|
||||
@@ -44,7 +44,7 @@ import org.diylc.utils.Constants;
|
||||
|
||||
@ComponentDescriptor(name = "Perf Board w/ Pads", category = "Boards", author = "Branislav Stojkovic",
|
||||
zOrder = IDIYComponent.BOARD, instanceNamePrefix = "Board", description = "Perforated board with solder pads",
|
||||
bomPolicy = BomPolicy.SHOW_ONLY_TYPE_NAME, autoEdit = false, keywordPolicy = KeywordPolicy.SHOW_TAG,
|
||||
bomPolicy = BomPolicy.SHOW_ONLY_TYPE_NAME, keywordPolicy = KeywordPolicy.SHOW_TAG,
|
||||
keywordTag = "Perf Board", transformer = AbstractBoardTransformer.class, enableCache = true)
|
||||
public class PerfBoard extends AbstractBoard implements ILayeredComponent {
|
||||
|
||||
|
||||
@@ -47,7 +47,7 @@ import org.diylc.core.measures.SizeUnit;
|
||||
|
||||
@ComponentDescriptor(name = "P-0+o (Proto) Board", category = "Boards", author = "Branislav Stojkovic",
|
||||
description = "A prototyping board for modular synths, central bus with V+ GND and V-", instanceNamePrefix = "BB",
|
||||
zOrder = IDIYComponent.BOARD, bomPolicy = BomPolicy.SHOW_ONLY_TYPE_NAME, autoEdit = false,
|
||||
zOrder = IDIYComponent.BOARD, bomPolicy = BomPolicy.SHOW_ONLY_TYPE_NAME,
|
||||
keywordPolicy = KeywordPolicy.SHOW_TYPE_NAME, enableCache = true, transformer = ProtoBoardTransformer.class)
|
||||
public class ProtoBoard extends AbstractProtoBoard {
|
||||
|
||||
|
||||
@@ -46,7 +46,7 @@ import org.diylc.core.measures.SizeUnit;
|
||||
author = "Branislav Stojkovic",
|
||||
description = "Prototyping board similar to Radio Shack 276-168B or MPJA 33304",
|
||||
instanceNamePrefix = "BB", zOrder = IDIYComponent.BOARD,
|
||||
bomPolicy = BomPolicy.SHOW_ONLY_TYPE_NAME, autoEdit = false,
|
||||
bomPolicy = BomPolicy.SHOW_ONLY_TYPE_NAME,
|
||||
keywordPolicy = KeywordPolicy.SHOW_TYPE_NAME, enableCache = true,
|
||||
transformer = ProtoBoardTransformer.class)
|
||||
public class ProtoBoard780 extends AbstractProtoBoard {
|
||||
|
||||
@@ -42,7 +42,7 @@ 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, autoEdit = false, keywordPolicy = KeywordPolicy.SHOW_TYPE_NAME,
|
||||
bomPolicy = BomPolicy.SHOW_ONLY_TYPE_NAME, keywordPolicy = KeywordPolicy.SHOW_TYPE_NAME,
|
||||
transformer = VeroBoardTransformer.class, enableCache = true)
|
||||
public class VeroBoard extends AbstractVeroBoard implements ILayeredComponent {
|
||||
|
||||
|
||||
+1
-1
@@ -47,7 +47,7 @@ import org.diylc.core.measures.SizeUnit;
|
||||
@ComponentDescriptor(name = "Copper Trace", author = "Branislav Stojkovic", category = "Connectivity",
|
||||
creationMethod = CreationMethod.POINT_BY_POINT, instanceNamePrefix = "Trace",
|
||||
description = "Straight copper trace", zOrder = IDIYComponent.TRACE, bomPolicy = BomPolicy.NEVER_SHOW,
|
||||
autoEdit = false, keywordPolicy = KeywordPolicy.SHOW_TAG, keywordTag = "PCB",
|
||||
keywordPolicy = KeywordPolicy.SHOW_TAG, keywordTag = "PCB",
|
||||
transformer = SimpleComponentTransformer.class)
|
||||
public class CopperTrace extends AbstractLeadedComponent<Void> implements ILayeredComponent, IGerberComponentSimple {
|
||||
|
||||
|
||||
+1
-1
@@ -46,7 +46,7 @@ import org.diylc.core.measures.SizeUnit;
|
||||
|
||||
@ComponentDescriptor(name = "Curved Trace", author = "Branislav Stojkovic", category = "Connectivity",
|
||||
instanceNamePrefix = "Trace", description = "Curved copper trace with two control points",
|
||||
zOrder = IDIYComponent.TRACE, bomPolicy = BomPolicy.NEVER_SHOW, autoEdit = false,
|
||||
zOrder = IDIYComponent.TRACE, bomPolicy = BomPolicy.NEVER_SHOW,
|
||||
keywordPolicy = KeywordPolicy.SHOW_TAG, keywordTag = "PCB", transformer = SimpleComponentTransformer.class,
|
||||
enableCache = true)
|
||||
public class CurvedTrace extends AbstractCurvedComponent<Void> implements ILayeredComponent, IGerberComponentSimple {
|
||||
|
||||
@@ -40,7 +40,7 @@ import org.diylc.utils.Constants;
|
||||
|
||||
@ComponentDescriptor(name = "Hookup Wire", author = "Branislav Stojkovic", category = "Connectivity",
|
||||
instanceNamePrefix = "W", description = "Flexible wire with two control points", zOrder = IDIYComponent.WIRING,
|
||||
flexibleZOrder = true, bomPolicy = BomPolicy.NEVER_SHOW, autoEdit = false,
|
||||
flexibleZOrder = true, bomPolicy = BomPolicy.NEVER_SHOW,
|
||||
transformer = SimpleComponentTransformer.class, enableCache = false)
|
||||
public class HookupWire extends AbstractCurvedComponent<AWG> implements IContinuity {
|
||||
|
||||
|
||||
+46
-24
@@ -28,21 +28,20 @@ import java.awt.geom.Path2D;
|
||||
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.Orientation45;
|
||||
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.*;
|
||||
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 = "Multimeter Probe", category = "Connectivity",
|
||||
author = "Branislav Stojkovic", description = "Multimeter Probe", instanceNamePrefix = "Probe",
|
||||
@@ -59,6 +58,7 @@ public class MultimeterProbe extends AbstractTransparentComponent<Color> {
|
||||
public static Size HANDLE_DIAMETER = new Size(0.2d, SizeUnit.in);
|
||||
public static Size HANDLE_LENGTH = new Size(0.4d, SizeUnit.in);
|
||||
public static Color HANDLE_COLOR = Color.red;
|
||||
public static Size SENSITIVITY = new Size(0.05d, SizeUnit.in);
|
||||
|
||||
private Point2D.Double point = new Point2D.Double(0, 0);
|
||||
private Color handleColor = HANDLE_COLOR;
|
||||
@@ -77,27 +77,49 @@ public class MultimeterProbe extends AbstractTransparentComponent<Color> {
|
||||
Shape[] shapes = getBody();
|
||||
g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(1f));
|
||||
|
||||
if (!outlineMode) {
|
||||
Composite oldComposite = g2d.getComposite();
|
||||
if (alpha < MAX_ALPHA) {
|
||||
g2d.setComposite(
|
||||
AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1f * alpha / MAX_ALPHA));
|
||||
}
|
||||
g2d.setColor(PROBE_COLOR);
|
||||
g2d.fill(shapes[0]);
|
||||
g2d.setColor(handleColor);
|
||||
g2d.fill(shapes[1]);
|
||||
g2d.setComposite(oldComposite);
|
||||
// draw an invisible conductive circle around the point to increase sensitivity
|
||||
g2d.setColor(Constants.TRANSPARENT_COLOR);
|
||||
drawingObserver.startTrackingContinuityArea(true);
|
||||
double sensitivity = SENSITIVITY.convertToPixels();
|
||||
g2d.fillOval((int) (point.getX() - sensitivity), (int) (point.getY() - sensitivity),
|
||||
(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));
|
||||
}
|
||||
g2d.setColor(
|
||||
componentState == ComponentState.SELECTED || componentState == ComponentState.DRAGGING
|
||||
? SELECTION_COLOR
|
||||
: handleColor.darker());
|
||||
g2d.setColor(outlineMode ? Constants.TRANSPARENT_COLOR : PROBE_COLOR);
|
||||
g2d.fill(shapes[0]);
|
||||
g2d.setColor(outlineMode ? Constants.TRANSPARENT_COLOR : handleColor);
|
||||
g2d.fill(shapes[1]);
|
||||
g2d.setComposite(oldComposite);
|
||||
drawingObserver.stopTracking();
|
||||
|
||||
Theme theme = (Theme) ConfigurationManager.getInstance().readObject(IPlugInPort.THEME_KEY,
|
||||
Constants.DEFAULT_THEME);
|
||||
|
||||
Color handleBorderColor;
|
||||
if (outlineMode) {
|
||||
handleBorderColor = theme.getOutlineColor();
|
||||
} else {
|
||||
handleBorderColor = componentState == ComponentState.SELECTED || componentState == ComponentState.DRAGGING
|
||||
? SELECTION_COLOR
|
||||
: handleColor.darker();
|
||||
}
|
||||
g2d.setColor(handleBorderColor);
|
||||
g2d.draw(shapes[1]);
|
||||
g2d.setColor(
|
||||
componentState == ComponentState.SELECTED || componentState == ComponentState.DRAGGING
|
||||
? SELECTION_COLOR
|
||||
: PROBE_COLOR.darker());
|
||||
|
||||
Color probeBorderColor;
|
||||
if (outlineMode) {
|
||||
probeBorderColor = theme.getOutlineColor();
|
||||
} else {
|
||||
probeBorderColor = componentState == ComponentState.SELECTED || componentState == ComponentState.DRAGGING
|
||||
? SELECTION_COLOR
|
||||
: PROBE_COLOR.darker();
|
||||
}
|
||||
g2d.setColor(probeBorderColor);
|
||||
g2d.draw(shapes[0]);
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -50,7 +50,7 @@ import org.diylc.utils.Constants;
|
||||
|
||||
@ComponentDescriptor(name = "PCB Terminal Block", category = "Connectivity",
|
||||
author = "Branislav Stojkovic", description = "Horizontal PCB terminal block with 5mm pitch",
|
||||
zOrder = IDIYComponent.COMPONENT, instanceNamePrefix = "TB", autoEdit = false,
|
||||
zOrder = IDIYComponent.COMPONENT, instanceNamePrefix = "TB",
|
||||
enableCache = true, transformer = PCBTerminalBlockTransformer.class)
|
||||
public class PCBTerminalBlock extends AbstractTransparentComponent<PCBTerminalBlockCount> implements IGerberComponentSimple {
|
||||
|
||||
|
||||
@@ -52,7 +52,7 @@ import org.diylc.utils.Constants;
|
||||
|
||||
@ComponentDescriptor(name = "Solder Pad", category = "Connectivity", author = "Branislav Stojkovic",
|
||||
description = "Copper solder pad, round or square", instanceNamePrefix = "Pad",
|
||||
zOrder = IDIYComponent.TRACE + 0.1, bomPolicy = BomPolicy.NEVER_SHOW, autoEdit = false,
|
||||
zOrder = IDIYComponent.TRACE + 0.1, bomPolicy = BomPolicy.NEVER_SHOW,
|
||||
keywordPolicy = KeywordPolicy.SHOW_TAG, keywordTag = "PCB",
|
||||
transformer = SimpleComponentTransformer.class, enableCache = true)
|
||||
public class SolderPad extends AbstractTransparentComponent<Void>
|
||||
|
||||
+1
-1
@@ -49,7 +49,7 @@ import org.diylc.utils.Constants;
|
||||
@ComponentDescriptor(name = "Twisted Leads", author = "Branislav Stojkovic",
|
||||
category = "Connectivity", instanceNamePrefix = "W",
|
||||
description = "A pair of flexible leads twisted tighly together", zOrder = IDIYComponent.WIRING,
|
||||
flexibleZOrder = true, bomPolicy = BomPolicy.NEVER_SHOW, autoEdit = false,
|
||||
flexibleZOrder = true, bomPolicy = BomPolicy.NEVER_SHOW,
|
||||
transformer = SimpleComponentTransformer.class, enableCache = true)
|
||||
public class TwistedWire extends AbstractCurvedComponent<Void> implements IContinuity {
|
||||
|
||||
|
||||
+1
-1
@@ -53,7 +53,7 @@ import org.diylc.utils.Constants;
|
||||
|
||||
@ComponentDescriptor(name = "9V Battery Snap", category = "Electro-Mechanical", author = "Branislav Stojkovic",
|
||||
description = "", zOrder = IDIYComponent.COMPONENT, instanceNamePrefix = "BTR",
|
||||
autoEdit = false, transformer = BatterySnapTransformer.class)
|
||||
transformer = BatterySnapTransformer.class)
|
||||
public class BatterySnap9V extends AbstractTransparentComponent<String> {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
+1
-1
@@ -58,7 +58,7 @@ 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", autoEdit = false, transformer = CliffJackTransformer.class,
|
||||
zOrder = IDIYComponent.COMPONENT, instanceNamePrefix = "J", transformer = CliffJackTransformer.class,
|
||||
enableCache = true)
|
||||
public class CliffJack1_4 extends AbstractMultiPartComponent<JackType> implements IGerberComponentSimple {
|
||||
|
||||
|
||||
+1
-1
@@ -54,7 +54,7 @@ import org.diylc.utils.Constants;
|
||||
|
||||
@ComponentDescriptor(name = "Cliff 1/8\" Jack", category = "Electro-Mechanical",
|
||||
author = "Branislav Stojkovic", description = "Cliff-style closed 1/8\" phono jack",
|
||||
zOrder = IDIYComponent.COMPONENT, instanceNamePrefix = "J", autoEdit = false,
|
||||
zOrder = IDIYComponent.COMPONENT, instanceNamePrefix = "J",
|
||||
transformer = CliffJackTransformer.class, enableCache = true)
|
||||
public class CliffJack1_8 extends AbstractMultiPartComponent<JackType> implements IGerberComponentSimple {
|
||||
|
||||
|
||||
+1
-1
@@ -59,7 +59,7 @@ 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", autoEdit = false, transformer = ClosedJackTransformer.class, enableCache = true)
|
||||
instanceNamePrefix = "J", transformer = ClosedJackTransformer.class, enableCache = true)
|
||||
public class ClosedJack1_4 extends AbstractMultiPartComponent<JackType> implements IGerberComponentSimple {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
+229
@@ -0,0 +1,229 @@
|
||||
/*
|
||||
*
|
||||
* 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.electromechanical;
|
||||
|
||||
import java.awt.*;
|
||||
import java.awt.geom.Ellipse2D;
|
||||
import java.awt.geom.Line2D;
|
||||
import java.awt.geom.Point2D;
|
||||
import java.awt.geom.Rectangle2D;
|
||||
|
||||
import com.bancika.gerberwriter.GerberFunctions;
|
||||
|
||||
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.PositiveNonZeroMeasureValidator;
|
||||
import org.diylc.core.gerber.GerberLayer;
|
||||
import org.diylc.core.gerber.IGerberComponentCustom;
|
||||
import org.diylc.core.gerber.IGerberDrawingObserver;
|
||||
import org.diylc.core.measures.Size;
|
||||
import org.diylc.core.measures.SizeUnit;
|
||||
|
||||
@ComponentDescriptor(name = "Drill Hole", category = "Electro-Mechanical", author = "Branislav Stojkovic",
|
||||
description = "Drill hole marker for PCB, chassis or faceplate", instanceNamePrefix = "Hole",
|
||||
zOrder = IDIYComponent.BOARD + 0.1, bomPolicy = BomPolicy.NEVER_SHOW,
|
||||
keywordPolicy = KeywordPolicy.SHOW_TAG, keywordTag = "PCB",
|
||||
transformer = SimpleComponentTransformer.class, enableCache = true)
|
||||
public class DrillHole extends AbstractTransparentComponent<Void>
|
||||
implements IGerberComponentCustom {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public static Size DIAMETER = new Size(3.0d, SizeUnit.mm);
|
||||
public static Color COLOR = Color.black;
|
||||
public static Size STROKE_WIDTH = new Size(1.0d, SizeUnit.px);
|
||||
public static Size CROSSHAIR_WIDTH = new Size(1.0d, SizeUnit.px);
|
||||
|
||||
private Size diameter = DIAMETER;
|
||||
private Color color = COLOR;
|
||||
private Point2D.Double point = new Point2D.Double(0, 0);
|
||||
|
||||
@Override
|
||||
public void draw(Graphics2D g2d, ComponentState componentState, boolean outlineMode,
|
||||
Project project, IDrawingObserver drawingObserver,
|
||||
IGerberDrawingObserver gerberDrawingObserver) {
|
||||
|
||||
if (checkPointsClipped(g2d.getClip())) {
|
||||
return;
|
||||
}
|
||||
double holeDiameter = getDiameter().convertToPixels();
|
||||
double borderWidth = STROKE_WIDTH.convertToPixels(); // Use constant stroke width
|
||||
|
||||
// Export to Gerber drill layer
|
||||
if (gerberDrawingObserver != null) {
|
||||
GerberLayer drillLayer = GerberLayer.DrillNonPlated;
|
||||
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));
|
||||
}
|
||||
|
||||
// Draw white circle (hole)
|
||||
g2d.setColor(Color.white);
|
||||
g2d.fill(new Ellipse2D.Double(point.getX() - holeDiameter / 2, point.getY() - holeDiameter / 2,
|
||||
holeDiameter, holeDiameter));
|
||||
|
||||
// Draw colored border
|
||||
g2d.setColor(
|
||||
componentState == ComponentState.SELECTED || componentState == ComponentState.DRAGGING
|
||||
? SELECTION_COLOR
|
||||
: color);
|
||||
g2d.setStroke(new BasicStroke((float) borderWidth));
|
||||
g2d.draw(new Ellipse2D.Double(point.getX() - holeDiameter / 2, point.getY() - holeDiameter / 2,
|
||||
holeDiameter, holeDiameter));
|
||||
|
||||
// Draw crosshairs
|
||||
double crosshairLength = holeDiameter * 0.4; // 40% of diameter for crosshair length (increased from 30%)
|
||||
double crosshairWidth = CROSSHAIR_WIDTH.convertToPixels(); // Use constant crosshair width
|
||||
|
||||
g2d.setStroke(new BasicStroke((float) crosshairWidth));
|
||||
|
||||
// Horizontal line
|
||||
g2d.draw(new Line2D.Double(
|
||||
point.getX() - crosshairLength / 2, point.getY(),
|
||||
point.getX() + crosshairLength / 2, point.getY()));
|
||||
|
||||
// Vertical line
|
||||
g2d.draw(new Line2D.Double(
|
||||
point.getX(), point.getY() - crosshairLength / 2,
|
||||
point.getX(), point.getY() + crosshairLength / 2));
|
||||
|
||||
drawingObserver.stopTracking();
|
||||
|
||||
if (gerberDrawingObserver != null) {
|
||||
gerberDrawingObserver.stopGerberOutput();
|
||||
}
|
||||
|
||||
g2d.setComposite(oldComposite);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void draw(Graphics2D g2d, ComponentState componentState, boolean outlineMode,
|
||||
Project project, IDrawingObserver drawingObserver) {
|
||||
this.draw(g2d, componentState, outlineMode, project, drawingObserver, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void drawIcon(Graphics2D g2d, int width, int height) {
|
||||
int diameter = getClosestOdd(width * 3 / 4); // Increased from width/2 to 3/4 of width
|
||||
int borderWidth = Math.max(1, (int) STROKE_WIDTH.convertToPixels()); // Use constant stroke width
|
||||
int crosshairLength = diameter * 2 / 5; // 40% of diameter (increased from 1/3)
|
||||
int crosshairWidth = Math.max(1, (int) CROSSHAIR_WIDTH.convertToPixels()); // Use constant crosshair width
|
||||
|
||||
// Draw white circle
|
||||
g2d.setColor(Color.white);
|
||||
g2d.fillOval((width - diameter) / 2, (height - diameter) / 2, diameter, diameter);
|
||||
|
||||
// Draw colored border
|
||||
g2d.setColor(COLOR);
|
||||
g2d.setStroke(new BasicStroke(borderWidth));
|
||||
g2d.drawOval((width - diameter) / 2, (height - diameter) / 2, diameter, diameter);
|
||||
|
||||
// Draw crosshairs
|
||||
g2d.setStroke(new BasicStroke(crosshairWidth));
|
||||
|
||||
// Horizontal line
|
||||
g2d.drawLine(
|
||||
(width - crosshairLength) / 2, height / 2,
|
||||
(width + crosshairLength) / 2, height / 2);
|
||||
|
||||
// Vertical line
|
||||
g2d.drawLine(
|
||||
width / 2, (height - crosshairLength) / 2,
|
||||
width / 2, (height + crosshairLength) / 2);
|
||||
}
|
||||
|
||||
@EditableProperty(validatorClass = PositiveNonZeroMeasureValidator.class)
|
||||
public Size getDiameter() {
|
||||
return diameter;
|
||||
}
|
||||
|
||||
public void setDiameter(Size diameter) {
|
||||
this.diameter = diameter;
|
||||
}
|
||||
|
||||
@EditableProperty(name = "Color")
|
||||
public Color getColor() {
|
||||
return color;
|
||||
}
|
||||
|
||||
public void setColor(Color color) {
|
||||
this.color = color;
|
||||
}
|
||||
|
||||
@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);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void getValue() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getControlPointNodeName(int index) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setValue(Void value) {}
|
||||
|
||||
@Override
|
||||
public Rectangle2D getCachingBounds() {
|
||||
double diameter = getDiameter().convertToPixels();
|
||||
return new Rectangle2D.Double(point.getX() - diameter, point.getY() - diameter,
|
||||
diameter * 2, diameter * 2);
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -53,7 +53,7 @@ import org.diylc.utils.Constants;
|
||||
|
||||
@ComponentDescriptor(name = "Fuse Holder (Panel)", category = "Electro-Mechanical", author = "Branislav Stojkovic",
|
||||
description = "Panel mounted fuse holder", zOrder = IDIYComponent.COMPONENT,
|
||||
instanceNamePrefix = "FH", autoEdit = false, enableCache = true)
|
||||
instanceNamePrefix = "FH", enableCache = true)
|
||||
public class FuseHolderPanel extends AbstractMultiPartComponent<String> {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
+1
-1
@@ -53,7 +53,7 @@ import org.diylc.utils.Constants;
|
||||
|
||||
@ComponentDescriptor(name = "IEC Socket", category = "Electro-Mechanical", author = "Branislav Stojkovic",
|
||||
description = "Panel mounted IEC power socket", zOrder = IDIYComponent.COMPONENT,
|
||||
instanceNamePrefix = "IEC", autoEdit = false, enableCache = true)
|
||||
instanceNamePrefix = "IEC", enableCache = true)
|
||||
public class IECSocket extends AbstractMultiPartComponent<String> {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
+12
-5
@@ -59,7 +59,7 @@ 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", autoEdit = false, enableCache = true, transformer = MiniToggleSwitchTransformer.class)
|
||||
instanceNamePrefix = "SW", enableCache = true, transformer = MiniToggleSwitchTransformer.class)
|
||||
public class MiniToggleSwitch extends AbstractTransparentComponent<ToggleSwitchType> implements ISwitch, ILayeredComponent, IGerberComponentSimple {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
@@ -502,10 +502,17 @@ public class MiniToggleSwitch extends AbstractTransparentComponent<ToggleSwitchT
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPositionName(int position) {
|
||||
if (switchType.name().endsWith("_off") && position == 2)
|
||||
return "OFF";
|
||||
return "ON" + Integer.toString(position + 1);
|
||||
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)
|
||||
|
||||
+1
-1
@@ -56,7 +56,7 @@ 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", autoEdit = false, transformer = NeutrikJack1_4Transformer.class,
|
||||
zOrder = IDIYComponent.COMPONENT, instanceNamePrefix = "J", transformer = NeutrikJack1_4Transformer.class,
|
||||
enableCache = true)
|
||||
public class NeutrikJack1_4 extends AbstractMultiPartComponent<JackType> {
|
||||
|
||||
|
||||
+1
-1
@@ -59,7 +59,7 @@ import org.diylc.utils.SwitchUtils;
|
||||
|
||||
@ComponentDescriptor(name = "Slide Switch", category = "Electro-Mechanical",
|
||||
author = "Branislav Stojkovic", description = "Panel mounted slide switch",
|
||||
zOrder = IDIYComponent.COMPONENT, instanceNamePrefix = "SW", autoEdit = false,
|
||||
zOrder = IDIYComponent.COMPONENT, instanceNamePrefix = "SW",
|
||||
enableCache = true, transformer = MiniToggleSwitchTransformer.class)
|
||||
public class SlideSwitch extends AbstractTransparentComponent<SlideSwitchType> implements ISwitch, IGerberComponentSimple {
|
||||
|
||||
|
||||
@@ -51,7 +51,7 @@ import org.diylc.utils.Constants;
|
||||
|
||||
@ComponentDescriptor(name = "Humbucker Pickup", category = "Guitar", author = "Branislav Stojkovic",
|
||||
description = "Double-coil humbucker guitar pickup (PAF, Mini Humbuckers, Filtertrons)",
|
||||
zOrder = IDIYComponent.COMPONENT, instanceNamePrefix = "PKP", autoEdit = false,
|
||||
zOrder = IDIYComponent.COMPONENT, instanceNamePrefix = "PKP",
|
||||
keywordPolicy = KeywordPolicy.SHOW_TAG, keywordTag = "Guitar Wiring Diagram", enableCache = true,
|
||||
transformer = GuitarPickupTransformer.class)
|
||||
public class HumbuckerPickup extends AbstractGuitarPickup {
|
||||
|
||||
@@ -52,7 +52,7 @@ 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", autoEdit = false,
|
||||
zOrder = IDIYComponent.COMPONENT, instanceNamePrefix = "PKP",
|
||||
keywordPolicy = KeywordPolicy.SHOW_TAG, keywordTag = "Guitar Wiring Diagram", enableCache = true,
|
||||
transformer = GuitarPickupTransformer.class)
|
||||
public class JazzBassPickup extends AbstractSingleOrHumbuckerPickup {
|
||||
|
||||
@@ -151,8 +151,13 @@ public class LeverSwitch extends AbstractAngledComponent<LeverSwitch.LeverSwitch
|
||||
g2d.draw(body[2]);
|
||||
|
||||
if (getShowMarkers()) {
|
||||
String[] markers =
|
||||
SwitchUtils.getSwitchingMarkers(this, getControlPointCount(), false);
|
||||
String[] markers;
|
||||
if(type == LeverSwitchType.DP3T_5pos_2502N) {
|
||||
markers = new String[]{"1", "2", "3", "4", "5", "6", "7", "8"};
|
||||
} else {
|
||||
markers = SwitchUtils.getSwitchingMarkers(this, getControlPointCount(), false);
|
||||
}
|
||||
|
||||
double theta = getAngle().getValueRad();
|
||||
g2d.setColor(MARKER_COLOR);
|
||||
|
||||
@@ -203,11 +208,13 @@ public class LeverSwitch extends AbstractAngledComponent<LeverSwitch.LeverSwitch
|
||||
|| type == LeverSwitchType.DP3T_5pos) {
|
||||
x += terminalLength;
|
||||
yOffset = 7;
|
||||
} else if (type == LeverSwitchType.DP3T_5pos_Import) {
|
||||
} else if (type == LeverSwitchType.DP3T_5pos_Import || type == LeverSwitchType.DP3T_5pos_2502N) {
|
||||
yOffset = 10;
|
||||
} else if (type == LeverSwitchType._6_WAY_OG) {
|
||||
x += terminalLength;
|
||||
yOffset = 8;
|
||||
} else if (type == LeverSwitchType._4P3T) {
|
||||
yOffset = 8;
|
||||
} else {
|
||||
yOffset = 12;
|
||||
}
|
||||
@@ -226,11 +233,21 @@ public class LeverSwitch extends AbstractAngledComponent<LeverSwitch.LeverSwitch
|
||||
- (waferLength - terminalSpacing * yOffset) / 2, waferThickness,
|
||||
waferLength));
|
||||
|
||||
if (type == LeverSwitchType._4P5T) {
|
||||
if (type == LeverSwitchType._4P5T || type == LeverSwitchType._6P5T) {
|
||||
waferArea.add(new Area(new Rectangle2D.Double(x - terminalLength / 2 - waferThickness / 2 + waferSpacing, y
|
||||
- (waferLength - terminalSpacing * 12) / 2, waferThickness,
|
||||
waferLength)));
|
||||
}
|
||||
if (type == LeverSwitchType._6P5T) {
|
||||
waferArea.add(new Area(new Rectangle2D.Double(x - terminalLength / 2 - waferThickness / 2 + waferSpacing * 2, y
|
||||
- (waferLength - terminalSpacing * 12) / 2, waferThickness,
|
||||
waferLength)));
|
||||
}
|
||||
if (type == LeverSwitchType._4P3T) {
|
||||
waferArea.add(new Area(new Rectangle2D.Double(x - terminalLength / 2 - waferThickness / 2 + waferSpacing, y
|
||||
- (waferLength - terminalSpacing * 8) / 2, waferThickness,
|
||||
waferLength)));
|
||||
}
|
||||
|
||||
double theta = getAngle().getValueRad();
|
||||
|
||||
@@ -294,6 +311,7 @@ public class LeverSwitch extends AbstractAngledComponent<LeverSwitch.LeverSwitch
|
||||
}
|
||||
break;
|
||||
case DP3T_5pos_Import:
|
||||
case DP3T_5pos_2502N:
|
||||
controlPoints = new Point2D[8];
|
||||
terminalSpacing *= 1.5;
|
||||
for (int i = 0; i < controlPoints.length; i++) {
|
||||
@@ -319,6 +337,21 @@ public class LeverSwitch extends AbstractAngledComponent<LeverSwitch.LeverSwitch
|
||||
controlPoints[i + 12] = new Point2D.Double(x + waferSpacing, y + i * terminalSpacing + (i >= 6 ? terminalSpacing : 0));
|
||||
}
|
||||
break;
|
||||
case _6P5T:
|
||||
controlPoints = new Point2D[36];
|
||||
for (int i = 0; i < controlPoints.length / 3; i++) {
|
||||
controlPoints[i] = new Point2D.Double(x, y + i * terminalSpacing + (i >= 6 ? terminalSpacing : 0));
|
||||
controlPoints[i + 12] = new Point2D.Double(x + waferSpacing, y + i * terminalSpacing + (i >= 6 ? terminalSpacing : 0));
|
||||
controlPoints[i + 24] = new Point2D.Double(x + waferSpacing * 2, y + i * terminalSpacing + (i >= 6 ? terminalSpacing : 0));
|
||||
}
|
||||
break;
|
||||
case _4P3T:
|
||||
controlPoints = new Point2D[16];
|
||||
for (int i = 0; i < controlPoints.length / 2; i++) {
|
||||
controlPoints[i] = new Point2D.Double(x, y + i * terminalSpacing + (i >= 4 ? terminalSpacing : 0));
|
||||
controlPoints[i + 8] = new Point2D.Double(x + waferSpacing, y + i * terminalSpacing + (i >= 4 ? terminalSpacing : 0));
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// Rotate if needed
|
||||
@@ -447,7 +480,16 @@ public class LeverSwitch extends AbstractAngledComponent<LeverSwitch.LeverSwitch
|
||||
|| (index2 == 11 && index2 - index1 == 5 - position);
|
||||
case _4P5T:
|
||||
return ((index1 == 0 || index1 == 12) && index2 - index1 == position + 1)
|
||||
|| ((index2 == 11 || index2 == 23) && index2 - index1 == 5 - position);
|
||||
|| ((index2 == 11 || index2 == 23) && index2 - index1 == 5 - position);
|
||||
case _6P5T:
|
||||
return ((index1 == 0 || index1 == 12 || index1 == 24) && index2 - index1 == position + 1)
|
||||
|| ((index2 == 11 || index2 == 23 || index2 == 35) && index2 - index1 == 5 - position);
|
||||
case _4P3T:
|
||||
return ((index1 == 0 || index1 == 8) && index2 - index1 == position + 1)
|
||||
|| ((index2 == 7 || index2 == 15) && index2 - index1 == 3 - position);
|
||||
case DP3T_5pos_2502N:
|
||||
positionConnections = DP3T_5pos_2502N_CONNECTIONS.get(position);
|
||||
break;
|
||||
}
|
||||
|
||||
if (positionConnections != null) {
|
||||
@@ -526,6 +568,32 @@ public class LeverSwitch extends AbstractAngledComponent<LeverSwitch.LeverSwitch
|
||||
) // position 6
|
||||
);
|
||||
|
||||
private static final List<List<int[]>> DP3T_5pos_2502N_CONNECTIONS = Arrays.asList(
|
||||
Arrays.asList(
|
||||
new int[] { 0, 3 }
|
||||
), // position 1
|
||||
Arrays.asList(
|
||||
new int[] { 0, 3 },
|
||||
new int[] { 1, 3 },
|
||||
new int[] { 4, 7 },
|
||||
new int[] { 5, 7 }
|
||||
), // position 2
|
||||
Arrays.asList(
|
||||
new int[] { 0, 3 },
|
||||
new int[] { 2, 3 },
|
||||
new int[] { 6, 7 }
|
||||
), // position 3
|
||||
Arrays.asList(
|
||||
new int[] { 1, 3 },
|
||||
new int[] { 2, 3 },
|
||||
new int[] { 5, 7 }
|
||||
), // position 4
|
||||
Arrays.asList(
|
||||
new int[] { 2, 3 },
|
||||
new int[] { 6, 7 }
|
||||
) // position 5
|
||||
);
|
||||
|
||||
@DynamicEditableProperty(source = LeverSwitchPositionPropertyValueSource.class)
|
||||
@EditableProperty(name = "Selected Position")
|
||||
@Override
|
||||
@@ -559,7 +627,10 @@ public class LeverSwitch extends AbstractAngledComponent<LeverSwitch.LeverSwitch
|
||||
_4P5T("4P5T (Super/Mega)", 5),
|
||||
DP4T("DP4T (4-Position Tele)", 4),
|
||||
_6_WAY_OG("DP4T (6-Position Oak Grigsby)", 6),
|
||||
DP5T("DP5T", 5);
|
||||
DP5T("DP5T", 5),
|
||||
_6P5T("6P5T (5-Position 6 Pole AxLabs)", 5),
|
||||
_4P3T("4P3T (3-Position 4 Pole AxLabs)", 3),
|
||||
DP3T_5pos_2502N("DP3T (Import 5-Position 2502N)", 5);
|
||||
|
||||
private final int positionCount;
|
||||
private String title;
|
||||
|
||||
@@ -53,7 +53,7 @@ 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", autoEdit = false,
|
||||
zOrder = IDIYComponent.COMPONENT, instanceNamePrefix = "PKP",
|
||||
keywordPolicy = KeywordPolicy.SHOW_TAG, keywordTag = "Guitar Wiring Diagram", enableCache = true)
|
||||
public class P90Pickup extends AbstractSingleOrHumbuckerPickup {
|
||||
|
||||
|
||||
@@ -52,7 +52,7 @@ 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", autoEdit = false,
|
||||
zOrder = IDIYComponent.COMPONENT, instanceNamePrefix = "PKP",
|
||||
keywordPolicy = KeywordPolicy.SHOW_TAG, keywordTag = "Guitar Wiring Diagram", enableCache = true,
|
||||
transformer = GuitarPickupTransformer.class)
|
||||
public class PBassPickup extends AbstractSingleOrHumbuckerPickup {
|
||||
|
||||
@@ -53,7 +53,7 @@ import org.diylc.utils.Constants;
|
||||
|
||||
@ComponentDescriptor(name = "S1 Switch", category = "Guitar", author = "Branislav Stojkovic",
|
||||
description = "Fender S1 4 pole pushbutton switch", zOrder = IDIYComponent.COMPONENT,
|
||||
instanceNamePrefix = "SW", autoEdit = false, enableCache = true)
|
||||
instanceNamePrefix = "SW", enableCache = true)
|
||||
public class S1Switch extends AbstractTransparentComponent<Void> implements ISwitch {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
@@ -208,9 +208,9 @@ public class S1Switch extends AbstractTransparentComponent<Void> implements ISwi
|
||||
|
||||
double dy = 0;
|
||||
if (i % 3 == 1) {
|
||||
dy = -1;
|
||||
} else if (i % 3 == 0) {
|
||||
dy = 1;
|
||||
} else if (i % 3 == 0) {
|
||||
dy = -1;
|
||||
}
|
||||
|
||||
Stroke stroke = g2d.getStroke();
|
||||
@@ -280,9 +280,9 @@ public class S1Switch extends AbstractTransparentComponent<Void> implements ISwi
|
||||
@Override
|
||||
public String getPositionName(int position) {
|
||||
if (position == 0) {
|
||||
return "Up";
|
||||
return "Down";
|
||||
}
|
||||
return "Down";
|
||||
return "Up";
|
||||
}
|
||||
|
||||
@EditableProperty(name = "Markers")
|
||||
|
||||
@@ -54,7 +54,7 @@ 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", autoEdit = false,
|
||||
zOrder = IDIYComponent.COMPONENT, instanceNamePrefix = "PKP",
|
||||
keywordPolicy = KeywordPolicy.SHOW_TAG, keywordTag = "Guitar Wiring Diagram", enableCache = true,
|
||||
transformer = GuitarPickupTransformer.class)
|
||||
public class SingleCoilPickup extends AbstractSingleOrHumbuckerPickup {
|
||||
|
||||
+1
-1
@@ -40,7 +40,7 @@ import java.awt.geom.*;
|
||||
|
||||
@ComponentDescriptor(name = "Stingray Bass Pickup", category = "Guitar", author = "JD",
|
||||
description = "Humbucker Bass Pickup for Musicman Stingray and similar guitars",
|
||||
zOrder = IDIYComponent.COMPONENT, instanceNamePrefix = "PKP", autoEdit = false,
|
||||
zOrder = IDIYComponent.COMPONENT, instanceNamePrefix = "PKP",
|
||||
keywordPolicy = KeywordPolicy.SHOW_TAG, keywordTag = "Guitar Wiring Diagram",
|
||||
enableCache = true, transformer = GuitarPickupTransformer.class)
|
||||
|
||||
|
||||
@@ -36,7 +36,7 @@ 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.SHOW_ALL_NAMES, autoEdit = false, transformer = SimpleComponentTransformer.class)
|
||||
bomPolicy = BomPolicy.SHOW_ALL_NAMES, transformer = SimpleComponentTransformer.class)
|
||||
public class Ellipse extends AbstractShapeWithDimensions {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@@ -40,7 +40,7 @@ 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.SHOW_ALL_NAMES, autoEdit = false,
|
||||
flexibleZOrder = true, bomPolicy = BomPolicy.SHOW_ALL_NAMES,
|
||||
transformer = SimpleComponentTransformer.class)
|
||||
public class Polygon extends AbstractShape {
|
||||
|
||||
|
||||
@@ -39,7 +39,7 @@ import org.diylc.core.measures.SizeUnit;
|
||||
|
||||
@ComponentDescriptor(name = "Rectangle", author = "Branislav Stojkovic", category = "Shapes",
|
||||
instanceNamePrefix = "RECT", description = "Ractangular area, with or withouth rounded edges",
|
||||
zOrder = IDIYComponent.COMPONENT, flexibleZOrder = true, bomPolicy = BomPolicy.SHOW_ALL_NAMES, autoEdit = false,
|
||||
zOrder = IDIYComponent.COMPONENT, flexibleZOrder = true, bomPolicy = BomPolicy.SHOW_ALL_NAMES,
|
||||
transformer = SimpleComponentTransformer.class)
|
||||
public class Rectangle extends AbstractShapeWithDimensions {
|
||||
|
||||
|
||||
@@ -53,7 +53,7 @@ import org.diylc.core.measures.SizeUnit;
|
||||
|
||||
@ComponentDescriptor(name = "Tape Measure", author = "Branislav Stojkovic", category = "Misc",
|
||||
creationMethod = CreationMethod.POINT_BY_POINT, instanceNamePrefix = "TM", description = "Measures distance between the two points",
|
||||
zOrder = IDIYComponent.COMPONENT, bomPolicy = BomPolicy.NEVER_SHOW, autoEdit = false,
|
||||
zOrder = IDIYComponent.COMPONENT, bomPolicy = BomPolicy.NEVER_SHOW,
|
||||
transformer = SimpleComponentTransformer.class)
|
||||
public class TapeMeasure extends AbstractLeadedComponent<String> {
|
||||
|
||||
|
||||
+5
-2
@@ -27,6 +27,7 @@ import java.awt.geom.Point2D;
|
||||
import org.diylc.common.IComponentTransformer;
|
||||
import org.diylc.common.OrientationHV;
|
||||
import org.diylc.components.electromechanical.MiniToggleSwitch;
|
||||
import org.diylc.components.electromechanical.ToggleSwitchType;
|
||||
import org.diylc.core.IDIYComponent;
|
||||
|
||||
public class MiniToggleSwitchTransformer implements IComponentTransformer {
|
||||
@@ -107,7 +108,8 @@ public class MiniToggleSwitchTransformer implements IComponentTransformer {
|
||||
MiniToggleSwitch sw = (MiniToggleSwitch) component;
|
||||
|
||||
if (direction == IComponentTransformer.HORIZONTAL) {
|
||||
double dx = 2 * (center.getX() - sw.getControlPoint(1).getX());
|
||||
double dx = 2 * (center.getX() -
|
||||
(sw.getControlPoint(0).getX() + sw.getControlPoint(sw.getControlPointCount() - 1).getX()) / 2);
|
||||
double dy = 0;
|
||||
|
||||
for (int i = 0; i < sw.getControlPointCount(); i++) {
|
||||
@@ -116,7 +118,8 @@ public class MiniToggleSwitchTransformer implements IComponentTransformer {
|
||||
}
|
||||
} else {
|
||||
double dx = 0;
|
||||
double dy = 2 * (center.getY() - sw.getControlPoint(1).getY());
|
||||
double dy = 2 * (center.getY() -
|
||||
(sw.getControlPoint(0).getY() + sw.getControlPoint(sw.getControlPointCount() - 1).getY()) / 2);
|
||||
|
||||
for (int i = 0; i < sw.getControlPointCount(); i++) {
|
||||
Point2D p = sw.getControlPoint(i);
|
||||
|
||||
@@ -28,6 +28,34 @@ public class LeverSwitchTests extends AbstractSwitchTests {
|
||||
leverSwitch.setValue(LeverSwitchType._4P5T);
|
||||
testSwitch(leverSwitch, validCombinations);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLeverSwitch6P5T() {
|
||||
LeverSwitch leverSwitch = new LeverSwitch();
|
||||
|
||||
String[] validCombinations = new String[] {
|
||||
"0,0,1", "0,6,11", "0,12,13", "0,18,23", "0,24,25", "0,30,35",
|
||||
"1,0,2", "1,7,11", "1,12,14", "1,19,23", "1,24,26", "1,31,35",
|
||||
"2,0,3", "2,8,11", "2,12,15", "2,20,23", "2,24,27", "2,32,35",
|
||||
"3,0,4", "3,9,11", "3,12,16", "3,21,23", "3,24,28", "3,33,35",
|
||||
"4,0,5", "4,10,11", "4,12,17", "4,22,23", "4,24,29", "4,34,35"
|
||||
};
|
||||
leverSwitch.setValue(LeverSwitchType._6P5T);
|
||||
testSwitch(leverSwitch, validCombinations);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLeverSwitch4P3T() {
|
||||
LeverSwitch leverSwitch = new LeverSwitch();
|
||||
|
||||
String[] validCombinations = new String[] {
|
||||
"0,0,1", "0,4,7", "0,8,9", "0,12,15",
|
||||
"1,0,2", "1,5,7", "1,8,10", "1,13,15",
|
||||
"2,0,3", "2,6,7", "2,8,11", "2,14,15",
|
||||
};
|
||||
leverSwitch.setValue(LeverSwitchType._4P3T);
|
||||
testSwitch(leverSwitch, validCombinations);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLeverSwitchImport() {
|
||||
@@ -50,4 +78,20 @@ public class LeverSwitchTests extends AbstractSwitchTests {
|
||||
leverSwitch.setValue(LeverSwitchType._6_WAY_OG);
|
||||
testSwitch(leverSwitch, validCombinations);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLeverSwitchImport2502N() {
|
||||
LeverSwitch leverSwitch = new LeverSwitch();
|
||||
|
||||
String[] validCombinations = new String[] {
|
||||
"0,0,3",
|
||||
"1,0,3", "1,1,3", "1,4,7", "1,5,7",
|
||||
"2,0,3", "2,2,3", "2,6,7",
|
||||
"3,1,3", "3,2,3", "3,5,7",
|
||||
"4,2,3", "4,6,7",
|
||||
};
|
||||
|
||||
leverSwitch.setValue(LeverSwitchType.DP3T_5pos_2502N);
|
||||
testSwitch(leverSwitch, validCombinations);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,24 +1,58 @@
|
||||
#!/bin/bash
|
||||
#set -x # Enable debug mode
|
||||
set -x # Enable debug mode
|
||||
|
||||
# Get the AppImage directory
|
||||
if [ -n "$APPDIR" ]; then
|
||||
HERE="$APPDIR/usr/bin"
|
||||
JRE_PATH="$APPDIR/usr/lib/jre/bin/java"
|
||||
JRE_DIR="$APPDIR/usr/lib/jre"
|
||||
else
|
||||
HERE="$(cd "$(dirname "$0")" && pwd)"
|
||||
JRE_PATH="$(dirname "$HERE")/lib/jre/bin/java"
|
||||
JRE_DIR="$(dirname "$HERE")/lib/jre"
|
||||
fi
|
||||
|
||||
echo "diylc.sh: Running from directory: $HERE"
|
||||
echo "diylc.sh: Looking for JRE at: $JRE_PATH"
|
||||
|
||||
# Use system Java
|
||||
JAVA="$(which java)"
|
||||
if [ -z "$JAVA" ] || [ ! -x "$JAVA" ]; then
|
||||
echo "diylc.sh: ERROR - System Java not found or not executable!"
|
||||
echo "diylc.sh: Please install Java 17 or later"
|
||||
# List directory contents for debugging
|
||||
echo "diylc.sh: Contents of $(dirname "$JRE_PATH"):"
|
||||
ls -la "$(dirname "$JRE_PATH")"
|
||||
|
||||
# Use bundled JRE
|
||||
if [ ! -f "$JRE_PATH" ]; then
|
||||
echo "diylc.sh: ERROR - Bundled JRE not found at: $JRE_PATH"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "diylc.sh: Using system Java: $JAVA"
|
||||
# Check if we're running from a mounted AppImage
|
||||
if [[ "$HERE" == /tmp/.mount_* ]]; then
|
||||
echo "diylc.sh: Running from mounted AppImage"
|
||||
# Create a temporary directory for the JRE
|
||||
TEMP_DIR="/tmp/diylc-jre-$$"
|
||||
mkdir -p "$TEMP_DIR"
|
||||
|
||||
# Copy the entire JRE directory to the temporary location
|
||||
echo "diylc.sh: Copying JRE to temporary location: $TEMP_DIR"
|
||||
cp -r "$JRE_DIR"/* "$TEMP_DIR/"
|
||||
chmod -R +x "$TEMP_DIR/bin"
|
||||
JRE_PATH="$TEMP_DIR/bin/java"
|
||||
|
||||
# Clean up the temporary directory on exit
|
||||
trap 'rm -rf "$TEMP_DIR"' EXIT
|
||||
fi
|
||||
|
||||
# Verify permissions
|
||||
echo "diylc.sh: Verifying JRE permissions..."
|
||||
ls -la "$JRE_PATH"
|
||||
|
||||
if [ ! -x "$JRE_PATH" ]; then
|
||||
echo "diylc.sh: ERROR - JRE is not executable at: $JRE_PATH"
|
||||
echo "diylc.sh: Current permissions: $(ls -l "$JRE_PATH")"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "diylc.sh: Using JRE: $JRE_PATH"
|
||||
|
||||
cd "$HERE"
|
||||
echo "diylc.sh: Current working directory: $(pwd)"
|
||||
@@ -26,15 +60,17 @@ echo "diylc.sh: Current working directory: $(pwd)"
|
||||
# Debug: Print command before execution
|
||||
echo "diylc.sh: Executing DIYLCStarter with Java"
|
||||
|
||||
exec "$JAVA" \
|
||||
-Xms1024m \
|
||||
-Xmx4096m \
|
||||
-cp "$APPDIR/usr/lib/diylc.jar" \
|
||||
--add-opens java.base/java.util=ALL-UNNAMED \
|
||||
--add-opens java.base/java.lang=ALL-UNNAMED \
|
||||
--add-opens java.base/java.text=ALL-UNNAMED \
|
||||
--add-opens java.desktop/java.awt=ALL-UNNAMED \
|
||||
--add-opens java.desktop/java.awt.font=ALL-UNNAMED \
|
||||
--add-opens java.desktop/java.awt.geom=ALL-UNNAMED \
|
||||
-Dorg.diylc.scriptRun=true \
|
||||
org.diylc.DIYLCStarter "$@"
|
||||
# Execute Java directly with the command array
|
||||
exec "$JRE_PATH" \
|
||||
-Xms1024m \
|
||||
-Xmx4096m \
|
||||
-cp "$(dirname "$HERE")/lib/diylc.jar" \
|
||||
--add-opens java.base/java.util=ALL-UNNAMED \
|
||||
--add-opens java.base/java.lang=ALL-UNNAMED \
|
||||
--add-opens java.base/java.text=ALL-UNNAMED \
|
||||
--add-opens java.desktop/java.awt=ALL-UNNAMED \
|
||||
--add-opens java.desktop/java.awt.font=ALL-UNNAMED \
|
||||
--add-opens java.desktop/java.awt.geom=ALL-UNNAMED \
|
||||
-Dorg.diylc.scriptRun=true \
|
||||
org.diylc.DIYLCStarter "$@"
|
||||
|
||||
|
||||
@@ -12,11 +12,11 @@ ChangesAssociations=yes
|
||||
AlwaysShowDirOnReadyPage=yes
|
||||
; Only allow the installer to run on x64-compatible systems,
|
||||
; and enable 64-bit install mode.
|
||||
ArchitecturesAllowed={#arch}
|
||||
ArchitecturesInstallIn64BitMode={#arch}
|
||||
ArchitecturesAllowed=x64compatible
|
||||
ArchitecturesInstallIn64BitMode=x64compatible
|
||||
|
||||
[Files]
|
||||
Source: "diylc-{#arch}.exe"; DestDir: "{app}"; DestName: "diylc.exe"
|
||||
Source: "diylc-x64.exe"; DestDir: "{app}"; DestName: "diylc.exe"
|
||||
Source: "..\..\src\main\resources\icons\diylc_file.ico"; DestDir: "{app}"
|
||||
Source: "..\..\target\diylc.jar"; DestDir: "{app}"
|
||||
Source: "..\..\target\jre_win\*"; DestDir: "{app}\jre17"; Flags: ignoreversion recursesubdirs
|
||||
|
||||
@@ -182,6 +182,7 @@ DP3T (Standard 5-Position Strat)
|
||||
DP4T (4-Position Tele)
|
||||
DP4T (6-Position Oak Grigsby)
|
||||
DP5T
|
||||
6P5T
|
||||
DPDT
|
||||
DPDT (On/Off/On)
|
||||
DPDT (On/On)
|
||||
|
||||
+64
-12
@@ -7,7 +7,7 @@
|
||||
<parent>
|
||||
<groupId>org.diylc</groupId>
|
||||
<artifactId>diylc-parent</artifactId>
|
||||
<version>5.4.0</version>
|
||||
<version>5.7.0</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>diylc-swing</artifactId>
|
||||
@@ -317,12 +317,49 @@
|
||||
</properties>
|
||||
<build>
|
||||
<plugins>
|
||||
<!-- Create AppDir structure and copy files -->
|
||||
<!-- Download and extract JRE -->
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-antrun-plugin</artifactId>
|
||||
<version>3.1.0</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>download-extract-jre</id>
|
||||
<phase>package</phase>
|
||||
<goals>
|
||||
<goal>run</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<target>
|
||||
<!-- Clean old jre folder -->
|
||||
<delete dir="${jre.dest.linux}" />
|
||||
|
||||
<!-- Create folder to hold extracted JRE -->
|
||||
<mkdir dir="${jre.dest.linux}" />
|
||||
|
||||
<!-- Download JRE for Linux -->
|
||||
<mkdir dir="${project.build.directory}/downloads" />
|
||||
<get src="${jdk.url.linux}"
|
||||
dest="${project.build.directory}/downloads/${jdk.archive.linux}"
|
||||
usetimestamp="true" />
|
||||
|
||||
<!-- Extract JRE -->
|
||||
<untar src="${project.build.directory}/downloads/${jdk.archive.linux}"
|
||||
dest="${jre.dest.linux}"
|
||||
compression="gzip" />
|
||||
|
||||
<!-- Move files up one level -->
|
||||
<move todir="${jre.dest.linux}">
|
||||
<fileset dir="${jre.dest.linux}/jdk-${jdk.version}-jre" />
|
||||
</move>
|
||||
|
||||
<!-- Remove empty top-level folder -->
|
||||
<delete dir="${jre.dest.linux}/jdk-${jdk.version}-jre" />
|
||||
</target>
|
||||
</configuration>
|
||||
</execution>
|
||||
|
||||
<!-- Create AppDir structure and copy files -->
|
||||
<execution>
|
||||
<id>create-appdir</id>
|
||||
<phase>package</phase>
|
||||
@@ -339,7 +376,22 @@
|
||||
|
||||
<!-- Copy app files -->
|
||||
<copy file="${project.build.directory}/diylc.jar" todir="${appdir.dir}/usr/lib" />
|
||||
|
||||
|
||||
<!-- Copy JRE -->
|
||||
<copy todir="${appdir.dir}/usr/lib/jre">
|
||||
<fileset dir="${jre.dest.linux}" />
|
||||
</copy>
|
||||
|
||||
<!-- Make JRE files executable -->
|
||||
<chmod perm="755">
|
||||
<fileset dir="${appdir.dir}/usr/lib/jre/bin" includes="**/*" />
|
||||
</chmod>
|
||||
|
||||
<!-- Ensure JRE binaries are executable in the source directory too -->
|
||||
<chmod perm="755">
|
||||
<fileset dir="${jre.dest.linux}/bin" includes="**/*" />
|
||||
</chmod>
|
||||
|
||||
<!-- Copy AppImage specific files -->
|
||||
<copy file="${project.basedir}/deploy/linux/appimage/diylc.sh" tofile="${appdir.dir}/usr/bin/diylc.sh" />
|
||||
<copy file="${project.basedir}/deploy/linux/appimage/AppRun" tofile="${appdir.dir}/AppRun" />
|
||||
@@ -581,7 +633,7 @@
|
||||
<argument>${project.basedir}:/workspace</argument>
|
||||
<argument>amake/innosetup</argument>
|
||||
<argument>/Ddiylcver=${project.version}</argument>
|
||||
<argument>/Darch=x64</argument>
|
||||
<!--<argument>/Darch=win64 arm64</argument>-->
|
||||
<argument>/workspace/deploy/win/install.iss</argument>
|
||||
</arguments>
|
||||
</configuration>
|
||||
@@ -839,11 +891,11 @@
|
||||
|
||||
<echo message="Creating unsigned zip for distribution..."/>
|
||||
<!-- Create unsigned zip for distribution -->
|
||||
<zip destfile="${project.build.directory}/diylc-${project.version}-osx-x86-unsigned.zip">
|
||||
<zip destfile="${project.build.directory}/diylc-${project.version}-osx-intel-unsigned.zip">
|
||||
<zipfileset filemode="755" dir="${project.build.directory}/DIYLC.app" prefix="DIYLC.app" />
|
||||
<zipfileset dir="${project.basedir}/deploy/mac" includes="README.txt" />
|
||||
</zip>
|
||||
<echo message="Unsigned zip created at: ${project.build.directory}/diylc-${project.version}-osx-x86-unsigned.zip"/>
|
||||
<echo message="Unsigned zip created at: ${project.build.directory}/diylc-${project.version}-osx-intel-unsigned.zip"/>
|
||||
|
||||
<!-- First remove existing signatures -->
|
||||
<echo message="Removing any existing signatures..."/>
|
||||
@@ -984,10 +1036,10 @@
|
||||
|
||||
<echo message="Creating final signed and notarized zip package..."/>
|
||||
<!-- Create final signed and notarized zip package -->
|
||||
<zip destfile="${project.build.directory}/diylc-${project.version}-osx-x86.zip">
|
||||
<zip destfile="${project.build.directory}/diylc-${project.version}-osx-intel.zip">
|
||||
<zipfileset filemode="755" dir="${project.build.directory}/DIYLC.app" prefix="DIYLC.app" />
|
||||
</zip>
|
||||
<echo message="Final package created at: ${project.build.directory}/diylc-${project.version}-osx-x86.zip"/>
|
||||
<echo message="Final package created at: ${project.build.directory}/diylc-${project.version}-osx-intel.zip"/>
|
||||
<echo message="Mac build process completed successfully!"/>
|
||||
</target>
|
||||
</configuration>
|
||||
@@ -1153,11 +1205,11 @@
|
||||
|
||||
<echo message="Creating unsigned zip for distribution..."/>
|
||||
<!-- Create unsigned zip for distribution -->
|
||||
<zip destfile="${project.build.directory}/diylc-${project.version}-osx-arm-unsigned.zip">
|
||||
<zip destfile="${project.build.directory}/diylc-${project.version}-osx-silicon-unsigned.zip">
|
||||
<zipfileset filemode="755" dir="${project.build.directory}/DIYLC.app" prefix="DIYLC.app" />
|
||||
<zipfileset dir="${project.basedir}/deploy/mac" includes="README.txt" />
|
||||
</zip>
|
||||
<echo message="Unsigned zip created at: ${project.build.directory}/diylc-${project.version}-osx-arm-unsigned.zip"/>
|
||||
<echo message="Unsigned zip created at: ${project.build.directory}/diylc-${project.version}-osx-silicon-unsigned.zip"/>
|
||||
|
||||
<!-- First remove existing signatures -->
|
||||
<echo message="Removing any existing signatures..."/>
|
||||
@@ -1298,10 +1350,10 @@
|
||||
|
||||
<echo message="Creating final signed and notarized zip package..."/>
|
||||
<!-- Create final signed and notarized zip package -->
|
||||
<zip destfile="${project.build.directory}/diylc-${project.version}-osx-arm.zip">
|
||||
<zip destfile="${project.build.directory}/diylc-${project.version}-osx-silicon.zip">
|
||||
<zipfileset filemode="755" dir="${project.build.directory}/DIYLC.app" prefix="DIYLC.app" />
|
||||
</zip>
|
||||
<echo message="Final package created at: ${project.build.directory}/diylc-${project.version}-osx-arm.zip"/>
|
||||
<echo message="Final package created at: ${project.build.directory}/diylc-${project.version}-osx-silicon.zip"/>
|
||||
<echo message="Mac build process completed successfully!"/>
|
||||
</target>
|
||||
</configuration>
|
||||
|
||||
@@ -33,6 +33,7 @@ import org.diylc.appframework.miscutils.PropertyInjector;
|
||||
import org.diylc.appframework.miscutils.Utils;
|
||||
import org.diylc.swingframework.export.DrawingExporter;
|
||||
import org.diylc.swingframework.fonts.FontOptimizer;
|
||||
import org.diylc.utils.ThemeUtils;
|
||||
import com.thoughtworks.xstream.XStream;
|
||||
import org.diylc.common.IPlugInPort;
|
||||
import org.diylc.core.IView;
|
||||
@@ -71,6 +72,9 @@ public class DIYLCStarter {
|
||||
}
|
||||
|
||||
public static void runDIYLC(String[] args) {
|
||||
// Apply OS dark theme settings before creating any UI components
|
||||
ThemeUtils.applyOSDarkTheme();
|
||||
|
||||
// Initialize splash screen
|
||||
DIYLCSplash splash = null;
|
||||
Exception splashException = null;
|
||||
@@ -137,6 +141,8 @@ public class DIYLCStarter {
|
||||
|
||||
try {
|
||||
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
|
||||
// Apply dark theme colors if dark mode is detected
|
||||
ThemeUtils.applyDarkThemeColors();
|
||||
} catch (Exception e) {
|
||||
LOG.error("Could not set Look&Feel", e);
|
||||
}
|
||||
|
||||
@@ -324,7 +324,7 @@ public class MainFrame extends JFrame implements ISwingUI {
|
||||
|
||||
@Override
|
||||
public void injectGUIComponent(JComponent component, int position, boolean collapsible, String visibilityConfigKey) throws BadPositionException {
|
||||
LOG.info(String.format("injectGUIComponent(%s, %s, %s, %s)", component.getClass().getName(), position, collapsible, visibilityConfigKey));
|
||||
// LOG.info(String.format("injectGUIComponent(%s, %s, %s, %s)", component.getClass().getName(), position, collapsible, visibilityConfigKey));
|
||||
if (collapsible) {
|
||||
CollapsiblePanel panel = new CollapsiblePanel(position, visibilityConfigKey);
|
||||
panel.add(component);
|
||||
@@ -354,8 +354,8 @@ public class MainFrame extends JFrame implements ISwingUI {
|
||||
|
||||
@Override
|
||||
public void injectMenuAction(Action action, String menuName) {
|
||||
LOG.info(String.format("injectMenuAction(%s, %s)", action == null ? "Separator" : action.getValue(Action.NAME),
|
||||
menuName));
|
||||
// LOG.info(String.format("injectMenuAction(%s, %s)", action == null ? "Separator" : action.getValue(Action.NAME),
|
||||
// menuName));
|
||||
if (menuName != null)
|
||||
menuName = LangUtil.translate(menuName);
|
||||
|
||||
|
||||
+43
-14
@@ -55,6 +55,21 @@ public class ActionBarPlugin implements IPlugIn {
|
||||
|
||||
private static final Logger LOG = Logger.getLogger(ActionBarPlugin.class);
|
||||
|
||||
private static final SupportOption[] SUPPORT_OPTIONS = new SupportOption[] {
|
||||
new SupportOption(
|
||||
"Enjoying DIYLC? Click here to buy me a coffee :)",
|
||||
"Donate",
|
||||
IconLoader.Donate,
|
||||
HelpMenuPlugin.DONATE_URL
|
||||
),
|
||||
new SupportOption(
|
||||
"Become a Patreon and enjoy perks",
|
||||
"Join Patreon",
|
||||
IconLoader.Patreon,
|
||||
HelpMenuPlugin.PATREON_URL
|
||||
)
|
||||
};
|
||||
|
||||
private IPlugInPort plugInPort;
|
||||
private ISwingUI swingUI;
|
||||
|
||||
@@ -62,13 +77,12 @@ public class ActionBarPlugin implements IPlugIn {
|
||||
private ActionToolbar contextActionToolbar;
|
||||
private ConfigToolbar configToolbar;
|
||||
private JLabel donateLabel;
|
||||
|
||||
private static final String DONATE_HTML = LangUtil.translate("Enjoying DIYLC? Click here to buy me a coffee :)");
|
||||
private static final String DONATE_HTML_SHORT = LangUtil.translate("Donate");
|
||||
private SupportOption selectedOption;
|
||||
private Consumer<Boolean> highlightConnectedAreasUpdateAction;
|
||||
|
||||
public ActionBarPlugin(ISwingUI swingUI) {
|
||||
this.swingUI = swingUI;
|
||||
this.selectedOption = SUPPORT_OPTIONS[(int)(Math.random() * SUPPORT_OPTIONS.length)];
|
||||
}
|
||||
|
||||
public JPanel getActionPanel() {
|
||||
@@ -110,12 +124,9 @@ public class ActionBarPlugin implements IPlugIn {
|
||||
|
||||
public JLabel getDonateLabel() {
|
||||
if (donateLabel == null) {
|
||||
donateLabel = new JLabel(DONATE_HTML);
|
||||
// Map<TextAttribute, Integer> fontAttributes = new HashMap<TextAttribute, Integer>();
|
||||
// fontAttributes.put(TextAttribute.UNDERLINE, TextAttribute.UNDERLINE_ON);
|
||||
// donateLabel.setFont(donateLabel.getFont().deriveFont(fontAttributes));
|
||||
donateLabel = new JLabel(selectedOption.longText);
|
||||
donateLabel.setForeground(Color.blue);
|
||||
donateLabel.setIcon(IconLoader.Donate.getIcon());
|
||||
donateLabel.setIcon(selectedOption.icon.getIcon());
|
||||
donateLabel.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
|
||||
this.swingUI.getOwnerFrame().addComponentListener(new ComponentAdapter() {
|
||||
|
||||
@@ -126,11 +137,15 @@ public class ActionBarPlugin implements IPlugIn {
|
||||
@Override
|
||||
public void componentResized(ComponentEvent e) {
|
||||
if (rootPane.getWidth() < 940) {
|
||||
if (!DONATE_HTML_SHORT.equals(donateLabel.getText()))
|
||||
donateLabel.setText(DONATE_HTML_SHORT);
|
||||
if (!selectedOption.shortText.equals(donateLabel.getText())) {
|
||||
donateLabel.setText(selectedOption.shortText);
|
||||
donateLabel.setIcon(selectedOption.icon.getIcon());
|
||||
}
|
||||
} else {
|
||||
if (!DONATE_HTML.equals(donateLabel.getText()))
|
||||
donateLabel.setText(DONATE_HTML);
|
||||
if (!selectedOption.longText.equals(donateLabel.getText())) {
|
||||
donateLabel.setText(selectedOption.longText);
|
||||
donateLabel.setIcon(selectedOption.icon.getIcon());
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -140,9 +155,11 @@ public class ActionBarPlugin implements IPlugIn {
|
||||
@Override
|
||||
public void mouseClicked(MouseEvent e) {
|
||||
try {
|
||||
Utils.openURL(HelpMenuPlugin.DONATE_URL);
|
||||
Utils.openURL(selectedOption.url);
|
||||
} catch (Exception e1) {
|
||||
swingUI.showMessage("Web browser launching failed. Please visit " + HelpMenuPlugin.DONATE_URL + " to donate. Thank you!", "Error", ISwingUI.INFORMATION_MESSAGE);
|
||||
swingUI.showMessage("Web browser launching failed. Please visit " +
|
||||
selectedOption.url +
|
||||
" to support DIYLC. Thank you!", "Error", ISwingUI.INFORMATION_MESSAGE);
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -225,4 +242,16 @@ public class ActionBarPlugin implements IPlugIn {
|
||||
OperationMode.HIGHLIGHT_CONNECTED_AREAS);
|
||||
}
|
||||
}
|
||||
|
||||
private record SupportOption(
|
||||
String longText,
|
||||
String shortText,
|
||||
IconLoader icon,
|
||||
String url
|
||||
) {
|
||||
public SupportOption {
|
||||
longText = LangUtil.translate(longText);
|
||||
shortText = LangUtil.translate(shortText);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -45,7 +45,7 @@ public class AutoSavePlugin implements IPlugIn {
|
||||
private static final Logger LOG = Logger.getLogger(AutoSavePlugin.class);
|
||||
|
||||
public static long BACKUP_FREQ_MS = 60 * 1000;
|
||||
public static int MAX_TOTAL_SIZE_MB = 64;
|
||||
public static int MAX_TOTAL_SIZE_MB = 1024;
|
||||
|
||||
private ExecutorService executor;
|
||||
|
||||
|
||||
@@ -146,42 +146,35 @@ public class CanvasPanel extends JComponent implements Autoscroll {
|
||||
}
|
||||
|
||||
private void initializeActions() {
|
||||
getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW)
|
||||
getInputMap(JComponent.WHEN_FOCUSED)
|
||||
.put(KeyStroke.getKeyStroke(KeyEvent.VK_BACK_QUOTE, 0), "repeatLast");
|
||||
|
||||
getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW)
|
||||
getInputMap(JComponent.WHEN_FOCUSED)
|
||||
.put(KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), "clearSlot");
|
||||
|
||||
getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW)
|
||||
.put(KeyStroke.getKeyStroke(KeyEvent.VK_ADD, KeyEvent.CTRL_DOWN_MASK), "zoomIn");
|
||||
getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW)
|
||||
.put(KeyStroke.getKeyStroke(KeyEvent.VK_PLUS, KeyEvent.CTRL_DOWN_MASK), "zoomIn");
|
||||
getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW)
|
||||
.put(KeyStroke.getKeyStroke(KeyEvent.VK_ADD, KeyEvent.META_DOWN_MASK), "zoomIn");
|
||||
getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW)
|
||||
.put(KeyStroke.getKeyStroke(KeyEvent.VK_EQUALS, KeyEvent.CTRL_DOWN_MASK), "zoomIn");
|
||||
getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW)
|
||||
.put(KeyStroke.getKeyStroke(KeyEvent.VK_EQUALS, KeyEvent.META_DOWN_MASK), "zoomIn");
|
||||
getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW)
|
||||
.put(KeyStroke.getKeyStroke(KeyEvent.VK_PLUS, KeyEvent.META_DOWN_MASK), "zoomIn");
|
||||
getInputMap(JComponent.WHEN_FOCUSED)
|
||||
.put(KeyStroke.getKeyStroke(KeyEvent.VK_ADD, 0), "zoomIn");
|
||||
getInputMap(JComponent.WHEN_FOCUSED)
|
||||
.put(KeyStroke.getKeyStroke(KeyEvent.VK_PLUS, 0), "zoomIn");
|
||||
|
||||
getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW)
|
||||
.put(KeyStroke.getKeyStroke(KeyEvent.VK_SUBTRACT, KeyEvent.CTRL_DOWN_MASK), "zoomOut");
|
||||
getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW)
|
||||
.put(KeyStroke.getKeyStroke(KeyEvent.VK_MINUS, KeyEvent.CTRL_DOWN_MASK), "zoomOut");
|
||||
getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW)
|
||||
.put(KeyStroke.getKeyStroke(KeyEvent.VK_SUBTRACT, KeyEvent.META_DOWN_MASK), "zoomOut");
|
||||
getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW)
|
||||
.put(KeyStroke.getKeyStroke(KeyEvent.VK_MINUS, KeyEvent.META_DOWN_MASK), "zoomOut");
|
||||
getInputMap(JComponent.WHEN_FOCUSED)
|
||||
.put(KeyStroke.getKeyStroke(KeyEvent.VK_EQUALS, 0), "zoomIn");
|
||||
getInputMap(JComponent.WHEN_FOCUSED)
|
||||
.put(KeyStroke.getKeyStroke(KeyEvent.VK_EQUALS, 0), "zoomIn");
|
||||
|
||||
getInputMap(JComponent.WHEN_FOCUSED)
|
||||
.put(KeyStroke.getKeyStroke(KeyEvent.VK_SUBTRACT, 0), "zoomOut");
|
||||
getInputMap(JComponent.WHEN_FOCUSED)
|
||||
.put(KeyStroke.getKeyStroke(KeyEvent.VK_MINUS, 0), "zoomOut");
|
||||
|
||||
getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW)
|
||||
.put(KeyStroke.getKeyStroke(KeyEvent.VK_0, KeyEvent.CTRL_DOWN_MASK), "resetZoom");
|
||||
getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW)
|
||||
.put(KeyStroke.getKeyStroke(KeyEvent.VK_NUMPAD0, KeyEvent.CTRL_DOWN_MASK), "resetZoom");
|
||||
getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW)
|
||||
.put(KeyStroke.getKeyStroke(KeyEvent.VK_0, KeyEvent.META_DOWN_MASK), "resetZoom");
|
||||
getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW)
|
||||
.put(KeyStroke.getKeyStroke(KeyEvent.VK_NUMPAD0, KeyEvent.META_DOWN_MASK), "resetZoom");
|
||||
getInputMap(JComponent.WHEN_FOCUSED)
|
||||
.put(KeyStroke.getKeyStroke(KeyEvent.VK_0, 0), "resetZoom");
|
||||
getInputMap(JComponent.WHEN_FOCUSED)
|
||||
.put(KeyStroke.getKeyStroke(KeyEvent.VK_NUMPAD0, 0), "resetZoom");
|
||||
getInputMap(JComponent.WHEN_FOCUSED)
|
||||
.put(KeyStroke.getKeyStroke(KeyEvent.VK_0, 0), "resetZoom");
|
||||
getInputMap(JComponent.WHEN_FOCUSED)
|
||||
.put(KeyStroke.getKeyStroke(KeyEvent.VK_NUMPAD0, 0), "resetZoom");
|
||||
|
||||
for (int i = 1; i <= 12; i++) {
|
||||
final int x = i;
|
||||
@@ -198,36 +191,6 @@ public class CanvasPanel extends JComponent implements Autoscroll {
|
||||
});
|
||||
}
|
||||
|
||||
// getActionMap().put("zoomIn", new AbstractAction() {
|
||||
//
|
||||
// private static final long serialVersionUID = 1L;
|
||||
//
|
||||
// @Override
|
||||
// public void actionPerformed(ActionEvent e) {
|
||||
// LOG.debug("Keyboard zoom-in triggered");
|
||||
// double oldZoom = CanvasPanel.this.plugInPort.getZoomLevel();
|
||||
// Double[] availableZoomLevels = CanvasPanel.this.plugInPort.getAvailableZoomLevels();
|
||||
// int index = Arrays.binarySearch(availableZoomLevels, oldZoom);
|
||||
// if (index < availableZoomLevels.length - 1)
|
||||
// CanvasPanel.this.plugInPort.setZoomLevel(availableZoomLevels[index + 1]);
|
||||
// }
|
||||
// });
|
||||
//
|
||||
// getActionMap().put("zoomOut", new AbstractAction() {
|
||||
//
|
||||
// private static final long serialVersionUID = 1L;
|
||||
//
|
||||
// @Override
|
||||
// public void actionPerformed(ActionEvent e) {
|
||||
// LOG.debug("Keyboard zoom-out triggered");
|
||||
// double oldZoom = CanvasPanel.this.plugInPort.getZoomLevel();
|
||||
// Double[] availableZoomLevels = CanvasPanel.this.plugInPort.getAvailableZoomLevels();
|
||||
// int index = Arrays.binarySearch(availableZoomLevels, oldZoom);
|
||||
// if (index > 0)
|
||||
// CanvasPanel.this.plugInPort.setZoomLevel(availableZoomLevels[index - 1]);
|
||||
// }
|
||||
// });
|
||||
|
||||
getActionMap().put("resetZoom", new AbstractAction() {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@@ -104,6 +104,7 @@ public class CloudPlugIn implements IPlugIn {
|
||||
getManageAccountAction().setEnabled(false);
|
||||
getChangePasswordAction().setEnabled(false);
|
||||
getLogOutAction().setEnabled(false);
|
||||
getConnectPatreonAction().setEnabled(false);
|
||||
}
|
||||
|
||||
public CloudBrowserFrame getCloudBrowser() {
|
||||
@@ -179,6 +180,7 @@ public class CloudPlugIn implements IPlugIn {
|
||||
getUploadAction().setEnabled(true);
|
||||
getManageProjectsAction().setEnabled(true);
|
||||
getChangePasswordAction().setEnabled(true);
|
||||
getConnectPatreonAction().setEnabled(true);
|
||||
}
|
||||
|
||||
public void loggedOut() {
|
||||
@@ -190,6 +192,7 @@ public class CloudPlugIn implements IPlugIn {
|
||||
getUploadAction().setEnabled(false);
|
||||
getManageProjectsAction().setEnabled(false);
|
||||
getChangePasswordAction().setEnabled(false);
|
||||
getConnectPatreonAction().setEnabled(false);
|
||||
}
|
||||
|
||||
// Getters for action classes
|
||||
|
||||
-1
@@ -60,7 +60,6 @@ public class ConnectPatreonAction extends AbstractAction {
|
||||
return;
|
||||
}
|
||||
String username = plugInPort.getCloudService().getCurrentUsername();
|
||||
username ="a b c";
|
||||
String url = "http://diy-fever.com/diylc/api/v1/ai/patreon_login.php?username=" + URLEncoder.encode(username, StandardCharsets.UTF_8);
|
||||
try {
|
||||
java.awt.Desktop.getDesktop().browse(new java.net.URI(url));
|
||||
|
||||
+58
-9
@@ -37,6 +37,7 @@ import javax.swing.JTextArea;
|
||||
import javax.swing.JTextField;
|
||||
import javax.swing.event.DocumentEvent;
|
||||
import javax.swing.event.DocumentListener;
|
||||
import javax.swing.UIManager;
|
||||
|
||||
import org.diylc.swingframework.ButtonDialog;
|
||||
|
||||
@@ -47,6 +48,14 @@ public class UserEditDialog extends ButtonDialog {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private static final String BULLET = " • ";
|
||||
private static final String PASSWORD_RULES_HTML = "<html>" + BULLET
|
||||
+ "Password must be at least 8 characters long<br>" + BULLET
|
||||
+ "Password must contain at least one letter<br>" + BULLET
|
||||
+ "Password must contain at least one number<br>" + BULLET
|
||||
+ "Passwords must match exactly<br>"
|
||||
+ "</html>";
|
||||
|
||||
private JPanel mainPanel;
|
||||
|
||||
private JTextField userNameField;
|
||||
@@ -65,6 +74,8 @@ public class UserEditDialog extends ButtonDialog {
|
||||
|
||||
private UserEntity existingEntity;
|
||||
|
||||
private JLabel passwordRulesLabel;
|
||||
|
||||
public UserEditDialog(JFrame owner, UserEntity existingEntity) {
|
||||
super(owner, existingEntity == null ? "New Account" : "Manage Account", new String[] {OK, CANCEL});
|
||||
|
||||
@@ -117,16 +128,33 @@ public class UserEditDialog extends ButtonDialog {
|
||||
|
||||
gbc.gridy = 2;
|
||||
mainPanel.add(new JLabel("Confirm Password:"), gbc);
|
||||
|
||||
// Add password rules hint pane
|
||||
gbc.gridy = 3;
|
||||
gbc.gridwidth = 2;
|
||||
gbc.gridx = 0;
|
||||
gbc.fill = GridBagConstraints.HORIZONTAL;
|
||||
gbc.insets = new Insets(4, 2, 4, 2); // Add more vertical padding
|
||||
mainPanel.add(getPasswordRulesLabel(), gbc);
|
||||
|
||||
// Reset gridwidth and gridx for remaining fields
|
||||
gbc.gridwidth = 1;
|
||||
gbc.gridx = 1;
|
||||
gbc.insets = new Insets(2, 2, 2, 2); // Reset insets
|
||||
gbc.gridy = 4;
|
||||
}
|
||||
|
||||
gbc.gridy = 3;
|
||||
gbc.gridy = existingEntity == null ? 4 : 3;
|
||||
gbc.gridx = 0;
|
||||
mainPanel.add(new JLabel("eMail:"), gbc);
|
||||
|
||||
gbc.gridy = 4;
|
||||
mainPanel.add(new JLabel("Website:"), gbc);
|
||||
gbc.gridy = existingEntity == null ? 5 : 4;
|
||||
gbc.gridx = 0;
|
||||
mainPanel.add(new JLabel("Website (optional):"), gbc);
|
||||
|
||||
gbc.gridy = 5;
|
||||
mainPanel.add(new JLabel("Short Bio:"), gbc);
|
||||
gbc.gridy = existingEntity == null ? 6 : 5;
|
||||
gbc.gridx = 0;
|
||||
mainPanel.add(new JLabel("Short Bio (optional):"), gbc);
|
||||
|
||||
gbc.gridx = 1;
|
||||
gbc.fill = GridBagConstraints.HORIZONTAL;
|
||||
@@ -144,13 +172,13 @@ public class UserEditDialog extends ButtonDialog {
|
||||
mainPanel.add(getConfirmPasswordField(), gbc);
|
||||
}
|
||||
|
||||
gbc.gridy = 3;
|
||||
gbc.gridy = existingEntity == null ? 4 : 3;
|
||||
mainPanel.add(getEmailField(), gbc);
|
||||
|
||||
gbc.gridy = 4;
|
||||
gbc.gridy = existingEntity == null ? 5 : 4;
|
||||
mainPanel.add(getWebsiteField(), gbc);
|
||||
|
||||
gbc.gridy = 5;
|
||||
gbc.gridy = existingEntity == null ? 6 : 5;
|
||||
gbc.fill = GridBagConstraints.BOTH;
|
||||
mainPanel.add(getBioPane(), gbc);
|
||||
}
|
||||
@@ -161,7 +189,16 @@ public class UserEditDialog extends ButtonDialog {
|
||||
this.userName = getUserNameField().getText();
|
||||
String password = new String(getPasswordField().getPassword());
|
||||
String confirmPassword = new String(getConfirmPasswordField().getPassword());
|
||||
if (password.equals(confirmPassword)) {
|
||||
|
||||
// Password validation
|
||||
boolean hasValidPassword = true;
|
||||
if (existingEntity == null) {
|
||||
hasValidPassword = password.length() >= 8 &&
|
||||
password.matches(".*[a-zA-Z].*") && // at least one letter
|
||||
password.matches(".*\\d.*"); // at least one number
|
||||
}
|
||||
|
||||
if (password.equals(confirmPassword) && hasValidPassword) {
|
||||
this.password = password;
|
||||
} else {
|
||||
this.password = null;
|
||||
@@ -342,4 +379,16 @@ public class UserEditDialog extends ButtonDialog {
|
||||
}
|
||||
return bioArea;
|
||||
}
|
||||
|
||||
private JLabel getPasswordRulesLabel() {
|
||||
if (passwordRulesLabel == null) {
|
||||
passwordRulesLabel = new JLabel();
|
||||
passwordRulesLabel.setOpaque(true);
|
||||
passwordRulesLabel.setBackground(UIManager.getColor("ToolTip.background"));
|
||||
passwordRulesLabel.setBorder(BorderFactory.createCompoundBorder(BorderFactory.createEtchedBorder(),
|
||||
BorderFactory.createEmptyBorder(2, 2, 2, 2)));
|
||||
passwordRulesLabel.setText(PASSWORD_RULES_HTML);
|
||||
}
|
||||
return passwordRulesLabel;
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -81,7 +81,7 @@ public class CloudBrowserFrame extends JFrame implements ISimpleView {
|
||||
super(TITLE);
|
||||
this.swingUI = swingUI;
|
||||
this.setIconImage(IconLoader.Cloud.getImage());
|
||||
this.setPreferredSize(new Dimension(700, 640));
|
||||
this.setPreferredSize(new Dimension(800, 640));
|
||||
this.plugInPort = plugInPort;
|
||||
this.searchSession = new SearchSession(plugInPort);
|
||||
|
||||
|
||||
@@ -63,10 +63,11 @@ public class HelpMenuPlugin implements IPlugIn {
|
||||
public static String PLUGIN_URL = "https://github.com/bancika/diy-layout-creator/blob/wiki/PluginAPI.md";
|
||||
public static String BUG_URL = "https://github.com/bancika/diy-layout-creator/issues";
|
||||
public static String DONATE_URL = "http://diy-fever.com/donate";
|
||||
public static String PATREON_URL = "http://diy-fever.com/patreon";
|
||||
|
||||
private IPlugInPort plugInPort;
|
||||
private AboutDialog aboutDialog;
|
||||
private ISwingUI swingUI;
|
||||
private final ISwingUI swingUI;
|
||||
|
||||
public HelpMenuPlugin(ISwingUI swingUI) {
|
||||
this.swingUI = swingUI;
|
||||
|
||||
@@ -0,0 +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
|
||||
* <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.diylc.utils;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.io.BufferedReader;
|
||||
import java.io.InputStreamReader;
|
||||
import javax.swing.UIManager;
|
||||
import org.apache.log4j.Logger;
|
||||
import org.diylc.appframework.miscutils.Utils;
|
||||
|
||||
/**
|
||||
* Utility class for detecting and applying OS dark theme settings.
|
||||
*
|
||||
* Note: Modern Java (11+) with system Look and Feel should automatically
|
||||
* respect OS dark theme settings, but this utility provides explicit detection
|
||||
* and ensures compatibility with older Java versions.
|
||||
*
|
||||
* @author Branislav Stojkovic
|
||||
*/
|
||||
public class ThemeUtils {
|
||||
|
||||
private static final Logger LOG = Logger.getLogger(ThemeUtils.class);
|
||||
|
||||
/**
|
||||
* Detects and applies OS dark theme settings.
|
||||
* This must be called before creating any AWT/Swing components.
|
||||
*/
|
||||
public static void applyOSDarkTheme() {
|
||||
try {
|
||||
if (Utils.isMac()) {
|
||||
applyMacOSDarkTheme();
|
||||
} else if (Utils.isWindows()) {
|
||||
detectWindowsDarkTheme();
|
||||
} else {
|
||||
detectLinuxDarkTheme();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
LOG.warn("Error detecting OS dark theme: " + e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies dark theme colors to UIManager after the Look and Feel is set.
|
||||
* This should be called after UIManager.setLookAndFeel().
|
||||
*
|
||||
* @return true if dark mode was detected and colors were applied, false otherwise
|
||||
*/
|
||||
public static boolean applyDarkThemeColors() {
|
||||
try {
|
||||
if (Utils.isMac()) {
|
||||
return applyMacOSDarkThemeColors();
|
||||
} else if (Utils.isWindows()) {
|
||||
return applyWindowsDarkThemeColors();
|
||||
} else {
|
||||
return applyLinuxDarkThemeColors();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
LOG.warn("Error applying dark theme colors: " + e.getMessage(), e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Detects and applies macOS dark theme settings.
|
||||
*/
|
||||
private static void applyMacOSDarkTheme() {
|
||||
// macOS: Check if dark mode is enabled
|
||||
// Modern Java (11+) should automatically detect this, but we'll check explicitly
|
||||
String appearance = System.getProperty("apple.awt.application.appearance");
|
||||
if (appearance == null) {
|
||||
// Try to detect dark mode via system command (for older Java versions)
|
||||
try {
|
||||
Process process = Runtime.getRuntime().exec(
|
||||
new String[]{"defaults", "read", "-g", "AppleInterfaceStyle"});
|
||||
BufferedReader reader = new BufferedReader(
|
||||
new InputStreamReader(process.getInputStream()));
|
||||
String result = reader.readLine();
|
||||
if ("Dark".equals(result)) {
|
||||
// Note: Setting this property after JVM start may not always work,
|
||||
// but it's worth trying for older Java versions
|
||||
System.setProperty("apple.awt.application.appearance", "NSAppearanceNameDarkAqua");
|
||||
LOG.info("Detected macOS dark mode - attempting to apply dark theme");
|
||||
} else {
|
||||
LOG.debug("macOS light mode detected");
|
||||
}
|
||||
} catch (Exception e) {
|
||||
// If detection fails, that's okay - modern Java will handle it automatically
|
||||
LOG.debug("Could not detect macOS theme via defaults command: " + e.getMessage());
|
||||
}
|
||||
} else if ("NSAppearanceNameDarkAqua".equals(appearance)) {
|
||||
LOG.info("macOS dark mode already detected by JVM");
|
||||
} else {
|
||||
LOG.debug("macOS appearance: " + appearance);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Detects Windows dark theme settings.
|
||||
*/
|
||||
private static void detectWindowsDarkTheme() {
|
||||
// Windows: Try to detect dark theme via registry
|
||||
try {
|
||||
Process process = Runtime.getRuntime().exec(
|
||||
new String[]{"reg", "query",
|
||||
"HKCU\\Software\\Microsoft\\Windows\\CurrentVersion\\Themes\\Personalize",
|
||||
"/v", "AppsUseLightTheme"});
|
||||
BufferedReader reader = new BufferedReader(
|
||||
new InputStreamReader(process.getInputStream()));
|
||||
String line;
|
||||
while ((line = reader.readLine()) != null) {
|
||||
if (line.contains("AppsUseLightTheme")) {
|
||||
// If value is 0, dark theme is enabled
|
||||
if (line.contains("0x0") || line.endsWith("0")) {
|
||||
// For Windows, the system Look and Feel should automatically respect dark mode
|
||||
// in Java 11+, but we can log it for debugging
|
||||
LOG.info("Detected Windows dark mode");
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
LOG.debug("Could not detect Windows theme via registry: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Detects Linux dark theme settings.
|
||||
*/
|
||||
private static void detectLinuxDarkTheme() {
|
||||
// Linux: Check GTK theme or environment variables
|
||||
try {
|
||||
String gtkTheme = System.getenv("GTK_THEME");
|
||||
if (gtkTheme != null && (gtkTheme.toLowerCase().contains("dark") ||
|
||||
gtkTheme.toLowerCase().contains("Dark"))) {
|
||||
LOG.info("Detected Linux dark theme: " + gtkTheme);
|
||||
}
|
||||
// Also check COLORFGBG environment variable (used by some terminals/desktops)
|
||||
String colorFgBg = System.getenv("COLORFGBG");
|
||||
if (colorFgBg != null) {
|
||||
// Format is typically "15;0" where second number < 8 indicates dark background
|
||||
String[] parts = colorFgBg.split(";");
|
||||
if (parts.length > 1) {
|
||||
try {
|
||||
int bgColor = Integer.parseInt(parts[parts.length - 1]);
|
||||
if (bgColor < 8) {
|
||||
LOG.info("Detected Linux dark background via COLORFGBG");
|
||||
}
|
||||
} catch (NumberFormatException e) {
|
||||
// Ignore
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
LOG.debug("Could not detect Linux theme: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies macOS dark theme colors to UIManager.
|
||||
* @return true if dark mode is active
|
||||
*/
|
||||
private static boolean applyMacOSDarkThemeColors() {
|
||||
boolean isDarkMode = false;
|
||||
|
||||
// Check if dark mode is active
|
||||
String appearance = System.getProperty("apple.awt.application.appearance");
|
||||
if (appearance == null) {
|
||||
try {
|
||||
Process process = Runtime.getRuntime().exec(
|
||||
new String[]{"defaults", "read", "-g", "AppleInterfaceStyle"});
|
||||
BufferedReader reader = new BufferedReader(
|
||||
new InputStreamReader(process.getInputStream()));
|
||||
String result = reader.readLine();
|
||||
isDarkMode = "Dark".equals(result);
|
||||
} catch (Exception e) {
|
||||
LOG.debug("Could not detect macOS theme: " + e.getMessage());
|
||||
// Try to infer from current UI colors
|
||||
Color menuBarBg = UIManager.getColor("MenuBar.background");
|
||||
if (menuBarBg != null && isDarkColor(menuBarBg)) {
|
||||
isDarkMode = true;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
isDarkMode = "NSAppearanceNameDarkAqua".equals(appearance);
|
||||
}
|
||||
|
||||
if (isDarkMode) {
|
||||
LOG.info("Applying macOS dark theme colors");
|
||||
applyDarkColors();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies Windows dark theme colors to UIManager.
|
||||
* @return true if dark mode is active
|
||||
*/
|
||||
private static boolean applyWindowsDarkThemeColors() {
|
||||
boolean isDarkMode = false;
|
||||
|
||||
try {
|
||||
Process process = Runtime.getRuntime().exec(
|
||||
new String[]{"reg", "query",
|
||||
"HKCU\\Software\\Microsoft\\Windows\\CurrentVersion\\Themes\\Personalize",
|
||||
"/v", "AppsUseLightTheme"});
|
||||
BufferedReader reader = new BufferedReader(
|
||||
new InputStreamReader(process.getInputStream()));
|
||||
String line;
|
||||
while ((line = reader.readLine()) != null) {
|
||||
if (line.contains("AppsUseLightTheme")) {
|
||||
// If value is 0, dark theme is enabled
|
||||
if (line.contains("0x0") || line.endsWith("0")) {
|
||||
isDarkMode = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
LOG.debug("Could not detect Windows theme: " + e.getMessage());
|
||||
// Try to infer from current UI colors
|
||||
Color menuBarBg = UIManager.getColor("MenuBar.background");
|
||||
if (menuBarBg != null && isDarkColor(menuBarBg)) {
|
||||
isDarkMode = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (isDarkMode) {
|
||||
LOG.info("Applying Windows dark theme colors");
|
||||
applyDarkColors();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies Linux dark theme colors to UIManager.
|
||||
* @return true if dark mode is active
|
||||
*/
|
||||
private static boolean applyLinuxDarkThemeColors() {
|
||||
boolean isDarkMode = false;
|
||||
|
||||
try {
|
||||
String gtkTheme = System.getenv("GTK_THEME");
|
||||
if (gtkTheme != null && (gtkTheme.toLowerCase().contains("dark") ||
|
||||
gtkTheme.toLowerCase().contains("Dark"))) {
|
||||
isDarkMode = true;
|
||||
}
|
||||
|
||||
// Also check COLORFGBG
|
||||
if (!isDarkMode) {
|
||||
String colorFgBg = System.getenv("COLORFGBG");
|
||||
if (colorFgBg != null) {
|
||||
String[] parts = colorFgBg.split(";");
|
||||
if (parts.length > 1) {
|
||||
try {
|
||||
int bgColor = Integer.parseInt(parts[parts.length - 1]);
|
||||
if (bgColor < 8) {
|
||||
isDarkMode = true;
|
||||
}
|
||||
} catch (NumberFormatException e) {
|
||||
// Ignore
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Try to infer from current UI colors
|
||||
if (!isDarkMode) {
|
||||
Color menuBarBg = UIManager.getColor("MenuBar.background");
|
||||
if (menuBarBg != null && isDarkColor(menuBarBg)) {
|
||||
isDarkMode = true;
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
LOG.debug("Could not detect Linux theme: " + e.getMessage());
|
||||
}
|
||||
|
||||
if (isDarkMode) {
|
||||
LOG.info("Applying Linux dark theme colors");
|
||||
applyDarkColors();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies dark theme colors to common UI components.
|
||||
* Only overrides colors that would cause visibility issues (e.g., dark text on dark background).
|
||||
*/
|
||||
private static void applyDarkColors() {
|
||||
// Menu bar and menu colors - fix text colors if background is dark
|
||||
Color menuBarBg = UIManager.getColor("MenuBar.background");
|
||||
Color menuBarFg = UIManager.getColor("MenuBar.foreground");
|
||||
|
||||
if (menuBarBg != null && isDarkColor(menuBarBg)) {
|
||||
// Background is dark, ensure text is light
|
||||
if (menuBarFg == null || isDarkColor(menuBarFg)) {
|
||||
UIManager.put("MenuBar.foreground", Color.WHITE);
|
||||
}
|
||||
|
||||
// Fix menu colors
|
||||
Color menuBg = UIManager.getColor("Menu.background");
|
||||
Color menuFg = UIManager.getColor("Menu.foreground");
|
||||
if (menuBg == null || isDarkColor(menuBg)) {
|
||||
UIManager.put("Menu.background", new Color(50, 50, 50));
|
||||
}
|
||||
if (menuFg == null || (menuBg != null && isDarkColor(menuBg) && isDarkColor(menuFg))) {
|
||||
UIManager.put("Menu.foreground", Color.WHITE);
|
||||
}
|
||||
UIManager.put("Menu.selectionBackground", new Color(60, 60, 60));
|
||||
UIManager.put("Menu.selectionForeground", Color.WHITE);
|
||||
|
||||
// Fix menu item colors
|
||||
Color menuItemBg = UIManager.getColor("MenuItem.background");
|
||||
Color menuItemFg = UIManager.getColor("MenuItem.foreground");
|
||||
if (menuItemBg == null || isDarkColor(menuItemBg)) {
|
||||
UIManager.put("MenuItem.background", new Color(50, 50, 50));
|
||||
}
|
||||
if (menuItemFg == null || (menuItemBg != null && isDarkColor(menuItemBg) && isDarkColor(menuItemFg))) {
|
||||
UIManager.put("MenuItem.foreground", Color.WHITE);
|
||||
}
|
||||
UIManager.put("MenuItem.selectionBackground", new Color(60, 60, 60));
|
||||
UIManager.put("MenuItem.selectionForeground", Color.WHITE);
|
||||
}
|
||||
|
||||
// Popup menu colors
|
||||
Color popupBg = UIManager.getColor("PopupMenu.background");
|
||||
if (popupBg == null || isDarkColor(popupBg)) {
|
||||
UIManager.put("PopupMenu.background", new Color(50, 50, 50));
|
||||
UIManager.put("PopupMenu.foreground", Color.WHITE);
|
||||
UIManager.put("PopupMenu.borderColor", new Color(70, 70, 70));
|
||||
}
|
||||
|
||||
// Checkbox and radio button menu items
|
||||
Color checkBoxMenuItemBg = UIManager.getColor("CheckBoxMenuItem.background");
|
||||
if (checkBoxMenuItemBg == null || isDarkColor(checkBoxMenuItemBg)) {
|
||||
UIManager.put("CheckBoxMenuItem.background", new Color(50, 50, 50));
|
||||
UIManager.put("CheckBoxMenuItem.foreground", Color.WHITE);
|
||||
UIManager.put("CheckBoxMenuItem.selectionBackground", new Color(60, 60, 60));
|
||||
UIManager.put("CheckBoxMenuItem.selectionForeground", Color.WHITE);
|
||||
}
|
||||
|
||||
Color radioMenuItemBg = UIManager.getColor("RadioButtonMenuItem.background");
|
||||
if (radioMenuItemBg == null || isDarkColor(radioMenuItemBg)) {
|
||||
UIManager.put("RadioButtonMenuItem.background", new Color(50, 50, 50));
|
||||
UIManager.put("RadioButtonMenuItem.foreground", Color.WHITE);
|
||||
UIManager.put("RadioButtonMenuItem.selectionBackground", new Color(60, 60, 60));
|
||||
UIManager.put("RadioButtonMenuItem.selectionForeground", Color.WHITE);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if a color is dark (suitable for dark theme).
|
||||
*/
|
||||
private static boolean isDarkColor(Color color) {
|
||||
if (color == null) {
|
||||
return false;
|
||||
}
|
||||
// Calculate luminance
|
||||
double luminance = (0.299 * color.getRed() + 0.587 * color.getGreen() + 0.114 * color.getBlue()) / 255;
|
||||
return luminance < 0.5;
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -6,7 +6,7 @@
|
||||
|
||||
<groupId>org.diylc</groupId>
|
||||
<artifactId>diylc-parent</artifactId>
|
||||
<version>5.4.0</version>
|
||||
<version>5.7.0</version>
|
||||
<packaging>pom</packaging>
|
||||
|
||||
<name>DIY Layout Creator</name>
|
||||
|
||||
@@ -129,7 +129,7 @@ INSERT INTO diylc_knowledge_base (category, section, content) ('Component Types'
|
||||
"type" : "java.lang.Boolean"
|
||||
}, {
|
||||
"name" : "Type",
|
||||
"type" : "org.diylc.components.guitar.LeverSwitch$LeverSwitchType(DP3T (Standard 3-Position Strat),DP3T (Standard 5-Position Strat),DP3T (Import 5-Position Strat),4P5T (Super/Mega),DP4T (4-Position Tele),DP4T (6-Position Oak Grigsby),DP5T)"
|
||||
"type" : "org.diylc.components.guitar.LeverSwitch$LeverSwitchType(DP3T (Standard 3-Position Strat),DP3T (Standard 5-Position Strat),DP3T (Import 5-Position Strat),4P5T (Super/Mega),DP4T (4-Position Tele),DP4T (6-Position Oak Grigsby),DP5T,6P5T (5-Position 6 Pole AxLabs)),4P3T (3-Position 3 Pole AxLabs),DP3T (Import 5-Position 2502N)"
|
||||
}, {
|
||||
"name" : "Angle",
|
||||
"type" : "org.diylc.core.Angle"
|
||||
|
||||
Reference in New Issue
Block a user