From 9dada76406b18a5e86227794942faabd1bc24190 Mon Sep 17 00:00:00 2001 From: bancika Date: Sun, 13 Dec 2020 11:12:45 +0100 Subject: [PATCH] Added a button in the action toolbar to toggle between snap modes (none, grid, component) --- .../src/org/diylc/presenter/update.xml | 6 +- diylc/diylc-swing/lang/Deutsch.txt | 3 +- diylc/diylc-swing/lang/English.txt | 3 +- diylc/diylc-swing/lang/Español.txt | 3 +- diylc/diylc-swing/lang/Français.txt | 3 +- diylc/diylc-swing/lang/Italiano.txt | 3 +- diylc/diylc-swing/lang/Nederlands.txt | 5 +- diylc/diylc-swing/lang/Srpski.txt | 3 +- .../src/org/diylc/swing/ActionFactory.java | 9 +- .../swing/gui/actionbar/ActionBarPlugin.java | 12 ++- .../swing/gui/actionbar/ConfigToolbar.java | 6 ++ .../gui/actionbar/ToggleConfigLabel.java | 85 ++++++++++++++++++ .../diylc/swing/gui/actionbar/ToggleItem.java | 28 ++++++ .../org/diylc/swing/images/IconLoader.java | 3 +- .../diylc/swing/images/snap_to_components.png | Bin 0 -> 2342 bytes .../org/diylc/swing/images/snap_to_grid.png | Bin 0 -> 2152 bytes .../org/diylc/swing/images/snap_to_none.png | Bin 0 -> 2129 bytes .../swing/plugins/canvas/CanvasPanel.java | 1 - .../swing/plugins/config/ConfigPlugin.java | 2 +- 19 files changed, 160 insertions(+), 15 deletions(-) create mode 100644 diylc/diylc-swing/src/org/diylc/swing/gui/actionbar/ToggleConfigLabel.java create mode 100644 diylc/diylc-swing/src/org/diylc/swing/gui/actionbar/ToggleItem.java create mode 100644 diylc/diylc-swing/src/org/diylc/swing/images/snap_to_components.png create mode 100644 diylc/diylc-swing/src/org/diylc/swing/images/snap_to_grid.png create mode 100644 diylc/diylc-swing/src/org/diylc/swing/images/snap_to_none.png diff --git a/diylc/diylc-core/src/org/diylc/presenter/update.xml b/diylc/diylc-core/src/org/diylc/presenter/update.xml index c7e56dc0..7e07aa57 100644 --- a/diylc/diylc-core/src/org/diylc/presenter/update.xml +++ b/diylc/diylc-core/src/org/diylc/presenter/update.xml @@ -3277,7 +3277,11 @@ 2020-11-19 00:00:00.000 CET - + + + NEW_FEATURE + Added a button in the action toolbar to toggle between snap modes (none, grid, component) + NEW_FEATURE Added pinch zooming functionality for compatible devices (tested on Mac and Win laptops) diff --git a/diylc/diylc-swing/lang/Deutsch.txt b/diylc/diylc-swing/lang/Deutsch.txt index 12f6c51e..1ef43568 100644 --- a/diylc/diylc-swing/lang/Deutsch.txt +++ b/diylc/diylc-swing/lang/Deutsch.txt @@ -61,6 +61,7 @@ Click on the canvas to set the %s control point of a new %s or press %s to cance Click the lightbulb icon in the bottom-right corner of the window for more info.|Klicken Sie auf das Glühbirnen-Symbol in der unteren rechten Ecke des Fensters, um weitere Informationen zu erhalten Click to fetch the most recent public announcement|Klicken Sie hier, um das neuste Update zu erhalten Click to show recent changes and updates|Klicken Sie hier, um die letzten Änderungen und Aktualisierungen anzuzeigen +Click to toggle to the next option|Klicken Sie, um zur nächsten Option zu wechseln Coil|Spule Coil Border|Spulenrand Coil Length|Spulenlänge @@ -367,7 +368,7 @@ Size|Größe Sizing Mode|Größenmodus Small-button B7G|Miniatur 7-pol Smooth|Glätten -Snap To...|Einrasten zu... +Snap To|Einrasten zu Soap Bar| Solid|Ununterbrochen South|Süden diff --git a/diylc/diylc-swing/lang/English.txt b/diylc/diylc-swing/lang/English.txt index dbd9291d..b2734953 100644 --- a/diylc/diylc-swing/lang/English.txt +++ b/diylc/diylc-swing/lang/English.txt @@ -58,6 +58,7 @@ Click on the canvas to set the %s control point of a new %s or press %s to cance Click the lightbulb icon in the bottom-right corner of the window for more info. Click to fetch the most recent public announcement Click to show recent changes and updates +Click to toggle to the next option Coil Coil Border Coil Length @@ -350,7 +351,7 @@ Size Sizing Mode Small-button B7G Smooth -Snap To... +Snap To Soap Bar Solid South diff --git a/diylc/diylc-swing/lang/Español.txt b/diylc/diylc-swing/lang/Español.txt index fe41150f..c12d26ff 100644 --- a/diylc/diylc-swing/lang/Español.txt +++ b/diylc/diylc-swing/lang/Español.txt @@ -58,6 +58,7 @@ Click on the canvas to set the %s control point of a new %s or press %s to cance Click the lightbulb icon in the bottom-right corner of the window for more info.|Haga clic en el icono de la bombilla en la esquina inferior derecha de la ventana para obtener más información. Click to fetch the most recent public announcement|Haga clic para obtener el anuncio público más reciente. Click to show recent changes and updates|Haga clic para ver cambios y actualizaciones recientes +Click to toggle to the next option|Haga clic para cambiar a la siguiente opción Coil|Bobina Coil Border|Borde de la bobina Coil Length|Longitud de la bobina @@ -356,7 +357,7 @@ Size|Tamaño Sizing Mode|Modo de Dimensionamiento Small-button B7G|Zócalo de Botón pequeño B7G Smooth|Suave -Snap To...|Ajustarse a... +Snap To|Ajustarse a Soap Bar|Soap Bar Solid|Sólido South|Sur diff --git a/diylc/diylc-swing/lang/Français.txt b/diylc/diylc-swing/lang/Français.txt index 5138ab21..db3d4c86 100644 --- a/diylc/diylc-swing/lang/Français.txt +++ b/diylc/diylc-swing/lang/Français.txt @@ -58,6 +58,7 @@ Click on the canvas to set the %s control point of a new %s or press %s to cance Click the lightbulb icon in the bottom-right corner of the window for more info.|Cliquez sur l'icône de l'ampoule dans le coin inférieur droit de la fenêtre pour plus d'informations. Click to fetch the most recent public announcement|Cliquez pour récupérer l'annonce publique la plus récente Click to show recent changes and updates|Cliquez pour afficher les modifications et mises à jour récentes +Click to toggle to the next option|Cliquez pour passer à l'option suivante Coil|Bobine Coil Border|Bordure de la bobine Coil Length|Longueur de la bobine @@ -352,7 +353,7 @@ Size|Taille Sizing Mode|Mode de redimensionnement Small-button B7G|Petit bouton B7G Smooth|Lisse -Snap To...|Aimanter à ... +Snap To|Aimanter à Soap Bar|Soap Bar Solid|Solide South|Sud diff --git a/diylc/diylc-swing/lang/Italiano.txt b/diylc/diylc-swing/lang/Italiano.txt index 3ef5892b..73b513e9 100644 --- a/diylc/diylc-swing/lang/Italiano.txt +++ b/diylc/diylc-swing/lang/Italiano.txt @@ -61,6 +61,7 @@ Click on the canvas to set the %s control point of a new %s or press %s to cance Click the lightbulb icon in the bottom-right corner of the window for more info.|Clicca sull'icona della lampadina nell'angolo in basso a destra della finestra per ulteriori informazioni. Click to fetch the most recent public announcement|Clicca per recuperare l'annuncio pubblico più recente Click to show recent changes and updates|Clicca per mostrare le modifiche e gli aggiornamenti recenti +Click to toggle to the next option|Clicca per passare all'opzione successiva Coil|Bobina Coil Border|Bordo della Bobina Coil Length|Lunghezza della Bobina @@ -367,7 +368,7 @@ Size|dimensione Sizing Mode|Modalità di dimensionamento Small-button B7G|Pulsante piccolo B7G Smooth|Smussato -Snap To...|Aggancia a ... +Snap To|Aggancia a Soap Bar|Soap Bar Solid|solido South|Sud diff --git a/diylc/diylc-swing/lang/Nederlands.txt b/diylc/diylc-swing/lang/Nederlands.txt index a33fa40f..53bfa341 100644 --- a/diylc/diylc-swing/lang/Nederlands.txt +++ b/diylc/diylc-swing/lang/Nederlands.txt @@ -60,7 +60,8 @@ Click on the canvas to create a new %s or press %s to cancel|Klik op het werkbla Click on the canvas to set the %s control point of a new %s or press %s to cancel|Klik op het werkblad om het %s-controlepunt van een nieuwe %s in te stellen of druk op %s om te annuleren Click the lightbulb icon in the bottom-right corner of the window for more info.|Klik op het gloeilampicoon in de rechteronderhoek van het venster voor meer informatie. Click to fetch the most recent public announcement|Klik om de meest recente openbare aankondiging op te halen -Click to show recent changes and updates|Klik om recente wijzigingen en updates weer te geven +Click to show recent changes and updates|Klik om recente wijzigingen en updates weer te geven +Click to toggle to the next option|Klik om naar de volgende optie te gaan Coil|Spoel Coil Border|Spoelrand Coil Length|Spoellengte @@ -367,7 +368,7 @@ Size|Maat Sizing Mode|Dimensioneringsmethode Small-button B7G|B7G met Kleine Knop Smooth|Egaliseren -Snap To...|Uitlijnen op... +Snap To|Uitlijnen op Soap Bar|Soap Bar Solid|Ononderbroken South|Zuid diff --git a/diylc/diylc-swing/lang/Srpski.txt b/diylc/diylc-swing/lang/Srpski.txt index 6cc7a694..0d27d66c 100644 --- a/diylc/diylc-swing/lang/Srpski.txt +++ b/diylc/diylc-swing/lang/Srpski.txt @@ -58,6 +58,7 @@ Click on the canvas to set the %s control point of a new %s or press %s to cance Click the lightbulb icon in the bottom-right corner of the window for more info.|Klikni na ikonicu sa sijalicom u donjem-desnom uglu prozora za više informacija. Click to fetch the most recent public announcement|Klikni za preuzimanje najnovijih objava Click to show recent changes and updates|Klikni za prikaz skorih unapređenja +Click to toggle to the next option|Klikni za prelaz za narednu opciju Coil|Kalem Coil Border|Ivica Kalema Coil Length|Dužina Kalema @@ -348,7 +349,7 @@ Size|Veličina Sizing Mode|Zadavanje Veličine Small-button B7G Smooth|Glatko -Snap To...|Zalepi Uz... +Snap To|Zalepi Uz Soap Bar Solid|Puna Linija South|Jug diff --git a/diylc/diylc-swing/src/org/diylc/swing/ActionFactory.java b/diylc/diylc-swing/src/org/diylc/swing/ActionFactory.java index e41c1d91..738df72b 100644 --- a/diylc/diylc-swing/src/org/diylc/swing/ActionFactory.java +++ b/diylc/diylc-swing/src/org/diylc/swing/ActionFactory.java @@ -1705,7 +1705,7 @@ public class ActionFactory { } } - public static class ToggleAction extends AbstractAction { + public static class ToggleAction extends AbstractAction implements IConfigListener { private static final long serialVersionUID = 1L; @@ -1720,6 +1720,8 @@ public class ActionFactory { .readString(configKey, defaultValue).equalsIgnoreCase(title)); if (icon != null) putValue(AbstractAction.SMALL_ICON, icon); + // keep track of config changes and update the state accordingly + ConfigurationManager.getInstance().addConfigListener(configKey, this); } @Override @@ -1727,6 +1729,11 @@ public class ActionFactory { LOG.info(getValue(AbstractAction.NAME) + " toggle triggered"); ConfigurationManager.getInstance().writeValue(configKey, getValue(AbstractAction.NAME)); } + + @Override + public void valueChanged(String key, Object value) { + putValue(AbstractAction.SELECTED_KEY, getValue(AbstractAction.NAME).toString().equalsIgnoreCase(value.toString())); + } } public static class ThemeAction extends AbstractAction { diff --git a/diylc/diylc-swing/src/org/diylc/swing/gui/actionbar/ActionBarPlugin.java b/diylc/diylc-swing/src/org/diylc/swing/gui/actionbar/ActionBarPlugin.java index 7ac1d3a2..4adf4cc7 100644 --- a/diylc/diylc-swing/src/org/diylc/swing/gui/actionbar/ActionBarPlugin.java +++ b/diylc/diylc-swing/src/org/diylc/swing/gui/actionbar/ActionBarPlugin.java @@ -26,7 +26,9 @@ import java.awt.event.ComponentAdapter; import java.awt.event.ComponentEvent; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; +import java.util.ArrayList; import java.util.EnumSet; +import java.util.List; import javax.swing.BorderFactory; import javax.swing.JLabel; @@ -42,11 +44,10 @@ import org.diylc.common.EventType; import org.diylc.common.IComponentTransformer; import org.diylc.common.IPlugIn; import org.diylc.common.IPlugInPort; -import org.diylc.swing.images.IconLoader; import org.diylc.lang.LangUtil; import org.diylc.swing.ActionFactory; import org.diylc.swing.ISwingUI; -import org.diylc.swing.plugins.canvas.CanvasPlugin; +import org.diylc.swing.images.IconLoader; import org.diylc.swing.plugins.help.HelpMenuPlugin; /** @@ -152,6 +153,13 @@ public class ActionBarPlugin implements IPlugIn { public ConfigToolbar getConfigToolbar() { if (configToolbar == null) { configToolbar = new ConfigToolbar(); + + List toggleItems = new ArrayList(); + toggleItems.add(new ToggleItem(IPlugInPort.SNAP_TO_NONE, IPlugInPort.SNAP_TO_NONE, IconLoader.SnapToNone.getIcon())); + toggleItems.add(new ToggleItem(IPlugInPort.SNAP_TO_GRID, IPlugInPort.SNAP_TO_GRID, IconLoader.SnapToGrid.getIcon())); + toggleItems.add(new ToggleItem(IPlugInPort.SNAP_TO_COMPONENTS, IPlugInPort.SNAP_TO_COMPONENTS, IconLoader.SnapToComponents.getIcon())); + configToolbar.addToggleLabel(LangUtil.translate("Snap To"), IPlugInPort.SNAP_TO_KEY, IPlugInPort.SNAP_TO_DEFAULT, toggleItems); + configToolbar.add(LangUtil.translate("Continuous Creation"), IPlugInPort.CONTINUOUS_CREATION_KEY, IconLoader.Elements.getIcon(), false); configToolbar.add(LangUtil.translate("Highlight Connected Areas"), IPlugInPort.HIGHLIGHT_CONTINUITY_AREA, IconLoader.LaserPointer.getIcon(), false); configToolbar.add(LangUtil.translate("Sticky Points"), IPlugInPort.STICKY_POINTS_KEY, IconLoader.GraphNodes.getIcon(), true); diff --git a/diylc/diylc-swing/src/org/diylc/swing/gui/actionbar/ConfigToolbar.java b/diylc/diylc-swing/src/org/diylc/swing/gui/actionbar/ConfigToolbar.java index 454d2477..fbf39e74 100644 --- a/diylc/diylc-swing/src/org/diylc/swing/gui/actionbar/ConfigToolbar.java +++ b/diylc/diylc-swing/src/org/diylc/swing/gui/actionbar/ConfigToolbar.java @@ -25,6 +25,7 @@ import java.awt.Component; import java.awt.Cursor; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; +import java.util.List; import javax.swing.BorderFactory; import javax.swing.Icon; @@ -75,6 +76,11 @@ public class ConfigToolbar extends JPanel { }); } + public void addToggleLabel(String text, String configKey, String defaultValue, List items) { + ToggleConfigLabel label = new ToggleConfigLabel(text, configKey, defaultValue, items); + add(label); + } + @Override public void setEnabled(boolean enabled) { for (Component c : getComponents()) diff --git a/diylc/diylc-swing/src/org/diylc/swing/gui/actionbar/ToggleConfigLabel.java b/diylc/diylc-swing/src/org/diylc/swing/gui/actionbar/ToggleConfigLabel.java new file mode 100644 index 00000000..350b720a --- /dev/null +++ b/diylc/diylc-swing/src/org/diylc/swing/gui/actionbar/ToggleConfigLabel.java @@ -0,0 +1,85 @@ +/* + + 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.swing.gui.actionbar; + +import java.awt.Cursor; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.util.List; + +import javax.swing.JLabel; +import javax.swing.SwingConstants; + +import org.diylc.appframework.miscutils.ConfigurationManager; +import org.diylc.appframework.miscutils.IConfigListener; +import org.diylc.lang.LangUtil; + +public class ToggleConfigLabel extends JLabel implements IConfigListener { + + private static final long serialVersionUID = 1L; + + private List items; + private String configItem; + private String title; + + private int itemIndex = 0; + + public ToggleConfigLabel(String title, String configKey, String defaultValue, List items) { + super(); + this.title = title; + this.configItem = configKey; + this.items = items; + setHorizontalTextPosition(SwingConstants.LEFT); + setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR)); + + valueChanged(configKey, ConfigurationManager.getInstance().readString(configKey, defaultValue)); + ConfigurationManager.getInstance().addConfigListener(configKey, this); + + addMouseListener(new MouseAdapter() { + @Override + public void mouseClicked(MouseEvent e) { + itemIndex++; + if (itemIndex >= items.size()) + itemIndex = 0; + ConfigurationManager.getInstance().writeValue(configKey, items.get(itemIndex).getConfigValue()); + } + }); + } + + @Override + public void valueChanged(String key, Object value) { + if (!this.configItem.equalsIgnoreCase(key) || value == null) + return; + + this.itemIndex = 0; + for (int i = 0; i < items.size(); i++) { + ToggleItem item = items.get(i); + if (item.getConfigValue().equalsIgnoreCase(value.toString())) + { + this.itemIndex = i; + setIcon(item.getIcon()); + setToolTipText(title + " " + item.getConfigValue() + ". " + LangUtil.translate("Click to toggle to the next option")); + break; + } + } + } +} diff --git a/diylc/diylc-swing/src/org/diylc/swing/gui/actionbar/ToggleItem.java b/diylc/diylc-swing/src/org/diylc/swing/gui/actionbar/ToggleItem.java new file mode 100644 index 00000000..313c1658 --- /dev/null +++ b/diylc/diylc-swing/src/org/diylc/swing/gui/actionbar/ToggleItem.java @@ -0,0 +1,28 @@ +package org.diylc.swing.gui.actionbar; + +import javax.swing.Icon; + +public class ToggleItem { + private String name; + private String configValue; + private Icon icon; + + public ToggleItem(String name, String configValue, Icon icon) { + super(); + this.name = name; + this.configValue = configValue; + this.icon = icon; + } + + public String getName() { + return name; + } + + public String getConfigValue() { + return configValue; + } + + public Icon getIcon() { + return icon; + } +} diff --git a/diylc/diylc-swing/src/org/diylc/swing/images/IconLoader.java b/diylc/diylc-swing/src/org/diylc/swing/images/IconLoader.java index 8f53fba3..8d320b3e 100644 --- a/diylc/diylc-swing/src/org/diylc/swing/images/IconLoader.java +++ b/diylc/diylc-swing/src/org/diylc/swing/images/IconLoader.java @@ -66,7 +66,8 @@ public enum IconLoader { Node("node.png"), Web("web.png"), Guitar("guitar.png"), Scientist("scientist.png"), StarGrey("star_grey.png"), StarBlue("star_blue.png"), JarBeanInto("jar_bean_into.png"), GraphEdgeDirected("graph_edge_directed.png"), LaserPointer("laserpointer.png"), TapeMeasure("tape_measure1.png"), Elements("elements1.png"), GraphNodes("graph_nodes.png"), User("user1.png"), FlexibleLeads("flexible_leads.png"), Pads("pads.png"), Lock("lock.png"), - Unlock("lock_open.png"), Earth("earth.png"), Loadline("loadline.png"), LoadlineAdd("loadline_add.png"); + Unlock("lock_open.png"), Earth("earth.png"), Loadline("loadline.png"), LoadlineAdd("loadline_add.png"), SnapToGrid("snap_to_grid.png"), + SnapToComponents("snap_to_components.png"), SnapToNone("snap_to_none.png"); protected String name; diff --git a/diylc/diylc-swing/src/org/diylc/swing/images/snap_to_components.png b/diylc/diylc-swing/src/org/diylc/swing/images/snap_to_components.png new file mode 100644 index 0000000000000000000000000000000000000000..6d274f3b3d19d589332aa9076a234b43a1509aab GIT binary patch literal 2342 zcmbVO32+lt7)}d?0#of^g(8k_m&0~ovq#b-yEKJ1>4goH5~MO5-R{0^7LshpZkx2A zAc)*|)e1O85O5e;#u3V412 zYhUK)jmV1W{#tj9MiY~hZOw=GSoMnT0>?LRKW5>rnE(`2t|-4oG{^}4kHbWo?s{n3H?xL&C3f+zBMys3qF}q zhoX2G9QXNrTAxlUd5dw9rfHm@aEihp0+Y+!3hT$*a=$hPE08&_=ut$;ji`)lkyN6X zQK&TNg3A-8b<3eJ!GPg@)`OE;LUkzsDJjV!<*Tq7gMHgEPaF4qfMZ%F}ERs|5Lc>s< zuKoKQizUx138E7&$oX06NKS^uK+*;SMrp}_T$_!_amxzp=0J|sjKcV6MUiJ{pl40V zR5GS7A_2yedILraG>HMd4gehwj73JaZNF9GO4KS)_Xit-mpI7rL|zd==!}9OV5Vff z5i<&KU;!s!w82DDI?iO`Krnbv%}B2Zdy;jwXH`}4kdZYS1jt2WEDr}rCSXtpfdS4y z5v)K79A#1~|B2-`mNe*}43jR0IxC$m4$Yim>N7+aK~+4h!w7*ez!p_QK$|$I+@NFi zMzV-!jVZX=RFDD*&Vsb~^X&&poyiteJ!K&kqrud$9wboR49lrqYeqS>Tmg@UUW*-M z>xJSH+V67!Ncx-_4qBHbLGiI(kX8&c`yy?EKTE&NmOfwoi`80C*3;@cXsiFJJ`^0z z!Mck9JP2@9^(T^<8a^!GL-@D>Zb4)B#6WgQ7v-4cb zy_X$yM9%f54VjbP%h)x$`xaC?%#CkO#J*m4{P!w`_DYMw|Ur&$r~pu*H>J(S9LE*8TtE| zbNt}C%6r!u>uP#WFWohMYs`Vl`p7%mJg=H&tX*@tqqQzUsUzf8A6i_rRtL?3kZZSGjL(GcIo3 zUEXa%Gx*z|Ja^8pPDq%zL{9DW~eRV^Hf1M#D s4H(`fzrNhugIe9M&+QqnWGCH^n%mf%H}>=~v-(daCu4-QCcSXhKi#=RivR!s literal 0 HcmV?d00001 diff --git a/diylc/diylc-swing/src/org/diylc/swing/images/snap_to_grid.png b/diylc/diylc-swing/src/org/diylc/swing/images/snap_to_grid.png new file mode 100644 index 0000000000000000000000000000000000000000..93a9df14bc2266097be47b381d4ad612dd2a3526 GIT binary patch literal 2152 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