/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
 *
 * The contents of this file are subject to the Netscape Public License
 * Version 1.0 (the "NPL"); you may not use this file except in
 * compliance with the NPL.  You may obtain a copy of the NPL at
 * http://www.mozilla.org/NPL/
 *
 * Software distributed under the NPL is distributed on an "AS IS" basis,
 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
 * for the specific language governing rights and limitations under the
 * NPL.
 *
 * The Initial Developer of this code under the NPL is Netscape
 * Communications Corporation.  Portions created by Netscape are
 * Copyright (C) 1998 Netscape Communications Corporation.  All Rights
 * Reserved.
 */
/*-----------------------------------------*/
/*																		*/
/* Name:		<Xfe/ToolBox.c>											*/
/* Description:	XfeToolBox widget source.								*/
/* Author:		Ramiro Estrugo <ramiro@netscape.com>					*/
/*																		*/
/*----------------------------------------------------------------------*/


#include <stdio.h>

#include <Xfe/ToolBoxP.h>
#include <Xfe/Button.h>
#include <Xfe/Tab.h>
#include <Xm/Form.h>

#define MESSAGE1 "Widget is not an XfeToolBox."
#define MESSAGE2 "XmNitemCount is a read-only resource."
#define MESSAGE3 "XfeToolBox can only have XfeToolItem childred."
#define MESSAGE4 "XmNswapThreshold is to large."
#define MESSAGE5 "XmNpositionIndex out of range for %s"
#define MESSAGE6 "XmNclosedTabs is a read-only resource."
#define MESSAGE7 "XmNopenedTabs is a read-only resource."

#define OPENED_TAB_BUTTON_NAME			"Tab"
#define CLOSED_TAB_BUTTON_NAME			"Tab"

#define DRAG_EVENTS (ButtonPressMask | ButtonReleaseMask | Button1MotionMask)

#define DIRECTION_NONE		0
#define DIRECTION_DOWN		1
#define DIRECTION_UP		-1

#define CHECK_RANGE(tp,i) \
( ( (i) >= 0 ) && ( i < (tp) -> item_count ) )

#define IS_OUR_TAB(w,child) \
(XfeIsTab(child) && (_XfeParent(child) == w))

#define _XfeSwap(_x,_y,_t)						\
{												\
	_t __tmp__ = _x;							\
												\
	_x = _y;									\
	_y = __tmp__;								\
}

/*----------------------------------------------------------------------*/
/*																		*/
/* Core class methods													*/
/*																		*/
/*----------------------------------------------------------------------*/
static void 	Initialize		(Widget,Widget,ArgList,Cardinal *);
static void 	Destroy			(Widget);
static Boolean	SetValues		(Widget,Widget,Widget,ArgList,Cardinal *);

/*----------------------------------------------------------------------*/
/*																		*/
/* Constraint Class Methods												*/
/*																		*/
/*----------------------------------------------------------------------*/
static void			ConstraintInitialize	(Widget,Widget,ArgList,Cardinal *);
static Boolean		ConstraintSetValues		(Widget,Widget,Widget,ArgList,
											 Cardinal *);

/*----------------------------------------------------------------------*/
/*																		*/
/* XfeManager class methods												*/
/*																		*/
/*----------------------------------------------------------------------*/
static void		PreferredGeometry	(Widget,Dimension *,Dimension *);
static void		MinimumGeometry	(Widget,Dimension *,Dimension *);
static void		LayoutComponents	(Widget);
static void		LayoutChildren		(Widget);
static Boolean	AcceptChild			(Widget);
static Boolean	DeleteChild			(Widget);
static Boolean	InsertChild			(Widget);

/*----------------------------------------------------------------------*/
/*																		*/
/* Misc XfeToolBox functions											*/
/*																		*/
/*----------------------------------------------------------------------*/
static Widget		CreateTab				(Widget,Boolean);
static Cardinal		ActiveItemCount			(Widget);
static Dimension	MaxItemWidth			(Widget);
static int			ItemToIndex				(Widget);
static int			TabToIndex				(Widget);
static void			CheckSwapThreshold		(Widget);


static void			DragStart				(Widget,XEvent *,int,int);
static void			DragEnd					(Widget,XEvent *,int,int);
static void			DragMotion				(Widget,XEvent *,int,int);

static Boolean		MoveItem				(Widget,Cardinal,int);
static int			MaxItemY				(Widget);
static void			SwapItems				(Widget,int,int);


static void			RaiseItem				(Widget,int);


static int			FindItemUnder			(Widget,int);
static Boolean		ItemOverItem			(Widget,int,int,Dimension);
static void			SnapItemInPlace			(Widget,int);


static int			FirstManagedIndex		(Widget);
static int			LastManagedIndex		(Widget);
static int			NextManagedIndex		(Widget,int);
static int			PreviousManagedIndex	(Widget,int);

static void			InvokeSwapCallbacks		(Widget,XEvent *,Widget,
											 Widget,int,int);
static void			InvokeCallbacks			(Widget,XtCallbackList,int,
											 XEvent *,Widget,Widget,Widget,int);
static void			UpdatePositionIndeces	(Widget);

/*----------------------------------------------------------------------*/
/*																		*/
/* Child functions														*/
/*																		*/
/*----------------------------------------------------------------------*/
static void			ChildSetDraggable		(Widget,Widget,Boolean);

/*----------------------------------------------------------------------*/
/*																		*/
/* Item functions														*/
/*																		*/
/*----------------------------------------------------------------------*/
static void			UpdateItems				(Widget);
static void			UpdatePixmaps			(Widget);

/*----------------------------------------------------------------------*/
/*																		*/
/* TaskBar callbacks													*/
/*																		*/
/*----------------------------------------------------------------------*/
static void	TabActivateCB				(Widget,XtPointer,XtPointer);
static void	TabArmCB					(Widget,XtPointer,XtPointer);
static void	TabDisarmCB					(Widget,XtPointer,XtPointer);

/*----------------------------------------------------------------------*/
/*																		*/
/* Descendant event handlers											*/
/*																		*/
/*----------------------------------------------------------------------*/
static void	DescendantEH		(Widget,XtPointer,XEvent *,Boolean *);

