class HomeMenu(Menu): """ Home Menu class. Extends base Menu class """ def __init__(self, util, bgr=None, bounding_box=None, font_size=None): """ Initializer :param util: utility object :param bgr: menu background :param bounding_box: bounding box """ self.util = util self.factory = Factory(util) self.config = util.config self.cdutil = CdUtil(util) self.bb = bounding_box self.horizontal_layout = True self.rows = None self.cols = None items = self.get_menu_items() cell_bb = items[2] m = self.create_home_menu_button label_area = (cell_bb.h / 100) * (100 - ICON_AREA) font_size = int((label_area / 100) * FONT_HEIGHT) Menu.__init__(self, util, bgr, bounding_box, None, None, create_item_method=m, font_size=font_size) self.set_modes(*items) def get_menu_items(self): """ Prepare menu items :return: array containing menu items, disabled items, cell bounding box snf icon box """ items = [] disabled_items = [] player = self.config[AUDIO][PLAYER_NAME] if self.config[HOME_MENU][RADIO]: items.append(RADIO) if not self.util.is_radio_enabled( ) or not self.util.connected_to_internet: disabled_items.append(RADIO) if self.config[HOME_MENU][AUDIO_FILES]: items.append(AUDIO_FILES) if self.config[HOME_MENU][AUDIOBOOKS]: items.append(AUDIOBOOKS) if not self.util.is_audiobooks_enabled( ) or not self.util.connected_to_internet: disabled_items.append(AUDIOBOOKS) if self.config[HOME_MENU][STREAM]: items.append(STREAM) if not self.util.connected_to_internet: disabled_items.append(STREAM) if self.config[HOME_MENU][CD_PLAYER]: cd_drives_info = self.cdutil.get_cd_drives_info() if len(cd_drives_info) == 0 or player == MPV_NAME: disabled_items.append(CD_PLAYER) items.append(CD_PLAYER) if self.config[HOME_MENU][PODCASTS]: podcasts_util = self.util.get_podcasts_util() podcasts = podcasts_util.get_podcasts_links() downloads = podcasts_util.are_there_any_downloads() connected = self.util.connected_to_internet valid_players = [VLC_NAME, MPV_NAME] if (connected and len(podcasts) == 0 and not downloads) or ( not connected and not downloads) or player not in valid_players: disabled_items.append(PODCASTS) items.append(PODCASTS) if self.config[HOME_MENU][AIRPLAY]: items.append(AIRPLAY) if not self.util.config[LINUX_PLATFORM]: disabled_items.append(AIRPLAY) if self.config[HOME_MENU][SPOTIFY_CONNECT]: items.append(SPOTIFY_CONNECT) if not self.util.config[LINUX_PLATFORM]: disabled_items.append(SPOTIFY_CONNECT) if self.config[HOME_MENU][COLLECTION]: items.append(COLLECTION) db_util = self.util.get_db_util() if db_util.conn == None: disabled_items.append(COLLECTION) l = self.get_layout(items) bounding_box = l.get_next_constraints() box = self.factory.get_icon_bounding_box(bounding_box, ICON_LOCATION, ICON_AREA, ICON_SIZE, BUTTON_PADDING) return (items, disabled_items, bounding_box, box) def set_current_modes(self): """ Set current player modes """ items = self.get_menu_items() self.set_modes(*items) def set_modes(self, items, disabled_items, bounding_box, box): """ Set menu items :param items: menu items :param disabled_items: disabled menu items :param bounding_box: cell bounding box :param box: image boundng box """ self.modes = self.util.load_menu(items, NAME, disabled_items, V_ALIGN_TOP, bb=box) va_commands = self.util.get_voice_commands() if self.config[USAGE][USE_VOICE_ASSISTANT]: self.add_voice_command(RADIO, ["VA_RADIO", "VA_GO_RADIO"], va_commands) self.add_voice_command(AUDIO_FILES, ["VA_FILES", "VA_GO_FILES"], va_commands) self.add_voice_command( AUDIOBOOKS, ["VA_AUDIOBOOKS", "VA_BOOKS", "VA_GO_BOOKS"], va_commands) self.add_voice_command(STREAM, ["VA_STREAM", "VA_GO_STREAM"], va_commands) self.add_voice_command(CD_PLAYER, ["VA_CD_PLAYER"], va_commands) self.add_voice_command(PODCASTS, ["VA_PODCAST", "VA_PODCASTS"], va_commands) if not items: return if not self.config[CURRENT][MODE]: for i in items: if i not in disabled_items: mode = i break else: mode = self.config[CURRENT][MODE] self.set_items(self.modes, 0, self.change_mode, False) self.current_mode = self.modes[mode.lower()] self.item_selected(self.current_mode) def create_home_menu_button(self, s, constr, action, scale, font_size): """ Create Home Menu button :param s: button state :param constr: scaling constraints :param action: button event listener :param scale: True - scale images, False - don't scale images :param font_size: label font height in pixels :return: home menu button """ s.padding = BUTTON_PADDING s.image_area_percent = ICON_AREA return self.factory.create_menu_button(s, constr, action, scale, font_size=font_size) def add_voice_command(self, name, commands, va_commands): """ Add voice command :param name: item name :param commands: item commands :param va_commands: voice commands """ if not self.config[HOME_MENU][name]: return c = [] for m in commands: c.append(va_commands[m].strip()) self.modes[name].voice_commands = c def change_mode(self, state): """ Change mode event listener :param state: button state """ if not self.visible: return state.previous_mode = self.current_mode.name self.current_mode = state self.config[CURRENT][MODE] = state.name self.notify_listeners(state)
class FileBrowserScreen(Screen): """ File Browser Screen """ def __init__(self, util, get_current_playlist, playlist_provider, listeners, voice_assistant): """ Initializer :param util: utility object :param listeners: file browser listeners """ self.util = util self.config = util.config self.factory = Factory(util) self.bounding_box = util.screen_rect layout = BorderLayout(self.bounding_box) layout.set_percent_constraints(PERCENT_TOP_HEIGHT, PERCENT_BOTTOM_HEIGHT, 0, 0) Screen.__init__(self, util, "", PERCENT_TOP_HEIGHT, voice_assistant, "file_browser_screen_title", True, layout.TOP) current_folder = self.util.file_util.current_folder d = {"current_title": current_folder} if self.config[FILE_PLAYBACK][ CURRENT_FILE_PLAYBACK_MODE] == FILE_PLAYLIST: f = self.config[FILE_PLAYBACK][CURRENT_FOLDER] p = self.config[FILE_PLAYBACK][CURRENT_FILE_PLAYLIST] d = f + os.sep + p self.screen_title.set_text(d) rows = self.config[FILE_BROWSER_ROWS] columns = self.config[FILE_BROWSER_COLUMNS] self.filelist = None playback_mode = self.config[FILE_PLAYBACK][CURRENT_FILE_PLAYBACK_MODE] if not playback_mode: self.config[FILE_PLAYBACK][ CURRENT_FILE_PLAYBACK_MODE] = playback_mode = FILE_AUDIO button_box = pygame.Rect(0, 0, layout.CENTER.w / columns, layout.CENTER.h / rows) if self.config[ALIGN_BUTTON_CONTENT_X] == 'center': location = TOP else: location = self.config[ALIGN_BUTTON_CONTENT_X] icon_box = self.factory.get_icon_bounding_box(button_box, location, self.config[IMAGE_AREA], self.config[IMAGE_SIZE], self.config[PADDING]) icon_box_without_label = self.factory.get_icon_bounding_box( button_box, location, 100, 100, self.config[PADDING], False) if playback_mode == FILE_AUDIO or playback_mode == FILE_RECURSIVE: folder_content = self.util.load_folder_content( current_folder, rows, columns, icon_box, icon_box_without_label) self.filelist = Page(folder_content, rows, columns) elif playback_mode == FILE_PLAYLIST: s = State() s.folder = self.config[FILE_PLAYBACK][CURRENT_FOLDER] s.music_folder = self.config[AUDIO][MUSIC_FOLDER] s.file_name = self.config[FILE_PLAYBACK][CURRENT_FILE_PLAYLIST] pl = self.get_filelist_items(get_current_playlist) if len(pl) == 0: pl = self.util.load_playlist(s, playlist_provider, rows, columns, (icon_box.w, icon_box.h)) else: pl = self.util.load_playlist_content(pl, rows, columns, (icon_box.w, icon_box.h)) self.filelist = Page(pl, rows, columns) self.file_menu = FileMenu(self.filelist, util, playlist_provider, layout.CENTER, location, icon_box, icon_box_without_label) self.file_menu.parent_screen = self self.file_menu.link_borders = self.link_borders self.file_menu.add_change_folder_listener(self.screen_title.set_text) self.file_menu.add_play_file_listener(listeners[KEY_PLAY_FILE]) listeners[GO_LEFT_PAGE] = self.file_menu.page_down listeners[GO_RIGHT_PAGE] = self.file_menu.page_up listeners[GO_USER_HOME] = self.file_menu.switch_to_user_home listeners[GO_ROOT] = self.file_menu.switch_to_root listeners[GO_TO_PARENT] = self.file_menu.switch_to_parent_folder self.navigator = FileNavigator(util, layout.BOTTOM, listeners) left = str(self.filelist.get_left_items_number()) right = str(self.filelist.get_right_items_number()) left_button = self.navigator.get_button_by_name(KEY_PAGE_DOWN) right_button = self.navigator.get_button_by_name(KEY_PAGE_UP) self.back_button = self.navigator.get_button_by_name(KEY_BACK) left_button.change_label(left) right_button.change_label(right) self.file_menu.add_left_number_listener(left_button.change_label) self.file_menu.add_right_number_listener(right_button.change_label) self.add_navigator(self.navigator) self.page_turned = False self.animated_title = True self.file_menu.navigator = self.navigator self.add_menu(self.file_menu) self.link_borders() self.back_button.set_selected(True) def get_filelist_items(self, get_current_playlist): """ Call player for files in the playlist :return: list of files from playlist """ playlist = get_current_playlist() files = [] if playlist: for n in range(len(playlist)): st = State() st.index = st.comparator_item = n st.file_type = FILE_AUDIO st.file_name = st.url = playlist[n] files.append(st) return files def add_screen_observers(self, update_observer, redraw_observer): """ Add screen observers :param update_observer: observer for updating the screen :param redraw_observer: observer to redraw the whole screen """ Screen.add_screen_observers(self, update_observer, redraw_observer) self.file_menu.add_menu_observers(update_observer, redraw_observer, release=False) self.file_menu.add_change_folder_listener(redraw_observer) self.file_menu.add_menu_navigation_listeners(redraw_observer) self.file_menu.add_left_number_listener(redraw_observer) self.file_menu.add_right_number_listener(redraw_observer) self.navigator.add_observers(update_observer, redraw_observer) def handle_event(self, event): """ Handle screen event :param event: the event to handle """ if event.type == USER_EVENT_TYPE and event.sub_type == SUB_TYPE_KEYBOARD and ( event.action == pygame.KEYUP or event.action == pygame.KEYDOWN): menu_selected = self.file_menu.get_selected_index() navigator_selected = self.navigator.is_selected() if menu_selected != None: self.file_menu.handle_event(event) elif navigator_selected: self.navigator.handle_event(event) else: Screen.handle_event(self, event)
class RadioGroupScreen(MenuScreen): """ Radio group screen """ def __init__(self, util, listeners, voice_assistant): self.util = util self.config = util.config self.groups_list = self.util.get_stations_folders() self.factory = Factory(util) d = [MENU_ROWS, MENU_COLUMNS] MenuScreen.__init__(self, util, listeners, MENU_ROWS, MENU_COLUMNS, voice_assistant, d, self.turn_page, page_in_title=False) self.total_pages = math.ceil(len(self.groups_list) / PAGE_SIZE) self.title = util.get_stations_top_folder() m = self.create_genre_menu_button label_area = ( (self.menu_layout.h / MENU_ROWS) / 100) * (100 - ICON_AREA) font_size = int((label_area / 100) * FONT_HEIGHT) self.groups_menu = MultiPageMenu(util, self.next_page, self.previous_page, self.set_title, self.reset_title, self.go_to_page, m, MENU_ROWS, MENU_COLUMNS, None, (0, 0, 0, 0), self.menu_layout, align=ALIGN_CENTER, font_size=font_size) self.groups_menu.add_listener(listeners[KEY_GENRE]) self.set_menu(self.groups_menu) color_dark_light = self.config[COLORS][COLOR_DARK_LIGHT] self.navigator = RadioGroupNavigator(self.util, self.layout.BOTTOM, listeners, color_dark_light, self.total_pages) self.add_component(self.navigator) current_name = self.get_current_group_name() if current_name == None: self.current_page = 1 else: try: current_group_index = self.groups_list.index(current_name) self.current_page = int(current_group_index / PAGE_SIZE) + 1 except: current_group_index = 0 self.turn_page() def create_genre_menu_button(self, s, constr, action, scale, font_size): """ Create Genre Menu button :param s: button state :param constr: scaling constraints :param action: button event listener :param scale: True - scale images, False - don't scale images :return: genre menu button """ s.padding = BUTTON_PADDING s.image_area_percent = ICON_AREA s.fixed_height = font_size s.v_align = CENTER return self.factory.create_menu_button(s, constr, action, scale, font_size=font_size) def get_current_group_name(self): key = STATIONS + "." + self.config[CURRENT][LANGUAGE] name = None try: name = self.config[key][CURRENT_STATIONS] except: pass return name def get_page(self): start = (self.current_page - 1) * PAGE_SIZE end = self.current_page * PAGE_SIZE tmp_layout = self.groups_menu.get_layout(self.groups_list) button_rect = tmp_layout.constraints[0] image_box = self.factory.get_icon_bounding_box(button_rect, ICON_LOCATION, ICON_AREA, ICON_SIZE, BUTTON_PADDING) groups_dict = self.util.load_stations_folders(image_box) return self.util.get_radio_group_slice(groups_dict, start, end) def turn_page(self): """ Turn book genre page """ group_page = self.get_page() self.groups_menu.set_items(group_page, 0, self.change_group, False) current_name = self.get_current_group_name() try: self.current_genre = group_page[current_name] self.groups_menu.item_selected(self.current_genre) except: keys = list(group_page.keys()) self.groups_menu.item_selected(group_page[keys[0]]) if self.navigator and self.total_pages > 1: self.navigator.left_button.change_label(str(self.current_page - 1)) self.navigator.right_button.change_label( str(self.total_pages - self.current_page)) for b in self.groups_menu.buttons.values(): b.parent_screen = self self.set_title(self.current_page) self.groups_menu.clean_draw_update() def change_group(self, state): """ Change group event listener :param state: button state """ if not self.visible: return self.current_genre = state key = STATIONS + "." + self.config[CURRENT][LANGUAGE] self.config[key][CURRENT_STATIONS] = state.genre state.source = GENRE self.groups_menu.notify_listeners(state) def add_screen_observers(self, update_observer, redraw_observer): """ Add screen observers :param update_observer: observer for updating the screen :param redraw_observer: observer to redraw the whole screen """ self.navigator.add_observers(update_observer, redraw_observer) self.groups_menu.add_menu_observers(update_observer, redraw_observer, release=False)
class SaverMenu(Menu): """ Screensaver Menu class. Extends base Menu class """ def __init__(self, util, bgr=None, bounding_box=None): """ Initializer :param util: utility object :param bgr: menu background :param bounding_box: bounding box """ self.factory = Factory(util) self.config = util.config items = [] if self.config[SCREENSAVER_MENU][CLOCK]: items.append(CLOCK) if self.config[SCREENSAVER_MENU][LOGO]: items.append(LOGO) if self.config[SCREENSAVER_MENU][SLIDESHOW]: items.append(SLIDESHOW) if self.config[SCREENSAVER_MENU][VUMETER]: items.append(VUMETER) if self.config[SCREENSAVER_MENU][WEATHER]: items.append(WEATHER) if self.config[SCREENSAVER_MENU][SPECTRUM]: items.append(SPECTRUM) if self.config[SCREENSAVER_MENU][LYRICS]: items.append(LYRICS) if self.config[SCREENSAVER_MENU][RANDOM]: items.append(RANDOM) rows_num = 2 cols_num = 4 length = len(items) if length == 6 or length == 5: rows_num = 2 cols_num = 3 elif length == 4: rows_num = 2 cols_num = 2 elif length == 3: rows_num = 1 cols_num = 3 elif length == 2: rows_num = 1 cols_num = 2 elif length == 1: rows_num = 1 cols_num = 1 m = self.create_saver_menu_button label_area = (bounding_box.h / rows_num / 100) * (100 - ICON_AREA) font_size = int((label_area / 100) * FONT_HEIGHT) Menu.__init__(self, util, bgr, bounding_box, rows=rows_num, cols=cols_num, create_item_method=m, font_size=font_size) current_saver_name = items[0] for s in items: if s == self.config[SCREENSAVER][NAME]: current_saver_name = s break l = self.get_layout(items) bounding_box = l.get_next_constraints() box = self.factory.get_icon_bounding_box(bounding_box, ICON_LOCATION, ICON_AREA, ICON_SIZE, BUTTON_PADDING) box.w = box.w / 2 self.savers = util.load_menu(items, GENRE, v_align=V_ALIGN_TOP, bb=box) if self.config[USAGE][USE_VOICE_ASSISTANT]: voice_commands = util.get_voice_commands() self.savers[CLOCK].voice_commands = [voice_commands["VA_CLOCK"].strip()] self.savers[LOGO].voice_commands = [voice_commands["VA_LOGO"].strip()] self.savers[SLIDESHOW].voice_commands = [voice_commands["VA_SLIDESHOW"].strip()] self.savers[VUMETER].voice_commands = [voice_commands["VA_INDICATOR"].strip()] self.savers[WEATHER].voice_commands = [voice_commands["VA_WEATHER"].strip()] self.set_items(self.savers, 0, self.change_saver, False) self.current_saver = self.savers[current_saver_name] self.item_selected(self.current_saver) def create_saver_menu_button(self, s, constr, action, scale, font_size): """ Create Screensaver Menu button :param s: button state :param constr: scaling constraints :param action: button event listener :param scale: True - scale images, False - don't scale images :param font_size: label font height in pixels :return: screensaver menu button """ s.padding = BUTTON_PADDING s.image_area_percent = ICON_AREA s.v_align = CENTER return self.factory.create_menu_button(s, constr, action, scale, font_size=font_size) def get_saver_by_index(self, index): """ Return screensaver specified by its index :param index: screensaver index in the map of screensavers :return: screensaver """ return self.savers[index] def change_saver(self, state): """ Change screensaver event listener :param state: button state """ if not self.visible: return self.config[SCREENSAVER][NAME] = state.name self.notify_listeners(state)
class LanguageMenu(Menu): """ Language Menu class. Extends base Menu class """ def __init__(self, util, bgr=None, bounding_box=None): """ Initializer :param util: utility object :param bgr: menu background :param bounding_box: bounding box """ self.util = util self.factory = Factory(util) m = self.create_language_menu_button Menu.__init__(self, util, bgr, bounding_box, None, None, create_item_method=m) self.config = self.util.config language = self.config[CURRENT][LANGUAGE] languages = self.config[KEY_LANGUAGES] layout = self.get_layout(languages) button_rect = layout.constraints[0] image_box = self.factory.get_icon_bounding_box(button_rect, ICON_LOCATION, ICON_AREA, ICON_SIZE, BUTTON_PADDING) self.languages = self.util.load_languages_menu(image_box) label_area = (button_rect.h / 100) * (100 - ICON_AREA) self.font_size = int((label_area / 100) * FONT_HEIGHT) self.set_items(self.languages, 0, self.change_language, False) self.current_language = self.languages[language] self.item_selected(self.current_language) def create_language_menu_button(self, s, constr, action, scale, font_size): """ Create Language Menu button :param s: button state :param constr: scaling constraints :param action: button event listener :param scale: True - scale images, False - don't scale images :return: language menu button """ s.padding = BUTTON_PADDING s.image_area_percent = ICON_AREA return self.factory.create_menu_button(s, constr, action, scale, font_size=font_size) def set_voice_commands(self, language): """ Set menu voice commands :param language: new language """ if not self.config[USAGE][USE_VOICE_ASSISTANT]: return va_commands = self.util.get_va_language_commands() for k, v in self.languages.items(): v.voice_commands = va_commands[k] def change_language(self, state): """ Change language event listener :param state: button state """ if not self.visible: return self.set_voice_commands(state.name) self.notify_listeners(state)
class HomeMenu(Menu): """ Home Menu class. Extends base Menu class """ def __init__(self, util, bgr=None, bounding_box=None, font_size=None): """ Initializer :param util: utility object :param bgr: menu background :param bounding_box: bounding box """ self.util = util self.factory = Factory(util) self.config = util.config self.cdutil = CdUtil(util) self.bb = bounding_box self.horizontal_layout = True self.rows = None self.cols = None items = self.get_menu_items() cell_bb = items[2] m = self.create_home_menu_button label_area = (cell_bb.h / 100) * (100 - ICON_AREA) font_size = int((label_area / 100) * FONT_HEIGHT) Menu.__init__(self, util, bgr, bounding_box, None, None, create_item_method=m, font_size=font_size) self.set_modes(*items) def get_menu_items(self): """ Prepare menu items :return: array containing menu items, disabled items, cell bounding box and icon box """ items = [] disabled_items = [] disabled_modes = self.util.get_disabled_modes() modes = [ RADIO, AUDIO_FILES, AUDIOBOOKS, STREAM, CD_PLAYER, PODCASTS, AIRPLAY, SPOTIFY_CONNECT, COLLECTION ] for mode in modes: self.add_mode(mode, items, disabled_items, disabled_modes) l = self.get_layout(items) bounding_box = l.get_next_constraints() box = self.factory.get_icon_bounding_box(bounding_box, ICON_LOCATION, ICON_AREA, ICON_SIZE, BUTTON_PADDING) return (items, disabled_items, bounding_box, box) def add_mode(self, mode, enabled, disabled, disabled_modes): """ Add mode :param mode: the mode to add :param enabled: list of enabled items :param disabled: list of disabled items :param disabled_modes: list of disabled modes """ if not self.config[HOME_MENU][mode]: return enabled.append(mode) if mode in disabled_modes: disabled.append(mode) def set_current_modes(self): """ Set current player modes """ items = self.get_menu_items() self.set_modes(*items) def set_modes(self, items, disabled_items, bounding_box, box): """ Set menu items :param items: menu items :param disabled_items: disabled menu items :param bounding_box: cell bounding box :param box: image boundng box """ self.modes = self.util.load_menu(items, NAME, disabled_items, V_ALIGN_TOP, bb=box) va_commands = self.util.get_voice_commands() if self.config[USAGE][USE_VOICE_ASSISTANT]: self.add_voice_command(RADIO, ["VA_RADIO", "VA_GO_RADIO"], va_commands) self.add_voice_command(AUDIO_FILES, ["VA_FILES", "VA_GO_FILES"], va_commands) self.add_voice_command( AUDIOBOOKS, ["VA_AUDIOBOOKS", "VA_BOOKS", "VA_GO_BOOKS"], va_commands) self.add_voice_command(STREAM, ["VA_STREAM", "VA_GO_STREAM"], va_commands) self.add_voice_command(CD_PLAYER, ["VA_CD_PLAYER"], va_commands) self.add_voice_command(PODCASTS, ["VA_PODCAST", "VA_PODCASTS"], va_commands) if not items: return if not self.config[CURRENT][MODE]: for i in items: if i not in disabled_items: mode = i break else: mode = self.config[CURRENT][MODE] self.set_items(self.modes, 0, self.change_mode, False) try: self.current_mode = self.modes[mode.lower()] self.item_selected(self.current_mode) except: pass def create_home_menu_button(self, s, constr, action, scale, font_size): """ Create Home Menu button :param s: button state :param constr: scaling constraints :param action: button event listener :param scale: True - scale images, False - don't scale images :param font_size: label font height in pixels :return: home menu button """ s.padding = BUTTON_PADDING s.image_area_percent = ICON_AREA return self.factory.create_menu_button(s, constr, action, scale, font_size=font_size) def add_voice_command(self, name, commands, va_commands): """ Add voice command :param name: item name :param commands: item commands :param va_commands: voice commands """ if not self.config[HOME_MENU][name]: return c = [] for m in commands: c.append(va_commands[m].strip()) self.modes[name].voice_commands = c def change_mode(self, state): """ Change mode event listener :param state: button state """ if not self.visible: return state.previous_mode = self.current_mode.name self.current_mode = state self.config[CURRENT][MODE] = state.name self.notify_listeners(state)
class RadioBrowserScreen(MenuScreen): """ Radio Browser Screen """ def __init__(self, util, listeners, voice_assistant): """ Initializer :param util: utility object :param listeners: screen event listeners :param voice_assistant: the voice assistant """ self.util = util self.config = util.config self.groups_list = self.util.get_stations_folders() self.factory = Factory(util) self.favorites_util = FavoritesUtil(self.util) rows = self.config[FILE_BROWSER_ROWS] columns = self.config[FILE_BROWSER_COLUMNS] d = [rows, columns] self.page_size = rows * columns MenuScreen.__init__(self, util, listeners, rows, columns, voice_assistant, d, self.turn_page, page_in_title=False) self.total_pages = 0 self.title = "" m = self.create_radio_browser_menu_button button_height = (self.menu_layout.h / rows) - (self.config[PADDING] * 2) bgr = self.config[BACKGROUND][MENU_BGR_COLOR] if self.config[ALIGN_BUTTON_CONTENT_X] == 'center': font_size = int(((100 - STATION_IMAGE_AREA) / 100) * self.config[FONT_HEIGHT_PERCENT]) else: font_size = int( (button_height / 100) * self.config[FONT_HEIGHT_PERCENT]) self.navigator = RadioNavigator(self.util, self.layout.BOTTOM, listeners) self.add_navigator(self.navigator) self.left_button = self.navigator.get_button_by_name(KEY_PAGE_DOWN) self.right_button = self.navigator.get_button_by_name(KEY_PAGE_UP) self.player_button = self.navigator.get_button_by_name(KEY_PLAYER) h = self.config[HORIZONTAL_LAYOUT] self.stations_menu = Menu(util, bgr, self.menu_layout, rows, columns, create_item_method=m, align=ALIGN_CENTER, horizontal_layout=h, font_size=font_size) self.set_menu(self.stations_menu) self.current_page = None self.current_language = self.config[CURRENT][LANGUAGE] self.current_genre = self.util.get_current_genre() self.turn_page() self.animated_title = True def create_radio_browser_menu_button(self, state, constr, action, scale, font_size): """ Factory function for menu button :param state: button state :param constr: bounding box :param action: action listener :param scale: True - sacle, False - don't scale :param font_size: the label font size :return: menu button """ s = copy(state) s.bounding_box = constr s.padding = self.config[PADDING] s.image_area_percent = STATION_IMAGE_AREA label_area_percent = 100 - s.image_area_percent if self.config[ALIGN_BUTTON_CONTENT_X] == 'left': s.image_location = LEFT s.label_location = LEFT s.h_align = H_ALIGN_LEFT elif self.config[ALIGN_BUTTON_CONTENT_X] == 'right': s.image_location = RIGHT s.label_location = RIGHT s.h_align = H_ALIGN_RIGHT elif self.config[ALIGN_BUTTON_CONTENT_X] == 'center': s.image_location = TOP s.label_location = BOTTOM s.h_align = H_ALIGN_CENTER s.v_align = CENTER s.wrap_labels = self.config[WRAP_LABELS] s.fixed_height = font_size s.scaled = True self.util.add_icon(s, self.get_scale_factor(s)) scale = True if hasattr(s, "show_label"): b = self.factory.create_menu_button( s, constr, action, scale, label_area_percent=label_area_percent, show_label=s.show_label, font_size=font_size) else: b = self.factory.create_menu_button( s, constr, action, scale, label_area_percent=label_area_percent, font_size=font_size) b.state.icon_selected_scaled = b.state.icon_base_scaled b.state.icon_selected = s.icon_base return b def get_scale_factor(self, s): """ Calculate scale factor :param s: button state object :return: scale width and height tuple """ bb = s.bounding_box if self.config[ALIGN_BUTTON_CONTENT_X] == 'center': location = TOP else: location = self.config[ALIGN_BUTTON_CONTENT_X] icon_box = self.factory.get_icon_bounding_box(bb, location, self.config[IMAGE_AREA], self.config[IMAGE_SIZE], self.config[PADDING]) icon_box_without_label = self.factory.get_icon_bounding_box( bb, location, 100, 100, self.config[PADDING], False) if self.config[HIDE_FOLDER_NAME]: s.show_label = False w = icon_box_without_label.w h = icon_box_without_label.h else: s.show_label = True w = icon_box.w h = icon_box.h return (w, h) def get_playlist(self, genre=None): """ Get playlist :param genre: the genre :return: the playlist """ if self.current_genre.name == KEY_FAVORITES: return self.favorites_util.get_favorites_playlist() else: return self.util.get_radio_browser_playlist(genre) def get_page(self): """ Get the current page from the playlist :return: the page """ language = self.config[CURRENT][LANGUAGE] genre = self.util.get_current_genre() playlist = self.get_playlist(genre.l_name) playlist_length = len(playlist) self.total_pages = math.ceil(playlist_length / self.page_size) if self.current_page == None or language != self.current_language or self.current_genre != genre: self.current_language = language self.current_genre = genre playlist = self.get_playlist(genre.l_name) playlist_length = len(playlist) self.total_pages = math.ceil(playlist_length / self.page_size) if self.total_pages == 0: self.left_button.change_label("0") self.right_button.change_label("0") self.set_title() return [] self.current_page = self.get_page_by_index() self.set_title() start = (self.current_page - 1) * self.page_size end = self.current_page * self.page_size return playlist[start:end] def get_page_by_index(self): """ Get the page by index :return: the page """ page = None index = self.util.get_current_radio_station_index() if index < self.page_size: page = 1 else: page = math.ceil(index / self.page_size) return page def set_title(self): """ Set the screen title """ genre = self.util.get_current_genre() if genre.name == KEY_FAVORITES: station = self.favorites_util.get_current_favorites_station() else: station = self.util.get_current_radio_station() if station: title = station.comparator_item else: title = "" d = {"current_title": title} self.screen_title.set_text(d) def turn_page(self): """ Turn page """ page = self.get_page() d = self.stations_menu.make_dict(page) self.stations_menu.set_items(d, 0, self.change_station, False) self.favorites_util.mark_favorites(self.stations_menu.buttons) index = self.util.get_current_radio_station_index() menu_selected = self.stations_menu.select_by_index(index) if self.navigator and self.total_pages > 1: self.left_button.change_label(str(self.current_page - 1)) self.right_button.change_label( str(self.total_pages - self.current_page)) else: self.left_button.change_label("0") self.right_button.change_label("0") for b in self.stations_menu.buttons.values(): b.parent_screen = self b.release_listeners.insert(0, self.handle_favorite) self.stations_menu.clean_draw_update() if menu_selected: self.navigator.unselect() self.link_borders() navigator_selected = self.navigator.is_selected() if (len(page) == 0 or (not menu_selected and not navigator_selected)) and self.navigator: self.navigator.unselect() self.player_button.set_selected(True) self.player_button.clean_draw_update() def change_station(self, state): """ Change station :param state: state object """ found = False for b in self.stations_menu.buttons.values(): if b.state == state: found = True break if not found: # after deleting favorite playlist = self.get_playlist(self.current_genre.l_name) index = self.util.get_current_radio_station_index() if playlist and len(playlist) > 0: state = playlist[index] else: state = None if state: state.source = KEY_RADIO_BROWSER state.name = self.util.get_current_genre().name self.util.set_radio_station_index(state.index) else: self.util.set_radio_station_index(None) self.go_player(state) self.set_title() def add_screen_observers(self, update_observer, redraw_observer): """ Add screen observers :param update_observer: observer for updating the screen :param redraw_observer: observer to redraw the whole screen """ self.navigator.add_observers(update_observer, redraw_observer) self.stations_menu.add_menu_observers(update_observer, redraw_observer, release=False) def set_current(self, state=None): """ Set current screen :param state: the source button state object """ self.turn_page() def handle_event(self, event): """ Handle screen event :param event: the event to handle """ self.handle_event_common(event) def handle_favorite(self, state): """ Add/Remove station to/from the favorites :param state: button state """ if state == None or not getattr(state, "long_press", False): return favorites, lang_dict = self.favorites_util.get_favorites_from_config() if self.favorites_util.is_favorite(favorites, state): self.favorites_util.remove_favorite(favorites, state) if self.current_genre.name == KEY_FAVORITES: current_index = state.index if len(favorites) == 0: self.util.set_radio_station_index(None) else: if current_index == 0: self.util.set_radio_station_index(0) else: self.util.set_radio_station_index(current_index - 1) self.turn_page() else: selected_button = self.stations_menu.get_selected_item() if selected_button and len(selected_button.components) == 4: del selected_button.components[3] selected_button.clean_draw_update() else: self.favorites_util.add_favorite(favorites, state) self.favorites_util.mark_favorites(self.stations_menu.buttons)
class CollectionMenu(Menu): """ Collection Menu class """ def __init__(self, util, bgr=None, bounding_box=None, font_size=None): """ Initializer :param util: utility object :param bgr: menu background :param bounding_box: bounding box :param font_size: labels font size """ self.util = util self.factory = Factory(util) self.config = util.config dbutil = util.get_db_util() self.stats = dbutil.get_collection_summary() suffix = [] items = [] item_list = [ GENRE, ARTIST, COMPOSER, ALBUM, TITLE, DATE, FOLDER, FILENAME, TYPE ] if self.config[USAGE][USE_VOICE_ASSISTANT]: command_list = [ "VA_GENRE", "VA_ARTIST", "VA_COMPOSER", "VA_ALBUM", "VA_TITLE", "VA_DATE", "VA_FOLDER", "VA_FILENAME", "VA_TYPE" ] va_commands = self.util.get_voice_commands() for n, i in enumerate(item_list): if self.stats and self.config[COLLECTION][SHOW_NUMBERS]: suffix.append(self.stats[i]) if i == FOLDER and self.config[COLLECTION_MENU][FOLDER]: items.append(KEY_AUDIO_FOLDER) elif i == FILENAME and self.config[COLLECTION_MENU][FILENAME]: items.append(KEY_FILE) elif self.config[COLLECTION_MENU][i]: items.append(i) if self.config[USAGE][USE_VOICE_ASSISTANT] and i in items: self.add_voice_command(i, command_list[n], va_commands) m = self.create_collection_main_menu_button label_area = ((bounding_box.h / 3) / 100) * (100 - ICON_AREA) font_size = int((label_area / 100) * FONT_HEIGHT) Menu.__init__(self, util, bgr, bounding_box, None, None, create_item_method=m, font_size=font_size) if not items: return l = self.get_layout(items) bounding_box = l.get_next_constraints() image_box = self.factory.get_icon_bounding_box(bounding_box, ICON_LOCATION, ICON_AREA, ICON_SIZE, BUTTON_PADDING) self.topics = self.util.load_menu(items, NAME, [], V_ALIGN_TOP, bb=image_box, suffix=suffix) self.set_items(self.topics, 0, self.change_topic, False) topic = self.config[COLLECTION_PLAYBACK][COLLECTION_TOPIC] if topic: for k in self.topics.keys(): if k == topic: self.current_topic = self.topics[k] break else: self.current_topic = self.topics[items[0]] self.item_selected(self.current_topic) def create_collection_main_menu_button(self, s, constr, action, scale, font_size): """ Create Collection Main Menu button :param s: button state :param constr: scaling constraints :param action: button event listener :param scale: True - scale images, False - don't scale images :return: home menu button """ s.padding = BUTTON_PADDING s.image_area_percent = ICON_AREA s.fixed_height = font_size s.v_align = CENTER return self.factory.create_menu_button(s, constr, action, scale, font_size=font_size) def add_voice_command(self, name, commands, va_commands): """ Add voice command :param name: item name :param commands: item commands :param va_commands: voice commands """ c = [] for m in commands: c.append(va_commands[m].strip()) self.topics[name].voice_commands = c def change_topic(self, state): """ Change topic event listener :param state: button state """ if not self.visible: return state.previous_mode = self.current_topic.name state.source = "menu" self.current_topic = state self.notify_listeners(state)