From 2b832f1b0ed88b7db2fa703a0e7ebe336df23c12 Mon Sep 17 00:00:00 2001 From: DJ Sundog Date: Sun, 2 Aug 2020 18:26:50 -0700 Subject: [PATCH] first working pass at menu scrolling --- SoundslabDisplay.py | 16 +++--- SoundslabInput.py | 127 ++++++++++++++++++++++++++++++++++---------- 2 files changed, 108 insertions(+), 35 deletions(-) diff --git a/SoundslabDisplay.py b/SoundslabDisplay.py index fe85f30..3d2355f 100644 --- a/SoundslabDisplay.py +++ b/SoundslabDisplay.py @@ -9,7 +9,7 @@ import musicpd from math import floor class SoundslabDisplay: - def __init__(self, player_client): + def __init__(self, player_client, input_handler): self.screen_size = 240, 240 self.spi_speed_mhz = 80 self.st7789 = ST7789( @@ -30,12 +30,13 @@ class SoundslabDisplay: # the connection to mpd passed in self.player_client = player_client + # the connection to the input handler passed in + self.input_handler = input_handler + # track battery voltage over time so we can figure out if we're charging the battery or not self.previous_voltage = 0.0 # track currently playing song's art path to eliminate unnecessary reloads of the same image file self.current_art_path = None - # start with menus hidden - self.show_menu = False def _displayOff(self): self.st7789.set_backlight(0) # turn off the backlight @@ -70,13 +71,14 @@ class SoundslabDisplay: return (voltage, capacity) - def updateMenu(self, menu_data=None): + def updateMenu(self): + menu_data = self.input_handler.getMenuOptions() # always start with a transparent menu overlay image bg_color = (200, 0, 0, 255) fg_color = (0, 0, 0, 255) im_menu_overlay = Image.new("RGBA", self.screen_size, (0, 0, 0, 0)) menu_overlay = ImageDraw.Draw(im_menu_overlay) - if self.show_menu and menu_data is not None: + if self.input_handler.state == self.input_handler.MENU and menu_data is not None: # we have a menu to display # # menu_data is structured as a dict describing the menu to be displayed: @@ -108,11 +110,11 @@ class SoundslabDisplay: font = ImageFont.truetype(font='/usr/share/fonts/truetype/hack/Hack-Bold.ttf', size=15) for idx, row in enumerate(menu_data["rows"], start=0): - if menu_data["selected"] == idx: + if idx == 1: menu_overlay.rectangle([(21, offset_from_top),(self.screen_size[0] - 21, offset_from_top + 40)], fg_color) # highlight background for selected menu item output_size = menu_overlay.textsize(row) # get the size of the text to draw so we can center it in our rectangle for this row - menu_overlay.text(((self.screen_size[0] / 2) - floor(output_size[0] / 2) - 14, offset_from_top + (20 - floor(output_size[1]) + 1)), row, font=font, fill=bg_color if menu_data["selected"] == idx else fg_color) # draw output text in appropriate color + menu_overlay.text(((self.screen_size[0] / 2) - floor(output_size[0] / 2) - 14, offset_from_top + (20 - floor(output_size[1]) + 1)), row, font=font, fill=bg_color if idx == 1 else fg_color) # draw output text in appropriate color offset_from_top += 40 # finally, set the current_menu image diff --git a/SoundslabInput.py b/SoundslabInput.py index baacc6b..78e2ea2 100644 --- a/SoundslabInput.py +++ b/SoundslabInput.py @@ -12,7 +12,14 @@ class SoundslabInputHandler: self.player_client.connect() # initialize connection to display - self.display = SoundslabDisplay(self.player_client) + self.display = SoundslabDisplay(self.player_client, self) + + # set up some states and an initial state + (self.NOWPLAYING, self.MENU, self.LOCKED) = [1, 2, 3] + self.state = self.NOWPLAYING + self.current_menu_level = 1 + self.current_menu_position = 0 + self.current_menu_items = [] # The buttons on Pirate Audio are connected to pins 5, 6, 16 and 24 # Boards prior to 23 January 2020 used 5, 6, 16 and 20 @@ -48,9 +55,53 @@ class SoundslabInputHandler: for pin in self.BUTTONS: GPIO.add_event_detect(pin, GPIO.FALLING, self.handle_button, bouncetime=150) + # menu handler + def getMenuOptions(self): + if self.current_menu_level == 1: + menu = { + "options": [ + "Toggle repeat", + "Toggle shuffle", + "View queue >", + "Browse playlists >", + "Browse artists >", + "Browse genres >", + "Browse decades >", + "Browse albums >", + "Browse songs >", + "Shuffle all songs", + "Shuffle all albums", + "Settings >", + "Power off", + "About" + ] + } + + if self.current_menu_position == 0: + rows = ["", menu["options"][self.current_menu_position], menu["options"][self.current_menu_position + 1]] + elif self.current_menu_position == len(menu["options"]) - 1: + rows = [menu["options"][self.current_menu_position - 1], menu["options"][self.current_menu_position], ""] + else: + # one before current, current, and one after current + rows = [ menu["options"][self.current_menu_position - 1], menu["options"][self.current_menu_position], menu["options"][self.current_menu_position + 1] ] + + self.current_menu_items = menu["options"] + + return { + "has_previous": False if self.current_menu_position == 0 else True, + "has_next": False if self.current_menu_position == len(menu["options"]) else True, + "selected": self.current_menu_position, + "rows": rows + } + else: + return None + + def handle_menu_option_select(self): + pass + # some button handlers def NE(self): - # play/pause toggle + # this is ALWAYS play/pause toggle status = self.player_client.status() if status['state'] == "play": print("pausing") @@ -63,7 +114,7 @@ class SoundslabInputHandler: player_client.play() def SW(self): - # previous track + # this is ALWAYS previous track status = player_client.status() if float(status['elapsed']) > 5.0: # restart track @@ -75,31 +126,59 @@ class SoundslabInputHandler: self.player_client.previous() def NW(self): - # open menu + # this is ALWAYS toggle menu print("toggling menu") - if self.display.show_menu is True: - self.display.show_menu = False + if self.state != self.MENU: + self.last_state = self.state + self.state = self.MENU else: - self.display.show_menu = True + self.state = self.last_state + self.current_menu_level = 1 + self.current_menu_position = 0 + self.current_menu_items = [] def SE(self): - # next track + # this is ALWAYS next track print("next track") self.player_client.next() def UP(self): - # volume up 10% - print("vol up") - status = self.player_client.status() - if int(status['volume']) < 100: - self.player_client.setvol(int(status['volume']) + 10) + # check current state + if self.state == self.NOWPLAYING: + # volume up 10% + print("vol up") + status = self.player_client.status() + if int(status['volume']) < 100: + self.player_client.setvol(int(status['volume']) + 10) + elif self.state == self.MENU: + # move up + print("up one menu item") + if self.current_menu_position != 0: + self.current_menu_position -= 1 + else: + print("cannot go up from here!") + else: + # no op when screen is locked + pass def DN(self): - # volume down 10% - print("vol down") - status = self.player_client.status() - if int(status['volume']) > 0: - self.player_client.setvol(int(status['volume']) - 10) + # check current state + if self.state == self.NOWPLAYING: + # volume down 10% + print("vol down") + status = self.player_client.status() + if int(status['volume']) > 0: + self.player_client.setvol(int(status['volume']) - 10) + elif self.state == self.MENU: + # move down + print("down one menu item") + if self.current_menu_position < len(self.current_menu_items) - 1: + self.current_menu_position += 1; + else: + print("cannot go down from here!") + else: + # no op when screen is locked + pass def LF(self): # seek back 10s @@ -129,16 +208,8 @@ class SoundslabInputHandler: input_handler = SoundslabInputHandler() while True: - if input_handler.display.show_menu is True: - # test menu - input_handler.display.updateMenu({ - "has_previous": False, - "has_next": True, - "selected": 0, - "rows": ["Turn repeat on", "Turn shuffle on", "View queue >"] - }) - else: - input_handler.display.updateMenu() + # test menu + input_handler.display.updateMenu() # test album art input_handler.display.updateAlbumArt() # test setting up the overlay