diff --git a/diylc/diylc-core/src/org/diylc/components/AbstractComponent.java b/diylc/diylc-core/src/org/diylc/components/AbstractComponent.java index c5aceee8..38c79418 100644 --- a/diylc/diylc-core/src/org/diylc/components/AbstractComponent.java +++ b/diylc/diylc-core/src/org/diylc/components/AbstractComponent.java @@ -266,11 +266,6 @@ public abstract class AbstractComponent implements IDIYComponent { return null; } - @Override - public String getCommonPointName(int pointIndex) { - return null; - } - @Override public boolean canPointMoveFreely(int pointIndex) { return true; diff --git a/diylc/diylc-core/src/org/diylc/core/ICommonNode.java b/diylc/diylc-core/src/org/diylc/core/ICommonNode.java new file mode 100644 index 00000000..ffb55e37 --- /dev/null +++ b/diylc/diylc-core/src/org/diylc/core/ICommonNode.java @@ -0,0 +1,29 @@ +/* + * + * 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 + * . + * + */ +package org.diylc.core; + +public interface ICommonNode { + + + /*** + * @return label of the common node. All nodes with the same labels will be considered as + * connected, e.g. B+ or A, B, C + */ + String getCommonNodeLabel(); +} diff --git a/diylc/diylc-core/src/org/diylc/core/IDIYComponent.java b/diylc/diylc-core/src/org/diylc/core/IDIYComponent.java index 7cfaa606..ecf2c54e 100644 --- a/diylc/diylc-core/src/org/diylc/core/IDIYComponent.java +++ b/diylc/diylc-core/src/org/diylc/core/IDIYComponent.java @@ -138,12 +138,6 @@ public interface IDIYComponent extends Serializable, Cloneable { */ String[] getSectionNames(int pointIndex); - /** - * @param pointIndex - * @return name of the common point that joins all the other points with the same name together, e.g. GND - */ - String getCommonPointName(int pointIndex); - /** * @param pointIndex * @return true if the control point can move without affecting other points' position, false otherwise diff --git a/diylc/diylc-core/src/org/diylc/netlist/NetlistBuilder.java b/diylc/diylc-core/src/org/diylc/netlist/NetlistBuilder.java index 81afd694..9c216646 100644 --- a/diylc/diylc-core/src/org/diylc/netlist/NetlistBuilder.java +++ b/diylc/diylc-core/src/org/diylc/netlist/NetlistBuilder.java @@ -30,6 +30,7 @@ import java.util.Set; import java.util.TreeSet; import java.util.stream.Collectors; import org.diylc.common.ComponentType; +import org.diylc.core.ICommonNode; import org.diylc.core.IContinuity; import org.diylc.core.IDIYComponent; import org.diylc.core.ISwitch; @@ -60,13 +61,15 @@ public class NetlistBuilder { List nodes = new ArrayList(); List switches = new ArrayList(); + + Set commonNodes = new HashSet(); for (IDIYComponent c : project.getComponents()) { ComponentType type = ComponentProcessor.getInstance() .extractComponentTypeFrom((Class>) c.getClass()); // extract nodes - if (!(c instanceof IContinuity)) { + if (!(c instanceof IContinuity) && !(c instanceof ICommonNode)) { for (int i = 0; i < c.getControlPointCount(); i++) { String nodeName = c.getControlPointNodeName(i); if (nodeName != null @@ -75,6 +78,15 @@ public class NetlistBuilder { } } } + + // create only one node per common label to avoid duplications in the netlist, as they will get eventually connected anyways + if (c instanceof ICommonNode) { + String label = ((ICommonNode)c).getCommonNodeLabel(); + if (!commonNodes.contains(label)) { + commonNodes.add(label); + nodes.add(new Node(c, 0)); + } + } // extract switches if (includeSwitches && ISwitch.class.isAssignableFrom(type.getInstanceClass())) @@ -342,6 +354,8 @@ public class NetlistBuilder { private static List getConnections(Project project, Map switchPositions) { Set connections = new TreeSet(); + Map>> commonNodeMap = new HashMap>>(); + for (IDIYComponent c : project.getComponents()) { ComponentType type = ComponentProcessor.getInstance().extractComponentTypeFrom((Class>) c.getClass()); @@ -361,6 +375,20 @@ public class NetlistBuilder { if (s.arePointsConnected(i, j, position)) connections.add(new Connection(c.getControlPoint(i), c.getControlPoint(j))); } + // handle common nodes + if (ICommonNode.class.isAssignableFrom(type.getInstanceClass())) { + ICommonNode commonNode = (ICommonNode) c; + String label = commonNode.getCommonNodeLabel(); + commonNodeMap.computeIfAbsent(label, (key) -> new ArrayList>()).add(c); + } + } + + // connect common nodes together by chaining them one by one + for (List> commonPoints : commonNodeMap.values()) { + IDIYComponent[] commonPointArr = commonPoints.toArray(new IDIYComponent[0]); + for (int i = 0; i < commonPointArr.length - 1; i++) { + connections.add(new Connection(commonPointArr[i].getControlPoint(0), commonPointArr[i + 1].getControlPoint(0))); + } } return new ArrayList(connections); diff --git a/diylc/diylc-core/src/org/diylc/netlist/Node.java b/diylc/diylc-core/src/org/diylc/netlist/Node.java index 319331f6..659c03c1 100644 --- a/diylc/diylc-core/src/org/diylc/netlist/Node.java +++ b/diylc/diylc-core/src/org/diylc/netlist/Node.java @@ -22,6 +22,7 @@ package org.diylc.netlist; import java.awt.geom.Point2D; +import org.diylc.core.ICommonNode; import org.diylc.core.IDIYComponent; /** @@ -87,6 +88,9 @@ public class Node implements Comparable { @Override public String toString() { + if (component instanceof ICommonNode) { + return ((ICommonNode)component).getCommonNodeLabel(); + } if (component.getControlPointCount() == 1) return component.getName(); return component.getName() + "." + getDisplayName() /*+ " @ (" + component.getControlPoint(pointIndex).getX() + ":" + component.getControlPoint(pointIndex).getY() + ")"*/; diff --git a/diylc/diylc-core/src/org/diylc/presenter/update.xml b/diylc/diylc-core/src/org/diylc/presenter/update.xml index e9bd4a01..bc0bd124 100644 --- a/diylc/diylc-core/src/org/diylc/presenter/update.xml +++ b/diylc/diylc-core/src/org/diylc/presenter/update.xml @@ -4062,9 +4062,21 @@ 2022-10-23 00:00:00.000 CET + + NEW_FEATURE + Added "Common Node" component that ties all nodes with the same label together, e.g. B+, V+, GND, etc + + + NEW_FEATURE + Ground symbol ties all grounded points together for circuit analysis + IMPROVEMENT "Snap to Components" features now works when creating new components as well as when moving existing ones + + + BUG_FIX + "Snap to" configuration menu does not work properly when using translated UI to any language other than English https://github.com/bancika/diy-layout-creator/releases diff --git a/diylc/diylc-library/lib/diylc-core.jar b/diylc/diylc-library/lib/diylc-core.jar index 720e7bff..c506f79a 100644 Binary files a/diylc/diylc-library/lib/diylc-core.jar and b/diylc/diylc-library/lib/diylc-core.jar differ diff --git a/diylc/diylc-library/src/org/diylc/components/misc/CommonNode.java b/diylc/diylc-library/src/org/diylc/components/misc/CommonNode.java new file mode 100644 index 00000000..6cacbf14 --- /dev/null +++ b/diylc/diylc-library/src/org/diylc/components/misc/CommonNode.java @@ -0,0 +1,206 @@ +/* + + 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 . + +*/ +package org.diylc.components.misc; + +import java.awt.Color; +import java.awt.Font; +import java.awt.FontMetrics; +import java.awt.Graphics2D; +import java.awt.Rectangle; +import java.awt.geom.Point2D; +import java.awt.geom.Rectangle2D; +import java.awt.geom.RoundRectangle2D; +import org.diylc.awt.StringUtils; +import org.diylc.common.HorizontalAlignment; +import org.diylc.common.ObjectCache; +import org.diylc.common.VerticalAlignment; +import org.diylc.components.AbstractComponent; +import org.diylc.components.transform.TextTransformer; +import org.diylc.core.ComponentState; +import org.diylc.core.ICommonNode; +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; + +@ComponentDescriptor(name = "Common Node", author = "Branislav Stojkovic", category = "Misc", + description = "Label that ties all nodes together", instanceNamePrefix = "CN", zOrder = IDIYComponent.TEXT, flexibleZOrder = true, + bomPolicy = BomPolicy.NEVER_SHOW, transformer = TextTransformer.class) +public class CommonNode extends AbstractComponent implements ICommonNode { + + public static String DEFAULT_TEXT = "X"; + + private static int BUFFER = 4; + private static final int STROKE_WIDTH = 2; + private static final Color BG_COLOR = Color.lightGray; + + private static final long serialVersionUID = 1L; + + private Point2D.Double point = new Point2D.Double(0, 0); + private String text = DEFAULT_TEXT; + private Font font = LABEL_FONT; + private Color color = LABEL_COLOR; + private Color bgColor = BG_COLOR; + + @Override + public void draw(Graphics2D g2d, ComponentState componentState, boolean outlineMode, Project project, + IDrawingObserver drawingObserver) { + g2d.setFont(font.deriveFont(Font.BOLD)); + + double x = point.getX(); + double y = point.getY(); + + g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(STROKE_WIDTH)); + + FontMetrics fontMetrics = g2d.getFontMetrics(); + Rectangle stringBounds = fontMetrics.getStringBounds(text, g2d).getBounds(); + + RoundRectangle2D rect = new RoundRectangle2D.Double(x - stringBounds.getWidth() / 2 - BUFFER, + y - stringBounds.getHeight() / 2 - BUFFER, stringBounds.getWidth() + 2 * BUFFER, stringBounds.getHeight() + 2 * BUFFER, + stringBounds.getHeight() / 2, stringBounds.getHeight() / 2); + + g2d.setColor(bgColor); + drawingObserver.startTrackingContinuityArea(true); + g2d.fill(rect); + drawingObserver.stopTrackingContinuityArea(); + drawingObserver.stopTracking(); + g2d.setColor(componentState == ComponentState.SELECTED ? LABEL_COLOR_SELECTED : color); + g2d.draw(rect); + + StringUtils.drawCenteredText(g2d, text, x, y, HorizontalAlignment.CENTER, VerticalAlignment.CENTER); + } + + @Override + public void drawIcon(Graphics2D g2d, int width, int height) { + + g2d.setFont(LABEL_FONT.deriveFont(13f * width / 32).deriveFont(Font.BOLD)); + + String text = "B+"; + + FontMetrics fontMetrics = g2d.getFontMetrics(); + Rectangle2D rect = fontMetrics.getStringBounds(text, g2d); + + int textHeight = (int) (rect.getHeight()); + int textWidth = (int) (rect.getWidth()); + + // Center text horizontally and vertically. + int x = (width - textWidth) / 2 + 1; + int y = (height - textHeight) / 2 + fontMetrics.getAscent(); + + g2d.setColor(BG_COLOR); + g2d.fillRoundRect(4, 6, width - 8, height - 12, 6, 6); + g2d.setColor(LABEL_COLOR); + g2d.drawRoundRect(4, 6, width - 8, height - 12, 6, 6); + g2d.drawString(text, x, y); + } + + @EditableProperty + public Font getFont() { + return font; + } + + public void setFont(Font font) { + this.font = font; + } + + @EditableProperty(name = "Font Size") + public int getFontSize() { + return font.getSize(); + } + + public void setFontSize(int size) { + font = font.deriveFont((float) size); + } + + @Override + public int getControlPointCount() { + return 1; + } + + @Override + public Point2D getControlPoint(int index) { + return point; + } + + @Override + public boolean isControlPointSticky(int index) { + return false; + } + + @Override + public VisibilityPolicy getControlPointVisibilityPolicy(int index) { + return VisibilityPolicy.WHEN_SELECTED; + } + + @Override + public void setControlPoint(Point2D point, int index) { + this.point.setLocation(point); + } + + @EditableProperty(name = "Label") + public Color getColor() { + return color; + } + + public void setColor(Color color) { + this.color = color; + } + + @EditableProperty(name = "Background") + public Color getBgColor() { + return bgColor; + } + + public void setBgColor(Color bgColor) { + this.bgColor = bgColor; + } + + @Deprecated + @Override + public String getName() { + return super.getName(); + } + + @EditableProperty + @Override + public String getValue() { + return text; + } + + @Override + public void setValue(String value) { + this.text = value; + } + + @Override + public String getControlPointNodeName(int index) { + return null; + } + + @Override + public String getCommonNodeLabel() { + return text; + } +} diff --git a/diylc/diylc-library/src/org/diylc/components/misc/GroundSymbol.java b/diylc/diylc-library/src/org/diylc/components/misc/GroundSymbol.java index bc8d5517..5545b8d9 100644 --- a/diylc/diylc-library/src/org/diylc/components/misc/GroundSymbol.java +++ b/diylc/diylc-library/src/org/diylc/components/misc/GroundSymbol.java @@ -29,6 +29,7 @@ import org.diylc.common.ObjectCache; import org.diylc.common.Orientation; import org.diylc.components.AbstractComponent; import org.diylc.core.ComponentState; +import org.diylc.core.ICommonNode; import org.diylc.core.IDIYComponent; import org.diylc.core.IDrawingObserver; import org.diylc.core.Project; @@ -42,7 +43,7 @@ import org.diylc.core.measures.SizeUnit; @ComponentDescriptor(name = "Ground", author = "Branislav Stojkovic", category = "Schematic Symbols", instanceNamePrefix = "GND", description = "Ground schematic symbol", zOrder = IDIYComponent.COMPONENT, bomPolicy = BomPolicy.NEVER_SHOW, autoEdit = false) -public class GroundSymbol extends AbstractComponent { +public class GroundSymbol extends AbstractComponent implements ICommonNode { private static final long serialVersionUID = 1L; @@ -161,14 +162,9 @@ public class GroundSymbol extends AbstractComponent { public void setControlPoint(Point2D point, int index) { this.point.setLocation(point); } -// -// @Override -// public String getControlPointNodeName(int index) { -// return getName(); -// } @Override - public String getCommonPointName(int pointIndex) { + public String getCommonNodeLabel() { return "GND"; } diff --git a/diylc/diylc-library/src/org/diylc/components/misc/Label.java b/diylc/diylc-library/src/org/diylc/components/misc/Label.java index 1e6904b6..fa32fd57 100644 --- a/diylc/diylc-library/src/org/diylc/components/misc/Label.java +++ b/diylc/diylc-library/src/org/diylc/components/misc/Label.java @@ -1,50 +1,50 @@ -/* - - 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 . - -*/ +/* + + 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 . + +*/ package org.diylc.components.misc; -import java.awt.Color; -import java.awt.Font; -import java.awt.FontMetrics; -import java.awt.Graphics2D; -import java.awt.geom.Point2D; -import java.awt.geom.Rectangle2D; -import org.diylc.awt.StringUtils; -import org.diylc.common.HorizontalAlignment; -import org.diylc.common.Orientation; -import org.diylc.common.VerticalAlignment; -import org.diylc.components.AbstractComponent; -import org.diylc.components.transform.TextTransformer; -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 java.awt.Color; +import java.awt.Font; +import java.awt.FontMetrics; +import java.awt.Graphics2D; +import java.awt.geom.Point2D; +import java.awt.geom.Rectangle2D; +import org.diylc.awt.StringUtils; +import org.diylc.common.HorizontalAlignment; +import org.diylc.common.Orientation; +import org.diylc.common.VerticalAlignment; +import org.diylc.components.AbstractComponent; +import org.diylc.components.transform.TextTransformer; +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.MultiLineText; @ComponentDescriptor(name = "Label", author = "Branislav Stojkovic", category = "Misc", - description = "User defined label", instanceNamePrefix = "L", zOrder = IDIYComponent.TEXT, flexibleZOrder = true, + description = "User defined label", instanceNamePrefix = "LAB", zOrder = IDIYComponent.TEXT, flexibleZOrder = true, bomPolicy = BomPolicy.NEVER_SHOW, transformer = TextTransformer.class) public class Label extends AbstractComponent { @@ -83,8 +83,8 @@ public class Label extends AbstractComponent { case _270: g2d.rotate(Math.PI * 3 / 2, point.getX(), point.getY()); break; - } - + } + StringUtils.drawCenteredText(g2d, text, x, y, getHorizontalAlignment(), getVerticalAlignment()); } @@ -244,7 +244,7 @@ public class Label extends AbstractComponent { return super.getName(); } - @EditableProperty(name="Text", defaultable = false) + @EditableProperty(name="Text", defaultable = false) @MultiLineText @Override public String getValue() { @@ -254,10 +254,10 @@ public class Label extends AbstractComponent { @Override public void setValue(String value) { this.text = value; - } - - @Override - public String getControlPointNodeName(int index) { - return null; + } + + @Override + public String getControlPointNodeName(int index) { + return null; } } diff --git a/diylc/diylc-swing/lib/diylc-core.jar b/diylc/diylc-swing/lib/diylc-core.jar index 720e7bff..c506f79a 100644 Binary files a/diylc/diylc-swing/lib/diylc-core.jar and b/diylc/diylc-swing/lib/diylc-core.jar differ diff --git a/diylc/diylc-swing/src/org/diylc/swing/ActionFactory.java b/diylc/diylc-swing/src/org/diylc/swing/ActionFactory.java index 3adc1697..eee65d2e 100644 --- a/diylc/diylc-swing/src/org/diylc/swing/ActionFactory.java +++ b/diylc/diylc-swing/src/org/diylc/swing/ActionFactory.java @@ -1823,9 +1823,12 @@ public class ActionFactory { private String configKey; + private String title; + public ToggleAction(String title, String configKey, String groupName, String defaultValue, Icon icon) { super(); + this.title = title; this.configKey = configKey; putValue(AbstractAction.NAME, title); putValue(IView.RADIO_BUTTON_GROUP_KEY, groupName); @@ -1840,13 +1843,12 @@ public class ActionFactory { @Override public void actionPerformed(ActionEvent e) { LOG.info(getValue(AbstractAction.NAME) + " toggle triggered"); - ConfigurationManager.getInstance().writeValue(configKey, getValue(AbstractAction.NAME)); + ConfigurationManager.getInstance().writeValue(configKey, title); } @Override public void valueChanged(String key, Object value) { - putValue(AbstractAction.SELECTED_KEY, - getValue(AbstractAction.NAME).toString().equalsIgnoreCase(value.toString())); + putValue(AbstractAction.SELECTED_KEY, title.equalsIgnoreCase(value.toString())); } }