Select Git revision
screenwidgets.py
screenwidgets.py 10.64 KiB
import math
import os.path
import re
from datetime import datetime
from config import PROP_WINDOW_SCALE, PROP_SCREEN_WIDTH, PROP_SCREEN_HEIGHT
from num_utils import get_screen_centre, get_ip, get_font_path_or_default
class IWidgetMeta(type):
"""
Metaclass for the IWidget interface
"""
def __instancecheck__(cls, instance):
return cls.__subclasscheck__(type(instance))
def __subclasscheck__(cls, subclass):
return hasattr(subclass, 'draw') and callable(subclass.draw)
class IWidget(metaclass=IWidgetMeta):
"""
Interface for a widget which can be drawn on the screen
"""
def __init__(self, config: dict):
pass
def draw(self, screen):
pass
class DigitalClockWidget(IWidget):
"""
A simple clock widget which displays the current time
"""
def __init__(self, config: dict):
# Call the parent constructor
super().__init__(config)
# Get the pygame module from the config
self.pygame = config['pygame']
# Get the font path
self.font_path = get_font_path_or_default(self.pygame, config.get("font_name", None), config.get("font_bold", False), config.get("font_italic", False))
# Load the font
self.font = self.pygame.font.Font(self.font_path, config.get("font_size", 36 * PROP_WINDOW_SCALE))
self.font.bold = config.get("font_bold", False)
self.font.italic = config.get("font_italic", False)
# Set the colours
self.color = config.get("font_color", "white")
self.background_color = config.get("background_color", "black")
# Set background options
self.draw_background = config.get("draw_background", False)
self.background_type = config.get("background_type", "color")
if self.background_type == "image" and config.get("background_image", "") != "":
self.bg_image = self.pygame.image.load(config.get("background_image", ""))
self.bg_image = self.pygame.transform.scale(self.bg_image, (PROP_SCREEN_WIDTH * PROP_WINDOW_SCALE, PROP_SCREEN_HEIGHT * PROP_WINDOW_SCALE))
# Set the clock format
self.clock_format = config.get("clock_format", "%H:%M:%S")
# Set the starting text
self.text = ""
def draw(self, screen):
# Update the text
self.text = datetime.now().strftime(self.clock_format)
# Fill the background
if self.draw_background:
if self.background_type == "color":
screen.fill(self.background_color)
elif self.background_type == "image":
screen.blit(self.bg_image, (0, 0))
# Render the text
text_surface = self.font.render(self.text, True, self.color)
# Blit the text to the screen
text_rect = text_surface.get_rect(center=get_screen_centre())
screen.blit(text_surface, text_rect)
class TestWidget(IWidget):
def __init__(self, config: dict):
super().__init__(config)
self.pygame = config['pygame']
self.color = config.get("color", "white")
self.bg_color = config.get("background_color", "black")
self.text = config.get("text", "Hello, world!")
self.font = self.pygame.font.Font(self.pygame.font.get_default_font(), 36 * PROP_WINDOW_SCALE)
def draw(self, screen):
screen.fill(self.bg_color)
text_surface = self.font.render(self.text, True, self.color)
text_rect = text_surface.get_rect(center=get_screen_centre())
screen.blit(text_surface, text_rect)
class AnalogClockWidget(IWidget):
def __init__(self, config: dict):
super().__init__(config)
self.pygame = config['pygame']
# Set the colours
self.background_color = config.get("background_color", "black")
self.marking_color = config.get("marking_color", "white")
self.clock_background_color = config.get("clock_background_color", "black")
self.hour_hand_color = config.get("hour_hand_color", "white")
self.minute_hand_color = config.get("minute_hand_color", "white")
self.second_hand_color = config.get("second_hand_color", "red")
# Set background options
self.draw_background = config.get("draw_background", False)
self.draw_clock_background = config.get("draw_clock_background", True)
self.background_type = config.get("background_type", "color")
if self.background_type == "image" and config.get("background_image", "") != "":
self.bg_image = self.pygame.image.load(config.get("background_image", ""))
self.bg_image = self.pygame.transform.scale(self.bg_image, (
PROP_SCREEN_WIDTH * PROP_WINDOW_SCALE,
PROP_SCREEN_HEIGHT * PROP_WINDOW_SCALE
))
# Set the clock format
self.clock_radius = config.get("clock_outer_radius", 100 * PROP_WINDOW_SCALE)
self.clock_inner_radius = config.get("clock_inner_radius", 80 * PROP_WINDOW_SCALE)
self.marking_length = config.get("marking_length", 10 * PROP_WINDOW_SCALE)
self.marking_width = config.get("marking_width", 2 * PROP_WINDOW_SCALE)
self.hour_hand_length = config.get("hour_hand_length", 40 * PROP_WINDOW_SCALE)
self.minute_hand_length = config.get("minute_hand_length", 50 * PROP_WINDOW_SCALE)
self.second_hand_length = config.get("second_hand_length", 60 * PROP_WINDOW_SCALE)
self.hour_hand_thickness = config.get("hour_hand_thickness", 2 * PROP_WINDOW_SCALE)
self.minute_hand_thickness = config.get("minute_hand_thickness", 2 * PROP_WINDOW_SCALE)
self.second_hand_thickness = config.get("second_hand_thickness", 2 * PROP_WINDOW_SCALE)
self.hands_rounded_edges = config.get("hands_rounded_edges", True)
self.hands_smooth_motion = config.get("hands_smooth_motion", True)
def draw_line_round_corners_polygon(self, surf, p1, p2, c, w):
p1v = self.pygame.math.Vector2(p1)
p2v = self.pygame.math.Vector2(p2)
lv = (p2v - p1v).normalize()
lnv = self.pygame.math.Vector2(-lv.y, lv.x) * w // 2
pts = [p1v + lnv, p2v + lnv, p2v - lnv, p1v - lnv]
self.pygame.draw.polygon(surf, c, pts)
self.pygame.draw.circle(surf, c, p1, round(w / 2))
self.pygame.draw.circle(surf, c, p2, round(w / 2))
def clock_hand(self, screen, centre, radius, angle, thickness, color):
x = centre[0] + radius * math.cos(math.radians(angle - 90))
y = centre[1] + radius * math.sin(math.radians(angle - 90))
self.pygame.draw.line(screen, color, centre, (int(x), int(y)), thickness)
if self.hands_rounded_edges:
# self.pygame.draw.circle(screen, color, (int(x), int(y)), thickness / 2)
self.draw_line_round_corners_polygon(screen, centre, (int(x), int(y)), color, thickness)
def draw_clock(self, screen):
screen_centre = get_screen_centre()
self.pygame.draw.circle(screen, self.clock_background_color, screen_centre, self.clock_radius)
def draw_markings(self, screen):
screen_centre = get_screen_centre()
for i in range(0, 360, 30):
angle_radians = math.radians(i)
cos = math.cos(angle_radians)
sin = math.sin(angle_radians)
x1 = screen_centre[0] + self.clock_inner_radius * cos
y1 = screen_centre[1] + self.clock_inner_radius * sin
x2 = x1 + self.marking_length * cos
y2 = y1 + self.marking_length * sin
self.pygame.draw.line(screen, self.marking_color, (x1, y1), (x2, y2), self.marking_width)
def draw(self, screen):
# Fill the background
if self.draw_background:
if self.background_type == "color":
screen.fill(self.background_color)
elif self.background_type == "image":
screen.blit(self.bg_image, (0, 0))
if self.draw_clock_background:
self.draw_clock(screen)
self.draw_markings(screen)
curr_time = datetime.now()
if self.hands_smooth_motion:
second = curr_time.second + curr_time.microsecond / 1000000
minute = curr_time.minute + second / 60
hour = curr_time.hour + minute / 60
else:
hour = curr_time.hour
minute = curr_time.minute
second = curr_time.second
self.clock_hand(screen, get_screen_centre(), self.second_hand_length, second * 6, self.second_hand_thickness, self.second_hand_color)
self.clock_hand(screen, get_screen_centre(), self.minute_hand_length, minute * 6, self.minute_hand_thickness, self.minute_hand_color)
self.clock_hand(screen, get_screen_centre(), self.hour_hand_length, hour * 30, self.hour_hand_thickness, self.hour_hand_color)
class IPShowWidget(IWidget):
def __init__(self, config: dict):
super().__init__(config)
self.pygame = config['pygame']
# Backgrounds
self.background_color = config.get("background_color", "black")
self.draw_background = config.get("draw_background", False)
self.draw_clock_background = config.get("draw_clock_background", True)
self.background_type = config.get("background_type", "color")
if self.background_type == "image" and config.get("background_image", "") != "":
self.bg_image = self.pygame.image.load(config.get("background_image", ""))
self.bg_image = self.pygame.transform.scale(self.bg_image, (
PROP_SCREEN_WIDTH * PROP_WINDOW_SCALE,
PROP_SCREEN_HEIGHT * PROP_WINDOW_SCALE
))
# Get the font path
self.font_path = get_font_path_or_default(self.pygame, config.get("font_name", None), config.get("font_bold", False), config.get("font_italic", False))
# Load the font
self.font = self.pygame.font.Font(self.font_path, config.get("font_size", 15 * PROP_WINDOW_SCALE))
self.font.bold = config.get("font_bold", False)
self.font.italic = config.get("font_italic", False)
# Set the colours
self.color = config.get("font_color", "white")
def draw(self, screen):
if self.draw_background:
if self.background_type == "color":
screen.fill(self.background_color)
elif self.background_type == "image":
screen.blit(self.bg_image, (0, 0))
text_surface = self.font.render(f"IP Address:", True, self.color)
text_surface_2 = self.font.render(get_ip(), True, self.color)
text_rect = text_surface.get_rect(center=get_screen_centre())
y = get_screen_centre()[1] + self.font.size("IP Address:")[1] + 10
text_rect_2 = text_surface_2.get_rect(center=(get_screen_centre()[0], y))
screen.blit(text_surface, text_rect)
screen.blit(text_surface_2, text_rect_2)