From ce597aa1ba1d77337301bf4e1013a881a79b1158 Mon Sep 17 00:00:00 2001 From: Max Worrall <96847801+Tsunami014@users.noreply.github.com> Date: Thu, 16 Nov 2023 08:20:42 +1100 Subject: [PATCH 01/91] =?UTF-8?q?feat(graphics):=20=F0=9F=8E=89=20Started?= =?UTF-8?q?=20working=20on=20the=20node=20element=20gen!?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit TODO: get better name for this --- elementGen/__init__.py | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 elementGen/__init__.py diff --git a/elementGen/__init__.py b/elementGen/__init__.py new file mode 100644 index 0000000..e69de29 From d19e2ec08a25c04ef0c2e83e4def9bf7b7d8f873 Mon Sep 17 00:00:00 2001 From: Max Worrall <96847801+Tsunami014@users.noreply.github.com> Date: Thu, 16 Nov 2023 08:21:25 +1100 Subject: [PATCH 02/91] =?UTF-8?q?feat(graphics):=20=E2=9C=A8=20Added=20nod?= =?UTF-8?q?e=5Feditor.py?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It's blank RN --- elementGen/node_editor.py | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 elementGen/node_editor.py diff --git a/elementGen/node_editor.py b/elementGen/node_editor.py new file mode 100644 index 0000000..e69de29 From 23f4ca3ba32989332a7a1059ee69f5413e78d11a Mon Sep 17 00:00:00 2001 From: Max Worrall <96847801+Tsunami014@users.noreply.github.com> Date: Thu, 16 Nov 2023 08:24:32 +1100 Subject: [PATCH 03/91] =?UTF-8?q?feat(main):=20=F0=9F=8E=89=20It's=20time?= =?UTF-8?q?=20to=20fix=20these=20stupid=20imports=20once=20and=20for=20all?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit I'm having on emain demo file to demo everything so: 1. I don't have to look through each file for a demo 2. The files don't have to have STUPID import statements anymore! --- demos.py | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 demos.py diff --git a/demos.py b/demos.py new file mode 100644 index 0000000..e69de29 From 0d5f3d67c8aec40a6f0a881493907b0ef2a3b45c Mon Sep 17 00:00:00 2001 From: Max Worrall <96847801+Tsunami014@users.noreply.github.com> Date: Thu, 16 Nov 2023 08:28:26 +1100 Subject: [PATCH 04/91] =?UTF-8?q?feat(main):=20=E2=9C=A8=20Added=20demo=20?= =?UTF-8?q?homescreen?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Uses Tkinter as everyone has that --- demos.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/demos.py b/demos.py index e69de29..b65862b 100644 --- a/demos.py +++ b/demos.py @@ -0,0 +1,12 @@ +import tkinter as Tk # Because everyone has tkinter + +def demo1(): + print('This is demo 1!') + +def demo2(): + print('This is demo 2!') + +root = Tk.Tk() +Tk.Button(root, text='Demo 1', command=demo1).pack() +Tk.Button(root, text='Demo 2', command=demo2).pack() +root.mainloop() From 15fa65561628b603cb63496cc4ae306acba9fc0d Mon Sep 17 00:00:00 2001 From: Max Worrall <96847801+Tsunami014@users.noreply.github.com> Date: Thu, 16 Nov 2023 08:41:14 +1100 Subject: [PATCH 05/91] =?UTF-8?q?chore(main):=20=F0=9F=9A=9A=20Moved=20the?= =?UTF-8?q?=20demos=20from=20Loading.py=20and=20graphics.py=20to=20demos.p?= =?UTF-8?q?y?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Getting there :D --- demos.py | 104 +++++++++++++++++++++++++++++++++++++++---- graphics/graphics.py | 70 ----------------------------- graphics/loading.py | 13 ------ 3 files changed, 96 insertions(+), 91 deletions(-) diff --git a/demos.py b/demos.py index b65862b..c176766 100644 --- a/demos.py +++ b/demos.py @@ -1,12 +1,100 @@ import tkinter as Tk # Because everyone has tkinter -def demo1(): - print('This is demo 1!') +def loadingDemo(): + import pygame + from graphics import Loading + from time import sleep + @Loading + def f(self): + for self.i in range(10): + sleep(1) + pygame.init() + WIN = pygame.display.set_mode() + font = pygame.font.Font(None, 64) + succeeded, ret = f(WIN, font) + pygame.quit() + print('Ran for %i seconds%s' % (ret['i'], (' Successfully! :)' if succeeded else ' And failed :('))) + print('end') -def demo2(): - print('This is demo 2!') +def GraphicsDemo(): + import pygame + import graphics.graphics_options as GO + from graphics import Graphic + from time import sleep + t = input('Please input the starting text for the middle: ') + G = Graphic() + @G.Loading + def test_loading(self): + for self.i in range(10): + sleep(1) + + @G.Graphic + def test(event, txt, element=None, aborted=False): # You do not need args and kwargs if you KNOW that your function will not take them in. Include what you need. + if event == GO.EFIRST: # First, before anything else happens in the function + G.Container.txt = txt + if event == GO.ELOADUI: # Load the graphics + CTOP = GO.PNEW([1, 0], GO.PSTACKS[GO.PCTOP][1], 0) # Bcos usually the Center Top makes the elements stack down, so I make a new thing that stacks sideways + G.Clear() + G.add_text('HI', GO.CGREEN, GO.PRBOTTOM, GO.FTITLE) + G.add_text(':) ', GO.CBLACK, GO.PRBOTTOM, GO.FTITLE) + G.add_empty_space(GO.PCCENTER, 0, -150) # Yes, you can have negative space. This makes the next things shifted the other direction. + G.add_text('This is a cool thing', GO.CBLUE, GO.PCCENTER) + G.add_text('Sorry, I meant a cool TEST', GO.CRED, GO.PCCENTER) + G.add_text(G.Container.txt, GO.CGREEN, GO.PCCENTER) + G.add_empty_space(GO.PCBOTTOM, 0, 20) + G.add_button('Button 1 :D', GO.CYELLOW, GO.PCBOTTOM) + G.add_text('Buttons above [^] and below [v]', GO.CBLUE, GO.PCBOTTOM) + G.add_button('Textbox test', GO.CBLUE, GO.PCBOTTOM) + G.add_button('Loading test', GO.CGREEN, GO.PCBOTTOM) + G.Container.exitbtn = G.add_button('EXIT', GO.CRED, GO.PCBOTTOM) + G.add_empty_space(CTOP, -150, 0) # Center it a little more + G.add_text('Are you ', GO.CBLACK, CTOP) + G.add_text('happy? ', GO.CGREEN, CTOP) + G.add_text('Or sad?', GO.CRED, CTOP) + elif event == GO.ETICK: # This runs every 1/60 secs (each tick) + return True # Return whether or not the loop should continue. + elif event == GO.EELEMENTCLICK: # Some UI element got clicked! + if element.type == GO.TBUTTON: + # This gets passed 'element': the element that got clicked. TODO: make an Element class + # The == means element's uid == __ + # UID gets generated based off order: so UID of 2 means second thing created that makes a UID. + # When you create a thing that makes a UID it returns it. e.g. button1 = G.add_button(etc.) + # So in that example button1 is the UID. Maybe try saving it to the container tho! Example shown by the exit button. + if element == 2: + succeeded, ret = test_loading() + G.Container.txt = ('Ran for %i seconds%s' % (ret['i']+1, (' Successfully! :)' if succeeded else ' And failed :('))) + G.Reload() + elif element == G.Container.exitbtn: + G.Abort() + elif element == 1: + bot = GO.PNEW([0, 0], GO.PSTACKS[GO.PCBOTTOM][1], 1) + G.add_TextBox('HALLOOOO! :)', bot) + G.Container.idx = 0 + else: + G.Container.txt = element.txt # put name of button in middle + G.Reload() + elif element.type == GO.TTEXTBOX: + if G.Container.idx == 0: + element.set_text("Happy coding!") + G.Container.idx = 1 + else: + element.remove() + elif event == GO.EEVENT: # When something like a button is pressed. Is passed 'element' too, but this time it is an event + if element.type == pygame.KEYDOWN: + if element.key == pygame.K_SPACE: + G.Container.txt = 'You pressed space!' + G.Reload() + elif event == GO.ELAST: + # This also gets passed 'aborted': Whether you aborted or exited the screen + return aborted # Whatever you return here will be returned by the function + print(test(t)) + pygame.quit() # this here for very fast quitting -root = Tk.Tk() -Tk.Button(root, text='Demo 1', command=demo1).pack() -Tk.Button(root, text='Demo 2', command=demo2).pack() -root.mainloop() +if __name__ == '__main__': + root = Tk.Tk() + def cmd(cmdd): + root.quit() + cmdd() + Tk.Button(root, text='Loading demo', command=lambda: cmd(loadingDemo)).pack() + Tk.Button(root, text='Graphics Demo', command=lambda: cmd(GraphicsDemo)).pack() + root.mainloop() diff --git a/graphics/graphics.py b/graphics/graphics.py index 105a6f9..8f91158 100644 --- a/graphics/graphics.py +++ b/graphics/graphics.py @@ -373,76 +373,7 @@ def Abort(self): self.ab = True if __name__ == '__main__': - from time import sleep - t = input('Please input the starting text for the middle: ') G = Graphic() - @G.Loading - def test_loading(self): - for self.i in range(10): - sleep(1) - - @G.Graphic - def test(event, txt, element=None, aborted=False): # You do not need args and kwargs if you KNOW that your function will not take them in. Include what you need. - if event == GO.EFIRST: # First, before anything else happens in the function - G.Container.txt = txt - if event == GO.ELOADUI: # Load the graphics - CTOP = GO.PNEW([1, 0], GO.PSTACKS[GO.PCTOP][1], 0) # Bcos usually the Center Top makes the elements stack down, so I make a new thing that stacks sideways - G.Clear() - G.add_text('HI', GO.CGREEN, GO.PRBOTTOM, GO.FTITLE) - G.add_text(':) ', GO.CBLACK, GO.PRBOTTOM, GO.FTITLE) - G.add_empty_space(GO.PCCENTER, 0, -150) # Yes, you can have negative space. This makes the next things shifted the other direction. - G.add_text('This is a cool thing', GO.CBLUE, GO.PCCENTER) - G.add_text('Sorry, I meant a cool TEST', GO.CRED, GO.PCCENTER) - G.add_text(G.Container.txt, GO.CGREEN, GO.PCCENTER) - G.add_empty_space(GO.PCBOTTOM, 0, 20) - G.add_button('Button 1 :D', GO.CYELLOW, GO.PCBOTTOM) - G.add_text('Buttons above [^] and below [v]', GO.CBLUE, GO.PCBOTTOM) - G.add_button('Textbox test', GO.CBLUE, GO.PCBOTTOM) - G.add_button('Loading test', GO.CGREEN, GO.PCBOTTOM) - G.Container.exitbtn = G.add_button('EXIT', GO.CRED, GO.PCBOTTOM) - G.add_empty_space(CTOP, -150, 0) # Center it a little more - G.add_text('Are you ', GO.CBLACK, CTOP) - G.add_text('happy? ', GO.CGREEN, CTOP) - G.add_text('Or sad?', GO.CRED, CTOP) - elif event == GO.ETICK: # This runs every 1/60 secs (each tick) - return True # Return whether or not the loop should continue. - elif event == GO.EELEMENTCLICK: # Some UI element got clicked! - if element.type == GO.TBUTTON: - # This gets passed 'element': the element that got clicked. TODO: make an Element class - # The == means element's uid == __ - # UID gets generated based off order: so UID of 2 means second thing created that makes a UID. - # When you create a thing that makes a UID it returns it. e.g. button1 = G.add_button(etc.) - # So in that example button1 is the UID. Maybe try saving it to the container tho! Example shown by the exit button. - if element == 2: - succeeded, ret = test_loading() - G.Container.txt = ('Ran for %i seconds%s' % (ret['i']+1, (' Successfully! :)' if succeeded else ' And failed :('))) - G.Reload() - elif element == G.Container.exitbtn: - G.Abort() - elif element == 1: - bot = GO.PNEW([0, 0], GO.PSTACKS[GO.PCBOTTOM][1], 1) - G.add_TextBox('HALLOOOO! :)', bot) - G.Container.idx = 0 - else: - G.Container.txt = element.txt # put name of button in middle - G.Reload() - elif element.type == GO.TTEXTBOX: - if G.Container.idx == 0: - element.set_text("Happy coding!") - G.Container.idx = 1 - else: - element.remove() - elif event == GO.EEVENT: # When something like a button is pressed. Is passed 'element' too, but this time it is an event - if element.type == pygame.KEYDOWN: - if element.key == pygame.K_SPACE: - G.Container.txt = 'You pressed space!' - G.Reload() - elif event == GO.ELAST: - # This also gets passed 'aborted': Whether you aborted or exited the screen - return aborted # Whatever you return here will be returned by the function - - print(test(t)) - # Copy this scaffold for your own code :) # Args and kwargs are passed through from the initial call of the func @G.Graphic # If you use classes, make this CGraphics and add a `self` argument to the function @@ -459,4 +390,3 @@ def funcname(event, *args, element=None, aborted=False, **kwargs): pass elif event == GO.ELAST: # Passed 'aborted' pass # Whatever you return here will be returned by the function - pygame.quit() # this here for very fast quitting diff --git a/graphics/loading.py b/graphics/loading.py index e700da7..b1d574a 100644 --- a/graphics/loading.py +++ b/graphics/loading.py @@ -76,16 +76,3 @@ def __call__(self, *args): t.raise_exception() return (not end), {i:getattr(m,i) for i in dir(m) if i not in dir(main)} return func2 - -if __name__ == '__main__': - @Loading - def f(self): - for self.i in range(10): - sleep(1) - pygame.init() - WIN = pygame.display.set_mode() - font = pygame.font.Font(None, 64) - succeeded, ret = f(WIN, font) - pygame.quit() - print('Ran for %i seconds%s' % (ret['i'], (' Successfully! :)' if succeeded else ' And failed :('))) - print('end') From 9c781c11260f3a9ffca5ad8b2f4c0ace0603b351 Mon Sep 17 00:00:00 2001 From: Max Worrall <96847801+Tsunami014@users.noreply.github.com> Date: Thu, 16 Nov 2023 15:42:58 +1100 Subject: [PATCH 06/91] =?UTF-8?q?feat(worlds):=20=F0=9F=9A=9A=20Moved=20te?= =?UTF-8?q?rrainGen=20and=20world=20demos=20to=20demos.py?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- demos.py | 25 ++++++++++++++++++++++++- utils/terrainGen.py | 14 -------------- utils/world.py | 4 ---- 3 files changed, 24 insertions(+), 19 deletions(-) diff --git a/demos.py b/demos.py index c176766..f860c10 100644 --- a/demos.py +++ b/demos.py @@ -90,11 +90,34 @@ def test(event, txt, element=None, aborted=False): # You do not need args and kw print(test(t)) pygame.quit() # this here for very fast quitting +def worldsDemo(): + from utils import World + World('test', 'Test World', 'A world for testing random stuff', 25, quality=500, override=True) + +def terrainGenDemo(): + from random import randint + from utils import MapGen + size = 1500 + n = 256 + inp = input('Input nothing to use random seed, input "." to use a preset good seed, or input your own INTEGER seed > ') + if inp == '': + map_seed = randint(0, 999999) + elif inp == '.': + map_seed = 762345 + else: + map_seed = int(inp) + useall = input('Type anything here to show all steps in terrain generation, or leave this blank and press enter to just show the finished product. > ') != '' + outs, trees = MapGen(size, map_seed, n, useall=useall, showAtEnd=True).outs + print(outs[0]) + pass + if __name__ == '__main__': root = Tk.Tk() def cmd(cmdd): root.quit() cmdd() - Tk.Button(root, text='Loading demo', command=lambda: cmd(loadingDemo)).pack() + Tk.Button(root, text='Loading Demo', command=lambda: cmd(loadingDemo)).pack() Tk.Button(root, text='Graphics Demo', command=lambda: cmd(GraphicsDemo)).pack() + Tk.Button(root, text='Generate World Demo', command=lambda: cmd(worldsDemo)).pack() + Tk.Button(root, text='Generate Terrain Demo', command=lambda: cmd(terrainGenDemo)).pack() root.mainloop() diff --git a/utils/terrainGen.py b/utils/terrainGen.py index 5ba99a1..ac6a521 100644 --- a/utils/terrainGen.py +++ b/utils/terrainGen.py @@ -844,17 +844,3 @@ def __init__(self, size, map_seed=762345, n=256, **kwargs): height_map = norm_map * scaling_factor # Convert to heights out = [[round(j) for j in i] for i in height_map] self.outs = ([out, colour_map, rivers_biome_colour_map, adjusted_height_river_map, river_land_mask, biome_masks], trees) - -if __name__ == '__main__': - size = 1500 - n = 256 - inp = input('Input nothing to use random seed, input "." to use a preset good seed, or input your own INTEGER seed > ') - if inp == '': - map_seed = randint(0, 999999) - elif inp == '.': - map_seed = 762345 - else: - map_seed = int(inp) - useall = input('Type anything here to show all steps in terrain generation, or leave this blank and press enter to just show the finished product. > ') != '' - outs, trees = MapGen(size, map_seed, n, useall=useall, showAtEnd=True).outs - print(outs[0]) diff --git a/utils/world.py b/utils/world.py index 35cebbf..e55fa11 100644 --- a/utils/world.py +++ b/utils/world.py @@ -152,7 +152,3 @@ def __init__(self, filename, name='', idea='', size=None, size2=50, quality=500, def get_pygame(self, lvl=0): if self.data != {}: return ldtk.LdtkJSON(self.data, folder).levels[lvl].layers[1].getImg() # TODO: have a number in the intgrid specifically for oceans, and get that from the terrain gen - -if __name__ == '__main__': - w = World('test', 'Test World', 'A world for testing random stuff', 25, quality=500, override=True) - pass From 58b883d1c29ee3da98ff2b23a597982f054663c5 Mon Sep 17 00:00:00 2001 From: Max Worrall <96847801+Tsunami014@users.noreply.github.com> Date: Thu, 16 Nov 2023 15:47:04 +1100 Subject: [PATCH 07/91] =?UTF-8?q?feat(other):=20=F0=9F=9A=9A=20Added=20asy?= =?UTF-8?q?nc=5Fhandling=20demo=20to=20demos.py?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- demos.py | 22 ++++++++++++++++++++++ graphics/async_handling.py | 30 ------------------------------ 2 files changed, 22 insertions(+), 30 deletions(-) diff --git a/demos.py b/demos.py index f860c10..07094ec 100644 --- a/demos.py +++ b/demos.py @@ -111,6 +111,27 @@ def terrainGenDemo(): print(outs[0]) pass +def async_handlingDemo(): # TODO: Improve this demo + import random, asyncio, pygame + from graphics import Progressbar + async def wait_random(): + seconds = random.randint(200, 2000) / 100 + #print(f"Waiting for {seconds} seconds...") + await asyncio.sleep(seconds) + #print(f"Done waiting for {seconds} seconds!") + return seconds + + pygame.init() + WIN = pygame.display.set_mode((800, 600)) + pygame.display.set_caption("Loading Bar Example") + WIN.fill((255, 255, 255)) + pygame.display.update() + bar = Progressbar(600, 50) + tasks = [wait_random() for _ in range(500)] + print(bar(WIN, (WIN.get_width() - 600) // 2, (WIN.get_height() - 50) // 2, 5, tasks)) + asyncio.get_event_loop().stop() + pygame.quit() + if __name__ == '__main__': root = Tk.Tk() def cmd(cmdd): @@ -120,4 +141,5 @@ def cmd(cmdd): Tk.Button(root, text='Graphics Demo', command=lambda: cmd(GraphicsDemo)).pack() Tk.Button(root, text='Generate World Demo', command=lambda: cmd(worldsDemo)).pack() Tk.Button(root, text='Generate Terrain Demo', command=lambda: cmd(terrainGenDemo)).pack() + Tk.Button(root, text='Async Progressbar Demo', command=lambda: cmd(async_handlingDemo)).pack() root.mainloop() diff --git a/graphics/async_handling.py b/graphics/async_handling.py index 233e73c..12ad03d 100644 --- a/graphics/async_handling.py +++ b/graphics/async_handling.py @@ -66,33 +66,3 @@ def run(): self.whileloading(x, y, self.bar.get_width(), self.bar.get_height(), border_width, window, update_func, loadingtxt, loadingtxtColour) #loop.stop() return self.results - -if __name__ == '__main__': - import random - # Define a coroutine function that waits a random amount of time - async def wait_random(): - # Get a random number of seconds between 2 and 20 - seconds = random.randint(200, 2000) / 100 - # Print a message - #print(f"Waiting for {seconds} seconds...") - # Wait for that amount of time - await asyncio.sleep(seconds) - # Print another message - #print(f"Done waiting for {seconds} seconds!") - return seconds - - # now we initialise pygame and load the window for our demo - pygame.init() - WIN = pygame.display.set_mode((800, 600)) - pygame.display.set_caption("Loading Bar Example") - WIN.fill(WHITE) - pygame.display.update() - # create a loading bar object - bar = Progressbar(600, 50) - # create a list of tasks to be completed - tasks = [wait_random() for _ in range(500)] - # run the loading bar - print(bar(WIN, (WIN.get_width() - 600) // 2, (WIN.get_height() - 50) // 2, 5, tasks)) - asyncio.get_event_loop().stop() - # exit pygame - pygame.quit() From 560e45861bfb307b1568e1b89b4fca2f0d692b21 Mon Sep 17 00:00:00 2001 From: Max Worrall <96847801+Tsunami014@users.noreply.github.com> Date: Thu, 16 Nov 2023 16:02:13 +1100 Subject: [PATCH 08/91] =?UTF-8?q?feat(other):=20=F0=9F=92=84=20Moved=20the?= =?UTF-8?q?=20very=20annoying=20async=20handling=20functions=20into=20the?= =?UTF-8?q?=20Graphic=20class=20:)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- demos.py | 15 +++++---------- graphics/graphics.py | 24 +++++++++++++++++++++++- 2 files changed, 28 insertions(+), 11 deletions(-) diff --git a/demos.py b/demos.py index 07094ec..b6c9663 100644 --- a/demos.py +++ b/demos.py @@ -111,9 +111,11 @@ def terrainGenDemo(): print(outs[0]) pass -def async_handlingDemo(): # TODO: Improve this demo +def async_handlingDemo(): import random, asyncio, pygame - from graphics import Progressbar + from graphics import Graphic + G = Graphic() + async def wait_random(): seconds = random.randint(200, 2000) / 100 #print(f"Waiting for {seconds} seconds...") @@ -121,15 +123,8 @@ async def wait_random(): #print(f"Done waiting for {seconds} seconds!") return seconds - pygame.init() - WIN = pygame.display.set_mode((800, 600)) - pygame.display.set_caption("Loading Bar Example") - WIN.fill((255, 255, 255)) - pygame.display.update() - bar = Progressbar(600, 50) tasks = [wait_random() for _ in range(500)] - print(bar(WIN, (WIN.get_width() - 600) // 2, (WIN.get_height() - 50) // 2, 5, tasks)) - asyncio.get_event_loop().stop() + G.PBLoading(tasks) pygame.quit() if __name__ == '__main__': diff --git a/graphics/graphics.py b/graphics/graphics.py index 8f91158..01eb7b7 100644 --- a/graphics/graphics.py +++ b/graphics/graphics.py @@ -1,14 +1,16 @@ -import pygame +import pygame, asyncio pygame.init() try: import graphics.graphics_options as GO from graphics.loading import Loading + from graphics.async_handling import Progressbar from graphics.GUI.randomGUIelements import Button from graphics.GUI import TextBoxFrame from graphics.GUI.textboxify.borders import LIGHT except: import graphics_options as GO from loading import Loading + from async_handling import Progressbar from GUI.randomGUIelements import Button from GUI import TextBoxFrame from GUI.textboxify.borders import LIGHT @@ -149,6 +151,26 @@ def func2(): return Loading(func)(self.WIN, GO.FTITLE) return func2 + def PBLoading(self, tasks): + """Have a loading screen! Like G.Loading, but with a progressbar! + + Parameters + ---------- + tasks : list[async functions] + The list of async functions to run. + + Returns + ------- + list + The output list of all the return values of each of the functions inputted + """ + self.WIN.fill(GO.CWHITE) + pygame.display.update() + pbar = Progressbar(600, 50) + res = pbar(self.WIN, (self.size[0] - 600) // 2, (self.size[1] - 50) // 2, 5, tasks) + asyncio.get_event_loop().stop() + return res + def CGraphic(self, funcy): # Function decorator, not to be called def func2(slf, *args, **kwargs): self.Graphic(funcy, slf)(*args, **kwargs) # Yes I know I'm calling it here. Deal with it. From f00a548477da043d2ffb9bf14e101f02748adba2 Mon Sep 17 00:00:00 2001 From: Max Worrall <96847801+Tsunami014@users.noreply.github.com> Date: Thu, 16 Nov 2023 16:03:05 +1100 Subject: [PATCH 09/91] =?UTF-8?q?fix(main):=20=F0=9F=90=9B=20Fixed=20tkint?= =?UTF-8?q?er=20window=20quitting=20issue?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit root.quit didn't work: changed to root.destroy --- demos.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/demos.py b/demos.py index b6c9663..ea83a98 100644 --- a/demos.py +++ b/demos.py @@ -130,7 +130,7 @@ async def wait_random(): if __name__ == '__main__': root = Tk.Tk() def cmd(cmdd): - root.quit() + root.destroy() cmdd() Tk.Button(root, text='Loading Demo', command=lambda: cmd(loadingDemo)).pack() Tk.Button(root, text='Graphics Demo', command=lambda: cmd(GraphicsDemo)).pack() From 9e702d0c72a58cbb3ba2c69024a7e14f1927359f Mon Sep 17 00:00:00 2001 From: Max Worrall <96847801+Tsunami014@users.noreply.github.com> Date: Thu, 16 Nov 2023 16:04:24 +1100 Subject: [PATCH 10/91] =?UTF-8?q?feat(main):=20=E2=9C=A8=20Tiny=20addition?= =?UTF-8?q?=20of=20print?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It was in the original and got removed, so I put it back --- demos.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/demos.py b/demos.py index ea83a98..373527a 100644 --- a/demos.py +++ b/demos.py @@ -124,7 +124,7 @@ async def wait_random(): return seconds tasks = [wait_random() for _ in range(500)] - G.PBLoading(tasks) + print(G.PBLoading(tasks)) pygame.quit() if __name__ == '__main__': From 23afca929ba1d098bac825ce4107492454a0d072 Mon Sep 17 00:00:00 2001 From: Max Worrall <96847801+Tsunami014@users.noreply.github.com> Date: Thu, 16 Nov 2023 16:07:12 +1100 Subject: [PATCH 11/91] =?UTF-8?q?feat(GUI):=20=F0=9F=9A=9A=20Moved=20the?= =?UTF-8?q?=20input=20box=20demo=20to=20demos.py?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- demos.py | 9 +++++++++ graphics/GUI/inputbox.py | 5 ----- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/demos.py b/demos.py index 373527a..b52caf1 100644 --- a/demos.py +++ b/demos.py @@ -127,6 +127,14 @@ async def wait_random(): print(G.PBLoading(tasks)) pygame.quit() +def inputBoxDemo(): # TODO: make part of Graphic class + import pygame as pg + from graphics.GUI import InputBox + screen = pg.display.set_mode((640, 480)) + input_box = InputBox(100, 100, 140, 32, 'type here!') + print('output:', input_box.interrupt(screen)) + pg.quit() + if __name__ == '__main__': root = Tk.Tk() def cmd(cmdd): @@ -137,4 +145,5 @@ def cmd(cmdd): Tk.Button(root, text='Generate World Demo', command=lambda: cmd(worldsDemo)).pack() Tk.Button(root, text='Generate Terrain Demo', command=lambda: cmd(terrainGenDemo)).pack() Tk.Button(root, text='Async Progressbar Demo', command=lambda: cmd(async_handlingDemo)).pack() + Tk.Button(root, text='Input Box Demo', command=lambda: cmd(inputBoxDemo)).pack() root.mainloop() diff --git a/graphics/GUI/inputbox.py b/graphics/GUI/inputbox.py index 183c6fa..8d2d1c5 100644 --- a/graphics/GUI/inputbox.py +++ b/graphics/GUI/inputbox.py @@ -130,8 +130,3 @@ def interrupt(self, screen, end_on=pg.K_RETURN, run_too=lambda screen: None, eve pg.display.flip() clock.tick(30) return self.text - -if __name__ == '__main__': - screen = pg.display.set_mode((640, 480)) - input_box = InputBox(100, 100, 140, 32, 'type here!') - print('output:', input_box.interrupt(screen)) From e3616368fce9b4b3841a52f0d22a5cd639b92884 Mon Sep 17 00:00:00 2001 From: Max Worrall <96847801+Tsunami014@users.noreply.github.com> Date: Thu, 16 Nov 2023 16:13:58 +1100 Subject: [PATCH 12/91] =?UTF-8?q?feat(main):=20=E2=9C=A8=20Made=20the=20lo?= =?UTF-8?q?ading=20demos=20better?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Joined 2 loading-like demos together --- demos.py | 30 +++++++++++------------------- graphics/graphics.py | 2 +- 2 files changed, 12 insertions(+), 20 deletions(-) diff --git a/demos.py b/demos.py index b52caf1..7e7de94 100644 --- a/demos.py +++ b/demos.py @@ -1,21 +1,5 @@ import tkinter as Tk # Because everyone has tkinter -def loadingDemo(): - import pygame - from graphics import Loading - from time import sleep - @Loading - def f(self): - for self.i in range(10): - sleep(1) - pygame.init() - WIN = pygame.display.set_mode() - font = pygame.font.Font(None, 64) - succeeded, ret = f(WIN, font) - pygame.quit() - print('Ran for %i seconds%s' % (ret['i'], (' Successfully! :)' if succeeded else ' And failed :('))) - print('end') - def GraphicsDemo(): import pygame import graphics.graphics_options as GO @@ -111,9 +95,10 @@ def terrainGenDemo(): print(outs[0]) pass -def async_handlingDemo(): +def LoadingDemo(): import random, asyncio, pygame from graphics import Graphic + from time import sleep G = Graphic() async def wait_random(): @@ -125,7 +110,15 @@ async def wait_random(): tasks = [wait_random() for _ in range(500)] print(G.PBLoading(tasks)) + + @G.Loading + def test_loading(self): + for self.i in range(10): + sleep(1) + + succeeded, ret = test_loading() pygame.quit() + print('Ran for %i seconds%s' % (ret['i'], (' Successfully! :)' if succeeded else ' And failed :('))) def inputBoxDemo(): # TODO: make part of Graphic class import pygame as pg @@ -140,10 +133,9 @@ def inputBoxDemo(): # TODO: make part of Graphic class def cmd(cmdd): root.destroy() cmdd() - Tk.Button(root, text='Loading Demo', command=lambda: cmd(loadingDemo)).pack() + Tk.Button(root, text='Loading Demo', command=lambda: cmd(LoadingDemo)).pack() Tk.Button(root, text='Graphics Demo', command=lambda: cmd(GraphicsDemo)).pack() Tk.Button(root, text='Generate World Demo', command=lambda: cmd(worldsDemo)).pack() Tk.Button(root, text='Generate Terrain Demo', command=lambda: cmd(terrainGenDemo)).pack() - Tk.Button(root, text='Async Progressbar Demo', command=lambda: cmd(async_handlingDemo)).pack() Tk.Button(root, text='Input Box Demo', command=lambda: cmd(inputBoxDemo)).pack() root.mainloop() diff --git a/graphics/graphics.py b/graphics/graphics.py index 01eb7b7..70b207e 100644 --- a/graphics/graphics.py +++ b/graphics/graphics.py @@ -151,7 +151,7 @@ def func2(): return Loading(func)(self.WIN, GO.FTITLE) return func2 - def PBLoading(self, tasks): + def PBLoading(self, tasks): # TODO: allow aborting """Have a loading screen! Like G.Loading, but with a progressbar! Parameters From 13b8af562ca862637b70fa4f0992b6136be62a6d Mon Sep 17 00:00:00 2001 From: Max Worrall <96847801+Tsunami014@users.noreply.github.com> Date: Thu, 16 Nov 2023 16:18:59 +1100 Subject: [PATCH 13/91] =?UTF-8?q?feat(conversation):=20=F0=9F=9A=9A=20Move?= =?UTF-8?q?d=20conversation=20parser=20demo=20to=20demos.py?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- demos.py | 23 +++++ .../conversation_parse/conversation_parser.py | 88 +++++++------------ 2 files changed, 57 insertions(+), 54 deletions(-) diff --git a/demos.py b/demos.py index 7e7de94..16f1a80 100644 --- a/demos.py +++ b/demos.py @@ -128,6 +128,28 @@ def inputBoxDemo(): # TODO: make part of Graphic class print('output:', input_box.interrupt(screen)) pg.quit() +def conversation_parserDemo(): + from utils.conversation_parse import Generator + # If you run this file you can see these next statements at work + # Each you can see is separated, by a like of ~~~~~~~~~~ + # You can see the different start params at work, with the same sample prompt + def gen(): + g = Generator() + yield g([(1, 2), 2]) + yield g([(0, 0), 3]) + yield g([(0, 3), 1]) + yield g([(3, 1), 2]) + yield g([(0, 2), 0]) + yield '\nAnd here are some randomly generated ones:\n' + g() + while True: + yield g() + g = gen() + print('Here are some I prepared earlier:\n') + while True: + print(next(g)) + if input() != '': + break + if __name__ == '__main__': root = Tk.Tk() def cmd(cmdd): @@ -138,4 +160,5 @@ def cmd(cmdd): Tk.Button(root, text='Generate World Demo', command=lambda: cmd(worldsDemo)).pack() Tk.Button(root, text='Generate Terrain Demo', command=lambda: cmd(terrainGenDemo)).pack() Tk.Button(root, text='Input Box Demo', command=lambda: cmd(inputBoxDemo)).pack() + Tk.Button(root, text='Conversation Parse Demo', command=lambda: cmd(conversation_parserDemo)).pack() root.mainloop() diff --git a/utils/conversation_parse/conversation_parser.py b/utils/conversation_parse/conversation_parser.py index 4eaaf81..dc27f3f 100644 --- a/utils/conversation_parse/conversation_parser.py +++ b/utils/conversation_parse/conversation_parser.py @@ -472,57 +472,37 @@ def cycle(my_list, start_at=None): yield my_list[start_at] start_at = (start_at + 1) % len(my_list) -if __name__ == '__main__': - from random import shuffle, choice, randint - class Generator: - def __init__(self): - l = list(range(91, 96)) - shuffle(l) - self.order = cycle(l) - self.order2 = cycle(l, 2) - def generate_desc(self): - K = Knowledge('Grapefruit') - self.args = {'is_adjs':choice([None, 'nice', 'nice/kind', 'nice/kind/happy/beautiful']), - 'is_a':choice([None, 'dragon', 'human', 'elf', 'wizard', 'brown dog']), - 'who':choice([None, 'loves life', 'reads lots/codes', 'gets bored easily/loves life/reads a lot/codes', 'always wears brown clothing']) - } - K.add_clause(**self.args) - return K.get(0) - def __call__(self, start=None): - out = '' - if start == None: start = [(randint(0, 3), randint(0, 4)), randint(0, len(STARTPARAM1)-1)] - sample_prompt = choice([ - [{'role': 'user', 'content': 'Hello! How are you?'}, {'role': 'bot', 'content': 'I am good, how are you?'}, {'role': 'user', 'content': 'I am good too! What did you do today?'}], - [{'role': 'user', 'content': 'Hello'}, {'role': 'bot', 'content': 'Hello! What can I help you with today?'}, {'role': 'user', 'content': 'I dunno...'}, {'role': 'bot', 'content': 'Well, I can help you with anything! Just pick a topic!'}, {'role': 'user', 'content': 'I like books'}, {'role': 'bot', 'content': 'I like books too! What is your favourite book?'}, {'role': 'user', 'content': 'I like Harry Potter'}], - [{'role': 'user', 'content': 'Hello! How are you?'}, {'role': 'bot', 'content': 'What can I help you with?'}, {'role': 'user', 'content': 'I need help with a Python project.'}], - [{'role': 'user', 'content': 'What is the best way to handle errors in Python?'}, {'role': 'bot', 'content': 'There are several ways to handle errors in Python, such as using try-except blocks or raising exceptions. What kind of errors are you trying to handle?'}, {'role': 'user', 'content': 'I\'m trying to handle file I/O errors.'}], - [{'role': 'user', 'content': 'How do I install a Python package using pip?'}, {'role': 'bot', 'content': 'You can install a Python package using pip by running the command "pip install package_name" in your terminal. Have you used pip before?'}, {'role': 'user', 'content': 'No, I haven\'t. Can you walk me through it?'}] - ]) - sample_desc = 'You are Grapefruit. '+self.generate_desc() - self.args['start'] = start - out += '\033[%sm| ' % str(next(self.order2)) - pretty = lambda x: '"' if isinstance(x, str) else '' - for i in self.args: out += i+' : '+pretty(self.args[i])+str(self.args[i])+pretty(self.args[i])+' | ' - out += '\033[0m\n' - out += PARSE(start, sample_desc, sample_prompt, 'Grapefruit')+'\n' - out += '\033[%sm~~~~~~~~~~~~~~~~~~~~~~~~~\033[0m' % str(next(self.order)) - return out - # If you run this file you can see these next statements at work - # Each you can see is separated, by a like of ~~~~~~~~~~ - # You can see the different start params at work, with the same sample prompt - def gen(): - g = Generator() - yield g([(1, 2), 2]) - yield g([(0, 0), 3]) - yield g([(0, 3), 1]) - yield g([(3, 1), 2]) - yield g([(0, 2), 0]) - yield '\nAnd here are some randomly generated ones:\n' + g() - while True: - yield g() - g = gen() - print('Here are some I prepared earlier:\n') - while True: - print(next(g)) - if input() != '': - break +from random import shuffle, choice, randint +class Generator: + def __init__(self): + l = list(range(91, 96)) + shuffle(l) + self.order = cycle(l) + self.order2 = cycle(l, 2) + def generate_desc(self): + K = Knowledge('Grapefruit') + self.args = {'is_adjs':choice([None, 'nice', 'nice/kind', 'nice/kind/happy/beautiful']), + 'is_a':choice([None, 'dragon', 'human', 'elf', 'wizard', 'brown dog']), + 'who':choice([None, 'loves life', 'reads lots/codes', 'gets bored easily/loves life/reads a lot/codes', 'always wears brown clothing']) + } + K.add_clause(**self.args) + return K.get(0) + def __call__(self, start=None): + out = '' + if start == None: start = [(randint(0, 3), randint(0, 4)), randint(0, len(STARTPARAM1)-1)] + sample_prompt = choice([ + [{'role': 'user', 'content': 'Hello! How are you?'}, {'role': 'bot', 'content': 'I am good, how are you?'}, {'role': 'user', 'content': 'I am good too! What did you do today?'}], + [{'role': 'user', 'content': 'Hello'}, {'role': 'bot', 'content': 'Hello! What can I help you with today?'}, {'role': 'user', 'content': 'I dunno...'}, {'role': 'bot', 'content': 'Well, I can help you with anything! Just pick a topic!'}, {'role': 'user', 'content': 'I like books'}, {'role': 'bot', 'content': 'I like books too! What is your favourite book?'}, {'role': 'user', 'content': 'I like Harry Potter'}], + [{'role': 'user', 'content': 'Hello! How are you?'}, {'role': 'bot', 'content': 'What can I help you with?'}, {'role': 'user', 'content': 'I need help with a Python project.'}], + [{'role': 'user', 'content': 'What is the best way to handle errors in Python?'}, {'role': 'bot', 'content': 'There are several ways to handle errors in Python, such as using try-except blocks or raising exceptions. What kind of errors are you trying to handle?'}, {'role': 'user', 'content': 'I\'m trying to handle file I/O errors.'}], + [{'role': 'user', 'content': 'How do I install a Python package using pip?'}, {'role': 'bot', 'content': 'You can install a Python package using pip by running the command "pip install package_name" in your terminal. Have you used pip before?'}, {'role': 'user', 'content': 'No, I haven\'t. Can you walk me through it?'}] + ]) + sample_desc = 'You are Grapefruit. '+self.generate_desc() + self.args['start'] = start + out += '\033[%sm| ' % str(next(self.order2)) + pretty = lambda x: '"' if isinstance(x, str) else '' + for i in self.args: out += i+' : '+pretty(self.args[i])+str(self.args[i])+pretty(self.args[i])+' | ' + out += '\033[0m\n' + out += PARSE(start, sample_desc, sample_prompt, 'Grapefruit')+'\n' + out += '\033[%sm~~~~~~~~~~~~~~~~~~~~~~~~~\033[0m' % str(next(self.order)) + return out From 00a4b590631758973238157e126b079e3a984ac2 Mon Sep 17 00:00:00 2001 From: Max Worrall <96847801+Tsunami014@users.noreply.github.com> Date: Fri, 17 Nov 2023 08:09:07 +1100 Subject: [PATCH 14/91] =?UTF-8?q?feat(AIs):=20=F0=9F=9A=9A=20Moved=20AIs'?= =?UTF-8?q?=20demos=20into=20demos.py?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Moved demos from install_tinyllm.py, set_preferences.py & tinyllm.py --- demos.py | 27 +++++++++++++++++++++++++++ utils/bot/install_tinyllm.py | 3 --- utils/bot/set_preferences.py | 4 ---- utils/bot/tinyllm.py | 15 --------------- 4 files changed, 27 insertions(+), 22 deletions(-) diff --git a/demos.py b/demos.py index 16f1a80..dac59db 100644 --- a/demos.py +++ b/demos.py @@ -149,6 +149,30 @@ def gen(): print(next(g)) if input() != '': break +def tinyLLMDemo(): + import asyncio + from utils.bot import TinyLLM, lm + tllm = TinyLLM() + prompt = f"System: Reply as a helpful assistant. Currently {lm.get_date()}." + while True: + inp = input('> ') + if inp == '': break + prompt += f"\n\nUser: {inp}" + i = asyncio.run(tllm.interrupt(inp)) + prompt += "\n\nAssistant:" + end = asyncio.run(tllm(prompt)) + print(i) + print(end) + prompt += f" {end}" + +def testLLMDemo(): + from utils.bot import test_tinyllm + test_tinyllm() + +def rateAIsDemo(): + import asyncio + from utils.bot import rate_all + asyncio.run(rate_all()) if __name__ == '__main__': root = Tk.Tk() @@ -161,4 +185,7 @@ def cmd(cmdd): Tk.Button(root, text='Generate Terrain Demo', command=lambda: cmd(terrainGenDemo)).pack() Tk.Button(root, text='Input Box Demo', command=lambda: cmd(inputBoxDemo)).pack() Tk.Button(root, text='Conversation Parse Demo', command=lambda: cmd(conversation_parserDemo)).pack() + Tk.Button(root, text='TinyLLM Demo', command=lambda: cmd(tinyLLMDemo)).pack() + Tk.Button(root, text='Test LLM Demo', command=lambda: cmd(testLLMDemo)).pack() + Tk.Button(root, text='Rate AIs Demo', command=lambda: cmd(rateAIsDemo)).pack() root.mainloop() diff --git a/utils/bot/install_tinyllm.py b/utils/bot/install_tinyllm.py index 11abf8e..09db70d 100644 --- a/utils/bot/install_tinyllm.py +++ b/utils/bot/install_tinyllm.py @@ -98,6 +98,3 @@ def test_tinyllm(): lm.store_doc(lm.get_wiki("C language"), "C") lm.store_doc(lm.get_wiki("Javascript"), "Javascript") print(lm.get_doc_context("What does it mean for batteries to be included in a language?")) - -if __name__ == '__main__': - test_tinyllm() \ No newline at end of file diff --git a/utils/bot/set_preferences.py b/utils/bot/set_preferences.py index 169bfd2..9a96134 100644 --- a/utils/bot/set_preferences.py +++ b/utils/bot/set_preferences.py @@ -55,7 +55,3 @@ async def rate_all(resps=None): else: out[name] = int(rating) i += 1 set_preferences(out) - -if __name__ == '__main__': - import asyncio - asyncio.run(rate_all()) diff --git a/utils/bot/tinyllm.py b/utils/bot/tinyllm.py index 62a14ba..d316d6d 100644 --- a/utils/bot/tinyllm.py +++ b/utils/bot/tinyllm.py @@ -67,18 +67,3 @@ async def interrupt(self, txt, ram=None): lm.set_max_ram(ram) if lm.classify(txt,"simple reply","complex reply") == 'complex reply': return 'l' return 's' - -if __name__ == '__main__': - import asyncio - tllm = TinyLLM() - prompt = f"System: Reply as a helpful assistant. Currently {lm.get_date()}." - while True: - inp = input('> ') - if inp == '': break - prompt += f"\n\nUser: {inp}" - i = asyncio.run(tllm.interrupt(inp)) - prompt += "\n\nAssistant:" - end = asyncio.run(tllm(prompt)) - print(i) - print(end) - prompt += f" {end}" From c123d1f29f485d3db36fe9a07ad71fa65d36a480 Mon Sep 17 00:00:00 2001 From: Max Worrall <96847801+Tsunami014@users.noreply.github.com> Date: Fri, 17 Nov 2023 08:21:58 +1100 Subject: [PATCH 15/91] =?UTF-8?q?feat(ALL=20:D):=20=F0=9F=9A=91=EF=B8=8F?= =?UTF-8?q?=20Fixed=20ALL=20the=20import=20statements=20of=20ALL=20the=20l?= =?UTF-8?q?ines=20of=20code!=20:D=20:D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit I hope this isn't bugged. I have not tested many things I should be testing... --- graphics/GUI/__init__.py | 20 ++++------------ graphics/GUI/example.py | 11 +++------ graphics/GUI/pyguix/__init__.py | 8 +------ graphics/GUI/pyguix/ui/elements.py | 8 +------ graphics/GUI/pyguix/utils.py | 16 +++---------- graphics/GUI/textboxify/__init__.py | 22 +++++------------- graphics/graphics.py | 20 +++++----------- main.py | 1 - requirements.txt | 1 + utils/Pyldtk.py | 2 +- utils/bot/AIs.py | 13 +---------- utils/bot/__init__.py | 23 ++++++------------- utils/bot/basebots.py | 13 +---------- utils/bot/copilot.py | 10 ++------ utils/bot/set_preferences.py | 17 +++----------- utils/bot/tinyllm.py | 8 +------ utils/characters.py | 8 ++----- utils/conversation_parse/__init__.py | 8 ++----- .../conversation_parse/conversation_parser.py | 8 +------ utils/converse.py | 1 - utils/discussions.py | 1 - utils/terrainGen.py | 8 +------ utils/world.py | 14 ++++------- 23 files changed, 51 insertions(+), 190 deletions(-) diff --git a/graphics/GUI/__init__.py b/graphics/GUI/__init__.py index 1fd7fc3..3ea66b1 100644 --- a/graphics/GUI/__init__.py +++ b/graphics/GUI/__init__.py @@ -1,16 +1,4 @@ -try: - from graphics.GUI.inputbox import RESIZE_W, RESIZE_H, RESIZE_NONE, InputBox, renderTextCenteredAt - from graphics.GUI.pyguix import * - from graphics.GUI.textboxify import * - from graphics.GUI.randomGUIelements import * -except ImportError: - try: - from GUI.inputbox import RESIZE_W, RESIZE_H, RESIZE_NONE, InputBox, renderTextCenteredAt - from GUI.pyguix import * - from GUI.textboxify import * - from GUI.randomGUIelements import * - except ImportError: - from inputbox import RESIZE_W, RESIZE_H, RESIZE_NONE, InputBox, renderTextCenteredAt - from pyguix import * - from textboxify import * - from randomGUIelements import * \ No newline at end of file +from graphics.GUI.inputbox import RESIZE_W, RESIZE_H, RESIZE_NONE, InputBox, renderTextCenteredAt +from graphics.GUI.pyguix import * +from graphics.GUI.textboxify import * +from graphics.GUI.randomGUIelements import * diff --git a/graphics/GUI/example.py b/graphics/GUI/example.py index 26c4c29..fa83164 100644 --- a/graphics/GUI/example.py +++ b/graphics/GUI/example.py @@ -1,13 +1,8 @@ import pygame from pygame import locals -try: - from __init__ import InputBox, RESIZE_H, TextBoxFrame - from __init__ import gui as ui - from textboxify.borders import LIGHT, BARBER_POLE -except ImportError: - from graphics.GUI import InputBox, RESIZE_H, TextBoxFrame - from graphics.GUI.pyguix import gui as ui - from graphics.GUI.textboxify.borders import LIGHT, BARBER_POLE +from graphics.GUI import InputBox, RESIZE_H, TextBoxFrame +from graphics.GUI.pyguix import gui as ui +from graphics.GUI.textboxify.borders import LIGHT, BARBER_POLE class SnapHUDPartInfoExample(ui.SnapHUDPartInfo): diff --git a/graphics/GUI/pyguix/__init__.py b/graphics/GUI/pyguix/__init__.py index 33bbc9b..34e7e5a 100644 --- a/graphics/GUI/pyguix/__init__.py +++ b/graphics/GUI/pyguix/__init__.py @@ -16,10 +16,4 @@ # See the License for the specific language governing permissions and # limitations under the License. -try: - from graphics.GUI.pyguix.ui import elements as gui -except ImportError: - try: - from GUI.pyguix.ui import elements as gui - except ImportError: - from pyguix.ui import elements as gui \ No newline at end of file +from graphics.GUI.pyguix.ui import elements as gui \ No newline at end of file diff --git a/graphics/GUI/pyguix/ui/elements.py b/graphics/GUI/pyguix/ui/elements.py index 67376c4..90751df 100644 --- a/graphics/GUI/pyguix/ui/elements.py +++ b/graphics/GUI/pyguix/ui/elements.py @@ -17,13 +17,7 @@ # limitations under the License. import pygame -try: - import graphics.GUI.pyguix.utils as utils -except ImportError: - try: - import GUI.pyguix.utils as utils - except ImportError: - import pyguix.utils as utils +import graphics.GUI.pyguix.utils as utils uth = utils.helper() # NOTE: When an action class is created, the base scope class adds its targetclasses as keys diff --git a/graphics/GUI/pyguix/utils.py b/graphics/GUI/pyguix/utils.py index 3be175c..6ae9d73 100644 --- a/graphics/GUI/pyguix/utils.py +++ b/graphics/GUI/pyguix/utils.py @@ -21,19 +21,9 @@ import dataclasses as dc import enum import json as js -try: - import graphics.GUI.pyguix.ui.themes as th - import graphics.GUI.pyguix.ui.context as cx - import graphics.GUI.pyguix.ui.settings as st -except ImportError: - try: - import GUI.pyguix.ui.themes as th - import GUI.pyguix.ui.context as cx - import GUI.pyguix.ui.settings as st - except ImportError: - import pyguix.ui.themes as th - import pyguix.ui.context as cx - import pyguix.ui.settings as st +import graphics.GUI.pyguix.ui.themes as th +import graphics.GUI.pyguix.ui.context as cx +import graphics.GUI.pyguix.ui.settings as st # Constants: DEFAULT_THEME='default.json' diff --git a/graphics/GUI/textboxify/__init__.py b/graphics/GUI/textboxify/__init__.py index ea35464..344b299 100644 --- a/graphics/GUI/textboxify/__init__.py +++ b/graphics/GUI/textboxify/__init__.py @@ -5,20 +5,10 @@ more elaborated boxes with animations and borders, because the package offers the ability to easily customize the boxes.""" -try: - # These are available when `import textboxify` is used. - from graphics.GUI.textboxify.text import Text - from graphics.GUI.textboxify.textbox import TextBox, TextBoxFrame +# These are available when `import textboxify` is used. +from graphics.GUI.textboxify.text import Text +from graphics.GUI.textboxify.textbox import TextBox, TextBoxFrame - # Border sprites are available with `textboxify.borders.DARK` after import or - # could be imported as: `textboxify.borders import *`. - from graphics.GUI.textboxify import borders -except ImportError: - try: - from GUI.textboxify.text import Text - from GUI.textboxify.textbox import TextBox, TextBoxFrame - from GUI.textboxify import borders - except: - from textboxify.text import Text - from textboxify.textbox import TextBox, TextBoxFrame - from textboxify import borders \ No newline at end of file +# Border sprites are available with `textboxify.borders.DARK` after import or +# could be imported as: `textboxify.borders import *`. +from graphics.GUI.textboxify import borders diff --git a/graphics/graphics.py b/graphics/graphics.py index 70b207e..efc44b9 100644 --- a/graphics/graphics.py +++ b/graphics/graphics.py @@ -1,19 +1,11 @@ import pygame, asyncio pygame.init() -try: - import graphics.graphics_options as GO - from graphics.loading import Loading - from graphics.async_handling import Progressbar - from graphics.GUI.randomGUIelements import Button - from graphics.GUI import TextBoxFrame - from graphics.GUI.textboxify.borders import LIGHT -except: - import graphics_options as GO - from loading import Loading - from async_handling import Progressbar - from GUI.randomGUIelements import Button - from GUI import TextBoxFrame - from GUI.textboxify.borders import LIGHT +import graphics.graphics_options as GO +from graphics.loading import Loading +from graphics.async_handling import Progressbar +from graphics.GUI.randomGUIelements import Button +from graphics.GUI import TextBoxFrame +from graphics.GUI.textboxify.borders import LIGHT class TerminalBar: def __init__(self, win, spacing=5): diff --git a/main.py b/main.py index 9a53ce7..778d2ad 100644 --- a/main.py +++ b/main.py @@ -2,7 +2,6 @@ from utils.bot import TinyLLM, UserBot from graphics.GUI import InputBox, RESIZE_H, TextBoxFrame from graphics.GUI.textboxify.borders import LIGHT -from graphics import Progressbar import pygame, asyncio, random pygame.init() diff --git a/requirements.txt b/requirements.txt index fca82b5..1e058cc 100644 --- a/requirements.txt +++ b/requirements.txt @@ -9,3 +9,4 @@ matplotlib g4f bs4 googlesearch-python +html2text diff --git a/utils/Pyldtk.py b/utils/Pyldtk.py index 124eb40..b5f6e42 100644 --- a/utils/Pyldtk.py +++ b/utils/Pyldtk.py @@ -1,7 +1,7 @@ import json from math import floor import pygame -import os, sys +import os def get_data(file): with open(file, "r") as data: diff --git a/utils/bot/AIs.py b/utils/bot/AIs.py index 590940e..f09451e 100644 --- a/utils/bot/AIs.py +++ b/utils/bot/AIs.py @@ -1,4 +1,4 @@ -import os, sys, time +import os, time import g4f import asyncio, aiohttp @@ -6,17 +6,6 @@ import nest_asyncio nest_asyncio.apply() -if os.getcwd().endswith('bot'): # set path 2 folders above - newpath = os.path.abspath(os.path.join(os.getcwd(), '../../')) - os.chdir(newpath) -elif os.getcwd().endswith('utils'): # set folder to one above - newpath = os.path.abspath(os.path.join(os.getcwd(), '../')) - os.chdir(newpath) - -# now current folder should be '\AIHub' and not '\AIHub\utils' or '\AIHub\utils\bot' anymore! - -sys.path.append(os.getcwd()) - from utils.conversation_parse import PARSE from utils.characters import * from api_keys import loadAPIkeys diff --git a/utils/bot/__init__.py b/utils/bot/__init__.py index 3247415..d9e47c7 100644 --- a/utils/bot/__init__.py +++ b/utils/bot/__init__.py @@ -1,16 +1,7 @@ -try: - from utils.bot.gpt4real import * - from utils.bot.set_preferences import * - from utils.bot.AIs import * - from utils.bot.basebots import * - from utils.bot.install_tinyllm import * - from utils.bot.tinyllm import * - #from utils.bot.copilot import * # errors... -except ImportError: - from bot.gpt4real import * - from bot.set_preferences import * - from bot.AIs import * - from bot.basebots import * - from bot.install_tinyllm import * - from bot.tinyllm import * - #from bot.copilot import * +from utils.bot.gpt4real import * +from utils.bot.set_preferences import * +from utils.bot.AIs import * +from utils.bot.basebots import * +from utils.bot.install_tinyllm import * +from utils.bot.tinyllm import * +#from utils.bot.copilot import * # errors... diff --git a/utils/bot/basebots.py b/utils/bot/basebots.py index 2010a2e..3940559 100644 --- a/utils/bot/basebots.py +++ b/utils/bot/basebots.py @@ -1,16 +1,5 @@ import time, asyncio, aiohttp -import os, sys - -if os.getcwd().endswith('bot'): # set path 2 folders above - newpath = os.path.abspath(os.path.join(os.getcwd(), '../../')) - os.chdir(newpath) -elif os.getcwd().endswith('utils'): # set folder to one above - newpath = os.path.abspath(os.path.join(os.getcwd(), '../')) - os.chdir(newpath) - -# now current folder should be '\AIHub' and not '\AIHub\utils' or '\AIHub\utils\bot' anymore! - -sys.path.append(os.getcwd()) +import os from utils.conversation_parse import PARSE diff --git a/utils/bot/copilot.py b/utils/bot/copilot.py index ef5972b..2178cdd 100644 --- a/utils/bot/copilot.py +++ b/utils/bot/copilot.py @@ -1,14 +1,8 @@ import languagemodels as lm import re from difflib import get_close_matches as GCM -try: - from utils.bot.tinyllm import * -except: - try: - from bot.tinyllm import * - except: - from tinyllm import * -# This will only work with GPT4all. +from utils.bot.tinyllm import * +# This will only work with GPT4All. class Copilot: def __init__(self, name): diff --git a/utils/bot/set_preferences.py b/utils/bot/set_preferences.py index 9a96134..f9fb161 100644 --- a/utils/bot/set_preferences.py +++ b/utils/bot/set_preferences.py @@ -1,16 +1,5 @@ -import json, os -try: - from utils.bot.AIs import AI -except ImportError: - try: - from bot.AIs import AI - except ImportError: - from AIs import AI - -import os, re -bef = re.findall(r'((utils\/?)?(bot)?\n)', os.getcwd().replace('\\','/')+'\n')[0][0][:-1] # inp ends in newline -bef = '/'.join([i for i in ['utils', 'bot'] if i not in bef.split('/')]) -if bef != '': bef += '/' +import json +from utils.bot.AIs import AI def get_all_ais(): return AI().AIs @@ -21,7 +10,7 @@ def get_all_ai_names(): def set_preferences(prefs): eprefs = get_preferences() eprefs.update(prefs) - with open(f'{bef}preferences.json', 'w') as f: + with open(f'/utils/bot/preferences.json', 'w') as f: d = json.load(f) d['models'].update(eprefs) json.dump(d, f, indent=4) diff --git a/utils/bot/tinyllm.py b/utils/bot/tinyllm.py index d316d6d..7451906 100644 --- a/utils/bot/tinyllm.py +++ b/utils/bot/tinyllm.py @@ -1,12 +1,6 @@ import languagemodels as lm import re -try: - from utils.bot.install_tinyllm import installed -except: - try: - from bot.install_tinyllm import installed - except: - from install_tinyllm import installed +from utils.bot.install_tinyllm import installed from googlesearch import search # pip install beautifulsoup4 google import bs4, requests diff --git a/utils/characters.py b/utils/characters.py index 2fa6a48..6c75d9c 100644 --- a/utils/characters.py +++ b/utils/characters.py @@ -1,10 +1,6 @@ import os -try: - from utils.discussions import * - from utils.conversation_parse import PARSE2 -except ImportError: - from discussions import * - from conversation_parse import PARSE2 +from utils.discussions import * +from utils.conversation_parse import PARSE2 class Character: def __init__(self, AI, name, personality): diff --git a/utils/conversation_parse/__init__.py b/utils/conversation_parse/__init__.py index 10a7ce6..7c1f736 100644 --- a/utils/conversation_parse/__init__.py +++ b/utils/conversation_parse/__init__.py @@ -1,6 +1,2 @@ -try: - from utils.conversation_parse.conversation_parser import * - from utils.conversation_parse.consts import * -except ImportError: - from conversation_parse.conversation_parser import * - from conversation_parse.consts import * +from utils.conversation_parse.conversation_parser import * +from utils.conversation_parse.consts import * diff --git a/utils/conversation_parse/conversation_parser.py b/utils/conversation_parse/conversation_parser.py index dc27f3f..9dd30b0 100644 --- a/utils/conversation_parse/conversation_parser.py +++ b/utils/conversation_parse/conversation_parser.py @@ -1,10 +1,4 @@ -try: - from utils.conversation_parse.consts import * -except ImportError: - try: - from conversation_parse.consts import * - except ImportError: - from consts import * +from utils.conversation_parse.consts import * import re from math import inf diff --git a/utils/converse.py b/utils/converse.py index 3cfa213..78e86b0 100644 --- a/utils/converse.py +++ b/utils/converse.py @@ -1,4 +1,3 @@ - # cnvrs = CoNVeRSation/CoNVeRSe class converse: diff --git a/utils/discussions.py b/utils/discussions.py index 3fef443..2a3d05b 100644 --- a/utils/discussions.py +++ b/utils/discussions.py @@ -1,4 +1,3 @@ - import sqlite3 from pathlib import Path __author__ = "parisneo" diff --git a/utils/terrainGen.py b/utils/terrainGen.py index ac6a521..e2c4cbf 100644 --- a/utils/terrainGen.py +++ b/utils/terrainGen.py @@ -1,8 +1,5 @@ # https://github.com/BilHim/minecraft-world-generation/blob/main/src/Minecraft%20Terrain%20Generation%20in%20Python%20-%20By%20Bilal%20Himite.ipynb - # Imports and parameters -# print('Importing...') - from random import randint import numpy as np from matplotlib import pyplot as plt @@ -17,10 +14,7 @@ from scipy.ndimage.filters import gaussian_filter from scipy.ndimage.morphology import binary_dilation -try: - from utils.conversation_parse import parseKWs -except: - from conversation_parse import parseKWs +from utils.conversation_parse import parseKWs class Map: def __init__(self, *args, **kwargs): diff --git a/utils/world.py b/utils/world.py index e55fa11..5b6fa4d 100644 --- a/utils/world.py +++ b/utils/world.py @@ -4,16 +4,10 @@ from math import floor, sqrt from copy import deepcopy -try: - from utils.characters import * - from utils.storyline import * - from utils.terrainGen import * - import utils.Pyldtk as ldtk -except ImportError: - from characters import * - from storyline import * - from terrainGen import * - import Pyldtk as ldtk +from utils.characters import * +from utils.storyline import * +from utils.terrainGen import * +import utils.Pyldtk as ldtk folder = 'data/worlds/' From cb29a3eb3ae9c7a7cc51fba639d966b147ceae66 Mon Sep 17 00:00:00 2001 From: Max Worrall <96847801+Tsunami014@users.noreply.github.com> Date: Fri, 17 Nov 2023 08:23:21 +1100 Subject: [PATCH 16/91] =?UTF-8?q?feat(main):=20=F0=9F=9A=9A=20Moved=20the?= =?UTF-8?q?=20API=20keys=20demo=20to=20demos.py?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- api_keys.py | 3 --- demos.py | 5 +++++ 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/api_keys.py b/api_keys.py index 16dd826..27bfad7 100644 --- a/api_keys.py +++ b/api_keys.py @@ -158,6 +158,3 @@ def __init__(self): # Start the Tkinter main loop self.root.mainloop() - -if __name__ == '__main__': - SaveAPIKeysDialog() \ No newline at end of file diff --git a/demos.py b/demos.py index dac59db..093bf82 100644 --- a/demos.py +++ b/demos.py @@ -174,6 +174,10 @@ def rateAIsDemo(): from utils.bot import rate_all asyncio.run(rate_all()) +def api_keysDemo(): + from api_keys import SaveAPIKeysDialog + SaveAPIKeysDialog() + if __name__ == '__main__': root = Tk.Tk() def cmd(cmdd): @@ -188,4 +192,5 @@ def cmd(cmdd): Tk.Button(root, text='TinyLLM Demo', command=lambda: cmd(tinyLLMDemo)).pack() Tk.Button(root, text='Test LLM Demo', command=lambda: cmd(testLLMDemo)).pack() Tk.Button(root, text='Rate AIs Demo', command=lambda: cmd(rateAIsDemo)).pack() + Tk.Button(root, text='API keys Demo', command=lambda: cmd(rateAIsDemo)).pack() root.mainloop() From baa2d3835487c904b73b26597b9e562886c3d753 Mon Sep 17 00:00:00 2001 From: Max Worrall <96847801+Tsunami014@users.noreply.github.com> Date: Fri, 17 Nov 2023 08:25:06 +1100 Subject: [PATCH 17/91] =?UTF-8?q?feat(GUI):=20=E2=9C=A8=20Added=20(blank)?= =?UTF-8?q?=20NodeEditor=20demo!?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- demos.py | 6 +++++- elementGen/__init__.py | 1 + 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/demos.py b/demos.py index 093bf82..b8564db 100644 --- a/demos.py +++ b/demos.py @@ -178,6 +178,9 @@ def api_keysDemo(): from api_keys import SaveAPIKeysDialog SaveAPIKeysDialog() +def node_editorDemo(): + pass + if __name__ == '__main__': root = Tk.Tk() def cmd(cmdd): @@ -192,5 +195,6 @@ def cmd(cmdd): Tk.Button(root, text='TinyLLM Demo', command=lambda: cmd(tinyLLMDemo)).pack() Tk.Button(root, text='Test LLM Demo', command=lambda: cmd(testLLMDemo)).pack() Tk.Button(root, text='Rate AIs Demo', command=lambda: cmd(rateAIsDemo)).pack() - Tk.Button(root, text='API keys Demo', command=lambda: cmd(rateAIsDemo)).pack() + Tk.Button(root, text='API Keys Demo', command=lambda: cmd(api_keysDemo)).pack() + Tk.Button(root, text='Node Editor Demo', command=lambda: cmd(node_editorDemo)).pack() root.mainloop() diff --git a/elementGen/__init__.py b/elementGen/__init__.py index e69de29..ab7a93f 100644 --- a/elementGen/__init__.py +++ b/elementGen/__init__.py @@ -0,0 +1 @@ +from elementGen.node_editor import * From 68c98292a268ad70d48d7e37f14b1bd873f3f513 Mon Sep 17 00:00:00 2001 From: Max Worrall <96847801+Tsunami014@users.noreply.github.com> Date: Fri, 17 Nov 2023 08:28:31 +1100 Subject: [PATCH 18/91] =?UTF-8?q?feat(GUI):=20=E2=9C=A8=20Made=20the=20bas?= =?UTF-8?q?ic=20NodeEditor=20function!=20Still=20does=20nothing=20yet.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit But also added docstring! --- demos.py | 5 ++++- elementGen/node_editor.py | 16 ++++++++++++++++ 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/demos.py b/demos.py index b8564db..1ac7a6a 100644 --- a/demos.py +++ b/demos.py @@ -179,7 +179,10 @@ def api_keysDemo(): SaveAPIKeysDialog() def node_editorDemo(): - pass + from graphics import Graphic + from elementGen import NodeEditor + G = Graphic() + NodeEditor(G) if __name__ == '__main__': root = Tk.Tk() diff --git a/elementGen/node_editor.py b/elementGen/node_editor.py index e69de29..a59e2bb 100644 --- a/elementGen/node_editor.py +++ b/elementGen/node_editor.py @@ -0,0 +1,16 @@ +def NodeEditor(G): + """Makes a Node Editor screen! Still in progress. Come back later! + + Parameters + ---------- + G : graphics.Graphic + The Graphic screen + + USE: +```py +from graphics import Graphic +G = Graphic() +NodeEditor(G) +``` + """ + pass From e45047a79e32696f9d061e10002c2e9011227265 Mon Sep 17 00:00:00 2001 From: Max Worrall <96847801+Tsunami014@users.noreply.github.com> Date: Thu, 16 Nov 2023 08:20:42 +1100 Subject: [PATCH 19/91] =?UTF-8?q?feat(graphics):=20=F0=9F=8E=89=20Started?= =?UTF-8?q?=20working=20on=20the=20node=20element=20gen!?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit TODO: get better name for this --- elementGen/__init__.py | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 elementGen/__init__.py diff --git a/elementGen/__init__.py b/elementGen/__init__.py new file mode 100644 index 0000000..e69de29 From fa928593bc7f8bdaad5775aadfa32c68ae972284 Mon Sep 17 00:00:00 2001 From: Max Worrall <96847801+Tsunami014@users.noreply.github.com> Date: Thu, 16 Nov 2023 08:21:25 +1100 Subject: [PATCH 20/91] =?UTF-8?q?feat(graphics):=20=E2=9C=A8=20Added=20nod?= =?UTF-8?q?e=5Feditor.py?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It's blank RN --- elementGen/node_editor.py | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 elementGen/node_editor.py diff --git a/elementGen/node_editor.py b/elementGen/node_editor.py new file mode 100644 index 0000000..e69de29 From e148b4eceacffc8c57812c975f410fc0be85ad92 Mon Sep 17 00:00:00 2001 From: Max Worrall <96847801+Tsunami014@users.noreply.github.com> Date: Thu, 16 Nov 2023 08:24:32 +1100 Subject: [PATCH 21/91] =?UTF-8?q?feat(main):=20=F0=9F=8E=89=20It's=20time?= =?UTF-8?q?=20to=20fix=20these=20stupid=20imports=20once=20and=20for=20all?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit I'm having on emain demo file to demo everything so: 1. I don't have to look through each file for a demo 2. The files don't have to have STUPID import statements anymore! --- demos.py | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 demos.py diff --git a/demos.py b/demos.py new file mode 100644 index 0000000..e69de29 From e5bf5c3130f6a461392f12b80b2eb88ce01e0e26 Mon Sep 17 00:00:00 2001 From: Max Worrall <96847801+Tsunami014@users.noreply.github.com> Date: Thu, 16 Nov 2023 08:28:26 +1100 Subject: [PATCH 22/91] =?UTF-8?q?feat(main):=20=E2=9C=A8=20Added=20demo=20?= =?UTF-8?q?homescreen?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Uses Tkinter as everyone has that --- demos.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/demos.py b/demos.py index e69de29..b65862b 100644 --- a/demos.py +++ b/demos.py @@ -0,0 +1,12 @@ +import tkinter as Tk # Because everyone has tkinter + +def demo1(): + print('This is demo 1!') + +def demo2(): + print('This is demo 2!') + +root = Tk.Tk() +Tk.Button(root, text='Demo 1', command=demo1).pack() +Tk.Button(root, text='Demo 2', command=demo2).pack() +root.mainloop() From e0d14086036b3d7346373453f74f812188e5c901 Mon Sep 17 00:00:00 2001 From: Max Worrall <96847801+Tsunami014@users.noreply.github.com> Date: Thu, 16 Nov 2023 08:41:14 +1100 Subject: [PATCH 23/91] =?UTF-8?q?chore(main):=20=F0=9F=9A=9A=20Moved=20the?= =?UTF-8?q?=20demos=20from=20Loading.py=20and=20graphics.py=20to=20demos.p?= =?UTF-8?q?y?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Getting there :D --- demos.py | 104 +++++++++++++++++++++++++++++++++++++++---- graphics/graphics.py | 75 ------------------------------- graphics/loading.py | 13 ------ 3 files changed, 96 insertions(+), 96 deletions(-) diff --git a/demos.py b/demos.py index b65862b..c176766 100644 --- a/demos.py +++ b/demos.py @@ -1,12 +1,100 @@ import tkinter as Tk # Because everyone has tkinter -def demo1(): - print('This is demo 1!') +def loadingDemo(): + import pygame + from graphics import Loading + from time import sleep + @Loading + def f(self): + for self.i in range(10): + sleep(1) + pygame.init() + WIN = pygame.display.set_mode() + font = pygame.font.Font(None, 64) + succeeded, ret = f(WIN, font) + pygame.quit() + print('Ran for %i seconds%s' % (ret['i'], (' Successfully! :)' if succeeded else ' And failed :('))) + print('end') -def demo2(): - print('This is demo 2!') +def GraphicsDemo(): + import pygame + import graphics.graphics_options as GO + from graphics import Graphic + from time import sleep + t = input('Please input the starting text for the middle: ') + G = Graphic() + @G.Loading + def test_loading(self): + for self.i in range(10): + sleep(1) + + @G.Graphic + def test(event, txt, element=None, aborted=False): # You do not need args and kwargs if you KNOW that your function will not take them in. Include what you need. + if event == GO.EFIRST: # First, before anything else happens in the function + G.Container.txt = txt + if event == GO.ELOADUI: # Load the graphics + CTOP = GO.PNEW([1, 0], GO.PSTACKS[GO.PCTOP][1], 0) # Bcos usually the Center Top makes the elements stack down, so I make a new thing that stacks sideways + G.Clear() + G.add_text('HI', GO.CGREEN, GO.PRBOTTOM, GO.FTITLE) + G.add_text(':) ', GO.CBLACK, GO.PRBOTTOM, GO.FTITLE) + G.add_empty_space(GO.PCCENTER, 0, -150) # Yes, you can have negative space. This makes the next things shifted the other direction. + G.add_text('This is a cool thing', GO.CBLUE, GO.PCCENTER) + G.add_text('Sorry, I meant a cool TEST', GO.CRED, GO.PCCENTER) + G.add_text(G.Container.txt, GO.CGREEN, GO.PCCENTER) + G.add_empty_space(GO.PCBOTTOM, 0, 20) + G.add_button('Button 1 :D', GO.CYELLOW, GO.PCBOTTOM) + G.add_text('Buttons above [^] and below [v]', GO.CBLUE, GO.PCBOTTOM) + G.add_button('Textbox test', GO.CBLUE, GO.PCBOTTOM) + G.add_button('Loading test', GO.CGREEN, GO.PCBOTTOM) + G.Container.exitbtn = G.add_button('EXIT', GO.CRED, GO.PCBOTTOM) + G.add_empty_space(CTOP, -150, 0) # Center it a little more + G.add_text('Are you ', GO.CBLACK, CTOP) + G.add_text('happy? ', GO.CGREEN, CTOP) + G.add_text('Or sad?', GO.CRED, CTOP) + elif event == GO.ETICK: # This runs every 1/60 secs (each tick) + return True # Return whether or not the loop should continue. + elif event == GO.EELEMENTCLICK: # Some UI element got clicked! + if element.type == GO.TBUTTON: + # This gets passed 'element': the element that got clicked. TODO: make an Element class + # The == means element's uid == __ + # UID gets generated based off order: so UID of 2 means second thing created that makes a UID. + # When you create a thing that makes a UID it returns it. e.g. button1 = G.add_button(etc.) + # So in that example button1 is the UID. Maybe try saving it to the container tho! Example shown by the exit button. + if element == 2: + succeeded, ret = test_loading() + G.Container.txt = ('Ran for %i seconds%s' % (ret['i']+1, (' Successfully! :)' if succeeded else ' And failed :('))) + G.Reload() + elif element == G.Container.exitbtn: + G.Abort() + elif element == 1: + bot = GO.PNEW([0, 0], GO.PSTACKS[GO.PCBOTTOM][1], 1) + G.add_TextBox('HALLOOOO! :)', bot) + G.Container.idx = 0 + else: + G.Container.txt = element.txt # put name of button in middle + G.Reload() + elif element.type == GO.TTEXTBOX: + if G.Container.idx == 0: + element.set_text("Happy coding!") + G.Container.idx = 1 + else: + element.remove() + elif event == GO.EEVENT: # When something like a button is pressed. Is passed 'element' too, but this time it is an event + if element.type == pygame.KEYDOWN: + if element.key == pygame.K_SPACE: + G.Container.txt = 'You pressed space!' + G.Reload() + elif event == GO.ELAST: + # This also gets passed 'aborted': Whether you aborted or exited the screen + return aborted # Whatever you return here will be returned by the function + print(test(t)) + pygame.quit() # this here for very fast quitting -root = Tk.Tk() -Tk.Button(root, text='Demo 1', command=demo1).pack() -Tk.Button(root, text='Demo 2', command=demo2).pack() -root.mainloop() +if __name__ == '__main__': + root = Tk.Tk() + def cmd(cmdd): + root.quit() + cmdd() + Tk.Button(root, text='Loading demo', command=lambda: cmd(loadingDemo)).pack() + Tk.Button(root, text='Graphics Demo', command=lambda: cmd(GraphicsDemo)).pack() + root.mainloop() diff --git a/graphics/graphics.py b/graphics/graphics.py index 412e4b4..5b16042 100644 --- a/graphics/graphics.py +++ b/graphics/graphics.py @@ -422,81 +422,7 @@ def Abort(self): self.ab = True if __name__ == '__main__': - from time import sleep - t = input('Please input the starting text for the middle: ') G = Graphic() - @G.Loading - def test_loading(self): - for self.i in range(10): - sleep(1) - - @G.Graphic - def test(event, txt, element=None, aborted=False): # You do not need args and kwargs if you KNOW that your function will not take them in. Include what you need. - if event == GO.EFIRST: # First, before anything else happens in the function - G.Container.txt = txt - if event == GO.ELOADUI: # Load the graphics - CTOP = GO.PNEW([1, 0], GO.PSTACKS[GO.PCTOP][1], 0) # Bcos usually the Center Top makes the elements stack down, so I make a new thing that stacks sideways - G.Clear() - G.add_text('HI', GO.CGREEN, GO.PRBOTTOM, GO.FTITLE) - G.add_text(':) ', GO.CBLACK, GO.PRBOTTOM, GO.FTITLE) - G.add_empty_space(GO.PCCENTER, 0, -150) # Yes, you can have negative space. This makes the next things shifted the other direction. - G.add_text('This is a cool thing', GO.CBLUE, GO.PCCENTER) - G.add_text('Sorry, I meant a cool TEST', GO.CRED, GO.PCCENTER) - G.add_text(G.Container.txt, GO.CGREEN, GO.PCCENTER) - G.add_empty_space(GO.PCBOTTOM, 0, 20) - G.add_button('Button 1 :D', GO.CYELLOW, GO.PCBOTTOM) - G.add_text('Buttons above [^] and below [v]', GO.CBLUE, GO.PCBOTTOM) - G.add_button('Textbox test', GO.CBLUE, GO.PCBOTTOM) - G.add_button('Loading test', GO.CGREEN, GO.PCBOTTOM) - G.Container.exitbtn = G.add_button('EXIT', GO.CRED, GO.PCBOTTOM) - G.add_empty_space(CTOP, -150, 0) # Center it a little more - G.add_text('Are you ', GO.CBLACK, CTOP) - G.add_text('happy? ', GO.CGREEN, CTOP) - G.add_text('Or sad?', GO.CRED, CTOP) - G.Container.inp = G.add_input(GO.PCCENTER, GO.FFONT, maximum=16) - elif event == GO.ETICK: # This runs every 1/60 secs (each tick) - return True # Return whether or not the loop should continue. - elif event == GO.EELEMENTCLICK: # Some UI element got clicked! - if element.type == GO.TBUTTON: - # This gets passed 'element': the element that got clicked. TODO: make an Element class - # The == means element's uid == __ - # UID gets generated based off order: so UID of 2 means second thing created that makes a UID. - # When you create a thing that makes a UID it returns it. e.g. button1 = G.add_button(etc.) - # So in that example button1 is the UID. Maybe try saving it to the container tho! Example shown by the exit button. - if element == 2: - succeeded, ret = test_loading() - G.Container.txt = ('Ran for %i seconds%s' % (ret['i']+1, (' Successfully! :)' if succeeded else ' And failed :('))) - G.Reload() - elif element == G.Container.exitbtn: - G.Abort() - elif element == 1: - bot = GO.PNEW([0, 0], GO.PSTACKS[GO.PCBOTTOM][1], 1) - G.add_TextBox('HALLOOOO! :)', bot) - G.Container.idx = 0 - else: - G.Container.txt = element.txt # put name of button in middle - G.Reload() - elif element.type == GO.TTEXTBOX: - if G.Container.idx == 0: - element.set_text("Happy coding!") - G.Container.idx = 1 - else: - element.remove() - elif element.type == GO.TINPUTBOX: - G.Container.txt = element.txt - element.remove() - G.Reload() - elif event == GO.EEVENT: # When something like a button is pressed. Is passed 'element' too, but this time it is an event - if element.type == pygame.KEYDOWN: - if element.key == pygame.K_s and element.mod & pygame.KMOD_CTRL: - G.Container.txt = 'Saved! (Don\'t worry - this does nothing)' - G.Reload() - elif event == GO.ELAST: - # This also gets passed 'aborted': Whether you aborted or exited the screen - return (aborted, G.uids[G.Container.inp].text) # Whatever you return here will be returned by the function - - print(test(t)) - # Copy this scaffold for your own code :) # Args and kwargs are passed through from the initial call of the func @G.Graphic # If you use classes, make this CGraphics and add a `self` argument to the function @@ -513,4 +439,3 @@ def funcname(event, *args, element=None, aborted=False, **kwargs): pass elif event == GO.ELAST: # Passed 'aborted' pass # Whatever you return here will be returned by the function - pygame.quit() # this here for very fast quitting diff --git a/graphics/loading.py b/graphics/loading.py index e700da7..b1d574a 100644 --- a/graphics/loading.py +++ b/graphics/loading.py @@ -76,16 +76,3 @@ def __call__(self, *args): t.raise_exception() return (not end), {i:getattr(m,i) for i in dir(m) if i not in dir(main)} return func2 - -if __name__ == '__main__': - @Loading - def f(self): - for self.i in range(10): - sleep(1) - pygame.init() - WIN = pygame.display.set_mode() - font = pygame.font.Font(None, 64) - succeeded, ret = f(WIN, font) - pygame.quit() - print('Ran for %i seconds%s' % (ret['i'], (' Successfully! :)' if succeeded else ' And failed :('))) - print('end') From 92399541f40f6251531d514ddaaf5c36237b22cb Mon Sep 17 00:00:00 2001 From: Max Worrall <96847801+Tsunami014@users.noreply.github.com> Date: Thu, 16 Nov 2023 15:42:58 +1100 Subject: [PATCH 24/91] =?UTF-8?q?feat(worlds):=20=F0=9F=9A=9A=20Moved=20te?= =?UTF-8?q?rrainGen=20and=20world=20demos=20to=20demos.py?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- demos.py | 25 ++++++++++++++++++++++++- utils/terrainGen.py | 14 -------------- utils/world.py | 4 ---- 3 files changed, 24 insertions(+), 19 deletions(-) diff --git a/demos.py b/demos.py index c176766..f860c10 100644 --- a/demos.py +++ b/demos.py @@ -90,11 +90,34 @@ def test(event, txt, element=None, aborted=False): # You do not need args and kw print(test(t)) pygame.quit() # this here for very fast quitting +def worldsDemo(): + from utils import World + World('test', 'Test World', 'A world for testing random stuff', 25, quality=500, override=True) + +def terrainGenDemo(): + from random import randint + from utils import MapGen + size = 1500 + n = 256 + inp = input('Input nothing to use random seed, input "." to use a preset good seed, or input your own INTEGER seed > ') + if inp == '': + map_seed = randint(0, 999999) + elif inp == '.': + map_seed = 762345 + else: + map_seed = int(inp) + useall = input('Type anything here to show all steps in terrain generation, or leave this blank and press enter to just show the finished product. > ') != '' + outs, trees = MapGen(size, map_seed, n, useall=useall, showAtEnd=True).outs + print(outs[0]) + pass + if __name__ == '__main__': root = Tk.Tk() def cmd(cmdd): root.quit() cmdd() - Tk.Button(root, text='Loading demo', command=lambda: cmd(loadingDemo)).pack() + Tk.Button(root, text='Loading Demo', command=lambda: cmd(loadingDemo)).pack() Tk.Button(root, text='Graphics Demo', command=lambda: cmd(GraphicsDemo)).pack() + Tk.Button(root, text='Generate World Demo', command=lambda: cmd(worldsDemo)).pack() + Tk.Button(root, text='Generate Terrain Demo', command=lambda: cmd(terrainGenDemo)).pack() root.mainloop() diff --git a/utils/terrainGen.py b/utils/terrainGen.py index 5ba99a1..ac6a521 100644 --- a/utils/terrainGen.py +++ b/utils/terrainGen.py @@ -844,17 +844,3 @@ def __init__(self, size, map_seed=762345, n=256, **kwargs): height_map = norm_map * scaling_factor # Convert to heights out = [[round(j) for j in i] for i in height_map] self.outs = ([out, colour_map, rivers_biome_colour_map, adjusted_height_river_map, river_land_mask, biome_masks], trees) - -if __name__ == '__main__': - size = 1500 - n = 256 - inp = input('Input nothing to use random seed, input "." to use a preset good seed, or input your own INTEGER seed > ') - if inp == '': - map_seed = randint(0, 999999) - elif inp == '.': - map_seed = 762345 - else: - map_seed = int(inp) - useall = input('Type anything here to show all steps in terrain generation, or leave this blank and press enter to just show the finished product. > ') != '' - outs, trees = MapGen(size, map_seed, n, useall=useall, showAtEnd=True).outs - print(outs[0]) diff --git a/utils/world.py b/utils/world.py index 35cebbf..e55fa11 100644 --- a/utils/world.py +++ b/utils/world.py @@ -152,7 +152,3 @@ def __init__(self, filename, name='', idea='', size=None, size2=50, quality=500, def get_pygame(self, lvl=0): if self.data != {}: return ldtk.LdtkJSON(self.data, folder).levels[lvl].layers[1].getImg() # TODO: have a number in the intgrid specifically for oceans, and get that from the terrain gen - -if __name__ == '__main__': - w = World('test', 'Test World', 'A world for testing random stuff', 25, quality=500, override=True) - pass From af685b4a7a015dd3928b201252c522519c9c1587 Mon Sep 17 00:00:00 2001 From: Max Worrall <96847801+Tsunami014@users.noreply.github.com> Date: Thu, 16 Nov 2023 15:47:04 +1100 Subject: [PATCH 25/91] =?UTF-8?q?feat(other):=20=F0=9F=9A=9A=20Added=20asy?= =?UTF-8?q?nc=5Fhandling=20demo=20to=20demos.py?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- demos.py | 22 ++++++++++++++++++++++ graphics/async_handling.py | 30 ------------------------------ 2 files changed, 22 insertions(+), 30 deletions(-) diff --git a/demos.py b/demos.py index f860c10..07094ec 100644 --- a/demos.py +++ b/demos.py @@ -111,6 +111,27 @@ def terrainGenDemo(): print(outs[0]) pass +def async_handlingDemo(): # TODO: Improve this demo + import random, asyncio, pygame + from graphics import Progressbar + async def wait_random(): + seconds = random.randint(200, 2000) / 100 + #print(f"Waiting for {seconds} seconds...") + await asyncio.sleep(seconds) + #print(f"Done waiting for {seconds} seconds!") + return seconds + + pygame.init() + WIN = pygame.display.set_mode((800, 600)) + pygame.display.set_caption("Loading Bar Example") + WIN.fill((255, 255, 255)) + pygame.display.update() + bar = Progressbar(600, 50) + tasks = [wait_random() for _ in range(500)] + print(bar(WIN, (WIN.get_width() - 600) // 2, (WIN.get_height() - 50) // 2, 5, tasks)) + asyncio.get_event_loop().stop() + pygame.quit() + if __name__ == '__main__': root = Tk.Tk() def cmd(cmdd): @@ -120,4 +141,5 @@ def cmd(cmdd): Tk.Button(root, text='Graphics Demo', command=lambda: cmd(GraphicsDemo)).pack() Tk.Button(root, text='Generate World Demo', command=lambda: cmd(worldsDemo)).pack() Tk.Button(root, text='Generate Terrain Demo', command=lambda: cmd(terrainGenDemo)).pack() + Tk.Button(root, text='Async Progressbar Demo', command=lambda: cmd(async_handlingDemo)).pack() root.mainloop() diff --git a/graphics/async_handling.py b/graphics/async_handling.py index 233e73c..12ad03d 100644 --- a/graphics/async_handling.py +++ b/graphics/async_handling.py @@ -66,33 +66,3 @@ def run(): self.whileloading(x, y, self.bar.get_width(), self.bar.get_height(), border_width, window, update_func, loadingtxt, loadingtxtColour) #loop.stop() return self.results - -if __name__ == '__main__': - import random - # Define a coroutine function that waits a random amount of time - async def wait_random(): - # Get a random number of seconds between 2 and 20 - seconds = random.randint(200, 2000) / 100 - # Print a message - #print(f"Waiting for {seconds} seconds...") - # Wait for that amount of time - await asyncio.sleep(seconds) - # Print another message - #print(f"Done waiting for {seconds} seconds!") - return seconds - - # now we initialise pygame and load the window for our demo - pygame.init() - WIN = pygame.display.set_mode((800, 600)) - pygame.display.set_caption("Loading Bar Example") - WIN.fill(WHITE) - pygame.display.update() - # create a loading bar object - bar = Progressbar(600, 50) - # create a list of tasks to be completed - tasks = [wait_random() for _ in range(500)] - # run the loading bar - print(bar(WIN, (WIN.get_width() - 600) // 2, (WIN.get_height() - 50) // 2, 5, tasks)) - asyncio.get_event_loop().stop() - # exit pygame - pygame.quit() From 18fe859b2d19e246109bbac6a8c06032b55206ad Mon Sep 17 00:00:00 2001 From: Max Worrall <96847801+Tsunami014@users.noreply.github.com> Date: Thu, 16 Nov 2023 16:02:13 +1100 Subject: [PATCH 26/91] =?UTF-8?q?feat(other):=20=F0=9F=92=84=20Moved=20the?= =?UTF-8?q?=20very=20annoying=20async=20handling=20functions=20into=20the?= =?UTF-8?q?=20Graphic=20class=20:)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- demos.py | 15 +++++---------- graphics/graphics.py | 24 +++++++++++++++++++++++- 2 files changed, 28 insertions(+), 11 deletions(-) diff --git a/demos.py b/demos.py index 07094ec..b6c9663 100644 --- a/demos.py +++ b/demos.py @@ -111,9 +111,11 @@ def terrainGenDemo(): print(outs[0]) pass -def async_handlingDemo(): # TODO: Improve this demo +def async_handlingDemo(): import random, asyncio, pygame - from graphics import Progressbar + from graphics import Graphic + G = Graphic() + async def wait_random(): seconds = random.randint(200, 2000) / 100 #print(f"Waiting for {seconds} seconds...") @@ -121,15 +123,8 @@ async def wait_random(): #print(f"Done waiting for {seconds} seconds!") return seconds - pygame.init() - WIN = pygame.display.set_mode((800, 600)) - pygame.display.set_caption("Loading Bar Example") - WIN.fill((255, 255, 255)) - pygame.display.update() - bar = Progressbar(600, 50) tasks = [wait_random() for _ in range(500)] - print(bar(WIN, (WIN.get_width() - 600) // 2, (WIN.get_height() - 50) // 2, 5, tasks)) - asyncio.get_event_loop().stop() + G.PBLoading(tasks) pygame.quit() if __name__ == '__main__': diff --git a/graphics/graphics.py b/graphics/graphics.py index 5b16042..50f1f08 100644 --- a/graphics/graphics.py +++ b/graphics/graphics.py @@ -1,13 +1,15 @@ -import pygame +import pygame, asyncio pygame.init() try: import graphics.graphics_options as GO from graphics.loading import Loading from graphics.GUI import TextBoxFrame, InputBox, Button + from graphics.async_handling import Progressbar from graphics.GUI.textboxify.borders import LIGHT except: import graphics_options as GO from loading import Loading + from async_handling import Progressbar from GUI import TextBoxFrame, InputBox, Button from GUI.textboxify.borders import LIGHT @@ -154,6 +156,26 @@ def func2(): return Loading(func)(self.WIN, GO.FTITLE) return func2 + def PBLoading(self, tasks): + """Have a loading screen! Like G.Loading, but with a progressbar! + + Parameters + ---------- + tasks : list[async functions] + The list of async functions to run. + + Returns + ------- + list + The output list of all the return values of each of the functions inputted + """ + self.WIN.fill(GO.CWHITE) + pygame.display.update() + pbar = Progressbar(600, 50) + res = pbar(self.WIN, (self.size[0] - 600) // 2, (self.size[1] - 50) // 2, 5, tasks) + asyncio.get_event_loop().stop() + return res + def CGraphic(self, funcy): # Function decorator, not to be called def func2(slf, *args, **kwargs): self.Graphic(funcy, slf)(*args, **kwargs) # Yes I know I'm calling it here. Deal with it. From e584edd60a0e6a3378d751f4c1e5b49947e36240 Mon Sep 17 00:00:00 2001 From: Max Worrall <96847801+Tsunami014@users.noreply.github.com> Date: Thu, 16 Nov 2023 16:03:05 +1100 Subject: [PATCH 27/91] =?UTF-8?q?fix(main):=20=F0=9F=90=9B=20Fixed=20tkint?= =?UTF-8?q?er=20window=20quitting=20issue?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit root.quit didn't work: changed to root.destroy --- demos.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/demos.py b/demos.py index b6c9663..ea83a98 100644 --- a/demos.py +++ b/demos.py @@ -130,7 +130,7 @@ async def wait_random(): if __name__ == '__main__': root = Tk.Tk() def cmd(cmdd): - root.quit() + root.destroy() cmdd() Tk.Button(root, text='Loading Demo', command=lambda: cmd(loadingDemo)).pack() Tk.Button(root, text='Graphics Demo', command=lambda: cmd(GraphicsDemo)).pack() From 78b1255b6606d4e6056912fb038b9407b67aa06b Mon Sep 17 00:00:00 2001 From: Max Worrall <96847801+Tsunami014@users.noreply.github.com> Date: Thu, 16 Nov 2023 16:04:24 +1100 Subject: [PATCH 28/91] =?UTF-8?q?feat(main):=20=E2=9C=A8=20Tiny=20addition?= =?UTF-8?q?=20of=20print?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It was in the original and got removed, so I put it back --- demos.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/demos.py b/demos.py index ea83a98..373527a 100644 --- a/demos.py +++ b/demos.py @@ -124,7 +124,7 @@ async def wait_random(): return seconds tasks = [wait_random() for _ in range(500)] - G.PBLoading(tasks) + print(G.PBLoading(tasks)) pygame.quit() if __name__ == '__main__': From eeb7f2fb33ba5218047c1057c8dc42e4e9e865c0 Mon Sep 17 00:00:00 2001 From: Max Worrall <96847801+Tsunami014@users.noreply.github.com> Date: Thu, 16 Nov 2023 16:07:12 +1100 Subject: [PATCH 29/91] =?UTF-8?q?feat(GUI):=20=F0=9F=9A=9A=20Moved=20the?= =?UTF-8?q?=20input=20box=20demo=20to=20demos.py?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- demos.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/demos.py b/demos.py index 373527a..b52caf1 100644 --- a/demos.py +++ b/demos.py @@ -127,6 +127,14 @@ async def wait_random(): print(G.PBLoading(tasks)) pygame.quit() +def inputBoxDemo(): # TODO: make part of Graphic class + import pygame as pg + from graphics.GUI import InputBox + screen = pg.display.set_mode((640, 480)) + input_box = InputBox(100, 100, 140, 32, 'type here!') + print('output:', input_box.interrupt(screen)) + pg.quit() + if __name__ == '__main__': root = Tk.Tk() def cmd(cmdd): @@ -137,4 +145,5 @@ def cmd(cmdd): Tk.Button(root, text='Generate World Demo', command=lambda: cmd(worldsDemo)).pack() Tk.Button(root, text='Generate Terrain Demo', command=lambda: cmd(terrainGenDemo)).pack() Tk.Button(root, text='Async Progressbar Demo', command=lambda: cmd(async_handlingDemo)).pack() + Tk.Button(root, text='Input Box Demo', command=lambda: cmd(inputBoxDemo)).pack() root.mainloop() From 2014e5c278063caf6f8cc4c46734313f918d2b0c Mon Sep 17 00:00:00 2001 From: Max Worrall <96847801+Tsunami014@users.noreply.github.com> Date: Thu, 16 Nov 2023 16:13:58 +1100 Subject: [PATCH 30/91] =?UTF-8?q?feat(main):=20=E2=9C=A8=20Made=20the=20lo?= =?UTF-8?q?ading=20demos=20better?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Joined 2 loading-like demos together --- demos.py | 30 +++++++++++------------------- graphics/graphics.py | 2 +- 2 files changed, 12 insertions(+), 20 deletions(-) diff --git a/demos.py b/demos.py index b52caf1..7e7de94 100644 --- a/demos.py +++ b/demos.py @@ -1,21 +1,5 @@ import tkinter as Tk # Because everyone has tkinter -def loadingDemo(): - import pygame - from graphics import Loading - from time import sleep - @Loading - def f(self): - for self.i in range(10): - sleep(1) - pygame.init() - WIN = pygame.display.set_mode() - font = pygame.font.Font(None, 64) - succeeded, ret = f(WIN, font) - pygame.quit() - print('Ran for %i seconds%s' % (ret['i'], (' Successfully! :)' if succeeded else ' And failed :('))) - print('end') - def GraphicsDemo(): import pygame import graphics.graphics_options as GO @@ -111,9 +95,10 @@ def terrainGenDemo(): print(outs[0]) pass -def async_handlingDemo(): +def LoadingDemo(): import random, asyncio, pygame from graphics import Graphic + from time import sleep G = Graphic() async def wait_random(): @@ -125,7 +110,15 @@ async def wait_random(): tasks = [wait_random() for _ in range(500)] print(G.PBLoading(tasks)) + + @G.Loading + def test_loading(self): + for self.i in range(10): + sleep(1) + + succeeded, ret = test_loading() pygame.quit() + print('Ran for %i seconds%s' % (ret['i'], (' Successfully! :)' if succeeded else ' And failed :('))) def inputBoxDemo(): # TODO: make part of Graphic class import pygame as pg @@ -140,10 +133,9 @@ def inputBoxDemo(): # TODO: make part of Graphic class def cmd(cmdd): root.destroy() cmdd() - Tk.Button(root, text='Loading Demo', command=lambda: cmd(loadingDemo)).pack() + Tk.Button(root, text='Loading Demo', command=lambda: cmd(LoadingDemo)).pack() Tk.Button(root, text='Graphics Demo', command=lambda: cmd(GraphicsDemo)).pack() Tk.Button(root, text='Generate World Demo', command=lambda: cmd(worldsDemo)).pack() Tk.Button(root, text='Generate Terrain Demo', command=lambda: cmd(terrainGenDemo)).pack() - Tk.Button(root, text='Async Progressbar Demo', command=lambda: cmd(async_handlingDemo)).pack() Tk.Button(root, text='Input Box Demo', command=lambda: cmd(inputBoxDemo)).pack() root.mainloop() diff --git a/graphics/graphics.py b/graphics/graphics.py index 50f1f08..67d4c6d 100644 --- a/graphics/graphics.py +++ b/graphics/graphics.py @@ -156,7 +156,7 @@ def func2(): return Loading(func)(self.WIN, GO.FTITLE) return func2 - def PBLoading(self, tasks): + def PBLoading(self, tasks): # TODO: allow aborting """Have a loading screen! Like G.Loading, but with a progressbar! Parameters From 838036936c9a735b0788e0aa8679d0dddef2d8e3 Mon Sep 17 00:00:00 2001 From: Max Worrall <96847801+Tsunami014@users.noreply.github.com> Date: Thu, 16 Nov 2023 16:18:59 +1100 Subject: [PATCH 31/91] =?UTF-8?q?feat(conversation):=20=F0=9F=9A=9A=20Move?= =?UTF-8?q?d=20conversation=20parser=20demo=20to=20demos.py?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- demos.py | 23 +++++ .../conversation_parse/conversation_parser.py | 88 +++++++------------ 2 files changed, 57 insertions(+), 54 deletions(-) diff --git a/demos.py b/demos.py index 7e7de94..16f1a80 100644 --- a/demos.py +++ b/demos.py @@ -128,6 +128,28 @@ def inputBoxDemo(): # TODO: make part of Graphic class print('output:', input_box.interrupt(screen)) pg.quit() +def conversation_parserDemo(): + from utils.conversation_parse import Generator + # If you run this file you can see these next statements at work + # Each you can see is separated, by a like of ~~~~~~~~~~ + # You can see the different start params at work, with the same sample prompt + def gen(): + g = Generator() + yield g([(1, 2), 2]) + yield g([(0, 0), 3]) + yield g([(0, 3), 1]) + yield g([(3, 1), 2]) + yield g([(0, 2), 0]) + yield '\nAnd here are some randomly generated ones:\n' + g() + while True: + yield g() + g = gen() + print('Here are some I prepared earlier:\n') + while True: + print(next(g)) + if input() != '': + break + if __name__ == '__main__': root = Tk.Tk() def cmd(cmdd): @@ -138,4 +160,5 @@ def cmd(cmdd): Tk.Button(root, text='Generate World Demo', command=lambda: cmd(worldsDemo)).pack() Tk.Button(root, text='Generate Terrain Demo', command=lambda: cmd(terrainGenDemo)).pack() Tk.Button(root, text='Input Box Demo', command=lambda: cmd(inputBoxDemo)).pack() + Tk.Button(root, text='Conversation Parse Demo', command=lambda: cmd(conversation_parserDemo)).pack() root.mainloop() diff --git a/utils/conversation_parse/conversation_parser.py b/utils/conversation_parse/conversation_parser.py index 4eaaf81..dc27f3f 100644 --- a/utils/conversation_parse/conversation_parser.py +++ b/utils/conversation_parse/conversation_parser.py @@ -472,57 +472,37 @@ def cycle(my_list, start_at=None): yield my_list[start_at] start_at = (start_at + 1) % len(my_list) -if __name__ == '__main__': - from random import shuffle, choice, randint - class Generator: - def __init__(self): - l = list(range(91, 96)) - shuffle(l) - self.order = cycle(l) - self.order2 = cycle(l, 2) - def generate_desc(self): - K = Knowledge('Grapefruit') - self.args = {'is_adjs':choice([None, 'nice', 'nice/kind', 'nice/kind/happy/beautiful']), - 'is_a':choice([None, 'dragon', 'human', 'elf', 'wizard', 'brown dog']), - 'who':choice([None, 'loves life', 'reads lots/codes', 'gets bored easily/loves life/reads a lot/codes', 'always wears brown clothing']) - } - K.add_clause(**self.args) - return K.get(0) - def __call__(self, start=None): - out = '' - if start == None: start = [(randint(0, 3), randint(0, 4)), randint(0, len(STARTPARAM1)-1)] - sample_prompt = choice([ - [{'role': 'user', 'content': 'Hello! How are you?'}, {'role': 'bot', 'content': 'I am good, how are you?'}, {'role': 'user', 'content': 'I am good too! What did you do today?'}], - [{'role': 'user', 'content': 'Hello'}, {'role': 'bot', 'content': 'Hello! What can I help you with today?'}, {'role': 'user', 'content': 'I dunno...'}, {'role': 'bot', 'content': 'Well, I can help you with anything! Just pick a topic!'}, {'role': 'user', 'content': 'I like books'}, {'role': 'bot', 'content': 'I like books too! What is your favourite book?'}, {'role': 'user', 'content': 'I like Harry Potter'}], - [{'role': 'user', 'content': 'Hello! How are you?'}, {'role': 'bot', 'content': 'What can I help you with?'}, {'role': 'user', 'content': 'I need help with a Python project.'}], - [{'role': 'user', 'content': 'What is the best way to handle errors in Python?'}, {'role': 'bot', 'content': 'There are several ways to handle errors in Python, such as using try-except blocks or raising exceptions. What kind of errors are you trying to handle?'}, {'role': 'user', 'content': 'I\'m trying to handle file I/O errors.'}], - [{'role': 'user', 'content': 'How do I install a Python package using pip?'}, {'role': 'bot', 'content': 'You can install a Python package using pip by running the command "pip install package_name" in your terminal. Have you used pip before?'}, {'role': 'user', 'content': 'No, I haven\'t. Can you walk me through it?'}] - ]) - sample_desc = 'You are Grapefruit. '+self.generate_desc() - self.args['start'] = start - out += '\033[%sm| ' % str(next(self.order2)) - pretty = lambda x: '"' if isinstance(x, str) else '' - for i in self.args: out += i+' : '+pretty(self.args[i])+str(self.args[i])+pretty(self.args[i])+' | ' - out += '\033[0m\n' - out += PARSE(start, sample_desc, sample_prompt, 'Grapefruit')+'\n' - out += '\033[%sm~~~~~~~~~~~~~~~~~~~~~~~~~\033[0m' % str(next(self.order)) - return out - # If you run this file you can see these next statements at work - # Each you can see is separated, by a like of ~~~~~~~~~~ - # You can see the different start params at work, with the same sample prompt - def gen(): - g = Generator() - yield g([(1, 2), 2]) - yield g([(0, 0), 3]) - yield g([(0, 3), 1]) - yield g([(3, 1), 2]) - yield g([(0, 2), 0]) - yield '\nAnd here are some randomly generated ones:\n' + g() - while True: - yield g() - g = gen() - print('Here are some I prepared earlier:\n') - while True: - print(next(g)) - if input() != '': - break +from random import shuffle, choice, randint +class Generator: + def __init__(self): + l = list(range(91, 96)) + shuffle(l) + self.order = cycle(l) + self.order2 = cycle(l, 2) + def generate_desc(self): + K = Knowledge('Grapefruit') + self.args = {'is_adjs':choice([None, 'nice', 'nice/kind', 'nice/kind/happy/beautiful']), + 'is_a':choice([None, 'dragon', 'human', 'elf', 'wizard', 'brown dog']), + 'who':choice([None, 'loves life', 'reads lots/codes', 'gets bored easily/loves life/reads a lot/codes', 'always wears brown clothing']) + } + K.add_clause(**self.args) + return K.get(0) + def __call__(self, start=None): + out = '' + if start == None: start = [(randint(0, 3), randint(0, 4)), randint(0, len(STARTPARAM1)-1)] + sample_prompt = choice([ + [{'role': 'user', 'content': 'Hello! How are you?'}, {'role': 'bot', 'content': 'I am good, how are you?'}, {'role': 'user', 'content': 'I am good too! What did you do today?'}], + [{'role': 'user', 'content': 'Hello'}, {'role': 'bot', 'content': 'Hello! What can I help you with today?'}, {'role': 'user', 'content': 'I dunno...'}, {'role': 'bot', 'content': 'Well, I can help you with anything! Just pick a topic!'}, {'role': 'user', 'content': 'I like books'}, {'role': 'bot', 'content': 'I like books too! What is your favourite book?'}, {'role': 'user', 'content': 'I like Harry Potter'}], + [{'role': 'user', 'content': 'Hello! How are you?'}, {'role': 'bot', 'content': 'What can I help you with?'}, {'role': 'user', 'content': 'I need help with a Python project.'}], + [{'role': 'user', 'content': 'What is the best way to handle errors in Python?'}, {'role': 'bot', 'content': 'There are several ways to handle errors in Python, such as using try-except blocks or raising exceptions. What kind of errors are you trying to handle?'}, {'role': 'user', 'content': 'I\'m trying to handle file I/O errors.'}], + [{'role': 'user', 'content': 'How do I install a Python package using pip?'}, {'role': 'bot', 'content': 'You can install a Python package using pip by running the command "pip install package_name" in your terminal. Have you used pip before?'}, {'role': 'user', 'content': 'No, I haven\'t. Can you walk me through it?'}] + ]) + sample_desc = 'You are Grapefruit. '+self.generate_desc() + self.args['start'] = start + out += '\033[%sm| ' % str(next(self.order2)) + pretty = lambda x: '"' if isinstance(x, str) else '' + for i in self.args: out += i+' : '+pretty(self.args[i])+str(self.args[i])+pretty(self.args[i])+' | ' + out += '\033[0m\n' + out += PARSE(start, sample_desc, sample_prompt, 'Grapefruit')+'\n' + out += '\033[%sm~~~~~~~~~~~~~~~~~~~~~~~~~\033[0m' % str(next(self.order)) + return out From dfac00bc5ceee372621067f657fce4d528cb9a4f Mon Sep 17 00:00:00 2001 From: Max Worrall <96847801+Tsunami014@users.noreply.github.com> Date: Fri, 17 Nov 2023 08:09:07 +1100 Subject: [PATCH 32/91] =?UTF-8?q?feat(AIs):=20=F0=9F=9A=9A=20Moved=20AIs'?= =?UTF-8?q?=20demos=20into=20demos.py?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Moved demos from install_tinyllm.py, set_preferences.py & tinyllm.py --- demos.py | 27 +++++++++++++++++++++++++++ utils/bot/install_tinyllm.py | 3 --- utils/bot/set_preferences.py | 4 ---- utils/bot/tinyllm.py | 15 --------------- 4 files changed, 27 insertions(+), 22 deletions(-) diff --git a/demos.py b/demos.py index 16f1a80..dac59db 100644 --- a/demos.py +++ b/demos.py @@ -149,6 +149,30 @@ def gen(): print(next(g)) if input() != '': break +def tinyLLMDemo(): + import asyncio + from utils.bot import TinyLLM, lm + tllm = TinyLLM() + prompt = f"System: Reply as a helpful assistant. Currently {lm.get_date()}." + while True: + inp = input('> ') + if inp == '': break + prompt += f"\n\nUser: {inp}" + i = asyncio.run(tllm.interrupt(inp)) + prompt += "\n\nAssistant:" + end = asyncio.run(tllm(prompt)) + print(i) + print(end) + prompt += f" {end}" + +def testLLMDemo(): + from utils.bot import test_tinyllm + test_tinyllm() + +def rateAIsDemo(): + import asyncio + from utils.bot import rate_all + asyncio.run(rate_all()) if __name__ == '__main__': root = Tk.Tk() @@ -161,4 +185,7 @@ def cmd(cmdd): Tk.Button(root, text='Generate Terrain Demo', command=lambda: cmd(terrainGenDemo)).pack() Tk.Button(root, text='Input Box Demo', command=lambda: cmd(inputBoxDemo)).pack() Tk.Button(root, text='Conversation Parse Demo', command=lambda: cmd(conversation_parserDemo)).pack() + Tk.Button(root, text='TinyLLM Demo', command=lambda: cmd(tinyLLMDemo)).pack() + Tk.Button(root, text='Test LLM Demo', command=lambda: cmd(testLLMDemo)).pack() + Tk.Button(root, text='Rate AIs Demo', command=lambda: cmd(rateAIsDemo)).pack() root.mainloop() diff --git a/utils/bot/install_tinyllm.py b/utils/bot/install_tinyllm.py index 11abf8e..09db70d 100644 --- a/utils/bot/install_tinyllm.py +++ b/utils/bot/install_tinyllm.py @@ -98,6 +98,3 @@ def test_tinyllm(): lm.store_doc(lm.get_wiki("C language"), "C") lm.store_doc(lm.get_wiki("Javascript"), "Javascript") print(lm.get_doc_context("What does it mean for batteries to be included in a language?")) - -if __name__ == '__main__': - test_tinyllm() \ No newline at end of file diff --git a/utils/bot/set_preferences.py b/utils/bot/set_preferences.py index 169bfd2..9a96134 100644 --- a/utils/bot/set_preferences.py +++ b/utils/bot/set_preferences.py @@ -55,7 +55,3 @@ async def rate_all(resps=None): else: out[name] = int(rating) i += 1 set_preferences(out) - -if __name__ == '__main__': - import asyncio - asyncio.run(rate_all()) diff --git a/utils/bot/tinyllm.py b/utils/bot/tinyllm.py index 62a14ba..d316d6d 100644 --- a/utils/bot/tinyllm.py +++ b/utils/bot/tinyllm.py @@ -67,18 +67,3 @@ async def interrupt(self, txt, ram=None): lm.set_max_ram(ram) if lm.classify(txt,"simple reply","complex reply") == 'complex reply': return 'l' return 's' - -if __name__ == '__main__': - import asyncio - tllm = TinyLLM() - prompt = f"System: Reply as a helpful assistant. Currently {lm.get_date()}." - while True: - inp = input('> ') - if inp == '': break - prompt += f"\n\nUser: {inp}" - i = asyncio.run(tllm.interrupt(inp)) - prompt += "\n\nAssistant:" - end = asyncio.run(tllm(prompt)) - print(i) - print(end) - prompt += f" {end}" From 93d5e4ddaa351d770382ee70443e60f9476a4c05 Mon Sep 17 00:00:00 2001 From: Max Worrall <96847801+Tsunami014@users.noreply.github.com> Date: Fri, 17 Nov 2023 08:21:58 +1100 Subject: [PATCH 33/91] =?UTF-8?q?feat(ALL=20:D):=20=F0=9F=9A=91=EF=B8=8F?= =?UTF-8?q?=20Fixed=20ALL=20the=20import=20statements=20of=20ALL=20the=20l?= =?UTF-8?q?ines=20of=20code!=20:D=20:D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit I hope this isn't bugged. I have not tested many things I should be testing... --- graphics/GUI/__init__.py | 20 ++++------------ graphics/GUI/example.py | 11 +++------ graphics/GUI/pyguix/__init__.py | 8 +------ graphics/GUI/pyguix/ui/elements.py | 8 +------ graphics/GUI/pyguix/utils.py | 16 +++---------- graphics/GUI/textboxify/__init__.py | 22 +++++------------- graphics/graphics.py | 17 ++++---------- main.py | 1 - requirements.txt | 1 + utils/Pyldtk.py | 2 +- utils/bot/AIs.py | 13 +---------- utils/bot/__init__.py | 23 ++++++------------- utils/bot/basebots.py | 13 +---------- utils/bot/copilot.py | 10 ++------ utils/bot/set_preferences.py | 17 +++----------- utils/bot/tinyllm.py | 8 +------ utils/characters.py | 8 ++----- utils/conversation_parse/__init__.py | 8 ++----- .../conversation_parse/conversation_parser.py | 8 +------ utils/converse.py | 1 - utils/discussions.py | 1 - utils/terrainGen.py | 8 +------ utils/world.py | 14 ++++------- 23 files changed, 50 insertions(+), 188 deletions(-) diff --git a/graphics/GUI/__init__.py b/graphics/GUI/__init__.py index 6e9d78c..53ad151 100644 --- a/graphics/GUI/__init__.py +++ b/graphics/GUI/__init__.py @@ -1,16 +1,4 @@ -try: - from graphics.GUI.inputbox import * - from graphics.GUI.pyguix import * - from graphics.GUI.textboxify import * - from graphics.GUI.randomGUIelements import * -except ImportError: - try: - from GUI.inputbox import * - from GUI.pyguix import * - from GUI.textboxify import * - from GUI.randomGUIelements import * - except ImportError: - from inputbox import * - from pyguix import * - from textboxify import * - from randomGUIelements import * \ No newline at end of file +from graphics.GUI.inputbox import * +from graphics.GUI.pyguix import * +from graphics.GUI.textboxify import * +from graphics.GUI.randomGUIelements import * diff --git a/graphics/GUI/example.py b/graphics/GUI/example.py index 26c4c29..fa83164 100644 --- a/graphics/GUI/example.py +++ b/graphics/GUI/example.py @@ -1,13 +1,8 @@ import pygame from pygame import locals -try: - from __init__ import InputBox, RESIZE_H, TextBoxFrame - from __init__ import gui as ui - from textboxify.borders import LIGHT, BARBER_POLE -except ImportError: - from graphics.GUI import InputBox, RESIZE_H, TextBoxFrame - from graphics.GUI.pyguix import gui as ui - from graphics.GUI.textboxify.borders import LIGHT, BARBER_POLE +from graphics.GUI import InputBox, RESIZE_H, TextBoxFrame +from graphics.GUI.pyguix import gui as ui +from graphics.GUI.textboxify.borders import LIGHT, BARBER_POLE class SnapHUDPartInfoExample(ui.SnapHUDPartInfo): diff --git a/graphics/GUI/pyguix/__init__.py b/graphics/GUI/pyguix/__init__.py index 33bbc9b..34e7e5a 100644 --- a/graphics/GUI/pyguix/__init__.py +++ b/graphics/GUI/pyguix/__init__.py @@ -16,10 +16,4 @@ # See the License for the specific language governing permissions and # limitations under the License. -try: - from graphics.GUI.pyguix.ui import elements as gui -except ImportError: - try: - from GUI.pyguix.ui import elements as gui - except ImportError: - from pyguix.ui import elements as gui \ No newline at end of file +from graphics.GUI.pyguix.ui import elements as gui \ No newline at end of file diff --git a/graphics/GUI/pyguix/ui/elements.py b/graphics/GUI/pyguix/ui/elements.py index 67376c4..90751df 100644 --- a/graphics/GUI/pyguix/ui/elements.py +++ b/graphics/GUI/pyguix/ui/elements.py @@ -17,13 +17,7 @@ # limitations under the License. import pygame -try: - import graphics.GUI.pyguix.utils as utils -except ImportError: - try: - import GUI.pyguix.utils as utils - except ImportError: - import pyguix.utils as utils +import graphics.GUI.pyguix.utils as utils uth = utils.helper() # NOTE: When an action class is created, the base scope class adds its targetclasses as keys diff --git a/graphics/GUI/pyguix/utils.py b/graphics/GUI/pyguix/utils.py index 3be175c..6ae9d73 100644 --- a/graphics/GUI/pyguix/utils.py +++ b/graphics/GUI/pyguix/utils.py @@ -21,19 +21,9 @@ import dataclasses as dc import enum import json as js -try: - import graphics.GUI.pyguix.ui.themes as th - import graphics.GUI.pyguix.ui.context as cx - import graphics.GUI.pyguix.ui.settings as st -except ImportError: - try: - import GUI.pyguix.ui.themes as th - import GUI.pyguix.ui.context as cx - import GUI.pyguix.ui.settings as st - except ImportError: - import pyguix.ui.themes as th - import pyguix.ui.context as cx - import pyguix.ui.settings as st +import graphics.GUI.pyguix.ui.themes as th +import graphics.GUI.pyguix.ui.context as cx +import graphics.GUI.pyguix.ui.settings as st # Constants: DEFAULT_THEME='default.json' diff --git a/graphics/GUI/textboxify/__init__.py b/graphics/GUI/textboxify/__init__.py index ea35464..344b299 100644 --- a/graphics/GUI/textboxify/__init__.py +++ b/graphics/GUI/textboxify/__init__.py @@ -5,20 +5,10 @@ more elaborated boxes with animations and borders, because the package offers the ability to easily customize the boxes.""" -try: - # These are available when `import textboxify` is used. - from graphics.GUI.textboxify.text import Text - from graphics.GUI.textboxify.textbox import TextBox, TextBoxFrame +# These are available when `import textboxify` is used. +from graphics.GUI.textboxify.text import Text +from graphics.GUI.textboxify.textbox import TextBox, TextBoxFrame - # Border sprites are available with `textboxify.borders.DARK` after import or - # could be imported as: `textboxify.borders import *`. - from graphics.GUI.textboxify import borders -except ImportError: - try: - from GUI.textboxify.text import Text - from GUI.textboxify.textbox import TextBox, TextBoxFrame - from GUI.textboxify import borders - except: - from textboxify.text import Text - from textboxify.textbox import TextBox, TextBoxFrame - from textboxify import borders \ No newline at end of file +# Border sprites are available with `textboxify.borders.DARK` after import or +# could be imported as: `textboxify.borders import *`. +from graphics.GUI.textboxify import borders diff --git a/graphics/graphics.py b/graphics/graphics.py index 67d4c6d..9c51db3 100644 --- a/graphics/graphics.py +++ b/graphics/graphics.py @@ -1,17 +1,10 @@ import pygame, asyncio pygame.init() -try: - import graphics.graphics_options as GO - from graphics.loading import Loading - from graphics.GUI import TextBoxFrame, InputBox, Button - from graphics.async_handling import Progressbar - from graphics.GUI.textboxify.borders import LIGHT -except: - import graphics_options as GO - from loading import Loading - from async_handling import Progressbar - from GUI import TextBoxFrame, InputBox, Button - from GUI.textboxify.borders import LIGHT +import graphics.graphics_options as GO +from graphics.loading import Loading +from graphics.async_handling import Progressbar +from graphics.GUI import Button, TextBoxFrame +from graphics.GUI.textboxify.borders import LIGHT class TerminalBar: def __init__(self, win, spacing=5): diff --git a/main.py b/main.py index 9a53ce7..778d2ad 100644 --- a/main.py +++ b/main.py @@ -2,7 +2,6 @@ from utils.bot import TinyLLM, UserBot from graphics.GUI import InputBox, RESIZE_H, TextBoxFrame from graphics.GUI.textboxify.borders import LIGHT -from graphics import Progressbar import pygame, asyncio, random pygame.init() diff --git a/requirements.txt b/requirements.txt index fca82b5..1e058cc 100644 --- a/requirements.txt +++ b/requirements.txt @@ -9,3 +9,4 @@ matplotlib g4f bs4 googlesearch-python +html2text diff --git a/utils/Pyldtk.py b/utils/Pyldtk.py index 124eb40..b5f6e42 100644 --- a/utils/Pyldtk.py +++ b/utils/Pyldtk.py @@ -1,7 +1,7 @@ import json from math import floor import pygame -import os, sys +import os def get_data(file): with open(file, "r") as data: diff --git a/utils/bot/AIs.py b/utils/bot/AIs.py index 590940e..f09451e 100644 --- a/utils/bot/AIs.py +++ b/utils/bot/AIs.py @@ -1,4 +1,4 @@ -import os, sys, time +import os, time import g4f import asyncio, aiohttp @@ -6,17 +6,6 @@ import nest_asyncio nest_asyncio.apply() -if os.getcwd().endswith('bot'): # set path 2 folders above - newpath = os.path.abspath(os.path.join(os.getcwd(), '../../')) - os.chdir(newpath) -elif os.getcwd().endswith('utils'): # set folder to one above - newpath = os.path.abspath(os.path.join(os.getcwd(), '../')) - os.chdir(newpath) - -# now current folder should be '\AIHub' and not '\AIHub\utils' or '\AIHub\utils\bot' anymore! - -sys.path.append(os.getcwd()) - from utils.conversation_parse import PARSE from utils.characters import * from api_keys import loadAPIkeys diff --git a/utils/bot/__init__.py b/utils/bot/__init__.py index 3247415..d9e47c7 100644 --- a/utils/bot/__init__.py +++ b/utils/bot/__init__.py @@ -1,16 +1,7 @@ -try: - from utils.bot.gpt4real import * - from utils.bot.set_preferences import * - from utils.bot.AIs import * - from utils.bot.basebots import * - from utils.bot.install_tinyllm import * - from utils.bot.tinyllm import * - #from utils.bot.copilot import * # errors... -except ImportError: - from bot.gpt4real import * - from bot.set_preferences import * - from bot.AIs import * - from bot.basebots import * - from bot.install_tinyllm import * - from bot.tinyllm import * - #from bot.copilot import * +from utils.bot.gpt4real import * +from utils.bot.set_preferences import * +from utils.bot.AIs import * +from utils.bot.basebots import * +from utils.bot.install_tinyllm import * +from utils.bot.tinyllm import * +#from utils.bot.copilot import * # errors... diff --git a/utils/bot/basebots.py b/utils/bot/basebots.py index 2010a2e..3940559 100644 --- a/utils/bot/basebots.py +++ b/utils/bot/basebots.py @@ -1,16 +1,5 @@ import time, asyncio, aiohttp -import os, sys - -if os.getcwd().endswith('bot'): # set path 2 folders above - newpath = os.path.abspath(os.path.join(os.getcwd(), '../../')) - os.chdir(newpath) -elif os.getcwd().endswith('utils'): # set folder to one above - newpath = os.path.abspath(os.path.join(os.getcwd(), '../')) - os.chdir(newpath) - -# now current folder should be '\AIHub' and not '\AIHub\utils' or '\AIHub\utils\bot' anymore! - -sys.path.append(os.getcwd()) +import os from utils.conversation_parse import PARSE diff --git a/utils/bot/copilot.py b/utils/bot/copilot.py index ef5972b..2178cdd 100644 --- a/utils/bot/copilot.py +++ b/utils/bot/copilot.py @@ -1,14 +1,8 @@ import languagemodels as lm import re from difflib import get_close_matches as GCM -try: - from utils.bot.tinyllm import * -except: - try: - from bot.tinyllm import * - except: - from tinyllm import * -# This will only work with GPT4all. +from utils.bot.tinyllm import * +# This will only work with GPT4All. class Copilot: def __init__(self, name): diff --git a/utils/bot/set_preferences.py b/utils/bot/set_preferences.py index 9a96134..f9fb161 100644 --- a/utils/bot/set_preferences.py +++ b/utils/bot/set_preferences.py @@ -1,16 +1,5 @@ -import json, os -try: - from utils.bot.AIs import AI -except ImportError: - try: - from bot.AIs import AI - except ImportError: - from AIs import AI - -import os, re -bef = re.findall(r'((utils\/?)?(bot)?\n)', os.getcwd().replace('\\','/')+'\n')[0][0][:-1] # inp ends in newline -bef = '/'.join([i for i in ['utils', 'bot'] if i not in bef.split('/')]) -if bef != '': bef += '/' +import json +from utils.bot.AIs import AI def get_all_ais(): return AI().AIs @@ -21,7 +10,7 @@ def get_all_ai_names(): def set_preferences(prefs): eprefs = get_preferences() eprefs.update(prefs) - with open(f'{bef}preferences.json', 'w') as f: + with open(f'/utils/bot/preferences.json', 'w') as f: d = json.load(f) d['models'].update(eprefs) json.dump(d, f, indent=4) diff --git a/utils/bot/tinyllm.py b/utils/bot/tinyllm.py index d316d6d..7451906 100644 --- a/utils/bot/tinyllm.py +++ b/utils/bot/tinyllm.py @@ -1,12 +1,6 @@ import languagemodels as lm import re -try: - from utils.bot.install_tinyllm import installed -except: - try: - from bot.install_tinyllm import installed - except: - from install_tinyllm import installed +from utils.bot.install_tinyllm import installed from googlesearch import search # pip install beautifulsoup4 google import bs4, requests diff --git a/utils/characters.py b/utils/characters.py index 2fa6a48..6c75d9c 100644 --- a/utils/characters.py +++ b/utils/characters.py @@ -1,10 +1,6 @@ import os -try: - from utils.discussions import * - from utils.conversation_parse import PARSE2 -except ImportError: - from discussions import * - from conversation_parse import PARSE2 +from utils.discussions import * +from utils.conversation_parse import PARSE2 class Character: def __init__(self, AI, name, personality): diff --git a/utils/conversation_parse/__init__.py b/utils/conversation_parse/__init__.py index 10a7ce6..7c1f736 100644 --- a/utils/conversation_parse/__init__.py +++ b/utils/conversation_parse/__init__.py @@ -1,6 +1,2 @@ -try: - from utils.conversation_parse.conversation_parser import * - from utils.conversation_parse.consts import * -except ImportError: - from conversation_parse.conversation_parser import * - from conversation_parse.consts import * +from utils.conversation_parse.conversation_parser import * +from utils.conversation_parse.consts import * diff --git a/utils/conversation_parse/conversation_parser.py b/utils/conversation_parse/conversation_parser.py index dc27f3f..9dd30b0 100644 --- a/utils/conversation_parse/conversation_parser.py +++ b/utils/conversation_parse/conversation_parser.py @@ -1,10 +1,4 @@ -try: - from utils.conversation_parse.consts import * -except ImportError: - try: - from conversation_parse.consts import * - except ImportError: - from consts import * +from utils.conversation_parse.consts import * import re from math import inf diff --git a/utils/converse.py b/utils/converse.py index 3cfa213..78e86b0 100644 --- a/utils/converse.py +++ b/utils/converse.py @@ -1,4 +1,3 @@ - # cnvrs = CoNVeRSation/CoNVeRSe class converse: diff --git a/utils/discussions.py b/utils/discussions.py index 3fef443..2a3d05b 100644 --- a/utils/discussions.py +++ b/utils/discussions.py @@ -1,4 +1,3 @@ - import sqlite3 from pathlib import Path __author__ = "parisneo" diff --git a/utils/terrainGen.py b/utils/terrainGen.py index ac6a521..e2c4cbf 100644 --- a/utils/terrainGen.py +++ b/utils/terrainGen.py @@ -1,8 +1,5 @@ # https://github.com/BilHim/minecraft-world-generation/blob/main/src/Minecraft%20Terrain%20Generation%20in%20Python%20-%20By%20Bilal%20Himite.ipynb - # Imports and parameters -# print('Importing...') - from random import randint import numpy as np from matplotlib import pyplot as plt @@ -17,10 +14,7 @@ from scipy.ndimage.filters import gaussian_filter from scipy.ndimage.morphology import binary_dilation -try: - from utils.conversation_parse import parseKWs -except: - from conversation_parse import parseKWs +from utils.conversation_parse import parseKWs class Map: def __init__(self, *args, **kwargs): diff --git a/utils/world.py b/utils/world.py index e55fa11..5b6fa4d 100644 --- a/utils/world.py +++ b/utils/world.py @@ -4,16 +4,10 @@ from math import floor, sqrt from copy import deepcopy -try: - from utils.characters import * - from utils.storyline import * - from utils.terrainGen import * - import utils.Pyldtk as ldtk -except ImportError: - from characters import * - from storyline import * - from terrainGen import * - import Pyldtk as ldtk +from utils.characters import * +from utils.storyline import * +from utils.terrainGen import * +import utils.Pyldtk as ldtk folder = 'data/worlds/' From 5870d60867d93cee5405f97afa4c5b45fd754b93 Mon Sep 17 00:00:00 2001 From: Max Worrall <96847801+Tsunami014@users.noreply.github.com> Date: Fri, 17 Nov 2023 08:23:21 +1100 Subject: [PATCH 34/91] =?UTF-8?q?feat(main):=20=F0=9F=9A=9A=20Moved=20the?= =?UTF-8?q?=20API=20keys=20demo=20to=20demos.py?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- api_keys.py | 3 --- demos.py | 5 +++++ 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/api_keys.py b/api_keys.py index 16dd826..27bfad7 100644 --- a/api_keys.py +++ b/api_keys.py @@ -158,6 +158,3 @@ def __init__(self): # Start the Tkinter main loop self.root.mainloop() - -if __name__ == '__main__': - SaveAPIKeysDialog() \ No newline at end of file diff --git a/demos.py b/demos.py index dac59db..093bf82 100644 --- a/demos.py +++ b/demos.py @@ -174,6 +174,10 @@ def rateAIsDemo(): from utils.bot import rate_all asyncio.run(rate_all()) +def api_keysDemo(): + from api_keys import SaveAPIKeysDialog + SaveAPIKeysDialog() + if __name__ == '__main__': root = Tk.Tk() def cmd(cmdd): @@ -188,4 +192,5 @@ def cmd(cmdd): Tk.Button(root, text='TinyLLM Demo', command=lambda: cmd(tinyLLMDemo)).pack() Tk.Button(root, text='Test LLM Demo', command=lambda: cmd(testLLMDemo)).pack() Tk.Button(root, text='Rate AIs Demo', command=lambda: cmd(rateAIsDemo)).pack() + Tk.Button(root, text='API keys Demo', command=lambda: cmd(rateAIsDemo)).pack() root.mainloop() From d3086ea12bf25b516eb97da9e6295231656ed8c3 Mon Sep 17 00:00:00 2001 From: Max Worrall <96847801+Tsunami014@users.noreply.github.com> Date: Fri, 17 Nov 2023 08:25:06 +1100 Subject: [PATCH 35/91] =?UTF-8?q?feat(GUI):=20=E2=9C=A8=20Added=20(blank)?= =?UTF-8?q?=20NodeEditor=20demo!?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- demos.py | 6 +++++- elementGen/__init__.py | 1 + 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/demos.py b/demos.py index 093bf82..b8564db 100644 --- a/demos.py +++ b/demos.py @@ -178,6 +178,9 @@ def api_keysDemo(): from api_keys import SaveAPIKeysDialog SaveAPIKeysDialog() +def node_editorDemo(): + pass + if __name__ == '__main__': root = Tk.Tk() def cmd(cmdd): @@ -192,5 +195,6 @@ def cmd(cmdd): Tk.Button(root, text='TinyLLM Demo', command=lambda: cmd(tinyLLMDemo)).pack() Tk.Button(root, text='Test LLM Demo', command=lambda: cmd(testLLMDemo)).pack() Tk.Button(root, text='Rate AIs Demo', command=lambda: cmd(rateAIsDemo)).pack() - Tk.Button(root, text='API keys Demo', command=lambda: cmd(rateAIsDemo)).pack() + Tk.Button(root, text='API Keys Demo', command=lambda: cmd(api_keysDemo)).pack() + Tk.Button(root, text='Node Editor Demo', command=lambda: cmd(node_editorDemo)).pack() root.mainloop() diff --git a/elementGen/__init__.py b/elementGen/__init__.py index e69de29..ab7a93f 100644 --- a/elementGen/__init__.py +++ b/elementGen/__init__.py @@ -0,0 +1 @@ +from elementGen.node_editor import * From f3eb37b99aa3b7ab54ca920d56710a63d120280a Mon Sep 17 00:00:00 2001 From: Max Worrall <96847801+Tsunami014@users.noreply.github.com> Date: Fri, 17 Nov 2023 08:28:31 +1100 Subject: [PATCH 36/91] =?UTF-8?q?feat(GUI):=20=E2=9C=A8=20Made=20the=20bas?= =?UTF-8?q?ic=20NodeEditor=20function!=20Still=20does=20nothing=20yet.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit But also added docstring! --- demos.py | 5 ++++- elementGen/node_editor.py | 16 ++++++++++++++++ 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/demos.py b/demos.py index b8564db..1ac7a6a 100644 --- a/demos.py +++ b/demos.py @@ -179,7 +179,10 @@ def api_keysDemo(): SaveAPIKeysDialog() def node_editorDemo(): - pass + from graphics import Graphic + from elementGen import NodeEditor + G = Graphic() + NodeEditor(G) if __name__ == '__main__': root = Tk.Tk() diff --git a/elementGen/node_editor.py b/elementGen/node_editor.py index e69de29..a59e2bb 100644 --- a/elementGen/node_editor.py +++ b/elementGen/node_editor.py @@ -0,0 +1,16 @@ +def NodeEditor(G): + """Makes a Node Editor screen! Still in progress. Come back later! + + Parameters + ---------- + G : graphics.Graphic + The Graphic screen + + USE: +```py +from graphics import Graphic +G = Graphic() +NodeEditor(G) +``` + """ + pass From 817330b85ce35e3f97a40feb7cb502dc355d3c15 Mon Sep 17 00:00:00 2001 From: Max Worrall <96847801+Tsunami014@users.noreply.github.com> Date: Fri, 17 Nov 2023 08:55:50 +1100 Subject: [PATCH 37/91] =?UTF-8?q?feat(GUI):=20=E2=9C=A8=20Put=20the=20Grap?= =?UTF-8?q?hic=20Demo=20into=20node=5Feditor?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- elementGen/node_editor.py | 70 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 69 insertions(+), 1 deletion(-) diff --git a/elementGen/node_editor.py b/elementGen/node_editor.py index a59e2bb..7b88201 100644 --- a/elementGen/node_editor.py +++ b/elementGen/node_editor.py @@ -1,3 +1,7 @@ +import graphics.graphics_options as GO +import pygame +from time import sleep + def NodeEditor(G): """Makes a Node Editor screen! Still in progress. Come back later! @@ -13,4 +17,68 @@ def NodeEditor(G): NodeEditor(G) ``` """ - pass + @G.Loading + def test_loading(self): + for self.i in range(10): + sleep(1) + + @G.Graphic + def test(event, txt, element=None, aborted=False): # You do not need args and kwargs if you KNOW that your function will not take them in. Include what you need. + if event == GO.EFIRST: # First, before anything else happens in the function + G.Container.txt = txt + if event == GO.ELOADUI: # Load the graphics + CTOP = GO.PNEW([1, 0], GO.PSTACKS[GO.PCTOP][1], 0) # Bcos usually the Center Top makes the elements stack down, so I make a new thing that stacks sideways + G.Clear() + G.add_text('HI', GO.CGREEN, GO.PRBOTTOM, GO.FTITLE) + G.add_text(':) ', GO.CBLACK, GO.PRBOTTOM, GO.FTITLE) + G.add_empty_space(GO.PCCENTER, 0, -150) # Yes, you can have negative space. This makes the next things shifted the other direction. + G.add_text('This is a cool thing', GO.CBLUE, GO.PCCENTER) + G.add_text('Sorry, I meant a cool TEST', GO.CRED, GO.PCCENTER) + G.add_text(G.Container.txt, GO.CGREEN, GO.PCCENTER) + G.add_empty_space(GO.PCBOTTOM, 0, 20) + G.add_button('Button 1 :D', GO.CYELLOW, GO.PCBOTTOM) + G.add_text('Buttons above [^] and below [v]', GO.CBLUE, GO.PCBOTTOM) + G.add_button('Textbox test', GO.CBLUE, GO.PCBOTTOM) + G.add_button('Loading test', GO.CGREEN, GO.PCBOTTOM) + G.Container.exitbtn = G.add_button('EXIT', GO.CRED, GO.PCBOTTOM) + G.add_empty_space(CTOP, -150, 0) # Center it a little more + G.add_text('Are you ', GO.CBLACK, CTOP) + G.add_text('happy? ', GO.CGREEN, CTOP) + G.add_text('Or sad?', GO.CRED, CTOP) + elif event == GO.ETICK: # This runs every 1/60 secs (each tick) + return True # Return whether or not the loop should continue. + elif event == GO.EELEMENTCLICK: # Some UI element got clicked! + if element.type == GO.TBUTTON: + # This gets passed 'element': the element that got clicked. TODO: make an Element class + # The == means element's uid == __ + # UID gets generated based off order: so UID of 2 means second thing created that makes a UID. + # When you create a thing that makes a UID it returns it. e.g. button1 = G.add_button(etc.) + # So in that example button1 is the UID. Maybe try saving it to the container tho! Example shown by the exit button. + if element == 2: + succeeded, ret = test_loading() + G.Container.txt = ('Ran for %i seconds%s' % (ret['i']+1, (' Successfully! :)' if succeeded else ' And failed :('))) + G.Reload() + elif element == G.Container.exitbtn: + G.Abort() + elif element == 1: + bot = GO.PNEW([0, 0], GO.PSTACKS[GO.PCBOTTOM][1], 1) + G.add_TextBox('HALLOOOO! :)', bot) + G.Container.idx = 0 + else: + G.Container.txt = element.txt # put name of button in middle + G.Reload() + elif element.type == GO.TTEXTBOX: + if G.Container.idx == 0: + element.set_text("Happy coding!") + G.Container.idx = 1 + else: + element.remove() + elif event == GO.EEVENT: # When something like a button is pressed. Is passed 'element' too, but this time it is an event + if element.type == pygame.KEYDOWN: + if element.key == pygame.K_SPACE: + G.Container.txt = 'You pressed space!' + G.Reload() + elif event == GO.ELAST: + # This also gets passed 'aborted': Whether you aborted or exited the screen + return aborted # Whatever you return here will be returned by the function + return test() From b2329c2d69ca14c58d968351bc8421d68882bd48 Mon Sep 17 00:00:00 2001 From: Max Worrall <96847801+Tsunami014@users.noreply.github.com> Date: Fri, 17 Nov 2023 15:34:30 +1100 Subject: [PATCH 38/91] =?UTF-8?q?docs(GUI):=20=F0=9F=93=9D=20Added=20what?= =?UTF-8?q?=20we=20need=20to=20do=20in=20the=20nodeeditor?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- elementGen/node_editor.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/elementGen/node_editor.py b/elementGen/node_editor.py index 7b88201..a88d69f 100644 --- a/elementGen/node_editor.py +++ b/elementGen/node_editor.py @@ -2,6 +2,10 @@ import pygame from time import sleep +# Select element to edit screen (copy world select) +# Each category of elements is a sub-folder under data/elements/ +# As well as a NodeEditor screen have a NodeRenderer screen, which is also used in NodeEditor + def NodeEditor(G): """Makes a Node Editor screen! Still in progress. Come back later! From c28f9951ec3a85c4b1b7ddd55c1f1de8aa16c813 Mon Sep 17 00:00:00 2001 From: Max Worrall <96847801+Tsunami014@users.noreply.github.com> Date: Fri, 17 Nov 2023 15:54:16 +1100 Subject: [PATCH 39/91] =?UTF-8?q?feat(GUI):=20=F0=9F=A9=B9=20Added=20the?= =?UTF-8?q?=20node=5Feditor=20selection=20screen?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Also modified one or two things in other files to make it work --- __main__.py | 4 +- demos.py | 4 +- elementGen/node_editor.py | 79 ++++++++++++++++++++++++++++++++++++++- graphics/graphics.py | 4 +- 4 files changed, 85 insertions(+), 6 deletions(-) diff --git a/__main__.py b/__main__.py index ab91575..6225554 100644 --- a/__main__.py +++ b/__main__.py @@ -79,14 +79,14 @@ def load(self): return True elif event == GO.EELEMENTCLICK: # Passed 'element' if element == 0: # back - return None + return False elif element == 1: # make new world @G.Loading def NW(self): # TODO: make a GUI screen to ask fr title and description self.world = World('newworld', 'New World', 'a new world', 25, quality=500) cont, res = NW() if cont: - self.world(res['world'], True) + return self.world(res['world'], True) else: return self.world(World(G.Container.res['worlds'][element.uid-2].name)) elif event == GO.ELAST: diff --git a/demos.py b/demos.py index 1ac7a6a..3325553 100644 --- a/demos.py +++ b/demos.py @@ -180,9 +180,9 @@ def api_keysDemo(): def node_editorDemo(): from graphics import Graphic - from elementGen import NodeEditor + from elementGen import NodeSelector G = Graphic() - NodeEditor(G) + print(NodeSelector(G)) if __name__ == '__main__': root = Tk.Tk() diff --git a/elementGen/node_editor.py b/elementGen/node_editor.py index a88d69f..35822a0 100644 --- a/elementGen/node_editor.py +++ b/elementGen/node_editor.py @@ -1,7 +1,84 @@ import graphics.graphics_options as GO -import pygame +import pygame, os, json from time import sleep +categories = [ + 'characters', + 'tilemaps', + 'others' +] + +def NodeSelector(G): + """Makes a Node Selector screen! Still in progress. Come back later! + + Parameters + ---------- + G : graphics.Graphic + The Graphic screen + + USE: +```py +from graphics import Graphic +G = Graphic() +NodeSelector(G) +``` + """ + @G.Graphic + def item_select(event, category, element=None, aborted=False): + if event == GO.EFIRST: + @G.Loading + def load(self): + self.items = [i for i in os.scandir('data/elements/'+category) if i.is_file()] + self.iteminfo = [json.load(open('data/elements/%s/%s/dat.json'%(category, i.name))) for i in self.items] + self.subs = ['Go back to the previous page', 'Make a new item from scratch'] + [i['idea'] for i in self.iteminfo] + cont, res = load() + G.Container.res = res + G.Container.txt = '' + G.Container.prevpresses = [] + if not cont: G.Abort() + elif event == GO.ELOADUI: + G.Clear() + G.add_text(category + ' item selection', GO.CBLACK, GO.PCTOP) + G.add_text(G.Container.txt, GO.CBLUE, GO.PCTOP) + G.add_button('Back', GO.CGREY, GO.PLTOP) + G.add_button('New Item', GO.CGREEN, GO.PLTOP) + for i in G.Container.res['iteminfo']: + G.add_button(i['name'], GO.CBLUE, GO.PLCENTER) + elif event == GO.ETICK: + if G.touchingbtns != G.Container.prevpresses: + G.Container.prevpresses = G.touchingbtns.copy() + try: G.Container.txt = G.Container.res['subs'][G.get_idx(G.touchingbtns[0])] + except: G.Container.txt = '' + G.Reload() + return True + elif event == GO.EELEMENTCLICK: # Passed 'element' + if element == 0: # back + return False + elif element == 1: # make new world + return 'NEW' + else: + return G.Container.res['worlds'][element.uid-2].name + @G.Graphic + def category_select(event, element=None, aborted=False): + if event == GO.ELOADUI: + G.Clear() + G.add_text('Category selection', GO.CBLACK, GO.PCTOP) + G.add_button('Back', GO.CGREY, GO.PLTOP) + G.add_button('New Category', GO.CGREEN, GO.PLTOP) + for i in categories: + G.add_button(i, GO.CBLUE, GO.PLCENTER) + elif event == GO.ETICK: + return True + elif event == GO.EELEMENTCLICK: # Passed 'element' + if element == 0: # back + return None + elif element == 1: # make new world + return 'NEW/NEW' + else: + name = element.txt + return name + item_select(name) + return category_select() + # Select element to edit screen (copy world select) # Each category of elements is a sub-folder under data/elements/ # As well as a NodeEditor screen have a NodeRenderer screen, which is also used in NodeEditor diff --git a/graphics/graphics.py b/graphics/graphics.py index 9c51db3..6c040c3 100644 --- a/graphics/graphics.py +++ b/graphics/graphics.py @@ -239,7 +239,9 @@ def func(event, element=None, aborted=False): if event.button == pygame.BUTTON_LEFT: self.TB.toggleactive(not self.TB.collides(*event.pos)) for i in self.touchingbtns: - func(GO.EELEMENTCLICK, Element(GO.TBUTTON, self.uids.index(i[0]), self, btn=i)) + r = func(GO.EELEMENTCLICK, Element(GO.TBUTTON, self.uids.index(i[0]), self, btn=i)) + if r != None: + return r if not self.pause and not blocked: func(GO.EEVENT, event) self.TB.update() for ibox in self.input_boxes: From e4fd734a3ca1ed63eb19c26b6821912e4803ed4c Mon Sep 17 00:00:00 2001 From: Max Worrall <96847801+Tsunami014@users.noreply.github.com> Date: Fri, 17 Nov 2023 16:00:15 +1100 Subject: [PATCH 40/91] =?UTF-8?q?feat(GUI):=20=E2=9C=A8=20Added=20rainbow?= =?UTF-8?q?=20colours=20to=20make=20for=20less=20monotonous=20UI=20:)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- __main__.py | 3 ++- elementGen/node_editor.py | 6 ++++-- graphics/graphics_options.py | 12 ++++++++++++ 3 files changed, 18 insertions(+), 3 deletions(-) diff --git a/__main__.py b/__main__.py index 6225554..ca64e16 100644 --- a/__main__.py +++ b/__main__.py @@ -68,8 +68,9 @@ def load(self): G.add_text(G.Container.txt, GO.CBLUE, GO.PCTOP) G.add_button('Back', GO.CGREY, GO.PLTOP) G.add_button('New World', GO.CGREEN, GO.PLTOP) + cols = GO.CRAINBOW() for i in G.Container.res['worldinfo']: - G.add_button(i['name'], GO.CBLUE, GO.PLCENTER) + G.add_button(i['name'], next(cols), GO.PLCENTER) elif event == GO.ETICK: if G.touchingbtns != G.Container.prevpresses: G.Container.prevpresses = G.touchingbtns.copy() diff --git a/elementGen/node_editor.py b/elementGen/node_editor.py index 35822a0..433ba57 100644 --- a/elementGen/node_editor.py +++ b/elementGen/node_editor.py @@ -42,8 +42,9 @@ def load(self): G.add_text(G.Container.txt, GO.CBLUE, GO.PCTOP) G.add_button('Back', GO.CGREY, GO.PLTOP) G.add_button('New Item', GO.CGREEN, GO.PLTOP) + cols = GO.CRAINBOW() for i in G.Container.res['iteminfo']: - G.add_button(i['name'], GO.CBLUE, GO.PLCENTER) + G.add_button(i['name'], next(cols), GO.PLCENTER) elif event == GO.ETICK: if G.touchingbtns != G.Container.prevpresses: G.Container.prevpresses = G.touchingbtns.copy() @@ -65,8 +66,9 @@ def category_select(event, element=None, aborted=False): G.add_text('Category selection', GO.CBLACK, GO.PCTOP) G.add_button('Back', GO.CGREY, GO.PLTOP) G.add_button('New Category', GO.CGREEN, GO.PLTOP) + cols = GO.CRAINBOW() for i in categories: - G.add_button(i, GO.CBLUE, GO.PLCENTER) + G.add_button(i, next(cols), GO.PLCENTER) elif event == GO.ETICK: return True elif event == GO.EELEMENTCLICK: # Passed 'element' diff --git a/graphics/graphics_options.py b/graphics/graphics_options.py index ca9dbe6..27f9033 100644 --- a/graphics/graphics_options.py +++ b/graphics/graphics_options.py @@ -15,6 +15,18 @@ def CNEW(name): CINACTIVE = CNEW('lightskyblue3') CACTIVE = CNEW('dodgerblue2') +def CRAINBOW(): + l = [ + CRED, + CYELLOW, + CGREEN, + CBLUE, + CBLACK, + CGREY + ] + while True: + for i in l: yield i + # Fonts FTITLE = pygame.font.SysFont('Comic Sans MS', 64, True) FCODEFONT = pygame.font.SysFont('Lucida Sans Typewriter', 16) From 15df123bcef9b2f4da7d13154ddcebebdb2c2c44 Mon Sep 17 00:00:00 2001 From: Max Worrall <96847801+Tsunami014@users.noreply.github.com> Date: Sun, 19 Nov 2023 12:39:22 +1100 Subject: [PATCH 41/91] =?UTF-8?q?feat(GUI):=20=E2=9C=A8=20Made=20the=20nod?= =?UTF-8?q?e=20selector!=20Now=20you=20can=20make=20new=20nodes=20and=20se?= =?UTF-8?q?lect=20them=20:)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit But you cannot do anything with them yet --- demos.py | 2 +- elementGen/node_editor.py | 101 +++++++++++++------------------------- readme.md | 4 +- 3 files changed, 37 insertions(+), 70 deletions(-) diff --git a/demos.py b/demos.py index 3325553..c1a5041 100644 --- a/demos.py +++ b/demos.py @@ -182,7 +182,7 @@ def node_editorDemo(): from graphics import Graphic from elementGen import NodeSelector G = Graphic() - print(NodeSelector(G)) + print(NodeSelector(G, 2)) if __name__ == '__main__': root = Tk.Tk() diff --git a/elementGen/node_editor.py b/elementGen/node_editor.py index 433ba57..dbbe356 100644 --- a/elementGen/node_editor.py +++ b/elementGen/node_editor.py @@ -8,13 +8,15 @@ 'others' ] -def NodeSelector(G): +def NodeSelector(G, continue_to_edit=0): """Makes a Node Selector screen! Still in progress. Come back later! Parameters ---------- G : graphics.Graphic The Graphic screen + continue_to_edit : int, optional + Whether to, once selected, return (0 & default), run the editor and exit once the editor gets exited (1) OR go back into select dialog when exit (2) USE: ```py @@ -29,7 +31,7 @@ def item_select(event, category, element=None, aborted=False): @G.Loading def load(self): self.items = [i for i in os.scandir('data/elements/'+category) if i.is_file()] - self.iteminfo = [json.load(open('data/elements/%s/%s/dat.json'%(category, i.name))) for i in self.items] + self.iteminfo = [json.load(open('data/elements/%s/%s'%(category, i.name))) for i in self.items] self.subs = ['Go back to the previous page', 'Make a new item from scratch'] + [i['idea'] for i in self.iteminfo] cont, res = load() G.Container.res = res @@ -58,7 +60,7 @@ def load(self): elif element == 1: # make new world return 'NEW' else: - return G.Container.res['worlds'][element.uid-2].name + return G.Container.res['items'][element.uid-2].name @G.Graphic def category_select(event, element=None, aborted=False): if event == GO.ELOADUI: @@ -75,23 +77,34 @@ def category_select(event, element=None, aborted=False): if element == 0: # back return None elif element == 1: # make new world - return 'NEW/NEW' + if continue_to_edit == 1 or continue_to_edit == 2: + NodeEditor(G, 'NEW/NEW') + if continue_to_edit != 2: + return 'NEW/NEW' else: name = element.txt - return name + item_select(name) + selection = item_select(name) + if selection != False and selection != None: + pth = name + '/' + selection + if continue_to_edit == 1 or continue_to_edit == 2: + NodeEditor(G, pth) + if continue_to_edit != 2: + return pth return category_select() # Select element to edit screen (copy world select) # Each category of elements is a sub-folder under data/elements/ # As well as a NodeEditor screen have a NodeRenderer screen, which is also used in NodeEditor -def NodeEditor(G): +def NodeEditor(G, path): """Makes a Node Editor screen! Still in progress. Come back later! Parameters ---------- G : graphics.Graphic The Graphic screen + path : str + The path to the currently editing Node. e.g. 'Other/niceness' USE: ```py @@ -100,68 +113,22 @@ def NodeEditor(G): NodeEditor(G) ``` """ - @G.Loading - def test_loading(self): - for self.i in range(10): - sleep(1) - @G.Graphic - def test(event, txt, element=None, aborted=False): # You do not need args and kwargs if you KNOW that your function will not take them in. Include what you need. - if event == GO.EFIRST: # First, before anything else happens in the function - G.Container.txt = txt - if event == GO.ELOADUI: # Load the graphics - CTOP = GO.PNEW([1, 0], GO.PSTACKS[GO.PCTOP][1], 0) # Bcos usually the Center Top makes the elements stack down, so I make a new thing that stacks sideways + def editor(event, path, element=None, aborted=False): + if event == GO.EFIRST: + if path.endswith('.elm'): + path = path[:-4] + if not os.path.exists('data/elements/'+path+'.elm'): + open('data/elements/'+path+'.elm', 'w+').write('{"idea": "BLANK", "name": "New File"}') + G.Container.contents = json.load(open('data/elements/'+path+'.elm')) + G.Container.name = G.Container.contents['name'] + if event == GO.ELOADUI: G.Clear() - G.add_text('HI', GO.CGREEN, GO.PRBOTTOM, GO.FTITLE) - G.add_text(':) ', GO.CBLACK, GO.PRBOTTOM, GO.FTITLE) - G.add_empty_space(GO.PCCENTER, 0, -150) # Yes, you can have negative space. This makes the next things shifted the other direction. - G.add_text('This is a cool thing', GO.CBLUE, GO.PCCENTER) - G.add_text('Sorry, I meant a cool TEST', GO.CRED, GO.PCCENTER) - G.add_text(G.Container.txt, GO.CGREEN, GO.PCCENTER) - G.add_empty_space(GO.PCBOTTOM, 0, 20) - G.add_button('Button 1 :D', GO.CYELLOW, GO.PCBOTTOM) - G.add_text('Buttons above [^] and below [v]', GO.CBLUE, GO.PCBOTTOM) - G.add_button('Textbox test', GO.CBLUE, GO.PCBOTTOM) - G.add_button('Loading test', GO.CGREEN, GO.PCBOTTOM) - G.Container.exitbtn = G.add_button('EXIT', GO.CRED, GO.PCBOTTOM) - G.add_empty_space(CTOP, -150, 0) # Center it a little more - G.add_text('Are you ', GO.CBLACK, CTOP) - G.add_text('happy? ', GO.CGREEN, CTOP) - G.add_text('Or sad?', GO.CRED, CTOP) - elif event == GO.ETICK: # This runs every 1/60 secs (each tick) - return True # Return whether or not the loop should continue. - elif event == GO.EELEMENTCLICK: # Some UI element got clicked! - if element.type == GO.TBUTTON: - # This gets passed 'element': the element that got clicked. TODO: make an Element class - # The == means element's uid == __ - # UID gets generated based off order: so UID of 2 means second thing created that makes a UID. - # When you create a thing that makes a UID it returns it. e.g. button1 = G.add_button(etc.) - # So in that example button1 is the UID. Maybe try saving it to the container tho! Example shown by the exit button. - if element == 2: - succeeded, ret = test_loading() - G.Container.txt = ('Ran for %i seconds%s' % (ret['i']+1, (' Successfully! :)' if succeeded else ' And failed :('))) - G.Reload() - elif element == G.Container.exitbtn: - G.Abort() - elif element == 1: - bot = GO.PNEW([0, 0], GO.PSTACKS[GO.PCBOTTOM][1], 1) - G.add_TextBox('HALLOOOO! :)', bot) - G.Container.idx = 0 - else: - G.Container.txt = element.txt # put name of button in middle - G.Reload() - elif element.type == GO.TTEXTBOX: - if G.Container.idx == 0: - element.set_text("Happy coding!") - G.Container.idx = 1 - else: - element.remove() + G.add_text('EDITING ELEMENT "%s"'%G.Container.name, GO.CGREEN, GO.PCTOP, GO.FTITLE) + elif event == GO.ETICK: + return True elif event == GO.EEVENT: # When something like a button is pressed. Is passed 'element' too, but this time it is an event if element.type == pygame.KEYDOWN: - if element.key == pygame.K_SPACE: - G.Container.txt = 'You pressed space!' - G.Reload() - elif event == GO.ELAST: - # This also gets passed 'aborted': Whether you aborted or exited the screen - return aborted # Whatever you return here will be returned by the function - return test() + if element.key == pygame.K_s and event.mod & pygame.KMOD_SHIFT: + json.dump(G.Container.contents, open('data/elements/'+path+'.elm', 'w+')) # Save + return editor(path) diff --git a/readme.md b/readme.md index e52f783..396096f 100644 --- a/readme.md +++ b/readme.md @@ -36,6 +36,6 @@ pip install -r requirements.txt Please join our [Discord server](https://discord.gg/9zrGKtF6Cs) for any information, queries, bugs, conversations, etc. that you may have! ## Next versions coming soon: - - v2.0.0 - 💥`Flare Sudio` - got a world and storyline and actually is playable!!!! - - v3.0.0 - 🌋`Fire Sudio` - cos by then it'll be on fire :grin: - all functionality complete! + - v2.0.0 - 💥`Flare Sudio` - Is able to make a simple simple simple game, no real functionality yet but just the basics + - v3.0.0 - 🌋`Fire Sudio` - cos by then it'll be on fire 😁 - all functionality complete! - v4.0.0 - 🔥`Blaze Sudio` - Unity integration! (And for all those who love catchphrases: `Oh, I want to make a game the easy way! How?` `I'll Blaze it!` (like "I'll chatGPT it" but cooler 😎)) From 02d4ccc0a0e263fe4d6ec0d6cfdd9f4104cce50f Mon Sep 17 00:00:00 2001 From: Max Worrall <96847801+Tsunami014@users.noreply.github.com> Date: Mon, 20 Nov 2023 15:55:55 +1100 Subject: [PATCH 42/91] =?UTF-8?q?feat(graphics):=20=F0=9F=A9=BA=20Well=20t?= =?UTF-8?q?he=20demo=20for=20the=20graphics=20work=20and=20that's=20what?= =?UTF-8?q?=20the=20commits=20were=20so=20I'll=20assume=20it=20worked=20:)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- demos.py | 11 ++++++++--- graphics/graphics.py | 2 +- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/demos.py b/demos.py index c1a5041..0642f4c 100644 --- a/demos.py +++ b/demos.py @@ -35,6 +35,7 @@ def test(event, txt, element=None, aborted=False): # You do not need args and kw G.add_text('Are you ', GO.CBLACK, CTOP) G.add_text('happy? ', GO.CGREEN, CTOP) G.add_text('Or sad?', GO.CRED, CTOP) + G.Container.inp = G.add_input(GO.PCCENTER, GO.FFONT, maximum=16) elif event == GO.ETICK: # This runs every 1/60 secs (each tick) return True # Return whether or not the loop should continue. elif event == GO.EELEMENTCLICK: # Some UI element got clicked! @@ -63,14 +64,18 @@ def test(event, txt, element=None, aborted=False): # You do not need args and kw G.Container.idx = 1 else: element.remove() + elif element.type == GO.TINPUTBOX: + G.Container.txt = element.txt + element.remove() + G.Reload() elif event == GO.EEVENT: # When something like a button is pressed. Is passed 'element' too, but this time it is an event if element.type == pygame.KEYDOWN: - if element.key == pygame.K_SPACE: - G.Container.txt = 'You pressed space!' + if element.key == pygame.K_s and element.mod & pygame.KMOD_CTRL: + G.Container.txt = 'Saved! (Don\'t worry - this does nothing)' G.Reload() elif event == GO.ELAST: # This also gets passed 'aborted': Whether you aborted or exited the screen - return aborted # Whatever you return here will be returned by the function + return (aborted, G.uids[G.Container.inp].text) # Whatever you return here will be returned by the function print(test(t)) pygame.quit() # this here for very fast quitting diff --git a/graphics/graphics.py b/graphics/graphics.py index 6c040c3..00958b9 100644 --- a/graphics/graphics.py +++ b/graphics/graphics.py @@ -3,7 +3,7 @@ import graphics.graphics_options as GO from graphics.loading import Loading from graphics.async_handling import Progressbar -from graphics.GUI import Button, TextBoxFrame +from graphics.GUI import Button, TextBoxFrame, InputBox from graphics.GUI.textboxify.borders import LIGHT class TerminalBar: From ef17f6df5ecc56b6657b839404aca6d6a2cf20c6 Mon Sep 17 00:00:00 2001 From: Max Worrall <96847801+Tsunami014@users.noreply.github.com> Date: Mon, 20 Nov 2023 15:58:59 +1100 Subject: [PATCH 43/91] =?UTF-8?q?fix(GUI):=20=F0=9F=90=9B=20Fixed=20bug=20?= =?UTF-8?q?where=20you=20can=20interact=20with=20textbox=20while=20paused?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- graphics/graphics.py | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/graphics/graphics.py b/graphics/graphics.py index 00958b9..f04f51c 100644 --- a/graphics/graphics.py +++ b/graphics/graphics.py @@ -216,10 +216,13 @@ def func(event, element=None, aborted=False): blocked = False if event.type == pygame.QUIT: run = False - for ibox in self.input_boxes: - if ibox.handle_event(event, pygame.K_RETURN) == False: - func(GO.EELEMENTCLICK, Element(GO.TINPUTBOX, self.uids.index(ibox), self, sprite=ibox, txt=ibox.text)) - blocked = True + if not self.pause: + for ibox in self.input_boxes: + if ibox.handle_event(event, pygame.K_RETURN) == False: + func(GO.EELEMENTCLICK, Element(GO.TINPUTBOX, self.uids.index(ibox), self, sprite=ibox, txt=ibox.text)) + blocked = True + else: + for ibox in self.input_boxes: ibox.active = False if event.type == pygame.KEYDOWN: if event.key == pygame.K_ESCAPE: run = False From 0f080e81558fa752e6a72bd837fedc82b6cb542e Mon Sep 17 00:00:00 2001 From: Max Worrall <96847801+Tsunami014@users.noreply.github.com> Date: Mon, 20 Nov 2023 16:08:43 +1100 Subject: [PATCH 44/91] =?UTF-8?q?feat(GUI):=20=E2=9C=A8=20Added=20a=20blan?= =?UTF-8?q?k=20settings=20page=20for=20the=20node=20editor=20:)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- elementGen/node_editor.py | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/elementGen/node_editor.py b/elementGen/node_editor.py index dbbe356..abb8418 100644 --- a/elementGen/node_editor.py +++ b/elementGen/node_editor.py @@ -125,6 +125,27 @@ def editor(event, path, element=None, aborted=False): if event == GO.ELOADUI: G.Clear() G.add_text('EDITING ELEMENT "%s"'%G.Container.name, GO.CGREEN, GO.PCTOP, GO.FTITLE) + G.add_button('Settings', GO.CGREEN, GO.PRTOP) + elif event == GO.EELEMENTCLICK: # This is going to be the only button that was created + @G.Graphic + def settings(event, element=None, aborted=False): + if event == GO.ELOADUI: + CBOT = GO.PNEW([1, 0], GO.PSTACKS[GO.PCBOTTOM][1], 0) + G.Clear() + G.add_empty_space(CBOT, -20, 0) + G.Container.go = G.add_button('Apply!', GO.CGREEN, CBOT) + G.Container.exit = G.add_button('Cancel', GO.CGREY, CBOT) + elif event == GO.ETICK: return True + elif event == GO.EELEMENTCLICK: + if element == G.Container.go: + print('GO!') + G.Abort() + elif element == G.Container.exit: + print('Cancel. :(') + G.Abort() + elif event == GO.ELAST: + pass # Whatever you return here will be returned by the function + settings() elif event == GO.ETICK: return True elif event == GO.EEVENT: # When something like a button is pressed. Is passed 'element' too, but this time it is an event From 9cd9125791091c61251a5650e326ef7b993072d3 Mon Sep 17 00:00:00 2001 From: Max Worrall <96847801+Tsunami014@users.noreply.github.com> Date: Mon, 20 Nov 2023 16:09:33 +1100 Subject: [PATCH 45/91] =?UTF-8?q?build(build):=20=F0=9F=99=88=20Added=20ne?= =?UTF-8?q?w=20elm=20file=20to=20list=20of=20files=20to=20ignore?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 1b601b4..23c1af5 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,4 @@ keys/apiKeys.key *.db *.ldtk *.json +*.elm From 34d8d2d9eb3f80026970946347295f2dbc1469dc Mon Sep 17 00:00:00 2001 From: Max Worrall <96847801+Tsunami014@users.noreply.github.com> Date: Tue, 21 Nov 2023 15:47:49 +1100 Subject: [PATCH 46/91] =?UTF-8?q?docs(docs):=20=F0=9F=93=9D=20Minor=20doc?= =?UTF-8?q?=20add?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- readme.md | 1 + 1 file changed, 1 insertion(+) diff --git a/readme.md b/readme.md index 396096f..ad34f51 100644 --- a/readme.md +++ b/readme.md @@ -23,6 +23,7 @@ Things to note: 3. I can modify it myself 4. You guys don't have to install another package 5. It won't ever change (unless I change it myself) +6. `git merge [branch2]` will not delete the second branch. DO NOT USE `git rebase [branch2]` AS A REPLACEMENT TODO: get link to Pyldtk From d69e58803e2d6860eaa5ad593f845e97246724f9 Mon Sep 17 00:00:00 2001 From: Max Worrall <96847801+Tsunami014@users.noreply.github.com> Date: Wed, 22 Nov 2023 07:50:43 +1100 Subject: [PATCH 47/91] =?UTF-8?q?feat(main):=20=E2=9C=A8=20Made=20the=20no?= =?UTF-8?q?de=20editor=20settings=20page=20have=20a=20textbox=20that=20cha?= =?UTF-8?q?nges=20the=20name=20of=20the=20node=20:)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- elementGen/node_editor.py | 24 +++++++++++++++++++++++- graphics/GUI/inputbox.py | 2 +- graphics/graphics.py | 7 +++++-- 3 files changed, 29 insertions(+), 4 deletions(-) diff --git a/elementGen/node_editor.py b/elementGen/node_editor.py index abb8418..96f9225 100644 --- a/elementGen/node_editor.py +++ b/elementGen/node_editor.py @@ -116,6 +116,7 @@ def NodeEditor(G, path): @G.Graphic def editor(event, path, element=None, aborted=False): if event == GO.EFIRST: + G.Container.saved = False if path.endswith('.elm'): path = path[:-4] if not os.path.exists('data/elements/'+path+'.elm'): @@ -131,7 +132,12 @@ def editor(event, path, element=None, aborted=False): def settings(event, element=None, aborted=False): if event == GO.ELOADUI: CBOT = GO.PNEW([1, 0], GO.PSTACKS[GO.PCBOTTOM][1], 0) + RTOP = GO.PNEW([0, 1], GO.PSTACKS[GO.PRTOP][1], 1) + LTOP = GO.PNEW([0, 1], GO.PSTACKS[GO.PLTOP][1], 2) G.Clear() + G.add_text('SETTINGS FOR NODE "%s":'%G.Container.name, GO.CGREEN, LTOP, GO.FFONT) + G.Container.inpname = G.add_input(LTOP, width=G.size[0]/3, resize=GO.RNONE, placeholder=G.Container.name) + G.add_text('SETTINGS FOR NODE EDITOR:', GO.CBLUE, RTOP, GO.FFONT) G.add_empty_space(CBOT, -20, 0) G.Container.go = G.add_button('Apply!', GO.CGREEN, CBOT) G.Container.exit = G.add_button('Cancel', GO.CGREY, CBOT) @@ -144,12 +150,28 @@ def settings(event, element=None, aborted=False): print('Cancel. :(') G.Abort() elif event == GO.ELAST: + res = G.uids[G.Container.inpname].text + if res != '': + G.Container.name = res + G.Container.contents['name'] = res pass # Whatever you return here will be returned by the function settings() elif event == GO.ETICK: return True elif event == GO.EEVENT: # When something like a button is pressed. Is passed 'element' too, but this time it is an event if element.type == pygame.KEYDOWN: - if element.key == pygame.K_s and event.mod & pygame.KMOD_SHIFT: + if element.key == pygame.K_s and element.mod & pygame.KMOD_CTRL: + if path.endswith('.elm'): + path = path[:-4] + G.Container.saved = True json.dump(G.Container.contents, open('data/elements/'+path+'.elm', 'w+')) # Save + elif event == GO.ELAST: + if G.Container.saved: + if path.endswith('.elm'): + path = path[:-4] + if G.Container.name != path.split('/')[1]: + os.remove('data/elements/'+path+'.elm') + path = path.split('/')[0] + '/' + G.Container.name + open('data/elements/'+path+'.elm', 'w+') + json.dump(G.Container.contents, open('data/elements/'+path+'.elm', 'w+')) return editor(path) diff --git a/graphics/GUI/inputbox.py b/graphics/GUI/inputbox.py index a16f525..406ec4d 100644 --- a/graphics/GUI/inputbox.py +++ b/graphics/GUI/inputbox.py @@ -60,7 +60,7 @@ def render_txt(self): ls = [self.text] else: ls = renderTextCenteredAt(self.text, self.font, self.rect.w - 5) - if self.resize == GO.RNONE: + if self.resize == GO.RNONE and ls != []: ls = [ls[0]] for line in ls: diff --git a/graphics/graphics.py b/graphics/graphics.py index bc3f4c8..1f94687 100644 --- a/graphics/graphics.py +++ b/graphics/graphics.py @@ -107,6 +107,7 @@ def get(self): Only works on: - GO.TSWITCH + - GO.TINPUTBOX Returns ------- @@ -115,6 +116,8 @@ def get(self): """ if self.type == GO.TSWITCH: return self.sprite.get() + elif self.type == GO.TINPUTBOX: + return self.sprite.text else: raise NotImplementedError( f'Set text has not been implemented for this element with type {self.name}!' @@ -433,8 +436,8 @@ def add_input(self, position, font=GO.FSMALL, width=None, resize=GO.RHEIGHT, pla int the UID of this element """ - sze = font.size(placeholder) - if maximum == None: maximum = sze + sze = list(font.size(placeholder)) + sze[1] += 10 if width != None: sze[0] = width pos = self.pos_store(GO.PSTACKS[position][1](self.size, sze), sze, position) ibox = InputBox(*pos, *sze, resize, placeholder, font, maximum) # TODO: Positioning and custom width & height & resize From 0ef3379e0fc38c26164780609a8f1b1169c901aa Mon Sep 17 00:00:00 2001 From: Max Worrall <96847801+Tsunami014@users.noreply.github.com> Date: Wed, 22 Nov 2023 08:07:53 +1100 Subject: [PATCH 48/91] =?UTF-8?q?feat(main):=20=E2=9C=A8=20Added=20first?= =?UTF-8?q?=20mouse=20press=20to=20node=20editor?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- elementGen/node_editor.py | 40 +++++++++++++++++++++++++++------------ 1 file changed, 28 insertions(+), 12 deletions(-) diff --git a/elementGen/node_editor.py b/elementGen/node_editor.py index 96f9225..61102f7 100644 --- a/elementGen/node_editor.py +++ b/elementGen/node_editor.py @@ -2,11 +2,14 @@ import pygame, os, json from time import sleep -categories = [ - 'characters', - 'tilemaps', - 'others' -] +categories = [i.name for i in os.scandir('data/elements') if i.is_dir()] + +def mouseDown(button=1): + i = False + while True: + r = pygame.mouse.get_pressed(3)[button-1] + yield ((i != r and r), r) + i = r def NodeSelector(G, continue_to_edit=0): """Makes a Node Selector screen! Still in progress. Come back later! @@ -117,6 +120,10 @@ def NodeEditor(G, path): def editor(event, path, element=None, aborted=False): if event == GO.EFIRST: G.Container.saved = False + G.Container.md = [ + mouseDown(), # Left mouse button + mouseDown(3) # Right mouse button + ] if path.endswith('.elm'): path = path[:-4] if not os.path.exists('data/elements/'+path+'.elm'): @@ -144,19 +151,28 @@ def settings(event, element=None, aborted=False): elif event == GO.ETICK: return True elif event == GO.EELEMENTCLICK: if element == G.Container.go: - print('GO!') + G.Container.went = True G.Abort() elif element == G.Container.exit: - print('Cancel. :(') + G.Container.went = False G.Abort() elif event == GO.ELAST: - res = G.uids[G.Container.inpname].text - if res != '': - G.Container.name = res - G.Container.contents['name'] = res - pass # Whatever you return here will be returned by the function + if G.Container.went: # Not cancelled + res = G.uids[G.Container.inpname].text + if res != '': + G.Container.name = res + G.Container.contents['name'] = res + pass # Whatever you return here will be returned by the function settings() elif event == GO.ETICK: + lf, l = next(G.Container.md[0]) + # lf = left mouse button first press, l = left mouse button is being pressed + rf, r = next(G.Container.md[1]) + # Same with r + if lf: + pygame.draw.circle(G.WIN, GO.CGREEN, pygame.mouse.get_pos(), 20) + elif l: + pygame.draw.circle(G.WIN, GO.CNEW('orange'), pygame.mouse.get_pos(), 10) return True elif event == GO.EEVENT: # When something like a button is pressed. Is passed 'element' too, but this time it is an event if element.type == pygame.KEYDOWN: From 93d80b3d656b976ec50ff31ed9dc0dbedd5ada91 Mon Sep 17 00:00:00 2001 From: Max Worrall <96847801+Tsunami014@users.noreply.github.com> Date: Wed, 22 Nov 2023 08:11:15 +1100 Subject: [PATCH 49/91] =?UTF-8?q?chore(GUI):=20=F0=9F=9A=9A=20Moved=20swit?= =?UTF-8?q?ch=20demo=20to=20demos.py?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Was left over after merge and I forgot to move it --- demos.py | 32 ++++++++++++++++++++++++++++++++ graphics/GUI/switch.py | 29 ----------------------------- 2 files changed, 32 insertions(+), 29 deletions(-) diff --git a/demos.py b/demos.py index 15548ab..8130993 100644 --- a/demos.py +++ b/demos.py @@ -199,6 +199,37 @@ def node_editorDemo(): G = Graphic() print(NodeSelector(G, 2)) +def switchDemo(): + import pygame + from graphics.GUI import Switch + pygame.init() + win = pygame.display.set_mode() + sprites = pygame.sprite.LayeredDirty() + curpos = (10, 10) + for _ in range(19): + s = Switch(win, *curpos, size=10+2*_) + sprites.add(s) + sze = s.rect.size + curpos = (curpos[0] + sze[0] + 10, curpos[1] + sze[1] + 10) + + run = True + while run: + for event in pygame.event.get(): + if event.type == pygame.QUIT: + run = False + elif event.type == pygame.KEYDOWN: + if event.key == pygame.K_ESCAPE: + run = False + elif event.type == pygame.MOUSEBUTTONDOWN: + if event.button == pygame.BUTTON_LEFT: + for i in sprites: + if i.rect.collidepoint(*pygame.mouse.get_pos()): + i.state = not i.state + win.fill((255, 255, 255)) + sprites.update() + pygame.display.update() + pygame.quit() + if __name__ == '__main__': root = Tk.Tk() def cmd(cmdd): @@ -214,5 +245,6 @@ def cmd(cmdd): Tk.Button(root, text='Test LLM Demo', command=lambda: cmd(testLLMDemo)).pack() Tk.Button(root, text='Rate AIs Demo', command=lambda: cmd(rateAIsDemo)).pack() Tk.Button(root, text='API Keys Demo', command=lambda: cmd(api_keysDemo)).pack() + Tk.Button(root, text='Switch Demo', command=lambda: cmd(switchDemo)).pack() Tk.Button(root, text='Node Editor Demo', command=lambda: cmd(node_editorDemo)).pack() root.mainloop() diff --git a/graphics/GUI/switch.py b/graphics/GUI/switch.py index eb5c26b..f6a64dd 100644 --- a/graphics/GUI/switch.py +++ b/graphics/GUI/switch.py @@ -24,33 +24,4 @@ def update(self): pygame.draw.circle(self.WIN, ((0, 255, 0) if self.state else (255, 0, 0)), (self.pos[0]+self.size/4+(self.anim/self.speed)*(self.size/20), self.pos[1]+self.size/4), self.size/2) def get(self): return self.state - -if __name__ == '__main__': - pygame.init() - win = pygame.display.set_mode() - sprites = pygame.sprite.LayeredDirty() - curpos = (10, 10) - for _ in range(19): - s = Switch(win, *curpos, size=10+2*_) - sprites.add(s) - sze = s.rect.size - curpos = (curpos[0] + sze[0] + 10, curpos[1] + sze[1] + 10) - - run = True - while run: - for event in pygame.event.get(): - if event.type == pygame.QUIT: - run = False - elif event.type == pygame.KEYDOWN: - if event.key == pygame.K_ESCAPE: - run = False - elif event.type == pygame.MOUSEBUTTONDOWN: - if event.button == pygame.BUTTON_LEFT: - for i in sprites: - if i.rect.collidepoint(*pygame.mouse.get_pos()): - i.state = not i.state - win.fill((255, 255, 255)) - sprites.update() - pygame.display.update() - pygame.quit() \ No newline at end of file From 0638de7e5531a936d00937d1f3cacdb29ec4d31d Mon Sep 17 00:00:00 2001 From: Max Worrall <96847801+Tsunami014@users.noreply.github.com> Date: Wed, 22 Nov 2023 08:14:00 +1100 Subject: [PATCH 50/91] =?UTF-8?q?chore(main):=20=F0=9F=8E=A8=20Made=20the?= =?UTF-8?q?=20commands=20down=20the=20bottom=20of=20demos.py=20look=20pret?= =?UTF-8?q?ty=20:)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Switched the order of 2 of them for ease of use too --- demos.py | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/demos.py b/demos.py index 8130993..6bf847b 100644 --- a/demos.py +++ b/demos.py @@ -235,16 +235,16 @@ def switchDemo(): def cmd(cmdd): root.destroy() cmdd() - Tk.Button(root, text='Loading Demo', command=lambda: cmd(LoadingDemo)).pack() - Tk.Button(root, text='Graphics Demo', command=lambda: cmd(GraphicsDemo)).pack() - Tk.Button(root, text='Generate World Demo', command=lambda: cmd(worldsDemo)).pack() - Tk.Button(root, text='Generate Terrain Demo', command=lambda: cmd(terrainGenDemo)).pack() - Tk.Button(root, text='Input Box Demo', command=lambda: cmd(inputBoxDemo)).pack() + Tk.Button(root, text='Node Editor Demo', command=lambda: cmd(node_editorDemo) ).pack() + Tk.Button(root, text='Loading Demo', command=lambda: cmd(LoadingDemo) ).pack() + Tk.Button(root, text='Graphics Demo', command=lambda: cmd(GraphicsDemo) ).pack() + Tk.Button(root, text='Generate World Demo', command=lambda: cmd(worldsDemo) ).pack() + Tk.Button(root, text='Generate Terrain Demo', command=lambda: cmd(terrainGenDemo) ).pack() + Tk.Button(root, text='Input Box Demo', command=lambda: cmd(inputBoxDemo) ).pack() + Tk.Button(root, text='TinyLLM Demo', command=lambda: cmd(tinyLLMDemo) ).pack() + Tk.Button(root, text='Test LLM Demo', command=lambda: cmd(testLLMDemo) ).pack() + Tk.Button(root, text='Rate AIs Demo', command=lambda: cmd(rateAIsDemo) ).pack() + Tk.Button(root, text='API Keys Demo', command=lambda: cmd(api_keysDemo) ).pack() + Tk.Button(root, text='Switch Demo', command=lambda: cmd(switchDemo) ).pack() Tk.Button(root, text='Conversation Parse Demo', command=lambda: cmd(conversation_parserDemo)).pack() - Tk.Button(root, text='TinyLLM Demo', command=lambda: cmd(tinyLLMDemo)).pack() - Tk.Button(root, text='Test LLM Demo', command=lambda: cmd(testLLMDemo)).pack() - Tk.Button(root, text='Rate AIs Demo', command=lambda: cmd(rateAIsDemo)).pack() - Tk.Button(root, text='API Keys Demo', command=lambda: cmd(api_keysDemo)).pack() - Tk.Button(root, text='Switch Demo', command=lambda: cmd(switchDemo)).pack() - Tk.Button(root, text='Node Editor Demo', command=lambda: cmd(node_editorDemo)).pack() root.mainloop() From 24e4c84ff611e0a751bffe60e122c4ba8a4e239c Mon Sep 17 00:00:00 2001 From: Max Worrall <96847801+Tsunami014@users.noreply.github.com> Date: Wed, 22 Nov 2023 08:23:30 +1100 Subject: [PATCH 51/91] =?UTF-8?q?feat(main):=20=E2=9C=A8=20Added=20node=5F?= =?UTF-8?q?parser.py=20and=20sample=20node!?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- data/nodes/test.py | 6 ++++++ demos.py | 6 ++++++ elementGen/__init__.py | 1 + elementGen/node_parser.py | 7 +++++++ 4 files changed, 20 insertions(+) create mode 100644 data/nodes/test.py create mode 100644 elementGen/node_parser.py diff --git a/data/nodes/test.py b/data/nodes/test.py new file mode 100644 index 0000000..28ef52c --- /dev/null +++ b/data/nodes/test.py @@ -0,0 +1,6 @@ +# @Add >int@A >int@B + +def node(A, B): + return A + B + +### END \ No newline at end of file diff --git a/demos.py b/demos.py index 6bf847b..f0a2b48 100644 --- a/demos.py +++ b/demos.py @@ -199,6 +199,11 @@ def node_editorDemo(): G = Graphic() print(NodeSelector(G, 2)) +def node_parserDemo(): + from elementGen import allCategories + alls = allCategories() + print('All categories:', alls) + def switchDemo(): import pygame from graphics.GUI import Switch @@ -236,6 +241,7 @@ def cmd(cmdd): root.destroy() cmdd() Tk.Button(root, text='Node Editor Demo', command=lambda: cmd(node_editorDemo) ).pack() + Tk.Button(root, text='Node Parser Demo', command=lambda: cmd(node_parserDemo) ).pack() Tk.Button(root, text='Loading Demo', command=lambda: cmd(LoadingDemo) ).pack() Tk.Button(root, text='Graphics Demo', command=lambda: cmd(GraphicsDemo) ).pack() Tk.Button(root, text='Generate World Demo', command=lambda: cmd(worldsDemo) ).pack() diff --git a/elementGen/__init__.py b/elementGen/__init__.py index ab7a93f..421c4be 100644 --- a/elementGen/__init__.py +++ b/elementGen/__init__.py @@ -1 +1,2 @@ from elementGen.node_editor import * +from elementGen.node_parser import * diff --git a/elementGen/node_parser.py b/elementGen/node_parser.py new file mode 100644 index 0000000..87a7301 --- /dev/null +++ b/elementGen/node_parser.py @@ -0,0 +1,7 @@ +import os + +def allCategories(): + return [i.name for i in os.scandir('data/nodes') if i.is_file()] + +def allNodes(category): + pass From 47d49a090c982ae27e90953632b0ded468cae929 Mon Sep 17 00:00:00 2001 From: Max Worrall <96847801+Tsunami014@users.noreply.github.com> Date: Wed, 22 Nov 2023 08:35:53 +1100 Subject: [PATCH 52/91] =?UTF-8?q?feat(main):=20=E2=9C=A8=20Made=20node=20p?= =?UTF-8?q?arser=20parse=20the=20nodes=20:)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- data/nodes/test.py | 4 ++-- demos.py | 4 ++-- elementGen/node_parser.py | 22 +++++++++++++++++++++- 3 files changed, 25 insertions(+), 5 deletions(-) diff --git a/data/nodes/test.py b/data/nodes/test.py index 28ef52c..f7dce7d 100644 --- a/data/nodes/test.py +++ b/data/nodes/test.py @@ -1,6 +1,6 @@ -# @Add >int@A >int@B +# @Add >int@A >int@B # def node(A, B): return A + B -### END \ No newline at end of file +# END # \ No newline at end of file diff --git a/demos.py b/demos.py index f0a2b48..a548ac1 100644 --- a/demos.py +++ b/demos.py @@ -200,9 +200,9 @@ def node_editorDemo(): print(NodeSelector(G, 2)) def node_parserDemo(): - from elementGen import allCategories + from elementGen import allCategories, allNodes, Parse alls = allCategories() - print('All categories:', alls) + print('All categories and nodes:', {i: allNodes(i) for i in alls}) def switchDemo(): import pygame diff --git a/elementGen/node_parser.py b/elementGen/node_parser.py index 87a7301..c8cc8b3 100644 --- a/elementGen/node_parser.py +++ b/elementGen/node_parser.py @@ -3,5 +3,25 @@ def allCategories(): return [i.name for i in os.scandir('data/nodes') if i.is_file()] +class Parse: + def __init__(self, category): + self.rdata = open('data/nodes/'+category).read() + self.data = {} + pattern = 0 + spl = self.rdata.split('#')[1:-1] + if spl[-1] == ' END ': spl = spl[:-1] # The END is for making it look nice, not actually needed + for i in spl: + i = i.strip(' \n') + if pattern == 0: + pattern = i + else: + self.data[pattern] = i + pattern = 0 + def __call__(self, funcname, *args, **kwargs): + exec(self.data[funcname]) + return eval('node(*args, **kwargs)', locals=locals()) + def getall(self): + return list(self.data.keys()) + def allNodes(category): - pass + return Parse(category).getall() From b615a70fea87d6a175f1bb68cfe420e91ee8d5ab Mon Sep 17 00:00:00 2001 From: Max Worrall <96847801+Tsunami014@users.noreply.github.com> Date: Wed, 22 Nov 2023 08:59:24 +1100 Subject: [PATCH 53/91] =?UTF-8?q?feat(main):=20=E2=9C=A8=20Made=20the=20no?= =?UTF-8?q?de=20parser=20WORK=20:D=20:D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The demo now has a Parse of test which includes the Add function adding 3 and 4 which successfully produces 7 :) --- data/nodes/test.py | 4 +--- demos.py | 2 ++ elementGen/node_parser.py | 25 ++++++++++++++++++++----- 3 files changed, 23 insertions(+), 8 deletions(-) diff --git a/data/nodes/test.py b/data/nodes/test.py index f7dce7d..3974099 100644 --- a/data/nodes/test.py +++ b/data/nodes/test.py @@ -1,6 +1,4 @@ -# @Add >int@A >int@B # +# Add int@A int@B # def node(A, B): return A + B - -# END # \ No newline at end of file diff --git a/demos.py b/demos.py index a548ac1..86adf72 100644 --- a/demos.py +++ b/demos.py @@ -203,6 +203,8 @@ def node_parserDemo(): from elementGen import allCategories, allNodes, Parse alls = allCategories() print('All categories and nodes:', {i: allNodes(i) for i in alls}) + tests = Parse('test') + print('Test results of function Add with inputs 3 & 4:', tests('Add', 3, 4)) def switchDemo(): import pygame diff --git a/elementGen/node_parser.py b/elementGen/node_parser.py index c8cc8b3..dc6f423 100644 --- a/elementGen/node_parser.py +++ b/elementGen/node_parser.py @@ -3,23 +3,38 @@ def allCategories(): return [i.name for i in os.scandir('data/nodes') if i.is_file()] +class Names: + def __init__(self, data): + self.rdata = data.strip(' \n') + spl = self.rdata.split(' ') + self.name = spl[0] + self.args = [] + for i in spl[1:]: + s = i.split('@') + self.args.append((s[1], s[0])) + def __str__(self): return self.name + def __repr__(self): return str(self) + class Parse: def __init__(self, category): + if not category.endswith('.py'): category += '.py' self.rdata = open('data/nodes/'+category).read() self.data = {} pattern = 0 - spl = self.rdata.split('#')[1:-1] - if spl[-1] == ' END ': spl = spl[:-1] # The END is for making it look nice, not actually needed + spl = self.rdata.split('#')[1:] + self.names = {} for i in spl: i = i.strip(' \n') if pattern == 0: + i = Names(i) pattern = i + self.names[str(i)] = i else: self.data[pattern] = i pattern = 0 - def __call__(self, funcname, *args, **kwargs): - exec(self.data[funcname]) - return eval('node(*args, **kwargs)', locals=locals()) + def __call__(self, funcname, *args): + exec(self.data[self.names[funcname]]) + return eval('node(*args)') def getall(self): return list(self.data.keys()) From 795302b3ea0e15ca03f26b4f57c89f799fe2d4a5 Mon Sep 17 00:00:00 2001 From: Max Worrall <96847801+Tsunami014@users.noreply.github.com> Date: Wed, 22 Nov 2023 15:46:55 +1100 Subject: [PATCH 54/91] =?UTF-8?q?feat(main):=20=F0=9F=9A=9A=20Moved=20exam?= =?UTF-8?q?ple.py's=20contents=20into=20demos.py=20although=20it=20is=20ve?= =?UTF-8?q?ry...=20not=20good?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Some features don't work and it is too much code. I will need to work on it --- demos.py | 140 ++++++++++++++++++++++++++++++++++++++++ graphics/GUI/example.py | 136 -------------------------------------- 2 files changed, 140 insertions(+), 136 deletions(-) delete mode 100644 graphics/GUI/example.py diff --git a/demos.py b/demos.py index 86adf72..3e1d3c6 100644 --- a/demos.py +++ b/demos.py @@ -237,6 +237,145 @@ def switchDemo(): pygame.display.update() pygame.quit() +def almostallgraphicsDemo(): + import pygame + from pygame import locals + from graphics.GUI import InputBox, TextBoxFrame + from graphics.GUI.pyguix import gui as ui + from graphics.GUI.textboxify.borders import LIGHT, BARBER_POLE + + class SnapHUDPartInfoExample(ui.SnapHUDPartInfo): + + # NOTE: Example bound function called by reflection OR by in game logic to update 'listening' SnapHUDPart: + # This example simply allows for setting of value or getting current value when calling .part_one() + # You can easily add other logic in part_one() that then updates the value when called. + # Yet still important is to return the part value. + def part_one(self,v=None): + return self.partinfo("part_one",v) + + def __init__(self) -> None: + super().__init__() + + def textboxify_test(screen): + # Customize and initialize a new dialog box. + dialog_box = TextBoxFrame( + text="Hello! This is a simple example of how TextBoxify can be implemented in Pygame games.", + text_width=320, + lines=2, + pos=(80, 180), + padding=(150, 100), + font_color=(92, 53, 102), + font_size=26, + bg_color=(173, 127, 168), + border=LIGHT, + ) + + # Optionally: add an animated or static image to indicate that the box is + # waiting for user input before it continue to do anything else. + # This uses the default indicator, but custom sprites can be used too. + dialog_box.set_indicator() + + # Optionally: add a animated portrait or a static image to represent who is + # talking. The portrait is adjusted to be the same height as the total line + # height in the box. + # This uses the default portrait, but custom sprites can be used too. + dialog_box.set_portrait() + + # Create sprite group for the dialog boxes. + dialog_group = pygame.sprite.LayeredDirty() + #dialog_group.clear(screen, background) + dialog_group.add(dialog_box) + + run = True + next_quit = False + while run: + pygame.time.Clock().tick(60) + screen.fill((92, 53, 102)) + all.draw(screen) + for event in pygame.event.get(): + if event.type == pygame.MOUSEBUTTONDOWN: + if event.button == pygame.BUTTON_LEFT: + shud.clicked() + if event.type == locals.QUIT: + run = False + if event.type == locals.KEYDOWN: + if event.key == locals.K_ESCAPE: + run = False + + # Event that let the user tell the box to print next lines of + # text or close when finished printing the whole message. + if event.key == locals.K_RETURN: + if not dialog_box.alive(): + dialog_group.add(dialog_box) + else: + # Cleans the text box to be able to go on printing text + # that didn't fit, as long as there are text to print out. + if dialog_box.words: + dialog_box.reset() + + # Whole message has been printed and the box can now reset + # to default values, set a new text to print out and close + # down itself. + else: + dialog_box.reset(hard=True) + dialog_box.set_text("Happy coding!") + dialog_box.__border = BARBER_POLE + dialog_box.kill() + if next_quit: + del dialog_box + return + else: + next_quit = True + + # Update the changes so the user sees the text. + dialog_group.update() + shud.update() # NOTE: update() called to check for 'hover' + rects = dialog_group.draw(screen) + pygame.display.update(rects) + pygame.display.update() + + pygame.init() + screen = pygame.display.set_mode((640, 360)) + + all = pygame.sprite.RenderUpdates() + + shudpie = SnapHUDPartInfoExample() + # NOTE: SnapHUD instance created AFTER the Info class instance. + shud = ui.SnapHUD(window=screen, rg=all, set_num_of_groups=0) + + run = True + shudpie.part_one("None") + while run: + screen.fill((92, 53, 102)) + all.draw(screen) + shud.update() + pygame.display.update() + mb = ui.MessageBox( + window=screen, + event_list=pygame.event.get(), + buttons=['textboxify', 'input box'], + ) + + # NOTE: Act upoon if the MessageBox was canceled, if not can act upon the .clicked() value.: + if not mb.canceled(): + if mb.clicked() == 'textboxify': + textboxify_test(screen) + else: + input_box = InputBox(100, 100, 140, 32, 'Type here!') + def _(screen): + all.draw(screen) + shud.update() + def __(event): + if event.type == pygame.MOUSEBUTTONDOWN: + if event.button == pygame.BUTTON_LEFT: + shud.clicked() + out = input_box.interrupt(screen, run_too=_, event_callback=__) + shudpie.part_one(out) + else: + print("You canceled the MessageBox instance.") + run = False + + if __name__ == '__main__': root = Tk.Tk() def cmd(cmdd): @@ -246,6 +385,7 @@ def cmd(cmdd): Tk.Button(root, text='Node Parser Demo', command=lambda: cmd(node_parserDemo) ).pack() Tk.Button(root, text='Loading Demo', command=lambda: cmd(LoadingDemo) ).pack() Tk.Button(root, text='Graphics Demo', command=lambda: cmd(GraphicsDemo) ).pack() + Tk.Button(root, text='Other Graphics Demo', command=lambda: cmd(almostallgraphicsDemo) ).pack() Tk.Button(root, text='Generate World Demo', command=lambda: cmd(worldsDemo) ).pack() Tk.Button(root, text='Generate Terrain Demo', command=lambda: cmd(terrainGenDemo) ).pack() Tk.Button(root, text='Input Box Demo', command=lambda: cmd(inputBoxDemo) ).pack() diff --git a/graphics/GUI/example.py b/graphics/GUI/example.py deleted file mode 100644 index fa83164..0000000 --- a/graphics/GUI/example.py +++ /dev/null @@ -1,136 +0,0 @@ -import pygame -from pygame import locals -from graphics.GUI import InputBox, RESIZE_H, TextBoxFrame -from graphics.GUI.pyguix import gui as ui -from graphics.GUI.textboxify.borders import LIGHT, BARBER_POLE - -class SnapHUDPartInfoExample(ui.SnapHUDPartInfo): - - # NOTE: Example bound function called by reflection OR by in game logic to update 'listening' SnapHUDPart: - # This example simply allows for setting of value or getting current value when calling .part_one() - # You can easily add other logic in part_one() that then updates the value when called. - # Yet still important is to return the part value. - def part_one(self,v=None): - return self.partinfo("part_one",v) - - def __init__(self) -> None: - super().__init__() - -def textboxify_test(screen): - # Customize and initialize a new dialog box. - dialog_box = TextBoxFrame( - text="Hello! This is a simple example of how TextBoxify can be implemented in Pygame games.", - text_width=320, - lines=2, - pos=(80, 180), - padding=(150, 100), - font_color=(92, 53, 102), - font_size=26, - bg_color=(173, 127, 168), - border=LIGHT, - ) - - # Optionally: add an animated or static image to indicate that the box is - # waiting for user input before it continue to do anything else. - # This uses the default indicator, but custom sprites can be used too. - dialog_box.set_indicator() - - # Optionally: add a animated portrait or a static image to represent who is - # talking. The portrait is adjusted to be the same height as the total line - # height in the box. - # This uses the default portrait, but custom sprites can be used too. - dialog_box.set_portrait() - - # Create sprite group for the dialog boxes. - dialog_group = pygame.sprite.LayeredDirty() - #dialog_group.clear(screen, background) - dialog_group.add(dialog_box) - - run = True - next_quit = False - while run: - pygame.time.Clock().tick(60) - screen.fill((92, 53, 102)) - all.draw(screen) - for event in pygame.event.get(): - if event.type == pygame.MOUSEBUTTONDOWN: - if event.button == pygame.BUTTON_LEFT: - shud.clicked() - if event.type == locals.QUIT: - run = False - if event.type == locals.KEYDOWN: - if event.key == locals.K_ESCAPE: - run = False - - # Event that let the user tell the box to print next lines of - # text or close when finished printing the whole message. - if event.key == locals.K_RETURN: - if not dialog_box.alive(): - dialog_group.add(dialog_box) - else: - # Cleans the text box to be able to go on printing text - # that didn't fit, as long as there are text to print out. - if dialog_box.words: - dialog_box.reset() - - # Whole message has been printed and the box can now reset - # to default values, set a new text to print out and close - # down itself. - else: - dialog_box.reset(hard=True) - dialog_box.set_text("Happy coding!") - dialog_box.__border = BARBER_POLE - dialog_box.kill() - if next_quit: - del dialog_box - return - else: - next_quit = True - - # Update the changes so the user sees the text. - dialog_group.update() - shud.update() # NOTE: update() called to check for 'hover' - rects = dialog_group.draw(screen) - pygame.display.update(rects) - pygame.display.update() - -pygame.init() -screen = pygame.display.set_mode((640, 360)) - -all = pygame.sprite.RenderUpdates() - -shudpie = SnapHUDPartInfoExample() -# NOTE: SnapHUD instance created AFTER the Info class instance. -shud = ui.SnapHUD(window=screen, rg=all, set_num_of_groups=1) - -run = True -shudpie.part_one("None") -while run: - screen.fill((92, 53, 102)) - all.draw(screen) - shud.update() - pygame.display.update() - mb = ui.MessageBox( - window=screen, - event_list=pygame.event.get(), - buttons=['textboxify', 'input box'], - ) - - # NOTE: Act upoon if the MessageBox was canceled, if not can act upon the .clicked() value.: - if not mb.canceled(): - if mb.clicked() == 'textboxify': - textboxify_test(screen) - else: - input_box = InputBox(100, 100, 140, 32, 'Type here!', resize=RESIZE_H) - def _(screen): - all.draw(screen) - shud.update() - def __(event): - if event.type == pygame.MOUSEBUTTONDOWN: - if event.button == pygame.BUTTON_LEFT: - shud.clicked() - out = input_box.interrupt(screen, run_too=_, event_callback=__) - shudpie.part_one(out) - else: - print("You canceled the MessageBox instance.") - run = False From 08305cfd414ae455c66f9b4dc9d390bf79d5fea0 Mon Sep 17 00:00:00 2001 From: Max Worrall <96847801+Tsunami014@users.noreply.github.com> Date: Thu, 23 Nov 2023 16:16:20 +1100 Subject: [PATCH 55/91] =?UTF-8?q?feat(nodes):=20=E2=9C=A8=20Added=20a=20fe?= =?UTF-8?q?w=20things=20that=20git=20deleted=20the=20commits=20of?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .vscode/settings.json | 3 ++- elementGen/node_editor.py | 47 +++++++++++++++++++++++++++++---------- elementGen/node_parser.py | 17 ++++++++++++-- graphics/GUI/dropdown.py | 6 ++--- graphics/graphics.py | 7 ++++-- 5 files changed, 60 insertions(+), 20 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index e425510..a0eacbe 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -20,7 +20,8 @@ "STT", "characters", "sound gen", - "other" + "other", + "nodes" ], "wolf.disableHotModeWarning": true } \ No newline at end of file diff --git a/elementGen/node_editor.py b/elementGen/node_editor.py index 61102f7..4f9fe70 100644 --- a/elementGen/node_editor.py +++ b/elementGen/node_editor.py @@ -1,9 +1,11 @@ +import pygame, os, pickle import graphics.graphics_options as GO -import pygame, os, json -from time import sleep +import elementGen.node_parser as np categories = [i.name for i in os.scandir('data/elements') if i.is_dir()] +nodes = [np.Parse(i) for i in np.allCategories()] + def mouseDown(button=1): i = False while True: @@ -12,7 +14,7 @@ def mouseDown(button=1): i = r def NodeSelector(G, continue_to_edit=0): - """Makes a Node Selector screen! Still in progress. Come back later! + """Makes a Node Selector screen! Parameters ---------- @@ -34,7 +36,7 @@ def item_select(event, category, element=None, aborted=False): @G.Loading def load(self): self.items = [i for i in os.scandir('data/elements/'+category) if i.is_file()] - self.iteminfo = [json.load(open('data/elements/%s/%s'%(category, i.name))) for i in self.items] + self.iteminfo = [pickle.load(open('data/elements/%s/%s'%(category, i.name), 'rb')) for i in self.items] self.subs = ['Go back to the previous page', 'Make a new item from scratch'] + [i['idea'] for i in self.iteminfo] cont, res = load() G.Container.res = res @@ -95,12 +97,11 @@ def category_select(event, element=None, aborted=False): return pth return category_select() -# Select element to edit screen (copy world select) -# Each category of elements is a sub-folder under data/elements/ +# Make delete category/node file # As well as a NodeEditor screen have a NodeRenderer screen, which is also used in NodeEditor def NodeEditor(G, path): - """Makes a Node Editor screen! Still in progress. Come back later! + """Makes a Node Editor screen! Parameters ---------- @@ -127,8 +128,12 @@ def editor(event, path, element=None, aborted=False): if path.endswith('.elm'): path = path[:-4] if not os.path.exists('data/elements/'+path+'.elm'): - open('data/elements/'+path+'.elm', 'w+').write('{"idea": "BLANK", "name": "New File"}') - G.Container.contents = json.load(open('data/elements/'+path+'.elm')) + pickle.dump({"idea": "BLANK", "name": "New File", "version": 2}, open('data/elements/'+path+'.elm', 'wb+')) + G.Container.contents = pickle.load(open('data/elements/'+path+'.elm', 'rb')) + if 'nodes' in G.Container.contents: + G.Container.nodes = G.Container.contents['nodes'] + else: + G.Container.nodes = [] G.Container.name = G.Container.contents['name'] if event == GO.ELOADUI: G.Clear() @@ -165,6 +170,10 @@ def settings(event, element=None, aborted=False): pass # Whatever you return here will be returned by the function settings() elif event == GO.ETICK: + for p, node in G.Container.nodes: + txt = GO.FFONT.render(str(node), 2, GO.CBLACK) + pygame.draw.rect(G.WIN, GO.CBLUE, pygame.Rect(*p, txt.get_width()+10, txt.get_height()+10), border_radius=8) + G.WIN.blit(txt, (p[0]+5, p[1]+5)) lf, l = next(G.Container.md[0]) # lf = left mouse button first press, l = left mouse button is being pressed rf, r = next(G.Container.md[1]) @@ -179,8 +188,22 @@ def settings(event, element=None, aborted=False): if element.key == pygame.K_s and element.mod & pygame.KMOD_CTRL: if path.endswith('.elm'): path = path[:-4] + G.Container.contents['nodes'] = G.Container.nodes + pickle.dump(G.Container.contents, open('data/elements/'+path+'.elm', 'wb+')) # Save G.Container.saved = True - json.dump(G.Container.contents, open('data/elements/'+path+'.elm', 'w+')) # Save + elif element.type == pygame.MOUSEBUTTONDOWN and element.button == pygame.BUTTON_RIGHT: + p = pygame.mouse.get_pos() + kgo = True + while kgo: + resp = G.Dropdown([str(i) for i in nodes], pos=p) + if isinstance(resp, int): + resp2 = G.Dropdown(['Back']+[str(i) for i in nodes[resp].getall()], pos=p) + if isinstance(resp2, int): + if resp2 != 0: + G.Container.nodes.append((p, nodes[resp].getall()[resp2-1])) + kgo = False + else: kgo = False + else: kgo = False elif event == GO.ELAST: if G.Container.saved: if path.endswith('.elm'): @@ -188,6 +211,6 @@ def settings(event, element=None, aborted=False): if G.Container.name != path.split('/')[1]: os.remove('data/elements/'+path+'.elm') path = path.split('/')[0] + '/' + G.Container.name - open('data/elements/'+path+'.elm', 'w+') - json.dump(G.Container.contents, open('data/elements/'+path+'.elm', 'w+')) + open('data/elements/'+path+'.elm', 'wb+') + pickle.dump(G.Container.contents, open('data/elements/'+path+'.elm', 'wb+')) return editor(path) diff --git a/elementGen/node_parser.py b/elementGen/node_parser.py index dc6f423..968b1d2 100644 --- a/elementGen/node_parser.py +++ b/elementGen/node_parser.py @@ -8,16 +8,25 @@ def __init__(self, data): self.rdata = data.strip(' \n') spl = self.rdata.split(' ') self.name = spl[0] - self.args = [] + self.inputs = [] + self.outputs = [] + input = True for i in spl[1:]: + if i == '|': + input = False + continue s = i.split('@') - self.args.append((s[1], s[0])) + if input: + self.inputs.append((s[1], s[0])) + else: + self.outputs.append((s[1], s[0])) def __str__(self): return self.name def __repr__(self): return str(self) class Parse: def __init__(self, category): if not category.endswith('.py'): category += '.py' + self.category = category self.rdata = open('data/nodes/'+category).read() self.data = {} pattern = 0 @@ -35,6 +44,10 @@ def __init__(self, category): def __call__(self, funcname, *args): exec(self.data[self.names[funcname]]) return eval('node(*args)') + + def __str__(self): return self.category[:-3] + def __repr__(self): return str(self) + def getall(self): return list(self.data.keys()) diff --git a/graphics/GUI/dropdown.py b/graphics/GUI/dropdown.py index 4d9ea2c..6e8c992 100644 --- a/graphics/GUI/dropdown.py +++ b/graphics/GUI/dropdown.py @@ -1,13 +1,13 @@ import pygame -def dropdown(win, elms, spacing=5, font=None, bgcolour=(0, 0, 0), txtcolour=(255, 255, 255), selectedcol=(0, 0, 255)): +def dropdown(win, elms, spacing=5, font=None, bgcolour=(0, 0, 0), txtcolour=(255, 255, 255), selectedcol=(0, 0, 255), mpos=None): if font == None: font = pygame.font.SysFont(None, 30) elements = [font.render(i, 2, txtcolour) for i in elms] mx = max([i.get_width() + spacing*2 for i in elements]) my = sum([i.get_height() + spacing*2 for i in elements]) rects = [] - mpos = pygame.mouse.get_pos() - pos = pygame.mouse.get_pos() + if mpos == None: mpos = pygame.mouse.get_pos() + pos = mpos for i in elements: sze = i.get_size() sze = (mx, sze[1] + spacing*2) diff --git a/graphics/graphics.py b/graphics/graphics.py index 7d9f031..92a954b 100644 --- a/graphics/graphics.py +++ b/graphics/graphics.py @@ -289,10 +289,11 @@ def func(event, element=None, aborted=False): self.clock.tick(60) ret = func(GO.ELAST, aborted=self.ab) self.ab = False + self.run = True return ret return func2 - def Dropdown(self, elements, spacing=5, font=GO.FFONT, activecol=GO.CACTIVE, bgcol=GO.CBLACK, txtcol=GO.CWHITE): + def Dropdown(self, elements, spacing=5, font=GO.FFONT, activecol=GO.CACTIVE, bgcol=GO.CBLACK, txtcol=GO.CWHITE, pos=None): """Spawns a dropdown! This will pause everything else! You will need to click out of the dropdown to exit it. @@ -310,6 +311,8 @@ def Dropdown(self, elements, spacing=5, font=GO.FFONT, activecol=GO.CACTIVE, bgc The colour of the background of the dropdown, by default GO.CBLACK txtcol : tuple[int, int, int], optional The colour of the text of the dropdown, by default GO.CWHITE + pos : tuple[int, int], optional + The position of the dropdown, by default the mouse location For ease of use default colours are provided as GO.C___ (e.g. GO.CGREEN) Returns @@ -318,7 +321,7 @@ def Dropdown(self, elements, spacing=5, font=GO.FFONT, activecol=GO.CACTIVE, bgc The index of the input elements list that was selected, else None if nothing selected False if you exited from the menu using escape or closing the window. This will also exit the GUI. """ - d = dropdown(self.WIN, elements, spacing, font, bgcol, txtcol, activecol) + d = dropdown(self.WIN, elements, spacing, font, bgcol, txtcol, activecol, pos) if d is False: self.run = False return d From cb84500b174e40937ba08343284f24a380a9538b Mon Sep 17 00:00:00 2001 From: Max Worrall <96847801+Tsunami014@users.noreply.github.com> Date: Fri, 24 Nov 2023 08:31:26 +1100 Subject: [PATCH 56/91] =?UTF-8?q?feat(nodes):=20=E2=9C=A8=20Added=20render?= =?UTF-8?q?ing=20of=20the=20node=20circles!?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Just inputs for now, outputs later --- elementGen/node_editor.py | 48 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 46 insertions(+), 2 deletions(-) diff --git a/elementGen/node_editor.py b/elementGen/node_editor.py index 4f9fe70..efe9de5 100644 --- a/elementGen/node_editor.py +++ b/elementGen/node_editor.py @@ -100,6 +100,36 @@ def category_select(event, element=None, aborted=False): # Make delete category/node file # As well as a NodeEditor screen have a NodeRenderer screen, which is also used in NodeEditor +def CAT(txt, front=True, bgcol=GO.CWHITE, colour=GO.CGREEN, colour2=None, filled=False): # Circle And Text + t = GO.FFONT.render(txt, 2, GO.CBLACK) + sze = GO.FFONT.size('a')[1] + poschange = t.get_height() - sze + sur = pygame.Surface((t.get_width() + sze + 5, t.get_height()+poschange)) + sur.fill(bgcol) + if front: + pygame.draw.circle(sur, GO.CWHITE, (sze//2, t.get_height()//2), sze//2-2) + pygame.draw.circle(sur, colour, (sze//2, t.get_height()//2), sze//2-2, 5) + if colour2 != None: + csur = pygame.Surface((sze, sze//2)) + csur.fill(GO.CWHITE) + pygame.draw.circle(csur, colour2, (sze//2, 0), sze//2-2, 5) + sur.blit(csur, (0, t.get_height()//2)) + if filled: pygame.draw.circle(sur, GO.CGREY, (sze//2, t.get_height()//2), sze//4) + pygame.draw.circle(sur, GO.CBLACK, (sze//2, t.get_height()//2), sze//2, 2) + sur.blit(t, (sze + 5, poschange)) + else: + pygame.draw.circle(sur, GO.CWHITE, (t.get_width() + 5 + sze//2, t.get_height()//2), sze//2-2) + pygame.draw.circle(sur, colour, (t.get_width() + 5 + sze//2, t.get_height()//2), sze//2-2, 5) + if colour2 != None: + csur = pygame.Surface((sze, sze//2)) + csur.fill(GO.CWHITE) + pygame.draw.circle(csur, colour2, (sze//2, 0), sze//2-2, 5) + sur.blit(csur, (t.get_width() + 5, t.get_height()//2)) + if filled: pygame.draw.circle(sur, GO.CGREY, (t.get_width() + 5 + sze//2, t.get_height()//2), sze//4) + pygame.draw.circle(sur, GO.CBLACK, (t.get_width() + 5 + sze//2, t.get_height()//2), sze//2, 2) + sur.blit(t, (0, poschange)) + return sur + def NodeEditor(G, path): """Makes a Node Editor screen! @@ -171,9 +201,23 @@ def settings(event, element=None, aborted=False): settings() elif event == GO.ETICK: for p, node in G.Container.nodes: + col = GO.CBLUE txt = GO.FFONT.render(str(node), 2, GO.CBLACK) - pygame.draw.rect(G.WIN, GO.CBLUE, pygame.Rect(*p, txt.get_width()+10, txt.get_height()+10), border_radius=8) - G.WIN.blit(txt, (p[0]+5, p[1]+5)) + sur = pygame.Surface(G.size) + sur.fill(col) + sur.blit(txt, (0, 0)) + i = txt.get_height() + 5 + mx = txt.get_width() + for name, typ in node.inputs: + s = CAT(name, bgcol=col) + sur.blit(s, (0, i)) + mx = max(mx, s.get_width()) + i += s.get_height() + 2 + sur2 = pygame.Surface((mx, i)) + sur2.fill(col) + sur2.blit(sur, (0, 0)) + pygame.draw.rect(G.WIN, col, pygame.Rect(*p, mx+10, i+10), border_radius=8) + G.WIN.blit(sur2, (p[0]+5, p[1]+5)) lf, l = next(G.Container.md[0]) # lf = left mouse button first press, l = left mouse button is being pressed rf, r = next(G.Container.md[1]) From cf640093374cd29bccf189d0a8cd2990b5c59474 Mon Sep 17 00:00:00 2001 From: Max Worrall <96847801+Tsunami014@users.noreply.github.com> Date: Fri, 24 Nov 2023 08:37:10 +1100 Subject: [PATCH 57/91] =?UTF-8?q?feat(graphics):=20=F0=9F=8C=88=20Made=20t?= =?UTF-8?q?he=20colours=20MUCH=20more=20pretty?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- elementGen/node_editor.py | 8 ++++---- graphics/graphics_options.py | 7 ++++--- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/elementGen/node_editor.py b/elementGen/node_editor.py index efe9de5..674cf92 100644 --- a/elementGen/node_editor.py +++ b/elementGen/node_editor.py @@ -107,22 +107,22 @@ def CAT(txt, front=True, bgcol=GO.CWHITE, colour=GO.CGREEN, colour2=None, filled sur = pygame.Surface((t.get_width() + sze + 5, t.get_height()+poschange)) sur.fill(bgcol) if front: - pygame.draw.circle(sur, GO.CWHITE, (sze//2, t.get_height()//2), sze//2-2) + pygame.draw.circle(sur, GO.CAWHITE, (sze//2, t.get_height()//2), sze//2-2) pygame.draw.circle(sur, colour, (sze//2, t.get_height()//2), sze//2-2, 5) if colour2 != None: csur = pygame.Surface((sze, sze//2)) - csur.fill(GO.CWHITE) + csur.fill(GO.CAWHITE) pygame.draw.circle(csur, colour2, (sze//2, 0), sze//2-2, 5) sur.blit(csur, (0, t.get_height()//2)) if filled: pygame.draw.circle(sur, GO.CGREY, (sze//2, t.get_height()//2), sze//4) pygame.draw.circle(sur, GO.CBLACK, (sze//2, t.get_height()//2), sze//2, 2) sur.blit(t, (sze + 5, poschange)) else: - pygame.draw.circle(sur, GO.CWHITE, (t.get_width() + 5 + sze//2, t.get_height()//2), sze//2-2) + pygame.draw.circle(sur, GO.CAWHITE, (t.get_width() + 5 + sze//2, t.get_height()//2), sze//2-2) pygame.draw.circle(sur, colour, (t.get_width() + 5 + sze//2, t.get_height()//2), sze//2-2, 5) if colour2 != None: csur = pygame.Surface((sze, sze//2)) - csur.fill(GO.CWHITE) + csur.fill(GO.CAWHITE) pygame.draw.circle(csur, colour2, (sze//2, 0), sze//2-2, 5) sur.blit(csur, (t.get_width() + 5, t.get_height()//2)) if filled: pygame.draw.circle(sur, GO.CGREY, (t.get_width() + 5 + sze//2, t.get_height()//2), sze//4) diff --git a/graphics/graphics_options.py b/graphics/graphics_options.py index d2bf3b0..344de49 100644 --- a/graphics/graphics_options.py +++ b/graphics/graphics_options.py @@ -3,9 +3,10 @@ # Colours CTRANSPARENT = (255, 255, 255, 1) CWHITE = (255, 255, 255) -CGREEN = (10, 255, 50) -CRED = (255, 10, 50) -CBLUE = (10, 50, 255) +CAWHITE = (200, 200, 200) +CGREEN = (60, 200, 100) +CRED = (255, 60, 100) +CBLUE = (60, 100, 255) CBLACK = (0, 0, 0) CYELLOW = (255, 200, 50) CGREY = (125, 125, 125) From 42c206969f9120b908760225fe49620cd816623d Mon Sep 17 00:00:00 2001 From: Max Worrall <96847801+Tsunami014@users.noreply.github.com> Date: Fri, 24 Nov 2023 15:40:30 +1100 Subject: [PATCH 58/91] =?UTF-8?q?feat(nodes):=20=E2=9C=A8=20Added=20the=20?= =?UTF-8?q?showing=20of=20outputs=20with=20the=20nodes=20:)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- data/nodes/test.py | 2 +- elementGen/node_editor.py | 17 ++++++++++++++--- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/data/nodes/test.py b/data/nodes/test.py index 3974099..e420639 100644 --- a/data/nodes/test.py +++ b/data/nodes/test.py @@ -1,4 +1,4 @@ -# Add int@A int@B # +# Add int@A int@B | int@Out # def node(A, B): return A + B diff --git a/elementGen/node_editor.py b/elementGen/node_editor.py index 674cf92..178e9dd 100644 --- a/elementGen/node_editor.py +++ b/elementGen/node_editor.py @@ -206,17 +206,28 @@ def settings(event, element=None, aborted=False): sur = pygame.Surface(G.size) sur.fill(col) sur.blit(txt, (0, 0)) - i = txt.get_height() + 5 + start = txt.get_height() + 5 + i = start mx = txt.get_width() for name, typ in node.inputs: s = CAT(name, bgcol=col) sur.blit(s, (0, i)) mx = max(mx, s.get_width()) i += s.get_height() + 2 - sur2 = pygame.Surface((mx, i)) + if node.outputs != []: + mx += 20 + i2 = start + mx2 = 0 + for name, typ in node.outputs: + s = CAT(name, front=False, bgcol=col) + sur.blit(s, (mx, i2)) + mx2 = max(mx2, s.get_width()) + i2 += s.get_height() + 2 + mx2 += mx + sur2 = pygame.Surface((mx2, max(i, i2))) sur2.fill(col) sur2.blit(sur, (0, 0)) - pygame.draw.rect(G.WIN, col, pygame.Rect(*p, mx+10, i+10), border_radius=8) + pygame.draw.rect(G.WIN, col, pygame.Rect(*p, mx2+10, max(i, i2)+10), border_radius=8) G.WIN.blit(sur2, (p[0]+5, p[1]+5)) lf, l = next(G.Container.md[0]) # lf = left mouse button first press, l = left mouse button is being pressed From 47eadbcb774e8a11685c7b1ac09cab8527980b3f Mon Sep 17 00:00:00 2001 From: Max Worrall <96847801+Tsunami014@users.noreply.github.com> Date: Fri, 24 Nov 2023 15:52:45 +1100 Subject: [PATCH 59/91] =?UTF-8?q?feat(nodes):=20=E2=9C=A8=20Can=20now=20se?= =?UTF-8?q?lect=20nodes!=20They=20look=20highlighted=20when=20selected=20:?= =?UTF-8?q?)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- elementGen/node_editor.py | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/elementGen/node_editor.py b/elementGen/node_editor.py index 178e9dd..69ff9a0 100644 --- a/elementGen/node_editor.py +++ b/elementGen/node_editor.py @@ -106,7 +106,9 @@ def CAT(txt, front=True, bgcol=GO.CWHITE, colour=GO.CGREEN, colour2=None, filled poschange = t.get_height() - sze sur = pygame.Surface((t.get_width() + sze + 5, t.get_height()+poschange)) sur.fill(bgcol) + cir = None if front: + cir = pygame.Rect(0, 0, sze, sze) pygame.draw.circle(sur, GO.CAWHITE, (sze//2, t.get_height()//2), sze//2-2) pygame.draw.circle(sur, colour, (sze//2, t.get_height()//2), sze//2-2, 5) if colour2 != None: @@ -118,6 +120,7 @@ def CAT(txt, front=True, bgcol=GO.CWHITE, colour=GO.CGREEN, colour2=None, filled pygame.draw.circle(sur, GO.CBLACK, (sze//2, t.get_height()//2), sze//2, 2) sur.blit(t, (sze + 5, poschange)) else: + cir = pygame.Rect(t.get_width() + 5, 0, sze, sze) pygame.draw.circle(sur, GO.CAWHITE, (t.get_width() + 5 + sze//2, t.get_height()//2), sze//2-2) pygame.draw.circle(sur, colour, (t.get_width() + 5 + sze//2, t.get_height()//2), sze//2-2, 5) if colour2 != None: @@ -128,7 +131,7 @@ def CAT(txt, front=True, bgcol=GO.CWHITE, colour=GO.CGREEN, colour2=None, filled if filled: pygame.draw.circle(sur, GO.CGREY, (t.get_width() + 5 + sze//2, t.get_height()//2), sze//4) pygame.draw.circle(sur, GO.CBLACK, (t.get_width() + 5 + sze//2, t.get_height()//2), sze//2, 2) sur.blit(t, (0, poschange)) - return sur + return sur, cir def NodeEditor(G, path): """Makes a Node Editor screen! @@ -209,8 +212,11 @@ def settings(event, element=None, aborted=False): start = txt.get_height() + 5 i = start mx = txt.get_width() + cirs = [] for name, typ in node.inputs: - s = CAT(name, bgcol=col) + s, c = CAT(name, bgcol=col) + c.move_ip(0+p[0], i+p[1]) + cirs.append(c) sur.blit(s, (0, i)) mx = max(mx, s.get_width()) i += s.get_height() + 2 @@ -219,7 +225,9 @@ def settings(event, element=None, aborted=False): i2 = start mx2 = 0 for name, typ in node.outputs: - s = CAT(name, front=False, bgcol=col) + s, c = CAT(name, front=False, bgcol=col) + c.move_ip(mx+p[0], i2+p[1]) + cirs.append(c) sur.blit(s, (mx, i2)) mx2 = max(mx2, s.get_width()) i2 += s.get_height() + 2 @@ -229,6 +237,9 @@ def settings(event, element=None, aborted=False): sur2.blit(sur, (0, 0)) pygame.draw.rect(G.WIN, col, pygame.Rect(*p, mx2+10, max(i, i2)+10), border_radius=8) G.WIN.blit(sur2, (p[0]+5, p[1]+5)) + for i in cirs: + if i.collidepoint(pygame.mouse.get_pos()): + G.WIN.blit(CAT('', filled=True, bgcol=col)[0], (i.topleft[0]+5, i.topleft[1]+7)) lf, l = next(G.Container.md[0]) # lf = left mouse button first press, l = left mouse button is being pressed rf, r = next(G.Container.md[1]) From b9cfe4ad4bbe0dcf9e5f6371ff805a3777c76ca6 Mon Sep 17 00:00:00 2001 From: Max Worrall <96847801+Tsunami014@users.noreply.github.com> Date: Fri, 24 Nov 2023 16:08:33 +1100 Subject: [PATCH 60/91] =?UTF-8?q?feat(nodes):=20=E2=9C=A8=20Added=20drag?= =?UTF-8?q?=20node=20for=20line=20:)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- elementGen/node_editor.py | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/elementGen/node_editor.py b/elementGen/node_editor.py index 69ff9a0..d313b3c 100644 --- a/elementGen/node_editor.py +++ b/elementGen/node_editor.py @@ -158,6 +158,7 @@ def editor(event, path, element=None, aborted=False): mouseDown(), # Left mouse button mouseDown(3) # Right mouse button ] + G.Container.selecting = None if path.endswith('.elm'): path = path[:-4] if not os.path.exists('data/elements/'+path+'.elm'): @@ -203,6 +204,7 @@ def settings(event, element=None, aborted=False): pass # Whatever you return here will be returned by the function settings() elif event == GO.ETICK: + cirs = [] for p, node in G.Container.nodes: col = GO.CBLUE txt = GO.FFONT.render(str(node), 2, GO.CBLACK) @@ -212,11 +214,10 @@ def settings(event, element=None, aborted=False): start = txt.get_height() + 5 i = start mx = txt.get_width() - cirs = [] for name, typ in node.inputs: s, c = CAT(name, bgcol=col) c.move_ip(0+p[0], i+p[1]) - cirs.append(c) + cirs.append((c, node)) sur.blit(s, (0, i)) mx = max(mx, s.get_width()) i += s.get_height() + 2 @@ -227,7 +228,7 @@ def settings(event, element=None, aborted=False): for name, typ in node.outputs: s, c = CAT(name, front=False, bgcol=col) c.move_ip(mx+p[0], i2+p[1]) - cirs.append(c) + cirs.append((c, node)) sur.blit(s, (mx, i2)) mx2 = max(mx2, s.get_width()) i2 += s.get_height() + 2 @@ -237,17 +238,20 @@ def settings(event, element=None, aborted=False): sur2.blit(sur, (0, 0)) pygame.draw.rect(G.WIN, col, pygame.Rect(*p, mx2+10, max(i, i2)+10), border_radius=8) G.WIN.blit(sur2, (p[0]+5, p[1]+5)) - for i in cirs: - if i.collidepoint(pygame.mouse.get_pos()): - G.WIN.blit(CAT('', filled=True, bgcol=col)[0], (i.topleft[0]+5, i.topleft[1]+7)) lf, l = next(G.Container.md[0]) # lf = left mouse button first press, l = left mouse button is being pressed rf, r = next(G.Container.md[1]) # Same with r - if lf: - pygame.draw.circle(G.WIN, GO.CGREEN, pygame.mouse.get_pos(), 20) - elif l: - pygame.draw.circle(G.WIN, GO.CNEW('orange'), pygame.mouse.get_pos(), 10) + + if not l: G.Container.selecting = None + for i in cirs: + if i[0].collidepoint(pygame.mouse.get_pos()): + G.WIN.blit(CAT('', filled=True, bgcol=col)[0], (i[0].topleft[0]+5, i[0].topleft[1]+7)) + if lf: + G.Container.selecting = (i[1], (i[0].center[0]+5, i[0].center[1]+7)) + + if G.Container.selecting != None: + pygame.draw.line(G.WIN, GO.CRED, G.Container.selecting[1], pygame.mouse.get_pos(), 10) return True elif event == GO.EEVENT: # When something like a button is pressed. Is passed 'element' too, but this time it is an event if element.type == pygame.KEYDOWN: From 25b4981b5d715dda0ee940574686c5b55b0de03d Mon Sep 17 00:00:00 2001 From: Max Worrall <96847801+Tsunami014@users.noreply.github.com> Date: Fri, 24 Nov 2023 16:19:31 +1100 Subject: [PATCH 61/91] =?UTF-8?q?feat(nodes):=20=E2=9C=A8=20Made=20the=20l?= =?UTF-8?q?ines=20that=20you=20make=20stay=20once=20they=20are=20connected?= =?UTF-8?q?!?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Saving is yet to come --- elementGen/node_editor.py | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/elementGen/node_editor.py b/elementGen/node_editor.py index d313b3c..f11a48c 100644 --- a/elementGen/node_editor.py +++ b/elementGen/node_editor.py @@ -159,6 +159,7 @@ def editor(event, path, element=None, aborted=False): mouseDown(3) # Right mouse button ] G.Container.selecting = None + G.Container.connections = {} if path.endswith('.elm'): path = path[:-4] if not os.path.exists('data/elements/'+path+'.elm'): @@ -243,7 +244,12 @@ def settings(event, element=None, aborted=False): rf, r = next(G.Container.md[1]) # Same with r - if not l: G.Container.selecting = None + if not l: + if G.Container.selecting != None: + for i in cirs: + if i[0].collidepoint(pygame.mouse.get_pos()): + G.Container.connections[G.Container.selecting[1]] = (G.Container.selecting[0], (i[0].center[0]+5, i[0].center[1]+7), i[1]) + G.Container.selecting = None for i in cirs: if i[0].collidepoint(pygame.mouse.get_pos()): G.WIN.blit(CAT('', filled=True, bgcol=col)[0], (i[0].topleft[0]+5, i[0].topleft[1]+7)) @@ -252,6 +258,9 @@ def settings(event, element=None, aborted=False): if G.Container.selecting != None: pygame.draw.line(G.WIN, GO.CRED, G.Container.selecting[1], pygame.mouse.get_pos(), 10) + + for i in G.Container.connections: + pygame.draw.line(G.WIN, GO.CNEW('orange'), i, G.Container.connections[i][1], 10) return True elif event == GO.EEVENT: # When something like a button is pressed. Is passed 'element' too, but this time it is an event if element.type == pygame.KEYDOWN: From 0eb1c2452e2e811a54d4d2f2f4123867482374c5 Mon Sep 17 00:00:00 2001 From: Max Worrall <96847801+Tsunami014@users.noreply.github.com> Date: Sun, 26 Nov 2023 12:12:16 +1100 Subject: [PATCH 62/91] =?UTF-8?q?feat(nodes):=20=E2=9C=A8=20Added=20some?= =?UTF-8?q?=20detection=20tools=20to=20do=20with=20connections=20:)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Made it so that an input can have only one line connected to it and also that you cannot connect an output to an output or an input to an input Also made the connections dict to be 2 lists - one with connections and one with their info --- elementGen/node_editor.py | 33 +++++++++++++++++++++++---------- 1 file changed, 23 insertions(+), 10 deletions(-) diff --git a/elementGen/node_editor.py b/elementGen/node_editor.py index f11a48c..d089999 100644 --- a/elementGen/node_editor.py +++ b/elementGen/node_editor.py @@ -159,7 +159,8 @@ def editor(event, path, element=None, aborted=False): mouseDown(3) # Right mouse button ] G.Container.selecting = None - G.Container.connections = {} + G.Container.connections = [] # The start pos-end pos + G.Container.connectionsinfo = [] # The nodes which contain these said start and end poses if path.endswith('.elm'): path = path[:-4] if not os.path.exists('data/elements/'+path+'.elm'): @@ -218,7 +219,7 @@ def settings(event, element=None, aborted=False): for name, typ in node.inputs: s, c = CAT(name, bgcol=col) c.move_ip(0+p[0], i+p[1]) - cirs.append((c, node)) + cirs.append((c, node, True)) sur.blit(s, (0, i)) mx = max(mx, s.get_width()) i += s.get_height() + 2 @@ -229,7 +230,7 @@ def settings(event, element=None, aborted=False): for name, typ in node.outputs: s, c = CAT(name, front=False, bgcol=col) c.move_ip(mx+p[0], i2+p[1]) - cirs.append((c, node)) + cirs.append((c, node, False)) sur.blit(s, (mx, i2)) mx2 = max(mx2, s.get_width()) i2 += s.get_height() + 2 @@ -247,20 +248,32 @@ def settings(event, element=None, aborted=False): if not l: if G.Container.selecting != None: for i in cirs: - if i[0].collidepoint(pygame.mouse.get_pos()): - G.Container.connections[G.Container.selecting[1]] = (G.Container.selecting[0], (i[0].center[0]+5, i[0].center[1]+7), i[1]) + if G.Container.selecting[2] != i[2]: + if i[0].collidepoint(pygame.mouse.get_pos()): + d = False + po = (i[0].center[0]+5, i[0].center[1]+7) + for j in range(len(G.Container.connections)): + if G.Container.connections[j][1] == po: + G.Container.connections[j] = [G.Container.selecting[1], po] + G.Container.connectionsinfo[j] = [G.Container.selecting[0], i[1]] + d = True + break + if not d: + G.Container.connections.append([G.Container.selecting[1], po]) + G.Container.connectionsinfo.append([G.Container.selecting[0], i[1]]) G.Container.selecting = None for i in cirs: - if i[0].collidepoint(pygame.mouse.get_pos()): - G.WIN.blit(CAT('', filled=True, bgcol=col)[0], (i[0].topleft[0]+5, i[0].topleft[1]+7)) - if lf: - G.Container.selecting = (i[1], (i[0].center[0]+5, i[0].center[1]+7)) + if G.Container.selecting == None or G.Container.selecting[2] != i[2]: + if i[0].collidepoint(pygame.mouse.get_pos()): + G.WIN.blit(CAT('', filled=True, bgcol=col)[0], (i[0].topleft[0]+5, i[0].topleft[1]+7)) + if lf: + G.Container.selecting = (i[1], (i[0].center[0]+5, i[0].center[1]+7), i[2]) if G.Container.selecting != None: pygame.draw.line(G.WIN, GO.CRED, G.Container.selecting[1], pygame.mouse.get_pos(), 10) for i in G.Container.connections: - pygame.draw.line(G.WIN, GO.CNEW('orange'), i, G.Container.connections[i][1], 10) + pygame.draw.line(G.WIN, GO.CNEW('orange'), i[0], i[1], 10) return True elif event == GO.EEVENT: # When something like a button is pressed. Is passed 'element' too, but this time it is an event if element.type == pygame.KEYDOWN: From dde78100c02070c35dfe4eeb814206045bbef0aa Mon Sep 17 00:00:00 2001 From: Max Worrall <96847801+Tsunami014@users.noreply.github.com> Date: Sun, 26 Nov 2023 12:25:01 +1100 Subject: [PATCH 63/91] =?UTF-8?q?feat(nodes):=20=E2=9C=A8=20Made=20it=20so?= =?UTF-8?q?=20when=20you=20move=20a=20connection=20from=20an=20input=20nod?= =?UTF-8?q?e=20to=20blank=20space=20it=20deletes=20it?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- elementGen/node_editor.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/elementGen/node_editor.py b/elementGen/node_editor.py index d089999..3ce7583 100644 --- a/elementGen/node_editor.py +++ b/elementGen/node_editor.py @@ -247,9 +247,11 @@ def settings(event, element=None, aborted=False): if not l: if G.Container.selecting != None: + conned = False for i in cirs: if G.Container.selecting[2] != i[2]: if i[0].collidepoint(pygame.mouse.get_pos()): + conned = True d = False po = (i[0].center[0]+5, i[0].center[1]+7) for j in range(len(G.Container.connections)): @@ -261,6 +263,12 @@ def settings(event, element=None, aborted=False): if not d: G.Container.connections.append([G.Container.selecting[1], po]) G.Container.connectionsinfo.append([G.Container.selecting[0], i[1]]) + if not conned and G.Container.selecting[2]: + for i in range(len(G.Container.connections)): + if G.Container.selecting[1] in G.Container.connections[i]: + del G.Container.connections[i] + del G.Container.connectionsinfo[i] + break G.Container.selecting = None for i in cirs: if G.Container.selecting == None or G.Container.selecting[2] != i[2]: From ff06e268aeb3ad90d21c84bb203b7c68435fd924 Mon Sep 17 00:00:00 2001 From: Max Worrall <96847801+Tsunami014@users.noreply.github.com> Date: Sun, 26 Nov 2023 16:17:31 +1100 Subject: [PATCH 64/91] =?UTF-8?q?feat(nodes):=20=E2=9C=A8=20Made=20you=20a?= =?UTF-8?q?ble=20to=20drag=20a=20connection=20to=20blank=20space=20to=20ma?= =?UTF-8?q?ke=20a=20new=20node?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- elementGen/node_editor.py | 33 ++++++++++++++++++--------------- 1 file changed, 18 insertions(+), 15 deletions(-) diff --git a/elementGen/node_editor.py b/elementGen/node_editor.py index 3ce7583..1f2bdcb 100644 --- a/elementGen/node_editor.py +++ b/elementGen/node_editor.py @@ -150,6 +150,19 @@ def NodeEditor(G, path): NodeEditor(G) ``` """ + def dropdown(): + p = pygame.mouse.get_pos() + while True: + resp = G.Dropdown([str(i) for i in nodes], pos=p) + if isinstance(resp, int) and not isinstance(resp, bool): + resp2 = G.Dropdown(['Back']+[str(i) for i in nodes[resp].getall()], pos=p) + if isinstance(resp2, int) and not isinstance(resp, bool): + if resp2 != 0: + G.Container.nodes.append((p, nodes[resp].getall()[resp2-1])) + return True + else: return False + else: return False + @G.Graphic def editor(event, path, element=None, aborted=False): if event == GO.EFIRST: @@ -266,9 +279,10 @@ def settings(event, element=None, aborted=False): if not conned and G.Container.selecting[2]: for i in range(len(G.Container.connections)): if G.Container.selecting[1] in G.Container.connections[i]: - del G.Container.connections[i] - del G.Container.connectionsinfo[i] - break + if dropdown() == False: + del G.Container.connections[i] + del G.Container.connectionsinfo[i] + break G.Container.selecting = None for i in cirs: if G.Container.selecting == None or G.Container.selecting[2] != i[2]: @@ -292,18 +306,7 @@ def settings(event, element=None, aborted=False): pickle.dump(G.Container.contents, open('data/elements/'+path+'.elm', 'wb+')) # Save G.Container.saved = True elif element.type == pygame.MOUSEBUTTONDOWN and element.button == pygame.BUTTON_RIGHT: - p = pygame.mouse.get_pos() - kgo = True - while kgo: - resp = G.Dropdown([str(i) for i in nodes], pos=p) - if isinstance(resp, int): - resp2 = G.Dropdown(['Back']+[str(i) for i in nodes[resp].getall()], pos=p) - if isinstance(resp2, int): - if resp2 != 0: - G.Container.nodes.append((p, nodes[resp].getall()[resp2-1])) - kgo = False - else: kgo = False - else: kgo = False + dropdown() elif event == GO.ELAST: if G.Container.saved: if path.endswith('.elm'): From eb595b3f161125c0863a11cb43d2e2b99f998ad8 Mon Sep 17 00:00:00 2001 From: Max Worrall <96847801+Tsunami014@users.noreply.github.com> Date: Wed, 29 Nov 2023 16:13:12 +1100 Subject: [PATCH 65/91] =?UTF-8?q?feat(nodes):=20=E2=9C=A8=20ACHIEVED=20EPI?= =?UTF-8?q?C=20AWESOMENESS=20:D=20:D=20:D=20:D=20:D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This took waaaay too long. 1. Made a Node class for each node (which is not a very good naming convention) 2. Made the checking of the nodes you dragged in the `for each node` loop 3. made you able to drag the node blocks themselves (but messes up the connections) 4. Debugged the crap out of it all --- elementGen/node_editor.py | 99 +++++++++++++++++++++++---------------- elementGen/node_parser.py | 13 ++++- 2 files changed, 69 insertions(+), 43 deletions(-) diff --git a/elementGen/node_editor.py b/elementGen/node_editor.py index 1f2bdcb..aa449ab 100644 --- a/elementGen/node_editor.py +++ b/elementGen/node_editor.py @@ -1,6 +1,7 @@ import pygame, os, pickle import graphics.graphics_options as GO import elementGen.node_parser as np +from copy import deepcopy categories = [i.name for i in os.scandir('data/elements') if i.is_dir()] @@ -158,7 +159,7 @@ def dropdown(): resp2 = G.Dropdown(['Back']+[str(i) for i in nodes[resp].getall()], pos=p) if isinstance(resp2, int) and not isinstance(resp, bool): if resp2 != 0: - G.Container.nodes.append((p, nodes[resp].getall()[resp2-1])) + G.Container.nodes.append((p, deepcopy(nodes[resp].getall()[resp2-1]))) return True else: return False else: return False @@ -177,7 +178,8 @@ def editor(event, path, element=None, aborted=False): if path.endswith('.elm'): path = path[:-4] if not os.path.exists('data/elements/'+path+'.elm'): - pickle.dump({"idea": "BLANK", "name": "New File", "version": 2}, open('data/elements/'+path+'.elm', 'wb+')) + # Version: major.minor + pickle.dump({"idea": "BLANK", "name": "New File", "version": 0.3}, open('data/elements/'+path+'.elm', 'wb+')) G.Container.contents = pickle.load(open('data/elements/'+path+'.elm', 'rb')) if 'nodes' in G.Container.contents: G.Container.nodes = G.Container.contents['nodes'] @@ -219,8 +221,16 @@ def settings(event, element=None, aborted=False): pass # Whatever you return here will be returned by the function settings() elif event == GO.ETICK: + lf, l = next(G.Container.md[0]) + # lf = left mouse button first press, l = left mouse button is being pressed + rf, r = next(G.Container.md[1]) + # Same with r + + rd = [] + conned = False cirs = [] for p, node in G.Container.nodes: + cirs = [] col = GO.CBLUE txt = GO.FFONT.render(str(node), 2, GO.CBLACK) sur = pygame.Surface(G.size) @@ -229,10 +239,10 @@ def settings(event, element=None, aborted=False): start = txt.get_height() + 5 i = start mx = txt.get_width() - for name, typ in node.inputs: - s, c = CAT(name, bgcol=col) + for n in node.inputs: + s, c = CAT(n.name, bgcol=col) c.move_ip(0+p[0], i+p[1]) - cirs.append((c, node, True)) + cirs.append((c, n, True, node)) sur.blit(s, (0, i)) mx = max(mx, s.get_width()) i += s.get_height() + 2 @@ -240,10 +250,10 @@ def settings(event, element=None, aborted=False): mx += 20 i2 = start mx2 = 0 - for name, typ in node.outputs: - s, c = CAT(name, front=False, bgcol=col) + for n in node.outputs: + s, c = CAT(n.name, front=False, bgcol=col) c.move_ip(mx+p[0], i2+p[1]) - cirs.append((c, node, False)) + cirs.append((c, n, False, node)) sur.blit(s, (mx, i2)) mx2 = max(mx2, s.get_width()) i2 += s.get_height() + 2 @@ -251,48 +261,55 @@ def settings(event, element=None, aborted=False): sur2 = pygame.Surface((mx2, max(i, i2))) sur2.fill(col) sur2.blit(sur, (0, 0)) - pygame.draw.rect(G.WIN, col, pygame.Rect(*p, mx2+10, max(i, i2)+10), border_radius=8) + r = pygame.Rect(*p, mx2+10, max(i, i2)+10) + pygame.draw.rect(G.WIN, col, r, border_radius=8) + for i in cirs: + if not l and isinstance(G.Container.selecting, tuple) and G.Container.selecting[2] != i[2] and not (G.Container.selecting[3] is i[3]): + if i[0].collidepoint(pygame.mouse.get_pos()): + conned = True + d = False + po = (i[0].center[0]+5, i[0].center[1]+7) + for j in range(len(G.Container.connections)): + k = [_ for _ in G.Container.connectionsinfo[j] if _.isinp][0] + if i[1] is k or G.Container.selecting[0] is k: + G.Container.connections[j] = [G.Container.selecting[1], po] + G.Container.connectionsinfo[j] = [G.Container.selecting[0], i[1]] + d = True + break + if not d: + G.Container.connections.append([G.Container.selecting[1], po]) + G.Container.connectionsinfo.append([G.Container.selecting[0], i[1]]) + elif G.Container.selecting == None or (isinstance(G.Container.selecting, tuple) and G.Container.selecting[2] != i[2] and not (G.Container.selecting[3] is i[3])): + if i[0].collidepoint(pygame.mouse.get_pos()): + rd.append((i[0].topleft[0]+5, i[0].topleft[1]+7)) + if lf: + G.Container.selecting = (i[1], (i[0].center[0]+5, i[0].center[1]+7), i[2], i[3]) + if G.Container.selecting == None and lf and r.collidepoint(pygame.mouse.get_pos()): + G.Container.selecting = G.Container.nodes.index((p, node)) G.WIN.blit(sur2, (p[0]+5, p[1]+5)) - lf, l = next(G.Container.md[0]) - # lf = left mouse button first press, l = left mouse button is being pressed - rf, r = next(G.Container.md[1]) - # Same with r + for i in rd: + G.WIN.blit(CAT('', filled=True, bgcol=col)[0], i) - if not l: - if G.Container.selecting != None: - conned = False - for i in cirs: - if G.Container.selecting[2] != i[2]: - if i[0].collidepoint(pygame.mouse.get_pos()): - conned = True - d = False - po = (i[0].center[0]+5, i[0].center[1]+7) - for j in range(len(G.Container.connections)): - if G.Container.connections[j][1] == po: - G.Container.connections[j] = [G.Container.selecting[1], po] - G.Container.connectionsinfo[j] = [G.Container.selecting[0], i[1]] - d = True - break - if not d: - G.Container.connections.append([G.Container.selecting[1], po]) - G.Container.connectionsinfo.append([G.Container.selecting[0], i[1]]) - if not conned and G.Container.selecting[2]: - for i in range(len(G.Container.connections)): - if G.Container.selecting[1] in G.Container.connections[i]: - if dropdown() == False: - del G.Container.connections[i] - del G.Container.connectionsinfo[i] - break + if not l and G.Container.selecting != None: + #if not conned:# and G.Container.selecting[2]: + # for i in range(len(G.Container.connections)): + # if G.Container.selecting[1] in G.Container.connections[i]: + # if dropdown() == False: + # del G.Container.connections[i] + # del G.Container.connectionsinfo[i] + # break G.Container.selecting = None for i in cirs: - if G.Container.selecting == None or G.Container.selecting[2] != i[2]: + if G.Container.selecting == None or (isinstance(G.Container.selecting, tuple) and not (G.Container.selecting[3] is i[3])): if i[0].collidepoint(pygame.mouse.get_pos()): G.WIN.blit(CAT('', filled=True, bgcol=col)[0], (i[0].topleft[0]+5, i[0].topleft[1]+7)) if lf: - G.Container.selecting = (i[1], (i[0].center[0]+5, i[0].center[1]+7), i[2]) + G.Container.selecting = (i[1], (i[0].center[0]+5, i[0].center[1]+7), i[2], i[3]) - if G.Container.selecting != None: + if isinstance(G.Container.selecting, tuple): pygame.draw.line(G.WIN, GO.CRED, G.Container.selecting[1], pygame.mouse.get_pos(), 10) + elif isinstance(G.Container.selecting, int): + G.Container.nodes[G.Container.selecting] = (pygame.mouse.get_pos(), G.Container.nodes[G.Container.selecting][1]) for i in G.Container.connections: pygame.draw.line(G.WIN, GO.CNEW('orange'), i[0], i[1], 10) diff --git a/elementGen/node_parser.py b/elementGen/node_parser.py index 968b1d2..def2ea5 100644 --- a/elementGen/node_parser.py +++ b/elementGen/node_parser.py @@ -3,6 +3,15 @@ def allCategories(): return [i.name for i in os.scandir('data/nodes') if i.is_file()] +class Node: + def __init__(self, parent, isinp, name, typ): + self.parent = parent + self.isinp = isinp + self.name = name + self.type = typ + def __str__(self): return f'' + def __repr__(self): return str(self) + class Names: def __init__(self, data): self.rdata = data.strip(' \n') @@ -17,9 +26,9 @@ def __init__(self, data): continue s = i.split('@') if input: - self.inputs.append((s[1], s[0])) + self.inputs.append(Node(self, True, s[1], s[0])) else: - self.outputs.append((s[1], s[0])) + self.outputs.append(Node(self, False, s[1], s[0])) def __str__(self): return self.name def __repr__(self): return str(self) From 30d46fd07107aeb6a7f4e8da53139b75770f4cec Mon Sep 17 00:00:00 2001 From: Max Worrall <96847801+Tsunami014@users.noreply.github.com> Date: Wed, 29 Nov 2023 16:16:09 +1100 Subject: [PATCH 66/91] =?UTF-8?q?docs(nodes):=20=F0=9F=93=9D=20Commented?= =?UTF-8?q?=20out=20some=20unused=20statements?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit All the commented out things can be uncommented for later use The commented out things are 'when you drag a node on a blank space it gives a dropdown' --- elementGen/node_editor.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/elementGen/node_editor.py b/elementGen/node_editor.py index aa449ab..12a7348 100644 --- a/elementGen/node_editor.py +++ b/elementGen/node_editor.py @@ -227,7 +227,7 @@ def settings(event, element=None, aborted=False): # Same with r rd = [] - conned = False + #conned = False cirs = [] for p, node in G.Container.nodes: cirs = [] @@ -266,7 +266,7 @@ def settings(event, element=None, aborted=False): for i in cirs: if not l and isinstance(G.Container.selecting, tuple) and G.Container.selecting[2] != i[2] and not (G.Container.selecting[3] is i[3]): if i[0].collidepoint(pygame.mouse.get_pos()): - conned = True + #conned = True d = False po = (i[0].center[0]+5, i[0].center[1]+7) for j in range(len(G.Container.connections)): @@ -298,6 +298,8 @@ def settings(event, element=None, aborted=False): # del G.Container.connections[i] # del G.Container.connectionsinfo[i] # break + del G.Container.connections[i] + del G.Container.connectionsinfo[i] G.Container.selecting = None for i in cirs: if G.Container.selecting == None or (isinstance(G.Container.selecting, tuple) and not (G.Container.selecting[3] is i[3])): From 82fd32732325f3588ab4c4f46cc311ee4c5e1d34 Mon Sep 17 00:00:00 2001 From: Max Worrall <96847801+Tsunami014@users.noreply.github.com> Date: Wed, 29 Nov 2023 16:16:09 +1100 Subject: [PATCH 67/91] =?UTF-8?q?docs(nodes):=20=F0=9F=93=9D=20Commented?= =?UTF-8?q?=20out=20some=20unused=20statements?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit All the commented out things can be uncommented for later use The commented out things are 'when you drag a node on a blank space it gives a dropdown' --- elementGen/node_editor.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/elementGen/node_editor.py b/elementGen/node_editor.py index aa449ab..6917fe1 100644 --- a/elementGen/node_editor.py +++ b/elementGen/node_editor.py @@ -227,7 +227,7 @@ def settings(event, element=None, aborted=False): # Same with r rd = [] - conned = False + #conned = False cirs = [] for p, node in G.Container.nodes: cirs = [] @@ -266,7 +266,7 @@ def settings(event, element=None, aborted=False): for i in cirs: if not l and isinstance(G.Container.selecting, tuple) and G.Container.selecting[2] != i[2] and not (G.Container.selecting[3] is i[3]): if i[0].collidepoint(pygame.mouse.get_pos()): - conned = True + #conned = True d = False po = (i[0].center[0]+5, i[0].center[1]+7) for j in range(len(G.Container.connections)): From 159af9c41e983217408401a015c50ab742e9fd87 Mon Sep 17 00:00:00 2001 From: Max Worrall <96847801+Tsunami014@users.noreply.github.com> Date: Thu, 30 Nov 2023 15:50:17 +1100 Subject: [PATCH 68/91] =?UTF-8?q?feat(nodes):=20=F0=9F=92=A5=20Boomed=20th?= =?UTF-8?q?e=20code=20There=20are=20bugs?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit added a bunch of stuff to node_parser.py and started work on the connections being based off of generated positions that update instead of fixed positions Also fixed a lot of bugs and moved a lot of code --- elementGen/node_editor.py | 82 +++++++++++++++++---------------------- elementGen/node_parser.py | 40 +++++++++++++++++-- 2 files changed, 73 insertions(+), 49 deletions(-) diff --git a/elementGen/node_editor.py b/elementGen/node_editor.py index 6917fe1..5a06af4 100644 --- a/elementGen/node_editor.py +++ b/elementGen/node_editor.py @@ -164,6 +164,25 @@ def dropdown(): else: return False else: return False + def parse(i, l, lf, rd): + if not l and isinstance(G.Container.selecting, tuple) and i.isntsimilar(G.Container.selecting[0]): + if i.rect.collidepoint(pygame.mouse.get_pos()): + d = False + for j in range(len(G.Container.connections)): + k = [_ for _ in G.Container.connections[j] if _.isinp][0] + if i == k or G.Container.selecting[0] == k: + G.Container.connections[j] = [G.Container.selecting[0], i] + d = True + break + if not d: + G.Container.connections.append([G.Container.selecting[0], i]) + elif G.Container.selecting == None or (isinstance(G.Container.selecting, tuple) and i.isntsimilar(G.Container.selecting[0])): + if i.rect.collidepoint(pygame.mouse.get_pos()): + rd.append((i.rect.topleft[0]+5, i.rect.topleft[1]+7)) + if lf: + G.Container.selecting = (i, (i.rect.center[0]+5, i.rect.center[1]+7)) + return rd + @G.Graphic def editor(event, path, element=None, aborted=False): if event == GO.EFIRST: @@ -173,13 +192,13 @@ def editor(event, path, element=None, aborted=False): mouseDown(3) # Right mouse button ] G.Container.selecting = None - G.Container.connections = [] # The start pos-end pos - G.Container.connectionsinfo = [] # The nodes which contain these said start and end poses + G.Container.connections = [] if path.endswith('.elm'): path = path[:-4] if not os.path.exists('data/elements/'+path+'.elm'): # Version: major.minor - pickle.dump({"idea": "BLANK", "name": "New File", "version": 0.3}, open('data/elements/'+path+'.elm', 'wb+')) + pickle.dump({"idea": "BLANK", "name": "New File", "version": "0.4"}, open('data/elements/'+path+'.elm', 'wb+')) + # TODO: version checking and updating (not for versions less than 1.0 which is the liftoff version) G.Container.contents = pickle.load(open('data/elements/'+path+'.elm', 'rb')) if 'nodes' in G.Container.contents: G.Container.nodes = G.Container.contents['nodes'] @@ -227,10 +246,8 @@ def settings(event, element=None, aborted=False): # Same with r rd = [] - #conned = False - cirs = [] for p, node in G.Container.nodes: - cirs = [] + node.cirs.reset() col = GO.CBLUE txt = GO.FFONT.render(str(node), 2, GO.CBLACK) sur = pygame.Surface(G.size) @@ -242,10 +259,11 @@ def settings(event, element=None, aborted=False): for n in node.inputs: s, c = CAT(n.name, bgcol=col) c.move_ip(0+p[0], i+p[1]) - cirs.append((c, n, True, node)) + node.cirs[n] = c sur.blit(s, (0, i)) mx = max(mx, s.get_width()) i += s.get_height() + 2 + rd = parse(n, l, lf, rd) if node.outputs != []: mx += 20 i2 = start @@ -253,66 +271,38 @@ def settings(event, element=None, aborted=False): for n in node.outputs: s, c = CAT(n.name, front=False, bgcol=col) c.move_ip(mx+p[0], i2+p[1]) - cirs.append((c, n, False, node)) + node.cirs[n] = c sur.blit(s, (mx, i2)) mx2 = max(mx2, s.get_width()) i2 += s.get_height() + 2 + rd = parse(n, l, lf, rd) mx2 += mx sur2 = pygame.Surface((mx2, max(i, i2))) sur2.fill(col) sur2.blit(sur, (0, 0)) r = pygame.Rect(*p, mx2+10, max(i, i2)+10) pygame.draw.rect(G.WIN, col, r, border_radius=8) - for i in cirs: - if not l and isinstance(G.Container.selecting, tuple) and G.Container.selecting[2] != i[2] and not (G.Container.selecting[3] is i[3]): - if i[0].collidepoint(pygame.mouse.get_pos()): - #conned = True - d = False - po = (i[0].center[0]+5, i[0].center[1]+7) - for j in range(len(G.Container.connections)): - k = [_ for _ in G.Container.connectionsinfo[j] if _.isinp][0] - if i[1] is k or G.Container.selecting[0] is k: - G.Container.connections[j] = [G.Container.selecting[1], po] - G.Container.connectionsinfo[j] = [G.Container.selecting[0], i[1]] - d = True - break - if not d: - G.Container.connections.append([G.Container.selecting[1], po]) - G.Container.connectionsinfo.append([G.Container.selecting[0], i[1]]) - elif G.Container.selecting == None or (isinstance(G.Container.selecting, tuple) and G.Container.selecting[2] != i[2] and not (G.Container.selecting[3] is i[3])): - if i[0].collidepoint(pygame.mouse.get_pos()): - rd.append((i[0].topleft[0]+5, i[0].topleft[1]+7)) - if lf: - G.Container.selecting = (i[1], (i[0].center[0]+5, i[0].center[1]+7), i[2], i[3]) if G.Container.selecting == None and lf and r.collidepoint(pygame.mouse.get_pos()): - G.Container.selecting = G.Container.nodes.index((p, node)) + G.Container.selecting = [G.Container.nodes.index((p, node)), (pygame.mouse.get_pos()[0]-p[0], pygame.mouse.get_pos()[1]-p[1])] G.WIN.blit(sur2, (p[0]+5, p[1]+5)) for i in rd: G.WIN.blit(CAT('', filled=True, bgcol=col)[0], i) if not l and G.Container.selecting != None: - #if not conned:# and G.Container.selecting[2]: - # for i in range(len(G.Container.connections)): - # if G.Container.selecting[1] in G.Container.connections[i]: - # if dropdown() == False: - # del G.Container.connections[i] - # del G.Container.connectionsinfo[i] - # break G.Container.selecting = None - for i in cirs: - if G.Container.selecting == None or (isinstance(G.Container.selecting, tuple) and not (G.Container.selecting[3] is i[3])): - if i[0].collidepoint(pygame.mouse.get_pos()): - G.WIN.blit(CAT('', filled=True, bgcol=col)[0], (i[0].topleft[0]+5, i[0].topleft[1]+7)) - if lf: - G.Container.selecting = (i[1], (i[0].center[0]+5, i[0].center[1]+7), i[2], i[3]) if isinstance(G.Container.selecting, tuple): pygame.draw.line(G.WIN, GO.CRED, G.Container.selecting[1], pygame.mouse.get_pos(), 10) - elif isinstance(G.Container.selecting, int): - G.Container.nodes[G.Container.selecting] = (pygame.mouse.get_pos(), G.Container.nodes[G.Container.selecting][1]) + elif isinstance(G.Container.selecting, list): + G.Container.nodes[G.Container.selecting[0]] = ( + (pygame.mouse.get_pos()[0]-G.Container.selecting[1][0], + pygame.mouse.get_pos()[1]-G.Container.selecting[1][1]), + G.Container.nodes[G.Container.selecting[0]][1]) for i in G.Container.connections: - pygame.draw.line(G.WIN, GO.CNEW('orange'), i[0], i[1], 10) + pygame.draw.line(G.WIN, GO.CNEW('orange'), \ + (i[0].rect.center[0]+5, i[0].rect.center[1]+7), \ + (i[1].rect.center[0]+5, i[1].rect.center[1]+7), 10) return True elif event == GO.EEVENT: # When something like a button is pressed. Is passed 'element' too, but this time it is an event if element.type == pygame.KEYDOWN: diff --git a/elementGen/node_parser.py b/elementGen/node_parser.py index def2ea5..1df3af7 100644 --- a/elementGen/node_parser.py +++ b/elementGen/node_parser.py @@ -3,14 +3,38 @@ def allCategories(): return [i.name for i in os.scandir('data/nodes') if i.is_file()] -class Node: +class FakeDict(dict): + def __init__(self, func=lambda: None, clearfunc=lambda: None): + self.func = func + self.clearfunc = clearfunc + def __setitem__(self, __key, __value): + self.func(__key, __value) + return super().__setitem__(__key, __value) + def reset(self): + for i in self: + self.clearfunc(i, None) + self.clear() + +class Connector: def __init__(self, parent, isinp, name, typ): self.parent = parent self.isinp = isinp self.name = name self.type = typ + self.rect = None + def isntsimilar(self, other): + try: + return self.parent != other.parent and self.isinp != other.isinp + except: return False + def __eq__(self, other): + return hash(self) == hash(other) + try: + A = lambda a: getattr(self, a) == getattr(other, a) + return A('isinp') and A('name') and A('type')# and A('parent') # We comment out this as it's annoying as hell to work with + except: return False # Didn't have one of the attributes def __str__(self): return f'' def __repr__(self): return str(self) + def __hash__(self): return hash(str(self)) class Names: def __init__(self, data): @@ -19,6 +43,7 @@ def __init__(self, data): self.name = spl[0] self.inputs = [] self.outputs = [] + self.cirs = FakeDict(self.setter, self.setter) # Relying on externals to generate input = True for i in spl[1:]: if i == '|': @@ -26,9 +51,18 @@ def __init__(self, data): continue s = i.split('@') if input: - self.inputs.append(Node(self, True, s[1], s[0])) + self.inputs.append(Connector(self, True, s[1], s[0])) else: - self.outputs.append(Node(self, False, s[1], s[0])) + self.outputs.append(Connector(self, False, s[1], s[0])) + def setter(self, key, value): + for i in range(len(self.inputs)): + if self.inputs[i] == key: + self.inputs[i].rect = value + return + for i in range(len(self.outputs)): + if self.outputs[i] == key: + self.outputs[i].rect = value + return def __str__(self): return self.name def __repr__(self): return str(self) From d01b09770b0bb15058d48b8a90e20c09a8545146 Mon Sep 17 00:00:00 2001 From: Max Worrall <96847801+Tsunami014@users.noreply.github.com> Date: Thu, 30 Nov 2023 16:18:41 +1100 Subject: [PATCH 69/91] =?UTF-8?q?feat(nodes):=20=F0=9F=90=9B=20IIIIIIIIIII?= =?UTF-8?q?IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIITWORKS=20OH=20YEAH!!!!!?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixed some issues with copying (in-code plagarism, but they got away with it so I hunted them down) (THAT WAS A JOKE) Oh I'm so happy this WORKS! --- elementGen/node_editor.py | 3 +-- elementGen/node_parser.py | 27 ++++++++++++++++++++++++++- 2 files changed, 27 insertions(+), 3 deletions(-) diff --git a/elementGen/node_editor.py b/elementGen/node_editor.py index 5a06af4..6b0a710 100644 --- a/elementGen/node_editor.py +++ b/elementGen/node_editor.py @@ -1,7 +1,6 @@ import pygame, os, pickle import graphics.graphics_options as GO import elementGen.node_parser as np -from copy import deepcopy categories = [i.name for i in os.scandir('data/elements') if i.is_dir()] @@ -159,7 +158,7 @@ def dropdown(): resp2 = G.Dropdown(['Back']+[str(i) for i in nodes[resp].getall()], pos=p) if isinstance(resp2, int) and not isinstance(resp, bool): if resp2 != 0: - G.Container.nodes.append((p, deepcopy(nodes[resp].getall()[resp2-1]))) + G.Container.nodes.append((p, nodes[resp].getall()[resp2-1].copy())) return True else: return False else: return False diff --git a/elementGen/node_parser.py b/elementGen/node_parser.py index 1df3af7..a1abc86 100644 --- a/elementGen/node_parser.py +++ b/elementGen/node_parser.py @@ -1,4 +1,6 @@ import os +from random import random +from copy import deepcopy def allCategories(): return [i.name for i in os.scandir('data/nodes') if i.is_file()] @@ -17,6 +19,7 @@ def reset(self): class Connector: def __init__(self, parent, isinp, name, typ): + self.num = random() self.parent = parent self.isinp = isinp self.name = name @@ -26,6 +29,10 @@ def isntsimilar(self, other): try: return self.parent != other.parent and self.isinp != other.isinp except: return False + def copy(self): + c = deepcopy(self) + c.num = random() + return c def __eq__(self, other): return hash(self) == hash(other) try: @@ -34,10 +41,11 @@ def __eq__(self, other): except: return False # Didn't have one of the attributes def __str__(self): return f'' def __repr__(self): return str(self) - def __hash__(self): return hash(str(self)) + def __hash__(self): return hash(self.parent) + hash(self.num) class Names: def __init__(self, data): + self.num = random() self.rdata = data.strip(' \n') spl = self.rdata.split(' ') self.name = spl[0] @@ -63,8 +71,25 @@ def setter(self, key, value): if self.outputs[i] == key: self.outputs[i].rect = value return + raise IndexError( + 'Could not find key in list!!' + ) + def copy(self): + c = deepcopy(self) + c.num = random() + """c.cirs = FakeDict(self.setter, self.setter) + iis = [] + for i in c.inputs: + iis.append(i.copy()) + c.inputs = iis + oos = [] + for i in c.outputs: + oos.append(i.copy()) + c.outputs = oos""" + return c def __str__(self): return self.name def __repr__(self): return str(self) + def __hash__(self): return hash(self.num) class Parse: def __init__(self, category): From f09bf3b268a3f83a32a76d782069d9e69702f8e8 Mon Sep 17 00:00:00 2001 From: Max Worrall <96847801+Tsunami014@users.noreply.github.com> Date: Thu, 30 Nov 2023 18:05:06 +1100 Subject: [PATCH 70/91] =?UTF-8?q?feat(nodes):=20=E2=9C=A8=20Added=20saving?= =?UTF-8?q?=20of=20the=20connections=20:)=20:)=20And=20fixed=20all=20error?= =?UTF-8?q?s=20that=20arose=20because=20of=20it?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- elementGen/node_editor.py | 6 +++++- elementGen/node_parser.py | 14 +++++++++++--- 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/elementGen/node_editor.py b/elementGen/node_editor.py index 6b0a710..e4a5aa0 100644 --- a/elementGen/node_editor.py +++ b/elementGen/node_editor.py @@ -191,7 +191,6 @@ def editor(event, path, element=None, aborted=False): mouseDown(3) # Right mouse button ] G.Container.selecting = None - G.Container.connections = [] if path.endswith('.elm'): path = path[:-4] if not os.path.exists('data/elements/'+path+'.elm'): @@ -203,6 +202,10 @@ def editor(event, path, element=None, aborted=False): G.Container.nodes = G.Container.contents['nodes'] else: G.Container.nodes = [] + if 'connections' in G.Container.contents: + G.Container.connections = G.Container.contents['connections'] + else: + G.Container.connections = [] G.Container.name = G.Container.contents['name'] if event == GO.ELOADUI: G.Clear() @@ -309,6 +312,7 @@ def settings(event, element=None, aborted=False): if path.endswith('.elm'): path = path[:-4] G.Container.contents['nodes'] = G.Container.nodes + G.Container.contents['connections'] = G.Container.connections pickle.dump(G.Container.contents, open('data/elements/'+path+'.elm', 'wb+')) # Save G.Container.saved = True elif element.type == pygame.MOUSEBUTTONDOWN and element.button == pygame.BUTTON_RIGHT: diff --git a/elementGen/node_parser.py b/elementGen/node_parser.py index a1abc86..7e9ad9a 100644 --- a/elementGen/node_parser.py +++ b/elementGen/node_parser.py @@ -10,7 +10,9 @@ def __init__(self, func=lambda: None, clearfunc=lambda: None): self.func = func self.clearfunc = clearfunc def __setitem__(self, __key, __value): - self.func(__key, __value) + try: + self.func(__key, __value) + except AttributeError: pass return super().__setitem__(__key, __value) def reset(self): for i in self: @@ -87,9 +89,15 @@ def copy(self): oos.append(i.copy()) c.outputs = oos""" return c - def __str__(self): return self.name + def __str__(self): + try: + return self.name + except AttributeError: return 'A Name object' def __repr__(self): return str(self) - def __hash__(self): return hash(self.num) + def __hash__(self): + try: + return hash(self.num) + except AttributeError: return hash(str(self)) class Parse: def __init__(self, category): From c293baadba8e091d2c7b0922962c7deacbb46e1d Mon Sep 17 00:00:00 2001 From: Max Worrall <96847801+Tsunami014@users.noreply.github.com> Date: Fri, 1 Dec 2023 08:00:23 +1100 Subject: [PATCH 71/91] =?UTF-8?q?feat(docs):=20=E2=9C=A8=20Added=20credits?= =?UTF-8?q?.md?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Will be constantly added to when I remember new things I forgot initially --- credits.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 credits.md diff --git a/credits.md b/credits.md new file mode 100644 index 0000000..123657b --- /dev/null +++ b/credits.md @@ -0,0 +1,5 @@ +# Blaze Sudios credits: +## Other people's stuff that's been used: + - LDtk by Deepnight games (Thanks so much! This wouldn't be the same without it!) + - Some peoples' code on Stack Overflow and Github +## Thanks to everyone who has helped make this project! From 55d213f84f58ca5e97cd224fdcbd23b2162600fe Mon Sep 17 00:00:00 2001 From: Max Worrall <96847801+Tsunami014@users.noreply.github.com> Date: Fri, 1 Dec 2023 08:04:27 +1100 Subject: [PATCH 72/91] =?UTF-8?q?feat(GUI):=20=F0=9F=8E=89=20Added=20start?= =?UTF-8?q?=20UI=20files?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- UIpack/Bonus/click1.ogg | Bin 0 -> 6952 bytes UIpack/Bonus/click2.ogg | Bin 0 -> 5784 bytes UIpack/Bonus/rollover1.ogg | Bin 0 -> 9144 bytes UIpack/Bonus/rollover2.ogg | Bin 0 -> 5838 bytes UIpack/Bonus/switch2.ogg | Bin 0 -> 11630 bytes UIpack/Bonus/switch3.ogg | Bin 0 -> 12227 bytes UIpack/Font/kenvector_future.ttf | Bin 0 -> 34136 bytes UIpack/Font/kenvector_future_thin.ttf | Bin 0 -> 34100 bytes UIpack/Spritesheet/blueSheet.png | Bin 0 -> 10406 bytes UIpack/Spritesheet/blueSheet.xml | 28 ++ UIpack/Spritesheet/greenSheet.png | Bin 0 -> 9977 bytes UIpack/Spritesheet/greenSheet.xml | 28 ++ UIpack/Spritesheet/greySheet.png | Bin 0 -> 12953 bytes UIpack/Spritesheet/greySheet.xml | 41 ++ UIpack/Spritesheet/redSheet.png | Bin 0 -> 10557 bytes UIpack/Spritesheet/redSheet.xml | 28 ++ UIpack/Spritesheet/yellowSheet.png | Bin 0 -> 10209 bytes UIpack/Spritesheet/yellowSheet.xml | 28 ++ UIpack/Vector/UIpack_vector.svg | 553 ++++++++++++++++++++++++++ UIpack/license.txt | 14 + credits.md | 1 + 21 files changed, 721 insertions(+) create mode 100644 UIpack/Bonus/click1.ogg create mode 100644 UIpack/Bonus/click2.ogg create mode 100644 UIpack/Bonus/rollover1.ogg create mode 100644 UIpack/Bonus/rollover2.ogg create mode 100644 UIpack/Bonus/switch2.ogg create mode 100644 UIpack/Bonus/switch3.ogg create mode 100644 UIpack/Font/kenvector_future.ttf create mode 100644 UIpack/Font/kenvector_future_thin.ttf create mode 100644 UIpack/Spritesheet/blueSheet.png create mode 100644 UIpack/Spritesheet/blueSheet.xml create mode 100644 UIpack/Spritesheet/greenSheet.png create mode 100644 UIpack/Spritesheet/greenSheet.xml create mode 100644 UIpack/Spritesheet/greySheet.png create mode 100644 UIpack/Spritesheet/greySheet.xml create mode 100644 UIpack/Spritesheet/redSheet.png create mode 100644 UIpack/Spritesheet/redSheet.xml create mode 100644 UIpack/Spritesheet/yellowSheet.png create mode 100644 UIpack/Spritesheet/yellowSheet.xml create mode 100644 UIpack/Vector/UIpack_vector.svg create mode 100644 UIpack/license.txt diff --git a/UIpack/Bonus/click1.ogg b/UIpack/Bonus/click1.ogg new file mode 100644 index 0000000000000000000000000000000000000000..4f17f1cdd3f3554546329fb2d84f330e7c17263b GIT binary patch literal 6952 zcmbU_2{@Ep+YiZ>BxEURgqIQ3Fk)m&gs~4JYZ7BGF(@=r4K)Zcwy`fmqj*bMi@eEF zma%1`q*8<;#3X6{Gt~RN-}hhF_g~k49LKrubD#5^d%q7WZ*NP?DJ~o zkmd*r3_j(HXQMa`Z~r2h-5{>xuww80yRmn20ElN~DM84P^=~a`)5bwauztkqFw8yB zF4P|8ta=cEIEYk5y22Dsx#Mx3u)s4g2j8le#74WbC-&6MM--ok5!m)YdjC}@2 z?KvP`fI*nUTBCcDu@EE#K_}(lf~j7na4NY_F+7uO!k)DrBxRCGtr8vyh_>GY4C%Q8 zg1De)MZU!12~)owl(&RJVsHV<*HW_##uI1r2F3Sy=?{-HrT0ty&-B3MdAB-l2JA!n zCNeRi81``LnoO(&7_LeMcgU3G1oJE1EV#_C+5x*_t~yncYN<7Kvp7*}TJe6b!4{SK z{b+NpQ{8Q%~! zy(`*zSE{>D&T2u~Mnt_&&B)fy0t;HG>+vugBP^5=MsUoGajqjc*2Or#h;e1cxJ$(T z>fZ=sOm<&q9mW9_$fDB6;YE9Q7QI6iZ6e0r=7c=iB7yOx?1iTko0fX{Rr+Sv_}r>F z-C3pFStYPe0+h?ez7161ODX+d-ODi@_kVYNpAIERAIP#jNUA+Z&Ilvd9<0o>F5wOc z=u{u0+!~BD#v|MD+MpYU7(OMNcYihC_FD;TwL_3TLaH@L>M4*0Mr9ya{WxBSfwy1) zQLrWQ-`k~idjX8d^<4b_xTH$*brI)hUjS{4MD4>aE z5Bx>4%T}nTWoEByFrY_r9Ox4MEUUF3tCxcBF%_UtH)i3&**q1ret?sl%n@vpbO&_4 z{S+SBumjlZ*h`tXSuYA^ByzSwb-mrjdB4npb|RMB_bE}CQkhigkR-v>0z?PAMEZK-F*NOpHAYf_8ghA^a~K2> zh1RY3_polt8&+JB5~uV`@m`l|r!srE-O{5qbEiejtFLLzlyZipp>GM)H!t$W^sjAqj z>0s@!$HPuLW`w@1jd6VuI>sQ3F|NCb$Nr~b{p~pra2n#ePm)h1Alh@TSQ_wcDEPPM z1c|oaka~JU&a6t#qF=dt0co{}>=QAvL0Z`EaP8X>Iv|F#J>)u|jvK(@o`>OvYjDoB z1jm|R4zuAlV~o&$cn;e|_M#HUO;Wi2-XPxmHKXjyqvv?Bih z@Eo7Gvdp-$YjKm;5*115z9dR{eNn)(%9)1$v;XZm#=&x+1J5xEmive2G$W*r0&l8P zwpiTYQKt_GG{i{!p9+AW=41i0^*CaKQF)G0e~wYX+Ufjvj{&RCkro3;AlNhrk_4d; z-bx`_ryQ|Fe=_oIgYi^we}EGuQeVVRWg2wYSSxu7NWRy9I*5oBT0G@ZCTh?XKTpLc z968WdhcQt6ix-4FF31LgxJ~z(%9$=8i%h=Cb<4(SZ;zIX&`z2(&Ffe^FAbTBhD*~^ z4R1`&YlEc1AqalO3<_oTaYk!$K=E?n(xwaADeuFP7NRn7DW#;nbTx}SuQ+pCY+?B? zkfK0Y2lEuml|Yy*pK9=YS>xXM3oM;(2pF!Bc?sNJ&dSz;;zdDrBS}Sm23YxSHSBMY zW`NbP4RI}}YWW|hta z;~ZmEBL4ha<%+PR?{dn~p4W%=4!7B5mxjJ`^B1cIJclrNEznUb2H! z0ow@lO`zzOAZ0T^zGw(sDRtZ-eUen92+~5i5;&2*?qCCU*mSCIo^Qn=2SGz48vz$Bn1rPPnX+j8)UJBvj1Mf^@NV5kpWJMYKI13B1TCbY*T=so6Q^$tohiDZoXre`L{aqK_#4! zgj9PK5S)1*QpL0%X(MU`1Z9@O7KDvDHVx;?77maM5DO43+i<7DOKIgGK-eAs3Jluy zc>2Gj!U4VE6NL0PAG)1*7K0RX@aaH9Fkn;&ZW&JjgANIzr~xmWDkKa+2j74y>7;?A zBGOYHO6CX2u9yr`mMPWX8e$Sg?#ILkdGs7nq*8Ap+F;}qjK7UX!VyJz>QIrt3;@v; zMhpWs=oF7Bw?q3?v`SFzXk-8)&@?<6fF5KFlk60KcSw;Mq6(_5if+`TC#buewm|wm zpfo&u$32voT6DJ=sEZQ{2ie{L&92IXWT+AzU5Km67;%ZJmow4!Ao7XKnKImLec0uL9uBi_a67XS(igSsASo4$OQJnHY8K3 z1lzb^M0Pz$Mg!LHJx6$C0I0~ey7d{zdDfWeOuQgF`?2Y$gTHqG5U2x)YGZ*&#{8ZE zI#3Y*-a!@yti%AEJW&|UD_=s!@UwTosYHwcD4c=SP|4P4cp(`u5A4T4aUGOr=X-f} z&X)(PV1bNQEM(JB$!uiW`T_>c2VfvGHVRBO#&r~&3O)po>nLF~yF$mH*H8XUhvsLa z;8dVb;Fr;mtdhzTOSMXEPGeD3bN!gu+guO^SU>wdfJ{BXX8jX!QXA*4Z)Fecn`|8P zH|qZfax{;M3r6dT{F{G)=flBRpt9f|6czXourIO+9N3p78m`0EM=p^Zv92gMd`aS{ zq6`qu%-vW^Ene#VLH}(sM6#0~jVY~qQ<0j2nbWDZ#`wY8UPqeA-|KhsZ=8H>rUY*r ziI_vxreMrf#GsSHZ=vYAlP%M{3Pv86fCxCDQ^0wS3K*Dd@c8%3=3j3d1P2ri;sV5B ze`nvl`+miBwA6TmnTu<~-VdcDqorS%>05MJbUU)3U9QzR+GZ!@Z{v zCgwM}Q=WXd98Ba(G zVX?GWZ&{yM??UFEaFi(SwkeNv)pmzu-hTP=V_sE_q!|{YKQC-(lDYNjkI;L&!sKh-H1nI>|G{$Iub|F05CL=&b6w=PvuBbhe$7{YXQZzp|hmeX%Ha*g!Zh!Y zgkVDw->&MI+aF32%)dT()Cyy;%~YMpcpXXk5n^wUMiR4SPG*u!u*c<1PS-L}a&F?blN zPL$(lb)PJsAt7j_;(e6*lWm{(%?;=#_6?4tvVvb*U2WPXmPSkcknmKNkvgLe3-x5yViC4cAuBNqlwAYd&4%j_O3<#5hm*s$B)Z!aHN@+1l*0v>^#kb zewe{)bhX|1`Mf5UE?GwSth;tzqHIEcN6~8ayX;yVqnc4k_UiIpTm9)}|LV_+wc?#m zN6w8An4@zYdy1b2(`AV}gD$N3Y1DC1FAshck<-zmuflMppR`ufoCLGH1srXLYzNOP z%v}3?r|4s>FnO)i_VZtA8!@{@!qOuEF(! zpjs+_xk^3yjD-vw^I|1r*lOX}#q__j63;Yl@EnkMU;5a1`u3FWy?}FvDxTN82pT6ZapkfWf)u-) zt#>=j`*%q%5-}~H*UmwDyW>CUA{yg*_OHE35bQ@_C#1RhCz8GX4d(yKraVkle%kD4WJ(rDf)S z#GFGHN{vwU`o^N7+?r<0Pu^I|^{H5})BX0~L8V4kOV8(rFPn1qFe2VfUChh<_F(n? zXvMw!yR697JNunu55(90z`NY&yKy)8f)=&kZF)+v_yD6QL+jP_GdDlds#)lVNL=IX z${_nh=T~lLT9!u3+MPplKe#AK*PflpSnVHBT4K^gX05m%uB_B+L`H>S1yG3$=0XaB zS++`Zo6Z{BpQ~CqqcNA{((X*4eEi z*S9Ee?n9o@lg2`()Qr@wt(kuqZ~79k>0_SuffExBj}gL9^hi|E>!I3R74+-gctY=C z`ZHQ_FkDdD?eceyiqKV0rQEuQexk1$$8w1)B5C%pLX_SaidI}k&{6)=z59Dy(y%ID z20z^{oGH|ptepHIp{wydhd`)oy_(f?r>C-U#XcZiPa%-m3%{A_f_+wQdm%89Usp@@ zo$>d9t4+_b^sqVl@yQaRK zYl;`&?U<2Py>RYv*zyw+>Euy??!)&q?q-PVSB5^-klW3Yw%j)SRE9ItCCT9?%hIdwWvrU^MSl!^ie6ZX$R)G{oly}FbZfUAR~hCSRKf<4sNptd z;<=6Xchpu&&g=NRihi=_;osj9GXa|=kZ@Kjs@2D^=ZDifI|=p=aOGYQ3mT8ucMoOo}CcokLcl~q9YjZzazZaQ$?l7UZUA^KLnzD%} zp&QL#UO3IM%t;8z7Rnf9IPbIliQ1XjmDAs+mQ#k#oNeJg7)dz0DSGoso{!6I%UbhF zrXUo+LYxP@FFdY#;x&Zqd4aon{$0Cn#moSKWxF%3=|srdv4o3OErlaY17m&-%iYfX zKD!Sr4HbO4IN?j*(=SnZZ+DG#%J>8y_vx<_^);oJ7PvzXbx*v+4d~;WUJQ1t-Jzg7 znEQ2e97@vLxsw@}x*uc|MO36L`m;oNb+&I`G|zZ-aZW**xyrL!zcF1ql`!$}qIcl8 zuiy_lWf>yCk_c1Ck{k{TjObp)6`tpr9}(JW&_DD2#bTD>R6DDH2xI1{ zg;&;JTos?&9k_boP^4gb{+Wn5?U6l#f8Aop&6ye8EgK7}`;o7G;}QX;5iyx0p0gpTG&*idncnou3}c^@>=g&*b(-vo$3lTx#K|j~d z)Lf@@mH3N?hFH<_C(9NGUb^YYdrM>th0=jgfv1Dl>q z5*%K4j_7;J>8DyNF&L3D;x8Vt0-=JkaMw-cbC2|rrl%vA*U`gK+FGkWz&Wg+Uz1lK zzW$S0)la>vJL@_iDe0ZRbun^wcfHGjImT+x#aG*&dwRZ?_c+P=>Dt&$M>#{QOx7BG zmPC}sAL**=f^DXyr-AP^0$M3 z6MdK&ecG%$w2-|PIXiH)ZPDYdLHZcsxI7_j&;0W8 i#251BV^a%a)*Q-rnv1>p3tT3m85$r~J3Bkzq5lD5lpv}A literal 0 HcmV?d00001 diff --git a/UIpack/Bonus/click2.ogg b/UIpack/Bonus/click2.ogg new file mode 100644 index 0000000000000000000000000000000000000000..c60f6a197342b6996467001c537d362c8c0de925 GIT binary patch literal 5784 zcmbU^2{_bS`@fMaktSrh*VPc2vDGl##?~~58T&9Yr0fip7%HSDcc_t63~916G_ECN zE!{TzzNfk=6``n9a^0@){6=-}_x+#e`<~~2o-=38`=0l_zw>VAeUC$6pfe-{eQlxp zRwo?`Wzq;`#F5Z&A36g@30ahWC7D|#u17e)JHI!0CjvmPf3J){TCDtA3tO|w2nW`8 zIT)k7LtP?WQ675RvDoc6J)9>B?c>ex_d|sqLb=fo2kAP52Wl`-2k1Vog70JCk092r z^3WohyCNVlfWg|LnwfnUs1SsNATKqHRB8YT!{g+kqcS+w@T_?|JA=b+R`5;2wtO2< zIKNF0Bn≈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 literal 0 HcmV?d00001 diff --git a/UIpack/Font/kenvector_future.ttf b/UIpack/Font/kenvector_future.ttf new file mode 100644 index 0000000000000000000000000000000000000000..39ebdfaa904e4b08df8791f4c99fa1e379c408da GIT binary patch literal 34136 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 PiOjzua{P-TkKXowY>-!K literal 0 HcmV?d00001 diff --git a/UIpack/Font/kenvector_future_thin.ttf b/UIpack/Font/kenvector_future_thin.ttf new file mode 100644 index 0000000000000000000000000000000000000000..9f4b4fa59ac2211aabf9cb60c6f7caf441d087ef GIT binary patch literal 34100 zcmeHQYm8l2bzXPwjP1lu;v^<7=W&xbA*9&jI1X}BXeT&02_ZaU*D^GPjK^co;CV4K zW^DR8mH1J$QI#JRLM=s9LMjrWid57h^^Ys1QUtU@t*Zh-!lZy&sYOsxi4x-5@B8-i zJnq~(i3JqRx!(8ez0cZfee1E;-sjwV$JR2lORccBb>4MwbkFd|Mh=^8{U~~$nwTA5 z_?y3eKPjFy8~((JnKQ>9|M7P}Y z1KM|)ZG7*-{L-=wbzcFVZ}U3J5K0?m8{UCy=!gvuJ%sjcxH^ohzXPP*)_m*q&7bUS z>)hPwbZ+b1*?FMz?5(%GJpA&8ZWpv2Nc_vzoTs_Y)7&o_BTe_;x_{R_+kK+@_LuHB z|J?b{oqzWHXU~7;{KwAU@y+K({(0n|D0%((1+u_;4E+K*^Jk$JbitP(#+_1r^kX zP};tPdW$sYT*>=}*ypdQjyBJ$713i1`H0S+DRZ@PyvDI{9NMdn$@o?2f-XE)^;r$W z#gY%1V}Td3h5FFBZXv9pkN8kRU(h3*Wed`RCX|4mJk`fDN*n{)K-25oi#Et`yt@VQ z_TrKIsYC-TJ+FCegUatkM|nN31^GCWMs(~u=jzf8?Qjk@4(DLYU<=tG@Bt6<8Ah9h zyfv}DX1|G<$%Ffh>Tz4^lW}go4j0`#ZQ1Maa`hqGXm|TM_EUC`uMgWz_8wm!vCTH; z>l-lgjIVFBH`^ci`X=;$(bq4r4fai6ztrAj-|_X$c5Q3BuWzy4tv$YencdYo>g$)= zuGSy;`qlP^))!nIU^lhC#U0e}CD7yU)_?eV%kCb!+SiBd@}al*dfUc^9`p5Kdtm4f zeSO5P8Txx)-+-|%`uavY-5&AvO?G$tw|)H*+tU6EU%%95+JEKin{C(dExx|Ro*I7K z*Dteo4}Z?rFSjR$U-9*;?TL~1x;k{(I`Y~5^9yGdr%y~RcOILZo0~k-*|Ynedr>_+ zIk7yy*g0@&`PAZM=g`#j+!K>0PR)!j9+;n7KDfMiYCSR#ii-_xz0Vi zc1OCMPR35k$e2$rb;di(i{r;8XU7*$cIJ6BZ8^ot5#W&e2oTGs~To>E$UWK*KNf z3|CfGc8Mv(l4YZuOe_#BjV?{iuZ-Tmd+*-8`}QwR0_KM&JNxHnXK}6b;PUd~^wCp< z-Z?lm4)Z=ZGktQ>^PTYIkVNWT^NS}&XQn46=awdyMvtD^ximg{@2=gW2gvd0^oh=g zPK{5ToSr+;`N-tL)S1Pl&IjkA%j_8_cDi$P^4R{BlaEgvzGuny+q^Ac(k$AvovPY?_S?~7`+pqn#YKa9k5fVpF({StwR_;jd4$)bppLJHjXO? zKsyJjgD8vW<>(+|5N;05Ae5boWR6+1C14@~rjK3FrOt0>NspaTk7nf4;Mjp?9qBV} z#~@`^nw~`8ydB5;0ciWE&O!GnTvz((;p z?(Mgf*>4xDI1lQ~Q=J>^dHZpLc0If#`u~O072u#oN8y`k;GlO_P+JBLjtv?l?_F9! zxB~hW*ft?`+6I)2s=@SW*4FuN3AR{*%BlqILpuKLkYM@aIXi=hX8Nj9&l>&Pt;HAY?ed%xXr`W2e!76m-X+ z>k7s`4i1MA;Y(a)hgv^qJ!2!dm-h>=J7W>P*YKnu?4`{L zdBae_u6EJFd+TM^hYIy|P~{T?9>>A2=@?W7z^<j541c(szv}o zg}T>>Fxp?2FQcz+uOOC}^hU_BMI{5DaF+f>_lw;ZyD#E0k2~y6yHB)i6?UI`Shw!i z@%l3Q3UUfs!0u?P_|d4xQ9)7|jr+eOO?pIsU7PC>@cT0aPy%G>Os+VDHA#2){54Qu z$M2~xfK9?Atu5hTB)ItzZCZ^2!Qh)J?wt}a(Am({i6xhW-v7euyLN+JjTaA4^s*zP znA`#dZ1o+C{+@coN7hXC12M+9c-Jh^;DWtE#ikgxI1#U412347=e00dl zkW=z0Jt3+xe>X{@6pas*8Hb=DuH!28mKVKcF65}FBPf7>8)}&XNeG5VXOfi*i|B9} zO`!{3t6tCefIAMw!)D6O4)h1V3%zd>Cyv6MNg=`P!v)m&^4W~od4bfpCUBZjpzD4K zv+?WfCk;GD`(UOJ0XsQ2Q7Ih%$frc(_?BrD1DBBx#)uhD+i-${?{pyLrW zD7VC?s7MJs(Jvb}MM%=mQ$ycqg=o(PTbE+C4?0@9XWXuauAucXi}7BM-&N2hyOrWN z^LW(JPd-WrUJdJ)n~xhUXjis>@&v{PpY_zT$@X45fF*~5KB{XOQRT6g=ZgW+(OS+A zX}&~x4d_6N5kiGC>o{Cy%Oa!!ov;nQ-vl{$105=O=i0;_v!Y!lX3+BhRglJ-8^ud0 z%VTUIF6=I_&e@>rwD@3S#Xh)$e{D~VKD&UzGtd+q1+F@aeZr+FoMto! zWH_=2&G$Iuq|$Fr-so(YAD2>j%2T#=GWo4awLRu7-%`B zmyy`-d9sFC-G~MpyszE;N60n7Yt`6@t_$qJAi$^?r@Be@=7MO5&BS4S&HZ$#@*a>2K>Kl0R#o_5soE=H9CD)$+872Ll(i+{0t#DWbb^BDT(3| z;uqtzviq|FxNK`&@itF9w>Rn$HCt65h$lbzF3JfuLvO+ruaY|WE%$iIhY4Hd{y;pz zK?FE^UC>Q$X`Z3Z2OXqf+mSZi$GI_jC?a;c4+{GOIW`V2Sc{Q~7K7}9#R-w{>OLxk zoQ%jO8BkqSa0a`|ylhql+r;W^D#nsaP}ao-aVKH=?5-&)d*3!`E;$#T2SV80|St3jmOkGZ%{(TNKUnfFWZ+l#moXD)+^ zc`s7OE9ePc##KKL61KKoSGPle+G6naFh`FWfDs&1)Qq#rOaK6Ybn&s>qe-?=IAeaK zSuId;{&Hx@#4dwcV?M(um$SU3GYipfvYoe2J)bGR-93 zAuFCkWTDI1w=Aocbv;b!bQ2m*3f}$UEasbJisLGv+n!P?WhdM9PRXE2PZ`C7qcoFs zP8=PNbj7h3#;}7Vt{fsbxJi;(vy96^2#>JXQc*44U}Ts z*469Zghd>|RbypOX^EaNNBn0TS`QtF;4O29B!W-0O0WPpWxYV|H_{je{z+F@p!7VE z7Qun{KtoRG&7Mp0YWCb&u2M|3HQN+TWwg{Qq+M_ib}FOB1)+xI_4^XUMBO^D5N#j4 z$(pz2D!vZ;+tM14`)vKbq-yKJML!}|Q&X|Moej=Dz2zxWJ*71(c_pmhZZ_@xOjzqyl%LIC2f)kcM9Oy&Xx3J!_$0<>;NE#xYj>{y z`u&KqpYw9qhr~$nId=ViB(n(OQdvJguiuZvrxDtJ!bJJXm{}~%-gr;+b8tU0#vF!x z#B2}~VXTBZuoMJoMRT`_)Yl~)s;$X{vyN~R;BP47&0)6P2pbBXwQp$J)8noSm&3gW z2**6$O8SndB^^UNnz&(&2*Ptk5XM_~&~q`#oyYP1R@FaM$rC#8^6m*K^?KBj@rWuy zLDe0>7y%4emqi5=dsAdaDuc`+fQREtRh8Sl{VI2tW!Jbh6Xd{vaYCpVsOcd!f;Oa1 zu^uH$3$K+{M1YD$bvicaF4OuucGW#+;$d5BWc>bLW=`*O3IUljVT`{FMo?Kkbviow z-~e*S0pO~DkjggjEq)hkv)y91+w1A&>`0(e&0pqd0tf*`y9jQR1sgma_Sj*(;}#T7 zpN*=gYF*0mch$jP-~%*iyt9XVzFk^T18LzDNXyv5>3s^P>H4ncbu+3-f$Lj0-TL%sX=quXg0KcM&lpScpQXCfGWw29a!2O7p7b2l!kc>`krRL6-GEl7o2##d8R#BVulb8N&RK zNjBDVfGoZ}T9AniXu2fKbR!JC0u9cYNnB(`t;vPo3dVPX!?%Mew`kh0#}!%FILlz6 zt!z|Z^_3y|*DY++v3WsD%NA)M0VkJly=@^&;)1P1n;d2MLg#2w=qH__)~eSr){PWZ z7?oCkH#*XUNJ&{95$WTM>;E476z5?((qNscv79=&4eJzCHm6X%ua&U`#ZQf!t$i^l zE{yq@?T?2Rs;>3!=LZSrPk}-c1`|jj(HGA!QOAAV9r%@S%@cL!C_1Zjt^OA3>#?7% zwbx=P{kA*WDa8M@ePkee)ofMkXqp4HNm1+QzsbHBbD%$uHTbP>4D^@Akp2HR(_TAb ztt*PbYxPZa29ZL-y@e3cIc07dD=fu6uQO(G6nyjB5LOGm;Rw`ml?lteR^|dV;Z?2-YFR~vvutHwRnH6zW4{3^Tp+H=1N~R$cxO=7e+PoKzy8r{!651w)PraH zZEyNNKUssvFGfNw&$AtaT4+Fn^k3^Prn)ZI@*bd_eibDD`9y|OXfg&2e#M5C#V%S}gXh$z+w4foKObTm%>*10&PCzuH`8 zjHn_`7pCkFuUH8k18dOtMx%dbT!Y51Ju}LWEw^^!?@xG}NNwUMI9+s(#^uAASBl0s zt?(fi*p>&zh>u%4(ZYg_ckzjwNg+H|w8!ANEgnyF0*8S{oGN#Zky~|L#*j7#cx>Ac zOHRwk)jPZHa}1TZvF>;I@Ptid2j++Ec*pZTK=~f7dM`{qlc^tb7xHXe>D`%O}sTbuD|_noq(dPD%<2P{86Zs zVUzNy7HksDQR-N$X)eOONc_$pWY_l^!S^ZiDe*Pt`Be>8O+w6Ja1oZg*YG8`+dWT=_WL}nHU85{IW76JS|eW{7?SO0P`>B3VB?0= z2z%hNUj#Ho(r$kc&jh^K$Mf%9xxgx~jis#|;7TCQTsdHsxg(@=GF^$;l)t6351^-wel4l@9h`I>(t{;XOZ zf$Q=8c|-MH$i`9(Hb0D9%f7j0!g}(m&c%Kd@>+}AUVVp(x@1Q8vjF}H!4FfR#iD88 zayNV8uEj?}aEF3jQli;Y!f|VbeD6QY4!`Om2!Zj4C;(z46z6h4r?~_{qUvh%Bx(;V zpQ-5g@rL=|jys`DU@lrvGVx&==W{CR7VHp!QbVkY0@eJSjFdrv1}kHHip}-syqeOm zNw68GKBEhNsyj=&&hcfttv~05l?s?@&HJs@2@pQbV** zj}y+h-zkdVh?7%Ojn^;2-f9g->6e3nsCjM3){b&4??BKGWT9d(gRDR2y-z7xxn%u0 zFITLd`$k+VPbkJ%EQnLo(c>Pygmre+=g*qD>(6bv`E9vq!;MU$!ssZ6oLKx- zjqoWh-OOZjb^W=qyR(Z1gzf6vvET^*0cJ2g9v!VeH_q>V)7(fkm}t!=4!7j5-q2wr zyy+MCVN|imV}0i{@Ac=#G)LJc>(7n#SHWSIeovO&Jx+mVGF$N%wC~_%yz=6zQ0c<5 z(Ra^s;Vjo1B$dAReL&dM1vx2%ItgFG_^8tU~_+Nj< z?CwK<%FmdUA|z9P*-(qObGEA7QDz$?w6w?MIjpXziAh+w6lq=f`Ty(zvBh7ng6nt~LOaJ?@{MiL$K_*|TjC0@cf#<@vAgl5O5i)bmkPAcs zGHTji!&gATJ;?_5YrinGuB1cWQ{{LETH(7f{I=M0mi>UEY>8^Spd(UjO2NDh-1-G9 z?d1PH+FJP6E$HP1i?RvJASkMTyQ`3g9D3Ag6?eZZ>!Kx2xWHcB`k@2=VC7f&+dpAx zoYZO3`@JR5xZl#z80A-`=>xe$a}mLkjT&)0b1HJoc5q6HWHqlD2{Uv= zp~02DAXz9i1lS^mfE`q|zA%DZL!RR90NAduP8nS^Hnoi}iAx3)#KO5*Chj|jv>B-Z zOKyTH1I!O+Q{t}fy&UW&nCvSO)Mg-L%$<_AkkGX0yPMqab7%3&N&GLj9V=7XzB^&8Y3Tp5bW zJR~bCmW4rknd^x+#;gY!9U}zU&OGjvWqM-EXH%Z7!aOX8FZen2U1rNTQ_|Cw@;ur< z!H8#}@v{5!NBi?Qe-#gw_Mv>-Yy`iNA9)hxk5RsW@(uhUqTMK{Z}^ef#scMs_-}(B zLHRb)655xX#ec;36bg86-iw01&F9UwT!(Vn?6MnCF#hs4qI?BEk)J{Nvf0)#6v(*} z{IC2iluw~x+*LdClG#!M3_MJH2xdY`nv)7NIfahJC zP(bsB8T>cPsNaqLyD{#UK5h2KDU=t?c7kpv+PjXRz#gN+D92FFneBcDN`Zp(|H zx9&i}xVL`ZY(K{C2i-$YnY|6X--fXVK5q8#A+txO%pU!e+1npN`Jvfk$576hy#v=C ze+SA}%-)G>@BF^myPh_C_gyIHdk@MJpg#zVhamIUwxK+0b{MpW|I_Tq78LL}@(C1- zeJ|+V2bsUVVD@AO1>=7M{N4}Q9{{$eK4Uh11my*@qx(?4U^elb*|EJSxHh>J1#%`) zKMr0eW>B6%c^>5_W>cV>Lf;hH(>qW;iUJuQME}W0P%v(06AH%6pnn#$bD*08hWXz& KTY$`k7yb_mr&(bD literal 0 HcmV?d00001 diff --git a/UIpack/Spritesheet/blueSheet.png b/UIpack/Spritesheet/blueSheet.png new file mode 100644 index 0000000000000000000000000000000000000000..2c0401a88e55e80d086b21dc9af7c8cf76a907c7 GIT binary patch literal 10406 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 literal 0 HcmV?d00001 diff --git a/UIpack/Spritesheet/blueSheet.xml b/UIpack/Spritesheet/blueSheet.xml new file mode 100644 index 0000000..9c8e74f --- /dev/null +++ b/UIpack/Spritesheet/blueSheet.xml @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/UIpack/Spritesheet/greenSheet.png b/UIpack/Spritesheet/greenSheet.png new file mode 100644 index 0000000000000000000000000000000000000000..8a7ff7fb6adba5dacf71f5ee99fd46931c781cfa GIT binary patch literal 9977 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 F{|CKvXhi@3 literal 0 HcmV?d00001 diff --git a/UIpack/Spritesheet/greenSheet.xml b/UIpack/Spritesheet/greenSheet.xml new file mode 100644 index 0000000..a9c8edc --- /dev/null +++ b/UIpack/Spritesheet/greenSheet.xml @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/UIpack/Spritesheet/greySheet.png b/UIpack/Spritesheet/greySheet.png new file mode 100644 index 0000000000000000000000000000000000000000..1ebbd975d33283c59cdbe7257a74d02855334d77 GIT binary patch literal 12953 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 P5MzeAraE~?9Dn;i{uUhC literal 0 HcmV?d00001 diff --git a/UIpack/Spritesheet/greySheet.xml b/UIpack/Spritesheet/greySheet.xml new file mode 100644 index 0000000..d7f87dd --- /dev/null +++ b/UIpack/Spritesheet/greySheet.xml @@ -0,0 +1,41 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/UIpack/Spritesheet/redSheet.png b/UIpack/Spritesheet/redSheet.png new file mode 100644 index 0000000000000000000000000000000000000000..0dc4f455e3eb672368aa3116580133ab0c968cbe GIT binary patch literal 10557 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 ROv5jNllta*MaP|^{s#*7<6Zy& literal 0 HcmV?d00001 diff --git a/UIpack/Spritesheet/redSheet.xml b/UIpack/Spritesheet/redSheet.xml new file mode 100644 index 0000000..0836bb6 --- /dev/null +++ b/UIpack/Spritesheet/redSheet.xml @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/UIpack/Spritesheet/yellowSheet.png b/UIpack/Spritesheet/yellowSheet.png new file mode 100644 index 0000000000000000000000000000000000000000..aef43dbc4bce9c6665d2b7e994bf04eff019da15 GIT binary patch literal 10209 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 UJ%y1t1y2N8C-qKb9 + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/UIpack/Vector/UIpack_vector.svg b/UIpack/Vector/UIpack_vector.svg new file mode 100644 index 0000000..6a89dc1 --- /dev/null +++ b/UIpack/Vector/UIpack_vector.svg @@ -0,0 +1,553 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/UIpack/license.txt b/UIpack/license.txt new file mode 100644 index 0000000..0c8c745 --- /dev/null +++ b/UIpack/license.txt @@ -0,0 +1,14 @@ + +############################################################################### + + UI pack by Kenney Vleugels (www.kenney.nl) + + ------------------------------ + + License (CC0) + http://creativecommons.org/publicdomain/zero/1.0/ + + You may use these graphics in personal and commercial projects. + Credit (Kenney or www.kenney.nl) would be nice but is not mandatory. + +############################################################################### \ No newline at end of file diff --git a/credits.md b/credits.md index 123657b..f3fcf49 100644 --- a/credits.md +++ b/credits.md @@ -1,5 +1,6 @@ # Blaze Sudios credits: ## Other people's stuff that's been used: - LDtk by Deepnight games (Thanks so much! This wouldn't be the same without it!) + - Kenney (www.kenney.nl) for the epic UI - Some peoples' code on Stack Overflow and Github ## Thanks to everyone who has helped make this project! From 1e7c6796ae1b5e19fb888b5f8a9fb50442f7b005 Mon Sep 17 00:00:00 2001 From: Max Worrall <96847801+Tsunami014@users.noreply.github.com> Date: Fri, 1 Dec 2023 08:06:44 +1100 Subject: [PATCH 73/91] =?UTF-8?q?feat(GUI):=20=F0=9F=8E=89=20Added=20blank?= =?UTF-8?q?=20python=20files=20for=20the=20GUI?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- UIpack/GUI.py | 0 UIpack/__init__.py | 1 + 2 files changed, 1 insertion(+) create mode 100644 UIpack/GUI.py create mode 100644 UIpack/__init__.py diff --git a/UIpack/GUI.py b/UIpack/GUI.py new file mode 100644 index 0000000..e69de29 diff --git a/UIpack/__init__.py b/UIpack/__init__.py new file mode 100644 index 0000000..9a9faa0 --- /dev/null +++ b/UIpack/__init__.py @@ -0,0 +1 @@ +from UIpack.GUI import * From 3897c1e9d4a2379c1d65c07a8be3201e80cbac92 Mon Sep 17 00:00:00 2001 From: Max Worrall <96847801+Tsunami014@users.noreply.github.com> Date: Fri, 1 Dec 2023 15:28:21 +1100 Subject: [PATCH 74/91] =?UTF-8?q?feat(GUI):=20=E2=9C=A8=20Added=20the=20st?= =?UTF-8?q?art=20to=20the=20GUI=20parsing?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit You can see the elements from the UI pack in Pygame --- UIpack/GUI.py | 57 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) diff --git a/UIpack/GUI.py b/UIpack/GUI.py index e69de29..197388e 100644 --- a/UIpack/GUI.py +++ b/UIpack/GUI.py @@ -0,0 +1,57 @@ +import pygame +pygame.init() +WIN = pygame.display.set_mode((500, 500)) + +import os +if os.getcwd().endswith('UIpack'): + app = '' +else: app = 'UIpack/' + +from xml.dom.minidom import parse +def getAll(colour): + p = parse(app+'Spritesheet/%sSheet.xml'%colour) + sur = pygame.image.load(app+'Spritesheet/%sSheet.png'%colour).convert_alpha() + #a = {i.attributes._attrs['name'].value: {j: int(i.attributes._attrs[j].value) for j in i.attributes._attrs.keys() if j != 'name'} for i in p.getElementsByTagName('SubTexture')} + return {i.attributes._attrs['name'].value[len(colour)+1:-4]: + sur.subsurface(pygame.Rect( + int(i.attributes._attrs['x'].value), + int(i.attributes._attrs['y'].value), + int(i.attributes._attrs['width'].value), + int(i.attributes._attrs['height'].value) + )) for i in p.getElementsByTagName('SubTexture')} + +def scrprint(sur, pos=(0, 0), cl=True): + pygame.event.pump() + if cl: WIN.fill((255, 255, 255)) + WIN.blit(sur, pos) + pygame.display.update() +def allscrprint(l): + WIN.fill((255, 255, 255)) + pos = [0, 0] + spacingy = 0 + for i in l: + spacingy = max(spacingy, i.get_height()) + if pos[0] + i.get_width() > WIN.get_width(): + pos[0] = 0 + pos[1] += spacingy + 10 + spacingy = 0 + scrprint(i, pos, False) + pos[0] += i.get_width() + 10 + +show = lambda col: allscrprint(getAll(col).values()) + +from random import shuffle + +def colours(): + l = ['blue', 'green', 'grey', 'red', 'yellow'] + shuffle(l) + while True: + for i in l: + yield i + +c = colours() +while True: + if pygame.event.get(pygame.QUIT): + show(next(c)) + +pass From 10e964dd789ad3a3f07592a661f99fe35780004c Mon Sep 17 00:00:00 2001 From: Max Worrall <96847801+Tsunami014@users.noreply.github.com> Date: Mon, 4 Dec 2023 08:12:06 +1100 Subject: [PATCH 75/91] =?UTF-8?q?feat(GUI):=20=E2=9C=A8=20Added=20some=20d?= =?UTF-8?q?ropdown=20PNGs=20that=20were=20not=20in=20the=20spritesheet?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- UIpack/PNGs/dropdownBottom.png | Bin 0 -> 1164 bytes UIpack/PNGs/dropdownMid.png | Bin 0 -> 995 bytes UIpack/PNGs/dropdownTop.png | Bin 0 -> 1261 bytes 3 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 UIpack/PNGs/dropdownBottom.png create mode 100644 UIpack/PNGs/dropdownMid.png create mode 100644 UIpack/PNGs/dropdownTop.png diff --git a/UIpack/PNGs/dropdownBottom.png b/UIpack/PNGs/dropdownBottom.png new file mode 100644 index 0000000000000000000000000000000000000000..e3d692a52e40db57ec4ce42d07d218f8826c5812 GIT binary patch literal 1164 zcmeAS@N?(olHy`uVBq!ia0vp^`+!)2gAGW!7`o>HDajJoh?3y^w370~qErUQl>DSr z1<%~X^wgl##FWaylc_cg49tp|ArU1JzCKpT`MG+DAT@dwxdlMo3=B5*6$OdO*{LN8 zNvY|XdA3ULckfqH$V{%1*XSQL?vFu&J;D8jzb> zlBiITo0C^;Rbi_HHrEQs1_|pcDS(xfWZNo192Makpx~Tel&WB=XR4cQU}UIZZmDNz zYGP?h+i#(Mch>H3D2mX`VkM*2oZxQ#zd*s+SwSN_GcP5- zyjT;g+}GF2Gq1QLF)umQ)5TT^XnMv>2~2MaLa!lCy`YqkTL84#CABECEH%ZgC_h&L>|?7;oNjS( z#c3W?ZwgMgxVYies}FRHJ}6$1;u$6cOgtbaJkkpD*rBKQCbBD* z&WhP5f8y`P>Kcxy=aTE+S4aBX-p1B(HvK-Q@s>~oF0Qk$9W(tiJLi)Pzxe4*2AW`jrInoZ6JjH$JxrUWW_;fG@}cv$x9M)t@$Fu< z>dV!Hxy9D|cb?9aao_i&BPdX0S*DcjJK^lNhx4s0Pj>HG=Q}OchbwTxw52b%zp&1{ z_v&Q*&+~PbMp`a!9xb+ic|P~UE{h+}Pt^!WX8u}mv3ofKGsCeq+oN%_`GY~_gQu&X J%Q~loCIHpNkYNA- literal 0 HcmV?d00001 diff --git a/UIpack/PNGs/dropdownMid.png b/UIpack/PNGs/dropdownMid.png new file mode 100644 index 0000000000000000000000000000000000000000..2424f7ef9b6fcd729c1095fedefcbe9823315f2f GIT binary patch literal 995 zcmaJ=O>5LZ7!IwVmbRcL6@)RpsJNL-_R9>7?RK-}0>{!8MS~JCo;m-p_foFh4ssa%n^mgt5w; zUghg6{$4mU#J`_vUsS$aWTghH(Nz|i0TBu|T_K?2nroy=OndX*M=~i0!&jVogEfrX z*rKjvCKxGpea;qy$*I^ktrlTmg{(QACjQ=gEds~Z#Ko*38-9^Aow==m)VAj9)>g|> zZE@-rn2a$Oa0xR(?5=wujy18Zi@BW~LlLwgtfh&apc=*kDAIs{tdvbzvVuTfl~6XL zB6I^NGD<@vLq$y?gfn@Ja-jQ&+*@F;;;LTm`r>-NzhtCEv=|0x{SH+=%DB%~XG#T&Oek+|}4F(4+RL7md|UKJObl+mzBeNZfd ztBa0j(wh8qU1cp)=Ai&S(?H_!zCW;aqSasb|5#I1lQ-DbrLxDiCqq;3)&fDXK*aaK)o*49vn-0AQ$prVA9vW z`rJF>!;_f(spXsg+!K!vd%&j}o?p7oZ$zV_7wYlXql0JX1TcE)&Gh2o((d!^cgz0% z(PQ}iM>(3+@BI3_zrFYJ$>I37xzmT>^6o=6jXT!xL7`*qjJGZRYiIn=-Jwz8!`ri| T_wLi5$+fGL=Jgjd%MXqLH$6IF literal 0 HcmV?d00001 diff --git a/UIpack/PNGs/dropdownTop.png b/UIpack/PNGs/dropdownTop.png new file mode 100644 index 0000000000000000000000000000000000000000..775ea7892a8460922e631b231cf50c6a35dd02c9 GIT binary patch literal 1261 zcmeAS@N?(olHy`uVBq!ia0vp^`+!)2gAGW!7`o>HDajJoh?3y^w370~qErUQl>DSr z1<%~X^wgl##FWaylc_cg49tp|ArU1JzCKpT`MG+DAT@dwxdlMo3=B5*6$OdO*{LN8 zNvY|XdA3ULckfqH$V{%1*XSQL?vFu&J;D8jzb> zlBiITo0C^;Rbi_HHrEQs1_|pcDS(xfWZNo192Makpx~Tel&WB=XR4cQU}UIZZmDNz zYGP?h+i#(Mch>H3D2mX`VkM*2oZxQ#zd*s+SwSN_GcP5- zyjT;g+}GF2Gq1QLF)umQ)5TT^XnMv>2~2MaT(6-4PQ9R%kXrz>*(J3ovn(~mttdZN0qkR|Ox$j9 z!D${;ZwgMg7`Wops}FRHJ}6$1;u$6cOgtbaJkax_)u}<;N%Ah`TP_q!U~kdwOd7;l`(j9<(HC6kE+*bu?+=B8^SU z@0I>J-`Dr=;6AZ!x7WJx-;olopSA4U>#Q~Q*V6L$-!H#-yl~C4&pY3+J04h-Sg>l< zq{wMYPkoNLWtQLgv?!Br{qb+-U*~Oq{jNvFGs2Q*R&By;%b7kZHJ2--_t|`W|5o1a z{VppbsooAb^XJ=_tv_Tx*Kdu`Ki2803=f%G_yz17eqd$Pzld&NWN31Vian`avI Date: Mon, 4 Dec 2023 08:12:36 +1100 Subject: [PATCH 76/91] =?UTF-8?q?chore(GUI):=20=F0=9F=94=A5=20Removed=20us?= =?UTF-8?q?eless=20svg=20from=20UI=20pack?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- UIpack/Vector/UIpack_vector.svg | 553 -------------------------------- 1 file changed, 553 deletions(-) delete mode 100644 UIpack/Vector/UIpack_vector.svg diff --git a/UIpack/Vector/UIpack_vector.svg b/UIpack/Vector/UIpack_vector.svg deleted file mode 100644 index 6a89dc1..0000000 --- a/UIpack/Vector/UIpack_vector.svg +++ /dev/null @@ -1,553 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file From a6f0b01402f58d3f36cd0086ed53ed0ad1028c28 Mon Sep 17 00:00:00 2001 From: Max Worrall <96847801+Tsunami014@users.noreply.github.com> Date: Mon, 4 Dec 2023 08:24:17 +1100 Subject: [PATCH 77/91] =?UTF-8?q?feat(GUI):=20=E2=9C=A8=20I=20hope=20this?= =?UTF-8?q?=20works...=20Made=20a=20consts=20file=20so=20you=20can=20easil?= =?UTF-8?q?y=20select=20a=20UI=20element=20to=20use?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- UIpack/GUI.py | 101 ++++++++++++++++++++++++++++++--------------- UIpack/__init__.py | 1 + UIpack/consts.py | 33 +++++++++++++++ 3 files changed, 102 insertions(+), 33 deletions(-) create mode 100644 UIpack/consts.py diff --git a/UIpack/GUI.py b/UIpack/GUI.py index 197388e..563b142 100644 --- a/UIpack/GUI.py +++ b/UIpack/GUI.py @@ -9,6 +9,8 @@ from xml.dom.minidom import parse def getAll(colour): + if colour == 'PNG': + return {i.name[:-4]: pygame.image.load(app+'PNGs/'+i.name).convert_alpha() for i in os.listdir(app+'PNGs')} p = parse(app+'Spritesheet/%sSheet.xml'%colour) sur = pygame.image.load(app+'Spritesheet/%sSheet.png'%colour).convert_alpha() #a = {i.attributes._attrs['name'].value: {j: int(i.attributes._attrs[j].value) for j in i.attributes._attrs.keys() if j != 'name'} for i in p.getElementsByTagName('SubTexture')} @@ -20,38 +22,71 @@ def getAll(colour): int(i.attributes._attrs['height'].value) )) for i in p.getElementsByTagName('SubTexture')} -def scrprint(sur, pos=(0, 0), cl=True): - pygame.event.pump() - if cl: WIN.fill((255, 255, 255)) - WIN.blit(sur, pos) - pygame.display.update() -def allscrprint(l): - WIN.fill((255, 255, 255)) - pos = [0, 0] - spacingy = 0 - for i in l: - spacingy = max(spacingy, i.get_height()) - if pos[0] + i.get_width() > WIN.get_width(): - pos[0] = 0 - pos[1] += spacingy + 10 - spacingy = 0 - scrprint(i, pos, False) - pos[0] += i.get_width() + 10 - -show = lambda col: allscrprint(getAll(col).values()) - -from random import shuffle - -def colours(): - l = ['blue', 'green', 'grey', 'red', 'yellow'] - shuffle(l) - while True: - for i in l: - yield i +def get_specific(name): + try: + colour = name[:name.index('_')] + except: + raise NameError( + f'The colour for the name {name} was not found!\n\ +The colour of the element should be before the first \'_\' (e.g. `grey_button01` the colour would be grey)' + ) + if colour == 'PNG': + return pygame.image.load(app+'PNGs/'+name[4:]).convert_alpha() + p = parse(app+'Spritesheet/%sSheet.xml'%colour) + sur = pygame.image.load(app+'Spritesheet/%sSheet.png'%colour).convert_alpha() + elms = p.getElementsByTagName('SubTexture') + i = None + for j in elms: + if j.attributes._attrs['name'] == name: + i = j + break + if i == None: + raise NameError( + f'The name "{name}" was not found in the coloursheet "{colour}"!' + ) + return sur.subsurface(pygame.Rect( + int(i.attributes._attrs['x'].value), + int(i.attributes._attrs['y'].value), + int(i.attributes._attrs['width'].value), + int(i.attributes._attrs['height'].value) + )) -c = colours() -while True: - if pygame.event.get(pygame.QUIT): - show(next(c)) +import UIpack.consts as Cs +from json import load +def Element(elm, colour, state=None): + """Get the code for an element! -pass + Parameters + ---------- + elm : `Cs._____` (NOT `Cs.C______`) + The element to get the value of + colour : `Cs.C_____` + The colour of the element + Please note also that some elements are just one colour, so this value will be ignored. But not all, so still include it anyways + state : tuple, optional + This is only for buttons, by default None + For a button you need to specify the following in the tuple in this order: + - The size of the button (`Cs.S_____`) + - Whether the button is pressed ('D' for Down) or not pressed ('U' for Up) + PLEASE NOTE THAT OUTLINE BUTTONS HAVE NO DOWN STATE SO DO NOT ATTEMPT TO GET THEIR DOWN STATE + Returns + ------- + str + The code for an element. To get the pic, use `get_specific(result)` + """ + if elm == Cs.HEMPTY: + return 'grey_box' + elif elm == Cs.OINPUT: + return 'grey_button05' + elif elm == Cs.RBLANK: + return 'grey_circle' + elif elm.startswith('A'): # Arrow + return 'grey_arrow'+elm[1:] + elif elm.startswith('D'): # Dropdown + 'PNG_dropdown'+elm[1:] + else: + j = load(open(app+'Spritesheet/key.json')) + if elm.startswith('B'): # Button + return colour + '_' + 'button' + j[colour[1:]]['B'][elm[1]+state[0][1]+state[1]] + else: + return colour + '_' + j[colour[1:]][elm[0]][elm[1]] diff --git a/UIpack/__init__.py b/UIpack/__init__.py index 9a9faa0..69e77f7 100644 --- a/UIpack/__init__.py +++ b/UIpack/__init__.py @@ -1 +1,2 @@ from UIpack.GUI import * +from UIpack.consts import * diff --git a/UIpack/consts.py b/UIpack/consts.py new file mode 100644 index 0000000..63ad990 --- /dev/null +++ b/UIpack/consts.py @@ -0,0 +1,33 @@ +# Colours +CBLUE = 'Cblue' +CGREEN = 'Cgreen' +CGREY = 'Cgrey' +CRED = 'Cred' +CYELLOW = 'Cyellow' +# Buttons +BRAISED = 'BRAISED' +BFLAT = 'BFLAT' +BGRAD = 'BGRADIENT' +BOUTLINE = 'BOUTLINE' +# Size +SSMALL = 'SSMALL' +SLONG = 'SLONG' +# cHeckbox +HEMPTY = 'HEMPTY' +HTICK = 'HTICK' +HCROSS = 'HCROSS' +# Radiobutton +RBLANK = 'RBLANK' +RSELECTED = 'RSELECTED' +# Dropdown +DBOT = 'DBottom' +DMID = 'DMid' +DTOP = 'DTop' +# Arrows +AGU = 'AUpGrey' +AWU = 'AUpWhite' +AGD = 'ADownGrey' +AWD = 'ADownWhite' +# Other +OPANEL = 'OPANEL' +OINPUT = 'OINPUT' From e2b71d42f4aa5ec6f923cb0e087b2c27b980b4a9 Mon Sep 17 00:00:00 2001 From: Max Worrall <96847801+Tsunami014@users.noreply.github.com> Date: Mon, 4 Dec 2023 08:35:42 +1100 Subject: [PATCH 78/91] =?UTF-8?q?feat(build):=20=E2=9C=A8=20Added=20the=20?= =?UTF-8?q?key.json=20that=20wasn't=20added=20due=20to=20silly=20.gitignor?= =?UTF-8?q?e=20issue?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit whoops --- .gitignore | 2 +- UIpack/Spritesheet/key.json | 142 ++++++++++++++++++++++++++++++++++++ 2 files changed, 143 insertions(+), 1 deletion(-) create mode 100644 UIpack/Spritesheet/key.json diff --git a/.gitignore b/.gitignore index 1b601b4..b44088d 100644 --- a/.gitignore +++ b/.gitignore @@ -3,4 +3,4 @@ keys/apiKeys.key *.bin *.db *.ldtk -*.json +data/worlds/*/* diff --git a/UIpack/Spritesheet/key.json b/UIpack/Spritesheet/key.json new file mode 100644 index 0000000..b681ab3 --- /dev/null +++ b/UIpack/Spritesheet/key.json @@ -0,0 +1,142 @@ +{ + "blue": { + "B": { + "RLU": "00", + "RLD": "01", + "FLU": "02", + "FLD": "03", + "GLU": "04", + "GLD": "05", + "OLU": "13", + "OSU": "06", + "RSU": "07", + "RSD": "08", + "FSU": "09", + "FSD": "10", + "GSU": "11", + "GSD": "12" + }, + "H": { + "T": "boxCheckmark", + "C": "boxCross" + }, + "R": { + "S": "boxTick" + }, + "O": { + "P": "panel" + } + }, + "green": { + "B": { + "RLU": "00", + "RLD": "01", + "FLU": "02", + "FLD": "03", + "GLU": "04", + "GLD": "05", + "OLU": "13", + "OSU": "06", + "RSU": "07", + "RSD": "08", + "FSU": "09", + "FSD": "10", + "GSU": "11", + "GSD": "12" + }, + "H": { + "T": "boxCheckmark", + "C": "boxCross" + }, + "R": { + "S": "boxTick" + }, + "O": { + "P": "panel" + } + }, + "grey": { + "B": { + "RLU": "00", + "RLD": "00", + "FLU": "01", + "FLD": "02", + "GLU": "03", + "GLD": "04", + "OLU": "06", + "OSU": "07", + "RSU": "08", + "RSD": "09", + "FSU": "10", + "FSD": "11", + "GSU": "12", + "GSD": "13" + }, + "H": { + "T": "boxCheckmark", + "C": "boxCross" + }, + "R": { + "S": "boxTick" + }, + "O": { + "P": "panel" + } + }, + "red": { + "B": { + "RLU": "00", + "RLD": "01", + "FLU": "02", + "FLD": "03", + "GLU": "04", + "GLD": "05", + "OLU": "13", + "OSU": "06", + "RSU": "07", + "RSD": "08", + "FSU": "09", + "FSD": "10", + "GSU": "11", + "GSD": "12" + }, + "H": { + "T": "boxCheckmark", + "C": "boxCross" + }, + "R": { + "S": "boxTick" + }, + "O": { + "P": "panel" + } + }, + "yellow": { + "B": { + "RLU": "00", + "RLD": "01", + "FLU": "02", + "FLD": "03", + "GLU": "04", + "GLD": "05", + "OLU": "13", + "OSU": "06", + "RSU": "07", + "RSD": "08", + "FSU": "09", + "FSD": "10", + "GSU": "11", + "GSD": "12" + }, + "H": { + "T": "boxCheckmark", + "C": "boxCross" + }, + "R": { + "S": "boxTick" + }, + "O": { + "P": "panel" + } + } +} \ No newline at end of file From aaa22e35e3df7c2ccdcfba74b1c0f55165c3dc38 Mon Sep 17 00:00:00 2001 From: Max Worrall <96847801+Tsunami014@users.noreply.github.com> Date: Tue, 5 Dec 2023 07:55:29 +1100 Subject: [PATCH 79/91] =?UTF-8?q?feat(nodes):=20=E2=9C=A8=20Added=20the=20?= =?UTF-8?q?ability=20for=20nodes'=20outputs=20to=20be=20shown!?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Added a node for the number 1 and 2 and made it so if you connect these to out it shows the result! --- data/nodes/test.py | 10 +++++++++- elementGen/node_editor.py | 11 ++++++++++- elementGen/node_parser.py | 18 ++++++++++++++++++ 3 files changed, 37 insertions(+), 2 deletions(-) diff --git a/data/nodes/test.py b/data/nodes/test.py index e420639..f4f535b 100644 --- a/data/nodes/test.py +++ b/data/nodes/test.py @@ -1,4 +1,12 @@ # Add int@A int@B | int@Out # def node(A, B): - return A + B + return {'Out': A + B} + +# One | int@1 # +def node(): + return {'1': 1} + +# Two | int@2 # +def node(): + return {'2': 2} diff --git a/elementGen/node_editor.py b/elementGen/node_editor.py index e4a5aa0..ba8f856 100644 --- a/elementGen/node_editor.py +++ b/elementGen/node_editor.py @@ -170,11 +170,17 @@ def parse(i, l, lf, rd): for j in range(len(G.Container.connections)): k = [_ for _ in G.Container.connections[j] if _.isinp][0] if i == k or G.Container.selecting[0] == k: + G.Container.connections[j][0].connectedto = None + G.Container.connections[j][1].connectedto = None G.Container.connections[j] = [G.Container.selecting[0], i] + G.Container.selecting[0].connectedto = i + i.connectedto = G.Container.selecting[0] d = True break if not d: G.Container.connections.append([G.Container.selecting[0], i]) + G.Container.selecting[0].connectedto = i + i.connectedto = G.Container.selecting[0] elif G.Container.selecting == None or (isinstance(G.Container.selecting, tuple) and i.isntsimilar(G.Container.selecting[0])): if i.rect.collidepoint(pygame.mouse.get_pos()): rd.append((i.rect.topleft[0]+5, i.rect.topleft[1]+7)) @@ -249,6 +255,7 @@ def settings(event, element=None, aborted=False): rd = [] for p, node in G.Container.nodes: + g = node.get() node.cirs.reset() col = GO.CBLUE txt = GO.FFONT.render(str(node), 2, GO.CBLACK) @@ -271,7 +278,9 @@ def settings(event, element=None, aborted=False): i2 = start mx2 = 0 for n in node.outputs: - s, c = CAT(n.name, front=False, bgcol=col) + name = n.name + if n.name in g: name = str(g[n.name]) + s, c = CAT(name, front=False, bgcol=col) c.move_ip(mx+p[0], i2+p[1]) node.cirs[n] = c sur.blit(s, (mx, i2)) diff --git a/elementGen/node_parser.py b/elementGen/node_parser.py index 7e9ad9a..a06bc7c 100644 --- a/elementGen/node_parser.py +++ b/elementGen/node_parser.py @@ -27,6 +27,7 @@ def __init__(self, parent, isinp, name, typ): self.name = name self.type = typ self.rect = None + self.connectedto = None # Relying on externs to generate def isntsimilar(self, other): try: return self.parent != other.parent and self.isinp != other.isinp @@ -54,6 +55,7 @@ def __init__(self, data): self.inputs = [] self.outputs = [] self.cirs = FakeDict(self.setter, self.setter) # Relying on externals to generate + self.func = None # Also relying on externals to generate, tho this time the 'externals' is the Parse class input = True for i in spl[1:]: if i == '|': @@ -89,6 +91,21 @@ def copy(self): oos.append(i.copy()) c.outputs = oos""" return c + def get(self): + ins = [] + for i in self.inputs: + try: + ins.append(i.connectedto.parent.get()[i.connectedto.name]) + except: + pass + try: + return self(*ins) + except: + return {} + def __call__(self, *args): + exec(self.func) + return eval('node(*args)') + def __str__(self): try: return self.name @@ -116,6 +133,7 @@ def __init__(self, category): self.names[str(i)] = i else: self.data[pattern] = i + pattern.func = i pattern = 0 def __call__(self, funcname, *args): exec(self.data[self.names[funcname]]) From 931dceee58bd2181411097868ed84bc3eac969b4 Mon Sep 17 00:00:00 2001 From: Max Worrall <96847801+Tsunami014@users.noreply.github.com> Date: Tue, 5 Dec 2023 07:57:06 +1100 Subject: [PATCH 80/91] todo: rebase --- data/nodes/test.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/data/nodes/test.py b/data/nodes/test.py index f4f535b..4e59880 100644 --- a/data/nodes/test.py +++ b/data/nodes/test.py @@ -1,7 +1,8 @@ # Add int@A int@B | int@Out # def node(A, B): - return {'Out': A + B} + return {'Out': A + B} # How this works is the dict is the outputs' names to replace by a new value + # So in this case the output with the name 'Out' gets shown as A + B instead of it's original 'Out' value if this doesn't fail # One | int@1 # def node(): From 329d03deee2db06e4c6c558fd1e1306e45fbfb51 Mon Sep 17 00:00:00 2001 From: Max Worrall <96847801+Tsunami014@users.noreply.github.com> Date: Tue, 5 Dec 2023 09:08:31 +1100 Subject: [PATCH 81/91] =?UTF-8?q?fix(nodes):=20=F0=9F=90=9B=20Bugfix=20of?= =?UTF-8?q?=20test.py=20node=20parsing=20and=20comment=20issues?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- data/nodes/test.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/data/nodes/test.py b/data/nodes/test.py index 4e59880..660a2a1 100644 --- a/data/nodes/test.py +++ b/data/nodes/test.py @@ -1,8 +1,12 @@ # Add int@A int@B | int@Out # def node(A, B): - return {'Out': A + B} # How this works is the dict is the outputs' names to replace by a new value - # So in this case the output with the name 'Out' gets shown as A + B instead of it's original 'Out' value if this doesn't fail + return {'Out': A + B} +''' +How this works is the dict is the outputs' names to replace by a new value +So in this case the output with the name 'Out' gets shown as A + B instead +of it's original 'Out' value if this doesn't error and has all things connected +''' # One | int@1 # def node(): From d1eb1b67bf8594ae0f1741dc8f5ef101b9e61873 Mon Sep 17 00:00:00 2001 From: Max Worrall <96847801+Tsunami014@users.noreply.github.com> Date: Tue, 5 Dec 2023 15:53:32 +1100 Subject: [PATCH 82/91] =?UTF-8?q?feat(nodes):=20=E2=9C=A8=20Added=20abilit?= =?UTF-8?q?y=20to=20select=20nodes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- elementGen/node_editor.py | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/elementGen/node_editor.py b/elementGen/node_editor.py index ba8f856..ce0b6c1 100644 --- a/elementGen/node_editor.py +++ b/elementGen/node_editor.py @@ -165,6 +165,7 @@ def dropdown(): def parse(i, l, lf, rd): if not l and isinstance(G.Container.selecting, tuple) and i.isntsimilar(G.Container.selecting[0]): + G.Container.highlighting = None if i.rect.collidepoint(pygame.mouse.get_pos()): d = False for j in range(len(G.Container.connections)): @@ -181,11 +182,15 @@ def parse(i, l, lf, rd): G.Container.connections.append([G.Container.selecting[0], i]) G.Container.selecting[0].connectedto = i i.connectedto = G.Container.selecting[0] + elif not l and isinstance(G.Container.selecting, list) and G.Container.selecting[2] == pygame.mouse.get_pos(): + # did not move, so select + G.Container.highlighting = G.Container.selecting[3] elif G.Container.selecting == None or (isinstance(G.Container.selecting, tuple) and i.isntsimilar(G.Container.selecting[0])): if i.rect.collidepoint(pygame.mouse.get_pos()): rd.append((i.rect.topleft[0]+5, i.rect.topleft[1]+7)) if lf: G.Container.selecting = (i, (i.rect.center[0]+5, i.rect.center[1]+7)) + G.Container.highlighting = None return rd @G.Graphic @@ -197,6 +202,7 @@ def editor(event, path, element=None, aborted=False): mouseDown(3) # Right mouse button ] G.Container.selecting = None + G.Container.highlighting = None if path.endswith('.elm'): path = path[:-4] if not os.path.exists('data/elements/'+path+'.elm'): @@ -215,7 +221,7 @@ def editor(event, path, element=None, aborted=False): G.Container.name = G.Container.contents['name'] if event == GO.ELOADUI: G.Clear() - G.add_text('EDITING ELEMENT "%s"'%G.Container.name, GO.CGREEN, GO.PCTOP, GO.FTITLE) + G.add_text('%s'%G.Container.name, GO.CGREEN, GO.PCTOP, GO.FTITLE) G.add_button('Settings', GO.CGREEN, GO.PRTOP) elif event == GO.EELEMENTCLICK: # This is going to be the only button that was created @G.Graphic @@ -293,8 +299,11 @@ def settings(event, element=None, aborted=False): sur2.blit(sur, (0, 0)) r = pygame.Rect(*p, mx2+10, max(i, i2)+10) pygame.draw.rect(G.WIN, col, r, border_radius=8) + if G.Container.highlighting == node: + pygame.draw.rect(G.WIN, GO.CACTIVE, pygame.Rect(p[0]-15, p[1]-15, mx2+40, max(i, i2)+40), width=10, border_radius=8) if G.Container.selecting == None and lf and r.collidepoint(pygame.mouse.get_pos()): - G.Container.selecting = [G.Container.nodes.index((p, node)), (pygame.mouse.get_pos()[0]-p[0], pygame.mouse.get_pos()[1]-p[1])] + G.Container.highlighting = None + G.Container.selecting = [G.Container.nodes.index((p, node)), (pygame.mouse.get_pos()[0]-p[0], pygame.mouse.get_pos()[1]-p[1]), pygame.mouse.get_pos(), node] G.WIN.blit(sur2, (p[0]+5, p[1]+5)) for i in rd: G.WIN.blit(CAT('', filled=True, bgcol=col)[0], i) @@ -316,6 +325,9 @@ def settings(event, element=None, aborted=False): (i[1].rect.center[0]+5, i[1].rect.center[1]+7), 10) return True elif event == GO.EEVENT: # When something like a button is pressed. Is passed 'element' too, but this time it is an event + if element.type == pygame.MOUSEBUTTONDOWN: + G.Container.highlighting = None + if element.type == pygame.KEYDOWN: if element.key == pygame.K_s and element.mod & pygame.KMOD_CTRL: if path.endswith('.elm'): From ec94ed19d6b8c094d4b9a40ba6364287234cc8a0 Mon Sep 17 00:00:00 2001 From: Max Worrall <96847801+Tsunami014@users.noreply.github.com> Date: Tue, 5 Dec 2023 16:04:29 +1100 Subject: [PATCH 83/91] =?UTF-8?q?feat(nodes):=20=E2=9C=A8=20Added=20a=20li?= =?UTF-8?q?ttle=20popup=20down=20the=20bottom-left=20corner=20of=20the=20s?= =?UTF-8?q?creen=20whenever=20you=20select=20something?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- elementGen/node_editor.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/elementGen/node_editor.py b/elementGen/node_editor.py index ce0b6c1..a2979e2 100644 --- a/elementGen/node_editor.py +++ b/elementGen/node_editor.py @@ -323,6 +323,14 @@ def settings(event, element=None, aborted=False): pygame.draw.line(G.WIN, GO.CNEW('orange'), \ (i[0].rect.center[0]+5, i[0].rect.center[1]+7), \ (i[1].rect.center[0]+5, i[1].rect.center[1]+7), 10) + + if G.Container.highlighting != None: + w, h = G.size[0] / 8 * 3, G.size[1] / 8 * 3 + pygame.draw.rect(G.WIN, GO.CNEW('light grey'), pygame.Rect(8, G.size[1]-h-8, w, h), border_radius=8) + node = G.Container.highlighting + txt = GO.FFONT.render(str(node), 2, GO.CBLACK) + G.WIN.blit(txt, ((w - txt.get_width())/2+8, G.size[1]-h+10)) + return True elif event == GO.EEVENT: # When something like a button is pressed. Is passed 'element' too, but this time it is an event if element.type == pygame.MOUSEBUTTONDOWN: From bb263800e9b7919ce0415dff5d33b0c60dfee229 Mon Sep 17 00:00:00 2001 From: Max Worrall <96847801+Tsunami014@users.noreply.github.com> Date: Wed, 6 Dec 2023 16:20:00 +1100 Subject: [PATCH 84/91] Leftover merge changes I forgot to stage --- demos.py | 27 ++++++++++++++++++++++++++- graphics/GUI/scrollable.py | 14 -------------- 2 files changed, 26 insertions(+), 15 deletions(-) diff --git a/demos.py b/demos.py index 0a63026..458ad61 100644 --- a/demos.py +++ b/demos.py @@ -43,6 +43,12 @@ def test(event, txt, element=None, aborted=False): # You do not need args and kw G.add_switch(GO.PRTOP, 40), G.add_switch(GO.PRTOP) ] + G.Container.scrollable, S = G.add_Scrollable(GO.PLTOP, (250, 200), (250, 350)) + S.add_button('Scroll me!', GO.CBLUE, GO.PCTOP) + S.add_button('Hello!', GO.CYELLOW, GO.PCTOP) + S.add_button('Bye!', GO.CGREEN, GO.PCTOP) + S.add_button('Hello again!', GO.CRED, GO.PCTOP) + G.Container.otherswitch = S.add_switch(GO.PCTOP) elif event == GO.ETICK: # This runs every 1/60 secs (each tick) return True # Return whether or not the loop should continue. elif event == GO.EELEMENTCLICK: # Some UI element got clicked! @@ -93,7 +99,8 @@ def test(event, txt, element=None, aborted=False): # You do not need args and kw 'Text in textbox': G.uids[G.Container.inp].get(), 'Num in num textbox': G.uids[G.Container.numinp].get(), 'Big switch state': G.uids[G.Container.switches[0]].get(), - 'Small switch state': G.uids[G.Container.switches[1]].get() + 'Small switch state': G.uids[G.Container.switches[1]].get(), + 'Switch in scrollable area state': G.uids[G.Container.scrollable].G.uids[G.Container.otherswitch].get() } # Whatever you return here will be returned by the function print(test('Right click! ' + t)) @@ -385,6 +392,23 @@ def __(event): print("You canceled the MessageBox instance.") run = False +def scrollableDemo(): + import pygame + from graphics.GUI import Scrollable + pygame.init() + w = pygame.display.set_mode() + from tkinter.filedialog import askopenfilename + S = Scrollable(pygame.image.load(askopenfilename(defaultextension='.png', filetypes=[('.png', '.png'), ('.jpg', '.jpg')])), (0, 0), (100, 100)) + while True: + for event in pygame.event.get(): + if event.type == pygame.QUIT: + quit() + elif event.type == pygame.MOUSEWHEEL: + S.update(event) + w.fill((0, 0, 0)) + S(w) + pygame.display.update() + if __name__ == '__main__': root = Tk.Tk() @@ -395,6 +419,7 @@ def cmd(cmdd): Tk.Button(root, text='Node Parser Demo', command=lambda: cmd(node_parserDemo) ).pack() Tk.Button(root, text='Loading Demo', command=lambda: cmd(LoadingDemo) ).pack() Tk.Button(root, text='Graphics Demo', command=lambda: cmd(GraphicsDemo) ).pack() + Tk.Button(root, text='Scrollable Demo', command=lambda: cmd(scrollableDemo) ).pack() Tk.Button(root, text='Other Graphics Demo', command=lambda: cmd(almostallgraphicsDemo) ).pack() Tk.Button(root, text='Generate World Demo', command=lambda: cmd(worldsDemo) ).pack() Tk.Button(root, text='Generate Terrain Demo', command=lambda: cmd(terrainGenDemo) ).pack() diff --git a/graphics/GUI/scrollable.py b/graphics/GUI/scrollable.py index cda2541..d8ee91b 100644 --- a/graphics/GUI/scrollable.py +++ b/graphics/GUI/scrollable.py @@ -17,17 +17,3 @@ def __call__(self, WIN): s = pygame.Surface(self.goalrect) s.blit(self.sur, (0, self.scroll)) WIN.blit(s, self.pos) - -if __name__ == '__main__': - pygame.init() - w = pygame.display.set_mode() - from tkinter.filedialog import askopenfilename - S = Scrollable(pygame.image.load(askopenfilename(defaultextension='.png', filetypes=[('.png', '.png'), ('.jpg', '.jpg')])), (0, 0), (100, 100)) - while True: - for event in pygame.event.get(): - if event.type == pygame.QUIT: - quit() - S.update(event) - w.fill((0, 0, 0)) - S(w) - pygame.display.update() From b725bd235bd4d68537bc7161e47e5b3847485cc5 Mon Sep 17 00:00:00 2001 From: Max Worrall <96847801+Tsunami014@users.noreply.github.com> Date: Wed, 6 Dec 2023 16:24:49 +1100 Subject: [PATCH 85/91] =?UTF-8?q?feat(main):=20=F0=9F=8E=A8=20Made=20the?= =?UTF-8?q?=20demo=20screen=20look=20MUCH=20better=20:)=20Added=20labels?= =?UTF-8?q?=20to=20categorise=20it=20and=20stuff=20:)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- demos.py | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/demos.py b/demos.py index 458ad61..986c46e 100644 --- a/demos.py +++ b/demos.py @@ -415,19 +415,28 @@ def scrollableDemo(): def cmd(cmdd): root.destroy() cmdd() + Tk.Label (root, text='Node stuff:' ).pack() Tk.Button(root, text='Node Editor Demo', command=lambda: cmd(node_editorDemo) ).pack() Tk.Button(root, text='Node Parser Demo', command=lambda: cmd(node_parserDemo) ).pack() - Tk.Button(root, text='Loading Demo', command=lambda: cmd(LoadingDemo) ).pack() + Tk.Label (root, text='Graphics stuff:' ).pack() Tk.Button(root, text='Graphics Demo', command=lambda: cmd(GraphicsDemo) ).pack() + Tk.Button(root, text='Loading Demo', command=lambda: cmd(LoadingDemo) ).pack() + Tk.Button(root, text='Switch Demo', command=lambda: cmd(switchDemo) ).pack() + Tk.Button(root, text='Input Box Demo', command=lambda: cmd(inputBoxDemo) ).pack() Tk.Button(root, text='Scrollable Demo', command=lambda: cmd(scrollableDemo) ).pack() Tk.Button(root, text='Other Graphics Demo', command=lambda: cmd(almostallgraphicsDemo) ).pack() + Tk.Label (root, text='Generation stuff:' ).pack() Tk.Button(root, text='Generate World Demo', command=lambda: cmd(worldsDemo) ).pack() Tk.Button(root, text='Generate Terrain Demo', command=lambda: cmd(terrainGenDemo) ).pack() - Tk.Button(root, text='Input Box Demo', command=lambda: cmd(inputBoxDemo) ).pack() + Tk.Label (root, text='AI stuff:' ).pack() Tk.Button(root, text='TinyLLM Demo', command=lambda: cmd(tinyLLMDemo) ).pack() Tk.Button(root, text='Test LLM Demo', command=lambda: cmd(testLLMDemo) ).pack() Tk.Button(root, text='Rate AIs Demo', command=lambda: cmd(rateAIsDemo) ).pack() + Tk.Label (root, text='Other stuff:' ).pack() Tk.Button(root, text='API Keys Demo', command=lambda: cmd(api_keysDemo) ).pack() - Tk.Button(root, text='Switch Demo', command=lambda: cmd(switchDemo) ).pack() Tk.Button(root, text='Conversation Parse Demo', command=lambda: cmd(conversation_parserDemo)).pack() + def btt(): + root.attributes('-topmost', True) + root.attributes('-topmost', False) + root.after(1, btt) root.mainloop() From 34a4a0b80fcf7c3bbc58f40213a253b056f24307 Mon Sep 17 00:00:00 2001 From: Max Worrall <96847801+Tsunami014@users.noreply.github.com> Date: Wed, 6 Dec 2023 20:15:52 +1100 Subject: [PATCH 86/91] test blank commit for this branch From 07e049905147bd4d3b576be3ee0ee47180f04e6f Mon Sep 17 00:00:00 2001 From: Max Worrall <96847801+Tsunami014@users.noreply.github.com> Date: Thu, 7 Dec 2023 08:37:13 +1100 Subject: [PATCH 87/91] =?UTF-8?q?feat(nodes):=20=E2=9C=A8=20Added=20a=20bl?= =?UTF-8?q?ank=20scroll=20area=20to=20the=20little=20popup=20in=20the=20bo?= =?UTF-8?q?ttom=20left=20corner=20of=20the=20nodes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- elementGen/node_editor.py | 24 ++++++++++++++++++------ graphics/graphics.py | 3 ++- 2 files changed, 20 insertions(+), 7 deletions(-) diff --git a/elementGen/node_editor.py b/elementGen/node_editor.py index d38af85..3ff0689 100644 --- a/elementGen/node_editor.py +++ b/elementGen/node_editor.py @@ -165,7 +165,7 @@ def dropdown(): def parse(i, l, lf, rd): if not l and isinstance(G.Container.selecting, tuple) and i.isntsimilar(G.Container.selecting[0]): - G.Container.highlighting = None + if not G.Container.DONTDOIT: G.Container.highlighting = None if i.rect.collidepoint(pygame.mouse.get_pos()): d = False for j in range(len(G.Container.connections)): @@ -190,7 +190,7 @@ def parse(i, l, lf, rd): rd.append((i.rect.topleft[0]+5, i.rect.topleft[1]+7)) if lf: G.Container.selecting = (i, (i.rect.center[0]+5, i.rect.center[1]+7)) - G.Container.highlighting = None + if not G.Container.DONTDOIT: G.Container.highlighting = None return rd @G.Graphic @@ -203,6 +203,7 @@ def editor(event, path, element=None, aborted=False): ] G.Container.selecting = None G.Container.highlighting = None + G.Container.DONTDOIT = False if path.endswith('.elm'): path = path[:-4] if not os.path.exists('data/elements/'+path+'.elm'): @@ -259,6 +260,10 @@ def settings(event, element=None, aborted=False): rf, r = next(G.Container.md[1]) # Same with r + w, h = G.size[0] / 8 * 3, G.size[1] / 8 * 3 + rec = pygame.Rect(8, G.size[1]-h-8, w, h) + G.Container.DONTDOIT = rec.collidepoint(*pygame.mouse.get_pos()) + rd = [] for p, node in G.Container.nodes: g = node.get() @@ -302,7 +307,7 @@ def settings(event, element=None, aborted=False): if G.Container.highlighting == node: pygame.draw.rect(G.WIN, GO.CACTIVE, pygame.Rect(p[0]-15, p[1]-15, mx2+40, max(i, i2)+40), width=10, border_radius=8) if G.Container.selecting == None and lf and r.collidepoint(pygame.mouse.get_pos()): - G.Container.highlighting = None + if not G.Container.DONTDOIT: G.Container.highlighting = None G.Container.selecting = [G.Container.nodes.index((p, node)), (pygame.mouse.get_pos()[0]-p[0], pygame.mouse.get_pos()[1]-p[1]), pygame.mouse.get_pos(), node] G.WIN.blit(sur2, (p[0]+5, p[1]+5)) for i in rd: @@ -326,15 +331,22 @@ def settings(event, element=None, aborted=False): if G.Container.highlighting != None: w, h = G.size[0] / 8 * 3, G.size[1] / 8 * 3 - pygame.draw.rect(G.WIN, GO.CNEW('light grey'), pygame.Rect(8, G.size[1]-h-8, w, h), border_radius=8) + pygame.draw.rect(G.WIN, GO.CNEW('light grey'), rec, border_radius=8) node = G.Container.highlighting txt = GO.FFONT.render(str(node), 2, GO.CBLACK) G.WIN.blit(txt, ((w - txt.get_width())/2+8, G.size[1]-h+10)) - + if G.scrollsables == []: + pos = GO.PSTATIC(12, G.size[1]-h+10+txt.get_height()+2) + size = 60 # TODO: CHANGE + size = max(size, h-(txt.get_height()+30)+1) + _, scr = G.add_Scrollable(pos, (w-8, h-(txt.get_height()+30)), (w-8, size), 2, True) + scr.bgcol = GO.CNEW('light grey') + elif G.scrollsables != []: + G.Reload() return True elif event == GO.EEVENT: # When something like a button is pressed. Is passed 'element' too, but this time it is an event if element.type == pygame.MOUSEBUTTONDOWN: - G.Container.highlighting = None + if not G.Container.DONTDOIT: G.Container.highlighting = None if element.type == pygame.KEYDOWN: if element.key == pygame.K_s and element.mod & pygame.KMOD_CTRL: diff --git a/graphics/graphics.py b/graphics/graphics.py index 34bf356..1df6146 100644 --- a/graphics/graphics.py +++ b/graphics/graphics.py @@ -339,7 +339,8 @@ def func(event, element=None, aborted=False): for i in self.touchingbtns: r = func(GO.EELEMENTCLICK, Element(GO.TBUTTON, self.uids.index(i[0]), self, btn=i)) if r != None: - return r + self.run = False + yield [r] elif event.type == pygame.MOUSEWHEEL and not self.pause: for i in self.scrollsables: i.update(event) if not self.pause and not blocked: func(GO.EEVENT, event) From 9ec02014286c2270f659a475a52a02ebc486397c Mon Sep 17 00:00:00 2001 From: Max Worrall <96847801+Tsunami014@users.noreply.github.com> Date: Fri, 8 Dec 2023 08:23:23 +1100 Subject: [PATCH 88/91] =?UTF-8?q?feat(main):=20=E2=9C=A8=20Made=20the=20de?= =?UTF-8?q?mos=20in=20demos.py=20that=20used=20to=20use=20the=20terminal?= =?UTF-8?q?=20now=20use=20the=20tkinter=20window=20itself!?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Slightly buggy and untested..... --- demos.py | 101 ++++++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 77 insertions(+), 24 deletions(-) diff --git a/demos.py b/demos.py index 53d51bc..3170b62 100644 --- a/demos.py +++ b/demos.py @@ -1,5 +1,3 @@ -import tkinter as Tk # Because everyone has tkinter - def GraphicsDemo(): import pygame import graphics.graphics_options as GO @@ -412,34 +410,89 @@ def scrollableDemo(): S(w) pygame.display.update() - if __name__ == '__main__': + import tkinter as Tk # Because everyone has tkinter + from tkinter.scrolledtext import ScrolledText root = Tk.Tk() def cmd(cmdd): root.destroy() + print('loading...') cmdd() - Tk.Label (root, text='Node stuff:' ).pack() - Tk.Button(root, text='Node Editor Demo', command=lambda: cmd(node_editorDemo) ).pack() - Tk.Button(root, text='Node Parser Demo', command=lambda: cmd(node_parserDemo) ).pack() - Tk.Label (root, text='Graphics stuff:' ).pack() - Tk.Button(root, text='Graphics Demo', command=lambda: cmd(GraphicsDemo) ).pack() - Tk.Button(root, text='Loading Demo', command=lambda: cmd(LoadingDemo) ).pack() - Tk.Button(root, text='Switch Demo', command=lambda: cmd(switchDemo) ).pack() - Tk.Button(root, text='Input Box Demo', command=lambda: cmd(inputBoxDemo) ).pack() - Tk.Button(root, text='Scrollable Demo', command=lambda: cmd(scrollableDemo) ).pack() - Tk.Button(root, text='Other Graphics Demo', command=lambda: cmd(almostallgraphicsDemo) ).pack() - Tk.Label (root, text='Generation stuff:' ).pack() - Tk.Button(root, text='Generate World Demo', command=lambda: cmd(worldsDemo) ).pack() - Tk.Button(root, text='Generate Terrain Demo', command=lambda: cmd(terrainGenDemo) ).pack() - Tk.Label (root, text='AI stuff:' ).pack() - Tk.Button(root, text='TinyLLM Demo', command=lambda: cmd(tinyLLMDemo) ).pack() - Tk.Button(root, text='Test LLM Demo', command=lambda: cmd(testLLMDemo) ).pack() - Tk.Button(root, text='Rate AIs Demo', command=lambda: cmd(rateAIsDemo) ).pack() - Tk.Label (root, text='Other stuff:' ).pack() - Tk.Button(root, text='API Keys Demo', command=lambda: cmd(api_keysDemo) ).pack() - Tk.Button(root, text='Conversation Parse Demo', command=lambda: cmd(conversation_parserDemo)).pack() + def rcmd(cmdd): + root.protocol("WM_DELETE_WINDOW", load) + for widget in root.winfo_children(): + widget.destroy() + E = ScrolledText(root, + wrap = Tk.WORD, + width = 40, + height = 10, + state=Tk.DISABLED) + E.pack(fill=Tk.BOTH, side=Tk.LEFT, expand=True) + def npr(*txts, sep=' '): + E.config(state=Tk.NORMAL) + E.insert(Tk.END,sep.join([str(i) for i in txts])+'\n') + E.config(state=Tk.DISABLED) + root.update() + def ninp(prompt=''): + class blank: pass + b = blank() + b.done = False + def run(): + v = E2.get() + for widget in root.winfo_children(): + if widget != E and not E in widget.winfo_children(): widget.destroy() + b.done = True + b.res = v + Tk.Label(root, text=prompt).pack() + E2 = Tk.Entry(root) + E2.pack() + E2.bind("", lambda *args: run()) + Tk.Button(root, command=lambda *args: run(), text='GO!').pack() + root.update() + while b.done == False: root.update() + return b.res + oprint = print + globals()['print'] = npr + oinput = input + globals()['input'] = ninp + oprint('Loading please wait...') + print('Loading please wait...') + root.update() + try: + cmdd() + except Exception as e: + print('AN EXCEPTION HAS OCURRED:', type(e), e, sep='\n') + globals()['print'] = oprint + globals()['input'] = oinput + + def load(): + for widget in root.winfo_children(): + widget.destroy() + Tk.Button(root, text='EXIT', command=root.destroy).pack() + + Tk.Label (root, text='Node stuff:').pack() + Tk.Button(root, text='Node Editor Demo', command=lambda: cmd(node_editorDemo) ).pack() + Tk.Button(root, text='Node Parser Demo', command=lambda: rcmd(node_parserDemo), relief=Tk.RIDGE ).pack() + Tk.Label (root, text='Graphics stuff:').pack() + Tk.Button(root, text='Graphics Demo', command=lambda: cmd(GraphicsDemo) ).pack() + Tk.Button(root, text='Loading Demo', command=lambda: cmd(LoadingDemo) ).pack() + Tk.Button(root, text='Switch Demo', command=lambda: cmd(switchDemo) ).pack() + Tk.Button(root, text='Input Box Demo', command=lambda: cmd(inputBoxDemo) ).pack() + Tk.Button(root, text='Scrollable Demo', command=lambda: cmd(scrollableDemo) ).pack() + Tk.Button(root, text='Other Graphics Demo', command=lambda: cmd(almostallgraphicsDemo) ).pack() + Tk.Label (root, text='Generation stuff:').pack() + Tk.Button(root, text='Generate World Demo', command=lambda: rcmd(worldsDemo), relief=Tk.RIDGE ).pack() + Tk.Button(root, text='Generate Terrain Demo', command=lambda: rcmd(terrainGenDemo), relief=Tk.RIDGE ).pack() + Tk.Label (root, text='AI stuff:').pack() + Tk.Button(root, text='TinyLLM Demo', command=lambda: rcmd(tinyLLMDemo), relief=Tk.RIDGE ).pack() + Tk.Button(root, text='Test LLM Demo', command=lambda: rcmd(testLLMDemo), relief=Tk.RIDGE ).pack() + Tk.Button(root, text='Rate AIs Demo', command=lambda: rcmd(rateAIsDemo), relief=Tk.RIDGE ).pack() + Tk.Label (root, text='Other stuff:').pack() + Tk.Button(root, text='API Keys Demo', command=lambda: cmd(api_keysDemo), ).pack() + Tk.Button(root, text='Conversation Parse Demo', command=lambda: cmd(conversation_parserDemo), relief=Tk.SUNKEN ).pack() + root.protocol("WM_DELETE_WINDOW", root.destroy) + load() def btt(): root.attributes('-topmost', True) - root.attributes('-topmost', False) root.after(1, btt) root.mainloop() From ad46e9195ec14c8b4c09bea01c1fe9e8e937dd5c Mon Sep 17 00:00:00 2001 From: Max Worrall <96847801+Tsunami014@users.noreply.github.com> Date: Fri, 8 Dec 2023 15:43:30 +1100 Subject: [PATCH 89/91] =?UTF-8?q?feat(nodes):=20=F0=9F=8E=89=20Added=20typ?= =?UTF-8?q?es.py?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- elementGen/__init__.py | 1 + elementGen/types.py | 9 +++++++++ 2 files changed, 10 insertions(+) create mode 100644 elementGen/types.py diff --git a/elementGen/__init__.py b/elementGen/__init__.py index 421c4be..27ace26 100644 --- a/elementGen/__init__.py +++ b/elementGen/__init__.py @@ -1,2 +1,3 @@ from elementGen.node_editor import * from elementGen.node_parser import * +from elementGen.types import * diff --git a/elementGen/types.py b/elementGen/types.py new file mode 100644 index 0000000..63c31b0 --- /dev/null +++ b/elementGen/types.py @@ -0,0 +1,9 @@ +types = { + 'int': int, + 'str': str +} + +defaults = { + 'int': 0, + 'str': '' +} From 15bee6cb4ca6bea07aea9c1ad920d17fdab49ee4 Mon Sep 17 00:00:00 2001 From: Max Worrall <96847801+Tsunami014@users.noreply.github.com> Date: Mon, 11 Dec 2023 16:05:54 +1100 Subject: [PATCH 90/91] =?UTF-8?q?feat(nodes):=20=E2=9C=A8=20Made=20the=20s?= =?UTF-8?q?crollable=20have=20boxes=20where=20you=20set=20an=20input!=20:)?= =?UTF-8?q?))))))=20THIS=20WORKS=20SO=20WELL!!!?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Made the parsed nodes have values and made boxes in the scrollable that when you change it the value changes and that value gets defaulted with the output --- elementGen/node_editor.py | 31 +++++++++++++++++++++++++++++-- elementGen/node_parser.py | 6 ++++-- elementGen/types.py | 10 ++++++++++ 3 files changed, 43 insertions(+), 4 deletions(-) diff --git a/elementGen/node_editor.py b/elementGen/node_editor.py index 3ff0689..171c974 100644 --- a/elementGen/node_editor.py +++ b/elementGen/node_editor.py @@ -1,6 +1,7 @@ import pygame, os, pickle import graphics.graphics_options as GO import elementGen.node_parser as np +import elementGen.types as Ts categories = [i.name for i in os.scandir('data/elements') if i.is_dir()] @@ -290,7 +291,7 @@ def settings(event, element=None, aborted=False): mx2 = 0 for n in node.outputs: name = n.name - if n.name in g: name = str(g[n.name]) + if n.name in g: name += ':'+str(g[n.name]) s, c = CAT(name, front=False, bgcol=col) c.move_ip(mx+p[0], i2+p[1]) node.cirs[n] = c @@ -337,10 +338,36 @@ def settings(event, element=None, aborted=False): G.WIN.blit(txt, ((w - txt.get_width())/2+8, G.size[1]-h+10)) if G.scrollsables == []: pos = GO.PSTATIC(12, G.size[1]-h+10+txt.get_height()+2) - size = 60 # TODO: CHANGE + adds = [[], []] + boxes = [] + getsize = lambda: sum([max(adds[0][i][2].get_height(),boxes[i][2][1])+10 for i in range(len(adds[0]))]) + for i in node.inputs: + r = GO.FFONT.render(i.name+':', 2, GO.CBLACK) + s = getsize() + adds[0].append((5, s, r)) + boxes.append((r.get_width()+7, s, Ts.sizing[Ts.strtypes[i.type]](i.value, GO.FFONT), Ts.strtypes[i.type], i.value)) + g = node.get() + for i in node.outputs: + name = i.name + if n.name in g: name += ':'+str(g[n.name]) + r = GO.FFONT.render(name, 2, GO.CBLACK) + adds[1].append((w-r.get_width()-10, sum([i[2].get_height()+10 for i in adds[1]]), r)) + size = max(getsize(), sum([i[2].get_height()+10 for i in adds[1]])) size = max(size, h-(txt.get_height()+30)+1) _, scr = G.add_Scrollable(pos, (w-8, h-(txt.get_height()+30)), (w-8, size), 2, True) scr.bgcol = GO.CNEW('light grey') + for i in adds[0]+adds[1]: + scr.add_surface(i[2], GO.PSTATIC(i[0], i[1])) + scr.add_surface(i[2], GO.PSTATIC(i[0], i[1])) + for i in boxes: + if i[3] == 'int': + scr.add_num_input(GO.PSTATIC(i[0], i[1]), font=GO.FFONT, width=10, start=i[4]) + elif i[3] == 'str': + scr.add_input(GO.PSTATIC(i[0], i[1]), font=GO.FFONT, width=GO.FFONT.size('c'*10)[0], start=i[4]) + else: + inps = G.scrollsables[0].G.input_boxes + for i in range(len(node.inputs)): + node.inputs[i].value = inps[i].get() elif G.scrollsables != []: G.Reload() return True diff --git a/elementGen/node_parser.py b/elementGen/node_parser.py index a06bc7c..410af1c 100644 --- a/elementGen/node_parser.py +++ b/elementGen/node_parser.py @@ -1,6 +1,7 @@ import os from random import random from copy import deepcopy +import elementGen.types as Ts def allCategories(): return [i.name for i in os.scandir('data/nodes') if i.is_file()] @@ -25,8 +26,9 @@ def __init__(self, parent, isinp, name, typ): self.parent = parent self.isinp = isinp self.name = name - self.type = typ + self.type = Ts.types[typ] self.rect = None + self.value = Ts.defaults[typ] self.connectedto = None # Relying on externs to generate def isntsimilar(self, other): try: @@ -97,7 +99,7 @@ def get(self): try: ins.append(i.connectedto.parent.get()[i.connectedto.name]) except: - pass + ins.append(i.value) try: return self(*ins) except: diff --git a/elementGen/types.py b/elementGen/types.py index 63c31b0..aada827 100644 --- a/elementGen/types.py +++ b/elementGen/types.py @@ -3,7 +3,17 @@ 'str': str } +strtypes = { + int: 'int', + str: 'str' +} + defaults = { 'int': 0, 'str': '' } + +sizing = { + 'int': lambda num, font: (font.size(str(num))[0], font.size(str(num))[1]+10), + 'str': lambda txt, font: (font.size(str(txt))[0], font.size(str(txt))[1]+10) +} From f0e85288dbd5da3131b226aee4dd3c1c780e4dbb Mon Sep 17 00:00:00 2001 From: Max Worrall <96847801+Tsunami014@users.noreply.github.com> Date: Mon, 11 Dec 2023 16:19:19 +1100 Subject: [PATCH 91/91] =?UTF-8?q?feat(nodes):=20=E2=9C=A8=20Made=20more=20?= =?UTF-8?q?funcs=20and=20made=20the=20add=20able=20to=20add=20nums=20AND?= =?UTF-8?q?=20text!?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- data/nodes/test.py | 32 +++++++++++++++++++++++++------- elementGen/node_editor.py | 2 ++ elementGen/node_parser.py | 6 +++--- elementGen/types.py | 14 ++++++++++---- 4 files changed, 40 insertions(+), 14 deletions(-) diff --git a/data/nodes/test.py b/data/nodes/test.py index 660a2a1..f005fc3 100644 --- a/data/nodes/test.py +++ b/data/nodes/test.py @@ -1,17 +1,35 @@ -# Add int@A int@B | int@Out # +# Add any@A any@B | Out # def node(A, B): + '''attempt to add the numbers as if they are ints, else just perform addition.''' + try: + return {'Out': int(A) + int(B)} + except: pass return {'Out': A + B} + ''' +Use this if you want: +``` +if type(A) != type(B): raise TypeError('Mismatching types!!!') +t = type(A) +``` + How this works is the dict is the outputs' names to replace by a new value So in this case the output with the name 'Out' gets shown as A + B instead of it's original 'Out' value if this doesn't error and has all things connected ''' -# One | int@1 # -def node(): - return {'1': 1} +# Subtract int@A int@B | Out # + +def node(A, B): + return {'Out': A - B} + +# Multiply int@A int@B | Out # -# Two | int@2 # -def node(): - return {'2': 2} +def node(A, B): + return {'Out': A * B} + +# Divide int@A int@B | Out # + +def node(A, B): + return {'Out': A / B} diff --git a/elementGen/node_editor.py b/elementGen/node_editor.py index 171c974..0c15f1f 100644 --- a/elementGen/node_editor.py +++ b/elementGen/node_editor.py @@ -364,6 +364,8 @@ def settings(event, element=None, aborted=False): scr.add_num_input(GO.PSTATIC(i[0], i[1]), font=GO.FFONT, width=10, start=i[4]) elif i[3] == 'str': scr.add_input(GO.PSTATIC(i[0], i[1]), font=GO.FFONT, width=GO.FFONT.size('c'*10)[0], start=i[4]) + elif i[3] == 'any': + scr.add_input(GO.PSTATIC(i[0], i[1]), font=GO.FFONT, width=GO.FFONT.size('c'*10)[0], start=str(i[4])) else: inps = G.scrollsables[0].G.input_boxes for i in range(len(node.inputs)): diff --git a/elementGen/node_parser.py b/elementGen/node_parser.py index 410af1c..2289835 100644 --- a/elementGen/node_parser.py +++ b/elementGen/node_parser.py @@ -21,7 +21,7 @@ def reset(self): self.clear() class Connector: - def __init__(self, parent, isinp, name, typ): + def __init__(self, parent, isinp, name, typ='any'): self.num = random() self.parent = parent self.isinp = isinp @@ -63,11 +63,11 @@ def __init__(self, data): if i == '|': input = False continue - s = i.split('@') if input: + s = i.split('@') self.inputs.append(Connector(self, True, s[1], s[0])) else: - self.outputs.append(Connector(self, False, s[1], s[0])) + self.outputs.append(Connector(self, False, i)) def setter(self, key, value): for i in range(len(self.inputs)): if self.inputs[i] == key: diff --git a/elementGen/types.py b/elementGen/types.py index aada827..fd2f0cd 100644 --- a/elementGen/types.py +++ b/elementGen/types.py @@ -1,19 +1,25 @@ +from typing import Any + types = { 'int': int, - 'str': str + 'str': str, + 'any': Any } strtypes = { int: 'int', - str: 'str' + str: 'str', + Any: 'any' } defaults = { 'int': 0, - 'str': '' + 'str': '', + 'any': None } sizing = { 'int': lambda num, font: (font.size(str(num))[0], font.size(str(num))[1]+10), - 'str': lambda txt, font: (font.size(str(txt))[0], font.size(str(txt))[1]+10) + 'str': lambda txt, font: (font.size(str(txt))[0], font.size(str(txt))[1]+10), + 'any': lambda _, font: (font.size(str('None'))[0], font.size(str("None"))[1]+10) }