/*
 * Motif
 *
 * Copyright (c) 1987-2012, The Open Group. All rights reserved.
 *
 * These libraries and programs are free software; you can
 * redistribute them and/or modify them under the terms of the GNU
 * Lesser General Public License as published by the Free Software
 * Foundation; either version 2 of the License, or (at your option)
 * any later version.
 *
 * These libraries and programs are distributed in the hope that
 * they will be useful, but WITHOUT ANY WARRANTY; without even the
 * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
 * PURPOSE. See the GNU Lesser General Public License for more
 * details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with these librararies and programs; if not, write
 * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
 * Floor, Boston, MA 02110-1301 USA
 * 
 */

/************************************************************
 *       INCLUDE FILES
 ************************************************************/
#include <Xm/Xm.h>
#include <stdio.h>
#include <Xm/ButtonBoxP.h>
#include <Xm/ExtP.h>
#include <Xm/TraitP.h>
#include <Xm/TakesDefT.h>
#include <Xm/VaSimpleP.h>
#include "XmI.h"

/************************************************************
 *       TYPEDEFS AND DEFINES
 ************************************************************/

#define SUPERCLASS ((ConstraintWidgetClass) &xmManagerClassRec)

/************************************************************
 *       MACROS
 ************************************************************/

#define IsHorizontal(x) (XmButtonBox_orientation((x)) == XmHORIZONTAL)
#define MarginH(x)	(XmButtonBox_margin_height((x)))
#define MarginW(x)	(XmButtonBox_margin_width((x)))
#define FillOption(x)	(XmButtonBox_fill_option((x)))
#define EqualSize(x)	(XmButtonBox_equal_size((x)))

/************************************************************
 *       EXTERNAL DECLARATIONS
 ************************************************************/

/************************************************************
 *       STATIC FUNCTION DECLARATIONS
 ************************************************************/

static void 	Initialize(Widget, Widget, ArgList, Cardinal *);
static void	    ClassInitialize(void);

static void     ClassPartInitialize(WidgetClass w_class) ;

static void	    InsertChild(Widget);
static void     Resize(Widget), ChangeManaged(Widget);
static void 	ConstraintInitialize(Widget, Widget, ArgList, Cardinal *);

static Boolean  SetValues(Widget, Widget, Widget, ArgList, Cardinal *);
static Boolean  ConstraintSetValues(Widget, Widget,
				    Widget, ArgList, Cardinal *);
static Boolean CvtStringToFillOption(Display *, XrmValuePtr, Cardinal *,
				     XrmValuePtr, XrmValuePtr);

static XtGeometryResult GeometryManager(Widget, XtWidgetGeometry *,
					XtWidgetGeometry *);
static XtGeometryResult QueryGeometry(Widget, XtWidgetGeometry *,
				      XtWidgetGeometry *);

static XtGeometryResult TryNewLayout(Widget, Mask *, Boolean);
static Cardinal	       	CalcChildrenPrefSizes(XmButtonBoxWidget, Dimension *,
					      Dimension *, Dimension *);
static void		LayoutChildren(Widget, Widget);
static void	 	CalcChildSize(XmButtonBoxWidget, Widget, Dimension,
				      Dimension, Dimension, Cardinal,
				      Dimension *, Dimension *);

static void ButtonBoxSetDefaultShadow(Widget button) ;


/************************************************************
 *       STATIC DECLARATIONS
 ************************************************************/

static XtResource resources[] =
{
  {
    XmNequalSize, XmCEqualSize, XmRBoolean,
    sizeof(Boolean), XtOffsetOf(XmButtonBoxRec, button_box.equal_size),
    XmRImmediate, (XtPointer) False
  },

  {
    XmNfillOption, XmCFillOption, XmRXmFillOption,
    sizeof(XmFillOption), XtOffsetOf(XmButtonBoxRec, button_box.fill_option),
    XmRImmediate, (XtPointer) XmFillNone
  },

  {
    XmNmarginHeight, XmCMargin, XmRVerticalDimension,
    sizeof(Dimension), XtOffsetOf(XmButtonBoxRec, button_box.margin_height),
    XmRImmediate, (XtPointer) 0
  },

  {
    XmNmarginWidth, XmCMargin, XmRHorizontalDimension,
    sizeof(Dimension), XtOffsetOf(XmButtonBoxRec, button_box.margin_width),
    XmRImmediate, (XtPointer) 0
  },

  {
    XmNorientation, XmCOrientation, XmROrientation,
    sizeof(unsigned char), XtOffsetOf(XmButtonBoxRec, button_box.orientation),
    XmRImmediate, (XtPointer)XmHORIZONTAL
  },

  {
    XmNdefaultButton, XmCWidget, XmRWidget,
    sizeof(Widget), XtOffsetOf(XmButtonBoxRec, button_box.default_button),
    XmRImmediate, (XtPointer) NULL
  }
};

