source: trunk/third/gtk/gtk/gtkbox.c @ 14482

Revision 14482, 18.0 KB checked in by ghudson, 24 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r14481, which included commits to RCS files with non-trunk default branches.
Line 
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 "gtkbox.h"
28
29enum {
30  ARG_0,
31  ARG_SPACING,
32  ARG_HOMOGENEOUS
33};
34
35enum {
36  CHILD_ARG_0,
37  CHILD_ARG_EXPAND,
38  CHILD_ARG_FILL,
39  CHILD_ARG_PADDING,
40  CHILD_ARG_PACK_TYPE,
41  CHILD_ARG_POSITION
42};
43
44static void gtk_box_class_init (GtkBoxClass    *klass);
45static void gtk_box_init       (GtkBox         *box);
46static void gtk_box_get_arg    (GtkObject      *object,
47                                GtkArg         *arg,
48                                guint           arg_id);
49static void gtk_box_set_arg    (GtkObject      *object,
50                                GtkArg         *arg,
51                                guint           arg_id);
52static void gtk_box_map        (GtkWidget      *widget);
53static void gtk_box_unmap      (GtkWidget      *widget);
54static void gtk_box_draw       (GtkWidget      *widget,
55                                GdkRectangle   *area);
56static gint gtk_box_expose     (GtkWidget      *widget,
57                                GdkEventExpose *event);
58static void gtk_box_add        (GtkContainer   *container,
59                                GtkWidget      *widget);
60static void gtk_box_remove     (GtkContainer   *container,
61                                GtkWidget      *widget);
62static void gtk_box_forall     (GtkContainer   *container,
63                                gboolean        include_internals,
64                                GtkCallback     callback,
65                                gpointer        callback_data);
66static void gtk_box_set_child_arg (GtkContainer   *container,
67                                   GtkWidget      *child,
68                                   GtkArg         *arg,
69                                   guint           arg_id);
70static void gtk_box_get_child_arg (GtkContainer   *container,
71                                   GtkWidget      *child,
72                                   GtkArg         *arg,
73                                   guint           arg_id);
74static GtkType gtk_box_child_type (GtkContainer   *container);
75     
76
77static GtkContainerClass *parent_class = NULL;
78
79
80GtkType
81gtk_box_get_type (void)
82{
83  static GtkType box_type = 0;
84
85  if (!box_type)
86    {
87      static const GtkTypeInfo box_info =
88      {
89        "GtkBox",
90        sizeof (GtkBox),
91        sizeof (GtkBoxClass),
92        (GtkClassInitFunc) gtk_box_class_init,
93        (GtkObjectInitFunc) gtk_box_init,
94        /* reserved_1 */ NULL,
95        /* reserved_2 */ NULL,
96        (GtkClassInitFunc) NULL,
97      };
98
99      box_type = gtk_type_unique (GTK_TYPE_CONTAINER, &box_info);
100    }
101
102  return box_type;
103}
104
105static void
106gtk_box_class_init (GtkBoxClass *class)
107{
108  GtkObjectClass *object_class;
109  GtkWidgetClass *widget_class;
110  GtkContainerClass *container_class;
111
112  object_class = (GtkObjectClass*) class;
113  widget_class = (GtkWidgetClass*) class;
114  container_class = (GtkContainerClass*) class;
115
116  parent_class = gtk_type_class (GTK_TYPE_CONTAINER);
117
118  gtk_object_add_arg_type ("GtkBox::spacing", GTK_TYPE_INT, GTK_ARG_READWRITE, ARG_SPACING);
119  gtk_object_add_arg_type ("GtkBox::homogeneous", GTK_TYPE_BOOL, GTK_ARG_READWRITE, ARG_HOMOGENEOUS);
120  gtk_container_add_child_arg_type ("GtkBox::expand", GTK_TYPE_BOOL, GTK_ARG_READWRITE, CHILD_ARG_EXPAND);
121  gtk_container_add_child_arg_type ("GtkBox::fill", GTK_TYPE_BOOL, GTK_ARG_READWRITE, CHILD_ARG_FILL);
122  gtk_container_add_child_arg_type ("GtkBox::padding", GTK_TYPE_ULONG, GTK_ARG_READWRITE, CHILD_ARG_PADDING);
123  gtk_container_add_child_arg_type ("GtkBox::pack_type", GTK_TYPE_PACK_TYPE, GTK_ARG_READWRITE, CHILD_ARG_PACK_TYPE);
124  gtk_container_add_child_arg_type ("GtkBox::position", GTK_TYPE_LONG, GTK_ARG_READWRITE, CHILD_ARG_POSITION);
125
126  object_class->set_arg = gtk_box_set_arg;
127  object_class->get_arg = gtk_box_get_arg;
128
129  widget_class->map = gtk_box_map;
130  widget_class->unmap = gtk_box_unmap;
131  widget_class->draw = gtk_box_draw;
132  widget_class->expose_event = gtk_box_expose;
133
134  container_class->add = gtk_box_add;
135  container_class->remove = gtk_box_remove;
136  container_class->forall = gtk_box_forall;
137  container_class->child_type = gtk_box_child_type;
138  container_class->set_child_arg = gtk_box_set_child_arg;
139  container_class->get_child_arg = gtk_box_get_child_arg;
140}
141
142static void
143gtk_box_init (GtkBox *box)
144{
145  GTK_WIDGET_SET_FLAGS (box, GTK_NO_WINDOW);
146
147  box->children = NULL;
148  box->spacing = 0;
149  box->homogeneous = FALSE;
150}
151
152static void
153gtk_box_set_arg (GtkObject    *object,
154                 GtkArg       *arg,
155                 guint         arg_id)
156{
157  GtkBox *box;
158
159  box = GTK_BOX (object);
160
161  switch (arg_id)
162    {
163    case ARG_SPACING:
164      gtk_box_set_spacing (box, GTK_VALUE_INT (*arg));
165      break;
166    case ARG_HOMOGENEOUS:
167      gtk_box_set_homogeneous (box, GTK_VALUE_BOOL (*arg));
168      break;
169    default:
170      break;
171    }
172}
173
174static void
175gtk_box_get_arg (GtkObject    *object,
176                 GtkArg       *arg,
177                 guint         arg_id)
178{
179  GtkBox *box;
180
181  box = GTK_BOX (object);
182
183  switch (arg_id)
184    {
185    case ARG_SPACING:
186      GTK_VALUE_INT (*arg) = box->spacing;
187      break;
188    case ARG_HOMOGENEOUS:
189      GTK_VALUE_BOOL (*arg) = box->homogeneous;
190      break;
191    default:
192      arg->type = GTK_TYPE_INVALID;
193      break;
194    }
195}
196
197static GtkType
198gtk_box_child_type      (GtkContainer   *container)
199{
200  return GTK_TYPE_WIDGET;
201}
202
203static void
204gtk_box_set_child_arg (GtkContainer   *container,
205                       GtkWidget      *child,
206                       GtkArg         *arg,
207                       guint           arg_id)
208{
209  gboolean expand = 0;
210  gboolean fill = 0;
211  guint padding = 0;
212  GtkPackType pack_type = 0;
213
214  if (arg_id != CHILD_ARG_POSITION)
215    gtk_box_query_child_packing (GTK_BOX (container),
216                                 child,
217                                 &expand,
218                                 &fill,
219                                 &padding,
220                                 &pack_type);
221 
222  switch (arg_id)
223    {
224    case CHILD_ARG_EXPAND:
225      gtk_box_set_child_packing (GTK_BOX (container),
226                                 child,
227                                 GTK_VALUE_BOOL (*arg),
228                                 fill,
229                                 padding,
230                                 pack_type);
231      break;
232    case CHILD_ARG_FILL:
233      gtk_box_set_child_packing (GTK_BOX (container),
234                                 child,
235                                 expand,
236                                 GTK_VALUE_BOOL (*arg),
237                                 padding,
238                                 pack_type);
239      break;
240    case CHILD_ARG_PADDING:
241      gtk_box_set_child_packing (GTK_BOX (container),
242                                 child,
243                                 expand,
244                                 fill,
245                                 GTK_VALUE_ULONG (*arg),
246                                 pack_type);
247      break;
248    case CHILD_ARG_PACK_TYPE:
249      gtk_box_set_child_packing (GTK_BOX (container),
250                                 child,
251                                 expand,
252                                 fill,
253                                 padding,
254                                 GTK_VALUE_ENUM (*arg));
255      break;
256    case CHILD_ARG_POSITION:
257      gtk_box_reorder_child (GTK_BOX (container),
258                             child,
259                             GTK_VALUE_LONG (*arg));
260      break;
261    default:
262      break;
263    }
264}
265
266static void
267gtk_box_get_child_arg (GtkContainer   *container,
268                       GtkWidget      *child,
269                       GtkArg         *arg,
270                       guint           arg_id)
271{
272  gboolean expand = 0;
273  gboolean fill = 0;
274  guint padding = 0;
275  GtkPackType pack_type = 0;
276  GList *list;
277
278  if (arg_id != CHILD_ARG_POSITION)
279    gtk_box_query_child_packing (GTK_BOX (container),
280                                 child,
281                                 &expand,
282                                 &fill,
283                                 &padding,
284                                 &pack_type);
285 
286  switch (arg_id)
287    {
288    case CHILD_ARG_EXPAND:
289      GTK_VALUE_BOOL (*arg) = expand;
290      break;
291    case CHILD_ARG_FILL:
292      GTK_VALUE_BOOL (*arg) = fill;
293      break;
294    case CHILD_ARG_PADDING:
295      GTK_VALUE_ULONG (*arg) = padding;
296      break;
297    case CHILD_ARG_PACK_TYPE:
298      GTK_VALUE_ENUM (*arg) = pack_type;
299      break;
300    case CHILD_ARG_POSITION:
301      GTK_VALUE_LONG (*arg) = 0;
302      for (list = GTK_BOX (container)->children; list; list = list->next)
303        {
304          GtkBoxChild *child_entry;
305
306          child_entry = list->data;
307          if (child_entry->widget == child)
308            break;
309          GTK_VALUE_LONG (*arg)++;
310        }
311      if (!list)
312        GTK_VALUE_LONG (*arg) = -1;
313      break;
314    default:
315      arg->type = GTK_TYPE_INVALID;
316      break;
317    }
318}
319
320void
321gtk_box_pack_start (GtkBox    *box,
322                    GtkWidget *child,
323                    gboolean   expand,
324                    gboolean   fill,
325                    guint      padding)
326{
327  GtkBoxChild *child_info;
328
329  g_return_if_fail (box != NULL);
330  g_return_if_fail (GTK_IS_BOX (box));
331  g_return_if_fail (child != NULL);
332  g_return_if_fail (child->parent == NULL);
333
334  child_info = g_new (GtkBoxChild, 1);
335  child_info->widget = child;
336  child_info->padding = padding;
337  child_info->expand = expand ? TRUE : FALSE;
338  child_info->fill = fill ? TRUE : FALSE;
339  child_info->pack = GTK_PACK_START;
340
341  box->children = g_list_append (box->children, child_info);
342
343  gtk_widget_set_parent (child, GTK_WIDGET (box));
344 
345  if (GTK_WIDGET_REALIZED (box))
346    gtk_widget_realize (child);
347
348  if (GTK_WIDGET_VISIBLE (box) && GTK_WIDGET_VISIBLE (child))
349    {
350      if (GTK_WIDGET_MAPPED (box))
351        gtk_widget_map (child);
352
353      gtk_widget_queue_resize (child);
354    }
355}
356
357void
358gtk_box_pack_end (GtkBox    *box,
359                  GtkWidget *child,
360                  gboolean   expand,
361                  gboolean   fill,
362                  guint      padding)
363{
364  GtkBoxChild *child_info;
365
366  g_return_if_fail (box != NULL);
367  g_return_if_fail (GTK_IS_BOX (box));
368  g_return_if_fail (child != NULL);
369  g_return_if_fail (child->parent == NULL);
370
371  child_info = g_new (GtkBoxChild, 1);
372  child_info->widget = child;
373  child_info->padding = padding;
374  child_info->expand = expand ? TRUE : FALSE;
375  child_info->fill = fill ? TRUE : FALSE;
376  child_info->pack = GTK_PACK_END;
377
378  box->children = g_list_append (box->children, child_info);
379
380  gtk_widget_set_parent (child, GTK_WIDGET (box));
381
382  if (GTK_WIDGET_REALIZED (box))
383    gtk_widget_realize (child);
384
385  if (GTK_WIDGET_VISIBLE (box) && GTK_WIDGET_VISIBLE (child))
386    {
387      if (GTK_WIDGET_MAPPED (box))
388        gtk_widget_map (child);
389
390      gtk_widget_queue_resize (child);
391    }
392}
393
394void
395gtk_box_pack_start_defaults (GtkBox    *box,
396                             GtkWidget *child)
397{
398  g_return_if_fail (box != NULL);
399  g_return_if_fail (GTK_IS_BOX (box));
400  g_return_if_fail (child != NULL);
401
402  gtk_box_pack_start (box, child, TRUE, TRUE, 0);
403}
404
405void
406gtk_box_pack_end_defaults (GtkBox    *box,
407                           GtkWidget *child)
408{
409  g_return_if_fail (box != NULL);
410  g_return_if_fail (GTK_IS_BOX (box));
411  g_return_if_fail (child != NULL);
412
413  gtk_box_pack_end (box, child, TRUE, TRUE, 0);
414}
415
416void
417gtk_box_set_homogeneous (GtkBox  *box,
418                         gboolean homogeneous)
419{
420  g_return_if_fail (box != NULL);
421  g_return_if_fail (GTK_IS_BOX (box));
422
423  if ((homogeneous ? TRUE : FALSE) != box->homogeneous)
424    {
425      box->homogeneous = homogeneous ? TRUE : FALSE;
426      gtk_widget_queue_resize (GTK_WIDGET (box));
427    }
428}
429
430void
431gtk_box_set_spacing (GtkBox *box,
432                     gint    spacing)
433{
434  g_return_if_fail (box != NULL);
435  g_return_if_fail (GTK_IS_BOX (box));
436
437  if (spacing != box->spacing)
438    {
439      box->spacing = spacing;
440      gtk_widget_queue_resize (GTK_WIDGET (box));
441    }
442}
443
444void
445gtk_box_reorder_child (GtkBox                   *box,
446                       GtkWidget                *child,
447                       gint                      position)
448{
449  GList *list;
450
451  g_return_if_fail (box != NULL);
452  g_return_if_fail (GTK_IS_BOX (box));
453  g_return_if_fail (child != NULL);
454
455  list = box->children;
456  while (list)
457    {
458      GtkBoxChild *child_info;
459
460      child_info = list->data;
461      if (child_info->widget == child)
462        break;
463
464      list = list->next;
465    }
466
467  if (list && box->children->next)
468    {
469      GList *tmp_list;
470
471      if (list->next)
472        list->next->prev = list->prev;
473      if (list->prev)
474        list->prev->next = list->next;
475      else
476        box->children = list->next;
477
478      tmp_list = box->children;
479      while (position && tmp_list->next)
480        {
481          position--;
482          tmp_list = tmp_list->next;
483        }
484
485      if (position)
486        {
487          tmp_list->next = list;
488          list->prev = tmp_list;
489          list->next = NULL;
490        }
491      else
492        {
493          if (tmp_list->prev)
494            tmp_list->prev->next = list;
495          else
496            box->children = list;
497          list->prev = tmp_list->prev;
498          tmp_list->prev = list;
499          list->next = tmp_list;
500        }
501
502      if (GTK_WIDGET_VISIBLE (child) && GTK_WIDGET_VISIBLE (box))
503        gtk_widget_queue_resize (child);
504    }
505}
506
507void
508gtk_box_query_child_packing (GtkBox             *box,
509                             GtkWidget          *child,
510                             gboolean           *expand,
511                             gboolean           *fill,
512                             guint              *padding,
513                             GtkPackType        *pack_type)
514{
515  GList *list;
516  GtkBoxChild *child_info = NULL;
517
518  g_return_if_fail (box != NULL);
519  g_return_if_fail (GTK_IS_BOX (box));
520  g_return_if_fail (child != NULL);
521
522  list = box->children;
523  while (list)
524    {
525      child_info = list->data;
526      if (child_info->widget == child)
527        break;
528
529      list = list->next;
530    }
531
532  if (list)
533    {
534      if (expand)
535        *expand = child_info->expand;
536      if (fill)
537        *fill = child_info->fill;
538      if (padding)
539        *padding = child_info->padding;
540      if (pack_type)
541        *pack_type = child_info->pack;
542    }
543}
544
545void
546gtk_box_set_child_packing (GtkBox               *box,
547                           GtkWidget            *child,
548                           gboolean              expand,
549                           gboolean              fill,
550                           guint                 padding,
551                           GtkPackType           pack_type)
552{
553  GList *list;
554  GtkBoxChild *child_info = NULL;
555
556  g_return_if_fail (box != NULL);
557  g_return_if_fail (GTK_IS_BOX (box));
558  g_return_if_fail (child != NULL);
559
560  list = box->children;
561  while (list)
562    {
563      child_info = list->data;
564      if (child_info->widget == child)
565        break;
566
567      list = list->next;
568    }
569
570  if (list)
571    {
572      child_info->expand = expand != FALSE;
573      child_info->fill = fill != FALSE;
574      child_info->padding = padding;
575      if (pack_type == GTK_PACK_END)
576        child_info->pack = GTK_PACK_END;
577      else
578        child_info->pack = GTK_PACK_START;
579
580      if (GTK_WIDGET_VISIBLE (child) && GTK_WIDGET_VISIBLE (box))
581        gtk_widget_queue_resize (child);
582    }
583}
584
585static void
586gtk_box_map (GtkWidget *widget)
587{
588  GtkBox *box;
589  GtkBoxChild *child;
590  GList *children;
591
592  g_return_if_fail (widget != NULL);
593  g_return_if_fail (GTK_IS_BOX (widget));
594
595  box = GTK_BOX (widget);
596  GTK_WIDGET_SET_FLAGS (box, GTK_MAPPED);
597
598  children = box->children;
599  while (children)
600    {
601      child = children->data;
602      children = children->next;
603
604      if (GTK_WIDGET_VISIBLE (child->widget) &&
605          !GTK_WIDGET_MAPPED (child->widget))
606        gtk_widget_map (child->widget);
607    }
608}
609
610static void
611gtk_box_unmap (GtkWidget *widget)
612{
613  GtkBox *box;
614  GtkBoxChild *child;
615  GList *children;
616
617  g_return_if_fail (widget != NULL);
618  g_return_if_fail (GTK_IS_BOX (widget));
619
620  box = GTK_BOX (widget);
621  GTK_WIDGET_UNSET_FLAGS (box, GTK_MAPPED);
622
623  children = box->children;
624  while (children)
625    {
626      child = children->data;
627      children = children->next;
628
629      if (GTK_WIDGET_VISIBLE (child->widget) &&
630          GTK_WIDGET_MAPPED (child->widget))
631        gtk_widget_unmap (child->widget);
632    }
633}
634
635static void
636gtk_box_draw (GtkWidget    *widget,
637              GdkRectangle *area)
638{
639  GtkBox *box;
640  GtkBoxChild *child;
641  GdkRectangle child_area;
642  GList *children;
643 
644  g_return_if_fail (widget != NULL);
645  g_return_if_fail (GTK_IS_BOX (widget));
646   
647  if (GTK_WIDGET_DRAWABLE (widget))
648    {
649      box = GTK_BOX (widget);
650       
651      children = box->children;
652      while (children)
653        {
654          child = children->data;
655          children = children->next;
656             
657          if (GTK_WIDGET_DRAWABLE (child->widget) &&
658              gtk_widget_intersect (child->widget, area, &child_area))
659            gtk_widget_draw (child->widget, &child_area);
660        }
661    }
662}
663
664static gint
665gtk_box_expose (GtkWidget      *widget,
666                GdkEventExpose *event)
667{
668  GtkBox *box;
669  GtkBoxChild *child;
670  GdkEventExpose child_event;
671  GList *children;
672
673  g_return_val_if_fail (widget != NULL, FALSE);
674  g_return_val_if_fail (GTK_IS_BOX (widget), FALSE);
675  g_return_val_if_fail (event != NULL, FALSE);
676
677  if (GTK_WIDGET_DRAWABLE (widget))
678    {
679      box = GTK_BOX (widget);
680
681      child_event = *event;
682
683      children = box->children;
684      while (children)
685        {
686          child = children->data;
687          children = children->next;
688
689          if (GTK_WIDGET_DRAWABLE (child->widget) &&
690              GTK_WIDGET_NO_WINDOW (child->widget) &&
691              gtk_widget_intersect (child->widget, &event->area, &child_event.area))
692            gtk_widget_event (child->widget, (GdkEvent*) &child_event);
693        }
694    }
695
696  return FALSE;
697}
698
699static void
700gtk_box_add (GtkContainer *container,
701             GtkWidget    *widget)
702{
703  g_return_if_fail (container != NULL);
704  g_return_if_fail (GTK_IS_BOX (container));
705  g_return_if_fail (widget != NULL);
706
707  gtk_box_pack_start_defaults (GTK_BOX (container), widget);
708}
709
710static void
711gtk_box_remove (GtkContainer *container,
712                GtkWidget    *widget)
713{
714  GtkBox *box;
715  GtkBoxChild *child;
716  GList *children;
717
718  g_return_if_fail (container != NULL);
719  g_return_if_fail (GTK_IS_BOX (container));
720  g_return_if_fail (widget != NULL);
721
722  box = GTK_BOX (container);
723
724  children = box->children;
725  while (children)
726    {
727      child = children->data;
728
729      if (child->widget == widget)
730        {
731          gboolean was_visible;
732
733          was_visible = GTK_WIDGET_VISIBLE (widget);
734          gtk_widget_unparent (widget);
735
736          box->children = g_list_remove_link (box->children, children);
737          g_list_free (children);
738          g_free (child);
739
740          /* queue resize regardless of GTK_WIDGET_VISIBLE (container),
741           * since that's what is needed by toplevels.
742           */
743          if (was_visible)
744            gtk_widget_queue_resize (GTK_WIDGET (container));
745
746          break;
747        }
748
749      children = children->next;
750    }
751}
752
753static void
754gtk_box_forall (GtkContainer *container,
755                gboolean      include_internals,
756                GtkCallback   callback,
757                gpointer      callback_data)
758{
759  GtkBox *box;
760  GtkBoxChild *child;
761  GList *children;
762
763  g_return_if_fail (container != NULL);
764  g_return_if_fail (GTK_IS_BOX (container));
765  g_return_if_fail (callback != NULL);
766
767  box = GTK_BOX (container);
768
769  children = box->children;
770  while (children)
771    {
772      child = children->data;
773      children = children->next;
774
775      if (child->pack == GTK_PACK_START)
776        (* callback) (child->widget, callback_data);
777    }
778
779  children = g_list_last (box->children);
780  while (children)
781    {
782      child = children->data;
783      children = children->prev;
784
785      if (child->pack == GTK_PACK_END)
786        (* callback) (child->widget, callback_data);
787    }
788}
Note: See TracBrowser for help on using the repository browser.