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