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