digsim-logic-simulator 0.11.0__tar.gz → 0.13.0__tar.gz

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 (121) hide show
  1. {digsim_logic_simulator-0.11.0/src/digsim_logic_simulator.egg-info → digsim_logic_simulator-0.13.0}/PKG-INFO +1 -1
  2. {digsim_logic_simulator-0.11.0 → digsim_logic_simulator-0.13.0}/pyproject.toml +1 -1
  3. {digsim_logic_simulator-0.11.0 → digsim_logic_simulator-0.13.0}/src/digsim/app/__main__.py +16 -12
  4. {digsim_logic_simulator-0.11.0 → digsim_logic_simulator-0.13.0}/src/digsim/app/gui/_circuit_area.py +32 -21
  5. {digsim_logic_simulator-0.11.0 → digsim_logic_simulator-0.13.0}/src/digsim/app/gui/_component_selection.py +2 -0
  6. {digsim_logic_simulator-0.11.0 → digsim_logic_simulator-0.13.0}/src/digsim/app/gui_objects/__init__.py +1 -1
  7. {digsim_logic_simulator-0.11.0 → digsim_logic_simulator-0.13.0}/src/digsim/app/gui_objects/_buzzer_object.py +7 -12
  8. {digsim_logic_simulator-0.11.0 → digsim_logic_simulator-0.13.0}/src/digsim/app/gui_objects/_component_context_menu.py +1 -1
  9. {digsim_logic_simulator-0.11.0 → digsim_logic_simulator-0.13.0}/src/digsim/app/gui_objects/_component_object.py +10 -9
  10. {digsim_logic_simulator-0.11.0 → digsim_logic_simulator-0.13.0}/src/digsim/app/gui_objects/_component_port_item.py +0 -2
  11. {digsim_logic_simulator-0.11.0 → digsim_logic_simulator-0.13.0}/src/digsim/app/gui_objects/_dip_switch_object.py +5 -4
  12. {digsim_logic_simulator-0.11.0 → digsim_logic_simulator-0.13.0}/src/digsim/app/gui_objects/_gui_note_object.py +10 -11
  13. {digsim_logic_simulator-0.11.0 → digsim_logic_simulator-0.13.0}/src/digsim/app/gui_objects/_gui_object_factory.py +1 -1
  14. {digsim_logic_simulator-0.11.0 → digsim_logic_simulator-0.13.0}/src/digsim/app/gui_objects/_image_objects.py +7 -5
  15. {digsim_logic_simulator-0.11.0 → digsim_logic_simulator-0.13.0}/src/digsim/app/gui_objects/_label_object.py +3 -2
  16. {digsim_logic_simulator-0.11.0 → digsim_logic_simulator-0.13.0}/src/digsim/app/gui_objects/_logic_analyzer_object.py +18 -9
  17. {digsim_logic_simulator-0.11.0 → digsim_logic_simulator-0.13.0}/src/digsim/app/gui_objects/_seven_segment_object.py +10 -3
  18. {digsim_logic_simulator-0.11.0 → digsim_logic_simulator-0.13.0}/src/digsim/app/gui_objects/_shortcut_objects.py +3 -2
  19. {digsim_logic_simulator-0.11.0 → digsim_logic_simulator-0.13.0}/src/digsim/app/model/_model.py +7 -3
  20. {digsim_logic_simulator-0.11.0 → digsim_logic_simulator-0.13.0}/src/digsim/app/model/_model_components.py +1 -4
  21. {digsim_logic_simulator-0.11.0 → digsim_logic_simulator-0.13.0}/src/digsim/app/model/_model_new_wire.py +2 -1
  22. {digsim_logic_simulator-0.11.0 → digsim_logic_simulator-0.13.0}/src/digsim/app/model/_model_objects.py +1 -5
  23. {digsim_logic_simulator-0.11.0 → digsim_logic_simulator-0.13.0}/src/digsim/app/model/_model_settings.py +1 -1
  24. {digsim_logic_simulator-0.11.0 → digsim_logic_simulator-0.13.0}/src/digsim/app/model/_model_shortcuts.py +0 -14
  25. {digsim_logic_simulator-0.11.0 → digsim_logic_simulator-0.13.0}/src/digsim/app/settings/_component_settings.py +1 -1
  26. {digsim_logic_simulator-0.11.0 → digsim_logic_simulator-0.13.0}/src/digsim/app/settings/_shortcut_dialog.py +3 -4
  27. {digsim_logic_simulator-0.11.0 → digsim_logic_simulator-0.13.0}/src/digsim/circuit/_circuit.py +52 -38
  28. {digsim_logic_simulator-0.11.0 → digsim_logic_simulator-0.13.0}/src/digsim/circuit/components/_button.py +1 -5
  29. {digsim_logic_simulator-0.11.0 → digsim_logic_simulator-0.13.0}/src/digsim/circuit/components/_yosys_component.py +1 -1
  30. {digsim_logic_simulator-0.11.0 → digsim_logic_simulator-0.13.0}/src/digsim/circuit/components/atoms/__init__.py +1 -0
  31. {digsim_logic_simulator-0.11.0 → digsim_logic_simulator-0.13.0}/src/digsim/circuit/components/atoms/_component.py +14 -4
  32. {digsim_logic_simulator-0.11.0 → digsim_logic_simulator-0.13.0}/src/digsim/circuit/components/atoms/_port.py +45 -29
  33. {digsim_logic_simulator-0.11.0 → digsim_logic_simulator-0.13.0}/src/digsim/storage_model/_app.py +7 -2
  34. {digsim_logic_simulator-0.11.0 → digsim_logic_simulator-0.13.0}/src/digsim/storage_model/_circuit.py +15 -7
  35. {digsim_logic_simulator-0.11.0 → digsim_logic_simulator-0.13.0}/src/digsim/synth/__main__.py +2 -2
  36. {digsim_logic_simulator-0.11.0 → digsim_logic_simulator-0.13.0}/src/digsim/synth/_synthesis.py +26 -1
  37. {digsim_logic_simulator-0.11.0 → digsim_logic_simulator-0.13.0}/src/digsim/utils/_yosys_netlist.py +9 -3
  38. {digsim_logic_simulator-0.11.0 → digsim_logic_simulator-0.13.0/src/digsim_logic_simulator.egg-info}/PKG-INFO +1 -1
  39. {digsim_logic_simulator-0.11.0 → digsim_logic_simulator-0.13.0}/tests/test_yosys_synth.py +1 -2
  40. {digsim_logic_simulator-0.11.0 → digsim_logic_simulator-0.13.0}/LICENSE.md +0 -0
  41. {digsim_logic_simulator-0.11.0 → digsim_logic_simulator-0.13.0}/MANIFEST.in +0 -0
  42. {digsim_logic_simulator-0.11.0 → digsim_logic_simulator-0.13.0}/README.md +0 -0
  43. {digsim_logic_simulator-0.11.0 → digsim_logic_simulator-0.13.0}/setup.cfg +0 -0
  44. {digsim_logic_simulator-0.11.0 → digsim_logic_simulator-0.13.0}/src/digsim/__init__.py +0 -0
  45. {digsim_logic_simulator-0.11.0 → digsim_logic_simulator-0.13.0}/src/digsim/app/gui/__init__.py +0 -0
  46. {digsim_logic_simulator-0.11.0 → digsim_logic_simulator-0.13.0}/src/digsim/app/gui/_main_window.py +0 -0
  47. {digsim_logic_simulator-0.11.0 → digsim_logic_simulator-0.13.0}/src/digsim/app/gui/_top_bar.py +0 -0
  48. {digsim_logic_simulator-0.11.0 → digsim_logic_simulator-0.13.0}/src/digsim/app/gui/_utils.py +0 -0
  49. {digsim_logic_simulator-0.11.0 → digsim_logic_simulator-0.13.0}/src/digsim/app/gui/_warning_dialog.py +0 -0
  50. {digsim_logic_simulator-0.11.0 → digsim_logic_simulator-0.13.0}/src/digsim/app/gui_objects/_bus_bit_object.py +0 -0
  51. {digsim_logic_simulator-0.11.0 → digsim_logic_simulator-0.13.0}/src/digsim/app/gui_objects/_hexdigit_object.py +0 -0
  52. {digsim_logic_simulator-0.11.0 → digsim_logic_simulator-0.13.0}/src/digsim/app/gui_objects/_yosys_object.py +0 -0
  53. {digsim_logic_simulator-0.11.0 → digsim_logic_simulator-0.13.0}/src/digsim/app/gui_objects/images/AND.png +0 -0
  54. {digsim_logic_simulator-0.11.0 → digsim_logic_simulator-0.13.0}/src/digsim/app/gui_objects/images/Analyzer.png +0 -0
  55. {digsim_logic_simulator-0.11.0 → digsim_logic_simulator-0.13.0}/src/digsim/app/gui_objects/images/BUF.png +0 -0
  56. {digsim_logic_simulator-0.11.0 → digsim_logic_simulator-0.13.0}/src/digsim/app/gui_objects/images/Buzzer.png +0 -0
  57. {digsim_logic_simulator-0.11.0 → digsim_logic_simulator-0.13.0}/src/digsim/app/gui_objects/images/Clock.png +0 -0
  58. {digsim_logic_simulator-0.11.0 → digsim_logic_simulator-0.13.0}/src/digsim/app/gui_objects/images/DFF.png +0 -0
  59. {digsim_logic_simulator-0.11.0 → digsim_logic_simulator-0.13.0}/src/digsim/app/gui_objects/images/DIP_SWITCH.png +0 -0
  60. {digsim_logic_simulator-0.11.0 → digsim_logic_simulator-0.13.0}/src/digsim/app/gui_objects/images/FlipFlop.png +0 -0
  61. {digsim_logic_simulator-0.11.0 → digsim_logic_simulator-0.13.0}/src/digsim/app/gui_objects/images/IC.png +0 -0
  62. {digsim_logic_simulator-0.11.0 → digsim_logic_simulator-0.13.0}/src/digsim/app/gui_objects/images/LED_OFF.png +0 -0
  63. {digsim_logic_simulator-0.11.0 → digsim_logic_simulator-0.13.0}/src/digsim/app/gui_objects/images/LED_ON.png +0 -0
  64. {digsim_logic_simulator-0.11.0 → digsim_logic_simulator-0.13.0}/src/digsim/app/gui_objects/images/MUX.png +0 -0
  65. {digsim_logic_simulator-0.11.0 → digsim_logic_simulator-0.13.0}/src/digsim/app/gui_objects/images/NAND.png +0 -0
  66. {digsim_logic_simulator-0.11.0 → digsim_logic_simulator-0.13.0}/src/digsim/app/gui_objects/images/NOR.png +0 -0
  67. {digsim_logic_simulator-0.11.0 → digsim_logic_simulator-0.13.0}/src/digsim/app/gui_objects/images/NOT.png +0 -0
  68. {digsim_logic_simulator-0.11.0 → digsim_logic_simulator-0.13.0}/src/digsim/app/gui_objects/images/ONE.png +0 -0
  69. {digsim_logic_simulator-0.11.0 → digsim_logic_simulator-0.13.0}/src/digsim/app/gui_objects/images/OR.png +0 -0
  70. {digsim_logic_simulator-0.11.0 → digsim_logic_simulator-0.13.0}/src/digsim/app/gui_objects/images/PB.png +0 -0
  71. {digsim_logic_simulator-0.11.0 → digsim_logic_simulator-0.13.0}/src/digsim/app/gui_objects/images/Switch_OFF.png +0 -0
  72. {digsim_logic_simulator-0.11.0 → digsim_logic_simulator-0.13.0}/src/digsim/app/gui_objects/images/Switch_ON.png +0 -0
  73. {digsim_logic_simulator-0.11.0 → digsim_logic_simulator-0.13.0}/src/digsim/app/gui_objects/images/XNOR.png +0 -0
  74. {digsim_logic_simulator-0.11.0 → digsim_logic_simulator-0.13.0}/src/digsim/app/gui_objects/images/XOR.png +0 -0
  75. {digsim_logic_simulator-0.11.0 → digsim_logic_simulator-0.13.0}/src/digsim/app/gui_objects/images/YOSYS.png +0 -0
  76. {digsim_logic_simulator-0.11.0 → digsim_logic_simulator-0.13.0}/src/digsim/app/gui_objects/images/ZERO.png +0 -0
  77. {digsim_logic_simulator-0.11.0 → digsim_logic_simulator-0.13.0}/src/digsim/app/images/app_icon.png +0 -0
  78. {digsim_logic_simulator-0.11.0 → digsim_logic_simulator-0.13.0}/src/digsim/app/model/__init__.py +0 -0
  79. {digsim_logic_simulator-0.11.0 → digsim_logic_simulator-0.13.0}/src/digsim/app/settings/__init__.py +0 -0
  80. {digsim_logic_simulator-0.11.0 → digsim_logic_simulator-0.13.0}/src/digsim/app/settings/_gui_settings.py +0 -0
  81. {digsim_logic_simulator-0.11.0 → digsim_logic_simulator-0.13.0}/src/digsim/circuit/__init__.py +0 -0
  82. {digsim_logic_simulator-0.11.0 → digsim_logic_simulator-0.13.0}/src/digsim/circuit/_waves_writer.py +0 -0
  83. {digsim_logic_simulator-0.11.0 → digsim_logic_simulator-0.13.0}/src/digsim/circuit/components/__init__.py +0 -0
  84. {digsim_logic_simulator-0.11.0 → digsim_logic_simulator-0.13.0}/src/digsim/circuit/components/_bus_bits.py +0 -0
  85. {digsim_logic_simulator-0.11.0 → digsim_logic_simulator-0.13.0}/src/digsim/circuit/components/_buzzer.py +0 -0
  86. {digsim_logic_simulator-0.11.0 → digsim_logic_simulator-0.13.0}/src/digsim/circuit/components/_clock.py +0 -0
  87. {digsim_logic_simulator-0.11.0 → digsim_logic_simulator-0.13.0}/src/digsim/circuit/components/_dip_switch.py +0 -0
  88. {digsim_logic_simulator-0.11.0 → digsim_logic_simulator-0.13.0}/src/digsim/circuit/components/_flip_flops.py +0 -0
  89. {digsim_logic_simulator-0.11.0 → digsim_logic_simulator-0.13.0}/src/digsim/circuit/components/_gates.py +0 -0
  90. {digsim_logic_simulator-0.11.0 → digsim_logic_simulator-0.13.0}/src/digsim/circuit/components/_hexdigit.py +0 -0
  91. {digsim_logic_simulator-0.11.0 → digsim_logic_simulator-0.13.0}/src/digsim/circuit/components/_ic.py +0 -0
  92. {digsim_logic_simulator-0.11.0 → digsim_logic_simulator-0.13.0}/src/digsim/circuit/components/_label_wire.py +0 -0
  93. {digsim_logic_simulator-0.11.0 → digsim_logic_simulator-0.13.0}/src/digsim/circuit/components/_led.py +0 -0
  94. {digsim_logic_simulator-0.11.0 → digsim_logic_simulator-0.13.0}/src/digsim/circuit/components/_logic_analyzer.py +0 -0
  95. {digsim_logic_simulator-0.11.0 → digsim_logic_simulator-0.13.0}/src/digsim/circuit/components/_mem64kbyte.py +0 -0
  96. {digsim_logic_simulator-0.11.0 → digsim_logic_simulator-0.13.0}/src/digsim/circuit/components/_memstdout.py +0 -0
  97. {digsim_logic_simulator-0.11.0 → digsim_logic_simulator-0.13.0}/src/digsim/circuit/components/_note.py +0 -0
  98. {digsim_logic_simulator-0.11.0 → digsim_logic_simulator-0.13.0}/src/digsim/circuit/components/_on_off_switch.py +0 -0
  99. {digsim_logic_simulator-0.11.0 → digsim_logic_simulator-0.13.0}/src/digsim/circuit/components/_seven_segment.py +0 -0
  100. {digsim_logic_simulator-0.11.0 → digsim_logic_simulator-0.13.0}/src/digsim/circuit/components/_static_level.py +0 -0
  101. {digsim_logic_simulator-0.11.0 → digsim_logic_simulator-0.13.0}/src/digsim/circuit/components/_static_value.py +0 -0
  102. {digsim_logic_simulator-0.11.0 → digsim_logic_simulator-0.13.0}/src/digsim/circuit/components/_yosys_atoms.py +0 -0
  103. {digsim_logic_simulator-0.11.0 → digsim_logic_simulator-0.13.0}/src/digsim/circuit/components/atoms/_digsim_exception.py +0 -0
  104. {digsim_logic_simulator-0.11.0 → digsim_logic_simulator-0.13.0}/src/digsim/circuit/components/ic/74162.json +0 -0
  105. {digsim_logic_simulator-0.11.0 → digsim_logic_simulator-0.13.0}/src/digsim/circuit/components/ic/7448.json +0 -0
  106. {digsim_logic_simulator-0.11.0 → digsim_logic_simulator-0.13.0}/src/digsim/storage_model/__init__.py +0 -0
  107. {digsim_logic_simulator-0.11.0 → digsim_logic_simulator-0.13.0}/src/digsim/synth/__init__.py +0 -0
  108. {digsim_logic_simulator-0.11.0 → digsim_logic_simulator-0.13.0}/src/digsim/utils/__init__.py +0 -0
  109. {digsim_logic_simulator-0.11.0 → digsim_logic_simulator-0.13.0}/src/digsim_logic_simulator.egg-info/SOURCES.txt +0 -0
  110. {digsim_logic_simulator-0.11.0 → digsim_logic_simulator-0.13.0}/src/digsim_logic_simulator.egg-info/dependency_links.txt +0 -0
  111. {digsim_logic_simulator-0.11.0 → digsim_logic_simulator-0.13.0}/src/digsim_logic_simulator.egg-info/requires.txt +0 -0
  112. {digsim_logic_simulator-0.11.0 → digsim_logic_simulator-0.13.0}/src/digsim_logic_simulator.egg-info/top_level.txt +0 -0
  113. {digsim_logic_simulator-0.11.0 → digsim_logic_simulator-0.13.0}/tests/test_gates.py +0 -0
  114. {digsim_logic_simulator-0.11.0 → digsim_logic_simulator-0.13.0}/tests/test_yosys_aldff.py +0 -0
  115. {digsim_logic_simulator-0.11.0 → digsim_logic_simulator-0.13.0}/tests/test_yosys_dff.py +0 -0
  116. {digsim_logic_simulator-0.11.0 → digsim_logic_simulator-0.13.0}/tests/test_yosys_dlatch.py +0 -0
  117. {digsim_logic_simulator-0.11.0 → digsim_logic_simulator-0.13.0}/tests/test_yosys_gates.py +0 -0
  118. {digsim_logic_simulator-0.11.0 → digsim_logic_simulator-0.13.0}/tests/test_yosys_latch.py +0 -0
  119. {digsim_logic_simulator-0.11.0 → digsim_logic_simulator-0.13.0}/tests/test_yosys_netlist.py +0 -0
  120. {digsim_logic_simulator-0.11.0 → digsim_logic_simulator-0.13.0}/tests/test_yosys_sdff.py +0 -0
  121. {digsim_logic_simulator-0.11.0 → digsim_logic_simulator-0.13.0}/tests/test_yosys_sr.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: digsim-logic-simulator