/*----------------------------------------------------------------------*/
/*																		*/
/* XfeToolBox Resources											        */
/*																		*/
/*----------------------------------------------------------------------*/
static XtResource resources[] = 	
{					
    /* Callback resources */     	
    { 
		XmNcloseCallback,
		XmCCallback,
		XmRCallback,
		sizeof(XtCallbackList),
		XtOffsetOf(XfeToolBoxRec , xfe_tool_box . close_callback),
		XmRImmediate, 
		(XtPointer) NULL
    },
    { 
		XmNopenCallback,
		XmCCallback,
		XmRCallback,
		sizeof(XtCallbackList),
		XtOffsetOf(XfeToolBoxRec , xfe_tool_box . open_callback),
		XmRImmediate, 
		(XtPointer) NULL
    },
    { 
		XmNdragAllowCallback,
		XmCCallback,
		XmRCallback,
		sizeof(XtCallbackList),
		XtOffsetOf(XfeToolBoxRec , xfe_tool_box . drag_allow_callback),
		XmRImmediate, 
		(XtPointer) NULL
    },
    { 
		XmNdragStartCallback,
		XmCCallback,
		XmRCallback,
		sizeof(XtCallbackList),
		XtOffsetOf(XfeToolBoxRec , xfe_tool_box . drag_start_callback),
		XmRImmediate, 
		(XtPointer) NULL
    },
    { 
		XmNdragEndCallback,
		XmCCallback,
		XmRCallback,
		sizeof(XtCallbackList),
		XtOffsetOf(XfeToolBoxRec , xfe_tool_box . drag_end_callback),
		XmRImmediate, 
		(XtPointer) NULL
    },
    { 
		XmNdragMotionCallback,
		XmCCallback,
		XmRCallback,
		sizeof(XtCallbackList),
		XtOffsetOf(XfeToolBoxRec , xfe_tool_box . drag_motion_callback),
		XmRImmediate, 
		(XtPointer) NULL
    },
    { 
		XmNnewItemCallback,
		XmCCallback,
		XmRCallback,
		sizeof(XtCallbackList),
		XtOffsetOf(XfeToolBoxRec , xfe_tool_box . new_item_callback),
		XmRImmediate, 
		(XtPointer) NULL
    },
    { 
		XmNswapCallback,
		XmCCallback,
		XmRCallback,
		sizeof(XtCallbackList),
		XtOffsetOf(XfeToolBoxRec , xfe_tool_box . swap_callback),
		XmRImmediate, 
		(XtPointer) NULL
    },
    { 
		XmNsnapCallback,
		XmCCallback,
		XmRCallback,
		sizeof(XtCallbackList),
		XtOffsetOf(XfeToolBoxRec , xfe_tool_box . snap_callback),
		XmRImmediate, 
		(XtPointer) NULL
    },


    /* Item resources */
    { 
		XmNitems,
		XmCReadOnly,
		XmRWidgetList,
		sizeof(WidgetList),
		XtOffsetOf(XfeToolBoxRec , xfe_tool_box . items),
		XmRImmediate, 
		(XtPointer) NULL
    },
    { 
		XmNitemCount,
		XmCReadOnly,
		XmRCardinal,
		sizeof(Cardinal),
		XtOffsetOf(XfeToolBoxRec , xfe_tool_box . item_count),
		XmRImmediate, 
		(XtPointer) 0
    },

    /* Tab resources */
    { 
		XmNclosedTabs,
		XmCReadOnly,
		XmRWidgetList,
		sizeof(WidgetList),
		XtOffsetOf(XfeToolBoxRec , xfe_tool_box . closed_tabs),
		XmRImmediate, 
		(XtPointer) NULL
    },
    { 
		XmNopenedTabs,
		XmCReadOnly,
		XmRWidgetList,
		sizeof(WidgetList),
		XtOffsetOf(XfeToolBoxRec , xfe_tool_box . opened_tabs),
		XmRImmediate, 
		(XtPointer) NULL
    },
    { 
		XmNtabOffset,
		XmCOffset,
		XmRHorizontalDimension,
		sizeof(Dimension),
		XtOffsetOf(XfeToolBoxRec , xfe_tool_box . tab_offset),
		XmRImmediate, 
		(XtPointer) 10
    },

    /* Spacing resources */
    { 
		XmNverticalSpacing,
		XmCSpacing,
		XmRVerticalDimension,
		sizeof(Dimension),
		XtOffsetOf(XfeToolBoxRec , xfe_tool_box . vertical_spacing),
		XmRImmediate, 
		(XtPointer) 0
    },
    { 
		XmNhorizontalSpacing,
		XmCSpacing,
		XmRHorizontalDimension,
		sizeof(Dimension),
		XtOffsetOf(XfeToolBoxRec , xfe_tool_box . horizontal_spacing),
		XmRImmediate, 
		(XtPointer) 0
    },


    /* Drag resources */
	{ 
		XmNdragCursor,
		XmCDragCursor,
		XmRCursor,
		sizeof(Widget),
		XtOffsetOf(XfeToolBoxRec , xfe_tool_box . drag_cursor),
		XmRString, 
		XfeDEFAULT_TOOL_BOX_DRAG_CURSOR
    },
	{ 
		XmNdragButton,
		XmCDragButton,
		XmRInt,
		sizeof(int),
		XtOffsetOf(XfeToolBoxRec , xfe_tool_box . drag_button),
		XmRImmediate, 
		(XtPointer) Button1
    },
	{ 
		XmNdragThreshold,
		XmCDragThreshold,
		XmRVerticalDimension,
		sizeof(Dimension),
		XtOffsetOf(XfeToolBoxRec , xfe_tool_box . drag_threshold),
		XmRImmediate, 
		(XtPointer) 10
    },

    /* Swap resources */
    { 
		XmNswapThreshold,
		XmCSwapThreshold,
		XmRVerticalDimension,
		sizeof(Dimension),
		XtOffsetOf(XfeToolBoxRec , xfe_tool_box . swap_threshold),
		XmRImmediate, 
		(XtPointer) 10
    },

	/* Pixmap resources */
    { 
		XmNbottomPixmap,
		XmCBottomPixmap,
		XmRPixmap,
		sizeof(Pixmap),
		XtOffsetOf(XfeToolBoxRec , xfe_tool_box . bottom_pixmap),
		XmRImmediate, 
		(XtPointer) XmUNSPECIFIED_PIXMAP
    },
    { 
		XmNhorizontalPixmap,
		XmCHorizontalPixmap,
		XmRPixmap,
		sizeof(Pixmap),
		XtOffsetOf(XfeToolBoxRec , xfe_tool_box . horizontal_pixmap),
		XmRImmediate, 
		(XtPointer) XmUNSPECIFIED_PIXMAP
    },
    { 
		XmNleftPixmap,
		XmCLeftPixmap,
		XmRPixmap,
		sizeof(Pixmap),
		XtOffsetOf(XfeToolBoxRec , xfe_tool_box . left_pixmap),
		XmRImmediate, 
		(XtPointer) XmUNSPECIFIED_PIXMAP
    },
    { 
		XmNrightPixmap,
		XmCRightPixmap,
		XmRPixmap,
		sizeof(Pixmap),
		XtOffsetOf(XfeToolBoxRec , xfe_tool_box . right_pixmap),
		XmRImmediate, 
		(XtPointer) XmUNSPECIFIED_PIXMAP
    },
    { 
		XmNtopPixmap,
		XmCTopPixmap,
		XmRPixmap,
		sizeof(Pixmap),
		XtOffsetOf(XfeToolBoxRec , xfe_tool_box . top_pixmap),
		XmRImmediate, 
		(XtPointer) XmUNSPECIFIED_PIXMAP
    },
    { 
		XmNverticalPixmap,
		XmCVerticalPixmap,
		XmRPixmap,
		sizeof(Pixmap),
		XtOffsetOf(XfeToolBoxRec , xfe_tool_box . vertical_pixmap),
		XmRImmediate, 
		(XtPointer) XmUNSPECIFIED_PIXMAP
    },
    { 
		XmNbottomRaisedPixmap,
		XmCBottomRaisedPixmap,
		XmRPixmap,
		sizeof(Pixmap),
		XtOffsetOf(XfeToolBoxRec , xfe_tool_box . bottom_raised_pixmap),
		XmRImmediate, 
		(XtPointer) XmUNSPECIFIED_PIXMAP
    },
    { 
		XmNhorizontalRaisedPixmap,
		XmCHorizontalRaisedPixmap,
		XmRPixmap,
		sizeof(Pixmap),
		XtOffsetOf(XfeToolBoxRec , xfe_tool_box . horizontal_raised_pixmap),
		XmRImmediate, 
		(XtPointer) XmUNSPECIFIED_PIXMAP
    },
    { 
		XmNleftRaisedPixmap,
		XmCLeftRaisedPixmap,
		XmRPixmap,
		sizeof(Pixmap),
		XtOffsetOf(XfeToolBoxRec , xfe_tool_box . left_raised_pixmap),
		XmRImmediate, 
		(XtPointer) XmUNSPECIFIED_PIXMAP
    },
    { 
		XmNrightRaisedPixmap,
		XmCRightRaisedPixmap,
		XmRPixmap,
		sizeof(Pixmap),
		XtOffsetOf(XfeToolBoxRec , xfe_tool_box . right_raised_pixmap),
		XmRImmediate, 
		(XtPointer) XmUNSPECIFIED_PIXMAP
    },
    { 
		XmNtopRaisedPixmap,
		XmCTopRaisedPixmap,
		XmRPixmap,
		sizeof(Pixmap),
		XtOffsetOf(XfeToolBoxRec , xfe_tool_box . top_raised_pixmap),
		XmRImmediate, 
		(XtPointer) XmUNSPECIFIED_PIXMAP
    },
    { 
		XmNverticalRaisedPixmap,
		XmCVerticalRaisedPixmap,
		XmRPixmap,
		sizeof(Pixmap),
		XtOffsetOf(XfeToolBoxRec , xfe_tool_box . vertical_raised_pixmap),
		XmRImmediate, 
		(XtPointer) XmUNSPECIFIED_PIXMAP
    },

	/* Force XmNusePreferredHeight to True and XmNusePreferredWidth to False */
	{
		XmNusePreferredHeight,
		XmCUsePreferredHeight,
		XmRBoolean,
		sizeof(Boolean),
		XtOffsetOf(XfeToolBoxRec , xfe_manager . use_preferred_height),
		XmRImmediate, 
		(XtPointer) True
	},
	{
		XmNusePreferredWidth,
		XmCUsePreferredWidth,
		XmRBoolean,
		sizeof(Boolean),
		XtOffsetOf(XfeToolBoxRec , xfe_manager . use_preferred_width),
		XmRImmediate, 
		(XtPointer) False
	},
};   

/*----------------------------------------------------------------------*/
/*																		*/
/* XfeBoxBar Synthetic Resources										*/
/*																		*/
/*----------------------------------------------------------------------*/
static XmSyntheticResource syn_resources[] =
{
	{ 
		XmNverticalSpacing,
		sizeof(Dimension),
		XtOffsetOf(XfeToolBoxRec , xfe_tool_box . vertical_spacing),
		_XmFromVerticalPixels,
		_XmToVerticalPixels 
	},
	{ 
		XmNhorizontalSpacing,
		sizeof(Dimension),
		XtOffsetOf(XfeToolBoxRec , xfe_tool_box . horizontal_spacing),
		_XmFromHorizontalPixels,
		_XmToHorizontalPixels 
	},
	{ 
		XmNswapThreshold,
		sizeof(Dimension),
		XtOffsetOf(XfeToolBoxRec , xfe_tool_box . swap_threshold),
		_XmFromVerticalPixels,
		_XmToVerticalPixels 
	},
	{ 
		XmNdragThreshold,
		sizeof(Dimension),
		XtOffsetOf(XfeToolBoxRec , xfe_tool_box . drag_threshold),
		_XmFromVerticalPixels,
		_XmToVerticalPixels 
	},
	{ 
 		XmNtabOffset,
		sizeof(Dimension),
		XtOffsetOf(XfeToolBoxRec , xfe_tool_box . tab_offset),
		_XmFromHorizontalPixels,
		_XmToHorizontalPixels 
	},
};

/*----------------------------------------------------------------------*/
/*																		*/
/* XfeToolBox constraint resources										*/
/*																		*/
/*----------------------------------------------------------------------*/
static XtResource constraint_resources[] = 
{
    { 
		XmNopen,
		XmCOpen,
		XmRBoolean,
		sizeof(Boolean),
		XtOffsetOf(XfeToolBoxConstraintRec , xfe_tool_box . open),
		XmRImmediate,
		(XtPointer) True
    },
};   

/*----------------------------------------------------------------------*/
/*																		*/
/* Widget Class Record Initialization                                   */
/*																		*/
/*----------------------------------------------------------------------*/
_XFE_WIDGET_CLASS_RECORD(toolbox,ToolBox) =
{
	{
		(WidgetClass) &xfeManagerClassRec,		/* superclass       	*/
		"XfeToolBox",							/* class_name       	*/
		sizeof(XfeToolBoxRec),					/* widget_size      	*/
		NULL,									/* class_initialize 	*/
		NULL,									/* class_part_initialize*/
		FALSE,                                  /* class_inited     	*/
		Initialize,                             /* initialize       	*/
		NULL,                                   /* initialize_hook  	*/
		XtInheritRealize,						/* realize          	*/
		NULL,									/* actions          	*/
		0,										/* num_actions			*/
		resources,                              /* resources        	*/
		XtNumber(resources),                    /* num_resources    	*/
		NULLQUARK,                              /* xrm_class        	*/
		TRUE,                                   /* compress_motion  	*/
		XtExposeCompressMaximal,                /* compress_exposure	*/
		TRUE,                                   /* compress_enterleave	*/
		FALSE,                                  /* visible_interest 	*/
		Destroy,								/* destroy          	*/
		XtInheritResize,                        /* resize           	*/
		XtInheritExpose,						/* expose           	*/
		SetValues,                              /* set_values       	*/
		NULL,                                   /* set_values_hook  	*/
		XtInheritSetValuesAlmost,				/* set_values_almost	*/
		NULL,									/* get_values_hook		*/
		NULL,                                   /* accexfe_focus     	*/
		XtVersion,                              /* version          	*/
		NULL,                                   /* callback_private 	*/
		XtInheritTranslations,					/* tm_table				*/
		XtInheritQueryGeometry,					/* query_geometry   	*/
		XtInheritDisplayAccelerator,            /* display accel    	*/
		NULL,                                   /* extension        	*/
	},

	/* Composite Part */
	{
		XtInheritGeometryManager,				/* geometry_manager		*/
		XtInheritChangeManaged,					/* change_managed		*/
		XtInheritInsertChild,					/* insert_child			*/
		XtInheritDeleteChild,					/* delete_child			*/
		NULL									/* extension			*/
	},

	/* Constraint Part */
	{
		constraint_resources,					/* constraint res		*/
		XtNumber(constraint_resources),			/* num constraint res	*/
		sizeof(XfeToolBoxConstraintRec),		/* constraint size     	*/
		ConstraintInitialize,					/* init proc			*/
		NULL,                                   /* destroy proc        	*/
		ConstraintSetValues,					/* set values proc		*/
		NULL,                                   /* extension           	*/
	},

	/* XmManager Part */
	{
		XtInheritTranslations,					/* tm_table				*/
		syn_resources,							/* syn resources		*/
		XtNumber(syn_resources),				/* num syn_resources	*/
		NULL,                                   /* syn_cont_resources  	*/
		0,                                      /* num_syn_cont_resource*/
		XmInheritParentProcess,                 /* parent_process      	*/
		NULL,                                   /* extension           	*/
	},

	/* XfeManager Part 	*/
	{
		XfeInheritBitGravity,					/* bit_gravity			*/
		PreferredGeometry,						/* preferred_geometry	*/
		MinimumGeometry,						/* minimum_geometry		*/
		XfeInheritUpdateRect,					/* update_rect			*/
		AcceptChild,							/* accept_child			*/
		InsertChild,							/* insert_child			*/
		DeleteChild,							/* delete_child			*/
		NULL,									/* change_managed		*/
		NULL,									/* prepare_components	*/
		LayoutComponents,						/* layout_components	*/
		LayoutChildren,							/* layout_children		*/
		NULL,									/* draw_background		*/
		XfeInheritDrawShadow,					/* draw_shadow			*/
		NULL,									/* draw_components		*/
		NULL,									/* extension          	*/
	},

	/* XfeToolBox Part */
	{
		NULL,									/* extension          	*/
	},
};

/*----------------------------------------------------------------------*/
/*																		*/
/* xfeToolBoxWidgetClass declaration.									*/
/*																		*/
/*----------------------------------------------------------------------*/
_XFE_WIDGET_CLASS(toolbox,ToolBox);

/*----------------------------------------------------------------------*/
/*																		*/
/* Core class methods													*/
/*																		*/
/*----------------------------------------------------------------------*/
static void
Initialize(Widget rw,Widget nw,ArgList args,Cardinal *nargs)
{
    XfeToolBoxPart *	tp = _XfeToolBoxPart(nw);

    /* Make sure read only resoures are not set */
    if (tp->item_count > 0)
    {
		tp->item_count = 0;

		_XfeWarning(nw,MESSAGE2);
    }

    if (tp->closed_tabs != NULL)
    {
		tp->closed_tabs = NULL;

		_XfeWarning(nw,MESSAGE7);
    }

    if (tp->opened_tabs != NULL)
    {
		tp->opened_tabs = NULL;

		_XfeWarning(nw,MESSAGE7);
    }


	tp->last_moved_item		= NULL;

	tp->dragging_tab		= False;
	tp->clicking_tab		= False;

    /* Finish of initialization */
    _XfeManagerChainInitialize(rw,nw,xfeToolBoxWidgetClass);
}
/*----------------------------------------------------------------------*/
static void
Destroy(Widget w)
{
    XfeToolBoxPart * tp = _XfeToolBoxPart(w);

	/* Free the tabs if needed */
	if (tp->closed_tabs)
	{
		XtFree((char *) tp->closed_tabs);
	}

	if (tp->opened_tabs)
	{
		XtFree((char *) tp->opened_tabs);
	}

	/* Free the items if needed */
	if (tp->items)
	{
		XtFree((char *) tp->items);
	}
}
/*----------------------------------------------------------------------*/
static Boolean
SetValues(Widget ow,Widget rw,Widget nw,ArgList args,Cardinal *nargs)
{
    XfeToolBoxPart *		np = _XfeToolBoxPart(nw);
    XfeToolBoxPart *		op = _XfeToolBoxPart(ow);
	Boolean					update_pixmaps = False;

    /* item_count */
    if (np->item_count != op->item_count)
    {
		np->item_count = op->item_count;

		_XfeWarning(nw,MESSAGE2);
    }

    /* closed_tabs */
    if (np->closed_tabs != op->closed_tabs)
    {
		np->closed_tabs = op->closed_tabs;

		_XfeWarning(nw,MESSAGE6);
    }

    /* opened_tabs */
    if (np->opened_tabs != op->opened_tabs)
    {
		np->opened_tabs = op->opened_tabs;

		_XfeWarning(nw,MESSAGE7);
    }

	/* tab_offset */
	if (np->tab_offset != op->tab_offset)
	{
		_XfemConfigFlags(nw) |= XfeConfigGLE;
	}

	/* tab_offset */
	if (np->tab_offset != op->tab_offset)
	{
		_XfemConfigFlags(nw) |= XfeConfigGLE;
	}

	/* left_pixmap */
	if ((np->left_pixmap				!= op->left_pixmap) || 
		(np->right_pixmap				!= op->right_pixmap) || 
		(np->top_pixmap					!= op->top_pixmap) || 
		(np->bottom_pixmap				!= op->bottom_pixmap) || 
		(np->vertical_pixmap			!= op->vertical_pixmap) || 
		(np->horizontal_pixmap			!= op->horizontal_pixmap) ||
		(np->left_raised_pixmap			!= op->left_raised_pixmap) || 
		(np->right_raised_pixmap		!= op->right_raised_pixmap) || 
		(np->top_raised_pixmap			!= op->top_raised_pixmap) || 
		(np->bottom_raised_pixmap		!= op->bottom_raised_pixmap) || 
		(np->vertical_raised_pixmap		!= op->vertical_raised_pixmap) || 
		(np->horizontal_raised_pixmap	!= op->horizontal_raised_pixmap))
	{
		update_pixmaps = True;
	}

	/* drag_cursor */
	if (np->drag_cursor != op->drag_cursor)
	{
		/* Update drag cursor */
	}

	/* swap_threshold */
	if (np->swap_threshold != op->swap_threshold)
	{
		/* Make sure the new swap threshold is ok */
		CheckSwapThreshold(nw);
	}

	/* Update pixmaps if needed */
	if (update_pixmaps)
	{
		UpdatePixmaps(nw);
	}

    return _XfeManagerChainSetValues(ow,rw,nw,xfeToolBoxWidgetClass);
}
/*----------------------------------------------------------------------*/