static XmSyntheticResource get_resources[] =
{
  {
    XmNmarginHeight, sizeof(Dimension),
    XtOffsetOf(XmButtonBoxRec, button_box.margin_height),
    XmeFromVerticalPixels, (XmImportProc) XmeToVerticalPixels
  },

  {
    XmNmarginWidth, sizeof(Dimension),
    XtOffsetOf(XmButtonBoxRec, button_box.margin_width),
    XmeFromHorizontalPixels, (XmImportProc) XmeToHorizontalPixels
  }
};

static XtResource constraints[] =
{
   {
      "pri.vate1", "Pri.vate1", XmRDimension, sizeof(Dimension),
      XtOffsetOf(XmBBoxConstraintsRec, bbox.pref_width),
      XmRImmediate, (XtPointer) 0
   },
   {
      "pri.vate2", "Pri.vate2", XmRAttachment, sizeof(Dimension),
      XtOffsetOf(XmBBoxConstraintsRec, bbox.pref_height),
      XmRImmediate, (XtPointer) 0
   }
};
	    
XmButtonBoxClassRec xmButtonBoxClassRec = {
  {
    /* core_class members      */
    /* superclass         */	(WidgetClass)SUPERCLASS,
    /* class_name         */	"XmButtonBox",                            
    /* widget_size        */	sizeof(XmButtonBoxRec),                 
    /* class_initialize   */	ClassInitialize,
    /* class_part_init    */	ClassPartInitialize, 	
    /* class_inited       */	False,                            	
    /* initialize         */	Initialize, 
    /* initialize_hook    */	NULL,                             	
    /* realize            */	XtInheritRealize, 
    /* actions            */	NULL,                     

        
    /* num_actions        */	0,                                	
    /* resources          */	(XtResource*)resources,                     
    /* num_resources      */	XtNumber(resources), 
    /* xrm_class          */	NULLQUARK,                        
    /* compress_motion    */	True,                             	
    /* compress_exposure  */	True,                             	
    /* compress_enterleave*/	True,                             	
    /* visible_interest   */	False,                            
    /* destroy            */	NULL,                             
    /* resize             */	Resize,                           
    /* expose             */	NULL,                             
    /* set_values         */	SetValues,                             
    /* set_values_hook    */	NULL,                             
    /* set_values_almost  */	XtInheritSetValuesAlmost,         
    /* get_values_hook    */	NULL,                             	
    /* accept_focus       */	NULL,                             
    /* version            */	XtVersion,
    /* callback_private   */	NULL,                             
    /* tm_table           */	XtInheritTranslations, 
    /* query_geometry     */	(XtGeometryHandler) QueryGeometry, 
    /* display_accelerator*/	NULL,                             
    /* extension          */	NULL,                             
  },
  {
    /* composite_class members */
    /* geometry_manager   */	GeometryManager,                  
    /* change_managed     */	ChangeManaged,                    
    /* insert_child       */	InsertChild,
    /* delete_child       */	XtInheritDeleteChild,
    /* extension          */	NULL,
  },
  { /* constraint_class fields */
    /* resource list      */    constraints,
    /* num resources      */    XtNumber(constraints),
    /* constraint size    */ 	sizeof(XmBBoxConstraintsRec),
    /* init proc          */ 	ConstraintInitialize,
    /* destroy proc       */ 	NULL,
    /* set values proc    */ 	ConstraintSetValues,
    /* extension          */ 	NULL,
  },
  { /* manager_class fields */
    /* default translations */ 	XtInheritTranslations,
    /* syn_resources        */ 	get_resources,
    /* num_syn_resources    */ 	XtNumber(get_resources),
    /* syn_cont_resources   */ 	NULL,
    /* num_syn_cont_resources */ 0,
    /* parent_process       */ 	XmInheritParentProcess,
    /* extension            */ 	NULL,
  },
  {
    /* Row class members */
    /* extension            */	NULL,                                
  }
};

WidgetClass xmButtonBoxWidgetClass = (WidgetClass)&xmButtonBoxClassRec;

/************************************************************
 *       STATIC CODE
 ************************************************************/

/*      Function Name: ClassInitialize
 *      Description:   Called to initialize information specific
 *                     to this widget class.
 *      Arguments:     none.
 *      Returns:       none.
 */

