easycoder 241218.1__py2.py3-none-any.whl → 241231.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_renderer.py CHANGED
@@ -1,335 +1,245 @@
1
- # renderer.py
2
-
3
- import sys, json
4
- import tkinter as tk
5
- from PIL import Image, ImageTk
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 getRealPos(self):
28
+ spec = self.spec
29
+ pos = spec.realpos
30
+ if spec.parent != None:
31
+ pos = Vector(pos) + spec.parent.realpos
32
+ return pos
33
+
34
+ def getPos(self):
35
+ spec = self.spec
36
+ pos = spec.pos
37
+ if spec.parent != None:
38
+ pos = Vector(pos) + spec.parent.pos
39
+ return pos
40
+
41
+ def setPos(self, pos):
42
+ self.spec.realpos = pos
43
+ self.spec.item.pos = pos
44
+
45
+ # Called when the parent moves
46
+ def repos(self):
47
+ spec = self.spec
48
+ spec.item.pos = Vector(spec.realpos) + spec.parent.realpos
49
+
50
+ def getRealSize(self):
51
+ return self.spec.realsize
52
+
53
+ def getSize(self):
54
+ return self.spec.size
55
+
56
+ def setSize(self, size):
57
+ self.spec.size = size
58
+
59
+ def getChildren(self):
60
+ return self.spec.children
28
61
 
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']
62
+ class UI(Widget):
38
63
 
39
- geometry = str(width) + 'x' + str(height) + '+' + str(screenLeft) + '+' + str(screenTop)
40
- screen.geometry(geometry)
64
+ elements = {}
65
+ zlist = []
41
66
 
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'] + getScreenLeft(values['parent'])
54
- y1 = values['top'] + getScreenTop(values['parent'])
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
67
+ def getElement(self, id):
68
+ if id in self.elements.keys():
69
+ return self.elements[id]
70
+ return None
71
+
72
+ def addElement(self, id, spec):
73
+ if id in self.elements.keys():
74
+ raise(Exception(f'Element {id} already exists'))
75
+ element = Element(type, spec)
76
+ element.cb = None
77
+ self.elements[id] = element
78
+ self.zlist.append(element)
79
+
80
+ def createElement(self, spec):
81
+ # Get a real position or size value
82
+ def getReal(val):
83
+ if isinstance(val, str):
84
+ c = val[-1]
85
+ if c in ['w', 'h']:
86
+ val = int(val[0:len(val)-1])
87
+ if spec.parent == None:
88
+ if c == 'w':
89
+ n = Window.width
90
+ else:
91
+ n = Window.height
92
+ else:
93
+ if c == 'w':
94
+ n = spec.parent.realsize[0]
95
+ else:
96
+ n = spec.parent.realsize[1]
97
+ return val * n / 100
98
+ return val
99
+
100
+ with self.canvas:
101
+ if hasattr(spec, 'fill'):
102
+ c = spec.fill
103
+ if isinstance(c, str):
104
+ c = colormap[c]
105
+ Color(c[0], c[1], c[2])
62
106
  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, parent, args):
