Esempio n. 1
0
    def __init__(self, listeners, util):
        """ Initializer
        
        :param util: utility object
        :param listener: screen menu event listener
        """
        self.util = util
        self.config = util.config
        Container.__init__(self, util, background=(0, 0, 0))
        self.factory = Factory(util)
        self.bounding_box = self.config[SCREEN_RECT]
        layout = BorderLayout(self.bounding_box)
        k = self.bounding_box.w/self.bounding_box.h
        percent_menu_width = (100.0 - PERCENT_TOP_HEIGHT - PERCENT_BOTTOM_HEIGHT)/k
        panel_width = (100.0 - percent_menu_width)/2.0
        layout.set_percent_constraints(PERCENT_TOP_HEIGHT, PERCENT_BOTTOM_HEIGHT, panel_width, panel_width)
        self.genres = util.load_menu(GENRE_ITEMS, GENRE)        
        self.current_genre = self.genres[self.config[CURRENT][PLAYLIST]]
        self.items_per_line = self.items_per_line(layout.CENTER.w)
        self.playlist = Playlist(self.config[CURRENT][LANGUAGE], self.current_genre.genre, util, self.items_per_line)
        
        font_size = (layout.TOP.h * PERCENT_TITLE_FONT)/100.0
        color_dark = self.config[COLORS][COLOR_DARK]
        color_contrast = self.config[COLORS][COLOR_CONTRAST]
        self.screen_title = self.factory.create_dynamic_text("station_screen_title", layout.TOP, color_dark, color_contrast, int(font_size))
        Container.add_component(self, self.screen_title)

        self.station_menu = StationMenu(self.playlist, util, (0, 0, 0), layout.CENTER)
        self.screen_title.set_text(self.station_menu.button.state.l_name)        
        Container.add_component(self, self.station_menu)
        
        self.create_left_panel(layout, listeners)
        self.create_right_panel(layout, listeners)        

        self.home_button.add_release_listener(listeners["go home"])
        self.genres_button.add_release_listener(listeners["go genres"])
        self.shutdown_button.add_release_listener(listeners["shutdown"])
        self.left_button.add_release_listener(self.station_menu.switch_to_previous_station)
        self.left_button.add_release_listener(self.update_arrow_button_labels)
        self.page_down_button.add_release_listener(self.station_menu.switch_to_previous_page)
        self.page_down_button.add_release_listener(self.update_arrow_button_labels)
        self.right_button.add_release_listener(self.station_menu.switch_to_next_station)
        self.right_button.add_release_listener(self.update_arrow_button_labels)
        self.page_up_button.add_release_listener(self.station_menu.switch_to_next_page)
        self.page_up_button.add_release_listener(self.update_arrow_button_labels)               
        self.station_menu.add_listener(listeners["play"])
        self.station_menu.add_listener(self.screen_title.set_state)
        self.station_menu.add_listener(self.update_arrow_button_labels)        
        self.station_menu.add_mode_listener(self.mode_listener)
        
        self.volume = self.factory.create_volume_control(layout.BOTTOM)
        self.volume.add_slide_listener(listeners["set volume"])
        self.volume.add_slide_listener(listeners["set config volume"])
        self.volume.add_slide_listener(listeners["set screensaver volume"])
        self.volume.add_knob_listener(listeners["mute"])        
        Container.add_component(self, self.volume)
Esempio n. 2
0
class Screen(Container):
    """ Base class for all screens. Extends Container class """
    
    def __init__(self, util, title_key):
        """ Initializer
        
        :param util: utility object
        :param title_key: the resource bundle key for the screen title
        """
        Container.__init__(self, util)
        self.util = util
        factory = Factory(util)
        config = util.config
        self.bounding_box = config[SCREEN_RECT]
        self.bgr = (0, 0, 0)
        self.layout = BorderLayout(config[SCREEN_RECT])
        self.layout.set_percent_constraints(PERCENT_TOP_HEIGHT, 0, 0, 0)

        font_size = (self.layout.TOP.h * PERCENT_TITLE_FONT)/100.0
        d = config[COLORS][COLOR_DARK]
        c = config[COLORS][COLOR_CONTRAST]
        self.screen_title = factory.create_output_text("screen_title", self.layout.TOP, d, c, int(font_size))
        label = config[LABELS][title_key]
        self.screen_title.set_text(label) 
        self.add_component(self.screen_title)
        
    def add_menu(self, menu):
        """ Add menu to the screen
        
        :param menu: the menu to add
        """
        self.menu = menu
        self.add_component(menu)
        
    def get_clickable_rect(self):
        """ Return the list of rectangles which define the clickable areas on screen. Used for web browser. 
        
        :return: list of rectangles
        """
        c = Component(self.util)
        c.name = "clickable_rect"
        c.content = self.menu.bounding_box
        c.bgr = c.fgr = (0, 0, 0)
        c.content_x = c.content_y = 0
        d = [c]       
        return d
Esempio n. 3
0
 def create_left_panel(self, layout, listeners):
     """ Create Station Screen left panel. Include Shutdown button, Left button and Home button.
     
     :param layout: left panel layout
     :param listeners: event listeners
     """
     panel_layout = BorderLayout(layout.LEFT)
     panel_layout.set_percent_constraints(PERCENT_SIDE_BOTTOM_HEIGHT, PERCENT_SIDE_BOTTOM_HEIGHT, 0, 0)
     left = self.station_menu.button.state.index
     self.left_button = self.factory.create_left_button(panel_layout.CENTER, str(left))
     self.page_down_button = self.factory.create_page_down_button(panel_layout.CENTER, str(left))
     self.page_down_button.set_visible(False)
     self.shutdown_button = self.factory.create_shutdown_button(panel_layout.TOP)
     self.home_button = self.factory.create_home_button(panel_layout.BOTTOM)
     panel = Container(self.util, layout.LEFT)
     panel.add_component(self.shutdown_button)
     panel.add_component(self.left_button)
     panel.add_component(self.page_down_button)
     panel.add_component(self.home_button)
     Container.add_component(self, panel)
Esempio n. 4
0
 def create_right_panel(self, layout, listeners):
     """ Create Station Screen right panel. Include Genre button, right button and Play/Pause button
     
     :param layout: right panel layout
     :param listeners: event listeners
     """
     panel_layout = BorderLayout(layout.RIGHT)
     panel_layout.set_percent_constraints(PERCENT_SIDE_BOTTOM_HEIGHT, PERCENT_SIDE_BOTTOM_HEIGHT, 0, 0)
     self.genres_button = self.factory.create_genre_button(panel_layout.TOP, self.current_genre)
     right = self.playlist.length - self.station_menu.button.state.index - 1 
     self.right_button = self.factory.create_right_button(panel_layout.CENTER, str(right))
     self.page_up_button = self.factory.create_page_up_button(panel_layout.CENTER, str(right))
     self.page_up_button.set_visible(False)
     self.play_button = self.factory.create_play_pause_button(panel_layout.BOTTOM, listeners["play-pause"])  
     panel = Container(self.util, layout.RIGHT)
     panel.add_component(self.genres_button)
     panel.add_component(self.right_button)
     panel.add_component(self.page_up_button)
     panel.add_component(self.play_button)
     Container.add_component(self, panel)
Esempio n. 5
0
class CdTracksScreen(Screen):
    """ File Browser Screen """
    def __init__(self, util, listeners, voice_assistant, state):
        """ Initializer
        
        :param util: utility object
        :param listeners: file browser listeners
        """
        self.util = util
        self.config = util.config
        self.cdutil = CdUtil(util)
        self.factory = Factory(util)
        self.bounding_box = self.config[SCREEN_RECT]
        self.layout = BorderLayout(self.bounding_box)
        self.layout.set_percent_constraints(PERCENT_TOP_HEIGHT,
                                            PERCENT_BOTTOM_HEIGHT, 0, 0)
        Screen.__init__(self, util, "", PERCENT_TOP_HEIGHT, voice_assistant,
                        "cd_tracks_screen_title", True, self.layout.TOP)
        color_dark_light = self.config[COLORS][COLOR_DARK_LIGHT]
        self.current_cd_drive_name = self.config[CD_PLAYBACK][CD_DRIVE_NAME]
        self.current_cd_drive_id = self.config[CD_PLAYBACK][CD_DRIVE_ID]

        self.filelist = self.get_filelist()

        self.file_menu = FileMenu(self.filelist,
                                  util,
                                  None, (0, 0, 0),
                                  self.layout.CENTER,
                                  align=ALIGN_LEFT)

        self.go_cd_player = listeners[KEY_PLAYER]
        self.file_menu.add_play_file_listener(self.play_track)
        Container.add_component(self, self.file_menu)

        listeners[GO_LEFT_PAGE] = self.file_menu.page_down
        listeners[GO_RIGHT_PAGE] = self.file_menu.page_up
        listeners[KEY_EJECT] = self.eject_cd
        listeners[KEY_REFRESH] = self.refresh_tracks
        connected_cd_drives = self.cdutil.get_cd_drives_number()
        self.navigator = CdTracksNavigator(util, connected_cd_drives,
                                           self.layout.BOTTOM, listeners,
                                           color_dark_light)
        Container.add_component(self, self.navigator)

        self.file_menu.add_left_number_listener(
            self.navigator.left_button.change_label)
        self.file_menu.add_right_number_listener(
            self.navigator.right_button.change_label)
        self.file_menu.update_buttons()
        self.page_turned = False

    def play_track(self, state):
        """ Set config and go to player
        
        :param state: state object with track info
        """
        self.config[CD_PLAYBACK][CD_DRIVE_ID] = self.current_cd_drive_id
        self.config[CD_PLAYBACK][CD_DRIVE_NAME] = self.current_cd_drive_name
        self.config[CD_PLAYBACK][CD_TRACK_TIME] = "0"

        if self.current_cd_drive_name != self.screen_title.text:
            state.album = self.screen_title.text

        self.go_cd_player(state)

    def get_filelist(self):
        """ Return CD tracks
        
        :return: page with CD tracks
        """
        rows = 5
        columns = 2

        layout = GridLayout(self.layout.CENTER)
        layout.set_pixel_constraints(rows, columns, 1, 1)
        constr = layout.get_next_constraints()
        fixed_height = int((constr.h * 35) / 100.0)

        tracks = self.cdutil.get_cd_tracks(rows, columns, fixed_height,
                                           self.current_cd_drive_name)
        if tracks == None:
            tracks = []
        return Page(tracks, rows, columns)

    def set_current(self, state):
        """ Set current CD drive
        
        :param state: state object with drive info
        """
        if not self.current_cd_drive_name or (
                getattr(state, "name", None)
                and self.current_cd_drive_name != state.name):
            change_menu = False
            if not self.current_cd_drive_name:
                self.current_cd_drive_name = self.cdutil.get_default_cd_drive(
                )[1]
                change_menu = True
            elif state.name != "cd":
                self.current_cd_drive_name = state.name
                change_menu = True

            name = self.current_cd_drive_name
            tracks = len(self.file_menu.filelist.items)
            empty = self.cdutil.is_drive_empty(name)
            if name and empty != 1 and tracks == 0:
                change_menu = True

            if change_menu:
                id = self.cdutil.get_cd_drive_id_by_name(
                    self.current_cd_drive_name)
                self.current_cd_drive_id = id
                self.file_menu.selected_index = 0
                self.set_file_menu()

            self.set_screen_title()

    def set_screen_title(self):
        """ Set screen title """

        title = drive_name = self.current_cd_drive_name
        try:
            title = self.util.cd_titles[drive_name]
        except:
            pass
        self.screen_title.set_text(title)

    def eject_cd(self, state):
        """ Eject CD
        
        :param state: state object with drive info
        """
        if len(str(self.current_cd_drive_id)) == 0:
            return

        del self.util.cd_track_names_cache[self.current_cd_drive_id]
        if state == None or getattr(state, "no_physical_eject", None) == None:
            self.cdutil.eject_cd(int(self.current_cd_drive_id))
        self.util.cd_titles[
            self.current_cd_drive_name] = self.current_cd_drive_name
        self.file_menu.selected_index = 0
        self.set_file_menu()
        self.set_screen_title()

    def refresh_tracks(self, state):
        """ Refresh tracks menu
        
        :param state: not used
        """
        name = self.current_cd_drive_name
        if name and self.cdutil.is_drive_empty(name):
            s = State()
            s.no_physical_eject = True
            self.eject_cd(s)

        self.set_file_menu()
        self.set_screen_title()

    def set_file_menu(self):
        """ Set file menu """

        filelist = self.get_filelist()
        self.file_menu.filelist = filelist
        self.file_menu.update_buttons()
        page = filelist.get_current_page()
        self.file_menu.set_page(filelist.current_item_index_in_page, page)

    def get_filelist_items(self, get_current_playlist):
        """ Call player for files in the playlist 
        
        :return: list of files from playlist
        """
        playlist = get_current_playlist()
        files = []
        if playlist:
            for n in range(len(playlist)):
                st = State()
                st.index = st.comparator_item = n
                st.file_type = FILE_AUDIO
                st.file_name = st.url = playlist[n]
                files.append(st)
        return files

    def add_screen_observers(self, update_observer, redraw_observer):
        """ Add screen observers
        
        :param update_observer: observer for updating the screen
        :param redraw_observer: observer to redraw the whole screen
        """
        Screen.add_screen_observers(self, update_observer, redraw_observer)
        self.file_menu.add_menu_observers(update_observer,
                                          redraw_observer=None,
                                          release=False)
        self.file_menu.add_change_folder_listener(redraw_observer)
        self.file_menu.add_menu_navigation_listeners(redraw_observer)

        self.file_menu.add_left_number_listener(redraw_observer)
        self.file_menu.add_right_number_listener(redraw_observer)

        self.navigator.add_observers(update_observer, redraw_observer)
Esempio n. 6
0
    def __init__(self, util, connected_cd_drives, bounding_box, listeners,
                 bgr):
        """ Initializer
        
        :param util: utility object
        :param bounding_box: bounding box
        :param listeners: buttons listeners
        :param bgr: menu background        
        """
        Container.__init__(self, util)
        self.factory = Factory(util)
        self.name = "navigator"
        self.content = bounding_box
        self.content_x = bounding_box.x
        self.content_y = bounding_box.y
        self.menu_buttons = []
        self.config = util.config

        arrow_layout = BorderLayout(bounding_box)
        arrow_layout.set_percent_constraints(0, 0, PERCENT_ARROW_WIDTH,
                                             PERCENT_ARROW_WIDTH)

        constr = arrow_layout.LEFT
        self.left_button = self.factory.create_page_down_button(
            constr, "0", 40, 100)
        self.left_button.add_release_listener(listeners[GO_LEFT_PAGE])
        self.add_component(self.left_button)
        self.menu_buttons.append(self.left_button)

        constr = arrow_layout.RIGHT
        self.right_button = self.factory.create_page_up_button(
            constr, "0", 40, 100)
        self.right_button.add_release_listener(listeners[GO_RIGHT_PAGE])
        self.add_component(self.right_button)
        self.menu_buttons.append(self.right_button)

        layout = GridLayout(arrow_layout.CENTER)
        p = self.config[AUDIO][PLAYER_NAME]
        show_drives = connected_cd_drives > 1 and (p == VLC_NAME
                                                   or p == MPD_NAME)

        if show_drives:
            layout.set_pixel_constraints(1, 5, 1, 0)
        else:
            layout.set_pixel_constraints(1, 4, 1, 0)
        layout.current_constraints = 0
        image_size = 56

        constr = layout.get_next_constraints()
        self.home_button = self.factory.create_button(
            KEY_HOME,
            KEY_HOME,
            constr,
            listeners[KEY_HOME],
            bgr,
            image_size_percent=image_size)
        self.add_component(self.home_button)
        self.menu_buttons.append(self.home_button)

        if show_drives:
            constr = layout.get_next_constraints()
            self.cd_drives_button = self.factory.create_button(
                KEY_CD_PLAYERS,
                KEY_ROOT,
                constr,
                listeners[KEY_CD_PLAYERS],
                bgr,
                image_size_percent=image_size)
            self.add_component(self.cd_drives_button)
            self.menu_buttons.append(self.cd_drives_button)

        constr = layout.get_next_constraints()
        self.refresh_button = self.factory.create_button(
            KEY_REFRESH,
            KEY_SETUP,
            constr,
            listeners[KEY_REFRESH],
            bgr,
            image_size_percent=image_size)
        self.add_component(self.refresh_button)
        self.menu_buttons.append(self.refresh_button)

        constr = layout.get_next_constraints()
        self.eject_button = self.factory.create_button(
            KEY_EJECT,
            KEY_PARENT,
            constr,
            listeners[KEY_EJECT],
            bgr,
            image_size_percent=image_size)
        self.add_component(self.eject_button)
        self.menu_buttons.append(self.eject_button)

        constr = layout.get_next_constraints()
        self.back_button = self.factory.create_button(
            KEY_BACK,
            KEY_BACK,
            constr,
            None,
            bgr,
            image_size_percent=image_size)
        self.back_button.add_release_listener(listeners[GO_BACK])
        self.back_button.add_release_listener(listeners[KEY_PLAYER])
        self.add_component(self.back_button)
        self.menu_buttons.append(self.back_button)
Esempio n. 7
0
class Screen(Container):
    """ Base class for all screens with menu and navigator """
    
    def __init__(self, util, title_key, percent_bottom_height=0, voice_assistant=None, screen_title_name="screen_title", 
        create_dynamic_title=False, title_layout=None, title=None, bgr=None):
        """ Initializer
        
        :param util: utility object
        :param title_key: the resource bundle key for the screen title
        """
        self.util = util
        self.factory = Factory(util)
        self.config = util.config
        self.bounding_box = util.screen_rect

        if title_key:
            self.name = title_key
        else:
            self.name = "tmp"

        bg = self.util.get_background(self.name, bgr)
        self.bgr_type = bg[0]
        self.bgr = bg[1]
        self.bgr_key = bg[5]
        Container.__init__(self, util, bounding_box=self.bounding_box, background=bg[1], content=bg[2], image_filename=bg[3])
        self.original_image_filename = None
        try:
            self.original_image_filename = bg[4].replace("\\", "/")
        except:
            pass

        self.layout = BorderLayout(util.screen_rect)
        self.layout.set_percent_constraints(PERCENT_TOP_HEIGHT, percent_bottom_height, 0, 0)
        self.voice_assistant = voice_assistant

        self.font_size = int((self.layout.TOP.h * PERCENT_TITLE_FONT)/100.0)
        b = self.config[BACKGROUND][HEADER_BGR_COLOR]
        c = self.config[COLORS][COLOR_CONTRAST]
        
        t_layout = self.layout.TOP
        if title_layout:
            t_layout = title_layout
        
        if create_dynamic_title:
            self.screen_title = self.factory.create_dynamic_text(screen_title_name, t_layout, b, c, self.font_size)
        else:
            self.screen_title = self.factory.create_output_text(screen_title_name, t_layout, b, c, self.font_size)
        
        if title:
            self.screen_title.set_text(title)
        else:    
            if title_key and len(title_key) > 0:
                try:
                    label = self.config[LABELS][title_key]
                    self.screen_title.set_text(label)
                except:
                    pass 
        
        if voice_assistant:
            self.screen_title.add_select_listener(self.handle_voice_assistant)
            self.layout.TOP.w += 1
            self.voice_command = self.factory.create_output_text("voice_command", self.layout.TOP, b, c, self.font_size)
            self.voice_command.add_select_listener(self.handle_voice_assistant)
            self.voice_assistant.add_text_recognized_listener(self.text_recognized)
            self.voice_assistant.assistant.add_start_conversation_listener(self.start_conversation)
            self.voice_assistant.assistant.add_stop_conversation_listener(self.stop_conversation)
        
        if voice_assistant and voice_assistant.is_running():
            self.title_selected = False
        else:
            self.title_selected = True
            
        self.draw_title_bar()        
        self.player_screen = False
        self.update_web_observer = None
        self.update_web_title = None

        self.loading_listeners = []
        self.LOADING = util.config[LABELS][KEY_LOADING]
        self.animated_title = False
    
    def add_component(self, c):
        """ Add screen component

        :param c: component to add
        """
        if c:
            c.set_parent_screen(self)
        Container.add_component(self, c)

    def draw_title_bar(self):
        """ Draw title bar on top of the screen """
        
        if len(self.components) != 0 and self.title_selected:
            self.add_component(self.voice_command)
            self.title_selected = False
        elif len(self.components) != 0 and not self.title_selected:
            self.add_component(self.screen_title)
            self.title_selected = True
        elif len(self.components) == 0 and self.title_selected:
            self.add_component(self.screen_title)
        elif len(self.components) == 0 and not self.title_selected:
            self.voice_command.set_text(self.config[LABELS][KEY_WAITING_FOR_COMMAND])
            self.add_component(self.voice_command)
            
    def handle_voice_assistant(self, state=None):
        """ Start/Stop voice assistant 
        
        :state: not used
        """
        if self.title_selected:
            self.voice_assistant.start()
        else:
            self.voice_assistant.stop()
    
    def text_recognized(self, text):
        """ Handle text recognized event 
        
        :text: recognized text
        """
        c = self.config[LABELS][KEY_VA_COMMAND] + " " + text
        self.voice_command.set_text(c)
        self.voice_command.clean_draw_update()
        time.sleep(self.config[VOICE_ASSISTANT][VOICE_COMMAND_DISPLAY_TIME])
        if self.update_web_title:
            self.update_web_title(self.voice_command)
        
    def start_conversation(self, event):
        """ Start voice conversation
        
        :event: not used
        """
        if self.visible: 
            self.voice_command.set_visible(True)
        self.voice_command.set_text_no_draw(self.config[LABELS][KEY_WAITING_FOR_COMMAND])
        self.components[0] = self.voice_command
        self.title_selected = False
        if self.visible:
            self.voice_command.clean_draw_update()
            if self.update_web_observer:
                self.update_web_observer()
    
    def stop_conversation(self):
        """ Stop voice conversation """
        
        if self.visible: 
            self.screen_title.set_visible(True)
        self.components[0] = self.screen_title
        self.title_selected = True
        if self.visible:
            self.screen_title.clean_draw_update()
            if self.update_web_observer:
                self.update_web_observer()
    
    def add_menu(self, menu):
        """ Add menu to the screen
        
        :param menu: the menu to add
        """
        self.menu = menu
        self.add_component(menu)

    def add_navigator(self, navigator):
        """ Add navigator to the screen
        
        :param menu: the menu to add
        """
        self.navigator = navigator
        self.add_component(navigator)

    def enable_player_screen(self, flag):
        """ Enable player screen
        
        :param flag: enable/disable flag
        """
        pass
    
    def exit_screen(self):
        """ Complete actions required to save screen state """
        
        self.set_visible(False)
    
    def add_screen_observers(self, update_observer, redraw_observer, title_to_json=None):
        """ Add screen observers.
        
        :param update_observer: observer for updating the screen
        :param redraw_observer: observer to redraw the whole screen
        """
        self.update_web_observer = redraw_observer
        self.update_web_title = title_to_json

    def set_loading(self, name=None, menu_bb=None, text=None):
        """ Show Loading... sign

        :param name: screen title
        :param menu_bb: menu bounding box
        :param text: screen text
        """
        b = self.config[BACKGROUND][MENU_BGR_COLOR]
        f = self.config[COLORS][COLOR_BRIGHT]
        fs = int(self.bounding_box.h * 0.07)

        if menu_bb != None:
            bb = menu_bb
        else:
            bb = self.bounding_box

        bb = Rect(bb.x, bb.y + 1, bb.w, bb.h - 1)

        t = self.factory.create_output_text(self.LOADING, bb, b, f, fs)
        if not text:
            t.set_text_no_draw(self.LOADING)
        else:
            t.set_text_no_draw(text)

        if name != None:
            self.screen_title.set_text(name)

        self.set_visible(True)
        self.add_component(t)
        if getattr(self, "menu", None) != None:
            self.menu.buttons = {}
            self.menu.components = []
        self.clean_draw_update()
        self.notify_loading_listeners()

    def reset_loading(self):
        """ Remove Loading label """

        del self.components[-1]
        self.notify_loading_listeners()

    def add_loading_listener(self, listener):
        """ Add loading listener

        :param listener: event listener
        """
        if listener not in self.loading_listeners:
            self.loading_listeners.append(listener)

    def notify_loading_listeners(self):
        """ Notify all loading listeners """

        for listener in self.loading_listeners:
            listener(None)

    def handle_event(self, event):
        """ Event handler

        :param event: event to handle
        """
        if not self.visible: return

        mouse_events = [pygame.MOUSEBUTTONUP, pygame.MOUSEBUTTONDOWN]
        
        if event.type in mouse_events and getattr(self, "menu", None) and getattr(self, "navigator", None):
            event_component = None

            for comp in self.menu.components:
                if getattr(comp, "state", None):
                    bb = comp.state.bounding_box
                else:
                    bb = comp.bounding_box

                if bb == None:
                    continue

                if bb.collidepoint(event.pos):
                    event_component = comp
                    for c in self.menu.components:
                        if hasattr(c, "set_selected") and c != comp:
                            c.set_selected(False)
                            c.clean_draw_update()

            if event_component:
                self.navigator.unselect()
                event_component.handle_event(event)
                if hasattr(self.menu, "current_slider"):
                    self.menu.current_slider = event_component.id
                if self.update_web_observer:
                    self.update_web_observer()
                return
            
            for comp in self.navigator.components:
                if getattr(comp, "state", None):
                    bb = comp.state.bounding_box
                else:
                    bb = comp.bounding_box

                if bb == None:
                    continue

                if bb.collidepoint(event.pos):
                    event_component = comp
                    break
            if event_component:
                for c in self.menu.components:
                    if getattr(c, "selected", False):
                        c.set_selected(False)
                        c.clean_draw_update()
                    elif hasattr(c, "slider"):
                        c.slider.set_knob_off()
                self.navigator.unselect()
                event_component.handle_event(event)
                if self.update_web_observer:
                    self.update_web_observer()
        else:
            Container.handle_event(self, event)
            self.update_web_observer()

    def get_menu_bottom_exit_xy(self, x):
        """ Get bottom exit coordinates

        :param x: event x coordinate
        """
        button = None
        xy = None
        for b in self.menu.components:
            if getattr(b, "bounding_box", None) == None:
                continue
            y = b.bounding_box.y + 5
            if b.bounding_box.collidepoint((x, y)):
                button = b

        if button == None:
            num = len(self.menu.components)
            if num != 0:
                button = self.menu.components[num - 1]
        
        if button != None and getattr(button, "bounding_box", None) != None:
            xy = (button.bounding_box.x + (button.bounding_box.w / 2), button.bounding_box.y)    

        return xy

    def link_borders(self, navigator_top_bottom_exit=True, first_index=None, last_index=None):
        """ Link components borders for the arrow keys navigation 

        :param navigator_top_bottom_exit:
        """
        if not hasattr(self.navigator, "components"):
            return

        margin = 10
        num = len(self.navigator.components)
        first_menu_comp = last_menu_comp = None

        if getattr(self, "menu", None):
            self.menu.exit_top_y = self.menu.exit_bottom_y = self.menu.bounding_box.y + self.menu.bounding_box.h + margin
            
            first_nav_comp = self.navigator.components[0]
            last_nav_comp = self.navigator.components[num - 1]

            self.menu.exit_right_x = first_nav_comp.bounding_box.x + margin
            self.menu.exit_right_y = first_nav_comp.bounding_box.y + margin
            
            self.menu.exit_left_x = last_nav_comp.bounding_box.x + last_nav_comp.bounding_box.w - margin
            self.menu.exit_left_y = last_nav_comp.bounding_box.y + margin

            if first_index == None: first_index = 0
            if last_index == None: last_index = len(self.menu.components) - 1
            if len(self.menu.components) > 0:
                first_menu_comp = self.menu.components[first_index]
                last_menu_comp = self.menu.components[last_index]

        if getattr(self, "menu", None) and len(self.menu.components) == 0:
            navigator_top_bottom_exit = False    

        for index, comp in enumerate(self.navigator.components):
            if navigator_top_bottom_exit and getattr(self, "menu", None):
                xy = self.get_menu_bottom_exit_xy(comp.bounding_box.x + 5)
                if xy:
                    comp.exit_top_y = xy[1] + margin
                    comp.exit_bottom_y = self.menu.bounding_box.y + margin
                    comp.exit_x = xy[0]
            else:
                comp.exit_top_y = None
                comp.exit_bottom_y = None
                comp.exit_x = None

            if index == 0:
                if last_menu_comp != None:
                    comp.exit_left_x = last_menu_comp.bounding_box.x + margin
                    comp.exit_left_y = last_menu_comp.bounding_box.y + margin
                else:
                    comp.exit_left_x = self.navigator.components[num - 1].bounding_box.x + margin
                    comp.exit_left_y = self.navigator.components[num - 1].bounding_box.y + margin
                c = self.navigator.components[index + 1]
                comp.exit_right_x = c.bounding_box.x + margin
            elif index == (num - 1):
                c = self.navigator.components[num - 2]
                comp.exit_left_x = c.bounding_box.x + margin
                if first_menu_comp != None:
                    comp.exit_right_x = first_menu_comp.bounding_box.x + margin
                    comp.exit_right_y = first_menu_comp.bounding_box.y + margin
                else:
                    comp.exit_right_x = self.navigator.components[0].bounding_box.x + margin
                    comp.exit_right_y = self.navigator.components[0].bounding_box.y + margin
            else:
                c = self.navigator.components[index - 1]
                comp.exit_left_x = c.bounding_box.x + margin
                c = self.navigator.components[index + 1]
                comp.exit_right_x = c.bounding_box.x + margin
