示例#1
0
    def quit_cb(self, *junk):
        self.app.doc.model.sync_pending_changes()
        self.app.save_gui_config(
        )  # FIXME: should do this periodically, not only on quit

        ok_to_quit = self.app.filehandler.confirm_destructive_action(
            title=C_(
                "Quit confirm dialog: title",
                u"Really Quit?",
            ),
            confirm=C_(
                "Quit confirm dialog: continue button",
                u"_Quit",
            ),
        )
        if not ok_to_quit:
            return True

        self.app.doc.model.cleanup()
        self.app.profiler.cleanup()
        Gtk.main_quit()
        return False
 def tool_widget_properties(self):
     """Run the properties dialog"""
     if not self._dialog:
         # TRANSLATORS: properties dialog for the current brush group
         buttons = (Gtk.STOCK_CANCEL, Gtk.ResponseType.REJECT)
         dia = Gtk.Dialog(title=C_(
             "brush group properties dialog: title",
             u"Group \u201C{group_name}\u201D",
         ).format(group_name=self._group, ),
                          modal=True,
                          destroy_with_parent=True,
                          window_position=Gtk.WindowPosition.MOUSE,
                          buttons=buttons)
         btn = Gtk.Button(
             C_(
                 "brush group properties dialog: action buttons",
                 "Rename Group",
             ))
         btn.connect("clicked", self._rename_cb)
         dia.vbox.pack_start(btn, False, False, 0)
         btn = Gtk.Button(
             C_(
                 "brush group properties dialog: action buttons",
                 "Export as Zipped Brushset",
             ))
         btn.connect("clicked", self._export_cb)
         dia.vbox.pack_start(btn, False, False, 0)
         btn = Gtk.Button(
             C_(
                 "brush group properties dialog: action buttons",
                 "Delete Group",
             ))
         btn.connect("clicked", self._delete_cb)
         dia.vbox.pack_start(btn, False, False, 0)
         dia.vbox.show_all()
         self._dialog = dia
     self._dialog.set_transient_for(self.get_toplevel())
     self._dialog.run()
     self._dialog.hide()
示例#3
0
 def _set_name_entry_warning_flag(self, show_warning):
     entry = self.view.layer_name_entry
     pos = Gtk.EntryIconPosition.SECONDARY
     warning_showing = entry.get_icon_name(pos)
     if show_warning:
         if not warning_showing:
             entry.set_icon_from_icon_name(pos, "dialog-warning")
             text = entry.get_text()
             if text.strip() == u"":
                 msg = C_(
                     "layer properties dialog: name entry: icon tooltip",
                     u"Layer names cannot be empty.",
                 )
             else:
                 msg = C_(
                     "layer properties dialog: name entry: icon tooltip",
                     u"Layer name is not unique.",
                 )
             entry.set_icon_tooltip_text(pos, msg)
     elif warning_showing:
         entry.set_icon_from_icon_name(pos, None)
         entry.set_icon_tooltip_text(pos, None)
示例#4
0
 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)
示例#5
0
 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)
class HSVSaturationSlider(SliderColorAdjuster):
    STATIC_TOOLTIP_TEXT = C_(
        "color component slider: tooltip",
        u"HSV Saturation",
    )

    def get_color_for_bar_amount(self, amt):
        col = HSVColor(color=self.get_managed_color())
        col.s = amt
        return col

    def get_bar_amount_for_color(self, col):
        return col.s
