easycoder 241215.1__py2.py3-none-any.whl → 241227.1__py2.py3-none-any.whl

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

Potentially problematic release.


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

easycoder/ec_program.py CHANGED
@@ -11,23 +11,18 @@ class Program:
11
11
 
12
12
  def __init__(self, argv):
13
13
  print(f'EasyCoder version {version("easycoder")}')
14
- scriptName = None
15
14
  if len(argv) == 0:
16
15
  print('No script supplied')
17
16
  exit()
18
17
  self.classes=[Core]
19
- for n in range(len(argv)):
20
- arg = argv[n]
21
- if arg == '-g':
22
- from .ec_graphics import Graphics
23
- self.classes.append(Graphics)
24
- else:
25
- scriptName = arg
18
+ scriptName = argv[0]
19
+ if scriptName.endswith('.ecg'):
20
+ from .ec_graphics import Graphics
21
+ self.classes.append(Graphics)
26
22
 
27
23
  f = open(scriptName, 'r')
28
24
  source = f.read()
29
25
  f.close()
30
- self.argv = argv
31
26
  self.domains = []
32
27
  self.domainIndex = {}
33
28
  self.name = '<anon>'
@@ -43,6 +38,8 @@ class Program:
43
38
  self.condition = self.compiler.condition
44
39
  self.processClasses()
45
40
  self.queue = deque()
41
+ self.externalControl = False
42
+ self.quit = False
46
43
 
47
44
  def start(self):
48
45
  startCompile = time.time()
@@ -242,18 +239,17 @@ class Program:
242
239
  index += 1
243
240
  lino += 1
244
241
  return
242
+
243
+ def finish(self):
244
+ self.quit = True
245
245
 
246
- # Run the script
247
- def run(self, pc):
248
- # print(f'Run from {pc}')
249
- length = len(self.queue)
250
- self.queue.append(pc)
251
- if length > 0:
252
- return
253
-
246
+ # Flush the queue
247
+ def flush(self):
254
248
  while len(self.queue):
255
249
  self.pc = self.queue.popleft()
256
250
  while True:
251
+ if self.quit:
252
+ return
257
253
  command = self.code[self.pc]
258
254
  domainName = command['domain']
259
255
  if domainName == None:
@@ -272,11 +268,20 @@ class Program:
272
268
  self.pc = handler(command)
273
269
  try:
274
270
  if self.pc == 0 or self.pc >= len(self.code):
275
- return 0
271
+ break
276
272
  except:
277
- return 0
278
- if self.pc < 0:
279
- return -1
273
+ break
274
+
275
+ def setExternalControl(self):
276
+ self.externalControl = True
277
+
278
+ # Run the script
279
+ def run(self, pc):
280
+ length = len(self.queue)
281
+ self.queue.append(pc)
282
+ if not self.externalControl:
283
+ if length == 0:
284
+ return self.flush()
280
285
 
281
286
  def nonNumericValueError(self):
282
287
  FatalError(self.compiler, 'Non-numeric value')
@@ -322,10 +327,3 @@ class Program:
322
327
  if v1 < v2:
323
328
  return -1
324
329
  return 0
325
-
326
- # This is the program launcher
327
- def Main():
328
- if (len(sys.argv) > 1):
329
- Program(sys.argv[1:]).start()
330
- else:
331
- print('Syntax: easycoder <scriptname> [plugins]')
easycoder/ec_renderer.py CHANGED
@@ -1,330 +1,185 @@
1
- # renderer.py
2
-
3
- import sys, json
4
- import tkinter as tk
5
- from PIL import *
6
-
7
- elements = {}
8
- zlist = []
9
- images = {}
10
- onTick = None
11
-
12
- # Set the canvas
13
- def setCanvas(c):
14
- global canvas
15
- canvas = c
16
-
17
- # Get the canvas
18
- def getCanvas():
19
- global canvas
20
- return canvas
21
-
22
- def createScreen(values):
23
- global screen, canvas, screenLeft, screenTop, running
24
- running = True
25
- screen = tk.Tk()
26
- screen.title('EasyCoder')
27
- # screen.attributes('-fullscreen', True)
1
+ from kivy.app import App
2
+ from kivy.uix.widget import Widget
3
+ from kivy.uix.label import CoreLabel
4
+ from kivy.uix.image import AsyncImage
5
+ from kivy.core.window import Window
6
+ from kivy.graphics import Color, Ellipse, Rectangle
7
+ from kivy.utils import colormap
8
+ from kivy.clock import Clock
9
+ from kivy.vector import Vector
10
+ import math
11
+
12
+ class Object():
13
+ pass
14
+
15
+ class Element():
16
+
17
+ def __init__(self, type, spec):
18
+ self.type = type
19
+ self.spec = spec
20
+
21
+ def getType(self):
22
+ return self.spec.type
23
+
24
+ def getID(self):
25
+ return self.spec.id
26
+
27
+ def getPos(self):
28
+ spec = self.spec
29
+ pos = spec.pos
30
+ if spec.parent != None:
31
+ pos = Vector(pos) + spec.parent.pos
32
+ return pos
33
+
34
+ def setPos(self, pos):
35
+ self.spec.pos = pos
36
+ self.spec.item.pos = pos
37
+
38
+ # Called when the parent moves
39
+ def repos(self):
40
+ spec = self.spec
41
+ spec.item.pos = Vector(spec.pos) + spec.parent.pos
42
+
43
+ def getSize(self):
44
+ return self.spec.size
45
+
46
+ def setSize(self, size):
47
+ self.spec.size = size
48
+
49
+ def getChildren(self):
50
+ return self.spec.children
28
51
 