Esempio n. 8
0
class CollectionBrowserNavigator(Container):
    """ Topic detail navigator """
    def __init__(self, util, bounding_box, listeners):
        """ Initializer

        :param util: utility object
        :param bounding_box: bounding box
        :param listeners: buttons listeners
        """
        Container.__init__(self, util)
        self.factory = Factory(util)
        self.name = "collection.navigator"
        self.content = bounding_box
        self.content_x = bounding_box.x
        self.content_y = bounding_box.y
        self.listeners = listeners
        self.menu_buttons = []
        self.config = util.config
        self.use_web = self.config[USAGE][USE_WEB]
        self.arrow_layout = BorderLayout(bounding_box)
        self.arrow_layout.set_percent_constraints(0, 0, PERCENT_ARROW_WIDTH,
                                                  PERCENT_ARROW_WIDTH)
        self.update_observer = None
        self.redraw_observer = None
        self.menu_buttons = []

        constr = self.arrow_layout.LEFT
        self.left_button = self.factory.create_page_down_button(
            constr, "0", 40, 100)
        self.left_button.add_release_listener(self.listeners[GO_LEFT_PAGE])
        self.add_component(self.left_button)
        self.menu_buttons.append(self.left_button)

        constr = self.arrow_layout.RIGHT
        self.right_button = self.factory.create_page_up_button(
            constr, "0", 40, 100)
        self.right_button.add_release_listener(self.listeners[GO_RIGHT_PAGE])
        self.add_component(self.right_button)
        self.menu_buttons.append(self.right_button)

        layout = GridLayout(self.arrow_layout.CENTER)
        layout.set_pixel_constraints(1, 5, 1, 0)
        layout.current_constraints = 0

        bgr = util.config[BACKGROUND][FOOTER_BGR_COLOR]
        self.add_button(KEY_HOME, KEY_HOME, layout, self.listeners[KEY_HOME],
                        bgr)
        self.add_button(COLLECTION, KEY_PARENT, layout,
                        self.listeners[COLLECTION], bgr)
        self.add_button(KEY_LIST, KEY_MENU, layout,
                        self.listeners[COLLECTION_TOPIC], bgr)
        self.add_button(KEY_DETAIL, KEY_SETUP, layout,
                        self.listeners[TOPIC_DETAIL], bgr)
        self.add_button(KEY_PLAYER, KEY_PLAY_PAUSE, layout,
                        self.listeners[KEY_PLAYER], bgr)

        if self.use_web and self.update_observer != None:
            self.add_observers(self.update_observer, self.redraw_observer)

    def add_button(self, img_name, key, layout, listener, bgr):
        """ Add button to the navigator

        :param img_name: button image name
        :param key: keyboard key
        :param layout: button layout
        :param listener: button listener
        """
        c = layout.get_next_constraints()
        b = self.factory.create_button(img_name,
                                       key,
                                       c,
                                       listener,
                                       bgr,
                                       source=KEY_NAVIGATOR,
                                       image_size_percent=IMAGE_SIZE_PERCENT)
        self.add_component(b)
        self.menu_buttons.append(b)

    def add_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
        """
        if self.update_observer == None:
            self.update_observer = update_observer
            self.redraw_observer = redraw_observer

        for b in self.menu_buttons:
            self.add_button_observers(b, update_observer, redraw_observer)
Esempio n. 9
0
    def __init__(self, util, bounding_box, listeners, bgr, language_url=None):
        """ Initializer
        
        :param util: utility object
        :param bounding_box: bounding box
        :param listeners: buttons listeners
        :param bgr: menu background
        :param language_url: language constant        
        """
        Container.__init__(self, util)
        self.factory = Factory(util)
        self.name = "navigator"
        arrow_layout = BorderLayout(bounding_box)
        arrow_layout.set_percent_constraints(0, 0, PERCENT_ARROW_WIDTH,
                                             PERCENT_ARROW_WIDTH)
        self.menu_buttons = []

        constr = arrow_layout.LEFT
        self.left_button = self.factory.create_page_down_button(
            constr, "0", 34, 100)
        self.left_button.add_release_listener(listeners[GO_LEFT_PAGE])
        self.add_component(self.left_button)
        self.menu_buttons.append(self.left_button)

        constr = arrow_layout.RIGHT
        self.right_button = self.factory.create_page_up_button(
            constr, "0", 34, 100)
        self.right_button.add_release_listener(listeners[GO_RIGHT_PAGE])
        self.add_component(self.right_button)
        self.menu_buttons.append(self.right_button)

        layout = GridLayout(arrow_layout.CENTER)
        if language_url == "":  # English-USA
            buttons = 5
        elif language_url == None:  #Russian
            buttons = 6
        else:
            buttons = 4
        layout.set_pixel_constraints(1, buttons, 1, 0)
        layout.current_constraints = 0
        image_size = 56

        constr = layout.get_next_constraints()
        self.home_button = self.factory.create_button(
            KEY_HOME,
            KEY_HOME,
            constr,
            listeners[KEY_HOME],
            bgr,
            image_size_percent=image_size)
        self.add_component(self.home_button)
        self.menu_buttons.append(self.home_button)

        if language_url == None:
            constr = layout.get_next_constraints()
            self.abc_button = self.factory.create_button(
                IMAGE_ABC,
                KEY_SETUP,
                constr,
                listeners[GO_USER_HOME],
                bgr,
                image_size_percent=image_size)
            self.add_component(self.abc_button)
            self.menu_buttons.append(self.abc_button)

        constr = layout.get_next_constraints()
        self.new_books_button = self.factory.create_button(
            IMAGE_NEW_BOOKS,
            KEY_MENU,
            constr,
            listeners[GO_ROOT],
            bgr,
            image_size_percent=image_size)
        self.add_component(self.new_books_button)
        self.menu_buttons.append(self.new_books_button)

        if language_url == None or language_url == "":  # English-USA or Russian
            constr = layout.get_next_constraints()
            self.genre_button = self.factory.create_button(
                IMAGE_BOOK_GENRE,
                KEY_ROOT,
                constr,
                listeners[GO_TO_PARENT],
                bgr,
                image_size_percent=image_size)
            self.add_component(self.genre_button)
            self.menu_buttons.append(self.genre_button)

        constr = layout.get_next_constraints()
        self.player_button = self.factory.create_button(
            IMAGE_PLAYER,
            KEY_PLAY_PAUSE,
            constr,
            listeners[GO_PLAYER],
            bgr,
            source=BOOK_NAVIGATOR,
            image_size_percent=image_size)
        self.add_component(self.player_button)
        self.menu_buttons.append(self.player_button)

        constr = layout.get_next_constraints()
        self.back_button = self.factory.create_button(
            KEY_BACK,
            KEY_BACK,
            constr,
            None,
            bgr,
            source=BOOK_NAVIGATOR_BACK,
            image_size_percent=image_size)
        self.back_button.add_release_listener(listeners[GO_BACK])
        try:
            self.back_button.add_release_listener(listeners[KEY_PLAY_FILE])
        except:
            pass
        self.add_component(self.back_button)
        self.menu_buttons.append(self.back_button)
Esempio n. 10
0
    def __init__(self, util, listener):
        """ Initializer
        
        :param util: utility object
        :Param listener: screen listener
        """
        self.name = KEY_INFO
        self.util = util
        self.config = util.config
        self.factory = Factory(util)
        self.listener = listener

        self.bg = self.util.get_background(self.name)
        self.bgr_type = self.bg[0]
        self.bgr = self.bg[1]
        self.bgr_key = self.bg[5]

        self.screen_w = self.config[SCREEN_INFO][WIDTH]
        self.screen_h = self.config[SCREEN_INFO][HEIGHT]
        self.lines = 14
        font_vertical_percent = 6
        self.bounding_box = util.screen_rect
        Container.__init__(self,
                           util,
                           self.bounding_box,
                           background=self.bg[1],
                           content=self.bg[2],
                           image_filename=self.bg[3])

        font_size = int((font_vertical_percent * self.bounding_box.h) / 100)
        self.f = util.get_font(font_size)

        center_layout = BorderLayout(self.bounding_box)
        center_layout.set_percent_constraints(0, 0, 44, 0)

        left_layout = center_layout.LEFT
        right_layout = center_layout.CENTER

        label_layout = GridLayout(left_layout)
        label_layout.set_pixel_constraints(self.lines, 1)
        label_layout.get_next_constraints()
        bb1 = label_layout.get_next_constraints()

        value_layout = GridLayout(right_layout)
        value_layout.set_pixel_constraints(self.lines, 1)
        value_layout.get_next_constraints()
        bb2 = value_layout.get_next_constraints()

        title_bb = pygame.Rect(bb1.x, bb1.y, bb1.w + bb2.w, bb1.h)
        self.title = self.add_title(title_bb)

        label_layout.get_next_constraints()
        self.add_label(label_layout, 1, self.config[LABELS]["file.size"] + ":")
        self.add_label(label_layout, 2,
                       self.config[LABELS]["sample.rate"] + ":")
        self.add_label(label_layout, 3, self.config[LABELS]["channels"] + ":")
        self.add_label(label_layout, 4,
                       self.config[LABELS]["bits.per.sample"] + ":")
        self.add_label(label_layout, 5, self.config[LABELS]["bit.rate"] + ":")

        label_layout.get_next_constraints()
        self.add_label(label_layout, 6, self.config[LABELS][GENRE] + ":")
        self.add_label(label_layout, 7, self.config[LABELS][ARTIST] + ":")
        self.add_label(label_layout, 8, self.config[LABELS][ALBUM] + ":")
        self.add_label(label_layout, 9, self.config[LABELS][DATE] + ":")

        value_layout.get_next_constraints()
        self.filesize = self.add_value(value_layout, 1)
        self.sample_rate = self.add_value(value_layout, 2)
        self.channels = self.add_value(value_layout, 3)
        self.bits = self.add_value(value_layout, 4)
        self.bit_rate = self.add_value(value_layout, 5)

        value_layout.get_next_constraints()
        self.genre = self.add_value(value_layout, 6)
        self.artist = self.add_value(value_layout, 7)
        self.album = self.add_value(value_layout, 8)
        self.date = self.add_value(value_layout, 9)

        self.values = [
            self.filesize, self.sample_rate, self.channels, self.bits,
            self.bit_rate, self.genre, self.artist, self.album, self.date
        ]
Esempio n. 11
0
    def __init__(self, util, bounding_box, listeners, bgr, pages):
        """ Initializer
        
        :param util: utility object
        :param bounding_box: bounding box
        :param listeners: buttons listeners
        :param bgr: menu background        
        """
        Container.__init__(self, util)
        self.factory = Factory(util)
        self.name = "navigator"
        self.content = bounding_box
        self.content_x = bounding_box.x
        self.content_y = bounding_box.y
        self.menu_buttons = []

        arrow_layout = BorderLayout(bounding_box)
        arrow_layout.set_percent_constraints(0, 0, PERCENT_ARROW_WIDTH,
                                             PERCENT_ARROW_WIDTH)

        if pages > 1:
            constr = arrow_layout.LEFT
            self.left_button = self.factory.create_page_down_button(
                constr, "0", 40, 100)
            self.left_button.add_release_listener(listeners[GO_LEFT_PAGE])
            self.add_component(self.left_button)
            self.menu_buttons.append(self.left_button)

            constr = arrow_layout.RIGHT
            self.right_button = self.factory.create_page_up_button(
                constr, "0", 40, 100)
            self.right_button.add_release_listener(listeners[GO_RIGHT_PAGE])
            self.add_component(self.right_button)
            self.menu_buttons.append(self.right_button)

        if pages > 1:
            layout = GridLayout(arrow_layout.CENTER)
        else:
            layout = GridLayout(bounding_box)

        layout.set_pixel_constraints(1, 2, 1, 0)
        layout.current_constraints = 0
        image_size = 64

        constr = layout.get_next_constraints()
        self.home_button = self.factory.create_button(
            KEY_HOME,
            KEY_HOME,
            constr,
            listeners[KEY_HOME],
            bgr,
            image_size_percent=image_size)
        self.add_component(self.home_button)
        self.menu_buttons.append(self.home_button)

        constr = layout.get_next_constraints()
        self.player_button = self.factory.create_button(
            KEY_PLAYER,
            KEY_PLAY_PAUSE,
            constr,
            listeners[KEY_PLAYER],
            bgr,
            image_size_percent=image_size)
        self.add_component(self.player_button)
        self.menu_buttons.append(self.player_button)
Esempio n. 12
0
class TimerScreen(Screen):
    """ Timer Screen """
    def __init__(self, util, listeners, voice_assistant, timer_lock,
                 start_timer_thread):
        """ Initializer

        :param util: utility object
        :param listeners: screen navigator listeners
        :param voice_assistant: voice assistant
        :param timer_lock: lock object
        :param start_timer_thread: start timer thread function
        """
        self.util = util
        self.timer_lock = timer_lock
        self.start_timer_thread = start_timer_thread
        self.config = util.config
        self.screen_layout = BorderLayout(util.screen_rect)
        self.screen_layout.set_percent_constraints(PERCENT_TITLE,
                                                   PERCENT_NAV_HEIGHT, 0, 0)
        Screen.__init__(self,
                        util,
                        "",
                        PERCENT_NAV_HEIGHT,
                        voice_assistant,
                        "timer_title",
                        title_layout=self.screen_layout.TOP)
        self.bounding_box = util.screen_rect
        label = self.config[LABELS][TIMER]
        self.screen_title.set_text(label)

        try:
            self.config[TIMER]
        except:
            self.config[TIMER] = {}

        c = GridLayout(self.screen_layout.CENTER)
        c.set_pixel_constraints(2, 1)
        layout = BorderLayout(c.get_next_constraints())
        layout.set_percent_constraints(0, 0, PERCENT_CLOCK,
                                       100 - PERCENT_CLOCK)
        gap = layout.h * 0.1
        layout.LEFT.w -= gap * 3
        layout.LEFT.h -= gap
        digits = util.image_util.get_flipclock_digits(layout.LEFT)

        change_codes = [
            HOURS_INCREMENT_SLEEP, MINUTES_INCREMENT_SLEEP,
            HOURS_DECREMENT_SLEEP, MINUTES_DECREMENT_SLEEP
        ]
        self.sleep_menu = SleepMenu(util, layout, gap, digits,
                                    self.handle_button, timer_lock,
                                    self.sleep_change_callback, change_codes)
        self.active_key_menu = self.sleep_menu
        self.add_component(self.sleep_menu)
        self.menu_index = -1
        self.sleep_menu.clock.add_change_listener(self.handle_clock_change)

        layout = BorderLayout(c.get_next_constraints())
        layout.set_percent_constraints(0, 0, PERCENT_CLOCK,
                                       100 - PERCENT_CLOCK)

        change_codes = [
            HOURS_INCREMENT_WAKE_UP, MINUTES_INCREMENT_WAKE_UP,
            HOURS_DECREMENT_WAKE_UP, MINUTES_DECREMENT_WAKE_UP
        ]
        self.wake_up_menu = WakeUpMenu(util, layout, gap, digits,
                                       self.handle_button, timer_lock,
                                       self.wake_up_change_callback,
                                       change_codes)
        self.add_component(self.wake_up_menu)
        self.wake_up_menu.clock.add_change_listener(self.handle_clock_change)

        self.navigator = TimerNavigator(self.util, self.screen_layout.BOTTOM,
                                        listeners)
        self.navigator.components[0].set_selected(True)
        self.add_component(self.navigator)
        self.home_button = self.navigator.get_button_by_name(KEY_HOME)
        self.sleep_now_button = self.navigator.get_button_by_name(SLEEP_NOW)
        self.player_button = self.navigator.get_button_by_name(KEY_PLAYER)

        self.menu_functions = {
            HOURS_INCREMENT_SLEEP: self.sleep_menu.clock.increment_hours,
            MINUTES_INCREMENT_SLEEP: self.sleep_menu.clock.increment_minutes,
            HOURS_DECREMENT_SLEEP: self.sleep_menu.clock.decrement_hours,
            MINUTES_DECREMENT_SLEEP: self.sleep_menu.clock.decrement_minutes,
            HOURS_INCREMENT_WAKE_UP: self.wake_up_menu.clock.increment_hours,
            MINUTES_INCREMENT_WAKE_UP:
            self.wake_up_menu.clock.increment_minutes,
            HOURS_DECREMENT_WAKE_UP: self.wake_up_menu.clock.decrement_hours,
            MINUTES_DECREMENT_WAKE_UP:
            self.wake_up_menu.clock.decrement_minutes
        }

        self.current_button = None
        self.link_borders()
        self.clean_draw_update()

    def link_borders(self):
        """ Link components borders for the arrow keys navigation """

        margin = 10
        self.enter_naviagtor_x = self.navigator.components[
            0].bounding_box.x + margin
        self.enter_naviagtor_y = self.navigator.components[
            0].bounding_box.y + margin
        self.exit_naviagtor_x = self.navigator.components[
            2].bounding_box.x + margin
        self.exit_naviagtor_y = self.navigator.components[
            2].bounding_box.y + margin
        self.enter_poweroff_x = self.sleep_menu.poweroff_button.bounding_box.x + margin
        self.enter_poweroff_y = self.sleep_menu.poweroff_button.bounding_box.y + margin
        self.enter_sleep_x = self.sleep_menu.sleep_button.bounding_box.x + margin
        self.enter_sleep_y = self.sleep_menu.sleep_button.bounding_box.y + margin
        self.enter_wake_up_x = self.wake_up_menu.button.bounding_box.x + margin
        self.enter_wake_up_y = self.wake_up_menu.button.bounding_box.y + margin

        self.exit_sleep_x = self.sleep_menu.bounding_box.x + self.sleep_menu.bounding_box.w + margin
        self.exit_sleep_incr_y = self.sleep_menu.bounding_box.y + margin
        self.exit_sleep_decr_y = self.sleep_menu.bounding_box.y + self.sleep_menu.bounding_box.h - margin

        self.exit_wake_up_x = self.wake_up_menu.bounding_box.x + self.wake_up_menu.bounding_box.w + margin
        self.exit_wake_up_y = self.wake_up_menu.bounding_box.y + margin

        self.exit_sleep_top_hour_x = self.exit_wake_up_bottom_hour_x = self.sleep_menu.clock.h1.bounding_box.x + self.sleep_menu.clock.h1.bounding_box.w
        self.exit_sleep_top_min_x = self.exit_wake_up_bottom_min_x = self.sleep_menu.clock.m1.bounding_box.x + self.sleep_menu.clock.m1.bounding_box.w
        self.exit_wake_up_bottom_y = self.wake_up_menu.bounding_box.y + self.wake_up_menu.bounding_box.h + margin

        self.sleep_menu.sleep_button.exit_top_y = self.screen_layout.BOTTOM.y + margin
        self.sleep_menu.sleep_button.exit_bottom_y = self.sleep_menu.poweroff_button.bounding_box.y + margin
        self.sleep_menu.sleep_button.exit_left_x = self.sleep_menu.clock.m2.top.x + self.sleep_menu.clock.m2.top.w - margin
        self.sleep_menu.sleep_button.exit_right_x = self.sleep_menu.clock.h1.top.x + margin
        self.sleep_menu.sleep_button.exit_right_y = self.sleep_menu.clock.h1.bottom.y + margin

        self.sleep_menu.poweroff_button.exit_top_y = self.sleep_menu.sleep_button.bounding_box.y + self.sleep_menu.sleep_button.bounding_box.h - margin
        self.sleep_menu.poweroff_button.exit_bottom_y = self.wake_up_menu.button.bounding_box.y + margin
        self.sleep_menu.poweroff_button.exit_left_x = self.sleep_menu.clock.m2.bottom.x + self.sleep_menu.clock.m2.bottom.w - margin
        self.sleep_menu.poweroff_button.exit_right_x = self.sleep_menu.clock.h1.bottom.x + margin
        self.sleep_menu.poweroff_button.exit_right_y = self.wake_up_menu.clock.h1.top.y + margin

        self.wake_up_menu.button.exit_top_y = self.sleep_menu.poweroff_button.bounding_box.y + self.sleep_menu.poweroff_button.bounding_box.h - margin
        self.wake_up_menu.button.exit_bottom_y = self.screen_layout.BOTTOM.y + margin
        self.wake_up_menu.button.exit_left_x = self.wake_up_menu.clock.m2.top.x + margin
        self.wake_up_menu.button.exit_left_y = self.wake_up_menu.clock.m2.top.y + margin
        self.wake_up_menu.button.exit_right_x = self.wake_up_menu.clock.h1.bottom.x + margin
        self.wake_up_menu.button.exit_right_y = self.wake_up_menu.clock.h1.bottom.y + margin

        for index, comp in enumerate(self.navigator.components):
            comp.exit_top_y = self.wake_up_menu.clock.h1.bounding_box.y + self.wake_up_menu.clock.h1.bounding_box.h - margin
            comp.exit_bottom_y = self.sleep_menu.clock.h1.bounding_box.y + margin
            if index == 0:
                comp.exit_left_x = self.wake_up_menu.clock.m2.bottom.x + margin
                comp.exit_left_y = self.wake_up_menu.clock.m2.bottom.y + margin
                comp.exit_right_x = self.sleep_now_button.bounding_box.x + margin
            elif index == 1:
                comp.exit_left_x = self.home_button.bounding_box.x + margin
                comp.exit_right_x = self.player_button.bounding_box.x + margin
            elif index == 2:
                comp.exit_left_x = self.sleep_now_button.bounding_box.x + margin
                comp.exit_right_x = self.sleep_menu.clock.h1.top.x + margin
                comp.exit_right_y = self.sleep_menu.clock.h1.top.y + margin

    def set_parent_screen(self, scr):
        """ Add parent screen

        :param scr: parent screen
        """
        self.sleep_menu.set_parent_screen(scr)
        self.wake_up_menu.set_parent_screen(scr)
        self.navigator.set_parent_screen(scr)

    def sleep_change_callback(self):
        """ Callback for sleep menu  """

        if self.active_key_menu != self.sleep_menu:
            self.wake_up_menu.clock.reset_key()
            self.active_key_menu = self.sleep_menu
        self.unselect_sleep_buttons()

    def wake_up_change_callback(self):
        """ Callback for wake up menu  """

        if self.active_key_menu != self.wake_up_menu:
            self.sleep_menu.clock.reset_key()
            self.active_key_menu = self.wake_up_menu
        self.unselect_wake_up()

    def handle_event(self, event):
        """ Handle screen event

        :param event: the event to handle
        """
        if not self.visible or event.type == pygame.MOUSEMOTION:
            return

        mouse_events = [pygame.MOUSEBUTTONUP, pygame.MOUSEBUTTONDOWN]

        if event.type in mouse_events:
            self.handle_mouse_event(event)
            return

        if event.type == SELECT_EVENT_TYPE:
            self.handle_select_action(event)
            return

        if not (event.type == USER_EVENT_TYPE and event.sub_type
                == SUB_TYPE_KEYBOARD and event.action == pygame.KEYUP):
            Container.handle_event(self, event)
            return

        keys = [
            kbd_keys[KEY_SELECT], kbd_keys[KEY_LEFT], kbd_keys[KEY_RIGHT],
            kbd_keys[KEY_UP], kbd_keys[KEY_DOWN]
        ]
        if event.keyboard_key in keys and self.menu_index == -1:
            if self.current_button == self.sleep_menu.sleep_button:
                self.sleep_menu.sleep_button.handle_event(event)
                if self.config[TIMER][SLEEP]:
                    self.sleep_menu.sleep_button.set_selected(True)
                    self.sleep_menu.sleep_button.clean_draw_update()
                else:
                    if event.keyboard_key == kbd_keys[KEY_SELECT]:
                        self.select_home()
            elif self.current_button == self.sleep_menu.poweroff_button:
                self.sleep_menu.poweroff_button.handle_event(event)
                if self.config[TIMER][POWEROFF]:
                    self.sleep_menu.poweroff_button.set_selected(True)
                    self.sleep_menu.poweroff_button.clean_draw_update()
                else:
                    if event.keyboard_key == kbd_keys[KEY_SELECT]:
                        self.select_home()
            elif self.current_button == self.wake_up_menu.button:
                self.wake_up_menu.button.handle_event(event)
                if self.config[TIMER][WAKE_UP]:
                    self.wake_up_menu.button.set_selected(True)
                    self.wake_up_menu.button.clean_draw_update()
                else:
                    if event.keyboard_key == kbd_keys[KEY_SELECT]:
                        self.select_home()
            else:
                self.navigator.handle_event(event)
            return

        if event.keyboard_key == kbd_keys[KEY_SELECT]:
            self.menu_functions[self.menu_index]()
        elif event.keyboard_key == kbd_keys[KEY_RIGHT]:
            if self.menu_index == MINUTES_INCREMENT_WAKE_UP:
                self.wake_up_menu.clock.reset_key()
                self.menu_index = -1
                self.util.post_exit_event(self.enter_wake_up_x,
                                          self.enter_wake_up_y,
                                          self.wake_up_menu)
            elif self.menu_index == MINUTES_DECREMENT_WAKE_UP:
                self.wake_up_menu.clock.reset_key()
                self.menu_index = -1
                self.util.post_exit_event(self.enter_naviagtor_x,
                                          self.enter_naviagtor_y,
                                          self.wake_up_menu)
            elif self.menu_index == MINUTES_INCREMENT_SLEEP:
                self.sleep_menu.clock.reset_key()
                self.menu_index = -1
                self.util.post_exit_event(self.exit_sleep_x,
                                          self.exit_sleep_incr_y,
                                          self.sleep_menu)
            elif self.menu_index == MINUTES_DECREMENT_SLEEP:
                self.sleep_menu.clock.reset_key()
                self.menu_index = -1
                self.util.post_exit_event(self.exit_sleep_x,
                                          self.exit_sleep_decr_y,
                                          self.sleep_menu)
            else:
                self.menu_index += 1
                self.wake_up_menu.clock.set_key_position(self.menu_index)
                self.sleep_menu.clock.set_key_position(self.menu_index)
        elif event.keyboard_key == kbd_keys[KEY_LEFT]:
            if self.menu_index == HOURS_INCREMENT_WAKE_UP:
                self.wake_up_menu.clock.reset_key()
                self.menu_index = -1
                self.util.post_exit_event(self.enter_poweroff_x,
                                          self.enter_poweroff_y,
                                          self.wake_up_menu)
            elif self.menu_index == HOURS_DECREMENT_WAKE_UP:
                self.wake_up_menu.clock.reset_key()
                self.menu_index = -1
                self.util.post_exit_event(self.exit_wake_up_x,
                                          self.exit_wake_up_y,
                                          self.wake_up_menu)
            elif self.menu_index == HOURS_INCREMENT_SLEEP:
                self.sleep_menu.clock.reset_key()
                self.menu_index = -1
                self.util.post_exit_event(self.exit_naviagtor_x,
                                          self.exit_naviagtor_y,
                                          self.sleep_menu)
            elif self.menu_index == HOURS_DECREMENT_SLEEP:
                self.sleep_menu.clock.reset_key()
                self.menu_index = -1
                self.util.post_exit_event(self.enter_sleep_x,
                                          self.enter_sleep_y, self.sleep_menu)
            else:
                self.menu_index -= 1
                self.wake_up_menu.clock.set_key_position(self.menu_index)
                self.sleep_menu.clock.set_key_position(self.menu_index)
        elif event.keyboard_key == kbd_keys[KEY_UP]:
            if self.menu_index == HOURS_INCREMENT_SLEEP:
                self.sleep_menu.clock.reset_key()
                self.menu_index = -1
                self.util.post_exit_event(self.exit_sleep_top_hour_x,
                                          self.exit_wake_up_bottom_y,
                                          self.sleep_menu)
            elif self.menu_index == MINUTES_INCREMENT_SLEEP:
                self.sleep_menu.clock.reset_key()
                self.menu_index = -1
                self.util.post_exit_event(self.exit_sleep_top_min_x,
                                          self.exit_wake_up_bottom_y,
                                          self.sleep_menu)
            elif self.menu_index == HOURS_DECREMENT_SLEEP:
                self.handle_up_down(HOURS_INCREMENT_SLEEP, self.sleep_menu)
            elif self.menu_index == MINUTES_DECREMENT_SLEEP:
                self.handle_up_down(MINUTES_INCREMENT_SLEEP, self.sleep_menu)
            elif self.menu_index == HOURS_INCREMENT_WAKE_UP:
                self.handle_up_down(HOURS_DECREMENT_SLEEP, self.sleep_menu,
                                    self.wake_up_menu, self.sleep_menu)
            elif self.menu_index == MINUTES_INCREMENT_WAKE_UP:
                self.handle_up_down(MINUTES_DECREMENT_SLEEP, self.sleep_menu,
                                    self.wake_up_menu, self.sleep_menu)
            elif self.menu_index == HOURS_DECREMENT_WAKE_UP:
                self.handle_up_down(HOURS_INCREMENT_WAKE_UP, self.wake_up_menu)
            elif self.menu_index == MINUTES_DECREMENT_WAKE_UP:
                self.handle_up_down(MINUTES_INCREMENT_WAKE_UP,
                                    self.wake_up_menu)
        elif event.keyboard_key == kbd_keys[KEY_DOWN]:
            if self.menu_index == HOURS_INCREMENT_SLEEP:
                self.handle_up_down(HOURS_DECREMENT_SLEEP, self.sleep_menu)
            elif self.menu_index == MINUTES_INCREMENT_SLEEP:
                self.handle_up_down(MINUTES_DECREMENT_SLEEP, self.sleep_menu)
            elif self.menu_index == HOURS_DECREMENT_SLEEP:
                self.handle_up_down(HOURS_INCREMENT_WAKE_UP, self.wake_up_menu,
                                    self.sleep_menu, self.wake_up_menu)
            elif self.menu_index == MINUTES_DECREMENT_SLEEP:
                self.handle_up_down(MINUTES_INCREMENT_WAKE_UP,
                                    self.wake_up_menu, self.sleep_menu,
                                    self.wake_up_menu)
            elif self.menu_index == HOURS_INCREMENT_WAKE_UP:
                self.handle_up_down(HOURS_DECREMENT_WAKE_UP, self.wake_up_menu)
            elif self.menu_index == MINUTES_INCREMENT_WAKE_UP:
                self.handle_up_down(MINUTES_DECREMENT_WAKE_UP,
                                    self.wake_up_menu)
            elif self.menu_index == HOURS_DECREMENT_WAKE_UP:
                self.wake_up_menu.clock.reset_key()
                self.menu_index = -1
                self.util.post_exit_event(self.exit_wake_up_bottom_hour_x,
                                          self.exit_wake_up_bottom_y,
                                          self.wake_up_menu)
            elif self.menu_index == MINUTES_DECREMENT_WAKE_UP:
                self.wake_up_menu.clock.reset_key()
                self.menu_index = -1
                self.util.post_exit_event(self.exit_wake_up_bottom_min_x,
                                          self.exit_wake_up_bottom_y,
                                          self.wake_up_menu)
        else:
            Container.handle_event(self, event)

        if event.keyboard_key in keys and self.update_web_observer != None:
            self.update_web_observer()

    def select_home(self):
        """ Select home button """

        self.current_button = None
        self.home_button.set_selected(True)
        self.home_button.clean_draw_update()

    def handle_select_action(self, event):
        """ Handle select action

        :param event: the event
        """
        pos = (event.x - 3, event.y)
        if self.sleep_menu.clock.h1.top.collidepoint(
                pos) or self.sleep_menu.clock.h2.top.collidepoint(pos):
            self.handle_up_down(HOURS_INCREMENT_SLEEP, self.sleep_menu)
        elif self.sleep_menu.clock.m1.top.collidepoint(
                pos) or self.sleep_menu.clock.m2.top.collidepoint(pos):
            self.handle_up_down(MINUTES_INCREMENT_SLEEP, self.sleep_menu)
        elif self.sleep_menu.clock.h1.bottom.collidepoint(
                pos) or self.sleep_menu.clock.h2.bottom.collidepoint(pos):
            self.handle_up_down(HOURS_DECREMENT_SLEEP, self.sleep_menu)
        elif self.sleep_menu.clock.m1.bottom.collidepoint(
                pos) or self.sleep_menu.clock.m2.bottom.collidepoint(pos):
            self.handle_up_down(MINUTES_DECREMENT_SLEEP, self.sleep_menu)
        elif self.wake_up_menu.clock.h1.top.collidepoint(
                pos) or self.wake_up_menu.clock.h2.top.collidepoint(pos):
            self.handle_up_down(HOURS_INCREMENT_WAKE_UP, self.wake_up_menu)
        elif self.wake_up_menu.clock.m1.top.collidepoint(
                pos) or self.wake_up_menu.clock.m2.top.collidepoint(pos):
            self.handle_up_down(MINUTES_INCREMENT_WAKE_UP, self.wake_up_menu)
        elif self.wake_up_menu.clock.h1.bottom.collidepoint(
                pos) or self.wake_up_menu.clock.h2.bottom.collidepoint(pos):
            self.handle_up_down(HOURS_DECREMENT_WAKE_UP, self.wake_up_menu)
        elif self.wake_up_menu.clock.m1.bottom.collidepoint(
                pos) or self.wake_up_menu.clock.m2.bottom.collidepoint(pos):
            self.handle_up_down(MINUTES_DECREMENT_WAKE_UP, self.wake_up_menu)
        elif self.screen_layout.BOTTOM.collidepoint(pos):
            self.navigator.handle_event(event)
            for c in self.navigator.components:
                if c.selected:
                    self.current_button = c
        elif self.sleep_menu.sleep_button.bounding_box.collidepoint(pos):
            self.sleep_menu.sleep_button.handle_event(event)
            self.current_button = self.sleep_menu.sleep_button
        elif self.sleep_menu.poweroff_button.bounding_box.collidepoint(pos):
            self.sleep_menu.poweroff_button.handle_event(event)
            self.current_button = self.sleep_menu.poweroff_button
        elif self.wake_up_menu.button.bounding_box.collidepoint(pos):
            self.wake_up_menu.button.handle_event(event)
            self.current_button = self.wake_up_menu.button

        self.update_web_observer()

    def handle_mouse_event(self, event):
        """ Handle mouse event

        :param event: the event
        """
        event_component = None

        for comp in self.sleep_menu.components:
            bb = comp.bounding_box
            if bb.collidepoint(event.pos):
                event_component = comp
                if comp == self.sleep_menu.sleep_button or comp == self.sleep_menu.poweroff_button:
                    if comp == self.sleep_menu.sleep_button:
                        self.current_button = self.sleep_menu.sleep_button
                    elif comp == self.sleep_menu.poweroff_button:
                        self.current_button = self.sleep_menu.poweroff_button
                    self.sleep_menu.clock.reset_key()
                    self.wake_up_menu.clock.reset_key()
                break

        for comp in self.wake_up_menu.components:
            bb = comp.bounding_box
            if bb.collidepoint(event.pos):
                event_component = comp
                if comp == self.wake_up_menu.button:
                    self.current_button = self.wake_up_menu.button
                    self.sleep_menu.clock.reset_key()
                    self.wake_up_menu.clock.reset_key()
                    self.menu_index = -1
                break

        if event_component:
            self.navigator.unselect()
            event_component.handle_event(event)
            return

        for comp in self.navigator.components:
            if getattr(comp, "state", None):
                bb = comp.state.bounding_box
            else:
                bb = comp.bounding_box

            if bb == None:
                continue

            if bb.collidepoint(event.pos):
                event_component = comp
                break

        if event_component:
            self.sleep_menu.clock.reset_key()
            self.wake_up_menu.clock.reset_key()
            self.menu_index = -1
            self.navigator.unselect()
            event_component.handle_event(event)

    def handle_up_down(self,
                       position,
                       set_menu,
                       reset_menu=None,
                       active_menu=None):
        """ Handle up and down keys

        :param position: key position
        :param set_menu: menu to set key position
        :param reset_menu: menu to reset
        :param active_menu:  active menu
        """
        if reset_menu != None:
            reset_menu.clock.reset_key()

        if active_menu != None:
            self.active_key_menu = active_menu

        set_menu.clock.set_key_position(position)
        self.menu_index = position

    def handle_clock_change(self, change_code):
        """ Clock change handler

        :param change_code: change code
        """
        if change_code == HOURS_INCREMENT_SLEEP:
            self.menu_index = HOURS_INCREMENT_SLEEP
        elif change_code == MINUTES_INCREMENT_SLEEP:
            self.menu_index = MINUTES_INCREMENT_SLEEP
        elif change_code == HOURS_DECREMENT_SLEEP:
            self.menu_index = HOURS_DECREMENT_SLEEP
        elif change_code == MINUTES_DECREMENT_SLEEP:
            self.menu_index = MINUTES_DECREMENT_SLEEP
        elif change_code == HOURS_INCREMENT_WAKE_UP:
            self.menu_index = HOURS_INCREMENT_WAKE_UP
        elif change_code == MINUTES_INCREMENT_WAKE_UP:
            self.menu_index = MINUTES_INCREMENT_WAKE_UP
        elif change_code == HOURS_DECREMENT_WAKE_UP:
            self.menu_index = HOURS_DECREMENT_WAKE_UP
        elif change_code == MINUTES_DECREMENT_WAKE_UP:
            self.menu_index = MINUTES_DECREMENT_WAKE_UP

    def handle_button(self, state):
        """ Button event handler

        :param state: button state
        """
        button = state.event_origin
        name = button.state.name

        if name == SLEEP:
            self.handle_sleep_button(button)
        elif name == POWEROFF:
            self.handle_poweroff_button(button)
        elif name == WAKE_UP:
            self.handle_wake_up_button(button)

    def handle_sleep_button(self, button):
        """ Sleep button handler

        :button: sleep button
        """
        if self.sleep_menu.sleep_selected:
            button.set_selected(False)
            with self.timer_lock:
                self.config[TIMER][SLEEP] = False
            self.sleep_menu.sleep_selected = False
            if self.wake_up_menu.button_selected:
                self.unselect_wake_up()
        else:
            button.set_selected(True)
            with self.timer_lock:
                self.config[TIMER][SLEEP] = True
                self.config[TIMER][POWEROFF] = False
            self.sleep_menu.sleep_selected = True
            self.sleep_menu.poweroff_selected = False
            self.sleep_menu.poweroff_button.set_selected(False)
            self.sleep_menu.poweroff_button.clean_draw_update()
            self.start_timer_thread()
        button.clean_draw_update()

    def handle_poweroff_button(self, button):
        """ Poweroff button handler

        :button: poweroff button
        """
        if self.sleep_menu.poweroff_selected:
            button.set_selected(False)
            with self.timer_lock:
                self.config[TIMER][POWEROFF] = False
            self.sleep_menu.poweroff_selected = False
        else:
            button.set_selected(True)
            with self.timer_lock:
                self.config[TIMER][POWEROFF] = True
                self.config[TIMER][SLEEP] = False
            self.sleep_menu.poweroff_selected = True
            self.sleep_menu.sleep_selected = False
            self.sleep_menu.sleep_button.set_selected(False)
            self.sleep_menu.sleep_button.clean_draw_update()
            if self.wake_up_menu.button_selected:
                self.unselect_wake_up()
            self.start_timer_thread()
        button.clean_draw_update()

    def handle_wake_up_button(self, button):
        """ Wake up button handler

        :button: wake up button
        """
        if self.wake_up_menu.button_selected:
            self.unselect_wake_up()
        else:
            button.set_selected(True)
            with self.timer_lock:
                self.config[TIMER][WAKE_UP] = True
            self.wake_up_menu.button_selected = True
            self.wake_up_menu.button.clean_draw_update()

    def unselect_sleep_buttons(self):
        """ Unselect sleep and poweroff buttons """

        with self.timer_lock:
            self.config[TIMER][SLEEP] = False
            self.config[TIMER][POWEROFF] = False
            self.sleep_menu.sleep_button.set_selected(False)
            self.sleep_menu.poweroff_button.set_selected(False)
            self.sleep_menu.sleep_selected = False
            self.sleep_menu.poweroff_selected = False
            self.sleep_menu.sleep_button.clean_draw_update()
            self.sleep_menu.poweroff_button.clean_draw_update()

    def unselect_wake_up(self):
        """ Unselect wake up button """

        self.wake_up_menu.button.set_selected(False)
        with self.timer_lock:
            self.config[TIMER][WAKE_UP] = False
        self.wake_up_menu.button_selected = False
        self.wake_up_menu.button.clean_draw_update()

    def add_screen_observers(self, update_observer, redraw_observer):
        """ Add screen observers

        :param update_observer: observer for updating the screen
        :param redraw_observer: observer to redraw the whole screen
        """
        Screen.add_screen_observers(self, update_observer, redraw_observer)
        self.sleep_menu.add_menu_observers(update_observer, redraw_observer)
        self.wake_up_menu.add_menu_observers(update_observer, redraw_observer)
        self.navigator.add_observers(update_observer, redraw_observer)
Esempio n. 13
0
 def __init__(self, util, get_current_playlist, playlist_provider, listeners, voice_assistant):
     """ Initializer
     
     :param util: utility object
     :param listeners: file browser listeners
     """
     self.util = util
     self.config = util.config
     self.factory = Factory(util)
     self.bounding_box = util.screen_rect
     layout = BorderLayout(self.bounding_box)
     layout.set_percent_constraints(PERCENT_TOP_HEIGHT, PERCENT_BOTTOM_HEIGHT, 0, 0)
     Screen.__init__(self, util, "", PERCENT_TOP_HEIGHT, voice_assistant, "file_browser_screen_title", True, layout.TOP)
     color_dark_light = self.config[COLORS][COLOR_DARK_LIGHT]
     current_folder = self.util.file_util.current_folder  
     d = {"current_title" : current_folder}
     
     if self.config[FILE_PLAYBACK][CURRENT_FILE_PLAYBACK_MODE] == FILE_PLAYLIST:
         f = self.config[FILE_PLAYBACK][CURRENT_FOLDER]
         p = self.config[FILE_PLAYBACK][CURRENT_FILE_PLAYLIST]
         d = f + os.sep + p
     
     self.screen_title.set_text(d)
     
     rows = self.config[FILE_BROWSER_ROWS]
     columns = self.config[FILE_BROWSER_COLUMNS]
     self.filelist = None
     playback_mode = self.config[FILE_PLAYBACK][CURRENT_FILE_PLAYBACK_MODE]
     
     if not playback_mode:
         self.config[FILE_PLAYBACK][CURRENT_FILE_PLAYBACK_MODE] = playback_mode = FILE_AUDIO
     
     if playback_mode == FILE_AUDIO or playback_mode == FILE_RECURSIVE:
         folder_content = self.util.load_folder_content(current_folder, rows, columns, layout.CENTER)  
         self.filelist = Page(folder_content, rows, columns)
     elif playback_mode == FILE_PLAYLIST:
         s = State()
         s.folder = self.config[FILE_PLAYBACK][CURRENT_FOLDER]
         s.music_folder = self.config[AUDIO][MUSIC_FOLDER]
         s.file_name = self.config[FILE_PLAYBACK][CURRENT_FILE_PLAYLIST]
         
         pl = self.get_filelist_items(get_current_playlist)
         if len(pl) == 0:            
             pl = self.util.load_playlist(s, playlist_provider, rows, columns)
         else:
             pl = self.util.load_playlist_content(pl, rows, columns)
         self.filelist = Page(pl, rows, columns)
     
     self.file_menu = FileMenu(self.filelist, util, playlist_provider, (0, 0, 0), layout.CENTER, self.config[ALIGN_BUTTON_CONTENT_X])
     
     Container.add_component(self, self.file_menu)
     self.file_menu.add_change_folder_listener(self.screen_title.set_text)
     self.file_menu.add_play_file_listener(listeners[KEY_PLAY_FILE])
     
     listeners[GO_LEFT_PAGE] = self.file_menu.page_down
     listeners[GO_RIGHT_PAGE] = self.file_menu.page_up
     listeners[GO_USER_HOME] = self.file_menu.switch_to_user_home
     listeners[GO_ROOT] = self.file_menu.switch_to_root
     listeners[GO_TO_PARENT] = self.file_menu.switch_to_parent_folder
     
     self.navigator = Navigator(util, layout.BOTTOM, listeners, color_dark_light)
     left = str(self.filelist.get_left_items_number())
     right = str(self.filelist.get_right_items_number())
     self.navigator.left_button.change_label(left)
     self.navigator.right_button.change_label(right)
     
     self.file_menu.add_left_number_listener(self.navigator.left_button.change_label)
     self.file_menu.add_right_number_listener(self.navigator.right_button.change_label)
     Container.add_component(self, self.navigator)
     self.page_turned = False
     self.animated_title = True   
Esempio n. 14
0
class MenuScreen(Screen):
    """ Site Menu Screen. Base class for all book menu screens """
    def __init__(self,
                 util,
                 listeners,
                 rows,
                 columns,
                 voice_assistant,
                 d=None,
                 turn_page=None,
                 page_in_title=True):
        """ Initializer
        
        :param util: utility object
        :param listeners: file browser listeners
        :param rows: menu rows
        :param d: dictionary with menu button flags
        :param turn_page: turn page callback
        :param util: utility object
        """
        self.util = util
        self.config = util.config
        self.factory = Factory(util)
        self.bounding_box = self.config[SCREEN_RECT]
        self.player = None
        self.turn_page = turn_page
        self.page_in_title = page_in_title

        self.cache = Cache(self.util)
        self.layout = BorderLayout(self.bounding_box)
        self.layout.set_percent_constraints(PERCENT_TOP_HEIGHT,
                                            PERCENT_BOTTOM_HEIGHT, 0, 0)
        Screen.__init__(self, util, "", PERCENT_TOP_HEIGHT, voice_assistant,
                        "menu_screen_screen_title", True, self.layout.TOP)

        color_dark_light = self.config[COLORS][COLOR_DARK_LIGHT]
        self.menu_layout = self.layout.CENTER

        self.menu_button_layout = self.get_menu_button_layout(d)
        self.img_rect = self.menu_button_layout.image_rectangle

        listeners[GO_LEFT_PAGE] = self.previous_page
        listeners[GO_RIGHT_PAGE] = self.next_page

        try:
            self.navigator = BookNavigator(util, self.layout.BOTTOM, listeners,
                                           color_dark_light, d[4])
            Container.add_component(self, None)
            Container.add_component(self, self.navigator)
        except:
            Container.add_component(self, None)

        self.total_pages = 0
        self.current_page = 1
        self.menu = None

        self.loading_listeners = []
        self.LOADING = util.config[LABELS][KEY_LOADING]

    def get_menu_button_layout(self, d):
        """ Return menu button layout
        
        :param d: dictionary with menu button flags
        
        :return: menu button layout
        """
        s = State()
        s.show_img = True
        s.show_label = True
        button_w = int(self.menu_layout.w / d[1])
        button_h = int(self.menu_layout.h / d[0])
        label_padding = 2
        image_padding = 4
        try:
            self.show_author = d[2]
        except:
            self.show_author = False

        try:
            self.show_genre = d[3]
        except:
            self.show_genre = False

        s.bounding_box = Rect(0, 0, button_w, button_h)
        return MultiLineButtonLayout(s, label_padding, image_padding)

    def previous_page(self, state):
        """ Handle click on left button 
        
        :param state: button state object
        """
        if self.current_page == 1:
            return

        self.current_page -= 1
        if getattr(state, "select_last", False):
            self.components[1].selected_index = 0

        self.menu.current_page = self.current_page
        self.menu.selected_index = 0
        self.turn_page()

    def next_page(self, state):
        """ Handle click on right button 
        
        :param state: button state object
        """
        if self.total_pages <= 1 or self.total_pages == self.current_page:
            return

        self.current_page += 1

        if self.current_page > self.total_pages:
            self.current_page = self.total_pages

        self.menu.current_page = self.current_page
        self.menu.selected_index = 0
        self.turn_page()

    def set_menu(self, menu):
        """ Set menu 
        
        :param menu: menu object
        """
        self.menu = self.components[1] = menu

    def set_title(self, page_num):
        """ Set screen title 
        
        :param page_num: menu page number
        """
        if self.total_pages == 1 or not self.page_in_title:
            self.screen_title.set_text(self.title)
            return

        if len(str(page_num)) <= len(str(self.total_pages)):
            self.screen_title.set_text(self.title + " (" + str(page_num) + ")")

    def reset_title(self):
        """ Reset screen title """

        self.screen_title.set_text(self.title + " (" + str(self.current_page) +
                                   ")")

    def go_to_page(self, page_num):
        """ Handle go to page event 
        
        :param page_num: menu page number
        """
        n = int(page_num)
        if n > self.total_pages:
            n = self.total_pages
        if n == 0:
            n = 1
        self.current_page = n
        self.menu.current_page = self.current_page
        self.turn_page()

    def get_image_from_cache(self, url):
        """ Return image from cache
        
        :param url: image url
        
        :return: image
        """
        return self.cache.get_image(url)

    def put_image_to_cache(self, url, img):
        """ Put image into cache
        
        :param url: image url
        :param img: image
        """
        self.cache.cache_image(img, url)

    def set_button_image(self, b, icon, img_y=None):
        """ Set button image
        
        :param b: button
        :param icon: image
        :param img_y: image Y coordinate
        """
        bb = b.bounding_box
        comps = b.components
        im = comps[1]
        im.content = icon
        w = im.content.get_size()[0]
        h = im.content.get_size()[1]
        im.content_x = bb.x + (bb.width - w) / 2

        if img_y == None:
            img_area_height = bb.height - ((bb.height / LINES) * 2)
            img_y = bb.y + (img_area_height - h) / 2

        im.content_y = img_y
        self.components[1].clean_draw_update()

    def set_loading(self, name):
        """ Show Loading... sign
        
        :name: screen title
        """
        b = self.config[COLORS][COLOR_DARK]
        f = self.config[COLORS][COLOR_BRIGHT]
        fs = int(self.bounding_box.h * 0.07)
        bb = self.menu_layout
        t = self.factory.create_output_text(self.LOADING, bb, b, f, fs)
        t.set_text(self.LOADING)
        self.screen_title.set_text(name)
        self.set_visible(True)
        self.add_component(t)
        self.clean_draw_update()
        self.notify_loading_listeners()

    def reset_loading(self):
        """ Remove Loading... sign """

        del self.components[-1]
        self.notify_loading_listeners()

    def add_loading_listener(self, listener):
        """ Add loading listener
        
        :param listener: event listener
        """
        if listener not in self.loading_listeners:
            self.loading_listeners.append(listener)

    def notify_loading_listeners(self):
        """ Notify all loading listeners """

        for listener in self.loading_listeners:
            listener(None)
Esempio n. 15
0
class FilePlayerScreen(Screen):
    """ File Player Screen """
    def __init__(self,
                 listeners,
                 util,
                 get_current_playlist,
                 voice_assistant,
                 player_stop=None,
                 arrow_labels=True,
                 active_file_button=True,
                 show_time_control=True,
                 show_order=True,
                 show_info=True):
        """ Initializer
        
        :param listeners: screen listeners
        :param util: utility object
        :param get_current_playlist: current playlist getter
        :param voice_assistant:   voice assistant
        :param player_stop: stop player function
        """
        self.util = util
        self.config = util.config
        self.cdutil = CdUtil(util)
        self.factory = Factory(util)
        self.image_util = util.image_util

        self.top_height = self.config[PLAYER_SCREEN][TOP_HEIGHT_PERCENT]
        self.bottom_height = self.config[PLAYER_SCREEN][BOTTOM_HEIGHT_PERCENT]
        self.button_height = self.config[PLAYER_SCREEN][BUTTON_HEIGHT_PERCENT]
        self.popup_width = self.config[PLAYER_SCREEN][POPUP_WIDTH_PERCENT]
        self.image_location = self.config[PLAYER_SCREEN][IMAGE_LOCATION]

        self.stop_player = player_stop
        self.get_current_playlist = get_current_playlist
        self.show_time_control = show_time_control

        self.bounding_box = util.screen_rect
        self.layout = self.get_layout()

        self.voice_assistant = voice_assistant
        Screen.__init__(self, util, "", self.top_height, voice_assistant,
                        "file_player_screen_title", True, self.layout.TOP)
        self.layout = self.get_layout()

        self.create_left_panel(self.layout, listeners, arrow_labels)
        self.create_right_panel(self.layout, listeners, arrow_labels)

        if not active_file_button:
            listeners[AUDIO_FILES] = None

        self.file_button = self.factory.create_file_button(
            self.layout.CENTER, listeners[AUDIO_FILES])
        self.add_component(self.file_button)

        self.audio_files = self.get_audio_files()
        self.home_button.add_release_listener(listeners[KEY_HOME])
        self.shutdown_button.add_release_listener(listeners[KEY_SHUTDOWN])
        self.left_button.add_release_listener(self.go_left)
        self.right_button.add_release_listener(self.go_right)

        self.show_order = show_order
        self.show_info = show_info
        self.order_button = None
        self.info_button = None
        self.order_popup = None
        self.info_popup = None
        self.playback_order = self.config[PLAYER_SETTINGS][PLAYBACK_ORDER]
        self.bottom_center_layout = self.layout.BOTTOM

        if self.show_order or self.show_info:
            self.start_screensaver = listeners[SCREENSAVER]
            self.go_info_screen = listeners[KEY_INFO]
            self.add_popups()

        self.volume = self.factory.create_volume_control(
            self.bottom_center_layout)
        self.volume.add_slide_listener(
            self.get_listener(listeners, KEY_SET_VOLUME))
        self.volume.add_slide_listener(
            self.get_listener(listeners, KEY_SET_CONFIG_VOLUME))
        self.volume.add_slide_listener(
            self.get_listener(listeners, KEY_SET_SAVER_VOLUME))
        self.volume.add_knob_listener(self.get_listener(listeners, KEY_MUTE))
        self.volume_visible = False
        self.volume.set_visible(self.volume_visible)
        self.add_component(self.volume)

        if self.show_time_control:
            self.time_control = self.factory.create_time_control(
                self.bottom_center_layout)
            if KEY_SEEK in listeners.keys():
                self.time_control.add_seek_listener(listeners[KEY_SEEK])

            self.play_button.add_listener(PAUSE, self.time_control.pause)
            self.play_button.add_listener(KEY_PLAY, self.time_control.resume)

            if self.config[PLAYER_SETTINGS][PAUSE]:
                self.time_control.pause()
            self.add_component(self.time_control)

        self.left_button.add_release_listener(
            self.play_button.draw_default_state)
        self.right_button.add_release_listener(
            self.play_button.draw_default_state)

        self.play_listeners = []
        self.add_play_listener(self.get_listener(listeners, KEY_PLAY))

        self.current_folder = self.config[FILE_PLAYBACK][CURRENT_FOLDER]
        self.file_button.state.cover_art_folder = self.util.file_util.get_cover_art_folder(
            self.current_folder)
        self.playlist_size = 0
        self.player_screen = True
        self.cd_album = None
        self.animated_title = True

        if self.order_popup:
            Container.add_component(self, self.order_popup)

        if self.info_popup:
            Container.add_component(self, self.info_popup)

    def get_layout(self):
        """ Get the layout of the center area of the screen for image and buttons

        :return: layout rectangle
        """
        layout = BorderLayout(self.bounding_box)
        k = self.bounding_box.w / self.bounding_box.h
        percent_menu_width = (100.0 - self.top_height - self.bottom_height) / k
        panel_width = (100.0 - percent_menu_width) / 2.0

        if self.image_location == LOCATION_CENTER:
            layout.set_percent_constraints(self.top_height, self.bottom_height,
                                           panel_width, panel_width)
        elif self.image_location == LOCATION_LEFT:
            layout.set_percent_constraints(self.top_height, self.bottom_height,
                                           0, panel_width * 2)
        elif self.image_location == LOCATION_RIGHT:
            layout.set_percent_constraints(self.top_height, self.bottom_height,
                                           panel_width * 2, 0)

        return layout

    def get_panel_layout(self, layout, panel_location):
        """ Get the layout of the panel for buttons

        :param layout: layout of the whole central area
        :param panel_location: panel location: left or right

        :return: panel layout rectangle
        """
        if self.image_location == LOCATION_CENTER:
            if panel_location == LOCATION_LEFT:
                return BorderLayout(layout.LEFT)
            else:
                return BorderLayout(layout.RIGHT)
        elif self.image_location == LOCATION_LEFT:
            r = layout.RIGHT
            if panel_location == LOCATION_LEFT:
                return BorderLayout(Rect(r.x, r.y, r.w / 2, r.h))
            else:
                return BorderLayout(
                    Rect(r.x + r.w / 2 + 1, r.y, r.w / 2 - 1, r.h))
        elif self.image_location == LOCATION_RIGHT:
            r = layout.LEFT
            if panel_location == LOCATION_LEFT:
                return BorderLayout(Rect(r.x, r.y, r.w / 2, r.h))
            else:
                return BorderLayout(
                    Rect(r.x + r.w / 2 + 1, r.y, r.w / 2 - 1, r.h))

    def add_popups(self):
        """ Add popup menus: playback order & info """

        self.bottom_layout = BorderLayout(self.layout.BOTTOM)
        if self.show_order and not self.show_info:
            self.bottom_layout.set_percent_constraints(0, 0, self.popup_width,
                                                       0)
            self.order_button = self.factory.create_order_button(
                self.bottom_layout.LEFT, self.handle_order_button,
                self.playback_order)
            self.order_popup = self.get_order_popup(self.bounding_box)
            self.add_component(self.order_button)
        elif self.show_order and self.show_info:
            self.bottom_layout.set_percent_constraints(0, 0, self.popup_width,
                                                       self.popup_width)
            self.order_button = self.factory.create_order_button(
                self.bottom_layout.LEFT, self.handle_order_button,
                self.playback_order)
            self.info_button = self.factory.create_info_button(
                self.bottom_layout.RIGHT, self.handle_info_button)
            self.order_popup = self.get_order_popup(self.bounding_box)
            self.info_popup = self.get_info_popup(self.bounding_box)
            self.add_component(self.order_button)
            self.add_component(self.info_button)
        elif not self.show_order and self.show_info:
            self.bottom_layout.set_percent_constraints(0, 0, 0,
                                                       self.popup_width)
            self.info_button = self.factory.create_info_button(
                self.bottom_layout.RIGHT, self.handle_info_button)
            self.info_popup = self.get_info_popup(self.bounding_box)
            self.add_component(self.info_button)

        self.bottom_layout.CENTER.w -= 2
        self.bottom_layout.CENTER.x += 1
        self.bottom_center_layout = self.bottom_layout.CENTER

    def handle_order_button(self, state):
        """ Handle playback order button

        :param state: button state
        """
        self.order_popup.set_visible(True)
        self.clean_draw_update()

    def handle_info_button(self, state):
        """ Handle info button

        :param state: button state
        """
        self.info_popup.set_visible(True)
        self.clean_draw_update()

    def get_order_popup(self, bb):
        """ Create playback order popup menu

        :param bb: bounding box

        :return: popup menu
        """
        items = []
        items.append(PLAYBACK_CYCLIC)
        items.append(PLAYBACK_REGULAR)
        items.append(PLAYBACK_SINGLE_TRACK)
        items.append(PLAYBACK_SHUFFLE)
        items.append(PLAYBACK_SINGLE_CYCLIC)

        layout = BorderLayout(bb)
        layout.set_percent_constraints(self.top_height, 0, self.popup_width, 0)
        popup = Popup(items,
                      self.util,
                      layout.LEFT,
                      self.clean_draw_update,
                      self.handle_order_popup_selection,
                      default_selection=self.playback_order)
        self.left_button.add_label_listener(popup.update_popup)

        return popup

    def get_info_popup(self, bb):
        """ Create info popup menu

        :param bb: bounding box

        :return: popup menu
        """
        items = []
        mode = self.config[CURRENT][MODE]

        items.append(CLOCK)
        items.append(WEATHER)
        items.append(LYRICS)

        if mode == AUDIO_FILES or mode == COLLECTION:
            items.append(FILE_INFO)

        layout = BorderLayout(bb)
        layout.set_percent_constraints(self.top_height, 0, 0, self.popup_width)
        popup = Popup(items, self.util, layout.RIGHT, self.clean_draw_update,
                      self.handle_info_popup_selection)
        self.right_button.add_label_listener(popup.update_popup)

        return popup

    def handle_order_popup_selection(self, state):
        """ Handle playback order menu selection

        :param state: button state
        """
        b = self.factory.create_order_button(self.bottom_layout.LEFT,
                                             self.handle_order_button,
                                             state.name)
        i = self.components.index(self.order_button)
        self.components[i] = b
        self.order_button = b
        self.add_button_observers(self.order_button, self.update_observer,
                                  self.redraw_observer)
        self.order_button.clean_draw_update()
        self.config[PLAYER_SETTINGS][PLAYBACK_ORDER] = state.name

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

        :param state: button state
        """
        n = state.name

        if n == CLOCK or n == WEATHER:
            self.start_screensaver(n)
        elif n == LYRICS:
            a = None
            try:
                m = self.util.get_file_metadata()
                a = m["artist"] + " - " + m["title"]
            except:
                pass
            if a != None:
                s = State()
                s.album = a
                self.start_screensaver(n, s)
            else:
                self.start_screensaver(n)
        else:
            self.go_info_screen(state)

    def get_audio_files(self):
        """ Return the list of audio files in current folder
        
        :return: list of audio files
        """
        files = []
        if self.config[CURRENT][MODE] == CD_PLAYER:
            af = getattr(self, "audio_files", None)
            if af == None:
                cd_drive_name = self.config[CD_PLAYBACK][CD_DRIVE_NAME]
                files = self.cdutil.get_cd_tracks_summary(cd_drive_name)
            else:
                return self.audio_files
        else:
            folder = self.config[FILE_PLAYBACK][CURRENT_FOLDER]
            files = self.util.get_audio_files_in_folder(folder)

        return files

    def get_current_track_index(self, state=None):
        """ Return current track index.
        In case of files goes through the file list.
        In case of playlist takes track index from the state object.
        
        :param state: button state

        :return: current track index
        """
        if self.config[CURRENT][MODE] == AUDIOBOOKS:
            t = None
            try:
                t = state["file_name"]
            except:
                pass

            if t == None:
                try:
                    t = state["current_title"]
                except:
                    pass

            if t == None:
                try:
                    t = state
                except:
                    pass

            for i, f in enumerate(self.audio_files):
                try:
                    s = f["file_name"]
                except:
                    pass

                if getattr(f, "file_name", None):
                    s = getattr(f, "file_name", None)

                if s.endswith(t):
                    return i
            return 0

        mode = self.config[FILE_PLAYBACK][CURRENT_FILE_PLAYBACK_MODE]
        if state and mode == FILE_PLAYLIST:
            try:
                n = state["Track"]
                if n: return int(n) - 1
            except:
                pass

        if self.config[CURRENT][MODE] == CD_PLAYER:
            cmp = int(self.config[CD_PLAYBACK][CD_TRACK]) - 1
        else:
            cmp = self.config[FILE_PLAYBACK][CURRENT_FILE]
            if state and isinstance(state, State):
                cmp = state.file_name

        for f in self.audio_files:
            if self.config[CURRENT][MODE] == CD_PLAYER:
                if f.index == cmp:
                    return f.index
            else:
                if f.file_name == cmp:
                    return f.index
        return 0

    def stop_recursive_playback(self):
        """ Stop recursive playback """

        self.config[FILE_PLAYBACK][CURRENT_FILE_PLAYBACK_MODE] = FILE_AUDIO
        self.config[FILE_PLAYBACK][CURRENT_FILE_PLAYLIST] = None
        self.config[FILE_PLAYBACK][CURRENT_TRACK_TIME] = None
        self.stop_timer()
        if self.show_time_control:
            self.time_control.stop_thread()
            self.time_control.reset()
        if self.stop_player != None:
            self.stop_player()

    def go_left(self, state):
        """ Switch to the previous track
        
        :param state: not used state object
        """
        if getattr(self, "current_track_index", None) == None:
            return

        filelist_size = self.get_filelist_size()

        if self.config[FILE_PLAYBACK][
                CURRENT_FILE_PLAYBACK_MODE] == FILE_RECURSIVE:
            self.stop_recursive_playback()
            return

        if self.current_track_index == 0:
            self.current_track_index = filelist_size - 1
        else:
            self.current_track_index -= 1
        self.change_track(self.current_track_index)

    def go_right(self, state):
        """ Switch to the next track
        
        :param state: not used state object
        """
        if getattr(self, "current_track_index", None) == None:
            return

        filelist_size = self.get_filelist_size()

        if self.config[FILE_PLAYBACK][
                CURRENT_FILE_PLAYBACK_MODE] == FILE_RECURSIVE and self.current_track_index == filelist_size - 1:
            self.stop_timer()
            if self.show_time_control:
                self.time_control.stop_thread()
            self.recursive_change_folder()
            self.current_track_index = 0
            self.change_track(self.current_track_index)
            self.file_button.clean_draw_update()
            return

        if self.current_track_index == filelist_size - 1:
            self.current_track_index = 0
        else:
            self.current_track_index += 1

        self.change_track(self.current_track_index)

    def get_filelist_size(self):
        """ Return the file list size
        
        :return: file list size
        """
        if self.audio_files:
            return len(self.audio_files)
        else:
            return 0

    def change_track(self, track_index):
        """ Change track
        
        :param track_index: index track
        """
        a = [AUDIOBOOKS, CD_PLAYER]
        m = self.config[CURRENT][MODE]
        if not (m in a):
            self.config[FILE_PLAYBACK][CURRENT_FILE] = self.get_filename(
                track_index)

        self.stop_timer()
        time.sleep(0.3)
        s = State()
        if m == FILE_PLAYBACK:
            s.playback_mode = self.config[FILE_PLAYBACK][
                CURRENT_FILE_PLAYBACK_MODE]

        s.playlist_track_number = track_index
        s.index = track_index
        s.source = ARROW_BUTTON
        s.file_name = self.get_filename(track_index)

        if self.cd_album != None:
            s.album = self.cd_album

        if self.config[CURRENT][MODE] == AUDIO_FILES:
            folder = self.current_folder
            if not folder.endswith(os.sep):
                folder += os.sep
            s.url = folder + s.file_name

        self.set_current(True, s)

    def stop_timer(self):
        """ Stop time control timer """

        if self.show_time_control:
            self.time_control.stop_timer()

    def get_filename(self, index):
        """ Get filename by index
        
        :param index: file index
        
        :return: filename
        """
        for b in self.audio_files:
            if b.index == index:
                return b.file_name
        return ""

    def is_valid_mode(self):
        current_mode = self.config[CURRENT][MODE]
        modes = [AUDIO_FILES, AUDIOBOOKS, CD_PLAYER]
        if current_mode in modes:
            return True
        else:
            return False

    def update_arrow_button_labels(self, state=None):
        """ Update left/right arrow button labels
        
        :param state: state object representing current track
        """
        if (not self.is_valid_mode()) or (not self.screen_title.active): return

        self.set_current_track_index(state)
        left = self.current_track_index
        right = 0

        if self.audio_files and len(self.audio_files) > 1:
            right = len(self.audio_files) - self.current_track_index - 1

        self.left_button.change_label(str(left))
        self.right_button.change_label(str(right))

    def set_current_track_index(self, state):
        """ Set current track index
        
        :param state: state object representing current track
        """
        if not self.is_valid_mode(): return

        if self.config[CURRENT][MODE] == CD_PLAYER and getattr(
                state, "cd_track_id", None):
            self.config[CD_PLAYBACK][CD_TRACK] = state["cd_track_id"]

        self.current_track_index = 0

        if self.playlist_size == 1:
            return

        if not self.audio_files:
            self.audio_files = self.get_audio_files()
            if not self.audio_files: return

        i = self.get_current_track_index(state)
        self.current_track_index = i

    def create_left_panel(self, layout, listeners, arrow_labels):
        """ Create left side buttons panel
        
        :param layout: panel layout 
        :param listeners: button listeners
        :param arrow_labels: show arrow label or not
        """
        panel_layout = self.get_panel_layout(layout, LOCATION_LEFT)
        panel_layout.set_percent_constraints(self.button_height,
                                             self.button_height, 0, 0)
        self.left_button = self.factory.create_left_button(
            panel_layout.CENTER, '', 40, 100, arrow_labels)
        panel_layout.TOP.y += 1
        panel_layout.TOP.h -= 2
        self.shutdown_button = self.factory.create_shutdown_button(
            panel_layout.TOP)
        panel_layout.BOTTOM.h += 1
        self.home_button = self.factory.create_button(KEY_HOME,
                                                      KEY_HOME,
                                                      panel_layout.BOTTOM,
                                                      image_size_percent=36)
        panel = Container(self.util, layout.LEFT)
        panel.add_component(self.shutdown_button)
        panel.add_component(self.left_button)
        panel.add_component(self.home_button)
        self.add_component(panel)

    def create_right_panel(self, layout, listeners, arrow_labels):
        """ Create right side buttons panel
        
        :param layout: panel layout 
        :param listeners: button listeners
        :param arrow_labels: show arrow label or not
        """
        panel_layout = self.get_panel_layout(layout, LOCATION_RIGHT)
        panel_layout.set_percent_constraints(self.button_height,
                                             self.button_height, 0, 0)
        panel_layout.TOP.y += 1
        panel_layout.TOP.h -= 2
        self.play_button = self.factory.create_play_pause_button(
            panel_layout.TOP, self.get_listener(listeners, KEY_PLAY_PAUSE))
        self.right_button = self.factory.create_right_button(
            panel_layout.CENTER, '', 40, 100, arrow_labels)
        panel_layout.BOTTOM.h += 1
        self.time_volume_button = self.factory.create_time_volume_button(
            panel_layout.BOTTOM, self.toggle_time_volume)
        panel = Container(self.util, layout.RIGHT)
        panel.add_component(self.play_button)
        panel.add_component(self.right_button)
        panel.add_component(self.time_volume_button)
        self.add_component(panel)

    def get_listener(self, listeners, name):
        """ Return listener

        :param listeners: all listeners
        :param name: listener name

        :return: listener if avaialble, None - otherwise
        """
        if name in listeners.keys():
            return listeners[name]
        else:
            return None

    def toggle_time_volume(self):
        """ Switch between time and volume controls """

        if self.volume_visible:
            self.volume.set_visible(False)
            if self.show_time_control:
                self.time_control.set_visible(True)
            self.volume_visible = False
        else:
            volume_level = int(self.config[PLAYER_SETTINGS][VOLUME])
            self.volume.set_position(volume_level)
            self.volume.update_position()
            self.volume.set_visible(True)
            if self.show_time_control:
                self.time_control.set_visible(False)
            self.volume_visible = True
        self.clean_draw_update()
        if hasattr(self, "time_control"):
            self.time_control.slider.clean_draw_update()

    def eject_cd(self, state):
        """ Eject CD
        
        :param state: button state object
        """
        self.audio_files = []
        self.screen_title.set_text(" ")
        self.update_arrow_button_labels(state)
        if self.show_time_control:
            self.time_control.reset()
        self.cd_album = None
        self.set_cd_album_art_image()

    def set_current(self, new_track=False, state=None):
        """ Set current file or playlist
        
        :param new_track: True - new audio file
        :param state: button state
        """
        self.cd_album = getattr(state, "album", None)

        if self.config[CURRENT][MODE] == AUDIO_FILES:
            if getattr(state, "url", None) is None:
                state.url = None
            state.full_screen_image = self.set_audio_file_image(state.url)
        elif self.config[CURRENT][MODE] == CD_PLAYER and getattr(
                state, "source", None) != INIT:
            state.full_screen_image = self.set_cd_album_art_image()
            state.image_base = self.file_button.components[1].content

        config_volume_level = int(self.config[PLAYER_SETTINGS][VOLUME])
        if state:
            if self.config[VOLUME_CONTROL][
                    VOLUME_CONTROL_TYPE] == VOLUME_CONTROL_TYPE_PLAYER:
                state.volume = config_volume_level
            else:
                state.volume = None

        self.set_audio_file(new_track, state)

        if self.volume.get_position() != config_volume_level:
            self.volume.set_position(config_volume_level)
            self.volume.update_position()

    def set_audio_file_image(self, url=None, folder=None):
        """ Set audio file image

        :param url: audio file name
        :param folder: folder name

        :return: image
        """
        if folder:
            f = folder
        else:
            f = self.config[FILE_PLAYBACK][CURRENT_FOLDER]

        if not f: return None

        img_tuple = self.image_util.get_audio_file_icon(
            f, self.bounding_box, url)
        self.set_file_button(img_tuple)
        self.file_button.clean_draw_update()

        return img_tuple[1]

    def set_cd_album_art_image(self):
        """ Set CD album art image """

        img_tuple = self.image_util.get_cd_album_art(self.cd_album,
                                                     self.bounding_box)
        if img_tuple == None:
            return None
        self.set_file_button(img_tuple)
        self.file_button.clean_draw_update()

        return img_tuple[1]

    def set_file_button(self, img_tuple):
        """ Set image in file button
        
        :param img_tuple: tuple where first element is image location, second element image itself 
        """
        full_screen_image = img_tuple[1]
        self.file_button.state.full_screen_image = full_screen_image

        scale_ratio = self.image_util.get_scale_ratio(
            (self.layout.CENTER.w, self.layout.CENTER.h), full_screen_image)
        img = self.image_util.scale_image(full_screen_image, scale_ratio)

        self.file_button.components[1].content = img
        self.file_button.state.icon_base = img
        self.file_button.components[
            1].image_filename = self.file_button.state.image_filename = img_tuple[
                0]

        self.file_button.components[1].content_x = self.layout.CENTER.x + (
            self.layout.CENTER.w - img.get_size()[0]) / 2

        if self.layout.CENTER.h > img.get_size()[1]:
            self.file_button.components[
                1].content_y = self.layout.CENTER.y + int(
                    (self.layout.CENTER.h - img.get_size()[1]) / 2) + 1
        else:
            self.file_button.components[1].content_y = self.layout.CENTER.y

    def set_audio_file(self, new_track, s=None):
        """ Set new audio file
        
        :param new_track: True - new audio file
        "param s" button state object
        """
        state = State()

        if s:
            state.playback_mode = getattr(s, "playback_mode", FILE_AUDIO)
            state.playlist_track_number = getattr(s, "playlist_track_number",
                                                  None)
            if self.config[CURRENT][MODE] == CD_PLAYER and getattr(
                    s, "source", None) != INIT:
                image_base = getattr(s, "image_base", None)
                if image_base != None:
                    state.image_base = image_base
        else:
            m = self.config[FILE_PLAYBACK][CURRENT_FILE_PLAYBACK_MODE]
            if m:
                state.playback_mode = m
            else:
                state.playback_mode = FILE_AUDIO

        if self.config[CURRENT][MODE] == AUDIO_FILES:
            self.current_folder = self.config[FILE_PLAYBACK][CURRENT_FOLDER]
            if not self.current_folder:
                return
            state.folder = self.current_folder
            state.file_name = self.config[FILE_PLAYBACK][CURRENT_FILE]
            if state.folder[-1] == os.sep:
                state.folder = state.folder[:-1]

            if os.sep in state.file_name:
                state.url = "\"" + state.file_name + "\""
            else:
                state.url = "\"" + state.folder + os.sep + state.file_name + "\""

            if s.url == None and state.url != None:
                state.full_screen_image = self.set_audio_file_image(
                    state.url.replace('\"', ""))

            state.music_folder = self.config[AUDIO][MUSIC_FOLDER]
        elif self.config[CURRENT][MODE] == CD_PLAYER:
            state.file_name = s.file_name
            state.url = getattr(s, "url", s.file_name)
            parts = s.file_name.split()
            self.config[CD_PLAYBACK][CD_DRIVE_NAME] = parts[0][len("cdda:///"
                                                                   ):]
            id = self.cdutil.get_cd_drive_id_by_name(
                self.config[CD_PLAYBACK][CD_DRIVE_NAME])
            self.config[CD_PLAYBACK][CD_DRIVE_ID] = int(id)
            self.config[CD_PLAYBACK][CD_TRACK] = int(parts[1].split("=")[1])

        self.config[PLAYER_SETTINGS][PAUSE] = False
        state.mute = self.config[PLAYER_SETTINGS][MUTE]
        state.pause = self.config[PLAYER_SETTINGS][PAUSE]
        self.play_button.draw_default_state(None)
        state.file_type = FILE_AUDIO
        state.dont_notify = True
        state.source = FILE_AUDIO

        if self.config[FILE_PLAYBACK][
                CURRENT_FILE_PLAYBACK_MODE] == FILE_AUDIO or self.config[
                    CURRENT][MODE] == CD_PLAYER:
            self.audio_files = self.get_audio_files()
        elif self.config[FILE_PLAYBACK][
                CURRENT_FILE_PLAYBACK_MODE] == FILE_PLAYLIST:
            state.file_name = self.config[FILE_PLAYBACK][CURRENT_FILE_PLAYLIST]
            self.load_playlist(state)
            state.file_name = self.config[FILE_PLAYBACK][CURRENT_FILE]
            self.audio_files = self.get_audio_files_from_playlist()
            state.playback_mode = FILE_PLAYLIST
            n = getattr(s, "file_name", None)
            if n:
                state.file_name = n

            try:
                state.playlist_track_number = int(state.file_name) - 1
            except:
                state.playlist_track_number = self.get_current_track_index(
                    state)

        source = None
        if s:
            source = getattr(s, "source", None)

        if new_track:
            tt = 0.0
        else:
            if self.config[CURRENT][MODE] == CD_PLAYER:
                tt = self.config[CD_PLAYBACK][CD_TRACK_TIME]
            else:
                tt = self.config[FILE_PLAYBACK][CURRENT_TRACK_TIME]

        if (isinstance(tt, str) and len(tt) != 0) or (
                isinstance(tt, float) or
            (source and source == RESUME)) or isinstance(tt, int):
            state.track_time = tt

        if self.show_time_control:
            self.time_control.slider.set_position(0)

        if self.file_button and self.file_button.components[
                1] and self.file_button.components[1].content:
            state.icon_base = self.file_button.components[1].content

        if s and hasattr(s, "volume"):
            state.volume = s.volume

        if self.config[CURRENT][MODE] == CD_PLAYER and s and getattr(
                s, "source", None) == INIT:
            try:
                self.cd_album = self.util.cd_titles[self.config[CD_PLAYBACK]
                                                    [CD_DRIVE_NAME]]
                self.set_cd_album_art_image()
                state.image_base = self.file_button.components[1].content
            except:
                self.cd_album = None

        if getattr(s, "full_screen_image", None) != None:
            state.full_screen_image = s.full_screen_image

        song_name = self.get_song_name(s)
        if song_name != None:
            state.album = song_name

        self.notify_play_listeners(state)

    def get_song_name(self, state):
        """ Get song name in the format: Artist - Song name
        
        :param state: state object
        """
        album = getattr(state, "album", None)
        if album == None:
            return None

        artist = album
        if "/" in album:
            artist = album.split("/")[0].strip()

        if artist == None or len(artist) == 0:
            return None

        name = getattr(state, "l_name", None)
        file_name = getattr(state, "file_name", None)
        if name == None:
            if file_name == None:
                return None
            else:
                if file_name.startswith("cdda:"):
                    id = int(file_name.split("=")[1].strip())
                    name = self.audio_files[id - 1].name
                else:
                    name = file_name

        pos = name.find(".")
        if pos != -1:
            tokens = name.split(".")
            if tokens[0].strip().isdigit():
                name = name[pos + 1:].strip()

        if name == None or len(name) == 0:
            return None
        else:
            return artist + " - " + name

    def get_audio_files_from_playlist(self):
        """ Call player for files in the playlist 
        
        :return: list of files from playlist
        """
        playlist = self.get_current_playlist()
        files = []
        if playlist:
            for n in range(len(playlist)):
                st = State()
                st.index = st.comparator_item = n
                st.file_type = FILE_AUDIO
                st.file_name = playlist[n]
                files.append(st)

        return files

    def restore_current_folder(self, state=None):
        """ Set current folder in config object
        
        :param state: not used
        """
        self.config[FILE_PLAYBACK][CURRENT_FOLDER] = self.current_folder

    def set_audio_file_playlist(self, index):
        """ Set file in playlist
        
        :param index: file index in playlist
        """
        state = State()
        state.playback_mode = FILE_PLAYLIST
        state.playlist_track_number = index
        state.file_type = FILE_AUDIO
        self.current_folder = self.config[FILE_PLAYBACK][CURRENT_FOLDER]
        self.notify_play_listeners(state)

    def go_back(self):
        """ Go back """
        pass

    def recursive_change_folder(self):
        start_folder = self.config[FILE_PLAYBACK][CURRENT_FILE_PLAYLIST]
        current_folder = self.config[FILE_PLAYBACK][CURRENT_FOLDER]
        f = self.util.file_util.get_next_folder_with_audio_files(
            start_folder, current_folder)
        if f == None or (f != None and f[0] == None):
            self.config[FILE_PLAYBACK][CURRENT_FILE_PLAYBACK_MODE] = FILE_AUDIO
            self.config[FILE_PLAYBACK][CURRENT_FILE_PLAYLIST] = None
            return False

        self.config[FILE_PLAYBACK][CURRENT_FOLDER] = f[0]
        self.config[FILE_PLAYBACK][CURRENT_FILE] = f[1]
        self.config[FILE_PLAYBACK][CURRENT_TRACK_TIME] = None
        state = State()
        state.file_type = FOLDER
        state.url = f[0]
        state.long_press = True
        state.playback_mode = FILE_RECURSIVE
        self.current_track_index = 0
        state.dont_notify = True
        self.audio_files = self.get_audio_files()
        self.recursive_notifier(f[0])
        return True

    def end_of_track(self):
        """ Handle end of track """

        if not self.screen_title.active:
            return

        i = getattr(self, "current_track_index", None)
        if i == None: return
        self.stop_timer()
        mode = self.config[CURRENT][MODE]
        if mode == RADIO or mode == STREAM or not self.audio_files:
            return

        if self.show_time_control:
            self.time_control.stop_thread()

        playback_mode = self.config[FILE_PLAYBACK][CURRENT_FILE_PLAYBACK_MODE]
        if playback_mode == FILE_RECURSIVE:
            if self.current_track_index == (len(self.audio_files) - 1):
                if not self.recursive_change_folder():
                    self.stop_recursive_playback()
                    return
                else:
                    index = 0
            else:
                index = self.current_track_index + 1
        else:
            index = self.get_next_index()

        if index == None:
            self.time_control.stop_thread()
            self.time_control.reset()
            return
        else:
            self.current_track_index = index

        if mode == AUDIO_FILES:
            self.config[FILE_PLAYBACK][CURRENT_TRACK_TIME] = None
        elif mode == AUDIOBOOKS:
            self.config[AUDIOBOOKS][BROWSER_BOOK_TIME] = None

        self.change_track(index)

        if playback_mode == FILE_RECURSIVE:
            self.file_button.clean_draw_update()

    def get_next_index(self):
        """ Return next file index

        :return: file index or None
        """
        order = self.config[PLAYER_SETTINGS][PLAYBACK_ORDER]
        n = self.current_track_index
        last = len(self.audio_files) - 1

        if order == PLAYBACK_SINGLE_TRACK:
            return None

        if order == PLAYBACK_SINGLE_CYCLIC:
            return n

        if order == PLAYBACK_CYCLIC:
            if n == last:
                return 0
            else:
                return n + 1
        elif order == PLAYBACK_REGULAR:
            if n == last:
                return None
            else:
                return n + 1
        elif order == PLAYBACK_SHUFFLE:
            if len(self.audio_files) == 1:
                return n
            else:
                return random.randint(0, last)

    def set_playlist_size(self, size):
        """ Set playlist size
        
        :param size: playlist size
        """
        self.playlist_size = size
        self.stop_timer()

    def set_visible(self, flag):
        """ Set visibility flag
         
        :param flag: True - screen visible, False - screen invisible
        """
        Container.set_visible(self, flag)

        if flag:
            if self.volume_visible:
                self.volume.set_visible(True)
                if self.show_time_control:
                    self.time_control.set_visible(False)
            else:
                self.volume.set_visible(False)
                if self.show_time_control:
                    self.time_control.set_visible(True)

    def add_play_listener(self, listener):
        """ Add play listener
        
        :param listener: event listener
        """
        if listener not in self.play_listeners:
            self.play_listeners.append(listener)

    def notify_play_listeners(self, state):
        """ Notify all play listeners
        
        :param state: button state
        """
        if not self.screen_title.active:
            return

        m = getattr(state, "playback_mode", None)
        if m != None and m != FILE_PLAYLIST:
            state.icon_base = self.file_button.state.icon_base
        folder = getattr(state, "folder", None)
        if folder:
            state.cover_art_folder = self.util.file_util.get_cover_art_folder(
                state.folder)

        for listener in self.play_listeners:
            listener(state)

    def enable_player_screen(self, flag):
        """ Enable player screen
        
        :param flag: enable/disable flag
        """
        self.screen_title.active = flag
        if self.show_time_control:
            self.time_control.active = flag

    def add_screen_observers(self, update_observer, redraw_observer,
                             start_time_control, stop_time_control,
                             title_to_json):
        """ Add screen observers
        
        :param update_observer: observer for updating the screen
        :param redraw_observer: observer to redraw the whole screen
        :param start_time_control:
        :param stop_time_control:
        :param title_to_json:
        """
        self.update_observer = update_observer
        self.redraw_observer = redraw_observer
        Screen.add_screen_observers(self, update_observer, redraw_observer,
                                    title_to_json)

        self.add_button_observers(self.shutdown_button,
                                  update_observer,
                                  redraw_observer=None)
        self.shutdown_button.add_cancel_listener(redraw_observer)
        self.screen_title.add_listener(redraw_observer)

        self.add_button_observers(self.play_button,
                                  update_observer,
                                  redraw_observer=None)
        self.add_button_observers(self.home_button, update_observer,
                                  redraw_observer)

        if self.order_button:
            self.add_button_observers(self.order_button, update_observer,
                                      redraw_observer)
        if self.info_button:
            self.add_button_observers(self.info_button, update_observer,
                                      redraw_observer)

        self.add_button_observers(self.left_button,
                                  update_observer,
                                  redraw_observer=None)
        self.left_button.add_label_listener(update_observer)
        self.add_button_observers(self.right_button,
                                  update_observer,
                                  redraw_observer=None)
        self.right_button.add_label_listener(update_observer)

        self.volume.add_slide_listener(update_observer)
        self.volume.add_knob_listener(update_observer)
        self.volume.add_press_listener(update_observer)
        self.volume.add_motion_listener(update_observer)

        self.add_button_observers(self.file_button,
                                  update_observer,
                                  redraw_observer,
                                  press=False,
                                  release=False)

        if self.order_popup:
            self.order_popup.add_menu_observers(update_observer,
                                                redraw_observer)

        if self.info_popup:
            self.info_popup.add_menu_observers(update_observer,
                                               redraw_observer)

        if self.show_time_control:
            self.add_button_observers(self.time_volume_button,
                                      update_observer,
                                      redraw_observer,
                                      release=False)
            self.time_control.web_seek_listener = update_observer
            if start_time_control:
                self.time_control.add_start_timer_listener(start_time_control)
            if stop_time_control:
                self.time_control.add_stop_timer_listener(stop_time_control)
            self.time_control.slider.add_slide_listener(update_observer)
            self.time_control.slider.add_knob_listener(update_observer)
            self.time_control.slider.add_press_listener(update_observer)
            self.time_control.slider.add_motion_listener(update_observer)