/*----------------------------------------------------------------------*/
/*																		*/
/* Constraint Class Methods												*/
/*																		*/
/*----------------------------------------------------------------------*/
static void
ConstraintInitialize(Widget rc,Widget nc,ArgList args,Cardinal *nargs)
{
/* 	Widget						w = XtParent(nc); */

/* 	printf("ConstraintInitialize(%s) for %s\n",XtName(w),XtName(nc)); */

/* 	Widget						w = XtParent(nc); */
/*	XfeManagerConstraintPart *	cp = _XfeManagerConstraintPart(nc);*/


	/* Finish constraint initialization */
	_XfeConstraintChainInitialize(rc,nc,xfeToolBoxWidgetClass);
}
/*----------------------------------------------------------------------*/
static Boolean
ConstraintSetValues(Widget oc,Widget rc,Widget nc,ArgList args,Cardinal *nargs)
{
	Widget						w = XtParent(nc);
    XfeToolBoxPart *			tp = _XfeToolBoxPart(w);
 	XfeToolBoxConstraintPart *	ncp = _XfeToolBoxConstraintPart(nc);
 	XfeToolBoxConstraintPart *	ocp = _XfeToolBoxConstraintPart(oc);

	/* position_index */
	if (_XfeManagerPositionIndex(nc) != _XfeManagerPositionIndex(oc))
	{
		/* Make sure the new position index is within range */
		if ((_XfeManagerPositionIndex(nc) < 0) || 
			(_XfeManagerPositionIndex(nc) >= tp->item_count))
		{
			_XfeManagerPositionIndex(nc) = _XfeManagerPositionIndex(oc);

			_XfeArgWarning(w,MESSAGE5,XtName(nc));
		}
		else
		{
			/* Swap the items */
			SwapItems(w,
					  _XfeManagerPositionIndex(nc),
					  _XfeManagerPositionIndex(oc));


/* 			UpdatePositionIndeces(w); */
			
 			_XfemConfigFlags(w) |= XfeConfigLayout;
		}
	}

	/* open */
	if (ncp->open != ocp->open)
	{
/*  		printf("%s,%s: change in open\n",XtName(nc),XtName(w)); */

		_XfemConfigFlags(w) |= XfeConfigGLE;
	}

	/* Finish constraint set values */
	return _XfeConstraintChainSetValues(oc,rc,nc,xfeToolBoxWidgetClass);
}
/*----------------------------------------------------------------------*/

 
/*----------------------------------------------------------------------*/
/*																		*/
/* XfeManager class methods												*/
/*																		*/
/*----------------------------------------------------------------------*/
static void
PreferredGeometry(Widget w,Dimension * width,Dimension * height)
{
	XfeToolBoxPart *		tp = _XfeToolBoxPart(w);
	Dimension				total_tab_width = 0;
	Dimension				total_tab_height = 0;
	Cardinal				i;

	*width  = _XfemOffsetLeft(w) + _XfemOffsetRight(w) + MaxItemWidth(w);
	*height = _XfemOffsetTop(w)  + _XfemOffsetBottom(w);

	for (i = 0; i < tp->item_count; i++)
	{
		/* Shown */
		if (_XfeChildIsShown(tp->items[i]))
		{
			/* Open */
			if (_XfeToolBoxChildOpen(tp->items[i]))
			{
				*height += (_XfeHeight(tp->items[i]) + tp->vertical_spacing);
			}
			/* Closed */
			else
			{
				total_tab_width += (_XfeHeight(tp->items[i]) + 
									tp->horizontal_spacing);

				total_tab_height = _XfePreferredHeight(tp->closed_tabs[i]);
			}
		}
	}

	*height += total_tab_height;

	/* Make sure the tool box is at least wide enough to hold the tabs */
	if (*width < total_tab_width)
	{
		*width = total_tab_width;
	}
}
/*----------------------------------------------------------------------*/
static void
MinimumGeometry(Widget w,Dimension * width,Dimension * height)
{
/* 	XfeToolBoxPart *		tp = _XfeToolBoxPart(w); */

	*width  = _XfemOffsetLeft(w) + _XfemOffsetRight(w);
	*height = _XfemOffsetTop(w) + _XfemOffsetBottom(w);
}
/*----------------------------------------------------------------------*/
static void
LayoutComponents(Widget w)
{
    XfeToolBoxPart *	tp = _XfeToolBoxPart(w);
	Cardinal			i;
	int					x = _XfemRectX(w);
	int					y = _XfemRectY(w);

/* 	if ((_XfeWidth(w) <= 10) || (_XfeHeight(w) <= 10)) */
/* 	{ */
/* 		return; */
/* 	} */

/* 	printf("LayoutComponents(%s)\n",XtName(w)); */

	for (i = 0; i < tp->item_count; i++)
	{
		/* Item is managed */
		if (_XfeChildIsShown(tp->items[i]))
		{
			/* Open */
			if (_XfeToolBoxChildOpen(tp->items[i]))
			{
				_XfeConfigureWidget(tp->opened_tabs[i],
									
									_XfemRectX(w),
									
									y,

									_XfePreferredWidth(tp->opened_tabs[i]),
									
									_XfeHeight(tp->items[i]));
				
				y += (_XfeHeight(tp->items[i]) + tp->vertical_spacing);

				_XfeMoveWidget(tp->closed_tabs[i],-1000,-1000);
			}
			/* Closed */
			else
			{
				Dimension width = _XfeHeight(tp->items[i]);
				
				_XfeConfigureWidget(tp->closed_tabs[i],
									
									x,
									
									_XfeHeight(w) - 
									_XfemOffsetBottom(w) -
									_XfePreferredHeight(tp->closed_tabs[i]),
									
									width,
								
									_XfePreferredHeight(tp->closed_tabs[i]));
				
				x += width;

				_XfeMoveWidget(tp->opened_tabs[i],-1000,-1000);
			}
		}
		/* Item is unmanaged */
		else
		{
			_XfeMoveWidget(tp->closed_tabs[i],-1000,-1000);
			_XfeMoveWidget(tp->opened_tabs[i],-1000,-1000);
		}
	}
}
/*----------------------------------------------------------------------*/
static void
LayoutChildren(Widget w)
{
    XfeToolBoxPart *		tp = _XfeToolBoxPart(w);
	Cardinal				i;
	int						y = _XfemRectY(w);

	for (i = 0; i < tp->item_count; i++)
	{
		Widget item = tp->items[i];

		if (_XfeIsAlive(item))
		{
			/* Item is managed */
			if (_XfeChildIsShown(item))
			{
				/* Open */
				if (_XfeToolBoxChildOpen(tp->items[i]))
				{
					_XfeConfigureWidget(item,
										
										_XfemRectX(w) + 
										_XfePreferredWidth(tp->opened_tabs[i]),
										
										y,
										
										_XfemRectWidth(w) - 
										_XfePreferredWidth(tp->opened_tabs[i]),
										
										_XfeHeight(item));
						   
					y += (_XfeHeight(item) + tp->vertical_spacing);

					XtVaSetValues(item,XmNmappedWhenManaged,True,NULL);
				}
				/* Closed */
				else
				{
					XtVaSetValues(item,XmNmappedWhenManaged,False,NULL);
				}
			}
		}
	}
}
/*----------------------------------------------------------------------*/
static Boolean
AcceptChild(Widget child)
{
	return True;
}
/*----------------------------------------------------------------------*/
static Boolean
InsertChild(Widget child)
{
	Widget					w = XtParent(child);
	XfeToolBoxPart *		tp = _XfeToolBoxPart(w);
	Widget					opened_tab;
	Widget					closed_tab;
	Cardinal				index;

/*  	printf("InsertChild(%s) for %s\n",XtName(w),XtName(child)); */

	/* Increase the item count */
	tp->item_count++;

	/* The new tab's index */
	index = tp->item_count - 1;

	/* For every tool item, we need 2 tab buttoms: (1 opened & 1 closed) */
	closed_tab = CreateTab(w,False);
	opened_tab = CreateTab(w,True);

	/* Add callbacks to tabs */
	XtAddCallback(closed_tab,XmNactivateCallback,TabActivateCB,NULL);
	XtAddCallback(closed_tab,XmNarmCallback,TabArmCB,NULL);
	XtAddCallback(closed_tab,XmNdisarmCallback,TabDisarmCB,NULL);

	XtAddCallback(opened_tab,XmNactivateCallback,TabActivateCB,NULL);
	XtAddCallback(opened_tab,XmNarmCallback,TabArmCB,NULL);
	XtAddCallback(opened_tab,XmNdisarmCallback,TabDisarmCB,NULL);

	/* Allocate more space for the new tabs */
	tp->closed_tabs = (WidgetList) XtRealloc((char *) tp->closed_tabs,
											 sizeof(Widget) * tp->item_count);
	
	tp->opened_tabs = (WidgetList) XtRealloc((char *) tp->opened_tabs,
											 sizeof(Widget) * tp->item_count);
	
	/* Place the new tabs in the tab lists */
	tp->closed_tabs[index] = closed_tab;
	tp->opened_tabs[index] = opened_tab;
	
	/* Allocate more space for the new item */
	tp->items = (WidgetList) XtRealloc((char *) tp->items,
									   sizeof(Widget) * tp->item_count);

	/* Place the new tab in the tab tab list */
	tp->items[index] = child;

	/* Add item event handlers */
	ChildSetDraggable(w,child,True);

	/* Make sure the swap threshold is ok */
	CheckSwapThreshold(w);

	/* Update the position_index contraint member of the items */
	UpdatePositionIndeces(w);

	/* Invoke new item callbacks */
	InvokeCallbacks(w,
					tp->new_item_callback,
					XmCR_TOOL_BOX_NEW_ITEM,
					NULL,
					child,
					closed_tab,
					opened_tab,
					index);

	/* Do layout only of the new child is managed */
	return XtIsManaged(child);
}
/*----------------------------------------------------------------------*/
static Boolean
DeleteChild(Widget child)
{
	Widget					w = XtParent(child);
	XfeToolBoxPart *		tp = _XfeToolBoxPart(w);
	int						index = ItemToIndex(child);

	assert( CHECK_RANGE(tp,index) );

	/* Remove the corresponding tabs */
	XtDestroyWidget(tp->closed_tabs[index]);
	XtDestroyWidget(tp->opened_tabs[index]);

	/* Mark the item and tab NULL */
	tp->items[index]		= NULL;
	tp->closed_tabs[index]  = NULL;
	tp->opened_tabs[index]  = NULL;

	/* Update the item and tab lists */
	UpdateItems(w);

	/* Decrease the item count */
	tp->item_count++;

	return XtIsManaged(child);
}
/*----------------------------------------------------------------------*/

/*----------------------------------------------------------------------*/
/*																		*/
/* Misc XfeToolBox functions											*/
/*																		*/
/*----------------------------------------------------------------------*/
static Widget
CreateTab(Widget w,Boolean opened)
{
    XfeToolBoxPart *	tp = _XfeToolBoxPart(w);
	Widget				tab;
	char				name_buf[20];
	Arg					av[10];
	Cardinal			ac = 0;

	XtSetArg(av[ac],XmNprivateComponent,		True); ac++;

	/* Opened - vertical */
	if (opened)
	{
		sprintf(name_buf,"%s%d",OPENED_TAB_BUTTON_NAME,tp->item_count - 1);

		XtSetArg(av[ac],XmNorientation,				XmVERTICAL); ac++;
		
		XtSetArg(av[ac],XmNtopPixmap,				tp->top_pixmap); ac++;
		XtSetArg(av[ac],XmNtopRaisedPixmap,			tp->top_raised_pixmap); ac++;

		XtSetArg(av[ac],XmNbottomPixmap,			tp->bottom_pixmap); ac++;
		XtSetArg(av[ac],XmNbottomRaisedPixmap,		tp->bottom_raised_pixmap); ac++;

		XtSetArg(av[ac],XmNverticalPixmap,			tp->vertical_pixmap); ac++;
		XtSetArg(av[ac],XmNverticalRaisedPixmap,	tp->vertical_raised_pixmap); ac++;
	}
	/* Closed - horizontal */
	else
	{
		sprintf(name_buf,"%s%d",CLOSED_TAB_BUTTON_NAME,tp->item_count - 1);

		XtSetArg(av[ac],XmNorientation,				XmHORIZONTAL); ac++;

		XtSetArg(av[ac],XmNleftPixmap,				tp->left_pixmap); ac++;
		XtSetArg(av[ac],XmNleftRaisedPixmap,		tp->left_raised_pixmap); ac++;

		XtSetArg(av[ac],XmNrightPixmap,				tp->right_pixmap); ac++;
		XtSetArg(av[ac],XmNrightRaisedPixmap,		tp->right_raised_pixmap); ac++;

		XtSetArg(av[ac],XmNhorizontalPixmap,		tp->horizontal_pixmap); ac++;
		XtSetArg(av[ac],XmNhorizontalRaisedPixmap,	tp->horizontal_raised_pixmap); ac++;
	}

	tab = XtCreateWidget(name_buf,xfeTabWidgetClass,w,av,ac);

	/* Allow the only the opened tab to drag the item */
	if (opened)
	{
		ChildSetDraggable(w,tab,True);
	}

	XtManageChild(tab);

	return tab;
}
/*----------------------------------------------------------------------*/
static Cardinal
ActiveItemCount(Widget w)
{
    XfeToolBoxPart *		tp = _XfeToolBoxPart(w);
	Cardinal				managed_item_count = 0;
	Cardinal				i;

	for (i = 0; i < tp->item_count; i++)
	{
		Widget child = tp->items[i];

		/* Shown and open */
		if (_XfeChildIsShown(child) && _XfeToolBoxChildOpen(tp->items[i]))
		{
			managed_item_count++;
		}
	}

	return managed_item_count;
}
/*----------------------------------------------------------------------*/
static Dimension
MaxItemWidth(Widget w)
{
	XfeToolBoxPart *		tp = _XfeToolBoxPart(w);
	Dimension				max_item_width = 0;
	Cardinal				i;
	
	for (i = 0; i < tp->item_count; i++)
	{
		/* Shown */
		if (_XfeChildIsShown(tp->items[i]))
		{
			if (_XfeWidth(tp->items[i]) > max_item_width)
			{
				max_item_width = _XfeWidth(tp->items[i]);
			}
		}
	}

	return max_item_width;
}
/*----------------------------------------------------------------------*/

