easycoder 251104.2__py2.py3-none-any.whl → 260110.1__py2.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 easycoder might be problematic. Click here for more details.

Files changed (60) hide show
  1. easycoder/__init__.py +5 -3
  2. easycoder/debugger/__init__.py +5 -0
  3. easycoder/debugger/ec_dbg_value_display copy.py +195 -0
  4. easycoder/debugger/ec_dbg_value_display.py +24 -0
  5. easycoder/debugger/ec_dbg_watch_list copy.py +219 -0
  6. easycoder/debugger/ec_dbg_watchlist.py +293 -0
  7. easycoder/debugger/ec_debug.py +1025 -0
  8. easycoder/ec_border.py +15 -11
  9. easycoder/ec_classes.py +487 -11
  10. easycoder/ec_compiler.py +81 -44
  11. easycoder/ec_condition.py +1 -1
  12. easycoder/ec_core.py +1044 -1090
  13. easycoder/ec_gclasses.py +236 -0
  14. easycoder/ec_graphics.py +1683 -0
  15. easycoder/ec_handler.py +18 -13
  16. easycoder/ec_keyboard.py +50 -50
  17. easycoder/ec_program.py +299 -156
  18. easycoder/ec_psutil.py +48 -0
  19. easycoder/ec_timestamp.py +2 -1
  20. easycoder/ec_value.py +65 -47
  21. easycoder/icons/exit.png +0 -0
  22. easycoder/icons/run.png +0 -0
  23. easycoder/icons/step.png +0 -0
  24. easycoder/icons/stop.png +0 -0
  25. easycoder/pre/README.md +3 -0
  26. easycoder/pre/__init__.py +17 -0
  27. easycoder/pre/debugger/__init__.py +5 -0
  28. easycoder/pre/debugger/ec_dbg_value_display copy.py +195 -0
  29. easycoder/pre/debugger/ec_dbg_value_display.py +24 -0
  30. easycoder/pre/debugger/ec_dbg_watch_list copy.py +219 -0
  31. easycoder/pre/debugger/ec_dbg_watchlist.py +293 -0
  32. easycoder/pre/debugger/ec_debug.py +1014 -0
  33. easycoder/pre/ec_border.py +67 -0
  34. easycoder/pre/ec_classes.py +470 -0
  35. easycoder/pre/ec_compiler.py +291 -0
  36. easycoder/pre/ec_condition.py +27 -0
  37. easycoder/pre/ec_core.py +2772 -0
  38. easycoder/pre/ec_gclasses.py +230 -0
  39. easycoder/{ec_pyside.py → pre/ec_graphics.py} +631 -496
  40. easycoder/pre/ec_handler.py +79 -0
  41. easycoder/pre/ec_keyboard.py +439 -0
  42. easycoder/pre/ec_program.py +557 -0
  43. easycoder/pre/ec_psutil.py +48 -0
  44. easycoder/pre/ec_timestamp.py +11 -0
  45. easycoder/pre/ec_value.py +124 -0
  46. easycoder/pre/icons/close.png +0 -0
  47. easycoder/pre/icons/exit.png +0 -0
  48. easycoder/pre/icons/run.png +0 -0
  49. easycoder/pre/icons/step.png +0 -0
  50. easycoder/pre/icons/stop.png +0 -0
  51. easycoder/pre/icons/tick.png +0 -0
  52. {easycoder-251104.2.dist-info → easycoder-260110.1.dist-info}/METADATA +11 -1
  53. easycoder-260110.1.dist-info/RECORD +58 -0
  54. easycoder/ec_debug.py +0 -464
  55. easycoder-251104.2.dist-info/RECORD +0 -20
  56. /easycoder/{close.png → icons/close.png} +0 -0
  57. /easycoder/{tick.png → icons/tick.png} +0 -0
  58. {easycoder-251104.2.dist-info → easycoder-260110.1.dist-info}/WHEEL +0 -0
  59. {easycoder-251104.2.dist-info → easycoder-260110.1.dist-info}/entry_points.txt +0 -0
  60. {easycoder-251104.2.dist-info → easycoder-260110.1.dist-info}/licenses/LICENSE +0 -0
@@ -1,9 +1,30 @@
1
1
  import sys
2
2
  from functools import partial
3
3
  from .ec_handler import Handler
4
- from .ec_classes import RuntimeError, Object
4
+ from .ec_classes import (
5
+ FatalError,
6
+ RuntimeError,
7
+ ECValue
8
+ )
9
+ from .ec_gclasses import (
10
+ ECWidget,
11
+ ECCoreWidget,
12
+ ECLayout,
13
+ ECGroup,
14
+ ECPanel,
15
+ ECLabel,
16
+ ECPushButton,
17
+ ECCheckBox,
18
+ ECLineInput,
19
+ ECMultiline,
20
+ ECListBox,
21
+ ECComboBox,
22
+ ECWindow,
23
+ ECDialog,
24
+ ECMessageBox,
25
+ )
5
26
  from .ec_border import Border
6
- from .ec_debug import Debugger
27
+ from .debugger.ec_debug import Debugger
7
28
  from PySide6.QtCore import Qt, QTimer, Signal, QRect
8
29
  from PySide6.QtGui import QPixmap, QPainter
