easycoder 251004.1__py2.py3-none-any.whl → 251104.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.
easycoder/__init__.py CHANGED
@@ -12,4 +12,4 @@ from .ec_pyside import *
12
12
  from .ec_timestamp import *
13
13
  from .ec_value import *
14
14
 
15
- __version__ = "251004.1"
15
+ __version__ = "251104.1"
easycoder/ec_classes.py CHANGED
@@ -16,7 +16,6 @@ class AssertionError:
16
16
  def __init__(self, program, msg=None):
17
17
  code = program.code[program.pc]
18
18
  lino = code['lino']
19
- script = program.script.lines[lino].strip()
20
19
  message = f'Assertion Error in {program.name} at line {lino + 1}'
21
20
  if msg != None:
22
21
  message += f': {msg}'
@@ -58,8 +57,5 @@ class Token:
58
57
  self.lino = lino
59
58
  self.token = token
60
59
 
61
- class Condition():
62
- negate = False
63
-
64
60
  class Object():
65
61
  pass
easycoder/ec_compiler.py CHANGED
@@ -1,4 +1,4 @@
1
- from .ec_classes import Token, FatalError
1
+ from .ec_classes import FatalError
2
2
  from .ec_value import Value
3
3
  from .ec_condition import Condition
4
4
 
@@ -18,9 +18,11 @@ class Compiler:
18
18
  self.debugCompile = False
19
19
  self.valueTypes = {}
20
20
 
21
- def getPC(self):
21
+ # Get the current code size. Used during compilation
22
+ def getCodeSize(self):
22
23
  return len(self.program.code)
23
24
 
25
+ # Get the current index (the program counter)
24
26
  def getIndex(self):
25
27
  return self.index
26
28
 
@@ -39,6 +41,7 @@ class Compiler:
39
41
  self.index += 1
40
42
  return self.getToken()
41
43
 
44
+ # Peek ahead to see the next token without advancing the index
42
45
  def peek(self):
43
46
  try:
44
47
  return self.tokens[self.index + 1].token
@@ -68,19 +71,23 @@ class Compiler:
68
71
  self.index += 1
69
72
  return self.condition.compileCondition()
70
73
 
74
+ # Test if the current token has a specified value
71
75
  def tokenIs(self, value):
72
76
  return self.getToken() == value
73
77
 
78
+ # Test if the next token has the specified value
74
79
  def nextIs(self, value):
75
80
  return self.nextToken() == value
76
81
 
82
+ # Get the command at a given pc in the code list
77
83
  def getCommandAt(self, pc):
78
84
  return self.program.code[pc]
79
85
 
80
86
  # Add a command to the code list
81
- def add(self, command):
87
+ def addCommand(self, command):
82
88
  self.code.append(command)
83
89
 
90
+ # Test if the current token is a symbol
84
91
  def isSymbol(self):
85
92
  token = self.getToken()
86
93
  try:
@@ -89,10 +96,12 @@ class Compiler:
89
96
  return False
90
97
  return True
91
98
 
99
+ # Test if the next token is a symbol
92
100
  def nextIsSymbol(self):
93
101
  self.next()
94
102
  return self.isSymbol()
95
103
 
104
+ # Skip the next token if it matches the value given
96
105
  def skip(self, token):
97
106
  next = self.peek()
98
107
  if type(token) == list:
@@ -102,21 +111,26 @@ class Compiler:
102
111
  return
103
112
  elif next == token: self.nextToken()
104
113
 
114
+ # Rewind to a given position in the code list
105
115
  def rewindTo(self, index):
106
116
  self.index = index
107
117
 
118
+ # Get source line number containing the current token
108
119
  def getLino(self):
109
120
  if self.index >= len(self.tokens):
110
121
  return 0
111
122
  return self.tokens[self.index].lino
112
123
 
124
+ # Issue a warning
113
125
  def warning(self, message):
114
126
  self.warnings.append(f'Warning at line {self.getLino() + 1} of {self.program.name}: {message}')
115
127
 
128
+ # Print all warnings
116
129
  def showWarnings(self):
117
130
  for warning in self.warnings:
118
131
  print(warning)
119
132
 
133
+ # Get the symbol record for the current token (assumes it is a symbol name)
120
134
  def getSymbolRecord(self):
121
135
  token = self.getToken()
122
136
  if not token in self.symbols:
@@ -128,18 +142,23 @@ class Compiler:
128
142
  symbolRecord['used'] = True
129
143
  return symbolRecord
130
144
 
145
+ # Add a value type
131
146
  def addValueType(self):
132
147
  self.valueTypes[self.getToken()] = True
133
148
 
149
+ # Test if a given value is in the value types list
134
150
  def hasValue(self, type):
135
151
  return type in self.valueTypes
136
152
 
153
+ # Compile a program label (a symbol ending with ':')
137
154
  def compileLabel(self, command):
138
155
  return self.compileSymbol(command, self.getToken())
139
156
 
157
+ # Compile a variable
140
158
  def compileVariable(self, command, extra=None):
141
159
  return self.compileSymbol(command, self.nextToken(), extra)
142
160
 
161
+ # Compile a symbol
143
162
  def compileSymbol(self, command, name, extra=None):
144
163
  try:
145
164
  v = self.symbols[name]
@@ -148,7 +167,7 @@ class Compiler:
148
167
  if v:
149
168
  FatalError(self, f'Duplicate symbol name "{name}"')
150
169
  return False
151
- self.symbols[name] = self.getPC()
170
+ self.symbols[name] = self.getCodeSize()
152
171
  command['program'] = self.program
153
172
  command['type'] = 'symbol'
154
173
  command['name'] = name
@@ -161,7 +180,7 @@ class Compiler:
161
180
  command['locked'] = False
162
181
  command['extra'] = extra
163
182
  if 'keyword' in command: command['hasValue'] = self.hasValue(command['keyword'])
164
- self.add(command)
183
+ self.addCommand(command)
165
184
  return True
166
185
 
167
186
  # Compile the current token
@@ -171,6 +190,10 @@ class Compiler:
171
190
  # print(f'Compile {token}')
172
191
  if not token:
173
192
  return False
193
+ if len(self.code) == 0:
194
+ if self.program.parent == None and hasattr(self.program, 'usingGraphics'):
195
+ cmd = {'domain': 'graphics', 'keyword': 'init', 'debug': False}
196
+ self.code.append(cmd)
174
197
  mark = self.getIndex()
175
198
  for domain in self.program.getDomains():
176
199
  handler = domain.keywordHandler(token)
@@ -195,7 +218,7 @@ class Compiler:
195
218
  keyword = self.getToken()
196
219
  if not keyword:
197
220
  return False
198
- # print(f'Compile keyword "{keyword}"')
221
+ # print(f'Compile keyword "{keyword}"')
199
222
  if keyword.endswith(':'):
200
223
  command = {}
201
224
  command['domain'] = None
@@ -209,7 +232,7 @@ class Compiler:
209
232
  self.index = index
210
233
  while True:
211
234
  token = self.tokens[self.index]
212
- keyword = token.token
235
+ # keyword = token.token
213
236
  if self.debugCompile: print(self.script.lines[token.lino])
214
237
  # if keyword != 'else':
215
238
  if self.compileOne() == True:
@@ -221,5 +244,10 @@ class Compiler:
221
244
  else:
222
245
  return False
223
246
 
247
+ # Compile fom the current location, stopping on any of a list of tokens
224
248
  def compileFromHere(self, stopOn):
225
249
  return self.compileFrom(self.getIndex(), stopOn)
250
+
251
+ # Compile from the start of the script
252
+ def compileFromStart(self):
253
+ return self.compileFrom(0, [])
easycoder/ec_condition.py CHANGED
@@ -19,7 +19,7 @@ class Condition:
19
19
  condition.domain= domain.getName()
20
20
  return condition
21
21
  self.rewindTo(mark)
22
- return None
22
+ return None
23
23
 
24
24
  def testCondition(self, condition):
25
25
  handler = self.program.domainIndex[condition.domain]
easycoder/ec_core.py CHANGED
@@ -3,7 +3,7 @@ import numbers, base64, binascii, random, requests, paramiko
3
3
  from copy import deepcopy
4
4
  from psutil import Process
5
5
  from datetime import datetime
6
- from .ec_classes import FatalError, RuntimeWarning, RuntimeError, AssertionError, NoValueError, NoValueRuntimeError, Condition, Object
6
+ from .ec_classes import FatalError, RuntimeWarning, RuntimeError, AssertionError, NoValueError, NoValueRuntimeError, Object
7
7
  from .ec_handler import Handler
8
8
  from .ec_timestamp import getTimestamp
9
9
 
@@ -31,13 +31,13 @@ class Core(Handler):
31
31
  cmd['keyword'] = 'gotoPC'
32
32
  cmd['goto'] = 0
33
33
  cmd['debug'] = False
34
- skip = self.getPC()
34
+ skip = self.getCodeSize()
35
35
  self.add(cmd)
36
36
  # Process the 'or'
37
- self.getCommandAt(orHere)['or'] = self.getPC()
37
+ self.getCommandAt(orHere)['or'] = self.getCodeSize()
38
38
  self.compileOne()
39
39
  # Fixup the skip
40
- self.getCommandAt(skip)['goto'] = self.getPC()
40
+ self.getCommandAt(skip)['goto'] = self.getCodeSize()
41
41
 
42
42
  #############################################################################
43
43
  # Keyword handlers
@@ -323,7 +323,8 @@ class Core(Handler):
323
323
  symbolRecord = self.getVariable(command['var'])
324
324
  value = self.getSymbolValue(symbolRecord)
325
325
  content = value['content']
326
- content.remove(key)
326
+ if key >= 0 and key < len(content): del(content[key])
327
+ else: RuntimeError(self.program, f'Index {key} out of range')
327
328
  value['content'] = content
328
329
  self.putSymbolValue(symbolRecord, value)
329
330
  return self.nextPC()
@@ -467,7 +468,7 @@ class Core(Handler):
467
468
  if url != None:
468
469
  command['url'] = url
469
470
  command['or'] = None
470
- get = self.getPC()
471
+ get = self.getCodeSize()
471
472
  if self.peek() == 'timeout':
472
473
  self.nextToken()
473
474
  command['timeout'] = self.nextValue()
@@ -555,7 +556,7 @@ class Core(Handler):
555
556
  command['condition'] = self.nextCondition()
556
557
  self.add(command)
557
558
  self.nextToken()
558
- pcElse = self.getPC()
559
+ pcElse = self.getCodeSize()
559
560
  cmd = {}
560
561
  cmd['lino'] = command['lino']
561
562
  cmd['domain'] = 'core'
@@ -568,7 +569,7 @@ class Core(Handler):
568
569
  if self.peek() == 'else':
569
570
  self.nextToken()
570
571
  # Add a 'goto' to skip the 'else'
571
- pcNext = self.getPC()
572
+ pcNext = self.getCodeSize()
572
573
  cmd = {}
573
574
  cmd['lino'] = command['lino']
574
575
  cmd['domain'] = 'core'
@@ -577,15 +578,15 @@ class Core(Handler):
577
578
  cmd['debug'] = False
578
579
  self.add(cmd)
579
580
  # Fixup the link to the 'else' branch
580
- self.getCommandAt(pcElse)['goto'] = self.getPC()
581
+ self.getCommandAt(pcElse)['goto'] = self.getCodeSize()
581
582
  # Process the 'else' branch
582
583
  self.nextToken()
583
584
  self.compileOne()
584
585
  # Fixup the pcNext 'goto'
585
- self.getCommandAt(pcNext)['goto'] = self.getPC()
586
+ self.getCommandAt(pcNext)['goto'] = self.getCodeSize()
586
587
  else:
587
588
  # We're already at the next command
588
- self.getCommandAt(pcElse)['goto'] = self.getPC()
589
+ self.getCommandAt(pcElse)['goto'] = self.getCodeSize()
589
590
  return True
590
591
 
591
592
  def r_if(self, command):
@@ -604,7 +605,7 @@ class Core(Handler):
604
605
  name = self.nextToken()
605
606
  item = [keyword, name]
606
607
  imports.append(item)
607
- self.symbols[name] = self.getPC()
608
+ self.symbols[name] = self.getCodeSize()
608
609
  variable = {}
609
610
  variable['domain'] = None
610
611
  variable['name'] = name
@@ -746,7 +747,7 @@ class Core(Handler):
746
747
  else:
747
748
  command['file'] = self.getValue()
748
749
  command['or'] = None
749
- load = self.getPC()
750
+ load = self.getCodeSize()
750
751
  self.processOr(command, load)
751
752
  return True
752
753
  else:
@@ -915,7 +916,7 @@ class Core(Handler):
915
916
  cmd['debug'] = False
916
917
  self.add(cmd)
917
918
  # Fixup the link
918
- command['goto'] = self.getPC()
919
+ command['goto'] = self.getCodeSize()
919
920
  return True
920
921
  return False
921
922
 
@@ -1006,7 +1007,7 @@ class Core(Handler):
1006
1007
  else:
1007
1008
  command['result'] = None
1008
1009
  command['or'] = None
1009
- post = self.getPC()
1010
+ post = self.getCodeSize()
1010
1011
  self.processOr(command, post)
1011
1012
  return True
1012
1013
 
@@ -1105,7 +1106,7 @@ class Core(Handler):
1105
1106
  FatalError(self.compiler, f'Symbol {symbolRecord["name"]} is not a value holder')
1106
1107
  else:
1107
1108
  command['or'] = None
1108
- self.processOr(command, self.getPC())
1109
+ self.processOr(command, self.getCodeSize())
1109
1110
  return True
1110
1111
  else:
1111
1112
  FatalError(self.compiler, f'Symbol {self.getToken()} is not a variable')
@@ -1273,7 +1274,7 @@ class Core(Handler):
1273
1274
  else:
