3332a354b93126d178b840dd9e05519555514446
[pspp-builds.git] / src / ui / gui / psppire-hbuttonbox.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-hbuttonbox.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_hbuttonbox_class_init          (PsppireHButtonBoxClass *);
35 static void psppire_hbuttonbox_init                (PsppireHButtonBox      *);
36
37 static void gtk_hbutton_box_size_request  (GtkWidget      *widget,
38                                            GtkRequisition *requisition);
39 static void gtk_hbutton_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_hbutton_box_get_type (void)
47 {
48   static GType hbuttonbox_type = 0;
49
50   if (!hbuttonbox_type)
51     {
52       static const GTypeInfo hbuttonbox_info =
53       {
54         sizeof (PsppireHButtonBoxClass),
55         NULL, /* base_init */
56         NULL, /* base_finalize */
57         (GClassInitFunc) psppire_hbuttonbox_class_init,
58         NULL, /* class_finalize */
59         NULL, /* class_data */
60         sizeof (PsppireHButtonBox),
61         0,
62         (GInstanceInitFunc) psppire_hbuttonbox_init,
63       };
64
65       hbuttonbox_type = g_type_register_static (PSPPIRE_BUTTONBOX_TYPE,
66                                             "PsppireHButtonBox", &hbuttonbox_info, 0);
67     }
68
69   return hbuttonbox_type;
70 }
71
72 static void
73 psppire_hbuttonbox_class_init (PsppireHButtonBoxClass *class)
74 {
75   GtkWidgetClass *widget_class;
76
77   widget_class = (GtkWidgetClass*) class;
78
79   widget_class->size_request = gtk_hbutton_box_size_request;
80   widget_class->size_allocate = gtk_hbutton_box_size_allocate;
81 }
82
83
84 static void
85 psppire_hbuttonbox_init (PsppireHButtonBox *hbuttonbox)
86 {
87 }
88
89
90 GtkWidget*
91 psppire_hbuttonbox_new (void)
92 {
93   PsppireHButtonBox *hbuttonbox ;
94
95   hbuttonbox = g_object_new (psppire_hbutton_box_get_type (), NULL);
96
97   return GTK_WIDGET (hbuttonbox) ;
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_hbutton_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->width =
141               nvis_children*child_width + ((nvis_children+1)*spacing);
142       break;
143     case GTK_BUTTONBOX_EDGE:
144     case GTK_BUTTONBOX_START:
145     case GTK_BUTTONBOX_END:
146       requisition->width = nvis_children*child_width + ((nvis_children-1)*spacing);
147       break;
148     default:
149       g_assert_not_reached();
150       break;
151     }
152
153     requisition->height = child_height;
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_hbutton_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 secondary_x = 0;
177   gint y = 0;
178   gint width;
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   width = allocation->width - GTK_CONTAINER (box)->border_width*2;
196   switch (layout)
197   {
198   case GTK_BUTTONBOX_SPREAD:
199     childspacing = (width - (nvis_children * child_width)) / (nvis_children + 1);
200     x = allocation->x + GTK_CONTAINER (box)->border_width + childspacing;
201     secondary_x = x + ((nvis_children - n_secondaries) * (child_width + childspacing));
202     break;
203   case GTK_BUTTONBOX_EDGE:
204     if (nvis_children >= 2)
205       {
206         childspacing = (width - (nvis_children * child_width)) / (nvis_children - 1);
207         x = allocation->x + GTK_CONTAINER (box)->border_width;
208         secondary_x = x + ((nvis_children - n_secondaries) * (child_width + childspacing));
209       }
210     else
211       {
212         /* one or zero children, just center */
213         childspacing = width;
214         x = secondary_x = allocation->x + (allocation->width - child_width) / 2;
215       }
216     break;
217   case GTK_BUTTONBOX_START:
218     childspacing = spacing;
219     x = allocation->x + GTK_CONTAINER (box)->border_width;
220     secondary_x = allocation->x + allocation->width
221       - child_width * n_secondaries
222       - spacing * (n_secondaries - 1)
223       - GTK_CONTAINER (box)->border_width;
224     break;
225   case GTK_BUTTONBOX_END:
226     childspacing = spacing;
227     x = allocation->x + allocation->width
228       - child_width * (nvis_children - n_secondaries)
229       - spacing * (nvis_children - n_secondaries - 1)
230       - GTK_CONTAINER (box)->border_width;
231     secondary_x = allocation->x + GTK_CONTAINER (box)->border_width;
232     break;
233   default:
234     g_assert_not_reached();
235     break;
236   }
237
238
239   y = allocation->y + (allocation->height - child_height) / 2;
240   childspace = child_width + childspacing;
241
242   children = GTK_BOX (box)->children;
243
244   while (children)
245     {
246       child = children->data;
247       children = children->next;
248
249       if (GTK_WIDGET_VISIBLE (child->widget))
250         {
251           child_allocation.width = child_width;
252           child_allocation.height = child_height;
253           child_allocation.y = y;
254
255           if (child->is_secondary)
256             {
257               child_allocation.x = secondary_x;
258               secondary_x += childspace;
259             }
260           else
261             {
262               child_allocation.x = x;
263               x += childspace;
264             }
265
266           if (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL)
267             child_allocation.x = (allocation->x + allocation->width) - (child_allocation.x + child_width - allocation->x);
268
269           gtk_widget_size_allocate (child->widget, &child_allocation);
270         }
271     }
272 }