1 /* GTK - The GIMP Toolkit
2 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
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
7 * Copyright Owen Taylor 4/9/97
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.
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.
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.
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/.
33 * SECTION:gtkaspectframe
34 * @Short_description: A frame that constrains its child to a particular aspect ratio
35 * @Title: GtkAspectFrame
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.
47 #include "gtkaspectframe.h"
48 #include "gtkprivate.h"
60 static void gtk_aspect_frame_set_property (GObject *object,
64 static void gtk_aspect_frame_get_property (GObject *object,
68 static void gtk_aspect_frame_compute_child_allocation (GtkFrame *frame,
69 GtkAllocation *child_allocation);
71 #define MAX_RATIO 10000.0
72 #define MIN_RATIO 0.0001
74 G_DEFINE_TYPE (GtkAspectFrame, gtk_aspect_frame, GTK_TYPE_FRAME)
77 gtk_aspect_frame_class_init (GtkAspectFrameClass *class)
79 GObjectClass *gobject_class;
80 GtkFrameClass *frame_class;
82 gobject_class = (GObjectClass*) class;
83 frame_class = (GtkFrameClass*) class;
85 gobject_class->set_property = gtk_aspect_frame_set_property;
86 gobject_class->get_property = gtk_aspect_frame_get_property;
88 frame_class->compute_child_allocation = gtk_aspect_frame_compute_child_allocation;
90 g_object_class_install_property (gobject_class,
92 g_param_spec_float ("xalign",
93 P_("Horizontal Alignment"),
94 P_("X alignment of the child"),
96 GTK_PARAM_READWRITE));
97 g_object_class_install_property (gobject_class,
99 g_param_spec_float ("yalign",
100 P_("Vertical Alignment"),
101 P_("Y alignment of the child"),
103 GTK_PARAM_READWRITE));
104 g_object_class_install_property (gobject_class,
106 g_param_spec_float ("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,
113 g_param_spec_boolean ("obey-child",
115 P_("Force aspect ratio to match that of the frame's child"),
117 GTK_PARAM_READWRITE));
121 gtk_aspect_frame_init (GtkAspectFrame *aspect_frame)
123 aspect_frame->xalign = 0.5;
124 aspect_frame->yalign = 0.5;
125 aspect_frame->ratio = 1.0;
126 aspect_frame->obey_child = TRUE;
130 gtk_aspect_frame_set_property (GObject *object,
135 GtkAspectFrame *aspect_frame = GTK_ASPECT_FRAME (object);
139 /* g_object_notify is handled by the _frame_set function */
141 gtk_aspect_frame_set (aspect_frame,
142 g_value_get_float (value),
143 aspect_frame->yalign,
145 aspect_frame->obey_child);
148 gtk_aspect_frame_set (aspect_frame,
149 aspect_frame->xalign,
150 g_value_get_float (value),
152 aspect_frame->obey_child);
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);
161 case PROP_OBEY_CHILD:
162 gtk_aspect_frame_set (aspect_frame,
163 aspect_frame->xalign,
164 aspect_frame->yalign,
166 g_value_get_boolean (value));
169 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
175 gtk_aspect_frame_get_property (GObject *object,
180 GtkAspectFrame *aspect_frame = GTK_ASPECT_FRAME (object);
185 g_value_set_float (value, aspect_frame->xalign);
188 g_value_set_float (value, aspect_frame->yalign);
191 g_value_set_float (value, aspect_frame->ratio);
193 case PROP_OBEY_CHILD:
194 g_value_set_boolean (value, aspect_frame->obey_child);
197 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
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.
215 * Create a new #GtkAspectFrame.
217 * Returns: the new #GtkAspectFrame.
220 gtk_aspect_frame_new (const gchar *label,
226 GtkAspectFrame *aspect_frame;
228 aspect_frame = g_object_new (GTK_TYPE_ASPECT_FRAME, NULL);
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;
235 gtk_frame_set_label (GTK_FRAME(aspect_frame), label);
237 return GTK_WIDGET (aspect_frame);
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.
253 * Set parameters for an existing #GtkAspectFrame.
256 gtk_aspect_frame_set (GtkAspectFrame *aspect_frame,
262 g_return_if_fail (GTK_IS_ASPECT_FRAME (aspect_frame));
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;
269 if ( (aspect_frame->xalign != xalign)
270 || (aspect_frame->yalign != yalign)
271 || (aspect_frame->ratio != ratio)
272 || (aspect_frame->obey_child != obey_child))
274 g_object_freeze_notify (G_OBJECT (aspect_frame));
276 if (aspect_frame->xalign != xalign)
278 aspect_frame->xalign = xalign;
279 g_object_notify (G_OBJECT (aspect_frame), "xalign");
281 if (aspect_frame->yalign != yalign)
283 aspect_frame->yalign = yalign;
284 g_object_notify (G_OBJECT (aspect_frame), "yalign");
286 if (aspect_frame->ratio != ratio)
288 aspect_frame->ratio = ratio;
289 g_object_notify (G_OBJECT (aspect_frame), "ratio");
291 if (aspect_frame->obey_child != obey_child)
293 aspect_frame->obey_child = obey_child;
294 g_object_notify (G_OBJECT (aspect_frame), "obey-child");
296 g_object_thaw_notify (G_OBJECT (aspect_frame));
298 gtk_widget_queue_resize (GTK_WIDGET (aspect_frame));
303 gtk_aspect_frame_compute_child_allocation (GtkFrame *frame,
304 GtkAllocation *child_allocation)
306 GtkAspectFrame *aspect_frame = GTK_ASPECT_FRAME (frame);
307 GtkBin *bin = GTK_BIN (frame);
310 if (bin->child && gtk_widget_get_visible (bin->child))
312 GtkAllocation full_allocation;
314 if (aspect_frame->obey_child)
316 GtkRequisition child_requisition;
318 gtk_widget_get_child_requisition (bin->child, &child_requisition);
319 if (child_requisition.height != 0)
321 ratio = ((gdouble) child_requisition.width /
322 child_requisition.height);
323 if (ratio < MIN_RATIO)
326 else if (child_requisition.width != 0)
332 ratio = aspect_frame->ratio;
334 GTK_FRAME_CLASS (gtk_aspect_frame_parent_class)->compute_child_allocation (frame, &full_allocation);
336 if (ratio * full_allocation.height > full_allocation.width)
338 child_allocation->width = full_allocation.width;
339 child_allocation->height = full_allocation.width / ratio + 0.5;
343 child_allocation->width = ratio * full_allocation.height + 0.5;
344 child_allocation->height = full_allocation.height;
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);
351 GTK_FRAME_CLASS (gtk_aspect_frame_parent_class)->compute_child_allocation (frame, child_allocation);
354 #define __GTK_ASPECT_FRAME_C__
355 #include "gtkaliasdef.c"