]> Pileus Git - ~andy/gtk/blob - gtk/gtkalignment.c
Define macros GTK_PARAM_READABLE, GTK_PARAM_WRITABLE, GTK_PARAM_READWRITE
[~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, "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   GtkAlignment *alignment;
445   GtkBin *bin;
446   GtkAlignmentPrivate *priv;
447
448   alignment = GTK_ALIGNMENT (widget);
449   bin = GTK_BIN (widget);
450   priv = GTK_ALIGNMENT_GET_PRIVATE (widget);
451
452   requisition->width = GTK_CONTAINER (widget)->border_width * 2;
453   requisition->height = GTK_CONTAINER (widget)->border_width * 2;
454
455   if (bin->child && GTK_WIDGET_VISIBLE (bin->child))
456     {
457       GtkRequisition child_requisition;
458       
459       gtk_widget_size_request (bin->child, &child_requisition);
460
461       requisition->width += child_requisition.width;
462       requisition->height += child_requisition.height;
463
464       /* Request extra space for the padding: */
465       requisition->width += (priv->padding_left + priv->padding_right);
466       requisition->height += (priv->padding_top + priv->padding_bottom);
467     }
468 }
469
470 static void
471 gtk_alignment_size_allocate (GtkWidget     *widget,
472                              GtkAllocation *allocation)
473 {
474   GtkAlignment *alignment;
475   GtkBin *bin;
476   GtkAllocation child_allocation;
477   GtkRequisition child_requisition;
478   gint width, height;
479   gint border_width;
480   gint padding_horizontal, padding_vertical;
481   GtkAlignmentPrivate *priv;
482   gfloat xalign;
483
484   padding_horizontal = 0;
485   padding_vertical = 0;
486
487   widget->allocation = *allocation;
488   alignment = GTK_ALIGNMENT (widget);
489   bin = GTK_BIN (widget);
490   
491   if (bin->child && GTK_WIDGET_VISIBLE (bin->child))
492     {
493       gtk_widget_get_child_requisition (bin->child, &child_requisition);
494
495       border_width = GTK_CONTAINER (alignment)->border_width;
496
497       priv = GTK_ALIGNMENT_GET_PRIVATE (widget);
498       padding_horizontal = priv->padding_left + priv->padding_right;
499       padding_vertical = priv->padding_top + priv->padding_bottom;
500
501       width = allocation->width - padding_horizontal - 2 * border_width;
502       height = allocation->height - padding_vertical - 2 * border_width;
503     
504       if (width > child_requisition.width)
505         child_allocation.width = (child_requisition.width *
506                                   (1.0 - alignment->xscale) +
507                                   width * alignment->xscale);
508       else
509         child_allocation.width = width;
510       
511       if (height > child_requisition.height)
512         child_allocation.height = (child_requisition.height *
513                                    (1.0 - alignment->yscale) +
514                                    height * alignment->yscale);
515       else
516         child_allocation.height = height;
517
518       xalign = alignment->xalign;
519       if (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL)
520         xalign = 1.0 - xalign;
521
522       child_allocation.x = xalign * (width - child_allocation.width) + allocation->x + border_width + priv->padding_left;
523       child_allocation.y = alignment->yalign * (height - child_allocation.height) + allocation->y + border_width + priv->padding_top;
524
525       gtk_widget_size_allocate (bin->child, &child_allocation);
526     }
527 }
528
529 /**
530  * gtk_alignment_set_padding:
531  * @alignment: a #GtkAlignment
532  * @padding_top: the padding at the top of the widget
533  * @padding_bottom: the padding at the bottom of the widget
534  * @padding_left: the padding at the left of the widget
535  * @padding_right: the padding at the right of the widget.
536  *
537  * Sets the padding on the different sides of the widget.
538  * The padding adds blank space to the sides of the widget. For instance,
539  * this can be used to indent the child widget towards the right by adding
540  * padding on the left.
541  *
542  * Since: 2.4
543  */
544 void
545 gtk_alignment_set_padding (GtkAlignment    *alignment,
546                            guint            padding_top,
547                            guint            padding_bottom,
548                            guint            padding_left,
549                            guint            padding_right)
550 {
551   GtkAlignmentPrivate *priv;
552   
553   g_return_if_fail (GTK_IS_ALIGNMENT (alignment));
554
555   priv = GTK_ALIGNMENT_GET_PRIVATE (alignment);
556
557   g_object_freeze_notify (G_OBJECT (alignment));
558
559   if (priv->padding_top != padding_top)
560     {
561       priv->padding_top = padding_top;
562       g_object_notify (G_OBJECT (alignment), "top_padding");
563     }
564   if (priv->padding_bottom != padding_bottom)
565     {
566       priv->padding_bottom = padding_bottom;
567       g_object_notify (G_OBJECT (alignment), "bottom_padding");
568     }
569   if (priv->padding_left != padding_left)
570     {
571       priv->padding_left = padding_left;
572       g_object_notify (G_OBJECT (alignment), "left_padding");
573     }
574   if (priv->padding_right != padding_right)
575     {
576       priv->padding_right = padding_right;
577       g_object_notify (G_OBJECT (alignment), "right_padding");
578     }
579
580   g_object_thaw_notify (G_OBJECT (alignment));
581   
582   /* Make sure that the widget and children are redrawn with the new setting: */
583   if (GTK_BIN (alignment)->child)
584     gtk_widget_queue_resize (GTK_BIN (alignment)->child);
585
586   gtk_widget_queue_draw (GTK_WIDGET (alignment));
587 }
588
589 /**
590  * gtk_alignment_get_padding:
591  * @alignment: a #GtkAlignment
592  * @padding_top: location to store the padding for the top of the widget, or %NULL
593  * @padding_bottom: location to store the padding for the bottom of the widget, or %NULL
594  * @padding_left: location to store the padding for the left of the widget, or %NULL
595  * @padding_right: location to store the padding for the right of the widget, or %NULL
596  *
597  * Gets the padding on the different sides of the widget.
598  * See gtk_alignment_set_padding ().
599  *
600  * Since: 2.4
601  */
602 void
603 gtk_alignment_get_padding (GtkAlignment    *alignment,
604                            guint           *padding_top,
605                            guint           *padding_bottom,
606                            guint           *padding_left,
607                            guint           *padding_right)
608 {
609   GtkAlignmentPrivate *priv;
610  
611   g_return_if_fail (GTK_IS_ALIGNMENT (alignment));
612
613   priv = GTK_ALIGNMENT_GET_PRIVATE (alignment);
614   if(padding_top)
615     *padding_top = priv->padding_top;
616   if(padding_bottom)
617     *padding_bottom = priv->padding_bottom;
618   if(padding_left)
619     *padding_left = priv->padding_left;
620   if(padding_right)
621     *padding_right = priv->padding_right;
622 }
623
624 #define __GTK_ALIGNMENT_C__
625 #include "gtkaliasdef.c"