Example #1
0
 def __init__(self, filename):
     self._filename = filename
     builder = Gtk.Builder()
     builder.set_translation_domain(self._TRANSLATION_DOMAIN)
     builder.add_from_file(filename)
     self._builder = builder
     self._cache = {}
def _test():
    win = Gtk.Window()
    win.set_title("accelmap.py")
    win.connect("destroy", Gtk.main_quit)
    builder = Gtk.Builder()
    import gui.factoryaction  # noqa F401: for side effects only
    builder.add_from_file("gui/resources.xml")
    uimgr = builder.get_object("app_ui_manager")
    editor = AccelMapEditor()
    editor.ui_manager = uimgr
    win.add(editor)
    win.set_default_size(400, 300)
    win.show_all()
    Gtk.main()
Example #3
0
 def __init__(self, app, **kwargs):
     """Initialize for the main app and its working doc."""
     super(Presenter, self).__init__(**kwargs)
     self._app = weakref.proxy(app)
     builder_xml = os.path.splitext(__file__)[0] + ".glade"
     builder = Gtk.Builder()
     builder.set_translation_domain("mypaint")
     builder.add_from_file(builder_xml)
     self._dialog = builder.get_object("recovery_dialog")
     self._treeview = builder.get_object("recovery_treeview")
     self._liststore = builder.get_object("recovery_liststore")
     self._recover_button = builder.get_object("recover_autosave_button")
     self._delete_button = builder.get_object("delete_autosave_button")
     at_start_checkbutton = builder.get_object("at_startup_checkbutton")
     at_start_checkbutton.set_active(self.check_at_startup)
     builder.connect_signals(self)
 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)
Example #5
0
def _test():
    """Interactive module test function"""
    import os
    import sys
    vbox = Gtk.VBox()
    builder = Gtk.Builder()

    # Handlers can find out about their template values by parsing their
    # name (using the GtkBuildable interface). Alternatively, you can set
    # up private attributes in the instantiation loop.

    def _test_button_clicked_cb(widget):
        id_ = Gtk.Buildable.get_name(widget)
        if isinstance(id_, bytes):
            id_ = id_.decode("utf-8")
        print("Clicked: id=%r" % (id_, ))
        print("          i=%r" % (widget._i, ))

    # Unicode is supported in IDs and template values.
    # The XML template may be plain ASCII since escape() is used when
    # filling it.
    object_ids = [u"button_{id}"]
    words = [u"à", u"chacun", u"son", u"goût"]
    for i in words:
        params = {"id": i, "label": i.upper()}
        objs = add_objects_from_template_string(builder, _TEST_TEMPLATE,
                                                object_ids, params)
        for w in objs:
            w.connect("clicked", _test_button_clicked_cb)
            vbox.pack_start(w, True, True, 0)
            w._i = i
    # The label should never be instantiated by this code. In fact, only
    # the four buttons should.
    for obj in builder.get_objects():
        assert isinstance(obj, Gtk.Button)
    # Remainder of the demo code
    window = Gtk.Window()
    window.add(vbox)
    window.set_title(os.path.basename(sys.argv[0]))
    window.connect("destroy", lambda *a: Gtk.main_quit())
    window.set_size_request(250, 200)
    window.show_all()
    Gtk.main()
    def __init__(self):
        import gui.application
        app = gui.application.get_app()
        assert app is not None

        super(PreferencesWindow, self).__init__(
            app=app,
            title=_('Preferences'),
            transient_for=app.drawWindow,
            destroy_with_parent=True,
        )
        self.add_buttons(
            Gtk.STOCK_REVERT_TO_SAVED, RESPONSE_REVERT,
            Gtk.STOCK_OK, Gtk.ResponseType.ACCEPT,
        )

        self.connect('response', self.on_response)

        self.in_update_ui = False

        # Set up widgets
        builder = Gtk.Builder()
        builder.set_translation_domain("mypaint")
        ui_dir = os.path.dirname(os.path.abspath(__file__))
        xml_path = os.path.join(ui_dir, 'preferenceswindow.glade')
        builder.add_from_file(xml_path)
        self._builder = builder

        getobj = builder.get_object
        self.compat_preferences = CompatibilityPreferences(app, builder)

        # Populate locale/language combo box
        locale_combo = getobj("locale_combobox")
        setup_locale_combobox(locale_combo)

        # Notebook
        nb = getobj("prefs_notebook")
        self.nb = nb
        self.vbox.pack_start(nb, True, True, 0)

        # Curve init
        curve = getobj("mapping_curve")
        curve.changed_cb = self.pressure_curve_changed_cb
        curve.magnetic = False
        self._pressure_curve = curve

        # Button mappings editor
        assert "input.button_mapping" in app.preferences
        reg = gui.mode.ModeRegistry
        actions_possible = [n for n in reg.get_action_names()
                            if issubclass(reg.get_mode_class(n),
                                          gui.mode.DragMode)]
        actions_possible += gui.mode.BUTTON_BINDING_ACTIONS
        bm_ed = getobj("button_mapping_editor")
        bm_ed.set_bindings(app.preferences["input.button_mapping"])
        bm_ed.set_actions(actions_possible)
        bm_ed.bindings_observers.append(self.button_mapping_edited_cb)

        # Autosave controls
        autosave_interval_spinbut = getobj("autosave_interval_spinbutton")
        self._autosave_interval_spinbutton = autosave_interval_spinbut

        # Signal hookup now everything is in the right initial state
        self._builder.connect_signals(self)
