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 Library 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 * Library General Public License for more details.
19 * You should have received a copy of the GNU Library General Public
20 * License along with this library; if not, write to the Free
21 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 #include "gtkaspectframe.h"
25 static void gtk_aspect_frame_class_init (GtkAspectFrameClass *klass);
26 static void gtk_aspect_frame_init (GtkAspectFrame *aspect_frame);
27 static void gtk_aspect_frame_draw (GtkWidget *widget,
29 static void gtk_aspect_frame_paint (GtkWidget *widget,
31 static gint gtk_aspect_frame_expose (GtkWidget *widget,
32 GdkEventExpose *event);
33 static void gtk_aspect_frame_size_allocate (GtkWidget *widget,
34 GtkAllocation *allocation);
36 #define MAX_RATIO 10000.0
37 #define MIN_RATIO 0.0001
40 gtk_aspect_frame_get_type ()
42 static guint aspect_frame_type = 0;
44 if (!aspect_frame_type)
46 GtkTypeInfo aspect_frame_info =
49 sizeof (GtkAspectFrame),
50 sizeof (GtkAspectFrameClass),
51 (GtkClassInitFunc) gtk_aspect_frame_class_init,
52 (GtkObjectInitFunc) gtk_aspect_frame_init,
56 aspect_frame_type = gtk_type_unique (gtk_frame_get_type (), &aspect_frame_info);
59 return aspect_frame_type;
63 gtk_aspect_frame_class_init (GtkAspectFrameClass *class)
65 GtkWidgetClass *widget_class;
67 widget_class = (GtkWidgetClass*) class;
69 widget_class->draw = gtk_aspect_frame_draw;
70 widget_class->expose_event = gtk_aspect_frame_expose;
71 widget_class->size_allocate = gtk_aspect_frame_size_allocate;
75 gtk_aspect_frame_init (GtkAspectFrame *aspect_frame)
77 aspect_frame->xalign = 0.5;
78 aspect_frame->yalign = 0.5;
79 aspect_frame->ratio = 1.0;
80 aspect_frame->obey_child = 1;
81 aspect_frame->center_allocation.x = -1;
82 aspect_frame->center_allocation.y = -1;
83 aspect_frame->center_allocation.width = 1;
84 aspect_frame->center_allocation.height = 1;
88 gtk_aspect_frame_new (const gchar *label,
94 GtkAspectFrame *aspect_frame;
96 aspect_frame = gtk_type_new (gtk_aspect_frame_get_type ());
98 aspect_frame->xalign = CLAMP (xalign, 0.0, 1.0);
99 aspect_frame->yalign = CLAMP (yalign, 0.0, 1.0);
100 aspect_frame->ratio = CLAMP (ratio, MIN_RATIO, MAX_RATIO);
101 aspect_frame->obey_child = obey_child;
103 gtk_frame_set_label (GTK_FRAME(aspect_frame), label);
105 return GTK_WIDGET (aspect_frame);
109 gtk_aspect_frame_set (GtkAspectFrame *aspect_frame,
115 g_return_if_fail (aspect_frame != NULL);
116 g_return_if_fail (GTK_IS_ASPECT_FRAME (aspect_frame));
118 xalign = CLAMP (xalign, 0.0, 1.0);
119 yalign = CLAMP (yalign, 0.0, 1.0);
120 ratio = CLAMP (ratio, MIN_RATIO, MAX_RATIO);
122 if ((aspect_frame->xalign != xalign) ||
123 (aspect_frame->yalign != yalign) ||
124 (aspect_frame->ratio != ratio) ||
125 (aspect_frame->obey_child != obey_child))
127 GtkWidget * this = GTK_WIDGET(aspect_frame);
129 aspect_frame->xalign = xalign;
130 aspect_frame->yalign = yalign;
131 aspect_frame->ratio = ratio;
132 aspect_frame->obey_child = obey_child;
134 if (GTK_WIDGET_MAPPED(this))
135 gdk_window_clear_area (this->window,
138 this->allocation.width,
139 this->allocation.height);
141 gtk_widget_size_allocate (this, &this->allocation);
142 gtk_widget_queue_draw (this);
147 gtk_aspect_frame_paint (GtkWidget *widget,
153 gint label_area_width;
155 GtkAllocation *allocation;
157 g_return_if_fail (widget != NULL);
158 g_return_if_fail (GTK_IS_ASPECT_FRAME (widget));
159 g_return_if_fail (area != NULL);
161 if (GTK_WIDGET_DRAWABLE (widget))
163 frame = GTK_FRAME (widget);
164 allocation = >K_ASPECT_FRAME(widget)->center_allocation;
166 state = widget->state;
167 if (!GTK_WIDGET_IS_SENSITIVE (widget))
168 state = GTK_STATE_INSENSITIVE;
170 height_extra = frame->label_height - widget->style->klass->xthickness;
171 height_extra = MAX (height_extra, 0);
173 x = GTK_CONTAINER (frame)->border_width;
174 y = GTK_CONTAINER (frame)->border_width;
176 gtk_draw_shadow (widget->style, widget->window,
177 GTK_STATE_NORMAL, frame->shadow_type,
179 allocation->y + y + height_extra / 2,
180 allocation->width - x * 2,
181 allocation->height - y * 2 - height_extra / 2);
185 label_area_width = (allocation->width +
186 GTK_CONTAINER (frame)->border_width * 2 -
187 widget->style->klass->xthickness * 2);
189 x = ((label_area_width - frame->label_width) * frame->label_xalign +
190 GTK_CONTAINER (frame)->border_width + widget->style->klass->xthickness);
191 y = (GTK_CONTAINER (frame)->border_width + widget->style->font->ascent);
193 gdk_window_clear_area (widget->window,
194 allocation->x + x + 2,
195 allocation->y + GTK_CONTAINER (frame)->border_width,
196 frame->label_width - 4, frame->label_height);
197 gtk_draw_string (widget->style, widget->window, state,
198 allocation->x + x + 3,
205 /* the only modification to the next two routines is to call
206 gtk_aspect_frame_paint instead of gtk_frame_paint */
209 gtk_aspect_frame_draw (GtkWidget *widget,
213 GdkRectangle child_area;
215 g_return_if_fail (widget != NULL);
216 g_return_if_fail (GTK_IS_ASPECT_FRAME (widget));
217 g_return_if_fail (area != NULL);
219 if (GTK_WIDGET_DRAWABLE (widget))
221 bin = GTK_BIN (widget);
223 gtk_aspect_frame_paint (widget, area);
225 if (bin->child && gtk_widget_intersect (bin->child, area, &child_area))
226 gtk_widget_draw (bin->child, &child_area);
231 gtk_aspect_frame_expose (GtkWidget *widget,
232 GdkEventExpose *event)
235 GdkEventExpose child_event;
237 g_return_val_if_fail (widget != NULL, FALSE);
238 g_return_val_if_fail (GTK_IS_ASPECT_FRAME (widget), FALSE);
239 g_return_val_if_fail (event != NULL, FALSE);
241 if (GTK_WIDGET_DRAWABLE (widget))
243 bin = GTK_BIN (widget);
245 gtk_aspect_frame_paint (widget, &event->area);
247 child_event = *event;
249 GTK_WIDGET_NO_WINDOW (bin->child) &&
250 gtk_widget_intersect (bin->child, &event->area, &child_event.area))
251 gtk_widget_event (bin->child, (GdkEvent*) &child_event);
258 gtk_aspect_frame_size_allocate (GtkWidget *widget,
259 GtkAllocation *allocation)
262 GtkAspectFrame *aspect_frame;
265 GtkAllocation child_allocation;
270 g_return_if_fail (widget != NULL);
271 g_return_if_fail (GTK_IS_ASPECT_FRAME (widget));
272 g_return_if_fail (allocation != NULL);
274 aspect_frame = GTK_ASPECT_FRAME (widget);
275 frame = GTK_FRAME (widget);
276 bin = GTK_BIN (widget);
278 if (GTK_WIDGET_MAPPED (widget) &&
279 ((widget->allocation.x != allocation->x) ||
280 (widget->allocation.y != allocation->y) ||
281 (widget->allocation.width != allocation->width) ||
282 (widget->allocation.height != allocation->height)) &&
283 (widget->allocation.width != 0) &&
284 (widget->allocation.height != 0))
285 gdk_window_clear_area (widget->window,
286 widget->allocation.x,
287 widget->allocation.y,
288 widget->allocation.width,
289 widget->allocation.height);
291 widget->allocation = *allocation;
293 if (bin->child && GTK_WIDGET_VISIBLE (bin->child))
295 if (aspect_frame->obey_child)
297 if (bin->child->requisition.height != 0)
299 ratio = (gdouble)bin->child->requisition.width /
300 bin->child->requisition.height;
301 if (ratio < MIN_RATIO) ratio = MIN_RATIO;
304 if (bin->child->requisition.height != 0)
310 ratio = aspect_frame->ratio;
312 x = (GTK_CONTAINER (frame)->border_width +
313 GTK_WIDGET (frame)->style->klass->xthickness);
314 width = allocation->width - x * 2;
316 y = (GTK_CONTAINER (frame)->border_width +
317 MAX (frame->label_height, GTK_WIDGET (frame)->style->klass->ythickness));
318 height = (allocation->height - y -
319 GTK_CONTAINER (frame)->border_width -
320 GTK_WIDGET (frame)->style->klass->ythickness);
322 if (height > width / ratio)
324 child_allocation.width = width;
325 child_allocation.height = width/ratio + 0.5;
327 else if (width > height * ratio)
329 child_allocation.width = ratio * height + 0.5;
330 child_allocation.height = height;
333 child_allocation.x = aspect_frame->xalign * (width - child_allocation.width) + allocation->x + x;
334 child_allocation.y = aspect_frame->yalign * (height - child_allocation.height) + allocation->y + y;
336 aspect_frame->center_allocation.width = child_allocation.width + 2*x;
337 aspect_frame->center_allocation.x = child_allocation.x - x;
338 aspect_frame->center_allocation.height = child_allocation.height + y +
339 GTK_CONTAINER (frame)->border_width +
340 GTK_WIDGET (frame)->style->klass->ythickness;
341 aspect_frame->center_allocation.y = child_allocation.y - y;
343 gtk_widget_size_allocate (bin->child, &child_allocation);