/* ARGSUSED */
static void 
ClassInitialize()
{
    XmButtonBoxClassRec *wc = &xmButtonBoxClassRec;

    XtSetTypeConverter(XmRString, XmRXmFillOption, 
		       (XtTypeConverter) CvtStringToFillOption,
                       NULL, (Cardinal)0, XtCacheAll, (XtDestructor)NULL);
}


/****************************************************************/
static void 
ClassPartInitialize(WidgetClass w_class )
{
    XmButtonBoxWidgetClass bbClass
        = (XmButtonBoxWidgetClass) w_class ;

/* this seems to do nothing.... why is it here? -rh
    XmButtonBoxWidgetClass bbSuper
	    = (XmButtonBoxWidgetClass) w_class->core_class.superclass ;
*/
    _XmFastSubclassInit (w_class, XmBUTTONBOX_BIT);

    
    /* Install the specifyrendertable trait for all subclasses */
    /*
    XmeTraitSet((XtPointer)w_class, XmQTspecifyRenderTable, 
		(XtPointer) &bulletinbSRT);
    */
    return ;
}


/****************************************************************/


/*	Function Name: Initialize
 *	Description:   Called to initialize information specific
 *                     to this widget.
 *	Arguments:     req - what was originally requested.
 *                     new - what will be created (our superclasses have
 *                           already mucked with this)
 *                     args, num_args - The arguments passed to 
 *                                      the creation call.
 *	Returns:       none.
 */

/* ARGSUSED */
static void Initialize(Widget req, Widget set, 
		       ArgList args, Cardinal * num_args)
{
    /*
     * This is here just in case no children are added before the
     * widget is realized.
     */

    if (req->core.width == 0)
	set->core.width = 1;

    if (req->core.height == 0)
	set->core.height = 1;
}

/*	Function Name: ConstraintInitialize
 *	Description:   Called to initialize information specific
 *                     to this child widget.
 *	Arguments:     req - what was originally requested.
 *                     set - what will be created (our superclassed have
 *                           already mucked with this)
 *                     args, num_args - The arguments passed to 
 *                                      the creation call.
 *	Returns:       none.
 */

/* ARGSUSED */
static void 
ConstraintInitialize(Widget request, Widget set, ArgList args, Cardinal *num_args)
{
    XmButtonBoxC_pref_width(set) = XmButtonBoxC_pref_height(set) = 0;
}

/*      Function Name: ConstraintSetValues
 *      Description:   Called when child widget data needs to be modified on-
 *                     the-fly.
 *      Arguments:     current - the current (old) widget values.
 *                     request - before superclassed have changed things.
 *                     set - what will acutally be the new values.
 *                     args, num_args - the arguments in the list.
 *      Returns:       none
 */

/* ARGSUSED */
static Boolean
ConstraintSetValues(Widget current, Widget request, Widget set,
		    ArgList args, Cardinal * num_args)
{
    if ((XmButtonBoxC_pref_width(set) != set->core.width) ||
	(XmButtonBoxC_pref_height(set) != set->core.height))
    {
	/*
	 * The desired height or width changed, this will
	 * tell the icon box to perform a new XtQueryGeom.
	 */

	XmButtonBoxC_pref_width(set) = XmButtonBoxC_pref_height(set) = 0;
    }

    return(False);
}

/*
 *	Function Name: Resize
 *      Description:   Called when this widget has been resized.
 *      Arguments:     w - Button Box Widget to resize.
 *      Returns:       none.
 */

/*ARGSUSED */
static void
Resize(Widget w)
{
    LayoutChildren(w, NULL);
} 

/*      Function Name: QueryGeometry
 *      Description:   Called when my parent wants to know my
 *                     preferred size.
 *      Arguments:     w - the widget to check.
 *                     intended - parent imposed geometry.
 *                     preferred - what I would like.
 *      Returns:       status.
 */

static XtGeometryResult
QueryGeometry(Widget w, XtWidgetGeometry *request,
              XtWidgetGeometry *preferred)
{
    XmButtonBoxWidget 	bbox = (XmButtonBoxWidget)w;
    Dimension		max_major, max_minor, child_major_total;
    
    /*
     * Calculate our desired size.
     */
    
    (void) CalcChildrenPrefSizes(bbox, &max_major,
				 &max_minor, &child_major_total);

    if (IsHorizontal(bbox)) {
	preferred->width = child_major_total + (2 * MarginW(bbox));
	preferred->height = max_minor + (2 * MarginH(bbox));
    }
    else
    {
	preferred->width = max_minor + (2 * MarginW(bbox));
	preferred->height = child_major_total + (2 * MarginH(bbox));
    }
    
    return(_XmHWQuery(w, request, preferred));
}

