[gimp] libgimpwidgets: make GimpScaleEntry into its own widget.



commit 5238958e55e279a6359adaaa8dbfe4c41e796fbc
Author: Jehan <jehan girinstud io>
Date:   Fri Oct 30 00:30:03 2020 +0100

    libgimpwidgets: make GimpScaleEntry into its own widget.
    
    Instead of the gimp_scale_entry_new() which creates several bound yet
    independant widgets, and in the same time pack them into an existing
    grid and return a GtkAdjustment (while heavily relying on GObject data
    to link widgets), let's have a proper custom widget with its own clean
    API.
    This also simplifies the gimp_prop_scale_entry_new() property widget
    variant.
    
    First advantage is that we don't force the usage of a grid to use this
    widget (there are a few pieces of code which create a GtkGrid with only
    this inside just to be able to use this feature).
    
    Second thing is that I am creating a much simpler API.
    gimp_scale_entry_new() had 17 parameters! How crazy is that? So I
    removed all the grid packing related parameters. Also I moved the spin
    button/scale unconstraining parameters into their separate function,
    because the constrained behavior is the most common use case, so it's
    stupid to add 3 permanent dummy parameters for most calls. Instead the
    few times where we'll want different ranges for the spin button and the
    scale, we'll call the separate API gimp_scale_entry_set_range().
    
    Thirdly the tooltip can be set directly with gimp_help_set_help_data()
    since this is now its own widget. No need to have dedicated logics
    anymore, better stay generic. Similarly no need of a custom function to
    switch sensitivitivy (instead of generic gtk_widget_set_sensitive()).
    
    Fourth thing is that we should not use macros for the public API, but
    proper functions, because macros are not properly introspected for
    binding.
    
    For future improvements, maybe we could even make this widget implement
    GtkOrientable interface, in order to be able to use it vertically.
    
    Note: right now, I created a separate gimp_scale_entry_new2() and only
    modified the property widget API to use this new code. Eventually I will
    remove fully the old gimp_scale_entry_new() function (and the new code
    will replace it).

 libgimpwidgets/gimppropwidgets.c  | 110 +++-----
 libgimpwidgets/gimppropwidgets.h  |  10 +-
 libgimpwidgets/gimpscaleentry.c   | 530 ++++++++++++++++++++++++++++++++++++++
 libgimpwidgets/gimpscaleentry.h   |  52 ++++
 libgimpwidgets/gimpwidgetstypes.h |   1 +
 5 files changed, 625 insertions(+), 78 deletions(-)
