Merge 'master' into 'gtk3'.
[pspp] / src / ui / gui / psppire-vbuttonbox.c
1 /* PSPPIRE - a graphical user interface for PSPP.
2    Copyright (C) 2007, 2010, 2011  Free Software Foundation
3
4    This program is free software: you can redistribute it and/or modify
5    it under the terms of the GNU General Public License as published by
6    the Free Software Foundation, either version 3 of the License, or
7    (at your option) any later version.
8
9    This program 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
12    GNU General Public License for more details.
13
14    You should have received a copy of the GNU General Public License
15    along with this program.  If not, see <http://www.gnu.org/licenses/>. */
16
17
18 #include <config.h>
19
20 #include <glib.h>
21 #include <gtk/gtk.h>
22 #include "psppire-vbuttonbox.h"
23 #include "psppire-dialog.h"
24
25 #include <gettext.h>
26
27 #define _(msgid) gettext (msgid)
28 #define N_(msgid) msgid
29
30
31 static void psppire_vbuttonbox_class_init          (PsppireVButtonBoxClass *);
32 static void psppire_vbuttonbox_init                (PsppireVButtonBox      *);
33
34 static void gtk_vbutton_box_size_request  (GtkWidget      *widget,
35                                            GtkRequisition *requisition);
36 static void gtk_vbutton_box_size_allocate (GtkWidget      *widget,
37                                            GtkAllocation  *allocation);
38
39
40 static void
41 psppire_vbutton_box_get_preferred_height (GtkWidget *widget,
42                                 gint      *minimal_height,
43                                 gint      *natural_height)
44 {
45   GtkRequisition requisition;
46
47   gtk_vbutton_box_size_request (widget, &requisition);
48
49   *minimal_height = *natural_height = requisition.height;
50 }
51
52
53 static void
54 psppire_vbutton_box_get_preferred_width (GtkWidget *widget,
55                                 gint      *minimal_width,
56                                 gint      *natural_width)
57 {
58   GtkRequisition requisition;
59
60   gtk_vbutton_box_size_request (widget, &requisition);
61
62   *minimal_width = *natural_width = requisition.width;
63 }
64
65
66 GType
67 psppire_vbutton_box_get_type (void)
68 {
69   static GType vbuttonbox_type = 0;
70
71   if (!vbuttonbox_type)
72     {
73       static const GTypeInfo vbuttonbox_info =
74       {
75         sizeof (PsppireVButtonBoxClass),
76         NULL, /* base_init */
77         NULL, /* base_finalize */
78         (GClassInitFunc) psppire_vbuttonbox_class_init,
79         NULL, /* class_finalize */
80         NULL, /* class_data */
81         sizeof (PsppireVButtonBox),
82         0,
83         (GInstanceInitFunc) psppire_vbuttonbox_init,
84       };
85
86       vbuttonbox_type = g_type_register_static (PSPPIRE_BUTTONBOX_TYPE,
87                                             "PsppireVButtonBox", &vbuttonbox_info, 0);
88     }
89
90   return vbuttonbox_type;
91 }
92
93 static void
94 psppire_vbuttonbox_class_init (PsppireVButtonBoxClass *class)
95 {
96   GtkWidgetClass *widget_class;
97
98   widget_class = (GtkWidgetClass*) class;
99
100   widget_class->get_preferred_width = psppire_vbutton_box_get_preferred_width;
101   widget_class->get_preferred_height = psppire_vbutton_box_get_preferred_height;
102   widget_class->size_allocate = gtk_vbutton_box_size_allocate;
103 }
104
105
106 static void
107 psppire_vbuttonbox_init (PsppireVButtonBox *vbuttonbox)
108 {
109 }
110
111
112 GtkWidget*
113 psppire_vbuttonbox_new (void)
114 {
115   PsppireVButtonBox *vbuttonbox ;
116
117   vbuttonbox = g_object_new (psppire_vbutton_box_get_type (), NULL);
118
119   return GTK_WIDGET (vbuttonbox) ;
120 }
121
122
123
124 /* The following two functions are lifted verbatim from
125    the Gtk2.10.6 library */
126
127 static void
128 gtk_vbutton_box_size_request (GtkWidget      *widget,
129                               GtkRequisition *requisition)
130 {
131   GtkBox *box;
132   GtkButtonBox *bbox;
133   gint nvis_children;
134   gint child_width;
135   gint child_height;
136   gint spacing;
137   GtkButtonBoxStyle layout;
138
139   box = GTK_BOX (widget);
140   bbox = GTK_BUTTON_BOX (widget);
141
142   spacing = gtk_box_get_spacing (box);
143   layout = gtk_button_box_get_layout (bbox);
144
145   _psppire_button_box_child_requisition (widget,
146                                          &nvis_children,
147                                          NULL,
148                                          &child_width,
149                                          &child_height);
150
151   if (nvis_children == 0)
152     {
153       requisition->width = 0;
154       requisition->height = 0;
155     }
156   else
157     {
158       switch (layout)
159       {
160       case GTK_BUTTONBOX_SPREAD:
161         requisition->height =
162                 nvis_children*child_height + ((nvis_children+1)*spacing);
163         break;
164       case GTK_BUTTONBOX_EDGE:
165       case GTK_BUTTONBOX_START:
166       case GTK_BUTTONBOX_END:
167       default:
168         requisition->height =
169                 nvis_children*child_height + ((nvis_children-1)*spacing);
170         break;
171       }
172       requisition->width = child_width;
173     }
174
175   requisition->width += gtk_container_get_border_width (GTK_CONTAINER (box)) * 2;
176   requisition->height += gtk_container_get_border_width (GTK_CONTAINER (box)) * 2;
177 }
178
179
180
181 static void
182 gtk_vbutton_box_size_allocate (GtkWidget     *widget,
183                                GtkAllocation *allocation)
184 {
185   GtkBox *base_box;
186   GtkButtonBox *box;
187   GList *children;
188   GtkAllocation child_allocation;
189   gint nvis_children;
190   gint n_secondaries;
191   gint child_width;
192   gint child_height;
193   gint x = 0;
194   gint y = 0;
195   gint secondary_y = 0;
196   gint height;
197   gint childspace;
198   gint childspacing = 0;
199   GtkButtonBoxStyle layout;
200   gint spacing;
201
202   base_box = GTK_BOX (widget);
203   box = GTK_BUTTON_BOX (widget);
204   spacing = gtk_box_get_spacing (base_box);
205   layout = gtk_button_box_get_layout (box) ;
206   _psppire_button_box_child_requisition (widget,
207                                      &nvis_children,
208                                      &n_secondaries,
209                                      &child_width,
210                                      &child_height);
211   gtk_widget_set_allocation (widget, allocation);
212   height = allocation->height - gtk_container_get_border_width (GTK_CONTAINER (box))*2;
213   switch (layout)
214   {
215   case GTK_BUTTONBOX_SPREAD:
216     childspacing = (height - (nvis_children * child_height)) / (nvis_children + 1);
217     y = allocation->y + gtk_container_get_border_width (GTK_CONTAINER (box)) + childspacing;
218     secondary_y = y + ((nvis_children - n_secondaries) * (child_height + childspacing));
219     break;
220   case GTK_BUTTONBOX_EDGE:
221   default:
222     if (nvis_children >= 2)
223       {
224         childspacing = (height - (nvis_children*child_height)) / (nvis_children-1);
225         y = allocation->y + gtk_container_get_border_width (GTK_CONTAINER (box));
226         secondary_y = y + ((nvis_children - n_secondaries) * (child_height + childspacing));
227       }
228     else
229       {
230         /* one or zero children, just center */
231         childspacing = height;
232         y = secondary_y = allocation->y + (allocation->height - child_height) / 2;
233       }
234     break;
235   case GTK_BUTTONBOX_START:
236     childspacing = spacing;
237     y = allocation->y + gtk_container_get_border_width (GTK_CONTAINER (box));
238     secondary_y = allocation->y + allocation->height
239       - child_height * n_secondaries
240       - spacing * (n_secondaries - 1)
241       - gtk_container_get_border_width (GTK_CONTAINER (box));
242     break;
243   case GTK_BUTTONBOX_END:
244     childspacing = spacing;
245     y = allocation->y + allocation->height
246       - child_height * (nvis_children - n_secondaries)
247       - spacing * (nvis_children - n_secondaries - 1)
248       - gtk_container_get_border_width (GTK_CONTAINER (box));
249     secondary_y = allocation->y + gtk_container_get_border_width (GTK_CONTAINER (box));
250     break;
251   }
252
253   x = allocation->x + (allocation->width - child_width) / 2;
254   childspace = child_height + childspacing;
255
256   children = gtk_container_get_children (GTK_CONTAINER (box));
257   while (children)
258     {
259       GtkWidget *child = children->data;
260       children = children->next;
261
262       if (gtk_widget_get_visible (child))
263         {
264           gboolean is_secondary = FALSE;
265           gtk_container_child_get (GTK_CONTAINER (box), child, "secondary", &is_secondary, NULL);
266
267           child_allocation.width = child_width;
268           child_allocation.height = child_height;
269           child_allocation.x = x;
270
271           if (is_secondary)
272             {
273               child_allocation.y = secondary_y;
274               secondary_y += childspace;
275             }
276           else
277             {
278               child_allocation.y = y;
279               y += childspace;
280             }
281
282           gtk_widget_size_allocate (child, &child_allocation);
283         }
284     }
285 }
286