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/.
32 #include "gtkaspectframe.h"
43 static void gtk_aspect_frame_class_init (GtkAspectFrameClass *klass);
44 static void gtk_aspect_frame_init (GtkAspectFrame *aspect_frame);
45 static void gtk_aspect_frame_set_property (GObject *object,
49 static void gtk_aspect_frame_get_property (GObject *object,
53 static void gtk_aspect_frame_compute_child_allocation (GtkFrame *frame,
54 GtkAllocation *child_allocation);
56 #define MAX_RATIO 10000.0
57 #define MIN_RATIO 0.0001
59 static GtkFrameClass *parent_class = NULL;
62 gtk_aspect_frame_get_type (void)
64 static GtkType aspect_frame_type = 0;
66 if (!aspect_frame_type)
68 static const GtkTypeInfo aspect_frame_info =
71 sizeof (GtkAspectFrame),
72 sizeof (GtkAspectFrameClass),
73 (GtkClassInitFunc) gtk_aspect_frame_class_init,
74 (GtkObjectInitFunc) gtk_aspect_frame_init,
75 /* reserved_1 */ NULL,
76 /* reserved_2 */ NULL,
77 (GtkClassInitFunc) NULL,
80 aspect_frame_type = gtk_type_unique (GTK_TYPE_FRAME, &aspect_frame_info);
83 return aspect_frame_type;
87 gtk_aspect_frame_class_init (GtkAspectFrameClass *class)
89 GObjectClass *gobject_class;
90 GtkObjectClass *object_class;
91 GtkFrameClass *frame_class;
93 parent_class = gtk_type_class (GTK_TYPE_FRAME);
95 gobject_class = (GObjectClass*) class;
96 object_class = (GtkObjectClass*) class;
97 frame_class = (GtkFrameClass*) class;
99 gobject_class->set_property = gtk_aspect_frame_set_property;
100 gobject_class->get_property = gtk_aspect_frame_get_property;
102 frame_class->compute_child_allocation = gtk_aspect_frame_compute_child_allocation;
104 g_object_class_install_property (gobject_class,
106 g_param_spec_float ("xalign",
107 _("Horizontal Alignment"),
108 _("X alignment of the child"),
110 G_PARAM_READABLE | G_PARAM_WRITABLE ));
111 g_object_class_install_property (gobject_class,
113 g_param_spec_float ("yalign",
114 _("Vertical Alignment"),
115 _("Y alignment of the child"),
117 G_PARAM_READABLE | G_PARAM_WRITABLE ));
118 g_object_class_install_property (gobject_class,
120 g_param_spec_float ("ratio",
122 _("Aspect ratio if obey_child is FALSE"),
123 MIN_RATIO, MAX_RATIO, 0.5,
124 G_PARAM_READABLE | G_PARAM_WRITABLE ));
125 g_object_class_install_property (gobject_class,
127 g_param_spec_boolean ("obey_child",
129 _("Force aspect ratio to match that of the frame's child"),
131 G_PARAM_READABLE | G_PARAM_WRITABLE));
135 gtk_aspect_frame_init (GtkAspectFrame *aspect_frame)
137 aspect_frame->xalign = 0.5;
138 aspect_frame->yalign = 0.5;
139 aspect_frame->ratio = 1.0;
140 aspect_frame->obey_child = TRUE;
144 gtk_aspect_frame_set_property (GObject *object,
149 GtkAspectFrame *aspect_frame = GTK_ASPECT_FRAME (object);
153 /* g_object_notify is handled by the _frame_set function */
155 gtk_aspect_frame_set (aspect_frame,
156 g_value_get_float (value),
157 aspect_frame->yalign,
159 aspect_frame->obey_child);
162 gtk_aspect_frame_set (aspect_frame,
163 aspect_frame->xalign,
164 g_value_get_float (value),
166 aspect_frame->obey_child);
169 gtk_aspect_frame_set (aspect_frame,
170 aspect_frame->xalign,
171 aspect_frame->yalign,
172 g_value_get_float (value),
173 aspect_frame->obey_child);
175 case PROP_OBEY_CHILD:
176 gtk_aspect_frame_set (aspect_frame,
177 aspect_frame->xalign,
178 aspect_frame->yalign,
180 g_value_get_boolean (value));
183 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
189 gtk_aspect_frame_get_property (GObject *object,
194 GtkAspectFrame *aspect_frame = GTK_ASPECT_FRAME (object);
199 g_value_set_float (value, aspect_frame->xalign);
202 g_value_set_float (value, aspect_frame->yalign);
205 g_value_set_float (value, aspect_frame->ratio);
207 case PROP_OBEY_CHILD:
208 g_value_set_boolean (value, aspect_frame->obey_child);
211 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
217 gtk_aspect_frame_new (const gchar *label,
223 GtkAspectFrame *aspect_frame;
225 aspect_frame = gtk_type_new (gtk_aspect_frame_get_type ());
227 aspect_frame->xalign = CLAMP (xalign, 0.0, 1.0);
228 aspect_frame->yalign = CLAMP (yalign, 0.0, 1.0);
229 aspect_frame->ratio = CLAMP (ratio, MIN_RATIO, MAX_RATIO);
230 aspect_frame->obey_child = obey_child != FALSE;
232 gtk_frame_set_label (GTK_FRAME(aspect_frame), label);
234 return GTK_WIDGET (aspect_frame);
238 gtk_aspect_frame_set (GtkAspectFrame *aspect_frame,
244 g_return_if_fail (GTK_IS_ASPECT_FRAME (aspect_frame));
246 xalign = CLAMP (xalign, 0.0, 1.0);
247 yalign = CLAMP (yalign, 0.0, 1.0);
248 ratio = CLAMP (ratio, MIN_RATIO, MAX_RATIO);
249 obey_child = obey_child != FALSE;
251 if ( (aspect_frame->xalign != xalign)
252 || (aspect_frame->yalign != yalign)
253 || (aspect_frame->ratio != ratio)
254 || (aspect_frame->obey_child != obey_child))
256 g_object_freeze_notify (G_OBJECT (aspect_frame));
258 if (aspect_frame->xalign != xalign)
260 aspect_frame->xalign = xalign;
261 g_object_notify (G_OBJECT (aspect_frame), "xalign");
263 if (aspect_frame->yalign != yalign)
265 aspect_frame->yalign = yalign;
266 g_object_notify (G_OBJECT (aspect_frame), "yalign");
268 if (aspect_frame->ratio != ratio)
270 aspect_frame->ratio = ratio;
271 g_object_notify (G_OBJECT (aspect_frame), "ratio");
273 if (aspect_frame->obey_child != obey_child)
275 aspect_frame->obey_child = obey_child;
276 g_object_notify (G_OBJECT (aspect_frame), "obey_child");
278 g_object_thaw_notify (G_OBJECT (aspect_frame));
280 gtk_widget_queue_resize (GTK_WIDGET (aspect_frame));
285 gtk_aspect_frame_compute_child_allocation (GtkFrame *frame,
286 GtkAllocation *child_allocation)
288 GtkAspectFrame *aspect_frame = GTK_ASPECT_FRAME (frame);
289 GtkBin *bin = GTK_BIN (frame);
292 if (bin->child && GTK_WIDGET_VISIBLE (bin->child))
294 GtkAllocation full_allocation;
296 if (aspect_frame->obey_child)
298 GtkRequisition child_requisition;
300 gtk_widget_get_child_requisition (bin->child, &child_requisition);
301 if (child_requisition.height != 0)
303 ratio = ((gdouble) child_requisition.width /
304 child_requisition.height);
305 if (ratio < MIN_RATIO)
308 else if (child_requisition.width != 0)
314 ratio = aspect_frame->ratio;
316 parent_class->compute_child_allocation (frame, &full_allocation);
318 if (ratio * full_allocation.height > full_allocation.width)
320 child_allocation->width = full_allocation.width;
321 child_allocation->height = full_allocation.width / ratio + 0.5;
325 child_allocation->width = ratio * full_allocation.height + 0.5;
326 child_allocation->height = full_allocation.height;
329 child_allocation->x = full_allocation.x + aspect_frame->xalign * (full_allocation.width - child_allocation->width);
330 child_allocation->y = full_allocation.y + aspect_frame->yalign * (full_allocation.height - child_allocation->height);
333 parent_class->compute_child_allocation (frame, child_allocation);