easycoder 250107.4__tar.gz → 250109.1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of easycoder might be problematic. Click here for more details.

Files changed (164) hide show
  1. {easycoder-250107.4 → easycoder-250109.1}/PKG-INFO +1 -1
  2. {easycoder-250107.4 → easycoder-250109.1}/easycoder/__init__.py +1 -1
  3. {easycoder-250107.4 → easycoder-250109.1}/easycoder/ec_graphics.py +25 -29
  4. {easycoder-250107.4 → easycoder-250109.1}/easycoder/ec_program.py +1 -1
  5. {easycoder-250107.4 → easycoder-250109.1}/easycoder/ec_renderer.py +36 -18
  6. {easycoder-250107.4 → easycoder-250109.1}/easycoder/ec_screenspec.py +14 -7
  7. {easycoder-250107.4 → easycoder-250109.1}/easycoder/ec_value.py +9 -2
  8. easycoder-250109.1/plugins/ec_keyboard.py +248 -0
  9. easycoder-250109.1/plugins/keyboards/4-function.json +58 -0
  10. easycoder-250109.1/plugins/keyboards/round-button.png +0 -0
  11. {easycoder-250107.4 → easycoder-250109.1}/scripts/graphics-demo.ecg +1 -1
  12. easycoder-250109.1/scripts/keyboard.ecg +22 -0
  13. {easycoder-250107.4 → easycoder-250109.1}/scripts/wave.ecg +20 -3
  14. {easycoder-250107.4 → easycoder-250109.1}/LICENSE +0 -0
  15. {easycoder-250107.4 → easycoder-250109.1}/README.md +0 -0
  16. {easycoder-250107.4 → easycoder-250109.1}/doc/README.md +0 -0
  17. {easycoder-250107.4 → easycoder-250109.1}/doc/core/README.md +0 -0
  18. {easycoder-250107.4 → easycoder-250109.1}/doc/core/conditions/boolean.md +0 -0
  19. {easycoder-250107.4 → easycoder-250109.1}/doc/core/conditions/empty.md +0 -0
  20. {easycoder-250107.4 → easycoder-250109.1}/doc/core/conditions/ends.md +0 -0
  21. {easycoder-250107.4 → easycoder-250109.1}/doc/core/conditions/even.md +0 -0
  22. {easycoder-250107.4 → easycoder-250109.1}/doc/core/conditions/exists.md +0 -0
  23. {easycoder-250107.4 → easycoder-250109.1}/doc/core/conditions/greater.md +0 -0
  24. {easycoder-250107.4 → easycoder-250109.1}/doc/core/conditions/hasProperty.md +0 -0
  25. {easycoder-250107.4 → easycoder-250109.1}/doc/core/conditions/includes.md +0 -0
  26. {easycoder-250107.4 → easycoder-250109.1}/doc/core/conditions/is.md +0 -0
  27. {easycoder-250107.4 → easycoder-250109.1}/doc/core/conditions/less.md +0 -0
  28. {easycoder-250107.4 → easycoder-250109.1}/doc/core/conditions/list.md +0 -0
  29. {easycoder-250107.4 → easycoder-250109.1}/doc/core/conditions/none.md +0 -0
  30. {easycoder-250107.4 → easycoder-250109.1}/doc/core/conditions/not.md +0 -0
  31. {easycoder-250107.4 → easycoder-250109.1}/doc/core/conditions/numeric.md +0 -0
  32. {easycoder-250107.4 → easycoder-250109.1}/doc/core/conditions/object.md +0 -0
  33. {easycoder-250107.4 → easycoder-250109.1}/doc/core/conditions/odd.md +0 -0
  34. {easycoder-250107.4 → easycoder-250109.1}/doc/core/conditions/starts.md +0 -0
  35. {easycoder-250107.4 → easycoder-250109.1}/doc/core/conditions/string.md +0 -0
  36. {easycoder-250107.4 → easycoder-250109.1}/doc/core/keywords/add.md +0 -0
  37. {easycoder-250107.4 → easycoder-250109.1}/doc/core/keywords/append.md +0 -0
  38. {easycoder-250107.4 → easycoder-250109.1}/doc/core/keywords/assert.md +0 -0
  39. {easycoder-250107.4 → easycoder-250109.1}/doc/core/keywords/begin.md +0 -0
  40. {easycoder-250107.4 → easycoder-250109.1}/doc/core/keywords/clear.md +0 -0
  41. {easycoder-250107.4 → easycoder-250109.1}/doc/core/keywords/close.md +0 -0
  42. {easycoder-250107.4 → easycoder-250109.1}/doc/core/keywords/create.md +0 -0
  43. {easycoder-250107.4 → easycoder-250109.1}/doc/core/keywords/debug.md +0 -0
  44. {easycoder-250107.4 → easycoder-250109.1}/doc/core/keywords/decrement.md +0 -0
  45. {easycoder-250107.4 → easycoder-250109.1}/doc/core/keywords/delete.md +0 -0
  46. {easycoder-250107.4 → easycoder-250109.1}/doc/core/keywords/divide.md +0 -0
  47. {easycoder-250107.4 → easycoder-250109.1}/doc/core/keywords/exit.md +0 -0
  48. {easycoder-250107.4 → easycoder-250109.1}/doc/core/keywords/file.md +0 -0
  49. {easycoder-250107.4 → easycoder-250109.1}/doc/core/keywords/fork.md +0 -0
  50. {easycoder-250107.4 → easycoder-250109.1}/doc/core/keywords/get.md +0 -0
  51. {easycoder-250107.4 → easycoder-250109.1}/doc/core/keywords/go.md +0 -0
  52. {easycoder-250107.4 → easycoder-250109.1}/doc/core/keywords/gosub.md +0 -0
  53. {easycoder-250107.4 → easycoder-250109.1}/doc/core/keywords/if.md +0 -0
  54. {easycoder-250107.4 → easycoder-250109.1}/doc/core/keywords/import.md +0 -0
  55. {easycoder-250107.4 → easycoder-250109.1}/doc/core/keywords/increment.md +0 -0
  56. {easycoder-250107.4 → easycoder-250109.1}/doc/core/keywords/index.md +0 -0
  57. {easycoder-250107.4 → easycoder-250109.1}/doc/core/keywords/init.md +0 -0
  58. {easycoder-250107.4 → easycoder-250109.1}/doc/core/keywords/input.md +0 -0
  59. {easycoder-250107.4 → easycoder-250109.1}/doc/core/keywords/load.md +0 -0
  60. {easycoder-250107.4 → easycoder-250109.1}/doc/core/keywords/lock.md +0 -0
  61. {easycoder-250107.4 → easycoder-250109.1}/doc/core/keywords/module.md +0 -0
  62. {easycoder-250107.4 → easycoder-250109.1}/doc/core/keywords/multiply.md +0 -0
  63. {easycoder-250107.4 → easycoder-250109.1}/doc/core/keywords/negate.md +0 -0
  64. {easycoder-250107.4 → easycoder-250109.1}/doc/core/keywords/open.md +0 -0
  65. {easycoder-250107.4 → easycoder-250109.1}/doc/core/keywords/pop.md +0 -0
  66. {easycoder-250107.4 → easycoder-250109.1}/doc/core/keywords/post.md +0 -0
  67. {easycoder-250107.4 → easycoder-250109.1}/doc/core/keywords/print.md +0 -0
  68. {easycoder-250107.4 → easycoder-250109.1}/doc/core/keywords/push.md +0 -0
  69. {easycoder-250107.4 → easycoder-250109.1}/doc/core/keywords/put.md +0 -0
  70. {easycoder-250107.4 → easycoder-250109.1}/doc/core/keywords/read.md +0 -0
  71. {easycoder-250107.4 → easycoder-250109.1}/doc/core/keywords/release.md +0 -0
  72. {easycoder-250107.4 → easycoder-250109.1}/doc/core/keywords/replace.md +0 -0
  73. {easycoder-250107.4 → easycoder-250109.1}/doc/core/keywords/return.md +0 -0
  74. {easycoder-250107.4 → easycoder-250109.1}/doc/core/keywords/run.md +0 -0
  75. {easycoder-250107.4 → easycoder-250109.1}/doc/core/keywords/save.md +0 -0
  76. {easycoder-250107.4 → easycoder-250109.1}/doc/core/keywords/script.md +0 -0
  77. {easycoder-250107.4 → easycoder-250109.1}/doc/core/keywords/set.md +0 -0
  78. {easycoder-250107.4 → easycoder-250109.1}/doc/core/keywords/split.md +0 -0
  79. {easycoder-250107.4 → easycoder-250109.1}/doc/core/keywords/stack.md +0 -0
  80. {easycoder-250107.4 → easycoder-250109.1}/doc/core/keywords/stop.md +0 -0
  81. {easycoder-250107.4 → easycoder-250109.1}/doc/core/keywords/system.md +0 -0
  82. {easycoder-250107.4 → easycoder-250109.1}/doc/core/keywords/take.md +0 -0
  83. {easycoder-250107.4 → easycoder-250109.1}/doc/core/keywords/toggle.md +0 -0
  84. {easycoder-250107.4 → easycoder-250109.1}/doc/core/keywords/truncate.md +0 -0
  85. {easycoder-250107.4 → easycoder-250109.1}/doc/core/keywords/unlock.md +0 -0
  86. {easycoder-250107.4 → easycoder-250109.1}/doc/core/keywords/variable.md +0 -0
  87. {easycoder-250107.4 → easycoder-250109.1}/doc/core/keywords/wait.md +0 -0
  88. {easycoder-250107.4 → easycoder-250109.1}/doc/core/keywords/while.md +0 -0
  89. {easycoder-250107.4 → easycoder-250109.1}/doc/core/keywords/write.md +0 -0
  90. {easycoder-250107.4 → easycoder-250109.1}/doc/core/values/arg.md +0 -0
  91. {easycoder-250107.4 → easycoder-250109.1}/doc/core/values/args.md +0 -0
  92. {easycoder-250107.4 → easycoder-250109.1}/doc/core/values/cos.md +0 -0
  93. {easycoder-250107.4 → easycoder-250109.1}/doc/core/values/datime.md +0 -0
  94. {easycoder-250107.4 → easycoder-250109.1}/doc/core/values/decode.md +0 -0
  95. {easycoder-250107.4 → easycoder-250109.1}/doc/core/values/element.md +0 -0
  96. {easycoder-250107.4 → easycoder-250109.1}/doc/core/values/elements.md +0 -0
  97. {easycoder-250107.4 → easycoder-250109.1}/doc/core/values/empty.md +0 -0
  98. {easycoder-250107.4 → easycoder-250109.1}/doc/core/values/encode.md +0 -0
  99. {easycoder-250107.4 → easycoder-250109.1}/doc/core/values/error.md +0 -0
  100. {easycoder-250107.4 → easycoder-250109.1}/doc/core/values/files.md +0 -0
  101. {easycoder-250107.4 → easycoder-250109.1}/doc/core/values/float.md +0 -0
  102. {easycoder-250107.4 → easycoder-250109.1}/doc/core/values/from.md +0 -0
  103. {easycoder-250107.4 → easycoder-250109.1}/doc/core/values/hash.md +0 -0
  104. {easycoder-250107.4 → easycoder-250109.1}/doc/core/values/index.md +0 -0
  105. {easycoder-250107.4 → easycoder-250109.1}/doc/core/values/integer.md +0 -0
  106. {easycoder-250107.4 → easycoder-250109.1}/doc/core/values/json.md +0 -0
  107. {easycoder-250107.4 → easycoder-250109.1}/doc/core/values/keys.md +0 -0
  108. {easycoder-250107.4 → easycoder-250109.1}/doc/core/values/left.md +0 -0
  109. {easycoder-250107.4 → easycoder-250109.1}/doc/core/values/length.md +0 -0
  110. {easycoder-250107.4 → easycoder-250109.1}/doc/core/values/lowercase.md +0 -0
  111. {easycoder-250107.4 → easycoder-250109.1}/doc/core/values/memory.md +0 -0
  112. {easycoder-250107.4 → easycoder-250109.1}/doc/core/values/modification.md +0 -0
  113. {easycoder-250107.4 → easycoder-250109.1}/doc/core/values/modulo.md +0 -0
  114. {easycoder-250107.4 → easycoder-250109.1}/doc/core/values/newline.md +0 -0
  115. {easycoder-250107.4 → easycoder-250109.1}/doc/core/values/now.md +0 -0
  116. {easycoder-250107.4 → easycoder-250109.1}/doc/core/values/position.md +0 -0
  117. {easycoder-250107.4 → easycoder-250109.1}/doc/core/values/property.md +0 -0
  118. {easycoder-250107.4 → easycoder-250109.1}/doc/core/values/random.md +0 -0
  119. {easycoder-250107.4 → easycoder-250109.1}/doc/core/values/right.md +0 -0
  120. {easycoder-250107.4 → easycoder-250109.1}/doc/core/values/sin.md +0 -0
  121. {easycoder-250107.4 → easycoder-250109.1}/doc/core/values/stringify.md +0 -0
  122. {easycoder-250107.4 → easycoder-250109.1}/doc/core/values/tab.md +0 -0
  123. {easycoder-250107.4 → easycoder-250109.1}/doc/core/values/tan.md +0 -0
  124. {easycoder-250107.4 → easycoder-250109.1}/doc/core/values/timestamp.md +0 -0
  125. {easycoder-250107.4 → easycoder-250109.1}/doc/core/values/today.md +0 -0
  126. {easycoder-250107.4 → easycoder-250109.1}/doc/core/values/trim.md +0 -0
  127. {easycoder-250107.4 → easycoder-250109.1}/doc/core/values/type.md +0 -0
  128. {easycoder-250107.4 → easycoder-250109.1}/doc/core/values/uppercase.md +0 -0
  129. {easycoder-250107.4 → easycoder-250109.1}/doc/core/values/value.md +0 -0
  130. {easycoder-250107.4 → easycoder-250109.1}/doc/core/values/weekday.md +0 -0
  131. {easycoder-250107.4 → easycoder-250109.1}/doc/graphics/README.md +0 -0
  132. {easycoder-250107.4 → easycoder-250109.1}/doc/graphics/keywords/attach.md +0 -0
  133. {easycoder-250107.4 → easycoder-250109.1}/doc/graphics/keywords/close.md +0 -0
  134. {easycoder-250107.4 → easycoder-250109.1}/doc/graphics/keywords/create.md +0 -0
  135. {easycoder-250107.4 → easycoder-250109.1}/doc/graphics/keywords/ellipse.md +0 -0
  136. {easycoder-250107.4 → easycoder-250109.1}/doc/graphics/keywords/image.md +0 -0
  137. {easycoder-250107.4 → easycoder-250109.1}/doc/graphics/keywords/move.md +0 -0
  138. {easycoder-250107.4 → easycoder-250109.1}/doc/graphics/keywords/on.md +0 -0
  139. {easycoder-250107.4 → easycoder-250109.1}/doc/graphics/keywords/rectangle.md +0 -0
  140. {easycoder-250107.4 → easycoder-250109.1}/doc/graphics/keywords/render.md +0 -0
  141. {easycoder-250107.4 → easycoder-250109.1}/doc/graphics/keywords/run.md +0 -0
  142. {easycoder-250107.4 → easycoder-250109.1}/doc/graphics/keywords/set.md +0 -0
  143. {easycoder-250107.4 → easycoder-250109.1}/doc/graphics/keywords/text.md +0 -0
  144. {easycoder-250107.4 → easycoder-250109.1}/doc/graphics/values/attribute.md +0 -0
  145. {easycoder-250107.4 → easycoder-250109.1}/doc/graphics/values/window.md +0 -0
  146. {easycoder-250107.4 → easycoder-250109.1}/easycoder/README.md +0 -0
  147. {easycoder-250107.4 → easycoder-250109.1}/easycoder/ec.py +0 -0
  148. {easycoder-250107.4 → easycoder-250109.1}/easycoder/ec_classes.py +0 -0
  149. {easycoder-250107.4 → easycoder-250109.1}/easycoder/ec_compiler.py +0 -0
  150. {easycoder-250107.4 → easycoder-250109.1}/easycoder/ec_condition.py +0 -0
  151. {easycoder-250107.4 → easycoder-250109.1}/easycoder/ec_core.py +0 -0
  152. {easycoder-250107.4 → easycoder-250109.1}/easycoder/ec_handler.py +0 -0
  153. {easycoder-250107.4 → easycoder-250109.1}/easycoder/ec_timestamp.py +0 -0
  154. {easycoder-250107.4 → easycoder-250109.1}/images/Semoigo Dawn.jpg +0 -0
  155. {easycoder-250107.4 → easycoder-250109.1}/json/graphics-demo.json +0 -0
  156. {easycoder-250107.4 → easycoder-250109.1}/plugins/ec_p100.py +0 -0
  157. {easycoder-250107.4 → easycoder-250109.1}/plugins/example.py +0 -0
  158. {easycoder-250107.4 → easycoder-250109.1}/pyproject.toml +0 -0
  159. {easycoder-250107.4 → easycoder-250109.1}/scripts/README.md +0 -0
  160. {easycoder-250107.4 → easycoder-250109.1}/scripts/benchmark.ecs +0 -0
  161. {easycoder-250107.4 → easycoder-250109.1}/scripts/fizzbuzz.ecs +0 -0
  162. {easycoder-250107.4 → easycoder-250109.1}/scripts/hello.ecs +0 -0
  163. {easycoder-250107.4 → easycoder-250109.1}/scripts/points.ecs +0 -0
  164. {easycoder-250107.4 → easycoder-250109.1}/scripts/tests.ecs +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: easycoder
