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