#!./bin/python3 import os import yaml import pygame # type: ignore from typing import Dict import random # Color constants BLACK = (0, 0, 0) GREEN = (0, 255, 0) WHITE = (255, 255, 255) class Display: ''' Display object ''' def __init__(self, config, pydsp): # Set config values self._dx = config.get("dimx", 128) # Drawing dimensions self._dy = config.get("dimy", 160) self._playlistFile = config.get("playlist", "music.yml") # Playlist data self._pydsp = pydsp # Pygame display object self._fontsize = config.get("fontsize", 12) # Fontsize to use self._drawlines = int(self._dy / 12) - 5 # Max number of drawn lines # Set initialisation values self._selection_pointer = 0 # Current selected value self._line_offset = 0 # Drawing offset in playlist self._current_item = None self._bgImg = None def getPlaylist(self) -> Dict: ''' Return the playlist for this display. ''' return yaml.safe_load(open(self._playlistFile)).get("playlist", []) def update(self): ''' Load the data from the given playlist file and draw it according to the current state. ''' self._pydsp.fill((0,0,0)) playlist = self.getPlaylist() # Correct offset and selection pointer if self._selection_pointer < 0: self._selection_pointer = 0 # Make sure the selection is at least at pos 0 if self._line_offset > 0: # Move the line offset down if possible self._line_offset-=1 elif self._selection_pointer > self._drawlines: # Make sure sure selection does not exceed list self._selection_pointer = self._drawlines # Move the line offset up if possible if self._line_offset < len(playlist) - self._drawlines - 1: self._line_offset+=1 # Draw lines font = pygame.font.Font('freesansbold.ttf', self._fontsize) drawline = 0 # Line currently drawm for i, item in enumerate(playlist): # Skip lines until we reached the offset if i < self._line_offset: continue # Draw the line if drawline == self._selection_pointer: text = font.render(item["name"], True, BLACK, GREEN) pygame.draw.rect(self._pydsp, BLACK, (0,0,self._dx,50)) try: self.drawArt(item) except Exception as e: print("Error while drawing art:", e) self._current_item = item else: text = font.render(item["name"], True, GREEN, BLACK) self._pydsp.blit(text, (0, drawline * self._fontsize+50)) # Increase number of drawn lines - stop when the maximum is reached drawline += 1 if drawline > self._drawlines: break def drawArt(self, item): ''' Beautify the display. ''' font = pygame.font.Font('freesansbold.ttf', self._fontsize) # Draw a background image if self._bgImg is None: bg = os.listdir("web/background") bg = bg[random.randint(0, len(bg)-1)] self._bgImg = pygame.image.load(os.path.join("web/background", bg)) pygame.transform.scale(self._bgImg, (self._dx, 50)) self._pydsp.blit(self._bgImg, (0,0), (0, 0, self._dx, 50)) path = item.get("path") title = item.get("name", "") artist = item.get("artist", "") # Try to extract meta data if path is not None: pass s = title if artist != "": s = "%s (%s)" % (s, artist) text = font.render(s, True, WHITE, BLACK) self._pydsp.blit(text, (0, 38)) def currentItem(self) -> Dict: ''' Return the current selected item. ''' return self._current_item def action(self, action: str): ''' Perform an action to this display. ''' if action == "up": self._selection_pointer-=1 elif action == "down": self._selection_pointer+=1 self.update()