Esempio n. 16
0
class ButtonLayout(object):
    """ Layout which arranges button components (icon and label) """
    
    def __init__(self, state):
        """ Initializer. Define bounding boxes for button label (if any) and icon (if any)
        
        :param state: button state
        """        
        s = state
        bb = s.bounding_box
        self.show_image = getattr(s, "show_img", None)
        self.show_label = getattr(s, "show_label", False)
        self.image_location = getattr(s, "image_location", CENTER)
        self.label_location = getattr(s, "label_location", BOTTOM)
        self.image_area_percent = getattr(s, "image_area_percent", 0)
        self.label_area_percent = getattr(s, "label_area_percent", 0)        
        self.layout = BorderLayout(bb)
        top = bottom = left = right = 0
        self.image_rectangle = self.label_rectangle = None
        
        if self.show_image and self.show_label:
            if self.image_location == TOP and self.label_location == CENTER:
                top = self.image_area_percent
                self.layout.set_percent_constraints(top, bottom, left, right)
                self.image_rectangle = self.layout.TOP
                self.label_rectangle = self.layout.CENTER
            elif self.image_location == BOTTOM and self.label_location == CENTER:
                bottom = self.image_area_percent
                self.layout.set_percent_constraints(top, bottom, left, right)
                self.image_rectangle = self.layout.BOTTOM
                self.label_rectangle = self.layout.CENTER
            elif self.image_location == CENTER and self.label_location == TOP:
                top = self.label_area_percent
                self.layout.set_percent_constraints(top, bottom, left, right)
                self.image_rectangle = self.layout.CENTER
                self.label_rectangle = self.layout.TOP
            elif self.image_location == CENTER and self.label_location == BOTTOM:
                bottom = self.label_area_percent
                self.layout.set_percent_constraints(top, bottom, left, right)
                self.image_rectangle = self.layout.CENTER
                self.label_rectangle = self.layout.BOTTOM                
            elif self.image_location == LEFT and self.label_location == CENTER:
                left = self.image_area_percent
                self.layout.set_percent_constraints(top, bottom, left, right)
                self.image_rectangle = self.layout.LEFT
                self.label_rectangle = self.layout.CENTER
            elif self.image_location == RIGHT and self.label_location == CENTER:
                right = self.image_area_percent
                self.layout.set_percent_constraints(top, bottom, left, right)
                self.image_rectangle = self.layout.RIGHT
                self.label_rectangle = self.layout.CENTER
            elif self.image_location == CENTER and self.label_location == LEFT:
                left = self.label_area_percent
                self.layout.set_percent_constraints(top, bottom, left, right)
                self.image_rectangle = self.layout.CENTER
                self.label_rectangle = self.layout.LEFT
            elif self.image_location == CENTER and self.label_location == RIGHT:
                right = self.label_area_percent
                self.layout.set_percent_constraints(top, bottom, left, right)
                self.image_rectangle = self.layout.CENTER
                self.label_rectangle = self.layout.RIGHT
        elif self.show_image and not self.show_label:
            self.layout.set_percent_constraints(top, bottom, left, right)
            self.image_rectangle = self.layout.CENTER
        elif not self.show_image and self.show_label:
            self.layout.set_percent_constraints(top, bottom, left, right)
            self.label_rectangle = self.layout.CENTER
        
    def get_image_rectangle(self):
        """ Return button image bounding box
        
        :return: image bounding box
        """
        return self.image_rectangle
        
    def get_label_rectangle(self):
        """ Return button label bounding box
        
        :return: label bounding box
        """
        return self.label_rectangle
