def __init__(self, util, listeners, voice_assistant): """ Initializer :param util: utility object :param listener: screen menu event listener """ self.util = util config = util.config screen_layout = BorderLayout(util.screen_rect) top = int((util.screen_rect.h * PERCENT_SAVERS) / 100) bottom = util.screen_rect.h - top screen_layout.set_pixel_constraints(top, bottom, 0, 0) layout = BorderLayout(screen_layout.TOP) layout.set_percent_constraints(PERCENT_TOP_HEIGHT, 0, 0, 0) Screen.__init__(self, util, "", PERCENT_TOP_HEIGHT, voice_assistant, "saver_title", title_layout=layout.TOP) factory = Factory(util) self.bounding_box = util.screen_rect self.saver_menu = SaverMenu(util, None, layout.CENTER) self.add_component(self.saver_menu) b = config[BACKGROUND][HEADER_BGR_COLOR] c = config[COLORS][COLOR_CONTRAST] font_size = (layout.TOP.h * PERCENT_TITLE_FONT) / 100.0 label = config[LABELS][SCREENSAVER] self.screen_title.set_text(label) layout = BorderLayout(screen_layout.BOTTOM) layout.set_percent_constraints(PERCENT_DELAY_TITLE, PERCENT_DELAY_TITLE, 0, 0) self.delay_menu = SaverDelayMenu(util, None, layout.CENTER) self.add_component(self.delay_menu) layout.TOP.y += 2 layout.TOP.h -= 2 self.saver_delay_title = factory.create_output_text( "saver_delay_title", layout.TOP, b, c, int(font_size)) label = config[LABELS][DELAY] self.saver_delay_title.set_text(label) self.add_component(self.saver_delay_title) b = self.config[BACKGROUND][FOOTER_BGR_COLOR] self.navigator = SaverNavigator(util, listeners, b, layout.BOTTOM) self.add_component(self.navigator) self.top_menu_enabled = True
def __init__(self, util, listeners, voice_assistant): """ Initializer :param util: utility object :param listener: screen menu event listener """ self.util = util config = util.config screen_layout = BorderLayout(config[SCREEN_RECT]) top = int((config[SCREEN_RECT].h * PERCENT_SAVERS) / 100) bottom = config[SCREEN_RECT].h - top screen_layout.set_pixel_constraints(top, bottom, 0, 0) layout = BorderLayout(screen_layout.TOP) layout.set_percent_constraints(PERCENT_TOP_HEIGHT, 0, 0, 0) Screen.__init__(self, util, "", PERCENT_TOP_HEIGHT, voice_assistant, "saver_title", title_layout=layout.TOP) factory = Factory(util) self.bounding_box = config[SCREEN_RECT] self.bgr = (0, 0, 0) self.saver_menu = SaverMenu(util, (0, 0, 0), layout.CENTER) self.add_component(self.saver_menu) d = config[COLORS][COLOR_DARK_LIGHT] c = config[COLORS][COLOR_CONTRAST] font_size = (layout.TOP.h * PERCENT_TITLE_FONT)/100.0 label = config[LABELS][SCREENSAVER] self.screen_title.set_text(label) layout = BorderLayout(screen_layout.BOTTOM) layout.set_percent_constraints(PERCENT_DELAY_TITLE, PERCENT_DELAY_TITLE, 0, 0) self.delay_menu = SaverDelayMenu(util, (0, 0, 0), layout.CENTER) self.add_component(self.delay_menu) layout.TOP.y += 1 layout.TOP.h -= 1 self.saver_delay_title = factory.create_output_text("saver_delay_title", layout.TOP, d, c, int(font_size)) label = config[LABELS][DELAY] self.saver_delay_title.set_text(label) self.add_component(self.saver_delay_title) buttons = factory.create_home_player_buttons(self, layout.BOTTOM, listeners) self.home_button = buttons[0] self.player_button = buttons[1] self.top_menu_enabled = True
def __init__(self, util): """ Initializer :param util: utility object """ self.util = util self.config = util.config self.color_web_bgr = self.config[COLORS][COLOR_WEB_BGR] Container.__init__(self, util, background=self.color_web_bgr) self.bounding_box = util.screen_rect self.start_listeners = [] factory = Factory(util) edition = "Holbein Edition" layout = BorderLayout(self.bounding_box) layout.set_percent_constraints(0, PERCENT_FOOTER_HEIGHT, 0, 0) release_font_size = (layout.BOTTOM.h * PERCENT_FOOTER_FONT) / 100.0 color_logo = self.config[COLORS][COLOR_LOGO] button = factory.create_image_button("peppy", bounding_box=layout.CENTER, bgr=self.color_web_bgr, image_size_percent=68, selected=False) 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) layout.BOTTOM.y -= 1 layout.BOTTOM.h += 1 release = factory.create_output_text("about-name", layout.BOTTOM, self.color_web_bgr, color_logo, int(release_font_size), full_width=True, valign=V_ALIGN_TOP) release.set_text_no_draw(edition) self.add_component(release)
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)
class NetworkScreen(MenuScreen): """ Network Screen """ def __init__(self, util, listeners, voice_assistant): """ Initializer :param util: utility object :param listeners: listeners :param voice_assistant: voice assistant """ self.util = util self.config = util.config self.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 if self.linux and self.config[USAGE][USE_BLUETOOTH]: rows = 7 else: rows = 6 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) rect = pygame.Rect(self.menu_layout.x, self.menu_layout.y + 1, self.menu_layout.w, self.menu_layout.h - 1) b = util.config[BACKGROUND][MENU_BGR_COLOR] bgr = Component(util, rect, 0, 0, self.menu_layout, bgr=b) 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) if self.linux and self.config[USAGE][USE_BLUETOOTH]: 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) if self.linux and self.config[USAGE][USE_BLUETOOTH]: self.bluetooth = self.add_value(value_layout, self.network_panel, 5) self.add_component(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.navigator.components[0].set_selected(True) self.add_navigator(self.navigator) self.original_networks = None self.networks = None self.current_network = None self.current_wifi_network = None self.clicked = False Screen.link_borders(self, False) def set_current(self, state): """ Set current state :param state: button state """ if state and getattr(state, "source", None) == "bluetooth": self.set_loading(self.title) self.bluetooth_util.connect_device(state.name, state.mac_address, True) self.set_initial_state(state) if self.bluetooth.text: self.bluetooth_util.update_asoundrc(OUTPUT_TYPE_BLUETOOTH, state.mac_address) self.reset_loading() self.clean_draw_update() return if not state or (state and not getattr(state, KEY_CALLBACK_VAR, None)): self.set_loading(self.title) self.set_initial_state(state) self.reset_loading() else: self.connect_wifi(state) self.clean_draw_update() def set_initial_state(self, state): """ Set initial screen :param state: button state """ info = self.get_network_info() self.internet_label.set_text("Internet:") self.ethernet_label.set_text("Ethernet IP:") self.wifi_network_label.set_text("Wi-Fi Network:") self.wifi_ip_label.set_text("Wi-Fi IP:") if self.linux and self.config[USAGE][USE_BLUETOOTH]: self.bluetooth_label.set_text("Bluetooth:") self.set_value(self.internet, info, CONNECTED) self.set_value(self.ethernet_ip, info, ETHERNET_IP) self.set_value(self.wifi_network, info, WIFI_NETWORK) self.set_value(self.wifi_ip, info, WIFI_IP) if self.linux and self.config[USAGE][USE_BLUETOOTH]: self.set_value(self.bluetooth, info, BLUETOOTH) def set_value(self, field, info, key): """ Set text in provided field :param field: text field :param info: info dictionary :param key: dictionary key """ try: field.set_text(self.truncate(info[key])) except: field.set_text("") def get_network_info(self): """ Get network information :return: dictionary with network info """ info = self.wifi_util.get_network() connected = self.check_internet_connectivity() if connected: info[CONNECTED] = self.config[LABELS]["connected"] else: info[CONNECTED] = self.config[LABELS]["disconnected"] info[BLUETOOTH] = "" d = self.bluetooth_util.get_connected_device() if d: info[BLUETOOTH] = d["name"] return info def truncate(self, s): """ Truncate string :param s: input string :return: truncated string """ CHARS = 18 if len(s) > CHARS: s = s[0:CHARS] + "..." return s def add_label(self, layout, parent, n): """ Add label component :param layout: label layout :param parent: parent container :param n: label number :return: label component """ c = layout.get_next_constraints() fgr = self.util.config[COLORS][COLOR_BRIGHT] h = H_ALIGN_RIGHT v = V_ALIGN_BOTTOM f = int((c.height * 50) / 100) name = "label." + str(n) label = self.factory.create_output_text(name, c, (0, 0, 0, 0), fgr, f, h, v) parent.add_component(label) return label def add_value(self, layout, parent, n): """ Add value component :param layout: layout :param parent: parent container :param n: component number :return: value component """ c = layout.get_next_constraints() fgr = self.util.config[COLORS][COLOR_CONTRAST] h = H_ALIGN_LEFT v = V_ALIGN_TOP f = int((c.height * 68) / 100) name = "value." + str(n) gap = int((c.height * 20) / 100) value = self.factory.create_output_text(name, c, (0, 0, 0, 0), fgr, f, halign=h, valign=v, shift_x=gap) parent.add_component(value) return value def set_current_wifi_network(self, net): """ Set current Wi-Fi network :param net: new network name """ self.current_wifi_network = net def connect_wifi(self, state): """ Connect to Wi-Fi network :param state: button state """ self.set_loading(self.title, self.config[LABELS][KEY_CONNECTING]) if self.linux: self.connect_wifi_linux(state) else: self.connect_wifi_windows() self.check_network() self.set_initial_state(None) self.reset_loading() def connect_wifi_windows(self): """ Connect to Wi-Fi on Windows """ self.wifi_util.connect_wifi_windows(self.current_wifi_network, self.current_wifi_network) time.sleep(4) def connect_wifi_linux(self, state): """" Connect to Wi-Fi on Linux :param state: button state """ pswd = getattr(state, KEY_CALLBACK_VAR, None) if not pswd: return encrypted_pswd = self.wifi_util.encrypt_psk(self.current_wifi_network, pswd) if not encrypted_pswd: return self.wifi_util.create_wpa_file(self.current_wifi_network, encrypted_pswd) time.sleep(10) def disconnect_wifi(self, state): """ Disconnect from Wi-Fi network :param state: button state """ self.set_loading(self.title, self.config[LABELS][KEY_DISCONNECTING]) self.wifi_util.disconnect_wifi() self.check_network() time.sleep(3) self.set_initial_state(None) self.reset_loading() self.clean_draw_update() def remove_bluetooth_devices(self, state): """ Remove bluetooth devices :param state: button state """ self.set_loading(self.title) self.bluetooth_util.remove_devices() self.set_initial_state(state) if not self.bluetooth.text: self.bluetooth_util.update_asoundrc(OUTPUT_TYPE_DEFAULT) self.reset_loading() self.clean_draw_update() def check_network(self): """ Check Internet connectivity """ self.util.connected_to_internet = self.check_internet_connectivity() self.set_modes() def handle_event(self, event): """ Event handler :param event: event to handle """ if not self.visible or event.type == pygame.MOUSEMOTION: return mouse_events = [pygame.MOUSEBUTTONUP, pygame.MOUSEBUTTONDOWN] pos = None try: pos = event.pos except: pass if pos and event.type in mouse_events: if self.menu_layout.collidepoint(event.pos): if event.type == pygame.MOUSEBUTTONDOWN: return self.go_home(None) self.redraw_observer() else: for b in self.navigator.components: if b.bounding_box.collidepoint(event.pos): b.set_selected(True) else: b.set_selected(False) b.clean_draw_update() Container.handle_event(self, event) def add_screen_observers(self, update_observer, redraw_observer): """ Add screen observers :param update_observer: observer for updating the screen :param redraw_observer: observer to redraw the whole screen """ MenuScreen.add_screen_observers(self, update_observer, redraw_observer) self.update_observer = update_observer self.redraw_observer = redraw_observer self.add_loading_listener(redraw_observer) self.navigator.add_observers(update_observer, redraw_observer)
class InfoScreen(Container): """ Info screen. Shows file specific info and metadata """ 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 ] def add_title(self, bb): """ Add title component :param bb: bounding box :return: title component """ fgr = self.util.config[COLORS][COLOR_CONTRAST] h = H_ALIGN_CENTER v = V_ALIGN_BOTTOM f = int((bb.height * 80) / 100) name = GENERATED_IMAGE + "title" shift = int(bb.h / 2) title = self.factory.create_output_text(name, bb, (0, 0, 0, 0), fgr, f, h, v, shift_y=-shift) self.add_component(title) return title def add_label(self, layout, n, label_name): """ Add label component :param layout: label layout :param n: label number :param label_name: label name """ c = layout.get_next_constraints() fgr = self.util.config[COLORS][COLOR_BRIGHT] h = H_ALIGN_RIGHT v = V_ALIGN_BOTTOM f = int((c.height * 70) / 100) name = GENERATED_IMAGE + "label." + str(n) label = self.factory.create_output_text(name, c, (0, 0, 0, 0), fgr, f, h, v) label.set_text(label_name) self.add_component(label) def add_value(self, layout, n): """ Add value component :param layout: layout :param parent: parent container :param n: component number :return: value component """ c = layout.get_next_constraints() fgr = self.util.config[COLORS][COLOR_CONTRAST] h = H_ALIGN_LEFT v = V_ALIGN_BOTTOM f = int((c.height * 70) / 100) name = GENERATED_IMAGE + "value." + str(n) gap = int((c.height * 20) / 100) value = self.factory.create_output_text(name, c, (0, 0, 0, 0), fgr, f, halign=h, valign=v, shift_x=gap) self.add_component(value) return value def set_current(self, state): """ Set info in current screen :param state: button state """ meta = self.util.get_file_metadata() if not meta: self.title.set_text("") for v in self.values: v.set_text("") return self.set_value(self.title, meta, "filename", max_chars=MAX_CHARS_TITLE) self.set_value(self.filesize, meta, "filesize", unit=self.config[LABELS]["bytes"]) self.set_value(self.sample_rate, meta, "sample_rate", unit=self.config[LABELS]["hz"]) self.set_value(self.channels, meta, "channels") self.set_value(self.bits, meta, "bits_per_sample") self.set_value(self.bit_rate, meta, "bitrate", unit=self.config[LABELS]["kbps"]) self.set_value(self.genre, meta, GENRE) self.set_value(self.artist, meta, ARTIST) self.set_value(self.album, meta, ALBUM) self.set_value(self.date, meta, DATE) def set_value(self, field, meta, key, max_chars=MAX_CHARS, unit=None): """ Set text in provided field :param field: text field :param meta: meta dictionary :param key: dictionary key :param max_chars: maximum characters in the field :param unit: value unit """ try: v = meta[key] if isinstance(v, numbers.Number): if key == "bitrate": v = round(v / 1000) n = "{:,}".format(v).replace(",", " ") if unit: n += " " + unit field.set_text(n) else: field.set_text(self.truncate(v, max_chars)) except: field.set_text("") def truncate(self, s, max_chars): """ Truncate string :param s: input string :param max_chars: maximum string length :return: truncated string """ if len(s) > max_chars: s = s[0:max_chars] + "..." return s def handle_event(self, event): """ Handle screen events :param event: event object """ if (event.type == pygame.MOUSEBUTTONUP and event.button == 1) or \ (event.type == USER_EVENT_TYPE and event.sub_type == SUB_TYPE_KEYBOARD and event.keyboard_key == pygame.K_ESCAPE): s = State() s.source = KEY_BACK self.listener(s) self.redraw_observer() def exit_screen(self): """ Exit screen """ pass def add_screen_observer(self, redraw_observer): """ Add screen observer :param redraw_observer: observer to redraw the whole screen """ self.redraw_observer = redraw_observer
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]
def __init__(self, util): """ Initializer :param util: utility object """ self.util = util self.config = util.config self.config_class = util.config_class self.color_web_bgr = self.config[COLORS][COLOR_WEB_BGR] color_logo = self.config[COLORS][COLOR_CONTRAST] color_status = self.config[COLORS][COLOR_LOGO] Container.__init__(self, util, background=self.color_web_bgr) self.bounding_box = util.screen_rect self.start_listeners = [] factory = Factory(util) 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=self.color_web_bgr, image_size_percent=68, selected=False) 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) layout.BOTTOM.y -= int((self.bounding_box.h * 5) / 100) layout.BOTTOM.h += 1 if self.util.connected_to_internet and self.config[USAGE][ USE_CHECK_FOR_UPDATES]: bottom_layout = GridLayout(layout.BOTTOM) bottom_layout.set_pixel_constraints(2, 1) line_top = bottom_layout.get_next_constraints() line_bottom = bottom_layout.get_next_constraints() else: line_top = layout.BOTTOM self.release = factory.create_output_text("installed", line_top, self.color_web_bgr, color_logo, font_size, full_width=True, valign=V_ALIGN_BOTTOM) 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, self.color_web_bgr, color_status, font_size, full_width=True, valign=V_ALIGN_TOP) self.add_component(self.status) self.new_release = self.get_new_release()
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()
class NetworkScreen(MenuScreen): """ Network Screen """ def __init__(self, util, listeners, voice_assistant): """ Initializer :param util: utility object :param listeners: listeners :param voice_assistant: voice assistant """ self.util = util self.config = util.config self.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.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 = [6, 1] MenuScreen.__init__(self, util, listeners, 6, 1, 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(6, 1) label_layout.get_next_constraints() value_layout = GridLayout(right_layout) value_layout.set_pixel_constraints(6, 1) 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.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.set_menu(self.network_panel) listeners[KEY_REFRESH] = self.set_current listeners[KEY_DISCONNECT] = self.disconnect_wifi 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 def set_current(self, state): """ Set current state :param state: button state """ if not state or (state and not getattr(state, KEY_CALLBACK_VAR, None)): self.set_loading(self.title) self.set_initial_state(state) self.reset_loading() else: self.connect_wifi(state) self.clean_draw_update() def set_initial_state(self, state): """ Set initial screen :param state: button state """ info = self.get_network_info() self.internet_label.set_text("Internet:") self.ethernet_label.set_text("Ethernet IP:") self.wifi_network_label.set_text("Wi-Fi Network:") self.wifi_ip_label.set_text("Wi-Fi IP:") self.set_value(self.internet, info, CONNECTED) self.set_value(self.ethernet_ip, info, ETHERNET_IP) self.set_value(self.wifi_network, info, WIFI_NETWORK) self.set_value(self.wifi_ip, info, WIFI_IP) def set_value(self, field, info, key): """ Set text in provided field :param field: text field :param info: info dictionary :param key: dictionary key """ try: field.set_text(info[key]) except: field.set_text("") def get_network_info(self): """ Get network information :return: dictionary with network info """ info = self.wifi_util.get_network() connected = self.check_internet_connectivity() if connected: info[CONNECTED] = self.config[LABELS]["connected"] else: info[CONNECTED] = self.config[LABELS]["disconnected"] return info def add_label(self, layout, parent, n): """ Add label component :param layout: label layout :param parent: parent container :param n: label number :return: label component """ c = layout.get_next_constraints() fgr = self.util.config[COLORS][COLOR_BRIGHT] bgr = self.util.config[COLORS][COLOR_DARK] h = H_ALIGN_RIGHT v = V_ALIGN_BOTTOM f = int((c.height * 50) / 100) name = "label." + str(n) label = self.factory.create_output_text(name, c, bgr, fgr, f, h, v) parent.add_component(label) return label def add_value(self, layout, parent, n): """ Add value component :param layout: layout :param parent: parent container :param n: component number :return: value component """ c = layout.get_next_constraints() fgr = self.util.config[COLORS][COLOR_BRIGHT] bgr = self.util.config[COLORS][COLOR_DARK] h = H_ALIGN_LEFT v = V_ALIGN_TOP f = int((c.height * 68) / 100) name = "value." + str(n) gap = int((c.height * 20) / 100) value = self.factory.create_output_text(name, c, bgr, fgr, f, halign=h, valign=v, shift_x=gap) parent.add_component(value) return value def set_current_wifi_network(self, net): """ Set current Wi-Fi network :param net: new network name """ self.current_wifi_network = net def connect_wifi(self, state): """ Connect to Wi-Fi network :param state: button state """ self.set_loading(self.title, self.config[LABELS][KEY_CONNECTING]) if "win" in sys.platform: self.connect_wifi_windows() else: self.connect_wifi_linux(state) self.check_network() self.set_initial_state(None) self.reset_loading() def connect_wifi_windows(self): """ Connect to Wi-Fi on Windows """ self.wifi_util.connect_wifi_windows(self.current_wifi_network, self.current_wifi_network) time.sleep(4) def connect_wifi_linux(self, state): """" Connect to Wi-Fi on Linux :param state: button state """ pswd = getattr(state, KEY_CALLBACK_VAR, None) if not pswd: return encrypted_pswd = self.wifi_util.encrypt_psk(self.current_wifi_network, pswd) if not encrypted_pswd: return self.wifi_util.create_wpa_file(self.current_wifi_network, encrypted_pswd) time.sleep(10) def disconnect_wifi(self, state): """ Disconnect from Wi-Fi network :param state: button state """ self.set_loading(self.title, self.config[LABELS][KEY_DISCONNECTING]) self.wifi_util.disconnect_wifi() self.check_network() time.sleep(3) self.set_initial_state(None) self.reset_loading() self.clean_draw_update() def check_network(self): """ Check Internet connectivity """ self.util.connected_to_internet = self.check_internet_connectivity() self.set_modes() def handle_event(self, event): """ Event handler :param event: event to handle """ if not self.visible: return pos = None try: pos = event.pos except: pass if (pos and event.type == pygame.MOUSEBUTTONDOWN and self.menu_layout.collidepoint(pos)) or \ (event.type == USER_EVENT_TYPE and event.sub_type == SUB_TYPE_KEYBOARD and event.action == pygame.KEYDOWN and \ event.keyboard_key == kbd_keys[KEY_SELECT]): self.clicked = True elif (pos and event.type == pygame.MOUSEBUTTONUP and self.menu_layout.collidepoint(pos) and self.clicked) or \ (event.type == USER_EVENT_TYPE and event.sub_type == SUB_TYPE_KEYBOARD and event.action == pygame.KEYUP and \ event.keyboard_key == kbd_keys[KEY_SELECT] and self.clicked): self.go_home(None) self.redraw_observer() self.clicked = False else: Container.handle_event(self, event) 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) for b in self.navigator.menu_buttons: self.add_button_observers(b, update_observer, redraw_observer)
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
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)
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)