9
30
  from PySide6.QtWidgets import (
@@ -42,6 +63,120 @@ from PySide6.QtWidgets import (
42
63
  QGraphicsDropShadowEffect
43
64
  )
44
65
 
66
+ #############################################################################
67
+ # EC Label widget class
68
+ class ECLabelWidget(QLabel):
69
+ def __init__(self, text=None):
70
+ super().__init__(text)
71
+ self.setStyleSheet("""
72
+ background-color: transparent;
73
+ border: none;
74
+ """)
75
+
76
+ #############################################################################
77
+ # EC Pushbutton widget class
78
+ class ECPushButtonWidget(QPushButton):
79
+ def __init__(self, text=None):
80
+ super().__init__(text)
81
+
82
+ def getContent(self):
83
+ return self.text()
84
+
85
+ #############################################################################
86
+ # EC Checkbox widget class
87
+ class ECCheckBoxWidget(QCheckBox):
88
+ def __init__(self, text=None):
89
+ super().__init__(text)
90
+ self.setStyleSheet("""
91
+ QCheckBox::indicator {
92
+ border: 1px solid black;
93
+ border-radius: 3px;
94
+ background: white;
95
+ width: 16px;
96
+ height: 16px;
97
+ }
98
+ QCheckBox::indicator:checked {
99
+ background: #0078d7;
100
+ }
101
+ QCheckBox {
102
+ border: none;
103
+ background: transparent;
104
+ }
105
+ """)
106
+
107
+ #############################################################################
108
+ # EC line edit widget class
109
+ class ECLineEditWidget(QLineEdit):
110
+ clicked = Signal()
111
+
112
+ def __init__(self):
113
+ super().__init__()
114
+ self.multiline = False
115
+ self.container = None
116
+
117
+ def setContainer(self, container):
118
+ self.container = container
119
+
120
+ def mousePressEvent(self, event):
121
+ self.clicked.emit()
122
+ super().mousePressEvent(event)
123
+ if self.container != None: self.container.setClickSource(self)
124
+
125
+ #############################################################################
126
+ # EC plain text edit widget class
127
+ class ECPlainTextEditWidget(QPlainTextEdit):
128
+ clicked = Signal()
129
+
130
+ def __init__(self):
131
+ super().__init__()
132
+ self.multiline = True
133
+ self.container = None
134
+
135
+ def setContainer(self, container):
136
+ self.container = container
137
+
138
+ def mousePressEvent(self, event):
139
+ self.clicked.emit()
140
+ super().mousePressEvent(event)
141
+ if self.container != None: self.container.setClickSource(self)
142
+
143
+ #############################################################################
144
+ # EC Listbox widget class
145
+ class ECListBoxWidget(QListWidget):
146
+ def __init__(self, text=None):
147
+ super().__init__(text)
148
+
149
+ def text(self):
150
+ return self.currentItem().text()
151
+
152
+ #############################################################################
153
+ # EC ComboBox widget class
154
+ class ECComboBoxWidget(QComboBox):
155
+ def __init__(self, text=None):
156
+ super().__init__(text)
157
+
158
+ def text(self):
159
+ return self.currentText()
160
+
161
+ #############################################################################
162
+ # EC dialog class
163
+ class ECDialogWindow(QDialog):
164
+ clicked = Signal()
165
+
166
+ def __init__(self, window):
167
+ super().__init__(window)
168
+ self.multiline = True
169
+ self.container = None
170
+
171
+ def setContainer(self, container):
172
+ self.container = container
173
+
174
+ def mousePressEvent(self, event):
175
+ self.clicked.emit()
176
+ super().mousePressEvent(event)
177
+ if self.container != None: self.container.setClickSource(self)
178
+
179
+ ###############################################################################
45
180
  class Graphics(Handler):
46
181
 
47
182
  def __init__(self, compiler):
@@ -56,71 +191,19 @@ class Graphics(Handler):
56
191
  def closeEvent(self):
57
192
  print('window closed')
58
193
 
59
- def isWidget(self, keyword):
60
- return keyword in [
61
- 'layout',
62
- 'group',
63
- 'label',
64
- 'pushbutton',
65
- 'checkbox',
66
- 'lineinput',
67
- 'multiline',
68
- 'listbox',
69
- 'combobox',
70
- 'widget'
71
- ]
72
-
73
- def setWidget(self, record, widget):
74
- if record['index'] >= record['elements']:
75
- RuntimeError(self.program, f'Index out of range for widget {record["name"]}')
76
- if not 'widget' in record:
77
- record['widget'] = [None] * record['elements']
78
- while len(record['widget']) < record['elements']:
79
- record['widget'].append(None)
80
- record['widget'][record['index']] = widget
194
+ def isCoreWidget(self, object):
195
+ if isinstance(object, dict): object = object['object']
196
+ return isinstance(object, ECCoreWidget)
81
197
 
82
- def getWidget(self, record):
83
- if 'widget' in record and record['widget'] != None:
84
- if record['keyword'] in ['layout', 'group']: return record['widget']
85
- return record['widget'][record['index']]
86
- else:
87
- return None
198
+ # Set a graphic element as the value of a record
199
+ def setGraphicElement(self, record, element):
200
+ object = self.getObject(record)
201
+ # object.setValue(ECValue(domain=self.getName(), type='object', content=element))
202
+ object.setValue(element)
88
203
 
89
204
  def dialogTypes(self):
90
205
  return ['confirm', 'lineedit', 'multiline', 'generic']
91
-
92
- class ClickableLineEdit(QLineEdit):
93
- clicked = Signal()
94
-
95
- def __init__(self):
96
- super().__init__()
97
- self.multiline = False
98
- self.container = None
99
-
100
- def setContainer(self, container):
101
- self.container = container
102
-
103
- def mousePressEvent(self, event):
104
- self.clicked.emit()
105
- super().mousePressEvent(event)
106
- if self.container != None: self.container.setClickSource(self)
107
-
108
- class ClickablePlainTextEdit(QPlainTextEdit):
109
- clicked = Signal()
110
-
111
- def __init__(self):
112
- super().__init__()
113
- self.multiline = True
114
- self.container = None
115
-
116
- def setContainer(self, container):
117
- self.container = container
118
-
119
- def mousePressEvent(self, event):
120
- self.clicked.emit()
121
- super().mousePressEvent(event)
122
- if self.container != None: self.container.setClickSource(self)
123
-
206
+
124
207
  #############################################################################
125
208
  # Keyword handlers
126
209
 
@@ -131,13 +214,16 @@ class Graphics(Handler):
131
214
  # (5) add spacer [size] {size} to {layout}
132
215
  # (6) add {widget} at {col} {row} in {grid layout}
133
216
  def k_add(self, command):
217
+
218
+ # Add to a layout, group, list or combo box
134
219
  def addToLayout():
135
220
  if self.nextIsSymbol():
136
221
  record = self.getSymbolRecord()
137
- if record['keyword'] in ['layout', 'group', 'element']:
138
- command['layout'] = record['name']
139
- self.add(command)
140
- return True
222
+ object = self.getObject(record)
223
+ self.checkObjectType(record, (ECLayout, ECGroup, ECListBox, ECComboBox))
224
+ command['target'] = record['name']
225
+ self.add(command)
226
+ return True
141
227
  return False
142
228
 
143
229
  token = self.peek()
@@ -166,82 +252,90 @@ class Graphics(Handler):
166
252
  self.skip('to')
167
253
  return addToLayout()
168
254
 
169
- # Here it's either (1) or (2)
255
+ # Here it's either (1), (2) or (6)
170
256
  elif self.nextIsSymbol():
171
257
  record = self.getSymbolRecord()
172
- if record['extra'] == 'gui':
173
- if self.isWidget(record['keyword']):
174
- command['widget'] = record['name']
175
- if self.peek() == 'to':
176
- # (2)
177
- record = self.getSymbolRecord()
178
- self.nextToken()
179
- return addToLayout()
180
- elif self.peek() == 'at':
181
- # (6)
182
- self.nextToken()
183
- command['row'] = self.nextValue()
184
- command['col'] = self.nextValue()
185
- self.skip('in')
186
- return addToLayout()
258
+ if self.isObjectType(record, ECWidget):
259
+ # It's either (2), (6) or (1)
260
+ command['widget'] = record['name']
261
+ if self.peek() == 'to':
262
+ # (2)
263
+ record = self.getSymbolRecord()
264
+ domainName = record['domain']
265
+ if domainName != self.getName():
266
+ domain = self.program.domainIndex[domainName]
267
+ handler = domain.keywordHandler('add')
268
+ return handler(command)
269
+ self.nextToken()
270
+ return addToLayout()
271
+ elif self.peek() == 'at':
272
+ # (6)
273
+ self.nextToken()
274
+ command['row'] = self.nextValue()
275
+ command['col'] = self.nextValue()
276
+ self.skip('in')
277
+ return addToLayout()
278
+ else:
279
+ # It's (1) with a non-widget variable
280
+ command['value'] = self.getValue()
281
+ self.skip('to')
282
+ return addToLayout()
187
283
 
188
- else: return False
189
- # (1)
284
+ # (1) with a value
190
285
  value = self.getValue()
191
286
  if value == None: return False
192
287
  command['value'] = value
193
288
  self.skip('to')
194
- if self.nextIsSymbol():
195
- record = self.getSymbolRecord()
196
- command['widget'] = record['name']
197
- self.add(command)
198
- return True
199
- return False
289
+ return addToLayout()
200
290
 
201
291
  def r_add(self, command):
202
292
  if 'value' in command:
203
- value = self.getRuntimeValue(command['value'])
204
- record = self.getVariable(command['widget'])
205
- if record['keyword'] == 'listbox':
206
- self.getWidget(record).addItem(value)
207
- elif record['keyword'] == 'combobox':
293
+ record = self.getVariable(command['target'])
294
+ object = self.getObject(record)
295
+ value = self.textify(command['value'])
296
+ if isinstance(object, ECListBox):
297
+ self.getInnerObject(record).addItem(value) # type: ignore
298
+ elif isinstance(object, ECComboBox):
208
299
  if isinstance(value, list): record['widget'].addItems(value)
209
- else: self.getWidget(record).addItem(value)
300
+ else: self.getInnerObject(record).addItem(value) # type: ignore
210
301
  elif 'row' in command and 'col' in command:
211
302
  layout = self.getVariable(command['layout'])['widget']
212
303
  record = self.getVariable(command['widget'])
213
- widget = self.getWidget(record)
214
- row = self.getRuntimeValue(command['row'])
215
- col = self.getRuntimeValue(command['col'])
216
- if record['keyword'] == 'layout':
304
+ widget = self.getInnerObject(record)
305
+ row = self.textify(command['row'])
306
+ col = self.textify(command['col'])
307
+ if self.isObjectType(record, ECLayout):
217
308
  layout.addLayout(widget, row, col)
218
309
  else:
219
310
  layout.addWidget(widget, row, col)
220
311
  else:
221
- layoutRecord = self.getVariable(command['layout'])
312
+ layoutRecord = self.getVariable(command['target'])
222
313
  widget = command['widget']
223
314
  if widget == 'stretch':
224
- self.getWidget(layoutRecord).addStretch()
315
+ self.getInnerObject(layoutRecord).addStretch() # type: ignore
225
316
  elif widget == 'spacer':
226
- self.getWidget(layoutRecord).addSpacing(self.getRuntimeValue(command['size']))
317
+ self.getInnerObject(layoutRecord).addSpacing(self.textify(command['size'])) # type: ignore
227
318
  else:
228
319
  widgetRecord = self.getVariable(widget)
229
- layoutRecord = self.getVariable(command['layout'])
230
- widget = self.getWidget(widgetRecord)
231
- layout = layoutRecord['widget']
320
+ self.checkObjectType(widgetRecord, ECCoreWidget)
321
+ self.checkObjectType(layoutRecord, ECLayout)
322
+ widget = self.getInnerObject(widgetRecord)
323
+ layout = self.getInnerObject(layoutRecord)
232
324
  stretch = 'stretch' in command
233
- if widgetRecord['keyword'] == 'layout':
234
- if layoutRecord['keyword'] == 'group':
235
- if widgetRecord['keyword'] == 'layout':
236
- layout.setLayout(widget)
325
+ if self.isObjectType(widgetRecord, ECLayout):
326
+ if self.isObjectType(layoutRecord, ECGroup):
327
+ if self.isObjectType(widgetRecord, ECLayout):
328
+ layout.setLayout(widget) # type: ignore
237
329
  else:
238
330
  RuntimeError(self.program, 'Can only add a layout to a group')
239
331
  else:
240
- if stretch: layout.addLayout(widget, stretch=1)
241
- else: layout.addLayout(widget)
332
+ if stretch: layout.addLayout(widget, stretch=1) # type: ignore
333
+ else:
334
+ layout.addLayout(widget) # type: ignore
242
335
  else:
243
- if stretch: layout.addWidget(widget, stretch=1)
244
- else: layout.addWidget(widget)
336
+ if stretch: layout.addWidget(widget, stretch=1) # type: ignore
337
+ else:
338
+ layout.addWidget(widget) # type: ignore
245
339
  return self.nextPC()
246
340
 
247
341
  # Center one window on another
@@ -249,46 +343,58 @@ class Graphics(Handler):
249
343
  def k_center(self, command):
250
344
  if self.nextIsSymbol():
251
345
  record = self.getSymbolRecord()
252
- if record['keyword'] == 'window':
346
+ if self.isObjectType(record, ECWindow):
253
347
  command['window2'] = record['name']
254
348
  self.skip('on')
255
349
  if self.nextIsSymbol():
256
350
  record = self.getSymbolRecord()
257
- if record['keyword'] == 'window':
351
+ if self.isObjectType(record, ECWindow):
258
352
  command['window1'] = record['name']
259
353
  self.add(command)
260
354
  return True
261
355
  return False
262
356
 
357
+ def k_centre(self,command):
358
+ return self.k_center(command)
359
+
263
360
  def r_center(self, command):
264
- window1 = self.getVariable(command['window1'])['window']
265
- window2 = self.getVariable(command['window2'])['window']
266
- geo1 = window1.geometry()
267
- geo2 = window2.geometry()
361
+ object = self.getVariable(command['window1'])['object']
362
+ self.checkObjectType(object, ECWindow)
363
+ window1 = self.getInnerObject(object)
364
+ object = self.getVariable(command['window2'])['object']
365
+ self.checkObjectType(object, ECWindow)
366
+ window2 = self.getInnerObject(object)
367
+ geo1 = window1.geometry() # type: ignore
368
+ geo2 = window2.geometry() # type: ignore
268
369
  geo2.moveCenter(geo1.center())
269
- window2.setGeometry(geo2)
370
+ window2.setGeometry(geo2) # type: ignore
270
371
  return self.nextPC()
271
372
 
272
373
  # Declare a checkbox variable
273
374
  def k_checkbox(self, command):
274
- return self.compileVariable(command, 'gui')
375
+ self.compiler.addValueType()
376
+ return self.compileVariable(command, 'ECCheckBox')
275
377
 
276
378
  def r_checkbox(self, command):
277
379
  return self.nextPC()
278
380
 
279
- # clear {widget}
381
+ # clear {window/widget}
280
382
  def k_clear(self, command):
281
383
  if self.nextIsSymbol():
282
384
  record = self.getSymbolRecord()
283
- if self.isWidget(record['keyword']):
284
- command['name'] = record['name']
285
- self.add(command)
286
- return True
385
+ object = self.getObject(record)
386
+ if object.isCoreClass():
387
+ if object.isClearable():
388
+ command['name'] = record['name']
389
+ self.add(command)
390
+ return True
391
+ raise FatalError(self.compiler, f'The object {record["name"]} is not clearable')
287
392
  return False
288
393
 
289
394
  def r_clear(self, command):
290
395
 
291
396
  def clearLayout(layout: QLayout) -> None:
397
+ """Recursively clear all items from a layout."""
292
398
  if layout is None:
293
399
  return
294
400
  while layout.count() > 0:
@@ -297,50 +403,59 @@ class Graphics(Handler):
297
403
  continue
298
404
  widget = item.widget()
299
405
  if widget is not None:
300
- # Delete the widget
301
406
  widget.deleteLater()
302
407
  elif item.layout() is not None:
303
- # Recursively clear sub-layout
304
408
  clearLayout(item.layout())
305
409
  item.layout().deleteLater()
306
- # The QLayoutItem will be automatically cleaned up by Qt
307
410
 
308
411
  def clearWidget(widget: QWidget) -> None:
412
+ """Clear all contents from a widget."""
309
413
  if widget is None:
310
414
  return
311
- # Clear the layout first
415
+ if isinstance(widget, (QListWidget, QComboBox)):
416
+ if isinstance(widget, QListWidget):
417
+ for i in range(widget.count()):
418
+ item_widget = widget.itemWidget(widget.item(i))
419
+ if item_widget:
420
+ item_widget.deleteLater()
421
+ widget.clear()
422
+ return
312
423
  layout = widget.layout()
313
424
  if layout is not None:
314
425
  clearLayout(layout)
315
426
  layout.deleteLater()
316
- # Clear any remaining child widgets
317
- child_widgets = widget.findChildren(QWidget, "", Qt.FindDirectChildrenOnly)
427
+ child_widgets = widget.findChildren(QWidget, "", Qt.FindChildOption.FindDirectChildrenOnly)
318
428
  for child in child_widgets:
319
429
  child.deleteLater()
320
430
 
321
- widget = self.getWidget(self.getVariable(command['name']))
322
- clearWidget(widget)
323
- return self.nextPC()
324
-
431
+ element = self.getInnerObject(self.getVariable(command['name']))
432
+ if isinstance(element, QLayout):
433
+ clearLayout(element) # type: ignore
434
+ else:
435
+ clearWidget(element) # type: ignore
325
436
  return self.nextPC()
326
437
 
327
438
  # close {window}
328
439
  def k_close(self, command):
329
440
  if self.nextIsSymbol():
330
441
  record = self.getSymbolRecord()
331
- if record['keyword'] == 'window':
442
+ if self.isObjectType(record, ECWindow):
332
443
  command['name'] = record['name']
333
444
  self.add(command)
334
445
  return True
335
446
  return False
336
447
 
337
448
  def r_close(self, command):
338
- self.getVariable(command['name'])['window'].close()
449
+ record = self.getVariable(command['name'])
450
+ window = self.getInnerObject(record)
451
+ self.checkObjectType(window, QMainWindow)
452
+ window.close() # type: ignore
339
453
  return self.nextPC()
340
454
 
341
455
  # Declare a combobox variable
342
456
  def k_combobox(self, command):
343
- return self.compileVariable(command, 'gui')
457
+ self.compiler.addValueType()
458
+ return self.compileVariable(command, 'ECComboBox')
344
459
 
345
460
  def r_combobox(self, command):
346
461
  return self.nextPC()
@@ -366,7 +481,7 @@ class Graphics(Handler):
366
481
  elif token == 'layout':
367
482
  if self.nextIsSymbol():
368
483
  record = self.getSymbolRecord()
369
- if record['keyword'] == 'layout':
484
+ if self.isObjectType(record, ECLayout):
370
485
  command['layout'] = record['name']
371
486
  else: return False
372
487
  else: break
@@ -476,7 +591,15 @@ class Graphics(Handler):
476
591
  self.add(command)
477
592
  return True
478
593
 
479
- def k_createWidget(self, command):
594
+ def k_createListBox(self, command):
595
+ self.add(command)
596
+ return True
597
+
598
+ def k_createComboBox(self, command):
599
+ self.add(command)
600
+ return True
601
+
602
+ def k_createPanel(self, command):
480
603
  self.add(command)
481
604
  return True
482
605
 
@@ -543,7 +666,6 @@ class Graphics(Handler):
543
666
  command['name'] = record['name']
544
667
  keyword = record['keyword']
545
668
  if keyword == 'window': return self.k_createWindow(command)
546
- elif keyword in ['listbox', 'combobox', 'widget']: return self.k_createWidget(command)
547
669
  elif keyword == 'layout': return self.k_createLayout(command)
548
670
  elif keyword == 'group': return self.k_createGroupBox(command)
549
671
  elif keyword == 'label': return self.k_createLabel(command)
@@ -551,17 +673,20 @@ class Graphics(Handler):
551
673
  elif keyword == 'checkbox': return self.k_createCheckBox(command)
552
674
  elif keyword == 'lineinput': return self.k_createLineEdit(command)
553
675
  elif keyword == 'multiline': return self.k_createMultiLineEdit(command)
676
+ elif keyword == 'listbox': return self.k_createListBox(command)
677
+ elif keyword == 'combobox': return self.k_createComboBox(command)
678
+ elif keyword == 'panel': return self.k_createPanel(command)
554
679
  elif keyword == 'dialog': return self.k_createDialog(command)
555
680
  elif keyword == 'messagebox': return self.k_createMessageBox(command)
556
681
  return False
557
682
 
558
683
  def r_createWindow(self, command, record):
559
684
  window = QMainWindow()
560
- title = self.getRuntimeValue(command['title'])
685
+ title = self.textify(command['title'])
561
686
  if title == None: title = 'EasyCoder Main Window'
562
687
  window.setWindowTitle(title)
563
- w = self.getRuntimeValue(command['w'])
564
- h = self.getRuntimeValue(command['h'])
688
+ w = self.textify(command['w'])
689
+ h = self.textify(command['h'])
565
690
  x = command['x']
566
691
  y = command['y']
567
692
  if hasattr(self.program, 'screenWidth'): screenWidth = self.program.screenWidth
@@ -569,11 +694,11 @@ class Graphics(Handler):
569
694
  if hasattr(self.program, 'screenHeight'): screenHeight = self.program.screenHeight
570
695
  else: screenHeight = self.program.parent.program.screenHeight
571
696
  if x == None: x = (screenWidth - w) / 2
572
- else: x = self.getRuntimeValue(x)
697
+ else: x = self.textify(x)
573
698
  if y == None: y = (screenHeight - h) / 2
574
- else: y = self.getRuntimeValue(x)
699
+ else: y = self.textify(x)
575
700
  window.setGeometry(x, y, w, h)
576
- record['window'] = window
701
+ self.setGraphicElement(record, window)
577
702
  return self.nextPC()
578
703
 
579
704
  def r_createLayout(self, command, record):
@@ -583,121 +708,104 @@ class Graphics(Handler):
583
708
  elif layoutType == 'QStackedLayout': layout = QStackedLayout()
584
709
  else: layout = QVBoxLayout()
585
710
  layout.setContentsMargins(5,0,5,0)
586
- record['widget'] = layout
711
+ self.setGraphicElement(record, layout)
587
712
  return self.nextPC()
588
713
 
589
714
  def r_createGroupBox(self, command, record):
590
- group = QGroupBox(self.getRuntimeValue(command['title']))
591
- group.setAlignment(Qt.AlignLeft)
592
- record['widget'] = group
715
+ group = QGroupBox(self.textify(command['title']))
716
+ group.setAlignment(Qt.AlignmentFlag.AlignLeft)
717
+ self.setGraphicElement(record, group)
593
718
  return self.nextPC()
594
719
 
595
720
  def r_createLabel(self, command, record):
596
- label = QLabel(str(self.getRuntimeValue(command['text'])))
597
- label.setStyleSheet("""
598
- background-color: transparent;
599
- border: none;
600
- """)
721
+ label = ECLabelWidget(str(self.textify(command['text'])))
601
722
  if 'size' in command:
602
723
  fm = label.fontMetrics()
603
724
  c = label.contentsMargins()
604
- w = fm.horizontalAdvance('m') * self.getRuntimeValue(command['size']) +c.left()+c.right()
725
+ w = fm.horizontalAdvance('m') * self.textify(command['size']) +c.left()+c.right()
605
726
  label.setMaximumWidth(w)
606
727
  if 'align' in command:
607
728
  alignment = command['align']
608
- if alignment == 'left': label.setAlignment(Qt.AlignLeft)
609
- elif alignment == 'right': label.setAlignment(Qt.AlignRight)
610
- elif alignment in ['center', 'centre']: label.setAlignment(Qt.AlignHCenter)
611
- elif alignment == 'justify': label.setAlignment(Qt.AlignJustify)
729
+ if alignment == 'left': label.setAlignment(Qt.AlignmentFlag.AlignLeft)
730
+ elif alignment == 'right': label.setAlignment(Qt.AlignmentFlag.AlignRight)
731
+ elif alignment in ['center', 'centre']: label.setAlignment(Qt.AlignmentFlag.AlignHCenter)
732
+ elif alignment == 'justify': label.setAlignment(Qt.AlignmentFlag.AlignJustify)
612
733
  if 'expand' in command:
613
- label.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Preferred)
614
- self.setWidget(record, label)
734
+ label.setSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Preferred)
735
+ self.setGraphicElement(record, label)
615
736
  return self.nextPC()
