]> Pileus Git - ~andy/gtk/blob - gtk/gtkalignment.c
5f852d09c83c52d55eb2a509a2adb74e95583d2a
[~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 <config.h>
28 #include "gtkalignment.h"
29 #include "gtkprivate.h"
30 #include "gtkintl.h"
31 #include "gtkalias.h"
32
33 enum {
34   PROP_0,
35
36   PROP_XALIGN,
37   PROP_YALIGN,
38   PROP_XSCALE,
39   PROP_YSCALE,
40
41   PROP_TOP_PADDING,
42   PROP_BOTTOM_PADDING,
43   PROP_LEFT_PADDING,
44   PROP_RIGHT_PADDING,
45   
46   PROP_LAST
47 };
48
49 #define GTK_ALIGNMENT_GET_PRIVATE(o)  (G_TYPE_INSTANCE_GET_PRIVATE ((o), GTK_TYPE_ALIGNMENT, GtkAlignmentPrivate))
50
51 struct _GtkAlignmentPrivate
52 {
53   guint padding_top;
54   guint padding_bottom;
55   guint padding_left;
56   guint padding_right;
57 };
58
59 static void gtk_alignment_size_request  (GtkWidget         *widget,
60                                          GtkRequisition    *requisition);
61 static void gtk_alignment_size_allocate (GtkWidget         *widget,
62                                          GtkAllocation     *allocation);
63 static void gtk_alignment_set_property (GObject         *object,
64                                         guint            prop_id,
65                                         const GValue    *value,
66                                         GParamSpec      *pspec);
67 static void gtk_alignment_get_property (GObject         *object,
68                                         guint            prop_id,
69                                         GValue          *value,
70                                         GParamSpec      *pspec);
71
72 G_DEFINE_TYPE (GtkAlignment, gtk_alignment, GTK_TYPE_BIN)
73
74 static void
75 gtk_alignment_class_init (GtkAlignmentClass *class)
76 {
77   GObjectClass *gobject_class;
78   GtkWidgetClass *widget_class;
79
80   gobject_class = (GObjectClass*) class;
81   widget_class = (GtkWidgetClass*) class;
82   
83   gobject_class->set_property = gtk_alignment_set_property;
84   gobject_class->get_property = gtk_alignment_get_property;
85
86   widget_class->size_request = gtk_alignment_size_request;
87   widget_class->size_allocate = gtk_alignment_size_allocate;
88
89   g_object_class_install_property (gobject_class,
90                                    PROP_XALIGN,
91                                    g_param_spec_float("xalign",
92                                                       P_("Horizontal alignment"),
93                                                       P_("Horizontal position of child in available space. 0.0 is left aligned, 1.0 is right aligned"),
94                                                       0.0,
95                                                       1.0,
96                                                       0.5,
97                                                       GTK_PARAM_READWRITE));
98    
99   g_object_class_install_property (gobject_class,
100                                    PROP_YALIGN,
101                                    g_param_spec_float("yalign",
102                                                       P_("Vertical alignment"),
103                                                       P_("Vertical position of child in available space. 0.0 is top aligned, 1.0 is bottom aligned"),
104                                                       0.0,
105                                                       1.0,
106                                                       0.5,
107                                                       GTK_PARAM_READWRITE));
108   g_object_class_install_property (gobject_class,
109                                    PROP_XSCALE,
110                                    g_param_spec_float("xscale",
111                                                       P_("Horizontal scale"),
112                                                       P_("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"),
113                                                       0.0,
114                                                       1.0,
115                                                       1.0,
116                                                       GTK_PARAM_READWRITE));
117   g_object_class_install_property (gobject_class,
118                                    PROP_YSCALE,
119                                    g_param_spec_float("yscale",
120                                                       P_("Vertical scale"),
121                                                       P_("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"),
122                                                       0.0,
123                                                       1.0,
124                                                       1.0,
125                                                       GTK_PARAM_READWRITE));
126
127
128 /**
129  * GtkAlignment:top-padding:
130  *
131  * The padding to insert at the top of the widget.
132  *
133  * Since: 2.4
134  */
135   g_object_class_install_property (gobject_class,
136                                    PROP_TOP_PADDING,
137                                    g_param_spec_uint("top-padding",
138                                                       P_("Top Padding"),
139                                                       P_("The padding to insert at the top of the widget."),
140                                                       0,
141                                                       G_MAXINT,
142                                                       0,
143                                                       GTK_PARAM_READWRITE));
144
145 /**
146  * GtkAlignment:bottom-padding:
147  *
148  * The padding to insert at the bottom of the widget.
149  *
150  * Since: 2.4
151  */
152   g_object_class_install_property (gobject_class,
153                                    PROP_BOTTOM_PADDING,
154                                    g_param_spec_uint("bottom-padding",
155                                                       P_("Bottom Padding"),
156                                                       P_("The padding to insert at the bottom of the widget."),
157                                                       0,
158                                                       G_MAXINT,
159                                                       0,
160                                                       GTK_PARAM_READWRITE));
161
162 /**
163  * GtkAlignment:left-padding:
164  *
165  * The padding to insert at the left of the widget.
166  *
167  * Since: 2.4
168  */
169   g_object_class_install_property (gobject_class,
170                                    PROP_LEFT_PADDING,
171                                    g_param_spec_uint("left-padding",
172                                                       P_("Left Padding"),
173                                                       P_("The padding to insert at the left of the widget."),
174                                                       0,
175                                                       G_MAXINT,
176                                                       0,
177                                                       GTK_PARAM_READWRITE));
178
179 /**
180  * GtkAlignment:right-padding:
181  *
182  * The padding to insert at the right of the widget.
183  *
184  * Since: 2.4
185  */
186   g_object_class_install_property (gobject_class,
187                                    PROP_RIGHT_PADDING,
188                                    g_param_spec_uint("right-padding",
189                                                       P_("Right Padding"),
190                                                       P_("The padding to insert at the right of the widget."),
191                                                       0,
192                                                       G_MAXINT,
193                                                       0,
194                                                       GTK_PARAM_READWRITE));
195
196   g_type_class_add_private (gobject_class, sizeof (GtkAlignmentPrivate));  
197 }
198
199 static void
200 gtk_alignment_init (GtkAlignment *alignment)
201 {
202   GtkAlignmentPrivate *priv;
203   
204   GTK_WIDGET_SET_FLAGS (alignment, GTK_NO_WINDOW);
205   gtk_widget_set_redraw_on_allocate (GTK_WIDGET (alignment), FALSE);
206
207   alignment->xalign = 0.5;
208   alignment->yalign = 0.5;
209   alignment->xscale = 1.0;
210   alignment->yscale = 1.0;
211
212   /* Initialize padding with default values: */
213   priv = GTK_ALIGNMENT_GET_PRIVATE (alignment);
214   priv->padding_top = 0;
215   priv->padding_bottom = 0;
216   priv->padding_left = 0;
217   priv->padding_right = 0;
218 }
219
220 GtkWidget*
221 gtk_alignment_new (gfloat xalign,
222                    gfloat yalign,
223                    gfloat xscale,
224                    gfloat yscale)
225 {
226   GtkAlignment *alignment;
227
228   alignment = g_object_new (GTK_TYPE_ALIGNMENT, NULL);
229
230   alignment->xalign = CLAMP (xalign, 0.0, 1.0);
231   alignment->yalign = CLAMP (yalign, 0.0, 1.0);
232   alignment->xscale = CLAMP (xscale, 0.0, 1.0);
233   alignment->yscale = CLAMP (yscale, 0.0, 1.0);
234
235   return GTK_WIDGET (alignment);
236 }
237
238 static void
239 gtk_alignment_set_property (GObject         *object,
240                             guint            prop_id,
241                             const GValue    *value,
242                             GParamSpec      *pspec)
243 {
244   GtkAlignment *alignment;
245   GtkAlignmentPrivate *priv;
246   
247   alignment = GTK_ALIGNMENT (object);
248   priv = GTK_ALIGNMENT_GET_PRIVATE (alignment);
249   
250   switch (prop_id)
251     {
252     case PROP_XALIGN:
253       gtk_alignment_set (alignment,
254                          g_value_get_float (value),
255                          alignment->yalign,
256                          alignment->xscale,
257                          alignment->yscale);
258       break;
259     case PROP_YALIGN:
260       gtk_alignment_set (alignment,
261                          alignment->xalign,
262                          g_value_get_float (value),
263                          alignment->xscale,
264                          alignment->yscale);
265       break;
266     case PROP_XSCALE:
267       gtk_alignment_set (alignment,
268                          alignment->xalign,
269                          alignment->yalign,
270                          g_value_get_float (value),
271                          alignment->yscale);
272       break;
273     case PROP_YSCALE:
274       gtk_alignment_set (alignment,
275                          alignment->xalign,
276                          alignment->yalign,
277                          alignment->xscale,
278                          g_value_get_float (value));
279       break;
280       
281     /* Padding: */
282     case PROP_TOP_PADDING:
283       gtk_alignment_set_padding (alignment,
284                          g_value_get_uint (value),
285                          priv->padding_bottom,
286                          priv->padding_left,
287                          priv->padding_right);
288       break;
289     case PROP_BOTTOM_PADDING:
290       gtk_alignment_set_padding (alignment,
291                          priv->padding_top,
292                          g_value_get_uint (value),
293                          priv->padding_left,
294                          priv->padding_right);
295       break;
296     case PROP_LEFT_PADDING:
297       gtk_alignment_set_padding (alignment,
298                          priv->padding_top,
299                          priv->padding_bottom,
300                          g_value_get_uint (value),
301                          priv->padding_right);
302       break;
303     case PROP_RIGHT_PADDING:
304       gtk_alignment_set_padding (alignment,
305                          priv->padding_top,
306                          priv->padding_bottom,
307                          priv->padding_left,
308                          g_value_get_uint (value));
309       break;
310     
311     default:
312       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
313       break;
314     }
315 }
316
317 static void
318 gtk_alignment_get_property (GObject         *object,
319                             guint            prop_id,
320                             GValue          *value,
321                             GParamSpec      *pspec)
322 {
323   GtkAlignment *alignment;
324   GtkAlignmentPrivate *priv;
325
326   alignment = GTK_ALIGNMENT (object);
327   priv = GTK_ALIGNMENT_GET_PRIVATE (alignment);
328    
329   switch (prop_id)
330     {
331     case PROP_XALIGN:
332       g_value_set_float(value, alignment->xalign);
333       break;
334     case PROP_YALIGN:
335       g_value_set_float(value, alignment->yalign);
336       break;
337     case PROP_XSCALE:
338       g_value_set_float(value, alignment->xscale);
339       break;
340     case PROP_YSCALE:
341       g_value_set_float(value, alignment->yscale);
342       break;
343
344     /* Padding: */
345     case PROP_TOP_PADDING:
346       g_value_set_uint (value, priv->padding_top);
347       break;
348     case PROP_BOTTOM_PADDING:
349       g_value_set_uint (value, priv->padding_bottom);
350       break;
351     case PROP_LEFT_PADDING:
352       g_value_set_uint (value, priv->padding_left);
353       break;
354     case PROP_RIGHT_PADDING:
355       g_value_set_uint (value, priv->padding_right);
356       break;
357       
358     default:
359       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
360       break;
361     }
362 }
363
364 void
365 gtk_alignment_set (GtkAlignment *alignment,
366                    gfloat        xalign,
367                    gfloat        yalign,
368                    gfloat        xscale,
369                    gfloat        yscale)
370 {
371   g_return_if_fail (GTK_IS_ALIGNMENT (alignment));
372
373   xalign = CLAMP (xalign, 0.0, 1.0);
374   yalign = CLAMP (yalign, 0.0, 1.0);
375   xscale = CLAMP (xscale, 0.0, 1.0);
376   yscale = CLAMP (yscale, 0.0, 1.0);
377
378   if (   (alignment->xalign != xalign)
379       || (alignment->yalign != yalign)
380       || (alignment->xscale != xscale)
381       || (alignment->yscale != yscale))
382     {
383       g_object_freeze_notify (G_OBJECT (alignment));
384       if (alignment->xalign != xalign)
385         {
386            alignment->xalign = xalign;
387            g_object_notify (G_OBJECT (alignment), "xalign");
388         }
389       if (alignment->yalign != yalign)
390         {
391            alignment->yalign = yalign;
392            g_object_notify (G_OBJECT (alignment), "yalign");
393         }
394       if (alignment->xscale != xscale)
395         {
396            alignment->xscale = xscale;
397            g_object_notify (G_OBJECT (alignment), "xscale");
398         }
399       if (alignment->yscale != yscale)
400         {
401            alignment->yscale = yscale;
402            g_object_notify (G_OBJECT (alignment), "yscale");
403         }
404       g_object_thaw_notify (G_OBJECT (alignment));
405
406       if (GTK_BIN (alignment)->child)
407         gtk_widget_queue_resize (GTK_BIN (alignment)->child);
408       gtk_widget_queue_draw (GTK_WIDGET (alignment));
409     }
410 }
411
412
413 static void
414 gtk_alignment_size_request (GtkWidget      *widget,
415                             GtkRequisition *requisition)
416 {
417   GtkBin *bin;
418   GtkAlignmentPrivate *priv;
419
420   bin = GTK_BIN (widget);
421   priv = GTK_ALIGNMENT_GET_PRIVATE (widget);
422
423   requisition->width = GTK_CONTAINER (widget)->border_width * 2;
424   requisition->height = GTK_CONTAINER (widget)->border_width * 2;
425
426   if (bin->child && GTK_WIDGET_VISIBLE (bin->child))
427     {
428       GtkRequisition child_requisition;
429       
430       gtk_widget_size_request (bin->child, &child_requisition);
431
432       requisition->width += child_requisition.width;
433       requisition->height += child_requisition.height;
434
435       /* Request extra space for the padding: */
436       requisition->width += (priv->padding_left + priv->padding_right);
437       requisition->height += (priv->padding_top + priv->padding_bottom);
438     }
439 }
440
441 static void
442 gtk_alignment_size_allocate (GtkWidget     *widget,
443                              GtkAllocation *allocation)
444 {
445   GtkAlignment *alignment;
446   GtkBin *bin;
447   GtkAllocation child_allocation;
448   GtkRequisition child_requisition;
449   gint width, height;
450   gint border_width;
451   gint padding_horizontal, padding_vertical;
452   GtkAlignmentPrivate *priv;
453
454   padding_horizontal = 0;
455   padding_vertical = 0;
456
457   widget->allocation = *allocation;
458   alignment = GTK_ALIGNMENT (widget);
459   bin = GTK_BIN (widget);
460   
461   if (bin->child && GTK_WIDGET_VISIBLE (bin->child))
462     {
463       gtk_widget_get_child_requisition (bin->child, &child_requisition);
464
465       border_width = GTK_CONTAINER (alignment)->border_width;
466
467       priv = GTK_ALIGNMENT_GET_PRIVATE (widget);
468       padding_horizontal = priv->padding_left + priv->padding_right;
469       padding_vertical = priv->padding_top + priv->padding_bottom;
470
471       width = allocation->width - padding_horizontal - 2 * border_width;
472       height = allocation->height - padding_vertical - 2 * border_width;
473     
474       if (width > child_requisition.width)
475         child_allocation.width = (child_requisition.width *
476                                   (1.0 - alignment->xscale) +
477                                   width * alignment->xscale);
478       else
479         child_allocation.width = width;
480       
481       if (height > child_requisition.height)
482         child_allocation.height = (child_requisition.height *
483                                    (1.0 - alignment->yscale) +
484                                    height * alignment->yscale);
485       else
486         child_allocation.height = height;
487
488       if (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL)
489         child_allocation.x = (1.0 - alignment->xalign) * (width - child_allocation.width) + allocation->x + border_width + priv->padding_right;
490       else 
491         child_allocation.x = alignment->xalign * (width - child_allocation.width) + allocation->x + border_width + priv->padding_left;
492
493       child_allocation.y = alignment->yalign * (height - child_allocation.height) + allocation->y + border_width + priv->padding_top;
494
495       gtk_widget_size_allocate (bin->child, &child_allocation);
496     }
497 }
498
499 /**
500  * gtk_alignment_set_padding:
501  * @alignment: a #GtkAlignment
502  * @padding_top: the padding at the top of the widget
503  * @padding_bottom: the padding at the bottom of the widget
504  * @padding_left: the padding at the left of the widget
505  * @padding_right: the padding at the right of the widget.
506  *
507  * Sets the padding on the different sides of the widget.
508  * The padding adds blank space to the sides of the widget. For instance,
509  * this can be used to indent the child widget towards the right by adding
510  * padding on the left.
511  *
512  * Since: 2.4
513  */
514 void
515 gtk_alignment_set_padding (GtkAlignment    *alignment,
516                            guint            padding_top,
517                            guint            padding_bottom,
518                            guint            padding_left,
519                            guint            padding_right)
520 {
521   GtkAlignmentPrivate *priv;
522   
523   g_return_if_fail (GTK_IS_ALIGNMENT (alignment));
524
525   priv = GTK_ALIGNMENT_GET_PRIVATE (alignment);
526
527   g_object_freeze_notify (G_OBJECT (alignment));
528
529   if (priv->padding_top != padding_top)
530     {
531       priv->padding_top = padding_top;
532       g_object_notify (G_OBJECT (alignment), "top-padding");
533     }
534   if (priv->padding_bottom != padding_bottom)
535     {
536       priv->padding_bottom = padding_bottom;
537       g_object_notify (G_OBJECT (alignment), "bottom-padding");
538     }
539   if (priv->padding_left != padding_left)
540     {
541       priv->padding_left = padding_left;
542       g_object_notify (G_OBJECT (alignment), "left-padding");
543     }
544   if (priv->padding_right != padding_right)
545     {
546       priv->padding_right = padding_right;
547       g_object_notify (G_OBJECT (alignment), "right-padding");
548     }
549
550   g_object_thaw_notify (G_OBJECT (alignment));
551   
552   /* Make sure that the widget and children are redrawn with the new setting: */
553   if (GTK_BIN (alignment)->child)
554     gtk_widget_queue_resize (GTK_BIN (alignment)->child);
555
556   gtk_widget_queue_draw (GTK_WIDGET (alignment));
557 }
558
559 /**
560  * gtk_alignment_get_padding:
561  * @alignment: a #GtkAlignment
562  * @padding_top: location to store the padding for the top of the widget, or %NULL
563  * @padding_bottom: location to store the padding for the bottom of the widget, or %NULL
564  * @padding_left: location to store the padding for the left of the widget, or %NULL
565  * @padding_right: location to store the padding for the right of the widget, or %NULL
566  *
567  * Gets the padding on the different sides of the widget.
568  * See gtk_alignment_set_padding ().
569  *
570  * Since: 2.4
571  */
572 void
573 gtk_alignment_get_padding (GtkAlignment    *alignment,
574                            guint           *padding_top,
575                            guint           *padding_bottom,
576                            guint           *padding_left,
577                            guint           *padding_right)
578 {
579   GtkAlignmentPrivate *priv;
580  
581   g_return_if_fail (GTK_IS_ALIGNMENT (alignment));
582
583   priv = GTK_ALIGNMENT_GET_PRIVATE (alignment);
584   if(padding_top)
585     *padding_top = priv->padding_top;
586   if(padding_bottom)
587     *padding_bottom = priv->padding_bottom;
588   if(padding_left)
589     *padding_left = priv->padding_left;
590   if(padding_right)
591     *padding_right = priv->padding_right;
592 }
593
594 #define __GTK_ALIGNMENT_C__
595 #include "gtkaliasdef.c"