From 376a7259be6ae5580ea3468baf3d024dec4503a8 Mon Sep 17 00:00:00 2001 From: hneemann Date: Tue, 16 Jul 2019 23:11:36 +0200 Subject: [PATCH 01/12] first working tutorial --- .../de/neemann/digital/core/element/Keys.java | 12 +- .../java/de/neemann/digital/gui/Main.java | 4 + .../java/de/neemann/digital/gui/Settings.java | 1 + .../gui/components/CircuitComponent.java | 33 +++ .../digital/gui/tutorial/InitialTutorial.java | 196 ++++++++++++++++++ .../digital/gui/tutorial/package-info.java | 10 + .../neemann/digital/undo/Modifications.java | 7 + src/main/java/de/neemann/gui/LineBreaker.java | 10 +- src/main/resources/lang/lang_de.xml | 56 +++++ src/main/resources/lang/lang_en.xml | 47 +++++ .../de/neemann/digital/lang/TestLang.java | 2 +- .../java/de/neemann/gui/LineBreakerTest.java | 4 +- 12 files changed, 375 insertions(+), 7 deletions(-) create mode 100644 src/main/java/de/neemann/digital/gui/tutorial/InitialTutorial.java create mode 100644 src/main/java/de/neemann/digital/gui/tutorial/package-info.java diff --git a/src/main/java/de/neemann/digital/core/element/Keys.java b/src/main/java/de/neemann/digital/core/element/Keys.java index ea0c0e10d..d629a7e68 100644 --- a/src/main/java/de/neemann/digital/core/element/Keys.java +++ b/src/main/java/de/neemann/digital/core/element/Keys.java @@ -452,7 +452,7 @@ public final class Keys { * enables the grid */ public static final Key SETTINGS_GRID - = new Key<>("grid", false); + = new Key<>("grid", true); /** * enables the wire bits view @@ -786,6 +786,14 @@ public final class Keys { * Circuit is generic */ public static final Key IS_GENERIC = - new Key("isGeneric", false).setSecondary(); + new Key<>("isGeneric", false).setSecondary(); + + + /** + * Enables the tutorial + */ + public static final Key SETTINGS_SHOW_TUTORIAL = + new Key<>("showTutorial", true).setSecondary(); + } diff --git a/src/main/java/de/neemann/digital/gui/Main.java b/src/main/java/de/neemann/digital/gui/Main.java index 733a74c4d..857efa0a2 100644 --- a/src/main/java/de/neemann/digital/gui/Main.java +++ b/src/main/java/de/neemann/digital/gui/Main.java @@ -43,6 +43,7 @@ import de.neemann.digital.gui.components.testing.TestAllDialog; import de.neemann.digital.gui.components.testing.ValueTableDialog; import de.neemann.digital.gui.components.tree.LibraryTreeModel; import de.neemann.digital.gui.components.tree.SelectTree; +import de.neemann.digital.gui.tutorial.InitialTutorial; import de.neemann.digital.gui.release.CheckForNewRelease; import de.neemann.digital.gui.remote.DigitalHandler; import de.neemann.digital.gui.remote.RemoteException; @@ -1837,6 +1838,9 @@ public final class Main extends JFrame implements ClosingWindowListener.ConfirmS } main.setVisible(true); + if (Settings.getInstance().getAttributes().get(Keys.SETTINGS_SHOW_TUTORIAL)) + new InitialTutorial(main).setVisible(true); + CheckForNewRelease.showReleaseDialog(main); }); } diff --git a/src/main/java/de/neemann/digital/gui/Settings.java b/src/main/java/de/neemann/digital/gui/Settings.java index 28ac9bbb9..5c5576327 100644 --- a/src/main/java/de/neemann/digital/gui/Settings.java +++ b/src/main/java/de/neemann/digital/gui/Settings.java @@ -61,6 +61,7 @@ public final class Settings implements AttributeListener { intList.add(Keys.SETTINGS_TOOLCHAIN_CONFIG); intList.add(Keys.SETTINGS_FONT_SCALING); intList.add(Keys.SETTINGS_MAC_MOUSE); + intList.add(Keys.SETTINGS_SHOW_TUTORIAL); settingsKeys = Collections.unmodifiableList(intList); diff --git a/src/main/java/de/neemann/digital/gui/components/CircuitComponent.java b/src/main/java/de/neemann/digital/gui/components/CircuitComponent.java index 555c74f0e..c06b66ba3 100644 --- a/src/main/java/de/neemann/digital/gui/components/CircuitComponent.java +++ b/src/main/java/de/neemann/digital/gui/components/CircuitComponent.java @@ -133,6 +133,7 @@ public class CircuitComponent extends JComponent implements ChangedListener, Lib private Mouse mouse = Mouse.getMouse(); private Circuit shallowCopy; private CircuitScrollPanel circuitScrollPanel; + private ModificationListener modificationListener; /** @@ -429,6 +430,8 @@ public class CircuitComponent extends JComponent implements ChangedListener, Lib try { if (modification != null) { undoManager.apply(modification); + if (modificationListener != null) + modificationListener.modified(modification); if (circuitScrollPanel != null) circuitScrollPanel.sizeChanged(); } @@ -620,6 +623,16 @@ public class CircuitComponent extends JComponent implements ChangedListener, Lib getCircuit().clearState(); } requestFocusInWindow(); + + if (modificationListener != null) + modificationListener.modified(null); + } + + /** + * @return true if circuit is running + */ + public boolean isRunning() { + return activeMouseController == mouseRun; } /** @@ -2314,6 +2327,15 @@ public class CircuitComponent extends JComponent implements ChangedListener, Lib new MouseControllerWizard(wizardNotification).activate(); } + /** + * Sets the modification listener. + * + * @param modificationListener is called every time the circuit is modified + */ + public void setModificationListener(ModificationListener modificationListener) { + this.modificationListener = modificationListener; + } + /** * Deactivate a wizard */ @@ -2366,4 +2388,15 @@ public class CircuitComponent extends JComponent implements ChangedListener, Lib void closed(); } + /** + * Listener to get notified if the circuit has changed + */ + public interface ModificationListener { + /** + * Called if the circuit was modified + * + * @param modification the modification + */ + void modified(Modification modification); + } } diff --git a/src/main/java/de/neemann/digital/gui/tutorial/InitialTutorial.java b/src/main/java/de/neemann/digital/gui/tutorial/InitialTutorial.java new file mode 100644 index 000000000..1d25ca148 --- /dev/null +++ b/src/main/java/de/neemann/digital/gui/tutorial/InitialTutorial.java @@ -0,0 +1,196 @@ +/* + * Copyright (c) 2019 Helmut Neemann. + * Use of this source code is governed by the GPL v3 license + * that can be found in the LICENSE file. + */ +package de.neemann.digital.gui.tutorial; + +import de.neemann.digital.core.NodeException; +import de.neemann.digital.core.basic.XOr; +import de.neemann.digital.core.element.ElementTypeDescription; +import de.neemann.digital.core.element.Keys; +import de.neemann.digital.core.io.In; +import de.neemann.digital.core.io.Out; +import de.neemann.digital.draw.elements.Circuit; +import de.neemann.digital.draw.elements.PinException; +import de.neemann.digital.draw.elements.VisualElement; +import de.neemann.digital.draw.library.ElementNotFoundException; +import de.neemann.digital.draw.model.ModelCreator; +import de.neemann.digital.gui.Main; +import de.neemann.digital.gui.Settings; +import de.neemann.digital.gui.components.CircuitComponent; +import de.neemann.digital.gui.components.modification.ModifyInsertWire; +import de.neemann.digital.lang.Lang; +import de.neemann.digital.undo.Modification; +import de.neemann.digital.undo.Modifications; +import de.neemann.gui.LineBreaker; +import de.neemann.gui.Screen; + +import javax.swing.*; +import java.awt.*; +import java.awt.event.WindowAdapter; +import java.awt.event.WindowEvent; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.Iterator; + +/** + * The tutorial dialog. + */ +public class InitialTutorial extends JDialog implements CircuitComponent.ModificationListener { + private static final ArrayList STEPS = new ArrayList<>(); + + static { + STEPS.add(new Step("tutorial1", (cc, mod, t) -> contains(cc, In.DESCRIPTION))); + STEPS.add(new Step("tutorial2", (cc, mod, t) -> contains(cc, In.DESCRIPTION, In.DESCRIPTION))); + STEPS.add(new Step("tutorial3", (cc, mod, t) -> contains(cc, In.DESCRIPTION, In.DESCRIPTION, XOr.DESCRIPTION))); + STEPS.add(new Step("tutorial4", (cc, mod, t) -> contains(cc, In.DESCRIPTION, In.DESCRIPTION, XOr.DESCRIPTION, Out.DESCRIPTION))); + STEPS.add(new Step("tutorial5", (cc, mod, t) -> contains(mod, ModifyInsertWire.class))); + STEPS.add(new Step("tutorial6", (cc, mod, t) -> isWorking(cc))); + STEPS.add(new Step("tutorial7", (cc, mod, t) -> cc.isRunning())); + STEPS.add(new Step("tutorial8", (cc, mod, t) -> !cc.isRunning())); + STEPS.add(new Step("tutorial9", (cc, mod, t) -> isIONamed(cc, 1, t))); + STEPS.add(new Step("tutorial10", (cc, mod, t) -> isIONamed(cc, 3, t))); + } + + private static boolean isIONamed(CircuitComponent cc, int expected, InitialTutorial t) { + HashSet set = new HashSet<>(); + int num = 0; + for (VisualElement ve : cc.getCircuit().getElements()) { + if (ve.equalsDescription(In.DESCRIPTION) || ve.equalsDescription(Out.DESCRIPTION)) { + String l = ve.getElementAttributes().getLabel(); + if (!l.isEmpty()) { + if (set.contains(l)) { + t.setTextByID("tutorialUniqueIdents"); + return false; + } + set.add(l); + num++; + } + } + } + return num == expected; + } + + private static boolean isWorking(CircuitComponent cc) { + try { + new ModelCreator(cc.getCircuit(), cc.getLibrary()).createModel(false); + return true; + } catch (PinException | NodeException | ElementNotFoundException e) { + return false; + } + } + + private static boolean contains(Modification mod, Class modifyClass) { + if (mod == null) + return false; + if (mod.getClass() == modifyClass) + return true; + if (mod instanceof Modifications) { + Modifications m = (Modifications) mod; + for (Object i : m.getModifications()) + if (i.getClass() == modifyClass) + return true; + } + return false; + } + + private static boolean contains(CircuitComponent cc, ElementTypeDescription... descriptions) { + ArrayList el = new ArrayList<>(cc.getCircuit().getElements()); + if (el.size() != descriptions.length) + return false; + for (ElementTypeDescription d : descriptions) { + Iterator it = el.iterator(); + while (it.hasNext()) { + if (it.next().equalsDescription(d)) { + it.remove(); + break; + } + } + } + return el.isEmpty(); + } + + + private final JTextPane text; + private final CircuitComponent circuitComponent; + private int stepIndex; + + /** + * Creates the tutorial dialog. + * @param main the main class + */ + public InitialTutorial(Main main) { + super(main, Lang.get("tutorial"), false); + setDefaultCloseOperation(DISPOSE_ON_CLOSE); + setAlwaysOnTop(true); + circuitComponent = main.getCircuitComponent(); + circuitComponent.setModificationListener(this); + + addWindowListener(new WindowAdapter() { + @Override + public void windowClosed(WindowEvent windowEvent) { + circuitComponent.setModificationListener(null); + } + }); + + text = new JTextPane(); + text.setEditable(false); + text.setFont(Screen.getInstance().getFont(1.2f)); + text.setPreferredSize(new Dimension(300, 400)); + + getContentPane().add(new JScrollPane(text)); + + pack(); + + final Point ml = main.getLocation(); + setLocation(ml.x - getWidth(), ml.y); + + stepIndex = -1; + incIndex(); + + } + + private void incIndex() { + stepIndex++; + if (stepIndex == STEPS.size()) { + Settings.getInstance().getAttributes().set(Keys.SETTINGS_SHOW_TUTORIAL, false); + dispose(); + } else { + setTextByID(STEPS.get(stepIndex).getId()); + } + } + + private void setTextByID(String id) { + final String s = Lang.get(id); + text.setText(new LineBreaker(1000).breakLines(s)); + } + + @Override + public void modified(Modification modification) { + if (STEPS.get(stepIndex).getChecker().accomplished(circuitComponent, modification, this)) + incIndex(); + } + + private static final class Step { + private final String id; + private final Checker checker; + + private Step(String id, Checker checker) { + this.id = id; + this.checker = checker; + } + + public String getId() { + return id; + } + + public Checker getChecker() { + return checker; + } + } + + private interface Checker { + boolean accomplished(CircuitComponent circuitComponent, Modification modification, InitialTutorial t); + } +} diff --git a/src/main/java/de/neemann/digital/gui/tutorial/package-info.java b/src/main/java/de/neemann/digital/gui/tutorial/package-info.java new file mode 100644 index 000000000..cc6bdd7cf --- /dev/null +++ b/src/main/java/de/neemann/digital/gui/tutorial/package-info.java @@ -0,0 +1,10 @@ +/* + * Copyright (c) 2019 Helmut Neemann. + * Use of this source code is governed by the GPL v3 license + * that can be found in the LICENSE file. + */ + +/** + * Classes used to show the initial tutorial + */ +package de.neemann.digital.gui.tutorial; diff --git a/src/main/java/de/neemann/digital/undo/Modifications.java b/src/main/java/de/neemann/digital/undo/Modifications.java index 06275a842..9779a5f08 100644 --- a/src/main/java/de/neemann/digital/undo/Modifications.java +++ b/src/main/java/de/neemann/digital/undo/Modifications.java @@ -27,6 +27,13 @@ public final class Modifications> implements Modification< m.modify(a); } + /** + * @return The contained modifications + */ + public ArrayList> getModifications() { + return modifications; + } + @Override public String toString() { return name; diff --git a/src/main/java/de/neemann/gui/LineBreaker.java b/src/main/java/de/neemann/gui/LineBreaker.java index aca30de18..e4c595d0d 100644 --- a/src/main/java/de/neemann/gui/LineBreaker.java +++ b/src/main/java/de/neemann/gui/LineBreaker.java @@ -82,21 +82,27 @@ public class LineBreaker { StringBuilder word = new StringBuilder(); pos = indent; + boolean lastLineBreak=false; for (int i = 0; i < text.length(); i++) { char c = text.charAt(i); switch (c) { case '\n': - if (preserveLineBreaks) { + if (preserveLineBreaks || lastLineBreak) { addWord(word); lineBreak(); - break; + } else { + addWord(word); + lastLineBreak = true; } + break; case '\r': case ' ': addWord(word); + lastLineBreak = false; break; default: word.append(c); + lastLineBreak = false; } } addWord(word); diff --git a/src/main/resources/lang/lang_de.xml b/src/main/resources/lang/lang_de.xml index 50638aced..d30f3f136 100644 --- a/src/main/resources/lang/lang_de.xml +++ b/src/main/resources/lang/lang_de.xml @@ -1348,6 +1348,9 @@ Sind evtl. die Namen der Variablen nicht eindeutig? Schaltung ist generisch Erlaubt die Erzeugung von generischen Schaltungen. + Tutorial beim Start anzeigen + Aktiviert das Tutorial. + Leitung eingefügt. Aus Zwischenablage eingefügt. Wert ''{0}'' in Element ''{1}'' verändert. @@ -1949,4 +1952,57 @@ Daher steht auch das Signal 'D_out' zur Verfügung, um in diesem Fall den Wert z Gibt es aus einem Zustand keinen unbedingten Übergang, bleibt der Automat in diesem Zustand, wenn keine andere Übergangsbedingung erfüllt ist. ]]> + + Tutorial + Im Folgenden werden Sie mit einem kurzen Tutorial zur ersten + Schaltung geführt: + + Fügen Sie einen Eingang in die Schaltung ein. + Sie finden den Eingang im Menu Bauteile▸IO. + Fügen Sie nun einen zweiten Eingang in die Schaltung ein. + Sie können auch auf den Eingang in der Toolbar klicken. + + Setzen Sie den zweiten Eingang am besten mit zwei Gitterabständen unter den ersten Eingang. + Sie können die Schaltung verschieben, wenn Sie die rechte Maustaste gedrückt halten. + Durch klicken auf die Eingänge können Sie diese verschieben. + + Als nächstes soll ein "Exklusiv Oder" Gatter eingefügt werden. + Sie finden dieses Gatter im Menu Bauteile▸Logisch. + Setzen Sie dieses Bauteil mit zwei Gitterabständen rechts neben die Eingänge. + + Als letztes Bauteil soll noch ein Ausgang eingefügt werden. + Setzen Sie diesen mit ebenfalls zwei Gitterabständen rechts neben das "Exklusiv Oder" Gatter. + + Um die Schaltung zu vervollständigen, sind Verbindungsleitungen zu ziehen. + + Klicken Sie auf den roten Punkt am ersten Eingang und verbinden Sie diesen mit einem Eingang + des "Exklusiv Oder" Gatters, indem Sie danach auf einen blauen Punkt des "Exklusiv Oder" + Gatters klicken. + + Verbinden Sie die roten Punkte der Eingänge mit den blauen Punkten des + "Exklusiv Oder" Gatters und den roten Punkt des "Exklusiv Oder" Gatters mit dem blauen Punkte + des Ausgangs. + + Durch Klicken können Sie die Leitung anheften. Rechts-Klick bricht das Zeichnen der Leitung ab. + + Damit ist Ihre erste Schaltung funktionsfähig. + Um die Simulation zu starten, können Sie auf den Play-Knopf in der Toolbar klicken. + + + Die Simulation ist jetzt aktiv. + Jetzt können Sie die Eingänge umschalten indem Sie darauf klicken. + Um die Simulation zu beenden, klicken Sie auf den Stop-Knopf in der Toolbar. + + + Der Vollständigkeit halber sollen die Ein- und Ausgänge benannt werden. + + Durch Rechts-Klick auf einen Ausgang öffnet sich ein Dialog. + Hier kann der Ausgang mit einer Bezeichnung versehen werden. + + + Benennen Sie alle Ein- und Ausgänge. + + + Die Ein- und Ausgänge sollten eindeutig benannt sein. + diff --git a/src/main/resources/lang/lang_en.xml b/src/main/resources/lang/lang_en.xml index 34a904d9a..1a508a6d3 100644 --- a/src/main/resources/lang/lang_en.xml +++ b/src/main/resources/lang/lang_en.xml @@ -1334,6 +1334,9 @@ Circuit is generic Allows to create a generic circuit. + Show Tutorial at Startup + Enables the tutorial. + Inserted wire. Insert from clipboard. Value ''{0}'' in component ''{1}'' modified. @@ -1918,4 +1921,48 @@ Therefore, the signal 'D_out' is also available to check the value in this case. transition condition is met. ]]> + Tutorial + In the following you will be guided to the first circuit with a short tutorial: + + Add an input into the circuit. You will find the input in the menu Components▸IO. + Now add a second input to the circuit. You can also click on the input + in the toolbar. + + It is best to place the second input with two grid spacings under the first input. + You can move the circuit by holding down the right mouse button. + By clicking on the inputs you can move them. + Next, an "Exclusive Or" gate is to be inserted. + You can find this gate in the menu Components▸Logic. + Place this component with two grid spacings to the right of the inputs. + The last component to be inserted is an output. + Set it with two grid spacings to the right of the "Exclusive Or" gate. + + In order to complete the circuit, connecting wires must be drawn. + + Click on the red dot at the first input and connect it to an input of the "Exclusive Or" gate, + by clicking on a blue dot of the "Exclusive Or" gate. + + Connect the red dots of the inputs to the blue dots of the + "Exclusive Or" gate and the red dot of the "Exclusive Or" gate to the blue dot of the output. + + You can pin the wire by clicking. Right-click cancels the drawing of the wire. + + Your first circuit is now functional. + To start the simulation, you can click on the Play button in the toolbar. + + + The simulation is now active. Now you can switch the inputs by clicking on them. + To stop the simulation, click on the Stop button in the toolbar. + + + For completeness, the inputs and outputs should be labeled. + + Right-click on an output to open a dialog. Here the output can be given a name. + + Label all inputs and outputs. + + + The inputs and outputs should be uniquely named. + + \ No newline at end of file diff --git a/src/test/java/de/neemann/digital/lang/TestLang.java b/src/test/java/de/neemann/digital/lang/TestLang.java index 83a567b41..df7dbe76f 100644 --- a/src/test/java/de/neemann/digital/lang/TestLang.java +++ b/src/test/java/de/neemann/digital/lang/TestLang.java @@ -68,7 +68,7 @@ public class TestLang extends TestCase { StringBuilder sb = new StringBuilder(); for (String key : map.keySet()) { if (!keys.contains(key)) { - if (!(key.startsWith("key_") || key.startsWith("elem_"))) { + if (!(key.startsWith("key_") || key.startsWith("elem_") || key.startsWith("tutorial"))) { if (sb.length() > 0) sb.append(", "); sb.append('"').append(key).append('"'); diff --git a/src/test/java/de/neemann/gui/LineBreakerTest.java b/src/test/java/de/neemann/gui/LineBreakerTest.java index 8a727ae6a..adf492bfe 100644 --- a/src/test/java/de/neemann/gui/LineBreakerTest.java +++ b/src/test/java/de/neemann/gui/LineBreakerTest.java @@ -12,8 +12,8 @@ import junit.framework.TestCase; public class LineBreakerTest extends TestCase { public void testBreakLines() throws Exception { - assertEquals("this is a test string", new LineBreaker(60).breakLines("this \n\n is \n a test \n\r string")); - assertEquals("this is a test\nstring", new LineBreaker(14).breakLines("this \n\n is \n a test \n\r string")); + assertEquals("this\nis a test string", new LineBreaker(60).breakLines("this \n\n is \n a test \n\r string")); + assertEquals("this\nis a test\nstring", new LineBreaker(14).breakLines("this \n\n is \n a test \n\r string")); assertEquals("This is a test string. This\n" + "is a test string. This is a\n" + "test string.", new LineBreaker(27).breakLines("This is a test string. This is a test string. This is a test string.")); From 396154cccc17c1cf9297fdf7aa0ccfc4b160c5e0 Mon Sep 17 00:00:00 2001 From: hneemann Date: Wed, 17 Jul 2019 09:00:00 +0200 Subject: [PATCH 02/12] Added a new step to the tutorial. --- .../gui/components/CircuitComponent.java | 29 +++++------- .../digital/gui/tutorial/InitialTutorial.java | 47 +++++++++++++++---- src/main/resources/lang/lang_de.xml | 17 ++++--- src/main/resources/lang/lang_en.xml | 18 ++++--- src/main/resources/lang/lang_es_ref.xml | 2 +- src/main/resources/lang/lang_pt_ref.xml | 2 +- 6 files changed, 74 insertions(+), 41 deletions(-) diff --git a/src/main/java/de/neemann/digital/gui/components/CircuitComponent.java b/src/main/java/de/neemann/digital/gui/components/CircuitComponent.java index c06b66ba3..df06e3ffe 100644 --- a/src/main/java/de/neemann/digital/gui/components/CircuitComponent.java +++ b/src/main/java/de/neemann/digital/gui/components/CircuitComponent.java @@ -133,7 +133,7 @@ public class CircuitComponent extends JComponent implements ChangedListener, Lib private Mouse mouse = Mouse.getMouse(); private Circuit shallowCopy; private CircuitScrollPanel circuitScrollPanel; - private ModificationListener modificationListener; + private TutorialListener tutorialListener; /** @@ -430,8 +430,8 @@ public class CircuitComponent extends JComponent implements ChangedListener, Lib try { if (modification != null) { undoManager.apply(modification); - if (modificationListener != null) - modificationListener.modified(modification); + if (tutorialListener != null) + tutorialListener.modified(modification); if (circuitScrollPanel != null) circuitScrollPanel.sizeChanged(); } @@ -624,15 +624,8 @@ public class CircuitComponent extends JComponent implements ChangedListener, Lib } requestFocusInWindow(); - if (modificationListener != null) - modificationListener.modified(null); - } - - /** - * @return true if circuit is running - */ - public boolean isRunning() { - return activeMouseController == mouseRun; + if (tutorialListener != null) + tutorialListener.modified(null); } /** @@ -1558,7 +1551,7 @@ public class CircuitComponent extends JComponent implements ChangedListener, Lib } private void insertWires(VisualElement element) { - if (element.isAutoWireCompatible()) { + if (element.isAutoWireCompatible() && tutorialListener == null) { Modifications.Builder wires = new Modifications.Builder<>(Lang.get("lib_wires")); for (Pin p : element.getPins()) insertWirePin(p, element.getRotate(), wires); @@ -2302,6 +2295,8 @@ public class CircuitComponent extends JComponent implements ChangedListener, Lib SwingUtilities.convertPointToScreen(p, CircuitComponent.this); boolean modelHasChanged = actor.interact(CircuitComponent.this, p, getPosVector(e), modelSync); if (modelHasChanged) { + if (tutorialListener != null) + tutorialListener.modified(null); modelHasChanged(); } else graphicHasChanged(); @@ -2330,10 +2325,10 @@ public class CircuitComponent extends JComponent implements ChangedListener, Lib /** * Sets the modification listener. * - * @param modificationListener is called every time the circuit is modified + * @param tutorialListener is called every time the circuit is modified */ - public void setModificationListener(ModificationListener modificationListener) { - this.modificationListener = modificationListener; + public void setTutorialListener(TutorialListener tutorialListener) { + this.tutorialListener = tutorialListener; } /** @@ -2391,7 +2386,7 @@ public class CircuitComponent extends JComponent implements ChangedListener, Lib /** * Listener to get notified if the circuit has changed */ - public interface ModificationListener { + public interface TutorialListener { /** * Called if the circuit was modified * diff --git a/src/main/java/de/neemann/digital/gui/tutorial/InitialTutorial.java b/src/main/java/de/neemann/digital/gui/tutorial/InitialTutorial.java index 1d25ca148..47e90d800 100644 --- a/src/main/java/de/neemann/digital/gui/tutorial/InitialTutorial.java +++ b/src/main/java/de/neemann/digital/gui/tutorial/InitialTutorial.java @@ -5,8 +5,9 @@ */ package de.neemann.digital.gui.tutorial; -import de.neemann.digital.core.NodeException; +import de.neemann.digital.core.*; import de.neemann.digital.core.basic.XOr; +import de.neemann.digital.core.element.Element; import de.neemann.digital.core.element.ElementTypeDescription; import de.neemann.digital.core.element.Keys; import de.neemann.digital.core.io.In; @@ -33,11 +34,12 @@ import java.awt.event.WindowEvent; import java.util.ArrayList; import java.util.HashSet; import java.util.Iterator; +import java.util.List; /** * The tutorial dialog. */ -public class InitialTutorial extends JDialog implements CircuitComponent.ModificationListener { +public class InitialTutorial extends JDialog implements CircuitComponent.TutorialListener { private static final ArrayList STEPS = new ArrayList<>(); static { @@ -47,10 +49,37 @@ public class InitialTutorial extends JDialog implements CircuitComponent.Modific STEPS.add(new Step("tutorial4", (cc, mod, t) -> contains(cc, In.DESCRIPTION, In.DESCRIPTION, XOr.DESCRIPTION, Out.DESCRIPTION))); STEPS.add(new Step("tutorial5", (cc, mod, t) -> contains(mod, ModifyInsertWire.class))); STEPS.add(new Step("tutorial6", (cc, mod, t) -> isWorking(cc))); - STEPS.add(new Step("tutorial7", (cc, mod, t) -> cc.isRunning())); - STEPS.add(new Step("tutorial8", (cc, mod, t) -> !cc.isRunning())); - STEPS.add(new Step("tutorial9", (cc, mod, t) -> isIONamed(cc, 1, t))); - STEPS.add(new Step("tutorial10", (cc, mod, t) -> isIONamed(cc, 3, t))); + STEPS.add(new Step("tutorial7", (cc, mod, t) -> t.main.getModel() != null)); + STEPS.add(new Step("tutorial8", (cc, mod, t) -> outputIsHigh(t))); + STEPS.add(new Step("tutorial9", (cc, mod, t) -> t.main.getModel() == null)); + STEPS.add(new Step("tutorial10", (cc, mod, t) -> isIONamed(cc, 1, t))); + STEPS.add(new Step("tutorial11", (cc, mod, t) -> isIONamed(cc, 3, t))); + } + + private final Main main; + + private static boolean outputIsHigh(InitialTutorial t) { + Model model = t.main.getModel(); + if (model == null) + return false; + List nl = model.getNodes(); + if (nl.size() != 1) + return false; + + Node n = nl.get(0); + if (n instanceof Element) { + Element e = (Element) n; + try { + final ObservableValues outputs = e.getOutputs(); + if (outputs.size() != 1) + return false; + else + return outputs.get(0).getValue() != 0; + } catch (PinException ex) { + return false; + } + } else + return false; } private static boolean isIONamed(CircuitComponent cc, int expected, InitialTutorial t) { @@ -118,19 +147,21 @@ public class InitialTutorial extends JDialog implements CircuitComponent.Modific /** * Creates the tutorial dialog. + * * @param main the main class */ public InitialTutorial(Main main) { super(main, Lang.get("tutorial"), false); + this.main = main; setDefaultCloseOperation(DISPOSE_ON_CLOSE); setAlwaysOnTop(true); circuitComponent = main.getCircuitComponent(); - circuitComponent.setModificationListener(this); + circuitComponent.setTutorialListener(this); addWindowListener(new WindowAdapter() { @Override public void windowClosed(WindowEvent windowEvent) { - circuitComponent.setModificationListener(null); + circuitComponent.setTutorialListener(null); } }); diff --git a/src/main/resources/lang/lang_de.xml b/src/main/resources/lang/lang_de.xml index d30f3f136..814af2ff2 100644 --- a/src/main/resources/lang/lang_de.xml +++ b/src/main/resources/lang/lang_de.xml @@ -1957,7 +1957,7 @@ Daher steht auch das Signal 'D_out' zur Verfügung, um in diesem Fall den Wert z Im Folgenden werden Sie mit einem kurzen Tutorial zur ersten Schaltung geführt: - Fügen Sie einen Eingang in die Schaltung ein. + Beginnen Sie, indem Sie einen Eingang in die Schaltung einfügen. Sie finden den Eingang im Menu Bauteile▸IO. Fügen Sie nun einen zweiten Eingang in die Schaltung ein. Sie können auch auf den Eingang in der Toolbar klicken. @@ -1983,7 +1983,8 @@ Daher steht auch das Signal 'D_out' zur Verfügung, um in diesem Fall den Wert z "Exklusiv Oder" Gatters und den roten Punkt des "Exklusiv Oder" Gatters mit dem blauen Punkte des Ausgangs. - Durch Klicken können Sie die Leitung anheften. Rechts-Klick bricht das Zeichnen der Leitung ab. + Während Sie die Leitung zeichnen, können Sie sie durch Klicken auf die Arbeitsfläche anheften. + Rechts-Klick bricht das Zeichnen der Leitung ab (Controll-Klick bei MacOS). Damit ist Ihre erste Schaltung funktionsfähig. Um die Simulation zu starten, können Sie auf den Play-Knopf in der Toolbar klicken. @@ -1991,15 +1992,17 @@ Daher steht auch das Signal 'D_out' zur Verfügung, um in diesem Fall den Wert z Die Simulation ist jetzt aktiv. Jetzt können Sie die Eingänge umschalten indem Sie darauf klicken. - Um die Simulation zu beenden, klicken Sie auf den Stop-Knopf in der Toolbar. - Der Vollständigkeit halber sollen die Ein- und Ausgänge benannt werden. - - Durch Rechts-Klick auf einen Ausgang öffnet sich ein Dialog. - Hier kann der Ausgang mit einer Bezeichnung versehen werden. + Um die Simulation zu beenden, klicken Sie auf den Stop-Knopf in der Toolbar. + Der Vollständigkeit halber sollen die Ein- und Ausgänge benannt werden. + + Durch Rechts-Klick auf einen Einsgang öffnet sich ein Dialog (Unter MacOS wird + Controll-Klick verwendet). Hier kann der Eingang mit einer Bezeichnung versehen werden. + + Benennen Sie alle Ein- und Ausgänge. diff --git a/src/main/resources/lang/lang_en.xml b/src/main/resources/lang/lang_en.xml index 1a508a6d3..8511926dc 100644 --- a/src/main/resources/lang/lang_en.xml +++ b/src/main/resources/lang/lang_en.xml @@ -129,7 +129,7 @@ - Out + Output Can be used to display an output signal in a circuit. This element is also used to connect a circuit to an embedding circuit. In this case the connection is bidirectional. @@ -1924,7 +1924,7 @@ Therefore, the signal 'D_out' is also available to check the value in this case. Tutorial In the following you will be guided to the first circuit with a short tutorial: - Add an input into the circuit. You will find the input in the menu Components▸IO. + First, insert an input into the circuit. You will find the input in the menu Components▸IO. Now add a second input to the circuit. You can also click on the input in the toolbar. @@ -1940,25 +1940,29 @@ Therefore, the signal 'D_out' is also available to check the value in this case. In order to complete the circuit, connecting wires must be drawn. Click on the red dot at the first input and connect it to an input of the "Exclusive Or" gate, - by clicking on a blue dot of the "Exclusive Or" gate. + by clicking on a blue dot of the "Exclusive Or" gate afterwards. Connect the red dots of the inputs to the blue dots of the "Exclusive Or" gate and the red dot of the "Exclusive Or" gate to the blue dot of the output. - You can pin the wire by clicking. Right-click cancels the drawing of the wire. + While drawing, you can pin the wire by clicking somewhere on the canvas. + Right-click cancels the drawing of the wire (control-click on MacOS). Your first circuit is now functional. To start the simulation, you can click on the Play button in the toolbar. The simulation is now active. Now you can switch the inputs by clicking on them. - To stop the simulation, click on the Stop button in the toolbar. + To stop the simulation, click on the Stop button in the toolbar. + + For completeness, the inputs and outputs should be labeled. - Right-click on an output to open a dialog. Here the output can be given a name. - + Right-click on an input to open a dialog. On MacOS control-click is used. + Here the input can be given a name. + Label all inputs and outputs. diff --git a/src/main/resources/lang/lang_es_ref.xml b/src/main/resources/lang/lang_es_ref.xml index ab5317f09..3a99c71f6 100644 --- a/src/main/resources/lang/lang_es_ref.xml +++ b/src/main/resources/lang/lang_es_ref.xml @@ -111,7 +111,7 @@ This component can be used to realize any necessary propagation delay. Input of the signal to be delayed. The input signal delayed by one gate delay time. - Out + Output Can be used to display an output signal in a circuit. This element is also used to connect a circuit to an embedding circuit. In this case the connection is bidirectional. diff --git a/src/main/resources/lang/lang_pt_ref.xml b/src/main/resources/lang/lang_pt_ref.xml index 318b2ee96..d9cc9ae5e 100644 --- a/src/main/resources/lang/lang_pt_ref.xml +++ b/src/main/resources/lang/lang_pt_ref.xml @@ -114,7 +114,7 @@ Input of the signal to be delayed. The input signal delayed by one gate delay time. - Out + Output Can be used to display an output signal in a circuit. This element is also used to connect a circuit to an embedding circuit. In this case the connection is bidirectional. From 736c9323cfc1b51d67b72f3966888061d7c40fa2 Mon Sep 17 00:00:00 2001 From: hneemann Date: Wed, 17 Jul 2019 09:10:58 +0200 Subject: [PATCH 03/12] Added "skip tutorial" button. --- .../digital/gui/tutorial/InitialTutorial.java | 15 +++++++++++++-- src/main/resources/lang/lang_de.xml | 3 +++ src/main/resources/lang/lang_en.xml | 4 +++- 3 files changed, 19 insertions(+), 3 deletions(-) diff --git a/src/main/java/de/neemann/digital/gui/tutorial/InitialTutorial.java b/src/main/java/de/neemann/digital/gui/tutorial/InitialTutorial.java index 47e90d800..2d7579a15 100644 --- a/src/main/java/de/neemann/digital/gui/tutorial/InitialTutorial.java +++ b/src/main/java/de/neemann/digital/gui/tutorial/InitialTutorial.java @@ -29,6 +29,7 @@ import de.neemann.gui.Screen; import javax.swing.*; import java.awt.*; +import java.awt.event.ActionEvent; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import java.util.ArrayList; @@ -171,6 +172,12 @@ public class InitialTutorial extends JDialog implements CircuitComponent.Tutoria text.setPreferredSize(new Dimension(300, 400)); getContentPane().add(new JScrollPane(text)); + getContentPane().add(new JButton(new AbstractAction(Lang.get("tutorialNotNeeded")) { + @Override + public void actionPerformed(ActionEvent actionEvent) { + disableTutorial(); + } + }), BorderLayout.SOUTH); pack(); @@ -182,11 +189,15 @@ public class InitialTutorial extends JDialog implements CircuitComponent.Tutoria } + private void disableTutorial() { + Settings.getInstance().getAttributes().set(Keys.SETTINGS_SHOW_TUTORIAL, false); + dispose(); + } + private void incIndex() { stepIndex++; if (stepIndex == STEPS.size()) { - Settings.getInstance().getAttributes().set(Keys.SETTINGS_SHOW_TUTORIAL, false); - dispose(); + disableTutorial(); } else { setTextByID(STEPS.get(stepIndex).getId()); } diff --git a/src/main/resources/lang/lang_de.xml b/src/main/resources/lang/lang_de.xml index 814af2ff2..1e6907d1a 100644 --- a/src/main/resources/lang/lang_de.xml +++ b/src/main/resources/lang/lang_de.xml @@ -2008,4 +2008,7 @@ Daher steht auch das Signal 'D_out' zur Verfügung, um in diesem Fall den Wert z Die Ein- und Ausgänge sollten eindeutig benannt sein. + + Tutorial überspringen + diff --git a/src/main/resources/lang/lang_en.xml b/src/main/resources/lang/lang_en.xml index 8511926dc..a03b88a2c 100644 --- a/src/main/resources/lang/lang_en.xml +++ b/src/main/resources/lang/lang_en.xml @@ -1968,5 +1968,7 @@ Therefore, the signal 'D_out' is also available to check the value in this case. The inputs and outputs should be uniquely named. - + + Skip Tutorial + \ No newline at end of file From 1c1b3ef6871c7eac6cb946e3e867c44c520abf78 Mon Sep 17 00:00:00 2001 From: hneemann Date: Wed, 17 Jul 2019 09:36:36 +0200 Subject: [PATCH 04/12] Avoid opening a file if tutorial is started. --- .../java/de/neemann/digital/gui/Main.java | 35 +++++++++++++------ src/main/resources/lang/lang_de.xml | 2 +- 2 files changed, 26 insertions(+), 11 deletions(-) diff --git a/src/main/java/de/neemann/digital/gui/Main.java b/src/main/java/de/neemann/digital/gui/Main.java index 857efa0a2..c1c9433c9 100644 --- a/src/main/java/de/neemann/digital/gui/Main.java +++ b/src/main/java/de/neemann/digital/gui/Main.java @@ -182,16 +182,18 @@ public final class Main extends JFrame implements ClosingWindowListener.ConfirmS circuitComponent = new CircuitComponent(this, library, shapeFactory); circuitComponent.addListener(this); - if (builder.circuit != null) { - SwingUtilities.invokeLater(() -> circuitComponent.setCircuit(builder.circuit)); - setFilename(builder.fileToOpen, false); - } else { - if (builder.fileToOpen != null) { - SwingUtilities.invokeLater(() -> loadFile(builder.fileToOpen, builder.library == null, builder.library == null)); + if (!builder.dontOpenFile) { + if (builder.circuit != null) { + SwingUtilities.invokeLater(() -> circuitComponent.setCircuit(builder.circuit)); + setFilename(builder.fileToOpen, false); } else { - File name = fileHistory.getMostRecent(); - if (name != null) { - SwingUtilities.invokeLater(() -> loadFile(name, true, false)); + if (builder.fileToOpen != null) { + SwingUtilities.invokeLater(() -> loadFile(builder.fileToOpen, builder.library == null, builder.library == null)); + } else { + File name = fileHistory.getMostRecent(); + if (name != null) { + SwingUtilities.invokeLater(() -> loadFile(name, true, false)); + } } } } @@ -1830,6 +1832,10 @@ public final class Main extends JFrame implements ClosingWindowListener.ConfirmS if (file != null) builder.setFileToOpen(file); SwingUtilities.invokeLater(() -> { + final boolean tutorial = Settings.getInstance().getAttributes().get(Keys.SETTINGS_SHOW_TUTORIAL); + if (tutorial) + builder.setDontOpenAFile(true); + Main main = builder.build(); try { new RemoteSever(new DigitalHandler(main)).start(41114); @@ -1838,7 +1844,7 @@ public final class Main extends JFrame implements ClosingWindowListener.ConfirmS } main.setVisible(true); - if (Settings.getInstance().getAttributes().get(Keys.SETTINGS_SHOW_TUTORIAL)) + if (tutorial) new InitialTutorial(main).setVisible(true); CheckForNewRelease.showReleaseDialog(main); @@ -1858,6 +1864,7 @@ public final class Main extends JFrame implements ClosingWindowListener.ConfirmS private File baseFileName; private boolean keepPrefMainFile; private boolean mainFrame = false; + private boolean dontOpenFile =false; /** * @param fileToOpen the file to open @@ -1925,6 +1932,14 @@ public final class Main extends JFrame implements ClosingWindowListener.ConfirmS return this; } + /** + * Avoids to open a file + * @param dontOpenFile true if no file should be opened + */ + public void setDontOpenAFile(boolean dontOpenFile) { + this.dontOpenFile = dontOpenFile; + } + /** * Creates a new Main instance * diff --git a/src/main/resources/lang/lang_de.xml b/src/main/resources/lang/lang_de.xml index 1e6907d1a..39ad5142b 100644 --- a/src/main/resources/lang/lang_de.xml +++ b/src/main/resources/lang/lang_de.xml @@ -1999,7 +1999,7 @@ Daher steht auch das Signal 'D_out' zur Verfügung, um in diesem Fall den Wert z Der Vollständigkeit halber sollen die Ein- und Ausgänge benannt werden. - Durch Rechts-Klick auf einen Einsgang öffnet sich ein Dialog (Unter MacOS wird + Durch Rechts-Klick auf einen Eingang öffnet sich ein Dialog (Unter MacOS wird Controll-Klick verwendet). Hier kann der Eingang mit einer Bezeichnung versehen werden. From 098456b8d98a14b7b592f29d28ce83ab160a968b Mon Sep 17 00:00:00 2001 From: hneemann Date: Wed, 17 Jul 2019 09:47:32 +0200 Subject: [PATCH 05/12] typos --- src/main/resources/lang/lang_de.xml | 6 +++--- src/main/resources/lang/lang_en.xml | 1 + 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/main/resources/lang/lang_de.xml b/src/main/resources/lang/lang_de.xml index 39ad5142b..93a88ead8 100644 --- a/src/main/resources/lang/lang_de.xml +++ b/src/main/resources/lang/lang_de.xml @@ -1977,14 +1977,14 @@ Daher steht auch das Signal 'D_out' zur Verfügung, um in diesem Fall den Wert z Klicken Sie auf den roten Punkt am ersten Eingang und verbinden Sie diesen mit einem Eingang des "Exklusiv Oder" Gatters, indem Sie danach auf einen blauen Punkt des "Exklusiv Oder" - Gatters klicken. + Gatters klicken. Die Maustaste NICHT gedrückt halten! Verbinden Sie die roten Punkte der Eingänge mit den blauen Punkten des "Exklusiv Oder" Gatters und den roten Punkt des "Exklusiv Oder" Gatters mit dem blauen Punkte des Ausgangs. Während Sie die Leitung zeichnen, können Sie sie durch Klicken auf die Arbeitsfläche anheften. - Rechts-Klick bricht das Zeichnen der Leitung ab (Controll-Klick bei MacOS). + Rechts-Klick bricht das Zeichnen der Leitung ab (Steuerung-Klick unter MacOS). Damit ist Ihre erste Schaltung funktionsfähig. Um die Simulation zu starten, können Sie auf den Play-Knopf in der Toolbar klicken. @@ -2000,7 +2000,7 @@ Daher steht auch das Signal 'D_out' zur Verfügung, um in diesem Fall den Wert z Der Vollständigkeit halber sollen die Ein- und Ausgänge benannt werden. Durch Rechts-Klick auf einen Eingang öffnet sich ein Dialog (Unter MacOS wird - Controll-Klick verwendet). Hier kann der Eingang mit einer Bezeichnung versehen werden. + Steuerung-Klick verwendet). Hier kann der Eingang mit einer Bezeichnung versehen werden. Benennen Sie alle Ein- und Ausgänge. diff --git a/src/main/resources/lang/lang_en.xml b/src/main/resources/lang/lang_en.xml index a03b88a2c..896963239 100644 --- a/src/main/resources/lang/lang_en.xml +++ b/src/main/resources/lang/lang_en.xml @@ -1941,6 +1941,7 @@ Therefore, the signal 'D_out' is also available to check the value in this case. Click on the red dot at the first input and connect it to an input of the "Exclusive Or" gate, by clicking on a blue dot of the "Exclusive Or" gate afterwards. + Do NOT drag with mouse button down! Connect the red dots of the inputs to the blue dots of the "Exclusive Or" gate and the red dot of the "Exclusive Or" gate to the blue dot of the output. From b1b8cbd2b4598a829805542404ea3cc584fe8deb Mon Sep 17 00:00:00 2001 From: hneemann Date: Wed, 17 Jul 2019 09:51:15 +0200 Subject: [PATCH 06/12] simplified builder again --- .../java/de/neemann/digital/gui/Main.java | 31 ++++++------------- 1 file changed, 10 insertions(+), 21 deletions(-) diff --git a/src/main/java/de/neemann/digital/gui/Main.java b/src/main/java/de/neemann/digital/gui/Main.java index c1c9433c9..d6a01d003 100644 --- a/src/main/java/de/neemann/digital/gui/Main.java +++ b/src/main/java/de/neemann/digital/gui/Main.java @@ -182,18 +182,16 @@ public final class Main extends JFrame implements ClosingWindowListener.ConfirmS circuitComponent = new CircuitComponent(this, library, shapeFactory); circuitComponent.addListener(this); - if (!builder.dontOpenFile) { - if (builder.circuit != null) { - SwingUtilities.invokeLater(() -> circuitComponent.setCircuit(builder.circuit)); - setFilename(builder.fileToOpen, false); + if (builder.circuit != null) { + SwingUtilities.invokeLater(() -> circuitComponent.setCircuit(builder.circuit)); + setFilename(builder.fileToOpen, false); + } else { + if (builder.fileToOpen != null) { + SwingUtilities.invokeLater(() -> loadFile(builder.fileToOpen, builder.library == null, builder.library == null)); } else { - if (builder.fileToOpen != null) { - SwingUtilities.invokeLater(() -> loadFile(builder.fileToOpen, builder.library == null, builder.library == null)); - } else { - File name = fileHistory.getMostRecent(); - if (name != null) { - SwingUtilities.invokeLater(() -> loadFile(name, true, false)); - } + File name = fileHistory.getMostRecent(); + if (name != null) { + SwingUtilities.invokeLater(() -> loadFile(name, true, false)); } } } @@ -1834,7 +1832,7 @@ public final class Main extends JFrame implements ClosingWindowListener.ConfirmS SwingUtilities.invokeLater(() -> { final boolean tutorial = Settings.getInstance().getAttributes().get(Keys.SETTINGS_SHOW_TUTORIAL); if (tutorial) - builder.setDontOpenAFile(true); + builder.setCircuit(new Circuit()); Main main = builder.build(); try { @@ -1864,7 +1862,6 @@ public final class Main extends JFrame implements ClosingWindowListener.ConfirmS private File baseFileName; private boolean keepPrefMainFile; private boolean mainFrame = false; - private boolean dontOpenFile =false; /** * @param fileToOpen the file to open @@ -1932,14 +1929,6 @@ public final class Main extends JFrame implements ClosingWindowListener.ConfirmS return this; } - /** - * Avoids to open a file - * @param dontOpenFile true if no file should be opened - */ - public void setDontOpenAFile(boolean dontOpenFile) { - this.dontOpenFile = dontOpenFile; - } - /** * Creates a new Main instance * From 6920097a90db88d919016eb16bcb7426c2c56dad Mon Sep 17 00:00:00 2001 From: hneemann Date: Wed, 17 Jul 2019 15:35:46 +0200 Subject: [PATCH 07/12] typos --- src/main/resources/lang/lang_de.xml | 23 ++++++++++++----------- src/main/resources/lang/lang_en.xml | 15 ++++++++------- 2 files changed, 20 insertions(+), 18 deletions(-) diff --git a/src/main/resources/lang/lang_de.xml b/src/main/resources/lang/lang_de.xml index 93a88ead8..306b72c4c 100644 --- a/src/main/resources/lang/lang_de.xml +++ b/src/main/resources/lang/lang_de.xml @@ -1954,24 +1954,24 @@ Daher steht auch das Signal 'D_out' zur Verfügung, um in diesem Fall den Wert z ]]> Tutorial - Im Folgenden werden Sie mit einem kurzen Tutorial zur ersten - Schaltung geführt: + Im Folgenden führt Sie ein kurzes Tutorial zur ersten, + einfachen Schaltung: Beginnen Sie, indem Sie einen Eingang in die Schaltung einfügen. Sie finden den Eingang im Menu Bauteile▸IO. Fügen Sie nun einen zweiten Eingang in die Schaltung ein. Sie können auch auf den Eingang in der Toolbar klicken. - Setzen Sie den zweiten Eingang am besten mit zwei Gitterabständen unter den ersten Eingang. + Setzen Sie den zweiten Eingang am besten mit etwas Abstand unter den ersten Eingang. Sie können die Schaltung verschieben, wenn Sie die rechte Maustaste gedrückt halten. - Durch klicken auf die Eingänge können Sie diese verschieben. + Durch klicken auf Bauteile können Sie diese verschieben. Als nächstes soll ein "Exklusiv Oder" Gatter eingefügt werden. Sie finden dieses Gatter im Menu Bauteile▸Logisch. - Setzen Sie dieses Bauteil mit zwei Gitterabständen rechts neben die Eingänge. + Setzen Sie dieses Bauteil mit etwas Abstand rechts neben die Eingänge. Als letztes Bauteil soll noch ein Ausgang eingefügt werden. - Setzen Sie diesen mit ebenfalls zwei Gitterabständen rechts neben das "Exklusiv Oder" Gatter. + Place it with some distance to the right of the "Exclusive Or" gate. Um die Schaltung zu vervollständigen, sind Verbindungsleitungen zu ziehen. @@ -1979,19 +1979,20 @@ Daher steht auch das Signal 'D_out' zur Verfügung, um in diesem Fall den Wert z des "Exklusiv Oder" Gatters, indem Sie danach auf einen blauen Punkt des "Exklusiv Oder" Gatters klicken. Die Maustaste NICHT gedrückt halten! - Verbinden Sie die roten Punkte der Eingänge mit den blauen Punkten des - "Exklusiv Oder" Gatters und den roten Punkt des "Exklusiv Oder" Gatters mit dem blauen Punkte - des Ausgangs. + Verbinden Sie den roten Punkt des zweiten Eingangs mit den zweiten blauen + Punkten des "Exklusiv Oder" Gatters und den roten Punkt des "Exklusiv Oder" Gatters mit dem + blauen Punkt des Ausgangs. Während Sie die Leitung zeichnen, können Sie sie durch Klicken auf die Arbeitsfläche anheften. Rechts-Klick bricht das Zeichnen der Leitung ab (Steuerung-Klick unter MacOS). Damit ist Ihre erste Schaltung funktionsfähig. Um die Simulation zu starten, können Sie auf den Play-Knopf in der Toolbar klicken. + Wenn Sie mit der Maus über die Toolbar fahren, werden Tool-Tipps angezeigt. Die Simulation ist jetzt aktiv. - Jetzt können Sie die Eingänge umschalten indem Sie darauf klicken. + Schalten Sie die Eingänge um, indem Sie darauf klicken. Um die Simulation zu beenden, klicken Sie auf den Stop-Knopf in der Toolbar. @@ -2006,7 +2007,7 @@ Daher steht auch das Signal 'D_out' zur Verfügung, um in diesem Fall den Wert z Benennen Sie alle Ein- und Ausgänge. - Die Ein- und Ausgänge sollten eindeutig benannt sein. + Ein- und Ausgänge sollten stets eindeutig benannt sein. Tutorial überspringen diff --git a/src/main/resources/lang/lang_en.xml b/src/main/resources/lang/lang_en.xml index 896963239..dc1980ae5 100644 --- a/src/main/resources/lang/lang_en.xml +++ b/src/main/resources/lang/lang_en.xml @@ -1922,18 +1922,18 @@ Therefore, the signal 'D_out' is also available to check the value in this case. ]]> Tutorial - In the following you will be guided to the first circuit with a short tutorial: + In the following a short tutorial leads you to the first, simple circuit: First, insert an input into the circuit. You will find the input in the menu Components▸IO. Now add a second input to the circuit. You can also click on the input in the toolbar. - It is best to place the second input with two grid spacings under the first input. + It is best to place the second input slightly below the first input. You can move the circuit by holding down the right mouse button. - By clicking on the inputs you can move them. + By clicking on components you can move them. Next, an "Exclusive Or" gate is to be inserted. You can find this gate in the menu Components▸Logic. - Place this component with two grid spacings to the right of the inputs. + Place this component with some distance to the right of the inputs. The last component to be inserted is an output. Set it with two grid spacings to the right of the "Exclusive Or" gate. @@ -1943,7 +1943,7 @@ Therefore, the signal 'D_out' is also available to check the value in this case. by clicking on a blue dot of the "Exclusive Or" gate afterwards. Do NOT drag with mouse button down! - Connect the red dots of the inputs to the blue dots of the + Connect the red dot of the second input to the second blue dot of the "Exclusive Or" gate and the red dot of the "Exclusive Or" gate to the blue dot of the output. While drawing, you can pin the wire by clicking somewhere on the canvas. @@ -1951,9 +1951,10 @@ Therefore, the signal 'D_out' is also available to check the value in this case. Your first circuit is now functional. To start the simulation, you can click on the Play button in the toolbar. + If you move the mouse over the toolbar, tool tips are shown. - The simulation is now active. Now you can switch the inputs by clicking on them. + The simulation is now active. Switch the inputs by clicking on them. To stop the simulation, click on the Stop button in the toolbar. @@ -1967,7 +1968,7 @@ Therefore, the signal 'D_out' is also available to check the value in this case. Label all inputs and outputs. - The inputs and outputs should be uniquely named. + Inputs and outputs should always be uniquely named. Skip Tutorial From a2b629281fed12ea24e010841263352098760bc0 Mon Sep 17 00:00:00 2001 From: hneemann Date: Sat, 20 Jul 2019 15:14:46 +0200 Subject: [PATCH 08/12] LineBreaker is able to deal with tabs --- src/main/java/de/neemann/gui/LineBreaker.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/de/neemann/gui/LineBreaker.java b/src/main/java/de/neemann/gui/LineBreaker.java index e4c595d0d..9ed1cd413 100644 --- a/src/main/java/de/neemann/gui/LineBreaker.java +++ b/src/main/java/de/neemann/gui/LineBreaker.java @@ -96,6 +96,7 @@ public class LineBreaker { } break; case '\r': + case '\t': case ' ': addWord(word); lastLineBreak = false; From 4f17f1aedf575af78ae683b0e69fac4b0b24f014 Mon Sep 17 00:00:00 2001 From: hneemann Date: Sat, 20 Jul 2019 15:16:43 +0200 Subject: [PATCH 09/12] updated spanish translation --- src/main/resources/lang/lang_es.xml | 48 +++++++++++++++++++++++ src/main/resources/lang/lang_es_ref.xml | 52 +++++++++++++++++++++++++ 2 files changed, 100 insertions(+) diff --git a/src/main/resources/lang/lang_es.xml b/src/main/resources/lang/lang_es.xml index 587253675..62372e7ce 100644 --- a/src/main/resources/lang/lang_es.xml +++ b/src/main/resources/lang/lang_es.xml @@ -1723,4 +1723,52 @@ Por tanto, la señal 'D_out' estará también disponible para chequear el valor Error al leer la configuración de la toolchain {0} ¡El comando "{0}" ha empezado! ¡El procesado puede llevar un tiempo! ¡El comando "{0}" ha sido completado! + Hay una entrada o una salida sin nombre + La señal "{0}" no es válida o se ha usado varias veces + Error al sustituir componentes para el análisis. + Error en la evaluación del código genérico del circuito. Código {1} en el Componente: {0} + Error al analizar código genérico + Parametrización genérica + Declaraciones hechas para generar un circuito + El circuito es genérico + Permite crear un circuito genérico + Muestra el tutorial en el arranque + Habilita el tutorial + Entradas + Bits + Bits de dirección + Tutorial + A continuación, podrás diseñar tu primer circuito tras un breve tutorial: + + Primero, pon una entrada en el circuito. Encontrarás las entradas en el menú Componentes▸Entrada-Salida + Ahora, añade una segunda entrada al circuito. También puedes hacer clic sobre la entrada que ha aparecido en la barra de herramientas. + + Es mejor colocar la segunda entrada a dos espacios de rejilla debajo de la primera. + Puedes mover el circuito presionando el botón derecho del ratón. + Haciendo clic sobre las entradas puedes moverlas. + A continuación vamos a insertar una puerta "OR Exclusiva". + Puedes encontrarla en el menú Componentes▸Lógica. + Coloca el componente a dos espacios de rejilla a la derecha de las entradas. + El último componente que vamos a insertar es una salida. + Colócala a dos espacios de rejilla a la derecha de la puerta "OR Exclusiva". + Para completar el circuito hay que dibujar los cables. + + Haz clic en el punto rojo de la primera entrada y conecta el cable que aparece a una entrada de la puerta "OR Exclusiva" + haciendo clic en uno de los puntos azules de dicha puerta. + ¡NO pinches y arrastres con el botón del ratón! + Conecta los puntos rojos de las entradas con los puntos azules de la puerta "OR Exclusiva" + y el punto rojo de dicha puerta con el punto azul de la salida. + Así de fácil: un punto rojo va a un punto azul. + Tu primer circuito ya funcionará. + Para empezar la simulación, puedes hacer clic en el botón "Simular" de la barra de herramientas. + La simulación ya está activa. Ahora puedes cambiar los valores de las entradas haciendo clic en ellas. + Para terminar la simulación, haz clic en el botón "Stop" de la barra de herramientas. + Para que todo quede perfecto, tendrías que poner etiquetas a las entradas y salidas. + + Haz clic con el botón derecho en una entrada para abrir un cuadro de diálogo. + En MacOS puedes usar el control-clic. + Así podrás nombrar la entrada. + Etiqueta todas las entradas y salidas. + Los nombres de las entradas y salidas deben ser únicos. + Saltar el tutorial diff --git a/src/main/resources/lang/lang_es_ref.xml b/src/main/resources/lang/lang_es_ref.xml index 3a99c71f6..bea37a0a2 100644 --- a/src/main/resources/lang/lang_es_ref.xml +++ b/src/main/resources/lang/lang_es_ref.xml @@ -1739,4 +1739,56 @@ Therefore, the signal 'D_out' is also available to check the value in this case. Error while reading the toolchain configuration {0} Command "{0}" has been started! Processing may take some time! The command "{0}" has been completed! + There is a unnamed input or output! + The signal name "{0}" is invalid or used multiple times! + Error when substituting components for the analysis. + Error in the evaluation of the generic code of the circuit. Code + {1} + at Component: {0} + Error while parsing generics code. + Generic Parameterization + Statements used to generify a circuit. + Circuit is generic + Allows to create a generic circuit. + Show Tutorial at Startup + Enables the tutorial. + Inputs + Bits + Addr. Bits + Tutorial + In the following you will be guided to the first circuit with a short tutorial: + + First, insert an input into the circuit. You will find the input in the menu Components▸IO. + Now add a second input to the circuit. You can also click on the input + in the toolbar. + + It is best to place the second input with two grid spacings under the first input. + You can move the circuit by holding down the right mouse button. + By clicking on the inputs you can move them. + Next, an "Exclusive Or" gate is to be inserted. + You can find this gate in the menu Components▸Logic. + Place this component with two grid spacings to the right of the inputs. + The last component to be inserted is an output. + Set it with two grid spacings to the right of the "Exclusive Or" gate. + In order to complete the circuit, connecting wires must be drawn. + + Click on the red dot at the first input and connect it to an input of the "Exclusive Or" gate, + by clicking on a blue dot of the "Exclusive Or" gate afterwards. + Do NOT drag with mouse button down! + Connect the red dots of the inputs to the blue dots of the + "Exclusive Or" gate and the red dot of the "Exclusive Or" gate to the blue dot of the output. + + While drawing, you can pin the wire by clicking somewhere on the canvas. + Right-click cancels the drawing of the wire (control-click on MacOS). + Your first circuit is now functional. + To start the simulation, you can click on the Play button in the toolbar. + The simulation is now active. Now you can switch the inputs by clicking on them. + To stop the simulation, click on the Stop button in the toolbar. + For completeness, the inputs and outputs should be labeled. + + Right-click on an input to open a dialog. On MacOS control-click is used. + Here the input can be given a name. + Label all inputs and outputs. + The inputs and outputs should be uniquely named. + Skip Tutorial From 28621493364264ecd69eec22724ce7e57476bb61 Mon Sep 17 00:00:00 2001 From: hneemann Date: Sun, 21 Jul 2019 08:26:34 +0200 Subject: [PATCH 10/12] updated spanish translation --- src/main/resources/lang/lang_es.xml | 11 ++++++--- src/main/resources/lang/lang_es_ref.xml | 30 +++++++++++++++---------- 2 files changed, 26 insertions(+), 15 deletions(-) diff --git a/src/main/resources/lang/lang_es.xml b/src/main/resources/lang/lang_es.xml index 62372e7ce..f91653fe0 100644 --- a/src/main/resources/lang/lang_es.xml +++ b/src/main/resources/lang/lang_es.xml @@ -241,7 +241,8 @@ Divisor Divide o crea un haz de cables o un bus de datos con más de un bit. Con un bus es posible, por ejemplo, generar conexiones de 16 bits sin tener que generar 16 cables individuales. - Las 16 conexiones pueden agruparse en un cable. + Las 16 conexiones pueden agruparse en un cable. + El divisor tiene una dirección, es decir, sólo puede transmitir señales en una dirección. Los bits de entrada {0} El bit de entrada {0} Los bits de salida {0} @@ -716,7 +717,8 @@ Se necesita un componente de reloj. Todos los flip-flops deben usar una señal de reloj. Este circuito no tiene entradas etiquetadas. Este circuito no tiene salidas etiquetadas. - Después de {0} ciclos, no se produjo ninguna interrupción en el punto de interrupción ''{1}''. + Después de {0} ciclos, no se produjo ninguna interrupción en el punto de interrupción ''{1}''. + Posiblemente el número de ciclos de tiempo muerto en el componente de interrupción deberían incrementarse. Expresión {0} no soportada. Operación {0} no soportada. Error creando la tabla de consulta (LUT). @@ -1257,7 +1259,7 @@ Guardar los datos en archivo CSV Test de velocidad Hace un test de velocidad calculando la frecuencia de reloj máxima. - Paso + Paso de puerta Calcula un paso de puerta simple Sintetizar Genera la expresión booleana mínima a partir de una tabla de verdad. @@ -1771,4 +1773,7 @@ Por tanto, la señal 'D_out' estará también disponible para chequear el valor Etiqueta todas las entradas y salidas. Los nombres de las entradas y salidas deben ser únicos. Saltar el tutorial + Ejecutar hasta parar en modo de puerta simple. + Ejecuta todos los pasos de puerta sencillos hasta que se detecta un flanco de subida en un componente de parada. + Si no hay componente de parada, se ejecutan los pasos de puerta simple restantes. diff --git a/src/main/resources/lang/lang_es_ref.xml b/src/main/resources/lang/lang_es_ref.xml index bea37a0a2..275783110 100644 --- a/src/main/resources/lang/lang_es_ref.xml +++ b/src/main/resources/lang/lang_es_ref.xml @@ -246,7 +246,8 @@ Splitter Splits or creates a wire bundle or a data bus with more than one bit. With a bus it is e.g. possible to generate 16-bit connections without having to route 16 individual wires. - All 16 connections can be merged into one wire. + All 16 connections can be merged into one wire. + The splitter has a direction, meaning it can only transmit signals in one direction. The input bits {0}. The input bit {0}. The output bits {0}. @@ -725,7 +726,8 @@ A single clock component is necessary. All flip-flops must use this clock signal. The circuit has no labeled inputs The circuit has no labeled outputs - No break detected after {0} cycles at break point ''{1}''. + No break detected after {0} cycles at break point ''{1}''. + Possibly the number of timout cycles in the break component should be increased. Expression {0} not supported Operation {0} not supported Error creating the lookup table. @@ -1270,8 +1272,8 @@ Save data as CSV file Speed Test Performs a speed test by calculating the max. clock frequency. - Step - Calculating a single gate step + Gate Step + Calculates a single gate step Synthesise Generates the minimal bool expressions described by a truth table. {0} variables @@ -1756,18 +1758,18 @@ Therefore, the signal 'D_out' is also available to check the value in this case. Bits Addr. Bits Tutorial - In the following you will be guided to the first circuit with a short tutorial: + In the following a short tutorial leads you to the first, simple circuit: First, insert an input into the circuit. You will find the input in the menu Components▸IO. Now add a second input to the circuit. You can also click on the input in the toolbar. - It is best to place the second input with two grid spacings under the first input. + It is best to place the second input slightly below the first input. You can move the circuit by holding down the right mouse button. - By clicking on the inputs you can move them. + By clicking on components you can move them. Next, an "Exclusive Or" gate is to be inserted. You can find this gate in the menu Components▸Logic. - Place this component with two grid spacings to the right of the inputs. + Place this component with some distance to the right of the inputs. The last component to be inserted is an output. Set it with two grid spacings to the right of the "Exclusive Or" gate. In order to complete the circuit, connecting wires must be drawn. @@ -1775,20 +1777,24 @@ Therefore, the signal 'D_out' is also available to check the value in this case. Click on the red dot at the first input and connect it to an input of the "Exclusive Or" gate, by clicking on a blue dot of the "Exclusive Or" gate afterwards. Do NOT drag with mouse button down! - Connect the red dots of the inputs to the blue dots of the + Connect the red dot of the second input to the second blue dot of the "Exclusive Or" gate and the red dot of the "Exclusive Or" gate to the blue dot of the output. While drawing, you can pin the wire by clicking somewhere on the canvas. Right-click cancels the drawing of the wire (control-click on MacOS). Your first circuit is now functional. - To start the simulation, you can click on the Play button in the toolbar. - The simulation is now active. Now you can switch the inputs by clicking on them. + To start the simulation, you can click on the Play button in the toolbar. + If you move the mouse over the toolbar, tool tips are shown. + The simulation is now active. Switch the inputs by clicking on them. To stop the simulation, click on the Stop button in the toolbar. For completeness, the inputs and outputs should be labeled. Right-click on an input to open a dialog. On MacOS control-click is used. Here the input can be given a name. Label all inputs and outputs. - The inputs and outputs should be uniquely named. + Inputs and outputs should always be uniquely named. Skip Tutorial + Run To Break in Single Gate Mode + Executes all single gate steps until a rising edge is detected on a break component. + If there is no break component, the remaining single gate steps are executed. From 77d81c5d8fb56bacaccb8cb4695a2b31324a567e Mon Sep 17 00:00:00 2001 From: hneemann Date: Sun, 21 Jul 2019 16:42:25 +0200 Subject: [PATCH 11/12] fixed a bug in the german language file --- src/main/resources/lang/lang_de.xml | 2 +- src/main/resources/lang/lang_en.xml | 2 +- src/main/resources/lang/lang_es_ref.xml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/resources/lang/lang_de.xml b/src/main/resources/lang/lang_de.xml index 1255a5905..27c5573c9 100644 --- a/src/main/resources/lang/lang_de.xml +++ b/src/main/resources/lang/lang_de.xml @@ -1975,7 +1975,7 @@ Daher steht auch das Signal 'D_out' zur Verfügung, um in diesem Fall den Wert z Setzen Sie dieses Bauteil mit etwas Abstand rechts neben die Eingänge. Als letztes Bauteil soll noch ein Ausgang eingefügt werden. - Place it with some distance to the right of the "Exclusive Or" gate. + Platzieren Sie den Ausgang etwas rechts des "Exklusiv Oder" Gatters. Um die Schaltung zu vervollständigen, sind Verbindungsleitungen zu ziehen. diff --git a/src/main/resources/lang/lang_en.xml b/src/main/resources/lang/lang_en.xml index f61448339..4a99c25dd 100644 --- a/src/main/resources/lang/lang_en.xml +++ b/src/main/resources/lang/lang_en.xml @@ -1939,7 +1939,7 @@ Therefore, the signal 'D_out' is also available to check the value in this case. You can find this gate in the menu Components▸Logic. Place this component with some distance to the right of the inputs. The last component to be inserted is an output. - Set it with two grid spacings to the right of the "Exclusive Or" gate. + Place it with some distance to the right of the "Exclusive Or" gate. In order to complete the circuit, connecting wires must be drawn. diff --git a/src/main/resources/lang/lang_es_ref.xml b/src/main/resources/lang/lang_es_ref.xml index 275783110..48f4d8a59 100644 --- a/src/main/resources/lang/lang_es_ref.xml +++ b/src/main/resources/lang/lang_es_ref.xml @@ -1771,7 +1771,7 @@ Therefore, the signal 'D_out' is also available to check the value in this case. You can find this gate in the menu Components▸Logic. Place this component with some distance to the right of the inputs. The last component to be inserted is an output. - Set it with two grid spacings to the right of the "Exclusive Or" gate. + Place it with some distance to the right of the "Exclusive Or" gate. In order to complete the circuit, connecting wires must be drawn. Click on the red dot at the first input and connect it to an input of the "Exclusive Or" gate, From 344ef6df1f52d29e66dc6e04b81adb355790c952 Mon Sep 17 00:00:00 2001 From: hneemann Date: Tue, 23 Jul 2019 09:24:15 +0200 Subject: [PATCH 12/12] removes the tutorial setting from the settings dialog --- src/main/java/de/neemann/digital/gui/Settings.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/java/de/neemann/digital/gui/Settings.java b/src/main/java/de/neemann/digital/gui/Settings.java index 5c5576327..28ac9bbb9 100644 --- a/src/main/java/de/neemann/digital/gui/Settings.java +++ b/src/main/java/de/neemann/digital/gui/Settings.java @@ -61,7 +61,6 @@ public final class Settings implements AttributeListener { intList.add(Keys.SETTINGS_TOOLCHAIN_CONFIG); intList.add(Keys.SETTINGS_FONT_SCALING); intList.add(Keys.SETTINGS_MAC_MOUSE); - intList.add(Keys.SETTINGS_SHOW_TUTORIAL); settingsKeys = Collections.unmodifiableList(intList);