]> Pileus Git - ~andy/gtk/blob - gtk/gtkpacker.c
Ignore calls with <= width or height.
[~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  * Modified by the GTK+ Team and others 1997-1999.  See the AUTHORS
90  * file for a list of people on the GTK+ Team.  See the ChangeLog
91  * files for a list of changes.  These files are distributed with
92  * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
93  */
94
95
96
97 #include "gtkpacker.h"
98
99
100 enum {
101   ARG_0,
102   ARG_SPACING,
103   ARG_D_BORDER_WIDTH,
104   ARG_D_PAD_X,
105   ARG_D_PAD_Y,
106   ARG_D_IPAD_X,
107   ARG_D_IPAD_Y
108 };
109
110 enum {
111   CHILD_ARG_0,
112   CHILD_ARG_SIDE,
113   CHILD_ARG_ANCHOR,
114   CHILD_ARG_EXPAND,
115   CHILD_ARG_FILL_X,
116   CHILD_ARG_FILL_Y,
117   CHILD_ARG_USE_DEFAULT,
118   CHILD_ARG_BORDER_WIDTH,
119   CHILD_ARG_PAD_X,
120   CHILD_ARG_PAD_Y,
121   CHILD_ARG_I_PAD_X,
122   CHILD_ARG_I_PAD_Y,
123   CHILD_ARG_POSITION
124 };
125
126 static void gtk_packer_class_init    (GtkPackerClass   *klass);
127 static void gtk_packer_init          (GtkPacker        *packer);
128 static void gtk_packer_map           (GtkWidget        *widget);
129 static void gtk_packer_unmap         (GtkWidget        *widget);
130 static void gtk_packer_draw          (GtkWidget        *widget,
131                                       GdkRectangle     *area);
132 static gint gtk_packer_expose        (GtkWidget        *widget,
133                                       GdkEventExpose   *event);
134 static void gtk_packer_size_request  (GtkWidget      *widget,
135                                       GtkRequisition *requisition);
136 static void gtk_packer_size_allocate (GtkWidget      *widget,
137                                       GtkAllocation  *allocation);
138 static void gtk_packer_container_add (GtkContainer   *container,
139                                       GtkWidget      *child);
140 static void gtk_packer_remove        (GtkContainer   *container,
141                                       GtkWidget      *widget);
142 static void gtk_packer_forall        (GtkContainer   *container,
143                                       gboolean        include_internals,
144                                       GtkCallback     callback,
145                                       gpointer        callback_data);
146 static void gtk_packer_set_arg       (GtkObject      *object,
147                                       GtkArg         *arg,
148                                       guint           arg_id);
149 static void gtk_packer_get_arg       (GtkObject      *object,
150                                       GtkArg         *arg,
151                                       guint           arg_id);
152 static void gtk_packer_get_child_arg (GtkContainer   *container,
153                                       GtkWidget      *child,
154                                       GtkArg         *arg,
155                                       guint           arg_id);
156 static void gtk_packer_set_child_arg (GtkContainer   *container,
157                                       GtkWidget      *child,
158                                       GtkArg         *arg,
159                                       guint           arg_id);
160 static GtkType gtk_packer_child_type (GtkContainer   *container);
161      
162
163 static GtkPackerClass *parent_class;
164
165 GtkType
166 gtk_packer_get_type (void)
167 {
168   static GtkType packer_type = 0;
169
170   if (!packer_type)
171     {
172       static const GtkTypeInfo packer_info =
173       {
174         "GtkPacker",
175         sizeof (GtkPacker),
176         sizeof (GtkPackerClass),
177         (GtkClassInitFunc) gtk_packer_class_init,
178         (GtkObjectInitFunc) gtk_packer_init,
179         /* reserved_1 */ NULL,
180         /* reserved_2 */ NULL,
181         (GtkClassInitFunc) NULL,
182       };
183
184       packer_type = gtk_type_unique (GTK_TYPE_CONTAINER, &packer_info);
185     }
186   
187   return packer_type;
188 }
189
190 static void
191 gtk_packer_class_init (GtkPackerClass *klass)
192 {
193   GtkObjectClass *object_class;
194   GtkWidgetClass *widget_class;
195   GtkContainerClass *container_class;
196   
197   object_class = (GtkObjectClass*) klass;
198   widget_class = (GtkWidgetClass*) klass;
199   container_class = (GtkContainerClass*) klass;
200   parent_class = gtk_type_class (GTK_TYPE_CONTAINER);
201   
202   gtk_object_add_arg_type ("GtkPacker::spacing", GTK_TYPE_UINT, GTK_ARG_READWRITE, ARG_SPACING);
203   gtk_object_add_arg_type ("GtkPacker::default_border_width", GTK_TYPE_UINT, GTK_ARG_READWRITE, ARG_D_BORDER_WIDTH);
204   gtk_object_add_arg_type ("GtkPacker::default_pad_x", GTK_TYPE_UINT, GTK_ARG_READWRITE, ARG_D_PAD_X);
205   gtk_object_add_arg_type ("GtkPacker::default_pad_y", GTK_TYPE_UINT, GTK_ARG_READWRITE, ARG_D_PAD_Y);
206   gtk_object_add_arg_type ("GtkPacker::default_ipad_x", GTK_TYPE_UINT, GTK_ARG_READWRITE, ARG_D_IPAD_X);
207   gtk_object_add_arg_type ("GtkPacker::default_ipad_y", GTK_TYPE_UINT, GTK_ARG_READWRITE, ARG_D_IPAD_Y);
208
209   gtk_container_add_child_arg_type ("GtkPacker::side", GTK_TYPE_SIDE_TYPE, GTK_ARG_READWRITE, CHILD_ARG_SIDE);
210   gtk_container_add_child_arg_type ("GtkPacker::anchor", GTK_TYPE_ANCHOR_TYPE, GTK_ARG_READWRITE, CHILD_ARG_ANCHOR);
211   gtk_container_add_child_arg_type ("GtkPacker::expand", GTK_TYPE_BOOL, GTK_ARG_READWRITE, CHILD_ARG_EXPAND);
212   gtk_container_add_child_arg_type ("GtkPacker::fill_x", GTK_TYPE_BOOL, GTK_ARG_READWRITE, CHILD_ARG_FILL_X);
213   gtk_container_add_child_arg_type ("GtkPacker::fill_y", GTK_TYPE_BOOL, GTK_ARG_READWRITE, CHILD_ARG_FILL_Y);
214   gtk_container_add_child_arg_type ("GtkPacker::use_default", GTK_TYPE_BOOL, GTK_ARG_READWRITE, CHILD_ARG_USE_DEFAULT);
215   gtk_container_add_child_arg_type ("GtkPacker::border_width", GTK_TYPE_UINT, GTK_ARG_READWRITE, CHILD_ARG_BORDER_WIDTH);
216   gtk_container_add_child_arg_type ("GtkPacker::pad_x", GTK_TYPE_UINT, GTK_ARG_READWRITE, CHILD_ARG_PAD_X);
217   gtk_container_add_child_arg_type ("GtkPacker::pad_y", GTK_TYPE_UINT, GTK_ARG_READWRITE, CHILD_ARG_PAD_Y);
218   gtk_container_add_child_arg_type ("GtkPacker::ipad_x", GTK_TYPE_UINT, GTK_ARG_READWRITE, CHILD_ARG_I_PAD_X);
219   gtk_container_add_child_arg_type ("GtkPacker::ipad_y", GTK_TYPE_UINT, GTK_ARG_READWRITE, CHILD_ARG_I_PAD_Y);
220   gtk_container_add_child_arg_type ("GtkPacker::position", GTK_TYPE_LONG, GTK_ARG_READWRITE, CHILD_ARG_POSITION);
221
222   object_class->set_arg = gtk_packer_set_arg;
223   object_class->get_arg = gtk_packer_get_arg;
224
225   widget_class->map = gtk_packer_map;
226   widget_class->unmap = gtk_packer_unmap;
227   widget_class->draw = gtk_packer_draw;
228   widget_class->expose_event = gtk_packer_expose;
229   
230   widget_class->size_request = gtk_packer_size_request;
231   widget_class->size_allocate = gtk_packer_size_allocate;
232   
233   container_class->add = gtk_packer_container_add;
234   container_class->remove = gtk_packer_remove;
235   container_class->forall = gtk_packer_forall;
236   container_class->child_type = gtk_packer_child_type;
237   container_class->get_child_arg = gtk_packer_get_child_arg;
238   container_class->set_child_arg = gtk_packer_set_child_arg;
239 }
240
241 static void
242 gtk_packer_set_arg (GtkObject    *object,
243                     GtkArg       *arg,
244                     guint         arg_id)
245 {
246   GtkPacker *packer;
247
248   packer = GTK_PACKER (object);
249
250   switch (arg_id)
251     {
252     case ARG_SPACING:
253       gtk_packer_set_spacing (packer, GTK_VALUE_UINT (*arg));
254       break;
255     case ARG_D_BORDER_WIDTH:
256       gtk_packer_set_default_border_width (packer, GTK_VALUE_UINT (*arg));
257       break;
258     case ARG_D_PAD_X:
259       gtk_packer_set_default_pad (packer,
260                                   GTK_VALUE_UINT (*arg),
261                                   packer->default_pad_y);
262       break;
263     case ARG_D_PAD_Y:
264       gtk_packer_set_default_pad (packer,
265                                   packer->default_pad_x,
266                                   GTK_VALUE_UINT (*arg));
267       break;
268     case ARG_D_IPAD_X:
269       gtk_packer_set_default_ipad (packer,
270                                    GTK_VALUE_UINT (*arg),
271                                    packer->default_i_pad_y);
272       break;
273     case ARG_D_IPAD_Y:
274       gtk_packer_set_default_ipad (packer,
275                                    packer->default_i_pad_x,
276                                    GTK_VALUE_UINT (*arg));
277       break;
278     default:
279       break;
280     }
281 }
282
283 static void
284 gtk_packer_get_arg (GtkObject    *object,
285                     GtkArg       *arg,
286                     guint         arg_id)
287 {
288   GtkPacker *packer;
289
290   packer = GTK_PACKER (object);
291
292   switch (arg_id)
293     {
294     case ARG_SPACING:
295       GTK_VALUE_UINT (*arg) = packer->spacing;
296       break;
297     case ARG_D_BORDER_WIDTH:
298       GTK_VALUE_UINT (*arg) = packer->default_border_width;
299       break;
300     case ARG_D_PAD_X:
301       GTK_VALUE_UINT (*arg) = packer->default_pad_x;
302       break;
303     case ARG_D_PAD_Y:
304       GTK_VALUE_UINT (*arg) = packer->default_pad_y;
305       break;
306     case ARG_D_IPAD_X:
307       GTK_VALUE_UINT (*arg) = packer->default_i_pad_x;
308       break;
309     case ARG_D_IPAD_Y:
310       GTK_VALUE_UINT (*arg) = packer->default_i_pad_y;
311       break;
312     default:
313       arg->type = GTK_TYPE_INVALID;
314       break;
315     }
316 }
317
318 static GtkType
319 gtk_packer_child_type (GtkContainer   *container)
320 {
321   return GTK_TYPE_WIDGET;
322 }
323
324 static void
325 gtk_packer_set_child_arg (GtkContainer   *container,
326                           GtkWidget      *child,
327                           GtkArg         *arg,
328                           guint           arg_id)
329 {
330   GtkPacker *packer;
331   GtkPackerChild *child_info = NULL;
332   
333   packer = GTK_PACKER (container);
334
335   if (arg_id != CHILD_ARG_POSITION)
336     {
337       GList *list;
338       
339       list = packer->children;
340       while (list)
341         {
342           child_info = list->data;
343           if (child_info->widget == child)
344             break;
345           
346           list = list->next;
347         }
348       if (!list)
349         return;
350     }
351
352   switch (arg_id)
353     {
354     case CHILD_ARG_SIDE:
355       child_info->side = GTK_VALUE_ENUM (*arg);
356       break;
357     case CHILD_ARG_ANCHOR:
358       child_info->anchor = GTK_VALUE_ENUM (*arg);
359       break;
360     case CHILD_ARG_EXPAND:
361       if (GTK_VALUE_BOOL (*arg))
362         child_info->options |= GTK_PACK_EXPAND;
363       else
364         child_info->options &= ~GTK_PACK_EXPAND;
365       break;
366     case CHILD_ARG_FILL_X:
367       if (GTK_VALUE_BOOL (*arg))
368         child_info->options |= GTK_FILL_X;
369       else
370         child_info->options &= ~GTK_FILL_X;
371       break;
372     case CHILD_ARG_FILL_Y:
373       if (GTK_VALUE_BOOL (*arg))
374         child_info->options |= GTK_FILL_Y;
375       else
376         child_info->options &= ~GTK_FILL_Y;
377       break;
378     case CHILD_ARG_USE_DEFAULT:
379       child_info->use_default = (GTK_VALUE_BOOL (*arg) != 0);
380       break;
381     case CHILD_ARG_BORDER_WIDTH:
382       if (!child_info->use_default)
383         child_info->border_width = GTK_VALUE_UINT (*arg);
384       break;
385     case CHILD_ARG_PAD_X:
386       if (!child_info->use_default)
387         child_info->pad_x = GTK_VALUE_UINT (*arg);
388       break;
389     case CHILD_ARG_PAD_Y:
390       if (!child_info->use_default)
391         child_info->pad_y = GTK_VALUE_UINT (*arg);
392       break;
393     case CHILD_ARG_I_PAD_X:
394       if (!child_info->use_default)
395         child_info->i_pad_x = GTK_VALUE_UINT (*arg);
396       break;
397     case CHILD_ARG_I_PAD_Y:
398       if (!child_info->use_default)
399         child_info->i_pad_y = GTK_VALUE_UINT (*arg);
400       break;
401     case CHILD_ARG_POSITION:
402       gtk_packer_reorder_child (packer,
403                                 child,
404                                 GTK_VALUE_LONG (*arg));
405       break;
406     default:
407       break;
408     }
409
410   if (arg_id != CHILD_ARG_POSITION &&
411       GTK_WIDGET_VISIBLE (packer) &&
412       GTK_WIDGET_VISIBLE (child))
413     gtk_widget_queue_resize (child);
414 }
415
416 static void
417 gtk_packer_get_child_arg (GtkContainer   *container,
418                           GtkWidget      *child,
419                           GtkArg         *arg,
420                           guint           arg_id)
421 {
422   GtkPacker *packer;
423   GtkPackerChild *child_info = NULL;
424   GList * list;
425   
426   packer = GTK_PACKER (container);
427
428   if (arg_id != CHILD_ARG_POSITION)
429     {
430       list = packer->children;
431       while (list)
432         {
433           child_info = list->data;
434           if (child_info->widget == child)
435             break;
436           
437           list = list->next;
438         }
439       if (!list)
440         {
441           arg->type = GTK_TYPE_INVALID;
442           return;
443         }
444     }
445
446   switch (arg_id)
447     {
448     case CHILD_ARG_SIDE:
449       GTK_VALUE_ENUM (*arg) = child_info->side;
450       break;
451     case CHILD_ARG_ANCHOR:
452       GTK_VALUE_ENUM (*arg) = child_info->anchor;
453       break;
454     case CHILD_ARG_EXPAND:
455       GTK_VALUE_BOOL (*arg) = (child_info->options & GTK_PACK_EXPAND) != 0;
456       break;
457     case CHILD_ARG_FILL_X:
458       GTK_VALUE_BOOL (*arg) = (child_info->options & GTK_FILL_X) != 0;
459       break;
460     case CHILD_ARG_FILL_Y:
461       GTK_VALUE_BOOL (*arg) = (child_info->options & GTK_FILL_Y) != 0;
462       break;
463     case CHILD_ARG_USE_DEFAULT:
464       GTK_VALUE_BOOL (*arg) = child_info->use_default;
465       break;
466     case CHILD_ARG_BORDER_WIDTH:
467       GTK_VALUE_UINT (*arg) = child_info->border_width;
468       break;
469     case CHILD_ARG_PAD_X:
470       GTK_VALUE_UINT (*arg) = child_info->pad_x;
471       break;
472     case CHILD_ARG_PAD_Y:
473       GTK_VALUE_UINT (*arg) = child_info->pad_y;
474       break;
475     case CHILD_ARG_I_PAD_X:
476       GTK_VALUE_UINT (*arg) = child_info->i_pad_x;
477       break;
478     case CHILD_ARG_I_PAD_Y:
479       GTK_VALUE_UINT (*arg) = child_info->i_pad_y;
480       break;
481     case CHILD_ARG_POSITION:
482       GTK_VALUE_LONG (*arg) = 0;
483       for (list = packer->children; list; list = list->next)
484         {
485           child_info = list->data;
486           if (child_info->widget == child)
487             break;
488           GTK_VALUE_LONG (*arg)++;
489         }
490       if (!list)
491         GTK_VALUE_LONG (*arg) = -1;
492       break;
493     default:
494       arg->type = GTK_TYPE_INVALID;
495       break;
496     }
497 }
498
499 static void
500 gtk_packer_init (GtkPacker *packer)
501 {
502   GTK_WIDGET_SET_FLAGS (packer, GTK_NO_WINDOW);
503   
504   packer->children = NULL;
505   packer->spacing = 0;
506 }
507
508 void
509 gtk_packer_set_spacing (GtkPacker *packer,
510                         guint      spacing)
511 {
512   g_return_if_fail (packer != NULL);
513   g_return_if_fail (GTK_IS_PACKER (packer));
514   
515   if (spacing != packer->spacing) 
516     {
517       packer->spacing = spacing;
518       gtk_widget_queue_resize (GTK_WIDGET (packer));
519     }
520 }
521
522 GtkWidget*
523 gtk_packer_new (void)
524 {
525   return GTK_WIDGET (gtk_type_new (GTK_TYPE_PACKER));
526 }
527
528 static void
529 redo_defaults_children (GtkPacker *packer)
530 {
531   GList *list;
532   GtkPackerChild *child;
533   
534   list = g_list_first(packer->children);
535   while (list != NULL) 
536     {
537       child = list->data;
538       
539       if (child->use_default) 
540         {
541           child->border_width = packer->default_border_width;
542           child->pad_x = packer->default_pad_x;
543           child->pad_y = packer->default_pad_y;
544           child->i_pad_x = packer->default_i_pad_x;
545           child->i_pad_y = packer->default_i_pad_y;
546           gtk_widget_queue_resize (GTK_WIDGET (child->widget));
547         }
548       list = g_list_next(list);
549     }
550 }
551
552 void
553 gtk_packer_set_default_border_width (GtkPacker *packer,
554                                      guint      border)
555 {
556   g_return_if_fail (packer != NULL);
557   g_return_if_fail (GTK_IS_PACKER (packer));
558   
559   if (packer->default_border_width != border) 
560     {
561       packer->default_border_width = border;;
562       redo_defaults_children (packer);
563     }
564 }
565 void
566 gtk_packer_set_default_pad (GtkPacker *packer,
567                             guint      pad_x,
568                             guint      pad_y)
569 {
570   g_return_if_fail (packer != NULL);
571   g_return_if_fail (GTK_IS_PACKER (packer));
572   
573   if (packer->default_pad_x != pad_x ||
574       packer->default_pad_y != pad_y) 
575     {
576       packer->default_pad_x = pad_x;
577       packer->default_pad_y = pad_y;
578       redo_defaults_children (packer);
579     }
580 }
581
582 void
583 gtk_packer_set_default_ipad (GtkPacker *packer,
584                              guint      i_pad_x,
585                              guint      i_pad_y)
586 {
587   g_return_if_fail (packer != NULL);
588   g_return_if_fail (GTK_IS_PACKER (packer));
589   
590   if (packer->default_i_pad_x != i_pad_x ||
591       packer->default_i_pad_y != i_pad_y) {
592     
593     packer->default_i_pad_x = i_pad_x;
594     packer->default_i_pad_y = i_pad_y;
595     redo_defaults_children (packer);
596   }
597 }
598
599 static void 
600 gtk_packer_container_add (GtkContainer *packer, GtkWidget *child)
601 {
602   gtk_packer_add_defaults(GTK_PACKER(packer), child,
603                           GTK_SIDE_TOP, GTK_ANCHOR_CENTER, 0);
604 }
605
606 void 
607 gtk_packer_add_defaults (GtkPacker       *packer,
608                          GtkWidget       *child,
609                          GtkSideType      side,
610                          GtkAnchorType    anchor,
611                          GtkPackerOptions options)
612 {
613   GtkPackerChild *pchild;
614   
615   g_return_if_fail (packer != NULL);
616   g_return_if_fail (GTK_IS_PACKER (packer));
617   g_return_if_fail (child != NULL);
618   g_return_if_fail (GTK_IS_WIDGET (child));
619   
620   pchild = (GtkPackerChild*) g_malloc(sizeof(GtkPackerChild));
621   
622   pchild->widget = child;
623   pchild->side = side;
624   pchild->options = options;
625   pchild->anchor = anchor;
626   
627   pchild->use_default = 1;
628   
629   pchild->border_width = packer->default_border_width;
630   pchild->pad_x = packer->default_pad_x;
631   pchild->pad_y = packer->default_pad_y;
632   pchild->i_pad_x = packer->default_i_pad_x;
633   pchild->i_pad_y = packer->default_i_pad_y;
634   
635   packer->children = g_list_append(packer->children, (gpointer) pchild);
636   
637   gtk_widget_set_parent (child, GTK_WIDGET (packer));
638   
639   if (GTK_WIDGET_REALIZED (child->parent))
640     gtk_widget_realize (child);
641
642   if (GTK_WIDGET_VISIBLE (child->parent) && GTK_WIDGET_VISIBLE (child))
643     {
644       if (GTK_WIDGET_MAPPED (child->parent))
645         gtk_widget_map (child);
646
647       gtk_widget_queue_resize (child);
648     }
649 }
650
651 void 
652 gtk_packer_add (GtkPacker       *packer,
653                 GtkWidget       *child,
654                 GtkSideType      side,
655                 GtkAnchorType    anchor,
656                 GtkPackerOptions options,
657                 guint            border_width,
658                 guint            pad_x,
659                 guint            pad_y,
660                 guint            i_pad_x,
661                 guint            i_pad_y)
662 {
663   GtkPackerChild *pchild;
664   
665   g_return_if_fail (packer != NULL);
666   g_return_if_fail (GTK_IS_PACKER (packer));
667   g_return_if_fail (child != NULL);
668   g_return_if_fail (GTK_IS_WIDGET (child));
669   
670   pchild = (GtkPackerChild*) g_malloc(sizeof(GtkPackerChild));
671   
672   pchild->widget = child;
673   pchild->side = side;
674   pchild->options = options;
675   pchild->anchor = anchor;
676   
677   pchild->use_default = 0;
678   
679   pchild->border_width = border_width;
680   pchild->pad_x = pad_x;
681   pchild->pad_y = pad_y;
682   pchild->i_pad_x = i_pad_x;
683   pchild->i_pad_y = i_pad_y;
684   
685   packer->children = g_list_append(packer->children, (gpointer) pchild);
686   
687   gtk_widget_set_parent (child, GTK_WIDGET (packer));
688   
689   if (GTK_WIDGET_REALIZED (child->parent))
690     gtk_widget_realize (child);
691
692   if (GTK_WIDGET_VISIBLE (child->parent) && GTK_WIDGET_VISIBLE (child))
693     {
694       if (GTK_WIDGET_MAPPED (child->parent))
695         gtk_widget_map (child);
696
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   
975   g_return_if_fail (widget != NULL);
976   g_return_if_fail (GTK_IS_PACKER (widget));
977   g_return_if_fail (requisition != NULL);
978   
979   packer = GTK_PACKER (widget);
980   container = GTK_CONTAINER (widget);
981
982   requisition->width = 0;
983   requisition->height = 0;
984   nvis_vert_children = 0;
985   nvis_horz_children = 0;
986   
987   width = height = maxWidth = maxHeight = 0;
988   
989   children = g_list_first(packer->children);
990   while (children != NULL) 
991     {
992       child = children->data;
993       
994       if (GTK_WIDGET_VISIBLE (child->widget)) 
995         {
996           GtkRequisition child_requisition;
997
998           gtk_widget_size_request (child->widget, &child_requisition);
999           
1000           if ((child->side == GTK_SIDE_TOP) || (child->side == GTK_SIDE_BOTTOM))
1001             {
1002               maxWidth = MAX (maxWidth,
1003                               (child_requisition.width +
1004                                2 * child->border_width +
1005                                child->pad_x + child->i_pad_x +
1006                                width));
1007               height += (child_requisition.height +
1008                          2 * child->border_width +
1009                          child->pad_y + child->i_pad_y);
1010             } 
1011           else 
1012             {
1013               maxHeight = MAX (maxHeight,
1014                                (child_requisition.height +
1015                                 2 * child->border_width +
1016                                 child->pad_y + child->i_pad_y +
1017                                 height));
1018               width += (child_requisition.width +
1019                         2 * child->border_width +
1020                         child->pad_x + child->i_pad_x);
1021             }
1022         }
1023
1024       children = g_list_next(children);
1025     }
1026
1027   requisition->width = MAX (maxWidth, width) + 2 * container->border_width;
1028   requisition->height = MAX (maxHeight, height) + 2 * container->border_width;
1029 }
1030
1031 static gint
1032 YExpansion (GList *children,
1033             gint   cavityHeight)
1034 {
1035   GList *list;
1036   GtkPackerChild *child;
1037   GtkWidget *widget;
1038   gint numExpand, minExpand, curExpand;
1039   gint childHeight;
1040   
1041   minExpand = cavityHeight;
1042   numExpand = 0;
1043   
1044   list = children;
1045   while (list != NULL) 
1046     {
1047       GtkRequisition child_requisition;
1048
1049       child = list->data;
1050       widget = child->widget;
1051       gtk_widget_get_child_requisition (widget, &child_requisition);
1052
1053       childHeight = (child_requisition.height +
1054                      2 * child->border_width +
1055                      child->i_pad_y +
1056                      child->pad_y);
1057       if ((child->side == GTK_SIDE_LEFT) || (child->side == GTK_SIDE_RIGHT)) 
1058         {
1059           curExpand = (cavityHeight - childHeight)/numExpand;
1060           minExpand = MIN(minExpand, curExpand);
1061         } 
1062       else 
1063         {
1064           cavityHeight -= childHeight;
1065           if (child->options & GTK_PACK_EXPAND)
1066             numExpand++;
1067         }
1068       list = g_list_next(list);
1069     } 
1070   curExpand = cavityHeight/numExpand; 
1071   if (curExpand < minExpand)
1072     minExpand = curExpand;
1073   return (minExpand < 0) ? 0 : minExpand;
1074 }
1075
1076 static gint
1077 XExpansion (GList *children,
1078             gint   cavityWidth)
1079 {
1080   GList *list;
1081   GtkPackerChild *child;
1082   GtkWidget *widget;
1083   gint numExpand, minExpand, curExpand;
1084   gint childWidth;
1085   
1086   minExpand = cavityWidth;
1087   numExpand = 0;
1088   
1089   list = children;
1090   while (list != NULL) 
1091     {
1092       GtkRequisition child_requisition;
1093
1094       child = list->data;
1095       widget = child->widget;
1096       gtk_widget_get_child_requisition (widget, &child_requisition);
1097
1098       childWidth = (child_requisition.width +
1099                     2 * child->border_width +
1100                     child->i_pad_x +
1101                     child->pad_x);
1102
1103       if ((child->side == GTK_SIDE_TOP) || (child->side == GTK_SIDE_BOTTOM)) 
1104         {
1105           curExpand = (cavityWidth - childWidth)/numExpand;
1106           minExpand = MIN(minExpand, curExpand); 
1107         } 
1108       else 
1109         {
1110           cavityWidth -= childWidth;
1111           if (child->options & GTK_PACK_EXPAND)
1112             numExpand++;
1113         }
1114       list = g_list_next(list);
1115     } 
1116   curExpand = cavityWidth/numExpand;
1117   if (curExpand < minExpand)
1118     minExpand = curExpand;
1119   return (minExpand < 0) ? 0 : minExpand; 
1120 }
1121
1122 static void 
1123 gtk_packer_size_allocate (GtkWidget      *widget,
1124                           GtkAllocation  *allocation)
1125 {
1126   GtkPacker *packer;
1127   GtkContainer *container;
1128   GtkAllocation child_allocation;
1129   GList *list;
1130   GtkPackerChild *child;
1131   gint cavityX, cavityY;
1132   gint cavityWidth, cavityHeight;
1133   gint width, height, x, y;
1134   gint frameHeight, frameWidth, frameX, frameY;
1135   gint borderX, borderY;
1136   
1137   g_return_if_fail (widget != NULL);
1138   g_return_if_fail (GTK_IS_PACKER (widget));
1139   g_return_if_fail (allocation != NULL);
1140
1141   packer = GTK_PACKER (widget);
1142   container = GTK_CONTAINER (widget);
1143
1144   x = y = 0;
1145
1146   widget->allocation = *allocation;
1147   
1148   cavityX = widget->allocation.x + container->border_width;
1149   cavityY = widget->allocation.y + container->border_width;
1150   cavityWidth = widget->allocation.width - 2 * container->border_width;
1151   cavityHeight = widget->allocation.height - 2 * container->border_width;
1152
1153   list = g_list_first (packer->children);
1154   while (list != NULL)
1155     {
1156       GtkRequisition child_requisition;
1157
1158       child = list->data;
1159       gtk_widget_get_child_requisition (child->widget, &child_requisition);
1160       
1161       if ((child->side == GTK_SIDE_TOP) || (child->side == GTK_SIDE_BOTTOM)) 
1162         {
1163           frameWidth = cavityWidth;
1164           frameHeight = (child_requisition.height +
1165                          2 * child->border_width +
1166                          child->pad_y +
1167                          child->i_pad_y);
1168           if (child->options & GTK_PACK_EXPAND)
1169             frameHeight += YExpansion(list, cavityHeight);
1170           cavityHeight -= frameHeight;
1171           if (cavityHeight < 0) 
1172             {
1173               frameHeight += cavityHeight;
1174               cavityHeight = 0;
1175             }
1176           frameX = cavityX;
1177           if (child->side == GTK_SIDE_TOP) 
1178             {
1179               frameY = cavityY;
1180               cavityY += frameHeight;
1181             } 
1182           else 
1183             {
1184               frameY = cavityY + cavityHeight;
1185             }
1186         } 
1187       else 
1188         {
1189           frameHeight = cavityHeight;
1190           frameWidth = (child_requisition.width +
1191                         2 * child->border_width +
1192                         child->pad_x +
1193                         child->i_pad_x);
1194           if (child->options & GTK_PACK_EXPAND)
1195             frameWidth += XExpansion(list, cavityWidth);
1196           cavityWidth -= frameWidth;
1197           if (cavityWidth < 0) {
1198             frameWidth += cavityWidth;
1199             cavityWidth = 0;
1200           }
1201           frameY = cavityY;
1202           if (child->side == GTK_SIDE_LEFT) 
1203             {
1204               frameX = cavityX;
1205               cavityX += frameWidth;
1206             } 
1207           else 
1208             {
1209               frameX = cavityX + cavityWidth;
1210             }
1211         }
1212       
1213       borderX = child->pad_x + 2 * child->border_width;
1214       borderY = child->pad_y + 2 * child->border_width;
1215       
1216       width = (child_requisition.width +
1217                2 * child->border_width +
1218                child->i_pad_x);
1219       if ((child->options & GTK_FILL_X) || (width > (frameWidth - borderX)))
1220         width = frameWidth - borderX;
1221
1222       height = (child_requisition.height +
1223                 2 * child->border_width +
1224                 child->i_pad_y);
1225       if ((child->options & GTK_FILL_Y) || (height > (frameHeight - borderY)))
1226         height = frameHeight - borderY;
1227       
1228       borderX /= 2;
1229       borderY /= 2;
1230       switch (child->anchor) 
1231         {
1232         case GTK_ANCHOR_N:
1233           x = frameX + (frameWidth - width)/2;
1234           y = frameY + borderY;
1235           break;
1236         case GTK_ANCHOR_NE:
1237           x = frameX + frameWidth - width - borderX;
1238           y = frameY + borderY;
1239           break;
1240         case GTK_ANCHOR_E:
1241           x = frameX + frameWidth - width - borderX;
1242           y = frameY + (frameHeight - height)/2;
1243           break;
1244         case GTK_ANCHOR_SE:
1245           x = frameX + frameWidth - width - borderX;
1246           y = frameY + frameHeight - height - borderY;
1247           break;
1248         case GTK_ANCHOR_S:
1249           x = frameX + (frameWidth - width)/2;
1250           y = frameY + frameHeight - height - borderY;
1251           break;
1252         case GTK_ANCHOR_SW:
1253           x = frameX + borderX;
1254           y = frameY + frameHeight - height - borderY;
1255           break;
1256         case GTK_ANCHOR_W:
1257           x = frameX + borderX;
1258           y = frameY + (frameHeight - height)/2;
1259           break;
1260         case GTK_ANCHOR_NW:
1261           x = frameX + borderX;
1262           y = frameY + borderY;
1263           break;
1264         case GTK_ANCHOR_CENTER:
1265           x = frameX + (frameWidth - width)/2;
1266           y = frameY + (frameHeight - height)/2;
1267           break;
1268         default:
1269           g_warning ("gtk_packer_size_allocate(): bad anchor type: %d", child->anchor);
1270         } 
1271  
1272         if (width <= 0 || height <= 0) 
1273           {
1274             gtk_widget_unmap(child->widget);
1275           } 
1276         else 
1277           {
1278             child_allocation.x = x;
1279             child_allocation.y = y;
1280             child_allocation.width = width;
1281             child_allocation.height = height;
1282             gtk_widget_size_allocate (child->widget, &child_allocation);
1283             
1284             if (GTK_WIDGET_MAPPED (widget) &&
1285                 !(GTK_WIDGET_MAPPED (child->widget)))
1286               gtk_widget_map(child->widget); 
1287           }
1288         
1289         list = g_list_next(list);
1290     }
1291 }
1292
1293 static void
1294 gtk_packer_forall (GtkContainer *container,
1295                    gboolean      include_internals,
1296                    GtkCallback   callback,
1297                    gpointer      callback_data)
1298 {
1299   GtkPacker *packer;
1300   GtkPackerChild *child;
1301   GList *children;
1302   
1303   g_return_if_fail (container != NULL);
1304   g_return_if_fail (GTK_IS_PACKER (container));
1305   g_return_if_fail (callback != NULL);
1306   
1307   packer = GTK_PACKER (container);
1308   
1309   children = g_list_first (packer->children);
1310   while (children != NULL) 
1311     {
1312       child = children->data;
1313       children = g_list_next(children);
1314       
1315       (* callback) (child->widget, callback_data);
1316     }
1317 }
1318