Esempio n. 17
0
    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]

        m = self.create_podcast_menu_button
        font_size = int(
            ((self.menu_layout.h / MENU_ROWS_PODCASTS) / 100) * FONT_HEIGHT)
        self.podcasts_menu = MultiPageMenu(util,
                                           self.next_page,
                                           self.previous_page,
                                           self.set_title,
                                           self.reset_title,
                                           self.go_to_page,
                                           m,
                                           MENU_ROWS_PODCASTS,
                                           MENU_COLUMNS_PODCASTS,
                                           None, (0, 0, 0, 0),
                                           self.menu_layout,
                                           align=ALIGN_CENTER,
                                           font_size=font_size)
        self.set_menu(self.podcasts_menu)

        self.navigator = PodcastNavigator(self.util, self.layout.BOTTOM,
                                          listeners, PAGE_SIZE_PODCASTS + 1)
        self.add_component(self.navigator)

        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
Esempio n. 18
0
class ButtonLayout(object):
    """ Layout which arranges button components (icon and label) """
    
    def __init__(self, state):
        """ Initializer. Define bounding boxes for button label (if any) and icon (if any)
        
        :param state: button state
        """        
        s = state
        bb = s.bounding_box
        self.show_image = getattr(s, "show_img", None)
        self.show_label = getattr(s, "show_label", False)
        self.image_location = getattr(s, "image_location", CENTER)
        self.label_location = getattr(s, "label_location", BOTTOM)
        self.image_area_percent = getattr(s, "image_size_percent", 0) * 100
        self.label_area_percent = getattr(s, "label_area_percent", 0)        
        self.layout = BorderLayout(bb)
        top = bottom = left = right = 0
        self.image_rectangle = self.label_rectangle = None
        
        if self.show_image and self.show_label:
            if self.image_location == TOP and self.label_location == CENTER:
                top = self.image_area_percent
                self.layout.set_percent_constraints(top, bottom, left, right)
                self.image_rectangle = self.layout.TOP
                self.label_rectangle = self.layout.CENTER
            elif self.image_location == BOTTOM and self.label_location == CENTER:
                bottom = self.image_area_percent
                self.layout.set_percent_constraints(top, bottom, left, right)
                self.image_rectangle = self.layout.BOTTOM
                self.label_rectangle = self.layout.CENTER
            elif self.image_location == CENTER and self.label_location == TOP:
                top = self.label_area_percent
                self.layout.set_percent_constraints(top, bottom, left, right)
                self.image_rectangle = self.layout.CENTER
                self.label_rectangle = self.layout.TOP
            elif self.image_location == CENTER and self.label_location == BOTTOM:
                bottom = self.label_area_percent
                self.layout.set_percent_constraints(top, bottom, left, right)
                self.image_rectangle = self.layout.CENTER
                self.label_rectangle = self.layout.BOTTOM                
            elif self.image_location == LEFT and self.label_location == CENTER:
                left = self.image_area_percent
                self.layout.set_percent_constraints(top, bottom, left, right)
                self.image_rectangle = self.layout.LEFT
                self.label_rectangle = self.layout.CENTER
            elif self.image_location == RIGHT and self.label_location == CENTER:
                right = self.image_area_percent
                self.layout.set_percent_constraints(top, bottom, left, right)
                self.image_rectangle = self.layout.RIGHT
                self.label_rectangle = self.layout.CENTER
            elif self.image_location == CENTER and self.label_location == LEFT:
                left = self.label_area_percent
                self.layout.set_percent_constraints(top, bottom, left, right)
                self.image_rectangle = self.layout.CENTER
                self.label_rectangle = self.layout.LEFT
            elif self.image_location == CENTER and self.label_location == RIGHT:
                right = self.label_area_percent
                self.layout.set_percent_constraints(top, bottom, left, right)
                self.image_rectangle = self.layout.CENTER
                self.label_rectangle = self.layout.RIGHT
        elif self.show_image and not self.show_label:
            self.layout.set_percent_constraints(top, bottom, left, right)
            self.image_rectangle = self.layout.CENTER
        elif not self.show_image and self.show_label:
            self.layout.set_percent_constraints(top, bottom, left, right)
            self.label_rectangle = self.layout.CENTER
        
    def get_image_rectangle(self):
        """ Return button image bounding box
        
        :return: image bounding box
        """
        return self.image_rectangle
        
    def get_label_rectangle(self):
        """ Return button label bounding box
        
        :return: label bounding box
        """
        return self.label_rectangle
