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