class Colorbar(object): ''' Colorbar window ''' def __init__(self, parent=None, screenshot=None): ''' init colorbar @param parent: the transient parent for this window @param screenshot: a Screenshot object ''' self.screenshot = screenshot self.win = self.screenshot.window self.height = 36 self.width = 279 self.window = Window(window_type=gtk.WINDOW_POPUP, shadow_visible=False) self.window.set_type_hint(gtk.gdk.WINDOW_TYPE_HINT_DIALOG) self.window.set_keep_above(True) self.window.set_transient_for(parent) self.window.set_decorated(False) #vbox = gtk.VBox(False, 0) self.box = gtk.HBox(False, 5) self.size_box = gtk.HBox(False, 5) self.dynamic_box = gtk.HBox() colorbox_align = gtk.Alignment() #colorbox_align.set(0.5, 0.5, 0, 0) colorbox_align.set(0, 0.5, 1, 0) colorbox_align.set_padding(2, 2, 11, 11) colorbox_align.add(self.box) self.window.window_frame.pack_start(colorbox_align, True, True) self.window.set_size_request(self.width, self.height) #self.window.set_size_request(-1, self.height) self.__size_button_dict = {} self.create_size_button("small", ACTION_SIZE_SMALL) self.create_size_button("normal", ACTION_SIZE_NORMAL) self.create_size_button("big", ACTION_SIZE_BIG) self.create_size_button("ellipse_fill", ACTION_SIZE_RECTANGLE_ELLIPSE_FILL) self.create_size_button("rect_fill", ACTION_SIZE_RECTANGLE_ELLIPSE_FILL) self._set_size_button_state("small", True) self.size_align = gtk.Alignment() #self.size_align.set(0.5,0.5,0,0) self.size_align.set(0, 0.5, 1, 0) self.size_align.add(self.size_box) #self.dynamic_box.pack_start(self.size_align) self.box.pack_start(self.dynamic_box) # font select self.font_box = gtk.HBox(False, 5) font_img = gtk.image_new_from_pixbuf(app_theme.get_pixbuf("action/text_normal.png").get_pixbuf()) self.font_spin = SpinBox(self.screenshot.font_size, 8, 72, 1) self.font_spin.connect("value-changed", self._font_size_changed) self.font_spin.value_entry.set_can_focus(False) self.font_box.pack_start(font_img) self.font_box.pack_start(self.font_spin) self.font_align = gtk.Alignment() self.font_align.set(0.5,0.5,0,0) self.font_align.add(self.font_box) # color select #self.color_select = gtk.EventBox() self.color_select = gtk.Image() pix = app_theme.get_pixbuf("color_big/red.png").get_pixbuf() self.color_select.set_from_pixbuf(pix) self.box.pack_start(self.color_select, False, False) # color button self.vbox = gtk.VBox(False, 2) self.above_hbox = gtk.HBox(False, 2) self.below_hbox = gtk.HBox(False, 2) self.color_map = { 'black' : "#000000", # 1-1 'gray_dark' : "#808080", # 1-2 'red' : "#FF0000", # 1-3 'yellow_dark' : "#FF9B00", # 1-4 'yellow' : "#FFFF00", # 1-5 'green' : "#B2E700", # 1-6 'green_dark' : "#008000", # 1-7 'wathet_dark' : "#008080", # 1-8 'white' : "#FFFFFF", # 2-1 'gray' : "#C0C0C0", # 2-2 'red_dark' : "#E2004E", # 2-3 'pink' : "#E2007A", # 2-4 'pink_dark' : "#800080", # 2-5 'blue_dark' : "#000080", # 2-6 'blue' : "#0085E1", # 2-7 'wathet' : "#009DE0"} # 2-8 self.create_color_button(self.above_hbox, "black") self.create_color_button(self.above_hbox, "gray_dark") self.create_color_button(self.above_hbox, "red") self.create_color_button(self.above_hbox, "yellow_dark") self.create_color_button(self.above_hbox, "yellow") self.create_color_button(self.above_hbox, "green") self.create_color_button(self.above_hbox, "green_dark") self.create_color_button(self.above_hbox, "wathet_dark") self.create_color_button(self.below_hbox, "white") self.create_color_button(self.below_hbox, "gray") self.create_color_button(self.below_hbox, "red_dark") self.create_color_button(self.below_hbox, "pink") self.create_color_button(self.below_hbox, "pink_dark") self.create_color_button(self.below_hbox, "blue_dark") self.create_color_button(self.below_hbox, "blue") self.create_color_button(self.below_hbox, "wathet") self.vbox.pack_start(self.above_hbox) self.vbox.pack_start(self.below_hbox) self.box.pack_start(self.vbox) def create_color_button(self, box, name): ''' create color button @param box: a gtk.HBox @param name: the button's name ''' button = ImageButton( app_theme.get_pixbuf("color/" + name + ".png"), app_theme.get_pixbuf("color/" + name + "_hover.png"), app_theme.get_pixbuf("color/" + name + "_hover.png")) button.connect('pressed', lambda w:self._color_button_pressed(name)) box.pack_start(button) def create_toggle_button(self, name): ''' create a togglebutton @param name: the button's name @return: a dtk.ui.ToggleButton ''' button = ToggleButton( app_theme.get_pixbuf("size/" + name + ".png"), app_theme.get_pixbuf("size/" + name + "_press.png"), app_theme.get_pixbuf("size/" + name + "_hover.png"), app_theme.get_pixbuf("size/" + name + "_press.png")) button.set_name(name) return button def create_size_button(self, name, index): ''' create size button @param name: the button's name @param index: the button's index in button list @return: a dtk.ui.ToggleButton ''' button = self.create_toggle_button(name) button.connect("pressed", self._size_button_pressed, index) #button.connect("toggled", self._size_button_toggled, name) button.connect("released", self._size_button_released) self.size_box.pack_start(button) self.__size_button_dict[name] = button return button def _font_size_changed(self, widget, value): '''font size changed, SpinBox changed callback''' self.screenshot.font_size = value if self.screenshot.show_text_window_flag: if not self.screenshot.text_window.set_font_size(value): #print value, self.screenshot.text_window.get_font_size() widget.set_value(self.screenshot.text_window.get_font_size()) self.win.refresh() def _color_button_pressed(self, name): ''' color button pressed callback''' pix = app_theme.get_pixbuf("color_big/" + name + ".png").get_pixbuf() self.color_select.set_from_pixbuf(pix) if self.screenshot is None: return self.screenshot.action_color = self.color_map[name] if self.screenshot.show_text_window_flag: self.screenshot.text_window.set_text_color(self.screenshot.action_color) self.win.refresh() def _size_button_pressed(self, widget, index): ''' size button pressed callback''' if self.screenshot is None: return self.screenshot.action_size = index for each in self.__size_button_dict: if self.__size_button_dict[each] == widget: continue else: self.__size_button_dict[each].set_active(False) def _size_button_released(self, widget): ''' size button release callback''' if not widget.get_active(): widget.set_active(True) def _set_size_button_state(self, name, state): ''' set size button state @param name: the button's name which will set @param state: the state to set, True or False ''' for each in self.__size_button_dict.keys(): if each == name: self.__size_button_dict[name].set_active(state) def show(self): ''' show the colorbar''' # action is text, show font size set if self.screenshot.action == ACTION_TEXT: self.window.set_size_request(self.width, self.height) self.window.resize(self.width, self.height) if self.size_align in self.dynamic_box.get_children(): self.dynamic_box.remove(self.size_align) if self.font_align not in self.dynamic_box.get_children(): self.dynamic_box.add(self.font_align) self.dynamic_box.show_all() # show draw size else: if self.font_align in self.dynamic_box.get_children(): self.dynamic_box.remove(self.font_align) if self.size_align not in self.dynamic_box.get_children(): self.dynamic_box.add(self.size_align) self.dynamic_box.show_all() # actin is rectangle or ellispe, show fill button # show rect fill button if self.screenshot.action == ACTION_RECTANGLE: self.window.set_size_request(self.width, self.height) self.window.resize(self.width, self.height) if self.__size_button_dict['rect_fill'] not in self.size_box.get_children(): self.size_box.pack_start(self.__size_button_dict['rect_fill']) if self.__size_button_dict['ellipse_fill'] in self.size_box.get_children(): self.size_box.remove(self.__size_button_dict['ellipse_fill']) if self.__size_button_dict['ellipse_fill'].get_active(): self.__size_button_dict['rect_fill'].pressed() self.__size_button_dict['rect_fill'].released() # show ellipse fill button elif self.screenshot.action == ACTION_ELLIPSE: self.window.set_size_request(self.width, self.height) self.window.resize(self.width, self.height) if self.__size_button_dict['ellipse_fill'] not in self.size_box.get_children(): self.size_box.pack_start(self.__size_button_dict['ellipse_fill']) if self.__size_button_dict['rect_fill'] in self.size_box.get_children(): self.size_box.remove(self.__size_button_dict['rect_fill']) if self.__size_button_dict['rect_fill'].get_active(): self.__size_button_dict['ellipse_fill'].pressed() self.__size_button_dict['ellipse_fill'].released() # don't show fill button else: self.window.set_size_request(self.width, self.height) self.window.resize(self.width, self.height) if self.__size_button_dict['rect_fill'] in self.size_box.get_children(): if self.__size_button_dict['rect_fill'].get_active(): self.__size_button_dict['small'].pressed() self.__size_button_dict['small'].released() self.size_box.remove(self.__size_button_dict['rect_fill']) if self.__size_button_dict['ellipse_fill'] in self.size_box.get_children(): if self.__size_button_dict['ellipse_fill'].get_active(): self.__size_button_dict['small'].pressed() self.__size_button_dict['small'].released() self.size_box.remove(self.__size_button_dict['ellipse_fill']) self.size_box.show_all() if not self.window.get_visible(): self.window.show_window() #print "colorbox:", self.box.allocation, self.window.allocation def hide(self): '''hide the toolbar''' if self.window.get_visible(): self.window.hide_all()
class Toolbar(object): ''' Toolbar window''' def __init__(self, parent=None, screenshot=None): ''' init toolbar @param parent: the transient parent for this window @param screenshot: a Screenshot object ''' self.screenshot = screenshot self.win = screenshot.window self.__config = OperateConfig() save_op = self.__config.get("save", "save_op") if save_op: self.screenshot.save_op_index = int(save_op) else: self.screenshot.save_op_index = SAVE_OP_AUTO #toolbar_padding_x = 15 #toolbar_padding_y = 5 #toolbar_icon_width = toolbar_icon_height = 28 #toolbar_icon_num = 10 #self.height = toolbar_icon_height + toolbar_padding_y * 2 self.height = 30 self.width = 279 #self.width = 240 self.window = Window(window_type=gtk.WINDOW_POPUP, shadow_visible=False) self.window.set_keep_above(True) self.window.set_decorated(False) self.window.set_transient_for(parent) self.toolbox = gtk.HBox(False, 6) toolbox_align = gtk.Alignment() toolbox_align.set(0, 0.5, 0, 0) toolbox_align.set_padding(2, 2, 11, 11) toolbox_align.add(self.toolbox) self.window.window_frame.pack_start(toolbox_align, True, True) #self.window.set_size_request(self.width, self.height) self.window.set_size_request(-1, self.height) self._toggle_button_list = [] self.__button_accelerator_dict = {} self._toggle_button_group = ToggleButtonGroup([], 6) self.toolbox.pack_start(self._toggle_button_group) self.create_toggle_button("rect", ACTION_RECTANGLE, 0, _("Draw Rectangle"), "<Alt>1") self.create_toggle_button("ellipse", ACTION_ELLIPSE, 1, _("Draw Ellipse"), "<Alt>2") self.create_toggle_button("arrow",ACTION_ARROW, 2, _("Draw Arrow"), "<Alt>3") self.create_toggle_button("line",ACTION_LINE, 3, _("Draw Line"), "<Alt>4") self.create_toggle_button("text",ACTION_TEXT, 4, _("Draw Text"), "<Alt>5") self.create_button("undo", _("Undo"), "<Alt>6") if self.screenshot.is_subprocess: self.create_button("save", _("Save"), "<Alt>7") else: # pack save and list button save_combo_button = ComboButton( app_theme.get_pixbuf("action/save_normal.png"), app_theme.get_pixbuf("action/save_hover.png"), app_theme.get_pixbuf("action/save_press.png"), app_theme.get_pixbuf("action/save_normal.png"), app_theme.get_pixbuf("action/list_normal.png"), app_theme.get_pixbuf("action/list_hover.png"), app_theme.get_pixbuf("action/list_press.png"), app_theme.get_pixbuf("action/list_normal.png"),) save_combo_button.set_name("save") save_combo_button.connect("button-clicked", self._button_clicked, "save") save_combo_button.connect("arrow-clicked", self._list_menu_show) save_tip_text_list = ["Save automatically", "Save as", "Save to clipboard", "Save automatically to file and clipboard"] tip_text = save_tip_text_list[self.screenshot.save_op_index] save_combo_button.connect("enter-notify-event", self._show_tooltip, _(tip_text)) self.toolbox.pack_start(save_combo_button) self.create_button("cancel", _("Cancel"), "<Alt>8") if not self.screenshot.is_subprocess: self.create_button("share", _("Share"), "<Alt>9") if self.screenshot: self._button_clicked_cb = { 'undo': self.screenshot.undo, 'save': self.save_operate, 'cancel': self.win.quit, 'share': self.share_picture} def create_toggle_button(self, name, action, index, text='', accel_key=None): ''' create a togglebutton @param name: the button's name, a string @param action: one of ACTION Type Constants @param index: the button's index in button list, an int num @param text: the button's tooltip text, a string ''' button = ToggleButtonItem( (app_theme.get_pixbuf("action/" + name + "_normal.png"), app_theme.get_pixbuf("action/" + name + "_press.png"), app_theme.get_pixbuf("action/" + name + "_hover.png"), app_theme.get_pixbuf("action/" + name + "_press.png"), None), index, self._toggle_button_group.set_index, self._toggle_button_group.get_index) button.connect("pressed", self._toggle_button_pressed) button.connect("toggled", self._toggle_button_toggled, action) button.connect("enter-notify-event", self._show_tooltip, text) button.set_name(name) #self.toolbox.pack_start(button) self._toggle_button_group.pack_start(button) self._toggle_button_list.append(button) if accel_key: self.__button_accelerator_dict[gtk.accelerator_name( *gtk.accelerator_parse(accel_key))] = button def create_button(self, name, text='', accel_key=None): ''' make a button @param name: the button's name, a string @param text: the button's tooltip text, a string ''' button = ImageButton( app_theme.get_pixbuf("action/" + name + "_normal.png"), app_theme.get_pixbuf("action/" + name + "_hover.png"), app_theme.get_pixbuf("action/" + name + "_press.png")) button.connect("enter-notify-event", self._show_tooltip, text) button.connect("clicked", self._button_clicked, name) button.set_name(name) #button.set_size_request(28, 28) self.toolbox.pack_start(button) if accel_key: self.__button_accelerator_dict[gtk.accelerator_name( *gtk.accelerator_parse(accel_key))] = button return button def _show_tooltip(self, widget, event, text): '''the button enter-notify-event callback. Create help tooltip.''' #widget.set_has_tooltip(True) #widget.set_tooltip_text(text) #widget.trigger_tooltip_query() Tooltip.text(widget, text) def _list_menu_show(self, button, x, y, offset_x, offset_y): '''the combo button clicked callback. show combo_buton list menu''' menu_item = [ (None, _("Save automatically"), self._list_menu_click, SAVE_OP_AUTO, button), (None, _("Save as"), self._list_menu_click, SAVE_OP_AS, button), (None, _("Save to clipboard"), self._list_menu_click, SAVE_OP_CLIP, button), (None, _("Save automatically to file and clipboard"), self._list_menu_click, SAVE_OP_AUTO_AND_CLIP, button)] # set current operate icon current_item = menu_item[self.screenshot.save_op_index] menu_pixbuf = ( app_theme.get_pixbuf("action/selected.png"), app_theme.get_pixbuf("action/selected_hover.png"), app_theme.get_pixbuf("action/selected.png")) menu_item[self.screenshot.save_op_index] = (menu_pixbuf, current_item[1], current_item[2], current_item[3]) self.combo_menu = Menu(menu_item, is_root_menu=True, menu_item_select_color=app_theme.get_shadow_color("menu_item_select").get_color_info()) self.set_all_inactive() self.combo_menu.show((x, y), (offset_x, offset_y)) def _list_menu_click(self, save_op_index, button=None): '''list menu clicked callback''' self.screenshot.save_op_index = save_op_index self.__config.set("save", save_op=str(save_op_index)) # reset the save button's tooltip if button: item = self.combo_menu.get_menu_items()[save_op_index] button.disconnect_by_func(self._show_tooltip) button.connect("enter-notify-event", self._show_tooltip, item.item[1]) self.combo_menu.destroy() self.save_operate() def _button_clicked(self, widget, name): ''' button clicked callback ''' if self.screenshot is None: return # save current input text if self.screenshot.show_text_window_flag: self.win.save_text_window() if name in self._button_clicked_cb: self._button_clicked_cb[name](widget) def _toggle_button_pressed(self, widget): ''' toggle button pressed callback ''' # save current input text if self.screenshot.show_text_window_flag: self.win.save_text_window() widget.released() def _toggle_button_toggled(self, widget, action): ''' toggle button toggled callback''' if self.screenshot is None: return if widget.get_active(): self.screenshot.set_action_type(action) self.win.set_cursor(action) self.win.show_colorbar() self.win.adjust_colorbar() elif widget.index == widget.get_index(): self.win.set_cursor(None) self.win.hide_colorbar() if not self.screenshot.action_list and not self.screenshot.text_action_list and self.screenshot.show_toolbar_flag and not self.screenshot.window_flag: self.screenshot.set_action_type(ACTION_SELECT) elif self.screenshot.action_list: self.screenshot.set_action_type(None) def set_button_active(self, name, state): ''' set button active @param name: the button's name which will set, a string type @param state: the state to set, True or False ''' if self._toggle_button_group.is_active(): button = self._toggle_button_list[self._toggle_button_group.get_index()] # if the button has been in this state, ignore if button.name == name: if button.get_active() == state: return else: button.set_active(False) self._toggle_button_group.set_index(-1) i = 0 for each in self._toggle_button_list: if name == each.get_name(): each.set_active(state) self._toggle_button_group.set_index(i) break i += 1 def has_button_active(self): ''' is has one toggle button active @return: True if has one togglebutton active, otherwise False ''' return self._toggle_button_group.is_active() def save_operate(self, widget=None): '''do save operate''' screenshot = self.screenshot if screenshot.is_subprocess: screenshot.save_to_tmp_file() else: # auto save if screenshot.save_op_index == SAVE_OP_AUTO: folder = utils.get_pictures_dir() filename = "%s%s.%s" % (_(DEFAULT_FILENAME), utils.get_format_time(), "png") screenshot.save_snapshot("%s/%s" % (folder, filename)) # save as elif screenshot.save_op_index == SAVE_OP_AS: self.save_to_file() # copy to clip elif screenshot.save_op_index == SAVE_OP_CLIP: screenshot.save_snapshot() # auto save and copy to clip else: folder = utils.get_pictures_dir() filename = "%s%s.%s" % (_(DEFAULT_FILENAME), utils.get_format_time(), "png") screenshot.save_snapshot("%s/%s" % (folder, filename), clip_flag=True) def share_picture(self, widget): '''share picture. share button clicked callback''' self.screenshot.share_to_flag = True self.screenshot.save_op_index = SAVE_OP_AUTO self.save_operate() def save_to_file(self): ''' save to file ''' self.win.hide_colorbar() self.win.hide_toolbar() #dialog = SaveFileDialog('', self.screenshot.window.window, #ok_callback=self._save_to_file_cb, cancel_callback=self._save_to_file_cancel) dialog = gtk.FileChooserDialog( "Save..", self.win.window, gtk.FILE_CHOOSER_ACTION_SAVE, (gtk.STOCK_CANCEL, gtk.RESPONSE_REJECT, gtk.STOCK_SAVE, gtk.RESPONSE_ACCEPT)) dialog.set_action(gtk.FILE_CHOOSER_ACTION_SAVE) dialog.set_default_response(gtk.RESPONSE_ACCEPT) dialog.set_position(gtk.WIN_POS_MOUSE) dialog.set_local_only(True) last_folder = self.__config.get("save", "folder") if last_folder: dialog.set_current_folder(last_folder) else: dialog.set_current_folder(utils.get_pictures_dir()) if config.OPTION_FILE: dialog.set_current_name(config.OPTION_FILE) else: dialog.set_current_name("%s%s.%s" % (_(DEFAULT_FILENAME), utils.get_format_time(), "png")) response = dialog.run() filename = dialog.get_filename() if response == gtk.RESPONSE_ACCEPT: self.__config.set("save", folder=dialog.get_current_folder()) self._save_to_file_cb(filename) else: self._save_to_file_cancel(filename) dialog.destroy() def _save_to_file_cancel(self, filename): ''' save file dialog cancel_callback''' self.screenshot.share_to_flag = False self.win.adjust_toolbar() self.win.show_toolbar() if self.has_button_active(): self.win.show_colorbar() def _save_to_file_cb(self, filename): ''' save file dialog ok_callback''' print "save", filename self.screenshot.save_snapshot(filename=filename) def set_all_inactive(self): '''set all toggle button inactive''' #index = self._toggle_button_group.get_index() #if index != -1: #self._toggle_button_list[index].set_active(False) #for each in self._toggle_button_list: #each.set_active(False) if self._toggle_button_group.is_active(): self._toggle_button_group.set_index(-1) def accel_group_callback(self, group, acceleratable, keyval, modifier): accel_name = gtk.accelerator_name(keyval, modifier) if accel_name in self.__button_accelerator_dict: button = self.__button_accelerator_dict[accel_name] button.pressed() button.released() #button.clicked() self.set_button_active(button.get_name(), True) def show(self): ''' show the toolbar ''' if not self.window.get_visible(): self.window.show_window() #print "toolbox:", self.toolbox.allocation, self.window.allocation def hide(self): '''hide the toolbar''' if self.window.get_visible(): self.window.hide_all()
class LyricsModule(object): def __init__(self): self.desktop_lyrics_win = DesktopLyrics() self.desktop_lyrics_win.connect("moved", self.adjust_toolbar_rect) self.desktop_lyrics_win.connect("resized", self.adjust_toolbar_rect) self.desktop_lyrics_win.connect("hide-bg", self.hide_toolbar) self.desktop_lyrics_win.connect("show-bg", self.show_toolbar) self.desktop_lyrics_win.connect("button-press-event", self.popup_desktop_right_menu) self.desktop_lyrics_win.connect("configure-event", self.lyrics_desktop_configure_event) self.scroll_lyrics = ScrollLyrics() self.scroll_lyrics.connect("configure-event", self.lyrcis_scroll_configure_event) self.scroll_lyrics.revert_button.connect("clicked", lambda w: self.switch_to_desktop_lyrics()) self.scroll_lyrics.connect("seek", self.seek_cb) self.scroll_lyrics.connect("right-press", self.scroll_right_press_cb) Player.connect("instant-new-song", self.instant_update_lrc) Player.connect("played", self.play_time_source) Player.connect("paused", self.pause_time_source) Player.connect("play-end", self.pause_time_source) Dispatcher.connect("reload-lrc", self.update_lrc) Dispatcher.connect("unlock-lyrics", self.__unlock_lyrics) Dispatcher.connect("lock-lyrics", self.__lock_lyrics) Dispatcher.connect("show-lyrics", lambda w : self.run()) Dispatcher.connect("close-lyrics", lambda w: self.hide_all()) Dispatcher.connect("search-lyrics", lambda w: self.open_search_window(w)) Dispatcher.connect("dialog-run", self.on_dialog_run) Dispatcher.connect("dialog-close", self.on_dialog_close) self.lrc_manager = LrcManager() self.lrc = LrcParser() self.search_ui = SearchUI() self.lrc_id = -1 self.lrc_next_id = -1 self.current_line = 0 self.message_source = None self.time_source = None self.song_duration = 0 self.__find_flag = False self.__lyrics_mode = config.getint("lyrics", "mode") self.__dialog_locked_flag = False self.init_toolbar() self.current_song = None self.next_lrc_to_download = None self.condition = threading.Condition() self.thread = threading.Thread(target=self.func_thread) self.thread.setDaemon(True) self.thread.start() def init_toolbar(self): self.toolbar = Window(window_type=gtk.WINDOW_POPUP) self.toolbar.set_size_request(-1, 41) padding_x, padding_y = 10, 5 play_box = gtk.HBox(spacing=2) play_box.connect("expose-event", self.expose_toolbar_mask) # swap played status handler Player.connect("played", self.__swap_play_status, True) Player.connect("paused", self.__swap_play_status, False) Player.connect("stopped", self.__swap_play_status, False) Player.connect("play-end", self.__swap_play_status, False) self.playpause_button = ToggleButton( app_theme.get_pixbuf("lyric/play_normal.png"), app_theme.get_pixbuf("lyric/pause_normal.png"), app_theme.get_pixbuf("lyric/play_hover.png"), app_theme.get_pixbuf("lyric/pause_hover.png"), app_theme.get_pixbuf("lyric/play_press.png"), app_theme.get_pixbuf("lyric/pause_press.png"), ) self.__id_signal_play = self.playpause_button.connect("toggled", lambda w: Player.playpause()) prev = self.__create_button("previous") next = self.__create_button("next") prev_align = gtk.Alignment() prev_align.set(0.5, 0.5, 0, 0) prev_align.add(prev) next_align = gtk.Alignment() next_align.set(0.5, 0.5, 0, 0) next_align.add(next) play_align = gtk.Alignment() play_align.set_padding(2, 0, 0, 0) play_align.set(0.5, 0.5, 0, 0) play_align.add(self.playpause_button) # separte line separate_line = ImageBox(app_theme.get_pixbuf("lyric/separate.png")) sep_align = gtk.Alignment() sep_align.set(0.5, 0.5, 0, 0) sep_align.add(separate_line) zoom_in_align = self.__create_zoom_button("zoom_in", _("increase the lyrics size")) zoom_out_align = self.__create_zoom_button("zoom_out", _("decrease the lyrics size")) predefine_align = self.__create_simple_button("predefine_color", self.popup_predefine_menu, _("Select color theme"), True) lock_align = self.__create_simple_button("lock", self.__lock_lyrics, _("Lock lyrics")) karaoke_align, self.karaoke_button = self.__create_single_toggle_button("karaoke", self.change_karaoke_status, _("karaoke on/off")) line_align, self.line_button = self.__create_simple_toggle_button("double_line", "single_line", self.change_line_status, _("Switch lines")) setting_align = self.__create_simple_button("setting", self.open_setting_window, _("Open settings panel")) search_align = self.__create_simple_button("search", self.open_search_window, _("search lrc file for current track")) close_align = self.__create_simple_button("close", self.close_lyric_window, _("Close lyrics")) before_align = self.__create_simple_button("before", self.before_offset, _("Lyrics rewind")) after_align = self.__create_simple_button("after", self.after_offset, _("Lyrics forward")) lrc_align = self.__create_simple_button("lrc", self.switch_to_scroll_lyrics, _("Switch to window mode")) play_box.pack_start(prev_align, False, False) play_box.pack_start(play_align, False, False) play_box.pack_start(next_align, False, False) play_box.pack_start(sep_align, False, False) play_box.pack_start(zoom_in_align, False, False) play_box.pack_start(zoom_out_align, False, False) play_box.pack_start(before_align, False, False) play_box.pack_start(after_align, False, False) play_box.pack_start(predefine_align, False, False) play_box.pack_start(karaoke_align, False, False) play_box.pack_start(line_align, False, False) play_box.pack_start(lock_align, False, False) play_box.pack_start(setting_align, False, False) play_box.pack_start(lrc_align, False, False) play_box.pack_start(search_align, False, False) play_box.pack_start(close_align, False, False) main_align = gtk.Alignment() main_align.set_padding(0, 0, padding_x, padding_x) main_align.set(0.5, 0.5, 0, 0) main_align.add(play_box) self.toolbar.window_frame.pack_start(main_align) self.load_button_status() def expose_toolbar_mask(self, widget, event): cr = widget.window.cairo_create() rect = widget.allocation draw_alpha_mask(cr, rect.x - 9, rect.y, rect.width + 18, rect.height, "lyricsMask") return False def scroll_right_press_cb(self, widget, event): menu_items = [ (self.get_scroll_menu_pixbufs("lrc"), _("Switch to desktop mode"), self.switch_to_desktop_lyrics), None, (self.get_scroll_menu_pixbufs("before"), _("Lyrics rewind"), lambda : self.before_offset(None)), (self.get_scroll_menu_pixbufs("after"), _("Lyrics forward"), lambda : self.after_offset(None)), None, (self.get_scroll_menu_pixbufs("search"), _("Search"), lambda :self.open_search_window(None)), (self.get_scroll_menu_pixbufs("setting"), _("Settings"), lambda : Dispatcher.show_scroll_page()), ] Menu(menu_items, True).show((int(event.x_root), int(event.y_root))) def popup_desktop_right_menu(self, widget, event): if event.button == 3 and Player.song: adjust_menu_item = [(None, _("Forward 0.5 seconds"), lambda : self.after_offset(None)), (None, _("Rewind 0.5 seconds"), lambda : self.before_offset(None))] menu_items = [ (None, _("Search"), lambda : self.open_search_window(None)), (None, _("Adjust lyrics"), Menu(adjust_menu_item)), None, (None, _("Choose local lrc"), self.allocation_lrc), (None, _("Open directory"), self.open_lrc_dir), None, (None, _("Settings"), lambda : self.open_setting_window(None)), (None, _("Switch to window mode"), lambda : self.switch_to_scroll_lyrics(None)) ] Menu(menu_items, True).show((int(event.x_root), int(event.y_root))) def allocation_lrc(self): lrc_path = WinFile(False).run() if lrc_path: self.lrc_manager.allocation_lrc_file(Player.song, lrc_path) def open_lrc_dir(self): save_dir = os.path.expanduser(config.get("lyrics", "save_lrc_path", "~/.lyrics")) utils.run_command("xdg-open %s" % save_dir) def get_scroll_menu_pixbufs(self, name): return ( app_theme.get_pixbuf("lyric/%s_normal.png" % name), None, None) def switch_to_scroll_lyrics(self, widget): config.set("lyrics", "mode", str(LRC_WINDOW_MODE)) self.__lyrics_mode = LRC_WINDOW_MODE self.hide_desktop_lyrics() self.show_scroll_lyrics() self.play_time_source() def switch_to_desktop_lyrics(self): config.set("lyrics", "mode", str(LRC_DESKTOP_MODE)) self.__lyrics_mode = LRC_DESKTOP_MODE self.hide_scroll_lyrics() self.show_desktop_lyrics() self.play_time_source() def seek_cb(self, widget, lyric_id, percentage): item_time = self.lrc.get_item_time(lyric_id) new_time = item_time / 1000 if Player.song.get_type() == "cue": new_time += Player.song.get("seek", 0) Player.seek(new_time) self.scroll_lyrics.set_progress(lyric_id, percentage) time.sleep(0.1) def load_button_status(self): if not config.getboolean("lyrics","karaoke_mode"): self.karaoke_button.set_active(True) if config.getint("lyrics", "line_count") == 1: self.line_button.set_active(True) def __create_simple_button(self, name, callback, tip_msg=None, has_event=False): button = ImageButton( app_theme.get_pixbuf("lyric/%s_normal.png" % name), app_theme.get_pixbuf("lyric/%s_hover.png" % name), app_theme.get_pixbuf("lyric/%s_press.png" % name) ) if has_event: button.connect("button-press-event", callback) else: button.connect("clicked", callback) if tip_msg: Tooltip.text(button, tip_msg) button_align = gtk.Alignment() button_align.set(0.5, 0.5, 0, 0) button_align.add(button) return button_align def __create_simple_toggle_button(self, normal_name, active_name, callback, tip_msg=None): toggle_button = ToggleButton( app_theme.get_pixbuf("lyric/%s_normal.png" % normal_name), app_theme.get_pixbuf("lyric/%s_normal.png" % active_name), app_theme.get_pixbuf("lyric/%s_hover.png" % normal_name), app_theme.get_pixbuf("lyric/%s_hover.png" % active_name), app_theme.get_pixbuf("lyric/%s_press.png" % normal_name), app_theme.get_pixbuf("lyric/%s_press.png" % active_name), ) toggle_button.connect("toggled", callback) toggle_align = gtk.Alignment() toggle_align.set(0.5, 0.5, 0, 0) toggle_align.add(toggle_button) if tip_msg: Tooltip.text(toggle_button, tip_msg) return toggle_align, toggle_button def __create_single_toggle_button(self, normal_name, callback, tip_msg=None): if normal_name == "karaoke": toggle_button = ToggleButton( app_theme.get_pixbuf("lyric/%s_press.png" % normal_name), app_theme.get_pixbuf("lyric/%s_normal.png" % normal_name), app_theme.get_pixbuf("lyric/%s_hover.png" % normal_name), ) else: toggle_button = ToggleButton( app_theme.get_pixbuf("lyric/%s_normal.png" % normal_name), app_theme.get_pixbuf("lyric/%s_press.png" % normal_name), app_theme.get_pixbuf("lyric/%s_hover.png" % normal_name), ) toggle_button.connect("toggled", callback) toggle_align = gtk.Alignment() toggle_align.set(0.5, 0.5, 0, 0) toggle_align.add(toggle_button) if tip_msg: Tooltip.text(toggle_button, tip_msg) return toggle_align, toggle_button def __create_button(self, name, tip_msg=None): button = ImageButton( app_theme.get_pixbuf("lyric/%s_normal.png" % name), app_theme.get_pixbuf("lyric/%s_hover.png" % name), app_theme.get_pixbuf("lyric/%s_press.png" % name) ) button.connect("clicked", self.player_control, name) return button def __swap_play_status(self, obj, active): self.playpause_button.handler_block(self.__id_signal_play) self.playpause_button.set_active(active) self.playpause_button.handler_unblock(self.__id_signal_play) def __create_zoom_button(self, name, msg=None): button = ImageButton( app_theme.get_pixbuf("lyric/%s_normal.png" % name), app_theme.get_pixbuf("lyric/%s_hover.png" % name), app_theme.get_pixbuf("lyric/%s_press.png" % name) ) button.connect("clicked", self.change_font_size, name) if msg: Tooltip.text(button, msg) align = gtk.Alignment() align.set(0.5, 0.5, 0, 0) align.add(button) return align def change_font_size(self, widget, name): old_size= self.desktop_lyrics_win.get_font_size() if name == "zoom_in": new_size = old_size + 2 if new_size > 70: new_size = 70 config.set("lyrics", "font_size", str(new_size)) elif name == "zoom_out": new_size = old_size - 2 if new_size < 16: new_size = 16 config.set("lyrics", "font_size", str(new_size)) def player_control(self, button, name): if name == "next": getattr(Player, name)(True) else: getattr(Player, name)() def before_offset(self, widget): self.lrc.set_offset(-500) def after_offset(self, widget): self.lrc.set_offset(500) def open_search_window(self, widget): try: self.search_ui.result_view.clear() self.search_ui.artist_entry.entry.set_text(Player.song.get_str("artist")) self.search_ui.title_entry.entry.set_text(Player.song.get_str("title")) self.search_ui.search_lyric_cb(None) except: pass self.search_ui.show_window() def close_lyric_window(self, widget): Dispatcher.close_lyrics() def open_setting_window(self, widget): Dispatcher.show_desktop_page() def on_dialog_close(self, sender): if self.__dialog_locked_flag: self.desktop_lyrics_win.set_locked(False) def on_dialog_run(self, sender): if config.getboolean("lyrics", "status"): if not self.desktop_lyrics_win.get_locked(): self.__dialog_locked_flag = True self.desktop_lyrics_win.set_locked() def __unlock_lyrics(self, *args): self.desktop_lyrics_win.set_locked(False) def __lock_lyrics(self, *args): self.desktop_lyrics_win.set_locked() def change_karaoke_status(self, widget): self.desktop_lyrics_win.set_karaoke_mode() def change_line_status(self, widget): if widget.get_active(): self.desktop_lyrics_win.set_line_count(1) else: self.desktop_lyrics_win.set_line_count(2) def popup_predefine_menu(self, widget, event): menu_dict = OrderedDict() menu_dict["vitality_yellow"] = _("Vitality yellow") menu_dict["fresh_green"] = _("Fresh green") menu_dict["playful_pink"] = _("Playful pink") menu_dict["cool_blue"] = _("Cool blue") menu_items = [] save_predefine_color = config.get("lyrics", "predefine_color", "vitality_yellow") for key, value in menu_dict.iteritems(): item_pixbuf = None if key == save_predefine_color: item_pixbuf = (app_theme.get_pixbuf("menu/tick.png"), app_theme.get_pixbuf("menu/tick_press.png"), app_theme.get_pixbuf("menu/tick_disable.png")) if item_pixbuf is None: menu_items.append((None, value, self.set_predefine_color, key)) else: menu_items.append((item_pixbuf, value, self.set_predefine_color, key)) predefine_menu = Menu(menu_items, True) predefine_menu.show((int(event.x_root), int(event.y_root))) def set_predefine_color(self, key): if key in PREDEFINE_COLORS.keys(): values = PREDEFINE_COLORS[key] config.set("lyrics", "predefine_color", key) config.set("lyrics", "inactive_color_upper", values[0]) config.set("lyrics", "inactive_color_middle", values[1]) config.set("lyrics", "inactive_color_bottom", values[2]) config.set("lyrics", "active_color_upper", values[3]) config.set("lyrics", "active_color_middle", values[4]) config.set("lyrics", "active_color_bottom", values[5]) def func_thread(self): while True: self.condition.acquire() while not self.next_lrc_to_download: self.condition.wait() next_lrc_to_download = self.next_lrc_to_download self.next_lrc_to_download = None self.condition.release() self.set_current_lrc(True, next_lrc_to_download) def set_duration(self, duration): if not duration: return self.song_duration = duration def set_lrc_file(self, filename): if filename and self.message_source != None: self.clear_message() # self.clear_lyrics() self.lrc.set_filename(filename) self.scroll_lyrics.set_whole_lyrics(self.lrc.scroll_lyrics) def set_scroll_played_time(self, played_time): info = self.lrc.get_lyric_by_time(played_time, self.song_duration) if not info: return text, percentage, lyric_id = info self.scroll_lyrics.set_progress(lyric_id, percentage) def set_played_time(self, played_time): info = self.lrc.get_lyric_by_time(played_time, self.song_duration) if not info: return text, percentage, lyric_id = info real_id, real_lyric = self.get_real_lyric(lyric_id) if real_lyric == None: nid = -1 else: nid = real_id if self.lrc_id != nid: if nid == -1: self.clear_lyrics() return if nid != self.lrc_next_id: self.current_line = 0 if real_lyric: self.desktop_lyrics_win.set_lyric(self.current_line, real_lyric) if nid != lyric_id: self.desktop_lyrics_win.set_current_percentage(0.0) self.update_next_lyric(real_id) else: self.desktop_lyrics_win.set_line_percentage(self.current_line, 1.0) self.current_line = 1 - self.current_line self.lrc_id = nid self.desktop_lyrics_win.set_current_line(self.current_line) if nid == lyric_id and percentage > 0.5: self.update_next_lyric(real_id) if nid == lyric_id: self.desktop_lyrics_win.set_current_percentage(percentage) def update_next_lyric(self, item_id): if self.desktop_lyrics_win.get_line_count() == 1: self.lrc_next_id = -1 return item_id += 1 real_id, real_lyric = self.get_real_lyric(item_id) if real_lyric == None: if self.lrc_next_id == -1: return else: self.lrc_next_id = -1 self.desktop_lyrics_win.set_lyric(1 - self.current_line, "") else: if self.lrc_next_id == real_id: return if real_lyric: self.lrc_next_id = real_id self.desktop_lyrics_win.set_lyric(1 - self.current_line, real_lyric) self.desktop_lyrics_win.set_line_percentage(1 - self.current_line, 0.0) def get_real_lyric(self, item_id): while True: if self.lrc.get_item_lyric(item_id) != "": break item_id += 1 return item_id, self.lrc.get_item_lyric(item_id) def clear_lyrics(self): self.desktop_lyrics_win.set_lyric(0, "") self.desktop_lyrics_win.set_lyric(1, "") self.current_line = 0 self.lrc_id = -1 self.lrc_next_id = -1 def set_message(self, message, duration_ms=None): if not message: return self.desktop_lyrics_win.set_current_line(0) self.desktop_lyrics_win.set_current_percentage(0.0) self.desktop_lyrics_win.set_lyric(0, message) self.desktop_lyrics_win.set_lyric(1, "") if self.message_source != None: gobject.source_remove(self.message_source) if duration_ms: self.message_source = gobject.timeout_add(duration_ms, self.hide_message) def hide_message(self): self.desktop_lyrics_win.set_lyric(0, "") self.message_source = None return False def clear_message(self): if self.message_source != None: gobject.source_remove(self.message_source) self.hide_message() def set_search_message(self, message): self.set_message(message, -1) def set_search_fail_message(self, message): self.set_message(message, MESSAGE_DURATION_MS) def set_download_fail_message(self, message): self.set_message(message, MESSAGE_DURATION_MS) def run(self): config.set("lyrics", "status", "true") self.play_time_source() if self.__lyrics_mode == LRC_WINDOW_MODE: self.show_scroll_lyrics() else: self.show_desktop_lyrics() def hide_toolbar(self, widget): self.toolbar.hide_all() def show_toolbar(self, widget): self.toolbar.show_all() self.toolbar.hide_all() l_x, l_y = self.desktop_lyrics_win.get_position() l_w, l_h = self.desktop_lyrics_win.get_size() rect = gtk.gdk.Rectangle(int(l_x), int(l_y), int(l_w), int(l_h)) self.adjust_toolbar_rect(None, rect) self.toolbar.show_all() def hide_all(self): config.set("lyrics", "status", "false") self.hide_scroll_lyrics() self.hide_desktop_lyrics() self.pause_time_source() def hide_without_config(self): self.hide_scroll_lyrics() self.hide_desktop_lyrics() self.pause_time_source() def hide_scroll_lyrics(self): self.scroll_lyrics.hide_all() def lyrcis_scroll_configure_event(self, widget, event): if widget.get_property("visible"): if widget.get_resizable(): config.set("lyrics","scroll_w","%d"%event.width) config.set("lyrics","scroll_h","%d"%event.height) config.set("lyrics","scroll_x","%d"%event.x) config.set("lyrics","scroll_y","%d"%event.y) def show_scroll_lyrics(self): if config.get("lyrics", "scroll_x") != "-1": x = config.getint("lyrics", "scroll_x") y = config.getint("lyrics", "scroll_y") self.scroll_lyrics.move(int(x), int(y)) try: w = config.getint("lyrics", "scroll_w") h = config.getint("lyrics", "scroll_h") self.scroll_lyrics.resize(int(w), int(h)) except: pass if not self.__find_flag: self.update_lrc(None, Player.song) self.scroll_lyrics.show_all() def hide_desktop_lyrics(self): self.desktop_lyrics_win.hide_all() self.toolbar.hide_all() def lyrics_desktop_configure_event(self, widget, event): if widget.get_property("visible"): if widget.get_resizable(): config.set("lyrics","desktop_h","%d"%event.height) config.set("lyrics","desktop_w","%d"%event.width) config.set("lyrics","desktop_y","%d"%event.y) config.set("lyrics","desktop_x","%d"%event.x) widget.update_lyric_rects() def show_desktop_lyrics(self): if config.get("lyrics", "desktop_x") == "-1": screen_w, screen_h = gtk.gdk.get_default_root_window().get_size() w , h = self.desktop_lyrics_win.get_size() x = screen_w / 2 - w / 2 y = screen_h - h else: x = config.getint("lyrics", "desktop_x") y = config.getint("lyrics", "desktop_y") self.desktop_lyrics_win.move(x, y) try: d_w = config.getint("lyrics", "desktop_w") d_h = config.getint("lyrics", "desktop_h") self.desktop_lyrics_win.resize(d_w, d_h) except: pass if not self.__find_flag: self.update_lrc(None, Player.song) self.desktop_lyrics_win.show_all() def adjust_toolbar_rect(self, widget, rect): screen_w, screen_h = gtk.gdk.get_default_root_window().get_size() centre_x = rect.x + rect.width / 2 l_w, l_h = self.toolbar.get_size() l_x = centre_x - l_w / 2 if rect.y < l_h: l_y = rect.y + rect.height elif rect.y > screen_h - rect.height: l_y = rect.y - l_h else: l_y = rect.y - l_h self.toolbar.move(l_x, l_y) def update_lrc(self, widget, songs): if not config.getboolean("lyrics", "status"): return if isinstance(songs, list): if self.current_song in songs: self.current_song = songs[songs.index(self.current_song)] else: self.current_song = songs if self.current_song is not None: if not self.set_current_lrc(False): self.condition.acquire() self.next_lrc_to_download = self.current_song self.condition.notify() self.condition.release() def real_show_lyrics(self): played_timed = Player.get_lyrics_position() if self.__lyrics_mode == LRC_WINDOW_MODE: self.set_scroll_played_time(played_timed) else: self.set_played_time(played_timed) return True def pause_time_source(self, *args): if self.time_source != None: gobject.source_remove(self.time_source) self.time_source = None def play_time_source(self, *args): self.pause_time_source() if not self.__find_flag: return if not config.getboolean("lyrics", "status"): return if self.__lyrics_mode == LRC_WINDOW_MODE: self.time_source = gobject.timeout_add(200, self.real_show_lyrics) else: self.time_source = gobject.timeout_add(100, self.real_show_lyrics) def set_current_lrc(self, try_web=True, force_song=None): ret = False if not force_song: force_song = self.current_song filename = self.lrc_manager.get_lrc(force_song, try_web) if filename and os.path.exists(filename): if self.time_source != None: gobject.source_remove(self.time_source) self.time_source = None self.clear_lyrics() if try_web: gobject.idle_add(self.set_lrc_file, filename) else: self.set_lrc_file(filename) ret = True self.set_duration(force_song.get("#duration")) self.__find_flag = True if config.getboolean("lyrics", "status"): self.play_time_source() else: if self.current_song != force_song: return if self.time_source != None: gobject.source_remove(self.time_source) self.time_source = None self.clear_lyrics() if try_web: self.set_message(self.get_default_message(force_song) + " "+ _("No lyrics found!")) self.scroll_lyrics.set_message(self.get_default_message(force_song) + " " + _("No lyrics found!")) else: self.set_search_fail_message(_("Searching for lyrics...")) self.scroll_lyrics.set_message(_("Searching for lyrics...")) self.__find_flag = False return ret def instant_update_lrc(self, widget, song): if song.get_type() in ('webcast', 'cue'): return self.scroll_lyrics.set_whole_lyrics([]) self.set_message(self.get_default_message(song)) self.update_lrc(widget, song) def get_default_message(self, song): artist = song.get_str("artist") title = song.get_str("title") if artist: return "%s-%s" % (artist, title) else: return "%s" % title
class LyricsModule(object): def __init__(self): self.desktop_lyrics_win = DesktopLyrics() self.desktop_lyrics_win.connect("moved", self.adjust_toolbar_rect) self.desktop_lyrics_win.connect("resized", self.adjust_toolbar_rect) self.desktop_lyrics_win.connect("hide-bg", self.hide_toolbar) self.desktop_lyrics_win.connect("show-bg", self.show_toolbar) self.desktop_lyrics_win.connect("button-press-event", self.popup_desktop_right_menu) self.desktop_lyrics_win.connect("configure-event", self.lyrics_desktop_configure_event) self.scroll_lyrics = ScrollLyrics() self.scroll_lyrics.connect("configure-event", self.lyrcis_scroll_configure_event) self.scroll_lyrics.revert_button.connect( "clicked", lambda w: self.switch_to_desktop_lyrics()) self.scroll_lyrics.connect("seek", self.seek_cb) self.scroll_lyrics.connect("right-press", self.scroll_right_press_cb) Player.connect("instant-new-song", self.instant_update_lrc) Player.connect("played", self.play_time_source) Player.connect("paused", self.pause_time_source) Player.connect("play-end", self.pause_time_source) Dispatcher.connect("reload-lrc", self.update_lrc) Dispatcher.connect("unlock-lyrics", self.__unlock_lyrics) Dispatcher.connect("lock-lyrics", self.__lock_lyrics) Dispatcher.connect("show-lyrics", lambda w: self.run()) Dispatcher.connect("close-lyrics", lambda w: self.hide_all()) Dispatcher.connect("search-lyrics", lambda w: self.open_search_window(w)) Dispatcher.connect("dialog-run", self.on_dialog_run) Dispatcher.connect("dialog-close", self.on_dialog_close) config.connect("config-changed", self.on_config_changed) self.lrc_manager = LrcManager() self.lrc = LrcParser() self.search_ui = SearchUI() self.lrc_id = -1 self.lrc_next_id = -1 self.current_line = 0 self.message_source = None self.time_source = None self.song_duration = 0 self.__find_flag = False self.__lyrics_mode = config.getint("lyrics", "mode") self.__dialog_locked_flag = False self.init_toolbar() self.current_song = None self.next_lrc_to_download = None self.condition = threading.Condition() self.thread = threading.Thread(target=self.func_thread) self.thread.setDaemon(True) self.thread.start() def init_toolbar(self): self.toolbar = Window(window_type=gtk.WINDOW_POPUP) self.toolbar.set_size_request(-1, 41) padding_x, padding_y = 10, 5 play_box = gtk.HBox(spacing=2) play_box.connect("expose-event", self.expose_toolbar_mask) # swap played status handler Player.connect("played", self.__swap_play_status, True) Player.connect("paused", self.__swap_play_status, False) Player.connect("stopped", self.__swap_play_status, False) Player.connect("play-end", self.__swap_play_status, False) self.playpause_button = ToggleButton( app_theme.get_pixbuf("lyric/play_normal.png"), app_theme.get_pixbuf("lyric/pause_normal.png"), app_theme.get_pixbuf("lyric/play_hover.png"), app_theme.get_pixbuf("lyric/pause_hover.png"), app_theme.get_pixbuf("lyric/play_press.png"), app_theme.get_pixbuf("lyric/pause_press.png"), ) self.__id_signal_play = self.playpause_button.connect( "toggled", lambda w: Player.playpause()) prev = self.__create_button("previous") next = self.__create_button("next") prev_align = gtk.Alignment() prev_align.set(0.5, 0.5, 0, 0) prev_align.add(prev) next_align = gtk.Alignment() next_align.set(0.5, 0.5, 0, 0) next_align.add(next) play_align = gtk.Alignment() play_align.set_padding(2, 0, 0, 0) play_align.set(0.5, 0.5, 0, 0) play_align.add(self.playpause_button) # separte line separate_line = ImageBox(app_theme.get_pixbuf("lyric/separate.png")) sep_align = gtk.Alignment() sep_align.set(0.5, 0.5, 0, 0) sep_align.add(separate_line) zoom_in_align = self.__create_zoom_button( "zoom_in", _("Increase the lyrics size")) zoom_out_align = self.__create_zoom_button( "zoom_out", _("Decrease the lyrics size")) predefine_align = self.__create_simple_button( "predefine_color", self.popup_predefine_menu, _("Select color theme"), True) lock_align = self.__create_simple_button("lock", self.__lock_lyrics, _("Lock Lyrics")) karaoke_align, self.karaoke_button = self.__create_single_toggle_button( "karaoke", self.change_karaoke_status, _("Karaoke on/off")) line_align, self.line_button = self.__create_simple_toggle_button( "single_line", "double_line", None, _("Switch lines")) self.line_button_toggled_id = self.line_button.connect( "toggled", self.change_line_status) setting_align = self.__create_simple_button("setting", self.open_setting_window, _("Open settings panel")) search_align = self.__create_simple_button( "search", self.open_search_window, _("Search lrc file for current track")) close_align = self.__create_simple_button("close", self.close_lyric_window, _("Close lyrics")) before_align = self.__create_simple_button("before", self.before_offset, _("Lyrics rewind")) after_align = self.__create_simple_button("after", self.after_offset, _("Lyrics forward")) lrc_align = self.__create_simple_button("lrc", self.switch_to_scroll_lyrics, _("Switch to window mode")) play_box.pack_start(prev_align, False, False) play_box.pack_start(play_align, False, False) play_box.pack_start(next_align, False, False) play_box.pack_start(sep_align, False, False) play_box.pack_start(zoom_in_align, False, False) play_box.pack_start(zoom_out_align, False, False) play_box.pack_start(before_align, False, False) play_box.pack_start(after_align, False, False) play_box.pack_start(predefine_align, False, False) play_box.pack_start(karaoke_align, False, False) play_box.pack_start(line_align, False, False) play_box.pack_start(lock_align, False, False) play_box.pack_start(setting_align, False, False) play_box.pack_start(lrc_align, False, False) play_box.pack_start(search_align, False, False) play_box.pack_start(close_align, False, False) main_align = gtk.Alignment() main_align.set_padding(0, 0, padding_x, padding_x) main_align.set(0.5, 0.5, 0, 0) main_align.add(play_box) self.toolbar.window_frame.pack_start(main_align) self.load_button_status() def on_config_changed(self, obj, selection, option, value): if selection == "lyrics" and option == "line_count": is_active = self.line_button.get_active() if value == "1" and not is_active: with self.line_button_toggled_status(): self.line_button.set_active(True) elif value == "2" and is_active: with self.line_button_toggled_status(): self.line_button.set_active(False) @contextmanager def line_button_toggled_status(self): self.line_button.disconnect(self.line_button_toggled_id) try: yield finally: self.line_button_toggled_id = self.line_button.connect( "toggled", self.change_line_status) def expose_toolbar_mask(self, widget, event): cr = widget.window.cairo_create() rect = widget.allocation draw_alpha_mask(cr, rect.x - 9, rect.y, rect.width + 18, rect.height, "lyricsMask") return False def scroll_right_press_cb(self, widget, event): menu_items = [ (self.get_scroll_menu_pixbufs("lrc"), _("Switch to desktop mode"), self.switch_to_desktop_lyrics), None, (self.get_scroll_menu_pixbufs("before"), _("Lyrics rewind"), lambda: self.before_offset(None)), (self.get_scroll_menu_pixbufs("after"), _("Lyrics forward"), lambda: self.after_offset(None)), None, (self.get_scroll_menu_pixbufs("search"), _("Search"), lambda: self.open_search_window(None)), (self.get_scroll_menu_pixbufs("setting"), _("Settings"), lambda: Dispatcher.show_scroll_page()), ] Menu(menu_items, True).show((int(event.x_root), int(event.y_root))) def popup_desktop_right_menu(self, widget, event): if event.button == 3 and Player.song: adjust_menu_item = [(None, _("Forward 0.5 seconds"), lambda: self.after_offset(None)), (None, _("Rewind 0.5 seconds"), lambda: self.before_offset(None))] menu_items = [ (None, _("Search"), lambda: self.open_search_window(None)), (None, _("Adjust lyrics"), Menu(adjust_menu_item)), None, (None, _("Choose local lrc"), self.allocation_lrc), (None, _("Open directory"), self.open_lrc_dir), None, (None, _("Settings"), lambda: self.open_setting_window(None)), (None, _("Switch to window mode"), lambda: self.switch_to_scroll_lyrics(None)) ] if Player.song.get("location_lrc", None): menu_items.insert(4, (None, _("Lyrics acquired by Network"), self.disassociate_lrc)) Menu(menu_items, True).show((int(event.x_root), int(event.y_root))) def allocation_lrc(self): lrc_path = WinFile(False).run() if lrc_path: self.lrc_manager.allocation_lrc_file(Player.song, lrc_path) def disassociate_lrc(self): self.lrc_manager.unallocation_lrc_file(Player.song) def open_lrc_dir(self): save_dir = os.path.expanduser( config.get("lyrics", "save_lrc_path", "~/.lyrics")) utils.run_command("xdg-open %s" % save_dir) def get_scroll_menu_pixbufs(self, name): return (app_theme.get_pixbuf("lyric/%s_normal.png" % name), None, None) def switch_to_scroll_lyrics(self, widget): config.set("lyrics", "mode", str(LRC_WINDOW_MODE)) self.__lyrics_mode = LRC_WINDOW_MODE self.hide_desktop_lyrics() self.show_scroll_lyrics() self.play_time_source() def switch_to_desktop_lyrics(self): config.set("lyrics", "mode", str(LRC_DESKTOP_MODE)) self.__lyrics_mode = LRC_DESKTOP_MODE self.hide_scroll_lyrics() self.show_desktop_lyrics() self.play_time_source() def seek_cb(self, widget, lyric_id, percentage): item_time = self.lrc.get_item_time(lyric_id) new_time = item_time / 1000 if Player.song.get_type() == "cue": new_time += Player.song.get("seek", 0) Player.seek(new_time) self.scroll_lyrics.set_progress(lyric_id, percentage) time.sleep(0.1) def load_button_status(self): if not config.getboolean("lyrics", "karaoke_mode"): self.karaoke_button.set_active(True) if config.getint("lyrics", "line_count") == 1: self.line_button.set_active(True) def __create_simple_button(self, name, callback, tip_msg=None, has_event=False): button = ImageButton( app_theme.get_pixbuf("lyric/%s_normal.png" % name), app_theme.get_pixbuf("lyric/%s_hover.png" % name), app_theme.get_pixbuf("lyric/%s_press.png" % name)) if has_event: button.connect("button-press-event", callback) else: button.connect("clicked", callback) if tip_msg: Tooltip.text(button, tip_msg) button_align = gtk.Alignment() button_align.set(0.5, 0.5, 0, 0) button_align.add(button) return button_align def __create_simple_toggle_button(self, normal_name, active_name, callback=None, tip_msg=None): toggle_button = ToggleButton( app_theme.get_pixbuf("lyric/%s_normal.png" % normal_name), app_theme.get_pixbuf("lyric/%s_normal.png" % active_name), app_theme.get_pixbuf("lyric/%s_hover.png" % normal_name), app_theme.get_pixbuf("lyric/%s_hover.png" % active_name), app_theme.get_pixbuf("lyric/%s_press.png" % normal_name), app_theme.get_pixbuf("lyric/%s_press.png" % active_name), ) if callback: toggle_button.connect("toggled", callback) toggle_align = gtk.Alignment() toggle_align.set(0.5, 0.5, 0, 0) toggle_align.add(toggle_button) if tip_msg: Tooltip.text(toggle_button, tip_msg) return toggle_align, toggle_button def __create_single_toggle_button(self, normal_name, callback, tip_msg=None): if normal_name == "karaoke": toggle_button = ToggleButton( app_theme.get_pixbuf("lyric/%s_press.png" % normal_name), app_theme.get_pixbuf("lyric/%s_normal.png" % normal_name), app_theme.get_pixbuf("lyric/%s_hover.png" % normal_name), ) else: toggle_button = ToggleButton( app_theme.get_pixbuf("lyric/%s_normal.png" % normal_name), app_theme.get_pixbuf("lyric/%s_press.png" % normal_name), app_theme.get_pixbuf("lyric/%s_hover.png" % normal_name), ) toggle_button.connect("toggled", callback) toggle_align = gtk.Alignment() toggle_align.set(0.5, 0.5, 0, 0) toggle_align.add(toggle_button) if tip_msg: Tooltip.text(toggle_button, tip_msg) return toggle_align, toggle_button def __create_button(self, name, tip_msg=None): button = ImageButton( app_theme.get_pixbuf("lyric/%s_normal.png" % name), app_theme.get_pixbuf("lyric/%s_hover.png" % name), app_theme.get_pixbuf("lyric/%s_press.png" % name)) button.connect("clicked", self.player_control, name) return button def __swap_play_status(self, obj, active): self.playpause_button.handler_block(self.__id_signal_play) self.playpause_button.set_active(active) self.playpause_button.handler_unblock(self.__id_signal_play) def __create_zoom_button(self, name, msg=None): button = ImageButton( app_theme.get_pixbuf("lyric/%s_normal.png" % name), app_theme.get_pixbuf("lyric/%s_hover.png" % name), app_theme.get_pixbuf("lyric/%s_press.png" % name)) button.connect("clicked", self.change_font_size, name) if msg: Tooltip.text(button, msg) align = gtk.Alignment() align.set(0.5, 0.5, 0, 0) align.add(button) return align def change_font_size(self, widget, name): old_size = self.desktop_lyrics_win.get_font_size() if name == "zoom_in": new_size = old_size + 2 if new_size > 70: new_size = 70 config.set("lyrics", "font_size", str(new_size)) elif name == "zoom_out": new_size = old_size - 2 if new_size < 16: new_size = 16 config.set("lyrics", "font_size", str(new_size)) def player_control(self, button, name): if name == "next": getattr(Player, name)(True) else: getattr(Player, name)() def before_offset(self, widget): self.lrc.set_offset(-500) def after_offset(self, widget): self.lrc.set_offset(500) def open_search_window(self, widget): try: self.search_ui.result_view.clear() self.search_ui.artist_entry.entry.set_text( Player.song.get_str("artist")) self.search_ui.title_entry.entry.set_text( Player.song.get_str("title")) self.search_ui.search_lyric_cb(None) except: pass self.search_ui.show_window() def close_lyric_window(self, widget): Dispatcher.close_lyrics() def open_setting_window(self, widget): Dispatcher.show_desktop_page() def on_dialog_close(self, sender): if self.__dialog_locked_flag: self.desktop_lyrics_win.set_locked(False) def on_dialog_run(self, sender): if config.getboolean("lyrics", "status"): if not self.desktop_lyrics_win.get_locked(): self.__dialog_locked_flag = True self.desktop_lyrics_win.set_locked() def __unlock_lyrics(self, *args): self.desktop_lyrics_win.set_locked(False) def __lock_lyrics(self, *args): self.desktop_lyrics_win.set_locked() def change_karaoke_status(self, widget): self.desktop_lyrics_win.set_karaoke_mode() def change_line_status(self, widget): if widget.get_active(): self.desktop_lyrics_win.set_line_count(1) else: self.desktop_lyrics_win.set_line_count(2) def popup_predefine_menu(self, widget, event): menu_dict = OrderedDict() menu_dict["vitality_yellow"] = _("Vitality yellow") menu_dict["fresh_green"] = _("Fresh green") menu_dict["playful_pink"] = _("Playful pink") menu_dict["cool_blue"] = _("Cool blue") menu_items = [] save_predefine_color = config.get("lyrics", "predefine_color", "vitality_yellow") for key, value in menu_dict.iteritems(): item_pixbuf = None if key == save_predefine_color: item_pixbuf = (app_theme.get_pixbuf("menu/tick.png"), app_theme.get_pixbuf("menu/tick_press.png"), app_theme.get_pixbuf("menu/tick_disable.png")) if item_pixbuf is None: menu_items.append((None, value, self.set_predefine_color, key)) else: menu_items.append( (item_pixbuf, value, self.set_predefine_color, key)) predefine_menu = Menu(menu_items, True) predefine_menu.show((int(event.x_root), int(event.y_root))) def set_predefine_color(self, key): if key in PREDEFINE_COLORS.keys(): values = PREDEFINE_COLORS[key] config.set("lyrics", "predefine_color", key) config.set("lyrics", "inactive_color_upper", values[0]) config.set("lyrics", "inactive_color_middle", values[1]) config.set("lyrics", "inactive_color_bottom", values[2]) config.set("lyrics", "active_color_upper", values[3]) config.set("lyrics", "active_color_middle", values[4]) config.set("lyrics", "active_color_bottom", values[5]) def func_thread(self): while True: self.condition.acquire() while not self.next_lrc_to_download: self.condition.wait() next_lrc_to_download = self.next_lrc_to_download self.next_lrc_to_download = None self.condition.release() self.set_current_lrc(True, next_lrc_to_download) def set_duration(self, duration): if not duration: return self.song_duration = duration def set_lrc_file(self, filename): if filename and self.message_source != None: self.clear_message() # self.clear_lyrics() self.lrc.set_filename(filename) self.scroll_lyrics.set_whole_lyrics(self.lrc.scroll_lyrics) def set_scroll_played_time(self, played_time): info = self.lrc.get_lyric_by_time(played_time, self.song_duration) if not info: return text, percentage, lyric_id = info self.scroll_lyrics.set_progress(lyric_id, percentage) def set_played_time(self, played_time): info = self.lrc.get_lyric_by_time(played_time, self.song_duration) if not info: return text, percentage, lyric_id = info real_id, real_lyric = self.get_real_lyric(lyric_id) if real_lyric == None: nid = -1 else: nid = real_id if self.lrc_id != nid: if nid == -1: self.clear_lyrics() return if nid != self.lrc_next_id: self.current_line = 0 if real_lyric: self.desktop_lyrics_win.set_lyric(self.current_line, real_lyric) if nid != lyric_id: self.desktop_lyrics_win.set_current_percentage(0.0) self.update_next_lyric(real_id) else: self.desktop_lyrics_win.set_line_percentage( self.current_line, 1.0) self.current_line = 1 - self.current_line self.lrc_id = nid self.desktop_lyrics_win.set_current_line(self.current_line) if nid == lyric_id and percentage > 0.5: self.update_next_lyric(real_id) if nid == lyric_id: self.desktop_lyrics_win.set_current_percentage(percentage) def update_next_lyric(self, item_id): if self.desktop_lyrics_win.get_line_count() == 1: self.lrc_next_id = -1 return item_id += 1 real_id, real_lyric = self.get_real_lyric(item_id) if real_lyric == None: if self.lrc_next_id == -1: return else: self.lrc_next_id = -1 self.desktop_lyrics_win.set_lyric(1 - self.current_line, "") else: if self.lrc_next_id == real_id: return if real_lyric: self.lrc_next_id = real_id self.desktop_lyrics_win.set_lyric(1 - self.current_line, real_lyric) self.desktop_lyrics_win.set_line_percentage(1 - self.current_line, 0.0) def get_real_lyric(self, item_id): while True: if self.lrc.get_item_lyric(item_id) != "": break item_id += 1 return item_id, self.lrc.get_item_lyric(item_id) def clear_lyrics(self): self.desktop_lyrics_win.set_lyric(0, "") self.desktop_lyrics_win.set_lyric(1, "") self.current_line = 0 self.lrc_id = -1 self.lrc_next_id = -1 def set_message(self, message, duration_ms=None): if not message: return self.desktop_lyrics_win.set_current_line(0) self.desktop_lyrics_win.set_current_percentage(0.0) self.desktop_lyrics_win.set_lyric(0, message) self.desktop_lyrics_win.set_lyric(1, "") if self.message_source != None: gobject.source_remove(self.message_source) if duration_ms: self.message_source = gobject.timeout_add(duration_ms, self.hide_message) def hide_message(self): self.desktop_lyrics_win.set_lyric(0, "") self.message_source = None return False def clear_message(self): if self.message_source != None: gobject.source_remove(self.message_source) self.hide_message() def set_search_message(self, message): self.set_message(message, -1) def set_search_fail_message(self, message): self.set_message(message, MESSAGE_DURATION_MS) def set_download_fail_message(self, message): self.set_message(message, MESSAGE_DURATION_MS) def run(self): config.set("lyrics", "status", "true") self.play_time_source() if self.__lyrics_mode == LRC_WINDOW_MODE: self.show_scroll_lyrics() else: self.show_desktop_lyrics() def hide_toolbar(self, widget): self.toolbar.hide_all() def show_toolbar(self, widget): self.toolbar.show_all() self.toolbar.hide_all() l_x, l_y = self.desktop_lyrics_win.get_position() l_w, l_h = self.desktop_lyrics_win.get_size() rect = gtk.gdk.Rectangle(int(l_x), int(l_y), int(l_w), int(l_h)) self.adjust_toolbar_rect(None, rect) self.toolbar.show_all() def hide_all(self): config.set("lyrics", "status", "false") self.hide_scroll_lyrics() self.hide_desktop_lyrics() self.pause_time_source() def hide_without_config(self): self.hide_scroll_lyrics() self.hide_desktop_lyrics() self.pause_time_source() def hide_scroll_lyrics(self): self.scroll_lyrics.hide_all() def lyrcis_scroll_configure_event(self, widget, event): if widget.get_property("visible"): if widget.get_resizable(): config.set("lyrics", "scroll_w", "%d" % event.width) config.set("lyrics", "scroll_h", "%d" % event.height) config.set("lyrics", "scroll_x", "%d" % event.x) config.set("lyrics", "scroll_y", "%d" % event.y) def show_scroll_lyrics(self): if config.get("lyrics", "scroll_x") != "-1": x = config.getint("lyrics", "scroll_x") y = config.getint("lyrics", "scroll_y") self.scroll_lyrics.move(int(x), int(y)) try: w = config.getint("lyrics", "scroll_w") h = config.getint("lyrics", "scroll_h") self.scroll_lyrics.resize(int(w), int(h)) except: pass if not self.__find_flag: self.update_lrc(None, Player.song) self.scroll_lyrics.show_all() def hide_desktop_lyrics(self): self.desktop_lyrics_win.hide_all() self.toolbar.hide_all() def lyrics_desktop_configure_event(self, widget, event): if widget.get_property("visible"): if widget.get_resizable(): config.set("lyrics", "desktop_h", "%d" % event.height) config.set("lyrics", "desktop_w", "%d" % event.width) config.set("lyrics", "desktop_y", "%d" % event.y) config.set("lyrics", "desktop_x", "%d" % event.x) widget.update_lyric_rects() def show_desktop_lyrics(self): if config.get("lyrics", "desktop_x") == "-1": screen_w, screen_h = gtk.gdk.get_default_root_window().get_size() w, h = self.desktop_lyrics_win.get_size() x = screen_w / 2 - w / 2 y = screen_h - h else: x = config.getint("lyrics", "desktop_x") y = config.getint("lyrics", "desktop_y") self.desktop_lyrics_win.move(x, y) try: d_w = config.getint("lyrics", "desktop_w") d_h = config.getint("lyrics", "desktop_h") self.desktop_lyrics_win.resize(d_w, d_h) except: pass if not self.__find_flag: self.update_lrc(None, Player.song) self.desktop_lyrics_win.show_all() def adjust_toolbar_rect(self, widget, rect): screen_w, screen_h = gtk.gdk.get_default_root_window().get_size() centre_x = rect.x + rect.width / 2 l_w, l_h = self.toolbar.get_size() l_x = centre_x - l_w / 2 if rect.y < l_h: l_y = rect.y + rect.height elif rect.y > screen_h - rect.height: l_y = rect.y - l_h else: l_y = rect.y - l_h self.toolbar.move(l_x, l_y) def update_lrc(self, widget, songs): if not config.getboolean("lyrics", "status"): return if isinstance(songs, list): if self.current_song in songs: self.current_song = songs[songs.index(self.current_song)] else: self.current_song = songs if self.current_song is not None: if not self.set_current_lrc(False): self.condition.acquire() self.next_lrc_to_download = self.current_song self.condition.notify() self.condition.release() def real_show_lyrics(self): played_timed = Player.get_lyrics_position() if self.__lyrics_mode == LRC_WINDOW_MODE: self.set_scroll_played_time(played_timed) else: self.set_played_time(played_timed) return True def pause_time_source(self, *args): if self.time_source != None: gobject.source_remove(self.time_source) self.time_source = None def play_time_source(self, *args): self.pause_time_source() if not self.__find_flag: return if not config.getboolean("lyrics", "status"): return if self.__lyrics_mode == LRC_WINDOW_MODE: self.time_source = gobject.timeout_add(200, self.real_show_lyrics) else: self.time_source = gobject.timeout_add(100, self.real_show_lyrics) def set_current_lrc(self, try_web=True, force_song=None): ret = False if not force_song: force_song = self.current_song filename = self.lrc_manager.get_lrc(force_song, try_web) if filename and os.path.exists(filename): if self.time_source != None: gobject.source_remove(self.time_source) self.time_source = None self.clear_lyrics() if try_web: gobject.idle_add(self.set_lrc_file, filename) else: self.set_lrc_file(filename) ret = True self.set_duration(force_song.get("#duration")) self.__find_flag = True if config.getboolean("lyrics", "status"): self.play_time_source() else: if self.current_song != force_song: return if self.time_source != None: gobject.source_remove(self.time_source) self.time_source = None self.clear_lyrics() if try_web: self.set_message( self.get_default_message(force_song) + " " + _("No lyrics found!")) self.scroll_lyrics.set_message( self.get_default_message(force_song) + " " + _("No lyrics found!")) else: self.set_search_fail_message(_("Searching for lyrics...")) self.scroll_lyrics.set_message(_("Searching for lyrics...")) self.__find_flag = False return ret def instant_update_lrc(self, widget, song): if song.get_type() in ('webcast', 'cue'): return self.scroll_lyrics.set_whole_lyrics([]) self.set_message(self.get_default_message(song)) self.update_lrc(widget, song) def get_default_message(self, song): artist = song.get_str("artist") title = song.get_str("title") if artist: return "%s-%s" % (artist, title) else: return "%s" % title
class Colorbar(): ''' Colorbar window ''' def __init__(self, parent=None, screenshot=None): ''' init colorbar @param parent: the transient parent for this window @param screenshot: a Screenshot object ''' self.screenshot = screenshot self.win = self.screenshot.window #padding_x = 5 #padding_y = 3 #icon_width = icon_height = 28 #self.width = 280 #color_num = 9 #self.height = icon_height + padding_y * 2 self.height = 36 self.width = 279 self.width_no_fill = 254 self.width_text = 259 self.window = Window(window_type=gtk.WINDOW_POPUP, shadow_visible=False) self.window.set_type_hint(gtk.gdk.WINDOW_TYPE_HINT_DIALOG) self.window.set_keep_above(True) self.window.set_transient_for(parent) self.window.set_decorated(False) #vbox = gtk.VBox(False, 0) self.box = gtk.HBox(False, 5) self.size_box = gtk.HBox(False, 5) self.dynamic_box = gtk.HBox() colorbox_align = gtk.Alignment() #colorbox_align.set(0.5, 0.5, 0, 0) colorbox_align.set(0, 0.5, 1, 0) colorbox_align.set_padding(2, 2, 11, 11) colorbox_align.add(self.box) self.window.window_frame.pack_start(colorbox_align, True, True) self.window.set_size_request(self.width, self.height) #self.window.set_size_request(-1, self.height) self.__size_button_dict = {} self.create_size_button("small", ACTION_SIZE_SMALL) self.create_size_button("normal", ACTION_SIZE_NORMAL) self.create_size_button("big", ACTION_SIZE_BIG) self.create_size_button("ellipse_fill", ACTION_SIZE_RECTANGLE_ELLIPSE_FILL) self.create_size_button("rect_fill", ACTION_SIZE_RECTANGLE_ELLIPSE_FILL) self._set_size_button_state("small", True) self.size_align = gtk.Alignment() #self.size_align.set(0.5,0.5,0,0) self.size_align.set(0, 0.5, 1, 0) self.size_align.add(self.size_box) #self.dynamic_box.pack_start(self.size_align) self.box.pack_start(self.dynamic_box) # font select self.font_box = gtk.HBox(False, 5) font_img = gtk.image_new_from_pixbuf( app_theme.get_pixbuf("action/text_normal.png").get_pixbuf()) self.font_spin = SpinBox(self.screenshot.font_size, 8, 72, 1) self.font_spin.connect("value-changed", self._font_size_changed) self.font_spin.value_entry.set_can_focus(False) self.font_box.pack_start(font_img) self.font_box.pack_start(self.font_spin) self.font_align = gtk.Alignment() self.font_align.set(0.5, 0.5, 0, 0) self.font_align.add(self.font_box) # color select #self.color_select = gtk.EventBox() self.color_select = gtk.Image() pix = app_theme.get_pixbuf("color_big/red.png").get_pixbuf() self.color_select.set_from_pixbuf(pix) self.box.pack_start(self.color_select, False, False) # color button self.vbox = gtk.VBox(False, 2) self.above_hbox = gtk.HBox(False, 2) self.below_hbox = gtk.HBox(False, 2) self.color_map = { 'black': "#000000", # 1-1 'gray_dark': "#808080", # 1-2 'red': "#FF0000", # 1-3 'yellow_dark': "#FF9B00", # 1-4 'yellow': "#FFFF00", # 1-5 'green': "#B2E700", # 1-6 'green_dark': "#008000", # 1-7 'wathet_dark': "#008080", # 1-8 'white': "#FFFFFF", # 2-1 'gray': "#C0C0C0", # 2-2 'red_dark': "#E2004E", # 2-3 'pink': "#E2007A", # 2-4 'pink_dark': "#800080", # 2-5 'blue_dark': "#000080", # 2-6 'blue': "#0085E1", # 2-7 'wathet': "#009DE0" } # 2-8 self.create_color_button(self.above_hbox, "black") self.create_color_button(self.above_hbox, "gray_dark") self.create_color_button(self.above_hbox, "red") self.create_color_button(self.above_hbox, "yellow_dark") self.create_color_button(self.above_hbox, "yellow") self.create_color_button(self.above_hbox, "green") self.create_color_button(self.above_hbox, "green_dark") self.create_color_button(self.above_hbox, "wathet_dark") self.create_color_button(self.below_hbox, "white") self.create_color_button(self.below_hbox, "gray") self.create_color_button(self.below_hbox, "red_dark") self.create_color_button(self.below_hbox, "pink") self.create_color_button(self.below_hbox, "pink_dark") self.create_color_button(self.below_hbox, "blue_dark") self.create_color_button(self.below_hbox, "blue") self.create_color_button(self.below_hbox, "wathet") self.vbox.pack_start(self.above_hbox) self.vbox.pack_start(self.below_hbox) self.box.pack_start(self.vbox) def create_color_button(self, box, name): ''' create color button @param box: a gtk.HBox @param name: the button's name ''' button = ImageButton( app_theme.get_pixbuf("color/" + name + ".png"), app_theme.get_pixbuf("color/" + name + "_hover.png"), app_theme.get_pixbuf("color/" + name + "_hover.png")) button.connect('pressed', lambda w: self._color_button_pressed(name)) box.pack_start(button) def create_toggle_button(self, name): ''' create a togglebutton @param name: the button's name @return: a dtk.ui.ToggleButton ''' button = ToggleButton( app_theme.get_pixbuf("size/" + name + ".png"), app_theme.get_pixbuf("size/" + name + "_press.png"), app_theme.get_pixbuf("size/" + name + "_hover.png"), app_theme.get_pixbuf("size/" + name + "_press.png")) button.set_name(name) return button def create_size_button(self, name, index): ''' create size button @param name: the button's name @param index: the button's index in button list @return: a dtk.ui.ToggleButton ''' button = self.create_toggle_button(name) button.connect("pressed", self._size_button_pressed, index) #button.connect("toggled", self._size_button_toggled, name) button.connect("released", self._size_button_released) self.size_box.pack_start(button) self.__size_button_dict[name] = button return button def _font_size_changed(self, widget, value): '''font size changed, SpinBox changed callback''' self.screenshot.font_size = value if self.screenshot.show_text_window_flag: if not self.screenshot.text_window.set_font_size(value): #print value, self.screenshot.text_window.get_font_size() widget.set_value(self.screenshot.text_window.get_font_size()) self.win.refresh() def _color_button_pressed(self, name): ''' color button pressed callback''' pix = app_theme.get_pixbuf("color_big/" + name + ".png").get_pixbuf() self.color_select.set_from_pixbuf(pix) if self.screenshot is None: return self.screenshot.action_color = self.color_map[name] if self.screenshot.show_text_window_flag: self.screenshot.text_window.set_text_color( self.screenshot.action_color) self.win.refresh() def _size_button_pressed(self, widget, index): ''' size button pressed callback''' if self.screenshot is None: return self.screenshot.action_size = index for each in self.__size_button_dict: if self.__size_button_dict[each] == widget: continue else: self.__size_button_dict[each].set_active(False) def _size_button_released(self, widget): ''' size button release callback''' if not widget.get_active(): widget.set_active(True) def _set_size_button_state(self, name, state): ''' set size button state @param name: the button's name which will set @param state: the state to set, True or False ''' for each in self.__size_button_dict.keys(): if each == name: self.__size_button_dict[name].set_active(state) def show(self): ''' show the colorbar''' # action is text, show font size set if self.screenshot.action == ACTION_TEXT: self.window.set_size_request(self.width_text, self.height) self.window.resize(self.width_text, self.height) if self.size_align in self.dynamic_box.get_children(): self.dynamic_box.remove(self.size_align) if self.font_align not in self.dynamic_box.get_children(): self.dynamic_box.add(self.font_align) # show draw size else: if self.font_align in self.dynamic_box.get_children(): self.dynamic_box.remove(self.font_align) if self.size_align not in self.dynamic_box.get_children(): self.dynamic_box.add(self.size_align) # actin is rectangle or ellispe, show fill button # show rect fill button if self.screenshot.action == ACTION_RECTANGLE: self.window.set_size_request(self.width, self.height) self.window.resize(self.width, self.height) if self.__size_button_dict[ 'rect_fill'] not in self.size_box.get_children(): self.size_box.pack_start( self.__size_button_dict['rect_fill']) if self.__size_button_dict[ 'ellipse_fill'] in self.size_box.get_children(): self.size_box.remove( self.__size_button_dict['ellipse_fill']) if self.__size_button_dict['ellipse_fill'].get_active(): self.__size_button_dict['rect_fill'].pressed() self.__size_button_dict['rect_fill'].released() # show ellipse fill button elif self.screenshot.action == ACTION_ELLIPSE: self.window.set_size_request(self.width, self.height) self.window.resize(self.width, self.height) if self.__size_button_dict[ 'ellipse_fill'] not in self.size_box.get_children(): self.size_box.pack_start( self.__size_button_dict['ellipse_fill']) if self.__size_button_dict[ 'rect_fill'] in self.size_box.get_children(): self.size_box.remove(self.__size_button_dict['rect_fill']) if self.__size_button_dict['rect_fill'].get_active(): self.__size_button_dict['ellipse_fill'].pressed() self.__size_button_dict['ellipse_fill'].released() # don't show fill button else: self.window.set_size_request(self.width_no_fill, self.height) self.window.resize(self.width_no_fill, self.height) if self.__size_button_dict[ 'rect_fill'] in self.size_box.get_children(): if self.__size_button_dict['rect_fill'].get_active(): self.__size_button_dict['small'].pressed() self.__size_button_dict['small'].released() self.size_box.remove(self.__size_button_dict['rect_fill']) if self.__size_button_dict[ 'ellipse_fill'] in self.size_box.get_children(): if self.__size_button_dict['ellipse_fill'].get_active(): self.__size_button_dict['small'].pressed() self.__size_button_dict['small'].released() self.size_box.remove( self.__size_button_dict['ellipse_fill']) if not self.window.get_visible(): self.window.show_window() #print "colorbox:", self.box.allocation, self.window.allocation def hide(self): '''hide the toolbar''' if self.window.get_visible(): self.window.hide_all()
class Toolbar(): ''' Toolbar window''' def __init__(self, parent=None, screenshot=None): ''' init toolbar @param parent: the transient parent for this window @param screenshot: a Screenshot object ''' self.screenshot = screenshot self.win = screenshot.window self.__config = OperateConfig() save_op = self.__config.get("save", "save_op") if save_op: self.screenshot.save_op_index = int(save_op) else: self.screenshot.save_op_index = SAVE_OP_AUTO #toolbar_padding_x = 15 #toolbar_padding_y = 5 #toolbar_icon_width = toolbar_icon_height = 28 #toolbar_icon_num = 10 #self.height = toolbar_icon_height + toolbar_padding_y * 2 self.height = 30 self.width = 279 #self.width = 240 self.window = Window(window_type=gtk.WINDOW_POPUP, shadow_visible=False) self.window.set_keep_above(True) self.window.set_decorated(False) self.window.set_transient_for(parent) self.toolbox = gtk.HBox(False, 6) toolbox_align = gtk.Alignment() toolbox_align.set(0, 0.5, 0, 0) toolbox_align.set_padding(2, 2, 11, 11) toolbox_align.add(self.toolbox) self.window.window_frame.pack_start(toolbox_align, True, True) #self.window.set_size_request(self.width, self.height) self.window.set_size_request(-1, self.height) self._toggle_button_list = [] self._toggle_button_group = ToggleButtonGroup([], 6) self.toolbox.pack_start(self._toggle_button_group) self.create_toggle_button("rect", ACTION_RECTANGLE, 0, _("draw rectangle")) self.create_toggle_button("ellipse", ACTION_ELLIPSE, 1, _("draw ellipse")) self.create_toggle_button("arrow", ACTION_ARROW, 2, _("draw arrow")) self.create_toggle_button("line", ACTION_LINE, 3, _("draw line")) self.create_toggle_button("text", ACTION_TEXT, 4, _("draw Text")) self.create_button("undo", _("undo")) # pack save and list button save_combo_button = ComboButton( app_theme.get_pixbuf("action/save_normal.png"), app_theme.get_pixbuf("action/save_hover.png"), app_theme.get_pixbuf("action/save_press.png"), app_theme.get_pixbuf("action/save_normal.png"), app_theme.get_pixbuf("action/list_normal.png"), app_theme.get_pixbuf("action/list_hover.png"), app_theme.get_pixbuf("action/list_press.png"), app_theme.get_pixbuf("action/list_normal.png"), ) save_combo_button.set_name("save") save_combo_button.connect("button-clicked", self._button_clicked, "save") save_combo_button.connect("arrow-clicked", self._list_menu_show) save_tip_text_list = [ "save automatically", "save as", "save to clipboard", "save automatically to file and clipboard" ] tip_text = save_tip_text_list[self.screenshot.save_op_index] save_combo_button.connect("enter-notify-event", self._show_tooltip, _(tip_text)) self.toolbox.pack_start(save_combo_button) self.create_button("cancel", _("cancel")) self.create_button("share", _("share")) if self.screenshot: self._button_clicked_cb = { 'undo': self.screenshot.undo, 'save': self.save_operate, 'cancel': self.win.quit, 'share': self.share_picture } def create_toggle_button(self, name, action, index, text=''): ''' create a togglebutton @param name: the button's name, a string @param action: one of ACTION Type Constants @param index: the button's index in button list, an int num @param text: the button's tooltip text, a string ''' button = ToggleButtonItem( (app_theme.get_pixbuf("action/" + name + "_normal.png"), app_theme.get_pixbuf("action/" + name + "_press.png"), app_theme.get_pixbuf("action/" + name + "_hover.png"), app_theme.get_pixbuf("action/" + name + "_press.png"), None), index, self._toggle_button_group.set_index, self._toggle_button_group.get_index) button.connect("pressed", self._toggle_button_pressed) button.connect("toggled", self._toggle_button_toggled, action) button.connect("enter-notify-event", self._show_tooltip, text) button.set_name(name) #self.toolbox.pack_start(button) self._toggle_button_group.pack_start(button) self._toggle_button_list.append(button) def create_button(self, name, text=''): ''' make a button @param name: the button's name, a string @param text: the button's tooltip text, a string ''' button = ImageButton( app_theme.get_pixbuf("action/" + name + "_normal.png"), app_theme.get_pixbuf("action/" + name + "_hover.png"), app_theme.get_pixbuf("action/" + name + "_press.png")) button.connect("enter-notify-event", self._show_tooltip, text) button.connect("clicked", self._button_clicked, name) button.set_name(name) #button.set_size_request(28, 28) self.toolbox.pack_start(button) return button def _show_tooltip(self, widget, event, text): '''the button enter-notify-event callback. Create help tooltip.''' #widget.set_has_tooltip(True) #widget.set_tooltip_text(text) #widget.trigger_tooltip_query() Tooltip.text(widget, text) def _list_menu_show(self, button, x, y, offset_x, offset_y): '''the combo button clicked callback. show combo_buton list menu''' menu_item = [(None, _("save automatically"), self._list_menu_click, SAVE_OP_AUTO, button), (None, _("save as"), self._list_menu_click, SAVE_OP_AS, button), (None, _("save to clipboard"), self._list_menu_click, SAVE_OP_CLIP, button), (None, _("save automatically to file and clipboard"), self._list_menu_click, SAVE_OP_AUTO_AND_CLIP, button)] # set current operate icon current_item = menu_item[self.screenshot.save_op_index] menu_pixbuf = (app_theme.get_pixbuf("action/selected.png"), app_theme.get_pixbuf("action/selected_hover.png"), app_theme.get_pixbuf("action/selected.png")) menu_item[self.screenshot.save_op_index] = (menu_pixbuf, current_item[1], current_item[2], current_item[3]) self.combo_menu = Menu( menu_item, is_root_menu=True, menu_item_select_color=app_theme.get_shadow_color( "menu_item_select").get_color_info()) self.set_all_inactive() self.combo_menu.show((x, y), (offset_x, offset_y)) def _list_menu_click(self, save_op_index, button=None): '''list menu clicked callback''' self.screenshot.save_op_index = save_op_index self.__config.set("save", save_op=str(save_op_index)) # reset the save button's tooltip if button: item = self.combo_menu.get_menu_items()[save_op_index] button.disconnect_by_func(self._show_tooltip) button.connect("enter-notify-event", self._show_tooltip, item.item[1]) self.combo_menu.destroy() self.save_operate() def _button_clicked(self, widget, name): ''' button clicked callback ''' if self.screenshot is None: return # save current input text if self.screenshot.show_text_window_flag: self.win.save_text_window() if name in self._button_clicked_cb: self._button_clicked_cb[name](widget) def _toggle_button_pressed(self, widget): ''' toggle button pressed callback ''' # save current input text if self.screenshot.show_text_window_flag: self.win.save_text_window() def _toggle_button_toggled(self, widget, action): ''' toggle button toggled callback''' if self.screenshot is None: return if widget.get_active(): self.screenshot.set_action_type(action) self.win.set_cursor(action) self.win.show_colorbar() self.win.adjust_colorbar() else: self.win.set_cursor(None) self.win.hide_colorbar() if not self.screenshot.action_list and not self.screenshot.text_action_list and self.screenshot.show_toolbar_flag and not self.screenshot.window_flag: self.screenshot.set_action_type(ACTION_SELECT) elif self.screenshot.action_list: self.screenshot.set_action_type(None) def set_button_active(self, name, state): ''' set button active @param name: the button's name which will set, a string type @param state: the state to set, True or False ''' if self._toggle_button_group.is_active(): button = self._toggle_button_list[ self._toggle_button_group.get_index()] # if the button has been in this state, ignore if button.name == name: if button.get_active() == state: return else: button.set_active(False) self._toggle_button_group.set_index(-1) i = 0 for each in self._toggle_button_list: if name == each.get_name(): each.set_active(state) self._toggle_button_group.set_index(i) break i += 1 def has_button_active(self): ''' is has one toggle button active @return: True if has one togglebutton active, otherwise False ''' return self._toggle_button_group.is_active() def save_operate(self, widget=None): '''do save operate''' screenshot = self.screenshot #print "operate:", screenshot.save_op_index # auto save if screenshot.save_op_index == SAVE_OP_AUTO: folder = utils.get_pictures_dir() filename = "%s%s.%s" % (_(DEFAULT_FILENAME), utils.get_format_time(), "png") screenshot.save_snapshot("%s/%s" % (folder, filename)) # save as elif screenshot.save_op_index == SAVE_OP_AS: self.save_to_file() # copy to clip elif screenshot.save_op_index == SAVE_OP_CLIP: screenshot.save_snapshot() # auto save and copy to clip else: folder = utils.get_pictures_dir() filename = "%s%s.%s" % (_(DEFAULT_FILENAME), utils.get_format_time(), "png") screenshot.save_snapshot("%s/%s" % (folder, filename), clip_flag=True) def share_picture(self, widget): '''share picture. share button clicked callback''' self.screenshot.share_to_flag = True self.screenshot.save_op_index = SAVE_OP_AUTO self.save_operate() def save_to_file(self): ''' save to file ''' self.win.hide_colorbar() self.win.hide_toolbar() #dialog = SaveFileDialog('', self.screenshot.window.window, #ok_callback=self._save_to_file_cb, cancel_callback=self._save_to_file_cancel) dialog = gtk.FileChooserDialog("Save..", self.win.window, gtk.FILE_CHOOSER_ACTION_SAVE, (gtk.STOCK_CANCEL, gtk.RESPONSE_REJECT, gtk.STOCK_SAVE, gtk.RESPONSE_ACCEPT)) dialog.set_action(gtk.FILE_CHOOSER_ACTION_SAVE) dialog.set_default_response(gtk.RESPONSE_ACCEPT) dialog.set_position(gtk.WIN_POS_MOUSE) dialog.set_local_only(True) last_folder = self.__config.get("save", "folder") if last_folder: dialog.set_current_folder(last_folder) else: dialog.set_current_folder(utils.get_pictures_dir()) dialog.set_current_name( "%s%s.%s" % (_(DEFAULT_FILENAME), utils.get_format_time(), "png")) response = dialog.run() filename = dialog.get_filename() if response == gtk.RESPONSE_ACCEPT: self.__config.set("save", folder=dialog.get_current_folder()) self._save_to_file_cb(filename) else: self._save_to_file_cancel(filename) dialog.destroy() def _save_to_file_cancel(self, filename): ''' save file dialog cancel_callback''' self.screenshot.share_to_flag = False self.win.adjust_toolbar() self.win.show_toolbar() if self.has_button_active(): self.win.show_colorbar() def _save_to_file_cb(self, filename): ''' save file dialog ok_callback''' print "save", filename self.screenshot.save_snapshot(filename=filename) def set_all_inactive(self): '''set all toggle button inactive''' #index = self._toggle_button_group.get_index() #if index != -1: #self._toggle_button_list[index].set_active(False) #for each in self._toggle_button_list: #each.set_active(False) if self._toggle_button_group.is_active(): self._toggle_button_group.set_index(-1) def show(self): ''' show the toolbar ''' if not self.window.get_visible(): self.window.show_window() #print "toolbox:", self.toolbox.allocation, self.window.allocation def hide(self): '''hide the toolbar''' if self.window.get_visible(): self.window.hide_all()