statable 3.1.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.
Files changed (117) hide show
  1. codegen/__init__.py +38 -0
  2. codegen/c_code_generator.py +1752 -0
  3. codegen/code_merger.py +371 -0
  4. codegen/code_templates.py +509 -0
  5. codegen/config.py +167 -0
  6. codegen/enum_generator.py +377 -0
  7. codegen/event_queue_generator.py +303 -0
  8. codegen/interrupt_generator.py +345 -0
  9. codegen/naming_convention.py +171 -0
  10. codegen/osal_generator.py +282 -0
  11. codegen/role_function_generator.py +1244 -0
  12. codegen/sample_data.py +269 -0
  13. codegen/state_actions_generator.py +395 -0
  14. codegen/struct_generator.py +721 -0
  15. codegen/timer_generator.py +299 -0
  16. codegen/transition_generator.py +907 -0
  17. codegen/type_mapper.py +69 -0
  18. codegen/validate/__init__.py +38 -0
  19. codegen/validate/change_actions.py +90 -0
  20. codegen/validate/change_applier.py +416 -0
  21. codegen/validate/clipboard_manager.py +47 -0
  22. codegen/validate/data/__init__.py +30 -0
  23. codegen/validate/data/action_definitions.py +200 -0
  24. codegen/validate/data/keywords.py +46 -0
  25. codegen/validate/data/prompt_templates.py +176 -0
  26. codegen/validate/data/validation_rules.py +205 -0
  27. codegen/validate/items/__init__.py +30 -0
  28. codegen/validate/items/base_validator.py +25 -0
  29. codegen/validate/items/cell_validator.py +275 -0
  30. codegen/validate/items/custom_type_validator.py +75 -0
  31. codegen/validate/items/event_validator.py +78 -0
  32. codegen/validate/items/flag_validator.py +74 -0
  33. codegen/validate/items/interrupt_validator.py +75 -0
  34. codegen/validate/items/queue_validator.py +73 -0
  35. codegen/validate/items/role_function_validator.py +175 -0
  36. codegen/validate/items/state_validator.py +88 -0
  37. codegen/validate/items/timer_validator.py +120 -0
  38. codegen/validate/items/transition_validator.py +113 -0
  39. codegen/validate/items/variable_validator.py +132 -0
  40. codegen/validate/logger.py +52 -0
  41. codegen/validate/models.py +177 -0
  42. codegen/validate/prompt_generator.py +724 -0
  43. codegen/validate/response_parser.py +154 -0
  44. codegen/validate/response_validator.py +275 -0
  45. codegen/validate/validation_dialog.py +322 -0
  46. codegen/validate/validator.py +94 -0
  47. codegen/variable_generator.py +419 -0
  48. statable/__init__.py +71 -0
  49. statable/__main__.py +49 -0
  50. statable/cli.py +251 -0
  51. statable/global_defs.py +256 -0
  52. statable/mermaid_gen.py +144 -0
  53. statable/model.py +426 -0
  54. statable/parser.py +64 -0
  55. statable/sample_data.py +435 -0
  56. statable/shared/__init__.py +24 -0
  57. statable/shared/condition_library.py +63 -0
  58. statable/shared/literal_library.py +66 -0
  59. statable/shared/role_function_library.py +150 -0
  60. statable/state_machine.py +121 -0
  61. statable/xml_io.py +1164 -0
  62. statable-3.1.0.dist-info/METADATA +151 -0
  63. statable-3.1.0.dist-info/RECORD +117 -0
  64. statable-3.1.0.dist-info/WHEEL +5 -0
  65. statable-3.1.0.dist-info/entry_points.txt +2 -0
  66. statable-3.1.0.dist-info/top_level.txt +3 -0
  67. statable_gui/__init__.py +23 -0
  68. statable_gui/action_edit_dialog.py +214 -0
  69. statable_gui/code_generation_dialog.py +486 -0
  70. statable_gui/code_generation_settings_dialog.py +522 -0
  71. statable_gui/common_widgets.py +537 -0
  72. statable_gui/condition_builder_dialog.py +500 -0
  73. statable_gui/condition_edit_dialog.py +123 -0
  74. statable_gui/condition_template_dialog.py +58 -0
  75. statable_gui/config.py +21 -0
  76. statable_gui/dialogs.py +439 -0
  77. statable_gui/event_definition_dialog.py +605 -0
  78. statable_gui/event_delivery_settings_dialog.py +191 -0
  79. statable_gui/event_queue_dialog.py +245 -0
  80. statable_gui/global_defs.py +167 -0
  81. statable_gui/global_defs_dialog.py +796 -0
  82. statable_gui/i18n/__init__.py +118 -0
  83. statable_gui/interrupt_handler_edit_dialog.py +810 -0
  84. statable_gui/layer_settings_dialog.py +180 -0
  85. statable_gui/libcntrl/__init__.py +23 -0
  86. statable_gui/libcntrl/condition_library.py +13 -0
  87. statable_gui/libcntrl/literal_library.py +13 -0
  88. statable_gui/libcntrl/literal_management_dialog.py +185 -0
  89. statable_gui/libcntrl/role_function_edit_dialog.py +145 -0
  90. statable_gui/libcntrl/role_function_library.py +13 -0
  91. statable_gui/literal_definition_dialog.py +62 -0
  92. statable_gui/logger.py +83 -0
  93. statable_gui/main_window.py +1380 -0
  94. statable_gui/matrix_table.py +413 -0
  95. statable_gui/preference_keys.py +18 -0
  96. statable_gui/preferences.py +74 -0
  97. statable_gui/role_function_dialog.py +244 -0
  98. statable_gui/sample_data.py +11 -0
  99. statable_gui/state_actions_dialog.py +398 -0
  100. statable_gui/symbol_picker.py +170 -0
  101. statable_gui/traceball.py +37 -0
  102. statable_gui/transition_editor_direct/__init__.py +15 -0
  103. statable_gui/transition_editor_direct/actions_tab.py +856 -0
  104. statable_gui/transition_editor_direct/code_widget.py +344 -0
  105. statable_gui/transition_editor_direct/coverage_analyzer.py +163 -0
  106. statable_gui/transition_editor_direct/dialog.py +335 -0
  107. statable_gui/transition_editor_direct/draft.py +270 -0
  108. statable_gui/transition_editor_direct/edit_dialogs.py +160 -0
  109. statable_gui/transition_editor_direct/overview_tab.py +173 -0
  110. statable_gui/transition_editor_direct/palette_widget.py +233 -0
  111. statable_gui/transition_editor_direct/relations_edit_dialog.py +156 -0
  112. statable_gui/transition_editor_direct/relations_tab.py +230 -0
  113. statable_gui/transition_editor_direct/system_global_dialog.py +52 -0
  114. statable_gui/transition_editor_direct/transition_actions_dialog.py +109 -0
  115. statable_gui/transition_editor_direct/transitions_tab.py +620 -0
  116. statable_gui/validation_dialog.py +285 -0
  117. statable_gui/widgets.py +1315 -0
