easycoder 250109.2__tar.gz → 250110.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 (172) hide show
  1. {easycoder-250109.2 → easycoder-250110.1}/PKG-INFO +11 -7
  2. {easycoder-250109.2 → easycoder-250110.1}/README.md +10 -6
  3. {easycoder-250109.2 → easycoder-250110.1}/easycoder/__init__.py +1 -1
  4. {easycoder-250109.2 → easycoder-250110.1}/easycoder/ec_renderer.py +47 -48
  5. {easycoder-250109.2 → easycoder-250110.1}/easycoder/ec_screenspec.py +9 -9
  6. easycoder-250110.1/plugins/ec_keyboard.py +191 -0
  7. easycoder-250110.1/plugins/keyboards/4-function.json +64 -0
  8. easycoder-250110.1/plugins/keyboards/4-function.png +0 -0
  9. easycoder-250110.1/plugins/keyboards/qwerty-0.png +0 -0
  10. easycoder-250110.1/plugins/keyboards/qwerty.json +182 -0
  11. easycoder-250110.1/scripts/ec_keyboard.py +191 -0
  12. easycoder-250110.1/scripts/keyboard.ecg +12 -0
  13. easycoder-250110.1/scripts/qwerty.ecg +12 -0
  14. easycoder-250109.2/plugins/ec_keyboard.py +0 -248
  15. easycoder-250109.2/plugins/keyboards/4-function.json +0 -58
  16. easycoder-250109.2/plugins/keyboards/round-button.png +0 -0
  17. easycoder-250109.2/scripts/keyboard.ecg +0 -19
  18. {easycoder-250109.2 → easycoder-250110.1}/LICENSE +0 -0
  19. {easycoder-250109.2 → easycoder-250110.1}/doc/README.md +0 -0
  20. {easycoder-250109.2 → easycoder-250110.1}/doc/core/README.md +0 -0
  21. {easycoder-250109.2 → easycoder-250110.1}/doc/core/conditions/boolean.md +0 -0
  22. {easycoder-250109.2 → easycoder-250110.1}/doc/core/conditions/empty.md +0 -0
  23. {easycoder-250109.2 → easycoder-250110.1}/doc/core/conditions/ends.md +0 -0
  24. {easycoder-250109.2 → easycoder-250110.1}/doc/core/conditions/even.md +0 -0
  25. {easycoder-250109.2 → easycoder-250110.1}/doc/core/conditions/exists.md +0 -0
  26. {easycoder-250109.2 → easycoder-250110.1}/doc/core/conditions/greater.md +0 -0
  27. {easycoder-250109.2 → easycoder-250110.1}/doc/core/conditions/hasProperty.md +0 -0
  28. {easycoder-250109.2 → easycoder-250110.1}/doc/core/conditions/includes.md +0 -0
  29. {easycoder-250109.2 → easycoder-250110.1}/doc/core/conditions/is.md +0 -0
  30. {easycoder-250109.2 → easycoder-250110.1}/doc/core/conditions/less.md +0 -0
  31. {easycoder-250109.2 → easycoder-250110.1}/doc/core/conditions/list.md +0 -0
  32. {easycoder-250109.2 → easycoder-250110.1}/doc/core/conditions/none.md +0 -0
  33. {easycoder-250109.2 → easycoder-250110.1}/doc/core/conditions/not.md +0 -0
  34. {easycoder-250109.2 → easycoder-250110.1}/doc/core/conditions/numeric.md +0 -0
  35. {easycoder-250109.2 → easycoder-250110.1}/doc/core/conditions/object.md +0 -0
  36. {easycoder-250109.2 → easycoder-250110.1}/doc/core/conditions/odd.md +0 -0
  37. {easycoder-250109.2 → easycoder-250110.1}/doc/core/conditions/starts.md +0 -0
  38. {easycoder-250109.2 → easycoder-250110.1}/doc/core/conditions/string.md +0 -0
  39. {easycoder-250109.2 → easycoder-250110.1}/doc/core/keywords/add.md +0 -0
  40. {easycoder-250109.2 → easycoder-250110.1}/doc/core/keywords/append.md +0 -0
  41. {easycoder-250109.2 → easycoder-250110.1}/doc/core/keywords/assert.md +0 -0
  42. {easycoder-250109.2 → easycoder-250110.1}/doc/core/keywords/begin.md +0 -0
  43. {easycoder-250109.2 → easycoder-250110.1}/doc/core/keywords/clear.md +0 -0
  44. {easycoder-250109.2 → easycoder-250110.1}/doc/core/keywords/close.md +0 -0
  45. {easycoder-250109.2 → easycoder-250110.1}/doc/core/keywords/create.md +0 -0
  46. {easycoder-250109.2 → easycoder-250110.1}/doc/core/keywords/debug.md +0 -0
  47. {easycoder-250109.2 → easycoder-250110.1}/doc/core/keywords/decrement.md +0 -0
  48. {easycoder-250109.2 → easycoder-250110.1}/doc/core/keywords/delete.md +0 -0
  49. {easycoder-250109.2 → easycoder-250110.1}/doc/core/keywords/divide.md +0 -0
  50. {easycoder-250109.2 → easycoder-250110.1}/doc/core/keywords/exit.md +0 -0
  51. {easycoder-250109.2 → easycoder-250110.1}/doc/core/keywords/file.md +0 -0
  52. {easycoder-250109.2 → easycoder-250110.1}/doc/core/keywords/fork.md +0 -0
  53. {easycoder-250109.2 → easycoder-250110.1}/doc/core/keywords/get.md +0 -0
  54. {easycoder-250109.2 → easycoder-250110.1}/doc/core/keywords/go.md +0 -0
  55. {easycoder-250109.2 → easycoder-250110.1}/doc/core/keywords/gosub.md +0 -0
  56. {easycoder-250109.2 → easycoder-250110.1}/doc/core/keywords/if.md +0 -0
  57. {easycoder-250109.2 → easycoder-250110.1}/doc/core/keywords/import.md +0 -0
  58. {easycoder-250109.2 → easycoder-250110.1}/doc/core/keywords/increment.md +0 -0
  59. {easycoder-250109.2 → easycoder-250110.1}/doc/core/keywords/index.md +0 -0
  60. {easycoder-250109.2 → easycoder-250110.1}/doc/core/keywords/init.md +0 -0
  61. {easycoder-250109.2 → easycoder-250110.1}/doc/core/keywords/input.md +0 -0
  62. {easycoder-250109.2 → easycoder-250110.1}/doc/core/keywords/load.md +0 -0
  63. {easycoder-250109.2 → easycoder-250110.1}/doc/core/keywords/lock.md +0 -0
  64. {easycoder-250109.2 → easycoder-250110.1}/doc/core/keywords/module.md +0 -0
  65. {easycoder-250109.2 → easycoder-250110.1}/doc/core/keywords/multiply.md +0 -0
  66. {easycoder-250109.2 → easycoder-250110.1}/doc/core/keywords/negate.md +0 -0
  67. {easycoder-250109.2 → easycoder-250110.1}/doc/core/keywords/open.md +0 -0
  68. {easycoder-250109.2 → easycoder-250110.1}/doc/core/keywords/pop.md +0 -0
  69. {easycoder-250109.2 → easycoder-250110.1}/doc/core/keywords/post.md +0 -0
  70. {easycoder-250109.2 → easycoder-250110.1}/doc/core/keywords/print.md +0 -0
  71. {easycoder-250109.2 → easycoder-250110.1}/doc/core/keywords/push.md +0 -0
  72. {easycoder-250109.2 → easycoder-250110.1}/doc/core/keywords/put.md +0 -0
  73. {easycoder-250109.2 → easycoder-250110.1}/doc/core/keywords/read.md +0 -0
  74. {easycoder-250109.2 → easycoder-250110.1}/doc/core/keywords/release.md +0 -0
  75. {easycoder-250109.2 → easycoder-250110.1}/doc/core/keywords/replace.md +0 -0
  76. {easycoder-250109.2 → easycoder-250110.1}/doc/core/keywords/return.md +0 -0
  77. {easycoder-250109.2 → easycoder-250110.1}/doc/core/keywords/run.md +0 -0
  78. {easycoder-250109.2 → easycoder-250110.1}/doc/core/keywords/save.md +0 -0
  79. {easycoder-250109.2 → easycoder-250110.1}/doc/core/keywords/script.md +0 -0
  80. {easycoder-250109.2 → easycoder-250110.1}/doc/core/keywords/set.md +0 -0
  81. {easycoder-250109.2 → easycoder-250110.1}/doc/core/keywords/split.md +0 -0
  82. {easycoder-250109.2 → easycoder-250110.1}/doc/core/keywords/stack.md +0 -0
  83. {easycoder-250109.2 → easycoder-250110.1}/doc/core/keywords/stop.md +0 -0
  84. {easycoder-250109.2 → easycoder-250110.1}/doc/core/keywords/system.md +0 -0
  85. {easycoder-250109.2 → easycoder-250110.1}/doc/core/keywords/take.md +0 -0
  86. {easycoder-250109.2 → easycoder-250110.1}/doc/core/keywords/toggle.md +0 -0
  87. {easycoder-250109.2 → easycoder-250110.1}/doc/core/keywords/truncate.md +0 -0
  88. {easycoder-250109.2 → easycoder-250110.1}/doc/core/keywords/unlock.md +0 -0
  89. {easycoder-250109.2 → easycoder-250110.1}/doc/core/keywords/variable.md +0 -0
  90. {easycoder-250109.2 → easycoder-250110.1}/doc/core/keywords/wait.md +0 -0
  91. {easycoder-250109.2 → easycoder-250110.1}/doc/core/keywords/while.md +0 -0
  92. {easycoder-250109.2 → easycoder-250110.1}/doc/core/keywords/write.md +0 -0
  93. {easycoder-250109.2 → easycoder-250110.1}/doc/core/values/arg.md +0 -0
  94. {easycoder-250109.2 → easycoder-250110.1}/doc/core/values/args.md +0 -0
  95. {easycoder-250109.2 → easycoder-250110.1}/doc/core/values/cos.md +0 -0
  96. {easycoder-250109.2 → easycoder-250110.1}/doc/core/values/datime.md +0 -0
  97. {easycoder-250109.2 → easycoder-250110.1}/doc/core/values/decode.md +0 -0
  98. {easycoder-250109.2 → easycoder-250110.1}/doc/core/values/element.md +0 -0
  99. {easycoder-250109.2 → easycoder-250110.1}/doc/core/values/elements.md +0 -0
  100. {easycoder-250109.2 → easycoder-250110.1}/doc/core/values/empty.md +0 -0
  101. {easycoder-250109.2 → easycoder-250110.1}/doc/core/values/encode.md +0 -0
  102. {easycoder-250109.2 → easycoder-250110.1}/doc/core/values/error.md +0 -0
  103. {easycoder-250109.2 → easycoder-250110.1}/doc/core/values/files.md +0 -0
  104. {easycoder-250109.2 → easycoder-250110.1}/doc/core/values/float.md +0 -0
  105. {easycoder-250109.2 → easycoder-250110.1}/doc/core/values/from.md +0 -0
  106. {easycoder-250109.2 → easycoder-250110.1}/doc/core/values/hash.md +0 -0
  107. {easycoder-250109.2 → easycoder-250110.1}/doc/core/values/index.md +0 -0
  108. {easycoder-250109.2 → easycoder-250110.1}/doc/core/values/integer.md +0 -0
  109. {easycoder-250109.2 → easycoder-250110.1}/doc/core/values/json.md +0 -0
  110. {easycoder-250109.2 → easycoder-250110.1}/doc/core/values/keys.md +0 -0
  111. {easycoder-250109.2 → easycoder-250110.1}/doc/core/values/left.md +0 -0
  112. {easycoder-250109.2 → easycoder-250110.1}/doc/core/values/length.md +0 -0
  113. {easycoder-250109.2 → easycoder-250110.1}/doc/core/values/lowercase.md +0 -0
  114. {easycoder-250109.2 → easycoder-250110.1}/doc/core/values/memory.md +0 -0
  115. {easycoder-250109.2 → easycoder-250110.1}/doc/core/values/modification.md +0 -0
  116. {easycoder-250109.2 → easycoder-250110.1}/doc/core/values/modulo.md +0 -0
  117. {easycoder-250109.2 → easycoder-250110.1}/doc/core/values/newline.md +0 -0
  118. {easycoder-250109.2 → easycoder-250110.1}/doc/core/values/now.md +0 -0
  119. {easycoder-250109.2 → easycoder-250110.1}/doc/core/values/position.md +0 -0
  120. {easycoder-250109.2 → easycoder-250110.1}/doc/core/values/property.md +0 -0
  121. {easycoder-250109.2 → easycoder-250110.1}/doc/core/values/random.md +0 -0
  122. {easycoder-250109.2 → easycoder-250110.1}/doc/core/values/right.md +0 -0
  123. {easycoder-250109.2 → easycoder-250110.1}/doc/core/values/sin.md +0 -0
  124. {easycoder-250109.2 → easycoder-250110.1}/doc/core/values/stringify.md +0 -0
  125. {easycoder-250109.2 → easycoder-250110.1}/doc/core/values/tab.md +0 -0
  126. {easycoder-250109.2 → easycoder-250110.1}/doc/core/values/tan.md +0 -0
  127. {easycoder-250109.2 → easycoder-250110.1}/doc/core/values/timestamp.md +0 -0
  128. {easycoder-250109.2 → easycoder-250110.1}/doc/core/values/today.md +0 -0
  129. {easycoder-250109.2 → easycoder-250110.1}/doc/core/values/trim.md +0 -0
  130. {easycoder-250109.2 → easycoder-250110.1}/doc/core/values/type.md +0 -0
  131. {easycoder-250109.2 → easycoder-250110.1}/doc/core/values/uppercase.md +0 -0
  132. {easycoder-250109.2 → easycoder-250110.1}/doc/core/values/value.md +0 -0
  133. {easycoder-250109.2 → easycoder-250110.1}/doc/core/values/weekday.md +0 -0
  134. {easycoder-250109.2 → easycoder-250110.1}/doc/graphics/README.md +0 -0
  135. {easycoder-250109.2 → easycoder-250110.1}/doc/graphics/keywords/attach.md +0 -0
  136. {easycoder-250109.2 → easycoder-250110.1}/doc/graphics/keywords/close.md +0 -0
  137. {easycoder-250109.2 → easycoder-250110.1}/doc/graphics/keywords/create.md +0 -0
  138. {easycoder-250109.2 → easycoder-250110.1}/doc/graphics/keywords/ellipse.md +0 -0
  139. {easycoder-250109.2 → easycoder-250110.1}/doc/graphics/keywords/image.md +0 -0
  140. {easycoder-250109.2 → easycoder-250110.1}/doc/graphics/keywords/move.md +0 -0
  141. {easycoder-250109.2 → easycoder-250110.1}/doc/graphics/keywords/on.md +0 -0
  142. {easycoder-250109.2 → easycoder-250110.1}/doc/graphics/keywords/rectangle.md +0 -0
  143. {easycoder-250109.2 → easycoder-250110.1}/doc/graphics/keywords/render.md +0 -0
  144. {easycoder-250109.2 → easycoder-250110.1}/doc/graphics/keywords/run.md +0 -0
  145. {easycoder-250109.2 → easycoder-250110.1}/doc/graphics/keywords/set.md +0 -0
  146. {easycoder-250109.2 → easycoder-250110.1}/doc/graphics/keywords/text.md +0 -0
  147. {easycoder-250109.2 → easycoder-250110.1}/doc/graphics/values/attribute.md +0 -0
  148. {easycoder-250109.2 → easycoder-250110.1}/doc/graphics/values/window.md +0 -0
  149. {easycoder-250109.2 → easycoder-250110.1}/easycoder/README.md +0 -0
  150. {easycoder-250109.2 → easycoder-250110.1}/easycoder/ec.py +0 -0
  151. {easycoder-250109.2 → easycoder-250110.1}/easycoder/ec_classes.py +0 -0
  152. {easycoder-250109.2 → easycoder-250110.1}/easycoder/ec_compiler.py +0 -0
  153. {easycoder-250109.2 → easycoder-250110.1}/easycoder/ec_condition.py +0 -0
  154. {easycoder-250109.2 → easycoder-250110.1}/easycoder/ec_core.py +0 -0
  155. {easycoder-250109.2 → easycoder-250110.1}/easycoder/ec_graphics.py +0 -0
  156. {easycoder-250109.2 → easycoder-250110.1}/easycoder/ec_handler.py +0 -0
  157. {easycoder-250109.2 → easycoder-250110.1}/easycoder/ec_program.py +0 -0
  158. {easycoder-250109.2 → easycoder-250110.1}/easycoder/ec_timestamp.py +0 -0
  159. {easycoder-250109.2 → easycoder-250110.1}/easycoder/ec_value.py +0 -0
  160. {easycoder-250109.2 → easycoder-250110.1}/images/Semoigo Dawn.jpg +0 -0
  161. {easycoder-250109.2 → easycoder-250110.1}/json/graphics-demo.json +0 -0
  162. {easycoder-250109.2 → easycoder-250110.1}/plugins/ec_p100.py +0 -0
  163. {easycoder-250109.2 → easycoder-250110.1}/plugins/example.py +0 -0
  164. {easycoder-250109.2 → easycoder-250110.1}/pyproject.toml +0 -0
  165. {easycoder-250109.2 → easycoder-250110.1}/scripts/README.md +0 -0
  166. {easycoder-250109.2 → easycoder-250110.1}/scripts/benchmark.ecs +0 -0
  167. {easycoder-250109.2 → easycoder-250110.1}/scripts/fizzbuzz.ecs +0 -0
  168. {easycoder-250109.2 → easycoder-250110.1}/scripts/graphics-demo.ecg +0 -0
  169. {easycoder-250109.2 → easycoder-250110.1}/scripts/hello.ecs +0 -0
  170. {easycoder-250109.2 → easycoder-250110.1}/scripts/points.ecs +0 -0
  171. {easycoder-250109.2 → easycoder-250110.1}/scripts/tests.ecs +0 -0
  172. {easycoder-250109.2 → easycoder-250110.1}/scripts/wave.ecg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: easycoder
