]> Pileus Git - ~andy/gtk/blob - gtk/gtkaspectframe.c
Don't use old toolbar API in toolbar stress test
[~andy/gtk] / gtk / gtkaspectframe.c
1 /* GTK - The GIMP Toolkit
2  * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
3  *
4  * GtkAspectFrame: Ensure that the child window has a specified aspect ratio
5  *    or, if obey_child, has the same aspect ratio as its requested size
6  *
7  *     Copyright Owen Taylor                          4/9/97
8  *
9  * This library is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Lesser General Public
11  * License as published by the Free Software Foundation; either
12  * version 2 of the License, or (at your option) any later version.
13  *
14  * This library is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17  * Lesser General Public License for more details.
18  *
19  * You should have received a copy of the GNU Lesser General Public
20  * License along with this library; if not, write to the
21  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
22  * Boston, MA 02111-1307, USA.
23  */
24
25 /*
26  * Modified by the GTK+ Team and others 1997-2001.  See the AUTHORS
27  * file for a list of people on the GTK+ Team.  See the ChangeLog
28  * files for a list of changes.  These files are distributed with
29  * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
30  */
31
32 /**
33  * SECTION:gtkaspectframe
34  * @Short_description: A frame that constrains its child to a particular aspect ratio
35  * @Title: GtkAspectFrame
36  *
37  * The #GtkAspectFrame is useful when you want
38  * pack a widget so that it can resize but always retains
39  * the same aspect ratio. For instance, one might be
40  * drawing a small preview of a larger image. #GtkAspectFrame
41  * derives from #GtkFrame, so it can draw a label and
42  * a frame around the child. The frame will be
43  * "shrink-wrapped" to the size of the child.
44  */
45
46 #include "config.h"
47 #include "gtkaspectframe.h"
48 #include "gtkprivate.h"
49 #include "gtkintl.h"
50 #include "gtkalias.h"
51
52 enum {
53   PROP_0,
54   PROP_XALIGN,
55   PROP_YALIGN,
56   PROP_RATIO,
57   PROP_OBEY_CHILD
58 };
59
60 static void gtk_aspect_frame_set_property (GObject         *object,
61                                            guint            prop_id,
62                                            const GValue    *value,
63                                            GParamSpec      *pspec);
64 static void gtk_aspect_frame_get_property (GObject         *object,
65                                            guint            prop_id,
66                                            GValue          *value,
67                                            GParamSpec      *pspec);
68 static void gtk_aspect_frame_compute_child_allocation (GtkFrame            *frame,
69                                                        GtkAllocation       *child_allocation);
70
71 #define MAX_RATIO 10000.0
72 #define MIN_RATIO 0.0001
73
74 G_DEFINE_TYPE (GtkAspectFrame, gtk_aspect_frame, GTK_TYPE_FRAME)
75
76 static void
77 gtk_aspect_frame_class_init (GtkAspectFrameClass *class)
78 {
79   GObjectClass *gobject_class;
80   GtkFrameClass *frame_class;
81   
82   gobject_class = (GObjectClass*) class;
83   frame_class = (GtkFrameClass*) class;
84   
85   gobject_class->set_property = gtk_aspect_frame_set_property;
86   gobject_class->get_property = gtk_aspect_frame_get_property;
87
88   frame_class->compute_child_allocation = gtk_aspect_frame_compute_child_allocation;
89
90   g_object_class_install_property (gobject_class,
91                                    PROP_XALIGN,
92                                    g_param_spec_float ("xalign",
93                                                        P_("Horizontal Alignment"),
94                                                        P_("X alignment of the child"),
95                                                        0.0, 1.0, 0.5,
96                                                        GTK_PARAM_READWRITE));
97   g_object_class_install_property (gobject_class,
98                                    PROP_YALIGN,
99                                    g_param_spec_float ("yalign",
100                                                        P_("Vertical Alignment"),
101                                                        P_("Y alignment of the child"),
102                                                        0.0, 1.0, 0.5,
103                                                        GTK_PARAM_READWRITE));
104   g_object_class_install_property (gobject_class,
105                                    PROP_RATIO,
106                                    g_param_spec_float ("ratio",
107                                                        P_("Ratio"),
108                                                        P_("Aspect ratio if obey_child is FALSE"),
109                                                        MIN_RATIO, MAX_RATIO, 1.0,
110                                                        GTK_PARAM_READWRITE));
111   g_object_class_install_property (gobject_class,
112                                    PROP_OBEY_CHILD,
113                                    g_param_spec_boolean ("obey-child",
114                                                          P_("Obey child"),
115                                                          P_("Force aspect ratio to match that of the frame's child"),
116                                                          TRUE,
117                                                          GTK_PARAM_READWRITE));
118 }
119
120 static void
121 gtk_aspect_frame_init (GtkAspectFrame *aspect_frame)
122 {
123   aspect_frame->xalign = 0.5;
124   aspect_frame->yalign = 0.5;
125   aspect_frame->ratio = 1.0;
126   aspect_frame->obey_child = TRUE;
127 }
128
129 static void
130 gtk_aspect_frame_set_property (GObject         *object,
131                                guint            prop_id,
132                                const GValue    *value,
133                                GParamSpec      *pspec)
134 {
135   GtkAspectFrame *aspect_frame = GTK_ASPECT_FRAME (object);
136   
137   switch (prop_id)
138     {
139       /* g_object_notify is handled by the _frame_set function */
140     case PROP_XALIGN:
141       gtk_aspect_frame_set (aspect_frame,
142                             g_value_get_float (value),
143                             aspect_frame->yalign,
144                             aspect_frame->ratio,
145                             aspect_frame->obey_child);
146       break;
147     case PROP_YALIGN:
148       gtk_aspect_frame_set (aspect_frame,
149                             aspect_frame->xalign,
150                             g_value_get_float (value),
151                             aspect_frame->ratio,
152                             aspect_frame->obey_child);
153       break;
154     case PROP_RATIO:
155       gtk_aspect_frame_set (aspect_frame,
156                             aspect_frame->xalign,
157                             aspect_frame->yalign,
158                             g_value_get_float (value),
159                             aspect_frame->obey_child);
160       break;
161     case PROP_OBEY_CHILD:
162       gtk_aspect_frame_set (aspect_frame,
163                             aspect_frame->xalign,
164                             aspect_frame->yalign,
165                             aspect_frame->ratio,
166                             g_value_get_boolean (value));
167       break;
168     default:
169        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
170       break;
171     }
172 }
173
174 static void
175 gtk_aspect_frame_get_property (GObject         *object,
176                                guint            prop_id,
177                                GValue          *value,
178                                GParamSpec      *pspec)
179 {
180   GtkAspectFrame *aspect_frame = GTK_ASPECT_FRAME (object);
181   
182   switch (prop_id)
183     {
184     case PROP_XALIGN:
185       g_value_set_float (value, aspect_frame->xalign);
186       break;
187     case PROP_YALIGN:
188       g_value_set_float (value, aspect_frame->yalign);
189       break;
190     case PROP_RATIO:
191       g_value_set_float (value, aspect_frame->ratio);
192       break;
193     case PROP_OBEY_CHILD:
194       g_value_set_boolean (value, aspect_frame->obey_child);
195       break;
196     default:
197        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
198       break;
199     }
200 }
201
202 /**
203  * gtk_aspect_frame_new:
204  * @label: Label text.
205  * @xalign: Horizontal alignment of the child within the allocation of
206  *  the #GtkAspectFrame. This ranges from 0.0 (left aligned)
207  *  to 1.0 (right aligned)
208  * @yalign: Vertical alignment of the child within the allocation of
209  *  the #GtkAspectFrame. This ranges from 0.0 (left aligned)
210  *  to 1.0 (right aligned)
211  * @ratio: The desired aspect ratio.
212  * @obey_child: If %TRUE, @ratio is ignored, and the aspect
213  *  ratio is taken from the requistion of the child.
214  *
215  * Create a new #GtkAspectFrame.
216  *
217  * Returns: the new #GtkAspectFrame.
218  */
219 GtkWidget*
220 gtk_aspect_frame_new (const gchar *label,
221                       gfloat       xalign,
222                       gfloat       yalign,
223                       gfloat       ratio,
224                       gboolean     obey_child)
225 {
226   GtkAspectFrame *aspect_frame;
227
228   aspect_frame = g_object_new (GTK_TYPE_ASPECT_FRAME, NULL);
229
230   aspect_frame->xalign = CLAMP (xalign, 0.0, 1.0);
231   aspect_frame->yalign = CLAMP (yalign, 0.0, 1.0);
232   aspect_frame->ratio = CLAMP (ratio, MIN_RATIO, MAX_RATIO);
233   aspect_frame->obey_child = obey_child != FALSE;
234
235   gtk_frame_set_label (GTK_FRAME(aspect_frame), label);
236
237   return GTK_WIDGET (aspect_frame);
238 }
239
240 /**
241  * gtk_aspect_frame_set:
242  * @aspect_frame: a #GtkAspectFrame
243  * @xalign: Horizontal alignment of the child within the allocation of
244  *  the #GtkAspectFrame. This ranges from 0.0 (left aligned)
245  *  to 1.0 (right aligned)
246  * @yalign: Vertical alignment of the child within the allocation of
247  *  the #GtkAspectFrame. This ranges from 0.0 (left aligned)
248  *  to 1.0 (right aligned)
249  * @ratio: The desired aspect ratio.
250  * @obey_child: If %TRUE, @ratio is ignored, and the aspect
251  *  ratio is taken from the requistion of the child.
252  *
253  * Set parameters for an existing #GtkAspectFrame.
254  */
255 void
256 gtk_aspect_frame_set (GtkAspectFrame *aspect_frame,
257                       gfloat          xalign,
258                       gfloat          yalign,
259                       gfloat          ratio,
260                       gboolean        obey_child)
261 {
262   g_return_if_fail (GTK_IS_ASPECT_FRAME (aspect_frame));
263   
264   xalign = CLAMP (xalign, 0.0, 1.0);
265   yalign = CLAMP (yalign, 0.0, 1.0);
266   ratio = CLAMP (ratio, MIN_RATIO, MAX_RATIO);
267   obey_child = obey_child != FALSE;
268   
269   if (   (aspect_frame->xalign != xalign)
270       || (aspect_frame->yalign != yalign)
271       || (aspect_frame->ratio != ratio)
272       || (aspect_frame->obey_child != obey_child))
273     {
274       g_object_freeze_notify (G_OBJECT (aspect_frame));
275
276       if (aspect_frame->xalign != xalign)
277         {
278           aspect_frame->xalign = xalign;
279           g_object_notify (G_OBJECT (aspect_frame), "xalign");
280         }
281       if (aspect_frame->yalign != yalign)
282         {
283           aspect_frame->yalign = yalign;
284           g_object_notify (G_OBJECT (aspect_frame), "yalign");
285         }
286       if (aspect_frame->ratio != ratio)
287         {
288           aspect_frame->ratio = ratio;
289           g_object_notify (G_OBJECT (aspect_frame), "ratio");
290         }
291       if (aspect_frame->obey_child != obey_child)
292         {
293           aspect_frame->obey_child = obey_child;
294           g_object_notify (G_OBJECT (aspect_frame), "obey-child");
295         }
296       g_object_thaw_notify (G_OBJECT (aspect_frame));
297
298       gtk_widget_queue_resize (GTK_WIDGET (aspect_frame));
299     }
300 }
301
302 static void
303 gtk_aspect_frame_compute_child_allocation (GtkFrame      *frame,
304                                            GtkAllocation *child_allocation)
305 {
306   GtkAspectFrame *aspect_frame = GTK_ASPECT_FRAME (frame);
307   GtkBin *bin = GTK_BIN (frame);
308   gdouble ratio;
309
310   if (bin->child && gtk_widget_get_visible (bin->child))
311     {
312       GtkAllocation full_allocation;
313       
314       if (aspect_frame->obey_child)
315         {
316           GtkRequisition child_requisition;
317
318           gtk_widget_get_child_requisition (bin->child, &child_requisition);
319           if (child_requisition.height != 0)
320             {
321               ratio = ((gdouble) child_requisition.width /
322                        child_requisition.height);
323               if (ratio < MIN_RATIO)
324                 ratio = MIN_RATIO;
325             }
326           else if (child_requisition.width != 0)
327             ratio = MAX_RATIO;
328           else
329             ratio = 1.0;
330         }
331       else
332         ratio = aspect_frame->ratio;
333
334       GTK_FRAME_CLASS (gtk_aspect_frame_parent_class)->compute_child_allocation (frame, &full_allocation);
335       
336       if (ratio * full_allocation.height > full_allocation.width)
337         {
338           child_allocation->width = full_allocation.width;
339           child_allocation->height = full_allocation.width / ratio + 0.5;
340         }
341       else
342         {
343           child_allocation->width = ratio * full_allocation.height + 0.5;
344           child_allocation->height = full_allocation.height;
345         }
346       
347       child_allocation->x = full_allocation.x + aspect_frame->xalign * (full_allocation.width - child_allocation->width);
348       child_allocation->y = full_allocation.y + aspect_frame->yalign * (full_allocation.height - child_allocation->height);
349     }
350   else
351     GTK_FRAME_CLASS (gtk_aspect_frame_parent_class)->compute_child_allocation (frame, child_allocation);
352 }
353
354 #define __GTK_ASPECT_FRAME_C__
355 #include "gtkaliasdef.c"