Ejemplo n.º 1
0
    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 = util.screen_rect
        self.bgr = (0, 0, 0)
        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)
        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

        self.loading_listeners = []
        self.LOADING = util.config[LABELS][KEY_LOADING]
Ejemplo n.º 2
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
Ejemplo n.º 3
0
class StationScreen(Container):
    """ Station Screen. Extends Container class """
    
    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)
    
    def mode_listener(self, mode):
        """ Station screen menu mode event listener
        
        :param mode: menu mode
        """
        if mode == self.station_menu.STATION_MODE:
            self.left_button.set_visible(True)
            self.right_button.set_visible(True)
            self.page_down_button.set_visible(False)
            self.page_up_button.set_visible(False)
            self.left_button.clean_draw_update()
            self.right_button.clean_draw_update()
        else:
            self.left_button.set_visible(False)
            self.right_button.set_visible(False)
            self.page_down_button.set_visible(True)
            self.page_up_button.set_visible(True)            
            if self.playlist.total_pages == 1:
                self.page_down_button.set_enabled(False)
                self.page_up_button.set_enabled(False)
            else:
                self.page_down_button.set_enabled(True)
                self.page_up_button.set_enabled(True)
            self.page_down_button.clean_draw_update()
            self.page_up_button.clean_draw_update()
    
    def update_arrow_button_labels(self, state):
        """ Update arrow buttons state
        
        :param state: button state used for update
        """
        if not self.station_menu.STATION_MODE: return
        
        left = self.station_menu.button.state.index
        right = self.playlist.length - self.station_menu.button.state.index - 1
        
        self.left_button.state.l_name = str(left)
        self.left_button.add_label(self.left_button.state, self.left_button.layout.get_label_rectangle())        
        self.page_down_button.state.l_name = str(left)
        self.page_down_button.add_label(self.page_down_button.state, self.page_down_button.layout.get_label_rectangle())        
        self.right_button.state.l_name = str(right)
        self.right_button.add_label(self.right_button.state, self.right_button.layout.get_label_rectangle())
        self.page_up_button.state.l_name = str(right)
        self.page_up_button.add_label(self.page_up_button.state, self.page_up_button.layout.get_label_rectangle())
        
        if self.station_menu.current_mode == self.station_menu.STATION_MODE:            
            self.left_button.clean_draw_update()
            self.right_button.clean_draw_update()
        else:
            self.page_down_button.clean_draw_update()
            self.page_up_button.clean_draw_update()        
        
    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)
    
    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)
    
    def items_per_line(self, width):
        """ Return the number of station menu items in line for specified screen width
        
        :param width: screen width
        
        :return: number of menu items per line
        """
        if width <= 102:
            return 1
        elif width <= 203:
            return 2
        elif width <= 304:
            return 3
        elif width <= 405:
            return 4
        elif width <= 506:
            return 5
        else:
            return 6
    
    def set_genre_button_image(self, genre):
        """ Set genre button image
        
        :param genre: genre button
        """
        s = State()
        s.__dict__ = genre.__dict__
        s.bounding_box = self.genres_button.state.bounding_box
        s.bgr = self.genres_button.bgr
        s.show_label = False
        s.keyboard_key = kbd_keys[KEY_MENU]
        self.genres_button.set_state(s)
        
    def set_current(self):
        """ Set current station by index defined in current playlist """
        
        selected_genre = self.genres[self.config[CURRENT][PLAYLIST]]          
        if selected_genre == self.current_genre: return
          
        self.config[PREVIOUS][self.station_menu.playlist.genre] = self.station_menu.get_current_station_index()         
        self.playlist = Playlist(self.config[CURRENT][LANGUAGE], selected_genre.genre, self.util, self.items_per_line)
        
        if self.playlist.length == 0:
            return
        
        self.station_menu.set_playlist(self.playlist)
        previous_station_index = 0 
        try:
            previous_station_index = self.config[PREVIOUS][selected_genre.name.lower()]
        except KeyError:
            pass
        self.station_menu.set_station(previous_station_index)
        self.station_menu.set_station_mode(None)
        self.config[CURRENT][STATION] = previous_station_index        
        self.set_genre_button_image(selected_genre)        
        self.current_genre = selected_genre
        self.screen_title.set_text(self.station_menu.get_current_station_name())
        pass
    
    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
        """
        bb = self.screen_title.bounding_box
        x = 0
        y = bb.h
        w = bb.width
        h = self.station_menu.bounding_box.height
        c = Component(self.util)
        c.name = "clickable_rect"
        c.content = pygame.Rect(x, y, w, h)
        c.bgr = c.fgr = (0, 0, 0)
        c.content_x = c.content_y = 0
        d = [c]       
        return d
    
    def set_visible(self, flag):
        """ Set visibility flag
        
        :param flag: True - screen visible, False - screen invisible
        """
        self.visible = flag
        self.screen_title.set_visible(flag)
Ejemplo n.º 4
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)