From 2ddea8eaa315b788ebfb5ef0a3854e58741cfc52 Mon Sep 17 00:00:00 2001 From: Caojunwei <97785943+dvdcjw@users.noreply.github.com> Date: Sun, 14 Jul 2024 08:42:07 +0800 Subject: [PATCH 1/9] Update oGUI.py This way, the overlay window won't show a icon in taskbar --- src/oGUI.py | 274 +++++++++++++++++++++++++++------------------------- 1 file changed, 145 insertions(+), 129 deletions(-) diff --git a/src/oGUI.py b/src/oGUI.py index e024b0b..5bbe884 100644 --- a/src/oGUI.py +++ b/src/oGUI.py @@ -25,165 +25,181 @@ darkgray = (41, 41, 41) purple = (133, 55, 250) + def init(): - pygame.init() - pygame.display.set_caption('oGUI window') - print('') - print(f'OverlayGUI {version}') - print('oGUI package by EthanEDITS') - print('') - - win32gui.SetWindowLong(hwnd, win32con.GWL_EXSTYLE, - win32gui.GetWindowLong(hwnd, win32con.GWL_EXSTYLE) | win32con.WS_EX_LAYERED) - win32gui.SetLayeredWindowAttributes(hwnd, win32api.RGB(*fuchsia), 0, win32con.LWA_COLORKEY) - win32gui.SetWindowPos(hwnd, win32con.HWND_TOPMOST, 0, 0, 0, 0, win32con.SWP_NOSIZE) - -def startLoop(): - for event in pygame.event.get(): + pygame.init() + pygame.display.set_caption('oGUI window') + print('') + print(f'OverlayGUI {version}') + print('oGUI package by EthanEDITS') + print('') + + +win32gui.SetWindowLong(hwnd, win32con.GWL_EXSTYLE, + win32gui.GetWindowLong(hwnd, + win32con.GWL_EXSTYLE) | win32con.WS_EX_LAYERED | win32con.WS_EX_TOOLWINDOW) +win32gui.SetLayeredWindowAttributes(hwnd, win32api.RGB(*fuchsia), 0, win32con.LWA_COLORKEY) +win32gui.SetWindowPos(hwnd, win32con.HWND_TOPMOST, 0, 0, 0, 0, win32con.SWP_NOSIZE) + + +def startLoop(): + for event in pygame.event.get(): if event.type == pygame.QUIT: exit(0) - screen.fill(fuchsia) + screen.fill(fuchsia) + def endLoop(): - pygame.display.update() + pygame.display.update() + class Checkbox: - def __init__(self, outsideColor, insideColor, x, y, width, height, enabledByDefault = False): - self.outsideColor = outsideColor - self.insideColor = insideColor - self.x = x - self.y = y - self.width = width - self.height = height - self.checkBox_enabled = enabledByDefault - self.is_hoverable = False - self.hover_color = gray - self.boolMousePos = False + def __init__(self, outsideColor, insideColor, x, y, width, height, enabledByDefault=False): + self.outsideColor = outsideColor + self.insideColor = insideColor + self.x = x + self.y = y + self.width = width + self.height = height + self.checkBox_enabled = enabledByDefault + self.is_hoverable = False + self.hover_color = gray + self.boolMousePos = False - def is_hovered(self, hoveredColor): - self.is_hoverable = True - self.hover_color = hoveredColor + def is_hovered(self, hoveredColor): + self.is_hoverable = True + self.hover_color = hoveredColor + + def printMousePos(self): + self.boolMousePos = True - def printMousePos(self): - self.boolMousePos = True + def is_enabled(self): + return self.checkBox_enabled - def is_enabled(self): - return self.checkBox_enabled + def draw(self): + pygame.draw.rect(screen, self.outsideColor, + pygame.Rect(self.x - self.width / 8, self.y - self.height / 8, self.width + self.width / 4, + self.height + self.height / 4)) - def draw(self): - pygame.draw.rect(screen, self.outsideColor, pygame.Rect(self.x - self.width/8, self.y - self.height/8, self.width + self.width/4, self.height + self.height/4)) + mouse = pygame.mouse - mouse = pygame.mouse + if self.x + self.width > mouse.get_pos()[0] > self.x and self.y + self.height > mouse.get_pos()[1] > self.y: + # When Hovered Over + if self.is_hoverable: + pygame.draw.rect(screen, self.hover_color, + pygame.Rect(self.x - self.width / 8, self.y - self.height / 8, + self.width + self.width / 4, self.height + self.height / 4)) - if self.x + self.width > mouse.get_pos()[0] > self.x and self.y + self.height > mouse.get_pos()[1] > self.y: - #When Hovered Over - if self.is_hoverable: - pygame.draw.rect(screen, self.hover_color, pygame.Rect(self.x - self.width/8, self.y - self.height/8, self.width + self.width/4, self.height + self.height/4)) + # When clicked + if mouse.get_pressed()[0]: + self.checkBox_enabled = not self.checkBox_enabled + time.sleep(0.15) - #When clicked - if mouse.get_pressed()[0]: - self.checkBox_enabled = not self.checkBox_enabled - time.sleep(0.15) + if self.checkBox_enabled: + pygame.draw.rect(screen, self.insideColor, pygame.Rect(self.x, self.y, self.width, self.height)) - if self.checkBox_enabled: - pygame.draw.rect(screen, self.insideColor, pygame.Rect(self.x, self.y, self.width, self.height)) + if self.boolMousePos: + print(mouse.get_pos()) - if self.boolMousePos: - print(mouse.get_pos()) class Rect: - - def __init__(self, color, x, y, width, height): - self.color = color - self.x = x - self.y = y - self.width = width - self.height = height - - def draw(self): - pygame.draw.rect(screen, self.color, pygame.Rect(self.x, self.y, self.width, self.height)) + + def __init__(self, color, x, y, width, height): + self.color = color + self.x = x + self.y = y + self.width = width + self.height = height + + def draw(self): + pygame.draw.rect(screen, self.color, pygame.Rect(self.x, self.y, self.width, self.height)) + class Box: - def __init__(self, color, x, y, width, height, thickness): - self.color = color - self.x = x - self.y = y - self.width = width - self.height = height - self.thickness = thickness - - def draw(self): - pygame.draw.line(screen, self.color, (self.x + self.width, self.y), (self.x, self.y), self.thickness) #Top - pygame.draw.line(screen, self.color, (self.x, self.y + self.height), (self.x, self.y), self.thickness) #Left - pygame.draw.line(screen, self.color, (self.x + self.width, self.y), (self.x + self.width, self.y + self.height), self.thickness) #Right - pygame.draw.line(screen, self.color, (self.x, self.y + self.height), (self.x + self.width, self.y + self.height), self.thickness) #Bottom + def __init__(self, color, x, y, width, height, thickness): + self.color = color + self.x = x + self.y = y + self.width = width + self.height = height + self.thickness = thickness + + def draw(self): + pygame.draw.line(screen, self.color, (self.x + self.width, self.y), (self.x, self.y), self.thickness) # Top + pygame.draw.line(screen, self.color, (self.x, self.y + self.height), (self.x, self.y), self.thickness) # Left + pygame.draw.line(screen, self.color, (self.x + self.width, self.y), (self.x + self.width, self.y + self.height), + self.thickness) # Right + pygame.draw.line(screen, self.color, (self.x, self.y + self.height), + (self.x + self.width, self.y + self.height), self.thickness) # Bottom + class Text: - def __init__(self, color, x, y, FontSize, textStr): - pygame.font.init() - self.color = color - self.x = x - self.y = y - self.FontSize = FontSize - self.textStr = textStr - self.FontString = 'Arial' - #DropShadow - self.dropShadowEnabled = False - self.dropShadowColor = black - self.dropShadowOffset = 2 - - def font(self, fontStr): - self.FontString = fontStr - - def dropShadow(self, color, offset): - self.dropShadowEnabled = True - self.dropShadowColor = color - self.dropShadowOffset = offset - - def draw(self): - myfont = pygame.font.SysFont(self.FontString, self.FontSize) - textSurface = myfont.render(self.textStr, True, self.color) #Main Text - - if self.dropShadowEnabled: - textSurface2 = myfont.render(self.textStr, True, black) #DropShadow - screen.blit(textSurface2, (self.x + self.dropShadowOffset, self.y)) #DropShadow - - screen.blit(textSurface, (self.x, self.y)) #Main Text + def __init__(self, color, x, y, FontSize, textStr): + pygame.font.init() + self.color = color + self.x = x + self.y = y + self.FontSize = FontSize + self.textStr = textStr + self.FontString = 'Arial' + # DropShadow + self.dropShadowEnabled = False + self.dropShadowColor = black + self.dropShadowOffset = 2 + + def font(self, fontStr): + self.FontString = fontStr + + def dropShadow(self, color, offset): + self.dropShadowEnabled = True + self.dropShadowColor = color + self.dropShadowOffset = offset + + def draw(self): + myfont = pygame.font.SysFont(self.FontString, self.FontSize) + textSurface = myfont.render(self.textStr, True, self.color) # Main Text + + if self.dropShadowEnabled: + textSurface2 = myfont.render(self.textStr, True, black) # DropShadow + screen.blit(textSurface2, (self.x + self.dropShadowOffset, self.y)) # DropShadow + + screen.blit(textSurface, (self.x, self.y)) # Main Text + class Button: - def __init__(self, color, clickedColor, x,y,width,height, text=''): - self.color = color - self.clickedColor = clickedColor - self.x = x - self.y = y - self.width = width - self.height = height - self.text = text - self.is_hoverable = False - self.hover_color = gray - self.button_enabled = False + def __init__(self, color, clickedColor, x, y, width, height, text=''): + self.color = color + self.clickedColor = clickedColor + self.x = x + self.y = y + self.width = width + self.height = height + self.text = text + self.is_hoverable = False + self.hover_color = gray + self.button_enabled = False def is_enabled(self): - return self.button_enabled + return self.button_enabled def is_hovered(self, hoveredColor): - self.is_hoverable = True - self.hover_color = hoveredColor + self.is_hoverable = True + self.hover_color = hoveredColor def draw(self): - pygame.draw.rect(screen, self.color, pygame.Rect(self.x, self.y, self.width, self.height)) - - mouse = pygame.mouse - - if self.x + self.width > mouse.get_pos()[0] > self.x and self.y + self.height > mouse.get_pos()[1] > self.y: - if self.is_hoverable: - pygame.draw.rect(screen, self.hover_color, pygame.Rect(self.x, self.y, self.width, self.height)) - - if mouse.get_pressed()[0]: - self.button_enabled = True - pygame.draw.rect(screen, self.clickedColor, pygame.Rect(self.x, self.y, self.width, self.height)) - else: - self.button_enabled = False + pygame.draw.rect(screen, self.color, pygame.Rect(self.x, self.y, self.width, self.height)) + + mouse = pygame.mouse + + if self.x + self.width > mouse.get_pos()[0] > self.x and self.y + self.height > mouse.get_pos()[1] > self.y: + if self.is_hoverable: + pygame.draw.rect(screen, self.hover_color, pygame.Rect(self.x, self.y, self.width, self.height)) + + if mouse.get_pressed()[0]: + self.button_enabled = True + pygame.draw.rect(screen, self.clickedColor, pygame.Rect(self.x, self.y, self.width, self.height)) + else: + self.button_enabled = False From 48d8b75a982b029f1c46b9110021d37dbe068257 Mon Sep 17 00:00:00 2001 From: Caojunwei <97785943+dvdcjw@users.noreply.github.com> Date: Sun, 14 Jul 2024 10:38:26 +0800 Subject: [PATCH 2/9] Update oGUI.py when checkbox is clicked, check if the cursor is held down continuously ( don't toggle) or it's the first frame of clicking action (toggle). Replaced time.sleep(0.15) for avoiding constant toggle in the left click duration --- src/oGUI.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/oGUI.py b/src/oGUI.py index 5bbe884..d64959c 100644 --- a/src/oGUI.py +++ b/src/oGUI.py @@ -60,6 +60,7 @@ def __init__(self, outsideColor, insideColor, x, y, width, height, enabledByDefa self.insideColor = insideColor self.x = x self.y = y + self.mouse_holding = False self.width = width self.height = height self.checkBox_enabled = enabledByDefault @@ -91,10 +92,13 @@ def draw(self): pygame.Rect(self.x - self.width / 8, self.y - self.height / 8, self.width + self.width / 4, self.height + self.height / 4)) - # When clicked + # When clicked + check if mouse was continuous held in the previous frames if mouse.get_pressed()[0]: - self.checkBox_enabled = not self.checkBox_enabled - time.sleep(0.15) + if not self.mouse_holding: + self.checkBox_enabled = not self.checkBox_enabled + self.mouse_holding = True + else: + self.mouse_holding = False if self.checkBox_enabled: pygame.draw.rect(screen, self.insideColor, pygame.Rect(self.x, self.y, self.width, self.height)) From 0e081419a452c51c54912019a1d39e9794d5ebae Mon Sep 17 00:00:00 2001 From: Caojunwei <97785943+dvdcjw@users.noreply.github.com> Date: Mon, 15 Jul 2024 11:56:24 +0800 Subject: [PATCH 3/9] Update oGUI.py --- src/oGUI.py | 257 ++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 187 insertions(+), 70 deletions(-) diff --git a/src/oGUI.py b/src/oGUI.py index d64959c..0da5e84 100644 --- a/src/oGUI.py +++ b/src/oGUI.py @@ -1,5 +1,19 @@ +import random + import pygame, win32api, win32gui, win32con, time +# A storage dict, stores all buttons, checkboxes. +# Enabled draw_gui function, which draws all elements in the dict. +# And the major update --- Callback function. +# Now, instead of manually checking the status and run a function, +# which would lead to code duplication and stability problems +# You can just assign a function to the element's "callback" attribute, +# and it will be called ONCE when the element is altered. +# +# It stores all the objects + +widgets = [] + version = 0.4 width = win32api.GetSystemMetrics(0) @@ -53,63 +67,22 @@ def endLoop(): pygame.display.update() -class Checkbox: - - def __init__(self, outsideColor, insideColor, x, y, width, height, enabledByDefault=False): - self.outsideColor = outsideColor - self.insideColor = insideColor - self.x = x - self.y = y - self.mouse_holding = False - self.width = width - self.height = height - self.checkBox_enabled = enabledByDefault - self.is_hoverable = False - self.hover_color = gray - self.boolMousePos = False - - def is_hovered(self, hoveredColor): - self.is_hoverable = True - self.hover_color = hoveredColor - - def printMousePos(self): - self.boolMousePos = True - - def is_enabled(self): - return self.checkBox_enabled - - def draw(self): - pygame.draw.rect(screen, self.outsideColor, - pygame.Rect(self.x - self.width / 8, self.y - self.height / 8, self.width + self.width / 4, - self.height + self.height / 4)) - - mouse = pygame.mouse - - if self.x + self.width > mouse.get_pos()[0] > self.x and self.y + self.height > mouse.get_pos()[1] > self.y: - # When Hovered Over - if self.is_hoverable: - pygame.draw.rect(screen, self.hover_color, - pygame.Rect(self.x - self.width / 8, self.y - self.height / 8, - self.width + self.width / 4, self.height + self.height / 4)) +class WidgetBasics: + def __init__(self, is_hidden=False): + global widgets + widgets.append(self) - # When clicked + check if mouse was continuous held in the previous frames - if mouse.get_pressed()[0]: - if not self.mouse_holding: - self.checkBox_enabled = not self.checkBox_enabled - self.mouse_holding = True - else: - self.mouse_holding = False + def hide(self): + self.is_hidden = True - if self.checkBox_enabled: - pygame.draw.rect(screen, self.insideColor, pygame.Rect(self.x, self.y, self.width, self.height)) + def show(self): + self.is_hidden = False - if self.boolMousePos: - print(mouse.get_pos()) - - -class Rect: +class Rect(WidgetBasics): def __init__(self, color, x, y, width, height): + super().__init__() + self.callable = False self.color = color self.x = x self.y = y @@ -120,9 +93,11 @@ def draw(self): pygame.draw.rect(screen, self.color, pygame.Rect(self.x, self.y, self.width, self.height)) -class Box: +class Box(WidgetBasics): def __init__(self, color, x, y, width, height, thickness): + super().__init__() + self.callable = False self.color = color self.x = x self.y = y @@ -139,20 +114,23 @@ def draw(self): (self.x + self.width, self.y + self.height), self.thickness) # Bottom -class Text: +class Text(WidgetBasics): - def __init__(self, color, x, y, FontSize, textStr): + def __init__(self, color, x, y, FontSize, textStr, dropShadowEnabled=True, textAlign=0, verticalAlign=0): + super().__init__() pygame.font.init() + self.callable = False self.color = color self.x = x self.y = y self.FontSize = FontSize self.textStr = textStr - self.FontString = 'Arial' - # DropShadow - self.dropShadowEnabled = False + self.FontString = 'Roboto' self.dropShadowColor = black self.dropShadowOffset = 2 + self.dropShadowEnabled = dropShadowEnabled + self.textAlign = textAlign + self.verticalAlign = verticalAlign def font(self, fontStr): self.FontString = fontStr @@ -162,32 +140,70 @@ def dropShadow(self, color, offset): self.dropShadowColor = color self.dropShadowOffset = offset + def setTextAlign(self, textAlign): + self.textAlign = textAlign + + def setVerticalAlign(self, verticalAlign): + self.verticalAlign = verticalAlign + def draw(self): myfont = pygame.font.SysFont(self.FontString, self.FontSize) textSurface = myfont.render(self.textStr, True, self.color) # Main Text + text_w, text_h = myfont.size(self.textStr) + textRect = textSurface.get_rect() + + if self.textAlign == 0: + x = self.x # Left Align + elif self.textAlign == 1: + x = self.x - text_w // 2 # Center + elif self.textAlign == 2: + x = self.x - text_w # Right Align + + if self.verticalAlign == 0: + y = self.y # Top Align + elif self.verticalAlign == 1: + y = self.y - text_h // 2 # Center + elif self.verticalAlign == 2: + y = self.y - text_h # Bottom Align + + textRect = (x, y) if self.dropShadowEnabled: textSurface2 = myfont.render(self.textStr, True, black) # DropShadow - screen.blit(textSurface2, (self.x + self.dropShadowOffset, self.y)) # DropShadow + textRect2 = (textRect[0] + self.dropShadowOffset, textRect[1]) + screen.blit(textSurface2, textRect2) # DropShadow - screen.blit(textSurface, (self.x, self.y)) # Main Text + screen.blit(textSurface, textRect) # Text -class Button: - def __init__(self, color, clickedColor, x, y, width, height, text=''): +class Button(WidgetBasics): + # since the term 'press' emphasizes the hold action, and click is more appropriate for a single action, + # the handle-anti-multi-trigger-per-click variables is names after 'press', while the callback is names after click + def __init__(self, color, clickedColor, x, y, width=None, height=30, text='', clicked_callback=None): + super().__init__() + self.type = 'button' + self.clicked_callback = clicked_callback + self.callable = True + self.last_frame_pressed = False self.color = color self.clickedColor = clickedColor self.x = x self.y = y self.width = width self.height = height - self.text = text - self.is_hoverable = False - self.hover_color = gray - self.button_enabled = False + + w, h = pygame.font.SysFont('Roboto', int(self.height)).size(text) + if not self.width: + self.width = w + 10 + self.text_widget = Text(self.clickedColor, self.x + self.width // 2, self.y + self.height // 2, self.height, + text, verticalAlign=1, textAlign=1) + + self.is_hoverable = True + self.hover_color = (self.clickedColor[0] / 2, self.clickedColor[1] / 2, self.clickedColor[2] / 2) + self.pressed = False def is_enabled(self): - return self.button_enabled + return self.pressed def is_hovered(self, hoveredColor): self.is_hoverable = True @@ -199,11 +215,112 @@ def draw(self): mouse = pygame.mouse if self.x + self.width > mouse.get_pos()[0] > self.x and self.y + self.height > mouse.get_pos()[1] > self.y: - if self.is_hoverable: + if self.is_hovered: pygame.draw.rect(screen, self.hover_color, pygame.Rect(self.x, self.y, self.width, self.height)) if mouse.get_pressed()[0]: - self.button_enabled = True + self.pressed = True pygame.draw.rect(screen, self.clickedColor, pygame.Rect(self.x, self.y, self.width, self.height)) else: - self.button_enabled = False + self.pressed = False + + +class Checkbox(WidgetBasics): + def __init__(self, outsideColor, insideColor, x, y, width, height, text=None, checked_callback=None, + toggled_callback=None, checkedByDefault=False): + super().__init__() + self.callable = True + self.checked_callback = checked_callback + self.toggled_callback = toggled_callback + self.type = 'checkbox' + self.last_frame_checked = checkedByDefault + self.outsideColor = outsideColor + self.insideColor = insideColor + self.x = x + self.y = y + self.mouse_holding = False + self.width = width + self.height = height + self.checked = checkedByDefault + self.is_hoverable = True + self.hover_color = (self.insideColor[0] / 2, self.insideColor[1] / 2, self.insideColor[2] / 2) + self.boolMousePos = False + + w, h = pygame.font.SysFont('Roboto', int(self.height)).size(text) + self.text_widget = Text(self.insideColor, self.x + 10 + self.width, self.y + self.height // 2, self.height, + text, verticalAlign=1, textAlign=0) + + def is_hovered(self, hoveredColor): + self.is_hoverable = True + self.hover_color = hoveredColor + + def printMousePos(self): + self.boolMousePos = True + + def is_enabled(self): + return self.checked + + def draw(self): + pygame.draw.rect(screen, self.outsideColor, + pygame.Rect(self.x - self.width / 8, self.y - self.height / 8, self.width + self.width / 4, + self.height + self.height / 4)) + + mouse = pygame.mouse + + if self.x + self.width > mouse.get_pos()[0] > self.x and self.y + self.height > mouse.get_pos()[1] > self.y: + # When Hovered Over + if self.is_hoverable: + pygame.draw.rect(screen, self.hover_color, + pygame.Rect(self.x - self.width / 8, self.y - self.height / 8, + self.width + self.width / 4, self.height + self.height / 4)) + + # When clicked + check if mouse was continuously held in the previous frames + if mouse.get_pressed()[0]: + if not self.mouse_holding: + self.checked = not self.checked + self.mouse_holding = True + else: + self.mouse_holding = False + + if self.checked: + pygame.draw.rect(screen, self.insideColor, pygame.Rect(self.x, self.y, self.width, self.height)) + + if self.boolMousePos: + print(mouse.get_pos()) + + +def update_gui(): + # the startLoop and endLoop would not be included in this function. + # In case the use creates something else not via this library but using pygame itself, + # they can use the startLoop and endLoop to wrap around their own code + for i in widgets: + i.draw() + handle_gui_alter() + + +def handle_checkbox_callback(checkbox_object): + if checkbox_object.last_frame_checked != checkbox_object.checked: + if checkbox_object.toggled_callback: + checkbox_object.toggled_callback() # this line executes the callback function while the last detects if there is one + if checkbox_object.checked: + if checkbox_object.checked_callback: + checkbox_object.checked_callback() + + checkbox_object.last_frame_checked = checkbox_object.checked + + +def handle_button_callback(button_object): + if button_object.last_frame_pressed != button_object.pressed: + if button_object.pressed: + if button_object.clicked_callback: + button_object.clicked_callback() + button_object.last_frame_pressed = button_object.pressed + + +def handle_gui_alter(): + for i in widgets: + if i.callable: + if i.type == 'checkbox': + handle_checkbox_callback(i) + if i.type == 'button': + handle_button_callback(i) From a350fb910f4dd265b6182abab4a4bb3a22de8b7b Mon Sep 17 00:00:00 2001 From: Caojunwei <97785943+dvdcjw@users.noreply.github.com> Date: Mon, 15 Jul 2024 11:56:41 +0800 Subject: [PATCH 4/9] Update example.py --- examples/example.py | 90 ++++++++++++++++++++++++++------------------- 1 file changed, 53 insertions(+), 37 deletions(-) diff --git a/examples/example.py b/examples/example.py index 8523eeb..0e9353d 100644 --- a/examples/example.py +++ b/examples/example.py @@ -2,51 +2,67 @@ oGUI.init() -checkbox = oGUI.Checkbox(oGUI.gray, oGUI.orange, 125, 150, 20, 20) -rect = oGUI.Rect(oGUI.darkgray, 100, 100, 300, 500) -box = oGUI.Box(oGUI.lightgray, 100, 100, 300, 500, 5) -button = oGUI.Button(oGUI.gray, oGUI.orange, 120, 200, 30, 30) -button2 = oGUI.Button(oGUI.darkgray, oGUI.lightgray, 368, 103, 30, 35) -myText = oGUI.Text(oGUI.orange, 195, 110, 30, "oGUI Demo") -myText2 = oGUI.Text(oGUI.orange, 155, 152, 25, "Checkbox") -myText3 = oGUI.Text(oGUI.orange, 155, 208, 25, "Button") -myText4 = oGUI.Text(oGUI.black, 375, 105, 30, "X") +def button_clicked(): + print('') + print('button is clicked!') + print('this massage would only appear once after the button is clicked') -while True: - oGUI.startLoop() #Start of Draw Loop +def checkbox_status_changed(): + print('') + print('checkbox status changed') + print('now, checkbox is:', 'checked' if checkbox.is_enabled() else 'unchecked') + print('this massage would only appear once after the checkbox is toggled') - rect.draw() #Drawing Rectangle, Box, Checkbox, and Button - box.draw() - checkbox.draw() - button.draw() - button2.draw() - myText.draw() #Drawing Text - myText2.draw() - myText3.draw() - myText4.draw() +def exit_button_clicked(): + exit(0) - oGUI.endLoop() #End of Draw Loop - checkbox.is_hovered(oGUI.lightgray) #Changes color when checkbox and button(s) is hovered over - button.is_hovered(oGUI.lightgray) - button2.is_hovered(oGUI.gray) +window_x = 100 +window_y = 100 +window_w = 300 +window_h = 500 + +rect = oGUI.Rect(oGUI.darkgray, window_x, window_y, window_w, window_h) +box = oGUI.Box(oGUI.lightgray, window_x, window_y, window_w, window_h, 5) +checkbox = oGUI.Checkbox(oGUI.gray, oGUI.orange, 125, 150, 20, 20, toggled_callback=checkbox_status_changed, + text='checkbox') +button = oGUI.Button(oGUI.gray, oGUI.orange, 120, 200, text='button', clicked_callback=button_clicked) +quit_button = oGUI.Button(oGUI.darkgray, oGUI.lightgray, 368, 103, 30, 35, clicked_callback=exit_button_clicked, + text='×') + +myText = oGUI.Text(oGUI.orange, window_x + window_w / 2, window_y + 5, 30, + "overlayGUI by ethanedits", textAlign=1) + +# DVDCJW - myText.font('Roboto') #Setting Text Object's font - myText2.font('Roboto') - myText3.font('Roboto') +credit_text = oGUI.Text(oGUI.orange, window_x + window_w / 2, window_y + window_h / 2 - 20, 30, + 'major overhaul by DVDCJW', textAlign=1, verticalAlign=1) +credit_text2 = oGUI.Text(oGUI.orange, window_x + window_w / 2, window_y + window_h / 2 + 20, 20, 'including:', + textAlign=1, verticalAlign=1) +credit_text3 = oGUI.Text(oGUI.orange, window_x + window_w / 2, window_y + window_h / 2 + 40, 25, + 'CALLBACK for button and checkbox', textAlign=1, verticalAlign=1) +credit_text4 = oGUI.Text(oGUI.orange, window_x + window_w / 2, window_y + window_h / 2 + 60, 25, 'widgets upgrade', + textAlign=1, verticalAlign=1) +credit_text5 = oGUI.Text(oGUI.orange, window_x + window_w / 2, window_y + window_h / 2 + 80, 20, + 'better checkbox hold logic', textAlign=1, verticalAlign=1) +credit_text6 = oGUI.Text(oGUI.orange, window_x + window_w / 2, window_y + window_h / 2 + 100, 20, + 'integrated text for callable widgets', textAlign=1, verticalAlign=1) - myText.dropShadow(oGUI.black, 2) #Setting Text Object's DropShadow - myText2.dropShadow(oGUI.black, 2) - myText3.dropShadow(oGUI.black, 2) - - if button.is_enabled(): #Do something if the button is enabled/pressed - print('Button was pressed') +# feel free to delete my credits if you're not comfortable with it. +# But I really made this project way more practical, efficient and maintainable - if button2.is_enabled(): #Exit Button - exit(0) +while True: + oGUI.startLoop() # Start of Draw Loop + + oGUI.update_gui() # handle update and callback + + # maybe some of your own pygame code if you'd like - if checkbox.is_enabled(): #Do something if the checkbox is enabled - print('Checkbox is Enabled!') + oGUI.endLoop() # End of Draw Loop + + checkbox.is_hovered(oGUI.lightgray) # Changes color when checkbox and button(s) is hovered over + button.is_hovered(oGUI.lightgray) + quit_button.is_hovered(oGUI.gray) From 6dedd2f213638ebdb6fb253366b2129711e33602 Mon Sep 17 00:00:00 2001 From: Caojunwei <97785943+dvdcjw@users.noreply.github.com> Date: Mon, 15 Jul 2024 11:57:36 +0800 Subject: [PATCH 5/9] Create requirements.txt --- requirements.txt | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 requirements.txt diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..81dea35 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,2 @@ +pygame +pypiwin32 From 8dc439ec193f1a5f296fcb806fbaa56fe77a7d31 Mon Sep 17 00:00:00 2001 From: Caojunwei <97785943+dvdcjw@users.noreply.github.com> Date: Mon, 15 Jul 2024 12:15:40 +0800 Subject: [PATCH 6/9] Update README.md --- README.md | 61 +++++++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 53 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index facec00..ab835e4 100644 --- a/README.md +++ b/README.md @@ -16,11 +16,12 @@ Once you have called this, you can create an **infinite loop** and call two func ```py while True: oGUI.startLoop() - + ... oGUI.endLoop() ``` -*Inbetween* the `start` and `end` loop, you can call the drawing functions. +*Inbetween* the `start` and `end` loop, you should execute the update_gui() ONCE. +Then it will redraw all the gui and handle the callbacks for you *Here is an example:* ```py @@ -29,7 +30,7 @@ checkbox = oGUI.Checkbox(oGUI.gray, oGUI.orange, 125, 150, 20, 20) while True: oGUI.startLoop() - checkbox.draw() + oGUI.update_gui() oGUI.endLoop() ``` @@ -54,24 +55,68 @@ These are the available colors: `oGUI.lightgray` `oGUI.darkgray` -**Functions** +**Creating widgets** --------------------- -Creating *checkboxes* +e.g. Creating *checkboxes* To create a **checkbox**, we can create a variable and then call the `oGUI.Checkbox()` function. Usage: ```py -checkbox1 = oGUI.Checkbox(outsideColor, insideColor, x position, y position, width, height, enabledByDefault) +checkbox1 = oGUI.Checkbox(outsideColor, insideColor, x position, y position, width, height, enabledByDefault, callback_function) ``` enabledByDefault is optional, and if you leave it blank (dont specify it), it will be false. We will continue to use *checkbox1* as the *checkbox variable* for the rest of the documentation, and the *rest of these functions* should be called in an **infinite loop.** -To *render* the actual checkbox, we must call its `.draw()` function. Usage: +To *render* the actual checkbox, ~~we must call its `.draw()` function~~ +Now, you will only have to run the update_gui() **ONCE** and it will draw **ALL* the widgets you've created(as long as they're not hidden) for you. +So idealy, you won't have to call the draw function manually. +Usage: ```py -checkbox1.draw() +while True: + oGUI.startLoop() + + oGUI.update_gui() + + oGUI.endLoop() ``` +for more widgets creation, goto [example.py](examples/example.py) + +** We need to put this function inbetween of our `startLoop()` and `endLoop()`. +**Callbacks** +--------------------- +call back is the core of a gui. This allows a funciton to be called once a widget is interacted in a certain way. +e.g. +```py +import oGUI + +oGUI.init() + + +def button_clicked(): + print('I am clicked') + +button = oGUI.Button(oGUI.blue, oGUI.white, 400, 300, 100, 30, text='click me', clicked_callback=button_clicked) + +while True: + oGUI.startLoop() # Start of Draw Loop + + oGUI.update_gui() # handle update and callback + + oGUI.endLoop() # End of Draw Loop +``` + +Notice that you WON'T want the brackets if you're defining the callback, +Just like in the example, we used button_clicked NOT button_clicked(). +The reason is that if you use *funciton*, the function itself will be passed on to the callback +On the contrary, if you use *function()*, the function itself will be executed and its return will be passed on to the callback. +Normally, we don't want this to happen. + +More examples of callback can be found in the [example.py](examples/example.py) + +**Malipulating widgets** +--------------------- We can also change the *color* of the box if it is hovered over, using the `.is_hovered()` function. Usage: ```py checkbox1.is_hovered(color) From 12301f853a7de86b8d250d69ee43baaf6f599508 Mon Sep 17 00:00:00 2001 From: Caojunwei <97785943+dvdcjw@users.noreply.github.com> Date: Mon, 15 Jul 2024 12:16:51 +0800 Subject: [PATCH 7/9] Update README.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index ab835e4..7f44f23 100644 --- a/README.md +++ b/README.md @@ -20,8 +20,8 @@ while True: oGUI.endLoop() ``` -*Inbetween* the `start` and `end` loop, you should execute the update_gui() ONCE. -Then it will redraw all the gui and handle the callbacks for you +*Inbetween* the `start` and `end` loop, you should execute the update_gui() *ONCE*. +Then it will render all the gui and handle the callbacks for you *Here is an example:* ```py From c4dcf5f3bf267986f824f8f309e51bdcb4ebabc2 Mon Sep 17 00:00:00 2001 From: Caojunwei <97785943+dvdcjw@users.noreply.github.com> Date: Mon, 15 Jul 2024 12:17:54 +0800 Subject: [PATCH 8/9] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 7f44f23..9594586 100644 --- a/README.md +++ b/README.md @@ -68,7 +68,7 @@ enabledByDefault is optional, and if you leave it blank (dont specify it), it wi We will continue to use *checkbox1* as the *checkbox variable* for the rest of the documentation, and the *rest of these functions* should be called in an **infinite loop.** To *render* the actual checkbox, ~~we must call its `.draw()` function~~ -Now, you will only have to run the update_gui() **ONCE** and it will draw **ALL* the widgets you've created(as long as they're not hidden) for you. +Now, you will only have to run the update_gui() **ONCE** and it will draw *ALL* the widgets you've created(as long as they're not hidden) for you. So idealy, you won't have to call the draw function manually. Usage: ```py From 4f4fa961698fccfc80577b7ab7aa5c262f796f3a Mon Sep 17 00:00:00 2001 From: Caojunwei <97785943+dvdcjw@users.noreply.github.com> Date: Mon, 15 Jul 2024 12:21:50 +0800 Subject: [PATCH 9/9] Update README.md --- README.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/README.md b/README.md index 9594586..cb07d56 100644 --- a/README.md +++ b/README.md @@ -106,6 +106,11 @@ while True: oGUI.endLoop() # End of Draw Loop ``` +The function *button_clicked* will be executed everytime the button is clicked. +However, the function will be run in the main thread defaultly, +this means the rest of the program and the mainloop would have to wait for the called function to finish. +So if the function takes up a considerable amount of time, the gui will noticibly stop responding. +To fix this, use multithread libs, so that the callback function and the maintheard can run simultaneously. Notice that you WON'T want the brackets if you're defining the callback, Just like in the example, we used button_clicked NOT button_clicked().