/*----------------------------------------------------------------------*/
/*																		*/
/* Tab callbacks														*/
/*																		*/
/*----------------------------------------------------------------------*/
static void
TabActivateCB(Widget button,XtPointer client_data,XtPointer call_data)
{
    Widget					w = XtParent(button);
	XfeToolBoxPart *		tp = _XfeToolBoxPart(w);
	int						index = TabToIndex(button);

	assert( CHECK_RANGE(tp,index) );

/* 	printf("TabActivateCB(%s = %d)\n",XtName(tp->items[index]),index); */

	/* Make sure that this callback was not the result of a drag */
	if (tp->dragging_tab)
	{
		tp->dragging_tab = False;

		return;
	}

	XfeToolBoxItemToggleOpen(w,tp->items[index]);

	/* Invoke open callbacks */
	if (_XfeToolBoxChildOpen(tp->items[index]))
	{
/* 		printf("Open(%s = %d)\n",XtName(tp->items[index]),index); */
		InvokeCallbacks(w,
						tp->open_callback,
						XmCR_TOOL_BOX_OPEN,
						NULL,
						tp->items[index],
						tp->closed_tabs[index],
						tp->opened_tabs[index],
						index);
	}
	/* Invoke close callbacks */
	else
	{
/* 		printf("Close(%s = %d)\n",XtName(tp->items[index]),index); */
		InvokeCallbacks(w,
						tp->close_callback,
						XmCR_TOOL_BOX_CLOSE,
						NULL,
						tp->items[index],
						tp->closed_tabs[index],
						tp->opened_tabs[index],
						index);
	}
}
/*----------------------------------------------------------------------*/
static void
TabArmCB(Widget button,XtPointer client_data,XtPointer call_data)
{
    Widget					w = XtParent(button);
	XfeToolBoxPart *		tp = _XfeToolBoxPart(w);

/*  	printf("TabArmCB(%s)\n",XtName(w)); */

	tp->clicking_tab = True;
}
/*----------------------------------------------------------------------*/
static void
TabDisarmCB(Widget button,XtPointer client_data,XtPointer call_data)
{
    Widget					w = XtParent(button);
	XfeToolBoxPart *		tp = _XfeToolBoxPart(w);

/*  	printf("TabDisarmCB(%s)\n",XtName(w)); */

	tp->clicking_tab = False;
}
/*----------------------------------------------------------------------*/

/*----------------------------------------------------------------------*/
/*																		*/
/* Descendant event handlers											*/
/*																		*/
/*----------------------------------------------------------------------*/
static void
DescendantEH(Widget			descendant,
			 XtPointer		client_data,
			 XEvent *		event,
			 Boolean *		cont)
{
	Widget				w = (Widget) client_data;
	XfeToolBoxPart *	tp = _XfeToolBoxPart(w);
    Widget				target = descendant;
	Widget				item = NULL;
	Position			y;

	assert( _XfeIsAlive(descendant) );
	assert( _XfeIsAlive(w) );

	/* Ignore drag request from sensitive XfeButtons */
	if (XfeIsButton(descendant) && 
		_XfeIsSensitive(descendant) && 
		!XfeIsTab(descendant))
	{
		return;
	}

	/* Find the ancestor item for the given descendant */
	if (XfeIsTab(descendant))
	{
		int index = TabToIndex(descendant);

		item = tp->items[index];
	}
	else
	{
		while (!item)
		{
			if (XfeIsToolBox(XtParent(target)))
			{
				item = target;
			}
			else
			{
				target = XtParent(target);
			}
		}
	}

	switch(event->type) 
	{
	case ButtonPress:

		if (event->xbutton.button == tp->drag_button)
		{
			y = event->xbutton.y;

			if (event->xbutton.y > _XfeHeight(w))
			{
				y -= (event->xbutton.y - _XfeHeight(w));
			}
			else if (event->xbutton.y < 0)
			{
				y -= event->xbutton.y;
			}

			DragStart(item,event,y,event->xbutton.y_root);

			/* Clear the dragging tab flag if needed */
			if (XfeIsTab(descendant))
			{
				tp->dragging_tab = False;
			}
		}

		break;

	case ButtonRelease:

		if (event->xbutton.button == tp->drag_button)
		{
			y = event->xbutton.y;
			
			if (event->xbutton.y > _XfeHeight(w))
			{
				y -= (event->xbutton.y - _XfeHeight(w));
			}
			else if (event->xbutton.y < 0)
			{
				y -= event->xbutton.y;
			}
			
			DragEnd(item,event,y,event->xbutton.y_root);
		}

		break;
		
	case MotionNotify:

		if (!(event->xmotion.state & Button1Mask))
		{
			return;
		}

		y = event->xmotion.y;
		

		if (event->xmotion.y > _XfeHeight(w))
		{
			y -= (event->xmotion.y - _XfeHeight(w));
		}
		else if (event->xmotion.y < 0)
		{
			y -= event->xmotion.y;
		}
		
		DragMotion(item,event,event->xmotion.y,event->xmotion.y_root);

		/* Set the dragging tab flag if needed */
		if (XfeIsTab(descendant))
		{
			tp->clicking_tab = False;
			tp->dragging_tab = True;
		}
		
		break;
	}


	*cont = True;
}
/*----------------------------------------------------------------------*/
static void
DragStart(Widget item,XEvent * event,int y,int root_y)
{
	Widget					w = XtParent(item);
	XfeToolBoxPart *		tp = _XfeToolBoxPart(w);
	int						index;

/* 	printf("DragStart(%s)\n",XtName(w)); */

	/* Make sure there are at least 2 items managed before dragging */
	if (ActiveItemCount(w) <= 1)
	{
		return;
	}

	index = ItemToIndex(item);

	assert( CHECK_RANGE(tp,index) );

	if (tp->drag_cursor != None)
	{
		XfeCursorDefine(w,tp->drag_cursor);
	}

	tp->dragging = True;

	tp->start_drag_y = root_y;

	tp->original_y = _XfeY(tp->items[index]);

	tp->last_y = _XfeY(tp->items[index]);

	tp->last_moved_item = NULL;

	tp->drag_direction = DIRECTION_NONE;

	/* Make sure the item being dragged is on top of other items */
	RaiseItem(w,index);
}
/*----------------------------------------------------------------------*/
static void
DragEnd(Widget item,XEvent * event,int y,int root_y)
{
	Widget					w = XtParent(item);
	XfeToolBoxPart *		tp = _XfeToolBoxPart(XtParent(item));
	int						index;

/* 	printf("DragEnd(%s)\n",XtName(w)); */

	tp->dragging = False;

	index = ItemToIndex(item);

	assert( CHECK_RANGE(tp,index) );

	if (tp->drag_cursor != None)
	{
		XfeCursorUndefine(w);
	}

	if (!tp->clicking_tab)
	{
		/* Snap the item in place */
		SnapItemInPlace(w,index);
	}

	LayoutComponents(w);
	LayoutChildren(w);
}
/*----------------------------------------------------------------------*/
static void
DragMotion(Widget item,XEvent * event,int y,int root_y)
{
	Widget					w = XtParent(item);
	XfeToolBoxPart *		tp = _XfeToolBoxPart(w);
	int						dy;
	int						index;
	int						new_y;
	int						old_drag_direction = tp->drag_direction;
	int						under_index;

/* 	printf("DragMotion(%s)\n",XtName(w)); */

	index = ItemToIndex(item);

	assert( CHECK_RANGE(tp,index) );

	/* Make sure we are dragging */
	if (!tp->dragging)
	{
		return;
	}

	/* Compute the change in position */
	dy = root_y - tp->start_drag_y;

	/* Make sure some change in y occurred before moving item */
	if (!dy)
	{
		return;
	}

	/* Compute the new item's position */
	new_y = tp->original_y + dy;

	/* Make sure the item moved only a reasonable amount to avoid holes */

	/* Check down */
	if (new_y > tp->last_y)
	{
		if ((new_y - tp->last_y) > tp->drag_threshold)
		{
			new_y = tp->last_y + tp->drag_threshold;
		}
	}
	/* Check up */
	else
	{
		if ((tp->last_y - new_y) > tp->drag_threshold)
		{
			new_y = tp->last_y - tp->drag_threshold;
		}
	}
		
	/* Make sure the new y position is within range */
	if (new_y < _XfemOffsetTop(w))
	{
		new_y = _XfemOffsetTop(w);
	}
	else if (new_y > MaxItemY(tp->items[index]))
	{
		new_y = MaxItemY(tp->items[index]);
	}

	/* Make sure the new y position is different */
	if (_XfeY(item) == new_y)
	{
		return;
	}

	/* Move the item to its new position */
	MoveItem(w,index,new_y);

	/* Compute the new drag direction */
	if (new_y > tp->last_y)
	{
		tp->drag_direction = DIRECTION_DOWN;
	}
	else
	{
		tp->drag_direction = DIRECTION_UP;
	}	

	/* Find out if an item is underneath the item */
	under_index = FindItemUnder(w,index);

	if (CHECK_RANGE(tp,under_index))
	{
		Widget		under_item = tp->items[under_index];
		Position	empty_slot_y;

		/* Make sure the item underneath was not already swapped */
		if (under_item != tp->last_moved_item)
		{
			/* Up */
			if (tp->drag_direction == DIRECTION_UP)
			{
				if (index == LastManagedIndex(w))
				{
					empty_slot_y = MaxItemY(tp->items[under_index]);
				}
				else
				{
					int next_index = NextManagedIndex(w,index);
					
					empty_slot_y = 
						_XfeY(tp->items[next_index]) - 
						_XfeHeight(tp->items[under_index]) -
						tp->vertical_spacing;
				}
			}
			/* Down */
			else
			{
				if (index == FirstManagedIndex(w))
				{
					empty_slot_y = _XfemRectY(w);
				}
				else
				{
					int prev_index = PreviousManagedIndex(w,index);

					empty_slot_y = 
						_XfeY(tp->items[prev_index]) +
						_XfeHeight(tp->items[prev_index]) +
						tp->vertical_spacing;
				}
			}

			/* Swap the item being dragged with the underneath item */
			MoveItem(w,under_index,empty_slot_y);
			
			SwapItems(w,index,under_index);
			
			tp->last_moved_item = under_item;

			/* Update the position_index contraint member of the items */
			UpdatePositionIndeces(w);

/* 			printf("Swap(%s = %d)\n",XtName(tp->items[index]),index); */

			/* Invoke the swap callbacks */
			InvokeSwapCallbacks(w,event,item,under_item,index,under_index);
		}
	}

	/* If the direction changed within a drag, rest the last moved item */
	if (old_drag_direction != tp->drag_direction)
	{
		if (_XfeIsAlive(tp->last_moved_item))
		{
			tp->last_moved_item = NULL;
		}
	}

	tp->last_y = new_y;
}
/*----------------------------------------------------------------------*/
static Boolean
MoveItem(Widget w,Cardinal index,int y)
{
	XfeToolBoxPart *		tp = _XfeToolBoxPart(w);

	if (_XfeY(tp->items[index]) != y)
	{
		/* Move the item */
		_XfeMoveWidget(tp->items[index],_XfeX(tp->items[index]),y);
		
		/* Move the item's tab button */
		_XfeMoveWidget(tp->opened_tabs[index],_XfeX(tp->opened_tabs[index]),y);

		return True;
	}

	return False;
}
/*----------------------------------------------------------------------*/
static int
MaxItemY(Widget item)
{
	Widget					w = XtParent(item);
	XfeToolBoxPart *		tp = _XfeToolBoxPart(w);
	Dimension				max_y  = _XfeHeight(w) - _XfemOffsetBottom(w);

	/* Include the closed tab button height if any are active */
	if (ActiveItemCount(w) < tp->item_count)
	{
		max_y -= _XfePreferredHeight(tp->closed_tabs[tp->item_count - 1]);
	}

	max_y -= _XfeHeight(item);

	return max_y;
}
/*----------------------------------------------------------------------*/
static void
SwapItems(Widget w,int i,int j)
{
	XfeToolBoxPart *			tp = _XfeToolBoxPart(w);
 	XfeToolBoxConstraintPart *	cpi;
 	XfeToolBoxConstraintPart *	cpj;

	assert( CHECK_RANGE(tp,i) );
	assert( CHECK_RANGE(tp,j) );

	/* Swap the item */
	_XfeSwap(tp->items[i],tp->items[j],Widget);

	/* Swap the tab buttons */
	_XfeSwap(tp->closed_tabs[i],tp->closed_tabs[j],Widget);
	_XfeSwap(tp->opened_tabs[i],tp->opened_tabs[j],Widget);

	/* Swap the item state */
	cpi = _XfeToolBoxConstraintPart(tp->items[i]);
	cpj = _XfeToolBoxConstraintPart(tp->items[j]);
	
	_XfeSwap(cpi->open,cpj->open,Boolean);
}
/*----------------------------------------------------------------------*/
static int
ItemToIndex(Widget item)
{
	XfeToolBoxPart *		tp = _XfeToolBoxPart(XtParent(item));
	Cardinal				i = 0;

	for (i = 0; i < tp->item_count; i++)
	{
		if (item == tp->items[i])
		{
			return i;
		}
	}

	return -1;
}
/*----------------------------------------------------------------------*/
static int
TabToIndex(Widget tab)
{
	XfeToolBoxPart *		tp = _XfeToolBoxPart(XtParent(tab));
	Cardinal				i = 0;

	for (i = 0; i < tp->item_count; i++)
	{
		if ((tab == tp->closed_tabs[i]) || (tab == tp->opened_tabs[i]))
		{
			return i;
		}
	}

	return -1;
}
/*----------------------------------------------------------------------*/

