8c6d25afbe60ca4fe76fd2519c63723aa195bde2
[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 GType
41 psppire_vbutton_box_get_type (void)
42 {
43   static GType vbuttonbox_type = 0;
44
45   if (!vbuttonbox_type)
46     {
47       static const GTypeInfo vbuttonbox_info =
48       {
49         sizeof (PsppireVButtonBoxClass),
50         NULL, /* base_init */
51         NULL, /* base_finalize */
52         (GClassInitFunc) psppire_vbuttonbox_class_init,
53         NULL, /* class_finalize */
54         NULL, /* class_data */
55         sizeof (PsppireVButtonBox),
56         0,
57         (GInstanceInitFunc) psppire_vbuttonbox_init,
58       };
59
60       vbuttonbox_type = g_type_register_static (PSPPIRE_BUTTONBOX_TYPE,
61                                             "PsppireVButtonBox", &vbuttonbox_info, 0);
62     }
63
64   return vbuttonbox_type;
65 }
66
67 static void
68 psppire_vbuttonbox_class_init (PsppireVButtonBoxClass *class)
69 {
70   GtkWidgetClass *widget_class;
71
72   widget_class = (GtkWidgetClass*) class;
73
74   widget_class->size_request = gtk_vbutton_box_size_request;
75   widget_class->size_allocate = gtk_vbutton_box_size_allocate;
76 }
77
78
79 static void
80 psppire_vbuttonbox_init (PsppireVButtonBox *vbuttonbox)
81 {
82 }
83
84
85 GtkWidget*
86 psppire_vbuttonbox_new (void)
87 {
88   PsppireVButtonBox *vbuttonbox ;
89
90   vbuttonbox = g_object_new (psppire_vbutton_box_get_type (), NULL);
91
92   return GTK_WIDGET (vbuttonbox) ;
93 }
94
95
96
97 /* The following two functions are lifted verbatim from
98    the Gtk2.10.6 library */
99
100 static void
101 gtk_vbutton_box_size_request (GtkWidget      *widget,
102                               GtkRequisition *requisition)
103 {
104   GtkBox *box;
105   GtkButtonBox *bbox;
106   gint nvis_children;
107   gint child_width;
108   gint child_height;
109   gint spacing;
110   GtkButtonBoxStyle layout;
111
112   box = GTK_BOX (widget);
113   bbox = GTK_BUTTON_BOX (widget);
114
115   spacing = gtk_box_get_spacing (box);
116   layout = gtk_button_box_get_layout (bbox);
117
118   _psppire_button_box_child_requisition (widget,
119                                          &nvis_children,
120                                          NULL,
121                                          &child_width,
122                                          &child_height);
123
124   if (nvis_children == 0)
125     {
126       requisition->width = 0;
127       requisition->height = 0;
128     }
129   else
130     {
131       switch (layout)
132       {
133       case GTK_BUTTONBOX_SPREAD:
134         requisition->height =
135                 nvis_children*child_height + ((nvis_children+1)*spacing);
136         break;
137       case GTK_BUTTONBOX_EDGE:
138       case GTK_BUTTONBOX_START:
139       case GTK_BUTTONBOX_END:
140       default:
141         requisition->height =
142                 nvis_children*child_height + ((nvis_children-1)*spacing);
143         break;
144       }
145       requisition->width = child_width;
146     }
147
148   requisition->width += gtk_container_get_border_width (GTK_CONTAINER (box)) * 2;
149   requisition->height += gtk_container_get_border_width (GTK_CONTAINER (box)) * 2;
150 }
151
152
153
154 static void
155 gtk_vbutton_box_size_allocate (GtkWidget     *widget,
156                                GtkAllocation *allocation)
157 {
158   GtkBox *base_box;
159   GtkButtonBox *box;
160   GList *children;
161   GtkAllocation child_allocation;
162   gint nvis_children;
163   gint n_secondaries;
164   gint child_width;
165   gint child_height;
166   gint x = 0;
167   gint y = 0;
168   gint secondary_y = 0;
169   gint height;
170   gint childspace;
171   gint childspacing = 0;
172   GtkButtonBoxStyle layout;
173   gint spacing;
174
175   base_box = GTK_BOX (widget);
176   box = GTK_BUTTON_BOX (widget);
177   spacing = gtk_box_get_spacing (base_box);
178   layout = gtk_button_box_get_layout (box) ;
179   _psppire_button_box_child_requisition (widget,
180                                      &nvis_children,
181                                      &n_secondaries,
182                                      &child_width,
183                                      &child_height);
184   gtk_widget_set_allocation (widget, allocation);
185   height = allocation->height - gtk_container_get_border_width (GTK_CONTAINER (box))*2;
186   switch (layout)
187   {
188   case GTK_BUTTONBOX_SPREAD:
189     childspacing = (height - (nvis_children * child_height)) / (nvis_children + 1);
190     y = allocation->y + gtk_container_get_border_width (GTK_CONTAINER (box)) + childspacing;
191     secondary_y = y + ((nvis_children - n_secondaries) * (child_height + childspacing));
192     break;
193   case GTK_BUTTONBOX_EDGE:
194   default:
195     if (nvis_children >= 2)
196       {
197         childspacing = (height - (nvis_children*child_height)) / (nvis_children-1);
198         y = allocation->y + gtk_container_get_border_width (GTK_CONTAINER (box));
199         secondary_y = y + ((nvis_children - n_secondaries) * (child_height + childspacing));
200       }
201     else
202       {
203         /* one or zero children, just center */
204         childspacing = height;
205         y = secondary_y = allocation->y + (allocation->height - child_height) / 2;
206       }
207     break;
208   case GTK_BUTTONBOX_START:
209     childspacing = spacing;
210     y = allocation->y + gtk_container_get_border_width (GTK_CONTAINER (box));
211     secondary_y = allocation->y + allocation->height
212       - child_height * n_secondaries
213       - spacing * (n_secondaries - 1)
214       - gtk_container_get_border_width (GTK_CONTAINER (box));
215     break;
216   case GTK_BUTTONBOX_END:
217     childspacing = spacing;
218     y = allocation->y + allocation->height
219       - child_height * (nvis_children - n_secondaries)
220       - spacing * (nvis_children - n_secondaries - 1)
221       - gtk_container_get_border_width (GTK_CONTAINER (box));
222     secondary_y = allocation->y + gtk_container_get_border_width (GTK_CONTAINER (box));
223     break;
224   }
225
226   x = allocation->x + (allocation->width - child_width) / 2;
227   childspace = child_height + childspacing;
228
229   children = gtk_container_get_children (GTK_CONTAINER (box));
230   while (children)
231     {
232       GtkWidget *child = children->data;
233       children = children->next;
234
235       if (gtk_widget_get_visible (child))
236         {
237           gboolean is_secondary = FALSE;
238           gtk_container_child_get (GTK_CONTAINER (box), child, "secondary", &is_secondary, NULL);
239
240           child_allocation.width = child_width;
241           child_allocation.height = child_height;
242           child_allocation.x = x;
243
244           if (is_secondary)
245             {
246               child_allocation.y = secondary_y;
247               secondary_y += childspace;
248             }
249           else
250             {
251               child_allocation.y = y;
252               y += childspace;
253             }
254
255           gtk_widget_size_allocate (child, &child_allocation);
256         }
257     }
258 }
259