114
- global zlist
115
- left = getValue(args, values['left']) if 'left' in values else 10
116
- screenLeft = left + getScreenLeft(parent)
117
- top = getValue(args, values['top']) if 'top' in values else 10
118
- screenTop = top + getScreenTop(parent)
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 = screenLeft + width
122
- bottom = screenTop + 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(screenLeft, screenTop, right, bottom, fill=fill, outline=outline, width=outlineWidth)
131
- elif widgetType == 'ellipse':
132
- widgetId = getCanvas().create_oval(screenLeft, screenTop, 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
- "parent": parent,
148
- "children": []
149
- }
150
- elements[widgetName] = widgetSpec
151
- zlist.append({widgetName: widgetSpec})
152
- if '#' in values:
153
- children = values['#']
154
- if type(children) == list:
155
- for item in children:
156
- if item in values:
157
- child = values[item]
158
- childSpec = renderWidget(child, widgetSpec, args)
159
- widgetSpec['children'].append(childSpec['name'])
160
- else:
161
- child = values[children]
162
- childSpec = renderWidget(child, widgetSpec, args)
163
- widgetSpec['children'].append(childSpec['name'])
164
- return widgetSpec
165
-
166
- def renderText(values, parent, args):
167
- left = getValue(args, values['left']) if 'left' in values else 10
168
- screenLeft = left + getScreenLeft(parent)
169
- top = getValue(args, values['top']) if 'top' in values else 10
170
- screenTop = top + getScreenTop(parent)
171
- width = getValue(args, values['width']) if 'width' in values else 100
172
- height = getValue(args, values['height']) if 'height' in values else 100
173
- shape = getValue(args, values['shape']) if 'shape' in values else 'rectangle'
174
- outline = getValue(args, values['outline']) if 'outline' in values else None
175
- color = getValue(args, values['color']) if 'color' in values else None
176
- text = getValue(args, values['text']) if 'text' in values else ''
177
- fontFace = getValue(args, values['fontFace']) if 'fontFace' in values else 'Helvetica'
178
- fontWeight = getValue(args, values['fontWeight']) if 'fontWeight' in values else 'normal'
179
- fontTop = int(round(screenTop + height/2))
180
- if 'fontSize' in values:
181
- fontSize = getValue(args, values['fontSize'])
182
- fontTop = int(round(screenTop + height/2 - fontSize/4))
183
- else:
184
- fontSize = int(round(height*2/5) if shape == 'ellipse' else round(height*3/5))
185
- fontTop -= int(round(screenTop + height/2 - fontSize/5))
186
- adjust = int(round(fontSize/5)) if shape == 'ellipse' else 0
187
- align = getValue(args, values['align']) if 'align' in values else 'center'
188
- if align == 'left':
189
- xoff = int(round(fontSize/5))
190
- anchor = 'w'
191
- elif align == 'right':
192
- xoff = width - int(round(fontSize/5))
193
- anchor = 'e'
194
- else:
195
- xoff = int(round(width/2))
196
- anchor = 'center'
197
- if xoff < 3:
198
- xoff = 3
199
- xoff -= int(round(fontSize/4))
200
- textId = canvas.create_text(screenLeft + xoff, fontTop + adjust, fill=color, font=f'"{fontFace}" {fontSize} {fontWeight}', text=text, anchor=anchor)
201
- if 'name' in values:
202
- widgetName = getValue(args, values['name'])
107
+ Color(c[0]/255, c[1]/255, c[2]/255)
108
+ pos = (getReal(spec.pos[0]), getReal(spec.pos[1]))
109
+ spec.realpos = pos
110
+ size = (getReal(spec.size[0]), getReal(spec.size[1]))
111
+ spec.realsize = size
112
+ if spec.parent != None:
113
+ pos = Vector(pos) + spec.parent.realpos
114
+ if spec.type == 'ellipse':
115
+ item = Ellipse(pos=pos, size=size)
116
+ elif spec.type == 'rectangle':
117
+ item = Rectangle(pos=pos, size=size)
118
+ elif spec.type == 'text':
119
+ if hasattr(spec, 'color'):
120
+ c = spec.color
121
+ if isinstance(c, str):
122
+ c = colormap[c]
123
+ Color(c[0], c[1], c[2])
124
+ else:
125
+ Color(c[0]/255, c[1]/255, c[2]/255)
126
+ else:
127
+ Color(1, 1, 1, 1)
128
+ label = CoreLabel(text=spec.text, font_size=1000, halign='center', valign='center')
129
+ label.refresh()
130
+ text = label.texture
131
+ item = Rectangle(pos=pos, size=size, texture=text)
132
+ elif spec.type == 'image':
133
+ item = AsyncImage(pos=pos, size=size, source=spec.source)
134
+ spec.item = item
135
+ self.addElement(spec.id, spec)
136
+
137
+ def moveElementBy(self, id, dist):
138
+ element = self.getElement(id)
139
+ if element != None:
140
+ element.setPos(Vector(element.getRealPos()) + dist)
141
+ for id in element.getChildren():
142
+ self.getElement(id).repos()
143
+ return
144
+
145
+ def moveElementTo(self, id, pos):
146
+ element = self.getElement(id)
147
+ if element != None:
148
+ self.moveElementBy(id, Vector(pos) - element.getRealPos())
149
+ return
150
+
151
+ def on_touch_down(self, touch):
152
+ tp = touch.pos
153
+ x = tp[0]
154
+ y = tp[1]
155
+ for element in reversed(self.zlist):
156
+ if element.cb != None:
157
+ spec = element.spec
158
+ pos = self.getRealPos()
159
+ if spec.parent != None:
160
+ pos = Vector(pos) + spec.parent.getRealPos()
161
+ size = spec.size
162
+ if spec.type == 'ellipse':
163
+ a = size[0]/2
164
+ b = size[1]/2
165
+ ctr = (pos[0] + a, pos[1] +b)
166
+ h = ctr[0]
167
+ k = ctr[1]
168
+ if (math.pow((x - h), 2) / math.pow(a, 2)) + (math.pow((y - k), 2) / math.pow(b, 2)) <= 1:
169
+ element.cb()
170
+ break
171
+ elif spec.type in ['rectangle', 'text', 'image']:
172
+ if tp[0] >= pos[0] and tp[0] < pos[0] + size[0] and tp[1] >= pos[1] and tp[1] < pos[1] + size[1]:
173
+ element.cb()
174
+ break
175
+
176
+ def setOnClick(self, id, callback):
177
+ self.getElement(id).cb = callback
178
+
179
+ def getWindowAttribute(self, attribute):
180
+ if attribute == 'left':
181
+ return Window.left
182
+ elif attribute == 'top':
183
+ return Window.top
184
+ elif attribute == 'width':
185
+ return Window.size[0]
186
+ elif attribute == 'height':
187
+ return Window.size[1]
203
188
  else:
204
- widgetName = None
205
- widgetSpec = {
206
- "type": "text",
207
- "name": widgetName,
208
- "id": textId,
209
- "left": left,
210
- "top": top,
211
- "width": width,
212
- "height": height,
213
- "parent": parent
214
- }
215
- elements[widgetName] = widgetSpec
216
- zlist.append({widgetName: widgetSpec})
217
- return widgetSpec
218
-
219
- def renderImage(values, parent, args):
220
- global images
221
- left = getValue(args, values['left']) if 'left' in values else 10
222
- screenLeft = left + getScreenLeft(parent)
223
- top = getValue(args, values['top']) if 'top' in values else 10
224
- screenTop = top + getScreenTop(parent)
225
- width = getValue(args, values['width']) if 'width' in values else 100
226
- source = getValue(args, values['source']) if 'source' in values else None
227
- if 'name' in values:
228
- widgetName = values['name']
189
+ raise Exception(f'Unknown attribute: {attribute}')
190
+
191
+ def getAttribute(self, id, attribute):
192
+ spec = self.getElement(id).spec
193
+ if attribute == 'left':
194
+ return spec.realpos[0]
195
+ elif attribute == 'bottom':
196
+ return spec.realpos[1]
197
+ elif attribute == 'width':
198
+ return spec.realsize[0]
199
+ elif attribute == 'height':
200
+ return spec.realsize[1]
229
201
  else:
