mirror of
https://github.com/bancika/diy-layout-creator
synced 2026-11-08 12:54:55 +10:00
Compare commits
65 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 00c8c23abb | |||
| 4f048ec15e | |||
| f02cf543a0 | |||
| f69c9459f5 | |||
| b468564821 | |||
| 5bbd7c8ab3 | |||
| 58e28a95fd | |||
| baaeefdbab | |||
| a5f6299de7 | |||
| 1d36394af0 | |||
| aec12898bf | |||
| b4c1ed74c2 | |||
| e17b79a2c4 | |||
| 34054a68f1 | |||
| 5052e10f0e | |||
| 8c9a8e71dc | |||
| 3b2dfb075f | |||
| 655df8c9db | |||
| 52a8935b1f | |||
| e3ff80532d | |||
| 0fb0502dea | |||
| b3ad9cc0d9 | |||
| 8de5b24809 | |||
| 2ca578b707 | |||
| 8267d17ff7 | |||
| 96d7f55e84 | |||
| a8d266f561 | |||
| b57b36141f | |||
| 0368cc404e | |||
| 220b648c56 | |||
| 733c293be6 | |||
| 77cebc3911 | |||
| 3a5f4bdb67 | |||
| ed11ec22a6 | |||
| a4bcbcc761 | |||
| 803caa706f | |||
| 27263e9443 | |||
| c1812e9b70 | |||
| 4811d009b5 | |||
| b001019c0c | |||
| e8a4c488e0 | |||
| 14565a102a | |||
| fbea6c965c | |||
| 6801f9b51b | |||
| 4203ffa9ec | |||
| 8b2f39c165 | |||
| 84dddcecdf | |||
| a86af6384b | |||
| 896a623c7c | |||
| 1c48d7c31f | |||
| 3fcc9091a7 | |||
| f925093c80 | |||
| 473630a5e8 | |||
| 2c642337b4 | |||
| 9d8555c4b7 | |||
| 74f43159c4 | |||
| a0b27de187 | |||
| 9230d709b4 | |||
| 823dcc431c | |||
| ede2a000d4 | |||
| c65ecc10bf | |||
| 858cab4ab4 | |||
| 39ba93ff2c | |||
| eadcb8d81e | |||
| 6e919714d3 |
@@ -7,7 +7,7 @@
|
||||
<parent>
|
||||
<groupId>org.diylc</groupId>
|
||||
<artifactId>diylc-parent</artifactId>
|
||||
<version>5.1.0</version>
|
||||
<version>5.2.0</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>diylc-core</artifactId>
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
package org.diylc.common;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import org.diylc.netlist.Netlist;
|
||||
import org.diylc.netlist.Node;
|
||||
@@ -59,4 +60,9 @@ public interface INetlistAnalyzer {
|
||||
* @return name of the font to be used for display.
|
||||
*/
|
||||
String getFontName();
|
||||
|
||||
/**
|
||||
* @return ability to process netlists with or without switches included.
|
||||
*/
|
||||
Set<NetlistSwitchPreference> getSwitchPreference();
|
||||
}
|
||||
|
||||
@@ -78,7 +78,6 @@ public interface IPlugInPort extends ISelectionProcessor, IMouseProcessor, IKeyP
|
||||
public static final String RECENT_FILES_KEY = "recentFiles";
|
||||
public static final String SHOW_RULERS_KEY = "showRulers";
|
||||
public static final String SHOW_GRID_KEY = "showGrid";
|
||||
public static final String HIGHLIGHT_CONTINUITY_AREA = "highlightContinuityArea";
|
||||
public static final String HARDWARE_ACCELERATION = "hardwareAcceleration";
|
||||
public static final String EXTRA_SPACE_KEY = "extraSpace";
|
||||
public static final String FAVORITES_KEY = "favorites";
|
||||
@@ -400,4 +399,16 @@ public interface IPlugInPort extends ISelectionProcessor, IMouseProcessor, IKeyP
|
||||
* @param threshold
|
||||
*/
|
||||
List<Area> checkContinuityAreaProximity(Size threshold);
|
||||
|
||||
/**
|
||||
* @return the current operation mode of the application
|
||||
*/
|
||||
OperationMode getOperationMode();
|
||||
|
||||
/**
|
||||
* Updates the current operation mode of the application
|
||||
*
|
||||
* @param operationMode
|
||||
*/
|
||||
void setOperationMode(OperationMode operationMode);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
package org.diylc.common;
|
||||
|
||||
public enum NetlistSwitchPreference {
|
||||
WITH, WITHOUT;
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
package org.diylc.common;
|
||||
|
||||
public enum OperationMode {
|
||||
EDIT, HIGHLIGHT_CONNECTED_AREAS
|
||||
}
|
||||
@@ -35,19 +35,9 @@ public enum Orientation {
|
||||
}
|
||||
|
||||
public double toDegrees() {
|
||||
switch (this) {
|
||||
case DEFAULT:
|
||||
return 0;
|
||||
case _180:
|
||||
return 180;
|
||||
case _270:
|
||||
return 270;
|
||||
case _90:
|
||||
return 90;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
if (this == DEFAULT)
|
||||
return 0;
|
||||
return Integer.parseInt(name().replace("_", ""));
|
||||
}
|
||||
|
||||
public double toRadians() {
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
|
||||
DIY Layout Creator (DIYLC).
|
||||
Copyright (c) 2009-2018 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.common;
|
||||
|
||||
public enum Orientation45 {
|
||||
|
||||
DEFAULT, _45, _90, _135, _180, _225, _270, _315;
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
if (this == DEFAULT) {
|
||||
return "Default";
|
||||
} else {
|
||||
return name().replace("_", "") + " degrees clockwise";
|
||||
}
|
||||
}
|
||||
|
||||
public double toDegrees() {
|
||||
if (this == DEFAULT)
|
||||
return 0;
|
||||
return Integer.parseInt(name().replace("_", ""));
|
||||
}
|
||||
|
||||
public double toRadians() {
|
||||
return Math.toRadians(toDegrees());
|
||||
}
|
||||
}
|
||||
@@ -24,6 +24,7 @@ package org.diylc.common;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
import org.diylc.core.IDynamicPropertySource;
|
||||
import org.diylc.core.IPropertyValidator;
|
||||
|
||||
/**
|
||||
@@ -45,9 +46,10 @@ public class PropertyWrapper implements Cloneable {
|
||||
private boolean changed = false;
|
||||
private int sortOrder;
|
||||
private Object ownerObject;
|
||||
private IDynamicPropertySource dynamicPropertySource;
|
||||
|
||||
public PropertyWrapper(String name, Class<?> type, String getter, String setter, boolean defaultable,
|
||||
IPropertyValidator validator, int sortOrder) {
|
||||
IPropertyValidator validator, int sortOrder, IDynamicPropertySource dynamicPropertySource) {
|
||||
super();
|
||||
this.name = name;
|
||||
this.type = type;
|
||||
@@ -56,6 +58,7 @@ public class PropertyWrapper implements Cloneable {
|
||||
this.defaultable = defaultable;
|
||||
this.validator = validator;
|
||||
this.sortOrder = sortOrder;
|
||||
this.dynamicPropertySource = dynamicPropertySource;
|
||||
this.ownerObject = null;
|
||||
}
|
||||
|
||||
@@ -138,6 +141,10 @@ public class PropertyWrapper implements Cloneable {
|
||||
return sortOrder;
|
||||
}
|
||||
|
||||
public IDynamicPropertySource getDynamicPropertySource() {
|
||||
return dynamicPropertySource;
|
||||
}
|
||||
|
||||
// @Override
|
||||
// public Object clone() throws CloneNotSupportedException {
|
||||
// // Try to invoke clone method on value if possible.
|
||||
@@ -152,7 +159,7 @@ public class PropertyWrapper implements Cloneable {
|
||||
public Object clone() throws CloneNotSupportedException {
|
||||
PropertyWrapper clone =
|
||||
new PropertyWrapper(this.name, this.type, this.getter, this.setter, this.defaultable, this.validator,
|
||||
this.sortOrder);
|
||||
this.sortOrder, this.dynamicPropertySource);
|
||||
clone.value = this.value;
|
||||
clone.changed = this.changed;
|
||||
clone.unique = this.unique;
|
||||
|
||||
@@ -201,6 +201,9 @@ public abstract class AbstractCurvedComponent<T> extends AbstractTransparentComp
|
||||
}
|
||||
|
||||
public void setPointCount(PointCount pointCount) {
|
||||
if (this.pointCount == pointCount)
|
||||
return;
|
||||
|
||||
Point2D[] p = getControlPoints();
|
||||
Point2D[] newPoints = new Point2D[pointCount.count];
|
||||
newPoints[0] = p[0];
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
package org.diylc.core;
|
||||
|
||||
import org.diylc.common.PropertyWrapper;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
public abstract class AbstractDynamicPropertyValueSource implements IDynamicPropertySource {
|
||||
|
||||
protected List<PropertyWrapper> properties;
|
||||
protected IDIYComponent<?> component;
|
||||
|
||||
@Override
|
||||
public void setProperties(List<PropertyWrapper> properties) {
|
||||
this.properties = properties;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setComponent(IDIYComponent<?> component) {
|
||||
this.component = component;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDisplayValue(Object value) {
|
||||
if (value == null) {
|
||||
return "None";
|
||||
}
|
||||
if (component instanceof ISwitch sw) {
|
||||
return sw.getPositionName((Integer)value);
|
||||
}
|
||||
return "#" + (((Integer)value) + 1);
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,10 @@
|
||||
package org.diylc.core;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class Angle {
|
||||
public class Angle implements Serializable {
|
||||
|
||||
private int value;
|
||||
|
||||
|
||||
@@ -8,9 +8,11 @@ public interface IBoard {
|
||||
|
||||
Rectangle2D getBoardRectangle();
|
||||
|
||||
BoardUndersideDisplay getBoardUndersideDisplay();
|
||||
BoardUndersideDisplay getUndersideDisplay();
|
||||
|
||||
Size getUndersideOffset();
|
||||
|
||||
Boolean getUndersideTransparency();
|
||||
|
||||
boolean shouldExportToGerber();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
|
||||
DIY Layout Creator (DIYLC).
|
||||
Copyright (c) 2009-2018 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.core;
|
||||
|
||||
import org.diylc.common.PropertyWrapper;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public interface IDynamicPropertySource {
|
||||
|
||||
void setProperties(List<PropertyWrapper> properties);
|
||||
|
||||
void setComponent(IDIYComponent<?> ownerObject);
|
||||
|
||||
List<Object> getAvailableValues();
|
||||
|
||||
String getDisplayValue(Object value);
|
||||
}
|
||||
@@ -21,12 +21,29 @@
|
||||
*/
|
||||
package org.diylc.core;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Interface for all component that can act as switches. They must have at least one position.
|
||||
*
|
||||
* @author Branislav Stojkovic
|
||||
*/
|
||||
public interface ISwitch {
|
||||
public interface ISwitch extends IContinuity {
|
||||
|
||||
Color[] POLE_COLORS = new Color[] {
|
||||
Color.decode("#FFD1DC"), // Pastel Pink
|
||||
Color.decode("#FFE5B4"), // Pastel Peach
|
||||
Color.decode("#B8F2E6"), // Pastel Mint
|
||||
Color.decode("#E6E6FA"), // Pastel Lavender
|
||||
Color.decode("#AEC6CF"), // Pastel Blue
|
||||
Color.decode("#FFFACD"), // Pastel Yellow
|
||||
Color.decode("#FF6961"), // Pastel Red
|
||||
Color.decode("#77DD77"), // Pastel Green
|
||||
Color.decode("#CDB4DB"), // Pastel Purple
|
||||
Color.decode("#AAF0D1") // Pastel Turquoise
|
||||
};
|
||||
|
||||
/**
|
||||
* @return a positive number of positions.
|
||||
@@ -48,4 +65,22 @@ public interface ISwitch {
|
||||
* @return true if the two points are connected in the given switch position, false otherwise.
|
||||
*/
|
||||
boolean arePointsConnected(int index1, int index2, int position);
|
||||
|
||||
/**
|
||||
* @return currently selected switch position, or null if none
|
||||
*/
|
||||
default Integer getSelectedPosition() {
|
||||
return null;
|
||||
}
|
||||
|
||||
default Boolean getHighlightConnectedTerminals() {
|
||||
return false;
|
||||
}
|
||||
|
||||
default boolean arePointsConnected(int index1, int index2) {
|
||||
if (getSelectedPosition() == null) {
|
||||
return false;
|
||||
}
|
||||
return arePointsConnected(index1, index2, getSelectedPosition());
|
||||
}
|
||||
}
|
||||
|
||||
+42
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
|
||||
DIY Layout Creator (DIYLC).
|
||||
Copyright (c) 2009-2018 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.core.annotations;
|
||||
|
||||
import org.diylc.core.IDynamicPropertySource;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
|
||||
/***
|
||||
* Used for properties having dynamic set of possible values. Only to be used in addition to
|
||||
* EditableProperty annotation.
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface DynamicEditableProperty {
|
||||
|
||||
/**
|
||||
* Optional parameter for dynamic values
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
Class<? extends IDynamicPropertySource> source() ;
|
||||
}
|
||||
@@ -0,0 +1,295 @@
|
||||
/*
|
||||
*
|
||||
* DIY Layout Creator (DIYLC). Copyright (c) 2009-2018 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.netlist;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import org.diylc.core.IDIYComponent;
|
||||
|
||||
public abstract class AbstractNetlistAnalyzer {
|
||||
|
||||
public AbstractNetlistAnalyzer() {}
|
||||
|
||||
public List<Summary> summarize(List<Netlist> netlists, Node preferredOutput) throws TreeException {
|
||||
Map<String, Summary> summaries = new HashMap<String, Summary>();
|
||||
for (Netlist n : netlists) {
|
||||
Summary s = summarize(n, preferredOutput);
|
||||
if (summaries.containsKey(s.getSummary()))
|
||||
summaries.get(s.getSummary()).append(n);
|
||||
else
|
||||
summaries.put(s.getSummary(), s);
|
||||
}
|
||||
|
||||
List<Summary> res = new ArrayList<Summary>(summaries.values());
|
||||
res.forEach(summary -> NetlistBuilder.cleanupRedundantSwitches(summary.getNetlist().getSwitchSetup()));
|
||||
Collections.sort(res);
|
||||
return res;
|
||||
}
|
||||
|
||||
protected abstract Summary summarize(Netlist netlist, Node preferredOutput) throws TreeException;
|
||||
|
||||
public Tree constructTreeBetween(Netlist netlist, Node nodeA, Node nodeB) {
|
||||
Tree tree = new Tree(TreeConnectionType.Parallel);
|
||||
connectNodes(netlist, nodeA, nodeB, tree.getChildren(), new Tree(TreeConnectionType.Series), new HashSet<Node>());
|
||||
|
||||
return tree;
|
||||
}
|
||||
|
||||
// protected Tree removeRedundantElements(Tree tree) {
|
||||
// List<Tree> children = tree.getChildren()
|
||||
// .stream()
|
||||
// .map(t -> removeRedundantElements(t))
|
||||
// .collect(Collectors.toList());
|
||||
// if (children.size() == 1) {
|
||||
// Tree first = children.get(0);
|
||||
// return first;
|
||||
// }
|
||||
// }
|
||||
|
||||
protected void connectNodes(Netlist netlist, Node nodeA, Node nodeB, List<Tree> concurrentPaths, Tree currentPath,
|
||||
Set<Node> visited) {
|
||||
if (nodeA == nodeB) {
|
||||
concurrentPaths.add(currentPath);
|
||||
return;
|
||||
}
|
||||
|
||||
Group groupA = findGroup(netlist, nodeA);
|
||||
|
||||
if (groupA == null)
|
||||
return;
|
||||
|
||||
if (groupA.getNodes().contains(nodeB)) {
|
||||
concurrentPaths.add(currentPath);
|
||||
return;
|
||||
}
|
||||
|
||||
visited.addAll(groupA.getNodes());
|
||||
|
||||
List<Tree> newConcurrentPaths = new ArrayList<Tree>();
|
||||
|
||||
for (Node n : groupA.getNodes()) {
|
||||
IDIYComponent<?> c = n.getComponent();
|
||||
for (int i = 0; i < c.getControlPointCount(); i++) {
|
||||
if (i != n.getPointIndex() && c.getInternalLinkName(i, n.getPointIndex()) != null) {
|
||||
TreeLeaf l = new TreeLeaf(c, i, n.getPointIndex());
|
||||
Node newNodeA = new Node(c, i, n.getZIndex());
|
||||
if (!visited.contains(newNodeA)) {
|
||||
// visited.add(n);
|
||||
Tree newCurrentPath = null;
|
||||
try {
|
||||
newCurrentPath = (Tree) currentPath.clone();
|
||||
} catch (CloneNotSupportedException e) {
|
||||
}
|
||||
Tree newItem = new Tree(l);
|
||||
if (!newCurrentPath.getChildren().contains(newItem))
|
||||
newCurrentPath.getChildren().add(newItem);
|
||||
// if (!currentPath.contains(l))
|
||||
// newCurrentPath.add(l);
|
||||
Set<Node> newVisited = new HashSet<Node>(visited);
|
||||
connectNodes(netlist, newNodeA, nodeB, newConcurrentPaths, newCurrentPath, newVisited);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (newConcurrentPaths.size() == 0)
|
||||
return;
|
||||
|
||||
if (newConcurrentPaths.size() == 1) {
|
||||
if (newConcurrentPaths.get(0).getConnectionType() == TreeConnectionType.Series) {
|
||||
currentPath.getChildren().clear();
|
||||
currentPath.getChildren().addAll(newConcurrentPaths.get(0).getChildren());
|
||||
} else {
|
||||
currentPath.getChildren().add(newConcurrentPaths.get(0));
|
||||
}
|
||||
concurrentPaths.add(currentPath);
|
||||
return;
|
||||
}
|
||||
|
||||
mergePaths(newConcurrentPaths, false);
|
||||
concurrentPaths.addAll(newConcurrentPaths);
|
||||
}
|
||||
|
||||
protected void mergePaths(List<Tree> paths, boolean backward) {
|
||||
// First sort paths to get deterministic output
|
||||
paths.sort((a, b) -> {
|
||||
// Convert paths to strings for comparison
|
||||
String pathA = pathToString(a);
|
||||
String pathB = pathToString(b);
|
||||
return pathA.compareTo(pathB);
|
||||
});
|
||||
|
||||
// Find common prefixes/suffixes between paths
|
||||
for (int i = 0; i < paths.size(); i++) {
|
||||
for (int j = i + 1; j < paths.size(); j++) {
|
||||
Tree path1 = paths.get(i);
|
||||
Tree path2 = paths.get(j);
|
||||
|
||||
// Find common prefix
|
||||
List<Tree> commonPrefix = new ArrayList<>();
|
||||
int prefixLen = 0;
|
||||
while (prefixLen < path1.getChildren().size() &&
|
||||
prefixLen < path2.getChildren().size() &&
|
||||
path1.getChildren().get(prefixLen).equals(path2.getChildren().get(prefixLen))) {
|
||||
commonPrefix.add(path1.getChildren().get(prefixLen));
|
||||
prefixLen++;
|
||||
}
|
||||
|
||||
// Find common suffix
|
||||
List<Tree> commonSuffix = new ArrayList<>();
|
||||
int suffixLen = 0;
|
||||
while (suffixLen < path1.getChildren().size() - prefixLen &&
|
||||
suffixLen < path2.getChildren().size() - prefixLen &&
|
||||
path1.getChildren().get(path1.getChildren().size() - 1 - suffixLen)
|
||||
.equals(path2.getChildren().get(path2.getChildren().size() - 1 - suffixLen))) {
|
||||
commonSuffix.add(0, path1.getChildren().get(path1.getChildren().size() - 1 - suffixLen));
|
||||
suffixLen++;
|
||||
}
|
||||
|
||||
// If we found common elements, merge the paths
|
||||
if (prefixLen > 0 || suffixLen > 0) {
|
||||
// Create series structure: prefix + parallel + suffix
|
||||
Tree mergedPath = new Tree(TreeConnectionType.Series);
|
||||
|
||||
// Add common prefix
|
||||
if (!commonPrefix.isEmpty()) {
|
||||
mergedPath.getChildren().addAll(commonPrefix);
|
||||
}
|
||||
|
||||
// Add parallel section
|
||||
Tree parallelSection = new Tree(TreeConnectionType.Parallel);
|
||||
|
||||
// Add unique parts of both paths
|
||||
List<Tree> unique1 = path1.getChildren().subList(prefixLen, path1.getChildren().size() - suffixLen);
|
||||
List<Tree> unique2 = path2.getChildren().subList(prefixLen, path2.getChildren().size() - suffixLen);
|
||||
|
||||
if (!unique1.isEmpty()) {
|
||||
Tree series1 = new Tree(TreeConnectionType.Series);
|
||||
series1.getChildren().addAll(unique1);
|
||||
parallelSection.getChildren().add(series1);
|
||||
}
|
||||
|
||||
if (!unique2.isEmpty()) {
|
||||
Tree series2 = new Tree(TreeConnectionType.Series);
|
||||
series2.getChildren().addAll(unique2);
|
||||
parallelSection.getChildren().add(series2);
|
||||
}
|
||||
|
||||
if (!parallelSection.getChildren().isEmpty()) {
|
||||
mergedPath.getChildren().add(parallelSection);
|
||||
}
|
||||
|
||||
// Add common suffix
|
||||
if (!commonSuffix.isEmpty()) {
|
||||
mergedPath.getChildren().addAll(commonSuffix);
|
||||
}
|
||||
|
||||
// Replace original paths with merged path
|
||||
paths.remove(j);
|
||||
paths.set(i, mergedPath);
|
||||
j--;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Helper method to convert a path to a sortable string
|
||||
private String pathToString(Tree path) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (Tree child : path.getChildren()) {
|
||||
if (child.getLeaf() != null) {
|
||||
sb.append(child.getLeaf().getComponent().getName())
|
||||
.append(":");
|
||||
} else {
|
||||
// For non-leaf nodes (parallel/series), recursively convert
|
||||
sb.append("(").append(pathToString(child)).append(")");
|
||||
}
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
protected Group findGroup(Netlist netlist, Node node) {
|
||||
for (Group g : netlist.getGroups())
|
||||
if (g.getNodes().contains(node))
|
||||
return g;
|
||||
return null;
|
||||
}
|
||||
|
||||
protected List<Node> find(Set<String> typeNames, String nodeName, Netlist netlist) {
|
||||
List<Node> res = new ArrayList<Node>();
|
||||
for (Group g : netlist.getGroups()) {
|
||||
for (Node n : g.getNodes()) {
|
||||
if (typeNames.contains(n.getComponent().getClass().getCanonicalName())
|
||||
&& (nodeName == null || n.getDisplayName().equalsIgnoreCase(nodeName))) {
|
||||
res.add(n);
|
||||
}
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
protected String extractName(IDIYComponent<?> c) {
|
||||
return c.getName() + " " + (c.getValueForDisplay() == null ? "" : c.getValueForDisplay());
|
||||
}
|
||||
|
||||
public static List<Set<IDIYComponent<?>>> extractComponentGroups(List<Netlist> netlists) {
|
||||
List<Set<IDIYComponent<?>>> res = new ArrayList<Set<IDIYComponent<?>>>();
|
||||
for (Netlist n : netlists) {
|
||||
res.addAll(extractComponentGroups(n));
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
public static List<Set<IDIYComponent<?>>> extractComponentGroups(Netlist netlist) {
|
||||
List<Set<IDIYComponent<?>>> res = new ArrayList<Set<IDIYComponent<?>>>();
|
||||
for (Group g : netlist.getGroups()) {
|
||||
Set<IDIYComponent<?>> components = new HashSet<IDIYComponent<?>>();
|
||||
for (Node n : g.getNodes())
|
||||
components.add(n.getComponent());
|
||||
res.add(components);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
protected int find(Node node, List<Group> groups) {
|
||||
for (int i = 0; i < groups.size(); i++)
|
||||
if (groups.get(i).getNodes().contains(node))
|
||||
return i;
|
||||
return -1;
|
||||
}
|
||||
|
||||
protected boolean intersect(List<Group> groups, Node node) {
|
||||
for (Group g : groups)
|
||||
if (g.getNodes().contains(node))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
protected Node intersect(List<Group> groups, Group group) {
|
||||
for (Group g : groups)
|
||||
for (Node node : group.getNodes())
|
||||
if (g.getNodes().contains(node))
|
||||
return node;
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -23,6 +23,7 @@ import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.diylc.core.IDIYComponent;
|
||||
|
||||
@@ -59,10 +60,6 @@ public class Netlist implements Comparable<Netlist> {
|
||||
return switchSetup;
|
||||
}
|
||||
|
||||
public void done() {
|
||||
Collections.sort(switchSetup);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
@@ -88,10 +85,15 @@ public class Netlist implements Comparable<Netlist> {
|
||||
return true;
|
||||
}
|
||||
|
||||
public String getSwitchSetupString() {
|
||||
return getSwitchSetup().isEmpty() ? "[ ALL ]" : "[ " +
|
||||
getSwitchSetup().stream().map(x -> x.toString()).collect(Collectors.joining(",")) + " ]";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("Switch setup: ").append(getSwitchSetup()).append("\n\n");
|
||||
sb.append("Switch setup: ").append(getSwitchSetupString()).append("\n\n");
|
||||
List<Group> list = getSortedGroups();
|
||||
for (Group g : list) {
|
||||
sb.append("\t").append(g).append("\n");
|
||||
|
||||
@@ -19,15 +19,7 @@ package org.diylc.netlist;
|
||||
|
||||
import java.awt.geom.Area;
|
||||
import java.awt.geom.Point2D;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.TreeSet;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
import org.apache.log4j.Logger;
|
||||
|
||||
@@ -77,7 +69,7 @@ public class NetlistBuilder {
|
||||
.extractComponentTypeFrom((Class<? extends IDIYComponent<?>>) c.getClass());
|
||||
|
||||
// extract nodes
|
||||
if (!(c instanceof IContinuity) && !(c instanceof ICommonNode)) {
|
||||
if (!(c instanceof IContinuity && !(c instanceof ISwitch)) && !(c instanceof ICommonNode)) {
|
||||
// regular components, create a node per control point
|
||||
for (int i = 0; i < c.getControlPointCount(); i++) {
|
||||
String nodeName = c.getControlPointNodeName(i);
|
||||
@@ -191,10 +183,29 @@ public class NetlistBuilder {
|
||||
// sort everything alphabetically
|
||||
List<Netlist> netlists = new ArrayList<Netlist>(result.keySet());
|
||||
Collections.sort(netlists);
|
||||
netlists.forEach(netlist -> cleanupRedundantSwitches(netlist.getSwitchSetup()));
|
||||
|
||||
return netlists;
|
||||
}
|
||||
|
||||
public static void cleanupRedundantSwitches(List<SwitchSetup> switchSetups) {
|
||||
Map<ISwitch, Set<Integer>> positionCountMap = new HashMap<>();
|
||||
switchSetups.forEach(s -> s.getPositions().forEach(pos -> {
|
||||
positionCountMap.computeIfAbsent(pos.getSwitch(), k -> new HashSet<Integer>()).add(pos.getPosition());
|
||||
}));
|
||||
// find switches that are here in all the positions, meaning that they don't affect the circuit
|
||||
Set<ISwitch> switchesToPrune = positionCountMap.entrySet().stream()
|
||||
.filter(e -> e.getKey().getPositionCount() == e.getValue().size())
|
||||
.map(x -> x.getKey())
|
||||
.collect(Collectors.toSet());
|
||||
switchSetups.forEach(s -> s.getPositions().removeIf(x -> switchesToPrune.contains(x.getSwitch())));
|
||||
switchSetups.removeIf(x -> x.getPositions().isEmpty());
|
||||
HashSet<SwitchSetup> uniqueSetups = new HashSet<>(switchSetups);
|
||||
switchSetups.clear();
|
||||
switchSetups.addAll(uniqueSetups);
|
||||
switchSetups.sort(Comparator.comparing(x -> x.toString()));
|
||||
}
|
||||
|
||||
public static Netlist buildNetlist(List<IDIYComponent<?>> components, Collection<Node> nodes,
|
||||
Collection<ContinuityArea> continuityAreas, Collection<Connection> connections) {
|
||||
ImmutableGraph<ProjectGraphNode> graph = buildGraph(nodes, continuityAreas, connections);
|
||||
@@ -404,8 +415,10 @@ public class NetlistBuilder {
|
||||
IDIYComponent<?> c = project.getComponents().get(z);
|
||||
ComponentType type = ComponentProcessor.getInstance()
|
||||
.extractComponentTypeFrom((Class<? extends IDIYComponent<?>>) c.getClass());
|
||||
// handle direct connections
|
||||
if (c instanceof IContinuity) {
|
||||
// handle direct connections or connections through a switch
|
||||
// when not using "includeSwitches" flag
|
||||
if (c instanceof IContinuity &&
|
||||
(!(c instanceof ISwitch) || switchPositions.isEmpty())) {
|
||||
for (int i = 0; i < c.getControlPointCount() - 1; i++)
|
||||
for (int j = i + 1; j < c.getControlPointCount(); j++)
|
||||
if (((IContinuity) c).arePointsConnected(i, j))
|
||||
|
||||
@@ -172,10 +172,10 @@ public class Tree {
|
||||
}
|
||||
|
||||
public String toAsciiString() {
|
||||
return String.join("<br>", toAscii());
|
||||
return String.join("<br>", toAsciiLines());
|
||||
}
|
||||
|
||||
private List<String> toAscii() {
|
||||
private List<String> toAsciiLines() {
|
||||
if (leaf != null) {
|
||||
return Arrays.asList(TreeAsciiUtil.generateString(TreeAsciiUtil.BOXH,
|
||||
1) + " " + leaf.toHTML() + " " + TreeAsciiUtil.generateString(TreeAsciiUtil.BOXH, 1));
|
||||
@@ -184,7 +184,7 @@ public class Tree {
|
||||
List<Tree> children = getOrderedChildren();
|
||||
|
||||
List<List<String>> childrenAscii =
|
||||
children.stream().map(c -> c.toAscii()).collect(Collectors.toList());
|
||||
children.stream().map(c -> c.toAsciiLines()).collect(Collectors.toList());
|
||||
|
||||
if (TreeConnectionType.Series.equals(connectionType)) {
|
||||
return TreeAsciiUtil.concatenateMultiLineSerial(
|
||||
|
||||
@@ -20,13 +20,15 @@ public class TreeAsciiUtil {
|
||||
|
||||
public static List<String> concatenateMultiLineParallel(List<List<String>> elementLines) {
|
||||
|
||||
if (elementLines.size() <= 1) {
|
||||
return elementLines.stream().findFirst().orElse(new ArrayList<>());
|
||||
if (elementLines == null || elementLines.isEmpty()) {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
|
||||
if (elementLines.size() == 1) {
|
||||
return new ArrayList<>(elementLines.get(0));
|
||||
}
|
||||
|
||||
List<Integer> lineCounts = elementLines.stream()
|
||||
.map(lines -> lines.size())
|
||||
.collect(Collectors.toList());
|
||||
// Calculate maximum line length for each element
|
||||
List<Integer> lineLengths = elementLines.stream()
|
||||
.map(element -> element.stream()
|
||||
.map(TreeAsciiUtil::htmlLength)
|
||||
@@ -34,180 +36,252 @@ public class TreeAsciiUtil {
|
||||
.orElse(0))
|
||||
.collect(Collectors.toList());
|
||||
int maxLineLength = Collections.max(lineLengths);
|
||||
int targetLineCount = lineCounts.stream()
|
||||
.mapToInt(Integer::intValue)
|
||||
.sum() + elementLines.size() - 1;
|
||||
int centerLine = targetLineCount / 2;
|
||||
|
||||
List<String> results = new ArrayList<String>();
|
||||
int overallLineCount = 0;
|
||||
|
||||
// Calculate total height and center positions
|
||||
List<Integer> elementHeights = elementLines.stream()
|
||||
.map(List::size)
|
||||
.collect(Collectors.toList());
|
||||
|
||||
// Calculate total height including spacing lines
|
||||
int totalHeight = elementHeights.stream().mapToInt(Integer::intValue).sum() + (elementLines.size() - 1);
|
||||
int centerLine = totalHeight / 2;
|
||||
|
||||
List<String> results = new ArrayList<>();
|
||||
int lineCounter = 0;
|
||||
|
||||
// Process each element
|
||||
for (int i = 0; i < elementLines.size(); i++) {
|
||||
List<String> lines = elementLines.get(i);
|
||||
|
||||
int lineLength = lineLengths.get(i);
|
||||
|
||||
String leftBuffer = "";
|
||||
String rightBuffer = "";
|
||||
if (lineLength < maxLineLength) {
|
||||
leftBuffer = generateString(" ", (maxLineLength - lineLength) / 2);
|
||||
rightBuffer = generateString(" ", (maxLineLength - lineLength) - (maxLineLength - lineLength) / 2);
|
||||
}
|
||||
|
||||
String leftBufferCentral = "";
|
||||
String rightBufferCentral = "";
|
||||
if (lineLength < maxLineLength) {
|
||||
leftBufferCentral = generateString(BOXH, (maxLineLength - lineLength) / 2);
|
||||
rightBufferCentral = generateString(BOXH, (maxLineLength - lineLength) - (maxLineLength - lineLength) / 2);
|
||||
}
|
||||
|
||||
int elementCenterLine = lines.size() / 2;
|
||||
|
||||
for (int j = 0; j < lines.size(); j++) {
|
||||
String line = lines.get(j);
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
List<String> element = elementLines.get(i);
|
||||
int elementHeight = element.size();
|
||||
int elementCenter = elementHeight / 2;
|
||||
|
||||
if (overallLineCount == centerLine) {
|
||||
sb.append(BOXH);
|
||||
} else {
|
||||
sb.append(NBSP);
|
||||
// Calculate the first and last line numbers for the entire parallel group
|
||||
int firstLineOfGroup = 0;
|
||||
int lastLineOfGroup = totalHeight - 1;
|
||||
|
||||
// Process each line of the element
|
||||
for (int j = 0; j < elementHeight; j++) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
String line = element.get(j);
|
||||
int lineLength = htmlLength(line);
|
||||
|
||||
// Calculate padding to center this element's content
|
||||
int leftPadding = (maxLineLength - lineLength) / 2;
|
||||
int rightPadding = maxLineLength - lineLength - leftPadding;
|
||||
|
||||
// Start character
|
||||
if (lineCounter == centerLine) {
|
||||
sb.append(BOXH);
|
||||
} else {
|
||||
sb.append(NBSP);
|
||||
}
|
||||
|
||||
// Left connection
|
||||
if (j == elementCenter) {
|
||||
if (i == 0) {
|
||||
// First element in parallel group
|
||||
sb.append(BOXDR); // Top-left corner (┌)
|
||||
} else if (i == elementLines.size() - 1) {
|
||||
// Last element in parallel group
|
||||
sb.append(BOXUR); // Bottom-left corner (└)
|
||||
} else {
|
||||
sb.append(BOXVR); // T-connection (├) for middle elements
|
||||
}
|
||||
} else {
|
||||
if (j < elementCenter && i == 0) {
|
||||
sb.append(NBSP); // No connection above first element
|
||||
} else if (j > elementCenter && i == elementLines.size() - 1) {
|
||||
sb.append(NBSP); // No connection below last element
|
||||
} else if (lineCounter == centerLine) {
|
||||
sb.append(BOXVL); // Horizontal connection
|
||||
} else {
|
||||
sb.append(BOXV); // Vertical line
|
||||
}
|
||||
}
|
||||
|
||||
// Left padding
|
||||
if (j == elementCenter) {
|
||||
sb.append(generateString(BOXH, leftPadding));
|
||||
} else {
|
||||
sb.append(generateString(NBSP, leftPadding));
|
||||
}
|
||||
|
||||
// Element content
|
||||
sb.append(line);
|
||||
|
||||
// Right padding
|
||||
if (j == elementCenter) {
|
||||
sb.append(generateString(BOXH, rightPadding));
|
||||
} else {
|
||||
sb.append(generateString(NBSP, rightPadding));
|
||||
}
|
||||
|
||||
// Right connection
|
||||
if (j == elementCenter) {
|
||||
if (i == 0) {
|
||||
// First element in parallel group
|
||||
sb.append(BOXDL); // Top-right corner (┐)
|
||||
} else if (i == elementLines.size() - 1) {
|
||||
// Last element in parallel group
|
||||
sb.append(BOXUL); // Bottom-right corner (┘)
|
||||
} else {
|
||||
sb.append(BOXVL); // T-connection (┤) for middle elements
|
||||
}
|
||||
} else {
|
||||
if (j < elementCenter && i == 0) {
|
||||
sb.append(NBSP); // No connection above first element
|
||||
} else if (j > elementCenter && i == elementLines.size() - 1) {
|
||||
sb.append(NBSP); // No connection below last element
|
||||
} else if (lineCounter == centerLine) {
|
||||
sb.append(BOXVR); // Horizontal connection
|
||||
} else {
|
||||
sb.append(BOXV); // Vertical line
|
||||
}
|
||||
}
|
||||
|
||||
// End character
|
||||
if (lineCounter == centerLine) {
|
||||
sb.append(BOXH);
|
||||
} else {
|
||||
sb.append(NBSP);
|
||||
}
|
||||
|
||||
results.add(sb.toString());
|
||||
lineCounter++;
|
||||
}
|
||||
|
||||
if ((j < elementCenterLine && i == 0) || (j > elementCenterLine && i == elementLines.size() - 1)) {
|
||||
sb.append(NBSP);
|
||||
} else if (j == elementCenterLine && i == 0) {
|
||||
sb.append(BOXDR);
|
||||
} else if (i == elementLines.size() - 1 && j == elementCenterLine) {
|
||||
sb.append(BOXUR);
|
||||
} else if (overallLineCount == centerLine) {
|
||||
if (j == elementCenterLine && i > 0 && i < elementLines.size() - 1) {
|
||||
sb.append(BOXVH);
|
||||
} else {
|
||||
sb.append(BOXVL);
|
||||
}
|
||||
} else {
|
||||
if (j == elementCenterLine && i > 0 && i < elementLines.size() - 1) {
|
||||
sb.append(BOXVR);
|
||||
} else {
|
||||
sb.append(BOXV);
|
||||
}
|
||||
// Add a separator line between elements (except after the last one)
|
||||
if (i < elementLines.size() - 1) {
|
||||
StringBuilder separatorLine = new StringBuilder();
|
||||
|
||||
// Start character
|
||||
if (lineCounter == centerLine) {
|
||||
separatorLine.append(BOXH);
|
||||
} else {
|
||||
separatorLine.append(NBSP);
|
||||
}
|
||||
|
||||
// Left connection
|
||||
if (lineCounter == centerLine) {
|
||||
separatorLine.append(BOXVL);
|
||||
separatorLine.append(generateString(NBSP, maxLineLength));
|
||||
separatorLine.append(BOXVR);
|
||||
} else {
|
||||
separatorLine.append(BOXV);
|
||||
separatorLine.append(generateString(NBSP, maxLineLength));
|
||||
separatorLine.append(BOXV);
|
||||
}
|
||||
|
||||
// End character
|
||||
if (lineCounter == centerLine) {
|
||||
separatorLine.append(BOXH);
|
||||
} else {
|
||||
separatorLine.append(NBSP);
|
||||
}
|
||||
|
||||
results.add(separatorLine.toString());
|
||||
lineCounter++;
|
||||
}
|
||||
|
||||
if (j == elementCenterLine) {
|
||||
sb.append(leftBufferCentral);
|
||||
} else {
|
||||
sb.append(leftBuffer);
|
||||
}
|
||||
sb.append(line);
|
||||
if (j == elementCenterLine) {
|
||||
sb.append(rightBufferCentral);
|
||||
} else {
|
||||
sb.append(rightBuffer);
|
||||
}
|
||||
|
||||
if ((j < elementCenterLine && i == 0) || (j > elementCenterLine && i == elementLines.size() - 1)) {
|
||||
sb.append(NBSP);
|
||||
} else if (j == elementCenterLine && i == 0) {
|
||||
sb.append(BOXDL);
|
||||
} else if (i == elementLines.size() - 1 && j == elementCenterLine) {
|
||||
sb.append(BOXUL);
|
||||
} else if (overallLineCount == centerLine) {
|
||||
if (j == elementCenterLine && i > 0 && i < elementLines.size() - 1) {
|
||||
sb.append(BOXVH);
|
||||
} else {
|
||||
sb.append(BOXVR);
|
||||
}
|
||||
} else {
|
||||
if (j == elementCenterLine && i > 0 && i < elementLines.size() - 1) {
|
||||
sb.append(BOXVL);
|
||||
} else {
|
||||
sb.append(BOXV);
|
||||
}
|
||||
}
|
||||
|
||||
if (overallLineCount == centerLine) {
|
||||
sb.append(BOXH);
|
||||
} else {
|
||||
sb.append(NBSP);
|
||||
}
|
||||
|
||||
results.add(sb.toString());
|
||||
overallLineCount++;
|
||||
}
|
||||
|
||||
|
||||
if (i < elementLines.size() - 1) {
|
||||
String leftEnding;
|
||||
String rightEnding;
|
||||
if (overallLineCount == centerLine) {
|
||||
leftEnding = BOXH + BOXVL;
|
||||
rightEnding = BOXVR + BOXH;
|
||||
} else {
|
||||
leftEnding = NBSP + BOXV;
|
||||
rightEnding = BOXV + NBSP;
|
||||
}
|
||||
String emptyLine = leftEnding + generateString(NBSP, maxLineLength) + rightEnding;
|
||||
results.add(emptyLine);
|
||||
overallLineCount++;
|
||||
}
|
||||
}
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
public static List<String> concatenateMultiLineSerial(String separator, List<List<String>> elementLines) {
|
||||
if (elementLines == null || elementLines.isEmpty()) {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
|
||||
if (elementLines.size() == 1) {
|
||||
return new ArrayList<>(elementLines.get(0));
|
||||
}
|
||||
|
||||
List<Integer> lineCounts = elementLines.stream()
|
||||
.map(lines -> lines.size())
|
||||
.map(List::size)
|
||||
.collect(Collectors.toList());
|
||||
|
||||
// Detect if all elements have the same height
|
||||
boolean uniformHeight = lineCounts.stream().distinct().count() == 1;
|
||||
|
||||
String blankSeparator = generateString(NBSP, htmlLength(separator));
|
||||
int maxLineCount = lineCounts.stream().mapToInt(Integer::intValue).max().orElse(0);
|
||||
int maxLineCount = Collections.max(lineCounts);
|
||||
int centerLine = maxLineCount / 2;
|
||||
|
||||
List<Integer> lineLengths = elementLines.stream()
|
||||
.map(element -> element.stream()
|
||||
.map(TreeAsciiUtil::htmlLength)
|
||||
.max(Integer::compare)
|
||||
.orElse(0))
|
||||
.collect(Collectors.toList());
|
||||
|
||||
List<String> results = new ArrayList<>();
|
||||
|
||||
for (int line = 0; line < maxLineCount; line++) {
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
for (int i = 0; i < elementLines.size(); i++) {
|
||||
int elementLineCount = lineCounts.get(i);
|
||||
int elementCenterLine = elementLineCount / 2;
|
||||
int elementLineLength = lineLengths.get(i);
|
||||
if (line < centerLine - elementCenterLine
|
||||
|| line > centerLine - elementCenterLine + elementLineCount) {
|
||||
sb.append(generateString(NBSP, elementLineLength));
|
||||
List<String> element = elementLines.get(i);
|
||||
int elementHeight = lineCounts.get(i);
|
||||
int elementCenter = elementHeight / 2;
|
||||
int elementWidth = lineLengths.get(i);
|
||||
|
||||
// Determine if this line aligns with the element
|
||||
boolean lineAligned = !(line < centerLine - elementCenter ||
|
||||
line > centerLine - elementCenter + elementHeight - 1);
|
||||
|
||||
if (!lineAligned) {
|
||||
// Line doesn't align - fill with spaces
|
||||
sb.append(generateString(NBSP, elementWidth));
|
||||
} else {
|
||||
int lineIndex = line + elementCenterLine - centerLine;
|
||||
List<String> element = elementLines.get(i);
|
||||
String elementLine;
|
||||
if (lineIndex < element.size()) {
|
||||
elementLine = element.get(lineIndex);
|
||||
// Line aligns - show content
|
||||
int elementLine = line - (centerLine - elementCenter);
|
||||
if (elementLine < element.size()) {
|
||||
String content = element.get(elementLine);
|
||||
sb.append(content);
|
||||
|
||||
// Pad if needed
|
||||
int contentLength = htmlLength(content);
|
||||
if (contentLength < elementWidth) {
|
||||
sb.append(generateString(NBSP, elementWidth - contentLength));
|
||||
}
|
||||
} else {
|
||||
elementLine = generateString(NBSP, elementLineLength);
|
||||
sb.append(generateString(NBSP, elementWidth));
|
||||
}
|
||||
sb.append(elementLine);
|
||||
}
|
||||
|
||||
// Add separator after each element except the last
|
||||
if (i < elementLines.size() - 1) {
|
||||
if (line == centerLine) {
|
||||
sb.append(separator);
|
||||
} else {
|
||||
sb.append(blankSeparator);
|
||||
}
|
||||
// Only add separator on the center line
|
||||
if (line == centerLine) {
|
||||
// Check if the current element ends with a box character
|
||||
String currentLine = sb.toString();
|
||||
if (currentLine.endsWith(BOXDL) || currentLine.endsWith(BOXUL)) {
|
||||
// If it ends with a box character, just add a single dash
|
||||
sb.append(BOXH);
|
||||
} else {
|
||||
// Otherwise add normal separator
|
||||
sb.append(separator);
|
||||
}
|
||||
} else {
|
||||
// Don't add any separator on non-center lines
|
||||
sb.append(NBSP);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
results.add(sb.toString());
|
||||
}
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
public static String generateString(String seed, int n) {
|
||||
if (n <= 0) return "";
|
||||
return String.join("", Collections.nCopies(n, seed));
|
||||
}
|
||||
|
||||
public static int htmlLength(String s) {
|
||||
if (s == null) return 0;
|
||||
return s.replaceAll("\\&.*?\\;", "x").length();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -37,11 +37,16 @@ import org.diylc.common.IComponentTransformer;
|
||||
import org.diylc.common.PropertyWrapper;
|
||||
import org.diylc.core.CreationMethod;
|
||||
import org.diylc.core.IDIYComponent;
|
||||
|
||||
import org.diylc.core.IDynamicPropertySource;
|
||||
import org.diylc.core.IPropertyValidator;
|
||||
import org.diylc.core.annotations.*;
|
||||
|
||||
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.lang.LangUtil;
|
||||
import org.reflections.Reflections;
|
||||
import org.reflections.util.ConfigurationBuilder;
|
||||
@@ -195,10 +200,16 @@ public class ComponentProcessor {
|
||||
LangUtil.translate(o.toString());
|
||||
}
|
||||
}
|
||||
|
||||
IDynamicPropertySource dynamicPropertySource = null;
|
||||
if (getter.isAnnotationPresent(DynamicEditableProperty.class)) {
|
||||
DynamicEditableProperty dynamicAnnotation = getter.getAnnotation(DynamicEditableProperty.class);
|
||||
dynamicPropertySource = getDynamicPropertySource(dynamicAnnotation.source());
|
||||
}
|
||||
|
||||
PropertyWrapper property =
|
||||
new PropertyWrapper(name, getter.getReturnType(), getter.getName(), setterName,
|
||||
annotation.defaultable(), validator, annotation.sortOrder());
|
||||
annotation.defaultable(), validator, annotation.sortOrder(), dynamicPropertySource);
|
||||
properties.add(property);
|
||||
}
|
||||
}
|
||||
@@ -328,6 +339,17 @@ public class ComponentProcessor {
|
||||
return validator;
|
||||
}
|
||||
|
||||
private IDynamicPropertySource getDynamicPropertySource(Class<? extends IDynamicPropertySource> clazz) {
|
||||
IDynamicPropertySource source;
|
||||
try {
|
||||
source = clazz.getDeclaredConstructor().newInstance();
|
||||
} catch (Exception e) {
|
||||
LOG.error("Could not instantiate source for " + clazz.getName(), e);
|
||||
return null;
|
||||
}
|
||||
return source;
|
||||
}
|
||||
|
||||
private IComponentTransformer getComponentTransformer(Class<? extends IComponentTransformer> clazz) {
|
||||
if (clazz == null)
|
||||
return null;
|
||||
@@ -361,4 +383,9 @@ public class ComponentProcessor {
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Add this method for testing purposes
|
||||
protected void setComponentTypeForTest(Class<? extends IDIYComponent<?>> componentClass, ComponentType componentType) {
|
||||
componentTypeMap.put(componentClass.getName(), componentType);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -191,7 +191,7 @@ public class DrawingManager {
|
||||
Map<IBoard, List<IDIYComponent<?>>> boardMap = project.getComponents().stream()
|
||||
.filter(IBoard.class::isInstance)
|
||||
.map(IBoard.class::cast)
|
||||
.filter(b -> b.getBoardUndersideDisplay() != BoardUndersideDisplay.NONE)
|
||||
.filter(b -> b.getUndersideDisplay() != BoardUndersideDisplay.NONE)
|
||||
.collect(Collectors.toMap(x -> x, x -> new ArrayList<IDIYComponent<?>>()));
|
||||
Map<IDIYComponent<?>, Set<IBoard>> componentBoardMap = new HashMap<IDIYComponent<?>, Set<IBoard>>();
|
||||
|
||||
@@ -201,10 +201,10 @@ public class DrawingManager {
|
||||
if (c == board) {
|
||||
continue;
|
||||
}
|
||||
boolean include = true;
|
||||
boolean include = false;
|
||||
for (int i = 0; i < c.getControlPointCount(); i++) {
|
||||
if (!boardRect.contains(c.getControlPoint(i))) {
|
||||
include = false;
|
||||
if (boardRect.contains(c.getControlPoint(i))) {
|
||||
include = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -333,27 +333,35 @@ public class DrawingManager {
|
||||
lastDrawnStateMap.put(component, state);
|
||||
}
|
||||
|
||||
// Mirror components that belong to boards that need to be mirrored
|
||||
if (componentBoardMap.containsKey(component)) {
|
||||
@SuppressWarnings("unchecked")
|
||||
ComponentType componentType = ComponentProcessor.getInstance()
|
||||
.extractComponentTypeFrom((Class<? extends IDIYComponent<?>>) component.getClass());
|
||||
if (componentType.getTransformer() != null) {
|
||||
Set<IBoard> boards = componentBoardMap.get(component);
|
||||
for (IBoard board : boards) {
|
||||
drawMirroredComponent(project, board, component, componentType, g2dWrapper, state, outlineMode);
|
||||
try {
|
||||
// Mirror components that belong to boards that need to be mirrored
|
||||
if (componentBoardMap.containsKey(component)) {
|
||||
@SuppressWarnings("unchecked")
|
||||
ComponentType componentType = ComponentProcessor.getInstance()
|
||||
.extractComponentTypeFrom((Class<? extends IDIYComponent<?>>) component.getClass());
|
||||
if (componentType.getTransformer() != null) {
|
||||
Set<IBoard> boards = componentBoardMap.get(component);
|
||||
for (IBoard board : boards) {
|
||||
drawMirroredComponent(project, board, component, componentType, g2dWrapper, state,
|
||||
outlineMode);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// if a component itself is a board that needs to be mirrored, do it
|
||||
if (IBoard.class.isInstance(component) && componentBoardMap.values().stream()
|
||||
.anyMatch(boards -> boards.contains(component))) {
|
||||
ComponentType componentType = ComponentProcessor.getInstance()
|
||||
.extractComponentTypeFrom((Class<? extends IDIYComponent<?>>) component.getClass());
|
||||
if (componentType.getTransformer() != null) {
|
||||
drawMirroredComponent(project, (IBoard) component, component, componentType, g2dWrapper, state, outlineMode);
|
||||
// if a component itself is a board that needs to be mirrored, do it
|
||||
if (IBoard.class.isInstance(component) && componentBoardMap.values().stream()
|
||||
.anyMatch(boards -> boards.contains(component))) {
|
||||
ComponentType componentType = ComponentProcessor.getInstance()
|
||||
.extractComponentTypeFrom((Class<? extends IDIYComponent<?>>) component.getClass());
|
||||
if (componentType.getTransformer() != null) {
|
||||
drawMirroredComponent(project, (IBoard) component, component, componentType,
|
||||
g2dWrapper, state, outlineMode);
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
// revert composite
|
||||
g2d.setComposite(oldComposite);
|
||||
g2d.setFont(oldFont);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -524,7 +532,7 @@ public class DrawingManager {
|
||||
IDIYComponent<?> clonedComponent = component.clone();
|
||||
int direction = 0;
|
||||
Point2D pivotPoint = new Point2D.Double();
|
||||
switch (board.getBoardUndersideDisplay()) {
|
||||
switch (board.getUndersideDisplay()) {
|
||||
case ABOVE:
|
||||
direction = IComponentTransformer.VERTICAL;
|
||||
pivotPoint.setLocation(boardRectangle.getMinX(), boardRectangle.getMinY() - offset / 2);
|
||||
@@ -543,7 +551,7 @@ public class DrawingManager {
|
||||
break;
|
||||
}
|
||||
componentType.getTransformer().mirror(clonedComponent, pivotPoint, direction);
|
||||
if (AbstractTransparentComponent.class.isInstance(clonedComponent)) {
|
||||
if (board.getUndersideTransparency() && AbstractTransparentComponent.class.isInstance(clonedComponent)) {
|
||||
AbstractTransparentComponent<?> transparentComponent = (AbstractTransparentComponent<?>) clonedComponent;
|
||||
transparentComponent.setAlpha(MIRROR_ALPHA);
|
||||
}
|
||||
|
||||
@@ -36,11 +36,9 @@ import org.apache.log4j.Logger;
|
||||
import org.diylc.appframework.miscutils.ConfigurationManager;
|
||||
|
||||
import org.diylc.clipboard.ComponentTransferable;
|
||||
import org.diylc.common.ComponentType;
|
||||
import org.diylc.common.IPlugInPort;
|
||||
import org.diylc.common.Orientation;
|
||||
import org.diylc.common.OrientationHV;
|
||||
import org.diylc.common.PropertyWrapper;
|
||||
|
||||
import org.diylc.common.*;
|
||||
|
||||
import org.diylc.core.Angle;
|
||||
import org.diylc.core.CreationMethod;
|
||||
import org.diylc.core.IDIYComponent;
|
||||
@@ -437,6 +435,7 @@ public class InstantiationManager {
|
||||
for (PropertyWrapper propertyWrapper : properties) {
|
||||
if (propertyWrapper.getType().getName().equals(Orientation.class.getName())
|
||||
|| propertyWrapper.getType().getName().equals(OrientationHV.class.getName())
|
||||
|| propertyWrapper.getType().getName().equals(Orientation45.class.getName())
|
||||
|| propertyWrapper.getName().equalsIgnoreCase("angle")) {
|
||||
angleProperty = propertyWrapper;
|
||||
break;
|
||||
@@ -456,6 +455,9 @@ public class InstantiationManager {
|
||||
} else if (value instanceof OrientationHV) {
|
||||
angleProperty.setValue(OrientationHV.values()[(((OrientationHV) value).ordinal() + 1)
|
||||
% OrientationHV.values().length]);
|
||||
} else if (value instanceof Orientation45) {
|
||||
angleProperty.setValue(Orientation45.values()[(((Orientation45) value).ordinal() + 1)
|
||||
% Orientation45.values().length]);
|
||||
} else if (value instanceof Angle) {
|
||||
Angle angle = (Angle) angleProperty.getValue();
|
||||
Angle newAngle = angle.rotate(1);
|
||||
|
||||
@@ -59,17 +59,7 @@ import com.thoughtworks.xstream.io.xml.DomDriver;
|
||||
import com.thoughtworks.xstream.security.AnyTypePermission;
|
||||
|
||||
import org.diylc.clipboard.ComponentTransferable;
|
||||
import org.diylc.common.ComponentType;
|
||||
import org.diylc.common.DrawOption;
|
||||
import org.diylc.common.EventType;
|
||||
import org.diylc.common.IComponentFilter;
|
||||
import org.diylc.common.IComponentTransformer;
|
||||
import org.diylc.common.IKeyProcessor;
|
||||
import org.diylc.common.INetlistAnalyzer;
|
||||
import org.diylc.common.IPlugIn;
|
||||
import org.diylc.common.IPlugInPort;
|
||||
import org.diylc.common.IProjectEditor;
|
||||
import org.diylc.common.PropertyWrapper;
|
||||
import org.diylc.common.*;
|
||||
import org.diylc.core.ExpansionMode;
|
||||
import org.diylc.core.IDIYComponent;
|
||||
import org.diylc.core.IDatasheetSupport;
|
||||
@@ -85,7 +75,7 @@ import org.diylc.core.measures.SizeUnit;
|
||||
import org.diylc.lang.LangUtil;
|
||||
import org.diylc.netlist.INetlistParser;
|
||||
import org.diylc.netlist.Netlist;
|
||||
import org.diylc.netlist.NetlistAnalyzer;
|
||||
import org.diylc.netlist.AbstractNetlistAnalyzer;
|
||||
import org.diylc.netlist.NetlistBuilder;
|
||||
import org.diylc.netlist.NetlistException;
|
||||
import org.diylc.serialization.ProjectFileManager;
|
||||
@@ -99,7 +89,7 @@ import org.diylc.utils.ReflectionUtils;
|
||||
*
|
||||
* @author Branislav Stojkovic
|
||||
*/
|
||||
public class Presenter implements IPlugInPort, IConfigListener {
|
||||
public class Presenter implements IPlugInPort {
|
||||
|
||||
private static final String REACHED_BOTTOM =
|
||||
LangUtil.translate("Selected component(s) have reached the bottom of their layer. Do you want to force the selection to the back?");
|
||||
@@ -182,36 +172,38 @@ public class Presenter implements IPlugInPort, IConfigListener {
|
||||
private Point2D previousScaledPoint;
|
||||
|
||||
private DIYTest test = null;
|
||||
|
||||
private OperationMode operationMode;
|
||||
|
||||
public Presenter(IView view, IConfigurationManager<?> configManager) {
|
||||
this(view, configManager, false);
|
||||
}
|
||||
|
||||
public Presenter(IView view, IConfigurationManager<?> configManager, boolean importVariantsAndBlocks) {
|
||||
this(view, configManager, importVariantsAndBlocks, new MessageDispatcher<EventType>(true));
|
||||
}
|
||||
|
||||
// New constructor for testing
|
||||
protected Presenter(IView view, IConfigurationManager<?> configManager, boolean importVariantsAndBlocks, MessageDispatcher<EventType> messageDispatcher) {
|
||||
super();
|
||||
this.view = view;
|
||||
this.configManager = configManager;
|
||||
this.messageDispatcher = messageDispatcher;
|
||||
plugIns = new ArrayList<IPlugIn>();
|
||||
messageDispatcher = new MessageDispatcher<EventType>(true);
|
||||
selectedComponents = new HashSet<IDIYComponent<?>>();
|
||||
lockedComponents = new HashSet<IDIYComponent<?>>();
|
||||
currentProject = new Project();
|
||||
// cloner = new Cloner();
|
||||
drawingManager = new DrawingManager(messageDispatcher, configManager);
|
||||
projectFileManager = new ProjectFileManager(messageDispatcher);
|
||||
instantiationManager = new InstantiationManager();
|
||||
variantManager = new VariantManager(configManager, projectFileManager.getXStream());
|
||||
buildingBlockManager = new BuildingBlockManager(configManager, projectFileManager.getXStream(), instantiationManager);
|
||||
|
||||
// lockedLayers = EnumSet.noneOf(ComponentLayer.class);
|
||||
// visibleLayers = EnumSet.allOf(ComponentLayer.class);
|
||||
if (importVariantsAndBlocks) {
|
||||
variantManager.upgradeVariants(getComponentTypes());
|
||||
variantManager.importDefaultVariants();
|
||||
buildingBlockManager.importDefaultBlocks();
|
||||
}
|
||||
|
||||
this.configManager.addConfigListener(HIGHLIGHT_CONTINUITY_AREA, this);
|
||||
}
|
||||
|
||||
public void installPlugin(Supplier<IPlugIn> plugInSupplier) {
|
||||
@@ -256,7 +248,7 @@ public class Presenter implements IPlugInPort, IConfigListener {
|
||||
@Override
|
||||
public Cursor getCursorAt(Point point, boolean ctrlDown, boolean shiftDown, boolean altDown) {
|
||||
// Only change the cursor if we're not making a new component.
|
||||
if (configManager.readBoolean(HIGHLIGHT_CONTINUITY_AREA, false) || altDown)
|
||||
if (operationMode == OperationMode.HIGHLIGHT_CONNECTED_AREAS || altDown)
|
||||
return Cursor.getPredefinedCursor(Cursor.CROSSHAIR_CURSOR);
|
||||
if (instantiationManager.getComponentTypeSlot() == null) {
|
||||
// Scale point to remove zoom factor.
|
||||
@@ -266,7 +258,7 @@ public class Presenter implements IPlugInPort, IConfigListener {
|
||||
}
|
||||
for (IDIYComponent<?> component : currentProject.getComponents()) {
|
||||
if (!isComponentLocked(component) && isComponentVisible(component)
|
||||
&& !configManager.readBoolean(HIGHLIGHT_CONTINUITY_AREA, false)) {
|
||||
&& operationMode != OperationMode.HIGHLIGHT_CONNECTED_AREAS) {
|
||||
ComponentArea area = drawingManager.getComponentArea(component);
|
||||
if (area != null && area.getOutlineArea() != null && scaledPoint != null && area.getOutlineArea().contains(scaledPoint)) {
|
||||
return Cursor.getPredefinedCursor(Cursor.HAND_CURSOR);
|
||||
@@ -608,7 +600,7 @@ public class Presenter implements IPlugInPort, IConfigListener {
|
||||
default:
|
||||
LOG.error("Unknown creation method: " + componentTypeSlot.getCreationMethod());
|
||||
}
|
||||
} else if (configManager.readBoolean(HIGHLIGHT_CONTINUITY_AREA, false) || altDown) {
|
||||
} else if (operationMode == OperationMode.HIGHLIGHT_CONNECTED_AREAS || altDown) {
|
||||
drawingManager.findContinuityAreaAtPoint(scaledPoint);
|
||||
messageDispatcher.dispatchMessage(EventType.REPAINT);
|
||||
} else {
|
||||
@@ -1082,8 +1074,8 @@ public class Presenter implements IPlugInPort, IConfigListener {
|
||||
dragAction == DnDConstants.ACTION_LINK, dragAction == DnDConstants.ACTION_MOVE, 1);
|
||||
return;
|
||||
}
|
||||
if (configManager.readBoolean(HIGHLIGHT_CONTINUITY_AREA, false)) {
|
||||
LOG.debug("Cannot start drag in hightlight continuity mode.");
|
||||
if (operationMode == OperationMode.HIGHLIGHT_CONNECTED_AREAS) {
|
||||
LOG.debug("Cannot start drag in highlight continuity mode.");
|
||||
return;
|
||||
}
|
||||
this.dragInProgress = true;
|
||||
@@ -1241,7 +1233,7 @@ public class Presenter implements IPlugInPort, IConfigListener {
|
||||
test.addStep(DIYTest.DRAG_OVER, params);
|
||||
}
|
||||
|
||||
if (point == null || configManager.readBoolean(HIGHLIGHT_CONTINUITY_AREA, false)) {
|
||||
if (point == null || operationMode == OperationMode.HIGHLIGHT_CONNECTED_AREAS) {
|
||||
return false;
|
||||
}
|
||||
Point2D scaledPoint = scalePoint(point);
|
||||
@@ -1556,7 +1548,7 @@ public class Presenter implements IPlugInPort, IConfigListener {
|
||||
new Point((int)previousDragPoint.getX(), (int)previousDragPoint.getY()));;
|
||||
}
|
||||
List<IDIYComponent<?>> newSelection = new ArrayList<IDIYComponent<?>>();
|
||||
if (!configManager.readBoolean(HIGHLIGHT_CONTINUITY_AREA, false))
|
||||
if (operationMode != OperationMode.HIGHLIGHT_CONNECTED_AREAS)
|
||||
for (IDIYComponent<?> component : currentProject.getComponents()) {
|
||||
if (!isComponentLocked(component) && isComponentVisible(component)) {
|
||||
ComponentArea area = drawingManager.getComponentArea(component);
|
||||
@@ -1984,7 +1976,7 @@ public class Presenter implements IPlugInPort, IConfigListener {
|
||||
if (netlists == null)
|
||||
return;
|
||||
|
||||
List<Set<IDIYComponent<?>>> allGroups = NetlistAnalyzer.extractComponentGroups(netlists);
|
||||
List<Set<IDIYComponent<?>>> allGroups = AbstractNetlistAnalyzer.extractComponentGroups(netlists);
|
||||
// Find control points of all selected components and all types
|
||||
Set<String> selectedNamePrefixes = new HashSet<String>();
|
||||
if (expansionMode == ExpansionMode.SAME_TYPE) {
|
||||
@@ -2746,7 +2738,7 @@ public class Presenter implements IPlugInPort, IConfigListener {
|
||||
}
|
||||
}
|
||||
|
||||
Collections.sort(result, new Comparator<INetlistAnalyzer>() {
|
||||
result.sort(new Comparator<INetlistAnalyzer>() {
|
||||
|
||||
@Override
|
||||
public int compare(INetlistAnalyzer o1, INetlistAnalyzer o2) {
|
||||
@@ -2801,17 +2793,24 @@ public class Presenter implements IPlugInPort, IConfigListener {
|
||||
public List<Area> checkContinuityAreaProximity(Size threshold) {
|
||||
return drawingManager.getContinuityAreaProximity((float)threshold.convertToPixels());
|
||||
}
|
||||
|
||||
// IConfigListener
|
||||
|
||||
@Override
|
||||
public void valueChanged(String configKey, Object value) {
|
||||
if (HIGHLIGHT_CONTINUITY_AREA.equalsIgnoreCase(configKey)) {
|
||||
drawingManager.clearContinuityArea();
|
||||
if (Boolean.TRUE.equals(value)) {
|
||||
drawingManager.clearComponentAreaMap();
|
||||
}
|
||||
messageDispatcher.dispatchMessage(EventType.REPAINT);
|
||||
public OperationMode getOperationMode() {
|
||||
return operationMode;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setOperationMode(OperationMode operationMode) {
|
||||
this.operationMode = operationMode;
|
||||
drawingManager.clearContinuityArea();
|
||||
if (OperationMode.HIGHLIGHT_CONNECTED_AREAS == operationMode) {
|
||||
drawingManager.clearComponentAreaMap();
|
||||
}
|
||||
messageDispatcher.dispatchMessage(EventType.REPAINT);
|
||||
messageDispatcher.dispatchMessage(EventType.STATUS_MESSAGE_CHANGED);
|
||||
}
|
||||
|
||||
protected MessageDispatcher<EventType> getMessageDispatcher() {
|
||||
return messageDispatcher;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,3 +1,24 @@
|
||||
/*
|
||||
|
||||
DIY Layout Creator (DIYLC).
|
||||
Copyright (c) 2009-2018 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 org.apache.log4j.Logger;
|
||||
@@ -6,6 +27,7 @@ import org.diylc.lang.LangUtil;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.URL;
|
||||
import java.net.URLDecoder;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
@@ -25,7 +47,9 @@ public class ResourceUtils {
|
||||
if (dirUrl != null) {
|
||||
if (dirUrl.getProtocol().equals("jar")) {
|
||||
// Running from JAR
|
||||
String jarPath = dirUrl.getPath().substring(5, dirUrl.getPath().indexOf("!"));
|
||||
String jarPath = dirUrl.getPath();
|
||||
// Remove the "file:" prefix and decode the URL
|
||||
jarPath = URLDecoder.decode(jarPath.substring(5, jarPath.indexOf("!")), StandardCharsets.UTF_8);
|
||||
JarFile jarFile = new JarFile(jarPath);
|
||||
try {
|
||||
jarFile.stream()
|
||||
|
||||
@@ -1,3 +1,24 @@
|
||||
/*
|
||||
|
||||
DIY Layout Creator (DIYLC).
|
||||
Copyright (c) 2009-2018 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.Graphics2D;
|
||||
|
||||
@@ -0,0 +1,76 @@
|
||||
/*
|
||||
|
||||
DIY Layout Creator (DIYLC).
|
||||
Copyright (c) 2009-2018 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 org.diylc.core.ISwitch;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
public class SwitchUtils {
|
||||
|
||||
public static String[] getSwitchingMarkers(ISwitch switchComponent, int numPoints, boolean verbose) {
|
||||
String[] markers = new String[numPoints];
|
||||
List<List<Set<Integer>>> switchingMatrix = new ArrayList<>();
|
||||
for (int p = 0; p < switchComponent.getPositionCount(); p++) {
|
||||
List<Set<Integer>> connectedPoints = new ArrayList<>();
|
||||
switchingMatrix.add(connectedPoints);
|
||||
for (int i = 0; i < numPoints - 1; i++) {
|
||||
for (int j = i + 1; j < numPoints; j++) {
|
||||
if (switchComponent.arePointsConnected(i, j, p)) {
|
||||
connectedPoints.add(Set.of(i, j));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
List<Integer> commonPoints = new ArrayList<>();
|
||||
for (int i = 0; i < numPoints; i++) {
|
||||
final int finalI = i;
|
||||
if (!switchingMatrix.stream().allMatch(
|
||||
l -> l.isEmpty()) &&
|
||||
switchingMatrix.stream().allMatch(
|
||||
l -> l.isEmpty() ||
|
||||
l.stream().anyMatch(
|
||||
s -> s.contains(finalI)))) {
|
||||
markers[i] = String.valueOf((char)((int)'A' + commonPoints.size()));
|
||||
commonPoints.add(i);
|
||||
}
|
||||
}
|
||||
for (int p = 0; p < switchComponent.getPositionCount(); p++) {
|
||||
for (int c : commonPoints) {
|
||||
for (int i = 0; i < numPoints; i++) {
|
||||
if (commonPoints.contains(i)) {
|
||||
continue;
|
||||
}
|
||||
if (switchComponent.arePointsConnected(Math.min(c, i), Math.max(c, i), p)) {
|
||||
String marker = verbose ? markers[c] + (p + 1) : Integer.toString(p + 1);
|
||||
if (markers[i] == null) {
|
||||
markers[i] = marker;
|
||||
} else {
|
||||
markers[i] += "," + marker;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return markers;
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
<java.util.Arrays_-ArrayList>
|
||||
<a class="org.diylc.appframework.update.Version-array">
|
||||
<a class="org.diylc.appframework.update.Version-array">
|
||||
<org.diylc.appframework.update.Version>
|
||||
<versionNumber>
|
||||
<major>4</major>
|
||||
@@ -12,27 +12,27 @@
|
||||
<org.diylc.appframework.update.Change>
|
||||
<changeType>NEW_FEATURE</changeType>
|
||||
<description>Buzzer component and symbol added (thanks M0JXD)</description>
|
||||
</org.diylc.appframework.update.Change>
|
||||
</org.diylc.appframework.update.Change>
|
||||
<org.diylc.appframework.update.Change>
|
||||
<changeType>NEW_FEATURE</changeType>
|
||||
<description>Resistor symbol now has two draw standards - ANSI and IEC (thanks M0JXD)</description>
|
||||
</org.diylc.appframework.update.Change>
|
||||
</org.diylc.appframework.update.Change>
|
||||
<org.diylc.appframework.update.Change>
|
||||
<changeType>IMPROVEMENT</changeType>
|
||||
<description>Fixed run.sh application starter for Linux and Apple OSX with M1/M2 processors when using Java 17 or newer</description>
|
||||
</org.diylc.appframework.update.Change>
|
||||
</org.diylc.appframework.update.Change>
|
||||
<org.diylc.appframework.update.Change>
|
||||
<changeType>IMPROVEMENT</changeType>
|
||||
<description>When editing Label components, default focus to the text editor</description>
|
||||
</org.diylc.appframework.update.Change>
|
||||
</org.diylc.appframework.update.Change>
|
||||
<org.diylc.appframework.update.Change>
|
||||
<changeType>BUG_FIX</changeType>
|
||||
<description>Unable to move selected components if one of them is close to being reduced to a point</description>
|
||||
</org.diylc.appframework.update.Change>
|
||||
</org.diylc.appframework.update.Change>
|
||||
<org.diylc.appframework.update.Change>
|
||||
<changeType>BUG_FIX</changeType>
|
||||
<description>Toroidal Inductor hangs the application if it doesn't have inductance value set</description>
|
||||
</org.diylc.appframework.update.Change>
|
||||
</org.diylc.appframework.update.Change>
|
||||
</changes>
|
||||
<url>https://github.com/bancika/diy-layout-creator/releases</url>
|
||||
</org.diylc.appframework.update.Version>
|
||||
@@ -48,7 +48,7 @@
|
||||
<org.diylc.appframework.update.Change>
|
||||
<changeType>IMPROVEMENT</changeType>
|
||||
<description>Upgraded JRE version of Mac builds to Temurin 17 and switched OpenGL to Metal rendering engine for improved performance</description>
|
||||
</org.diylc.appframework.update.Change>
|
||||
</org.diylc.appframework.update.Change>
|
||||
<org.diylc.appframework.update.Change>
|
||||
<changeType>BUG_FIX</changeType>
|
||||
<description>Choosing "Print" option from the menu starts printing immediately before choosing printing preferences</description>
|
||||
@@ -88,7 +88,7 @@
|
||||
<org.diylc.appframework.update.Change>
|
||||
<changeType>NEW_FEATURE</changeType>
|
||||
<description>Ability to change pitch and appearance of PCB Terminal Block component</description>
|
||||
</org.diylc.appframework.update.Change>
|
||||
</org.diylc.appframework.update.Change>
|
||||
<org.diylc.appframework.update.Change>
|
||||
<changeType>IMPROVEMENT</changeType>
|
||||
<description>Better rendering of the effective circuit graph in the guitar wiring analyzer, showing series and parallel connections in a more intuitive way</description>
|
||||
@@ -188,7 +188,7 @@
|
||||
<org.diylc.appframework.update.Change>
|
||||
<changeType>BUG_FIX</changeType>
|
||||
<description>'Highlight Continuity Areas' sometimes renders stale areas when clicked</description>
|
||||
</org.diylc.appframework.update.Change>
|
||||
</org.diylc.appframework.update.Change>
|
||||
</changes>
|
||||
<url>https://github.com/bancika/diy-layout-creator/releases</url>
|
||||
</org.diylc.appframework.update.Version>
|
||||
@@ -200,7 +200,7 @@
|
||||
</versionNumber>
|
||||
<releaseDate>2025-03-08 00:00:00.000 CET</releaseDate>
|
||||
<name></name>
|
||||
<changes>
|
||||
<changes>
|
||||
<org.diylc.appframework.update.Change>
|
||||
<changeType>BUG_FIX</changeType>
|
||||
<description>Do not mirror bottom layers for Gerber export as fabrication service providers expect a top view for everything</description>
|
||||
@@ -220,7 +220,7 @@
|
||||
</versionNumber>
|
||||
<releaseDate>2025-03-09 00:00:00.000 CET</releaseDate>
|
||||
<name></name>
|
||||
<changes>
|
||||
<changes>
|
||||
<org.diylc.appframework.update.Change>
|
||||
<changeType>NEW_FEATURE</changeType>
|
||||
<description>Switched to AppImage distribution for Linux system, abandoning Flatpak as a means of distribution. DIYLC AppImage will be available alongside with other executables on the official DIYLC GitHub page.</description>
|
||||
@@ -296,5 +296,93 @@
|
||||
</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>1</minor>
|
||||
<build>1</build>
|
||||
</versionNumber>
|
||||
<releaseDate>2025-03-27 00:00:00.000 CET</releaseDate>
|
||||
<name></name>
|
||||
<changes>
|
||||
<org.diylc.appframework.update.Change>
|
||||
<changeType>IMPROVEMENT</changeType>
|
||||
<description>Include windows ZIP package</description>
|
||||
</org.diylc.appframework.update.Change>
|
||||
<org.diylc.appframework.update.Change>
|
||||
<changeType>BUG_FIX</changeType>
|
||||
<description>Windows version doesn't start in some cases</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>2</minor>
|
||||
<build>0</build>
|
||||
</versionNumber>
|
||||
<releaseDate>2025-03-20 00:00:00.000 CET</releaseDate>
|
||||
<name></name>
|
||||
<changes>
|
||||
<org.diylc.appframework.update.Change>
|
||||
<changeType>NEW_FEATURE</changeType>
|
||||
<description>'Virtual Multimeter' from 'Analyze' menu traces the circuit finding all possible paths of electricity between two points designated by the probe symbol.</description>
|
||||
</org.diylc.appframework.update.Change>
|
||||
<org.diylc.appframework.update.Change>
|
||||
<changeType>NEW_FEATURE</changeType>
|
||||
<description>Added ability to display switch lug markings in order to illustrate how it works internally</description>
|
||||
</org.diylc.appframework.update.Change>
|
||||
<org.diylc.appframework.update.Change>
|
||||
<changeType>NEW_FEATURE</changeType>
|
||||
<description>Added a 'Save' button to all analysis screens which saves results of a circuit analysis to an HTML file</description>
|
||||
</org.diylc.appframework.update.Change>
|
||||
<org.diylc.appframework.update.Change>
|
||||
<changeType>NEW_FEATURE</changeType>
|
||||
<description>Added ability control if the board underside display should render as transparent or not</description>
|
||||
</org.diylc.appframework.update.Change>
|
||||
<org.diylc.appframework.update.Change>
|
||||
<changeType>IMPROVEMENT</changeType>
|
||||
<description>Moved 'Analyze' functions from 'File' menu to their own menu for faster access</description>
|
||||
</org.diylc.appframework.update.Change>
|
||||
<org.diylc.appframework.update.Change>
|
||||
<changeType>IMPROVEMENT</changeType>
|
||||
<description>Moved 'Highlight Connected Areas' feature from 'Config' menu to 'Analyze' menu</description>
|
||||
</org.diylc.appframework.update.Change>
|
||||
<org.diylc.appframework.update.Change>
|
||||
<changeType>IMPROVEMENT</changeType>
|
||||
<description>Fully configurable colors for 'Mini Toggle Switch' components</description>
|
||||
</org.diylc.appframework.update.Change>
|
||||
<org.diylc.appframework.update.Change>
|
||||
<changeType>IMPROVEMENT</changeType>
|
||||
<description>Removed 'DP3T' options from 'Mini Toggle Switch' because that is covered by 'Slide Switch' component and does not belong here</description>
|
||||
</org.diylc.appframework.update.Change>
|
||||
<org.diylc.appframework.update.Change>
|
||||
<changeType>IMPROVEMENT</changeType>
|
||||
<description>Include components in the underside display that have at least one control point laying in the board, as opposed to all</description>
|
||||
</org.diylc.appframework.update.Change>
|
||||
<org.diylc.appframework.update.Change>
|
||||
<changeType>BUG_FIX</changeType>
|
||||
<description>Applying a variant to a 'Hookup Wire' or 'Curved Trace' makes it lose its shape</description>
|
||||
</org.diylc.appframework.update.Change>
|
||||
<org.diylc.appframework.update.Change>
|
||||
<changeType>BUG_FIX</changeType>
|
||||
<description>Copy operation doesn't work when certain component types are selected</description>
|
||||
</org.diylc.appframework.update.Change>
|
||||
<org.diylc.appframework.update.Change>
|
||||
<changeType>BUG_FIX</changeType>
|
||||
<description>Board underside display does not work if there's a Label or PCB Text component on the board</description>
|
||||
</org.diylc.appframework.update.Change>
|
||||
<org.diylc.appframework.update.Change>
|
||||
<changeType>BUG_FIX</changeType>
|
||||
<description>Using board underside display sometimes makes other components semi-transparent</description>
|
||||
</org.diylc.appframework.update.Change>
|
||||
<org.diylc.appframework.update.Change>
|
||||
<changeType>BUG_FIX</changeType>
|
||||
<description>Fixed Windows ZIP package issue with the bundled JRE</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>
|
||||
|
||||
@@ -2,6 +2,12 @@ package org.diylc.netlist;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.ArrayList;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
@@ -56,4 +62,89 @@ public class TreeAsciiUtilTest {
|
||||
// assertEquals("yy-yyy", result.get(1));
|
||||
// assertEquals(" aaa", result.get(2));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSimpleParallel() {
|
||||
List<String> result = TreeAsciiUtil.concatenateMultiLineParallel(
|
||||
Arrays.asList(Arrays.asList("xx"), Arrays.asList("yy")));
|
||||
assertNotNull(result);
|
||||
assertEquals(3, result.size());
|
||||
assertEquals(" ┌xx┐ ", result.get(0));
|
||||
assertEquals("─┤ ├─", result.get(1));
|
||||
assertEquals(" └yy┘ ", result.get(2));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHtmlLength() {
|
||||
assertEquals(3, TreeAsciiUtil.htmlLength("abc"));
|
||||
assertEquals(1, TreeAsciiUtil.htmlLength(" "));
|
||||
assertEquals(1, TreeAsciiUtil.htmlLength("─"));
|
||||
assertEquals(5, TreeAsciiUtil.htmlLength("a b─c"));
|
||||
assertEquals(0, TreeAsciiUtil.htmlLength(""));
|
||||
assertEquals(0, TreeAsciiUtil.htmlLength(null));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGenerateString() {
|
||||
assertEquals("", TreeAsciiUtil.generateString("a", 0));
|
||||
assertEquals("", TreeAsciiUtil.generateString("a", -1));
|
||||
assertEquals("aaa", TreeAsciiUtil.generateString("a", 3));
|
||||
assertEquals(" ", TreeAsciiUtil.generateString(" ", 2));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testConcatenateMultiLineSerialSimple() {
|
||||
List<String> element1 = Arrays.asList("A", "B", "C");
|
||||
List<String> element2 = Arrays.asList("D", "E", "F");
|
||||
|
||||
List<List<String>> elements = Arrays.asList(element1, element2);
|
||||
List<String> result = TreeAsciiUtil.concatenateMultiLineSerial(" --- ", elements);
|
||||
|
||||
assertEquals(3, result.size());
|
||||
assertEquals("A D", result.get(0));
|
||||
assertEquals("B --- E", result.get(1));
|
||||
assertEquals("C F", result.get(2));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testConcatenateMultiLineSerialDifferentHeights() {
|
||||
List<String> element1 = Arrays.asList("A", "B", "C");
|
||||
List<String> element2 = Arrays.asList("D");
|
||||
|
||||
List<List<String>> elements = Arrays.asList(element1, element2);
|
||||
List<String> result = TreeAsciiUtil.concatenateMultiLineSerial(" --- ", elements);
|
||||
|
||||
assertEquals(3, result.size());
|
||||
assertEquals("A ", result.get(0));
|
||||
assertEquals("B --- D", result.get(1));
|
||||
assertEquals("C ", result.get(2));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testConcatenateMultiLineParallelSimple() {
|
||||
List<String> element1 = Arrays.asList("A", "B", "C");
|
||||
List<String> element2 = Arrays.asList("D", "E", "F");
|
||||
|
||||
List<List<String>> elements = Arrays.asList(element1, element2);
|
||||
List<String> result = TreeAsciiUtil.concatenateMultiLineParallel(elements);
|
||||
|
||||
assertEquals(7, result.size()); // 3 lines for element1 + 1 separator + 3 lines for element2
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testConcatenateMultiLineParallelEmptyInput() {
|
||||
assertEquals(0, TreeAsciiUtil.concatenateMultiLineParallel(Collections.emptyList()).size());
|
||||
assertEquals(0, TreeAsciiUtil.concatenateMultiLineParallel(null).size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testConcatenateMultiLineParallelSingleElement() {
|
||||
List<String> element = Arrays.asList("A", "B");
|
||||
List<List<String>> elements = Arrays.asList(element);
|
||||
|
||||
List<String> result = TreeAsciiUtil.concatenateMultiLineParallel(elements);
|
||||
assertEquals(2, result.size());
|
||||
// We just get back the original element
|
||||
assertEquals(element.size(), result.size());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,186 @@
|
||||
package org.diylc.utils;
|
||||
|
||||
import org.diylc.core.ISwitch;
|
||||
import org.junit.Test;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
public class SwitchUtilsTest {
|
||||
|
||||
// Mock switch implementation for testing
|
||||
private static class MockSwitch implements ISwitch {
|
||||
private final List<List<int[]>> connectionsByPosition;
|
||||
private final Integer selectedPosition;
|
||||
private final boolean renderConnected;
|
||||
private final int positionCount;
|
||||
|
||||
public MockSwitch(List<List<int[]>> connectionsByPosition, Integer selectedPosition, boolean renderConnected) {
|
||||
this.connectionsByPosition = connectionsByPosition;
|
||||
this.selectedPosition = selectedPosition;
|
||||
this.renderConnected = renderConnected;
|
||||
this.positionCount = connectionsByPosition.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean arePointsConnected(int index1, int index2, int position) {
|
||||
if (position >= connectionsByPosition.size()) return false;
|
||||
return connectionsByPosition.get(position).stream()
|
||||
.anyMatch(conn ->
|
||||
(conn[0] == index1 && conn[1] == index2) ||
|
||||
(conn[0] == index2 && conn[1] == index1));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer getSelectedPosition() {
|
||||
return selectedPosition;
|
||||
}
|
||||
|
||||
public Boolean getShowMarkers() {
|
||||
return renderConnected;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getPositionCount() {
|
||||
return positionCount;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPositionName(int position) {
|
||||
return String.valueOf(position + 1);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSimpleSPSTSwitch() {
|
||||
// Create a simple SPST switch with 2 points
|
||||
List<List<int[]>> connectionsByPosition = Arrays.asList(
|
||||
Arrays.asList(new int[]{0, 1}) // Position 0
|
||||
);
|
||||
MockSwitch mockSwitch = new MockSwitch(connectionsByPosition, 0, true);
|
||||
|
||||
String[] markers = SwitchUtils.getSwitchingMarkers(mockSwitch, 2, true);
|
||||
|
||||
// Both points are common in the only position
|
||||
assertEquals("A", markers[0]);
|
||||
assertEquals("B", markers[1]);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSPDTSwitch() {
|
||||
// Create an SPDT switch with 3 points
|
||||
List<List<int[]>> connectionsByPosition = Arrays.asList(
|
||||
Arrays.asList(new int[]{0, 1}), // Position 0
|
||||
Arrays.asList(new int[]{0, 2}) // Position 1
|
||||
);
|
||||
MockSwitch mockSwitch = new MockSwitch(connectionsByPosition, 0, true);
|
||||
|
||||
String[] markers = SwitchUtils.getSwitchingMarkers(mockSwitch, 3, true);
|
||||
|
||||
// Point 0 is common in all positions
|
||||
assertEquals("A", markers[0]);
|
||||
// Point 1 is connected to point 0 in position 0
|
||||
assertEquals("A1", markers[1]);
|
||||
// Point 2 is connected to point 0 in position 1
|
||||
assertEquals("A2", markers[2]);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDPDTSwitch() {
|
||||
// Create a DPDT switch with 6 points
|
||||
List<List<int[]>> connectionsByPosition = Arrays.asList(
|
||||
Arrays.asList(new int[]{0, 1}, new int[]{3, 4}), // Position 0
|
||||
Arrays.asList(new int[]{0, 2}, new int[]{3, 5}) // Position 1
|
||||
);
|
||||
MockSwitch mockSwitch = new MockSwitch(connectionsByPosition, 0, true);
|
||||
|
||||
String[] markers = SwitchUtils.getSwitchingMarkers(mockSwitch, 6, true);
|
||||
|
||||
// Points 0 and 3 are common in all positions
|
||||
assertEquals("A", markers[0]);
|
||||
assertEquals("A1", markers[1]);
|
||||
assertEquals("A2", markers[2]);
|
||||
assertEquals("B", markers[3]);
|
||||
assertEquals("B1", markers[4]);
|
||||
assertEquals("B2", markers[5]);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNonVerboseMarkers() {
|
||||
// Create a DPDT switch with 6 points
|
||||
List<List<int[]>> connectionsByPosition = Arrays.asList(
|
||||
Arrays.asList(new int[]{0, 1}, new int[]{3, 4}), // Position 0
|
||||
Arrays.asList(new int[]{0, 2}, new int[]{3, 5}) // Position 1
|
||||
);
|
||||
MockSwitch mockSwitch = new MockSwitch(connectionsByPosition, 0, true);
|
||||
|
||||
String[] markers = SwitchUtils.getSwitchingMarkers(mockSwitch, 6, false);
|
||||
|
||||
// Points 0 and 3 are common in all positions
|
||||
assertEquals("A", markers[0]);
|
||||
assertEquals("1", markers[1]);
|
||||
assertEquals("2", markers[2]);
|
||||
assertEquals("B", markers[3]);
|
||||
assertEquals("1", markers[4]);
|
||||
assertEquals("2", markers[5]);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMultiplePositions() {
|
||||
// Test switch with multiple positions
|
||||
List<List<int[]>> connectionsByPosition = Arrays.asList(
|
||||
Arrays.asList(new int[]{0, 1}), // Position 0
|
||||
Arrays.asList(new int[]{0, 2}), // Position 1
|
||||
Arrays.asList(new int[]{0, 3}) // Position 2
|
||||
);
|
||||
MockSwitch mockSwitch = new MockSwitch(connectionsByPosition, 0, true);
|
||||
|
||||
String[] markers = SwitchUtils.getSwitchingMarkers(mockSwitch, 4, true);
|
||||
|
||||
// Point 0 is common in all positions
|
||||
assertEquals("A", markers[0]);
|
||||
// Points 1, 2, 3 are connected to point 0 in positions 0, 1, 2 respectively
|
||||
assertEquals("A1", markers[1]);
|
||||
assertEquals("A2", markers[2]);
|
||||
assertEquals("A3", markers[3]);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNoConnections() {
|
||||
// Test switch with no connections
|
||||
List<List<int[]>> connectionsByPosition = Arrays.asList(
|
||||
Collections.emptyList() // Position 0 with no connections
|
||||
);
|
||||
MockSwitch mockSwitch = new MockSwitch(connectionsByPosition, 0, true);
|
||||
|
||||
String[] markers = SwitchUtils.getSwitchingMarkers(mockSwitch, 3, true);
|
||||
|
||||
// No common points when there are no connections
|
||||
assertNull(markers[0]);
|
||||
assertNull(markers[1]);
|
||||
assertNull(markers[2]);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testComplexSwitch() {
|
||||
// Test a more complex switch with multiple poles and positions
|
||||
List<List<int[]>> connectionsByPosition = Arrays.asList(
|
||||
Arrays.asList(new int[]{0, 1}, new int[]{3, 4}, new int[]{6, 7}), // Position 0
|
||||
Arrays.asList(new int[]{0, 2}, new int[]{3, 5}, new int[]{6, 8}) // Position 1
|
||||
);
|
||||
MockSwitch mockSwitch = new MockSwitch(connectionsByPosition, 0, true);
|
||||
|
||||
String[] markers = SwitchUtils.getSwitchingMarkers(mockSwitch, 9, true);
|
||||
|
||||
// Points 0, 3, and 6 are common in all positions
|
||||
assertEquals("A", markers[0]);
|
||||
assertEquals("A1", markers[1]);
|
||||
assertEquals("A2", markers[2]);
|
||||
assertEquals("B", markers[3]);
|
||||
assertEquals("B1", markers[4]);
|
||||
assertEquals("B2", markers[5]);
|
||||
assertEquals("C", markers[6]);
|
||||
assertEquals("C1", markers[7]);
|
||||
assertEquals("C2", markers[8]);
|
||||
}
|
||||
}
|
||||
@@ -7,7 +7,7 @@
|
||||
<parent>
|
||||
<groupId>org.diylc</groupId>
|
||||
<artifactId>diylc-parent</artifactId>
|
||||
<version>5.1.0</version>
|
||||
<version>5.2.0</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>diylc-library</artifactId>
|
||||
|
||||
@@ -79,6 +79,7 @@ public abstract class AbstractBoard extends AbstractTransparentComponent<String>
|
||||
|
||||
protected BoardUndersideDisplay boardUndersideDisplay = BoardUndersideDisplay.NONE;
|
||||
protected Size undersideOffset = DEFAULT_UNDERSIDE_OFFSET;
|
||||
private Boolean undersideTransparency = true;
|
||||
|
||||
@Override
|
||||
public void draw(Graphics2D g2d, ComponentState componentState, boolean outlineMode, Project project,
|
||||
@@ -372,14 +373,14 @@ public abstract class AbstractBoard extends AbstractTransparentComponent<String>
|
||||
|
||||
@EditableProperty(name = "Underside Display")
|
||||
@Override
|
||||
public BoardUndersideDisplay getBoardUndersideDisplay() {
|
||||
public BoardUndersideDisplay getUndersideDisplay() {
|
||||
if (this.boardUndersideDisplay == null) {
|
||||
this.boardUndersideDisplay = BoardUndersideDisplay.NONE;
|
||||
}
|
||||
return this.boardUndersideDisplay;
|
||||
}
|
||||
|
||||
public void setBoardUndersideDisplay(BoardUndersideDisplay boardUndersideDisplay) {
|
||||
public void setUndersideDisplay(BoardUndersideDisplay boardUndersideDisplay) {
|
||||
this.boardUndersideDisplay = boardUndersideDisplay;
|
||||
}
|
||||
|
||||
@@ -396,6 +397,19 @@ public abstract class AbstractBoard extends AbstractTransparentComponent<String>
|
||||
this.undersideOffset = undersideOffset;
|
||||
}
|
||||
|
||||
@EditableProperty(name = "Underside Transparency")
|
||||
@Override
|
||||
public Boolean getUndersideTransparency() {
|
||||
if (undersideTransparency == null) {
|
||||
undersideTransparency = true;
|
||||
}
|
||||
return undersideTransparency;
|
||||
}
|
||||
|
||||
public void setUndersideTransparency(Boolean undersideTransparency) {
|
||||
this.undersideTransparency = undersideTransparency;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Rectangle2D getBoardRectangle() {
|
||||
Point2D finalSecondPoint = getFinalSecondPoint();
|
||||
@@ -452,4 +466,4 @@ public abstract class AbstractBoard extends AbstractTransparentComponent<String>
|
||||
return label;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+243
@@ -0,0 +1,243 @@
|
||||
/*
|
||||
*
|
||||
* DIY Layout Creator (DIYLC). Copyright (c) 2009-2018 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.connectivity;
|
||||
|
||||
import java.awt.AlphaComposite;
|
||||
import java.awt.Color;
|
||||
import java.awt.Composite;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.Shape;
|
||||
import java.awt.geom.AffineTransform;
|
||||
import java.awt.geom.Path2D;
|
||||
import java.awt.geom.Point2D;
|
||||
import java.awt.geom.Rectangle2D;
|
||||
|
||||
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.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;
|
||||
|
||||
@ComponentDescriptor(name = "Multimeter Probe", category = "Connectivity",
|
||||
author = "Branislav Stojkovic", description = "Multimeter Probe", instanceNamePrefix = "Probe",
|
||||
zOrder = IDIYComponent.TEXT, bomPolicy = BomPolicy.NEVER_SHOW, autoEdit = false,
|
||||
keywordPolicy = KeywordPolicy.SHOW_TYPE_NAME, transformer = SimpleComponentTransformer.class,
|
||||
enableCache = true)
|
||||
public class MultimeterProbe extends AbstractTransparentComponent<Color> {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public static Size PROBE_DIAMETER = new Size(0.05d, SizeUnit.in);
|
||||
public static Size PROBE_LENGTH = new Size(0.4d, SizeUnit.in);
|
||||
public static Color PROBE_COLOR = METAL_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;
|
||||
|
||||
private Point2D.Double point = new Point2D.Double(0, 0);
|
||||
private Color handleColor = HANDLE_COLOR;
|
||||
private Orientation45 orientation = Orientation45._315;
|
||||
|
||||
private transient Shape[] body = null;
|
||||
|
||||
public MultimeterProbe() {
|
||||
this.alpha = (byte) (MAX_ALPHA / 2);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void draw(Graphics2D g2d, ComponentState componentState, boolean outlineMode,
|
||||
Project project, IDrawingObserver drawingObserver) {
|
||||
|
||||
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);
|
||||
}
|
||||
g2d.setColor(
|
||||
componentState == ComponentState.SELECTED || componentState == ComponentState.DRAGGING
|
||||
? SELECTION_COLOR
|
||||
: handleColor.darker());
|
||||
g2d.draw(shapes[1]);
|
||||
g2d.setColor(
|
||||
componentState == ComponentState.SELECTED || componentState == ComponentState.DRAGGING
|
||||
? SELECTION_COLOR
|
||||
: PROBE_COLOR.darker());
|
||||
g2d.draw(shapes[0]);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void drawIcon(Graphics2D g2d, int width, int height) {
|
||||
double probeDiameter = 2;
|
||||
double probeLength = height / 2 + 2;
|
||||
double handleDiameter = width / 4;
|
||||
double handleLength = height / 2 + 2;
|
||||
double x = 2;
|
||||
double y = height - 2;
|
||||
Shape probe = buildProbeShape(probeDiameter, probeLength, x, y);
|
||||
Shape handle = buildHandleShape(probeDiameter, probeLength, handleDiameter, handleLength, x, y);
|
||||
|
||||
double theta = Math.PI / 4;
|
||||
AffineTransform tx = AffineTransform.getRotateInstance(theta, x, y);
|
||||
probe = tx.createTransformedShape(probe);
|
||||
handle = tx.createTransformedShape(handle);
|
||||
|
||||
g2d.setColor(PROBE_COLOR);
|
||||
g2d.fill(probe);
|
||||
g2d.setColor(HANDLE_COLOR);
|
||||
g2d.fill(handle);
|
||||
|
||||
g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(1));
|
||||
g2d.setColor(PROBE_COLOR.darker());
|
||||
g2d.draw(probe);
|
||||
g2d.setColor(HANDLE_COLOR.darker());
|
||||
g2d.draw(handle);
|
||||
}
|
||||
|
||||
public Shape[] getBody() {
|
||||
if (body == null) {
|
||||
double probeDiameter = PROBE_DIAMETER.convertToPixels();
|
||||
double probeLength = PROBE_LENGTH.convertToPixels();
|
||||
double handleDiameter = HANDLE_DIAMETER.convertToPixels();
|
||||
double handleLength = HANDLE_LENGTH.convertToPixels();
|
||||
double x = point.getX();
|
||||
double y = point.getY();
|
||||
body = new Shape[2];
|
||||
Path2D probe = buildProbeShape(probeDiameter, probeLength, x, y);
|
||||
body[0] = probe;
|
||||
Path2D handle =
|
||||
buildHandleShape(probeDiameter, probeLength, handleDiameter, handleLength, x, y);
|
||||
body[1] = handle;
|
||||
|
||||
double theta = orientation.toRadians();
|
||||
if (theta != 0) {
|
||||
AffineTransform tx = AffineTransform.getRotateInstance(theta, x, y);
|
||||
body[0] = tx.createTransformedShape(body[0]);
|
||||
body[1] = tx.createTransformedShape(body[1]);
|
||||
}
|
||||
}
|
||||
return body;
|
||||
}
|
||||
|
||||
private Path2D buildHandleShape(double probeDiameter, double probeLength, double handleDiameter,
|
||||
double handleLength, double x, double y) {
|
||||
Path2D handle = new Path2D.Double();
|
||||
handle.moveTo(x + probeDiameter, y - probeLength);
|
||||
handle.lineTo(x + handleDiameter / 2, y - handleLength - probeLength);
|
||||
handle.lineTo(x - handleDiameter / 2, y - handleLength - probeLength);
|
||||
handle.lineTo(x - probeDiameter, y - probeLength);
|
||||
handle.moveTo(x + probeDiameter, y - probeLength);
|
||||
handle.closePath();
|
||||
return handle;
|
||||
}
|
||||
|
||||
private Path2D buildProbeShape(double probeDiameter, double probeLength, double x, double y) {
|
||||
Path2D probe = new Path2D.Double();
|
||||
probe.moveTo(x, y);
|
||||
probe.lineTo(x - probeDiameter / 2, y - probeDiameter);
|
||||
probe.lineTo(x - probeDiameter / 2, y - probeLength);
|
||||
probe.lineTo(x + probeDiameter / 2, y - probeLength);
|
||||
probe.lineTo(x + probeDiameter / 2, y - probeDiameter);
|
||||
probe.lineTo(x, y);
|
||||
probe.closePath();
|
||||
return probe;
|
||||
}
|
||||
|
||||
@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);
|
||||
this.body = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
@EditableProperty(name = "Color")
|
||||
public Color getValue() {
|
||||
return handleColor;
|
||||
}
|
||||
|
||||
public void setValue(Color color) {
|
||||
this.handleColor = color;
|
||||
}
|
||||
|
||||
@EditableProperty(name = "Angle")
|
||||
public Orientation45 getOrientation() {
|
||||
return orientation;
|
||||
}
|
||||
|
||||
public void setOrientation(Orientation45 orientation) {
|
||||
this.orientation = orientation;
|
||||
this.body = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getControlPointNodeName(int index) {
|
||||
return "Tip";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Rectangle2D getCachingBounds() {
|
||||
Shape[] shapes = getBody();
|
||||
Rectangle2D bounds1 = shapes[0].getBounds2D();
|
||||
Rectangle2D bounds2 = shapes[1].getBounds2D();
|
||||
double minX = Math.min(bounds1.getMinX(), bounds2.getMinX());
|
||||
double minY = Math.min(bounds1.getMinY(), bounds2.getMinY());
|
||||
double maxX = Math.max(bounds1.getMaxX(), bounds2.getMaxX());
|
||||
double maxY = Math.max(bounds1.getMaxY(), bounds2.getMaxY());
|
||||
return new Rectangle2D.Double(minX - 1, minY - 1, maxX - minX + 2, maxY - minY + 2);
|
||||
}
|
||||
}
|
||||
+112
-53
@@ -31,12 +31,13 @@ import java.awt.geom.Area;
|
||||
import java.awt.geom.Point2D;
|
||||
import java.awt.geom.Rectangle2D;
|
||||
import java.awt.geom.RoundRectangle2D;
|
||||
|
||||
import org.diylc.appframework.miscutils.ConfigurationManager;
|
||||
|
||||
import org.diylc.common.IPlugInPort;
|
||||
import org.diylc.common.ObjectCache;
|
||||
import org.diylc.common.OrientationHV;
|
||||
import org.diylc.awt.StringUtils;
|
||||
import org.diylc.common.*;
|
||||
import org.diylc.components.AbstractTransparentComponent;
|
||||
import org.diylc.components.guitar.ToggleSwitchPositionPropertyValueSource;
|
||||
import org.diylc.components.transform.MiniToggleSwitchTransformer;
|
||||
import org.diylc.core.ComponentState;
|
||||
import org.diylc.core.IDIYComponent;
|
||||
@@ -47,12 +48,14 @@ import org.diylc.core.Project;
|
||||
import org.diylc.core.Theme;
|
||||
import org.diylc.core.VisibilityPolicy;
|
||||
import org.diylc.core.annotations.ComponentDescriptor;
|
||||
import org.diylc.core.annotations.DynamicEditableProperty;
|
||||
import org.diylc.core.annotations.EditableProperty;
|
||||
import org.diylc.core.annotations.PositiveNonZeroMeasureValidator;
|
||||
import org.diylc.core.gerber.IGerberComponentSimple;
|
||||
import org.diylc.core.measures.Size;
|
||||
import org.diylc.core.measures.SizeUnit;
|
||||
import org.diylc.utils.Constants;
|
||||
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,
|
||||
@@ -66,10 +69,14 @@ public class MiniToggleSwitch extends AbstractTransparentComponent<ToggleSwitchT
|
||||
private static Size CIRCLE_SIZE = new Size(0.09d, SizeUnit.in);
|
||||
private static Size LUG_WIDTH = new Size(0.060d, SizeUnit.in);
|
||||
private static Size LUG_THICKNESS = new Size(0.02d, SizeUnit.in);
|
||||
private static Size MARKER_OFFSET = new Size(0.07d, SizeUnit.in);
|
||||
|
||||
private static Color BODY_COLOR = Color.decode("#3299CC");
|
||||
private static Color BORDER_COLOR = BODY_COLOR.darker();
|
||||
private static Color CIRCLE_COLOR = Color.decode("#FFFFAA");
|
||||
private static Color CIRCLE_COLOR = Color.decode("#287ba4");
|
||||
private static Color TERMINAL_COLOR = LIGHT_METAL_COLOR;
|
||||
private static Color MARKER_COLOR = LIGHT_METAL_COLOR;
|
||||
|
||||
|
||||
protected Point2D[] controlPoints = new Point2D[] {new Point2D.Double(0, 0)};
|
||||
transient protected Shape body;
|
||||
@@ -79,6 +86,11 @@ public class MiniToggleSwitch extends AbstractTransparentComponent<ToggleSwitchT
|
||||
|
||||
private Color bodyColor = BODY_COLOR;
|
||||
private Color borderColor = BORDER_COLOR;
|
||||
private Color terminalPadColor = CIRCLE_COLOR;
|
||||
private Color terminalColor = TERMINAL_COLOR;
|
||||
|
||||
private Integer selectedPosition;
|
||||
private Boolean showMarkers;
|
||||
|
||||
@Deprecated
|
||||
protected String name;
|
||||
@@ -112,17 +124,6 @@ public class MiniToggleSwitch extends AbstractTransparentComponent<ToggleSwitchT
|
||||
new Point2D.Double(firstPoint.getX() + spacing, firstPoint.getY() + spacing),
|
||||
new Point2D.Double(firstPoint.getX() + spacing, firstPoint.getY() + 2 * spacing)};
|
||||
break;
|
||||
case _DP3T_mustang:
|
||||
controlPoints =
|
||||
new Point2D[] {firstPoint,
|
||||
new Point2D.Double(firstPoint.getX(), firstPoint.getY() + spacing),
|
||||
new Point2D.Double(firstPoint.getX(), firstPoint.getY() + 2 * spacing),
|
||||
new Point2D.Double(firstPoint.getX(), firstPoint.getY() + 3 * spacing),
|
||||
new Point2D.Double(firstPoint.getX() + spacing, firstPoint.getY()),
|
||||
new Point2D.Double(firstPoint.getX() + spacing, firstPoint.getY() + spacing),
|
||||
new Point2D.Double(firstPoint.getX() + spacing, firstPoint.getY() + 2 * spacing),
|
||||
new Point2D.Double(firstPoint.getX() + spacing, firstPoint.getY() + 3 * spacing)};
|
||||
break;
|
||||
case _3PDT:
|
||||
case _3PDT_off:
|
||||
controlPoints =
|
||||
@@ -313,8 +314,9 @@ public class MiniToggleSwitch extends AbstractTransparentComponent<ToggleSwitchT
|
||||
lugWidth = getClosestOdd((int) LUG_WIDTH.convertToPixels());
|
||||
lugHeight = getClosestOdd((int) LUG_THICKNESS.convertToPixels());
|
||||
}
|
||||
|
||||
for (Point2D p : controlPoints) {
|
||||
|
||||
for (int i = 0; i < controlPoints.length; i++) {
|
||||
Point2D p = controlPoints[i];
|
||||
if (outlineMode) {
|
||||
// g2d.setColor(Constants.TRANSPARENT_COLOR);
|
||||
// drawingObserver.startTrackingContinuityArea(true);
|
||||
@@ -322,16 +324,46 @@ public class MiniToggleSwitch extends AbstractTransparentComponent<ToggleSwitchT
|
||||
// drawingObserver.stopTrackingContinuityArea();
|
||||
|
||||
g2d.setColor(theme.getOutlineColor());
|
||||
g2d.drawRect((int)(p.getX() - lugWidth / 2), (int)(p.getY() - lugHeight / 2), lugWidth, lugHeight);
|
||||
g2d.drawRect((int)(p.getX() - lugWidth / 2d), (int)(p.getY() - lugHeight / 2d), lugWidth, lugHeight);
|
||||
} else {
|
||||
g2d.setColor(CIRCLE_COLOR);
|
||||
g2d.fillOval((int)(p.getX() - circleDiameter / 2), (int)(p.getY() - circleDiameter / 2), circleDiameter, circleDiameter);
|
||||
g2d.setColor(METAL_COLOR);
|
||||
g2d.setColor(getTerminalPadColor().darker());
|
||||
|
||||
g2d.drawOval((int)(p.getX() - circleDiameter / 2d), (int)(p.getY() - circleDiameter / 2d), circleDiameter, circleDiameter);
|
||||
|
||||
g2d.setColor(getTerminalPadColor());
|
||||
g2d.fillOval((int)(p.getX() - circleDiameter / 2d), (int)(p.getY() - circleDiameter / 2d), circleDiameter, circleDiameter);
|
||||
g2d.setColor(getTerminalColor());
|
||||
// drawingObserver.startTrackingContinuityArea(true);
|
||||
g2d.fillRect((int)(p.getX() - lugWidth / 2), (int)(p.getY() - lugHeight / 2), lugWidth, lugHeight);
|
||||
g2d.fillRect((int)(p.getX() - lugWidth / 2d), (int)(p.getY() - lugHeight / 2d), lugWidth, lugHeight);
|
||||
// drawingObserver.stopTrackingContinuityArea();
|
||||
}
|
||||
}
|
||||
|
||||
if (getShowMarkers()) {
|
||||
String[] markers =
|
||||
SwitchUtils.getSwitchingMarkers(this, getControlPointCount(), false);
|
||||
|
||||
g2d.setColor(MARKER_COLOR);
|
||||
|
||||
double offset = MARKER_OFFSET.convertToPixels();
|
||||
for (int i = 0; i < getControlPointCount(); i++) {
|
||||
if (markers[i] == null)
|
||||
continue;
|
||||
|
||||
Point2D p = getControlPoint(i);
|
||||
Point2D labelPoint = new Point2D.Double(offset, 0);
|
||||
|
||||
AffineTransform tx = null;
|
||||
if (getOrientation() == OrientationHV.HORIZONTAL) {
|
||||
tx = AffineTransform.getRotateInstance(-Math.PI / 2, 0, 0);
|
||||
}
|
||||
if (tx != null) {
|
||||
tx.transform(labelPoint, labelPoint);
|
||||
}
|
||||
StringUtils.drawCenteredText(g2d, markers[i], p.getX() + labelPoint.getX(), p.getY() + labelPoint.getY(),
|
||||
HorizontalAlignment.CENTER, VerticalAlignment.CENTER);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public Shape getBody() {
|
||||
@@ -359,11 +391,6 @@ public class MiniToggleSwitch extends AbstractTransparentComponent<ToggleSwitchT
|
||||
new RoundRectangle2D.Double(firstPoint.getX() - margin, firstPoint.getY() - margin, 2 * margin + spacing, 2
|
||||
* margin + 2 * spacing, margin, margin);
|
||||
break;
|
||||
case _DP3T_mustang:
|
||||
body =
|
||||
new RoundRectangle2D.Double(firstPoint.getX() - margin, firstPoint.getY() - margin, 2 * margin + spacing, 2
|
||||
* margin + 3 * spacing, margin, margin);
|
||||
break;
|
||||
case _3PDT:
|
||||
case _3PDT_off:
|
||||
body =
|
||||
@@ -402,7 +429,7 @@ public class MiniToggleSwitch extends AbstractTransparentComponent<ToggleSwitchT
|
||||
g2d.setColor(BORDER_COLOR);
|
||||
g2d.drawRoundRect(width / 4, 1, width / 2, height - 2, circleSize, circleSize);
|
||||
for (int i = 1; i <= 3; i++) {
|
||||
g2d.setColor(CIRCLE_COLOR);
|
||||
g2d.setColor(LIGHT_METAL_COLOR);
|
||||
g2d.fillOval(width / 2 - circleSize / 2, i * height / 4 - 3, circleSize, circleSize);
|
||||
g2d.setColor(METAL_COLOR);
|
||||
g2d.drawLine(width / 2 - circleSize / 2 + 1, i * height / 4 - 1, width / 2 + circleSize / 2 - 1, i * height / 4
|
||||
@@ -431,7 +458,31 @@ public class MiniToggleSwitch extends AbstractTransparentComponent<ToggleSwitchT
|
||||
public void setBorderColor(Color borderColor) {
|
||||
this.borderColor = borderColor;
|
||||
}
|
||||
|
||||
|
||||
@EditableProperty(name = "Pad")
|
||||
public Color getTerminalPadColor() {
|
||||
if (terminalPadColor == null) {
|
||||
terminalPadColor = CIRCLE_COLOR;
|
||||
}
|
||||
return terminalPadColor;
|
||||
}
|
||||
|
||||
public void setTerminalPadColor(Color terminalPadColor) {
|
||||
this.terminalPadColor = terminalPadColor;
|
||||
}
|
||||
|
||||
@EditableProperty(name = "Terminal")
|
||||
public Color getTerminalColor() {
|
||||
if (terminalColor == null) {
|
||||
terminalColor = TERMINAL_COLOR;
|
||||
}
|
||||
return terminalColor;
|
||||
}
|
||||
|
||||
public void setTerminalColor(Color terminalColor) {
|
||||
this.terminalColor = terminalColor;
|
||||
}
|
||||
|
||||
// switch stuff
|
||||
//
|
||||
// @Override
|
||||
@@ -447,27 +498,7 @@ public class MiniToggleSwitch extends AbstractTransparentComponent<ToggleSwitchT
|
||||
|
||||
@Override
|
||||
public int getPositionCount() {
|
||||
switch (switchType) {
|
||||
case SPST:
|
||||
case SPDT:
|
||||
case DPDT:
|
||||
case _3PDT:
|
||||
case _4PDT:
|
||||
case _5PDT:
|
||||
return 2;
|
||||
case _DP3T_mustang:
|
||||
case SPDT_off:
|
||||
case DPDT_off:
|
||||
case _3PDT_off:
|
||||
case _4PDT_off:
|
||||
case _4PDT_ononon_1:
|
||||
case _4PDT_ononon_2:
|
||||
case _5PDT_off:
|
||||
case DPDT_ononon_1:
|
||||
case DPDT_ononon_2:
|
||||
return 3;
|
||||
}
|
||||
return 2;
|
||||
return switchType.getPositionCount();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -477,8 +508,34 @@ public class MiniToggleSwitch extends AbstractTransparentComponent<ToggleSwitchT
|
||||
return "ON" + Integer.toString(position + 1);
|
||||
}
|
||||
|
||||
@DynamicEditableProperty(source = ToggleSwitchPositionPropertyValueSource.class)
|
||||
@EditableProperty(name = "Selected Position")
|
||||
@Override
|
||||
public Integer getSelectedPosition() {
|
||||
return selectedPosition;
|
||||
}
|
||||
|
||||
public void setSelectedPosition(Integer selectedPosition) {
|
||||
this.selectedPosition = selectedPosition;
|
||||
}
|
||||
|
||||
@EditableProperty(name = "Markers")
|
||||
public Boolean getShowMarkers() {
|
||||
if (showMarkers == null) {
|
||||
showMarkers = false;
|
||||
}
|
||||
return showMarkers;
|
||||
}
|
||||
|
||||
public void setShowMarkers(Boolean showMarkers) {
|
||||
this.showMarkers = showMarkers;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean arePointsConnected(int index1, int index2, int position) {
|
||||
if (index1 >= index2)
|
||||
return false;
|
||||
|
||||
switch (switchType) {
|
||||
case SPST:
|
||||
return position == 0;
|
||||
@@ -493,9 +550,11 @@ public class MiniToggleSwitch extends AbstractTransparentComponent<ToggleSwitchT
|
||||
case _3PDT_off:
|
||||
case _4PDT_off:
|
||||
case _5PDT_off:
|
||||
return position != 2 && (index2 - index1) < 3 && index1 % 3 == position && index2 % 3 == position + 1;
|
||||
case _DP3T_mustang:
|
||||
return (index2 - index1) < 3 && index1 % 3 == 0 && index2 % 3 == position + 1;
|
||||
if (position == 1)
|
||||
return false;
|
||||
if (position == 2)
|
||||
position = 1;
|
||||
return (index2 - index1) < 3 && index1 % 3 == position && index2 % 3 == position + 1;
|
||||
case DPDT_ononon_1:
|
||||
switch (position) {
|
||||
case 0:
|
||||
|
||||
+27
-60
@@ -32,6 +32,9 @@ import java.awt.geom.Rectangle2D;
|
||||
import java.awt.geom.RoundRectangle2D;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.stream.IntStream;
|
||||
|
||||
import org.diylc.appframework.miscutils.ConfigurationManager;
|
||||
|
||||
import org.diylc.awt.StringUtils;
|
||||
@@ -41,6 +44,7 @@ import org.diylc.common.IPlugInPort;
|
||||
import org.diylc.common.ObjectCache;
|
||||
import org.diylc.common.VerticalAlignment;
|
||||
import org.diylc.components.AbstractAngledComponent;
|
||||
import org.diylc.components.guitar.RotarySwitchOpenPositionPropertyValueSource;
|
||||
import org.diylc.components.transform.AngledComponentTransformer;
|
||||
import org.diylc.core.Angle;
|
||||
import org.diylc.core.ComponentState;
|
||||
@@ -51,6 +55,7 @@ import org.diylc.core.Project;
|
||||
import org.diylc.core.Theme;
|
||||
import org.diylc.core.VisibilityPolicy;
|
||||
import org.diylc.core.annotations.ComponentDescriptor;
|
||||
import org.diylc.core.annotations.DynamicEditableProperty;
|
||||
import org.diylc.core.annotations.EditableProperty;
|
||||
import org.diylc.core.annotations.KeywordPolicy;
|
||||
import org.diylc.core.gerber.IGerberComponentSimple;
|
||||
@@ -58,6 +63,7 @@ import org.diylc.core.measures.Size;
|
||||
import org.diylc.core.measures.SizeUnit;
|
||||
import org.diylc.presenter.AreaUtils;
|
||||
import org.diylc.utils.Constants;
|
||||
import org.diylc.utils.SwitchUtils;
|
||||
|
||||
@ComponentDescriptor(name = "Rotary Switch (Open)", author = "Branislav Stojkovic",
|
||||
category = "Electro-Mechanical", instanceNamePrefix = "SW",
|
||||
@@ -99,6 +105,8 @@ public class RotarySwitchOpen extends AbstractAngledComponent<RotarySwitchOpenTy
|
||||
private Point2D[] controlPoints = new Point2D[] {new Point2D.Double(0, 0)};
|
||||
private double[] pointAngles;
|
||||
|
||||
private Integer selectedPosition;
|
||||
|
||||
public RotarySwitchOpen() {
|
||||
super();
|
||||
updateControlPoints();
|
||||
@@ -246,7 +254,6 @@ public class RotarySwitchOpen extends AbstractAngledComponent<RotarySwitchOpenTy
|
||||
|
||||
bodyList.add(bodyArea);
|
||||
|
||||
|
||||
int pinWidth = getClosestOdd(PIN_WIDTH.convertToPixels());
|
||||
int pinThickness = getClosestOdd(PIN_THICKNESS.convertToPixels());
|
||||
|
||||
@@ -391,7 +398,10 @@ public class RotarySwitchOpen extends AbstractAngledComponent<RotarySwitchOpenTy
|
||||
// StringUtils.drawCenteredText(g2d, name, controlPoints[0].getX(), controlPoints[0].getY(),
|
||||
// HorizontalAlignment.CENTER, VerticalAlignment.CENTER);
|
||||
|
||||
if (showMarkers) {
|
||||
String[] switchingMarkers =
|
||||
SwitchUtils.getSwitchingMarkers(this, this.getControlPointCount(), false);
|
||||
|
||||
if (getShowMarkers()) {
|
||||
g2d.setColor(labelColor);
|
||||
int innerPinSpacing = getClosestOdd(INNER_PIN_SPACING.convertToPixels());
|
||||
int innerCommonPinSpacing = getClosestOdd(INNER_COMMON_PIN_SPACING.convertToPixels());
|
||||
@@ -403,7 +413,7 @@ public class RotarySwitchOpen extends AbstractAngledComponent<RotarySwitchOpenTy
|
||||
+ Math.cos(pointAngles[i + 1]) * relativeLabelLocation * innerPinSpacing / 2);
|
||||
int y = (int) (firstPoint.getY()
|
||||
+ Math.sin(pointAngles[i + 1]) * relativeLabelLocation * innerPinSpacing / 2);
|
||||
StringUtils.drawCenteredText(g2d, getControlPointNodeNameForRender(i + 1), x, y,
|
||||
StringUtils.drawCenteredText(g2d, switchingMarkers[i + 1], x, y,
|
||||
HorizontalAlignment.CENTER, VerticalAlignment.CENTER);
|
||||
}
|
||||
relativeLabelLocation = 0.65;
|
||||
@@ -412,7 +422,7 @@ public class RotarySwitchOpen extends AbstractAngledComponent<RotarySwitchOpenTy
|
||||
* relativeLabelLocation * innerCommonPinSpacing / 2);
|
||||
int y = (int) (firstPoint.getY() + Math.sin(pointAngles[i + outerPinCount + 1])
|
||||
* relativeLabelLocation * innerCommonPinSpacing / 2);
|
||||
StringUtils.drawCenteredText(g2d, getControlPointNodeNameForRender(i + outerPinCount + 1),
|
||||
StringUtils.drawCenteredText(g2d, switchingMarkers[i + outerPinCount + 1],
|
||||
x, y, HorizontalAlignment.CENTER, VerticalAlignment.CENTER);
|
||||
}
|
||||
|
||||
@@ -427,7 +437,7 @@ public class RotarySwitchOpen extends AbstractAngledComponent<RotarySwitchOpenTy
|
||||
int y = (int) (firstPoint.getY() + Math.sin(pointAngles[i + 1 + secondLevelStart])
|
||||
* relativeLabelLocation * outerPinSpacing / 2);
|
||||
StringUtils.drawCenteredText(g2d,
|
||||
getControlPointNodeNameForRender(i + 1 + secondLevelStart), x, y,
|
||||
switchingMarkers[i + secondLevelStart + 1], x, y,
|
||||
HorizontalAlignment.CENTER, VerticalAlignment.CENTER);
|
||||
}
|
||||
// relativeLabelLocation = 0.90;
|
||||
@@ -439,7 +449,7 @@ public class RotarySwitchOpen extends AbstractAngledComponent<RotarySwitchOpenTy
|
||||
+ Math.sin(pointAngles[i + outerPinCount + 1 + secondLevelStart])
|
||||
* relativeLabelLocation * outerCommonPinSpacing / 2);
|
||||
StringUtils.drawCenteredText(g2d,
|
||||
getControlPointNodeNameForRender(i + outerPinCount + 1 + secondLevelStart), x, y,
|
||||
switchingMarkers[i + outerPinCount + secondLevelStart + 1], x, y,
|
||||
HorizontalAlignment.CENTER, VerticalAlignment.CENTER);
|
||||
}
|
||||
}
|
||||
@@ -562,6 +572,17 @@ public class RotarySwitchOpen extends AbstractAngledComponent<RotarySwitchOpenTy
|
||||
body = null;
|
||||
}
|
||||
|
||||
@DynamicEditableProperty(source = RotarySwitchOpenPositionPropertyValueSource.class)
|
||||
@EditableProperty(name = "Selected Position")
|
||||
@Override
|
||||
public Integer getSelectedPosition() {
|
||||
return selectedPosition;
|
||||
}
|
||||
|
||||
public void setSelectedPosition(Integer selectedPosition) {
|
||||
this.selectedPosition = selectedPosition;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Rectangle2D getCachingBounds() {
|
||||
Shape[] body = getBody();
|
||||
@@ -607,60 +628,6 @@ public class RotarySwitchOpen extends AbstractAngledComponent<RotarySwitchOpenTy
|
||||
return Integer.toString(position + 1);
|
||||
}
|
||||
|
||||
public String getControlPointNodeNameForRender(int index) {
|
||||
int commonPinCount = 2;
|
||||
int positionCount = configuration.getPositionCount();
|
||||
|
||||
if (index <= positionCount) {
|
||||
return Integer.toString(positionCount + 1 - index);
|
||||
}
|
||||
if (index <= 2 * positionCount) {
|
||||
return Integer.toString(2 * positionCount + 1 - index);
|
||||
}
|
||||
if (index <= 2 * positionCount + commonPinCount) {
|
||||
return Character.toString((char) ('A' + (index - 2 * positionCount - 1)));
|
||||
}
|
||||
int secondLevelStart = 2 * positionCount + commonPinCount;
|
||||
if (index <= positionCount + secondLevelStart) {
|
||||
return Integer.toString(positionCount + 1 - index + secondLevelStart);
|
||||
}
|
||||
if (index <= 2 * positionCount + secondLevelStart) {
|
||||
return Integer.toString(2 * positionCount + 1 - index + secondLevelStart);
|
||||
}
|
||||
if (index <= 2 * positionCount + commonPinCount + secondLevelStart) {
|
||||
return Character.toString((char) ('C' + (index - 2 * positionCount - 1 - secondLevelStart)));
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getControlPointNodeName(int index) {
|
||||
int commonPinCount = 2;
|
||||
int positionCount = configuration.getPositionCount();
|
||||
|
||||
if (index <= positionCount) {
|
||||
return "A" + (positionCount + 1 - index);
|
||||
}
|
||||
if (index <= 2 * positionCount) {
|
||||
return "B" + (2 * positionCount + 1 - index);
|
||||
}
|
||||
if (index <= 2 * positionCount + commonPinCount) {
|
||||
return Character.toString((char) ('A' + (index - 2 * positionCount - 1)));
|
||||
}
|
||||
|
||||
int secondLevelStart = 2 * positionCount + commonPinCount;
|
||||
if (index <= positionCount + secondLevelStart) {
|
||||
return "C" + (positionCount + 1 - index + secondLevelStart);
|
||||
}
|
||||
if (index <= 2 * positionCount + secondLevelStart) {
|
||||
return "D" + (2 * positionCount + 1 - index + secondLevelStart);
|
||||
}
|
||||
if (index <= 2 * positionCount + commonPinCount + secondLevelStart) {
|
||||
return Character.toString((char) ('C' + (index - 2 * positionCount - 1 - secondLevelStart)));
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean arePointsConnected(int index1, int index2, int position) {
|
||||
if (index1 == 0)
|
||||
|
||||
+105
-36
@@ -29,12 +29,16 @@ import java.awt.geom.Ellipse2D;
|
||||
import java.awt.geom.Point2D;
|
||||
import java.awt.geom.Rectangle2D;
|
||||
import java.awt.geom.RoundRectangle2D;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.stream.IntStream;
|
||||
|
||||
import org.diylc.appframework.miscutils.ConfigurationManager;
|
||||
|
||||
import org.diylc.common.IPlugInPort;
|
||||
import org.diylc.common.ObjectCache;
|
||||
import org.diylc.common.OrientationHV;
|
||||
import org.diylc.awt.StringUtils;
|
||||
import org.diylc.common.*;
|
||||
import org.diylc.components.AbstractTransparentComponent;
|
||||
import org.diylc.components.guitar.Freeway3x4_03SwitchPositionPropertyValueSource;
|
||||
import org.diylc.components.transform.MiniToggleSwitchTransformer;
|
||||
import org.diylc.core.ComponentState;
|
||||
import org.diylc.core.IDIYComponent;
|
||||
@@ -44,12 +48,14 @@ import org.diylc.core.Project;
|
||||
import org.diylc.core.Theme;
|
||||
import org.diylc.core.VisibilityPolicy;
|
||||
import org.diylc.core.annotations.ComponentDescriptor;
|
||||
import org.diylc.core.annotations.DynamicEditableProperty;
|
||||
import org.diylc.core.annotations.EditableProperty;
|
||||
import org.diylc.core.annotations.PositiveNonZeroMeasureValidator;
|
||||
import org.diylc.core.gerber.IGerberComponentSimple;
|
||||
import org.diylc.core.measures.Size;
|
||||
import org.diylc.core.measures.SizeUnit;
|
||||
import org.diylc.utils.Constants;
|
||||
import org.diylc.utils.SwitchUtils;
|
||||
|
||||
@ComponentDescriptor(name = "Slide Switch", category = "Electro-Mechanical",
|
||||
author = "Branislav Stojkovic", description = "Panel mounted slide switch",
|
||||
@@ -65,12 +71,14 @@ public class SlideSwitch extends AbstractTransparentComponent<SlideSwitchType> i
|
||||
private static Size LUG_WIDTH = new Size(0.020d, SizeUnit.in);
|
||||
private static Size LUG_THICKNESS = new Size(0.1d, SizeUnit.in);
|
||||
private static Size HOLE_DIAMETER = new Size(3d, SizeUnit.mm);
|
||||
private static Size MARKER_OFFSET = new Size(0.05d, SizeUnit.in);
|
||||
|
||||
private static Color BODY_COLOR = PHENOLIC_DARK_COLOR;
|
||||
private static Color BORDER_COLOR = Color.gray;
|
||||
public static Color TERMINAL_COLOR = METAL_COLOR;
|
||||
public static Color LABEL_COLOR = Color.white;
|
||||
public static Color BRACKET_COLOR = Color.lightGray;
|
||||
public static Color MARKER_COLOR = Color.lightGray;
|
||||
|
||||
protected Point2D[] controlPoints = new Point2D[] {new Point2D.Double(0, 0)};
|
||||
transient protected Shape[] body;
|
||||
@@ -85,6 +93,9 @@ public class SlideSwitch extends AbstractTransparentComponent<SlideSwitchType> i
|
||||
private Color bracketColor = BRACKET_COLOR;
|
||||
private Boolean showBracket = true;
|
||||
|
||||
private Integer selectedPosition;
|
||||
private Boolean showMarkers;
|
||||
|
||||
public SlideSwitch() {
|
||||
super();
|
||||
updateControlPoints();
|
||||
@@ -122,9 +133,10 @@ public class SlideSwitch extends AbstractTransparentComponent<SlideSwitchType> i
|
||||
firstPoint.getY() + 3 * rowSpacing)};
|
||||
break;
|
||||
}
|
||||
AffineTransform xform =
|
||||
AffineTransform.getRotateInstance(-Math.PI / 2, firstPoint.getX(), firstPoint.getY());
|
||||
|
||||
if (getOrientation() == OrientationHV.HORIZONTAL) {
|
||||
AffineTransform xform =
|
||||
AffineTransform.getRotateInstance(-Math.PI / 2, firstPoint.getX(), firstPoint.getY());
|
||||
for (int i = 1; i < controlPoints.length; i++) {
|
||||
xform.transform(controlPoints[i], controlPoints[i]);
|
||||
}
|
||||
@@ -274,38 +286,48 @@ public class SlideSwitch extends AbstractTransparentComponent<SlideSwitchType> i
|
||||
}
|
||||
|
||||
g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(1));
|
||||
for (Point2D p : controlPoints) {
|
||||
for (int i = 0; i < controlPoints.length; i++) {
|
||||
Point2D p = controlPoints[i];
|
||||
if (outlineMode) {
|
||||
g2d.setColor(theme.getOutlineColor());
|
||||
g2d.drawRect((int) (p.getX() - lugWidth / 2), (int) (p.getY() - lugHeight / 2), lugWidth,
|
||||
g2d.drawRect((int) (p.getX() - lugWidth / 2d), (int) (p.getY() - lugHeight / 2d), lugWidth,
|
||||
lugHeight);
|
||||
} else {
|
||||
g2d.setColor(TERMINAL_COLOR);
|
||||
g2d.fillRect((int) (p.getX() - lugWidth / 2), (int) (p.getY() - lugHeight / 2), lugWidth,
|
||||
g2d.fillRect((int) (p.getX() - lugWidth / 2d), (int) (p.getY() - lugHeight / 2d), lugWidth,
|
||||
lugHeight);
|
||||
g2d.setColor(TERMINAL_COLOR.darker());
|
||||
g2d.drawRect((int) (p.getX() - lugWidth / 2), (int) (p.getY() - lugHeight / 2), lugWidth,
|
||||
g2d.drawRect((int) (p.getX() - lugWidth / 2d), (int) (p.getY() - lugHeight / 2d), lugWidth,
|
||||
lugHeight);
|
||||
}
|
||||
}
|
||||
|
||||
// g2d.setFont(project.getFont());
|
||||
// g2d.setColor(getLabelColor());
|
||||
//
|
||||
// double labelOffsetX = 0;
|
||||
// double labelOffsetY = 0;
|
||||
// if (getValue() == SlideSwitchType.SPDT) {
|
||||
// int rowSpacing = (int) getRowSpacing().convertToPixels();
|
||||
// if (getOrientation() == OrientationHV.VERTICAL) {
|
||||
// labelOffsetY = -rowSpacing / 2;
|
||||
// } else {
|
||||
// labelOffsetX = -rowSpacing / 2;
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// Rectangle bounds = body[0].getBounds();
|
||||
// StringUtils.drawCenteredText(g2d, getName(), bounds.getCenterX() + labelOffsetX,
|
||||
// bounds.getCenterY() + labelOffsetY, HorizontalAlignment.CENTER, VerticalAlignment.CENTER);
|
||||
if (getShowMarkers()) {
|
||||
String[] markers =
|
||||
SwitchUtils.getSwitchingMarkers(this, getControlPointCount(), false);
|
||||
|
||||
g2d.setColor(MARKER_COLOR);
|
||||
|
||||
double offset = MARKER_OFFSET.convertToPixels();
|
||||
for (int i = 0; i < getControlPointCount(); i++) {
|
||||
if (markers[i] == null)
|
||||
continue;
|
||||
|
||||
Point2D p = getControlPoint(i);
|
||||
int direction = switchType == SlideSwitchType.SPDT || i < getControlPointCount() / 2 ? 1 : -1;
|
||||
Point2D labelPoint = new Point2D.Double(direction * offset, 0);
|
||||
|
||||
AffineTransform tx = null;
|
||||
if (getOrientation() == OrientationHV.HORIZONTAL) {
|
||||
tx = AffineTransform.getRotateInstance(-Math.PI / 2, 0, 0);
|
||||
}
|
||||
if (tx != null) {
|
||||
tx.transform(labelPoint, labelPoint);
|
||||
}
|
||||
StringUtils.drawCenteredText(g2d, markers[i], p.getX() + labelPoint.getX(), p.getY() + labelPoint.getY(),
|
||||
HorizontalAlignment.CENTER, VerticalAlignment.CENTER);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public Shape[] getBody() {
|
||||
@@ -411,14 +433,7 @@ public class SlideSwitch extends AbstractTransparentComponent<SlideSwitchType> i
|
||||
|
||||
@Override
|
||||
public int getPositionCount() {
|
||||
switch (switchType) {
|
||||
case SPDT:
|
||||
case DPDT:
|
||||
return 2;
|
||||
case DP3T:
|
||||
return 3;
|
||||
}
|
||||
return 2;
|
||||
return switchType.getPositionCount();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -428,12 +443,43 @@ public class SlideSwitch extends AbstractTransparentComponent<SlideSwitchType> i
|
||||
|
||||
@Override
|
||||
public boolean arePointsConnected(int index1, int index2, int position) {
|
||||
// Method assumes index1 < index2
|
||||
switch (switchType) {
|
||||
case SPDT:
|
||||
return (index1 == position) && (index2 - index1 == 1);
|
||||
// For SPDT, index 1 is the common (center) terminal
|
||||
// Position 1: connects terminals 0-1
|
||||
// Position 2: connects terminals 1-2
|
||||
if (position == 0) {
|
||||
return index1 == 0 && index2 == 1;
|
||||
} else if (position == 1) {
|
||||
return index1 == 1 && index2 == 2;
|
||||
}
|
||||
return false;
|
||||
case DPDT:
|
||||
// For DPDT, indices 1 and 4 are the common (center) terminals
|
||||
// Position 1: connects terminals 0-1 and 3-4
|
||||
// Position 2: connects terminals 1-2 and 4-5
|
||||
if (position == 0) {
|
||||
return (index1 == 0 && index2 == 1) || (index1 == 3 && index2 == 4);
|
||||
} else if (position == 1) {
|
||||
return (index1 == 1 && index2 == 2) || (index1 == 4 && index2 == 5);
|
||||
}
|
||||
return false;
|
||||
case DP3T:
|
||||
return (index1 == position * 2 || index1 == position * 2 + 1) && (index2 - index1 == 2);
|
||||
// For DP3T, following the schematic:
|
||||
// Position 1: A1-A2 and B1-B2 (0-1 and 4-5)
|
||||
// Position 2: A2-A3 and B2-B3 (1-2 and 5-6)
|
||||
// Position 3: A3-A4 and B3-B4 (2-3 and 6-7)
|
||||
if (position == 0) { // Position 1
|
||||
return (index1 == 0 && index2 == 1) || // A1-A2
|
||||
(index1 == 4 && index2 == 5); // B1-B2
|
||||
} else if (position == 1) { // Position 2
|
||||
return (index1 == 1 && index2 == 2) || // A2-A3
|
||||
(index1 == 5 && index2 == 6); // B2-B3
|
||||
} else if (position == 2) { // Position 3
|
||||
return (index1 == 2 && index2 == 3) || // A3-A4
|
||||
(index1 == 6 && index2 == 7); // B3-B4
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -465,6 +511,29 @@ public class SlideSwitch extends AbstractTransparentComponent<SlideSwitchType> i
|
||||
this.bracketColor = bracketColor;
|
||||
}
|
||||
|
||||
@DynamicEditableProperty(source = SlideSwitchPositionPropertyValueSource.class)
|
||||
@EditableProperty(name = "Selected Position")
|
||||
@Override
|
||||
public Integer getSelectedPosition() {
|
||||
return selectedPosition;
|
||||
}
|
||||
|
||||
public void setSelectedPosition(Integer selectedPosition) {
|
||||
this.selectedPosition = selectedPosition;
|
||||
}
|
||||
|
||||
@EditableProperty(name = "Markers")
|
||||
public Boolean getShowMarkers() {
|
||||
if (showMarkers == null) {
|
||||
showMarkers = false;
|
||||
}
|
||||
return showMarkers;
|
||||
}
|
||||
|
||||
public void setShowMarkers(Boolean showMarkers) {
|
||||
this.showMarkers = showMarkers;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Rectangle2D getCachingBounds() {
|
||||
int margin = 20;
|
||||
|
||||
+41
@@ -0,0 +1,41 @@
|
||||
package org.diylc.components.electromechanical;
|
||||
|
||||
import org.diylc.common.PropertyWrapper;
|
||||
import org.diylc.components.guitar.LeverSwitch;
|
||||
import org.diylc.core.AbstractDynamicPropertyValueSource;
|
||||
import org.diylc.core.IDIYComponent;
|
||||
import org.diylc.core.IDynamicPropertySource;
|
||||
import org.diylc.core.ISwitch;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
public class SlideSwitchPositionPropertyValueSource extends AbstractDynamicPropertyValueSource {
|
||||
|
||||
@Override
|
||||
public List<Object> getAvailableValues() {
|
||||
if (properties == null) {
|
||||
return List.of();
|
||||
}
|
||||
Optional<PropertyWrapper> optionalPropertyWrapper = this.properties.stream().filter(p -> {
|
||||
try {
|
||||
return p.getGetter().getName().equals("getValue");
|
||||
} catch (NoSuchMethodException e) {
|
||||
return false;
|
||||
}
|
||||
}).findFirst();
|
||||
if (optionalPropertyWrapper.isEmpty()) {
|
||||
return List.of();
|
||||
}
|
||||
SlideSwitchType
|
||||
switchType = (SlideSwitchType) optionalPropertyWrapper.get().getValue();
|
||||
int positionCount = switchType.getPositionCount();
|
||||
List<Object> res = new ArrayList<>();
|
||||
res.add(null);
|
||||
for (int i = 0; i < positionCount; i++) {
|
||||
res.add(i);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
}
|
||||
+10
-11
@@ -2,16 +2,15 @@ package org.diylc.components.electromechanical;
|
||||
|
||||
public enum SlideSwitchType {
|
||||
|
||||
SPDT, DPDT, DP3T;
|
||||
SPDT(2), DPDT(2), DP3T(3);
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
String name = name();
|
||||
if (name.startsWith("_"))
|
||||
name = name.substring(1);
|
||||
name = name.replace("_", " ");
|
||||
name = name.replace("mustang", "");
|
||||
name = name.replace("off", " (Center OFF)");
|
||||
return name;
|
||||
private final int positionCount;
|
||||
|
||||
SlideSwitchType(int positionCount) {
|
||||
this.positionCount = positionCount;
|
||||
}
|
||||
}
|
||||
|
||||
public int getPositionCount() {
|
||||
return positionCount;
|
||||
}
|
||||
}
|
||||
|
||||
+23
-7
@@ -23,16 +23,32 @@ package org.diylc.components.electromechanical;
|
||||
|
||||
public enum ToggleSwitchType {
|
||||
|
||||
SPST("SPST"), SPDT("SPDT (On/On)"), SPDT_off("SPDT (On/Off/On)"), DPDT("DPDT (On/On)"),DPDT_off("DPDT (On/Off/On)"),
|
||||
DPDT_ononon_1("DPDT (On/On/On Type 1)"), DPDT_ononon_2("DPDT (On/On/On Type 2)"),
|
||||
_DP3T_mustang("DP3T"), _3PDT("3PDT"),_3PDT_off("3PDT (On/Off/On)"), _4PDT("4PDT"), _4PDT_off("4PDT (On/Off/On)"),
|
||||
_4PDT_ononon_1("4PDT (On/On/On Type 1)"), _4PDT_ononon_2("4PDT (On/On/On Type 2)"),
|
||||
_5PDT("5PDT"), _5PDT_off("5PDT (On/Off/On)");
|
||||
SPST("SPST", 2),
|
||||
SPDT("SPDT (On/On)", 2),
|
||||
SPDT_off("SPDT (On/Off/On)", 3),
|
||||
DPDT("DPDT (On/On)", 2),
|
||||
DPDT_off("DPDT (On/Off/On)", 3),
|
||||
DPDT_ononon_1("DPDT (On/On/On Type 1)", 3),
|
||||
DPDT_ononon_2("DPDT (On/On/On Type 2)", 3),
|
||||
_3PDT("3PDT", 2),
|
||||
_3PDT_off("3PDT (On/Off/On)", 3),
|
||||
_4PDT("4PDT", 2),
|
||||
_4PDT_off("4PDT (On/Off/On)", 3),
|
||||
_4PDT_ononon_1("4PDT (On/On/On Type 1)", 3),
|
||||
_4PDT_ononon_2("4PDT (On/On/On Type 2)", 3),
|
||||
_5PDT("5PDT", 2),
|
||||
_5PDT_off("5PDT (On/Off/On)", 3);
|
||||
|
||||
private String label;
|
||||
|
||||
private ToggleSwitchType(String label) {
|
||||
private final int positionCount;
|
||||
|
||||
private ToggleSwitchType(String label, int positionCount) {
|
||||
this.label = label;
|
||||
this.positionCount = positionCount;
|
||||
}
|
||||
|
||||
public int getPositionCount() {
|
||||
return positionCount;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -33,6 +33,9 @@ import java.net.URI;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Random;
|
||||
import java.util.Set;
|
||||
import java.util.stream.IntStream;
|
||||
|
||||
import org.apache.log4j.Logger;
|
||||
import org.apache.poi.util.IOUtils;
|
||||
import org.diylc.appframework.miscutils.ConfigurationManager;
|
||||
@@ -42,24 +45,19 @@ import com.kitfox.svg.SVGElement;
|
||||
import com.kitfox.svg.SVGUniverse;
|
||||
import com.kitfox.svg.ShapeElement;
|
||||
|
||||
import org.diylc.common.IPlugInPort;
|
||||
import org.diylc.common.ObjectCache;
|
||||
import org.diylc.common.Orientation;
|
||||
import org.diylc.awt.StringUtils;
|
||||
import org.diylc.common.*;
|
||||
import org.diylc.components.AbstractTransparentComponent;
|
||||
import org.diylc.components.transform.Freeway3x3_03Transformer;
|
||||
import org.diylc.core.ComponentState;
|
||||
import org.diylc.core.IDIYComponent;
|
||||
import org.diylc.core.IDrawingObserver;
|
||||
import org.diylc.core.ISwitch;
|
||||
import org.diylc.core.Project;
|
||||
import org.diylc.core.Theme;
|
||||
import org.diylc.core.VisibilityPolicy;
|
||||
import org.diylc.core.*;
|
||||
import org.diylc.core.annotations.ComponentDescriptor;
|
||||
import org.diylc.core.annotations.DynamicEditableProperty;
|
||||
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;
|
||||
import org.diylc.utils.SwitchUtils;
|
||||
|
||||
@ComponentDescriptor(name = "Freeway 3X3-03 Toggle", category = "Guitar",
|
||||
author = "Branislav Stojkovic", description = "Freeway 3X3-03 Toggle Switch",
|
||||
@@ -76,6 +74,7 @@ public class Freeway3x3_03 extends AbstractTransparentComponent<Void> implements
|
||||
private static Color PAD_COLOR = COPPER_COLOR;
|
||||
private static Color LABEL_COLOR = Color.WHITE;
|
||||
private static Color CASE_COLOR = METAL_COLOR;
|
||||
private static Color MARKER_COLOR = Color.lightGray;
|
||||
|
||||
private static final double[] X_OFFSETS =
|
||||
new double[] {9, 15, 21, 21, 21, 21, 21, 21, 12, 3, 3, 3, 3, 3, 3};
|
||||
@@ -91,6 +90,9 @@ public class Freeway3x3_03 extends AbstractTransparentComponent<Void> implements
|
||||
|
||||
private Orientation orientation = Orientation.DEFAULT;
|
||||
|
||||
private Integer selectedPosition;
|
||||
private Boolean showMarkers;
|
||||
|
||||
private transient SVGDiagram svgDiagram;
|
||||
private transient List<Shape> pads;
|
||||
private transient List<Shape> labels;
|
||||
@@ -126,8 +128,6 @@ public class Freeway3x3_03 extends AbstractTransparentComponent<Void> implements
|
||||
double[] xOffsets = getXOffsetsPx();
|
||||
double[] yOffsets = getYOffsetsPx();
|
||||
|
||||
|
||||
|
||||
Rectangle2D rect = new Rectangle2D.Double(x - xOffsets[0], y - yOffsets[0], bounds2d.getWidth(),
|
||||
bounds2d.getHeight());
|
||||
|
||||
@@ -151,6 +151,8 @@ public class Freeway3x3_03 extends AbstractTransparentComponent<Void> implements
|
||||
g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1f * alpha / MAX_ALPHA));
|
||||
}
|
||||
|
||||
AffineTransform oldTx = new AffineTransform(g2d.getTransform());
|
||||
|
||||
if (getOrientation() != Orientation.DEFAULT) {
|
||||
double theta = orientation.toRadians();
|
||||
g2d.rotate(theta, x, y);
|
||||
@@ -181,15 +183,15 @@ public class Freeway3x3_03 extends AbstractTransparentComponent<Void> implements
|
||||
g2d.draw(base);
|
||||
|
||||
drawingObserver.startTrackingContinuityArea(true);
|
||||
g2d.setColor(PAD_COLOR);
|
||||
for (Shape pad : pads) {
|
||||
g2d.fill(pad);
|
||||
for (int i = 0; i < pads.size(); i++) {
|
||||
g2d.setColor(PAD_COLOR);
|
||||
g2d.fill(pads.get(i));
|
||||
}
|
||||
drawingObserver.stopTrackingContinuityArea();
|
||||
|
||||
g2d.setColor(PAD_COLOR.darker());
|
||||
for (Shape pad : pads) {
|
||||
g2d.draw(pad);
|
||||
for (int i = 0; i < pads.size(); i++) {
|
||||
g2d.setColor(PAD_COLOR.darker());
|
||||
g2d.draw(pads.get(i));
|
||||
}
|
||||
|
||||
g2d.setColor(LABEL_COLOR);
|
||||
@@ -203,6 +205,20 @@ public class Freeway3x3_03 extends AbstractTransparentComponent<Void> implements
|
||||
g2d.setColor(CASE_COLOR.darker());
|
||||
g2d.draw(caseShape);
|
||||
|
||||
if (getShowMarkers()) {
|
||||
g2d.setTransform(oldTx);
|
||||
// g2d.setFont(g2d.getFont().deriveFont(g2d.getFont().getSize() * 0.8f));
|
||||
String[] markers = SwitchUtils.getSwitchingMarkers(this, this.getControlPointCount(), false);
|
||||
g2d.setColor(MARKER_COLOR);
|
||||
for (int i = 0; i < getControlPointCount(); i++) {
|
||||
if (markers[i] == null)
|
||||
continue;;
|
||||
|
||||
Point2D p = getControlPoint(i);
|
||||
StringUtils.drawCenteredText(g2d, markers[i], p.getX(), p.getY(), HorizontalAlignment.CENTER, VerticalAlignment.CENTER);
|
||||
}
|
||||
}
|
||||
|
||||
g2d.setComposite(oldComposite);
|
||||
}
|
||||
|
||||
@@ -420,6 +436,29 @@ public class Freeway3x3_03 extends AbstractTransparentComponent<Void> implements
|
||||
return Integer.toString(position + 1);
|
||||
}
|
||||
|
||||
@DynamicEditableProperty(source = Freeway3x4_03SwitchPositionPropertyValueSource.class)
|
||||
@EditableProperty(name = "Selected Position")
|
||||
@Override
|
||||
public Integer getSelectedPosition() {
|
||||
return selectedPosition;
|
||||
}
|
||||
|
||||
public void setSelectedPosition(Integer selectedPosition) {
|
||||
this.selectedPosition = selectedPosition;
|
||||
}
|
||||
|
||||
@EditableProperty(name = "Markers")
|
||||
public Boolean getShowMarkers() {
|
||||
if (showMarkers == null) {
|
||||
showMarkers = false;
|
||||
}
|
||||
return showMarkers;
|
||||
}
|
||||
|
||||
public void setShowMarkers(Boolean showMarkers) {
|
||||
this.showMarkers = showMarkers;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean arePointsConnected(int index1, int index2, int position) {
|
||||
if (position == 0 && ((index1 == 0 && index2 == 9) || (index1 == 1 && index2 == 7))) {
|
||||
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
package org.diylc.components.guitar;
|
||||
|
||||
import org.diylc.common.PropertyWrapper;
|
||||
import org.diylc.core.AbstractDynamicPropertyValueSource;
|
||||
import org.diylc.core.IDIYComponent;
|
||||
import org.diylc.core.IDynamicPropertySource;
|
||||
import org.diylc.core.ISwitch;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
public class Freeway3x4_03SwitchPositionPropertyValueSource extends
|
||||
AbstractDynamicPropertyValueSource {
|
||||
|
||||
@Override
|
||||
public List<Object> getAvailableValues() {
|
||||
int positionCount = 6;
|
||||
List<Object> res = new ArrayList<>();
|
||||
res.add(null);
|
||||
for (int i = 0; i < positionCount; i++) {
|
||||
res.add(i);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
}
|
||||
@@ -32,27 +32,26 @@ import java.awt.geom.Ellipse2D;
|
||||
import java.awt.geom.Point2D;
|
||||
import java.awt.geom.Rectangle2D;
|
||||
import java.awt.geom.RoundRectangle2D;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.*;
|
||||
|
||||
import org.diylc.appframework.miscutils.ConfigurationManager;
|
||||
|
||||
import org.diylc.awt.StringUtils;
|
||||
import org.diylc.common.HorizontalAlignment;
|
||||
import org.diylc.common.IPlugInPort;
|
||||
import org.diylc.common.ObjectCache;
|
||||
import org.diylc.common.VerticalAlignment;
|
||||
import org.diylc.components.AbstractAngledComponent;
|
||||
import org.diylc.components.transform.AngledComponentTransformer;
|
||||
import org.diylc.core.ComponentState;
|
||||
import org.diylc.core.IDIYComponent;
|
||||
import org.diylc.core.IDrawingObserver;
|
||||
import org.diylc.core.ISwitch;
|
||||
import org.diylc.core.Project;
|
||||
import org.diylc.core.Theme;
|
||||
import org.diylc.core.VisibilityPolicy;
|
||||
import org.diylc.core.*;
|
||||
import org.diylc.core.annotations.ComponentDescriptor;
|
||||
import org.diylc.core.annotations.DynamicEditableProperty;
|
||||
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;
|
||||
import org.diylc.utils.SwitchUtils;
|
||||
|
||||
@ComponentDescriptor(name = "Lever Switch", category = "Guitar", author = "Branislav Stojkovic",
|
||||
description = "Strat-style lever switch", zOrder = IDIYComponent.COMPONENT,
|
||||
@@ -65,7 +64,7 @@ public class LeverSwitch extends AbstractAngledComponent<LeverSwitch.LeverSwitch
|
||||
private static Color BASE_COLOR = Color.lightGray;
|
||||
private static Color WAFER_COLOR = Color.decode("#CD8500");
|
||||
private static Color LUG_COLOR = METAL_COLOR;
|
||||
private static Color COMMON_LUG_COLOR = Color.decode("#FF9999");
|
||||
private static Color MARKER_COLOR = Color.gray;
|
||||
|
||||
private static Size BASE_WIDTH = new Size(10d, SizeUnit.mm);
|
||||
private static Size BASE_LENGTH = new Size(47.5d, SizeUnit.mm);
|
||||
@@ -77,13 +76,17 @@ public class LeverSwitch extends AbstractAngledComponent<LeverSwitch.LeverSwitch
|
||||
private static Size TERMINAL_WIDTH = new Size(2d, SizeUnit.mm);
|
||||
private static Size TERMINAL_LENGTH = new Size(0.1d, SizeUnit.in);
|
||||
private static Size TERMINAL_SPACING = new Size(0.1d, SizeUnit.in);
|
||||
private static Size MARKER_OFFSET = new Size(0.1d, SizeUnit.in);
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
@Deprecated
|
||||
private transient String value = "";
|
||||
private Point2D[] controlPoints = new Point2D[] {new Point2D.Double(0, 0)};
|
||||
private LeverSwitchType type = LeverSwitchType.DP3T;
|
||||
@Deprecated
|
||||
private Boolean highlightCommon;
|
||||
private Integer selectedPosition;
|
||||
private Boolean showMarkers;
|
||||
|
||||
public LeverSwitch() {
|
||||
super();
|
||||
@@ -142,10 +145,31 @@ public class LeverSwitch extends AbstractAngledComponent<LeverSwitch.LeverSwitch
|
||||
g2d.fill(body[2]);
|
||||
g2d.setColor(LUG_COLOR.darker());
|
||||
g2d.draw(body[2]);
|
||||
g2d.setColor(COMMON_LUG_COLOR);
|
||||
g2d.fill(body[3]);
|
||||
g2d.setColor(COMMON_LUG_COLOR.darker());
|
||||
g2d.draw(body[3]);
|
||||
|
||||
if (getShowMarkers()) {
|
||||
String[] markers =
|
||||
SwitchUtils.getSwitchingMarkers(this, getControlPointCount(), false);
|
||||
double theta = getAngle().getValueRad();
|
||||
g2d.setColor(MARKER_COLOR);
|
||||
|
||||
double offset = MARKER_OFFSET.convertToPixels();
|
||||
for (int i = 0; i < getControlPointCount(); i++) {
|
||||
if (markers[i] == null)
|
||||
continue;
|
||||
|
||||
Point2D p = getControlPoint(i);
|
||||
Point2D labelPoint = new Point2D.Double(offset, 0);
|
||||
AffineTransform tx = null;
|
||||
if (theta != 0) {
|
||||
tx = AffineTransform.getRotateInstance(theta);
|
||||
}
|
||||
if (tx != null) {
|
||||
tx.transform(labelPoint, labelPoint);
|
||||
}
|
||||
StringUtils.drawCenteredText(g2d, markers[i], p.getX() + labelPoint.getX(), p.getY() + labelPoint.getY(),
|
||||
HorizontalAlignment.CENTER, VerticalAlignment.CENTER);
|
||||
}
|
||||
}
|
||||
|
||||
// g2d.setColor(Color.black);
|
||||
// for(int i = 0; i < getControlPointCount(); i++) {
|
||||
@@ -156,7 +180,6 @@ public class LeverSwitch extends AbstractAngledComponent<LeverSwitch.LeverSwitch
|
||||
@SuppressWarnings("incomplete-switch")
|
||||
public Shape[] getBody() {
|
||||
if (body == null) {
|
||||
body = new Shape[4];
|
||||
|
||||
double x = controlPoints[0].getX();
|
||||
double y = controlPoints[0].getY();
|
||||
@@ -192,7 +215,7 @@ public class LeverSwitch extends AbstractAngledComponent<LeverSwitch.LeverSwitch
|
||||
+ (baseLength - holeSpacing) / 2 - holeSize / 2, holeSize, holeSize)));
|
||||
baseArea.subtract(new Area(new Ellipse2D.Double(baseX + baseWidth / 2 - holeSize / 2, baseY
|
||||
+ (baseLength - holeSpacing) / 2 - holeSize / 2 + holeSpacing, holeSize, holeSize)));
|
||||
body[0] = baseArea;
|
||||
|
||||
|
||||
Area waferArea =
|
||||
new Area(new Rectangle2D.Double(x - terminalLength / 2 - waferThickness / 2, y
|
||||
@@ -204,43 +227,35 @@ public class LeverSwitch extends AbstractAngledComponent<LeverSwitch.LeverSwitch
|
||||
- (waferLength - terminalSpacing * 12) / 2, waferThickness,
|
||||
waferLength)));
|
||||
}
|
||||
body[1] = waferArea;
|
||||
|
||||
double theta = getAngle().getValueRad();
|
||||
|
||||
Area terminalArea = new Area();
|
||||
Area commonTerminalArea = new Area();
|
||||
body = new Shape[3];
|
||||
body[0] = baseArea;
|
||||
body[1] = waferArea;
|
||||
body[2] = new Area();
|
||||
|
||||
for (int i = 0; i < controlPoints.length; i++) {
|
||||
Point2D point = controlPoints[i];
|
||||
Area terminal =
|
||||
new Area(new RoundRectangle2D.Double(point.getX() - terminalLength / 2, point.getY() - terminalWidth / 2,
|
||||
terminalLength, terminalWidth, terminalWidth / 2, terminalWidth / 2));
|
||||
terminal.subtract(new Area(new RoundRectangle2D.Double(point.getX() - terminalLength / 4, point.getY() - terminalWidth
|
||||
/ 4, terminalLength / 2, terminalWidth / 2, terminalWidth / 2, terminalWidth / 2)));
|
||||
new Area(new RoundRectangle2D.Double(point.getX() - terminalLength / 2d, point.getY() - terminalWidth / 2d,
|
||||
terminalLength, terminalWidth, terminalWidth / 2d, terminalWidth / 2d));
|
||||
terminal.subtract(new Area(new RoundRectangle2D.Double(point.getX() - terminalLength / 4d, point.getY() - terminalWidth
|
||||
/ 4d, terminalLength / 2d, terminalWidth / 2d, terminalWidth / 2d, terminalWidth / 2d)));
|
||||
// Rotate the terminal if needed
|
||||
if (theta != 0) {
|
||||
AffineTransform rotation = AffineTransform.getRotateInstance(theta, point.getX(), point.getY());
|
||||
terminal.transform(rotation);
|
||||
}
|
||||
terminalArea.add(terminal);
|
||||
if (getHighlightCommon() &&
|
||||
(((type == LeverSwitchType.DP3T || type == LeverSwitchType.DP3T_5pos) && (i == 1 || i == 6)) ||
|
||||
((type == LeverSwitchType._6_WAY_OG) && (i == 1 || i == 8)) ||
|
||||
(type == LeverSwitchType.DP4T && (i == 1 || i == 8)) ||
|
||||
(type == LeverSwitchType.DP3T_5pos_Import && (i == 3 || i == 4)) ||
|
||||
((type == LeverSwitchType._4P5T || type == LeverSwitchType.DP5T) && (i == 0 || i == 11 || i == 12 || i == 23))))
|
||||
commonTerminalArea.add(terminal);
|
||||
else
|
||||
terminalArea.add(terminal);
|
||||
|
||||
((Area)body[2]).add(terminal);
|
||||
}
|
||||
body[2] = terminalArea;
|
||||
body[3] = commonTerminalArea;
|
||||
|
||||
// Rotate if needed
|
||||
if (theta != 0) {
|
||||
AffineTransform rotation = AffineTransform.getRotateInstance(theta, controlPoints[0].getX(), controlPoints[0].getY());
|
||||
// Skip the last two because terminals are already rotated
|
||||
for (int i = 0; i < body.length - 2; i++) {
|
||||
// Skip the last one because terminals are already rotated
|
||||
for (int i = 0; i < body.length - 1; i++) {
|
||||
Shape shape = body[i];
|
||||
Area area = (Area) shape;
|
||||
area.transform(rotation);
|
||||
@@ -250,6 +265,8 @@ public class LeverSwitch extends AbstractAngledComponent<LeverSwitch.LeverSwitch
|
||||
return body;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@SuppressWarnings("incomplete-switch")
|
||||
protected void updateControlPoints() {
|
||||
double x = controlPoints[0].getX();
|
||||
@@ -382,22 +399,7 @@ public class LeverSwitch extends AbstractAngledComponent<LeverSwitch.LeverSwitch
|
||||
// Invalidate body
|
||||
this.body = null;
|
||||
}
|
||||
|
||||
@EditableProperty(name = "Mark Common Lugs")
|
||||
public Boolean getHighlightCommon() {
|
||||
if (highlightCommon == null)
|
||||
highlightCommon = true;
|
||||
return highlightCommon;
|
||||
}
|
||||
|
||||
public void setHighlightCommon(Boolean highlightCommon) {
|
||||
this.highlightCommon = highlightCommon;
|
||||
|
||||
body = null;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// @Override
|
||||
// public String getControlPointNodeName(int index) {
|
||||
// // we don't want the switch to produce any nodes, it just makes connections
|
||||
@@ -408,20 +410,7 @@ public class LeverSwitch extends AbstractAngledComponent<LeverSwitch.LeverSwitch
|
||||
|
||||
@Override
|
||||
public int getPositionCount() {
|
||||
switch (type) {
|
||||
case DP3T:
|
||||
return 3;
|
||||
case DP4T:
|
||||
return 4;
|
||||
case DP3T_5pos:
|
||||
case DP3T_5pos_Import:
|
||||
case DP5T:
|
||||
case _4P5T:
|
||||
return 5;
|
||||
case _6_WAY_OG:
|
||||
return 6;
|
||||
}
|
||||
return 0;
|
||||
return type.getPositionCount();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -467,7 +456,7 @@ public class LeverSwitch extends AbstractAngledComponent<LeverSwitch.LeverSwitch
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean canPointMoveFreely(int pointIndex) {
|
||||
return false;
|
||||
@@ -532,18 +521,54 @@ public class LeverSwitch extends AbstractAngledComponent<LeverSwitch.LeverSwitch
|
||||
new int[] { 1, 9 }
|
||||
) // position 6
|
||||
);
|
||||
|
||||
|
||||
@DynamicEditableProperty(source = LeverSwitchPositionPropertyValueSource.class)
|
||||
@EditableProperty(name = "Selected Position")
|
||||
@Override
|
||||
public Integer getSelectedPosition() {
|
||||
return selectedPosition;
|
||||
}
|
||||
|
||||
public void setSelectedPosition(Integer selectedPosition) {
|
||||
this.selectedPosition = selectedPosition;
|
||||
this.body = null;
|
||||
}
|
||||
|
||||
@EditableProperty(name = "Markers")
|
||||
public Boolean getShowMarkers() {
|
||||
if (showMarkers == null) {
|
||||
showMarkers = false;
|
||||
}
|
||||
return showMarkers;
|
||||
}
|
||||
|
||||
public void setShowMarkers(Boolean showMarkers) {
|
||||
this.showMarkers = showMarkers;
|
||||
this.body = null;
|
||||
}
|
||||
|
||||
public static enum LeverSwitchType {
|
||||
|
||||
DP3T("DP3T (Standard 3-Position Strat)"), DP3T_5pos("DP3T (Standard 5-Position Strat)"), DP3T_5pos_Import("DP3T (Import 5-Position Strat)"),
|
||||
_4P5T("4P5T (Super/Mega)"), DP4T("DP4T (4-Position Tele)"), _6_WAY_OG("DP4T (6-Position Oak Grigsby)"), DP5T("DP5T");
|
||||
DP3T("DP3T (Standard 3-Position Strat)", 3),
|
||||
DP3T_5pos("DP3T (Standard 5-Position Strat)", 5),
|
||||
DP3T_5pos_Import("DP3T (Import 5-Position Strat)", 5),
|
||||
_4P5T("4P5T (Super/Mega)", 5),
|
||||
DP4T("DP4T (4-Position Tele)", 4),
|
||||
_6_WAY_OG("DP4T (6-Position Oak Grigsby)", 6),
|
||||
DP5T("DP5T", 5);
|
||||
|
||||
private final int positionCount;
|
||||
private String title;
|
||||
|
||||
private LeverSwitchType(String title) {
|
||||
private LeverSwitchType(String title, int positionCount) {
|
||||
this.positionCount = positionCount;
|
||||
this.title = title;
|
||||
}
|
||||
|
||||
public int getPositionCount() {
|
||||
return positionCount;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return title;
|
||||
|
||||
+38
@@ -0,0 +1,38 @@
|
||||
package org.diylc.components.guitar;
|
||||
|
||||
import org.diylc.common.PropertyWrapper;
|
||||
import org.diylc.core.AbstractDynamicPropertyValueSource;
|
||||
import org.diylc.core.IDIYComponent;
|
||||
import org.diylc.core.IDynamicPropertySource;
|
||||
import org.diylc.core.ISwitch;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
public class LeverSwitchPositionPropertyValueSource extends AbstractDynamicPropertyValueSource {
|
||||
|
||||
@Override
|
||||
public List<Object> getAvailableValues() {
|
||||
if (properties == null) {
|
||||
return List.of();
|
||||
}
|
||||
Optional<PropertyWrapper> optionalPropertyWrapper = this.properties.stream().filter(p -> {
|
||||
try {
|
||||
return p.getGetter().getName().equals("getValue");
|
||||
} catch (NoSuchMethodException e) {
|
||||
return false;
|
||||
}
|
||||
}).findFirst();
|
||||
if (optionalPropertyWrapper.isEmpty()) {
|
||||
return List.of();
|
||||
}
|
||||
LeverSwitch.LeverSwitchType
|
||||
switchType = (LeverSwitch.LeverSwitchType) optionalPropertyWrapper.get().getValue();
|
||||
int positionCount = switchType.getPositionCount();
|
||||
List<Object> res = new ArrayList<>();
|
||||
res.add(null);
|
||||
for (int i = 0; i < positionCount; i++) {
|
||||
res.add(i);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
}
|
||||
+39
@@ -0,0 +1,39 @@
|
||||
package org.diylc.components.guitar;
|
||||
|
||||
import org.diylc.common.PropertyWrapper;
|
||||
import org.diylc.components.electromechanical.RotarySwitchOpenType;
|
||||
import org.diylc.components.electromechanical.ToggleSwitchType;
|
||||
import org.diylc.core.AbstractDynamicPropertyValueSource;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
public class RotarySwitchOpenPositionPropertyValueSource extends AbstractDynamicPropertyValueSource {
|
||||
|
||||
@Override
|
||||
public List<Object> getAvailableValues() {
|
||||
if (properties == null) {
|
||||
return List.of();
|
||||
}
|
||||
Optional<PropertyWrapper> optionalPropertyWrapper = this.properties.stream().filter(p -> {
|
||||
try {
|
||||
return p.getGetter().getName().equals("getValue");
|
||||
} catch (NoSuchMethodException e) {
|
||||
return false;
|
||||
}
|
||||
}).findFirst();
|
||||
if (optionalPropertyWrapper.isEmpty()) {
|
||||
return List.of();
|
||||
}
|
||||
RotarySwitchOpenType
|
||||
switchType = (RotarySwitchOpenType) optionalPropertyWrapper.get().getValue();
|
||||
int positionCount = switchType.getPositionCount();
|
||||
List<Object> res = new ArrayList<>();
|
||||
res.add(null);
|
||||
for (int i = 0; i < positionCount; i++) {
|
||||
res.add(i);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
}
|
||||
+76
-76
@@ -32,6 +32,10 @@ import java.awt.geom.Rectangle2D;
|
||||
import java.awt.geom.RoundRectangle2D;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.stream.IntStream;
|
||||
|
||||
import com.kitfox.svg.A;
|
||||
import org.diylc.appframework.miscutils.ConfigurationManager;
|
||||
|
||||
import org.diylc.awt.StringUtils;
|
||||
@@ -41,15 +45,9 @@ import org.diylc.common.ObjectCache;
|
||||
import org.diylc.common.VerticalAlignment;
|
||||
import org.diylc.components.AbstractAngledComponent;
|
||||
import org.diylc.components.transform.AngledComponentTransformer;
|
||||
import org.diylc.core.Angle;
|
||||
import org.diylc.core.ComponentState;
|
||||
import org.diylc.core.IDIYComponent;
|
||||
import org.diylc.core.IDrawingObserver;
|
||||
import org.diylc.core.ISwitch;
|
||||
import org.diylc.core.Project;
|
||||
import org.diylc.core.Theme;
|
||||
import org.diylc.core.VisibilityPolicy;
|
||||
import org.diylc.core.*;
|
||||
import org.diylc.core.annotations.ComponentDescriptor;
|
||||
import org.diylc.core.annotations.DynamicEditableProperty;
|
||||
import org.diylc.core.annotations.EditableProperty;
|
||||
import org.diylc.core.annotations.KeywordPolicy;
|
||||
import org.diylc.core.images.IconLoader;
|
||||
@@ -67,7 +65,7 @@ public class SchallerMegaSwitch extends AbstractAngledComponent<String> implemen
|
||||
|
||||
private static Color BASE_COLOR = Color.lightGray;
|
||||
private static Color WAFER_COLOR = FR4_LIGHT_COLOR;
|
||||
private static Color LUG_COLOR = GOLD_COLOR;
|
||||
private static Color LUG_COLOR = METAL_COLOR;
|
||||
|
||||
private static Size BASE_WIDTH = new Size(10d, SizeUnit.mm);
|
||||
private static Size BASE_LENGTH = new Size(47.5d, SizeUnit.mm);
|
||||
@@ -90,6 +88,9 @@ public class SchallerMegaSwitch extends AbstractAngledComponent<String> implemen
|
||||
private transient Double labelDx = null;
|
||||
private transient Double labelDy = null;
|
||||
|
||||
private Integer selectedPosition;
|
||||
private Boolean showMarkers;
|
||||
|
||||
public SchallerMegaSwitch() {
|
||||
super();
|
||||
updateControlPoints();
|
||||
@@ -152,11 +153,12 @@ public class SchallerMegaSwitch extends AbstractAngledComponent<String> implemen
|
||||
g2d.fill(body[2]);
|
||||
g2d.setColor(LUG_COLOR.darker());
|
||||
g2d.draw(body[2]);
|
||||
|
||||
// g2d.setColor(Color.black);
|
||||
// for(int i = 0; i < getControlPointCount(); i++) {
|
||||
// g2d.drawString(i + "", controlPoints[i].getX(), controlPoints[i].getY());
|
||||
// }
|
||||
for (int i = 3; i < body.length; i++) {
|
||||
g2d.setColor(ISwitch.POLE_COLORS[i - 3]);
|
||||
g2d.fill(body[i]);
|
||||
g2d.setColor(ISwitch.POLE_COLORS[i - 3].darker());
|
||||
g2d.draw(body[i]);
|
||||
}
|
||||
|
||||
g2d.setColor(labelColor);
|
||||
// g2d.setFont(project.getFont().deriveFont(LABEL_FONT_SIZE));
|
||||
@@ -200,14 +202,14 @@ public class SchallerMegaSwitch extends AbstractAngledComponent<String> implemen
|
||||
}
|
||||
|
||||
g2d.setFont(project.getFont().deriveFont((float) (project.getFont().getSize2D() * 1.25)));
|
||||
StringUtils.drawCenteredText(g2d, "Schaller Megaswitch� " + type.toString(), x, y,
|
||||
StringUtils.drawCenteredText(g2d, "Schaller Megaswitch " + type.toString(), x, y,
|
||||
HorizontalAlignment.CENTER, VerticalAlignment.CENTER);
|
||||
}
|
||||
|
||||
public Shape[] getBody() {
|
||||
if (body == null) {
|
||||
body = new Shape[4];
|
||||
|
||||
body = new Shape[3];
|
||||
|
||||
int lastPointIdx =
|
||||
type == MegaSwitchType.M ? controlPoints.length / 2 - 1 : controlPoints.length - 1;
|
||||
@@ -248,10 +250,10 @@ public class SchallerMegaSwitch extends AbstractAngledComponent<String> implemen
|
||||
new Area(new Rectangle2D.Double(waferX, waferY, waferThickness, waferLength));
|
||||
|
||||
body[1] = waferArea;
|
||||
body[2] = new Area();
|
||||
|
||||
double theta = getAngle().getValueRad();
|
||||
|
||||
Area terminalArea = new Area();
|
||||
for (int i = 0; i < controlPoints.length; i++) {
|
||||
Point2D point = controlPoints[i];
|
||||
Area terminal = new Area(new RoundRectangle2D.Double(point.getX() - terminalSize / 2,
|
||||
@@ -266,10 +268,9 @@ public class SchallerMegaSwitch extends AbstractAngledComponent<String> implemen
|
||||
AffineTransform rotation = AffineTransform.getRotateInstance(theta, point.getX(), point.getY());
|
||||
terminal.transform(rotation);
|
||||
}
|
||||
|
||||
terminalArea.add(terminal);
|
||||
|
||||
((Area)body[2]).add(terminal);
|
||||
}
|
||||
body[2] = terminalArea;
|
||||
|
||||
// Rotate if needed
|
||||
if (theta != 0) {
|
||||
@@ -293,24 +294,12 @@ public class SchallerMegaSwitch extends AbstractAngledComponent<String> implemen
|
||||
double terminalWidth = TERMINAL_WIDTH.convertToPixels();
|
||||
int waferThickness = (int) WAFER_THICKNESS.convertToPixels();
|
||||
|
||||
int pointCount = 0;
|
||||
|
||||
switch (type) {
|
||||
case E:
|
||||
case P:
|
||||
pointCount = 7;
|
||||
break;
|
||||
case E_PLUS:
|
||||
pointCount = 9;
|
||||
break;
|
||||
case S:
|
||||
case T:
|
||||
pointCount = 8;
|
||||
break;
|
||||
case M:
|
||||
pointCount = 24;
|
||||
break;
|
||||
}
|
||||
int pointCount = switch (type) {
|
||||
case E, P -> 7;
|
||||
case E_PLUS -> 9;
|
||||
case S, T -> 8;
|
||||
case M -> 24;
|
||||
};
|
||||
|
||||
controlPoints = new Point2D[pointCount];
|
||||
if (pointCount < 12) {
|
||||
@@ -457,12 +446,19 @@ public class SchallerMegaSwitch extends AbstractAngledComponent<String> implemen
|
||||
}
|
||||
|
||||
public enum MegaSwitchType {
|
||||
E("E"), E_PLUS("E+"), M("M"), P("P"), S("S"), T("T");
|
||||
E("E", 5), E_PLUS("E+", 5), M("M", 5),
|
||||
P("P", 5), S("S", 5), T("T", 3);
|
||||
|
||||
private String title;
|
||||
private final int positionCount;
|
||||
|
||||
private MegaSwitchType(String title) {
|
||||
private MegaSwitchType(String title, int positionCount) {
|
||||
this.title = title;
|
||||
this.positionCount = positionCount;
|
||||
}
|
||||
|
||||
public int getPositionCount() {
|
||||
return positionCount;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -481,10 +477,7 @@ public class SchallerMegaSwitch extends AbstractAngledComponent<String> implemen
|
||||
|
||||
@Override
|
||||
public int getPositionCount() {
|
||||
if (type == MegaSwitchType.T) {
|
||||
return 3;
|
||||
}
|
||||
return 5;
|
||||
return type.getPositionCount();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -494,38 +487,22 @@ public class SchallerMegaSwitch extends AbstractAngledComponent<String> implemen
|
||||
|
||||
@Override
|
||||
public boolean arePointsConnected(int index1, int index2, int position) {
|
||||
List<List<int[]>> connections = null;
|
||||
|
||||
switch (type) {
|
||||
case E:
|
||||
connections = E_CONNECTIONS;
|
||||
break;
|
||||
case E_PLUS:
|
||||
connections = E_PLUS_CONNECTIONS;
|
||||
break;
|
||||
case S:
|
||||
connections = S_CONNECTIONS;
|
||||
break;
|
||||
case P:
|
||||
connections = P_CONNECTIONS;
|
||||
break;
|
||||
case T:
|
||||
connections = T_CONNECTIONS;
|
||||
break;
|
||||
case M:
|
||||
connections = M_CONNECTIONS;
|
||||
break;
|
||||
List<List<int[]>> connections = switch (type) {
|
||||
case E -> E_CONNECTIONS;
|
||||
case E_PLUS -> E_PLUS_CONNECTIONS;
|
||||
case S -> S_CONNECTIONS;
|
||||
case P -> P_CONNECTIONS;
|
||||
case T -> T_CONNECTIONS;
|
||||
case M -> M_CONNECTIONS;
|
||||
};
|
||||
|
||||
List<int[]> positionConnections = connections.get(position);
|
||||
for (int[] arr : positionConnections) {
|
||||
if (arr[0] == index1 && arr[1] == index2) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (connections != null) {
|
||||
List<int[]> positionConnections = connections.get(position);
|
||||
for (int[] arr : positionConnections) {
|
||||
if (arr[0] == index1 && arr[1] == index2) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -541,7 +518,30 @@ public class SchallerMegaSwitch extends AbstractAngledComponent<String> implemen
|
||||
public boolean canPointMoveFreely(int pointIndex) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@DynamicEditableProperty(source = SchallerMegaSwitchPositionPropertyValueSource.class)
|
||||
@EditableProperty(name = "Selected Position")
|
||||
@Override
|
||||
public Integer getSelectedPosition() {
|
||||
return selectedPosition;
|
||||
}
|
||||
|
||||
public void setSelectedPosition(Integer selectedPosition) {
|
||||
this.selectedPosition = selectedPosition;
|
||||
this.body = null;
|
||||
}
|
||||
|
||||
@EditableProperty(name = "Markers")
|
||||
public Boolean getShowMarkers() {
|
||||
if (showMarkers == null) {
|
||||
showMarkers = false;
|
||||
}
|
||||
return showMarkers;
|
||||
}
|
||||
|
||||
public void setShowMarkers(Boolean showMarkers) {
|
||||
this.showMarkers = showMarkers;
|
||||
}
|
||||
|
||||
private static final List<List<int[]>> E_CONNECTIONS = Arrays.asList(
|
||||
Arrays.asList(
|
||||
|
||||
+41
@@ -0,0 +1,41 @@
|
||||
package org.diylc.components.guitar;
|
||||
|
||||
import org.diylc.common.PropertyWrapper;
|
||||
import org.diylc.core.AbstractDynamicPropertyValueSource;
|
||||
import org.diylc.core.IDIYComponent;
|
||||
import org.diylc.core.IDynamicPropertySource;
|
||||
import org.diylc.core.ISwitch;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
public class SchallerMegaSwitchPositionPropertyValueSource extends
|
||||
AbstractDynamicPropertyValueSource {
|
||||
|
||||
@Override
|
||||
public List<Object> getAvailableValues() {
|
||||
if (properties == null) {
|
||||
return List.of();
|
||||
}
|
||||
Optional<PropertyWrapper> optionalPropertyWrapper = this.properties.stream().filter(p -> {
|
||||
try {
|
||||
return p.getGetter().getName().equals("getType");
|
||||
} catch (NoSuchMethodException e) {
|
||||
return false;
|
||||
}
|
||||
}).findFirst();
|
||||
if (optionalPropertyWrapper.isEmpty()) {
|
||||
return List.of();
|
||||
}
|
||||
SchallerMegaSwitch.MegaSwitchType
|
||||
switchType = (SchallerMegaSwitch.MegaSwitchType) optionalPropertyWrapper.get().getValue();
|
||||
int positionCount = switchType.getPositionCount();
|
||||
List<Object> res = new ArrayList<>();
|
||||
res.add(null);
|
||||
for (int i = 0; i < positionCount; i++) {
|
||||
res.add(i);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
}
|
||||
+38
@@ -0,0 +1,38 @@
|
||||
package org.diylc.components.guitar;
|
||||
|
||||
import org.diylc.common.PropertyWrapper;
|
||||
import org.diylc.components.electromechanical.ToggleSwitchType;
|
||||
import org.diylc.core.AbstractDynamicPropertyValueSource;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
public class ToggleSwitchPositionPropertyValueSource extends AbstractDynamicPropertyValueSource {
|
||||
|
||||
@Override
|
||||
public List<Object> getAvailableValues() {
|
||||
if (properties == null) {
|
||||
return List.of();
|
||||
}
|
||||
Optional<PropertyWrapper> optionalPropertyWrapper = this.properties.stream().filter(p -> {
|
||||
try {
|
||||
return p.getGetter().getName().equals("getValue");
|
||||
} catch (NoSuchMethodException e) {
|
||||
return false;
|
||||
}
|
||||
}).findFirst();
|
||||
if (optionalPropertyWrapper.isEmpty()) {
|
||||
return List.of();
|
||||
}
|
||||
ToggleSwitchType
|
||||
switchType = (ToggleSwitchType) optionalPropertyWrapper.get().getValue();
|
||||
int positionCount = switchType.getPositionCount();
|
||||
List<Object> res = new ArrayList<>();
|
||||
res.add(null);
|
||||
for (int i = 0; i < positionCount; i++) {
|
||||
res.add(i);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
}
|
||||
+1
-16
@@ -26,23 +26,13 @@ import org.diylc.components.misc.Label;
|
||||
import org.diylc.components.misc.PCBText;
|
||||
import org.diylc.core.IDIYComponent;
|
||||
|
||||
public class TextTransformer implements IComponentTransformer {
|
||||
public class TextTransformer extends SimpleComponentTransformer {
|
||||
|
||||
@Override
|
||||
public boolean canRotate(IDIYComponent<?> component) {
|
||||
return component.getClass().equals(Label.class) || component.getClass().equals(PCBText.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canMirror(IDIYComponent<?> component) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean mirroringChangesCircuit() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void rotate(IDIYComponent<?> component, Point2D center, int direction) {
|
||||
AffineTransform rotate = AffineTransform.getRotateInstance(Math.PI / 2 * direction, center.getX(), center.getY());
|
||||
@@ -76,9 +66,4 @@ public class TextTransformer implements IComponentTransformer {
|
||||
snap.setOrientation(o);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mirror(IDIYComponent<?> component, Point2D center, int direction) {
|
||||
throw new RuntimeException("Unexpected call to mirror() in LabelTransformer");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,6 +30,7 @@ import java.util.stream.Collectors;
|
||||
import javax.swing.JLabel;
|
||||
|
||||
import org.diylc.common.INetlistAnalyzer;
|
||||
import org.diylc.common.NetlistSwitchPreference;
|
||||
import org.diylc.components.electromechanical.ClosedJack1_4;
|
||||
import org.diylc.components.electromechanical.OpenJack1_4;
|
||||
import org.diylc.components.guitar.AbstractGuitarPickup;
|
||||
@@ -56,7 +57,7 @@ import org.diylc.netlist.TreeException;
|
||||
import org.diylc.netlist.TreeLeaf;
|
||||
import org.diylc.netlist.Tree.ITreeWalker;
|
||||
|
||||
public class GuitarDiagramAnalyzer extends NetlistAnalyzer implements INetlistAnalyzer {
|
||||
public class GuitarDiagramAnalyzer extends AbstractNetlistAnalyzer implements INetlistAnalyzer {
|
||||
|
||||
private static Set<String> JACK_TYPES = new HashSet<String>();
|
||||
private static Set<String> POT_TYPES = new HashSet<String>();
|
||||
@@ -89,6 +90,10 @@ public class GuitarDiagramAnalyzer extends NetlistAnalyzer implements INetlistAn
|
||||
RC_TYPES.addAll(RESISTOR_TYPES);
|
||||
}
|
||||
|
||||
private int positiveCount;
|
||||
private int negativeCount;
|
||||
private int noiseCount;
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "Analyze Guitar Diagrams";
|
||||
@@ -109,10 +114,10 @@ public class GuitarDiagramAnalyzer extends NetlistAnalyzer implements INetlistAn
|
||||
return new JLabel().getFont().getName();
|
||||
}
|
||||
|
||||
|
||||
private int positiveCount;
|
||||
private int negativeCount;
|
||||
private int noiseCount;
|
||||
@Override
|
||||
public Set<NetlistSwitchPreference> getSwitchPreference() {
|
||||
return Set.of(NetlistSwitchPreference.WITH);
|
||||
}
|
||||
|
||||
protected Summary summarize(Netlist netlist, Node preferredOutput) throws TreeException {
|
||||
List<String> notes = new ArrayList<String>();
|
||||
|
||||
@@ -0,0 +1,100 @@
|
||||
/*
|
||||
*
|
||||
* DIY Layout Creator (DIYLC). Copyright (c) 2009-2018 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.netlist;
|
||||
|
||||
import java.util.*;
|
||||
import javax.swing.JLabel;
|
||||
import org.diylc.common.INetlistAnalyzer;
|
||||
import org.diylc.common.NetlistSwitchPreference;
|
||||
import org.diylc.components.connectivity.MultimeterProbe;
|
||||
|
||||
public class MultimeterAnalyzer extends AbstractNetlistAnalyzer implements INetlistAnalyzer {
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "Virtual Multimeter";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getShortName() {
|
||||
return "multimeter";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getIconName() {
|
||||
return "Multimeter";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getFontName() {
|
||||
return new JLabel().getFont().getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<NetlistSwitchPreference> getSwitchPreference() {
|
||||
return EnumSet.allOf(NetlistSwitchPreference.class);
|
||||
}
|
||||
|
||||
protected Summary summarize(Netlist netlist, Node preferredOutput) throws TreeException {
|
||||
Tree tree = constructTree(netlist);
|
||||
|
||||
if (tree == null) {
|
||||
return new Summary(netlist, "No components found connecting the two multimeter probes.");
|
||||
}
|
||||
|
||||
List<String> notes = new ArrayList<String>();
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
String asciiTree = tree.toAsciiString();
|
||||
|
||||
if (asciiTree.trim().isEmpty()) {
|
||||
notes.add("No connection detected");
|
||||
} else {
|
||||
sb.append("<br><br>")
|
||||
.append("<font face='Courier New'>")
|
||||
.append(asciiTree)
|
||||
.append("</font>");
|
||||
}
|
||||
|
||||
if (!notes.isEmpty()) {
|
||||
Collections.sort(notes);
|
||||
sb.append("<br><br>");
|
||||
for (String v : notes) {
|
||||
sb.append(v).append("<br>");
|
||||
}
|
||||
}
|
||||
|
||||
return new Summary(netlist, sb.toString());
|
||||
}
|
||||
|
||||
public Tree constructTree(Netlist netlist) throws TreeException {
|
||||
List<Node> probeNodes = find(Set.of(MultimeterProbe.class.getCanonicalName()), null, netlist);
|
||||
|
||||
if (probeNodes.isEmpty()) {
|
||||
throw new TreeException("No multimeter probes are placed on the circuit.");
|
||||
} else if (probeNodes.size() != 2) {
|
||||
throw new TreeException(
|
||||
"Place exactly two multimeter probes on the circuit in order to run the analysis.");
|
||||
} else {
|
||||
probeNodes.sort(Comparator.comparing(n -> n.getDisplayName()));
|
||||
return constructTreeBetween(netlist, probeNodes.get(0), probeNodes.get(1));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -21,11 +21,15 @@
|
||||
*/
|
||||
package org.diylc.netlist;
|
||||
|
||||
import java.lang.reflect.ParameterizedType;
|
||||
import java.util.ArrayList;
|
||||
import java.util.EnumSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.diylc.common.INetlistAnalyzer;
|
||||
import org.diylc.common.NetlistSwitchPreference;
|
||||
import org.diylc.core.IDIYComponent;
|
||||
import org.diylc.netlist.Group;
|
||||
import org.diylc.netlist.Netlist;
|
||||
@@ -33,8 +37,9 @@ import org.diylc.netlist.NetlistAnalyzer;
|
||||
import org.diylc.netlist.Node;
|
||||
import org.diylc.netlist.Summary;
|
||||
import org.diylc.netlist.TreeException;
|
||||
import org.diylc.presenter.ComponentProcessor;
|
||||
|
||||
public class SpiceAnalyzer extends NetlistAnalyzer implements INetlistAnalyzer {
|
||||
public class SpiceAnalyzer extends AbstractNetlistAnalyzer implements INetlistAnalyzer {
|
||||
|
||||
public SpiceAnalyzer() {
|
||||
}
|
||||
@@ -58,6 +63,11 @@ public class SpiceAnalyzer extends NetlistAnalyzer implements INetlistAnalyzer {
|
||||
public String getFontName() {
|
||||
return "Courier New";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<NetlistSwitchPreference> getSwitchPreference() {
|
||||
return EnumSet.allOf(NetlistSwitchPreference.class);
|
||||
}
|
||||
|
||||
protected Summary summarize(Netlist netlist, Node preferredOutput) throws TreeException {
|
||||
// grab all components that are in the netlist
|
||||
@@ -121,7 +131,7 @@ public class SpiceAnalyzer extends NetlistAnalyzer implements INetlistAnalyzer {
|
||||
sb.append(" ");
|
||||
}
|
||||
|
||||
sb.append(c.getValue());
|
||||
sb.append(formatValue(c));
|
||||
|
||||
if (c instanceof ISpiceMapper) {
|
||||
String comment = ((ISpiceMapper)c).getComment();
|
||||
@@ -137,7 +147,27 @@ public class SpiceAnalyzer extends NetlistAnalyzer implements INetlistAnalyzer {
|
||||
.sorted()
|
||||
.collect(Collectors.joining("\n")));
|
||||
}
|
||||
|
||||
|
||||
private static Object formatValue(IDIYComponent<?> c) {
|
||||
if (c.getValue() == null || c.getValue().toString().trim().isEmpty()) {
|
||||
String typeName = ComponentProcessor.getInstance()
|
||||
.extractComponentTypeFrom((Class<? extends IDIYComponent<?>>) c.getClass()).getName();
|
||||
// if (
|
||||
// Void.class.equals(((ParameterizedType) c.getClass()
|
||||
// .getGenericSuperclass()).getActualTypeArguments()[0])) {
|
||||
// return typeName;
|
||||
// }
|
||||
if (typeName.contains(" ")) {
|
||||
return "\"" + typeName + "\"";
|
||||
}
|
||||
return typeName;
|
||||
}
|
||||
if (c.getValue().toString().contains(" ")) {
|
||||
return "\"" + c.getValue() + "\"";
|
||||
}
|
||||
return c.getValue();
|
||||
}
|
||||
|
||||
private static String formatSpiceNode(int i) {
|
||||
return String.format("N%03d" , i);
|
||||
}
|
||||
|
||||
+49
-9
@@ -21,6 +21,8 @@ package org.diylc.netlist;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import java.util.Arrays;
|
||||
|
||||
import org.diylc.components.passive.AxialFilmCapacitor;
|
||||
import org.diylc.components.passive.Resistor;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.diylc.components.electromechanical.OpenJack1_4;
|
||||
@@ -28,13 +30,8 @@ import org.diylc.components.guitar.HumbuckerPickup;
|
||||
import org.diylc.components.guitar.SingleCoilPickup;
|
||||
import org.diylc.components.passive.PotentiometerPanel;
|
||||
import org.diylc.components.passive.RadialCeramicDiskCapacitor;
|
||||
import org.diylc.netlist.Group;
|
||||
import org.diylc.netlist.GuitarDiagramAnalyzer;
|
||||
import org.diylc.netlist.Netlist;
|
||||
import org.diylc.netlist.Tree;
|
||||
import org.diylc.netlist.TreeException;
|
||||
|
||||
public class GuitarNetlistAnalyzerTests {
|
||||
public class GuitarDiagramAnalyzerTests {
|
||||
|
||||
@Test
|
||||
public void testOneSinglePickup() throws TreeException {
|
||||
@@ -67,6 +64,49 @@ public class GuitarNetlistAnalyzerTests {
|
||||
assertEquals("((Volume.1-2 + Pickup.North<-) || Volume.2-3)", s);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOneSinglePickupVolPotTrebleBleedSeries() throws TreeException {
|
||||
OpenJack1_4 jack = new OpenJack1_4();
|
||||
SingleCoilPickup pickup = new SingleCoilPickup();
|
||||
pickup.setName("Pickup");
|
||||
PotentiometerPanel vol = new PotentiometerPanel();
|
||||
vol.setName("Volume");
|
||||
AxialFilmCapacitor cap = new AxialFilmCapacitor();
|
||||
cap.setName("Cbleed");
|
||||
Resistor resistor = new Resistor();
|
||||
resistor.setName("Rbleed");
|
||||
Netlist netlist = new Netlist(Arrays.asList(jack, pickup, vol));
|
||||
Group hotGroup = new Group().connect(pickup, 1).connect(vol, 0).connect(resistor, 1);
|
||||
Group tipGroup = new Group().connect(jack, 0).connect(vol, 1).connect(cap, 1);
|
||||
Group sleeveGroup = new Group().connect(jack, 1).connect(pickup, 2).connect(vol, 2);
|
||||
Group trebleBleedGroup = new Group().connect(cap, 0).connect(resistor, 0);
|
||||
netlist.add(tipGroup).add(tipGroup).add(sleeveGroup).add(hotGroup).add(trebleBleedGroup);
|
||||
Tree tree = new GuitarDiagramAnalyzer().constructTree(netlist);
|
||||
String s = tree.toString();
|
||||
assertEquals("((((Cbleed + Rbleed) || Volume.1-2) + Pickup.North<-) || Volume.2-3)", s);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOneSinglePickupVolPotTrebleBleedParallel() throws TreeException {
|
||||
OpenJack1_4 jack = new OpenJack1_4();
|
||||
SingleCoilPickup pickup = new SingleCoilPickup();
|
||||
pickup.setName("Pickup");
|
||||
PotentiometerPanel vol = new PotentiometerPanel();
|
||||
vol.setName("Volume");
|
||||
AxialFilmCapacitor cap = new AxialFilmCapacitor();
|
||||
cap.setName("Cbleed");
|
||||
Resistor resistor = new Resistor();
|
||||
resistor.setName("Rbleed");
|
||||
Netlist netlist = new Netlist(Arrays.asList(jack, pickup, vol));
|
||||
Group hotGroup = new Group().connect(pickup, 1).connect(vol, 0).connect(resistor, 1).connect(cap, 1);
|
||||
Group tipGroup = new Group().connect(jack, 0).connect(vol, 1).connect(resistor, 0).connect(cap, 0);
|
||||
Group sleeveGroup = new Group().connect(jack, 1).connect(pickup, 2).connect(vol, 2);
|
||||
netlist.add(tipGroup).add(tipGroup).add(sleeveGroup).add(hotGroup);
|
||||
Tree tree = new GuitarDiagramAnalyzer().constructTree(netlist);
|
||||
String s = tree.toString();
|
||||
assertEquals("(((Cbleed || Rbleed || Volume.1-2) + Pickup.North<-) || Volume.2-3)", s);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOneSinglePickupVolTonePot() throws TreeException {
|
||||
OpenJack1_4 jack = new OpenJack1_4();
|
||||
@@ -87,7 +127,7 @@ public class GuitarNetlistAnalyzerTests {
|
||||
netlist.add(tipGroup).add(tipGroup).add(sleeveGroup).add(hotGroup).add(toneGroup);
|
||||
Tree tree = new GuitarDiagramAnalyzer().constructTree(netlist);
|
||||
String s = tree.toString();
|
||||
assertEquals("((Volume.1-2 + (Tone.2-3 + Cap) || Pickup.North<-) || Volume.2-3)", s);
|
||||
assertEquals("((Volume.1-2 + ((Tone.2-3 + Cap) || Pickup.North<-)) || Volume.2-3)", s);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -121,7 +161,7 @@ public class GuitarNetlistAnalyzerTests {
|
||||
Tree tree = new GuitarDiagramAnalyzer().constructTree(netlist);
|
||||
String s = tree.toString();
|
||||
assertEquals(
|
||||
"((Volume.1-2 + (Tone1.2-3 + Cap1) || (Tone2.2-3 + Cap2) || Pickup1.North<- || Pickup2.North<-) || Volume.2-3)",
|
||||
"((Volume.1-2 + (Pickup1.North<- || Pickup2.North<- || (Tone1.2-3 + Cap1) || (Tone2.2-3 + Cap2))) || Volume.2-3)",
|
||||
s);
|
||||
}
|
||||
|
||||
@@ -285,7 +325,7 @@ public class GuitarNetlistAnalyzerTests {
|
||||
Tree tree = new GuitarDiagramAnalyzer().constructTree(netlist);
|
||||
String s = tree.toString();
|
||||
assertEquals(
|
||||
"((Volume.1-2 + (Pickup1.North<- + Pickup1.South<-) || (Pickup2.North<- + Pickup2.South<-) || (Tone1.2-3 + Cap1) || (Tone2.2-3 + Cap2)) || Volume.2-3)",
|
||||
"((Volume.1-2 + ((Pickup1.North<- + Pickup1.South<-) || (Pickup2.North<- + Pickup2.South<-) || (Tone1.2-3 + Cap1) || (Tone2.2-3 + Cap2))) || Volume.2-3)",
|
||||
s);
|
||||
}
|
||||
}
|
||||
@@ -8,18 +8,168 @@ import org.diylc.components.electromechanical.ToggleSwitchType;
|
||||
public class MiniToggleSwitchTests extends AbstractSwitchTests {
|
||||
|
||||
@Test
|
||||
public void testMiniToggleSwitchDPDTononon1() {
|
||||
public void testMiniToggleSwitchSPST() {
|
||||
MiniToggleSwitch toggleSwitch = new MiniToggleSwitch();
|
||||
toggleSwitch.setValue(ToggleSwitchType.DPDT_ononon_1);
|
||||
String[] validCombinations = new String[] {"0,0,1", "0,3,4", "1,0,1", "1,4,5", "2,1,2", "2,4,5"};
|
||||
toggleSwitch.setValue(ToggleSwitchType.SPST);
|
||||
String[] validCombinations = new String[] {"0,0,1"};
|
||||
testSwitch(toggleSwitch, validCombinations);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMiniToggleSwitchDPDTononon2() {
|
||||
public void testMiniToggleSwitchSPDT() {
|
||||
MiniToggleSwitch toggleSwitch = new MiniToggleSwitch();
|
||||
toggleSwitch.setValue(ToggleSwitchType.SPDT);
|
||||
String[] validCombinations = new String[] {
|
||||
"0,0,1",
|
||||
"1,1,2"
|
||||
};
|
||||
testSwitch(toggleSwitch, validCombinations);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMiniToggleSwitchSPDT_off() {
|
||||
MiniToggleSwitch toggleSwitch = new MiniToggleSwitch();
|
||||
toggleSwitch.setValue(ToggleSwitchType.SPDT_off);
|
||||
String[] validCombinations = new String[] {
|
||||
"0,0,1",
|
||||
"2,1,2"
|
||||
};
|
||||
testSwitch(toggleSwitch, validCombinations);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMiniToggleSwitchDPDT() {
|
||||
MiniToggleSwitch toggleSwitch = new MiniToggleSwitch();
|
||||
toggleSwitch.setValue(ToggleSwitchType.DPDT);
|
||||
String[] validCombinations = new String[] {
|
||||
"0,0,1", "0,3,4",
|
||||
"1,1,2", "1,4,5"
|
||||
};
|
||||
testSwitch(toggleSwitch, validCombinations);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMiniToggleSwitchDPDT_off() {
|
||||
MiniToggleSwitch toggleSwitch = new MiniToggleSwitch();
|
||||
toggleSwitch.setValue(ToggleSwitchType.DPDT_off);
|
||||
String[] validCombinations = new String[] {
|
||||
"0,0,1", "0,3,4",
|
||||
"2,1,2", "2,4,5"
|
||||
};
|
||||
testSwitch(toggleSwitch, validCombinations);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMiniToggleSwitchDPDT_ononon1() {
|
||||
MiniToggleSwitch toggleSwitch = new MiniToggleSwitch();
|
||||
toggleSwitch.setValue(ToggleSwitchType.DPDT_ononon_1);
|
||||
String[] validCombinations = new String[] {
|
||||
"0,0,1", "0,3,4",
|
||||
"1,0,1", "1,4,5",
|
||||
"2,1,2", "2,4,5"
|
||||
};
|
||||
testSwitch(toggleSwitch, validCombinations);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMiniToggleSwitchDPDT_ononon2() {
|
||||
MiniToggleSwitch toggleSwitch = new MiniToggleSwitch();
|
||||
toggleSwitch.setValue(ToggleSwitchType.DPDT_ononon_2);
|
||||
String[] validCombinations = new String[] {"0,0,1", "0,3,4", "1,1,2", "1,3,4", "2,1,2", "2,4,5"};
|
||||
String[] validCombinations = new String[] {
|
||||
"0,0,1", "0,3,4",
|
||||
"1,1,2", "1,3,4",
|
||||
"2,1,2", "2,4,5"
|
||||
};
|
||||
testSwitch(toggleSwitch, validCombinations);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMiniToggleSwitch_3PDT() {
|
||||
MiniToggleSwitch toggleSwitch = new MiniToggleSwitch();
|
||||
toggleSwitch.setValue(ToggleSwitchType._3PDT);
|
||||
String[] validCombinations = new String[] {
|
||||
"0,0,1", "0,3,4", "0,6,7",
|
||||
"1,1,2", "1,4,5", "1,7,8"
|
||||
};
|
||||
testSwitch(toggleSwitch, validCombinations);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMiniToggleSwitch_3PDT_off() {
|
||||
MiniToggleSwitch toggleSwitch = new MiniToggleSwitch();
|
||||
toggleSwitch.setValue(ToggleSwitchType._3PDT_off);
|
||||
String[] validCombinations = new String[] {
|
||||
"0,0,1", "0,3,4", "0,6,7",
|
||||
"2,1,2", "2,4,5", "2,7,8"
|
||||
};
|
||||
testSwitch(toggleSwitch, validCombinations);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMiniToggleSwitch_4PDT() {
|
||||
MiniToggleSwitch toggleSwitch = new MiniToggleSwitch();
|
||||
toggleSwitch.setValue(ToggleSwitchType._4PDT);
|
||||
String[] validCombinations = new String[] {
|
||||
"0,0,1", "0,3,4", "0,6,7", "0,9,10",
|
||||
"1,1,2", "1,4,5", "1,7,8", "1,10,11"
|
||||
};
|
||||
testSwitch(toggleSwitch, validCombinations);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMiniToggleSwitch_4PDT_off() {
|
||||
MiniToggleSwitch toggleSwitch = new MiniToggleSwitch();
|
||||
toggleSwitch.setValue(ToggleSwitchType._4PDT_off);
|
||||
String[] validCombinations = new String[] {
|
||||
"0,0,1", "0,3,4", "0,6,7", "0,9,10",
|
||||
"2,1,2", "2,4,5", "2,7,8", "2,10,11"
|
||||
};
|
||||
testSwitch(toggleSwitch, validCombinations);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMiniToggleSwitch_4PDT_ononon1() {
|
||||
MiniToggleSwitch toggleSwitch = new MiniToggleSwitch();
|
||||
toggleSwitch.setValue(ToggleSwitchType._4PDT_ononon_1);
|
||||
String[] validCombinations = new String[] {
|
||||
"0,0,1", "0,3,4", "0,6,7", "0,9,10",
|
||||
"1,0,1", "1,4,5", "1,6,7", "1,10,11",
|
||||
"2,1,2", "2,4,5", "2,7,8", "2,10,11"
|
||||
};
|
||||
testSwitch(toggleSwitch, validCombinations);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMiniToggleSwitch_4PDT_ononon2() {
|
||||
MiniToggleSwitch toggleSwitch = new MiniToggleSwitch();
|
||||
toggleSwitch.setValue(ToggleSwitchType._4PDT_ononon_2);
|
||||
String[] validCombinations = new String[] {
|
||||
"0,0,1", "0,3,4", "0,6,7", "0,9,10",
|
||||
"1,1,2", "1,3,4", "1,7,8", "1,9,10",
|
||||
"2,1,2", "2,4,5", "2,7,8", "2,10,11"
|
||||
};
|
||||
testSwitch(toggleSwitch, validCombinations);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMiniToggleSwitch_5PDT() {
|
||||
MiniToggleSwitch toggleSwitch = new MiniToggleSwitch();
|
||||
toggleSwitch.setValue(ToggleSwitchType._5PDT);
|
||||
String[] validCombinations = new String[] {
|
||||
"0,0,1", "0,3,4", "0,6,7", "0,9,10", "0,12,13",
|
||||
"1,1,2", "1,4,5", "1,7,8", "1,10,11", "1,13,14"
|
||||
};
|
||||
testSwitch(toggleSwitch, validCombinations);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMiniToggleSwitch_5PDT_off() {
|
||||
MiniToggleSwitch toggleSwitch = new MiniToggleSwitch();
|
||||
toggleSwitch.setValue(ToggleSwitchType._5PDT_off);
|
||||
String[] validCombinations = new String[] {
|
||||
"0,0,1", "0,3,4", "0,6,7", "0,9,10", "0,12,13",
|
||||
"2,1,2", "2,4,5", "2,7,8", "2,10,11", "2,13,14"
|
||||
};
|
||||
testSwitch(toggleSwitch, validCombinations);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@ import org.junit.Test;
|
||||
import org.diylc.components.electromechanical.SlideSwitch;
|
||||
import org.diylc.components.electromechanical.SlideSwitchType;
|
||||
|
||||
public abstract class SlideSwitchTests extends AbstractSwitchTests {
|
||||
public class SlideSwitchTests extends AbstractSwitchTests {
|
||||
|
||||
@Test
|
||||
public void testSlideSwitchSPDT() {
|
||||
@@ -19,7 +19,10 @@ public abstract class SlideSwitchTests extends AbstractSwitchTests {
|
||||
public void testSlideSwitchDPDT() {
|
||||
SlideSwitch slideSwitch = new SlideSwitch();
|
||||
slideSwitch.setValue(SlideSwitchType.DPDT);
|
||||
String[] validCombinations = new String[] {"0,0,2", "0,1,3", "1,2,4", "1,3,5"};
|
||||
String[] validCombinations = new String[] {
|
||||
"0,0,1", "0,3,4", // Position 1 connections
|
||||
"1,1,2", "1,4,5" // Position 2 connections
|
||||
};
|
||||
testSwitch(slideSwitch, validCombinations);
|
||||
}
|
||||
|
||||
@@ -27,7 +30,11 @@ public abstract class SlideSwitchTests extends AbstractSwitchTests {
|
||||
public void testSlideSwitchDP3T() {
|
||||
SlideSwitch slideSwitch = new SlideSwitch();
|
||||
slideSwitch.setValue(SlideSwitchType.DP3T);
|
||||
String[] validCombinations = new String[] {"0,0,2", "0,1,3", "1,2,4", "1,3,5", "2,4,6", "2,5,7"};
|
||||
String[] validCombinations = new String[] {
|
||||
"0,0,1", "0,4,5", // Position 1 connections
|
||||
"1,1,2", "1,5,6", // Position 2 connections
|
||||
"2,2,3", "2,6,7" // Position 3 connections
|
||||
};
|
||||
testSwitch(slideSwitch, validCombinations);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,16 +6,11 @@ SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
|
||||
# Set DEBUG environment variable
|
||||
export DEBUG=true
|
||||
|
||||
# Build classpath from lib and library directories
|
||||
CLASSPATH=""
|
||||
for jar in "$SCRIPT_DIR/../lib"/*.jar "$SCRIPT_DIR/../library"/*.jar; do
|
||||
if [ -f "$jar" ]; then
|
||||
CLASSPATH="$CLASSPATH:$jar"
|
||||
fi
|
||||
done
|
||||
|
||||
# Remove leading colon
|
||||
CLASSPATH="${CLASSPATH#:}"
|
||||
|
||||
# Run the VersionReader class
|
||||
java -cp "$CLASSPATH" org.diylc.utils.VersionReader "$SCRIPT_DIR/../"
|
||||
java -cp "../target/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 \
|
||||
org.diylc.utils.VersionReader "$SCRIPT_DIR/../"
|
||||
|
||||
@@ -29,5 +29,12 @@
|
||||
</includes>
|
||||
<fileMode>755</fileMode>
|
||||
</fileSet>
|
||||
<fileSet>
|
||||
<directory>${project.basedir}/src/main/resources</directory>
|
||||
<outputDirectory>/</outputDirectory>
|
||||
<includes>
|
||||
<include>icons/**</include>
|
||||
</includes>
|
||||
</fileSet>
|
||||
</fileSets>
|
||||
</assembly>
|
||||
|
||||
Binary file not shown.
Binary file not shown.
@@ -3,7 +3,7 @@
|
||||
<dontWrapJar>true</dontWrapJar>
|
||||
<headerType>gui</headerType>
|
||||
<jar>diylc.jar</jar>
|
||||
<outfile>C:\Users\bancika\Documents\GitHub\diy-layout-creator\diylc\diylc-swing\deploy\diylc-x64.exe</outfile>
|
||||
<outfile>C:\Users\bancika\Documents\GitHub\diy-layout-creator\diylc\diylc-swing\deploy\win\diylc-x64.exe</outfile>
|
||||
<errTitle></errTitle>
|
||||
<cmdLine></cmdLine>
|
||||
<chdir>.</chdir>
|
||||
@@ -13,10 +13,9 @@
|
||||
<stayAlive>false</stayAlive>
|
||||
<restartOnCrash>false</restartOnCrash>
|
||||
<manifest></manifest>
|
||||
<icon>C:\Users\bancika\Documents\GitHub\diy-layout-creator\diylc\diylc-swing\icons\diylc.ico</icon>
|
||||
<icon>C:\Users\bancika\Documents\GitHub\diy-layout-creator\diylc\diylc-swing\src\main\resources\icons\diylc.ico</icon>
|
||||
<classPath>
|
||||
<mainClass>org.diylc.DIYLCStarter</mainClass>
|
||||
<cp>lib</cp>
|
||||
</classPath>
|
||||
<jre>
|
||||
<path>jre17</path>
|
||||
@@ -28,7 +27,6 @@
|
||||
<maxHeapSize>4096</maxHeapSize>
|
||||
<opt>-Dorg.diylc.scriptRun=true</opt>
|
||||
<opt>-Dfile.encoding=UTF-8</opt>
|
||||
<opt>-javaagent:lib/jar-loader.jar</opt>
|
||||
<opt>--add-opens java.base/java.util=ALL-UNNAMED</opt>
|
||||
<opt>--add-opens java.base/java.lang=ALL-UNNAMED</opt>
|
||||
<opt>--add-opens java.base/java.text=ALL-UNNAMED</opt>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<dontWrapJar>true</dontWrapJar>
|
||||
<headerType>gui</headerType>
|
||||
<jar>diylc.jar</jar>
|
||||
<outfile>C:\Users\bancika\Documents\GitHub\diy-layout-creator\diylc\diylc-swing\deploy\diylc-x86.exe</outfile>
|
||||
<outfile>C:\Users\bancika\Documents\GitHub\diy-layout-creator\diylc\diylc-swing\deploy\win\diylc-x86.exe</outfile>
|
||||
<errTitle></errTitle>
|
||||
<cmdLine></cmdLine>
|
||||
<chdir>.</chdir>
|
||||
@@ -13,10 +13,9 @@
|
||||
<stayAlive>false</stayAlive>
|
||||
<restartOnCrash>false</restartOnCrash>
|
||||
<manifest></manifest>
|
||||
<icon>C:\Users\bancika\Documents\GitHub\diy-layout-creator\diylc\diylc-swing\icons\diylc.ico</icon>
|
||||
<icon>C:\Users\bancika\Documents\GitHub\diy-layout-creator\diylc\diylc-swing\src\main\resources\icons\diylc.ico</icon>
|
||||
<classPath>
|
||||
<mainClass>org.diylc.DIYLCStarter</mainClass>
|
||||
<cp>lib</cp>
|
||||
</classPath>
|
||||
<jre>
|
||||
<path>jre17</path>
|
||||
@@ -24,11 +23,10 @@
|
||||
<requires64Bit>false</requires64Bit>
|
||||
<minVersion>17</minVersion>
|
||||
<maxVersion></maxVersion>
|
||||
<initialHeapSize>512</initialHeapSize>
|
||||
<initialHeapSize>1024</initialHeapSize>
|
||||
<maxHeapSize>2048</maxHeapSize>
|
||||
<opt>-Dorg.diylc.scriptRun=true</opt>
|
||||
<opt>-Dfile.encoding=UTF-8</opt>
|
||||
<opt>-javaagent:lib/jar-loader.jar</opt>
|
||||
<opt>--add-opens java.base/java.util=ALL-UNNAMED</opt>
|
||||
<opt>--add-opens java.base/java.lang=ALL-UNNAMED</opt>
|
||||
<opt>--add-opens java.base/java.text=ALL-UNNAMED</opt>
|
||||
|
||||
@@ -20,20 +20,24 @@
|
||||
10 throws / 10 positions
|
||||
11 throws / 11 positions
|
||||
12 throws / 12 positions
|
||||
135 degrees clockwise
|
||||
180 degrees clockwise
|
||||
1P12T
|
||||
2 throws / 2 positions
|
||||
2 throws / 3 positions / OFF even positions
|
||||
225 degrees clockwise
|
||||
270 degrees clockwise
|
||||
2P5T
|
||||
2P6T
|
||||
3 throws / 3 positions
|
||||
3 throws / 5 positions / SHORT even positions
|
||||
315 degrees clockwise
|
||||
3P4T
|
||||
3PDT
|
||||
3PDT (On/Off/On)
|
||||
4 band
|
||||
4 throws / 4 positions
|
||||
45 degrees clockwise
|
||||
4P3T
|
||||
4P5T
|
||||
4P5T (Super/Mega)
|
||||
@@ -604,6 +608,7 @@ Vertical Inline
|
||||
Vertical Offset 1
|
||||
Vertical Offset 2
|
||||
View
|
||||
Virtual Multimeter
|
||||
Visible
|
||||
Voltage
|
||||
Wafer
|
||||
|
||||
+110
-17
@@ -7,7 +7,7 @@
|
||||
<parent>
|
||||
<groupId>org.diylc</groupId>
|
||||
<artifactId>diylc-parent</artifactId>
|
||||
<version>5.1.0</version>
|
||||
<version>5.2.0</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>diylc-swing</artifactId>
|
||||
@@ -159,9 +159,9 @@
|
||||
<dependency>
|
||||
<groupId>org.diylc.local</groupId>
|
||||
<artifactId>swing-framework</artifactId>
|
||||
<version>1.0</version>
|
||||
<version>1.1</version>
|
||||
<scope>system</scope>
|
||||
<systemPath>${project.basedir}/../lib/swing-framework-1.0.jar</systemPath>
|
||||
<systemPath>${project.basedir}/../lib/swing-framework-1.1.jar</systemPath>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
@@ -586,6 +586,99 @@
|
||||
</build>
|
||||
</profile>
|
||||
|
||||
<profile>
|
||||
<id>win64-zip</id>
|
||||
<properties>
|
||||
<jdk.version>17.0.14+7</jdk.version>
|
||||
<jdk.version.file>17.0.14_7</jdk.version.file>
|
||||
<jdk.archive.win64>OpenJDK17U-jre_x64_windows_hotspot_${jdk.version.file}.zip</jdk.archive.win64>
|
||||
<jdk.url.win64>https://github.com/adoptium/temurin17-binaries/releases/download/jdk-${jdk.version}/${jdk.archive.win64}</jdk.url.win64>
|
||||
<jre.dest.win64>${project.build.directory}/jre_win</jre.dest.win64>
|
||||
</properties>
|
||||
<build>
|
||||
<plugins>
|
||||
<!-- 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_win folder -->
|
||||
<delete dir="${jre.dest.win64}" />
|
||||
|
||||
<!-- Create folder to hold extracted JRE -->
|
||||
<mkdir dir="${jre.dest.win64}" />
|
||||
|
||||
<!-- Download JRE 64-bit for Windows -->
|
||||
<mkdir dir="${project.build.directory}/downloads" />
|
||||
<get src="${jdk.url.win64}"
|
||||
dest="${project.build.directory}/downloads/${jdk.archive.win64}"
|
||||
usetimestamp="true" />
|
||||
|
||||
<!-- Extract JRE into jre_win -->
|
||||
<unzip src="${project.build.directory}/downloads/${jdk.archive.win64}"
|
||||
dest="${jre.dest.win64}" />
|
||||
|
||||
<!-- Move files up one level -->
|
||||
<move todir="${jre.dest.win64}">
|
||||
<fileset dir="${jre.dest.win64}/jdk-${jdk.version}-jre" />
|
||||
</move>
|
||||
|
||||
<!-- Remove empty top-level folder -->
|
||||
<delete dir="${jre.dest.win64}/jdk-${jdk.version}-jre" />
|
||||
</target>
|
||||
</configuration>
|
||||
</execution>
|
||||
|
||||
<!-- Create ZIP package -->
|
||||
<execution>
|
||||
<id>create-zip-package</id>
|
||||
<phase>package</phase>
|
||||
<goals>
|
||||
<goal>run</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<target>
|
||||
<!-- Create a temporary directory for the zip contents -->
|
||||
<mkdir dir="${project.build.directory}/zip-temp" />
|
||||
|
||||
<!-- Copy JAR file -->
|
||||
<copy file="${project.build.directory}/diylc.jar"
|
||||
tofile="${project.build.directory}/zip-temp/diylc.jar" />
|
||||
|
||||
<!-- Copy and rename the executable -->
|
||||
<copy file="${project.basedir}/deploy/win/diylc-x64.exe"
|
||||
tofile="${project.build.directory}/zip-temp/diylc.exe" />
|
||||
|
||||
<!-- Copy JRE to jre17 folder instead of jre -->
|
||||
<copy todir="${project.build.directory}/zip-temp/jre17">
|
||||
<fileset dir="${jre.dest.win64}" />
|
||||
</copy>
|
||||
|
||||
<!-- Create the ZIP file -->
|
||||
<zip destfile="${project.build.directory}/diylc-${project.version}-win64.zip">
|
||||
<fileset dir="${project.build.directory}/zip-temp" />
|
||||
</zip>
|
||||
|
||||
<!-- Clean up temporary directory -->
|
||||
<delete dir="${project.build.directory}/zip-temp" />
|
||||
</target>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</profile>
|
||||
|
||||
<profile>
|
||||
<id>mac-x86</id>
|
||||
<properties>
|
||||
@@ -737,13 +830,6 @@
|
||||
<option value="-Xdock:name=DIY Layout Creator"/>
|
||||
<option value="-Xdock:icon=Contents/Resources/diylc.icns"/>
|
||||
</bundleapp>
|
||||
|
||||
<!-- First remove existing signatures -->
|
||||
<echo message="Removing any existing signatures..."/>
|
||||
<exec executable="codesign" failonerror="false">
|
||||
<arg value="--remove-signature"/>
|
||||
<arg value="${project.build.directory}/DIYLC.app"/>
|
||||
</exec>
|
||||
|
||||
<echo message="Creating unsigned zip for distribution..."/>
|
||||
<!-- Create unsigned zip for distribution -->
|
||||
@@ -753,6 +839,13 @@
|
||||
</zip>
|
||||
<echo message="Unsigned zip created at: ${project.build.directory}/diylc-${project.version}-osx-x86-unsigned.zip"/>
|
||||
|
||||
<!-- First remove existing signatures -->
|
||||
<echo message="Removing any existing signatures..."/>
|
||||
<exec executable="codesign" failonerror="false">
|
||||
<arg value="--remove-signature"/>
|
||||
<arg value="${project.build.directory}/DIYLC.app"/>
|
||||
</exec>
|
||||
|
||||
<!-- Sign the entire app bundle in one shot -->
|
||||
<echo message="Signing complete app bundle..."/>
|
||||
<exec executable="codesign" failonerror="true">
|
||||
@@ -1051,13 +1144,6 @@
|
||||
<option value="-Xdock:name=DIY Layout Creator"/>
|
||||
<option value="-Xdock:icon=Contents/Resources/diylc.icns"/>
|
||||
</bundleapp>
|
||||
|
||||
<!-- First remove existing signatures -->
|
||||
<echo message="Removing any existing signatures..."/>
|
||||
<exec executable="codesign" failonerror="false">
|
||||
<arg value="--remove-signature"/>
|
||||
<arg value="${project.build.directory}/DIYLC.app"/>
|
||||
</exec>
|
||||
|
||||
<echo message="Creating unsigned zip for distribution..."/>
|
||||
<!-- Create unsigned zip for distribution -->
|
||||
@@ -1067,6 +1153,13 @@
|
||||
</zip>
|
||||
<echo message="Unsigned zip created at: ${project.build.directory}/diylc-${project.version}-osx-arm-unsigned.zip"/>
|
||||
|
||||
<!-- First remove existing signatures -->
|
||||
<echo message="Removing any existing signatures..."/>
|
||||
<exec executable="codesign" failonerror="false">
|
||||
<arg value="--remove-signature"/>
|
||||
<arg value="${project.build.directory}/DIYLC.app"/>
|
||||
</exec>
|
||||
|
||||
<!-- Sign the entire app bundle in one shot -->
|
||||
<echo message="Signing complete app bundle..."/>
|
||||
<exec executable="codesign" failonerror="true">
|
||||
|
||||
@@ -21,6 +21,7 @@ import java.awt.Desktop;
|
||||
import java.io.File;
|
||||
import java.io.InputStream;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.net.URL;
|
||||
import java.util.Arrays;
|
||||
import java.util.Properties;
|
||||
@@ -43,6 +44,7 @@ import org.diylc.serialization.ProjectFileManager;
|
||||
import org.diylc.swing.gui.MainFrame;
|
||||
import org.diylc.swing.gui.TemplateDialog;
|
||||
import org.diylc.swing.plugins.file.ProjectDrawingProvider;
|
||||
import org.diylc.utils.UIScalingUtil;
|
||||
|
||||
/**
|
||||
* Main class that runs DIYLC.
|
||||
@@ -96,14 +98,25 @@ public class DIYLCStarter {
|
||||
}
|
||||
|
||||
initializeConfiguration();
|
||||
|
||||
if (exportMode) {
|
||||
|
||||
try {
|
||||
SwingUtilities.invokeAndWait(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
UIScalingUtil.initialize();
|
||||
|
||||
}
|
||||
});
|
||||
} catch (InterruptedException e) {
|
||||
throw new RuntimeException(e);
|
||||
} catch (InvocationTargetException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
if (exportMode) {
|
||||
LOG.info("Running in export mode with params: " + String.join(", ", args));
|
||||
}
|
||||
|
||||
// disable HIGHLIGHT_CONTINUITY_AREA config, keep it transient
|
||||
ConfigurationManager.getInstance().writeValue(IPlugInPort.HIGHLIGHT_CONTINUITY_AREA, false);
|
||||
|
||||
LOG.info("Loading languages...");
|
||||
|
||||
LangUtil.configure();
|
||||
|
||||
@@ -21,6 +21,7 @@ import java.awt.datatransfer.Clipboard;
|
||||
import java.awt.datatransfer.ClipboardOwner;
|
||||
import javax.swing.Icon;
|
||||
import org.apache.log4j.Logger;
|
||||
import org.diylc.swing.actions.analyze.HighlightConnectedAreasAction;
|
||||
import org.diylc.swingframework.IDrawingProvider;
|
||||
|
||||
import org.diylc.common.INetlistAnalyzer;
|
||||
@@ -34,9 +35,9 @@ import org.diylc.swing.actions.ExportGerberAction;
|
||||
import org.diylc.swing.actions.ExportPNGAction;
|
||||
import org.diylc.swing.actions.FindAction;
|
||||
import org.diylc.swing.actions.FlexibleLeadsAction;
|
||||
import org.diylc.swing.actions.GenerateNetlistAction;
|
||||
import org.diylc.swing.actions.analyze.GenerateNetlistAction;
|
||||
import org.diylc.swing.actions.RenumberAction;
|
||||
import org.diylc.swing.actions.SummarizeNetlistAction;
|
||||
import org.diylc.swing.actions.analyze.SummarizeNetlistAction;
|
||||
import org.diylc.swing.actions.ThemeAction;
|
||||
import org.diylc.swing.actions.ToggleAction;
|
||||
import org.diylc.swing.actions.edit.BringToFrontAction;
|
||||
@@ -247,11 +248,6 @@ public class ActionFactory {
|
||||
return new ConfigAction(plugInPort, title, configKey, defaultValue);
|
||||
}
|
||||
|
||||
public ConfigAction createConfigAction(IPlugInPort plugInPort, String title, String configKey,
|
||||
boolean defaultValue, String tipKey) {
|
||||
return new ConfigAction(plugInPort, title, configKey, defaultValue, tipKey);
|
||||
}
|
||||
|
||||
public ToggleAction createToggleAction(String title, String configKey, String groupName,
|
||||
String defaultValue) {
|
||||
return new ToggleAction(title, configKey, groupName, defaultValue, null);
|
||||
@@ -280,11 +276,15 @@ public class ActionFactory {
|
||||
}
|
||||
|
||||
public SummarizeNetlistAction createSummarizeNetlistAction(IPlugInPort plugInPort,
|
||||
ISwingUI swingUI, INetlistAnalyzer summarizer) {
|
||||
return new SummarizeNetlistAction(plugInPort, swingUI, summarizer);
|
||||
ISwingUI swingUI, INetlistAnalyzer summarizer, boolean includeSwitches) {
|
||||
return new SummarizeNetlistAction(plugInPort, swingUI, summarizer, includeSwitches);
|
||||
}
|
||||
|
||||
public CheckProximityAction createCheckProximityAction(IPlugInPort plugInPort, ISwingUI swingUI) {
|
||||
return new CheckProximityAction(plugInPort, swingUI);
|
||||
}
|
||||
|
||||
public HighlightConnectedAreasAction createHighlightConnectedAreasAction(IPlugInPort plugInPort) {
|
||||
return new HighlightConnectedAreasAction(plugInPort);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -49,7 +49,7 @@ public class CheckProximityAction extends AbstractAction implements Cloneable {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
PropertyWrapper wrapper = new PropertyWrapper("Threshold", Size.class, "getThreshold",
|
||||
"setThreshold", false, new PositiveNonZeroMeasureValidator(), 0);
|
||||
"setThreshold", false, new PositiveNonZeroMeasureValidator(), 0, null);
|
||||
try {
|
||||
wrapper.readFrom(CheckProximityAction.this);
|
||||
} catch (Exception e1) {
|
||||
@@ -105,4 +105,4 @@ public class CheckProximityAction extends AbstractAction implements Cloneable {
|
||||
public Object clone() throws CloneNotSupportedException {
|
||||
return new CheckProximityAction(plugInPort, swingUI);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+2
-2
@@ -1,4 +1,4 @@
|
||||
package org.diylc.swing.actions;
|
||||
package org.diylc.swing.actions.analyze;
|
||||
|
||||
import java.awt.Dimension;
|
||||
import java.awt.event.ActionEvent;
|
||||
@@ -83,4 +83,4 @@ public class GenerateNetlistAction extends AbstractAction {
|
||||
}
|
||||
}, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
+45
@@ -0,0 +1,45 @@
|
||||
package org.diylc.swing.actions.analyze;
|
||||
|
||||
import org.diylc.appframework.miscutils.ConfigurationManager;
|
||||
import org.diylc.appframework.miscutils.IConfigListener;
|
||||
import org.diylc.common.IPlugInPort;
|
||||
import org.diylc.common.OperationMode;
|
||||
import org.diylc.core.IView;
|
||||
import org.diylc.swing.ActionFactory;
|
||||
import org.diylc.swing.gui.DialogFactory;
|
||||
import org.diylc.utils.IconLoader;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.awt.event.ActionEvent;
|
||||
|
||||
public class HighlightConnectedAreasAction extends AbstractAction {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private final IPlugInPort plugInPort;
|
||||
|
||||
public HighlightConnectedAreasAction(IPlugInPort plugInPort) {
|
||||
super();
|
||||
this.plugInPort = plugInPort;
|
||||
|
||||
putValue(AbstractAction.NAME, "Highlight Connected Areas");
|
||||
putValue(IView.CHECK_BOX_MENU_ITEM, true);
|
||||
putValue(AbstractAction.SELECTED_KEY,
|
||||
plugInPort.getOperationMode() == OperationMode.HIGHLIGHT_CONNECTED_AREAS);
|
||||
putValue(AbstractAction.SMALL_ICON, IconLoader.LaserPointer.getIcon());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
if (Boolean.TRUE.equals(getValue(AbstractAction.SELECTED_KEY))) {
|
||||
plugInPort.setOperationMode(OperationMode.HIGHLIGHT_CONNECTED_AREAS);
|
||||
} else {
|
||||
plugInPort.setOperationMode(OperationMode.EDIT);
|
||||
}
|
||||
}
|
||||
|
||||
public void refreshState() {
|
||||
putValue(AbstractAction.SELECTED_KEY,
|
||||
plugInPort.getOperationMode() == OperationMode.HIGHLIGHT_CONNECTED_AREAS);
|
||||
}
|
||||
}
|
||||
+12
-5
@@ -1,4 +1,4 @@
|
||||
package org.diylc.swing.actions;
|
||||
package org.diylc.swing.actions.analyze;
|
||||
|
||||
import java.awt.Dimension;
|
||||
import java.awt.event.ActionEvent;
|
||||
@@ -22,14 +22,21 @@ public class SummarizeNetlistAction extends AbstractAction {
|
||||
private IPlugInPort plugInPort;
|
||||
private ISwingUI swingUI;
|
||||
private INetlistAnalyzer summarizer;
|
||||
private final boolean includeSwitches;
|
||||
|
||||
public SummarizeNetlistAction(IPlugInPort plugInPort, ISwingUI swingUI,
|
||||
INetlistAnalyzer summarizer) {
|
||||
INetlistAnalyzer summarizer, boolean includeSwitches) {
|
||||
super();
|
||||
this.plugInPort = plugInPort;
|
||||
this.swingUI = swingUI;
|
||||
this.summarizer = summarizer;
|
||||
putValue(AbstractAction.NAME, summarizer.getName());
|
||||
this.includeSwitches = includeSwitches;
|
||||
String name = summarizer.getName();
|
||||
if (summarizer.getSwitchPreference().size() > 1) {
|
||||
name += includeSwitches ?
|
||||
" (incl. Switches)" : " (excl. Switches)";
|
||||
}
|
||||
putValue(AbstractAction.NAME, name);
|
||||
putValue(AbstractAction.SMALL_ICON,
|
||||
Enum.valueOf(IconLoader.class, summarizer.getIconName()).getIcon());
|
||||
}
|
||||
@@ -41,7 +48,7 @@ public class SummarizeNetlistAction extends AbstractAction {
|
||||
|
||||
@Override
|
||||
public List<Summary> doInBackground() throws Exception {
|
||||
List<Netlist> netlists = plugInPort.extractNetlists(true);
|
||||
List<Netlist> netlists = plugInPort.extractNetlists(includeSwitches);
|
||||
if (netlists == null || netlists.isEmpty()) {
|
||||
throw new Exception("The generated netlist is empty, nothing to show.");
|
||||
}
|
||||
@@ -84,4 +91,4 @@ public class SummarizeNetlistAction extends AbstractAction {
|
||||
}
|
||||
}, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -68,7 +68,7 @@ public class InfoDialog extends ButtonDialog {
|
||||
super.setVisible(b);
|
||||
}
|
||||
|
||||
private static String[] tipKeys = new String[] {IPlugInPort.HIGHLIGHT_CONTINUITY_AREA};
|
||||
private static String[] tipKeys = new String[] {"HIGHLIGHT_CONTINUITY_AREA"};
|
||||
private static String[] messages =
|
||||
new String[] {"Click on a component to highlight continuity area directly or indirectly connected to it.<br>In this mode components cannot be moved or edited. In order to continue editing,<br>this mode needs to be switched OFF."};
|
||||
}
|
||||
|
||||
@@ -59,6 +59,7 @@ import org.apache.log4j.Logger;
|
||||
import org.diylc.appframework.miscutils.ConfigurationManager;
|
||||
import org.diylc.appframework.miscutils.IConfigurationManager;
|
||||
import org.diylc.swing.IDynamicSubmenuHandler;
|
||||
import org.diylc.swing.plugins.analyze.AnalyzeMenuPlugin;
|
||||
import org.diylc.swingframework.ButtonDialog;
|
||||
|
||||
import org.diylc.common.BadPositionException;
|
||||
@@ -126,6 +127,7 @@ public class MainFrame extends JFrame implements ISwingUI {
|
||||
|
||||
presenter.installPlugin(() -> new ToolBox(this));
|
||||
presenter.installPlugin(() -> new FileMenuPlugin(this));
|
||||
presenter.installPlugin(() -> new AnalyzeMenuPlugin(this));
|
||||
presenter.installPlugin(() -> new EditMenuPlugin(this));
|
||||
presenter.installPlugin(() -> new ConfigPlugin(this));
|
||||
presenter.installPlugin(() -> new LayersMenuPlugin(this));
|
||||
|
||||
+19
-11
@@ -29,6 +29,7 @@ import java.awt.event.MouseEvent;
|
||||
import java.util.ArrayList;
|
||||
import java.util.EnumSet;
|
||||
import java.util.List;
|
||||
import java.util.function.Consumer;
|
||||
import javax.swing.BorderFactory;
|
||||
import javax.swing.JLabel;
|
||||
import javax.swing.JPanel;
|
||||
@@ -38,11 +39,7 @@ import javax.swing.SwingUtilities;
|
||||
import org.apache.log4j.Logger;
|
||||
import org.diylc.appframework.miscutils.Utils;
|
||||
|
||||
import org.diylc.common.BadPositionException;
|
||||
import org.diylc.common.EventType;
|
||||
import org.diylc.common.IComponentTransformer;
|
||||
import org.diylc.common.IPlugIn;
|
||||
import org.diylc.common.IPlugInPort;
|
||||
import org.diylc.common.*;
|
||||
import org.diylc.lang.LangUtil;
|
||||
import org.diylc.swing.ActionFactory;
|
||||
import org.diylc.swing.ISwingUI;
|
||||
@@ -68,6 +65,7 @@ public class ActionBarPlugin implements IPlugIn {
|
||||
|
||||
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 Consumer<Boolean> highlightConnectedAreasUpdateAction;
|
||||
|
||||
public ActionBarPlugin(ISwingUI swingUI) {
|
||||
this.swingUI = swingUI;
|
||||
@@ -165,7 +163,14 @@ public class ActionBarPlugin implements IPlugIn {
|
||||
configToolbar.add(new JLabel(" "));
|
||||
|
||||
configToolbar.add(LangUtil.translate("Continuous Creation"), IPlugInPort.CONTINUOUS_CREATION_KEY, IconLoader.Elements.getIcon(), false);
|
||||
configToolbar.add(LangUtil.translate("Highlight Connected Areas") + " (Alt)", IPlugInPort.HIGHLIGHT_CONTINUITY_AREA, IconLoader.LaserPointer.getIcon(), false);
|
||||
highlightConnectedAreasUpdateAction =
|
||||
configToolbar.add(LangUtil.translate("Highlight Connected Areas") + " (Alt)",
|
||||
IconLoader.LaserPointer.getIcon(),
|
||||
plugInPort.getOperationMode() == OperationMode.HIGHLIGHT_CONNECTED_AREAS,
|
||||
() -> plugInPort.setOperationMode(
|
||||
plugInPort.getOperationMode() == OperationMode.EDIT ?
|
||||
OperationMode.HIGHLIGHT_CONNECTED_AREAS :
|
||||
OperationMode.EDIT));
|
||||
configToolbar.add(LangUtil.translate("Sticky Points") + " (Ctrl)", IPlugInPort.STICKY_POINTS_KEY, IconLoader.GraphNodes.getIcon(), true);
|
||||
}
|
||||
return configToolbar;
|
||||
@@ -207,14 +212,17 @@ public class ActionBarPlugin implements IPlugIn {
|
||||
|
||||
@Override
|
||||
public EnumSet<EventType> getSubscribedEventTypes() {
|
||||
return EnumSet.of(EventType.SELECTION_CHANGED);
|
||||
return EnumSet.of(EventType.SELECTION_CHANGED, EventType.STATUS_MESSAGE_CHANGED);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void processMessage(EventType eventType, Object... params) {
|
||||
if (eventType != EventType.SELECTION_CHANGED)
|
||||
return;
|
||||
boolean enabled = !plugInPort.getSelectedComponents().isEmpty();
|
||||
getContextActionToolbar().setEnabled(enabled);
|
||||
if (eventType == EventType.SELECTION_CHANGED) {
|
||||
boolean enabled = !plugInPort.getSelectedComponents().isEmpty();
|
||||
getContextActionToolbar().setEnabled(enabled);
|
||||
} else if (eventType == EventType.STATUS_MESSAGE_CHANGED) {
|
||||
highlightConnectedAreasUpdateAction.accept(plugInPort.getOperationMode() ==
|
||||
OperationMode.HIGHLIGHT_CONNECTED_AREAS);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,6 +26,9 @@ import java.awt.Cursor;
|
||||
import java.awt.event.MouseAdapter;
|
||||
import java.awt.event.MouseEvent;
|
||||
import java.util.List;
|
||||
import java.util.function.BooleanSupplier;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Function;
|
||||
import javax.swing.BorderFactory;
|
||||
import javax.swing.Icon;
|
||||
import javax.swing.JLabel;
|
||||
@@ -33,6 +36,7 @@ import javax.swing.JPanel;
|
||||
import javax.swing.JSeparator;
|
||||
import org.diylc.appframework.miscutils.ConfigurationManager;
|
||||
import org.diylc.appframework.miscutils.IConfigListener;
|
||||
import org.diylc.common.IPlugInPort;
|
||||
|
||||
public class ConfigToolbar extends JPanel {
|
||||
|
||||
@@ -73,7 +77,33 @@ public class ConfigToolbar extends JPanel {
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
public Consumer<Boolean> add(String title, Icon icon, boolean defaultState, Runnable toggleAction) {
|
||||
final JLabel label = new JLabel();
|
||||
label.setText(defaultState ? CHECK : UNCHECK);
|
||||
label.setIcon(icon);
|
||||
label.setToolTipText(title);
|
||||
label.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
|
||||
label.addMouseListener(new MouseAdapter() {
|
||||
|
||||
@Override
|
||||
public void mouseClicked(MouseEvent e) {
|
||||
toggleAction.run();
|
||||
}
|
||||
});
|
||||
add(label);
|
||||
|
||||
// ConfigurationManager.getInstance().addConfigListener(configKey, new IConfigListener() {
|
||||
//
|
||||
// @Override
|
||||
// public void valueChanged(String key, Object value) {
|
||||
// boolean checked = (boolean) value;
|
||||
// label.setText(checked ? CHECK : UNCHECK);
|
||||
// }
|
||||
// });
|
||||
return (checked) -> label.setText(checked ? CHECK : UNCHECK);
|
||||
}
|
||||
|
||||
public void addToggleLabel(String text, String configKey, String defaultValue, List<ToggleItem> items) {
|
||||
ToggleConfigLabel label = new ToggleConfigLabel(text, configKey, defaultValue, items);
|
||||
add(label);
|
||||
|
||||
@@ -0,0 +1,193 @@
|
||||
/*
|
||||
|
||||
DIY Layout Creator (DIYLC).
|
||||
Copyright (c) 2009-2018 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.swing.gui.editor;
|
||||
|
||||
import org.diylc.common.PropertyWrapper;
|
||||
import org.diylc.core.IDIYComponent;
|
||||
import org.diylc.core.IDynamicPropertySource;
|
||||
import org.diylc.lang.LangUtil;
|
||||
import org.diylc.utils.Constants;
|
||||
|
||||
import javax.swing.*;
|
||||
import javax.swing.event.ListDataEvent;
|
||||
import javax.swing.event.ListDataListener;
|
||||
import javax.swing.event.PopupMenuEvent;
|
||||
import javax.swing.event.PopupMenuListener;
|
||||
import java.awt.*;
|
||||
import java.awt.event.FocusAdapter;
|
||||
import java.awt.event.FocusEvent;
|
||||
import java.awt.event.ItemEvent;
|
||||
import java.awt.event.ItemListener;
|
||||
import java.awt.event.KeyAdapter;
|
||||
import java.awt.event.KeyEvent;
|
||||
import java.awt.event.MouseListener;
|
||||
import java.util.Vector;
|
||||
|
||||
public class DynamicValueEditor extends JComboBox<Object> {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private Color oldBg = getBackground();
|
||||
|
||||
private final PropertyWrapper property;
|
||||
|
||||
public DynamicValueEditor(final PropertyWrapper property) {
|
||||
this.property = property;
|
||||
IDynamicPropertySource dynamicPropertySource = property.getDynamicPropertySource();
|
||||
if (property.getOwnerObject() == null || !(property.getOwnerObject() instanceof IDIYComponent)) {
|
||||
setModel(new DefaultComboBoxModel<Object>(new Object[0]));
|
||||
setEnabled(false);
|
||||
} else {
|
||||
dynamicPropertySource.setComponent((IDIYComponent<?>) property.getOwnerObject());
|
||||
setModel(new DynamicComboBoxModel(dynamicPropertySource));
|
||||
}
|
||||
if (property.isReadOnly())
|
||||
setEnabled(false);
|
||||
|
||||
setRenderer(new DefaultListCellRenderer() {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Override
|
||||
public Component getListCellRendererComponent(JList<?> list, Object value, int index,
|
||||
boolean isSelected, boolean cellHasFocus) {
|
||||
// TODO Auto-generated method stub
|
||||
return super.getListCellRendererComponent(list, LangUtil.translate(dynamicPropertySource.getDisplayValue(value)),
|
||||
index, isSelected, cellHasFocus);
|
||||
}
|
||||
|
||||
});
|
||||
setSelectedItem(property.getValue());
|
||||
|
||||
// Create a shared refresh action
|
||||
final Runnable refreshAction = () -> {
|
||||
if (getModel() instanceof DynamicComboBoxModel model) {
|
||||
model.refreshValues();
|
||||
}
|
||||
};
|
||||
|
||||
addPopupMenuListener(new PopupMenuListener() {
|
||||
@Override
|
||||
public void popupMenuWillBecomeVisible(PopupMenuEvent e) {
|
||||
refreshAction.run();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void popupMenuWillBecomeInvisible(PopupMenuEvent e) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void popupMenuCanceled(PopupMenuEvent e) {
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
addItemListener(new ItemListener() {
|
||||
|
||||
@Override
|
||||
public void itemStateChanged(ItemEvent e) {
|
||||
if (e.getStateChange() == ItemEvent.SELECTED) {
|
||||
property.setChanged(true);
|
||||
setBackground(oldBg);
|
||||
DynamicValueEditor.this.property.setValue(e.getItem());
|
||||
}
|
||||
}
|
||||
});
|
||||
if (!property.isUnique()) {
|
||||
setBackground(Constants.MULTI_VALUE_COLOR);
|
||||
}
|
||||
}
|
||||
|
||||
class DynamicComboBoxModel implements ComboBoxModel<Object> {
|
||||
private final Vector<Object> items;
|
||||
private Object selectedItem;
|
||||
private final Vector<ListDataListener> listeners;
|
||||
private final IDynamicPropertySource dynamicPropertySource;
|
||||
|
||||
public DynamicComboBoxModel(IDynamicPropertySource source) {
|
||||
this.dynamicPropertySource = source;
|
||||
this.items = new Vector<>();
|
||||
this.listeners = new Vector<>();
|
||||
refreshValues();
|
||||
}
|
||||
|
||||
private void refreshValues() {
|
||||
if (dynamicPropertySource != null) {
|
||||
java.util.List<?> newValues = dynamicPropertySource.getAvailableValues();
|
||||
if (!items.equals(newValues)) {
|
||||
Object selected = selectedItem;
|
||||
items.clear();
|
||||
items.addAll(newValues);
|
||||
|
||||
// Single update event
|
||||
ListDataEvent event = new ListDataEvent(this, ListDataEvent.CONTENTS_CHANGED, 0, items.size());
|
||||
for (ListDataListener listener : listeners) {
|
||||
listener.contentsChanged(event);
|
||||
}
|
||||
|
||||
// Restore selection if possible
|
||||
if (selected != null && items.contains(selected)) {
|
||||
selectedItem = selected;
|
||||
} else if (!items.isEmpty()) {
|
||||
selectedItem = items.get(0);
|
||||
} else {
|
||||
selectedItem = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSelectedItem(Object anItem) {
|
||||
if ((selectedItem != null && !selectedItem.equals(anItem)) ||
|
||||
selectedItem == null && anItem != null) {
|
||||
selectedItem = anItem;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getSelectedItem() {
|
||||
return selectedItem;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSize() {
|
||||
return items.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getElementAt(int index) {
|
||||
return items.get(index);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addListDataListener(ListDataListener l) {
|
||||
listeners.add(l);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeListDataListener(ListDataListener l) {
|
||||
listeners.remove(l);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -95,6 +95,10 @@ public class FieldEditorFactory {
|
||||
EnumEditor editor = new EnumEditor(property);
|
||||
return editor;
|
||||
}
|
||||
if (property.getDynamicPropertySource() != null) {
|
||||
DynamicValueEditor editor = new DynamicValueEditor(property);
|
||||
return editor;
|
||||
}
|
||||
if (Byte.class.isAssignableFrom(property.getType()) || byte.class.isAssignableFrom(property.getType())) {
|
||||
ByteEditor editor = new ByteEditor(property);
|
||||
return editor;
|
||||
|
||||
@@ -76,6 +76,13 @@ public class PropertyEditorDialog extends ButtonDialog {
|
||||
this.properties = properties;
|
||||
this.defaultedProperties = new HashSet<PropertyWrapper>();
|
||||
|
||||
// update dynamic property sources
|
||||
// TODO consider better way to do this
|
||||
properties.stream()
|
||||
.map(x -> x.getDynamicPropertySource())
|
||||
.filter(x -> x != null)
|
||||
.forEach(source -> source.setProperties(properties));
|
||||
|
||||
setMinimumSize(new Dimension(240, 40));
|
||||
|
||||
layoutGui();
|
||||
|
||||
+113
@@ -0,0 +1,113 @@
|
||||
/*
|
||||
*
|
||||
* DIY Layout Creator (DIYLC). Copyright (c) 2009-2018 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.swing.plugins.analyze;
|
||||
|
||||
import org.apache.log4j.Logger;
|
||||
import org.diylc.appframework.miscutils.ConfigurationManager;
|
||||
import org.diylc.common.*;
|
||||
import org.diylc.swing.ActionFactory;
|
||||
import org.diylc.swing.IDynamicSubmenuHandler;
|
||||
import org.diylc.swing.ISwingUI;
|
||||
import org.diylc.swing.actions.analyze.HighlightConnectedAreasAction;
|
||||
import org.diylc.swing.loadline.LoadlineEditorFrame;
|
||||
import org.diylc.swing.plugins.file.ProjectDrawingProvider;
|
||||
import org.diylc.swing.plugins.file.TraceMaskDrawingProvider;
|
||||
import org.diylc.utils.IconLoader;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.awt.*;
|
||||
import java.awt.event.KeyEvent;
|
||||
import java.util.*;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Entry point class for Analyze toors.
|
||||
*
|
||||
* @author Branislav Stojkovic
|
||||
*/
|
||||
public class AnalyzeMenuPlugin implements IPlugIn {
|
||||
|
||||
private static final Logger LOG = Logger.getLogger(AnalyzeMenuPlugin.class);
|
||||
|
||||
private static final String ANALYZE_TITLE = "Analyze";
|
||||
private static final String EXPORT_TITLE = "Export";
|
||||
|
||||
private ISwingUI swingUI;
|
||||
private IPlugInPort plugInPort;
|
||||
|
||||
private HighlightConnectedAreasAction highlightConnectedAreasAction;
|
||||
|
||||
public AnalyzeMenuPlugin(ISwingUI swingUI) {
|
||||
super();
|
||||
this.swingUI = swingUI;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void connect(IPlugInPort plugInPort) {
|
||||
this.plugInPort = plugInPort;
|
||||
|
||||
ActionFactory actionFactory = ActionFactory.getInstance();
|
||||
List<Action> menuActions = new ArrayList<>();
|
||||
|
||||
// Add all menu actions to the list
|
||||
menuActions.add(actionFactory.createCheckProximityAction(plugInPort, swingUI));
|
||||
menuActions.add(actionFactory.createBomAction(plugInPort));
|
||||
menuActions.add(actionFactory.createGenerateNetlistAction(plugInPort, swingUI, false));
|
||||
menuActions.add(actionFactory.createGenerateNetlistAction(plugInPort, swingUI, true));
|
||||
highlightConnectedAreasAction =
|
||||
actionFactory.createHighlightConnectedAreasAction(plugInPort);
|
||||
menuActions.add(highlightConnectedAreasAction);
|
||||
|
||||
List<INetlistAnalyzer> summarizers = plugInPort.getNetlistAnalyzers();
|
||||
if (summarizers != null) {
|
||||
for (INetlistAnalyzer summarizer : summarizers) {
|
||||
if (summarizer.getSwitchPreference().contains(NetlistSwitchPreference.WITH)) {
|
||||
menuActions.add(actionFactory.createSummarizeNetlistAction(plugInPort, swingUI, summarizer, true));
|
||||
}
|
||||
if (summarizer.getSwitchPreference().contains(NetlistSwitchPreference.WITHOUT)) {
|
||||
menuActions.add(actionFactory.createSummarizeNetlistAction(plugInPort, swingUI, summarizer, false));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Sort actions by name
|
||||
menuActions.sort((a1, a2) -> {
|
||||
String name1 = (String) a1.getValue(Action.NAME);
|
||||
String name2 = (String) a2.getValue(Action.NAME);
|
||||
return name1.compareTo(name2);
|
||||
});
|
||||
|
||||
// Inject sorted actions
|
||||
for (Action action : menuActions) {
|
||||
swingUI.injectMenuAction(action, ANALYZE_TITLE);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public EnumSet<EventType> getSubscribedEventTypes() {
|
||||
return EnumSet.of(EventType.STATUS_MESSAGE_CHANGED);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void processMessage(EventType eventType, Object... params) {
|
||||
if (eventType == EventType.STATUS_MESSAGE_CHANGED) {
|
||||
highlightConnectedAreasAction.refreshState();;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -51,6 +51,7 @@ import org.diylc.common.IPlugInPort;
|
||||
import org.diylc.common.IBlockProcessor.InvalidBlockException;
|
||||
import org.diylc.swing.plugins.tree.TreePanel;
|
||||
import org.diylc.utils.ScaledBufferedImage;
|
||||
import org.diylc.utils.UIScalingUtil;
|
||||
|
||||
/**
|
||||
* GUI class used to draw onto.
|
||||
@@ -323,7 +324,7 @@ public class CanvasPanel extends JComponent implements Autoscroll {
|
||||
final Graphics2D g2d = (Graphics2D)g;
|
||||
double scaleFactor;
|
||||
if (configManager.readBoolean(IPlugInPort.HIGH_DPI_RENDERING, false)) {
|
||||
scaleFactor = Math.sqrt(g2d.getTransform().getDeterminant());
|
||||
scaleFactor = UIScalingUtil.GUISCALINGFACTOR_CUSTOMGRAPHICS;
|
||||
} else {
|
||||
scaleFactor = 1d;
|
||||
}
|
||||
|
||||
@@ -187,15 +187,6 @@ public class CanvasPlugin implements IPlugIn{
|
||||
}
|
||||
});
|
||||
|
||||
configManager.addConfigListener(IPlugInPort.HIGHLIGHT_CONTINUITY_AREA,
|
||||
new IConfigListener() {
|
||||
|
||||
@Override
|
||||
public void valueChanged(String key, Object value) {
|
||||
canvasPanel.repaint();
|
||||
}
|
||||
});
|
||||
|
||||
getScrollPane().getViewport().setVisible(false);
|
||||
}
|
||||
|
||||
|
||||
@@ -107,13 +107,10 @@ public class ConfigPlugin implements IPlugIn {
|
||||
swingUI.injectMenuAction(
|
||||
ActionFactory.getInstance().createConfigAction(plugInPort, "Hi-Quality Rendering",
|
||||
IPlugInPort.HI_QUALITY_RENDER_KEY, false), CONFIG_MENU);
|
||||
swingUI.injectMenuAction(
|
||||
ActionFactory.getInstance().createConfigAction(plugInPort, "Highlight Connected Areas", IPlugInPort.HIGHLIGHT_CONTINUITY_AREA,
|
||||
false), CONFIG_MENU);
|
||||
|
||||
try {
|
||||
List<Language> languages = LangUtil.getAvailableLanguages();
|
||||
if (languages != null && languages.size() > 0) {
|
||||
if (languages != null && !languages.isEmpty()) {
|
||||
swingUI.injectSubmenu(LANGUAGE_MENU, IconLoader.Earth.getIcon(), CONFIG_MENU);
|
||||
for(Language language : languages) {
|
||||
Icon icon = null;
|
||||
|
||||
@@ -24,13 +24,9 @@ import java.util.EnumSet;
|
||||
import java.util.List;
|
||||
import org.apache.log4j.Logger;
|
||||
import org.diylc.appframework.miscutils.ConfigurationManager;
|
||||
import org.diylc.common.*;
|
||||
import org.diylc.swing.IDynamicSubmenuHandler;
|
||||
|
||||
import org.diylc.common.EventType;
|
||||
import org.diylc.common.INetlistAnalyzer;
|
||||
import org.diylc.common.IPlugIn;
|
||||
import org.diylc.common.IPlugInPort;
|
||||
import org.diylc.common.ITask;
|
||||
import org.diylc.swing.ActionFactory;
|
||||
import org.diylc.swing.ISwingUI;
|
||||
import org.diylc.utils.IconLoader;
|
||||
@@ -48,7 +44,6 @@ public class FileMenuPlugin implements IPlugIn, IDynamicSubmenuHandler {
|
||||
private static final String FILE_TITLE = "File";
|
||||
private static final String TRACE_MASK_TITLE = "Trace Mask";
|
||||
private static final String INTEGRATION_TITLE = "Integration";
|
||||
private static final String ANALYZE_TITLE = "Analyze";
|
||||
private static final String EXPORT_TITLE = "Export";
|
||||
|
||||
private ProjectDrawingProvider drawingProvider;
|
||||
@@ -97,23 +92,6 @@ public class FileMenuPlugin implements IPlugIn, IDynamicSubmenuHandler {
|
||||
Toolkit.getDefaultToolkit().getMenuShortcutKeyMaskEx() | KeyEvent.SHIFT_DOWN_MASK),
|
||||
TRACE_MASK_TITLE);
|
||||
|
||||
swingUI.injectSubmenu(ANALYZE_TITLE, IconLoader.Scientist.getIcon(), FILE_TITLE);
|
||||
swingUI.injectMenuAction(actionFactory.createCheckProximityAction(plugInPort, swingUI),
|
||||
ANALYZE_TITLE);
|
||||
swingUI.injectMenuAction(actionFactory.createBomAction(plugInPort), ANALYZE_TITLE);
|
||||
swingUI.injectMenuAction(actionFactory.createGenerateNetlistAction(plugInPort, swingUI, false),
|
||||
ANALYZE_TITLE);
|
||||
swingUI.injectMenuAction(actionFactory.createGenerateNetlistAction(plugInPort, swingUI, true),
|
||||
ANALYZE_TITLE);
|
||||
|
||||
List<INetlistAnalyzer> summarizers = plugInPort.getNetlistAnalyzers();
|
||||
if (summarizers != null) {
|
||||
for (INetlistAnalyzer summarizer : summarizers)
|
||||
swingUI.injectMenuAction(
|
||||
actionFactory.createSummarizeNetlistAction(plugInPort, swingUI, summarizer),
|
||||
ANALYZE_TITLE);
|
||||
}
|
||||
|
||||
swingUI.injectMenuAction(null, FILE_TITLE);
|
||||
swingUI.injectSubmenu(INTEGRATION_TITLE, IconLoader.Node.getIcon(), FILE_TITLE);
|
||||
swingUI.injectMenuAction(actionFactory.createImportBlocksAction(swingUI, plugInPort),
|
||||
|
||||
@@ -54,6 +54,7 @@ import org.diylc.appframework.miscutils.IConfigListener;
|
||||
import org.diylc.appframework.miscutils.Utils;
|
||||
import org.diylc.appframework.update.UpdateChecker;
|
||||
import org.diylc.appframework.update.Version;
|
||||
import org.diylc.common.*;
|
||||
import org.diylc.swingframework.MemoryBar;
|
||||
import org.diylc.swingframework.miscutils.PercentageListCellRenderer;
|
||||
import org.diylc.swingframework.update.UpdateDialog;
|
||||
@@ -61,12 +62,6 @@ import org.diylc.swingframework.update.UpdateLabel;
|
||||
import net.java.balloontip.BalloonTip;
|
||||
import net.java.balloontip.styles.EdgedBalloonStyle;
|
||||
import org.diylc.announcements.AnnouncementProvider;
|
||||
import org.diylc.common.BadPositionException;
|
||||
import org.diylc.common.ComponentType;
|
||||
import org.diylc.common.EventType;
|
||||
import org.diylc.common.IPlugIn;
|
||||
import org.diylc.common.IPlugInPort;
|
||||
import org.diylc.common.ITask;
|
||||
import org.diylc.core.IDIYComponent;
|
||||
import org.diylc.core.IView;
|
||||
import org.diylc.lang.LangUtil;
|
||||
@@ -192,14 +187,6 @@ public class StatusBar extends JPanel implements IPlugIn {
|
||||
refreshPosition((Boolean)value);
|
||||
}
|
||||
});
|
||||
|
||||
ConfigurationManager.getInstance().addConfigListener(IPlugInPort.HIGHLIGHT_CONTINUITY_AREA, new IConfigListener() {
|
||||
|
||||
@Override
|
||||
public void valueChanged(String key, Object value) {
|
||||
refreshStatusText();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private JComboBox<Double> getZoomBox() {
|
||||
@@ -494,7 +481,7 @@ public class StatusBar extends JPanel implements IPlugIn {
|
||||
refreshStatusText();
|
||||
break;
|
||||
case STATUS_MESSAGE_CHANGED:
|
||||
statusMessage = (String) params[0];
|
||||
statusMessage = params.length > 0 ? (String) params[0] : null;
|
||||
refreshStatusText();
|
||||
break;
|
||||
case MOUSE_MOVED:
|
||||
@@ -569,8 +556,7 @@ public class StatusBar extends JPanel implements IPlugIn {
|
||||
}
|
||||
|
||||
// override any other status with this when in highlight mode, as we cannot do anything else
|
||||
Boolean highlightConnectedAreasMode = ConfigurationManager.getInstance().readBoolean(IPlugInPort.HIGHLIGHT_CONTINUITY_AREA, false);
|
||||
if (highlightConnectedAreasMode)
|
||||
if (plugInPort.getOperationMode() == OperationMode.HIGHLIGHT_CONNECTED_AREAS)
|
||||
statusText = HIGHLIGHT_CONNECTED_TIP;
|
||||
|
||||
final String finalStatus = statusText;
|
||||
|
||||
@@ -71,7 +71,7 @@ public enum IconLoader {
|
||||
SnapToComponents("snap_to_components.png"), SnapToNone("snap_to_none.png"), TraceProximity("trace_proximity.png"),
|
||||
ComponentLarge("component_large.png"), ImportNetlist("import_netlist.png"), SplashIC("splash_ic.png"),
|
||||
ComponentPreferences("component_preferences.png"), ComponentReplace("component_replace.png"), Barcode("barcode.png"),
|
||||
DocumentGerber("document_gerber.png"), DocumentX2("document_x2.png"), Export("export.png");
|
||||
DocumentGerber("document_gerber.png"), DocumentX2("document_x2.png"), Export("export.png"), Multimeter("multimeter.png");
|
||||
|
||||
protected String name;
|
||||
|
||||
|
||||
@@ -0,0 +1,458 @@
|
||||
package org.diylc.utils;
|
||||
|
||||
import org.apache.log4j.Logger;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.awt.*;
|
||||
import java.awt.geom.AffineTransform;
|
||||
|
||||
|
||||
// Please note: This class emerged over time. It gets the job done, but it's horrible. Even the commenting is horrible.
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* TL;DR:
|
||||
* <p>
|
||||
* Call GUIScaling.initialize() at application start on the Swing thread.
|
||||
* <p>
|
||||
* If you set your own Component font sizes or border sizes or window sizes, multiply them by GUIScaling.GUISCALINGFACTOR_COMPONENTSANDFONTS and/or use the
|
||||
* helper methods newDimension() and scaleForComponent(). Works on Java 8 and 9.
|
||||
* <p>
|
||||
* If you do your own custom graphics and want to have control down to the actual pixel, create an instance of GUIScalingCustomGraphics to obtain your
|
||||
* Graphics2D at scaling 1 and your component's true physical width and height (Which Java 9 reports differently!), and scale all your graphics using
|
||||
* GUIScaling.GUISCALINGFACTOR_CUSTOMGRAPHICS and/or use the helper method scaleForCustom(). The helper method scaleForRealComponentSize() can transform your
|
||||
* mouse coordinates to the real physical coordinate, which Java 9 reports differently!
|
||||
* <p>
|
||||
* <p>
|
||||
* <p>
|
||||
* <p>
|
||||
* <p>
|
||||
* <p>
|
||||
* <p>
|
||||
* <p>
|
||||
* <p>
|
||||
* <p>
|
||||
* GUIScaling class v[4, 2022-01-15 07!00 UTC] by dreamspace-president.com
|
||||
* <p>
|
||||
* This Swing class detects the system's display scaling setting, which is important to make your GUI and custom graphics scale properly like the user wants it.
|
||||
* On a 4K display, for example, you'd probably set 200% in your system.
|
||||
* <p>
|
||||
* Not tested with Java less than 8!
|
||||
* <p>
|
||||
* On Java 8 (and with most but not all (e.g. no the default) LooksAndFeels), component sizes (e.g. JButton) and their font sizes will scale automatically, but
|
||||
* if you have a certain border width in mind, or decided for a certain min and default window size or a certain font size, you have to upscale those on a
|
||||
* non-100%-system. With this class, just multiply the values with GUISCALINGFACTOR_COMPONENTSANDFONTS. Done. newDimension() and scaleForComponent() help with
|
||||
* that.
|
||||
* <p>
|
||||
* On Java 9, component sizes and their font sizes DO NOT SCALE from the perspective of the application, but in reality they are scaled: A window set to 800x600
|
||||
* size will really be 1600x1200, but it will still report half this size when asked. A border of 50 pixels will really be 100 pixels. A Graphics2D object
|
||||
* (paint method etc.) will have a scaling of 2! (Not if you just create a BufferedImage object and do createGraphics(), the scale here will be 1.) So, you
|
||||
* don't have to bother with GUI scaling here at all. YOU CAN STILL USE GUISCALINGFACTOR_COMPONENTSANDFONTS, because this class will set it to 1 on Java 9. This
|
||||
* is detected by indeed checking the scaling of a Graphics2D object. So, your Java 8 and 9 component/font code will be exactly the same in regards to scaling.
|
||||
* <p>
|
||||
* CUSTOM GRAPHICS: If you do your own painting and want to insist on true physical pixels (in which case obviously you'd have to scale your fonts with
|
||||
* GUISCALINGFACTOR_CUSTOMGRAPHICS instead of GUISCALINGFACTOR_COMPONENTSANDFONTS), on Java 9 you have to reset the scaling of the Graphics2D object the
|
||||
* paint(Component)() method gives you from 2 to 1, and (also Java 9) you have to adjust the width/height reported by your component. Both is done by making an
|
||||
* instance of GUIScalingCustomGraphics. You can do this blindly on Java 8 and 9, your code will stay the same. And then, apply this class'
|
||||
* GUISCALINGFACTOR_CUSTOMGRAPHICS to scale everything according to system settings. Or, instead of insisting on true physical pixels, you could trust Java 9
|
||||
* and not mess with the initial scaling - but then you'd have to distinguish whether you're dealing with Java 8 or 9, because on 8, you'd still have to scale
|
||||
* your custom graphics. In case you decide for this, use GUISCALINGFACTOR_COMPONENTSANDFONTS for your custom graphics instead of
|
||||
* GUISCALINGFACTOR_CUSTOMGRAPHICS because the former will be ***1*** on Java 9 but will be proper (e.g. 2.0 for a 200% system) on Java 8.
|
||||
* <p>
|
||||
* A weird problem that comes with Java 9: If you use the mouse coordinates as reported by the system (instead of, say, quasi-fix the physical mouse pointer
|
||||
* invisibly at the screen center and make your own pointer based on coordinate differences), you will have HALF THE USUAL RESOLUTION. On Java 8, a 3840x2160
|
||||
* screen will give you according mouse coordinates, but on Java 9, you get half these coordinates (if the system is set to scaling 200%). While
|
||||
* scaleForRealComponentSize() helps correct this, a custom drawn mouse pointer will now step in 2 pixel distances, it can not reach every individual pixel any
|
||||
* longer. I wish they had updated the MouseEvent class accordingly with additional float methods.
|
||||
*/
|
||||
final public class UIScalingUtil { // INITIAL TOUCHING of this class MUST be on Swing thread!
|
||||
|
||||
private static final Logger LOG = Logger.getLogger(UIScalingUtil.class);
|
||||
|
||||
/**
|
||||
* Call this at the start of your application ON THE SWING THREAD. This initializes the class and hence its values.
|
||||
*/
|
||||
public static void initialize() {
|
||||
|
||||
LOG.info("UIScalingUtil initialized");
|
||||
}
|
||||
|
||||
|
||||
public static void setLookAndFeelDefault() {
|
||||
// The last three (Nimbus etc.) DO NOT automatically scale their font sizes with the system's GUI scaling,
|
||||
// so using the font size in those cases to derive the scaling WILL FAIL.
|
||||
// Btw., the JButton font size at 100% Windows 10 system scaling is 11.0 in all cases but the last three.
|
||||
UIScalingUtil.setLookAndFeel("Windows",
|
||||
UIManager.getSystemLookAndFeelClassName(),
|
||||
UIManager.getCrossPlatformLookAndFeelClassName(),
|
||||
"Windows Classic",
|
||||
"Nimbus",
|
||||
"Metal",
|
||||
"CDE/Motif");
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* By calling this, you ALSO initialize the class, so you don't HAVE TO use initialize() in that case (but it really doesn't matter). And you can indeed set
|
||||
* a LookAndFeel of your choice, even though initialization of this class also sets AND TEMPORARILY USES a LookAndFeel.
|
||||
*
|
||||
* @param intendedLAFIs ANYTHING, but ideally a LookAndFeel name or several. The first value that equalsIgnoreCase an installed LookAndFeelInfo.getName()
|
||||
* will be used.
|
||||
*/
|
||||
public static void setLookAndFeel(final String... intendedLAFIs) {
|
||||
|
||||
if (intendedLAFIs != null && intendedLAFIs.length > 0) {
|
||||
final UIManager.LookAndFeelInfo[] installedLAFIs = UIManager.getInstalledLookAndFeels();
|
||||
LAFILOOP:
|
||||
for (String intendedLAFI : intendedLAFIs) {
|
||||
for (final UIManager.LookAndFeelInfo lafi : UIManager.getInstalledLookAndFeels()) {
|
||||
if (lafi.getName().equalsIgnoreCase(intendedLAFI)) {
|
||||
try {
|
||||
UIManager.setLookAndFeel(lafi.getClassName());
|
||||
break LAFILOOP;
|
||||
} catch (Exception e) {
|
||||
continue LAFILOOP;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
throw new IllegalArgumentException("intendedLAFIs is null or empty.");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Convenience method, compatible with Java 8 and 9.
|
||||
*/
|
||||
public static Dimension newDimension(final int w,
|
||||
final int h) {
|
||||
|
||||
return new Dimension(scaleForComponent(w), scaleForComponent(h));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param v E.g. the width of a component, or the size of a border.
|
||||
* @return v scaled by the necessary display scaling factor for components and fonts, compatible with Java 8 and 9.
|
||||
*/
|
||||
public static int scaleForComponent(final double v) {
|
||||
|
||||
return (int) Math.round(v * GUISCALINGFACTOR_COMPONENTSANDFONTS);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param v E.g. the width of a rectangle being drawn in a paint() or paintComponent() override.
|
||||
* @return v scaled by the necessary display scaling factor for custom graphics, compatible with Java 8 and 9.
|
||||
*/
|
||||
public static int scaleForCustom(final double v) {
|
||||
|
||||
return (int) Math.round(v * GUISCALINGFACTOR_CUSTOMGRAPHICS);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* E.g. when the GraphicsContext tells you the screen bounds. Which in Java 8 on 2x 4K desktop will be the full 4K numbers. But, same conditions except Java
|
||||
* 9, will be half that. Even though you still need the full size.
|
||||
* <p>
|
||||
* But this is just an example case. The method was originally made for different cases.
|
||||
*
|
||||
* @param v E.g. the width as reported by a component. (Java 9 on 200% desktop reports e.g. 200, but the physical size is actually 400. This method returns
|
||||
* 400 then.)
|
||||
* @return v scaled so that it represents real physical pixels, compatible with Java 8 and 9.
|
||||
*/
|
||||
public static int scaleForRealComponentSize(final double v) {
|
||||
|
||||
return (int) Math.round(v * GUISCALINGFACTOR_REALCOMPONENTSIZE);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* E.g. when you scaled the mouse location with the partner method, and now you want to use the mouse action result to scale/locate a window - then you need
|
||||
* to UNDO the damage.
|
||||
*/
|
||||
public static int scaleForRealComponentSizeInverted(final double v) {
|
||||
|
||||
return (int) Math.round(v / GUISCALINGFACTOR_REALCOMPONENTSIZE);
|
||||
}
|
||||
|
||||
|
||||
public static Point scaleMouseEventCoordinatesForCustomGraphics(final Point mouseEventPoint) {
|
||||
|
||||
return new Point(scaleForRealComponentSize(mouseEventPoint.x),
|
||||
scaleForRealComponentSize(mouseEventPoint.y));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param font A font instance (Or null. Returns null.) whose size has been derived kinda like this: "new JLabel().getFont().getSize()" So it will look
|
||||
* correct when used in components, no matter the current Java version. ......... WAIT WTF why does that look correct on Java 8
|
||||
* ?!??!?!?!?!?!?!?! Anyway ... when you want to use THAT font in custom drawing, you'll have a bad time once you get on Java 9. Because
|
||||
* components will have SMALLER font sizes than on Java 8 on a 200% desktop because their Graphics objects are scaled. But if you use custom
|
||||
* drawing, you'll use the class GUIScalingCustomGraphics below, which reset the scaling to 1. But then the font is too small. THIS METHOD
|
||||
* RETURNS THE SCALED FONT independent of the Java version.
|
||||
* @return
|
||||
*/
|
||||
public static Font scaleFontForCustom(final Font font) {
|
||||
|
||||
if (font != null) {
|
||||
return font.deriveFont(font.getSize2D() * (float) GUISCALINGFACTOR_REALCOMPONENTSIZE);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param font A font instance (Or null. Returns null.) whose size is just a constant number in your source code, and which you want to use in an already
|
||||
* normalized custom graphics context (meaning you used GUIScaling.GUIScalingCustomGraphics on it.) This font has to be scaled simply by the
|
||||
* derived System scaling factor to look correct. This method does that.
|
||||
* @return
|
||||
*/
|
||||
public static Font scaleMagicConstantFontForCustom(final Font font) {
|
||||
|
||||
if (font != null) {
|
||||
return font.deriveFont(font.getSize2D() * (float) GUISCALINGFACTOR_SYSTEM);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* For Java 9, but can blindly be used in Java 8, too. Ensures that the scaling of a paint(Component)()'s Graphics2D object is 1. Conveniently does the
|
||||
* usual casting, too.
|
||||
* <p>
|
||||
* Also calculates the physical pixel width/height of the component, which is reported differently on Java 9 if the display scaling is not 100%.
|
||||
*/
|
||||
final public static class GUIScalingCustomGraphics {
|
||||
|
||||
|
||||
final public double guiScalingFactor_manualDrawing = GUISCALINGFACTOR_CUSTOMGRAPHICS;
|
||||
final public double guiScalingFactor_fontsThatLookCorrectInComponents = GUISCALINGFACTOR_FONTINCUSTOMGRAPHICSCONTEXT;
|
||||
|
||||
final public Component component; // Just for convenience. You can hand the whole instance down your paint call hierarchy.
|
||||
final public int w; // The physical pixel width of the component.
|
||||
final public int h; // dto. height
|
||||
final public Graphics2D g; // Scale will be 1, even on Java 9 with a non-100% display scaling.
|
||||
|
||||
|
||||
/**
|
||||
* @param component NOT NULL. The component (e.g. JPanel or JFrame) whose paint() method you're overriding.
|
||||
* @param graphics NOT NULL. The Graphics argument given to your paint() method.
|
||||
*/
|
||||
public GUIScalingCustomGraphics(final Component component,
|
||||
final Graphics graphics) {
|
||||
|
||||
this.component = component;
|
||||
w = scaleForRealComponentSize(component.getWidth());
|
||||
h = scaleForRealComponentSize(component.getHeight());
|
||||
|
||||
g = (Graphics2D) graphics;
|
||||
final AffineTransform t = g.getTransform();
|
||||
final double xTrans = t.getTranslateX();
|
||||
final double yTrans = t.getTranslateY();
|
||||
t.setToScale(1, 1);
|
||||
t.translate(xTrans, yTrans);
|
||||
g.setTransform(t);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param graphics NOT NULL. The Graphics argument given to your paint() method.
|
||||
*/
|
||||
public GUIScalingCustomGraphics(final Graphics graphics) {
|
||||
|
||||
component = null;
|
||||
w = 0;
|
||||
h = 0;
|
||||
|
||||
g = (Graphics2D) graphics;
|
||||
final AffineTransform t = g.getTransform();
|
||||
t.setToScale(1, 1);
|
||||
g.setTransform(t);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param x E.g. the width of a rectangle to be drawn.
|
||||
* @return x scaled so that it represents real physical pixels, compatible with Java 8 and 9.
|
||||
*/
|
||||
public int scale(final double x) {
|
||||
|
||||
return (int) Math.round(x * guiScalingFactor_manualDrawing);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Scales the font and then sets it. Assumption: The given font looked correct in components. In Java 9, it would be TOO SMALL in custom graphics via
|
||||
* this class. This method fixes that.
|
||||
*
|
||||
* @param font NULL = null will be returned and G's font will not change.
|
||||
* @return returns the set font for convenience. NULL if your argument was null.
|
||||
*/
|
||||
public Font setFont(final Font font) {
|
||||
|
||||
final Font ret = font == null ? null : font.deriveFont(font.getSize2D() * (float) guiScalingFactor_fontsThatLookCorrectInComponents);
|
||||
g.setFont(ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
|
||||
return "[GUIScalingCustomGraphics" +
|
||||
" guiScalingFactor_manualDrawing=" + guiScalingFactor_manualDrawing +
|
||||
" w=" + w +
|
||||
" h=" + h +
|
||||
" component=" + component +
|
||||
" g=" + g +
|
||||
']';
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Convenience method that saves you unnecessary calls and code clutter. In your live painting method, you'll probably check first if your component has
|
||||
* any pixels, aka if with AND height are at least 1. If they're not, you return before doing anything.
|
||||
* <p>
|
||||
* This method is a shortcut. Call this right at the beginning. If it returns true, you abort.
|
||||
*/
|
||||
public boolean isSizeZero() {
|
||||
|
||||
return w < 1 || h < 1;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* A tiny rectangle will be filled with the current color and width/height of HAIRLINETHICKNESS.
|
||||
*/
|
||||
public static void drawPixel(final Graphics2D g,
|
||||
final int x,
|
||||
final int y) {
|
||||
|
||||
g.fillRect(x - UIScalingUtil.HAIRLINETHICKNESS_HALF,
|
||||
y - UIScalingUtil.HAIRLINETHICKNESS_HALF,
|
||||
UIScalingUtil.HAIRLINETHICKNESS,
|
||||
UIScalingUtil.HAIRLINETHICKNESS);
|
||||
}
|
||||
|
||||
|
||||
final public static double JBUTTONFONTSIZE_ON_100PERCENTSCALE_JAVA8_W10_WITH_LOOKANDFEEL_WINDOWSORSYSTEMORXPLATFORMORWINCLASSIC = 11.0;
|
||||
final public static float JBUTTONFONTSIZE_ON_UNKNOWNSCALE_UNKNOWNJAVA_UNKNOWNOS_WITH_LOOKANDFEEL_WINDOWSORSYSTEMORXPLATFORMORWINCLASSIC;
|
||||
|
||||
final public static double GUISCALINGFACTOR_SYSTEM; // The scaling set in the system.
|
||||
final public static double GUISCALINGFACTOR_COMPONENTSANDFONTS; // The scaling necessary if you set component/font sizes yourself.
|
||||
final public static double GUISCALINGFACTOR_CUSTOMGRAPHICS; // The scaling necessary if you want your custom graphics, too, to be scaled according to System settings.
|
||||
final public static double GUISCALINGFACTOR_REALCOMPONENTSIZE; // The factor by which getWidth() and such return values have to be multiplied, because Java 9 reports them differently.
|
||||
final public static double GUISCALINGFACTOR_FONTINCUSTOMGRAPHICSCONTEXT; // (This is exactly the custom graphics scaling probed by this class.) The factor by which a proper looking font would have to be scaled when used in custom graphics whose scale is 1. (Java 9 pre-scales it to e.g. 2 if Desktop is at 200%, then you reset that with the class above. Then the fonts that look right in the components will be TOO SMALL in the custom graphics. Use this factor / the method above to fix that.)
|
||||
|
||||
|
||||
final public static int HAIRLINETHICKNESS; // A "hairline" would be a line with pixel thickness 1. However, if the GUI is scaled up, that should be a little thicker. This value will have a value of AT LEAST 1. If the GUI scaling of the system is 200%, the value will be 2. If it's 175%, the value will ALSO be 2 due to rounding.
|
||||
|
||||
final public static int HAIRLINETHICKNESS_HALF;
|
||||
final public static double HAIRLINETHICKNESS_HALF_DOUBLE;
|
||||
|
||||
|
||||
static {
|
||||
|
||||
if (!SwingUtilities.isEventDispatchThread()) { // This also makes sure an obfuscator doesn't remove this method and its calls.
|
||||
throw new IllegalStateException("Must be initialized on Swing thread!");
|
||||
}
|
||||
|
||||
LOG.debug("Initializing GUI scaling ...");
|
||||
|
||||
UIScalingUtil.setLookAndFeelDefault();
|
||||
|
||||
JBUTTONFONTSIZE_ON_UNKNOWNSCALE_UNKNOWNJAVA_UNKNOWNOS_WITH_LOOKANDFEEL_WINDOWSORSYSTEMORXPLATFORMORWINCLASSIC =
|
||||
new JButton().getFont().getSize2D(); // 21.0 on 200% desktop on Java 8 // 11.0 on 100% desktop on Java 8
|
||||
|
||||
final Integer[] paintScalingInPercent = new Integer[1];
|
||||
|
||||
final JDialog bruteForceJava9ScalingCheck = new JDialog((Frame) null, "", true) {
|
||||
|
||||
{
|
||||
// setLocation(-1000, -1000); // Outamysight!
|
||||
setLocation(100,
|
||||
100); // else you might have compatibility problems (see stackoverflow where I posted this class)
|
||||
|
||||
final Runnable fallbackInCaseOlderJavaVersionDoesNotEndUpClosingThisWindow = () -> {
|
||||
try {
|
||||
Thread.sleep(500);
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
SwingUtilities.invokeLater(() -> {
|
||||
paintScalingInPercent[0] = 100;
|
||||
dispose();
|
||||
});
|
||||
};
|
||||
final Thread t = new Thread(fallbackInCaseOlderJavaVersionDoesNotEndUpClosingThisWindow);
|
||||
t.setDaemon(true);
|
||||
t.setName("GUI scaling detector fallback thread");
|
||||
t.start();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void paint(final Graphics graphics) {
|
||||
|
||||
final Graphics2D g = (Graphics2D) graphics;
|
||||
final AffineTransform originalTransform = g.getTransform();
|
||||
paintScalingInPercent[0] = (int) Math.round(originalTransform.getScaleX() * 100);
|
||||
dispose();
|
||||
}
|
||||
};
|
||||
|
||||
bruteForceJava9ScalingCheck.setVisible(true); // This call blocks until dispose() is reached.
|
||||
|
||||
if (paintScalingInPercent[0] == null) {
|
||||
|
||||
throw new Error("Unexpected behavior: Modal dialog did not block!");
|
||||
|
||||
} else if (paintScalingInPercent[0] != 100) {
|
||||
|
||||
// Must be Java 9 (or newer?).
|
||||
|
||||
GUISCALINGFACTOR_SYSTEM = paintScalingInPercent[0] * 0.01;
|
||||
GUISCALINGFACTOR_COMPONENTSANDFONTS = 1; // Java 9 does everything. The developer's considerations are made unnecessary/harmless by this "1".
|
||||
GUISCALINGFACTOR_CUSTOMGRAPHICS = GUISCALINGFACTOR_SYSTEM;
|
||||
GUISCALINGFACTOR_FONTINCUSTOMGRAPHICSCONTEXT = GUISCALINGFACTOR_SYSTEM;
|
||||
|
||||
} else {
|
||||
|
||||
// Either Java 8 (or older?) or scaling IS just at the normal 1 (100).
|
||||
|
||||
final double factorPreliminary = JBUTTONFONTSIZE_ON_UNKNOWNSCALE_UNKNOWNJAVA_UNKNOWNOS_WITH_LOOKANDFEEL_WINDOWSORSYSTEMORXPLATFORMORWINCLASSIC / JBUTTONFONTSIZE_ON_100PERCENTSCALE_JAVA8_W10_WITH_LOOKANDFEEL_WINDOWSORSYSTEMORXPLATFORMORWINCLASSIC;
|
||||
// System.err.println("FIX MEEEEEEEEEEEEEEEEEEEEEEEEEEEEE!");
|
||||
// final double factorPreliminary = 1;
|
||||
|
||||
// If we just divide the two, we get 1.454545... on a 150% desktop, because the font sizes
|
||||
// chosen by Java are integer values, so we experience a rounding error.
|
||||
// The crappy but probably in most cases nicely working solution is: We round the result to .25 steps!
|
||||
|
||||
GUISCALINGFACTOR_SYSTEM = Math.round(factorPreliminary * 4) / 4d;
|
||||
GUISCALINGFACTOR_COMPONENTSANDFONTS = GUISCALINGFACTOR_SYSTEM;
|
||||
GUISCALINGFACTOR_CUSTOMGRAPHICS = GUISCALINGFACTOR_SYSTEM;
|
||||
GUISCALINGFACTOR_FONTINCUSTOMGRAPHICSCONTEXT = 1; // No font scaling, the fonts used will look correct in custom scaling without extra treatment.
|
||||
}
|
||||
|
||||
GUISCALINGFACTOR_REALCOMPONENTSIZE = GUISCALINGFACTOR_CUSTOMGRAPHICS / GUISCALINGFACTOR_COMPONENTSANDFONTS;
|
||||
|
||||
|
||||
HAIRLINETHICKNESS = (int) Math.max(1, Math.round(GUISCALINGFACTOR_CUSTOMGRAPHICS));
|
||||
HAIRLINETHICKNESS_HALF_DOUBLE = HAIRLINETHICKNESS * 0.5;
|
||||
HAIRLINETHICKNESS_HALF = (int) Math.round(HAIRLINETHICKNESS_HALF_DOUBLE);
|
||||
|
||||
// System.err.println("GUISCALINGFACTOR_SYSTEM = " + GUISCALINGFACTOR_SYSTEM);
|
||||
// System.err.println("GUISCALINGFACTOR_COMPONENTSANDFONTS = " + GUISCALINGFACTOR_COMPONENTSANDFONTS);
|
||||
// System.err.println("GUISCALINGFACTOR_CUSTOMGRAPHICS = " + GUISCALINGFACTOR_CUSTOMGRAPHICS);
|
||||
// System.err.println("GUISCALINGFACTOR_REALCOMPONENTSIZE = " + GUISCALINGFACTOR_REALCOMPONENTSIZE);
|
||||
|
||||
LOG.debug("... done.");
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 864 B |
@@ -1,65 +0,0 @@
|
||||
<org.diylc.core.Project>
|
||||
<title>New Project</title>
|
||||
<author>Branislav Stojkovic</author>
|
||||
<width>
|
||||
<value>29.0</value>
|
||||
<unit class="org.diylc.core.measures.SizeUnit">cm</unit>
|
||||
</width>
|
||||
<height>
|
||||
<value>21.0</value>
|
||||
<unit class="org.diylc.core.measures.SizeUnit">cm</unit>
|
||||
</height>
|
||||
<gridSpacing>
|
||||
<value>0.1</value>
|
||||
<unit class="org.diylc.core.measures.SizeUnit">in</unit>
|
||||
</gridSpacing>
|
||||
<components>
|
||||
<org.diylc.components.boards.EyeletBoard>
|
||||
<name>Board1</name>
|
||||
<alpha>127</alpha>
|
||||
<value></value>
|
||||
<controlPoints>
|
||||
<java.awt.Point>
|
||||
<x>555</x>
|
||||
<y>450</y>
|
||||
</java.awt.Point>
|
||||
<java.awt.Point>
|
||||
<x>1140</x>
|
||||
<y>795</y>
|
||||
</java.awt.Point>
|
||||
</controlPoints>
|
||||
<firstPoint>
|
||||
<x>555</x>
|
||||
<y>450</y>
|
||||
</firstPoint>
|
||||
<secondPoint>
|
||||
<x>1140</x>
|
||||
<y>795</y>
|
||||
</secondPoint>
|
||||
<boardColor>
|
||||
<red>248</red>
|
||||
<green>235</green>
|
||||
<blue>179</blue>
|
||||
<alpha>255</alpha>
|
||||
</boardColor>
|
||||
<borderColor>
|
||||
<red>173</red>
|
||||
<green>164</green>
|
||||
<blue>125</blue>
|
||||
<alpha>255</alpha>
|
||||
</borderColor>
|
||||
<spacing>
|
||||
<value>0.3</value>
|
||||
<unit class="org.diylc.core.measures.SizeUnit">in</unit>
|
||||
</spacing>
|
||||
<eyeletColor>
|
||||
<red>195</red>
|
||||
<green>228</green>
|
||||
<blue>237</blue>
|
||||
<alpha>255</alpha>
|
||||
</eyeletColor>
|
||||
</org.diylc.components.boards.EyeletBoard>
|
||||
</components>
|
||||
<groups/>
|
||||
<lockedLayers/>
|
||||
</org.diylc.core.Project>
|
||||
@@ -1,65 +0,0 @@
|
||||
<org.diylc.core.Project>
|
||||
<title>New Project</title>
|
||||
<author>Branislav Stojkovic</author>
|
||||
<width>
|
||||
<value>29.0</value>
|
||||
<unit class="org.diylc.core.measures.SizeUnit">cm</unit>
|
||||
</width>
|
||||
<height>
|
||||
<value>21.0</value>
|
||||
<unit class="org.diylc.core.measures.SizeUnit">cm</unit>
|
||||
</height>
|
||||
<gridSpacing>
|
||||
<value>0.1</value>
|
||||
<unit class="org.diylc.core.measures.SizeUnit">in</unit>
|
||||
</gridSpacing>
|
||||
<components>
|
||||
<org.diylc.components.boards.PerfBoard>
|
||||
<name>Board1</name>
|
||||
<alpha>127</alpha>
|
||||
<value></value>
|
||||
<controlPoints>
|
||||
<java.awt.Point>
|
||||
<x>585</x>
|
||||
<y>450</y>
|
||||
</java.awt.Point>
|
||||
<java.awt.Point>
|
||||
<x>1050</x>
|
||||
<y>690</y>
|
||||
</java.awt.Point>
|
||||
</controlPoints>
|
||||
<firstPoint>
|
||||
<x>585</x>
|
||||
<y>450</y>
|
||||
</firstPoint>
|
||||
<secondPoint>
|
||||
<x>1050</x>
|
||||
<y>690</y>
|
||||
</secondPoint>
|
||||
<boardColor>
|
||||
<red>248</red>
|
||||
<green>235</green>
|
||||
<blue>179</blue>
|
||||
<alpha>255</alpha>
|
||||
</boardColor>
|
||||
<borderColor>
|
||||
<red>173</red>
|
||||
<green>164</green>
|
||||
<blue>125</blue>
|
||||
<alpha>255</alpha>
|
||||
</borderColor>
|
||||
<spacing>
|
||||
<value>0.1</value>
|
||||
<unit class="org.diylc.core.measures.SizeUnit">in</unit>
|
||||
</spacing>
|
||||
<padColor>
|
||||
<red>218</red>
|
||||
<green>138</green>
|
||||
<blue>103</blue>
|
||||
<alpha>255</alpha>
|
||||
</padColor>
|
||||
</org.diylc.components.boards.PerfBoard>
|
||||
</components>
|
||||
<groups/>
|
||||
<lockedLayers/>
|
||||
</org.diylc.core.Project>
|
||||
@@ -1,27 +0,0 @@
|
||||
<org.diylc.core.Theme>
|
||||
<name>Blueprint</name>
|
||||
<bgColor>
|
||||
<red>3</red>
|
||||
<green>122</green>
|
||||
<blue>198</blue>
|
||||
<alpha>255</alpha>
|
||||
</bgColor>
|
||||
<gridColor>
|
||||
<red>29</red>
|
||||
<green>140</green>
|
||||
<blue>193</blue>
|
||||
<alpha>255</alpha>
|
||||
</gridColor>
|
||||
<dotColor>
|
||||
<red>142</red>
|
||||
<green>219</green>
|
||||
<blue>255</blue>
|
||||
<alpha>255</alpha>
|
||||
</dotColor>
|
||||
<outlineColor>
|
||||
<red>255</red>
|
||||
<green>255</green>
|
||||
<blue>255</blue>
|
||||
<alpha>255</alpha>
|
||||
</outlineColor>
|
||||
</org.diylc.core.Theme>
|
||||
@@ -1,27 +0,0 @@
|
||||
<org.diylc.core.Theme>
|
||||
<name>Dark</name>
|
||||
<bgColor>
|
||||
<red>26</red>
|
||||
<green>29</green>
|
||||
<blue>33</blue>
|
||||
<alpha>255</alpha>
|
||||
</bgColor>
|
||||
<gridColor>
|
||||
<red>53</red>
|
||||
<green>53</green>
|
||||
<blue>59</blue>
|
||||
<alpha>255</alpha>
|
||||
</gridColor>
|
||||
<dotColor>
|
||||
<red>60</red>
|
||||
<green>60</green>
|
||||
<blue>60</blue>
|
||||
<alpha>255</alpha>
|
||||
</dotColor>
|
||||
<outlineColor>
|
||||
<red>255</red>
|
||||
<green>255</green>
|
||||
<blue>255</blue>
|
||||
<alpha>255</alpha>
|
||||
</outlineColor>
|
||||
</org.diylc.core.Theme>
|
||||
@@ -1,27 +0,0 @@
|
||||
<org.diylc.core.Theme>
|
||||
<name>Light</name>
|
||||
<bgColor>
|
||||
<red>255</red>
|
||||
<green>255</green>
|
||||
<blue>255</blue>
|
||||
<alpha>255</alpha>
|
||||
</bgColor>
|
||||
<gridColor>
|
||||
<red>240</red>
|
||||
<green>240</green>
|
||||
<blue>240</blue>
|
||||
<alpha>240</alpha>
|
||||
</gridColor>
|
||||
<dotColor>
|
||||
<red>200</red>
|
||||
<green>200</green>
|
||||
<blue>200</blue>
|
||||
<alpha>240</alpha>
|
||||
</dotColor>
|
||||
<outlineColor>
|
||||
<red>0</red>
|
||||
<green>0</green>
|
||||
<blue>0</blue>
|
||||
<alpha>255</alpha>
|
||||
</outlineColor>
|
||||
</org.diylc.core.Theme>
|
||||
Binary file not shown.
+1
-1
@@ -6,7 +6,7 @@
|
||||
|
||||
<groupId>org.diylc</groupId>
|
||||
<artifactId>diylc-parent</artifactId>
|
||||
<version>5.1.0</version>
|
||||
<version>5.2.0</version>
|
||||
<packaging>pom</packaging>
|
||||
|
||||
<name>DIY Layout Creator</name>
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
Executable
+152
@@ -0,0 +1,152 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Script to parse DIYLC update_archive.xml and update.xml files to generate
|
||||
SQL INSERT statements for the diylc_knowledge_base table with JSON content.
|
||||
"""
|
||||
import xml.etree.ElementTree as ET
|
||||
import json
|
||||
import os
|
||||
|
||||
# Paths to the XML files
|
||||
ARCHIVE_XML_PATH = "../diylc/diylc-core/src/main/resources/update_archive.xml"
|
||||
CURRENT_XML_PATH = "../diylc/diylc-core/src/main/resources/update.xml"
|
||||
OUTPUT_SQL_FILE = "diylc_version_history.sql"
|
||||
|
||||
def parse_xml_file(file_path):
|
||||
"""Parse the XML file and extract version information."""
|
||||
try:
|
||||
tree = ET.parse(file_path)
|
||||
root = tree.getroot()
|
||||
|
||||
# The root is <java.util.Arrays_-ArrayList>
|
||||
# Inside it there is an <a> element containing <org.diylc.appframework.update.Version> elements
|
||||
versions = []
|
||||
|
||||
for version_elem in root.find('a').findall('org.diylc.appframework.update.Version'):
|
||||
version_info = {}
|
||||
|
||||
# Extract version number
|
||||
version_number = version_elem.find('versionNumber')
|
||||
major = version_number.find('major').text
|
||||
minor = version_number.find('minor').text
|
||||
build = version_number.find('build').text
|
||||
version_info['version'] = f"{major}.{minor}.{build}"
|
||||
|
||||
# Extract release date if available
|
||||
release_date_elem = version_elem.find('releaseDate')
|
||||
if release_date_elem is not None and release_date_elem.text:
|
||||
version_info['releaseDate'] = release_date_elem.text
|
||||
|
||||
# Extract name if available (might be empty)
|
||||
name_elem = version_elem.find('name')
|
||||
if name_elem is not None and name_elem.text:
|
||||
version_info['name'] = name_elem.text
|
||||
|
||||
# Extract changes
|
||||
changes = []
|
||||
changes_elem = version_elem.find('changes')
|
||||
if changes_elem is not None:
|
||||
for change_elem in changes_elem.findall('org.diylc.appframework.update.Change'):
|
||||
change_type_elem = change_elem.find('changeType')
|
||||
description_elem = change_elem.find('description')
|
||||
|
||||
if change_type_elem is not None and description_elem is not None:
|
||||
# Replace underscores with spaces in change type
|
||||
change_type = change_type_elem.text.replace('_', ' ')
|
||||
description = description_elem.text
|
||||
|
||||
if description: # Skip empty descriptions
|
||||
changes.append({
|
||||
'type': change_type,
|
||||
'description': description
|
||||
})
|
||||
|
||||
# Extract URL if available
|
||||
url_elem = version_elem.find('url')
|
||||
if url_elem is not None and url_elem.text:
|
||||
version_info['url'] = url_elem.text.strip()
|
||||
|
||||
version_info['changes'] = changes
|
||||
versions.append(version_info)
|
||||
|
||||
return versions
|
||||
except Exception as e:
|
||||
print(f"Error parsing XML file {file_path}: {e}")
|
||||
return []
|
||||
|
||||
def generate_sql_insert(version_info):
|
||||
"""Generate SQL INSERT statement for a single version with JSON content."""
|
||||
version = version_info['version']
|
||||
|
||||
# Create a JSON object with version info and changes
|
||||
json_data = {
|
||||
'version': version,
|
||||
'changes': version_info['changes']
|
||||
}
|
||||
|
||||
# Add optional fields if available (excluding URL)
|
||||
for field in ['releaseDate', 'name']:
|
||||
if field in version_info:
|
||||
json_data[field] = version_info[field]
|
||||
|
||||
# Convert to JSON string and escape single quotes for SQL
|
||||
json_string = json.dumps(json_data, indent=2).replace("'", "''")
|
||||
|
||||
sql_insert = f"""-- Version {version}
|
||||
DELETE FROM diylc_knowledge_base WHERE section = 'DIYLC Version {version}' and category = 'History';
|
||||
INSERT INTO diylc_knowledge_base (category, section, content)
|
||||
VALUES ('History', 'DIYLC Version {version}',
|
||||
'{json_string}');
|
||||
"""
|
||||
return sql_insert
|
||||
|
||||
def generate_sql_file(versions, output_file):
|
||||
"""Generate SQL file with INSERT statements for all versions."""
|
||||
with open(output_file, 'w') as f:
|
||||
f.write("-- SQL script to insert DIYLC version history into diylc_knowledge_base table\n")
|
||||
f.write("-- Generated from update_archive.xml and update.xml data\n")
|
||||
f.write("-- Content is stored as JSON for easier parsing and flexibility\n\n")
|
||||
|
||||
# Sort versions by version number
|
||||
versions.sort(key=lambda v: [int(x) for x in v['version'].split('.')])
|
||||
|
||||
# Remove duplicates (prefer entries from update.xml over update_archive.xml)
|
||||
unique_versions = {}
|
||||
for version_info in versions:
|
||||
unique_versions[version_info['version']] = version_info
|
||||
|
||||
for version_info in unique_versions.values():
|
||||
sql_insert = generate_sql_insert(version_info)
|
||||
f.write(sql_insert)
|
||||
f.write("\n")
|
||||
|
||||
if __name__ == "__main__":
|
||||
# Check if files exist
|
||||
versions = []
|
||||
|
||||
# Try to parse the archive file
|
||||
if os.path.exists(ARCHIVE_XML_PATH):
|
||||
print(f"Parsing archive XML file: {ARCHIVE_XML_PATH}")
|
||||
archive_versions = parse_xml_file(ARCHIVE_XML_PATH)
|
||||
print(f"Found {len(archive_versions)} versions in archive file.")
|
||||
versions.extend(archive_versions)
|
||||
else:
|
||||
print(f"Warning: Archive XML file not found at {ARCHIVE_XML_PATH}")
|
||||
|
||||
# Try to parse the current file
|
||||
if os.path.exists(CURRENT_XML_PATH):
|
||||
print(f"Parsing current XML file: {CURRENT_XML_PATH}")
|
||||
current_versions = parse_xml_file(CURRENT_XML_PATH)
|
||||
print(f"Found {len(current_versions)} versions in current file.")
|
||||
versions.extend(current_versions)
|
||||
else:
|
||||
print(f"Warning: Current XML file not found at {CURRENT_XML_PATH}")
|
||||
|
||||
if not versions:
|
||||
print("Error: No versions found in either file.")
|
||||
exit(1)
|
||||
|
||||
print(f"Total unique versions found: {len(set(v['version'] for v in versions))}")
|
||||
generate_sql_file(versions, OUTPUT_SQL_FILE)
|
||||
print(f"SQL file generated: {OUTPUT_SQL_FILE}")
|
||||
print("Done!")
|
||||
@@ -0,0 +1,222 @@
|
||||
DELETE FROM diylc_knowledge_base WHERE section = 'User Manual - System requirements';
|
||||
INSERT INTO diylc_knowledge_base(category, section, content) VALUES ('User Manual', 'User Manual - System requirements','* [Java JRE/JDK](http://www.oracle.com/technetwork/java/javase/downloads/index.html) 1.8 or newer
|
||||
* 1GB free RAM memory is recommended, 2GB or more is ideal
|
||||
* **Mac OSX** users must allow 3rd party apps before installing DIYLC. [This document](https://support.apple.com/en-us/HT202491) covers how to do it.');
|
||||
|
||||
DELETE FROM diylc_knowledge_base WHERE section = 'User Manual - Installing the app - Windows';
|
||||
INSERT INTO diylc_knowledge_base(category, section, content) VALUES ('User Manual', 'User Manual - Installing the app - Windows','There are several ways to run DIYLC on Windows:
|
||||
**Windows 64bit** – Download the Windows installer build (ending with *-win64.exe*) and follow the wizard to install it. Java JRE is not required as it comes bundled with the installation.
|
||||
– Download the Windows ZIP build (ending with *-win64.zip*) and unpack to the desired folder. Java JRE is not required as it comes bundled with the installation.
|
||||
**Windows 32bit** – Download the universal ZIP build (ending with *-universal.zip*) and unpack to the desired folder. Java JRE 17 or newer is required because universal builds come without a bundled JRE.');
|
||||
|
||||
DELETE FROM diylc_knowledge_base WHERE section = 'User Manual - Installing the app - Mac OS';
|
||||
INSERT INTO diylc_knowledge_base(category, section, content) VALUES ('User Manual', 'User Manual - Installing the app - Mac OS','Download the OSX build matching your Mac\'s architecture (ending with *-osx-arm.zip* for Apple Silicon M1/M2/M3 processors or *-osx-x86.zip* for older Intel-based Macs) and unpack it into the Applications folder. Java JRE is not required as it comes bundled with the app. There are two ways to get DIYLC to run on a Mac:
|
||||
– Download a signed and notarized version from DIYLC Patreon (no extra steps needed). Visit DIYLC\'s Patreon to become a member.
|
||||
– Download the unsigned build and allow DIYLC to run after OSX Gatekeeper blocks it initially as unsafe (details below).');
|
||||
|
||||
DELETE FROM diylc_knowledge_base WHERE section = 'User Manual - Installing the app - Mac OS - Installing on OSX Sierra and El Captain';
|
||||
INSERT INTO diylc_knowledge_base(category, section, content) VALUES ('User Manual', 'User Manual - Installing the app - Mac OS - Installing on OSX Sierra and El Captain','Since version 4.0.0, DIYLC runs on Java 8 which supports newer Mac machines, but can cause issues on older Sierra and El Capitan Macs. If the OSX application bundle *diylc-4.X.Y-osx.zip* fails on Sierra or El Capitan, you can still run the multi-platform version:
|
||||
1. Download the latest *diylc-4.X.Y.zip* (without "osx" in the name) and extract it to a folder.
|
||||
2. Open the Terminal, navigate to the extracted DIYLC directory, and change the permissions of *run.sh*:
|
||||
`sudo chmod 755 run.sh`
|
||||
3. Run the app using: `./run.sh`
|
||||
If DIYLC still fails to start, try double-clicking on **diylc.jar** to launch the app.');
|
||||
|
||||
DELETE FROM diylc_knowledge_base WHERE section = 'User Manual - Installing the app - Linux';
|
||||
INSERT INTO diylc_knowledge_base(category, section, content) VALUES ('User Manual', 'User Manual - Installing the app - Linux','DIYLC for Linux is packaged as an AppImage (since version 5.0.0) and includes a bundled JRE 17. If you encounter issues with the AppImage build, you can always use the universal build.');
|
||||
|
||||
DELETE FROM diylc_knowledge_base WHERE section = 'User Manual - Installing the app - Universal';
|
||||
INSERT INTO diylc_knowledge_base(category, section, content) VALUES ('User Manual', 'User Manual - Installing the app - Universal','The universal build should work on any Linux/Unix machine as well as MacOS, provided Java JRE is installed. To run DIYLC universal build:
|
||||
1. Extract the entire *diylc-[version]-universal.zip* file into a separate directory.
|
||||
2. Open the Terminal.
|
||||
3. Change directory (`cd`) into the extracted DIYLC folder.
|
||||
4. Make *run.sh* executable: `chmod +x run.sh`.
|
||||
5. Launch DIYLC by running: `./run.sh` (or `sh run.sh`).');
|
||||
|
||||
DELETE FROM diylc_knowledge_base WHERE section = 'User Manual - User interface';
|
||||
INSERT INTO diylc_knowledge_base(category, section, content) VALUES ('User Manual', 'User Manual - User interface','The DIYLC user interface is divided into four main sections:
|
||||
1. **Canvas** – A WYSIWYG editor area for creating the project layout.
|
||||
2. **Component tree (toolbar)** – Lists all available components, organized in categories. You can select a component here to add to the project.
|
||||
3. **Main menu** – Provides file operations (save, load, export), clipboard actions, etc.
|
||||
4. **Status bar** – Displays context-specific information (selected component details, zoom level, memory usage, update notifications).');
|
||||
|
||||
DELETE FROM diylc_knowledge_base WHERE section = 'User Manual - Mouse operation';
|
||||
INSERT INTO diylc_knowledge_base(category, section, content) VALUES ('User Manual', 'User Manual - Mouse operation','**Left mouse button**:
|
||||
* Single-click a component on the canvas to select it.
|
||||
* **Ctrl + Click** to add a component to an existing selection on the canvas.
|
||||
* Single-click a component type in the Toolbox/Toolbar to select it (for placement).
|
||||
* Drag a component type from the Toolbox onto the canvas to create that component.
|
||||
* Click and drag on the canvas to draw a selection rectangle (multi-select).
|
||||
* Double-click a component on the canvas to edit its properties.
|
||||
|
||||
**Right mouse button**:
|
||||
* Single-click empty canvas space for the project context menu.
|
||||
* Single-click a component for the component context menu.
|
||||
|
||||
**Middle mouse button**:
|
||||
* Click and drag on the canvas to pan (move the visible area).');
|
||||
|
||||
DELETE FROM diylc_knowledge_base WHERE section = 'User Manual - Configuring the application';
|
||||
INSERT INTO diylc_knowledge_base(category, section, content) VALUES ('User Manual', 'User Manual - Configuring the application','DIYLC settings can be adjusted via the **Config** menu. Key options include:
|
||||
* **Anti-Aliasing** – Smooths graphics and text (better visuals, slightly slower). Disable if experiencing performance issues.
|
||||
* **Auto-Create Pads** – When enabled, automatically adds solder pads when a component is placed (for applicable layouts).
|
||||
* **Auto-Edit Mode** – When enabled, the component edit dialog pops up each time a new component is added (like DIYLC 1.x behavior).
|
||||
* **Continuous Creation** – When enabled, after placing a component, the tool remains active for repeated placements of that same component type (speeds up multiple inserts).
|
||||
* **Enable Cache Boost** – Improves rendering speed at the cost of higher memory usage (generally recommended unless low on memory).
|
||||
* **Export Grid** – If enabled, grid lines are included in exported images, PDFs, or prints.
|
||||
* **Extra Working Area** – Adds extra space around project boundaries for auxiliary components (excluded from final output).
|
||||
* **Hi-Quality Rendering** – Slightly improves rendered image quality (minor performance tradeoff).
|
||||
* **Highlight Connected Areas** – Switches project to a read-only debug mode (cursor becomes crosshairs). Clicking a component highlights all directly connected conductive parts (wires, traces, copper, etc.) in green. (To exit, disable this mode in the Config menu.)
|
||||
* **Language** – Changes the UI language.
|
||||
* **Mouse Wheel Zoom** – When enabled, zoom is controlled by the mouse wheel (instead of scrolling the canvas).
|
||||
* **Outline Mode** – When enabled, components are drawn as outlines only (no fill or decoration).
|
||||
* **Renumber on Paste** – When enabled, pasted components get new unique names instead of retaining duplicates.
|
||||
* **Show Rulers** – Toggles display of rulers along the canvas edges.
|
||||
* **Show Grid** – Toggles visibility of grid lines on the canvas.
|
||||
* **Snap to** – Controls snapping behavior of control points: to grid, to other components, or no snap. (Tip: Hold **Ctrl + Shift** while dragging to temporarily disable grid snap, allowing free movement.)
|
||||
* **Sticky Points** – If enabled, components snap/stick to each other when moved. (Tip: Hold **Ctrl** while dragging to temporarily toggle sticky behavior.)
|
||||
* **Theme** – Select a theme (background and grid colors). Themes are XML files in the DIYLC *themes* directory; you can create custom themes by copying and editing an existing theme file.');
|
||||
|
||||
DELETE FROM diylc_knowledge_base WHERE section = 'User Manual - Adding components to the project';
|
||||
INSERT INTO diylc_knowledge_base(category, section, content) VALUES ('User Manual', 'User Manual - Adding components to the project','To add an existing component from the library to your project:
|
||||
1. Find the component in the component tree (components are grouped in category folders, e.g., Passive, ICs, Guitar). Use the search box at the top of the component tree to filter the list if needed.
|
||||
2. Click the desired component type in the tree. (The status bar will update to reflect the active component type.)
|
||||
3. Click on the canvas where you want to place the component. Some components (e.g., solder pads, trace cuts) place with a single click; others (e.g., resistors, wires) require two clicks to set start and end points. Follow the instructions in the status bar during component placement. The component will appear semi-transparent until placement is complete.
|
||||
|
||||
**Tip**: Press the tilde (~) key to repeat the last added component type at the current mouse location.');
|
||||
|
||||
DELETE FROM diylc_knowledge_base WHERE section = 'User Manual - Moving components around';
|
||||
INSERT INTO diylc_knowledge_base(category, section, content) VALUES ('User Manual', 'User Manual - Moving components around','There are multiple ways to move components on the canvas:
|
||||
**Method 1:** Click and drag the selected component(s) to the desired location. When hovering over a component, the cursor changes to a hand icon and the status bar shows the name of the component that will be moved.
|
||||
|
||||
**Method 2:** Use the keyboard: select component(s), then press arrow keys while holding **Ctrl** to nudge them.
|
||||
|
||||
**Notes for Methods 1 & 2:**
|
||||
– If multiple components are selected, all will move together.
|
||||
– If a moved component has other components stuck to its control points, those stuck components will move or stretch accordingly. (The status bar lists components affected by the move.) Hold **Ctrl** during the drag or nudge to temporarily unstick components, moving only the selected items.
|
||||
|
||||
**Method 3:** Use the **Nudge** function from the *Transform* menu (shortcut **Ctrl + Q**). This opens a dialog where you can specify an exact X and Y offset and whether to include stuck components in the move.');
|
||||
|
||||
DELETE FROM diylc_knowledge_base WHERE section = 'User Manual - Control points';
|
||||
INSERT INTO diylc_knowledge_base(category, section, content) VALUES ('User Manual', 'User Manual - Control points','Many components have one or more **control points**, which determine their position and allow connections to other components. For components like resistors or wires, each control point can often be repositioned individually when the component is selected.
|
||||
|
||||
**Key points:**
|
||||
* The status bar will list all components that will be affected when dragging a control point (especially if components are stuck together at that point).
|
||||
* Control points become draggable (turn green) when the component is selected. You can only drag a control point when it is highlighted (green).');
|
||||
|
||||
DELETE FROM diylc_knowledge_base WHERE section = 'User Manual - Editing component properties';
|
||||
INSERT INTO diylc_knowledge_base(category, section, content) VALUES ('User Manual', 'User Manual - Editing component properties','Newly added components start with default parameters (size, color, value, name, etc.), but you can edit these properties in several ways:
|
||||
* **Double-click** a single component to open its edit dialog.
|
||||
* **Right-click** and choose "Edit Selection" (or press **Ctrl + E**) to edit one or multiple selected components at once.
|
||||
|
||||
When editing **multiple components** together, only properties common to all selected components are shown. If a property has different values among selections (e.g., a resistor\'s resistance vs. a capacitor\'s capacitance), its input field will appear highlighted in yellow, indicating a mixed value. Changing a yellow-highlighted field will apply that new value to all selected components.
|
||||
|
||||
**Default Values:** In the edit dialog, each property has a "Default" checkbox. Checking it sets the current value as the new default for that component type, so future added components will use that value instead of the original default.
|
||||
|
||||
**Units & Expressions:** For numeric properties with units (size, resistance, capacitance, etc.), you can enter math expressions. For example, typing `3/32` will automatically convert to a decimal, and you can use parentheses and basic arithmetic operators (+, -, *, /) for complex expressions.');
|
||||
|
||||
DELETE FROM diylc_knowledge_base WHERE section = 'User Manual - Assigning keyboard shortcuts to components';
|
||||
INSERT INTO diylc_knowledge_base(category, section, content) VALUES ('User Manual', 'User Manual - Assigning keyboard shortcuts to components','DIYLC allows assigning up to 12 component types to function keys (F1–F12) as shortcuts for quick access:
|
||||
* In the component tree, click the drop-down menu (triangle icon) next to a component category, and choose **Assign Shortcut** for the desired component. Select one of the available **F** keys.
|
||||
* Components with an assigned shortcut display an indicator (e.g., "F2") next to their name in the component tree.
|
||||
* To remove a shortcut, use the Assign Shortcut menu and choose "None".
|
||||
|
||||
Once set, pressing that function key will activate the component tool, allowing you to place that component without needing to click in the toolbar.');
|
||||
|
||||
DELETE FROM diylc_knowledge_base WHERE section = 'User Manual - Using component variants';
|
||||
INSERT INTO diylc_knowledge_base(category, section, content) VALUES ('User Manual', 'User Manual - Using component variants','Every component type starts with default values (size, color, etc.), but you can create **variants** with customized properties:
|
||||
* After editing a component to the desired settings, right-click it and choose **Save as Variant** from the context menu. This stores the current component properties as a reusable variant.
|
||||
* To apply a variant to an existing component, right-click the component and select the variant from the context menu. The component will update to match the variant\'s properties.
|
||||
* To add a new component using a saved variant, right-click the component type in the component tree; a context menu will list available variants – choose one to create a component with those properties.
|
||||
* To set a variant as the default for new components, right-click the component type in the tree and click the pin icon next to the variant (pin icon means "use this variant by default"). New components of that type will now use the variant\'s properties. (A trash icon in that menu can delete a variant.)');
|
||||
|
||||
DELETE FROM diylc_knowledge_base WHERE section = 'User Manual - Grouping components together';
|
||||
INSERT INTO diylc_knowledge_base(category, section, content) VALUES ('User Manual', 'User Manual - Grouping components together','DIYLC supports grouping components, similar to grouping objects in vector drawing tools, to manipulate them as a single unit:
|
||||
* Select two or more components and press **Ctrl + G** (or use *Group Selection* from the menu) to create a group. Once grouped, moving or editing will apply to all components in the group.
|
||||
* Double-click any component in a group to open a combined edit dialog showing all properties common to the group\'s components (so you can batch-edit them).
|
||||
* While components are grouped, you cannot individually drag their control points; you must ungroup to do so.
|
||||
* To ungroup, select the group and press **Ctrl + U** (or use *Ungroup Selection* from the menu).
|
||||
|
||||
**Note:** Nested grouping (grouping groups into larger groups) is not supported – grouping two existing groups will merge them into one single group.');
|
||||
|
||||
DELETE FROM diylc_knowledge_base WHERE section = 'User Manual - Using building blocks';
|
||||
INSERT INTO diylc_knowledge_base(category, section, content) VALUES ('User Manual', 'User Manual - Using building blocks','When you frequently use a cluster of components configured in a specific way, you can save them as a **Building Block** for reuse:
|
||||
1. Arrange and configure the components (e.g., a transistor with three wires forming a TO-92 package).
|
||||
2. Select all these components, right-click, and choose **Save as Building Block**.
|
||||
3. The new building block will appear under the **(Building Blocks)** category in the component tree. You can now add this cluster to any project with a single click, just like a normal component.
|
||||
4. To delete a building block, right-click it in the component tree and choose the delete option from its context menu.');
|
||||
|
||||
DELETE FROM diylc_knowledge_base WHERE section = 'User Manual - Working with layers';
|
||||
INSERT INTO diylc_knowledge_base(category, section, content) VALUES ('User Manual', 'User Manual - Working with layers','Each component in DIYLC has not only X and Y position but also a **Z-order layer** that controls stacking (what appears on top of what). Unlike free-form graphics editors, DIYLC uses fixed layers based on component types: **Chassis**, **Board**, **Trace**, **Component**, **Wiring**, **Text** (from bottom to top). For example, all traces are drawn above boards, and all components above traces, etc.
|
||||
|
||||
**Bring to Front/Send to Back** commands usually operate within a component\'s designated layer. If you move a component beyond its layer bounds, DIYLC will prompt to confirm crossing into a different layer (unusual cases).
|
||||
|
||||
Layer management features:
|
||||
* Temporarily **hide** an entire layer (useful to work on buried components).
|
||||
* **Lock/unlock** a layer, which keeps its components visible but not selectable/editable.
|
||||
* **Select all** components on a given layer (for quick bulk edits).');
|
||||
|
||||
DELETE FROM diylc_knowledge_base WHERE section = 'User Manual - Showing board underside';
|
||||
INSERT INTO diylc_knowledge_base(category, section, content) VALUES ('User Manual', 'User Manual - Showing board underside','To simplify designing and assembling circuit boards, DIYLC can display a board\'s underside along with its top side:
|
||||
* Double-click a board component (or open its edit dialog through other means) and adjust the underside settings:
|
||||
- **Underside Display**: Choose how to position the bottom view relative to the top (None, Above, Below, Left, Right of the original).
|
||||
- **Underside Offset**: Set the distance (spacing) between the top view and the bottom view.
|
||||
- **Underside Transparency**: If enabled, the bottom side is drawn semi-transparent to differentiate it from the top side.
|
||||
|
||||
Once configured, DIYLC will render both sides of the board simultaneously, making it easier to visualize double-sided layouts.');
|
||||
|
||||
DELETE FROM diylc_knowledge_base WHERE section = 'User Manual - Using the status bar';
|
||||
INSERT INTO diylc_knowledge_base(category, section, content) VALUES ('User Manual', 'User Manual - Using the status bar','The status bar (typically at the bottom of the window) provides several info panels from left to right:
|
||||
* **Information bar** – Contextual hints and messages guiding you through actions (e.g., instructions during component placement, or details about the current tool).
|
||||
* **Selection size** – The dimensions of the bounding box around all selected components (respects current unit, e.g., inches or cm).
|
||||
* **Zoom control** – A slider or control to zoom in/out on the canvas.
|
||||
* **Announcements** – Displays any public announcements (if present).
|
||||
* **Auto-update** indicator – A light bulb icon that lights up when a new version of DIYLC is available. Click it for more info.
|
||||
* **Memory bar** – A blue bar indicating current memory usage. Hover to see details, or click it to trigger garbage collection (free up memory). It turns red if memory usage is high, signaling potential performance issues.');
|
||||
|
||||
DELETE FROM diylc_knowledge_base WHERE section = 'User Manual - Using ''Highlight Connected Areas'' Feature';
|
||||
INSERT INTO diylc_knowledge_base(category, section, content) VALUES ('User Manual', 'User Manual - Using ''Highlight Connected Areas'' Feature','Introduced in DIYLC 3.42.0, the **Highlight Connected Areas** feature helps trace connections in your layout by highlighting conductive paths:
|
||||
* Activate it from **Analyze → Highlight Connected Areas**. The cursor changes to crosshairs and the project becomes temporarily read-only (you cannot move components in this mode).
|
||||
* Click on any component or connection point. DIYLC will highlight in green all components and traces that are electrically connected to that point (assuming zero-resistance connections).
|
||||
* This is particularly useful for debugging stripboard/veroboard layouts, PCBs, breadboards, or point-to-point wiring – it visually confirms which nodes are connected.
|
||||
* To exit this mode and resume editing, uncheck **Highlight Connected Areas** in the “Analyze” menu (which will turn the feature off).');
|
||||
|
||||
DELETE FROM diylc_knowledge_base WHERE section = 'User Manual - Drawing and Analyzing Guitar Wiring Diagrams (Part 1)';
|
||||
INSERT INTO diylc_knowledge_base(category, section, content) VALUES ('User Manual', 'User Manual - Drawing and Analyzing Guitar Wiring Diagrams (Part 1)','DIYLC can be used to create and analyze guitar wiring diagrams. Drawing the diagram uses the same tools and steps as any DIYLC project (with guitar-specific components under the **Guitar** category and common parts like jacks and switches under **Electro-Mechanical**). The powerful part is the **Guitar Wiring Analyzer** feature, which helps you understand and troubleshoot the wiring:
|
||||
|
||||
*The analyzer is accessed via File → Analyze → Guitar Wiring Diagrams, and requires a fully drawn diagram.* You should have at least one guitar pickup wired through any switches/pots and ultimately connected to an output jack (the jack is required for analysis). The analyzer will perform these checks:
|
||||
|
||||
- Identify all switches and consider every combination of switch positions. (For example, a 3-way toggle plus a push-pull pot yields 3 x 2 = 6 distinct configurations.) For each configuration, it will:
|
||||
- Determine which pickup coils are active.
|
||||
- Check if humbuckers are in full humbucking mode or split-coil.
|
||||
- Check if active coils are wired in series or parallel.
|
||||
- Check the phase relationship of each coil (and if multiple coils are active, whether they are in-phase or out-of-phase with each other).
|
||||
- Determine if the active pickup combination is noise-cancelling (hum canceling).
|
||||
- See if any potentiometers are functioning as volume or tone controls in that configuration.
|
||||
- Check if a treble bleed network is present on any volume control.');
|
||||
|
||||
DELETE FROM diylc_knowledge_base WHERE section = 'User Manual - Drawing and Analyzing Guitar Wiring Diagrams (Part 2)';
|
||||
INSERT INTO diylc_knowledge_base(category, section, content) VALUES ('User Manual', 'User Manual - Drawing and Analyzing Guitar Wiring Diagrams (Part 2)','Below is an example of a fully wired guitar diagram analyzed by DIYLC: it has two rail humbucker pickups, a 3-way toggle switch, and one push-pull volume pot (which splits the humbuckers when pulled) plus a treble bleed circuit on the volume.
|
||||
|
||||
*(You can download this example as a DIYLC file named "travelcaster.diy".)*
|
||||
|
||||
To run the analyzer, go to File → Analyze → Guitar Wiring Diagrams. The output will be divided into sections for each switch configuration. For instance, here\'s the output for the middle position of a 3-way switch with the push-pull not engaged:
|
||||
|
||||
- It shows a **parallel/series connectivity tree** representing the circuit from the output jack\'s perspective for that configuration. The tree uses parentheses for hierarchy, "+" for series connections, and "||" for parallel connections. Pickup coils are labeled like **PickupName.North** or **PickupName.South**, with an arrow indicating polarity.
|
||||
- Below the tree, DIYLC lists notes deduced from the connectivity, such as which coils are active, their phase relationship, whether the combination is hum-cancelling, etc. This is where the analysis "magic" happens – it provides insights into the wiring\'s behavior.
|
||||
|
||||
For a full detailed analysis of this example, DIYLC provides an HTML report (accessible via an online viewer for *travelcaster_analysis.html*).');
|
||||
|
||||
DELETE FROM diylc_knowledge_base WHERE section = 'Component API - General advice';
|
||||
INSERT INTO diylc_knowledge_base(category, section, content) VALUES ('User Manual', 'Component API - General advice','When creating a new DIYLC component, strive for consistency with existing components in both appearance and behavior, as well as code style. This ensures a uniform user experience and maintainable codebase across all components. **Key advice:** follow the established visual design patterns and coding standards in DIYLC for any custom component.');
|
||||
|
||||
DELETE FROM diylc_knowledge_base WHERE section = 'Component API - Prerequisites';
|
||||
INSERT INTO diylc_knowledge_base(category, section, content) VALUES ('User Manual', 'Component API - Prerequisites','Before developing DIYLC components, ensure you have:
|
||||
* Java **JDK 17** (or later) installed.
|
||||
* A Java IDE, e.g. IntelliJ IDEA
|
||||
* Maven
|
||||
* A working **Git** client (to fetch and manage DIYLC code).
|
||||
* Solid Java knowledge (including generics, annotations, and familiarity with **Graphics2D** for rendering).
|
||||
* Docker (only for building the deployment packages)
|
||||
|
||||
Note: Unlike DIYLC v2, versions 3 and higher components require actual Java coding for custom appearance and behavior. This raises the bar for non-programmers but gives greater flexibility and performance.');
|
||||
Reference in New Issue
Block a user