From d59a7af38c4dc3f5b763a8c57bff7dee38bc1a78 Mon Sep 17 00:00:00 2001 From: lloyd konneker Date: Sat, 15 Oct 2022 15:11:05 -0400 Subject: [PATCH] libgimp: API refactor GUI for GimpResource Simplifies chooser widgets (e.g. GimpBrushSelect) by eliminating attributes (e.g. opacity) of chosen resource. See #8745, but this commit fixes that by first refactoring the code. Refactors GUI widgets (e.g. GimpBrushSelectButton and GimpBrushSelect etc.) Refactor by "Extract class" GimpResourceSelectButton from GimpBrushSelectButton etc. This moves common code into an inherited class (formerly called GimpSelectButton) but the subclasses still exist. The subclasses mainly just do drawing now. Refactor by "Extract module" GimpResourceSelect from GimpBrushSelect etc. Moves common code into one file, generic at runtime on type of GimpResource, that is, the new code dispatches on type i.e. switch statements. In the future, when core is changed some of that can be deleted. The files gimpbrushselect.[c,h] etc. are deleted. The module adapts the API from core to the API of callbacks to libgimp. Note that core is running the resource chooser (select) widgets remotely. Core is still calling back over the wire via PDB with more attributes than necessary. The new design gets the attributes from the resource themselves, instead of receiving them from core callback. The libgimp side adapts by discarding unneeded attributes. In the future, core (running choosers for plugins) can be simplified also. Fix gimp_prop_chooser_brush_new same as other resources. Finish changes, and clean style. Annotations --- app/core/Makefile.am | 2 + app/core/gimpparamspecs.c | 1 + app/core/gimpresource.c | 53 + app/core/gimpresource.h | 32 + app/core/meson.build | 1 + app/pdb/brush-select-cmds.c | 88 +- app/pdb/font-select-cmds.c | 24 +- app/pdb/gradient-select-cmds.c | 36 +- app/pdb/palette-select-cmds.c | 20 +- app/pdb/pattern-select-cmds.c | 18 +- libgimp/Makefile.gi | 22 +- libgimp/gimp.def | 15 +- libgimp/gimp.h | 10 +- libgimp/gimpbrushselect.c | 265 ----- libgimp/gimpbrushselect.h | 68 -- libgimp/gimpbrushselect_pdb.c | 49 +- libgimp/gimpbrushselect_pdb.h | 18 +- libgimp/gimpbrushselectbutton.c | 1037 ++++++----------- libgimp/gimpbrushselectbutton.h | 75 +- libgimp/gimpfontselect.c | 179 --- libgimp/gimpfontselect.h | 46 - libgimp/gimpfontselect_pdb.c | 31 +- libgimp/gimpfontselect_pdb.h | 2 +- libgimp/gimpfontselectbutton.c | 519 ++++----- libgimp/gimpfontselectbutton.h | 58 +- libgimp/gimpgradientselect.c | 199 ---- libgimp/gimpgradientselect.h | 49 - libgimp/gimpgradientselect_pdb.c | 22 +- libgimp/gimpgradientselect_pdb.h | 3 +- libgimp/gimpgradientselectbutton.c | 623 ++++------ libgimp/gimpgradientselectbutton.h | 60 +- libgimp/gimppaletteselect.c | 187 --- libgimp/gimppaletteselect.h | 46 - libgimp/gimppaletteselect_pdb.c | 19 +- libgimp/gimppaletteselect_pdb.h | 2 +- libgimp/gimppaletteselectbutton.c | 525 ++++----- libgimp/gimppaletteselectbutton.h | 60 +- libgimp/gimpparamspecs-body-resource.c | 133 +++ libgimp/gimpparamspecs-resource.h | 34 +- libgimp/gimppatternselect.c | 221 ---- libgimp/gimppatternselect.h | 59 - libgimp/gimppatternselect_pdb.c | 17 +- libgimp/gimppatternselect_pdb.h | 2 +- libgimp/gimppatternselectbutton.c | 985 ++++++++-------- libgimp/gimppatternselectbutton.h | 64 +- libgimp/gimpprocedure-params.h | 26 + libgimp/gimpproceduredialog.c | 22 +- libgimp/gimppropbrushchooser.c | 299 ----- libgimp/gimppropbrushchooser.h | 35 - libgimp/gimppropchooser.c | 105 ++ libgimp/gimppropchooser.h | 47 + libgimp/gimppropchooserfactory.c | 118 ++ libgimp/gimppropchooserfactory.h | 46 + libgimp/gimpresourceselect.c | 622 ++++++++++ libgimp/gimpresourceselect.h | 55 + libgimp/gimpresourceselectbutton.c | 731 ++++++++++++ libgimp/gimpresourceselectbutton.h | 85 ++ libgimp/gimpselectbutton.c | 94 -- libgimp/gimpselectbutton.h | 81 -- libgimp/gimpui.def | 17 +- libgimp/gimpui.h | 5 +- libgimp/gimpuimarshal.list | 4 +- libgimp/meson.build | 21 +- libgimpconfig/gimpconfig-params.c | 4 + pdb/groups/brush_select.pdb | 69 +- pdb/groups/font_select.pdb | 52 +- pdb/groups/gradient_select.pdb | 50 +- pdb/groups/palette_select.pdb | 37 +- pdb/groups/pattern_select.pdb | 35 +- plug-ins/Makefile.am | 6 +- plug-ins/gfig/gfig-dialog.c | 3 +- plug-ins/gfig/gfig-style.c | 50 +- plug-ins/gfig/gfig-style.h | 2 +- plug-ins/meson.build | 6 +- plug-ins/python/Makefile.am | 6 + plug-ins/python/test-dialog.py | 63 +- .../libscriptfu/script-fu-interface.c | 16 +- po-libgimp/POTFILES.in | 3 - 78 files changed, 4053 insertions(+), 4741 deletions(-) create mode 100644 app/core/gimpresource.c create mode 100644 app/core/gimpresource.h delete mode 100644 libgimp/gimpbrushselect.c delete mode 100644 libgimp/gimpbrushselect.h delete mode 100644 libgimp/gimpfontselect.c delete mode 100644 libgimp/gimpfontselect.h delete mode 100644 libgimp/gimpgradientselect.c delete mode 100644 libgimp/gimpgradientselect.h delete mode 100644 libgimp/gimppaletteselect.c delete mode 100644 libgimp/gimppaletteselect.h delete mode 100644 libgimp/gimppatternselect.c delete mode 100644 libgimp/gimppatternselect.h delete mode 100644 libgimp/gimppropbrushchooser.c delete mode 100644 libgimp/gimppropbrushchooser.h create mode 100644 libgimp/gimppropchooser.c create mode 100644 libgimp/gimppropchooser.h create mode 100644 libgimp/gimppropchooserfactory.c create mode 100644 libgimp/gimppropchooserfactory.h create mode 100644 libgimp/gimpresourceselect.c create mode 100644 libgimp/gimpresourceselect.h create mode 100644 libgimp/gimpresourceselectbutton.c create mode 100644 libgimp/gimpresourceselectbutton.h delete mode 100644 libgimp/gimpselectbutton.c delete mode 100644 libgimp/gimpselectbutton.h diff --git a/app/core/Makefile.am b/app/core/Makefile.am index 05504e5a2d..53c3188db9 100644 --- a/app/core/Makefile.am +++ b/app/core/Makefile.am @@ -433,6 +433,8 @@ libappcore_a_sources = \ gimpprojectable.h \ gimpprojection.c \ gimpprojection.h \ + gimpresource.c \ + gimpresource.h \ gimpsamplepoint.c \ gimpsamplepoint.h \ gimpsamplepointundo.c \ diff --git a/app/core/gimpparamspecs.c b/app/core/gimpparamspecs.c index b93adb8c76..f96399b949 100644 --- a/app/core/gimpparamspecs.c +++ b/app/core/gimpparamspecs.c @@ -37,6 +37,7 @@ #include "vectors/gimpvectors.h" /* resource types */ +#include "gimpresource.h" #include "gimpbrush.h" #include "gimpgradient.h" #include "gimppalette.h" diff --git a/app/core/gimpresource.c b/app/core/gimpresource.c new file mode 100644 index 0000000000..19a709a1db --- /dev/null +++ b/app/core/gimpresource.c @@ -0,0 +1,53 @@ +/* LIBGIMP - The GIMP Library + * Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball + * + * This library is free software: you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see + * . + */ + +#include "config.h" + +#include +#include +#include + +#include "gimpresource.h" + + /* This class exists to support gimp_param_spec_resource, + * which is needed to communicate with libgimp. + * So that gimp_param_spec_resource has a GIMP_TYPE_RESOURCE on the app side. + * + * This class on libgimp side is a superclass. + * On app side of wire, it is not a superclass (e.g. GimpBrush does not inherit.) + * On app side, the class is never inherited and never instantiated. + * + * The code is derived from libgimp/gimpresource.c + */ + + +G_DEFINE_TYPE (GimpResource, gimp_resource, G_TYPE_OBJECT) + +/* Class construction */ +static void +gimp_resource_class_init (GimpResourceClass *klass) +{ + g_debug("gimp_resource_class_init"); +} + +/* Instance construction. */ +static void +gimp_resource_init (GimpResource *self) +{ + g_debug("gimp_resource_init"); +} diff --git a/app/core/gimpresource.h b/app/core/gimpresource.h new file mode 100644 index 0000000000..5e593f4769 --- /dev/null +++ b/app/core/gimpresource.h @@ -0,0 +1,32 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef __GIMP_RESOURCE_H__ +#define __GIMP_RESOURCE_H__ + +#define GIMP_TYPE_RESOURCE (gimp_resource_get_type ()) +G_DECLARE_DERIVABLE_TYPE (GimpResource, gimp_resource, GIMP, RESOURCE, GObject) + +struct _GimpResourceClass +{ + GObjectClass parent_class; + + /* Padding for future expansion */ + gpointer padding[8]; +}; + +#endif /* __GIMP_RESOURCE_H__ */ diff --git a/app/core/meson.build b/app/core/meson.build index 6a8313025a..c7155729f9 100644 --- a/app/core/meson.build +++ b/app/core/meson.build @@ -217,6 +217,7 @@ libappcore_sources = [ 'gimpprogress.c', 'gimpprojectable.c', 'gimpprojection.c', + 'gimpresource.c', 'gimpsamplepoint.c', 'gimpsamplepointundo.c', 'gimpscanconvert.c', diff --git a/app/pdb/brush-select-cmds.c b/app/pdb/brush-select-cmds.c index 6e5b038867..554504ccab 100644 --- a/app/pdb/brush-select-cmds.c +++ b/app/pdb/brush-select-cmds.c @@ -49,31 +49,19 @@ brushes_popup_invoker (GimpProcedure *procedure, gboolean success = TRUE; const gchar *brush_callback; const gchar *popup_title; - const gchar *initial_brush; - gdouble opacity; - gint spacing; - gint paint_mode; + const gchar *initial_brush_name; brush_callback = g_value_get_string (gimp_value_array_index (args, 0)); popup_title = g_value_get_string (gimp_value_array_index (args, 1)); - initial_brush = g_value_get_string (gimp_value_array_index (args, 2)); - opacity = g_value_get_double (gimp_value_array_index (args, 3)); - spacing = g_value_get_int (gimp_value_array_index (args, 4)); - paint_mode = g_value_get_enum (gimp_value_array_index (args, 5)); + initial_brush_name = g_value_get_string (gimp_value_array_index (args, 2)); if (success) { - if (paint_mode == GIMP_LAYER_MODE_OVERLAY_LEGACY) - paint_mode = GIMP_LAYER_MODE_SOFTLIGHT_LEGACY; - - if (gimp->no_interface || + if (gimp->no_interface || ! gimp_pdb_lookup_procedure (gimp->pdb, brush_callback) || ! gimp_pdb_dialog_new (gimp, context, progress, gimp_data_factory_get_container (gimp->brush_factory), - popup_title, brush_callback, initial_brush, - "opacity", opacity / 100.0, - "paint-mode", paint_mode, - "spacing", spacing, + popup_title, brush_callback, initial_brush_name, NULL)) success = FALSE; } @@ -119,28 +107,16 @@ brushes_set_popup_invoker (GimpProcedure *procedure, gboolean success = TRUE; const gchar *brush_callback; const gchar *brush_name; - gdouble opacity; - gint spacing; - gint paint_mode; brush_callback = g_value_get_string (gimp_value_array_index (args, 0)); brush_name = g_value_get_string (gimp_value_array_index (args, 1)); - opacity = g_value_get_double (gimp_value_array_index (args, 2)); - spacing = g_value_get_int (gimp_value_array_index (args, 3)); - paint_mode = g_value_get_enum (gimp_value_array_index (args, 4)); if (success) { - if (paint_mode == GIMP_LAYER_MODE_OVERLAY_LEGACY) - paint_mode = GIMP_LAYER_MODE_SOFTLIGHT_LEGACY; - if (gimp->no_interface || ! gimp_pdb_lookup_procedure (gimp->pdb, brush_callback) || ! gimp_pdb_dialog_set (gimp, gimp_data_factory_get_container (gimp->brush_factory), brush_callback, brush_name, - "opacity", opacity / 100.0, - "paint-mode", paint_mode, - "spacing", spacing, NULL)) success = FALSE; } @@ -161,8 +137,8 @@ register_brush_select_procs (GimpPDB *pdb) gimp_object_set_static_name (GIMP_OBJECT (procedure), "gimp-brushes-popup"); gimp_procedure_set_static_help (procedure, - "Invokes the Gimp brush selection.", - "This procedure opens the brush selection dialog.", + "Invokes the GIMP brush selection dialog.", + "Opens a dialog letting a user choose a brush.", NULL); gimp_procedure_set_static_attribution (procedure, "Andy Thomas", @@ -171,7 +147,7 @@ register_brush_select_procs (GimpPDB *pdb) gimp_procedure_add_argument (procedure, gimp_param_spec_string ("brush-callback", "brush callback", - "The callback PDB proc to call when brush selection is made", + "The callback PDB proc to call when user chooses a brush", FALSE, FALSE, TRUE, NULL, GIMP_PARAM_READWRITE)); @@ -183,31 +159,12 @@ register_brush_select_procs (GimpPDB *pdb) NULL, GIMP_PARAM_READWRITE)); gimp_procedure_add_argument (procedure, - gimp_param_spec_string ("initial-brush", - "initial brush", - "The name of the brush to set as the first selected", + gimp_param_spec_string ("initial-brush-name", + "initial brush name", + "The name of the brush to set as the initial choice", FALSE, TRUE, FALSE, NULL, GIMP_PARAM_READWRITE)); - gimp_procedure_add_argument (procedure, - g_param_spec_double ("opacity", - "opacity", - "The initial opacity of the brush", - 0, 100, 0, - GIMP_PARAM_READWRITE)); - gimp_procedure_add_argument (procedure, - g_param_spec_int ("spacing", - "spacing", - "The initial spacing of the brush (if < 0 then use brush default spacing)", - G_MININT32, 1000, 0, - GIMP_PARAM_READWRITE)); - gimp_procedure_add_argument (procedure, - g_param_spec_enum ("paint-mode", - "paint mode", - "The initial paint mode", - GIMP_TYPE_LAYER_MODE, - GIMP_LAYER_MODE_NORMAL, - GIMP_PARAM_READWRITE)); gimp_pdb_register_procedure (pdb, procedure); g_object_unref (procedure); @@ -219,7 +176,7 @@ register_brush_select_procs (GimpPDB *pdb) "gimp-brushes-close-popup"); gimp_procedure_set_static_help (procedure, "Close the brush selection dialog.", - "This procedure closes an opened brush selection dialog.", + "Closes an open brush selection dialog.", NULL); gimp_procedure_set_static_attribution (procedure, "Andy Thomas", @@ -242,8 +199,8 @@ register_brush_select_procs (GimpPDB *pdb) gimp_object_set_static_name (GIMP_OBJECT (procedure), "gimp-brushes-set-popup"); gimp_procedure_set_static_help (procedure, - "Sets the current brush in a brush selection dialog.", - "Sets the current brush in a brush selection dialog.", + "Sets the selected brush in a brush selection dialog.", + "Sets the selected brush in a brush selection dialog.", NULL); gimp_procedure_set_static_attribution (procedure, "Andy Thomas", @@ -263,25 +220,6 @@ register_brush_select_procs (GimpPDB *pdb) FALSE, FALSE, FALSE, NULL, GIMP_PARAM_READWRITE)); - gimp_procedure_add_argument (procedure, - g_param_spec_double ("opacity", - "opacity", - "The initial opacity of the brush", - 0, 100, 0, - GIMP_PARAM_READWRITE)); - gimp_procedure_add_argument (procedure, - g_param_spec_int ("spacing", - "spacing", - "The initial spacing of the brush (if < 0 then use brush default spacing)", - G_MININT32, 1000, 0, - GIMP_PARAM_READWRITE)); - gimp_procedure_add_argument (procedure, - g_param_spec_enum ("paint-mode", - "paint mode", - "The initial paint mode", - GIMP_TYPE_LAYER_MODE, - GIMP_LAYER_MODE_NORMAL, - GIMP_PARAM_READWRITE)); gimp_pdb_register_procedure (pdb, procedure); g_object_unref (procedure); } diff --git a/app/pdb/font-select-cmds.c b/app/pdb/font-select-cmds.c index 93878ac93f..bca497e57a 100644 --- a/app/pdb/font-select-cmds.c +++ b/app/pdb/font-select-cmds.c @@ -49,11 +49,11 @@ fonts_popup_invoker (GimpProcedure *procedure, gboolean success = TRUE; const gchar *font_callback; const gchar *popup_title; - const gchar *initial_font; + const gchar *initial_font_name; font_callback = g_value_get_string (gimp_value_array_index (args, 0)); popup_title = g_value_get_string (gimp_value_array_index (args, 1)); - initial_font = g_value_get_string (gimp_value_array_index (args, 2)); + initial_font_name = g_value_get_string (gimp_value_array_index (args, 2)); if (success) { @@ -62,7 +62,7 @@ fonts_popup_invoker (GimpProcedure *procedure, ! gimp_data_factory_data_wait (gimp->font_factory) || ! gimp_pdb_dialog_new (gimp, context, progress, gimp_data_factory_get_container (gimp->font_factory), - popup_title, font_callback, initial_font, + popup_title, font_callback, initial_font_name, NULL)) success = FALSE; } @@ -141,8 +141,8 @@ register_font_select_procs (GimpPDB *pdb) gimp_object_set_static_name (GIMP_OBJECT (procedure), "gimp-fonts-popup"); gimp_procedure_set_static_help (procedure, - "Invokes the Gimp font selection.", - "This procedure opens the font selection dialog.", + "Invokes the Gimp font selection dialog.", + "Opens a dialog letting a user choose a font.", NULL); gimp_procedure_set_static_attribution (procedure, "Sven Neumann ", @@ -151,7 +151,7 @@ register_font_select_procs (GimpPDB *pdb) gimp_procedure_add_argument (procedure, gimp_param_spec_string ("font-callback", "font callback", - "The callback PDB proc to call when font selection is made", + "The callback PDB proc to call when user chooses a font", FALSE, FALSE, TRUE, NULL, GIMP_PARAM_READWRITE)); @@ -163,9 +163,9 @@ register_font_select_procs (GimpPDB *pdb) NULL, GIMP_PARAM_READWRITE)); gimp_procedure_add_argument (procedure, - gimp_param_spec_string ("initial-font", - "initial font", - "The name of the font to set as the first selected", + gimp_param_spec_string ("initial-font-name", + "initial font name", + "The name of the initial font choice.", FALSE, TRUE, FALSE, NULL, GIMP_PARAM_READWRITE)); @@ -180,7 +180,7 @@ register_font_select_procs (GimpPDB *pdb) "gimp-fonts-close-popup"); gimp_procedure_set_static_help (procedure, "Close the font selection dialog.", - "This procedure closes an opened font selection dialog.", + "Closes an open font selection dialog.", NULL); gimp_procedure_set_static_attribution (procedure, "Sven Neumann ", @@ -189,7 +189,7 @@ register_font_select_procs (GimpPDB *pdb) gimp_procedure_add_argument (procedure, gimp_param_spec_string ("font-callback", "font callback", - "The name of the callback registered for this pop-up", + "The name of the callback registered in the PDB for this dialog", FALSE, FALSE, TRUE, NULL, GIMP_PARAM_READWRITE)); @@ -213,7 +213,7 @@ register_font_select_procs (GimpPDB *pdb) gimp_procedure_add_argument (procedure, gimp_param_spec_string ("font-callback", "font callback", - "The name of the callback registered for this pop-up", + "The name of the callback registered in the PDB for the dialog.", FALSE, FALSE, TRUE, NULL, GIMP_PARAM_READWRITE)); diff --git a/app/pdb/gradient-select-cmds.c b/app/pdb/gradient-select-cmds.c index ca83f48fa8..9e5880a0c8 100644 --- a/app/pdb/gradient-select-cmds.c +++ b/app/pdb/gradient-select-cmds.c @@ -50,25 +50,25 @@ gradients_popup_invoker (GimpProcedure *procedure, gboolean success = TRUE; const gchar *gradient_callback; const gchar *popup_title; - const gchar *initial_gradient; - gint sample_size; + const gchar *initial_gradient_name; gradient_callback = g_value_get_string (gimp_value_array_index (args, 0)); popup_title = g_value_get_string (gimp_value_array_index (args, 1)); - initial_gradient = g_value_get_string (gimp_value_array_index (args, 2)); - sample_size = g_value_get_int (gimp_value_array_index (args, 3)); + initial_gradient_name = g_value_get_string (gimp_value_array_index (args, 2)); if (success) { - if (sample_size < 1 || sample_size > 10000) - sample_size = GIMP_GRADIENT_DEFAULT_SAMPLE_SIZE; + /* Formerly, this procedure had another parameter: + * the sample size of the gradient's data passed in the changed callback. + * Now the sample size is determined by core, and in the future, + * the callback won't return a sample of the data at all. + */ if (gimp->no_interface || ! gimp_pdb_lookup_procedure (gimp->pdb, gradient_callback) || ! gimp_pdb_dialog_new (gimp, context, progress, gimp_data_factory_get_container (gimp->gradient_factory), - popup_title, gradient_callback, initial_gradient, - "sample-size", sample_size, + popup_title, gradient_callback, initial_gradient_name, NULL)) success = FALSE; } @@ -144,8 +144,8 @@ register_gradient_select_procs (GimpPDB *pdb) gimp_object_set_static_name (GIMP_OBJECT (procedure), "gimp-gradients-popup"); gimp_procedure_set_static_help (procedure, - "Invokes the Gimp gradients selection.", - "This procedure opens the gradient selection dialog.", + "Invokes the Gimp gradients selection dialog.", + "Opens a dialog letting a user choose a gradient.", NULL); gimp_procedure_set_static_attribution (procedure, "Andy Thomas", @@ -154,7 +154,7 @@ register_gradient_select_procs (GimpPDB *pdb) gimp_procedure_add_argument (procedure, gimp_param_spec_string ("gradient-callback", "gradient callback", - "The callback PDB proc to call when gradient selection is made", + "The callback PDB proc to call when user chooses a gradient", FALSE, FALSE, TRUE, NULL, GIMP_PARAM_READWRITE)); @@ -166,18 +166,12 @@ register_gradient_select_procs (GimpPDB *pdb) NULL, GIMP_PARAM_READWRITE)); gimp_procedure_add_argument (procedure, - gimp_param_spec_string ("initial-gradient", - "initial gradient", - "The name of the gradient to set as the first selected", + gimp_param_spec_string ("initial-gradient-name", + "initial gradient name", + "The name of the initial gradient choice", FALSE, TRUE, FALSE, NULL, GIMP_PARAM_READWRITE)); - gimp_procedure_add_argument (procedure, - g_param_spec_int ("sample-size", - "sample size", - "Size of the sample to return when the gradient is changed", - 1, 10000, 1, - GIMP_PARAM_READWRITE | GIMP_PARAM_NO_VALIDATE)); gimp_pdb_register_procedure (pdb, procedure); g_object_unref (procedure); @@ -189,7 +183,7 @@ register_gradient_select_procs (GimpPDB *pdb) "gimp-gradients-close-popup"); gimp_procedure_set_static_help (procedure, "Close the gradient selection dialog.", - "This procedure closes an opened gradient selection dialog.", + "Closes an open gradient selection dialog.", NULL); gimp_procedure_set_static_attribution (procedure, "Andy Thomas", diff --git a/app/pdb/palette-select-cmds.c b/app/pdb/palette-select-cmds.c index 01e0c84a66..2b8b095abe 100644 --- a/app/pdb/palette-select-cmds.c +++ b/app/pdb/palette-select-cmds.c @@ -49,11 +49,11 @@ palettes_popup_invoker (GimpProcedure *procedure, gboolean success = TRUE; const gchar *palette_callback; const gchar *popup_title; - const gchar *initial_palette; + const gchar *initial_palette_name; palette_callback = g_value_get_string (gimp_value_array_index (args, 0)); popup_title = g_value_get_string (gimp_value_array_index (args, 1)); - initial_palette = g_value_get_string (gimp_value_array_index (args, 2)); + initial_palette_name = g_value_get_string (gimp_value_array_index (args, 2)); if (success) { @@ -61,7 +61,7 @@ palettes_popup_invoker (GimpProcedure *procedure, ! gimp_pdb_lookup_procedure (gimp->pdb, palette_callback) || ! gimp_pdb_dialog_new (gimp, context, progress, gimp_data_factory_get_container (gimp->palette_factory), - popup_title, palette_callback, initial_palette, + popup_title, palette_callback, initial_palette_name, NULL)) success = FALSE; } @@ -137,8 +137,8 @@ register_palette_select_procs (GimpPDB *pdb) gimp_object_set_static_name (GIMP_OBJECT (procedure), "gimp-palettes-popup"); gimp_procedure_set_static_help (procedure, - "Invokes the Gimp palette selection.", - "This procedure opens the palette selection dialog.", + "Invokes the Gimp palette selection dialog.", + "Opens a dialog letting a user choose a palette.", NULL); gimp_procedure_set_static_attribution (procedure, "Michael Natterer ", @@ -147,7 +147,7 @@ register_palette_select_procs (GimpPDB *pdb) gimp_procedure_add_argument (procedure, gimp_param_spec_string ("palette-callback", "palette callback", - "The callback PDB proc to call when palette selection is made", + "The callback PDB proc to call when user chooses a palette", FALSE, FALSE, TRUE, NULL, GIMP_PARAM_READWRITE)); @@ -159,9 +159,9 @@ register_palette_select_procs (GimpPDB *pdb) NULL, GIMP_PARAM_READWRITE)); gimp_procedure_add_argument (procedure, - gimp_param_spec_string ("initial-palette", - "initial palette", - "The name of the palette to set as the first selected", + gimp_param_spec_string ("initial-palette-name", + "initial palette name", + "The palette to set as the initial choice.", FALSE, TRUE, FALSE, NULL, GIMP_PARAM_READWRITE)); @@ -176,7 +176,7 @@ register_palette_select_procs (GimpPDB *pdb) "gimp-palettes-close-popup"); gimp_procedure_set_static_help (procedure, "Close the palette selection dialog.", - "This procedure closes an opened palette selection dialog.", + "Closes an open palette selection dialog.", NULL); gimp_procedure_set_static_attribution (procedure, "Michael Natterer ", diff --git a/app/pdb/pattern-select-cmds.c b/app/pdb/pattern-select-cmds.c index 284b4f924c..7790d3ac1a 100644 --- a/app/pdb/pattern-select-cmds.c +++ b/app/pdb/pattern-select-cmds.c @@ -49,11 +49,11 @@ patterns_popup_invoker (GimpProcedure *procedure, gboolean success = TRUE; const gchar *pattern_callback; const gchar *popup_title; - const gchar *initial_pattern; + const gchar *initial_pattern_name; pattern_callback = g_value_get_string (gimp_value_array_index (args, 0)); popup_title = g_value_get_string (gimp_value_array_index (args, 1)); - initial_pattern = g_value_get_string (gimp_value_array_index (args, 2)); + initial_pattern_name = g_value_get_string (gimp_value_array_index (args, 2)); if (success) { @@ -61,7 +61,7 @@ patterns_popup_invoker (GimpProcedure *procedure, ! gimp_pdb_lookup_procedure (gimp->pdb, pattern_callback) || ! gimp_pdb_dialog_new (gimp, context, progress, gimp_data_factory_get_container (gimp->pattern_factory), - popup_title, pattern_callback, initial_pattern, + popup_title, pattern_callback, initial_pattern_name, NULL)) success = FALSE; } @@ -138,7 +138,7 @@ register_pattern_select_procs (GimpPDB *pdb) "gimp-patterns-popup"); gimp_procedure_set_static_help (procedure, "Invokes the Gimp pattern selection.", - "This procedure opens the pattern selection dialog.", + "Opens the pattern selection dialog.", NULL); gimp_procedure_set_static_attribution (procedure, "Andy Thomas", @@ -147,7 +147,7 @@ register_pattern_select_procs (GimpPDB *pdb) gimp_procedure_add_argument (procedure, gimp_param_spec_string ("pattern-callback", "pattern callback", - "The callback PDB proc to call when pattern selection is made", + "The callback PDB proc to call when the user chooses a pattern", FALSE, FALSE, TRUE, NULL, GIMP_PARAM_READWRITE)); @@ -159,9 +159,9 @@ register_pattern_select_procs (GimpPDB *pdb) NULL, GIMP_PARAM_READWRITE)); gimp_procedure_add_argument (procedure, - gimp_param_spec_string ("initial-pattern", - "initial pattern", - "The name of the pattern to set as the first selected", + gimp_param_spec_string ("initial-pattern-name", + "initial pattern name", + "The name of the pattern to set as the initial choice", FALSE, TRUE, FALSE, NULL, GIMP_PARAM_READWRITE)); @@ -176,7 +176,7 @@ register_pattern_select_procs (GimpPDB *pdb) "gimp-patterns-close-popup"); gimp_procedure_set_static_help (procedure, "Close the pattern selection dialog.", - "This procedure closes an opened pattern selection dialog.", + "Closes an open pattern selection dialog.", NULL); gimp_procedure_set_static_attribution (procedure, "Andy Thomas", diff --git a/libgimp/Makefile.gi b/libgimp/Makefile.gi index e4217d64f0..61f85a8b71 100644 --- a/libgimp/Makefile.gi +++ b/libgimp/Makefile.gi @@ -112,14 +112,11 @@ libgimp_introspectable_headers = \ ../libgimp/gimpenums.h \ ${PDB_WRAPPERS_H} \ ../libgimp/gimpbatchprocedure.h \ - ../libgimp/gimpbrushselect.h \ ../libgimp/gimpchannel.h \ ../libgimp/gimpdisplay.h \ ../libgimp/gimpdrawable.h \ ../libgimp/gimpfileprocedure.h \ - ../libgimp/gimpfontselect.h \ ../libgimp/gimpgimprc.h \ - ../libgimp/gimpgradientselect.h \ ../libgimp/gimpimage.h \ ../libgimp/gimpimagecolorprofile.h \ ../libgimp/gimpimagemetadata.h \ @@ -128,16 +125,15 @@ libgimp_introspectable_headers = \ ../libgimp/gimplayer.h \ ../libgimp/gimplayermask.h \ ../libgimp/gimploadprocedure.h \ - ../libgimp/gimppaletteselect.h \ ../libgimp/gimpparamspecs.h \ ../libgimp/gimpparamspecs-resource.h \ - ../libgimp/gimppatternselect.h \ ../libgimp/gimppdb.h \ ../libgimp/gimpplugin.h \ ../libgimp/gimpprocedure.h \ ../libgimp/gimpprocedureconfig.h \ ../libgimp/gimpprogress.h \ ../libgimp/gimpresource.h \ + ../libgimp/gimpresourceselect.h \ ../libgimp/gimpresource-subclass.h \ ../libgimp/gimpsaveprocedure.h \ ../libgimp/gimpselection.h \ @@ -151,14 +147,11 @@ libgimp_introspectable = \ ../libgimp/gimp.c \ ${PDB_WRAPPERS_C} \ ../libgimp/gimpbatchprocedure.c \ - ../libgimp/gimpbrushselect.c \ ../libgimp/gimpchannel.c \ ../libgimp/gimpdisplay.c \ ../libgimp/gimpdrawable.c \ ../libgimp/gimpfileprocedure.c \ - ../libgimp/gimpfontselect.c \ ../libgimp/gimpgimprc.c \ - ../libgimp/gimpgradientselect.c \ ../libgimp/gimpimage.c \ ../libgimp/gimpimagecolorprofile.c \ ../libgimp/gimpimagemetadata.c \ @@ -168,15 +161,14 @@ libgimp_introspectable = \ ../libgimp/gimplayer.c \ ../libgimp/gimplayermask.c \ ../libgimp/gimploadprocedure.c \ - ../libgimp/gimppaletteselect.c \ ../libgimp/gimpparamspecs.c \ - ../libgimp/gimppatternselect.c \ ../libgimp/gimppdb.c \ ../libgimp/gimpplugin.c \ ../libgimp/gimpprocedure.c \ ../libgimp/gimpprocedureconfig.c \ ../libgimp/gimpprogress.c \ ../libgimp/gimpresource.c \ + ../libgimp/gimpresourceselect.c \ ../libgimp/gimpresource-subclass.c \ ../libgimp/gimpsaveprocedure.c \ ../libgimp/gimpselection.c \ @@ -201,9 +193,10 @@ libgimpui_introspectable_headers = \ ../libgimp/gimpproceduredialog.h \ ../libgimp/gimpprocview.h \ ../libgimp/gimpprogressbar.h \ - ../libgimp/gimppropbrushchooser.h \ + ../libgimp/gimppropchooser.h \ + ../libgimp/gimppropchooserfactory.h \ + ../libgimp/gimpresourceselectbutton.h \ ../libgimp/gimpsaveproceduredialog.h \ - ../libgimp/gimpselectbutton.h \ ../libgimp/gimpzoompreview.h libgimpui_introspectable = \ @@ -222,8 +215,9 @@ libgimpui_introspectable = \ ../libgimp/gimpprocbrowserdialog.c \ ../libgimp/gimpproceduredialog.c \ ../libgimp/gimpprocview.c \ - ../libgimp/gimppropbrushchooser.c \ + ../libgimp/gimppropchooser.c \ + ../libgimp/gimppropchooserfactory.c \ ../libgimp/gimpsaveproceduredialog.c \ ../libgimp/gimpprogressbar.c \ - ../libgimp/gimpselectbutton.c \ + ../libgimp/gimpresourceselectbutton.c \ ../libgimp/gimpzoompreview.c diff --git a/libgimp/gimp.def b/libgimp/gimp.def index 4c185fadf4..6659774f40 100644 --- a/libgimp/gimp.def +++ b/libgimp/gimp.def @@ -25,8 +25,6 @@ EXPORTS gimp_brush_is_valid gimp_brush_new gimp_brush_rename - gimp_brush_select_destroy - gimp_brush_select_new gimp_brush_set_angle gimp_brush_set_aspect_ratio gimp_brush_set_hardness @@ -299,8 +297,6 @@ EXPORTS gimp_font_get_type gimp_font_id_is_valid gimp_font_is_valid - gimp_font_select_destroy - gimp_font_select_new gimp_fonts_close_popup gimp_fonts_get_list gimp_fonts_popup @@ -355,8 +351,6 @@ EXPORTS gimp_gradient_segment_set_middle_pos gimp_gradient_segment_set_right_color gimp_gradient_segment_set_right_pos - gimp_gradient_select_destroy - gimp_gradient_select_new gimp_gradients_close_popup gimp_gradients_get_list gimp_gradients_popup @@ -661,8 +655,6 @@ EXPORTS gimp_palette_is_valid gimp_palette_new gimp_palette_rename - gimp_palette_select_destroy - gimp_palette_select_new gimp_palette_set_columns gimp_palettes_close_popup gimp_palettes_get_list @@ -681,6 +673,7 @@ EXPORTS gimp_param_layer_mask_get_type gimp_param_palette_get_type gimp_param_pattern_get_type + gimp_param_resource_get_type gimp_param_selection_get_type gimp_param_spec_brush gimp_param_spec_channel @@ -695,6 +688,7 @@ EXPORTS gimp_param_spec_layer_mask gimp_param_spec_palette gimp_param_spec_pattern + gimp_param_spec_resource gimp_param_spec_selection gimp_param_spec_text_layer gimp_param_spec_vectors @@ -705,8 +699,6 @@ EXPORTS gimp_pattern_get_type gimp_pattern_id_is_valid gimp_pattern_is_valid - gimp_pattern_select_destroy - gimp_pattern_select_new gimp_patterns_close_popup gimp_patterns_get_list gimp_patterns_popup @@ -818,6 +810,9 @@ EXPORTS gimp_quit gimp_resource_get_id gimp_resource_get_type + gimp_resource_select_destroy + gimp_resource_select_new + gimp_resource_select_set gimp_save_procedure_get_support_comment gimp_save_procedure_get_support_exif gimp_save_procedure_get_support_iptc diff --git a/libgimp/gimp.h b/libgimp/gimp.h index 5197f295d2..197954e3bb 100644 --- a/libgimp/gimp.h +++ b/libgimp/gimp.h @@ -37,13 +37,10 @@ #include #include -#include #include #include #include -#include #include -#include #include #include #include @@ -52,10 +49,8 @@ #include #include #include -#include #include #include -#include #include #include #include @@ -69,6 +64,11 @@ #include #include +/* Resources and their widgets. Order important. */ +#include +#include +#include + #include #undef __GIMP_H_INSIDE__ diff --git a/libgimp/gimpbrushselect.c b/libgimp/gimpbrushselect.c deleted file mode 100644 index 101f5a1b18..0000000000 --- a/libgimp/gimpbrushselect.c +++ /dev/null @@ -1,265 +0,0 @@ -/* LIBGIMP - The GIMP Library - * Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball - * - * gimpbrushselect.c - * - * This library is free software: you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library. If not, see - * . - */ - -#include "config.h" - -#include "gimp.h" - - -typedef struct -{ - gchar *brush_callback; - guint idle_id; - gchar *brush_name; - gdouble opacity; - gint spacing; - gint paint_mode; - gint width; - gint height; - gint brush_mask_size; - guchar *brush_mask_data; - GimpRunBrushCallback callback; - gboolean closing; - gpointer data; - GDestroyNotify data_destroy; -} GimpBrushData; - - -/* local function prototypes */ - -static void gimp_brush_data_free (GimpBrushData *data); - -static GimpValueArray * gimp_temp_brush_run (GimpProcedure *procedure, - const GimpValueArray *args, - gpointer run_data); -static gboolean gimp_temp_brush_idle (GimpBrushData *data); - - -/* public functions */ - -/** - * gimp_brush_select_new: - * @title: Title of the brush selection dialog. - * @brush_name: The name of the brush to set as the first selected. - * @opacity: The initial opacity of the brush. - * @spacing: The initial spacing of the brush (if < 0 then use brush default spacing). - * @paint_mode: The initial paint mode. - * @callback: (scope notified): The callback function to call each time a settings change. - * @data: (closure callback): the run_data given to @callback. - * @data_destroy: (destroy data): the destroy function for @data. - * - * Invokes a brush selection dialog then run @callback with the selected - * brush, various settings and user's @data. - * - * Returns: (transfer none): the name of a temporary PDB procedure. The - * string belongs to the brush selection dialog and will be - * freed automatically when the dialog is closed. - **/ -const gchar * -gimp_brush_select_new (const gchar *title, - const gchar *brush_name, - gdouble opacity, - gint spacing, - GimpLayerMode paint_mode, - GimpRunBrushCallback callback, - gpointer data, - GDestroyNotify data_destroy) -{ - GimpPlugIn *plug_in = gimp_get_plug_in (); - GimpProcedure *procedure; - gchar *brush_callback; - GimpBrushData *brush_data; - - brush_callback = gimp_pdb_temp_procedure_name (gimp_get_pdb ()); - - brush_data = g_slice_new0 (GimpBrushData); - - brush_data->brush_callback = brush_callback; - brush_data->callback = callback; - brush_data->data = data; - brush_data->data_destroy = data_destroy; - - procedure = gimp_procedure_new (plug_in, - brush_callback, - GIMP_PDB_PROC_TYPE_TEMPORARY, - gimp_temp_brush_run, - brush_data, - (GDestroyNotify) - gimp_brush_data_free); - - GIMP_PROC_ARG_STRING (procedure, "brush-name", - "Brush name", - "The brush name", - NULL, - G_PARAM_READWRITE); - - GIMP_PROC_ARG_DOUBLE (procedure, "opacity", - "Opacity", - NULL, - 0.0, 100.0, 100.0, - G_PARAM_READWRITE); - - GIMP_PROC_ARG_INT (procedure, "spacing", - "Spacing", - NULL, - -1, 1000, 20, - G_PARAM_READWRITE); - - GIMP_PROC_ARG_ENUM (procedure, "paint-mode", - "Paint mode", - NULL, - GIMP_TYPE_LAYER_MODE, - GIMP_LAYER_MODE_NORMAL, - G_PARAM_READWRITE); - - GIMP_PROC_ARG_INT (procedure, "mask-width", - "Brush width", - NULL, - 0, 10000, 0, - G_PARAM_READWRITE); - - GIMP_PROC_ARG_INT (procedure, "mask-height", - "Brush height", - NULL, - 0, 10000, 0, - G_PARAM_READWRITE); - - GIMP_PROC_ARG_INT (procedure, "mask-len", - "Mask length", - "Length of brush mask data", - 0, G_MAXINT, 0, - G_PARAM_READWRITE); - - GIMP_PROC_ARG_UINT8_ARRAY (procedure, "mask-data", - "Mask data", - "The brush mask data", - G_PARAM_READWRITE); - - GIMP_PROC_ARG_BOOLEAN (procedure, "closing", - "Closing", - "If the dialog was closing", - FALSE, - G_PARAM_READWRITE); - - gimp_plug_in_add_temp_procedure (plug_in, procedure); - g_object_unref (procedure); - - if (gimp_brushes_popup (brush_callback, title, brush_name, - opacity, spacing, paint_mode)) - { - /* Allow callbacks to be watched */ - gimp_plug_in_extension_enable (plug_in); - - return brush_callback; - } - - gimp_plug_in_remove_temp_procedure (plug_in, brush_callback); - - return NULL; -} - -void -gimp_brush_select_destroy (const gchar *brush_callback) -{ - GimpPlugIn *plug_in = gimp_get_plug_in (); - - g_return_if_fail (brush_callback != NULL); - - gimp_plug_in_remove_temp_procedure (plug_in, brush_callback); -} - - -/* private functions */ - -static void -gimp_brush_data_free (GimpBrushData *data) -{ - if (data->idle_id) - g_source_remove (data->idle_id); - - if (data->brush_callback) - { - gimp_brushes_close_popup (data->brush_callback); - g_free (data->brush_callback); - } - - g_free (data->brush_name); - g_free (data->brush_mask_data); - - if (data->data_destroy) - data->data_destroy (data->data); - - g_slice_free (GimpBrushData, data); -} - -static GimpValueArray * -gimp_temp_brush_run (GimpProcedure *procedure, - const GimpValueArray *args, - gpointer run_data) -{ - GimpBrushData *data = run_data; - - g_free (data->brush_name); - g_free (data->brush_mask_data); - - data->brush_name = GIMP_VALUES_DUP_STRING (args, 0); - data->opacity = GIMP_VALUES_GET_DOUBLE (args, 1); - data->spacing = GIMP_VALUES_GET_INT (args, 2); - data->paint_mode = GIMP_VALUES_GET_ENUM (args, 3); - data->width = GIMP_VALUES_GET_INT (args, 4); - data->height = GIMP_VALUES_GET_INT (args, 5); - data->brush_mask_size = GIMP_VALUES_GET_INT (args, 6); - data->brush_mask_data = GIMP_VALUES_DUP_UINT8_ARRAY (args, 7); - data->closing = GIMP_VALUES_GET_BOOLEAN (args, 8); - - if (! data->idle_id) - data->idle_id = g_idle_add ((GSourceFunc) gimp_temp_brush_idle, data); - - return gimp_procedure_new_return_values (procedure, GIMP_PDB_SUCCESS, NULL); -} - -static gboolean -gimp_temp_brush_idle (GimpBrushData *data) -{ - data->idle_id = 0; - - if (data->callback) - data->callback (data->brush_name, - data->opacity, - data->spacing, - data->paint_mode, - data->width, - data->height, - data->brush_mask_size, - data->brush_mask_data, - data->closing, - data->data); - - if (data->closing) - { - gchar *brush_callback = data->brush_callback; - - data->brush_callback = NULL; - gimp_brush_select_destroy (brush_callback); - g_free (brush_callback); - } - - return G_SOURCE_REMOVE; -} diff --git a/libgimp/gimpbrushselect.h b/libgimp/gimpbrushselect.h deleted file mode 100644 index 6ed7916653..0000000000 --- a/libgimp/gimpbrushselect.h +++ /dev/null @@ -1,68 +0,0 @@ -/* LIBGIMP - The GIMP Library - * Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball - * - * gimpbrushselect.h - * - * This library is free software: you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library. If not, see - * . - */ - -#if !defined (__GIMP_H_INSIDE__) && !defined (GIMP_COMPILATION) -#error "Only can be included directly." -#endif - -#ifndef __GIMP_BRUSH_SELECT_H__ -#define __GIMP_BRUSH_SELECT_H__ - -G_BEGIN_DECLS - -/** - * GimpRunBrushCallback: - * @brush_name: Name of the brush - * @opacity: Opacity - * @spacing: Spacing - * @paint_mode: Paint mode - * @width: width - * @height: height - * @mask_size: Mask size. - * @mask_data: (array length=mask_size): Mask data - * @dialog_closing: Dialog closing? - * @user_data: (closure): user data - */ -typedef void (* GimpRunBrushCallback) (const gchar *brush_name, - gdouble opacity, - gint spacing, - GimpLayerMode paint_mode, - gint width, - gint height, - gint mask_size, - const guchar *mask_data, - gboolean dialog_closing, - gpointer user_data); - - -const gchar * gimp_brush_select_new (const gchar *title, - const gchar *brush_name, - gdouble opacity, - gint spacing, - GimpLayerMode paint_mode, - GimpRunBrushCallback callback, - gpointer data, - GDestroyNotify data_destroy); -void gimp_brush_select_destroy (const gchar *brush_callback); - - -G_END_DECLS - -#endif /* __GIMP_BRUSH_SELECT_H__ */ diff --git a/libgimp/gimpbrushselect_pdb.c b/libgimp/gimpbrushselect_pdb.c index 0ab224b9dc..8719854f11 100644 --- a/libgimp/gimpbrushselect_pdb.c +++ b/libgimp/gimpbrushselect_pdb.c @@ -30,34 +30,29 @@ /** * SECTION: gimpbrushselect * @title: gimpbrushselect - * @short_description: Functions providing a brush selection dialog. + * @short_description: Methods of a font chooser dialog * - * Functions providing a brush selection dialog. + * A dialog letting a user choose a brush. Read more at + * gimpfontselect. **/ /** * gimp_brushes_popup: - * @brush_callback: The callback PDB proc to call when brush selection is made. + * @brush_callback: The callback PDB proc to call when user chooses a brush. * @popup_title: Title of the brush selection dialog. - * @initial_brush: The name of the brush to set as the first selected. - * @opacity: The initial opacity of the brush. - * @spacing: The initial spacing of the brush (if < 0 then use brush default spacing). - * @paint_mode: The initial paint mode. + * @initial_brush_name: The name of the brush to set as the initial choice. * - * Invokes the Gimp brush selection. + * Invokes the GIMP brush selection dialog. * - * This procedure opens the brush selection dialog. + * Opens a dialog letting a user choose a brush. * * Returns: TRUE on success. **/ gboolean -gimp_brushes_popup (const gchar *brush_callback, - const gchar *popup_title, - const gchar *initial_brush, - gdouble opacity, - gint spacing, - GimpLayerMode paint_mode) +gimp_brushes_popup (const gchar *brush_callback, + const gchar *popup_title, + const gchar *initial_brush_name) { GimpValueArray *args; GimpValueArray *return_vals; @@ -66,10 +61,7 @@ gimp_brushes_popup (const gchar *brush_callback, args = gimp_value_array_new_from_types (NULL, G_TYPE_STRING, brush_callback, G_TYPE_STRING, popup_title, - G_TYPE_STRING, initial_brush, - G_TYPE_DOUBLE, opacity, - G_TYPE_INT, spacing, - GIMP_TYPE_LAYER_MODE, paint_mode, + G_TYPE_STRING, initial_brush_name, G_TYPE_NONE); return_vals = gimp_pdb_run_procedure_array (gimp_get_pdb (), @@ -90,7 +82,7 @@ gimp_brushes_popup (const gchar *brush_callback, * * Close the brush selection dialog. * - * This procedure closes an opened brush selection dialog. + * Closes an open brush selection dialog. * * Returns: TRUE on success. **/ @@ -121,22 +113,16 @@ gimp_brushes_close_popup (const gchar *brush_callback) * gimp_brushes_set_popup: * @brush_callback: The name of the callback registered for this pop-up. * @brush_name: The name of the brush to set as selected. - * @opacity: The initial opacity of the brush. - * @spacing: The initial spacing of the brush (if < 0 then use brush default spacing). - * @paint_mode: The initial paint mode. * - * Sets the current brush in a brush selection dialog. + * Sets the selected brush in a brush selection dialog. * - * Sets the current brush in a brush selection dialog. + * Sets the selected brush in a brush selection dialog. * * Returns: TRUE on success. **/ gboolean -gimp_brushes_set_popup (const gchar *brush_callback, - const gchar *brush_name, - gdouble opacity, - gint spacing, - GimpLayerMode paint_mode) +gimp_brushes_set_popup (const gchar *brush_callback, + const gchar *brush_name) { GimpValueArray *args; GimpValueArray *return_vals; @@ -145,9 +131,6 @@ gimp_brushes_set_popup (const gchar *brush_callback, args = gimp_value_array_new_from_types (NULL, G_TYPE_STRING, brush_callback, G_TYPE_STRING, brush_name, - G_TYPE_DOUBLE, opacity, - G_TYPE_INT, spacing, - GIMP_TYPE_LAYER_MODE, paint_mode, G_TYPE_NONE); return_vals = gimp_pdb_run_procedure_array (gimp_get_pdb (), diff --git a/libgimp/gimpbrushselect_pdb.h b/libgimp/gimpbrushselect_pdb.h index ae401f2d59..f47165bdf0 100644 --- a/libgimp/gimpbrushselect_pdb.h +++ b/libgimp/gimpbrushselect_pdb.h @@ -32,18 +32,12 @@ G_BEGIN_DECLS /* For information look into the C source or the html documentation */ -gboolean gimp_brushes_popup (const gchar *brush_callback, - const gchar *popup_title, - const gchar *initial_brush, - gdouble opacity, - gint spacing, - GimpLayerMode paint_mode); -gboolean gimp_brushes_close_popup (const gchar *brush_callback); -gboolean gimp_brushes_set_popup (const gchar *brush_callback, - const gchar *brush_name, - gdouble opacity, - gint spacing, - GimpLayerMode paint_mode); +gboolean gimp_brushes_popup (const gchar *brush_callback, + const gchar *popup_title, + const gchar *initial_brush_name); +gboolean gimp_brushes_close_popup (const gchar *brush_callback); +gboolean gimp_brushes_set_popup (const gchar *brush_callback, + const gchar *brush_name); G_END_DECLS diff --git a/libgimp/gimpbrushselectbutton.c b/libgimp/gimpbrushselectbutton.c index 6c89d67770..d529ebc273 100644 --- a/libgimp/gimpbrushselectbutton.c +++ b/libgimp/gimpbrushselectbutton.c @@ -37,437 +37,239 @@ /** * SECTION: gimpbrushselectbutton - * @title: gimpbrushselectbutton - * @short_description: A button that pops up a brush selection dialog. + * @title: GimpBrushSelectButton + * @short_description: A button which pops up a brush selection dialog. * - * A button that pops up a brush selection dialog. + * A button which pops up a brush selection dialog. **/ - #define CELL_SIZE 20 - -enum +/* A B&W image. mask_data is allocated and must be freed. */ +typedef struct _PreviewBitmap { - BRUSH_SET, - LAST_SIGNAL -}; - -enum -{ - PROP_0, - PROP_TITLE, - PROP_BRUSH_NAME, - PROP_BRUSH_OPACITY, - PROP_BRUSH_SPACING, - PROP_BRUSH_PAINT_MODE, - N_PROPS -}; - - -struct _GimpBrushSelectButtonPrivate -{ - gchar *title; - - gchar *brush_name; /* Local copy */ - gdouble opacity; - gint spacing; - GimpLayerMode paint_mode; gint width; gint height; - guchar *mask_data; /* local copy */ + guchar *mask_data; +} _PreviewBitmap; - GtkWidget *inside; - GtkWidget *preview; - GtkWidget *popup; +struct _GimpBrushSelectButton +{ + /* !! Not a pointer, is contained. */ + GimpResourceSelectButton parent_instance; + + /* Partial view of brush image. Receives drag. Receives mouse down to popup zoom. */ + GtkWidget *peephole_view; + GtkWidget *popup; /* Popup showing entire, full-size brush image. */ + GtkWidget *browse_button; /* Clickable area that popups remote chooser. */ }; +/* local */ -/* local function prototypes */ +/* implement virtual. */ +static void gimp_brush_select_button_finalize (GObject *object); +static void gimp_brush_select_button_draw_interior (GimpResourceSelectButton *self); -static void gimp_brush_select_button_finalize (GObject *object); +/* init methods. */ +static void gimp_brush_select_button_embed_interior (GimpBrushSelectButton *self); +static void gimp_brush_select_button_set_drag_target (GimpBrushSelectButton *self); -static void gimp_brush_select_button_set_property (GObject *object, - guint property_id, - const GValue *value, - GParamSpec *pspec); -static void gimp_brush_select_button_get_property (GObject *object, - guint property_id, - GValue *value, - GParamSpec *pspec); +static GtkWidget *gimp_brush_select_button_create_interior (GimpBrushSelectButton *self); -static void gimp_brush_select_button_clicked (GimpBrushSelectButton *button); +/* Event handlers. */ +static void gimp_brush_select_on_preview_resize (GimpBrushSelectButton *button); +static gboolean gimp_brush_select_on_preview_events (GtkWidget *widget, + GdkEvent *event, + GimpBrushSelectButton *button); -static void gimp_brush_select_button_callback (const gchar *brush_name, - gdouble opacity, - gint spacing, - GimpLayerMode paint_mode, - gint width, - gint height, - gint mask_size, - const guchar *mask_data, - gboolean dialog_closing, - gpointer user_data); +/* local drawing methods. */ +static void gimp_brush_select_preview_draw (GimpPreviewArea *area, + gint x, + gint y, + _PreviewBitmap mask, + gint rowstride); +static void gimp_brush_select_preview_fill_draw (GtkWidget *preview, + _PreviewBitmap mask); -static void gimp_brush_select_preview_resize (GimpBrushSelectButton *button); -static gboolean gimp_brush_select_preview_events (GtkWidget *widget, - GdkEvent *event, - GimpBrushSelectButton *button); -static void gimp_brush_select_preview_draw (GimpPreviewArea *area, - gint x, - gint y, - gint width, - gint height, - const guchar *mask_data, - gint rowstride); -static void gimp_brush_select_preview_update (GtkWidget *preview, - gint brush_width, - gint brush_height, - const guchar *mask_data); +static void gimp_brush_select_button_draw (GimpBrushSelectButton *self); +static _PreviewBitmap gimp_brush_select_button_get_brush_bitmap (GimpBrushSelectButton *self); +/* Popup methods. */ static void gimp_brush_select_button_open_popup (GimpBrushSelectButton *button, gint x, gint y); static void gimp_brush_select_button_close_popup (GimpBrushSelectButton *button); -static void gimp_brush_select_drag_data_received (GimpBrushSelectButton *button, - GdkDragContext *context, - gint x, - gint y, - GtkSelectionData *selection, - guint info, - guint time); - -static GtkWidget * gimp_brush_select_button_create_inside (GimpBrushSelectButton *button); -static const GtkTargetEntry target = { "application/x-gimp-brush-name", 0 }; -static guint brush_button_signals[LAST_SIGNAL] = { 0 }; -static GParamSpec *brush_button_props[N_PROPS] = { NULL, }; +/* A GtkTargetEntry has a string and two ints. + * This is one, but we treat it as an array. + */ +static const GtkTargetEntry drag_target = { "application/x-gimp-brush-name", 0, 0 }; - -G_DEFINE_TYPE_WITH_PRIVATE (GimpBrushSelectButton, gimp_brush_select_button, - GIMP_TYPE_SELECT_BUTTON) +G_DEFINE_FINAL_TYPE (GimpBrushSelectButton, + gimp_brush_select_button, + GIMP_TYPE_RESOURCE_SELECT_BUTTON) static void gimp_brush_select_button_class_init (GimpBrushSelectButtonClass *klass) { - GObjectClass *object_class = G_OBJECT_CLASS (klass); - GimpSelectButtonClass *select_button_class = GIMP_SELECT_BUTTON_CLASS (klass); + /* Alias cast klass to super classes. */ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + GimpResourceSelectButtonClass *superclass = GIMP_RESOURCE_SELECT_BUTTON_CLASS (klass); + + g_debug ("%s called", G_STRFUNC); object_class->finalize = gimp_brush_select_button_finalize; - object_class->set_property = gimp_brush_select_button_set_property; - object_class->get_property = gimp_brush_select_button_get_property; - select_button_class->select_destroy = gimp_brush_select_destroy; + /* Implement pure virtual functions. */ + superclass->draw_interior = gimp_brush_select_button_draw_interior; - klass->brush_set = NULL; + /* Set data member of class. */ + superclass->resource_type = GIMP_TYPE_BRUSH; - /** - * GimpBrushSelectButton:title: - * - * The title to be used for the brush selection popup dialog. - * - * Since: 2.4 + /* We don't define property getter/setters: use superclass getter/setters. + * But super property name is "resource", not "brush" */ - brush_button_props[PROP_TITLE] = g_param_spec_string ("title", - "Title", - "The title to be used for the brush selection popup dialog", - _("Brush Selection"), - GIMP_PARAM_READWRITE | - G_PARAM_CONSTRUCT_ONLY); - - /** - * GimpBrushSelectButton:brush-name: - * - * The name of the currently selected brush. - * - * Since: 2.4 - */ - brush_button_props[PROP_BRUSH_NAME] = g_param_spec_string ("brush-name", - "Brush name", - "The name of the currently selected brush", - NULL, - GIMP_PARAM_READWRITE); - - /** - * GimpBrushSelectButton:opacity: - * - * The opacity of the currently selected brush. - * - * Since: 2.4 - */ - brush_button_props[PROP_BRUSH_OPACITY] = g_param_spec_double ("brush-opacity", - "Brush opacity", - "The opacity of the currently selected brush", - -1.0, 100.0, -1.0, - GIMP_PARAM_READWRITE); - - /** - * GimpBrushSelectButton:spacing: - * - * The spacing of the currently selected brush. - * - * Since: 2.4 - */ - brush_button_props[PROP_BRUSH_SPACING] = g_param_spec_int ("brush-spacing", - "Brush spacing", - "The spacing of the currently selected brush", - -G_MAXINT, 1000, -1, - GIMP_PARAM_READWRITE); - - /** - * GimpBrushSelectButton:paint-mode: - * - * The paint mode. - * - * Since: 2.4 - */ - brush_button_props[PROP_BRUSH_PAINT_MODE] = g_param_spec_int ("brush-paint-mode", - "Brush paint mode", - "The paint mode of the currently selected brush", - -1, GIMP_LAYER_MODE_LUMINANCE, - -1, - GIMP_PARAM_READWRITE); - - g_object_class_install_properties (object_class, N_PROPS, brush_button_props); - - /** - * GimpBrushSelectButton::brush-set: - * @widget: the object which received the signal. - * @brush_name: the name of the currently selected brush. - * @opacity: opacity of the brush - * @spacing: spacing of the brush - * @paint_mode: paint mode of the brush - * @width: width of the brush - * @height: height of the brush - * @mask_data: (array) (element-type guchar): brush mask data - * @dialog_closing: whether the dialog was closed or not. - * - * The ::brush-set signal is emitted when the user selects a brush. - * - * Since: 2.4 - */ - brush_button_signals[BRUSH_SET] = - g_signal_new ("brush-set", - G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_FIRST, - G_STRUCT_OFFSET (GimpBrushSelectButtonClass, brush_set), - NULL, NULL, - _gimpui_marshal_VOID__STRING_DOUBLE_INT_INT_INT_INT_POINTER_BOOLEAN, - G_TYPE_NONE, 8, - G_TYPE_STRING, - G_TYPE_DOUBLE, - G_TYPE_INT, - G_TYPE_INT, - G_TYPE_INT, - G_TYPE_INT, - G_TYPE_POINTER, - G_TYPE_BOOLEAN); } static void -gimp_brush_select_button_init (GimpBrushSelectButton *button) +gimp_brush_select_button_init (GimpBrushSelectButton *self) { - GimpBrushSelectButtonPrivate *priv; - gint mask_bpp; - gint mask_data_size; - gint color_bpp; - gint color_data_size; - guint8 *color_data; + g_debug ("%s called", G_STRFUNC); - button->priv = gimp_brush_select_button_get_instance_private (button); + /* Specialize: + * - embed our widget interior instance to super widget instance. + * - connect our widget to dnd + * These will call superclass methods. + * These are on instance, not our subclass. + */ + gimp_brush_select_button_embed_interior (self); - priv = button->priv; + gimp_brush_select_button_set_drag_target (self); - priv->brush_name = gimp_context_get_brush (); - gimp_brush_get_pixels (priv->brush_name, - &priv->width, - &priv->height, - &mask_bpp, - &mask_data_size, - &priv->mask_data, - &color_bpp, - &color_data_size, - &color_data); - - if (color_data) - g_free (color_data); - - priv->inside = gimp_brush_select_button_create_inside (button); - gtk_container_add (GTK_CONTAINER (button), priv->inside); + /* Tell super which sub widget pops up remote chooser. + * Only the browse_button. + * A click in the peephole_view does something else: popup a zoom. + */ + gimp_resource_select_button_set_clickable (GIMP_RESOURCE_SELECT_BUTTON (self), + self->browse_button); } /** * gimp_brush_select_button_new: - * @title: (nullable): Title of the dialog to use or %NULL means to use the default - * title. - * @brush_name: (nullable): Initial brush name or %NULL to use current selection. - * @opacity: Initial opacity. -1 means to use current opacity. - * @spacing: Initial spacing. -1 means to use current spacing. - * @paint_mode: Initial paint mode. -1 means to use current paint mode. + * @title: (nullable): Title of the dialog to use or %NULL to use the default title. + * @resource: (nullable): Initial brush. * - * Creates a new #GtkWidget that completely controls the selection of - * a brush. This widget is suitable for placement in a table in a - * plug-in dialog. + * Creates a new #GtkWidget that lets a user choose a brush. + * You can put this widget in a plug-in dialog. + * + * When brush is NULL, initial choice is from context. * * Returns: A #GtkWidget that you can use in your UI. * * Since: 2.4 */ GtkWidget * -gimp_brush_select_button_new (const gchar *title, - const gchar *brush_name, - gdouble opacity, - gint spacing, - GimpLayerMode paint_mode) +gimp_brush_select_button_new (const gchar *title, + GimpResource *resource) { - GtkWidget *button; + GtkWidget *self; - if (title) - button = g_object_new (GIMP_TYPE_BRUSH_SELECT_BUTTON, - "title", title, - "brush-name", brush_name, - "brush-opacity", opacity, - "brush-spacing", spacing, - "brush-paint-mode", paint_mode, - NULL); - else - button = g_object_new (GIMP_TYPE_BRUSH_SELECT_BUTTON, - "brush-name", brush_name, - "brush-opacity", opacity, - "brush-spacing", spacing, - "brush-paint-mode", paint_mode, - NULL); + g_debug ("%s called", G_STRFUNC); - return button; + if (resource == NULL) + { + g_debug ("%s defaulting brush from context", G_STRFUNC); + resource = GIMP_RESOURCE (gimp_context_get_brush ()); + } + g_assert (resource != NULL); + /* This method is polymorphic, so a factory can call it, but requires Brush. */ + g_return_val_if_fail (GIMP_IS_BRUSH (resource), NULL); + + /* Create instance of self (not super.) + * This will call superclass init, self class init, superclass init, and instance init. + * Self subclass class_init will specialize by implementing virtual funcs + * that open and set remote chooser dialog, and that draw self interior. + * + * !!! property belongs to superclass and is named "resource" + */ + if (title) + self = g_object_new (GIMP_TYPE_BRUSH_SELECT_BUTTON, + "title", title, + "resource", resource, + NULL); + else + self = g_object_new (GIMP_TYPE_BRUSH_SELECT_BUTTON, + "resource", resource, + NULL); + + /* We don't subscribe to events from super. + * Super will queue a draw when it's resource changes. + * Except that the above setting of property happens too late, + * so we now draw the initial resource. + */ + + /* Draw it with the initial resource. + * Easier to call draw method than to queue a draw. + * + * Cast self from Widget. + */ + gimp_brush_select_button_draw_interior (GIMP_RESOURCE_SELECT_BUTTON (self)); + + g_debug ("%s returns", G_STRFUNC); + + return self; } + +/* Getter and setter. + * We could omit these, and use only the superclass methods. + * But script-fu-interface.c uses these, until FUTURE. + */ + /** * gimp_brush_select_button_get_brush: - * @button: A #GimpBrushSelectButton - * @opacity: (out) (optional): Opacity of the selected brush. - * @spacing: (out) (optional): Spacing of the selected brush. - * @paint_mode: (out) (optional): Paint mode of the selected brush. + * @self: A #GimpBrushSelectButton * - * Retrieves the properties of currently selected brush. + * Gets the currently selected brush. * - * Returns: an internal copy of the brush name which must not be freed. + * Returns: (transfer none): an internal copy of the brush which must not be freed. * * Since: 2.4 */ -const gchar * -gimp_brush_select_button_get_brush (GimpBrushSelectButton *button, - gdouble *opacity, - gint *spacing, - GimpLayerMode *paint_mode) +GimpBrush * +gimp_brush_select_button_get_brush (GimpBrushSelectButton *self) { - g_return_val_if_fail (GIMP_IS_BRUSH_SELECT_BUTTON (button), NULL); + g_return_val_if_fail (GIMP_IS_BRUSH_SELECT_BUTTON (self), NULL); - if (opacity) - *opacity = button->priv->opacity; - - if (spacing) - *spacing = button->priv->spacing; - - if (paint_mode) - *paint_mode = button->priv->paint_mode; - - return button->priv->brush_name; + /* Delegate to super w upcast arg and downcast result. */ + return (GimpBrush *) gimp_resource_select_button_get_resource ((GimpResourceSelectButton*) self); } /** * gimp_brush_select_button_set_brush: - * @button: A #GimpBrushSelectButton - * @brush_name: (nullable): Brush name to set; %NULL means no change. - * @opacity: Opacity to set. -1.0 means no change. - * @spacing: Spacing to set. -1 means no change. - * @paint_mode: Paint mode to set. -1 means no change. + * @self: A #GimpBrushSelectButton + * @brush: Brush to set. * - * Sets the current brush and other values for the brush select - * button. + * Sets the currently selected brush. + * Usually you should not call this; the user is in charge. + * Changes the selection in both the button and it's popup chooser. * * Since: 2.4 */ void -gimp_brush_select_button_set_brush (GimpBrushSelectButton *button, - const gchar *brush_name, - gdouble opacity, - gint spacing, - GimpLayerMode paint_mode) +gimp_brush_select_button_set_brush (GimpBrushSelectButton *self, + GimpBrush *brush) { - GimpSelectButton *select_button; + g_return_if_fail (GIMP_IS_BRUSH_SELECT_BUTTON (self)); - g_return_if_fail (GIMP_IS_BRUSH_SELECT_BUTTON (button)); + g_debug ("%s", G_STRFUNC); - select_button = GIMP_SELECT_BUTTON (button); - - if (select_button->temp_callback) - { - gimp_brushes_set_popup (select_button->temp_callback, brush_name, - opacity, spacing, paint_mode); - } - else - { - gchar *name; - gint width; - gint height; - gint bytes; - gint mask_data_size; - guint8 *mask_data; - gint color_bpp; - gint color_data_size; - guint8 *color_data; - - if (brush_name && *brush_name) - name = g_strdup (brush_name); - else - name = gimp_context_get_brush (); - - if (gimp_brush_get_pixels (name, - &width, - &height, - &bytes, - &mask_data_size, - &mask_data, - &color_bpp, - &color_data_size, - &color_data)) - { - if (color_data) - g_free (color_data); - - if (opacity < 0.0) - opacity = gimp_context_get_opacity (); - - if (spacing == -1) - { - /* GimpBrush now a class. get_spacing is now an instance method. - * FIXME: when this widget takes a brush instance instead of a name, - * the next two lines should be deleted. - */ - GimpBrush *brush = g_object_new (GIMP_TYPE_BRUSH, NULL); - g_object_set (brush, "id", name, NULL); - - spacing = gimp_brush_get_spacing (brush); - } - - if (paint_mode == -1) - paint_mode = gimp_context_get_paint_mode (); - - gimp_brush_select_button_callback (name, - opacity, spacing, paint_mode, - width, height, width * height, - mask_data, - FALSE, button); - - g_free (mask_data); - } - - g_free (name); - } + /* Delegate to super with upcasts */ + gimp_resource_select_button_set_resource (GIMP_RESOURCE_SELECT_BUTTON (self), GIMP_RESOURCE (brush)); } @@ -476,221 +278,217 @@ gimp_brush_select_button_set_brush (GimpBrushSelectButton *button, static void gimp_brush_select_button_finalize (GObject *object) { - GimpBrushSelectButton *button = GIMP_BRUSH_SELECT_BUTTON (object); + g_debug ("%s called", G_STRFUNC); - g_clear_pointer (&button->priv->brush_name, g_free); - g_clear_pointer (&button->priv->mask_data, g_free); - g_clear_pointer (&button->priv->title, g_free); + /* Has no allocations.*/ + /* Chain up. */ G_OBJECT_CLASS (gimp_brush_select_button_parent_class)->finalize (object); } -static void -gimp_brush_select_button_set_property (GObject *object, - guint property_id, - const GValue *value, - GParamSpec *pspec) + +/* Create a widget that is the interior of another widget, a GimpBrushSelectButton. + * Super creates the exterior, self creates interior. + * Exterior is-a container and self calls super to add interior to the container. + */ +static GtkWidget * +gimp_brush_select_button_create_interior (GimpBrushSelectButton *self) { - GimpBrushSelectButton *button = GIMP_BRUSH_SELECT_BUTTON (object); - gdouble opacity; - gint32 spacing; - gint32 paint_mode; + GtkWidget *hbox; + GtkWidget *frame; + GtkWidget *peephole_view; + GtkWidget *browse_button; - switch (property_id) - { - case PROP_TITLE: - button->priv->title = g_value_dup_string (value); - break; + g_debug ("%s", G_STRFUNC); - case PROP_BRUSH_NAME: - gimp_brush_select_button_set_brush (button, - g_value_get_string (value), - -1.0, -1, -1); - break; + hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6); - case PROP_BRUSH_OPACITY: - opacity = g_value_get_double (value); - if (opacity >= 0.0) - button->priv->opacity = opacity; - break; + frame = gtk_frame_new (NULL); + gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN); + gtk_box_pack_start (GTK_BOX (hbox), frame, FALSE, FALSE, 0); - case PROP_BRUSH_SPACING: - spacing = g_value_get_int (value); - if (spacing != -1) - button->priv->spacing = spacing; - break; + peephole_view = gimp_preview_area_new (); + gtk_widget_add_events (peephole_view, + GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK); + gtk_widget_set_size_request (peephole_view, CELL_SIZE, CELL_SIZE); + gtk_container_add (GTK_CONTAINER (frame), peephole_view); - case PROP_BRUSH_PAINT_MODE: - paint_mode = g_value_get_int (value); - if (paint_mode != -1) - button->priv->paint_mode = paint_mode; - break; + g_signal_connect_swapped (peephole_view, "size-allocate", + G_CALLBACK (gimp_brush_select_on_preview_resize), + self); - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); - break; - } + /* preview receives mouse events to popup and down. */ + g_signal_connect (peephole_view, "event", + G_CALLBACK (gimp_brush_select_on_preview_events), + self); + + browse_button = gtk_button_new_with_mnemonic (_("_Browse...")); + gtk_box_pack_start (GTK_BOX (hbox), browse_button, TRUE, TRUE, 0); + + gtk_widget_show_all (hbox); + + /* Ensure self knows sub widgets. */ + self->peephole_view = peephole_view; + self->browse_button = browse_button; + + /* Return the whole, it is not a button, only contains a button. */ + return hbox; +} + +/* This is NOT an implementation of virtual function. */ +static void +gimp_brush_select_button_embed_interior (GimpBrushSelectButton *self) +{ + GtkWidget *interior; + + g_debug ("%s", G_STRFUNC); + + interior = gimp_brush_select_button_create_interior (self); + + /* This subclass does not connect to draw signal on interior widget. */ + + /* Call super with upcasts. */ + gimp_resource_select_button_embed_interior (GIMP_RESOURCE_SELECT_BUTTON (self), interior); } static void -gimp_brush_select_button_get_property (GObject *object, - guint property_id, - GValue *value, - GParamSpec *pspec) +gimp_brush_select_button_set_drag_target (GimpBrushSelectButton *self) { - GimpBrushSelectButton *button = GIMP_BRUSH_SELECT_BUTTON (object); - - switch (property_id) - { - case PROP_TITLE: - g_value_set_string (value, button->priv->title); - break; - - case PROP_BRUSH_NAME: - g_value_set_string (value, button->priv->brush_name); - break; - - case PROP_BRUSH_OPACITY: - g_value_set_double (value, button->priv->opacity); - break; - - case PROP_BRUSH_SPACING: - g_value_set_int (value, button->priv->spacing); - break; - - case PROP_BRUSH_PAINT_MODE: - g_value_set_int (value, button->priv->paint_mode); - break; - - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); - break; - } + /* Self knows the GtkTargetEntry, super knows how to create target and receive drag. */ + /* Only the peephole_view receives drag. */ + gimp_resource_select_button_set_drag_target (GIMP_RESOURCE_SELECT_BUTTON (self), + self->peephole_view, + &drag_target); } + +/* Knows how to draw self interior. + * Self knows resource, it is not passed. + * + * Overrides virtual method in super, so it is generic on Resource. + */ static void -gimp_brush_select_button_callback (const gchar *name, - gdouble opacity, - gint spacing, - GimpLayerMode paint_mode, - gint width, - gint height, - gint mask_size, - const guchar *mask_data, - gboolean dialog_closing, - gpointer data) +gimp_brush_select_button_draw_interior (GimpResourceSelectButton *self) { - GimpBrushSelectButton *button = GIMP_BRUSH_SELECT_BUTTON (data); - GimpSelectButton *select_button = GIMP_SELECT_BUTTON (button); + g_debug ("%s", G_STRFUNC); - g_free (button->priv->brush_name); - g_free (button->priv->mask_data); + g_return_if_fail (GIMP_IS_BRUSH_SELECT_BUTTON (self)); - button->priv->brush_name = g_strdup (name); - button->priv->width = width; - button->priv->height = height; - button->priv->mask_data = g_memdup2 (mask_data, width * height); - button->priv->opacity = opacity; - button->priv->spacing = spacing; - button->priv->paint_mode = paint_mode; - - gimp_brush_select_preview_update (button->priv->preview, - width, height, mask_data); - - if (dialog_closing) - select_button->temp_callback = NULL; - - g_signal_emit (button, brush_button_signals[BRUSH_SET], 0, - name, opacity, spacing, paint_mode, width, height, mask_data, - dialog_closing); - g_object_notify_by_pspec (G_OBJECT (button), brush_button_props[PROP_BRUSH_NAME]); + gimp_brush_select_button_draw (GIMP_BRUSH_SELECT_BUTTON (self)); } + +/* Draw self. + * + * This knows that we only draw the peephole_view. Gtk draws the browse button. + */ static void -gimp_brush_select_button_clicked (GimpBrushSelectButton *button) +gimp_brush_select_button_draw (GimpBrushSelectButton *self) { - GimpSelectButton *select_button = GIMP_SELECT_BUTTON (button); + _PreviewBitmap mask; - if (select_button->temp_callback) - { - /* calling gimp_brushes_set_popup() raises the dialog */ - gimp_brushes_set_popup (select_button->temp_callback, - button->priv->brush_name, - button->priv->opacity, - button->priv->spacing, - button->priv->paint_mode); - } - else - { - select_button->temp_callback = - gimp_brush_select_new (button->priv->title, - button->priv->brush_name, - button->priv->opacity, - button->priv->spacing, - button->priv->paint_mode, - gimp_brush_select_button_callback, - button, NULL); - } + g_debug ("%s", G_STRFUNC); + + /* Draw the peephole. */ + mask = gimp_brush_select_button_get_brush_bitmap (self); + gimp_brush_select_preview_fill_draw (self->peephole_view, mask); + g_free (mask.mask_data); } + + +/* Return the mask portion of self's brush's data. + * Caller must free mask_data. + */ +static _PreviewBitmap +gimp_brush_select_button_get_brush_bitmap (GimpBrushSelectButton *self) +{ + GimpBrush *brush; + gint mask_bpp; + gint mask_data_size; + gint color_bpp; + gint color_data_size; + guint8 *color_data; + _PreviewBitmap result; + + g_debug ("%s", G_STRFUNC); + + g_object_get (self, "resource", &brush, NULL); + + gimp_brush_get_pixels (brush, + &result.width, + &result.height, + &mask_bpp, + &mask_data_size, + &result.mask_data, + &color_bpp, + &color_data_size, + &color_data); + + /* Discard any color data, bitmap is B&W i.e. i.e. depth one i.e. a mask */ + if (color_data) + g_free (color_data); + + return result; +} + + +/* On resize event, redraw. */ static void -gimp_brush_select_preview_resize (GimpBrushSelectButton *button) +gimp_brush_select_on_preview_resize (GimpBrushSelectButton *self) { - if (button->priv->width > 0 && - button->priv->height > 0) - gimp_brush_select_preview_update (button->priv->preview, - button->priv->width, - button->priv->height, - button->priv->mask_data); + g_debug ("%s", G_STRFUNC); + + gimp_brush_select_button_draw (self); } + +/* On mouse events in self's peephole_view, popup a zoom view of entire brush */ static gboolean -gimp_brush_select_preview_events (GtkWidget *widget, - GdkEvent *event, - GimpBrushSelectButton *button) +gimp_brush_select_on_preview_events (GtkWidget *widget, + GdkEvent *event, + GimpBrushSelectButton *self) { GdkEventButton *bevent; - if (button->priv->mask_data) + g_debug ("%s", G_STRFUNC); + + switch (event->type) { - switch (event->type) + case GDK_BUTTON_PRESS: + bevent = (GdkEventButton *) event; + + if (bevent->button == 1) { - case GDK_BUTTON_PRESS: - bevent = (GdkEventButton *) event; - - if (bevent->button == 1) - { - gtk_grab_add (widget); - gimp_brush_select_button_open_popup (button, - bevent->x, bevent->y); - } - break; - - case GDK_BUTTON_RELEASE: - bevent = (GdkEventButton *) event; - - if (bevent->button == 1) - { - gtk_grab_remove (widget); - gimp_brush_select_button_close_popup (button); - } - break; - - default: - break; + gtk_grab_add (widget); + gimp_brush_select_button_open_popup (self, + bevent->x, bevent->y); } + break; + + case GDK_BUTTON_RELEASE: + bevent = (GdkEventButton *) event; + + if (bevent->button == 1) + { + gtk_grab_remove (widget); + gimp_brush_select_button_close_popup (self); + } + break; + + default: + break; } return FALSE; } +/* Draw a GimpPreviewArea with a given bitmap. */ static void gimp_brush_select_preview_draw (GimpPreviewArea *area, gint x, gint y, - gint width, - gint height, - const guchar *mask_data, + _PreviewBitmap mask, gint rowstride) { const guchar *src; @@ -698,45 +496,49 @@ gimp_brush_select_preview_draw (GimpPreviewArea *area, guchar *buf; gint i, j; - buf = g_new (guchar, width * height); + g_debug ("%s", G_STRFUNC); - src = mask_data; + buf = g_new (guchar, mask.width * mask.height); + + src = mask.mask_data; dest = buf; - for (j = 0; j < height; j++) + for (j = 0; j < mask.height; j++) { const guchar *s = src; - for (i = 0; i < width; i++, s++, dest++) + for (i = 0; i < mask.width; i++, s++, dest++) *dest = 255 - *s; src += rowstride; } gimp_preview_area_draw (area, - x, y, width, height, + x, y, mask.width, mask.height, GIMP_GRAY_IMAGE, buf, - width); + mask.width); g_free (buf); } +/* Fill a GimpPreviewArea with a bitmap then draw. */ static void -gimp_brush_select_preview_update (GtkWidget *preview, - gint brush_width, - gint brush_height, - const guchar *mask_data) +gimp_brush_select_preview_fill_draw (GtkWidget *preview, + _PreviewBitmap mask) { GimpPreviewArea *area = GIMP_PREVIEW_AREA (preview); GtkAllocation allocation; gint x, y; gint width, height; + _PreviewBitmap drawn_mask; + + g_debug ("%s", G_STRFUNC); gtk_widget_get_allocation (preview, &allocation); - width = MIN (brush_width, allocation.width); - height = MIN (brush_height, allocation.height); + width = MIN (mask.width, allocation.width); + height = MIN (mask.height, allocation.height); x = ((allocation.width - width) / 2); y = ((allocation.height - height) / 2); @@ -748,159 +550,92 @@ gimp_brush_select_preview_update (GtkWidget *preview, allocation.height, 0xFF, 0xFF, 0xFF); + /* Draw same data to new bounds. + * drawn_mask.mask_data points to same array. + */ + drawn_mask.width = width; + drawn_mask.height = height; + drawn_mask.mask_data = mask.mask_data; + gimp_brush_select_preview_draw (area, - x, y, width, height, - mask_data, brush_width); + x, y, + drawn_mask, + mask.width); /* row stride */ + /* Caller will free mask.mask_data */ } +/* popup methods. */ + static void -gimp_brush_select_button_open_popup (GimpBrushSelectButton *button, +gimp_brush_select_button_open_popup (GimpBrushSelectButton *self, gint x, gint y) { - GimpBrushSelectButtonPrivate *priv = button->priv; GtkWidget *frame; GtkWidget *preview; GdkMonitor *monitor; GdkRectangle workarea; gint x_org; gint y_org; + _PreviewBitmap mask; - if (priv->popup) - gimp_brush_select_button_close_popup (button); + g_debug ("%s", G_STRFUNC); - if (priv->width <= CELL_SIZE && priv->height <= CELL_SIZE) - return; + if (self->popup) + gimp_brush_select_button_close_popup (self); - priv->popup = gtk_window_new (GTK_WINDOW_POPUP); - gtk_window_set_type_hint (GTK_WINDOW (priv->popup), GDK_WINDOW_TYPE_HINT_DND); - gtk_window_set_screen (GTK_WINDOW (priv->popup), - gtk_widget_get_screen (GTK_WIDGET (button))); + mask = gimp_brush_select_button_get_brush_bitmap (self); - frame = gtk_frame_new (NULL); - gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_OUT); - gtk_container_add (GTK_CONTAINER (priv->popup), frame); - gtk_widget_show (frame); - - preview = gimp_preview_area_new (); - gtk_widget_set_size_request (preview, priv->width, priv->height); - gtk_container_add (GTK_CONTAINER (frame), preview); - gtk_widget_show (preview); - - /* decide where to put the popup */ - gdk_window_get_origin (gtk_widget_get_window (priv->preview), - &x_org, &y_org); - - monitor = gimp_widget_get_monitor (GTK_WIDGET (button)); - gdk_monitor_get_workarea (monitor, &workarea); - - x = x_org + x - (priv->width / 2); - y = y_org + y - (priv->height / 2); - - x = CLAMP (x, workarea.x, workarea.x + workarea.width - priv->width); - y = CLAMP (y, workarea.y, workarea.y + workarea.height - priv->height); - - gtk_window_move (GTK_WINDOW (priv->popup), x, y); - - gtk_widget_show (priv->popup); - - /* Draw the brush */ - gimp_brush_select_preview_draw (GIMP_PREVIEW_AREA (preview), - 0, 0, priv->width, priv->height, - priv->mask_data, priv->width); -} - -static void -gimp_brush_select_button_close_popup (GimpBrushSelectButton *button) -{ - g_clear_pointer (&button->priv->popup, gtk_widget_destroy); -} - -static void -gimp_brush_select_drag_data_received (GimpBrushSelectButton *button, - GdkDragContext *context, - gint x, - gint y, - GtkSelectionData *selection, - guint info, - guint time) -{ - gint length = gtk_selection_data_get_length (selection); - gchar *str; - - if (gtk_selection_data_get_format (selection) != 8 || length < 1) + if (mask.width <= CELL_SIZE && mask.height <= CELL_SIZE) { - g_warning ("%s: received invalid brush data", G_STRFUNC); + g_debug ("%s: omit popup smaller than peephole.", G_STRFUNC); return; } - str = g_strndup ((const gchar *) gtk_selection_data_get_data (selection), - length); - - if (g_utf8_validate (str, -1, NULL)) - { - gint pid; - gpointer unused; - gint name_offset = 0; - - if (sscanf (str, "%i:%p:%n", &pid, &unused, &name_offset) >= 2 && - pid == gimp_getpid () && name_offset > 0) - { - gchar *name = str + name_offset; - - gimp_brush_select_button_set_brush (button, name, -1.0, -1, -1); - } - } - - g_free (str); -} - -static GtkWidget * -gimp_brush_select_button_create_inside (GimpBrushSelectButton *brush_button) -{ - GimpBrushSelectButtonPrivate *priv = brush_button->priv; - GtkWidget *hbox; - GtkWidget *frame; - GtkWidget *button; - - hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6); + self->popup = gtk_window_new (GTK_WINDOW_POPUP); + gtk_window_set_type_hint (GTK_WINDOW (self->popup), GDK_WINDOW_TYPE_HINT_DND); + gtk_window_set_screen (GTK_WINDOW (self->popup), + gtk_widget_get_screen (GTK_WIDGET (self))); frame = gtk_frame_new (NULL); - gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN); - gtk_box_pack_start (GTK_BOX (hbox), frame, FALSE, FALSE, 0); + gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_OUT); + gtk_container_add (GTK_CONTAINER (self->popup), frame); + gtk_widget_show (frame); - priv->preview = gimp_preview_area_new (); - gtk_widget_add_events (priv->preview, - GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK); - gtk_widget_set_size_request (priv->preview, CELL_SIZE, CELL_SIZE); - gtk_container_add (GTK_CONTAINER (frame), priv->preview); + preview = gimp_preview_area_new (); + gtk_widget_set_size_request (preview, mask.width, mask.height); + gtk_container_add (GTK_CONTAINER (frame), preview); + gtk_widget_show (preview); - g_signal_connect_swapped (priv->preview, "size-allocate", - G_CALLBACK (gimp_brush_select_preview_resize), - brush_button); - g_signal_connect (priv->preview, "event", - G_CALLBACK (gimp_brush_select_preview_events), - brush_button); + /* decide where to put the popup: near the peephole_view i.e. at mousedown coords */ + gdk_window_get_origin (gtk_widget_get_window (self->peephole_view), + &x_org, &y_org); - gtk_drag_dest_set (GTK_WIDGET (priv->preview), - GTK_DEST_DEFAULT_HIGHLIGHT | - GTK_DEST_DEFAULT_MOTION | - GTK_DEST_DEFAULT_DROP, - &target, 1, - GDK_ACTION_COPY); + monitor = gimp_widget_get_monitor (GTK_WIDGET (self)); + gdk_monitor_get_workarea (monitor, &workarea); - g_signal_connect_swapped (priv->preview, "drag-data-received", - G_CALLBACK (gimp_brush_select_drag_data_received), - brush_button); + x = x_org + x - (mask.width / 2); + y = y_org + y - (mask.height / 2); - button = gtk_button_new_with_mnemonic (_("_Browse...")); - gtk_box_pack_start (GTK_BOX (hbox), button, TRUE, TRUE, 0); + x = CLAMP (x, workarea.x, workarea.x + workarea.width - mask.width); + y = CLAMP (y, workarea.y, workarea.y + workarea.height - mask.height); - g_signal_connect_swapped (button, "clicked", - G_CALLBACK (gimp_brush_select_button_clicked), - brush_button); + gtk_window_move (GTK_WINDOW (self->popup), x, y); - gtk_widget_show_all (hbox); + gtk_widget_show (self->popup); - return hbox; + /* Draw popup now. Usual events do not cause a draw. */ + gimp_brush_select_preview_draw (GIMP_PREVIEW_AREA (preview), + 0, 0, + mask, + mask.width); + g_free (mask.mask_data); +} + +static void +gimp_brush_select_button_close_popup (GimpBrushSelectButton *self) +{ + g_debug ("%s", G_STRFUNC); + + g_clear_pointer (&self->popup, gtk_widget_destroy); } diff --git a/libgimp/gimpbrushselectbutton.h b/libgimp/gimpbrushselectbutton.h index 95be946d0d..6a16a90ea6 100644 --- a/libgimp/gimpbrushselectbutton.h +++ b/libgimp/gimpbrushselectbutton.h @@ -25,76 +25,35 @@ #ifndef __GIMP_BRUSH_SELECT_BUTTON_H__ #define __GIMP_BRUSH_SELECT_BUTTON_H__ -#include +#include G_BEGIN_DECLS -/* For information look into the C source or the html documentation */ +/* This defines certain structs and the usual macros. + * A final type has no private. + */ +#define GIMP_TYPE_BRUSH_SELECT_BUTTON (gimp_brush_select_button_get_type ()) +G_DECLARE_FINAL_TYPE (GimpBrushSelectButton, + gimp_brush_select_button, + GIMP, BRUSH_SELECT_BUTTON, + GimpResourceSelectButton) -#define GIMP_TYPE_BRUSH_SELECT_BUTTON (gimp_brush_select_button_get_type ()) -#define GIMP_BRUSH_SELECT_BUTTON(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GIMP_TYPE_BRUSH_SELECT_BUTTON, GimpBrushSelectButton)) -#define GIMP_BRUSH_SELECT_BUTTON_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GIMP_TYPE_BRUSH_SELECT_BUTTON, GimpBrushSelectButtonClass)) -#define GIMP_IS_BRUSH_SELECT_BUTTON(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GIMP_TYPE_BRUSH_SELECT_BUTTON)) -#define GIMP_IS_BRUSH_SELECT_BUTTON_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GIMP_TYPE_BRUSH_SELECT_BUTTON)) -#define GIMP_BRUSH_SELECT_BUTTON_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GIMP_TYPE_BRUSH_SELECT_BUTTON, GimpBrushSelectButtonClass)) - - -typedef struct _GimpBrushSelectButtonPrivate GimpBrushSelectButtonPrivate; -typedef struct _GimpBrushSelectButtonClass GimpBrushSelectButtonClass; - -struct _GimpBrushSelectButton -{ - GimpSelectButton parent_instance; - - GimpBrushSelectButtonPrivate *priv; -}; - struct _GimpBrushSelectButtonClass { - GimpSelectButtonClass parent_class; + GimpResourceSelectButtonClass parent_class; - /* brush_set signal is emitted when brush is chosen */ - void (* brush_set) (GimpBrushSelectButton *button, - const gchar *brush_name, - gdouble opacity, - gint spacing, - GimpLayerMode paint_mode, - gint width, - gint height, - const guchar *mask_data, - gboolean dialog_closing); - - /* Padding for future expansion */ - void (*_gimp_reserved1) (void); - void (*_gimp_reserved2) (void); - void (*_gimp_reserved3) (void); - void (*_gimp_reserved4) (void); - void (*_gimp_reserved5) (void); - void (*_gimp_reserved6) (void); - void (*_gimp_reserved7) (void); - void (*_gimp_reserved8) (void); + /* _set signal is not defined. Use resource_set signal from superclass */ }; -GType gimp_brush_select_button_get_type (void) G_GNUC_CONST; - -GtkWidget * gimp_brush_select_button_new (const gchar *title, - const gchar *brush_name, - gdouble opacity, - gint spacing, - GimpLayerMode paint_mode); - -const gchar * gimp_brush_select_button_get_brush (GimpBrushSelectButton *button, - gdouble *opacity, - gint *spacing, - GimpLayerMode *paint_mode); -void gimp_brush_select_button_set_brush (GimpBrushSelectButton *button, - const gchar *brush_name, - gdouble opacity, - gint spacing, - GimpLayerMode paint_mode); +GtkWidget * gimp_brush_select_button_new (const gchar *title, + GimpResource *resource); +/* FUTURE eliminate. Use superclass method get_resource */ +GimpBrush * gimp_brush_select_button_get_brush (GimpBrushSelectButton *self); +void gimp_brush_select_button_set_brush (GimpBrushSelectButton *self, + GimpBrush *brush); G_END_DECLS diff --git a/libgimp/gimpfontselect.c b/libgimp/gimpfontselect.c deleted file mode 100644 index 5c4714fda5..0000000000 --- a/libgimp/gimpfontselect.c +++ /dev/null @@ -1,179 +0,0 @@ -/* LIBGIMP - The GIMP Library - * Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball - * - * gimpfontselect.c - * - * This library is free software: you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library. If not, see - * . - */ - -#include "config.h" - -#include "gimp.h" - - -typedef struct -{ - gchar *font_callback; - guint idle_id; - gchar *font_name; - GimpRunFontCallback callback; - gboolean closing; - gpointer data; - GDestroyNotify data_destroy; -} GimpFontData; - - -/* local function prototypes */ - -static void gimp_font_data_free (GimpFontData *data); - -static GimpValueArray * gimp_temp_font_run (GimpProcedure *procedure, - const GimpValueArray *args, - gpointer run_data); -static gboolean gimp_temp_font_idle (GimpFontData *data); - - -/* public functions */ - -const gchar * -gimp_font_select_new (const gchar *title, - const gchar *font_name, - GimpRunFontCallback callback, - gpointer data, - GDestroyNotify data_destroy) -{ - GimpPlugIn *plug_in = gimp_get_plug_in (); - GimpProcedure *procedure; - gchar *font_callback; - GimpFontData *font_data; - - font_callback = gimp_pdb_temp_procedure_name (gimp_get_pdb ()); - - font_data = g_slice_new0 (GimpFontData); - - font_data->font_callback = font_callback; - font_data->callback = callback; - font_data->data = data; - font_data->data_destroy = data_destroy; - - procedure = gimp_procedure_new (plug_in, - font_callback, - GIMP_PDB_PROC_TYPE_TEMPORARY, - gimp_temp_font_run, - font_data, - (GDestroyNotify) - gimp_font_data_free); - - GIMP_PROC_ARG_STRING (procedure, "font-name", - "Font name", - "The font name", - NULL, - G_PARAM_READWRITE); - - GIMP_PROC_ARG_BOOLEAN (procedure, "closing", - "Closing", - "If the dialog was closing", - FALSE, - G_PARAM_READWRITE); - - gimp_plug_in_add_temp_procedure (plug_in, procedure); - g_object_unref (procedure); - - if (gimp_fonts_popup (font_callback, title, font_name)) - { - /* Allow callbacks to be watched */ - gimp_plug_in_extension_enable (plug_in); - - return font_callback; - } - - gimp_plug_in_remove_temp_procedure (plug_in, font_callback); - - return NULL; -} - -void -gimp_font_select_destroy (const gchar *font_callback) -{ - GimpPlugIn *plug_in = gimp_get_plug_in (); - - g_return_if_fail (font_callback != NULL); - - gimp_plug_in_remove_temp_procedure (plug_in, font_callback); -} - - -/* private functions */ - -static void -gimp_font_data_free (GimpFontData *data) -{ - if (data->idle_id) - g_source_remove (data->idle_id); - - g_free (data->font_name); - - if (data->font_callback) - { - gimp_fonts_close_popup (data->font_callback); - g_free (data->font_callback); - } - - if (data->data_destroy) - data->data_destroy (data->data); - - g_slice_free (GimpFontData, data); -} - -static GimpValueArray * -gimp_temp_font_run (GimpProcedure *procedure, - const GimpValueArray *args, - gpointer run_data) -{ - GimpFontData *data = run_data; - - g_free (data->font_name); - - data->font_name = GIMP_VALUES_DUP_STRING (args, 0); - data->closing = GIMP_VALUES_GET_BOOLEAN (args, 1); - - if (! data->idle_id) - data->idle_id = g_idle_add ((GSourceFunc) gimp_temp_font_idle, - data); - - return gimp_procedure_new_return_values (procedure, GIMP_PDB_SUCCESS, NULL); -} - -static gboolean -gimp_temp_font_idle (GimpFontData *data) -{ - data->idle_id = 0; - - if (data->callback) - data->callback (data->font_name, - data->closing, - data->data); - - if (data->closing) - { - gchar *font_callback = data->font_callback; - - data->font_callback = NULL; - gimp_font_select_destroy (font_callback); - g_free (font_callback); - } - - return G_SOURCE_REMOVE; -} diff --git a/libgimp/gimpfontselect.h b/libgimp/gimpfontselect.h deleted file mode 100644 index 6a41c31422..0000000000 --- a/libgimp/gimpfontselect.h +++ /dev/null @@ -1,46 +0,0 @@ -/* LIBGIMP - The GIMP Library - * Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball - * - * gimpfontselect.h - * - * This library is free software: you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library. If not, see - * . - */ - -#if !defined (__GIMP_H_INSIDE__) && !defined (GIMP_COMPILATION) -#error "Only can be included directly." -#endif - -#ifndef __GIMP_FONT_SELECT_H__ -#define __GIMP_FONT_SELECT_H__ - -G_BEGIN_DECLS - - -typedef void (* GimpRunFontCallback) (const gchar *font_name, - gboolean dialog_closing, - gpointer user_data); - - -const gchar * gimp_font_select_new (const gchar *title, - const gchar *font_name, - GimpRunFontCallback callback, - gpointer data, - GDestroyNotify data_destroy); -void gimp_font_select_destroy (const gchar *font_callback); - - -G_END_DECLS - -#endif /* __GIMP_FONT_SELECT_H__ */ diff --git a/libgimp/gimpfontselect_pdb.c b/libgimp/gimpfontselect_pdb.c index 10223193ff..65c9a11a55 100644 --- a/libgimp/gimpfontselect_pdb.c +++ b/libgimp/gimpfontselect_pdb.c @@ -30,28 +30,37 @@ /** * SECTION: gimpfontselect * @title: gimpfontselect - * @short_description: Functions providing a font selection dialog. + * @short_description: Methods of a font chooser dialog. * - * Functions providing a font selection dialog. + * A font chooser dialog shows installed fonts. + * The dialog is non-modal with its owning dialog, + * which is usually a plugin procedure's dialog. + * When a user selects a font, + * the dialog calls back but the dialog remains open. + * The chosen font is only a choice for the owning widget + * and does not select the font for the context. + * The user can close but not cancel the dialog. + * The owning dialog can close the font chooser dialog + * when the user closes or cancels the owning dialog. **/ /** * gimp_fonts_popup: - * @font_callback: The callback PDB proc to call when font selection is made. + * @font_callback: The callback PDB proc to call when user chooses a font. * @popup_title: Title of the font selection dialog. - * @initial_font: The name of the font to set as the first selected. + * @initial_font_name: The name of the initial font choice. * - * Invokes the Gimp font selection. + * Invokes the Gimp font selection dialog. * - * This procedure opens the font selection dialog. + * Opens a dialog letting a user choose a font. * * Returns: TRUE on success. **/ gboolean gimp_fonts_popup (const gchar *font_callback, const gchar *popup_title, - const gchar *initial_font) + const gchar *initial_font_name) { GimpValueArray *args; GimpValueArray *return_vals; @@ -60,7 +69,7 @@ gimp_fonts_popup (const gchar *font_callback, args = gimp_value_array_new_from_types (NULL, G_TYPE_STRING, font_callback, G_TYPE_STRING, popup_title, - G_TYPE_STRING, initial_font, + G_TYPE_STRING, initial_font_name, G_TYPE_NONE); return_vals = gimp_pdb_run_procedure_array (gimp_get_pdb (), @@ -77,11 +86,11 @@ gimp_fonts_popup (const gchar *font_callback, /** * gimp_fonts_close_popup: - * @font_callback: The name of the callback registered for this pop-up. + * @font_callback: The name of the callback registered in the PDB for this dialog. * * Close the font selection dialog. * - * This procedure closes an opened font selection dialog. + * Closes an open font selection dialog. * * Returns: TRUE on success. **/ @@ -110,7 +119,7 @@ gimp_fonts_close_popup (const gchar *font_callback) /** * gimp_fonts_set_popup: - * @font_callback: The name of the callback registered for this pop-up. + * @font_callback: The name of the callback registered in the PDB for the dialog. * @font_name: The name of the font to set as selected. * * Sets the current font in a font selection dialog. diff --git a/libgimp/gimpfontselect_pdb.h b/libgimp/gimpfontselect_pdb.h index 1685e351a3..c0456c632f 100644 --- a/libgimp/gimpfontselect_pdb.h +++ b/libgimp/gimpfontselect_pdb.h @@ -34,7 +34,7 @@ G_BEGIN_DECLS gboolean gimp_fonts_popup (const gchar *font_callback, const gchar *popup_title, - const gchar *initial_font); + const gchar *initial_font_name); gboolean gimp_fonts_close_popup (const gchar *font_callback); gboolean gimp_fonts_set_popup (const gchar *font_callback, const gchar *font_name); diff --git a/libgimp/gimpfontselectbutton.c b/libgimp/gimpfontselectbutton.c index 5f994eccdc..9e47e17f29 100644 --- a/libgimp/gimpfontselectbutton.c +++ b/libgimp/gimpfontselectbutton.c @@ -43,233 +43,193 @@ * A button which pops up a font selection dialog. **/ - -enum +struct _GimpFontSelectButton { - FONT_SET, - LAST_SIGNAL + /* !! Not a pointer, is contained. */ + GimpResourceSelectButton parent_instance; + + GtkWidget *font_name_label; + GtkWidget *drag_region_widget; + GtkWidget *button; }; -enum -{ - PROP_0, - PROP_TITLE, - PROP_FONT_NAME, - N_PROPS -}; +/* local */ +/* implement virtual */ +static void gimp_font_select_button_finalize (GObject *object); +static void gimp_font_select_button_draw_interior (GimpResourceSelectButton *self); -struct _GimpFontSelectButtonPrivate -{ - gchar *title; +/* Called at init. */ +static GtkWidget *gimp_font_select_button_create_interior (GimpFontSelectButton *self); - gchar *font_name; /* local copy */ +/* A GtkTargetEntry has a string and two ints. This is one, but treat as an array.*/ +static const GtkTargetEntry drag_target = { "application/x-gimp-font-name", 0, 0 }; - GtkWidget *inside; - GtkWidget *label; -}; - - -/* local function prototypes */ - -static void gimp_font_select_button_finalize (GObject *object); - -static void gimp_font_select_button_set_property (GObject *object, - guint property_id, - const GValue *value, - GParamSpec *pspec); -static void gimp_font_select_button_get_property (GObject *object, - guint property_id, - GValue *value, - GParamSpec *pspec); - -static void gimp_font_select_button_clicked (GimpFontSelectButton *button); - -static void gimp_font_select_button_callback (const gchar *font_name, - gboolean dialog_closing, - gpointer user_data); - -static void gimp_font_select_drag_data_received (GimpFontSelectButton *button, - GdkDragContext *context, - gint x, - gint y, - GtkSelectionData *selection, - guint info, - guint time); - -static GtkWidget * gimp_font_select_button_create_inside (GimpFontSelectButton *button); - - -static const GtkTargetEntry target = { "application/x-gimp-font-name", 0 }; - -static guint font_button_signals[LAST_SIGNAL] = { 0 }; -static GParamSpec *font_button_props[N_PROPS] = { NULL, }; - - -G_DEFINE_TYPE_WITH_PRIVATE (GimpFontSelectButton, gimp_font_select_button, - GIMP_TYPE_SELECT_BUTTON) +G_DEFINE_FINAL_TYPE (GimpFontSelectButton, + gimp_font_select_button, + GIMP_TYPE_RESOURCE_SELECT_BUTTON) static void gimp_font_select_button_class_init (GimpFontSelectButtonClass *klass) { - GObjectClass *object_class = G_OBJECT_CLASS (klass); - GimpSelectButtonClass *select_button_class = GIMP_SELECT_BUTTON_CLASS (klass); + /* Alias cast klass to super classes. */ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + GimpResourceSelectButtonClass *superclass = GIMP_RESOURCE_SELECT_BUTTON_CLASS (klass); + g_debug ("%s called", G_STRFUNC); + + /* Override virtual. */ object_class->finalize = gimp_font_select_button_finalize; - object_class->set_property = gimp_font_select_button_set_property; - object_class->get_property = gimp_font_select_button_get_property; - select_button_class->select_destroy = gimp_font_select_destroy; + /* Implement pure virtual functions. */ + superclass->draw_interior = gimp_font_select_button_draw_interior; - klass->font_set = NULL; + /* Set data member of class. */ + superclass->resource_type = GIMP_TYPE_FONT; - /** - * GimpFontSelectButton:title: - * - * The title to be used for the font selection popup dialog. - * - * Since: 2.4 + /* We don't define property getter/setters: use superclass getter/setters. + * But super property name is "resource", not "font" */ - font_button_props[PROP_TITLE] = g_param_spec_string ("title", - "Title", - "The title to be used for the font selection popup dialog", - _("Font Selection"), - GIMP_PARAM_READWRITE | - G_PARAM_CONSTRUCT_ONLY); - - /** - * GimpFontSelectButton:font-name: - * - * The name of the currently selected font. - * - * Since: 2.4 - */ - font_button_props[PROP_FONT_NAME] = g_param_spec_string ("font-name", - "Font name", - "The name of the currently selected font", - "Sans-serif", - GIMP_PARAM_READWRITE); - - g_object_class_install_properties (object_class, N_PROPS, font_button_props); - - /** - * GimpFontSelectButton::font-set: - * @widget: the object which received the signal. - * @font_name: the name of the currently selected font. - * @dialog_closing: whether the dialog was closed or not. - * - * The ::font-set signal is emitted when the user selects a font. - * - * Since: 2.4 - */ - font_button_signals[FONT_SET] = - g_signal_new ("font-set", - G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_FIRST, - G_STRUCT_OFFSET (GimpFontSelectButtonClass, font_set), - NULL, NULL, - _gimpui_marshal_VOID__STRING_BOOLEAN, - G_TYPE_NONE, 2, - G_TYPE_STRING, - G_TYPE_BOOLEAN); } static void -gimp_font_select_button_init (GimpFontSelectButton *button) +gimp_font_select_button_init (GimpFontSelectButton *self) { - button->priv = gimp_font_select_button_get_instance_private (button); + GtkWidget *interior; - button->priv->inside = gimp_font_select_button_create_inside (button); - gtk_container_add (GTK_CONTAINER (button), button->priv->inside); + g_debug ("%s called", G_STRFUNC); + + /* Specialize super: + * - embed our widget interior instance to super widget instance. + * - tell super our dnd widget + * - tell super our clickable button + * Call superclass methods, with upcasts. + * These are on instance, not our subclass. + */ + interior = gimp_font_select_button_create_interior (self); + /* require self has sub widgets initialized. */ + + /* Embed the whole button.*/ + gimp_resource_select_button_embed_interior (GIMP_RESOURCE_SELECT_BUTTON (self), interior); + + /* Self knows the GtkTargetEntry, super creates target and handles receive drag. */ + gimp_resource_select_button_set_drag_target (GIMP_RESOURCE_SELECT_BUTTON (self), + self->drag_region_widget, + &drag_target); + /* Super handles button clicks. */ + gimp_resource_select_button_set_clickable (GIMP_RESOURCE_SELECT_BUTTON (self), + self->button); } /** * gimp_font_select_button_new: * @title: (nullable): Title of the dialog to use or %NULL to use the default title. - * @font_name: (nullable): Initial font name. + * @resource: (nullable): Initial font. * - * Creates a new #GtkWidget that completely controls the selection of - * a font. This widget is suitable for placement in a table in a - * plug-in dialog. + * Creates a new #GtkWidget that lets a user choose a font. + * You can put this widget in a plug-in dialog. + * + * When font is NULL, initial choice is from context. * * Returns: A #GtkWidget that you can use in your UI. * * Since: 2.4 */ GtkWidget * -gimp_font_select_button_new (const gchar *title, - const gchar *font_name) +gimp_font_select_button_new (const gchar *title, + GimpResource *resource) { - GtkWidget *button; + GtkWidget *self; - if (title) - button = g_object_new (GIMP_TYPE_FONT_SELECT_BUTTON, - "title", title, - "font-name", font_name, - NULL); - else - button = g_object_new (GIMP_TYPE_FONT_SELECT_BUTTON, - "font-name", font_name, - NULL); + g_debug ("%s called", G_STRFUNC); - return button; + if (resource == NULL) + { + g_debug ("%s defaulting font from context", G_STRFUNC); + resource = GIMP_RESOURCE (gimp_context_get_font ()); + } + g_assert (resource != NULL); + /* This method is polymorphic, so a factory can call it, but requires Font. */ + g_return_val_if_fail (GIMP_IS_FONT (resource), NULL); + + /* Create instance of self (not super.) + * This will call superclass init, self class init, superclass init, and instance init. + * Self subclass class_init will specialize by implementing virtual funcs + * that open and set remote chooser dialog, and that draw self interior. + * + * !!! property belongs to superclass and is named "resource" + */ + if (title) + self = g_object_new (GIMP_TYPE_FONT_SELECT_BUTTON, + "title", title, + "resource", resource, + NULL); + else + self = g_object_new (GIMP_TYPE_FONT_SELECT_BUTTON, + "resource", resource, + NULL); + + /* We don't subscribe to events from super (such as draw events.) + * Super will call our draw method when it's resource changes. + * Except that the above setting of property happens too late, + * so we now draw the initial resource. + */ + + /* Draw with the initial resource. Cast self from Widget. */ + gimp_font_select_button_draw_interior (GIMP_RESOURCE_SELECT_BUTTON (self)); + + g_debug ("%s returns", G_STRFUNC); + + return self; } + +/* Getter and setter. + * We could omit these, and use only the superclass methods. + * But script-fu-interface.c uses these, until FUTURE. + */ + /** * gimp_font_select_button_get_font: - * @button: A #GimpFontSelectButton + * @self: A #GimpFontSelectButton * - * Retrieves the name of currently selected font. + * Gets the currently selected font. * - * Returns: an internal copy of the font name which must not be freed. + * Returns: (transfer none): an internal copy of the font which must not be freed. * * Since: 2.4 */ -const gchar * -gimp_font_select_button_get_font (GimpFontSelectButton *button) +GimpFont * +gimp_font_select_button_get_font (GimpFontSelectButton *self) { - g_return_val_if_fail (GIMP_IS_FONT_SELECT_BUTTON (button), NULL); + g_return_val_if_fail (GIMP_IS_FONT_SELECT_BUTTON (self), NULL); - return button->priv->font_name; + /* Delegate to super w upcast arg and downcast result. */ + return (GimpFont *) gimp_resource_select_button_get_resource ((GimpResourceSelectButton*) self); } /** * gimp_font_select_button_set_font: - * @button: A #GimpFontSelectButton - * @font_name: (nullable): Font name to set; %NULL means no change. + * @self: A #GimpFontSelectButton + * @font: Font to set. * - * Sets the current font for the font select button. + * Sets the currently selected font. + * Usually you should not call this; the user is in charge. + * Changes the selection in both the button and it's popup chooser. * * Since: 2.4 */ void -gimp_font_select_button_set_font (GimpFontSelectButton *button, - const gchar *font_name) +gimp_font_select_button_set_font (GimpFontSelectButton *self, + GimpFont *font) { - GimpSelectButton *select_button; + g_return_if_fail (GIMP_IS_FONT_SELECT_BUTTON (self)); - g_return_if_fail (GIMP_IS_FONT_SELECT_BUTTON (button)); + g_debug ("%s", G_STRFUNC); - select_button = GIMP_SELECT_BUTTON (button); - - if (select_button->temp_callback) - { - gimp_fonts_set_popup (select_button->temp_callback, font_name); - } - else - { - gchar *name; - - if (font_name && *font_name) - name = g_strdup (font_name); - else - name = gimp_context_get_font (); - - gimp_font_select_button_callback (name, FALSE, button); - - g_free (name); - } + /* Delegate to super with upcasts */ + gimp_resource_select_button_set_resource (GIMP_RESOURCE_SELECT_BUTTON (self), GIMP_RESOURCE (font)); } @@ -278,181 +238,98 @@ gimp_font_select_button_set_font (GimpFontSelectButton *button, static void gimp_font_select_button_finalize (GObject *object) { - GimpFontSelectButton *button = GIMP_FONT_SELECT_BUTTON (object); + g_debug ("%s called", G_STRFUNC); - g_clear_pointer (&button->priv->font_name, g_free); - g_clear_pointer (&button->priv->title, g_free); + /* Has no allocations.*/ + /* Chain up. */ G_OBJECT_CLASS (gimp_font_select_button_parent_class)->finalize (object); } -static void -gimp_font_select_button_set_property (GObject *object, - guint property_id, - const GValue *value, - GParamSpec *pspec) + + + +/* This is NOT an implementation of virtual function. + * + * Create a widget that is the interior of a button. + * Super creates the button, self creates interior. + * Button is-a container and self calls super to add interior to the container. + * + * Special: an hbox containing a general icon for a font and + * a label that is the name of the font family and style. + * FUTURE: label styled in the current font family and style. + */ +static GtkWidget* +gimp_font_select_button_create_interior (GimpFontSelectButton *self) { - GimpFontSelectButton *button = GIMP_FONT_SELECT_BUTTON (object); + GtkWidget *button; + GtkWidget *hbox; + GtkWidget *image; + GtkWidget *label; + gchar *font_name = "unknown"; - switch (property_id) - { - case PROP_TITLE: - button->priv->title = g_value_dup_string (value); - break; - - case PROP_FONT_NAME: - gimp_font_select_button_set_font (button, - g_value_get_string (value)); - break; - - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); - break; - } -} - -static void -gimp_font_select_button_get_property (GObject *object, - guint property_id, - GValue *value, - GParamSpec *pspec) -{ - GimpFontSelectButton *button = GIMP_FONT_SELECT_BUTTON (object); - - switch (property_id) - { - case PROP_TITLE: - g_value_set_string (value, button->priv->title); - break; - - case PROP_FONT_NAME: - g_value_set_string (value, button->priv->font_name); - break; - - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); - break; - } -} - -static void -gimp_font_select_button_callback (const gchar *font_name, - gboolean dialog_closing, - gpointer user_data) -{ - GimpFontSelectButton *button = GIMP_FONT_SELECT_BUTTON (user_data); - GimpFontSelectButtonPrivate *priv = button->priv; - GimpSelectButton *select_button = GIMP_SELECT_BUTTON (button); - - g_free (priv->font_name); - priv->font_name = g_strdup (font_name); - - gtk_label_set_text (GTK_LABEL (priv->label), font_name); - - if (dialog_closing) - select_button->temp_callback = NULL; - - g_signal_emit (button, font_button_signals[FONT_SET], 0, - font_name, dialog_closing); - g_object_notify_by_pspec (G_OBJECT (button), font_button_props[PROP_FONT_NAME]); -} - -static void -gimp_font_select_button_clicked (GimpFontSelectButton *button) -{ - GimpSelectButton *select_button = GIMP_SELECT_BUTTON (button); - - if (select_button->temp_callback) - { - /* calling gimp_fonts_set_popup() raises the dialog */ - gimp_fonts_set_popup (select_button->temp_callback, - button->priv->font_name); - } - else - { - select_button->temp_callback = - gimp_font_select_new (button->priv->title, - button->priv->font_name, - gimp_font_select_button_callback, - button, NULL); - } -} - -static void -gimp_font_select_drag_data_received (GimpFontSelectButton *button, - GdkDragContext *context, - gint x, - gint y, - GtkSelectionData *selection, - guint info, - guint time) -{ - gint length = gtk_selection_data_get_length (selection); - gchar *str; - - if (gtk_selection_data_get_format (selection) != 8 || length < 1) - { - g_warning ("%s: received invalid font data", G_STRFUNC); - return; - } - - str = g_strndup ((const gchar *) gtk_selection_data_get_data (selection), - length); - - if (g_utf8_validate (str, -1, NULL)) - { - gint pid; - gpointer unused; - gint name_offset = 0; - - if (sscanf (str, "%i:%p:%n", &pid, &unused, &name_offset) >= 2 && - pid == gimp_getpid () && name_offset > 0) - { - gchar *name = str + name_offset; - - gimp_font_select_button_set_font (button, name); - } - } - - g_free (str); -} - -static GtkWidget * -gimp_font_select_button_create_inside (GimpFontSelectButton *font_button) -{ - GimpFontSelectButtonPrivate *priv = font_button->priv; - GtkWidget *button; - GtkWidget *hbox; - GtkWidget *image; + g_debug ("%s", G_STRFUNC); + /* Outermost is-a button. */ button = gtk_button_new (); + /* inside the button is hbox. */ hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 4); gtk_container_add (GTK_CONTAINER (button), hbox); + /* first item in hbox is an icon. */ image = gtk_image_new_from_icon_name (GIMP_ICON_FONT, GTK_ICON_SIZE_BUTTON); gtk_box_pack_start (GTK_BOX (hbox), image, FALSE, FALSE, 0); - priv->label = gtk_label_new (priv->font_name); - gtk_box_pack_start (GTK_BOX (hbox), priv->label, TRUE, TRUE, 4); + /* Second item in hbox is font name. + * The initial text is dummy, a draw will soon refresh it. + * This function does not know the resource/font. + */ + label = gtk_label_new (font_name); + gtk_box_pack_start (GTK_BOX (hbox), label, TRUE, TRUE, 4); - gtk_widget_show_all (button); + /* Ensure sub widgets saved for subsequent use. */ - g_signal_connect_swapped (button, "clicked", - G_CALLBACK (gimp_font_select_button_clicked), - font_button); + self->font_name_label = label; /* Save label for redraw. */ + self->drag_region_widget = hbox; + self->button = button; - gtk_drag_dest_set (GTK_WIDGET (button), - GTK_DEST_DEFAULT_HIGHLIGHT | - GTK_DEST_DEFAULT_MOTION | - GTK_DEST_DEFAULT_DROP, - &target, 1, - GDK_ACTION_COPY); - - g_signal_connect_swapped (button, "drag-data-received", - G_CALLBACK (gimp_font_select_drag_data_received), - font_button); + /* This subclass does not connect to draw signal on interior widget. */ + /* Return the whole interior, which is-a button. */ return button; } + + +/* Knows how to draw self interior. + * Self knows resource, it is not passed. + * + * Overrides virtual method in super, so it is generic on Resource. + */ +static void +gimp_font_select_button_draw_interior (GimpResourceSelectButton *self) +{ + gchar *font_name; + GimpResource *resource; + GimpFontSelectButton *self_as_font_select; + + g_debug ("%s", G_STRFUNC); + + g_return_if_fail (GIMP_IS_FONT_SELECT_BUTTON (self)); + self_as_font_select = GIMP_FONT_SELECT_BUTTON (self); + + g_object_get (self, "resource", &resource, NULL); + + /* For now, the "id" property of the resource is the name. + * FUTURE: core will support name distinct from ID. + */ + g_object_get (resource, "id", &font_name, NULL); + + /* We are not keeping a copy of font name, nothing to free. */ + + /* Not styling the text using the chosen font, + * just replacing the text with the name of the chosen font. + */ + gtk_label_set_text (GTK_LABEL (self_as_font_select->font_name_label), font_name); +} diff --git a/libgimp/gimpfontselectbutton.h b/libgimp/gimpfontselectbutton.h index ac816092aa..7adde5bdad 100644 --- a/libgimp/gimpfontselectbutton.h +++ b/libgimp/gimpfontselectbutton.h @@ -25,61 +25,35 @@ #ifndef __GIMP_FONT_SELECT_BUTTON_H__ #define __GIMP_FONT_SELECT_BUTTON_H__ -#include +#include G_BEGIN_DECLS -/* For information look into the C source or the html documentation */ +/* This defines certain structs and the usual macros. + * A final type has no private. + */ +#define GIMP_TYPE_FONT_SELECT_BUTTON (gimp_font_select_button_get_type ()) +G_DECLARE_FINAL_TYPE (GimpFontSelectButton, + gimp_font_select_button, + GIMP, FONT_SELECT_BUTTON, + GimpResourceSelectButton) -#define GIMP_TYPE_FONT_SELECT_BUTTON (gimp_font_select_button_get_type ()) -#define GIMP_FONT_SELECT_BUTTON(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GIMP_TYPE_FONT_SELECT_BUTTON, GimpFontSelectButton)) -#define GIMP_FONT_SELECT_BUTTON_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GIMP_TYPE_FONT_SELECT_BUTTON, GimpFontSelectButtonClass)) -#define GIMP_IS_FONT_SELECT_BUTTON(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GIMP_TYPE_FONT_SELECT_BUTTON)) -#define GIMP_IS_FONT_SELECT_BUTTON_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GIMP_TYPE_FONT_SELECT_BUTTON)) -#define GIMP_FONT_SELECT_BUTTON_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GIMP_TYPE_FONT_SELECT_BUTTON, GimpFontSelectButtonClass)) - - -typedef struct _GimpFontSelectButtonPrivate GimpFontSelectButtonPrivate; -typedef struct _GimpFontSelectButtonClass GimpFontSelectButtonClass; - -struct _GimpFontSelectButton -{ - GimpSelectButton parent_instance; - - GimpFontSelectButtonPrivate *priv; -}; - struct _GimpFontSelectButtonClass { - GimpSelectButtonClass parent_class; + GimpResourceSelectButtonClass parent_class; - /* font_set signal is emitted when font is chosen */ - void (* font_set) (GimpFontSelectButton *button, - const gchar *font_name, - gboolean dialog_closing); - - /* Padding for future expansion */ - void (*_gimp_reserved1) (void); - void (*_gimp_reserved2) (void); - void (*_gimp_reserved3) (void); - void (*_gimp_reserved4) (void); - void (*_gimp_reserved5) (void); - void (*_gimp_reserved6) (void); - void (*_gimp_reserved7) (void); - void (*_gimp_reserved8) (void); + /* _set signal is not defined. Use resource_set signal from superclass */ }; -GType gimp_font_select_button_get_type (void) G_GNUC_CONST; - GtkWidget * gimp_font_select_button_new (const gchar *title, - const gchar *font_name); - -const gchar * gimp_font_select_button_get_font (GimpFontSelectButton *button); -void gimp_font_select_button_set_font (GimpFontSelectButton *button, - const gchar *font_name); + GimpResource *resource); +/* FUTURE eliminate. Use superclass method get_resource */ +GimpFont * gimp_font_select_button_get_font (GimpFontSelectButton *self); +void gimp_font_select_button_set_font (GimpFontSelectButton *self, + GimpFont *font); G_END_DECLS diff --git a/libgimp/gimpgradientselect.c b/libgimp/gimpgradientselect.c deleted file mode 100644 index 3982aea0df..0000000000 --- a/libgimp/gimpgradientselect.c +++ /dev/null @@ -1,199 +0,0 @@ -/* LIBGIMP - The GIMP Library - * Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball - * - * gimpgradientselect.c - * - * This library is free software: you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library. If not, see - * . - */ - -#include "config.h" - -#include "gimp.h" - - -typedef struct -{ - gchar *gradient_callback; - guint idle_id; - gchar *gradient_name; - gint width; - gdouble *gradient_data; - GimpRunGradientCallback callback; - gboolean closing; - gpointer data; - GDestroyNotify data_destroy; -} GimpGradientData; - - -/* local function prototypes */ - -static void gimp_gradient_data_free (GimpGradientData *data); - -static GimpValueArray * gimp_temp_gradient_run (GimpProcedure *procedure, - const GimpValueArray *args, - gpointer run_data); -static gboolean gimp_temp_gradient_idle (GimpGradientData *data); - - -/* public functions */ - -const gchar * -gimp_gradient_select_new (const gchar *title, - const gchar *gradient_name, - gint sample_size, - GimpRunGradientCallback callback, - gpointer data, - GDestroyNotify data_destroy) -{ - GimpPlugIn *plug_in = gimp_get_plug_in (); - GimpProcedure *procedure; - gchar *gradient_callback; - GimpGradientData *gradient_data; - - gradient_callback = gimp_pdb_temp_procedure_name (gimp_get_pdb ()); - - gradient_data = g_slice_new0 (GimpGradientData); - - gradient_data->gradient_callback = gradient_callback; - gradient_data->callback = callback; - gradient_data->data = data; - gradient_data->data_destroy = data_destroy; - - procedure = gimp_procedure_new (plug_in, - gradient_callback, - GIMP_PDB_PROC_TYPE_TEMPORARY, - gimp_temp_gradient_run, - gradient_data, - (GDestroyNotify) - gimp_gradient_data_free); - - GIMP_PROC_ARG_STRING (procedure, "gradient-name", - "Gradient name", - "The gradient name", - NULL, - G_PARAM_READWRITE); - - GIMP_PROC_ARG_INT (procedure, "gradient-width", - "Gradient width", - "The gradient width", - 0, G_MAXINT, 0, - G_PARAM_READWRITE); - - GIMP_PROC_ARG_FLOAT_ARRAY (procedure, "gradient-data", - "Gradient data", - "The gradient data", - G_PARAM_READWRITE); - - GIMP_PROC_ARG_BOOLEAN (procedure, "closing", - "Closing", - "If the dialog was closing", - FALSE, - G_PARAM_READWRITE); - - gimp_plug_in_add_temp_procedure (plug_in, procedure); - g_object_unref (procedure); - - if (gimp_gradients_popup (gradient_callback, title, gradient_name, - sample_size)) - { - /* Allow callbacks to be watched */ - gimp_plug_in_extension_enable (plug_in); - - return gradient_callback; - } - - gimp_plug_in_remove_temp_procedure (plug_in, gradient_callback); - - return NULL; -} - -void -gimp_gradient_select_destroy (const gchar *gradient_callback) -{ - GimpPlugIn *plug_in = gimp_get_plug_in (); - - g_return_if_fail (gradient_callback != NULL); - - gimp_plug_in_remove_temp_procedure (plug_in, gradient_callback); -} - - -/* private functions */ - -static void -gimp_gradient_data_free (GimpGradientData *data) -{ - if (data->idle_id) - g_source_remove (data->idle_id); - - if (data->gradient_callback) - { - gimp_gradients_close_popup (data->gradient_callback); - g_free (data->gradient_callback); - } - - g_free (data->gradient_name); - g_free (data->gradient_data); - - if (data->data_destroy) - data->data_destroy (data->data); - - g_slice_free (GimpGradientData, data); -} - -static GimpValueArray * -gimp_temp_gradient_run (GimpProcedure *procedure, - const GimpValueArray *args, - gpointer run_data) -{ - GimpGradientData *data = run_data; - - g_free (data->gradient_name); - g_free (data->gradient_data); - - data->gradient_name = GIMP_VALUES_DUP_STRING (args, 0); - data->width = GIMP_VALUES_GET_INT (args, 1); - data->gradient_data = GIMP_VALUES_DUP_FLOAT_ARRAY (args, 2); - data->closing = GIMP_VALUES_GET_BOOLEAN (args, 3); - - if (! data->idle_id) - data->idle_id = g_idle_add ((GSourceFunc) gimp_temp_gradient_idle, data); - - return gimp_procedure_new_return_values (procedure, GIMP_PDB_SUCCESS, NULL); -} - -static gboolean -gimp_temp_gradient_idle (GimpGradientData *data) -{ - data->idle_id = 0; - - if (data->callback) - data->callback (data->gradient_name, - data->width, - data->gradient_data, - data->closing, - data->data); - - if (data->closing) - { - gchar *gradient_callback = data->gradient_callback; - - data->gradient_callback = NULL; - gimp_gradient_select_destroy (gradient_callback); - g_free (gradient_callback); - } - - return G_SOURCE_REMOVE; -} diff --git a/libgimp/gimpgradientselect.h b/libgimp/gimpgradientselect.h deleted file mode 100644 index 972e7eb18b..0000000000 --- a/libgimp/gimpgradientselect.h +++ /dev/null @@ -1,49 +0,0 @@ -/* LIBGIMP - The GIMP Library - * Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball - * - * gimpgradientselect.h - * - * This library is free software: you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library. If not, see - * . - */ - -#if !defined (__GIMP_H_INSIDE__) && !defined (GIMP_COMPILATION) -#error "Only can be included directly." -#endif - -#ifndef __GIMP_GRADIENT_SELECT_H__ -#define __GIMP_GRADIENT_SELECT_H__ - -G_BEGIN_DECLS - - -typedef void (* GimpRunGradientCallback) (const gchar *gradient_name, - gint width, - const gdouble *grad_data, - gboolean dialog_closing, - gpointer user_data); - - -const gchar * gimp_gradient_select_new (const gchar *title, - const gchar *gradient_name, - gint sample_size, - GimpRunGradientCallback callback, - gpointer data, - GDestroyNotify data_destroy); -void gimp_gradient_select_destroy (const gchar *gradient_callback); - - -G_END_DECLS - -#endif /* __GIMP_GRADIENT_SELECT_H__ */ diff --git a/libgimp/gimpgradientselect_pdb.c b/libgimp/gimpgradientselect_pdb.c index c55c341bf2..67a47d217a 100644 --- a/libgimp/gimpgradientselect_pdb.c +++ b/libgimp/gimpgradientselect_pdb.c @@ -30,30 +30,29 @@ /** * SECTION: gimpgradientselect * @title: gimpgradientselect - * @short_description: Functions providing a gradient selection dialog. + * @short_description: Methods of a gradient chooser dialog * - * Functions providing a gradient selection dialog. + * A dialog letting a user choose a gradient. Read more at + * gimpfontselect. **/ /** * gimp_gradients_popup: - * @gradient_callback: The callback PDB proc to call when gradient selection is made. + * @gradient_callback: The callback PDB proc to call when user chooses a gradient. * @popup_title: Title of the gradient selection dialog. - * @initial_gradient: The name of the gradient to set as the first selected. - * @sample_size: Size of the sample to return when the gradient is changed. + * @initial_gradient_name: The name of the initial gradient choice. * - * Invokes the Gimp gradients selection. + * Invokes the Gimp gradients selection dialog. * - * This procedure opens the gradient selection dialog. + * Opens a dialog letting a user choose a gradient. * * Returns: TRUE on success. **/ gboolean gimp_gradients_popup (const gchar *gradient_callback, const gchar *popup_title, - const gchar *initial_gradient, - gint sample_size) + const gchar *initial_gradient_name) { GimpValueArray *args; GimpValueArray *return_vals; @@ -62,8 +61,7 @@ gimp_gradients_popup (const gchar *gradient_callback, args = gimp_value_array_new_from_types (NULL, G_TYPE_STRING, gradient_callback, G_TYPE_STRING, popup_title, - G_TYPE_STRING, initial_gradient, - G_TYPE_INT, sample_size, + G_TYPE_STRING, initial_gradient_name, G_TYPE_NONE); return_vals = gimp_pdb_run_procedure_array (gimp_get_pdb (), @@ -84,7 +82,7 @@ gimp_gradients_popup (const gchar *gradient_callback, * * Close the gradient selection dialog. * - * This procedure closes an opened gradient selection dialog. + * Closes an open gradient selection dialog. * * Returns: TRUE on success. **/ diff --git a/libgimp/gimpgradientselect_pdb.h b/libgimp/gimpgradientselect_pdb.h index e3b85937d6..c283ac5aeb 100644 --- a/libgimp/gimpgradientselect_pdb.h +++ b/libgimp/gimpgradientselect_pdb.h @@ -34,8 +34,7 @@ G_BEGIN_DECLS gboolean gimp_gradients_popup (const gchar *gradient_callback, const gchar *popup_title, - const gchar *initial_gradient, - gint sample_size); + const gchar *initial_gradient_name); gboolean gimp_gradients_close_popup (const gchar *gradient_callback); gboolean gimp_gradients_set_popup (const gchar *gradient_callback, const gchar *gradient_name); diff --git a/libgimp/gimpgradientselectbutton.c b/libgimp/gimpgradientselectbutton.c index c464edc885..b24f9ea40b 100644 --- a/libgimp/gimpgradientselectbutton.c +++ b/libgimp/gimpgradientselectbutton.c @@ -44,271 +44,157 @@ **/ -#define CELL_HEIGHT 18 -#define CELL_WIDTH 84 - -enum +struct _GimpGradientSelectButton { - GRADIENT_SET, - LAST_SIGNAL + /* !! Not a pointer, is contained. */ + GimpResourceSelectButton parent_instance; + + GtkWidget *button; + GtkWidget *drag_region_widget; + GtkWidget *preview; /* needed by draw. */ }; -enum -{ - PROP_0, - PROP_TITLE, - PROP_GRADIENT_NAME, - N_PROPS -}; - - -struct _GimpGradientSelectButtonPrivate -{ - gchar *title; - - gchar *gradient_name; /* Local copy */ - gint sample_size; - gboolean reverse; - gint n_samples; - gdouble *gradient_data; /* Local copy */ - - GtkWidget *inside; - GtkWidget *preview; -}; - - /* local function prototypes */ -static void gimp_gradient_select_button_finalize (GObject *object); +static void gimp_gradient_select_button_finalize (GObject *object); -static void gimp_gradient_select_button_set_property (GObject *object, - guint property_id, - const GValue *value, - GParamSpec *pspec); -static void gimp_gradient_select_button_get_property (GObject *object, - guint property_id, - GValue *value, - GParamSpec *pspec); +static void gimp_gradient_select_button_embed_interior (GimpGradientSelectButton *self); +static void gimp_gradient_select_button_draw_interior (GimpResourceSelectButton *self); +static void gimp_gradient_select_button_set_drag_target (GimpGradientSelectButton *self); -static void gimp_gradient_select_button_clicked (GimpGradientSelectButton *button); - -static void gimp_gradient_select_button_callback (const gchar *gradient_name, - gint n_samples, - const gdouble *gradient_data, - gboolean dialog_closing, - gpointer user_data); - -static void gimp_gradient_select_preview_size_allocate - (GtkWidget *widget, - GtkAllocation *allocation, - GimpGradientSelectButton *button); -static gboolean gimp_gradient_select_preview_draw (GtkWidget *preview, - cairo_t *cr, - GimpGradientSelectButton *button); - -static void gimp_gradient_select_drag_data_received (GimpGradientSelectButton *button, - GdkDragContext *context, - gint x, - gint y, - GtkSelectionData *selection, - guint info, - guint time); - -static GtkWidget * gimp_gradient_select_button_create_inside (GimpGradientSelectButton *button); +static void gimp_gradient_select_preview_size_allocate (GtkWidget *widget, + GtkAllocation *allocation, + GimpGradientSelectButton *self); +static gboolean gimp_gradient_select_preview_draw_handler (GtkWidget *preview, + cairo_t *cr, + GimpGradientSelectButton *self); -static const GtkTargetEntry target = { "application/x-gimp-gradient-name", 0 }; +static const GtkTargetEntry drag_target = { "application/x-gimp-gradient-name", 0 }; -static guint gradient_button_signals[LAST_SIGNAL] = { 0 }; -static GParamSpec *gradient_button_props[N_PROPS] = { NULL, }; - - -G_DEFINE_TYPE_WITH_PRIVATE (GimpGradientSelectButton, - gimp_gradient_select_button, - GIMP_TYPE_SELECT_BUTTON) +G_DEFINE_FINAL_TYPE (GimpGradientSelectButton, + gimp_gradient_select_button, + GIMP_TYPE_RESOURCE_SELECT_BUTTON) +/* Initial dimensions of widget. */ +#define CELL_HEIGHT 18 +#define CELL_WIDTH 84 static void gimp_gradient_select_button_class_init (GimpGradientSelectButtonClass *klass) { - GObjectClass *object_class = G_OBJECT_CLASS (klass); - GimpSelectButtonClass *select_button_class = GIMP_SELECT_BUTTON_CLASS (klass); + GObjectClass *object_class = G_OBJECT_CLASS (klass); + GimpResourceSelectButtonClass *superclass = GIMP_RESOURCE_SELECT_BUTTON_CLASS (klass); + + g_debug ("%s", G_STRFUNC); object_class->finalize = gimp_gradient_select_button_finalize; - object_class->set_property = gimp_gradient_select_button_set_property; - object_class->get_property = gimp_gradient_select_button_get_property; - select_button_class->select_destroy = gimp_gradient_select_destroy; + /* Implement pure virtual functions. */ + superclass->draw_interior = gimp_gradient_select_button_draw_interior; - klass->gradient_set = NULL; - - /** - * GimpGradientSelectButton:title: - * - * The title to be used for the gradient selection popup dialog. - * - * Since: 2.4 - */ - gradient_button_props[PROP_TITLE] = g_param_spec_string ("title", - "Title", - "The title to be used for the gradient selection popup dialog", - _("Gradient Selection"), - GIMP_PARAM_READWRITE | - G_PARAM_CONSTRUCT_ONLY); - - /** - * GimpGradientSelectButton:gradient-name: - * - * The name of the currently selected gradient. - * - * Since: 2.4 - */ - gradient_button_props[PROP_GRADIENT_NAME] = g_param_spec_string ("gradient-name", - "Gradient name", - "The name of the currently selected gradient", - NULL, - GIMP_PARAM_READWRITE); - - g_object_class_install_properties (object_class, N_PROPS, gradient_button_props); - - /** - * GimpGradientSelectButton::gradient-set: - * @widget: the object which received the signal. - * @gradient_name: the name of the currently selected gradient. - * @width: width of the gradient - * @grad_data: gradient data - * @dialog_closing: whether the dialog was closed or not. - * - * The ::gradient-set signal is emitted when the user selects a gradient. - * - * Since: 2.4 - */ - gradient_button_signals[GRADIENT_SET] = - g_signal_new ("gradient-set", - G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_FIRST, - G_STRUCT_OFFSET (GimpGradientSelectButtonClass, gradient_set), - NULL, NULL, - _gimpui_marshal_VOID__STRING_INT_POINTER_BOOLEAN, - G_TYPE_NONE, 4, - G_TYPE_STRING, - G_TYPE_INT, - G_TYPE_POINTER, - G_TYPE_BOOLEAN); + /* Set data member of class. */ + superclass->resource_type = GIMP_TYPE_GRADIENT; } static void -gimp_gradient_select_button_init (GimpGradientSelectButton *button) +gimp_gradient_select_button_init (GimpGradientSelectButton *self) { - button->priv = gimp_gradient_select_button_get_instance_private (button); + g_debug ("%s", G_STRFUNC); - button->priv->gradient_name = gimp_context_get_gradient (); - button->priv->sample_size = CELL_WIDTH; - button->priv->reverse = FALSE; + gimp_gradient_select_button_embed_interior (self); - button->priv->inside = gimp_gradient_select_button_create_inside (button); - gtk_container_add (GTK_CONTAINER (button), button->priv->inside); + gimp_gradient_select_button_set_drag_target (self); + + gimp_resource_select_button_set_clickable (GIMP_RESOURCE_SELECT_BUTTON (self), + self->button); } /** * gimp_gradient_select_button_new: * @title: (nullable): Title of the dialog to use or %NULL to use the default title. - * @gradient_name: (nullable): Initial gradient name. + * @gradient: (nullable): Initial gradient. * - * Creates a new #GtkWidget that completely controls the selection of - * a gradient. This widget is suitable for placement in a table in a - * plug-in dialog. + * Creates a new #GtkWidget that lets a user choose a gradient. + * You can use this widget in a table in a plug-in dialog. * * Returns: A #GtkWidget that you can use in your UI. * * Since: 2.4 */ GtkWidget * -gimp_gradient_select_button_new (const gchar *title, - const gchar *gradient_name) +gimp_gradient_select_button_new (const gchar *title, + GimpResource *gradient) { - GtkWidget *button; + GtkWidget *self; + + if (gradient == NULL) + { + g_debug ("%s defaulting gradient from context", G_STRFUNC); + gradient = GIMP_RESOURCE (gimp_context_get_gradient ()); + } + g_assert (gradient != NULL); + /* This method is polymorphic, so a factory can call it, but requires gradient. */ + g_return_val_if_fail (GIMP_IS_GRADIENT (gradient), NULL); + + g_debug ("%s", G_STRFUNC); if (title) - button = g_object_new (GIMP_TYPE_GRADIENT_SELECT_BUTTON, - "title", title, - "gradient-name", gradient_name, - NULL); + self = g_object_new (GIMP_TYPE_GRADIENT_SELECT_BUTTON, + "title", title, + "resource", gradient, + NULL); else - button = g_object_new (GIMP_TYPE_GRADIENT_SELECT_BUTTON, - "gradient-name", gradient_name, - NULL); + self = g_object_new (GIMP_TYPE_GRADIENT_SELECT_BUTTON, + "resource", gradient, + NULL); - return button; + gimp_gradient_select_button_draw_interior (GIMP_RESOURCE_SELECT_BUTTON (self)); + return self; } + /** * gimp_gradient_select_button_get_gradient: - * @button: A #GimpGradientSelectButton + * @self: A #GimpGradientSelectButton * - * Retrieves the name of currently selected gradient. + * Gets the currently selected gradient. * - * Returns: an internal copy of the gradient name which must not be freed. + * Returns: (transfer none): an internal copy of the gradient, which you must not free. * * Since: 2.4 */ -const gchar * -gimp_gradient_select_button_get_gradient (GimpGradientSelectButton *button) +GimpGradient * +gimp_gradient_select_button_get_gradient (GimpGradientSelectButton *self) { - g_return_val_if_fail (GIMP_IS_GRADIENT_SELECT_BUTTON (button), NULL); + g_debug ("%s", G_STRFUNC); - return button->priv->gradient_name; + g_return_val_if_fail (GIMP_IS_GRADIENT_SELECT_BUTTON (self), NULL); + + /* Delegate to super w upcast arg and downcast result. */ + return (GimpGradient *) gimp_resource_select_button_get_resource ((GimpResourceSelectButton*) self); } + /** * gimp_gradient_select_button_set_gradient: - * @button: A #GimpGradientSelectButton - * @gradient_name: (nullable): Gradient name to set. + * @self: A #GimpGradientSelectButton + * @gradient: (nullable): Gradient to set. * * Sets the current gradient for the gradient select button. * * Since: 2.4 */ void -gimp_gradient_select_button_set_gradient (GimpGradientSelectButton *button, - const gchar *gradient_name) +gimp_gradient_select_button_set_gradient (GimpGradientSelectButton *self, + GimpGradient *gradient) { - GimpSelectButton *select_button; + g_return_if_fail (GIMP_IS_GRADIENT_SELECT_BUTTON (self)); - g_return_if_fail (GIMP_IS_GRADIENT_SELECT_BUTTON (button)); + g_debug ("%s", G_STRFUNC); - select_button = GIMP_SELECT_BUTTON (button); - - if (select_button->temp_callback) - { - gimp_gradients_set_popup (select_button->temp_callback, gradient_name); - } - else - { - gchar *name; - gdouble *samples; - gint n_samples; - - if (gradient_name && *gradient_name) - name = g_strdup (gradient_name); - else - name = gimp_context_get_gradient (); - - if (gimp_gradient_get_uniform_samples (name, - button->priv->sample_size, - button->priv->reverse, - &n_samples, - &samples)) - { - gimp_gradient_select_button_callback (name, - n_samples, samples, - FALSE, button); - - g_free (samples); - } - - g_free (name); - } + /* Delegate to super with upcasts */ + gimp_resource_select_button_set_resource (GIMP_RESOURCE_SELECT_BUTTON (self), GIMP_RESOURCE (gradient)); } @@ -317,167 +203,117 @@ gimp_gradient_select_button_set_gradient (GimpGradientSelectButton *button, static void gimp_gradient_select_button_finalize (GObject *object) { - GimpGradientSelectButton *button = GIMP_GRADIENT_SELECT_BUTTON (object); + g_debug ("%s", G_STRFUNC); - g_clear_pointer (&button->priv->gradient_name, g_free); - g_clear_pointer (&button->priv->gradient_data, g_free); - g_clear_pointer (&button->priv->title, g_free); + /* Nothing was allocated. */ G_OBJECT_CLASS (gimp_gradient_select_button_parent_class)->finalize (object); } static void -gimp_gradient_select_button_set_property (GObject *object, - guint property_id, - const GValue *value, - GParamSpec *pspec) +gimp_gradient_select_button_draw_interior (GimpResourceSelectButton *self) { - GimpGradientSelectButton *button = GIMP_GRADIENT_SELECT_BUTTON (object); + GimpGradientSelectButton *self_as_gradient_select; - switch (property_id) - { - case PROP_TITLE: - button->priv->title = g_value_dup_string (value); - break; + g_debug ("%s", G_STRFUNC); - case PROP_GRADIENT_NAME: - gimp_gradient_select_button_set_gradient (button, - g_value_get_string (value)); - break; + g_return_if_fail (GIMP_IS_GRADIENT_SELECT_BUTTON (self)); + self_as_gradient_select = GIMP_GRADIENT_SELECT_BUTTON (self); - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); - break; - } + /* Not actually draw, just queue. Continuation is the handler. */ + gtk_widget_queue_draw (self_as_gradient_select->preview); } -static void -gimp_gradient_select_button_get_property (GObject *object, - guint property_id, - GValue *value, - GParamSpec *pspec) -{ - GimpGradientSelectButton *button = GIMP_GRADIENT_SELECT_BUTTON (object); - - switch (property_id) - { - case PROP_TITLE: - g_value_set_string (value, button->priv->title); - break; - - case PROP_GRADIENT_NAME: - g_value_set_string (value, button->priv->gradient_name); - break; - - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); - break; - } -} - -static void -gimp_gradient_select_button_callback (const gchar *gradient_name, - gint n_samples, - const gdouble *gradient_data, - gboolean dialog_closing, - gpointer user_data) -{ - GimpGradientSelectButton *button = user_data; - GimpSelectButton *select_button = GIMP_SELECT_BUTTON (button); - - g_free (button->priv->gradient_name); - g_free (button->priv->gradient_data); - - button->priv->gradient_name = g_strdup (gradient_name); - button->priv->n_samples = n_samples; - button->priv->gradient_data = g_memdup2 (gradient_data, - n_samples * sizeof (gdouble)); - - gtk_widget_queue_draw (button->priv->preview); - - if (dialog_closing) - select_button->temp_callback = NULL; - - g_signal_emit (button, gradient_button_signals[GRADIENT_SET], 0, - gradient_name, n_samples, gradient_data, dialog_closing); - g_object_notify_by_pspec (G_OBJECT (button), gradient_button_props[PROP_GRADIENT_NAME]); -} - -static void -gimp_gradient_select_button_clicked (GimpGradientSelectButton *button) -{ - GimpSelectButton *select_button = GIMP_SELECT_BUTTON (button); - - if (select_button->temp_callback) - { - /* calling gimp_gradients_set_popup() raises the dialog */ - gimp_gradients_set_popup (select_button->temp_callback, - button->priv->gradient_name); - } - else - { - select_button->temp_callback = - gimp_gradient_select_new (button->priv->title, - button->priv->gradient_name, - button->priv->sample_size, - gimp_gradient_select_button_callback, - button, NULL); - } -} - -static void -gimp_gradient_select_preview_size_allocate (GtkWidget *widget, - GtkAllocation *allocation, - GimpGradientSelectButton *button) +/* Get array of samples from self's gradient. + * Return array and size at given handles. + * Return success. + */ +static gboolean +get_gradient_data (GimpGradientSelectButton *self, + gint allocation_width, + gint *sample_count, + gdouble **sample_array + ) { + gboolean result; gdouble *samples; gint n_samples; - if (gimp_gradient_get_uniform_samples (button->priv->gradient_name, - allocation->width, - button->priv->reverse, - &n_samples, - &samples)) - { - g_free (button->priv->gradient_data); + GimpGradient *gradient; - button->priv->sample_size = allocation->width; - button->priv->n_samples = n_samples; - button->priv->gradient_data = samples; + g_debug ("%s", G_STRFUNC); + + /* Self's gradient is property "resource" + * (resource field of super is private.) + */ + g_object_get (self, "resource", &gradient, NULL); + g_return_val_if_fail (GIMP_IS_GRADIENT (gradient), FALSE); + + result = gimp_gradient_get_uniform_samples ( + gradient, + allocation_width, + FALSE, /* not reversed. */ + &n_samples, + &samples); + + if (result) + { + /* Return array of samples to dereferenced handles. */ + *sample_array = samples; + *sample_count = n_samples; } + + /* When result is true, caller must free the array. */ + return result; } -static gboolean -gimp_gradient_select_preview_draw (GtkWidget *widget, - cairo_t *cr, - GimpGradientSelectButton *button) + +/* Called on widget resized. */ +static void +gimp_gradient_select_preview_size_allocate (GtkWidget *widget, + GtkAllocation *allocation, + GimpGradientSelectButton *self) +{ + g_debug ("%s", G_STRFUNC); + + /* Do nothing. + * + * In former code, we cached the gradient data in self, on allocate event. + * But allocate event always seems to be paired with a draw event, + * so there is no point in caching the gradient data. + * And caching gradient data is a premature optimization, + * without deep knowledge of Gtk and actual performance testing, + * you can't know caching helps performance. + */ +} + + + +/* Draw array of samples. + * This understands mostly cairo, and little about gradient. + */ +static void +gimp_gradient_select_preview_draw ( + cairo_t *cr, + gint src_width, + gint dest_width, + gdouble *src) { - GtkAllocation allocation; cairo_pattern_t *pattern; cairo_surface_t *surface; - const gdouble *src; guchar *dest; - gint width; gint x; - src = button->priv->gradient_data; - if (! src) - return FALSE; - - gtk_widget_get_allocation (widget, &allocation); - pattern = gimp_cairo_checkerboard_create (cr, GIMP_CHECK_SIZE_SM, NULL, NULL); cairo_set_source (cr, pattern); cairo_pattern_destroy (pattern); cairo_paint (cr); - width = button->priv->n_samples / 4; - - surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, width, 1); + surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, src_width, 1); for (x = 0, dest = cairo_image_surface_get_data (surface); - x < width; + x < src_width; x++, src += 4, dest += 4) { GimpRGB color; @@ -486,7 +322,7 @@ gimp_gradient_select_preview_draw (GtkWidget *widget, gimp_rgba_set (&color, src[0], src[1], src[2], src[3]); gimp_rgba_get_uchar (&color, &r, &g, &b, &a); - GIMP_CAIRO_ARGB32_SET_PIXEL(dest, r, g, b, a); + GIMP_CAIRO_ARGB32_SET_PIXEL (dest, r, g, b, a); } cairo_surface_mark_dirty (surface); @@ -495,91 +331,94 @@ gimp_gradient_select_preview_draw (GtkWidget *widget, cairo_pattern_set_extend (pattern, CAIRO_EXTEND_REFLECT); cairo_surface_destroy (surface); - cairo_scale (cr, (gdouble) allocation.width / (gdouble) width, 1.0); + cairo_scale (cr, (gdouble) dest_width / (gdouble) src_width, 1.0); cairo_set_source (cr, pattern); cairo_pattern_destroy (pattern); cairo_paint (cr); +} + + + +/* Handles a draw signal. + * Draw self, i.e. interior of button. + * + * Always returns FALSE, but doesn't draw when fail to get gradient data. + * + * Is passed neither gradient nor attributes of gradient: get them now from self. + */ +static gboolean +gimp_gradient_select_preview_draw_handler ( + GtkWidget *widget, + cairo_t *cr, + GimpGradientSelectButton *self) +{ + GtkAllocation allocation; + + /* Attributes of the source.*/ + gdouble *src; + gint n_samples; + gint src_width; + + g_debug ("%s", G_STRFUNC); + + gtk_widget_get_allocation (widget, &allocation); + + if (!get_gradient_data (self, allocation.width, &n_samples, &src)) + return FALSE; + + /* Width in pixels of src, since BPP is 4. */ + src_width = n_samples / 4; + + gimp_gradient_select_preview_draw (cr, src_width, allocation.width, src); + + g_free (src); return FALSE; } + static void -gimp_gradient_select_drag_data_received (GimpGradientSelectButton *button, - GdkDragContext *context, - gint x, - gint y, - GtkSelectionData *selection, - guint info, - guint time) +gimp_gradient_select_button_embed_interior (GimpGradientSelectButton *self) { - gint length = gtk_selection_data_get_length (selection); - gchar *str; + GtkWidget *button; + GtkWidget *preview; - if (gtk_selection_data_get_format (selection) != 8 || length < 1) - { - g_warning ("%s: received invalid gradient data", G_STRFUNC); - return; - } - - str = g_strndup ((const gchar *) gtk_selection_data_get_data (selection), - length); - - if (g_utf8_validate (str, -1, NULL)) - { - gint pid; - gpointer unused; - gint name_offset = 0; - - if (sscanf (str, "%i:%p:%n", &pid, &unused, &name_offset) >= 2 && - pid == gimp_getpid () && name_offset > 0) - { - gchar *name = str + name_offset; - - gimp_gradient_select_button_set_gradient (button, name); - } - } - - g_free (str); -} - -static GtkWidget * -gimp_gradient_select_button_create_inside (GimpGradientSelectButton *gradient_button) -{ - GimpGradientSelectButtonPrivate *priv = gradient_button->priv; - GtkWidget *button; + g_debug ("%s", G_STRFUNC); + /* Outermost is button. */ button = gtk_button_new (); - priv->preview = gtk_drawing_area_new (); - gtk_widget_set_size_request (priv->preview, CELL_WIDTH, CELL_HEIGHT); - gtk_container_add (GTK_CONTAINER (button), priv->preview); + /* Entire interior of button is a preview image. */ + preview = gtk_drawing_area_new (); + gtk_widget_set_size_request (preview, CELL_WIDTH, CELL_HEIGHT); + gtk_container_add (GTK_CONTAINER (button), preview); - g_signal_connect (priv->preview, "size-allocate", + g_signal_connect (preview, "size-allocate", G_CALLBACK (gimp_gradient_select_preview_size_allocate), - gradient_button); + self); - g_signal_connect (priv->preview, "draw", - G_CALLBACK (gimp_gradient_select_preview_draw), - gradient_button); + g_signal_connect (preview, "draw", + G_CALLBACK (gimp_gradient_select_preview_draw_handler), + self); gtk_widget_show_all (button); - g_signal_connect_swapped (button, "clicked", - G_CALLBACK (gimp_gradient_select_button_clicked), - gradient_button); + /* Remember widgets needed later. */ + self->drag_region_widget = preview; + self->button = button; + self->preview = preview; - gtk_drag_dest_set (GTK_WIDGET (button), - GTK_DEST_DEFAULT_HIGHLIGHT | - GTK_DEST_DEFAULT_MOTION | - GTK_DEST_DEFAULT_DROP, - &target, 1, - GDK_ACTION_COPY); - - g_signal_connect_swapped (button, "drag-data-received", - G_CALLBACK (gimp_gradient_select_drag_data_received), - gradient_button); - - return button; + /* Call super with upcasts. */ + gimp_resource_select_button_embed_interior (GIMP_RESOURCE_SELECT_BUTTON (self), button); +} + +static void +gimp_gradient_select_button_set_drag_target (GimpGradientSelectButton *self) +{ + /* Self knows the GtkTargetEntry, super knows how to create target and receive drag. */ + gimp_resource_select_button_set_drag_target (GIMP_RESOURCE_SELECT_BUTTON (self), + self->drag_region_widget, + &drag_target); } diff --git a/libgimp/gimpgradientselectbutton.h b/libgimp/gimpgradientselectbutton.h index 2d0549385a..e2bfbe5e4f 100644 --- a/libgimp/gimpgradientselectbutton.h +++ b/libgimp/gimpgradientselectbutton.h @@ -25,62 +25,28 @@ #ifndef __GIMP_GRADIENT_SELECT_BUTTON_H__ #define __GIMP_GRADIENT_SELECT_BUTTON_H__ -#include +#include G_BEGIN_DECLS -/* For information look into the C source or the html documentation */ - - -#define GIMP_TYPE_GRADIENT_SELECT_BUTTON (gimp_gradient_select_button_get_type ()) -#define GIMP_GRADIENT_SELECT_BUTTON(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GIMP_TYPE_GRADIENT_SELECT_BUTTON, GimpGradientSelectButton)) -#define GIMP_GRADIENT_SELECT_BUTTON_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GIMP_TYPE_GRADIENT_SELECT_BUTTON, GimpGradientSelectButtonClass)) -#define GIMP_IS_GRADIENT_SELECT_BUTTON(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GIMP_TYPE_GRADIENT_SELECT_BUTTON)) -#define GIMP_IS_GRADIENT_SELECT_BUTTON_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GIMP_TYPE_GRADIENT_SELECT_BUTTON)) -#define GIMP_GRADIENT_SELECT_BUTTON_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GIMP_TYPE_GRADIENT_SELECT_BUTTON, GimpGradientSelectButtonClass)) - - -typedef struct _GimpGradientSelectButtonPrivate GimpGradientSelectButtonPrivate; -typedef struct _GimpGradientSelectButtonClass GimpGradientSelectButtonClass; - -struct _GimpGradientSelectButton -{ - GimpSelectButton parent_instance; - - GimpGradientSelectButtonPrivate *priv; -}; +#define GIMP_TYPE_GRADIENT_SELECT_BUTTON (gimp_gradient_select_button_get_type ()) +G_DECLARE_FINAL_TYPE (GimpGradientSelectButton, + gimp_gradient_select_button, + GIMP, + GRADIENT_SELECT_BUTTON, + GimpResourceSelectButton) struct _GimpGradientSelectButtonClass { - GimpSelectButtonClass parent_class; - - /* gradient_set signal is emitted when gradient is chosen */ - void (* gradient_set) (GimpGradientSelectButton *button, - const gchar *gradient_name, - gint width, - const gdouble *gradient_data, - gboolean dialog_closing); - - /* Padding for future expansion */ - void (*_gimp_reserved1) (void); - void (*_gimp_reserved2) (void); - void (*_gimp_reserved3) (void); - void (*_gimp_reserved4) (void); - void (*_gimp_reserved5) (void); - void (*_gimp_reserved6) (void); - void (*_gimp_reserved7) (void); - void (*_gimp_reserved8) (void); + GimpResourceSelectButtonClass parent_class; }; +GtkWidget * gimp_gradient_select_button_new (const gchar *title, + GimpResource *gradient); -GType gimp_gradient_select_button_get_type (void) G_GNUC_CONST; - -GtkWidget * gimp_gradient_select_button_new (const gchar *title, - const gchar *gradient_name); - -const gchar * gimp_gradient_select_button_get_gradient (GimpGradientSelectButton *button); -void gimp_gradient_select_button_set_gradient (GimpGradientSelectButton *button, - const gchar *gradient_name); +GimpGradient *gimp_gradient_select_button_get_gradient (GimpGradientSelectButton *self); +void gimp_gradient_select_button_set_gradient (GimpGradientSelectButton *self, + GimpGradient *gradient); G_END_DECLS diff --git a/libgimp/gimppaletteselect.c b/libgimp/gimppaletteselect.c deleted file mode 100644 index 0df01c3f4c..0000000000 --- a/libgimp/gimppaletteselect.c +++ /dev/null @@ -1,187 +0,0 @@ -/* LIBGIMP - The GIMP Library - * Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball - * - * gimppaletteselect.c - * - * This library is free software: you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library. If not, see - * . - */ - -#include "config.h" - -#include "gimp.h" - - -typedef struct -{ - gchar *palette_callback; - guint idle_id; - gchar *palette_name; - gint num_colors; - GimpRunPaletteCallback callback; - gboolean closing; - gpointer data; - GDestroyNotify data_destroy; -} GimpPaletteData; - - -/* local function prototypes */ - -static void gimp_palette_data_free (GimpPaletteData *data); - -static GimpValueArray * gimp_temp_palette_run (GimpProcedure *procedure, - const GimpValueArray *args, - gpointer run_data); -static gboolean gimp_temp_palette_idle (GimpPaletteData *data); - - -/* public functions */ - -const gchar * -gimp_palette_select_new (const gchar *title, - const gchar *palette_name, - GimpRunPaletteCallback callback, - gpointer data, - GDestroyNotify data_destroy) -{ - GimpPlugIn *plug_in = gimp_get_plug_in (); - GimpProcedure *procedure; - gchar *palette_callback; - GimpPaletteData *palette_data; - - palette_callback = gimp_pdb_temp_procedure_name (gimp_get_pdb ()); - - palette_data = g_slice_new0 (GimpPaletteData); - - palette_data->palette_callback = palette_callback; - palette_data->callback = callback; - palette_data->data = data; - palette_data->data_destroy = data_destroy; - - procedure = gimp_procedure_new (plug_in, - palette_callback, - GIMP_PDB_PROC_TYPE_TEMPORARY, - gimp_temp_palette_run, - palette_data, - (GDestroyNotify) - gimp_palette_data_free); - - GIMP_PROC_ARG_STRING (procedure, "palette-name", - "Palette name", - "The palette name", - NULL, - G_PARAM_READWRITE); - - GIMP_PROC_ARG_INT (procedure, "num-colors", - "Num colors", - "Number of colors", - 0, G_MAXINT, 0, - G_PARAM_READWRITE); - - GIMP_PROC_ARG_BOOLEAN (procedure, "closing", - "Closing", - "If the dialog was closing", - FALSE, - G_PARAM_READWRITE); - - gimp_plug_in_add_temp_procedure (plug_in, procedure); - g_object_unref (procedure); - - if (gimp_palettes_popup (palette_callback, title, palette_name)) - { - /* Allow callbacks to be watched */ - gimp_plug_in_extension_enable (plug_in); - - return palette_callback; - } - - gimp_plug_in_remove_temp_procedure (plug_in, palette_callback); - - return NULL; -} - -void -gimp_palette_select_destroy (const gchar *palette_callback) -{ - GimpPlugIn *plug_in = gimp_get_plug_in (); - - g_return_if_fail (palette_callback != NULL); - - gimp_plug_in_remove_temp_procedure (plug_in, palette_callback); -} - - -/* private functions */ - -static void -gimp_palette_data_free (GimpPaletteData *data) -{ - if (data->idle_id) - g_source_remove (data->idle_id); - - if (data->palette_callback) - { - gimp_palettes_close_popup (data->palette_callback); - g_free (data->palette_callback); - } - - g_free (data->palette_name); - - if (data->data_destroy) - data->data_destroy (data->data); - - g_slice_free (GimpPaletteData, data); -} - -static GimpValueArray * -gimp_temp_palette_run (GimpProcedure *procedure, - const GimpValueArray *args, - gpointer run_data) -{ - GimpPaletteData *data = run_data; - - g_free (data->palette_name); - - data->palette_name = GIMP_VALUES_DUP_STRING (args, 0); - data->num_colors = GIMP_VALUES_GET_INT (args, 1); - data->closing = GIMP_VALUES_GET_BOOLEAN (args, 2); - - if (! data->idle_id) - data->idle_id = g_idle_add ((GSourceFunc) gimp_temp_palette_idle, - data); - - return gimp_procedure_new_return_values (procedure, GIMP_PDB_SUCCESS, NULL); -} - -static gboolean -gimp_temp_palette_idle (GimpPaletteData *data) -{ - data->idle_id = 0; - - if (data->callback) - data->callback (data->palette_name, - data->closing, - data->data); - - if (data->closing) - { - gchar *palette_callback = data->palette_callback; - - data->palette_callback = NULL; - gimp_palette_select_destroy (palette_callback); - g_free (palette_callback); - } - - return G_SOURCE_REMOVE; -} diff --git a/libgimp/gimppaletteselect.h b/libgimp/gimppaletteselect.h deleted file mode 100644 index 505ee1d9eb..0000000000 --- a/libgimp/gimppaletteselect.h +++ /dev/null @@ -1,46 +0,0 @@ -/* LIBGIMP - The GIMP Library - * Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball - * - * gimppaletteselect.h - * - * This library is free software: you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library. If not, see - * . - */ - -#if !defined (__GIMP_H_INSIDE__) && !defined (GIMP_COMPILATION) -#error "Only can be included directly." -#endif - -#ifndef __GIMP_PALETTE_SELECT_H__ -#define __GIMP_PALETTE_SELECT_H__ - -G_BEGIN_DECLS - - -typedef void (* GimpRunPaletteCallback) (const gchar *palette_name, - gboolean dialog_closing, - gpointer user_data); - - -const gchar * gimp_palette_select_new (const gchar *title, - const gchar *palette_name, - GimpRunPaletteCallback callback, - gpointer data, - GDestroyNotify data_destroy); -void gimp_palette_select_destroy (const gchar *palette_callback); - - -G_END_DECLS - -#endif /* __GIMP_PALETTE_SELECT_H__ */ diff --git a/libgimp/gimppaletteselect_pdb.c b/libgimp/gimppaletteselect_pdb.c index 6a1ebaa9c6..72c9cd0730 100644 --- a/libgimp/gimppaletteselect_pdb.c +++ b/libgimp/gimppaletteselect_pdb.c @@ -30,28 +30,29 @@ /** * SECTION: gimppaletteselect * @title: gimppaletteselect - * @short_description: Functions providing a palette selection dialog. + * @short_description: Methods of a palette chooser dialog * - * Functions providing a palette selection dialog. + * A dialog letting a user choose a palette. Read more at + * gimpfontselect. **/ /** * gimp_palettes_popup: - * @palette_callback: The callback PDB proc to call when palette selection is made. + * @palette_callback: The callback PDB proc to call when user chooses a palette. * @popup_title: Title of the palette selection dialog. - * @initial_palette: The name of the palette to set as the first selected. + * @initial_palette_name: The palette to set as the initial choice. * - * Invokes the Gimp palette selection. + * Invokes the Gimp palette selection dialog. * - * This procedure opens the palette selection dialog. + * Opens a dialog letting a user choose a palette. * * Returns: TRUE on success. **/ gboolean gimp_palettes_popup (const gchar *palette_callback, const gchar *popup_title, - const gchar *initial_palette) + const gchar *initial_palette_name) { GimpValueArray *args; GimpValueArray *return_vals; @@ -60,7 +61,7 @@ gimp_palettes_popup (const gchar *palette_callback, args = gimp_value_array_new_from_types (NULL, G_TYPE_STRING, palette_callback, G_TYPE_STRING, popup_title, - G_TYPE_STRING, initial_palette, + G_TYPE_STRING, initial_palette_name, G_TYPE_NONE); return_vals = gimp_pdb_run_procedure_array (gimp_get_pdb (), @@ -81,7 +82,7 @@ gimp_palettes_popup (const gchar *palette_callback, * * Close the palette selection dialog. * - * This procedure closes an opened palette selection dialog. + * Closes an open palette selection dialog. * * Returns: TRUE on success. **/ diff --git a/libgimp/gimppaletteselect_pdb.h b/libgimp/gimppaletteselect_pdb.h index 221ec4b7b3..840108db9d 100644 --- a/libgimp/gimppaletteselect_pdb.h +++ b/libgimp/gimppaletteselect_pdb.h @@ -34,7 +34,7 @@ G_BEGIN_DECLS gboolean gimp_palettes_popup (const gchar *palette_callback, const gchar *popup_title, - const gchar *initial_palette); + const gchar *initial_palette_name); gboolean gimp_palettes_close_popup (const gchar *palette_callback); gboolean gimp_palettes_set_popup (const gchar *palette_callback, const gchar *palette_name); diff --git a/libgimp/gimppaletteselectbutton.c b/libgimp/gimppaletteselectbutton.c index b4a57197c8..ef782f5ab6 100644 --- a/libgimp/gimppaletteselectbutton.c +++ b/libgimp/gimppaletteselectbutton.c @@ -19,6 +19,8 @@ * . */ +/* Similar to gimpfontselectbutton.c, initially created by simple substitution. */ + #include "config.h" #include @@ -37,241 +39,199 @@ /** * SECTION: gimppaletteselectbutton - * @title: GimpPaletteSelect - * @short_description: A button which pops up a palette select dialog. + * @title: GimpPaletteSelectButton + * @short_description: A button which pops up a palette selection dialog. * - * A button which pops up a palette select dialog. + * A button which pops up a palette selection dialog. **/ - -struct _GimpPaletteSelectButtonPrivate +struct _GimpPaletteSelectButton { - gchar *title; + /* !! Not a pointer, is contained. */ + GimpResourceSelectButton parent_instance; - gchar *palette_name; /* Local copy */ - - GtkWidget *inside; - GtkWidget *label; + GtkWidget *palette_name_label; + GtkWidget *drag_region_widget; + GtkWidget *button; }; -enum -{ - PALETTE_SET, - LAST_SIGNAL -}; +/* local */ -enum -{ - PROP_0, - PROP_TITLE, - PROP_PALETTE_NAME, - N_PROPS -}; +/* implement virtual */ +static void gimp_palette_select_button_finalize (GObject *object); +static void gimp_palette_select_button_draw_interior (GimpResourceSelectButton *self); +/* Called at init. */ +static GtkWidget *gimp_palette_select_button_create_interior (GimpPaletteSelectButton *self); -/* local function prototypes */ +/* A GtkTargetEntry has a string and two ints. This is one, but treat as an array.*/ +static const GtkTargetEntry drag_target = { "application/x-gimp-palette-name", 0, 0 }; -static void gimp_palette_select_button_finalize (GObject *object); - -static void gimp_palette_select_button_set_property (GObject *object, - guint property_id, - const GValue *value, - GParamSpec *pspec); -static void gimp_palette_select_button_get_property (GObject *object, - guint property_id, - GValue *value, - GParamSpec *pspec); - -static void gimp_palette_select_button_clicked (GimpPaletteSelectButton *button); - -static void gimp_palette_select_button_callback (const gchar *palette_name, - gboolean dialog_closing, - gpointer user_data); - -static void gimp_palette_select_drag_data_received (GimpPaletteSelectButton *button, - GdkDragContext *context, - gint x, - gint y, - GtkSelectionData *selection, - guint info, - guint time); - -static GtkWidget * gimp_palette_select_button_create_inside (GimpPaletteSelectButton *palette_button); - - -static const GtkTargetEntry target = { "application/x-gimp-palette-name", 0 }; - -static guint palette_button_signals[LAST_SIGNAL] = { 0 }; -static GParamSpec *palette_button_props[N_PROPS] = { NULL, }; - - -G_DEFINE_TYPE_WITH_PRIVATE (GimpPaletteSelectButton, gimp_palette_select_button, - GIMP_TYPE_SELECT_BUTTON) +G_DEFINE_FINAL_TYPE (GimpPaletteSelectButton, + gimp_palette_select_button, + GIMP_TYPE_RESOURCE_SELECT_BUTTON) static void gimp_palette_select_button_class_init (GimpPaletteSelectButtonClass *klass) { - GObjectClass *object_class = G_OBJECT_CLASS (klass); - GimpSelectButtonClass *select_button_class = GIMP_SELECT_BUTTON_CLASS (klass); + /* Alias cast klass to super classes. */ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + GimpResourceSelectButtonClass *superclass = GIMP_RESOURCE_SELECT_BUTTON_CLASS (klass); + g_debug ("%s called", G_STRFUNC); + + /* Override virtual. */ object_class->finalize = gimp_palette_select_button_finalize; - object_class->set_property = gimp_palette_select_button_set_property; - object_class->get_property = gimp_palette_select_button_get_property; - select_button_class->select_destroy = gimp_palette_select_destroy; + /* Implement pure virtual functions. */ + superclass->draw_interior = gimp_palette_select_button_draw_interior; - klass->palette_set = NULL; + /* Set data member of class. */ + superclass->resource_type = GIMP_TYPE_PALETTE; - /** - * GimpPaletteSelectButton:title: - * - * The title to be used for the palette selection popup dialog. - * - * Since: 2.4 + /* We don't define property getter/setters: use superclass getter/setters. + * But super property name is "resource", not "palette" */ - palette_button_props[PROP_TITLE] = g_param_spec_string ("title", - "Title", - "The title to be used for the palette selection popup dialog", - _("Palette Selection"), - GIMP_PARAM_READWRITE | - G_PARAM_CONSTRUCT_ONLY); - - /** - * GimpPaletteSelectButton:palette-name: - * - * The name of the currently selected palette. - * - * Since: 2.4 - */ - palette_button_props[PROP_PALETTE_NAME] = g_param_spec_string ("palette-name", - "Palette name", - "The name of the currently selected palette", - NULL, - GIMP_PARAM_READWRITE); - - g_object_class_install_properties (object_class, N_PROPS, palette_button_props); - - /** - * GimpPaletteSelectButton::palette-set: - * @widget: the object which received the signal. - * @palette_name: the name of the currently selected palette. - * @dialog_closing: whether the dialog was closed or not. - * - * The ::palette-set signal is emitted when the user selects a palette. - * - * Since: 2.4 - */ - palette_button_signals[PALETTE_SET] = - g_signal_new ("palette-set", - G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_FIRST, - G_STRUCT_OFFSET (GimpPaletteSelectButtonClass, palette_set), - NULL, NULL, - _gimpui_marshal_VOID__STRING_BOOLEAN, - G_TYPE_NONE, 2, - G_TYPE_STRING, - G_TYPE_BOOLEAN); } static void -gimp_palette_select_button_init (GimpPaletteSelectButton *button) +gimp_palette_select_button_init (GimpPaletteSelectButton *self) { - button->priv = gimp_palette_select_button_get_instance_private (button); + GtkWidget *interior; - button->priv->inside = gimp_palette_select_button_create_inside (button); - gtk_container_add (GTK_CONTAINER (button), button->priv->inside); + g_debug ("%s called", G_STRFUNC); + + /* Specialize super: + * - embed our widget interior instance to super widget instance. + * - tell super our dnd widget + * - tell super our clickable button + * Call superclass methods, with upcasts. + * These are on instance, not our subclass. + */ + interior = gimp_palette_select_button_create_interior (self); + /* require self has sub widgets initialized. */ + + /* Embed the whole button.*/ + gimp_resource_select_button_embed_interior (GIMP_RESOURCE_SELECT_BUTTON (self), interior); + + /* Self knows the GtkTargetEntry, super creates target and handles receive drag. */ + gimp_resource_select_button_set_drag_target (GIMP_RESOURCE_SELECT_BUTTON (self), + self->drag_region_widget, + &drag_target); + /* Super handles button clicks. */ + gimp_resource_select_button_set_clickable (GIMP_RESOURCE_SELECT_BUTTON (self), + self->button); } /** * gimp_palette_select_button_new: * @title: (nullable): Title of the dialog to use or %NULL to use the default title. - * @palette_name: (nullable): Initial palette name. + * @resource: (nullable): Initial palette. * - * Creates a new #GtkWidget that completely controls the selection of - * a palette. This widget is suitable for placement in a table in a - * plug-in dialog. + * Creates a new #GtkWidget that lets a user choose a palette. + * You can put this widget in a table in a plug-in dialog. + * + * When palette is NULL, initial choice is from context. * * Returns: A #GtkWidget that you can use in your UI. * * Since: 2.4 */ GtkWidget * -gimp_palette_select_button_new (const gchar *title, - const gchar *palette_name) +gimp_palette_select_button_new (const gchar *title, + GimpResource *resource) { - GtkWidget *button; + GtkWidget *self; - if (title) - button = g_object_new (GIMP_TYPE_PALETTE_SELECT_BUTTON, - "title", title, - "palette-name", palette_name, - NULL); - else - button = g_object_new (GIMP_TYPE_PALETTE_SELECT_BUTTON, - "palette-name", palette_name, - NULL); + g_debug ("%s called", G_STRFUNC); - return button; + if (resource == NULL) + { + g_debug ("%s defaulting palette from context", G_STRFUNC); + resource = GIMP_RESOURCE (gimp_context_get_palette ()); + } + g_assert (resource != NULL); + /* This method is polymorphic, so a factory can call it, but requires Palette. */ + g_return_val_if_fail (GIMP_IS_PALETTE (resource), NULL); + + /* Create instance of self (not super.) + * This will call superclass init, self class init, superclass init, and instance init. + * Self subclass class_init will specialize by implementing virtual funcs + * that open and set remote chooser dialog, and that draw self interior. + * + * !!! property belongs to superclass and is named "resource" + */ + if (title) + self = g_object_new (GIMP_TYPE_PALETTE_SELECT_BUTTON, + "title", title, + "resource", resource, + NULL); + else + self = g_object_new (GIMP_TYPE_PALETTE_SELECT_BUTTON, + "resource", resource, + NULL); + + /* We don't subscribe to events from super (such as draw events.) + * Super will call our draw method when it's resource changes. + * Except that the above setting of property happens too late, + * so we now draw the initial resource. + */ + + /* Draw with the initial resource. Cast self from Widget. */ + gimp_palette_select_button_draw_interior (GIMP_RESOURCE_SELECT_BUTTON (self)); + + g_debug ("%s returns", G_STRFUNC); + + return self; } + +/* Getter and setter. + * We could omit these, and use only the superclass methods. + * But script-fu-interface.c uses these, until FUTURE. + */ + /** * gimp_palette_select_button_get_palette: - * @button: A #GimpPaletteSelectButton + * @self: A #GimpPaletteSelectButton * - * Retrieves the name of currently selected palette. + * Gets the currently selected palette. * - * Returns: an internal copy of the palette name which must not be freed. + * Returns: (transfer none): an internal copy of the palette which must not be freed. * * Since: 2.4 */ -const gchar * -gimp_palette_select_button_get_palette (GimpPaletteSelectButton *button) +GimpPalette * +gimp_palette_select_button_get_palette (GimpPaletteSelectButton *self) { - g_return_val_if_fail (GIMP_IS_PALETTE_SELECT_BUTTON (button), NULL); + g_return_val_if_fail (GIMP_IS_PALETTE_SELECT_BUTTON (self), NULL); - return button->priv->palette_name; + /* Delegate to super w upcast arg and downcast result. */ + return (GimpPalette *) gimp_resource_select_button_get_resource ((GimpResourceSelectButton*) self); } /** * gimp_palette_select_button_set_palette: - * @button: A #GimpPaletteSelectButton - * @palette_name: (nullable): Palette name to set; %NULL means set to palette in context. + * @self: A #GimpPaletteSelectButton + * @palette: Palette to set. * - * Sets the current palette for the palette select button. + * Sets the currently selected palette. + * Usually you should not call this; the user is in charge. + * Changes the selection in both the button and it's popup chooser. * * Since: 2.4 */ void -gimp_palette_select_button_set_palette (GimpPaletteSelectButton *button, - const gchar *palette_name) +gimp_palette_select_button_set_palette (GimpPaletteSelectButton *self, + GimpPalette *palette) { - GimpSelectButton *select_button; + g_return_if_fail (GIMP_IS_PALETTE_SELECT_BUTTON (self)); - g_return_if_fail (GIMP_IS_PALETTE_SELECT_BUTTON (button)); + g_debug ("%s", G_STRFUNC); - select_button = GIMP_SELECT_BUTTON (button); - - if (select_button->temp_callback) - { - gimp_palettes_set_popup (select_button->temp_callback, palette_name); - } - else - { - gchar *name; - - /* If not NULL and not empty string. */ - if (palette_name && *palette_name) - name = palette_name; - else - { - GimpPalette * palette = gimp_context_get_palette (); - - name = gimp_resource_get_id (GIMP_RESOURCE (palette)); - } - - gimp_palette_select_button_callback (name, FALSE, button); - } + /* Delegate to super with upcasts */ + gimp_resource_select_button_set_resource (GIMP_RESOURCE_SELECT_BUTTON (self), GIMP_RESOURCE (palette)); } @@ -280,179 +240,98 @@ gimp_palette_select_button_set_palette (GimpPaletteSelectButton *button, static void gimp_palette_select_button_finalize (GObject *object) { - GimpPaletteSelectButton *button = GIMP_PALETTE_SELECT_BUTTON (object); + g_debug ("%s called", G_STRFUNC); - g_clear_pointer (&button->priv->palette_name, g_free); - g_clear_pointer (&button->priv->title, g_free); + /* Has no allocations.*/ + /* Chain up. */ G_OBJECT_CLASS (gimp_palette_select_button_parent_class)->finalize (object); } -static void -gimp_palette_select_button_set_property (GObject *object, - guint property_id, - const GValue *value, - GParamSpec *pspec) + + + +/* This is NOT an implementation of virtual function. + * + * Create a widget that is the interior of a button. + * Super creates the button, self creates interior. + * Button is-a container and self calls super to add interior to the container. + * + * Special: an hbox containing a general icon for a palette and + * a label that is the name of the palette family and style. + * FUTURE: label styled in the current palette family and style. + */ +static GtkWidget* +gimp_palette_select_button_create_interior (GimpPaletteSelectButton *self) { - GimpPaletteSelectButton *button = GIMP_PALETTE_SELECT_BUTTON (object); + GtkWidget *button; + GtkWidget *hbox; + GtkWidget *image; + GtkWidget *label; + gchar *palette_name = "unknown"; - switch (property_id) - { - case PROP_TITLE: - button->priv->title = g_value_dup_string (value); - break; - - case PROP_PALETTE_NAME: - gimp_palette_select_button_set_palette (button, - g_value_get_string (value)); - break; - - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); - break; - } -} - -static void -gimp_palette_select_button_get_property (GObject *object, - guint property_id, - GValue *value, - GParamSpec *pspec) -{ - GimpPaletteSelectButton *button = GIMP_PALETTE_SELECT_BUTTON (object); - - switch (property_id) - { - case PROP_TITLE: - g_value_set_string (value, button->priv->title); - break; - - case PROP_PALETTE_NAME: - g_value_set_string (value, button->priv->palette_name); - break; - - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); - break; - } -} - -static void -gimp_palette_select_button_callback (const gchar *palette_name, - gboolean dialog_closing, - gpointer user_data) -{ - GimpPaletteSelectButton *button = user_data; - GimpSelectButton *select_button = GIMP_SELECT_BUTTON (button); - - g_free (button->priv->palette_name); - button->priv->palette_name = g_strdup (palette_name); - - gtk_label_set_text (GTK_LABEL (button->priv->label), palette_name); - - if (dialog_closing) - select_button->temp_callback = NULL; - - g_signal_emit (button, palette_button_signals[PALETTE_SET], 0, - palette_name, dialog_closing); - g_object_notify_by_pspec (G_OBJECT (button), palette_button_props[PROP_PALETTE_NAME]); -} - -static void -gimp_palette_select_button_clicked (GimpPaletteSelectButton *button) -{ - GimpSelectButton *select_button = GIMP_SELECT_BUTTON (button); - - if (select_button->temp_callback) - { - /* calling gimp_palettes_set_popup() raises the dialog */ - gimp_palettes_set_popup (select_button->temp_callback, - button->priv->palette_name); - } - else - { - select_button->temp_callback = - gimp_palette_select_new (button->priv->title, - button->priv->palette_name, - gimp_palette_select_button_callback, - button, NULL); - } -} - -static void -gimp_palette_select_drag_data_received (GimpPaletteSelectButton *button, - GdkDragContext *context, - gint x, - gint y, - GtkSelectionData *selection, - guint info, - guint time) -{ - gint length = gtk_selection_data_get_length (selection); - gchar *str; - - if (gtk_selection_data_get_format (selection) != 8 || length < 1) - { - g_warning ("%s: received invalid palette data", G_STRFUNC); - return; - } - - str = g_strndup ((const gchar *) gtk_selection_data_get_data (selection), - length); - - if (g_utf8_validate (str, -1, NULL)) - { - gint pid; - gpointer unused; - gint name_offset = 0; - - if (sscanf (str, "%i:%p:%n", &pid, &unused, &name_offset) >= 2 && - pid == gimp_getpid () && name_offset > 0) - { - gchar *name = str + name_offset; - - gimp_palette_select_button_set_palette (button, name); - } - } - - g_free (str); -} - -static GtkWidget * -gimp_palette_select_button_create_inside (GimpPaletteSelectButton *palette_button) -{ - GtkWidget *button; - GtkWidget *hbox; - GtkWidget *image; + g_debug ("%s", G_STRFUNC); + /* Outermost is-a button. */ button = gtk_button_new (); + /* inside the button is hbox. */ hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 4); gtk_container_add (GTK_CONTAINER (button), hbox); + /* first item in hbox is an icon. */ image = gtk_image_new_from_icon_name (GIMP_ICON_PALETTE, GTK_ICON_SIZE_BUTTON); gtk_box_pack_start (GTK_BOX (hbox), image, FALSE, FALSE, 0); - palette_button->priv->label = gtk_label_new (palette_button->priv->palette_name); - gtk_box_pack_start (GTK_BOX (hbox), palette_button->priv->label, TRUE, TRUE, 4); + /* Second item in hbox is palette name. + * The initial text is dummy, a draw will soon refresh it. + * This function does not know the resource/palette. + */ + label = gtk_label_new (palette_name); + gtk_box_pack_start (GTK_BOX (hbox), label, TRUE, TRUE, 4); - gtk_widget_show_all (button); + /* Ensure sub widgets saved for subsequent use. */ - g_signal_connect_swapped (button, "clicked", - G_CALLBACK (gimp_palette_select_button_clicked), - palette_button); + self->palette_name_label = label; /* Save label for redraw. */ + self->drag_region_widget = hbox; + self->button = button; - gtk_drag_dest_set (GTK_WIDGET (button), - GTK_DEST_DEFAULT_HIGHLIGHT | - GTK_DEST_DEFAULT_MOTION | - GTK_DEST_DEFAULT_DROP, - &target, 1, - GDK_ACTION_COPY); - - g_signal_connect_swapped (button, "drag-data-received", - G_CALLBACK (gimp_palette_select_drag_data_received), - palette_button); + /* This subclass does not connect to draw signal on interior widget. */ + /* Return the whole interior, which is-a button. */ return button; } + + +/* Knows how to draw self interior. + * Self knows resource, it is not passed. + * + * Overrides virtual method in super, so it is generic on Resource. + */ +static void +gimp_palette_select_button_draw_interior (GimpResourceSelectButton *self) +{ + gchar *palette_name; + GimpResource *resource; + GimpPaletteSelectButton *self_as_palette_select; + + g_debug ("%s", G_STRFUNC); + + g_return_if_fail (GIMP_IS_PALETTE_SELECT_BUTTON (self)); + self_as_palette_select = GIMP_PALETTE_SELECT_BUTTON (self); + + g_object_get (self, "resource", &resource, NULL); + + /* For now, the "id" property of the resource is the name. + * FUTURE: core will support name distinct from ID. + */ + g_object_get (resource, "id", &palette_name, NULL); + + /* We are not keeping a copy of palette name, nothing to free. */ + + /* Not styling the text using the chosen palette, + * just replacing the text with the name of the chosen palette. + */ + gtk_label_set_text (GTK_LABEL (self_as_palette_select->palette_name_label), palette_name); +} diff --git a/libgimp/gimppaletteselectbutton.h b/libgimp/gimppaletteselectbutton.h index 23cf63264e..1d2a1c57d2 100644 --- a/libgimp/gimppaletteselectbutton.h +++ b/libgimp/gimppaletteselectbutton.h @@ -25,61 +25,35 @@ #ifndef __GIMP_PALETTE_SELECT_BUTTON_H__ #define __GIMP_PALETTE_SELECT_BUTTON_H__ -#include +#include G_BEGIN_DECLS -/* For information look into the C source or the html documentation */ +/* This defines certain structs and the usual macros. + * A final type has no private. + */ +#define GIMP_TYPE_PALETTE_SELECT_BUTTON (gimp_palette_select_button_get_type ()) +G_DECLARE_FINAL_TYPE (GimpPaletteSelectButton, + gimp_palette_select_button, + GIMP, PALETTE_SELECT_BUTTON, + GimpResourceSelectButton) -#define GIMP_TYPE_PALETTE_SELECT_BUTTON (gimp_palette_select_button_get_type ()) -#define GIMP_PALETTE_SELECT_BUTTON(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GIMP_TYPE_PALETTE_SELECT_BUTTON, GimpPaletteSelectButton)) -#define GIMP_PALETTE_SELECT_BUTTON_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GIMP_TYPE_PALETTE_SELECT_BUTTON, GimpPaletteSelectButtonClass)) -#define GIMP_IS_PALETTE_SELECT_BUTTON(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GIMP_TYPE_PALETTE_SELECT_BUTTON)) -#define GIMP_IS_PALETTE_SELECT_BUTTON_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GIMP_TYPE_PALETTE_SELECT_BUTTON)) -#define GIMP_PALETTE_SELECT_BUTTON_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GIMP_TYPE_PALETTE_SELECT_BUTTON, GimpPaletteSelectButtonClass)) - - -typedef struct _GimpPaletteSelectButtonPrivate GimpPaletteSelectButtonPrivate; -typedef struct _GimpPaletteSelectButtonClass GimpPaletteSelectButtonClass; - -struct _GimpPaletteSelectButton -{ - GimpSelectButton parent_instance; - - GimpPaletteSelectButtonPrivate *priv; -}; - struct _GimpPaletteSelectButtonClass { - GimpSelectButtonClass parent_class; + GimpResourceSelectButtonClass parent_class; - /* palette_set signal is emitted when palette is chosen */ - void (* palette_set) (GimpPaletteSelectButton *button, - const gchar *palette_name, - gboolean dialog_closing); - - /* Padding for future expansion */ - void (*_gimp_reserved1) (void); - void (*_gimp_reserved2) (void); - void (*_gimp_reserved3) (void); - void (*_gimp_reserved4) (void); - void (*_gimp_reserved5) (void); - void (*_gimp_reserved6) (void); - void (*_gimp_reserved7) (void); - void (*_gimp_reserved8) (void); + /* _set signal is not defined. Use resource_set signal from superclass */ }; -GType gimp_palette_select_button_get_type (void) G_GNUC_CONST; - -GtkWidget * gimp_palette_select_button_new (const gchar *title, - const gchar *palette_name); - -const gchar * gimp_palette_select_button_get_palette (GimpPaletteSelectButton *button); -void gimp_palette_select_button_set_palette (GimpPaletteSelectButton *button, - const gchar *palette_name); +GtkWidget * gimp_palette_select_button_new (const gchar *title, + GimpResource *resource); +/* FUTURE eliminate. Use superclass method get_resource */ +GimpPalette *gimp_palette_select_button_get_palette (GimpPaletteSelectButton *self); +void gimp_palette_select_button_set_palette (GimpPaletteSelectButton *self, + GimpPalette *palette); G_END_DECLS diff --git a/libgimp/gimpparamspecs-body-resource.c b/libgimp/gimpparamspecs-body-resource.c index 3ae744d0c7..e53770ab00 100644 --- a/libgimp/gimpparamspecs-body-resource.c +++ b/libgimp/gimpparamspecs-body-resource.c @@ -25,6 +25,139 @@ */ + /* + * GIMP_TYPE_PARAM_RESOURCE + */ + + static void gimp_param_resource_class_init (GParamSpecClass *klass); + static void gimp_param_resource_init (GParamSpec *pspec); + static gboolean gimp_param_resource_validate (GParamSpec *pspec, + GValue *value); + + GType + gimp_param_resource_get_type (void) + { + static GType type = 0; + + if (! type) + { + const GTypeInfo info = + { + sizeof (GParamSpecClass), + NULL, NULL, + (GClassInitFunc) gimp_param_resource_class_init, + NULL, NULL, + sizeof (GimpParamSpecResource), + 0, + (GInstanceInitFunc) gimp_param_resource_init + }; + + type = g_type_register_static (G_TYPE_PARAM_OBJECT, + "GimpParamResource", &info, 0); + } + + return type; + } + + static void + gimp_param_resource_class_init (GParamSpecClass *klass) + { + klass->value_type = GIMP_TYPE_RESOURCE; + klass->value_validate = gimp_param_resource_validate; + } + + static void + gimp_param_resource_init (GParamSpec *pspec) + { + GimpParamSpecResource *ispec = GIMP_PARAM_SPEC_RESOURCE (pspec); + + ispec->none_ok = FALSE; + } + + /* Return TRUE when value is invalid!!! + * FIXME: should be named is_invalid. + */ +static gboolean +gimp_param_resource_validate (GParamSpec *pspec, + GValue *value) +{ + GimpParamSpecResource *ispec = GIMP_PARAM_SPEC_RESOURCE (pspec); + GimpResource *resource = value->data[0].v_pointer; + + g_debug (">>>>>%s", G_STRFUNC); + + if (! ispec->none_ok && resource == NULL) + /* NULL when NULL not allowed is invalid. */ + return TRUE; + + if (resource != NULL) + { + if (GIMP_IS_BRUSH (resource) && gimp_brush_is_valid (GIMP_BRUSH (resource))) + return FALSE; + else if (GIMP_IS_FONT (resource) && gimp_font_is_valid (GIMP_FONT (resource))) + return FALSE; + else if (GIMP_IS_GRADIENT (resource) && gimp_gradient_is_valid (GIMP_GRADIENT (resource))) + return FALSE; + else if (GIMP_IS_PALETTE (resource) && gimp_palette_is_valid (GIMP_PALETTE (resource))) + return FALSE; + else if (GIMP_IS_PATTERN (resource) && gimp_pattern_is_valid (GIMP_PATTERN (resource))) + return FALSE; + else + { + /* Not a resource type or is invalid reference to core resource. + * Plugin might be using a resource that was uninstalled. + */ + g_object_unref (resource); + value->data[0].v_pointer = NULL; + return TRUE; + } + } + else + { + /* resource is NULL but null is valid.*/ + return FALSE; + } +} + + /** + * gimp_param_spec_resource: + * @name: Canonical name of the property specified. + * @nick: Nick name of the property specified. + * @blurb: Description of the property specified. + * @none_ok: Whether no is a valid value. + * @flags: Flags for the property specified. + * + * Creates a new #GimpParamSpecResource specifying a + * #GIMP_TYPE_RESOURCE property. + * + * See g_param_spec_internal() for details on property names. + * + * Returns: (transfer full): The newly created #GimpParamSpecResource. + * + * Since: 3.0 + **/ + GParamSpec * + gimp_param_spec_resource (const gchar *name, + const gchar *nick, + const gchar *blurb, + gboolean none_ok, + GParamFlags flags) + { + GimpParamSpecResource *ispec; + + ispec = g_param_spec_internal (GIMP_TYPE_PARAM_RESOURCE, + name, nick, blurb, flags); + + g_return_val_if_fail (ispec, NULL); + + ispec->none_ok = none_ok ? TRUE : FALSE; + + return G_PARAM_SPEC (ispec); + } + + + + /* * GIMP_TYPE_PARAM_BRUSH */ diff --git a/libgimp/gimpparamspecs-resource.h b/libgimp/gimpparamspecs-resource.h index 978b82aa39..83fc4943a8 100644 --- a/libgimp/gimpparamspecs-resource.h +++ b/libgimp/gimpparamspecs-resource.h @@ -27,6 +27,34 @@ G_BEGIN_DECLS +/* + * GIMP_TYPE_PARAM_RESOURCE + */ + +/* See bottom of this file for definition of GIMP_VALUE_HOLDS_RESOURCE(value) */ + +#define GIMP_TYPE_PARAM_RESOURCE (gimp_param_resource_get_type ()) +#define GIMP_PARAM_SPEC_RESOURCE(pspec) (G_TYPE_CHECK_INSTANCE_CAST ((pspec), GIMP_TYPE_PARAM_RESOURCE, GimpParamSpecResource)) +#define GIMP_IS_PARAM_SPEC_RESOURCE(pspec) (G_TYPE_CHECK_INSTANCE_TYPE ((pspec), GIMP_TYPE_PARAM_RESOURCE)) + +typedef struct _GimpParamSpecResource GimpParamSpecResource; + +struct _GimpParamSpecResource +{ + GParamSpecObject parent_instance; + gboolean none_ok; +}; + +GType gimp_param_resource_get_type (void) G_GNUC_CONST; + +GParamSpec * gimp_param_spec_resource ( + const gchar *name, + const gchar *nick, + const gchar *blurb, + gboolean none_ok, + GParamFlags flags); + + /* * GIMP_TYPE_PARAM_BRUSH @@ -164,7 +192,11 @@ GParamSpec * gimp_param_spec_pattern (const gchar *name, -#define GIMP_VALUE_HOLDS_RESOURCE(value) (GIMP_VALUE_HOLDS_BRUSH (value) || GIMP_VALUE_HOLDS_FONT (value) || GIMP_VALUE_HOLDS_GRADIENT (value) || GIMP_VALUE_HOLDS_PALETTE (value) || GIMP_VALUE_HOLDS_PATTERN (value) ) +#define GIMP_VALUE_HOLDS_RESOURCE(value) (GIMP_VALUE_HOLDS_BRUSH (value) || \ + GIMP_VALUE_HOLDS_FONT (value) || \ + GIMP_VALUE_HOLDS_GRADIENT (value) || \ + GIMP_VALUE_HOLDS_PALETTE (value) || \ + GIMP_VALUE_HOLDS_PATTERN (value) ) diff --git a/libgimp/gimppatternselect.c b/libgimp/gimppatternselect.c deleted file mode 100644 index da53110a06..0000000000 --- a/libgimp/gimppatternselect.c +++ /dev/null @@ -1,221 +0,0 @@ -/* LIBGIMP - The GIMP Library - * Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball - * - * gimppatternselect.c - * - * This library is free software: you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library. If not, see - * . - */ - -#include "config.h" - -#include "gimp.h" - - -typedef struct -{ - gchar *pattern_callback; - guint idle_id; - gchar *pattern_name; - gint width; - gint height; - gint bytes; - guchar *pattern_mask_data; - GimpRunPatternCallback callback; - gboolean closing; - gpointer data; - GDestroyNotify data_destroy; -} GimpPatternData; - - -/* local function prototypes */ - -static void gimp_pattern_data_free (GimpPatternData *data); - -static GimpValueArray * gimp_temp_pattern_run (GimpProcedure *procedure, - const GimpValueArray *args, - gpointer run_data); -static gboolean gimp_temp_pattern_idle (GimpPatternData *data); - - -/* public functions */ - -const gchar * -gimp_pattern_select_new (const gchar *title, - const gchar *pattern_name, - GimpRunPatternCallback callback, - gpointer data, - GDestroyNotify data_destroy) -{ - GimpPlugIn *plug_in = gimp_get_plug_in (); - GimpProcedure *procedure; - gchar *pattern_callback; - GimpPatternData *pattern_data; - - pattern_callback = gimp_pdb_temp_procedure_name (gimp_get_pdb ()); - - pattern_data = g_slice_new0 (GimpPatternData); - - pattern_data->pattern_callback = pattern_callback; - pattern_data->callback = callback; - pattern_data->data = data; - pattern_data->data_destroy = data_destroy; - - procedure = gimp_procedure_new (plug_in, - pattern_callback, - GIMP_PDB_PROC_TYPE_TEMPORARY, - gimp_temp_pattern_run, - pattern_data, - (GDestroyNotify) - gimp_pattern_data_free); - - GIMP_PROC_ARG_STRING (procedure, "pattern-name", - "Pattern name", - "The pattern name", - NULL, - G_PARAM_READWRITE); - - GIMP_PROC_ARG_INT (procedure, "mask-width", - "Mask width", - "Pattern width", - 0, 10000, 0, - G_PARAM_READWRITE); - - GIMP_PROC_ARG_INT (procedure, "mask-height", - "Mask height", - "Pattern height", - 0, 10000, 0, - G_PARAM_READWRITE); - - GIMP_PROC_ARG_INT (procedure, "mask-bpp", - "Mask bpp", - "Pattern bytes per pixel", - 0, 10000, 0, - G_PARAM_READWRITE); - - GIMP_PROC_ARG_INT (procedure, "mask-len", - "Mask length", - "Length of pattern mask data", - 0, G_MAXINT, 0, - G_PARAM_READWRITE); - - GIMP_PROC_ARG_UINT8_ARRAY (procedure, "mask-data", - "Mask data", - "The pattern mask data", - G_PARAM_READWRITE); - - GIMP_PROC_ARG_BOOLEAN (procedure, "closing", - "Closing", - "If the dialog was cloaing", - FALSE, - G_PARAM_READWRITE); - - gimp_plug_in_add_temp_procedure (plug_in, procedure); - g_object_unref (procedure); - - if (gimp_patterns_popup (pattern_callback, title, pattern_name)) - { - /* Allow callbacks to be watched */ - gimp_plug_in_extension_enable (plug_in); - - return pattern_callback; - } - - gimp_plug_in_remove_temp_procedure (plug_in, pattern_callback); - - return NULL; -} - -void -gimp_pattern_select_destroy (const gchar *pattern_callback) -{ - GimpPlugIn *plug_in = gimp_get_plug_in (); - - g_return_if_fail (pattern_callback != NULL); - - gimp_plug_in_remove_temp_procedure (plug_in, pattern_callback); -} - - -/* private functions */ - -static void -gimp_pattern_data_free (GimpPatternData *data) -{ - if (data->idle_id) - g_source_remove (data->idle_id); - - if (data->pattern_callback) - { - gimp_patterns_close_popup (data->pattern_callback); - g_free (data->pattern_callback); - } - - g_free (data->pattern_name); - g_free (data->pattern_mask_data); - - if (data->data_destroy) - data->data_destroy (data->data); - - g_slice_free (GimpPatternData, data); -} - -static GimpValueArray * -gimp_temp_pattern_run (GimpProcedure *procedure, - const GimpValueArray *args, - gpointer run_data) -{ - GimpPatternData *data = run_data; - - g_free (data->pattern_name); - g_free (data->pattern_mask_data); - - data->pattern_name = GIMP_VALUES_DUP_STRING (args, 0); - data->width = GIMP_VALUES_GET_INT (args, 1); - data->height = GIMP_VALUES_GET_INT (args, 2); - data->bytes = GIMP_VALUES_GET_INT (args, 3); - data->pattern_mask_data = GIMP_VALUES_DUP_UINT8_ARRAY (args, 5); - data->closing = GIMP_VALUES_GET_BOOLEAN (args, 6); - - if (! data->idle_id) - data->idle_id = g_idle_add ((GSourceFunc) gimp_temp_pattern_idle, data); - - return gimp_procedure_new_return_values (procedure, GIMP_PDB_SUCCESS, NULL); -} - -static gboolean -gimp_temp_pattern_idle (GimpPatternData *data) -{ - data->idle_id = 0; - - if (data->callback) - data->callback (data->pattern_name, - data->width, - data->height, - data->bytes, - data->pattern_mask_data, - data->closing, - data->data); - - if (data->closing) - { - gchar *pattern_callback = data->pattern_callback; - - data->pattern_callback = NULL; - gimp_pattern_select_destroy (pattern_callback); - g_free (pattern_callback); - } - - return G_SOURCE_REMOVE; -} diff --git a/libgimp/gimppatternselect.h b/libgimp/gimppatternselect.h deleted file mode 100644 index 024257732f..0000000000 --- a/libgimp/gimppatternselect.h +++ /dev/null @@ -1,59 +0,0 @@ -/* LIBGIMP - The GIMP Library - * Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball - * - * gimppatternselect.h - * - * This library is free software: you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library. If not, see - * . - */ - -#if !defined (__GIMP_H_INSIDE__) && !defined (GIMP_COMPILATION) -#error "Only can be included directly." -#endif - -#ifndef __GIMP_PATTERN_SELECT_H__ -#define __GIMP_PATTERN_SELECT_H__ - -G_BEGIN_DECLS - -/** - * GimpRunPatternCallback: - * @pattern_name: Name of the pattern - * @width: width - * @height: height - * @bpp: bytes per pixel - * @mask_data: (array): Mask data - * @dialog_closing: Dialog closing? - * @user_data: (closure): user data - */ -typedef void (* GimpRunPatternCallback) (const gchar *pattern_name, - gint width, - gint height, - gint bpp, - const guchar *mask_data, - gboolean dialog_closing, - gpointer user_data); - - -const gchar * gimp_pattern_select_new (const gchar *title, - const gchar *pattern_name, - GimpRunPatternCallback callback, - gpointer data, - GDestroyNotify data_destroy); -void gimp_pattern_select_destroy (const gchar *pattern_callback); - - -G_END_DECLS - -#endif /* __GIMP_PATTERN_SELECT_H__ */ diff --git a/libgimp/gimppatternselect_pdb.c b/libgimp/gimppatternselect_pdb.c index d1f9fbde90..02657e28f8 100644 --- a/libgimp/gimppatternselect_pdb.c +++ b/libgimp/gimppatternselect_pdb.c @@ -30,28 +30,29 @@ /** * SECTION: gimppatternselect * @title: gimppatternselect - * @short_description: Functions providing a pattern selection dialog. + * @short_description: Methods of a pattern chooser dialog * - * Functions providing a pattern selection dialog. + * A dialog letting a user choose a pattern. Read more at + * gimpfontselect. **/ /** * gimp_patterns_popup: - * @pattern_callback: The callback PDB proc to call when pattern selection is made. + * @pattern_callback: The callback PDB proc to call when the user chooses a pattern. * @popup_title: Title of the pattern selection dialog. - * @initial_pattern: The name of the pattern to set as the first selected. + * @initial_pattern_name: The name of the pattern to set as the initial choice. * * Invokes the Gimp pattern selection. * - * This procedure opens the pattern selection dialog. + * Opens the pattern selection dialog. * * Returns: TRUE on success. **/ gboolean gimp_patterns_popup (const gchar *pattern_callback, const gchar *popup_title, - const gchar *initial_pattern) + const gchar *initial_pattern_name) { GimpValueArray *args; GimpValueArray *return_vals; @@ -60,7 +61,7 @@ gimp_patterns_popup (const gchar *pattern_callback, args = gimp_value_array_new_from_types (NULL, G_TYPE_STRING, pattern_callback, G_TYPE_STRING, popup_title, - G_TYPE_STRING, initial_pattern, + G_TYPE_STRING, initial_pattern_name, G_TYPE_NONE); return_vals = gimp_pdb_run_procedure_array (gimp_get_pdb (), @@ -81,7 +82,7 @@ gimp_patterns_popup (const gchar *pattern_callback, * * Close the pattern selection dialog. * - * This procedure closes an opened pattern selection dialog. + * Closes an open pattern selection dialog. * * Returns: TRUE on success. **/ diff --git a/libgimp/gimppatternselect_pdb.h b/libgimp/gimppatternselect_pdb.h index 50a04287b4..b56f4be488 100644 --- a/libgimp/gimppatternselect_pdb.h +++ b/libgimp/gimppatternselect_pdb.h @@ -34,7 +34,7 @@ G_BEGIN_DECLS gboolean gimp_patterns_popup (const gchar *pattern_callback, const gchar *popup_title, - const gchar *initial_pattern); + const gchar *initial_pattern_name); gboolean gimp_patterns_close_popup (const gchar *pattern_callback); gboolean gimp_patterns_set_popup (const gchar *pattern_callback, const gchar *pattern_name); diff --git a/libgimp/gimppatternselectbutton.c b/libgimp/gimppatternselectbutton.c index 46cc6ef306..444f1f8367 100644 --- a/libgimp/gimppatternselectbutton.c +++ b/libgimp/gimppatternselectbutton.c @@ -19,6 +19,10 @@ * . */ +/* Similar to gimpbrushselectbutton.c. + * FUTURE: inherit or share common code. + */ + #include "config.h" #include @@ -38,301 +42,244 @@ /** * SECTION: gimppatternselectbutton * @title: GimpPatternSelectButton - * @short_description: A button which pops up a pattern select dialog. + * @short_description: A button which pops up a pattern selection dialog. * - * A button which pops up a pattern select dialog. + * A button which pops up a pattern selection dialog. **/ - #define CELL_SIZE 20 - -#define GET_PRIVATE(obj) (((GimpPatternSelectButtonPrivate *) (obj))->priv) - -struct _GimpPatternSelectButtonPrivate +/* An image. pixelels is allocated and must be freed. */ +typedef struct _PreviewImage { - gchar *title; + gint width; + gint height; + gint bpp; + guchar *pixelels; +} _PreviewImage; - gchar *pattern_name; /* Local copy */ - gint width; - gint height; - gint bytes; - guchar *mask_data; /* local copy */ +struct _GimpPatternSelectButton +{ + /* !! Not a pointer, is contained. */ + GimpResourceSelectButton parent_instance; - GtkWidget *inside; - GtkWidget *preview; - GtkWidget *popup; + /* Partial view of pattern image. Receives drag. Receives mouse down to popup zoom. */ + GtkWidget *peephole_view; + GtkWidget *popup; /* Popup showing entire, full-size pattern image. */ + GtkWidget *browse_button; /* Clickable area that popups remote chooser. */ }; -enum -{ - PATTERN_SET, - LAST_SIGNAL -}; +/* local */ -enum -{ - PROP_0, - PROP_TITLE, - PROP_PATTERN_NAME, - N_PROPS -}; +/* implement virtual. */ +static void gimp_pattern_select_button_finalize (GObject *object); +static void gimp_pattern_select_button_draw_interior (GimpResourceSelectButton *self); +/* init methods. */ +static GtkWidget *gimp_pattern_select_button_create_interior (GimpPatternSelectButton *self); -/* local function prototypes */ +/* Event handlers. */ +static void gimp_pattern_select_on_preview_resize (GimpPatternSelectButton *button); +static gboolean gimp_pattern_select_on_preview_events (GtkWidget *widget, + GdkEvent *event, + GimpPatternSelectButton *button); -static void gimp_pattern_select_button_finalize (GObject *object); +/* local drawing methods. */ +static void gimp_pattern_select_preview_draw (GimpPreviewArea *area, + gint x, + gint y, + _PreviewImage image, + gint rowstride); +static void gimp_pattern_select_preview_fill_draw (GtkWidget *preview, + _PreviewImage image); -static void gimp_pattern_select_button_set_property (GObject *object, - guint property_id, - const GValue *value, - GParamSpec *pspec); -static void gimp_pattern_select_button_get_property (GObject *object, - guint property_id, - GValue *value, - GParamSpec *pspec); - -static void gimp_pattern_select_button_clicked (GimpPatternSelectButton *button); - -static void gimp_pattern_select_button_callback (const gchar *pattern_name, - gint width, - gint height, - gint bytes, - const guchar *mask_data, - gboolean dialog_closing, - gpointer user_data); - -static void gimp_pattern_select_preview_resize (GimpPatternSelectButton *button); -static gboolean gimp_pattern_select_preview_events (GtkWidget *widget, - GdkEvent *event, - GimpPatternSelectButton *button); -static void gimp_pattern_select_preview_update (GtkWidget *preview, - gint width, - gint height, - gint bytes, - const guchar *mask_data); +static void gimp_pattern_select_button_draw (GimpPatternSelectButton *self); +static _PreviewImage gimp_pattern_select_button_get_pattern_image (GimpPatternSelectButton *self); +/* Popup methods. */ static void gimp_pattern_select_button_open_popup (GimpPatternSelectButton *button, gint x, gint y); static void gimp_pattern_select_button_close_popup (GimpPatternSelectButton *button); -static void gimp_pattern_select_drag_data_received (GimpPatternSelectButton *button, - GdkDragContext *context, - gint x, - gint y, - GtkSelectionData *selection, - guint info, - guint time); - -static GtkWidget * gimp_pattern_select_button_create_inside (GimpPatternSelectButton *button); -static const GtkTargetEntry target = { "application/x-gimp-pattern-name", 0 }; -static guint pattern_button_signals[LAST_SIGNAL] = { 0 }; -static GParamSpec *pattern_button_props[N_PROPS] = { NULL, }; +/* A GtkTargetEntry has a string and two ints. + * This is one, but we treat it as an array. + */ +static const GtkTargetEntry drag_target = { "application/x-gimp-pattern-name", 0, 0 }; - -G_DEFINE_TYPE_WITH_PRIVATE (GimpPatternSelectButton, gimp_pattern_select_button, - GIMP_TYPE_SELECT_BUTTON) +G_DEFINE_FINAL_TYPE (GimpPatternSelectButton, + gimp_pattern_select_button, + GIMP_TYPE_RESOURCE_SELECT_BUTTON) static void gimp_pattern_select_button_class_init (GimpPatternSelectButtonClass *klass) { - GObjectClass *object_class = G_OBJECT_CLASS (klass); - GimpSelectButtonClass *select_button_class = GIMP_SELECT_BUTTON_CLASS (klass); + /* Alias cast klass to super classes. */ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + GimpResourceSelectButtonClass *superclass = GIMP_RESOURCE_SELECT_BUTTON_CLASS (klass); + + g_debug ("%s called", G_STRFUNC); object_class->finalize = gimp_pattern_select_button_finalize; - object_class->set_property = gimp_pattern_select_button_set_property; - object_class->get_property = gimp_pattern_select_button_get_property; - select_button_class->select_destroy = gimp_pattern_select_destroy; + /* Implement pure virtual functions. */ + superclass->draw_interior = gimp_pattern_select_button_draw_interior; - klass->pattern_set = NULL; + /* Set data member of class. */ + superclass->resource_type = GIMP_TYPE_PATTERN; - /** - * GimpPatternSelectButton:title: - * - * The title to be used for the pattern selection popup dialog. - * - * Since: 2.4 + /* We don't define property getter/setters: use superclass getter/setters. + * But super property name is "resource", not "pattern" */ - pattern_button_props[PROP_TITLE] = g_param_spec_string ("title", - "Title", - "The title to be used for the pattern selection popup dialog", - _("Pattern Selection"), - GIMP_PARAM_READWRITE | - G_PARAM_CONSTRUCT_ONLY); - - /** - * GimpPatternSelectButton:pattern-name: - * - * The name of the currently selected pattern. - * - * Since: 2.4 - */ - pattern_button_props[PROP_PATTERN_NAME] = g_param_spec_string ("pattern-name", - "Pattern name", - "The name of the currently selected pattern", - NULL, - GIMP_PARAM_READWRITE); - - g_object_class_install_properties (object_class, N_PROPS, pattern_button_props); - - /** - * GimpPatternSelectButton::pattern-set: - * @widget: the object which received the signal. - * @pattern_name: the name of the currently selected pattern. - * @width: width of the pattern - * @height: height of the pattern - * @bpp: bpp of the pattern - * @mask_data: pattern mask data - * @dialog_closing: whether the dialog was closed or not. - * - * The ::pattern-set signal is emitted when the user selects a pattern. - * - * Since: 2.4 - */ - pattern_button_signals[PATTERN_SET] = - g_signal_new ("pattern-set", - G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_FIRST, - G_STRUCT_OFFSET (GimpPatternSelectButtonClass, pattern_set), - NULL, NULL, - _gimpui_marshal_VOID__STRING_INT_INT_INT_POINTER_BOOLEAN, - G_TYPE_NONE, 6, - G_TYPE_STRING, - G_TYPE_INT, - G_TYPE_INT, - G_TYPE_INT, - G_TYPE_POINTER, - G_TYPE_BOOLEAN); } static void -gimp_pattern_select_button_init (GimpPatternSelectButton *button) +gimp_pattern_select_button_init (GimpPatternSelectButton *self) { - gint mask_data_size; + GtkWidget *interior; - button->priv = gimp_pattern_select_button_get_instance_private (button); + g_debug ("%s called", G_STRFUNC); - button->priv->pattern_name = gimp_context_get_pattern (); - gimp_pattern_get_pixels (button->priv->pattern_name, - &button->priv->width, - &button->priv->height, - &button->priv->bytes, - &mask_data_size, - &button->priv->mask_data); + /* Specialize: + * - embed our widget interior instance to super widget instance. + * - connect our widget to dnd + * These will call superclass methods. + * These are on instance, not our subclass. + */ + interior = gimp_pattern_select_button_create_interior (self); - button->priv->inside = gimp_pattern_select_button_create_inside (button); - gtk_container_add (GTK_CONTAINER (button), button->priv->inside); + gimp_resource_select_button_embed_interior (GIMP_RESOURCE_SELECT_BUTTON (self), interior); + + /* Self knows the GtkTargetEntry, super knows how to create target and receive drag. */ + /* Only the peephole_view receives drag. */ + gimp_resource_select_button_set_drag_target (GIMP_RESOURCE_SELECT_BUTTON (self), + self->peephole_view, + &drag_target); + + /* Tell super which sub widget pops up remote chooser. + * Only the browse_button. + * A click in the peephole_view does something else: popup a zoom. + */ + gimp_resource_select_button_set_clickable (GIMP_RESOURCE_SELECT_BUTTON (self), + self->browse_button); } /** * gimp_pattern_select_button_new: * @title: (nullable): Title of the dialog to use or %NULL to use the default title. - * @pattern_name: (nullable): Initial pattern name or %NULL to use current selection. + * @resource: (nullable): Initial pattern. * - * Creates a new #GtkWidget that completely controls the selection of - * a pattern. This widget is suitable for placement in a table in a - * plug-in dialog. + * Creates a new #GtkWidget that lets a user choose a pattern. + * You can put this widget in a table in a plug-in dialog. + * + * When pattern is NULL, initial choice is from context. * * Returns: A #GtkWidget that you can use in your UI. * * Since: 2.4 */ GtkWidget * -gimp_pattern_select_button_new (const gchar *title, - const gchar *pattern_name) +gimp_pattern_select_button_new (const gchar *title, + GimpResource *resource) { - GtkWidget *button; + GtkWidget *self; - if (title) - button = g_object_new (GIMP_TYPE_PATTERN_SELECT_BUTTON, - "title", title, - "pattern-name", pattern_name, - NULL); - else - button = g_object_new (GIMP_TYPE_PATTERN_SELECT_BUTTON, - "pattern-name", pattern_name, - NULL); + g_debug ("%s called", G_STRFUNC); - return button; + if (resource == NULL) + { + g_debug ("%s defaulting pattern from context", G_STRFUNC); + resource = GIMP_RESOURCE (gimp_context_get_pattern ()); + } + g_assert (resource != NULL); + /* This method is polymorphic, so a factory can call it, but requires Pattern. */ + g_return_val_if_fail (GIMP_IS_PATTERN (resource), NULL); + + /* Create instance of self (not super.) + * This will call superclass init, self class init, superclass init, and instance init. + * Self subclass class_init will specialize by implementing virtual funcs + * that open and set remote chooser dialog, and that draw self interior. + * + * !!! property belongs to superclass and is named "resource" + */ + if (title) + self = g_object_new (GIMP_TYPE_PATTERN_SELECT_BUTTON, + "title", title, + "resource", resource, + NULL); + else + self = g_object_new (GIMP_TYPE_PATTERN_SELECT_BUTTON, + "resource", resource, + NULL); + + /* We don't subscribe to events from super. + * Super will queue a draw when it's resource changes. + * Except that the above setting of property happens too late, + * so we now draw the initial resource. + */ + + /* Draw it with the initial resource. + * Easier to call draw method than to queue a draw. + * + * Cast self from Widget. + */ + gimp_pattern_select_button_draw_interior (GIMP_RESOURCE_SELECT_BUTTON (self)); + + g_debug ("%s returns", G_STRFUNC); + + return self; } + +/* Getter and setter. + * We could omit these, and use only the superclass methods. + * But script-fu-interface.c uses these, until FUTURE. + */ + /** * gimp_pattern_select_button_get_pattern: - * @button: A #GimpPatternSelectButton + * @self: A #GimpPatternSelectButton * - * Retrieves the name of currently selected pattern. + * Gets the currently selected pattern. * - * Returns: an internal copy of the pattern name which must not be freed. + * Returns: (transfer none): an internal copy of the pattern which must not be freed. * * Since: 2.4 */ -const gchar * -gimp_pattern_select_button_get_pattern (GimpPatternSelectButton *button) +GimpPattern * +gimp_pattern_select_button_get_pattern (GimpPatternSelectButton *self) { - g_return_val_if_fail (GIMP_IS_PATTERN_SELECT_BUTTON (button), NULL); + g_return_val_if_fail (GIMP_IS_PATTERN_SELECT_BUTTON (self), NULL); - return button->priv->pattern_name; + /* Delegate to super w upcast arg and downcast result. */ + return (GimpPattern *) gimp_resource_select_button_get_resource ((GimpResourceSelectButton*) self); } /** * gimp_pattern_select_button_set_pattern: - * @button: A #GimpPatternSelectButton - * @pattern_name: (nullable): Pattern name to set; %NULL means no change. + * @self: A #GimpPatternSelectButton + * @pattern: Pattern to set. * - * Sets the current pattern for the pattern select button. + * Sets the currently selected pattern. + * Usually you should not call this; the user is in charge. + * Changes the selection in both the button and it's popup chooser. * * Since: 2.4 */ void -gimp_pattern_select_button_set_pattern (GimpPatternSelectButton *button, - const gchar *pattern_name) +gimp_pattern_select_button_set_pattern (GimpPatternSelectButton *self, + GimpPattern *pattern) { - GimpSelectButton *select_button; + g_return_if_fail (GIMP_IS_PATTERN_SELECT_BUTTON (self)); - g_return_if_fail (GIMP_IS_PATTERN_SELECT_BUTTON (button)); + g_debug ("%s", G_STRFUNC); - select_button = GIMP_SELECT_BUTTON (button); - - if (select_button->temp_callback) - { - gimp_patterns_set_popup (select_button->temp_callback, pattern_name); - } - else - { - gchar *name; - gint width; - gint height; - gint bytes; - gint mask_data_size; - guint8 *mask_data; - - if (pattern_name && *pattern_name) - name = g_strdup (pattern_name); - else - name = gimp_context_get_pattern (); - - if (gimp_pattern_get_pixels (name, - &width, - &height, - &bytes, - &mask_data_size, - &mask_data)) - { - gimp_pattern_select_button_callback (name, - width, height, bytes, mask_data, - FALSE, button); - - g_free (mask_data); - } - - g_free (name); - } + /* Delegate to super with upcasts */ + gimp_resource_select_button_set_resource (GIMP_RESOURCE_SELECT_BUTTON (self), GIMP_RESOURCE (pattern)); } @@ -341,305 +288,28 @@ gimp_pattern_select_button_set_pattern (GimpPatternSelectButton *button, static void gimp_pattern_select_button_finalize (GObject *object) { - GimpPatternSelectButton *button = GIMP_PATTERN_SELECT_BUTTON (object); + g_debug ("%s called", G_STRFUNC); - g_clear_pointer (&button->priv->pattern_name, g_free); - g_clear_pointer (&button->priv->mask_data, g_free); - g_clear_pointer (&button->priv->title, g_free); + /* Has no allocations.*/ + /* Chain up. */ G_OBJECT_CLASS (gimp_pattern_select_button_parent_class)->finalize (object); } -static void -gimp_pattern_select_button_set_property (GObject *object, - guint property_id, - const GValue *value, - GParamSpec *pspec) -{ - GimpPatternSelectButton *button = GIMP_PATTERN_SELECT_BUTTON (object); - - switch (property_id) - { - case PROP_TITLE: - button->priv->title = g_value_dup_string (value); - break; - - case PROP_PATTERN_NAME: - gimp_pattern_select_button_set_pattern (button, - g_value_get_string (value)); - break; - - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); - break; - } -} - -static void -gimp_pattern_select_button_get_property (GObject *object, - guint property_id, - GValue *value, - GParamSpec *pspec) -{ - GimpPatternSelectButton *button = GIMP_PATTERN_SELECT_BUTTON (object); - - switch (property_id) - { - case PROP_TITLE: - g_value_set_string (value, button->priv->title); - break; - - case PROP_PATTERN_NAME: - g_value_set_string (value, button->priv->pattern_name); - break; - - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); - break; - } -} - -static void -gimp_pattern_select_button_callback (const gchar *pattern_name, - gint width, - gint height, - gint bytes, - const guchar *mask_data, - gboolean dialog_closing, - gpointer user_data) -{ - GimpPatternSelectButton *button = user_data; - GimpSelectButton *select_button = GIMP_SELECT_BUTTON (button); - - g_free (button->priv->pattern_name); - g_free (button->priv->mask_data); - - button->priv->pattern_name = g_strdup (pattern_name); - button->priv->width = width; - button->priv->height = height; - button->priv->bytes = bytes; - button->priv->mask_data = g_memdup2 (mask_data, width * height * bytes); - - gimp_pattern_select_preview_update (button->priv->preview, - width, height, bytes, mask_data); - - if (dialog_closing) - select_button->temp_callback = NULL; - - g_signal_emit (button, pattern_button_signals[PATTERN_SET], 0, - pattern_name, width, height, bytes, dialog_closing); - g_object_notify_by_pspec (G_OBJECT (button), pattern_button_props[PROP_PATTERN_NAME]); -} - -static void -gimp_pattern_select_button_clicked (GimpPatternSelectButton *button) -{ - GimpSelectButton *select_button = GIMP_SELECT_BUTTON (button); - - if (select_button->temp_callback) - { - /* calling gimp_patterns_set_popup() raises the dialog */ - gimp_patterns_set_popup (select_button->temp_callback, - button->priv->pattern_name); - } - else - { - select_button->temp_callback = - gimp_pattern_select_new (button->priv->title, - button->priv->pattern_name, - gimp_pattern_select_button_callback, - button, NULL); - } -} - -static void -gimp_pattern_select_preview_resize (GimpPatternSelectButton *button) -{ - if (button->priv->width > 0 && button->priv->height > 0) - gimp_pattern_select_preview_update (button->priv->preview, - button->priv->width, - button->priv->height, - button->priv->bytes, - button->priv->mask_data); -} - -static gboolean -gimp_pattern_select_preview_events (GtkWidget *widget, - GdkEvent *event, - GimpPatternSelectButton *button) -{ - GdkEventButton *bevent; - - if (button->priv->mask_data) - { - switch (event->type) - { - case GDK_BUTTON_PRESS: - bevent = (GdkEventButton *) event; - - if (bevent->button == 1) - { - gtk_grab_add (widget); - gimp_pattern_select_button_open_popup (button, - bevent->x, bevent->y); - } - break; - - case GDK_BUTTON_RELEASE: - bevent = (GdkEventButton *) event; - - if (bevent->button == 1) - { - gtk_grab_remove (widget); - gimp_pattern_select_button_close_popup (button); - } - break; - - default: - break; - } - } - - return FALSE; -} - -static void -gimp_pattern_select_preview_update (GtkWidget *preview, - gint width, - gint height, - gint bytes, - const guchar *mask_data) -{ - GimpImageType type; - - switch (bytes) - { - case 1: type = GIMP_GRAY_IMAGE; break; - case 2: type = GIMP_GRAYA_IMAGE; break; - case 3: type = GIMP_RGB_IMAGE; break; - case 4: type = GIMP_RGBA_IMAGE; break; - default: - return; - } - - gimp_preview_area_draw (GIMP_PREVIEW_AREA (preview), - 0, 0, width, height, - type, - mask_data, - width * bytes); -} - -static void -gimp_pattern_select_button_open_popup (GimpPatternSelectButton *button, - gint x, - gint y) -{ - GimpPatternSelectButtonPrivate *priv = button->priv; - GtkWidget *frame; - GtkWidget *preview; - GdkMonitor *monitor; - GdkRectangle workarea; - gint x_org; - gint y_org; - - if (priv->popup) - gimp_pattern_select_button_close_popup (button); - - if (priv->width <= CELL_SIZE && priv->height <= CELL_SIZE) - return; - - priv->popup = gtk_window_new (GTK_WINDOW_POPUP); - gtk_window_set_type_hint (GTK_WINDOW (priv->popup), GDK_WINDOW_TYPE_HINT_DND); - gtk_window_set_screen (GTK_WINDOW (priv->popup), - gtk_widget_get_screen (GTK_WIDGET (button))); - - frame = gtk_frame_new (NULL); - gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_OUT); - gtk_container_add (GTK_CONTAINER (priv->popup), frame); - gtk_widget_show (frame); - - preview = gimp_preview_area_new (); - gtk_widget_set_size_request (preview, priv->width, priv->height); - gtk_container_add (GTK_CONTAINER (frame), preview); - gtk_widget_show (preview); - - /* decide where to put the popup */ - gdk_window_get_origin (gtk_widget_get_window (priv->preview), - &x_org, &y_org); - - monitor = gimp_widget_get_monitor (GTK_WIDGET (button)); - gdk_monitor_get_workarea (monitor, &workarea); - - x = x_org + x - (priv->width / 2); - y = y_org + y - (priv->height / 2); - - x = CLAMP (x, workarea.x, workarea.x + workarea.width - priv->width); - y = CLAMP (y, workarea.y, workarea.y + workarea.height - priv->height); - - gtk_window_move (GTK_WINDOW (priv->popup), x, y); - - gtk_widget_show (priv->popup); - - /* Draw the pattern */ - gimp_pattern_select_preview_update (preview, - priv->width, - priv->height, - priv->bytes, - priv->mask_data); -} - -static void -gimp_pattern_select_button_close_popup (GimpPatternSelectButton *button) -{ - g_clear_pointer (&button->priv->popup, gtk_widget_destroy); -} - -static void -gimp_pattern_select_drag_data_received (GimpPatternSelectButton *button, - GdkDragContext *context, - gint x, - gint y, - GtkSelectionData *selection, - guint info, - guint time) -{ - gint length = gtk_selection_data_get_length (selection); - gchar *str; - - if (gtk_selection_data_get_format (selection) != 8 || length < 1) - { - g_warning ("Received invalid pattern data!"); - return; - } - - str = g_strndup ((const gchar *) gtk_selection_data_get_data (selection), - length); - - if (g_utf8_validate (str, -1, NULL)) - { - gint pid; - gpointer unused; - gint name_offset = 0; - - if (sscanf (str, "%i:%p:%n", &pid, &unused, &name_offset) >= 2 && - pid == gimp_getpid () && name_offset > 0) - { - gchar *name = str + name_offset; - - gimp_pattern_select_button_set_pattern (button, name); - } - } - - g_free (str); -} +/* Create a widget that is the interior of another widget, a GimpPatternSelectButton. + * Super creates the exterior, self creates interior. + * Exterior is-a container and self calls super to add interior to the container. + */ static GtkWidget * -gimp_pattern_select_button_create_inside (GimpPatternSelectButton *pattern_button) +gimp_pattern_select_button_create_interior (GimpPatternSelectButton *self) { - GimpPatternSelectButtonPrivate *priv = pattern_button->priv; - GtkWidget *hbox; - GtkWidget *frame; - GtkWidget *button; + GtkWidget *hbox; + GtkWidget *frame; + GtkWidget *peephole_view; + GtkWidget *browse_button; + + g_debug ("%s", G_STRFUNC); hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6); @@ -647,38 +317,291 @@ gimp_pattern_select_button_create_inside (GimpPatternSelectButton *pattern_butto gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN); gtk_box_pack_start (GTK_BOX (hbox), frame, FALSE, FALSE, 0); - priv->preview = gimp_preview_area_new (); - gtk_widget_add_events (priv->preview, + peephole_view = gimp_preview_area_new (); + gtk_widget_add_events (peephole_view, GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK); - gtk_widget_set_size_request (priv->preview, CELL_SIZE, CELL_SIZE); - gtk_container_add (GTK_CONTAINER (frame), priv->preview); + gtk_widget_set_size_request (peephole_view, CELL_SIZE, CELL_SIZE); + gtk_container_add (GTK_CONTAINER (frame), peephole_view); - g_signal_connect_swapped (priv->preview, "size-allocate", - G_CALLBACK (gimp_pattern_select_preview_resize), - pattern_button); - g_signal_connect (priv->preview, "event", - G_CALLBACK (gimp_pattern_select_preview_events), - pattern_button); + g_signal_connect_swapped (peephole_view, "size-allocate", + G_CALLBACK (gimp_pattern_select_on_preview_resize), + self); - gtk_drag_dest_set (GTK_WIDGET (priv->preview), - GTK_DEST_DEFAULT_HIGHLIGHT | - GTK_DEST_DEFAULT_MOTION | - GTK_DEST_DEFAULT_DROP, - &target, 1, - GDK_ACTION_COPY); + /* preview receives mouse events to popup and down. */ + g_signal_connect (peephole_view, "event", + G_CALLBACK (gimp_pattern_select_on_preview_events), + self); - g_signal_connect_swapped (priv->preview, "drag-data-received", - G_CALLBACK (gimp_pattern_select_drag_data_received), - pattern_button); - - button = gtk_button_new_with_mnemonic (_("_Browse...")); - gtk_box_pack_start (GTK_BOX (hbox), button, TRUE, TRUE, 0); - - g_signal_connect_swapped (button, "clicked", - G_CALLBACK (gimp_pattern_select_button_clicked), - pattern_button); + browse_button = gtk_button_new_with_mnemonic (_("_Browse...")); + gtk_box_pack_start (GTK_BOX (hbox), browse_button, TRUE, TRUE, 0); gtk_widget_show_all (hbox); + /* Ensure self knows sub widgets. */ + self->peephole_view = peephole_view; + self->browse_button = browse_button; + + /* Return the whole, it is not a button, only contains a button. */ return hbox; } + + +/* Knows how to draw self interior. + * Self knows resource, it is not passed. + * + * Overrides virtual method in super, so it is generic on Resource. + */ +static void +gimp_pattern_select_button_draw_interior (GimpResourceSelectButton *self) +{ + g_debug ("%s", G_STRFUNC); + + g_return_if_fail (GIMP_IS_PATTERN_SELECT_BUTTON (self)); + + gimp_pattern_select_button_draw (GIMP_PATTERN_SELECT_BUTTON (self)); +} + + +/* Draw self. + * + * This knows that we only draw the peephole_view. Gtk draws the browse button. + */ +static void +gimp_pattern_select_button_draw (GimpPatternSelectButton *self) +{ + _PreviewImage image; + + g_debug ("%s", G_STRFUNC); + + /* Draw the peephole. */ + image = gimp_pattern_select_button_get_pattern_image (self); + gimp_pattern_select_preview_fill_draw (self->peephole_view, image); + g_free (image.pixelels); +} + + + +/* Return the image of self's pattern. + * Caller must free pixelels. + */ +static _PreviewImage +gimp_pattern_select_button_get_pattern_image (GimpPatternSelectButton *self) +{ + GimpPattern *pattern; + gint pixelels_size; + _PreviewImage result; + + g_debug ("%s", G_STRFUNC); + + g_object_get (self, "resource", &pattern, NULL); + + gimp_pattern_get_pixels (pattern, + &result.width, + &result.height, + &result.bpp, + &pixelels_size, /* discarded. */ + &result.pixelels); + + return result; +} + + +/* On resize event, redraw. */ +static void +gimp_pattern_select_on_preview_resize (GimpPatternSelectButton *self) +{ + g_debug ("%s", G_STRFUNC); + + gimp_pattern_select_button_draw (self); +} + + +/* On mouse events in self's peephole_view, popup a zoom view of entire pattern */ +static gboolean +gimp_pattern_select_on_preview_events (GtkWidget *widget, + GdkEvent *event, + GimpPatternSelectButton *self) +{ + GdkEventButton *bevent; + + g_debug ("%s", G_STRFUNC); + + switch (event->type) + { + case GDK_BUTTON_PRESS: + bevent = (GdkEventButton *) event; + + if (bevent->button == 1) + { + gtk_grab_add (widget); + gimp_pattern_select_button_open_popup (self, + bevent->x, bevent->y); + } + break; + + case GDK_BUTTON_RELEASE: + bevent = (GdkEventButton *) event; + + if (bevent->button == 1) + { + gtk_grab_remove (widget); + gimp_pattern_select_button_close_popup (self); + } + break; + + default: + break; + } + + return FALSE; +} + +/* Draw a GimpPreviewArea with a given image. */ +static void +gimp_pattern_select_preview_draw (GimpPreviewArea *area, + gint x, + gint y, + _PreviewImage image, + gint rowstride) +{ + GimpImageType type; + + g_debug ("%s", G_STRFUNC); + + switch (image.bpp) + { + case 1: type = GIMP_GRAY_IMAGE; break; + case 2: type = GIMP_GRAYA_IMAGE; break; + case 3: type = GIMP_RGB_IMAGE; break; + case 4: type = GIMP_RGBA_IMAGE; break; + default: + g_warning ("Invalid bpp"); + return; + } + + gimp_preview_area_draw (area, + x, y, + image.width, image.height, + type, + image.pixelels, + rowstride); +} + +/* Fill a GimpPreviewArea with a image then draw. */ +static void +gimp_pattern_select_preview_fill_draw (GtkWidget *preview, + _PreviewImage image) +{ + GimpPreviewArea *area = GIMP_PREVIEW_AREA (preview); + GtkAllocation allocation; + gint x, y; + gint width, height; + _PreviewImage drawn_image; + + g_debug ("%s", G_STRFUNC); + + gtk_widget_get_allocation (preview, &allocation); + + width = MIN (image.width, allocation.width); + height = MIN (image.height, allocation.height); + + x = ((allocation.width - width) / 2); + y = ((allocation.height - height) / 2); + + if (x || y) + gimp_preview_area_fill (area, + 0, 0, + allocation.width, + allocation.height, + 0xFF, 0xFF, 0xFF); + + /* Draw same data to new bounds. + * drawn_image.pixelels points to same array. + */ + drawn_image.width = width; + drawn_image.height = height; + drawn_image.pixelels = image.pixelels; + drawn_image.bpp = image.bpp; + + gimp_pattern_select_preview_draw (area, + x, y, + drawn_image, + image.width * image.bpp ); /* row stride */ + /* Caller will free image.pixelels */ +} + +/* popup methods. */ + +static void +gimp_pattern_select_button_open_popup (GimpPatternSelectButton *self, + gint x, + gint y) +{ + GtkWidget *frame; + GtkWidget *preview; + GdkMonitor *monitor; + GdkRectangle workarea; + gint x_org; + gint y_org; + _PreviewImage image; + + g_debug ("%s", G_STRFUNC); + + if (self->popup) + gimp_pattern_select_button_close_popup (self); + + image = gimp_pattern_select_button_get_pattern_image (self); + + if (image.width <= CELL_SIZE && image.height <= CELL_SIZE) + { + g_debug ("%s: omit popup smaller than peephole.", G_STRFUNC); + return; + } + + self->popup = gtk_window_new (GTK_WINDOW_POPUP); + gtk_window_set_type_hint (GTK_WINDOW (self->popup), GDK_WINDOW_TYPE_HINT_DND); + gtk_window_set_screen (GTK_WINDOW (self->popup), + gtk_widget_get_screen (GTK_WIDGET (self))); + + frame = gtk_frame_new (NULL); + gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_OUT); + gtk_container_add (GTK_CONTAINER (self->popup), frame); + gtk_widget_show (frame); + + preview = gimp_preview_area_new (); + gtk_widget_set_size_request (preview, image.width, image.height); + gtk_container_add (GTK_CONTAINER (frame), preview); + gtk_widget_show (preview); + + /* decide where to put the popup: near the peephole_view i.e. at mousedown coords */ + gdk_window_get_origin (gtk_widget_get_window (self->peephole_view), + &x_org, &y_org); + + monitor = gimp_widget_get_monitor (GTK_WIDGET (self)); + gdk_monitor_get_workarea (monitor, &workarea); + + x = x_org + x - (image.width / 2); + y = y_org + y - (image.height / 2); + + x = CLAMP (x, workarea.x, workarea.x + workarea.width - image.width); + y = CLAMP (y, workarea.y, workarea.y + workarea.height - image.height); + + gtk_window_move (GTK_WINDOW (self->popup), x, y); + + gtk_widget_show (self->popup); + + /* Draw popup now. Usual events do not cause a draw. */ + gimp_pattern_select_preview_draw (GIMP_PREVIEW_AREA (preview), + 0, 0, + image, + image.width * image.bpp); + g_free (image.pixelels); +} + +static void +gimp_pattern_select_button_close_popup (GimpPatternSelectButton *self) +{ + g_debug ("%s", G_STRFUNC); + + g_clear_pointer (&self->popup, gtk_widget_destroy); +} diff --git a/libgimp/gimppatternselectbutton.h b/libgimp/gimppatternselectbutton.h index 202f6920e9..dd42ff31e9 100644 --- a/libgimp/gimppatternselectbutton.h +++ b/libgimp/gimppatternselectbutton.h @@ -25,65 +25,35 @@ #ifndef __GIMP_PATTERN_SELECT_BUTTON_H__ #define __GIMP_PATTERN_SELECT_BUTTON_H__ -#include +#include G_BEGIN_DECLS -/* For information look into the C source or the html documentation */ +/* This defines certain structs and the usual macros. + * A final type has no private. + */ +#define GIMP_TYPE_PATTERN_SELECT_BUTTON (gimp_pattern_select_button_get_type ()) +G_DECLARE_FINAL_TYPE (GimpPatternSelectButton, + gimp_pattern_select_button, + GIMP, PATTERN_SELECT_BUTTON, + GimpResourceSelectButton) -#define GIMP_TYPE_PATTERN_SELECT_BUTTON (gimp_pattern_select_button_get_type ()) -#define GIMP_PATTERN_SELECT_BUTTON(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GIMP_TYPE_PATTERN_SELECT_BUTTON, GimpPatternSelectButton)) -#define GIMP_PATTERN_SELECT_BUTTON_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GIMP_TYPE_PATTERN_SELECT_BUTTON, GimpPatternSelectButtonClass)) -#define GIMP_IS_PATTERN_SELECT_BUTTON(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GIMP_TYPE_PATTERN_SELECT_BUTTON)) -#define GIMP_IS_PATTERN_SELECT_BUTTON_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GIMP_TYPE_PATTERN_SELECT_BUTTON)) -#define GIMP_PATTERN_SELECT_BUTTON_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GIMP_TYPE_PATTERN_SELECT_BUTTON, GimpPatternSelectButtonClass)) - - -typedef struct _GimpPatternSelectButtonPrivate GimpPatternSelectButtonPrivate; -typedef struct _GimpPatternSelectButtonClass GimpPatternSelectButtonClass; - -struct _GimpPatternSelectButton -{ - GimpSelectButton parent_instance; - - GimpPatternSelectButtonPrivate *priv; -}; - struct _GimpPatternSelectButtonClass { - GimpSelectButtonClass parent_class; + GimpResourceSelectButtonClass parent_class; - /* pattern_set signal is emitted when pattern is chosen */ - void (* pattern_set) (GimpPatternSelectButton *button, - const gchar *pattern_name, - gint width, - gint height, - gint bpp, - const guchar *mask_data, - gboolean dialog_closing); - - /* Padding for future expansion */ - void (*_gimp_reserved1) (void); - void (*_gimp_reserved2) (void); - void (*_gimp_reserved3) (void); - void (*_gimp_reserved4) (void); - void (*_gimp_reserved5) (void); - void (*_gimp_reserved6) (void); - void (*_gimp_reserved7) (void); - void (*_gimp_reserved8) (void); + /* _set signal is not defined. Use resource_set signal from superclass */ }; -GType gimp_pattern_select_button_get_type (void) G_GNUC_CONST; - -GtkWidget * gimp_pattern_select_button_new (const gchar *title, - const gchar *pattern_name); - -const gchar * gimp_pattern_select_button_get_pattern (GimpPatternSelectButton *button); -void gimp_pattern_select_button_set_pattern (GimpPatternSelectButton *button, - const gchar *pattern_name); +GtkWidget * gimp_pattern_select_button_new (const gchar *title, + GimpResource *resource); +/* FUTURE eliminate. Use superclass method get_resource */ +GimpPattern *gimp_pattern_select_button_get_pattern (GimpPatternSelectButton *self); +void gimp_pattern_select_button_set_pattern (GimpPatternSelectButton *self, + GimpPattern *pattern); G_END_DECLS diff --git a/libgimp/gimpprocedure-params.h b/libgimp/gimpprocedure-params.h index 6a052435f9..597b5ee6a7 100644 --- a/libgimp/gimpprocedure-params.h +++ b/libgimp/gimpprocedure-params.h @@ -861,6 +861,32 @@ G_BEGIN_DECLS /* Resource */ +#define GIMP_PROC_ARG_BRUSH(procedure, name, nick, blurb, flags) \ + gimp_procedure_add_argument (procedure,\ + gimp_param_spec_brush (name, nick, blurb,\ + GIMP_TYPE_BRUSH,\ + flags)) +#define GIMP_PROC_ARG_FONT(procedure, name, nick, blurb, flags) \ + gimp_procedure_add_argument (procedure,\ + gimp_param_spec_font (name, nick, blurb,\ + GIMP_TYPE_FONT,\ + flags)) +#define GIMP_PROC_ARG_GRADIENT(procedure, name, nick, blurb, flags) \ + gimp_procedure_add_argument (procedure,\ + gimp_param_spec_gradient (name, nick, blurb,\ + GIMP_TYPE_GRADIENT,\ + flags)) +#define GIMP_PROC_ARG_PALETTE(procedure, name, nick, blurb, flags) \ + gimp_procedure_add_argument (procedure,\ + gimp_param_spec_palette (name, nick, blurb,\ + GIMP_TYPE_PALETTE,\ + flags)) +#define GIMP_PROC_ARG_PATTERN(procedure, name, nick, blurb, flags) \ + gimp_procedure_add_argument (procedure,\ + gimp_param_spec_pattern (name, nick, blurb,\ + GIMP_TYPE_PATTERN,\ + flags)) + #define GIMP_VALUES_GET_BRUSH(args, n) \ g_value_get_object (gimp_value_array_index (args, n)) #define GIMP_VALUES_SET_BRUSH(args, n, value) \ diff --git a/libgimp/gimpproceduredialog.c b/libgimp/gimpproceduredialog.c index 4a52d17dbc..935679b9b5 100644 --- a/libgimp/gimpproceduredialog.c +++ b/libgimp/gimpproceduredialog.c @@ -725,12 +725,28 @@ gimp_procedure_dialog_get_widget (GimpProcedureDialog *dialog, property, NULL, GTK_FILE_CHOOSER_ACTION_OPEN); } + /* GimpResource subclasses */ + /* FUTURE: title the chooser more specifically, with a prefix that is the nick of the property. */ else if (G_IS_PARAM_SPEC_OBJECT (pspec) && pspec->value_type == GIMP_TYPE_BRUSH) { - widget = gimp_prop_brush_chooser_button_new (G_OBJECT (dialog->priv->config), - property, NULL); + widget = gimp_prop_chooser_brush_new (G_OBJECT (dialog->priv->config), property, _("Brush Chooser")); + } + else if (G_IS_PARAM_SPEC_OBJECT (pspec) && pspec->value_type == GIMP_TYPE_FONT) + { + widget = gimp_prop_chooser_font_new (G_OBJECT (dialog->priv->config), property, _("Font Chooser")); + } + else if (G_IS_PARAM_SPEC_OBJECT (pspec) && pspec->value_type == GIMP_TYPE_GRADIENT) + { + widget = gimp_prop_chooser_gradient_new (G_OBJECT (dialog->priv->config), property, _("Gradient Chooser")); + } + else if (G_IS_PARAM_SPEC_OBJECT (pspec) && pspec->value_type == GIMP_TYPE_PALETTE) + { + widget = gimp_prop_chooser_palette_new (G_OBJECT (dialog->priv->config), property, _("Palette Chooser")); + } + else if (G_IS_PARAM_SPEC_OBJECT (pspec) && pspec->value_type == GIMP_TYPE_PATTERN) + { + widget = gimp_prop_chooser_pattern_new (G_OBJECT (dialog->priv->config), property, _("Pattern Chooser")); } - /* FIXME add cases for other resources. */ else if (G_PARAM_SPEC_TYPE (pspec) == G_TYPE_PARAM_ENUM) { GimpIntStore *store; diff --git a/libgimp/gimppropbrushchooser.c b/libgimp/gimppropbrushchooser.c deleted file mode 100644 index 9151ff795d..0000000000 --- a/libgimp/gimppropbrushchooser.c +++ /dev/null @@ -1,299 +0,0 @@ - -/* LIBGIMP - The GIMP Library - * Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball - * - * This library is free software: you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library. If not, see - * . - */ - -#include "config.h" - -#include -#include -#include - -#include "gimpui.h" - -/* Several of these local functions were copied from gimppropwidgets. - * FUTURE: make utility functions shared by prop widgets. - */ - -/* When property_name of object changes, call the callback passing callback_data. */ -static void -connect_notify_property_changed (GObject *object, - const gchar *property_name, - GCallback callback, - gpointer callback_data) -{ - gchar *notify_name; - - notify_name = g_strconcat ("notify::", property_name, NULL); - - g_signal_connect_object (object, notify_name, callback, callback_data, 0); - - g_free (notify_name); -} - - -/* Setter and getters for a config property bound to a widget. - * - * A prop widget is responsible for knowing the config property it is bound to. - * The config property is a pair [config, property_name] - * - * The property name is unique among properties of the config. - * But it is not constant, and the config can have many similarly named properties, - * when the config has many properties each a value of type say GimpBrush. - * For example, the widget may have property "brush" but the config have "brush2" - * - * We arbitrarily store it in data, not in yet another property. - */ - -static void -gimp_widget_set_bound_property (GtkWidget *widget, - GObject *config, - const gchar *property_name) -{ - g_debug ("%s: %s", G_STRFUNC, property_name); - - g_return_if_fail (GTK_IS_WIDGET (widget)); - - /* Widget destruction notifies this and frees the string. */ - g_object_set_data_full (G_OBJECT (widget), - "gimp-widget-property-name", - g_strdup (property_name), - (GDestroyNotify) g_free); - g_object_set_data_full (G_OBJECT (widget), - "gimp-widget-property-config", - g_object_ref (config), - (GDestroyNotify) g_object_unref); -} - -/* The result string is owned by the widget and is destroyed with the widget. - * Caller must copy it if caller needs it after the widget is destroyed. - */ -static const gchar * -gimp_widget_get_bound_property_name (GtkWidget *widget) -{ - gchar * result=NULL; - - g_return_val_if_fail (GTK_IS_WIDGET (widget), NULL); - - result = (gchar *) g_object_get_data (G_OBJECT (widget), - "gimp-widget-property-name"); - - /* Ensure result is NULL when set_bound_property was not called prior. */ - g_debug ("bound to %s", result); - return result; -} - -static GObject * -gimp_widget_get_bound_property_owner (GtkWidget *widget) -{ - GObject * result=NULL; - - g_return_val_if_fail (GTK_IS_WIDGET (widget), NULL); - - result = g_object_get_data (G_OBJECT (widget), - "gimp-widget-property-config"); - - /* Ensure result is NULL if the widget lacks the property. - * When set_bound_property was not called prior. - */ - g_debug("bound to owner %p", result); - return result; -} - -static GParamSpec * -find_param_spec (GObject *object, - const gchar *property_name, - const gchar *strloc) -{ - GParamSpec *param_spec; - - param_spec = g_object_class_find_property (G_OBJECT_GET_CLASS (object), - property_name); - - if (! param_spec) - g_warning ("%s: %s has no property named '%s'", - strloc, - g_type_name (G_TYPE_FROM_INSTANCE (object)), - property_name); - - return param_spec; -} - -#ifdef DEBUG -/* Print the ID of a GimpResource */ -static void -debug_resource_id(GimpBrush *property_value) -{ - gchar * id; - - g_object_get (GIMP_RESOURCE(property_value), "id", &id, NULL); - g_debug ("brush's id: %s", id); -} -#else -static void debug_resource_id(GimpBrush *property_value) {} -#endif - - -/* Called when the "brush" property of the widget changes. - * - * Do a prop widget's essential behavior: - * copy from widget property to GimpProcedureConfig property. - * - * Require the widget to have previously bound the config's property to itself. - - * We don't compare current value with new value: - * that is an optimization to reduce signals. - * Only we are subscribed to this notify signal. - * The config is only being used to marshall args to a procedure call. - */ -static void -gimp_prop_brush_chooser_button_notify (GtkWidget *button) -{ - GimpBrush *widget_property_value = NULL; - GimpBrush *config_property_value = NULL; - - /* This pair designates a property of a GimpProcedureConfig. */ - GObject *config; - const gchar *config_property_name; - - /* Get changed value of the widget's property */ - g_object_get (button, "brush", &widget_property_value, NULL); - - debug_resource_id (widget_property_value); - - /* Get the name of the config property the widget is bound to. */ - config = gimp_widget_get_bound_property_owner (button); - config_property_name = gimp_widget_get_bound_property_name (button); - g_assert (config_property_name != NULL); - - /* FUTURE: migrate much of this code to a new method - * GimpProcedureConfig.replace_object_value(property_name, new_value) - * It would know to free the existing value. - */ - - /* Free the existing config property. - * - * Properties of type GObject might not have default value, - * so expect it can be NULL, when the config (settings) have never been serialized. - * - * Here we get a pointer to the object, and g_object_clear it. - * The config still points to the freed object, but we soon replace it. - */ - g_debug ("notify callback, get property: %s from config. ", config_property_name); - g_object_get (config, config_property_name, &config_property_value, NULL); - g_clear_object (&config_property_value); - - /* Set the config's property to the widget's property */ - g_object_set (config, config_property_name, widget_property_value, NULL); - /* Assert that g_object_set refs the value, - * so value won't be freed when widget closes. - */ -} - - -/** - * gimp_prop_brush_chooser_button_new: - * @config: Object to which property is attached. - * @property_name: Name of property controlled by button. - * - * Creates a #GimpBrushSelectButton that displays and sets the property, - * which is a GimpBrush. - * - * The button is labeled with the @property_name's nick. - * - * When pushed, the button shows a dialog that lets the user choose a brush. - * - * Returns: (transfer full): The newly created #GimpBrushSelectButton widget. - * - * Since: 3.0 - */ -GtkWidget * -gimp_prop_brush_chooser_button_new (GObject *config, - const gchar *property_name, - const gchar *title) -{ - GParamSpec *param_spec; - GtkWidget *button; - GimpBrush *brush; - - g_return_val_if_fail (G_IS_OBJECT (config), NULL); - g_return_val_if_fail (property_name != NULL, NULL); - - g_debug ("config is %p", config); - g_debug ("property name is %s", property_name); - - param_spec = find_param_spec (config, property_name, G_STRFUNC); - if (! param_spec) - { - g_warning ("%s: %s has no property named '%s'", - G_STRFUNC, g_type_name (G_TYPE_FROM_INSTANCE (config)), - property_name); - return NULL; - } - - if (! G_IS_PARAM_SPEC_OBJECT (param_spec) || param_spec->value_type != GIMP_TYPE_BRUSH) - { - g_warning ("%s: property '%s' of %s is not a G_PARAM_SPEC_OBJECT of value type GIMP_TYPE_BRUSH.", - G_STRFUNC, param_spec->name, - g_type_name (param_spec->owner_type)); - return NULL; - } - - if (! title) - title = g_param_spec_get_nick (param_spec); - - /* Initial choice in chooser is the brush of the config. */ - /* Assert the property exists, but might be NULL. */ - g_object_get (config, property_name, &brush, NULL); - if (brush == NULL) - { - /* Property has no default. - * Get a reasonable value from context. - * The widget will show some value selected, - * ensure it is the the value in context. - */ - g_warning ("No brush property in config. Using brush from context."); - brush = gimp_context_get_brush(); - } - - debug_resource_id (brush); - - /* FIXME: use a widget that chooses only a brush, - * and not opacity, spacing, layer_mode. - */ - button = gimp_brush_select_button_new (title, brush, - 1.0, 2, GIMP_LAYER_MODE_NORMAL); - - /* Unlike other prop widgets, we don't use a callback for a signal of the widget. - * And we don't bind directly to a property. - * Instead get a callback for the notify signal of the widget "brush" property. - * Handler will copy widget's property to config's property. - */ - connect_notify_property_changed ( - (GObject *)button, "brush", /* Source of signal. */ - G_CALLBACK (gimp_prop_brush_chooser_button_notify), /* signal handler. */ - button); /* Data passed to handler. */ - - /* widget knows what config property it is bound to. */ - gimp_widget_set_bound_property (button, config, property_name); - - /* FIXME: label the widget with the nick of the paramspec. */ - - gtk_widget_show (button); - - return button; -} diff --git a/libgimp/gimppropbrushchooser.h b/libgimp/gimppropbrushchooser.h deleted file mode 100644 index 72003cf91e..0000000000 --- a/libgimp/gimppropbrushchooser.h +++ /dev/null @@ -1,35 +0,0 @@ - -/* LIBGIMP - The GIMP Library - * Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball - * - * This library is free software: you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library. If not, see - * . - */ - - #if !defined (__GIMP_UI_H_INSIDE__) && !defined (GIMP_COMPILATION) - #error "Only can be included directly." - #endif - -#ifndef __GIMP_PROP_BRUSH_CHOOSER_H__ -#define __GIMP_PROP_BRUSH_CHOOSER_H__ - -G_BEGIN_DECLS - -GtkWidget * gimp_prop_brush_chooser_button_new (GObject *config, - const gchar *property_name, - const gchar *title); - -G_END_DECLS - -#endif /* __GIMP_PROP_BRUSH_CHOOSER_H__ */ diff --git a/libgimp/gimppropchooser.c b/libgimp/gimppropchooser.c new file mode 100644 index 0000000000..b9dd888116 --- /dev/null +++ b/libgimp/gimppropchooser.c @@ -0,0 +1,105 @@ +/* LIBGIMP - The GIMP Library + * Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball + * + * This library is free software: you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see + * . + */ + +#include "config.h" + +#include +#include +#include + +#include "gimpui.h" + + +/* PropChooser + * A GtkWidget, more specifically a GtkButtonWidget. + * Pops up a chooser widget. + * Has Prop widget trait, i.e. binds property of the chooser widget + * to a property of a ProcedureConfig. + * + * For now, only for Resource choosers, + * which are named GimpResourceSelectButton ("select" means "choose") + * + * Call a factory to create PropWidgets, passing a creator function of + * a kind of wrapped widget. + * + * Stack of objects: + * PropWidget (this file) + * SelectButton button pops up a + * Select dialog lets user choose + * libgimp wire protocol to core + * PDBDialog (app/widgets/gimppdbdialog.c) + */ + +/* Only brush is annotated. + * Usually these are created by GimpProcedureDialog. + * FIXME: It is not clear that these need to be public API, + * unless a plugin creates its own dialog. + */ + +/** + * gimp_prop_chooser_brush_new: + * @config: Object to which property is attached. + * @property_name: Name of property controlled by button. + * @chooser_title: Title for the popup chooser dialog. + * + * Creates a #GimpBrushSelectButton that displays and sets the property. + * + * @config is usually a GimpProcedureConfig (but it could be otherwise.) + * The @config must have a property with name @property_name. + * The property must be type #GimpBrush. + * The @property_name need not be "brush", + * since the @config may have more than one property of type #GimpBrush. + * + * The button is labeled with the @property_name's nick. + * + * When pushed, the button pops up a dialog that lets the user choose a brush. + * The dialog will have the given title. + * + * Returns: (transfer full): The newly created #GimpBrushSelectButton widget. + * + * Since: 3.0 + */ +GtkWidget * +gimp_prop_chooser_brush_new (GObject *config, const gchar *property_name, const gchar *title) +{ + return gimp_prop_chooser_factory (gimp_brush_select_button_new, config, property_name, title); +}; + +GtkWidget * +gimp_prop_chooser_font_new (GObject *config, const gchar *property_name, const gchar *title) +{ + return gimp_prop_chooser_factory (gimp_font_select_button_new, config, property_name, title); +}; + +GtkWidget * +gimp_prop_chooser_gradient_new (GObject *config, const gchar *property_name, const gchar *title) +{ + return gimp_prop_chooser_factory (gimp_gradient_select_button_new, config, property_name, title); +}; + +GtkWidget * +gimp_prop_chooser_palette_new (GObject *config, const gchar *property_name, const gchar *title) +{ + return gimp_prop_chooser_factory (gimp_palette_select_button_new, config, property_name, title); +}; + +GtkWidget * +gimp_prop_chooser_pattern_new (GObject *config, const gchar *property_name, const gchar *title) +{ + return gimp_prop_chooser_factory (gimp_pattern_select_button_new, config, property_name, title); +}; diff --git a/libgimp/gimppropchooser.h b/libgimp/gimppropchooser.h new file mode 100644 index 0000000000..d4ffb7efb8 --- /dev/null +++ b/libgimp/gimppropchooser.h @@ -0,0 +1,47 @@ + +/* LIBGIMP - The GIMP Library + * Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball + * + * This library is free software: you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see + * . + */ + + #if !defined (__GIMP_UI_H_INSIDE__) && !defined (GIMP_COMPILATION) + #error "Only can be included directly." + #endif + +#ifndef __GIMP_PROP_CHOOSER_H__ +#define __GIMP_PROP_CHOOSER_H__ + +G_BEGIN_DECLS + +GtkWidget *gimp_prop_chooser_brush_new (GObject *config, + const gchar *property_name, + const gchar *chooser_title); +GtkWidget *gimp_prop_chooser_font_new (GObject *config, + const gchar *property_name, + const gchar *chooser_title); +GtkWidget *gimp_prop_chooser_gradient_new (GObject *config, + const gchar *property_name, + const gchar *chooser_title); +GtkWidget *gimp_prop_chooser_palette_new (GObject *config, + const gchar *property_name, + const gchar *chooser_title); +GtkWidget *gimp_prop_chooser_pattern_new (GObject *config, + const gchar *property_name, + const gchar *chooser_title); + +G_END_DECLS + +#endif /* __GIMP_PROP_CHOOSER_H__ */ diff --git a/libgimp/gimppropchooserfactory.c b/libgimp/gimppropchooserfactory.c new file mode 100644 index 0000000000..a61979f05e --- /dev/null +++ b/libgimp/gimppropchooserfactory.c @@ -0,0 +1,118 @@ +/* LIBGIMP - The GIMP Library + * Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball + * + * This library is free software: you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see + * . + */ + +#include "config.h" + +#include +#include + +#include "libgimp/gimp.h" +#include "libgimp/gimpui.h" + + static GimpResource * get_initial_resource_from_config (GObject *config, + const gchar *property_name); + +/** +* gimp_prop_chooser_factory: +* @widget_creator_func: (scope async): Function that creates a chooser widget +* @config: Object to which property is attached. +* @property_name: Name of property set by the widget. +* @chooser_title: Title for the popup chooser dialog. +* +* Creates a #GimpResourceSelectButton that displays +* and sets the named property of the config. +* +* The factory makes many kinds of widgets. +* Parameterized by passing a creator function for a kind of widget. +* E.G. creator function is gimp_brush_select_button_new. +* The created widget must have a property named "resource". +* +* The factory wraps the widget so that it is a *prop* widget. +* A prop widget gets the initial choice from the @config +* and binds the property named @property_name +* of the @config to the widget's "resource" property. +* +* @config is usually a #GimpProcedureConfig (but it could be otherwise.) +* The @config must have a property with name @property_name. +* The property must be of type that matches that of the @widget_creator_func, +* e.g. #GimpBrush. +* The @property_name need not be "brush", +* since the @config may have more than one property of the same type e.g. #GimpBrush. +* +* Returns: (transfer full): The newly created #GimpResourceSelectButton widget. +* +* Since: 3.0 +*/ +GtkWidget * +gimp_prop_chooser_factory (GimpResourceWidgetCreator widget_creator_func, + GObject *config, + const gchar *property_name, + const gchar *chooser_title) +{ + GtkWidget *result_widget; + GimpResource *initial_resource; + + g_debug ("%s called", G_STRFUNC); + + initial_resource = get_initial_resource_from_config (config, property_name); + + /* initial_resource may be NULL. + * When NULL, the widget creator will set it's resource property from context. + * We bind with G_BINDING_SYNC_CREATE which immediately flows widget to config. + * So the config property is not NULL after this. + */ + + /* Create the wrapped widget. For example, call gimp_font_select_button_new.*/ + result_widget = widget_creator_func (chooser_title, + initial_resource); + + /* Bind the wrapped widget's property to the config's property. + * + * The property name of the config can vary, e.g. "font" or "font1" + * The property name on widget is generic "resource" not specific e.g. "font" + * + * We bind G_BINDING_BIDIRECTIONAL. + * But we expect no other actor beside widget will change the config, + * (at least while the widget lives.) + * Bind from widget source to config target, + * because G_BINDING_SYNC_CREATE initially flows that way. + */ + g_object_bind_property (result_widget, /* Source for initial transfer */ + "resource", + config, /* Target of initial transfer. */ + property_name, + G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE); + + return result_widget; +} + + +static GimpResource * +get_initial_resource_from_config (GObject *config, + const gchar *property_name) +{ + GimpResource *initial_resource; + + g_debug ("%s called", G_STRFUNC); + + g_object_get (config, + property_name, &initial_resource, + NULL); + + return initial_resource; +} diff --git a/libgimp/gimppropchooserfactory.h b/libgimp/gimppropchooserfactory.h new file mode 100644 index 0000000000..d012a151be --- /dev/null +++ b/libgimp/gimppropchooserfactory.h @@ -0,0 +1,46 @@ +/* LIBGIMP - The GIMP Library + * Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball + * + * This library is free software: you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see + * . + */ + + #if !defined (__GIMP_UI_H_INSIDE__) && !defined (GIMP_COMPILATION) + #error "Only can be included directly." + #endif + +#ifndef __GIMP_PROP_CHOOSER_FACTORY_H__ +#define __GIMP_PROP_CHOOSER_FACTORY_H__ + +G_BEGIN_DECLS + +/** +* GimpResourceWidgetCreator: +* @title: title of the popup chooser dialog +* @initial_resource: Resource to show as initial choice +* +* Function producing a chooser widget for a specific GimpResource object type. +* e.g. gimp_font_select_button_new +* Widgets for resource subclass choosers all have the same signature. +**/ +typedef GtkWidget* (*GimpResourceWidgetCreator)(const gchar* title, GimpResource * initial_resource); + +GtkWidget *gimp_prop_chooser_factory (GimpResourceWidgetCreator widget_creator_func, + GObject *config, + const gchar *property_name, + const gchar *chooser_title); + +G_END_DECLS + +#endif /* __GIMP_PROP_CHOOSER_FACTORY_H__ */ diff --git a/libgimp/gimpresourceselect.c b/libgimp/gimpresourceselect.c new file mode 100644 index 0000000000..071255c8ca --- /dev/null +++ b/libgimp/gimpresourceselect.c @@ -0,0 +1,622 @@ +/* LIBGIMP - The GIMP Library + * Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball + * + * This library is free software: you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see + * . + */ + +#include "config.h" + +#include "gimp.h" + +/* Data bounced back and forth to/from core and libgimp, + * and here from the temp PDB procedure to the idle func. + * But it is opaque to core, passed and returned unaltered. + * + * Not all fields are meaningful in each direction or transfer. + * !!! We don't pass resource to core in this struct, + * only from the temp callback to the idle func. + * + * Lifetime is as long as the remote dialog is open. + * Closing the chooser dialog frees the adaption struct. + */ +typedef struct +{ + /* This portion is passed to and from idle. */ + /* !!! resource is not long lived, only during a transfer to idle. */ + guint idle_id; + GimpResource *resource; + GType resource_type; + gboolean closing; + + /* This portion is passed to and from core, and to idle. */ + gchar *temp_PDB_callback_name; + GimpResourceChoosedCallback callback; + gpointer owner_data; + GDestroyNotify data_destroy; +} GimpResourceAdaption; + + +/* local */ + +static void gimp_resource_data_free (GimpResourceAdaption *adaption); + +static GimpValueArray * gimp_temp_resource_run (GimpProcedure *procedure, + const GimpValueArray *args, + gpointer run_data); +static gboolean gimp_temp_resource_idle (GimpResourceAdaption *adaption); + + +/* public */ + +/* Annotation, which appears in the libgimp API doc. + * Not a class, only functions. + * The functions appear as class methods of GimpResource class. + * Formerly, API had separate functions for each resource subclass. + */ + +/** + * SECTION: gimpresourceselect + * @title: GimpResourceSelect + * @short_description: A resource selection dialog. + * + * A resource selection dialog. + * + * An adapter and proxy between libgimp and core. + * (see Adapter and Proxy patterns in programming literature.) + * + * Proxy: to a remote dialog in core. + * Is a dialog, but the dialog is remote (another process.) + * Remote dialog is a chooser dialog of subclass of GimpResource, + * e.g. GimpBrush, GimpFont, etc. + * + * Adapter: gets a callback via PDB procedure from remote dialog + * and shuffles parameters to call a owner's callback on libgimp side. + * + * Generic on type of GimpResource subclass. + * That is, the type of GimpResource subclass is passed. + * + * Responsibilities: + * + * - implement a proxy to a chooser widget in core + * + * Collaborations: + * + * - called by GimpResourceSelectButton to popup as a sibling widget + * - PDB procedures to/from core, which implements the remote dialog + * (from via PDB temp callback, to via PDB procs such as gimp_fonts_popup) + * - plugins implementing their own GUI + **/ + +/* This was extracted from gimpbrushselect.c, gimpfontselect.c, etc. + * and those were deleted. + */ + +/* Functions that dispatch on resource type. + * + * For now, the design is that core callbacks pass + * attributes of the resource (not just the resource.) + * FUTURE: core will use the same signature for all remote dialogs, + * regardless of resource type. + * Then all this dispatching code can be deleted. + */ + + +/* Create args for temp PDB callback. + * Must match signature that core hardcodes in a subclass of gimp_pdb_dialog. + * + * For example, see app/widgets/paletteselect.c + * + * When testing, the error "Unable to run callback... temp_proc... wrong type" + * means a signature mismatch. + * + * Note the signature from core might be from an old design where + * the core sent all data needed to draw the resource. + * In the new design, libgimp gets the attributes of the resource + * from core in a separate PDB proc call back to core. + * While core uses the old design and libgimp uses the new design, + * libgimp simply ignores the extra args (adapts the signature.) + */ +static void +create_callback_PDB_procedure_params ( + GimpProcedure *procedure, + GType resource_type) +{ + /* Order of args is important. */ + + /* Prefix of args is same across resource_type. */ + /* !!! core gimp_pdb_dialog is still passing string. */ + GIMP_PROC_ARG_STRING (procedure, "resource-name", + "Resource name", + "The resource name", + NULL, + G_PARAM_READWRITE); + + /* Create args for the extra, superfluous args that core is passing.*/ + if (g_type_is_a (resource_type, GIMP_TYPE_FONT)) + { + /* No other args. */ + } + else if (g_type_is_a (resource_type, GIMP_TYPE_GRADIENT)) + { + GIMP_PROC_ARG_INT (procedure, "gradient-width", + "Gradient width", + "The gradient width", + 0, G_MAXINT, 0, + G_PARAM_READWRITE); + + GIMP_PROC_ARG_FLOAT_ARRAY (procedure, "gradient-data", + "Gradient data", + "The gradient data", + G_PARAM_READWRITE); + } + else if (g_type_is_a (resource_type, GIMP_TYPE_BRUSH)) + { + GIMP_PROC_ARG_DOUBLE (procedure, "opacity", + "Opacity", + NULL, + 0.0, 100.0, 100.0, + G_PARAM_READWRITE); + + GIMP_PROC_ARG_INT (procedure, "spacing", + "Spacing", + NULL, + -1, 1000, 20, + G_PARAM_READWRITE); + + GIMP_PROC_ARG_ENUM (procedure, "paint-mode", + "Paint mode", + NULL, + GIMP_TYPE_LAYER_MODE, + GIMP_LAYER_MODE_NORMAL, + G_PARAM_READWRITE); + + GIMP_PROC_ARG_INT (procedure, "mask-width", + "Brush width", + NULL, + 0, 10000, 0, + G_PARAM_READWRITE); + + GIMP_PROC_ARG_INT (procedure, "mask-height", + "Brush height", + NULL, + 0, 10000, 0, + G_PARAM_READWRITE); + + GIMP_PROC_ARG_INT (procedure, "mask-len", + "Mask length", + "Length of brush mask data", + 0, G_MAXINT, 0, + G_PARAM_READWRITE); + + GIMP_PROC_ARG_UINT8_ARRAY (procedure, "mask-data", + "Mask data", + "The brush mask data", + G_PARAM_READWRITE); + } + else if (g_type_is_a (resource_type, GIMP_TYPE_PALETTE)) + { + GIMP_PROC_ARG_INT (procedure, "num-colors", + "Num colors", + "Number of colors", + 0, G_MAXINT, 0, + G_PARAM_READWRITE); + } + else if (g_type_is_a (resource_type, GIMP_TYPE_PATTERN)) + { + GIMP_PROC_ARG_INT (procedure, "mask-width", + "Mask width", + "Pattern width", + 0, 10000, 0, + G_PARAM_READWRITE); + + GIMP_PROC_ARG_INT (procedure, "mask-height", + "Mask height", + "Pattern height", + 0, 10000, 0, + G_PARAM_READWRITE); + + GIMP_PROC_ARG_INT (procedure, "mask-bpp", + "Mask bpp", + "Pattern bytes per pixel", + 0, 10000, 0, + G_PARAM_READWRITE); + + GIMP_PROC_ARG_INT (procedure, "mask-len", + "Mask length", + "Length of pattern mask data", + 0, G_MAXINT, 0, + G_PARAM_READWRITE); + + GIMP_PROC_ARG_UINT8_ARRAY (procedure, "mask-data", + "Mask data", + "The pattern mask data", + G_PARAM_READWRITE); + } + else + { + g_warning ("%s: unhandled resource type", G_STRFUNC); + } + + /* Suffix of args is same across resource_type. */ + GIMP_PROC_ARG_BOOLEAN (procedure, "closing", + "Closing", + "If the dialog was closing", + FALSE, + G_PARAM_READWRITE); +} + +/* Open (create) a remote chooser dialog of resource. + * + * Dispatch on subclass of GimpResource. + * Call a PDB procedure that communicates with core to create remote dialog. + */ +static gboolean +popup_remote_chooser ( + const gchar *title, + GimpResource *resource, + gchar *temp_PDB_callback_name, + GType resource_type) +{ + gboolean result = FALSE; + gchar *resource_name; + + g_debug ("%s", G_STRFUNC); + + /* The PDB procedure still takes a name aka ID instead of a resource object. */ + g_object_get (resource, "id", &resource_name, NULL); + + if (g_type_is_a (resource_type, GIMP_TYPE_BRUSH)) + { + result = gimp_brushes_popup (temp_PDB_callback_name, title, resource_name); + } + else if (g_type_is_a (resource_type, GIMP_TYPE_FONT)) + { + result = gimp_fonts_popup (temp_PDB_callback_name, title, resource_name); + } + else if (g_type_is_a (resource_type, GIMP_TYPE_GRADIENT)) + { + result = gimp_gradients_popup (temp_PDB_callback_name, title, resource_name); + } + else if (g_type_is_a (resource_type, GIMP_TYPE_PALETTE)) + { + result = gimp_palettes_popup (temp_PDB_callback_name, title, resource_name); + } + else if (g_type_is_a (resource_type, GIMP_TYPE_PATTERN)) + { + result = gimp_patterns_popup (temp_PDB_callback_name, title, resource_name); + } + else + { + g_warning ("%s: unhandled resource type", G_STRFUNC); + } + return result; +} + +/*Does nothing, quietly, when the remote dialog is not open. */ +static void +close_remote_chooser ( + gchar *temp_PDB_callback_name, + GType resource_type) +{ + if (g_type_is_a (resource_type, GIMP_TYPE_FONT)) + { + gimp_fonts_close_popup (temp_PDB_callback_name); + } + else if (g_type_is_a (resource_type, GIMP_TYPE_GRADIENT)) + { + gimp_gradients_close_popup (temp_PDB_callback_name); + } + else if (g_type_is_a (resource_type, GIMP_TYPE_BRUSH)) + { + gimp_brushes_close_popup (temp_PDB_callback_name); + } + else if (g_type_is_a (resource_type, GIMP_TYPE_PALETTE)) + { + gimp_palettes_close_popup (temp_PDB_callback_name); + } + else if (g_type_is_a (resource_type, GIMP_TYPE_PATTERN)) + { + gimp_patterns_close_popup (temp_PDB_callback_name); + } + else + { + g_warning ("%s: unhandled resource type", G_STRFUNC); + } +} + +/* Get the index of the is_closing arg in a GimpValueArray of the tempPDBproc. + * Count the extra args above, and add that to 1. + */ +static gint +index_of_is_closing_arg (GType resource_type) +{ + if (g_type_is_a (resource_type, GIMP_TYPE_FONT)) + { + return 1; + } + else if (g_type_is_a (resource_type, GIMP_TYPE_GRADIENT)) + { + return 3; + } + else if (g_type_is_a (resource_type, GIMP_TYPE_BRUSH)) + { + return 8; + } + else if (g_type_is_a (resource_type, GIMP_TYPE_PALETTE)) + { + return 2; + } + else if (g_type_is_a (resource_type, GIMP_TYPE_PATTERN)) + { + return 6; + } + else + { + g_warning ("%s: unhandled resource type", G_STRFUNC); + return 0; + } +} + + +/** + * gimp_resource_select_new: + * @title: Title of the resource selection dialog. + * @resource: The resource to set as the initial choice. + * @resource_type: The type of the subclass of resource. + * @callback: (scope notified): The callback function to call when a user chooses a resource. + * @owner_data: (closure callback): The run_data given to @callback. + * @data_destroy: (destroy owner_data): The destroy function for @owner_data. + * + * Invoke a resource chooser dialog which may call @callback with the chosen + * resource and owner's @data. + * + * A proxy to a remote dialog in core, which knows the model i.e. installed resources. + * + * Generic on type of #GimpResource subclass passed in @resource_type. + * + * Returns: (transfer none): the name of a temporary PDB procedure. The + * string belongs to the resource selection dialog and will be + * freed automatically when the dialog is closed. + **/ + + +const gchar * +gimp_resource_select_new ( + const gchar *title, + GimpResource *resource, + GType resource_type, + GimpResourceChoosedCallback callback, + gpointer owner_data, + GDestroyNotify data_destroy) +{ + GimpPlugIn *plug_in = gimp_get_plug_in (); + GimpProcedure *procedure; + gchar *temp_PDB_callback_name; + GimpResourceAdaption *adaption; + + g_debug ("%s", G_STRFUNC); + + g_return_val_if_fail (resource != NULL, NULL); + g_return_val_if_fail (callback != NULL, NULL); + g_return_val_if_fail (resource_type != 0, NULL); + + temp_PDB_callback_name = gimp_pdb_temp_procedure_name (gimp_get_pdb ()); + + adaption = g_slice_new0 (GimpResourceAdaption); + + adaption->temp_PDB_callback_name = temp_PDB_callback_name; + adaption->callback = callback; + adaption->owner_data = owner_data; + adaption->data_destroy = data_destroy; + adaption->resource_type = resource_type; + + /* !!! Only part of the adaption has been initialized. */ + + procedure = gimp_procedure_new (plug_in, + temp_PDB_callback_name, + GIMP_PDB_PROC_TYPE_TEMPORARY, + gimp_temp_resource_run, + adaption, + (GDestroyNotify) gimp_resource_data_free); + + create_callback_PDB_procedure_params (procedure, resource_type); + + gimp_plug_in_add_temp_procedure (plug_in, procedure); + g_object_unref (procedure); + + if (popup_remote_chooser (title, resource, temp_PDB_callback_name, resource_type)) + { + /* Allow callbacks to be watched */ + gimp_plug_in_extension_enable (plug_in); + + return temp_PDB_callback_name; + } + else + { + g_warning ("Failed to open remote resource select dialog."); + gimp_plug_in_remove_temp_procedure (plug_in, temp_PDB_callback_name); + return NULL; + } +} + + +void +gimp_resource_select_destroy (const gchar *temp_PDB_callback_name) +{ + GimpPlugIn *plug_in = gimp_get_plug_in (); + + g_debug ("%s", G_STRFUNC); + + g_return_if_fail (temp_PDB_callback_name != NULL); + + gimp_plug_in_remove_temp_procedure (plug_in, temp_PDB_callback_name); + + /* Assert that removing temp procedure will callback the destroy function + * gimp_resource_data_free. + * The allocated adaption must not be used again. + */ +} + + +/* Set currently selected resource in remote chooser. + * + * Calls a PDB procedure. + * + * Note core is still using string name of resource, + * so pdb/groups/_select.pdb, _set_popup must have type string. + */ +void +gimp_resource_select_set ( + const gchar *temp_pdb_callback, + GimpResource *resource, + GType resource_type) +{ + gchar * resource_name; + + g_debug ("%s", G_STRFUNC); + + /* The remote setter is e.g. gimp_fonts_set_popup, a PDB procedure. + * It still takes a name aka ID instead of a resource object. + */ + g_object_get (resource, "id", &resource_name, NULL); + + if (g_type_is_a (resource_type, GIMP_TYPE_FONT)) + { + gimp_fonts_set_popup (temp_pdb_callback, resource_name); + } + else if (g_type_is_a (resource_type, GIMP_TYPE_GRADIENT)) + { + gimp_gradients_set_popup (temp_pdb_callback, resource_name); + } + else if (g_type_is_a (resource_type, GIMP_TYPE_BRUSH)) + { + gimp_brushes_set_popup (temp_pdb_callback, resource_name); + } + else if (g_type_is_a (resource_type, GIMP_TYPE_PALETTE)) + { + gimp_palettes_set_popup (temp_pdb_callback, resource_name); + } + else if (g_type_is_a (resource_type, GIMP_TYPE_PATTERN)) + { + gimp_patterns_set_popup (temp_pdb_callback, resource_name); + } + else + { + g_warning ("%s: unhandled resource type", G_STRFUNC); + } +} + +/* private functions */ + +/* Free a GimpResourceAdaption struct. + * A GimpResourceAdaption and this func are passed to a GimpProcedure + * and this func is called back when the procedure is removed. + * + * This can be called for the exception: failed to open remote dialog. + * + * Each allocated field must be safely freed (not assuming it is valid pointer.) + */ +static void +gimp_resource_data_free (GimpResourceAdaption *adaption) +{ + g_debug ("%s", G_STRFUNC); + + if (adaption->idle_id) + g_source_remove (adaption->idle_id); + + /* adaption->resource should be NULL, else we failed to transfer to the owner. */ + g_clear_object (&adaption->resource); + + if (adaption->temp_PDB_callback_name) + { + close_remote_chooser (adaption->temp_PDB_callback_name, adaption->resource_type); + g_free (adaption->temp_PDB_callback_name); + } + + /* Destroy any inner generic data passed by the owner. */ + if (adaption->data_destroy) + adaption->data_destroy (adaption->owner_data); + + g_slice_free (GimpResourceAdaption, adaption); +} + +/* Run func for the temporary PDB procedure. + * Called when user chooses a resource in remote dialog. + */ +static GimpValueArray * +gimp_temp_resource_run ( + GimpProcedure *procedure, + const GimpValueArray *args, + gpointer run_data) /* is-a adaption */ +{ + GimpResourceAdaption *adaption = run_data; + const gchar *resource_name; + GimpResource *resource; + + g_debug ("%s", G_STRFUNC); + + /* Convert name string to object. */ + resource_name = GIMP_VALUES_GET_STRING(args, 0); + resource = g_object_new (adaption->resource_type, "id", resource_name, NULL); + /* Pass the new resource object to the idle func, which will transfer ownership. + * and clear adaption->resource. + * Thus assert that adaption->resource is NULL, and this is not a leak. + */ + adaption->resource = resource; + + /* !!! Adapting the temp PDB callback signature to simplified libgimp callback. + * I.E. discarding args that are attributes of the resource. + */ + adaption->closing = GIMP_VALUES_GET_BOOLEAN (args, index_of_is_closing_arg (adaption->resource_type)); + + /* Set idle_id to remember an idle source exists, + * but idle_id is not used by the idle func. + */ + if (! adaption->idle_id) + adaption->idle_id = g_idle_add ((GSourceFunc) gimp_temp_resource_idle, + adaption); + + return gimp_procedure_new_return_values (procedure, GIMP_PDB_SUCCESS, NULL); +} + +static gboolean +gimp_temp_resource_idle (GimpResourceAdaption *adaption) +{ + adaption->idle_id = 0; + + g_debug ("%s", G_STRFUNC); + + /* We don't expect callback to be NULL, but check anyway. + * This is asynchronous so there could be a race. + */ + if (adaption->callback) + adaption->callback (adaption->resource, + adaption->closing, + adaption->owner_data); + + /* Ownership of resource transfers to whom we are calling back. */ + adaption->resource = NULL; + + if (adaption->closing) + { + gchar *temp_PDB_callback_name = adaption->temp_PDB_callback_name; + + adaption->temp_PDB_callback_name = NULL; + gimp_resource_select_destroy (temp_PDB_callback_name); + g_free (temp_PDB_callback_name); + } + + return G_SOURCE_REMOVE; +} diff --git a/libgimp/gimpresourceselect.h b/libgimp/gimpresourceselect.h new file mode 100644 index 0000000000..8ad8fe47a6 --- /dev/null +++ b/libgimp/gimpresourceselect.h @@ -0,0 +1,55 @@ +/* LIBGIMP - The GIMP Library + * Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball + * + * This library is free software: you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see + * . + */ + +#if !defined (__GIMP_H_INSIDE__) && !defined (GIMP_COMPILATION) +#error "Only can be included directly." +#endif + +#ifndef __GIMP_RESOURCE_SELECT_H__ +#define __GIMP_RESOURCE_SELECT_H__ + +G_BEGIN_DECLS + +/** + * GimpResourceChoosedCallback: + * @resource: Chosen resource + * @is_dialog_closing: Did user click Close button of dialog? + * @owner_data: (closure): Owner's data + * + * Callback from libgimp GimpResourceSelect adapter to owner. + **/ +typedef void (* GimpResourceChoosedCallback) (GimpResource *resource, + gboolean is_dialog_closing, + gpointer owner_data); + +const gchar * gimp_resource_select_new (const gchar *title, + GimpResource *resource, + GType resource_type, + GimpResourceChoosedCallback callback, + gpointer owner_data, + GDestroyNotify data_destroy); + +void gimp_resource_select_destroy (const gchar *temp_pdb_callback); + +void gimp_resource_select_set (const gchar *temp_pdb_callback, + GimpResource *resource, + GType resource_type); + +G_END_DECLS + +#endif /* __GIMP_RESOURCE_SELECT_H__ */ diff --git a/libgimp/gimpresourceselectbutton.c b/libgimp/gimpresourceselectbutton.c new file mode 100644 index 0000000000..31ce8e1a75 --- /dev/null +++ b/libgimp/gimpresourceselectbutton.c @@ -0,0 +1,731 @@ +/* LIBGIMP - The GIMP Library + * Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball + * + * This library is free software: you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see + * . + */ + +#include "config.h" + +#include +#include + +#include "libgimpwidgets/gimpwidgets.h" + +#include "gimp.h" + +#include "gimpuitypes.h" +#include "gimpresourceselectbutton.h" +#include "gimpuimarshal.h" + +#include "libgimp-intl.h" + + +/* Annotation for the class, which appears in the GimpUi doc. */ + +/** + * SECTION: gimpresourceselectbutton + * @title: GimpResourceSelectButton + * @short_description: Base class for buttons that popup a resource selection dialog. + * + * A button which pops up a resource selection dialog. + * + * Subclasses: GimpFontSelectButton is a minimal one. + * A subclass provides button trait (clickable), + * but possibly not a GtkButton and may have many sub widgets. + * + * Responsibilities: + * + * - implementing outer container widget, + * - managing clicks and popping up a remote chooser, + * - having a resource property, + * - signaling when user selects resource + * - receiving drag, + * - triggering draws of the button interior (by subclass) and draws of remote popup chooser. + * + * Collaborations: + * + * - owned by GimpProcedureDialog via GimpPropWidget + * - resource property usually bound to a GimpConfig for a GimpPluginProcedure. + * - communicates using GimpResourceSelect with remote GimpPDBDialog, + * to choose an installed GimpResource owned by core. + * + * Subclass responsibilities: + * + * - creating interior widgets + * - drawing the interior (a preview of the chosen resource) + * - declaring which interior widgets are drag destinations + * - declaring which interior widgets are clickable (generate "clicked" signal) + * - generate "clicked" (delegating to GtkButton or implementing from mouse events) + * + * Class is abstract and cannot be instantiated: no new () method. + * Instead, instantiate a subclass. + * + * Since: 3.0 + **/ + +/* This class was derived from GimpSelectButton and its subclass GimpPatternSelectButton. + * By moving things from the subclass to the super class, generalizing. + * I.E. refactored by inheriting methods that are the same across subclasses. + */ + + + +enum +{ + RESOURCE_SET, + LAST_SIGNAL +}; + +enum +{ + PROP_0, + PROP_TITLE, + PROP_RESOURCE, + N_PROPS +}; + + +/* Private structure definition. */ +typedef struct +{ + GimpResource *resource; /* Thing self widget chooses*/ + /* Type of resource is known by the class, not instance. + * e.g. GimpFont, some subclass of GimpResource + */ + + /* Self collaborates with a remote widget, a popup chooser dialog. */ + const gchar *title; /* Title of remote widget. */ + + /* Interface functions to remote dialog. + * Instance knows a temporary PDB procedure which the remote dialog callbacks self. + * This specializes us, and is returned by a call to e.g. gimp_pattern_select_new, + * a libgimp function that talks to remote dialog. + * + * It does not need to be freed, owned by the PDB. + */ + const gchar *temp_callback_from_remote_dialog; + + /* Self is-a GtkContainer widget to which subclasses will embed. */ + /* Widget interior to self, created and drawn by subclass. */ + GtkWidget *interior_widget; + +} GimpResourceSelectButtonPrivate; + + +/* local function prototypes */ + +/* Overridden GObject methods. */ +static void gimp_resource_select_button_dispose (GObject *object); +static void gimp_resource_select_button_finalize (GObject *object); + +static void gimp_resource_select_button_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec); +static void gimp_resource_select_button_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec); + +static void gimp_resource_select_button_clicked (GimpResourceSelectButton *self); + +static void gimp_resource_select_button_callback (GimpResource *resource, + gboolean dialog_closing, + gpointer user_data); + +static void gimp_resource_select_drag_data_received (GimpResourceSelectButton *self, + GdkDragContext *context, + gint x, + gint y, + GtkSelectionData *selection, + guint info, + guint time); + +static void gimp_resource_select_button_set_remote_dialog (GimpResourceSelectButton *self, + GimpResource *resource); + +static guint resource_button_signals[LAST_SIGNAL] = { 0 }; +static GParamSpec *resource_button_props[N_PROPS] = { NULL, }; + +G_DEFINE_TYPE_WITH_PRIVATE (GimpResourceSelectButton, gimp_resource_select_button, + GTK_TYPE_BOX) + + +static void +gimp_resource_select_button_class_init (GimpResourceSelectButtonClass *klass) +{ + /* Root super class */ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + g_debug ("%s", G_STRFUNC); + + /* Override to root super class GObject. */ + object_class->dispose = gimp_resource_select_button_dispose; + object_class->finalize = gimp_resource_select_button_finalize; + object_class->set_property = gimp_resource_select_button_set_property; + object_class->get_property = gimp_resource_select_button_get_property; + + /* Signals */ + klass->resource_set = NULL; + + /** + * GimpResourceSelectButton:title: + * + * The title to be used for the resource selection popup dialog. + * + * Since: 2.4 + */ + /* Default is not localized i18n since caller should provide a value. */ + resource_button_props[PROP_TITLE] + = g_param_spec_string ("title", + "Title", + "The title to be used for the resource selection popup dialog", + "Resource Selection", /* default */ + GIMP_PARAM_READWRITE | + G_PARAM_CONSTRUCT_ONLY); + + /** + * GimpResourceSelectButton:resource: + * + * The currently selected resource. + * + * Since: 2.4 + */ + /* Has no default. */ + resource_button_props[PROP_RESOURCE] + = gimp_param_spec_resource ("resource", /* name */ + "Resource", /* nick */ + "The currently selected resource", + TRUE, /* none_ok */ + GIMP_PARAM_READWRITE); + + g_object_class_install_properties (object_class, N_PROPS, resource_button_props); + + /** + * GimpResourceSelectButton::resource-set: + * @widget: the object which received the signal. + * @resource: the currently selected resource. + * @dialog_closing: whether the dialog was closed or not. + * + * The ::resource-set signal is emitted when the user selects a resource. + * + * Since: 2.4 + */ + resource_button_signals[RESOURCE_SET] = + g_signal_new ("resource-set", + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (GimpResourceSelectButtonClass, resource_set), + NULL, NULL, + _gimpui_marshal_VOID__POINTER_BOOLEAN, + G_TYPE_NONE, 2, + G_TYPE_OBJECT, + G_TYPE_BOOLEAN); +} + +static void +gimp_resource_select_button_init (GimpResourceSelectButton *self) +{ + GimpResourceSelectButtonPrivate *priv = gimp_resource_select_button_get_instance_private (self); + + g_debug ("%s", G_STRFUNC); + + g_return_if_fail (GIMP_IS_RESOURCE_SELECT_BUTTON (self)); + + gtk_orientable_set_orientation (GTK_ORIENTABLE (self), GTK_ORIENTATION_HORIZONTAL); + + /* No need to initialize interior_widget. A subclass will add it, which must have a clickable.*/ + + /* Remote dialog not exist yet. */ + priv->temp_callback_from_remote_dialog = NULL; +} + + +/** + * gimp_resource_select_button_set_drag_target: + * @self: A #GimpResourceSelectButton + * @drag_region_widget: An interior widget to be a droppable region and emit "drag-data-received" signal + * @drag_target: The drag target to accept + * + * Called by a subclass init to specialize the instance. + * + * Subclass knows its interior widget whose region is a drop zone. + * Subclass knows what things can be dropped (target.) + * Self (super) handles the drop. + * + * Since: 3.0 + **/ +void +gimp_resource_select_button_set_drag_target ( + GimpResourceSelectButton *self, + GtkWidget *drag_region_widget, + const GtkTargetEntry *drag_target) +{ + g_debug ("%s", G_STRFUNC); + + g_return_if_fail (GIMP_IS_RESOURCE_SELECT_BUTTON (self)); + g_return_if_fail (drag_target != NULL); + g_return_if_fail (drag_region_widget != NULL); + + gtk_drag_dest_set (drag_region_widget, + GTK_DEST_DEFAULT_HIGHLIGHT | + GTK_DEST_DEFAULT_MOTION | + GTK_DEST_DEFAULT_DROP, + drag_target, 1, /* Pass array of size 1 */ + GDK_ACTION_COPY); + + /* connect drag_region_widget's drag_received signal to self's callback. */ + g_signal_connect_swapped (drag_region_widget, "drag-data-received", + G_CALLBACK (gimp_resource_select_drag_data_received), + self); +} + +/** + * gimp_resource_select_button_set_clickable: + * @self: A #GimpResourceSelectButton + * @widget: An interior widget that emits "clicked" signal + * + * Called by a subclass init to specialize the instance. + * + * Subclass knows its interior widget whose region when clicked + * should popup remote chooser. + * Self handles the click event. + * + * Since: 3.0 + **/ +void +gimp_resource_select_button_set_clickable (GimpResourceSelectButton *self, + GtkWidget *widget) +{ + g_debug ("%s", G_STRFUNC); + + g_return_if_fail (GIMP_IS_RESOURCE_SELECT_BUTTON (self)); + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_WIDGET (widget)); + + /* Require the widget have a signal "clicked", usually a button. */ + g_signal_connect_swapped (widget, "clicked", + G_CALLBACK (gimp_resource_select_button_clicked), + self); +} + +/** + * gimp_resource_select_button_get_resource: + * @self: A #GimpResourceSelectButton + * + * Gets the currently selected resource. + * + * Returns: (transfer none): an internal copy of the resource which must not be freed. + * You should ref and unref it when you want to own the resource. + * + * Since: 2.4 + */ +GimpResource * +gimp_resource_select_button_get_resource (GimpResourceSelectButton *self) +{ + GimpResourceSelectButtonPrivate *priv; + + g_return_val_if_fail (GIMP_IS_RESOURCE_SELECT_BUTTON (self), NULL); + + priv = gimp_resource_select_button_get_instance_private (self); + return priv->resource; +} + +/** + * gimp_resource_select_button_set_resource: + * @self: A #GimpResourceSelectButton + * @resource: Resource to set. + * + * Sets the currently selected resource. + * This will select the resource in both the button and any chooser popup. + * + * Since: 2.4 + */ +void +gimp_resource_select_button_set_resource (GimpResourceSelectButton *self, + GimpResource *resource) +{ + GimpResourceSelectButtonPrivate *priv; + + g_return_if_fail (GIMP_IS_RESOURCE_SELECT_BUTTON (self)); + g_return_if_fail (resource != NULL); + + priv = gimp_resource_select_button_get_instance_private (self); + + g_debug ("%s", G_STRFUNC); + + if (priv->temp_callback_from_remote_dialog) + { + /* A popup chooser dialog is already shown. + * Call its setter to change the selection there + * (since all views of the resource must be consistent.) + * That will call back, which will change our own view of the resource. + */ + gimp_resource_select_button_set_remote_dialog (self, resource); + } + else + { + /* Call our own setter. */ + gimp_resource_select_button_callback (resource, FALSE, self); + } +} + + +/** + * gimp_resource_select_button_embed_interior: + * @self: A #GimpResourceSelectButton + * @interior: Interior widget to embed into the exterior container widget. + * + * Called by subclasses init to specialize the instance. + * + * Embed an interior widget into self's outer container widget. + * + * Since: 3.0 + */ +void +gimp_resource_select_button_embed_interior (GimpResourceSelectButton *self, GtkWidget * interior) +{ + g_return_if_fail (GIMP_IS_RESOURCE_SELECT_BUTTON (self)); + g_return_if_fail (GTK_IS_WIDGET (interior)); + g_return_if_fail (GTK_IS_CONTAINER (self)); + + gtk_container_add (GTK_CONTAINER (self), interior); + + /* Show self as widget, now it is complete. */ + gtk_widget_show_all (GTK_WIDGET (self)); + + /* We can't draw the interior until self property "resource" is set. */ +} + +/** + * gimp_resource_select_button_draw_interior: + * @self: A #GimpResourceSelectButton + * @resource: A resource instance whose attributes should be drawn. + * + * Calls the virtual method of a similar name, which subclasses must override. + * + * A subclass knows how to draw its interior. + * Called by super when the view is invalidated (needs to be redrawn.) + * Public, but subclasses do not ordinarily call this function. + * + * Since: 3.0 + **/ +void +gimp_resource_select_button_draw_interior (GimpResourceSelectButton *self, GimpResource *resource) +{ + GimpResourceSelectButtonClass *klass; + + g_debug ("%s", G_STRFUNC); + + g_return_if_fail (GIMP_IS_RESOURCE_SELECT_BUTTON (self)); + g_return_if_fail (GIMP_IS_RESOURCE (resource)); + + klass = GIMP_RESOURCE_SELECT_BUTTON_GET_CLASS (self); + + /* Check subclass has overridden before calling it. */ + g_return_if_fail (klass->draw_interior != NULL); + /* Call the subclass drawing method. */ + klass->draw_interior (self); + + /* Note that gtk_widget_queue_draw is specific to cairo drawing areas, + * and is not a general method of forcing a refresh of a wiget. + * We always call the subclass draw method via its implementation + * of our virtual draw method. + * The subclass may use gtk_widget_queue_draw, but we don't. + */ +} + +/* private functions */ + +static void +gimp_resource_select_button_set_remote_dialog (GimpResourceSelectButton *self, + GimpResource *resource) +{ + GimpResourceSelectButtonPrivate *priv; + GimpResourceSelectButtonClass *klass; + + g_debug ("%s", G_STRFUNC); + + g_return_if_fail (GIMP_IS_RESOURCE_SELECT_BUTTON (self)); + g_return_if_fail (resource != NULL); + + priv = gimp_resource_select_button_get_instance_private (self); + klass = GIMP_RESOURCE_SELECT_BUTTON_GET_CLASS (self); + + /* Require virtual method was overridden by subclass. */ + g_return_if_fail (klass->resource_type != G_TYPE_INVALID); + + /* The ultimate remote setter is e.g. gimp_fonts_set_popup, a PDB procedure. + * + * !!! Use the passed resource, not priv->resource. + * Expect a callback which will change priv->resource. + */ + gimp_resource_select_set (priv->temp_callback_from_remote_dialog, + resource, + klass->resource_type); +} + +/* Setter for property. + * Overrides setter of base class GObject. + * The underlying field may be NULL after init, + * but after that, do not allow it to be set to NULL. + * I.E. invariant is (priv->resource != NULL) after new () + */ +static void +gimp_resource_select_button_set_property (GObject *object, + guint property_id, + const GValue *gvalue, + GParamSpec *pspec) +{ + GimpResourceSelectButton *self = GIMP_RESOURCE_SELECT_BUTTON (object); + GimpResourceSelectButtonPrivate *priv = gimp_resource_select_button_get_instance_private (self); + + g_debug ("%s, id: %i", G_STRFUNC, property_id); + + switch (property_id) + { + case PROP_TITLE: + priv->title = g_value_dup_string (gvalue); + break; + + case PROP_RESOURCE: + /* Do not use the exported method set_resource. + * That is internal and less safe + * because it is agnostic of NULL values passed, + * and does not unref any existing value. + */ + GimpResource * specific_value; + + specific_value = g_value_get_object (gvalue); + g_assert (specific_value != NULL); + priv->resource = specific_value; + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + + +static void +gimp_resource_select_button_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec) +{ + GimpResourceSelectButton *self = GIMP_RESOURCE_SELECT_BUTTON (object); + GimpResourceSelectButtonPrivate *priv = gimp_resource_select_button_get_instance_private (self); + + switch (property_id) + { + case PROP_TITLE: + g_value_set_string (value, priv->title); + break; + + case PROP_RESOURCE: + g_value_set_object (value, priv->resource); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + +/* A callback from the remote resource select popup. + * When user chooses a resource. + * Via a temporary PDB procedure. + * + * Set self's model (priv->resource) + * Notify any parent widget subscribed on the "resource" property + * typically a prop widget. + * Update the view, since model changed. + */ +static void +gimp_resource_select_button_callback (GimpResource *resource, + gboolean dialog_closing, + gpointer user_data) +{ + GimpResourceSelectButton *self = GIMP_RESOURCE_SELECT_BUTTON (user_data); + GimpResourceSelectButtonPrivate *priv = gimp_resource_select_button_get_instance_private (self); + + g_debug ("%s, id: %s", G_STRFUNC, gimp_resource_get_id (resource)); + + g_object_unref (priv->resource); + priv->resource = resource; + + /* Feedback user choice of resource into the look of the widget interior. + * Call virtual method overridden by subclass. + */ + gimp_resource_select_button_draw_interior (self, resource); + + if (dialog_closing) + priv->temp_callback_from_remote_dialog = NULL; + + g_signal_emit (self, resource_button_signals[RESOURCE_SET], 0, resource, dialog_closing); + g_object_notify_by_pspec (G_OBJECT (self), resource_button_props[PROP_RESOURCE]); +} + + +static void +gimp_resource_select_button_clicked (GimpResourceSelectButton *self) +{ + GimpResourceSelectButtonPrivate *priv = gimp_resource_select_button_get_instance_private (self); + GimpResourceSelectButtonClass *klass = GIMP_RESOURCE_SELECT_BUTTON_GET_CLASS (self); + + g_debug ("%s called", G_STRFUNC); + + if (priv->temp_callback_from_remote_dialog) + { + /* Popup already created. Calling setter raises the popup. */ + gimp_resource_select_button_set_remote_dialog (self, priv->resource); + } + else + { + g_debug ("%s calling newer of remote dialog", G_STRFUNC); + + /* Call GimpResourceSelect which dispatches on resource_type. */ + priv->temp_callback_from_remote_dialog = + gimp_resource_select_new (priv->title, + priv->resource, + klass->resource_type, + gimp_resource_select_button_callback, + self, + NULL); /* No func to free data. */ + } + g_debug ("%s returns", G_STRFUNC); +} + + +/* Drag methods. */ + +static void +gimp_resource_select_drag_data_received (GimpResourceSelectButton *self, + GdkDragContext *context, + gint x, + gint y, + GtkSelectionData *selection, + guint info, + guint time) +{ + gint length = gtk_selection_data_get_length (selection); + gchar *str; + + GimpResourceSelectButtonClass *klass; + + g_debug ("%s called", G_STRFUNC); + + klass = GIMP_RESOURCE_SELECT_BUTTON_GET_CLASS (self); + /* Require class resource_type was initialized. */ + g_assert (klass->resource_type != 0); + + /* Drag data is a string that is the ID of the resource. */ + + if (gtk_selection_data_get_format (selection) != 8 || length < 1) + { + g_warning ("%s: received invalid resource data", G_STRFUNC); + return; + } + + str = g_strndup ((const gchar *) gtk_selection_data_get_data (selection), + length); + + if (g_utf8_validate (str, -1, NULL)) + { + gint pid; + gpointer unused; + gint name_offset = 0; + + if (sscanf (str, "%i:%p:%n", &pid, &unused, &name_offset) >= 2 && + pid == gimp_getpid () && name_offset > 0) + { + gchar *name = str + name_offset; + GimpResource *resource; + + /* Create just a proxy object, not a new resource in core. + * Create an instance of the type (e.g. GimpFont) that this class creates. + */ + resource = g_object_new (klass->resource_type, "id", name, NULL); + gimp_resource_select_button_set_resource (self, resource); + } + } + + g_free (str); +} + + +/* Dispose, finalize, destroy. */ + +/* When self is disposed, e.g. when user Cancels owning dialog, + * close the remote popup, which will destroy it. + * Dispose is first phase to break possible cycle of the popup referencing self. + */ +static void +gimp_resource_select_button_dispose (GObject *self) +{ + g_debug ("%s", G_STRFUNC); + + gimp_resource_select_button_close_popup (GIMP_RESOURCE_SELECT_BUTTON (self)); + + /* Chain up. */ + G_OBJECT_CLASS (gimp_resource_select_button_parent_class)->dispose (self); +} + +/** + * gimp_resource_select_button_close_popup: + * @self: A #GimpResourceSelectButton + * + * Closes the popup resource chooser dialog associated with @self. + * + * FUTURE: Possibly obsolete this by making it private, + * since only called by script-fu-interface.c. + * Might be needed if we allow plugins to implement their own dialogs. + * + * Since: 2.4 + */ +void +gimp_resource_select_button_close_popup (GimpResourceSelectButton *self) +{ + GimpResourceSelectButtonPrivate *priv; + + g_debug ("%s", G_STRFUNC); + + g_return_if_fail (GIMP_IS_RESOURCE_SELECT_BUTTON (self)); + priv = gimp_resource_select_button_get_instance_private (self); + + if (priv->temp_callback_from_remote_dialog) + { + gimp_resource_select_destroy (priv->temp_callback_from_remote_dialog); + + priv->temp_callback_from_remote_dialog = NULL; + } + /* Else already closed. */ +} + +static void +gimp_resource_select_button_finalize (GObject *object) +{ + GimpResourceSelectButton *self = GIMP_RESOURCE_SELECT_BUTTON (object); + GimpResourceSelectButtonPrivate *priv = gimp_resource_select_button_get_instance_private (self); + + g_debug ("%s", G_STRFUNC); + + g_clear_pointer (&priv->resource, g_free); + g_free ((gpointer) priv->title); + + /* Chain up. */ + G_OBJECT_CLASS (gimp_resource_select_button_parent_class)->finalize (object); +} diff --git a/libgimp/gimpresourceselectbutton.h b/libgimp/gimpresourceselectbutton.h new file mode 100644 index 0000000000..2e73e30d1a --- /dev/null +++ b/libgimp/gimpresourceselectbutton.h @@ -0,0 +1,85 @@ +/* LIBGIMP - The GIMP Library + * Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball + * + * This library is free software: you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see + * . + */ + +#if !defined (__GIMP_UI_H_INSIDE__) && !defined (GIMP_COMPILATION) +#error "Only can be included directly." +#endif + +#ifndef __GIMP_RESOURCE_SELECT_BUTTON_H__ +#define __GIMP_RESOURCE_SELECT_BUTTON_H__ + +G_BEGIN_DECLS + +/* Inherits GtkBox + * Inheritable by e.g. GimpBrushSelectButton. + */ +#define GIMP_TYPE_RESOURCE_SELECT_BUTTON gimp_resource_select_button_get_type () +G_DECLARE_DERIVABLE_TYPE (GimpResourceSelectButton, gimp_resource_select_button, GIMP, RESOURCE_SELECT_BUTTON, GtkBox) + +struct _GimpResourceSelectButtonClass +{ + GtkBoxClass parent_class; + + /* Signal resource_set. Emitted when user chooses a resource. + * The signal carries only the resource (a proxy having an ID). + * The resource knows its own attributes needed for drawing it. + * Such attributes are NOT in the signal. + * + * Seems to be unused by GIMP internal code, + * instead GimpPropChooser binds to property. + */ + /* FIXME: should be an annotation. */ + void (* resource_set) (GimpResourceSelectButton *self, + GimpResource *resource, + gboolean dialog_closing); + + /* virtual methods. */ + void (*draw_interior) (GimpResourceSelectButton *self); + + /* Specialized by subclass. */ + GType resource_type; /* e.g. GimpBrush */ + + /* Padding for future expansion */ + gpointer padding[8]; +}; + +/* Abstract, no new(), instead new a subclass. */ + +/* API from above, e.g. used by GimpPropChooser */ +GimpResource *gimp_resource_select_button_get_resource (GimpResourceSelectButton *self); +void gimp_resource_select_button_set_resource (GimpResourceSelectButton *self, + GimpResource *resource); + +/* Public, but called by super. */ +void gimp_resource_select_button_draw_interior (GimpResourceSelectButton *self, + GimpResource *resource); + +/* API from below, used by subclasses e.g. GimpBrushSelectButton */ + +void gimp_resource_select_button_embed_interior (GimpResourceSelectButton *self, + GtkWidget *interior); +void gimp_resource_select_button_set_drag_target (GimpResourceSelectButton *self, + GtkWidget *drag_region_widget, + const GtkTargetEntry *drag_target); +void gimp_resource_select_button_set_clickable (GimpResourceSelectButton *self, + GtkWidget *widget); +void gimp_resource_select_button_close_popup (GimpResourceSelectButton *self); + +G_END_DECLS + +#endif /* __GIMP_RESOURCE_SELECT_BUTTON_H__ */ diff --git a/libgimp/gimpselectbutton.c b/libgimp/gimpselectbutton.c deleted file mode 100644 index 36ca90c52d..0000000000 --- a/libgimp/gimpselectbutton.c +++ /dev/null @@ -1,94 +0,0 @@ -/* LIBGIMP - The GIMP Library - * Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball - * - * gimpselectbutton.c - * Copyright (C) 2003 Sven Neumann - * - * This library is free software: you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library. If not, see - * . - */ - -#include "config.h" - -#include - -#include "gimp.h" - -#include "gimpuitypes.h" -#include "gimpselectbutton.h" - - -/** - * SECTION: gimpselectbutton - * @title: GimpSelectButton - * @short_description: The base class of the data select buttons. - * - * The base class of the brush, pattern, gradient, palette and font - * select buttons. - **/ - - -/* local function prototypes */ - -static void gimp_select_button_dispose (GObject *object); - - -G_DEFINE_TYPE (GimpSelectButton, gimp_select_button, GTK_TYPE_BOX) - - -static void -gimp_select_button_class_init (GimpSelectButtonClass *klass) -{ - GObjectClass *object_class = G_OBJECT_CLASS (klass); - - object_class->dispose = gimp_select_button_dispose; -} - -static void -gimp_select_button_init (GimpSelectButton *select_button) -{ - gtk_orientable_set_orientation (GTK_ORIENTABLE (select_button), - GTK_ORIENTATION_HORIZONTAL); -} - -static void -gimp_select_button_dispose (GObject *object) -{ - gimp_select_button_close_popup (GIMP_SELECT_BUTTON (object)); - - G_OBJECT_CLASS (gimp_select_button_parent_class)->dispose (object); -} - -/** - * gimp_select_button_close_popup: - * @button: A #GimpSelectButton - * - * Closes the popup window associated with @button. - * - * Since: 2.4 - */ -void -gimp_select_button_close_popup (GimpSelectButton *button) -{ - g_return_if_fail (GIMP_IS_SELECT_BUTTON (button)); - - if (button->temp_callback) - { - GimpSelectButtonClass *klass = GIMP_SELECT_BUTTON_GET_CLASS (button); - - klass->select_destroy (button->temp_callback); - - button->temp_callback = NULL; - } -} diff --git a/libgimp/gimpselectbutton.h b/libgimp/gimpselectbutton.h deleted file mode 100644 index 6b191f697d..0000000000 --- a/libgimp/gimpselectbutton.h +++ /dev/null @@ -1,81 +0,0 @@ -/* LIBGIMP - The GIMP Library - * Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball - * - * gimpselectbutton.h - * - * This library is free software: you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library. If not, see - * . - */ - -#if !defined (__GIMP_UI_H_INSIDE__) && !defined (GIMP_COMPILATION) -#error "Only can be included directly." -#endif - -#ifndef __GIMP_SELECT_BUTTON_H__ -#define __GIMP_SELECT_BUTTON_H__ - -G_BEGIN_DECLS - -/* For information look into the C source or the html documentation */ - - -#define GIMP_TYPE_SELECT_BUTTON (gimp_select_button_get_type ()) -#define GIMP_SELECT_BUTTON(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GIMP_TYPE_SELECT_BUTTON, GimpSelectButton)) -#define GIMP_SELECT_BUTTON_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GIMP_TYPE_SELECT_BUTTON, GimpSelectButtonClass)) -#define GIMP_IS_SELECT_BUTTON(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GIMP_TYPE_SELECT_BUTTON)) -#define GIMP_IS_SELECT_BUTTON_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GIMP_TYPE_SELECT_BUTTON)) -#define GIMP_SELECT_BUTTON_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GIMP_TYPE_SELECT_BUTTON, GimpSelectButtonClass)) - - -typedef struct _GimpSelectButtonPrivate GimpSelectButtonPrivate; -typedef struct _GimpSelectButtonClass GimpSelectButtonClass; - -struct _GimpSelectButton -{ - GtkBox parent_instance; - - GimpSelectButtonPrivate *priv; - - /* FIXME MOVE TO PRIVATE */ - const gchar *temp_callback; -}; - -struct _GimpSelectButtonClass -{ - GtkBoxClass parent_class; - - gchar *default_title; - - void (* select_destroy) (const gchar *callback); - - /* Padding for future expansion */ - void (*_gimp_reserved1) (void); - void (*_gimp_reserved2) (void); - void (*_gimp_reserved3) (void); - void (*_gimp_reserved4) (void); - void (*_gimp_reserved5) (void); - void (*_gimp_reserved6) (void); - void (*_gimp_reserved7) (void); - void (*_gimp_reserved8) (void); -}; - - -GType gimp_select_button_get_type (void) G_GNUC_CONST; - -void gimp_select_button_close_popup (GimpSelectButton *button); - - -G_END_DECLS - -#endif /* __GIMP_SELECT_BUTTON_H__ */ diff --git a/libgimp/gimpui.def b/libgimp/gimpui.def index 557d8b1308..ce71f3002a 100644 --- a/libgimp/gimpui.def +++ b/libgimp/gimpui.def @@ -61,12 +61,23 @@ EXPORTS gimp_procedure_dialog_set_sensitive gimp_progress_bar_get_type gimp_progress_bar_new - gimp_prop_brush_chooser_button_new + gimp_prop_chooser_brush_new + gimp_prop_chooser_factory + gimp_prop_chooser_font_new + gimp_prop_chooser_gradient_new + gimp_prop_chooser_palette_new + gimp_prop_chooser_pattern_new + gimp_resource_select_button_close_popup + gimp_resource_select_button_draw_interior + gimp_resource_select_button_embed_interior + gimp_resource_select_button_get_resource + gimp_resource_select_button_get_type + gimp_resource_select_button_set_clickable + gimp_resource_select_button_set_drag_target + gimp_resource_select_button_set_resource gimp_save_procedure_dialog_add_metadata gimp_save_procedure_dialog_get_type gimp_save_procedure_dialog_new - gimp_select_button_close_popup - gimp_select_button_get_type gimp_ui_get_display_window gimp_ui_get_progress_window gimp_ui_init diff --git a/libgimp/gimpui.h b/libgimp/gimpui.h index 1dd189d990..d5675a5215 100644 --- a/libgimp/gimpui.h +++ b/libgimp/gimpui.h @@ -33,6 +33,7 @@ #include #include #include +#include #include #include #include @@ -43,10 +44,10 @@ #include #include #include +#include +#include #include -#include #include -#include #undef __GIMP_UI_H_INSIDE__ diff --git a/libgimp/gimpuimarshal.list b/libgimp/gimpuimarshal.list index 59ec674668..5e2b8e72c8 100644 --- a/libgimp/gimpuimarshal.list +++ b/libgimp/gimpuimarshal.list @@ -23,6 +23,4 @@ # BOOL deprecated alias for BOOLEAN VOID: STRING, BOOLEAN -VOID: STRING, INT, POINTER, BOOLEAN -VOID: STRING, INT, INT, INT, POINTER, BOOLEAN -VOID: STRING, DOUBLE, INT, INT, INT, INT, POINTER, BOOLEAN +VOID: POINTER, BOOLEAN diff --git a/libgimp/meson.build b/libgimp/meson.build index e15b53a838..c296a291ea 100644 --- a/libgimp/meson.build +++ b/libgimp/meson.build @@ -166,14 +166,11 @@ pdb_wrappers_headers = [ libgimp_sources_introspectable = [ 'gimp.c', 'gimpbatchprocedure.c', - 'gimpbrushselect.c', 'gimpchannel.c', 'gimpdisplay.c', 'gimpdrawable.c', 'gimpfileprocedure.c', - 'gimpfontselect.c', 'gimpgimprc.c', - 'gimpgradientselect.c', 'gimpimage.c', 'gimpimagecolorprofile.c', 'gimpimagemetadata.c', @@ -183,15 +180,14 @@ libgimp_sources_introspectable = [ 'gimplayer.c', 'gimplayermask.c', 'gimploadprocedure.c', - 'gimppaletteselect.c', 'gimpparamspecs.c', - 'gimppatternselect.c', 'gimppdb.c', 'gimpplugin.c', 'gimpprocedure.c', 'gimpprocedureconfig.c', 'gimpprogress.c', 'gimpresource.c', + 'gimpresourceselect.c', 'gimpresource-subclass.c', 'gimpsaveprocedure.c', 'gimpselection.c', @@ -225,14 +221,11 @@ libgimp_headers_introspectable = [ # Other headers 'gimpbatchprocedure.h', - 'gimpbrushselect.h', 'gimpchannel.h', 'gimpdisplay.h', 'gimpdrawable.h', 'gimpfileprocedure.h', - 'gimpfontselect.h', 'gimpgimprc.h', - 'gimpgradientselect.h', 'gimpimage.h', 'gimpimagecolorprofile.h', 'gimpimagemetadata.h', @@ -241,16 +234,15 @@ libgimp_headers_introspectable = [ 'gimplayer.h', 'gimplayermask.h', 'gimploadprocedure.h', - 'gimppaletteselect.h', 'gimpparamspecs.h', 'gimpparamspecs-resource.h', - 'gimppatternselect.h', 'gimppdb.h', 'gimpplugin.h', 'gimpprocedure.h', 'gimpprocedureconfig.h', 'gimpprogress.h', 'gimpresource.h', + 'gimpresourceselect.h', 'gimpresource-subclass.h', 'gimpsaveprocedure.h', 'gimpselection.h', @@ -267,7 +259,6 @@ libgimp_headers = [ libgimpui_sources_introspectable = [ 'gimpaspectpreview.c', - 'gimppropbrushchooser.c', 'gimpbrushselectbutton.c', 'gimpdrawablepreview.c', 'gimpexport.c', @@ -281,8 +272,10 @@ libgimpui_sources_introspectable = [ 'gimpproceduredialog.c', 'gimpprocview.c', 'gimpprogressbar.c', + 'gimppropchooser.c', + 'gimppropchooserfactory.c', + 'gimpresourceselectbutton.c', 'gimpsaveproceduredialog.c', - 'gimpselectbutton.c', 'gimpui.c', 'gimpzoompreview.c', ] @@ -312,8 +305,10 @@ libgimpui_headers_introspectable = [ 'gimpproceduredialog.h', 'gimpprocview.h', 'gimpprogressbar.h', + 'gimppropchooser.h', + 'gimppropchooserfactory.h', + 'gimpresourceselectbutton.h', 'gimpsaveproceduredialog.h', - 'gimpselectbutton.h', 'gimpzoompreview.h', ] diff --git a/libgimpconfig/gimpconfig-params.c b/libgimpconfig/gimpconfig-params.c index 1b6e1fd81e..15f817bb7e 100644 --- a/libgimpconfig/gimpconfig-params.c +++ b/libgimpconfig/gimpconfig-params.c @@ -352,6 +352,10 @@ gimp_config_param_spec_duplicate (GParamSpec *pspec) g_strcmp0 (type_name, "GimpChannel") == 0 || g_strcmp0 (type_name, "GimpSelection") == 0 || g_strcmp0 (type_name, "GimpBrush") == 0 || + g_strcmp0 (type_name, "GimpFont") == 0 || + g_strcmp0 (type_name, "GimpGradient") == 0 || + g_strcmp0 (type_name, "GimpPalette") == 0 || + g_strcmp0 (type_name, "GimpPattern") == 0 || g_strcmp0 (type_name, "GimpVectors") == 0) { copy = g_param_spec_object (name, nick, blurb, diff --git a/pdb/groups/brush_select.pdb b/pdb/groups/brush_select.pdb index f6002bd7cc..b61bbfefef 100644 --- a/pdb/groups/brush_select.pdb +++ b/pdb/groups/brush_select.pdb @@ -17,43 +17,28 @@ # "Perlized" from C source by Manish Singh sub brushes_popup { - $blurb = 'Invokes the Gimp brush selection.'; - $help = 'This procedure opens the brush selection dialog.'; + $blurb = 'Invokes the GIMP brush selection dialog.'; + $help = 'Opens a dialog letting a user choose a brush.'; &andy_pdb_misc('1998'); @inargs = ( - { name => 'brush_callback', type => 'string', non_empty => 1, - desc => 'The callback PDB proc to call when brush selection is - made' }, - { name => 'popup_title', type => 'string', - desc => 'Title of the brush selection dialog' }, - { name => 'initial_brush', type => 'string', null_ok => 1, - desc => 'The name of the brush to set as the first selected' }, - { name => 'opacity', type => '0 <= float <= 100', - desc => 'The initial opacity of the brush' }, - { name => 'spacing', type => 'int32 <= 1000', - desc => 'The initial spacing of the brush (if < 0 then use brush - default spacing)' }, - { name => 'paint_mode', type => 'enum GimpLayerMode', - default => 'GIMP_LAYER_MODE_NORMAL', - desc => 'The initial paint mode' } + { name => 'brush_callback', type => 'string', non_empty => 1, + desc => 'The callback PDB proc to call when user chooses a brush' }, + { name => 'popup_title', type => 'string', + desc => 'Title of the brush selection dialog' }, + { name => 'initial_brush_name', type => 'string', null_ok => 1, + desc => 'The name of the brush to set as the initial choice' } ); %invoke = ( code => <<'CODE' { - if (paint_mode == GIMP_LAYER_MODE_OVERLAY_LEGACY) - paint_mode = GIMP_LAYER_MODE_SOFTLIGHT_LEGACY; - - if (gimp->no_interface || + if (gimp->no_interface || ! gimp_pdb_lookup_procedure (gimp->pdb, brush_callback) || ! gimp_pdb_dialog_new (gimp, context, progress, gimp_data_factory_get_container (gimp->brush_factory), - popup_title, brush_callback, initial_brush, - "opacity", opacity / 100.0, - "paint-mode", paint_mode, - "spacing", spacing, + popup_title, brush_callback, initial_brush_name, NULL)) success = FALSE; } @@ -63,13 +48,13 @@ CODE sub brushes_close_popup { $blurb = 'Close the brush selection dialog.'; - $help = 'This procedure closes an opened brush selection dialog.'; + $help = 'Closes an open brush selection dialog.'; &andy_pdb_misc('1998'); @inargs = ( - { name => 'brush_callback', type => 'string', non_empty => 1, - desc => 'The name of the callback registered for this pop-up' } + { name => 'brush_callback', type => 'string', non_empty => 1, + desc => 'The name of the callback registered for this pop-up' } ); %invoke = ( @@ -86,39 +71,25 @@ CODE } sub brushes_set_popup { - $blurb = 'Sets the current brush in a brush selection dialog.'; + $blurb = 'Sets the selected brush in a brush selection dialog.'; $help = $blurb; &andy_pdb_misc('1998'); @inargs = ( - { name => 'brush_callback', type => 'string', non_empty => 1, - desc => 'The name of the callback registered for this pop-up' }, - { name => 'brush_name', type => 'string', - desc => 'The name of the brush to set as selected' }, - { name => 'opacity', type => '0 <= float <= 100', - desc => 'The initial opacity of the brush' }, - { name => 'spacing', type => 'int32 <= 1000', - desc => 'The initial spacing of the brush (if < 0 then use brush - default spacing)' }, - { name => 'paint_mode', type => 'enum GimpLayerMode', - default => 'GIMP_LAYER_MODE_NORMAL', - desc => 'The initial paint mode' } + { name => 'brush_callback', type => 'string', non_empty => 1, + desc => 'The name of the callback registered for this pop-up' }, + { name => 'brush_name', type => 'string', + desc => 'The name of the brush to set as selected' } ); %invoke = ( code => <<'CODE' { - if (paint_mode == GIMP_LAYER_MODE_OVERLAY_LEGACY) - paint_mode = GIMP_LAYER_MODE_SOFTLIGHT_LEGACY; - if (gimp->no_interface || ! gimp_pdb_lookup_procedure (gimp->pdb, brush_callback) || ! gimp_pdb_dialog_set (gimp, gimp_data_factory_get_container (gimp->brush_factory), brush_callback, brush_name, - "opacity", opacity / 100.0, - "paint-mode", paint_mode, - "spacing", spacing, NULL)) success = FALSE; } @@ -138,7 +109,7 @@ CODE $desc = 'Brush UI'; $doc_title = 'gimpbrushselect'; -$doc_short_desc = 'Functions providing a brush selection dialog.'; -$doc_long_desc = 'Functions providing a brush selection dialog.'; +$doc_short_desc = 'Methods of a font chooser dialog'; +$doc_long_desc = 'A dialog letting a user choose a brush. Read more at gimpfontselect.'; 1; diff --git a/pdb/groups/font_select.pdb b/pdb/groups/font_select.pdb index 29cf362187..8f680d2d22 100644 --- a/pdb/groups/font_select.pdb +++ b/pdb/groups/font_select.pdb @@ -16,19 +16,20 @@ # "Perlized" from C source by Manish Singh + sub fonts_popup { - $blurb = 'Invokes the Gimp font selection.'; - $help = 'This procedure opens the font selection dialog.'; + $blurb = 'Invokes the Gimp font selection dialog.'; + $help = 'Opens a dialog letting a user choose a font.'; &neo_pdb_misc('2003'); @inargs = ( - { name => 'font_callback', type => 'string', non_empty => 1, - desc => 'The callback PDB proc to call when font selection is made' }, - { name => 'popup_title', type => 'string', - desc => 'Title of the font selection dialog' }, - { name => 'initial_font', type => 'string', null_ok => 1, - desc => 'The name of the font to set as the first selected' } + { name => 'font_callback', type => 'string', non_empty => 1, + desc => 'The callback PDB proc to call when user chooses a font' }, + { name => 'popup_title', type => 'string', + desc => 'Title of the font selection dialog' }, + { name => 'initial_font_name', type => 'string', null_ok => 1, + desc => 'The name of the initial font choice.' } ); %invoke = ( @@ -39,7 +40,7 @@ sub fonts_popup { ! gimp_data_factory_data_wait (gimp->font_factory) || ! gimp_pdb_dialog_new (gimp, context, progress, gimp_data_factory_get_container (gimp->font_factory), - popup_title, font_callback, initial_font, + popup_title, font_callback, initial_font_name, NULL)) success = FALSE; } @@ -49,13 +50,13 @@ CODE sub fonts_close_popup { $blurb = 'Close the font selection dialog.'; - $help = 'This procedure closes an opened font selection dialog.'; + $help = 'Closes an open font selection dialog.'; &neo_pdb_misc('2003'); @inargs = ( - { name => 'font_callback', type => 'string', non_empty => 1, - desc => 'The name of the callback registered for this pop-up' } + { name => 'font_callback', type => 'string', non_empty => 1, + desc => 'The name of the callback registered in the PDB for this dialog' } ); %invoke = ( @@ -65,7 +66,7 @@ sub fonts_close_popup { ! gimp_pdb_lookup_procedure (gimp->pdb, font_callback) || ! gimp_pdb_dialog_close (gimp, gimp_data_factory_get_container (gimp->font_factory), - font_callback)) + font_callback)) success = FALSE; } CODE @@ -79,10 +80,10 @@ sub fonts_set_popup { &neo_pdb_misc('2003'); @inargs = ( - { name => 'font_callback', type => 'string', non_empty => 1, - desc => 'The name of the callback registered for this pop-up' }, - { name => 'font_name', type => 'string', - desc => 'The name of the font to set as selected' } + { name => 'font_callback', type => 'string', non_empty => 1, + desc => 'The name of the callback registered in the PDB for the dialog.' }, + { name => 'font_name', type => 'string', + desc => 'The name of the font to set as selected' } ); %invoke = ( @@ -93,7 +94,7 @@ sub fonts_set_popup { ! gimp_data_factory_data_wait (gimp->font_factory) || ! gimp_pdb_dialog_set (gimp, gimp_data_factory_get_container (gimp->font_factory), - font_callback, font_name, + font_callback, font_name, NULL)) success = FALSE; } @@ -113,7 +114,18 @@ CODE $desc = 'Font UI'; $doc_title = 'gimpfontselect'; -$doc_short_desc = 'Functions providing a font selection dialog.'; -$doc_long_desc = 'Functions providing a font selection dialog.'; +$doc_short_desc = 'Methods of a font chooser dialog.'; +$doc_long_desc = <<'LONG_DESC'; +A font chooser dialog shows installed fonts. +The dialog is non-modal with its owning dialog, +which is usually a plugin procedure's dialog. +When a user selects a font, +the dialog calls back but the dialog remains open. +The chosen font is only a choice for the owning widget +and does not select the font for the context. +The user can close but not cancel the dialog. +The owning dialog can close the font chooser dialog +when the user closes or cancels the owning dialog. +LONG_DESC 1; diff --git a/pdb/groups/gradient_select.pdb b/pdb/groups/gradient_select.pdb index a4f2ab153f..80aade519d 100644 --- a/pdb/groups/gradient_select.pdb +++ b/pdb/groups/gradient_select.pdb @@ -16,36 +16,36 @@ # "Perlized" from C source by Manish Singh + sub gradients_popup { - $blurb = 'Invokes the Gimp gradients selection.'; - $help = 'This procedure opens the gradient selection dialog.'; + $blurb = 'Invokes the Gimp gradients selection dialog.'; + $help = 'Opens a dialog letting a user choose a gradient.'; &andy_pdb_misc('1998'); @inargs = ( - { name => 'gradient_callback', type => 'string', non_empty => 1, - desc => 'The callback PDB proc to call when gradient selection is - made' }, - { name => 'popup_title', type => 'string', - desc => 'Title of the gradient selection dialog' }, - { name => 'initial_gradient', type => 'string', null_ok => 1, - desc => 'The name of the gradient to set as the first selected' }, - { name => 'sample_size', type => '1 <= int32 <= 10000', no_validate => 1, - desc => 'Size of the sample to return when the gradient is changed' } - ); + { name => 'gradient_callback', type => 'string', non_empty => 1, + desc => 'The callback PDB proc to call when user chooses a gradient' }, + { name => 'popup_title', type => 'string', + desc => 'Title of the gradient selection dialog' }, + { name => 'initial_gradient_name', type => 'string', null_ok => 1, + desc => 'The name of the initial gradient choice' } + ); %invoke = ( code => <<'CODE' { - if (sample_size < 1 || sample_size > 10000) - sample_size = GIMP_GRADIENT_DEFAULT_SAMPLE_SIZE; + /* Formerly, this procedure had another parameter: + * the sample size of the gradient's data passed in the changed callback. + * Now the sample size is determined by core, and in the future, + * the callback won't return a sample of the data at all. + */ if (gimp->no_interface || ! gimp_pdb_lookup_procedure (gimp->pdb, gradient_callback) || ! gimp_pdb_dialog_new (gimp, context, progress, gimp_data_factory_get_container (gimp->gradient_factory), - popup_title, gradient_callback, initial_gradient, - "sample-size", sample_size, + popup_title, gradient_callback, initial_gradient_name, NULL)) success = FALSE; } @@ -55,13 +55,13 @@ CODE sub gradients_close_popup { $blurb = 'Close the gradient selection dialog.'; - $help = 'This procedure closes an opened gradient selection dialog.'; + $help = 'Closes an open gradient selection dialog.'; &andy_pdb_misc('1998'); @inargs = ( - { name => 'gradient_callback', type => 'string', non_empty => 1, - desc => 'The name of the callback registered for this pop-up' } + { name => 'gradient_callback', type => 'string', non_empty => 1, + desc => 'The name of the callback registered for this pop-up' } ); %invoke = ( @@ -84,10 +84,10 @@ sub gradients_set_popup { &andy_pdb_misc('1998'); @inargs = ( - { name => 'gradient_callback', type => 'string', non_empty => 1, - desc => 'The name of the callback registered for this pop-up' }, - { name => 'gradient_name', type => 'string', - desc => 'The name of the gradient to set as selected' } + { name => 'gradient_callback', type => 'string', non_empty => 1, + desc => 'The name of the callback registered for this pop-up' }, + { name => 'gradient_name', type => 'string', + desc => 'The name of the gradient to set as selected' } ); %invoke = ( @@ -117,7 +117,7 @@ CODE $desc = 'Gradient UI'; $doc_title = 'gimpgradientselect'; -$doc_short_desc = 'Functions providing a gradient selection dialog.'; -$doc_long_desc = 'Functions providing a gradient selection dialog.'; +$doc_short_desc = 'Methods of a gradient chooser dialog'; +$doc_long_desc = 'A dialog letting a user choose a gradient. Read more at gimpfontselect.'; 1; diff --git a/pdb/groups/palette_select.pdb b/pdb/groups/palette_select.pdb index b55d0a06ca..5394df853b 100644 --- a/pdb/groups/palette_select.pdb +++ b/pdb/groups/palette_select.pdb @@ -17,19 +17,18 @@ # "Perlized" from C source by Manish Singh sub palettes_popup { - $blurb = 'Invokes the Gimp palette selection.'; - $help = 'This procedure opens the palette selection dialog.'; + $blurb = 'Invokes the Gimp palette selection dialog.'; + $help = 'Opens a dialog letting a user choose a palette.'; &mitch_pdb_misc('2002'); @inargs = ( - { name => 'palette_callback', type => 'string', non_empty => 1, - desc => 'The callback PDB proc to call when palette selection is - made' }, - { name => 'popup_title', type => 'string', - desc => 'Title of the palette selection dialog' }, - { name => 'initial_palette', type => 'string', null_ok => 1, - desc => 'The name of the palette to set as the first selected' } + { name => 'palette_callback', type => 'string', non_empty => 1, + desc => 'The callback PDB proc to call when user chooses a palette' }, + { name => 'popup_title', type => 'string', + desc => 'Title of the palette selection dialog' }, + { name => 'initial_palette_name', type => 'string', null_ok => 1, + desc => 'The palette to set as the initial choice.' } ); %invoke = ( @@ -39,7 +38,7 @@ sub palettes_popup { ! gimp_pdb_lookup_procedure (gimp->pdb, palette_callback) || ! gimp_pdb_dialog_new (gimp, context, progress, gimp_data_factory_get_container (gimp->palette_factory), - popup_title, palette_callback, initial_palette, + popup_title, palette_callback, initial_palette_name, NULL)) success = FALSE; } @@ -49,13 +48,13 @@ CODE sub palettes_close_popup { $blurb = 'Close the palette selection dialog.'; - $help = 'This procedure closes an opened palette selection dialog.'; + $help = 'Closes an open palette selection dialog.'; &mitch_pdb_misc('2002'); @inargs = ( - { name => 'palette_callback', type => 'string', non_empty => 1, - desc => 'The name of the callback registered for this pop-up' } + { name => 'palette_callback', type => 'string', non_empty => 1, + desc => 'The name of the callback registered for this pop-up' } ); %invoke = ( @@ -78,10 +77,10 @@ sub palettes_set_popup { &mitch_pdb_misc('2002'); @inargs = ( - { name => 'palette_callback', type => 'string', non_empty => 1, - desc => 'The name of the callback registered for this pop-up' }, - { name => 'palette_name', type => 'string', - desc => 'The name of the palette to set as selected' }, + { name => 'palette_callback', type => 'string', non_empty => 1, + desc => 'The name of the callback registered for this pop-up' }, + { name => 'palette_name', type => 'string', + desc => 'The name of the palette to set as selected' }, ); %invoke = ( @@ -110,7 +109,7 @@ CODE $desc = 'Palette UI'; $doc_title = 'gimppaletteselect'; -$doc_short_desc = 'Functions providing a palette selection dialog.'; -$doc_long_desc = 'Functions providing a palette selection dialog.'; +$doc_short_desc = 'Methods of a palette chooser dialog'; +$doc_long_desc = 'A dialog letting a user choose a palette. Read more at gimpfontselect.'; 1; diff --git a/pdb/groups/pattern_select.pdb b/pdb/groups/pattern_select.pdb index 02e54c284e..8c334f9947 100644 --- a/pdb/groups/pattern_select.pdb +++ b/pdb/groups/pattern_select.pdb @@ -18,18 +18,17 @@ sub patterns_popup { $blurb = 'Invokes the Gimp pattern selection.'; - $help = 'This procedure opens the pattern selection dialog.'; + $help = 'Opens the pattern selection dialog.'; &andy_pdb_misc('1998'); @inargs = ( - { name => 'pattern_callback', type => 'string', non_empty => 1, - desc => 'The callback PDB proc to call when pattern selection is - made' }, - { name => 'popup_title', type => 'string', - desc => 'Title of the pattern selection dialog' }, - { name => 'initial_pattern', type => 'string', null_ok => 1, - desc => 'The name of the pattern to set as the first selected' } + { name => 'pattern_callback', type => 'string', non_empty => 1, + desc => 'The callback PDB proc to call when the user chooses a pattern' }, + { name => 'popup_title', type => 'string', + desc => 'Title of the pattern selection dialog' }, + { name => 'initial_pattern_name', type => 'string', null_ok => 1, + desc => 'The name of the pattern to set as the initial choice' } ); %invoke = ( @@ -39,7 +38,7 @@ sub patterns_popup { ! gimp_pdb_lookup_procedure (gimp->pdb, pattern_callback) || ! gimp_pdb_dialog_new (gimp, context, progress, gimp_data_factory_get_container (gimp->pattern_factory), - popup_title, pattern_callback, initial_pattern, + popup_title, pattern_callback, initial_pattern_name, NULL)) success = FALSE; } @@ -49,13 +48,13 @@ CODE sub patterns_close_popup { $blurb = 'Close the pattern selection dialog.'; - $help = 'This procedure closes an opened pattern selection dialog.'; + $help = 'Closes an open pattern selection dialog.'; &andy_pdb_misc('1998'); @inargs = ( - { name => 'pattern_callback', type => 'string', non_empty => 1, - desc => 'The name of the callback registered for this pop-up' } + { name => 'pattern_callback', type => 'string', non_empty => 1, + desc => 'The name of the callback registered for this pop-up' } ); %invoke = ( @@ -78,10 +77,10 @@ sub patterns_set_popup { &andy_pdb_misc('1998'); @inargs = ( - { name => 'pattern_callback', type => 'string', non_empty => 1, - desc => 'The name of the callback registered for this pop-up' }, - { name => 'pattern_name', type => 'string', - desc => 'The name of the pattern to set as selected' } + { name => 'pattern_callback', type => 'string', non_empty => 1, + desc => 'The name of the callback registered for this pop-up' }, + { name => 'pattern_name', type => 'string', + desc => 'The name of the pattern to set as selected' } ); %invoke = ( @@ -110,7 +109,7 @@ CODE $desc = 'Pattern UI'; $doc_title = 'gimppatternselect'; -$doc_short_desc = 'Functions providing a pattern selection dialog.'; -$doc_long_desc = 'Functions providing a pattern selection dialog.'; +$doc_short_desc = 'Methods of a pattern chooser dialog'; +$doc_long_desc = 'A dialog letting a user choose a pattern. Read more at gimpfontselect.'; 1; diff --git a/plug-ins/Makefile.am b/plug-ins/Makefile.am index 06d5cabfeb..a8c4869c27 100644 --- a/plug-ins/Makefile.am +++ b/plug-ins/Makefile.am @@ -24,6 +24,10 @@ if HAVE_WEBP file_webp = file-webp endif +# lkk temporarily not making these plugins until next commit fixes them for Resource +# gfig +# pagecurl + SUBDIRS = \ script-fu \ file-bmp \ @@ -43,7 +47,6 @@ SUBDIRS = \ $(file_webp) \ flame \ fractal-explorer \ - gfig \ gimpressionist \ gradient-flare \ help \ @@ -53,7 +56,6 @@ SUBDIRS = \ lighting \ map-object \ metadata \ - pagecurl \ $(print) \ $(python) \ screenshot \ diff --git a/plug-ins/gfig/gfig-dialog.c b/plug-ins/gfig/gfig-dialog.c index 23209b0fbd..a856b13a7f 100644 --- a/plug-ins/gfig/gfig-dialog.c +++ b/plug-ins/gfig/gfig-dialog.c @@ -394,8 +394,7 @@ gfig_dialog (void) /* brush selector in Stroke frame */ gfig_context->brush_select = gimp_brush_select_button_new ("Brush", - gfig_context->default_style.brush_name, - -1.0, -1, -1); + gfig_context->default_style.brush); g_signal_connect (gfig_context->brush_select, "brush-set", G_CALLBACK (gfig_brush_changed_callback), NULL); gtk_box_pack_start (GTK_BOX (vbox), gfig_context->brush_select, diff --git a/plug-ins/gfig/gfig-style.c b/plug-ins/gfig/gfig-style.c index a215ac3703..fc018b2a03 100644 --- a/plug-ins/gfig/gfig-style.c +++ b/plug-ins/gfig/gfig-style.c @@ -255,9 +255,9 @@ gfig_load_style (Style *style, } gfig_read_parameter_string (style_text, nitems, "BrushName", - &style->brush_name); + &style->brush); - if (style->brush_name == NULL) + if (style->brush == NULL) g_message ("Error loading style: got NULL for brush name."); gfig_read_parameter_string (style_text, nitems, "Pattern", &style->pattern); @@ -353,11 +353,11 @@ gfig_save_style (Style *style, gint blen = G_ASCII_DTOSTR_BUF_SIZE; if (gfig_context->debug_styles) - g_printerr ("Saving style %s, brush name '%s'\n", style->name, style->brush_name); + g_printerr ("Saving style %s, brush name '%s'\n", style->name, style->brush); g_string_append_printf (string, "