---
diff --git a/libgimpwidgets/gimppropwidgets.c b/libgimpwidgets/gimppropwidgets.c
index 453144f041..1ff31c29a6 100644
--- a/libgimpwidgets/gimppropwidgets.c
+++ b/libgimpwidgets/gimppropwidgets.c
@@ -1462,39 +1462,32 @@ gimp_prop_hscale_new (GObject     *config,
 /**
  * gimp_prop_scale_entry_new:
  * @config:         Object to which property is attached.
- * @property_name:  Name of double property controlled by the spin button.
- * @grid:           The #GtkGrid the widgets will be attached to.
- * @column:         The column to start with.
- * @row:            The row to attach the widgets.
  * @label: (nullable): The text for the #GtkLabel which will appear left of
  *                     the #GtkHScale.
+ * @property_name:  Name of integer or double property controlled by the scale.
  * @step_increment: Step size.
  * @page_increment: Page size.
- * @digits:         Number of digits after decimal point to display.
+ * @digits:         Number of digits after decimal point to display. For
+ *                  integer properties, this will be ignored (always 0).
  * @limit_scale:    %FALSE if the range of possible values of the
  *                  GtkHScale should be the same as of the GtkSpinButton.
  * @lower_limit:    The scale's lower boundary if @scale_limits is %TRUE.
  * @upper_limit:    The scale's upper boundary if @scale_limits is %TRUE.
  *
- * Creates a #libgimpwidgets-gimpscaleentry (slider and spin button)
- * to set and display the value of the specified double property.  See
- * gimp_scale_entry_new() for more information.
+ * Creates a #GimpScaleEntry (slider and spin button) to set and display
+ * the value of a specified int or double property.
+ * See gimp_scale_entry_new() for more information.
+ *
  * If @label is %NULL, the @property_name's nick will be used as label
  * of the returned object.
  *
- * Note that the @scale_limits boolean is the inverse of
- * gimp_scale_entry_new()'s "constrain" parameter.
- *
- * Returns: (transfer full): The #GtkSpinButton's #GtkAdjustment.
+ * Returns: (transfer full): The newly allocated #GimpScaleEntry.
  *
  * Since: 2.4
  */
-GtkAdjustment *
+GtkWidget *
 gimp_prop_scale_entry_new (GObject     *config,
                            const gchar *property_name,
-                           GtkGrid     *grid,
-                           gint         column,
-                           gint         row,
                            const gchar *label,
                            gdouble      step_increment,
                            gdouble      page_increment,
@@ -1503,12 +1496,12 @@ gimp_prop_scale_entry_new (GObject     *config,
                            gdouble      lower_limit,
                            gdouble      upper_limit)
 {
-  GParamSpec    *param_spec;
-  GtkAdjustment *adjustment;
-  const gchar   *tooltip;
-  gdouble        value;
-  gdouble        lower;
-  gdouble        upper;
+  GtkWidget   *widget;
+  GParamSpec  *param_spec;
+  const gchar *tooltip;
+  gdouble      value;
+  gdouble      lower;
+  gdouble      upper;
 
   param_spec = find_param_spec (config, property_name, G_STRFUNC);
   if (! param_spec)
@@ -1518,45 +1511,30 @@ gimp_prop_scale_entry_new (GObject     *config,
                             param_spec, &value, &lower, &upper, G_STRFUNC))
     return NULL;
 
+  if (G_IS_PARAM_SPEC_INT (param_spec) || G_IS_PARAM_SPEC_UINT (param_spec))
+    digits = 0;
+
   if (! label)
     label = g_param_spec_get_nick (param_spec);
 
-  tooltip = g_param_spec_get_blurb (param_spec);
-
-  if (! limit_scale)
+  widget = gimp_scale_entry_new2 (label, value, lower, upper,
+                                  step_increment, page_increment,
+                                  digits);
+  if (limit_scale)
     {
-      adjustment = gimp_scale_entry_new (grid, column, row,
-                                         label, -1, -1,
-                                         value, lower, upper,
-                                         step_increment, page_increment,
-                                         digits,
-                                         TRUE, 0.0, 0.0,
-                                         tooltip,
-                                         NULL);
+      gimp_scale_entry_set_range (GIMP_SCALE_ENTRY (widget),
+                                  lower_limit, upper_limit,
+                                  FALSE);
     }
-  else
-    {
-      adjustment = gimp_scale_entry_new (grid, column, row,
-                                         label, -1, -1,
-                                         value, lower_limit, upper_limit,
-                                         step_increment, page_increment,
-                                         digits,
-                                         FALSE, lower, upper,
-                                         tooltip,
-                                         NULL);
-    }
-
-  set_param_spec (G_OBJECT (adjustment), NULL,  param_spec);
 
-  g_signal_connect (adjustment, "value-changed",
-                    G_CALLBACK (gimp_prop_adjustment_callback),
-                    config);
+  tooltip = g_param_spec_get_blurb (param_spec);
+  gimp_help_set_help_data (widget, tooltip, NULL);
 
-  connect_notify (config, property_name,
-                  G_CALLBACK (gimp_prop_adjustment_notify),
-                  adjustment);
+  g_object_bind_property (config, property_name,
+                          widget, "value",
+                          G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE);
 
-  return adjustment;
+  return widget;
 }
 
 static void
@@ -1620,9 +1598,6 @@ gimp_prop_widget_set_factor (GtkWidget     *widget,
  * gimp_prop_opacity_entry_new:
  * @config:        Object to which property is attached.
  * @property_name: Name of double property controlled by the spin button.
- * @grid:          The #GtkGrid the widgets will be attached to.
- * @column:        The column to start with.
- * @row:           The row to attach the widgets.
  * @label:         The text for the #GtkLabel which will appear left of the
  *                 #GtkHScale.
  *
@@ -1635,32 +1610,27 @@ gimp_prop_widget_set_factor (GtkWidget     *widget,
  *
  * Since: 2.4
  */
-GtkAdjustment *
+GtkWidget *
 gimp_prop_opacity_entry_new (GObject     *config,
                              const gchar *property_name,
-                             GtkGrid     *grid,
-                             gint         column,
-                             gint         row,
                              const gchar *label)
 {
-  GtkAdjustment *adjustment;
+  GtkWidget *widget;
 
   g_return_val_if_fail (G_IS_OBJECT (config), NULL);
   g_return_val_if_fail (property_name != NULL, NULL);
 
-  adjustment = gimp_prop_scale_entry_new (config, property_name,
-                                          grid, column, row, label,
-                                          0.01, 0.1, 1,
-                                          FALSE, 0.0, 0.0);
+  widget = gimp_prop_scale_entry_new (config, property_name,
+                                      label, 0.01, 0.1, 1,
+                                      FALSE, 0.0, 0.0);
 
-  if (adjustment)
+  if (widget)
     {
-      gimp_prop_widget_set_factor (GIMP_SCALE_ENTRY_SPINBUTTON (adjustment),
-                                   adjustment,
-                                   100.0, 0.0, 0.0, 1);
+      gimp_prop_widget_set_factor (gimp_scale_entry_get_spin_button (GIMP_SCALE_ENTRY (widget)),
+                                   NULL, 100.0, 0.0, 0.0, 1);
     }
 
-  return adjustment;
+  return widget;
 }
 
 
diff --git a/libgimpwidgets/gimppropwidgets.h b/libgimpwidgets/gimppropwidgets.h
index 4e0343ecf2..e871229ee5 100644
--- a/libgimpwidgets/gimppropwidgets.h
+++ b/libgimpwidgets/gimppropwidgets.h
@@ -120,11 +120,8 @@ GtkWidget     * gimp_prop_hscale_new              (GObject      *config,
                                                    gdouble       page_increment,
                                                    gint          digits);
 
-GtkAdjustment * gimp_prop_scale_entry_new         (GObject      *config,
+GtkWidget     * gimp_prop_scale_entry_new         (GObject      *config,
                                                    const gchar  *property_name,
-                                                   GtkGrid      *grid,
-                                                   gint          column,
-                                                   gint          row,
                                                    const gchar  *label,
                                                    gdouble       step_increment,
                                                    gdouble       page_increment,
@@ -135,11 +132,8 @@ GtkAdjustment * gimp_prop_scale_entry_new         (GObject      *config,
 
 /*  special form of gimp_prop_scale_entry_new() for GParamDouble  */
 
-GtkAdjustment * gimp_prop_opacity_entry_new       (GObject       *config,
+GtkWidget     * gimp_prop_opacity_entry_new       (GObject       *config,
                                                    const gchar   *property_name,
-                                                   GtkGrid       *grid,
-                                                   gint           column,
-                                                   gint           row,
                                                    const gchar   *label);
 
 
diff --git a/libgimpwidgets/gimpscaleentry.c b/libgimpwidgets/gimpscaleentry.c
index 7e95b1a9e0..819fc4709f 100644
--- a/libgimpwidgets/gimpscaleentry.c
+++ b/libgimpwidgets/gimpscaleentry.c
@@ -31,6 +31,50 @@
 #include "gimpwidgets.h"
 
 
+/**
+ * SECTION: gimpscaleentry
+ * @title: GimpScaleEntry
+ * @short_description: Widget containing a scale, a spin button and a
+ *                     label.
+ *
+ * This widget is a #GtkGrid showing a #GtkSpinButton and a #GtkScale
+ * bound together. It also displays a #GtkLabel which is used as
+ * mnemonic on the #GtkSpinButton.
+ **/
+
+
+enum
+{
+  PROP_0,
+  PROP_LABEL,
+  PROP_VALUE,
+  PROP_LOWER,
+  PROP_UPPER,
+  PROP_STEP_INCREMENT,
+  PROP_PAGE_INCREMENT,
+  PROP_DIGITS,
+};
+
+struct _GimpScaleEntryPrivate
+{
+  GtkWidget *label;
+  GtkWidget *spinbutton;
+  GtkWidget *scale;
+
+  GBinding  *binding;
+};
+
+
+static void   gimp_scale_entry_constructed          (GObject       *object);
+static void   gimp_scale_entry_set_property         (GObject       *object,
+                                                     guint          property_id,
+                                                     const GValue  *value,
+                                                     GParamSpec    *pspec);
+static void   gimp_scale_entry_get_property         (GObject       *object,
+                                                     guint          property_id,
+                                                     GValue        *value,
+                                                     GParamSpec    *pspec);
+
 static gboolean        gimp_scale_entry_linear_to_log (GBinding     *binding,
                                                        const GValue *from_value,
                                                        GValue       *to_value,
@@ -60,6 +104,326 @@ static GtkAdjustment * gimp_scale_entry_new_internal  (gboolean      color_scale
                                                        const gchar  *help_id);
 
 
+G_DEFINE_TYPE_WITH_PRIVATE (GimpScaleEntry, gimp_scale_entry, GTK_TYPE_GRID)
+
+#define parent_class gimp_scale_entry_parent_class
+
+
+static void
+gimp_scale_entry_class_init (GimpScaleEntryClass *klass)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+  object_class->constructed  = gimp_scale_entry_constructed;
+  object_class->set_property = gimp_scale_entry_set_property;
+  object_class->get_property = gimp_scale_entry_get_property;
+
+  /**
+   * GimpScaleEntry:label:
+   *
+   * Since: 3.0
+   **/
+  g_object_class_install_property (object_class, PROP_LABEL,
+                                   g_param_spec_string ("label",
+                                                        "Label text",
+                                                        "The text of the label part of this widget",
+                                                        NULL,
+                                                        GIMP_PARAM_READWRITE));
+
+  /**
+   * GimpScaleEntry:value:
+   *
+   * Since: 3.0
+   **/
+  g_object_class_install_property (object_class, PROP_VALUE,
+                                   g_param_spec_double ("value", NULL,
+                                                        "Current value",
+                                                        -G_MAXDOUBLE, G_MAXDOUBLE, 1.0,
+                                                        GIMP_PARAM_READWRITE));
+
+  /**
+   * GimpScaleEntry:lower:
+   *
+   * Since: 3.0
+   **/
+  g_object_class_install_property (object_class, PROP_LOWER,
+                                   g_param_spec_double ("lower", NULL,
+                                                        "Minimum value",
+                                                        -G_MAXDOUBLE, G_MAXDOUBLE, 1.0,
+                                                        GIMP_PARAM_READWRITE));
+
+  /**
+   * GimpScaleEntry:upper:
+   *
+   * Since: 3.0
+   **/
+  g_object_class_install_property (object_class, PROP_UPPER,
+                                   g_param_spec_double ("upper", NULL,
+                                                        "Max value",
+                                                        -G_MAXDOUBLE, G_MAXDOUBLE, 0.0,
+                                                        GIMP_PARAM_READWRITE));
+
+  /**
+   * GimpScaleEntry:step-increment:
+   *
+   * Since: 3.0
+   **/
+  g_object_class_install_property (object_class, PROP_STEP_INCREMENT,
+                                   g_param_spec_double ("step-increment", NULL,
+                                                        "Step increment",
+                                                        G_MINDOUBLE, G_MAXDOUBLE, 1.0,
+                                                        GIMP_PARAM_READWRITE));
+
+  /**
+   * GimpScaleEntry:page-increment:
+   *
+   * Since: 3.0
+   **/
+  g_object_class_install_property (object_class, PROP_PAGE_INCREMENT,
+                                   g_param_spec_double ("page-increment", NULL,
+                                                        "Page increment",
+                                                        G_MINDOUBLE, G_MAXDOUBLE, 10.0,
+                                                        GIMP_PARAM_READWRITE));
+
+  /**
+   * GimpScaleEntry:digits:
+   *
+   * Since: 3.0
+   **/
+  g_object_class_install_property (object_class, PROP_DIGITS,
+                                   g_param_spec_uint ("digits", NULL,
+                                                      "The number of decimal places to display",
+                                                      0, G_MAXUINT, 2,
+                                                      GIMP_PARAM_READWRITE));
+}
+
+static void
+gimp_scale_entry_init (GimpScaleEntry *entry)
+{
+  entry->priv = gimp_scale_entry_get_instance_private (entry);
+}
+
+static void
+gimp_scale_entry_constructed (GObject *object)
+{
+  GimpScaleEntry *entry = GIMP_SCALE_ENTRY (object);
+  GtkAdjustment  *adjustment;
+
+  /* Construction values are a bit random but should be properly
+   * overrided with expected values if the object was created with
+   * gimp_scale_entry_new().
+   */
+
+  entry->priv->label = gtk_label_new_with_mnemonic (NULL);
+  gtk_label_set_xalign (GTK_LABEL (entry->priv->label), 0.0);
+
+  adjustment = gtk_adjustment_new (0.0, 0.0, 100.0, 1.0, 10.0, 0.0);
+
+  entry->priv->spinbutton = gimp_spin_button_new (adjustment, 2.0, 2.0);
+  gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (entry->priv->spinbutton), TRUE);
+  gtk_label_set_mnemonic_widget (GTK_LABEL (entry->priv->label), entry->priv->spinbutton);
+
+  entry->priv->scale = gtk_scale_new (GTK_ORIENTATION_HORIZONTAL, adjustment);
+  gtk_scale_set_draw_value (GTK_SCALE (entry->priv->scale), FALSE);
+  gtk_widget_set_hexpand (entry->priv->scale, TRUE);
+
+  gtk_grid_attach (GTK_GRID (entry), entry->priv->label,      0, 0, 1, 1);
+  gtk_grid_attach (GTK_GRID (entry), entry->priv->scale,      1, 0, 1, 1);
+  gtk_grid_attach (GTK_GRID (entry), entry->priv->spinbutton, 2, 0, 1, 1);
+  gtk_widget_show (entry->priv->label);
+  gtk_widget_show (entry->priv->scale);
+  gtk_widget_show (entry->priv->spinbutton);
+
+  /* This is important to make this object into a property widget. It
+   * will allow config object to bind the "value" property of this
+   * widget, and therefore be updated automatically.
+   */
+  g_object_bind_property (G_OBJECT (adjustment),  "value",
+                          object,                 "value",
+                          G_BINDING_BIDIRECTIONAL |
+                          G_BINDING_SYNC_CREATE);
+}
+
+static void
+gimp_scale_entry_set_property (GObject      *object,
+                               guint         property_id,
+                               const GValue *value,
+                               GParamSpec   *pspec)
+{
+  GimpScaleEntry *entry = GIMP_SCALE_ENTRY (object);
+
+  switch (property_id)
+    {
+    case PROP_LABEL:
+        {
+          /* This should not happen since the property is **not** set with
+           * G_PARAM_CONSTRUCT, hence the label should exist when the
+           * property is first set.
+           */
+          g_return_if_fail (entry->priv->label);
+
+          gtk_label_set_markup_with_mnemonic (GTK_LABEL (entry->priv->label),
+                                              g_value_get_string (value));
+        }
+      break;
+    case PROP_VALUE:
+        {
+          GtkSpinButton *spinbutton;
+          GtkAdjustment *adj;
+
+          g_return_if_fail (entry->priv->spinbutton);
+
+          /* Set on the spin button, because it might have a bigger
+           * range, hence shows the real value.
+           */
+          spinbutton = GTK_SPIN_BUTTON (entry->priv->spinbutton);
+          adj = gtk_spin_button_get_adjustment (spinbutton);
+
+          /* Avoid looping forever since we have bound this widget's
+           * "value" property with the spin button "value" property.
+           */
+          if (gtk_adjustment_get_value (adj) != g_value_get_double (value))
+            gtk_adjustment_set_value (adj, g_value_get_double (value));
+        }
+      break;
+    case PROP_LOWER:
+        {
+          GtkSpinButton *spinbutton;
+          GtkAdjustment *adj;
+
+          g_return_if_fail (entry->priv->spinbutton);
+
+          /* This sets the range only on the spin button which may share
+           * or not its adjustment with the scale.
+           * To change only the scale, see gimp_scale_entry_set_range().
+           */
+          spinbutton = GTK_SPIN_BUTTON (entry->priv->spinbutton);
+          adj = gtk_spin_button_get_adjustment (spinbutton);
+          gtk_adjustment_set_lower (adj, g_value_get_double (value));
+        }
+      break;
+    case PROP_UPPER:
+        {
+          GtkSpinButton *spinbutton;
+          GtkAdjustment *adj;
+
+          g_return_if_fail (entry->priv->spinbutton);
+
+          spinbutton = GTK_SPIN_BUTTON (entry->priv->spinbutton);
+          adj = gtk_spin_button_get_adjustment (spinbutton);
+          gtk_adjustment_set_upper (adj, g_value_get_double (value));
+        }
+      break;
+    case PROP_STEP_INCREMENT:
+        {
+          GtkSpinButton *spinbutton;
+          GtkAdjustment *adj;
+
+          g_return_if_fail (entry->priv->scale && entry->priv->spinbutton);
+
+          adj = gtk_range_get_adjustment (GTK_RANGE (entry->priv->scale));
+          gtk_adjustment_set_step_increment (adj, g_value_get_double (value));
+
+          spinbutton = GTK_SPIN_BUTTON (entry->priv->spinbutton);
+          if (adj != gtk_spin_button_get_adjustment (spinbutton))
+            gtk_adjustment_set_step_increment (gtk_spin_button_get_adjustment (spinbutton), 
g_value_get_double (value));
+
+          g_object_set (entry->priv->spinbutton,
+                        "climb-rate", g_value_get_double (value),
+                        NULL);
+        }
+      break;
+    case PROP_PAGE_INCREMENT:
+        {
+          GtkSpinButton *spinbutton;
+          GtkAdjustment *adj;
+
+          g_return_if_fail (entry->priv->scale && entry->priv->spinbutton);
+
+          adj = gtk_range_get_adjustment (GTK_RANGE (entry->priv->scale));
+          gtk_adjustment_set_page_increment (adj, g_value_get_double (value));
+
+          spinbutton = GTK_SPIN_BUTTON (entry->priv->spinbutton);
+          if (adj != gtk_spin_button_get_adjustment (spinbutton))
+            gtk_adjustment_set_page_increment (gtk_spin_button_get_adjustment (spinbutton), 
g_value_get_double (value));
+        }
+      break;
+    case PROP_DIGITS:
+        {
+          g_return_if_fail (entry->priv->scale && entry->priv->spinbutton);
+
+          gtk_scale_set_digits (GTK_SCALE (entry->priv->scale),
+                                g_value_get_uint (value));
+          gtk_spin_button_set_digits (GTK_SPIN_BUTTON (entry->priv->spinbutton),
+                                      g_value_get_uint (value));
+        }
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+      break;
+    }
+}
+
+static void
+gimp_scale_entry_get_property (GObject    *object,
+                               guint       property_id,
+                               GValue     *value,
+                               GParamSpec *pspec)
+{
+  GimpScaleEntry *entry      = GIMP_SCALE_ENTRY (object);
+  GtkSpinButton  *spinbutton = GTK_SPIN_BUTTON (entry->priv->spinbutton);
+
+  switch (property_id)
+    {
+    case PROP_LABEL:
+      g_value_set_string (value, gtk_label_get_label (GTK_LABEL (entry->priv->label)));
+      break;
+    case PROP_VALUE:
+      g_value_set_double (value, gtk_spin_button_get_value (spinbutton));
+      break;
+    case PROP_LOWER:
+        {
+          GtkAdjustment *adj;
+
+          adj = gtk_spin_button_get_adjustment (spinbutton);
+          g_value_set_double (value, gtk_adjustment_get_lower (adj));
+        }
+      break;
+    case PROP_UPPER:
+        {
+          GtkAdjustment *adj;
+
+          adj = gtk_spin_button_get_adjustment (spinbutton);
+          g_value_set_double (value, gtk_adjustment_get_upper (adj));
+        }
+      break;
+    case PROP_STEP_INCREMENT:
+        {
+          GtkAdjustment *adj;
+
+          adj = gtk_spin_button_get_adjustment (spinbutton);
+          g_value_set_double (value, gtk_adjustment_get_step_increment (adj));
+        }
+      break;
+    case PROP_PAGE_INCREMENT:
+        {
+          GtkAdjustment *adj;
+
+          adj = gtk_spin_button_get_adjustment (spinbutton);
+          g_value_set_double (value, gtk_adjustment_get_page_increment (adj));
+        }
+      break;
+    case PROP_DIGITS:
+      g_value_set_uint (value, gtk_spin_button_get_digits (spinbutton));
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+      break;
+    }
+}
+
 static gboolean
 gimp_scale_entry_linear_to_log (GBinding     *binding,
                                 const GValue *from_value,
@@ -209,6 +573,172 @@ gimp_scale_entry_new_internal (gboolean     color_scale,
   return spin_adjustment;
 }
 
+/**
+ * gimp_scale_entry_new2:
+ * @text:           The text for the #GtkLabel which will appear left of
+ *                  the #GtkHScale.
+ * @value:          The initial value.
+ * @lower:          The lower boundary.
+ * @upper:          The upper boundary.
+ * @step_increment: The step increment.
+ * @page_increment: The page increment.
+ * @digits:         The number of decimal digits.
+ *
+ * This function creates a #GtkLabel, a #GtkHScale and a #GtkSpinButton and
+ * attaches them to a 3-column #GtkGrid.
+ *
+ * Returns: (transfer full): The new #GtkScaleEntry.
+ **/
+GtkWidget *
+gimp_scale_entry_new2 (const gchar *text,
+                       gdouble      value,
+                       gdouble      lower,
+                       gdouble      upper,
+                       gdouble      step_increment,
+                       gdouble      page_increment,
+                       guint        digits)
+{
+  GtkWidget *entry;
+
+  entry = g_object_new (GIMP_TYPE_SCALE_ENTRY,
+                        "label",          text,
+                        "value",          value,
+                        "lower",          lower,
+                        "upper",          upper,
+                        "step-increment", step_increment,
+                        "page-increment", page_increment,
+                        "digits",         digits,
+                        NULL);
+
+  return entry;
+}
+
+
+/**
+ * gimp_scale_entry_get_label:
+ * @entry: The #GtkScaleEntry.
+ *
+ * This function returns the #GtkLabel packed in @entry. This can be
+ * useful if you need to customize some aspects of the widget.
+ *
+ * Returns: (transfer none): The new #GtkLabel contained in @entry.
+ **/
+GtkWidget *
+gimp_scale_entry_get_label (GimpScaleEntry *entry)
+{
+  return entry->priv->label;
+}
+
+/**
+ * gimp_scale_entry_get_spin_button:
+ * @entry: The #GtkScaleEntry.
+ *
+ * This function returns the #GtkSpinButton packed in @entry. This can
+ * be useful if you need to customize some aspects of the widget.
+ *
+ * Returns: (transfer none): The new #GtkSpinButton contained in @entry.
+ **/
+GtkWidget *
+gimp_scale_entry_get_spin_button (GimpScaleEntry *entry)
+{
+  return entry->priv->spinbutton;
+}
+
+/**
+ * gimp_scale_entry_get_scale:
+ * @entry: The #GtkScaleEntry.
+ *
+ * This function returns the #GtkScale packed in @entry. This can be
+   * useful if you need to customize some aspects of the widget
+ *
+ * Returns: (transfer none): The new #GtkScale contained in @entry.
+ **/
+GtkWidget *
+gimp_scale_entry_get_scale (GimpScaleEntry *entry)
+{
+  return entry->priv->scale;
+}
+
+/**
+ * gimp_scale_entry_set_range:
+ * @entry:       The #GtkScaleEntry.
+ * @lower:       the lower value for the whole widget if @limit_scale is
+ *               %FALSE, or only for the #GtkScale if %TRUE.
+ * @upper:       the upper value for the whole widget if @limit_scale is
+ *               %FALSE, or only for the #GtkSpinButton if %TRUE.
+ * @limit_scale: Whether the range should only apply to the #GtkScale or
+ *               if it should share its #GtkAdjustement with the
+ *               #GtkScale. If %TRUE, both @lower and @upper must be
+ *               included in current #GtkSpinButton range.
+ *
+ * By default the #GtkSpinButton and #GtkScale will have the same range
+ * (they will even share their GtkAdjustment). In some case, you want to
+ * set a different range. In particular when the finale range is huge,
+ * the #GtkScale might become nearly useless as every tiny slider move
+ * would dramatically update the value. In this case, it is common to
+ * set the #GtkScale to a smaller common range, while the #GtkSpinButton
+ * would allow for the full allowed range.
+ * This function allows this. Obviously the #GtkAdjustment of both
+ * widgets would be synced but if the set value is out of the #GtkScale
+ * range, the slider would simply show at one extreme.
+ *
+ * If @limit_scale is %FALSE though, it would sync back both widgets
+ * range to the new values.
+ **/
+void
+gimp_scale_entry_set_range (GimpScaleEntry *entry,
+                            gdouble         lower,
+                            gdouble         upper,
+                            gboolean        limit_scale)
+{
+  GtkSpinButton *spinbutton = GTK_SPIN_BUTTON (entry->priv->spinbutton);
+  GtkAdjustment *spin_adjustment;
+  GtkAdjustment *scale_adjustment;
+
+  spin_adjustment  = gtk_spin_button_get_adjustment (spinbutton);
+  scale_adjustment = gtk_range_get_adjustment (GTK_RANGE (entry->priv->scale));
+
+  if (limit_scale)
+    {
+      g_return_if_fail (lower >= gtk_adjustment_get_lower (spin_adjustment) &&
+                        upper <= gtk_adjustment_get_upper (spin_adjustment));
+
+      if (spin_adjustment == scale_adjustment)
+        {
+          scale_adjustment = gtk_adjustment_new (gtk_adjustment_get_value (spin_adjustment),
+                                                 lower, upper,
+                                                 gtk_adjustment_get_step_increment (spin_adjustment),
+                                                 gtk_adjustment_get_page_increment (spin_adjustment),
+                                                 gtk_adjustment_get_page_size (spin_adjustment));
+          gtk_range_set_adjustment (GTK_RANGE (entry->priv->scale), scale_adjustment);
+
+          entry->priv->binding = g_object_bind_property (G_OBJECT (spin_adjustment),  "value",
+                                                         G_OBJECT (scale_adjustment), "value",
+                                                         G_BINDING_BIDIRECTIONAL |
+                                                         G_BINDING_SYNC_CREATE);
+        }
+      else
+        {
+          gtk_adjustment_set_lower (scale_adjustment, lower);
+          gtk_adjustment_set_upper (scale_adjustment, upper);
+        }
+    }
+  else if (! limit_scale)
+    {
+      if (spin_adjustment != scale_adjustment)
+        {
+          g_clear_object (&entry->priv->binding);
+
+          gtk_range_set_adjustment (GTK_RANGE (entry->priv->scale), spin_adjustment);
+        }
+
+      g_object_set (entry,
+                    "lower", lower,
+                    "upper", upper,
+                    NULL);
+    }
+}
+
 /**
  * gimp_scale_entry_new:
  * @grid:                The #GtkGrid the widgets will be attached to.
diff --git a/libgimpwidgets/gimpscaleentry.h b/libgimpwidgets/gimpscaleentry.h
index bdb810a4b6..76fd7defff 100644
--- a/libgimpwidgets/gimpscaleentry.h
+++ b/libgimpwidgets/gimpscaleentry.h
@@ -29,6 +29,58 @@
 
 G_BEGIN_DECLS
 
+#define GIMP_TYPE_SCALE_ENTRY            (gimp_scale_entry_get_type ())
+#define GIMP_SCALE_ENTRY(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), GIMP_TYPE_SCALE_ENTRY, 
GimpScaleEntry))
+#define GIMP_SCALE_ENTRY_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), GIMP_TYPE_SCALE_ENTRY, 
GimpScaleEntryClass))
+#define GIMP_IS_SCALE_ENTRY(obj)         (G_TYPE_CHECK_INSTANCE_TYPE (obj, GIMP_TYPE_SCALE_ENTRY))
+#define GIMP_IS_SCALE_ENTRY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GIMP_TYPE_SCALE_ENTRY))
+#define GIMP_SCALE_ENTRY_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), GIMP_TYPE_SCALE_ENTRY, 
GimpScaleEntryClass))
+
+
+typedef struct _GimpScaleEntryPrivate GimpScaleEntryPrivate;
+typedef struct _GimpScaleEntryClass   GimpScaleEntryClass;
+
+struct _GimpScaleEntry
+{
+  GtkGrid                parent_instance;
+
+  GimpScaleEntryPrivate *priv;
+};
+
+struct _GimpScaleEntryClass
+{
+  GtkGridClass  parent_class;
+
+  /* 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_scale_entry_get_type        (void) G_GNUC_CONST;
+
+GtkWidget     * gimp_scale_entry_new2            (const gchar *text,
+                                                  gdouble      value,
+                                                  gdouble      lower,
+                                                  gdouble      upper,
+                                                  gdouble      step_increment,
+                                                  gdouble      page_increment,
+                                                  guint        digits);
+
+GtkWidget     * gimp_scale_entry_get_label       (GimpScaleEntry *entry);
+GtkWidget     * gimp_scale_entry_get_spin_button (GimpScaleEntry *entry);
+GtkWidget     * gimp_scale_entry_get_scale       (GimpScaleEntry *entry);
+
+void            gimp_scale_entry_set_range       (GimpScaleEntry *entry,
+                                                  gdouble         lower,
+                                                  gdouble         upper,
+                                                  gboolean        limit_scale);
+
 
 /**
  * GIMP_SCALE_ENTRY_LABEL:
diff --git a/libgimpwidgets/gimpwidgetstypes.h b/libgimpwidgets/gimpwidgetstypes.h
index 0fea008b97..687f3efb53 100644
--- a/libgimpwidgets/gimpwidgetstypes.h
+++ b/libgimpwidgets/gimpwidgetstypes.h
@@ -70,6 +70,7 @@ typedef struct _GimpPickButton                GimpPickButton;
 typedef struct _GimpPreview                   GimpPreview;
 typedef struct _GimpPreviewArea               GimpPreviewArea;
 typedef struct _GimpRuler                     GimpRuler;
+typedef struct _GimpScaleEntry                GimpScaleEntry;
 typedef struct _GimpScrolledPreview           GimpScrolledPreview;
 typedef struct _GimpSizeEntry                 GimpSizeEntry;
 typedef struct _GimpSpinButton                GimpSpinButton;


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]