]> Pileus Git - ~andy/gtk/blob - gtk/gtkalignment.c
282f712024ea7864f880556fbf289d38138d5dd7
[~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                                                       _("Value between 0.0 and 1.0 to indicate X alignment"),
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                                                       _("Value between 0.0 and 1.0 to indicate Y alignment"),
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                                                       _("Value between 0.0 and 1.0 to indicate X scale"),
123                                                       0.0,
124                                                       1.0,
125                                                       0.5,
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                                                       _("Value between 0.0 and 1.0 to indicate Y scale"),
132                                                       0.0,
133                                                       1.0,
134                                                       0.5,
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   gboolean values_changed = FALSE; 
251   
252   g_return_if_fail (GTK_IS_ALIGNMENT (alignment));
253
254   xalign = CLAMP (xalign, 0.0, 1.0);
255   yalign = CLAMP (yalign, 0.0, 1.0);
256   xscale = CLAMP (xscale, 0.0, 1.0);
257   yscale = CLAMP (yscale, 0.0, 1.0);
258
259   if (alignment->xalign != xalign)
260     {
261        values_changed = TRUE;
262        alignment->xalign = xalign;
263        g_object_notify (G_OBJECT(alignment), "xalign");
264     }
265   if (alignment->yalign != yalign)
266     {
267        values_changed = TRUE;
268        alignment->yalign = yalign;
269        g_object_notify (G_OBJECT(alignment), "yalign");
270     }
271   if (alignment->xscale != xscale)
272     {
273        values_changed = TRUE;
274        alignment->xscale = xscale;
275        g_object_notify (G_OBJECT(alignment), "xscale");
276     }
277   if (alignment->yscale != yscale)
278     {
279        values_changed = TRUE;
280        alignment->yscale = yscale;
281        g_object_notify (G_OBJECT(alignment), "yscale");
282     }
283
284    if (values_changed == TRUE)
285     {
286       gtk_widget_size_allocate (GTK_WIDGET (alignment), &(GTK_WIDGET (alignment)->allocation));
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 }