3
- Version: 250109.2
3
+ Version: 250110.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>
@@ -12,7 +12,8 @@ Project-URL: Home, https://github.com/easycoder/easycoder-py
12
12
  # Introduction
13
13
  **_EasyCoder_** is a high-level English-like scripting language suited for prototyping and rapid testing of ideas. It operates on the command line and a graphics module is under construction. This version of the language is written in Python and it acts as a fairly thin wrapper around Python functions, giving fast compilation and good runtime performance for general applications.
14
14
  <hr>
15
- For the JavaScript version of **_EasyCoder_**, which provides a full set of graphical features to run in a browser, please visit
15
+
16
+ There is also a JavaScript version of **_EasyCoder_**, which provides a full set of graphical features to run in a browser. For this, please visit
16
17
 
17
18
  Repository: [https://github.com/easycoder/easycoder.github.io](https://github.com/easycoder/easycoder.github.io)
18
19
  Website: [https://easycoder.github.io](https://easycoder.github.io)
@@ -23,6 +24,8 @@ Install **_EasyCoder_** in your Python environment:
23
24
  ```
24
25
  pip install easycoder
25
26
  ```
27
+ You may also need to install `pytz`, as some commands need it.
28
+
26
29
  Write a test script, 'hello.ecs', containing the following:
27
30
  ```
28
31
  print `Hello, world!`
@@ -30,28 +33,27 @@ print `Hello, world!`
30
33
  This is traditionally the first program to be written in virtually any language. To run it, use `easycoder hello.ecs`.
31
34
 
32
35
  The output will look like this (the version number will differ):
33
-
34
36
  ```
35
37
  EasyCoder version 250101.1
36
38
  Compiled <anon>: 1 lines (2 tokens) in 0 ms
37
39
  Run <anon>
38
40
  1-> Hello, world!
39
41
  ```
40
- It's conventional to add a program title to a script:
41
42
 
43
+ It's conventional to add a program title to a script:
42
44
  ```
43
45
  ! Test script
44
46
  script Test
45
47
  print `Hello, world!`
46
48
  ```
47
49
  The first line here is just a comment and has no effect on the running of the script. The second line gives the script a name, which is useful in debugging as it says which script was running. When run, the output is now
48
-
49
50
  ```
50
51
  EasyCoder version 250101.1
51
52
  Compiled Test: 3 lines (4 tokens) in 0 ms
52
53
  Run Test
53
54
  3-> Hello, world!
54
55
  ```
56
+
55
57
  As you might guess from the above, the print command shows the line in the script it was called from. This is very useful in tracking down debugging print commands in large scripts.
56
58
 
57
59
  Here in the repository is a folder called `scripts` containing some sample scripts:
@@ -65,13 +67,15 @@ Here in the repository is a folder called `scripts` containing some sample scrip
65
67
 
66
68
  Graphical scripts look much like any other script but their file names must use the extension `.ecg` to signal to **_EasyCoder_** that it needs to load the graphics module. Non-graphical applications can use any extension but `.ecs` is recommended. This allows the **_EasyCoder_** application to be used wherever Python is installed, in either a command-line or a graphical environment, but graphics will of course not be available in the former.
67
69
 
68
- A couple of demo graphical scripts are included in the `scripts` directory:
70
+ Some demo graphical scripts are included in the `scripts` directory:
69
71
 
70
72
  `graphics-demo.ecg` shows some of the elements that can be created, and demonstrates a variety of the graphical features of the language such as detecting when elements are clicked.
71
73
 
72
74
  `wave.ecg` is a "Mexican Wave" simulation.
73
75
 
74
- **_EasyCoder_** graphics are handled by a library module, `ec_renderer` that can be used outside of the **_EasyCoder_** environment, in other Python programs.
76
+ `keyboard.ecg` creates an on-screen keyboard (currently a 4-function calculator keypad) that responds to clicks on its keys. It uses a plugin module (see below) to add extra vocabulary and syntax to the language. This is currently under development so its features are likely to change. The intention is to support a wide range of keyboard styles with the minimum mount of coding. The plugin (`ec_keyword.py`) can be downloaded from the repository.
77
+
78
+ **_EasyCoder_** graphics are handled by a library module, `ec_renderer` that can be used outside of the **_EasyCoder_** environment, in other Python programs. The renderer works with JSON-formatted specifications of the itens to be displayed.
75
79
 
76
80
  ## Significant features
77
81
 
@@ -1,7 +1,8 @@
1
1
  # Introduction
2
2
  **_EasyCoder_** is a high-level English-like scripting language suited for prototyping and rapid testing of ideas. It operates on the command line and a graphics module is under construction. This version of the language is written in Python and it acts as a fairly thin wrapper around Python functions, giving fast compilation and good runtime performance for general applications.
3
3
  <hr>
4
- For the JavaScript version of **_EasyCoder_**, which provides a full set of graphical features to run in a browser, please visit
4
+
5
+ There is also a JavaScript version of **_EasyCoder_**, which provides a full set of graphical features to run in a browser. For this, please visit
5
6
 
6
7
  Repository: [https://github.com/easycoder/easycoder.github.io](https://github.com/easycoder/easycoder.github.io)
7
8
  Website: [https://easycoder.github.io](https://easycoder.github.io)
@@ -12,6 +13,8 @@ Install **_EasyCoder_** in your Python environment:
12
13
  ```
13
14
  pip install easycoder
14
15
  ```
16
+ You may also need to install `pytz`, as some commands need it.
17
+
15
18
  Write a test script, 'hello.ecs', containing the following:
16
19
  ```
17
20
  print `Hello, world!`
@@ -19,28 +22,27 @@ print `Hello, world!`
19
22
  This is traditionally the first program to be written in virtually any language. To run it, use `easycoder hello.ecs`.
20
23
 
21
24
  The output will look like this (the version number will differ):
22
-
23
25
  ```
24
26
  EasyCoder version 250101.1
25
27
  Compiled <anon>: 1 lines (2 tokens) in 0 ms
26
28
  Run <anon>
27
29
  1-> Hello, world!
28
30
  ```
29
- It's conventional to add a program title to a script:
30
31
 
32
+ It's conventional to add a program title to a script:
31
33
  ```
32
34
  ! Test script
33
35
  script Test
34
36
  print `Hello, world!`
35
37
  ```
36
38
  The first line here is just a comment and has no effect on the running of the script. The second line gives the script a name, which is useful in debugging as it says which script was running. When run, the output is now
37
-
38
39
  ```
39
40
  EasyCoder version 250101.1
40
41
  Compiled Test: 3 lines (4 tokens) in 0 ms
41
42
  Run Test
42
43
  3-> Hello, world!
43
44
  ```
45
+
44
46
  As you might guess from the above, the print command shows the line in the script it was called from. This is very useful in tracking down debugging print commands in large scripts.
45
47
 
46
48
  Here in the repository is a folder called `scripts` containing some sample scripts:
@@ -54,13 +56,15 @@ Here in the repository is a folder called `scripts` containing some sample scrip
54
56
 
55
57
  Graphical scripts look much like any other script but their file names must use the extension `.ecg` to signal to **_EasyCoder_** that it needs to load the graphics module. Non-graphical applications can use any extension but `.ecs` is recommended. This allows the **_EasyCoder_** application to be used wherever Python is installed, in either a command-line or a graphical environment, but graphics will of course not be available in the former.
56
58
 
57
- A couple of demo graphical scripts are included in the `scripts` directory:
59
+ Some demo graphical scripts are included in the `scripts` directory:
58
60
 
59
61
  `graphics-demo.ecg` shows some of the elements that can be created, and demonstrates a variety of the graphical features of the language such as detecting when elements are clicked.
60
62
 
61
63
  `wave.ecg` is a "Mexican Wave" simulation.
62
64
 
63
- **_EasyCoder_** graphics are handled by a library module, `ec_renderer` that can be used outside of the **_EasyCoder_** environment, in other Python programs.
65
+ `keyboard.ecg` creates an on-screen keyboard (currently a 4-function calculator keypad) that responds to clicks on its keys. It uses a plugin module (see below) to add extra vocabulary and syntax to the language. This is currently under development so its features are likely to change. The intention is to support a wide range of keyboard styles with the minimum mount of coding. The plugin (`ec_keyword.py`) can be downloaded from the repository.
66
+
67
+ **_EasyCoder_** graphics are handled by a library module, `ec_renderer` that can be used outside of the **_EasyCoder_** environment, in other Python programs. The renderer works with JSON-formatted specifications of the itens to be displayed.
64
68
 
65
69
  ## Significant features
66
70
 
@@ -10,4 +10,4 @@ from .ec_program import *
10
10
  from .ec_timestamp import *
11
11
  from .ec_value import *
12
12
 
13
- __version__ = "250109.2"
13
+ __version__ = "250110.1"
@@ -9,8 +9,6 @@ from kivy.clock import Clock
9
9
  from kivy.vector import Vector
10
10
  import math, os
11
11
 
12
- os.environ['KIVY_TEXT'] = 'pango'
13
-
14
12
  ec_ui = None
15
13
 
16
14
  def getUI():
@@ -108,53 +106,54 @@ class UI(Widget):
108
106
  self.zlist.append(element)
109
107
 
110
108
  def createElement(self, spec):
111
- with self.canvas:
112
- if hasattr(spec, 'fill'):
113
- c = spec.fill
114
- if isinstance(c, str):
115
- c = colormap[c]
116
- Color(c[0], c[1], c[2])
117
- else:
118
- Color(c[0]/255, c[1]/255, c[2]/255)
119
- size = (getActual(spec.size[0], spec), getActual(spec.size[1], spec))
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
132
- if spec.parent != None:
133
- pos = Vector(pos) + spec.parent.realpos
134
- if spec.type == 'ellipse':
135
- item = Ellipse(pos=pos, size=size)
136
- elif spec.type == 'rectangle':
137
- item = Rectangle(pos=pos, size=size)
138
- elif spec.type == 'text':
139
- if hasattr(spec, 'color'):
140
- c = spec.color
109
+ size = (getActual(spec.size[0], spec), getActual(spec.size[1], spec))
110
+ spec.realsize = size
111
+ # Deal with special case of 'center'
112
+ if spec.pos[0] == 'center':
113
+ left = getActual('50w', spec) - spec.realsize[0]/2
114
+ else:
115
+ left = getActual(spec.pos[0], spec)
116
+ if spec.pos[1] == 'center':
117
+ bottom = getActual('50h', spec) - spec.realsize[1]/2
118
+ else:
119
+ bottom = getActual(spec.pos[1], spec)
120
+ pos = (left, bottom)
121
+ spec.realpos = pos
122
+ if spec.parent != None:
123
+ pos = Vector(pos) + spec.parent.realpos
124
+ if spec.type != 'hotspot':
125
+ with self.canvas:
126
+ if hasattr(spec, 'fill'):
127
+ c = spec.fill
141
128
  if isinstance(c, str):
142
129
  c = colormap[c]
143
130
  Color(c[0], c[1], c[2])
144
131
  else:
145
132
  Color(c[0]/255, c[1]/255, c[2]/255)
146
- else:
147
- Color(1, 1, 1, 1)
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')
152
- label.refresh()
153
- item = Rectangle(pos=pos, size=size, texture=label.texture)
154
- elif spec.type == 'image':
155
- item = AsyncImage(pos=pos, size=size, source=spec.source)
156
- spec.item = item
157
- self.addElement(spec.id, spec)
133
+ if spec.type == 'ellipse':
134
+ item = Ellipse(pos=pos, size=size)
135
+ elif spec.type == 'rectangle':
136
+ item = Rectangle(pos=pos, size=size)
137
+ elif spec.type == 'text':
138
+ if hasattr(spec, 'color'):
139
+ c = spec.color
140
+ if isinstance(c, str):
141
+ c = colormap[c]
142
+ Color(c[0], c[1], c[2])
143
+ else:
144
+ Color(c[0]/255, c[1]/255, c[2]/255)
145
+ else:
146
+ Color(1, 1, 1, 1)
147
+ if self.font == None:
148
+ label = CoreLabel(text=spec.text, font_size=1000, halign='center', valign='center')
149
+ else:
150
+ label = CoreLabel(text=spec.text, font_context = None, font_name=self.font, font_size=1000, halign='center', valign='center')
151
+ label.refresh()
152
+ item = Rectangle(pos=pos, size=size, texture=label.texture)
153
+ elif spec.type == 'image':
154
+ item = AsyncImage(pos=pos, size=size, source=spec.source)
155
+ spec.item = item
156
+ self.addElement(spec.id, spec)
158
157
 
159
158
  def moveElementBy(self, id, dist):
160
159
  element = self.getElement(id)
@@ -185,19 +184,19 @@ class UI(Widget):
185
184
  for element in reversed(self.zlist):
186
185
  if element.actionCB != None:
187
186
  spec = element.spec
188
- pos = spec.realpos
187
+ pos = element.getPos()
189
188
  size = element.getSize()
190
189
  if spec.type == 'ellipse':
191
190
  a = int(size[0])/2
192
191
  b = int(size[1])/2
193
- ctr = (pos[0] + a, pos[1] +b)
192
+ ctr = (pos[0]+a, pos[1]+b)
194
193
  h = ctr[0]
195
194
  k = ctr[1]
196
195
  if (math.pow((x - h), 2) / math.pow(a, 2)) + (math.pow((y - k), 2) / math.pow(b, 2)) <= 1:
197
196
  element.actionCB(element.data)
198
197
  break
199
- elif spec.type in ['rectangle', 'text', 'image']:
200
- if tp[0] >= pos[0] and tp[0] < pos[0] + size[0] and tp[1] >= pos[1] and tp[1] < pos[1] + size[1]:
198
+ elif spec.type in ['rectangle', 'text', 'image', 'hotspot']:
199
+ if x >= pos[0] and x < pos[0] + size[0] and y >= pos[1] and y < pos[1] + size[1]:
201
200
  element.actionCB(element.data)
202
201
  break
203
202
 
@@ -58,16 +58,16 @@ class ScreenSpec():
58
58
 
59
59
  # Render a complete specification
60
60
  def renderSpec(self, spec, parent):
61
- if 'font' in spec: getUI().font = spec['font']
62
- else: getUI().font = None
63
- widgets = spec['#']
64
- # If a list, iterate it
65
- if isinstance(widgets, list):
66
- for widget in widgets:
67
- self.createWidget(spec[widget], parent)
68
- # Otherwise, process the single widget
61
+ if 'type' in spec: self.createWidget(spec, parent)
69
62
  else:
70
- self.createWidget(spec[widgets], parent)
63
+ widgets = spec['#']
64
+ # If a list, iterate it
65
+ if isinstance(widgets, list):
66
+ for widget in widgets:
67
+ self.createWidget(spec[widget], parent)
68
+ # Otherwise, process the single widget
69
+ else:
70
+ self.createWidget(spec[widgets], parent)
71
71
 
72
72
  # Render a graphic specification
73
73
  def render(self, spec, parent):
@@ -0,0 +1,191 @@
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
+ # on click/tap keyboard
23
+ def k_on(self, command):
24
+ token = self.nextToken()
25
+ if token in ['click', 'tap']:
26
+ if self.nextIs('keyboard'):
27
+ command['goto'] = self.getPC() + 2
28
+ self.add(command)
29
+ self.nextToken()
30
+ pcNext = self.getPC()
31
+ cmd = {}
32
+ cmd['domain'] = 'core'
33
+ cmd['lino'] = command['lino']
34
+ cmd['keyword'] = 'gotoPC'
35
+ cmd['goto'] = 0
36
+ cmd['debug'] = False
37
+ self.addCommand(cmd)
38
+ self.compileOne()
39
+ cmd = {}
40
+ cmd['domain'] = 'core'
41
+ cmd['lino'] = command['lino']
42
+ cmd['keyword'] = 'stop'
43
+ cmd['debug'] = False
44
+ self.addCommand(cmd)
45
+ # Fixup the link
46
+ self.getCommandAt(pcNext)['goto'] = self.getPC()
47
+ return True
48
+ return False
49
+
50
+ # Set a handler
51
+ def r_on(self, command):
52
+ self.onTap = command['goto']
53
+ return self.nextPC()
54
+
55
+ # Render a keyboard
56
+ # render keyboard {layout) at {left} {bottom} width {width}
57
+ def k_render(self, command):
58
+ if self.nextIs('keyboard'):
59
+ command['layout'] = self.nextValue()
60
+ x = getConstant('10w')
61
+ y = getConstant('10h')
62
+ w = getConstant('50w')
63
+ token = self.peek()
64
+ while token in ['at', 'width']:
65
+ self.nextToken()
66
+ if token == 'at':
67
+ x = self.nextValue()
68
+ y = self.nextValue()
69
+ elif token == 'width':
70
+ w = self.nextValue()
71
+ token = self.peek()
72
+ command['x'] = x
73
+ command['y'] = y
74
+ command['w'] = w
75
+ self.add(command)
76
+ return True
77
+ return False
78
+
79
+ def r_render(self, command):
80
+ self.keyboard = Object()
81
+ layout = self.getRuntimeValue(command['layout'])
82
+ with open(f'{layout}') as f: spec = f.read()
83
+ self.keyboard.layout = json.loads(spec)
84
+ layout = self.keyboard.layout[0]
85
+ x = getActual(self.getRuntimeValue(command['x']))
86
+ y = getActual(self.getRuntimeValue(command['y']))
87
+ w = getActual(self.getRuntimeValue(command['w']))
88
+ # Scan the keyboard layout to find the longest row
89
+ max = 0
90
+ rows = self.keyboard.layout[0]['rows']
91
+ nrows = len(rows)
92
+ for r in range(0, nrows):
93
+ row = rows[r]
94
+ # Count the number of buttons
95
+ count = 0.0
96
+ for n in range(0, len(row)):
97
+ key = row[n]
98
+ if 'span' in key: count += float(key['span'])
99
+ else: count += 1.0
100
+ if count > max: max = count
101
+ # Divide the keyboard width by the number of buttons to get the button size
102
+ # The basic key is always a square
103
+ bs = w / max
104
+ # Compute the keyboard height
105
+ h = bs * nrows
106
+ # Build the spec
107
+ spec = {}
108
+ spec['type'] = 'image'
109
+ spec['id'] = 'face'
110
+ spec['source'] = layout['face']
111
+ spec['left'] = x
112
+ spec['bottom'] = y
113
+ spec['width'] = w
114
+ spec['height'] = h
115
+ buttons = []
116
+ list = []
117
+ by = h
118
+ for r in range(0, nrows):
119
+ by -= bs
120
+ row = rows[r]
121
+ bx = 0
122
+ for b in range(0, len(row)):
123
+ button = row[b]
124
+ id = button['id']
125
+ if 'span' in button: span = float(button['span'])
126
+ else: span = 1.0
127
+ width = bs * span
128
+ button['type'] = 'hotspot'
129
+ button['left'] = bx
130
+ button['bottom'] = by
131
+ button['width'] = width
132
+ button['height'] = bs
133
+ button['parent'] = spec
134
+ buttons.append(button)
135
+ list.append(id)
136
+ bx += width
137
+ spec['#'] = list
138
+ for n in range(0, len(list)):
139
+ spec[list[n]] = buttons[n]
140
+ try:
141
+ ScreenSpec().render(spec, None)
142
+ except Exception as e:
143
+ RuntimeError(self.program, e)
144
+
145
+ # Add a callback to each button
146
+ def oncb(id):
147
+ self.key = id
148
+ if self.onTap != None:
149
+ self.program.run(self.onTap)
150
+ for b in range(0, len(list)):
151
+ id = list[b]
152
+ getUI().setOnClick(id, id, oncb)
153
+
154
+ return self.nextPC()
155
+
156
+ #############################################################################
157
+ # Modify a value or leave it unchanged.
158
+ def modifyValue(self, value):
159
+ return value
160
+
161
+ #############################################################################
162
+ # Compile a value in this domain
163
+ def compileValue(self):
164
+ value = {}
165
+ value['domain'] = self.getName()
166
+ if self.tokenIs('the'):
167
+ self.nextToken()
168
+ kwd = self.getToken()
169
+
170
+ if kwd == 'key':
171
+ value['type'] = kwd
172
+ return value
173
+ return None
174
+
175
+ #############################################################################
176
+ # Value handlers
177
+
178
+ def v_key(self, v):
179
+ value = {}
180
+ value['type'] = 'text'
181
+ value['content'] = self.key
182
+ return value
183
+
184
+ #############################################################################
185
+ # Compile a condition in this domain
186
+ def compileCondition(self):
187
+ condition = {}
188
+ return condition
189
+
190
+ #############################################################################
191
+ # Condition handlers
@@ -0,0 +1,64 @@
1
+ [
2
+ {
3
+ "face": "plugins/keyboards/4-function.png",
4
+ "rows":
5
+ [
6
+ [
7
+ {
8
+ "id": "1"
9
+ },
10
+ {
11
+ "id": "2"
12
+ },
13
+ {
14
+ "id": "3"
15
+ },
16
+ {
17
+ "id": "+"
18
+ }
19
+ ],
20
+ [
21
+ {
22
+ "id": "4"
23
+ },
24
+ {
25
+ "id": "5"
26
+ },
27
+ {
28
+ "id": "6"
29
+ },
30
+ {
31
+ "id": "-"
32
+ }
33
+ ],
34
+ [
35
+ {
36
+ "id": "7"
37
+ },
38
+ {
39
+ "id": "8"
40
+ },
41
+ {
42
+ "id": "9"
43
+ },
44
+ {
45
+ "id": "*"
46
+ }
47
+ ],
48
+ [
49
+ {
50
+ "id": "0"
51
+ },
52
+ {
53
+ "id": "C"
54
+ },
55
+ {
56
+ "id": "="
57
+ },
58
+ {
59
+ "id": "/"
60
+ }
61
+ ]
62
+ ]
63
+ }
64
+ ]