/*********************************************************************
 *
 *         EZWGL, the EZ Widget and Graphics Library
 *
 *             Copyright (C) 1996, 1997  Maorong Zou
 *  
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public
 * License along with this library; if not, write to the Free
 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 *
 **********************************************************************/
/*
 *  June 1996.  Beta Release.
 *  Sept 1996.  Release Version 1.0
 *  Dec 1996.  Release Version 1.1 Beta
 *  April 1997.  Release Version 1.2
 *  November 1997.  Release Version 1.3
 */
/******************************************************************
 ***                                                            ***
 ***     Compute the size and position of a widget window.      ***
 ***                                                            ***
 ******************************************************************/
#define _EZ_WIDGET_GEOM_C_
#include "EZ_Widget.h"

/*********************************************************************
 * 
 *  Functions implemented in this file:
 */
void                 EZ_ComputeWidgetWindowSize MY_ANSIARGS((EZ_Widget *widget,
							     int *w, int *h,
							     EZ_Widget *dirtyAns));
void                 EZ_SetChildrenPositionAndSize MY_ANSIARGS((EZ_Widget *widget, int w, int h));

/*********************************************************************
 * 
 *  Local Functions 
 */

static int EZ_CountWidthScalableChildren MY_ANSIARGS((EZ_Widget *widget));
static int EZ_CountHeightScalableChildren MY_ANSIARGS((EZ_Widget *widget));
static int EZ_GetNumberOfActiveChildren MY_ANSIARGS((EZ_Widget *widget));
/*********************************************************************
 *
 * Compute the minimal dimension of widget. It is the smallest size
 * to let its children fit in nicely.
 */