29
- # screen.overrideredirect(True)
30
- width = values['width']['content'] if 'width' in values else 600
31
- height = values['height']['content'] if 'height' in values else 800
32
- screenLeft = int((screen.winfo_screenwidth() - width) / 2)
33
- screenTop = int((screen.winfo_screenheight() - height) / 2)
34
- if 'left' in values:
35
- screenLeft = values['left']['content']
36
- if 'top' in values:
37
- screenTop = values['top']['content']
52
+ class UI(Widget):
38
53
 
39
- geometry = str(width) + 'x' + str(height) + '+' + str(screenLeft) + '+' + str(screenTop)
40
- screen.geometry(geometry)
54
+ elements = {}
55
+ zlist = []
41
56
 
42
- # Handle a click in the screen
43
- def onClick(event):
44
- global screenLeft, screenTop, zlist
45
- x = event.x
46
- y = event.y
47
- # print('Clicked at : '+ str(x) +","+ str(y))
48
- for i in range(1, len(zlist) + 1):
49
- element = zlist[-i]
50
- id = list(element)[0]
51
- values = element[id]
52
- x1 = values['left']
53
- x2 = x1 + values['width']
54
- y1 = values['top']
55
- y2 = y1 + values['height']
56
- if x >= x1 and x < x2 and y >= y1 and y < y2:
57
- if id in elements:
58
- element = elements[id]
59
- if 'cb' in element:
60
- element['cb']()
61
- break
57
+ def getElement(self, id):
58
+ if id in self.elements.keys():
59
+ return self.elements[id]
60
+ return None
61
+
62
+ def addElement(self, id, spec):
63
+ if id in self.elements.keys():
64
+ raise(Exception(f'Element {id} already exists'))
65
+ element = Element(type, spec)
66
+ element.cb = None
67
+ self.elements[id] = element
68
+ self.zlist.append(element)
69
+
70
+ def createElement(self, spec):
71
+ with self.canvas:
72
+ if hasattr(spec, 'fill'):
73
+ c = spec.fill
74
+ if isinstance(c, str):
75
+ c = colormap[c]
76
+ Color(c[0], c[1], c[2])
62
77
  else:
63
- RuntimeError(None, f'Element \'{id}\' does not exist')
64
-
65
- screen.bind('<Button-1>', onClick)
66
-
67
- fill = values['fill']['content'] if 'fill' in values else 'white'
68
- canvas = tk.Canvas(master=screen, width=width, height=height, bg=fill)
69
- canvas.place(x=0, y=0)
70
- setCanvas(canvas)
71
-
72
- # Close the screen
73
- def closeScreen():
74
- global screen
75
- screen.destroy()
76
-
77
- # Set up a click handler in an element
78
- def setOnClick(id, cb):
79
- global elements
80
- if id in elements:
81
- elements[id]['cb'] = cb
82
- else:
83
- RuntimeError(None, f'Element \'{id}\' does not exist')
84
- return
85
-
86
- # Set up the tick handler
87
- def setOnTick(cb):
88
- global onTick
89
- onTick = cb
90
-
91
- # Show the screen and issue tick callbacks
92
- def showScreen():
93
- global screen, onTick
94
- def afterCB(screen):
95
- if onTick != None:
96
- onTick()
97
- screen.after(100, lambda: afterCB(screen))
98
- screen.after(1000, lambda: afterCB(screen))
99
- screen.mainloop()
100
- sys.exit()
101
-
102
- # Render a graphic specification
103
- def render(spec, parent):
104
- global elements
105
-
106
- def getValue(args, item):
107
- if item in args:
108
- if type(item) == int:
109
- return item
110
- return args[item]
111
- return item
112
-
113
- def renderIntoRectangle(widgetType, values, offset, args):
114
- global zlist
115
- left = getValue(args, values['left']) if 'left' in values else 10
116
- top = getValue(args, values['top']) if 'top' in values else 10
117
- left = offset['dx'] + left
118
- top = offset['dy'] + top
119
- width = getValue(args, values['width']) if 'width' in values else 100
120
- height = getValue(args, values['height']) if 'height' in values else 100
121
- right = left + width
122
- bottom = top + height
123
- fill = values['fill'] if 'fill' in values else None
124
- outline = values['outline'] if 'outline' in values else None
125
- if outline != None:
126
- outlineWidth = getValue(args, values['outlineWidth']) if 'outlineWidth' in values else 1
127
- else:
128
- outlineWidth = 0
129
- if widgetType == 'rectangle':
130
- widgetId = getCanvas().create_rectangle(left, top, right, bottom, fill=fill, outline=outline, width=outlineWidth)
131
- elif widgetType == 'ellipse':
132
- widgetId = getCanvas().create_oval(left, top, right, bottom, fill=fill, outline=outline, width=outlineWidth)
133
- else:
134
- return f'Unknown widget type \'{widgetType}\''
135
- if 'name' in values:
136
- widgetName = getValue(args, values['name'])
137
- else:
138
- widgetName = None
139
- widgetSpec = {
140
- "type": widgetType,
141
- "name": widgetName,
142
- "id": widgetId,
143
- "left": left,
144
- "top": top,
145
- "width": width,
146
- "height": height,
147
- "children": []
148
- }
149
- elements[widgetName] = widgetSpec
150
- zlist.append({widgetName: widgetSpec})
151
- if '#' in values:
152
- children = values['#']
153
- if type(children) == list:
154
- for item in children:
155
- if item in values:
156
- child = values[item]
157
- childSpec = renderWidget(child, {'dx': left, 'dy': top}, args)
158
- widgetSpec['children'].append(childSpec['name'])
159
- else:
160
- child = values[children]
161
- childSpec = renderWidget(child, {'dx': left, 'dy': top}, args)
162
- widgetSpec['children'].append(childSpec['name'])
163
- return widgetSpec
164
-
165
- def renderText(values, offset, args):
166
- left = getValue(args, values['left']) if 'left' in values else 10
167
- top = getValue(args, values['top']) if 'top' in values else 10
168
- left = offset['dx'] + left
169
- top = offset['dy'] + top
170
- width = getValue(args, values['width']) if 'width' in values else 100
171
- height = getValue(args, values['height']) if 'height' in values else 100
172
- right = left + width
173
- bottom = top + height
174
- shape = getValue(args, values['shape']) if 'shape' in values else 'rectangle'
175
- fill = getValue(args, values['fill']) if 'fill' in values else None
176
- outline = getValue(args, values['outline']) if 'outline' in values else None
177
- outlineWidth = getValue(args, values['outlineWidth']) if 'outlineWidth' in values else 0 if outline == None else 1
178
- color = getValue(args, values['color']) if 'color' in values else None
179
- text = getValue(args, values['text']) if 'text' in values else ''
180
- fontFace = getValue(args, values['fontFace']) if 'fontFace' in values else 'Helvetica'
181
- fontWeight = getValue(args, values['fontWeight']) if 'fontWeight' in values else 'normal'
182
- fontSize = round(height*2/5) if shape == 'ellipse' else round(height*3/5)
183
- fontTop = top + height/2
184
- if 'fontSize' in values:
185
- fontSize = getValue(args, values['fontSize'])
186
- fontTop = top + round(fontSize * 5 / 4)
187
- adjust = round(fontSize/5) if shape == 'ellipse' else 0
188
- align = getValue(args, values['align']) if 'align' in values else 'center'
189
- if align == 'left':
190
- xoff = round(fontSize/5)
191
- anchor = 'w'
192
- elif align == 'right':
193
- xoff = width - round(fontSize/5)
194
- anchor = 'e'
195
- else:
196
- xoff = width/2
197
- anchor = 'center'
198
- if xoff < 3:
199
- xoff = 3
200
- if shape == 'ellipse':
201
- containerId = getCanvas().create_oval(left, top, right, bottom, fill=fill, outline=outline, width=outlineWidth)
202
- else:
203
- containerId = getCanvas().create_rectangle(left, top, right, bottom, fill=fill, outline=outline, width=outlineWidth)
204
- textId = canvas.create_text(left + xoff, fontTop + adjust, fill=color, font=f'"{fontFace}" {fontSize} {fontWeight}', text=text, anchor=anchor)
205
- if 'name' in values:
206
- widgetName = getValue(args, values['name'])
207
- else:
208
- widgetName = None
209
- widgetSpec = {
210
- "type": "text",
211
- "name": widgetName,
212
- "id": textId,
213
- "containerId": containerId,
214
- "left": left,
215
- "top": top,
216
- "width": width,
217
- "height": height
218
- }
219
- elements[widgetName] = widgetSpec
220
- zlist.append({widgetName: widgetSpec})
221
- return widgetSpec
222
-
223
- def renderImage(values, offset, args):
224
- global images
225
- left = getValue(args, values['left']) if 'left' in values else 10
226
- top = getValue(args, values['top']) if 'top' in values else 10
227
- left = offset['dx'] + left
228
- top = offset['dy'] + top
229
- width = getValue(args, values['width']) if 'width' in values else 100
230
- height = getValue(args, values['height']) if 'height' in values else 100
231
- right = left + width
232
- bottom = top + height
233
- src = getValue(args, values['src']) if 'src' in values else None
234
- containerId = getCanvas().create_rectangle(left, top, right, bottom, width=0)
235
- if 'name' in values:
236
- widgetName = values['name']
237
- else:
238
- widgetName = None
239
- widgetSpec = {
240
- "type": "image",
241
- "nme": widgetName,
242
- "id": containerId,
243
- "left": left,
244
- "top": top,
245
- "width": width,
246
- "height": height
247
- }
248
- elements[widgetName] = widgetSpec
249
- zlist.append({widgetName: widgetSpec})
250
- if src == None:
251
- raise(Exception(f'No image source given for \'{id}\''))
252
- img = (Image.open(src))
253
- resized_image= img.resize((width, height), Image.ANTIALIAS)
254
- new_image= ImageTk.PhotoImage(resized_image)
255
- imageid = getCanvas().create_image(left, top, anchor='nw', image=new_image)
256
- images[containerId] = {'id': imageid, "image": new_image}
257
- return widgetSpec
258
-
259
- # Create a canvas or render a widget
260
- def renderWidget(widget, offset, args):
261
- widgetType = widget['type']
262
- if widgetType in ['rectangle', 'ellipse']:
263
- return renderIntoRectangle(widgetType, widget, offset, args)
264
- elif widgetType == 'text':
265
- return renderText(widget, offset, args)
266
- elif widgetType == 'image':
267
- return renderImage(widget, offset, args)
268
-
269
- # Render a complete specification
270
- def renderSpec(spec, offset, args):
271
- widgets = spec['#']
272
- # If a list, iterate it
273
- if type(widgets) is list:
274
- for widget in widgets:
275
- renderWidget(spec[widget], offset, args)
276
- # Otherwise, process the single widget
78
+ Color(c[0]/255, c[1]/255, c[2]/255)
79
+ pos = spec.pos
80
+ if spec.parent != None:
81
+ pos = Vector(pos) + spec.parent.pos
82
+ if spec.type == 'ellipse':
83
+ item = Ellipse(pos=pos, size=spec.size)
84
+ elif spec.type == 'rectangle':
85
+ item = Rectangle(pos=pos, size=spec.size)
86
+ elif spec.type == 'text':
87
+ if hasattr(spec, 'color'):
88
+ c = spec.color
89
+ if isinstance(c, str):
90
+ c = colormap[c]
91
+ Color(c[0], c[1], c[2])
92
+ else:
93
+ Color(c[0]/255, c[1]/255, c[2]/255)
94
+ else:
95
+ Color(1, 1, 1, 1)
96
+ label = CoreLabel(text=spec.text, font_size=1000, halign='center', valign='center')
97
+ label.refresh()
98
+ text = label.texture
99
+ item = Rectangle(pos=spec.pos, size=spec.size, texture=text)
100
+ elif spec.type == 'image':
101
+ item = AsyncImage(pos=spec.pos, size=spec.size, source=spec.source)
102
+ spec.item = item
103
+ self.addElement(spec.id, spec)
104
+
105
+ def moveElementBy(self, id, dist):
106
+ element = self.getElement(id)
107
+ if element != None:
108
+ element.setPos(Vector(element.getPos()) + dist)
109
+ for id in element.getChildren():
110
+ self.getElement(id).repos()
111
+ return
112
+
113
+ def moveElementTo(self, id, pos):
114
+ element = self.getElement(id)
115
+ if element != None:
116
+ self.moveElementBy(id, Vector(pos) - element.getPos())
117
+ return
118
+
119
+ def on_touch_down(self, touch):
120
+ tp = touch.pos
121
+ x = tp[0]
122
+ y = tp[1]
123
+ for element in reversed(self.zlist):
124
+ if element.cb != None:
125
+ spec = element.spec
126
+ pos = spec.pos
127
+ if spec.parent != None:
128
+ pos = Vector(pos) + spec.parent.pos
129
+ size = spec.size
130
+ if spec.type == 'ellipse':
131
+ a = size[0]/2
132
+ b = size[1]/2
133
+ ctr = (pos[0] + a, pos[1] +b)
134
+ h = ctr[0]
135
+ k = ctr[1]
136
+ if (math.pow((x - h), 2) / math.pow(a, 2)) + (math.pow((y - k), 2) / math.pow(b, 2)) <= 1:
137
+ element.cb()
138
+ break
139
+ elif spec.type in ['rectangle', 'text', 'image']:
140
+ if tp[0] >= pos[0] and tp[0] < pos[0] + size[0] and tp[1] >= pos[1] and tp[1] < pos[1] + size[1]:
141
+ element.cb()
142
+ break
143
+
144
+ def setOnClick(self, id, callback):
145
+ self.getElement(id).cb = callback
146
+
147
+ def getAttribute(self, id, attribute):
148
+ spec = self.getElement(id).spec
149
+ if attribute == 'left':
150
+ return spec.pos[0]
151
+ elif attribute == 'bottom':
152
+ return spec.pos[1]
153
+ elif attribute == 'width':
154
+ return spec.size[0]
155
+ elif attribute == 'height':
156
+ return spec.size[1]
277
157
  else:
278
- renderWidget(spec[widgets], offset, args)
279
-
280
- # Main entry point
281
- offset = {'dx': 0, 'dy': 0}
282
- if parent != screen:
283
- RuntimeError(None, 'Can\'t yet render into parent widget')
284
-
285
- # If it'a string, process it
286
- if type(spec) is str:
287
- renderSpec(json.loads(spec), offset, {})
158
+ raise Exception(f'Unknown attribute: {attribute}')
288
159
 
289
- # If it's a 'dict', extract the spec and the args
290
- if type(spec) is dict:
291
- args = spec['args']
292
- spec = json.loads(spec['spec'])
293
- renderSpec(spec, offset, args)
294
160
 
295
- # Get the widget whose name is given
296
- def getElement(name):
297
- global elements
298
- if name in elements:
299
- return elements[name]
300
- else:
301
- RuntimeError(None, f'Element \'{name}\' does not exist')
161
+ class Renderer(App):
302
162
 
303
- # Set the content of a text widget
304
- def setText(name, value):
305
- getCanvas().itemconfig(getElement(name)['id'], text=value)
306
-
307
- # Set the background of a rectangle or ellipse widget
308
- def setBackground(name, value):
309
- id = getElement(name)['id']
310
- getCanvas().itemconfig(getElement(name)['id'], fill=value)
163
+ def getUI(self):
164
+ return self.ui
311
165
 