3
- Version: 250107.4
3
+ Version: 250109.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>
@@ -10,4 +10,4 @@ from .ec_program import *
10
10
  from .ec_timestamp import *
11
11
  from .ec_value import *
12
12
 
13
- __version__ = "250107.4"
13
+ __version__ = "250109.1"
@@ -1,8 +1,7 @@
1
- import sys, threading, json
2
1
  from .ec_classes import FatalError, RuntimeError, Object
3
2
  from .ec_handler import Handler
4
3
  from .ec_screenspec import ScreenSpec
5
- from .ec_renderer import Renderer
4
+ from .ec_renderer import Renderer, getUI
6
5
  from .ec_program import flush
7
6
 
8
7
  class Graphics(Handler):
@@ -32,7 +31,7 @@ class Graphics(Handler):
32
31
  targetRecord = self.getVariable(command['name'])
33
32
  keyword = targetRecord['keyword']
34
33
  id = self.getRuntimeValue(command['id'])
35
- uiElement = self.ui.getElement(id)
34
+ uiElement = getUI().getElement(id)
36
35
  if uiElement == None:
37
36
  FatalError(self.program.compiler, f'There is no screen element with id \'{id}\'')
38
37
  return -1
@@ -122,6 +121,7 @@ class Graphics(Handler):
122
121
  for item in ['width', 'height', 'left', 'bottom', 'r', 'g', 'b', 'text']:
123
122
  if command[item] == None:
124
123
  FatalError(self.program.compiler, f'Missing property \'{item}\'')
124
+ else: return False
125
125
  self.add(command)
126
126
  record['elementID'] = command['id']
127
127
  return False
@@ -199,7 +199,7 @@ class Graphics(Handler):
199
199
  self.windowSpec.fill = (self.getRuntimeValue(command['fill'][0])/255, self.getRuntimeValue(command['fill'][1])/255, self.getRuntimeValue(command['fill'][2])/255)
200
200
  self.windowCreated = True
201
201
  else:
202
- element = self.ui.createWidget(self.getWidgetSpec(command))
202
+ element = getUI().createWidget(self.getWidgetSpec(command))
203
203
  print(element)
204
204
  except Exception as e:
205
205
  RuntimeError(self.program, e)
@@ -224,10 +224,6 @@ class Graphics(Handler):
224
224
  def r_ellipse(self, command):
225
225
  return self.nextPC()
226
226
 
227
- def r_getui(self, command):
228
- self.ui = self.renderer.getUI()
229
- return self.nextPC()
230
-
231
227
  # Hide an element
232
228
  def k_hide(self, command):
233
229
  if self.nextIsSymbol():
@@ -240,7 +236,7 @@ class Graphics(Handler):
240
236
  return False
