예제 #1
0
class RadioPlayerScreen(PlayerScreen):
    """ The Radio Player Screen """
    def __init__(self, util, listeners, voice_assistant=None):
        """ Initializer
        
        :param util: utility object
        :param listeners: screen event listeners
        :param voice_assistant: the voice assistant
        """
        self.util = util
        self.config = util.config
        self.bounding_box = util.screen_rect
        self.favorites_util = FavoritesUtil(self.util)
        self.image_util = util.image_util
        show_arrow_labels = True
        self.show_order = False
        self.show_info = True
        self.show_time_slider = False
        self.listeners = listeners
        self.change_logo_listeners = []
        self.favorites_util.set_favorites_in_config()

        PlayerScreen.__init__(self, util, listeners, "station_screen_title",
                              show_arrow_labels, self.show_order,
                              self.show_info, self.show_time_slider,
                              voice_assistant)

        self.set_custom_button()
        self.set_center_button()
        self.favorites_util.mark_favorites({"b": self.center_button})
        self.add_component(self.info_popup)
        self.set_listeners(listeners)
        self.shutdown_button.release_listeners.insert(
            0, self.favorites_util.save_favorites)
        # self.link_borders()

        if self.center_button == None:
            self.custom_button.set_selected(True)
            self.current_button = self.custom_button
            self.custom_button.clean_draw_update()

    def set_custom_button(self):
        """ Set the custom buttom """

        self.genres = self.util.get_genres()
        self.genres[
            KEY_FAVORITES] = self.favorites_util.get_favorites_button_state(
                self.custom_button_layout)
        self.current_genre = self.util.get_current_genre()
        self.current_genre.bounding_box = self.custom_button_layout
        self.custom_button = self.get_custom_button(self.current_genre,
                                                    self.listeners[KEY_GENRES])
        self.right_panel.add_component(self.custom_button)

    def stop(self):
        """ Stop playback """

        if self.center_button:
            self.center_button.components[1] = None
        self.set_title("")
        if hasattr(self, "stop_player"):
            self.stop_player()

    def set_center_button(self):
        """ Set the center button """

        if self.current_genre.name == KEY_FAVORITES:
            self.playlist = self.favorites_util.get_favorites_playlist()
        else:
            self.playlist = self.util.get_radio_player_playlist(
                self.current_genre.name)

        if self.playlist == None or len(self.playlist) == 0:
            self.clean_center_button()
            self.update_arrow_button_labels()
            self.set_title("")
            self.stop()
            return

        self.current_index = self.util.get_current_radio_station_index()

        if self.current_index >= len(self.playlist):
            self.current_index = len(self.playlist) - 1

        self.current_state = self.playlist[self.current_index]
        self.current_state.bounding_box = self.layout.CENTER

        if not hasattr(self.current_state, "icon_base"):
            self.util.add_icon(self.current_state)

        if self.center_button == None:
            self.center_button = self.get_center_button(self.current_state)
            self.current_button = self.center_button
            self.add_component(self.center_button)
        else:
            button = self.get_center_button(self.current_state)
            self.center_button.state = button.state
            self.center_button.components = button.components

        self.center_button.selected = True
        self.center_button.add_release_listener(self.handle_favorite)
        self.center_button.add_release_listener(
            self.listeners[KEY_RADIO_BROWSER])

        self.center_button.clean_draw_update()
        img = self.center_button.components[1]
        self.logo_button_content = (img.image_filename, img.content,
                                    img.content_x, img.content_y)

        self.update_arrow_button_labels()
        self.set_title(self.current_state)
        self.link_borders()

    def get_custom_button(self, genre_button_state, listener):
        """ Get the custom button

        :param genre_button_state: the genre button state
        :param listener: the button listener
        """
        self.util.add_icons(genre_button_state)
        bb = genre_button_state.bounding_box
        button = self.factory.get_genre_button(bb, genre_button_state,
                                               PERCENT_GENRE_IMAGE_AREA)
        button.add_release_listener(listener)
        return button

    def get_center_button(self, s):
        """ Create the center button

        :param s: button state

        :return: station logo button
        """
        bb = Rect(self.layout.CENTER.x + 1, self.layout.CENTER.y + 1,
                  self.layout.CENTER.w - 1, self.layout.CENTER.h - 1)
        if not hasattr(s, "icon_base"):
            self.util.add_icon(s)

        state = State()
        state.icon_base = s.icon_base
        self.factory.set_state_scaled_icons(s, bb)
        state.index = s.index
        state.genre = s.genre
        state.scaled = getattr(s, "scaled", False)
        state.icon_base_scaled = s.icon_base_scaled
        state.name = "station." + s.name
        state.l_name = s.l_name
        state.url = s.url
        state.keyboard_key = kbd_keys[KEY_SELECT]
        state.bounding_box = bb
        state.img_x = bb.x
        state.img_y = bb.y
        state.auto_update = False
        state.show_bgr = True
        state.show_img = True
        state.logo_image_path = s.image_path
        state.image_align_v = V_ALIGN_BOTTOM
        state.comparator_item = self.current_state.comparator_item
        button = Button(self.util, state)

        img = button.components[1]
        self.logo_button_content = (img.image_filename, img.content,
                                    img.content_x, img.content_y)

        return button

    def add_change_logo_listener(self, listener):
        """ Add change logo listener
        
        :param listener: event listener
        """
        if listener not in self.change_logo_listeners:
            self.change_logo_listeners.append(listener)

    def notify_change_logo_listeners(self, state):
        """ Notify change logo event listeners
        
        :param state: state object with new image in 'icon_base'
        """
        for listener in self.change_logo_listeners:
            listener(state)

    def change_genre(self, state=None):
        """ Change genre

        :para, state: the button state with new genre
        """
        self.genres = self.util.get_genres()
        self.genres[
            KEY_FAVORITES] = self.favorites_util.get_favorites_button_state(
                self.custom_button_layout)
        self.current_genre = self.genres[state.name]
        self.current_genre.bounding_box = self.custom_button_layout
        button = self.get_custom_button(self.current_genre,
                                        self.listeners[KEY_GENRES])
        self.custom_button.state = button.state
        self.custom_button.set_selected(True)
        self.set_center_button()

    def set_current(self, state=None):
        """ Set the current screen state

        :param state: the state object
        """
        if state == None:
            self.clean_center_button()
            self.update_arrow_button_labels()
            self.set_title("")
            self.stop_player()
            self.current_button = self.home_button
            self.home_button.clean_draw_update()
            return

        if not hasattr(state, "source"):
            return

        src = getattr(state, "source", None)

        if src == KEY_HOME:
            if not hasattr(self, "current_button"):  # after changing language
                self.home_button.set_selected(True)
                self.home_button.clean_draw_update()
                self.current_button = self.home_button
            if state.change_mode:
                self.start_playback()
        if src == GENRE:
            if state.comparator_item != self.current_genre.comparator_item:
                self.change_genre(state)
                if self.current_genre.name != KEY_FAVORITES:
                    self.favorites_util.mark_favorites(
                        {"b": self.center_button})
                self.play()
            self.center_button.set_selected(False)
        elif src == KEY_FAVORITES:
            current_language = self.config[CURRENT][LANGUAGE]
            key = STATIONS + "." + current_language
            self.config[key][CURRENT_STATIONS] = KEY_FAVORITES

            self.change_genre(state)
            self.center_button.set_selected(False)

            if self.favorites_util.get_current_favorites_station() != None:
                self.play()
        elif src == KEY_RADIO_BROWSER:
            if self.center_button and self.center_button.state.url != state.url:
                self.start_playback()

            favorites, lang_dict = self.favorites_util.get_favorites_from_config(
            )

            if self.center_button and len(self.center_button.components) == 4:
                if not self.favorites_util.is_favorite(
                        favorites, self.center_button.state
                ):  # remove star icon if not favorite anymore
                    del self.center_button.components[3]
            elif self.center_button and len(
                    self.center_button.components) == 3:
                if self.current_genre.name == KEY_FAVORITES:
                    if not self.favorites_util.is_favorite(
                            favorites, self.center_button.state):
                        self.start_playback()
                else:
                    if self.favorites_util.is_favorite(
                            favorites, self.center_button.state
                    ):  # add star icon if favorite
                        self.favorites_util.mark_favorites(
                            {"b": self.center_button})

    def start_playback(self):
        """ Start playback """

        self.set_center_button()
        self.set_title(self.current_state)
        self.play()

    def set_current_item(self, index):
        """ Specific for each player. Sets config item """

        self.util.set_radio_station_index(index)

    def clean_center_button(self):
        """ Clean the center button """

        if self.center_button == None or self.center_button.components[
                1] == None:
            return
        self.center_button.components[1].content = None
        self.center_button.components[1].image_filename = None
        self.center_button.state.icon_base = None
        self.center_button.state.icon_base_scaled = None
        self.center_button.state.comparator_item = None
        if len(self.center_button.components) == 4:
            del self.center_button.components[3]
        if self.visible:
            self.center_button.clean_draw_update()

    def show_logo(self):
        """ Show station logo image """

        self.center_button.components[
            1].image_filename = self.logo_button_content[0]
        self.center_button.components[1].content = self.logo_button_content[1]
        self.center_button.components[1].content_x = self.logo_button_content[
            2]
        self.center_button.components[1].content_y = self.logo_button_content[
            3]
        self.center_button.state.icon_base = (self.logo_button_content[0],
                                              self.logo_button_content[1])

        self.center_button.state.comparator_item = self.current_state.comparator_item

        if self.visible:
            self.center_button.clean_draw_update()

        self.notify_change_logo_listeners(self.center_button.state)
        self.redraw_observer()

    def show_album_art(self, status):
        """ Show album art from discogs.com
        
        :param status: object having artist & track names
        """
        self.current_album_image = None

        if self.config[CURRENT][MODE] != RADIO or status == None:
            return

        album = status['current_title']

        if len(album) < 10 or "jingle" in album.lower():
            self.show_logo()
            self.redraw_observer()
            return

        r = Rect(0, 0, self.config[SCREEN_INFO][WIDTH],
                 self.config[SCREEN_INFO][HEIGHT])
        full_screen_image = self.image_util.get_cd_album_art(album, r)

        bb = self.center_button.bounding_box
        scale_ratio = self.image_util.get_scale_ratio((bb.w, bb.h),
                                                      full_screen_image[1])
        album_art = (full_screen_image[0],
                     self.image_util.scale_image(full_screen_image,
                                                 scale_ratio))

        if album_art and album_art[0] != None and album_art[0].endswith(
                DEFAULT_CD_IMAGE) or album_art[1] == None:
            self.show_logo()
            self.redraw_observer()
            return

        size = album_art[1].get_size()

        if self.center_button.components[1] == None:
            button = self.get_center_button(self.current_state)
            self.center_button.state = button.state
            self.center_button.components = button.components

        name = GENERATED_IMAGE + "album.art"
        self.center_button.components[1].image_filename = name
        self.center_button.components[1].content = album_art[1]
        self.center_button.components[1].content_x = int(bb.x +
                                                         (bb.w - size[0]) / 2)
        self.center_button.components[1].content_y = int(bb.y +
                                                         (bb.h - size[1]) / 2)
        album_art = (name, album_art[1])
        self.center_button.state.icon_base = self.center_button.state.icon_base_scaled = album_art
        self.center_button.state.comparator_item = self.current_state.comparator_item

        if full_screen_image:
            self.center_button.state.full_screen_image = full_screen_image[1]

        self.center_button.state.album = album
        if self.visible:
            self.center_button.clean_draw_update()

        self.notify_change_logo_listeners(self.center_button.state)
        self.redraw_observer()

    def handle_info_popup_selection(self, state):
        """ Handle info menu selection

        :param state: button state
        """
        if state.name == LYRICS:
            a = None
            try:
                a = self.screen_title.text
            except:
                pass
            if a != None:
                s = State()
                s.album = a
                self.start_screensaver(state.name, s)
            else:
                self.start_screensaver(state.name)
        else:
            self.start_screensaver(state.name)

    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:
                if len(self.playlist) > 0:
                    if state.index == 0:
                        self.current_index = 0
                    else:
                        self.current_index = state.index - 1
                    self.util.set_radio_station_index(self.current_index)
                    self.set_center_button()
                    self.play()
                else:
                    self.util.set_radio_station_index(None)
                    self.stop()
        else:
            if isinstance(state.icon_base, tuple):
                state.image_path = state.icon_base[0]
            self.favorites_util.add_favorite(favorites, state)
            if self.center_button and len(self.center_button.components) == 3:
                self.favorites_util.mark_favorites({"b": self.center_button})
