def notify_start_conversation_listeners(self): """ Notify start conversation listeners """ for listener in self.start_conversation_listeners: s = State() s.type = USER_EVENT_TYPE listener(s)
def set_list(self, state=None): """ Set list view """ s = State() s.source = KEY_LIST s.name = self.collection_topic self.set_current(s)
def get_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 slider_action_handler(self, evt): """ Slider action handler :param evt: event """ a = self.config[FILE_PLAYBACK][CURRENT_FILE] b = self.config[AUDIOBOOKS][BROWSER_TRACK_FILENAME] c = self.config[CD_PLAYBACK][CD_TRACK] d = self.config[PODCASTS][PODCAST_EPISODE_URL] if not (a or b or c or d): return if not self.timer_started: return step = self.total_track_time / 100 self.seek_time = step * evt.position st = self.convert_seconds_to_label(self.seek_time) self.set_track_time(self.current_time_name, st, self.current_time_layout, self.CURRENT_TIME_LAYER) self.notify_seek_listeners(str(self.seek_time)) s = State() s.event_origin = self s.seek_time_label = str(self.seek_time) self.web_seek_listener(s)
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): screen_savers = [WEATHER, CLOCK, LYRICS, LOGO] if self.current_screensaver.name in screen_savers: s.screen = self.current_screensaver else: 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 slider_action_handler(self, evt): """ Slider action handler :param evt: event """ a = self.config[FILE_PLAYBACK][CURRENT_FILE] b = self.config[AUDIOBOOKS][BROWSER_TRACK_FILENAME] c = self.config[CD_PLAYBACK][CD_TRACK] d = self.config[PODCASTS][PODCAST_EPISODE_URL] e = self.config[COLLECTION_PLAYBACK][COLLECTION_FILE] if not (a or b or c or d or e): return if not self.timer_started: return step = self.total_track_time / 100 self.seek_time = step * evt.position st = self.convert_seconds_to_label(self.seek_time) self.current.set_text(st) self.notify_seek_listeners(str(self.seek_time)) if self.use_web and hasattr(self, "web_seek_listener"): s = State() s.event_origin = self s.seek_time_label = str(self.seek_time) self.web_seek_listener(s)
def get_network_info(self, index, name, strength, bb): """ Prepare state object for network button :param index: network index :param name: network name :param strength: signal strength :param bb: bounding box :return: state object with network info """ s = State() s.index = index s.name = name s.l_name = name s.strength = strength s.comparator_item = s.index s.bgr = self.config[COLORS][COLOR_DARK] s.show_bgr = True if strength <= 25: n = "s-1" elif strength > 25 and strength <= 50: n = "s-2" elif strength > 50 and strength <= 75: n = "s-3" elif strength > 75: n = "s-4" s.icon_base = self.util.load_mono_svg_icon(n, self.util.COLOR_MAIN, bb, 0.5) return s
def get_cd_tracks_summary(self, cd_drive_name): """ Get the list of CD tracks summaries :param cd_drive_name: CD drive name :return: CD tracks summaries """ drive_id = self.get_cd_drive_id_by_name(cd_drive_name) names = self.get_cd_track_names(drive_id) if not names: return None items = [] for id, cd in enumerate(names): s = State() s.index = id s.playlist_track_number = id s.name = cd s.l_name = s.name s.file_type = FILE_AUDIO s.playback_mode = FILE_AUDIO s.file_name = self.get_cd_track_url(cd_drive_name, id + 1) s.url = s.file_name items.append(s) return items
def start_screensaver(self, name=None, state=None): """ Starts screensaver :param name: screensaver name :param state: state object with song info """ if name != None: # info self.previous_saver = self.config[SCREENSAVER][NAME] self.config[SCREENSAVER][NAME] = name self.change_saver_type() if name == LYRICS and state != None and hasattr(state, "album"): self.current_screensaver.set_song_info(state) if self.config[SCREENSAVER][NAME] in WEB_SAVERS: s = State() s.screen = self.current_screensaver else: s = None self.current_screen.clean() self.current_screen.set_visible(False) self.current_screensaver.start() self.current_screensaver.refresh() self.counter = 0 self.delay_counter = 0 self.saver_running = True self.notify_start_listeners(s)
def update_playlist_menu(self, state): """ Update playlist menu This is initiated by player :param state: state object from player defining current playlist file """ if self.config[FILE_PLAYBACK][ CURRENT_FILE_PLAYBACK_MODE] != FILE_PLAYLIST: return s = State() s.dont_notify = True i = self.util.get_dictionary_value(state, "current_track_id") s.track_time = self.util.get_dictionary_value(state, "seek_time", "0") self.config[FILE_PLAYBACK][CURRENT_TRACK_TIME] = s.track_time if i != None: b = self.get_button_by_index_in_page(int(i) - 1) if not b: self.switch_to_next_page(s) s.comparator_item = int(i) name = self.util.get_dictionary_value(state, "Track") if not name: name = self.util.get_dictionary_value(state, "file_name") if name != None: self.config[FILE_PLAYBACK][CURRENT_FILE] = name self.item_selected(state)
def set_value(self, v): self.top.set_text(v) 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 notify_motion_listeners(self): """ Notify all motion event listeners """ state = State() state.event_origin = self state.position = self.get_position() for listener in self.motion_listeners: listener(state)
def notify_slide_listeners(self): """ Notify event listeners for clicking on slider line event """ state = State() state.event_origin = self state.position = self.get_position() for listener in self.slide_listeners: listener(state)
def load_m3u(self, path, folder, top_folder, items_per_page, default_icon_path): """ Load m3u playlist :param path: base path :param folder: main folder :param top_folder: top folder :param items_per_page: items per page :param default_icon_path: path to the default icon :return: list of State objects representing playlist """ items = [] lines = [] item_name = None index = 0 for encoding in ["utf8", "utf-8-sig", "utf-16"]: try: lines = codecs.open(path, "r", encoding).read().split("\n") break except Exception as e: logging.error(e) for line in lines: if len(line.rstrip()) == 0: continue if line.startswith("#") and not item_name: item_name = line[1:].rstrip() continue name = item_name.rstrip() path = os.path.join(folder, name + EXT_PNG) icon = self.image_util.load_image(path) if not icon: path = os.path.join(folder, name + EXT_JPG) icon = self.image_util.load_image(path) if not icon: icon = self.image_util.load_image(default_icon_path) state = State() state.index = index state.genre = top_folder state.url = line.rstrip() state.name = str(index) state.l_name = name state.icon_base = icon state.comparator_item = NAME state.index_in_page = index % items_per_page items.append(state) index += 1 item_name = None return items
def keep_sending_event(self): """ Keep sending event when button was kept pressed """ state = State() state.pos = self.pos time.sleep(0.5) while self.keep_sending: self.notify_area_listeners(state) time.sleep(0.1)
def notify_start_conversation_listeners(self): """ Notify start conversation listeners """ if not self.run_assistant: return for listener in self.start_conversation_listeners: s = State() s.type = USER_EVENT_TYPE listener(s)
def get_page(self, page, devices): """ Get page of devices for provided page number :param page: page number :param devices: list of all devices :return: page of devices """ p = {} if len(devices) == 0: return p start_index = (page - 1) * PAGE_SIZE_BLUETOOTH end_index = start_index + PAGE_SIZE_BLUETOOTH for i, d in enumerate(devices): s = State() s.index = i s.name = d["name"] s.l_name = s.name s.mac_address = d["mac_address"] s.comparator_item = i s.bgr = self.config[COLORS][COLOR_DARK] s.show_bgr = True if i >= start_index and i < end_index: p[d["name"]] = s return p
def change_track(self, track_index): """ Change track :param track_index: index track """ a = [AUDIOBOOKS, CD_PLAYER] m = self.config[CURRENT][MODE] if not (m in a): self.config[FILE_PLAYBACK][CURRENT_FILE] = self.get_filename( track_index) self.stop_timer() time.sleep(0.3) s = State() if m == FILE_PLAYBACK: s.playback_mode = self.config[FILE_PLAYBACK][ CURRENT_FILE_PLAYBACK_MODE] s.playlist_track_number = track_index s.index = track_index s.source = ARROW_BUTTON s.file_name = self.get_filename(track_index) if self.cd_album != None: s.album = self.cd_album if self.config[CURRENT][MODE] == AUDIO_FILES: folder = self.current_folder if not folder.endswith(os.sep): folder += os.sep s.url = folder + s.file_name self.set_current(True, s)
def create_keyboard(self, keyboard_type, span, transition_map): """ Create keyboard :param keyboard_type: type :param span: span :param transition_map: transition map """ layout = self.get_layout(span) buttons = [] keys = None self.current_keyboard_type = keyboard_type try: buttons = self.keyboards[keyboard_type] self.components = buttons return except: pass if keyboard_type == KEYBOARD_abc: keys = KEYBOARD_1 elif keyboard_type == KEYBOARD_ABC: keys = KEYBOARD_2 elif keyboard_type == KEYBOARD_123: keys = KEYBOARD_3 elif keyboard_type == KEYBOARD_symbol: keys = KEYBOARD_4 for i, k in enumerate(keys): if not k: c = Component(self.util, layout[i], bgr=self.config[BACKGROUND][MENU_BGR_COLOR]) c.parent_screen = self.screen c.name = "gap" + str(i) buttons.append(c) continue s = State() s.index = i s.name = k s.l_name = k s.comparator_item = s.index s.bgr = self.config[COLORS][COLOR_DARK] s.show_bgr = True s.bounding_box = layout[i] s.key_map = transition_map[i] button = self.factory.create_menu_button(s, layout[i], self.press_key, False, 50, 100, False, True) buttons.append(button) buttons[0].set_selected(True) self.keyboards[keyboard_type] = buttons self.components = buttons if keyboard_type != KEYBOARD_abc: self.set_observers() self.buttons = {i : item for i, item in enumerate(buttons)}
def handle_event(self, event): """ Handle menu events :param event: event object """ if not self.visible: return if event.type == USER_EVENT_TYPE and event.sub_type == SUB_TYPE_KEYBOARD and event.action == pygame.KEYUP: i = self.get_selected_index() k = event.keyboard_key if k == kbd_keys[KEY_LEFT]: if i == None: return if i == 0 and self.current_page == 1: pass elif i == 0 and self.current_page != 1: s = State() s.select_last = True self.previous_page(s) self.unselect() self.select_by_index(len(self.buttons) - 1) else: self.unselect() self.select_by_index(i - 1) elif k == kbd_keys[KEY_RIGHT]: if i == None: return if i == len(self.buttons) - 1: self.next_page(None) else: self.unselect() self.select_by_index(i + 1) elif k == kbd_keys[KEY_UP] or k == kbd_keys[KEY_DOWN]: Menu.handle_event(self, event) elif k == kbd_keys[KEY_SELECT] and not self.start_page_num: Menu.handle_event(self, event) elif k in kbd_num_keys: self.start_page_num = True self.current_page_num += self.get_num_str(k) self.set_title(int(self.current_page_num)) elif k == kbd_keys[KEY_SELECT] and self.start_page_num: self.start_page_num = False self.go_to_page(int(self.current_page_num)) self.current_page_num = "" self.select_by_index(0) elif k == kbd_keys[KEY_PARENT] and self.start_page_num: self.start_page_num = False self.current_page_num = "" self.reset_title() else: Menu.handle_event(self, event)
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 set_audio_file_playlist(self, index): """ Set file in playlist :param index: file index in playlist """ state = State() state.playback_mode = FILE_PLAYLIST state.playlist_track_number = index state.file_type = FILE_AUDIO self.current_folder = self.config[FILE_PLAYBACK][CURRENT_FOLDER] self.notify_play_listeners(state)
def notify_knob_listeners(self): """ Notify all knob event listeners """ for listener in self.knob_listeners: n = listener.__name__ if "mute" in n: listener() elif "update_web_ui" in n: state = State() state.event_origin = self listener(state) else: listener(self.get_position())
def refresh_tracks(self, state): """ Refresh tracks menu :param state: not used """ name = self.current_cd_drive_name if name and self.cdutil.is_drive_empty(name): s = State() s.no_physical_eject = True self.eject_cd(s) self.set_file_menu() self.set_screen_title()
def get_cd_track(self): """ Get CD track info for the track defined in the configuration :return: track info """ s = State() cd_drive = self.config[CD_PLAYBACK][CD_DRIVE_NAME] cd_track = self.config[CD_PLAYBACK][CD_TRACK] if cd_drive and cd_track: s.file_name = self.get_cd_track_url(cd_drive, int(cd_track)) s.url = s.file_name return s return None
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 load_playlist(self, state, playlist_provider, rows, columns): """ Handle playlist :param state: state object defining playlist :param playlist_provider: provider :param rows: menu rows :param columns: menu columns :return: playlist """ n = getattr(state, "file_name", None) if n == None: state.file_name = self.config[FILE_PLAYBACK][FILE_AUDIO] p = playlist_provider(state) if not p: return play_list = [] for i, n in enumerate(p): s = State() s.index = i s.playlist_track_number = i s.file_name = n s.file_type = FILE_AUDIO s.url = state.folder + os.sep + n s.playback_mode = FILE_PLAYLIST play_list.append(s) return self.load_playlist_content(play_list, rows, columns)
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 = {} for n in names: state = State() state.name = n state.l_name = self.config[LABELS][n] state.comparator_item = n state.bgr = self.config[COLORS][COLOR_DARK] delays[state.name] = state return delays
def get_audio_files_from_playlist(self): """ Call player for files in the playlist :return: list of files from playlist """ files = [] if getattr(self, "playlist", None): for n in range(len(self.playlist)): st = State() st.index = st.comparator_item = n t = self.playlist[n] st.file_type = FILE_AUDIO st.file_name = t["file_name"] files.append(st) return files
def get_filelist_items(self, get_current_playlist): """ Call player for files in the playlist :return: list of files from playlist """ playlist = get_current_playlist() files = [] if playlist: for n in range(len(playlist)): st = State() st.index = st.comparator_item = n st.file_type = FILE_AUDIO st.file_name = st.url = playlist[n] files.append(st) return files
def prepare_page(self): """ Prepare topic page :return: page dictionary """ page, self.first_item, self.last_item = self.get_current_page() p = {} for i, n in enumerate(page): s = State() s.index = i if "\x00" in n: n = n.replace("\x00", "") s.name = n s.l_name = n p[str(i)] = s return p
def 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 load_stations(self, language, genre, stations_per_page): """ Load stations for specified language and genre :param language: the language :param genre: the genre :param stations_per_page: stations per page used to assign indexes :return: list of button state objects. State contains station icons, index, genre, name etc. """ stations = [] folder = os.path.join(FOLDER_STATIONS, language, genre) path = os.path.join(folder, genre + EXT_M3U) lines = [] try: lines = codecs.open(path, "r", UTF_8).read().split("\n") except Exception as e: logging.error(str(e)) pass for i in range(0, len(lines), 3): if len(lines[i].rstrip()) == 0: continue index = int(lines[i].rstrip()[1:]) localized_name = lines[i + 1][1:] url = lines[i + 2] icon = self.load_station_icon(folder, index) state = State() state.index = index state.genre = genre state.url = url.rstrip() state.name = str(index) state.l_name = localized_name.rstrip() state.icon_base = icon state.comparator_item = INDEX state.index_in_page = index % stations_per_page stations.append(state) return stations
def create_arrow_button(self, bb, name, key, location, label_text, image_area=40): """ 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 :return: arrow button """ s = State() s.name = name s.bounding_box = bb s.keyboard_key = key s.bgr = self.config[COLORS][COLOR_DARK] s.show_bgr = True s.show_img = True s.show_label = True s.image_location = location s.label_location = CENTER s.image_area_percent = image_area s.label_text_height = 44 s.l_name = label_text s.auto_update = True 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) b = Button(self.util, s) return b
def create_station_button(self, s, bb, action=None): """ Create station button :param s: button state :param bb: bounding box :param action: event listener :return: station logo button """ state = State() state.icon_base = s.icon_base state.index_in_page = s.index_in_page state.index = s.index state.scaled = getattr(s, "scaled", False) state.icon_base_scaled = s.icon_base_scaled state.name = "station_menu." + 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.image_align_v = V_ALIGN_BOTTOM button = Button(self.util, state) button.add_release_listener(action) return button
def create_play_pause_button(self, bb, action): """ Create Play/Pause button :param bb: bounding box :param action: event listener :return: play/pause button """ states = [] pause_state = State() pause_state.name = "pause" pause_state.bounding_box = bb pause_state.bgr = (0, 0, 0) pause_state.keyboard_key = kbd_keys[KEY_PLAY_PAUSE] pause_state.action = action pause_state.img_x = None pause_state.img_y = None pause_state.auto_update = True pause_state.image_align_v = V_ALIGN_CENTER pause_state.show_bgr = True pause_state.show_img = True states.append(pause_state) play_state = State() play_state.name = "play" play_state.bounding_box = bb play_state.bgr = (0, 0, 0) play_state.keyboard_key = kbd_keys[KEY_PLAY_PAUSE] play_state.action = action play_state.img_x = None play_state.img_y = None play_state.auto_update = True play_state.image_align_v = V_ALIGN_CENTER play_state.show_bgr = True play_state.show_img = True states.append(play_state) return self.create_multi_state_button(states)
def create_image_button(self, name, action=None, keyboard_key=None, lirc_code=None, bounding_box=None, bgr=(0, 0, 0), x_margin_percent=None, resizable=True): """ Create image button :param name: button name :param action: action listener :param keyboard_key: keyboard key assigned to the button :param lirc_code: LIRC code assigned to the button :param bounding_box: button bounding box :param bgr: button background color :param x_margin_percent: X margin for the button :param resizable: flag defining if button can be resized, True - resizable, False - non-resizable """ state = State() state.name = name state.bounding_box = bounding_box state.bgr = bgr state.keyboard_key = keyboard_key state.lirc_code = lirc_code state.img_x = None state.img_y = None state.auto_update = True state.show_bgr = True state.show_img = True state.image_align_v = V_ALIGN_CENTER state.x_margin_percent = x_margin_percent state.resizable = resizable self.set_state_icons(state) button = Button(self.util, state) if action: button.add_release_listener(action) return button
def create_toggle_button(self, name, keyboard_key=None, lirc_code=None, bounding_box=None): """ 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 = (0, 0, 0) 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 self.set_state_icons(state) button = ToggleButton(self.util, state) return button
def load_menu(self, names, comparator, disabled_items=None): """ Load menu items :param names: list of menu item names (should have corresponding filename) :param comparator: string used to sort items :param disabled_items: list of items which should be disabled :return: dictionary with menu items """ items = {} f = self.config[ICON_SIZE_FOLDER] for name in names: filename = name + EXT_PNG path = os.path.join(FOLDER_ICONS, f, filename) icon = self.load_image(path) filename = name + IMAGE_SELECTED_SUFFIX + EXT_PNG path_on = os.path.join(FOLDER_ICONS, f, filename) icon_on = self.load_image(path_on) filename = name + IMAGE_DISABLED_SUFFIX + EXT_PNG path_off = os.path.join(FOLDER_ICONS, f, filename) icon_off = self.load_image(path_off) state = State() state.name = name state.genre = name state.l_genre = self.config[LABELS][name] state.l_name = self.config[LABELS][name] state.icon_base = icon if icon_on: state.icon_selected = icon_on else: state.icon_selected = icon if not icon_off: state.icon_disabled = icon_on 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 if comparator == NAME: state.comparator_item = state.name elif comparator == GENRE: state.comparator_item = state.genre if disabled_items and name in disabled_items: state.enabled = False items[state.name] = state return items