/* LIBPIKA - The PIKA Library * Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball * * pikapropwidgets.c * Copyright (C) 2023 Jehan * * 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 * . */ #include "config.h" #include "libpika/pikaui.h" #include "libpika-intl.h" /* * This is a complement of libpikawidgets/pikapropwidgets.c * These are property functions for types from libpika, such as * [class@Gimp.Resource] or [class@Gimp.Item] subclasses. */ typedef GtkWidget* (*PikaResourceWidgetCreator) (const gchar *title, const gchar *label, PikaResource *initial_resource); /* utility function prototypes */ static GtkWidget * pika_prop_resource_chooser_factory (PikaResourceWidgetCreator widget_creator_func, GObject *config, const gchar *property_name, const gchar *chooser_title); static gchar * pika_utils_make_canonical_menu_label (const gchar *path); /** * pika_prop_brush_chooser_new: * @config: Object to which property is attached. * @property_name: Name of a [class@Gimp.Brush] property. * @chooser_title: (nullable): title for the poppable dialog. * * Creates a [class@Gimp.Brush.Chooser] controlled by the specified property. * * Returns: (transfer full): A new [class@GimpUi.BrushChooser]. * * Since: 3.0 */ GtkWidget * pika_prop_brush_chooser_new (GObject *config, const gchar *property_name, const gchar *chooser_title) { return pika_prop_resource_chooser_factory (pika_brush_chooser_new, config, property_name, chooser_title); } /** * pika_prop_font_chooser_new: * @config: Object to which property is attached. * @property_name: Name of a [class@Gimp.Font] property. * @chooser_title: (nullable): title for the poppable dialog. * * Creates a [class@GimpUi.FontChooser] controlled by the specified property. * * Returns: (transfer full): A new [class@GimpUi.FontChooser]. * * Since: 3.0 */ GtkWidget * pika_prop_font_chooser_new (GObject *config, const gchar *property_name, const gchar *chooser_title) { return pika_prop_resource_chooser_factory (pika_font_chooser_new, config, property_name, chooser_title); } /** * pika_prop_gradient_chooser_new: * @config: Object to which property is attached. * @property_name: Name of a [class@Gimp.Gradient] property. * @chooser_title: (nullable): title for the poppable dialog. * * Creates a [class@GimpUi.GradientChooser] controlled by the specified property. * * Returns: (transfer full): A new [class@GimpUi.GradientChooser]. * * Since: 3.0 */ GtkWidget * pika_prop_gradient_chooser_new (GObject *config, const gchar *property_name, const gchar *chooser_title) { return pika_prop_resource_chooser_factory (pika_gradient_chooser_new, config, property_name, chooser_title); } /** * pika_prop_palette_chooser_new: * @config: Object to which property is attached. * @property_name: Name of a [class@Gimp.Palette] property. * @chooser_title: (nullable): title for the poppable dialog. * * Creates a [class@GimpUi.PaletteChooser] controlled by the specified property. * * Returns: (transfer full): A new [class@GimpUi.PaletteChooser]. * * Since: 3.0 */ GtkWidget * pika_prop_palette_chooser_new (GObject *config, const gchar *property_name, const gchar *chooser_title) { return pika_prop_resource_chooser_factory (pika_palette_chooser_new, config, property_name, chooser_title); } /** * pika_prop_pattern_chooser_new: * @config: Object to which property is attached. * @property_name: Name of a [class@Gimp.Pattern] property. * @chooser_title: (nullable): title for the poppable dialog. * * Creates a [class@GimpUi.PatternChooser] controlled by the specified property. * * Returns: (transfer full): A new [class@GimpUi.PatternChooser]. * * Since: 3.0 */ GtkWidget * pika_prop_pattern_chooser_new (GObject *config, const gchar *property_name, const gchar *chooser_title) { return pika_prop_resource_chooser_factory (pika_pattern_chooser_new, config, property_name, chooser_title); } /** * pika_prop_drawable_chooser_new: * @config: Object to which property is attached. * @property_name: Name of a [class@Gimp.Drawable] property. * @chooser_title: (nullable): title for the poppable dialog. * * Creates a [class@GimpUi.DrawableChooser] controlled by the specified property. * * Returns: (transfer full): A new [class@GimpUi.DrawableChooser]. * * Since: 3.0 */ GtkWidget * pika_prop_drawable_chooser_new (GObject *config, const gchar *property_name, const gchar *chooser_title) { GParamSpec *param_spec; GtkWidget *prop_chooser; PikaDrawable *initial_drawable = NULL; gchar *title = NULL; const gchar *label; param_spec = g_object_class_find_property (G_OBJECT_GET_CLASS (config), property_name); g_return_val_if_fail (param_spec != NULL, NULL); g_return_val_if_fail (g_type_is_a (G_TYPE_FROM_INSTANCE (param_spec), G_TYPE_PARAM_OBJECT) && g_type_is_a (param_spec->value_type, PIKA_TYPE_DRAWABLE), NULL); g_object_get (config, property_name, &initial_drawable, NULL); label = g_param_spec_get_nick (param_spec); if (chooser_title == NULL) { gchar *canonical; canonical = pika_utils_make_canonical_menu_label (label); if (g_type_is_a (param_spec->value_type, PIKA_TYPE_LAYER)) title = g_strdup_printf (_("Choose layer: %s"), canonical); if (g_type_is_a (param_spec->value_type, PIKA_TYPE_CHANNEL)) title = g_strdup_printf (_("Choose channel: %s"), canonical); else title = g_strdup_printf (_("Choose drawable: %s"), canonical); g_free (canonical); } else { title = g_strdup (chooser_title); } prop_chooser = pika_drawable_chooser_new (title, label, param_spec->value_type, initial_drawable); g_clear_object (&initial_drawable); g_free (title); g_object_bind_property (prop_chooser, "drawable", config, property_name, G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE); return prop_chooser; } /*******************************/ /* private utility functions */ /*******************************/ static GtkWidget * pika_prop_resource_chooser_factory (PikaResourceWidgetCreator widget_creator_func, GObject *config, const gchar *property_name, const gchar *chooser_title) { GParamSpec *param_spec; GtkWidget *prop_chooser; PikaResource *initial_resource; const gchar *label; param_spec = g_object_class_find_property (G_OBJECT_GET_CLASS (config), property_name); g_return_val_if_fail (param_spec != NULL, NULL); g_return_val_if_fail (g_type_is_a (G_TYPE_FROM_INSTANCE (param_spec), G_TYPE_PARAM_OBJECT) && g_type_is_a (param_spec->value_type, PIKA_TYPE_RESOURCE), NULL); g_object_get (config, property_name, &initial_resource, NULL); label = g_param_spec_get_nick (param_spec); /* Create the wrapped widget. For example, call pika_font_chooser_new. * When initial_resource is NULL, the widget creator will set it's resource * property from context. */ prop_chooser = widget_creator_func (chooser_title, label, initial_resource); g_clear_object (&initial_resource); g_object_bind_property (prop_chooser, "resource", config, property_name, G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE); return prop_chooser; } /* This is a copy of the similarly-named function in app/widgets/pikawidgets-utils.c * I hesitated to put this maybe in libpikawidgets/pikawidgetsutils.h but for * now, let's not. If it's useful to more people, it's always easier to move the * function in rather than deprecating it. */ static gchar * pika_utils_make_canonical_menu_label (const gchar *path) { gchar **split_path; gchar *canon_path; /* The first underscore of each path item is a mnemonic. */ split_path = g_strsplit (path, "_", 2); canon_path = g_strjoinv ("", split_path); g_strfreev (split_path); return canon_path; }