]> Pileus Git - ~andy/gtk/blob - gtk/gtkframe.c
Removed, because that's what a NULL comparison function means. And it
[~andy/gtk] / gtk / gtkframe.c
1 /* GTK - The GIMP Toolkit
2  * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
3  *
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.
8  *
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.
13  *
14  * You should have received a copy of the GNU Library General Public
15  * License along with this library; if not, write to the Free
16  * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17  */
18 #include <string.h>
19 #include "gtkframe.h"
20
21 enum {
22   ARG_0,
23   ARG_LABEL,
24   ARG_LABEL_XALIGN,
25   ARG_LABEL_YALIGN,
26   ARG_SHADOW
27 };
28
29
30 static void gtk_frame_class_init    (GtkFrameClass  *klass);
31 static void gtk_frame_init          (GtkFrame       *frame);
32 static void gtk_frame_set_arg       (GtkFrame       *frame,
33                                      GtkArg         *arg,
34                                      guint           arg_id);
35 static void gtk_frame_get_arg       (GtkFrame       *frame,
36                                      GtkArg         *arg,
37                                      guint           arg_id);
38 static void gtk_frame_finalize      (GtkObject      *object);
39 static void gtk_frame_paint         (GtkWidget      *widget,
40                                      GdkRectangle   *area);
41 static void gtk_frame_draw          (GtkWidget      *widget,
42                                      GdkRectangle   *area);
43 static gint gtk_frame_expose        (GtkWidget      *widget,
44                                      GdkEventExpose *event);
45 static void gtk_frame_size_request  (GtkWidget      *widget,
46                                      GtkRequisition *requisition);
47 static void gtk_frame_size_allocate (GtkWidget      *widget,
48                                      GtkAllocation  *allocation);
49 static void gtk_frame_style_set     (GtkWidget      *widget,
50                                      GtkStyle       *previous_style);
51
52
53 static GtkBinClass *parent_class = NULL;
54
55
56 guint
57 gtk_frame_get_type ()
58 {
59   static guint frame_type = 0;
60
61   if (!frame_type)
62     {
63       GtkTypeInfo frame_info =
64       {
65         "GtkFrame",
66         sizeof (GtkFrame),
67         sizeof (GtkFrameClass),
68         (GtkClassInitFunc) gtk_frame_class_init,
69         (GtkObjectInitFunc) gtk_frame_init,
70         (GtkArgSetFunc) gtk_frame_set_arg,
71         (GtkArgGetFunc) gtk_frame_get_arg,
72       };
73
74       frame_type = gtk_type_unique (gtk_bin_get_type (), &frame_info);
75     }
76
77   return frame_type;
78 }
79
80 static void
81 gtk_frame_class_init (GtkFrameClass *class)
82 {
83   GtkObjectClass *object_class;
84   GtkWidgetClass *widget_class;
85
86   object_class = (GtkObjectClass*) class;
87   widget_class = (GtkWidgetClass*) class;
88
89   parent_class = gtk_type_class (gtk_bin_get_type ());
90
91   gtk_object_add_arg_type ("GtkFrame::label", GTK_TYPE_STRING, GTK_ARG_READWRITE, ARG_LABEL);
92   gtk_object_add_arg_type ("GtkFrame::label_xalign", GTK_TYPE_DOUBLE, GTK_ARG_READWRITE, ARG_LABEL_XALIGN);
93   gtk_object_add_arg_type ("GtkFrame::label_yalign", GTK_TYPE_DOUBLE, GTK_ARG_READWRITE, ARG_LABEL_YALIGN);
94   gtk_object_add_arg_type ("GtkFrame::shadow", GTK_TYPE_ENUM, GTK_ARG_READWRITE, ARG_SHADOW);
95
96   object_class->finalize = gtk_frame_finalize;
97
98   widget_class->draw = gtk_frame_draw;
99   widget_class->expose_event = gtk_frame_expose;
100   widget_class->size_request = gtk_frame_size_request;
101   widget_class->size_allocate = gtk_frame_size_allocate;
102   widget_class->style_set = gtk_frame_style_set;
103 }
104
105 static void
106 gtk_frame_init (GtkFrame *frame)
107 {
108   GTK_WIDGET_SET_FLAGS (frame, GTK_BASIC);
109
110   frame->label = NULL;
111   frame->shadow_type = GTK_SHADOW_ETCHED_IN;
112   frame->label_width = 0;
113   frame->label_height = 0;
114   frame->label_xalign = 0.0;
115   frame->label_yalign = 0.5;
116 }
117
118 static void
119 gtk_frame_set_arg (GtkFrame       *frame,
120                    GtkArg         *arg,
121                    guint           arg_id)
122 {
123   switch (arg_id)
124     {
125     case ARG_LABEL:
126       gtk_frame_set_label (frame, GTK_VALUE_STRING (*arg));
127       break;
128     case ARG_LABEL_XALIGN:
129       gtk_frame_set_label_align (frame, GTK_VALUE_DOUBLE (*arg), frame->label_yalign);
130       break;
131     case ARG_LABEL_YALIGN:
132       gtk_frame_set_label_align (frame, frame->label_xalign, GTK_VALUE_DOUBLE (*arg));
133       break;
134     case ARG_SHADOW:
135       gtk_frame_set_shadow_type (frame, GTK_VALUE_ENUM (*arg));
136       break;
137     default:
138       arg->type = GTK_TYPE_INVALID;
139       break;
140     }
141 }
142
143 static void
144 gtk_frame_get_arg (GtkFrame       *frame,
145                    GtkArg         *arg,
146                    guint           arg_id)
147 {
148   switch (arg_id)
149     {
150     case ARG_LABEL:
151       GTK_VALUE_STRING (*arg) = g_strdup (frame->label);
152       break;
153     case ARG_LABEL_XALIGN:
154       GTK_VALUE_DOUBLE (*arg) = frame->label_xalign;
155       break;
156     case ARG_LABEL_YALIGN:
157       GTK_VALUE_DOUBLE (*arg) = frame->label_yalign;
158       break;
159     case ARG_SHADOW:
160       GTK_VALUE_ENUM (*arg) = frame->shadow_type;
161       break;
162     default:
163       arg->type = GTK_TYPE_INVALID;
164       break;
165     }
166 }
167
168 GtkWidget*
169 gtk_frame_new (const gchar *label)
170 {
171   GtkFrame *frame;
172
173   frame = gtk_type_new (gtk_frame_get_type ());
174
175   gtk_frame_set_label (frame, label);
176
177   return GTK_WIDGET (frame);
178 }
179
180 static void
181 gtk_frame_style_set (GtkWidget      *widget,
182                      GtkStyle       *previous_style)
183 {
184   GtkFrame *frame;
185
186   frame = GTK_FRAME (widget);
187
188   if (frame->label)
189     {
190       frame->label_width = gdk_string_measure (GTK_WIDGET (frame)->style->font, frame->label) + 7;
191       frame->label_height = (GTK_WIDGET (frame)->style->font->ascent +
192                              GTK_WIDGET (frame)->style->font->descent + 1);
193     }
194
195   if (GTK_WIDGET_CLASS (parent_class)->style_set)
196     GTK_WIDGET_CLASS (parent_class)->style_set (widget, previous_style);
197 }
198
199 void
200 gtk_frame_set_label (GtkFrame *frame,
201                      const gchar *label)
202 {
203   g_return_if_fail (frame != NULL);
204   g_return_if_fail (GTK_IS_FRAME (frame));
205
206   if ((label && frame->label && (strcmp (frame->label, label) == 0)) ||
207       (!label && !frame->label))
208     return;
209
210   if (frame->label)
211     g_free (frame->label);
212   frame->label = NULL;
213
214   if (label)
215     {
216       frame->label = g_strdup (label);
217       frame->label_width = gdk_string_measure (GTK_WIDGET (frame)->style->font, frame->label) + 7;
218       frame->label_height = (GTK_WIDGET (frame)->style->font->ascent +
219                              GTK_WIDGET (frame)->style->font->descent + 1);
220     }
221   else
222     {
223       frame->label_width = 0;
224       frame->label_height = 0;
225     }
226
227   if (GTK_WIDGET_DRAWABLE (frame))
228     {
229       GtkWidget *widget;
230
231       /* clear the old label area
232       */
233       widget = GTK_WIDGET (frame);
234       gdk_window_clear_area (widget->window,
235                              widget->allocation.x + GTK_CONTAINER (frame)->border_width,
236                              widget->allocation.y + GTK_CONTAINER (frame)->border_width,
237                              widget->allocation.width - GTK_CONTAINER (frame)->border_width,
238                              widget->allocation.y + frame->label_height);
239
240     }
241   
242   gtk_widget_queue_resize (GTK_WIDGET (frame));
243 }
244
245 void
246 gtk_frame_set_label_align (GtkFrame *frame,
247                            gfloat    xalign,
248                            gfloat    yalign)
249 {
250   g_return_if_fail (frame != NULL);
251   g_return_if_fail (GTK_IS_FRAME (frame));
252
253   xalign = CLAMP (xalign, 0.0, 1.0);
254   yalign = CLAMP (yalign, 0.0, 1.0);
255
256   if ((xalign != frame->label_xalign) || (yalign != frame->label_yalign))
257     {
258       frame->label_xalign = xalign;
259       frame->label_yalign = yalign;
260
261       if (GTK_WIDGET_DRAWABLE (frame))
262         {
263           GtkWidget *widget;
264
265           /* clear the old label area
266           */
267           widget = GTK_WIDGET (frame);
268           gdk_window_clear_area (widget->window,
269                                  widget->allocation.x + GTK_CONTAINER (frame)->border_width,
270                                  widget->allocation.y + GTK_CONTAINER (frame)->border_width,
271                                  widget->allocation.width - GTK_CONTAINER (frame)->border_width,
272                                  widget->allocation.y + frame->label_height);
273
274         }
275       gtk_widget_queue_resize (GTK_WIDGET (frame));
276     }
277 }
278
279 void
280 gtk_frame_set_shadow_type (GtkFrame      *frame,
281                            GtkShadowType  type)
282 {
283   g_return_if_fail (frame != NULL);
284   g_return_if_fail (GTK_IS_FRAME (frame));
285
286   if ((GtkShadowType) frame->shadow_type != type)
287     {
288       frame->shadow_type = type;
289
290       if (GTK_WIDGET_DRAWABLE (frame))
291         {
292           gdk_window_clear_area (GTK_WIDGET (frame)->window,
293                                  GTK_WIDGET (frame)->allocation.x,
294                                  GTK_WIDGET (frame)->allocation.y,
295                                  GTK_WIDGET (frame)->allocation.width,
296                                  GTK_WIDGET (frame)->allocation.height);
297         }
298       gtk_widget_queue_resize (GTK_WIDGET (frame));
299     }
300 }
301
302
303 static void
304 gtk_frame_finalize (GtkObject *object)
305 {
306   GtkFrame *frame;
307
308   g_return_if_fail (object != NULL);
309   g_return_if_fail (GTK_IS_FRAME (object));
310
311   frame = GTK_FRAME (object);
312
313   if (frame->label)
314     g_free (frame->label);
315
316   (* GTK_OBJECT_CLASS (parent_class)->finalize) (object);
317 }
318
319 static void
320 gtk_frame_paint (GtkWidget    *widget,
321                  GdkRectangle *area)
322 {
323   GtkFrame *frame;
324   gint height_extra;
325   gint label_area_width;
326   gint x, y;
327
328   g_return_if_fail (widget != NULL);
329   g_return_if_fail (GTK_IS_FRAME (widget));
330   g_return_if_fail (area != NULL);
331
332   if (GTK_WIDGET_DRAWABLE (widget))
333     {
334       frame = GTK_FRAME (widget);
335
336       height_extra = frame->label_height - widget->style->klass->xthickness;
337       height_extra = MAX (height_extra, 0);
338
339       x = GTK_CONTAINER (frame)->border_width;
340       y = GTK_CONTAINER (frame)->border_width;
341
342       gtk_draw_shadow (widget->style, widget->window,
343                        GTK_STATE_NORMAL, frame->shadow_type,
344                        widget->allocation.x + x,
345                        widget->allocation.y + y + height_extra / 2,
346                        widget->allocation.width - x * 2,
347                        widget->allocation.height - y * 2 - height_extra / 2);
348
349       if (frame->label)
350         {
351           label_area_width = (widget->allocation.width -
352                               GTK_CONTAINER (frame)->border_width * 2 -
353                               widget->style->klass->xthickness * 2);
354
355           x = ((label_area_width - frame->label_width) * frame->label_xalign +
356                GTK_CONTAINER (frame)->border_width + widget->style->klass->xthickness);
357           y = (GTK_CONTAINER (frame)->border_width + widget->style->font->ascent);
358
359           gdk_window_clear_area (widget->window,
360                                  widget->allocation.x + x + 2,
361                                  widget->allocation.y + GTK_CONTAINER (frame)->border_width,
362                                  frame->label_width - 4,
363                                  frame->label_height);
364           gtk_draw_string (widget->style, widget->window, GTK_WIDGET_STATE (widget),
365                            widget->allocation.x + x + 3,
366                            widget->allocation.y + y,
367                            frame->label);
368         }
369     }
370 }
371
372 static void
373 gtk_frame_draw (GtkWidget    *widget,
374                 GdkRectangle *area)
375 {
376   GtkBin *bin;
377   GdkRectangle child_area;
378
379   g_return_if_fail (widget != NULL);
380   g_return_if_fail (GTK_IS_FRAME (widget));
381   g_return_if_fail (area != NULL);
382
383   if (GTK_WIDGET_DRAWABLE (widget))
384     {
385       bin = GTK_BIN (widget);
386
387       gtk_frame_paint (widget, area);
388
389       if (bin->child && gtk_widget_intersect (bin->child, area, &child_area))
390         gtk_widget_draw (bin->child, &child_area);
391     }
392 }
393
394 static gint
395 gtk_frame_expose (GtkWidget      *widget,
396                   GdkEventExpose *event)
397 {
398   GtkBin *bin;
399   GdkEventExpose child_event;
400
401   g_return_val_if_fail (widget != NULL, FALSE);
402   g_return_val_if_fail (GTK_IS_FRAME (widget), FALSE);
403   g_return_val_if_fail (event != NULL, FALSE);
404
405   if (GTK_WIDGET_DRAWABLE (widget))
406     {
407       bin = GTK_BIN (widget);
408
409       gtk_frame_paint (widget, &event->area);
410
411       child_event = *event;
412       if (bin->child &&
413           GTK_WIDGET_NO_WINDOW (bin->child) &&
414           gtk_widget_intersect (bin->child, &event->area, &child_event.area))
415         gtk_widget_event (bin->child, (GdkEvent*) &child_event);
416     }
417
418   return FALSE;
419 }
420
421 static void
422 gtk_frame_size_request (GtkWidget      *widget,
423                         GtkRequisition *requisition)
424 {
425   GtkFrame *frame;
426   GtkBin *bin;
427   gint tmp_height;
428
429   g_return_if_fail (widget != NULL);
430   g_return_if_fail (GTK_IS_FRAME (widget));
431   g_return_if_fail (requisition != NULL);
432
433   frame = GTK_FRAME (widget);
434   bin = GTK_BIN (widget);
435
436   requisition->width = (GTK_CONTAINER (widget)->border_width +
437                         GTK_WIDGET (widget)->style->klass->xthickness) * 2;
438
439   tmp_height = frame->label_height - GTK_WIDGET (widget)->style->klass->ythickness;
440   tmp_height = MAX (tmp_height, 0);
441
442   requisition->height = tmp_height + (GTK_CONTAINER (widget)->border_width +
443                                       GTK_WIDGET (widget)->style->klass->ythickness) * 2;
444
445   if (bin->child && GTK_WIDGET_VISIBLE (bin->child))
446     {
447       gtk_widget_size_request (bin->child, &bin->child->requisition);
448
449       requisition->width += MAX (bin->child->requisition.width, frame->label_width);
450       requisition->height += bin->child->requisition.height;
451     }
452   else
453     {
454       requisition->width += frame->label_width;
455     }
456 }
457
458 static void
459 gtk_frame_size_allocate (GtkWidget     *widget,
460                          GtkAllocation *allocation)
461 {
462   GtkFrame *frame;
463   GtkBin *bin;
464   GtkAllocation child_allocation;
465
466   g_return_if_fail (widget != NULL);
467   g_return_if_fail (GTK_IS_FRAME (widget));
468   g_return_if_fail (allocation != NULL);
469
470   frame = GTK_FRAME (widget);
471   bin = GTK_BIN (widget);
472
473   if (GTK_WIDGET_MAPPED (widget) &&
474       ((widget->allocation.x != allocation->x) ||
475        (widget->allocation.y != allocation->y) ||
476        (widget->allocation.width != allocation->width) ||
477        (widget->allocation.height != allocation->height)) &&
478       (widget->allocation.width != 0) &&
479       (widget->allocation.height != 0))
480     gdk_window_clear_area (widget->window,
481                            widget->allocation.x,
482                            widget->allocation.y,
483                            widget->allocation.width,
484                            widget->allocation.height);
485
486   widget->allocation = *allocation;
487
488   if (bin->child && GTK_WIDGET_VISIBLE (bin->child))
489     {
490       child_allocation.x = (GTK_CONTAINER (frame)->border_width +
491                             GTK_WIDGET (frame)->style->klass->xthickness);
492       child_allocation.width = MAX(0, allocation->width - child_allocation.x * 2);
493
494       child_allocation.y = (GTK_CONTAINER (frame)->border_width +
495                             MAX (frame->label_height, GTK_WIDGET (frame)->style->klass->ythickness));
496       child_allocation.height = MAX (1, (allocation->height - child_allocation.y -
497                                          GTK_CONTAINER (frame)->border_width -
498                                          GTK_WIDGET (frame)->style->klass->ythickness));
499
500       child_allocation.x += allocation->x;
501       child_allocation.y += allocation->y;
502
503       gtk_widget_size_allocate (bin->child, &child_allocation);
504     }
505 }