def create(fuProcedure, gimpProcedure=None): # Configure use_header_bar from Gtk settings, not Gimp settings? use_header_bar = Gtk.Settings.get_default().get_property( "gtk-dialogs-use-header") # TODO i18n ? """ This dialog is only for the plugin/procedure we are implementing (not for procedures we may call.) So we can use the local FuProcedure instead of the Gimp.Procedure. """ # Configure title the same as the menu label # title = gimpProcedure.get_menu_label() # method of gimpProcedure title = fuProcedure.menu_label # property of fuProcedure dialog = GimpUi.Dialog(use_header_bar=use_header_bar, title=title) return dialog
def blob_dialog(self): """Bring up a dialog prompting for blobipy options. Return (response, blur) """ use_header_bar = Gtk.Settings.get_default().get_property( "gtk-dialogs-use-header") dialog = GimpUi.Dialog(use_header_bar=use_header_bar, title="Give a puffy, 3-D appearance", role="blobypy") dialog.add_button("_Cancel", Gtk.ResponseType.CANCEL) dialog.add_button("_OK", Gtk.ResponseType.OK) vbox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, homogeneous=False, spacing=10) dialog.get_content_area().add(vbox) vbox.show() self.blurspin = Gtk.SpinButton.new_with_range(0., 50., 1.) self.blurspin.set_value(5) vbox.pack_start(self.blurspin, False, False, 0) self.blurspin.show() return dialog
def run(procedure, run_mode, image, n_layers, layers, args, data): gio_file = args.index(0) bucket_size = args.index(1) sample_average = args.index(2) output_format = args.index(3) progress_bar = None config = None if run_mode == Gimp.RunMode.INTERACTIVE: config = procedure.create_config() # Set properties from arguments. These properties will be changed by the UI. #config.set_property("file", gio_file) #config.set_property("bucket_size", bucket_size) #config.set_property("sample_average", sample_average) #config.set_property("output_format", output_format) config.begin_run(image, run_mode, args) GimpUi.init("histogram-export.py") use_header_bar = Gtk.Settings.get_default().get_property( "gtk-dialogs-use-header") dialog = GimpUi.Dialog(use_header_bar=use_header_bar, title=_("Histogram Export...")) dialog.add_button("_Cancel", Gtk.ResponseType.CANCEL) dialog.add_button("_OK", Gtk.ResponseType.OK) vbox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, homogeneous=False, spacing=10) dialog.get_content_area().add(vbox) vbox.show() # Create grid to set all the properties inside. grid = Gtk.Grid() grid.set_column_homogeneous(False) grid.set_border_width(10) grid.set_column_spacing(10) grid.set_row_spacing(10) vbox.add(grid) grid.show() # UI for the file parameter def choose_file(widget): if file_chooser_dialog.run() == Gtk.ResponseType.OK: if file_chooser_dialog.get_file() is not None: config.set_property("file", file_chooser_dialog.get_file()) file_entry.set_text( file_chooser_dialog.get_file().get_path()) file_chooser_dialog.hide() file_chooser_button = Gtk.Button.new_with_mnemonic(label=_("_File...")) grid.attach(file_chooser_button, 0, 0, 1, 1) file_chooser_button.show() file_chooser_button.connect("clicked", choose_file) file_entry = Gtk.Entry.new() grid.attach(file_entry, 1, 0, 1, 1) file_entry.set_width_chars(40) file_entry.set_placeholder_text(_("Choose export file...")) if gio_file is not None: file_entry.set_text(gio_file.get_path()) file_entry.show() file_chooser_dialog = Gtk.FileChooserDialog( use_header_bar=use_header_bar, title=_("Histogram Export file..."), action=Gtk.FileChooserAction.SAVE) file_chooser_dialog.add_button("_Cancel", Gtk.ResponseType.CANCEL) file_chooser_dialog.add_button("_OK", Gtk.ResponseType.OK) # Bucket size parameter label = Gtk.Label.new_with_mnemonic(_("_Bucket Size")) grid.attach(label, 0, 1, 1, 1) label.show() spin = GimpUi.prop_spin_button_new(config, "bucket_size", step_increment=0.001, page_increment=0.1, digits=3) grid.attach(spin, 1, 1, 1, 1) spin.show() # Sample average parameter spin = GimpUi.prop_check_button_new(config, "sample_average", _("Sample _Average")) spin.set_tooltip_text( _("If checked, the histogram is generated from merging all visible layers." " Otherwise, the histogram is only for the current layer.")) grid.attach(spin, 1, 2, 1, 1) spin.show() # Output format parameter label = Gtk.Label.new_with_mnemonic(_("_Output Format")) grid.attach(label, 0, 3, 1, 1) label.show() combo = GimpUi.prop_string_combo_box_new( config, "output_format", output_format_enum.get_tree_model(), 0, 1) grid.attach(combo, 1, 3, 1, 1) combo.show() progress_bar = Gtk.ProgressBar() vbox.add(progress_bar) progress_bar.show() dialog.show() if dialog.run() != Gtk.ResponseType.OK: return procedure.new_return_values(Gimp.PDBStatusType.CANCEL, GLib.Error()) # Extract values from UI gio_file = Gio.file_new_for_path( file_entry.get_text()) # config.get_property("file") bucket_size = config.get_property("bucket_size") sample_average = config.get_property("sample_average") output_format = config.get_property("output_format") if gio_file is None: error = 'No file given' return procedure.new_return_values(Gimp.PDBStatusType.CALLING_ERROR, GLib.Error(error)) result = histogram_export(procedure, image, layers, gio_file, bucket_size, sample_average, output_format, progress_bar) # If the execution was successful, save parameters so they will be restored next time we show dialog. if result.index(0) == Gimp.PDBStatusType.SUCCESS and config is not None: config.end_run(Gimp.PDBStatusType.SUCCESS) return result
def run(self, procedure, args, run_data): GimpUi.init("pydev-client") dialog = GimpUi.Dialog(use_header_bar=True, title=_("PyDev Client"), role="pydev-client") dialog.add_button(_("_Cancel"), Gtk.ResponseType.CANCEL) dialog.add_button(_("_Source"), Gtk.ResponseType.APPLY) dialog.add_button(_("_OK"), Gtk.ResponseType.OK) geometry = Gdk.Geometry() # geometry.min_aspect = 0.5 # geometry.max_aspect = 1.0 # dialog.set_geometry_hints(None, geometry, Gdk.WindowHints.ASPECT) box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=2) dialog.get_content_area().add(box) box.show() label = Gtk.Label(label=head_text) box.pack_start(label, False, False, 1) label.show() contents = "Hola Mundo!" if contents is not None: scrolled = Gtk.ScrolledWindow() scrolled.set_vexpand(True) box.pack_start(scrolled, True, True, 1) scrolled.show() view = Gtk.TextView() view.set_wrap_mode(Gtk.WrapMode.WORD) view.set_editable(False) buffer = view.get_buffer() buffer.set_text(contents, -1) scrolled.add(view) view.show() th = mp.Process(target=set_trace) th.start() while True: response = dialog.run() if response == Gtk.ResponseType.OK: dialog.destroy() break elif response == Gtk.ResponseType.APPLY: url = "https://github.com/isman7/gimp-python-development" Gio.app_info_launch_default_for_uri(url, None) continue else: th.terminate() dialog.destroy() return procedure.new_return_values(Gimp.PDBStatusType.CANCEL, GLib.Error()) th.terminate() return procedure.new_return_values(Gimp.PDBStatusType.SUCCESS, GLib.Error())
def run(self, procedure, args, data): palette = None amount = 1 # Get the parameters if args.length() < 1: error = 'No parameters given' return procedure.new_return_values( Gimp.PDBStatusType.CALLING_ERROR, GLib.Error(error)) runmode = args.index(0) if args.length() > 1: palette = args.index(1) if palette == '' or palette is None: palette = Gimp.context_get_palette() (exists, num_colors) = Gimp.palette_get_info(palette) if not exists: error = 'Unknown palette: {}'.format(palette) return procedure.new_return_values( Gimp.PDBStatusType.CALLING_ERROR, GLib.Error(error)) if args.length() > 2: amount = args.index(2) if runmode == Gimp.RunMode.INTERACTIVE: gi.require_version('Gtk', '3.0') from gi.repository import Gtk GimpUi.ui_init("palette-offset.py") use_header_bar = Gtk.Settings.get_default().get_property( "gtk-dialogs-use-header") dialog = GimpUi.Dialog(use_header_bar=use_header_bar, title=_("Offset Palette...")) dialog.add_button("_Cancel", Gtk.ResponseType.CANCEL) dialog.add_button("_OK", Gtk.ResponseType.OK) box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, homogeneous=False, spacing=12) dialog.get_content_area().add(box) box.show() label = Gtk.Label.new_with_mnemonic("Off_set") box.pack_start(label, False, False, 1) label.show() amount = self.set_property("amount", amount) spin = GimpUi.prop_spin_button_new(self, "amount", 1.0, 5.0, 0) spin.set_activates_default(True) box.pack_end(spin, False, False, 1) spin.show() dialog.show() if dialog.run() != Gtk.ResponseType.OK: return procedure.new_return_values(Gimp.PDBStatusType.CANCEL, GLib.Error()) amount = self.get_property("amount") #If palette is read only, work on a copy: editable = Gimp.palette_is_editable(palette) if not editable: palette = Gimp.palette_duplicate(palette) tmp_entry_array = [] for i in range(num_colors): tmp_entry_array.append((Gimp.palette_entry_get_name(palette, i)[1], Gimp.palette_entry_get_color(palette, i)[1])) for i in range(num_colors): target_index = i + amount if target_index >= num_colors: target_index -= num_colors elif target_index < 0: target_index += num_colors Gimp.palette_entry_set_name(palette, target_index, tmp_entry_array[i][0]) Gimp.palette_entry_set_color(palette, target_index, tmp_entry_array[i][1]) retval = procedure.new_return_values(Gimp.PDBStatusType.SUCCESS, GLib.Error()) value = GObject.Value(GObject.TYPE_STRING, palette) retval.remove(1) retval.insert(1, value) return retval
def run(self, procedure, run_mode, image, drawable, args, run_data): if run_mode == Gimp.RunMode.INTERACTIVE: gi.require_version('Gtk', '3.0') from gi.repository import Gtk gi.require_version('Gdk', '3.0') from gi.repository import Gdk GimpUi.ui_init("palette-offset.py") dialog = GimpUi.Dialog(use_header_bar=True, title=_("Exercise a goat (Python 3)"), role="goat-exercise-Python3") dialog.add_button("_Cancel", Gtk.ResponseType.CANCEL) dialog.add_button("_Source", Gtk.ResponseType.APPLY) dialog.add_button("_OK", Gtk.ResponseType.OK) geometry = Gdk.Geometry() geometry.min_aspect = 0.5 geometry.max_aspect = 1.0 dialog.set_geometry_hints(None, geometry, Gdk.WindowHints.ASPECT) box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=2) dialog.get_content_area().add(box) box.show() # XXX We use printf-style string for sharing the localized # string. You may just use recommended Python format() or # any style you like in your plug-ins. head_text = ("This plug-in is an exercise in '%s' to " "demo plug-in creation.\nCheck out the last " "version of the source code online by clicking " "the \"Source\" button." % ("Python 3")) label = Gtk.Label(label=head_text) box.pack_start(label, False, False, 1) label.show() contents = None # Get the file contents Python-style instead of using # GLib.file_get_contents() which returns bytes result, and # when converting to string, get newlines as text contents. # Rather than wasting time to figure this out, use Python # core API! with open(os.path.realpath(__file__), 'r') as f: contents = f.read() if contents is not None: scrolled = Gtk.ScrolledWindow() scrolled.set_vexpand(True) box.pack_start(scrolled, True, True, 1) scrolled.show() view = Gtk.TextView() view.set_wrap_mode(Gtk.WrapMode.WORD) view.set_editable(False) buffer = view.get_buffer() buffer.set_text(contents, -1) scrolled.add(view) view.show() while (True): response = dialog.run() if response == Gtk.ResponseType.OK: dialog.destroy() break elif response == Gtk.ResponseType.APPLY: url = "https://gitlab.gnome.org/GNOME/gimp/-/blob/master/plug-ins/goat-exercises/goat-exercise-py3.py" Gio.app_info_launch_default_for_uri(url, None) continue else: dialog.destroy() return procedure.new_return_values( Gimp.PDBStatusType.CANCEL, GLib.Error()) intersect, x, y, width, height = drawable.mask_intersect() if intersect: Gegl.init(None) buffer = drawable.get_buffer() shadow_buffer = drawable.get_shadow_buffer() graph = Gegl.Node() input = graph.create_child("gegl:buffer-source") input.set_property("buffer", buffer) invert = graph.create_child("gegl:invert") output = graph.create_child("gegl:write-buffer") output.set_property("buffer", shadow_buffer) input.link(invert) invert.link(output) output.process() # This is extremely important in bindings, since we don't # unref buffers. If we don't explicitly flush a buffer, we # may left hanging forever. This step is usually done # during an unref(). shadow_buffer.flush() drawable.merge_shadow(True) drawable.update(x, y, width, height) Gimp.displays_flush() return procedure.new_return_values(Gimp.PDBStatusType.SUCCESS, GLib.Error())
def run(self, procedure, run_mode, image, n_drawables, drawables, args, run_data): if n_drawables != 1: msg = _( f"Procedure '{procedure.get_name()}' only works with one drawable." ) error = GLib.Error.new_literal(Gimp.PlugIn.error_quark(), msg, 0) return procedure.new_return_values( Gimp.PDBStatusType.CALLING_ERROR, error) else: drawable = drawables[0] # check if selection exist selection = image.get_selection() flag, non_empty, x1, y1, x2, y2 = selection.bounds(image) if not non_empty: msg = _( f"The selection is empty, create a selection box and precede with the use of this plugin." ) error = GLib.Error.new_literal(Gimp.PlugIn.error_quark(), msg, 0) return procedure.new_return_values( Gimp.PDBStatusType.CALLING_ERROR, error) if run_mode == Gimp.RunMode.INTERACTIVE: gi.require_version('Gtk', '3.0') from gi.repository import Gtk gi.require_version('Gdk', '3.0') from gi.repository import Gdk GimpUi.init("add_balloon.py") dialog = GimpUi.Dialog(use_header_bar=True, title=_("Add Balloon)"), role="add_balloon-Python3") dialog.add_button(_("_Cancel"), Gtk.ResponseType.CANCEL) dialog.add_button(_("_OK"), Gtk.ResponseType.OK) geometry = Gdk.Geometry() geometry.min_aspect = 0.5 geometry.max_aspect = 1.0 dialog.set_geometry_hints(None, geometry, Gdk.WindowHints.ASPECT) box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=2) dialog.get_content_area().add(box) box.show() # Label text content label = Gtk.Label(label='Text:') box.pack_start(label, False, False, 1) label.show() # scroll area for text scrolled = Gtk.ScrolledWindow() scrolled.set_vexpand(True) box.pack_start(scrolled, True, True, 1) scrolled.show() # text content box text_content = Gtk.TextView() contents = 'text' buffer = text_content.get_buffer() buffer.set_text(contents, -1) scrolled.add(text_content) text_content.show() # Improve UI font_chooser = Gtk.FontChooserWidget() box.pack_start(font_chooser, False, False, 1) font_chooser.show() # TODO add spinner for waiting while (True): response = dialog.run() if response == Gtk.ResponseType.OK: # TODO enable spinner and lock all other values # layer position position = Gimp.get_pdb().run_procedure( 'gimp-image-get-item-position', [image, drawable]).index(1) # Create group layer_group = Gimp.get_pdb().run_procedure( 'gimp-layer-group-new', [image]).index(1) image.insert_layer(layer_group, None, position) # add new trasparent layer overlay_layer = Gimp.Layer.new(image, 'hide_background', drawable.get_width(), drawable.get_height(), Gimp.ImageType.RGBA_IMAGE, 100.0, Gimp.LayerMode.NORMAL) image.insert_layer(overlay_layer, layer_group, position) overlay_layer.fill(Gimp.FillType.TRANSPARENT) # add white fill the selection Gimp.get_pdb().run_procedure( 'gimp-drawable-edit-fill', [overlay_layer, Gimp.FillType.WHITE]) # add text layer buffer = text_content.get_buffer() text = buffer.get_text(buffer.get_start_iter(), buffer.get_end_iter(), True) font_str = font_chooser.get_font() font_size = float(font_str.split(' ')[-1]) font_name = ' '.join(font_str.split(' ')[0:-2]) text_layer = Gimp.get_pdb().run_procedure( 'gimp-text-layer-new', [image, text, font_name, font_size, 3]).index(1) image.insert_layer(text_layer, layer_group, position - 1) # center text layer Gimp.get_pdb().run_procedure( 'gimp-text-layer-set-justification', [text_layer, 2]) cx = (x1 + x2) / 2 - text_layer.get_width() / 2 cy = (y1 + y2) / 2 - text_layer.get_height() / 2 Gimp.get_pdb().run_procedure( 'gimp-item-transform-translate', [text_layer, cx, cy]) # set selected layer image.set_selected_layers([layer_group]) dialog.destroy() break else: dialog.destroy() return procedure.new_return_values( Gimp.PDBStatusType.CANCEL, GLib.Error()) return procedure.new_return_values(Gimp.PDBStatusType.SUCCESS, GLib.Error())