]> Pileus Git - ~andy/gtk/blob - gtk/gtkpacker.c
Modified Files: gtkclist.c gtkclist.h gtkctree.c gtkctree.h gtknotebook.c
[~andy/gtk] / gtk / gtkpacker.c
1 /* GTK - The GIMP Toolkit
2  * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
3  * 
4  * GtkPacker Widget 
5  * Copyright (C) 1998 Shawn T. Amundson, James S. Mitchell, Michael L. Staiger
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Library General Public
9  * License as published by the Free Software Foundation; either
10  * version 2 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Library General Public License for more details.
16  *
17  * You should have received a copy of the GNU Library General Public
18  * License along with this library; if not, write to the
19  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20  * Boston, MA 02111-1307, USA.
21  */
22
23
24 /* 
25  * This file contains modified code derived from Tk 8.0.  Below is the header of
26  * the relevant file.  The file 'license.terms' is included inline below.
27  * 
28  * tkPack.c --
29  *
30  *      This file contains code to implement the "packer"
31  *      geometry manager for Tk.
32  *
33  * Copyright (c) 1990-1994 The Regents of the University of California.
34  * Copyright (c) 1994-1995 Sun Microsystems, Inc.
35  *
36  * See the file "license.terms" for information on usage and redistribution
37  * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
38  *
39  * SCCS: @(#) tkPack.c 1.64 96/05/03 10:51:52
40  *
41  * The file license.terms is below.  NOTE: THE FOLLOWING APPLIES ONLY TO
42  * PORTIONS DERIVED FROM TK 8.0.  THE LICENSE FOR THIS FILE IS LGPL, AS
43  * STATED ABOVE AND ALLOWED BELOW.  
44 -- BEGIN license.terms --
45 This software is copyrighted by the Regents of the University of
46 California, Sun Microsystems, Inc., and other parties.  The following
47 terms apply to all files associated with the software unless explicitly
48 disclaimed in individual files.
49
50 The authors hereby grant permission to use, copy, modify, distribute,
51 and license this software and its documentation for any purpose, provided
52 that existing copyright notices are retained in all copies and that this
53 notice is included verbatim in any distributions. No written agreement,
54 license, or royalty fee is required for any of the authorized uses.
55 Modifications to this software may be copyrighted by their authors
56 and need not follow the licensing terms described here, provided that
57 the new terms are clearly indicated on the first page of each file where
58 they apply.
59
60 IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY
61 FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
62 ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY
63 DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE
64 POSSIBILITY OF SUCH DAMAGE.
65
66 THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES,
67 INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY,
68 FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT.  THIS SOFTWARE
69 IS PROVIDED ON AN "AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE
70 NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR
71 MODIFICATIONS.
72
73 GOVERNMENT USE: If you are acquiring this software on behalf of the
74 U.S. government, the Government shall have only "Restricted Rights"
75 in the software and related documentation as defined in the Federal 
76 Acquisition Regulations (FARs) in Clause 52.227.19 (c) (2).  If you
77 are acquiring the software on behalf of the Department of Defense, the
78 software shall be classified as "Commercial Computer Software" and the
79 Government shall have only "Restricted Rights" as defined in Clause
80 252.227-7013 (c) (1) of DFARs.  Notwithstanding the foregoing, the
81 authors grant the U.S. Government and others acting in its behalf
82 permission to use and distribute the software in accordance with the
83 terms specified in this license.
84 -- END license.terms --
85  *
86  */
87
88
89 #include "gtkpacker.h"
90
91
92 enum {
93   ARG_0,
94   ARG_SPACING,
95   ARG_D_BORDER_WIDTH,
96   ARG_D_PAD_X,
97   ARG_D_PAD_Y,
98   ARG_D_IPAD_X,
99   ARG_D_IPAD_Y
100 };
101
102 enum {
103   CHILD_ARG_0,
104   CHILD_ARG_SIDE,
105   CHILD_ARG_ANCHOR,
106   CHILD_ARG_EXPAND,
107   CHILD_ARG_FILL_X,
108   CHILD_ARG_FILL_Y,
109   CHILD_ARG_USE_DEFAULT,
110   CHILD_ARG_BORDER_WIDTH,
111   CHILD_ARG_PAD_X,
112   CHILD_ARG_PAD_Y,
113   CHILD_ARG_I_PAD_X,
114   CHILD_ARG_I_PAD_Y,
115   CHILD_ARG_POSITION
116 };
117
118 static void gtk_packer_class_init    (GtkPackerClass   *klass);
119 static void gtk_packer_init          (GtkPacker        *packer);
120 static void gtk_packer_map           (GtkWidget        *widget);
121 static void gtk_packer_unmap         (GtkWidget        *widget);
122 static void gtk_packer_draw          (GtkWidget        *widget,
123                                       GdkRectangle     *area);
124 static gint gtk_packer_expose        (GtkWidget        *widget,
125                                       GdkEventExpose   *event);
126 static void gtk_packer_size_request  (GtkWidget      *widget,
127                                       GtkRequisition *requisition);
128 static void gtk_packer_size_allocate (GtkWidget      *widget,
129                                       GtkAllocation  *allocation);
130 static void gtk_packer_container_add (GtkContainer   *container,
131                                       GtkWidget      *child);
132 static void gtk_packer_remove        (GtkContainer   *container,
133                                       GtkWidget      *widget);
134 static void gtk_packer_forall        (GtkContainer   *container,
135                                       gboolean        include_internals,
136                                       GtkCallback     callback,
137                                       gpointer        callback_data);
138 static void gtk_packer_set_arg       (GtkObject      *object,
139                                       GtkArg         *arg,
140                                       guint           arg_id);
141 static void gtk_packer_get_arg       (GtkObject      *object,
142                                       GtkArg         *arg,
143                                       guint           arg_id);
144 static void gtk_packer_get_child_arg (GtkContainer   *container,
145                                       GtkWidget      *child,
146                                       GtkArg         *arg,
147                                       guint           arg_id);
148 static void gtk_packer_set_child_arg (GtkContainer   *container,
149                                       GtkWidget      *child,
150                                       GtkArg         *arg,
151                                       guint           arg_id);
152 static GtkType gtk_packer_child_type (GtkContainer   *container);
153      
154
155 static GtkPackerClass *parent_class;
156
157 GtkType
158 gtk_packer_get_type (void)
159 {
160   static GtkType packer_type = 0;
161
162   if (!packer_type)
163     {
164       GtkTypeInfo packer_info =
165       {
166         "GtkPacker",
167         sizeof (GtkPacker),
168         sizeof (GtkPackerClass),
169         (GtkClassInitFunc) gtk_packer_class_init,
170         (GtkObjectInitFunc) gtk_packer_init,
171         /* reserved_1 */ NULL,
172         /* reserved_2 */ NULL,
173         (GtkClassInitFunc) NULL,
174       };
175
176       packer_type = gtk_type_unique (GTK_TYPE_CONTAINER, &packer_info);
177     }
178   
179   return packer_type;
180 }
181
182 static void
183 gtk_packer_class_init (GtkPackerClass *klass)
184 {
185   GtkObjectClass *object_class;
186   GtkWidgetClass *widget_class;
187   GtkContainerClass *container_class;
188   
189   object_class = (GtkObjectClass*) klass;
190   widget_class = (GtkWidgetClass*) klass;
191   container_class = (GtkContainerClass*) klass;
192   parent_class = gtk_type_class (GTK_TYPE_CONTAINER);
193   
194   gtk_object_add_arg_type ("GtkPacker::spacing", GTK_TYPE_UINT, GTK_ARG_READWRITE, ARG_SPACING);
195   gtk_object_add_arg_type ("GtkPacker::default_border_width", GTK_TYPE_UINT, GTK_ARG_READWRITE, ARG_D_BORDER_WIDTH);
196   gtk_object_add_arg_type ("GtkPacker::default_pad_x", GTK_TYPE_UINT, GTK_ARG_READWRITE, ARG_D_PAD_X);
197   gtk_object_add_arg_type ("GtkPacker::default_pad_y", GTK_TYPE_UINT, GTK_ARG_READWRITE, ARG_D_PAD_Y);
198   gtk_object_add_arg_type ("GtkPacker::default_ipad_x", GTK_TYPE_UINT, GTK_ARG_READWRITE, ARG_D_IPAD_X);
199   gtk_object_add_arg_type ("GtkPacker::default_ipad_y", GTK_TYPE_UINT, GTK_ARG_READWRITE, ARG_D_IPAD_Y);
200
201   gtk_container_add_child_arg_type ("GtkPacker::side", GTK_TYPE_SIDE_TYPE, GTK_ARG_READWRITE, CHILD_ARG_SIDE);
202   gtk_container_add_child_arg_type ("GtkPacker::anchor", GTK_TYPE_ANCHOR_TYPE, GTK_ARG_READWRITE, CHILD_ARG_ANCHOR);
203   gtk_container_add_child_arg_type ("GtkPacker::expand", GTK_TYPE_BOOL, GTK_ARG_READWRITE, CHILD_ARG_EXPAND);
204   gtk_container_add_child_arg_type ("GtkPacker::fill_x", GTK_TYPE_BOOL, GTK_ARG_READWRITE, CHILD_ARG_FILL_X);
205   gtk_container_add_child_arg_type ("GtkPacker::fill_y", GTK_TYPE_BOOL, GTK_ARG_READWRITE, CHILD_ARG_FILL_Y);
206   gtk_container_add_child_arg_type ("GtkPacker::use_default", GTK_TYPE_BOOL, GTK_ARG_READWRITE, CHILD_ARG_USE_DEFAULT);
207   gtk_container_add_child_arg_type ("GtkPacker::border_width", GTK_TYPE_UINT, GTK_ARG_READWRITE, CHILD_ARG_BORDER_WIDTH);
208   gtk_container_add_child_arg_type ("GtkPacker::pad_x", GTK_TYPE_UINT, GTK_ARG_READWRITE, CHILD_ARG_PAD_X);
209   gtk_container_add_child_arg_type ("GtkPacker::pad_y", GTK_TYPE_UINT, GTK_ARG_READWRITE, CHILD_ARG_PAD_Y);
210   gtk_container_add_child_arg_type ("GtkPacker::ipad_x", GTK_TYPE_UINT, GTK_ARG_READWRITE, CHILD_ARG_I_PAD_X);
211   gtk_container_add_child_arg_type ("GtkPacker::ipad_y", GTK_TYPE_UINT, GTK_ARG_READWRITE, CHILD_ARG_I_PAD_Y);
212   gtk_container_add_child_arg_type ("GtkPacker::position", GTK_TYPE_LONG, GTK_ARG_READWRITE, CHILD_ARG_POSITION);
213
214   object_class->set_arg = gtk_packer_set_arg;
215   object_class->get_arg = gtk_packer_get_arg;
216
217   widget_class->map = gtk_packer_map;
218   widget_class->unmap = gtk_packer_unmap;
219   widget_class->draw = gtk_packer_draw;
220   widget_class->expose_event = gtk_packer_expose;
221   
222   widget_class->size_request = gtk_packer_size_request;
223   widget_class->size_allocate = gtk_packer_size_allocate;
224   
225   container_class->add = gtk_packer_container_add;
226   container_class->remove = gtk_packer_remove;
227   container_class->forall = gtk_packer_forall;
228   container_class->child_type = gtk_packer_child_type;
229   container_class->get_child_arg = gtk_packer_get_child_arg;
230   container_class->set_child_arg = gtk_packer_set_child_arg;
231 }
232
233 static void
234 gtk_packer_set_arg (GtkObject    *object,
235                     GtkArg       *arg,
236                     guint         arg_id)
237 {
238   GtkPacker *packer;
239
240   packer = GTK_PACKER (object);
241
242   switch (arg_id)
243     {
244     case ARG_SPACING:
245       gtk_packer_set_spacing (packer, GTK_VALUE_UINT (*arg));
246       break;
247     case ARG_D_BORDER_WIDTH:
248       gtk_packer_set_default_border_width (packer, GTK_VALUE_UINT (*arg));
249       break;
250     case ARG_D_PAD_X:
251       gtk_packer_set_default_pad (packer,
252                                   GTK_VALUE_UINT (*arg),
253                                   packer->default_pad_y);
254       break;
255     case ARG_D_PAD_Y:
256       gtk_packer_set_default_pad (packer,
257                                   packer->default_pad_x,
258                                   GTK_VALUE_UINT (*arg));
259       break;
260     case ARG_D_IPAD_X:
261       gtk_packer_set_default_ipad (packer,
262                                    GTK_VALUE_UINT (*arg),
263                                    packer->default_i_pad_y);
264       break;
265     case ARG_D_IPAD_Y:
266       gtk_packer_set_default_ipad (packer,
267                                    packer->default_i_pad_x,
268                                    GTK_VALUE_UINT (*arg));
269       break;
270     default:
271       break;
272     }
273 }
274
275 static void
276 gtk_packer_get_arg (GtkObject    *object,
277                     GtkArg       *arg,
278                     guint         arg_id)
279 {
280   GtkPacker *packer;
281
282   packer = GTK_PACKER (object);
283
284   switch (arg_id)
285     {
286     case ARG_SPACING:
287       GTK_VALUE_UINT (*arg) = packer->spacing;
288       break;
289     case ARG_D_BORDER_WIDTH:
290       GTK_VALUE_UINT (*arg) = packer->default_border_width;
291       break;
292     case ARG_D_PAD_X:
293       GTK_VALUE_UINT (*arg) = packer->default_pad_x;
294       break;
295     case ARG_D_PAD_Y:
296       GTK_VALUE_UINT (*arg) = packer->default_pad_y;
297       break;
298     case ARG_D_IPAD_X:
299       GTK_VALUE_UINT (*arg) = packer->default_i_pad_x;
300       break;
301     case ARG_D_IPAD_Y:
302       GTK_VALUE_UINT (*arg) = packer->default_i_pad_y;
303       break;
304     default:
305       arg->type = GTK_TYPE_INVALID;
306       break;
307     }
308 }
309
310 static GtkType
311 gtk_packer_child_type (GtkContainer   *container)
312 {
313   return GTK_TYPE_WIDGET;
314 }
315
316 static void
317 gtk_packer_set_child_arg (GtkContainer   *container,
318                           GtkWidget      *child,
319                           GtkArg         *arg,
320                           guint           arg_id)
321 {
322   GtkPacker *packer;
323   GtkPackerChild *child_info = NULL;
324   
325   packer = GTK_PACKER (container);
326
327   if (arg_id != CHILD_ARG_POSITION)
328     {
329       GList *list;
330       
331       list = packer->children;
332       while (list)
333         {
334           child_info = list->data;
335           if (child_info->widget == child)
336             break;
337           
338           list = list->next;
339         }
340       if (!list)
341         return;
342     }
343
344   switch (arg_id)
345     {
346     case CHILD_ARG_SIDE:
347       child_info->side = GTK_VALUE_ENUM (*arg);
348       break;
349     case CHILD_ARG_ANCHOR:
350       child_info->anchor = GTK_VALUE_ENUM (*arg);
351       break;
352     case CHILD_ARG_EXPAND:
353       if (GTK_VALUE_BOOL (*arg))
354         child_info->options |= GTK_PACK_EXPAND;
355       else
356         child_info->options &= ~GTK_PACK_EXPAND;
357       break;
358     case CHILD_ARG_FILL_X:
359       if (GTK_VALUE_BOOL (*arg))
360         child_info->options |= GTK_FILL_X;
361       else
362         child_info->options &= ~GTK_FILL_X;
363       break;
364     case CHILD_ARG_FILL_Y:
365       if (GTK_VALUE_BOOL (*arg))
366         child_info->options |= GTK_FILL_Y;
367       else
368         child_info->options &= ~GTK_FILL_Y;
369       break;
370     case CHILD_ARG_USE_DEFAULT:
371       child_info->use_default = (GTK_VALUE_BOOL (*arg) != 0);
372       break;
373     case CHILD_ARG_BORDER_WIDTH:
374       if (!child_info->use_default)
375         child_info->border_width = GTK_VALUE_UINT (*arg);
376       break;
377     case CHILD_ARG_PAD_X:
378       if (!child_info->use_default)
379         child_info->pad_x = GTK_VALUE_UINT (*arg);
380       break;
381     case CHILD_ARG_PAD_Y:
382       if (!child_info->use_default)
383         child_info->pad_y = GTK_VALUE_UINT (*arg);
384       break;
385     case CHILD_ARG_I_PAD_X:
386       if (!child_info->use_default)
387         child_info->i_pad_x = GTK_VALUE_UINT (*arg);
388       break;
389     case CHILD_ARG_I_PAD_Y:
390       if (!child_info->use_default)
391         child_info->i_pad_y = GTK_VALUE_UINT (*arg);
392       break;
393     case CHILD_ARG_POSITION:
394       gtk_packer_reorder_child (packer,
395                                 child,
396                                 GTK_VALUE_LONG (*arg));
397       break;
398     default:
399       break;
400     }
401
402   if (arg_id != CHILD_ARG_POSITION &&
403       GTK_WIDGET_VISIBLE (packer) &&
404       GTK_WIDGET_VISIBLE (child))
405     gtk_widget_queue_resize (child);
406 }
407
408 static void
409 gtk_packer_get_child_arg (GtkContainer   *container,
410                           GtkWidget      *child,
411                           GtkArg         *arg,
412                           guint           arg_id)
413 {
414   GtkPacker *packer;
415   GtkPackerChild *child_info = NULL;
416   GList * list;
417   
418   packer = GTK_PACKER (container);
419
420   if (arg_id != CHILD_ARG_POSITION)
421     {
422       list = packer->children;
423       while (list)
424         {
425           child_info = list->data;
426           if (child_info->widget == child)
427             break;
428           
429           list = list->next;
430         }
431       if (!list)
432         {
433           arg->type = GTK_TYPE_INVALID;
434           return;
435         }
436     }
437
438   switch (arg_id)
439     {
440     case CHILD_ARG_SIDE:
441       GTK_VALUE_ENUM (*arg) = child_info->side;
442       break;
443     case CHILD_ARG_ANCHOR:
444       GTK_VALUE_ENUM (*arg) = child_info->anchor;
445       break;
446     case CHILD_ARG_EXPAND:
447       GTK_VALUE_BOOL (*arg) = (child_info->options & GTK_PACK_EXPAND) != 0;
448       break;
449     case CHILD_ARG_FILL_X:
450       GTK_VALUE_BOOL (*arg) = (child_info->options & GTK_FILL_X) != 0;
451       break;
452     case CHILD_ARG_FILL_Y:
453       GTK_VALUE_BOOL (*arg) = (child_info->options & GTK_FILL_Y) != 0;
454       break;
455     case CHILD_ARG_USE_DEFAULT:
456       GTK_VALUE_BOOL (*arg) = child_info->use_default;
457       break;
458     case CHILD_ARG_BORDER_WIDTH:
459       GTK_VALUE_UINT (*arg) = child_info->border_width;
460       break;
461     case CHILD_ARG_PAD_X:
462       GTK_VALUE_UINT (*arg) = child_info->pad_x;
463       break;
464     case CHILD_ARG_PAD_Y:
465       GTK_VALUE_UINT (*arg) = child_info->pad_y;
466       break;
467     case CHILD_ARG_I_PAD_X:
468       GTK_VALUE_UINT (*arg) = child_info->i_pad_x;
469       break;
470     case CHILD_ARG_I_PAD_Y:
471       GTK_VALUE_UINT (*arg) = child_info->i_pad_y;
472       break;
473     case CHILD_ARG_POSITION:
474       GTK_VALUE_LONG (*arg) = 0;
475       for (list = packer->children; list; list = list->next)
476         {
477           child_info = list->data;
478           if (child_info->widget == child)
479             break;
480           GTK_VALUE_LONG (*arg)++;
481         }
482       if (!list)
483         GTK_VALUE_LONG (*arg) = -1;
484       break;
485     default:
486       arg->type = GTK_TYPE_INVALID;
487       break;
488     }
489 }
490
491 static void
492 gtk_packer_init (GtkPacker *packer)
493 {
494   GTK_WIDGET_SET_FLAGS (packer, GTK_NO_WINDOW);
495   
496   packer->children = NULL;
497   packer->spacing = 0;
498 }
499
500 void
501 gtk_packer_set_spacing (GtkPacker *packer,
502                         guint      spacing)
503 {
504   g_return_if_fail (packer != NULL);
505   g_return_if_fail (GTK_IS_PACKER (packer));
506   
507   if (spacing != packer->spacing) 
508     {
509       packer->spacing = spacing;
510       gtk_widget_queue_resize (GTK_WIDGET (packer));
511     }
512 }
513
514 GtkWidget*
515 gtk_packer_new (void)
516 {
517   return GTK_WIDGET (gtk_type_new (GTK_TYPE_PACKER));
518 }
519
520 static void
521 redo_defaults_children (GtkPacker *packer)
522 {
523   GList *list;
524   GtkPackerChild *child;
525   
526   list = g_list_first(packer->children);
527   while (list != NULL) 
528     {
529       child = list->data;
530       
531       if (child->use_default) 
532         {
533           child->border_width = packer->default_border_width;
534           child->pad_x = packer->default_pad_x;
535           child->pad_y = packer->default_pad_y;
536           child->i_pad_x = packer->default_i_pad_x;
537           child->i_pad_y = packer->default_i_pad_y;
538           gtk_widget_queue_resize (GTK_WIDGET (child->widget));
539         }
540       list = g_list_next(list);
541     }
542 }
543
544 void
545 gtk_packer_set_default_border_width (GtkPacker *packer,
546                                      guint      border)
547 {
548   g_return_if_fail (packer != NULL);
549   g_return_if_fail (GTK_IS_PACKER (packer));
550   
551   if (packer->default_border_width != border) 
552     {
553       packer->default_border_width = border;;
554       redo_defaults_children (packer);
555     }
556 }
557 void
558 gtk_packer_set_default_pad (GtkPacker *packer,
559                             guint      pad_x,
560                             guint      pad_y)
561 {
562   g_return_if_fail (packer != NULL);
563   g_return_if_fail (GTK_IS_PACKER (packer));
564   
565   if (packer->default_pad_x != pad_x ||
566       packer->default_pad_y != pad_y) 
567     {
568       packer->default_pad_x = pad_x;
569       packer->default_pad_y = pad_y;
570       redo_defaults_children (packer);
571     }
572 }
573
574 void
575 gtk_packer_set_default_ipad (GtkPacker *packer,
576                              guint      i_pad_x,
577                              guint      i_pad_y)
578 {
579   g_return_if_fail (packer != NULL);
580   g_return_if_fail (GTK_IS_PACKER (packer));
581   
582   if (packer->default_i_pad_x != i_pad_x ||
583       packer->default_i_pad_y != i_pad_y) {
584     
585     packer->default_i_pad_x = i_pad_x;
586     packer->default_i_pad_y = i_pad_y;
587     redo_defaults_children (packer);
588   }
589 }
590
591 static void 
592 gtk_packer_container_add (GtkContainer *packer, GtkWidget *child)
593 {
594   gtk_packer_add_defaults(GTK_PACKER(packer), child,
595                           GTK_SIDE_TOP, GTK_ANCHOR_CENTER, 0);
596 }
597
598 void 
599 gtk_packer_add_defaults (GtkPacker       *packer,
600                          GtkWidget       *child,
601                          GtkSideType      side,
602                          GtkAnchorType    anchor,
603                          GtkPackerOptions options)
604 {
605   GtkPackerChild *pchild;
606   
607   g_return_if_fail (packer != NULL);
608   g_return_if_fail (GTK_IS_PACKER (packer));
609   g_return_if_fail (child != NULL);
610   g_return_if_fail (GTK_IS_WIDGET (child));
611   
612   pchild = (GtkPackerChild*) g_malloc(sizeof(GtkPackerChild));
613   
614   pchild->widget = child;
615   pchild->side = side;
616   pchild->options = options;
617   pchild->anchor = anchor;
618   
619   pchild->use_default = 1;
620   
621   pchild->border_width = packer->default_border_width;
622   pchild->pad_x = packer->default_pad_x;
623   pchild->pad_y = packer->default_pad_y;
624   pchild->i_pad_x = packer->default_i_pad_x;
625   pchild->i_pad_y = packer->default_i_pad_y;
626   
627   packer->children = g_list_append(packer->children, (gpointer) pchild);
628   
629   gtk_widget_set_parent (child, GTK_WIDGET (packer));
630   
631   if (GTK_WIDGET_VISIBLE (GTK_WIDGET (packer))) 
632     {
633       if (GTK_WIDGET_REALIZED (GTK_WIDGET (packer)) &&
634           !GTK_WIDGET_REALIZED (child)) 
635         gtk_widget_realize (child);
636       
637       if (GTK_WIDGET_MAPPED (GTK_WIDGET (packer)) &&
638           !GTK_WIDGET_MAPPED (child)) 
639         gtk_widget_map (child);
640     }
641
642   if (GTK_WIDGET_VISIBLE (child) && GTK_WIDGET_VISIBLE (packer))
643     gtk_widget_queue_resize (child);
644   
645 }
646
647 void 
648 gtk_packer_add (GtkPacker       *packer,
649                 GtkWidget       *child,
650                 GtkSideType      side,
651                 GtkAnchorType    anchor,
652                 GtkPackerOptions options,
653                 guint            border_width,
654                 guint            pad_x,
655                 guint            pad_y,
656                 guint            i_pad_x,
657                 guint            i_pad_y)
658 {
659   GtkPackerChild *pchild;
660   
661   g_return_if_fail (packer != NULL);
662   g_return_if_fail (GTK_IS_PACKER (packer));
663   g_return_if_fail (child != NULL);
664   g_return_if_fail (GTK_IS_WIDGET (child));
665   
666   pchild = (GtkPackerChild*) g_malloc(sizeof(GtkPackerChild));
667   
668   pchild->widget = child;
669   pchild->side = side;
670   pchild->options = options;
671   pchild->anchor = anchor;
672   
673   pchild->use_default = 0;
674   
675   pchild->border_width = border_width;
676   pchild->pad_x = pad_x;
677   pchild->pad_y = pad_y;
678   pchild->i_pad_x = i_pad_x;
679   pchild->i_pad_y = i_pad_y;
680   
681   packer->children = g_list_append(packer->children, (gpointer) pchild);
682   
683   gtk_widget_set_parent (child, GTK_WIDGET (packer));
684   
685   if (GTK_WIDGET_VISIBLE (GTK_WIDGET (packer))) 
686     {
687       if (GTK_WIDGET_REALIZED (GTK_WIDGET (packer)) &&
688           !GTK_WIDGET_REALIZED (child)) 
689         gtk_widget_realize (child);
690       
691       if (GTK_WIDGET_MAPPED (GTK_WIDGET (packer)) &&
692           !GTK_WIDGET_MAPPED (child)) 
693         gtk_widget_map (child);
694     }
695   
696   if (GTK_WIDGET_VISIBLE (child) && GTK_WIDGET_VISIBLE (packer))
697     gtk_widget_queue_resize (child);
698   
699 }
700
701 void
702 gtk_packer_configure (GtkPacker       *packer,
703                       GtkWidget       *child,
704                       GtkSideType      side,
705                       GtkAnchorType    anchor,
706                       GtkPackerOptions options,
707                       guint            border_width,
708                       guint            pad_x,
709                       guint            pad_y,
710                       guint            i_pad_x,
711                       guint            i_pad_y)
712 {
713   GList *list;
714   GtkPackerChild *pchild;
715   
716   g_return_if_fail (packer != NULL);
717   g_return_if_fail (GTK_IS_PACKER (packer));
718   g_return_if_fail (child != NULL);
719   
720   list = g_list_first(packer->children);
721   while (list != NULL) 
722     {
723       pchild = (GtkPackerChild*) list->data;
724       if (pchild->widget == child) 
725         {
726           pchild->side = side;
727           pchild->anchor = anchor;
728           pchild->options = options;
729           
730           pchild->use_default = 0;
731           
732           pchild->border_width = border_width;
733           pchild->pad_x = pad_x;
734           pchild->pad_y = pad_y;
735           pchild->i_pad_x = i_pad_x;
736           pchild->i_pad_y = i_pad_y;
737           
738           if (GTK_WIDGET_VISIBLE (child) && GTK_WIDGET_VISIBLE (packer))
739             gtk_widget_queue_resize (child);
740           return;
741         }
742       list = g_list_next(list);
743     }
744
745   g_warning ("gtk_packer_configure(): couldn't find child `%s' amongst the packer's children", gtk_type_name (GTK_OBJECT_TYPE (child)));
746
747 }
748
749 void
750 gtk_packer_reorder_child (GtkPacker *packer,
751                           GtkWidget *child,
752                           gint       position)
753 {
754   GList *list;
755
756   g_return_if_fail (packer != NULL);
757   g_return_if_fail (GTK_IS_PACKER (packer));
758   g_return_if_fail (child != NULL);
759
760   list = packer->children;
761   while (list)
762     {
763       GtkPackerChild *child_info;
764
765       child_info = list->data;
766       if (child_info->widget == child)
767         break;
768
769       list = list->next;
770     }
771
772   if (list && packer->children->next)
773     {
774       GList *tmp_list;
775
776       if (list->next)
777         list->next->prev = list->prev;
778       if (list->prev)
779         list->prev->next = list->next;
780       else
781         packer->children = list->next;
782
783       tmp_list = packer->children;
784       while (position && tmp_list->next)
785         {
786           position--;
787           tmp_list = tmp_list->next;
788         }
789
790       if (position)
791         {
792           tmp_list->next = list;
793           list->prev = tmp_list;
794           list->next = NULL;
795         }
796       else
797         {
798           if (tmp_list->prev)
799             tmp_list->prev->next = list;
800           else
801             packer->children = list;
802           list->prev = tmp_list->prev;
803           tmp_list->prev = list;
804           list->next = tmp_list;
805         }
806
807       if (GTK_WIDGET_VISIBLE (child) && GTK_WIDGET_VISIBLE (packer))
808         gtk_widget_queue_resize (child);
809     }
810 }
811
812 static void 
813 gtk_packer_remove (GtkContainer *container,
814                    GtkWidget    *widget) 
815 {
816   GtkPacker *packer;
817   GtkPackerChild *child;
818   GList *children;
819   gint visible;
820   
821   g_return_if_fail (container != NULL);
822   g_return_if_fail (widget != NULL);
823   
824   packer = GTK_PACKER (container);
825   
826   children = g_list_first(packer->children);
827   while (children) 
828     {
829       child = children->data;
830       
831       if (child->widget == widget) 
832         {
833           visible = GTK_WIDGET_VISIBLE (widget);
834           gtk_widget_unparent (widget);
835           
836           packer->children = g_list_remove_link (packer->children, children);
837           g_list_free (children);
838           g_free (child);
839           
840           if (visible && GTK_WIDGET_VISIBLE (container))
841             gtk_widget_queue_resize (GTK_WIDGET (container));
842           
843           break;
844         }
845       
846       children = g_list_next(children);
847     }
848 }
849
850 static void 
851 gtk_packer_map (GtkWidget *widget)
852 {
853   GtkPacker *packer;
854   GtkPackerChild *child;
855   GList *children;
856   
857   g_return_if_fail (widget != NULL);
858   g_return_if_fail (GTK_IS_PACKER (widget));
859   
860   packer = GTK_PACKER (widget);
861   GTK_WIDGET_SET_FLAGS (packer, GTK_MAPPED);
862   
863   children = g_list_first(packer->children);
864   while (children != NULL) 
865     {
866       child = children->data;
867       children = g_list_next(children);
868       
869       if (GTK_WIDGET_VISIBLE (child->widget) &&
870           !GTK_WIDGET_MAPPED (child->widget))
871         gtk_widget_map (child->widget);
872     }
873 }
874
875 static void 
876 gtk_packer_unmap (GtkWidget *widget)
877 {
878   GtkPacker *packer;
879   GtkPackerChild *child;
880   GList *children;
881   
882   g_return_if_fail (widget != NULL);
883   g_return_if_fail (GTK_IS_PACKER (widget));
884   
885   packer = GTK_PACKER (widget);
886   GTK_WIDGET_UNSET_FLAGS (packer, GTK_MAPPED);
887   
888   children = g_list_first(packer->children);
889   while (children) 
890     {
891       child = children->data;
892       children = g_list_next(children);
893       
894       if (GTK_WIDGET_VISIBLE (child->widget) &&
895           GTK_WIDGET_MAPPED (child->widget))
896         gtk_widget_unmap (child->widget);
897     }
898 }
899
900 static void 
901 gtk_packer_draw (GtkWidget *widget, GdkRectangle     *area)
902 {
903   GtkPacker *packer;
904   GtkPackerChild *child;
905   GdkRectangle child_area;
906   GList *children;
907
908   g_return_if_fail (widget != NULL);
909   g_return_if_fail (GTK_IS_PACKER (widget));
910  
911   if (GTK_WIDGET_DRAWABLE (widget)) 
912     {
913       packer = GTK_PACKER (widget);
914       
915       children = g_list_first(packer->children);
916       while (children != NULL) 
917         {
918           child = children->data;
919           children = g_list_next(children);
920           
921           if (gtk_widget_intersect (child->widget, area, &child_area))
922             gtk_widget_draw (child->widget, &child_area);
923         }
924     }
925   
926 }
927
928 static gint 
929 gtk_packer_expose (GtkWidget *widget, GdkEventExpose *event)
930 {
931   GtkPacker *packer;
932   GtkPackerChild *child;
933   GdkEventExpose child_event;
934   GList *children;
935   
936   g_return_val_if_fail (widget != NULL, FALSE);
937   g_return_val_if_fail (GTK_IS_PACKER (widget), FALSE);
938   g_return_val_if_fail (event != NULL, FALSE);
939   
940   if (GTK_WIDGET_DRAWABLE (widget)) 
941     {
942       packer = GTK_PACKER (widget);
943       
944       child_event = *event;
945       
946       children = g_list_first(packer->children);
947       while (children) 
948         {
949           child = children->data;
950           children = g_list_next(children);
951           
952           if (GTK_WIDGET_NO_WINDOW (child->widget) &&
953               gtk_widget_intersect (child->widget, &event->area, &child_event.area))
954             gtk_widget_event (child->widget, (GdkEvent*) &child_event);
955         }
956     }   
957   
958   return FALSE;
959 }
960
961 static void 
962 gtk_packer_size_request (GtkWidget *widget, GtkRequisition *requisition)
963 {
964   GtkPacker *packer;
965   GtkContainer *container;
966   GtkPackerChild *child;
967   GList *children;
968   gint nvis_vert_children;
969   gint nvis_horz_children;
970   gint width, height;
971   gint maxWidth, maxHeight;
972   
973   g_return_if_fail (widget != NULL);
974   g_return_if_fail (GTK_IS_PACKER (widget));
975   g_return_if_fail (requisition != NULL);
976   
977   packer = GTK_PACKER (widget);
978   container = GTK_CONTAINER (widget);
979
980   requisition->width = 0;
981   requisition->height = 0;
982   nvis_vert_children = 0;
983   nvis_horz_children = 0;
984   
985   width = height = maxWidth = maxHeight = 0;
986   
987   children = g_list_first(packer->children);
988   while (children != NULL) 
989     {
990       child = children->data;
991       
992       if (GTK_WIDGET_VISIBLE (child->widget)) 
993         {
994           gtk_widget_size_request (child->widget, &child->widget->requisition);
995           
996           if((child->side == GTK_SIDE_TOP) || (child->side == GTK_SIDE_BOTTOM))
997             {
998               maxWidth = MAX (maxWidth,
999                               (child->widget->requisition.width +
1000                                2 * child->border_width +
1001                                child->pad_x + child->i_pad_x +
1002                                width));
1003               height += (child->widget->requisition.height +
1004                          2 * child->border_width +
1005                          child->pad_y + child->i_pad_y);
1006             } 
1007           else 
1008             {
1009               maxHeight = MAX (maxHeight,
1010                                (child->widget->requisition.height +
1011                                 2 * child->border_width +
1012                                 child->pad_y + child->i_pad_y +
1013                                 height));
1014               width += (child->widget->requisition.width +
1015                         2 * child->border_width +
1016                         child->pad_x + child->i_pad_x);
1017             }
1018         }
1019
1020       children = g_list_next(children);
1021     }
1022
1023   requisition->width = MAX (maxWidth, width) + 2 * container->border_width;
1024   requisition->height = MAX (maxHeight, height) + 2 * container->border_width;
1025 }
1026
1027 static gint
1028 YExpansion (GList *children, gint cavityHeight)
1029 {
1030   GList *list;
1031   GtkPackerChild *child;
1032   GtkWidget *widget;
1033   gint numExpand, minExpand, curExpand;
1034   gint childHeight;
1035   
1036   minExpand = cavityHeight;
1037   numExpand = 0;
1038   
1039   list = children;
1040   while (list != NULL) 
1041     {
1042       child = list->data;
1043       widget = child->widget;
1044       childHeight = (widget->requisition.height +
1045                      2 * child->border_width +
1046                      child->i_pad_y +
1047                      child->pad_y);
1048       if ((child->side == GTK_SIDE_LEFT) || (child->side == GTK_SIDE_RIGHT)) 
1049         {
1050           curExpand = (cavityHeight - childHeight)/numExpand;
1051           minExpand = MIN(minExpand, curExpand);
1052         } 
1053       else 
1054         {
1055           cavityHeight -= childHeight;
1056           if (child->options & GTK_PACK_EXPAND)
1057             numExpand++;
1058         }
1059       list = g_list_next(list);
1060     } 
1061   curExpand = cavityHeight/numExpand; 
1062   if (curExpand < minExpand)
1063     minExpand = curExpand;
1064   return (minExpand < 0) ? 0 : minExpand;
1065 }
1066
1067 static gint
1068 XExpansion (GList *children, gint cavityWidth)
1069 {
1070   GList *list;
1071   GtkPackerChild *child;
1072   GtkWidget *widget;
1073   gint numExpand, minExpand, curExpand;
1074   gint childWidth;
1075   
1076   minExpand = cavityWidth;
1077   numExpand = 0;
1078   
1079   list = children;
1080   while (list != NULL) 
1081     {
1082       child = list->data;
1083       widget = child->widget;
1084       childWidth = (widget->requisition.width +
1085                     2 * child->border_width +
1086                     child->i_pad_x +
1087                     child->pad_x);
1088
1089       if ((child->side == GTK_SIDE_TOP) || (child->side == GTK_SIDE_BOTTOM)) 
1090         {
1091           curExpand = (cavityWidth - childWidth)/numExpand;
1092           minExpand = MIN(minExpand, curExpand); 
1093         } 
1094       else 
1095         {
1096           cavityWidth -= childWidth;
1097           if (child->options & GTK_PACK_EXPAND)
1098             numExpand++;
1099         }
1100       list = g_list_next(list);
1101     } 
1102   curExpand = cavityWidth/numExpand;
1103   if (curExpand < minExpand)
1104     minExpand = curExpand;
1105   return (minExpand < 0) ? 0 : minExpand; 
1106 }
1107
1108 static void 
1109 gtk_packer_size_allocate (GtkWidget *widget, GtkAllocation  *allocation)
1110 {
1111   GtkPacker *packer;
1112   GtkContainer *container;
1113   GtkAllocation child_allocation;
1114   GList *list;
1115   GtkPackerChild *child;
1116   gint cavityX, cavityY;
1117   gint cavityWidth, cavityHeight;
1118   gint width, height, x, y;
1119   gint frameHeight, frameWidth, frameX, frameY;
1120   gint borderX, borderY;
1121   
1122   g_return_if_fail (widget != NULL);
1123   g_return_if_fail (GTK_IS_PACKER (widget));
1124   g_return_if_fail (allocation != NULL);
1125
1126   packer = GTK_PACKER (widget);
1127   container = GTK_CONTAINER (widget);
1128
1129   x = y = 0;
1130
1131   widget->allocation = *allocation;
1132   
1133   cavityX = widget->allocation.x + container->border_width;
1134   cavityY = widget->allocation.y + container->border_width;
1135   cavityWidth = widget->allocation.width - 2 * container->border_width;
1136   cavityHeight = widget->allocation.height - 2 * container->border_width;
1137
1138   list = g_list_first (packer->children);
1139   while (list != NULL)
1140     {
1141       child = list->data;
1142       
1143       if ((child->side == GTK_SIDE_TOP) || (child->side == GTK_SIDE_BOTTOM)) 
1144         {
1145           frameWidth = cavityWidth;
1146           frameHeight = (child->widget->requisition.height +
1147                          2 * child->border_width +
1148                          child->pad_y +
1149                          child->i_pad_y);
1150           if (child->options & GTK_PACK_EXPAND)
1151             frameHeight += YExpansion(list, cavityHeight);
1152           cavityHeight -= frameHeight;
1153           if (cavityHeight < 0) 
1154             {
1155               frameHeight += cavityHeight;
1156               cavityHeight = 0;
1157             }
1158           frameX = cavityX;
1159           if (child->side == GTK_SIDE_TOP) 
1160             {
1161               frameY = cavityY;
1162               cavityY += frameHeight;
1163             } 
1164           else 
1165             {
1166               frameY = cavityY + cavityHeight;
1167             }
1168         } 
1169       else 
1170         {
1171           frameHeight = cavityHeight;
1172           frameWidth = (child->widget->requisition.width +
1173                         2 * child->border_width +
1174                         child->pad_x +
1175                         child->i_pad_x);
1176           if (child->options & GTK_PACK_EXPAND)
1177             frameWidth += XExpansion(list, cavityWidth);
1178           cavityWidth -= frameWidth;
1179           if (cavityWidth < 0) {
1180             frameWidth += cavityWidth;
1181             cavityWidth = 0;
1182           }
1183           frameY = cavityY;
1184           if (child->side == GTK_SIDE_LEFT) 
1185             {
1186               frameX = cavityX;
1187               cavityX += frameWidth;
1188             } 
1189           else 
1190             {
1191               frameX = cavityX + cavityWidth;
1192             }
1193         }
1194       
1195       borderX = child->pad_x + 2 * child->border_width;
1196       borderY = child->pad_y + 2 * child->border_width;
1197       
1198       width = (child->widget->requisition.width +
1199                2 * child->border_width +
1200                child->i_pad_x);
1201       if ((child->options & GTK_FILL_X) || (width > (frameWidth - borderX)))
1202         width = frameWidth - borderX;
1203
1204       height = (child->widget->requisition.height +
1205                 2 * child->border_width +
1206                 child->i_pad_y);
1207       if ((child->options & GTK_FILL_Y) || (height > (frameHeight - borderY)))
1208         height = frameHeight - borderY;
1209       
1210       borderX /= 2;
1211       borderY /= 2;
1212       switch (child->anchor) 
1213         {
1214         case GTK_ANCHOR_N:
1215           x = frameX + (frameWidth - width)/2;
1216           y = frameY + borderY;
1217           break;
1218         case GTK_ANCHOR_NE:
1219           x = frameX + frameWidth - width - borderX;
1220           y = frameY + borderY;
1221           break;
1222         case GTK_ANCHOR_E:
1223           x = frameX + frameWidth - width - borderX;
1224           y = frameY + (frameHeight - height)/2;
1225           break;
1226         case GTK_ANCHOR_SE:
1227           x = frameX + frameWidth - width - borderX;
1228           y = frameY + frameHeight - height - borderY;
1229           break;
1230         case GTK_ANCHOR_S:
1231           x = frameX + (frameWidth - width)/2;
1232           y = frameY + frameHeight - height - borderY;
1233           break;
1234         case GTK_ANCHOR_SW:
1235           x = frameX + borderX;
1236           y = frameY + frameHeight - height - borderY;
1237           break;
1238         case GTK_ANCHOR_W:
1239           x = frameX + borderX;
1240           y = frameY + (frameHeight - height)/2;
1241           break;
1242         case GTK_ANCHOR_NW:
1243           x = frameX + borderX;
1244           y = frameY + borderY;
1245           break;
1246         case GTK_ANCHOR_CENTER:
1247           x = frameX + (frameWidth - width)/2;
1248           y = frameY + (frameHeight - height)/2;
1249           break;
1250         default:
1251           g_warning ("gtk_packer_size_allocate(): bad anchor type: %d", child->anchor);
1252         } 
1253  
1254         if (width <= 0 || height <= 0) 
1255           {
1256             gtk_widget_unmap(child->widget);
1257           } 
1258         else 
1259           {
1260             child_allocation.x = x;
1261             child_allocation.y = y;
1262             child_allocation.width = width;
1263             child_allocation.height = height;
1264             gtk_widget_size_allocate (child->widget, &child_allocation);
1265             
1266             if (GTK_WIDGET_MAPPED (widget) &&
1267                 !(GTK_WIDGET_MAPPED (child->widget)))
1268               gtk_widget_map(child->widget); 
1269           }
1270         
1271         list = g_list_next(list);
1272     }
1273 }
1274
1275 static void
1276 gtk_packer_forall (GtkContainer *container,
1277                    gboolean      include_internals,
1278                    GtkCallback   callback,
1279                    gpointer      callback_data)
1280 {
1281   GtkPacker *packer;
1282   GtkPackerChild *child;
1283   GList *children;
1284   
1285   g_return_if_fail (container != NULL);
1286   g_return_if_fail (GTK_IS_PACKER (container));
1287   g_return_if_fail (callback != NULL);
1288   
1289   packer = GTK_PACKER (container);
1290   
1291   children = g_list_first (packer->children);
1292   while (children != NULL) 
1293     {
1294       child = children->data;
1295       children = g_list_next(children);
1296       
1297       (* callback) (child->widget, callback_data);
1298     }
1299 }
1300