framework-lib 0.1.2__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.
@@ -0,0 +1,1470 @@
1
+ """
2
+ DOCUMENTATION for models.py:
3
+
4
+ ========================
5
+
6
+ GENERAL INFORMATION:
7
+
8
+ - ErrorForm is used for raising errors without crashes and to be friendly
9
+
10
+ - SpaceField, InputField, RedirectField, TextField: fields for your own models
11
+
12
+ - ErrorHelper is used for automatical type error checks
13
+
14
+ - ListErrorHelper is used for automatical list length checks
15
+
16
+ - check is used for checking user errors related to InputField
17
+
18
+ - Embedding is used for storing data about multiple fields and managing them
19
+
20
+ - CanvasEmbedding is an embedding that is used for Tkinter
21
+
22
+ - ImageField is used for displaying images with Tkinter
23
+
24
+ - TextFieldAdv is used for displaying text with Tkinter
25
+
26
+ - ButtonField is used for displaying button with Tkinter
27
+
28
+ - InputForm is used for displaying input with Tkinter
29
+
30
+ - BackgroundForm is used for displaying tiled images(e.g. backgrounds) with Tkinter
31
+
32
+ - GeometryField is used for displaying geometric shapes with Tkinter
33
+
34
+ - InteractiveUserErrorForm is used for displaying user errors with Tkinter
35
+
36
+ - Container is used for containing multiple Tkinter fields/forms and positioning them
37
+
38
+ - PygameEmbedding is an embedding that is used for Pygame
39
+
40
+ - ImageSprite is used for displaying sprites from images in Pygame
41
+
42
+ - ButtonPressField is used for commanding program what to do on specific key press events
43
+
44
+ - ButtonFieldAdv is used for displaying buttons in Pygame
45
+
46
+ - TextFieldExp is used for displaying text in Pygame
47
+
48
+
49
+ ========================
50
+
51
+ VALUE INFORMATION:
52
+
53
+ - page must be STR unless Redirect field where it must be class with self.name and self.call()
54
+
55
+ - InputField's argument "type" supports only int, bool, str, float
56
+
57
+ ========================
58
+
59
+ ERROR INFORMATION:
60
+
61
+ - 1xx: Framework/developer fault - PREFIX
62
+
63
+ - 2xx: User fault - PREFIX
64
+
65
+ - 3xx: Developer fault - PREFIX
66
+
67
+ - 4xx: Warning - PREFIX
68
+
69
+ - 100 INTERNAL ERROR:
70
+ Used by framework, raises when something within framework does not work.
71
+
72
+ - 101 REDIRECT ERROR:
73
+ Used by framework, raises when page isn't valid(page in development, developer should setup VALID_PAGES to not raise this error).
74
+
75
+ - 102 DATABASE ERROR:
76
+ Used by framework (look in data.py), raises when database key does not exist or database is not found.
77
+
78
+ - 103 NON-EXISTENT ERROR:
79
+ Used by framework to indicate that something within framework does not exist
80
+
81
+ - 104 IMAGE ERROR:
82
+ Used by framework (look in data.py), raises when something is wrong with image
83
+
84
+ - 105 INSTANCE ERROR:
85
+ Used by framework, raises when an instance is invalid
86
+
87
+ - 106 CALLABILITY ERROR:
88
+ Used by framework, raises when an object has incorrect callability(can be called while shouldn't or can't be called while should)
89
+
90
+ - 107 ARGUMENT ERROR:
91
+ Used by framework when an object has incorrect signature
92
+
93
+ - 108 SOUND ERROR:
94
+ Used by framework, raises when something is wrong with sound
95
+
96
+ - 200 INPUT ERROR:
97
+ Used by framework AND by developer to show user they have entered incorrect input
98
+
99
+ - 201 ACCESS ERROR:
100
+ Used by developer to show user that they have tried to access something without respective permission(when creating pages)
101
+
102
+ - 300 PAGE ERROR:
103
+ Used by framework when page is non-existent, doesn't have name or .call() with ctx.
104
+
105
+ - 301 PROGRAM ERROR:
106
+ Used by framework(look in program.py) when program is non existent, doesn't have name, etc
107
+
108
+ - 302 HISTORY ERROR:
109
+ Used by framework(look in program.py) when developer tries to access a history page which is unreachable
110
+
111
+ - 303 CANVAS ERROR:
112
+ Used by framework when developer tries to do something illegal with CanvasEmbedding
113
+
114
+ - 304 GAME ERROR:
115
+ Used by framework(look in program.py) when developer tries to do something illegal with Game
116
+
117
+ - 400 EXIT WARNING:
118
+ Used by framework(look in program.py) when developer or user tries to force-quit the program
119
+ """
120
+
121
+ """CODE"""
122
+ from inspect import signature as s
123
+ from math import floor, ceil
124
+ from tkinter import *
125
+ from time import sleep
126
+ import os
127
+ os.environ["PYGAME_HIDE_SUPPORT_PROMPT"] = "hide"
128
+ import pygame
129
+ import pygame.font
130
+ import sys
131
+ class ErrorForm:
132
+ def __init__(self, text, occurrence, type="200 INPUT ERROR"):
133
+ self.t=text
134
+ self.o=occurrence
135
+ self.ty=type
136
+ self.w=""
137
+ if "warning" not in self.ty.lower():
138
+ self.w=f"An error occurred on page {self.o}: "
139
+ def call(self):
140
+ SpaceField("=", 40, "ERRS").call()
141
+ TextField(self.ty, "ERRS", fancy=True, fancytotal=40).call()
142
+ TextField(f"{self.w}{self.t}", "ERRS",delim=0).call()
143
+ SpaceField("=", 40, "ERRS").call()
144
+
145
+ class SpaceField:
146
+ def __init__(self, sym, amo, page):
147
+ self.s=sym
148
+ self.a=amo
149
+ asr=["page", "symbol", "amount"]
150
+ args=[page, sym, amo]
151
+ types=[str, str, int]
152
+ self.c=ErrorHelper(asr, args, types)
153
+
154
+ def __str__(self):
155
+ return self.s*self.a
156
+
157
+ def call(self):
158
+ if self.c:
159
+ return 1
160
+ else:
161
+ print(self)
162
+ return 0
163
+
164
+ def ErrorHelper(argstrrep, args, types, ignore=False):
165
+ caller=True
166
+ if type(argstrrep) is not list:
167
+ ErrorForm(f"Invalid type for ErrorHelper argument 'argument string representation': {type(argstrrep).__name__}", "ERRHELP", type="100 INTERNAL ERROR").call()
168
+ caller=False
169
+ elif type(args) is not list:
170
+ ErrorForm(f"Invalid type for ErrorHelper argument 'arguments': {type(args).__name__}", "ERRHELP", type="100 INTERNAL ERROR").call()
171
+ caller=False
172
+ elif type(types) is not list:
173
+ ErrorForm(f"Invalid type for ErrorHelper argument 'types': {type(types).__name__}", "ERRHELP", type="100 INTERNAL ERROR").call()
174
+ caller=False
175
+ elif type(ignore) is not bool:
176
+ ErrorForm(f"Invalid type for ErrorHelper argument 'ignore': {type(ignore).__name__}", "ERRHELP", type="100 INTERNAL ERROR").call()
177
+ caller=False
178
+ if caller:
179
+ for x in range(0, len(argstrrep)):
180
+ if argstrrep[x]=="page" or ignore:
181
+ pfp="UNDEFINED"
182
+ else:
183
+ pfp=args[argstrrep.index("page")]
184
+ if type(types[x]) is list:
185
+ if args[x] not in types[x]:
186
+ ErrorForm(f"Invalid type for argument '{argstrrep[x]}': {type(args[x]).__name__} not in {types[x]}", f"{pfp}", type="100 INTERNAL ERROR").call()
187
+ caller=False
188
+ break
189
+ elif not isinstance(args[x],types[x]):
190
+ ErrorForm(f"Invalid type for argument '{argstrrep[x]}': {type(args[x]).__name__}", f"{pfp}", type="100 INTERNAL ERROR").call()
191
+ caller=False
192
+ break
193
+ return not caller
194
+
195
+ def ListErrorHelper(lists):
196
+ caller=True
197
+ for x in range(len(lists)):
198
+ if type(lists[x]) is not list:
199
+ ErrorForm(f"Invalid type for ListErrorHelper argument 'lists[{x}]': {type(lists).__name__}", "ERRHELP", type="100 INTERNAL ERROR").call()
200
+ caller=False
201
+ if caller:
202
+ lens=[]
203
+ for x in range(0, len(lists)):
204
+ lens.append(len(lists[x]))
205
+ prev=lens[0]
206
+ for x in range(1, len(lens)):
207
+ if prev==lens[x]:
208
+ prev=lens[x]
209
+ else:
210
+ ErrorForm(f"Invalid length for list 'lists[{x}]': {lens[x]}", "ERRHELP", type="100 INTERNAL ERROR").call()
211
+ caller=False
212
+ break
213
+ return not caller
214
+
215
+ class TextField:
216
+ def __init__(self, text, page, modifs=[], delim=0, fancy=False, fancytotal=40, sign="="):
217
+ self.d=delim
218
+ self.t=text
219
+ self.m=modifs
220
+ self.f=fancy
221
+ self.ft=fancytotal
222
+ asr=["page", "modifiers", "delimiter", "fancy", "fancytotal"]
223
+ args=[page, modifs, delim, fancy, fancytotal]
224
+ types=[str, list, int, bool, int]
225
+ caller=ErrorHelper(asr, args, types)
226
+ if self.ft<len(self.t) and not caller and self.f:
227
+ ErrorForm(f"Invalid amount for argument 'fancytotal': {self.ft} is less than length of text", page, type="100 INTERNAL ERROR").call()
228
+ caller=True
229
+ self.s=sign
230
+ self.p=page
231
+ self.c=caller
232
+
233
+ def __str__(self):
234
+ if self.c:
235
+ return "ERR"
236
+ out=""
237
+ txt=self.t
238
+ if self.f:
239
+ oka=self.s*floor((self.ft-len(self.t))/2)
240
+ else:
241
+ oka=self.s*self.d
242
+ out+=oka
243
+ e=True
244
+ for mod in self.m:
245
+ if mod.lower()=="up":
246
+ txt=txt.upper()
247
+ elif mod.lower()=="lo":
248
+ txt=txt.lower()
249
+ else:
250
+ ErrorForm(f"Unknown modifier {mod}", page, type="100 INTERNAL ERROR").call()
251
+ e=False
252
+ break
253
+ if e:
254
+ out+=txt
255
+ if self.f:
256
+ oka=self.s*ceil((self.ft-len(self.t))/2)
257
+ else:
258
+ oka=self.s*self.d
259
+ out+=oka
260
+ return out
261
+ else:
262
+ self.c=True
263
+ return "ERR"
264
+
265
+ def call(self):
266
+ val=self.__str__()
267
+ if self.c:
268
+ return 1
269
+ else:
270
+ print(val)
271
+ return 0
272
+
273
+ class InputField:
274
+ def __init__(self, prompt, name, page, req=True, inp_type=str, minimum=0, maximum=100, discretes=None):
275
+ self.TYPES=[str, float, int, bool]
276
+ self.p=page
277
+ self.pr=prompt
278
+ self.r=req
279
+ self.n=name
280
+ self.m=minimum
281
+ self.ma=maximum
282
+ self.t=inp_type
283
+ self.d=discretes
284
+ val=[]
285
+ if discretes:
286
+ val=discretes
287
+ asr=["page", "prompt", "required", "minimum","maximum", "discrete values"]
288
+ args=[self.p, self.pr, self.r, self.m, self.ma, val]
289
+ types=[str, str, bool, int, int, list]
290
+ self.c=ErrorHelper(asr, args, types)
291
+ if not self.c and inp_type not in self.TYPES:
292
+ ErrorForm(f"Type {inp_type} cannot be parsed", self.p, type="100 INTERNAL ERROR").call()
293
+ self.c=True
294
+ def call(self):
295
+ if self.c:
296
+ return "ERR"
297
+ res=""
298
+ if self.r:
299
+ bad=True
300
+ while res=="" or res==None or bad:
301
+ print(self.pr+"(field required):")
302
+ val=input()
303
+ if val=="" or val==None:
304
+ ErrorForm(f"Field {self.n} is required", self.p).call()
305
+ else:
306
+ res, bad=check(val, self.t, self.p, self.m, self.ma, self.d)
307
+ else:
308
+ bad=True
309
+ while bad:
310
+ print(self.pr+":")
311
+ val=input()
312
+ res, bad=check(val, self.t, self.p, self.m, self.ma, self.d)
313
+ return res
314
+
315
+ def check(val, req, page, mini, maxi, dis, adv=False, cne=None, canvas=None, element=None):
316
+ res=val
317
+ bad=False
318
+ rk=False
319
+ rk2=False
320
+ def s(req, page, cne, canvas, element):
321
+ if not adv:
322
+ ErrorForm(f"Wrong type: '{req}' type required", page).call()
323
+ else:
324
+ InteractiveUserErrorForm(cne, canvas, element, f"Wrong type: '{req}' type required", page).call()
325
+ return True
326
+ def k(mini, page, cne, canvas, element):
327
+ if not adv:
328
+ ErrorForm(f"Minimum limit is {mini}. Your input is not sufficiently large", page).call()
329
+ else:
330
+ InteractiveUserErrorForm(cne, canvas, element, f"Minimum limit is {mini}. Your input is not sufficiently large", page).call()
331
+ def u(maxi, page, cne, canvas, element):
332
+ if not adv:
333
+ ErrorForm(f"Maximum limit is {maxi}. Your input is too large", page).call()
334
+ else:
335
+ InteractiveUserErrorForm(cne, canvas, element, f"Maximum limit is {maxi}. Your input is too large", page).call()
336
+ if req==bool:
337
+ try:
338
+ if val.lower()=="true" or val=="1":
339
+ res=True
340
+ elif val.lower()=="false" or val=="0":
341
+ res=False
342
+ else:
343
+ raise ValueError()
344
+ except:
345
+ bad=s("bool", page, cne, canvas, element)
346
+ elif req==int:
347
+ try:
348
+ res=int(val)
349
+ if res<mini:
350
+ rk=True
351
+ elif res>maxi:
352
+ rk2=True
353
+ except:
354
+ bad=s("int", page, cne, canvas, element)
355
+ elif req==str:
356
+ try:
357
+ res=str(val)
358
+ if len(res)<mini:
359
+ rk=True
360
+ elif len(res)>maxi:
361
+ rk2=True
362
+ except:
363
+ bad=s("str", page, cne, canvas, element)
364
+ elif req==float:
365
+ try:
366
+ res=float(val)
367
+ if res<mini:
368
+ rk=True
369
+ elif res>maxi:
370
+ rk2=True
371
+ except:
372
+ bad=s("float", page, cne, canvas, element)
373
+ if rk:
374
+ k(mini, page, cne, canvas, element)
375
+ bad=True
376
+ elif rk2:
377
+ u(maxi, page, cne, canvas, element)
378
+ bad=True
379
+ if dis and (req!=bool):
380
+ if res not in dis and not bad:
381
+ distxt="Possible input values are: "
382
+ for di in dis:
383
+ distxt+=f"'{di}', "
384
+ distxt+=". You did not input one of them."
385
+ ErrorForm(distxt, page).call()
386
+ bad=True
387
+ return res, bad
388
+
389
+ class RedirectField:
390
+ def __init__(self, target, page, program, ctx={}):
391
+ self.pr=program
392
+ try:
393
+ self.t=target()
394
+ self.tc=target
395
+ self.p=page()
396
+ except:
397
+ ErrorForm("Target or starter page class for redirect isn't a class","UNDEFINED", type="300 PAGE ERROR").call()
398
+ self.c=True
399
+ return
400
+ self.ct=ctx
401
+ err=False
402
+ if not self.pr:
403
+ ErrorForm("Program isn't defined", "UNDEFINED", type="301 PROGRAM ERROR").call()
404
+ self.c=True
405
+ return
406
+ else:
407
+ try:
408
+ if program.vpgs!=[]:
409
+ VALID_PAGES=program.vpgs
410
+ else:
411
+ raise ValueError()
412
+ except:
413
+ ErrorForm("Program doesn't have any valid pages", "UNDEFINED", type="301 PROGRAM ERROR").call()
414
+ self.c=True
415
+ return
416
+ if not self.p:
417
+ ErrorForm("Starter page of redirect does not exist", "UNDEFINED", type="300 PAGE ERROR").call()
418
+ err=True
419
+ else:
420
+ try:
421
+ if type(self.p.name)==str:
422
+ pass
423
+ else:
424
+ raise ValueError()
425
+ except:
426
+ ErrorForm("Starter page of redirect has an invalid name/type", "UNDEFINED", type="300 PAGE ERROR").call()
427
+ err=True
428
+ if not err and (self.p.name not in VALID_PAGES):
429
+ ErrorForm(f"Page {self.p.name} is not a valid page for a redirect starter", self.p.name, type="101 REDIRECT ERROR").call()
430
+ err=True
431
+ elif not self.t:
432
+ ErrorForm("Target page of redirect does not exist", self.p.name, type="300 PAGE ERROR").call()
433
+ err=True
434
+ else:
435
+ try:
436
+ if type(self.t.name)==str:
437
+ pass
438
+ else:
439
+ raise ValueError()
440
+ except:
441
+ ErrorForm("Target page of redirect has an invalid name/type or it does not exist", self.p.name, type="300 PAGE ERROR").call()
442
+ err=True
443
+ if not err and (self.t.name not in VALID_PAGES):
444
+ ErrorForm(f"Page {self.t.name} is not a valid page for a redirect target", self.p.name, type="101 REDIRECT ERROR").call()
445
+ err=True
446
+ if not err:
447
+ try:
448
+ si=s(self.t.call)
449
+ args=list(si.parameters)
450
+ if "ctx" not in args:
451
+ err=True
452
+ ErrorForm(f"Target page does not conform to standards: a page must have a context argument 'ctx' in target.call", self.p.name, type="300 PAGE ERROR").call()
453
+ except:
454
+ err=True
455
+ ErrorForm(f"Target page does not conform to standards: target.call function not found", self.p.name, type="300 PAGE ERROR").call()
456
+
457
+ if not err:
458
+ self.c=ErrorHelper(["page", "context"], [self.p.name, self.ct], [str, dict])
459
+ else:
460
+ self.c=False
461
+ self.c=self.c or err
462
+ def call(self):
463
+ global control
464
+ global page_class
465
+ global page_ctx
466
+ if self.c:
467
+ return 1
468
+ else:
469
+ self.pr.control=self.t.name
470
+ self.pr.page_class=self.tc
471
+ self.pr.page_ctx=self.ct
472
+ return 0
473
+
474
+ class DummyPage:
475
+ name="dummy"
476
+ def call(self, ctx={}):
477
+ pass
478
+
479
+ class Embedding:
480
+ def __init__(self,page, grouped={}):
481
+ self.pg=page
482
+ self.gr=grouped
483
+ asr=["page","grouped data"]
484
+ args=[page, grouped]
485
+ types=[str, dict]
486
+ self.c=ErrorHelper(asr,args,types)
487
+
488
+ class CanvasEmbedding:
489
+ def __init__(self, page, name, width, height, program, resizex=0, resizey=0, thick=0, highlight_thick=0):
490
+ asr=["page", "name", "width", "height", "resizable - x-axis", "resizable - y-axis", "border thickness", "border highlight thickness"]
491
+ args=[page, name, width, height, resizex, resizey, thick, highlight_thick]
492
+ types=[str, str, int, int, int, int, int, int]
493
+ self.c=ErrorHelper(asr,args,types)
494
+ self.wins=[]
495
+ self.cnvs=[]
496
+ if not self.c:
497
+ self.embed=Embedding(page, {"page": page, "name":name, "program": program, "width":width, "height": height, "rx":resizex, "ry":resizey, "thick":thick, "hlt":highlight_thick})
498
+ def NewWindow(self):
499
+ if self.c:
500
+ return 1
501
+ gr=self.embed.gr
502
+ self.tk = Tk()
503
+ self.tk.title(gr["name"])
504
+ self.tk.resizable(gr["rx"], gr["ry"])
505
+ self.tk.wm_attributes("-topmost",1)
506
+ self.wins.append(self.tk)
507
+ return 0
508
+
509
+ def NewCanvas(self, window):
510
+ if self.c:
511
+ return 1
512
+ if self.wins==[]:
513
+ ErrorForm("Canvas Embedding did not find any valid windows. Please create a window by using NewWindow.", self.embed.gr["page"], type="103 NON-EXISTENT ERROR").call()
514
+ return 1
515
+ if ErrorHelper(["page", "window"], [self.embed.gr["page"], window], [str,int]):
516
+ return 1
517
+ if window>len(self.wins)-1 or window<0:
518
+ ErrorForm(f"Canvas Embedding did not find the window in question(Window #{window}). Please select another window ID.", self.embed.gr["page"], type="103 NON-EXISTENT ERROR").call()
519
+ return 1
520
+ self.cnv=Canvas(self.wins[window], width=self.embed.gr["width"], height=self.embed.gr["height"], bd=self.embed.gr["thick"], highlightthickness=self.embed.gr["hlt"])
521
+ self.cnvs.append({"tk":self.wins[window], "cnv":self.cnv})
522
+ self.cnv.pack()
523
+ return 0
524
+
525
+ def call(self):
526
+ if self.c:
527
+ return 1
528
+ if self.tk:
529
+ self.tk.update_idletasks()
530
+ self.tk.update()
531
+ return 0
532
+ else:
533
+ ErrorForm("Canvas Embedding did not find any valid windows. Please create a window by using NewWindow.", self.embed.gr["page"], type="103 NON-EXISTENT ERROR").call()
534
+ return 1
535
+
536
+
537
+ class ButtonField:
538
+ def __init__(self, canvas_embed, cmd, name, canvas, background="None", foreground="None", anchor="nw", x=150, y=100):
539
+ self.c=False
540
+ if not isinstance(canvas_embed, CanvasEmbedding):
541
+ ErrorForm("Wrong Embedding", "UNKNOWN", "304 CANVAS ERROR").call()
542
+ self.c=True
543
+ else:
544
+ self.cne=canvas_embed
545
+ if not self.c:
546
+ asr=["page", "button name", "button background color", "button foreground color", "canvas number", "button window position x", "button window position y", "button window anchor"]
547
+ args=[self.cne.embed.gr["page"], name, background, foreground, canvas, x, y, anchor]
548
+ types=[str, str, str, str, int, int, int, ["nw", "sw", "w", "n", "s", "e","ne", "se", "center"]]
549
+ self.c=self.c or ErrorHelper(asr, args, types)
550
+ if not self.c and len(self.cne.cnvs)==0:
551
+ ErrorForm("Canvas Embedding did not find any valid canvases.", self.cne.embed.gr["page"], type="103 NON-EXISTENT ERROR").call()
552
+ self.c=True
553
+ if not self.c and canvas>len(self.cne.cnvs)-1 or canvas<0:
554
+ ErrorForm(f"Canvas Embedding did not find the canvas in question(Canvas #{canvas})", self.cne.embed.gr["page"], type="103 NON-EXISTENT ERROR").call()
555
+ self.c=True
556
+ if not self.c:
557
+ self.x=x
558
+ self.y=y
559
+ self.w=0
560
+ self.embed=Embedding(self.cne.embed.gr["page"],{"canvas":canvas, "background":background, "foreground":foreground, "name":name, "command":cmd, "anchor":anchor, "x":x,"y":y,"w":0,"container":None, "special":False,"window":None})
561
+ def call(self, redraw=False, ignored=False):
562
+ if self.c:
563
+ return 1
564
+ if redraw and self.embed.gr["window"]:
565
+ self.cne.cnvs[self.embed.gr["canvas"]]["cnv"].delete(self.embed.gr["window"])
566
+ if ignored:
567
+ return 0
568
+ if self.embed.gr["background"]=="None" and self.embed.gr["foreground"]=="None":
569
+ self.btn=Button(self.cne.cnvs[self.embed.gr["canvas"]]["tk"], text=self.embed.gr["name"], command=self.embed.gr["command"])
570
+ elif self.embed.gr["background"]=="None":
571
+ self.btn=Button(self.cne.cnvs[self.embed.gr["canvas"]]["tk"], text=self.embed.gr["name"], command=self.embed.gr["command"], fg=self.embed.gr["foreground"])
572
+ elif self.embed.gr["foreground"]=="None":
573
+ self.btn=Button(self.cne.cnvs[self.embed.gr["canvas"]]["tk"], text=self.embed.gr["name"], command=self.embed.gr["command"], bg=self.embed.gr["background"])
574
+ else:
575
+ self.btn=Button(self.cne.cnvs[self.embed.gr["canvas"]]["tk"], text=self.embed.gr["name"], command=self.embed.gr["command"], bg=self.embed.gr["background"], fg=self.embed.gr["foreground"])
576
+ self.embed.gr["window"]=self.cne.cnvs[self.embed.gr["canvas"]]["cnv"].create_window(self.x, self.y, window=self.btn, anchor=self.embed.gr["anchor"])
577
+ self.cne.call()
578
+ return 0
579
+
580
+ class ChoiceForm:
581
+ def __init__(self, canvas_embed, choicenames, choicecmds, canvas, backgrounds=[], foregrounds=[], anchor="nw", x=150, y=100, distance=30):
582
+ self.cne=canvas_embed
583
+ self.ca=canvas
584
+ self.d=distance
585
+ self.bg=backgrounds
586
+ self.fg=foregrounds
587
+ self.nm=choicenames
588
+ self.cmd=choicecmds
589
+ self.an=anchor
590
+ self.w=0
591
+ self.x=x
592
+ self.y=y
593
+ if backgrounds==[]:
594
+ self.bg=["None"]*len(choicenames)
595
+ if foregrounds==[]:
596
+ self.fg=["None"]*len(choicenames)
597
+ self.c=ErrorHelper(["distance from choice to choice"], [distance], [int], ignore=True)
598
+ self.c=self.c or ListErrorHelper([choicenames, choicecmds, self.bg, self.fg])
599
+ self.cont=None
600
+ self.special=False
601
+ self.wind=None
602
+
603
+ def call(self, redraw=False, ignored=False):
604
+ if self.c:
605
+ return 1
606
+ for x in range(len(self.bg)):
607
+ ButtonField(self.cne, self.cmd[x], self.nm[x], self.ca, self.bg[x], self.fg[x], self.an, self.x+x*self.d, self.y).call(redraw=redraw, ignored=ignored)
608
+ return 0
609
+
610
+ class TextFieldAdv:
611
+ def __init__(self, canvas_embed, text, canvas, x, y, font_color="black", font_type="Times", font_size=15, anchor="nw"):
612
+ self.c=False
613
+ if not isinstance(canvas_embed, CanvasEmbedding):
614
+ ErrorForm("Wrong Embedding", "UNKNOWN", "304 CANVAS ERROR").call()
615
+ self.c=True
616
+ else:
617
+ self.cne=canvas_embed
618
+ if not self.c:
619
+ asr=["page", "font size", "font color", "text", "canvas number", "text window position x", "text window position y", "anchor"]
620
+ args=[self.cne.embed.gr["page"], font_size, font_color, text, canvas, x, y, anchor]
621
+ types=[str, int, str, str, int, int, int, ["nw", "sw", "w", "n", "s", "e","ne", "se", "center"]]
622
+ self.c=self.c or ErrorHelper(asr, args, types)
623
+ if not self.c and len(self.cne.cnvs)==0:
624
+ ErrorForm("Canvas Embedding did not find any valid canvases.", self.cne.embed.gr["page"], type="103 NON-EXISTENT ERROR").call()
625
+ self.c=True
626
+ if not self.c and canvas>len(self.cne.cnvs)-1 or canvas<0:
627
+ ErrorForm(f"Canvas Embedding did not find the canvas in question(Canvas #{canvas})", self.cne.embed.gr["page"], type="103 NON-EXISTENT ERROR").call()
628
+ self.c=True
629
+ if not self.c:
630
+ self.fs=font_size
631
+ self.fc=font_color
632
+ self.tx=text
633
+ self.ca=canvas
634
+ self.x=x
635
+ self.y=y
636
+ self.ft=font_type
637
+ self.an=anchor
638
+ self.w=(font_size/3)*len(text)
639
+ self.cont=None
640
+ self.special=False
641
+ self.wind=None
642
+ self.iuef=None
643
+ def call(self, redraw=False, ignored=False):
644
+ if self.c:
645
+ return 1
646
+ if redraw and self.wind:
647
+ self.cne.cnvs[self.ca]["cnv"].delete(self.wind)
648
+ if ignored:
649
+ return 0
650
+ self.wind=self.cne.cnvs[self.ca]["cnv"].create_text(self.x, self.y, text=self.tx, font=(self.ft, self.fs), fill=self.fc, anchor=self.an)
651
+ self.cne.call()
652
+ return self.wind
653
+
654
+ class ImageField:
655
+ def __init__(self, canvas_embed, x, y, canvas, img="./uploads/example.png", anchor="nw"):
656
+ self.c=False
657
+ if not isinstance(canvas_embed, CanvasEmbedding):
658
+ ErrorForm("Wrong Embedding", "UNKNOWN", "304 CANVAS ERROR").call()
659
+ self.c=True
660
+ else:
661
+ self.cne=canvas_embed
662
+ if not self.c:
663
+ asr=["page", "image x coordinate", "image y coordinate", "canvas number", "anchor"]
664
+ args=[self.cne.embed.gr["page"], x, y, canvas, anchor]
665
+ types=[str, int, int, int, ["nw", "sw", "w", "n", "s", "e","ne", "se", "center"]]
666
+ if not isinstance(img, PhotoImage):
667
+ asr.append("image path")
668
+ args.append(img)
669
+ types.append(str)
670
+ flag=True
671
+ self.c=self.c or ErrorHelper(asr, args, types)
672
+ if not self.c and len(self.cne.cnvs)==0:
673
+ ErrorForm("Canvas Embedding did not find any valid canvases.", self.cne.embed.gr["page"], type="103 NON-EXISTENT ERROR").call()
674
+ self.c=True
675
+ if not self.c and canvas>len(self.cne.cnvs)-1 or canvas<0:
676
+ ErrorForm(f"Canvas Embedding did not find the canvas in question(Canvas #{canvas})", self.cne.embed.gr["page"], type="103 NON-EXISTENT ERROR").call()
677
+ self.c=True
678
+ if not self.c:
679
+ self.x=x
680
+ self.y=y
681
+ self.ca=canvas
682
+ self.img=img
683
+ self.an=anchor
684
+ if not isinstance(self.img, PhotoImage):
685
+ self.imgf=PhotoImage(file=self.img)
686
+ else:
687
+ self.imgf=self.img
688
+ self.w=self.imgf.width()
689
+ self.cont=None
690
+ self.special=False
691
+ self.wind=None
692
+
693
+ def call(self, redraw=False, ignored=False):
694
+ if self.c:
695
+ return 1
696
+ if redraw and self.wind:
697
+ self.cne.cnvs[self.ca]["cnv"].delete(self.wind)
698
+ if ignored:
699
+ return 0
700
+ self.wind=self.cne.cnvs[self.ca]["cnv"].create_image(self.x, self.y, image=self.imgf, anchor=self.an)
701
+ self.cne.call()
702
+ return self
703
+
704
+ def updimg(self, image):
705
+ asr=["page"]
706
+ args=[self.cne.embed.gr["page"]]
707
+ types=[str]
708
+ if not isinstance(image, PhotoImage):
709
+ asr.append("image path")
710
+ args.append(image)
711
+ types.append(str)
712
+ if ErrorHelper(asr, args, types):
713
+ return 1
714
+ if not isinstance(image, PhotoImage):
715
+ self.imgf=PhotoImage(file=image)
716
+ else:
717
+ self.imgf=image
718
+ self.w=self.imgf.width()
719
+ return 0
720
+
721
+ class BackgroundForm:
722
+ def __init__(self, canvas_embed, beginx, beginy, copyx, copyy, canvas, img="./uploads/example.png", anchor="nw"):
723
+ self.c=False
724
+ flag=False
725
+ if not isinstance(canvas_embed, CanvasEmbedding):
726
+ ErrorForm("Wrong Embedding", "UNKNOWN", "304 CANVAS ERROR").call()
727
+ self.c=True
728
+ else:
729
+ self.cne=canvas_embed
730
+ if not self.c:
731
+ asr=["page", "begin x coordinate", "begin y coordinate", "times to copy on x axis", "times to copy on y axis", "canvas number", "anchor"]
732
+ args=[self.cne.embed.gr["page"], beginx, beginy, copyx, copyy, canvas, anchor]
733
+ types=[str, int, int, int, int, int,["nw", "sw", "w", "n", "s", "e","ne", "se", "center"]]
734
+ if not isinstance(img, PhotoImage):
735
+ asr.append("image path")
736
+ args.append(img)
737
+ types.append(str)
738
+ flag=True
739
+ self.c=self.c or ErrorHelper(asr, args, types)
740
+ if not self.c and len(self.cne.cnvs)==0:
741
+ ErrorForm("Canvas Embedding did not find any valid canvases.", self.cne.embed.gr["page"], type="103 NON-EXISTENT ERROR").call()
742
+ self.c=True
743
+ if not self.c and canvas>len(self.cne.cnvs)-1 or canvas<0:
744
+ ErrorForm(f"Canvas Embedding did not find the canvas in question(Canvas #{canvas})", self.cne.embed.gr["page"], type="103 NON-EXISTENT ERROR").call()
745
+ self.c=True
746
+ if not self.c:
747
+ self.bx=beginx
748
+ self.by=beginy
749
+ self.cx=copyx
750
+ self.cy=copyy
751
+ self.ca=canvas
752
+ self.img=img
753
+ self.tiles=[]
754
+ self.an=anchor
755
+ if flag:
756
+ self.imgf=PhotoImage(file=self.img)
757
+ else:
758
+ self.imgf=self.img
759
+ self.wi = self.imgf.width()
760
+ self.w=self.wi*self.cx
761
+ self.cont=None
762
+ self.special=False
763
+ self.wind=None
764
+ def call(self, redraw=False, ignored=False):
765
+ if self.c:
766
+ return 1
767
+ if redraw:
768
+ self.tiles=[]
769
+ h = self.imgf.height()
770
+ for x in range(self.cx):
771
+ self.tiles.append([])
772
+ for y in range(self.cy):
773
+ self.tiles[x].append(ImageField(self.cne, self.bx+x*self.wi, self.by+y*h,self.ca, self.imgf,self.an).call(redraw=redraw, ignored=ignored))
774
+ return 0
775
+
776
+ class GeometryField:
777
+ def __init__(self, canvas_embed, xs, ys, canvas, extent=180, bd=1, outline="black", fill="", typea="arc"):
778
+ self.c=False
779
+ if not isinstance(canvas_embed, CanvasEmbedding):
780
+ ErrorForm("Wrong Embedding", "UNKNOWN", "304 CANVAS ERROR").call()
781
+ self.c=True
782
+ else:
783
+ self.cne=canvas_embed
784
+ if not self.c:
785
+ asr=["page", "x coordinates", "y coordinates", "extent", "outline", "fill", "border width","type"]
786
+ args=[self.cne.embed.gr["page"], xs, ys, extent, outline, fill, bd, typea]
787
+ types=[str, list, list, int, str, str, int, ["arc", "polygon"]]
788
+ self.c=self.c or ErrorHelper(asr, args, types)
789
+ if not self.c and len(self.cne.cnvs)==0:
790
+ ErrorForm("Canvas Embedding did not find any valid canvases.", self.cne.embed.gr["page"], type="103 NON-EXISTENT ERROR").call()
791
+ self.c=True
792
+ if not self.c and canvas>len(self.cne.cnvs)-1 or canvas<0:
793
+ ErrorForm(f"Canvas Embedding did not find the canvas in question(Canvas #{canvas})", self.cne.embed.gr["page"], type="103 NON-EXISTENT ERROR").call()
794
+ self.c=True
795
+ if not self.c and len(xs)!=len(ys):
796
+ ErrorForm(f"Lengths of lists don't match", self.cne.embed.gr["page"], type="100 INTERNAL ERROR").call()
797
+ self.c=True
798
+ if not self.c and len(xs)<2:
799
+ ErrorForm(f"Lengths of lists aren't large enough", self.cne.embed.gr["page"], type="100 INTERNAL ERROR").call()
800
+ self.c=True
801
+ if not self.c:
802
+ self.xs=xs
803
+ self.ys=ys
804
+ self.ca=canvas
805
+ self.ex=extent
806
+ self.ol=outline
807
+ self.fl=fill
808
+ self.ty=typea
809
+ self.cont=None
810
+ self.special=False
811
+ self.wind=None
812
+ self.bdw=bd
813
+ def call(self, redraw=False,ignored=False):
814
+ if self.c:
815
+ return 1
816
+ if redraw and self.wind:
817
+ self.cne.cnvs[self.ca]["cnv"].delete(self.wind)
818
+ if ignored:
819
+ return 0
820
+ if self.ty=="arc":
821
+ self.wind=self.cne.cnvs[self.ca]["cnv"].create_arc(self.xs[0], self.ys[0], self.xs[1], self.ys[1], extent=self.ex, style=ARC, width=self.bdw, fill=self.fl, outline=self.ol)
822
+ elif self.ty=="polygon":
823
+ res=[]
824
+ for x in range(len(self.xs)):
825
+ res.append(self.xs[x])
826
+ res.append(self.ys[x])
827
+ self.wind=self.cne.cnvs[self.ca]["cnv"].create_polygon(*res, fill=self.fl, width=self.bdw, outline=self.ol)
828
+ self.cne.call()
829
+ return 0
830
+
831
+ class InteractiveUserErrorForm:
832
+ def __init__(self, cne, canvas, element, text,occurrence, type="200 INPUT ERROR"):
833
+ self.t=text
834
+ self.o=occurrence
835
+ self.ty=type
836
+ self.e=element
837
+ self.cne=cne
838
+ self.ca=canvas
839
+ self.cont=None
840
+ self.special=False
841
+ self.wind=None
842
+ def call(self, redraw=False, ignored=False):
843
+ if redraw and self.wind:
844
+ self.cne.cnvs[self.ca]["cnv"].delete(self.wind)
845
+ if ignored:
846
+ self.e.special=False
847
+ self.e.cont.call()
848
+ return 0
849
+ self.e.y+=20
850
+ if self.e.cont:
851
+ ignore, ypos=self.e.cont.get_pos(self.e)
852
+ xpos=self.e.cont.x
853
+ self.e.special=True
854
+ else:
855
+ xpos, ypos=self.e.x, self.e.y-20
856
+ self.wind=TextFieldAdv(self.cne, f"{self.ty}: {self.t}", self.ca, xpos, ypos, font_color="red", font_size=10).call(redraw=redraw)
857
+ self.e.cont.call()
858
+ self.e.iuef=self
859
+ return 0
860
+
861
+ class InputForm:
862
+ def __init__(self, canvas_embed, width, x, y, canvas, prompt, anchor="nw", type_req=str, minimum=0, maximum=100, discretes=[]):
863
+ required=type_req
864
+ self.c=False
865
+ if not isinstance(canvas_embed, CanvasEmbedding):
866
+ ErrorForm("Wrong Embedding", "UNKNOWN", "304 CANVAS ERROR").call()
867
+ self.c=True
868
+ else:
869
+ self.cne=canvas_embed
870
+ if not self.c:
871
+ asr=["page", "x coordinate", "y coordinate", "width", "canvas number", "anchor", "field required", "minimum value", "maximum value", "discrete values"]
872
+ args=[self.cne.embed.gr["page"], x, y, width, canvas, anchor, required, minimum, maximum, discretes]
873
+ types=[str, int, int, int, int, ["nw", "sw", "w", "ne", "e", "se", "center"], [str, int, bool, float], int, int, list]
874
+ self.c=self.c or ErrorHelper(asr, args, types)
875
+ if not self.c and len(self.cne.cnvs)==0:
876
+ ErrorForm("Canvas Embedding did not find any valid canvases.", self.cne.embed.gr["page"], type="103 NON-EXISTENT ERROR").call()
877
+ self.c=True
878
+ if not self.c and canvas>len(self.cne.cnvs)-1 or canvas<0:
879
+ ErrorForm(f"Canvas Embedding did not find the canvas in question(Canvas #{canvas})", self.cne.embed.gr["page"], type="103 NON-EXISTENT ERROR").call()
880
+ self.c=True
881
+ if not self.c:
882
+ if not isinstance(prompt, TextFieldAdv):
883
+ ErrorForm("Wrong Prompt Field: Field is not TextFieldAdv", self.cne.embed.gr["page"], type="105 INSTANCE ERROR").call()
884
+ self.c=True
885
+ if not self.c:
886
+ self.x=x
887
+ self.y=y
888
+ self.p=prompt
889
+ self.w=max(self.p.w, width)
890
+ self.wi=width
891
+ self.ca=canvas
892
+ self.an=anchor
893
+ self.r=required
894
+ self.mi=minimum
895
+ self.ma=maximum
896
+ self.d=discretes
897
+ self.cont=None
898
+ self.special=False
899
+ self.wind=None
900
+ self.ch_b=False
901
+ self.iuef=None
902
+ def call(self, redraw=False, ignored=False):
903
+ if self.c:
904
+ return 1
905
+ if redraw and self.wind:
906
+ self.cne.cnvs[self.ca]["cnv"].delete(self.wind)
907
+ if ignored:
908
+ return 0
909
+ x=self.p.x
910
+ y=self.p.y
911
+ self.p.x=self.x
912
+ self.p.y=self.y
913
+ self.p.call(redraw=redraw)
914
+ self.p.x=x
915
+ self.p.y=y
916
+ self.e=Entry(self.cne.tk, width=self.wi)
917
+ self.wind=self.cne.cnvs[self.ca]["cnv"].create_window(self.x, self.y+self.p.fs+10, window=self.e, anchor=self.an)
918
+ self.cne.call()
919
+ return 0
920
+ def get(self):
921
+ if self.c:
922
+ return "ERR"
923
+ ch=check(self.e.get(), self.r, self.cne.embed.gr["page"], self.mi, self.ma, self.d, adv=True, cne=self.cne, canvas=self.ca, element=self)
924
+ if ch[1]==False and self.ch_b:
925
+ self.iuef.call(redraw=True,ignored=True)
926
+ if not self.ch_b and ch[1]==True:
927
+ self.ch_b=True
928
+ return ch
929
+
930
+ class Container:
931
+ def __init__(self, canvas_embed, beginx, beginy, endx, canvas, fields=[], height=40, pos="center"):
932
+ instances=[TextFieldAdv, ImageField, ButtonField, InputForm, GeometryField, ChoiceForm, self.__class__]
933
+ self.c=False
934
+ if not isinstance(canvas_embed, CanvasEmbedding):
935
+ ErrorForm("Wrong Embedding", "UNKNOWN", "304 CANVAS ERROR").call()
936
+ self.c=True
937
+ else:
938
+ self.cne=canvas_embed
939
+ if not self.c:
940
+ asr=["page", "begin x coordinate", "begin y coordinate", "canvas number", "fields list", "height of one field", "end x coordinate", "position in container"]
941
+ args=[self.cne.embed.gr["page"], beginx, beginy, canvas, fields, height, endx, pos]
942
+ types=[str, int, int, int, list, int, int, ["begin", "end", "center"]]
943
+ self.c=self.c or ErrorHelper(asr, args, types)
944
+ if not self.c and len(self.cne.cnvs)==0:
945
+ ErrorForm("Canvas Embedding did not find any valid canvases.", self.cne.embed.gr["page"], type="103 NON-EXISTENT ERROR").call()
946
+ self.c=True
947
+ if not self.c and canvas>len(self.cne.cnvs)-1 or canvas<0:
948
+ ErrorForm(f"Canvas Embedding did not find the canvas in question(Canvas #{canvas})", self.cne.embed.gr["page"], type="103 NON-EXISTENT ERROR").call()
949
+ self.c=True
950
+ if not self.c:
951
+ for field in fields:
952
+ back=False
953
+ for instance in instances:
954
+ if isinstance(field, instance):
955
+ back=True
956
+ break
957
+ if not back:
958
+ self.c=True
959
+ ErrorForm("Non-valid instance detected", self.cne.embed.gr["page"], type="105 INSTANCE ERROR").call()
960
+ break
961
+ if not self.c:
962
+ self.x=beginx
963
+ self.y=beginy
964
+ self.ca=canvas
965
+ self.fs=fields
966
+ self.h=height
967
+ self.po=pos
968
+ self.ex=endx
969
+ self.w=self.ex-self.x
970
+ for el in fields:
971
+ el.cont=self
972
+ el.special=False
973
+
974
+ def call(self, ignored=False):
975
+ if self.c:
976
+ return 1
977
+ for fld in range(len(self.fs)):
978
+ xp=self.fs[fld].x
979
+ if self.po=="begin":
980
+ self.fs[fld].x=self.x
981
+ elif self.po=="center":
982
+ self.fs[fld].x=int(max(self.x, self.x+self.w/2-self.fs[fld].w/2))
983
+ elif self.po=="end":
984
+ self.fs[fld].x=int(self.ex-self.fs[fld].w)
985
+ yp=self.fs[fld].y
986
+ self.fs[fld].y=self.y+fld*self.h
987
+ if self.fs[fld].special:
988
+ self.fs[fld].y+=20
989
+ self.fs[fld].call(redraw=True, ignored=ignored)
990
+ self.fs[fld].y=yp
991
+ self.fs[fld].x=xp
992
+ return 0
993
+
994
+ def get_pos(self, fld2):
995
+ for fld in range(len(self.fs)):
996
+ if self.fs[fld] == fld2:
997
+ if self.po=="begin":
998
+ xx=self.x
999
+ elif self.po=="center":
1000
+ xx=int(max(self.x, self.x+self.w/2-self.fs[fld].w/2))
1001
+ elif self.po=="end":
1002
+ xx=int(self.ex-self.fs[fld].w)
1003
+ return xx, self.y+fld*self.h
1004
+
1005
+ def DummyCmd():
1006
+ pass
1007
+ def DummyCmdArgs(*args):
1008
+ pass
1009
+ class PygameEmbedding:
1010
+ def __init__(self, width, height, name,page, color=(230,230,230)):
1011
+ asr=["page", "width", "height", "red", "green", "blue", "name"]
1012
+ args=[page, width, height, color[0], color[1], color[2], name]
1013
+ types=[str, int, int, int, int, int, str]
1014
+ self.c=ErrorHelper(asr, args, types)
1015
+ self.sprites=[]
1016
+ self.kys=[]
1017
+ if not self.c:
1018
+ pygame.init()
1019
+ self.color=color
1020
+ self.center=(width/2,height/2)
1021
+ self.screen = pygame.display.set_mode((width, height))
1022
+ self.width, self.height=width, height
1023
+ pygame.display.set_caption(name)
1024
+ self.page=page
1025
+ self.rect=self.screen.get_rect()
1026
+ self.exit=False
1027
+ self.setup()
1028
+ def link(self,sprite):
1029
+ if self.c:
1030
+ return 1
1031
+ if ErrorHelper(["page","sprite"], [self.page,sprite], [str,ImageSprite]):
1032
+ return 1
1033
+ elif sprite.c:
1034
+ return 1
1035
+ self.sprites.append(sprite)
1036
+ return 0
1037
+
1038
+ def linkbtn(self,sprite):
1039
+ if self.c:
1040
+ return 1
1041
+ if ErrorHelper(["page","sprite"], [self.page,sprite], [str,ButtonFieldAdv]):
1042
+ return 1
1043
+ elif sprite.c:
1044
+ return 1
1045
+ self.sprites.append(sprite)
1046
+ return 0
1047
+
1048
+ def linkkey(self,keypress):
1049
+ if self.c:
1050
+ return 1
1051
+ elif ErrorHelper(["page","key press field"], [self.page,keypress], [str,ButtonPressField]):
1052
+ return 1
1053
+ elif keypress.c:
1054
+ return 1
1055
+ self.kys.append(keypress)
1056
+ return 0
1057
+
1058
+ def register_keys(self,*btns):
1059
+ for btn in btns:
1060
+ self.linkkey(btn)
1061
+ return 0
1062
+
1063
+ def setup(self,exec_before_flip=DummyCmd, ticks=DummyCmd, before_imgs=DummyCmd, custom_event_checker=DummyCmdArgs):
1064
+ if self.c:
1065
+ return 1
1066
+ if not callable(exec_before_flip):
1067
+ ErrorForm("Non-callable object recieved, exec_before_flip should be a callable", self.page, "106 CALLABILITY ERROR").call()
1068
+ return 1
1069
+ si=s(exec_before_flip)
1070
+ args=list(si.parameters)
1071
+ if len(args)!=0:
1072
+ ErrorForm(f"exec_before_flip does not conform to standards: should accept no arguments", self.page, type="107 ARGUMENT ERROR").call()
1073
+ return 1
1074
+
1075
+ if not callable(ticks):
1076
+ ErrorForm("Non-callable object recieved, clock ticks function should be a callable", self.page, "106 CALLABILITY ERROR").call()
1077
+ return 1
1078
+ si=s(ticks)
1079
+ args=list(si.parameters)
1080
+ if len(args)!=0:
1081
+ ErrorForm(f"clock ticks function does not conform to standards: should accept no arguments", self.page, type="107 ARGUMENT ERROR").call()
1082
+ return 1
1083
+
1084
+ if not callable(before_imgs):
1085
+ ErrorForm("Non-callable object recieved, before drawing images function should be a callable", self.page, "106 CALLABILITY ERROR").call()
1086
+ return 1
1087
+ si=s(before_imgs)
1088
+ args=list(si.parameters)
1089
+ if len(args)!=0:
1090
+ ErrorForm(f"before drawing images function does not conform to standards: should accept no arguments", self.page, type="107 ARGUMENT ERROR").call()
1091
+ return 1
1092
+
1093
+ if not callable(custom_event_checker):
1094
+ ErrorForm("Non-callable object recieved, custom event checking function should be a callable", self.page, "106 CALLABILITY ERROR").call()
1095
+ return 1
1096
+ si=s(custom_event_checker)
1097
+ args=list(si.parameters)
1098
+ if len(args)!=1:
1099
+ ErrorForm(f"custom event checking function does not conform to standards: should accept event argument", self.page, type="107 ARGUMENT ERROR").call()
1100
+ return 1
1101
+
1102
+ self.ebf=exec_before_flip
1103
+ self.tks=ticks
1104
+ self.bim=before_imgs
1105
+ self.cec=custom_event_checker
1106
+
1107
+ def call(self):
1108
+ if self.c:
1109
+ return 1
1110
+
1111
+ self.mouse=pygame.mouse.get_pos()
1112
+
1113
+ self.tks()
1114
+ for event in pygame.event.get():
1115
+ if event.type==pygame.QUIT:
1116
+ self.exit=True
1117
+ elif event.type==pygame.KEYUP:
1118
+ for fld in self.kys:
1119
+ if event.key==fld.key and not fld.cont:
1120
+ fld.cmdr()
1121
+ elif event.type==pygame.KEYDOWN:
1122
+ for fld in self.kys:
1123
+ if event.key==fld.key and not fld.cont:
1124
+ fld.cmd()
1125
+ self.cec(event)
1126
+ keys=pygame.key.get_pressed()
1127
+ for fld in self.kys:
1128
+ if fld.cont and keys[fld.key]:
1129
+ fld.cmd()
1130
+ self.screen.fill(self.color)
1131
+ self.bim()
1132
+ for sprite in self.sprites:
1133
+ sprite.upd()
1134
+ sprite.call()
1135
+ self.ebf()
1136
+ pygame.display.flip()
1137
+ return 0
1138
+
1139
+ class ImageSprite:
1140
+ def __init__(self,embed,center, imgpath):
1141
+ self.c=ErrorHelper(["page", "path to image", "Pygame embedding", "center x", "center y"],["Sprite loader", imgpath,embed,center[0], center[1]],[str,str, PygameEmbedding, int,int])
1142
+ if not self.c:
1143
+ if "/" in imgpath:
1144
+ actpath=imgpath
1145
+ else:
1146
+ actpath=f"uploads/{imgpath}"
1147
+ try:
1148
+ self.img=pygame.image.load(actpath)
1149
+ except:
1150
+ self.c=True
1151
+ ErrorForm(f"Image {imgpath} was not found or had a wrong extension", "Sprite loader", "104 IMAGE ERROR").call()
1152
+ if embed.c:
1153
+ ErrorForm(f"Invalid CanvasEmbedding object: Object had an error", "Sprite loader","105 INSTANCE ERROR").call()
1154
+ self.c=self.c or embed.c
1155
+
1156
+ if not self.c:
1157
+ self.screen=embed.screen
1158
+ self.srect=embed.rect
1159
+ self.rect=self.img.get_rect()
1160
+ self.rect.center=center
1161
+ self.embed=embed
1162
+ self.moving=[False,False,False,False]
1163
+ self.pix=[0,0,0,0]
1164
+ self.x=float(self.rect.x)
1165
+ self.y=float(self.rect.y)
1166
+
1167
+ def call(self):
1168
+ if self.c:
1169
+ return 1
1170
+ self.screen.blit(self.img,self.rect)
1171
+ return 0
1172
+
1173
+ def toggle_move(self, pix,dire="left"):
1174
+ if self.c:
1175
+ return 1
1176
+ elif ErrorHelper(["page", "direction", "pixels"], [self.embed.page,dire,pix],[str, ["left", "right", "up", "down"], float]):
1177
+ return 1
1178
+ if dire=="left":
1179
+ self.moving[0]=not self.moving[0]
1180
+ self.pix[0]=pix
1181
+ elif dire=="right":
1182
+ self.moving[1]=not self.moving[1]
1183
+ self.pix[1]=pix
1184
+ elif dire=="up":
1185
+ self.moving[2]=not self.moving[2]
1186
+ self.pix[2]=pix
1187
+ elif dire=="down":
1188
+ self.moving[3]=not self.moving[3]
1189
+ self.pix[3]=pix
1190
+ return 0
1191
+ def upd(self):
1192
+ if self.c:
1193
+ return 1
1194
+ if self.moving[0] and self.rect.left>0:
1195
+ self.x-=self.pix[0]
1196
+ if self.moving[1] and self.rect.right<self.srect.right:
1197
+ self.x+=self.pix[1]
1198
+ if self.moving[2] and self.rect.top>0:
1199
+ self.y-=self.pix[2]
1200
+ if self.moving[3] and self.rect.bottom<self.srect.bottom:
1201
+ self.y+=self.pix[3]
1202
+ self.rect.x=self.x
1203
+ self.rect.y=self.y
1204
+ if self.rect.top<0:
1205
+ self.rect.top=0
1206
+ self.y=self.rect.y
1207
+ if self.rect.bottom>self.srect.bottom:
1208
+ self.rect.bottom=self.srect.bottom
1209
+ self.y=self.rect.y
1210
+ if self.rect.right>self.srect.right:
1211
+ self.rect.right=self.srect.right
1212
+ self.x=self.rect.x
1213
+ if self.rect.left<0:
1214
+ self.rect.left=0
1215
+ self.x=self.rect.x
1216
+ return 0
1217
+
1218
+ class ButtonPressField:
1219
+ def __init__(self, key, cmd,cmdr=DummyCmd, continuous=True):
1220
+ self.c=False
1221
+ if pygame.key.name(key)=="unknown key":
1222
+ self.c=True
1223
+ if not self.c:
1224
+ self.key=key
1225
+ self.cmd=cmd
1226
+ self.cmdr=cmdr
1227
+ self.cont=continuous
1228
+
1229
+ class ButtonFieldAdv:
1230
+ def __init__(self, embed, text, width, height, begin_x, begin_y,on_click,color=(150,150,200), text_color=(255,255,255), fonttype=None, fontsize=48, begin_state=0):
1231
+ if fonttype==None:
1232
+ fonttype=""
1233
+ self.c=ErrorHelper(["page", "Pygame embedding", "text","width","height","red button color", "green button color","blue button color","red text color","green text color","blue text color","font type","font size", "begin x coordinate", "begin y coordinate","begin state"],["Button loader", embed,text,width,height,color[0],color[1],color[2],text_color[0],text_color[1],text_color[2], fonttype,fontsize, begin_x,begin_y,begin_state],[str, PygameEmbedding,str,int,int,int,int,int,int,int,int,str,int,int,int, [0,1,2]])
1234
+ if not callable(on_click):
1235
+ ErrorForm("Non-callable object recieved, on_click should be a callable", self.page, "106 CALLABILITY ERROR").call()
1236
+ self.c=True
1237
+ if not self.c:
1238
+ if fonttype=="":
1239
+ fonttype=None
1240
+ self.ft=fonttype
1241
+ self.embed=embed
1242
+ self.color=color
1243
+ self.width=width
1244
+ self.height=height
1245
+ self.tc=text_color
1246
+ self.font=pygame.font.SysFont(fonttype,fontsize)
1247
+ self.screen=embed.screen
1248
+ self.srect=embed.rect
1249
+ self.text=text
1250
+ self.rect=pygame.Rect(0,0,self.width,self.height)
1251
+ self.rect.topleft=(begin_x, begin_y)
1252
+ self.oc=on_click
1253
+ self.state=begin_state
1254
+ self.pressed=False
1255
+ self._prep_msg(text)
1256
+
1257
+ def _prep_msg(self,msg):
1258
+ self.mimg=self.font.render(msg, True, self.tc, self.color)
1259
+ self.mimgrect = self.mimg.get_rect()
1260
+ self.mimgrect.center=self.rect.center
1261
+ return 0
1262
+
1263
+ def change_text(self,nxt):
1264
+ self.c=ErrorHelper(["page","new text"], ["Pygame Button Text Changer", nxt], [str,str])
1265
+ if self.c:
1266
+ return 1
1267
+ self._prep_msg(nxt)
1268
+ self.text=nxt
1269
+
1270
+ def call(self):
1271
+ if self.c:
1272
+ return 1
1273
+ if self.state!=2:
1274
+ self.screen.fill(self.color,self.rect)
1275
+ self.screen.blit(self.mimg, self.mimgrect)
1276
+ return 0
1277
+
1278
+ def upd(self):
1279
+ if self.c:
1280
+ return 1
1281
+ if self.rect.collidepoint(self.embed.mouse) and self.state==0 and pygame.mouse.get_pressed()[0] and not self.pressed:
1282
+ self.pressed=True
1283
+ return 2
1284
+ if self.rect.collidepoint(self.embed.mouse) and self.state==0 and not pygame.mouse.get_pressed()[0] and self.pressed:
1285
+ self.pressed=False
1286
+ self.oc()
1287
+ return 0
1288
+
1289
+ def disable(self):
1290
+ self.state=1
1291
+
1292
+ def enable(self):
1293
+ self.state=0
1294
+
1295
+ def off(self):
1296
+ self.state=2
1297
+
1298
+ class TextFieldExp:
1299
+ def __init__(self, embed, text, begin_x, begin_y,color=(230,230,230), text_color=(255,255,255), fonttype=None, fontsize=48, begin_state=0, nobg=0):
1300
+ if fonttype==None:
1301
+ fonttype=""
1302
+ self.c=ErrorHelper(["page", "Pygame embedding", "text","red outside color", "green outside color","blue outside color","red text color","green text color","blue text color","font type","font size", "begin x coordinate", "begin y coordinate","begin state", "no background"],["Text loader", embed,text,color[0],color[1],color[2],text_color[0],text_color[1],text_color[2], fonttype,fontsize, begin_x,begin_y,begin_state, nobg],[str, PygameEmbedding,str,int,int,int,int,int,int,str,int,int,int, [0,1], [0,1]])
1303
+ if not self.c:
1304
+ if fonttype=="":
1305
+ fonttype=None
1306
+ self.ft=fonttype
1307
+ self.embed=embed
1308
+ self.color=color
1309
+ self.tc=text_color
1310
+ self.font=pygame.font.SysFont(fonttype,fontsize)
1311
+ self.screen=embed.screen
1312
+ self.srect=embed.rect
1313
+ self.text=text
1314
+ self.tl=(begin_x,begin_y)
1315
+ self.state=begin_state
1316
+ self.nobg=nobg
1317
+ self._prep_msg(text)
1318
+
1319
+ def _prep_msg(self,msg):
1320
+ if self.nobg:
1321
+ self.mimg=self.font.render(msg, True, self.tc)
1322
+ else:
1323
+ self.mimg=self.font.render(msg, True, self.tc, self.color)
1324
+ self.mimgrect = self.mimg.get_rect()
1325
+ self.mimgrect.topleft=self.tl
1326
+ return 0
1327
+
1328
+ def change_text(self,nxt):
1329
+ self.c=ErrorHelper(["page","new text"], ["Pygame Text Changer", nxt], [str,str])
1330
+ if self.c:
1331
+ return 1
1332
+ self.text=nxt
1333
+ self._prep_msg(nxt)
1334
+
1335
+ def call(self):
1336
+ if self.c:
1337
+ return 1
1338
+ if self.state==0:
1339
+ self.screen.blit(self.mimg, self.mimgrect)
1340
+ return 0
1341
+
1342
+ def on(self):
1343
+ self.state=0
1344
+
1345
+ def off(self):
1346
+ self.state=1
1347
+
1348
+ class Music:
1349
+ def __init__(self, embed, filepath, type="sound", permanent=0, volume=0.5):
1350
+ self.c=ErrorHelper(["page", "pygame embedding", "music type", "permanent music", "path to file", "volume"], ["Music loader and player", embed, type, permanent,filepath, volume], [str, PygameEmbedding, ["music", "sound"], [0,1],str, float])
1351
+ if not self.c:
1352
+ if "/" in filepath:
1353
+ actpath=filepath
1354
+ else:
1355
+ actpath=f"uploads/{filepath}"
1356
+ try:
1357
+ if type=="music":
1358
+ snd=pygame.mixer.music.load(actpath)
1359
+ elif type=="sound":
1360
+ snd=pygame.mixer.Sound(actpath)
1361
+ except:
1362
+ self.c=True
1363
+ ErrorForm(f"Sound {filepath} was not found or had a wrong extension", "Sound loader", "108 SOUND ERROR").call()
1364
+ if not self.c:
1365
+ self.type=type
1366
+ self.sound=snd
1367
+ self.permanent=permanent
1368
+ self.volume=volume
1369
+
1370
+ def call(self):
1371
+ if self.c:
1372
+ return 1
1373
+ if self.type=="music":
1374
+ pygame.mixer.music.set_volume(self.volume)
1375
+ if self.permanent:
1376
+ pygame.mixer.music.play(-1)
1377
+ else:
1378
+ pygame.mixer.music.play()
1379
+ else:
1380
+ self.sound.set_volume(self.volume)
1381
+ self.sound.play()
1382
+
1383
+ return 0
1384
+
1385
+ def newvolume(self, volume):
1386
+ self.c=self.c or ErrorHelper(["page", "volume"], ["Sound changer", volume], [str, float])
1387
+ if self.c:
1388
+ return 1
1389
+ self.volume=volume
1390
+ if self.type=="music":
1391
+ pygame.mixer.music.set_volume(volume)
1392
+ else:
1393
+ self.sound.set_volume(self.volume)
1394
+ class Slider:
1395
+ def __init__(self, embed, pos, size, limit, slidercolor, rectcolor, initialpercentage=0):
1396
+ self.c=ErrorHelper(["page", "pygame embedding", "position", "x coordinate", "y coordinate", "size", "limit", "slider color", "slider color red", "slider color green", "slider color blue", "rect color", "rect color red", "rect color green", "rect color blue", "initial percentage"],["Slider loader", embed, pos, pos[0],pos[1], size, limit, slidercolor, slidercolor[0], slidercolor[1], slidercolor[2], rectcolor, rectcolor[0], rectcolor[1], rectcolor[2], initialpercentage],[str, PygameEmbedding, tuple, int, int, int, int, tuple, int, int, int, tuple, int, int, int, float])
1397
+ if not self.c:
1398
+ self.track=pygame.Rect(pos, (limit-pos[0]+size, size+4))
1399
+ self.slidecirclepos=(self.track.midleft[0]+size/2, self.track.midleft[1])
1400
+ self.slidecircleradius=size/2
1401
+ self.held=False
1402
+ self.embed=embed
1403
+ self.slider_color=slidercolor
1404
+ self.rect_color=rectcolor
1405
+ self.size=size
1406
+ self.limit=(self.track.midleft[0]+size/2, self.track.midright[0]-size/2)
1407
+ self.slidecirclepos=(min(max(self.limit[0]+initialpercentage*(self.limit[1]-self.limit[0]), self.limit[0]), self.limit[1]), self.slidecirclepos[1])
1408
+
1409
+ def call(self):
1410
+ if self.c:
1411
+ return 2
1412
+ mouse=self.embed.mouse
1413
+ if self.held:
1414
+ self.slidecirclepos=(min(max(mouse[0], self.limit[0]), self.limit[1]), self.slidecirclepos[1])
1415
+ pygame.draw.rect(self.embed.screen, self.rect_color, self.track, border_radius=int(2+self.size/2))
1416
+ pygame.draw.circle(self.embed.screen, self.slider_color, self.slidecirclepos, self.slidecircleradius)
1417
+ if pygame.mouse.get_pressed()[0] and (mouse[0]-self.slidecirclepos[0])**2+(mouse[1]-self.slidecirclepos[1])**2<=self.slidecircleradius**2:
1418
+ self.held=True
1419
+ else:
1420
+ self.held=False
1421
+ return (self.slidecirclepos[0]-self.limit[0])/(self.limit[1]-self.limit[0])
1422
+
1423
+ class PygameObjectGroup:
1424
+ AVAILABLE_TYPES=[ImageSprite, ButtonFieldAdv, TextFieldExp, Music, Slider]
1425
+ def __init__(self, embed, togroup):
1426
+ self.c=ErrorHelper(["page", "pygame embedding"], ["Pygame group creator", embed], [str, PygameEmbedding])
1427
+ if not self.c:
1428
+ self.grouped=[]
1429
+ for obj in togroup:
1430
+ calc=0
1431
+ for type_ in self.AVAILABLE_TYPES:
1432
+ if not isinstance(obj, type_):
1433
+ calc+=1
1434
+ if calc==len(self.AVAILABLE_TYPES):
1435
+ ErrorForm(f"Invalid type for subargument of argument togroup: Can't group object of type {(obj).__class__} into a group", "100 INTERNAL ERROR").call()
1436
+ elif obj.c:
1437
+ ErrorForm(f"Invalid state for subargument of argument togroup: Can't group errored object {obj} of type {(obj).__class__} into a group", "100 INTERNAL ERROR").call()
1438
+ else:
1439
+ self.grouped.append(obj)
1440
+ def off_all(self):
1441
+ for obj in self.grouped:
1442
+ objclass=(obj).__class__
1443
+ if objclass==TextFieldExp or objclass==ButtonFieldAdv:
1444
+ obj.off()
1445
+ elif objclass==Music:
1446
+ obj.newvolume(0.0)
1447
+
1448
+ def on_all(self):
1449
+ for obj in self.grouped:
1450
+ objclass=(obj).__class__
1451
+ if objclass==TextFieldExp:
1452
+ obj.on()
1453
+ elif objclass==ButtonFieldAdv:
1454
+ obj.enable()
1455
+ elif objclass==Music:
1456
+ obj.newvolume(1.0)
1457
+
1458
+ def disable_all(self):
1459
+ for obj in self.grouped:
1460
+ objclass=(obj).__class__
1461
+ if objclass==ButtonFieldAdv:
1462
+ obj.disable()
1463
+
1464
+ def call(self):
1465
+ values=[]
1466
+ for obj in self.grouped:
1467
+ values.append(obj.call())
1468
+ return values
1469
+
1470
+