230
- widgetName = None
231
- if source == None:
232
- raise(Exception(f'No image source given for \'{id}\''))
233
- img = (Image.open(source))
234
- height = int(round(img.height * width / img.width))
235
- resized_image= img.resize((width, height), Image.LANCZOS)
236
- new_image= ImageTk.PhotoImage(resized_image)
237
- imageid = getCanvas().create_image(screenLeft, screenTop, anchor='nw', image=new_image)
238
- images[widgetName] = {'id': imageid, "image": new_image}
239
- widgetSpec = {
240
- "type": "image",
241
- "nme": widgetName,
242
- "left": left,
243
- "top": top,
244
- "width": width,
245
- "height": height,
246
- "source": source,
247
- "parent": parent
248
- }
249
- elements[widgetName] = widgetSpec
250
- zlist.append({widgetName: widgetSpec})
251
- return widgetSpec
252
-
253
- # Create a canvas or render a widget
254
- def renderWidget(widget, parent, args):
255
- widgetType = widget['type']
256
- if widgetType in ['rectangle', 'ellipse']:
257
- return renderIntoRectangle(widgetType, widget, parent, args)
258
- elif widgetType == 'text':
259
- return renderText(widget, parent, args)
260
- elif widgetType == 'image':
261
- return renderImage(widget, parent, args)
262
-
263
- # Render a complete specification
264
- def renderSpec(spec, parent, args):
265
- widgets = spec['#']
266
- # If a list, iterate it
267
- if type(widgets) is list:
268
- for widget in widgets:
269
- renderWidget(spec[widget], parent, args)
270
- # Otherwise, process the single widget
202
+ raise Exception(f'Unknown attribute: {attribute}')
203
+
204
+ def setAttribute(self, id, attribute, value):
205
+ spec = self.getElement(id).spec
206
+ if attribute == 'left':
207
+ spec.realpos = (value, spec.realsize[0])
208
+ spec.item.pos = (value, spec.realsize[0])
209
+ elif attribute == 'bottom':
210
+ spec.realpos = (spec.realsize[0], value)
211
+ spec.item.pos = (spec.realsize[0], value)
212
+ elif attribute == 'width':
213
+ spec.realsize = (value, spec.realsize[0])
214
+ spec.item.size = (value, spec.realsize[0])
215
+ elif attribute == 'height':
216
+ spec.realsize = (spec.realsize[0], value)
217
+ spec.item.size = (spec.realsize[0], value)
271
218
  else:
272
- renderWidget(spec[widgets], parent, args)
219
+ raise Exception(f'Unknown attribute: {attribute}')
273
220
 
274
- # Main entry point
275
- if parent != screen:
276
- RuntimeError(None, 'Can\'t yet render into parent widget')
221
+ class Renderer(App):
277
222
 
278
- # If it'a string, process it
279
- if type(spec) is str:
280
- renderSpec(json.loads(spec), None, {})
281
-
282
- # If it's a 'dict', extract the spec and the args
283
- if type(spec) is dict:
284
- args = spec['args']
285
- spec = json.loads(spec['spec'])
286
- renderSpec(spec, None, args)
287
-
288
- # Get the widget whose name is given
289
- def getElement(name):
290
- global elements
291
- if name in elements:
292
- return elements[name]
293
- else:
294
- RuntimeError(None, f'Element \'{name}\' does not exist')
295
-
296
- # Set the content of a text widget
297
- def setText(name, value):
298
- getCanvas().itemconfig(getElement(name)['id'], text=value)
299
-
300
- # Set the background of a rectangle or ellipse widget
301
- def setBackground(name, value):
302
- id = getElement(name)['id']
303
- getCanvas().itemconfig(getElement(name)['id'], fill=value)
223
+ def getUI(self):
224
+ return self.ui
304
225
 