1274
1275
  command['file'] = self.getValue()
1275
1276
  command['or'] = None
1276
- save = self.getPC()
1277
+ save = self.getCodeSize()
1277
1278
  self.processOr(command, save)
1278
1279
  return True
1279
1280
 
@@ -1768,12 +1769,17 @@ class Core(Handler):
1768
1769
  self.program.importPlugin(f'{source}:{clazz}')
1769
1770
  return True
1770
1771
  return False
1771
- elif self.nextIs('graphics'):
1772
- print('Loading graphics module')
1773
- from .ec_pyside import Graphics
1774
- self.program.graphics = Graphics
1775
- self.program.useClass(Graphics)
1776
- return True
1772
+ else:
1773
+ token = self.nextToken()
1774
+ if token in ['graphics', 'debugger']:
1775
+ if not hasattr(self.program, 'usingGraphics'):
1776
+ print('Loading graphics module')
1777
+ from .ec_pyside import Graphics
1778
+ self.program.graphics = Graphics
1779
+ self.program.useClass(Graphics)
1780
+ self.program.usingGraphics = True
1781
+ if token == 'debugger': self.program.debugging = True
1782
+ return True
1777
1783
  return False
1778
1784
 
1779
1785
  # Declare a general-purpose variable
@@ -1817,10 +1823,10 @@ class Core(Handler):
1817
1823
  return None
1818
1824
  # token = self.getToken()
1819
1825
  command['condition'] = code
1820
- test = self.getPC()
1826
+ test = self.getCodeSize()
1821
1827
  self.add(command)
1822
1828
  # Set up a goto for when the test fails
1823
- fail = self.getPC()
1829
+ fail = self.getCodeSize()
1824
1830
  cmd = {}
1825
1831
  cmd['lino'] = command['lino']
1826
1832
  cmd['domain'] = 'core'
@@ -1841,7 +1847,7 @@ class Core(Handler):
1841
1847
  cmd['debug'] = False
1842
1848
  self.add(cmd)
1843
1849
  # Fixup the 'goto' on completion
1844
- self.getCommandAt(fail)['goto'] = self.getPC()
1850
+ self.getCommandAt(fail)['goto'] = self.getCodeSize()
1845
1851
  return True
1846
1852
 
1847
1853
  def r_while(self, command):
@@ -2631,7 +2637,8 @@ class Core(Handler):
2631
2637
  #############################################################################
2632
2638
  # Compile a condition
2633
2639
  def compileCondition(self):
2634
- condition = Condition()
2640
+ condition = Object()
2641
+ condition.negate = False
2635
2642
 
2636
2643
  token = self.getToken()
2637
2644
 
@@ -2655,7 +2662,14 @@ class Core(Handler):
2655
2662
  path = self.nextValue()
2656
2663
  condition.path = path
2657
2664
  condition.type = 'exists'
2658
- token = self.nextToken()
2665
+ self.skip('on')
2666
+ if self.nextIsSymbol():
2667
+ record = self.getSymbolRecord()
2668
+ if record['keyword'] == 'ssh':
2669
+ condition.type = 'sshExists'
2670
+ condition.target = record['name']
2671
+ token = self.nextToken()
2672
+ else: token = self.getToken()
2659
2673
  if token == 'exists':
2660
2674
  return condition
2661
2675
  elif token == 'does':
@@ -2839,6 +2853,17 @@ class Core(Handler):
2839
2853
  test = errormsg != None
2840
2854
  return not test if condition.negate else test
2841
2855
 
2856
+ def c_sshExists(self, condition):
2857
+ path = self.getRuntimeValue(condition.path)
2858
+ ssh = self.getVariable(condition.target)
2859
+ sftp = ssh['sftp']
2860
+ try:
2861
+ with sftp.open(path, 'r') as remote_file: remote_file.read().decode()
2862
+ comparison = True
2863
+ except:
2864
+ comparison = False
2865
+ return not comparison if condition.negate else comparison
2866
+
2842
2867
  def c_starts(self, condition):
2843
2868
  value1 = self.getRuntimeValue(condition.value1)
2844
2869
  value2 = self.getRuntimeValue(condition.value2)
easycoder/ec_handler.py CHANGED
@@ -22,8 +22,8 @@ class Handler:
22
22
  self.compileVariable = compiler.compileVariable
23
23
  self.rewindTo = compiler.rewindTo
24
24
  self.warning = compiler.warning
25
- self.getPC = compiler.getPC
26
- self.add = compiler.add
25
+ self.getCodeSize = compiler.getCodeSize
26
+ self.add = compiler.addCommand
27
27
  self.getCommandAt = compiler.getCommandAt
28
28
  self.compileOne = compiler.compileOne
29
29
  self.compileFromHere = compiler.compileFromHere
easycoder/ec_keyboard.py CHANGED
@@ -158,6 +158,8 @@ class KeyboardView(QVBoxLayout):
158
158
  for row in rows:
159
159
  self.addLayout(row)
160
160
 
161
+ ###############################################################################
162
+ # VirtualKeyboard Class
161
163
  class VirtualKeyboard(QStackedWidget):
162
164
  def __init__(self, keyboardType, buttonHeight, receiver, onFinished):
163
165
  super().__init__()
@@ -173,6 +175,8 @@ class VirtualKeyboard(QStackedWidget):
173
175
  self.addKeyboardLayout2()
174
176
  self.addKeyboardLayout3()
175
177
 
178
+ ###########################################################################
179
+ # Add the first keyboard layout (lowercase letters)
176
180
  def addKeyboardLayout0(self):
177
181
  rowList = []
178
182
 
@@ -214,7 +218,7 @@ class VirtualKeyboard(QStackedWidget):
214
218
  KeyboardButton(self.buttonHeight * 1.5, self.buttonHeight, self.onClickNumbers, None, 'img/numbers.png'),
215
219
  QSpacerItem(self.buttonHeight * 0.05, 0, QSizePolicy.Fixed, QSizePolicy.Minimum),
216
220
  KeyboardButton(self.buttonHeight, self.buttonHeight, self.onClickChar, ","),
217
- KeyboardButton(self.buttonHeight * 5, self.buttonHeight, self.onClickSpace, None, 'skeyboard/pace.png'),
221
+ KeyboardButton(self.buttonHeight * 5, self.buttonHeight, self.onClickSpace, None, 'keyboard/space.png'),
218
222
  KeyboardButton(self.buttonHeight, self.buttonHeight, self.onClickChar, "."),
219
223
  QSpacerItem(self.buttonHeight * 0.05, 0, QSizePolicy.Fixed, QSizePolicy.Minimum),
220
224
  KeyboardButton(self.buttonHeight * 1.5, self.buttonHeight, self.onClickEnter, None, 'img/enter.png'),
@@ -228,6 +232,8 @@ class VirtualKeyboard(QStackedWidget):
228
232
  container.setLayout(keyboardView)
229
233
  self.addWidget(container)
230
234
 
235
+ ###########################################################################
236
+ # Add the second keyboard layout (uppercase letters)
231
237
  def addKeyboardLayout1(self):
232
238
  rowList = []
233
239
 
@@ -283,6 +289,8 @@ class VirtualKeyboard(QStackedWidget):
283
289
  container.setLayout(keyboardView)
284
290
  self.addWidget(container)
285
291
 
292
+ ###########################################################################
293
+ # Add the third keyboard layout (numbers and symbols)
286
294
  def addKeyboardLayout2(self):
287
295
  rowList = []
288
296
 
@@ -320,11 +328,11 @@ class VirtualKeyboard(QStackedWidget):
320
328
  KeyboardButton(self.buttonHeight * 1.5, self.buttonHeight, self.onClickLetters, None, 'img/letters.png'),
321
329
  QSpacerItem(self.buttonHeight * 0.05, 0, QSizePolicy.Fixed, QSizePolicy.Minimum),
322
330
  KeyboardButton(self.buttonHeight, self.buttonHeight, self.onClickChar, ","),
323
- KeyboardButton(self.buttonHeight * 6, self.buttonHeight, self.onClickSpace, None, 'img/space.png'),
331
+ KeyboardButton(self.buttonHeight * 5.2, self.buttonHeight, self.onClickSpace, None, 'keyboard/space.png'),
324
332
  KeyboardButton(self.buttonHeight, self.buttonHeight, self.onClickChar, "."),
325
333
  QSpacerItem(self.buttonHeight * 0.05, 0, QSizePolicy.Fixed, QSizePolicy.Minimum),
326
334
  KeyboardButton(self.buttonHeight * 1.5, self.buttonHeight, self.onClickEnter, None, 'img/enter.png'),
327
- QSpacerItem(20, 40, QSizePolicy.Expanding, QSizePolicy.Minimum)
335
+ QSpacerItem(10, 40, QSizePolicy.Expanding, QSizePolicy.Minimum)
328
336
  ])
329
337
  rowList.append(row4)
330
338
 
@@ -334,6 +342,8 @@ class VirtualKeyboard(QStackedWidget):
334
342
  container.setLayout(keyboardView)
335
343
  self.addWidget(container)
336
344
 
345
+ ###########################################################################
346
+ # Add the fourth keyboard layout (additional symbols)
337
347
  def addKeyboardLayout3(self):
338
348
  rowList = []
339
349
 
easycoder/ec_program.py CHANGED
@@ -34,9 +34,9 @@ class Program:
34
34
  self.domainIndex = {}
35
35
  self.name = '<anon>'
36
36
  self.code = []
37
+ self.pc = 0
37
38
  self.symbols = {}
38
39
  self.onError = 0
39
- self.pc = 0
40
40
  self.debugStep = False
41
41
  self.stack = []
42
42
  self.script = Script(source)
@@ -48,7 +48,6 @@ class Program:
48
48
  self.externalControl = False
49
49
  self.ticker = 0
50
50
  self.running = True
51
- # self.start()
52
51
 
53
52
  # This is called at 10msec intervals by the GUI code
54
53
  def flushCB(self):
@@ -62,7 +61,7 @@ class Program:
62
61
  module['child'] = self
63
62
  startCompile = time.time()
64
63
  self.tokenise(self.script)
65
- if self.compiler.compileFrom(0, []):
64
+ if self.compiler.compileFromStart():
66
65
  finishCompile = time.time()
67
66
  s = len(self.script.lines)
68
67
  t = len(self.script.tokens)
easycoder/ec_pyside.py CHANGED
@@ -1,7 +1,7 @@
1
1
  import sys
2
2
  from functools import partial
3
3
  from .ec_handler import Handler
4
- from .ec_classes import RuntimeError
4
+ from .ec_classes import RuntimeError, Object
5
5
  from .ec_border import Border
6
6
  from PySide6.QtCore import Qt, QTimer, Signal, QRect
7
7
  from PySide6.QtGui import QPixmap, QPainter
@@ -26,6 +26,7 @@ from PySide6.QtWidgets import (
26
26
  QSlider,
27
27
  QSpinBox,
28
28
  QTimeEdit,
29
+ QLayout,
29
30
  QVBoxLayout,
30
31
  QHBoxLayout,
31
32
  QGridLayout,
@@ -67,13 +68,25 @@ class Graphics(Handler):
67
68
  'combobox',
68
69
  'widget'
69
70
  ]
71
+
72
+ def setWidget(self, record, widget):
73
+ if record['index'] >= record['elements']:
74
+ RuntimeError(self.program, f'Index out of range for widget {record["name"]}')
75
+ if not 'widget' in record:
76
+ record['widget'] = [None] * record['elements']
77
+ while len(record['widget']) < record['elements']:
78
+ record['widget'].append(None)
79
+ record['widget'][record['index']] = widget
80
+
81
+ def getWidget(self, record):
82
+ if 'widget' in record and record['widget'] != None:
83
+ if record['keyword'] in ['layout', 'group']: return record['widget']
84
+ return record['widget'][record['index']]
85
+ else:
86
+ return None
70
87
 
71
88
  def dialogTypes(self):
72
89
  return ['confirm', 'lineedit', 'multiline', 'generic']
73
-
74
- def getWidget(self, record):
75
- if record['keyword'] in ['pushbutton']: return self.getSymbolContent(record)
76
- else: return record['widget']
77
90
 
78
91
  class ClickableLineEdit(QLineEdit):
79
92
  clicked = Signal()
@@ -114,7 +127,7 @@ class Graphics(Handler):
114
127
  # (2) add {widget} to {layout}
115
128
  # (3) add stretch {widget} to {layout}
116
129
  # (4) add stretch to {layout}
117
- # (5) add spacer {size} to {layout}
130
+ # (5) add spacer [size] {size} to {layout}
118
131
  # (6) add {widget} at {col} {row} in {grid layout}
119
132
  def k_add(self, command):
120
133
  def addToLayout():
@@ -146,6 +159,7 @@ class Graphics(Handler):
146
159
 
147
160
  elif token == 'spacer':
148
161
  self.nextToken()
162
+ self.skip('size')
149
163
  command['widget'] = 'spacer'
150
164
  command['size'] = self.nextValue()
151
165
  self.skip('to')
@@ -186,19 +200,19 @@ class Graphics(Handler):
186
200
  def r_add(self, command):
187
201
  if 'value' in command:
188
202
  value = self.getRuntimeValue(command['value'])
189
- widget = self.getVariable(command['widget'])
190
- if widget['keyword'] == 'listbox':
191
- widget['widget'].addItem(value)
192
- elif widget['keyword'] == 'combobox':
193
- if isinstance(value, list): widget['widget'].addItems(value)
194
- else: widget['widget'].addItem(value)
203
+ record = self.getVariable(command['widget'])
204
+ if record['keyword'] == 'listbox':
205
+ self.getWidget(record).addItem(value)
206
+ elif record['keyword'] == 'combobox':
207
+ if isinstance(value, list): record['widget'].addItems(value)
208
+ else: self.getWidget(record).addItem(value)
195
209
  elif 'row' in command and 'col' in command:
196
210
  layout = self.getVariable(command['layout'])['widget']
197
- widgetVar = self.getVariable(command['widget'])
198
- widget = widgetVar['widget']
211
+ record = self.getVariable(command['widget'])
212
+ widget = self.getWidget(record)
199
213
  row = self.getRuntimeValue(command['row'])
200
214
  col = self.getRuntimeValue(command['col'])
201
- if widgetVar['keyword'] == 'layout':
215
+ if record['keyword'] == 'layout':
202
216
  layout.addLayout(widget, row, col)
203
217
  else:
204
218
  layout.addWidget(widget, row, col)
@@ -272,8 +286,41 @@ class Graphics(Handler):
272
286
  return False
273
287
 
274
288
  def r_clear(self, command):
275
- widget = self.getVariable(command['name'])['widget']
276
- widget.clear()
289
+
290
+ def clearLayout(layout: QLayout) -> None:
291
+ if layout is None:
292
+ return
293
+ while layout.count() > 0:
294
+ item = layout.takeAt(0)
295
+ if item is None:
296
+ continue
297
+ widget = item.widget()
298
+ if widget is not None:
299
+ # Delete the widget
300
+ widget.deleteLater()
301
+ elif item.layout() is not None:
302
+ # Recursively clear sub-layout
303
+ clearLayout(item.layout())
304
+ item.layout().deleteLater()
305
+ # The QLayoutItem will be automatically cleaned up by Qt
306
+
307
+ def clearWidget(widget: QWidget) -> None:
308
+ if widget is None:
309
+ return
310
+ # Clear the layout first
311
+ layout = widget.layout()
312
+ if layout is not None:
313
+ clearLayout(layout)
314
+ layout.deleteLater()
315
+ # Clear any remaining child widgets
316
+ child_widgets = widget.findChildren(QWidget, "", Qt.FindDirectChildrenOnly)
317
+ for child in child_widgets:
318
+ child.deleteLater()
319
+
320
+ widget = self.getWidget(self.getVariable(command['name']))
321
+ clearWidget(widget)
322
+ return self.nextPC()
323
+
277
324
  return self.nextPC()
278
325
 
279
326
  # close {window}
@@ -370,17 +417,18 @@ class Graphics(Handler):
370
417
  return True
371
418
 
372
419
  def k_createPushbutton(self, command):
373
- text = ''
374
420
  while True:
375
421
  token = self.peek()
376
422
  if token == 'text':
377
423
  self.nextToken()
378
- text = self.nextValue()
424
+ command['text'] = self.nextValue()
425
+ elif token == 'icon':
426
+ self.nextToken()
427
+ command['icon'] = self.nextValue()
379
428
  elif token == 'size':
380
429
  self.nextToken()
381
430
  command['size'] = self.nextValue()
382
431
  else: break
383
- command['text'] = text
384
432
  self.add(command)
385
433
  return True
386
434
 
@@ -562,19 +610,33 @@ class Graphics(Handler):
562
610
  elif alignment == 'justify': label.setAlignment(Qt.AlignJustify)
563
611
  if 'expand' in command:
564
612
  label.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Preferred)
565
- record['widget'] = label
613
+ self.setWidget(record, label)
566
614
  return self.nextPC()
567
615
 
568
616
  def r_createPushbutton(self, command, record):
569
- text = self.getRuntimeValue(command['text'])
570
- pushbutton = QPushButton(text)
571
- pushbutton.setAccessibleName(text)
572
617
  if 'size' in command:
573
- fm = pushbutton.fontMetrics()
574
- c = pushbutton.contentsMargins()
575
- w = fm.horizontalAdvance('m') * self.getRuntimeValue(command['size']) + c.left()+c.right()
576
- pushbutton.setMaximumWidth(w)
618
+ size = self.getRuntimeValue(command['size'])
619
+ else: size = None
620
+ if 'icon' in command:
621
+ iconPath = self.getRuntimeValue(command['icon'])
622
+ pixmap = QPixmap(iconPath)
623
+ if pixmap.isNull():
624
+ RuntimeError(self.program, f'Icon not found: {iconPath}')
625
+ icon = pixmap.scaledToHeight(size if size != None else 24, Qt.SmoothTransformation)
626
+ pushbutton = QPushButton()
627
+ pushbutton.setIcon(icon)
628
+ pushbutton.setIconSize(icon.size())
629
+ elif 'text' in command:
630
+ text = self.getRuntimeValue(command['text'])
631
+ pushbutton = QPushButton(text)
632
+ pushbutton.setAccessibleName(text)
633
+ if size != None:
634
+ fm = pushbutton.fontMetrics()
635
+ c = pushbutton.contentsMargins()
636
+ w = fm.horizontalAdvance('m') * self.getRuntimeValue(command['size']) + c.left()+c.right()
637
+ pushbutton.setMaximumWidth(w)
577
638
  self.putSymbolValue(record, pushbutton)
639
+ self.setWidget(record, pushbutton)
578
640
  return self.nextPC()
579
641
 
580
642
  def r_createCheckBox(self, command, record):
@@ -596,7 +658,7 @@ class Graphics(Handler):
596
658
  }
