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