/*----------------------------------------------------------------------*/
/*																		*/
/* Item functions														*/
/*																		*/
/*----------------------------------------------------------------------*/
static void
UpdateItems(Widget w)
{
	XfeToolBoxPart *		tp = _XfeToolBoxPart(w);
	Cardinal				i;
	Cardinal				new_count = 0;

	/* First, count the number of items that are alive */
	for (i = 0; i < tp->item_count; i++)
	{
		if (_XfeIsAlive(tp->items[i]))
		{
			new_count++;
		}
	}

	if (!new_count)
	{
		if (tp->items)
		{
			XtFree((char *) tp->items);
		}

		if (tp->closed_tabs)
		{
			XtFree((char *) tp->closed_tabs);
		}

		if (tp->opened_tabs)
		{
			XtFree((char *) tp->opened_tabs);
		}

		tp->items		= NULL;
		tp->closed_tabs = NULL;
		tp->opened_tabs	= NULL;
		tp->item_count	= 0;
	}
	else
	{
		WidgetList	new_items = 
			(WidgetList) XtMalloc(sizeof(Widget) * new_count);

		WidgetList	new_closed_tabs  = 
			(WidgetList) XtMalloc(sizeof(Widget) * new_count);

		WidgetList	new_opened_tabs  = 
			(WidgetList) XtMalloc(sizeof(Widget) * new_count);

		Cardinal	index = 0;
		
		for (i = 0; i < tp->item_count; i++)
		{
			if (_XfeIsAlive(tp->items[i]))
			{
				new_items[index]		= tp->items[i];
				new_closed_tabs[index]	= tp->closed_tabs[i];
				new_opened_tabs[index]	= tp->opened_tabs[i];

				index++;
			}
		}

		if (tp->items)
		{
			XtFree((char *) tp->items);
		}

		if (tp->closed_tabs)
		{
			XtFree((char *) tp->closed_tabs);
		}

		if (tp->opened_tabs)
		{
			XtFree((char *) tp->opened_tabs);
		}

		tp->items		= new_items;
		tp->closed_tabs	= new_closed_tabs;
		tp->opened_tabs	= new_opened_tabs;
		tp->item_count	= new_count;
	}
}
/*----------------------------------------------------------------------*/