/*      Function Name: GeometryManager
 *      Description:   handles request from children for size changes.
 *      Arguments:     child - the child to change.
 *                     request - desired geometry of child.
 *                     result - what will be allowed if almost.
 *      Returns:       status.
 */

/* ARGSUSED */
static XtGeometryResult
GeometryManager(Widget w, XtWidgetGeometry *request,
                XtWidgetGeometry *reply)
{
    XmButtonBoxWidget	bbox = (XmButtonBoxWidget)w->core.parent;
    Mask             	mask = 0;
    XtGeometryResult 	result;

    /*
     * Say no to any change in position.
     */
  
    if ( (request->request_mode & (CWX | CWY | CWBorderWidth)) && 
	 !(request->request_mode & (CWWidth | CWHeight)) )
    {
	return (XtGeometryNo);
    }
  
    if ( request->request_mode & (CWWidth | CWHeight) )
    {
	Dimension		max_major, max_minor;
	Dimension		child_major, child_minor;
	Dimension	        child_width, child_height;
	Dimension		child_major_total;
    
	Cardinal   		num_managed;

	/*
	 * Save the old size, and set the corresponding
	 * widget fields to the requested sizes.
	 */

	Dimension old_width       = XmButtonBoxC_pref_width(w);
	Dimension old_height      = XmButtonBoxC_pref_height(w);

	if ( request->request_mode & CWWidth )
	    XmButtonBoxC_pref_width(w)  = request->width;
	
	if ( request->request_mode & CWHeight )
	    XmButtonBoxC_pref_height(w) = request->height;
	
	/*
	 * See if everything fits with the new size.
	 */
	
	(void) TryNewLayout((Widget)bbox, &mask, 
			    (request->request_mode & XtCWQueryOnly));

	num_managed = CalcChildrenPrefSizes(bbox, &max_major,
					    &max_minor, &child_major_total);

	CalcChildSize(bbox, w, max_major, max_minor, 
		      child_major_total, num_managed, &child_major, 
		      &child_minor);

	if (IsHorizontal(bbox)) {
	    child_height = child_minor;
	    child_width = child_major;
	}
	else {
	    child_height = child_major;
	    child_width = child_minor;
	}

	if ( (int)child_width >= (int)(2 * w->core.border_width) ) 
	    child_width -= (2 * w->core.border_width);
	
	if ( (int)child_height >= (int)(2 * w->core.border_width) )
	    child_height -= (2 * w->core.border_width);

	if (((child_width == XmButtonBoxC_pref_width(w)) ||
	     !(request->request_mode & CWWidth)) &&
	    ((child_height == XmButtonBoxC_pref_height(w)) ||
	     !(request->request_mode & CWHeight)))
	{
	    result = XtGeometryYes;
	}
	else if ((child_width != w->core.width) || 
		 (child_height != w->core.height))
	{
	    reply->request_mode = CWHeight | CWWidth;
	    reply->height = child_height;
	    reply->width = child_width;
	    result = XtGeometryAlmost;
	}
	else {
	    result = XtGeometryNo;
	}

	if ((request->request_mode & XtCWQueryOnly) ||
	    (result != XtGeometryYes))
	{
	    XmButtonBoxC_pref_width(w) = old_width;
	    XmButtonBoxC_pref_height(w) = old_height;
	}
	else 
	    LayoutChildren((Widget)bbox, w);

	/*
	 * We didn't get what we wanted, our preferred
	 * size should be recomputed the next time we have
	 * a chance to ask it, given that we're rejecting
	 * its current geometry and that it may not agree
	 * with our Almost reply.
	 */

	if (result != XtGeometryYes) {
	    if ( request->request_mode & CWWidth )
		XmButtonBoxC_pref_width(w) = 0;
	    
	    if ( request->request_mode & CWHeight )
		XmButtonBoxC_pref_height(w) = 0;
	}

	return(result);
    }

    /*
     * Stacking request only.
     */

    return (XtGeometryYes);
}


/*      Function Name: ChangeManaged
 *      Description:   when a management change has occurred.
 *      Arguments:     w - the ButtonBox widget.
 *      Returns:       none.
 */

/* ARGSUSED */
static void
ChangeManaged(Widget w)
{
    Mask		mask = 0;
    /* CR03420 mask should be set accordingly */
    if (w->core.width == 1) mask |= CWWidth;
    if (w->core.height == 1) mask |= CWHeight;
    if (mask) (void)TryNewLayout(w, &mask, False);
    LayoutChildren(w, NULL);

   /*
    * for Motif navigation
    */

   XmeNavigChangeManaged(w);
}


/*      Function Name: InsertChild
 *      Description:   when a child widget is added.
 *      Arguments:     w - the child widget
 *      Returns:       none.
 */