@@ -0,0 +1,170 @@
1
+ from PySide6.QtCore import Qt, Signal
2
+ from PySide6.QtWidgets import (
3
+ QWidget, QVBoxLayout, QHBoxLayout, QLineEdit, QListWidget,
4
+ QListWidgetItem, QPushButton, QLabel, QDialog
5
+ )
6
+ from PySide6.QtGui import QFont
7
+
8
+ from statable.global_defs import GlobalDefinitions
9
+ from .global_defs_dialog import VariableEditDialog, FlagEditDialog, GlobalDefinitionsDialog
10
+ from .logger import StaTableLogger
11
+
12
+
13
+ class SymbolPickerWidget(QWidget):
14
+ """Common widget for selecting global variables, event flags, and role function return values"""
15
+
16
+ insert_requested = Signal(str)
17
+
18
+ def __init__(self, parent=None, global_defs=None, role_functions=None):
19
+ super().__init__(parent)
20
+ self.global_defs = global_defs if global_defs else GlobalDefinitions()
21
+ self.role_functions = role_functions if role_functions is not None else {}
22
+
23
+ layout = QVBoxLayout(self)
24
+
25
+ # Title
26
+ title = QLabel(self.tr("Global variables, event flags, and return values"))
27
+ title.setFont(QFont("sans-serif", 10, QFont.Bold))
28
+ layout.addWidget(title)
29
+
30
+ # Search
31
+ search_label = QLabel(self.tr("Search (prefix match):"))
32
+ layout.addWidget(search_label)
33
+ self.search_edit = QLineEdit()
34
+ self.search_edit.setPlaceholderText(self.tr("Enter title, member name, and group name"))
35
+ self.search_edit.textChanged.connect(self.refresh_list)
36
+ layout.addWidget(self.search_edit)
37
+
38
+ # List
39
+ self.list_widget = QListWidget()
40
+ self.list_widget.itemDoubleClicked.connect(self._on_item_double_clicked)
41
+ layout.addWidget(self.list_widget, stretch=1)
42
+
43
+ # Register button
44
+ btn_layout = QHBoxLayout()
45
+ add_var_btn = QPushButton(self.tr("Register variable..."))
46
+ add_var_btn.clicked.connect(self.register_variable)
47
+ btn_layout.addWidget(add_var_btn)
48
+
49
+ add_flag_btn = QPushButton(self.tr("Register flag..."))
50
+ add_flag_btn.clicked.connect(self.register_flag)
51
+ btn_layout.addWidget(add_flag_btn)
52
+ layout.addLayout(btn_layout)
53
+
54
+ # Open global definitions
55
+ open_defs_btn = QPushButton(self.tr("Open global definitions..."))
56
+ open_defs_btn.clicked.connect(self.open_global_definitions)
57
+ layout.addWidget(open_defs_btn)
58
+
59
+ self.refresh_list()
60
+ StaTableLogger.debug("SymbolPickerWidget initialized")
61
+
62
+ # ------------------------------------------------------------------
63
+ # Refresh list
64
+ # ------------------------------------------------------------------
65
+ def refresh_list(self):
66
+ query = self.search_edit.text().strip().lower() if hasattr(self, 'search_edit') else ""
67
+ StaTableLogger.debug(f"SymbolPickerWidget.refresh_list: query='{query}'")
68
+
69
+ self.list_widget.clear()
70
+
71
+ # Global variables
72
+ for var in self.global_defs.variables:
73
+ if self._matches(var.title, var.name, var.group, query):
74
+ item = QListWidgetItem(f"Variable: {var.title}")
75
+ item.setData(Qt.UserRole, var.name)
76
+ item.setToolTip(
77
+ f"Kind: Global variable\n"
78
+ f"Title: {var.title}\n"
79
+ f"Name: {var.name}\n"
80
+ f"Type: {var.type}\n"
81
+ f"Unit: {var.unit}\n"
82
+ f"Initial value: {var.default_value}\n"
83
+ f"Group: {var.group}\n"
84
+ f"Description: {var.description}"
85
+ )
86
+ self.list_widget.addItem(item)
87
+
88
+ # Event flags
89
+ for flag in self.global_defs.flags:
90
+ if self._matches(flag.title, flag.name, flag.group, query):
91
+ item = QListWidgetItem(f"Flag: {flag.title}")
92
+ item.setData(Qt.UserRole, flag.name)
93
+ item.setToolTip(
94
+ f"Kind: Event flag\n"
95
+ f"Title: {flag.title}\n"
96
+ f"Name: {flag.name}\n"
97
+ f"Min value: {flag.min_value}\n"
98
+ f"Max value: {flag.max_value}\n"
99
+ f"Bit width: {flag.bit_width} bit\n"
100
+ f"Group: {flag.group}\n"
101
+ f"Description: {flag.description}"
102
+ )
103
+ self.list_widget.addItem(item)
104
+
105
+ # Role function return value (temp variable)
106
+ for func_name in self.role_functions.keys():
107
+ temp_var = f"rv_{func_name}"
108
+ if self._matches(temp_var, func_name, "", query):
109
+ item = QListWidgetItem(f"Return value: {temp_var}")
110
+ item.setData(Qt.UserRole, temp_var)
111
+ item.setToolTip(
112
+ f"Kind: Role function return value\n"
113
+ f"Function: {func_name}\n"
114
+ f"Temp variable: {temp_var}"
115
+ )
116
+ self.list_widget.addItem(item)
117
+
118
+ StaTableLogger.debug(f"SymbolPickerWidget: {self.list_widget.count()} items displayed")
119
+
120
+ def _matches(self, title: str, name: str, group: str, query: str) -> bool:
121
+ if not query:
122
+ return True
123
+ q = query.lower()
124
+ return (
125
+ title.lower().startswith(q) or
126
+ name.lower().startswith(q) or
127
+ group.lower().startswith(q)
128
+ )
129
+
130
+ # ------------------------------------------------------------------
131
+ # Double-click
132
+ # ------------------------------------------------------------------
133
+ def _on_item_double_clicked(self, item: QListWidgetItem):
134
+ insertion_text = item.data(Qt.UserRole)
135
+ StaTableLogger.debug(f"SymbolPickerWidget double-click: '{insertion_text}'")
136
+ if insertion_text:
137
+ self.insert_requested.emit(insertion_text)
138
+
139
+ # ------------------------------------------------------------------
140
+ # Register
141
+ # ------------------------------------------------------------------
142
+ def register_variable(self):
143
+ StaTableLogger.debug("SymbolPickerWidget.register_variable called")
144
+ dlg = VariableEditDialog(self, groups=self.global_defs.variable_groups())
145
+ if dlg.exec() == QDialog.Accepted:
146
+ var = dlg.get_variable()
147
+ if not var.name:
148
+ return
149
+ if any(v.name == var.name for v in self.global_defs.variables):
150
+ return
151
+ self.global_defs.variables.append(var)
152
+ self.refresh_list()
153
+
154
+ def register_flag(self):
155
+ StaTableLogger.debug("SymbolPickerWidget.register_flag called")
156
+ dlg = FlagEditDialog(self, groups=self.global_defs.flag_groups())
157
+ if dlg.exec() == QDialog.Accepted:
158
+ flag = dlg.get_flag()
159
+ if not flag.name:
160
+ return
161
+ if any(f.name == flag.name for f in self.global_defs.flags):
162
+ return
163
+ self.global_defs.flags.append(flag)
164
+ self.refresh_list()
165
+
166
+ def open_global_definitions(self):
167
+ StaTableLogger.debug("SymbolPickerWidget.open_global_definitions called")
168
+ dlg = GlobalDefinitionsDialog(self.global_defs, self)
169
+ dlg.exec()
170
+ self.refresh_list()
@@ -0,0 +1,37 @@
1
+ from PySide6.QtWidgets import QDockWidget, QPlainTextEdit, QWidget, QVBoxLayout
2
+ from PySide6.QtCore import Qt
3
+
4
+ from .logger import StaTableLogger
5
+
6
+
7
+ class TraceBallWidget(QDockWidget):
8
+ def __init__(self, parent=None):
9
+ super().__init__("TraceBall", parent)
10
+ self.setObjectName("TraceBall")
11
+ self.setAllowedAreas(Qt.AllDockWidgetAreas)
12
+ self.setFeatures(
13
+ QDockWidget.DockWidgetFloatable |
14
+ QDockWidget.DockWidgetMovable |
15
+ QDockWidget.DockWidgetClosable
16
+ )
17
+
18
+ container = QWidget()
19
+ layout = QVBoxLayout(container)
20
+ self.text_view = QPlainTextEdit()
21
+ self.text_view.setReadOnly(True)
22
+ self.text_view.setMaximumBlockCount(1000)
23
+ layout.addWidget(self.text_view)
24
+ self.setWidget(container)
25
+
26
+ logger = StaTableLogger()
27
+ logger.set_log_callback(self.append_log)
28
+
29
+ self.append_log("TraceBall ready.")
30
+
31
+ def append_log(self, message: str):
32
+ self.text_view.appendPlainText(message)
33
+ scrollbar = self.text_view.verticalScrollBar()
34
+ scrollbar.setValue(scrollbar.maximum())
35
+
36
+ def clear(self):
37
+ self.text_view.clear()
@@ -0,0 +1,15 @@
1
+ # statable_gui/transition_editor_direct/__init__.py
2
+ """
3
+ Action edit D&D package
4
+ """
5
+
6
+ from .draft import FlowItem, TransitionParams, ActionDraft, SystemGlobal
7
+ from .dialog import ActionEditorDialog
8
+
9
+ __all__ = [
10
+ 'FlowItem',
11
+ 'TransitionParams',
12
+ 'ActionDraft',
13
+ 'SystemGlobal',
14
+ 'ActionEditorDialog',
15
+ ]