616
737
 
617
738
  def r_createPushbutton(self, command, record):
618
739
  if 'size' in command:
619
- size = self.getRuntimeValue(command['size'])
740
+ size = self.textify(command['size'])
620
741
  else: size = None
621
742
  if 'icon' in command:
622
- iconPath = self.getRuntimeValue(command['icon'])
743
+ iconPath = self.textify(command['icon'])
623
744
  pixmap = QPixmap(iconPath)
624
745
  if pixmap.isNull():
625
746
  RuntimeError(self.program, f'Icon not found: {iconPath}')
626
- icon = pixmap.scaledToHeight(size if size != None else 24, Qt.SmoothTransformation)
747
+ icon = pixmap.scaledToHeight(size if size != None else 24, Qt.TransformationMode.SmoothTransformation)
627
748
  pushbutton = QPushButton()
628
749
  pushbutton.setIcon(icon)
629
750
  pushbutton.setIconSize(icon.size())
630
751
  elif 'text' in command:
631
- text = self.getRuntimeValue(command['text'])
632
- pushbutton = QPushButton(text)
752
+ text = self.textify(command['text'])
753
+ pushbutton = ECPushButtonWidget(text)
633
754
  pushbutton.setAccessibleName(text)
634
755
  if size != None:
635
756
  fm = pushbutton.fontMetrics()
636
757
  c = pushbutton.contentsMargins()
