1
0
Fork 0

Configurable color schemes, set Nord as an example

This commit is contained in:
Michał Rudowicz 2024-09-10 17:39:53 +02:00
parent 3b9e279db1
commit 0ecf532464
2 changed files with 32 additions and 23 deletions

View File

@ -31,5 +31,12 @@
"action_message": "Doing GET example"
}
],
"bg_color": "lime"
}
"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"
}
}

44
menu.py
View File

@ -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()