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 / gimpframe.c < prev    next >
C/C++ Source or Header  |  2004-07-13  |  12KB  |  377 lines

  1. /* LIBGIMP - The GIMP Library
  2.  * Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball
  3.  *
  4.  * gimpframe.c
  5.  * Copyright (C) 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.  * Lesser 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 <string.h>
  26.  
  27. #include <gtk/gtk.h>
  28.  
  29. #include "gimpwidgetstypes.h"
  30.  
  31. #include "gimpframe.h"
  32.  
  33.  
  34. #define DEFAULT_LABEL_SPACING       6
  35. #define DEFAULT_LABEL_BOLD          TRUE
  36.  
  37. #define GIMP_FRAME_INDENT_KEY       "gimp-frame-indent"
  38. #define GIMP_FRAME_IN_EXPANDER_KEY  "gimp-frame-in-expander"
  39.  
  40.  
  41. static void      gimp_frame_class_init          (GimpFrameClass *klass);
  42. static void      gimp_frame_init                (GimpFrame      *frame);
  43.  
  44. static void      gimp_frame_size_request        (GtkWidget      *widget,
  45.                                                  GtkRequisition *requisition);
  46. static void      gimp_frame_size_allocate       (GtkWidget      *widget,
  47.                                                  GtkAllocation  *allocation);
  48. static void      gimp_frame_child_allocate      (GtkFrame       *frame,
  49.                                                  GtkAllocation  *allocation);
  50. static void      gimp_frame_style_set           (GtkWidget      *widget,
  51.                                                  GtkStyle       *previous);
  52. static gboolean  gimp_frame_expose_event        (GtkWidget      *widget,
  53.                                                  GdkEventExpose *event);
  54. static void      gimp_frame_label_widget_notify (GtkFrame       *frame);
  55. static gint      gimp_frame_get_indent          (GtkWidget      *widget);
  56. static gint      gimp_frame_get_label_spacing   (GtkFrame       *frame);
  57.  
  58.  
  59. static GtkVBoxClass *parent_class = NULL;
  60.  
  61.  
  62. GType
  63. gimp_frame_get_type (void)
  64. {
  65.   static GType frame_type = 0;
  66.  
  67.   if (! frame_type)
  68.     {
  69.       static const GTypeInfo frame_info =
  70.       {
  71.         sizeof (GimpFrameClass),
  72.         (GBaseInitFunc)     NULL,
  73.         (GBaseFinalizeFunc) NULL,
  74.         (GClassInitFunc)    gimp_frame_class_init,
  75.         NULL,           /* class_finalize */
  76.         NULL,           /* class_data     */
  77.         sizeof (GimpFrame),
  78.         0,              /* n_preallocs    */
  79.         (GInstanceInitFunc) gimp_frame_init,
  80.       };
  81.  
  82.       frame_type = g_type_register_static (GTK_TYPE_FRAME,
  83.                                            "GimpFrame",
  84.                                            &frame_info, 0);
  85.     }
  86.  
  87.   return frame_type;
  88. }
  89.  
  90. static void
  91. gimp_frame_class_init (GimpFrameClass *klass)
  92. {
  93.   GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
  94.   GtkFrameClass  *frame_class  = GTK_FRAME_CLASS (klass);
  95.  
  96.   parent_class = g_type_class_peek_parent (klass);
  97.  
  98.   widget_class->size_request  = gimp_frame_size_request;
  99.   widget_class->size_allocate = gimp_frame_size_allocate;
  100.   widget_class->style_set     = gimp_frame_style_set;
  101.   widget_class->expose_event  = gimp_frame_expose_event;
  102.  
  103.   frame_class->compute_child_allocation = gimp_frame_child_allocate;
  104.  
  105.   gtk_widget_class_install_style_property (widget_class,
  106.                                            g_param_spec_boolean ("label_bold",
  107.                                                                  NULL, NULL,
  108.                                                                  DEFAULT_LABEL_BOLD,
  109.                                                                  G_PARAM_READABLE));
  110.   gtk_widget_class_install_style_property (widget_class,
  111.                                            g_param_spec_int ("label_spacing",
  112.                                                              NULL, NULL,
  113.                                                              0,
  114.                                                              G_MAXINT,
  115.                                                              DEFAULT_LABEL_SPACING,
  116.                                                              G_PARAM_READABLE));
  117. }
  118.  
  119.  
  120. static void
  121. gimp_frame_init (GimpFrame *frame)
  122. {
  123.   g_signal_connect (frame, "notify::label-widget",
  124.                     G_CALLBACK (gimp_frame_label_widget_notify),
  125.                     NULL);
  126. }
  127.  
  128. static void
  129. gimp_frame_size_request (GtkWidget      *widget,
  130.                          GtkRequisition *requisition)
  131. {
  132.   GtkFrame       *frame = GTK_FRAME (widget);
  133.   GtkBin         *bin   = GTK_BIN (widget);
  134.   GtkRequisition  child_requisition;
  135.  
  136.   if (frame->label_widget && GTK_WIDGET_VISIBLE (frame->label_widget))
  137.     {
  138.       gtk_widget_size_request (frame->label_widget, requisition);
  139.     }
  140.   else
  141.     {
  142.       requisition->width  = 0;
  143.       requisition->height = 0;
  144.     }
  145.  
  146.   requisition->height += gimp_frame_get_label_spacing (frame);
  147.  
  148.   if (bin->child && GTK_WIDGET_VISIBLE (bin->child))
  149.     {
  150.       gint indent = gimp_frame_get_indent (widget);
  151.  
  152.       gtk_widget_size_request (bin->child, &child_requisition);
  153.  
  154.       requisition->width = MAX (requisition->width,
  155.                                 child_requisition.width + indent);
  156.       requisition->height += child_requisition.height;
  157.     }
  158.  
  159.   requisition->width  += 2 * GTK_CONTAINER (widget)->border_width;
  160.   requisition->height += 2 * GTK_CONTAINER (widget)->border_width;
  161. }
  162.  
  163. static void
  164. gimp_frame_size_allocate (GtkWidget     *widget,
  165.                           GtkAllocation *allocation)
  166. {
  167.   GtkFrame *frame = GTK_FRAME (widget);
  168.   GtkBin   *bin   = GTK_BIN (widget);
  169.  
  170.   widget->allocation = *allocation;
  171.  
  172.   gimp_frame_child_allocate (frame, &frame->child_allocation);
  173.  
  174.   if (bin->child && GTK_WIDGET_VISIBLE (bin->child))
  175.     gtk_widget_size_allocate (bin->child, &frame->child_allocation);
  176.  
  177.   if (frame->label_widget && GTK_WIDGET_VISIBLE (frame->label_widget))
  178.     {
  179.       GtkAllocation   label_allocation;
  180.       GtkRequisition  label_requisition;
  181.       gint            border = GTK_CONTAINER (widget)->border_width;
  182.  
  183.       gtk_widget_get_child_requisition (frame->label_widget,
  184.                                         &label_requisition);
  185.  
  186.       label_allocation.x      = allocation->x + border;
  187.       label_allocation.y      = allocation->y + border;
  188.       label_allocation.width  = MAX (label_requisition.width,
  189.                                      allocation->width - 2 * border);
  190.       label_allocation.height = label_requisition.height;
  191.  
  192.       gtk_widget_size_allocate (frame->label_widget, &label_allocation);
  193.     }
  194. }
  195.  
  196. static void
  197. gimp_frame_child_allocate (GtkFrame      *frame,
  198.                            GtkAllocation *child_allocation)
  199. {
  200.   GtkWidget     *widget     = GTK_WIDGET (frame);
  201.   GtkAllocation *allocation = &widget->allocation;
  202.   gint           border     = GTK_CONTAINER (frame)->border_width;
  203.   gint           spacing    = 0;
  204.   gint           indent     = gimp_frame_get_indent (widget);
  205.  
  206.   if (frame->label_widget && GTK_WIDGET_VISIBLE (frame->label_widget))
  207.     {
  208.       GtkRequisition  child_requisition;
  209.  
  210.       gtk_widget_get_child_requisition (frame->label_widget,
  211.                                         &child_requisition);
  212.       spacing += child_requisition.height;
  213.     }
  214.  
  215.   spacing += gimp_frame_get_label_spacing (frame);
  216.  
  217.   if (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_LTR)
  218.     child_allocation->x    = border + indent;
  219.   else
  220.     child_allocation->x    = border;
  221.  
  222.   child_allocation->y      = border + spacing;
  223.   child_allocation->width  = MAX (1,
  224.                                   allocation->width - 2 * border - indent);
  225.   child_allocation->height = MAX (1,
  226.                                   allocation->height -
  227.                                   child_allocation->y - border);
  228.  
  229.   child_allocation->x += allocation->x;
  230.   child_allocation->y += allocation->y;
  231. }
  232.  
  233. static void
  234. gimp_frame_style_set (GtkWidget *widget,
  235.                       GtkStyle  *previous)
  236. {
  237.   /*  font changes invalidate the indentation  */
  238.   g_object_set_data (G_OBJECT (widget), GIMP_FRAME_INDENT_KEY, NULL);
  239.  
  240.   /*  for "label_bold"  */
  241.   gimp_frame_label_widget_notify (GTK_FRAME (widget));
  242. }
  243.  
  244. static gboolean
  245. gimp_frame_expose_event (GtkWidget      *widget,
  246.                          GdkEventExpose *event)
  247. {
  248.   if (GTK_WIDGET_DRAWABLE (widget))
  249.     {
  250.       GtkWidgetClass *widget_class = g_type_class_peek_parent (parent_class);
  251.  
  252.       return widget_class->expose_event (widget, event);
  253.     }
  254.  
  255.   return FALSE;
  256. }
  257.  
  258. static void
  259. gimp_frame_label_widget_notify (GtkFrame *frame)
  260. {
  261.   if (frame->label_widget)
  262.     {
  263.       GtkLabel *label = NULL;
  264.  
  265.       if (GTK_IS_LABEL (frame->label_widget))
  266.         {
  267.           label = GTK_LABEL (frame->label_widget);
  268.  
  269.           gtk_misc_set_alignment (GTK_MISC (label),
  270.                                   frame->label_xalign, frame->label_yalign);
  271.         }
  272.       else if (GTK_IS_BIN (frame->label_widget))
  273.         {
  274.           GtkWidget *child = gtk_bin_get_child (GTK_BIN (frame->label_widget));
  275.  
  276.           if (GTK_IS_LABEL (child))
  277.             label = GTK_LABEL (child);
  278.         }
  279.  
  280.       if (label)
  281.         {
  282.           PangoAttrList  *attrs = pango_attr_list_new ();
  283.           PangoAttribute *attr;
  284.           gboolean        bold;
  285.  
  286.           gtk_widget_style_get (GTK_WIDGET (frame), "label_bold", &bold, NULL);
  287.  
  288.           attr = pango_attr_weight_new (bold ?
  289.                                         PANGO_WEIGHT_BOLD :
  290.                                         PANGO_WEIGHT_NORMAL);
  291.           attr->start_index = 0;
  292.           attr->end_index   = -1;
  293.           pango_attr_list_insert (attrs, attr);
  294.  
  295.           gtk_label_set_attributes (label, attrs);
  296.  
  297.           pango_attr_list_unref (attrs);
  298.         }
  299.     }
  300. }
  301.  
  302. static gint
  303. gimp_frame_get_indent (GtkWidget *widget)
  304. {
  305.   gint width = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (widget),
  306.                                                    GIMP_FRAME_INDENT_KEY));
  307.  
  308.   if (! width)
  309.     {
  310.       PangoLayout *layout;
  311.  
  312.       /*  the HIG suggests to use four spaces so do just that  */
  313.       layout = gtk_widget_create_pango_layout (widget, "    ");
  314.       pango_layout_get_pixel_size (layout, &width, NULL);
  315.       g_object_unref (layout);
  316.  
  317.       g_object_set_data (G_OBJECT (widget),
  318.                          GIMP_FRAME_INDENT_KEY, GINT_TO_POINTER (width));
  319.     }
  320.  
  321.   return width;
  322. }
  323.  
  324. static gint
  325. gimp_frame_get_label_spacing (GtkFrame *frame)
  326. {
  327.   gint spacing = 0;
  328.  
  329.   if ((frame->label_widget && GTK_WIDGET_VISIBLE (frame->label_widget)) ||
  330.       (g_object_get_data (G_OBJECT (frame), GIMP_FRAME_IN_EXPANDER_KEY)))
  331.     {
  332.       gtk_widget_style_get (GTK_WIDGET (frame),
  333.                             "label_spacing", &spacing,
  334.                             NULL);
  335.     }
  336.  
  337.   return spacing;
  338. }
  339.  
  340. /**
  341.  * gimp_frame_new:
  342.  * @label: text to set as the frame's title label (or %NULL for no title)
  343.  *
  344.  * Creates a #GimpFrame widget. A #GimpFrame is a HIG-compliant
  345.  * variant of #GtkFrame. It doesn't render a frame at all but
  346.  * otherwise behaves like a frame. The frame's title is rendered in
  347.  * bold and the frame content is indented four spaces as suggested by
  348.  * the GNOME HIG (see http://developer.gnome.org/projects/gup/hig/).
  349.  *
  350.  * Return value: a new #GimpFrame widget
  351.  *
  352.  * Since: GIMP 2.2
  353.  **/
  354. GtkWidget *
  355. gimp_frame_new (const gchar *label)
  356. {
  357.   GtkWidget *frame;
  358.   gboolean   expander = FALSE;
  359.  
  360.   /*  somewhat hackish, should perhaps be an object property of GimpFrame  */
  361.   if (label && strcmp (label, "<expander>") == 0)
  362.     {
  363.       expander = TRUE;
  364.       label    = NULL;
  365.     }
  366.  
  367.   frame = g_object_new (GIMP_TYPE_FRAME,
  368.                         "label", label,
  369.                         NULL);
  370.  
  371.   if (expander)
  372.     g_object_set_data (G_OBJECT (frame),
  373.                        GIMP_FRAME_IN_EXPANDER_KEY, (gpointer) TRUE);
  374.  
  375.   return frame;
  376. }
  377.