def update_title(self, filename): if filename: #TRANSLATORS: window title for use with a filename self.set_title(_("%s - MyPaint") % os.path.basename(filename)) else: #TRANSLATORS: window title for use without a filename self.set_title(_("MyPaint"))
def __init__(self, app): self.app = app #NOTE: filehandling and drawwindow are very tightly coupled self.save_dialog = None ag = app.builder.get_object('FileActions') rf = gtk.RecentFilter() rf.add_application('mypaint') ra = app.find_action("OpenRecent") ra.add_filter(rf) for action in ag.list_actions(): self.app.kbm.takeover_action(action) self._filename = None self.current_file_observers = [] self.file_opened_observers = [] self.active_scrap_filename = None self.lastsavefailed = False self.set_recent_items() self.file_filters = [ # (name, patterns) (_("All Recognized Formats"), ("*.ora", "*.png", "*.jpg", "*.jpeg")), (_("OpenRaster (*.ora)"), ("*.ora",)), (_("PNG (*.png)"), ("*.png",)), (_("JPEG (*.jpg; *.jpeg)"), ("*.jpg", "*.jpeg")), ] saveformat_keys = [ SAVE_FORMAT_ANY, SAVE_FORMAT_ORA, SAVE_FORMAT_PNGSOLID, SAVE_FORMAT_PNGTRANS, SAVE_FORMAT_PNGMULTI, SAVE_FORMAT_JPEG, ] saveformat_values = [ # (name, extension, options) (_("By extension (prefer default format)"), None, {}), (_("OpenRaster (*.ora)"), '.ora', {}), (_("PNG solid with background (*.png)"), '.png', {'alpha': False}), (_("PNG transparent (*.png)"), '.png', {'alpha': True}), (_("Multiple PNG transparent (*.XXX.png)"), '.png', {'multifile': True}), (_("JPEG 90% quality (*.jpg; *.jpeg)"), '.jpg', {'quality': 90}), ] self.saveformats = OrderedDict(zip(saveformat_keys, saveformat_values)) self.ext2saveformat = { ".ora": (SAVE_FORMAT_ORA, "image/openraster"), ".png": (SAVE_FORMAT_PNGAUTO, "image/png"), ".jpeg": (SAVE_FORMAT_JPEG, "image/jpeg"), ".jpg": (SAVE_FORMAT_JPEG, "image/jpeg"), } self.config2saveformat = { 'openraster': SAVE_FORMAT_ORA, 'jpeg-90%': SAVE_FORMAT_JPEG, 'png-solid': SAVE_FORMAT_PNGSOLID, } self.__statusbar_context_id = None
class ScratchpadTool(SizedVBoxToolWidget): __gtype_name__ = 'MyPaintScratchpadTool' SIZED_VBOX_NATURAL_HEIGHT = TOOL_WIDGET_NATURAL_HEIGHT_SHORT tool_widget_title = _("Scratchpad") tool_widget_icon_name = 'mypaint-scratchpad-symbolic' tool_widget_description = _("Mix colors and make sketches on " "separate scrap pages") def __init__(self): super(SizedVBoxToolWidget, self).__init__() from gui.application import get_app app = get_app() self.app = app toolbar = inline_toolbar(app, [ ("ScratchNew", "mypaint-add-symbolic"), ("ScratchLoad", None), ("ScratchSaveAs", "mypaint-document-save-symbolic"), ("ScratchRevert", "mypaint-document-revert-symbolic"), ]) scratchpad_view = app.scratchpad_doc.tdw scratchpad_view.set_size_request(64, 64) self.connect("destroy-event", self._save_cb) self.connect("delete-event", self._save_cb) scratchpad_box = Gtk.EventBox() scratchpad_box.add(scratchpad_view) self.pack_start(scratchpad_box, True, True, 0) self.pack_start(toolbar, False, True, 0) def _save_cb(self, action): filename = self.app.scratchpad_filename logger.info("Saving the scratchpad to %r", filename) self.app.filehandler.save_scratchpad(filename)
def __init__(self): super(AccelMapEditor, self).__init__() self.ui_manager = None self.connect("show", self._show_cb) store = Gtk.ListStore(*self._COLUMN_TYPES) self._store = store self._action_labels = {} self._accel_labels = {} scrolls = Gtk.ScrolledWindow() scrolls.set_shadow_type(Gtk.ShadowType.IN) view = Gtk.TreeView() view.set_model(store) view.set_size_request(480, 320) view.set_hexpand(True) view.set_vexpand(True) scrolls.add(view) self.attach(scrolls, 0, 0, 1, 1) view.set_headers_clickable(True) view.set_enable_search(True) view.set_search_column(self._SEARCH_TEXT_COLUMN) view.set_search_equal_func(self._view_search_equal_cb) self._view = view cell = Gtk.CellRendererText() cell.set_property("ellipsize", Pango.EllipsizeMode.END) cell.set_property("editable", False) cell.set_property("ypad", 8) cell.set_property("xpad", 8) col = Gtk.TreeViewColumn(_("Action"), cell) col.add_attribute(cell, "markup", self._ACTION_LABEL_COLUMN) col.set_expand(True) col.set_resizable(True) col.set_min_width(200) col.set_sort_column_id(self._ACTION_LABEL_SORT_COLUMN) view.append_column(col) cell = Gtk.CellRendererText() cell.set_property("ellipsize", Pango.EllipsizeMode.END) cell.set_property("editable", True) cell.set_property("ypad", 8) cell.set_property("xpad", 8) cell.connect("edited", self._accel_edited_cb) cell.connect("editing-started", self._accel_editing_started_cb) # TRANSLATORS: Refers to a keyboard key combination, such as "Ctrl+G". # TRANSLATORS: Second column label in the keybinding preferences tab. col = Gtk.TreeViewColumn(_("Key combination"), cell) col.add_attribute(cell, "markup", self._ACCEL_LABEL_COLUMN) col.set_expand(False) col.set_resizable(True) col.set_min_width(75) col.set_sort_column_id(self._ACCEL_LABEL_SORT_COLUMN) view.append_column(col) store.set_sort_column_id( self._ACTION_LABEL_SORT_COLUMN, Gtk.SortType.ASCENDING, )
def __init__(self): super(AccelMapEditor, self).__init__() self.ui_manager = None self.connect("show", self._show_cb) store = Gtk.ListStore(*self._COLUMN_TYPES) self._store = store self._action_labels = {} self._accel_labels = {} scrolls = Gtk.ScrolledWindow() scrolls.set_shadow_type(Gtk.ShadowType.IN) view = Gtk.TreeView() view.set_model(store) view.set_size_request(480, 320) view.set_hexpand(True) view.set_vexpand(True) scrolls.add(view) self.attach(scrolls, 0, 0, 1, 1) view.set_headers_clickable(True) view.set_enable_search(True) view.set_search_column(self._SEARCH_TEXT_COLUMN) view.set_search_equal_func(self._view_search_equal_cb) view.set_rules_hint(True) self._view = view cell = Gtk.CellRendererText() cell.set_property("ellipsize", Pango.EllipsizeMode.END) cell.set_property("editable", False) cell.set_property("ypad", 8) cell.set_property("xpad", 8) col = Gtk.TreeViewColumn(_("Action"), cell) col.add_attribute(cell, "markup", self._ACTION_LABEL_COLUMN) col.set_expand(True) col.set_resizable(True) col.set_min_width(200) col.set_sort_column_id(self._ACTION_LABEL_COLUMN) view.append_column(col) cell = Gtk.CellRendererText() cell.set_property("ellipsize", Pango.EllipsizeMode.END) cell.set_property("editable", True) cell.set_property("ypad", 8) cell.set_property("xpad", 8) cell.connect("edited", self._accel_edited_cb) cell.connect("editing-started", self._accel_editing_started_cb) col = Gtk.TreeViewColumn(_("Key combination"), cell) col.add_attribute(cell, "markup", self._ACCEL_LABEL_COLUMN) col.set_expand(False) col.set_resizable(True) col.set_min_width(75) col.set_sort_column_id(self._ACCEL_LABEL_COLUMN) view.append_column(col) store.set_sort_column_id( self._ACTION_LABEL_COLUMN, Gtk.SortType.ASCENDING, )
def confirm_destructive_action(self, title=_('Confirm'), question=_('Really continue?')): """Asks the user to confirm an action that might lose work :param title: Dialog title :param question: Question to ask the user :rtype bool: :returns: true if the user chose to destroy their work This method doesn't bother asking if there are fewer than a handful of seconds of unsaved work. By default, that's 1 second, but the build-time and runtime debugging flags make this period longer to allow faster develop and test cycles. """ self.doc.model.sync_pending_changes() t = self.doc.model.unsaved_painting_time t_bother = 1 if mypaintlib.heavy_debug: t_bother += 7 if os.environ.get("MYPAINT_DEBUG", False): t_bother += 7 # This used to be 30, but see https://gna.org/bugs/?17955 # Then 8 by default, but Twitter users hate that too. logger.debug("Destructive action don't-bother period is %ds", t_bother) if t < t_bother: return True #TRANSLATORS: Abbreviated string is an already translated time #TRANSLATORS: period abbreviation, like "6m42s", or "103s". unsaved_str = _( u"This will discard {abbreviated_time} of unsaved painting" ).format(abbreviated_time=helpers.fmt_time_period_abbr(t), ) d = gtk.Dialog(title, self.app.drawWindow, gtk.DIALOG_MODAL) b = d.add_button(gtk.STOCK_DISCARD, gtk.RESPONSE_OK) b.set_image( gtk.image_new_from_stock(gtk.STOCK_DELETE, gtk.ICON_SIZE_BUTTON)) d.add_button(gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL) b = d.add_button(_("_Save as Scrap"), gtk.RESPONSE_APPLY) b.set_image( gtk.image_new_from_stock(gtk.STOCK_SAVE, gtk.ICON_SIZE_BUTTON)) d.set_default_response(gtk.RESPONSE_CANCEL) l = gtk.Label() l.set_markup("<b>%s</b>\n\n%s" % (question, unsaved_str)) l.set_padding(10, 10) l.show() d.vbox.pack_start(l) response = d.run() d.destroy() if response == gtk.RESPONSE_APPLY: self.save_scrap_cb(None) return True return response == gtk.RESPONSE_OK
def update_fullscreen_action(self): action = self.action_group.get_action("Fullscreen") if self.is_fullscreen: action.set_icon_name("mypaint-unfullscreen-symbolic") action.set_tooltip(_("Leave Fullscreen Mode")) action.set_label(_("Leave Fullscreen")) else: action.set_icon_name("mypaint-fullscreen-symbolic") action.set_tooltip(_("Enter Fullscreen Mode")) action.set_label(_("Fullscreen"))
def confirm_destructive_action(self, title=_('Confirm'), question=_('Really continue?')): """Asks the user to confirm an action that might lose work :param title: Dialog title :param question: Question to ask the user :rtype bool: :returns: true if the user chose to destroy their work This method doesn't bother asking if there are fewer than a handful of seconds of unsaved work. By default, that's 1 second, but the build-time and runtime debugging flags make this period longer to allow faster develop and test cycles. """ self.doc.model.sync_pending_changes() t = self.doc.model.unsaved_painting_time t_bother = 1 if mypaintlib.heavy_debug: t_bother += 7 if os.environ.get("MYPAINT_DEBUG", False): t_bother += 7 # This used to be 30, but see https://gna.org/bugs/?17955 # Then 8 by default, but Twitter users hate that too. logger.debug("Destructive action don't-bother period is %ds", t_bother) if t < t_bother: return True #TRANSLATORS: Abbreviated string is an already translated time #TRANSLATORS: period abbreviation, like "6m42s", or "103s". unsaved_str = _( u"This will discard {abbreviated_time} of unsaved painting" ).format( abbreviated_time = helpers.fmt_time_period_abbr(t), ) d = gtk.Dialog(title, self.app.drawWindow, gtk.DIALOG_MODAL) b = d.add_button(gtk.STOCK_DISCARD, gtk.RESPONSE_OK) b.set_image(gtk.image_new_from_stock(gtk.STOCK_DELETE, gtk.ICON_SIZE_BUTTON)) d.add_button(gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL) b = d.add_button(_("_Save as Scrap"), gtk.RESPONSE_APPLY) b.set_image(gtk.image_new_from_stock(gtk.STOCK_SAVE, gtk.ICON_SIZE_BUTTON)) d.set_default_response(gtk.RESPONSE_CANCEL) l = gtk.Label() l.set_markup("<b>%s</b>\n\n%s" % (question, unsaved_str)) l.set_padding(10, 10) l.show() d.vbox.pack_start(l) response = d.run() d.destroy() if response == gtk.RESPONSE_APPLY: self.save_scrap_cb(None) return True return response == gtk.RESPONSE_OK
def import_brush_pack_cb(self, *junk): format_id, filename = dialogs.open_dialog( _("Import brush package..."), self, [(_("MyPaint brush package (*.zip)"), "*.zip")] ) if not filename: return imported = self.app.brushmanager.import_brushpack(filename, self) logger.info("Imported brush groups %r", imported) workspace = self.app.workspace for groupname in imported: workspace.reveal_tool_widget("MyPaintBrushGroupTool", (groupname,))
def import_brush_pack_cb(self, *junk): format_id, filename = dialogs.open_dialog( _("Import brush package..."), self, [(_("MyPaint brush package (*.zip)"), "*.zip")]) if not filename: return imported = self.app.brushmanager.import_brushpack(filename, self) logger.info("Imported brush groups %r", imported) workspace = self.app.workspace for groupname in imported: workspace.reveal_tool_widget("MyPaintBrushGroupTool", (groupname, ))
def update_title(self, filename): if filename: # TRANSLATORS: window title for use with a filename title_base = _("%s - MyPaint") % os.path.basename(filename) else: # TRANSLATORS: window title for use without a filename title_base = _("MyPaint") # Show whether legacy 1.x compatibility mode is active if self.app.compat_mode == compatibility.C1X: compat_str = " (%s)" % C_("Prefs Dialog|Compatibility", "1.x") else: compat_str = "" self.set_title(title_base + compat_str)
def menu_command_about(): about_win = Toplevel() wallpapoz_logo_path = os.path.dirname(os.path.abspath(__file__)) +\ '/../../share/wallpapoz/images/wallpapoz.png' if os.path.exists(wallpapoz_logo_path): img = Image.open(wallpapoz_logo_path) logo = ImageTk.PhotoImage(img) image_label = Label(about_win, image=logo) image_label.pack() image_label.image = logo wallpapoz_label = Label(about_win, text='wallpapoz', font=('courier', 20, 'bold')) wallpapoz_label.pack() unix_label = Label(about_win, text=_('Unix Desktop Wallpapers ' 'Configuration System'), font=('courier', 12)) unix_label.pack() copyright_label = Label(about_win, text=_('Copyright') + ' @ 2004 - 2013 Vajrasky Kok') copyright_label.pack() def click_wallpapoz_website_label(event): import webbrowser webbrowser.open('http://vajrasky.wordpress.com/wallpapoz') wallpapoz_website_label = Label(about_win, text=_('Wallpapoz Website'), font=('courier', 11, 'underline'), fg='blue') wallpapoz_website_label.bind('<Button-1>', click_wallpapoz_website_label) wallpapoz_website_label.pack() buttons_frame = Frame(about_win) Button(buttons_frame, text='Credits', command=launch_credit_window)\ .pack(side=LEFT) Button(buttons_frame, text='License', command=launch_license_window)\ .pack(side=LEFT) Button(buttons_frame, text='Close', command=about_win.destroy)\ .pack(side=LEFT) buttons_frame.pack() about_win.title(_('About Wallpapoz')) about_win.focus_set() about_win.grab_set()
def add_files(): filenames = filedialog.askopenfilenames() from wallpapoz_gui.wallpapoz_main_window import tree tree_selection = tree.selection() if '_' in tree_selection[0]: showerror(_("Empty tree parent selection"), _("Must choose at least one tree parent.")) else: for selection in tree_selection: if '_' not in selection: n = len(tree.get_children(selection)) for filename in filenames: if _is_valid_image(filename): tree.insert(selection, 'end', selection + '_' + str(n+1), text=filename) n += 1
def _makesetting(setting_window, conf): setting_label = Label(setting_window, text=_('Setting'), font=('courier', 20, 'bold')) setting_label.pack(side=TOP) style_container = Frame(setting_window) style_container.pack(side=TOP) style_label = Label(style_container, text=_('Display wallpaper in style: '), font=('courier', 15, 'bold')) style_label.pack(side=LEFT) style_combobox = Combobox(style_container) available_style = { '3': 'zoom', '2': 'scaled', '1': 'stretched', '0': 'centered', '4': 'wallpaper' } style_combobox['value'] = (_('centered'), _('stretched'), _('scaled'), _('zoom'), _('wallpaper')) style_combobox.state(['readonly']) style_combobox.current(int(conf['style'])) style_combobox.pack(side=LEFT) random_container = Frame(setting_window) random_container.pack(side=TOP) random_label = Label(random_container, text=_('Choose wallpaper randomly? '), font=('courier', 15, 'bold')) random_label.pack(side=LEFT) random_checkbutton = Checkbutton(random_container) random_checkbutton.pack(side=LEFT) if conf['random'] == "1": random_checkbutton.select() interval_container = Frame(setting_window) interval_container.pack(side=TOP) interval_label = Label(interval_container, text=_('Change wallpaper every '), font=('courier', 15, 'bold')) interval_label.pack(side=LEFT) interval_text = Text(interval_container, height=1, width=4) interval_text.insert(END, conf['interval']) interval_text.pack(side=LEFT) minute_label = Label(interval_container, text=_(' minutes.'), font=('courier', 15, 'bold')) minute_label.pack(side=LEFT)
def open_scratchpad_dialog(self): dialog = gtk.FileChooserDialog(_("Open Scratchpad..."), self.app.drawWindow, gtk.FILE_CHOOSER_ACTION_OPEN, (gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL, gtk.STOCK_OPEN, gtk.RESPONSE_OK)) dialog.set_default_response(gtk.RESPONSE_OK) preview = gtk.Image() dialog.set_preview_widget(preview) dialog.connect("update-preview", self.update_preview_cb, preview) add_filters_to_dialog(self.file_filters, dialog) if self.app.scratchpad_filename: dialog.set_filename(self.app.scratchpad_filename) else: # choose the most recent save folder self.set_recent_items() for item in reversed(self.recent_items): uri = item.get_uri() fn = fileutils.uri2filename(uri) dn = os.path.dirname(fn) if os.path.isdir(dn): dialog.set_current_folder(dn) break try: if dialog.run() == gtk.RESPONSE_OK: dialog.hide() self.app.scratchpad_filename = dialog.get_filename().decode('utf-8') self.open_scratchpad(self.app.scratchpad_filename) finally: dialog.destroy()
def open_scrap_cb(self, action): groups = self.list_scraps_grouped() if not groups: msg = _('There are no scrap files named "%s" yet.') % \ (self.get_scrap_prefix() + '[0-9]*') self.app.message_dialog(msg, Gtk.MessageType.WARNING) return next = action.get_name() == 'NextScrap' if next: dialog_title = C_( u'File→Open Next/Prev Scrap confirm dialog: ' u'title', u"Open Next Scrap?") idx = 0 delta = 1 else: dialog_title = C_( u'File→Open Next/Prev Scrap confirm dialog: ' u'title', u"Open Previous Scrap?") idx = -1 delta = -1 ok_to_open = self.app.filehandler.confirm_destructive_action( title=dialog_title, confirm=C_( u'File→Open Next/Prev Scrap confirm dialog: ' u'continue button', u"_Open"), ) if not ok_to_open: return for i, group in enumerate(groups): if self.active_scrap_filename in group: idx = i + delta filename = groups[idx % len(groups)][-1] self.open_file(filename)
def init_save_dialog(self, export): if export: save_dialog_name = C_("Dialogs: Save As...", u"Export") else: save_dialog_name = C_("Dialogs: Save As...", u"Save") dialog = Gtk.FileChooserDialog( save_dialog_name, self.app.drawWindow, Gtk.FileChooserAction.SAVE, ( Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL, Gtk.STOCK_SAVE, Gtk.ResponseType.OK, ), ) dialog.set_default_response(Gtk.ResponseType.OK) dialog.set_do_overwrite_confirmation(True) _add_filters_to_dialog(self.file_filters, dialog) # Add widget for selecting save format box = Gtk.HBox() label = Gtk.Label(_('Format to save as:')) label.set_alignment(0.0, 0.0) combo = self.saveformat_combo = Gtk.ComboBoxText() for name, ext, opt in self.saveformats.itervalues(): combo.append_text(name) combo.set_active(0) combo.connect('changed', self.selected_save_format_changed_cb) box.pack_start(label, True, True, 0) box.pack_start(combo, False, True, 0) dialog.set_extra_widget(box) dialog.show_all() return dialog
def open_cb(self, action): if not self.confirm_destructive_action(): return dialog = gtk.FileChooserDialog(_("Open..."), self.app.drawWindow, gtk.FILE_CHOOSER_ACTION_OPEN, (gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL, gtk.STOCK_OPEN, gtk.RESPONSE_OK)) dialog.set_default_response(gtk.RESPONSE_OK) preview = gtk.Image() dialog.set_preview_widget(preview) dialog.connect("update-preview", self.update_preview_cb, preview) add_filters_to_dialog(self.file_filters, dialog) if self.filename: dialog.set_filename(self.filename) else: # choose the most recent save folder self.set_recent_items() for item in reversed(self.recent_items): uri = item.get_uri() fn, _h = lib.glib.filename_from_uri(uri) dn = os.path.dirname(fn) if os.path.isdir(dn): dialog.set_current_folder(dn) break try: if dialog.run() == gtk.RESPONSE_OK: dialog.hide() self.open_file(dialog.get_filename().decode('utf-8')) finally: dialog.destroy()
def init_save_dialog(self): dialog = gtk.FileChooserDialog( C_("Dialogs: Save As...", u"Save"), self.app.drawWindow, gtk.FILE_CHOOSER_ACTION_SAVE, ( gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL, gtk.STOCK_SAVE, gtk.RESPONSE_OK, ), ) self.save_dialog = dialog dialog.set_default_response(gtk.RESPONSE_OK) dialog.set_do_overwrite_confirmation(True) _add_filters_to_dialog(self.file_filters, dialog) # Add widget for selecting save format box = gtk.HBox() label = gtk.Label(_('Format to save as:')) label.set_alignment(0.0, 0.0) combo = self.saveformat_combo = gtk.ComboBoxText() for name, ext, opt in self.saveformats.itervalues(): combo.append_text(name) combo.set_active(0) combo.connect('changed', self.selected_save_format_changed_cb) box.pack_start(label) box.pack_start(combo, expand=False) dialog.set_extra_widget(box) dialog.show_all()
def open_scratchpad_dialog(self): dialog = Gtk.FileChooserDialog( _("Open Scratchpad..."), self.app.drawWindow, Gtk.FileChooserAction.OPEN, (Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL, Gtk.STOCK_OPEN, Gtk.ResponseType.OK)) dialog.set_default_response(Gtk.ResponseType.OK) preview = Gtk.Image() dialog.set_preview_widget(preview) dialog.connect("update-preview", self.update_preview_cb, preview) _add_filters_to_dialog(self.file_filters, dialog) if self.app.scratchpad_filename: dialog.set_filename(self.app.scratchpad_filename) else: # choose the most recent save folder self._update_recent_items() for item in reversed(self._recent_items): uri = item.get_uri() fn, _h = lib.glib.filename_from_uri(uri) dn = os.path.dirname(fn) if os.path.isdir(dn): dialog.set_current_folder(dn) break try: if dialog.run() == Gtk.ResponseType.OK: dialog.hide() self.app.scratchpad_filename = dialog.get_filename().decode('utf-8') self.open_scratchpad(self.app.scratchpad_filename) finally: dialog.destroy()
def open_scratchpad_dialog(self): dialog = gtk.FileChooserDialog(_("Open Scratchpad..."), self.app.drawWindow, gtk.FILE_CHOOSER_ACTION_OPEN, (gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL, gtk.STOCK_OPEN, gtk.RESPONSE_OK)) dialog.set_default_response(gtk.RESPONSE_OK) preview = gtk.Image() dialog.set_preview_widget(preview) dialog.connect("update-preview", self.update_preview_cb, preview) _add_filters_to_dialog(self.file_filters, dialog) if self.app.scratchpad_filename: dialog.set_filename(self.app.scratchpad_filename) else: # choose the most recent save folder self._update_recent_items() for item in reversed(self._recent_items): uri = item.get_uri() fn, _h = lib.glib.filename_from_uri(uri) dn = os.path.dirname(fn) if os.path.isdir(dn): dialog.set_current_folder(dn) break try: if dialog.run() == gtk.RESPONSE_OK: dialog.hide() self.app.scratchpad_filename = dialog.get_filename().decode( 'utf-8') self.open_scratchpad(self.app.scratchpad_filename) finally: dialog.destroy()
def add_directory(): directory = filedialog.askdirectory() if not directory: return from wallpapoz_gui.wallpapoz_main_window import tree tree_selection = tree.selection() if '_' in tree_selection[0]: showerror(_("Empty tree parent selection"), _("Must choose at least one tree parent.")) else: for selection in tree_selection: n = len(tree.get_children(selection)) for root, dirs, filenames in os.walk(directory): for filename in filenames: image_path = root + '/' + filename if _is_valid_image(image_path): tree.insert(selection, 'end', selection + '_' + str(n+1), text=image_path) n += 1
def _edit_dialog_set_standard_hint(self, dialog): """Set the boring how-to message in capture dialog""" # TRANSLATORS: "keys" refers to keyboard keys, assignment refers # TRANSLATORS: to an assignment of a keyboard key combination to # TRANSLATORS: an action. This is an instructive message in the # TRANSLATORS: keybinding dialog (Preferences | Keys). markup = _("Press keys to update this assignment") self._edit_dialog_set_hint(dialog, markup)
def get_display_name(self): """Gets a displayable name for the brush.""" if self.bm.is_in_brushlist(self): # FIXME: get rid of this check dname = self.name else: dname = self.brushinfo.get_string_property("parent_brush_name") if dname is None: return _("Unknown Brush") return dname.replace("_", " ")
def launch_credit_window(): credit_win = Toplevel() tabs = ttk.Notebook(credit_win) credit_tab = ttk.Frame(tabs) t = Text(credit_tab, width=50, height=10) t.insert(END, "Vajrasky Kok <*****@*****.**>") t.configure(state='disabled') t.pack() documentation_tab = ttk.Frame(tabs) t = Text(documentation_tab, width=50, height=10) t.insert(END, "Vajrasky Kok <*****@*****.**>") t.configure(state='disabled') t.pack() tabs.add(credit_tab, text=_("Written by")) tabs.add(documentation_tab, text=_("Documentated by")) tabs.pack() credit_win.title(_("Wallpapoz Credit")) credit_win.focus_set() credit_win.grab_set()
def color_details_dialog_cb(self, action): mgr = self.app.brush_color_manager new_col = dialogs.ask_for_color( title=_("Set current color"), color=mgr.get_color(), previous_color=mgr.get_previous_color(), parent=self, ) if new_col is not None: mgr.set_color(new_col)
def add_to_grid(self, grid, row): self._label = Gtk.Label() self._label.set_text(_(self.name + ":")) self._label.set_alignment(1.0, 0.5) self._changer = self._get_gui_item() if self.gui_setup_cb is not None: self.gui_setup_cb(self._changer) grid.attach(self._label, 0, row, 1, 1) grid.attach(self._changer, 1, row, 1, 1) return row + 1
def _app_name_datafunc(self, col, cell, model, it, data): app = model.get_value(it, 0) name = app.get_display_name() desc = app.get_description() if desc is not None: markup_template = "<b>{name}</b>\n{description}" else: markup_template = "<b>{name}</b>\n<i>({description})</i>" desc = _("no description") markup = markup_template.format(name=lib.xml.escape(name), description=lib.xml.escape(desc)) cell.set_property("markup", markup)
def _makesetting(setting_window, conf): setting_label = Label(setting_window, text=_('Setting'), font=('courier', 20, 'bold')) setting_label.pack(side=TOP) style_container = Frame(setting_window) style_container.pack(side=TOP) style_label = Label(style_container, text=_('Display wallpaper in style: '), font=('courier', 15, 'bold')) style_label.pack(side=LEFT) style_combobox = Combobox(style_container) available_style = {'3': 'zoom', '2': 'scaled', '1': 'stretched', '0': 'centered', '4': 'wallpaper'} style_combobox['value'] = (_('centered'), _('stretched'), _('scaled'), _('zoom'), _('wallpaper')) style_combobox.state(['readonly']) style_combobox.current(int(conf['style'])) style_combobox.pack(side=LEFT) random_container = Frame(setting_window) random_container.pack(side=TOP) random_label = Label(random_container, text=_('Choose wallpaper randomly? '), font=('courier', 15, 'bold')) random_label.pack(side=LEFT) random_checkbutton = Checkbutton(random_container) random_checkbutton.pack(side=LEFT) if conf['random'] == "1": random_checkbutton.select() interval_container = Frame(setting_window) interval_container.pack(side=TOP) interval_label = Label(interval_container, text=_('Change wallpaper every '), font=('courier', 15, 'bold')) interval_label.pack(side=LEFT) interval_text = Text(interval_container, height=1, width=4) interval_text.insert(END, conf['interval']) interval_text.pack(side=LEFT) minute_label = Label(interval_container, text=_(' minutes.'), font=('courier', 15, 'bold')) minute_label.pack(side=LEFT)
def launch_license_window(): license_win = Toplevel() license_file = os.path.dirname(os.path.abspath(__file__)) +\ '/../../COPYING' license_content = None with open(license_file) as lf: license_content = lf.read() t = Text(license_win, width=80, height=40) t.insert(END, "(c) 2013 Vajrasky Kok\n" + license_content) t.configure(state='disabled') t.pack() license_win.title(_("Wallpapoz License")) license_win.focus_set() license_win.grab_set()
def _app_name_datafunc(self, col, cell, model, it, data): app = model.get_value(it, 0) name = app.get_display_name() desc = app.get_description() if desc is not None: markup_template = "<b>{name}</b>\n{description}" else: markup_template = "<b>{name}</b>\n<i>({description})</i>" desc = _("no description") markup = markup_template.format( name=lib.xml.escape(name), description=lib.xml.escape(desc), ) cell.set_property("markup", markup)
def init_save_dialog(self): dialog = gtk.FileChooserDialog(_("Save..."), self.app.drawWindow, gtk.FILE_CHOOSER_ACTION_SAVE, (gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL, gtk.STOCK_SAVE, gtk.RESPONSE_OK)) self.save_dialog = dialog dialog.set_default_response(gtk.RESPONSE_OK) dialog.set_do_overwrite_confirmation(True) _add_filters_to_dialog(self.file_filters, dialog) # Add widget for selecting save format box = gtk.HBox() label = gtk.Label(_('Format to save as:')) label.set_alignment(0.0, 0.0) combo = self.saveformat_combo = gtk.ComboBoxText() for name, ext, opt in self.saveformats.itervalues(): combo.append_text(name) combo.set_active(0) combo.connect('changed', self.selected_save_format_changed_cb) box.pack_start(label) box.pack_start(combo, expand=False) dialog.set_extra_widget(box) dialog.show_all()
def get_open_dialog(self, filename=None, start_in_folder=None, file_filters=[]): dialog = gtk.FileChooserDialog(_("Open..."), self.app.drawWindow, gtk.FILE_CHOOSER_ACTION_OPEN, (gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL, gtk.STOCK_OPEN, gtk.RESPONSE_OK)) dialog.set_default_response(gtk.RESPONSE_OK) add_filters_to_dialog(file_filters, dialog) if filename: dialog.set_filename(filename) elif start_in_folder and os.path.isdir(start_in_folder): dialog.set_current_folder(start_in_folder) return dialog
def launch_license_window(): license_win = Toplevel() license_file = os.path.dirname(os.path.abspath(__file__)) +\ '/../../COPYING' license_content = None with open(license_file) as lf: license_content = lf.read() t = Text(license_win, width=80, height=40) t.insert(END, "(c) 2014 Vajrasky Kok\n" + license_content) t.configure(state='disabled') t.pack() license_win.title(_("Wallpapoz License")) license_win.focus_set() license_win.grab_set()
def get_open_dialog(self, filename=None, start_in_folder=None, file_filters=[]): dialog = Gtk.FileChooserDialog( _("Open..."), self.app.drawWindow, Gtk.FileChooserAction.OPEN, (Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL, Gtk.STOCK_OPEN, Gtk.ResponseType.OK)) dialog.set_default_response(Gtk.ResponseType.OK) _add_filters_to_dialog(file_filters, dialog) if filename: dialog.set_filename(filename) elif start_in_folder and os.path.isdir(start_in_folder): dialog.set_current_folder(start_in_folder) return dialog
def get_open_dialog(self, filename=None, start_in_folder=None, file_filters=[]): dialog = gtk.FileChooserDialog(_("Open..."), self.app.drawWindow, gtk.FILE_CHOOSER_ACTION_OPEN, (gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL, gtk.STOCK_OPEN, gtk.RESPONSE_OK)) dialog.set_default_response(gtk.RESPONSE_OK) _add_filters_to_dialog(file_filters, dialog) if filename: dialog.set_filename(filename) elif start_in_folder and os.path.isdir(start_in_folder): dialog.set_current_folder(start_in_folder) return dialog
def open_scrap_cb(self, action): groups = self.list_scraps_grouped() if not groups: msg = _('There are no scrap files named "%s" yet.') % \ (self.get_scrap_prefix() + '[0-9]*') self.app.message_dialog(msg, Gtk.MessageType.WARNING) return next = action.get_name() == 'NextScrap' if next: dialog_title = C_( u'File→Open Next/Prev Scrap confirm dialog: ' u'title', u"Open Next Scrap?" ) idx = 0 delta = 1 else: dialog_title = C_( u'File→Open Next/Prev Scrap confirm dialog: ' u'title', u"Open Previous Scrap?" ) idx = -1 delta = -1 ok_to_open = self.app.filehandler.confirm_destructive_action( title = dialog_title, confirm = C_( u'File→Open Next/Prev Scrap confirm dialog: ' u'continue button', u"_Open" ), ) if not ok_to_open: return for i, group in enumerate(groups): if self.active_scrap_filename in group: idx = i + delta filename = groups[idx % len(groups)][-1] self.open_file(filename)
def open_scrap_cb(self, action): groups = self.list_scraps_grouped() if not groups: msg = _('There are no scrap files named "%s" yet.') % \ (self.get_scrap_prefix() + '[0-9]*') self.app.message_dialog(msg, gtk.MESSAGE_WARNING) return if not self.confirm_destructive_action(): return next = action.get_name() == 'NextScrap' if next: idx = 0 else: idx = -1 for i, group in enumerate(groups): if self.active_scrap_filename in group: if next: idx = i + 1 else: idx = i - 1 filename = groups[idx % len(groups)][-1] self.open_file(filename)
def __init__(self, content_type, specific_file=False): Gtk.Dialog.__init__(self) self.set_title(_("Open With...")) self.add_button(Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL) self.add_button(Gtk.STOCK_OK, Gtk.ResponseType.OK) self.set_default_response(Gtk.ResponseType.CANCEL) self.set_response_sensitive(Gtk.ResponseType.OK, False) self.connect("show", self._show_cb) content_box = self.get_content_area() content_box.set_border_width(12) content_box.set_spacing(12) msg_template = self.GENERIC_MSG if specific_file: msg_template = self.SPECIFIC_FILE_MSG msg_text = msg_template.format( content_type=content_type, type_name=Gio.content_type_get_description(content_type), ) msg_label = Gtk.Label(msg_text) msg_label.set_single_line_mode(False) msg_label.set_line_wrap(True) msg_label.set_alignment(0.0, 0.5) content_box.pack_start(msg_label, False, False, 0) default_app = Gio.AppInfo.get_default_for_type(content_type, False) default_iter = None app_list_store = Gtk.ListStore(object) for app in Gio.AppInfo.get_all_for_type(content_type): if not app.should_show(): continue row_iter = app_list_store.append([app]) if default_iter is not None: continue if default_app and Gio.AppInfo.equal(app, default_app): default_iter = row_iter # TreeView to show available apps for this content type view = Gtk.TreeView() view.set_model(app_list_store) view.set_headers_clickable(False) view.set_headers_visible(False) view.connect("row-activated", self._row_activated_cb) view_scrolls = Gtk.ScrolledWindow() view_scrolls.set_shadow_type(Gtk.ShadowType.IN) view_scrolls.add(view) view_scrolls.set_size_request(375, 225) content_box.pack_start(view_scrolls, True, True, 0) # Column 0: application icon cell = Gtk.CellRendererPixbuf() col = Gtk.TreeViewColumn(_("Icon"), cell) col.set_cell_data_func(cell, self._app_icon_datafunc) icon_size_ok, icon_w, icon_h = Gtk.icon_size_lookup(self.ICON_SIZE) if icon_size_ok: col.set_min_width(icon_w) col.set_expand(False) col.set_resizable(False) view.append_column(col) # Column 1: application name cell = Gtk.CellRendererText() cell.set_property("ellipsize", Pango.EllipsizeMode.END) cell.set_property("editable", False) col = Gtk.TreeViewColumn(_("Name"), cell) col.set_cell_data_func(cell, self._app_name_datafunc) col.set_expand(True) col.set_min_width(150) view.append_column(col) # Selection: mode and initial value selection = view.get_selection() selection.set_mode(Gtk.SelectionMode.SINGLE) if default_iter: selection.select_iter(default_iter) self.set_default_response(Gtk.ResponseType.OK) self.set_response_sensitive(Gtk.ResponseType.OK, True) selection.connect("changed", self._selection_changed_cb) # Results go here self.selected_appinfo = default_app #: The app the user chose
def __init__(self, app): self.app = app self.save_dialog = None # File filters definitions, for dialogs self.file_filters = [ # (name, patterns) (_("All Recognized Formats"), ("*.ora", "*.png", "*.jpg", "*.jpeg")), (_("OpenRaster (*.ora)"), ("*.ora",)), (_("PNG (*.png)"), ("*.png",)), (_("JPEG (*.jpg; *.jpeg)"), ("*.jpg", "*.jpeg")), ] # Recent filter, for the menu. # Better to use a regex with re.IGNORECASE than # .upper()==.upper() hacks since internally, filenames are # Unicode and capitalization rules like Turkish's dotless "i" # exist. One day we want all the formats GdkPixbuf can load to # be supported in the dialog. file_regex_exts = set() for name, patts in self.file_filters: for p in patts: e = p.replace("*.", "", 1) file_regex_exts.add(re.escape(e)) file_re = r'[.](?:' + ('|'.join(file_regex_exts)) + r')$' logger.debug("Using regex /%s/i for filtering recent files", file_re) self._file_extension_regex = re.compile(file_re, re.IGNORECASE) rf = Gtk.RecentFilter() rf.add_pattern('') # The blank-string pattern is eeded so the custom func will # get URIs at all, despite the needed flags below. rf.add_custom( func = self._recentfilter_func, needed = ( Gtk.RecentFilterFlags.APPLICATION | Gtk.RecentFilterFlags.URI ) ) ra = app.find_action("OpenRecent") ra.add_filter(rf) ag = app.builder.get_object('FileActions') for action in ag.list_actions(): self.app.kbm.takeover_action(action) self._filename = None self.current_file_observers = [] self.file_opened_observers = [] self.active_scrap_filename = None self.lastsavefailed = False self._update_recent_items() saveformat_keys = [ SAVE_FORMAT_ANY, SAVE_FORMAT_ORA, SAVE_FORMAT_PNGSOLID, SAVE_FORMAT_PNGTRANS, SAVE_FORMAT_PNGMULTI, SAVE_FORMAT_JPEG, ] saveformat_values = [ # (name, extension, options) (_("By extension (prefer default format)"), None, {}), (_("OpenRaster (*.ora)"), '.ora', {}), (_("PNG solid with background (*.png)"), '.png', {'alpha': False}), (_("PNG transparent (*.png)"), '.png', {'alpha': True}), (_("Multiple PNG transparent (*.XXX.png)"), '.png', {'multifile': True}), (_("JPEG 90% quality (*.jpg; *.jpeg)"), '.jpg', {'quality': 90}), ] self.saveformats = OrderedDict(zip(saveformat_keys, saveformat_values)) self.ext2saveformat = { ".ora": (SAVE_FORMAT_ORA, "image/openraster"), ".png": (SAVE_FORMAT_PNGAUTO, "image/png"), ".jpeg": (SAVE_FORMAT_JPEG, "image/jpeg"), ".jpg": (SAVE_FORMAT_JPEG, "image/jpeg"), } self.config2saveformat = { 'openraster': SAVE_FORMAT_ORA, 'jpeg-90%': SAVE_FORMAT_JPEG, 'png-solid': SAVE_FORMAT_PNGSOLID, } self.__statusbar_context_id = None
def translate_group_name(name): """Translates a group name from a disk name to a display name.""" d = {FOUND_BRUSHES_GROUP: _('Lost & Found'), DELETED_BRUSH_GROUP: _('Deleted'), FAVORITES_BRUSH_GROUP: _('Favorites'), 'ink': _('Ink'), 'classic': _('Classic'), 'set#1': _('Set#1'), 'set#2': _('Set#2'), 'set#3': _('Set#3'), 'set#4': _('Set#4'), 'set#5': _('Set#5'), 'experimental': _('Experimental'), 'new': _('New'), } return d.get(name, name)
def __init__(self, docmodel): super(RootStackTreeView, self).__init__() self._docmodel = docmodel treemodel = RootStackTreeModelWrapper(docmodel) self.set_model(treemodel) target1 = Gtk.TargetEntry.new( target="GTK_TREE_MODEL_ROW", flags=Gtk.TargetFlags.SAME_WIDGET, info=1, ) self.drag_source_set( start_button_mask=Gdk.ModifierType.BUTTON1_MASK, targets=[target1], actions=Gdk.DragAction.MOVE, ) self.drag_dest_set( flags=Gtk.DestDefaults.MOTION | Gtk.DestDefaults.DROP, targets=[target1], actions=Gdk.DragAction.MOVE, ) self.connect("button-press-event", self._button_press_cb) # Motion and modifier keys during drag self.connect("drag-begin", self._drag_begin_cb) self.connect("drag-motion", self._drag_motion_cb) self.connect("drag-leave", self._drag_leave_cb) self.connect("drag-drop", self._drag_drop_cb) self.connect("drag-end", self._drag_end_cb) # Track updates from the model self._processing_model_updates = False root = docmodel.layer_stack root.current_path_updated += self._current_path_updated_cb root.expand_layer += self._expand_layer_cb root.collapse_layer += self._collapse_layer_cb root.layer_content_changed += self._layer_content_changed_cb root.current_layer_solo_changed += lambda *a: self.queue_draw() # View behaviour and appearance self.set_headers_visible(False) selection = self.get_selection() selection.set_mode(Gtk.SelectionMode.BROWSE) self.set_size_request(150, 200) # Visibility flag column col = Gtk.TreeViewColumn(_("Visible")) col.set_sizing(Gtk.TreeViewColumnSizing.FIXED) self._flags1_col = col # Visibility cell cell = Gtk.CellRendererPixbuf() col.pack_start(cell, False) datafunc = self._layer_visible_pixbuf_datafunc col.set_cell_data_func(cell, datafunc) # Name and preview column: will be indented col = Gtk.TreeViewColumn(_("Name")) col.set_sizing(Gtk.TreeViewColumnSizing.GROW_ONLY) self._name_col = col # Preview cell cell = Gtk.CellRendererPixbuf() col.pack_start(cell, False) datafunc = self._layer_preview_pixbuf_datafunc col.set_cell_data_func(cell, datafunc) self._preview_cell = cell # Name cell cell = Gtk.CellRendererText() cell.set_property("ellipsize", Pango.EllipsizeMode.END) col.pack_start(cell, True) datafunc = self._layer_name_text_datafunc col.set_cell_data_func(cell, datafunc) col.set_expand(True) col.set_min_width(48) # Other flags column col = Gtk.TreeViewColumn(_("Flags")) col.set_sizing(Gtk.TreeViewColumnSizing.GROW_ONLY) area = col.get_property("cell-area") area.set_orientation(Gtk.Orientation.VERTICAL) self._flags2_col = col # Locked cell cell = Gtk.CellRendererPixbuf() col.pack_end(cell, False) datafunc = self._layer_locked_pixbuf_datafunc col.set_cell_data_func(cell, datafunc) # Column order on screen self._columns = [ self._flags1_col, self._name_col, self._flags2_col, ] for col in self._columns: self.append_column(col) # View appearance self.set_show_expanders(True) self.set_enable_tree_lines(True) self.set_expander_column(self._name_col) self.connect_after("show", self._post_show_cb)
def translate_group_name(name): """Translates a group name from a disk name to a display name.""" d = { FOUND_BRUSHES_GROUP: _('Lost & Found'), DELETED_BRUSH_GROUP: _('Deleted'), FAVORITES_BRUSH_GROUP: _('Favorites'), 'ink': _('Ink'), 'classic': _('Classic'), 'set#1': _('Set#1'), 'set#2': _('Set#2'), 'set#3': _('Set#3'), 'set#4': _('Set#4'), 'set#5': _('Set#5'), 'experimental': _('Experimental'), 'new': _('New'), } return d.get(name, name)
def _edit_dialog_set_standard_hint(self, dialog): """Set the boring how-to message in capture dialog""" markup = _("Press keys to update this assignment") self._edit_dialog_set_hint(dialog, markup)
def _edit_dialog_key_press_cb(self, dialog, event, editable): if event.type != Gdk.EventType.KEY_PRESS: return False if event.is_modifier: return False if self._USE_NORMAL_DIALOG_KEYS: if event.keyval == Gdk.KEY_Return: dialog.response(Gtk.ResponseType.OK) return True elif event.keyval == Gdk.KEY_Escape: dialog.response(Gtk.ResponseType.CANCEL) return True elif event.keyval == Gdk.KEY_BackSpace: dialog.response(Gtk.ResponseType.REJECT) return True # Stolen from GTK 2.24's gtk/gtkmenu.c (gtk_menu_key_press()) # Figure out what modifiers went into determining the key symbol keymap = Gdk.Keymap.get_default() bound, keyval, effective_group, level, consumed_modifiers = ( keymap.translate_keyboard_state( event.hardware_keycode, event.state, event.group, )) keyval = Gdk.keyval_to_lower(keyval) mods = Gdk.ModifierType( event.state & Gtk.accelerator_get_default_mod_mask() & ~consumed_modifiers) # If lowercasing affects the keysym, then we need to include # SHIFT in the modifiers. We re-upper case when we match against # the keyval, but display and save in caseless form. if keyval != event.keyval: mods |= Gdk.ModifierType.SHIFT_MASK accel_label = Gtk.accelerator_get_label(keyval, mods) # So we get (<Shift>j, Shift+J) but just (plus, +). As I # understand it. if not Gtk.accelerator_valid(keyval, mods): return True clash_accel_path = None clash_action_label = None for path, kv, m, changed in self._get_accel_map_entries(): if (kv, m) == (keyval, mods): clash_accel_path = path clash_action_label = self._action_labels.get( clash_accel_path, _("Unknown Action"), ) break if clash_accel_path == dialog.accel_path: # no change self._edit_dialog_set_standard_hint(dialog) label = str(accel_label) dialog.accel_label_widget.set_text(label) elif clash_accel_path: markup_tmpl = _( "<b>{accel} is already in use for '{action}'. " "The existing assignment will be replaced.</b>" ) markup = markup_tmpl.format( accel=lib.xml.escape(accel_label), action=lib.xml.escape(clash_action_label), ) self._edit_dialog_set_hint(dialog, markup) label = "%s (replace)" % (accel_label,) dialog.accel_label_widget.set_text(str(label)) else: self._edit_dialog_set_standard_hint(dialog) label = "%s (changed)" % (accel_label,) dialog.accel_label_widget.set_text(label) dialog.result_mods = mods dialog.result_keyval = keyval return True
def _accel_editing_started_cb(self, cell, editable, treepath): """Begin editing by showing a key capture dialog""" store = self._store it = store.get_iter(treepath) accel_path = store.get_value(it, self._PATH_COLUMN) accel_label = self._accel_labels[accel_path] action_label = self._action_labels[accel_path] editable.set_sensitive(False) dialog = Gtk.Dialog() dialog.set_title(_("Edit Key for '%s'") % action_label) dialog.set_transient_for(self.get_toplevel()) dialog.set_position(Gtk.WindowPosition.CENTER_ON_PARENT) dialog.add_buttons( Gtk.STOCK_DELETE, Gtk.ResponseType.REJECT, Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL, Gtk.STOCK_OK, Gtk.ResponseType.OK, ) dialog.set_default_response(Gtk.ResponseType.OK) dialog.connect("response", self._edit_dialog_response_cb, editable, accel_path) evbox = Gtk.EventBox() evbox.set_border_width(12) dialog.connect("key-press-event", self._edit_dialog_key_press_cb, editable) grid = Gtk.Grid() grid.set_row_spacing(12) grid.set_column_spacing(12) row = 0 label = Gtk.Label() label.set_alignment(0, 0.5) label.set_text(_("Action:")) grid.attach(label, 0, row, 1, 1) label = Gtk.Label() label.set_alignment(0, 0.5) label.set_text(str(action_label)) label.set_tooltip_text(str(accel_path)) label.set_hexpand(True) grid.attach(label, 1, row, 1, 1) if self._SHOW_ACCEL_PATH: row += 1 label = Gtk.Label() label.set_alignment(0, 0.5) label.set_text(_("Path:")) grid.attach(label, 0, row, 1, 1) label = Gtk.Label() label.set_alignment(0, 0.5) label.set_text(str(accel_path)) label.set_hexpand(True) grid.attach(label, 1, row, 1, 1) row += 1 label = Gtk.Label() label.set_alignment(0, 0.5) label.set_text(_("Key:")) grid.attach(label, 0, row, 1, 1) label = Gtk.Label() label.set_alignment(0, 0.5) label.set_text(str(accel_label)) dialog.accel_label_widget = label label.set_hexpand(True) grid.attach(label, 1, row, 1, 1) row += 1 label = Gtk.Label() label.set_hexpand(True) label.set_vexpand(True) label.set_margin_top(12) label.set_margin_bottom(12) label.set_alignment(0, 0) label.set_line_wrap(True) label.set_size_request(200, 75) dialog.hint_widget = label self._edit_dialog_set_standard_hint(dialog) grid.attach(label, 0, row, 2, 1) evbox.add(grid) dialog.get_content_area().pack_start(evbox, True, True, 0) evbox.show_all() dialog.initial_accel_label = accel_label dialog.accel_path = accel_path dialog.result_keyval = None dialog.result_mods = None dialog.show()
def _accel_editing_started_cb(self, cell, editable, treepath): """Begin editing by showing a key capture dialog""" store = self._store it = store.get_iter(treepath) accel_path = store.get_value(it, self._PATH_COLUMN) accel_label = self._accel_labels[accel_path] action_label = self._action_labels[accel_path] editable.set_sensitive(False) dialog = Gtk.Dialog() dialog.set_title(_("Edit Key for '%s'") % action_label) dialog.set_transient_for(self.get_toplevel()) dialog.set_position(Gtk.WindowPosition.CENTER_ON_PARENT) dialog.add_buttons( Gtk.STOCK_DELETE, Gtk.ResponseType.REJECT, Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL, Gtk.STOCK_OK, Gtk.ResponseType.OK, ) dialog.set_default_response(Gtk.ResponseType.OK) dialog.connect( "response", self._edit_dialog_response_cb, editable, accel_path ) evbox = Gtk.EventBox() evbox.set_border_width(12) dialog.connect( "key-press-event", self._edit_dialog_key_press_cb, editable ) grid = Gtk.Grid() grid.set_row_spacing(12) grid.set_column_spacing(12) row = 0 label = Gtk.Label() label.set_alignment(0, 0.5) label.set_text(_("Action:")) grid.attach(label, 0, row, 1, 1) label = Gtk.Label() label.set_alignment(0, 0.5) label.set_text(str(action_label)) label.set_tooltip_text(str(accel_path)) label.set_hexpand(True) grid.attach(label, 1, row, 1, 1) if self._SHOW_ACCEL_PATH: row += 1 label = Gtk.Label() label.set_alignment(0, 0.5) label.set_text(_("Path:")) grid.attach(label, 0, row, 1, 1) label = Gtk.Label() label.set_alignment(0, 0.5) label.set_text(str(accel_path)) label.set_hexpand(True) grid.attach(label, 1, row, 1, 1) row += 1 label = Gtk.Label() label.set_alignment(0, 0.5) label.set_text(_("Key:")) grid.attach(label, 0, row, 1, 1) label = Gtk.Label() label.set_alignment(0, 0.5) label.set_text(str(accel_label)) dialog.accel_label_widget = label label.set_hexpand(True) grid.attach(label, 1, row, 1, 1) row += 1 label = Gtk.Label() label.set_hexpand(True) label.set_vexpand(True) label.set_margin_top(12) label.set_margin_bottom(12) label.set_alignment(0, 0) label.set_line_wrap(True) label.set_size_request(200, 75) dialog.hint_widget = label self._edit_dialog_set_standard_hint(dialog) grid.attach(label, 0, row, 2, 1) evbox.add(grid) dialog.get_content_area().pack_start(evbox, True, True, 0) evbox.show_all() dialog.initial_accel_label = accel_label dialog.accel_path = accel_path dialog.result_keyval = None dialog.result_mods = None dialog.show()
def _edit_dialog_key_press_cb(self, dialog, event, editable): if event.type != Gdk.EventType.KEY_PRESS: return False if event.is_modifier: return False if self._USE_NORMAL_DIALOG_KEYS: if event.keyval == Gdk.KEY_Return: dialog.response(Gtk.ResponseType.OK) return True elif event.keyval == Gdk.KEY_Escape: dialog.response(Gtk.ResponseType.CANCEL) return True elif event.keyval == Gdk.KEY_BackSpace: dialog.response(Gtk.ResponseType.REJECT) return True # Stolen from GTK 2.24's gtk/gtkmenu.c (gtk_menu_key_press()) # Figure out what modifiers went into determining the key symbol keymap = Gdk.Keymap.get_default() bound, keyval, effective_group, level, consumed_modifiers = ( keymap.translate_keyboard_state( event.hardware_keycode, event.state, event.group, )) keyval = Gdk.keyval_to_lower(keyval) mods = Gdk.ModifierType(event.state & Gtk.accelerator_get_default_mod_mask() & ~consumed_modifiers) # If lowercasing affects the keysym, then we need to include # SHIFT in the modifiers. We re-upper case when we match against # the keyval, but display and save in caseless form. if keyval != event.keyval: mods |= Gdk.ModifierType.SHIFT_MASK accel_label = Gtk.accelerator_get_label(keyval, mods) # So we get (<Shift>j, Shift+J) but just (plus, +). As I # understand it. # This is rejecting some legit key combinations such as the # arrowkeys, so I had to remove it... # if not Gtk.accelerator_valid(keyval, mods) # return True clash_accel_path = None clash_action_label = None for path, kv, m, changed in self._get_accel_map_entries(): if (kv, m) == (keyval, mods): clash_accel_path = path clash_action_label = _udecode( self._action_labels.get( clash_accel_path, _(u"Unknown Action"), )) break if clash_accel_path == dialog.accel_path: # no change self._edit_dialog_set_standard_hint(dialog) label = str(accel_label) dialog.accel_label_widget.set_text(label) elif clash_accel_path: markup_tmpl = _(u"<b>{accel} is already in use for '{action}'. " u"The existing assignment will be replaced.</b>") markup = markup_tmpl.format( accel=lib.xml.escape(accel_label), action=lib.xml.escape(clash_action_label), ) self._edit_dialog_set_hint(dialog, markup) label = u"%s (replace)" % (accel_label, ) dialog.accel_label_widget.set_text(str(label)) else: self._edit_dialog_set_standard_hint(dialog) label = u"%s (changed)" % (accel_label, ) dialog.accel_label_widget.set_text(label) dialog.result_mods = mods dialog.result_keyval = keyval return True