[gimp] libgimp: improvements to GimpProcedureDialog API.
- From: Jehan <jehanp src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gimp] libgimp: improvements to GimpProcedureDialog API.
- Date: Tue, 24 Nov 2020 20:42:16 +0000 (UTC)
commit 3fb2ff1b9d1380be35e68861cdb1dc2ac70c5723
Author: Jehan <jehan girinstud io>
Date: Tue Nov 24 15:00:34 2020 +0100
libgimp: improvements to GimpProcedureDialog API.
- New gimp_procedure_dialog_fill_box(_list)() functions to create a
GtkBox in the layout.
- Generating widgets for parameters of type double (and computing
appropriate "ok defaults" digits for these, depending on the min-max
range of the property).
libgimp/gimpproceduredialog.c | 337 +++++++++++++++++++++++++++++++-----------
libgimp/gimpproceduredialog.h | 7 +
libgimp/gimpui.def | 2 +
3 files changed, 259 insertions(+), 87 deletions(-)
---
diff --git a/libgimp/gimpproceduredialog.c b/libgimp/gimpproceduredialog.c
index 47e292482c..21202e50ba 100644
--- a/libgimp/gimpproceduredialog.c
+++ b/libgimp/gimpproceduredialog.c
@@ -88,12 +88,18 @@ static void gimp_procedure_dialog_save_defaults (GtkWidget *button,
static void gimp_procedure_dialog_estimate_increments (gdouble lower,
gdouble upper,
gdouble *step,
- gdouble *page);
+ gdouble *page,
+ gint *digits);
static gboolean gimp_procedure_dialog_check_mnemonic (GimpProcedureDialog *dialog,
GtkWidget *widget,
const gchar *id,
const gchar *core_id);
+static GtkWidget *
+ gimp_procedure_dialog_fill_container_list (GimpProcedureDialog *dialog,
+ const gchar *container_id,
+ GtkContainer *container,
+ GList *properties);
G_DEFINE_TYPE_WITH_PRIVATE (GimpProcedureDialog, gimp_procedure_dialog,
GIMP_TYPE_DIALOG)
@@ -427,32 +433,48 @@ gimp_procedure_dialog_get_widget (GimpProcedureDialog *dialog,
_(g_param_spec_get_nick (pspec)),
&label, NULL);
}
- else if (G_PARAM_SPEC_TYPE (pspec) == G_TYPE_PARAM_INT)
+ else if (G_PARAM_SPEC_TYPE (pspec) == G_TYPE_PARAM_INT ||
+ G_PARAM_SPEC_TYPE (pspec) == G_TYPE_PARAM_DOUBLE)
{
+ gdouble minimum;
+ gdouble maximum;
+ gdouble step = 0.0;
+ gdouble page = 0.0;
+ gint digits = 0;
+
+ if (G_PARAM_SPEC_TYPE (pspec) == G_TYPE_PARAM_INT)
+ {
+ GParamSpecInt *pspecint = (GParamSpecInt *) pspec;
+
+ minimum = (gdouble) pspecint->minimum;
+ maximum = (gdouble) pspecint->maximum;
+ }
+ else /* G_TYPE_PARAM_DOUBLE */
+ {
+ GParamSpecDouble *pspecdouble = (GParamSpecDouble *) pspec;
+
+ minimum = pspecdouble->minimum;
+ maximum = pspecdouble->maximum;
+ }
+ gimp_procedure_dialog_estimate_increments (minimum, maximum, &step, &page, &digits);
+
if (widget_type == G_TYPE_NONE || widget_type == GIMP_TYPE_LABEL_SPIN)
{
widget = gimp_prop_label_spin_new (G_OBJECT (dialog->priv->config),
- property, 0);
+ property, digits);
}
else if (widget_type == GIMP_TYPE_SCALE_ENTRY)
{
widget = gimp_prop_scale_entry_new (G_OBJECT (dialog->priv->config),
property,
_(g_param_spec_get_nick (pspec)),
- 0, FALSE, 0.0, 0.0);
+ digits, FALSE, 0.0, 0.0);
}
else if (widget_type == GIMP_TYPE_SPIN_BUTTON)
{
/* Just some spin button without label. */
- GParamSpecInt *pspecint = (GParamSpecInt *) pspec;
- gdouble step = 0.0;
- gdouble page = 0.0;
-
- gimp_procedure_dialog_estimate_increments (pspecint->minimum,
- pspecint->maximum,
- &step, &page);
widget = gimp_prop_spin_button_new (G_OBJECT (dialog->priv->config),
- property, step, page, 0);
+ property, step, page, digits);
}
}
else if (G_PARAM_SPEC_TYPE (pspec) == G_TYPE_PARAM_STRING)
@@ -755,6 +777,98 @@ gimp_procedure_dialog_fill_list (GimpProcedureDialog *dialog,
g_list_free (properties);
}
+/**
+ * gimp_procedure_dialog_fill_box:
+ * @dialog: the #GimpProcedureDialog.
+ * @container_id: a container identifier.
+ * @first_property: the first property name.
+ * @...: a %NULL-terminated list of other property names.
+ *
+ * Creates and populates a new #GtkBox with widgets corresponding to
+ * every listed properties. If the list is empty, the created box will
+ * be filled by the whole list of properties of the associated
+ * #GimpProcedure, in the defined order. This is similar of how
+ * gimp_procedure_dialog_fill() works except that it creates a new
+ * widget which is not inside @dialog itself.
+ *
+ * The @container_id must be a unique ID which is neither the name of a
+ * property of the #GimpProcedureConfig associated to @dialog, nor is it
+ * the ID of any previously created container. This ID can later be used
+ * together with property names to be packed in other containers or
+ * inside @dialog itself.
+ *
+ * Returns: (transfer none): the #GtkBox representing @property. The
+ * object belongs to @dialog and must not be
+ * freed.
+ */
+GtkWidget *
+gimp_procedure_dialog_fill_box (GimpProcedureDialog *dialog,
+ const gchar *container_id,
+ const gchar *first_property,
+ ...)
+{
+ const gchar *prop_name = first_property;
+ GtkWidget *box;
+ GList *list = NULL;
+ va_list va_args;
+
+ g_return_val_if_fail (GIMP_IS_PROCEDURE_DIALOG (dialog), NULL);
+ g_return_val_if_fail (container_id != NULL, NULL);
+
+ if (first_property)
+ {
+ va_start (va_args, first_property);
+
+ do
+ list = g_list_prepend (list, (gpointer) prop_name);
+ while ((prop_name = va_arg (va_args, const gchar *)));
+
+ va_end (va_args);
+ }
+
+ list = g_list_reverse (list);
+ box = gimp_procedure_dialog_fill_box_list (dialog, container_id, list);
+ if (list)
+ g_list_free (list);
+
+ return box;
+}
+
+/**
+ * gimp_procedure_dialog_fill_box_list: (rename-to gimp_procedure_dialog_fill_box)
+ * @dialog: the #GimpProcedureDialog.
+ * @container_id: a container identifier.
+ * @properties: (nullable) (element-type gchar*): the list of property names.
+ *
+ * Creates and populates a new #GtkBox with widgets corresponding to
+ * every listed @properties. If the list is empty, the created box will
+ * be filled by the whole list of properties of the associated
+ * #GimpProcedure, in the defined order. This is similar of how
+ * gimp_procedure_dialog_fill() works except that it creates a new
+ * widget which is not inside @dialog itself.
+ *
+ * The @container_id must be a unique ID which is neither the name of a
+ * property of the #GimpProcedureConfig associated to @dialog, nor is it
+ * the ID of any previously created container. This ID can later be used
+ * together with property names to be packed in other containers or
+ * inside @dialog itself.
+ *
+ * Returns: (transfer none): the #GtkBox representing @property. The
+ * object belongs to @dialog and must not be
+ * freed.
+ */
+GtkWidget *
+gimp_procedure_dialog_fill_box_list (GimpProcedureDialog *dialog,
+ const gchar *container_id,
+ GList *properties)
+{
+ g_return_val_if_fail (container_id != NULL, NULL);
+
+ return gimp_procedure_dialog_fill_container_list (dialog, container_id,
+ GTK_CONTAINER (gtk_box_new (GTK_ORIENTATION_VERTICAL,
2)),
+ properties);
+}
+
/**
* gimp_procedure_dialog_fill_flowbox:
* @dialog: the #GimpProcedureDialog.
@@ -840,80 +954,11 @@ gimp_procedure_dialog_fill_flowbox_list (GimpProcedureDialog *dialog,
const gchar *container_id,
GList *properties)
{
- GtkWidget *flowbox;
- GList *iter;
- gboolean free_properties = FALSE;
-
g_return_val_if_fail (container_id != NULL, NULL);
- if (g_object_class_find_property (G_OBJECT_GET_CLASS (dialog->priv->config),
- container_id))
- {
- g_warning ("%s: container identifier '%s' cannot be an existing property name.",
- G_STRFUNC, container_id);
- return NULL;
- }
-
- if ((flowbox = g_hash_table_lookup (dialog->priv->widgets, container_id)))
- {
- g_warning ("%s: container identifier '%s' was already configured.",
- G_STRFUNC, container_id);
- return flowbox;
- }
-
- flowbox = gtk_flow_box_new ();
-
- if (! properties)
- {
- GParamSpec **pspecs;
- guint n_pspecs;
- gint i;
-
- pspecs = g_object_class_list_properties (G_OBJECT_GET_CLASS (dialog->priv->config),
- &n_pspecs);
-
- for (i = 0; i < n_pspecs; i++)
- {
- const gchar *prop_name;
- GParamSpec *pspec = pspecs[i];
-
- /* skip our own properties */
- if (pspec->owner_type == GIMP_TYPE_PROCEDURE_CONFIG)
- continue;
-
- prop_name = g_param_spec_get_name (pspec);
- properties = g_list_prepend (properties, (gpointer) prop_name);
- }
-
- properties = g_list_reverse (properties);
-
- if (properties)
- free_properties = TRUE;
- }
-
- for (iter = properties; iter; iter = iter->next)
- {
- GtkWidget *widget;
-
- widget = gimp_procedure_dialog_get_widget (dialog, iter->data, G_TYPE_NONE);
- if (widget)
- {
- /* Reference the widget because the hash table will
- * unreference it anyway when getting destroyed so we don't
- * want to give the only reference to the parent widget.
- */
- g_object_ref (widget);
- gtk_container_add (GTK_CONTAINER (flowbox), widget);
- gtk_widget_show (widget);
- }
- }
-
- if (free_properties)
- g_list_free (properties);
-
- g_hash_table_insert (dialog->priv->widgets, g_strdup (container_id), flowbox);
-
- return flowbox;
+ return gimp_procedure_dialog_fill_container_list (dialog, container_id,
+ GTK_CONTAINER (gtk_flow_box_new ()),
+ properties);
}
@@ -1157,12 +1202,13 @@ static void
gimp_procedure_dialog_estimate_increments (gdouble lower,
gdouble upper,
gdouble *step,
- gdouble *page)
+ gdouble *page,
+ gint *digits)
{
gdouble range;
g_return_if_fail (upper >= lower);
- g_return_if_fail (step || page);
+ g_return_if_fail (step || page || digits);
range = upper - lower;
@@ -1170,6 +1216,9 @@ gimp_procedure_dialog_estimate_increments (gdouble lower,
{
gdouble places = 10.0;
+ if (digits)
+ *digits = 3;
+
/* Compute some acceptable step and page increments always in the
* format `10**-X` where X is the rounded precision.
* So for instance:
@@ -1178,7 +1227,11 @@ gimp_procedure_dialog_estimate_increments (gdouble lower,
* 0.06 will also have increments 0.001 and 0.01.
*/
while (range * places < 5.0)
- places *= 10.0;
+ {
+ places *= 10.0;
+ if (digits)
+ (*digits)++;
+ }
if (step)
@@ -1192,6 +1245,9 @@ gimp_procedure_dialog_estimate_increments (gdouble lower,
*step = 0.01;
if (page)
*page = 0.1;
+
+ if (digits)
+ *digits = 3;
}
else if (range <= 5.0)
{
@@ -1199,6 +1255,8 @@ gimp_procedure_dialog_estimate_increments (gdouble lower,
*step = 0.1;
if (page)
*page = 1.0;
+ if (digits)
+ *digits = 2;
}
else if (range <= 40.0)
{
@@ -1206,6 +1264,8 @@ gimp_procedure_dialog_estimate_increments (gdouble lower,
*step = 1.0;
if (page)
*page = 2.0;
+ if (digits)
+ *digits = 2;
}
else
{
@@ -1213,6 +1273,8 @@ gimp_procedure_dialog_estimate_increments (gdouble lower,
*step = 1.0;
if (page)
*page = 10.0;
+ if (digits)
+ *digits = 1;
}
}
@@ -1285,3 +1347,104 @@ gimp_procedure_dialog_check_mnemonic (GimpProcedureDialog *dialog,
return success;
}
+
+/**
+ * gimp_procedure_dialog_fill_container_list:
+ * @dialog:
+ * @container_id:
+ * @container: (transfer full):
+ * @properties:
+ *
+ * A generic function to be used by various publich functions
+ * gimp_procedure_dialog_fill_*_list(). Note in particular that
+ * @container is taken over by this function which may return it or not.
+ * @container is assumed to be a floating GtkContainer (i.e. newly
+ * created widget without a parent yet).
+ * If the object returns a different object (because @container_id
+ * already represents another widget) or %NULL, the function takes care
+ * of freeing @container. Calling code must therefore not reuse the
+ * pointer anymore.
+ */
+static GtkWidget *
+gimp_procedure_dialog_fill_container_list (GimpProcedureDialog *dialog,
+ const gchar *container_id,
+ GtkContainer *container,
+ GList *properties)
+{
+ GList *iter;
+ gboolean free_properties = FALSE;
+
+ g_return_val_if_fail (container_id != NULL, NULL);
+ g_return_val_if_fail (GTK_IS_CONTAINER (container), NULL);
+ g_return_val_if_fail (g_object_is_floating (G_OBJECT (container)), NULL);
+
+ g_object_ref_sink (container);
+ if (g_object_class_find_property (G_OBJECT_GET_CLASS (dialog->priv->config),
+ container_id))
+ {
+ g_warning ("%s: container identifier '%s' cannot be an existing property name.",
+ G_STRFUNC, container_id);
+ g_object_unref (container);
+ return NULL;
+ }
+
+ if (g_hash_table_lookup (dialog->priv->widgets, container_id))
+ {
+ g_warning ("%s: container identifier '%s' was already configured.",
+ G_STRFUNC, container_id);
+ g_object_unref (container);
+ return g_hash_table_lookup (dialog->priv->widgets, container_id);
+ }
+
+ if (! properties)
+ {
+ GParamSpec **pspecs;
+ guint n_pspecs;
+ gint i;
+
+ pspecs = g_object_class_list_properties (G_OBJECT_GET_CLASS (dialog->priv->config),
+ &n_pspecs);
+
+ for (i = 0; i < n_pspecs; i++)
+ {
+ const gchar *prop_name;
+ GParamSpec *pspec = pspecs[i];
+
+ /* skip our own properties */
+ if (pspec->owner_type == GIMP_TYPE_PROCEDURE_CONFIG)
+ continue;
+
+ prop_name = g_param_spec_get_name (pspec);
+ properties = g_list_prepend (properties, (gpointer) prop_name);
+ }
+
+ properties = g_list_reverse (properties);
+
+ if (properties)
+ free_properties = TRUE;
+ }
+
+ for (iter = properties; iter; iter = iter->next)
+ {
+ GtkWidget *widget;
+
+ widget = gimp_procedure_dialog_get_widget (dialog, iter->data, G_TYPE_NONE);
+ if (widget)
+ {
+ /* Reference the widget because the hash table will
+ * unreference it anyway when getting destroyed so we don't
+ * want to give the only reference to the parent widget.
+ */
+ g_object_ref (widget);
+ gtk_container_add (container, widget);
+ gtk_widget_show (widget);
+ }
+ }
+
+ if (free_properties)
+ g_list_free (properties);
+
+ g_hash_table_insert (dialog->priv->widgets, g_strdup (container_id), container);
+
+ return GTK_WIDGET (container);
+}
diff --git a/libgimp/gimpproceduredialog.h b/libgimp/gimpproceduredialog.h
index 8825f93d7c..d8d321f357 100644
--- a/libgimp/gimpproceduredialog.h
+++ b/libgimp/gimpproceduredialog.h
@@ -85,6 +85,13 @@ GtkWidget * gimp_procedure_dialog_get_label (GimpProcedureDialog *dialog
const gchar *label_id,
const gchar *text);
+GtkWidget * gimp_procedure_dialog_fill_box (GimpProcedureDialog *dialog,
+ const gchar *container_id,
+ const gchar *first_property,
+ ...);
+GtkWidget * gimp_procedure_dialog_fill_box_list (GimpProcedureDialog *dialog,
+ const gchar *container_id,
+ GList *properties);
GtkWidget * gimp_procedure_dialog_fill_flowbox (GimpProcedureDialog *dialog,
const gchar *container_id,
const gchar *first_property,
diff --git a/libgimp/gimpui.def b/libgimp/gimpui.def
index e61530fc74..2477e8e26b 100644
--- a/libgimp/gimpui.def
+++ b/libgimp/gimpui.def
@@ -40,6 +40,8 @@ EXPORTS
gimp_proc_browser_dialog_new
gimp_proc_view_new
gimp_procedure_dialog_fill
+ gimp_procedure_dialog_fill_box
+ gimp_procedure_dialog_fill_box_list
gimp_procedure_dialog_fill_flowbox
gimp_procedure_dialog_fill_flowbox_list
gimp_procedure_dialog_fill_frame
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]