637
- w = fm.horizontalAdvance('m') * self.getRuntimeValue(command['size']) + c.left()+c.right()
758
+ w = fm.horizontalAdvance('m') * self.textify(command['size']) + c.left()+c.right()
638
759
  pushbutton.setMaximumWidth(w)
639
760
  self.putSymbolValue(record, pushbutton)
640
- self.setWidget(record, pushbutton)
761
+ self.setGraphicElement(record, pushbutton)
641
762
  return self.nextPC()
642
763
 
643
764
  def r_createCheckBox(self, command, record):
644
- checkbox = QCheckBox(self.getRuntimeValue(command['text']))
645
- checkbox.setStyleSheet("""
646
- QCheckBox::indicator {
647
- border: 1px solid black;
648
- border-radius: 3px;
649
- background: white;
650
- width: 16px;
651
- height: 16px;
652
- }
653
- QCheckBox::indicator:checked {
654
- background: #0078d7;
655
- }
656
- QCheckBox {
657
- border: none;
658
- background: transparent;
659
- }
660
- """)
661
- checkbox.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Preferred)
662
- self.setWidget(record, checkbox)
765
+ checkbox = ECCheckBoxWidget(self.textify(command['text']))
766
+ checkbox.setSizePolicy(QSizePolicy.Policy.Fixed, QSizePolicy.Policy.Preferred)
767
+ self.setGraphicElement(record, checkbox)
663
768
  return self.nextPC()
664
769
 
665
770
  def r_createLineEdit(self, command, record):
666
- lineinput = self.ClickableLineEdit()
667
- lineinput.setText(self.getRuntimeValue(command['text']))
771
+ lineinput = ECLineEditWidget()
772
+ lineinput.setText(self.textify(command['text']))
668
773
  fm = lineinput.fontMetrics()
669
774
  m = lineinput.textMargins()
670
775
  c = lineinput.contentsMargins()
671
- w = fm.horizontalAdvance('x') * self.getRuntimeValue(command['size']) +m.left()+m.right()+c.left()+c.right()
776
+ w = fm.horizontalAdvance('x') * self.textify(command['size']) +m.left()+m.right()+c.left()+c.right()
672
777
  lineinput.setMaximumWidth(w)
673
- self.setWidget(record, lineinput)
778
+ self.setGraphicElement(record, lineinput)
674
779
  return self.nextPC()
675
780
 
676
781
  def r_createMultiLineEdit(self, command, record):
677
- textinput = self.ClickablePlainTextEdit()
782
+ textinput = ECPlainTextEditWidget()
678
783
  fontMetrics = textinput.fontMetrics()
679
784
  charWidth = fontMetrics.horizontalAdvance('x')
680
785
  charHeight = fontMetrics.height()
681
- textinput.setFixedWidth(charWidth * self.getRuntimeValue(command['cols']))
682
- textinput.setFixedHeight(charHeight * self.getRuntimeValue(command['rows']))
683
- self.setWidget(record, textinput)
786
+ textinput.setFixedWidth(charWidth * self.textify(command['cols']))
787
+ textinput.setFixedHeight(charHeight * self.textify(command['rows']))
788
+ self.setGraphicElement(record, textinput)
684
789
  return self.nextPC()
685
790
 
686
791
  def r_createListWidget(self, command, record):
687
- self.setWidget(record, QListWidget())
792
+ listwidget = ECListBoxWidget()
793
+ self.setGraphicElement(record, listwidget)
688
794
  return self.nextPC()
689
795
 
690
796
  def r_createComboBox(self, command, record):
691
- self.setWidget(record, QComboBox())
797
+ combobox = ECComboBoxWidget()
798
+ self.setGraphicElement(record, combobox)
692
799
  return self.nextPC()
693
800
 
694
- def r_createWidget(self, command, record):
695
- self.setWidget(record, QWidget())
801
+ def r_createPanel(self, command, record):
802
+ self.setGraphicElement(record, QWidget())
696
803
  return self.nextPC()
697
804
 
698
805
  def r_createDialog(self, command, record):
699
806
 
700
- class ECDialog(QDialog):
807
+ # This is probably not needed anymore
808
+ class ECDialogX(QDialog):
701
809
  def __init__(self, parent, record):
702
810
  super().__init__(parent)
703
811
  self.record = record
@@ -711,15 +819,15 @@ class Graphics(Handler):
711
819
 
712
820
  win = command['window']
713
821
  if win != None:
714
- win = self.getVariable(win)['window']
715
- dialog = ECDialog(win, record)
822
+ win = self.getInnerObject(self.getVariable(win))
823
+ dialog = ECDialogWindow(win)
716
824
  dialogType = command['type'].lower()
717
- dialog.dialogType = dialogType
825
+ dialog.dialogType = dialogType # type: ignore
718
826
  mainLayout = QVBoxLayout(dialog)
719
827
  if dialogType == 'generic':
720
828
  dialog.setFixedWidth(500)
721
829
  dialog.setFixedHeight(500)
722
- dialog.setWindowFlags(Qt.FramelessWindowHint)
830
+ dialog.setWindowFlags(Qt.WindowType.FramelessWindowHint)
723
831
  dialog.setModal(True)
724
832
  dialog.setStyleSheet('background-color: white;border:1px solid black;')
725
833
 
@@ -732,36 +840,35 @@ class Graphics(Handler):
732
840
  mainLayout.addLayout(layout)
733
841
  dialog.setLayout(mainLayout)
734
842
  else:
735
- dialog.setWindowTitle(self.getRuntimeValue(command['title']))
736
- prompt = self.getRuntimeValue(command['prompt'])
843
+ dialog.setWindowTitle(self.textify(command['title']))
844
+ prompt = self.textify(command['prompt'])
737
845
  if dialogType == 'confirm':
738
- mainLayout.addWidget(QLabel(prompt))
846
+ mainLayout.addWidget(ECLabelWidget(prompt))
739
847
  elif dialogType == 'lineedit':
740
- mainLayout.addWidget(QLabel(prompt))
741
- dialog.lineEdit = self.ClickableLineEdit(dialog)
742
- dialog.value = self.getRuntimeValue(command['value'])
743
- dialog.lineEdit.setText(dialog.value)
744
- mainLayout.addWidget(dialog.lineEdit)
848
+ mainLayout.addWidget(ECLabelWidget(prompt))
849
+ dialog.lineEdit = self.ECLineEdit(dialog) # type: ignore
850
+ dialog.value = self.textify(command['value']) # type: ignore
851
+ dialog.lineEdit.setText(dialog.value) # type: ignore
852
+ mainLayout.addWidget(dialog.lineEdit) # type: ignore
745
853
  elif dialogType == 'multiline':
746
- mainLayout.addWidget(QLabel(prompt))
747
- dialog.textEdit = self.ClickablePlainTextEdit(self)
748
- dialog.textEdit.setText(dialog.value)
749
- mainLayout.addWidget(dialog.textEdit)
750
- buttonBox = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel)
854
+ mainLayout.addWidget(ECLabelWidget(prompt))
855
+ dialog.textEdit = self.ECPlainTextEdit(dialog) # type: ignore
856
+ dialog.textEdit.setText(dialog.value) # type: ignore
857
+ mainLayout.addWidget(dialog.textEdit) # type: ignore
858
+ buttonBox = QDialogButtonBox(QDialogButtonBox.StandardButton.Ok | QDialogButtonBox.StandardButton.Cancel)
751
859
  buttonBox.accepted.connect(dialog.accept)
752
860
  buttonBox.rejected.connect(dialog.reject)
753
- mainLayout.addWidget(buttonBox, alignment=Qt.AlignHCenter)
754
- record['dialog'] = dialog
861
+ mainLayout.addWidget(buttonBox, alignment=Qt.AlignmentFlag.AlignHCenter)
862
+
863
+ self.setGraphicElement(record, dialog)
755
864
  return self.nextPC()
756
865
 
757
866
  # Creates a message box but doesn't run it
758
867
  def r_createMessageBox(self, command, record):
759
- data = {}
760
- data['window'] = command['window']
761
- data['style'] = command['style']
762
- data['title'] = self.getRuntimeValue(command['title'])
763
- data['message'] = self.getRuntimeValue(command['message'])
764
- record['data'] = data
868
+ record['window'] = command['window']
869
+ record['style'] = command['style']
870
+ record['title'] = self.textify(command['title'])
871
+ record['message'] = self.textify(command['message'])
765
872
  return self.nextPC()
766
873
 
767
874
  def r_create(self, command):
@@ -777,14 +884,15 @@ class Graphics(Handler):
777
884
  elif keyword == 'multiline': return self.r_createMultiLineEdit(command, record)
778
885
  elif keyword == 'listbox': return self.r_createListWidget(command, record)
779
886
  elif keyword == 'combobox': return self.r_createComboBox(command, record)
780
- elif keyword == 'widget': return self.r_createWidget(command, record)
887
+ elif keyword == 'panel': return self.r_createPanel(command, record)
781
888
  elif keyword == 'dialog': return self.r_createDialog(command, record)
782
889
  elif keyword == 'messagebox': return self.r_createMessageBox(command, record)
783
890
  return None
784
891
 
785
892
  # Declare a dialog variable
786
893
  def k_dialog(self, command):
787
- return self.compileVariable(command, 'gui')
894
+ self.compiler.addValueType()
895
+ return self.compileVariable(command, 'ECDialog')
788
896
 
789
897
  def r_dialog(self, command):
790
898
  return self.nextPC()
@@ -798,7 +906,7 @@ class Graphics(Handler):
798
906
  return False
799
907
 
800
908
  def r_disable(self, command):
801
- self.getWidget(self.getVariable(command['name'])).setEnabled(False)
909
+ self.getInnerObject(self.getVariable(command['name'])).setEnabled(False) # type: ignore
802
910
  return self.nextPC()
803
911
 
804
912
  # Enable a widget
@@ -810,12 +918,13 @@ class Graphics(Handler):
810
918
  return False
811
919
 
812
920
  def r_enable(self, command):
813
- self.getWidget(self.getVariable(command['name'])).setEnabled(True)
921
+ self.getInnerObject(self.getVariable(command['name'])).setEnabled(True) # type: ignore
814
922
  return self.nextPC()
815
923
 
816
924
  # Create a group box
817
925
  def k_group(self, command):
818
- return self.compileVariable(command, 'gui')
926
+ self.compiler.addValueType()
927
+ return self.compileVariable(command, 'ECGroup')
819
928
 
820
929
  def r_group(self, command):
821
930
  return self.nextPC()
@@ -824,7 +933,8 @@ class Graphics(Handler):
824
933
  def k_hide(self, command):
825
934
  if self.nextIsSymbol():
826
935
  record = self.getSymbolRecord()
