1 /* GTK - The GIMP Toolkit
2 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library 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.
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 * Library General Public License for more details.
14 * You should have received a copy of the GNU Library 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.
21 * Modified by the GTK+ Team and others 1997-1999. 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/.
39 static void gtk_frame_class_init (GtkFrameClass *klass);
40 static void gtk_frame_init (GtkFrame *frame);
41 static void gtk_frame_set_arg (GtkObject *object,
44 static void gtk_frame_get_arg (GtkObject *object,
47 static void gtk_frame_finalize (GObject *object);
48 static void gtk_frame_paint (GtkWidget *widget,
50 static void gtk_frame_draw (GtkWidget *widget,
52 static gint gtk_frame_expose (GtkWidget *widget,
53 GdkEventExpose *event);
54 static void gtk_frame_size_request (GtkWidget *widget,
55 GtkRequisition *requisition);
56 static void gtk_frame_size_allocate (GtkWidget *widget,
57 GtkAllocation *allocation);
58 static void gtk_frame_style_set (GtkWidget *widget,
59 GtkStyle *previous_style);
62 static GtkBinClass *parent_class = NULL;
66 gtk_frame_get_type (void)
68 static GtkType frame_type = 0;
72 static const GtkTypeInfo frame_info =
76 sizeof (GtkFrameClass),
77 (GtkClassInitFunc) gtk_frame_class_init,
78 (GtkObjectInitFunc) gtk_frame_init,
79 /* reserved_1 */ NULL,
80 /* reserved_2 */ NULL,
81 (GtkClassInitFunc) NULL,
84 frame_type = gtk_type_unique (gtk_bin_get_type (), &frame_info);
91 gtk_frame_class_init (GtkFrameClass *class)
93 GObjectClass *gobject_class = G_OBJECT_CLASS (class);
94 GtkObjectClass *object_class;
95 GtkWidgetClass *widget_class;
97 object_class = (GtkObjectClass*) class;
98 widget_class = (GtkWidgetClass*) class;
100 parent_class = gtk_type_class (gtk_bin_get_type ());
102 gobject_class->finalize = gtk_frame_finalize;
104 gtk_object_add_arg_type ("GtkFrame::label", GTK_TYPE_STRING, GTK_ARG_READWRITE, ARG_LABEL);
105 gtk_object_add_arg_type ("GtkFrame::label_xalign", GTK_TYPE_FLOAT, GTK_ARG_READWRITE, ARG_LABEL_XALIGN);
106 gtk_object_add_arg_type ("GtkFrame::label_yalign", GTK_TYPE_FLOAT, GTK_ARG_READWRITE, ARG_LABEL_YALIGN);
107 gtk_object_add_arg_type ("GtkFrame::shadow", GTK_TYPE_SHADOW_TYPE, GTK_ARG_READWRITE, ARG_SHADOW);
109 object_class->set_arg = gtk_frame_set_arg;
110 object_class->get_arg = gtk_frame_get_arg;
112 widget_class->draw = gtk_frame_draw;
113 widget_class->expose_event = gtk_frame_expose;
114 widget_class->size_request = gtk_frame_size_request;
115 widget_class->size_allocate = gtk_frame_size_allocate;
116 widget_class->style_set = gtk_frame_style_set;
120 gtk_frame_init (GtkFrame *frame)
123 frame->shadow_type = GTK_SHADOW_ETCHED_IN;
124 frame->label_width = 0;
125 frame->label_height = 0;
126 frame->label_xalign = 0.0;
127 frame->label_yalign = 0.5;
131 gtk_frame_set_arg (GtkObject *object,
137 frame = GTK_FRAME (object);
142 gtk_frame_set_label (frame, GTK_VALUE_STRING (*arg));
144 case ARG_LABEL_XALIGN:
145 gtk_frame_set_label_align (frame, GTK_VALUE_FLOAT (*arg), frame->label_yalign);
147 case ARG_LABEL_YALIGN:
148 gtk_frame_set_label_align (frame, frame->label_xalign, GTK_VALUE_FLOAT (*arg));
151 gtk_frame_set_shadow_type (frame, GTK_VALUE_ENUM (*arg));
159 gtk_frame_get_arg (GtkObject *object,
165 frame = GTK_FRAME (object);
170 GTK_VALUE_STRING (*arg) = g_strdup (frame->label);
172 case ARG_LABEL_XALIGN:
173 GTK_VALUE_FLOAT (*arg) = frame->label_xalign;
175 case ARG_LABEL_YALIGN:
176 GTK_VALUE_FLOAT (*arg) = frame->label_yalign;
179 GTK_VALUE_ENUM (*arg) = frame->shadow_type;
182 arg->type = GTK_TYPE_INVALID;
188 gtk_frame_new (const gchar *label)
192 frame = gtk_type_new (gtk_frame_get_type ());
194 gtk_frame_set_label (frame, label);
196 return GTK_WIDGET (frame);
200 gtk_frame_style_set (GtkWidget *widget,
201 GtkStyle *previous_style)
205 frame = GTK_FRAME (widget);
209 frame->label_width = gdk_string_measure (GTK_WIDGET (frame)->style->font, frame->label) + 7;
210 frame->label_height = (GTK_WIDGET (frame)->style->font->ascent +
211 GTK_WIDGET (frame)->style->font->descent + 1);
214 if (GTK_WIDGET_CLASS (parent_class)->style_set)
215 GTK_WIDGET_CLASS (parent_class)->style_set (widget, previous_style);
219 gtk_frame_set_label (GtkFrame *frame,
222 g_return_if_fail (frame != NULL);
223 g_return_if_fail (GTK_IS_FRAME (frame));
225 if ((label && frame->label && (strcmp (frame->label, label) == 0)) ||
226 (!label && !frame->label))
230 g_free (frame->label);
235 frame->label = g_strdup (label);
236 frame->label_width = gdk_string_measure (GTK_WIDGET (frame)->style->font, frame->label) + 7;
237 frame->label_height = (GTK_WIDGET (frame)->style->font->ascent +
238 GTK_WIDGET (frame)->style->font->descent + 1);
242 frame->label_width = 0;
243 frame->label_height = 0;
246 if (GTK_WIDGET_DRAWABLE (frame))
250 /* clear the old label area
252 widget = GTK_WIDGET (frame);
253 gtk_widget_queue_clear_area (widget,
254 widget->allocation.x + GTK_CONTAINER (frame)->border_width,
255 widget->allocation.y + GTK_CONTAINER (frame)->border_width,
256 widget->allocation.width - GTK_CONTAINER (frame)->border_width,
257 widget->allocation.y + frame->label_height);
261 gtk_widget_queue_resize (GTK_WIDGET (frame));
265 gtk_frame_set_label_align (GtkFrame *frame,
269 g_return_if_fail (frame != NULL);
270 g_return_if_fail (GTK_IS_FRAME (frame));
272 xalign = CLAMP (xalign, 0.0, 1.0);
273 yalign = CLAMP (yalign, 0.0, 1.0);
275 if ((xalign != frame->label_xalign) || (yalign != frame->label_yalign))
277 frame->label_xalign = xalign;
278 frame->label_yalign = yalign;
280 if (GTK_WIDGET_DRAWABLE (frame))
284 /* clear the old label area
286 widget = GTK_WIDGET (frame);
287 gtk_widget_queue_clear_area (widget,
288 widget->allocation.x + GTK_CONTAINER (frame)->border_width,
289 widget->allocation.y + GTK_CONTAINER (frame)->border_width,
290 widget->allocation.width - GTK_CONTAINER (frame)->border_width,
291 widget->allocation.y + frame->label_height);
294 gtk_widget_queue_resize (GTK_WIDGET (frame));
299 gtk_frame_set_shadow_type (GtkFrame *frame,
302 g_return_if_fail (frame != NULL);
303 g_return_if_fail (GTK_IS_FRAME (frame));
305 if ((GtkShadowType) frame->shadow_type != type)
307 frame->shadow_type = type;
309 if (GTK_WIDGET_DRAWABLE (frame))
311 gtk_widget_queue_clear (GTK_WIDGET (frame));
313 gtk_widget_queue_resize (GTK_WIDGET (frame));
319 gtk_frame_finalize (GObject *object)
323 g_return_if_fail (GTK_IS_FRAME (object));
325 frame = GTK_FRAME (object);
328 g_free (frame->label);
330 G_OBJECT_CLASS (parent_class)->finalize (object);
334 gtk_frame_paint (GtkWidget *widget,
339 gint label_area_width;
342 g_return_if_fail (widget != NULL);
343 g_return_if_fail (GTK_IS_FRAME (widget));
344 g_return_if_fail (area != NULL);
346 if (GTK_WIDGET_DRAWABLE (widget))
348 frame = GTK_FRAME (widget);
350 height_extra = frame->label_height - widget->style->klass->xthickness;
351 height_extra = MAX (height_extra, 0);
353 x = GTK_CONTAINER (frame)->border_width;
354 y = GTK_CONTAINER (frame)->border_width;
358 label_area_width = (widget->allocation.width -
359 GTK_CONTAINER (frame)->border_width * 2 -
360 widget->style->klass->xthickness * 2);
362 x2 = ((label_area_width - frame->label_width) * frame->label_xalign +
363 GTK_CONTAINER (frame)->border_width + widget->style->klass->xthickness);
364 y2 = (GTK_CONTAINER (frame)->border_width + widget->style->font->ascent);
366 gtk_paint_shadow_gap (widget->style, widget->window,
367 GTK_STATE_NORMAL, frame->shadow_type,
368 area, widget, "frame",
369 widget->allocation.x + x,
370 widget->allocation.y + y + height_extra / 2,
371 widget->allocation.width - x * 2,
372 widget->allocation.height - y * 2 - height_extra / 2,
374 x2 + 2 - x, frame->label_width - 4);
376 gtk_paint_string (widget->style, widget->window, GTK_WIDGET_STATE (widget),
377 area, widget, "frame",
378 widget->allocation.x + x2 + 3,
379 widget->allocation.y + y2,
383 gtk_paint_shadow (widget->style, widget->window,
384 GTK_STATE_NORMAL, frame->shadow_type,
385 area, widget, "frame",
386 widget->allocation.x + x,
387 widget->allocation.y + y + height_extra / 2,
388 widget->allocation.width - x * 2,
389 widget->allocation.height - y * 2 - height_extra / 2);
394 gtk_frame_draw (GtkWidget *widget,
398 GdkRectangle child_area;
400 g_return_if_fail (widget != NULL);
401 g_return_if_fail (GTK_IS_FRAME (widget));
402 g_return_if_fail (area != NULL);
404 if (GTK_WIDGET_DRAWABLE (widget))
406 bin = GTK_BIN (widget);
408 gtk_frame_paint (widget, area);
410 if (bin->child && gtk_widget_intersect (bin->child, area, &child_area))
411 gtk_widget_draw (bin->child, &child_area);
416 gtk_frame_expose (GtkWidget *widget,
417 GdkEventExpose *event)
420 GdkEventExpose child_event;
422 g_return_val_if_fail (widget != NULL, FALSE);
423 g_return_val_if_fail (GTK_IS_FRAME (widget), FALSE);
424 g_return_val_if_fail (event != NULL, FALSE);
426 if (GTK_WIDGET_DRAWABLE (widget))
428 bin = GTK_BIN (widget);
430 gtk_frame_paint (widget, &event->area);
432 child_event = *event;
434 GTK_WIDGET_NO_WINDOW (bin->child) &&
435 gtk_widget_intersect (bin->child, &event->area, &child_event.area))
436 gtk_widget_event (bin->child, (GdkEvent*) &child_event);
443 gtk_frame_size_request (GtkWidget *widget,
444 GtkRequisition *requisition)
450 g_return_if_fail (widget != NULL);
451 g_return_if_fail (GTK_IS_FRAME (widget));
452 g_return_if_fail (requisition != NULL);
454 frame = GTK_FRAME (widget);
455 bin = GTK_BIN (widget);
457 requisition->width = (GTK_CONTAINER (widget)->border_width +
458 GTK_WIDGET (widget)->style->klass->xthickness) * 2;
460 tmp_height = frame->label_height - GTK_WIDGET (widget)->style->klass->ythickness;
461 tmp_height = MAX (tmp_height, 0);
463 requisition->height = tmp_height + (GTK_CONTAINER (widget)->border_width +
464 GTK_WIDGET (widget)->style->klass->ythickness) * 2;
466 if (bin->child && GTK_WIDGET_VISIBLE (bin->child))
468 GtkRequisition child_requisition;
470 gtk_widget_size_request (bin->child, &child_requisition);
472 requisition->width += MAX (child_requisition.width, frame->label_width);
473 requisition->height += child_requisition.height;
477 requisition->width += frame->label_width;
482 gtk_frame_size_allocate (GtkWidget *widget,
483 GtkAllocation *allocation)
487 GtkAllocation child_allocation;
489 g_return_if_fail (widget != NULL);
490 g_return_if_fail (GTK_IS_FRAME (widget));
491 g_return_if_fail (allocation != NULL);
493 frame = GTK_FRAME (widget);
494 bin = GTK_BIN (widget);
496 if (GTK_WIDGET_MAPPED (widget) &&
497 ((widget->allocation.x != allocation->x) ||
498 (widget->allocation.y != allocation->y) ||
499 (widget->allocation.width != allocation->width) ||
500 (widget->allocation.height != allocation->height)) &&
501 (widget->allocation.width != 0) &&
502 (widget->allocation.height != 0))
503 gtk_widget_queue_clear (widget);
505 widget->allocation = *allocation;
507 if (bin->child && GTK_WIDGET_VISIBLE (bin->child))
509 child_allocation.x = (GTK_CONTAINER (frame)->border_width +
510 GTK_WIDGET (frame)->style->klass->xthickness);
511 child_allocation.width = MAX(1, (gint)allocation->width - child_allocation.x * 2);
513 child_allocation.y = (GTK_CONTAINER (frame)->border_width +
514 MAX (frame->label_height, GTK_WIDGET (frame)->style->klass->ythickness));
515 child_allocation.height = MAX (1, ((gint)allocation->height - child_allocation.y -
516 (gint)GTK_CONTAINER (frame)->border_width -
517 (gint)GTK_WIDGET (frame)->style->klass->ythickness));
519 child_allocation.x += allocation->x;
520 child_allocation.y += allocation->y;
522 gtk_widget_size_allocate (bin->child, &child_allocation);