/* ARGSUSED */
static void
InsertChild(register Widget child)
{
Boolean         is_button = False ;
XmButtonBoxWidget bb = (XmButtonBoxWidget) XtParent( child) ;
    /*
     * Check for non-widgets - ButtonBox doesn't support gadgets, for now ...
     */

    if (_XmGadgetWarning(child))
    {
    	return;
    }
    
    /*
     * Insert the child widget in the composite children list with the
     * superclass insert_child routine.
     */

    /* (*SUPERCLASS->composite_class.insert_child)(w); */

    /* Another process may be updating the superclass's data */
    /* (This was missed for some reason... - scorch)
     * use composite class insert proc to do all the dirty work
     */
    {
       XtWidgetProc insert_child;
       _XmProcessLock();
       insert_child = ((XmManagerWidgetClass)xmManagerWidgetClass)->
				composite_class.insert_child; 
       _XmProcessUnlock();
       (*insert_child)(child);
    }

    if(XmeTraitGet((XtPointer)XtClass(child), XmQTtakesDefault))
    {
        is_button = TRUE ;

        if( XmButtonBox_default_button( bb) )
        {   
            /* Notify child that it has to be ready for default visual */
            ButtonBoxSetDefaultShadow( child) ;
        }
    }

}

    
/*      Function Name: SetValues
 *      Description:   Called when some widget data needs to be modified on-
 *                     the-fly.
 *      Arguments:     current - the current (old) widget values.
 *                     request - before superclassed have changed things.
 *                     set - what will acutally be the new values.
 *                     args, num_args - the arguments in the list.
 *      Returns:       none
 */

/* ARGSUSED */
static Boolean
SetValues(Widget current, Widget request, Widget set,
          ArgList args, Cardinal * num_args)
{
    XmButtonBoxWidget b_old = (XmButtonBoxWidget) current;
    XmButtonBoxWidget b_set = (XmButtonBoxWidget) set;
    Boolean	      newLayout = False;
    Mask mask = 0; /* CR03420 */
    if ( XmButtonBox_equal_size(b_set) != XmButtonBox_equal_size(b_old) ||
	 XmButtonBox_fill_option(b_set) != XmButtonBox_fill_option(b_old) ||
	 XmButtonBox_margin_height(b_set) != XmButtonBox_margin_height(b_old) ||
	 XmButtonBox_margin_width(b_set) != XmButtonBox_margin_width(b_old) ||
	 XmButtonBox_orientation(b_set) != XmButtonBox_orientation(b_old) )
    {
	newLayout = True;
    }

    if (set->core.width == 0) 
    { /* CR03420 */
      set->core.width = 1; /* setting to 1 to prevent zero width */
      mask |= CWWidth;
    }
    if (set->core.height == 0)
    { /* CR03420 */
      set->core.height = 1; /* setting to 1 to prevent zero height */
      mask |= CWHeight;
    }
    if (mask) TryNewLayout((Widget)b_set, &mask, False);
    if ( newLayout == True ) LayoutChildren((Widget)b_set, NULL);
    
    return(False);
}

/************************************************************
 * Type Converters.
 ************************************************************/

/*      Function Name: CvtStringToFillOption
 *      Description:   Converts a string to a FillOption
 *      Arguments:     dpy - the X Display.
 *                     args, num_args - *** NOT USED ***
 *                     fromVal - contains the string to convert.
 *                     toVal - contains the converted node state.
 *      Returns:
 */

/* ARGSUSED */
static Boolean
CvtStringToFillOption(Display * dpy, XrmValuePtr args, Cardinal *num_args,
		      XrmValuePtr fromVal, XrmValuePtr toVal)
{
    static XmFillOption 	option;
    char 			lowerName[BUFSIZ];

    XmCopyISOLatin1Lowered(lowerName, (char *)fromVal->addr);
    
    if ( streq(lowerName, "none") || streq(lowerName,"fillnone") )
        option = XmFillNone;
    else if ( streq(lowerName, "major") || streq(lowerName, "fillmajor") )
	option = XmFillMajor;
    else if ( streq(lowerName, "minor") || streq(lowerName, "fillminor") )
	option = XmFillMinor;
    else if ( streq(lowerName, "all") || streq(lowerName, "fillall") )
	option = XmFillAll;
    else
    {
	XtDisplayStringConversionWarning(dpy, fromVal->addr, XmRXmFillOption);
        return(False);          /* Conversion failed. */
    }

    if ( toVal->addr == NULL ) 
    {
        toVal->size = sizeof(XmFillOption);
        toVal->addr = (XtPointer)&option;
        return(True);
    }
    else
    {
	toVal->size = sizeof(XmFillOption);
	if ( toVal->size >= sizeof(XmFillOption) ) 
	{
	    XmFillOption *state = (XmFillOption *)toVal->addr;

	    *state = option;
	    return(True);
	}
	else
	{
	    return(False);
	}
    }
}

