display.py 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148
  1. #!./bin/python3
  2. import os
  3. import yaml
  4. import pygame # type: ignore
  5. from typing import Dict
  6. import random
  7. # Color constants
  8. BLACK = (0, 0, 0)
  9. GREEN = (0, 255, 0)
  10. WHITE = (255, 255, 255)
  11. class Display:
  12. '''
  13. Display object
  14. '''
  15. def __init__(self, config, pydsp):
  16. # Set config values
  17. self._dx = config.get("dimx", 128) # Drawing dimensions
  18. self._dy = config.get("dimy", 160)
  19. self._playlistFile = config.get("playlist", "music.yml") # Playlist data
  20. self._pydsp = pydsp # Pygame display object
  21. self._fontsize = config.get("fontsize", 12) # Fontsize to use
  22. self._drawlines = int(self._dy / 12) - 5 # Max number of drawn lines
  23. # Set initialisation values
  24. self._selection_pointer = 0 # Current selected value
  25. self._line_offset = 0 # Drawing offset in playlist
  26. self._current_item = None
  27. self._bgImg = None
  28. def getPlaylist(self) -> Dict:
  29. '''
  30. Return the playlist for this display.
  31. '''
  32. return yaml.safe_load(open(self._playlistFile)).get("playlist", [])
  33. def update(self):
  34. '''
  35. Load the data from the given playlist file and draw it according to the current state.
  36. '''
  37. self._pydsp.fill((0,0,0))
  38. playlist = self.getPlaylist()
  39. # Correct offset and selection pointer
  40. if self._selection_pointer < 0:
  41. self._selection_pointer = 0 # Make sure the selection is at least at pos 0
  42. if self._line_offset > 0: # Move the line offset down if possible
  43. self._line_offset-=1
  44. elif self._selection_pointer > self._drawlines: # Make sure sure selection does not exceed list
  45. self._selection_pointer = self._drawlines # Move the line offset up if possible
  46. if self._line_offset < len(playlist) - self._drawlines - 1:
  47. self._line_offset+=1
  48. # Draw lines
  49. font = pygame.font.Font('freesansbold.ttf', self._fontsize)
  50. drawline = 0 # Line currently drawm
  51. for i, item in enumerate(playlist):
  52. # Skip lines until we reached the offset
  53. if i < self._line_offset:
  54. continue
  55. # Draw the line
  56. if drawline == self._selection_pointer:
  57. text = font.render(item["name"], True, BLACK, GREEN)
  58. pygame.draw.rect(self._pydsp, BLACK, (0,0,self._dx,50))
  59. try:
  60. self.drawArt(item)
  61. except Exception as e:
  62. print("Error while drawing art:", e)
  63. self._current_item = item
  64. else:
  65. text = font.render(item["name"], True, GREEN, BLACK)
  66. self._pydsp.blit(text, (0, drawline * self._fontsize+50))
  67. # Increase number of drawn lines - stop when the maximum is reached
  68. drawline += 1
  69. if drawline > self._drawlines:
  70. break
  71. def drawArt(self, item):
  72. '''
  73. Beautify the display.
  74. '''
  75. font = pygame.font.Font('freesansbold.ttf', self._fontsize)
  76. # Draw a background image
  77. if self._bgImg is None:
  78. bg = os.listdir("web/background")
  79. bg = bg[random.randint(0, len(bg)-1)]
  80. self._bgImg = pygame.image.load(os.path.join("web/background", bg))
  81. pygame.transform.scale(self._bgImg, (self._dx, 50))
  82. self._pydsp.blit(self._bgImg, (0,0), (0, 0, self._dx, 50))
  83. path = item.get("path")
  84. title = item.get("name", "")
  85. artist = item.get("artist", "")
  86. # Try to extract meta data
  87. if path is not None:
  88. pass
  89. s = title
  90. if artist != "":
  91. s = "%s (%s)" % (s, artist)
  92. text = font.render(s, True, WHITE, BLACK)
  93. self._pydsp.blit(text, (0, 38))
  94. def currentItem(self) -> Dict:
  95. '''
  96. Return the current selected item.
  97. '''
  98. return self._current_item
  99. def action(self, action: str):
  100. '''
  101. Perform an action to this display.
  102. '''
  103. if action == "up":
  104. self._selection_pointer-=1
  105. elif action == "down":
  106. self._selection_pointer+=1
  107. self.update()