home *** CD-ROM | disk | FTP | other *** search
/ Chip 2005 February / CMCD0205.ISO / Linux / gimp-2.2.0.tar.gz / gimp-2.2.0.tar / gimp-2.2.0 / libgimpwidgets / gimpcellrenderertoggle.c < prev    next >
C/C++ Source or Header  |  2004-07-26  |  17KB  |  469 lines

  1. /* LIBGIMP - The GIMP Library
  2.  * Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball
  3.  *
  4.  * gimpcellrenderertoggle.c
  5.  * Copyright (C) 2003-2004  Sven Neumann <sven@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 "gimpwidgetstypes.h"
  28.  
  29. #include "gimpwidgetsmarshal.h"
  30. #include "gimpcellrenderertoggle.h"
  31.  
  32.  
  33. #define DEFAULT_ICON_SIZE  GTK_ICON_SIZE_BUTTON
  34.  
  35.  
  36. enum
  37. {
  38.   CLICKED,
  39.   LAST_SIGNAL
  40. };
  41.  
  42. enum
  43. {
  44.   PROP_0,
  45.   PROP_STOCK_ID,
  46.   PROP_STOCK_SIZE
  47. };
  48.  
  49.  
  50. static void gimp_cell_renderer_toggle_class_init (GimpCellRendererToggleClass *klass);
  51.  
  52. static void gimp_cell_renderer_toggle_finalize     (GObject         *object);
  53. static void gimp_cell_renderer_toggle_get_property (GObject         *object,
  54.                                                     guint            param_id,
  55.                                                     GValue          *value,
  56.                                                     GParamSpec      *pspec);
  57. static void gimp_cell_renderer_toggle_set_property (GObject         *object,
  58.                                                     guint            param_id,
  59.                                                     const GValue    *value,
  60.                                                     GParamSpec      *pspec);
  61. static void gimp_cell_renderer_toggle_get_size     (GtkCellRenderer *cell,
  62.                                                     GtkWidget       *widget,
  63.                                                     GdkRectangle    *rectangle,
  64.                                                     gint            *x_offset,
  65.                                                     gint            *y_offset,
  66.                                                     gint            *width,
  67.                                                     gint            *height);
  68. static void gimp_cell_renderer_toggle_render       (GtkCellRenderer *cell,
  69.                                                     GdkWindow       *window,
  70.                                                     GtkWidget       *widget,
  71.                                                     GdkRectangle    *background_area,
  72.                                                     GdkRectangle    *cell_area,
  73.                                                     GdkRectangle    *expose_area,
  74.                                                     GtkCellRendererState flags);
  75. static gboolean gimp_cell_renderer_toggle_activate (GtkCellRenderer *cell,
  76.                                                     GdkEvent        *event,
  77.                                                     GtkWidget       *widget,
  78.                                                     const gchar     *path,
  79.                                                     GdkRectangle    *background_area,
  80.                                                     GdkRectangle    *cell_area,
  81.                                                     GtkCellRendererState  flags);
  82. static void gimp_cell_renderer_toggle_create_pixbuf (GimpCellRendererToggle *toggle,
  83.                                                      GtkWidget              *widget);
  84.  
  85.  
  86. static guint toggle_cell_signals[LAST_SIGNAL] = { 0 };
  87.  
  88. static GtkCellRendererToggleClass *parent_class = NULL;
  89.  
  90.  
  91. GType
  92. gimp_cell_renderer_toggle_get_type (void)
  93. {
  94.   static GType cell_type = 0;
  95.  
  96.   if (! cell_type)
  97.     {
  98.       static const GTypeInfo cell_info =
  99.       {
  100.         sizeof (GimpCellRendererToggleClass),
  101.         NULL,        /* base_init      */
  102.         NULL,        /* base_finalize  */
  103.         (GClassInitFunc) gimp_cell_renderer_toggle_class_init,
  104.         NULL,        /* class_finalize */
  105.         NULL,        /* class_data     */
  106.         sizeof (GimpCellRendererToggle),
  107.         0,              /* n_preallocs    */
  108.         NULL            /* instance_init  */
  109.       };
  110.  
  111.       cell_type = g_type_register_static (GTK_TYPE_CELL_RENDERER_TOGGLE,
  112.                                           "GimpCellRendererToggle",
  113.                                           &cell_info, 0);
  114.     }
  115.  
  116.   return cell_type;
  117. }
  118.  
  119. static void
  120. gimp_cell_renderer_toggle_class_init (GimpCellRendererToggleClass *klass)
  121. {
  122.   GObjectClass         *object_class = G_OBJECT_CLASS (klass);
  123.   GtkCellRendererClass *cell_class   = GTK_CELL_RENDERER_CLASS (klass);
  124.  
  125.   parent_class = g_type_class_peek_parent (klass);
  126.  
  127.   toggle_cell_signals[CLICKED] =
  128.     g_signal_new ("clicked",
  129.           G_OBJECT_CLASS_TYPE (object_class),
  130.           G_SIGNAL_RUN_LAST,
  131.           G_STRUCT_OFFSET (GimpCellRendererToggleClass, clicked),
  132.           NULL, NULL,
  133.           _gimp_widgets_marshal_VOID__STRING_FLAGS,
  134.           G_TYPE_NONE, 2,
  135.           G_TYPE_STRING,
  136.                   GDK_TYPE_MODIFIER_TYPE);
  137.  
  138.   object_class->finalize     = gimp_cell_renderer_toggle_finalize;
  139.   object_class->get_property = gimp_cell_renderer_toggle_get_property;
  140.   object_class->set_property = gimp_cell_renderer_toggle_set_property;
  141.  
  142.   cell_class->get_size       = gimp_cell_renderer_toggle_get_size;
  143.   cell_class->render         = gimp_cell_renderer_toggle_render;
  144.   cell_class->activate       = gimp_cell_renderer_toggle_activate;
  145.  
  146.   g_object_class_install_property (object_class,
  147.                                    PROP_STOCK_ID,
  148.                                    g_param_spec_string ("stock_id",
  149.                                                         NULL, NULL,
  150.                                                         NULL,
  151.                                                         G_PARAM_READWRITE |
  152.                                                         G_PARAM_CONSTRUCT));
  153.   g_object_class_install_property (object_class,
  154.                                    PROP_STOCK_SIZE,
  155.                                    g_param_spec_int ("stock_size",
  156.                                                      NULL, NULL,
  157.                                                      0, G_MAXINT,
  158.                                                      DEFAULT_ICON_SIZE,
  159.                                                      G_PARAM_READWRITE |
  160.                                                      G_PARAM_CONSTRUCT));
  161. }
  162.  
  163. static void
  164. gimp_cell_renderer_toggle_finalize (GObject *object)
  165. {
  166.   GimpCellRendererToggle *toggle;
  167.  
  168.   toggle = GIMP_CELL_RENDERER_TOGGLE (object);
  169.  
  170.   if (toggle->stock_id)
  171.     {
  172.       g_free (toggle->stock_id);
  173.       toggle->stock_id = NULL;
  174.     }
  175.   if (toggle->pixbuf)
  176.     {
  177.       g_object_unref (toggle->pixbuf);
  178.       toggle->pixbuf = NULL;
  179.     }
  180.  
  181.   G_OBJECT_CLASS (parent_class)->finalize (object);
  182. }
  183.  
  184. static void
  185. gimp_cell_renderer_toggle_get_property (GObject    *object,
  186.                                         guint       param_id,
  187.                                         GValue     *value,
  188.                                         GParamSpec *pspec)
  189. {
  190.   GimpCellRendererToggle *toggle = GIMP_CELL_RENDERER_TOGGLE (object);
  191.  
  192.   switch (param_id)
  193.     {
  194.     case PROP_STOCK_ID:
  195.       g_value_set_string (value, toggle->stock_id);
  196.       break;
  197.     case PROP_STOCK_SIZE:
  198.       g_value_set_int (value, toggle->stock_size);
  199.       break;
  200.  
  201.     default:
  202.       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
  203.       break;
  204.     }
  205. }
  206.  
  207. static void
  208. gimp_cell_renderer_toggle_set_property (GObject      *object,
  209.                                         guint         param_id,
  210.                                         const GValue *value,
  211.                                         GParamSpec   *pspec)
  212. {
  213.   GimpCellRendererToggle *toggle = GIMP_CELL_RENDERER_TOGGLE (object);
  214.  
  215.   switch (param_id)
  216.     {
  217.     case PROP_STOCK_ID:
  218.       if (toggle->stock_id)
  219.     g_free (toggle->stock_id);
  220.       toggle->stock_id = g_value_dup_string (value);
  221.       break;
  222.     case PROP_STOCK_SIZE:
  223.       toggle->stock_size = g_value_get_int (value);
  224.       break;
  225.  
  226.     default:
  227.       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
  228.       break;
  229.     }
  230.  
  231.   if (toggle->pixbuf)
  232.     {
  233.       g_object_unref (toggle->pixbuf);
  234.       toggle->pixbuf = NULL;
  235.     }
  236. }
  237.  
  238. static void
  239. gimp_cell_renderer_toggle_get_size (GtkCellRenderer *cell,
  240.                                     GtkWidget       *widget,
  241.                                     GdkRectangle    *cell_area,
  242.                                     gint            *x_offset,
  243.                                     gint            *y_offset,
  244.                                     gint            *width,
  245.                                     gint            *height)
  246. {
  247.   GimpCellRendererToggle *toggle = GIMP_CELL_RENDERER_TOGGLE (cell);
  248.   gint                    calc_width;
  249.   gint                    calc_height;
  250.   gint                    pixbuf_width;
  251.   gint                    pixbuf_height;
  252.  
  253.   if (!toggle->stock_id)
  254.     {
  255.       GTK_CELL_RENDERER_CLASS (parent_class)->get_size (cell,
  256.                                                         widget,
  257.                                                         cell_area,
  258.                                                         x_offset, y_offset,
  259.                                                         width, height);
  260.       return;
  261.     }
  262.  
  263.   if (!toggle->pixbuf)
  264.     gimp_cell_renderer_toggle_create_pixbuf (toggle, widget);
  265.  
  266.   pixbuf_width  = gdk_pixbuf_get_width  (toggle->pixbuf);
  267.   pixbuf_height = gdk_pixbuf_get_height (toggle->pixbuf);
  268.  
  269.   calc_width  = (pixbuf_width +
  270.                  (gint) cell->xpad * 2 + widget->style->xthickness * 2);
  271.   calc_height = (pixbuf_height +
  272.                  (gint) cell->ypad * 2 + widget->style->ythickness * 2);
  273.  
  274.   if (x_offset) *x_offset = 0;
  275.   if (y_offset) *y_offset = 0;
  276.  
  277.   if (cell_area)
  278.     {
  279.       if (x_offset)
  280.     {
  281.       *x_offset = (((gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL) ?
  282.                         (1.0 - cell->xalign) : cell->xalign) *
  283.                        (cell_area->width - calc_width));
  284.       *x_offset = MAX (*x_offset, 0);
  285.     }
  286.       if (y_offset)
  287.     {
  288.       *y_offset = cell->yalign * (cell_area->height - calc_height);
  289.       *y_offset = MAX (*y_offset, 0);
  290.     }
  291.     }
  292.  
  293.   if (width)  *width  = calc_width;
  294.   if (height) *height = calc_height;
  295. }
  296.  
  297. static void
  298. gimp_cell_renderer_toggle_render (GtkCellRenderer      *cell,
  299.                                   GdkWindow            *window,
  300.                                   GtkWidget            *widget,
  301.                                   GdkRectangle         *background_area,
  302.                                   GdkRectangle         *cell_area,
  303.                                   GdkRectangle         *expose_area,
  304.                                   GtkCellRendererState  flags)
  305. {
  306.   GimpCellRendererToggle *toggle = GIMP_CELL_RENDERER_TOGGLE (cell);
  307.   GdkRectangle            toggle_rect;
  308.   GdkRectangle            draw_rect;
  309.   GtkStateType            state;
  310.   gboolean                active;
  311.  
  312.   if (!toggle->stock_id)
  313.     {
  314.       GTK_CELL_RENDERER_CLASS (parent_class)->render (cell, window, widget,
  315.                                                       background_area,
  316.                                                       cell_area, expose_area,
  317.                                                       flags);
  318.       return;
  319.     }
  320.  
  321.   gimp_cell_renderer_toggle_get_size (cell, widget, cell_area,
  322.                                       &toggle_rect.x,
  323.                                       &toggle_rect.y,
  324.                                       &toggle_rect.width,
  325.                                       &toggle_rect.height);
  326.  
  327.   toggle_rect.x      += cell_area->x + cell->xpad;
  328.   toggle_rect.y      += cell_area->y + cell->ypad;
  329.   toggle_rect.width  -= cell->xpad * 2;
  330.   toggle_rect.height -= cell->ypad * 2;
  331.  
  332.   if (toggle_rect.width <= 0 || toggle_rect.height <= 0)
  333.     return;
  334.  
  335.   active =
  336.     gtk_cell_renderer_toggle_get_active (GTK_CELL_RENDERER_TOGGLE (cell));
  337.  
  338.   if ((flags & GTK_CELL_RENDERER_SELECTED) == GTK_CELL_RENDERER_SELECTED)
  339.     {
  340.       if (GTK_WIDGET_HAS_FOCUS (widget))
  341.     state = GTK_STATE_SELECTED;
  342.       else
  343.     state = GTK_STATE_ACTIVE;
  344.     }
  345.   else
  346.     {
  347.       if (GTK_CELL_RENDERER_TOGGLE (cell)->activatable)
  348.         state = GTK_STATE_NORMAL;
  349.       else
  350.         state = GTK_STATE_INSENSITIVE;
  351.     }
  352.  
  353.   if (gdk_rectangle_intersect (expose_area, cell_area, &draw_rect) &&
  354.       (flags & GTK_CELL_RENDERER_PRELIT))
  355.     gtk_paint_shadow (widget->style,
  356.                       window,
  357.                       state,
  358.                       active ? GTK_SHADOW_IN : GTK_SHADOW_OUT,
  359.                       &draw_rect,
  360.                       widget, NULL,
  361.                       toggle_rect.x,     toggle_rect.y,
  362.                       toggle_rect.width, toggle_rect.height);
  363.  
  364.   if (active)
  365.     {
  366.       toggle_rect.x      += widget->style->xthickness;
  367.       toggle_rect.y      += widget->style->ythickness;
  368.       toggle_rect.width  -= widget->style->xthickness * 2;
  369.       toggle_rect.height -= widget->style->ythickness * 2;
  370.  
  371.       if (gdk_rectangle_intersect (&draw_rect, &toggle_rect, &draw_rect))
  372.         gdk_draw_pixbuf (window,
  373.                          widget->style->black_gc,
  374.                          toggle->pixbuf,
  375.                          /* pixbuf 0, 0 is at toggle_rect.x, toggle_rect.y */
  376.                          draw_rect.x - toggle_rect.x,
  377.                          draw_rect.y - toggle_rect.y,
  378.                          draw_rect.x,
  379.                          draw_rect.y,
  380.                          draw_rect.width,
  381.                          draw_rect.height,
  382.                          GDK_RGB_DITHER_NORMAL,
  383.                          0, 0);
  384.     }
  385. }
  386.  
  387. static gboolean
  388. gimp_cell_renderer_toggle_activate (GtkCellRenderer      *cell,
  389.                                     GdkEvent             *event,
  390.                                     GtkWidget            *widget,
  391.                                     const gchar          *path,
  392.                                     GdkRectangle         *background_area,
  393.                                     GdkRectangle         *cell_area,
  394.                                     GtkCellRendererState  flags)
  395. {
  396.   GtkCellRendererToggle *toggle = GTK_CELL_RENDERER_TOGGLE (cell);
  397.  
  398.   if (toggle->activatable)
  399.     {
  400.       GdkModifierType state = 0;
  401.  
  402.       if (event && ((GdkEventAny *) event)->type == GDK_BUTTON_PRESS)
  403.         state = ((GdkEventButton *) event)->state;
  404.  
  405.       gimp_cell_renderer_toggle_clicked (GIMP_CELL_RENDERER_TOGGLE (cell),
  406.                                          path, state);
  407.  
  408.       return TRUE;
  409.     }
  410.  
  411.   return FALSE;
  412. }
  413.  
  414. static void
  415. gimp_cell_renderer_toggle_create_pixbuf (GimpCellRendererToggle *toggle,
  416.                                          GtkWidget              *widget)
  417. {
  418.   if (toggle->pixbuf)
  419.     g_object_unref (toggle->pixbuf);
  420.  
  421.   toggle->pixbuf = gtk_widget_render_icon (widget,
  422.                                            toggle->stock_id,
  423.                                            toggle->stock_size, NULL);
  424. }
  425.  
  426.  
  427. /**
  428.  * gimp_cell_renderer_toggle_new:
  429.  * @stock_id: the stock_id of the icon to use for the active state
  430.  *
  431.  * Creates a custom version of the #GtkCellRendererToggle. Instead of
  432.  * showing the standard toggle button, it shows a stock icon if the
  433.  * cell is active and no icon otherwise. This cell renderer is for
  434.  * example used in the Layers treeview to indicate and control the
  435.  * layer's visibility by showing %GIMP_STOCK_VISIBLE.
  436.  *
  437.  * Return value: a new #GimpCellRendererToggle
  438.  *
  439.  * Since: GIMP 2.2
  440.  **/
  441. GtkCellRenderer *
  442. gimp_cell_renderer_toggle_new (const gchar *stock_id)
  443. {
  444.   return g_object_new (GIMP_TYPE_CELL_RENDERER_TOGGLE,
  445.                        "stock_id", stock_id,
  446.                        NULL);
  447. }
  448.  
  449. /**
  450.  * gimp_cell_renderer_toggle_clicked:
  451.  * @cell: a #GimpCellRendererToggle
  452.  * @path:
  453.  * @state:
  454.  *
  455.  * Emits the "clicked" signal from a #GimpCellRendererToggle.
  456.  *
  457.  * Since: GIMP 2.2
  458.  **/
  459. void
  460. gimp_cell_renderer_toggle_clicked (GimpCellRendererToggle *cell,
  461.                                    const gchar            *path,
  462.                                    GdkModifierType         state)
  463. {
  464.   g_return_if_fail (GIMP_IS_CELL_RENDERER_TOGGLE (cell));
  465.   g_return_if_fail (path != NULL);
  466.  
  467.   g_signal_emit (cell, toggle_cell_signals[CLICKED], 0, path, state);
  468. }
  469.