/************************************************************
 *      LOCAL CODE
 ************************************************************/

/*      Function Name: TryNewLayout
 *      Description:   tries to do a layout within the current width
 *                     and height.  If that fails, it tries to resize and
 *                     do it within the geometry given in preferred_size.
 *      Arguments:     parent - the ButtonBox
 *		       mask - request mask
 *		       queryOnly - should this only query
 *      Returns:       status.
 */

/* ARGSUSED */
static XtGeometryResult 
TryNewLayout(Widget parent, Mask *mask, 
	     Boolean queryOnly)
{
    XmButtonBoxWidget 	bbox = (XmButtonBoxWidget)parent;
    Dimension		new_width, new_height;
    Dimension		max_major, max_minor, child_major_total;
    
    /*
     * Get the bounding width and height of all children.
     */

    (void) CalcChildrenPrefSizes(bbox, &max_major,
				 &max_minor, &child_major_total);

    if (IsHorizontal(bbox)) 
    {
	new_width = child_major_total + 2 * MarginW(bbox);
	new_height = max_minor + 2 * MarginH(bbox);
    }
    else
    {
	new_width = max_minor + 2 * MarginW(bbox);
	new_height = child_major_total + 2 * MarginH(bbox);
    }
    
    /*
     * Be sure that we are always at least one pixel high.
     */

    if (new_width == 0)
	new_width = 1;
    if (new_height == 0)
	new_height = 1;

    if ( new_width != parent->core.width || new_height != parent->core.height )
    {
	XtWidgetGeometry	request, reply;
	XtGeometryResult	result;

	request.width = new_width;
	request.height = new_height;

	reply.width = 0;
	reply.height = 0;
	
	request.request_mode = *mask; /* CR03420 */
	if ( queryOnly )
	{
	    request.request_mode |= XtCWQueryOnly;
	}
	result = XtMakeGeometryRequest(parent, &request, &reply);

	if ( request.width == reply.width )
	{
	    *mask |= CWWidth;
	}
	if ( request.height == reply.height )
	{
	    *mask |= CWHeight;
	}

	if ( result == XtGeometryAlmost && !queryOnly )
	{
	    result = XtMakeGeometryRequest(parent, &reply, &reply);
	}
	
	return(result);
    }

    *mask = CWWidth | CWHeight;
    return(XtGeometryYes);
}


/*      Function Name: LayoutChildren
 *      Description:   Lays out the "child" widgets in the ButtonBox widget.
 *      Arguments:     w - the ButtonBox widget.
 *                     special_child - Treat this child special, actually
 *                                     set the new width and height instead
 *                                     of calling the Xt routine.  This helps
 *                                     the geom mgr implement XtGeometryYes
 *                                     policy.
 *      Returns:       none.
 */

