home *** CD-ROM | disk | FTP | other *** search
/ PC Pro 2002 April / pcpro0402.iso / essentials / graphics / Gimp / gimp-src-20001226.exe / src / gimp / libgimp / gimpwidgets.c < prev    next >
Encoding:
C/C++ Source or Header  |  2000-12-10  |  41.4 KB  |  1,399 lines

  1. /* LIBGIMP - The GIMP Library
  2.  * Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball
  3.  *
  4.  * gimpwidgets.c
  5.  * Copyright (C) 2000 Michael Natterer <mitch@gimp.org>
  6.  *
  7.  * This library is free software; you can redistribute it and/or
  8.  * modify it under the terms of the GNU Lesser General Public
  9.  * License as published by the Free Software Foundation; either
  10.  * version 2 of the License, or (at your option) any later version.
  11.  *
  12.  * This library is distributed in the hope that it will be useful,
  13.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  15.  * Library General Public License for more details.
  16.  *
  17.  * You should have received a copy of the GNU Lesser General Public
  18.  * License along with this library; if not, write to the
  19.  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
  20.  * Boston, MA 02111-1307, USA.
  21.  */
  22.  
  23. #include "config.h"
  24.  
  25. #include <gtk/gtk.h>
  26.  
  27. #include "gimpchainbutton.h"
  28. #include "gimphelpui.h"
  29. #include "gimppixmap.h"
  30. #include "gimpunitmenu.h"
  31. #include "gimpwidgets.h"
  32. #include "gimpmath.h"
  33.  
  34. #include "libgimp-intl.h"
  35.  
  36.  
  37. /*
  38.  *  Widget Constructors
  39.  */
  40.  
  41. /**
  42.  * gimp_option_menu_new:
  43.  * @menu_only: #TRUE if the function should return a #GtkMenu only.
  44.  * @...:       A #NULL terminated @va_list describing the menu items.
  45.  *
  46.  * Returns: A #GtkOptionMenu or a #GtkMenu (depending on @menu_only).
  47.  **/
  48. GtkWidget *
  49. gimp_option_menu_new (gboolean            menu_only,
  50.  
  51.               /* specify menu items as va_list:
  52.                *  const gchar    *label,
  53.                *  GtkSignalFunc   callback,
  54.                *  gpointer        data,
  55.                *  gpointer        user_data,
  56.                *  GtkWidget     **widget_ptr,
  57.                *  gboolean        active
  58.                */
  59.  
  60.                ...)
  61. {
  62.   GtkWidget *menu;
  63.   GtkWidget *menuitem;
  64.  
  65.   /*  menu item variables  */
  66.   const gchar    *label;
  67.   GtkSignalFunc   callback;
  68.   gpointer        data;
  69.   gpointer        user_data;
  70.   GtkWidget     **widget_ptr;
  71.   gboolean        active;
  72.  
  73.   va_list args;
  74.   gint    i;
  75.   gint    initial_index;
  76.  
  77.   menu = gtk_menu_new ();
  78.  
  79.   /*  create the menu items  */
  80.   initial_index = 0;
  81.  
  82.   va_start (args, menu_only);
  83.   label = va_arg (args, const gchar *);
  84.  
  85.   for (i = 0; label; i++)
  86.     {
  87.       callback   = va_arg (args, GtkSignalFunc);
  88.       data       = va_arg (args, gpointer);
  89.       user_data  = va_arg (args, gpointer);
  90.       widget_ptr = va_arg (args, GtkWidget **);
  91.       active     = va_arg (args, gboolean);
  92.  
  93.       if (strcmp (label, "---"))
  94.     {
  95.       menuitem = gtk_menu_item_new_with_label (label);
  96.  
  97.       gtk_signal_connect (GTK_OBJECT (menuitem), "activate",
  98.                   callback,
  99.                   data);
  100.  
  101.       if (user_data)
  102.         gtk_object_set_user_data (GTK_OBJECT (menuitem), user_data);
  103.     }
  104.       else
  105.     {
  106.       menuitem = gtk_menu_item_new ();
  107.  
  108.       gtk_widget_set_sensitive (menuitem, FALSE);
  109.     }
  110.  
  111.       gtk_menu_append (GTK_MENU (menu), menuitem);
  112.  
  113.       if (widget_ptr)
  114.     *widget_ptr = menuitem;
  115.  
  116.       gtk_widget_show (menuitem);
  117.  
  118.       /*  remember the initial menu item  */
  119.       if (active)
  120.     initial_index = i;
  121.  
  122.       label = va_arg (args, const gchar *);
  123.     }
  124.   va_end (args);
  125.  
  126.   if (! menu_only)
  127.     {
  128.       GtkWidget *optionmenu;
  129.  
  130.       optionmenu = gtk_option_menu_new ();
  131.       gtk_option_menu_set_menu (GTK_OPTION_MENU (optionmenu), menu);
  132.  
  133.       /*  select the initial menu item  */
  134.       gtk_option_menu_set_history (GTK_OPTION_MENU (optionmenu), initial_index);
  135.  
  136.       return optionmenu;
  137.     }
  138.  
  139.   return menu;
  140. }
  141.  
  142. /**
  143.  * gimp_option_menu_new2:
  144.  * @menu_only:          #TRUE if the function should return a #GtkMenu only.
  145.  * @menu_item_callback: The callback each menu item's "activate" signal will
  146.  *                      be connected with.
  147.  * @data:               The data which will be passed to gtk_signal_connect().
  148.  * @initial:            The @user_data of the initially selected menu item.
  149.  * @...:                A #NULL terminated @va_list describing the menu items.
  150.  *
  151.  * Returns: A #GtkOptionMenu or a #GtkMenu (depending on @menu_only).
  152.  **/
  153. GtkWidget *
  154. gimp_option_menu_new2 (gboolean         menu_only,
  155.                GtkSignalFunc    menu_item_callback,
  156.                gpointer         data,
  157.                gpointer         initial, /* user_data */
  158.  
  159.                /* specify menu items as va_list:
  160.             *  const gchar *label,
  161.             *  gpointer     user_data,
  162.             *  GtkWidget  **widget_ptr,
  163.             */
  164.  
  165.                ...)
  166. {
  167.   GtkWidget *menu;
  168.   GtkWidget *menuitem;
  169.  
  170.   /*  menu item variables  */
  171.   const gchar  *label;
  172.   gpointer      user_data;
  173.   GtkWidget   **widget_ptr;
  174.  
  175.   va_list args;
  176.   gint    i;
  177.   gint    initial_index;
  178.  
  179.   menu = gtk_menu_new ();
  180.  
  181.   /*  create the menu items  */
  182.   initial_index = 0;
  183.  
  184.   va_start (args, initial);
  185.   label = va_arg (args, const gchar *);
  186.  
  187.   for (i = 0; label; i++)
  188.     {
  189.       user_data  = va_arg (args, gpointer);
  190.       widget_ptr = va_arg (args, GtkWidget **);
  191.  
  192.       if (strcmp (label, "---"))
  193.     {
  194.       menuitem = gtk_menu_item_new_with_label (label);
  195.  
  196.       gtk_signal_connect (GTK_OBJECT (menuitem), "activate",
  197.                   menu_item_callback,
  198.                   data);
  199.  
  200.       if (user_data)
  201.         gtk_object_set_user_data (GTK_OBJECT (menuitem), user_data);
  202.     }
  203.       else
  204.     {
  205.       menuitem = gtk_menu_item_new ();
  206.  
  207.       gtk_widget_set_sensitive (menuitem, FALSE);
  208.     }
  209.  
  210.       gtk_menu_append (GTK_MENU (menu), menuitem);
  211.  
  212.       if (widget_ptr)
  213.     *widget_ptr = menuitem;
  214.  
  215.       gtk_widget_show (menuitem);
  216.  
  217.       /*  remember the initial menu item  */
  218.       if (user_data == initial)
  219.     initial_index = i;
  220.  
  221.       label = va_arg (args, const gchar *);
  222.     }
  223.   va_end (args);
  224.  
  225.   if (! menu_only)
  226.     {
  227.       GtkWidget *optionmenu;
  228.  
  229.       optionmenu = gtk_option_menu_new ();
  230.       gtk_option_menu_set_menu (GTK_OPTION_MENU (optionmenu), menu);
  231.  
  232.       /*  select the initial menu item  */
  233.       gtk_option_menu_set_history (GTK_OPTION_MENU (optionmenu), initial_index);
  234.  
  235.       return optionmenu;
  236.     }
  237.  
  238.   return menu;
  239. }
  240.  
  241. /**
  242.  * gimp_option_menu_set_history:
  243.  * @option_menu: A #GtkOptionMenu as returned by gimp_option_menu_new() or
  244.  *               gimp_option_menu_new2().
  245.  * @user_data:   The @user_data of the menu item you want to select.
  246.  **/
  247. void
  248. gimp_option_menu_set_history (GtkOptionMenu *option_menu,
  249.                   gpointer       user_data)
  250. {
  251.   GtkWidget *menu_item;
  252.   GList     *list;
  253.   gint       history = 0;
  254.  
  255.   g_return_if_fail (option_menu);
  256.   g_return_if_fail (GTK_IS_OPTION_MENU (option_menu));
  257.  
  258.   for (list = GTK_MENU_SHELL (option_menu->menu)->children;
  259.        list;
  260.        list = g_list_next (list))
  261.     {
  262.       menu_item = GTK_WIDGET (list->data);
  263.  
  264.       if (GTK_IS_LABEL (GTK_BIN (menu_item)->child) &&
  265.       gtk_object_get_user_data (GTK_OBJECT (menu_item)) == user_data)
  266.     {
  267.       break;
  268.     }
  269.  
  270.       history++;
  271.     }
  272.  
  273.   if (list)
  274.     gtk_option_menu_set_history (option_menu, history);
  275. }
  276.  
  277. /**
  278.  * gimp_radio_group_new:
  279.  * @in_frame:    #TRUE if you want a #GtkFrame around the radio button group.
  280.  * @frame_title: The title of the Frame or #NULL if you don't want a title.
  281.  * @...:         A #NULL terminated @va_list describing the radio buttons.
  282.  *
  283.  * Returns: A #GtkFrame or #GtkVbox (depending on @in_frame).
  284.  **/
  285. GtkWidget *
  286. gimp_radio_group_new (gboolean            in_frame,
  287.               const gchar        *frame_title,
  288.  
  289.               /* specify radio buttons as va_list:
  290.                *  const gchar    *label,
  291.                *  GtkSignalFunc   callback,
  292.                *  gpointer        data,
  293.                *  gpointer        user_data,
  294.                *  GtkWidget     **widget_ptr,
  295.                *  gboolean        active,
  296.                */
  297.  
  298.               ...)
  299. {
  300.   GtkWidget *vbox;
  301.   GtkWidget *button;
  302.   GSList    *group;
  303.  
  304.   /*  radio button variables  */
  305.   const gchar    *label;
  306.   GtkSignalFunc   callback;
  307.   gpointer        data;
  308.   gpointer        user_data;
  309.   GtkWidget     **widget_ptr;
  310.   gboolean        active;
  311.  
  312.   va_list args;
  313.  
  314.   vbox = gtk_vbox_new (FALSE, 1);
  315.  
  316.   group = NULL;
  317.  
  318.   /*  create the radio buttons  */
  319.   va_start (args, frame_title);
  320.   label = va_arg (args, const gchar *);
  321.   while (label)
  322.     {
  323.       callback   = va_arg (args, GtkSignalFunc);
  324.       data       = va_arg (args, gpointer);
  325.       user_data  = va_arg (args, gpointer);
  326.       widget_ptr = va_arg (args, GtkWidget **);
  327.       active     = va_arg (args, gboolean);
  328.  
  329.       if (label != (gpointer) 1)
  330.     button = gtk_radio_button_new_with_label (group, label);
  331.       else
  332.     button = gtk_radio_button_new (group);
  333.  
  334.       group = gtk_radio_button_group (GTK_RADIO_BUTTON (button));
  335.       gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0);
  336.  
  337.       if (user_data)
  338.     gtk_object_set_user_data (GTK_OBJECT (button), user_data);
  339.  
  340.       if (widget_ptr)
  341.     *widget_ptr = button;
  342.  
  343.       if (active)
  344.     gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), TRUE);
  345.  
  346.       gtk_signal_connect (GTK_OBJECT (button), "toggled",
  347.               callback,
  348.               data);
  349.  
  350.       gtk_widget_show (button);
  351.  
  352.       label = va_arg (args, const gchar *);
  353.     }
  354.   va_end (args);
  355.  
  356.   if (in_frame)
  357.     {
  358.       GtkWidget *frame;
  359.  
  360.       gtk_container_set_border_width (GTK_CONTAINER (vbox), 2);
  361.  
  362.       frame = gtk_frame_new (frame_title);
  363.       gtk_container_add (GTK_CONTAINER (frame), vbox);
  364.       gtk_widget_show (vbox);
  365.  
  366.       return frame;
  367.     }
  368.  
  369.   return vbox;
  370. }
  371.  
  372. /**
  373.  * gimp_radio_group_new2:
  374.  * @in_frame:              #TRUE if you want a #GtkFrame around the
  375.  *                         radio button group.
  376.  * @frame_title:           The title of the Frame or #NULL if you don't want
  377.  *                         a title.
  378.  * @radio_button_callback: The callback each button's "toggled" signal will
  379.  *                         be connected with.
  380.  * @data:                  The data which will be passed to
  381.  *                         gtk_signal_connect().
  382.  * @initial:               The @user_data of the initially pressed radio button.
  383.  * @...:                   A #NULL terminated @va_list describing
  384.  *                         the radio buttons.
  385.  *
  386.  * Returns: A #GtkFrame or #GtkVbox (depending on @in_frame).
  387.  **/
  388. GtkWidget *
  389. gimp_radio_group_new2 (gboolean         in_frame,
  390.                const gchar     *frame_title,
  391.                GtkSignalFunc    radio_button_callback,
  392.                gpointer         data,
  393.                gpointer         initial, /* user_data */
  394.  
  395.                /* specify radio buttons as va_list:
  396.             *  const gchar *label,
  397.             *  gpointer     user_data,
  398.             *  GtkWidget  **widget_ptr,
  399.             */
  400.  
  401.                ...)
  402. {
  403.   GtkWidget *vbox;
  404.   GtkWidget *button;
  405.   GSList    *group;
  406.  
  407.   /*  radio button variables  */
  408.   const gchar *label;
  409.   gpointer     user_data;
  410.   GtkWidget  **widget_ptr;
  411.  
  412.   va_list args;
  413.  
  414.   vbox = gtk_vbox_new (FALSE, 1);
  415.  
  416.   group = NULL;
  417.  
  418.   /*  create the radio buttons  */
  419.   va_start (args, initial);
  420.   label = va_arg (args, const gchar *);
  421.  
  422.   while (label)
  423.     {
  424.       user_data  = va_arg (args, gpointer);
  425.       widget_ptr = va_arg (args, GtkWidget **);
  426.  
  427.       if (label != (gpointer) 1)
  428.     button = gtk_radio_button_new_with_label (group, label);
  429.       else
  430.     button = gtk_radio_button_new (group);
  431.  
  432.       group = gtk_radio_button_group (GTK_RADIO_BUTTON (button));
  433.       gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0);
  434.  
  435.       if (user_data)
  436.     gtk_object_set_user_data (GTK_OBJECT (button), user_data);
  437.  
  438.       if (widget_ptr)
  439.     *widget_ptr = button;
  440.  
  441.       if (initial == user_data)
  442.     gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), TRUE);
  443.  
  444.       gtk_signal_connect (GTK_OBJECT (button), "toggled",
  445.               radio_button_callback,
  446.               data);
  447.  
  448.       gtk_widget_show (button);
  449.  
  450.       label = va_arg (args, const gchar *);
  451.     }
  452.   va_end (args);
  453.  
  454.   if (in_frame)
  455.     {
  456.       GtkWidget *frame;
  457.  
  458.       gtk_container_set_border_width (GTK_CONTAINER (vbox), 2);
  459.  
  460.       frame = gtk_frame_new (frame_title);
  461.       gtk_container_add (GTK_CONTAINER (frame), vbox);
  462.       gtk_widget_show (vbox);
  463.  
  464.       return frame;
  465.     }
  466.  
  467.   return vbox;
  468. }
  469.  
  470. /**
  471.  * gimp_spin_button_new:
  472.  * @adjustment:     Returns the spinbutton's #GtkAdjustment.
  473.  * @value:          The initial value of the spinbutton.
  474.  * @lower:          The lower boundary.
  475.  * @upper:          The uppper boundary.
  476.  * @step_increment: The spinbutton's step increment.
  477.  * @page_increment: The spinbutton's page increment (mouse button 2).
  478.  * @page_size:      The spinbutton's page size.
  479.  * @climb_rate:     The spinbutton's climb rate.
  480.  * @digits:         The spinbutton's number of decimal digits.
  481.  *
  482.  * This function is a shortcut for gtk_adjustment_new() and a subsequent
  483.  * gtk_spin_button_new() and does some more initialisation stuff like
  484.  * setting a standard minimun horizontal size.
  485.  *
  486.  * Returns: A #GtkSpinbutton and it's #GtkAdjustment.
  487.  **/
  488. GtkWidget *
  489. gimp_spin_button_new (GtkObject **adjustment,  /* return value */
  490.               gfloat      value,
  491.               gfloat      lower,
  492.               gfloat      upper,
  493.               gfloat      step_increment,
  494.               gfloat      page_increment,
  495.               gfloat      page_size,
  496.               gfloat      climb_rate,
  497.               guint       digits)
  498. {
  499.   GtkWidget *spinbutton;
  500.  
  501.   *adjustment = gtk_adjustment_new (value, lower, upper,
  502.                     step_increment, page_increment, page_size);
  503.  
  504.   spinbutton = gtk_spin_button_new (GTK_ADJUSTMENT (*adjustment),
  505.                     climb_rate, digits);
  506.   gtk_spin_button_set_shadow_type (GTK_SPIN_BUTTON (spinbutton),
  507.                    GTK_SHADOW_NONE);
  508.   gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (spinbutton), TRUE);
  509.   gtk_widget_set_usize (spinbutton, 75, -1);
  510.  
  511.   return spinbutton;
  512. }
  513.  
  514. static void
  515. gimp_scale_entry_unconstrained_adjustment_callback (GtkAdjustment *adjustment,
  516.                             GtkAdjustment *other_adj)
  517. {
  518.   gtk_signal_handler_block_by_data (GTK_OBJECT (other_adj), adjustment);
  519.  
  520.   gtk_adjustment_set_value (other_adj, adjustment->value);
  521.  
  522.   gtk_signal_handler_unblock_by_data (GTK_OBJECT (other_adj), adjustment);
  523. }
  524.  
  525. /**
  526.  * gimp_scale_entry_new:
  527.  * @table:               The #GtkTable the widgets will be attached to.
  528.  * @column:              The column to start with.
  529.  * @row:                 The row to attach the widgets.
  530.  * @text:                The text for the #GtkLabel which will appear
  531.  *                       left of the #GtkHScale.
  532.  * @scale_usize:         The minimum horizontal size of the #GtkHScale.
  533.  * @spinbutton_usize:    The minimum horizontal size of the #GtkSpinButton.
  534.  * @value:               The initial value.
  535.  * @lower:               The lower boundary.
  536.  * @upper:               The upper boundary.
  537.  * @step_increment:      The step increment.
  538.  * @page_increment:      The page increment.
  539.  * @digits:              The number of decimal digits.
  540.  * @constrain:           #TRUE if the range of possible values of the
  541.  *                       #GtkSpinButton should be the same as of the #GtkHScale.
  542.  * @unconstrained_lower: The spinbutton's lower boundary
  543.  *                       if @constrain == #FALSE.
  544.  * @unconstrained_upper: The spinbutton's upper boundary
  545.  *                       if @constrain == #FALSE.
  546.  * @tooltip:             A tooltip message for the scale and the spinbutton.
  547.  * @help_data:           The widgets' help_data (see gimp_help_set_help_data()).
  548.  *
  549.  * This function creates a #GtkLabel, a #GtkHScale and a #GtkSpinButton and
  550.  * attaches them to a 3-column #GtkTable.
  551.  *
  552.  * Note that if you pass a @tooltip or @help_data to this function you'll
  553.  * have to initialize GIMP's help system with gimp_help_init() before using it.
  554.  *
  555.  * Returns: The #GtkSpinButton's #GtkAdjustment.
  556.  **/
  557. GtkObject *
  558. gimp_scale_entry_new (GtkTable    *table,
  559.               gint         column,
  560.               gint         row,
  561.               const gchar *text,
  562.               gint         scale_usize,
  563.               gint         spinbutton_usize,
  564.               gfloat       value,
  565.               gfloat       lower,
  566.               gfloat       upper,
  567.               gfloat       step_increment,
  568.               gfloat       page_increment,
  569.               guint        digits,
  570.               gboolean     constrain,
  571.               gfloat       unconstrained_lower,
  572.               gfloat       unconstrained_upper,
  573.               const gchar *tooltip,
  574.               const gchar *help_data)
  575. {
  576.   GtkWidget *label;
  577.   GtkWidget *scale;
  578.   GtkWidget *spinbutton;
  579.   GtkObject *adjustment;
  580.   GtkObject *return_adj;
  581.  
  582.   label = gtk_label_new (text);
  583.   gtk_misc_set_alignment (GTK_MISC (label), 1.0, 0.5);
  584.   gtk_table_attach (GTK_TABLE (table), label,
  585.                     column, column + 1, row, row + 1,
  586.                     GTK_FILL, GTK_FILL, 0, 0);
  587.   gtk_widget_show (label);
  588.  
  589.   if (! constrain &&
  590.       unconstrained_lower <= lower &&
  591.       unconstrained_upper >= upper)
  592.     {
  593.       GtkObject *constrained_adj;
  594.  
  595.       constrained_adj = gtk_adjustment_new (value, lower, upper,
  596.                         step_increment, page_increment,
  597.                         0.0);
  598.  
  599.       spinbutton = gimp_spin_button_new (&adjustment, value,
  600.                      unconstrained_lower,
  601.                      unconstrained_upper,
  602.                      step_increment, page_increment, 0.0,
  603.                      1.0, digits);
  604.  
  605.       gtk_signal_connect
  606.     (GTK_OBJECT (constrained_adj), "value_changed",
  607.      GTK_SIGNAL_FUNC (gimp_scale_entry_unconstrained_adjustment_callback),
  608.      adjustment);
  609.  
  610.       gtk_signal_connect
  611.     (GTK_OBJECT (adjustment), "value_changed",
  612.      GTK_SIGNAL_FUNC (gimp_scale_entry_unconstrained_adjustment_callback),
  613.      constrained_adj);
  614.  
  615.       return_adj = adjustment;
  616.  
  617.       adjustment = constrained_adj;
  618.     }
  619.   else
  620.     {
  621.       spinbutton = gimp_spin_button_new (&adjustment, value, lower, upper,
  622.                      step_increment, page_increment, 0.0,
  623.                      1.0, digits);
  624.  
  625.       return_adj = adjustment;
  626.     }
  627.     
  628.   if (spinbutton_usize > 0)
  629.     gtk_widget_set_usize (spinbutton, spinbutton_usize, -1);
  630.  
  631.   scale = gtk_hscale_new (GTK_ADJUSTMENT (adjustment));
  632.   if (scale_usize > 0)
  633.     gtk_widget_set_usize (scale, scale_usize, -1);
  634.   gtk_scale_set_digits (GTK_SCALE (scale), digits);
  635.   gtk_scale_set_draw_value (GTK_SCALE (scale), FALSE);
  636.   gtk_table_attach (GTK_TABLE (table), scale,
  637.             column + 1, column + 2, row, row + 1,
  638.             GTK_FILL | GTK_EXPAND, GTK_FILL, 0, 0);
  639.   gtk_widget_show (scale);
  640.  
  641.   gtk_table_attach (GTK_TABLE (table), spinbutton,
  642.             column + 2, column + 3, row, row + 1,
  643.             GTK_SHRINK, GTK_SHRINK, 0, 0);
  644.   gtk_widget_show (spinbutton);
  645.  
  646.   if (tooltip || help_data)
  647.     {
  648.       gimp_help_set_help_data (scale, tooltip, help_data);
  649.       gimp_help_set_help_data (spinbutton, tooltip, help_data);
  650.     }
  651.  
  652.   gtk_object_set_data (GTK_OBJECT (return_adj), "label", label);
  653.   gtk_object_set_data (GTK_OBJECT (return_adj), "scale", scale);
  654.   gtk_object_set_data (GTK_OBJECT (return_adj), "spinbutton", spinbutton);
  655.  
  656.   return return_adj;
  657. }
  658.  
  659. static void
  660. gimp_random_seed_toggle_update (GtkWidget *widget,
  661.                 gpointer   data)
  662. {
  663.   gint *toggle_val;
  664.  
  665.   toggle_val = (gint *) data;
  666.  
  667.   if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget)))
  668.     *toggle_val = GPOINTER_TO_INT (gtk_object_get_data (GTK_OBJECT (widget),
  669.                             "time_true"));
  670.   else
  671.     *toggle_val = GPOINTER_TO_INT (gtk_object_get_data (GTK_OBJECT (widget),
  672.                             "time_false"));
  673.  
  674.   gimp_toggle_button_sensitive_update (GTK_TOGGLE_BUTTON (widget));
  675. }
  676.  
  677. /**
  678.  * gimp_random_seed_new:
  679.  * @seed:       A pointer to the variable which stores the random seed.
  680.  * @use_time:   A pointer to the variable which stores the @use_time
  681.  *              toggle boolean.
  682.  * @time_true:  The value to write to @use_time if the toggle button is checked.
  683.  * @time_false: The value to write to @use_time if the toggle button is
  684.  *              unchecked.
  685.  *
  686.  * Note that this widget automatically sets tooltips with
  687.  * gimp_help_set_help_data(), so you'll have to initialize GIMP's help
  688.  * system with gimp_help_init() before using it.
  689.  *
  690.  * Returns: A #GtkHBox containing a #GtkSpinButton for the random seed and
  691.  *          a #GtkToggleButton for toggling the @use_time behaviour.
  692.  **/
  693. GtkWidget *
  694. gimp_random_seed_new (gint       *seed,
  695.               gint       *use_time,
  696.               gint        time_true,
  697.               gint        time_false)
  698. {
  699.   GtkWidget *hbox;
  700.   GtkWidget *spinbutton;
  701.   GtkObject *adj;
  702.   GtkWidget *button;
  703.  
  704.   hbox = gtk_hbox_new (FALSE, 4);
  705.  
  706.   spinbutton = gimp_spin_button_new (&adj, *seed,
  707.                                      0, G_MAXRAND, 1, 10, 0, 1, 0);
  708.   gtk_box_pack_start (GTK_BOX (hbox), spinbutton, FALSE, FALSE, 0);
  709.   gtk_signal_connect (GTK_OBJECT (adj), "value_changed",
  710.                       GTK_SIGNAL_FUNC (gimp_int_adjustment_update),
  711.                       seed);
  712.   gtk_widget_show (spinbutton);
  713.  
  714.   gimp_help_set_help_data (spinbutton,
  715.                            _("If the \"Time\" button is not pressed, "
  716.                              "use this value for random number generator "
  717.                              "seed - this allows you to repeat a "
  718.                              "given \"random\" operation"), NULL);
  719.  
  720.   button = gtk_toggle_button_new_with_label (_("Time"));
  721.   gtk_misc_set_padding (GTK_MISC (GTK_BIN (button)->child), 2, 0);
  722.   gtk_signal_connect (GTK_OBJECT (button), "toggled",
  723.                       GTK_SIGNAL_FUNC (gimp_random_seed_toggle_update),
  724.                       use_time);
  725.   gtk_box_pack_end (GTK_BOX (hbox), button, FALSE, FALSE, 0);
  726.   gtk_widget_show (button);
  727.  
  728.   gimp_help_set_help_data (button,
  729.                            _("Seed random number generator from the current "
  730.                              "time - this guarantees a reasonable "
  731.                              "randomization"), NULL);
  732.  
  733.   gtk_object_set_data (GTK_OBJECT (button), "time_true",
  734.                GINT_TO_POINTER (time_true));
  735.   gtk_object_set_data (GTK_OBJECT (button), "time_false",
  736.                GINT_TO_POINTER (time_false));
  737.  
  738.   gtk_object_set_data (GTK_OBJECT (button), "inverse_sensitive",
  739.                spinbutton);
  740.  
  741.   gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button),
  742.                                 *use_time == time_true);
  743.  
  744.   gtk_object_set_data (GTK_OBJECT (hbox), "spinbutton", spinbutton);
  745.   gtk_object_set_data (GTK_OBJECT (hbox), "togglebutton", button);
  746.  
  747.   return hbox;
  748. }
  749.  
  750. typedef struct
  751. {
  752.   GimpChainButton *chainbutton;
  753.   gboolean         chain_constrains_ratio;
  754.   gdouble          orig_x;
  755.   gdouble          orig_y;
  756.   gdouble          last_x;
  757.   gdouble          last_y;
  758. } GimpCoordinatesData;
  759.  
  760. static void
  761. gimp_coordinates_callback (GtkWidget *widget,
  762.                gpointer   data)
  763. {
  764.   GimpCoordinatesData *gcd;
  765.   gdouble new_x;
  766.   gdouble new_y;
  767.  
  768.   gcd = (GimpCoordinatesData *) data;
  769.  
  770.   new_x = gimp_size_entry_get_refval (GIMP_SIZE_ENTRY (widget), 0);
  771.   new_y = gimp_size_entry_get_refval (GIMP_SIZE_ENTRY (widget), 1);
  772.  
  773.   if (gimp_chain_button_get_active (gcd->chainbutton))
  774.     {
  775.       gtk_signal_emit_stop_by_name (GTK_OBJECT (widget), "value_changed");
  776.  
  777.       if (gcd->chain_constrains_ratio)
  778.     {
  779.       if ((gcd->orig_x != 0) && (gcd->orig_y != 0))
  780.         {
  781.           if (new_x != gcd->last_x)
  782.         {
  783.           gcd->last_x = new_x;
  784.           gcd->last_y = new_y = (new_x * gcd->orig_y) / gcd->orig_x;
  785.           gimp_size_entry_set_refval (GIMP_SIZE_ENTRY (widget), 1,
  786.                           new_y);
  787.         }
  788.           else if (new_y != gcd->last_y)
  789.         {
  790.           gcd->last_y = new_y;
  791.           gcd->last_x = new_x = (new_y * gcd->orig_x) / gcd->orig_y;
  792.           gimp_size_entry_set_refval (GIMP_SIZE_ENTRY (widget), 0,
  793.                           new_x);
  794.         }
  795.         }
  796.     }
  797.       else
  798.     {
  799.       if (new_x != gcd->last_x)
  800.         {
  801.           gcd->last_y = new_y = gcd->last_x = new_x;
  802.           gimp_size_entry_set_refval (GIMP_SIZE_ENTRY (widget), 1, new_x);
  803.         }
  804.       else if (new_y != gcd->last_y)
  805.         {
  806.           gcd->last_x = new_x = gcd->last_y = new_y;
  807.           gimp_size_entry_set_refval (GIMP_SIZE_ENTRY (widget), 0, new_y);
  808.         }
  809.     }
  810.     }
  811.   else
  812.     {
  813.       if (new_x != gcd->last_x)
  814.         gcd->last_x = new_x;
  815.       if (new_y != gcd->last_y)
  816.         gcd->last_y = new_y;
  817.     }     
  818. }
  819.  
  820. /**
  821.  * gimp_coordinates_new:
  822.  * @unit:                   The initial unit of the #GimpUnitMenu.
  823.  * @unit_format:            The unit format string as passed to
  824.  *                          gimp_size_entry_new().
  825.  * @menu_show_pixels:       #TRUE if the #GimpUnitMenu should contain an item for
  826.  *                          GIMP_UNIT_PIXEL.
  827.  * @menu_show_percent:      #TRUE if the #GimpUnitMenu should contain an item for
  828.  *                          GIMP_UNIT_PERCENT.
  829.  * @spinbutton_usize:       The horizontal usize of the #GimpSizeEntry's
  830.  *                           #GtkSpinButton's.
  831.  * @update_policy:          The update policy for the #GimpSizeEntry.
  832.  * @chainbutton_active:     #TRUE if the attached #GimpChainButton should be
  833.  *                          active.
  834.  * @chain_constrains_ratio: #TRUE if the chainbutton should constrain the
  835.  *                          fields' aspect ratio. If #FALSE, the values will
  836.  *                          be constrained.
  837.  * @xlabel:                 The label for the X coordinate.
  838.  * @x:                      The initial value of the X coordinate.
  839.  * @xres:                   The horizontal resolution in DPI.
  840.  * @lower_boundary_x:       The lower boundary of the X coordinate.
  841.  * @upper_boundary_x:       The upper boundary of the X coordinate.
  842.  * @xsize_0:                The X value which will be treated as 0%.
  843.  * @xsize_100:              The X value which will be treated as 100%.
  844.  * @ylabel:                 The label for the Y coordinate.
  845.  * @y:                      The initial value of the Y coordinate.
  846.  * @yres:                   The vertical resolution in DPI.
  847.  * @lower_boundary_y:       The lower boundary of the Y coordinate.
  848.  * @upper_boundary_y:       The upper boundary of the Y coordinate.
  849.  * @ysize_0:                The Y value which will be treated as 0%.
  850.  * @ysize_100:              The Y value which will be treated as 100%.
  851.  *
  852.  * Returns: A #GimpSizeEntry with two fields for x/y coordinates/sizes with
  853.  *          a #GimpChainButton attached to constrain either the two fields'
  854.  *          values or the ratio between them.
  855.  **/
  856. GtkWidget *
  857. gimp_coordinates_new (GimpUnit         unit,
  858.               const gchar     *unit_format,
  859.               gboolean         menu_show_pixels,
  860.               gboolean         menu_show_percent,
  861.               gint             spinbutton_usize,
  862.               GimpSizeEntryUpdatePolicy  update_policy,
  863.  
  864.               gboolean         chainbutton_active,
  865.               gboolean         chain_constrains_ratio,
  866.  
  867.               const gchar     *xlabel,
  868.               gdouble          x,
  869.               gdouble          xres,
  870.               gdouble          lower_boundary_x,
  871.               gdouble          upper_boundary_x,
  872.               gdouble          xsize_0,   /* % */
  873.               gdouble          xsize_100, /* % */
  874.  
  875.               const gchar     *ylabel,
  876.               gdouble          y,
  877.               gdouble          yres,
  878.               gdouble          lower_boundary_y,
  879.               gdouble          upper_boundary_y,
  880.               gdouble          ysize_0,   /* % */
  881.               gdouble          ysize_100  /* % */)
  882. {
  883.   GimpCoordinatesData *gcd;
  884.   GtkObject *adjustment;
  885.   GtkWidget *spinbutton;
  886.   GtkWidget *sizeentry;
  887.   GtkWidget *chainbutton;
  888.  
  889.   spinbutton = gimp_spin_button_new (&adjustment, 1, 0, 1, 1, 10, 1, 1, 2);
  890.   sizeentry = gimp_size_entry_new (1, unit, unit_format,
  891.                    menu_show_pixels,
  892.                    menu_show_percent,
  893.                    FALSE,
  894.                    spinbutton_usize,
  895.                    update_policy);
  896.   gtk_table_set_col_spacing (GTK_TABLE (sizeentry), 0, 4);  
  897.   gtk_table_set_col_spacing (GTK_TABLE (sizeentry), 2, 4);  
  898.   gimp_size_entry_add_field (GIMP_SIZE_ENTRY (sizeentry),
  899.                              GTK_SPIN_BUTTON (spinbutton), NULL);
  900.   gtk_table_attach_defaults (GTK_TABLE (sizeentry), spinbutton, 1, 2, 0, 1);
  901.   gtk_widget_show (spinbutton);
  902.  
  903.   gimp_size_entry_set_unit (GIMP_SIZE_ENTRY (sizeentry),
  904.                 (update_policy == GIMP_SIZE_ENTRY_UPDATE_RESOLUTION) || (menu_show_pixels == FALSE) ?
  905.                 GIMP_UNIT_INCH : GIMP_UNIT_PIXEL);
  906.  
  907.   gimp_size_entry_set_resolution (GIMP_SIZE_ENTRY (sizeentry), 0, xres, TRUE);
  908.   gimp_size_entry_set_resolution (GIMP_SIZE_ENTRY (sizeentry), 1, yres, TRUE);
  909.   gimp_size_entry_set_refval_boundaries (GIMP_SIZE_ENTRY (sizeentry), 0,
  910.                      lower_boundary_x, upper_boundary_x);
  911.   gimp_size_entry_set_refval_boundaries (GIMP_SIZE_ENTRY (sizeentry), 1,
  912.                      lower_boundary_y, upper_boundary_y);
  913.  
  914.   if (menu_show_percent)
  915.     {
  916.       gimp_size_entry_set_size (GIMP_SIZE_ENTRY (sizeentry), 0,
  917.                 xsize_0, xsize_100);
  918.       gimp_size_entry_set_size (GIMP_SIZE_ENTRY (sizeentry), 1,
  919.                 ysize_0, ysize_100);
  920.     }
  921.  
  922.   gimp_size_entry_set_refval (GIMP_SIZE_ENTRY (sizeentry), 0, x);
  923.   gimp_size_entry_set_refval (GIMP_SIZE_ENTRY (sizeentry), 1, y);
  924.  
  925.   gimp_size_entry_attach_label (GIMP_SIZE_ENTRY (sizeentry), xlabel, 0, 0, 1.0);
  926.   gimp_size_entry_attach_label (GIMP_SIZE_ENTRY (sizeentry), ylabel, 1, 0, 1.0);
  927.  
  928.   chainbutton = gimp_chain_button_new (GIMP_CHAIN_RIGHT);
  929.   if (chainbutton_active)
  930.     gimp_chain_button_set_active (GIMP_CHAIN_BUTTON (chainbutton), TRUE);
  931.   gtk_table_attach (GTK_TABLE (sizeentry), chainbutton, 2, 3, 0, 2,
  932.             GTK_SHRINK | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0);
  933.   gtk_widget_show (chainbutton);
  934.  
  935.   gcd = g_new (GimpCoordinatesData, 1);
  936.   gcd->chainbutton            = GIMP_CHAIN_BUTTON (chainbutton);
  937.   gcd->chain_constrains_ratio = chain_constrains_ratio;
  938.   gcd->orig_x                 = x;
  939.   gcd->orig_y                 = y;
  940.   gcd->last_x                 = x;
  941.   gcd->last_y                 = y;
  942.  
  943.   gtk_signal_connect_object (GTK_OBJECT (sizeentry), "destroy",
  944.                  GTK_SIGNAL_FUNC (g_free),
  945.                  (GtkObject *) gcd);
  946.  
  947.   gtk_signal_connect (GTK_OBJECT (sizeentry), "value_changed", 
  948.                       GTK_SIGNAL_FUNC (gimp_coordinates_callback),
  949.                       gcd);
  950.  
  951.   gtk_object_set_data (GTK_OBJECT (sizeentry), "chainbutton", chainbutton);
  952.  
  953.   return sizeentry;
  954. }
  955.  
  956. typedef struct
  957. {
  958.   GtkAdjustment *adjustment;
  959.   GtkAdjustment *divided_adj;
  960.   guint          mem_size_unit;
  961. } GimpMemSizeEntryData;
  962.  
  963. static void
  964. gimp_mem_size_entry_callback (GtkAdjustment *adj,
  965.                   gpointer       data)
  966. {
  967.   GimpMemSizeEntryData *gmsed;
  968.   guint new_value;
  969.  
  970.   gmsed = (GimpMemSizeEntryData *)data;
  971.   new_value = adj->value * gmsed->mem_size_unit;
  972.  
  973.   gtk_adjustment_set_value (gmsed->adjustment, new_value);
  974. }
  975.  
  976. static void
  977. gimp_mem_size_unit_callback (GtkWidget *widget,
  978.                  gpointer   data)
  979. {
  980.   GimpMemSizeEntryData *gmsed;
  981.   guint divided_mem_size;
  982.   guint new_unit;
  983.  
  984.   gmsed = (GimpMemSizeEntryData *)data;
  985.  
  986.   new_unit = (guint) gtk_object_get_user_data (GTK_OBJECT (widget));
  987.  
  988.   if (new_unit && new_unit != gmsed->mem_size_unit)
  989.     {
  990.       divided_mem_size = gmsed->adjustment->value / new_unit;
  991.       gmsed->mem_size_unit = new_unit;
  992.  
  993.       gtk_adjustment_set_value (GTK_ADJUSTMENT (gmsed->divided_adj), divided_mem_size);
  994.     }
  995. }
  996.  
  997. /**
  998.  * gimp_mem_size_entry_new:
  999.  * @adjustment: The adjustment containing the memsize and it's limits.
  1000.  *
  1001.  * Returns: A #GtkHBox with a #GtkSpinButton and a #GtkOptionMenu.
  1002.  **/
  1003. GtkWidget *
  1004. gimp_mem_size_entry_new (GtkAdjustment *adjustment)
  1005. {
  1006.   GtkWidget *hbox;
  1007.   GtkObject *divided_adj;
  1008.   GtkWidget *spinbutton;
  1009.   GtkWidget *optionmenu;
  1010.  
  1011.   GimpMemSizeEntryData *gmsed;
  1012.   guint mem_size_unit = 1;
  1013.   guint divided_mem_size;  
  1014.   gint i;
  1015.  
  1016.   gmsed = g_new (GimpMemSizeEntryData, 1);
  1017.  
  1018.   for (i = 0; i < 3; i++)
  1019.     {
  1020.       if ( (gint) adjustment->value % (mem_size_unit * 1024) != 0 )
  1021.     break;
  1022.       mem_size_unit *= 1024;
  1023.     }
  1024.   divided_mem_size =  adjustment->value / mem_size_unit;
  1025.  
  1026.   hbox = gtk_hbox_new (FALSE, 2);
  1027.   spinbutton =
  1028.     gimp_spin_button_new (÷d_adj, divided_mem_size,
  1029.               0.0, (4096.0 * 1024 * 1024 - 1), 1.0, 16.0, 0.0,
  1030.               1.0, 0.0);
  1031.   gtk_signal_connect (GTK_OBJECT (divided_adj), "value_changed",
  1032.               GTK_SIGNAL_FUNC (gimp_mem_size_entry_callback),
  1033.               gmsed);
  1034.   gtk_box_pack_start (GTK_BOX (hbox), spinbutton, FALSE, FALSE, 0);
  1035.   gtk_widget_show (spinbutton);
  1036.  
  1037.   optionmenu =
  1038.     gimp_option_menu_new2 (FALSE, gimp_mem_size_unit_callback,
  1039.                gmsed, (gpointer) mem_size_unit,
  1040.  
  1041.                _("Bytes"),     (gpointer) 1, NULL,
  1042.                _("KiloBytes"), (gpointer) 1024, NULL,
  1043.                _("MegaBytes"), (gpointer) (1024 * 1024), NULL,
  1044.  
  1045.                NULL);
  1046.   gtk_box_pack_start (GTK_BOX (hbox), optionmenu, FALSE, FALSE, 0);
  1047.   gtk_widget_show (optionmenu);
  1048.  
  1049.   gtk_signal_connect_object (GTK_OBJECT (hbox), "destroy",
  1050.                  GTK_SIGNAL_FUNC (gtk_object_unref),
  1051.                  GTK_OBJECT (adjustment));
  1052.   gtk_signal_connect_object (GTK_OBJECT (hbox), "destroy",
  1053.                  GTK_SIGNAL_FUNC (g_free),
  1054.                  (GtkObject *) gmsed);
  1055.  
  1056.   gmsed->adjustment = adjustment;
  1057.   gmsed->divided_adj = GTK_ADJUSTMENT (divided_adj);
  1058.   gmsed->mem_size_unit = mem_size_unit;
  1059.  
  1060.   gtk_object_set_data (GTK_OBJECT (hbox), "spinbutton", spinbutton);
  1061.   gtk_object_set_data (GTK_OBJECT (hbox), "optionmenu", optionmenu);
  1062.  
  1063.   return hbox;
  1064. }
  1065.  
  1066. /**
  1067.  * gimp_pixmap_button_new:
  1068.  * @xpm_data: The XPM data which will be passed to gimp_pixmap_new().
  1069.  * @text:     An optional text which will appear right of the pixmap.
  1070.  *
  1071.  * Returns: A #GtkButton with a #GimpPixmap and an optional #GtkLabel.
  1072.  **/
  1073. GtkWidget *
  1074. gimp_pixmap_button_new (gchar       **xpm_data,
  1075.             const gchar  *text)
  1076. {
  1077.   GtkWidget *button;
  1078.   GtkWidget *pixmap;
  1079.  
  1080.   button = gtk_button_new ();
  1081.   pixmap = gimp_pixmap_new (xpm_data);
  1082.  
  1083.   if (text)
  1084.     {
  1085.       GtkWidget *abox;
  1086.       GtkWidget *hbox;
  1087.       GtkWidget *label;
  1088.  
  1089.       abox = gtk_alignment_new (0.5, 0.5, 0.0, 0.0);
  1090.       gtk_container_add (GTK_CONTAINER (button), abox);
  1091.       gtk_widget_show (abox);
  1092.  
  1093.       hbox = gtk_hbox_new (FALSE, 0);
  1094.       gtk_container_add (GTK_CONTAINER (abox), hbox);
  1095.       gtk_widget_show (hbox);
  1096.  
  1097.       gtk_box_pack_start (GTK_BOX (hbox), pixmap, FALSE, FALSE, 4);
  1098.       gtk_widget_show (pixmap);
  1099.  
  1100.       label = gtk_label_new (text);
  1101.       gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 4);
  1102.       gtk_widget_show (label);
  1103.     }
  1104.   else
  1105.     {
  1106.       gtk_container_add (GTK_CONTAINER (button), pixmap);
  1107.       gtk_widget_show (pixmap);
  1108.     }
  1109.  
  1110.  
  1111.   return button;
  1112. }
  1113.  
  1114. /*
  1115.  *  Standard Callbacks
  1116.  */
  1117.  
  1118. /**
  1119.  * gimp_toggle_button_sensitive_update:
  1120.  * @toggle_button: The #GtkToggleButton the "set_sensitive" and
  1121.  *                 "inverse_sensitive" lists are attached to.
  1122.  *
  1123.  * If you attached a pointer to a #GtkWidget with gtk_object_set_data() and
  1124.  * the "set_sensitive" key to the #GtkToggleButton, the sensitive state of
  1125.  * the attached widget will be set according to the toggle button's
  1126.  * "active" state.
  1127.  *
  1128.  * You can attach an arbitrary list of widgets by attaching another
  1129.  * "set_sensitive" data pointer to the first widget (and so on...).
  1130.  *
  1131.  * This function can also set the sensitive state according to the toggle
  1132.  * button's inverse "active" state by attaching widgets with the
  1133.  * "inverse_sensitive" key.
  1134.  **/
  1135. void
  1136. gimp_toggle_button_sensitive_update (GtkToggleButton *toggle_button)
  1137. {
  1138.   GtkWidget *set_sensitive;
  1139.   gboolean   active;
  1140.  
  1141.   active = gtk_toggle_button_get_active (toggle_button);
  1142.  
  1143.   set_sensitive =
  1144.     gtk_object_get_data (GTK_OBJECT (toggle_button), "set_sensitive");
  1145.   while (set_sensitive)
  1146.     {
  1147.       gtk_widget_set_sensitive (set_sensitive, active);
  1148.       set_sensitive =
  1149.         gtk_object_get_data (GTK_OBJECT (set_sensitive), "set_sensitive");
  1150.     }
  1151.  
  1152.   set_sensitive =
  1153.     gtk_object_get_data (GTK_OBJECT (toggle_button), "inverse_sensitive");
  1154.   while (set_sensitive)
  1155.     {
  1156.       gtk_widget_set_sensitive (set_sensitive, ! active);
  1157.       set_sensitive =
  1158.         gtk_object_get_data (GTK_OBJECT (set_sensitive), "inverse_sensitive");
  1159.     }
  1160. }
  1161.  
  1162. /**
  1163.  * gimp_toggle_button_update:
  1164.  * @widget: A #GtkToggleButton.
  1165.  * @data:   A pointer to a #gint variable which will store the value of
  1166.  *          gtk_toggle_button_get_active().
  1167.  *
  1168.  * Note that this function calls gimp_toggle_button_sensitive_update().
  1169.  **/
  1170. void
  1171. gimp_toggle_button_update (GtkWidget *widget,
  1172.                gpointer   data)
  1173. {
  1174.   gint *toggle_val;
  1175.  
  1176.   toggle_val = (gint *) data;
  1177.  
  1178.   if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget)))
  1179.     *toggle_val = TRUE;
  1180.   else
  1181.     *toggle_val = FALSE;
  1182.  
  1183.   gimp_toggle_button_sensitive_update (GTK_TOGGLE_BUTTON (widget));
  1184. }
  1185.  
  1186. /**
  1187.  * gimp_radio_button_update:
  1188.  * @widget: A #GtkRadioButton.
  1189.  * @data:   A pointer to a #gint variable which will store the value of
  1190.  *          GPOINTER_TO_INT (gtk_object_get_user_data()).
  1191.  *
  1192.  * Note that this function calls gimp_toggle_button_sensitive_update().
  1193.  **/
  1194. void
  1195. gimp_radio_button_update (GtkWidget *widget,
  1196.               gpointer   data)
  1197. {
  1198.   gint *toggle_val;
  1199.  
  1200.   if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget)))
  1201.     {
  1202.       toggle_val = (gint *) data;
  1203.  
  1204.       *toggle_val =
  1205.     GPOINTER_TO_INT (gtk_object_get_user_data (GTK_OBJECT (widget)));
  1206.     }
  1207.  
  1208.   gimp_toggle_button_sensitive_update (GTK_TOGGLE_BUTTON (widget));
  1209. }
  1210.  
  1211. /**
  1212.  * gimp_menu_item_update:
  1213.  * @widget: A #GtkMenuItem.
  1214.  * @data:   A pointer to a #gint variable which will store the value of
  1215.  *          GPOINTER_TO_INT (gtk_object_get_user_data()).
  1216.  **/
  1217. void
  1218. gimp_menu_item_update (GtkWidget *widget,
  1219.                gpointer   data)
  1220. {
  1221.   gint *item_val;
  1222.  
  1223.   item_val = (gint *) data;
  1224.  
  1225.   *item_val = GPOINTER_TO_INT (gtk_object_get_user_data (GTK_OBJECT (widget)));
  1226. }
  1227.  
  1228. /**
  1229.  * gimp_int_adjustment_update:
  1230.  * @adjustment: A #GtkAdjustment.
  1231.  * @data:       A pointer to a #gint variable which will store the
  1232.  *              @adjustment's value.
  1233.  *
  1234.  * Note that the #GtkAdjustment's value (which is a #gfloat) will be rounded
  1235.  * with RINT().
  1236.  **/
  1237. void
  1238. gimp_int_adjustment_update (GtkAdjustment *adjustment,
  1239.                 gpointer       data)
  1240. {
  1241.   gint *val;
  1242.  
  1243.   val = (gint *) data;
  1244.   *val = RINT (adjustment->value);
  1245. }
  1246.  
  1247. /**
  1248.  * gimp_uint_adjustment_update:
  1249.  * @adjustment: A #GtkAdjustment.
  1250.  * @data:       A pointer to a #guint variable which will store the
  1251.  *              @adjustment's value.
  1252.  *
  1253.  * Note that the #GtkAdjustment's value (which is a #gfloat) will be rounded
  1254.  * with (#guint) (value + 0.5).
  1255.  **/
  1256. void
  1257. gimp_uint_adjustment_update (GtkAdjustment *adjustment,
  1258.                  gpointer       data)
  1259. {
  1260.   guint *val;
  1261.  
  1262.   val = (guint *) data;
  1263.   *val = (guint) (adjustment->value + 0.5);
  1264. }
  1265.  
  1266. /**
  1267.  * gimp_float_adjustment_update:
  1268.  * @adjustment: A #GtkAdjustment.
  1269.  * @data:       A pointer to a #gfloat varaiable which willl store the
  1270.  *              @adjustment's value.
  1271.  **/
  1272. void
  1273. gimp_float_adjustment_update (GtkAdjustment *adjustment,
  1274.                   gpointer       data)
  1275. {
  1276.   gfloat *val;
  1277.  
  1278.   val = (gfloat *) data;
  1279.   *val = adjustment->value;
  1280. }
  1281.  
  1282. /**
  1283.  * gimp_double_adjustment_update:
  1284.  * @adjustment: A #GtkAdjustment.
  1285.  * @data:       A pointer to a #gdouble variable which will store the
  1286.  *              @adjustment's value.
  1287.  **/
  1288. void
  1289. gimp_double_adjustment_update (GtkAdjustment *adjustment,
  1290.                    gpointer       data)
  1291. {
  1292.   gdouble *val;
  1293.  
  1294.   val = (gdouble *) data;
  1295.   *val = adjustment->value;
  1296. }
  1297.  
  1298. /**
  1299.  * gimp_unit_menu_update:
  1300.  * @widget: A #GimpUnitMenu.
  1301.  * @data:   A pointer to a #GimpUnit variable which will store the unit menu's
  1302.  *          value.
  1303.  *
  1304.  * This callback can set the number of decimal digits of an arbitrary number
  1305.  * of #GtkSpinButton's. To use this functionality, attach the spinbuttons
  1306.  * as list of data pointers attached with gtk_object_set_data() with the
  1307.  * "set_digits" key.
  1308.  *
  1309.  * See gimp_toggle_button_sensitive_update() for a description of how
  1310.  * to set up the list.
  1311.  **/
  1312. void
  1313. gimp_unit_menu_update (GtkWidget *widget,
  1314.                gpointer   data)
  1315. {
  1316.   GimpUnit  *val;
  1317.   GtkWidget *spinbutton;
  1318.   gint       digits;
  1319.  
  1320.   val = (GimpUnit *) data;
  1321.   *val = gimp_unit_menu_get_unit (GIMP_UNIT_MENU (widget));
  1322.  
  1323.   digits = ((*val == GIMP_UNIT_PIXEL) ? 0 :
  1324.         ((*val == GIMP_UNIT_PERCENT) ? 2 :
  1325.          (MIN (6, MAX (3, gimp_unit_get_digits (*val))))));
  1326.  
  1327.   spinbutton =
  1328.     gtk_object_get_data (GTK_OBJECT (widget), "set_digits");
  1329.   while (spinbutton)
  1330.     {
  1331.       gtk_spin_button_set_digits (GTK_SPIN_BUTTON (spinbutton), digits);
  1332.       spinbutton = gtk_object_get_data (GTK_OBJECT (spinbutton), "set_digits");
  1333.     }
  1334. }
  1335.  
  1336. /*
  1337.  *  Helper Functions
  1338.  */
  1339.  
  1340. /**
  1341.  * gimp_table_attach_aligned:
  1342.  * @table:      The #GtkTable the widgets will be attached to.
  1343.  * @column:     The column to start with.
  1344.  * @row:        The row to attach the eidgets.
  1345.  * @label_text: The text for the #GtkLabel which will be attached left of the
  1346.  *              widget.
  1347.  * @xalign:     The horizontal alignment of the #GtkLabel.
  1348.  * @yalign:     The vertival alignment of the #GtkLabel.
  1349.  * @widget:     The #GtkWidget to attach right of the label.
  1350.  * @colspan:    The number of columns the widget will use.
  1351.  * @left_align: #TRUE if the widget should be left-aligned.
  1352.  *
  1353.  * Note that the @label_text can be #NULL and that the widget will be attached
  1354.  * starting at (@column + 1) in this case, too.
  1355.  **/
  1356. void
  1357. gimp_table_attach_aligned (GtkTable    *table,
  1358.                gint         column,
  1359.                gint         row,
  1360.                const gchar *label_text,
  1361.                gfloat       xalign,
  1362.                gfloat       yalign,
  1363.                GtkWidget   *widget,
  1364.                gint         colspan,
  1365.                gboolean     left_align)
  1366. {
  1367.   if (label_text)
  1368.     {
  1369.       GtkWidget *label;
  1370.  
  1371.       label = gtk_label_new (label_text);
  1372.       gtk_misc_set_alignment (GTK_MISC (label), xalign, yalign);
  1373.       gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_RIGHT);
  1374.       gtk_table_attach (table, label,
  1375.             column, column + 1,
  1376.             row, row + 1,
  1377.             GTK_FILL, GTK_FILL, 0, 0);
  1378.       gtk_widget_show (label);
  1379.     }
  1380.  
  1381.   if (left_align)
  1382.     {
  1383.       GtkWidget *alignment;
  1384.  
  1385.       alignment = gtk_alignment_new (0.0, 0.5, 0.0, 0.0);
  1386.       gtk_container_add (GTK_CONTAINER (alignment), widget);
  1387.       gtk_widget_show (widget);
  1388.  
  1389.       widget = alignment;
  1390.     }
  1391.  
  1392.   gtk_table_attach (table, widget,
  1393.             column + 1, column + 1 + colspan,
  1394.             row, row + 1,
  1395.             GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0);
  1396.  
  1397.   gtk_widget_show (widget);
  1398. }
  1399.