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