/* ARGSUSED */
static void
LayoutChildren(Widget w, Widget special_child)
{
    XmButtonBoxWidget 	bbox = (XmButtonBoxWidget)w;
    Widget             *childp;

    Dimension		margin_major, margin_minor;
    Dimension		max_major, max_minor;
    Dimension		box_major, box_minor;
    Dimension		child_major, child_minor;
    Dimension	        child_width, child_height;
    Dimension		child_major_total;
    
    Position		pos_minor;
    Position   	        pos_x, pos_y;

    float  		pad = 0, pos_major;
    Cardinal   		num_managed;

    child_major = 0;
    child_minor = 0;
    
    if ( IsHorizontal(bbox) )
    {
	margin_major = MarginW(bbox);
	margin_minor = MarginH(bbox);
	box_major = bbox->core.width;
	box_minor = bbox->core.height;
    }
    else
    {
	margin_major = MarginH(bbox);
	margin_minor = MarginW(bbox);
	box_major = bbox->core.height;
	box_minor = bbox->core.width;
    }
    if ((int)box_major > (int)(2 * margin_major))
	box_major -= 2 * margin_major;
    else
	box_major = 1;

    if ((int)box_minor > (int)(2 * margin_minor))
	box_minor -= 2 * margin_minor;
    else
	box_minor = 1;

    num_managed = CalcChildrenPrefSizes(bbox, &max_major,
					&max_minor, &child_major_total);

    pad = 0.0;
    pos_major = (float) margin_major;
    if ((FillOption(bbox) == XmFillNone) || (FillOption(bbox) == XmFillMinor))
    {
	if ( box_major >= child_major_total ) {
	    pad = ((float) box_major - 
		   (float) child_major_total) / ((float) num_managed + 1.0);
	    pos_major += pad;
	}
    }
    
    ForAllChildren(bbox, childp) {
	if ( !XtIsManaged(*childp) ) 
	    continue;

	CalcChildSize(bbox, *childp, max_major, max_minor, 
		      child_major_total, num_managed, &child_major, 
		      &child_minor);
	
	if ((FillOption(bbox) == XmFillNone) || 
	    (FillOption(bbox) == XmFillMajor))
	{
	    pos_minor = (((int)(box_minor - child_minor)) /2) + margin_minor;
	}
	else
	    pos_minor = margin_minor;
	
	if ( IsHorizontal(bbox) ) {
	    child_width = child_major;
	    child_height = child_minor;
	    if (LayoutIsRtoLM(bbox))
		pos_x = box_major - (int) pos_major - child_width;
	    else
		pos_x = (int) pos_major;
	    pos_y = pos_minor;
	}
	else {
	    pos_x = pos_minor;
	    pos_y = (int) pos_major;
	    child_width = child_minor;
	    child_height = child_major;
	}

	if ( (int)child_width >= (int)(2 * (*childp)->core.border_width) ) 
	    child_width -= (2 * (*childp)->core.border_width);
	
	if ( (int)child_height >= (int)(2 * (*childp)->core.border_width) )
	    child_height -= (2 * (*childp)->core.border_width);
	
	child_width = (child_width == 0) ? 1 : child_width;
	child_height = (child_height == 0) ? 1 : child_height;

	if (*childp == special_child) {
	    special_child->core.x = pos_x;
	    special_child->core.y = pos_y;
	    special_child->core.width = child_width;
	    special_child->core.height = child_height;
	}
	else {
	    _XmConfigureWidget(*childp, pos_x, pos_y, child_width, 
			       child_height, (*childp)->core.border_width);
	}

	pos_major += (float) child_major + pad;
    }
}

/*      Function Name: CalcChildrenPrefSizes
 *      Description:   Determines the total size in the major direction
 *		       of all children of the ButtonBox, as well as the 
 *                     maximum value in both major and minor directions.
 *      Arguments:     bbox - the ButtonBox parent.
 *		       max_major - the maximum size of all the children
 *				   in the major dimension.
 *		       total - return location for the total size in the
 *			       major direction.
 *      Returns:       number of managed children.
 */

/* ARGSUSED */
static Cardinal
CalcChildrenPrefSizes(XmButtonBoxWidget bbox, Dimension *max_major,
		      Dimension *max_minor, Dimension *total)
{
    Cardinal		num_managed = 0;
    Widget	       *childp;
    XtWidgetGeometry	geo;
    Dimension	       *maj_dim, *minor_dim;
    Boolean		is_equal = EqualSize(bbox);
    
    if ( IsHorizontal(bbox) ) 
    {
	maj_dim = &geo.width;
	minor_dim = &geo.height;
    }
    else
    {
	maj_dim = &geo.height;
	minor_dim = &geo.width;
    }
    
    *total = *max_major = *max_minor = 1;
    
    ForAllChildren(bbox, childp) {

	if ( !XtIsManaged(*childp) ) 
	    continue;

	num_managed++;
	    
	if ((XmButtonBoxC_pref_width(*childp) == 0) ||
	    (XmButtonBoxC_pref_height(*childp) == 0)) 
	{
	    XtQueryGeometry(*childp, NULL, &geo);
	}
	else
	    geo.border_width = (*childp)->core.border_width;
	
	if (XmButtonBoxC_pref_width(*childp) == 0)
	    XmButtonBoxC_pref_width(*childp) = geo.width;
	else
	    geo.width = XmButtonBoxC_pref_width(*childp);
	
	if (XmButtonBoxC_pref_height(*childp) == 0)
	    XmButtonBoxC_pref_height(*childp) = geo.height;
	else
	    geo.height = XmButtonBoxC_pref_height(*childp);
	
	ASSIGN_MAX(*max_major, *maj_dim + (2 * geo.border_width));
	ASSIGN_MAX(*max_minor, *minor_dim + (2 * geo.border_width));
	
	if (!is_equal) 
	    *total += (*maj_dim + (2 * geo.border_width));
    }
    
    if ( is_equal )
        *total = num_managed * (*max_major);
    
    return(num_managed);
}

