]> Pileus Git - ~andy/gtk/blob - gtk/gtkpacker.c
Fixed some bugs with set_default_size.
[~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       static const 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_set_child_packing (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 ("couldn't find child `%s' amongst the packer's children", gtk_type_name (GTK_OBJECT_TYPE (child)));
746 }
747
748 void
749 gtk_packer_reorder_child (GtkPacker *packer,
750                           GtkWidget *child,
751                           gint       position)
752 {
753   GList *list;
754
755   g_return_if_fail (packer != NULL);
756   g_return_if_fail (GTK_IS_PACKER (packer));
757   g_return_if_fail (child != NULL);
758
759   list = packer->children;
760   while (list)
761     {
762       GtkPackerChild *child_info;
763
764       child_info = list->data;
765       if (child_info->widget == child)
766         break;
767
768       list = list->next;
769     }
770
771   if (list && packer->children->next)
772     {
773       GList *tmp_list;
774
775       if (list->next)
776         list->next->prev = list->prev;
777       if (list->prev)
778         list->prev->next = list->next;
779       else
780         packer->children = list->next;
781
782       tmp_list = packer->children;
783       while (position && tmp_list->next)
784         {
785           position--;
786           tmp_list = tmp_list->next;
787         }
788
789       if (position)
790         {
791           tmp_list->next = list;
792           list->prev = tmp_list;
793           list->next = NULL;
794         }
795       else
796         {
797           if (tmp_list->prev)
798             tmp_list->prev->next = list;
799           else
800             packer->children = list;
801           list->prev = tmp_list->prev;
802           tmp_list->prev = list;
803           list->next = tmp_list;
804         }
805
806       if (GTK_WIDGET_VISIBLE (child) && GTK_WIDGET_VISIBLE (packer))
807         gtk_widget_queue_resize (child);
808     }
809 }
810
811 static void 
812 gtk_packer_remove (GtkContainer *container,
813                    GtkWidget    *widget) 
814 {
815   GtkPacker *packer;
816   GtkPackerChild *child;
817   GList *children;
818   gint visible;
819   
820   g_return_if_fail (container != NULL);
821   g_return_if_fail (widget != NULL);
822   
823   packer = GTK_PACKER (container);
824   
825   children = g_list_first(packer->children);
826   while (children) 
827     {
828       child = children->data;
829       
830       if (child->widget == widget) 
831         {
832           visible = GTK_WIDGET_VISIBLE (widget);
833           gtk_widget_unparent (widget);
834           
835           packer->children = g_list_remove_link (packer->children, children);
836           g_list_free (children);
837           g_free (child);
838           
839           if (visible && GTK_WIDGET_VISIBLE (container))
840             gtk_widget_queue_resize (GTK_WIDGET (container));
841           
842           break;
843         }
844       
845       children = g_list_next(children);
846     }
847 }
848
849 static void 
850 gtk_packer_map (GtkWidget *widget)
851 {
852   GtkPacker *packer;
853   GtkPackerChild *child;
854   GList *children;
855   
856   g_return_if_fail (widget != NULL);
857   g_return_if_fail (GTK_IS_PACKER (widget));
858   
859   packer = GTK_PACKER (widget);
860   GTK_WIDGET_SET_FLAGS (packer, GTK_MAPPED);
861   
862   children = g_list_first(packer->children);
863   while (children != NULL) 
864     {
865       child = children->data;
866       children = g_list_next(children);
867       
868       if (GTK_WIDGET_VISIBLE (child->widget) &&
869           !GTK_WIDGET_MAPPED (child->widget))
870         gtk_widget_map (child->widget);
871     }
872 }
873
874 static void 
875 gtk_packer_unmap (GtkWidget *widget)
876 {
877   GtkPacker *packer;
878   GtkPackerChild *child;
879   GList *children;
880   
881   g_return_if_fail (widget != NULL);
882   g_return_if_fail (GTK_IS_PACKER (widget));
883   
884   packer = GTK_PACKER (widget);
885   GTK_WIDGET_UNSET_FLAGS (packer, GTK_MAPPED);
886   
887   children = g_list_first(packer->children);
888   while (children) 
889     {
890       child = children->data;
891       children = g_list_next(children);
892       
893       if (GTK_WIDGET_VISIBLE (child->widget) &&
894           GTK_WIDGET_MAPPED (child->widget))
895         gtk_widget_unmap (child->widget);
896     }
897 }
898
899 static void 
900 gtk_packer_draw (GtkWidget    *widget,
901                  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,
930                    GdkEventExpose *event)
931 {
932   GtkPacker *packer;
933   GtkPackerChild *child;
934   GdkEventExpose child_event;
935   GList *children;
936   
937   g_return_val_if_fail (widget != NULL, FALSE);
938   g_return_val_if_fail (GTK_IS_PACKER (widget), FALSE);
939   g_return_val_if_fail (event != NULL, FALSE);
940   
941   if (GTK_WIDGET_DRAWABLE (widget)) 
942     {
943       packer = GTK_PACKER (widget);
944       
945       child_event = *event;
946       
947       children = g_list_first(packer->children);
948       while (children) 
949         {
950           child = children->data;
951           children = g_list_next(children);
952           
953           if (GTK_WIDGET_NO_WINDOW (child->widget) &&
954               gtk_widget_intersect (child->widget, &event->area, &child_event.area))
955             gtk_widget_event (child->widget, (GdkEvent*) &child_event);
956         }
957     }   
958   
959   return FALSE;
960 }
961
962 static void 
963 gtk_packer_size_request (GtkWidget      *widget,
964                          GtkRequisition *requisition)
965 {
966   GtkPacker *packer;
967   GtkContainer *container;
968   GtkPackerChild *child;
969   GList *children;
970   gint nvis_vert_children;
971   gint nvis_horz_children;
972   gint width, height;
973   gint maxWidth, maxHeight;
974   GtkRequisition child_requisition;
975   
976   g_return_if_fail (widget != NULL);
977   g_return_if_fail (GTK_IS_PACKER (widget));
978   g_return_if_fail (requisition != NULL);
979   
980   packer = GTK_PACKER (widget);
981   container = GTK_CONTAINER (widget);
982
983   requisition->width = 0;
984   requisition->height = 0;
985   nvis_vert_children = 0;
986   nvis_horz_children = 0;
987   
988   width = height = maxWidth = maxHeight = 0;
989   
990   children = g_list_first(packer->children);
991   while (children != NULL) 
992     {
993       child = children->data;
994       
995       if (GTK_WIDGET_VISIBLE (child->widget)) 
996         {
997           GtkRequisition child_requisition;
998
999           gtk_widget_size_request (child->widget, &child_requisition);
1000           
1001           if ((child->side == GTK_SIDE_TOP) || (child->side == GTK_SIDE_BOTTOM))
1002             {
1003               maxWidth = MAX (maxWidth,
1004                               (child_requisition.width +
1005                                2 * child->border_width +
1006                                child->pad_x + child->i_pad_x +
1007                                width));
1008               height += (child_requisition.height +
1009                          2 * child->border_width +
1010                          child->pad_y + child->i_pad_y);
1011             } 
1012           else 
1013             {
1014               maxHeight = MAX (maxHeight,
1015                                (child_requisition.height +
1016                                 2 * child->border_width +
1017                                 child->pad_y + child->i_pad_y +
1018                                 height));
1019               width += (child_requisition.width +
1020                         2 * child->border_width +
1021                         child->pad_x + child->i_pad_x);
1022             }
1023         }
1024
1025       children = g_list_next(children);
1026     }
1027
1028   requisition->width = MAX (maxWidth, width) + 2 * container->border_width;
1029   requisition->height = MAX (maxHeight, height) + 2 * container->border_width;
1030 }
1031
1032 static gint
1033 YExpansion (GList *children,
1034             gint   cavityHeight)
1035 {
1036   GList *list;
1037   GtkPackerChild *child;
1038   GtkWidget *widget;
1039   gint numExpand, minExpand, curExpand;
1040   gint childHeight;
1041   
1042   minExpand = cavityHeight;
1043   numExpand = 0;
1044   
1045   list = children;
1046   while (list != NULL) 
1047     {
1048       GtkRequisition child_requisition;
1049
1050       child = list->data;
1051       widget = child->widget;
1052       gtk_widget_get_child_requisition (widget, &child_requisition);
1053
1054       childHeight = (child_requisition.height +
1055                      2 * child->border_width +
1056                      child->i_pad_y +
1057                      child->pad_y);
1058       if ((child->side == GTK_SIDE_LEFT) || (child->side == GTK_SIDE_RIGHT)) 
1059         {
1060           curExpand = (cavityHeight - childHeight)/numExpand;
1061           minExpand = MIN(minExpand, curExpand);
1062         } 
1063       else 
1064         {
1065           cavityHeight -= childHeight;
1066           if (child->options & GTK_PACK_EXPAND)
1067             numExpand++;
1068         }
1069       list = g_list_next(list);
1070     } 
1071   curExpand = cavityHeight/numExpand; 
1072   if (curExpand < minExpand)
1073     minExpand = curExpand;
1074   return (minExpand < 0) ? 0 : minExpand;
1075 }
1076
1077 static gint
1078 XExpansion (GList *children,
1079             gint   cavityWidth)
1080 {
1081   GList *list;
1082   GtkPackerChild *child;
1083   GtkWidget *widget;
1084   gint numExpand, minExpand, curExpand;
1085   gint childWidth;
1086   
1087   minExpand = cavityWidth;
1088   numExpand = 0;
1089   
1090   list = children;
1091   while (list != NULL) 
1092     {
1093       GtkRequisition child_requisition;
1094
1095       child = list->data;
1096       widget = child->widget;
1097       gtk_widget_get_child_requisition (widget, &child_requisition);
1098
1099       childWidth = (child_requisition.width +
1100                     2 * child->border_width +
1101                     child->i_pad_x +
1102                     child->pad_x);
1103
1104       if ((child->side == GTK_SIDE_TOP) || (child->side == GTK_SIDE_BOTTOM)) 
1105         {
1106           curExpand = (cavityWidth - childWidth)/numExpand;
1107           minExpand = MIN(minExpand, curExpand); 
1108         } 
1109       else 
1110         {
1111           cavityWidth -= childWidth;
1112           if (child->options & GTK_PACK_EXPAND)
1113             numExpand++;
1114         }
1115       list = g_list_next(list);
1116     } 
1117   curExpand = cavityWidth/numExpand;
1118   if (curExpand < minExpand)
1119     minExpand = curExpand;
1120   return (minExpand < 0) ? 0 : minExpand; 
1121 }
1122
1123 static void 
1124 gtk_packer_size_allocate (GtkWidget      *widget,
1125                           GtkAllocation  *allocation)
1126 {
1127   GtkPacker *packer;
1128   GtkContainer *container;
1129   GtkAllocation child_allocation;
1130   GList *list;
1131   GtkPackerChild *child;
1132   gint cavityX, cavityY;
1133   gint cavityWidth, cavityHeight;
1134   gint width, height, x, y;
1135   gint frameHeight, frameWidth, frameX, frameY;
1136   gint borderX, borderY;
1137   
1138   g_return_if_fail (widget != NULL);
1139   g_return_if_fail (GTK_IS_PACKER (widget));
1140   g_return_if_fail (allocation != NULL);
1141
1142   packer = GTK_PACKER (widget);
1143   container = GTK_CONTAINER (widget);
1144
1145   x = y = 0;
1146
1147   widget->allocation = *allocation;
1148   
1149   cavityX = widget->allocation.x + container->border_width;
1150   cavityY = widget->allocation.y + container->border_width;
1151   cavityWidth = widget->allocation.width - 2 * container->border_width;
1152   cavityHeight = widget->allocation.height - 2 * container->border_width;
1153
1154   list = g_list_first (packer->children);
1155   while (list != NULL)
1156     {
1157       GtkRequisition child_requisition;
1158
1159       child = list->data;
1160       gtk_widget_get_child_requisition (child->widget, &child_requisition);
1161       
1162       if ((child->side == GTK_SIDE_TOP) || (child->side == GTK_SIDE_BOTTOM)) 
1163         {
1164           frameWidth = cavityWidth;
1165           frameHeight = (child_requisition.height +
1166                          2 * child->border_width +
1167                          child->pad_y +
1168                          child->i_pad_y);
1169           if (child->options & GTK_PACK_EXPAND)
1170             frameHeight += YExpansion(list, cavityHeight);
1171           cavityHeight -= frameHeight;
1172           if (cavityHeight < 0) 
1173             {
1174               frameHeight += cavityHeight;
1175               cavityHeight = 0;
1176             }
1177           frameX = cavityX;
1178           if (child->side == GTK_SIDE_TOP) 
1179             {
1180               frameY = cavityY;
1181               cavityY += frameHeight;
1182             } 
1183           else 
1184             {
1185               frameY = cavityY + cavityHeight;
1186             }
1187         } 
1188       else 
1189         {
1190           frameHeight = cavityHeight;
1191           frameWidth = (child_requisition.width +
1192                         2 * child->border_width +
1193                         child->pad_x +
1194                         child->i_pad_x);
1195           if (child->options & GTK_PACK_EXPAND)
1196             frameWidth += XExpansion(list, cavityWidth);
1197           cavityWidth -= frameWidth;
1198           if (cavityWidth < 0) {
1199             frameWidth += cavityWidth;
1200             cavityWidth = 0;
1201           }
1202           frameY = cavityY;
1203           if (child->side == GTK_SIDE_LEFT) 
1204             {
1205               frameX = cavityX;
1206               cavityX += frameWidth;
1207             } 
1208           else 
1209             {
1210               frameX = cavityX + cavityWidth;
1211             }
1212         }
1213       
1214       borderX = child->pad_x + 2 * child->border_width;
1215       borderY = child->pad_y + 2 * child->border_width;
1216       
1217       width = (child_requisition.width +
1218                2 * child->border_width +
1219                child->i_pad_x);
1220       if ((child->options & GTK_FILL_X) || (width > (frameWidth - borderX)))
1221         width = frameWidth - borderX;
1222
1223       height = (child_requisition.height +
1224                 2 * child->border_width +
1225                 child->i_pad_y);
1226       if ((child->options & GTK_FILL_Y) || (height > (frameHeight - borderY)))
1227         height = frameHeight - borderY;
1228       
1229       borderX /= 2;
1230       borderY /= 2;
1231       switch (child->anchor) 
1232         {
1233         case GTK_ANCHOR_N:
1234           x = frameX + (frameWidth - width)/2;
1235           y = frameY + borderY;
1236           break;
1237         case GTK_ANCHOR_NE:
1238           x = frameX + frameWidth - width - borderX;
1239           y = frameY + borderY;
1240           break;
1241         case GTK_ANCHOR_E:
1242           x = frameX + frameWidth - width - borderX;
1243           y = frameY + (frameHeight - height)/2;
1244           break;
1245         case GTK_ANCHOR_SE:
1246           x = frameX + frameWidth - width - borderX;
1247           y = frameY + frameHeight - height - borderY;
1248           break;
1249         case GTK_ANCHOR_S:
1250           x = frameX + (frameWidth - width)/2;
1251           y = frameY + frameHeight - height - borderY;
1252           break;
1253         case GTK_ANCHOR_SW:
1254           x = frameX + borderX;
1255           y = frameY + frameHeight - height - borderY;
1256           break;
1257         case GTK_ANCHOR_W:
1258           x = frameX + borderX;
1259           y = frameY + (frameHeight - height)/2;
1260           break;
1261         case GTK_ANCHOR_NW:
1262           x = frameX + borderX;
1263           y = frameY + borderY;
1264           break;
1265         case GTK_ANCHOR_CENTER:
1266           x = frameX + (frameWidth - width)/2;
1267           y = frameY + (frameHeight - height)/2;
1268           break;
1269         default:
1270           g_warning ("gtk_packer_size_allocate(): bad anchor type: %d", child->anchor);
1271         } 
1272  
1273         if (width <= 0 || height <= 0) 
1274           {
1275             gtk_widget_unmap(child->widget);
1276           } 
1277         else 
1278           {
1279             child_allocation.x = x;
1280             child_allocation.y = y;
1281             child_allocation.width = width;
1282             child_allocation.height = height;
1283             gtk_widget_size_allocate (child->widget, &child_allocation);
1284             
1285             if (GTK_WIDGET_MAPPED (widget) &&
1286                 !(GTK_WIDGET_MAPPED (child->widget)))
1287               gtk_widget_map(child->widget); 
1288           }
1289         
1290         list = g_list_next(list);
1291     }
1292 }
1293
1294 static void
1295 gtk_packer_forall (GtkContainer *container,
1296                    gboolean      include_internals,
1297                    GtkCallback   callback,
1298                    gpointer      callback_data)
1299 {
1300   GtkPacker *packer;
1301   GtkPackerChild *child;
1302   GList *children;
1303   
1304   g_return_if_fail (container != NULL);
1305   g_return_if_fail (GTK_IS_PACKER (container));
1306   g_return_if_fail (callback != NULL);
1307   
1308   packer = GTK_PACKER (container);
1309   
1310   children = g_list_first (packer->children);
1311   while (children != NULL) 
1312     {
1313       child = children->data;
1314       children = g_list_next(children);
1315       
1316       (* callback) (child->widget, callback_data);
1317     }
1318 }
1319