]> Pileus Git - ~andy/gtk/blob - gtk/gtkmisc.c
52749323abc16b04b1f16291a9799f94ac810be1
[~andy/gtk] / gtk / gtkmisc.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 "gtkcontainer.h"
29 #include "gtkmisc.h"
30 #include "gtkintl.h"
31 #include "gtkprivate.h"
32
33
34 /**
35  * SECTION:gtkmisc
36  * @Short_description: Base class for widgets with alignments and padding
37  * @Title: GtkMisc
38  *
39  * The #GtkMisc widget is an abstract widget which is not useful itself, but
40  * is used to derive subclasses which have alignment and padding attributes.
41  *
42  * The horizontal and vertical padding attributes allows extra space to be
43  * added around the widget.
44  *
45  * The horizontal and vertical alignment attributes enable the widget to be
46  * positioned within its allocated area. Note that if the widget is added to
47  * a container in such a way that it expands automatically to fill its
48  * allocated area, the alignment settings will not alter the widgets position.
49  *
50  * <note>
51  * Note that the desired effect can in most cases be achieved by using the
52  * #GtkWidget:halign, #GtkWidget:valign and #GtkWidget:margin properties
53  * on the child widget, so GtkMisc should not be used in new code.
54  * </note>
55  */
56
57
58 struct _GtkMiscPrivate
59 {
60   gfloat        xalign;
61   gfloat        yalign;
62
63   guint16       xpad;
64   guint16       ypad;
65 };
66
67 enum {
68   PROP_0,
69   PROP_XALIGN,
70   PROP_YALIGN,
71   PROP_XPAD,
72   PROP_YPAD
73 };
74
75 static void gtk_misc_realize      (GtkWidget    *widget);
76 static void gtk_misc_set_property (GObject         *object,
77                                    guint            prop_id,
78                                    const GValue    *value,
79                                    GParamSpec      *pspec);
80 static void gtk_misc_get_property (GObject         *object,
81                                    guint            prop_id,
82                                    GValue          *value,
83                                    GParamSpec      *pspec);
84
85
86 G_DEFINE_ABSTRACT_TYPE (GtkMisc, gtk_misc, GTK_TYPE_WIDGET)
87
88 static void
89 gtk_misc_class_init (GtkMiscClass *class)
90 {
91   GObjectClass   *gobject_class;
92   GtkWidgetClass *widget_class;
93
94   gobject_class = G_OBJECT_CLASS (class);
95   widget_class = (GtkWidgetClass*) class;
96
97   gobject_class->set_property = gtk_misc_set_property;
98   gobject_class->get_property = gtk_misc_get_property;
99   
100   widget_class->realize = gtk_misc_realize;
101
102   g_object_class_install_property (gobject_class,
103                                    PROP_XALIGN,
104                                    g_param_spec_float ("xalign",
105                                                        P_("X align"),
106                                                        P_("The horizontal alignment, from 0 (left) to 1 (right). Reversed for RTL layouts."),
107                                                        0.0,
108                                                        1.0,
109                                                        0.5,
110                                                        GTK_PARAM_READWRITE));
111
112   g_object_class_install_property (gobject_class,
113                                    PROP_YALIGN,
114                                    g_param_spec_float ("yalign",
115                                                        P_("Y align"),
116                                                        P_("The vertical alignment, from 0 (top) to 1 (bottom)"),
117                                                        0.0,
118                                                        1.0,
119                                                        0.5,
120                                                        GTK_PARAM_READWRITE));
121
122   g_object_class_install_property (gobject_class,
123                                    PROP_XPAD,
124                                    g_param_spec_int ("xpad",
125                                                      P_("X pad"),
126                                                      P_("The amount of space to add on the left and right of the widget, in pixels"),
127                                                      0,
128                                                      G_MAXINT,
129                                                      0,
130                                                      GTK_PARAM_READWRITE));
131
132   g_object_class_install_property (gobject_class,
133                                    PROP_YPAD,
134                                    g_param_spec_int ("ypad",
135                                                      P_("Y pad"),
136                                                      P_("The amount of space to add on the top and bottom of the widget, in pixels"),
137                                                      0,
138                                                      G_MAXINT,
139                                                      0,
140                                                      GTK_PARAM_READWRITE));
141
142   g_type_class_add_private (class, sizeof (GtkMiscPrivate));
143 }
144
145 static void
146 gtk_misc_init (GtkMisc *misc)
147 {
148   GtkMiscPrivate *priv;
149
150   misc->priv = G_TYPE_INSTANCE_GET_PRIVATE (misc,
151                                             GTK_TYPE_MISC,
152                                             GtkMiscPrivate);
153   priv = misc->priv;
154
155   priv->xalign = 0.5;
156   priv->yalign = 0.5;
157   priv->xpad = 0;
158   priv->ypad = 0;
159 }
160
161 static void
162 gtk_misc_set_property (GObject      *object,
163                        guint         prop_id,
164                        const GValue *value,
165                        GParamSpec   *pspec)
166 {
167   GtkMisc *misc = GTK_MISC (object);
168   GtkMiscPrivate *priv = misc->priv;
169
170   switch (prop_id)
171     {
172     case PROP_XALIGN:
173       gtk_misc_set_alignment (misc, g_value_get_float (value), priv->yalign);
174       break;
175     case PROP_YALIGN:
176       gtk_misc_set_alignment (misc, priv->xalign, g_value_get_float (value));
177       break;
178     case PROP_XPAD:
179       gtk_misc_set_padding (misc, g_value_get_int (value), priv->ypad);
180       break;
181     case PROP_YPAD:
182       gtk_misc_set_padding (misc, priv->xpad, g_value_get_int (value));
183       break;
184     default:
185       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
186       break;
187     }
188 }
189
190 static void
191 gtk_misc_get_property (GObject      *object,
192                        guint         prop_id,
193                        GValue       *value,
194                        GParamSpec   *pspec)
195 {
196   GtkMisc *misc = GTK_MISC (object);
197   GtkMiscPrivate *priv = misc->priv;
198
199   switch (prop_id)
200     {
201     case PROP_XALIGN:
202       g_value_set_float (value, priv->xalign);
203       break;
204     case PROP_YALIGN:
205       g_value_set_float (value, priv->yalign);
206       break;
207     case PROP_XPAD:
208       g_value_set_int (value, priv->xpad);
209       break;
210     case PROP_YPAD:
211       g_value_set_int (value, priv->ypad);
212       break;
213     default:
214       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
215       break;
216     }
217 }
218
219 /**
220  * gtk_misc_set_alignment:
221  * @misc: a #GtkMisc.
222  * @xalign: the horizontal alignment, from 0 (left) to 1 (right).
223  * @yalign: the vertical alignment, from 0 (top) to 1 (bottom).
224  *
225  * Sets the alignment of the widget.
226  */
227 void
228 gtk_misc_set_alignment (GtkMisc *misc,
229                         gfloat   xalign,
230                         gfloat   yalign)
231 {
232   GtkMiscPrivate *priv;
233   GtkWidget *widget;
234
235   g_return_if_fail (GTK_IS_MISC (misc));
236
237   priv = misc->priv;
238
239   if (xalign < 0.0)
240     xalign = 0.0;
241   else if (xalign > 1.0)
242     xalign = 1.0;
243
244   if (yalign < 0.0)
245     yalign = 0.0;
246   else if (yalign > 1.0)
247     yalign = 1.0;
248
249   if ((xalign != priv->xalign) || (yalign != priv->yalign))
250     {
251       g_object_freeze_notify (G_OBJECT (misc));
252       if (xalign != priv->xalign)
253         g_object_notify (G_OBJECT (misc), "xalign");
254
255       if (yalign != priv->yalign)
256         g_object_notify (G_OBJECT (misc), "yalign");
257
258       priv->xalign = xalign;
259       priv->yalign = yalign;
260       
261       /* clear the area that was allocated before the change
262        */
263       widget = GTK_WIDGET (misc);
264       if (gtk_widget_is_drawable (widget))
265         gtk_widget_queue_draw (widget);
266
267       g_object_thaw_notify (G_OBJECT (misc));
268     }
269 }
270
271 /**
272  * gtk_misc_get_alignment:
273  * @misc: a #GtkMisc
274  * @xalign: (out) (allow-none): location to store X alignment of @misc, or %NULL
275  * @yalign: (out) (allow-none): location to store Y alignment of @misc, or %NULL
276  *
277  * Gets the X and Y alignment of the widget within its allocation. 
278  * See gtk_misc_set_alignment().
279  **/
280 void
281 gtk_misc_get_alignment (GtkMisc *misc,
282                         gfloat  *xalign,
283                         gfloat  *yalign)
284 {
285   GtkMiscPrivate *priv;
286
287   g_return_if_fail (GTK_IS_MISC (misc));
288
289   priv = misc->priv;
290
291   if (xalign)
292     *xalign = priv->xalign;
293   if (yalign)
294     *yalign = priv->yalign;
295 }
296
297 /**
298  * gtk_misc_set_padding:
299  * @misc: a #GtkMisc.
300  * @xpad: the amount of space to add on the left and right of the widget,
301  *   in pixels.
302  * @ypad: the amount of space to add on the top and bottom of the widget,
303  *   in pixels.
304  *
305  * Sets the amount of space to add around the widget.
306  */
307 void
308 gtk_misc_set_padding (GtkMisc *misc,
309                       gint     xpad,
310                       gint     ypad)
311 {
312   GtkMiscPrivate *priv;
313
314   g_return_if_fail (GTK_IS_MISC (misc));
315
316   priv = misc->priv;
317
318   if (xpad < 0)
319     xpad = 0;
320   if (ypad < 0)
321     ypad = 0;
322
323   if ((xpad != priv->xpad) || (ypad != priv->ypad))
324     {
325       g_object_freeze_notify (G_OBJECT (misc));
326       if (xpad != priv->xpad)
327         g_object_notify (G_OBJECT (misc), "xpad");
328
329       if (ypad != priv->ypad)
330         g_object_notify (G_OBJECT (misc), "ypad");
331
332       priv->xpad = xpad;
333       priv->ypad = ypad;
334
335       if (gtk_widget_is_drawable (GTK_WIDGET (misc)))
336         gtk_widget_queue_resize (GTK_WIDGET (misc));
337
338       g_object_thaw_notify (G_OBJECT (misc));
339     }
340 }
341
342 /**
343  * gtk_misc_get_padding:
344  * @misc: a #GtkMisc
345  * @xpad: (out) (allow-none): location to store padding in the X
346  *        direction, or %NULL
347  * @ypad: (out) (allow-none): location to store padding in the Y
348  *        direction, or %NULL
349  *
350  * Gets the padding in the X and Y directions of the widget. 
351  * See gtk_misc_set_padding().
352  **/
353 void
354 gtk_misc_get_padding (GtkMisc *misc,
355                       gint    *xpad,
356                       gint    *ypad)
357 {
358   GtkMiscPrivate *priv;
359
360   g_return_if_fail (GTK_IS_MISC (misc));
361
362   priv = misc->priv;
363
364   if (xpad)
365     *xpad = priv->xpad;
366   if (ypad)
367     *ypad = priv->ypad;
368 }
369
370 static void
371 gtk_misc_realize (GtkWidget *widget)
372 {
373   GtkAllocation allocation;
374   GdkWindow *window;
375   GdkWindowAttr attributes;
376   gint attributes_mask;
377
378   gtk_widget_set_realized (widget, TRUE);
379
380   if (!gtk_widget_get_has_window (widget))
381     {
382       window = gtk_widget_get_parent_window (widget);
383       gtk_widget_set_window (widget, window);
384       g_object_ref (window);
385     }
386   else
387     {
388       gtk_widget_get_allocation (widget, &allocation);
389
390       attributes.window_type = GDK_WINDOW_CHILD;
391       attributes.x = allocation.x;
392       attributes.y = allocation.y;
393       attributes.width = allocation.width;
394       attributes.height = allocation.height;
395       attributes.wclass = GDK_INPUT_OUTPUT;
396       attributes.visual = gtk_widget_get_visual (widget);
397       attributes.event_mask = gtk_widget_get_events (widget) | GDK_EXPOSURE_MASK;
398       attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL;
399
400       window = gdk_window_new (gtk_widget_get_parent_window (widget), &attributes, attributes_mask);
401       gtk_widget_set_window (widget, window);
402       gdk_window_set_user_data (window, widget);
403       gdk_window_set_background_pattern (window, NULL);
404     }
405 }
406
407 /* Semi-private function used by gtk widgets inheriting from
408  * GtkMisc that takes into account both css padding and border
409  * and the padding specified with the GtkMisc properties.
410  */
411 void
412 _gtk_misc_get_padding_and_border (GtkMisc   *misc,
413                                   GtkBorder *border)
414 {
415   GtkStyleContext *context;
416   GtkStateFlags state;
417   GtkBorder tmp;
418   gint xpad, ypad;
419
420   g_return_if_fail (GTK_IS_MISC (misc));
421
422   context = gtk_widget_get_style_context (GTK_WIDGET (misc));
423   state = gtk_widget_get_state_flags (GTK_WIDGET (misc));
424
425   gtk_style_context_get_padding (context, state, border);
426
427   gtk_misc_get_padding (misc, &xpad, &ypad);
428   border->top += ypad;
429   border->left += xpad;
430   border->bottom += ypad;
431   border->right += xpad;
432
433   gtk_style_context_get_border (context, state, &tmp);
434   border->top += tmp.top;
435   border->right += tmp.right;
436   border->bottom += tmp.bottom;
437   border->left += tmp.left;
438 }
439