digsim-logic-simulator 0.3.0__py3-none-any.whl → 0.5.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of digsim-logic-simulator might be problematic. Click here for more details.

Files changed (72) hide show
  1. digsim/__init__.py +1 -1
  2. digsim/app/__main__.py +1 -1
  3. digsim/app/gui/__init__.py +1 -1
  4. digsim/app/gui/_circuit_area.py +1 -6
  5. digsim/app/gui/_component_selection.py +1 -3
  6. digsim/app/gui/_main_window.py +1 -3
  7. digsim/app/gui/_top_bar.py +1 -4
  8. digsim/app/gui/_warning_dialog.py +1 -3
  9. digsim/app/gui_objects/__init__.py +1 -1
  10. digsim/app/gui_objects/_bus_bit_object.py +2 -5
  11. digsim/app/gui_objects/_buzzer_object.py +1 -1
  12. digsim/app/gui_objects/_component_context_menu.py +2 -2
  13. digsim/app/gui_objects/_component_object.py +8 -10
  14. digsim/app/gui_objects/_component_port_item.py +1 -1
  15. digsim/app/gui_objects/_dip_switch_object.py +2 -5
  16. digsim/app/gui_objects/_gui_note_object.py +1 -1
  17. digsim/app/gui_objects/_gui_object_factory.py +1 -1
  18. digsim/app/gui_objects/_hexdigit_object.py +1 -1
  19. digsim/app/gui_objects/_image_objects.py +2 -4
  20. digsim/app/gui_objects/_label_object.py +1 -1
  21. digsim/app/gui_objects/_logic_analyzer_object.py +1 -2
  22. digsim/app/gui_objects/_seven_segment_object.py +2 -4
  23. digsim/app/gui_objects/_shortcut_objects.py +2 -4
  24. digsim/app/gui_objects/_yosys_object.py +1 -1
  25. digsim/app/model/__init__.py +1 -1
  26. digsim/app/model/_model.py +15 -18
  27. digsim/app/model/_model_components.py +12 -15
  28. digsim/app/model/_model_objects.py +30 -26
  29. digsim/app/model/_model_settings.py +1 -5
  30. digsim/app/model/_model_shortcuts.py +3 -3
  31. digsim/app/settings/__init__.py +1 -1
  32. digsim/app/settings/_component_settings.py +5 -7
  33. digsim/app/settings/_gui_settings.py +1 -3
  34. digsim/app/settings/_shortcut_dialog.py +1 -3
  35. digsim/circuit/__init__.py +1 -1
  36. digsim/circuit/_circuit.py +21 -64
  37. digsim/circuit/_waves_writer.py +1 -4
  38. digsim/circuit/components/__init__.py +1 -1
  39. digsim/circuit/components/_bus_bits.py +2 -2
  40. digsim/circuit/components/_button.py +1 -1
  41. digsim/circuit/components/_buzzer.py +2 -2
  42. digsim/circuit/components/_clock.py +2 -2
  43. digsim/circuit/components/_dip_switch.py +2 -2
  44. digsim/circuit/components/_gates.py +7 -9
  45. digsim/circuit/components/_hexdigit.py +3 -3
  46. digsim/circuit/components/_ic.py +1 -0
  47. digsim/circuit/components/_label_wire.py +4 -4
  48. digsim/circuit/components/_led.py +1 -1
  49. digsim/circuit/components/_logic_analyzer.py +2 -2
  50. digsim/circuit/components/_note.py +1 -1
  51. digsim/circuit/components/_on_off_switch.py +1 -1
  52. digsim/circuit/components/_seven_segment.py +2 -1
  53. digsim/circuit/components/_static_level.py +1 -1
  54. digsim/circuit/components/_static_value.py +2 -2
  55. digsim/circuit/components/_yosys_atoms.py +1 -6
  56. digsim/circuit/components/_yosys_component.py +1 -4
  57. digsim/circuit/components/atoms/__init__.py +1 -1
  58. digsim/circuit/components/atoms/_component.py +2 -44
  59. digsim/circuit/components/atoms/_port.py +7 -18
  60. digsim/storage_model/__init__.py +7 -0
  61. digsim/storage_model/_app.py +53 -0
  62. digsim/storage_model/_circuit.py +118 -0
  63. digsim/synth/__init__.py +1 -1
  64. digsim/synth/__main__.py +1 -1
  65. digsim/synth/_synthesis.py +10 -2
  66. digsim/utils/__init__.py +1 -1
  67. {digsim_logic_simulator-0.3.0.dist-info → digsim_logic_simulator-0.5.0.dist-info}/METADATA +12 -7
  68. digsim_logic_simulator-0.5.0.dist-info/RECORD +105 -0
  69. {digsim_logic_simulator-0.3.0.dist-info → digsim_logic_simulator-0.5.0.dist-info}/WHEEL +1 -1
  70. digsim_logic_simulator-0.3.0.dist-info/RECORD +0 -102
  71. {digsim_logic_simulator-0.3.0.dist-info → digsim_logic_simulator-0.5.0.dist-info}/LICENSE.md +0 -0
  72. {digsim_logic_simulator-0.3.0.dist-info → digsim_logic_simulator-0.5.0.dist-info}/top_level.txt +0 -0
