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, "