312
- # Move an element by an amount
313
- def moveElement(name, dx, dy):
314
- element = getElement(name)
315
- getCanvas().move(element['id'], dx, dy)
316
- element['left'] += dx
317
- element['top'] += dy
318
- for childName in element['children']:
319
- element = getElement(childName)
320
- getCanvas().move(element['id'], dx, dy)
321
-
322
- # Move an element to a new location
323
- def moveElementTo(name, left, top):
324
- element = getElement(name)
325
- moveElement(name, left - element['left'], top - element['top'])
326
-
327
- # Get an attribute of an element
328
- def getAttribute(name, attribute):
329
- element = getElement(name)
330
- return element[attribute]
166
+ def request_close(self):
167
+ print('close window')
168
+ Window.close()
169
+
170
+ def flushQueue(self, dt):
171
+ self.flush()
172
+
173
+ def build(self):
174
+ Clock.schedule_interval(self.flushQueue, 0.05)
175
+ self.ui = UI()
176
+ return self.ui
177
+
178
+ def init(self, spec):
179
+ self.title = spec.title
180
+ self.flush = spec.flush
181
+ Window.size = spec.size
182
+ Window.left = spec.pos[0]
183
+ Window.top = spec.pos[1]
184
+ Window.clearcolor = spec.fill
185
+ Window.on_request_close=self.request_close