241
237
 
242
238
  def r_hide(self, command):
243
- self.ui.setVisible(self.getRuntimeValue(command['target']), False)
239
+ getUI().setVisible(self.getRuntimeValue(command['target']), False)
244
240
  return self.nextPC()
245
241
 
246
242
  def k_image(self, command):
@@ -272,12 +268,12 @@ class Graphics(Handler):
272
268
 
273
269
  def r_move(self, command):
274
270
  pos = (self.getRuntimeValue(command['x']), self.getRuntimeValue(command['y']))
275
- self.ui.moveElementTo(self.getRuntimeValue(command['target']), pos)
271
+ getUI().moveElementTo(self.getRuntimeValue(command['target']), pos)
276
272
  return self.nextPC()
277
273
 
278
274
  def r_moveBy(self, command):
279
275
  dist = (self.getRuntimeValue(command['dx']), self.getRuntimeValue(command['dy']))
280
- self.ui.moveElementBy(self.getRuntimeValue(command['target']), dist)
276
+ getUI().moveElementBy(self.getRuntimeValue(command['target']), dist)
281
277
  return self.nextPC()
282
278
 
283
279
  # on click/tap {element} {action}
@@ -288,7 +284,7 @@ class Graphics(Handler):
288
284
  if self.nextIsSymbol():
289
285
  target = self.getSymbolRecord()
290
286
  else:
291
- FatalError(self.program.compiler, f'{self.getToken()} is not a screen element')
287
+ Warning(f'{self.getToken()} is not a screen element')
292
288
  return False
