From bd0a86c7dec28a87edea998d932e5141826d5283 Mon Sep 17 00:00:00 2001 From: CaseyHackerMan Date: Wed, 31 Aug 2022 14:24:28 -0700 Subject: [PATCH 01/13] added Button and test, changed stuff Implemented button.py and wrote a test, moved pygame initialization stuff to guipy/__init__.py, added default font util, added optional function to textbox, changed sub_coords() to sub_vector() (and add_vector()), and added a black border to @Zjjc123's slider_test.py --- guipy/__init__.py | 4 ++ guipy/components/button.py | 112 ++++++++++++++++++++++++++++++++++++ guipy/components/plot.py | 4 +- guipy/components/textbox.py | 23 +++++++- guipy/manager.py | 5 +- guipy/utils.py | 33 +++++++++-- tests/button_test.py | 44 ++++++++++++++ tests/plot_test.py | 2 - tests/slider_test.py | 9 +-- tests/textbox_test.py | 11 ++-- 10 files changed, 222 insertions(+), 25 deletions(-) create mode 100644 guipy/components/button.py create mode 100644 tests/button_test.py diff --git a/guipy/__init__.py b/guipy/__init__.py index e69de29..c7f88d7 100644 --- a/guipy/__init__.py +++ b/guipy/__init__.py @@ -0,0 +1,4 @@ +import pygame + +pygame.init() +pygame.font.init() diff --git a/guipy/components/button.py b/guipy/components/button.py new file mode 100644 index 0000000..46c54c6 --- /dev/null +++ b/guipy/components/button.py @@ -0,0 +1,112 @@ +import pygame +from guipy.components._component import Component +from guipy.utils import * + + +class Button(Component): + """ + Button component + """ + + def __init__(self, width=None, height=None, font=None, text="Bruh", func=None): + """ + Button init + + :param width: button width in pixels, defaults to fit text + :param height: button height in pixels, defaults to fit text + :param font: pygame Font object to use + :param text: text to display on the button + :param func: function to run when button is released + """ + if font == None: + self.font = get_default_font() + else: + self.font = font + + min_w, min_h = self.font.size(text) + if width == None: + width = min_w + 6 + if height == None: + height = min_h + super().__init__(width, height) + + self.pressed = False + self.prev_mouse_down = False + + self.set_text(text) + self.set_func(func) + + def get_val(self): + """ + Get current state + """ + return self.pressed + + def set_func(self, func): + """ + Set the function to be run when button is released + + :param func: Function with signature (button:Button) + """ + self.func = func + return self + + def set_text(self, text): + """ + Sets the text on the button and redraws the surface + + :param text: + """ + self.text = text + text_surf = self.font.render(text, True, BLACK) + + x, y = sub_vector(self.root.get_size(), text_surf.get_size()) + pos = (x // 2, y // 2) + + surf = self.root.copy() + pygame.draw.rect(surf, LIGHT_GREY, surf.get_rect()) + pygame.draw.rect(surf, DARK_GREY, surf.get_rect(), 1) + surf.blit(text_surf, pos) + self.off_surf = surf + + surf = self.root.copy() + pygame.draw.rect(surf, GREY, surf.get_rect()) + pygame.draw.rect(surf, DARK_GREY, surf.get_rect(), 1) + surf.blit(text_surf, pos) + self.on_surf = surf + + return self + + def draw(self): + """ + Renders the button + """ + self.root.fill((0, 0, 0, 0)) + + if self.pressed: + self.root.blit(self.on_surf, (0, 0)) + else: + self.root.blit(self.off_surf, (0, 0)) + + def update(self, rel_mouse, events): + """ + Update the button + + :param rel_mouse: Relative mouse position + :param events: Pygame Event list + """ + + mouse_down = pygame.mouse.get_pressed()[0] + + in_comp = self.root.get_rect().collidepoint(rel_mouse) + on_release = not mouse_down and self.prev_mouse_down + + if self.pressed and on_release: + self.pressed = False + if self.func != None: + self.func(self) + + if mouse_down and in_comp: + self.pressed = True + + self.prev_mouse_down = mouse_down diff --git a/guipy/components/plot.py b/guipy/components/plot.py index f2ad18b..db43606 100644 --- a/guipy/components/plot.py +++ b/guipy/components/plot.py @@ -45,9 +45,7 @@ def __init__(self, width, height, xlabel=None, ylabel=None): self.ymax = 1 self.points = [] - pygame.font.init() - font_name = pygame.font.get_fonts()[0] - self.font = pygame.font.SysFont(font_name, 20) + self.font = get_default_font() self.window = pygame.Surface( (width - self.yaxis_spacer, height - self.xaxis_spacer) diff --git a/guipy/components/textbox.py b/guipy/components/textbox.py index 196c558..5835525 100644 --- a/guipy/components/textbox.py +++ b/guipy/components/textbox.py @@ -1,5 +1,6 @@ import pygame from guipy.components._component import Component +from guipy.utils import * class Textbox(Component): @@ -15,15 +16,20 @@ def __init__(self, width, font=None, default_text="Type here..."): :param font: Pygame Font object to be used :param default_text: Text to be shown when textbox is empty """ + if font == None: + self.font = get_default_font() + else: + self.font = font + height = font.get_height() + 6 super().__init__(width, height) self.active = False self.prev_mouse_down = False self.text = "" - self.font = font self.text_surf = font.render(default_text, True, (200, 200, 200)) self.default = self.text_surf + self.func = None def get_val(self): """ @@ -31,6 +37,15 @@ def get_val(self): """ return self.text + def set_func(self, func): + """ + Set the function to be run when text is entered + + :param func: Function with signature (textbox:Textbox) + """ + self.func = func + return self + def draw(self): """ Renders the textbox @@ -58,14 +73,18 @@ def update(self, rel_mouse, events): on_click = mouse_down and not self.prev_mouse_down if on_click: + if self.active and not in_comp and self.func != None: + self.func(self) self.active = in_comp if self.active: + for event in events: if event.type == pygame.KEYDOWN: # check for backspace if event.key == pygame.K_RETURN: - self.active = False + if self.func != None: + self.func(self) elif event.key == pygame.K_BACKSPACE: self.text = self.text[:-1] else: # add character diff --git a/guipy/manager.py b/guipy/manager.py index 3d6e327..786bca1 100644 --- a/guipy/manager.py +++ b/guipy/manager.py @@ -1,3 +1,6 @@ +from guipy.utils import * + + class GUIManager: """ GUI Manager @@ -31,7 +34,7 @@ def update(self, mouse_pos, events): """ for component in self.components: - rel_mouse = tuple(i[0] - i[1] for i in zip(mouse_pos, component[1])) + rel_mouse = sub_vector(mouse_pos, component[1]) component[0].update(rel_mouse, events) def draw(self, root): diff --git a/guipy/utils.py b/guipy/utils.py index ed12e28..7449bc4 100644 --- a/guipy/utils.py +++ b/guipy/utils.py @@ -1,12 +1,24 @@ -def sub_coords(offset, coord): +import pygame + + +def add_vector(a, b): """ - Finds the relative coordinate of one point in another point + Adds two vectors (a+b) + + :param a: + :param b: + """ + return (a[0] + b[0], a[1] + b[1]) + - :param coord: the coordinate - :param offset: the coordinate relative to +def sub_vector(a, b): + """ + Subtracts two vectors (a-b) + :param a: + :param b: """ - return (coord[0] - offset[0], coord[1] - offset[1]) + return (a[0] - b[0], a[1] - b[1]) def translate(value, min1, max1, min2, max2): @@ -27,6 +39,11 @@ def translate(value, min1, max1, min2, max2): return min2 + (valueScaled * span2) +def get_default_font(): + font_name = pygame.font.get_fonts()[0] + return pygame.font.SysFont(font_name, 20) + + WHITE = (255, 255, 255) """ Preset for the color White @@ -47,7 +64,11 @@ def translate(value, min1, max1, min2, max2): """ Preset for the color Black """ -GREY = (230, 230, 230) +LIGHT_GREY = (230, 230, 230) +""" +Preset for the color Light Grey +""" +GREY = (200, 200, 200) """ Preset for the color Grey """ diff --git a/tests/button_test.py b/tests/button_test.py new file mode 100644 index 0000000..8e4f5b7 --- /dev/null +++ b/tests/button_test.py @@ -0,0 +1,44 @@ +import sys +import os +import inspect + +import pygame + +currentdir = os.path.dirname(os.path.abspath(inspect.getfile(inspect.currentframe()))) +parentdir = os.path.dirname(currentdir) +sys.path.insert(0, parentdir) + +from guipy.manager import GUIManager +from guipy.components.button import Button +from guipy.utils import * + + +def func(button): + button.set_text(button.text + "!") + print(button.text) + + +winW = 1280 +winH = 720 + +root = pygame.display.set_mode((winW, winH)) + +man = GUIManager() +myButton1 = Button(width=200, func=func) +myButton2 = Button(width=200, func=func) +myButton3 = Button(width=200, func=func) +myButton4 = Button(width=200, func=func) + +man.add(myButton1, (10, 25)) +man.add(myButton2, (10, 75)) +man.add(myButton3, (10, 125)) +man.add(myButton4, (10, 175)) +while True: + events = pygame.event.get() + for event in events: + if event.type == pygame.QUIT: + sys.exit() + root.fill(WHITE) + man.draw(root) + man.update(pygame.mouse.get_pos(), events) + pygame.display.update() diff --git a/tests/plot_test.py b/tests/plot_test.py index 29d5fe5..a5a6f73 100644 --- a/tests/plot_test.py +++ b/tests/plot_test.py @@ -11,8 +11,6 @@ from guipy.manager import GUIManager from guipy.components.plot import Plot -pygame.init() - winW = 1280 winH = 720 diff --git a/tests/slider_test.py b/tests/slider_test.py index 6df8707..d3875f3 100644 --- a/tests/slider_test.py +++ b/tests/slider_test.py @@ -11,8 +11,7 @@ from guipy.components.slider import Slider from guipy.manager import GUIManager - -pygame.init() +from guipy.utils import * winW = 1280 winH = 720 @@ -45,8 +44,10 @@ mySlider2.get_val(), mySlider3.get_val(), mySlider4.get_val() ) ) - - pygame.draw.circle(root, color, (winW / 2, winH / 2), 10 + mySlider.get_val() * 100) + center = (winW // 2, winH // 2) + r = 10 + mySlider.get_val() * 100 + pygame.draw.circle(root, color, center, r) + pygame.draw.circle(root, BLACK, center, r, 3) man.draw(root) man.update(pygame.mouse.get_pos(), events) diff --git a/tests/textbox_test.py b/tests/textbox_test.py index 6ab0638..be881d6 100644 --- a/tests/textbox_test.py +++ b/tests/textbox_test.py @@ -11,9 +11,6 @@ from guipy.manager import GUIManager from guipy.components.textbox import Textbox -pygame.init() -pygame.font.init() - myFont = pygame.font.SysFont("Microsoft Sans Serif", 20) winW = 1280 @@ -22,10 +19,10 @@ root = pygame.display.set_mode((winW, winH)) man = GUIManager() -myTextbox1 = Textbox(width=400, font=myFont) -myTextbox2 = Textbox(width=400, font=myFont) -myTextbox3 = Textbox(width=400, font=myFont) -myTextbox4 = Textbox(width=400, font=myFont) +myTextbox1 = Textbox(width=400, font=myFont).set_func(lambda x: print("1: " + x.text)) +myTextbox2 = Textbox(width=400, font=myFont).set_func(lambda x: print("2: " + x.text)) +myTextbox3 = Textbox(width=400, font=myFont).set_func(lambda x: print("3: " + x.text)) +myTextbox4 = Textbox(width=400, font=myFont).set_func(lambda x: print("4: " + x.text)) man.add(myTextbox1, (10, 25)) man.add(myTextbox2, (10, 75)) From 03ae1ab30b60c4cf48b71515ff8117dd93d12780 Mon Sep 17 00:00:00 2001 From: CaseyHackerMan Date: Wed, 31 Aug 2022 16:46:48 -0700 Subject: [PATCH 02/13] added Switch and test, changed stuff Implemented switch.py and test, refactored button, added _render() to some components to contain the visual design, added TRANSPARENT color. --- guipy/components/button.py | 38 ++++++++++-------- guipy/components/plot.py | 29 +++++++------- guipy/components/switch.py | 80 ++++++++++++++++++++++++++++++++++++++ guipy/utils.py | 4 ++ tests/button_test.py | 4 +- tests/plot_test.py | 3 +- tests/switch_test.py | 49 +++++++++++++++++++++++ 7 files changed, 176 insertions(+), 31 deletions(-) create mode 100644 guipy/components/switch.py create mode 100644 tests/switch_test.py diff --git a/guipy/components/button.py b/guipy/components/button.py index 46c54c6..7f3839a 100644 --- a/guipy/components/button.py +++ b/guipy/components/button.py @@ -28,12 +28,17 @@ def __init__(self, width=None, height=None, font=None, text="Bruh", func=None): width = min_w + 6 if height == None: height = min_h + super().__init__(width, height) + self.off_surf = self.root.copy() + self.on_surf = self.root.copy() + self.root = self.off_surf self.pressed = False self.prev_mouse_down = False + self.text = text - self.set_text(text) + self._render() self.set_func(func) def get_val(self): @@ -51,42 +56,43 @@ def set_func(self, func): self.func = func return self - def set_text(self, text): - """ - Sets the text on the button and redraws the surface - - :param text: - """ - self.text = text - text_surf = self.font.render(text, True, BLACK) + def _render(self): + text_surf = self.font.render(self.text, True, BLACK) x, y = sub_vector(self.root.get_size(), text_surf.get_size()) pos = (x // 2, y // 2) - surf = self.root.copy() + self.off_surf.fill(TRANSPARENT) + surf = self.off_surf pygame.draw.rect(surf, LIGHT_GREY, surf.get_rect()) pygame.draw.rect(surf, DARK_GREY, surf.get_rect(), 1) surf.blit(text_surf, pos) - self.off_surf = surf - surf = self.root.copy() + self.on_surf.fill(TRANSPARENT) + surf = self.on_surf pygame.draw.rect(surf, GREY, surf.get_rect()) pygame.draw.rect(surf, DARK_GREY, surf.get_rect(), 1) surf.blit(text_surf, pos) - self.on_surf = surf + def set_text(self, text): + """ + Sets the text on the button and redraws the surface + + :param text: + """ + self.text = text + self._render() return self def draw(self): """ Renders the button """ - self.root.fill((0, 0, 0, 0)) if self.pressed: - self.root.blit(self.on_surf, (0, 0)) + self.root = self.on_surf else: - self.root.blit(self.off_surf, (0, 0)) + self.root = self.off_surf def update(self, rel_mouse, events): """ diff --git a/guipy/components/plot.py b/guipy/components/plot.py index db43606..99d2cfb 100644 --- a/guipy/components/plot.py +++ b/guipy/components/plot.py @@ -64,18 +64,7 @@ def _y(self, y): # coordinate to pixel y, self.ymax, self.ymin, self._windrect.top, self._windrect.bottom ) - def set_range(self, xrange, yrange): - """ - Sets the plot X and Y range and draws the axes using the new range. - - :param xrange: List of minimum and maximum X values. ex: (0,100) - :param yrange: List of minimum and maximum Y values. ex: (0,100) - """ - self.xmin = xrange[0] - self.xmax = xrange[1] - self.ymin = yrange[0] - self.ymax = yrange[1] - + def _render(self): w = self.window.get_width() h = self.window.get_height() @@ -85,7 +74,7 @@ def set_range(self, xrange, yrange): scale = math.floor(math.log10(self.xmax - self.xmin)) - 1 res = 10**scale - i = math.ceil(xrange[0] / res) * res + i = math.ceil(self.xmin / res) * res while i <= self.xmax: p1 = (self._x(i), h) @@ -129,6 +118,20 @@ def set_range(self, xrange, yrange): p = (self.width - label.get_width(), (h - label.get_height()) / 2) self.root.blit(label, p) + def set_range(self, xrange, yrange): + """ + Sets the plot X and Y range and draws the axes using the new range. + + :param xrange: List of minimum and maximum X values. ex: (0,100) + :param yrange: List of minimum and maximum Y values. ex: (0,100) + """ + self.xmin = xrange[0] + self.xmax = xrange[1] + self.ymin = yrange[0] + self.ymax = yrange[1] + + self._render() + def plot(self, data, style=line): """ Plots a list of points diff --git a/guipy/components/switch.py b/guipy/components/switch.py new file mode 100644 index 0000000..400c0f1 --- /dev/null +++ b/guipy/components/switch.py @@ -0,0 +1,80 @@ +import pygame +from guipy.components._component import Component +from guipy.utils import * + + +class Switch(Component): + def __init__(self, width, height): + super().__init__(width, height) + self.off_surf = self.root.copy() + self.on_surf = self.root.copy() + + self.state = False + self.prev_mouse_down = False + self.root = self.off_surf + + self._render() + + def get_val(self): + return self.state + + def set_funcs(self, on_func=None, off_func=None): + self.on_func = on_func + self.off_func = off_func + return self + + def _render(self): + spacer = 3 + corner = 7 + alpha = 200 + + self.off_surf.fill(TRANSPARENT) + surf = self.off_surf + pygame.draw.rect(surf, (255, 0, 0, alpha), surf.get_rect(), 0, corner) + pygame.draw.rect(surf, BLACK, surf.get_rect(), 1, corner) + rect = pygame.Rect( + spacer, spacer, self.width // 2 - spacer, self.height - spacer * 2 + ) + pygame.draw.rect(surf, GREY, rect, 0, corner) + pygame.draw.rect(surf, BLACK, rect, 1, corner) + + self.on_surf.fill(TRANSPARENT) + surf = self.on_surf + pygame.draw.rect(surf, (0, 255, 0, alpha), surf.get_rect(), 0, corner) + pygame.draw.rect(surf, BLACK, surf.get_rect(), 1, corner) + rect = pygame.Rect( + self.width // 2, spacer, self.width // 2 - spacer, self.height - spacer * 2 + ) + pygame.draw.rect(surf, GREY, rect, 0, corner) + pygame.draw.rect(surf, BLACK, rect, 1, corner) + + def draw(self): + if self.state: + self.root = self.on_surf + else: + self.root = self.off_surf + + def update(self, rel_mouse, events): + """ + Update the button + + :param rel_mouse: Relative mouse position + :param events: Pygame Event list + """ + + mouse_down = pygame.mouse.get_pressed()[0] + + in_comp = self.root.get_rect().collidepoint(rel_mouse) + on_click = mouse_down and not self.prev_mouse_down + + if on_click and in_comp: + self.state = not self.state + + if self.state: + if self.on_func != None: + self.on_func() + else: + if self.off_func != None: + self.off_func() + + self.prev_mouse_down = mouse_down diff --git a/guipy/utils.py b/guipy/utils.py index 7449bc4..7838c00 100644 --- a/guipy/utils.py +++ b/guipy/utils.py @@ -80,3 +80,7 @@ def get_default_font(): """ Preset for the color Orange """ +TRANSPARENT = (0, 0, 0, 0) +""" +Preset for transparent (for alpha surfaces) +""" diff --git a/tests/button_test.py b/tests/button_test.py index 8e4f5b7..4738fac 100644 --- a/tests/button_test.py +++ b/tests/button_test.py @@ -38,7 +38,9 @@ def func(button): for event in events: if event.type == pygame.QUIT: sys.exit() + root.fill(WHITE) - man.draw(root) + man.update(pygame.mouse.get_pos(), events) + man.draw(root) pygame.display.update() diff --git a/tests/plot_test.py b/tests/plot_test.py index a5a6f73..7e7d1a8 100644 --- a/tests/plot_test.py +++ b/tests/plot_test.py @@ -10,6 +10,7 @@ from guipy.manager import GUIManager from guipy.components.plot import Plot +from guipy.utils import * winW = 1280 winH = 720 @@ -29,7 +30,7 @@ for event in events: if event.type == pygame.QUIT: sys.exit() - root.fill((200, 200, 200)) + root.fill(LIGHT_GREY) p = pygame.mouse.get_pos() x = p[0] if p[0] else x diff --git a/tests/switch_test.py b/tests/switch_test.py new file mode 100644 index 0000000..41976b1 --- /dev/null +++ b/tests/switch_test.py @@ -0,0 +1,49 @@ +import sys +import os +import inspect + +import pygame + +currentdir = os.path.dirname(os.path.abspath(inspect.getfile(inspect.currentframe()))) +parentdir = os.path.dirname(currentdir) +sys.path.insert(0, parentdir) + +from guipy.manager import GUIManager +from guipy.components.switch import Switch +from guipy.utils import * + + +def func1(): + print("on") + + +def func2(): + print("off") + + +winW = 1280 +winH = 720 + +root = pygame.display.set_mode((winW, winH)) + +man = GUIManager() +mySwitch1 = Switch(width=20, height=10).set_funcs(on_func=func1, off_func=func2) +mySwitch2 = Switch(width=30, height=15).set_funcs(on_func=func1, off_func=func2) +mySwitch3 = Switch(width=60, height=30).set_funcs(on_func=func1, off_func=func2) +mySwitch4 = Switch(width=200, height=300).set_funcs(on_func=func1, off_func=func2) + +man.add(mySwitch1, (10, 25)) +man.add(mySwitch2, (10, 75)) +man.add(mySwitch3, (10, 125)) +man.add(mySwitch4, (10, 175)) +while True: + events = pygame.event.get() + for event in events: + if event.type == pygame.QUIT: + sys.exit() + + root.fill(WHITE) + + man.update(pygame.mouse.get_pos(), events) + man.draw(root) + pygame.display.update() From c469191fdb38edef5eea99881d98a96b389aed6c Mon Sep 17 00:00:00 2001 From: CaseyHackerMan Date: Fri, 2 Sep 2022 16:38:27 -0700 Subject: [PATCH 03/13] added AutoPlot (in plot.py) and test Implemented AutoPlot and test, fixed some range issues in Plot, slight change to translate(), commented switch.py --- guipy/components/plot.py | 102 +++++++++++++++++++++++++++++++++++-- guipy/components/switch.py | 24 ++++++++- guipy/utils.py | 2 + tests/liveplot_test.py | 42 +++++++++++++++ 4 files changed, 165 insertions(+), 5 deletions(-) create mode 100644 tests/liveplot_test.py diff --git a/guipy/components/plot.py b/guipy/components/plot.py index 99d2cfb..7ac5bb5 100644 --- a/guipy/components/plot.py +++ b/guipy/components/plot.py @@ -72,6 +72,8 @@ def _render(self): # draw x-axis scale = math.floor(math.log10(self.xmax - self.xmin)) - 1 + if scale < -13: + scale = -13 res = 10**scale i = math.ceil(self.xmin / res) * res @@ -96,6 +98,8 @@ def _render(self): # draw y-axis scale = math.floor(math.log10(self.ymax - self.ymin)) - 1 + if scale < -13: + scale = -13 res = 10**scale i = math.ceil(self.ymin / res) * res @@ -125,10 +129,14 @@ def set_range(self, xrange, yrange): :param xrange: List of minimum and maximum X values. ex: (0,100) :param yrange: List of minimum and maximum Y values. ex: (0,100) """ - self.xmin = xrange[0] - self.xmax = xrange[1] - self.ymin = yrange[0] - self.ymax = yrange[1] + + if xrange[0] != xrange[1]: + self.xmin = xrange[0] + self.xmax = xrange[1] + + if yrange[0] != yrange[1]: + self.ymin = yrange[0] + self.ymax = yrange[1] self._render() @@ -155,3 +163,89 @@ def draw(self): """ self.root.blit(self.window, (0, 0)) pygame.draw.rect(self.root, BLACK, self.window.get_rect(), 1) + + +class LivePlot(Plot): + """ + Live plot component. Unlike Plot, this will receive data continouously and add it to a buffer. Data is deleted from the buffer when it falls outside of a specified time range (time_range). \ + The axes adjust automatically to show all the data.""" + + def __init__( + self, + width, + height, + style=line, + glide=10, + xlabel="Time", + ylabel="Data", + time_range=10, + ): + """ + LivePlot init + + :param width: Plot width in pixels + :param height: Plot height in pixels + :param glide: y-axis glide value. A glide value above 1 will adjust the y range gradually. A value of 1 will make the y range snap to the new value. Any value below 1 will only increase the y range. + :param xlabel: X-axis label + :param ylabel: Y-axis label + """ + + super().__init__(width, height, xlabel=xlabel, ylabel=ylabel) + + self.glide = glide + # self.auto_range = True + self.style = style + self.time_range = time_range + + self.buffer = [] + + def add(self, data): + """ + Add a single or multiple data points to the plot. Removes data that is outside of the time range + + :param data: data to add. ex: [(time1:float,data1:float),(time2,data2),...] + """ + + self.buffer += data + + if self.time_range >= 0 and len(self.buffer) > 1: + i = 1 + while (self.buffer[-1][0] - self.buffer[i][0]) > self.time_range: + i += 1 + self.buffer = self.buffer[i - 1 :] + + def reset(self): + self.buffer = [] + + def update(self, rel_mouse, events): + if len(self.buffer) < 2: + return + + data = list(i[1] for i in self.buffer) + low = min(data) + high = max(data) + + xmin = self.xmin + xmax = self.xmax + ymin = self.ymin + ymax = self.ymax + + if self.glide >= 1: + ymin += (low - ymin) / self.glide + ymax += (high - ymax) / self.glide + else: + if high > ymax: + ymax = high + if low < ymin: + ymin = low + + t = self.buffer[-1][0] + xmax = t + xmin = t - self.time_range + + self.set_range((xmin, xmax), (ymin, ymax)) + + def draw(self): + self.clear() + self.plot(self.buffer, self.style) + super().draw() diff --git a/guipy/components/switch.py b/guipy/components/switch.py index 400c0f1..df6fcd5 100644 --- a/guipy/components/switch.py +++ b/guipy/components/switch.py @@ -4,7 +4,17 @@ class Switch(Component): + """ + Switch component + """ + def __init__(self, width, height): + """ + Switch init + + :param width: Width in pixels + :param height: Height in pixels + """ super().__init__(width, height) self.off_surf = self.root.copy() self.on_surf = self.root.copy() @@ -16,9 +26,18 @@ def __init__(self, width, height): self._render() def get_val(self): + """ + Gets the state of the switch as a boolean + """ return self.state def set_funcs(self, on_func=None, off_func=None): + """ + Sets the functions to run when the switch is turned on or off + + :param on_func: Function to run when the switch is turned on + :param off_func: Function to run when the switch is turned off + """ self.on_func = on_func self.off_func = off_func return self @@ -49,6 +68,9 @@ def _render(self): pygame.draw.rect(surf, BLACK, rect, 1, corner) def draw(self): + """ + Draws the switch dependant on the state + """ if self.state: self.root = self.on_surf else: @@ -56,7 +78,7 @@ def draw(self): def update(self, rel_mouse, events): """ - Update the button + Update the switch :param rel_mouse: Relative mouse position :param events: Pygame Event list diff --git a/guipy/utils.py b/guipy/utils.py index 7838c00..dbca839 100644 --- a/guipy/utils.py +++ b/guipy/utils.py @@ -35,6 +35,8 @@ def translate(value, min1, max1, min2, max2): span2 = max2 - min2 if span1 == 0: return 0 + if value == None: + return None valueScaled = float(value - min1) / float(span1) return min2 + (valueScaled * span2) diff --git a/tests/liveplot_test.py b/tests/liveplot_test.py new file mode 100644 index 0000000..94307fa --- /dev/null +++ b/tests/liveplot_test.py @@ -0,0 +1,42 @@ +import sys +import os +import inspect +import time + +import pygame + +currentdir = os.path.dirname(os.path.abspath(inspect.getfile(inspect.currentframe()))) +parentdir = os.path.dirname(currentdir) +sys.path.insert(0, parentdir) + +from guipy.manager import GUIManager +from guipy.components.plot import LivePlot +from guipy.utils import * + +winW = 1280 +winH = 720 + +root = pygame.display.set_mode((winW, winH)) + +myPlot1 = LivePlot(height=winH, width=winW) + +man = GUIManager() +man.add(myPlot1, (0, 0)) + + +while True: + events = pygame.event.get() + for event in events: + if event.type == pygame.QUIT: + sys.exit() + + root.fill(LIGHT_GREY) + + p = pygame.mouse.get_pos() + + myPlot1.add([(time.time(), p[1])]) + + man.update(p, []) + man.draw(root) + + pygame.display.update() From b26b5cf938f413c0cc9b21f4ccff2e93c516a0ee Mon Sep 17 00:00:00 2001 From: CaseyHackerMan Date: Fri, 2 Sep 2022 16:47:47 -0700 Subject: [PATCH 04/13] comments on AutoPlot also added to gitignore to be sneaky --- .gitignore | 3 +++ guipy/components/plot.py | 23 +++++++++++++++++++---- 2 files changed, 22 insertions(+), 4 deletions(-) diff --git a/.gitignore b/.gitignore index e1cd353..dcd3822 100644 --- a/.gitignore +++ b/.gitignore @@ -130,3 +130,6 @@ dmypy.json # DS_Store .DS_Store + +# secret tests +tests/test.py \ No newline at end of file diff --git a/guipy/components/plot.py b/guipy/components/plot.py index 7ac5bb5..676b407 100644 --- a/guipy/components/plot.py +++ b/guipy/components/plot.py @@ -168,7 +168,8 @@ def draw(self): class LivePlot(Plot): """ Live plot component. Unlike Plot, this will receive data continouously and add it to a buffer. Data is deleted from the buffer when it falls outside of a specified time range (time_range). \ - The axes adjust automatically to show all the data.""" + The axes adjust automatically to show all the data. + """ def __init__( self, @@ -185,9 +186,11 @@ def __init__( :param width: Plot width in pixels :param height: Plot height in pixels + :param style: Style function to be used. Should have the signature (surf:Surface, points:List[Tuple]) :param glide: y-axis glide value. A glide value above 1 will adjust the y range gradually. A value of 1 will make the y range snap to the new value. Any value below 1 will only increase the y range. - :param xlabel: X-axis label - :param ylabel: Y-axis label + :param xlabel: x-axis label + :param ylabel: y-axis label + :param time_range: x-axis range width """ super().__init__(width, height, xlabel=xlabel, ylabel=ylabel) @@ -214,10 +217,19 @@ def add(self, data): i += 1 self.buffer = self.buffer[i - 1 :] - def reset(self): + def clear_buffer(self): + """ + Removes all data from the buffer + """ self.buffer = [] def update(self, rel_mouse, events): + """ + Updates the plot, specifically the range + + :param rel_mouse: relative mouse position (unused) + :param events: Pygame event list (unused) + """ if len(self.buffer) < 2: return @@ -246,6 +258,9 @@ def update(self, rel_mouse, events): self.set_range((xmin, xmax), (ymin, ymax)) def draw(self): + """ + Draw the plot + """ self.clear() self.plot(self.buffer, self.style) super().draw() From bcb30d8c244de551eb9e589d06285c8143cb64cb Mon Sep 17 00:00:00 2001 From: Jason Zhang Date: Tue, 6 Sep 2022 21:25:34 -0700 Subject: [PATCH 05/13] DOES NOT WORK but what I'm going for --- guipy/components/slider.py | 18 ++++++++++++------ guipy/components/switch.py | 4 ++-- 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/guipy/components/slider.py b/guipy/components/slider.py index 45987c2..1f8d357 100644 --- a/guipy/components/slider.py +++ b/guipy/components/slider.py @@ -34,22 +34,28 @@ def get_val(self): """ return self.val - def draw(self): + def _draw(self): """ Renders slider onto surface """ - self.root.fill((0, 0, 0, 0)) + surf = pygame.Surface(self.width, self.height) + surf.fill((0, 0, 0, 0)) p1 = (self.r, self.height // 2) p2 = (self.width - self.r, self.height // 2) pVal = (self.r + self.val * (self.width - self.r * 2), self.height // 2) - pygame.draw.line(self.root, (57, 189, 248), p1, pVal, self.thickness) - pygame.draw.line(self.root, (200, 200, 200), pVal, p2, self.thickness) + pygame.draw.line(surf, (57, 189, 248), p1, pVal, self.thickness) + pygame.draw.line(surf, (200, 200, 200), pVal, p2, self.thickness) - pygame.draw.circle(self.root, (0, 0, 0), pVal, self.r) - pygame.draw.circle(self.root, (255, 255, 255), pVal, self.r - 3) + pygame.draw.circle(surf, (0, 0, 0), pVal, self.r) + pygame.draw.circle(surf, (255, 255, 255), pVal, self.r - 3) + + return surf + + def render(self): + self.root = self._draw() def update(self, rel_mouse, events): """ diff --git a/guipy/components/switch.py b/guipy/components/switch.py index df6fcd5..791fca2 100644 --- a/guipy/components/switch.py +++ b/guipy/components/switch.py @@ -42,7 +42,7 @@ def set_funcs(self, on_func=None, off_func=None): self.off_func = off_func return self - def _render(self): + def _draw(self): spacer = 3 corner = 7 alpha = 200 @@ -67,7 +67,7 @@ def _render(self): pygame.draw.rect(surf, GREY, rect, 0, corner) pygame.draw.rect(surf, BLACK, rect, 1, corner) - def draw(self): + def render(self): """ Draws the switch dependant on the state """ From a08a9bf4f7fc2d1ca02643943942eb6b1009b35e Mon Sep 17 00:00:00 2001 From: CaseyHackerMan Date: Wed, 7 Sep 2022 17:35:02 -0700 Subject: [PATCH 06/13] what he was going for and some other stuff that I don't feel like listing --- guipy/components/_component.py | 30 +++++++++++--- guipy/components/button.py | 57 +++++++++++++------------- guipy/components/plot.py | 16 ++++---- guipy/components/slider.py | 56 ++++++++++--------------- guipy/components/switch.py | 53 +++++++++--------------- guipy/components/textbox.py | 74 ++++++++++++++++------------------ guipy/manager.py | 3 +- guipy/utils.py | 4 ++ tests/button_test.py | 8 ++-- tests/slider_test.py | 6 +-- tests/switch_test.py | 19 +++++---- 11 files changed, 157 insertions(+), 169 deletions(-) diff --git a/guipy/components/_component.py b/guipy/components/_component.py index 162a50b..4b63636 100644 --- a/guipy/components/_component.py +++ b/guipy/components/_component.py @@ -3,16 +3,34 @@ class Component: def __init__(self, width, height): + """ + Component init. Should create a surface for the component + """ self.width = width self.height = height + self.root = pygame.Surface((width, height)) - self.root = pygame.Surface((width, height)).convert_alpha() + def _draw(self): + """ + All the drawing + """ - def get_surf(self): - return self.root + def render(self): + """ + Makes sure the root is ready to be used. - def draw(self): - pass + :return: Surface + """ + self._draw() + return self.root def update(self, rel_mouse, events): - pass + """ + Update the component. Should not draw anything, just change state. + + :param rel_mouse: Mouse position relative to the component + :param events: Pygame event list + """ + + def _collide(self, rel_mouse): + return 0 <= rel_mouse[0] < self.width and 0 <= rel_mouse[1] < self.height diff --git a/guipy/components/button.py b/guipy/components/button.py index 7f3839a..abf7ea8 100644 --- a/guipy/components/button.py +++ b/guipy/components/button.py @@ -8,7 +8,7 @@ class Button(Component): Button component """ - def __init__(self, width=None, height=None, font=None, text="Bruh", func=None): + def __init__(self, width=None, height=None, font=None, text="Bruh"): """ Button init @@ -29,17 +29,16 @@ def __init__(self, width=None, height=None, font=None, text="Bruh", func=None): if height == None: height = min_h - super().__init__(width, height) - self.off_surf = self.root.copy() - self.on_surf = self.root.copy() - self.root = self.off_surf + self.width = width + self.height = height + self.off_surf = pygame.Surface((self.width, self.height)).convert_alpha() + self.on_surf = pygame.Surface((self.width, self.height)).convert_alpha() self.pressed = False - self.prev_mouse_down = False - self.text = text - self._render() - self.set_func(func) + self.set_text(text) + + self.cb = None def get_val(self): """ @@ -47,19 +46,19 @@ def get_val(self): """ return self.pressed - def set_func(self, func): + def set_callback(self, cb): """ Set the function to be run when button is released :param func: Function with signature (button:Button) """ - self.func = func + self.cb = cb return self - def _render(self): + def _draw(self): text_surf = self.font.render(self.text, True, BLACK) - x, y = sub_vector(self.root.get_size(), text_surf.get_size()) + x, y = sub_vector((self.width, self.height), text_surf.get_size()) pos = (x // 2, y // 2) self.off_surf.fill(TRANSPARENT) @@ -81,18 +80,18 @@ def set_text(self, text): :param text: """ self.text = text - self._render() + self._draw() return self - def draw(self): + def render(self): """ Renders the button """ if self.pressed: - self.root = self.on_surf + return self.on_surf else: - self.root = self.off_surf + return self.off_surf def update(self, rel_mouse, events): """ @@ -101,18 +100,20 @@ def update(self, rel_mouse, events): :param rel_mouse: Relative mouse position :param events: Pygame Event list """ + on_click = False + on_release = False + for event in events: + if event.type == pygame.MOUSEBUTTONDOWN: + on_click = True + if event.type == pygame.MOUSEBUTTONUP: + on_release = True - mouse_down = pygame.mouse.get_pressed()[0] - - in_comp = self.root.get_rect().collidepoint(rel_mouse) - on_release = not mouse_down and self.prev_mouse_down + in_comp = self._collide(rel_mouse) - if self.pressed and on_release: - self.pressed = False - if self.func != None: - self.func(self) - - if mouse_down and in_comp: + if on_click and in_comp: self.pressed = True - self.prev_mouse_down = mouse_down + if on_release and self.pressed: + if in_comp and self.cb != None: + self.cb(self) + self.pressed = False diff --git a/guipy/components/plot.py b/guipy/components/plot.py index 676b407..407543a 100644 --- a/guipy/components/plot.py +++ b/guipy/components/plot.py @@ -31,7 +31,8 @@ def __init__(self, width, height, xlabel=None, ylabel=None): :param xlabel: X-axis label :param ylabel: Y-axis label """ - super().__init__(width, height) + self.width = width + self.height = height self.xlabel = xlabel self.ylabel = ylabel @@ -46,7 +47,7 @@ def __init__(self, width, height, xlabel=None, ylabel=None): self.points = [] self.font = get_default_font() - + self.root = pygame.Surface((self.width, self.height)).convert_alpha() self.window = pygame.Surface( (width - self.yaxis_spacer, height - self.xaxis_spacer) ) @@ -64,7 +65,7 @@ def _y(self, y): # coordinate to pixel y, self.ymax, self.ymin, self._windrect.top, self._windrect.bottom ) - def _render(self): + def _draw(self): w = self.window.get_width() h = self.window.get_height() @@ -138,7 +139,7 @@ def set_range(self, xrange, yrange): self.ymin = yrange[0] self.ymax = yrange[1] - self._render() + self._draw() def plot(self, data, style=line): """ @@ -157,12 +158,13 @@ def clear(self): """ self.window.fill(WHITE) - def draw(self): + def render(self): """ Draws the window onto the plot """ self.root.blit(self.window, (0, 0)) pygame.draw.rect(self.root, BLACK, self.window.get_rect(), 1) + return self.root class LivePlot(Plot): @@ -257,10 +259,10 @@ def update(self, rel_mouse, events): self.set_range((xmin, xmax), (ymin, ymax)) - def draw(self): + def render(self): """ Draw the plot """ self.clear() self.plot(self.buffer, self.style) - super().draw() + return super().render() diff --git a/guipy/components/slider.py b/guipy/components/slider.py index 1f8d357..5203e1f 100644 --- a/guipy/components/slider.py +++ b/guipy/components/slider.py @@ -1,5 +1,6 @@ import pygame from guipy.components._component import Component +from guipy.utils import * class Slider(Component): @@ -17,45 +18,33 @@ def __init__(self, width, height, thickness=2, radius=10, initial_val=0): :param radius: radius of knob :param initial_val: initial value of the slider (0.0 - 1.0) """ - super().__init__(width, height) + self.width = width + self.height = height + + self.root = pygame.Surface((self.width, self.height)).convert_alpha() self.thickness = thickness self.val = initial_val self.r = radius self.grabbed = False - self.prev_mouse_down = False - - def get_val(self): - """ - Get the value of the slider - - :return current value of slider (0.0 - 1.0) - """ - return self.val def _draw(self): """ - Renders slider onto surface + Draws slider onto root """ - surf = pygame.Surface(self.width, self.height) - surf.fill((0, 0, 0, 0)) + self.root.fill((0, 0, 0, 0)) p1 = (self.r, self.height // 2) p2 = (self.width - self.r, self.height // 2) pVal = (self.r + self.val * (self.width - self.r * 2), self.height // 2) - pygame.draw.line(surf, (57, 189, 248), p1, pVal, self.thickness) - pygame.draw.line(surf, (200, 200, 200), pVal, p2, self.thickness) + pygame.draw.line(self.root, (57, 189, 248), p1, pVal, self.thickness) + pygame.draw.line(self.root, (200, 200, 200), pVal, p2, self.thickness) - pygame.draw.circle(surf, (0, 0, 0), pVal, self.r) - pygame.draw.circle(surf, (255, 255, 255), pVal, self.r - 3) - - return surf - - def render(self): - self.root = self._draw() + pygame.draw.circle(self.root, (0, 0, 0), pVal, self.r) + pygame.draw.circle(self.root, (255, 255, 255), pVal, self.r - 3) def update(self, rel_mouse, events): """ @@ -63,26 +52,23 @@ def update(self, rel_mouse, events): :param rel_mouse: relative mouse position based on slider position """ - mouse_down = pygame.mouse.get_pressed()[0] + on_click = False + on_release = False + for event in events: + if event.type == pygame.MOUSEBUTTONDOWN: + on_click = True + if event.type == pygame.MOUSEBUTTONUP: + on_release = True - # TODO put this in parent class - in_comp = 0 <= rel_mouse[0] < self.width and 0 <= rel_mouse[1] < self.height - on_click = mouse_down and not self.prev_mouse_down + in_comp = self._collide(rel_mouse) if in_comp and on_click: self.grabbed = True - if not mouse_down: + if on_release: self.grabbed = False if self.grabbed: new_val = (rel_mouse[0] - self.r) / (self.width - 2 * self.r) - if new_val < 0: - new_val = 0 - elif new_val > 1: - new_val = 1 # TODO add to parent class / helper classes/functions - - self.val = new_val - - self.prev_mouse_down = mouse_down + self.val = clip(new_val, 0, 1) diff --git a/guipy/components/switch.py b/guipy/components/switch.py index 791fca2..33b301f 100644 --- a/guipy/components/switch.py +++ b/guipy/components/switch.py @@ -15,31 +15,24 @@ def __init__(self, width, height): :param width: Width in pixels :param height: Height in pixels """ - super().__init__(width, height) - self.off_surf = self.root.copy() - self.on_surf = self.root.copy() + self.width = width + self.height = height - self.state = False - self.prev_mouse_down = False - self.root = self.off_surf + self.off_surf = pygame.Surface((self.width, self.height)).convert_alpha() + self.on_surf = pygame.Surface((self.width, self.height)).convert_alpha() - self._render() + self.state = False + self.cb = None - def get_val(self): - """ - Gets the state of the switch as a boolean - """ - return self.state + self._draw() - def set_funcs(self, on_func=None, off_func=None): + def set_callback(self, cb): """ - Sets the functions to run when the switch is turned on or off + Sets the function to run when the switch is changed - :param on_func: Function to run when the switch is turned on - :param off_func: Function to run when the switch is turned off + :param cb: Callback function """ - self.on_func = on_func - self.off_func = off_func + self.cb = cb return self def _draw(self): @@ -72,9 +65,9 @@ def render(self): Draws the switch dependant on the state """ if self.state: - self.root = self.on_surf + return self.on_surf else: - self.root = self.off_surf + return self.off_surf def update(self, rel_mouse, events): """ @@ -83,20 +76,14 @@ def update(self, rel_mouse, events): :param rel_mouse: Relative mouse position :param events: Pygame Event list """ + on_click = False + for event in events: + if event.type == pygame.MOUSEBUTTONDOWN: + on_click = True - mouse_down = pygame.mouse.get_pressed()[0] - - in_comp = self.root.get_rect().collidepoint(rel_mouse) - on_click = mouse_down and not self.prev_mouse_down + if on_click and self._collide(rel_mouse): - if on_click and in_comp: self.state = not self.state - if self.state: - if self.on_func != None: - self.on_func() - else: - if self.off_func != None: - self.off_func() - - self.prev_mouse_down = mouse_down + if self.cb != None: + self.cb(self) diff --git a/guipy/components/textbox.py b/guipy/components/textbox.py index 5835525..c7cfa40 100644 --- a/guipy/components/textbox.py +++ b/guipy/components/textbox.py @@ -21,43 +21,43 @@ def __init__(self, width, font=None, default_text="Type here..."): else: self.font = font - height = font.get_height() + 6 - super().__init__(width, height) + self.width = width + self.height = font.get_height() + 6 + self.root = pygame.Surface((self.width, self.height)) - self.active = False - self.prev_mouse_down = False self.text = "" - self.text_surf = font.render(default_text, True, (200, 200, 200)) - self.default = self.text_surf - self.func = None + self.default = default_text - def get_val(self): - """ - Get current text - """ - return self.text + self.active = False + self.func = None def set_func(self, func): """ Set the function to be run when text is entered :param func: Function with signature (textbox:Textbox) + + :return: self """ self.func = func return self - def draw(self): + def _draw(self): """ - Renders the textbox + Draws the textbox """ - self.root.fill((0, 0, 0, 0)) + self.root.fill(WHITE) - pygame.draw.rect(self.root, (255, 255, 255), self.root.get_rect()) if self.active: pygame.draw.rect(self.root, (0, 0, 0), self.root.get_rect(), width=2) else: pygame.draw.rect(self.root, (0, 0, 0), self.root.get_rect(), width=1) - self.root.blit(self.text_surf, (4, 3)) + + if self.text: + text = self.font.render(self.text, True, BLACK) + else: + text = self.font.render(self.default, True, LIGHT_GREY) + self.root.blit(text, (4, 3)) def update(self, rel_mouse, events): """ @@ -66,33 +66,27 @@ def update(self, rel_mouse, events): :param rel_mouse: Relative mouse position :param events: Pygame Event list (used to read keypresses) """ - - mouse_down = pygame.mouse.get_pressed()[0] - - in_comp = self.root.get_rect().collidepoint(rel_mouse) - on_click = mouse_down and not self.prev_mouse_down + keydowns = [] + on_click = False + for event in events: + if event.type == pygame.KEYDOWN: + keydowns.append(event) + elif event.type == pygame.MOUSEBUTTONDOWN: + on_click = True if on_click: + in_comp = self._collide(rel_mouse) if self.active and not in_comp and self.func != None: self.func(self) self.active = in_comp if self.active: - - for event in events: - if event.type == pygame.KEYDOWN: - # check for backspace - if event.key == pygame.K_RETURN: - if self.func != None: - self.func(self) - elif event.key == pygame.K_BACKSPACE: - self.text = self.text[:-1] - else: # add character - self.text += event.unicode - - if len(self.text) > 0: - self.text_surf = self.font.render(self.text, True, (0, 0, 0)) - else: - self.text_surf = self.default - - self.prev_mouse_down = mouse_down + for event in keydowns: + # check for backspace + if event.key == pygame.K_RETURN: + if self.func != None: + self.func(self) + elif event.key == pygame.K_BACKSPACE: + self.text = self.text[:-1] + else: # add character + self.text += event.unicode diff --git a/guipy/manager.py b/guipy/manager.py index 786bca1..622920e 100644 --- a/guipy/manager.py +++ b/guipy/manager.py @@ -44,5 +44,4 @@ def draw(self, root): :param root: the surface these components should be drawn on """ for component in self.components: - component[0].draw() - root.blit(component[0].get_surf(), component[1]) + root.blit(component[0].render(), component[1]) diff --git a/guipy/utils.py b/guipy/utils.py index dbca839..070e763 100644 --- a/guipy/utils.py +++ b/guipy/utils.py @@ -46,6 +46,10 @@ def get_default_font(): return pygame.font.SysFont(font_name, 20) +def clip(value, min1, max1): + return max(min1, min(max1, value)) + + WHITE = (255, 255, 255) """ Preset for the color White diff --git a/tests/button_test.py b/tests/button_test.py index 4738fac..153f4cd 100644 --- a/tests/button_test.py +++ b/tests/button_test.py @@ -24,10 +24,10 @@ def func(button): root = pygame.display.set_mode((winW, winH)) man = GUIManager() -myButton1 = Button(width=200, func=func) -myButton2 = Button(width=200, func=func) -myButton3 = Button(width=200, func=func) -myButton4 = Button(width=200, func=func) +myButton1 = Button(width=200).set_callback(func) +myButton2 = Button(width=200).set_callback(func) +myButton3 = Button(width=200).set_callback(func) +myButton4 = Button(width=200).set_callback(func) man.add(myButton1, (10, 25)) man.add(myButton2, (10, 75)) diff --git a/tests/slider_test.py b/tests/slider_test.py index d3875f3..78fa6da 100644 --- a/tests/slider_test.py +++ b/tests/slider_test.py @@ -40,12 +40,10 @@ color = tuple( i * 255 - for i in colorsys.hls_to_rgb( - mySlider2.get_val(), mySlider3.get_val(), mySlider4.get_val() - ) + for i in colorsys.hls_to_rgb(mySlider2.val, mySlider3.val, mySlider4.val) ) center = (winW // 2, winH // 2) - r = 10 + mySlider.get_val() * 100 + r = 10 + mySlider.val * 100 pygame.draw.circle(root, color, center, r) pygame.draw.circle(root, BLACK, center, r, 3) diff --git a/tests/switch_test.py b/tests/switch_test.py index 41976b1..40e9ff9 100644 --- a/tests/switch_test.py +++ b/tests/switch_test.py @@ -13,12 +13,11 @@ from guipy.utils import * -def func1(): - print("on") - - -def func2(): - print("off") +def func1(switch): + if switch.state: + print("on") + else: + print("off") winW = 1280 @@ -27,10 +26,10 @@ def func2(): root = pygame.display.set_mode((winW, winH)) man = GUIManager() -mySwitch1 = Switch(width=20, height=10).set_funcs(on_func=func1, off_func=func2) -mySwitch2 = Switch(width=30, height=15).set_funcs(on_func=func1, off_func=func2) -mySwitch3 = Switch(width=60, height=30).set_funcs(on_func=func1, off_func=func2) -mySwitch4 = Switch(width=200, height=300).set_funcs(on_func=func1, off_func=func2) +mySwitch1 = Switch(width=20, height=10).set_callback(func1) +mySwitch2 = Switch(width=30, height=15).set_callback(func1) +mySwitch3 = Switch(width=60, height=30).set_callback(func1) +mySwitch4 = Switch(width=200, height=300).set_callback(func1) man.add(mySwitch1, (10, 25)) man.add(mySwitch2, (10, 75)) From 77d48e0607c0cbd19d3f3f9fe8b09cc2e0a084b9 Mon Sep 17 00:00:00 2001 From: Jason Zhang Date: Thu, 8 Sep 2022 00:52:52 -0700 Subject: [PATCH 07/13] Update --- guipy/manager.py | 16 ++++++---------- tests/button_test.py | 3 +-- tests/liveplot_test.py | 3 +-- tests/plot_test.py | 3 +-- tests/slider_test.py | 3 +-- tests/switch_test.py | 3 +-- tests/textbox_test.py | 4 ++-- 7 files changed, 13 insertions(+), 22 deletions(-) diff --git a/guipy/manager.py b/guipy/manager.py index 622920e..07a23b2 100644 --- a/guipy/manager.py +++ b/guipy/manager.py @@ -25,23 +25,19 @@ def add(self, component, pos): """ self.components.append((component, pos)) - def update(self, mouse_pos, events): + def update(self, mouse_pos, events, root): """ - Update all components in the manager + Update all components in the manager, and render onto root :param mouse_pos: Mouse position used to update the components so components understand the relative location :param events: pygame events used to update the components - """ - for component in self.components: - rel_mouse = sub_vector(mouse_pos, component[1]) - component[0].update(rel_mouse, events) - - def draw(self, root): - """ - Render all components unto a surface :param root: the surface these components should be drawn on """ for component in self.components: root.blit(component[0].render(), component[1]) + + for component in self.components: + rel_mouse = sub_vector(mouse_pos, component[1]) + component[0].update(rel_mouse, events) diff --git a/tests/button_test.py b/tests/button_test.py index 153f4cd..17d10b8 100644 --- a/tests/button_test.py +++ b/tests/button_test.py @@ -41,6 +41,5 @@ def func(button): root.fill(WHITE) - man.update(pygame.mouse.get_pos(), events) - man.draw(root) + man.update(pygame.mouse.get_pos(), events, root) pygame.display.update() diff --git a/tests/liveplot_test.py b/tests/liveplot_test.py index 94307fa..07069e4 100644 --- a/tests/liveplot_test.py +++ b/tests/liveplot_test.py @@ -36,7 +36,6 @@ myPlot1.add([(time.time(), p[1])]) - man.update(p, []) - man.draw(root) + man.update(p, [], root) pygame.display.update() diff --git a/tests/plot_test.py b/tests/plot_test.py index 7e7d1a8..aaa6e58 100644 --- a/tests/plot_test.py +++ b/tests/plot_test.py @@ -46,6 +46,5 @@ [(10, 60), (10, 40), (0, 30), (0, 10), (10, 0), (20, 10), (20, 30), (15, 35)] ) - man.draw(root) - # man.update(pygame.mouse.get_pos(),events) + man.update(pygame.mouse.get_pos(), events, root) pygame.display.update() diff --git a/tests/slider_test.py b/tests/slider_test.py index 78fa6da..e3eb716 100644 --- a/tests/slider_test.py +++ b/tests/slider_test.py @@ -47,6 +47,5 @@ pygame.draw.circle(root, color, center, r) pygame.draw.circle(root, BLACK, center, r, 3) - man.draw(root) - man.update(pygame.mouse.get_pos(), events) + man.update(pygame.mouse.get_pos(), events, root) pygame.display.update() diff --git a/tests/switch_test.py b/tests/switch_test.py index 40e9ff9..23e9f05 100644 --- a/tests/switch_test.py +++ b/tests/switch_test.py @@ -43,6 +43,5 @@ def func1(switch): root.fill(WHITE) - man.update(pygame.mouse.get_pos(), events) - man.draw(root) + man.update(pygame.mouse.get_pos(), events, root) pygame.display.update() diff --git a/tests/textbox_test.py b/tests/textbox_test.py index be881d6..dc22171 100644 --- a/tests/textbox_test.py +++ b/tests/textbox_test.py @@ -34,6 +34,6 @@ if event.type == pygame.QUIT: sys.exit() root.fill((200, 200, 200)) - man.draw(root) - man.update(pygame.mouse.get_pos(), events) + + man.update(pygame.mouse.get_pos(), events, root) pygame.display.update() From da23a13222716c389ee81ff66c3d0cc965ef7d31 Mon Sep 17 00:00:00 2001 From: Casey Date: Thu, 8 Sep 2022 11:02:10 -0700 Subject: [PATCH 08/13] added Dropdown component and test Dropdown is in menu.py --- guipy/components/menu.py | 142 +++++++++++++++++++++++++++++++++++++++ tests/menu_test.py | 47 +++++++++++++ 2 files changed, 189 insertions(+) create mode 100644 guipy/components/menu.py create mode 100644 tests/menu_test.py diff --git a/guipy/components/menu.py b/guipy/components/menu.py new file mode 100644 index 0000000..45d3d18 --- /dev/null +++ b/guipy/components/menu.py @@ -0,0 +1,142 @@ +import pygame +from guipy.components._component import Component +from guipy.utils import * + + +class Dropdown(Component): + """ + Dropdown menu component + """ + + def __init__(self, width, font=None): + """ + Dropdown init + + :param width: Menu width in pixels + :param font: pygame Font object to use + """ + if font == None: + self.font = get_default_font() + else: + self.font = font + + self.height = self.font.get_linesize() + self.width = max(self.height, width) + + self.open = False + self.value = None + self.highlighted = -1 + self.options = [] + + self.cb = None + + self._draw() + + def set_callback(self, cb): + """ + Set the function to be run when button is released + + :param func: Function with signature (button:Button) + """ + self.cb = cb + return self + + def _draw(self): + w = self.width - self.height + n = len(self.options) + if self.open: + self.root = pygame.Surface( + (self.width, self.height * (n + 1)) + ).convert_alpha() + self.root.fill((200, 200, 200, 150)) + + for i in range(n): + y = (i + 1) * self.height + if i == self.highlighted: + box = pygame.Rect(0, y, self.width, self.height) + pygame.draw.rect(self.root, (170, 170, 170, 150), box) + text = self.font.render(str(self.options[i]), True, BLACK) + self.root.blit(text, (3, y)) + else: + self.root = pygame.Surface((self.width, self.height)).convert_alpha() + + box = pygame.Rect(0, 0, self.width, self.height) + pygame.draw.rect(self.root, WHITE, box) + if self.value != None: + text = self.font.render(str(self.value), True, BLACK) + self.root.blit(text, (3, 0)) + arrow = pygame.Rect(self.width - self.height, 0, self.height, self.height) + pygame.draw.rect(self.root, GREY, arrow) + y = self.height // 2 + x = y + w + if self.open: + pygame.draw.line( + self.root, + WHITE, + (x, y - self.height // 6), + (x - self.height // 3, y + self.height // 6), + 2, + ) + pygame.draw.line( + self.root, + WHITE, + (x, y - self.height // 6), + (x + self.height // 3, y + self.height // 6), + 2, + ) + else: + pygame.draw.line( + self.root, + WHITE, + (x, y + self.height // 6), + (x - self.height // 3, y - self.height // 6), + 2, + ) + pygame.draw.line( + self.root, + WHITE, + (x, y + self.height // 6), + (x + self.height // 3, y - self.height // 6), + 2, + ) + pygame.draw.rect(self.root, BLACK, self.root.get_rect(), 1) + + def render(self): + return self.root + + def add(self, *options): + self.options += options + return self + + def update(self, rel_mouse, events): + """ + Update the dropdown menu + + :param rel_mouse: Relative mouse position + :param events: Pygame Event list + """ + on_click = False + for event in events: + if event.type == pygame.MOUSEBUTTONDOWN: + on_click = True + + in_width = 0 <= rel_mouse[0] < self.width + index = rel_mouse[1] // self.height - 1 + + if self.open: + if 0 <= index < len(self.options) and in_width: + self.highlighted = index + if on_click: + self.value = self.options[index] + if not self.cb == None: + self.cb(self) + else: + self.highlighted = -1 + if on_click: + self.open = False + self.highlighted = -1 + self._draw() + + else: + if on_click and in_width and index == -1: + self.open = True diff --git a/tests/menu_test.py b/tests/menu_test.py new file mode 100644 index 0000000..17a726c --- /dev/null +++ b/tests/menu_test.py @@ -0,0 +1,47 @@ +import sys +import os +import inspect + +import pygame + +currentdir = os.path.dirname(os.path.abspath(inspect.getfile(inspect.currentframe()))) +parentdir = os.path.dirname(currentdir) +sys.path.insert(0, parentdir) + +from guipy.manager import GUIManager +from guipy.components.menu import * +from guipy.components.switch import * +from guipy.utils import * + + +def func(menu): + print(menu.value) + + +winW = 1280 +winH = 720 + +root = pygame.display.set_mode((winW, winH)) + + +myFont = pygame.font.SysFont("Microsoft Sans Serif", 20) +man = GUIManager() +myMenu1 = ( + Dropdown(200, myFont).add("A", "B", "C", "D", "Bruh", 1 / 7).set_callback(func) +) + + +man.add(myMenu1, (100, 100)) + + +while True: + events = pygame.event.get() + for event in events: + if event.type == pygame.QUIT: + sys.exit() + + root.fill(LIGHT_GREY) + + man.update(pygame.mouse.get_pos(), events) + man.draw(root) + pygame.display.update() From 99378f487e1565e6ca9979b8935976a7935eb5b1 Mon Sep 17 00:00:00 2001 From: CaseyHackerMan Date: Thu, 8 Sep 2022 13:38:11 -0700 Subject: [PATCH 09/13] various updates Mainly combined render() and update() for all components, and added back get_surf() method. --- guipy/components/_component.py | 17 ++++++----------- guipy/components/button.py | 10 ++++------ guipy/components/menu.py | 7 ++----- guipy/components/plot.py | 23 +++++++++-------------- guipy/components/slider.py | 2 ++ guipy/components/switch.py | 4 ++-- guipy/components/textbox.py | 22 +++++++++++----------- guipy/manager.py | 3 +-- tests/menu_test.py | 9 ++++----- 9 files changed, 41 insertions(+), 56 deletions(-) diff --git a/guipy/components/_component.py b/guipy/components/_component.py index 4b63636..8677012 100644 --- a/guipy/components/_component.py +++ b/guipy/components/_component.py @@ -15,22 +15,17 @@ def _draw(self): All the drawing """ - def render(self): - """ - Makes sure the root is ready to be used. - - :return: Surface - """ - self._draw() + def get_surf(self): return self.root + def _collide(self, rel_mouse): + return 0 <= rel_mouse[0] < self.width and 0 <= rel_mouse[1] < self.height + def update(self, rel_mouse, events): """ - Update the component. Should not draw anything, just change state. + Update the component. Usually calls :param rel_mouse: Mouse position relative to the component :param events: Pygame event list """ - - def _collide(self, rel_mouse): - return 0 <= rel_mouse[0] < self.width and 0 <= rel_mouse[1] < self.height + self._draw() diff --git a/guipy/components/button.py b/guipy/components/button.py index abf7ea8..94f3c4f 100644 --- a/guipy/components/button.py +++ b/guipy/components/button.py @@ -16,7 +16,6 @@ def __init__(self, width=None, height=None, font=None, text="Bruh"): :param height: button height in pixels, defaults to fit text :param font: pygame Font object to use :param text: text to display on the button - :param func: function to run when button is released """ if font == None: self.font = get_default_font() @@ -48,9 +47,9 @@ def get_val(self): def set_callback(self, cb): """ - Set the function to be run when button is released + Set the callback to be run when the button is released - :param func: Function with signature (button:Button) + :param cb: Callback function """ self.cb = cb return self @@ -83,11 +82,10 @@ def set_text(self, text): self._draw() return self - def render(self): + def get_surf(self): """ - Renders the button + Get the button's surface """ - if self.pressed: return self.on_surf else: diff --git a/guipy/components/menu.py b/guipy/components/menu.py index 45d3d18..e3cbb8b 100644 --- a/guipy/components/menu.py +++ b/guipy/components/menu.py @@ -34,9 +34,9 @@ def __init__(self, width, font=None): def set_callback(self, cb): """ - Set the function to be run when button is released + Set the callback to be run when a new option is selected - :param func: Function with signature (button:Button) + :param cb: Callback function """ self.cb = cb return self @@ -101,9 +101,6 @@ def _draw(self): ) pygame.draw.rect(self.root, BLACK, self.root.get_rect(), 1) - def render(self): - return self.root - def add(self, *options): self.options += options return self diff --git a/guipy/components/plot.py b/guipy/components/plot.py index 407543a..0a53146 100644 --- a/guipy/components/plot.py +++ b/guipy/components/plot.py @@ -123,9 +123,12 @@ def _draw(self): p = (self.width - label.get_width(), (h - label.get_height()) / 2) self.root.blit(label, p) + self.root.blit(self.window, (0, 0)) + pygame.draw.rect(self.root, BLACK, self.window.get_rect(), 1) + def set_range(self, xrange, yrange): """ - Sets the plot X and Y range and draws the axes using the new range. + Sets the plot X and Y range :param xrange: List of minimum and maximum X values. ex: (0,100) :param yrange: List of minimum and maximum Y values. ex: (0,100) @@ -139,8 +142,6 @@ def set_range(self, xrange, yrange): self.ymin = yrange[0] self.ymax = yrange[1] - self._draw() - def plot(self, data, style=line): """ Plots a list of points @@ -158,13 +159,11 @@ def clear(self): """ self.window.fill(WHITE) - def render(self): + def update(self, rel_mouse, events): """ - Draws the window onto the plot + Update the plot """ - self.root.blit(self.window, (0, 0)) - pygame.draw.rect(self.root, BLACK, self.window.get_rect(), 1) - return self.root + self._draw() class LivePlot(Plot): @@ -227,7 +226,7 @@ def clear_buffer(self): def update(self, rel_mouse, events): """ - Updates the plot, specifically the range + Updates the plot :param rel_mouse: relative mouse position (unused) :param events: Pygame event list (unused) @@ -259,10 +258,6 @@ def update(self, rel_mouse, events): self.set_range((xmin, xmax), (ymin, ymax)) - def render(self): - """ - Draw the plot - """ self.clear() self.plot(self.buffer, self.style) - return super().render() + super().update(rel_mouse, events) diff --git a/guipy/components/slider.py b/guipy/components/slider.py index 5203e1f..53dd0e2 100644 --- a/guipy/components/slider.py +++ b/guipy/components/slider.py @@ -72,3 +72,5 @@ def update(self, rel_mouse, events): new_val = (rel_mouse[0] - self.r) / (self.width - 2 * self.r) self.val = clip(new_val, 0, 1) + + self._draw() diff --git a/guipy/components/switch.py b/guipy/components/switch.py index 33b301f..9bffd12 100644 --- a/guipy/components/switch.py +++ b/guipy/components/switch.py @@ -60,9 +60,9 @@ def _draw(self): pygame.draw.rect(surf, GREY, rect, 0, corner) pygame.draw.rect(surf, BLACK, rect, 1, corner) - def render(self): + def get_surf(self): """ - Draws the switch dependant on the state + Gets the component's surface """ if self.state: return self.on_surf diff --git a/guipy/components/textbox.py b/guipy/components/textbox.py index c7cfa40..bbd88b7 100644 --- a/guipy/components/textbox.py +++ b/guipy/components/textbox.py @@ -22,7 +22,7 @@ def __init__(self, width, font=None, default_text="Type here..."): self.font = font self.width = width - self.height = font.get_height() + 6 + self.height = font.get_height() + 4 self.root = pygame.Surface((self.width, self.height)) self.text = "" @@ -33,11 +33,9 @@ def __init__(self, width, font=None, default_text="Type here..."): def set_func(self, func): """ - Set the function to be run when text is entered + Set the callback to be run when the textbox is unselected, or enter is pressed - :param func: Function with signature (textbox:Textbox) - - :return: self + :param cb: Callback function """ self.func = func return self @@ -48,16 +46,16 @@ def _draw(self): """ self.root.fill(WHITE) - if self.active: - pygame.draw.rect(self.root, (0, 0, 0), self.root.get_rect(), width=2) - else: - pygame.draw.rect(self.root, (0, 0, 0), self.root.get_rect(), width=1) - if self.text: text = self.font.render(self.text, True, BLACK) else: text = self.font.render(self.default, True, LIGHT_GREY) - self.root.blit(text, (4, 3)) + self.root.blit(text, (4, 1)) + + if self.active: + pygame.draw.rect(self.root, (0, 0, 0), self.root.get_rect(), width=2) + else: + pygame.draw.rect(self.root, (0, 0, 0), self.root.get_rect(), width=1) def update(self, rel_mouse, events): """ @@ -90,3 +88,5 @@ def update(self, rel_mouse, events): self.text = self.text[:-1] else: # add character self.text += event.unicode + + self._draw() diff --git a/guipy/manager.py b/guipy/manager.py index 07a23b2..b393f32 100644 --- a/guipy/manager.py +++ b/guipy/manager.py @@ -35,9 +35,8 @@ def update(self, mouse_pos, events, root): :param root: the surface these components should be drawn on """ - for component in self.components: - root.blit(component[0].render(), component[1]) for component in self.components: rel_mouse = sub_vector(mouse_pos, component[1]) component[0].update(rel_mouse, events) + root.blit(component[0].get_surf(), component[1]) diff --git a/tests/menu_test.py b/tests/menu_test.py index 17a726c..8f3e122 100644 --- a/tests/menu_test.py +++ b/tests/menu_test.py @@ -26,11 +26,11 @@ def func(menu): myFont = pygame.font.SysFont("Microsoft Sans Serif", 20) man = GUIManager() -myMenu1 = ( - Dropdown(200, myFont).add("A", "B", "C", "D", "Bruh", 1 / 7).set_callback(func) -) +myMenu1 = Dropdown(200, myFont).add("A", "B", "C", "D").set_callback(func) +myMenu2 = Dropdown(200, myFont).add(1, 2, 3, 4).set_callback(func) +man.add(myMenu2, (150, 150)) man.add(myMenu1, (100, 100)) @@ -42,6 +42,5 @@ def func(menu): root.fill(LIGHT_GREY) - man.update(pygame.mouse.get_pos(), events) - man.draw(root) + man.update(pygame.mouse.get_pos(), events, root) pygame.display.update() From e44f4d9f3201236d63577c55def1b5c5500a6104 Mon Sep 17 00:00:00 2001 From: Casey Date: Tue, 8 Aug 2023 14:59:17 -0700 Subject: [PATCH 10/13] added Text component --- guipy/components/text.py | 58 ++++++++++++++++++++++++++++++++++++++++ tests/text_test.py | 46 +++++++++++++++++++++++++++++++ 2 files changed, 104 insertions(+) create mode 100644 guipy/components/text.py create mode 100644 tests/text_test.py diff --git a/guipy/components/text.py b/guipy/components/text.py new file mode 100644 index 0000000..31bad57 --- /dev/null +++ b/guipy/components/text.py @@ -0,0 +1,58 @@ +import pygame +from guipy.components._component import Component +from guipy.utils import * + + +class Text(Component): + """ + Text component for displaying text + """ + + def __init__(self, font=None, default_text="Your text here!", color=BLACK): + """ + Text init + + :param font: Pygame Font object to be used + :param default_text: Text to be shown + """ + if font == None: + self.font = get_default_font() + else: + self.font = font + + self.set_text(default_text, color) + self.func = None + + def set_func(self, func): + """ + Set the callback to be run when the text is selected + + :param cb: Callback function + """ + self.func = func + return self + + def set_text(self, text, color=None): + if color: self.color = color + self.text = text + self._draw() + self.width = self.root.get_width() + self.height = self.root.get_height() + + def _draw(self): + """ + Draws the textbox + """ + self.root = self.font.render(self.text, True, self.color) + + def update(self, rel_mouse, events): + """ + Update the textbox + + :param rel_mouse: Relative mouse position + :param events: Pygame Event list (used to read keypresses) + """ + for event in events: + if event.type == pygame.MOUSEBUTTONDOWN: + if (self._collide(rel_mouse)): + self.func(self) diff --git a/tests/text_test.py b/tests/text_test.py new file mode 100644 index 0000000..7afb2c3 --- /dev/null +++ b/tests/text_test.py @@ -0,0 +1,46 @@ +import sys +import os +import inspect + +import pygame + +currentdir = os.path.dirname(os.path.abspath(inspect.getfile(inspect.currentframe()))) +parentdir = os.path.dirname(currentdir) +sys.path.insert(0, parentdir) + +from guipy.manager import GUIManager +from guipy.components.text import Text + +def f(x): + print(x.text) + x.set_text(x.text+' beep') + +font1 = pygame.font.SysFont("Microsoft Sans Serif", 20) +font2 = pygame.font.SysFont("Comic Sans MS", 20) +font3 = pygame.font.SysFont("consolas", 20) +font4 = pygame.font.SysFont("arial", 20) + +winW = 1280 +winH = 720 + +root = pygame.display.set_mode((winW, winH)) + +man = GUIManager() +myText1 = Text(font1, default_text="I'm text!").set_func(f) +myText2 = Text(font2, default_text="I'm a label.").set_func(f) +myText3 = Text(font3, default_text="I'm a caption,").set_func(f) +myText4 = Text(font4, default_text="I'm a paragraph?").set_func(f) + +man.add(myText1, (10, 25)) +man.add(myText2, (400, 100)) +man.add(myText3, (10, 125)) +man.add(myText4, (300, 300)) +while True: + events = pygame.event.get() + for event in events: + if event.type == pygame.QUIT: + sys.exit() + root.fill((200, 200, 200)) + + man.update(pygame.mouse.get_pos(), events, root) + pygame.display.update() From d12c874c61c6e397dce95d079a2892d7eeadeccd Mon Sep 17 00:00:00 2001 From: Casey Date: Tue, 8 Aug 2023 15:00:45 -0700 Subject: [PATCH 11/13] Update text.py --- guipy/components/text.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/guipy/components/text.py b/guipy/components/text.py index 31bad57..85329b3 100644 --- a/guipy/components/text.py +++ b/guipy/components/text.py @@ -41,13 +41,13 @@ def set_text(self, text, color=None): def _draw(self): """ - Draws the textbox + Draws the text """ self.root = self.font.render(self.text, True, self.color) def update(self, rel_mouse, events): """ - Update the textbox + Update the text :param rel_mouse: Relative mouse position :param events: Pygame Event list (used to read keypresses) From 0ee0b0d5fab6b157abab98f4d81c1633bcaf058c Mon Sep 17 00:00:00 2001 From: Casey Date: Tue, 8 Aug 2023 15:06:36 -0700 Subject: [PATCH 12/13] linter --- guipy/components/text.py | 9 +++++---- tests/text_test.py | 4 +++- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/guipy/components/text.py b/guipy/components/text.py index 85329b3..4f67970 100644 --- a/guipy/components/text.py +++ b/guipy/components/text.py @@ -31,9 +31,10 @@ def set_func(self, func): """ self.func = func return self - + def set_text(self, text, color=None): - if color: self.color = color + if color: + self.color = color self.text = text self._draw() self.width = self.root.get_width() @@ -44,7 +45,7 @@ def _draw(self): Draws the text """ self.root = self.font.render(self.text, True, self.color) - + def update(self, rel_mouse, events): """ Update the text @@ -54,5 +55,5 @@ def update(self, rel_mouse, events): """ for event in events: if event.type == pygame.MOUSEBUTTONDOWN: - if (self._collide(rel_mouse)): + if self._collide(rel_mouse): self.func(self) diff --git a/tests/text_test.py b/tests/text_test.py index 7afb2c3..417396c 100644 --- a/tests/text_test.py +++ b/tests/text_test.py @@ -11,9 +11,11 @@ from guipy.manager import GUIManager from guipy.components.text import Text + def f(x): print(x.text) - x.set_text(x.text+' beep') + x.set_text(x.text + " beep") + font1 = pygame.font.SysFont("Microsoft Sans Serif", 20) font2 = pygame.font.SysFont("Comic Sans MS", 20) From 902de3f6a1df56af41b855572473877daf2c3a2f Mon Sep 17 00:00:00 2001 From: Casey Date: Tue, 8 Aug 2023 15:27:19 -0700 Subject: [PATCH 13/13] had to update linter --- guipy/components/switch.py | 1 - 1 file changed, 1 deletion(-) diff --git a/guipy/components/switch.py b/guipy/components/switch.py index 9bffd12..356edb8 100644 --- a/guipy/components/switch.py +++ b/guipy/components/switch.py @@ -82,7 +82,6 @@ def update(self, rel_mouse, events): on_click = True if on_click and self._collide(rel_mouse): - self.state = not self.state if self.cb != None: