Skip to content
Snippets Groups Projects
Select Git revision
  • 86b8cd1ef2751e82ea50f31e7a0465f19670b76d
  • master default protected
2 results

screenwidgets.py

Blame
  • 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)