293
289
  command['target'] = target['name']
294
290
  command['goto'] = self.getPC() + 2
@@ -329,7 +325,7 @@ class Graphics(Handler):
329
325
  data = Object()
330
326
  data.pc = pc
331
327
  data.index = index
332
- self.ui.setOnClick(id, data, oncb)
328
+ getUI().setOnClick(id, data, oncb)
333
329
  else:
334
330
  name = record['name']
335
331
  RuntimeError(self.program, f'{name} is not a clickable object')
@@ -341,25 +337,26 @@ class Graphics(Handler):
341
337
  def r_rectangle(self, command):
342
338
  return self.nextPC()
343
339
 
344
- # render {spec}
340
+ # render spec {spec}
345
341
  def k_render(self, command):
346
- command['spec'] = self.nextValue()
347
- command['parent'] = None
348
- if self.peek() == 'in':
349
- self.nextToken()
350
- if self.nextIsSymbol():
351
- command['parent'] = self.getSymbolRecord()['name']
352
- self.add(command)
353
- return True
342
+ if self.nextToken() in ['specification', 'spec']:
343
+ command['spec'] = self.nextValue()
344
+ command['parent'] = None
345
+ if self.peek() == 'in':
346
+ self.nextToken()
347
+ if self.nextIsSymbol():
348
+ command['parent'] = self.getSymbolRecord()['name']
349
+ self.add(command)
350
+ return True
351
+ return False
354
352
 
355
353
  def r_render(self, command):
356
354
  spec = self.getRuntimeValue(command['spec'])
357
355
  parent = command['parent']
358
356
  if parent !=None:
359
357
  parent = self.getVariable(command['parent'])
360
- self.ui = self.renderer.getUI()
361
358
  try:
362
- ScreenSpec().render(spec, parent, self.ui)
359
+ ScreenSpec().render(spec, parent)
363
360
  except Exception as e:
364
361
  RuntimeError(self.program, e)
365
362
  return self.nextPC()
@@ -374,7 +371,6 @@ class Graphics(Handler):
374
371
  def r_run(self, command):
375
372
  self.renderer = Renderer()
376
373
  self.renderer.init(self.windowSpec)
377
- self.ui = self.renderer.getUI()
378
374
  self.program.setExternalControl()
379
375
  self.program.run(self.nextPC())
380
376
  self.renderer.run()
@@ -405,7 +401,7 @@ class Graphics(Handler):
405
401
  target = self.getVariable(command['target'])
406
402
  id = target['value'][target['index']]['content']
407
403
  value = self.getRuntimeValue(command['value'])
408
- self.ui.setAttribute(id, attribute, value)
404
+ getUI().setAttribute(id, attribute, value)
409
405
  return self.nextPC()
410
406
 
411
407
  # Show an element (restore it to its current position)
@@ -420,7 +416,7 @@ class Graphics(Handler):
420
416
  return False
421
417
 
422
418
  def r_show(self, command):
423
- self.ui.setVisible(self.getRuntimeValue(command['target']), True)
419
+ getUI().setVisible(self.getRuntimeValue(command['target']), True)
424
420
  return self.nextPC()
425
421
 
426
422
  def k_text(self, command):
@@ -483,7 +479,7 @@ class Graphics(Handler):
483
479
  attribute = self.getRuntimeValue(v['attribute'])
484
480
  target = self.getVariable(v['target'])
485
481
  val = self.getSymbolValue(target)
486
- v = self.ui.getAttribute(val['content'], attribute)
482
+ v = getUI().getAttribute(val['content'], attribute)
487
483
  value = {}
488
484
  value['type'] = 'int'
489
485
  value['content'] = int(round(v))
@@ -505,7 +501,7 @@ class Graphics(Handler):
505
501
  attribute = v['attribute']
506
502
  value = {}
507
503
  value['type'] = 'int'
508
- value['content'] = int(round(self.ui.getWindowAttribute(attribute)))
504
+ value['content'] = int(round(getUI().getWindowAttribute(attribute)))
509
505
  return value
510
506
  except Exception as e:
511
507
  RuntimeError(self.program, e)
@@ -18,7 +18,6 @@ class Program:
18
18
 
19
19
  def __init__(self, argv):
20
20
  global queue
21
- print(f'EasyCoder version {version("easycoder")}')
22
21
  if len(argv) == 0:
23
22
  print('No script supplied')
24
23
  exit()
@@ -387,6 +386,7 @@ class Program:
387
386
 
388
387
  # This is the program launcher
389
388
  def Main():
389
+ print(f'EasyCoder version {version("easycoder")}')
390
390
  if (len(sys.argv) > 1):
391
391
  Program(sys.argv[1]).start()
392
392
  else:
@@ -1,23 +1,31 @@
1
1
  from kivy.app import App
2
2
  from kivy.uix.widget import Widget
3
+ from kivy.graphics import Color, Ellipse, Rectangle
3
4
  from kivy.uix.label import CoreLabel
4
5
  from kivy.uix.image import AsyncImage
5
6
  from kivy.core.window import Window
6
- from kivy.graphics import Color, Ellipse, Rectangle
7
7
  from kivy.utils import colormap
8
8
  from kivy.clock import Clock
9
9
  from kivy.vector import Vector
10
- import math
10
+ import math, os
11
+
12
+ os.environ['KIVY_TEXT'] = 'pango'
11
13
 
12
- # Get a real position or size value
13
- # These are {n}w/h, where w/h are percentages
14
+ ec_ui = None
15
+
16
+ def getUI():
17
+ global ec_ui
18
+ return ec_ui
19
+
20
+ # Get an actual screeen position or size value from a specified value
21
+ # such as {n}w/h, where w/h are percentages
14
22
  # e.g. 25w or 50h