digsim/__init__.py CHANGED
@@ -1,6 +1,6 @@
1
1
  # Copyright (c) Fredrik Andersson, 2023
2
2
  # All rights reserved
3
3
 
4
- """ All classes within digsim namespace """
4
+ """All classes within digsim namespace"""
5
5
 
6
6
  from .circuit import Circuit # noqa: F401
digsim/app/__main__.py CHANGED
@@ -1,7 +1,7 @@
1
1
  # Copyright (c) Fredrik Andersson, 2023
2
2
  # All rights reserved
3
3
 
4
- """ The main class module of the digsim.app namespace """
4
+ """The main class module of the digsim.app namespace"""
5
5
 
6
6
  import argparse
7
7
  import sys
@@ -1,6 +1,6 @@
1
1
  # Copyright (c) Fredrik Andersson, 2023
2
2
  # All rights reserved
3
3
 
4
- """ All classes within digsim.app.gui namespace """
4
+ """All classes within digsim.app.gui namespace"""
5
5
 
6
6
  from ._main_window import MainWindow # noqa: F401
@@ -1,12 +1,8 @@
1
- # Copyright (c) Fredrik Andersson, 2023
1
+ # Copyright (c) Fredrik Andersson, 2023-2024
2
2
  # All rights reserved
3
3
 
4
4
  """The circuit area and component widget"""
5
5
 
6
- # pylint: disable=unused-argument
7
- # pylint: disable=useless-parent-delegation
8
- # pylint: disable=too-few-public-methods
9
-
10
6
  from functools import partial
11
7
 
12
8
  from PySide6.QtCore import QPoint, QPointF, QRect, QRectF, Qt, QTimer
@@ -23,7 +19,6 @@ from digsim.app.settings import ComponentSettingsDialog
23
19
 
24
20
 
25
21
  class WirePartGraphicsItem(QGraphicsRectItem):
26
-
27
22
  """A part of a wire graphcis item"""
28
23
 
29
24
  CLOSE_TO_WIRE_MARGIN = 10
@@ -1,10 +1,8 @@
1
- # Copyright (c) Fredrik Andersson, 2023
1
+ # Copyright (c) Fredrik Andersson, 2023-2024
2
2
  # All rights reserved
3
3
 
4
4
  """Module for the component selection classes"""
5
5
 
6
- # pylint: disable=too-few-public-methods
7
-
8
6
  from functools import partial
9
7
 
10
8
  from PySide6.QtCore import QMimeData, QSize, Qt, QTimer
@@ -1,10 +1,8 @@
1
- # Copyright (c) Fredrik Andersson, 2023
1
+ # Copyright (c) Fredrik Andersson, 2023-2024
2
2
  # All rights reserved
3
3
 
4
4
  """The main window and widgets of the digsim gui application"""
5
5
 
6
- # pylint: disable=too-few-public-methods
7
-
8
6
  from PySide6.QtCore import Qt
9
7
  from PySide6.QtGui import QKeySequence, QShortcut
