home *** CD-ROM | disk | FTP | other *** search
/ Chip 2005 February / CMCD0205.ISO / Linux / gimp-2.2.0.tar.gz / gimp-2.2.0.tar / gimp-2.2.0 / libgimpwidgets / gimpsizeentry.c < prev    next >
C/C++ Source or Header  |  2004-05-18  |  38KB  |  1,253 lines

  1. /* LIBGIMP - The GIMP Library
  2.  * Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball
  3.  *
  4.  * gimpsizeentry.c
  5.  * Copyright (C) 1999-2000 Sven Neumann <sven@gimp.org>
  6.  *                         Michael Natterer <mitch@gimp.org>
  7.  *
  8.  * This library is free software; you can redistribute it and/or
  9.  * modify it under the terms of the GNU Lesser General Public
  10.  * License as published by the Free Software Foundation; either
  11.  * version 2 of the License, or (at your option) any later version.
  12.  *
  13.  * This library is distributed in the hope that it will be useful,
  14.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  16.  * Library General Public License for more details.
  17.  *
  18.  * You should have received a copy of the GNU Lesser General Public
  19.  * License along with this library; if not, write to the
  20.  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
  21.  * Boston, MA 02111-1307, USA.
  22.  */
  23.  
  24. #include "config.h"
  25.  
  26. #include <gtk/gtk.h>
  27.  
  28. #include "libgimpbase/gimpbase.h"
  29.  
  30. #include "gimpwidgetstypes.h"
  31.  
  32. #include "gimpsizeentry.h"
  33. #include "gimpunitmenu.h"
  34.  
  35.  
  36. #define SIZE_MAX_VALUE 500000.0
  37.  
  38. #define GIMP_SIZE_ENTRY_DIGITS(unit) (MIN (gimp_unit_get_digits (unit), 5) + 1)
  39.  
  40.  
  41. enum
  42. {
  43.   VALUE_CHANGED,
  44.   REFVAL_CHANGED,
  45.   UNIT_CHANGED,
  46.   LAST_SIGNAL
  47. };
  48.  
  49.  
  50. struct _GimpSizeEntryField
  51. {
  52.   GimpSizeEntry *gse;
  53.  
  54.   gdouble        resolution;
  55.   gdouble        lower;
  56.   gdouble        upper;
  57.  
  58.   GtkObject     *value_adjustment;
  59.   GtkWidget     *value_spinbutton;
  60.   gdouble        value;
  61.   gdouble        min_value;
  62.   gdouble        max_value;
  63.  
  64.   GtkObject     *refval_adjustment;
  65.   GtkWidget     *refval_spinbutton;
  66.   gdouble        refval;
  67.   gdouble        min_refval;
  68.   gdouble        max_refval;
  69.   gint           refval_digits;
  70.  
  71.   gint           stop_recursion;
  72. };
  73.  
  74.  
  75. static void   gimp_size_entry_class_init      (GimpSizeEntryClass *class);
  76. static void   gimp_size_entry_init            (GimpSizeEntry      *gse);
  77.  
  78. static void   gimp_size_entry_finalize        (GObject            *object);
  79.  
  80. static void   gimp_size_entry_update_value    (GimpSizeEntryField *gsef,
  81.                            gdouble             value);
  82. static void   gimp_size_entry_value_callback  (GtkWidget          *widget,
  83.                            gpointer            data);
  84. static void   gimp_size_entry_update_refval   (GimpSizeEntryField *gsef,
  85.                            gdouble             refval);
  86. static void   gimp_size_entry_refval_callback (GtkWidget          *widget,
  87.                            gpointer            data);
  88. static void   gimp_size_entry_update_unit     (GimpSizeEntry      *gse,
  89.                            GimpUnit            unit);
  90. static void   gimp_size_entry_unit_callback   (GtkWidget          *widget,
  91.                            GimpSizeEntry      *sizeentry);
  92.  
  93.  
  94. static guint gimp_size_entry_signals[LAST_SIGNAL] = { 0 };
  95.  
  96. static GtkTableClass *parent_class = NULL;
  97.  
  98.  
  99. GType
  100. gimp_size_entry_get_type (void)
  101. {
  102.   static GType gse_type = 0;
  103.  
  104.   if (! gse_type)
  105.     {
  106.       static const GTypeInfo gse_info =
  107.       {
  108.         sizeof (GimpSizeEntryClass),
  109.     (GBaseInitFunc) NULL,
  110.     (GBaseFinalizeFunc) NULL,
  111.     (GClassInitFunc) gimp_size_entry_class_init,
  112.     NULL,        /* class_finalize */
  113.     NULL,        /* class_data     */
  114.     sizeof (GimpSizeEntry),
  115.     0,              /* n_preallocs    */
  116.     (GInstanceInitFunc) gimp_size_entry_init,
  117.       };
  118.  
  119.       gse_type = g_type_register_static (GTK_TYPE_TABLE,
  120.                                          "GimpSizeEntry",
  121.                                          &gse_info, 0);
  122.     }
  123.  
  124.   return gse_type;
  125. }
  126.  
  127. static void
  128. gimp_size_entry_class_init (GimpSizeEntryClass *klass)
  129. {
  130.   GObjectClass *object_class;
  131.  
  132.   object_class = G_OBJECT_CLASS (klass);
  133.  
  134.   parent_class = g_type_class_peek_parent (klass);
  135.  
  136.   gimp_size_entry_signals[VALUE_CHANGED] =
  137.     g_signal_new ("value_changed",
  138.           G_TYPE_FROM_CLASS (klass),
  139.           G_SIGNAL_RUN_FIRST,
  140.           G_STRUCT_OFFSET (GimpSizeEntryClass, value_changed),
  141.           NULL, NULL,
  142.           g_cclosure_marshal_VOID__VOID,
  143.           G_TYPE_NONE, 0);
  144.  
  145.   gimp_size_entry_signals[REFVAL_CHANGED] =
  146.     g_signal_new ("refval_changed",
  147.           G_TYPE_FROM_CLASS (klass),
  148.           G_SIGNAL_RUN_FIRST,
  149.           G_STRUCT_OFFSET (GimpSizeEntryClass, refval_changed),
  150.           NULL, NULL,
  151.           g_cclosure_marshal_VOID__VOID,
  152.           G_TYPE_NONE, 0);
  153.  
  154.   gimp_size_entry_signals[UNIT_CHANGED] =
  155.     g_signal_new ("unit_changed",
  156.           G_TYPE_FROM_CLASS (klass),
  157.           G_SIGNAL_RUN_FIRST,
  158.           G_STRUCT_OFFSET (GimpSizeEntryClass, unit_changed),
  159.           NULL, NULL,
  160.           g_cclosure_marshal_VOID__VOID,
  161.           G_TYPE_NONE, 0);
  162.  
  163.   object_class->finalize = gimp_size_entry_finalize;
  164.  
  165.   klass->value_changed   = NULL;
  166.   klass->refval_changed  = NULL;
  167.   klass->unit_changed    = NULL;
  168. }
  169.  
  170. static void
  171. gimp_size_entry_init (GimpSizeEntry *gse)
  172. {
  173.   gse->fields            = NULL;
  174.   gse->number_of_fields  = 0;
  175.   gse->unitmenu          = NULL;
  176.   gse->unit              = GIMP_UNIT_PIXEL;
  177.   gse->menu_show_pixels  = TRUE;
  178.   gse->menu_show_percent = TRUE;
  179.   gse->show_refval       = FALSE;
  180.   gse->update_policy     = GIMP_SIZE_ENTRY_UPDATE_NONE;
  181. }
  182.  
  183. static void
  184. gimp_size_entry_finalize (GObject *object)
  185. {
  186.   GimpSizeEntry *gse;
  187.  
  188.   g_return_if_fail (GIMP_IS_SIZE_ENTRY (object));
  189.  
  190.   gse = GIMP_SIZE_ENTRY (object);
  191.  
  192.   if (gse->fields)
  193.     {
  194.       g_slist_foreach (gse->fields, (GFunc) g_free, NULL);
  195.       g_slist_free (gse->fields);
  196.       gse->fields = NULL;
  197.     }
  198.  
  199.   G_OBJECT_CLASS (parent_class)->finalize (object);
  200. }
  201.  
  202. /**
  203.  * gimp_size_entry_new:
  204.  * @number_of_fields:  The number of input fields.
  205.  * @unit:              The initial unit.
  206.  * @unit_format:       A printf-like unit-format string as is used with
  207.  *                     gimp_unit_menu_new().
  208.  * @menu_show_pixels:  %TRUE if the unit menu shold contain an item for
  209.  *                     GIMP_UNIT_PIXEL (ignored if the @update_policy is not
  210.  *                     GIMP_SIZE_ENTRY_UPDATE_NONE).
  211.  * @menu_show_percent: %TRUE if the unit menu shold contain an item for
  212.  *                     GIMP_UNIT_PERCENT.
  213.  * @show_refval:       %TRUE if you want an extra "reference value"
  214.  *                     spinbutton per input field.
  215.  * @spinbutton_width:  The minimal horizontal size of the #GtkSpinButton's.
  216.  * @update_policy:     How the automatic pixel <-> real-world-unit
  217.  *                     calculations should be done.
  218.  *
  219.  * Creates a new #GimpSizeEntry widget.
  220.  *
  221.  * To have all automatic calculations performed correctly, set up the
  222.  * widget in the following order:
  223.  *
  224.  * 1. gimp_size_entry_new()
  225.  *
  226.  * 2. (for each additional input field) gimp_size_entry_add_field()
  227.  *
  228.  * 3. gimp_size_entry_set_unit()
  229.  *
  230.  * For each input field:
  231.  *
  232.  * 4. gimp_size_entry_set_resolution()
  233.  *
  234.  * 5. gimp_size_entry_set_refval_boundaries()
  235.  *    (or gimp_size_entry_set_value_boundaries())
  236.  *
  237.  * 6. gimp_size_entry_set_size()
  238.  *
  239.  * 7. gimp_size_entry_set_refval() (or gimp_size_entry_set_value())
  240.  *
  241.  * The #GimpSizeEntry is derived from #GtkTable and will have
  242.  * an empty border of one cell width on each side plus an empty column left
  243.  * of the #GimpUnitMenu to allow the caller to add labels or a
  244.  * #GimpChainButton.
  245.  *
  246.  * Returns: A Pointer to the new #GimpSizeEntry widget.
  247.  **/
  248. GtkWidget *
  249. gimp_size_entry_new (gint                       number_of_fields,
  250.              GimpUnit                   unit,
  251.              const gchar               *unit_format,
  252.              gboolean                   menu_show_pixels,
  253.              gboolean                   menu_show_percent,
  254.              gboolean                   show_refval,
  255.              gint                       spinbutton_width,
  256.              GimpSizeEntryUpdatePolicy  update_policy)
  257. {
  258.   GimpSizeEntry *gse;
  259.   gint           i;
  260.  
  261.   g_return_val_if_fail ((number_of_fields >= 0) && (number_of_fields <= 16),
  262.             NULL);
  263.  
  264.   gse = g_object_new (GIMP_TYPE_SIZE_ENTRY, NULL);
  265.  
  266.   gse->number_of_fields = number_of_fields;
  267.   gse->unit             = unit;
  268.   gse->show_refval      = show_refval;
  269.   gse->update_policy    = update_policy;
  270.  
  271.   gtk_table_resize (GTK_TABLE (gse),
  272.             1 + gse->show_refval + 2,
  273.             number_of_fields + 1 + 3);
  274.  
  275.   /*  show the 'pixels' menu entry only if we are a 'size' sizeentry and
  276.    *  don't have the reference value spinbutton
  277.    */
  278.   if ((update_policy == GIMP_SIZE_ENTRY_UPDATE_RESOLUTION) ||
  279.       (show_refval == TRUE))
  280.     gse->menu_show_pixels = FALSE;
  281.   else
  282.     gse->menu_show_pixels = menu_show_pixels;
  283.  
  284.   /*  show the 'percent' menu entry only if we are a 'size' sizeentry
  285.    */
  286.   if (update_policy == GIMP_SIZE_ENTRY_UPDATE_RESOLUTION)
  287.     gse->menu_show_percent = FALSE;
  288.   else
  289.     gse->menu_show_percent = menu_show_percent;
  290.  
  291.   for (i = 0; i < number_of_fields; i++)
  292.     {
  293.       GimpSizeEntryField *gsef;
  294.  
  295.       gsef = g_new0 (GimpSizeEntryField, 1);
  296.       gse->fields = g_slist_append (gse->fields, gsef);
  297.  
  298.       gsef->gse               = gse;
  299.       gsef->resolution        = 1.0; /*  just to avoid division by zero  */
  300.       gsef->lower             = 0.0;
  301.       gsef->upper             = 100.0;
  302.       gsef->value             = 0;
  303.       gsef->min_value         = 0;
  304.       gsef->max_value         = SIZE_MAX_VALUE;
  305.       gsef->refval_adjustment = NULL;
  306.       gsef->value_adjustment  = NULL;
  307.       gsef->refval            = 0;
  308.       gsef->min_refval        = 0;
  309.       gsef->max_refval        = SIZE_MAX_VALUE;
  310.       gsef->refval_digits     =
  311.     (update_policy == GIMP_SIZE_ENTRY_UPDATE_SIZE) ? 0 : 3;
  312.       gsef->stop_recursion    = 0;
  313.  
  314.       gsef->value_adjustment = gtk_adjustment_new (gsef->value,
  315.                            gsef->min_value,
  316.                            gsef->max_value,
  317.                            1.0, 10.0, 0.0);
  318.       gsef->value_spinbutton =
  319.     gtk_spin_button_new (GTK_ADJUSTMENT (gsef->value_adjustment), 1.0,
  320.                  (unit == GIMP_UNIT_PIXEL) ? gsef->refval_digits :
  321.                  (unit == GIMP_UNIT_PERCENT) ? 2 :
  322.                  GIMP_SIZE_ENTRY_DIGITS (unit));
  323.  
  324.       if (spinbutton_width > 0)
  325.         {
  326.           if (spinbutton_width < 17)
  327.             gtk_entry_set_width_chars (GTK_ENTRY (gsef->value_spinbutton),
  328.                                        spinbutton_width);
  329.           else
  330.             gtk_widget_set_size_request (gsef->value_spinbutton,
  331.                                          spinbutton_width, -1);
  332.         }
  333.  
  334.       gtk_table_attach_defaults (GTK_TABLE (gse), gsef->value_spinbutton,
  335.                  i+1, i+2,
  336.                  gse->show_refval+1, gse->show_refval+2);
  337.       g_signal_connect (gsef->value_adjustment, "value_changed",
  338.                         G_CALLBACK (gimp_size_entry_value_callback),
  339.                         gsef);
  340.  
  341.       gtk_widget_show (gsef->value_spinbutton);
  342.  
  343.       if (gse->show_refval)
  344.     {
  345.       gsef->refval_adjustment = gtk_adjustment_new (gsef->refval,
  346.                             gsef->min_refval,
  347.                             gsef->max_refval,
  348.                             1.0, 10.0, 0.0);
  349.       gsef->refval_spinbutton =
  350.         gtk_spin_button_new (GTK_ADJUSTMENT (gsef->refval_adjustment),
  351.                  1.0,
  352.                  gsef->refval_digits);
  353.       gtk_widget_set_size_request (gsef->refval_spinbutton,
  354.                        spinbutton_width, -1);
  355.       gtk_table_attach_defaults (GTK_TABLE (gse), gsef->refval_spinbutton,
  356.                      i + 1, i + 2, 1, 2);
  357.       g_signal_connect (gsef->refval_adjustment,
  358.                             "value_changed",
  359.                             G_CALLBACK (gimp_size_entry_refval_callback),
  360.                             gsef);
  361.  
  362.       gtk_widget_show (gsef->refval_spinbutton);
  363.     }
  364.  
  365.       if (gse->menu_show_pixels && (unit == GIMP_UNIT_PIXEL) &&
  366.           ! gse->show_refval)
  367.     gtk_spin_button_set_digits (GTK_SPIN_BUTTON (gsef->value_spinbutton),
  368.                     gsef->refval_digits);
  369.     }
  370.  
  371.   gse->unitmenu = gimp_unit_menu_new (unit_format, unit,
  372.                       gse->menu_show_pixels,
  373.                       gse->menu_show_percent, TRUE);
  374.   gtk_table_attach (GTK_TABLE (gse), gse->unitmenu,
  375.             i+2, i+3,
  376.             gse->show_refval+1, gse->show_refval+2,
  377.             GTK_SHRINK | GTK_FILL, GTK_SHRINK | GTK_FILL, 0, 0);
  378.   g_signal_connect (gse->unitmenu, "unit_changed",
  379.                     G_CALLBACK (gimp_size_entry_unit_callback),
  380.                     gse);
  381.   gtk_widget_show (gse->unitmenu);
  382.  
  383.   return GTK_WIDGET (gse);
  384. }
  385.  
  386.  
  387. /**
  388.  * gimp_size_entry_add_field:
  389.  * @gse:               The sizeentry you want to add a field to.
  390.  * @value_spinbutton:  The spinbutton to display the field's value.
  391.  * @refval_spinbutton: The spinbutton to display the field's reference value.
  392.  *
  393.  * Adds an input field to the #GimpSizeEntry.
  394.  *
  395.  * The new input field will have the index 0. If you specified @show_refval
  396.  * as %TRUE in gimp_size_entry_new() you have to pass an additional
  397.  * #GtkSpinButton to hold the reference value. If @show_refval was %FALSE,
  398.  * @refval_spinbutton will be ignored.
  399.  **/
  400. void
  401. gimp_size_entry_add_field  (GimpSizeEntry *gse,
  402.                 GtkSpinButton *value_spinbutton,
  403.                 GtkSpinButton *refval_spinbutton)
  404. {
  405.   GimpSizeEntryField *gsef;
  406.   gint                digits;
  407.  
  408.   g_return_if_fail (GIMP_IS_SIZE_ENTRY (gse));
  409.   g_return_if_fail (GTK_IS_SPIN_BUTTON (value_spinbutton));
  410.  
  411.   if (gse->show_refval)
  412.     {
  413.       g_return_if_fail (GTK_IS_SPIN_BUTTON (refval_spinbutton));
  414.     }
  415.  
  416.   gsef = g_new0 (GimpSizeEntryField, 1);
  417.  
  418.   gse->fields = g_slist_prepend (gse->fields, gsef);
  419.   gse->number_of_fields++;
  420.  
  421.   gsef->gse            = gse;
  422.   gsef->resolution     = 1.0; /*  just to avoid division by zero  */
  423.   gsef->lower          = 0.0;
  424.   gsef->upper          = 100.0;
  425.   gsef->value          = 0;
  426.   gsef->min_value      = 0;
  427.   gsef->max_value      = SIZE_MAX_VALUE;
  428.   gsef->refval         = 0;
  429.   gsef->min_refval     = 0;
  430.   gsef->max_refval     = SIZE_MAX_VALUE;
  431.   gsef->refval_digits  =
  432.     (gse->update_policy == GIMP_SIZE_ENTRY_UPDATE_SIZE) ? 0 : 3;
  433.   gsef->stop_recursion = 0;
  434.  
  435.   gsef->value_adjustment =
  436.     GTK_OBJECT (gtk_spin_button_get_adjustment (value_spinbutton));
  437.   gsef->value_spinbutton = GTK_WIDGET (value_spinbutton);
  438.   g_signal_connect (gsef->value_adjustment, "value_changed",
  439.                     G_CALLBACK (gimp_size_entry_value_callback),
  440.                     gsef);
  441.  
  442.   if (gse->show_refval)
  443.     {
  444.       gsef->refval_adjustment =
  445.     GTK_OBJECT (gtk_spin_button_get_adjustment (refval_spinbutton));
  446.       gsef->refval_spinbutton = GTK_WIDGET (refval_spinbutton);
  447.       g_signal_connect (gsef->refval_adjustment, "value_changed",
  448.                         G_CALLBACK (gimp_size_entry_refval_callback),
  449.                         gsef);
  450.     }
  451.  
  452.   digits = ((gse->unit == GIMP_UNIT_PIXEL) ? gsef->refval_digits :
  453.             (gse->unit == GIMP_UNIT_PERCENT) ? 2 :
  454.             GIMP_SIZE_ENTRY_DIGITS (gse->unit));
  455.  
  456.   gtk_spin_button_set_digits (GTK_SPIN_BUTTON (value_spinbutton), digits);
  457.  
  458.   if (gse->menu_show_pixels &&
  459.       !gse->show_refval &&
  460.       (gse->unit == GIMP_UNIT_PIXEL))
  461.     {
  462.       gtk_spin_button_set_digits (GTK_SPIN_BUTTON (gsef->value_spinbutton),
  463.                   gsef->refval_digits);
  464.     }
  465. }
  466.  
  467. /**
  468.  * gimp_size_entry_attach_label:
  469.  * @gse:       The sizeentry you want to add a label to.
  470.  * @text:      The text of the label.
  471.  * @row:       The row where the label will be attached.
  472.  * @column:    The column where the label will be attached.
  473.  * @alignment: The horizontal alignment of the label.
  474.  *
  475.  * Attaches a #GtkLabel to the #GimpSizeEntry (which is a #GtkTable).
  476.  *
  477.  * Returns: A pointer to the new #GtkLabel widget.
  478.  **/
  479. GtkWidget *
  480. gimp_size_entry_attach_label (GimpSizeEntry *gse,
  481.                   const gchar   *text,
  482.                   gint           row,
  483.                   gint           column,
  484.                   gfloat         alignment)
  485. {
  486.   GtkWidget *label;
  487.  
  488.   g_return_val_if_fail (GIMP_IS_SIZE_ENTRY (gse), NULL);
  489.   g_return_val_if_fail (text != NULL, NULL);
  490.  
  491.   label = gtk_label_new_with_mnemonic (text);
  492.  
  493.   if (column == 0)
  494.     {
  495.       GtkTableChild *child;
  496.       GList         *list;
  497.  
  498.       for (list = GTK_TABLE (gse)->children; list; list = g_list_next (list))
  499.         {
  500.           child = (GtkTableChild *) list->data;
  501.  
  502.           if (child->left_attach == 1 && child->top_attach == row)
  503.             {
  504.               gtk_label_set_mnemonic_widget (GTK_LABEL (label),
  505.                                              child->widget);
  506.               break;
  507.             }
  508.         }
  509.     }
  510.  
  511.   gtk_misc_set_alignment (GTK_MISC (label), alignment, 0.5);
  512.  
  513.   gtk_table_attach (GTK_TABLE (gse), label, column, column+1, row, row+1,
  514.             GTK_SHRINK | GTK_FILL, GTK_SHRINK | GTK_FILL, 0, 0);
  515.   gtk_widget_show (label);
  516.  
  517.   return label;
  518. }
  519.  
  520.  
  521. /**
  522.  * gimp_size_entry_set_resolution:
  523.  * @gse:        The sizeentry you want to set a resolution for.
  524.  * @field:      The index of the field you want to set the resolution for.
  525.  * @resolution: The new resolution (in dpi) for the chosen @field.
  526.  * @keep_size:  %TRUE if the @field's size in pixels should stay the same.
  527.  *              %FALSE if the @field's size in units should stay the same.
  528.  *
  529.  * Sets the resolution (in dpi) for field # @field of the #GimpSizeEntry.
  530.  *
  531.  * The @resolution passed will be clamped to fit in
  532.  * [#GIMP_MIN_RESOLUTION..#GIMP_MAX_RESOLUTION].
  533.  *
  534.  * This function does nothing if the #GimpSizeEntryUpdatePolicy specified in
  535.  * gimp_size_entry_new() doesn't equal to #GIMP_SIZE_ENTRY_UPDATE_SIZE.
  536.  **/
  537. void
  538. gimp_size_entry_set_resolution (GimpSizeEntry *gse,
  539.                 gint           field,
  540.                 gdouble        resolution,
  541.                 gboolean       keep_size)
  542. {
  543.   GimpSizeEntryField *gsef;
  544.   gfloat              val;
  545.  
  546.   g_return_if_fail (GIMP_IS_SIZE_ENTRY (gse));
  547.   g_return_if_fail ((field >= 0) && (field < gse->number_of_fields));
  548.  
  549.   resolution = CLAMP (resolution, GIMP_MIN_RESOLUTION, GIMP_MAX_RESOLUTION);
  550.  
  551.   gsef = (GimpSizeEntryField*) g_slist_nth_data (gse->fields, field);
  552.   gsef->resolution = resolution;
  553.  
  554.   val = gsef->value;
  555.  
  556.   gsef->stop_recursion = 0;
  557.   gimp_size_entry_set_refval_boundaries (gse, field,
  558.                      gsef->min_refval, gsef->max_refval);
  559.  
  560.   if (! keep_size)
  561.     gimp_size_entry_set_value (gse, field, val);
  562. }
  563.  
  564.  
  565. /**
  566.  * gimp_size_entry_set_size:
  567.  * @gse:   The sizeentry you want to set a size for.
  568.  * @field: The index of the field you want to set the size for.
  569.  * @lower: The reference value which will be treated as 0%.
  570.  * @upper: The reference value which will be treated as 100%.
  571.  *
  572.  * Sets the pixel values for field # @field of the #GimpSizeEntry
  573.  * which will be treated as 0% and 100%.
  574.  *
  575.  * These values will be used if you specified @menu_show_percent as %TRUE
  576.  * in gimp_size_entry_new() and the user has selected GIMP_UNIT_PERCENT in
  577.  * the #GimpSizeEntry's #GimpUnitMenu.
  578.  *
  579.  * This function does nothing if the #GimpSizeEntryUpdatePolicy specified in
  580.  * gimp_size_entry_new() doesn't equal to GIMP_SIZE_ENTRY_UPDATE_SIZE.
  581.  **/
  582. void
  583. gimp_size_entry_set_size (GimpSizeEntry *gse,
  584.               gint           field,
  585.               gdouble        lower,
  586.               gdouble        upper)
  587. {
  588.   GimpSizeEntryField *gsef;
  589.  
  590.   g_return_if_fail (GIMP_IS_SIZE_ENTRY (gse));
  591.   g_return_if_fail ((field >= 0) && (field < gse->number_of_fields));
  592.   g_return_if_fail (lower <= upper);
  593.  
  594.   gsef = (GimpSizeEntryField*) g_slist_nth_data (gse->fields, field);
  595.   gsef->lower = lower;
  596.   gsef->upper = upper;
  597.  
  598.   gimp_size_entry_set_refval (gse, field, gsef->refval);
  599. }
  600.  
  601.  
  602. /**
  603.  * gimp_size_entry_set_value_boundaries:
  604.  * @gse:   The sizeentry you want to set value boundaries for.
  605.  * @field: The index of the field you want to set value boundaries for.
  606.  * @lower: The new lower boundary of the value of the chosen @field.
  607.  * @upper: The new upper boundary of the value of the chosen @field.
  608.  *
  609.  * Limits the range of possible values which can be entered in field # @field
  610.  * of the #GimpSizeEntry.
  611.  *
  612.  * The current value of the @field will be clamped to fit in the @field's
  613.  * new boundaries.
  614.  *
  615.  * NOTE: In most cases you won't be interested in these values because the
  616.  *       #GimpSizeEntry's purpose is to shield the programmer from unit
  617.  *       calculations. Use gimp_size_entry_set_refval_boundaries() instead.
  618.  *       Whatever you do, don't mix these calls. A size entry should either
  619.  *       be clamped by the value or the reference value.
  620.  **/
  621. void
  622. gimp_size_entry_set_value_boundaries (GimpSizeEntry *gse,
  623.                       gint           field,
  624.                       gdouble        lower,
  625.                       gdouble        upper)
  626. {
  627.   GimpSizeEntryField *gsef;
  628.  
  629.   g_return_if_fail (GIMP_IS_SIZE_ENTRY (gse));
  630.   g_return_if_fail ((field >= 0) && (field < gse->number_of_fields));
  631.   g_return_if_fail (lower <= upper);
  632.  
  633.   gsef = (GimpSizeEntryField*) g_slist_nth_data (gse->fields, field);
  634.   gsef->min_value        = lower;
  635.   gsef->max_value        = upper;
  636.  
  637.   GTK_ADJUSTMENT (gsef->value_adjustment)->lower = gsef->min_value;
  638.   GTK_ADJUSTMENT (gsef->value_adjustment)->upper = gsef->max_value;
  639.  
  640.   if (gsef->stop_recursion) /* this is a hack (but useful ;-) */
  641.     return;
  642.  
  643.   gsef->stop_recursion++;
  644.   switch (gsef->gse->update_policy)
  645.     {
  646.     case GIMP_SIZE_ENTRY_UPDATE_NONE:
  647.       break;
  648.  
  649.     case GIMP_SIZE_ENTRY_UPDATE_SIZE:
  650.       switch (gse->unit)
  651.     {
  652.     case GIMP_UNIT_PIXEL:
  653.       gimp_size_entry_set_refval_boundaries (gse, field,
  654.                          gsef->min_value,
  655.                          gsef->max_value);
  656.       break;
  657.     case GIMP_UNIT_PERCENT:
  658.       gimp_size_entry_set_refval_boundaries (gse, field,
  659.                          gsef->lower +
  660.                          (gsef->upper - gsef->lower) *
  661.                          gsef->min_value / 100,
  662.                          gsef->lower +
  663.                          (gsef->upper - gsef->lower) *
  664.                          gsef->max_value / 100);
  665.       break;
  666.     default:
  667.       gimp_size_entry_set_refval_boundaries (gse, field,
  668.                          gsef->min_value *
  669.                          gsef->resolution /
  670.                          gimp_unit_get_factor (gse->unit),
  671.                          gsef->max_value *
  672.                          gsef->resolution /
  673.                          gimp_unit_get_factor (gse->unit));
  674.       break;
  675.     }
  676.       break;
  677.  
  678.     case GIMP_SIZE_ENTRY_UPDATE_RESOLUTION:
  679.       gimp_size_entry_set_refval_boundaries (gse, field,
  680.                          gsef->min_value *
  681.                          gimp_unit_get_factor (gse->unit),
  682.                          gsef->max_value *
  683.                          gimp_unit_get_factor (gse->unit));
  684.       break;
  685.  
  686.     default:
  687.       break;
  688.     }
  689.   gsef->stop_recursion--;
  690.  
  691.   gimp_size_entry_set_value (gse, field, gsef->value);
  692. }
  693.  
  694. /**
  695.  * gimp_size_entry_get_value;
  696.  * @gse:   The sizeentry you want to know a value of.
  697.  * @field: The index of the field you want to know the value of.
  698.  *
  699.  * Returns the value of field # @field of the #GimpSizeEntry.
  700.  *
  701.  * The @value returned is a distance or resolution
  702.  * in the #GimpUnit the user has selected in the #GimpSizeEntry's
  703.  * #GimpUnitMenu.
  704.  *
  705.  * NOTE: In most cases you won't be interested in this value because the
  706.  *       #GimpSizeEntry's purpose is to shield the programmer from unit
  707.  *       calculations. Use gimp_size_entry_get_refval() instead.
  708.  *
  709.  * Returns: The value of the chosen @field.
  710.  **/
  711. gdouble
  712. gimp_size_entry_get_value (GimpSizeEntry *gse,
  713.                gint           field)
  714. {
  715.   GimpSizeEntryField *gsef;
  716.  
  717.   g_return_val_if_fail (GIMP_IS_SIZE_ENTRY (gse), 0);
  718.   g_return_val_if_fail ((field >= 0) && (field < gse->number_of_fields), 0);
  719.  
  720.   gsef = (GimpSizeEntryField *) g_slist_nth_data (gse->fields, field);
  721.   return gsef->value;
  722. }
  723.  
  724. static void
  725. gimp_size_entry_update_value (GimpSizeEntryField *gsef,
  726.                   gdouble             value)
  727. {
  728.   if (gsef->stop_recursion > 1)
  729.     return;
  730.  
  731.   gsef->value = value;
  732.  
  733.   switch (gsef->gse->update_policy)
  734.     {
  735.     case GIMP_SIZE_ENTRY_UPDATE_NONE:
  736.       break;
  737.  
  738.     case GIMP_SIZE_ENTRY_UPDATE_SIZE:
  739.       switch (gsef->gse->unit)
  740.     {
  741.     case GIMP_UNIT_PIXEL:
  742.       gsef->refval = value;
  743.       break;
  744.     case GIMP_UNIT_PERCENT:
  745.       gsef->refval =
  746.         CLAMP (gsef->lower + (gsef->upper - gsef->lower) * value / 100,
  747.            gsef->min_refval, gsef->max_refval);
  748.       break;
  749.     default:
  750.       gsef->refval =
  751.         CLAMP (value * gsef->resolution /
  752.            gimp_unit_get_factor (gsef->gse->unit),
  753.            gsef->min_refval, gsef->max_refval);
  754.       break;
  755.     }
  756.       if (gsef->gse->show_refval)
  757.     gtk_adjustment_set_value (GTK_ADJUSTMENT (gsef->refval_adjustment),
  758.                   gsef->refval);
  759.       break;
  760.  
  761.     case GIMP_SIZE_ENTRY_UPDATE_RESOLUTION:
  762.       gsef->refval =
  763.     CLAMP (value * gimp_unit_get_factor (gsef->gse->unit),
  764.            gsef->min_refval, gsef->max_refval);
  765.       if (gsef->gse->show_refval)
  766.     gtk_adjustment_set_value (GTK_ADJUSTMENT (gsef->refval_adjustment),
  767.                   gsef->refval);
  768.       break;
  769.  
  770.     default:
  771.       break;
  772.     }
  773.  
  774.   g_signal_emit (gsef->gse, gimp_size_entry_signals[VALUE_CHANGED], 0);
  775. }
  776.  
  777. /**
  778.  * gimp_size_entry_set_value;
  779.  * @gse:   The sizeentry you want to set a value for.
  780.  * @field: The index of the field you want to set a value for.
  781.  * @value: The new value for @field.
  782.  *
  783.  * Sets the value for field # @field of the #GimpSizeEntry.
  784.  *
  785.  * The @value passed is treated to be a distance or resolution
  786.  * in the #GimpUnit the user has selected in the #GimpSizeEntry's
  787.  * #GimpUnitMenu.
  788.  *
  789.  * NOTE: In most cases you won't be interested in this value because the
  790.  *       #GimpSizeEntry's purpose is to shield the programmer from unit
  791.  *       calculations. Use gimp_size_entry_set_refval() instead.
  792.  **/
  793. void
  794. gimp_size_entry_set_value (GimpSizeEntry *gse,
  795.                gint           field,
  796.                gdouble        value)
  797. {
  798.   GimpSizeEntryField *gsef;
  799.  
  800.   g_return_if_fail (GIMP_IS_SIZE_ENTRY (gse));
  801.   g_return_if_fail ((field >= 0) && (field < gse->number_of_fields));
  802.  
  803.   gsef = (GimpSizeEntryField *) g_slist_nth_data (gse->fields, field);
  804.  
  805.   value = CLAMP (value, gsef->min_value, gsef->max_value);
  806.  
  807.   gtk_adjustment_set_value (GTK_ADJUSTMENT (gsef->value_adjustment), value);
  808.   gimp_size_entry_update_value (gsef, value);
  809. }
  810.  
  811.  
  812. static void
  813. gimp_size_entry_value_callback (GtkWidget *widget,
  814.                 gpointer   data)
  815. {
  816.   GimpSizeEntryField *gsef;
  817.   gdouble             new_value;
  818.  
  819.   gsef = (GimpSizeEntryField *) data;
  820.  
  821.   new_value = GTK_ADJUSTMENT (widget)->value;
  822.  
  823.   if (gsef->value != new_value)
  824.     gimp_size_entry_update_value (gsef, new_value);
  825. }
  826.  
  827.  
  828. /**
  829.  * gimp_size_entry_set_refval_boundaries:
  830.  * @gse:   The sizeentry you want to set the reference value boundaries for.
  831.  * @field: The index of the field you want to set the reference value
  832.  *         boundaries for.
  833.  * @lower: The new lower boundary of the reference value of the chosen @field.
  834.  * @upper: The new upper boundary of the reference value of the chosen @field.
  835.  *
  836.  * Limits the range of possible reference values which can be entered in
  837.  * field # @field of the #GimpSizeEntry.
  838.  *
  839.  * The current reference value of the @field will be clamped to fit in the
  840.  * @field's new boundaries.
  841.  **/
  842. void
  843. gimp_size_entry_set_refval_boundaries (GimpSizeEntry *gse,
  844.                                        gint           field,
  845.                                        gdouble        lower,
  846.                                        gdouble        upper)
  847. {
  848.   GimpSizeEntryField *gsef;
  849.  
  850.   g_return_if_fail (GIMP_IS_SIZE_ENTRY (gse));
  851.   g_return_if_fail ((field >= 0) && (field < gse->number_of_fields));
  852.   g_return_if_fail (lower <= upper);
  853.  
  854.   gsef = (GimpSizeEntryField *) g_slist_nth_data (gse->fields, field);
  855.   gsef->min_refval = lower;
  856.   gsef->max_refval = upper;
  857.  
  858.   if (gse->show_refval)
  859.     {
  860.       GTK_ADJUSTMENT (gsef->refval_adjustment)->lower = gsef->min_refval;
  861.       GTK_ADJUSTMENT (gsef->refval_adjustment)->upper = gsef->max_refval;
  862.     }
  863.  
  864.   if (gsef->stop_recursion) /* this is a hack (but useful ;-) */
  865.     return;
  866.  
  867.   gsef->stop_recursion++;
  868.   switch (gsef->gse->update_policy)
  869.     {
  870.     case GIMP_SIZE_ENTRY_UPDATE_NONE:
  871.       break;
  872.  
  873.     case GIMP_SIZE_ENTRY_UPDATE_SIZE:
  874.       switch (gse->unit)
  875.     {
  876.     case GIMP_UNIT_PIXEL:
  877.       gimp_size_entry_set_value_boundaries (gse, field,
  878.                         gsef->min_refval,
  879.                         gsef->max_refval);
  880.       break;
  881.     case GIMP_UNIT_PERCENT:
  882.       gimp_size_entry_set_value_boundaries (gse, field,
  883.                         100 * (gsef->min_refval -
  884.                                gsef->lower) /
  885.                         (gsef->upper - gsef->lower),
  886.                         100 * (gsef->max_refval -
  887.                                gsef->lower) /
  888.                         (gsef->upper - gsef->lower));
  889.       break;
  890.     default:
  891.       gimp_size_entry_set_value_boundaries (gse, field,
  892.                         gsef->min_refval *
  893.                         gimp_unit_get_factor (gse->unit) /
  894.                         gsef->resolution,
  895.                         gsef->max_refval *
  896.                         gimp_unit_get_factor (gse->unit) /
  897.                         gsef->resolution);
  898.       break;
  899.     }
  900.       break;
  901.  
  902.     case GIMP_SIZE_ENTRY_UPDATE_RESOLUTION:
  903.       gimp_size_entry_set_value_boundaries (gse, field,
  904.                         gsef->min_refval /
  905.                         gimp_unit_get_factor (gse->unit),
  906.                         gsef->max_refval /
  907.                         gimp_unit_get_factor (gse->unit));
  908.       break;
  909.  
  910.     default:
  911.       break;
  912.     }
  913.   gsef->stop_recursion--;
  914.  
  915.   gimp_size_entry_set_refval (gse, field, gsef->refval);
  916. }
  917.  
  918. /**
  919.  * gimp_size_entry_set_refval_digits:
  920.  * @gse:    The sizeentry you want to set the reference value digits for.
  921.  * @field:  The index of the field you want to set the reference value for.
  922.  * @digits: The new number of decimal digits for the #GtkSpinButton which
  923.  *          displays @field's reference value.
  924.  *
  925.  * Sets the decimal digits of field # @field of the #GimpSizeEntry to
  926.  * @digits.
  927.  *
  928.  * If you don't specify this value explicitly, the reference value's number
  929.  * of digits will equal to 0 for #GIMP_SIZE_ENTRY_UPDATE_SIZE and to 2 for
  930.  * #GIMP_SIZE_ENTRY_UPDATE_RESOLUTION.
  931.  **/
  932. void
  933. gimp_size_entry_set_refval_digits (GimpSizeEntry *gse,
  934.                    gint           field,
  935.                    gint           digits)
  936. {
  937.   GimpSizeEntryField *gsef;
  938.  
  939.   g_return_if_fail (GIMP_IS_SIZE_ENTRY (gse));
  940.   g_return_if_fail ((field >= 0) && (field < gse->number_of_fields));
  941.   g_return_if_fail ((digits >= 0) && (digits <= 6));
  942.  
  943.   gsef = (GimpSizeEntryField*) g_slist_nth_data (gse->fields, field);
  944.   gsef->refval_digits = digits;
  945.  
  946.   if (gse->update_policy == GIMP_SIZE_ENTRY_UPDATE_SIZE)
  947.     {
  948.       if (gse->show_refval)
  949.     gtk_spin_button_set_digits (GTK_SPIN_BUTTON (gsef->refval_spinbutton),
  950.                     gsef->refval_digits);
  951.       else if (gse->unit == GIMP_UNIT_PIXEL)
  952.     gtk_spin_button_set_digits (GTK_SPIN_BUTTON (gsef->value_spinbutton),
  953.                     gsef->refval_digits);
  954.     }
  955. }
  956.  
  957. /**
  958.  * gimp_size_entry_get_refval;
  959.  * @gse:   The sizeentry you want to know a reference value of.
  960.  * @field: The index of the field you want to know the reference value of.
  961.  *
  962.  * Returns the reference value for field # @field of the #GimpSizeEntry.
  963.  *
  964.  * The reference value is either a distance in pixels or a resolution
  965.  * in dpi, depending on which #GimpSizeEntryUpdatePolicy you chose in
  966.  * gimp_size_entry_new().
  967.  *
  968.  * Returns: The reference value of the chosen @field.
  969.  **/
  970. gdouble
  971. gimp_size_entry_get_refval (GimpSizeEntry *gse,
  972.                 gint           field)
  973. {
  974.   GimpSizeEntryField *gsef;
  975.  
  976.   /*  return 1.0 to avoid division by zero  */
  977.   g_return_val_if_fail (GIMP_IS_SIZE_ENTRY (gse), 1.0);
  978.   g_return_val_if_fail ((field >= 0) && (field < gse->number_of_fields), 1.0);
  979.  
  980.   gsef = (GimpSizeEntryField*) g_slist_nth_data (gse->fields, field);
  981.   return gsef->refval;
  982. }
  983.  
  984. static void
  985. gimp_size_entry_update_refval (GimpSizeEntryField *gsef,
  986.                    gdouble             refval)
  987. {
  988.   if (gsef->stop_recursion > 1)
  989.     return;
  990.  
  991.   gsef->refval = refval;
  992.  
  993.   switch (gsef->gse->update_policy)
  994.     {
  995.     case GIMP_SIZE_ENTRY_UPDATE_NONE:
  996.       break;
  997.  
  998.     case GIMP_SIZE_ENTRY_UPDATE_SIZE:
  999.       switch (gsef->gse->unit)
  1000.     {
  1001.     case GIMP_UNIT_PIXEL:
  1002.       gsef->value = refval;
  1003.       break;
  1004.     case GIMP_UNIT_PERCENT:
  1005.       gsef->value =
  1006.         CLAMP (100 * (refval - gsef->lower) / (gsef->upper - gsef->lower),
  1007.            gsef->min_value, gsef->max_value);
  1008.       break;
  1009.     default:
  1010.       gsef->value =
  1011.         CLAMP (refval * gimp_unit_get_factor (gsef->gse->unit) /
  1012.            gsef->resolution,
  1013.            gsef->min_value, gsef->max_value);
  1014.       break;
  1015.     }
  1016.       gtk_adjustment_set_value (GTK_ADJUSTMENT (gsef->value_adjustment),
  1017.                 gsef->value);
  1018.       break;
  1019.  
  1020.     case GIMP_SIZE_ENTRY_UPDATE_RESOLUTION:
  1021.       gsef->value =
  1022.     CLAMP (refval / gimp_unit_get_factor (gsef->gse->unit),
  1023.            gsef->min_value, gsef->max_value);
  1024.       gtk_adjustment_set_value (GTK_ADJUSTMENT (gsef->value_adjustment),
  1025.                 gsef->value);
  1026.       break;
  1027.  
  1028.     default:
  1029.       break;
  1030.     }
  1031.  
  1032.   g_signal_emit (gsef->gse, gimp_size_entry_signals[REFVAL_CHANGED], 0);
  1033. }
  1034.  
  1035. /**
  1036.  * gimp_size_entry_set_refval;
  1037.  * @gse:    The sizeentry you want to set a reference value for.
  1038.  * @field:  The index of the field you want to set the reference value for.
  1039.  * @refval: The new reference value for @field.
  1040.  *
  1041.  * Sets the reference value for field # @field of the #GimpSizeEntry.
  1042.  *
  1043.  * The @refval passed is either a distance in pixels or a resolution in dpi,
  1044.  * depending on which #GimpSizeEntryUpdatePolicy you chose in
  1045.  * gimp_size_entry_new().
  1046.  **/
  1047. void
  1048. gimp_size_entry_set_refval (GimpSizeEntry *gse,
  1049.                 gint           field,
  1050.                 gdouble        refval)
  1051. {
  1052.   GimpSizeEntryField *gsef;
  1053.  
  1054.   g_return_if_fail (GIMP_IS_SIZE_ENTRY (gse));
  1055.   g_return_if_fail ((field >= 0) && (field < gse->number_of_fields));
  1056.  
  1057.   gsef = (GimpSizeEntryField *) g_slist_nth_data (gse->fields, field);
  1058.  
  1059.   refval = CLAMP (refval, gsef->min_refval, gsef->max_refval);
  1060.  
  1061.   if (gse->show_refval)
  1062.     gtk_adjustment_set_value (GTK_ADJUSTMENT (gsef->refval_adjustment),
  1063.                               refval);
  1064.  
  1065.   gimp_size_entry_update_refval (gsef, refval);
  1066. }
  1067.  
  1068. static void
  1069. gimp_size_entry_refval_callback (GtkWidget *widget,
  1070.                  gpointer   data)
  1071. {
  1072.   GimpSizeEntryField *gsef;
  1073.   gdouble             new_refval;
  1074.  
  1075.   gsef = (GimpSizeEntryField *) data;
  1076.  
  1077.   new_refval = GTK_ADJUSTMENT (widget)->value;
  1078.  
  1079.   if (gsef->refval != new_refval)
  1080.     gimp_size_entry_update_refval (gsef, new_refval);
  1081. }
  1082.  
  1083.  
  1084. /**
  1085.  * gimp_size_entry_get_unit:
  1086.  * @gse: The sizeentry you want to know the unit of.
  1087.  *
  1088.  * Returns the #GimpUnit the user has selected in the #GimpSizeEntry's
  1089.  * #GimpUnitMenu.
  1090.  *
  1091.  * Returns: The sizeentry's unit.
  1092.  **/
  1093. GimpUnit
  1094. gimp_size_entry_get_unit (GimpSizeEntry *gse)
  1095. {
  1096.   g_return_val_if_fail (GIMP_IS_SIZE_ENTRY (gse), GIMP_UNIT_INCH);
  1097.  
  1098.   return gse->unit;
  1099. }
  1100.  
  1101. static void
  1102. gimp_size_entry_update_unit (GimpSizeEntry *gse,
  1103.                  GimpUnit       unit)
  1104. {
  1105.   GimpSizeEntryField *gsef;
  1106.   gint                i;
  1107.   gint                digits;
  1108.  
  1109.   gse->unit = unit;
  1110.  
  1111.   digits = gimp_unit_menu_get_pixel_digits (GIMP_UNIT_MENU (gse->unitmenu));
  1112.  
  1113.   for (i = 0; i < gse->number_of_fields; i++)
  1114.     {
  1115.       gsef = (GimpSizeEntryField *) g_slist_nth_data (gse->fields, i);
  1116.  
  1117.       if (gse->update_policy == GIMP_SIZE_ENTRY_UPDATE_SIZE)
  1118.     {
  1119.       if (unit == GIMP_UNIT_PIXEL)
  1120.         gtk_spin_button_set_digits (GTK_SPIN_BUTTON (gsef->value_spinbutton),
  1121.                     gsef->refval_digits + digits);
  1122.       else if (unit == GIMP_UNIT_PERCENT)
  1123.         gtk_spin_button_set_digits (GTK_SPIN_BUTTON (gsef->value_spinbutton),
  1124.                     2 + digits);
  1125.       else
  1126.         gtk_spin_button_set_digits (GTK_SPIN_BUTTON (gsef->value_spinbutton),
  1127.                     GIMP_SIZE_ENTRY_DIGITS (unit) + digits);
  1128.     }
  1129.       else if (gse->update_policy == GIMP_SIZE_ENTRY_UPDATE_RESOLUTION)
  1130.     {
  1131.       digits = (gimp_unit_get_digits (GIMP_UNIT_INCH) -
  1132.                     gimp_unit_get_digits (unit));
  1133.       gtk_spin_button_set_digits (GTK_SPIN_BUTTON (gsef->value_spinbutton),
  1134.                       MAX (3 + digits, 3));
  1135.     }
  1136.  
  1137.       gsef->stop_recursion = 0; /* hack !!! */
  1138.  
  1139.       gimp_size_entry_set_refval_boundaries (gse, i,
  1140.                                              gsef->min_refval,
  1141.                                              gsef->max_refval);
  1142.     }
  1143.  
  1144.   g_signal_emit (gse, gimp_size_entry_signals[UNIT_CHANGED], 0);
  1145. }
  1146.  
  1147.  
  1148. /**
  1149.  * gimp_size_entry_set_unit:
  1150.  * @gse:  The sizeentry you want to change the unit for.
  1151.  * @unit: The new unit.
  1152.  *
  1153.  * Sets the #GimpSizeEntry's unit. The reference value for all fields will
  1154.  * stay the same but the value in units or pixels per unit will change
  1155.  * according to which #GimpSizeEntryUpdatePolicy you chose in
  1156.  * gimp_size_entry_new().
  1157.  **/
  1158. void
  1159. gimp_size_entry_set_unit (GimpSizeEntry *gse,
  1160.               GimpUnit       unit)
  1161. {
  1162.   g_return_if_fail (GIMP_IS_SIZE_ENTRY (gse));
  1163.   g_return_if_fail (gse->menu_show_pixels || (unit != GIMP_UNIT_PIXEL));
  1164.   g_return_if_fail (gse->menu_show_percent || (unit != GIMP_UNIT_PERCENT));
  1165.  
  1166.   gimp_unit_menu_set_unit (GIMP_UNIT_MENU (gse->unitmenu), unit);
  1167.   gimp_size_entry_update_unit (gse, unit);
  1168. }
  1169.  
  1170. static void
  1171. gimp_size_entry_unit_callback (GtkWidget     *widget,
  1172.                    GimpSizeEntry *gse)
  1173. {
  1174.   GimpUnit new_unit;
  1175.  
  1176.   new_unit = gimp_unit_menu_get_unit (GIMP_UNIT_MENU (widget));
  1177.  
  1178.   if (gse->unit != new_unit)
  1179.     gimp_size_entry_update_unit (gse, new_unit);
  1180. }
  1181.  
  1182.  
  1183. /**
  1184.  * gimp_size_entry_set_pixel_digits:
  1185.  * @gse: a #GimpSizeEntry
  1186.  * @digits: the number of digits to display for a pixel size
  1187.  *
  1188.  * Similar to gimp_unit_menu_set_pixel_digits(), this function allows
  1189.  * you set up a #GimpSizeEntry so that sub-pixel sizes can be entered.
  1190.  **/
  1191. void
  1192. gimp_size_entry_set_pixel_digits (GimpSizeEntry *gse,
  1193.                                   gint           digits)
  1194. {
  1195.   GimpUnitMenu *menu;
  1196.  
  1197.   g_return_if_fail (GIMP_IS_SIZE_ENTRY (gse));
  1198.  
  1199.   menu = GIMP_UNIT_MENU (gse->unitmenu);
  1200.  
  1201.   gimp_unit_menu_set_pixel_digits (menu, digits);
  1202.   gimp_size_entry_update_unit (gse, gimp_unit_menu_get_unit (menu));
  1203. }
  1204.  
  1205.  
  1206. /**
  1207.  * gimp_size_entry_grab_focus:
  1208.  * @gse: The sizeentry you want to grab the keyboard focus.
  1209.  *
  1210.  * This function is rather ugly and just a workaround for the fact that
  1211.  * it's impossible to implement gtk_widget_grab_focus() for a #GtkTable.
  1212.  **/
  1213. void
  1214. gimp_size_entry_grab_focus (GimpSizeEntry *gse)
  1215. {
  1216.   GimpSizeEntryField *gsef;
  1217.  
  1218.   g_return_if_fail (GIMP_IS_SIZE_ENTRY (gse));
  1219.  
  1220.   gsef = (GimpSizeEntryField*) gse->fields->data;
  1221.  
  1222.   gtk_widget_grab_focus (gse->show_refval ?
  1223.              gsef->refval_spinbutton : gsef->value_spinbutton);
  1224. }
  1225.  
  1226. /**
  1227.  * gimp_size_entry_get_help_widget:
  1228.  * @gse: a #GimpSizeEntry
  1229.  * @field: the index of the widget you want to get a pointer to
  1230.  *
  1231.  * You shouldn't fiddle with the internals of a #GimpSizeEntry but
  1232.  * if you want to set tooltips using gimp_help_set_help_data() you
  1233.  * can use this function to get a pointer to the spinbuttons.
  1234.  *
  1235.  * Return value: a #GtkWidget pointer that you can attach a tooltip to.
  1236.  **/
  1237. GtkWidget *
  1238. gimp_size_entry_get_help_widget (GimpSizeEntry *gse,
  1239.                                  gint           field)
  1240. {
  1241.   GimpSizeEntryField *gsef;
  1242.  
  1243.   g_return_val_if_fail (GIMP_IS_SIZE_ENTRY (gse), NULL);
  1244.   g_return_val_if_fail ((field >= 0) && (field < gse->number_of_fields), NULL);
  1245.  
  1246.   gsef = g_slist_nth_data (gse->fields, field);
  1247.   if (!gsef)
  1248.     return NULL;
  1249.  
  1250.   return (gsef->refval_spinbutton ?
  1251.           gsef->refval_spinbutton : gsef->value_spinbutton);
  1252. }
  1253.