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