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 (GtkObject *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 GtkObjectClass *object_class;
94 GtkWidgetClass *widget_class;
96 object_class = (GtkObjectClass*) class;
97 widget_class = (GtkWidgetClass*) class;
99 parent_class = gtk_type_class (gtk_bin_get_type ());
101 gtk_object_add_arg_type ("GtkFrame::label", GTK_TYPE_STRING, GTK_ARG_READWRITE, ARG_LABEL);
102 gtk_object_add_arg_type ("GtkFrame::label_xalign", GTK_TYPE_FLOAT, GTK_ARG_READWRITE, ARG_LABEL_XALIGN);
103 gtk_object_add_arg_type ("GtkFrame::label_yalign", GTK_TYPE_FLOAT, GTK_ARG_READWRITE, ARG_LABEL_YALIGN);
104 gtk_object_add_arg_type ("GtkFrame::shadow", GTK_TYPE_SHADOW_TYPE, GTK_ARG_READWRITE, ARG_SHADOW);
106 object_class->set_arg = gtk_frame_set_arg;
107 object_class->get_arg = gtk_frame_get_arg;
108 object_class->finalize = gtk_frame_finalize;
110 widget_class->draw = gtk_frame_draw;
111 widget_class->expose_event = gtk_frame_expose;
112 widget_class->size_request = gtk_frame_size_request;
113 widget_class->size_allocate = gtk_frame_size_allocate;
114 widget_class->style_set = gtk_frame_style_set;
118 gtk_frame_init (GtkFrame *frame)
121 frame->shadow_type = GTK_SHADOW_ETCHED_IN;
122 frame->label_width = 0;
123 frame->label_height = 0;
124 frame->label_xalign = 0.0;
125 frame->label_yalign = 0.5;
129 gtk_frame_set_arg (GtkObject *object,
135 frame = GTK_FRAME (object);
140 gtk_frame_set_label (frame, GTK_VALUE_STRING (*arg));
142 case ARG_LABEL_XALIGN:
143 gtk_frame_set_label_align (frame, GTK_VALUE_FLOAT (*arg), frame->label_yalign);
145 case ARG_LABEL_YALIGN:
146 gtk_frame_set_label_align (frame, frame->label_xalign, GTK_VALUE_FLOAT (*arg));
149 gtk_frame_set_shadow_type (frame, GTK_VALUE_ENUM (*arg));
157 gtk_frame_get_arg (GtkObject *object,
163 frame = GTK_FRAME (object);
168 GTK_VALUE_STRING (*arg) = g_strdup (frame->label);
170 case ARG_LABEL_XALIGN:
171 GTK_VALUE_FLOAT (*arg) = frame->label_xalign;
173 case ARG_LABEL_YALIGN:
174 GTK_VALUE_FLOAT (*arg) = frame->label_yalign;
177 GTK_VALUE_ENUM (*arg) = frame->shadow_type;
180 arg->type = GTK_TYPE_INVALID;
186 gtk_frame_new (const gchar *label)
190 frame = gtk_type_new (gtk_frame_get_type ());
192 gtk_frame_set_label (frame, label);
194 return GTK_WIDGET (frame);
198 gtk_frame_style_set (GtkWidget *widget,
199 GtkStyle *previous_style)
203 frame = GTK_FRAME (widget);
207 frame->label_width = gdk_string_measure (GTK_WIDGET (frame)->style->font, frame->label) + 7;
208 frame->label_height = (GTK_WIDGET (frame)->style->font->ascent +
209 GTK_WIDGET (frame)->style->font->descent + 1);
212 if (GTK_WIDGET_CLASS (parent_class)->style_set)
213 GTK_WIDGET_CLASS (parent_class)->style_set (widget, previous_style);
217 gtk_frame_set_label (GtkFrame *frame,
220 g_return_if_fail (frame != NULL);
221 g_return_if_fail (GTK_IS_FRAME (frame));
223 if ((label && frame->label && (strcmp (frame->label, label) == 0)) ||
224 (!label && !frame->label))
228 g_free (frame->label);
233 frame->label = g_strdup (label);
234 frame->label_width = gdk_string_measure (GTK_WIDGET (frame)->style->font, frame->label) + 7;
235 frame->label_height = (GTK_WIDGET (frame)->style->font->ascent +
236 GTK_WIDGET (frame)->style->font->descent + 1);
240 frame->label_width = 0;
241 frame->label_height = 0;
244 if (GTK_WIDGET_DRAWABLE (frame))
248 /* clear the old label area
250 widget = GTK_WIDGET (frame);
251 gtk_widget_queue_clear_area (widget,
252 widget->allocation.x + GTK_CONTAINER (frame)->border_width,
253 widget->allocation.y + GTK_CONTAINER (frame)->border_width,
254 widget->allocation.width - GTK_CONTAINER (frame)->border_width,
255 widget->allocation.y + frame->label_height);
259 gtk_widget_queue_resize (GTK_WIDGET (frame));
263 gtk_frame_set_label_align (GtkFrame *frame,
267 g_return_if_fail (frame != NULL);
268 g_return_if_fail (GTK_IS_FRAME (frame));
270 xalign = CLAMP (xalign, 0.0, 1.0);
271 yalign = CLAMP (yalign, 0.0, 1.0);
273 if ((xalign != frame->label_xalign) || (yalign != frame->label_yalign))
275 frame->label_xalign = xalign;
276 frame->label_yalign = yalign;
278 if (GTK_WIDGET_DRAWABLE (frame))
282 /* clear the old label area
284 widget = GTK_WIDGET (frame);
285 gtk_widget_queue_clear_area (widget,
286 widget->allocation.x + GTK_CONTAINER (frame)->border_width,
287 widget->allocation.y + GTK_CONTAINER (frame)->border_width,
288 widget->allocation.width - GTK_CONTAINER (frame)->border_width,
289 widget->allocation.y + frame->label_height);
292 gtk_widget_queue_resize (GTK_WIDGET (frame));
297 gtk_frame_set_shadow_type (GtkFrame *frame,
300 g_return_if_fail (frame != NULL);
301 g_return_if_fail (GTK_IS_FRAME (frame));
303 if ((GtkShadowType) frame->shadow_type != type)
305 frame->shadow_type = type;
307 if (GTK_WIDGET_DRAWABLE (frame))
309 gtk_widget_queue_clear (GTK_WIDGET (frame));
311 gtk_widget_queue_resize (GTK_WIDGET (frame));
317 gtk_frame_finalize (GtkObject *object)
321 g_return_if_fail (object != NULL);
322 g_return_if_fail (GTK_IS_FRAME (object));
324 frame = GTK_FRAME (object);
327 g_free (frame->label);
329 (* GTK_OBJECT_CLASS (parent_class)->finalize) (object);
333 gtk_frame_paint (GtkWidget *widget,
338 gint label_area_width;
341 g_return_if_fail (widget != NULL);
342 g_return_if_fail (GTK_IS_FRAME (widget));
343 g_return_if_fail (area != NULL);
345 if (GTK_WIDGET_DRAWABLE (widget))
347 frame = GTK_FRAME (widget);
349 height_extra = frame->label_height - widget->style->klass->xthickness;
350 height_extra = MAX (height_extra, 0);
352 x = GTK_CONTAINER (frame)->border_width;
353 y = GTK_CONTAINER (frame)->border_width;
357 label_area_width = (widget->allocation.width -
358 GTK_CONTAINER (frame)->border_width * 2 -
359 widget->style->klass->xthickness * 2);
361 x2 = ((label_area_width - frame->label_width) * frame->label_xalign +
362 GTK_CONTAINER (frame)->border_width + widget->style->klass->xthickness);
363 y2 = (GTK_CONTAINER (frame)->border_width + widget->style->font->ascent);
365 gtk_paint_shadow_gap (widget->style, widget->window,
366 GTK_STATE_NORMAL, frame->shadow_type,
367 area, widget, "frame",
368 widget->allocation.x + x,
369 widget->allocation.y + y + height_extra / 2,
370 widget->allocation.width - x * 2,
371 widget->allocation.height - y * 2 - height_extra / 2,
373 x2 + 2 - x, frame->label_width - 4);
375 gtk_paint_string (widget->style, widget->window, GTK_WIDGET_STATE (widget),
376 area, widget, "frame",
377 widget->allocation.x + x2 + 3,
378 widget->allocation.y + y2,
382 gtk_paint_shadow (widget->style, widget->window,
383 GTK_STATE_NORMAL, frame->shadow_type,
384 area, widget, "frame",
385 widget->allocation.x + x,
386 widget->allocation.y + y + height_extra / 2,
387 widget->allocation.width - x * 2,
388 widget->allocation.height - y * 2 - height_extra / 2);
393 gtk_frame_draw (GtkWidget *widget,
397 GdkRectangle child_area;
399 g_return_if_fail (widget != NULL);
400 g_return_if_fail (GTK_IS_FRAME (widget));
401 g_return_if_fail (area != NULL);
403 if (GTK_WIDGET_DRAWABLE (widget))
405 bin = GTK_BIN (widget);
407 gtk_frame_paint (widget, area);
409 if (bin->child && gtk_widget_intersect (bin->child, area, &child_area))
410 gtk_widget_draw (bin->child, &child_area);
415 gtk_frame_expose (GtkWidget *widget,
416 GdkEventExpose *event)
419 GdkEventExpose child_event;
421 g_return_val_if_fail (widget != NULL, FALSE);
422 g_return_val_if_fail (GTK_IS_FRAME (widget), FALSE);
423 g_return_val_if_fail (event != NULL, FALSE);
425 if (GTK_WIDGET_DRAWABLE (widget))
427 bin = GTK_BIN (widget);
429 gtk_frame_paint (widget, &event->area);
431 child_event = *event;
433 GTK_WIDGET_NO_WINDOW (bin->child) &&
434 gtk_widget_intersect (bin->child, &event->area, &child_event.area))
435 gtk_widget_event (bin->child, (GdkEvent*) &child_event);
442 gtk_frame_size_request (GtkWidget *widget,
443 GtkRequisition *requisition)
449 g_return_if_fail (widget != NULL);
450 g_return_if_fail (GTK_IS_FRAME (widget));
451 g_return_if_fail (requisition != NULL);
453 frame = GTK_FRAME (widget);
454 bin = GTK_BIN (widget);
456 requisition->width = (GTK_CONTAINER (widget)->border_width +
457 GTK_WIDGET (widget)->style->klass->xthickness) * 2;
459 tmp_height = frame->label_height - GTK_WIDGET (widget)->style->klass->ythickness;
460 tmp_height = MAX (tmp_height, 0);
462 requisition->height = tmp_height + (GTK_CONTAINER (widget)->border_width +
463 GTK_WIDGET (widget)->style->klass->ythickness) * 2;
465 if (bin->child && GTK_WIDGET_VISIBLE (bin->child))
467 GtkRequisition child_requisition;
469 gtk_widget_size_request (bin->child, &child_requisition);
471 requisition->width += MAX (child_requisition.width, frame->label_width);
472 requisition->height += child_requisition.height;
476 requisition->width += frame->label_width;
481 gtk_frame_size_allocate (GtkWidget *widget,
482 GtkAllocation *allocation)
486 GtkAllocation child_allocation;
488 g_return_if_fail (widget != NULL);
489 g_return_if_fail (GTK_IS_FRAME (widget));
490 g_return_if_fail (allocation != NULL);
492 frame = GTK_FRAME (widget);
493 bin = GTK_BIN (widget);
495 if (GTK_WIDGET_MAPPED (widget) &&
496 ((widget->allocation.x != allocation->x) ||
497 (widget->allocation.y != allocation->y) ||
498 (widget->allocation.width != allocation->width) ||
499 (widget->allocation.height != allocation->height)) &&
500 (widget->allocation.width != 0) &&
501 (widget->allocation.height != 0))
502 gtk_widget_queue_clear (widget);
504 widget->allocation = *allocation;
506 if (bin->child && GTK_WIDGET_VISIBLE (bin->child))
508 child_allocation.x = (GTK_CONTAINER (frame)->border_width +
509 GTK_WIDGET (frame)->style->klass->xthickness);
510 child_allocation.width = MAX(1, (gint)allocation->width - child_allocation.x * 2);
512 child_allocation.y = (GTK_CONTAINER (frame)->border_width +
513 MAX (frame->label_height, GTK_WIDGET (frame)->style->klass->ythickness));
514 child_allocation.height = MAX (1, ((gint)allocation->height - child_allocation.y -
515 (gint)GTK_CONTAINER (frame)->border_width -
516 (gint)GTK_WIDGET (frame)->style->klass->ythickness));
518 child_allocation.x += allocation->x;
519 child_allocation.y += allocation->y;
521 gtk_widget_size_allocate (bin->child, &child_allocation);