Esempio n. 19
0
class Screen(Container):
    """ Base class for all screens. Extends Container class """
    def __init__(self,
                 util,
                 title_key,
                 percent_bottom_height=0,
                 voice_assistant=None,
                 screen_title_name="screen_title",
                 create_dynamic_title=False,
                 title_layout=None,
                 title=None,
                 bgr=None):
        """ Initializer
        
        :param util: utility object
        :param title_key: the resource bundle key for the screen title
        """
        self.util = util
        self.factory = Factory(util)
        self.config = util.config
        self.bounding_box = util.screen_rect

        if title_key:
            self.name = title_key
        else:
            self.name = "tmp"

        bg = self.util.get_background(self.name, bgr)
        self.bgr_type = bg[0]
        self.bgr = bg[1]
        self.bgr_key = bg[5]
        Container.__init__(self,
                           util,
                           bounding_box=self.bounding_box,
                           background=bg[1],
                           content=bg[2],
                           image_filename=bg[3])
        self.original_image_filename = None
        try:
            self.original_image_filename = bg[4].replace("\\", "/")
        except:
            pass

        self.layout = BorderLayout(util.screen_rect)
        self.layout.set_percent_constraints(PERCENT_TOP_HEIGHT,
                                            percent_bottom_height, 0, 0)
        self.voice_assistant = voice_assistant

        self.font_size = int((self.layout.TOP.h * PERCENT_TITLE_FONT) / 100.0)
        b = self.config[BACKGROUND][HEADER_BGR_COLOR]
        c = self.config[COLORS][COLOR_CONTRAST]

        t_layout = self.layout.TOP
        if title_layout:
            t_layout = title_layout

        if create_dynamic_title:
            self.screen_title = self.factory.create_dynamic_text(
                screen_title_name, t_layout, b, c, self.font_size)
        else:
            self.screen_title = self.factory.create_output_text(
                screen_title_name, t_layout, b, c, self.font_size)

        if title:
            self.screen_title.set_text(title)
        else:
            if title_key and len(title_key) > 0:
                try:
                    label = self.config[LABELS][title_key]
                    self.screen_title.set_text(label)
                except:
                    pass

        if voice_assistant:
            self.screen_title.add_select_listener(self.handle_voice_assistant)
            self.layout.TOP.w += 1
            self.voice_command = self.factory.create_output_text(
                "voice_command", self.layout.TOP, b, c, self.font_size)
            self.voice_command.add_select_listener(self.handle_voice_assistant)
            self.voice_assistant.add_text_recognized_listener(
                self.text_recognized)
            self.voice_assistant.assistant.add_start_conversation_listener(
                self.start_conversation)
            self.voice_assistant.assistant.add_stop_conversation_listener(
                self.stop_conversation)

        if voice_assistant and voice_assistant.is_running():
            self.title_selected = False
        else:
            self.title_selected = True

        self.draw_title_bar()
        self.player_screen = False
        self.update_web_observer = None
        self.update_web_title = None

        self.loading_listeners = []
        self.LOADING = util.config[LABELS][KEY_LOADING]
        self.animated_title = False

    def add_component(self, c):
        """ Add screen component

        :param c: component to add
        """
        if c:
            c.set_parent_screen(self)
        Container.add_component(self, c)

    def draw_title_bar(self):
        """ Draw title bar on top of the screen """

        if len(self.components) != 0 and self.title_selected:
            self.add_component(self.voice_command)
            self.title_selected = False
        elif len(self.components) != 0 and not self.title_selected:
            self.add_component(self.screen_title)
            self.title_selected = True
        elif len(self.components) == 0 and self.title_selected:
            self.add_component(self.screen_title)
        elif len(self.components) == 0 and not self.title_selected:
            self.voice_command.set_text(
                self.config[LABELS][KEY_WAITING_FOR_COMMAND])
            self.add_component(self.voice_command)

    def handle_voice_assistant(self, state=None):
        """ Start/Stop voice assistant 
        
        :state: not used
        """
        if self.title_selected:
            self.voice_assistant.start()
        else:
            self.voice_assistant.stop()

    def text_recognized(self, text):
        """ Handle text recognized event 
        
        :text: recognized text
        """
        c = self.config[LABELS][KEY_VA_COMMAND] + " " + text
        self.voice_command.set_text(c)
        self.voice_command.clean_draw_update()
        time.sleep(self.config[VOICE_ASSISTANT][VOICE_COMMAND_DISPLAY_TIME])
        if self.update_web_title:
            self.update_web_title(self.voice_command)

    def start_conversation(self, event):
        """ Start voice conversation
        
        :event: not used
        """
        if self.visible:
            self.voice_command.set_visible(True)
        self.voice_command.set_text_no_draw(
            self.config[LABELS][KEY_WAITING_FOR_COMMAND])
        self.components[0] = self.voice_command
        self.title_selected = False
        if self.visible:
            self.voice_command.clean_draw_update()
            if self.update_web_observer:
                self.update_web_observer()

    def stop_conversation(self):
        """ Stop voice conversation """

        if self.visible:
            self.screen_title.set_visible(True)
        self.components[0] = self.screen_title
        self.title_selected = True
        if self.visible:
            self.screen_title.clean_draw_update()
            if self.update_web_observer:
                self.update_web_observer()

    def add_menu(self, menu):
        """ Add menu to the screen
        
        :param menu: the menu to add
        """
        self.menu = menu
        self.add_component(menu)

    def enable_player_screen(self, flag):
        """ Enable player screen
        
        :param flag: enable/disable flag
        """
        pass

    def exit_screen(self):
        """ Complete actions required to save screen state """

        self.set_visible(False)

    def add_screen_observers(self,
                             update_observer,
                             redraw_observer,
                             title_to_json=None):
        """ Add screen observers.
        
        :param update_observer: observer for updating the screen
        :param redraw_observer: observer to redraw the whole screen
        """
        self.update_web_observer = redraw_observer
        self.update_web_title = title_to_json

    def set_loading(self, name=None, menu_bb=None, text=None):
        """ Show Loading... sign

        :param name: screen title
        :param menu_bb: menu bounding box
        :param text: screen text
        """
        b = self.config[BACKGROUND][MENU_BGR_COLOR]
        f = self.config[COLORS][COLOR_BRIGHT]
        fs = int(self.bounding_box.h * 0.07)

        if menu_bb != None:
            bb = menu_bb
        else:
            bb = self.bounding_box

        bb = Rect(bb.x, bb.y + 1, bb.w, bb.h - 1)

        t = self.factory.create_output_text(self.LOADING, bb, b, f, fs)
        if not text:
            t.set_text_no_draw(self.LOADING)
        else:
            t.set_text_no_draw(text)

        if name != None:
            self.screen_title.set_text(name)

        self.set_visible(True)
        self.add_component(t)
        if getattr(self, "menu", None) != None:
            self.menu.buttons = {}
            self.menu.components = []
        self.clean_draw_update()
        self.notify_loading_listeners()

    def reset_loading(self):
        """ Remove Loading label """

        del self.components[-1]
        self.notify_loading_listeners()

    def add_loading_listener(self, listener):
        """ Add loading listener

        :param listener: event listener
        """
        if listener not in self.loading_listeners:
            self.loading_listeners.append(listener)

    def notify_loading_listeners(self):
        """ Notify all loading listeners """

        for listener in self.loading_listeners:
            listener(None)