/*      Function Name: CalcChildSize
 *      Description:   Determines the size of a child
 *      Arguments:     bbox - the ButtonBox parent.
 *		       w - the child of interest.
 *		       max_major - the largest size allowed in the
 *				   major direction.
 *		       max_minor - the largest size allowed in the
 *				   minor direction.
 *		       child_major_total - total size of all children in the
 *					   major direction.
 *		       num_managed - number of managed children.
 *		       child_major - return location for child's base 
 *				     major size.
 *		       child_minor - return location for child's base
 *				     minor size.
 *      Returns:       none.
 */

/* ARGSUSED */
static void
CalcChildSize(XmButtonBoxWidget bbox, Widget w, Dimension max_major,
	      Dimension max_minor, Dimension child_major_total, 
	      Cardinal num_managed, Dimension *child_major, 
	      Dimension *child_minor)
{
    XtWidgetGeometry	geo;
    Dimension		box_minor, box_major;
    Dimension		margin_major, margin_minor;
    
    if ((XmButtonBoxC_pref_width(w) == 0)||(XmButtonBoxC_pref_height(w) == 0)) 
	XtQueryGeometry(w, NULL, &geo);
    else
	geo.border_width = w->core.border_width;
    
    if (XmButtonBoxC_pref_width(w) != 0)
	geo.width = XmButtonBoxC_pref_width(w);
    
    if (XmButtonBoxC_pref_height(w) != 0)
	geo.height = XmButtonBoxC_pref_height(w);

    if ( IsHorizontal(bbox) )
    {
	margin_major = MarginW(bbox);
	margin_minor = MarginH(bbox);
	box_major = bbox->core.width;
        box_minor = bbox->core.height;
        *child_major = geo.width;
        *child_minor = geo.height;
    }
    else
    {
	margin_major = MarginH(bbox);
	margin_minor = MarginW(bbox);
	box_major = bbox->core.height;
        box_minor = bbox->core.width;
        *child_major = geo.height;
        *child_minor = geo.width;
    }
    *child_major += (2 * geo.border_width);
    *child_minor += (2 * geo.border_width);

    if ((int)box_major > (int)(2 * margin_major))
	box_major -= (2 * margin_major);
    else
	box_major = 1;

    if ((int)box_minor > (int)(2 * margin_minor))
	box_minor -= (2 * margin_minor);
    else
	box_minor = 1;

    if ( EqualSize(bbox) )
    {
        *child_major = max_major;
        *child_minor = max_minor;
    }
    if ( FillOption(bbox) == XmFillMajor || FillOption(bbox) == XmFillAll ||
	 child_major_total > box_major )
    {
	*child_major = (Dimension)
	    (((float)*child_major/(float)child_major_total) * box_major);
    }
    if ( FillOption(bbox) == XmFillMinor || FillOption(bbox) == XmFillAll || 
	 *child_minor > box_minor )
    {
	*child_minor = box_minor;
    }
}

/************************************************************
 *
 *  Public functions
 *
 ************************************************************/

/*	Function Name: XmCreateButtonBox
 *	Description: Creation Routine for UIL and ADA.
 *	Arguments: parent - the parent widget.
 *                 name - the name of the widget.
 *                 args, num_args - the number and list of args.
 *	Returns: The created widget.
 */

Widget
XmCreateButtonBox(Widget parent, String name, ArgList args, Cardinal num_args)
{
    return(XtCreateWidget(name, 
			  xmButtonBoxWidgetClass, parent, args, num_args));
}

Widget 
XmVaCreateButtonBox(
        Widget parent,
        char *name,
        ...)
{
    register Widget w;
    va_list var;
    int count;
    
    Va_start(var,name);
    count = XmeCountVaListSimple(var);
    va_end(var);

    
    Va_start(var, name);
    w = XmeVLCreateWidget(name, 
                         xmButtonBoxWidgetClass,
                         parent, False, 
                         var, count);
    va_end(var);   
    return w;
}

Widget
XmVaCreateManagedButtonBox(
        Widget parent,
        char *name,
        ...)
{
    Widget w = NULL;
    va_list var;
    int count;
    
    Va_start(var, name);
    count = XmeCountVaListSimple(var);
    va_end(var);
    
    Va_start(var, name);
    w = XmeVLCreateWidget(name, 
                         xmButtonBoxWidgetClass,
                         parent, True, 
                         var, count);
    va_end(var);   
    return w;
}

/****************************************************************/
static void 
ButtonBoxSetDefaultShadow(Widget button)
{   
    XmTakesDefaultTrait trait_default ;
    
    trait_default = (XmTakesDefaultTrait) XmeTraitGet((XtPointer)
						      XtClass(button), 
						      XmQTtakesDefault) ;
    if (trait_default) 
	trait_default->showAsDefault  (button, XmDEFAULT_READY);
}