Example #7
0
    def __init__(self):
        import gui.application
        app = gui.application.get_app()
        assert app is not None

        super(PreferencesWindow, self).__init__(
            app=app,
            title=_('Preferences'),
            transient_for=app.drawWindow,
            destroy_with_parent=True,
        )
        self.add_buttons(
            Gtk.STOCK_REVERT_TO_SAVED,
            RESPONSE_REVERT,
            Gtk.STOCK_OK,
            Gtk.ResponseType.ACCEPT,
        )

        self.connect('response', self.on_response)

        self.in_update_ui = False

        # Set up widgets
        builder = Gtk.Builder()
        builder.set_translation_domain("mypaint")
        ui_dir = os.path.dirname(os.path.abspath(__file__))
        xml_path = os.path.join(ui_dir, 'preferenceswindow.glade')
        builder.add_from_file(xml_path)
        self._builder = builder

        getobj = builder.get_object
        self.compat_preferences = CompatibilityPreferences(app, builder)

        # Populate locale/language combo box
        locale_combo = getobj("locale_combobox")
        setup_locale_combobox(locale_combo)

        # Notebook
        nb = getobj("prefs_notebook")
        self.nb = nb
        self.vbox.pack_start(nb, True, True, 0)

        # Curve init
        curve = getobj("mapping_curve")
        curve.changed_cb = self.pressure_curve_changed_cb
        curve.magnetic = False
        self._pressure_curve = curve

        # Button mappings editor
        assert "input.button_mapping" in app.preferences
        reg = gui.mode.ModeRegistry
        actions_possible = [
            n for n in reg.get_action_names()
            if issubclass(reg.get_mode_class(n), gui.mode.DragMode)
        ]
        actions_possible += gui.mode.BUTTON_BINDING_ACTIONS
        bm_ed = getobj("button_mapping_editor")
        bm_ed.set_bindings(app.preferences["input.button_mapping"])
        bm_ed.set_actions(actions_possible)
        bm_ed.bindings_observers.append(self.button_mapping_edited_cb)

        # Autosave controls
        autosave_interval_spinbut = getobj("autosave_interval_spinbutton")
        self._autosave_interval_spinbutton = autosave_interval_spinbut

        # Dynamic brush cursor crosshair settings
        p = app.preferences
        dyn_ch_checkbut = getobj("show_crosshair_checkbutton")
        dyn_ch_enabled = p.get("cursor.dynamic_crosshair", False)
        dyn_ch_checkbut.set_active(dyn_ch_enabled)
        self._dynamic_crosshair_checkbut = dyn_ch_checkbut

        dyn_ch_spinner = getobj("dynamic_crosshair_threshold_spinbutton")
        dyn_ch_threshold = p.get("cursor.dynamic_crosshair_threshold", 8)

        max_cursor = max(Gdk.Display.get_default().get_maximal_cursor_size())
        adj = Gtk.Adjustment(value=dyn_ch_threshold,
                             lower=(1 +
                                    p.get("cursor.freehand.min_size", 4) // 2),
                             upper=max_cursor,
                             step_increment=1,
                             page_increment=2)
        dyn_ch_spinner.set_adjustment(adj)

        dyn_ch_spinner.set_sensitive(dyn_ch_enabled)
        self._dyn_crosshair_threshold = dyn_ch_spinner
        self._dyn_crosshair_label = getobj("dynamic_crosshair_threshold_label")

        # Signal hookup now everything is in the right initial state
        self._builder.connect_signals(self)
Example #8
0
    def __init__(self, filenames, state_dirs, version, fullscreen=False):
        """Construct, but do not run.

        :param list filenames: The list of files to load (unicode required)
        :param StateDirs state_dirs: static special paths.
        :param unicode version: Version string for the about dialog.
        :param bool fullscreen: Go fullscreen after starting.

        Only the first filename listed will be loaded. If no files are
        listed, the autosave recovery dialog may be shown when the
        application starts up.

        """
        assert Application._INSTANCE is None
        super(Application, self).__init__()
        Application._INSTANCE = self

        self.state_dirs = state_dirs  #: Static special paths: see StateDirs

        self.version = version  #: version string for the app.

        # Create the user's config directory and any needed R/W data
        # storage areas.
        for basedir in [state_dirs.user_config, state_dirs.user_data]:
            if not os.path.isdir(basedir):
                os.makedirs(basedir)
                logger.info('Created basedir %r', basedir)
        for datasubdir in [u'backgrounds', u'brushes', u'scratchpads']:
            datadir = os.path.join(state_dirs.user_data, datasubdir)
            if not os.path.isdir(datadir):
                os.mkdir(datadir)
                logger.info('Created data subdir %r', datadir)

        _init_icons(state_dirs.app_icons)

        # Core actions and menu structure
        ui_dir = os.path.dirname(os.path.abspath(__file__))
        resources_xml = join(ui_dir, "resources.xml")
        self.builder = Gtk.Builder()
        self.builder.set_translation_domain("mypaint")
        self.builder.add_from_file(resources_xml)

        self.ui_manager = self.builder.get_object("app_ui_manager")
        signal_callback_objs = [self]

        Gdk.set_program_class('MyPaint')

        self.pixmaps = PixbufDirectory(join(state_dirs.app_data, u'pixmaps'))
        self.cursor_color_picker = Gdk.Cursor.new_from_pixbuf(
            Gdk.Display.get_default(),
            self.pixmaps.cursor_color_picker,
            3,
            15,
        )
        self.cursor_color_picker_h = Gdk.Cursor.new_from_pixbuf(
            Gdk.Display.get_default(),
            self.pixmaps.cursor_color_picker_h,
            3,
            15,
        )
        self.cursor_color_picker_c = Gdk.Cursor.new_from_pixbuf(
            Gdk.Display.get_default(),
            self.pixmaps.cursor_color_picker_c,
            3,
            15,
        )
        self.cursor_color_picker_y = Gdk.Cursor.new_from_pixbuf(
            Gdk.Display.get_default(),
            self.pixmaps.cursor_color_picker_y,
            3,
            15,
        )
        self.cursors = gui.cursor.CustomCursorMaker(self)

        # App-level settings
        self._preferences = lib.observable.ObservableDict()
        self.load_settings()

        # Set up compatibility mode (most of it)
        self.compat_mode = None
        self.reset_compat_mode(update=False)
        compat.update_default_layer_type(self)

        # Unmanaged main brush.
        # Always the same instance (we can attach settings_observers).
        # This brush is where temporary changes (color, size...) happen.
        self.brush = brush.BrushInfo()
        self.brush.load_defaults()

        # Global pressure mapping function, ignored unless set
        self.pressure_mapping = None

        # Fake inputs to send when using a mouse.  Adjustable
        # via slider and/or hotkeys
        self.fakepressure = 0.5
        self.fakerotation = 0.5

        # Keyboard manager
        self.kbm = keyboard.KeyboardManager(self)

        # File I/O
        self.filehandler = filehandling.FileHandler(self)

        # Picking grabs
        self.context_grab = gui.picker.ContextPickingGrabPresenter()
        self.context_grab.app = self
        self.color_grab = gui.picker.ColorPickingGrabPresenter()
        self.color_grab.app = self

        # Load the main interface
        mypaint_main_xml = join(ui_dir, "mypaint.glade")
        self.builder.add_from_file(mypaint_main_xml)

        # Main drawing window
        self.drawWindow = self.builder.get_object("drawwindow")
        signal_callback_objs.append(self.drawWindow)

        # Workspace widget. Manages layout of toolwindows, and autohide in
        # fullscreen.
        wkspace = self.builder.get_object("app_workspace")
        wkspace.build_from_layout(self.preferences["workspace.layout"])
        wkspace.floating_window_created += self._floating_window_created_cb
        fs_autohide_action = self.builder.get_object("FullscreenAutohide")
        fs_autohide_action.set_active(wkspace.autohide_enabled)
        self.workspace = wkspace

        # Working document: viewer widget
        app_canvas = self.builder.get_object("app_canvas")

        # Working document: model and controller
        cache_size = self.preferences.get('ui.rendered_tile_cache_size',
                                          lib.cache.DEFAULT_CACHE_SIZE)
        default_stack_size = lib.document.DEFAULT_UNDO_STACK_SIZE
        undo_stack_size = self.preferences.setdefault(
            'command.max_undo_stack_size', default_stack_size)
        undo_stack_size = validation.validate(
            undo_stack_size, default_stack_size, int, lambda a: a > 0,
            "The undo stack size ({value}) must be a positive integer!")
        model = lib.document.Document(self.brush,
                                      cache_size=cache_size,
                                      max_undo_stack_size=undo_stack_size)
        self.doc = document.Document(self, app_canvas, model)
        app_canvas.set_model(model)

        signal_callback_objs.append(self.doc)
        signal_callback_objs.append(self.doc.modes)

        self.scratchpad_filename = ""
        scratchpad_model = lib.document.Document(
            self.brush,
            painting_only=True,
            cache_size=lib.cache.DEFAULT_CACHE_SIZE / 4)
        scratchpad_tdw = tileddrawwidget.TiledDrawWidget()
        scratchpad_tdw.scroll_on_allocate = False
        scratchpad_tdw.set_model(scratchpad_model)
        self.scratchpad_doc = document.Document(self, scratchpad_tdw,
                                                scratchpad_model)

        self.brushmanager = brushmanager.BrushManager(
            lib.config.mypaint_brushdir,
            join(self.state_dirs.user_data, 'brushes'),
            self,
        )

        signal_callback_objs.append(self.filehandler)
        self.brushmodifier = brushmodifier.BrushModifier(self)
        signal_callback_objs.append(self.brushmodifier)
        self.blendmodemanager = blendmodehandler.BlendModeManager(self)
        signal_callback_objs.append(self.blendmodemanager)
        self.blendmodemanager.register(self.brushmodifier.bm)

        self.line_mode_settings = linemode.LineModeSettings(self)

        # Button press mapping
        self.button_mapping = ButtonMapping()

        # Monitors pluggings and uses of input device, configures them,
        # and switches between device-specific brushes.
        self.device_monitor = gui.device.Monitor(self)

        if not self.preferences.get("scratchpad.last_opened_scratchpad", None):
            self.preferences["scratchpad.last_opened_scratchpad"] \
                = self.filehandler.get_scratchpad_autosave()
        self.scratchpad_filename \
            = self.preferences["scratchpad.last_opened_scratchpad"]

        self.brush_color_manager = BrushColorManager(self)
        self.brush_color_manager.set_picker_cursor(self.cursor_color_picker)
        self.brush_color_manager.set_data_path(self.datapath)

        #: Mapping of setting cname to a GtkAdjustment which controls the base
        #: value of that setting for the app's current brush.
        self.brush_adjustment = {}
        self.init_brush_adjustments()
        # Extend with some fake inputs that act kind of like brush settings
        self.fake_adjustment = {}

        # Connect signals defined in resources.xml
        callback_finder = CallbackFinder(signal_callback_objs)
        self.builder.connect_signals(callback_finder)

        self.kbm.start_listening()
        self.filehandler.doc = self.doc
        self.filehandler.filename = None
        Gtk.AccelMap.load(join(self.user_confpath, 'accelmap.conf'))

        # Load the default background image
        self.doc.reset_background()

        # Non-dockable subwindows
        # Loading is deferred as late as possible
        self._subwindow_classes = {
            # action-name: action-class
            "BackgroundWindow": backgroundwindow.BackgroundWindow,
            "BrushEditorWindow": brusheditor.BrushEditorWindow,
            "PreferencesWindow": preferenceswindow.PreferencesWindow,
            "InputTestWindow": inputtestwindow.InputTestWindow,
            "BrushIconEditorWindow": brushiconeditor.BrushIconEditorWindow,
        }
        self._subwindows = {}

        # Statusbar init
        statusbar = self.builder.get_object("app_statusbar")
        self.statusbar = statusbar
        context_id = statusbar.get_context_id("transient-message")
        self._transient_msg_context_id = context_id
        self._transient_msg_remove_timeout_id = None

        # Profiling & debug stuff
        self.profiler = gui.profiling.Profiler()

        # Show main UI.
        self.drawWindow.show_all()
        GLib.idle_add(self._at_application_start, filenames, fullscreen)