From 0ecf5324642ea3d20d2e49bf5c53165ea79e6273 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Rudowicz?= Date: Tue, 10 Sep 2024 17:39:53 +0200 Subject: [PATCH] Configurable color schemes, set Nord as an example --- example_config.json | 11 +++++++++-- menu.py | 44 +++++++++++++++++++++++--------------------- 2 files changed, 32 insertions(+), 23 deletions(-) diff --git a/example_config.json b/example_config.json index bcec215..2df9329 100644 --- a/example_config.json +++ b/example_config.json @@ -31,5 +31,12 @@ "action_message": "Doing GET example" } ], - "bg_color": "lime" -} \ No newline at end of file + "color_scheme": { + "menu_bg_color": "#4c566a", + "message_bg_color": "#eceff4", + "message_text_color": "#2e3440", + "btn_bg_color": "#d8dee9", + "btn_hover_color": "#eceff4", + "btn_text_color": "#2e3440" + } +} diff --git a/menu.py b/menu.py index f5da54a..30bc96b 100644 --- a/menu.py +++ b/menu.py @@ -7,7 +7,7 @@ from enum import Enum, auto from time import sleep from threading import Thread from queue import Queue, Empty -from typing import Tuple, Callable, TypedDict, List +from typing import Tuple, Callable, TypedDict, List, Dict import pygame import pygame.freetype @@ -38,18 +38,19 @@ class Button: PRESS_OFFSET = 2 HOVER_ANIMATION_STEPS = 5 - def __init__(self, position: pygame.Rect, text: str, cbk: Callable[[], None]): + def __init__(self, position: pygame.Rect, text: str, color_scheme: Dict, cbk: Callable[[], None]): self.position: pygame.Rect self.set_position(position) self.text = text + self.color_scheme = color_scheme self.cbk = cbk self.font = pygame.freetype.SysFont(name="Sans", size=20) text_rect = self.font.get_rect(self.text) self.text_pos = pygame.Rect((self.position.left + (self.position.width - text_rect.width)/2), (self.position.top + (self.position.height - text_rect.height)/2), text_rect.width, text_rect.height) - self.bg_color = pygame.Color("black") - self.hover_bg_color = pygame.Color("violetred4") + self.bg_color = pygame.Color(self.color_scheme["btn_bg_color"]) + self.hover_bg_color = pygame.Color(self.color_scheme["btn_hover_color"]) self.hover_animation_step = 0 def get_bg_color(self): @@ -87,7 +88,7 @@ class Button: def draw(self, screen: pygame.Surface): pygame.draw.rect(screen, self.get_bg_color(), self.get_position(), 0) - self.font.render_to(screen, self.get_text_pos(), self.text, fgcolor="pink") + self.font.render_to(screen, self.get_text_pos(), self.text, fgcolor=self.color_scheme["btn_text_color"]) def pos_is_inside(self, pos: Tuple) -> bool: return (self.position.left < pos[0] and (self.position.left + self.position.width) > pos[0]) and \ @@ -100,14 +101,14 @@ class Button: class MessageBoard(IBoard): - def __init__(self, screen_rect: pygame.Rect, text: str, bg_color: str): + def __init__(self, screen_rect: pygame.Rect, text: str, color_scheme: Dict): self.text = text self.font = pygame.freetype.SysFont(name="Sans", size=30) text_rect = self.font.get_rect(self.text) self.text_pos = pygame.Rect((screen_rect.left + (screen_rect.width - text_rect.width)/2), (screen_rect.top + (screen_rect.height - text_rect.height)/2), text_rect.width, text_rect.height) - self.bg_color = bg_color + self.color_scheme = color_scheme self.was_drawn_already = False def handle_event(self, _): @@ -115,23 +116,23 @@ class MessageBoard(IBoard): def draw(self, screen: pygame.Surface, force_redraw: bool): if not self.was_drawn_already or force_redraw: - screen.fill(self.bg_color) - self.font.render_to(screen, self.text_pos, self.text, fgcolor="black") + screen.fill(self.color_scheme["message_bg_color"]) + self.font.render_to(screen, self.text_pos, self.text, fgcolor=self.color_scheme["message_text_color"]) self.was_drawn_already = True class MenuBoard(IBoard): BUTTON_MARGINS = 10 - def __init__(self, screen_rect: pygame.Rect, buttons: List[ButtonDef], bg_color: str): + def __init__(self, screen_rect: pygame.Rect, buttons: List[ButtonDef], color_scheme: Dict): self.rows = math.floor(math.sqrt(len(buttons))) self.cols = math.ceil(math.sqrt(len(buttons))) if (self.rows * self.cols) < len(buttons): # extra row if buttons don't fit self.rows += 1 button_positions = self.generate_button_positions(screen_rect) - self.buttons = list(map(lambda d: Button(next(button_positions), d['text'], d['cbk']), buttons)) - self.bg_color = bg_color + self.buttons = list(map(lambda d: Button(next(button_positions), d['text'], color_scheme, d['cbk']), buttons)) + self.color_scheme = color_scheme def generate_button_positions(self, screen_rect: pygame.Rect): current_button_row = 0 @@ -153,7 +154,7 @@ class MenuBoard(IBoard): def draw(self, screen: pygame.Surface, force_redraw: bool): if force_redraw or any(map(Button.needs_redrawing, self.buttons)): - screen.fill(self.bg_color) + screen.fill(self.color_scheme["menu_bg_color"]) for b in self.buttons: b.draw(screen) @@ -161,7 +162,7 @@ class MenuBoard(IBoard): class App: FPS = 30 - def __init__(self, urls: List[Action], bg_color: str, fullscreen: bool, screensaver_delay: int): + def __init__(self, urls: List[Action], color_scheme: Dict, fullscreen: bool, screensaver_delay: int): pygame.init() info = pygame.display.Info() flags = 0 @@ -170,10 +171,10 @@ class App: self.screen = pygame.display.set_mode((info.current_w, info.current_h), flags=flags) self.clock = pygame.time.Clock() self.running = False - self.bg_color = bg_color + self.color_scheme = color_scheme buttons = list(map(lambda u: ButtonDef(text=u['label'], cbk=self.button_press_handler(u)), urls)) buttons.append(ButtonDef(text="Exit", cbk=self.quit)) - self.board: IBoard = MenuBoard(self.get_screen_rect(), buttons, bg_color) + self.board: IBoard = MenuBoard(self.get_screen_rect(), buttons, color_scheme) self.task_q = Queue() self.screensaver = ClockScreensaver() self.TICKS_UNTIL_SCREENSAVER = screensaver_delay * self.FPS @@ -196,7 +197,8 @@ class App: except Exception as e: def f(ex): def x(): - self.board = MessageBoard(self.get_screen_rect(), f"Exception caught: {ex}", bg_color="red") + self.board = MessageBoard(self.get_screen_rect(), f"Exception caught: {ex}", + color_scheme=self.color_scheme) return x self.task_q.put(f(e)) sleep(5) @@ -205,7 +207,7 @@ class App: process_thr = Thread(target=thr_fun) process_thr.start() - self.board = MessageBoard(self.get_screen_rect(), action['action_message'], bg_color=self.bg_color) + self.board = MessageBoard(self.get_screen_rect(), action['action_message'], color_scheme=self.color_scheme) return impl def get_handler(self, action: Action) -> Callable[[], None]: @@ -222,7 +224,7 @@ class App: process_thr = Thread(target=thr_fun) process_thr.start() - self.board = MessageBoard(self.get_screen_rect(), action['action_message'], bg_color=self.bg_color) + self.board = MessageBoard(self.get_screen_rect(), action['action_message'], color_scheme=self.color_scheme) return impl def button_press_handler(self, action: Action) -> Callable[[], None]: @@ -261,7 +263,7 @@ class App: pygame.quit() def quit(self): - self.board = MessageBoard(self.get_screen_rect(), "Exiting...", bg_color=self.bg_color) + self.board = MessageBoard(self.get_screen_rect(), "Exiting...", color_scheme=self.color_scheme) self.running = False @@ -288,6 +290,6 @@ if __name__ == '__main__': data = json.load(f) url_defs = get_url_defs(data) - app = App(url_defs, bg_color=data["bg_color"], fullscreen=not args.no_fullscreen, + app = App(url_defs, color_scheme=data["color_scheme"], fullscreen=not args.no_fullscreen, screensaver_delay=args.screensaver_delay) app.loop()