예제 #1
0
class TopicScreen(MenuScreen):
    """ Collection Topic Screen """

    def __init__(self, util, listeners, voice_assistant):
        """ Initializer

        :param util: utility object
        :param listeners: listeners
        :param voice_assistant: voice assistant
        """
        self.util = util
        self.config = util.config
        self.listeners = listeners
        self.listeners[KEY_LIST] = self.set_list
        self.factory = Factory(util)
        dbutil = util.get_db_util()
        self.selector = Selector(dbutil)

        self.bounding_box = util.screen_rect
        layout = BorderLayout(self.bounding_box)
        layout.set_percent_constraints(PERCENT_TOP_HEIGHT, PERCENT_BOTTOM_HEIGHT, 0, 0)

        MenuScreen.__init__(self, util, listeners, ROWS, COLUMNS, voice_assistant, [ROWS, COLUMNS],
                            self.turn_page, page_in_title=False, show_loading=False)        

        m = self.factory.create_collection_menu_button
        font_size = int(((self.menu_layout.h / ROWS) / 100) * FONT_HEIGHT)

        h = self.config[HORIZONTAL_LAYOUT]
        bgr = self.config[BACKGROUND][MENU_BGR_COLOR]
        self.topic_menu = Menu(util, bgr, self.menu_layout, ROWS, COLUMNS, create_item_method=m, align=ALIGN_LEFT, horizontal_layout=h, font_size=font_size)
        self.set_menu(self.topic_menu)

        self.navigator = TopicNavigator(self.util, self.layout.BOTTOM, listeners)
        self.add_navigator(self.navigator)

        self.current_topic = None
        self.current_item = None
        self.current_page_items = None
        self.first_item = None
        self.last_item = None
        self.collection_topic = None
        self.previous_page = 1
        self.search_string = None
        self.source = None
        self.mode = KEY_LIST
        self.animated_title = True

    def set_current(self, state):
        """ Set current state

        :param state: button state
        """
        self.source = getattr(state, KEY_SOURCE, None)
        if self.source:
            if self.source == KEY_ABC:
                self.mode = KEY_ABC
            elif self.source == KEY_SEARCH:
                self.mode = KEY_SEARCH
            elif self.source == KEY_LIST:
                self.mode = KEY_LIST

        if self.current_topic and (self.source == KEY_NAVIGATOR or self.source == KEY_BACK or self.source == None):
            return

        if self.source == KEY_MENU:
            self.config[COLLECTION_PLAYBACK][COLLECTION_TOPIC] = state.name
            self.mode = KEY_LIST

        if hasattr(state, "genre"):
            if self.current_topic == state.genre:
                return
            else:
                self.current_topic = state.genre
                self.current_item = None

        name = self.config[COLLECTION_PLAYBACK][COLLECTION_TOPIC]
        if self.source:
            if self.source == KEY_ABC:
                name = getattr(state, KEY_NAME, None)
            elif self.source == KEY_SEARCH:
                name = getattr(state, KEY_CALLBACK_VAR, None)

        if not self.source or not name:
            return

        if self.source != KEY_ABC and self.source != KEY_SEARCH:
            self.collection_topic = name
            self.search_string == None
        else:            
            self.search_string = name

        self.navigator.set_buttons(self.collection_topic)
        self.navigator.left_button.change_label("0")
        self.navigator.right_button.change_label("0")
        self.navigator.set_parent_screen(self)
        self.current_page_items = None
        self.first_item = ""
        self.last_item = ""
        self.current_page = 1
        self.previous_page = 1

        if not self.current_topic:
            return

        self.title = self.get_title(name)
        self.set_title(1) 
        self.set_loading(self.title)
        self.total_pages = self.get_total_pages(name)        
        self.turn_page()
        self.reset_loading()

    def set_list(self, state=None):
        """ Set list view """

        s = State()
        s.source = KEY_LIST
        s.name = self.collection_topic
        self.set_current(s)

    def get_title(self, search_string):
        """ Return title based on call source. The source can be:
        - Collection screen
        - ABC keyboard
        - Keyboard Search screen

        :param search_string: search string from keyboard

        :return: title which depends on call source
        """
        title = None
        try:
            title = self.config[LABELS][self.collection_topic]
        except:
            pass

        if self.source == KEY_ABC:
            title = f"{title}. {search_string.strip()}"
        elif self.source == KEY_SEARCH:
            title = f"{title}. *{search_string.strip()}*"

        return title

    def get_total_pages(self, search_string):
        """ Return the number of total pages for defined search criteria

        :param search_string: search string from keyboard

        :return: total pages number
        """
        mode = self.collection_topic
        if mode == KEY_AUDIO_FOLDER:
            mode = FOLDER
        elif mode == KEY_FILE:
            mode = FILENAME

        total_pages = 0

        if self.source == KEY_ABC:
            total_pages = self.selector.get_page_count_by_char(mode, search_string.strip(), PAGE_SIZE)
        elif self.source == KEY_SEARCH:
            total_pages = self.selector.get_page_count_by_pattern(mode, search_string.strip(), PAGE_SIZE)
        else:
            total_pages = self.selector.get_page_count(mode, PAGE_SIZE)
            
        return total_pages

    def turn_page(self):
        """ Turn page """

        if self.total_pages == 0:
            self.topic_menu.set_items({}, 0, self.select_item, False)
            self.link_borders()
            return

        p = self.prepare_page()
        self.topic_menu.set_items(p, 0, self.select_item, False)
        keys = list(p.keys())

        if len(keys) != 0 and 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))

        self.topic_menu.clean_draw_update()

        if hasattr(self, "update_observer"):
            self.topic_menu.add_menu_observers(self.update_observer, self.redraw_observer)

        for b in self.topic_menu.buttons.values():
            b.parent_screen = self

        self.topic_menu.unselect()
        self.link_borders()

        if self.navigator.is_selected():
            return

        for b in self.topic_menu.buttons.values():
            b.parent_screen = self
            if self.current_item == b.state.name:
                self.topic_menu.select_by_index(b.state.index)
                return
        self.navigator.menu_button.set_selected(True)
        self.navigator.menu_button.clean_draw_update()

    def prepare_page(self):
        """ Prepare topic page

        :return: page dictionary
        """
        page, self.first_item, self.last_item = self.get_current_page()
        p = {}
        for i, n in enumerate(page):
            s = State()
            s.index = i
            if "\x00" in n:
                n = n.replace("\x00", "")
            s.name = n
            s.l_name = n
            p[str(i)] = s
        return p

    def get_current_page(self):
        """ Get current page content 
        
        :return: page content
        """
        topic = self.collection_topic
        if topic == KEY_AUDIO_FOLDER:
            topic = FOLDER
        elif topic == KEY_FILE:
            topic = FILENAME

        page_items = self.selector.get_topic_page(self.mode, topic, self.search_string, 
            self.current_page, self.previous_page, self.first_item, self.last_item, PAGE_SIZE)

        self.previous_page = self.current_page
    
        if not page_items:
            page_items = []
            first_item = None
            last_item = None
        else:
            first_item = page_items[0]
            last_item = page_items[len(page_items) - 1]

        return (page_items, first_item, last_item)

    def select_item(self, s=None):
        """ Select item from menu

        :param s: button state
        """
        if not s: return

        self.current_item = s.name
        s.collection_topic = self.collection_topic
        self.topic_menu.selected_index = s.index

        if self.collection_topic == KEY_AUDIO_FOLDER:
            s.folder = os.path.join(self.config[COLLECTION][BASE_FOLDER], s.name[1:])
            s.source = KEY_MENU
            files = self.util.get_audio_files_in_folder(s.folder, False)
            if files:
                f = files[0]
                s.file_name = f.file_name
                s.url = os.path.join(s.folder, s.file_name)
            else:
                s.file_name = None
                s.url = None
        
        self.listeners[TOPIC_DETAIL](s)

    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
        """
        MenuScreen.add_screen_observers(self, update_observer, redraw_observer)
        self.update_observer = update_observer
        self.redraw_observer = redraw_observer
        self.add_loading_listener(redraw_observer)
        self.topic_menu.add_menu_observers(update_observer, redraw_observer)
        self.navigator.add_observers(update_observer, redraw_observer)
예제 #2
0
class PodcastsScreen(MenuScreen):
    """ Podcasts Screen """
    
    def __init__(self, util, listeners, voice_assistant):
        """ Initializer
        
        :param util: utility object
        :param listeners: listeners
        :param voice_assistant: voice assistant
        """
        self.util = util
        self.config = util.config
        self.listeners = listeners
        self.factory = Factory(util)
        
        self.podcasts_util = util.get_podcasts_util()        
        self.bounding_box = util.screen_rect
        layout = BorderLayout(self.bounding_box)
        layout.set_percent_constraints(PERCENT_TOP_HEIGHT, PERCENT_BOTTOM_HEIGHT, 0, 0)
        
        d = [MENU_ROWS_PODCASTS, MENU_COLUMNS_PODCASTS]
        MenuScreen.__init__(self, util, listeners, MENU_ROWS_PODCASTS, MENU_COLUMNS_PODCASTS, voice_assistant, d, self.turn_page, 
            page_in_title=False, show_loading=True)        
        self.title = self.config[LABELS][PODCASTS]
        self.current_item = self.config[PODCASTS][PODCAST_URL]
        
        self.navigator = PodcastNavigator(self.util, self.layout.BOTTOM, listeners, PAGE_SIZE_PODCASTS + 1)
        self.add_navigator(self.navigator)

        m = self.create_podcast_menu_button
        font_size = int(((self.menu_layout.h / MENU_ROWS_PODCASTS) / 100) * FONT_HEIGHT)
        h = self.config[HORIZONTAL_LAYOUT]
        bgr = self.config[BACKGROUND][MENU_BGR_COLOR]
        self.podcasts_menu = Menu(util, bgr, self.menu_layout, MENU_ROWS_PODCASTS, MENU_COLUMNS_PODCASTS, create_item_method=m, align=ALIGN_CENTER, horizontal_layout=h, font_size=font_size)
        self.set_menu(self.podcasts_menu)
        
        url = self.config[PODCASTS][PODCAST_URL]
        if url and len(url) > 0:
            self.current_page = self.podcasts_util.get_podcast_page(url, PAGE_SIZE_PODCASTS)
        else:
            self.current_page = 1

        self.animated_title = True

    def create_podcast_menu_button(self, s, constr, action, scale, font_size):
        """ Create podcast 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.bounding_box = constr
        s.img_x = None
        s.img_y = None
        s.auto_update = True
        s.show_bgr = True
        s.show_img = True
        s.show_label = True
        s.image_location = ICON_LOCATION
        s.label_location = CENTER
        s.label_area_percent = 30
        s.image_size_percent = ICON_SIZE
        s.text_color_normal = self.config[COLORS][COLOR_BRIGHT]
        s.text_color_selected = self.config[COLORS][COLOR_CONTRAST]
        s.text_color_disabled = self.config[COLORS][COLOR_MEDIUM]
        s.text_color_current = s.text_color_normal
        s.scale = scale
        s.source = None
        s.v_align = V_ALIGN_TOP
        s.h_align = H_ALIGN_LEFT
        s.v_offset = (constr.h/100) * 5
        s.bgr = self.config[BACKGROUND][MENU_BGR_COLOR]
        s.image_area_percent = ICON_AREA
        s.fixed_height = font_size

        button = PodcastButton(self.util, s)
        button.add_release_listener(action)
        if not getattr(s, "enabled", True):
            button.set_enabled(False)
        elif getattr(s, "icon_base", False) and not getattr(s, "scaled", False):
            button.components[1].content = s.icon_base
        button.scaled = scale
        return button

    def set_current(self, state):
        """ Set current state
        
        :param state: button state
        """
        if self.util.connected_to_internet:
            podcast_links_num = len(self.podcasts_util.get_podcasts_links())
        else:
            podcast_links_num = len(self.podcasts_util.load_podcasts())
        
        self.total_pages = math.ceil(podcast_links_num / PAGE_SIZE_PODCASTS)
        
        self.set_loading(self.title)        
        self.turn_page()
        self.reset_loading()        
  
    def select_item(self, s=None):
        """ Select item from menu

        :param s: button state
        """
        if not s: return

        self.current_item = s.url
        self.listeners[KEY_PODCAST_EPISODES](s)

    def turn_page(self):
        """ Turn podcasts page """

        page = {}
        if self.util.connected_to_internet:
            page = self.podcasts_util.get_podcasts(self.current_page, PAGE_SIZE_PODCASTS)
        
        if len(list(page.keys())) == 0 or not self.util.connected_to_internet:
            page = self.podcasts_util.get_podcasts_from_disk(self.current_page, PAGE_SIZE_PODCASTS)
            
        self.podcasts_menu.set_items(page, 0, self.select_item, False)
        
        keys = list(page.keys())
        
        if len(keys) != 0 and self.navigator and self.total_pages > 1:
            self.navigator.get_button_by_name(KEY_PAGE_DOWN).change_label(str(self.current_page - 1))
            self.navigator.get_button_by_name(KEY_PAGE_UP).change_label(str(self.total_pages - self.current_page))
            
        self.set_title(self.current_page)
        self.podcasts_menu.clean_draw_update()
        
        if hasattr(self, "update_observer"):
            self.podcasts_menu.add_menu_observers(self.update_observer, self.redraw_observer)
        
        for b in self.podcasts_menu.buttons.values():
            b.parent_screen = self

        self.podcasts_menu.unselect()
        self.link_borders()
        self.current_item = self.config[PODCASTS][PODCAST_URL]

        menu_selected = self.menu.get_selected_index()
        if menu_selected == None:
            if self.current_item == None or len(self.current_item) == 0:
                self.podcasts_menu.select_by_index(0)
                item = self.podcasts_menu.get_selected_item()
                if item != None:
                    self.current_item = item.state.url

        for b in self.podcasts_menu.buttons.values():
            b.parent_screen = self
            if self.current_item == b.state.url:
                self.podcasts_menu.select_by_index(b.state.index)
                self.navigator.unselect()
                return

    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
        """
        MenuScreen.add_screen_observers(self, update_observer, redraw_observer)
        self.update_observer = update_observer
        self.redraw_observer = redraw_observer
        self.add_loading_listener(redraw_observer)      
        self.navigator.add_observers(update_observer, redraw_observer)
        
예제 #3
0
class TopicDetailScreen(MenuScreen):
    """ Topic Detail Screen """
    def __init__(self, util, listeners, voice_assistant):
        """ Initializer

        :param util: utility object
        :param listeners: listeners
        :param voice_assistant: voice assistant
        """
        self.util = util
        self.config = util.config
        self.listeners = listeners
        self.factory = Factory(util)
        self.go_home = listeners[KEY_HOME]
        self.go_file_playback = listeners[KEY_PLAY_COLLECTION]

        dbutil = util.get_db_util()
        self.selector = Selector(dbutil)

        self.bounding_box = util.screen_rect
        layout = BorderLayout(self.bounding_box)
        layout.set_percent_constraints(PERCENT_TOP_HEIGHT,
                                       PERCENT_BOTTOM_HEIGHT, 0, 0)

        MenuScreen.__init__(self,
                            util,
                            listeners,
                            ROWS,
                            COLUMNS,
                            voice_assistant, [ROWS, COLUMNS],
                            self.turn_page,
                            page_in_title=False,
                            show_loading=False)

        self.navigator = TopicDetailNavigator(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)

        m = self.factory.create_collection_menu_button
        font_size = int(((self.menu_layout.h / ROWS) / 100) * FONT_HEIGHT)
        h = self.config[HORIZONTAL_LAYOUT]
        bgr = self.config[BACKGROUND][MENU_BGR_COLOR]
        self.collection_list_menu = Menu(util,
                                         bgr,
                                         self.menu_layout,
                                         ROWS,
                                         COLUMNS,
                                         create_item_method=m,
                                         align=ALIGN_LEFT,
                                         horizontal_layout=h,
                                         font_size=font_size)
        self.set_menu(self.collection_list_menu)

        self.current_item = None
        self.current_page_items = None
        self.first_item = None
        self.last_item = None
        self.collection_topic = None
        self.selection = None
        self.prev_page = 1
        self.animated_title = True

    def set_current(self, state):
        """ Set current state

        :param state: button state
        """
        source = getattr(state, KEY_SOURCE, None)

        if source == KEY_NAVIGATOR or source == KEY_BACK:
            self.link_borders()
            if self.collection_list_menu.get_selected_item(
            ) == None and not self.navigator.is_selected():
                self.player_button.set_selected(True)
                self.player_button.clean_draw_update()
            return

        if hasattr(state, "collection_topic"):
            self.collection_topic = getattr(state, "collection_topic", "")

        if hasattr(state, "name") and hasattr(state, "collection_topic"):
            self.selection = getattr(state, "name", "")

        self.title = self.config[LABELS][
            self.collection_topic] + ": " + self.selection
        self.set_title(1)

        self.current_page = 1
        self.prev_page = 1
        self.left_button.change_label("0")
        self.right_button.change_label("0")

        self.set_loading(self.title)

        topic = self.get_topic()

        self.total_pages = self.selector.get_page_count_by_column(
            topic, self.selection, PAGE_SIZE)

        if self.total_pages == 0:
            self.reset_loading()
            return

        self.filename = None
        self.title = None

        if self.collection_topic == KEY_FILE:
            self.filename = state.name
        elif self.collection_topic == TITLE:
            self.title = state.name

        self.turn_page()
        self.reset_loading()

    def turn_page(self):
        """ Turn page """

        topic = self.get_topic()

        self.current_page_items = self.selector.get_topic_detail_page(
            topic, self.selection, self.current_page, self.prev_page,
            self.first_item, self.last_item, PAGE_SIZE)
        self.prev_page = self.current_page

        if not self.current_page_items:
            self.current_page_items = []
            self.link_borders()
            return

        self.current_item = self.current_page_items[0]
        self.first_item = self.current_item
        self.last_item = self.current_page_items[len(self.current_page_items) -
                                                 1]

        p = {}
        for i, f in enumerate(self.current_page_items):
            s = State()
            s.index = i
            s.folder = f
            if "\x00" in f:
                f = f.replace("\x00", "")
            if "/" in f:
                parts = f.split("/")
                if len(parts) > 1:
                    last = parts[len(parts) - 1]
                    if len(last) > 6:
                        f = last
                    else:
                        f = parts[len(parts) - 2] + "/" + last
            s.name = f
            s.l_name = s.name
            if self.filename:
                s.file_name = self.filename
            if self.title:
                s.title = self.title
            p[str(i)] = s

        self.collection_list_menu.set_items(p, 0, self.select_item, False)

        keys = list(p.keys())

        if len(keys) != 0 and 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))

        self.collection_list_menu.clean_draw_update()

        if hasattr(self, "update_observer"):
            self.collection_list_menu.add_menu_observers(
                self.update_observer, self.redraw_observer)

        for b in self.collection_list_menu.buttons.values():
            b.parent_screen = self

        self.collection_list_menu.unselect()
        self.link_borders()

        menu_selected = self.menu.get_selected_index()
        if menu_selected == None:
            if self.current_item == None:
                self.collection_list_menu.select_by_index(0)
                item = self.collection_list_menu.get_selected_item()
                if item != None:
                    self.current_item = item.state.name

        if self.navigator.is_selected():
            return

        for b in self.collection_list_menu.buttons.values():
            b.parent_screen = self
            if self.current_item == b.state.name:
                self.collection_list_menu.select_by_index(b.state.index)
                return

    def get_topic(self):
        """ Get topic

        :return: proper topic name
        """
        topic = self.collection_topic
        if topic == KEY_AUDIO_FOLDER:
            topic = FOLDER
        elif topic == KEY_FILE:
            topic = FILENAME

        return topic

    def select_item(self, s=None):
        """ Select item from menu

        :param state: button state
        """
        self.current_item = s.name
        state = State()
        state.folder = os.path.join(self.config[COLLECTION][BASE_FOLDER],
                                    s.folder[1:])
        state.topic = self.collection_topic

        if state.topic == KEY_FILE:
            state.file_name = s.file_name
            state.url = os.path.join(state.folder, state.file_name)
        elif state.topic == TITLE:
            state.file_name = self.selector.get_filename_by_title(
                s.folder, self.title)
            state.url = os.path.join(state.folder, state.file_name)
        else:
            files = self.util.get_audio_files_in_folder(
                state.folder, False, False)
            if files:
                f = files[0]
                state.file_name = f.file_name
                state.url = os.path.join(state.folder, state.file_name)
            else:
                state.file_name = None
                state.url = None

        state.source = "detail"
        self.collection_list_menu.select_by_index(s.index)
        self.go_file_playback(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
        """
        MenuScreen.add_screen_observers(self, update_observer, redraw_observer)
        self.update_observer = update_observer
        self.redraw_observer = redraw_observer
        self.add_loading_listener(redraw_observer)
        self.navigator.add_observers(update_observer, redraw_observer)
예제 #4
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)