Esempio n. 20
0
class PodcastEpisodesScreen(MenuScreen):
    """ Podcast Episodes Screen """
    def __init__(self, util, listeners, voice_assistant, state):
        """ Initializer
        
        :param util: utility object
        :param listeners: file browser listeners
        :param voice_assistant: voice assistant
        :param state: button state
        """
        self.util = util
        self.config = util.config
        self.podcasts_util = util.get_podcasts_util()
        self.listeners = listeners
        self.factory = Factory(util)
        self.bounding_box = util.screen_rect
        self.layout = BorderLayout(self.bounding_box)
        self.layout.set_percent_constraints(PERCENT_TOP_HEIGHT,
                                            PERCENT_BOTTOM_HEIGHT, 0, 0)

        d = [MENU_ROWS_EPISODES, MENU_COLUMNS_EPISODES]
        MenuScreen.__init__(self,
                            util,
                            listeners,
                            MENU_ROWS_EPISODES,
                            MENU_COLUMNS_EPISODES,
                            voice_assistant,
                            d,
                            self.turn_page,
                            page_in_title=False)

        if hasattr(state, "podcast_url"):
            podcast_url = state.podcast_url
            self.title = self.podcasts_util.summary_cache[podcast_url].name
        else:
            self.title = state.name

        m = self.create_episode_menu_button
        font_size = int(
            ((self.menu_layout.h / MENU_ROWS_EPISODES) / 100) * FONT_HEIGHT)
        self.episodes_menu = MultiPageMenu(util,
                                           self.next_page,
                                           self.previous_page,
                                           self.set_title,
                                           self.reset_title,
                                           self.go_to_page,
                                           m,
                                           MENU_ROWS_EPISODES,
                                           MENU_COLUMNS_EPISODES,
                                           None, (0, 0, 0, 0),
                                           self.menu_layout,
                                           align=ALIGN_CENTER,
                                           font_size=font_size)
        self.set_menu(self.episodes_menu)

        self.total_pages = PAGE_SIZE_EPISODES * 2
        self.episodes = []
        self.navigator = EpisodeNavigator(self.util, self.layout.BOTTOM,
                                          listeners, self.total_pages)
        self.add_component(self.navigator)
        self.current_page = 1

        self.save_episode_listeners = []
        self.animated_title = True

    def create_episode_menu_button(self, s, constr, action, scale, font_size):
        """ Create podcast episode menu button

        :param s: button state
        :param constr: scaling constraints
        :param action: button event listener
        :param scale: True - scale images, False - don't scale images
        :param font_size: label font height in pixels

        :return: 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 = LEFT
        s.label_location = CENTER
        s.label_area_percent = 30
        s.image_size_percent = 0.12
        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 = "episode_menu"
        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 = EpisodeButton(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 not self.util.connected_to_internet and len(
                self.episodes) == 0 and not hasattr(state, "url"):
            return

        if state.name == KEY_BACK or (getattr(state, "source",
                                              None) == FILE_BUTTON
                                      and len(self.episodes) != 0):
            self.episodes_menu.clean_draw_update()
            return

        if getattr(state, "podcast_url", None) != None:
            self.episodes = self.podcasts_util.get_episodes(state.podcast_url)
            if len(self.episodes) != 0:
                self.total_pages = math.ceil(
                    len(self.episodes) / PAGE_SIZE_EPISODES)
                self.turn_page(state)
                return

        self.set_loading(self.title)
        if state.name != self.title or len(self.episodes) == 0:
            self.title = state.name
            if self.util.connected_to_internet:
                self.episodes = self.podcasts_util.get_episodes(state.url)
            else:
                self.episodes = self.podcasts_util.get_episodes_from_disk(
                    state.url)

        self.total_pages = math.ceil(len(self.episodes) / PAGE_SIZE_EPISODES)

        self.turn_page(state)
        self.reset_loading()

    def turn_page(self, state=None):
        """ Turn screen page
        
        :param state: button state
        """
        filelist = Page(self.episodes, MENU_ROWS_EPISODES,
                        MENU_COLUMNS_EPISODES)

        if state == None:
            filelist.current_page_index = self.current_page - 1
            index = filelist.current_page_index * PAGE_SIZE_EPISODES
        else:
            if getattr(state, "status", None) == STATUS_LOADED:
                if hasattr(state, "original_url") and len(
                        state.original_url.strip()) > 0:
                    filelist.set_current_item_by_url(state.original_url)
                else:
                    filelist.set_current_item_by_file_name(state.file_name)
            else:
                filelist.set_current_item_by_url(state.url)
            index = filelist.current_item_index

        self.current_page = filelist.current_page_index + 1

        page = filelist.get_current_page()
        d = self.episodes_menu.make_dict(page)
        self.episodes_menu.set_items(d, filelist.current_page_index,
                                     self.select_episode, False)
        self.set_title(self.current_page)
        self.episodes_menu.unselect()
        self.episodes_menu.select_by_index(index)

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

        self.navigator.left_button.change_label(
            str(filelist.get_left_items_number()))
        self.navigator.right_button.change_label(
            str(filelist.get_right_items_number()))
        self.episodes_menu.clean_draw_update()

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

    def select_episode(self, state):
        """ Select podacst episode
        
        :param state: button state
        """
        if getattr(state, "long_press", None) == True:
            if state.status == STATUS_LOADED:
                self.podcasts_util.delete_episode(state)
                if not self.util.connected_to_internet:
                    for i, c in enumerate(self.episodes):
                        if c.name == state.name:
                            del self.episodes[i]
                            break
                    if len(self.episodes) == 0:
                        self.title = " "
                        self.set_title(0)
                    self.turn_page(state)
                else:
                    state.icon_base = state.event_origin.components[
                        1].content = self.podcasts_util.available_icon
                    state.status = STATUS_AVAILABLE
            elif state.status == STATUS_AVAILABLE:
                if self.podcasts_util.is_podcast_folder_available():
                    state.icon_base = state.event_origin.components[
                        1].content = self.podcasts_util.loading_icon
                    state.status = STATUS_LOADING
                    self.add_save_episode_listener(state)
                    self.podcasts_util.save_episode(
                        state, self.notify_save_episode_listeners)
            self.clean_draw_update()
        else:
            podcast_player = self.listeners[KEY_PLAYER]
            podcast_player(state)

    def add_save_episode_listener(self, listener):
        """ Add save episode listener
        
        :param listener: event listener
        """
        if listener not in self.save_episode_listeners:
            self.save_episode_listeners.append(listener)

    def notify_save_episode_listeners(self):
        """ Notify all save episode listeners """

        for index, listener in enumerate(self.save_episode_listeners):
            listener.icon_base = listener.event_origin.components[
                1].content = self.podcasts_util.loaded_icon
            listener.status = STATUS_LOADED
            self.clean_draw_update()
            if hasattr(self, "redraw_observer"):
                self.redraw_observer()
            del self.save_episode_listeners[index]

    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(self.update_observer,
                                     self.redraw_observer)
Esempio n. 21
0
    def __init__(self, util, listeners, voice_assistant, timer_lock,
                 start_timer_thread):
        """ Initializer

        :param util: utility object
        :param listeners: screen navigator listeners
        :param voice_assistant: voice assistant
        :param timer_lock: lock object
        :param start_timer_thread: start timer thread function
        """
        self.util = util
        self.timer_lock = timer_lock
        self.start_timer_thread = start_timer_thread
        self.config = util.config
        self.screen_layout = BorderLayout(util.screen_rect)
        self.screen_layout.set_percent_constraints(PERCENT_TITLE,
                                                   PERCENT_NAV_HEIGHT, 0, 0)
        Screen.__init__(self,
                        util,
                        "",
                        PERCENT_NAV_HEIGHT,
                        voice_assistant,
                        "timer_title",
                        title_layout=self.screen_layout.TOP)
        self.bounding_box = util.screen_rect
        label = self.config[LABELS][TIMER]
        self.screen_title.set_text(label)

        try:
            self.config[TIMER]
        except:
            self.config[TIMER] = {}

        c = GridLayout(self.screen_layout.CENTER)
        c.set_pixel_constraints(2, 1)
        layout = BorderLayout(c.get_next_constraints())
        layout.set_percent_constraints(0, 0, PERCENT_CLOCK,
                                       100 - PERCENT_CLOCK)
        gap = layout.h * 0.1
        layout.LEFT.w -= gap * 3
        layout.LEFT.h -= gap
        digits = util.image_util.get_flipclock_digits(layout.LEFT)

        change_codes = [
            HOURS_INCREMENT_SLEEP, MINUTES_INCREMENT_SLEEP,
            HOURS_DECREMENT_SLEEP, MINUTES_DECREMENT_SLEEP
        ]
        self.sleep_menu = SleepMenu(util, layout, gap, digits,
                                    self.handle_button, timer_lock,
                                    self.sleep_change_callback, change_codes)
        self.active_key_menu = self.sleep_menu
        self.add_component(self.sleep_menu)
        self.menu_index = -1
        self.sleep_menu.clock.add_change_listener(self.handle_clock_change)

        layout = BorderLayout(c.get_next_constraints())
        layout.set_percent_constraints(0, 0, PERCENT_CLOCK,
                                       100 - PERCENT_CLOCK)

        change_codes = [
            HOURS_INCREMENT_WAKE_UP, MINUTES_INCREMENT_WAKE_UP,
            HOURS_DECREMENT_WAKE_UP, MINUTES_DECREMENT_WAKE_UP
        ]
        self.wake_up_menu = WakeUpMenu(util, layout, gap, digits,
                                       self.handle_button, timer_lock,
                                       self.wake_up_change_callback,
                                       change_codes)
        self.add_component(self.wake_up_menu)
        self.wake_up_menu.clock.add_change_listener(self.handle_clock_change)

        self.navigator = TimerNavigator(self.util, self.screen_layout.BOTTOM,
                                        listeners)
        self.navigator.components[0].set_selected(True)
        self.add_component(self.navigator)
        self.home_button = self.navigator.get_button_by_name(KEY_HOME)
        self.sleep_now_button = self.navigator.get_button_by_name(SLEEP_NOW)
        self.player_button = self.navigator.get_button_by_name(KEY_PLAYER)

        self.menu_functions = {
            HOURS_INCREMENT_SLEEP: self.sleep_menu.clock.increment_hours,
            MINUTES_INCREMENT_SLEEP: self.sleep_menu.clock.increment_minutes,
            HOURS_DECREMENT_SLEEP: self.sleep_menu.clock.decrement_hours,
            MINUTES_DECREMENT_SLEEP: self.sleep_menu.clock.decrement_minutes,
            HOURS_INCREMENT_WAKE_UP: self.wake_up_menu.clock.increment_hours,
            MINUTES_INCREMENT_WAKE_UP:
            self.wake_up_menu.clock.increment_minutes,
            HOURS_DECREMENT_WAKE_UP: self.wake_up_menu.clock.decrement_hours,
            MINUTES_DECREMENT_WAKE_UP:
            self.wake_up_menu.clock.decrement_minutes
        }

        self.current_button = None
        self.link_borders()
        self.clean_draw_update()
Esempio n. 22
0
    def __init__(self, f, id, util, name, bgr, slider_color, img_knob,
                 img_knob_on, key_incr, key_decr, key_knob, bb, listener,
                 label):
        """ Initializer
        
        :param id: band ID
        :param util: utility object
        :param name: slider name
        :param bgr: slider background color
        :param slider_color: slider center line color
        :param img_knob: knob image
        :param img_knob_on: knob image in on state
        :param key_incr: keyboard key associated with slider increment action
        :param key_decr: keyboard key associated with slider decrement action
        :param key_knob: keyboard key associated with single click on knob
        :param bb: slider bounding box
        """
        Container.__init__(self,
                           util,
                           background=bgr,
                           bounding_box=bb,
                           content=None)
        self.util = util
        self.config = util.config
        self.bgr = bgr

        self.VALUE_LAYER = 2
        self.LABEL_LAYER = 1

        layout = BorderLayout(bb)
        layout.set_percent_constraints(10.0, 10.0, 0.0, 0.0)

        self.value_name = name + ".value." + str(id)
        self.label_name = name + ".label." + str(id)
        self.value_layout = layout.TOP
        self.label_layout = layout.BOTTOM
        self.label_layout.y -= 1
        self.label_layout.h += 2

        self.slider = Slider(util, "slider." + str(id), bgr, slider_color,
                             img_knob, img_knob_on, None, key_incr, key_decr,
                             key_knob, layout.CENTER)
        self.slider.add_slide_listener(listener)
        self.add_component(self.slider)

        height = 60
        font_size = int((self.value_layout.h * height) / 100.0)
        c = self.config[COLORS][COLOR_BRIGHT]
        self.top = f.create_output_text("top.label." + str(id),
                                        self.value_layout, bgr, c, font_size)
        self.bottom = f.create_output_text("bottom.label." + str(id),
                                           self.label_layout, bgr, c,
                                           font_size)
        self.bottom.set_text(label)

        self.add_component(self.top)
        self.add_component(self.bottom)

        self.seek_listeners = []
        self.update_seek_listeners = True
        self.use_web = self.config[USAGE][USE_WEB]
Esempio n. 23
0
class EqualizerMenu(Container):
    """ Equalizer Menu class """
    def __init__(self, util, handle_slider_event, bounding_box=None):
        """ Initializer
        
        :param util: utility object
        :param handle_slider_event: slider event handler
        :param listeners: menu listeners
        :param bgr: menu background
        :param bounding_box: bounding box
        """
        self.labels = [
            "31", "63", "125", "250", "500", "1k", "2k", "4k", "8k", "16k"
        ]

        self.util = util
        Container.__init__(self, util)
        name = "equalizermenu"
        self.factory = Factory(util)

        self.bounding_box = bounding_box
        self.bounding_box.y += 1
        self.bounding_box.h -= 1
        self.bgr_color = util.config[BACKGROUND][MENU_BGR_COLOR]

        self.eq_layout = BorderLayout(self.bounding_box)
        self.eq_layout.set_percent_constraints(0, 0, 5, 5)

        self.bands = 10
        self.sliders = self.add_sliders(handle_slider_event)
        self.current_slider = -1

        self.left_filler = Component(util, self.eq_layout.LEFT)
        self.left_filler.name = name + ".bgr.left"
        self.left_filler.bgr = self.bgr_color
        self.add_component(self.left_filler)

        self.right_filler = Component(util, self.eq_layout.RIGHT)
        self.right_filler.name = name + ".bgr.right"
        self.right_filler.bgr = self.bgr_color
        self.add_component(self.right_filler)

        self.SLOW_INCREMENT = 1
        self.FAST_INCREMENT = self.sliders[0].slider.knob_height / 2

        self.mouse_events = [
            pygame.MOUSEBUTTONUP, pygame.MOUSEBUTTONDOWN, pygame.MOUSEMOTION
        ]

    def add_sliders(self, handle_slider_event):

        layout = GridLayout(self.eq_layout.CENTER)
        layout.set_pixel_constraints(1, self.bands, 0, 0)
        layout.current_constraints = 0
        sliders = []

        for n in range(self.bands):
            constr = layout.get_next_constraints()
            s = self.factory.create_equalizer_slider(n, constr, "band",
                                                     handle_slider_event,
                                                     self.labels[n],
                                                     self.bgr_color)
            s.slider.active = False
            s.content = None
            s.slider.content = None
            self.add_component(s)
            sliders.append(s)

        return sliders

    def set_bands(self, values):
        for n, s in enumerate(self.sliders):
            v = values[n]
            s.slider.set_position(v)
            s.slider.update_position()
            s.set_value(str(v))
            s.slider.set_knob_off()
            self.current_slider = -1

    def set_parent_screen(self, scr):
        """ Add parent screen

        :param scr: parent screen
        """
        self.left_filler.parent_screen = scr
        self.right_filler.parent_screen = scr
        for s in self.sliders:
            s.slider.parent_screen = scr
            s.top.parent_screen = scr
            s.bottom.parent_screen = scr

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

        if event.type == USER_EVENT_TYPE and event.sub_type == SUB_TYPE_KEYBOARD:
            key_events = [
                kbd_keys[KEY_LEFT], kbd_keys[KEY_RIGHT], kbd_keys[KEY_UP],
                kbd_keys[KEY_DOWN], kbd_keys[KEY_PAGE_UP],
                kbd_keys[KEY_PAGE_DOWN], kbd_keys[KEY_SELECT]
            ]
            if event.keyboard_key not in key_events:
                return

            if not self.is_menu_selected():
                return

            if event.action == pygame.KEYUP:
                self.key_up(event)
            elif event.action == pygame.KEYDOWN:
                self.key_down(event)
        elif event.type == SELECT_EVENT_TYPE:
            if event.source == self:
                return
            self.handle_select_action(event.x, event.y)
        elif event.type in self.mouse_events:
            if not self.bounding_box.collidepoint(event.pos):
                return

            Container.handle_event(self, event)

    def handle_select_action(self, x, y):
        """ Handle select action

        :param x: x coordinate
        :param y: y coordinate
        """
        for index, s in enumerate(self.sliders):
            if s.bounding_box.collidepoint((x - 3, y)):
                s.slider.selected = True
                self.current_slider = index
                self.activate_slider()

    def key_up(self, event):
        """ Handle key up

        :param event: the event to handle
        """
        avoided_keys = [
            kbd_keys[KEY_UP], kbd_keys[KEY_DOWN], kbd_keys[KEY_PAGE_UP],
            kbd_keys[KEY_PAGE_DOWN]
        ]
        if self.current_slider == -1 and (event.keyboard_key in avoided_keys):
            return

        self.deactivate_current_slider()
        if event.keyboard_key == kbd_keys[KEY_LEFT]:
            if self.current_slider == 0 or self.current_slider == -1:
                y = self.exit_bottom_y
                slider = self.sliders[len(self.sliders) - 1].slider
                if self.exit_menu(y, event, slider):
                    return
            else:
                self.current_slider -= 1
        elif event.keyboard_key == kbd_keys[KEY_RIGHT]:
            if self.current_slider == len(self.sliders) - 1:
                y = self.exit_bottom_y
                slider = self.sliders[0].slider
                if self.exit_menu(y, event, slider):
                    return
            else:
                self.current_slider += 1
        elif event.keyboard_key == kbd_keys[KEY_SELECT]:
            if not self.is_menu_selected():
                return
            slider = self.sliders[self.current_slider].slider
            if self.exit_menu(self.exit_bottom_y, event, slider):
                return

        self.activate_slider()

    def exit_menu(self, exit_border, event, slider):
        """ Exit menu

        :param exit_border: exit border
        :param event: exit event
        :param slider: the slider
        """
        if exit_border == None or slider == None or event.action != pygame.KEYUP:
            return False

        x = int(slider.bounding_box.x + (slider.bounding_box.w / 2))
        y = exit_border
        slider.selected = False
        self.current_slider = -1
        for s in self.sliders:
            s.slider.selected = False
        self.util.post_exit_event(x, y, self)
        if self.redraw_observer:
            self.redraw_observer()
        return True

    def key_down(self, event):
        """ Handle key down

        :param event: the event to handle
        """
        if self.current_slider == -1: return

        slider = self.sliders[self.current_slider].slider

        if event.keyboard_key == kbd_keys[KEY_UP]:
            slider.release_action(
                (slider.knob_x, slider.last_knob_position +
                 slider.knob_height / 2 - self.SLOW_INCREMENT))
        elif event.keyboard_key == kbd_keys[
                KEY_DOWN] and event.action == pygame.KEYDOWN:
            slider.release_action(
                (slider.knob_x, slider.last_knob_position +
                 slider.knob_height / 2 + self.SLOW_INCREMENT))
        elif event.keyboard_key == kbd_keys[
                KEY_PAGE_UP] and event.action == pygame.KEYDOWN:
            slider.release_action(
                (slider.knob_x,
                 slider.last_knob_position - self.FAST_INCREMENT))
        elif event.keyboard_key == kbd_keys[
                KEY_PAGE_DOWN] and event.action == pygame.KEYDOWN:
            slider.release_action(
                (slider.knob_x, slider.last_knob_position +
                 slider.knob_height / 2 + self.FAST_INCREMENT))

        slider.set_knob_on()

    def deactivate_current_slider(self):
        """ Deactivate the current slider """

        if self.current_slider == -1:
            return

        slider = self.sliders[self.current_slider].slider
        slider.release_action((slider.knob_x, slider.last_knob_position))
        slider.clean_draw_update()

    def activate_slider(self):
        """ Activate the current slider """

        slider = self.sliders[self.current_slider].slider
        slider.press_action()
        slider.clean_draw_update()

    def is_menu_selected(self):
        """ Check if menu has selected slider

        :return: True - has selected slider, False - doesn't have
        """
        for s in self.sliders:
            if s.slider.selected:
                return True
        return False

    def add_menu_observers(self, update_observer, redraw_observer):
        """ Add menu observer
        
        :param update_observer: observer for updating menu
        :param redraw_observer: observer to redraw the whole screen
        """
        self.redraw_observer = redraw_observer
        for s in self.sliders:
            s.slider.add_slide_listener(update_observer)
            s.slider.add_knob_listener(update_observer)
            s.slider.add_press_listener(update_observer)
            s.slider.add_motion_listener(update_observer)
            s.web_seek_listener = update_observer
Esempio n. 24
0
    def __init__(self, listeners, util, voice_assistant, screen_mode=STATION):
        """ Initializer
        
        :param util: utility object
        :param listener: screen menu event listener
        """
        self.util = util
        self.config = util.config
        self.factory = Factory(util)
        self.screen_mode = screen_mode
        self.bounding_box = util.screen_rect
        self.favorites_util = FavoritesUtil(self.util)

        self.top_height = self.config[PLAYER_SCREEN][TOP_HEIGHT_PERCENT]
        self.bottom_height = self.config[PLAYER_SCREEN][BOTTOM_HEIGHT_PERCENT]
        self.button_height = self.config[PLAYER_SCREEN][BUTTON_HEIGHT_PERCENT]
        self.popup_width = self.config[PLAYER_SCREEN][POPUP_WIDTH_PERCENT]
        self.image_location = self.config[PLAYER_SCREEN][IMAGE_LOCATION]

        self.layout = self.get_layout()
        Screen.__init__(self, util, "", self.top_height, voice_assistant,
                        "station_screen_title", True, self.layout.TOP)
        self.layout = self.get_layout()

        folders = self.util.get_stations_folders()
        if folders:
            panel_layout = self.get_panel_layout(self.layout, LOCATION_RIGHT)
            panel_layout.set_percent_constraints(self.button_height,
                                                 self.button_height, 0, 0)
            self.genres = util.load_stations_folders(panel_layout.BOTTOM)
            self.genres[
                KEY_FAVORITES] = self.favorites_util.get_favorites_button_state(
                    panel_layout.BOTTOM)
            current_genre_name = list(self.genres.keys())[0]
            self.current_genre = self.genres[current_genre_name]
        self.items_per_line = self.items_per_line(self.layout.CENTER.w)
        items = []
        if self.screen_mode == STATION:
            k = STATIONS + "." + self.config[CURRENT][LANGUAGE]
            try:
                self.config[k]
                self.current_genre = self.genres[self.config[k]
                                                 [CURRENT_STATIONS]]
            except:
                self.config[k] = {}
                self.config[k][CURRENT_STATIONS] = self.current_genre.name
            items = self.load_stations(
                self.config[CURRENT][LANGUAGE], self.current_genre.name,
                self.items_per_line * self.items_per_line)
        elif self.screen_mode == STREAM:
            items = util.load_streams(self.items_per_line *
                                      self.items_per_line)

        self.playlist = Page(items, self.items_per_line, self.items_per_line)

        self.station_menu = StationMenu(
            self.playlist, util, screen_mode,
            self.config[BACKGROUND][SCREEN_BGR_COLOR], self.layout.CENTER)
        if self.station_menu.is_button_defined():
            d = {"current_title": self.station_menu.button.state.l_name}
            self.screen_title.set_text(d)
        Container.add_component(self, self.station_menu)

        self.stop_player = listeners[KEY_STOP]
        self.create_left_panel(self.layout, listeners)
        self.create_right_panel(self.layout, listeners)

        self.home_button.add_release_listener(listeners[KEY_HOME])
        if self.screen_mode == STATION:
            self.genres_button.add_release_listener(listeners[KEY_GENRES])
        self.shutdown_button.add_release_listener(
            self.favorites_util.save_favorites)
        self.shutdown_button.add_release_listener(listeners[KEY_SHUTDOWN])
        self.left_button.add_release_listener(
            self.station_menu.switch_to_previous_station)
        self.left_button.add_release_listener(self.update_arrow_button_labels)
        self.page_down_button.add_release_listener(
            self.station_menu.switch_to_previous_page)
        self.page_down_button.add_release_listener(
            self.update_arrow_button_labels)
        self.right_button.add_release_listener(
            self.station_menu.switch_to_next_station)
        self.right_button.add_release_listener(self.update_arrow_button_labels)
        self.page_up_button.add_release_listener(
            self.station_menu.switch_to_next_page)
        self.page_up_button.add_release_listener(
            self.update_arrow_button_labels)
        self.station_menu.add_listener(listeners[KEY_PLAY])
        self.station_menu.add_listener(self.screen_title.set_state)
        self.station_menu.add_listener(self.update_arrow_button_labels)
        self.station_menu.add_mode_listener(self.mode_listener)

        self.info_button = None
        self.info_popup = None
        self.start_screensaver = listeners[SCREENSAVER]
        bottom_layout = BorderLayout(self.layout.BOTTOM)
        bottom_layout.set_percent_constraints(0, 0, 0, self.popup_width)

        volume_layout = bottom_layout.CENTER
        volume_layout.w -= 2
        volume_layout.x += 1

        self.volume = self.factory.create_volume_control(volume_layout)
        self.volume.add_slide_listener(listeners[KEY_SET_VOLUME])
        self.volume.add_slide_listener(listeners[KEY_SET_CONFIG_VOLUME])
        self.volume.add_slide_listener(listeners[KEY_SET_SAVER_VOLUME])
        self.volume.add_knob_listener(listeners[KEY_MUTE])
        self.add_component(self.volume)
        self.player_screen = True

        self.add_popup(bottom_layout.RIGHT)

        if self.current_genre.name == KEY_FAVORITES:
            self.favorites_mode = True
        else:
            self.favorites_mode = False

        self.favorites_util.set_favorites_in_config(self.items_per_line)
        self.animated_title = True
Esempio n. 25
0
    def __init__(self, util, bounding_box, listeners, pages):
        """ Initializer

        :param util: utility object
        :param bounding_box: bounding box
        :param listeners: buttons listeners
        :param pages: number of Wi-Fi menu pages
        """
        Container.__init__(self, util)
        self.factory = Factory(util)
        self.name = "wifi.navigator"
        self.content = bounding_box
        self.content_x = bounding_box.x
        self.content_y = bounding_box.y
        self.menu_buttons = []

        bgr = util.config[COLORS][COLOR_DARK_LIGHT]

        arrow_layout = BorderLayout(bounding_box)
        arrow_layout.set_percent_constraints(0, 0, PERCENT_ARROW_WIDTH,
                                             PERCENT_ARROW_WIDTH)

        if pages > 1:
            constr = arrow_layout.LEFT
            self.left_button = self.factory.create_page_down_button(
                constr, "0", 40, 100)
            self.left_button.add_release_listener(listeners[GO_LEFT_PAGE])
            self.add_component(self.left_button)
            self.menu_buttons.append(self.left_button)

            constr = arrow_layout.RIGHT
            self.right_button = self.factory.create_page_up_button(
                constr, "0", 40, 100)
            self.right_button.add_release_listener(listeners[GO_RIGHT_PAGE])
            self.add_component(self.right_button)
            self.menu_buttons.append(self.right_button)
            layout = GridLayout(arrow_layout.CENTER)
        else:
            layout = GridLayout(bounding_box)

        layout.set_pixel_constraints(1, 5, 1, 0)
        layout.current_constraints = 0
        image_size = 64

        constr = layout.get_next_constraints()
        self.home_button = self.factory.create_button(
            KEY_HOME,
            KEY_HOME,
            constr,
            listeners[KEY_HOME],
            bgr,
            image_size_percent=image_size)
        self.add_component(self.home_button)
        self.menu_buttons.append(self.home_button)

        constr = layout.get_next_constraints()
        self.sort_strength = self.factory.create_button(
            KEY_REFRESH,
            KEY_SETUP,
            constr,
            listeners[KEY_REFRESH],
            bgr,
            image_size_percent=image_size)
        self.add_component(self.sort_strength)
        self.menu_buttons.append(self.sort_strength)

        constr = layout.get_next_constraints()
        self.sort_abc = self.factory.create_button(
            KEY_SORT,
            KEY_PARENT,
            constr,
            listeners[KEY_SORT],
            bgr,
            image_size_percent=image_size)
        self.add_component(self.sort_abc)
        self.menu_buttons.append(self.sort_abc)

        constr = layout.get_next_constraints()
        self.network_button = self.factory.create_button(
            KEY_NETWORK,
            KEY_BACK,
            constr,
            listeners[KEY_CALLBACK],
            bgr,
            image_size_percent=image_size)
        self.add_component(self.network_button)
        self.menu_buttons.append(self.network_button)

        constr = layout.get_next_constraints()
        self.player_button = self.factory.create_button(
            KEY_PLAYER,
            KEY_PLAY_PAUSE,
            constr,
            listeners[KEY_PLAYER],
            bgr,
            image_size_percent=image_size)
        self.add_component(self.player_button)
        self.menu_buttons.append(self.player_button)
Esempio n. 26
0
    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
Esempio n. 27
0
class Screen(Container):
    """ Base class for all screens. Extends Container class """
    def __init__(self,
                 util,
                 title_key,
                 percent_bottom_height=0,
                 voice_assistant=None,
                 screen_title_name="screen_title",
                 create_dynamic_title=False,
                 title_layout=None,
                 title=None):
        """ Initializer
        
        :param util: utility object
        :param title_key: the resource bundle key for the screen title
        """
        Container.__init__(self, util)
        self.util = util
        factory = Factory(util)
        self.config = util.config
        self.bounding_box = self.config[SCREEN_RECT]
        self.bgr = (0, 0, 0)
        self.layout = BorderLayout(self.config[SCREEN_RECT])
        self.layout.set_percent_constraints(PERCENT_TOP_HEIGHT,
                                            percent_bottom_height, 0, 0)
        self.voice_assistant = voice_assistant

        self.font_size = int((self.layout.TOP.h * PERCENT_TITLE_FONT) / 100.0)
        d = self.config[COLORS][COLOR_DARK_LIGHT]
        c = self.config[COLORS][COLOR_CONTRAST]

        t_layout = self.layout.TOP
        if title_layout:
            t_layout = title_layout

        if create_dynamic_title:
            self.screen_title = factory.create_dynamic_text(
                screen_title_name, t_layout, d, c, self.font_size)
        else:
            self.screen_title = factory.create_output_text(
                screen_title_name, t_layout, d, c, self.font_size)

        if title:
            self.screen_title.set_text(title)
        else:
            if title_key and len(title_key) > 0:
                try:
                    label = self.config[LABELS][title_key]
                    self.screen_title.set_text(label)
                except:
                    pass

        if voice_assistant:
            self.screen_title.add_select_listener(self.handle_voice_assistant)
            self.layout.TOP.w += 1
            self.voice_command = factory.create_output_text(
                "voice_command", self.layout.TOP, d, c, self.font_size)
            self.voice_command.add_select_listener(self.handle_voice_assistant)
            self.voice_assistant.add_text_recognized_listener(
                self.text_recognized)
            self.voice_assistant.assistant.add_start_conversation_listener(
                self.start_conversation)
            self.voice_assistant.assistant.add_stop_conversation_listener(
                self.stop_conversation)

        if voice_assistant and voice_assistant.is_running():
            self.title_selected = False
        else:
            self.title_selected = True

        self.draw_title_bar()
        self.player_screen = False
        self.update_web_observer = None
        self.update_web_title = None

    def draw_title_bar(self):
        """ Draw title bar on top of the screen """

        if len(self.components) != 0 and self.title_selected:
            self.components[0] = self.voice_command
            self.title_selected = False
        elif len(self.components) != 0 and not self.title_selected:
            self.components[0] = self.screen_title
            self.title_selected = True
        elif len(self.components) == 0 and self.title_selected:
            self.components.append(self.screen_title)
        elif len(self.components) == 0 and not self.title_selected:
            self.voice_command.set_text(
                self.config[LABELS][KEY_WAITING_FOR_COMMAND])
            self.components.append(self.voice_command)

    def handle_voice_assistant(self, state=None):
        """ Start/Stop voice assistant 
        
        :state: not used
        """
        if self.title_selected:
            self.voice_assistant.start()
        else:
            self.voice_assistant.stop()

    def text_recognized(self, text):
        """ Handle text recognized event 
        
        :text: recognized text
        """
        c = self.config[LABELS][KEY_VA_COMMAND] + " " + text
        self.voice_command.set_text(c)
        self.voice_command.clean_draw_update()
        if self.update_web_title:
            self.update_web_title(self.voice_command)

    def start_conversation(self, event):
        """ Start voice conversation
        
        :event: not used
        """
        if self.visible:
            self.voice_command.set_visible(True)
        self.voice_command.set_text_no_draw(
            self.config[LABELS][KEY_WAITING_FOR_COMMAND])
        self.components[0] = self.voice_command
        self.title_selected = False
        if self.visible:
            self.voice_command.clean_draw_update()
            if self.update_web_observer:
                self.update_web_observer()

    def stop_conversation(self):
        """ Stop voice conversation """

        if self.visible:
            self.screen_title.set_visible(True)
        self.components[0] = self.screen_title
        self.title_selected = True
        if self.visible:
            self.screen_title.clean_draw_update()
            if self.update_web_observer:
                self.update_web_observer()

    def add_menu(self, menu):
        """ Add menu to the screen
        
        :param menu: the menu to add
        """
        self.menu = menu
        self.add_component(menu)

    def enable_player_screen(self, flag):
        """ Enable player screen
        
        :param flag: enable/disable flag
        """
        pass

    def exit_screen(self):
        """ Complete actions required to save screen state """

        self.set_visible(False)

    def add_screen_observers(self,
                             update_observer,
                             redraw_observer,
                             title_to_json=None):
        """ Add screen observers.
        
        :param update_observer: observer for updating the screen
        :param redraw_observer: observer to redraw the whole screen
        """
        self.update_web_observer = redraw_observer
        self.update_web_title = title_to_json
Esempio n. 28
0
    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_keyboard = listeners[KEY_KEYBOARD_KEY]
        self.keyboard_callback = listeners[KEY_CALLBACK]

        self.wifi_selection_listeners = []

        self.wifi_util = WiFiUtil(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_WIFI, MENU_COLUMNS_WIFI]
        MenuScreen.__init__(self,
                            util,
                            listeners,
                            MENU_ROWS_WIFI,
                            MENU_COLUMNS_WIFI,
                            voice_assistant,
                            d,
                            self.turn_page,
                            page_in_title=False,
                            show_loading=False)
        self.title = self.config[LABELS]["select.wifi"]
        self.set_title(1)

        listeners[KEY_REFRESH] = self.set_current
        listeners[KEY_SORT] = self.sort_abc
        self.navigator = WiFiNavigator(self.util, self.layout.BOTTOM,
                                       listeners, PAGE_SIZE_WIFI + 1)
        self.add_component(self.navigator)
        self.network_button = self.navigator.get_button_by_name(KEY_NETWORK)

        m = self.factory.create_wifi_menu_button
        font_height = 32
        font_size = int(
            ((self.menu_layout.h / MENU_ROWS_WIFI) / 100) * font_height)
        self.wifi_menu = MultiPageMenu(util,
                                       self.next_page,
                                       self.previous_page,
                                       self.set_title,
                                       self.reset_title,
                                       self.go_to_page,
                                       m,
                                       MENU_ROWS_WIFI,
                                       MENU_COLUMNS_WIFI,
                                       None, (0, 0, 0),
                                       self.menu_layout,
                                       align=ALIGN_CENTER,
                                       font_size=font_size)
        self.set_menu(self.wifi_menu)

        self.original_networks = None
        self.networks = None
        self.sort_direction = False
        self.current_network = None
        self.link_borders()
Esempio n. 29
0
class FilePlayerScreen(Screen):
    """ File Player Screen """
    def __init__(self,
                 listeners,
                 util,
                 get_current_playlist,
                 voice_assistant,
                 player_stop=None):
        """ Initializer
        
        :param listeners: screen listeners
        :param util: utility object         
        """
        self.util = util
        self.config = util.config
        self.cdutil = CdUtil(util)
        self.factory = Factory(util)
        self.stop_player = player_stop
        self.get_current_playlist = get_current_playlist
        self.bounding_box = self.config[SCREEN_RECT]
        self.layout = BorderLayout(self.bounding_box)
        k = self.bounding_box.w / self.bounding_box.h
        percent_menu_width = (100.0 - PERCENT_TOP_HEIGHT -
                              PERCENT_BOTTOM_HEIGHT) / k
        panel_width = (100.0 - percent_menu_width) / 2.0
        self.layout.set_percent_constraints(PERCENT_TOP_HEIGHT,
                                            PERCENT_BOTTOM_HEIGHT, panel_width,
                                            panel_width)
        self.voice_assistant = voice_assistant
        Screen.__init__(self, util, "", PERCENT_TOP_HEIGHT, voice_assistant,
                        "file_player_screen_title", True, self.layout.TOP)
        self.layout = BorderLayout(self.bounding_box)
        self.layout.set_percent_constraints(PERCENT_TOP_HEIGHT,
                                            PERCENT_BOTTOM_HEIGHT, panel_width,
                                            panel_width)

        self.create_left_panel(self.layout, listeners)
        self.create_right_panel(self.layout, listeners)

        self.file_button = self.factory.create_file_button(
            self.layout.CENTER, listeners[AUDIO_FILES])

        Container.add_component(self, self.file_button)
        self.audio_files = self.get_audio_files()
        self.home_button.add_release_listener(listeners[KEY_HOME])
        self.shutdown_button.add_release_listener(listeners[KEY_SHUTDOWN])
        self.left_button.add_release_listener(self.go_left)
        self.right_button.add_release_listener(self.go_right)

        self.volume = self.factory.create_volume_control(self.layout.BOTTOM)
        self.volume.add_slide_listener(listeners[KEY_SET_VOLUME])
        self.volume.add_slide_listener(listeners[KEY_SET_CONFIG_VOLUME])
        self.volume.add_slide_listener(listeners[KEY_SET_SAVER_VOLUME])
        self.volume.add_knob_listener(listeners[KEY_MUTE])
        self.volume_visible = False
        self.volume.set_visible(self.volume_visible)
        Container.add_component(self, self.volume)

        self.time_control = self.factory.create_time_control(
            self.layout.BOTTOM)
        self.time_control.add_seek_listener(listeners[KEY_SEEK])

        self.play_button.add_listener(PAUSE, self.time_control.pause)
        self.play_button.add_listener(KEY_PLAY, self.time_control.resume)
        self.left_button.add_release_listener(
            self.play_button.draw_default_state)
        self.right_button.add_release_listener(
            self.play_button.draw_default_state)

        if self.config[PLAYER_SETTINGS][PAUSE]:
            self.time_control.pause()

        Container.add_component(self, self.time_control)

        self.play_listeners = []
        self.add_play_listener(listeners[KEY_PLAY])

        self.current_folder = self.config[FILE_PLAYBACK][CURRENT_FOLDER]
        self.file_button.state.cover_art_folder = self.util.file_util.get_cover_art_folder(
            self.current_folder)
        self.playlist_size = 0
        self.player_screen = True
        self.cd_album = None

    def get_audio_files(self):
        """ Return the list of audio files in current folder
        
        :return: list of audio files
        """
        files = []
        if self.config[CURRENT][MODE] == CD_PLAYER:
            af = getattr(self, "audio_files", None)
            if af == None:
                cd_drive_name = self.config[CD_PLAYBACK][CD_DRIVE_NAME]
                files = self.cdutil.get_cd_tracks_summary(cd_drive_name)
            else:
                return self.audio_files
        else:
            folder = self.config[FILE_PLAYBACK][CURRENT_FOLDER]
            files = self.util.get_audio_files_in_folder(folder)

        return files

    def get_current_track_index(self, state=None):
        """ Return current track index.
        In case of files goes through the file list.
        In case of playlist takes track index from the state object.
        
        :return: current track index
        """
        if self.config[CURRENT][MODE] == AUDIOBOOKS:
            t = None
            try:
                t = state["file_name"]
            except:
                pass

            if t == None:
                try:
                    t = state["current_title"]
                except:
                    pass

            if t == None:
                try:
                    t = state
                except:
                    pass

            for i, f in enumerate(self.audio_files):
                try:
                    s = f["file_name"]
                except:
                    pass

                if getattr(f, "file_name", None):
                    s = getattr(f, "file_name", None)

                if s.endswith(t):
                    return i
            return 0

        mode = self.config[FILE_PLAYBACK][CURRENT_FILE_PLAYBACK_MODE]
        if state and mode == FILE_PLAYLIST:
            try:
                n = state["Track"]
                if n: return int(n) - 1
            except:
                pass

        if self.config[CURRENT][MODE] == CD_PLAYER:
            cmp = int(self.config[CD_PLAYBACK][CD_TRACK]) - 1
        else:
            cmp = self.config[FILE_PLAYBACK][CURRENT_FILE]
            if state and isinstance(state, State):
                cmp = state.file_name

        for f in self.audio_files:
            if self.config[CURRENT][MODE] == CD_PLAYER:
                if f.index == cmp:
                    return f.index
            else:
                if f.file_name == cmp:
                    return f.index
        return 0

    def stop_recursive_playback(self):
        """ Stop recursive playback """

        self.config[FILE_PLAYBACK][CURRENT_FILE_PLAYBACK_MODE] = FILE_AUDIO
        self.config[FILE_PLAYBACK][CURRENT_FILE_PLAYLIST] = None
        self.config[FILE_PLAYBACK][CURRENT_TRACK_TIME] = None
        self.stop_timer()
        self.time_control.stop_thread()
        self.time_control.reset()
        if self.stop_player != None:
            self.stop_player()

    def go_left(self, state):
        """ Switch to the previous track
        
        :param state: not used state object
        """
        if getattr(self, "current_track_index", None) == None:
            return

        filelist_size = self.get_filelist_size()

        if self.config[FILE_PLAYBACK][
                CURRENT_FILE_PLAYBACK_MODE] == FILE_RECURSIVE:
            self.stop_recursive_playback()
            return

        if self.current_track_index == 0:
            self.current_track_index = filelist_size - 1
        else:
            self.current_track_index -= 1
        self.change_track(self.current_track_index)

    def go_right(self, state):
        """ Switch to the next track
        
        :param state: not used state object
        """
        if getattr(self, "current_track_index", None) == None:
            return

        filelist_size = self.get_filelist_size()

        if self.config[FILE_PLAYBACK][
                CURRENT_FILE_PLAYBACK_MODE] == FILE_RECURSIVE and self.current_track_index == filelist_size - 1:
            self.stop_timer()
            self.time_control.stop_thread()
            self.recursive_change_folder()
            self.current_track_index = 0
            self.change_track(self.current_track_index)
            self.file_button.clean_draw_update()
            return

        if self.current_track_index == filelist_size - 1:
            self.current_track_index = 0
        else:
            self.current_track_index += 1

        self.change_track(self.current_track_index)

    def get_filelist_size(self):
        """ Return the file list size
        
        :return: file list size
        """
        if self.audio_files:
            return len(self.audio_files)
        else:
            return 0

    def change_track(self, track_index):
        """ Change track
        
        :param track_index: index track
        """
        a = [AUDIOBOOKS, CD_PLAYER]
        m = self.config[CURRENT][MODE]
        if not (m in a):
            self.config[FILE_PLAYBACK][CURRENT_FILE] = self.get_filename(
                track_index)

        self.stop_timer()
        time.sleep(0.3)
        s = State()
        if m == FILE_PLAYBACK:
            s.playback_mode = self.config[FILE_PLAYBACK][
                CURRENT_FILE_PLAYBACK_MODE]

        s.playlist_track_number = track_index
        s.index = track_index
        s.source = ARROW_BUTTON
        s.file_name = self.get_filename(track_index)

        if self.cd_album != None:
            s.album = self.cd_album

        self.set_current(True, s)

    def stop_timer(self):
        """ Stop time control timer """

        self.time_control.stop_timer()

    def get_filename(self, index):
        """ Get filename by index
        
        :param index: file index
        
        :return: filename
        """
        for b in self.audio_files:
            if b.index == index:
                return b.file_name
        return ""

    def is_valid_mode(self):
        current_mode = self.config[CURRENT][MODE]
        modes = [AUDIO_FILES, AUDIOBOOKS, CD_PLAYER]
        if current_mode in modes:
            return True
        else:
            return False

    def update_arrow_button_labels(self, state=None):
        """ Update left/right arrow button labels
        
        :param state: state object representing current track
        """
        if (not self.is_valid_mode()) or (not self.screen_title.active): return

        self.set_current_track_index(state)
        left = self.current_track_index
        right = 0

        if self.audio_files and len(self.audio_files) > 1:
            right = len(self.audio_files) - self.current_track_index - 1

        self.left_button.change_label(str(left))
        self.right_button.change_label(str(right))

    def set_current_track_index(self, state):
        """ Set current track index
        
        :param state: state object representing current track
        """
        if not self.is_valid_mode(): return

        if self.config[CURRENT][MODE] == CD_PLAYER and getattr(
                state, "cd_track_id", None):
            self.config[CD_PLAYBACK][CD_TRACK] = state["cd_track_id"]

        self.current_track_index = 0

        if self.playlist_size == 1:
            return

        if not self.audio_files:
            self.audio_files = self.get_audio_files()
            if not self.audio_files: return

        i = self.get_current_track_index(state)
        self.current_track_index = i

    def create_left_panel(self, layout, listeners):
        """ Create left side buttons panel
        
        :param layout: panel layout 
        :param listeners: button listeners 
        """
        panel_layout = BorderLayout(layout.LEFT)
        panel_layout.set_percent_constraints(PERCENT_SIDE_BOTTOM_HEIGHT,
                                             PERCENT_SIDE_BOTTOM_HEIGHT, 0, 0)
        self.left_button = self.factory.create_left_button(
            panel_layout.CENTER, '', 40, 100)
        self.shutdown_button = self.factory.create_shutdown_button(
            panel_layout.TOP)
        self.home_button = self.factory.create_button(KEY_HOME,
                                                      KEY_HOME,
                                                      panel_layout.BOTTOM,
                                                      image_size_percent=36)
        panel = Container(self.util, layout.LEFT)
        panel.add_component(self.shutdown_button)
        panel.add_component(self.left_button)
        panel.add_component(self.home_button)
        Container.add_component(self, panel)

    def create_right_panel(self, layout, listeners):
        """ Create right side buttons panel
        
        :param layout: panel layout 
        :param listeners: button listeners 
        """
        panel_layout = BorderLayout(layout.RIGHT)
        panel_layout.set_percent_constraints(PERCENT_SIDE_BOTTOM_HEIGHT,
                                             PERCENT_SIDE_BOTTOM_HEIGHT, 0, 0)
        self.play_button = self.factory.create_play_pause_button(
            panel_layout.TOP, listeners[KEY_PLAY_PAUSE])
        self.right_button = self.factory.create_right_button(
            panel_layout.CENTER, '', 40, 100)
        self.time_volume_button = self.factory.create_time_volume_button(
            panel_layout.BOTTOM, self.toggle_time_volume)
        panel = Container(self.util, layout.RIGHT)
        panel.add_component(self.play_button)
        panel.add_component(self.right_button)
        panel.add_component(self.time_volume_button)
        Container.add_component(self, panel)

    def toggle_time_volume(self):
        """ Switch between time and volume controls """

        if self.volume_visible:
            self.volume.set_visible(False)
            self.time_control.set_visible(True)
            self.volume_visible = False
        else:
            volume_level = int(self.config[PLAYER_SETTINGS][VOLUME])
            self.volume.set_position(volume_level)
            self.volume.update_position()
            self.volume.set_visible(True)
            self.time_control.set_visible(False)
            self.volume_visible = True
        self.clean_draw_update()

    def eject_cd(self, state):
        """ Eject CD
        
        :param state: button state object
        """
        self.audio_files = []
        self.screen_title.set_text(" ")
        self.update_arrow_button_labels(state)
        self.time_control.reset()
        self.cd_album = None
        self.set_cd_album_art_image()

    def set_current(self, new_track=False, state=None):
        """ Set current file or playlist
        
        :param new_track: True - new audio file
        """
        self.cd_album = getattr(state, "album", None)

        if self.config[CURRENT][MODE] == AUDIO_FILES:
            state.full_screen_image = self.set_audio_file_image()
        elif self.config[CURRENT][MODE] == CD_PLAYER and getattr(
                state, "source", None) != INIT:
            state.full_screen_image = self.set_cd_album_art_image()
            state.image_base = self.file_button.components[1].content

        config_volume_level = int(self.config[PLAYER_SETTINGS][VOLUME])
        if state:
            state.volume = config_volume_level

        self.set_audio_file(new_track, state)

        if self.volume.get_position() != config_volume_level:
            self.volume.set_position(config_volume_level)
            self.volume.update_position()

    def set_audio_file_image(self):
        """ Set audio file image """

        f = self.config[FILE_PLAYBACK][CURRENT_FOLDER]
        if not f: return None

        img_tuple = self.util.get_audio_file_icon(f, self.bounding_box)
        self.set_file_button(img_tuple)

        return img_tuple[1]

    def set_cd_album_art_image(self):
        """ Set CD album art image """

        img_tuple = self.util.get_cd_album_art(self.cd_album,
                                               self.bounding_box)
        if img_tuple == None:
            return None
        self.set_file_button(img_tuple)
        self.file_button.clean_draw_update()

        return img_tuple[1]

    def set_file_button(self, img_tuple):
        """ Set image in file button
        
        :param img_tuple: tuple where first element is image location, second element image itself 
        """
        full_screen_image = img_tuple[1]
        self.file_button.state.full_screen_image = full_screen_image

        scale_ratio = self.util.get_scale_ratio(
            (self.layout.CENTER.w, self.layout.CENTER.h), full_screen_image)
        img = self.util.scale_image(full_screen_image, scale_ratio)

        self.file_button.components[1].content = img
        self.file_button.state.icon_base = img
        self.file_button.components[
            1].image_filename = self.file_button.state.image_filename = img_tuple[
                0]

        self.file_button.components[1].content_x = self.layout.CENTER.x + (
            self.layout.CENTER.w - img.get_size()[0]) / 2

        if self.layout.CENTER.h > img.get_size()[1]:
            self.file_button.components[
                1].content_y = self.layout.CENTER.y + int(
                    (self.layout.CENTER.h - img.get_size()[1]) / 2) + 1
        else:
            self.file_button.components[1].content_y = self.layout.CENTER.y

    def set_audio_file(self, new_track, s=None):
        """ Set new audio file
        
        :param new_track: True - new audio file
        "param s" button state object
        """
        state = State()

        if s:
            state.playback_mode = getattr(s, "playback_mode", FILE_AUDIO)
            state.playlist_track_number = getattr(s, "playlist_track_number",
                                                  None)
            if self.config[CURRENT][MODE] == CD_PLAYER and getattr(
                    s, "source", None) != INIT:
                image_base = getattr(s, "image_base", None)
                if image_base != None:
                    state.image_base = image_base
        else:
            m = self.config[FILE_PLAYBACK][CURRENT_FILE_PLAYBACK_MODE]
            if m:
                state.playback_mode = m
            else:
                state.playback_mode = FILE_AUDIO

        if self.config[CURRENT][MODE] == AUDIO_FILES:
            self.current_folder = self.config[FILE_PLAYBACK][CURRENT_FOLDER]
            if not self.current_folder:
                return
            state.folder = self.current_folder
            state.file_name = self.config[FILE_PLAYBACK][CURRENT_FILE]
            if state.folder[-1] == os.sep:
                state.folder = state.folder[:-1]

            if os.sep in state.file_name:
                state.url = "\"" + state.file_name + "\""
            else:
                state.url = "\"" + state.folder + os.sep + state.file_name + "\""

            state.music_folder = self.config[AUDIO][MUSIC_FOLDER]
        elif self.config[CURRENT][MODE] == CD_PLAYER:
            state.file_name = s.file_name
            state.url = getattr(s, "url", s.file_name)
            parts = s.file_name.split()
            self.config[CD_PLAYBACK][CD_DRIVE_NAME] = parts[0][len("cdda:///"
                                                                   ):]
            id = self.cdutil.get_cd_drive_id_by_name(
                self.config[CD_PLAYBACK][CD_DRIVE_NAME])
            self.config[CD_PLAYBACK][CD_DRIVE_ID] = int(id)
            self.config[CD_PLAYBACK][CD_TRACK] = int(parts[1].split("=")[1])

        state.mute = self.config[PLAYER_SETTINGS][MUTE]
        state.pause = self.config[PLAYER_SETTINGS][PAUSE]
        state.file_type = FILE_AUDIO
        state.dont_notify = True
        state.source = FILE_AUDIO

        if self.config[FILE_PLAYBACK][
                CURRENT_FILE_PLAYBACK_MODE] == FILE_AUDIO or self.config[
                    CURRENT][MODE] == CD_PLAYER:
            self.audio_files = self.get_audio_files()
        elif self.config[FILE_PLAYBACK][
                CURRENT_FILE_PLAYBACK_MODE] == FILE_PLAYLIST:
            state.file_name = self.config[FILE_PLAYBACK][CURRENT_FILE_PLAYLIST]
            self.load_playlist(state)
            state.file_name = self.config[FILE_PLAYBACK][CURRENT_FILE]
            self.audio_files = self.get_audio_files_from_playlist()
            state.playback_mode = FILE_PLAYLIST
            n = getattr(s, "file_name", None)
            if n:
                state.file_name = n

            try:
                state.playlist_track_number = int(state.file_name) - 1
            except:
                state.playlist_track_number = self.get_current_track_index(
                    state)

        source = None
        if s:
            source = getattr(s, "source", None)

        if new_track:
            tt = 0.0
        else:
            if self.config[CURRENT][MODE] == CD_PLAYER:
                tt = self.config[CD_PLAYBACK][CD_TRACK_TIME]
            else:
                tt = self.config[FILE_PLAYBACK][CURRENT_TRACK_TIME]

        if (isinstance(tt, str) and len(tt) != 0) or (
                isinstance(tt, float) or
            (source and source == RESUME)) or isinstance(tt, int):
            state.track_time = tt

        self.time_control.slider.set_position(0)

        if self.file_button and self.file_button.components[
                1] and self.file_button.components[1].content:
            state.icon_base = self.file_button.components[1].content

        if s and s.volume:
            state.volume = s.volume

        if self.config[CURRENT][MODE] == CD_PLAYER and s and getattr(
                s, "source", None) == INIT:
            try:
                self.cd_album = self.util.cd_titles[self.config[CD_PLAYBACK]
                                                    [CD_DRIVE_NAME]]
                self.set_cd_album_art_image()
                state.image_base = self.file_button.components[1].content
            except:
                self.cd_album = None

        if getattr(s, "full_screen_image", None) != None:
            state.full_screen_image = s.full_screen_image

        self.notify_play_listeners(state)

    def get_audio_files_from_playlist(self):
        """ Call player for files in the playlist 
        
        :return: list of files from playlist
        """
        playlist = self.get_current_playlist()
        files = []
        if playlist:
            for n in range(len(playlist)):
                st = State()
                st.index = st.comparator_item = n
                st.file_type = FILE_AUDIO
                st.file_name = playlist[n]
                files.append(st)
        return files

    def restore_current_folder(self, state=None):
        """ Set current folder in config object
        
        :param state: not used
        """
        self.config[FILE_PLAYBACK][CURRENT_FOLDER] = self.current_folder

    def set_audio_file_playlist(self, index):
        """ Set file in playlist
        
        :param index: file index in playlist
        """
        state = State()
        state.playback_mode = FILE_PLAYLIST
        state.playlist_track_number = index
        state.file_type = FILE_AUDIO
        self.current_folder = self.config[FILE_PLAYBACK][CURRENT_FOLDER]
        self.notify_play_listeners(state)

    def go_back(self):
        """ Go back """

        if self.config[CURRENT][MODE] == CD_PLAYER:
            return

        img_tuple = self.util.get_audio_file_icon(self.current_folder,
                                                  self.layout.CENTER)
        img = img_tuple[1]
        self.file_button.components[1].content = img
        self.file_button.state.icon_base = img_tuple

        self.file_button.components[1].content_x = self.layout.CENTER.x
        if self.layout.CENTER.h > img.get_size()[1]:
            self.file_button.components[
                1].content_y = self.layout.CENTER.y + int(
                    (self.layout.CENTER.h - img.get_size()[1]) / 2)
        else:
            self.file_button.components[1].content_y = self.layout.CENTER.y

    def recursive_change_folder(self):
        start_folder = self.config[FILE_PLAYBACK][CURRENT_FILE_PLAYLIST]
        current_folder = self.config[FILE_PLAYBACK][CURRENT_FOLDER]
        f = self.util.file_util.get_next_folder_with_audio_files(
            start_folder, current_folder)
        if f == None or (f != None and f[0] == None):
            self.config[FILE_PLAYBACK][CURRENT_FILE_PLAYBACK_MODE] = FILE_AUDIO
            self.config[FILE_PLAYBACK][CURRENT_FILE_PLAYLIST] = None
            return False

        self.config[FILE_PLAYBACK][CURRENT_FOLDER] = f[0]
        self.config[FILE_PLAYBACK][CURRENT_FILE] = f[1]
        self.config[FILE_PLAYBACK][CURRENT_TRACK_TIME] = None
        state = State()
        state.file_type = FOLDER
        state.url = f[0]
        state.long_press = True
        state.playback_mode = FILE_RECURSIVE
        self.current_track_index = 0
        state.dont_notify = True
        self.audio_files = self.get_audio_files()
        self.recursive_notifier(f[0])
        return True

    def end_of_track(self):
        """ Handle end of track """

        if not self.screen_title.active:
            return

        i = getattr(self, "current_track_index", None)
        if i == None: return
        self.stop_timer()
        mode = self.config[CURRENT][MODE]
        if mode == RADIO or mode == STREAM or not self.audio_files:
            return

        self.time_control.stop_thread()

        if self.config[AUTO_PLAY_NEXT_TRACK]:
            if self.current_track_index == len(self.audio_files) - 1:
                if self.config[FILE_PLAYBACK][
                        CURRENT_FILE_PLAYBACK_MODE] == FILE_RECURSIVE:
                    if not self.recursive_change_folder():
                        self.stop_recursive_playback()
                        return
                elif self.config[CYCLIC_PLAYBACK]:
                    self.current_track_index = 0
            else:
                self.current_track_index += 1

            if mode == AUDIO_FILES:
                self.config[FILE_PLAYBACK][CURRENT_TRACK_TIME] = None
            elif mode == AUDIOBOOKS:
                self.config[AUDIOBOOKS][BROWSER_BOOK_TIME] = None

            self.change_track(self.current_track_index)

            if self.config[FILE_PLAYBACK][
                    CURRENT_FILE_PLAYBACK_MODE] == FILE_RECURSIVE:
                self.file_button.clean_draw_update()

    def set_playlist_size(self, size):
        """ Set playlist size
        
        :param size: playlist size
        """
        self.playlist_size = size
        self.stop_timer()

    def set_visible(self, flag):
        """ Set visibility flag
         
        :param flag: True - screen visible, False - screen invisible
        """
        Container.set_visible(self, flag)

        if flag:
            if self.volume_visible:
                self.volume.set_visible(True)
                self.time_control.set_visible(False)
            else:
                self.volume.set_visible(False)
                self.time_control.set_visible(True)

    def add_play_listener(self, listener):
        """ Add play listener
        
        :param listener: event listener
        """
        if listener not in self.play_listeners:
            self.play_listeners.append(listener)

    def notify_play_listeners(self, state):
        """ Notify all play listeners
        
        :param state: button state
        """
        if not self.screen_title.active:
            return

        m = getattr(state, "playback_mode", None)
        if m != None and m != FILE_PLAYLIST:
            state.icon_base = self.file_button.state.icon_base
        folder = getattr(state, "folder", None)
        if folder:
            state.cover_art_folder = self.util.file_util.get_cover_art_folder(
                state.folder)

        for listener in self.play_listeners:
            listener(state)

    def enable_player_screen(self, flag):
        """ Enable player screen
        
        :param flag: enable/disable flag
        """
        self.screen_title.active = flag
        self.time_control.active = flag

    def add_screen_observers(self, update_observer, redraw_observer,
                             start_time_control, stop_time_control,
                             title_to_json):
        """ Add screen observers
        
        :param update_observer: observer for updating the screen
        :param redraw_observer: observer to redraw the whole screen
        :param start_time_control:
        :param stop_time_control:
        :param title_to_json:
        """
        Screen.add_screen_observers(self, update_observer, redraw_observer,
                                    title_to_json)

        self.add_button_observers(self.shutdown_button,
                                  update_observer,
                                  redraw_observer=None)
        self.shutdown_button.add_cancel_listener(redraw_observer)
        self.screen_title.add_listener(redraw_observer)

        self.add_button_observers(self.play_button,
                                  update_observer,
                                  redraw_observer=None)
        self.add_button_observers(self.home_button, update_observer,
                                  redraw_observer)

        self.add_button_observers(self.left_button,
                                  update_observer,
                                  redraw_observer=None)
        self.left_button.add_label_listener(update_observer)
        self.add_button_observers(self.right_button,
                                  update_observer,
                                  redraw_observer=None)
        self.right_button.add_label_listener(update_observer)

        self.volume.add_slide_listener(update_observer)
        self.volume.add_knob_listener(update_observer)
        self.volume.add_press_listener(update_observer)
        self.volume.add_motion_listener(update_observer)

        self.add_button_observers(self.time_volume_button,
                                  update_observer,
                                  redraw_observer,
                                  release=False)
        self.add_button_observers(self.file_button,
                                  update_observer,
                                  redraw_observer,
                                  press=False,
                                  release=False)

        self.time_control.web_seek_listener = update_observer
        self.time_control.add_start_timer_listener(start_time_control)
        self.time_control.add_stop_timer_listener(stop_time_control)
        self.time_control.slider.add_slide_listener(update_observer)
        self.time_control.slider.add_knob_listener(update_observer)
        self.time_control.slider.add_press_listener(update_observer)
        self.time_control.slider.add_motion_listener(update_observer)
Esempio n. 30
0
    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.factory = Factory(util)
        self.check_internet_connectivity = listeners[KEY_CHECK_INTERNET]
        self.go_home = listeners[KEY_HOME]
        self.set_modes = listeners[KEY_SET_MODES]
        self.linux = self.config[LINUX_PLATFORM]

        self.wifi_util = WiFiUtil(util)
        self.bluetooth_util = self.util.get_bluetooth_util()

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

        rows = 7
        columns = 1
        d = [rows, columns]
        MenuScreen.__init__(self,
                            util,
                            listeners,
                            rows,
                            columns,
                            voice_assistant,
                            d,
                            None,
                            page_in_title=False,
                            show_loading=False)
        self.title = self.config[LABELS]["network"]
        self.set_title(1)

        center_layout = BorderLayout(self.menu_layout)
        center_layout.set_percent_constraints(0, 0, 47, 0)

        left_layout = center_layout.LEFT
        right_layout = center_layout.CENTER

        label_layout = GridLayout(left_layout)
        label_layout.set_pixel_constraints(rows, columns)
        label_layout.get_next_constraints()

        value_layout = GridLayout(right_layout)
        value_layout.set_pixel_constraints(rows, columns)
        value_layout.get_next_constraints()

        self.network_panel = Container(util, self.menu_layout, (100, 0, 0))

        rect = pygame.Rect(self.menu_layout.x, self.menu_layout.y + 1,
                           self.menu_layout.w, self.menu_layout.h - 1)
        bgr = Component(util, rect, 0, 0, self.menu_layout, (0, 0, 0),
                        self.util.config[COLORS][COLOR_DARK])
        bgr.name = "network.panel.bgr"
        self.network_panel.add_component(bgr)

        self.internet_label = self.add_label(label_layout, self.network_panel,
                                             1)
        self.ethernet_label = self.add_label(label_layout, self.network_panel,
                                             2)
        self.wifi_network_label = self.add_label(label_layout,
                                                 self.network_panel, 3)
        self.wifi_ip_label = self.add_label(label_layout, self.network_panel,
                                            4)
        self.bluetooth_label = self.add_label(label_layout, self.network_panel,
                                              5)

        self.internet = self.add_value(value_layout, self.network_panel, 1)
        self.ethernet_ip = self.add_value(value_layout, self.network_panel, 2)
        self.wifi_network = self.add_value(value_layout, self.network_panel, 3)
        self.wifi_ip = self.add_value(value_layout, self.network_panel, 4)
        self.bluetooth = self.add_value(value_layout, self.network_panel, 5)

        self.set_menu(self.network_panel)

        listeners[KEY_REFRESH] = self.set_current
        listeners[KEY_DISCONNECT] = self.disconnect_wifi
        listeners[KEY_BLUETOOTH_REMOVE] = self.remove_bluetooth_devices

        self.navigator = NetworkNavigator(self.util, self.layout.BOTTOM,
                                          listeners)
        self.components.append(self.navigator)
        self.original_networks = None
        self.networks = None
        self.current_network = None
        self.current_wifi_network = None
        self.clicked = False
Esempio n. 31
0
class TopicNavigator(Container):
    """ Collection topic navigator """

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

        :param util: utility object
        :param bounding_box: bounding box
        :param listeners: buttons listeners
        """
        Container.__init__(self, util)
        self.factory = Factory(util)
        self.name = "collection.navigator"
        self.content = bounding_box
        self.content_x = bounding_box.x
        self.content_y = bounding_box.y
        self.listeners = listeners
        self.menu_buttons = []
        self.config = util.config
        self.use_web = self.config[USAGE][USE_WEB]
        self.go_abc = listeners[KEY_ABC]
        self.go_keyboard = listeners[KEY_KEYBOARD_KEY]
        self.keyboard_callback = listeners[KEY_CALLBACK]
        self.bgr = util.config[COLORS][COLOR_DARK_LIGHT]
        self.arrow_layout = BorderLayout(bounding_box)
        self.arrow_layout.set_percent_constraints(0, 0, PERCENT_ARROW_WIDTH, PERCENT_ARROW_WIDTH)
        self.collection_topic = None
        self.update_observer = None
        self.redraw_observer = None

    def set_buttons(self, topic):
        """ Set navigator buttons depending on topic

        :param topic: collection topic
        """
        if self.collection_topic == topic:
            return

        if self.menu_buttons and topic in TEXT_TOPICS and self.collection_topic in TEXT_TOPICS:
            self.collection_topic = topic
            return 

        self.collection_topic = topic
        self.components = []
        self.menu_buttons = []

        constr = self.arrow_layout.LEFT
        self.left_button = self.factory.create_page_down_button(constr, "0", 40, 100)
        self.left_button.add_release_listener(self.listeners[GO_LEFT_PAGE])
        self.add_component(self.left_button)
        self.menu_buttons.append(self.left_button)

        constr = self.arrow_layout.RIGHT
        self.right_button = self.factory.create_page_up_button(constr, "0", 40, 100)
        self.right_button.add_release_listener(self.listeners[GO_RIGHT_PAGE])
        self.add_component(self.right_button)
        self.menu_buttons.append(self.right_button)

        if topic in TEXT_TOPICS:
            n = 7
        elif topic == TYPE:
            n = 5
        else:
            n = 6
        layout = GridLayout(self.arrow_layout.CENTER)
        layout.set_pixel_constraints(1, n, 1, 0)
        layout.current_constraints = 0

        self.add_button(KEY_HOME, KEY_HOME, layout, self.listeners[KEY_HOME])
        self.add_button(KEY_BACK, KEY_BACK, layout, self.listeners[KEY_BACK])
        self.add_button(COLLECTION, KEY_PARENT, layout, self.listeners[COLLECTION])
        self.add_button(KEY_LIST, KEY_MENU, layout, self.listeners[KEY_LIST])

        if n == 7:
            self.add_button(IMAGE_ABC, KEY_SETUP, layout, self.pre_abc)
        if n != 5:
            self.add_button(IMAGE_BOOK_GENRE, KEY_ROOT, layout, self.pre_keyboard)
        self.add_button(KEY_PLAYER, KEY_PLAY_PAUSE, layout, self.listeners[KEY_PLAYER])

        if self.use_web and self.update_observer != None:
            self.add_observers(self.update_observer, self.redraw_observer)

    def add_button(self, img_name, key, layout, listener):
        """ Add button to the navigator

        :param img_name: button image name
        :param key: keyboard key
        :param layout: button layout
        :param listener: button listener
        """
        c = layout.get_next_constraints()
        b = self.factory.create_button(img_name, key, c, listener, self.bgr, source="navigator", image_size_percent=IMAGE_SIZE_PERCENT)
        self.add_component(b)
        self.menu_buttons.append(b)

    def pre_abc(self, state=None):
        """ Set state parameters and go to ABC screen

        :param state: button state
        """
        state.title = self.config[LABELS][self.collection_topic]
        state.visibility = False
        state.callback = self.keyboard_callback
        self.go_abc(state)

    def pre_keyboard(self, state=None):
        """ Set state parameters and go to Keyboard screen

        :param state: button state
        """
        state.title = self.config[LABELS][self.collection_topic]
        state.visibility = False
        state.callback = self.keyboard_callback
        self.go_keyboard(state)

    def add_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
        """
        if self.update_observer == None:
            self.update_observer = update_observer
            self.redraw_observer = redraw_observer

        for b in self.menu_buttons:
            self.add_button_observers(b, update_observer, redraw_observer)
Esempio n. 32
0
    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_network = listeners[KEY_NETWORK]
        self.go_player = listeners[KEY_PLAYER]

        self.wifi_selection_listeners = []

        self.bluetooth_util = self.util.get_bluetooth_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_BLUETOOTH, MENU_COLUMNS_BLUETOOTH]
        MenuScreen.__init__(self,
                            util,
                            listeners,
                            MENU_ROWS_BLUETOOTH,
                            MENU_COLUMNS_BLUETOOTH,
                            voice_assistant,
                            d,
                            self.turn_page,
                            page_in_title=False,
                            show_loading=False)
        self.title = self.config[LABELS]["select.bluetooth.device"]
        self.set_title(1)

        listeners[KEY_HOME] = self.before_home
        listeners[KEY_NETWORK] = self.before_network
        listeners[KEY_PLAYER] = self.before_player
        listeners[KEY_REFRESH] = self.set_current

        self.navigator = BluetoothNavigator(self.util, self.layout.BOTTOM,
                                            listeners, PAGE_SIZE_BLUETOOTH + 1)
        self.add_navigator(self.navigator)
        self.network_button = self.navigator.get_button_by_name(KEY_NETWORK)
        self.left_button = self.navigator.get_button_by_name(KEY_PAGE_DOWN)
        self.right_button = self.navigator.get_button_by_name(KEY_PAGE_UP)

        m = self.factory.create_wifi_menu_button
        font_height = 32
        font_size = int(
            ((self.menu_layout.h / MENU_ROWS_BLUETOOTH) / 100) * font_height)
        self.bluetooth_menu = MultiPageMenu(util,
                                            self.next_page,
                                            self.previous_page,
                                            self.set_title,
                                            self.reset_title,
                                            self.go_to_page,
                                            m,
                                            MENU_ROWS_BLUETOOTH,
                                            MENU_COLUMNS_BLUETOOTH,
                                            None, (0, 0, 0),
                                            self.menu_layout,
                                            align=ALIGN_LEFT,
                                            font_size=font_size)
        self.set_menu(self.bluetooth_menu)

        self.devices = None
        self.networks = None
        self.sort_direction = False
        self.current_device = None
Esempio n. 33
0
    def __init__(self, util, name, bgr, slider_color, img_knob, img_knob_on,
                 key_incr, key_decr, key_knob, bb):
        """ Initializer
        
        :param util: utility object
        :param name: slider name
        :param bgr: slider background color
        :param slider_color: slider center line color
        :param img_knob: knob image
        :param img_knob_on: knob image in on state
        :param key_incr: keyboard key associated with slider increment action
        :param key_decr: keyboard key associated with slider decrement action
        :param key_knob: keyboard key associated with single click on knob
        :param bb: slider bounding box
        """
        Container.__init__(self, util, background=bgr, bounding_box=bb)
        self.util = util
        self.config = util.config

        self.lock = RLock()
        self.CURRENT_TIME_LAYER = 3
        self.TOTAL_TIME_LAYER = 2
        # don't increase the following number too much as it affects UV Meter screen-saver performance
        self.LOOP_CYCLES_PER_SECOND = 5
        self.CYCLE_TIME = 1 / self.LOOP_CYCLES_PER_SECOND

        self.active = True
        comp = Component(self.util, bb)
        comp.name = name + "bgr"
        comp.bgr = bgr
        self.add_component(comp)

        layout = BorderLayout(bb)
        layout.set_percent_constraints(0.0, 0.0, 20.0, 20.0)

        self.current_time_name = name + "current"
        self.total_time_name = name + "total"
        self.current_time_layout = layout.LEFT
        self.total_time_layout = layout.RIGHT

        self.slider = Slider(util, name + "slider", bgr, slider_color,
                             img_knob, img_knob_on, None, key_incr, key_decr,
                             key_knob, layout.CENTER, False)
        self.slider.add_slide_listener(self.slider_action_handler)
        self.total_track_time = 0
        self.seek_time = 0
        self.add_component(self.slider)

        c = Component(self.util, None)  # init total time layer
        self.add_component(c)
        c = Component(self.util, None)  # init current time layer
        self.add_component(c)

        self.seek_listeners = []
        self.start_timer_listeners = []
        self.stop_timer_listeners = []
        self.update_seek_listeners = True
        self.use_web = self.config[USAGE][USE_WEB]

        self.stop_timer()
        thread = Thread(target=self.start_loop)
        thread.start()
Esempio n. 34
0
    def __init__(self, util):
        """ Initializer
        
        :param util: utility object
        """        
        self.util = util
        self.config = util.config
        self.config_class = util.config_class
        factory = Factory(util)
        self.name = "about.screen"

        self.color_web_bgr = self.config[COLORS][COLOR_WEB_BGR]
        color_logo = self.config[COLORS][COLOR_CONTRAST]
        color_status = self.config[COLORS][COLOR_LOGO]
        opacity = self.config[BACKGROUND][MENU_BGR_OPACITY]
        c = (self.color_web_bgr[0], self.color_web_bgr[1], self.color_web_bgr[2], opacity)
        
        cont = util.screen_rect
        img_filename = None
        bg = self.util.get_background("about", c)

        self.bgr_type = bg[0]
        if bg[2]:
            self.bgr = bg[1]
            cont = bg[2]
        else:
            self.bgr = (bg[1][0], bg[1][1], bg[1][2])
        
        img_filename = bg[3]
        self.bgr_key = bg[5]
            
        Container.__init__(self, util, bounding_box=util.screen_rect, background=self.color_web_bgr, content=cont, image_filename=img_filename)
        
        self.start_listeners = []
        
        self.installed_release = self.config[RELEASE]
        self.installed_edition = self.installed_release[EDITION_NAME]
        self.installed_year = self.installed_release[RELEASE_YEAR]
        self.installed_month = self.installed_release[RELEASE_MONTH]
        self.installed_day = self.installed_release[RELEASE_DAY]
        
        layout = BorderLayout(self.bounding_box)
        layout.set_percent_constraints(0, PERCENT_FOOTER_HEIGHT, 0, 0)
        font_size = int((layout.BOTTOM.h * PERCENT_FOOTER_FONT)/100.0)

        button = factory.create_image_button("peppy", bounding_box=layout.CENTER, bgr=bg[1], image_size_percent=68, selected=False)
        if bg[2]:
            button.parent_screen = bg[2]
        else:
            button.parent_screen = layout.CENTER
        x = layout.CENTER.w/2 - button.components[1].content.get_size()[0]/2
        y = layout.CENTER.h/2 - button.components[1].content.get_size()[1]/2        
        button.components[1].content_x = x
        button.components[1].content_y = y
        self.add_component(button)
        
        bottom_bgr = pygame.Rect(layout.BOTTOM.x, layout.BOTTOM.y - 1, layout.BOTTOM.w, layout.BOTTOM.h + 2)
        comp = Component(self.util, bottom_bgr, bb=bottom_bgr, bgr=bg[1])
        comp.name = "txt.bgr"
        self.add_component(comp)

        text_layout = pygame.Rect(layout.BOTTOM.x, layout.BOTTOM.y - int((self.bounding_box.h * 5) / 100), layout.BOTTOM.w, layout.BOTTOM.h)

        if self.util.connected_to_internet and self.config[USAGE][USE_CHECK_FOR_UPDATES]:
            bottom_layout = GridLayout(text_layout)
            bottom_layout.set_pixel_constraints(2, 1)
            line_top = bottom_layout.get_next_constraints()
            line_bottom = bottom_layout.get_next_constraints()
        else:
            line_top = text_layout

        transparent = (0, 0, 0, 0)
        self.release = factory.create_output_text("installed", line_top, transparent, color_logo, font_size, full_width=True, valign=V_ALIGN_BOTTOM)
        self.release.parent_screen = bg[2]
        if bg[2]:
            self.release.parent_screen = bg[2]
        else:
            self.release.parent_screen = line_top
        self.add_component(self.release)

        if self.util.connected_to_internet and self.config[USAGE][USE_CHECK_FOR_UPDATES]:
            self.status = factory.create_output_text("status", line_bottom, transparent, color_status, font_size, full_width=True, valign=V_ALIGN_TOP)
            self.status.parent_screen = bg[2]
            self.add_component(self.status)
            self.new_release = self.get_new_release()
Esempio n. 35
0
    def __init__(self, util, bounding_box, name, items, arrow_items=None):
        """ Initializer
        
        :param util: utility object
        :param bounding_box: bounding box
        :param name: navigator name
        :param items: dictionary with button details
        :param arrow_items: dictionary with arrow buttons details
        """
        Container.__init__(self, util)
        self.factory = Factory(util)
        self.name = name
        self.content = bounding_box
        self.content_x = bounding_box.x
        self.content_y = bounding_box.y
        self.buttons = []

        if arrow_items:
            arrow_layout = BorderLayout(bounding_box)
            left_arrow = arrow_items[0]
            listeners = left_arrow[LISTENER]
            arrow_layout.set_percent_constraints(0, 0, PERCENT_ARROW_WIDTH,
                                                 PERCENT_ARROW_WIDTH)
            constr = arrow_layout.LEFT
            button = self.factory.create_page_down_button(constr, "0", 40, 100)
            button.add_release_listener(listeners[0])
            self.add_component(button)
            self.buttons.append(button)
            layout = GridLayout(arrow_layout.CENTER)
        else:
            layout = GridLayout(bounding_box)

        layout.set_pixel_constraints(1, len(items), 1, 0)
        layout.current_constraints = 0
        image_size = 64
        b = util.config[BACKGROUND][FOOTER_BGR_COLOR]

        for item in items:
            constr = layout.get_next_constraints()
            image_name = item[IMAGE_NAME]
            listeners = item[LISTENER]
            keybiard_key = item[KEYBOARD_KEY]
            source = item[SOURCE]

            if len(listeners) == 1:
                button = self.factory.create_button(
                    image_name,
                    keybiard_key,
                    constr,
                    listeners[0],
                    b,
                    image_size_percent=image_size,
                    source=source)
            else:
                button = self.factory.create_button(
                    image_name,
                    keybiard_key,
                    constr,
                    None,
                    b,
                    image_size_percent=image_size,
                    source=source)
                for listener in listeners:
                    button.add_release_listener(listener)

            self.add_component(button)
            self.buttons.append(button)

        if arrow_items:
            right_arrow = arrow_items[1]
            listeners = right_arrow[LISTENER]
            constr = arrow_layout.RIGHT
            button = self.factory.create_page_up_button(constr, "0", 40, 100)
            button.add_release_listener(listeners[0])
            self.add_component(button)
            self.buttons.append(button)