示例#7
0
 def _update_brush_header(self, modified=False):
     """Updates the header strip with the current brush's icon and name"""
     mb = None
     if self.app:
         mb = self.app.brushmanager.selected_brush
     # Brush name label
     if mb:
         if mb.name:
             name = mb.name.replace("_", " ")
         else:
             name = C_(
                 "brush settings editor: header: fallback name",
                 "(Unnamed brush)",
             )
     else:
         name = "(Not running as part of MyPaint)"
     if modified:
         name = C_(
             "brush settings editor: header: is-modified hint",
             "{brush_name} [unsaved]",
         ).format(
             brush_name = name,
         )
     label = self._builder.get_object("brush_name_label")
     label.set_text(name)
     # Brush icon
     image = self._builder.get_object("brush_preview_image")
     w = image.get_allocated_width()
     h = image.get_allocated_height()
     if mb:
         pixbuf = mb.preview
     else:
         pixbuf = None
     if pixbuf:
         pixbuf = pixbuf.scale_simple(w, h, GdkPixbuf.InterpType.BILINEAR)
     if not pixbuf:
         pixbuf = GdkPixbuf.Pixbuf.new(GdkPixbuf.Colorspace.RGB,
                                       True, 8, w, h)
     image.set_from_pixbuf(pixbuf)
 def _switch_page_cb(self, notebook, page, page_num):
     tool_widget = page.get_child()
     has_properties = hasattr(tool_widget, "tool_widget_properties")
     self._properties_button.set_sensitive(has_properties)
     title = _tool_widget_get_title(tool_widget)
     close_tooltip = C_(
         "workspace: sidebar tabs: button tooltips",
         u"{tab_title}: close tab",
     ).format(tab_title=title)
     props_tooltip = C_(
         "workspace: sidebar tabs: button tooltips",
         u"{tab_title}: tab options and properties",
     ).format(tab_title=title)
     swap_tooltip = C_(
         "workspace: sidebar tabs: button tooltips",
         u"{tab_title}: move tab to other sidebar",
     ).format(tab_title=title)
     if not has_properties:
         props_tooltip = u""
     self._properties_button.set_tooltip_text(props_tooltip)
     self._close_button.set_tooltip_text(close_tooltip)
     self._sidebar_swap_button.set_tooltip_text(swap_tooltip)
 def _remove_cb(self, menuitem):
     bl = self._brushlist
     brush = self._brush
     msg = C_(
         "brush group: context menu: remove from group",
         u"Really remove brush “{brush_name}” "
         u"from group “{group_name}”?").format(
             brush_name=brush.name,
             group_name=bl.group,
         )
     if not dialogs.confirm(bl, msg):
         return
     bl.remove_brush(brush)
示例#10
0
 def __init__(self):
     super(BrushGroupsMenu, self).__init__()
     from gui.application import get_app
     self.app = get_app()
     # Static items
     item = Gtk.SeparatorMenuItem()
     self.append(item)
     item = Gtk.MenuItem(label=C_("brush groups menu", u"New Group…"))
     item.connect("activate", self._new_brush_group_cb)
     self.append(item)
     item = Gtk.MenuItem(label=C_("brush groups menu", u"Import Brushes…"))
     item.connect("activate", self.app.drawWindow.import_brush_pack_cb)
     self.append(item)
     item = Gtk.MenuItem(
         label=C_("brush groups menu", u"Get More Brushes…"))
     item.connect("activate", self.app.drawWindow.download_brush_pack_cb)
     self.append(item)
     # Dynamic items
     bm = self.app.brushmanager
     self._items = {}
     self._update(bm)
     bm.groups_changed += self._update
示例#11
0
 def _new_brush_group_cb(self, widget):
     # XXX should be moved somewhere more sensible than this
     toplevel = self.app.drawWindow
     name = dialogs.ask_for_name(
         toplevel,
         C_("new brush group dialog: title", 'Create Group'),
         '',
     )
     if name is None:
         return
     name = name.strip()
     if name:
         bm = self.app.brushmanager
         bm.create_group(name)
示例#12
0
class RGBBlueSlider(SliderColorAdjuster):
    STATIC_TOOLTIP_TEXT = C_("color component slider: tooltip", "RGB Blue")

    def get_background_validity(self):
        col = self.get_managed_color()
        r, g, b = col.get_rgb()
        return r, g

    def get_color_for_bar_amount(self, amt):
        col = RGBColor(color=self.get_managed_color())
        col.b = amt
        return col

    def get_bar_amount_for_color(self, col):
        return col.b
示例#13
0
 def _clone_cb(self, menuitem):
     bl = self._brushlist
     brush = self._brush
     # Pick a nice unique name
     new_name = C_(
         "brush group: context menu: unique names for cloned brushes",
         u"{original_name} copy").format(original_name=brush.name, )
     uniquifier = 0
     while bl.bm.get_brush_by_name(new_name):
         uniquifier += 1
         new_name = C_(
             "brush group: context menu: unique names for cloned brushes",
             u"{original_name} copy {n}").format(
                 name=brush.name,
                 n=uniquifier,
             )
     # Make a copy and insert it near the original
     brush_copy = brush.clone(new_name)
     index = bl.brushes.index(brush) + 1
     bl.insert_brush(index, brush_copy)
     brush_copy.save()
     bl.bm.save_brushorder()
     # Select the copy, for highlighting
     bl.bm.select_brush(brush_copy)