827
- if self.isWidget(record['keyword']):
936
+ if self.isObjectType(record, ECCoreWidget):
937
+ command['domain'] = record['domain']
828
938
  command['widget'] = record['name']
829
939
  self.add(command)
830
940
  return True
@@ -832,17 +942,18 @@ class Graphics(Handler):
832
942
 
833
943
  def r_hide(self, command):
834
944
  record = self.getVariable(command['widget'])
835
- if 'widget' in record: self.getWidget(record).hide()
945
+ self.getInnerObject(record).hide() # type: ignore
836
946
  return self.nextPC()
837
947
 
838
948
  # Initialize the graphics environment
839
949
  # Unused: def k_init(self, command):
840
950
 
841
951
  def r_init(self, command):
952
+ print('Initializing graphics...')
842
953
  self.app = QApplication(sys.argv)
843
954
  screen = QApplication.screens()[0].size().toTuple()
844
- self.program.screenWidth = screen[0]
845
- self.program.screenHeight = screen[1]
955
+ self.program.screenWidth = screen[0] # type: ignore
956
+ self.program.screenHeight = screen[1] # type: ignore
846
957
  print(f'Screen: {self.program.screenWidth}x{self.program.screenHeight}')
847
958
  # return self.nextPC()
848
959
  def on_last_window_closed():
@@ -858,53 +969,61 @@ class Graphics(Handler):
858
969
  timer.timeout.connect(flush)
859
970
  timer.start(10)
860
971
  QTimer.singleShot(500, init)
861
- if self.program.debugging: self.program.debugger = Debugger(self.program)
972
+ self.program.startGraphics()
973
+ if self.program.debugging:
974
+ print('Starting debugger...')
975
+ self.program.debugger = Debugger(self.program)
976
+ self.program.debugger.enableBreakpoints()
862
977
  self.app.lastWindowClosed.connect(on_last_window_closed)
863
978
  self.app.exec()
864
979
 
865
980
  # Declare a label variable
866
981
  def k_label(self, command):
867
- return self.compileVariable(command, 'gui')
868
-
982
+ self.compiler.addValueType()
983
+ return self.compileVariable(command, 'ECLabel')
869
984
  def r_label(self, command):
870
985
  return self.nextPC()
871
986
 
872
987
  # Declare a layout variable
873
988
  def k_layout(self, command):
874
- return self.compileVariable(command, 'gui')
989
+ self.compiler.addValueType()
990
+ return self.compileVariable(command, 'ECLayout')
875
991
 
876
992
  def r_layout(self, command):
877
993
  return self.nextPC()
878
994
 
879
995
  # Declare a line input variable
880
996
  def k_lineinput(self, command):
881
- return self.compileVariable(command, 'gui')
997
+ self.compiler.addValueType()
998
+ return self.compileVariable(command, 'ECLineInput')
882
999
 
883
1000
  def r_lineinput(self, command):
884
1001
  return self.nextPC()
885
1002
 
886
1003
  # Declare a listbox input variable
887
1004
  def k_listbox(self, command):
888
- return self.compileVariable(command, 'gui')
1005
+ self.compiler.addValueType()
1006
+ return self.compileVariable(command, 'ECListBox')
889
1007
 
890
1008
  def r_listbox(self, command):
891
1009
  return self.nextPC()
892
1010
 
893
1011
  # Declare a messagebox variable
894
1012
  def k_messagebox(self, command):
895
- return self.compileVariable(command)
1013
+ self.compiler.addValueType()
1014
+ return self.compileVariable(command, 'ECMessageBox')
896
1015
 
897
1016
  def r_messagebox(self, command):
898
1017
  return self.nextPC()
899
1018
 
900
1019
  # Declare a multiline input variable
901
1020
  def k_multiline(self, command):
902
- return self.compileVariable(command, 'gui')
903
-
1021
+ self.compiler.addValueType()
1022
+ return self.compileVariable(command, 'ECMultiline')
904
1023
  def r_multiline(self, command):
905
1024
  return self.nextPC()
906
1025
 
907
- # on click {pushbutton}/{lineinput}/{multiline}
1026
+ # on click/tap {pushbutton}/{lineinput}/{multiline}
908
1027
  # on select {combobox}/{listbox}
909
1028
  # on tick
910
1029
  def k_on(self, command):
@@ -934,17 +1053,18 @@ class Graphics(Handler):
934
1053
 
935
1054
  token = self.nextToken()
936
1055
  command['type'] = token
937
- if token == 'click':
1056
+ if token in ['click', 'tap']:
938
1057
  if self.nextIsSymbol():
939
1058
  record = self.getSymbolRecord()
940
- if record['keyword'] in ['pushbutton', 'lineinput', 'multiline']:
1059
+ if isinstance(self.getObject(record), ECWidget):
1060
+ command['domain'] = record['domain']
941
1061
  command['name'] = record['name']
942
1062
  setupOn()
943
1063
  return True
944
1064
  elif token == 'select':
945
1065
  if self.nextIsSymbol():
946
1066
  record = self.getSymbolRecord()
947
- if record['keyword'] in ['combobox', 'listbox']:
1067
+ if isinstance(self.getObject(record), ECCoreWidget):
948
1068
  command['name'] = record['name']
949
1069
  setupOn()
950
1070
  return True
@@ -976,50 +1096,53 @@ class Graphics(Handler):
976
1096
  return False
977
1097
 
978
1098
  def r_on(self, command):
979
- def run(widget, record):
980
- for i, w in enumerate(record['widget']):
981
- if w == widget:
982
- record['index'] = i
983
- self.run(command['goto'])
984
- return
985
-
986
1099
  if command['type'] == 'tick':
987
1100
  self.runOnTick = command['runOnTick']
988
1101
  else:
989
1102
  record = self.getVariable(command['name'])
990
- widget = self.getWidget(record)
991
- keyword = record['keyword']
992
- if keyword == 'pushbutton':
993
- handler = partial(run, widget, record)
1103
+ widget = self.getInnerObject(self.getObject(record))
1104
+ goto = command['goto']
1105
+ if self.isObjectType(record, ECPushButton):
1106
+ handler = partial(self.callback, widget, record, goto)
994
1107
  widget.clicked.connect(handler)
995
- elif keyword == 'combobox':
996
- widget.currentIndexChanged.connect(lambda: self.run(command['goto']))
997
- elif keyword == 'listbox':
998
- widget.itemClicked.connect(lambda: self.run(command['goto']))
1108
+ elif self.isObjectType(record, ECComboBox):
1109
+ widget.currentIndexChanged.connect(lambda: self.run(goto))
1110
+ elif self.isObjectType(record, ECListBox):
1111
+ widget.itemClicked.connect(lambda: self.run(goto))
1112
+ return self.nextPC()
1113
+
1114
+ # Declare a simple panel variable
1115
+ def k_panel(self, command):
1116
+ self.compiler.addValueType()
1117
+ return self.compileVariable(command, 'ECPanel')
1118
+
1119
+ def r_panel(self, command):
999
1120
  return self.nextPC()
1000
1121
 
1001
1122
  # Declare a pushbutton variable
1002
1123
  def k_pushbutton(self, command):
1003
- return self.compileVariable(command, 'gui')
1124
+ self.compiler.addValueType()
1125
+ return self.compileVariable(command, 'ECPushButton')
1004
1126
 
1005
1127
  def r_pushbutton(self, command):
1006
1128
  return self.nextPC()
1007
1129
 
1008
1130
  # remove [the] [current/selected] [item] [from/in] {combobox}/{listbox}
1131
+ # Graphics-reserved syntax: optional article pattern is plugin-safe (core-only command)
1009
1132
  def k_remove(self, command):
1010
1133
  command['variant'] = None
1011
- self.skip('the')
1134
+ self.skipArticles() # Optional 'the', 'a', 'an' — syntactic sugar
1012
1135
  self.skip(['current', 'selected'])
1013
1136
  self.skip('item')
1014
1137
  self.skip(['from', 'in'])
1015
1138
  if self.nextIsSymbol():
1016
1139
  record = self.getSymbolRecord()
1017
- if record['keyword'] == 'combobox':
1140
+ if self.isObjectType(record, ECComboBox):
1018
1141
  command['variant'] = 'current'
1019
1142
  command['name'] = record['name']
1020
1143
  self.add(command)
1021
1144
  return True
1022
- elif record['keyword'] == 'listbox':
1145
+ elif self.isObjectType(record, ECListBox):
1023
1146
  command['variant'] = 'current'
1024
1147
  command['name'] = record['name']
1025
1148
  self.add(command)
@@ -1030,15 +1153,15 @@ class Graphics(Handler):
1030
1153
  variant = command['variant']
1031
1154
  record = self.getVariable(command['name'])
1032
1155
  if variant == 'current':
1033
- if record['keyword'] == 'combobox':
1034
- widget = self.getWidget(record)
1035
- widget.removeItem(widget.currentIndex())
1036
- if record['keyword'] == 'listbox':
1037
- widget = self.getWidget(record)
1038
- selectedItem = widget.currentItem()
1156
+ if self.isObjectType(record, ECComboBox):
1157
+ widget = self.getInnerObject(record)
1158
+ widget.removeItem(widget.currentIndex()) # type: ignore
1159
+ if self.isObjectType(record, ECListBox):
1160
+ widget = self.getInnerObject(record)
1161
+ selectedItem = widget.currentItem() # type: ignore
1039
1162
  if selectedItem:
1040
- row = widget.row(selectedItem)
1041
- widget.takeItem(row)
1163
+ row = widget.row(selectedItem) # type: ignore
1164
+ widget.takeItem(row) # type: ignore
1042
1165
  return self.nextPC()
1043
1166
 
1044
1167
  # select index {n} [of] {combobox]}
@@ -1052,21 +1175,21 @@ class Graphics(Handler):
1052
1175
  self.skip('in')
1053
1176
  if self.nextIsSymbol():
1054
1177
  record = self.getSymbolRecord()
1055
- if record['keyword'] == 'combobox':
1178
+ if self.isObjectType(record, ECComboBox):
1056
1179
  command['widget'] = record['name']
1057
1180
  self.add(command)
1058
1181
  return True
1059
1182
  return False
1060
1183
 
1061
1184
  def r_select(self, command):
1062
- widget = self.getWidget(self.getVariable(command['widget']))
1185
+ widget = self.getInnerObject(self.getVariable(command['widget']))
1063
1186
  if 'index' in command:
1064
- index = self.getRuntimeValue(command['index'])
1187
+ index = self.textify(command['index'])
1065
1188
  else:
1066
- name = self.getRuntimeValue(command['name'])
1067
- index = widget.findText(name, Qt.MatchFixedString)
1189
+ name = self.textify(command['name'])
1190
+ index = widget.findText(name, Qt.MatchFlag.MatchFixedString) # type: ignore
1068
1191
  if index >= 0:
1069
- widget.setCurrentIndex(index)
1192
+ widget.setCurrentIndex(index) # type: ignore
1070
1193
  return self.nextPC()
1071
1194
 
1072
1195
  # set [the] width/height [of] {widget} [to] {value}
@@ -1079,14 +1202,18 @@ class Graphics(Handler):
1079
1202
  # set {listbox} to {list}
1080
1203
  # set blocked true/false
1081
1204
  def k_set(self, command):
1082
- self.skip('the')
1205
+ # Graphics-reserved syntax: optional article pattern with 'of'/'to' prepositions
1206
+ # Forms like 'set the layout of Window to MainPanel' and 'set layout of Window to MainPanel' are equivalent
1207
+ # Plugin-safe: graphics is a core-only module
1208
+ self.skipArticles() # Optional 'the', 'a', 'an' — syntactic sugar for readability
1083
1209
  token = self.nextToken()
1084
1210
  command['what'] = token
1085
1211
  if token in ['width', 'height']:
1086
1212
  self.skip('of')
1087
1213
  if self.nextIsSymbol():
1088
1214
  record = self.getSymbolRecord()
1089
- if record['extra'] == 'gui':
1215
+ if self.isObjectType(record, ECCoreWidget):
1216
+ command['domain'] = record['domain']
1090
1217
  command['name'] = record['name']
1091
1218
  self.skip('to')
1092
1219
  command['value'] = self.nextValue()
@@ -1096,13 +1223,12 @@ class Graphics(Handler):
1096
1223
  self.skip('of')
1097
1224
  if self.nextIsSymbol():
1098
1225
  record = self.getSymbolRecord()
1099
- keyword = record['keyword']
1100
- if keyword in ['window', 'widget']:
1226
+ if self.isObjectType(record, (ECWindow, ECGroup, ECPanel)):
1101
1227
  command['name'] = record['name']
1102
1228
  self.skip('to')
1103
1229
  if self.nextIsSymbol():
1104
1230
  record = self.getSymbolRecord()
1105
- if record['keyword'] == 'layout':
1231
+ if self.isObjectType(record, ECLayout):
1106
1232
  command['layout'] = record['name']
1107
1233
  self.add(command)
1108
1234
  return True
@@ -1110,7 +1236,7 @@ class Graphics(Handler):
1110
1236
  self.skip('of')
1111
1237
  if self.nextIsSymbol():
1112
1238
  record = self.getSymbolRecord()
1113
- if record['keyword'] == 'layout':
1239
+ if self.isObjectType(record, ECLayout):
1114
1240
  command['name'] = record['name']
1115
1241
  self.skip('to')
1116
1242
  command['value'] = self.nextValue()
@@ -1120,7 +1246,7 @@ class Graphics(Handler):
1120
1246
  self.skip('of')
1121
1247
  if self.nextIsSymbol():
1122
1248
  record = self.getSymbolRecord()
1123
- if record['keyword'] in ['label', 'pushbutton', 'lineinput', 'multiline', 'element']:
1249
+ if self.isObjectType(record, (ECLabel, ECPushButton, ECLineInput, ECMultiline)):
1124
1250
  command['name'] = record['name']
1125
1251
  self.skip('to')
1126
1252
  command['value'] = self.nextValue()
@@ -1130,7 +1256,7 @@ class Graphics(Handler):
1130
1256
  self.skip('of')
1131
1257
  if self.nextIsSymbol():
1132
1258
  record = self.getSymbolRecord()
1133
- if record['keyword'] == 'checkbox':
1259
+ if self.isObjectType(record, ECCheckBox):
1134
1260
  command['name'] = record['name']
1135
1261
  self.skip('to')
1136
1262
  if self.peek() == 'checked':
@@ -1146,7 +1272,7 @@ class Graphics(Handler):
1146
1272
  self.skip('of')
1147
1273
  if self.nextIsSymbol():
1148
1274
  record = self.getSymbolRecord()
1149
- if record['extra'] == 'gui':
1275
+ if self.isObjectType(record, ECWidget):
1150
1276
  command['name'] = record['name']
1151
1277
  self.skip('to')
1152
1278
  command['value'] = self.nextValue()
@@ -1156,7 +1282,7 @@ class Graphics(Handler):
1156
1282
  self.skip('of')
1157
1283
  if self.nextIsSymbol():
1158
1284
  record = self.getSymbolRecord()
1159
- if record['extra'] == 'gui':
1285
+ if self.isObjectType(record, ECWidget):
1160
1286
  command['name'] = record['name']
1161
1287
  self.skip('to')
1162
1288
  flags = []
@@ -1169,7 +1295,7 @@ class Graphics(Handler):
1169
1295
  self.skip('of')
1170
1296
  if self.nextIsSymbol():
1171
1297
  record = self.getSymbolRecord()
1172
- if record['keyword'] == 'label':
1298
+ if self.isObjectType(record, ECLabel):
1173
1299
  command['name'] = record['name']
1174
1300
  self.skip('to')
1175
1301
  command['value'] = self.nextValue()
@@ -1179,7 +1305,7 @@ class Graphics(Handler):
1179
1305
  self.skip('of')
1180
1306
  if self.nextIsSymbol():
1181
1307
  record = self.getSymbolRecord()
1182
- if record['keyword'] == 'label':
1308
+ if self.isObjectType(record, ECLabel):
1183
1309
  command['name'] = record['name']
1184
1310
  self.skip('to')
1185
1311
  command['value'] = self.nextValue()
@@ -1190,7 +1316,7 @@ class Graphics(Handler):
1190
1316
  self.skip('of')
1191
1317
  if self.nextIsSymbol():
1192
1318
  record = self.getSymbolRecord()
1193
- if record['keyword'] in ['label', 'pushbutton', 'lineinput', 'multiline']:
1319
+ if self.isObjectType(record, (ECLabel, ECPushButton, ECLineInput, ECMultiline)):
1194
1320
  command['name'] = record['name']
1195
1321
  self.skip('to')
1196
1322
  command['value'] = self.nextValue()
@@ -1201,7 +1327,7 @@ class Graphics(Handler):
1201
1327
  return True
1202
1328
  elif self.isSymbol():
1203
1329
  record = self.getSymbolRecord()
1204
- if record['keyword'] == 'listbox':
1330
+ if self.isObjectType(record, ECListBox):
1205
1331
  command['what'] = 'listbox'
1206
1332
  command['name'] = record['name']
1207
1333
  self.skip('to')
@@ -1213,78 +1339,78 @@ class Graphics(Handler):
1213
1339
  def r_set(self, command):
1214
1340
  what = command['what']
1215
1341
  if what == 'height':
1216
- widget = self.getWidget(self.getVariable(command['name']))
1217
- widget.setFixedHeight(self.getRuntimeValue(command['value']))
1342
+ widget = self.getInnerObject(self.getVariable(command['name']))
1343
+ widget.setFixedHeight(self.textify(command['value'])) # type: ignore
1218
1344
  elif what == 'width':
1219
- widget = self.getWidget(self.getVariable(command['name']))
1220
- widget.setFixedWidth(self.getRuntimeValue(command['value']))
1345
+ widget = self.getInnerObject(self.getVariable(command['name']))
1346
+ widget.setFixedWidth(self.textify(command['value'])) # type: ignore
1221
1347
  elif what == 'layout':
1222
- record = self.getVariable(command['layout'])
1223
- layout = record['widget']
1224
- record = self.getVariable(command['name'])
1225
- keyword = record['keyword']
1226
- if keyword == 'window':
1227
- window = record['window']
1348
+ target = self.getVariable(command['name'])
1349
+ object = target['object']
1350
+ layoutObject = self.getVariable(command['layout'])['object']
1351
+ self.checkObjectType(layoutObject, ECLayout)
1352
+ layout = self.getInnerObject(layoutObject)
1353
+ if isinstance(object, ECWindow):
1354
+ window = self.getInnerObject(object)
1228
1355
  container = QWidget()
1229
- container.setLayout(layout)
1230
- window.setCentralWidget(container)
1231
- elif keyword == 'widget':
1232
- widget = self.getWidget(record)
1233
- widget.setLayout(layout)
1356
+ container.setLayout(layout) # type: ignore
1357
+ self.getInnerObject(object).setCentralWidget(container) # type: ignore
1358
+ elif isinstance(object, (ECLayout, ECGroup, ECPanel)):
1359
+ self.getInnerObject(object).setLayout(layout) # type: ignore
1234
1360
  elif what == 'spacing':
1235
- layout = self.getWidget(self.getVariable(command['name']))
1236
- layout.setSpacing(self.getRuntimeValue(command['value']))
1361
+ layout = self.getInnerObject(self.getVariable(command['name']))
1362
+ layout.setSpacing(self.textify(command['value'])) # type: ignore
1237
1363
  elif what == 'text':
1238
1364
  record = self.getVariable(command['name'])
1239
- widget = self.getWidget(record)
1240
- text = self.getRuntimeValue(command['value'])
1365
+ widget = self.getInnerObject(record)
1366
+ text = self.textify(command['value'])
1241
1367
  keyword = record['keyword']
1242
1368
  setText = getattr(widget, "setText", None)
1243
1369
  if callable(setText):
1244
- widget.setText(text)
1245
- elif keyword == 'multiline':
1246
- widget.setPlainText(text)
1247
- if record['keyword'] == 'pushbutton':
1248
- widget.setAccessibleName(text)
1370
+ widget.setText(text) # type: ignore
1371
+ elif self.isObjectType(record, ECMultiline):
1372
+ widget.setPlainText(text) # type: ignore
1373
+ if self.isObjectType(record, ECPushButton):
1374
+ widget.setAccessibleName(text) # type: ignore
1249
1375
  elif what == 'state':
1250
1376
  record = self.getVariable(command['name'])
1251
- if record['keyword'] == 'checkbox':
1252
- state = self.getRuntimeValue(command['value'])
1253
- self.getWidget(record).setChecked(state)
1377
+ if self.isObjectType(record, ECCheckBox):
1378
+ state = self.textify(command['value'])
1379
+ self.getInnerObject(record).setChecked(state) # type: ignore
1254
1380
  elif what == 'alignment':
1255
1381
  widget = self.getVariable(command['name'])['widget']
1256
1382
  flags = command['value']
1257
1383
  alignment = 0
1258
1384
  for flag in flags:
1259
- if flag == 'left': alignment |= Qt.AlignLeft
1260
- elif flag == 'hcenter': alignment |= Qt.AlignHCenter
1261
- elif flag == 'right': alignment |= Qt.AlignRight
1262
- elif flag == 'top': alignment |= Qt.AlignTop
1263
- elif flag == 'vcenter': alignment |= Qt.AlignVCenter
1264
- elif flag == 'bottom': alignment |= Qt.AlignBottom
1265
- elif flag == 'center': alignment |= Qt.AlignCenter
1385
+ if flag == 'left': alignment |= Qt.AlignmentFlag.AlignLeft
1386
+ elif flag == 'hcenter': alignment |= Qt.AlignmentFlag.AlignHCenter
1387
+ elif flag == 'right': alignment |= Qt.AlignmentFlag.AlignRight
1388
+ elif flag == 'top': alignment |= Qt.AlignmentFlag.AlignTop
1389
+ elif flag == 'vcenter': alignment |= Qt.AlignmentFlag.AlignVCenter
1390
+ elif flag == 'bottom': alignment |= Qt.AlignmentFlag.AlignBottom
1391
+ elif flag == 'center': alignment |= Qt.AlignmentFlag.AlignCenter
1266
1392
  widget.setAlignment(alignment)
1267
1393
  elif what == 'style':
1268
1394
  record = self.getVariable(command['name'])
1269
- widget = self.getWidget(record)
1270
- styles = self.getRuntimeValue(command['value'])
1271
- widget.setStyleSheet(styles)
1395
+ widget = self.getInnerObject(record)
1396
+ styles = self.textify(command['value'])
1397
+ widget.setStyleSheet(styles) # type: ignore
1272
1398
  elif what == 'color':
1273
1399
  record = self.getVariable(command['name'])
1274
- widget = self.getWidget(record)
1275
- color = self.getRuntimeValue(command['value'])
1276
- widget.setStyleSheet(f"color: {color};")
1400
+ widget = self.getInnerObject(record)
1401
+ color = self.textify(command['value'])
1402
+ widget.setStyleSheet(f"color: {color};") # type: ignore
1277
1403
  elif what == 'background-color':
1278
1404
  record = self.getVariable(command['name'])
1279
- widget = self.getWidget(record)
1280
- bg_color = self.getRuntimeValue(command['value'])
1281
- widget.setStyleSheet(f"background-color: {bg_color};")
1405
+ widget = self.getInnerObject(record)
1406
+ bg_color = self.textify(command['value'])
1407
+ widget.setStyleSheet(f"background-color: {bg_color};") # type: ignore
1282
1408
  elif what == 'listbox':
1283
1409
  record = self.getVariable(command['name'])
1284
- widget = self.getWidget(record)
1285
- value = self.getRuntimeValue(command['value'])
1286
- widget.clear()
1287
- widget.addItems(value)
1410
+ widget = self.getInnerObject(record)
1411
+ value = self.textify(command['value'])
1412
+ widget.clear() # type: ignore
1413
+ widget.addItems(value) # type: ignore
1288
1414
  return self.nextPC()
1289
1415
 
1290
1416
  # show {window}
@@ -1294,20 +1420,20 @@ class Graphics(Handler):
1294
1420
  def k_show(self, command):
1295
1421
  if self.nextIsSymbol():
1296
1422
  record = self.getSymbolRecord()
1297
- keyword = record['keyword']
1298
- if keyword == 'window':
1299
- command['window'] = record['name']
1423
+ if self.isObjectType(record, ECCoreWidget):
1424
+ command['domain'] = record['domain']
1425
+ command['name'] = record['name']
1300
1426
  self.add(command)
1301
1427
  return True
1302
- elif keyword == 'dialog':
1303
- command['dialog'] = record['name']
1428
+ elif self.isObjectType(record, ECWindow):
1429
+ command['window'] = record['name']
1304
1430
  self.add(command)
1305
1431
  return True
1306
- elif self.isWidget(keyword):
1307
- command['name'] = record['name']
1432
+ elif self.isObjectType(record, ECDialog):
1433
+ command['dialog'] = record['name']
1308
1434
  self.add(command)
1309
1435
  return True
1310
- elif keyword == 'messagebox':
1436
+ elif self.isObjectType(record, ECMessageBox):
1311
1437
  command['messagebox'] = record['name']
1312
1438
  self.skip('giving')
1313
1439
  if self.nextIsSymbol():
@@ -1318,95 +1444,65 @@ class Graphics(Handler):
1318
1444
 
1319
1445
  def r_show(self, command):
1320
1446
  if 'messagebox' in command:
1321
- data = self.getVariable(command['messagebox'])['data']
1322
- symbolRecord = self.getVariable(command['result'])
1323
- window = self.getVariable(data['window'])['window']
1324
- style = data['style']
1325
- title = data['title']
1326
- message = data['message']
1447
+ record = self.getVariable(command['messagebox'])
1448
+ windowRecord = self.getVariable(record['window'])
1449
+ window = self.getInnerObject(windowRecord)
1450
+ style = record['style']
1451
+ title = record['title']
1452
+ message = record['message']
1453
+ target = self.getVariable(command['result'])
1327
1454
  if style == 'question':
1328
1455
  choice = QMessageBox.question(window, title, message)
1329
- result = 'Yes' if choice == QMessageBox.Yes else 'No'
1456
+ result = 'Yes' if choice == QMessageBox.StandardButton.Yes else 'No'
1330
1457
  elif style == 'yesnocancel':
1331
1458
  choice = QMessageBox.question(
1332
1459
  window,
1333
1460
  title,
1334
1461
  message,
1335
- QMessageBox.Yes | QMessageBox.No | QMessageBox.Cancel
1462
+ QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No | QMessageBox.StandardButton.Cancel
1336
1463
  )
1337
- if choice == QMessageBox.Yes:
1464
+ if choice == QMessageBox.StandardButton.Yes:
1338
1465
  result = 'Yes'
1339
- elif choice == QMessageBox.No:
1466
+ elif choice == QMessageBox.StandardButton.No:
1340
1467
  result = 'No'
1341
1468
  else:
1342
1469
  result = 'Cancel'
1343
1470
  elif style == 'warning':
1344
1471
  choice = QMessageBox.warning(window, title, message)
1345
- if choice == QMessageBox.Ok: result = 'OK'
1472
+ if choice == QMessageBox.StandardButton.Ok: result = 'OK'
1346
1473
  else: result = ''
1347
1474
  else: result = 'Cancel'
1348
- v = {}
1349
- v['type'] = 'text'
1350
- v['content'] = result
1351
- self.putSymbolValue(symbolRecord, v)
1475
+ v = ECValue(domain='graphics', type=str, content=result)
1476
+ self.putSymbolValue(target, v)
1352
1477
  elif 'window' in command:
1353
- window = self.getVariable(command['window'])['window']
1354
- window.show()
1478
+ window = self.getInnerObject(self.getVariable(command['window'])['object'])
1479
+ window.show() # type: ignore
1355
1480
  elif 'dialog' in command:
1356
1481
  record = self.getVariable(command['dialog'])
1357
- dialog = record['dialog']
1482
+ object = self.getObject(record)
1483
+ dialog = self.getInnerObject(record)
1358
1484
  if dialog.dialogType == 'generic':
1359
- record['result'] = dialog.exec()
1485
+ object.result = dialog.exec()
1360
1486
  elif dialog.dialogType == 'confirm':
1361
- record['result'] = True if dialog.exec() == QDialog.Accepted else False
1487
+ object.result = True if dialog.exec() == QDialog.DialogCode.Accepted else False
1488
+ pass
1362
1489
  elif dialog.dialogType == 'lineedit':
1363
- if dialog.exec() == QDialog.Accepted:
1364
- record['result'] = dialog.lineEdit.text()
1365
- else: record['result'] = dialog.value
1490
+ if dialog.exec() == QDialog.DialogCode.Accepted:
1491
+ object.result = dialog.lineEdit.text() # type: ignore
1492
+ else: object.result = dialog.value # type: ignore
1366
1493
  elif dialog.dialogType == 'multiline':
1367
- if dialog.exec() == QDialog.Accepted:
1368
- record['result'] = dialog.textEdit.toPlainText()
1369
- else: record['result'] = dialog.value
1494
+ if dialog.exec() == QDialog.DialogCode.Accepted:
1495
+ object.result = dialog.textEdit.toPlainText() # type: ignore
1496
+ else: object.result = dialog.value # type: ignore
1370
1497
  elif 'name' in command:
1371
1498
  record = self.getVariable(command['name'])
1372
- if 'widget' in record: self.getWidget(record).show()
1373
- return self.nextPC()
1374
-
1375
- # Start the graphics
1376
- def k_start(self, command):
1377
- if self.nextIs('graphics'):
1378
- self.add(command)
1379
- return True
1380
- return False
1381
-
1382
- def r_start(self, command):
1383
- return self.nextPC()
1384
- # def on_last_window_closed():
1385
- # self.program.kill()
1386
- # def init():
1387
- # self.program.flush(self.nextPC())
1388
- # def flush():
1389
- # if not self.blocked:
1390
- # if self.runOnTick != 0:
1391
- # self.program.run(self.runOnTick)
1392
- # self.program.flushCB()
1393
- # timer = QTimer()
1394
- # timer.timeout.connect(flush)
1395
- # timer.start(10)
1396
- # QTimer.singleShot(500, init)
1397
- # self.app.lastWindowClosed.connect(on_last_window_closed)
1398
- # self.app.exec()
1399
-
1400
- # Declare a widget variable
1401
- def k_widget(self, command):
1402
- return self.compileVariable(command, 'gui')
1403
-
1404
- def r_widget(self, command):
1499
+ self.getInnerObject(record).show() # type: ignore
1405
1500
  return self.nextPC()
1406
1501
 
1407
1502
  # Declare a window variable
1408
1503
  def k_window(self, command):
1409
- return self.compileVariable(command)
1504
+ self.compiler.addValueType()
1505
+ return self.compileVariable(command, 'ECWindow')
1410
1506
 
1411
1507
  def r_window(self, command):
1412
1508
  return self.nextPC()
@@ -1414,42 +1510,57 @@ class Graphics(Handler):
1414
1510
  #############################################################################
1415
1511
  # Compile a value in this domain
1416
1512
  def compileValue(self):
1417
- value = {}
1418
- value['domain'] = self.getName()
1513
+ value = ECValue(domain=self.getName())
1419
1514
  token = self.getToken()
1420
1515
  if self.isSymbol():
1516
+ value.setContent(token)
1421
1517
  record = self.getSymbolRecord()
