From 598c88207663d9237d348e84ba260c50dd6aedf3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Rudowicz?= Date: Mon, 9 Sep 2024 22:58:58 +0200 Subject: [PATCH] Animated screensaver, command line args for ssaver delay and fullscreen --- iboard.py | 16 ++++++++++++++++ menu.py | 51 +++++++++++++++---------------------------------- screensavers.py | 37 +++++++++++++++++++++++++++++++++++ 3 files changed, 68 insertions(+), 36 deletions(-) create mode 100644 iboard.py create mode 100644 screensavers.py diff --git a/iboard.py b/iboard.py new file mode 100644 index 0000000..a70751a --- /dev/null +++ b/iboard.py @@ -0,0 +1,16 @@ +#!/usr/bin/env python3 + +from abc import abstractmethod + +from pygame import Surface +from pygame.event import Event + + +class IBoard: + @abstractmethod + def draw(self, screen: Surface): + raise NotImplementedError() + + @abstractmethod + def handle_event(self, event: Event): + raise NotImplementedError() diff --git a/menu.py b/menu.py index d68d935..ca55fe5 100644 --- a/menu.py +++ b/menu.py @@ -4,16 +4,18 @@ import math import argparse import json from enum import Enum, auto -from time import sleep, strftime +from time import sleep from threading import Thread from queue import Queue, Empty -from abc import abstractmethod from typing import Tuple, Callable, TypedDict, List import pygame import pygame.freetype import requests +from iboard import IBoard +from screensavers import ClockScreensaver + class ButtonDef(TypedDict): text: str @@ -31,36 +33,6 @@ class Action(TypedDict): param: str -class IBoard: - @abstractmethod - def draw(self, screen: pygame.Surface): - raise NotImplementedError() - - @abstractmethod - def handle_event(self, event: pygame.event.Event): - raise NotImplementedError() - - -class Screensaver(IBoard): - def handle_event(self, _): - pass - - -class ClockScreensaver(Screensaver): - def __init__(self): - self.font = pygame.freetype.SysFont(name="Sans", size=20) - - def draw(self, screen: pygame.Surface): - text = strftime("%H:%M:%S") - screen.fill("black") - pygame.Rect(0, 0, screen.get_width(), screen.get_height()) - text_rect = self.font.get_rect(text) - text_pos = pygame.Rect((screen.get_width() - text_rect.width)/2, - (screen.get_height() - text_rect.height)/2, - text_rect.width, text_rect.height) - self.font.render_to(screen, text_pos, text, fgcolor="pink") - - class Button: PRESS_OFFSET = 2 @@ -161,12 +133,14 @@ class MenuBoard(IBoard): class App: FPS = 30 - TICKS_UNTIL_SCREENSAVER = 1 * FPS - def __init__(self, urls: List[Action], bg_color: str): + def __init__(self, urls: List[Action], bg_color: str, fullscreen: bool, screensaver_delay: int): pygame.init() info = pygame.display.Info() - self.screen = pygame.display.set_mode((info.current_w, info.current_h), flags=pygame.FULLSCREEN) + flags = 0 + if fullscreen: + flags = pygame.FULLSCREEN + 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 @@ -175,6 +149,7 @@ class App: self.board: IBoard = MenuBoard(self.get_screen_rect(), buttons, bg_color) self.task_q = Queue() self.screensaver = ClockScreensaver() + self.TICKS_UNTIL_SCREENSAVER = screensaver_delay * self.FPS self.screensaver_ticks = self.TICKS_UNTIL_SCREENSAVER def get_screen_rect(self) -> pygame.Rect: @@ -262,6 +237,9 @@ def get_url_defs(config_data: dict) -> List[Action]: if __name__ == '__main__': parser = argparse.ArgumentParser() parser.add_argument("config_path", help="Path to the config file.", type=str) + parser.add_argument("--no-fullscreen", help="Fullscreen", action='store_true') + parser.add_argument("--screensaver-delay", help="Screensaver delay, in seconds. Default=30", + type=int, default=30) args = parser.parse_args() url_defs: List[Action] = [] @@ -269,5 +247,6 @@ if __name__ == '__main__': data = json.load(f) url_defs = get_url_defs(data) - app = App(url_defs, bg_color=data["bg_color"]) + app = App(url_defs, bg_color=data["bg_color"], fullscreen=not args.no_fullscreen, + screensaver_delay=args.screensaver_delay) app.loop() diff --git a/screensavers.py b/screensavers.py new file mode 100644 index 0000000..104f361 --- /dev/null +++ b/screensavers.py @@ -0,0 +1,37 @@ +#!/usr/bin/env python3 + +from time import strftime +from typing import Tuple + +import pygame + +from iboard import IBoard + + +class Screensaver(IBoard): + def handle_event(self, _): + pass + + +class ClockScreensaver(Screensaver): + def __init__(self): + self.font = pygame.freetype.SysFont(name="Sans", size=40) + self.dx = 1 + self.dy = 1 + self.text_xy: Tuple[int, int] = (0, 0) + + def draw(self, screen: pygame.Surface): + text = strftime("%H:%M:%S") + screen.fill("black") + pygame.Rect(0, 0, screen.get_width(), screen.get_height()) + text_rect = self.font.get_rect(text) + if ((self.text_xy[0] + self.dx + text_rect.width) > screen.get_width()) or \ + ((self.text_xy[0] + self.dx) < 0): + self.dx *= -1 + if ((self.text_xy[1] + self.dy + text_rect.height) > screen.get_height()) or \ + ((self.text_xy[1] + self.dy) < 0): + self.dy *= -1 + self.text_xy = (self.text_xy[0] + self.dx, self.text_xy[1] + self.dy) + text_pos = pygame.Rect(self.text_xy[0], self.text_xy[1], + text_rect.width, text_rect.height) + self.font.render_to(screen, text_pos, text, fgcolor="pink")