示例#14
0
 def _query_tooltip_cb(self, da, x, y, keyboard_mode, tooltip):
     s = self._TOOLTIP_ICON_SIZE
     scaled_pixbuf = self._get_scaled_pixbuf(s)
     tooltip.set_icon(scaled_pixbuf)
     brush_name = self._brush_name
     if not brush_name:
         brush_name = self._DEFAULT_BRUSH_DISPLAY_NAME
         # Rare cases, see https://github.com/mypaint/mypaint/issues/402.
         # Probably just after init.
     template_params = {"brush_name": lib.xml.escape(brush_name)}
     markup_template = C_(
         "current brush indicator: tooltip (no-description case)",
         u"<b>{brush_name}</b>",
     )
     if self._brush_desc:
         markup_template = C_(
             "current brush indicator: tooltip (description case)",
             u"<b>{brush_name}</b>\n{brush_desc}",
         )
         template_params["brush_desc"] = lib.xml.escape(self._brush_desc)
     markup = markup_template.format(**template_params)
     tooltip.set_markup(markup)
     # TODO: summarize changes?
     return True
示例#15
0
 def save_button_clicked_cb(self, button):
     """Save the current brush settings (overwrites)"""
     bm = self.app.brushmanager
     b = bm.selected_brush
     if not b.name:
         msg = C_(
             'brush settings editor: save brush: error message',
             'No brush selected, please use “Add As New” instead.',
         )
         dialogs.error(self, msg)
         return
     b.brushinfo = self.app.brush.clone()
     b.save()
     self._mark_all_settings_unmodified_in_treeview()
     self._update_brush_header(modified=False)
