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