]> Pileus Git - ~andy/gtk/blob - gtk/gtkbbox.c
Define macros GTK_PARAM_READABLE, GTK_PARAM_WRITABLE, GTK_PARAM_READWRITE
[~andy/gtk] / gtk / gtkbbox.c
1 /* GTK - The GIMP Toolkit
2  * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17  * Boston, MA 02111-1307, USA.
18  */
19
20 /*
21  * Modified by the GTK+ Team and others 1997-2000.  See the AUTHORS
22  * file for a list of people on the GTK+ Team.  See the ChangeLog
23  * files for a list of changes.  These files are distributed with
24  * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
25  */
26
27 #include <config.h>
28 #include "gtkbbox.h"
29 #include "gtkprivate.h"
30 #include "gtkintl.h"
31 #include "gtkalias.h"
32
33 enum {
34   PROP_0,
35   PROP_LAYOUT_STYLE,
36   PROP_LAST
37 };
38
39 enum {
40   CHILD_PROP_0,
41   CHILD_PROP_SECONDARY
42 };
43
44 static void gtk_button_box_class_init         (GtkButtonBoxClass *klass);
45 static void gtk_button_box_init               (GtkButtonBox      *box);
46 static void gtk_button_box_set_property       (GObject           *object,
47                                                guint              prop_id,
48                                                const GValue      *value,
49                                                GParamSpec        *pspec);
50 static void gtk_button_box_get_property       (GObject           *object,
51                                                guint              prop_id,
52                                                GValue            *value,
53                                                GParamSpec        *pspec);
54 static void gtk_button_box_set_child_property (GtkContainer      *container,
55                                                GtkWidget         *child,
56                                                guint              property_id,
57                                                const GValue      *value,
58                                                GParamSpec        *pspec);
59 static void gtk_button_box_get_child_property (GtkContainer      *container,
60                                                GtkWidget         *child,
61                                                guint              property_id,
62                                                GValue            *value,
63                                                GParamSpec        *pspec);
64
65 #define DEFAULT_CHILD_MIN_WIDTH 85
66 #define DEFAULT_CHILD_MIN_HEIGHT 27
67 #define DEFAULT_CHILD_IPAD_X 4
68 #define DEFAULT_CHILD_IPAD_Y 0
69
70 GType
71 gtk_button_box_get_type (void)
72 {
73   static GType button_box_type = 0;
74
75   if (!button_box_type)
76     {
77       static const GTypeInfo button_box_info =
78       {
79         sizeof (GtkButtonBoxClass),
80         NULL,           /* base_init */
81         NULL,           /* base_finalize */
82         (GClassInitFunc) gtk_button_box_class_init,
83         NULL,           /* class_finalize */
84         NULL,           /* class_data */
85         sizeof (GtkButtonBox),
86         0,               /* n_preallocs */
87         (GInstanceInitFunc) gtk_button_box_init,
88         NULL,           /* value_table */
89       };
90
91       button_box_type =
92         g_type_register_static (GTK_TYPE_BOX, "GtkButtonBox",
93                                 &button_box_info, G_TYPE_FLAG_ABSTRACT);
94     }
95
96   return button_box_type;
97 }
98
99 static void
100 gtk_button_box_class_init (GtkButtonBoxClass *class)
101 {
102   GtkWidgetClass *widget_class;
103   GObjectClass *gobject_class;
104   GtkContainerClass *container_class;
105
106   gobject_class = G_OBJECT_CLASS (class);
107   widget_class = (GtkWidgetClass*) class;
108   container_class = (GtkContainerClass*) class;
109
110   gobject_class->set_property = gtk_button_box_set_property;
111   gobject_class->get_property = gtk_button_box_get_property;
112
113   container_class->set_child_property = gtk_button_box_set_child_property;
114   container_class->get_child_property = gtk_button_box_get_child_property;
115   
116   /* FIXME we need to override the "spacing" property on GtkBox once
117    * libgobject allows that.
118    */
119   gtk_widget_class_install_style_property (widget_class,
120                                            g_param_spec_int ("child-min-width",
121                                                              P_("Minimum child width"),
122                                                              P_("Minimum width of buttons inside the box"),
123                                                              0,
124                                                              G_MAXINT,
125                                                              DEFAULT_CHILD_MIN_WIDTH,
126                                                              GTK_PARAM_READABLE));
127
128   gtk_widget_class_install_style_property (widget_class,
129                                            g_param_spec_int ("child-min-height",
130                                                              P_("Minimum child height"),
131                                                              P_("Minimum height of buttons inside the box"),
132                                                              0,
133                                                              G_MAXINT,
134                                                              DEFAULT_CHILD_MIN_HEIGHT,
135                                                              GTK_PARAM_READABLE));
136
137   gtk_widget_class_install_style_property (widget_class,
138                                            g_param_spec_int ("child-internal-pad-x",
139                                                              P_("Child internal width padding"),
140                                                              P_("Amount to increase child's size on either side"),
141                                                              0,
142                                                              G_MAXINT,
143                                                              DEFAULT_CHILD_IPAD_X,
144                                                              GTK_PARAM_READABLE));
145
146   gtk_widget_class_install_style_property (widget_class,
147                                            g_param_spec_int ("child-internal-pad-y",
148                                                              P_("Child internal height padding"),
149                                                              P_("Amount to increase child's size on the top and bottom"),
150                                                              0,
151                                                              G_MAXINT,
152                                                              DEFAULT_CHILD_IPAD_Y,
153                                                              GTK_PARAM_READABLE));
154   g_object_class_install_property (gobject_class,
155                                    PROP_LAYOUT_STYLE,
156                                    g_param_spec_enum ("layout-style",
157                                                       P_("Layout style"),
158                                                       P_("How to layout the buttons in the box. Possible values are default, spread, edge, start and end"),
159                                                       GTK_TYPE_BUTTON_BOX_STYLE,
160                                                       GTK_BUTTONBOX_DEFAULT_STYLE,
161                                                       GTK_PARAM_READWRITE));
162
163   gtk_container_class_install_child_property (container_class,
164                                               CHILD_PROP_SECONDARY,
165                                               g_param_spec_boolean ("secondary", 
166                                                                     P_("Secondary"),
167                                                                     P_("If TRUE, the child appears in a secondary group of children, suitable for, e.g., help buttons"),
168                                                                     FALSE,
169                                                                     GTK_PARAM_READWRITE));
170 }
171
172 static void
173 gtk_button_box_init (GtkButtonBox *button_box)
174 {
175   GTK_BOX (button_box)->spacing = 0;
176   button_box->child_min_width = GTK_BUTTONBOX_DEFAULT;
177   button_box->child_min_height = GTK_BUTTONBOX_DEFAULT;
178   button_box->child_ipad_x = GTK_BUTTONBOX_DEFAULT;
179   button_box->child_ipad_y = GTK_BUTTONBOX_DEFAULT;
180   button_box->layout_style = GTK_BUTTONBOX_DEFAULT_STYLE;
181 }
182
183 static void
184 gtk_button_box_set_property (GObject         *object,
185                              guint            prop_id,
186                              const GValue    *value,
187                              GParamSpec      *pspec)
188 {
189   switch (prop_id) 
190     {
191     case PROP_LAYOUT_STYLE:
192       gtk_button_box_set_layout (GTK_BUTTON_BOX (object),
193                                  g_value_get_enum (value));
194       break;
195     default:
196       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
197       break;
198     }
199 }
200
201 static void
202 gtk_button_box_get_property (GObject         *object,
203                              guint            prop_id,
204                              GValue          *value,
205                              GParamSpec      *pspec)
206 {
207   switch (prop_id)
208     {
209     case PROP_LAYOUT_STYLE:
210       g_value_set_enum (value, GTK_BUTTON_BOX (object)->layout_style);
211       break;
212     default:
213       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
214       break;
215     }
216 }
217
218 static void
219 gtk_button_box_set_child_property (GtkContainer    *container,
220                                    GtkWidget       *child,
221                                    guint            property_id,
222                                    const GValue    *value,
223                                    GParamSpec      *pspec)
224 {
225   switch (property_id)
226     {
227     case CHILD_PROP_SECONDARY:
228       gtk_button_box_set_child_secondary (GTK_BUTTON_BOX (container), child,
229                                           g_value_get_boolean (value));
230       break;
231     default:
232       GTK_CONTAINER_WARN_INVALID_CHILD_PROPERTY_ID (container, property_id, pspec);
233       break;
234     }
235 }
236
237 static void
238 gtk_button_box_get_child_property (GtkContainer *container,
239                                    GtkWidget    *child,
240                                    guint         property_id,
241                                    GValue       *value,
242                                    GParamSpec   *pspec)
243 {
244   switch (property_id)
245     {
246     case CHILD_PROP_SECONDARY:
247       g_value_set_boolean (value, 
248                            gtk_button_box_get_child_secondary (GTK_BUTTON_BOX (container), 
249                                                                child));
250       break;
251     default:
252       GTK_CONTAINER_WARN_INVALID_CHILD_PROPERTY_ID (container, property_id, pspec);
253       break;
254     }
255 }
256
257 /* set per widget values for spacing, child size and child internal padding */
258
259 void 
260 gtk_button_box_set_child_size (GtkButtonBox *widget, 
261                                gint width, gint height)
262 {
263   g_return_if_fail (GTK_IS_BUTTON_BOX (widget));
264
265   widget->child_min_width = width;
266   widget->child_min_height = height;
267 }
268
269 void 
270 gtk_button_box_set_child_ipadding (GtkButtonBox *widget,
271                                    gint ipad_x, gint ipad_y)
272 {
273   g_return_if_fail (GTK_IS_BUTTON_BOX (widget));
274
275   widget->child_ipad_x = ipad_x;
276   widget->child_ipad_y = ipad_y;
277 }
278
279 void
280 gtk_button_box_set_layout (GtkButtonBox      *widget, 
281                            GtkButtonBoxStyle  layout_style)
282 {
283   g_return_if_fail (GTK_IS_BUTTON_BOX (widget));
284   g_return_if_fail (layout_style >= GTK_BUTTONBOX_DEFAULT_STYLE &&
285                     layout_style <= GTK_BUTTONBOX_END);
286
287   if (widget->layout_style != layout_style)
288     {
289       widget->layout_style = layout_style;
290       g_object_notify (G_OBJECT (widget), "layout_style");
291       gtk_widget_queue_resize (GTK_WIDGET (widget));
292     }
293 }
294
295
296 /* get per widget values for spacing, child size and child internal padding */
297
298 void 
299 gtk_button_box_get_child_size (GtkButtonBox *widget,
300                                gint *width, gint *height)
301 {
302   g_return_if_fail (GTK_IS_BUTTON_BOX (widget));
303   g_return_if_fail (width != NULL);
304   g_return_if_fail (height != NULL);
305
306   *width  = widget->child_min_width;
307   *height = widget->child_min_height;
308 }
309
310 void
311 gtk_button_box_get_child_ipadding (GtkButtonBox *widget,
312                                    gint* ipad_x, gint *ipad_y)
313 {
314   g_return_if_fail (GTK_IS_BUTTON_BOX (widget));
315   g_return_if_fail (ipad_x != NULL);
316   g_return_if_fail (ipad_y != NULL);
317
318   *ipad_x = widget->child_ipad_x;
319   *ipad_y = widget->child_ipad_y;
320 }
321
322 GtkButtonBoxStyle 
323 gtk_button_box_get_layout (GtkButtonBox *widget)
324 {
325   g_return_val_if_fail (GTK_IS_BUTTON_BOX (widget), GTK_BUTTONBOX_SPREAD);
326   
327   return widget->layout_style;
328 }
329
330 /**
331  * gtk_button_box_get_child_secondary:
332  * @widget: a #GtkButtonBox
333  * @child: a child of @widget 
334  * 
335  * Returns whether @child should appear in a secondary group of children.
336  *
337  * Return value: whether @child should appear in a secondary group of children.
338  *
339  * Since: 2.4
340  **/
341 gboolean 
342 gtk_button_box_get_child_secondary (GtkButtonBox *widget,
343                                     GtkWidget    *child)
344 {
345   GList *list;
346   GtkBoxChild *child_info;
347
348   g_return_val_if_fail (GTK_IS_BUTTON_BOX (widget), FALSE);
349   g_return_val_if_fail (GTK_IS_WIDGET (child), FALSE);
350
351   child_info = NULL;
352   list = GTK_BOX (widget)->children;
353   while (list)
354     {
355       child_info = list->data;
356       if (child_info->widget == child)
357         break;
358
359       list = list->next;
360     }
361
362   g_return_val_if_fail (list != NULL, FALSE);
363
364   return child_info->is_secondary;
365 }
366
367 /**
368  * gtk_button_box_set_child_secondary
369  * @widget: a #GtkButtonBox
370  * @child: a child of @widget
371  * @is_secondary: if %TRUE, the @child appears in a secondary group of the
372  *                button box.
373  *
374  * Sets whether @child should appear in a secondary group of children.
375  * A typical use of a secondary child is the help button in a dialog.
376  *
377  * This group appears after the other children if the style
378  * is %GTK_BUTTONBOX_START, %GTK_BUTTONBOX_SPREAD or
379  * %GTK_BUTTONBOX_EDGE, and before the other children if the style
380  * is %GTK_BUTTONBOX_END. For horizontal button boxes, the definition
381  * of before/after depends on direction of the widget (see
382  * gtk_widget_set_direction()). If the style is %GTK_BUTTONBOX_START
383  * or %GTK_BUTTONBOX_END, then the secondary children are aligned at
384  * the other end of the button box from the main children. For the
385  * other styles, they appear immediately next to the main children.
386  **/
387 void 
388 gtk_button_box_set_child_secondary (GtkButtonBox *widget, 
389                                     GtkWidget    *child,
390                                     gboolean      is_secondary)
391 {
392   GList *list;
393   
394   g_return_if_fail (GTK_IS_BUTTON_BOX (widget));
395   g_return_if_fail (GTK_IS_WIDGET (child));
396   g_return_if_fail (child->parent == GTK_WIDGET (widget));
397
398   list = GTK_BOX (widget)->children;
399   while (list)
400     {
401       GtkBoxChild *child_info = list->data;
402       if (child_info->widget == child)
403         {
404           child_info->is_secondary = is_secondary;
405           break;
406         }
407
408       list = list->next;
409     }
410
411   gtk_widget_child_notify (child, "secondary");
412
413   if (GTK_WIDGET_VISIBLE (widget) && GTK_WIDGET_VISIBLE (child))
414     gtk_widget_queue_resize (child);
415 }
416
417 /* Ask children how much space they require and round up 
418    to match minimum size and internal padding.
419    Returns the size each single child should have. */
420 void
421 _gtk_button_box_child_requisition (GtkWidget *widget,
422                                    int       *nvis_children,
423                                    int       *nvis_secondaries,
424                                    int       *width,
425                                    int       *height)
426 {
427   GtkButtonBox *bbox;
428   GtkBoxChild *child;
429   GList *children;
430   gint nchildren;
431   gint nsecondaries;
432   gint needed_width;
433   gint needed_height;
434   GtkRequisition child_requisition;
435   gint ipad_w;
436   gint ipad_h;
437   gint width_default;
438   gint height_default;
439   gint ipad_x_default;
440   gint ipad_y_default;
441   
442   gint child_min_width;
443   gint child_min_height;
444   gint ipad_x;
445   gint ipad_y;
446   
447   g_return_if_fail (GTK_IS_BUTTON_BOX (widget));
448
449   bbox = GTK_BUTTON_BOX (widget);
450
451   gtk_widget_style_get (widget,
452                         "child_min_width",
453                         &width_default,
454                         "child_min_height",
455                         &height_default,
456                         "child_internal_pad_x",
457                         &ipad_x_default,
458                         "child_internal_pad_y",
459                         &ipad_y_default, NULL);
460   
461   child_min_width = bbox->child_min_width   != GTK_BUTTONBOX_DEFAULT
462           ? bbox->child_min_width : width_default;
463   child_min_height = bbox->child_min_height !=GTK_BUTTONBOX_DEFAULT
464           ? bbox->child_min_height : height_default;
465   ipad_x = bbox->child_ipad_x != GTK_BUTTONBOX_DEFAULT
466           ? bbox->child_ipad_x : ipad_x_default;
467   ipad_y = bbox->child_ipad_y != GTK_BUTTONBOX_DEFAULT
468           ? bbox->child_ipad_y : ipad_y_default;
469
470   nchildren = 0;
471   nsecondaries = 0;
472   children = GTK_BOX(bbox)->children;
473   needed_width = child_min_width;
474   needed_height = child_min_height;  
475   ipad_w = ipad_x * 2;
476   ipad_h = ipad_y * 2;
477   
478   while (children)
479     {
480       child = children->data;
481       children = children->next;
482
483       if (GTK_WIDGET_VISIBLE (child->widget))
484         {
485           nchildren += 1;
486           gtk_widget_size_request (child->widget, &child_requisition);
487           
488           if (child_requisition.width + ipad_w > needed_width)
489             needed_width = child_requisition.width + ipad_w;
490           if (child_requisition.height + ipad_h > needed_height)
491             needed_height = child_requisition.height + ipad_h;
492           if (child->is_secondary)
493             nsecondaries++;
494         }
495     }
496
497   if (nvis_children)
498     *nvis_children = nchildren;
499   if (nvis_secondaries)
500     *nvis_secondaries = nsecondaries;
501   if (width)
502     *width = needed_width;
503   if (height)
504     *height = needed_height;
505 }
506
507 #define __GTK_BUTTON_BOX_C__
508 #include "gtkaliasdef.c"