예제 #2
0
class StationMenu(Menu):
    """ Station Menu class. Extends base Menu class """

    PAGE_MODE = 0
    STATION_MODE = 1
    STATION = "station"
    LOGO_SCALE_FACTOR = 200 / 228

    def __init__(self,
                 playlist,
                 util,
                 mode=STATION,
                 bgr=None,
                 bounding_box=None):
        """ Initializer
        
        :param playlist: playlist object
        :param util: utility object
        :param bgr: menu background
        :param bounding_box: bounding box
        """
        self.factory = Factory(util)
        self.util = util
        self.config = self.util.config
        self.image_util = util.image_util
        self.favorites_util = FavoritesUtil(self.util)
        m = self.create_station_menu_button
        bb = bounding_box
        self.menu_mode = mode
        Menu.__init__(self,
                      util,
                      bgr,
                      bb,
                      playlist.rows,
                      playlist.columns,
                      create_item_method=m)
        self.bounding_box = bb
        self.playlist = playlist
        self.current_mode = self.STATION_MODE

        path = os.path.join(FOLDER_ICONS, IMAGE_SHADOW + EXT_PNG)
        self.original_shadow = self.image_util.load_image(path,
                                                          bounding_box=(bb.w,
                                                                        bb.h))
        h = self.bounding_box.h
        self.shadow = (self.original_shadow[0],
                       self.image_util.scale_image(self.original_shadow[1],
                                                   (h, h)))
        self.shadow_component = None

        path = os.path.join(FOLDER_ICONS, IMAGE_SELECTION + EXT_PNG)
        self.selection = self.image_util.load_image(path)
        self.station_button = None
        self.menu_click_listeners = []
        self.mode_listeners = []
        self.change_logo_listeners = []
        self.page_turned = False
        self.genre = None
        self.current_logo_image = None
        self.current_logo_filename = None
        self.current_album_image = None

    def create_station_menu_button(self, s, constr, action, scale):
        """ Create Station 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: station menu button
        """
        if scale:
            self.factory.set_state_scaled_icons(s, constr)
        s.scaled = scale
        button = self.create_station_button(s, constr, action)
        button.bgr = (0, 0, 0)
        return button

    def create_station_button(self, s, bb, action=None):
        """ Create station button

        :param s: button state
        :param bb: bounding box
        :param action: event listener

        :return: station logo button
        """
        state = State()
        state.icon_base = s.icon_base
        state.index_in_page = s.index_in_page
        state.index = s.index
        state.genre = s.genre
        state.scaled = getattr(s, "scaled", False)
        state.icon_base_scaled = s.icon_base_scaled
        state.name = "station_menu." + s.name
        state.l_name = s.l_name
        state.url = s.url
        state.keyboard_key = kbd_keys[KEY_SELECT]
        state.bounding_box = bb
        state.img_x = bb.x
        state.img_y = bb.y
        state.auto_update = False
        state.show_bgr = True
        state.show_img = True
        state.image_align_v = V_ALIGN_BOTTOM
        button = Button(self.util, state)
        button.add_release_listener(action)
        return button

    def set_playlist(self, playlist):
        """ Set playlist
        
        :param playlist: the playlist to set
        """
        self.playlist = playlist

    def init_station(self, index):
        """ Initialize the station specified by its index
        
        :param index: station index
        """
        self.current_album_image = None
        self.playlist.set_current_item(index)
        index = self.playlist.current_item_index
        index_on_page = self.playlist.current_item_index_in_page
        page = self.playlist.get_current_page()
        self.set_page(index, index_on_page, page)

    def set_page(self, index, index_on_page, page):
        """ Set new page of stations
        
        :param index: current station index in playlist
        :param index_on_page: station index on page
        :param page: list of stations
        """
        self.set_items(self.make_dict(page), index_on_page, self.switch_mode)
        if not self.favorites_util.is_favorite_mode():
            self.favorites_util.mark_favorites(self.buttons)

        for b in self.buttons.values():
            b.add_release_listener(self.handle_favorite)

        self.shadow_component = self.get_shadow()
        self.add_component(self.shadow_component)

        self.station_button = self.get_logo_button(index)
        if self.current_album_image == None:
            self.large_station_button = self.get_logo_button(index)

        self.add_component(self.large_station_button)
        if not self.is_button_defined():
            return
        self.add_component(self.get_selection_frame(self.button))

    def is_button_defined(self):
        """ Check if ''button' object was defined
        
        :return: true - button object defined, false - not defined
        """
        return getattr(self, "button", None) != None

    def get_shadow(self):
        """ Return the button shadow component
        
        :return: shadow component
        """
        c = Component(self.util, self.shadow[1])
        c.name = "station_menu.shadow"
        c.image_filename = self.shadow[0]
        c.content_x = self.bounding_box.x
        c.content_y = self.bounding_box.y

        return c

    def get_logo_button(self, index):
        """ Return the button of the station specified by its index
        
        :param index: button index in the playlist
        
        :return: current station button
        """

        try:
            self.button = self.buttons[str(index)]
        except:
            pass

        if not self.is_button_defined():
            return

        b = self.create_station_button(self.button.state, self.bounding_box,
                                       self.switch_mode)
        b.components[1].content = self.button.state.icon_base
        img = b.components[1].content
        if isinstance(img, tuple):
            self.current_logo_filename = img[0]
            img = img[1]
        bb = self.bounding_box

        logo_height = int(bb.h * self.LOGO_SCALE_FACTOR)
        self.current_logo_image = self.image_util.scale_image(
            img, (logo_height, logo_height))
        b.components[1].content = self.current_logo_image
        b.components[
            1].content_x = bb.x + bb.w / 2 - self.current_logo_image.get_size(
            )[0] / 2
        b.components[
            1].content_y = bb.y + bb.h / 2 - self.current_logo_image.get_size(
            )[1] / 2

        b.add_release_listener(self.handle_favorite)
        self.favorites_util.mark_favorites({"b": b})

        return b

    def handle_favorite(self, state):
        """ Add/Remove station to/from the favorites
        
        :param state: button state
        """
        if self.config[CURRENT][MODE] != RADIO or 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,
                                                self.playlist.rows,
                                                self.playlist.columns)
            size = self.playlist.rows * self.playlist.columns
            length = len(favorites)
            if self.favorites_util.is_favorite_mode():
                del self.buttons[str(state.index)]
                if len(self.buttons) == 0:
                    self.components = []
                    if length > 0:
                        self.switch_to_previous_station(state)
                else:
                    for i, comp in enumerate(self.components):
                        if type(
                                comp
                        ) is Button and comp.state.genre == state.genre and comp.state.l_name == state.l_name:
                            del self.components[state.index_in_page]
                            break
                    if state.index_in_page == 0 and len(favorites) <= size:
                        self.set_station(0)
                    else:
                        self.switch_to_previous_station(state)
                self.playlist.items = favorites
                self.playlist.length = length
                self.playlist.total_pages = int(length / size)
                if len(favorites) > 0:
                    state = favorites[self.playlist.current_item_index]
                else:
                    state.l_name = " "
                self.notify_listeners(state)
            if len(self.station_button.components) == 4:
                del self.station_button.components[3]
            if self.large_station_button and len(
                    self.large_station_button.components) == 4:
                del self.large_station_button.components[3]
        else:
            items_per_page = self.playlist.rows * self.playlist.columns
            self.favorites_util.add_favorite(favorites, state, items_per_page)
            self.favorites_util.mark_favorites({"b": self.station_button})
            self.favorites_util.mark_favorites(
                {"b": self.large_station_button})

        self.favorites_util.mark_favorites(self.buttons)
        self.clean_draw_update()

    def get_selection_frame(self, button):
        """ Create the selection frame used in Page mode
        
        :param button: button for which the selection frame should be created
        
        :return: selection frame component
        """
        x = button.components[0].content.x
        y = button.components[0].content.y
        w = button.components[0].content.w
        h = button.components[0].content.h
        i = self.image_util.scale_image(self.selection[1], (w, h))
        c = Component(self.util, i)
        c.content_x = x
        c.content_y = y
        c.name = "station_menu.selection"
        c.image_filename = self.selection[0]
        c.visible = False
        c.selection_index = button.state.index_in_page
        return c

    def set_station(self, index, save=True, notify=True):
        """ Set new station specified by its index
        
        :param index: the index of new station
        :param save: flag defining if index should be saved in configuration object, True - save, False - don't save
        """
        try:
            self.config[PLAYER_SETTINGS][PAUSE] = False
            self.init_station(index)
            self.draw()

            if self.config[VOLUME_CONTROL][
                    VOLUME_CONTROL_TYPE] == VOLUME_CONTROL_TYPE_PLAYER:
                self.button.state.volume = self.config[PLAYER_SETTINGS][VOLUME]
            else:
                self.button.state.volume = None

            self.button.state.mute = self.config[PLAYER_SETTINGS][MUTE]
            self.button.state.pause = self.config[PLAYER_SETTINGS][PAUSE]
            if notify:
                self.notify_listeners(self.button.state)
            if save:
                self.save_station_index(self.button.state.index)
        except KeyError:
            pass

    def save_station_index(self, index):
        """ Save station/stream index in configuration object
        
        :param index: the index
        """
        lang = self.config[CURRENT][LANGUAGE]
        mode = self.config[CURRENT][MODE]

        if mode == RADIO:
            k = STATIONS + "." + lang
            try:
                self.config[k]
            except:
                self.config[k] = {}
                self.config[k][CURRENT_STATIONS] = self.genre

            self.config[k][self.genre] = index
        elif mode == STREAM:
            try:
                self.config[CURRENT][STREAM] = index
            except:
                pass

    def get_current_station_name(self):
        """ Return the current station name
        
        :return: localized name of the current station
        """
        index = self.playlist.current_item_index
        button = self.buttons[str(index)]
        return button.state.l_name

    def get_current_station_index(self):
        """ Return the index of the current station
        
        :return: the index
        """
        return self.playlist.current_item.index

    def switch_to_next_station(self, state):
        """ Switch to the next station
        
        :param state: button state
        """
        if len(self.playlist.get_current_page()) == (
                self.playlist.current_item_index_in_page + 1):
            self.switch_to_next_page(state)
            if self.playlist.current_item_index == self.playlist.length - 1:
                self.playlist.current_item_index = 0
            else:
                self.playlist.current_item_index += 1
        else:
            self.playlist.current_item_index += 1
        self.set_station(self.playlist.current_item_index)

    def switch_to_previous_station(self, state):
        """ Switch to the previous station
        
        :param state: button state
        """
        if self.playlist.current_item_index == 0:
            self.switch_to_previous_page(state)
            l = len(self.components)
            self.playlist.current_item_index = self.get_button_by_index_in_page(
                l - 4).state.index
        else:
            self.playlist.current_item_index -= 1
        self.set_station(self.playlist.current_item_index)

    def switch_to_next_page(self, state):
        """ Switch to the next page
        
        :param state: button state
        """
        next_page = self.playlist.next_page()
        self.set_page(self.playlist.current_item_index,
                      self.playlist.current_page_index, next_page)
        if state != None:
            l = len(self.components)
            next_selected_button = self.get_button_by_index_in_page(0)
            self.components[l -
                            1] = self.get_selection_frame(next_selected_button)
        self.draw()
        self.page_turned = True

    def switch_to_previous_page(self, state):
        """ Switch to the previous page
        
        :param state: button state
        """
        next_page = self.playlist.previous_page()
        self.set_page(self.playlist.current_item_index,
                      self.playlist.current_page_index, next_page)
        if state != None:
            l = len(self.components)
            next_selected_button = self.get_button_by_index_in_page(0)
            self.components[l -
                            1] = self.get_selection_frame(next_selected_button)
        self.draw()
        self.page_turned = True

    def switch_mode(self, state):
        """ Switch menu mode. There are two modes - Station and Page
        
        :param state: button state
        """
        if self.current_mode == self.STATION_MODE:
            self.set_page_mode()
        else:
            self.set_station_mode(state)

    def set_page_mode(self):
        """ Set Page mode """

        self.current_mode = self.PAGE_MODE
        self.draw()
        self.notify_mode_listeners(self.current_mode)

    def set_station_mode(self, state):
        """ Set Station mode
        
        :param state: button state
        """
        self.current_mode = self.STATION_MODE

        if self.page_turned:
            l = len(self.components)
            self.components[l - 1] = self.get_selection_frame(self.button)
            self.page_turned = False

        if state and state.index != self.playlist.current_item_index:
            self.set_station(state.index)
        else:
            self.draw()
        self.notify_mode_listeners(self.current_mode)

    def get_button_by_index_in_page(self, index):
        """ Return the button by its index on page
        
        :param index: button index
        :return: the button
        """
        for button in self.buttons.values():
            if button.state.index_in_page == index:
                return button
        return None

    def handle_event(self, event):
        """ Station menu event handler
        
        :param event: event to handle
        """
        if not self.visible: return

        if self.current_mode == self.STATION_MODE:
            self.station_button.handle_event(event)
        else:
            if event.type == USER_EVENT_TYPE and event.sub_type == SUB_TYPE_KEYBOARD and event.action == pygame.KEYUP:
                l = len(self.components)
                selection = self.components[l - 1]
                key_event = False

                col = int(selection.selection_index % self.cols)
                row = int(selection.selection_index / self.cols)

                if event.keyboard_key == kbd_keys[KEY_LEFT]:
                    if col == 0 and row == 0:
                        self.switch_to_previous_page(None)
                        l = len(self.components)
                        selection.selection_index = l - 4
                    else:
                        selection.selection_index = selection.selection_index - 1
                    key_event = True
                elif event.keyboard_key == kbd_keys[KEY_RIGHT]:
                    if col == self.cols - 1 and row == self.rows - 1:
                        self.switch_to_next_page(None)
                        selection.selection_index = 0
                        l = len(self.components)
                    else:
                        m = selection.selection_index + 1
                        if self.get_button_by_index_in_page(m):
                            selection.selection_index = m
                        else:
                            self.switch_to_next_page(None)
                            selection.selection_index = 0
                            l = len(self.components)
                    key_event = True
                elif event.keyboard_key == kbd_keys[KEY_UP]:
                    if row == 0:
                        for n in range(self.rows):
                            m = selection.selection_index + (self.rows - 1 -
                                                             n) * self.cols
                            if self.get_button_by_index_in_page(m):
                                selection.selection_index = m
                    else:
                        selection.selection_index = selection.selection_index - self.cols
                    key_event = True
                elif event.keyboard_key == kbd_keys[KEY_DOWN]:
                    if row == self.rows - 1:
                        selection.selection_index = int(
                            selection.selection_index % self.cols)
                    else:
                        m = selection.selection_index + self.cols
                        if self.get_button_by_index_in_page(m):
                            selection.selection_index = m
                        else:
                            selection.selection_index = int(
                                selection.selection_index % self.cols)
                    key_event = True
                elif event.keyboard_key == kbd_keys[KEY_BACK]:
                    self.init_station(self.station_button.state.index)
                    self.switch_mode(self.station_button.state)
                    self.draw()
                    key_event = False

                if key_event:
                    next_selected_button = self.get_button_by_index_in_page(
                        selection.selection_index)
                    self.components[l - 1] = self.get_selection_frame(
                        next_selected_button)
                    self.draw()

                if event.keyboard_key == kbd_keys[KEY_SELECT]:
                    selected_button = self.get_button_by_index_in_page(
                        selection.selection_index)
                    self.item_selected(selected_button.state)
                    self.switch_mode(selected_button.state)

                self.notify_menu_click_listeners(event)
            else:
                Menu.handle_event(self, event)

        if self.visible and event.type == pygame.MOUSEBUTTONUP and self.bounding_box.collidepoint(
                event.pos):
            self.notify_menu_click_listeners(event)

    def draw(self):
        """ Draw Station Menu """

        self.clean()
        l = len(self.components)

        if l > 2 and self.current_mode == self.STATION_MODE:
            self.components[l - 3].set_visible(True)
            self.components[l - 2].set_visible(True)
            self.components[l - 2].components[0].set_visible(False)
            self.components[l - 1].set_visible(False)
        elif l > 2:
            self.components[l - 3].set_visible(False)
            self.components[l - 2].set_visible(False)
            self.components[l - 1].set_visible(True)
        super(StationMenu, self).draw()
        self.update()

    def add_menu_click_listener(self, listener):
        """ Add menu button click listener
        
        :param listener: event listener
        """
        if listener not in self.menu_click_listeners:
            self.menu_click_listeners.append(listener)

    def notify_menu_click_listeners(self, event):
        """ Notify all menu button click event listeners
        
        :param event: event to handle
        """
        for listener in self.menu_click_listeners:
            listener(event)

    def add_mode_listener(self, listener):
        """ Add change mode listener
        
        :param listener: event listener
        """
        if listener not in self.mode_listeners:
            self.mode_listeners.append(listener)

    def notify_mode_listeners(self, mode):
        """ Notify all menu change mode event listeners
        
        :param mode: the mode
        """
        for listener in self.mode_listeners:
            listener(mode)

    def add_change_logo_listener(self, listener):
        """ Add change logo listener
        
        :param listener: event listener
        """
        if listener not in self.change_logo_listeners:
            self.change_logo_listeners.append(listener)

    def notify_change_logo_listeners(self, state):
        """ Notify change logo event listeners
        
        :param state: state object with new image in 'icon_base'
        """
        for listener in self.change_logo_listeners:
            listener(state)

    def show_logo(self):
        """ Show station logo image """

        b = self.large_station_button
        bb = self.bounding_box
        logo_height = int(bb.h * self.LOGO_SCALE_FACTOR)
        b.components[1].image_filename = self.current_logo_filename
        b.components[1].content = self.current_logo_image
        b.components[
            1].content_x = bb.x + bb.w / 2 - self.current_logo_image.get_size(
            )[0] / 2
        b.components[
            1].content_y = bb.y + bb.h / 2 - self.current_logo_image.get_size(
            )[1] / 2
        if self.visible:
            self.draw()
        self.notify_change_logo_listeners(b.state)

    def show_album_art(self, status):
        """ Show album art from discogs.com
        
        :param status: object having artist & track names
        """
        self.current_album_image = None

        if self.config[CURRENT][
                MODE] != RADIO or status == None or self.current_mode == self.PAGE_MODE:
            return

        album = status['current_title']

        if len(album) < 10 or "jingle" in album.lower():
            self.show_logo()
            return

        bb_w = self.bounding_box.w * self.LOGO_SCALE_FACTOR
        bb_h = bb_w
        bb_x = self.bounding_box.x + (self.bounding_box.w - bb_w) / 2
        bb_y = self.bounding_box.y + (self.bounding_box.h - bb_h) / 2
        bb = pygame.Rect(bb_x, bb_y, bb_w, bb_w)

        r = pygame.Rect(0, 0, self.config[SCREEN_INFO][WIDTH],
                        self.config[SCREEN_INFO][HEIGHT])
        full_screen_image = self.image_util.get_cd_album_art(album, r)

        scale_ratio = self.image_util.get_scale_ratio((bb.w, bb.h),
                                                      full_screen_image[1])
        album_art = (full_screen_image[0],
                     self.image_util.scale_image(full_screen_image,
                                                 scale_ratio))

        if album_art and album_art[0] != None and album_art[0].endswith(
                DEFAULT_CD_IMAGE) or album_art[1] == None:
            self.show_logo()
            return

        if album_art and album_art[0] != None and album_art[0].endswith(
                DEFAULT_CD_IMAGE) or album_art[1] == None:
            self.show_logo()
            return

        size = album_art[1].get_size()
        self.current_album_image = album_art[1]
        b = self.large_station_button
        img = b.components[1]
        img.content = album_art[1]
        img.content_x = int(bb_x + (bb_w - size[0]) / 2)
        img.content_y = int(bb_y + (bb_h - size[1]) / 2)

        url = self.util.encode_url(album_art[0])

        img.image_filename = url
        b.state.icon_base = album_art
        if full_screen_image:
            b.state.full_screen_image = full_screen_image[1]

        k = 17 / 15
        w = int(size[0] * k)
        h = int(size[1] * k)
        shadow = self.image_util.scale_image(self.original_shadow[1], (w, h))
        self.shadow_component.content = shadow
        size = shadow.get_size()
        x = int(self.bounding_box.x + (self.bounding_box.w - w) / 2)
        y = int(self.bounding_box.y + (self.bounding_box.h - h) / 2)
        w = size[0]
        h = size[1]
        self.shadow_component.content_x = x
        self.shadow_component.content_y = y
        self.shadow_component.bounding_box = pygame.Rect(0, 0, w, h)

        if self.visible:
            self.draw()

        b.state.album = album
        self.notify_change_logo_listeners(b.state)
예제 #3
0
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)