1422
- if record['extra'] == 'gui':
1423
- if self.isWidget(record['keyword']):
1424
- value['name'] = token
1425
- value['type'] = 'symbol'
1426
- return value
1427
-
1518
+ object = self.getObject(record)
1519
+ if isinstance(object, ECCoreWidget) and object.hasRuntimeValue():
1520
+ value.setType('object')
1521
+ return value
1522
+ else: return None
1428
1523
  else:
1429
1524
  if self.tokenIs('the'): token = self.nextToken()
1430
- if token == 'count':
1525
+ value.setType(token)
1526
+ if token in ['count', 'current', 'selected']:
1527
+ value.setType(token)
1528
+ if token == 'count':
1529
+ self.skip('of')
1530
+ elif token in ['current', 'selected']:
1531
+ token = self.nextToken()
1532
+ value.option = token
1533
+ if token == 'item': self.skip('in')
1534
+ elif token == 'index': self.skip('of')
1535
+ if self.nextIsSymbol():
1536
+ record = self.getSymbolRecord()
1537
+ if self.isObjectType(record, ECListBox) or self.isObjectType(record, ECComboBox): # type: ignore
1538
+ value.setContent(ECValue(domain=self.getName(), type='object', content=record['name']))
1539
+ return value
1540
+ elif token == 'count':
1431
1541
  self.skip('of')
1432
1542
  if self.nextIsSymbol():
1433
- value['type'] = 'symbol'
1434
1543
  record = self.getSymbolRecord()
1435
- keyword = record['keyword']
1436
- if keyword in ['combobox', 'listbox']:
1437
- value['type'] = 'count'
1438
- value['name'] = record['name']
1544
+ if self.isObjectType(record, ECListBox) or self.isObjectType(record, ECComboBox): # type: ignore
1545
+ value.setContent(ECValue(domain=self.getName(), type='object', content=record['name']))
1439
1546
  return value
1440
-
1441
- elif token == 'current':
1442
- self.skip('item')
1443
- self.skip('in')
1547
+ elif token == 'text':
1548
+ self.skip('of')
1444
1549
  if self.nextIsSymbol():
1445
- value['type'] = 'symbol'
1446
1550
  record = self.getSymbolRecord()
1447
- keyword = record['keyword']
1448
- if keyword == 'listbox':
1449
- value['type'] = 'current'
1450
- value['name'] = record['name']
1551
+ if (
1552
+ self.isObjectType(record, (ECLabel, ECPushButton, ECMultiline, ECLineInput))
1553
+ ): # type: ignore
1554
+ value.setContent(ECValue(domain=self.getName(), type='object', content=record['name']))
1555
+ return value
1556
+ elif token == 'index':
1557
+ self.skip('of')
1558
+ value.element = self.getValue()
1559
+ if self.nextIsSymbol():
1560
+ record = self.getSymbolRecord()
1561
+ if self.isObjectType(record, (ECListBox, ECComboBox)): # type: ignore
1562
+ value.setContent(ECValue(domain=self.getName(), type='object', content=record['name']))
1451
1563
  return value
1452
-
1453
1564
  return None
1454
1565
 
1455
1566
  #############################################################################
@@ -1461,80 +1572,104 @@ class Graphics(Handler):
1461
1572
  # Value handlers
1462
1573
 
1463
1574
  # This is used by the expression evaluator to get the value of a symbol
1464
- def v_symbol(self, symbolRecord):
1465
- symbolRecord = self.getVariable(symbolRecord['name'])
1466
- keyword = symbolRecord['keyword']
1467
- if keyword == 'pushbutton':
1468
- pushbutton = self.getWidget(symbolRecord)
1469
- v = {}
1470
- v['type'] = 'text'
1471
- v['content'] = pushbutton.accessibleName()
1575
+ def v_symbol(self, record):
1576
+ record = self.getVariable(record['name'])
1577
+ keyword = record['keyword']
1578
+ if self.isObjectType(record, ECPushButton):
1579
+ pushbutton = self.getInnerObject(record)
1580
+ v = ECValue(domain=self.getName(), type=str, content=pushbutton.accessibleName())
1472
1581
  return v
1473
- elif keyword == 'lineinput':
1474
- lineinput = self.getWidget(symbolRecord)
1475
- v = {}
1476
- v['type'] = 'text'
1477
- v['content'] = lineinput.displayText()
1582
+ elif self.isObjectType(record, ECLineInput):
1583
+ lineinput = self.getInnerObject(record)
1584
+ v = ECValue(domain=self.getName(), type=str, content=lineinput.displayText())
1478
1585
  return v
1479
- elif keyword == 'multiline':
1480
- multiline = self.getWidget(symbolRecord)
1481
- v = {}
1482
- v['type'] = 'text'
1483
- v['content'] = multiline.toPlainText()
1586
+ elif self.isObjectType(record, ECMultiline):
1587
+ multiline = self.getInnerObject(record)
1588
+ v = ECValue(domain=self.getName(), type=str, content=multiline.toPlainText())
1484
1589
  return v
1485
- elif keyword == 'combobox':
1486
- combobox = self.getWidget(symbolRecord)
1487
- v = {}
1488
- v['type'] = 'text'
1489
- v['content'] = combobox.currentText()
1590
+ elif self.isObjectType(record, ECComboBox):
1591
+ combobox = self.getInnerObject(record)
1592
+ v = ECValue(domain=self.getName(), type=str, content=combobox.currentText())
1490
1593
  return v
1491
- elif keyword == 'listbox':
1492
- listbox = self.getWidget(symbolRecord)
1493
- content = listbox.currentItem().text()
1494
- v = {}
1495
- v['type'] = 'text'
1496
- v['content'] = content
1594
+ elif self.isObjectType(record, ECListBox):
1595
+ listbox = self.getInnerObject(record)
1596
+ content = listbox.currentItem().text() # type: ignore
1597
+ v = ECValue(domain=self.getName(), type=str, content=content)
1497
1598
  return v
1498
- elif keyword == 'checkbox':
1499
- checkbox =self.getWidget(symbolRecord)
1500
- content = checkbox.isChecked()
1501
- v = {}
1502
- v['type'] = 'boolean'
1503
- v['content'] = content
1599
+ elif self.isObjectType(record, ECCheckBox):
1600
+ checkbox =self.getInnerObject(record)
1601
+ content = checkbox.isChecked() # type: ignore
1602
+ v = ECValue(domain=self.getName(), type=bool, content=content)
1504
1603
  return v
1505
- elif keyword == 'dialog':
1506
- content = symbolRecord['result']
1507
- v = {}
1508
- v['type'] = 'text'
1509
- v['content'] = content
1604
+ elif self.isObjectType(record, ECDialog):
1605
+ content = record['result']
1606
+ v = ECValue(domain=self.getName(), type=str, content=content)
1510
1607
  return v
1511
1608
  return None
1512
1609
 
1513
1610
  def v_count(self, v):
1514
- record = self.getVariable(v['name'])
1515
- keyword = record['keyword']
1516
- widget = self.getWidget(record)
1517
- if keyword in ['combobox', 'listbox']: content = widget.count()
1518
- value = {}
1519
- value['type'] = 'int'
1520
- value['content'] = content
1521
- return value
1611
+ content = v.getContent()
1612
+ if isinstance(content, ECValue) and content.getType() == 'object':
1613
+ record = self.getVariable(content.getContent())
1614
+ object = self.getObject(record)
1615
+ if isinstance(object, (ECListBox, ECComboBox)):
1616
+ widget = self.getInnerObject(object)
1617
+ value = widget.count() # type: ignore
1618
+ return ECValue(domain=self.getName(), type=int, content=value) # type: ignore
1619
+ else: raise RuntimeError(self.program, f"Object is not a listbox or combobox")
1522
1620
 
1523
1621
  def v_current(self, v):
1524
- record = self.getVariable(v['name'])
1525
- keyword = record['keyword']
1526
- widget = self.getWidget(record)
1527
- if keyword == 'listbox': content = widget.currentItem().text()
1528
- value = {}
1529
- value['type'] = 'text'
1530
- value['content'] = content
1531
- return value
1622
+ content = v.getContent()
1623
+ if isinstance(content, ECValue) and content.getType() == 'object':
1624
+ record = self.getVariable(content.getContent())
1625
+ object = self.getObject(record)
1626
+ option = v.option
1627
+ if isinstance(object, (ECListBox)):
1628
+ if option == 'item':
1629
+ content = object.getText() # type: ignore
1630
+ elif option == 'index':
1631
+ content = object.getIndex() # type: ignore
1632
+ return ECValue(domain=self.getName(), type=int, content=content)
1633
+ elif isinstance(object, (ECComboBox)):
1634
+ content = str(object.currentText()) # type: ignore
1635
+ return ECValue(domain=self.getName(), type=int, content=content)
1636
+ else: raise RuntimeError(self.program, f"Object is not a listbox or combobox")
1637
+
1638
+ def v_element(self, v):
1639
+ return v.getContent()
1640
+
1641
+ def v_empty(self, v):
1642
+ if v.type == 'object':
1643
+ record = self.getVariable(v.getContent())
1644
+ object = self.getObject(record)
1645
+ value = object.isEmpty()
1646
+ return ECValue(domain=self.getName(), type=bool, content=value) # type: ignore
1647
+ return None
1648
+
1649
+ def v_selected(self, v): return self.v_current(v)
1650
+
1651
+ def v_text(self, v):
1652
+ content = v.getContent()
1653
+ if isinstance(content, ECValue) and content.getType() == 'object':
1654
+ record = self.getVariable(content.getContent())
1655
+ object = self.getObject(record)
1656
+ value = object.getText()
1657
+ return ECValue(domain=self.getName(), type=int, content=value) # type: ignore
1658
+
1659
+ #############################################################################
1660
+ # Get the value of an unknown item (domain-specific)
1661
+ def getUnknownValue(self, value):
1662
+ if self.isObjectType(value, (ECLabelWidget, ECPushButtonWidget, ECLineEditWidget, ECListBoxWidget, ECComboBoxWidget)):
1663
+ return value.text() # type: ignore
1664
+ if self.isObjectType(value, (ECDialogWindow,)):
1665
+ return value.result() # type: ignore
1666
+ return None # Unable to get value
1532
1667
 
1533
1668
  #############################################################################
1534
1669
  # Compile a condition
1535
1670
  def compileCondition(self):
1536
- condition = Object()
1537
- condition.negate = False
1671
+ condition = ECValue()
1672
+ condition.negate = False # type: ignore
1538
1673
  return None
1539
1674
 
1540
1675
  #############################################################################