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

Revision 14482, 35.4 KB checked in by ghudson, 24 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r14481, which included commits to RCS files with non-trunk default branches.
Line 
1/* GTK - The GIMP Toolkit
2 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
3 *
4 * 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 --
45This software is copyrighted by the Regents of the University of
46California, Sun Microsystems, Inc., and other parties.  The following
47terms apply to all files associated with the software unless explicitly
48disclaimed in individual files.
49
50The authors hereby grant permission to use, copy, modify, distribute,
51and license this software and its documentation for any purpose, provided
52that existing copyright notices are retained in all copies and that this
53notice is included verbatim in any distributions. No written agreement,
54license, or royalty fee is required for any of the authorized uses.
55Modifications to this software may be copyrighted by their authors
56and need not follow the licensing terms described here, provided that
57the new terms are clearly indicated on the first page of each file where
58they apply.
59
60IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY
61FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
62ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY
63DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE
64POSSIBILITY OF SUCH DAMAGE.
65
66THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES,
67INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY,
68FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT.  THIS SOFTWARE
69IS PROVIDED ON AN "AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE
70NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR
71MODIFICATIONS.
72
73GOVERNMENT USE: If you are acquiring this software on behalf of the
74U.S. government, the Government shall have only "Restricted Rights"
75in the software and related documentation as defined in the Federal
76Acquisition Regulations (FARs) in Clause 52.227.19 (c) (2).  If you
77are acquiring the software on behalf of the Department of Defense, the
78software shall be classified as "Commercial Computer Software" and the
79Government shall have only "Restricted Rights" as defined in Clause
80252.227-7013 (c) (1) of DFARs.  Notwithstanding the foregoing, the
81authors grant the U.S. Government and others acting in its behalf
82permission to use and distribute the software in accordance with the
83terms 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
100enum {
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
110enum {
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
126static void gtk_packer_class_init    (GtkPackerClass   *klass);
127static void gtk_packer_init          (GtkPacker        *packer);
128static void gtk_packer_map           (GtkWidget        *widget);
129static void gtk_packer_unmap         (GtkWidget        *widget);
130static void gtk_packer_draw          (GtkWidget        *widget,
131                                      GdkRectangle     *area);
132static gint gtk_packer_expose        (GtkWidget        *widget,
133                                      GdkEventExpose   *event);
134static void gtk_packer_size_request  (GtkWidget      *widget,
135                                      GtkRequisition *requisition);
136static void gtk_packer_size_allocate (GtkWidget      *widget,
137                                      GtkAllocation  *allocation);
138static void gtk_packer_container_add (GtkContainer   *container,
139                                      GtkWidget      *child);
140static void gtk_packer_remove        (GtkContainer   *container,
141                                      GtkWidget      *widget);
142static void gtk_packer_forall        (GtkContainer   *container,
143                                      gboolean        include_internals,
144                                      GtkCallback     callback,
145                                      gpointer        callback_data);
146static void gtk_packer_set_arg       (GtkObject      *object,
147                                      GtkArg         *arg,
148                                      guint           arg_id);
149static void gtk_packer_get_arg       (GtkObject      *object,
150                                      GtkArg         *arg,
151                                      guint           arg_id);
152static void gtk_packer_get_child_arg (GtkContainer   *container,
153                                      GtkWidget      *child,
154                                      GtkArg         *arg,
155                                      guint           arg_id);
156static void gtk_packer_set_child_arg (GtkContainer   *container,
157                                      GtkWidget      *child,
158                                      GtkArg         *arg,
159                                      guint           arg_id);
160static GtkType gtk_packer_child_type (GtkContainer   *container);
161     
162
163static GtkPackerClass *parent_class;
164
165GtkType
166gtk_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
190static void
191gtk_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
241static void
242gtk_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
283static void
284gtk_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
318static GtkType
319gtk_packer_child_type (GtkContainer   *container)
320{
321  return GTK_TYPE_WIDGET;
322}
323
324static void
325gtk_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
416static void
417gtk_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
499static void
500gtk_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
508void
509gtk_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
522GtkWidget*
523gtk_packer_new (void)
524{
525  return GTK_WIDGET (gtk_type_new (GTK_TYPE_PACKER));
526}
527
528static void
529redo_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
552void
553gtk_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}
565void
566gtk_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
582void
583gtk_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
599static void
600gtk_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
606void
607gtk_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
651void
652gtk_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
701void
702gtk_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
748void
749gtk_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
811static void
812gtk_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
849static void
850gtk_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
874static void
875gtk_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
899static void
900gtk_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
928static gint
929gtk_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
962static void
963gtk_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
1031static gint
1032YExpansion (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
1076static gint
1077XExpansion (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
1122static void
1123gtk_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
1293static void
1294gtk_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
Note: See TracBrowser for help on using the repository browser.