void EZ_ComputeWidgetWindowSize(widget, w, h, EZ_TopmostGeomDirtyWidget)
     EZ_Widget *widget,*EZ_TopmostGeomDirtyWidget;
     int             *w, *h;
{
  int               cw, ch, tw, th, ww,wh, type, gmdone=0;
  int               stacking, numchildren=0, itmp, jtmp, fillmode;
  EZ_Widget         *children;
  EZ_GManager       *gmanager; 
  /*------------------------------------------------------------
   *  A NULL widget must be of size 0
   *-----------------------------------------------------------*/
  if(widget == (EZ_Widget *)NULL || EZ_GetWidgetNonActiveFlag(widget) != 0)
    {
      *w = 0; *h = 0;
      return;
    }
  /*-----------------------------------------------------------
   *  If widget is a terminal widget. ww and wh holds its
   *  minimal size.
   *---------------------------------------------------------*/
  type = EZ_WidgetType(widget); 
  (EZ_WidgetHandlingFunctions[type]->ComputeSize)(widget, &ww, &wh);
      
  gmanager = EZ_WidgetGManager(widget);
  if(gmanager)
    {
      if(EZ_GMType(gmanager) == EZ_GB_GEOM_MANAGER)
	{
	  EZ_RowColumnComputeGeometry(widget, &cw, &ch, EZ_TopmostGeomDirtyWidget);
	  numchildren = EZ_GetNumberOfActiveChildren(widget);
	  gmdone = 1;
	}
    }
  if(gmdone == 0) /* default gm manager */
    {
      cw = 0; 
      ch = 0;
      stacking = EZ_WidgetStacking(widget);
      fillmode = (EZ_WidgetFillMode(widget) == EZ_FILL_NONE ? 1 : 0);

      if((children = EZ_WidgetChildren(widget)) != (EZ_Widget *)NULL)
	{
	  /*------------------------------------------------------
	   *  figure out the dimensions of all descendants
	   *-----------------------------------------------------*/
	  while(children)
	    {
	      if(EZ_GetWidgetNonActiveFlag(children) == 0)
		{
		  EZ_ComputeWidgetWindowSize(children, &tw, &th, EZ_TopmostGeomDirtyWidget);
		  if(EZ_WidgetType(children) < EZ_WIDGET_ITOPLEVEL)
		    {
		      if(stacking >= EZ_HORIZONTAL && stacking <= EZ_HORIZONTAL_CENTER)
			{
			  if(fillmode && EZ_GetWidgetXSetFlag(children) && 
			     EZ_GetWidgetExpandFlag(children)== 0)
			    {
			      itmp = EZ_WidgetOriginX(children) + tw;
			      cw = MAXV(cw, itmp);
			    }
			  else
			    {
			      EZ_ClearWidgetXSetFlag(children);
			      cw += tw;
			    }
			  if(fillmode && EZ_GetWidgetYSetFlag(children) && 
			     EZ_GetWidgetExpandFlag(children) == 0)
			    {
			      itmp = EZ_WidgetOriginY(children) + th;
			      ch = MAXV(ch, itmp);
			    }		  
			  else 
			    {
			      EZ_ClearWidgetYSetFlag(children);
			      ch = MAXV(ch, th);
			    }
			}
		      else /* stacking >= EZ_VERTICAL && stacking <= EZ_VERTICAL_CENTER */
			{
			  if(fillmode && EZ_GetWidgetXSetFlag(children) &&
			     EZ_GetWidgetExpandFlag(children) == 0)
			    {
			      itmp = EZ_WidgetOriginX(children) + tw;
			      cw = MAXV(cw, itmp);
			    }
			  else
			    {
			      EZ_ClearWidgetXSetFlag(children);
			      cw = MAXV(cw,tw);
			    }
			  if(fillmode && EZ_GetWidgetYSetFlag(children) && 
			     EZ_GetWidgetExpandFlag(children) == 0)
			    {
			      itmp = EZ_WidgetOriginY(children) + th;
			      ch = MAXV(ch, itmp);
			    }		  
			  else 
			    {
			      EZ_ClearWidgetYSetFlag(children);
			      ch += th ;
			    }
			}
		    }
		}
	      children = EZ_WidgetSibling(children);
	    }
	  /*----------------------------------------------------
	   *  Now include the borderwidth and padding,
	   *---------------------------------------------------*/
	  itmp = EZ_WidgetBorderWidth(widget) + EZ_WidgetPadB(widget);
	  jtmp = ch;
	  ch += ((itmp + EZ_WidgetPadY(widget) + EZ_WidgetAuxY(widget)) << 1) +
	    EZ_WidgetHAdjust(widget);
	  /*==========================================================
	   *
	   * The size of the check mark depends on the size of the
	   * check_button/radio_button. Too bad!
	   */
	  switch(EZ_WidgetType(widget))
	    {
	    case  EZ_WIDGET_CHECK_BUTTON:
	    case  EZ_WIDGET_MENU_CHECK_BUTTON:
	      if(EZ_CButtonCheckType(widget) != EZ_EMPTY_INDICATOR)	  
		EZ_WidgetAuxXLeft(widget) = (ch << 1)/5  + 6 + EZ_CButtonCheckSizeAdjust(widget);    
	      else  EZ_WidgetAuxXLeft(widget) = 0;
	      break;
	    case  EZ_WIDGET_RADIO_BUTTON:
	    case  EZ_WIDGET_MENU_RADIO_BUTTON:
	      if(EZ_RButtonCheckType(widget) != EZ_EMPTY_INDICATOR)	  
		EZ_WidgetAuxXLeft(widget) =  (ch << 1)/5  + 6 + EZ_RButtonCheckSizeAdjust(widget);    
	      else  EZ_WidgetAuxXLeft(widget) = 0;
	      break;
	    case  EZ_WIDGET_MENU_BUTTON:
	      if(EZ_MButtonCheckType(widget) != EZ_EMPTY_INDICATOR)	  
		EZ_WidgetAuxXLeft(widget) = (ch << 1)/5  + 6 + EZ_MButtonCheckSizeAdjust(widget);    
	      else  EZ_WidgetAuxXLeft(widget) = 0;
	      break;
	    case EZ_WIDGET_MENU_SUBMENU:
	      EZ_SubMenuArrowSize(widget) = (jtmp >>1);
	      EZ_WidgetAuxXRight(widget) = EZ_SubMenuLabel2Width(widget) +
		EZ_SubMenuArrowSize(widget) + (EZ_SubMenuArrowBWidth(widget)<<1) + 8;
	      break;
	    default:
	      break;
	    }
	  /*==========================================================*/
	  cw += ((itmp + EZ_WidgetPadX(widget))<<1) + EZ_WidgetAuxXLeft(widget) + EZ_WidgetAuxXRight(widget);

	  numchildren = EZ_GetNumberOfActiveChildren(widget);
	  /*----------------------------------------------------------------
	   * Finally, include the internal spacing between children widgets
	   *----------------------------------------------------------------*/
	  if(stacking >= EZ_HORIZONTAL && stacking <= EZ_HORIZONTAL_CENTER)
	    cw += (EZ_WidgetSepX(widget) * (numchildren - 1));
	  else
	    ch += (EZ_WidgetSepY(widget) * (numchildren - 1));
	}
    }
  /*-----------------------------------------------------
   * we need to remember the difference between
   * the internal min size and the min size needed to
   * fit all children in.
   *----------------------------------------------------*/
  {
    int tmp;
    
    tmp = ww - cw;
    EZ_WidgetCW(widget) = tmp > 0? tmp: 0;
    tmp = wh - ch;
    EZ_WidgetCH(widget) = tmp > 0? tmp: 0;
  }
  /*------------------------------------------------------
   *  This is the smallest possible size of widget
   *-----------------------------------------------------*/
  tw = MAXV(cw,ww);  tw = (tw > 0? tw : 1);
  th = MAXV(ch,wh);  th = (th > 0? th : 1);

  /*----------------------------------------------------------
   * set the minimal size of widget.
   *---------------------------------------------------------*/
  EZ_WidgetMinWidth(widget) = tw;
  EZ_WidgetMinHeight(widget) = th;
  EZ_WidgetAMinWidth(widget) = tw;
  EZ_WidgetAMinHeight(widget) = th;

  /* for notebook widget, record the max mini dim of pages */
  if(EZ_WidgetType(widget) == EZ_WIDGET_NB_PAGE)
    {
      EZ_Widget *notebook = EZ_NBPageNoteBook(widget);
      int tmpwidth = EZ_NoteBookMaxMinWidth(notebook);
      int tmpheight = EZ_NoteBookMaxMinHeight(notebook);

      tmpwidth =  EZ_NoteBookMaxMinWidth(notebook) = MAXV(tmpwidth, tw);
      tmpheight = EZ_NoteBookMaxMinHeight(notebook) = MAXV(tmpheight, th);
      EZ_WidgetWidthHint(widget) = tmpwidth;
      EZ_WidgetHeightHint(widget) = tmpheight;
    }

  /*-----------------------------------------------------------
   * Ttricky toplevel windows ...
   *----------------------------------------------------------*/
  {
    int wset = 0, hset = 0;

    if(EZ_WidgetParent(widget) == (EZ_Widget *)NULL && 
       EZ_GetWidgetEmbededFlag(widget) == 0 && 
       type < EZ_WIDGET_POPUP_MENU)
      {
	if(EZ_WidgetWidth(widget) >= EZ_WidgetMinWidth(widget)) wset = 1;
	if(EZ_WidgetHeight(widget)>= EZ_WidgetMinHeight(widget)) hset = 1;
      }
    /*-----------------------------------------------------------
     * Honor configured size only if explicitly set
     *----------------------------------------------------------*/
    if(wset == 0)
      {
	if((EZ_GetWidgetWidthSetFlag(widget) && EZ_WidgetWidthHint(widget) > 0) ||
	   (EZ_GetWidgetWidthHintFlag(widget) && EZ_WidgetWidthHint(widget) >=tw))
	  EZ_WidgetWidth(widget) = EZ_WidgetWidthHint(widget);
	else EZ_WidgetWidth(widget) = tw;
      }
    if(hset == 0)
      {
	if((EZ_GetWidgetHeightSetFlag(widget) && EZ_WidgetHeightHint(widget) > 0) ||
	   (EZ_GetWidgetHeightHintFlag(widget) && EZ_WidgetHeightHint(widget) >= th))
	  EZ_WidgetHeight(widget) = EZ_WidgetHeightHint(widget);
	else EZ_WidgetHeight(widget) = th;
      }
  }
  /*----------------------------------------------------------
   * 3D canvas is special
   *---------------------------------------------------------*/
  if(EZ_WidgetType(widget) == EZ_WIDGET_3D_CANVAS)

    {
      int oldwidth = EZ_WidgetWidth(widget);
      int oldheight = EZ_WidgetHeight(widget);
      int xsize = oldwidth;
      int ysize = oldheight;

      xsize  = (xsize > 1024? 1024: ((xsize < 16)? 16: xsize));
      ysize = (ysize > 1024? 1024:((ysize < 16)? 16: ysize));
      /*
       * make sure the size is a multiple of 4
       */
      xsize = xsize & ~3;
      ysize = ysize & ~3;
      /*-----------------------------------
       * The set size of 3D Canvas.
       *----------------------------------*/
      EZ_WidgetWidth(widget) = xsize;
      EZ_WidgetHeight(widget) = ysize;
      if(EZ_WidgetWindow(widget) != (Window )NULL)
	{
	  /*---------------------------------------------
	   * The widget window has already been created.
	   * If the size has been changed, we'll have to
	   * reconfigure the GL stuff.
	   *--------------------------------------------*/
	  EZ_Widget *currentCanvas = EZ_CurrentGWindow;
	  if(EZ_WindowWidth != xsize || EZ_WindowHeight != ysize)
	    EZ_Configure3DCanvas(widget);
	  if(currentCanvas != widget) EZ_Set3DCanvas(currentCanvas);
	}
    }
  /*---------------------------------------------------
   *  If the DoNotPropagateFlag is set on widget and
   *  if widget is the starting widget whose geom is being
   *  computed and its size has been previously assigned
   *  by its parent. Using the assigned geom instead.
   *  
   *  Its the FILL_MODE and EXPAND make life hard here.
   *--------------------------------------------------*/
  if(widget == EZ_TopmostGeomDirtyWidget   &&
     EZ_GetDoNotPropagateFlag(widget) != 0 &&
     EZ_WidgetAWidth(widget) > 0 )
    {
      EZ_WidgetWidth(widget) = (int) EZ_WidgetAWidth(widget);
      EZ_WidgetHeight(widget) = (int) EZ_WidgetAHeight(widget);
    }
  /*---------------------------------------------------
   *  Mark that the geometry of widget is current.
   *--------------------------------------------------*/
  EZ_SetWidgetSizeComputedFlag(widget);
  *w = EZ_WidgetWidth(widget);
  *h = EZ_WidgetHeight(widget);

  /*--------------------------------------------------------
   *  Compute the position of children widgets.
   *-------------------------------------------------------*/
  if(numchildren != 0)
    EZ_SetChildrenPositionAndSize(widget,  *w, *h);

  /*--------------------------------------------------------
   *  For notebook widget, set the broken border of bottom
   *  frame.
   *-------------------------------------------------------*/
  if(EZ_WidgetType(widget) == EZ_WIDGET_NB_PAGE)
    {
      EZ_Widget *companion = EZ_NBPageCompanion(widget); 
      if(companion)
	{
	  int c_bw = EZ_WidgetBorderWidth(companion) + EZ_WidgetPadB(companion);
	  int c_w = EZ_WidgetWidth(companion) - c_bw -  EZ_WidgetPadB(companion);
	  EZ_NBPageBrokenBdXBgn(widget) = EZ_WidgetOriginX(companion) + c_bw;
	  EZ_NBPageBrokenBdLength(widget) = c_w;
	}
    }
}

