def handle_info_popup_selection(self, state): """ Handle info menu selection :param state: button state """ if state.name == LYRICS: a = None try: a = self.screen_title.text except: pass if a != None: s = State() s.album = a self.start_screensaver(state.name, s) else: self.start_screensaver(state.name) else: self.start_screensaver(state.name)
def start_loop(self): """ Animation loop """ count = 1 while True: if self.timer_started: start_update_time = timer() if count == 1: seek_time_label = self.convert_seconds_to_label( self.seek_time) self.set_track_time(self.current_time_name, seek_time_label, self.current_time_layout, self.CURRENT_TIME_LAYER) step = self.total_track_time / 100 if step > 0: p = int(float(self.seek_time) / step) if p > self.slider.get_position() or p == 0: self.slider.set_position(p) self.slider.update_position() if self.use_web and self.update_seek_listeners: s = State() s.event_origin = self s.seek_time_label = seek_time_label self.web_seek_listener(s) self.update_seek_listeners = False self.seek_time += 1 if int(self.seek_time) >= self.total_track_time + 1: count = self.LOOP_CYCLES_PER_SECOND - 1 self.stop_timer() if count == self.LOOP_CYCLES_PER_SECOND: count = 1 else: count += 1 t = self.CYCLE_TIME - (timer() - start_update_time) if t > 0: time.sleep(t) else: time.sleep(0.3) else: time.sleep(0.3)
def set_genre_button_image(self, genre): """ Set genre button image :param genre: genre button """ if self.favorites_mode: favorites_button_state = self.favorites_util.get_favorites_button_state( self.genres_button.state.bounding_box) self.genres_button.selected = False self.genres_button.set_state(favorites_button_state) else: 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.factory.scale_genre_button_image(s, PERCENT_GENRE_IMAGE_AREA) self.genres_button.set_state(s)
def get_podcast_info(self, index, podcast_url): """ Get podcast info as state object :param index: podcast index :param podcast_url: podcast url :return: podcast info as State object """ try: response = requests.get(podcast_url) if response.status_code == 404: return None rss = feedparser.parse(response.content) if rss and getattr(rss, "bozo_exception", None): return None except: return None s = State() s.index = index s.name = rss.feed.title s.l_name = s.name s.description = rss.feed.subtitle s.url = podcast_url s.online = True s.fixed_height = int(self.podcast_button_font_size * 0.8) s.file_type = PODCASTS s.comparator_item = s.index s.bgr = self.config[COLORS][COLOR_DARK] s.show_bgr = True if 'image' in rss.feed and 'href' in rss.feed.image: img = rss.feed.image.href.strip() else: img = '' s.image_name = img s.icon_base = self.get_podcast_image(img, 0.48, 0.8, self.podcast_button_bb) self.summary_cache[s.url] = s return s
def release_action(self, event): """ Release button event handler """ if not self.enabled: return self.clicked = False self.clean_draw_update() release_time = pygame.time.get_ticks() time_pressed = release_time - self.press_time state = State() if time_pressed >= self.LONG_PRESS_TIME: state.long_press = True else: state.long_press = False self.notify_release_listeners(state) with self.lock: self.keep_sending = False
def press_action(self): """ Press button event handler """ if not self.enabled: return self.clicked = True self.clean_draw_update() self.notify_press_listeners() self.press_time = pygame.time.get_ticks() self.keep_sending = False time.sleep(0.12) self.keep_sending = True self.press_thread = Thread(target=self.keep_sending_event) self.press_thread.start() state = State() state.pos = self.pos self.notify_area_listeners(state)
def press_key(self, state): """ Key press handler :param state: button state """ if state.name not in self.controls and len(self.text) == 32: return self.unselect() state.event_origin.set_selected(True) if state.name == "Caps" or state.name == "ABC": if state.name == "Caps": self.caps = not self.caps if self.caps: self.create_keyboard(KEYBOARD_ABC, LAYOUT_1, TRANSITION_MAP_1) else: self.create_keyboard(KEYBOARD_abc, LAYOUT_1, TRANSITION_MAP_1) elif state.name == "123": self.create_keyboard(KEYBOARD_123, LAYOUT_2, TRANSITION_MAP_2) elif state.name == "#+=": self.create_keyboard(KEYBOARD_symbol, LAYOUT_3, TRANSITION_MAP_3) elif state.name == "Space": self.text += " " self.notify_text_listeners(self.text) elif state.name == "Del": if len(self.text) > 0: self.text = self.text[0: -1] self.notify_text_listeners(self.text) elif state.name == "Enter": if len(self.text) == 0: return s = State() s.source = "search" s.callback_var = self.text self.callback(s) else: self.text += state.name self.notify_text_listeners(self.text) self.clean_draw_update()
def get_screensaver_delays(self): """ Get screensaver delay button states :return: dictionary with button states """ names = [ KEY_SCREENSAVER_DELAY_1, KEY_SCREENSAVER_DELAY_3, KEY_SCREENSAVER_DELAY_OFF ] delays = {} index = 0 for n in names: state = State() state.name = n state.index = index state.l_name = self.config[LABELS][n] state.comparator_item = index state.bgr = self.config[COLORS][COLOR_DARK] delays[state.name] = state index += 1 return delays
def refresh(self): """ Refresh screensaver """ if self.saver_running: self.counter = self.counter + 1 if int(self.counter * self.one_cycle_period) == self.update_period * 1000: self.current_screensaver.refresh() self.counter = 0 if self.config[SCREENSAVER][NAME] in WEB_SAVERS: s = State() if isinstance(self.current_screensaver, Component): s.screen = Container(self.util) s.screen.components = [self.current_screensaver] else: s.screen = self.current_screensaver self.notify_start_listeners(s) else: if self.current_delay == 0: return self.delay_counter = self.delay_counter + 1 if int(self.delay_counter * self.one_cycle_period) == self.current_delay * 1000: self.start_screensaver()
def create_genre_button(self, bb, state, image_area): """ Create Genre button :param bb: bounding box :param state: button state :return: genre button """ s = State() s.__dict__ = state.__dict__ s.bgr = (0, 0, 0) s.bounding_box = bb s.keyboard_key = kbd_keys[KEY_MENU] s.img_x = None s.img_y = None s.auto_update = True s.image_align_v = V_ALIGN_CENTER s.show_bgr = True s.show_img = True s.show_label = False self.scale_genre_button_image(s, image_area) return Button(self.util, s)
def set_tracks(self, tracks, page): """ Set tracks in menu :param tracks: list of tracks :param page: page number """ if tracks == None: return self.tracks = tracks items = {} start_index = TRACKS_PER_PAGE * (page - 1) end_index = start_index + TRACKS_PER_PAGE layout = GridLayout(self.bb) layout.set_pixel_constraints(TRACK_ROWS, TRACK_COLUMNS, 1, 1) constr = layout.get_next_constraints() fixed_height = int((constr.h * LABEL_HEIGHT_PERCENT) / 100.0) for i, a in enumerate(self.tracks[start_index:end_index]): state = State() state.name = a.file_name state.l_name = state.name state.bgr = self.config[COLORS][COLOR_DARK] state.img_x = None state.img_y = None state.auto_update = True state.show_bgr = True state.show_img = False state.show_label = True state.comparator_item = state.name state.index = i state.fixed_height = fixed_height state.file_name = a.file_name state.folder = a.folder state.file_name = a.file_name state.url = a.url state.padding = PADDING items[state.name] = state self.set_items(items, 0, self.play_track, False)
def get_center_button(self, s): """ Create the center button :param s: button state :return: station logo button """ bb = Rect(self.layout.CENTER.x + 1, self.layout.CENTER.y + 1, self.layout.CENTER.w - 1, self.layout.CENTER.h - 1) if not hasattr(s, "icon_base"): self.util.add_icon(s) state = State() state.icon_base = s.icon_base self.factory.set_state_scaled_icons(s, bb) state.index = s.index state.genre = s.genre state.scaled = getattr(s, "scaled", False) state.icon_base_scaled = s.icon_base_scaled state.name = "station." + s.name state.l_name = s.l_name state.url = s.url state.keyboard_key = kbd_keys[KEY_SELECT] state.bounding_box = bb state.img_x = bb.x state.img_y = bb.y state.auto_update = False state.show_bgr = True state.show_img = True state.logo_image_path = s.image_path state.image_align_v = V_ALIGN_BOTTOM state.comparator_item = self.current_state.comparator_item button = Button(self.util, state) img = button.components[1] self.logo_button_content = (img.image_filename, img.content, img.content_x, img.content_y) return button
def create_disabled_button(self, bb, name, scale): """ Create disabled button :param bb: bounding box :param name: image name :param scale: image scale :return: disabled button """ state = State() state.name = name state.icon_base = self.image_util.load_icon_off(state.name, bb, scale) state.icon_selected = state.icon_base state.bgr = self.config[BACKGROUND][MENU_BGR_COLOR] state.bounding_box = bb state.img_x = None state.img_y = None state.auto_update = True state.image_align_v = V_ALIGN_CENTER state.show_bgr = True state.show_img = True state.show_label = False return Button(self.util, state)
def get_icon_bounding_box(self, constr, location, image_area, image_size, padding, show_label=True): """ Create icon bounding box :param constr: bounding box :param location: image location :param image_area: image area in bounding box :param image_size: image size inside of image area :param padding: padding """ s = State() s.show_img = True s.show_label = show_label s.image_location = location s.image_area_percent = image_area image_size_percent = image_size s.bounding_box = constr s.padding = padding layout = ButtonLayout(s) box = layout.image_rectangle box.h = (box.h / 100) * image_size_percent return box
def create_arrow_button(self, bb, name, key, location, label_text, image_area, image_size, arrow_labels=True): """ Create Arrow button (e.g. Left, Next Page etc.) :param bb: bounding box :param name: button name :param key: keyboard key associated with button :param location: image location inside of bounding box :param label_text: button label text :param image_area: percentage of height occupied by button image :param arrow_labels: show arrow label or not :return: arrow button """ s = State() s.name = name s.bounding_box = bb s.keyboard_key = key s.bgr = self.config[COLORS][COLOR_DARK_LIGHT] s.show_bgr = True s.show_img = True if arrow_labels: s.show_label = True else: s.show_label = False s.image_location = location s.label_location = CENTER s.label_text_height = 40 s.l_name = label_text s.auto_update = True s.image_size_percent = image_area / 100 s.text_color_normal = self.config[COLORS][COLOR_BRIGHT] s.text_color_selected = self.config[COLORS][COLOR_CONTRAST] s.text_color_disabled = self.config[COLORS][COLOR_MEDIUM] s.text_color_current = s.text_color_normal self.set_state_icons(s) if image_size != 100: self.resize_image(s, image_size) b = Button(self.util, s) return b
def create_disabled_button(self, bb, name, scale): """ Create disabled button :param bb: bounding box :param name: image name :param scale: image scale :return: disabled button """ state = State() state.name = name state.icon_base = self.util.load_mono_svg_icon(state.name, self.util.COLOR_OFF, bb, scale) state.icon_selected = state.icon_base state.bgr = (0, 0, 0) state.bounding_box = bb state.img_x = None state.img_y = None state.auto_update = True state.image_align_v = V_ALIGN_CENTER state.show_bgr = True state.show_img = True state.show_label = False return Button(self.util, state)
def change_track(self, track_index): """ Change track :param track_index: index track """ self.config[COLLECTION_PLAYBACK][COLLECTION_FILE] = self.get_filename( track_index) self.stop_timer() time.sleep(0.3) s = State() s.playlist_track_number = track_index s.index = track_index s.source = ARROW_BUTTON s.file_name = self.get_filename(track_index) folder = self.current_folder if not folder.endswith(os.sep): folder += os.sep s.folder = os.path.join(self.config[COLLECTION][BASE_FOLDER], folder) s.url = os.path.join(s.folder, s.file_name) self.set_current(True, s)
def __init__(self, util, next_page, previous_page, set_title, reset_title, go_to_page, callback, rows, columns, menu_button_layout, bounding_box=None): """ Initializer :param util: utility object :param next_page: next page callback :param previous_page: previous page callback :param set_title: set title callback :param reset_title: reset title callback :param go_to_page: go to page callback :param callback: :param rows: menu rows :param columns: menu columns :param menu_button_layout: button layout :param bounding_box: bounding box """ self.factory = Factory(util) self.util = util self.callback = callback self.config = self.util.config m = self.create_book_menu_button self.bounding_box = bounding_box self.menu_button_layout = menu_button_layout MultiPageMenu.__init__(self, util, next_page, previous_page, set_title, reset_title, go_to_page, m, rows, columns, menu_button_layout, None, bounding_box, align=ALIGN_CENTER) self.browsing_history = {} self.left_number_listeners = [] self.right_number_listeners = [] self.change_folder_listeners = [] self.play_file_listeners = [] self.playlist_size_listeners = [] self.menu_navigation_listeners = [] self.page_turned = False self.separator = os.sep self.selected_index = 0 self.empty_state = State()
def load_languages_menu(self, button_bounding_box): """ Load languages menu items :param button_bounding_box: menu button bounding box :return: dictionary with menu items """ items = {} i = 0 current_language = self.get_current_language() labels = current_language[TRANSLATIONS] va_commands = self.get_va_language_commands() for language in self.config[KEY_LANGUAGES]: name = language[NAME] state = State() state.name = name state.l_name = labels[name] path = os.path.join(os.getcwd(), FOLDER_LANGUAGES, name, FILE_FLAG) img = self.prepare_flag_image(path, button_bounding_box) state.icon_base = (path, img) state.bgr = self.config[COLORS][COLOR_DARK] state.img_x = None state.img_y = None state.auto_update = True state.show_bgr = True state.show_img = True state.show_label = True state.comparator_item = state.name state.index = i state.voice_commands = va_commands[name] state.v_align = V_ALIGN_TOP items[state.name] = state i += 1 return items
def get_books_objects(self, books, rows, cols, bounding_box): """ Prepare book objects :param books: list of books :param rows: menu rows :param cols: menu columns :param bounding_box: bounding box :return: books objects """ items = [] for index, b in enumerate(books): s = State() s.index = index s.name = {} title = b[BOOK_TITLE] s.l_name = title s.show_img = False s.show_bgr = True s.bgr = (255, 255, 255) s.book_url = b[BOOK_URL] s.comparator_item = index s.index_in_page = index % (cols * rows) s.show_label = True self.add_title(s.name, title) if self.show_author: self.add_author(b, s.name) if self.show_genre: self.add_genre(b, s.name) self.add_image(b, s, bounding_box, cols, rows) items.append(s) return items
def load_menu(self): """ Load menu items :return: dictionary of the items """ items = {} for i, a in enumerate(ABC): state = State() state.name = a state.l_name = state.name state.bgr = self.config[COLORS][COLOR_DARK] state.img_x = None state.img_y = None state.auto_update = True state.show_bgr = True state.show_img = False state.show_label = True state.comparator_item = state.name state.index = i items[state.name] = state return items
def create_stream_button(self, bb): """ Create Stream button :param bb: bounding box :return: genre button """ state = State() state.name = "stream" state.icon_base = self.util.load_mono_svg_icon(state.name, self.util.COLOR_OFF, bb, 0.4) state.icon_selected = state.icon_base state.bgr = (0, 0, 0) state.bounding_box = bb state.img_x = None state.img_y = None state.auto_update = True state.image_align_v = V_ALIGN_CENTER state.show_bgr = True state.show_img = True state.show_label = False return Button(self.util, state)
def recursive_change_folder(self): start_folder = self.config[FILE_PLAYBACK][CURRENT_FILE_PLAYLIST] current_folder = self.config[FILE_PLAYBACK][CURRENT_FOLDER] f = self.util.file_util.get_next_folder_with_audio_files( start_folder, current_folder) if f == None or (f != None and f[0] == None): self.config[FILE_PLAYBACK][CURRENT_FILE_PLAYBACK_MODE] = FILE_AUDIO self.config[FILE_PLAYBACK][CURRENT_FILE_PLAYLIST] = None return False self.config[FILE_PLAYBACK][CURRENT_FOLDER] = f[0] self.config[FILE_PLAYBACK][CURRENT_FILE] = f[1] self.config[FILE_PLAYBACK][CURRENT_TRACK_TIME] = None state = State() state.file_type = FOLDER state.url = f[0] state.long_press = True state.playback_mode = FILE_RECURSIVE self.current_track_index = 0 state.dont_notify = True self.audio_files = self.get_audio_files() self.recursive_notifier(f[0]) return True
def handle_info_popup_selection(self, state): """ Handle info menu selection :param state: button state """ n = state.name if n == CLOCK or n == WEATHER: self.start_screensaver(n) elif n == LYRICS: a = None try: m = self.util.get_file_metadata() a = m["artist"] + " - " + m["title"] except: pass if a != None: s = State() s.album = a self.start_screensaver(n, s) else: self.start_screensaver(n) else: self.go_info_screen(state)
def handle_metadata(self, state=None): """ Handle metadata UI callback :param state: metadata object """ if not state: return if "picture" in state.keys(): img = ("current_shairport_image", state["picture"]) self.set_file_button(img) self.file_button.clean_draw_update() state = State() state.icon_base = img state.full_screen_image = img self.change_screensaver_image(state) elif "current_title" in state.keys(): title = state["current_title"] self.screen_title.set_text(title) elif "volume" in state.keys(): volume = state["volume"] self.volume.set_position(volume) self.volume.update_position() self.volume.notify_slide_listeners() elif "stream" in state.keys(): type = state["stream"] if type == "end": self.play_button.draw_state(1) elif type == "begin": self.play_button.draw_state(0) elif "Time" in state.keys() and "seek_time" in state.keys(): state["state"] = "running" if self.visible: if self.update_web_observer: self.update_web_observer()
def create_toggle_button(self, name, keyboard_key=None, lirc_code=None, bounding_box=None, image_size_percent=100): """ Create toggle button (e.g. Shutdown button) :param name: button name :param keyboard_key: keyboard key assigned to the button :param lirc_code: LIRC code assigned to the button :param bounding_box: button bounding box """ state = State() state.name = name state.keyboard_key = keyboard_key state.lirc_code = lirc_code state.bgr = self.config[BACKGROUND][MENU_BGR_COLOR] state.bounding_box = bounding_box state.img_x = None state.img_y = None state.auto_update = True state.image_align_v = V_ALIGN_CENTER state.show_bgr = True state.show_img = True state.image_size_percent = image_size_percent self.set_state_icons(state) button = ToggleButton(self.util, state) return button
def create_book_author_items(self, authors): """ Create dictionary with author books :param authors: list of author books :return: dictionary with author books """ items = {} for i, g in enumerate(authors): state = State() state.name = g[AUTHOR_NAME] state.url = g[AUTHOR_URL] + "/" state.l_name = state.name + " (" + g[AUTHOR_BOOKS] + ")" state.bgr = self.config[COLORS][COLOR_DARK] state.img_x = None state.img_y = None state.auto_update = True state.show_bgr = True state.show_img = False state.show_label = True state.comparator_item = state.name state.index = i items[state.name] = state return items
def create_file_button(self, bb, action=None): """ Create default audio file button :param bb: bounding box :param action: button event listener :return: default audio file button """ state = State() state.icon_base = self.util.get_audio_file_icon("", bb) state.scaled = False state.name = "cd" state.keyboard_key = kbd_keys[KEY_SELECT] state.bounding_box = bb state.img_x = bb.x state.img_y = bb.y state.auto_update = False state.show_bgr = False state.show_img = True state.image_align_v = V_ALIGN_CENTER button = Button(self.util, state) button.add_release_listener(action) return button
def set_labels(self, name, v, bb, layer_num): font_size = int((bb.h * 45) / 100.0) font = self.util.get_font(font_size) size = font.size(v) label = font.render(v, 1, self.config[COLORS][COLOR_BRIGHT]) c = Component(self.util, label) c.bgr = (255, 0, 0) c.name = name c.text = v c.text_size = font_size c.text_color_current = self.config[COLORS][COLOR_BRIGHT] c.content_x = bb.x + (bb.width - size[0]) / 2 c.content_y = bb.y + (bb.height - size[1]) / 2 self.components[layer_num] = c if self.visible: self.draw() self.update() if self.use_web and getattr(self, "web_seek_listener", None): s = State() s.event_origin = self s.seek_time_label = v self.web_seek_listener(s)
def cancel_screensaver(self, event=None): """ Stop currently running screensaver. Show current screen. :param event: mouse event """ if self.config[DSI_DISPLAY_BACKLIGHT][USE_DSI_DISPLAY] and self.config[ DSI_DISPLAY_BACKLIGHT][SCREENSAVER_DISPLAY_POWER_OFF]: self.config[BACKLIGHTER].power = True else: if self.config[DSI_DISPLAY_BACKLIGHT][ USE_DSI_DISPLAY] and self.config[BACKLIGHTER]: screensaver_brightness = int( self.config[DSI_DISPLAY_BACKLIGHT][SCREEN_BRIGHTNESS]) self.config[BACKLIGHTER].brightness = screensaver_brightness if getattr( self.current_screensaver, "has_exit_area", False) and not self.current_screensaver.is_exit_clicked(event): s = State() s.screen = self.current_screensaver self.notify_start_listeners(s) return self.current_screensaver.stop() self.current_screensaver.set_visible(False) self.current_screen.set_visible(True) self.current_screen.clean_draw_update() self.saver_running = False self.notify_stop_listeners(None) if self.previous_saver != None and self.config[SCREENSAVER][ NAME] != self.previous_saver: self.config[SCREENSAVER][NAME] = self.previous_saver self.change_saver_type() self.previous_saver = None