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/__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/_component.py b/guipy/components/_component.py index 162a50b..8677012 100644 --- a/guipy/components/_component.py +++ b/guipy/components/_component.py @@ -3,16 +3,29 @@ 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 draw(self): - pass + 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): - pass + """ + Update the component. Usually calls + + :param rel_mouse: Mouse position relative to the component + :param events: Pygame event list + """ + self._draw() diff --git a/guipy/components/button.py b/guipy/components/button.py new file mode 100644 index 0000000..94f3c4f --- /dev/null +++ b/guipy/components/button.py @@ -0,0 +1,117 @@ +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"): + """ + 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 + """ + 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 + + 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.set_text(text) + + self.cb = None + + def get_val(self): + """ + Get current state + """ + return self.pressed + + def set_callback(self, cb): + """ + Set the callback to be run when the button is released + + :param cb: Callback function + """ + self.cb = cb + return self + + def _draw(self): + text_surf = self.font.render(self.text, True, BLACK) + + x, y = sub_vector((self.width, self.height), text_surf.get_size()) + pos = (x // 2, y // 2) + + 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.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) + + def set_text(self, text): + """ + Sets the text on the button and redraws the surface + + :param text: + """ + self.text = text + self._draw() + return self + + def get_surf(self): + """ + Get the button's surface + """ + if self.pressed: + return self.on_surf + else: + return self.off_surf + + def update(self, rel_mouse, events): + """ + Update the button + + :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 + + in_comp = self._collide(rel_mouse) + + if on_click and in_comp: + self.pressed = True + + if on_release and self.pressed: + if in_comp and self.cb != None: + self.cb(self) + self.pressed = False diff --git a/guipy/components/menu.py b/guipy/components/menu.py new file mode 100644 index 0000000..e3cbb8b --- /dev/null +++ b/guipy/components/menu.py @@ -0,0 +1,139 @@ +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 callback to be run when a new option is selected + + :param cb: Callback function + """ + 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 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/guipy/components/plot.py b/guipy/components/plot.py index f2ad18b..0a53146 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 @@ -45,10 +46,8 @@ 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.root = pygame.Surface((self.width, self.height)).convert_alpha() self.window = pygame.Surface( (width - self.yaxis_spacer, height - self.xaxis_spacer) ) @@ -66,18 +65,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 _draw(self): w = self.window.get_width() h = self.window.get_height() @@ -85,9 +73,11 @@ def set_range(self, xrange, yrange): # draw x-axis scale = math.floor(math.log10(self.xmax - self.xmin)) - 1 + if scale < -13: + scale = -13 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) @@ -109,6 +99,8 @@ def set_range(self, xrange, yrange): # 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 @@ -131,6 +123,25 @@ def set_range(self, xrange, yrange): 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 + + :param xrange: List of minimum and maximum X values. ex: (0,100) + :param yrange: List of minimum and maximum Y values. ex: (0,100) + """ + + 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] + def plot(self, data, style=line): """ Plots a list of points @@ -148,9 +159,105 @@ def clear(self): """ self.window.fill(WHITE) - def draw(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) + self._draw() + + +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 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 time_range: x-axis range width + """ + + 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 clear_buffer(self): + """ + Removes all data from the buffer + """ + self.buffer = [] + + def update(self, rel_mouse, events): + """ + Updates the plot + + :param rel_mouse: relative mouse position (unused) + :param events: Pygame event list (unused) + """ + 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)) + + self.clear() + self.plot(self.buffer, self.style) + super().update(rel_mouse, events) diff --git a/guipy/components/slider.py b/guipy/components/slider.py index 45987c2..53dd0e2 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,26 +18,20 @@ 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) + def _draw(self): """ - return self.val - - def draw(self): - """ - Renders slider onto surface + Draws slider onto root """ self.root.fill((0, 0, 0, 0)) @@ -57,26 +52,25 @@ 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.val = clip(new_val, 0, 1) - self.prev_mouse_down = mouse_down + self._draw() diff --git a/guipy/components/switch.py b/guipy/components/switch.py new file mode 100644 index 0000000..356edb8 --- /dev/null +++ b/guipy/components/switch.py @@ -0,0 +1,88 @@ +import pygame +from guipy.components._component import Component +from guipy.utils import * + + +class Switch(Component): + """ + Switch component + """ + + def __init__(self, width, height): + """ + Switch init + + :param width: Width in pixels + :param height: Height in pixels + """ + 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.state = False + self.cb = None + + self._draw() + + def set_callback(self, cb): + """ + Sets the function to run when the switch is changed + + :param cb: Callback function + """ + self.cb = cb + return self + + def _draw(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 get_surf(self): + """ + Gets the component's surface + """ + if self.state: + return self.on_surf + else: + return self.off_surf + + def update(self, rel_mouse, events): + """ + Update the switch + + :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 + + if on_click and self._collide(rel_mouse): + self.state = not self.state + + if self.cb != None: + self.cb(self) diff --git a/guipy/components/text.py b/guipy/components/text.py new file mode 100644 index 0000000..4f67970 --- /dev/null +++ b/guipy/components/text.py @@ -0,0 +1,59 @@ +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 text + """ + self.root = self.font.render(self.text, True, self.color) + + def update(self, rel_mouse, events): + """ + Update the text + + :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/guipy/components/textbox.py b/guipy/components/textbox.py index 196c558..bbd88b7 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,34 +16,46 @@ 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 """ - height = font.get_height() + 6 - super().__init__(width, height) + if font == None: + self.font = get_default_font() + else: + self.font = font + + self.width = width + self.height = font.get_height() + 4 + self.root = pygame.Surface((self.width, self.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.default = default_text + + self.active = False + self.func = None - def get_val(self): + def set_func(self, func): """ - Get current text + Set the callback to be run when the textbox is unselected, or enter is pressed + + :param cb: Callback function """ - return self.text + 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) + + 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, 1)) - 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)) def update(self, rel_mouse, events): """ @@ -51,29 +64,29 @@ 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: - self.active = False - 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 + + self._draw() diff --git a/guipy/manager.py b/guipy/manager.py index 3d6e327..b393f32 100644 --- a/guipy/manager.py +++ b/guipy/manager.py @@ -1,3 +1,6 @@ +from guipy.utils import * + + class GUIManager: """ GUI Manager @@ -22,24 +25,18 @@ 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 = tuple(i[0] - i[1] for i in zip(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: - component[0].draw() + 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/guipy/utils.py b/guipy/utils.py index ed12e28..070e763 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): + """ + Adds two vectors (a+b) + + :param a: + :param b: """ - Finds the relative coordinate of one point in another point + return (a[0] + b[0], a[1] + b[1]) - :param coord: the coordinate - :param offset: the coordinate relative to +def sub_vector(a, b): """ - return (coord[0] - offset[0], coord[1] - offset[1]) + Subtracts two vectors (a-b) + + :param a: + :param b: + """ + return (a[0] - b[0], a[1] - b[1]) def translate(value, min1, max1, min2, max2): @@ -23,10 +35,21 @@ 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) +def get_default_font(): + font_name = pygame.font.get_fonts()[0] + 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 @@ -47,7 +70,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 """ @@ -59,3 +86,7 @@ def translate(value, min1, max1, min2, max2): """ 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 new file mode 100644 index 0000000..17d10b8 --- /dev/null +++ b/tests/button_test.py @@ -0,0 +1,45 @@ +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).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)) +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.update(pygame.mouse.get_pos(), events, root) + pygame.display.update() diff --git a/tests/liveplot_test.py b/tests/liveplot_test.py new file mode 100644 index 0000000..07069e4 --- /dev/null +++ b/tests/liveplot_test.py @@ -0,0 +1,41 @@ +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, [], root) + + pygame.display.update() diff --git a/tests/menu_test.py b/tests/menu_test.py new file mode 100644 index 0000000..8f3e122 --- /dev/null +++ b/tests/menu_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.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").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)) + + +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, root) + pygame.display.update() diff --git a/tests/plot_test.py b/tests/plot_test.py index 29d5fe5..aaa6e58 100644 --- a/tests/plot_test.py +++ b/tests/plot_test.py @@ -10,8 +10,7 @@ from guipy.manager import GUIManager from guipy.components.plot import Plot - -pygame.init() +from guipy.utils import * winW = 1280 winH = 720 @@ -31,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 @@ -47,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 6df8707..e3eb716 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 @@ -41,13 +40,12 @@ 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.val * 100 + pygame.draw.circle(root, color, center, r) + pygame.draw.circle(root, BLACK, center, r, 3) - pygame.draw.circle(root, color, (winW / 2, winH / 2), 10 + mySlider.get_val() * 100) - - 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 new file mode 100644 index 0000000..23e9f05 --- /dev/null +++ b/tests/switch_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.switch import Switch +from guipy.utils import * + + +def func1(switch): + if switch.state: + print("on") + else: + print("off") + + +winW = 1280 +winH = 720 + +root = pygame.display.set_mode((winW, winH)) + +man = GUIManager() +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)) +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, root) + pygame.display.update() diff --git a/tests/text_test.py b/tests/text_test.py new file mode 100644 index 0000000..417396c --- /dev/null +++ b/tests/text_test.py @@ -0,0 +1,48 @@ +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() diff --git a/tests/textbox_test.py b/tests/textbox_test.py index 6ab0638..dc22171 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)) @@ -37,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()