15
- def getReal(spec, val):
23
+ def getActual(val, spec=None):
16
24
  if isinstance(val, str):
17
25
  c = val[-1]
18
26
  if c in ['w', 'h']:
19
27
  val = int(val[0:len(val)-1])
20
- if spec.parent == None:
28
+ if spec == None or spec.parent == None:
21
29
  if c == 'w':
22
30
  n = Window.width
23
31
  else:
@@ -40,8 +48,8 @@ class Element():
40
48
 
41
49
  def getRelativePosition(self):
42
50
  spec = self.spec
43
- x = getReal(spec, spec.pos[0])
44
- y = getReal(spec, spec.pos[1])
51
+ x = getActual(spec.pos[0], spec)
52
+ y = getActual(spec.pos[1], spec)
45
53
  return Vector(x, y)
46
54
 
47
55
  def getType(self):
@@ -108,10 +116,19 @@ class UI(Widget):
108
116
  Color(c[0], c[1], c[2])
109
117
  else:
110
118
  Color(c[0]/255, c[1]/255, c[2]/255)
111
- pos = (getReal(spec, spec.pos[0]), getReal(spec, spec.pos[1]))
112
- spec.realpos = pos
113
- size = (getReal(spec, spec.size[0]), getReal(spec, spec.size[1]))
119
+ size = (getActual(spec.size[0], spec), getActual(spec.size[1], spec))
114
120
  spec.realsize = size
121
+ # Deal with special case of 'center'
122
+ if spec.pos[0] == 'center':
123
+ left = getActual('50w', spec) - spec.realsize[0]/2
124
+ else:
125
+ left = getActual(spec.pos[0], spec)
126
+ if spec.pos[1] == 'center':
127
+ bottom = getActual('50h', spec) - spec.realsize[1]/2
128
+ else:
129
+ bottom = getActual(spec.pos[1], spec)
130
+ pos = (left, bottom)
131
+ spec.realpos = pos
115
132
  if spec.parent != None:
116
133
  pos = Vector(pos) + spec.parent.realpos
117
134
  if spec.type == 'ellipse':
@@ -128,10 +145,12 @@ class UI(Widget):
128
145
  Color(c[0]/255, c[1]/255, c[2]/255)
129
146
  else:
130
147
  Color(1, 1, 1, 1)
131
- label = CoreLabel(text=spec.text, font_size=1000, halign='center', valign='center')
148
+ if self.font == None:
149
+ label = CoreLabel(text=spec.text, font_size=1000, halign='center', valign='center')
150
+ else:
151
+ label = CoreLabel(text=spec.text, font_context = None, font_name=self.font, font_size=1000, halign='center', valign='center')
132
152
  label.refresh()
133
- text = label.texture
134
- item = Rectangle(pos=pos, size=size, texture=text)
153
+ item = Rectangle(pos=pos, size=size, texture=label.texture)
135
154
  elif spec.type == 'image':
136
155
  item = AsyncImage(pos=pos, size=size, source=spec.source)
137
156
  spec.item = item
@@ -231,9 +250,6 @@ class UI(Widget):
231
250
 
232
251
  class Renderer(App):
233
252
 
234
- def getUI(self):
235
- return self.ui
236
-
237
253
  def request_close(self):
238
254
  print('close window')
239
255
  self.kill()
@@ -247,7 +263,9 @@ class Renderer(App):
247
263
  return self.ui
248
264
 
249
265
  def init(self, spec):
250
- self.ui = UI()
266
+ global ec_ui
267
+ ec_ui = UI()
268
+ self.ui = ec_ui
251
269
  self.title = spec.title
252
270
  self.flush = spec.flush
253
271
  self.kill = spec.kill
@@ -1,21 +1,28 @@
1
1
  # screenspec.py
2
2
 
3
3
  from json import loads
4
- from .ec_renderer import Object
4
+ from .ec_renderer import Object, getUI
5
+
6
+ global_id = 0
5
7
 
6
8
  class ScreenSpec():
7
9
 
10
+ id = 0
11
+
8
12
  # Get an attribute of an element
9
13
  def getAttribute(self, id, attribute):
10
- element = self.ui.getElement(id)
14
+ element = getUI().getElement(id)
11
15
  return element[attribute]
12
16
 
13
17
  # Render a single widget
14
18
  def createWidget(self, widget, parent):
19
+ global global_id
15
20
  spec = Object()
16
21
  type = widget['type']
17
22
  spec.type = type
18
- spec.id = widget['id']
23
+ global_id += 1
24
+ if 'id' in widget: spec.id = widget['id']
25
+ else: spec.id = f'_{global_id}'
19
26
  spec.pos = (widget['left'], widget['bottom'])
20
27
  spec.size = (widget['width'], widget['height'])
21
28
  if widget.get('fill') != None:
@@ -30,7 +37,7 @@ class ScreenSpec():
30
37
  spec.color = widget['color']
31
38
  spec.parent = parent
32
39
  spec.children = []
33
- self.ui.createElement(spec)
40
+ getUI().createElement(spec)
34
41
 
35
42
  if '#' in widget:
36
43
  children = widget['#']
@@ -51,6 +58,8 @@ class ScreenSpec():
51
58
 
52
59
  # Render a complete specification
53
60
  def renderSpec(self, spec, parent):
61
+ if 'font' in spec: getUI().font = spec['font']
62
+ else: getUI().font = None
54
63
  widgets = spec['#']