/*******************************************************************
 *
 *  Set the internal position and size of a widget window. If
 *  necessary, adjust the position of its direct children.
 *
 *  When this function is called, the dimension of widget and
 *  all its descendants must have been computed.
 */
void  EZ_SetChildrenPositionAndSize(widget, w, h)
     EZ_Widget   *widget;
     int         w,h;         /* new dimension of widget */
{
  int             cw, ch, tw, th, wtmp, htmp, type;
  int             bwpadx, bwpady, sepx,sepy,auxxL,auxxR, auxxT, auxy, auxy2;
  int             stacking, alignment, fillmode, hadjust;
  int             numchildren, ncWS, ncHS;
  float           dx, dy, xx, yy, x0, y0;
  EZ_Widget       *children;
  EZ_GManager       *gmanager; 

  if(widget == (EZ_Widget *)NULL || EZ_GetWidgetNonActiveFlag(widget) != 0)
    return;

  gmanager = EZ_WidgetGManager(widget);
  if(gmanager)
    {
      if(EZ_GMType(gmanager) == EZ_GB_GEOM_MANAGER)
	{
	  EZ_RowColSetChildrenPositionAndSize(widget,w,h);
	  return;
	}
    }
  type = EZ_WidgetType(widget);
  /*-----------------------------------------------------------
   *  Because of the design, 3D_Canvas has to be treated 
   *  differently. 
   *----------------------------------------------------------*/
  cw = EZ_WidgetMinWidth(widget);
  ch = EZ_WidgetMinHeight(widget);  
  if(type == EZ_WIDGET_3D_CANVAS)
    {
      int xsize = w;
      int ysize = h;

      if(!(EZ_GetWidgetWidthSetFlag(widget)))
	{ 
	  xsize  = (xsize > 1024? 1024: ((xsize < 16)? 16: xsize)); 
	  xsize = xsize & ~3;
	  EZ_WidgetWidth(widget) = xsize;
	}
      if(!(EZ_GetWidgetHeightSetFlag(widget)))
	{
	  ysize = (ysize > 1024? 1024:((ysize < 16)? 16: ysize));
	  ysize = ysize & ~3;
	  EZ_WidgetHeight(widget)  = ysize;
	}
      if(EZ_WidgetWindow(widget) != (Window )NULL)
	{
	  /*--------------------------------------
	   * The canvas has already been created.
	   * The possible change of size comes from
	   * a widget reconfiguration or a resizing
	   * of the top level widget. If the size
	   * has really been changed, we have to
	   * reconfigure the canvas.
	   *-------------------------------------*/
	  EZ_Widget *currentCanvas = EZ_CurrentGWindow;  /* current canvas */
	  if(EZ_WindowWidth != xsize || EZ_WindowHeight != ysize)
	    EZ_Configure3DCanvas(widget);
	  if(currentCanvas != widget) EZ_Set3DCanvas(currentCanvas);	  
	}
      if(EZ_WidgetAWidth(widget) > 0) 
	{
	  EZ_WidgetAWidth(widget) = EZ_WidgetWidth(widget);
	  EZ_WidgetAHeight(widget) = EZ_WidgetHeight(widget);
	}
    }
  else /* other kinds of widgets */
    {
      /*-----------------------------------------------------------
       * If the W or H of widget has been specified explicitly,
       * honor that.
       *----------------------------------------------------------*/
      if(!(EZ_GetWidgetWidthSetFlag(widget))) EZ_WidgetWidth(widget)  = w;
      if(!(EZ_GetWidgetHeightSetFlag(widget))) EZ_WidgetHeight(widget)  = h;
    }
  /*----------------------------------------------------------
   * widget has no children, don't need to do anything
   *---------------------------------------------------------*/
  numchildren = EZ_GetNumberOfActiveChildren(widget);
  if(numchildren == 0)  return; 

  bwpadx = EZ_WidgetBorderWidth(widget) + EZ_WidgetPadX(widget) + EZ_WidgetPadB(widget);
  bwpady = EZ_WidgetBorderWidth(widget) + EZ_WidgetPadY(widget) + EZ_WidgetPadB(widget);
  auxxL = EZ_WidgetAuxXLeft(widget);
  auxxR = EZ_WidgetAuxXRight(widget);
  auxxT = auxxL + auxxR;
  auxy = EZ_WidgetAuxY(widget);
  auxy2 = auxy << 1;
  hadjust = EZ_WidgetHAdjust(widget);

  stacking = EZ_WidgetStacking(widget);
  alignment = EZ_WidgetAlignment(widget);
  fillmode = EZ_WidgetFillMode(widget);

  /*------------------------------------------------
   * Reset the position of all descendants
   *-----------------------------------------------*/ 
  tw = EZ_WidgetWidth(widget);      /* the new width  */
  th = EZ_WidgetHeight(widget);     /* the new height */


  /* like "NW gravity":  This has effects only when the set dimension is smaller than
   * the minimal dimension of a parent widget.
   * 
   * With the following 2 lines, the position of children are computed normally, using
   * parent's minimal dimension. (toplevel widgets)
   *
   * Without them, children are squeezed together, may overlaping ... (internal widgets )
   *
   */
  if(tw < cw )
    {
      if(EZ_WidgetParent(widget) == (EZ_Widget *)NULL && EZ_GetWidgetEmbededFlag(widget) == 0)
	tw = cw;
    }
  if(th < ch )
    {
      if(EZ_WidgetParent(widget) == (EZ_Widget *)NULL && EZ_GetWidgetEmbededFlag(widget) == 0)
	th = ch; 
    }

  /*---------------------------------------------
   *  First check to see if any children widget 
   *  need to be stretched.
   *------------------------------------------*/
  if(stacking >= EZ_VERTICAL && stacking <= EZ_VERTICAL_CENTER)
    {
      /* children are stacked vertically, stretch in the horizontal direction */
      children = EZ_WidgetChildren(widget);
      while(children)
	{
	  EZ_WidgetAWidth(children) = 0;
	  if(EZ_GetWidgetExpandFlag(children) != 0 &&
	     EZ_WidgetType(children) < EZ_WIDGET_ITOPLEVEL &&
	     EZ_GetWidgetWidthSetFlag(children) == 0 && 
	     EZ_GetWidgetNonActiveFlag(children) == 0)
	    {
	      int ttt;
	      if(EZ_GetWidgetXSetFlag(children)) ttt = tw - EZ_WidgetOriginX(children) - auxxR;
	      else ttt = tw - auxxT;
	      EZ_WidgetAWidth(children) = ttt;
	      EZ_WidgetAHeight(children) = EZ_WidgetHeight(children);
	      EZ_SetChildrenPositionAndSize(children, ttt, EZ_WidgetHeight(children));
	    }
	  children = EZ_WidgetSibling(children);
	}
    }
  else
    {
      /* children are stacked horizontally, stretch in the vertical direction */
      children = EZ_WidgetChildren(widget);
      while(children)
	{
	  EZ_WidgetAWidth(children) = 0;
	  if(EZ_GetWidgetExpandFlag(children) != 0  &&
	     EZ_WidgetType(children) < EZ_WIDGET_ITOPLEVEL &&
	     EZ_GetWidgetHeightSetFlag(children) == 0 &&
	     EZ_GetWidgetNonActiveFlag(children) == 0)
	    {
	      int ttt;
	      if(EZ_GetWidgetYSetFlag(children)) ttt = th - EZ_WidgetOriginY(children) - auxy;
	      else ttt = th - auxy2 - hadjust;
	      EZ_WidgetAWidth(children) =EZ_WidgetWidth(children);
	      EZ_WidgetAHeight(children) =  ttt;
	      EZ_SetChildrenPositionAndSize(children, EZ_WidgetWidth(children), ttt);
	    }
	  children = EZ_WidgetSibling(children);
	}
    }

  /*---------------------------------------------
   *  If a fill mode is set on this widget, fill 
   *  its scalable children and recompute the
   *  geometry of all children widgets.
   *------------------------------------------*/
  ncWS = EZ_CountWidthScalableChildren(widget);
  ncHS = EZ_CountHeightScalableChildren(widget);

  cw -= EZ_WidgetCW(widget);
  ch -= EZ_WidgetCH(widget);

  switch(fillmode)
    {
    case  EZ_FILL_VERTICALLY:
      if(stacking >= EZ_VERTICAL && stacking <= EZ_VERTICAL_CENTER)
	{
	  if(ncHS > 0)
	    {
	      htmp = (th - ch) / ncHS;
	      if(htmp > 0)
		{
		  int herror = th - ch - ncHS * htmp;
		  EZ_WidgetMinHeight(widget) = th; 
		  EZ_WidgetCH(widget) = 0;
		  children = EZ_WidgetChildren(widget);
		  while(children)
		    {
		      if(EZ_GetWidgetHeightSetFlag(children) == 0 && 
			 EZ_WidgetType(children) < EZ_WIDGET_ITOPLEVEL &&
			 EZ_GetWidgetNonActiveFlag(children) == 0)
			{
			  int tmpwidth = EZ_WidgetWidth(children);
			  int tmpheight = EZ_WidgetHeight(children) + htmp + herror;
			  EZ_WidgetAWidth(children) =tmpwidth;
			  EZ_WidgetAHeight(children) = tmpheight;
			  EZ_SetChildrenPositionAndSize(children, tmpwidth,tmpheight);
			  herror = 0;
			}
		      children = EZ_WidgetSibling(children);
		    }
		}
	    }
	}
      else  /* children are stacked horizontally */
	{
	  htmp = th - (bwpady << 1) - auxy2 - hadjust;
	  children = EZ_WidgetChildren(widget);
	  while(children)
	    {
	      if(EZ_GetWidgetNonActiveFlag(children) == 0 &&
		 EZ_WidgetType(children) < EZ_WIDGET_ITOPLEVEL &&
		 EZ_WidgetHeight(children) < htmp  && 
		 EZ_GetWidgetHeightSetFlag(children) == 0)
		{
		  int tmpwidth = EZ_WidgetWidth(children);
		  int tmpheight = htmp;
		  EZ_WidgetAWidth(children) =tmpwidth;
		  EZ_WidgetAHeight(children) = tmpheight;
		  EZ_SetChildrenPositionAndSize(children, tmpwidth, tmpheight);
		}
	      children = EZ_WidgetSibling(children);
	    }
	}
      break;
    case EZ_FILL_HORIZONTALLY:
      if(stacking >= EZ_HORIZONTAL && stacking <= EZ_HORIZONTAL_CENTER)
	{
	  if(ncWS > 0)
	    {
	      wtmp = (tw - cw) / ncWS;
	      if(wtmp > 0)
		{
		  int werror = tw - cw - ncWS * wtmp;
		  EZ_WidgetMinWidth(widget) = tw; 
		  EZ_WidgetCW(widget) = 0;
		  children = EZ_WidgetChildren(widget);
		  while(children)
		    {
		      if(EZ_GetWidgetWidthSetFlag(children) == 0 && 
			 EZ_WidgetType(children) < EZ_WIDGET_ITOPLEVEL &&
			 EZ_GetWidgetNonActiveFlag(children) == 0)
			{
			  int tmpwidth = EZ_WidgetWidth(children) + wtmp + werror;
			  int tmpheight = EZ_WidgetHeight(children);
			  EZ_WidgetAWidth(children) =tmpwidth;
			  EZ_WidgetAHeight(children) = tmpheight;
			  EZ_SetChildrenPositionAndSize(children, tmpwidth, tmpheight);
			  werror = 0;
			}
		      children = EZ_WidgetSibling(children);
		    }
		}
	    }	      
	}
      else 
	{
	  wtmp = tw - (bwpadx << 1) - auxxT;
	  children = EZ_WidgetChildren(widget);
	  while(children)
	    {
	      if((EZ_GetWidgetNonActiveFlag(children) == 0) &&
		 EZ_WidgetType(children) < EZ_WIDGET_ITOPLEVEL &&
		 EZ_GetWidgetWidthSetFlag(children) == 0 &&
		 EZ_WidgetWidth(children) < wtmp)
		{
		  int tmpwidth = wtmp;
		  int tmpheight = EZ_WidgetHeight(children);
		  EZ_WidgetAWidth(children) =tmpwidth;
		  EZ_WidgetAHeight(children) = tmpheight;
		  EZ_SetChildrenPositionAndSize(children, tmpwidth, tmpheight);
		}
	      children = EZ_WidgetSibling(children);
	    }	      
	}
      break;
    case EZ_FILL_BOTH:
      if(stacking >= EZ_HORIZONTAL && stacking <= EZ_HORIZONTAL_CENTER)
	{
	  int new_width, new_height, werror=0; 
	  
	  htmp = th - (bwpady << 1) - auxy2 - hadjust;
	  if(ncWS > 0)
	    {
	      wtmp = (tw - cw) /ncWS;
	      werror = tw - cw - wtmp * ncWS;
	      EZ_WidgetMinWidth(widget) = tw; 
	      EZ_WidgetCW(widget) = 0;
	    }
	  else wtmp = 0;
	  
	  children = EZ_WidgetChildren(widget);
	  while(children)
	    {
	      if(EZ_GetWidgetNonActiveFlag(children) == 0 &&
		 EZ_WidgetType(children) < EZ_WIDGET_ITOPLEVEL)
		{
		  if(wtmp > 0 || EZ_WidgetHeight(children) < htmp)
		    {
		      new_width = EZ_WidgetWidth(children);
		      new_height = EZ_WidgetHeight(children);
		      
		      if( wtmp > 0 && EZ_GetWidgetWidthSetFlag(children) == 0)
			{ new_width += wtmp + werror; werror = 0; }
		      if(EZ_GetWidgetHeightSetFlag(children) == 0 &&
			 EZ_WidgetHeight(children) < htmp)  new_height = htmp;
		      EZ_WidgetAWidth(children) =new_width;
		      EZ_WidgetAHeight(children) = new_height;		  
		      EZ_SetChildrenPositionAndSize(children,new_width, new_height);
		    }
		}
	      children = EZ_WidgetSibling(children);
	    } 
	}
      else /* if(stacking >= EZ_VERTICAL && stacking <= EZ_VERTICAL_CENTER) */
	{
	  int new_width, new_height, herror;
	  
	  wtmp = tw - (bwpadx << 1) - auxxT;
	  if(ncHS > 0)
	    {
	      htmp = (th - ch) / ncHS;
	      herror = th - ch - ncHS * htmp;
	      EZ_WidgetMinHeight(widget) = th; 
	      EZ_WidgetCH(widget) = 0;
	    }
	  else { htmp = 0; herror = 0; }

	  children = EZ_WidgetChildren(widget);
	  while(children)
	    {
	      if(EZ_GetWidgetNonActiveFlag(children) == 0 &&
		 EZ_WidgetType(children) < EZ_WIDGET_ITOPLEVEL)
		{
		  new_width = EZ_WidgetWidth(children);
		  new_height = EZ_WidgetHeight(children);
		  
		  if(htmp > 0 || EZ_WidgetWidth(children) < wtmp)
		    {
		      if( EZ_GetWidgetWidthSetFlag(children) == 0 &&
			 EZ_WidgetWidth(children) < wtmp) new_width = wtmp;
		      if( htmp > 0 && EZ_GetWidgetHeightSetFlag(children) == 0)
			{ new_height += htmp + herror; herror = 0;}
		      EZ_WidgetAWidth(children) =new_width;
		      EZ_WidgetAHeight(children) = new_height; 
		      EZ_SetChildrenPositionAndSize(children, new_width, new_height);
		    }
		}
	      children = EZ_WidgetSibling(children);
	    } 
	}
      break;
    default:
      break;
    }
      
  /*---------------------------------------------
   * Now compute the position of children widgets
   *---------------------------------------------*/
  cw = EZ_WidgetMinWidth(widget) - EZ_WidgetCW(widget);
  ch = EZ_WidgetMinHeight(widget) - EZ_WidgetCH(widget); 

  sepx = EZ_WidgetSepX(widget);       /* horizontal space between neighboring children */
  sepy = EZ_WidgetSepY(widget);       /* vertical space between neighboring children   */

      
  if(stacking >= EZ_HORIZONTAL && stacking <= EZ_HORIZONTAL_CENTER)
    {                           /* Children are stacked horizontally */
      dx = 0.0;
      if(stacking == EZ_HORIZONTAL_LEFT)         x0 = 0.0;
      else if(stacking == EZ_HORIZONTAL_RIGHT)   x0 = (float)(tw - cw);
      else if(stacking == EZ_HORIZONTAL_CENTER)  x0 = 0.5* (tw - cw);
      else
	{
	  dx = (float)(tw - cw)/((float)numchildren + 1.0);
	  x0 = dx;
	}
      x0 += (float)(bwpadx + auxxL);    /* starting  X  */
      dx += (float)sepx;  
      xx = 0.0;
      children = EZ_WidgetChildren(widget);
      while(children)
	{
	  if(EZ_GetWidgetNonActiveFlag(children) == 0 &&
	     EZ_WidgetType(children) < EZ_WIDGET_ITOPLEVEL)
	    {
	      if(alignment == EZ_TOP_ALIGNED) 
		yy = (float)(bwpady + auxy + hadjust);
	      else if(alignment == EZ_BOTTOM_ALIGNED)  
		yy = (float)( th - EZ_WidgetHeight(children) - bwpady - auxy);
	      else   
		yy = 0.5*(float)(th + hadjust - EZ_WidgetHeight(children));
	      
	      if(EZ_GetWidgetXSetFlag(children) == 0)
		EZ_WidgetOriginX(children) =  (int) (xx + x0);
	      if(EZ_GetWidgetYSetFlag(children) == 0)	      
		{
		  if(EZ_GetWidgetExpandFlag(children) != 0  &&
		     EZ_GetWidgetHeightSetFlag(children) == 0)
		    EZ_WidgetOriginY(children) = auxy + hadjust;
		  else 	EZ_WidgetOriginY(children) =  (int) (yy);
		}
	      xx += (dx + EZ_WidgetWidth(children)); 
	    }
	  children = EZ_WidgetSibling(children);
	}
    }
  /* Children are stacked vertically */
  else /* stacking >= EZ_VERTICAL && stacking <= EZ_VERTICAL_CENTER */
    {
      dy = 0.0;
      if(stacking == EZ_VERTICAL_TOP)           y0 = 0.0;
      else if(stacking == EZ_VERTICAL_BOTTOM)   y0 = (float)(th - ch);
      else if(stacking == EZ_VERTICAL_CENTER)   y0 = 0.5 * (th - ch);
      else
	{
	  dy = (float)(th - ch)/((float)numchildren + 1.0);
	  y0 = dy;
	}
      y0 += (float)(bwpady + hadjust + auxy);       /* Starting Y */
      dy += (float) sepy; 
      yy = 0.0;
      children = EZ_WidgetChildren(widget);
      while(children)
	{
	  if(EZ_GetWidgetNonActiveFlag(children) == 0 &&
	     EZ_WidgetType(children) < EZ_WIDGET_ITOPLEVEL )
	    {
	      if(alignment == EZ_LEFT_ALIGNED)
  		xx = (float)(bwpadx + auxxL);
	      else if(alignment == EZ_RIGHT_ALIGNED)  
		xx = (float)( tw -  EZ_WidgetWidth(children) - bwpadx - auxxR);
	      else     
		xx = 0.5*(tw + auxxL - auxxR - EZ_WidgetWidth(children));

	      if(EZ_GetWidgetXSetFlag(children) == 0)	      
		{
		  if(EZ_GetWidgetExpandFlag(children) != 0  &&
		     EZ_GetWidgetWidthSetFlag(children) == 0)
		    EZ_WidgetOriginX(children) = auxxL;
		  else 	EZ_WidgetOriginX(children) = (int) (xx);
		}
	      if(EZ_GetWidgetYSetFlag(children) == 0)
		EZ_WidgetOriginY(children) = (int) (yy + y0);
	      yy += (dy + EZ_WidgetHeight(children)); 
	    }
	  children = EZ_WidgetSibling(children);
	}
    }
}

