]> Pileus Git - ~andy/gtk/blob - gtk/gtkbbox.c
609e45dc33ca995836e703eb5c068b5b51a9a608
[~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 };
37
38 enum {
39   CHILD_PROP_0,
40   CHILD_PROP_SECONDARY
41 };
42
43 static void gtk_button_box_set_property       (GObject           *object,
44                                                guint              prop_id,
45                                                const GValue      *value,
46                                                GParamSpec        *pspec);
47 static void gtk_button_box_get_property       (GObject           *object,
48                                                guint              prop_id,
49                                                GValue            *value,
50                                                GParamSpec        *pspec);
51 static void gtk_button_box_set_child_property (GtkContainer      *container,
52                                                GtkWidget         *child,
53                                                guint              property_id,
54                                                const GValue      *value,
55                                                GParamSpec        *pspec);
56 static void gtk_button_box_get_child_property (GtkContainer      *container,
57                                                GtkWidget         *child,
58                                                guint              property_id,
59                                                GValue            *value,
60                                                GParamSpec        *pspec);
61
62 #define DEFAULT_CHILD_MIN_WIDTH 85
63 #define DEFAULT_CHILD_MIN_HEIGHT 27
64 #define DEFAULT_CHILD_IPAD_X 4
65 #define DEFAULT_CHILD_IPAD_Y 0
66
67 G_DEFINE_ABSTRACT_TYPE (GtkButtonBox, gtk_button_box, GTK_TYPE_BOX)
68
69 static void
70 gtk_button_box_class_init (GtkButtonBoxClass *class)
71 {
72   GtkWidgetClass *widget_class;
73   GObjectClass *gobject_class;
74   GtkContainerClass *container_class;
75
76   gobject_class = G_OBJECT_CLASS (class);
77   widget_class = (GtkWidgetClass*) class;
78   container_class = (GtkContainerClass*) class;
79
80   gobject_class->set_property = gtk_button_box_set_property;
81   gobject_class->get_property = gtk_button_box_get_property;
82
83   container_class->set_child_property = gtk_button_box_set_child_property;
84   container_class->get_child_property = gtk_button_box_get_child_property;
85   
86   /* FIXME we need to override the "spacing" property on GtkBox once
87    * libgobject allows that.
88    */
89   gtk_widget_class_install_style_property (widget_class,
90                                            g_param_spec_int ("child-min-width",
91                                                              P_("Minimum child width"),
92                                                              P_("Minimum width of buttons inside the box"),
93                                                              0,
94                                                              G_MAXINT,
95                                                              DEFAULT_CHILD_MIN_WIDTH,
96                                                              GTK_PARAM_READABLE));
97
98   gtk_widget_class_install_style_property (widget_class,
99                                            g_param_spec_int ("child-min-height",
100                                                              P_("Minimum child height"),
101                                                              P_("Minimum height of buttons inside the box"),
102                                                              0,
103                                                              G_MAXINT,
104                                                              DEFAULT_CHILD_MIN_HEIGHT,
105                                                              GTK_PARAM_READABLE));
106
107   gtk_widget_class_install_style_property (widget_class,
108                                            g_param_spec_int ("child-internal-pad-x",
109                                                              P_("Child internal width padding"),
110                                                              P_("Amount to increase child's size on either side"),
111                                                              0,
112                                                              G_MAXINT,
113                                                              DEFAULT_CHILD_IPAD_X,
114                                                              GTK_PARAM_READABLE));
115
116   gtk_widget_class_install_style_property (widget_class,
117                                            g_param_spec_int ("child-internal-pad-y",
118                                                              P_("Child internal height padding"),
119                                                              P_("Amount to increase child's size on the top and bottom"),
120                                                              0,
121                                                              G_MAXINT,
122                                                              DEFAULT_CHILD_IPAD_Y,
123                                                              GTK_PARAM_READABLE));
124   g_object_class_install_property (gobject_class,
125                                    PROP_LAYOUT_STYLE,
126                                    g_param_spec_enum ("layout-style",
127                                                       P_("Layout style"),
128                                                       P_("How to layout the buttons in the box. Possible values are default, spread, edge, start and end"),
129                                                       GTK_TYPE_BUTTON_BOX_STYLE,
130                                                       GTK_BUTTONBOX_DEFAULT_STYLE,
131                                                       GTK_PARAM_READWRITE));
132
133   gtk_container_class_install_child_property (container_class,
134                                               CHILD_PROP_SECONDARY,
135                                               g_param_spec_boolean ("secondary", 
136                                                                     P_("Secondary"),
137                                                                     P_("If TRUE, the child appears in a secondary group of children, suitable for, e.g., help buttons"),
138                                                                     FALSE,
139                                                                     GTK_PARAM_READWRITE));
140 }
141
142 static void
143 gtk_button_box_init (GtkButtonBox *button_box)
144 {
145   GTK_BOX (button_box)->spacing = 0;
146   button_box->child_min_width = GTK_BUTTONBOX_DEFAULT;
147   button_box->child_min_height = GTK_BUTTONBOX_DEFAULT;
148   button_box->child_ipad_x = GTK_BUTTONBOX_DEFAULT;
149   button_box->child_ipad_y = GTK_BUTTONBOX_DEFAULT;
150   button_box->layout_style = GTK_BUTTONBOX_DEFAULT_STYLE;
151 }
152
153 static void
154 gtk_button_box_set_property (GObject         *object,
155                              guint            prop_id,
156                              const GValue    *value,
157                              GParamSpec      *pspec)
158 {
159   switch (prop_id) 
160     {
161     case PROP_LAYOUT_STYLE:
162       gtk_button_box_set_layout (GTK_BUTTON_BOX (object),
163                                  g_value_get_enum (value));
164       break;
165     default:
166       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
167       break;
168     }
169 }
170
171 static void
172 gtk_button_box_get_property (GObject         *object,
173                              guint            prop_id,
174                              GValue          *value,
175                              GParamSpec      *pspec)
176 {
177   switch (prop_id)
178     {
179     case PROP_LAYOUT_STYLE:
180       g_value_set_enum (value, GTK_BUTTON_BOX (object)->layout_style);
181       break;
182     default:
183       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
184       break;
185     }
186 }
187
188 static void
189 gtk_button_box_set_child_property (GtkContainer    *container,
190                                    GtkWidget       *child,
191                                    guint            property_id,
192                                    const GValue    *value,
193                                    GParamSpec      *pspec)
194 {
195   switch (property_id)
196     {
197     case CHILD_PROP_SECONDARY:
198       gtk_button_box_set_child_secondary (GTK_BUTTON_BOX (container), child,
199                                           g_value_get_boolean (value));
200       break;
201     default:
202       GTK_CONTAINER_WARN_INVALID_CHILD_PROPERTY_ID (container, property_id, pspec);
203       break;
204     }
205 }
206
207 static void
208 gtk_button_box_get_child_property (GtkContainer *container,
209                                    GtkWidget    *child,
210                                    guint         property_id,
211                                    GValue       *value,
212                                    GParamSpec   *pspec)
213 {
214   switch (property_id)
215     {
216     case CHILD_PROP_SECONDARY:
217       g_value_set_boolean (value, 
218                            gtk_button_box_get_child_secondary (GTK_BUTTON_BOX (container), 
219                                                                child));
220       break;
221     default:
222       GTK_CONTAINER_WARN_INVALID_CHILD_PROPERTY_ID (container, property_id, pspec);
223       break;
224     }
225 }
226
227 /* set per widget values for spacing, child size and child internal padding */
228
229 void 
230 gtk_button_box_set_child_size (GtkButtonBox *widget, 
231                                gint width, gint height)
232 {
233   g_return_if_fail (GTK_IS_BUTTON_BOX (widget));
234
235   widget->child_min_width = width;
236   widget->child_min_height = height;
237 }
238
239 void 
240 gtk_button_box_set_child_ipadding (GtkButtonBox *widget,
241                                    gint ipad_x, gint ipad_y)
242 {
243   g_return_if_fail (GTK_IS_BUTTON_BOX (widget));
244
245   widget->child_ipad_x = ipad_x;
246   widget->child_ipad_y = ipad_y;
247 }
248
249 void
250 gtk_button_box_set_layout (GtkButtonBox      *widget, 
251                            GtkButtonBoxStyle  layout_style)
252 {
253   g_return_if_fail (GTK_IS_BUTTON_BOX (widget));
254   g_return_if_fail (layout_style >= GTK_BUTTONBOX_DEFAULT_STYLE &&
255                     layout_style <= GTK_BUTTONBOX_CENTER);
256
257   if (widget->layout_style != layout_style)
258     {
259       widget->layout_style = layout_style;
260       g_object_notify (G_OBJECT (widget), "layout-style");
261       gtk_widget_queue_resize (GTK_WIDGET (widget));
262     }
263 }
264
265
266 /* get per widget values for spacing, child size and child internal padding */
267
268 void 
269 gtk_button_box_get_child_size (GtkButtonBox *widget,
270                                gint *width, gint *height)
271 {
272   g_return_if_fail (GTK_IS_BUTTON_BOX (widget));
273   g_return_if_fail (width != NULL);
274   g_return_if_fail (height != NULL);
275
276   *width  = widget->child_min_width;
277   *height = widget->child_min_height;
278 }
279
280 void
281 gtk_button_box_get_child_ipadding (GtkButtonBox *widget,
282                                    gint* ipad_x, gint *ipad_y)
283 {
284   g_return_if_fail (GTK_IS_BUTTON_BOX (widget));
285   g_return_if_fail (ipad_x != NULL);
286   g_return_if_fail (ipad_y != NULL);
287
288   *ipad_x = widget->child_ipad_x;
289   *ipad_y = widget->child_ipad_y;
290 }
291
292 GtkButtonBoxStyle 
293 gtk_button_box_get_layout (GtkButtonBox *widget)
294 {
295   g_return_val_if_fail (GTK_IS_BUTTON_BOX (widget), GTK_BUTTONBOX_SPREAD);
296   
297   return widget->layout_style;
298 }
299
300 /**
301  * gtk_button_box_get_child_secondary:
302  * @widget: a #GtkButtonBox
303  * @child: a child of @widget 
304  * 
305  * Returns whether @child should appear in a secondary group of children.
306  *
307  * Return value: whether @child should appear in a secondary group of children.
308  *
309  * Since: 2.4
310  **/
311 gboolean 
312 gtk_button_box_get_child_secondary (GtkButtonBox *widget,
313                                     GtkWidget    *child)
314 {
315   GList *list;
316   GtkBoxChild *child_info;
317
318   g_return_val_if_fail (GTK_IS_BUTTON_BOX (widget), FALSE);
319   g_return_val_if_fail (GTK_IS_WIDGET (child), FALSE);
320
321   child_info = NULL;
322   list = GTK_BOX (widget)->children;
323   while (list)
324     {
325       child_info = list->data;
326       if (child_info->widget == child)
327         break;
328
329       list = list->next;
330     }
331
332   g_return_val_if_fail (list != NULL, FALSE);
333
334   return child_info->is_secondary;
335 }
336
337 /**
338  * gtk_button_box_set_child_secondary
339  * @widget: a #GtkButtonBox
340  * @child: a child of @widget
341  * @is_secondary: if %TRUE, the @child appears in a secondary group of the
342  *                button box.
343  *
344  * Sets whether @child should appear in a secondary group of children.
345  * A typical use of a secondary child is the help button in a dialog.
346  *
347  * This group appears after the other children if the style
348  * is %GTK_BUTTONBOX_START, %GTK_BUTTONBOX_SPREAD or
349  * %GTK_BUTTONBOX_EDGE, and before the other children if the style
350  * is %GTK_BUTTONBOX_END. For horizontal button boxes, the definition
351  * of before/after depends on direction of the widget (see
352  * gtk_widget_set_direction()). If the style is %GTK_BUTTONBOX_START
353  * or %GTK_BUTTONBOX_END, then the secondary children are aligned at
354  * the other end of the button box from the main children. For the
355  * other styles, they appear immediately next to the main children.
356  **/
357 void 
358 gtk_button_box_set_child_secondary (GtkButtonBox *widget, 
359                                     GtkWidget    *child,
360                                     gboolean      is_secondary)
361 {
362   GList *list;
363   
364   g_return_if_fail (GTK_IS_BUTTON_BOX (widget));
365   g_return_if_fail (GTK_IS_WIDGET (child));
366   g_return_if_fail (child->parent == GTK_WIDGET (widget));
367
368   list = GTK_BOX (widget)->children;
369   while (list)
370     {
371       GtkBoxChild *child_info = list->data;
372       if (child_info->widget == child)
373         {
374           child_info->is_secondary = is_secondary;
375           break;
376         }
377
378       list = list->next;
379     }
380
381   gtk_widget_child_notify (child, "secondary");
382
383   if (GTK_WIDGET_VISIBLE (widget) && GTK_WIDGET_VISIBLE (child))
384     gtk_widget_queue_resize (child);
385 }
386
387 /* Ask children how much space they require and round up 
388    to match minimum size and internal padding.
389    Returns the size each single child should have. */
390 void
391 _gtk_button_box_child_requisition (GtkWidget *widget,
392                                    int       *nvis_children,
393                                    int       *nvis_secondaries,
394                                    int       *width,
395                                    int       *height)
396 {
397   GtkButtonBox *bbox;
398   GtkBoxChild *child;
399   GList *children;
400   gint nchildren;
401   gint nsecondaries;
402   gint needed_width;
403   gint needed_height;
404   GtkRequisition child_requisition;
405   gint ipad_w;
406   gint ipad_h;
407   gint width_default;
408   gint height_default;
409   gint ipad_x_default;
410   gint ipad_y_default;
411   
412   gint child_min_width;
413   gint child_min_height;
414   gint ipad_x;
415   gint ipad_y;
416   
417   g_return_if_fail (GTK_IS_BUTTON_BOX (widget));
418
419   bbox = GTK_BUTTON_BOX (widget);
420
421   gtk_widget_style_get (widget,
422                         "child-min-width", &width_default,
423                         "child-min-height", &height_default,
424                         "child-internal-pad-x", &ipad_x_default,
425                         "child-internal-pad-y", &ipad_y_default, 
426                         NULL);
427   
428   child_min_width = bbox->child_min_width   != GTK_BUTTONBOX_DEFAULT
429           ? bbox->child_min_width : width_default;
430   child_min_height = bbox->child_min_height !=GTK_BUTTONBOX_DEFAULT
431           ? bbox->child_min_height : height_default;
432   ipad_x = bbox->child_ipad_x != GTK_BUTTONBOX_DEFAULT
433           ? bbox->child_ipad_x : ipad_x_default;
434   ipad_y = bbox->child_ipad_y != GTK_BUTTONBOX_DEFAULT
435           ? bbox->child_ipad_y : ipad_y_default;
436
437   nchildren = 0;
438   nsecondaries = 0;
439   children = GTK_BOX(bbox)->children;
440   needed_width = child_min_width;
441   needed_height = child_min_height;  
442   ipad_w = ipad_x * 2;
443   ipad_h = ipad_y * 2;
444   
445   while (children)
446     {
447       child = children->data;
448       children = children->next;
449
450       if (GTK_WIDGET_VISIBLE (child->widget))
451         {
452           nchildren += 1;
453           gtk_widget_size_request (child->widget, &child_requisition);
454           
455           if (child_requisition.width + ipad_w > needed_width)
456             needed_width = child_requisition.width + ipad_w;
457           if (child_requisition.height + ipad_h > needed_height)
458             needed_height = child_requisition.height + ipad_h;
459           if (child->is_secondary)
460             nsecondaries++;
461         }
462     }
463
464   if (nvis_children)
465     *nvis_children = nchildren;
466   if (nvis_secondaries)
467     *nvis_secondaries = nsecondaries;
468   if (width)
469     *width = needed_width;
470   if (height)
471     *height = needed_height;
472 }
473
474 #define __GTK_BUTTON_BOX_C__
475 #include "gtkaliasdef.c"