55
64
  # If a list, iterate it
56
65
  if isinstance(widgets, list):
@@ -61,8 +70,7 @@ class ScreenSpec():
61
70
  self.createWidget(spec[widgets], parent)
62
71
 
63
72
  # Render a graphic specification
64
- def render(self, spec, parent, ui):
65
- self.ui = ui
73
+ def render(self, spec, parent):
66
74
 
67
75
  # If it'a string, process it
68
76
  if isinstance(spec, str):
@@ -71,4 +79,3 @@ class ScreenSpec():
71
79
  # If it's a 'dict', extract the spec and the args
72
80
  else:
73
81
  self.renderSpec(spec, parent)
74
-
@@ -1,5 +1,12 @@
1
1
  from .ec_classes import FatalError
2
2
 
3
+ # Create a constant
4
+ def getConstant(str):
5
+ value = {}
6
+ value['type'] = 'text'
7
+ value['content'] = str
8
+ return value
9
+
3
10
  class Value:
4
11
 
5
12
  def __init__(self, compiler):
@@ -15,7 +22,7 @@ class Value:
15
22
  return None
16
23
 
17
24
  value = {}
18
-
25
+
19
26
  if token == 'true':
20
27
  value['type'] = 'boolean'
21
28
  value['content'] = True
@@ -80,7 +87,7 @@ class Value:
80
87
  value = domain.modifyValue(value)
81
88
 
82
89
  return value
83
-
90
+
84
91
  def compileConstant(self, token):
85
92
  value = {}
86
93
  if type(token) == 'str':