示例#16
0
class CIECAMChromaSlider (SliderColorAdjuster):
    STATIC_TOOLTIP_TEXT = C_("color component slider: tooltip",
                             "CIECAM Colorfulness/Chroma/Saturation")
    draw_background = True

    @property
    def samples(self):
        alloc = self.get_allocation()
        len = self.vertical and alloc.height or alloc.width
        len -= self.BORDER_WIDTH * 2
        return min(int(len // 3), 16)

    def get_color_for_bar_amount(self, amt):
        col = self._get_app_brush_color()
        col.s = max(0.0, amt) * 120
        col.gamutmapping = "highlightC"
        col.cachedrgb = None
        return col

    def get_bar_amount_for_color(self, col):
        col = self._get_app_brush_color()
        if col.limit_purity is not None:
            return min(col.s, col.limit_purity) / 120
        else:
            return max(0.0, col.s) / 120

    def get_background_validity(self):
        from gui.application import get_app
        app = get_app()
        cm = self.get_color_manager()
        prefs = cm.get_prefs()
        try:
            if app.brush.get_setting('cie_v') == '':
                return True
            limit_purity = prefs['color.limit_purity']
            vsh = (
                int(app.brush.get_setting('cie_v') * 100),
                int(app.brush.get_setting('cie_s') * 100),
                int(app.brush.get_setting('cie_h') * 100))

            cieaxes = app.brush.get_setting('cieaxes'),
            lightsource = (
                app.brush.get_setting('lightsource_X'),
                app.brush.get_setting('lightsource_Y'),
                app.brush.get_setting('lightsource_Z'))
        except KeyError:
            return True
        return vsh, cieaxes, lightsource, limit_purity
示例#17
0
    def import_layers_cb(self, action):
        """Action callback: import layers from multiple files."""
        dialog = Gtk.FileChooserDialog(title=C_(
            u'Layers→Import Layers: files-chooser dialog: title',
            u"Import Layers",
        ),
                                       parent=self.app.drawWindow,
                                       action=Gtk.FileChooserAction.OPEN,
                                       buttons=[
                                           Gtk.STOCK_CANCEL,
                                           Gtk.ResponseType.CANCEL,
                                           Gtk.STOCK_OPEN,
                                           Gtk.ResponseType.OK,
                                       ])
        dialog.set_default_response(Gtk.ResponseType.OK)

        dialog.set_select_multiple(True)

        # TODO: decide how well the preview plays with multiple-select.
        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)

        # 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

        filenames = []
        try:
            if dialog.run() == Gtk.ResponseType.OK:
                dialog.hide()
                filenames = dialog.get_filenames()
        finally:
            dialog.destroy()

        if filenames:
            filenames = [f.decode('utf-8') for f in filenames]
            self.import_layers(filenames)
示例#18
0
 def __load_clicked(self, button):
     preview = HCYMaskPreview()
     preview.set_size_request(128, 128)
     target_mgr = self.target.get_color_manager()
     prefs_ro = deepcopy(target_mgr.get_prefs())
     datapath = target_mgr.get_data_path()
     mgr = ColorManager(prefs=prefs_ro, datapath=datapath)
     preview.set_color_manager(mgr)
     preview.set_managed_color(self.editor.get_managed_color())
     dialog_title = C_(
         "HCY Gamut Mask load dialog: window title",
         u"Load Mask from a GIMP Palette",
     )
     pal = palette_load_via_dialog(title=dialog_title, parent=self,
                                   preview=preview)
     if pal is None:
         return
     self.editor.set_mask_from_palette(pal)
 def __init__(self):
     app = None
     if __name__ != '__main__':
         from gui.application import get_app
         app = get_app()
         self._brush = app.brush
         bm = app.brushmanager
         bm.brush_selected += self.brush_selected_cb
     else:
         self._brush = lib.brush.BrushInfo()
         self._brush.load_defaults()
     SubWindow.__init__(self, app, key_input=True)
     # Tracking vars for updating the treestore in response to
     # brush setting changes and loading new brushes.
     self._treestore = None
     self._setting_treepath = {}  # {cname: Gtk.TreePath}, path for setting
     self._group_treepath = {}  # {groupid: Gtk.TreePath}, path for group
     self._setting_group = {}  # {cname: groupid}, group containing setting
     # Adjusters: may be shared with those of the app
     self._base_adj = {}  #: setting cname => base value adj
     self._input_y_adj = {}  #: input name => scale y range (+-) adj
     self._input_xmin_adj = {}  #: input name => scale x min adj
     self._input_xmax_adj = {}  #: input name => scale x min adj
     self._disable_input_adj_changed_cb = False
     self._init_adjustments()
     self.set_title(
         C_(
             "brush settings editor: subwindow title",
             "Brush Settings Editor",
         ))
     self._scales = []
     self._setting = None
     self._builder = Gtk.Builder()
     self._builder.set_translation_domain("mypaint")
     self._build_ui()
     self._base_value_scale = self._builder.get_object("base_value_scale")
     self.connect_after("show", self._post_show_cb)
     self.connect('button-press-event', self._clear_focus)
     editor = self._builder.get_object("brush_editor")
     self.add(editor)
     self._brush.observers.append(self.brush_modified_cb)
     self._live_update_idle_cb_id = None
     self._updating_metadata_ui = False
     self.set_default_size(1000, 800)
示例#20
0
    def __init__(self, root_stack):
        super(FlatLayerList, self).__init__()

        root_stack.layer_properties_changed += self._layer_props_changed_cb
        root_stack.layer_inserted += self._layer_inserted_cb
        root_stack.layer_deleted += self._layer_deleted_cb

        self.root = root_stack
        # Column data : name, layer_path, layer
        self.set_column_types((str, object, object))
        default_selection = C_(
            "fill option: default option in the Source Layer dropdown",
            u"Selected Layer")
        # Add default option and separator
        self.append((default_selection, None, None))
        self.append((None, None, None))
        # Flatten layer tree into rows
        for layer in root_stack:
            self._initalize(layer)
示例#21
0
 def _rename_button_clicked_cb(self, button):
     old_name = self._lvm.current_view_name
     if old_name is None:
         return
     new_name = gui.dialogs.ask_for_name(
         title=C_(
             "view controls: rename view dialog",
             u"Rename View",
         ),
         widget=self._app.drawWindow,
         default=old_name,
     )
     if new_name is None:
         return
     new_name = new_name.strip()
     if new_name == old_name:
         return
     doc = self._docmodel
     cmd = lib.layervis.RenameActiveLayerView(doc, new_name)
     doc.do(cmd)
示例#22
0
 def render_language_names(_, name_cell, model, it):
     locale, lang_en, lang_nat = model[it][:3]
     # Mark default with bold font
     if locale is None:
         name_cell.set_property("markup",
                                "<b>{lang_en}</b>".format(lang_en=lang_en))
     # If a language does not have its native spelling
     # available, only show its name in english.
     elif lang_en == lang_nat or lang_nat == "":
         name_cell.set_property("text", lang_en)
     else:
         name_cell.set_property(
             "text",
             C_(
                 "Prefs Dialog|View|Interface - menu entries",
                 # TRANSLATORS: lang_en is the english name of the language
                 # TRANSLATORS: lang_nat is the native name of the language
                 # TRANSLATORS: in that _same language_.
                 # TRANSLATORS: This can just be copied most of the time.
                 "{lang_en} - ({lang_nat})").format(lang_en=lang_en,
                                                    lang_nat=lang_nat))
示例#23
0
class HCYLumaSlider (SliderColorAdjuster):
    STATIC_TOOLTIP_TEXT = C_("color component slider: tooltip", "HCY Luma (Y')")

    @property
    def samples(self):
        alloc = self.get_allocation()
        len = self.vertical and alloc.height or alloc.width
        len -= self.BORDER_WIDTH * 2
        return min(int(len / 3), 64)

    def get_color_for_bar_amount(self, amt):
        col = HCYColor(color=self.get_managed_color())
        col.y = amt
        return col

    def get_bar_amount_for_color(self, col):
        col = HCYColor(color=col)
        return col.y

    def get_background_validity(self):
        col = HCYColor(color=self.get_managed_color())
        return int(col.h * 1000), int(col.c * 1000)
示例#24
0
 def __save_clicked(self, button):
     pal = Palette()
     mask = self.editor.get_mask()
     for i, shape in enumerate(mask):
         for j, col in enumerate(shape):
             col_name = "mask#%d primary#%d" % (i, j)  # NOT localised
             pal.append(col, col_name)
     preview = HCYMaskPreview()
     preview.set_size_request(128, 128)
     target_mgr = self.target.get_color_manager()
     prefs_ro = deepcopy(target_mgr.get_prefs())
     datapath = target_mgr.get_data_path()
     mgr = ColorManager(prefs=prefs_ro, datapath=datapath)
     preview.set_color_manager(mgr)
     preview.set_managed_color(self.editor.get_managed_color())
     palette_save_via_dialog(
         pal,
         title=C_("HCY Gamut Mask load dialog: window title",
                  u"Save Mask as a GIMP Palette"),
         parent=self,
         preview=preview,
     )
示例#25
0
    def init_view(self):
        self._init_model()
        store = Gtk.ListStore(str, str)  # columns: <our_id, display_markup>
        markup = C_(
            "view controls: dropdown: item markup",
            u"<i>{builtin_view_name}</i>",
        ).format(builtin_view_name=escape(
            lib.layervis.UNSAVED_VIEW_DISPLAY_NAME), )
        # None has a special meaning for GTK combo ID columns,
        # so we substitute the empty string. Corrolory: you can't name
        # views to the empty string.
        store.append([u"", markup])
        store.set_sort_column_id(0, Gtk.SortType.ASCENDING)
        self._store = store

        combo = self.view.current_view_combo
        combo.set_model(store)
        combo.set_id_column(0)

        cell = self.view.layer_text_cell
        combo.add_attribute(cell, "markup", 1)

        self._refresh_ui()
示例#26
0
文件: meta.py 项目: eprotiva/mypaint
import os
import platform

from gi.repository import Gtk
from gi.repository import GdkPixbuf
from gi.repository import GLib
import cairo

from lib.gettext import C_
import lib.meta
from lib.xml import escape

## Program-related string constants

COPYRIGHT_STRING = C_(
    "About dialog: copyright statement", u"Copyright (C) 2005-2016\n"
    u"Martin Renold and the MyPaint Development Team")
WEBSITE_URI = "http://mypaint.org"
LICENSE_SUMMARY = C_(
    "About dialog: license summary",
    u"This program is free software; you can redistribute it and/or modify "
    u"it under the terms of the GNU General Public License as published by "
    u"the Free Software Foundation; either version 2 of the License, or "
    u"(at your option) any later version.\n"
    u"\n"
    u"This program is distributed in the hope that it will be useful, "
    u"but WITHOUT ANY WARRANTY. See the COPYING file for more details.")

## Credits-related string constants

# Strings for specific tasks, all translated
示例#27
0
    def import_brushpack(self, path, window):
        """Import a brushpack from a zipfile, with confirmation dialogs.

        :param path: Brush pack zipfile path
        :type path: str
        :param window: Parent window, for dialogs to set.
        :type window: GtkWindow
        :returns: Set of imported group names
        :rtype: set

        """

        with zipfile.ZipFile(path) as zf:
            names = zf.namelist()
            # zipfile does utf-8 decoding on its own; this is just to make
            # sure we have only unicode objects as brush names.
            names = [s.decode('utf-8') for s in names]

            readme = None
            if _BRUSHPACK_README in names:
                readme = zf.read(_BRUSHPACK_README)

            if _BRUSHPACK_ORDERCONF not in names:
                raise InvalidBrushpack(
                    C_(
                        "brushpack import failure messages",
                        u"No file named “{order_conf_file}”. "
                        u"This is not a brushpack.").format(
                            order_conf_file=_BRUSHPACK_ORDERCONF, ))
            groups = _parse_order_conf(zf.read(_BRUSHPACK_ORDERCONF))

            new_brushes = []
            for brushes in groups.itervalues():
                for brush in brushes:
                    if brush not in new_brushes:
                        new_brushes.append(brush)
            logger.info(
                "%d different brushes found in %r of brushpack",
                len(new_brushes),
                _BRUSHPACK_ORDERCONF,
            )

            # Validate file content. The names in order.conf and the
            # brushes found in the zip must match. This should catch
            # encoding screwups, everything should be a unicode object.
            for brush in new_brushes:
                if brush + '.myb' not in names:
                    raise InvalidBrushpack(
                        C_(
                            "brushpack import failure messages",
                            u"Brush “{brush_name}” is "
                            u"listed in “{order_conf_file}”, "
                            u"but it does not exist in the zipfile.").format(
                                brush_name=brush,
                                order_conf_file=_BRUSHPACK_ORDERCONF,
                            ))
            for name in names:
                if name.endswith('.myb'):
                    brush = name[:-4]
                    if brush not in new_brushes:
                        raise InvalidBrushpack(
                            C_(
                                "brushpack import failure messages",
                                u"Brush “{brush_name}” exists in the zipfile, "
                                u"but it is not listed in “{order_conf_file}”."
                            ).format(
                                brush_name=brush,
                                order_conf_file=_BRUSHPACK_ORDERCONF,
                            ))
            if readme:
                answer = dialogs.confirm_brushpack_import(
                    basename(path),
                    window,
                    readme,
                )
                if answer == Gtk.ResponseType.REJECT:
                    return set()

            do_overwrite = False
            do_ask = True
            renamed_brushes = {}
            imported_groups = set()
            for groupname, brushes in groups.iteritems():
                managed_brushes = self.get_group_brushes(groupname)
                if managed_brushes:
                    answer = dialogs.confirm_rewrite_group(
                        window, translate_group_name(groupname),
                        translate_group_name(DELETED_BRUSH_GROUP))
                    if answer == dialogs.CANCEL:
                        return set()
                    elif answer == dialogs.OVERWRITE_THIS:
                        self.delete_group(groupname)
                    elif answer == dialogs.DONT_OVERWRITE_THIS:
                        i = 0
                        old_groupname = groupname
                        while groupname in self.groups:
                            i += 1
                            groupname = old_groupname + '#%d' % i
                    managed_brushes = self.get_group_brushes(groupname)
                imported_groups.add(groupname)

                for brushname in brushes:
                    # extract the brush from the zip
                    assert (brushname + '.myb') in zf.namelist()
                    # Support for utf-8 ZIP filenames that don't have
                    # the utf-8 bit set.
                    brushname_utf8 = brushname.encode('utf-8')
                    try:
                        myb_data = zf.read(brushname + '.myb')
                    except KeyError:
                        myb_data = zf.read(brushname_utf8 + '.myb')
                    try:
                        preview_data = zf.read(brushname + '_prev.png')
                    except KeyError:
                        preview_data = zf.read(brushname_utf8 + '_prev.png')
                    # in case we have imported that brush already in a
                    # previous group, but decided to rename it
                    if brushname in renamed_brushes:
                        brushname = renamed_brushes[brushname]
                    # possibly ask how to import the brush file
                    # (if we didn't already)
                    b = self.get_brush_by_name(brushname)
                    if brushname in new_brushes:
                        new_brushes.remove(brushname)
                        if b:
                            existing_preview_pixbuf = b.preview
                            if do_ask:
                                answer = dialogs.confirm_rewrite_brush(
                                    window,
                                    brushname,
                                    existing_preview_pixbuf,
                                    preview_data,
                                )
                                if answer == dialogs.CANCEL:
                                    break
                                elif answer == dialogs.OVERWRITE_ALL:
                                    do_overwrite = True
                                    do_ask = False
                                elif answer == dialogs.OVERWRITE_THIS:
                                    do_overwrite = True
                                    do_ask = True
                                elif answer == dialogs.DONT_OVERWRITE_THIS:
                                    do_overwrite = False
                                    do_ask = True
                                elif answer == dialogs.DONT_OVERWRITE_ANYTHING:
                                    do_overwrite = False
                                    do_ask = False
                            # find a new name (if requested)
                            brushname_old = brushname
                            i = 0
                            while not do_overwrite and b:
                                i += 1
                                brushname = brushname_old + '#%d' % i
                                renamed_brushes[brushname_old] = brushname
                                b = self.get_brush_by_name(brushname)

                        if not b:
                            b = ManagedBrush(self, brushname)

                        # write to disk and reload brush (if overwritten)
                        prefix = b._get_fileprefix(saving=True)
                        with open(prefix + '.myb', 'w') as myb_f:
                            myb_f.write(myb_data)
                        with open(prefix + '_prev.png', 'wb') as preview_f:
                            preview_f.write(preview_data)
                        b.load()
                    # finally, add it to the group
                    if b not in managed_brushes:
                        managed_brushes.append(b)
                    self.brushes_changed(managed_brushes)

        if DELETED_BRUSH_GROUP in self.groups:
            # remove deleted brushes that are in some group again
            self.delete_group(DELETED_BRUSH_GROUP)
        return imported_groups
示例#28
0
文件: device.py 项目: yazici/mypaint
    def __init__(self, monitor=None):
        """Initialize

        :param Monitor monitor: monitor instance (for testing)

        By default, the central app's `device_monitor` is used to permit
        parameterless construction.
        """
        super(SettingsEditor, self).__init__()
        if monitor is None:
            from gui.application import get_app
            app = get_app()
            monitor = app.device_monitor
        self._monitor = monitor

        self._devices_store = Gtk.ListStore(object)
        self._devices_view = Gtk.TreeView(self._devices_store)

        # TRANSLATORS: Column's data is the device's name
        col = Gtk.TreeViewColumn(
            C_(
                "prefs: devices table: column header",
                "Device",
            ))
        col.set_min_width(200)
        col.set_expand(True)
        col.set_sizing(Gtk.TreeViewColumnSizing.AUTOSIZE)
        self._devices_view.append_column(col)
        cell = Gtk.CellRendererText()
        cell.set_property("ellipsize", Pango.EllipsizeMode.MIDDLE)
        col.pack_start(cell, True)
        col.set_cell_data_func(cell, self._device_name_datafunc)

        # TRANSLATORS: Column's data is an integer count of the number of axes
        col = Gtk.TreeViewColumn(
            C_(
                "prefs: devices table: column header",
                "Axes",
            ))
        col.set_min_width(30)
        col.set_resizable(True)
        col.set_expand(False)
        col.set_sizing(Gtk.TreeViewColumnSizing.AUTOSIZE)
        self._devices_view.append_column(col)
        cell = Gtk.CellRendererText()
        col.pack_start(cell, True)
        col.set_cell_data_func(cell, self._device_axes_datafunc)

        # TRANSLATORS: Column shows type labels ("Touchscreen", "Pen" etc.)
        col = Gtk.TreeViewColumn(
            C_(
                "prefs: devices table: column header",
                "Type",
            ))
        col.set_min_width(120)
        col.set_resizable(True)
        col.set_expand(False)
        col.set_sizing(Gtk.TreeViewColumnSizing.AUTOSIZE)
        self._devices_view.append_column(col)
        cell = Gtk.CellRendererText()
        cell.set_property("ellipsize", Pango.EllipsizeMode.END)
        col.pack_start(cell, True)
        col.set_cell_data_func(cell, self._device_type_datafunc)

        # Usage config value => string store (dropdowns)
        store = Gtk.ListStore(str, str)
        for conf_val in AllowedUsage.VALUES:
            string = AllowedUsage.DISPLAY_STRING[conf_val]
            store.append([conf_val, string])
        self._usage_store = store

        # TRANSLATORS: Column's data is a dropdown allowing the allowed
        # TRANSLATORS: tasks for the row's device to be configured.
        col = Gtk.TreeViewColumn(
            C_(
                "prefs: devices table: column header",
                "Use for...",
            ))
        col.set_min_width(100)
        col.set_resizable(True)
        col.set_expand(False)
        self._devices_view.append_column(col)

        cell = Gtk.CellRendererCombo()
        cell.set_property("model", self._usage_store)
        cell.set_property("text-column", self._USAGE_STRING_COL)
        cell.set_property("mode", Gtk.CellRendererMode.EDITABLE)
        cell.set_property("editable", True)
        cell.set_property("has-entry", False)
        cell.set_property("ellipsize", Pango.EllipsizeMode.END)
        cell.connect("changed", self._usage_cell_changed_cb)
        col.pack_start(cell, True)
        col.set_cell_data_func(cell, self._device_usage_datafunc)

        # Scroll action config value => string store (dropdowns)
        store = Gtk.ListStore(str, str)
        for conf_val in ScrollAction.VALUES:
            string = ScrollAction.DISPLAY_STRING[conf_val]
            store.append([conf_val, string])
        self._scroll_store = store

        # TRANSLATORS: Column's data is a dropdown for how the device's
        # TRANSLATORS: scroll wheel or scroll-gesture events are to be
        # TRANSLATORS: interpreted normally.
        col = Gtk.TreeViewColumn(
            C_(
                "prefs: devices table: column header",
                "Scroll...",
            ))
        col.set_min_width(100)
        col.set_resizable(True)
        col.set_expand(False)
        self._devices_view.append_column(col)

        cell = Gtk.CellRendererCombo()
        cell.set_property("model", self._scroll_store)
        cell.set_property("text-column", self._USAGE_STRING_COL)
        cell.set_property("mode", Gtk.CellRendererMode.EDITABLE)
        cell.set_property("editable", True)
        cell.set_property("has-entry", False)
        cell.set_property("ellipsize", Pango.EllipsizeMode.END)
        cell.connect("changed", self._scroll_cell_changed_cb)
        col.pack_start(cell, True)
        col.set_cell_data_func(cell, self._device_scroll_datafunc)

        # Pretty borders
        view_scroll = Gtk.ScrolledWindow()
        view_scroll.set_shadow_type(Gtk.ShadowType.ETCHED_IN)
        pol = Gtk.PolicyType.AUTOMATIC
        view_scroll.set_policy(pol, pol)
        view_scroll.add(self._devices_view)
        view_scroll.set_hexpand(True)
        view_scroll.set_vexpand(True)
        self.attach(view_scroll, 0, 0, 1, 1)

        self._update_devices_store()
        self._monitor.devices_updated += self._update_devices_store
示例#29
0
文件: device.py 项目: yazici/mypaint
# The per-device settings are stored in the prefs in a sub-dict whose
# string keys are formed from the device name and enough extra
# information to (hopefully) identify the device uniquely. Names are not
# unique, and IDs vary according to the order in which you plug devices
# in. So for now, our unique strings use a combination of the device's
# name, its source as presented by GDK, and the number of axes.

_PREFS_ROOT = "input.devices"
_PREFS_DEVICE_SUBKEY_FMT = "{name}:{source}:{num_axes}"

## Device type strings

_DEVICE_TYPE_STRING = {
    Gdk.InputSource.CURSOR: C_(
        "prefs: device's type label",
        "Cursor/puck",
    ),
    Gdk.InputSource.ERASER: C_(
        "prefs: device's type label",
        "Eraser",
    ),
    Gdk.InputSource.KEYBOARD: C_(
        "prefs: device's type label",
        "Keyboard",
    ),
    Gdk.InputSource.MOUSE: C_(
        "prefs: device's type label",
        "Mouse",
    ),
    Gdk.InputSource.PEN: C_(
        "prefs: device's type label",
示例#30
0
    def rename_button_clicked_cb(self, button):
        """Rename the current brush; user is prompted for a new name"""
        bm = self.app.brushmanager
        src_brush = bm.selected_brush
        if not src_brush.name:
            dialogs.error(
                self,
                C_(
                    'brush settings editor: rename brush: error message',
                    'No brush selected!',
                ))
            return

        src_name_pp = src_brush.name.replace('_', ' ')
        dst_name = dialogs.ask_for_name(
            self,
            C_(
                "brush settings editor: rename brush: dialog title",
                "Rename Brush",
            ),
            src_name_pp,
        )
        if not dst_name:
            return
        dst_name = dst_name.replace(' ', '_')
        # ensure we don't overwrite an existing brush by accident
        dst_deleted = None
        for group, brushes in bm.groups.iteritems():
            for b2 in brushes:
                if b2.name == dst_name:
                    if group == brushmanager.DELETED_BRUSH_GROUP:
                        dst_deleted = b2
                    else:
                        msg = C_(
                            'brush settings editor: '
                            'rename brush: error message',
                            'A brush with this name already exists!',
                        )
                        dialogs.error(self, msg)
                        return

        logger.info("Renaming brush %r -> %r", src_brush.name, dst_name)
        if dst_deleted:
            deleted_group = brushmanager.DELETED_BRUSH_GROUP
            deleted_brushes = bm.get_group_brushes(deleted_group)
            deleted_brushes.remove(dst_deleted)
            bm.brushes_changed(deleted_brushes)

        # save src as dst
        src_name = src_brush.name
        src_brush.name = dst_name
        src_brush.save()
        src_brush.name = src_name
        # load dst
        dst_brush = brushmanager.ManagedBrush(bm, dst_name, persistent=True)
        dst_brush.load()

        # Replace src with dst, but keep src in the deleted list if it
        # is a stock brush
        self._delete_brush(src_brush, replacement=dst_brush)

        bm.select_brush(dst_brush)