3
- Version: 0.11.0
3
+ Version: 0.13.0
4
4
  Summary: Interactive Digital Logic Simulator
5
5
  Author-email: Fredrik Andersson <freand@gmail.com>
6
6
  Maintainer-email: Fredrik Andersson <freand@gmail.com>
@@ -5,7 +5,7 @@ build-backend = "setuptools.build_meta"
5
5
  [project]
6
6
  name = "digsim-logic-simulator"
7
7
  description = "Interactive Digital Logic Simulator"
8
- version = "0.11.0"
8
+ version = "0.13.0"
9
9
  authors = [{name = "Fredrik Andersson", email = "freand@gmail.com"}]
10
10
  maintainers = [{name = "Fredrik Andersson", email = "freand@gmail.com"}]
11
11
  readme = "README.md"
@@ -16,21 +16,25 @@ from digsim.app.model import AppModel
16
16
 
17
17
 
18
18
  if __name__ == "__main__":
19
+
20
+ def _create_app_icon(image_path: Path) -> QIcon:
21
+ image_pixmap = QPixmap(image_path)
22
+ size = max(image_pixmap.size().height(), image_pixmap.size().width())
23
+ icon_pixmap = QPixmap(size, size)
24
+ icon_pixmap.fill(Qt.transparent)
25
+ painter = QPainter(icon_pixmap)
26
+ painter.drawPixmap(
27
+ (icon_pixmap.size().width() - image_pixmap.size().width()) // 2,
28
+ (icon_pixmap.size().height() - image_pixmap.size().height()) // 2,
29
+ image_pixmap,
30
+ )
31
+ painter.end()
32
+ return QIcon(icon_pixmap)
33
+
19
34
  app = QApplication(sys.argv)
