]> Pileus Git - ~andy/gtk/blob - gtk/gtkalignment.c
9c33fd3077201aaa5501a2ef7b6fd1961f3a3feb
[~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   gtk_widget_set_redraw_on_allocate (GTK_WIDGET (alignment), FALSE);
143
144   alignment->xalign = 0.5;
145   alignment->yalign = 0.5;
146   alignment->xscale = 1.0;
147   alignment->yscale = 1.0;
148 }
149
150 GtkWidget*
151 gtk_alignment_new (gfloat xalign,
152                    gfloat yalign,
153                    gfloat xscale,
154                    gfloat yscale)
155 {
156   GtkAlignment *alignment;
157
158   alignment = gtk_type_new (gtk_alignment_get_type ());
159
160   alignment->xalign = CLAMP (xalign, 0.0, 1.0);
161   alignment->yalign = CLAMP (yalign, 0.0, 1.0);
162   alignment->xscale = CLAMP (xscale, 0.0, 1.0);
163   alignment->yscale = CLAMP (yscale, 0.0, 1.0);
164
165   return GTK_WIDGET (alignment);
166 }
167
168 static void
169 gtk_alignment_set_property (GObject         *object,
170                             guint            prop_id,
171                             const GValue    *value,
172                             GParamSpec      *pspec)
173 {
174   GtkAlignment *alignment;
175   
176   alignment = GTK_ALIGNMENT (object);
177   
178   switch (prop_id)
179     {
180     case PROP_XALIGN:
181       gtk_alignment_set (alignment,
182                          g_value_get_float (value),
183                          alignment->yalign,
184                          alignment->xscale,
185                          alignment->yscale);
186       break;
187     case PROP_YALIGN:
188       gtk_alignment_set (alignment,
189                          alignment->xalign,
190                          g_value_get_float (value),
191                          alignment->xscale,
192                          alignment->yscale);
193       break;
194     case PROP_XSCALE:
195       gtk_alignment_set (alignment,
196                          alignment->xalign,
197                          alignment->yalign,
198                          g_value_get_float (value),
199                          alignment->yscale);
200       break;
201     case PROP_YSCALE:
202       gtk_alignment_set (alignment,
203                          alignment->xalign,
204                          alignment->yalign,
205                          alignment->xscale,
206                          g_value_get_float (value));
207       break;
208     default:
209       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
210       break;
211     }
212 }
213
214 static void
215 gtk_alignment_get_property (GObject         *object,
216                             guint            prop_id,
217                             GValue          *value,
218                             GParamSpec      *pspec)
219 {
220   GtkAlignment *alignment;
221   
222   alignment = GTK_ALIGNMENT (object);
223    
224   switch (prop_id)
225     {
226     case PROP_XALIGN:
227       g_value_set_float(value, alignment->xalign);
228       break;
229     case PROP_YALIGN:
230       g_value_set_float(value, alignment->yalign);
231       break;
232     case PROP_XSCALE:
233       g_value_set_float(value, alignment->xscale);
234       break;
235     case PROP_YSCALE:
236       g_value_set_float(value, alignment->yscale);
237       break;
238     default:
239       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
240       break;
241     }
242 }
243
244 void
245 gtk_alignment_set (GtkAlignment *alignment,
246                    gfloat        xalign,
247                    gfloat        yalign,
248                    gfloat        xscale,
249                    gfloat        yscale)
250 {
251   g_return_if_fail (GTK_IS_ALIGNMENT (alignment));
252
253   xalign = CLAMP (xalign, 0.0, 1.0);
254   yalign = CLAMP (yalign, 0.0, 1.0);
255   xscale = CLAMP (xscale, 0.0, 1.0);
256   yscale = CLAMP (yscale, 0.0, 1.0);
257
258   if (   (alignment->xalign != xalign)
259       || (alignment->yalign != yalign)
260       || (alignment->xscale != xscale)
261       || (alignment->yscale != yscale))
262     {
263       g_object_freeze_notify (G_OBJECT (alignment));
264       if (alignment->xalign != xalign)
265         {
266            alignment->xalign = xalign;
267            g_object_notify (G_OBJECT(alignment), "xalign");
268         }
269       if (alignment->yalign != yalign)
270         {
271            alignment->yalign = yalign;
272            g_object_notify (G_OBJECT(alignment), "yalign");
273         }
274       if (alignment->xscale != xscale)
275         {
276            alignment->xscale = xscale;
277            g_object_notify (G_OBJECT(alignment), "xscale");
278         }
279       if (alignment->yscale != yscale)
280         {
281            alignment->yscale = yscale;
282            g_object_notify (G_OBJECT(alignment), "yscale");
283         }
284       g_object_thaw_notify (G_OBJECT (alignment));
285
286       if (GTK_BIN (alignment)->child)
287         gtk_widget_queue_resize (GTK_BIN (alignment)->child);
288       gtk_widget_queue_draw (GTK_WIDGET (alignment));
289     }
290 }
291
292
293 static void
294 gtk_alignment_size_request (GtkWidget      *widget,
295                             GtkRequisition *requisition)
296 {
297   GtkAlignment *alignment;
298   GtkBin *bin;
299
300   g_return_if_fail (GTK_IS_ALIGNMENT (widget));
301   g_return_if_fail (requisition != NULL);
302
303   alignment = GTK_ALIGNMENT (widget);
304   bin = GTK_BIN (widget);
305
306   requisition->width = GTK_CONTAINER (widget)->border_width * 2;
307   requisition->height = GTK_CONTAINER (widget)->border_width * 2;
308
309   if (bin->child && GTK_WIDGET_VISIBLE (bin->child))
310     {
311       GtkRequisition child_requisition;
312       
313       gtk_widget_size_request (bin->child, &child_requisition);
314
315       requisition->width += child_requisition.width;
316       requisition->height += child_requisition.height;
317     }
318 }
319
320 static void
321 gtk_alignment_size_allocate (GtkWidget     *widget,
322                              GtkAllocation *allocation)
323 {
324   GtkAlignment *alignment;
325   GtkBin *bin;
326   GtkAllocation child_allocation;
327   GtkRequisition child_requisition;
328   gint width, height;
329   gint x, y;
330
331   g_return_if_fail (GTK_IS_ALIGNMENT (widget));
332   g_return_if_fail (allocation != NULL);
333
334   widget->allocation = *allocation;
335   alignment = GTK_ALIGNMENT (widget);
336   bin = GTK_BIN (widget);
337   
338   if (bin->child && GTK_WIDGET_VISIBLE (bin->child))
339     {
340       gtk_widget_get_child_requisition (bin->child, &child_requisition);
341       
342       x = GTK_CONTAINER (alignment)->border_width;
343       y = GTK_CONTAINER (alignment)->border_width;
344       width = MAX (allocation->width - 2 * x, 0);
345       height = MAX (allocation->height - 2 * y, 0);
346       
347       if (width > child_requisition.width)
348         child_allocation.width = (child_requisition.width *
349                                   (1.0 - alignment->xscale) +
350                                   width * alignment->xscale);
351       else
352         child_allocation.width = width;
353       
354       if (height > child_requisition.height)
355         child_allocation.height = (child_requisition.height *
356                                    (1.0 - alignment->yscale) +
357                                    height * alignment->yscale);
358       else
359         child_allocation.height = height;
360
361       child_allocation.x = alignment->xalign * (width - child_allocation.width) + allocation->x + x;
362       child_allocation.y = alignment->yalign * (height - child_allocation.height) + allocation->y + y;
363
364       gtk_widget_size_allocate (bin->child, &child_allocation);
365     }
366 }