597
659
  """)
598
660
  checkbox.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Preferred)
599
- record['widget'] = checkbox
661
+ self.setWidget(record, checkbox)
600
662
  return self.nextPC()
601
663
 
602
664
  def r_createLineEdit(self, command, record):
@@ -607,7 +669,7 @@ class Graphics(Handler):
607
669
  c = lineinput.contentsMargins()
608
670
  w = fm.horizontalAdvance('x') * self.getRuntimeValue(command['size']) +m.left()+m.right()+c.left()+c.right()
609
671
  lineinput.setMaximumWidth(w)
610
- record['widget'] = lineinput
672
+ self.setWidget(record, lineinput)
611
673
  return self.nextPC()
612
674
 
613
675
  def r_createMultiLineEdit(self, command, record):
@@ -617,19 +679,19 @@ class Graphics(Handler):
617
679
  charHeight = fontMetrics.height()
618
680
  textinput.setFixedWidth(charWidth * self.getRuntimeValue(command['cols']))
619
681
  textinput.setFixedHeight(charHeight * self.getRuntimeValue(command['rows']))
620
- record['widget'] = textinput
682
+ self.setWidget(record, textinput)
621
683
  return self.nextPC()
622
684
 
623
685
  def r_createListWidget(self, command, record):
624
- record['widget'] = QListWidget()
686
+ self.setWidget(record, QListWidget())
625
687
  return self.nextPC()
626
688
 
627
689
  def r_createComboBox(self, command, record):
628
- record['widget'] = QComboBox()
690
+ self.setWidget(record, QComboBox())
629
691
  return self.nextPC()
630
692
 
631
693
  def r_createWidget(self, command, record):
632
- record['widget'] = QWidget()
694
+ self.setWidget(record, QWidget())
633
695
  return self.nextPC()
634
696
 
635
697
  def r_createDialog(self, command, record):
@@ -757,12 +819,23 @@ class Graphics(Handler):
757
819
  def r_group(self, command):
758
820
  return self.nextPC()
759
821
 
760
- # Initialize the graphics environment
761
- def k_init(self, command):
762
- if self.nextIs('graphics'):
763
- self.add(command)
764
- return True
822
+ # hide {widget}
823
+ def k_hide(self, command):
824
+ if self.nextIsSymbol():
825
+ record = self.getSymbolRecord()
826
+ if self.isWidget(record['keyword']):
827
+ command['widget'] = record['name']
828
+ self.add(command)
829
+ return True
765
830
  return False
831
+
832
+ def r_hide(self, command):
833
+ record = self.getVariable(command['widget'])
834
+ if 'widget' in record: self.getWidget(record).hide()
835
+ return self.nextPC()
836
+
837
+ # Initialize the graphics environment
838
+ # Unused: def k_init(self, command):
766
839
 
767
840
  def r_init(self, command):
768
841
  self.app = QApplication(sys.argv)
@@ -770,7 +843,22 @@ class Graphics(Handler):
770
843
  self.program.screenWidth = screen[0]
771
844
  self.program.screenHeight = screen[1]
772
845
  print(f'Screen: {self.program.screenWidth}x{self.program.screenHeight}')
773
- return self.nextPC()
846
+ # return self.nextPC()
847
+ def on_last_window_closed():
848
+ self.program.kill()
849
+ def init():
850
+ self.program.flush(self.nextPC())
851
+ def flush():
852
+ if not self.blocked:
853
+ if self.runOnTick != 0:
854
+ self.program.run(self.runOnTick)
855
+ self.program.flushCB()
856
+ timer = QTimer()
857
+ timer.timeout.connect(flush)
858
+ timer.start(10)
859
+ QTimer.singleShot(500, init)
860
+ self.app.lastWindowClosed.connect(on_last_window_closed)
861
+ self.app.exec()
774
862
 
775
863
  # Declare a label variable
776
864
  def k_label(self, command):
@@ -819,11 +907,11 @@ class Graphics(Handler):
819
907
  # on tick
820
908
  def k_on(self, command):
821
909
  def setupOn():
822
- command['goto'] = self.getPC() + 2
910
+ command['goto'] = self.getCodeSize() + 2
823
911
  self.add(command)
824
912
  self.nextToken()
825
913
  # Step over the click handler
826
- pcNext = self.getPC()
914
+ pcNext = self.getCodeSize()
827
915
  cmd = {}
828
916
  cmd['domain'] = 'core'
829
917
  cmd['lino'] = command['lino']
@@ -840,7 +928,7 @@ class Graphics(Handler):
840
928
  cmd['debug'] = False
841
929
  self.add(cmd)
842
930
  # Fixup the goto
843
- self.getCommandAt(pcNext)['goto'] = self.getPC()
931
+ self.getCommandAt(pcNext)['goto'] = self.getCodeSize()
844
932
 
845
933
  token = self.nextToken()
846
934
  command['type'] = token
@@ -860,11 +948,11 @@ class Graphics(Handler):
860
948
  return True
861
949
  elif token == 'tick':
862
950
  command['tick'] = True
863
- command['runOnTick'] = self.getPC() + 2
951
+ command['runOnTick'] = self.getCodeSize() + 2
864
952
  self.add(command)
865
953
  self.nextToken()
866
954
  # Step over the on tick action
867
- pcNext = self.getPC()
955
+ pcNext = self.getCodeSize()
868
956
  cmd = {}
869
957
  cmd['domain'] = 'core'
870
958
  cmd['lino'] = command['lino']
@@ -881,13 +969,13 @@ class Graphics(Handler):
881
969
  cmd['debug'] = False
882
970
  self.add(cmd)
883
971
  # Fixup the goto
884
- self.getCommandAt(pcNext)['goto'] = self.getPC()
972
+ self.getCommandAt(pcNext)['goto'] = self.getCodeSize()
885
973
  return True
886
974
  return False
887
975
 
888
976
  def r_on(self, command):
889
977
  def run(widget, record):
890
- for i, w in enumerate(record['value']):
978
+ for i, w in enumerate(record['widget']):
891
979
  if w == widget:
892
980
  record['index'] = i
893
981
  self.run(command['goto'])
@@ -941,10 +1029,10 @@ class Graphics(Handler):
941
1029
  record = self.getVariable(command['name'])
942
1030
  if variant == 'current':
943
1031
  if record['keyword'] == 'combobox':
944
- widget = record['widget']
1032
+ widget = self.getWidget(record)
945
1033
  widget.removeItem(widget.currentIndex())
946
1034
  if record['keyword'] == 'listbox':
947
- widget = record['widget']
1035
+ widget = self.getWidget(record)
948
1036
  selectedItem = widget.currentItem()
949
1037
  if selectedItem:
950
1038
  row = widget.row(selectedItem)
@@ -969,7 +1057,7 @@ class Graphics(Handler):
969
1057
  return False
970
1058
 
971
1059
  def r_select(self, command):
972
- widget = self.getVariable(command['widget'])['widget']
1060
+ widget = self.getWidget(self.getVariable(command['widget']))
973
1061
  if 'index' in command:
974
1062
  index = self.getRuntimeValue(command['index'])
975
1063
  else:
@@ -1012,9 +1100,10 @@ class Graphics(Handler):
1012
1100
  self.skip('to')
1013
1101
  if self.nextIsSymbol():
1014
1102
  record = self.getSymbolRecord()
1015
- command['layout'] = record['name']
1016
- self.add(command)
1017
- return True
1103
+ if record['keyword'] == 'layout':
1104
+ command['layout'] = record['name']
1105
+ self.add(command)
1106
+ return True
1018
1107
  elif token == 'spacing':
1019
1108
  self.skip('of')
1020
1109
  if self.nextIsSymbol():
@@ -1122,25 +1211,26 @@ class Graphics(Handler):
1122
1211
  def r_set(self, command):
1123
1212
  what = command['what']
1124
1213
  if what == 'height':
1125
- widget = self.getVariable(command['name'])['widget']
1214
+ widget = self.getWidget(self.getVariable(command['name']))
1126
1215
  widget.setFixedHeight(self.getRuntimeValue(command['value']))
1127
1216
  elif what == 'width':
1128
- widget = self.getVariable(command['name'])['widget']
1217
+ widget = self.getWidget(self.getVariable(command['name']))
1129
1218
  widget.setFixedWidth(self.getRuntimeValue(command['value']))
1130
1219
  elif what == 'layout':
1131
- content = self.getVariable(command['layout'])['widget']
1220
+ record = self.getVariable(command['layout'])
1221
+ layout = record['widget']
1132
1222
  record = self.getVariable(command['name'])
1133
1223
  keyword = record['keyword']
1134
1224
  if keyword == 'window':
1135
1225
  window = record['window']
1136
1226
  container = QWidget()
1137
- container.setLayout(content)
1227
+ container.setLayout(layout)
1138
1228
  window.setCentralWidget(container)
1139
1229
  elif keyword == 'widget':
1140
- widget = record['widget']
1141
- widget.setLayout(content)
1230
+ widget = self.getWidget(record)
1231
+ widget.setLayout(layout)
1142
1232
  elif what == 'spacing':
1143
- layout = self.getVariable(command['name'])['widget']
1233
+ layout = self.getWidget(self.getVariable(command['name']))
1144
1234
  layout.setSpacing(self.getRuntimeValue(command['value']))
1145
1235
  elif what == 'text':
1146
1236
  record = self.getVariable(command['name'])
@@ -1158,7 +1248,7 @@ class Graphics(Handler):
1158
1248
  record = self.getVariable(command['name'])
1159
1249
  if record['keyword'] == 'checkbox':
1160
1250
  state = self.getRuntimeValue(command['value'])
1161
- record['widget'].setChecked(state)
1251
+ self.getWidget(record).setChecked(state)
1162
1252
  elif what == 'alignment':
1163
1253
  widget = self.getVariable(command['name'])['widget']
1164
1254
  flags = command['value']
@@ -1197,6 +1287,7 @@ class Graphics(Handler):
1197
1287
 
1198
1288
  # show {window}
1199
1289
  # show {dialog}
1290
+ # show {widget}
1200
1291
  # show {messagebox} giving {result}}
1201
1292
  def k_show(self, command):
1202
1293
  if self.nextIsSymbol():
@@ -1210,6 +1301,10 @@ class Graphics(Handler):
1210
1301
  command['dialog'] = record['name']
1211
1302
  self.add(command)
1212
1303
  return True
1304
+ elif self.isWidget(keyword):
1305
+ command['name'] = record['name']
1306
+ self.add(command)
1307
+ return True
1213
1308
  elif keyword == 'messagebox':
1214
1309
  command['messagebox'] = record['name']
1215
1310
  self.skip('giving')
@@ -1270,6 +1365,9 @@ class Graphics(Handler):
1270
1365
  if dialog.exec() == QDialog.Accepted:
1271
1366
  record['result'] = dialog.textEdit.toPlainText()
1272
1367
  else: record['result'] = dialog.value
1368
+ elif 'name' in command:
1369
+ record = self.getVariable(command['name'])
1370
+ if 'widget' in record: self.getWidget(record).show()
1273
1371
  return self.nextPC()
1274
1372
 
1275
1373
  # Start the graphics
@@ -1280,21 +1378,22 @@ class Graphics(Handler):
1280
1378
  return False
1281
1379
 
1282
1380
  def r_start(self, command):
1283
- def on_last_window_closed():
1284
- self.program.kill()
1285
- def init():
1286
- self.program.flush(self.nextPC())
1287
- def flush():
1288
- if not self.blocked:
1289
- if self.runOnTick != 0:
1290
- self.program.run(self.runOnTick)
1291
- self.program.flushCB()
1292
- timer = QTimer()
1293
- timer.timeout.connect(flush)
1294
- timer.start(10)
1295
- QTimer.singleShot(500, init)
1296
- self.app.lastWindowClosed.connect(on_last_window_closed)
1297
- self.app.exec()
1381
+ return self.nextPC()
1382
+ # def on_last_window_closed():
1383
+ # self.program.kill()
1384
+ # def init():
1385
+ # self.program.flush(self.nextPC())
1386
+ # def flush():
1387
+ # if not self.blocked:
1388
+ # if self.runOnTick != 0:
1389
+ # self.program.run(self.runOnTick)
1390
+ # self.program.flushCB()
1391
+ # timer = QTimer()
1392
+ # timer.timeout.connect(flush)
1393
+ # timer.start(10)
1394
+ # QTimer.singleShot(500, init)
1395
+ # self.app.lastWindowClosed.connect(on_last_window_closed)
1396
+ # self.app.exec()
1298
1397
 
1299
1398
  # Declare a widget variable
1300
1399
  def k_widget(self, command):
@@ -1364,38 +1463,38 @@ class Graphics(Handler):
1364
1463
  symbolRecord = self.getVariable(symbolRecord['name'])
1365
1464
  keyword = symbolRecord['keyword']
1366
1465
  if keyword == 'pushbutton':
1367
- pushbutton = self.getSymbolContent(symbolRecord) # symbolRecord['widget']
1466
+ pushbutton = self.getWidget(symbolRecord)
1368
1467
  v = {}
1369
1468
  v['type'] = 'text'
1370
1469
  v['content'] = pushbutton.accessibleName()
1371
1470
  return v
1372
1471
  elif keyword == 'lineinput':
1373
- lineinput = symbolRecord['widget']
1472
+ lineinput = self.getWidget(symbolRecord)
1374
1473
  v = {}
1375
1474
  v['type'] = 'text'
1376
1475
  v['content'] = lineinput.displayText()
1377
1476
  return v
1378
1477
  elif keyword == 'multiline':
1379
- multiline = symbolRecord['widget']
1478
+ multiline = self.getWidget(symbolRecord)
1380
1479
  v = {}
1381
1480
  v['type'] = 'text'
1382
1481
  v['content'] = multiline.toPlainText()
1383
1482
  return v
1384
1483
  elif keyword == 'combobox':
1385
- combobox = symbolRecord['widget']
1484
+ combobox = self.getWidget(symbolRecord)
1386
1485
  v = {}
1387
1486
  v['type'] = 'text'
1388
1487
  v['content'] = combobox.currentText()
1389
1488
  return v
1390
1489
  elif keyword == 'listbox':
1391
- listbox = symbolRecord['widget']
1490
+ listbox = self.getWidget(symbolRecord)
1392
1491
  content = listbox.currentItem().text()
1393
1492
  v = {}
1394
1493
  v['type'] = 'text'
1395
1494
  v['content'] = content
1396
1495
  return v
1397
1496
  elif keyword == 'checkbox':
1398
- checkbox = symbolRecord['widget']
1497
+ checkbox =self.getWidget(symbolRecord)
1399
1498
  content = checkbox.isChecked()
1400
1499
  v = {}
1401
1500
  v['type'] = 'boolean'
@@ -1412,7 +1511,7 @@ class Graphics(Handler):
1412
1511
  def v_count(self, v):
1413
1512
  record = self.getVariable(v['name'])
1414
1513
  keyword = record['keyword']
1415
- widget = record['widget']
1514
+ widget = self.getWidget(record)
1416
1515
  if keyword in ['combobox', 'listbox']: content = widget.count()
1417
1516
  value = {}
1418
1517
  value['type'] = 'int'
@@ -1422,7 +1521,7 @@ class Graphics(Handler):
1422
1521
  def v_current(self, v):
1423
1522
  record = self.getVariable(v['name'])
1424
1523
  keyword = record['keyword']
1425
- widget = record['widget']
1524
+ widget = self.getWidget(record)
1426
1525
  if keyword == 'listbox': content = widget.currentItem().text()
1427
1526
  value = {}
1428
1527
  value['type'] = 'text'
@@ -1432,8 +1531,9 @@ class Graphics(Handler):
1432
1531
  #############################################################################
1433
1532
  # Compile a condition
1434
1533
  def compileCondition(self):
1435
- condition = {}
1436
- return condition
1534
+ condition = Object()
1535
+ condition.negate = False
1536
+ return None
1437
1537
 
1438
1538
  #############################################################################
1439
1539
  # Condition handlers
@@ -1442,4 +1542,4 @@ class Graphics(Handler):
1442
1542
  # Force the application to exit
1443
1543
  def force_exit(self):
1444
1544
  QApplication.quit() # Gracefully close the application
1445
- sys.exit(0) # Force a complete system exit
1545
+ sys.exit(0) # Force a complete system exit
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: easycoder
3
- Version: 251004.1
3
+ Version: 251104.1
4
4
  Summary: Rapid scripting in English
5
5
  Keywords: compiler,scripting,prototyping,programming,coding,python,low code,hypertalk,computer language,learn to code
6
6
  Author-email: Graham Trott <gtanyware@gmail.com>
@@ -0,0 +1,19 @@
1
+ easycoder/__init__.py,sha256=7ZoWrgGr2R_dOw69Yis1-y0u8zR8AAQ24gN0GpfM5rc,339
2
+ easycoder/close.png,sha256=3B9ueRNtEu9E4QNmZhdyC4VL6uqKvGmdfeFxIV9aO_Y,9847
3
+ easycoder/ec_border.py,sha256=KpOy0Jq8jI_6DYGo4jaFvoBP_jTIoAYWrmuHhl-FXA4,2355
4
+ easycoder/ec_classes.py,sha256=YGUiKnVN6T5scoeBmmGDQAtE8xJgaTHi0Exh9A7H2Y4,1750
5
+ easycoder/ec_compiler.py,sha256=2bdB7Bb4Cn_Uj7g0wjDn_gO0gQivqeaFellbgbAT2Hg,6587
6
+ easycoder/ec_condition.py,sha256=uamZrlW3Ej3R4bPDuduGB2f00M80Z1D0qV8muDx4Qfw,784
7
+ easycoder/ec_core.py,sha256=K89KR1z_clnubQgq_-L3SiTTRI4qs2ue1MhuUkB9xoU,100888
8
+ easycoder/ec_handler.py,sha256=doGCMXBCQxvSaD3omKMlXoR_LvQODxV7dZyoWafecyg,2336
9
+ easycoder/ec_keyboard.py,sha256=H8DhPT8-IvAIGgRxCs4qSaF_AQLaS6lxxtDteejbktM,19010
10
+ easycoder/ec_program.py,sha256=aPuZOYWFqGd1jsLDl5M5YmLu5LfFAewF9EZh6zHIbyM,10308
11
+ easycoder/ec_pyside.py,sha256=DwHMsk5kDBXg8feSbkyUinGWPO1a4uH-rcT3F9J4Aiw,58287
12
+ easycoder/ec_timestamp.py,sha256=myQnnF-mT31_1dpQKv2VEAu4BCcbypvMdzq7_DUi1xc,277
13
+ easycoder/ec_value.py,sha256=zgDJTJhIg3yOvmnnKIfccIizmIhGbtvL_ghLTL1T5fg,2516
14
+ easycoder/tick.png,sha256=OedASXJJTYvnza4J6Kv5m5lz6DrBfy667zX_WGgtbmM,9127
15
+ easycoder-251104.1.dist-info/entry_points.txt,sha256=JXAZbenl0TnsIft2FcGJbJ-4qoztVu2FuT8PFmWFexM,44
16
+ easycoder-251104.1.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
17
+ easycoder-251104.1.dist-info/WHEEL,sha256=Dyt6SBfaasWElUrURkknVFAZDHSTwxg3PaTza7RSbkY,100
18
+ easycoder-251104.1.dist-info/METADATA,sha256=jWlzWZY1kVcRNkxMiIn6SGBsgK3UESTSnMhp8KlG064,6897
19
+ easycoder-251104.1.dist-info/RECORD,,
@@ -1,19 +0,0 @@
1
- easycoder/__init__.py,sha256=q9lIBFHBsL7m8IFo13YFUlg_4clZurFfRFYX7kZnBCo,339
2
- easycoder/close.png,sha256=3B9ueRNtEu9E4QNmZhdyC4VL6uqKvGmdfeFxIV9aO_Y,9847
3
- easycoder/ec_border.py,sha256=KpOy0Jq8jI_6DYGo4jaFvoBP_jTIoAYWrmuHhl-FXA4,2355
4
- easycoder/ec_classes.py,sha256=bejrby7mLHTeAQXhhz-1l8iv6LSbNSy30lW21KJKjXE,1832
5
- easycoder/ec_compiler.py,sha256=LYwGNs8dcHKXI_nnu1sVFe1N36vjvylcUO_tX_bLjrk,5359
6
- easycoder/ec_condition.py,sha256=YXvSBQKEzKGCcgUGo3Qp8iHolXmm2BpEm0NimSDszIM,785
7
- easycoder/ec_core.py,sha256=VTAnhdLp3ftZ1tLPhovKX0PQ1CplmC9x17jH_DfrJsQ,99650
8
- easycoder/ec_handler.py,sha256=ED08ULiOlZkcs4XHxAguvdPZw_dFXuwGDFLbFuo0kLs,2317
9
- easycoder/ec_keyboard.py,sha256=ru-HdWolBMZJPyck2s72In9tXFeLJQSPtR1TpjmIo90,18350
10
- easycoder/ec_program.py,sha256=srVDRlELMElvnkjxmREczUVPkvPXPvanZglN4hKreLI,10324
11
- easycoder/ec_pyside.py,sha256=bnGwnlYyN-4KI4ECpocrgVx2uGO_9aDrDZNjT4AK7ak,54148
12
- easycoder/ec_timestamp.py,sha256=myQnnF-mT31_1dpQKv2VEAu4BCcbypvMdzq7_DUi1xc,277
13
- easycoder/ec_value.py,sha256=zgDJTJhIg3yOvmnnKIfccIizmIhGbtvL_ghLTL1T5fg,2516
14
- easycoder/tick.png,sha256=OedASXJJTYvnza4J6Kv5m5lz6DrBfy667zX_WGgtbmM,9127
15
- easycoder-251004.1.dist-info/entry_points.txt,sha256=JXAZbenl0TnsIft2FcGJbJ-4qoztVu2FuT8PFmWFexM,44
16
- easycoder-251004.1.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
17
- easycoder-251004.1.dist-info/WHEEL,sha256=Dyt6SBfaasWElUrURkknVFAZDHSTwxg3PaTza7RSbkY,100
18
- easycoder-251004.1.dist-info/METADATA,sha256=O3CZb_23D8wHS9r_IMN0TLjZVRg1JMgq_SgOuxU6nb8,6897
19
- easycoder-251004.1.dist-info/RECORD,,