10
8
  from PySide6.QtWidgets import (
@@ -1,11 +1,8 @@
1
- # Copyright (c) Fredrik Andersson, 2023
1
+ # Copyright (c) Fredrik Andersson, 2023-2024
2
2
  # All rights reserved
3
3
 
4
4
  """The top bar of the main window/gui application"""
5
5
 
6
- # pylint: disable=too-few-public-methods
7
- # pylint: disable=too-many-instance-attributes
8
-
9
6
  from pathlib import Path
10
7
 
11
8
  import qtawesome as qta
@@ -1,10 +1,8 @@
1
- # Copyright (c) Fredrik Andersson, 2023
1
+ # Copyright (c) Fredrik Andersson, 2023-2024
2
2
  # All rights reserved
3
3
 
4
4
  """A warning dialog"""
5
5
 
6
- # pylint: disable=too-few-public-methods
7
-
8
6
  from PySide6.QtCore import QSize, Qt
9
7
  from PySide6.QtWidgets import (
10
8
  QDialog,
@@ -1,7 +1,7 @@
1
1
  # Copyright (c) Fredrik Andersson, 2023
2
2
  # All rights reserved
3
3
 
4
- """ All classes within digsim.app.gui_object namespace """
4
+ """All classes within digsim.app.gui_object namespace"""
5
5
 
6
6
  from ._component_object import ComponentObject # noqa: F401
7
7
  from ._gui_object_factory import get_class_by_name as class_factory # noqa: F401
@@ -1,7 +1,7 @@
1
- # Copyright (c) Fredrik Andersson, 2023
1
+ # Copyright (c) Fredrik Andersson, 2023-2024
2
2
  # All rights reserved
3
3
 
4
- """ A hexdigit component placed in the GUI """
4
+ """A hexdigit component placed in the GUI"""
5
5
 
6
6
  from PySide6.QtCore import QPoint, QSize, Qt
7
7
  from PySide6.QtGui import QPen
@@ -9,9 +9,6 @@ from PySide6.QtGui import QPen
9
9
  from ._component_object import ComponentObject
10
10
 
11
11
 
12
- # pylint: disable=too-many-arguments
13
-
14
-
15
12
  class BusBitsObject(ComponentObject):
16
13
  """The class for a bus/bit component placed in the GUI"""
17
14
 
@@ -1,7 +1,7 @@
1
1
  # Copyright (c) Fredrik Andersson, 2023
2
2
  # All rights reserved
3
3
 
4
- """ A buzzer component object """
4
+ """A buzzer component object"""
5
5
 
6
6
  from math import pi, sin
7
7
  from struct import pack
@@ -1,7 +1,7 @@
1
1
  # Copyright (c) Fredrik Andersson, 2023
2
2
  # All rights reserved
3
3
 
4
- """ A component context menu """
4
+ """A component context menu"""
5
5
 
6
6
  from PySide6.QtGui import QAction
7
7
  from PySide6.QtWidgets import QMenu
@@ -58,7 +58,7 @@ class ComponentContextMenu(QMenu):
58
58
  return self._menu_action.text() if self._menu_action is not None else ""
59
59
 
60
60
  def _delete(self):
61
- self._component_object.select(True)
61
+ self._component_object.setSelected(True)
62
62
  self._app_model.objects.delete_selected()
63
63
 
64
64
  def _raise(self):
@@ -1,12 +1,7 @@
1
- # Copyright (c) Fredrik Andersson, 2023
1
+ # Copyright (c) Fredrik Andersson, 2023-2024
2
2
  # All rights reserved
3
3
 
4
- """ A component placed in the GUI """
5
-
6
- # pylint: disable=unused-argument
7
- # pylint: disable=too-many-public-methods
8
- # pylint: disable=too-many-instance-attributes
9
- # pylint: disable=too-many-arguments
4
+ """A component placed in the GUI"""
10
5
 
11
6
  import abc
12
7
 
@@ -14,6 +9,8 @@ from PySide6.QtCore import QPoint, QRect, QSize, Qt
14
9
  from PySide6.QtGui import QFont, QFontMetrics, QPen
15
10
  from PySide6.QtWidgets import QGraphicsItem, QGraphicsRectItem
16
11
 
12
+ from digsim.storage_model import GuiPositionDataClass
13
+
17
14
  from ._component_context_menu import ComponentContextMenu
18
15
  from ._component_port_item import PortGraphicsItem
19
16
 
@@ -370,6 +367,7 @@ class ComponentObject(QGraphicsRectItem):
370
367
  """Set zlevel"""
371
368
  self.setZValue(level)
372
369
 
373
- def to_dict(self):
374
- """Return position as dict"""
375
- return {"x": int(self._save_pos.x()), "y": int(self._save_pos.y()), "z": self.zlevel}
370
+ def to_gui_dataclass(self):
371
+ return GuiPositionDataClass(
372
+ x=int(self._save_pos.x()), y=int(self._save_pos.y()), z=int(self.zlevel)
373
+ )
@@ -1,7 +1,7 @@
1
1
  # Copyright (c) Fredrik Andersson, 2023
2
2
  # All rights reserved
3
3
 
4
- """ A component port graphics item """
4
+ """A component port graphics item"""
5
5
 
6
6
  from PySide6.QtCore import QRect, Qt
7
7
  from PySide6.QtGui import QBrush, QPen
@@ -1,7 +1,7 @@
1
- # Copyright (c) Fredrik Andersson, 2023
1
+ # Copyright (c) Fredrik Andersson, 2023-2024
2
2
  # All rights reserved
3
3
 
4
- """ A hexdigit component placed in the GUI """
4
+ """A hexdigit component placed in the GUI"""
5
5
 
6
6
  from PySide6.QtCore import QPoint, QRect, Qt
7
7
  from PySide6.QtGui import QFont, QPen
@@ -9,9 +9,6 @@ from PySide6.QtGui import QFont, QPen
9
9
  from ._image_objects import ImageObject
10
10
 
11
11
 
12
- # pylint: disable=too-many-arguments
13
-
14
-
15
12
  class DipSwitchObject(ImageObject):
16
13
  """The class for a bus/bit component placed in the GUI"""
17
14
 
@@ -1,7 +1,7 @@
1
1
  # Copyright (c) Fredrik Andersson, 2023
2
2
  # All rights reserved
3
3
 
4
- """ A GUI note object """
4
+ """A GUI note object"""
5
5
 
6
6
  from PySide6.QtCore import QPoint, QRect, Qt
7
7
  from PySide6.QtGui import QFont, QFontMetrics, QPen
@@ -1,7 +1,7 @@
1
1
  # Copyright (c) Fredrik Andersson, 2023
2
2
  # All rights reserved
3
3
 
4
- """ A GUI component object factory module """
4
+ """A GUI component object factory module"""
5
5
 
6
6
  from digsim.circuit.components.atoms import DigsimException
7
7
 
@@ -1,7 +1,7 @@
1
1
  # Copyright (c) Fredrik Andersson, 2023
2
2
  # All rights reserved
3
3
 
4
- """ A hexdigit component placed in the GUI """
4
+ """A hexdigit component placed in the GUI"""
5
5
 
6
6
  from ._component_object import ComponentObject
7
7
  from ._seven_segment_object import SevenSegmentObject
@@ -1,9 +1,7 @@
1
- # Copyright (c) Fredrik Andersson, 2023
1
+ # Copyright (c) Fredrik Andersson, 2023-2024
2
2
  # All rights reserved
3
3
 
4
- """ A component with an image as symbol the GUI """
5
-
6
- # pylint: disable=too-many-arguments
4
+ """A component with an image as symbol the GUI"""
7
5
 
8
6
  from pathlib import Path
9
7
 
@@ -1,7 +1,7 @@
1
1
  # Copyright (c) Fredrik Andersson, 2023
2
2
  # All rights reserved
3
3
 
4
- """ A label component placed in the GUI """
4
+ """A label component placed in the GUI"""
5
5
 
6
6
  from PySide6.QtCore import QPoint, QRect, Qt
7
7
  from PySide6.QtGui import QPen, QPolygon
@@ -1,7 +1,7 @@
1
1
  # Copyright (c) Fredrik Andersson, 2023
2
2
  # All rights reserved
3
3
 
4
- """ A Logic Analyzer component placed in the GUI """
4
+ """A Logic Analyzer component placed in the GUI"""
5
5
 
6
6
  from PySide6.QtCore import QPoint, QRect, Qt
7
7
  from PySide6.QtGui import QPainterPath, QPen
@@ -23,7 +23,6 @@ class LogicAnalyzerObject(ImageObject):
23
23
  self.update_ports()
24
24
 
25
25
  def paint_component(self, painter):
26
-
27
26
  self.paint_component_base(painter)
28
27
  painter.setBrush(Qt.SolidPattern)
29
28
  painter.setBrush(Qt.black)
@@ -1,9 +1,7 @@
1
- # Copyright (c) Fredrik Andersson, 2023
1
+ # Copyright (c) Fredrik Andersson, 2023-2024
2
2
  # All rights reserved
3
3
 
4
- """ A 7-segment component placed in the GUI """
5
-
6
- # pylint: disable=too-many-arguments
4
+ """A 7-segment component placed in the GUI"""
7
5
 
8
6
  from PySide6.QtCore import QPoint, Qt
9
7
  from PySide6.QtGui import QPainterPath
@@ -1,9 +1,7 @@
1
- # Copyright (c) Fredrik Andersson, 2023
1
+ # Copyright (c) Fredrik Andersson, 2023-2024
2
2
  # All rights reserved
3
3
 
4
- """ A button component with an image as symbol the GUI """
5
-
6
- # pylint: disable=too-few-public-methods
4
+ """A button component with an image as symbol the GUI"""
7
5
 
8
6
  from functools import partial
9
7
 
@@ -1,7 +1,7 @@
1
1
  # Copyright (c) Fredrik Andersson, 2023
2
2
  # All rights reserved
3
3
 
4
- """ A yosys component with an image as symbol the GUI """
4
+ """A yosys component with an image as symbol the GUI"""
5
5
 
6
6
  from PySide6.QtGui import QAction
7
7
 
@@ -1,6 +1,6 @@
1
1
  # Copyright (c) Fredrik Andersson, 2023
2
2
  # All rights reserved
3
3
 
4
- """ All classes within digsim.app.model namespace """
4
+ """All classes within digsim.app.model namespace"""
5
5
 
6
6
  from ._model import AppModel # noqa: F401
@@ -1,11 +1,8 @@
1
- # Copyright (c) Fredrik Andersson, 2023
1
+ # Copyright (c) Fredrik Andersson, 2023-2024
2
2
  # All rights reserved
3
3
 
4
- """ An application model for a GUI simulated circuit """
4
+ """An application model for a GUI simulated circuit"""
5
5
 
6
- # pylint: disable=too-many-instance-attributes
7
-
8
- import json
9
6
  import queue
10
7
  import time
11
8
  from pathlib import Path
@@ -14,6 +11,7 @@ from PySide6.QtCore import QThread, Signal
14
11
 
15
12
  from digsim.app.gui_objects import ComponentObject
16
13
  from digsim.circuit.components.atoms import Component
14
+ from digsim.storage_model import AppFileDataClass
17
15
 
18
16
  from ._model_objects import ModelObjects
19
17
  from ._model_settings import ModelSettings
@@ -157,28 +155,27 @@ class AppModel(QThread):
157
155
  def save_circuit(self, path):
158
156
  """Save the circuit with GUI information"""
159
157
  circuit_folder = str(Path(path).parent)
160
- circuit_dict = self.objects.circuit_to_dict(circuit_folder)
161
- shortcuts_dict = self.shortcuts.to_dict()
162
- circuit_dict.update(shortcuts_dict)
163
- settings_dict = self.settings.to_dict()
164
- circuit_dict.update(settings_dict)
165
- json_object = json.dumps(circuit_dict, indent=4)
166
- with open(path, mode="w", encoding="utf-8") as json_file:
167
- json_file.write(json_object)
158
+ model_dataclass = self.objects.circuit_to_model(circuit_folder)
159
+ appfile_dataclass = AppFileDataClass(
160
+ circuit=model_dataclass.circuit,
161
+ gui=model_dataclass.gui,
162
+ shortcuts=self.shortcuts.to_dict(),
163
+ settings=self.settings.get_all(),
164
+ )
165
+ appfile_dataclass.save(path)
168
166
  self._changed = False
169
167
  self.sig_control_notify.emit()
170
168
 
171
169
  def load_circuit(self, path):
172
170
  """Load a circuit with GUI information"""
173
171
  self._model_clear()
174
- with open(path, mode="r", encoding="utf-8") as json_file:
175
- circuit_dict = json.load(json_file)
172
+ app_file_dc = AppFileDataClass.load(path)
176
173
  circuit_folder = str(Path(path).parent)
177
174
  if len(circuit_folder) == 0:
178
175
  circuit_folder = "."
179
- exception_str_list = self.objects.dict_to_circuit(circuit_dict, circuit_folder)
180
- self.shortcuts.from_dict(circuit_dict)
181
- self.settings.from_dict(circuit_dict)
176
+ exception_str_list = self.objects.model_to_circuit(app_file_dc, circuit_folder)
177
+ self.shortcuts.from_dict(app_file_dc.shortcuts)
178
+ self.settings.from_dict(app_file_dc.settings)
182
179
  self.model_init()
183
180
  self._changed = False
184
181
  self.objects.reset_undo_stack()
@@ -1,4 +1,4 @@
1
- # Copyright (c) Fredrik Andersson, 2023
1
+ # Copyright (c) Fredrik Andersson, 2023-2024
2
2
  # All rights reserved
3
3
 
4
4
  """Handle component objects in the model"""
@@ -7,6 +7,7 @@ import digsim.circuit.components
7
7
  from digsim.app.gui_objects import ComponentObject
8
8
  from digsim.circuit.components import Buzzer
9
9
  from digsim.circuit.components.atoms import CallbackComponent
10
+ from digsim.storage_model import GuiPositionDataClass
10
11
 
11
12
 
12
13
  class ModelComponents:
@@ -149,20 +150,16 @@ class ModelComponents:
149
150
  self._circuit.delete_component(component_object.component)
150
151
  self._app_model.sig_delete_component.emit(component_object)
151
152
 
152
- def create_from_dict(self, circuit_dict):
153
+ def add_gui_positions(self, gui_dc_dict):
153
154
  """Create model components from circuit_dict"""
154
155
  for comp in self._circuit.get_toplevel_components():
155
- gui_dict = circuit_dict.get("gui", {})
156
- component_dict = gui_dict.get(comp.name(), {})
157
- x = component_dict.get("x", 100)
158
- y = component_dict.get("y", 100)
159
- z = component_dict.get("z", 0)
160
- component_object = self._add_object(comp, x, y)
161
- component_object.zlevel = z
162
-
163
- def get_circuit_dict(self):
164
- """Create model components dict"""
165
- model_components_dict = {"gui": {}}
156
+ gui_dc = gui_dc_dict.get(comp.name(), GuiPositionDataClass())
157
+ component_object = self._add_object(comp, gui_dc.x, gui_dc.y)
158
+ component_object.zlevel = gui_dc.z
159
+
160
+ def get_gui_dict(self):
161
+ """Return gui dict from component objects"""
162
+ gui_dict = {}
166
163
  for comp, comp_object in self.get_dict().items():
167
- model_components_dict["gui"][comp.name()] = comp_object.to_dict()
168
- return model_components_dict
164
+ gui_dict[comp.name()] = comp_object.to_gui_dataclass()
165
+ return gui_dict
@@ -1,12 +1,11 @@
1
- # Copyright (c) Fredrik Andersson, 2023
1
+ # Copyright (c) Fredrik Andersson, 2023-2024
2
2
  # All rights reserved
3
3
 
4
4
  """Handle objects in the model"""
5
5
 
6
- # pylint: disable=too-many-public-methods
7
-
8
6
  from digsim.circuit import Circuit
9
7
  from digsim.circuit.components.atoms import DigsimException
8
+ from digsim.storage_model import AppFileDataClass, ModelDataClass
10
9
 
11
10
  from ._model_components import ModelComponents
12
11
  from ._model_new_wire import NewWire
@@ -74,32 +73,37 @@ class ModelObjects:
74
73
  self._app_model.model_changed()
75
74
  self._app_model.sig_delete_wires.emit()
76
75
 
77
- def circuit_to_dict(self, circuit_folder):
78
- """Convert circuit and objects to dict"""
79
- circuit_dict = self.circuit.to_dict(circuit_folder)
80
- model_components_dict = self.components.get_circuit_dict()
81
- circuit_dict.update(model_components_dict)
82
- return circuit_dict
76
+ def model_to_circuit(self, model_dc, circuit_folder):
77
+ if isinstance(model_dc, AppFileDataClass):
78
+ # Loaded model
79
+ dc = ModelDataClass.from_app_file_dc(model_dc)
80
+ else:
81
+ dc = model_dc
83
82
 
84
- def dict_to_circuit(self, circuit_dict, circuit_folder):
85
- """Convert dict to circuit and objects"""
86
- exception_str_list = []
87
83
  try:
88
- exception_str_list = self.circuit.from_dict(
89
- circuit_dict, circuit_folder, component_exceptions=False, connect_exceptions=False
84
+ # Create circuit
85
+ exception_str_list = self.circuit.from_dataclass(
86
+ dc.circuit,
87
+ circuit_folder,
88
+ component_exceptions=False,
89
+ connect_exceptions=False,
90
90
  )
91
+ # Add component positions
92
+ self.components.add_gui_positions(dc.gui)
91
93
  except DigsimException as exc:
92
94
  self.sig_error.emit(f"Circuit error: {str(exc)}")
93
95
  return exception_str_list
94
-
95
- # Create GUI components
96
- self.components.create_from_dict(circuit_dict)
97
-
98
96
  return exception_str_list
99
97
 
100
- def _restore_state(self, state):
98
+ def circuit_to_model(self, circuit_folder):
99
+ model_dc = ModelDataClass(
100
+ circuit=self.circuit.to_dataclass(circuit_folder), gui=self.components.get_gui_dict()
101
+ )
102
+ return model_dc
103
+
104
+ def _restore_state(self, model_dc):
101
105
  self.clear()
102
- exception_str_list = self.dict_to_circuit(state, "/")
106
+ exception_str_list = self.model_to_circuit(model_dc, None)
103
107
  self._app_model.model_init()
104
108
  self._app_model.model_changed()
105
109
  if len(exception_str_list) > 0:
@@ -113,7 +117,7 @@ class ModelObjects:
113
117
 
114
118
  def push_undo_state(self, clear_redo_stack=True):
115
119
  """Push undo state to stack"""
116
- self._undo_stack.append(self.circuit_to_dict("/"))
120
+ self._undo_stack.append(self.circuit_to_model("/"))
117
121
  if clear_redo_stack:
118
122
  self._redo_stack = []
119
123
  self._app_model.sig_control_notify.emit()
@@ -126,14 +130,14 @@ class ModelObjects:
126
130
 
127
131
  def push_redo_state(self):
128
132
  """Push redo state to stack"""
129
- self._redo_stack.append(self.circuit_to_dict("/"))
133
+ self._redo_stack.append(self.circuit_to_model("/"))
130
134
 
131
135
  def undo(self):
132
136
  """Undo to last saved state"""
133
137
  if len(self._undo_stack) > 0:
134
138
  self.push_redo_state()
135
- state = self._undo_stack.pop()
136
- self._restore_state(state)
139
+ model_dc = self._undo_stack.pop()
140
+ self._restore_state(model_dc)
137
141
  self._app_model.sig_control_notify.emit()
138
142
  self._app_model.sig_synchronize_gui.emit()
139
143
 
@@ -141,8 +145,8 @@ class ModelObjects:
141
145
  """Undo to last saved state"""
142
146
  if len(self._redo_stack) > 0:
143
147
  self.push_undo_state(clear_redo_stack=False)
144
- state = self._redo_stack.pop()
145
- self._restore_state(state)
148
+ model_dc = self._redo_stack.pop()
149
+ self._restore_state(model_dc)
146
150
  self._app_model.sig_control_notify.emit()
147
151
  self._app_model.sig_synchronize_gui.emit()
148
152
 
@@ -1,4 +1,4 @@
1
- # Copyright (c) Fredrik Andersson, 2023
1
+ # Copyright (c) Fredrik Andersson, 2023-2024
2
2
  # All rights reserved
3
3
 
4
4
  """Handle settings in the model"""
@@ -25,10 +25,6 @@ class ModelSettings:
25
25
  """Return settings dict"""
26
26
  return self._settings
27
27
 
28
- def to_dict(self):
29
- """Return settings dict to save"""
30
- return {"settings": self._settings}
31
-
32
28
  def from_dict(self, circuit_dict):
33
29
  """Get settings from circuit dict"""
34
30
  for key, data in circuit_dict.get("settings", {}).items():
@@ -1,4 +1,4 @@
1
- # Copyright (c) Fredrik Andersson, 2023
1
+ # Copyright (c) Fredrik Andersson, 2023-2024
2
2
  # All rights reserved
3
3
 
4
4
  """Handle shortcuts in the model"""
@@ -72,9 +72,9 @@ class ModelShortcuts:
72
72
 
73
73
  def to_dict(self):
74
74
  """Generate dict from shortcuts"""
75
- shortcuts_dict = {"shortcuts": {}}
75
+ shortcuts_dict = {}
76
76
  for key, component in self._shortcut_component.items():
77
- shortcuts_dict["shortcuts"][key] = component.name()
77
+ shortcuts_dict[key] = component.name()
78
78
  return shortcuts_dict
79
79
 
80
80
  def from_dict(self, model_dict):
@@ -1,7 +1,7 @@
1
1
  # Copyright (c) Fredrik Andersson, 2023
2
2
  # All rights reserved
3
3
 
4
- """ All classes within digsim.app.settings namespace """
4
+ """All classes within digsim.app.settings namespace"""
5
5
 
6
6
  from ._component_settings import ComponentSettingsDialog # noqa: F401
7
7
  from ._gui_settings import GuiSettingsDialog # noqa: F401
@@ -1,10 +1,8 @@
1
- # Copyright (c) Fredrik Andersson, 2023
1
+ # Copyright (c) Fredrik Andersson, 2023-2024
2
2
  # All rights reserved
3
3
 
4
4
  """The component settings dialog(s)"""
5
5
 
6
- # pylint: disable=too-many-branches
7
-
8
6
  import pathlib
9
7
 
10
8
  from PySide6.QtCore import Qt, Signal
@@ -360,9 +358,9 @@ class ComponentSettingsDialog(QDialog):
360
358
  widget = ComponentSettingsCheckBoxWidthBool(
361
359
  self, parameter, parameter_dict, self._settings
362
360
  )
363
- elif parameter_dict["type"] == int:
361
+ elif parameter_dict["type"] == "int":
364
362
  widget = ComponentSettingsSlider(self, parameter, parameter_dict, self._settings)
365
- elif parameter_dict["type"] == str:
363
+ elif parameter_dict["type"] == "str":
366
364
  single_line = parameter_dict.get("single_line", False)
367
365
  if single_line:
368
366
  widget = ComponentSettingSingleLineText(
@@ -370,7 +368,7 @@ class ComponentSettingsDialog(QDialog):
370
368
  )
371
369
  else:
372
370
  widget = ComponentSettingText(self, parameter, parameter_dict, self._settings)
373
- elif parameter_dict["type"] == bool:
371
+ elif parameter_dict["type"] == "bool":
374
372
  widget = ComponentSettingsCheckBox(self, parameter, parameter_dict, self._settings)
375
373
  elif parameter_dict["type"] == "intrange":
376
374
  widget = ComponentSettingsIntRangeSlider(
@@ -384,7 +382,7 @@ class ComponentSettingsDialog(QDialog):
384
382
  widget = ComponentSettingsNameSelector(
385
383
  self, parameter, parameter_dict, self._settings
386
384
  )
387
- elif parameter_dict["type"] == list:
385
+ elif parameter_dict["type"] == "list":
388
386
  widget = ComponentSettingsListSelector(
389
387
  self, parameter, parameter_dict, self._settings
390
388
  )