@@ -0,0 +1,248 @@
1
+ from easycoder import Object, FatalError, RuntimeError
2
+ from easycoder import Handler
3
+ from easycoder import getConstant
4
+ from easycoder.ec_screenspec import ScreenSpec
5
+ from easycoder.ec_renderer import getActual, getUI
6
+ import json
7
+
8
+ class Keyboard(Handler):
9
+
10
+ def __init__(self, compiler):
11
+ Handler.__init__(self, compiler)
12
+ self.keyboard = None
13
+ self.key = None
14
+ self.onTap = None
15
+
16
+ def getName(self):
17
+ return 'keyboard'
18
+
19
+ #############################################################################
20
+ # Keyword handlers
21
+
22
+ # Create a keyboard
23
+ def k_create(self, command):
24
+ if self.nextIs('keyboard'):
25
+ command['template'] = self.nextValue()
26
+ buttonStyle = 'ellipse'
27
+ buttonTemplate = None
28
+ buttonTextWidth = getConstant('50w')
29
+ buttonTextHeight = getConstant('50h')
30
+ buttonTextColor = getConstant('black')
31
+ buttonTextX = getConstant('center')
32
+ buttonTextY = getConstant('center')
33
+ buttonColor = getConstant('white')
34
+ buttonFont = None
35
+ while True:
36
+ token = self.peek()
37
+ if token == 'button':
38
+ self.nextToken()
39
+ token = self.nextToken()
40
+ if token == 'style':
41
+ token = self.nextToken()
42
+ if token in ['ellipse', 'rectangle', 'image']:
43
+ buttonStyle = token
44
+ else: RuntimeError(self.program, f'Unknown style \'token\'')
45
+ elif token == 'color':
46
+ buttonColor = self.nextValue()
47
+ elif token == 'font':
48
+ buttonFont = self.nextValue()
49
+ elif token == 'template':
50
+ buttonTemplate = self.nextValue()
51
+ elif token == 'text':
52
+ token = self.nextToken()
53
+ if token =='width':
54
+ buttonTextWidth = self.nextValue()
55
+ elif token == 'height':
56
+ buttonTextHeight = self.nextValue()
57
+ elif token == 'color':
58
+ buttonTextColor = self.nextValue()
59
+ elif token == 'x':
60
+ buttonTextX = self.nextValue()
61
+ elif token == 'y':
62
+ buttonTextY = self.nextValue()
63
+ else: RuntimeError(self.program, f'Unknown property \'token\'')
64
+ else:
65
+ break
66
+ command['button-style'] = buttonStyle
67
+ command['button-template'] = buttonTemplate
68
+ command['button-text-width'] = buttonTextWidth
69
+ command['button-text-height'] = buttonTextHeight
70
+ command['button-text-color'] = buttonTextColor
71
+ command['button-text-x'] = buttonTextX
72
+ command['button-text-y'] = buttonTextY
73
+ command['button-color'] = buttonColor
74
+ command['button-font'] = buttonFont
75
+ self.add(command)
76
+ return True
77
+ return False
78
+
79
+ def r_create(self, command):
80
+ self.keyboard = Object()
81
+ template = self.getRuntimeValue(command['template'])
82
+ with open(f'{template}') as f: s = f.read()
83
+ self.keyboard.layout = json.loads(s)
84
+ self.keyboard.buttonStyle = command['button-style']
85
+ self.keyboard.buttonTemplate = self.getRuntimeValue(command['button-template'])
86
+ self.keyboard.buttonTextWidth = self.getRuntimeValue(command['button-text-width'])
87
+ self.keyboard.buttonTextHeight = self.getRuntimeValue(command['button-text-height'])
88
+ self.keyboard.buttonTextColor = self.getRuntimeValue(command['button-text-color'])
89
+ self.keyboard.buttonTextX = self.getRuntimeValue(command['button-text-x'])
90
+ self.keyboard.buttonTextY = self.getRuntimeValue(command['button-text-y'])
91
+ self.keyboard.buttonColor = self.getRuntimeValue(command['button-color'])
92
+ self.keyboard.buttonFont = self.getRuntimeValue(command['button-font'])
93
+ return self.nextPC()
94
+
95
+ # on click/tap keyboard
96
+ def k_on(self, command):
97
+ token = self.nextToken()
98
+ if token in ['click', 'tap']:
99
+ if self.nextIs('keyboard'):
100
+ command['goto'] = self.getPC() + 2
101
+ self.add(command)
102
+ self.nextToken()
103
+ pcNext = self.getPC()
104
+ cmd = {}
105
+ cmd['domain'] = 'core'
106
+ cmd['lino'] = command['lino']
107
+ cmd['keyword'] = 'gotoPC'
108
+ cmd['goto'] = 0
109
+ cmd['debug'] = False
110
+ self.addCommand(cmd)
111
+ self.compileOne()
112
+ cmd = {}
113
+ cmd['domain'] = 'core'
114
+ cmd['lino'] = command['lino']
115
+ cmd['keyword'] = 'stop'
116
+ cmd['debug'] = False
117
+ self.addCommand(cmd)
118
+ # Fixup the link
119
+ self.getCommandAt(pcNext)['goto'] = self.getPC()
120
+ return True
121
+ return False
122
+
123
+ # Set a handler
124
+ def r_on(self, command):
125
+ self.onTap = command['goto']
126
+ return self.nextPC()
127
+
128
+ # Render a keyboard
129
+ # render keyboard at {left} {bottom} width {width}
130
+ def k_render(self, command):
131
+ if self.nextIs('keyboard'):
132
+ token = self.peek()
133
+ while token in ['at', 'width']:
134
+ self.nextToken()
135
+ if token == 'at':
136
+ command['x'] = self.nextValue()
137
+ command['y'] = self.nextValue()
138
+ elif token == 'width':
139
+ command['w'] = self.nextValue()
140
+ token = self.peek()
141
+ self.add(command)
142
+ return True
143
+ return False
144
+
145
+ def r_render(self, command):
146
+ x = getActual(self.getRuntimeValue(command['x']))
147
+ y = getActual(self.getRuntimeValue(command['y']))
148
+ w = getActual(self.getRuntimeValue(command['w']))
149
+ # Scan the keyboard layout to find the longest row
150
+ max = 0
151
+ nrows = len(self.keyboard.layout)
152
+ for r in range(0, nrows):
153
+ row = self.keyboard.layout[r]
154
+ # Count the number of buttons
155
+ if len(row) > max: max = len(row)
156
+ # Divide the keyboard width by the number of buttons to get the button size
157
+ bs = w / max
158
+ # Compute the keyboard height
159
+ h = bs * nrows
160
+ # Build the spec
161
+ buttons = []
162
+ list = []
163
+ by = y
164
+ for r in reversed(range(0, nrows)):
165
+ row = self.keyboard.layout[r]
166
+ bx = x
167
+ for b in range(0, len(row)):
168
+ button = row[b]
169
+ id = button['id']
170
+ button['type'] = self.keyboard.buttonStyle
171
+ button['source'] = self.keyboard.buttonTemplate
172
+ button['left'] = bx
173
+ button['bottom'] = by
174
+ button['width'] = bs
175
+ button['height'] = bs
176
+ button['fill'] = self.keyboard.buttonColor
177
+ label = {}
178
+ label['type'] = 'text'
179
+ label['left'] = self.keyboard.buttonTextX
180
+ label['bottom'] = self.keyboard.buttonTextY
181
+ label['width'] = self.keyboard.buttonTextWidth
182
+ label['height'] = self.keyboard.buttonTextHeight
183
+ label['text'] = id
184
+ label['color'] = self.keyboard.buttonTextColor
185
+ button['#'] = 'Label'
186
+ button['Label'] = label
187
+ buttons.append(button)
188
+ list.append(id)
189
+ bx += bs
190
+ by += bs
191
+ spec = {}
192
+ spec['#'] = list
193
+ for n in range(0, len(list)):
194
+ spec[list[n]] = buttons[n]
195
+
196
+ spec['font'] = self.keyboard.buttonFont
197
+ try:
198
+ ScreenSpec().render(spec, None)
199
+ except Exception as e:
200
+ RuntimeError(self.program, e)
201
+
202
+ # Add a callback to each button
203
+ def oncb(id):
204
+ self.key = id
205
+ if self.onTap != None:
206
+ self.program.run(self.onTap)
207
+ for b in range(0, len(list)):
208
+ id = list[b]
209
+ getUI().setOnClick(id, id, oncb)
210
+
211
+ return self.nextPC()
212
+
213
+ #############################################################################
214
+ # Modify a value or leave it unchanged.
215
+ def modifyValue(self, value):
216
+ return value
217
+
218
+ #############################################################################
219
+ # Compile a value in this domain
220
+ def compileValue(self):
221
+ value = {}
222
+ value['domain'] = self.getName()
223
+ if self.tokenIs('the'):
224
+ self.nextToken()
225
+ kwd = self.getToken()
226
+
227
+ if kwd == 'key':
228
+ value['type'] = kwd
229
+ return value
230
+ return None
231
+
232
+ #############################################################################
233
+ # Value handlers
234
+
235
+ def v_key(self, v):
236
+ value = {}
237
+ value['type'] = 'text'
238
+ value['content'] = self.key
239
+ return value
240
+
241
+ #############################################################################
242
+ # Compile a condition in this domain
243
+ def compileCondition(self):
244
+ condition = {}
245
+ return condition
246
+
247
+ #############################################################################
248
+ # Condition handlers