305
- # Move an element by an amount
306
- def moveElement(name, dx, dy):
307
- element = getElement(name)
308
- getCanvas().move(element['id'], dx, dy)
309
- element['left'] += dx
310
- element['top'] += dy
311
- for childName in element['children']:
312
- element = getElement(childName)
313
- getCanvas().move(element['id'], dx, dy)
314
-
315
- # Move an element to a new location
316
- def moveElementTo(name, left, top):
317
- element = getElement(name)
318
- moveElement(name, left - element['left'], top - element['top'])
319
-
320
- # Get an attribute of an element
321
- def getAttribute(name, attribute):
322
- element = getElement(name)
323
- return element[attribute]
324
-
325
- # Get the screen left position of an element
326
- def getScreenLeft(element):
327
- if element == None:
328
- return 0
329
- return element['left'] + getScreenLeft(element['parent'])
330
-
331
- # Get the screen top position of an element
332
- def getScreenTop(element):
333
- if element == None:
334
- return 0
335
- return element['top'] + getScreenTop(element['parent'])
226
+ def request_close(self):
227
+ print('close window')
228
+ Window.close()
229
+
230
+ def flushQueue(self, dt):
231
+ self.flush()
232
+
233
+ def build(self):
234
+ Clock.schedule_interval(self.flushQueue, 0.01)
235
+ self.ui = UI()
236
+ return self.ui
237
+
238
+ def init(self, spec):
239
+ self.title = spec.title
240
+ self.flush = spec.flush
241
+ Window.size = spec.size
242
+ Window.left = spec.pos[0]
243
+ Window.top = spec.pos[1]
244
+ Window.clearcolor = spec.fill
245
+ Window.on_request_close=self.request_close
@@ -0,0 +1,77 @@
1
+ # screenspec.py
2
+
3
+ from json import loads
4
+ from .ec_renderer import Object
5
+
6
+ class ScreenSpec():
7
+
8
+ # Get an attribute of an element
9
+ def getAttribute(self, id, attribute):
10
+ element = self.ui.getElement(id)
11
+ return element[attribute]
12
+
13
+ # Render a single widget
14
+ def createWidget(self, widget, parent):
15
+ spec = Object()
16
+ type = widget['type']
17
+ spec.type = type
18
+ spec.id = widget['id']
19
+ spec.pos = (widget['left'], widget['bottom'])
20
+ spec.size = (widget['width'], widget['height'])
21
+ if widget.get('fill') != None:
22
+ spec.fill = widget['fill']
23
+ if widget.get('text') != None:
24
+ spec.text = widget['text']
25
+ if widget.get('fontSize') != None:
26
+ spec.fontSize = widget['fontSize']
27
+ if widget.get('source') != None:
28
+ spec.source = widget['source']
29
+ if widget.get('color') != None:
30
+ spec.color = widget['color']
31
+ spec.parent = parent
32
+ spec.children = []
33
+ self.ui.createElement(spec)
34
+
35
+ if '#' in widget:
36
+ children = widget['#']
37
+ if isinstance(children, list):
38
+ for item in children:
39
+ if item in widget:
40
+ child = widget[item]
41
+ childSpec = self.createWidget(child, spec)
42
+ spec.children.append(childSpec.id)
43
+ else:
44
+ raise Exception(f'Child \'{item}\' is missing')
45
+ else:
46
+ child = widget[children]
47
+ childSpec = self.createWidget(child, spec)
48
+ spec.children.append(childSpec.id)
49
+
50
+ return spec
51
+
52
+ # Render a complete specification
53
+ def renderSpec(self, spec, parent):
54
+ widgets = spec['#']
55
+ # If a list, iterate it
56
+ if isinstance(widgets, list):
57
+ for widget in widgets:
58
+ self.createWidget(spec[widget], parent)
59
+ # Otherwise, process the single widget
60
+ else:
61
+ self.createWidget(spec[widgets], parent)
62
+
63
+ # Render a graphic specification
64
+ def render(self, spec, ui):
65
+ self.ui = ui
66
+
67
+ # If it'a string, process it
68
+ if isinstance(spec, str):
69
+ self.renderSpec(loads(spec), None)
70
+
71
+ # If it's a 'dict', extract the spec and the args
72
+ elif isinstance(spec, dict):
73
+ spec = loads(spec['spec'])
74
+ self.renderSpec(spec, None)
75
+
76
+ else:
77
+ raise Exception('Spec is an unknown type')