]> Pileus Git - ~andy/gtk/blob - gtk/gtkalignment.c
5db7589c72b216fb0dd68b99eedde26ed25613ab
[~andy/gtk] / gtk / gtkalignment.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 "gtkalignment.h"
28 #include "gtkintl.h"
29
30 enum {
31   PROP_0,
32
33   PROP_XALIGN,
34   PROP_YALIGN,
35   PROP_XSCALE,
36   PROP_YSCALE,
37   
38   PROP_LAST
39 };
40
41
42 static void gtk_alignment_class_init    (GtkAlignmentClass *klass);
43 static void gtk_alignment_init          (GtkAlignment      *alignment);
44 static void gtk_alignment_size_request  (GtkWidget         *widget,
45                                          GtkRequisition    *requisition);
46 static void gtk_alignment_size_allocate (GtkWidget         *widget,
47                                          GtkAllocation     *allocation);
48 static void gtk_alignment_set_property (GObject         *object,
49                                         guint            prop_id,
50                                         const GValue    *value,
51                                         GParamSpec      *pspec);
52 static void gtk_alignment_get_property (GObject         *object,
53                                         guint            prop_id,
54                                         GValue          *value,
55                                         GParamSpec      *pspec);
56
57 GtkType
58 gtk_alignment_get_type (void)
59 {
60   static GtkType alignment_type = 0;
61
62   if (!alignment_type)
63     {
64       static const GtkTypeInfo alignment_info =
65       {
66         "GtkAlignment",
67         sizeof (GtkAlignment),
68         sizeof (GtkAlignmentClass),
69         (GtkClassInitFunc) gtk_alignment_class_init,
70         (GtkObjectInitFunc) gtk_alignment_init,
71         /* reserved_1 */ NULL,
72         /* reserved_2 */ NULL,
73         (GtkClassInitFunc) NULL,
74       };
75
76       alignment_type = gtk_type_unique (GTK_TYPE_BIN, &alignment_info);
77     }
78
79   return alignment_type;
80 }
81
82 static void
83 gtk_alignment_class_init (GtkAlignmentClass *class)
84 {
85   GObjectClass *gobject_class;
86   GtkObjectClass *object_class;
87   GtkWidgetClass *widget_class;
88
89   gobject_class = (GObjectClass*) class;
90   object_class = (GtkObjectClass*) class;
91   widget_class = (GtkWidgetClass*) class;
92   
93   gobject_class->set_property = gtk_alignment_set_property;
94   gobject_class->get_property = gtk_alignment_get_property;
95
96   widget_class->size_request = gtk_alignment_size_request;
97   widget_class->size_allocate = gtk_alignment_size_allocate;
98   
99   g_object_class_install_property (gobject_class,
100                                    PROP_XALIGN,
101                                    g_param_spec_float("xalign",
102                                                       _("Horizontal alignment"),
103                                                       _("Horizontal position of child in available space. 0.0 is left aligned, 1.0 is right aligned"),
104                                                       0.0,
105                                                       1.0,
106                                                       0.5,
107                                                       G_PARAM_READABLE | G_PARAM_WRITABLE));
108    
109   g_object_class_install_property (gobject_class,
110                                    PROP_YALIGN,
111                                    g_param_spec_float("yalign",
112                                                       _("Vertical alignment"),
113                                                       _("Vertical position of child in available space. 0.0 is top aligned, 1.0 is bottom aligned"),
114                                                       0.0,
115                                                       1.0,
116                                                       0.5,
117                                                       G_PARAM_READABLE | G_PARAM_WRITABLE));
118   g_object_class_install_property (gobject_class,
119                                    PROP_XSCALE,
120                                    g_param_spec_float("xscale",
121                                                       _("Horizontal scale"),
122                                                       _("If available horizontal space is bigger than needed for the child, how much of it to use for the child. 0.0 means none, 1.0 means all"),
123                                                       0.0,
124                                                       1.0,
125                                                       1.0,
126                                                       G_PARAM_READABLE | G_PARAM_WRITABLE));
127   g_object_class_install_property (gobject_class,
128                                    PROP_YSCALE,
129                                    g_param_spec_float("yscale",
130                                                       _("Vertical scale"),
131                                                       _("If available vertical space is bigger than needed for the child, how much of it to use for the child. 0.0 means none, 1.0 means all"),
132                                                       0.0,
133                                                       1.0,
134                                                       1.0,
135                                                       G_PARAM_READABLE | G_PARAM_WRITABLE));
136 }
137
138 static void
139 gtk_alignment_init (GtkAlignment *alignment)
140 {
141   GTK_WIDGET_SET_FLAGS (alignment, GTK_NO_WINDOW);
142
143   alignment->xalign = 0.5;
144   alignment->yalign = 0.5;
145   alignment->xscale = 1.0;
146   alignment->yscale = 1.0;
147 }
148
149 GtkWidget*
150 gtk_alignment_new (gfloat xalign,
151                    gfloat yalign,
152                    gfloat xscale,
153                    gfloat yscale)
154 {
155   GtkAlignment *alignment;
156
157   alignment = gtk_type_new (gtk_alignment_get_type ());
158
159   alignment->xalign = CLAMP (xalign, 0.0, 1.0);
160   alignment->yalign = CLAMP (yalign, 0.0, 1.0);
161   alignment->xscale = CLAMP (xscale, 0.0, 1.0);
162   alignment->yscale = CLAMP (yscale, 0.0, 1.0);
163
164   return GTK_WIDGET (alignment);
165 }
166
167 static void
168 gtk_alignment_set_property (GObject         *object,
169                             guint            prop_id,
170                             const GValue    *value,
171                             GParamSpec      *pspec)
172 {
173   GtkAlignment *alignment;
174   
175   alignment = GTK_ALIGNMENT (object);
176   
177   switch (prop_id)
178     {
179     case PROP_XALIGN:
180       gtk_alignment_set (alignment,
181                          g_value_get_float (value),
182                          alignment->yalign,
183                          alignment->xscale,
184                          alignment->yscale);
185       break;
186     case PROP_YALIGN:
187       gtk_alignment_set (alignment,
188                          alignment->xalign,
189                          g_value_get_float (value),
190                          alignment->xscale,
191                          alignment->yscale);
192       break;
193     case PROP_XSCALE:
194       gtk_alignment_set (alignment,
195                          alignment->xalign,
196                          alignment->yalign,
197                          g_value_get_float (value),
198                          alignment->yscale);
199       break;
200     case PROP_YSCALE:
201       gtk_alignment_set (alignment,
202                          alignment->xalign,
203                          alignment->yalign,
204                          alignment->xscale,
205                          g_value_get_float (value));
206       break;
207     default:
208       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
209       break;
210     }
211 }
212
213 static void
214 gtk_alignment_get_property (GObject         *object,
215                             guint            prop_id,
216                             GValue          *value,
217                             GParamSpec      *pspec)
218 {
219   GtkAlignment *alignment;
220   
221   alignment = GTK_ALIGNMENT (object);
222    
223   switch (prop_id)
224     {
225     case PROP_XALIGN:
226       g_value_set_float(value, alignment->xalign);
227       break;
228     case PROP_YALIGN:
229       g_value_set_float(value, alignment->yalign);
230       break;
231     case PROP_XSCALE:
232       g_value_set_float(value, alignment->xscale);
233       break;
234     case PROP_YSCALE:
235       g_value_set_float(value, alignment->yscale);
236       break;
237     default:
238       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
239       break;
240     }
241 }
242
243 void
244 gtk_alignment_set (GtkAlignment *alignment,
245                    gfloat        xalign,
246                    gfloat        yalign,
247                    gfloat        xscale,
248                    gfloat        yscale)
249 {
250   g_return_if_fail (GTK_IS_ALIGNMENT (alignment));
251
252   xalign = CLAMP (xalign, 0.0, 1.0);
253   yalign = CLAMP (yalign, 0.0, 1.0);
254   xscale = CLAMP (xscale, 0.0, 1.0);
255   yscale = CLAMP (yscale, 0.0, 1.0);
256
257   if (   (alignment->xalign != xalign)
258       || (alignment->yalign != yalign)
259       || (alignment->xscale != xscale)
260       || (alignment->yscale != yscale))
261     {
262       g_object_freeze_notify (G_OBJECT (alignment));
263       if (alignment->xalign != xalign)
264         {
265            alignment->xalign = xalign;
266            g_object_notify (G_OBJECT(alignment), "xalign");
267         }
268       if (alignment->yalign != yalign)
269         {
270            alignment->yalign = yalign;
271            g_object_notify (G_OBJECT(alignment), "yalign");
272         }
273       if (alignment->xscale != xscale)
274         {
275            alignment->xscale = xscale;
276            g_object_notify (G_OBJECT(alignment), "xscale");
277         }
278       if (alignment->yscale != yscale)
279         {
280            alignment->yscale = yscale;
281            g_object_notify (G_OBJECT(alignment), "yscale");
282         }
283       g_object_thaw_notify (G_OBJECT (alignment));
284
285       if (GTK_BIN (alignment)->child)
286         gtk_widget_queue_resize (GTK_BIN (alignment)->child);
287       gtk_widget_queue_draw (GTK_WIDGET (alignment));
288     }
289 }
290
291
292 static void
293 gtk_alignment_size_request (GtkWidget      *widget,
294                             GtkRequisition *requisition)
295 {
296   GtkAlignment *alignment;
297   GtkBin *bin;
298
299   g_return_if_fail (GTK_IS_ALIGNMENT (widget));
300   g_return_if_fail (requisition != NULL);
301
302   alignment = GTK_ALIGNMENT (widget);
303   bin = GTK_BIN (widget);
304
305   requisition->width = GTK_CONTAINER (widget)->border_width * 2;
306   requisition->height = GTK_CONTAINER (widget)->border_width * 2;
307
308   if (bin->child && GTK_WIDGET_VISIBLE (bin->child))
309     {
310       GtkRequisition child_requisition;
311       
312       gtk_widget_size_request (bin->child, &child_requisition);
313
314       requisition->width += child_requisition.width;
315       requisition->height += child_requisition.height;
316     }
317 }
318
319 static void
320 gtk_alignment_size_allocate (GtkWidget     *widget,
321                              GtkAllocation *allocation)
322 {
323   GtkAlignment *alignment;
324   GtkBin *bin;
325   GtkAllocation child_allocation;
326   GtkRequisition child_requisition;
327   gint width, height;
328   gint x, y;
329
330   g_return_if_fail (GTK_IS_ALIGNMENT (widget));
331   g_return_if_fail (allocation != NULL);
332
333   widget->allocation = *allocation;
334   alignment = GTK_ALIGNMENT (widget);
335   bin = GTK_BIN (widget);
336   
337   if (bin->child && GTK_WIDGET_VISIBLE (bin->child))
338     {
339       gtk_widget_get_child_requisition (bin->child, &child_requisition);
340       
341       x = GTK_CONTAINER (alignment)->border_width;
342       y = GTK_CONTAINER (alignment)->border_width;
343       width = MAX (allocation->width - 2 * x, 0);
344       height = MAX (allocation->height - 2 * y, 0);
345       
346       if (width > child_requisition.width)
347         child_allocation.width = (child_requisition.width *
348                                   (1.0 - alignment->xscale) +
349                                   width * alignment->xscale);
350       else
351         child_allocation.width = width;
352       
353       if (height > child_requisition.height)
354         child_allocation.height = (child_requisition.height *
355                                    (1.0 - alignment->yscale) +
356                                    height * alignment->yscale);
357       else
358         child_allocation.height = height;
359
360       child_allocation.x = alignment->xalign * (width - child_allocation.width) + allocation->x + x;
361       child_allocation.y = alignment->yalign * (height - child_allocation.height) + allocation->y + y;
362
363       gtk_widget_size_allocate (bin->child, &child_allocation);
364     }
365 }