static int
FirstManagedIndex(Widget w)
{
	XfeToolBoxPart *		tp = _XfeToolBoxPart(w);
	Cardinal				i;

	for (i = 0; i < tp->item_count; i++)
	{
		if (XtIsManaged(tp->items[i]))
		{
			return i;
		}
	}

	return -1;
}
/*----------------------------------------------------------------------*/
static int
LastManagedIndex(Widget w)
{
	XfeToolBoxPart *		tp = _XfeToolBoxPart(w);
	Cardinal				i;

	for (i = (tp->item_count - 1); i >= 0; i--)
	{
		if (XtIsManaged(tp->items[i]))
		{
			return i;
		}
	}

	return -1;
}
/*----------------------------------------------------------------------*/
static int
NextManagedIndex(Widget w,int index)
{
	XfeToolBoxPart *		tp = _XfeToolBoxPart(w);
	Cardinal				i;

	assert( CHECK_RANGE(tp,index) );
	assert( CHECK_RANGE(tp,index + 1) );

	for (i = (index + 1); i < tp->item_count; i++)
	{
		if (XtIsManaged(tp->items[i]))
		{
			return i;
		}
	}

	return -1;
}
/*----------------------------------------------------------------------*/
static int
PreviousManagedIndex(Widget w,int index)
{
	XfeToolBoxPart *		tp = _XfeToolBoxPart(w);
	Cardinal				i;

	assert( CHECK_RANGE(tp,index) );
	assert( CHECK_RANGE(tp,index - 1) );

	for (i = (index - 1); i >= 0; i--)
	{
		if (XtIsManaged(tp->items[i]))
		{
			return i;
		}
	}

	return -1;
}
/*----------------------------------------------------------------------*/
static void
RaiseItem(Widget w,int index)
{
	XfeToolBoxPart *		tp = _XfeToolBoxPart(w);

	assert( CHECK_RANGE(tp,index) );
	assert( _XfeIsAlive(tp->items[index]) );
	assert( _XfeIsAlive(tp->opened_tabs[index]) );

	XRaiseWindow(XtDisplay(w),_XfeWindow(tp->items[index]));
	XRaiseWindow(XtDisplay(w),_XfeWindow(tp->opened_tabs[index]));
}
/*----------------------------------------------------------------------*/
static void
SnapItemInPlace(Widget w,int index)
{
	XfeToolBoxPart *		tp = _XfeToolBoxPart(w);
	int						last_managed_index;
	int						first_managed_index;
	Boolean					moved = False;

	assert( CHECK_RANGE(tp,index) );
	assert( _XfeIsAlive(tp->items[index]) );
	assert( _XfeIsAlive(tp->opened_tabs[index]) );

 	first_managed_index = FirstManagedIndex(w);
	last_managed_index = LastManagedIndex(w);

	/* Check for the first item */
	if (index == first_managed_index)
	{
		moved = MoveItem(w,index,_XfemRectY(w));
	}
	/* Check for the last item */
	else if (index == last_managed_index)
	{
		moved = MoveItem(w,index,MaxItemY(tp->items[index]));
	}
	/* Other in-between items */
	else
	{
		int next_managed_index = NextManagedIndex(w,index);
		int previous_managed_index = PreviousManagedIndex(w,index);

		assert( CHECK_RANGE(tp,previous_managed_index) );
		assert( CHECK_RANGE(tp,next_managed_index) );

		/* Check previous item */
		if (ItemOverItem(w,index,previous_managed_index,0))
		{
			moved = MoveItem(w,
							 index,
							 _XfeY(tp->items[previous_managed_index]) + 
							 _XfeHeight(tp->items[previous_managed_index]) + 
							 tp->vertical_spacing);
		}
		/* Check next item */
		/*else if (ItemOverItem(w,index,next_managed_index,0))*/
		else
		{
			moved = MoveItem(w,
							 index,
							 _XfeY(tp->items[next_managed_index]) - 
							 _XfeHeight(tp->items[index]) - 
							 tp->vertical_spacing);
		}
	}

	/* Invoke snap callbacks only if the item actually moved */
	if (moved)
	{
		InvokeCallbacks(w,
						tp->snap_callback,
						XmCR_TOOL_BOX_SNAP,
						NULL,
						tp->items[index],
						tp->closed_tabs[index],
						tp->opened_tabs[index],
						index);
	}
}
/*----------------------------------------------------------------------*/
static int
FindItemUnder(Widget w,int over_index)
{
	XfeToolBoxPart *		tp = _XfeToolBoxPart(w);
	Cardinal				i;

	assert( CHECK_RANGE(tp,over_index) );

	for (i = 0; i < tp->item_count; i++)
	{
		/* Ignore the over item */
		if (i != over_index)
		{
			if (XtIsManaged(tp->items[i]))
			{
				if (ItemOverItem(w,over_index,i,tp->swap_threshold))
				{
					return i;
				}
			}
		}
	}

	return -1;
}
/*----------------------------------------------------------------------*/
static Boolean
ItemOverItem(Widget w,int over_index,int under_index,Dimension threshold)
{
	XfeToolBoxPart *		tp = _XfeToolBoxPart(w);
	Widget					over_item;
	Widget					under_item;
	Position				over_y0;
	Position				over_y1;
	Position				under_y0;
	Position				under_y1;

	assert( CHECK_RANGE(tp,over_index) );
	assert( CHECK_RANGE(tp,under_index) );

	over_item = tp->items[over_index];
	under_item = tp->items[under_index];

	over_y0 = _XfeY(over_item);
	over_y1 = _XfeY(over_item) + _XfeHeight(over_item);

	under_y0 = _XfeY(under_item);
	under_y1 = _XfeY(under_item) + _XfeHeight(under_item);

	assert( _XfeIsAlive(over_item) );
	assert( _XfeIsAlive(under_item) );

	return (

		((over_y1 > under_y1) && (over_y0 < under_y0)) ||
		((over_y1 > (under_y0 + threshold)) && (over_y1 < under_y1)) ||
		((over_y0 > under_y0) && (over_y0 < (under_y1 - threshold))) 

		);
}
/*----------------------------------------------------------------------*/
static void
CheckSwapThreshold(Widget w)
{
	XfeToolBoxPart *		tp = _XfeToolBoxPart(w);
	Cardinal				i;

	return;

	for (i = 0; i < tp->item_count; i++)
	{
		if (tp->swap_threshold > (_XfeHeight(tp->items[i]) - 4))
		{
			tp->swap_threshold = (_XfeHeight(tp->items[i]) - 4);

			_XfeWarning(w,MESSAGE4);
		}
	}
}
/*----------------------------------------------------------------------*/
static void
UpdatePixmaps(Widget w)
{
	XfeToolBoxPart *	tp = _XfeToolBoxPart(w);
	Cardinal			i;
	Arg					oav[6];
	Cardinal			oac = 0;
	Arg					cav[6];
	Cardinal			cac = 0;

	/* Opened - vertical */
	XtSetArg(oav[oac],XmNtopPixmap,				tp->top_pixmap); oac++;
	XtSetArg(oav[oac],XmNtopRaisedPixmap,		tp->top_raised_pixmap); oac++;
	
	XtSetArg(oav[oac],XmNbottomPixmap,			tp->bottom_pixmap); oac++;
	XtSetArg(oav[oac],XmNbottomRaisedPixmap,	tp->bottom_raised_pixmap); oac++;
	
	XtSetArg(oav[oac],XmNverticalPixmap,		tp->vertical_pixmap); oac++;
	XtSetArg(oav[oac],XmNverticalRaisedPixmap,	tp->vertical_raised_pixmap); oac++;
	
	/* Closed - horizontal */
	XtSetArg(cav[cac],XmNleftPixmap,			tp->left_pixmap); cac++;
	XtSetArg(cav[cac],XmNleftRaisedPixmap,		tp->left_raised_pixmap); cac++;
	
	XtSetArg(cav[cac],XmNrightPixmap,			tp->right_pixmap); cac++;
	XtSetArg(cav[cac],XmNrightRaisedPixmap,		tp->right_raised_pixmap); cac++;
	
	XtSetArg(cav[cac],XmNhorizontalPixmap,		tp->horizontal_pixmap); cac++;
	XtSetArg(cav[cac],XmNhorizontalRaisedPixmap,tp->horizontal_raised_pixmap); cac++;

	for (i = 0; i < tp->item_count; i++)
	{
		XtSetValues(tp->opened_tabs[i],oav,oac);
		XtSetValues(tp->closed_tabs[i],cav,cac);
	}
}
/*----------------------------------------------------------------------*/
static void
InvokeSwapCallbacks(Widget		w,
					XEvent *	event,
					Widget		swapped,
					Widget		displaced,
					int			from_index,
					int			to_index)
{
	XfeToolBoxPart *	tp = _XfeToolBoxPart(w);

	if (tp->swap_callback)
	{
		XfeToolBoxSwapCallbackStruct cbs;

		cbs.reason		= XmCR_TOOL_BOX_SWAP;
		cbs.event		= event;
		cbs.swapped		= swapped;
		cbs.displaced	= displaced;
		cbs.from_index	= from_index;
		cbs.to_index	= to_index;

		/* Invoke the Callback List */
		XtCallCallbackList(w,tp->swap_callback,&cbs);
	}
}
/*----------------------------------------------------------------------*/
static void
InvokeCallbacks(Widget			w,
				XtCallbackList	list,
				int				reason,
				XEvent *		event,
				Widget			item,
				Widget			closed_tab,
				Widget			opened_tab,
				int				index)
{
	if (list)
	{
		XfeToolBoxCallbackStruct cbs;

		cbs.reason		= reason;
		cbs.event		= event;
		cbs.item		= item;
		cbs.closed_tab	= closed_tab;
		cbs.opened_tab	= opened_tab;
		cbs.index		= index;

		XFlush(XtDisplay(w));

		/* Invoke the Callback List */
		XtCallCallbackList(w,list,&cbs);
	}
}
/*----------------------------------------------------------------------*/
static void
UpdatePositionIndeces(Widget w)
{
	XfeToolBoxPart *		tp = _XfeToolBoxPart(w);
	Cardinal				i;
	Cardinal				index = 0;

	/* Update the position_index contraint resource of the items */
	for (i = 0; i < tp->item_count; i++)
	{
		if (_XfeIsAlive(tp->items[i]))
		{
			_XfeManagerPositionIndex(tp->items[i]) = index;

			index++;
		}
	}
}
/*----------------------------------------------------------------------*/

/*----------------------------------------------------------------------*/
/*																		*/
/* Child functions														*/
/*																		*/
/*----------------------------------------------------------------------*/
static void
ChildSetDraggable(Widget w,Widget child,Boolean draggable)
{
	if (_XfeIsAlive(child))
	{
		/* First remove any event handler that might have been added */
		XtRemoveEventHandler(child,DRAG_EVENTS,True,DescendantEH,w);

		/* Add the event handler if needed */
		if (draggable)
		{
			XtAddEventHandler(child,DRAG_EVENTS,True,DescendantEH,w);
		}
	}
}
/*----------------------------------------------------------------------*/

#if 0
static void
UpdatePositionIndeces(Widget w)
{
	XfeToolBoxPart *		tp = _XfeToolBoxPart(w);
	Cardinal				i;

	/* Update the position_index contraint resource of the items */
	for (i = 0; i < tp->item_count; i++)
	{
		
		assert( _XfeIsAlive(tp->items[i]) );

		_XfeManagerPositionIndex(tp->items[i]) = i;
	}


}
/*----------------------------------------------------------------------*/
#endif
/*----------------------------------------------------------------------*/
/*																		*/
/* XfeToolBox Public Methods											*/
/*																		*/
/*----------------------------------------------------------------------*/
/* extern */ Widget
XfeCreateToolBox(Widget parent,char *name,Arg *args,Cardinal count)
{
   return (XtCreateWidget(name,xfeToolBoxWidgetClass,parent,args,count));
}
/*----------------------------------------------------------------------*/

/*----------------------------------------------------------------------*/
/*																		*/
/* XfeToolBox drag descendant											*/
/*																		*/
/*----------------------------------------------------------------------*/
/* extern */ void
XfeToolBoxAddDragDescendant(Widget w,Widget descendant)
{
	assert( _XfeIsAlive(w) );
	assert( XfeIsToolBox(w) );
	assert( _XfeIsAlive(descendant) );

	ChildSetDraggable(w,descendant,True);
}
/*----------------------------------------------------------------------*/
/* extern */ extern void
XfeToolBoxRemoveDragDescendant(Widget w,Widget descendant)
{
	assert( _XfeIsAlive(w) );
	assert( XfeIsToolBox(w) );

	ChildSetDraggable(w,descendant,False);
}
/*----------------------------------------------------------------------*/

/*----------------------------------------------------------------------*/
/*																		*/
/* XfeToolBox index methods												*/
/*																		*/
/*----------------------------------------------------------------------*/
/* extern */ int
XfeToolBoxItemGetIndex(Widget w,Widget item)
{
	XfeToolBoxPart *	tp = _XfeToolBoxPart(w);
	Cardinal			i;
	
	assert( _XfeIsAlive(w) );
	assert( XfeIsToolBox(w) );
	assert( _XfeIsAlive(item) );

	for (i = 0; i < tp->item_count; i++)
	{
		if (item == tp->items[i])
		{
			return i;
		}
	}

	return -1;
}
/*----------------------------------------------------------------------*/
#if 0
/* extern */ int
XfeToolBoxTabGetIndex(Widget w,Widget tab)
{
	XfeToolBoxPart *	tp = _XfeToolBoxPart(w);
	Cardinal			i;
	
	assert( _XfeIsAlive(w) );
	assert( XfeIsToolBox(w) );
	assert( _XfeIsAlive(tab) );

	for (i = 0; i < tp->item_count; i++)
	{
		if ((tab == tp->closed_tabs[i]) || (tab == tp->opened_tabs[i]))
		{
			return i;
		}
	}

	return -1;
}
/*----------------------------------------------------------------------*/
#endif
/* extern */ Widget
XfeToolBoxItemGetByIndex(Widget w,Cardinal index)
{
	XfeToolBoxPart *	tp = _XfeToolBoxPart(w);
	
	assert( _XfeIsAlive(w) );
	assert( XfeIsToolBox(w) );

	if (index >= tp->item_count)
	{
		return NULL;
	}

	return tp->items[index];
}
/*----------------------------------------------------------------------*/
/* extern */ Widget
XfeToolBoxItemGetTab(Widget w,Widget item,Boolean opened)
{
	XfeToolBoxPart *	tp = _XfeToolBoxPart(w);
	Cardinal			i = XfeToolBoxItemGetIndex(w,item);

	if (i != -1)
	{
		return opened ? tp->opened_tabs[i] : tp->closed_tabs[i];
	}

	return NULL;
}
/*----------------------------------------------------------------------*/