20
35
  main_path = Path(__file__).parent
21
36
  image_path = main_path / "images/app_icon.png"
22
- image_pixmap = QPixmap(image_path)
23
- size = max(image_pixmap.size().height(), image_pixmap.size().width())
24
- icon_pixmap = QPixmap(size, size)
25
- icon_pixmap.fill(Qt.transparent)
26
- painter = QPainter(icon_pixmap)
27
- painter.drawPixmap(
28
- (icon_pixmap.size().width() - image_pixmap.size().width()) // 2,
29
- (icon_pixmap.size().height() - image_pixmap.size().height()) // 2,
30
- image_pixmap,
31
- )
32
- painter.end()
33
- icon = QIcon(icon_pixmap)
37
+ icon = _create_app_icon(image_path)
34
38
  app.setWindowIcon(icon)
35
39
  app_model = AppModel()
36
40
  window = MainWindow(app_model)
@@ -6,7 +6,7 @@
6
6
  from functools import partial
7
7
 
8
8
  from PySide6.QtCore import QPoint, QPointF, QRect, QRectF, Qt, QTimer
9
- from PySide6.QtGui import QBrush, QPainterPath, QPen
9
+ from PySide6.QtGui import QBrush, QColor, QPainterPath, QPen
10
10
  from PySide6.QtWidgets import (
11
11
  QGraphicsItem,
12
12
  QGraphicsPathItem,
@@ -52,6 +52,19 @@ class WirePartGraphicsItem(QGraphicsRectItem):
52
52
  self._parent.select(self.isSelected())
53
53
  return super().itemChange(change, value)
54
54
 
55
+ def _get_wire_color(self, port_value, bus_width):
56
+ if port_value == "X":
57
+ return Qt.red
58
+ if port_value == 0:
59
+ return Qt.darkGray
60
+
61
+ max_value = 2**bus_width - 1
62
+ # Start with dark gray
63
+ green = 128
64
+ # Calculate the green component, ranging from 128 to 255
65
+ green += int(127 * port_value / max_value)
66
+ return QColor(128, green, 128)
67
+
55
68
  def paint(self, painter, option, widget=None):
56
69
  """QT function"""
57
70
  pen = QPen(Qt.darkGray)
@@ -60,20 +73,13 @@ class WirePartGraphicsItem(QGraphicsRectItem):
60
73
  pen.setWidth(4)
61
74
  else:
62
75
  pen.setWidth(2)
76
+
63
77
  if not self._app_model.is_running and self._selected:
64
78
  pen.setColor(Qt.black)
65
- else:
66
- if self._app_model.settings.get("color_wires"):
67
- port_value = self._src_port.value
68
- if port_value == "X":
69
- pen.setColor(Qt.red)
70
- elif port_value != 0:
71
- max_value = 2**bus_width - 1
72
- color = pen.color()
73
- green = color.green()
74
- full_range = 255 - green
75
- color.setGreen(green + (full_range * port_value / max_value))
76
- pen.setColor(color)
79
+ elif self._app_model.settings.get("color_wires"):
80
+ port_value = self._src_port.value
81
+ pen.setColor(self._get_wire_color(port_value, bus_width))
82
+
77
83
  painter.setPen(pen)
78
84
  painter.drawLine(self._start, self._end)
79
85
 
@@ -82,6 +88,7 @@ class WireGraphicsItem(QGraphicsPathItem):
82
88
  """A wire graphics item"""
83
89
 
84
90
  WIRE_TO_COMPONENT_DIST = 5
91
+ X_OFFSET = 10
85
92
 
86
93
  def __init__(self, app_model, connection, src_port_item, dst_port_item):
87
94
  super().__init__()
@@ -116,14 +123,14 @@ class WireGraphicsItem(QGraphicsPathItem):
116
123
  def create_points(cls, source, dest, rect):
117
124
  """Create a wire path"""
118
125
  points = []
119
-
120
126
  points.append(source)
127
+
121
128
  if source.x() < dest.x():
122
129
  half_dist_x = (dest.x() - source.x()) / 2
123
130
  points.append(QPointF(source.x() + half_dist_x, source.y()))
124
131
  points.append(QPointF(source.x() + half_dist_x, dest.y()))
125
132
  else:
126
- half_dist_y = dest.y() - (dest.y() - source.y()) / 2
133
+ half_dist_y = (source.y() + dest.y()) / 2
127
134
  if dest.y() < source.y():
128
135
  comp_top = rect.y() - cls.WIRE_TO_COMPONENT_DIST
129
136
  y_mid = min(comp_top, half_dist_y)
@@ -131,10 +138,11 @@ class WireGraphicsItem(QGraphicsPathItem):
131
138
  comp_bottom = rect.y() + rect.height() + cls.WIRE_TO_COMPONENT_DIST
132
139
  y_mid = max(comp_bottom, half_dist_y)
133
140
 
134
- points.append(QPointF(source.x() + 10, source.y()))
135
- points.append(QPointF(source.x() + 10, y_mid))
136
- points.append(QPointF(dest.x() - 10, y_mid))
137
- points.append(QPointF(dest.x() - 10, dest.y()))
141
+ points.append(QPointF(source.x() + cls.X_OFFSET, source.y()))
142
+ points.append(QPointF(source.x() + cls.X_OFFSET, y_mid))
143
+ points.append(QPointF(dest.x() - cls.X_OFFSET, y_mid))
144
+ points.append(QPointF(dest.x() - cls.X_OFFSET, dest.y()))
145
+
138
146
  points.append(dest)
139
147
  return points
140
148
 
@@ -315,6 +323,9 @@ class _CircuitAreaScene(QGraphicsScene):
315
323
  class CircuitArea(QGraphicsView):
316
324
  """The circuit area graphics view"""
317
325
 
326
+ ZOOM_IN_FACTOR = 1.25
327
+ ZOOM_OUT_FACTOR = 0.8
328
+
318
329
  def __init__(self, app_model, parent):
319
330
  super().__init__(parent=parent)
320
331
  self._app_model = app_model
@@ -333,10 +344,10 @@ class CircuitArea(QGraphicsView):
333
344
  return len(self._scene.selectedItems()) > 0
334
345
 
335
346
  def _zoom_in(self):
336
- self.scale(1.25, 1.25)
347
+ self.scale(self.ZOOM_IN_FACTOR, self.ZOOM_IN_FACTOR)
337
348
 
338
349
  def _zoom_out(self):
339
- self.scale(0.8, 0.8)
350
+ self.scale(self.ZOOM_OUT_FACTOR, self.ZOOM_OUT_FACTOR)
340
351
 
341
352
  def _repaint(self):
342
353
  """Make scene repaint for component update"""
@@ -40,6 +40,8 @@ class SelectableComponentWidget(QPushButton):
40
40
  mime.setText(self._name)
41
41
  drag.setMimeData(mime)
42
42
  drag.setHotSpot(event.pos() - self.rect().topLeft())
43
+ # Create a square pixmap for dragging, using the widget's width for both dimensions.
44
+ # This is intentional to maintain a consistent visual representation during drag operations.
43
45
  pixmap = QPixmap(self.size().width(), self.size().width())
44
46
  self.render(pixmap)
45
47
  drag.setPixmap(pixmap)
@@ -4,4 +4,4 @@
4
4
  """All classes within digsim.app.gui_object namespace"""
5
5
 
6
6
  from ._component_object import ComponentObject # noqa: F401
7
- from ._gui_object_factory import get_class_by_name as class_factory # noqa: F401
7
+ from ._gui_object_factory import class_factory # noqa: F401
@@ -66,12 +66,7 @@ class BuzzerObject(ImageObjectWithActiveRect):
66
66
  self.audio_sink = None
67
67
  self._app_model.sig_audio_start.connect(self._audio_start)
68
68
  self._app_model.sig_audio_notify.connect(self._audio_notify)
69
- self.device = None
70
- devices = QMediaDevices.audioOutputs()
71
- if len(devices) == 0:
72
- return
73
- self.device = devices[0]
74
-
69
+ self.device = QMediaDevices.defaultAudioOutput()
75
70
  self.audio_format = QAudioFormat()
76
71
  self.audio_format.setSampleRate(self.DATA_SAMPLE_RATE_HZ)
77
72
  self.audio_format.setChannelCount(1)
@@ -92,11 +87,11 @@ class BuzzerObject(ImageObjectWithActiveRect):
92
87
  if self.device is None:
93
88
  return
94
89
  if active:
95
- self.audio_sink = QAudioSink(self.device, self.audio_format)
96
- self.audio_sink.setVolume(0.1)
90
+ if self.audio_sink is None:
91
+ self.audio_sink = QAudioSink(self.device, self.audio_format)
92
+ self.audio_sink.setVolume(0.1)
97
93
  self.audio_sink.start(self.audio_output)
98
94
  else:
99
- if self.audio_sink is None:
100
- return
101
- self.audio_sink.stop()
102
- self.audio_sink = None
95
+ if self.audio_sink is not None:
96
+ self.audio_sink.stop()
97
+ self.audio_sink = None
@@ -18,7 +18,7 @@ class ComponentContextMenu(QMenu):
18
18
  self._app_model = app_model
19
19
  self._component_object = component_object
20
20
  self._component = self._component_object.component
21
- self._reconfigurable_parameters = None
21
+ self._reconfigurable_parameters = {}
22
22
  # Title
23
23
  titleAction = QAction(self._component.display_name(), self)
24
24
  titleAction.setEnabled(False)
@@ -25,6 +25,10 @@ class ComponentObject(QGraphicsRectItem):
25
25
  PORT_SIDE = 8
26
26
  DEFAULT_PORT_TO_PORT_DISTANCE = 20
27
27
 
28
+ _COMPONENT_NAME_FONT = QFont("Arial", 10)
29
+ _PORT_NAME_FONT = QFont("Arial", 8)
30
+ _SELECTABLE_COMPONENT_NAME_FONT = QFont("Arial", 8)
31
+
28
32
  def __init__(
29
33
  self, app_model, component, xpos, ypos, port_distance=DEFAULT_PORT_TO_PORT_DISTANCE
30
34
  ):
@@ -237,9 +241,8 @@ class ComponentObject(QGraphicsRectItem):
237
241
 
238
242
  def paint_component_name(self, painter):
239
243
  """Paint the component name"""
240
- font = QFont("Arial", 10)
241
- painter.setFont(font)
242
- fm = QFontMetrics(font)
244
+ painter.setFont(self._COMPONENT_NAME_FONT)
245
+ fm = QFontMetrics(self._COMPONENT_NAME_FONT)
243
246
  display_name_str = self._component.display_name()
244
247
  str_pixels_w = fm.horizontalAdvance(display_name_str)
245
248
  str_pixels_h = fm.height()
@@ -278,11 +281,10 @@ class ComponentObject(QGraphicsRectItem):
278
281
  @classmethod
279
282
  def paint_selectable_component_name(cls, painter, point, size, name):
280
283
  """Paint the name for the selectable component"""
281
- font = QFont("Arial", 8)
282
- fm = QFontMetrics(font)
284
+ painter.setFont(cls._SELECTABLE_COMPONENT_NAME_FONT)
285
+ fm = QFontMetrics(cls._SELECTABLE_COMPONENT_NAME_FONT)
283
286
  str_pixels_w = fm.horizontalAdvance(name)
284
287
  str_pixels_h = fm.height()
285
- painter.setFont(font)
286
288
  painter.setPen(Qt.black)
287
289
  painter.drawText(
288
290
  point.x() + size.width() / 2 - str_pixels_w / 2,
@@ -297,12 +299,11 @@ class ComponentObject(QGraphicsRectItem):
297
299
  def paint_portnames(self, painter, color=Qt.black):
298
300
  """Paint component ports"""
299
301
  painter.setPen(color)
300
- font = QFont("Arial", 8)
301
- painter.setFont(font)
302
+ painter.setFont(self._PORT_NAME_FONT)
302
303
  for port in self._component.ports:
303
304
  rect = self.get_port_item(port).rect()
304
305
  port_str = self._port_dict[port]["name"]
305
- str_pixels_w, str_pixels_h = self.get_string_metrics(port_str, font)
306
+ str_pixels_w, str_pixels_h = self.get_string_metrics(port_str, self._PORT_NAME_FONT)
306
307
  text_y = rect.y() + str_pixels_h - self.PORT_SIDE / 2
307
308
  if rect.x() < self.object_pos.x():
308
309
  text_pos = QPoint(rect.x() + self.inport_x_pos(), text_y)
@@ -44,7 +44,6 @@ class PortGraphicsItem(QGraphicsRectItem):
44
44
  return
45
45
  self.setBrush(QBrush(Qt.black))
46
46
  self.setCursor(Qt.CrossCursor)
47
- self._repaint()
48
47
 
49
48
  def hoverLeaveEvent(self, _):
50
49
  """QT event callback function"""
@@ -52,7 +51,6 @@ class PortGraphicsItem(QGraphicsRectItem):
52
51
  return
53
52
  self.setBrush(QBrush(Qt.gray))
54
53
  self.setCursor(Qt.ArrowCursor)
55
- self._repaint()
56
54
 
57
55
  def portParentRect(self):
58
56
  """return the parent rect"""
@@ -16,6 +16,8 @@ class DipSwitchObject(ImageObject):
16
16
  DIP_SWITCH_WIDTH = 20
17
17
  DIP_SWITCH_HEIGHT = 10
18
18
 
19
+ _DIP_SWITCH_FONT = QFont("Arial", 8)
20
+
19
21
  def __init__(self, app_model, component, xpos, ypos):
20
22
  super().__init__(app_model, component, xpos, ypos, port_distance=self.DIP_SWITCH_HEIGHT)
21
23
  self.width = 2.5 * self.DIP_SWITCH_WIDTH
@@ -77,17 +79,16 @@ class DipSwitchObject(ImageObject):
77
79
  painter.drawRect(
78
80
  rect.x() + 1, rect.y() + 1, rect.width() / 2 - 2, rect.height() - 2
79
81
  )
80
- font = QFont("Arial", 8)
81
- painter.setFont(font)
82
+ painter.setFont(self._DIP_SWITCH_FONT)
82
83
  painter.setPen(Qt.white)
83
84
  for idx, rect in enumerate(self._rects):
84
85
  port_str = f"{idx + 1}"
85
- str_pixels_w, _ = self.get_string_metrics(port_str, font)
86
+ str_pixels_w, _ = self.get_string_metrics(port_str, self._DIP_SWITCH_FONT)
86
87
  painter.drawText(
87
88
  QPoint(rect.x() - str_pixels_w - 4, rect.y() + rect.height() - 1), port_str
88
89
  )
89
90
 
90
- _, str_h = self.get_string_metrics("ON", font)
91
+ _, str_h = self.get_string_metrics("ON", self._DIP_SWITCH_FONT)
91
92
  painter.drawText(
92
93
  self.rect().x() + self.rect().width() / 2,
93
94
  self.rect().y() + self.BORDER_TO_PORT - str_h,
@@ -16,16 +16,18 @@ class GuiNoteObject(ComponentObject):
16
16
  NOTE_MINIMUM_WIDTH = 50
17
17
  NOTE_MINIMUM_HEIGHT = 20
18
18
 
19
+ _NOTE_FONT = QFont("Arial", 8)
20
+ _NOTE_PEN = QPen(Qt.black)
21
+
19
22
  def __init__(self, app_model, component, xpos, ypos):
20
23
  super().__init__(app_model, component, xpos, ypos)
21
- self._font = QFont("Arial", 8)
22
24
  self.update_size()
23
25
 
24
26
  def _get_lines(self):
25
27
  return self.component.parameter_get("text").split("\n")
26
28
 
27
29
  def update_size(self):
28
- fm = QFontMetrics(self._font)
30
+ fm = QFontMetrics(self._NOTE_FONT)
29
31
  width = self.NOTE_MINIMUM_WIDTH
30
32
  lines = self._get_lines()
31
33
  for line in lines:
@@ -39,19 +41,18 @@ class GuiNoteObject(ComponentObject):
39
41
 
40
42
  def paint_component(self, painter):
41
43
  """Paint note rectangle"""
42
- fm = QFontMetrics(self._font)
44
+ fm = QFontMetrics(self._NOTE_FONT)
43
45
  lines = self._get_lines()
44
- pen = QPen()
46
+ pen = self._NOTE_PEN
45
47
  if self.selected:
46
48
  pen.setWidth(4)
47
49
  else:
48
50
  pen.setWidth(1)
49
- pen.setColor(Qt.black)
50
51
  painter.setPen(pen)
51
52
  painter.setBrush(Qt.SolidPattern)
52
53
  painter.setBrush(Qt.yellow)
53
54
  painter.drawRect(self.rect())
54
- painter.setFont(self._font)
55
+ painter.setFont(self._NOTE_FONT)
55
56
  for idx, line in enumerate(lines):
56
57
  painter.drawText(
57
58
  self.object_pos.x() + self.NOTE_BORDER,
@@ -67,15 +68,13 @@ class GuiNoteObject(ComponentObject):
67
68
  size.width() - 2 * cls.NOTE_BORDER,
68
69
  size.width() - 2 * cls.NOTE_BORDER,
69
70
  )
70
- pen = QPen()
71
+ pen = cls._NOTE_PEN
71
72
  pen.setWidth(1)
72
- pen.setColor(Qt.black)
73
73
  painter.setPen(pen)
74
74
  painter.setBrush(Qt.SolidPattern)
75
75
  painter.setBrush(Qt.yellow)
76
76
  painter.drawRect(note_rect)
77
- font = QFont("Arial", 8)
78
- fm = QFontMetrics(font)
79
- painter.setFont(font)
77
+ painter.setFont(cls._NOTE_FONT)
78
+ fm = QFontMetrics(cls._NOTE_FONT)
80
79
  painter.drawText(2 * cls.NOTE_BORDER, 2 * cls.NOTE_BORDER + fm.height(), "abc..")
81
80
  cls.paint_selectable_component_name(painter, QPoint(0, 0), size, name)
@@ -70,7 +70,7 @@ CLASS_NAME_TO_COMPONENT_OBJECT = {
70
70
  }
71
71
 
72
72
 
73
- def get_class_by_name(component_class_name):
73
+ def class_factory(component_class_name):
74
74
  """A function that returns the GUI for a component class (str or class)"""
75
75
 
76
76
  if component_class_name in CLASS_NAME_TO_COMPONENT_OBJECT:
@@ -165,6 +165,8 @@ class ImageObjectStaticValue(ImageObject):
165
165
  IMAGE_FILENAME = "images/ZERO.png"
166
166
  ACTIVE_IMAGE_FILENAME = "images/ONE.png"
167
167
 
168
+ _STATIC_VALUE_FONT = QFont("Arial", 16)
169
+
168
170
  def __init__(self, app_model, component, xpos, ypos):
169
171
  super().__init__(app_model, component, xpos, ypos)
170
172
  self.show_name(False)
@@ -174,10 +176,9 @@ class ImageObjectStaticValue(ImageObject):
174
176
  super().paint_component(painter)
175
177
  else:
176
178
  self.paint_component_base(painter)
177
- font = QFont("Arial", 16)
178
179
  value_str = f"{self.component.parameter_get('value')}"
179
- str_w, str_h = self.get_string_metrics(value_str, font=font)
180
- painter.setFont(font)
180
+ str_w, str_h = self.get_string_metrics(value_str, font=self._STATIC_VALUE_FONT)
181
+ painter.setFont(self._STATIC_VALUE_FONT)
181
182
  painter.drawText(
182
183
  self.rect().x() + self.rect().width() / 2 - str_w / 2,
183
184
  self.rect().y() + str_h,
@@ -213,6 +214,8 @@ class ImageObjectWithActiveRect(ImageObject):
213
214
  When active the image will have a green border painted around it.
214
215
  """
215
216
 
217
+ _ACTIVE_RECT_PEN = QPen(Qt.green)
218
+
216
219
  def __init__(self, app_model, component, xpos, ypos):
217
220
  super().__init__(app_model, component, xpos, ypos)
218
221
  self.show_name(False)
@@ -223,9 +226,8 @@ class ImageObjectWithActiveRect(ImageObject):
223
226
  if self.component.active:
224
227
  xpos = self.object_pos.x() + self.size.width() / 2 - self._pixmap.width() / 2
225
228
  ypos = self.object_pos.y() + self.size.height() / 2 - self._pixmap.height() / 2
226
- pen = QPen()
229
+ pen = self._ACTIVE_RECT_PEN
227
230
  pen.setWidth(4)
228
- pen.setColor(Qt.green)
229
231
  painter.setPen(pen)
230
232
  painter.setBrush(Qt.NoBrush)
231
233
  painter.drawRoundedRect(xpos, ypos, self._pixmap.width(), self._pixmap.height(), 5, 5)
@@ -12,6 +12,8 @@ from ._component_object import ComponentObject
12
12
  class LabelObject(ComponentObject):
13
13
  """The class for a bus/bit component placed in the GUI"""
14
14
 
15
+ _LABEL_PEN = QPen(Qt.black)
16
+
15
17
  def __init__(self, app_model, component, xpos, ypos):
16
18
  super().__init__(app_model, component, xpos, ypos)
17
19
  label = component.label()
@@ -35,12 +37,11 @@ class LabelObject(ComponentObject):
35
37
 
36
38
  @classmethod
37
39
  def _paint_label(cls, painter, comp_rect, name, selected=False):
38
- pen = QPen()
40
+ pen = cls._LABEL_PEN
39
41
  if selected:
40
42
  pen.setWidth(4)
41
43
  else:
42
44
  pen.setWidth(1)
43
- pen.setColor(Qt.black)
44
45
  painter.setPen(pen)
45
46
  painter.setBrush(Qt.SolidPattern)
46
47
  painter.setBrush(Qt.gray)
@@ -17,6 +17,10 @@ class LogicAnalyzerObject(ImageObject):
17
17
  SIGNAL_NAME_WIDTH = 40
18
18
  ANALYZER_DISPLAY_WIDTH = 200
19
19
 
20
+ _ANALYZER_PEN = QPen(Qt.green)
21
+ _SIGNAL_VERTICAL_SCALE = 10
22
+ _SIGNAL_HORIZONTAL_SCALE = 2
23
+
20
24
  def __init__(self, app_model, component, xpos, ypos):
21
25
  super().__init__(app_model, component, xpos, ypos)
22
26
  self.width = self.SIGNAL_NAME_WIDTH + self.ANALYZER_DISPLAY_WIDTH + 2 * self.RECT_TO_BORDER
@@ -37,8 +41,7 @@ class LogicAnalyzerObject(ImageObject):
37
41
  5,
38
42
  )
39
43
 
40
- pen = QPen()
41
- pen.setColor(Qt.green)
44
+ pen = self._ANALYZER_PEN
42
45
  pen.setWidth(2)
43
46
  painter.setPen(pen)
44
47
  signal_data_dict = self.component.signal_data()
@@ -48,7 +51,7 @@ class LogicAnalyzerObject(ImageObject):
48
51
  path = QPainterPath(
49
52
  QPoint(
50
53
  self.object_pos.x() + self.SIGNAL_NAME_WIDTH,
51
- port_pos.y() - signal_data[0] * 10,
54
+ port_pos.y() - signal_data[0] * self._SIGNAL_VERTICAL_SCALE,
52
55
  )
53
56
  )
54
57
  last_level = signal_data[0]
@@ -57,21 +60,27 @@ class LogicAnalyzerObject(ImageObject):
57
60
  continue
58
61
  path.lineTo(
59
62
  QPoint(
60
- self.object_pos.x() + self.SIGNAL_NAME_WIDTH + (idx + 1) * 2,
61
- port_pos.y() - last_level * 10,
63
+ self.object_pos.x()
64
+ + self.SIGNAL_NAME_WIDTH
65
+ + (idx + 1) * self._SIGNAL_HORIZONTAL_SCALE,
66
+ port_pos.y() - last_level * self._SIGNAL_VERTICAL_SCALE,
62
67
  )
63
68
  )
64
69
  path.lineTo(
65
70
  QPoint(
66
- self.object_pos.x() + self.SIGNAL_NAME_WIDTH + (idx + 1) * 2,
67
- port_pos.y() - level * 10,
71
+ self.object_pos.x()
72
+ + self.SIGNAL_NAME_WIDTH
73
+ + (idx + 1) * self._SIGNAL_HORIZONTAL_SCALE,
74
+ port_pos.y() - level * self._SIGNAL_VERTICAL_SCALE,
68
75
  )
69
76
  )
70
77
  last_level = level
71
78
  path.lineTo(
72
79
  QPoint(
73
- self.object_pos.x() + self.SIGNAL_NAME_WIDTH + len(signal_data) * 2,
74
- port_pos.y() - last_level * 10,
80
+ self.object_pos.x()
81
+ + self.SIGNAL_NAME_WIDTH
82
+ + len(signal_data) * self._SIGNAL_HORIZONTAL_SCALE,
83
+ port_pos.y() - last_level * self._SIGNAL_VERTICAL_SCALE,
75
84
  )
76
85
  )
77
86
  painter.drawPath(path)
@@ -47,6 +47,10 @@ class SevenSegmentObject(ComponentObject):
47
47
  DIGIT_WIDTH = 54
48
48
  DIGIT_HEIGHT = 80
49
49
 
50
+ DOT_OFFSET_X = 40
51
+ DOT_OFFSET_Y = 60
52
+ DOT_RADIUS = 3
53
+
50
54
  def __init__(self, app_model, component, xpos, ypos, port_distance=10):
51
55
  super().__init__(app_model, component, xpos, ypos, port_distance=port_distance)
52
56
  self.setup_size()
@@ -89,7 +93,6 @@ class SevenSegmentObject(ComponentObject):
89
93
  """Paint the digit background"""
90
94
  painter.setBrush(Qt.SolidPattern)
91
95
  painter.setPen(Qt.black)
92
- painter.setBrush(Qt.black)
93
96
  painter.drawRoundedRect(xpos, ypos, cls.DIGIT_WIDTH * digits, cls.DIGIT_HEIGHT, 4, 4)
94
97
 
95
98
  @classmethod
@@ -114,11 +117,15 @@ class SevenSegmentObject(ComponentObject):
114
117
  path.closeSubpath()
115
118
  painter.drawPath(path)
116
119
 
120
+ DOT_OFFSET_X = 40
121
+ DOT_OFFSET_Y = 60
122
+ DOT_RADIUS = 3
123
+
117
124
  if "." in active_segments:
118
125
  painter.setPen(Qt.red)
119
126
  painter.setBrush(Qt.red)
120
127
  else:
121
128
  painter.setPen(Qt.darkRed)
122
129
  painter.setBrush(Qt.darkRed)
123
- dotPoint = QPoint(40, 60) + start_point
124
- painter.drawEllipse(dotPoint, 3, 3)
130
+ dotPoint = QPoint(DOT_OFFSET_X, DOT_OFFSET_Y) + start_point
131
+ painter.drawEllipse(dotPoint, DOT_RADIUS, DOT_RADIUS)
@@ -37,6 +37,8 @@ class ButtonObject(ImageObject):
37
37
  IMAGE_FILENAME = "images/PB.png"
38
38
  BUTTON_RADIUS = 35
39
39
 
40
+ _BUTTON_ACTIVE_PEN = QPen(Qt.green)
41
+
40
42
  def __init__(self, app_model, component, xpos, ypos):
41
43
  super().__init__(app_model, component, xpos, ypos)
42
44
  self.show_name(False)
@@ -45,9 +47,8 @@ class ButtonObject(ImageObject):
45
47
  def paint_component(self, painter):
46
48
  super().paint_component(painter)
47
49
  if self.component.active:
48
- pen = QPen()
50
+ pen = self._BUTTON_ACTIVE_PEN
49
51
  pen.setWidth(4)
50
- pen.setColor(Qt.green)
51
52
  painter.setPen(pen)
52
53
  painter.setBrush(Qt.NoBrush)
53
54
  painter.drawEllipse(
@@ -37,15 +37,18 @@ class AppModel(QThread):
37
37
 
38
38
  def __init__(self):
39
39
  super().__init__()
40
- self._model_objects = ModelObjects(self)
41
- self._model_shortcuts = ModelShortcuts(self)
42
- self._model_settings = ModelSettings(self)
40
+ self._setup_model_components()
43
41
  self._started = False
44
42
  self._single_step = False
45
43
  self._changed = False
46
44
  self._gui_event_queue = queue.Queue()
47
45
  self._multi_select = False
48
46
 
47
+ def _setup_model_components(self):
48
+ self._model_objects = ModelObjects(self)
49
+ self._model_shortcuts = ModelShortcuts(self)
50
+ self._model_settings = ModelSettings(self)
51
+
49
52
  @property
50
53
  def objects(self):
51
54
  """return the model objects"""
@@ -100,6 +103,7 @@ class AppModel(QThread):
100
103
  def model_stop(self):
101
104
  """Stop model simulation thread"""
102
105
  self._started = False
106
+ self.wait()
103
107
 
104
108
  def model_reset(self):
105
109
  """Reset model simulation"""
@@ -125,10 +125,7 @@ class ModelComponents:
125
125
 
126
126
  def get_object_list(self):
127
127
  """Get list of component objects"""
128
- component_objects = []
129
- for _, comp in self._component_objects.items():
130
- component_objects.append(comp)
131
- return component_objects
128
+ return list(self._component_objects.values())
132
129
 
133
130
  def update_settings(self, component_object, settings):
134
131
  """Update settings for a component"""
@@ -29,11 +29,12 @@ class NewWire:
29
29
 
30
30
  def end(self, component, portname):
31
31
  """End new wire object"""
32
- self._app_model.objects.push_undo_state()
33
32
  end_port = component.port(portname)
34
33
  if self._start_port.is_output() and end_port.is_input():
34
+ self._app_model.objects.push_undo_state()
35
35
  self._start_port.wire = end_port
36
36
  elif self._start_port.is_input() and end_port.is_output():
37
+ self._app_model.objects.push_undo_state()
37
38
  end_port.wire = self._start_port
38
39
  else:
39
40
  raise PortConnectionError("Cannot connect to port of same type")