easycoder 251105.1__py2.py3-none-any.whl → 251215.2__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.
@@ -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) # type: ignore
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) # type: ignore
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() # type: ignore
315
+ self.getInnerObject(layoutRecord).addStretch() # type: ignore
225
316
  elif widget == 'spacer':
226
- self.getWidget(layoutRecord).addSpacing(self.getRuntimeValue(command['size'])) # type: ignore
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
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) # type: ignore
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,25 +708,21 @@ 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']))
715
+ group = QGroupBox(self.textify(command['title']))
591
716
  group.setAlignment(Qt.AlignmentFlag.AlignLeft)
592
- record['widget'] = group
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']
@@ -611,15 +732,15 @@ class Graphics(Handler):
611
732
  elif alignment == 'justify': label.setAlignment(Qt.AlignmentFlag.AlignJustify)
612
733
  if 'expand' in command:
613
734
  label.setSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Preferred)
614
- self.setWidget(record, label)
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}')
@@ -628,76 +749,63 @@ class Graphics(Handler):
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
- """)
765
+ checkbox = ECCheckBoxWidget(self.textify(command['text']))
661
766
  checkbox.setSizePolicy(QSizePolicy.Policy.Fixed, QSizePolicy.Policy.Preferred)
662
- self.setWidget(record, checkbox)
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,8 +819,8 @@ 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
825
  dialog.dialogType = dialogType # type: ignore
718
826
  mainLayout = QVBoxLayout(dialog)
@@ -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) # type: ignore
742
- dialog.value = self.getRuntimeValue(command['value']) # type: ignore
848
+ mainLayout.addWidget(ECLabelWidget(prompt))
849
+ dialog.lineEdit = self.ECLineEdit(dialog) # type: ignore
850
+ dialog.value = self.textify(command['value']) # type: ignore
743
851
  dialog.lineEdit.setText(dialog.value) # type: ignore
744
852
  mainLayout.addWidget(dialog.lineEdit) # type: ignore
745
853
  elif dialogType == 'multiline':
746
- mainLayout.addWidget(QLabel(prompt))
747
- dialog.textEdit = self.ClickablePlainTextEdit(self) # type: ignore
854
+ mainLayout.addWidget(ECLabelWidget(prompt))
855
+ dialog.textEdit = self.ECPlainTextEdit(dialog) # type: ignore
748
856
  dialog.textEdit.setText(dialog.value) # type: ignore
749
857
  mainLayout.addWidget(dialog.textEdit) # type: ignore
750
858
  buttonBox = QDialogButtonBox(QDialogButtonBox.StandardButton.Ok | QDialogButtonBox.StandardButton.Cancel)
751
859
  buttonBox.accepted.connect(dialog.accept)
752
860
  buttonBox.rejected.connect(dialog.reject)
753
861
  mainLayout.addWidget(buttonBox, alignment=Qt.AlignmentFlag.AlignHCenter)
754
- record['dialog'] = dialog
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) # type: ignore
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) # type: ignore
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,13 +942,14 @@ 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() # type: ignore
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
955
  self.program.screenWidth = screen[0] # type: ignore
@@ -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,31 +1096,33 @@ 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)
994
- widget.clicked.connect(handler) # type: ignore
995
- elif keyword == 'combobox':
996
- widget.currentIndexChanged.connect(lambda: self.run(command['goto'])) # type: ignore
997
- elif keyword == 'listbox':
998
- widget.itemClicked.connect(lambda: self.run(command['goto'])) # type: ignore
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)
1107
+ widget.clicked.connect(handler)
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()
@@ -1014,12 +1136,12 @@ class Graphics(Handler):
1014
1136
  self.skip(['from', 'in'])
1015
1137
  if self.nextIsSymbol():
1016
1138
  record = self.getSymbolRecord()
1017
- if record['keyword'] == 'combobox':
1139
+ if self.isObjectType(record, ECComboBox):
1018
1140
  command['variant'] = 'current'
1019
1141
  command['name'] = record['name']
1020
1142
  self.add(command)
1021
1143
  return True
1022
- elif record['keyword'] == 'listbox':
1144
+ elif self.isObjectType(record, ECListBox):
1023
1145
  command['variant'] = 'current'
1024
1146
  command['name'] = record['name']
1025
1147
  self.add(command)
@@ -1030,11 +1152,11 @@ class Graphics(Handler):
1030
1152
  variant = command['variant']
1031
1153
  record = self.getVariable(command['name'])
1032
1154
  if variant == 'current':
1033
- if record['keyword'] == 'combobox':
1034
- widget = self.getWidget(record)
1155
+ if self.isObjectType(record, ECComboBox):
1156
+ widget = self.getInnerObject(record)
1035
1157
  widget.removeItem(widget.currentIndex()) # type: ignore
1036
- if record['keyword'] == 'listbox':
1037
- widget = self.getWidget(record)
1158
+ if self.isObjectType(record, ECListBox):
1159
+ widget = self.getInnerObject(record)
1038
1160
  selectedItem = widget.currentItem() # type: ignore
1039
1161
  if selectedItem:
1040
1162
  row = widget.row(selectedItem) # type: ignore
@@ -1052,18 +1174,18 @@ class Graphics(Handler):
1052
1174
  self.skip('in')
1053
1175
  if self.nextIsSymbol():
1054
1176
  record = self.getSymbolRecord()
1055
- if record['keyword'] == 'combobox':
1177
+ if self.isObjectType(record, ECComboBox):
1056
1178
  command['widget'] = record['name']
1057
1179
  self.add(command)
1058
1180
  return True
1059
1181
  return False
1060
1182
 
1061
1183
  def r_select(self, command):
1062
- widget = self.getWidget(self.getVariable(command['widget']))
1184
+ widget = self.getInnerObject(self.getVariable(command['widget']))
1063
1185
  if 'index' in command:
1064
- index = self.getRuntimeValue(command['index'])
1186
+ index = self.textify(command['index'])
1065
1187
  else:
1066
- name = self.getRuntimeValue(command['name'])
1188
+ name = self.textify(command['name'])
1067
1189
  index = widget.findText(name, Qt.MatchFlag.MatchFixedString) # type: ignore
1068
1190
  if index >= 0:
1069
1191
  widget.setCurrentIndex(index) # type: ignore
@@ -1086,7 +1208,8 @@ class Graphics(Handler):
1086
1208
  self.skip('of')
1087
1209
  if self.nextIsSymbol():
1088
1210
  record = self.getSymbolRecord()
1089
- if record['extra'] == 'gui':
1211
+ if self.isObjectType(record, ECCoreWidget):
1212
+ command['domain'] = record['domain']
1090
1213
  command['name'] = record['name']
1091
1214
  self.skip('to')
1092
1215
  command['value'] = self.nextValue()
@@ -1096,13 +1219,12 @@ class Graphics(Handler):
1096
1219
  self.skip('of')
1097
1220
  if self.nextIsSymbol():
1098
1221
  record = self.getSymbolRecord()
1099
- keyword = record['keyword']
1100
- if keyword in ['window', 'widget']:
1222
+ if self.isObjectType(record, (ECWindow, ECGroup, ECPanel)):
1101
1223
  command['name'] = record['name']
1102
1224
  self.skip('to')
1103
1225
  if self.nextIsSymbol():
1104
1226
  record = self.getSymbolRecord()
1105
- if record['keyword'] == 'layout':
1227
+ if self.isObjectType(record, ECLayout):
1106
1228
  command['layout'] = record['name']
1107
1229
  self.add(command)
1108
1230
  return True
@@ -1110,7 +1232,7 @@ class Graphics(Handler):
1110
1232
  self.skip('of')
1111
1233
  if self.nextIsSymbol():
1112
1234
  record = self.getSymbolRecord()
1113
- if record['keyword'] == 'layout':
1235
+ if self.isObjectType(record, ECLayout):
1114
1236
  command['name'] = record['name']
1115
1237
  self.skip('to')
1116
1238
  command['value'] = self.nextValue()
@@ -1120,7 +1242,7 @@ class Graphics(Handler):
1120
1242
  self.skip('of')
1121
1243
  if self.nextIsSymbol():
1122
1244
  record = self.getSymbolRecord()
1123
- if record['keyword'] in ['label', 'pushbutton', 'lineinput', 'multiline', 'element']:
1245
+ if self.isObjectType(record, (ECLabel, ECPushButton, ECLineInput, ECMultiline)):
1124
1246
  command['name'] = record['name']
1125
1247
  self.skip('to')
1126
1248
  command['value'] = self.nextValue()
@@ -1130,7 +1252,7 @@ class Graphics(Handler):
1130
1252
  self.skip('of')
1131
1253
  if self.nextIsSymbol():
1132
1254
  record = self.getSymbolRecord()
1133
- if record['keyword'] == 'checkbox':
1255
+ if self.isObjectType(record, ECCheckBox):
1134
1256
  command['name'] = record['name']
1135
1257
  self.skip('to')
1136
1258
  if self.peek() == 'checked':
@@ -1146,7 +1268,7 @@ class Graphics(Handler):
1146
1268
  self.skip('of')
1147
1269
  if self.nextIsSymbol():
1148
1270
  record = self.getSymbolRecord()
1149
- if record['extra'] == 'gui':
1271
+ if self.isObjectType(record, ECWidget):
1150
1272
  command['name'] = record['name']
1151
1273
  self.skip('to')
1152
1274
  command['value'] = self.nextValue()
@@ -1156,7 +1278,7 @@ class Graphics(Handler):
1156
1278
  self.skip('of')
1157
1279
  if self.nextIsSymbol():
1158
1280
  record = self.getSymbolRecord()
1159
- if record['extra'] == 'gui':
1281
+ if self.isObjectType(record, ECWidget):
1160
1282
  command['name'] = record['name']
1161
1283
  self.skip('to')
1162
1284
  flags = []
@@ -1169,7 +1291,7 @@ class Graphics(Handler):
1169
1291
  self.skip('of')
1170
1292
  if self.nextIsSymbol():
1171
1293
  record = self.getSymbolRecord()
1172
- if record['keyword'] == 'label':
1294
+ if self.isObjectType(record, ECLabel):
1173
1295
  command['name'] = record['name']
1174
1296
  self.skip('to')
1175
1297
  command['value'] = self.nextValue()
@@ -1179,7 +1301,7 @@ class Graphics(Handler):
1179
1301
  self.skip('of')
1180
1302
  if self.nextIsSymbol():
1181
1303
  record = self.getSymbolRecord()
1182
- if record['keyword'] == 'label':
1304
+ if self.isObjectType(record, ECLabel):
1183
1305
  command['name'] = record['name']
1184
1306
  self.skip('to')
1185
1307
  command['value'] = self.nextValue()
@@ -1190,7 +1312,7 @@ class Graphics(Handler):
1190
1312
  self.skip('of')
1191
1313
  if self.nextIsSymbol():
1192
1314
  record = self.getSymbolRecord()
1193
- if record['keyword'] in ['label', 'pushbutton', 'lineinput', 'multiline']:
1315
+ if self.isObjectType(record, (ECLabel, ECPushButton, ECLineInput, ECMultiline)):
1194
1316
  command['name'] = record['name']
1195
1317
  self.skip('to')
1196
1318
  command['value'] = self.nextValue()
@@ -1201,7 +1323,7 @@ class Graphics(Handler):
1201
1323
  return True
1202
1324
  elif self.isSymbol():
1203
1325
  record = self.getSymbolRecord()
1204
- if record['keyword'] == 'listbox':
1326
+ if self.isObjectType(record, ECListBox):
1205
1327
  command['what'] = 'listbox'
1206
1328
  command['name'] = record['name']
1207
1329
  self.skip('to')
@@ -1213,44 +1335,44 @@ class Graphics(Handler):
1213
1335
  def r_set(self, command):
1214
1336
  what = command['what']
1215
1337
  if what == 'height':
1216
- widget = self.getWidget(self.getVariable(command['name']))
1217
- widget.setFixedHeight(self.getRuntimeValue(command['value'])) # type: ignore
1338
+ widget = self.getInnerObject(self.getVariable(command['name']))
1339
+ widget.setFixedHeight(self.textify(command['value'])) # type: ignore
1218
1340
  elif what == 'width':
1219
- widget = self.getWidget(self.getVariable(command['name']))
1220
- widget.setFixedWidth(self.getRuntimeValue(command['value'])) # type: ignore
1341
+ widget = self.getInnerObject(self.getVariable(command['name']))
1342
+ widget.setFixedWidth(self.textify(command['value'])) # type: ignore
1221
1343
  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']
1344
+ target = self.getVariable(command['name'])
1345
+ object = target['object']
1346
+ layoutObject = self.getVariable(command['layout'])['object']
1347
+ self.checkObjectType(layoutObject, ECLayout)
1348
+ layout = self.getInnerObject(layoutObject)
1349
+ if isinstance(object, ECWindow):
1350
+ window = self.getInnerObject(object)
1228
1351
  container = QWidget()
1229
- container.setLayout(layout)
1230
- window.setCentralWidget(container)
1231
- elif keyword == 'widget':
1232
- widget = self.getWidget(record)
1233
- widget.setLayout(layout) # type: ignore
1352
+ container.setLayout(layout) # type: ignore
1353
+ self.getInnerObject(object).setCentralWidget(container) # type: ignore
1354
+ elif isinstance(object, (ECLayout, ECGroup, ECPanel)):
1355
+ self.getInnerObject(object).setLayout(layout) # type: ignore
1234
1356
  elif what == 'spacing':
1235
- layout = self.getWidget(self.getVariable(command['name']))
1236
- layout.setSpacing(self.getRuntimeValue(command['value'])) # type: ignore
1357
+ layout = self.getInnerObject(self.getVariable(command['name']))
1358
+ layout.setSpacing(self.textify(command['value'])) # type: ignore
1237
1359
  elif what == 'text':
1238
1360
  record = self.getVariable(command['name'])
1239
- widget = self.getWidget(record)
1240
- text = self.getRuntimeValue(command['value'])
1361
+ widget = self.getInnerObject(record)
1362
+ text = self.textify(command['value'])
1241
1363
  keyword = record['keyword']
1242
1364
  setText = getattr(widget, "setText", None)
1243
1365
  if callable(setText):
1244
1366
  widget.setText(text) # type: ignore
1245
- elif keyword == 'multiline':
1367
+ elif self.isObjectType(record, ECMultiline):
1246
1368
  widget.setPlainText(text) # type: ignore
1247
- if record['keyword'] == 'pushbutton':
1369
+ if self.isObjectType(record, ECPushButton):
1248
1370
  widget.setAccessibleName(text) # type: ignore
1249
1371
  elif what == 'state':
1250
1372
  record = self.getVariable(command['name'])
1251
- if record['keyword'] == 'checkbox':
1252
- state = self.getRuntimeValue(command['value'])
1253
- self.getWidget(record).setChecked(state) # type: ignore
1373
+ if self.isObjectType(record, ECCheckBox):
1374
+ state = self.textify(command['value'])
1375
+ self.getInnerObject(record).setChecked(state) # type: ignore
1254
1376
  elif what == 'alignment':
1255
1377
  widget = self.getVariable(command['name'])['widget']
1256
1378
  flags = command['value']
@@ -1266,23 +1388,23 @@ class Graphics(Handler):
1266
1388
  widget.setAlignment(alignment)
1267
1389
  elif what == 'style':
1268
1390
  record = self.getVariable(command['name'])
1269
- widget = self.getWidget(record)
1270
- styles = self.getRuntimeValue(command['value'])
1391
+ widget = self.getInnerObject(record)
1392
+ styles = self.textify(command['value'])
1271
1393
  widget.setStyleSheet(styles) # type: ignore
1272
1394
  elif what == 'color':
1273
1395
  record = self.getVariable(command['name'])
1274
- widget = self.getWidget(record)
1275
- color = self.getRuntimeValue(command['value'])
1396
+ widget = self.getInnerObject(record)
1397
+ color = self.textify(command['value'])
1276
1398
  widget.setStyleSheet(f"color: {color};") # type: ignore
1277
1399
  elif what == 'background-color':
1278
1400
  record = self.getVariable(command['name'])
1279
- widget = self.getWidget(record)
1280
- bg_color = self.getRuntimeValue(command['value'])
1401
+ widget = self.getInnerObject(record)
1402
+ bg_color = self.textify(command['value'])
1281
1403
  widget.setStyleSheet(f"background-color: {bg_color};") # type: ignore
1282
1404
  elif what == 'listbox':
1283
1405
  record = self.getVariable(command['name'])
1284
- widget = self.getWidget(record)
1285
- value = self.getRuntimeValue(command['value'])
1406
+ widget = self.getInnerObject(record)
1407
+ value = self.textify(command['value'])
1286
1408
  widget.clear() # type: ignore
1287
1409
  widget.addItems(value) # type: ignore
1288
1410
  return self.nextPC()
@@ -1294,20 +1416,20 @@ class Graphics(Handler):
1294
1416
  def k_show(self, command):
1295
1417
  if self.nextIsSymbol():
1296
1418
  record = self.getSymbolRecord()
1297
- keyword = record['keyword']
1298
- if keyword == 'window':
1299
- command['window'] = record['name']
1419
+ if self.isObjectType(record, ECCoreWidget):
1420
+ command['domain'] = record['domain']
1421
+ command['name'] = record['name']
1300
1422
  self.add(command)
1301
1423
  return True
1302
- elif keyword == 'dialog':
1303
- command['dialog'] = record['name']
1424
+ elif self.isObjectType(record, ECWindow):
1425
+ command['window'] = record['name']
1304
1426
  self.add(command)
1305
1427
  return True
1306
- elif self.isWidget(keyword):
1307
- command['name'] = record['name']
1428
+ elif self.isObjectType(record, ECDialog):
1429
+ command['dialog'] = record['name']
1308
1430
  self.add(command)
1309
1431
  return True
1310
- elif keyword == 'messagebox':
1432
+ elif self.isObjectType(record, ECMessageBox):
1311
1433
  command['messagebox'] = record['name']
1312
1434
  self.skip('giving')
1313
1435
  if self.nextIsSymbol():
@@ -1318,12 +1440,13 @@ class Graphics(Handler):
1318
1440
 
1319
1441
  def r_show(self, command):
1320
1442
  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']
1443
+ record = self.getVariable(command['messagebox'])
1444
+ windowRecord = self.getVariable(record['window'])
1445
+ window = self.getInnerObject(windowRecord)
1446
+ style = record['style']
1447
+ title = record['title']
1448
+ message = record['message']
1449
+ target = self.getVariable(command['result'])
1327
1450
  if style == 'question':
1328
1451
  choice = QMessageBox.question(window, title, message)
1329
1452
  result = 'Yes' if choice == QMessageBox.StandardButton.Yes else 'No'
@@ -1345,53 +1468,37 @@ class Graphics(Handler):
1345
1468
  if choice == QMessageBox.StandardButton.Ok: result = 'OK'
1346
1469
  else: result = ''
1347
1470
  else: result = 'Cancel'
1348
- v = {}
1349
- v['type'] = 'text'
1350
- v['content'] = result
1351
- self.putSymbolValue(symbolRecord, v)
1471
+ v = ECValue(domain='graphics', type='str', content=result)
1472
+ self.putSymbolValue(target, v)
1352
1473
  elif 'window' in command:
1353
- window = self.getVariable(command['window'])['window']
1354
- window.show()
1474
+ window = self.getInnerObject(self.getVariable(command['window'])['object'])
1475
+ window.show() # type: ignore
1355
1476
  elif 'dialog' in command:
1356
1477
  record = self.getVariable(command['dialog'])
1357
- dialog = record['dialog']
1478
+ object = self.getObject(record)
1479
+ dialog = self.getInnerObject(record)
1358
1480
  if dialog.dialogType == 'generic':
1359
- record['result'] = dialog.exec()
1481
+ object.result = dialog.exec()
1360
1482
  elif dialog.dialogType == 'confirm':
1361
- record['result'] = True if dialog.exec() == QDialog.DialogCode.Accepted else False
1483
+ object.result = True if dialog.exec() == QDialog.DialogCode.Accepted else False
1484
+ pass
1362
1485
  elif dialog.dialogType == 'lineedit':
1363
1486
  if dialog.exec() == QDialog.DialogCode.Accepted:
1364
- record['result'] = dialog.lineEdit.text() # type: ignore
1365
- else: record['result'] = dialog.value # type: ignore
1487
+ object.result = dialog.lineEdit.text() # type: ignore
1488
+ else: object.result = dialog.value # type: ignore
1366
1489
  elif dialog.dialogType == 'multiline':
1367
1490
  if dialog.exec() == QDialog.DialogCode.Accepted:
1368
- record['result'] = dialog.textEdit.toPlainText() # type: ignore
1369
- else: record['result'] = dialog.value # type: ignore
1491
+ object.result = dialog.textEdit.toPlainText() # type: ignore
1492
+ else: object.result = dialog.value # type: ignore
1370
1493
  elif 'name' in command:
1371
1494
  record = self.getVariable(command['name'])
1372
- if 'widget' in record: self.getWidget(record).show() # type: ignore
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
-
1385
- # Declare a widget variable
1386
- def k_widget(self, command):
1387
- return self.compileVariable(command, 'gui')
1388
-
1389
- def r_widget(self, command):
1495
+ self.getInnerObject(record).show() # type: ignore
1390
1496
  return self.nextPC()
1391
1497
 
1392
1498
  # Declare a window variable
1393
1499
  def k_window(self, command):
1394
- return self.compileVariable(command)
1500
+ self.compiler.addValueType()
1501
+ return self.compileVariable(command, 'ECWindow')
1395
1502
 
1396
1503
  def r_window(self, command):
1397
1504
  return self.nextPC()
@@ -1399,42 +1506,48 @@ class Graphics(Handler):
1399
1506
  #############################################################################
1400
1507
  # Compile a value in this domain
1401
1508
  def compileValue(self):
1402
- value = {}
1403
- value['domain'] = self.getName()
1509
+ value = ECValue(domain=self.getName())
1404
1510
  token = self.getToken()
1405
1511
  if self.isSymbol():
1512
+ value.setContent(token)
1406
1513
  record = self.getSymbolRecord()
1407
- if record['extra'] == 'gui':
1408
- if self.isWidget(record['keyword']):
1409
- value['name'] = token
1410
- value['type'] = 'symbol'
1411
- return value
1412
-
1514
+ object = self.getObject(record)
1515
+ if isinstance(object, ECCoreWidget) and object.hasRuntimeValue():
1516
+ value.setType('object')
1517
+ return value
1518
+ else: return None
1413
1519
  else:
1414
1520
  if self.tokenIs('the'): token = self.nextToken()
1415
- if token == 'count':
1521
+ value.setType(token)
1522
+ if token in ['count', 'current', 'selected']:
1523
+ value.setType(token)
1524
+ if token == 'count':
1525
+ self.skip('of')
1526
+ elif token in ['current', 'selected']:
1527
+ token = self.nextToken()
1528
+ if token == 'item': self.skip('in')
1529
+ elif token == 'index': self.skip('of')
1530
+ if self.nextIsSymbol():
1531
+ record = self.getSymbolRecord()
1532
+ if self.isObjectType(record, ECListBox) or self.isObjectType(record, ECComboBox): # type: ignore
1533
+ value.setContent(ECValue(domain=self.getName(), type='object', content=record['name']))
1534
+ return value
1535
+ elif token == 'count':
1416
1536
  self.skip('of')
1417
1537
  if self.nextIsSymbol():
1418
- value['type'] = 'symbol'
1419
1538
  record = self.getSymbolRecord()
1420
- keyword = record['keyword']
1421
- if keyword in ['combobox', 'listbox']:
1422
- value['type'] = 'count'
1423
- value['name'] = record['name']
1539
+ if self.isObjectType(record, ECListBox) or self.isObjectType(record, ECComboBox): # type: ignore
1540
+ value.setContent(ECValue(domain=self.getName(), type='object', content=record['name']))
1424
1541
  return value
1425
-
1426
- elif token == 'current':
1427
- self.skip('item')
1428
- self.skip('in')
1542
+ elif token == 'text':
1543
+ self.skip('of')
1429
1544
  if self.nextIsSymbol():
1430
- value['type'] = 'symbol'
1431
1545
  record = self.getSymbolRecord()
1432
- keyword = record['keyword']
1433
- if keyword == 'listbox':
1434
- value['type'] = 'current'
1435
- value['name'] = record['name']
1546
+ if (
1547
+ self.isObjectType(record, (ECLabel, ECPushButton, ECMultiline, ECLineInput))
1548
+ ): # type: ignore
1549
+ value.setContent(ECValue(domain=self.getName(), type='object', content=record['name']))
1436
1550
  return value
1437
-
1438
1551
  return None
1439
1552
 
1440
1553
  #############################################################################
@@ -1446,80 +1559,102 @@ class Graphics(Handler):
1446
1559
  # Value handlers
1447
1560
 
1448
1561
  # This is used by the expression evaluator to get the value of a symbol
1449
- def v_symbol(self, symbolRecord):
1450
- symbolRecord = self.getVariable(symbolRecord['name'])
1451
- keyword = symbolRecord['keyword']
1452
- if keyword == 'pushbutton':
1453
- pushbutton = self.getWidget(symbolRecord)
1454
- v = {}
1455
- v['type'] = 'text'
1456
- v['content'] = pushbutton.accessibleName() # type: ignore
1562
+ def v_symbol(self, record):
1563
+ record = self.getVariable(record['name'])
1564
+ keyword = record['keyword']
1565
+ if self.isObjectType(record, ECPushButton):
1566
+ pushbutton = self.getInnerObject(record)
1567
+ v = ECValue(domain=self.getName(), type='str', content=pushbutton.accessibleName())
1457
1568
  return v
1458
- elif keyword == 'lineinput':
1459
- lineinput = self.getWidget(symbolRecord)
1460
- v = {}
1461
- v['type'] = 'text'
1462
- v['content'] = lineinput.displayText() # type: ignore
1569
+ elif self.isObjectType(record, ECLineInput):
1570
+ lineinput = self.getInnerObject(record)
1571
+ v = ECValue(domain=self.getName(), type='str', content=lineinput.displayText())
1463
1572
  return v
1464
- elif keyword == 'multiline':
1465
- multiline = self.getWidget(symbolRecord)
1466
- v = {}
1467
- v['type'] = 'text'
1468
- v['content'] = multiline.toPlainText() # type: ignore
1573
+ elif self.isObjectType(record, ECMultiline):
1574
+ multiline = self.getInnerObject(record)
1575
+ v = ECValue(domain=self.getName(), type='str', content=multiline.toPlainText())
1469
1576
  return v
1470
- elif keyword == 'combobox':
1471
- combobox = self.getWidget(symbolRecord)
1472
- v = {}
1473
- v['type'] = 'text'
1474
- v['content'] = combobox.currentText() # type: ignore
1577
+ elif self.isObjectType(record, ECComboBox):
1578
+ combobox = self.getInnerObject(record)
1579
+ v = ECValue(domain=self.getName(), type='str', content=combobox.currentText())
1475
1580
  return v
1476
- elif keyword == 'listbox':
1477
- listbox = self.getWidget(symbolRecord)
1581
+ elif self.isObjectType(record, ECListBox):
1582
+ listbox = self.getInnerObject(record)
1478
1583
  content = listbox.currentItem().text() # type: ignore
1479
- v = {}
1480
- v['type'] = 'text'
1481
- v['content'] = content
1584
+ v = ECValue(domain=self.getName(), type='str', content=content)
1482
1585
  return v
1483
- elif keyword == 'checkbox':
1484
- checkbox =self.getWidget(symbolRecord)
1586
+ elif self.isObjectType(record, ECCheckBox):
1587
+ checkbox =self.getInnerObject(record)
1485
1588
  content = checkbox.isChecked() # type: ignore
1486
- v = {}
1487
- v['type'] = 'boolean'
1488
- v['content'] = content
1589
+ v = ECValue(domain=self.getName(), type='boolean', content=content)
1489
1590
  return v
1490
- elif keyword == 'dialog':
1491
- content = symbolRecord['result']
1492
- v = {}
1493
- v['type'] = 'text'
1494
- v['content'] = content
1591
+ elif self.isObjectType(record, ECDialog):
1592
+ content = record['result']
1593
+ v = ECValue(domain=self.getName(), type='str', content=content)
1495
1594
  return v
1496
1595
  return None
1497
1596
 
1498
1597
  def v_count(self, v):
1499
- record = self.getVariable(v['name'])
1500
- keyword = record['keyword']
1501
- widget = self.getWidget(record)
1502
- if keyword in ['combobox', 'listbox']: content = widget.count() # type: ignore
1503
- value = {}
1504
- value['type'] = 'int'
1505
- value['content'] = content
1506
- return value
1598
+ content = v.getContent()
1599
+ if isinstance(content, ECValue) and content.getType() == 'object':
1600
+ record = self.getVariable(content.getContent())
1601
+ object = self.getObject(record)
1602
+ if isinstance(object, (ECListBox, ECComboBox)):
1603
+ widget = self.getInnerObject(object)
1604
+ value = widget.count() # type: ignore
1605
+ return ECValue(domain=self.getName(), type='int', content=value) # type: ignore
1606
+ else: raise RuntimeError(self.program, f"Object is not a listbox or combobox")
1507
1607
 
1508
1608
  def v_current(self, v):
1509
- record = self.getVariable(v['name'])
1510
- keyword = record['keyword']
1511
- widget = self.getWidget(record)
1512
- if keyword == 'listbox': content = widget.currentItem().text() # type: ignore
1513
- value = {}
1514
- value['type'] = 'text'
1515
- value['content'] = content
1516
- return value
1609
+ content = v.getContent()
1610
+ if isinstance(content, ECValue) and content.getType() == 'object':
1611
+ record = self.getVariable(content.getContent())
1612
+ keyword = record['keyword']
1613
+ object = self.getObject(record)
1614
+ widget = self.getInnerObject(object)
1615
+ if isinstance(widget, (QListWidget)):
1616
+ content = widget.currentItem().text() # type: ignore
1617
+ return ECValue(domain=self.getName(), type='int', content=content)
1618
+ elif isinstance(widget, (QComboBox)):
1619
+ content = str(widget.currentText()) # type: ignore
1620
+ return ECValue(domain=self.getName(), type='int', content=content)
1621
+ else: raise RuntimeError(self.program, f"Object is not a listbox or combobox")
1622
+
1623
+ def v_element(self, v):
1624
+ return v.getContent()
1625
+
1626
+ def v_empty(self, v):
1627
+ if v.type == 'object':
1628
+ record = self.getVariable(v.getContent())
1629
+ object = self.getObject(record)
1630
+ value = object.isEmpty()
1631
+ return ECValue(domain=self.getName(), type='boolean', content=value) # type: ignore
1632
+ return None
1633
+
1634
+ def v_selected(self, v): return self.v_current(v)
1635
+
1636
+ def v_text(self, v):
1637
+ content = v.getContent()
1638
+ if isinstance(content, ECValue) and content.getType() == 'object':
1639
+ record = self.getVariable(content.getContent())
1640
+ object = self.getObject(record)
1641
+ value = object.getText()
1642
+ return ECValue(domain=self.getName(), type='int', content=value) # type: ignore
1643
+
1644
+ #############################################################################
1645
+ # Get the value of an unknown item (domain-specific)
1646
+ def getUnknownValue(self, value):
1647
+ if self.isObjectType(value, (ECLabelWidget, ECPushButtonWidget, ECLineEditWidget, ECListBoxWidget, ECComboBoxWidget)):
1648
+ return value.text() # type: ignore
1649
+ if self.isObjectType(value, (ECDialogWindow,)):
1650
+ return value.result() # type: ignore
1651
+ return None # Unable to get value
1517
1652
 
1518
1653
  #############################################################################
1519
1654
  # Compile a condition
1520
1655
  def compileCondition(self):
1521
- condition = Object()
1522
- condition.negate = False
1656
+ condition = ECValue()
1657
+ condition.negate = False # type: ignore
1523
1658
  return None
1524
1659
 
1525
1660
  #############################################################################