/*----------------------------------------------------------------------*/
/*																		*/
/* XfeToolBox position methods											*/
/*																		*/
/*----------------------------------------------------------------------*/
/* extern */ void
XfeToolBoxItemSetPosition(Widget w,Widget item,int pos)
{
	XfeToolBoxPart *	tp = _XfeToolBoxPart(w);
	int					old_pos;
	
	assert( _XfeIsAlive(w) );
	assert( XfeIsToolBox(w) );
	assert( tp->item_count > 1 );

	if (pos == XmLAST_POSITION)
	{
		pos = tp->item_count - 1;
	}

 	assert( pos < tp->item_count );
	assert( pos >= 0 );

	if ((tp->item_count < 2) ||
		(pos < 0) || 
		(pos >= tp->item_count) || 
		(pos == _XfeManagerPositionIndex(item)))
	{
		return;
	}

	/* Last position */
	if (pos == (tp->item_count - 1))
	{
		old_pos = pos - 1;
	}
	/* Between 0 and last */
	else
	{
		old_pos = pos + 1;
	}

	SwapItems(w,pos,old_pos);

	/* Update the position_index contraint member of the items */
	UpdatePositionIndeces(w);
	
	LayoutComponents(w);
	LayoutChildren(w);

/* 	printf("Swap(%s = %d)\n",XtName(tp->items[pos]),pos); */

	/* Invoke the swap callbacks */
	InvokeSwapCallbacks(w,NULL,tp->items[pos],tp->items[old_pos],pos,old_pos);
}
/*----------------------------------------------------------------------*/
/* extern */ int
XfeToolBoxItemGetPosition(Widget w,Widget item)
{
	assert( _XfeIsAlive(w) );
	assert( XfeIsToolBox(w) );

	return _XfeManagerPositionIndex(item);
}
/*----------------------------------------------------------------------*/

/*----------------------------------------------------------------------*/
/*																		*/
/* XfeToolBox open methods												*/
/*																		*/
/*----------------------------------------------------------------------*/
/* extern */ void
XfeToolBoxItemSetOpen(Widget w,Widget item,Boolean open)
{
	XfeToolBoxPart *	tp = _XfeToolBoxPart(w);
	int					index;
	
	assert( _XfeIsAlive(w) );
	assert( XfeIsToolBox(w) );
	assert( _XfeIsAlive(item) );
	assert( tp->item_count >= 1 );

	index = ItemToIndex(item);

	assert( CHECK_RANGE(tp,index) );
	
	/* Make sure open is different */
	if (_XfeToolBoxChildOpen(tp->items[index]) == open)
	{
		return;
	}

#if 0
	printf("XtVaSetValues(%s,XmNopen,%s,NULL)\n",
		   XtName(item),
		   open ? "open" : "closed");
#endif

	XtVaSetValues(item,XmNopen,open,NULL);
}
/*----------------------------------------------------------------------*/
/* extern */ Boolean
XfeToolBoxItemGetOpen(Widget w,Widget item)
{
	assert( _XfeIsAlive(w) );
	assert( XfeIsToolBox(w) );

	return _XfeToolBoxChildOpen(item);
}
/*----------------------------------------------------------------------*/
/* extern */  void
XfeToolBoxItemToggleOpen(Widget w,Widget item)
{
	assert( _XfeIsAlive(w) );
	assert( XfeIsToolBox(w) );

	XfeToolBoxItemSetOpen(w,item,!_XfeToolBoxChildOpen(item));
}
/*----------------------------------------------------------------------*/

/*----------------------------------------------------------------------*/
/*																		*/
/* XfeToolBoxIsNeeded()													*/
/*																		*/
/*----------------------------------------------------------------------*/
/* extern */ Boolean
XfeToolBoxIsNeeded(Widget w)
{
	XfeToolBoxPart *	tp = _XfeToolBoxPart(w);
	Cardinal			i;

	assert( _XfeIsAlive(w) );
	assert( XfeIsToolBox(w) );

	if (tp->item_count)
	{
		for (i = 0; i < tp->item_count; i++)
		{
			/* If at least one child is shown, the tool box is needed */
			if (_XfeChildIsShown(tp->items[i]))
			{
				return True;
			}
		}
	}
	
	return False;
}
/*----------------------------------------------------------------------*/

/*----------------------------------------------------------------------*/
/*																		*/
/* Hackery crap which should go sway real soon							*/
/*																		*/
/*----------------------------------------------------------------------*/
static void
FormResizeEH(Widget			form,
			 XtPointer		client_data,
			 XEvent *		event,
			 Boolean *		cont)
{
	XfeToolBoxFormDoLayout(form);

	*cont = True;
}
/*----------------------------------------------------------------------*/
static void
ToolBoxTabCB(Widget w,XtPointer client_data,XtPointer call_data)
{
	XfeToolBoxFormDoLayout(XtParent(w));
}
/*----------------------------------------------------------------------*/
static void
ToolBoxChangeManagedCB(Widget w,XtPointer client_data,XtPointer call_data)
{
	XfeToolBoxFormDoLayout(XtParent(w));
}
/*----------------------------------------------------------------------*/
/* extern */ void
XfeToolBoxAddLayoutSupport(Widget form,Widget tool_box)
{
	assert( XmIsForm(form) );
	assert( XfeIsToolBox(tool_box) );
	assert( XtParent(tool_box) == form );

	XtAddEventHandler(form,
					  StructureNotifyMask,
					  True,
					  FormResizeEH,
					  (XtPointer) NULL);

	XtAddCallback(tool_box,
				  XmNopenCallback,
				  ToolBoxTabCB,
				  (XtPointer) NULL);

	XtAddCallback(tool_box,
				  XmNcloseCallback,
				  ToolBoxTabCB,
				  (XtPointer) NULL);

	XtAddCallback(tool_box,
				  XmNchangeManagedCallback,
				  ToolBoxChangeManagedCB,
				  (XtPointer) NULL);
}
/*----------------------------------------------------------------------*/
/* extern */ void
XfeToolBoxFormDoLayout(Widget form)
{
	Widget *		children;
	Cardinal		num_children;
	Widget			tool_box = NULL;
	Widget			view_area = NULL;
	Widget			above_view_area = NULL;
	Cardinal		i;

	Boolean			show_tool_box;
	Boolean			show_view_area;
	Boolean			show_above_view_area;

	/* Make sure the form is alive */
	if (!_XfeIsAlive(form))
	{
		return;
	}

	children = _XfemChildren(form);
	num_children = _XfemNumChildren(form);

	/* Make sure there is something to layout */
	if (!children || !num_children)
	{
		return;
	}

	assert( num_children >= 1 );
	assert( num_children <= 3 );

	tool_box = XfeDescendantFindByClass(form,
										xfeToolBoxWidgetClass,
										XfeFIND_ALIVE,
										False);

	/* Find the view area and above view area */
	for(i = 0; i < num_children; i++)
	{
		if (tool_box && (children[i] != tool_box))
		{
			if (!view_area)
			{
				view_area = children[i];
			}
			else
			{
				above_view_area = children[i];
			}
		}
	}

	/* Determine if we need to show the toolbox */
	show_tool_box = (_XfeIsAlive(tool_box) && XfeToolBoxIsNeeded(tool_box));

	/* Determine if we to need show the above view area */
	show_above_view_area = (_XfeIsAlive(above_view_area) && 
							XtIsManaged(above_view_area));

	/* Determine if we need to show the view area */
	show_view_area = (_XfeIsAlive(view_area) && 
					  XtIsManaged(view_area));
	
	/* Configure the tool box */
	if (_XfeIsAlive(tool_box))
	{
		XtVaSetValues(tool_box,XmNusePreferredHeight,True,NULL);

		if (show_tool_box)
		{
			XtVaSetValues(tool_box,
						  XmNleftAttachment,	XmATTACH_FORM,
						  XmNrightAttachment,	XmATTACH_FORM,
						  XmNtopAttachment,		XmATTACH_FORM,
						  XmNbottomAttachment,	XmATTACH_NONE,
						  XmNtopOffset,			0,
						  NULL);

			_XfeResizeWidget(tool_box,
							 _XfeWidth(tool_box),
							 _XfemPreferredHeight(tool_box));

   			XfeResize(tool_box); 
		}
		else
		{
			XtVaSetValues(tool_box,XmNtopOffset,-2,NULL);
		}
	}
	
	/* Configure the above view area */
	if (show_above_view_area)
	{
		/* 
		 * We cant seem to be able to use attachments for the toolbox
		 * because of the dynamic nature of the toolbox geometry.
		 * It should work  but it doesn't so we do this hckery instead.
		 */
		int offset = 0;

		/* Place after toolbox if needed */
		if (show_tool_box)
		{
			offset = _XfeX(tool_box) + _XfemPreferredHeight(tool_box);
		}

		XtVaSetValues(above_view_area,
					  XmNleftAttachment,	XmATTACH_FORM,
					  XmNrightAttachment,	XmATTACH_FORM,
					  XmNbottomAttachment,	XmATTACH_NONE,
					  XmNtopAttachment,		XmATTACH_FORM,
					  XmNtopOffset,			offset,
					  NULL);
	}

	/* Configure the view area */
	if (show_view_area)
	{
		Widget			top_widget = NULL;
		unsigned char	top_attachment;

		/* Place after above view area if needed */
		if (show_above_view_area)
		{
			top_widget = above_view_area;
		}
		/* Place after tool box if needed */
		else if (show_tool_box)
		{
			top_widget = tool_box;
		}

		top_widget		= _XfeIsAlive(top_widget) ? top_widget : NULL;
		top_attachment	= top_widget ? XmATTACH_WIDGET : XmATTACH_FORM;

		XtVaSetValues(view_area,
					  XmNleftAttachment,	XmATTACH_FORM,
					  XmNrightAttachment,	XmATTACH_FORM,
					  XmNbottomAttachment,	XmATTACH_FORM,
					  XmNtopAttachment,		top_attachment,
					  XmNtopWidget,			top_widget,
					  NULL);
	}
}
/*----------------------------------------------------------------------*/
