]> Pileus Git - ~andy/gtk/blob - gtk/gtkframe.c
Remove all references to offscreen flag which was no longer used.
[~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
16  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17  * Boston, MA 02111-1307, USA.
18  */
19
20 /*
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/. 
25  */
26
27 #include <string.h>
28 #include "gtkframe.h"
29 #include "gtklabel.h"
30
31 enum {
32   ARG_0,
33   ARG_LABEL,
34   ARG_LABEL_XALIGN,
35   ARG_LABEL_YALIGN,
36   ARG_SHADOW
37 };
38
39
40 static void gtk_frame_class_init    (GtkFrameClass  *klass);
41 static void gtk_frame_init          (GtkFrame       *frame);
42 static void gtk_frame_set_arg       (GtkObject      *object,
43                                      GtkArg         *arg,
44                                      guint           arg_id);
45 static void gtk_frame_get_arg       (GtkObject      *object,
46                                      GtkArg         *arg,
47                                      guint           arg_id);
48 static void gtk_frame_paint         (GtkWidget      *widget,
49                                      GdkRectangle   *area);
50 static void gtk_frame_draw          (GtkWidget      *widget,
51                                      GdkRectangle   *area);
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_map           (GtkWidget      *widget);
59 static void gtk_frame_unmap         (GtkWidget      *widget);
60 static void gtk_frame_remove        (GtkContainer   *container,
61                                      GtkWidget      *child);
62 static void gtk_frame_forall        (GtkContainer   *container,
63                                      gboolean        include_internals,
64                                      GtkCallback     callback,
65                                      gpointer        callback_data);
66
67 static void gtk_frame_compute_child_allocation      (GtkFrame      *frame,
68                                                      GtkAllocation *child_allocation);
69 static void gtk_frame_real_compute_child_allocation (GtkFrame      *frame,
70                                                      GtkAllocation *child_allocation);
71
72 static GtkBinClass *parent_class = NULL;
73
74
75 GtkType
76 gtk_frame_get_type (void)
77 {
78   static GtkType frame_type = 0;
79
80   if (!frame_type)
81     {
82       static const GtkTypeInfo frame_info =
83       {
84         "GtkFrame",
85         sizeof (GtkFrame),
86         sizeof (GtkFrameClass),
87         (GtkClassInitFunc) gtk_frame_class_init,
88         (GtkObjectInitFunc) gtk_frame_init,
89         /* reserved_1 */ NULL,
90         /* reserved_2 */ NULL,
91         (GtkClassInitFunc) NULL,
92       };
93
94       frame_type = gtk_type_unique (gtk_bin_get_type (), &frame_info);
95     }
96
97   return frame_type;
98 }
99
100 static void
101 gtk_frame_class_init (GtkFrameClass *class)
102 {
103   GtkObjectClass *object_class;
104   GtkWidgetClass *widget_class;
105   GtkContainerClass *container_class;
106
107   object_class = GTK_OBJECT_CLASS (class);
108   widget_class = GTK_WIDGET_CLASS (class);
109   container_class = GTK_CONTAINER_CLASS (class);
110
111   parent_class = gtk_type_class (gtk_bin_get_type ());
112
113   gtk_object_add_arg_type ("GtkFrame::label", GTK_TYPE_STRING, GTK_ARG_READWRITE, ARG_LABEL);
114   gtk_object_add_arg_type ("GtkFrame::label_xalign", GTK_TYPE_FLOAT, GTK_ARG_READWRITE, ARG_LABEL_XALIGN);
115   gtk_object_add_arg_type ("GtkFrame::label_yalign", GTK_TYPE_FLOAT, GTK_ARG_READWRITE, ARG_LABEL_YALIGN);
116   gtk_object_add_arg_type ("GtkFrame::shadow", GTK_TYPE_SHADOW_TYPE, GTK_ARG_READWRITE, ARG_SHADOW);
117
118   object_class->set_arg = gtk_frame_set_arg;
119   object_class->get_arg = gtk_frame_get_arg;
120
121   widget_class->draw = gtk_frame_draw;
122   widget_class->expose_event = gtk_frame_expose;
123   widget_class->size_request = gtk_frame_size_request;
124   widget_class->size_allocate = gtk_frame_size_allocate;
125   widget_class->map = gtk_frame_map;
126   widget_class->unmap = gtk_frame_unmap;
127
128   container_class->remove = gtk_frame_remove;
129   container_class->forall = gtk_frame_forall;
130
131   class->compute_child_allocation = gtk_frame_real_compute_child_allocation;
132 }
133
134 static void
135 gtk_frame_init (GtkFrame *frame)
136 {
137   frame->label_widget = NULL;
138   frame->shadow_type = GTK_SHADOW_ETCHED_IN;
139   frame->label_xalign = 0.0;
140   frame->label_yalign = 0.5;
141 }
142
143 static void
144 gtk_frame_set_arg (GtkObject      *object,
145                    GtkArg         *arg,
146                    guint           arg_id)
147 {
148   GtkFrame *frame;
149
150   frame = GTK_FRAME (object);
151
152   switch (arg_id)
153     {
154     case ARG_LABEL:
155       gtk_frame_set_label (frame, GTK_VALUE_STRING (*arg));
156       break;
157     case ARG_LABEL_XALIGN:
158       gtk_frame_set_label_align (frame, GTK_VALUE_FLOAT (*arg), frame->label_yalign);
159       break;
160     case ARG_LABEL_YALIGN:
161       gtk_frame_set_label_align (frame, frame->label_xalign, GTK_VALUE_FLOAT (*arg));
162       break;
163     case ARG_SHADOW:
164       gtk_frame_set_shadow_type (frame, GTK_VALUE_ENUM (*arg));
165       break;
166     default:
167       break;
168     }
169 }
170
171 static void
172 gtk_frame_get_arg (GtkObject      *object,
173                    GtkArg         *arg,
174                    guint           arg_id)
175 {
176   GtkFrame *frame;
177
178   frame = GTK_FRAME (object);
179
180   switch (arg_id)
181     {
182     case ARG_LABEL:
183       GTK_VALUE_STRING (*arg) = gtk_frame_get_label (frame);
184       break;
185     case ARG_LABEL_XALIGN:
186       GTK_VALUE_FLOAT (*arg) = frame->label_xalign;
187       break;
188     case ARG_LABEL_YALIGN:
189       GTK_VALUE_FLOAT (*arg) = frame->label_yalign;
190       break;
191     case ARG_SHADOW:
192       GTK_VALUE_ENUM (*arg) = frame->shadow_type;
193       break;
194     default:
195       arg->type = GTK_TYPE_INVALID;
196       break;
197     }
198 }
199
200 GtkWidget*
201 gtk_frame_new (const gchar *label)
202 {
203   GtkFrame *frame;
204
205   frame = gtk_type_new (gtk_frame_get_type ());
206
207   gtk_frame_set_label (frame, label);
208
209   return GTK_WIDGET (frame);
210 }
211
212 static void
213 gtk_frame_remove (GtkContainer *container,
214                   GtkWidget    *child)
215 {
216   GtkFrame *frame = GTK_FRAME (container);
217
218   if (frame->label_widget == child)
219     gtk_frame_set_label_widget (frame, NULL);
220   else
221     GTK_CONTAINER_CLASS (parent_class)->remove (container, child);
222 }
223
224 static void
225 gtk_frame_forall (GtkContainer *container,
226                   gboolean      include_internals,
227                   GtkCallback   callback,
228                   gpointer      callback_data)
229 {
230   GtkBin *bin = GTK_BIN (container);
231   GtkFrame *frame = GTK_FRAME (container);
232
233   if (bin->child)
234     (* callback) (bin->child, callback_data);
235
236   if (frame->label_widget)
237     (* callback) (frame->label_widget, callback_data);
238 }
239
240 void
241 gtk_frame_set_label (GtkFrame *frame,
242                      const gchar *label)
243 {
244   g_return_if_fail (frame != NULL);
245   g_return_if_fail (GTK_IS_FRAME (frame));
246
247   if (!label)
248     {
249       gtk_frame_set_label_widget (frame, NULL);
250     }
251   else
252     {
253       GtkWidget *child = gtk_label_new (label);
254       gtk_widget_show (child);
255
256       gtk_frame_set_label_widget (frame, child);
257     }
258 }
259
260 /**
261  * gtk_frame_get_label:
262  * @frame: a #GtkFrame
263  * 
264  * If the frame's label widget is a #GtkLabel, return the
265  * text in the label widget. (The frame will have a #GtkLabel
266  * for the label widget if a non-%NULL argument was passed
267  * to gtk_frame_new().)
268  * 
269  * Return value: the text in the label, or %NULL if there
270  *               was no label widget or the lable widget was not
271  *               a #GtkLabel. This value must be freed with g_free().
272  **/
273 gchar *
274 gtk_frame_get_label (GtkFrame *frame)
275 {
276   g_return_val_if_fail (frame != NULL, NULL);
277   g_return_val_if_fail (GTK_IS_FRAME (frame), NULL);
278
279   if (frame->label_widget && GTK_IS_LABEL (frame->label_widget))
280     return gtk_label_get_text (GTK_LABEL (frame->label_widget));
281   else
282     return NULL;
283 }
284
285 /**
286  * gtk_frame_set_label_widget:
287  * @frame: a #GtkFrame
288  * @label_widget: the new label widget
289  * 
290  * Set the label widget for the frame. This is the widget that
291  * will appear embedded in the top edge of the frame as a
292  * title.
293  **/
294 void
295 gtk_frame_set_label_widget (GtkFrame  *frame,
296                             GtkWidget *label_widget)
297 {
298   gboolean need_resize = FALSE;
299   
300   g_return_if_fail (frame != NULL);
301   g_return_if_fail (GTK_IS_FRAME (frame));
302   g_return_if_fail (label_widget == NULL || GTK_IS_WIDGET (label_widget));
303   g_return_if_fail (label_widget == NULL || label_widget->parent == NULL);
304   
305   if (frame->label_widget == label_widget)
306     return;
307   
308   if (frame->label_widget)
309     {
310       need_resize = GTK_WIDGET_VISIBLE (frame->label_widget);
311       gtk_widget_unparent (frame->label_widget);
312     }
313
314   frame->label_widget = label_widget;
315     
316   if (label_widget)
317     {
318       frame->label_widget = label_widget;
319       gtk_widget_set_parent (label_widget, GTK_WIDGET (frame));
320       need_resize |= GTK_WIDGET_VISIBLE (label_widget);
321     }
322
323   if (GTK_WIDGET_VISIBLE (frame) && need_resize)
324     gtk_widget_queue_resize (GTK_WIDGET (frame));
325 }
326
327 void
328 gtk_frame_set_label_align (GtkFrame *frame,
329                            gfloat    xalign,
330                            gfloat    yalign)
331 {
332   g_return_if_fail (frame != NULL);
333   g_return_if_fail (GTK_IS_FRAME (frame));
334
335   xalign = CLAMP (xalign, 0.0, 1.0);
336   yalign = CLAMP (yalign, 0.0, 1.0);
337
338   if ((xalign != frame->label_xalign) || (yalign != frame->label_yalign))
339     {
340       frame->label_xalign = xalign;
341       frame->label_yalign = yalign;
342
343       gtk_widget_queue_resize (GTK_WIDGET (frame));
344     }
345 }
346
347 void
348 gtk_frame_set_shadow_type (GtkFrame      *frame,
349                            GtkShadowType  type)
350 {
351   g_return_if_fail (frame != NULL);
352   g_return_if_fail (GTK_IS_FRAME (frame));
353
354   if ((GtkShadowType) frame->shadow_type != type)
355     {
356       frame->shadow_type = type;
357
358       if (GTK_WIDGET_DRAWABLE (frame))
359         {
360           gtk_widget_queue_clear (GTK_WIDGET (frame));
361         }
362       gtk_widget_queue_resize (GTK_WIDGET (frame));
363     }
364 }
365
366 static void
367 gtk_frame_paint (GtkWidget    *widget,
368                  GdkRectangle *area)
369 {
370   GtkFrame *frame;
371   gint x, y, width, height;
372
373   if (GTK_WIDGET_DRAWABLE (widget))
374     {
375       frame = GTK_FRAME (widget);
376
377       x = frame->child_allocation.x - widget->style->klass->xthickness;
378       y = frame->child_allocation.y - widget->style->klass->ythickness;
379       width = frame->child_allocation.width + 2 * widget->style->klass->xthickness;
380       height =  frame->child_allocation.height + 2 * widget->style->klass->ythickness;
381
382       if (frame->label_widget)
383         {
384           GtkRequisition child_requisition;
385           gfloat xalign;
386           gint height_extra;
387           gint x2;
388
389           gtk_widget_get_child_requisition (frame->label_widget, &child_requisition);
390
391           if (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_LTR)
392             xalign = frame->label_xalign;
393           else
394             xalign = 1 - frame->label_xalign;
395
396           height_extra = MAX (0, child_requisition.height - widget->style->klass->xthickness);
397           y -= height_extra * (1 - frame->label_yalign);
398           height += height_extra * (1 - frame->label_yalign);
399           
400           x2 = 2 + (frame->child_allocation.width - child_requisition.width) * xalign;
401
402           gtk_paint_shadow_gap (widget->style, widget->window,
403                                 GTK_STATE_NORMAL, frame->shadow_type,
404                                 area, widget, "frame",
405                                 x, y, width, height,
406                                 GTK_POS_TOP, 
407                                 x2, child_requisition.width - 4);
408         }
409        else
410          gtk_paint_shadow (widget->style, widget->window,
411                            GTK_STATE_NORMAL, frame->shadow_type,
412                            area, widget, "frame",
413                            x, y, width, height);
414     }
415 }
416
417 static void
418 gtk_frame_draw (GtkWidget    *widget,
419                 GdkRectangle *area)
420 {
421   GtkBin *bin = GTK_BIN (widget);
422   GtkFrame *frame = GTK_FRAME (widget);
423   GdkRectangle child_area;
424
425   if (GTK_WIDGET_DRAWABLE (widget))
426     {
427       gtk_frame_paint (widget, area);
428
429       if (bin->child && gtk_widget_intersect (bin->child, area, &child_area))
430         gtk_widget_draw (bin->child, &child_area);
431
432       if (frame->label_widget && gtk_widget_intersect (frame->label_widget, area, &child_area))
433         gtk_widget_draw (frame->label_widget, &child_area);
434     }
435 }
436
437 static gboolean
438 gtk_frame_expose (GtkWidget      *widget,
439                   GdkEventExpose *event)
440 {
441   GtkBin *bin = GTK_BIN (widget);
442   GtkFrame *frame = GTK_FRAME (widget);
443   GdkEventExpose child_event;
444
445   if (GTK_WIDGET_DRAWABLE (widget))
446     {
447       gtk_frame_paint (widget, &event->area);
448
449       if (bin->child && GTK_WIDGET_NO_WINDOW (bin->child))
450         {
451           child_event = *event;
452           if (gtk_widget_intersect (bin->child, &event->area, &child_event.area))
453             gtk_widget_event (bin->child, (GdkEvent*) &child_event);
454         }
455       
456       if (frame->label_widget && GTK_WIDGET_NO_WINDOW (frame->label_widget))
457         {
458           child_event = *event;
459           if (gtk_widget_intersect (frame->label_widget, &event->area, &child_event.area))
460             gtk_widget_event (frame->label_widget, (GdkEvent*) &child_event);
461         }
462     }
463
464   return FALSE;
465 }
466
467 static void
468 gtk_frame_size_request (GtkWidget      *widget,
469                         GtkRequisition *requisition)
470 {
471   GtkFrame *frame = GTK_FRAME (widget);
472   GtkBin *bin = GTK_BIN (widget);
473   GtkRequisition child_requisition;
474   
475   if (frame->label_widget && GTK_WIDGET_VISIBLE (frame->label_widget))
476     {
477       gtk_widget_size_request (frame->label_widget, &child_requisition);
478
479       requisition->width = child_requisition.width;
480       requisition->height =
481         MAX (0, child_requisition.height - GTK_WIDGET (widget)->style->klass->xthickness);
482     }
483   else
484     {
485       requisition->width = 0;
486       requisition->height = 0;
487     }
488   
489   if (bin->child && GTK_WIDGET_VISIBLE (bin->child))
490     {
491       gtk_widget_size_request (bin->child, &child_requisition);
492
493       requisition->width = MAX (requisition->width, child_requisition.width);
494       requisition->height += child_requisition.height;
495     }
496
497   requisition->width += (GTK_CONTAINER (widget)->border_width +
498                          GTK_WIDGET (widget)->style->klass->xthickness) * 2;
499   requisition->height += (GTK_CONTAINER (widget)->border_width +
500                           GTK_WIDGET (widget)->style->klass->xthickness) * 2;
501 }
502
503 static void
504 gtk_frame_size_allocate (GtkWidget     *widget,
505                          GtkAllocation *allocation)
506 {
507   GtkFrame *frame = GTK_FRAME (widget);
508   GtkBin *bin = GTK_BIN (widget);
509
510   widget->allocation = *allocation;
511
512   if (bin->child && GTK_WIDGET_VISIBLE (bin->child))
513     {
514       GtkAllocation new_allocation;
515       
516       gtk_frame_compute_child_allocation (frame, &new_allocation);
517
518       /* If the child allocation changed, that means that the frame is drawn
519        * in a new place, so we must redraw the entire widget.
520        */
521       if (GTK_WIDGET_MAPPED (widget) &&
522           (new_allocation.x != frame->child_allocation.x ||
523            new_allocation.y != frame->child_allocation.y ||
524            new_allocation.width != frame->child_allocation.width ||
525            new_allocation.height != frame->child_allocation.height))
526         gtk_widget_queue_clear (widget);
527       
528       gtk_widget_size_allocate (bin->child, &new_allocation);
529       frame->child_allocation = new_allocation;
530     }
531
532   if (frame->label_widget && GTK_WIDGET_VISIBLE (frame->label_widget))
533     {
534       GtkRequisition child_requisition;
535       GtkAllocation child_allocation;
536       gfloat xalign;
537
538       gtk_widget_get_child_requisition (frame->label_widget, &child_requisition);
539
540       if (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_LTR)
541         xalign = frame->label_xalign;
542       else
543         xalign = 1 - frame->label_xalign;
544       
545       child_allocation.x = frame->child_allocation.x +
546         (frame->child_allocation.width - child_requisition.width) * xalign;
547       child_allocation.width = child_requisition.width;
548
549       child_allocation.y = frame->child_allocation.y - child_requisition.height;
550       child_allocation.height = child_requisition.height;
551
552       gtk_widget_size_allocate (frame->label_widget, &child_allocation);
553     }
554 }
555
556 static void
557 gtk_frame_map (GtkWidget *widget)
558 {
559   GtkFrame *frame = GTK_FRAME (widget);
560   
561   if (frame->label_widget &&
562       GTK_WIDGET_VISIBLE (frame->label_widget) &&
563       !GTK_WIDGET_MAPPED (frame->label_widget))
564     gtk_widget_map (frame->label_widget);
565
566   if (GTK_WIDGET_CLASS (parent_class)->map)
567     (* GTK_WIDGET_CLASS (parent_class)->map) (widget);
568 }
569
570 static void
571 gtk_frame_unmap (GtkWidget *widget)
572 {
573   GtkFrame *frame = GTK_FRAME (widget);
574
575   if (GTK_WIDGET_CLASS (parent_class)->unmap)
576     (* GTK_WIDGET_CLASS (parent_class)->unmap) (widget);
577
578   if (frame->label_widget && GTK_WIDGET_MAPPED (frame->label_widget))
579     gtk_widget_unmap (frame->label_widget);
580 }
581
582 static void
583 gtk_frame_compute_child_allocation (GtkFrame      *frame,
584                                     GtkAllocation *child_allocation)
585 {
586   g_return_if_fail (frame != NULL);
587   g_return_if_fail (GTK_IS_FRAME (frame));
588   g_return_if_fail (child_allocation != NULL);
589
590   GTK_FRAME_GET_CLASS (frame)->compute_child_allocation (frame, child_allocation);
591 }
592
593 static void
594 gtk_frame_real_compute_child_allocation (GtkFrame      *frame,
595                                          GtkAllocation *child_allocation)
596 {
597   GtkWidget *widget = GTK_WIDGET (frame);
598   GtkAllocation *allocation = &widget->allocation;
599   GtkRequisition child_requisition;
600   gint top_margin;
601
602   if (frame->label_widget)
603     {
604       gtk_widget_get_child_requisition (frame->label_widget, &child_requisition);
605       top_margin = MAX (child_requisition.height, widget->style->klass->ythickness);
606     }
607   else
608     top_margin = widget->style->klass->ythickness;
609   
610   child_allocation->x = (GTK_CONTAINER (frame)->border_width +
611                          widget->style->klass->xthickness);
612   child_allocation->width = MAX(1, (gint)allocation->width - child_allocation->x * 2);
613   
614   child_allocation->y = (GTK_CONTAINER (frame)->border_width + top_margin);
615   child_allocation->height = MAX (1, ((gint)allocation->height - child_allocation->y -
616                                       (gint)GTK_CONTAINER (frame)->border_width -
617                                       (gint)widget->style->klass->ythickness));
618   
619   child_allocation->x += allocation->x;
620   child_allocation->y += allocation->y;
621 }