/****************************************************************************
 *
 *  Count the number of children of widget whose width/height may be streched.
 */
static int EZ_CountWidthScalableChildren(widget)
     EZ_Widget *widget;
{
  EZ_Widget *child;
  int              count = 0;
  
  if(widget == (EZ_Widget *)NULL) return(0);
  
  child = EZ_WidgetChildren(widget);
  
  while(child != (EZ_Widget *)NULL)
    {
      if(EZ_GetWidgetNonActiveFlag(child) == 0 && 
	 EZ_WidgetType(child) < EZ_WIDGET_ITOPLEVEL &&
	 EZ_GetWidgetWidthSetFlag(child) == 0 ) count++;
      child = EZ_WidgetSibling(child);
    }
  return(count);
}

static int EZ_CountHeightScalableChildren(widget)
     EZ_Widget *widget;
{
  EZ_Widget *child;
  int              count = 0;
  
  if(widget == (EZ_Widget *)NULL) return(0);
  
  child = EZ_WidgetChildren(widget);
  
  while(child != (EZ_Widget *)NULL)
    {
      if( EZ_GetWidgetNonActiveFlag(child) == 0 &&
	 EZ_WidgetType(child) < EZ_WIDGET_ITOPLEVEL &&
	 EZ_GetWidgetHeightSetFlag(child) == 0 ) count++;
      child = EZ_WidgetSibling(child);
    }
  return(count);
}
/*************************************************************************************
 *
 *  Return the number of active children of widget
 */
static int EZ_GetNumberOfActiveChildren(widget)
     EZ_Widget *widget;     
{
  EZ_Widget *child;
  int             count = 0;
  
  if(widget == (EZ_Widget *)NULL) return(0);
  
  child = EZ_WidgetChildren(widget);

  while(child != (EZ_Widget *)NULL)
    {
      if(EZ_GetWidgetNonActiveFlag(child) == 0 &&
	 EZ_WidgetType(child) < EZ_WIDGET_ITOPLEVEL)
	count++;
      child = EZ_WidgetSibling(child);
    }  
  return(count);
}
/*************************************************************************************/
#undef _EZ_WIDGET_GEOM_C_
