/*********************************************************************
 *
 *         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
 */
/*****************************************************************
 ***                                                           ***
 ***              Widget H and V Slider                        ***
 ***                                                           ***
 *****************************************************************/
#define _EZ_WIDGET_SLIDER_C_

#include "EZ_Widget.h"

/*********************************************************************
 * 
 *  Functions implemented in this file:
 */
EZ_Widget   *EZ_CreateSlider  MY_ANSIARGS((EZ_Widget *parent, char *lab, 
					   float mnv, float mxv, float initv, int type));
void         EZ_SliserEventHandle  MY_ANSIARGS((EZ_Widget *widget, XEvent *event));
void         EZ_SetSliderValue  MY_ANSIARGS((EZ_Widget *widget, float value));
float        EZ_GetSliderValue  MY_ANSIARGS((EZ_Widget *widget));

void         EZ_ComputeWidgetHSliderSize  MY_ANSIARGS((EZ_Widget *widget, int *w, int *h));
void         EZ_ComputeWidgetVSliderSize  MY_ANSIARGS((EZ_Widget *widget, int *w, int *h));
void         EZ_DrawWidgetHorizontalSlider  MY_ANSIARGS((EZ_Widget *widget));
void         EZ_DrawWidgetVerticalSlider MY_ANSIARGS((EZ_Widget *widget));
void         EZ_FreeWidgetSliderData  MY_ANSIARGS((EZ_Widget *widget));
void         EZ_SetSliderRange MY_ANSIARGS((EZ_Widget *widget, float f, float t));
/*********************************************************************
 * 
 *  Local functions:
 */
static void         EZ_SetSliderFormat  MY_ANSIARGS((EZ_Widget *widget));
static void         EZ_InitialHSliderInternalData  MY_ANSIARGS((EZ_Widget *widget, int w, int h));
static void         EZ_InitialVSliderInternalData  MY_ANSIARGS((EZ_Widget *widget, int w, int h));
static void         EZ_FixSliderValue MY_ANSIARGS((EZ_Widget *widget));

/*********************************************************************
 * 
 *  Local Variables.
 */
static EZ_WidgetHandle EZ_HSliderHandle =
{
  EZ_ComputeWidgetHSliderSize,
  EZ_DrawWidgetHorizontalSlider,
  EZ_FreeWidgetSliderData,
  EZ_SliserEventHandle,
};

static EZ_WidgetHandle EZ_VSliderHandle =
{
  EZ_ComputeWidgetVSliderSize,
  EZ_DrawWidgetVerticalSlider,
  EZ_FreeWidgetSliderData,
  EZ_SliserEventHandle,
};

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

EZ_Widget  *EZ_CreateSlider(parent,label, minvalue, maxvalue, init_v, type)
     EZ_Widget  *parent;     /* parent widget    */
     char             *label;
     float            minvalue, maxvalue, init_v;
     int              type;
{
  EZ_Widget  *wptr;

  wptr = EZ_CreateNewWidget(parent);
  EZ_SetWidgetTypeAndNames(wptr, type);
  /*--------------------------------------------
   * This is a hack. For HSlider, we really
   * don't want the width be modified when
   * a fill mode is set on its parent.
   * For VSlider, we don't want the width be
   * modified.
   *------------------------------------------*/
  if(type == EZ_WIDGET_HORIZONTAL_SLIDER) 
    {
      /*--------------------------------------------------
       * Register the handling functions for ...
       *  has to be done after  EZ_CreateNewWiget.
       *-------------------------------------------------*/
      EZ_WidgetHandlingFunctions[EZ_WIDGET_HORIZONTAL_SLIDER] = &EZ_HSliderHandle;
      EZ_SetWidgetHeightSetFlag(wptr); 
    }
  else
    {
      /*--------------------------------------------------
       * Register the handling functions for ...
       *  has to be done after  EZ_CreateNewWiget.
       *-------------------------------------------------*/
      EZ_WidgetHandlingFunctions[EZ_WIDGET_VERTICAL_SLIDER] = &EZ_VSliderHandle;
      EZ_SetWidgetWidthSetFlag(wptr);
    }
      
  if(label != (char *)NULL)
    {
      EZ_SliderLabel(wptr) = EZ_AllocCopyString(label);
      EZ_SliderLabelLength(wptr) = strlen(label);
    }
  else
    {
      EZ_SliderLabel(wptr) = (char *)NULL;
      EZ_SliderLabelLength(wptr) = 0;
    }
  EZ_SliderFont(wptr) = EZ_GetFontFromId(EZ_SLIDER_FONT);
  EZ_WidgetBorderStyle(wptr)  = EZ_BORDER_NONE;
  EZ_WidgetPadB(wptr) = 2;  

  EZ_SliderTWidth(wptr)     = 0;
  EZ_SliderTHeight(wptr)    = 0;
  EZ_SliderFontAscent(wptr) = 0;

  EZ_SliderWidth(wptr) = 16;           /* default size of slider */
  EZ_SliderLength(wptr) = 100;
  EZ_SliderSliderLength(wptr) = 32;

  EZ_SliderResolution(wptr) = -1.0;

  EZ_SliderBorderWidth(wptr) = 2;
  EZ_SliderBorderStyle(wptr) = EZ_BORDER_UP;

  EZ_SliderMinValue(wptr) = minvalue;
  EZ_SliderMaxValue(wptr) = maxvalue;
  EZ_SliderValue(wptr) = init_v;
  EZ_SliderPosition(wptr) = 0;     /* to be computed */

  EZ_SliderDisplayValue(wptr) = 1;
  EZ_SliderVWidth(wptr) = 0;
  EZ_SliderVWidtha(wptr) = 0;

  EZ_SliderFormat(wptr)[0] = '\0';
  EZ_SliderWidthSet(wptr) = 0;
  EZ_SliderLengthSet(wptr) = 0;

  EZ_SetWidgetFocusableFlag(wptr);  

  return(wptr);
}

void   EZ_FreeWidgetSliderData(widget)
     EZ_Widget *widget;
{
  if(EZ_SliderLabel(widget) != (char *)NULL)
    (void) my_free( (char *) EZ_SliderLabel(widget));
}

/********************************************************************
 *
 *  Figure out the dimension of a horizontal slider
 */
void EZ_ComputeWidgetHSliderSize(widget, w, h)
    EZ_Widget *widget;
     int             *w, *h;
{
  int length, height, cw, ch,bs,ss, tmp;

  bs = (EZ_SliderLabel(widget) != (char *)NULL) ? 2 : 0;
  ss = (EZ_SliderDisplayValue(widget) != 0) ? 2 : 0;
  if(!(EZ_GetWidgetSizeComputedFlag(widget)))
    { 
      /* 6.3.96 */
      /* make sure slider button is big enough */
      tmp = ( (EZ_SliderBorderWidth(widget))<< 1) + 4;
      if(EZ_SliderWidth(widget) < tmp) EZ_SliderWidth(widget) =  tmp;
      if(EZ_SliderSliderLength(widget) < tmp + tmp) EZ_SliderSliderLength(widget) = tmp + tmp;

      if( EZ_SliderLabel(widget) != (char *)NULL)
	{
	  EZ_SliderTWidth(widget) = XTextWidth(EZ_SliderFont(widget),
					       EZ_SliderLabel(widget),
					       EZ_SliderLabelLength(widget));
	  EZ_SliderTHeight(widget) = EZ_SliderFont(widget)->ascent +
	    EZ_SliderFont(widget)->descent;
	  EZ_SliderFontAscent(widget) = EZ_SliderFont(widget)->ascent;
	}
      if(EZ_SliderDisplayValue(widget))
	{
	  char tmp[32];
	  int  itmp1,itmp2, itmp3;

	  EZ_SetSliderFormat(widget); 
	  (void)sprintf(tmp, EZ_SliderFormat(widget), EZ_SliderMaxValue(widget));
	  itmp1 = EZ_SliderVWidth(widget) = XTextWidth(EZ_SliderFont(widget),
						       tmp,
						       strlen(tmp));

	  (void)sprintf(tmp, EZ_SliderFormat(widget), EZ_SliderMinValue(widget));
	  itmp2 = EZ_SliderVWidtha(widget) = XTextWidth(EZ_SliderFont(widget),
							tmp,
							strlen(tmp));

	  EZ_SliderVHeight(widget) = EZ_SliderFont(widget)->ascent +
	    EZ_SliderFont(widget)->descent;
	  EZ_SliderFontAscent(widget) = EZ_SliderFont(widget)->ascent;
	  
	  itmp3 = (MAXV(itmp1,itmp2)>>1) + 1;
	  if(EZ_SliderSliderLength(widget) < itmp3)
	    EZ_SliderSliderLength(widget) = itmp3;
	}
      EZ_SetWidgetSizeComputedFlag(widget);
    }

  length = EZ_SliderTWidth(widget) + 
    ((EZ_SliderVWidth(widget) + EZ_SliderVWidtha(widget)) << 1)
      + EZ_SliderSliderLength(widget) + 4;
  height = EZ_SliderTHeight(widget) + ((EZ_SliderVHeight(widget)) << 1) + bs + (ss<<1); 
  EZ_SliderLength(widget) = length; 
  
  cw = EZ_WidgetPadX(widget) + EZ_WidgetBorderWidth(widget) + EZ_WidgetPadB(widget) 
    + EZ_SliderBorderWidth(widget) ;
  ch = EZ_WidgetPadY(widget) + EZ_WidgetBorderWidth(widget) + EZ_WidgetPadB(widget)
    + EZ_SliderBorderWidth(widget);

  /*-------------------------------
   *  minimal size of the X window
   *------------------------------*/
  ch = ch + ch + EZ_SliderWidth(widget) + height;
  cw = cw + cw + EZ_SliderLength(widget);
  *w = cw;
  *h = ch;

  EZ_InitialHSliderInternalData(widget,cw,ch);
}	  

/*******************************************************************************
 *
 *  Initialize H slider internal data.
 */

static void EZ_InitialHSliderInternalData(widget,w,h)
     EZ_Widget *widget;
     int             w,h;
{
  int cw, ch, padb, sl, tmp,bs,ss;

  padb = EZ_WidgetPadB(widget);
  bs = (EZ_SliderLabel(widget) != (char *)NULL) ? 2 : 0;
  ss = (EZ_SliderDisplayValue(widget) != 0) ? 2 : 0;

  cw = EZ_WidgetPadX(widget) + EZ_WidgetBorderWidth(widget) + EZ_SliderBorderWidth(widget) + padb;
  ch = EZ_WidgetPadY(widget) + EZ_WidgetBorderWidth(widget) + EZ_SliderBorderWidth(widget) + padb;

  sl = EZ_SliderLength(widget) = w - (cw <<1);

  if(!EZ_SliderWidthSet(widget))
    EZ_SliderWidth(widget) = ( h - ((ch <<1) + bs + (ss<<1) + EZ_SliderTHeight(widget)
					   + (EZ_SliderVHeight(widget)<<1)));

  /*-----------------------------------------------
   * min scrn coor of slider and the slider window
   *----------------------------------------------*/
  EZ_SliderPositionMin(widget) = cw + (EZ_SliderSliderLength(widget)>>1);
  EZ_SliderMinx(widget) = cw;
  EZ_SliderMaxx(widget) = cw + EZ_SliderLength(widget);
  EZ_SliderMiny(widget) = ch + EZ_SliderTHeight(widget) + EZ_SliderVHeight(widget) + bs + ss;
  EZ_SliderMaxy(widget) = h - ch - EZ_SliderVHeight(widget) - ss;

  /*--------------------------
   * compute scaling factor
   *--------------------------*/
  if( (tmp = (sl - EZ_SliderSliderLength(widget))) <= 0) tmp = 1;
  EZ_SliderFactor(widget) = (EZ_SliderMaxValue(widget) - EZ_SliderMinValue(widget))/
      (float)tmp;
  /*-------------------------------------------
   * Set initial slider position 
   *------------------------------------------*/
  EZ_SliderPosition(widget) = (int)
    (EZ_SliderPositionMin(widget) +
     (EZ_SliderValue(widget) -EZ_SliderMinValue(widget))/EZ_SliderFactor(widget));
}


/***************************************************************
 *
 *  Figure out the precision needed to display the slider value
 */

static void EZ_SetSliderFormat(wptr)
     EZ_Widget *wptr;
{
  double fa,fb, ftmp;
  int    maxdigits, resolutiondigits, digits, itmp;

  fa = fabs(EZ_SliderMaxValue(wptr));
  fb = fabs(EZ_SliderMinValue(wptr));
  if(fa == 0.0) fa = 1.0;
  if(fb == 0.0) fb = 1.0;
  if(fa > fb) { ftmp = fa; fa = fb; fb = ftmp;}
  maxdigits = floor(log10(fa)); 
  digits = floor(log10(fb));
  maxdigits = (abs(digits) > abs(maxdigits)? digits: maxdigits);


  if(EZ_SliderResolution(wptr) > 0.0)
    resolutiondigits = floor(log10(EZ_SliderResolution(wptr))) + 1;
  else
    {
      ftmp = (float) EZ_SliderLength(wptr);
      fa = fabs(EZ_SliderMaxValue(wptr) - EZ_SliderMinValue(wptr))/ftmp;
      resolutiondigits = floor(log10(fa));
    }
  digits = (maxdigits - resolutiondigits) + 1;   
  /* this is the number of digits needed */

  itmp = digits - maxdigits;  /* digits for fractional part */
  if(itmp < 0) itmp  = 0;
  (void) sprintf(EZ_SliderFormat(wptr), "%%.%df", itmp);
}  

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

void  EZ_DrawWidgetHorizontalSlider(wptr)
     EZ_Widget *wptr;
{
  int             w, h,x,y,xx,yy, ww, hh, cw,ch,bs,ss, padb, padb2, filled = 0;
  Pixmap          pixmap;
  Window          win;
  GC              gc, gc1, junkgc;
  int             offset = 0;
  unsigned long   bgpv, bgpva;

  win = EZ_WidgetWindow(wptr);
  w   = EZ_WidgetWidth(wptr);
  h   = EZ_WidgetHeight(wptr);
  padb = EZ_WidgetPadB(wptr);
  padb2 = padb + padb;

  bs = (EZ_SliderLabel(wptr) != (char *)NULL)? 2 : 0;
  ss = (EZ_SliderDisplayValue(wptr) != 0) ? 2 : 0;

  if(EZ_WidgetSizeMayBeChandedFlag(wptr))
    {
      EZ_InitialHSliderInternalData(wptr,w,h);
      EZ_ClearWidgetSizeMayBeChandedFlag(wptr);
    }
  /*-----------------------------------------------------------
   *  Create a pixmap, draw into this pixmap in background and
   *  copy to the button window when finished.
   *----------------------------------------------------------*/
  pixmap = XCreatePixmap(EZ_DisplayForWidgets, win, w, h, EZ_DepthForWidgets);    
  if(padb > 0)
    {
      EZ_GetParentBgGCN(wptr, &gc,&bgpva);
      XFillRectangle(EZ_DisplayForWidgets, pixmap, gc, 0,0, w, h); 
      filled = 1;
    }
  else bgpva = 0;  
  EZ_GetBackgroundGC(wptr, &gc, &bgpv,0, 0);
  if(filled == 0 || bgpv != bgpva)
    XFillRectangle(EZ_Display, pixmap, gc, padb,padb, w-padb2, h-padb2); 

  cw = EZ_WidgetBorderWidth(wptr) + EZ_WidgetPadX(wptr) + padb;
  ch = EZ_WidgetBorderWidth(wptr) + EZ_WidgetPadY(wptr) + padb;
  /*--------------------------------------------------------
   *  Draw label and values.
   *-------------------------------------------------------*/
  if(EZ_SliderDisplayValue(wptr) || EZ_SliderLabel(wptr) != (char *)NULL)
    {
      if( EZ_GetWidgetDisabledFlag(wptr) )
	{
	  GC  bgc, lgc, ngc;
	  EZ_GetDarkBrightNormalBDGC(wptr, &bgc, &lgc, &ngc);
	  XSetFont(EZ_DisplayForWidgets, bgc, EZ_WidgetFont(wptr)->fid);
	  XSetFont(EZ_DisplayForWidgets, lgc, EZ_WidgetFont(wptr)->fid);
	  XSetFont(EZ_DisplayForWidgets, ngc, EZ_WidgetFont(wptr)->fid);

	  if(EZ_SliderLabel(wptr) != (char *)NULL)
	    {
	      x = ( (w  - EZ_SliderTWidth(wptr)) >> 1);
	      y =  EZ_SliderFontAscent(wptr) + ch;
	      XDrawString(EZ_DisplayForWidgets, pixmap, bgc,
			  x+1, y+1,
			  EZ_SliderLabel(wptr),
			  EZ_SliderLabelLength(wptr));
	      XDrawString(EZ_DisplayForWidgets, pixmap, lgc,
			  x-1, y-1,
			  EZ_SliderLabel(wptr),
			  EZ_SliderLabelLength(wptr));
	      XDrawString(EZ_DisplayForWidgets, pixmap, ngc,
			  x, y,
			  EZ_SliderLabel(wptr),
			  EZ_SliderLabelLength(wptr));
	    }
	  if(EZ_SliderDisplayValue(wptr))
	    {
	      char tmp[32];

	      (void) sprintf(tmp, EZ_SliderFormat(wptr),EZ_SliderMinValue(wptr));
	      x =  EZ_SliderPositionMin(wptr)  - (EZ_SliderVWidtha(wptr)>>1);
	      y =  EZ_SliderTHeight(wptr) + EZ_SliderFontAscent(wptr)  + ch + bs;
	      XDrawString(EZ_DisplayForWidgets, pixmap, bgc,
			  x+1, y+1,  tmp,  strlen(tmp));
	      XDrawString(EZ_DisplayForWidgets, pixmap,lgc,
			  x-1, y-1, tmp,  strlen(tmp));
	      XDrawString(EZ_DisplayForWidgets, pixmap,gc,
			  x, y, tmp,  strlen(tmp));

	      (void) sprintf(tmp, EZ_SliderFormat(wptr),EZ_SliderMaxValue(wptr));
	      x =  EZ_SliderMaxx(wptr) - ((EZ_SliderSliderLength(wptr)+EZ_SliderVWidth(wptr))>>1);
	      XDrawString(EZ_DisplayForWidgets, pixmap, bgc,
			  x+1, y+1,  tmp,  strlen(tmp));
	      XDrawString(EZ_DisplayForWidgets, pixmap, lgc,
			  x-1, y-1,  tmp,  strlen(tmp));
	      XDrawString(EZ_DisplayForWidgets, pixmap, ngc,
			  x, y,  tmp,  strlen(tmp));

	      (void) sprintf(tmp, EZ_SliderFormat(wptr),EZ_SliderValue(wptr)); 
	      x =  EZ_SliderPosition(wptr) - (EZ_SliderVWidth(wptr)>>1);
	      y =  h - (ch + EZ_SliderVHeight(wptr) - EZ_SliderFontAscent(wptr)) + ss;
	      XDrawString(EZ_DisplayForWidgets, pixmap, bgc,
			  x+1, y+1,  tmp,  strlen(tmp));	  
	      XDrawString(EZ_DisplayForWidgets, pixmap, lgc,
			  x-1, y-1,  tmp,  strlen(tmp));	  
	      XDrawString(EZ_DisplayForWidgets, pixmap, ngc,
			  x, y,  tmp,  strlen(tmp));	  
	    }
	}
      else
	{
	  if(EZ_SliderForeground(wptr) != EZ_DefaultForeground || 
	     EZ_SliderFont(wptr) != EZ_GetFontFromId(EZ_BUTTON_FONT))
	    {
	      XSetFont(EZ_DisplayForWidgets, EZ_WRITABLEGC, EZ_SliderFont(wptr)->fid);
	      XSetForeground(EZ_DisplayForWidgets, EZ_WRITABLEGC, EZ_SliderForeground(wptr));	
	      gc = EZ_WRITABLEGC;
	    }
	  else  gc = EZ_BUTTON_TEXTGC;
	  
	  if(EZ_SliderLabel(wptr) != (char *)NULL)
	    {
	      x = ( (w  - EZ_SliderTWidth(wptr)) >> 1);
	      y =  EZ_SliderFontAscent(wptr) + ch;
	      XDrawString(EZ_DisplayForWidgets, pixmap, gc, 
			  x, y,
			  EZ_SliderLabel(wptr),
			  EZ_SliderLabelLength(wptr));
	    }
	  if(EZ_SliderDisplayValue(wptr))
	    {
	      char tmp[32];

	      (void) sprintf(tmp, EZ_SliderFormat(wptr),EZ_SliderMinValue(wptr));
	      x =  EZ_SliderPositionMin(wptr)  - (EZ_SliderVWidtha(wptr)>>1);
	      y =  EZ_SliderTHeight(wptr) + EZ_SliderFontAscent(wptr)  + ch + bs;
	      XDrawString(EZ_DisplayForWidgets, pixmap, gc, 
			  x, y,
			  tmp,
			  strlen(tmp));

	      (void) sprintf(tmp, EZ_SliderFormat(wptr),EZ_SliderMaxValue(wptr));
	      x =  EZ_SliderMaxx(wptr) - ((EZ_SliderSliderLength(wptr)+EZ_SliderVWidth(wptr))>>1);
	      XDrawString(EZ_DisplayForWidgets, pixmap, gc, 
			  x, y,
			  tmp,
			  strlen(tmp));

	      (void) sprintf(tmp, EZ_SliderFormat(wptr),EZ_SliderValue(wptr)); 
	      x =  EZ_SliderPosition(wptr) - (EZ_SliderVWidth(wptr)>>1);
	      y =  h - (ch + EZ_SliderVHeight(wptr) - EZ_SliderFontAscent(wptr)) + ss;
	      XDrawString(EZ_DisplayForWidgets, pixmap, gc, 
			  x, y,
			  tmp,
			  strlen(tmp));	  
	    }
	}
    }
  /*---------------------------------------------------------
   *     Draw the slider.
   *--------------------------------------------------------*/
  x = cw;
  y = ch + bs + ss + EZ_SliderTHeight(wptr) + EZ_SliderVHeight(wptr);

  ww = EZ_SliderLength(wptr);
  hh = EZ_SliderWidth(wptr);

  EZ_DrawRectBorderWithSize(wptr, pixmap, x,y,
			    ww + (EZ_SliderBorderWidth(wptr)<< 1),
			    hh + (EZ_SliderBorderWidth(wptr)<< 1),
			    EZ_SliderBorderWidth(wptr),
			    EZ_BORDER_DOWN);

  x =  EZ_SliderPosition(wptr) - (EZ_SliderSliderLength(wptr)>>1);
  y += EZ_SliderBorderWidth(wptr);


  EZ_GetBackgroundGC(wptr, &gc, &bgpv,1, 0);
  XFillRectangle(EZ_DisplayForWidgets, pixmap, gc,
		 x, y,
		 EZ_SliderSliderLength(wptr), hh);
  if(EZ_SliderBorderStyle(wptr) == EZ_BORDER_DOWN) offset = 1;

  xx = EZ_SliderPosition(wptr) + offset - 1;
  yy = y + offset +EZ_SliderBorderWidth(wptr);
  EZ_GetDarkBrightNormalBDGC(wptr, &gc, &gc1, &junkgc);
  XDrawLine(EZ_DisplayForWidgets,pixmap, gc,
	    xx, yy,
	    xx, yy+ EZ_SliderWidth(wptr) - (EZ_SliderBorderWidth(wptr)<<1));
  XDrawLine(EZ_DisplayForWidgets,pixmap, gc1,
	    xx+2, yy,
	    xx+2, yy+ EZ_SliderWidth(wptr) - (EZ_SliderBorderWidth(wptr)<<1));

  EZ_DrawRectBorderWithSize(wptr, pixmap, 
			    x,
			    y,
			    EZ_SliderSliderLength(wptr),
			    hh,
			    EZ_SliderBorderWidth(wptr),
			    EZ_SliderBorderStyle(wptr));

  EZ_DrawRectBorder(wptr, pixmap);

  XCopyArea(EZ_DisplayForWidgets,pixmap,win, EZ_WRITABLEGC,0,0,w,h,0,0); 
  XFreePixmap(EZ_DisplayForWidgets, pixmap);                             
}

/********************************************************************
 *
 *  Figure out the dimension of a vertical slider
 */
void EZ_ComputeWidgetVSliderSize(widget, w, h)
    EZ_Widget *widget;
     int             *w, *h;
{
  int length, width, cw, ch,itmp1,itmp2, bs,ss, tmp;

  bs = (EZ_SliderLabel(widget) != (char *)NULL)? 2 : 0;
  ss = (EZ_SliderDisplayValue(widget) != 0) ? 2 : 0;

  if(!(EZ_GetWidgetSizeComputedFlag(widget)))
    { 
      tmp = ( (EZ_SliderBorderWidth(widget))<< 1) + 4;
      if(EZ_SliderWidth(widget) < tmp) EZ_SliderWidth(widget) =  tmp;
      if(EZ_SliderSliderLength(widget) < tmp + tmp) EZ_SliderSliderLength(widget) = tmp + tmp;

      if( EZ_SliderLabel(widget) != (char *)NULL)
	{
	  EZ_SliderTWidth(widget) = XTextWidth(EZ_SliderFont(widget),
					       EZ_SliderLabel(widget),
					       EZ_SliderLabelLength(widget));
	  EZ_SliderTHeight(widget) = EZ_SliderFont(widget)->ascent +
	    EZ_SliderFont(widget)->descent;
	  EZ_SliderFontAscent(widget) = EZ_SliderFont(widget)->ascent;
	}
      if(EZ_SliderDisplayValue(widget))
	{
	  char tmp[32];

	  EZ_SetSliderFormat(widget); 
	  (void)sprintf(tmp, EZ_SliderFormat(widget), EZ_SliderMaxValue(widget));
	  EZ_SliderVWidth(widget) = XTextWidth(EZ_SliderFont(widget),
					       tmp,
					       strlen(tmp));
	  (void)sprintf(tmp, EZ_SliderFormat(widget), EZ_SliderMinValue(widget));
	  EZ_SliderVWidtha(widget) = XTextWidth(EZ_SliderFont(widget),
						tmp,
						strlen(tmp));

	  EZ_SliderVHeight(widget) = EZ_SliderFont(widget)->ascent +
	    EZ_SliderFont(widget)->descent;
	  EZ_SliderFontAscent(widget) = EZ_SliderFont(widget)->ascent;
	}
      EZ_SetWidgetSizeComputedFlag(widget);
    }
  itmp1 = EZ_SliderTWidth(widget);
  itmp2 = (MAXV(EZ_SliderVWidth(widget), EZ_SliderVWidtha(widget)) <<1) + EZ_SliderWidth(widget) + (ss<<1);
  width = MAXV(itmp1,itmp2);
  length = EZ_SliderTHeight(widget) + EZ_SliderSliderLength(widget) + 4 + (EZ_SliderVHeight(widget)<<1);

  EZ_SliderLength(widget) = length;
  
  cw = EZ_WidgetPadX(widget) + EZ_WidgetBorderWidth(widget) + EZ_WidgetPadB(widget)
    + EZ_SliderBorderWidth(widget) ;
  ch = EZ_WidgetPadY(widget) + EZ_WidgetBorderWidth(widget) + EZ_WidgetPadB(widget)
    + EZ_SliderBorderWidth(widget);

  
  /*----------------------------
   *  Dimension of the X window
   *----------------------------*/
  ch = ch + ch + EZ_SliderLength(widget) +  EZ_SliderTHeight(widget) + bs;
  cw = cw + cw + width;

  *w = cw;
  *h = ch;
  EZ_InitialVSliderInternalData(widget,cw,ch);
}

/**********************************************************************************
 *
 *  Initialize the internal data for a V slider.
 */
static void  EZ_InitialVSliderInternalData(widget,w,h)
     EZ_Widget *widget;
     int             w,h;
{
  int cw, ch, sl, tmp,itmp1,itmp2, bs,ss,padb;

  bs = (EZ_SliderLabel(widget) != (char *)NULL)? 2 : 0;
  ss = (EZ_SliderDisplayValue(widget) != 0) ? 2 : 0;
  padb = EZ_WidgetPadB(widget);

  cw = padb+ EZ_WidgetPadX(widget) + EZ_WidgetBorderWidth(widget) + EZ_SliderBorderWidth(widget) ;
  ch = padb +EZ_WidgetPadY(widget) + EZ_WidgetBorderWidth(widget) + EZ_SliderBorderWidth(widget);

  sl = EZ_SliderLength(widget) = h - (ch <<1) - bs - EZ_SliderTHeight(widget);
  itmp1 = EZ_SliderVWidth(widget);
  itmp2 = EZ_SliderVWidtha(widget);
  tmp = MAXV(itmp1,itmp2);
  if(!EZ_SliderWidthSet(widget))
    {
      if(bs == 0) /* no label */
	EZ_SliderWidth(widget) = w - ((tmp + cw) << 1);
      else EZ_SliderWidth(widget) = ( EZ_SliderSliderLength(widget)>>1);
    }

 /*-----------------------------------------------
   * min scrn coor of slider and the slider window
   *----------------------------------------------*/
  EZ_SliderPositionMin(widget) = ch + EZ_SliderTHeight(widget) + (EZ_SliderSliderLength(widget)>>1) + bs;
  EZ_SliderMinx(widget) = ((w -EZ_SliderWidth(widget)) >>1);
  EZ_SliderMaxx(widget) = ((w +EZ_SliderWidth(widget)) >>1);
  EZ_SliderMiny(widget) = EZ_SliderPositionMin(widget) -  (EZ_SliderSliderLength(widget)>>1);
  EZ_SliderMaxy(widget) = h - ch;
  
  /*--------------------------
   * compute scaling factor
   *--------------------------*/
  if( (tmp = (sl - EZ_SliderSliderLength(widget))) <= 0) tmp = 1;
  EZ_SliderFactor(widget) = (EZ_SliderMaxValue(widget) - EZ_SliderMinValue(widget))/
    (float)tmp;

  /*-------------------------------------------
   * Set initial slider position
   *------------------------------------------*/
  EZ_SliderPosition(widget) = (int)
    (EZ_SliderPositionMin(widget) +
     (EZ_SliderValue(widget) -EZ_SliderMinValue(widget))/EZ_SliderFactor(widget));
}	  

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

void  EZ_DrawWidgetVerticalSlider(wptr)
     EZ_Widget *wptr;
{
  int             w, h,x,y,xx,yy, ww, hh, ch,cw,bs,ss, padb,padb2, filled = 0;
  Pixmap          pixmap;
  Window          win;
  GC              gc, gc1, junkgc;
  int             offset = 0;
  unsigned long   bgpv, bgpva;

  win = EZ_WidgetWindow(wptr);
  w   = EZ_WidgetWidth(wptr);
  h   = EZ_WidgetHeight(wptr);
  padb = EZ_WidgetPadB(wptr);
  padb2 = padb + padb;

  bs = (EZ_SliderLabel(wptr) != (char *)NULL)? 2 : 0;
  ss = (EZ_SliderDisplayValue(wptr) != 0) ? 2 : 0;

  if(EZ_WidgetSizeMayBeChandedFlag(wptr))
    {
      EZ_InitialVSliderInternalData(wptr,w,h);
      EZ_ClearWidgetSizeMayBeChandedFlag(wptr);
    }
  /*-----------------------------------------------------------
   *  Create a pixmap, draw into this pixmap in background and
   *  copy to the button window when finished.
   *----------------------------------------------------------*/
  pixmap = XCreatePixmap(EZ_DisplayForWidgets, win, w, h, EZ_DepthForWidgets);    
  if(padb > 0)
    {
      EZ_GetParentBgGCN(wptr, &gc,&bgpva);
      XFillRectangle(EZ_DisplayForWidgets, pixmap, gc, 0,0, w, h); 
      filled = 1;
    }
  else bgpva = 0;  
  EZ_GetBackgroundGC(wptr, &gc, &bgpv, 0, 0);  
  if(filled == 0 || bgpva != bgpv)
    XFillRectangle(EZ_Display, pixmap, gc, padb,padb, w-padb2, h-padb2); 

  cw = EZ_WidgetBorderWidth(wptr) + EZ_WidgetPadX(wptr) + padb;  
  ch = EZ_WidgetBorderWidth(wptr) + EZ_WidgetPadY(wptr) + padb;  
  /*--------------------------------------------------------
   *  Draw label and values.
   *-------------------------------------------------------*/
  if(EZ_SliderDisplayValue(wptr) || EZ_SliderLabel(wptr) != (char *)NULL)
    {
      if( EZ_GetWidgetDisabledFlag(wptr) )
	{
	  GC  bgc, lgc, ngc;
	  EZ_GetDarkBrightNormalBDGC(wptr, &bgc, &lgc, &ngc);
	  XSetFont(EZ_DisplayForWidgets, bgc, EZ_WidgetFont(wptr)->fid);
	  XSetFont(EZ_DisplayForWidgets, lgc, EZ_WidgetFont(wptr)->fid);
	  XSetFont(EZ_DisplayForWidgets, ngc, EZ_WidgetFont(wptr)->fid);

	  if(EZ_SliderLabel(wptr) != (char *)NULL)
	    {
	      x = ((w - EZ_SliderTWidth(wptr)) >> 1);
	      y = EZ_SliderFontAscent(wptr) + ch;
	  
	      XDrawString(EZ_DisplayForWidgets, pixmap, bgc,
			  x+1, y+1,  EZ_SliderLabel(wptr), EZ_SliderLabelLength(wptr));
	      XDrawString(EZ_DisplayForWidgets, pixmap, lgc,
			  x-1, y-1,  EZ_SliderLabel(wptr), EZ_SliderLabelLength(wptr));
	      XDrawString(EZ_DisplayForWidgets, pixmap, ngc,
			  x, y,  EZ_SliderLabel(wptr), EZ_SliderLabelLength(wptr));
	    }
	  if(EZ_SliderDisplayValue(wptr))
	    {
	      char tmp[32];
	      
	      (void) sprintf(tmp, EZ_SliderFormat(wptr),EZ_SliderMinValue(wptr));
	      x =  EZ_SliderMinx(wptr) - EZ_SliderVWidtha(wptr) - ss - EZ_SliderBorderWidth(wptr);
	      y =  EZ_SliderPositionMin(wptr) + ( EZ_SliderFontAscent(wptr)>>1);
	      XDrawString(EZ_DisplayForWidgets, pixmap, bgc,
			  x+1, y+1, tmp,  strlen(tmp));
	      XDrawString(EZ_DisplayForWidgets, pixmap, lgc,
			  x-1, y-1, tmp,  strlen(tmp));
	      XDrawString(EZ_DisplayForWidgets, pixmap, ngc,
			  x, y, tmp,  strlen(tmp));

	      (void) sprintf(tmp, EZ_SliderFormat(wptr),EZ_SliderMaxValue(wptr));
	      x += EZ_SliderVWidtha(wptr) - EZ_SliderVWidth(wptr);
	      y =  EZ_SliderMaxy(wptr) - (EZ_SliderSliderLength(wptr)>>1) + ( EZ_SliderFontAscent(wptr)>>1);
	      XDrawString(EZ_DisplayForWidgets, pixmap, bgc,
			  x+1, y+1, tmp, strlen(tmp));
	      XDrawString(EZ_DisplayForWidgets, pixmap, lgc,
			  x-1, y-1, tmp, strlen(tmp));
	      XDrawString(EZ_DisplayForWidgets, pixmap, gc,
			  x, y, tmp, strlen(tmp));

	      (void) sprintf(tmp, EZ_SliderFormat(wptr),EZ_SliderValue(wptr)); 
	      x =  EZ_SliderMaxx(wptr) + (ss<1) + EZ_SliderBorderWidth(wptr);;
	      y =  EZ_SliderPosition(wptr) + ( EZ_SliderFontAscent(wptr)>>1);
	      XDrawString(EZ_DisplayForWidgets, pixmap, bgc,
			  x+1, y+1, tmp, strlen(tmp));	  
	      XDrawString(EZ_DisplayForWidgets, pixmap, lgc,
			  x-1, y-1, tmp, strlen(tmp));	  
	      XDrawString(EZ_DisplayForWidgets, pixmap, ngc,
			  x, y, tmp, strlen(tmp));	  
	    }
	}
      else
	{
	  if(EZ_SliderForeground(wptr) != EZ_DefaultForeground || 
	     EZ_SliderFont(wptr) != EZ_GetFontFromId(EZ_BUTTON_FONT))
	    {
	      XSetFont(EZ_DisplayForWidgets, EZ_WRITABLEGC, EZ_SliderFont(wptr)->fid);
	      XSetForeground(EZ_DisplayForWidgets, EZ_WRITABLEGC, EZ_SliderForeground(wptr));	
	      gc = EZ_WRITABLEGC;
	    }
	  else  gc = EZ_BUTTON_TEXTGC;

	  if(EZ_SliderLabel(wptr) != (char *)NULL)
	    {
	      x = ((w - EZ_SliderTWidth(wptr)) >> 1);
	      y = EZ_SliderFontAscent(wptr) + ch;
	  
	      XDrawString(EZ_DisplayForWidgets, pixmap, gc, 
			  x, y,
			  EZ_SliderLabel(wptr),
			  EZ_SliderLabelLength(wptr));
	    }
	  if(EZ_SliderDisplayValue(wptr))
	    {
	      char tmp[32];
	      
	      (void) sprintf(tmp, EZ_SliderFormat(wptr),EZ_SliderMinValue(wptr));
	      x =  EZ_SliderMinx(wptr) - EZ_SliderVWidtha(wptr) - ss - EZ_SliderBorderWidth(wptr);
	      y =  EZ_SliderPositionMin(wptr) + ( EZ_SliderFontAscent(wptr)>>1);
	      XDrawString(EZ_DisplayForWidgets, pixmap, gc, 
			  x, y,
			  tmp,
			  strlen(tmp));

	      (void) sprintf(tmp, EZ_SliderFormat(wptr),EZ_SliderMaxValue(wptr));
	      x += EZ_SliderVWidtha(wptr) - EZ_SliderVWidth(wptr);
	      y =  EZ_SliderMaxy(wptr) - (EZ_SliderSliderLength(wptr)>>1) + ( EZ_SliderFontAscent(wptr)>>1);
	      XDrawString(EZ_DisplayForWidgets, pixmap, gc, 
			  x, y,
			  tmp,
			  strlen(tmp));

	      (void) sprintf(tmp, EZ_SliderFormat(wptr),EZ_SliderValue(wptr)); 
	      x =  EZ_SliderMaxx(wptr) + (ss<1) + EZ_SliderBorderWidth(wptr);;
	      y =  EZ_SliderPosition(wptr) + ( EZ_SliderFontAscent(wptr)>>1);
	      XDrawString(EZ_DisplayForWidgets, pixmap, gc, 
			  x, y,
			  tmp,
			  strlen(tmp));	  
	    }
	}
    }
  /*---------------------------------------------------------
   *     Draw the slider.
   *--------------------------------------------------------*/
  x = EZ_SliderMinx(wptr) - EZ_SliderBorderWidth(wptr);
  y = EZ_SliderMiny(wptr) - EZ_SliderBorderWidth(wptr);
  
  hh = EZ_SliderLength(wptr);
  ww = EZ_SliderWidth(wptr);

  EZ_DrawRectBorderWithSize(wptr, pixmap, x,y,
			    ww + (EZ_SliderBorderWidth(wptr)<< 1),
			    hh + (EZ_SliderBorderWidth(wptr)<< 1),
			    EZ_SliderBorderWidth(wptr),
			    EZ_BORDER_DOWN);

  x += EZ_SliderBorderWidth(wptr);
  y =  EZ_SliderPosition(wptr) - (EZ_SliderSliderLength(wptr)>>1); 

  EZ_GetBackgroundGC(wptr, &gc, &bgpv, 1, 0);  
  XFillRectangle(EZ_DisplayForWidgets, pixmap, gc,
		 x, y,
		 ww,EZ_SliderSliderLength(wptr));

  if(EZ_SliderBorderStyle(wptr) == EZ_BORDER_DOWN) offset = 1;

  xx = x + offset +EZ_SliderBorderWidth(wptr);
  yy =  EZ_SliderPosition(wptr) + offset - 1;
  EZ_GetDarkBrightNormalBDGC(wptr, &gc, &gc1, &junkgc);
  XDrawLine(EZ_DisplayForWidgets,pixmap, gc,
	    xx, yy,
	    xx+ EZ_SliderWidth(wptr) - (EZ_SliderBorderWidth(wptr)<<1), 
	    yy);
  XDrawLine(EZ_DisplayForWidgets,pixmap, gc1,
	    xx, yy+2,
	    xx+ EZ_SliderWidth(wptr) - (EZ_SliderBorderWidth(wptr)<<1), 
	    yy+2);
  
  EZ_DrawRectBorderWithSize(wptr, pixmap, 
			    x,
			    y,
			    ww,
			    EZ_SliderSliderLength(wptr),
			    EZ_SliderBorderWidth(wptr),
			    EZ_SliderBorderStyle(wptr));

  EZ_DrawRectBorder(wptr, pixmap);

  XCopyArea(EZ_DisplayForWidgets,pixmap,win, EZ_WRITABLEGC,0,0,w,h,0,0); 
  XFreePixmap(EZ_DisplayForWidgets, pixmap);                             
}

/**************************************************************************/
void  EZ_SliserEventHandle(widget, event)
     EZ_Widget *widget;
     XEvent          *event;
{
  int button;
  if(widget == (EZ_Widget *)NULL) return;
  if(event->type == Expose) EZ_DrawWidget(widget);      
  if( EZ_GetWidgetDisabledFlag(widget) ) return;
  if(event->type == ButtonPress && event->xbutton.button == EZ_Btn3)
    return;

  switch(event->type)
    {
    case EnterNotify:
      break;
    case LeaveNotify:
      EZ_DrawWidget(widget);
      break;
    case ButtonPress:
      button = event->xbutton.button;

      switch(EZ_WidgetType(widget))
	{
	case EZ_WIDGET_HORIZONTAL_SLIDER:
	  {
	    int     x,y, onbutton, inwindow, halflength, newpos;
	    XEvent  xevent;

	    x = event->xbutton.x;
	    y = event->xbutton.y;
	    onbutton = 0;
	    inwindow = 0;

	    if(y >= EZ_SliderMiny(widget) && y <= EZ_SliderMaxy(widget))
	      {
		/*--------------------------------------------------
		 * First, check if the button press is on the button
		 *--------------------------------------------------*/
		if(x >= EZ_SliderPosition(widget) - (EZ_SliderSliderLength(widget)>>1) &&
		   x <= EZ_SliderPosition(widget) +(EZ_SliderSliderLength(widget)>>1))
		  {
		    onbutton = 1;
		    /*----------------------------------------------
		     * Press is on the button. Update button 
		     * appearence immediately. But don't update
		     * the slider position yet.
		     *---------------------------------------------*/
		    if(EZ_DepresionDisabled == 0)
		      EZ_SliderBorderStyle(widget) = EZ_BORDER_DOWN;
		  }
		else if( x >= EZ_SliderMinx(widget) && x <= EZ_SliderMaxx(widget))
		  {
		    inwindow = 1;

		    /*---------------------------------------------------
		     * press is in the slider window. If Button2, Update
		     * slider position and appearance immediately
		     *-------------------------------------------------*/
		    if(button == EZ_Btn2)
		      {
			halflength = (EZ_SliderSliderLength(widget)>>1);
			if( x < EZ_SliderPositionMin(widget))
			  newpos =  EZ_SliderPositionMin(widget);
			else if( x > EZ_SliderMaxx(widget) - halflength)
			  newpos =  EZ_SliderMaxx(widget) - halflength;
			else  newpos = x;
			EZ_SliderPosition(widget) = newpos;
			EZ_SliderValue(widget) = EZ_SliderMinValue(widget) +
			  EZ_SliderFactor(widget) * (newpos - EZ_SliderPositionMin(widget));
			EZ_FixSliderValue(widget);
			if(EZ_DepresionDisabled == 0)
			  EZ_SliderBorderStyle(widget) = EZ_BORDER_DOWN;
			onbutton = 1;
		      }
		  }
		if(onbutton)
		  {
		    int wox, woy;
		    Window junkwin;
		    XTranslateCoordinates(EZ_Display, EZ_WidgetWindow(widget),
					  RootWindow(EZ_Display, EZ_ScreenNum),
					  0, 0,
					  &wox,&woy, &junkwin);
		    /*---------------------------------------------
		     *  Now wait for a ButtonRelease event. Process
		     *  all pointer motion event.
		     *--------------------------------------------*/
		    EZ_SetWidgetHighlightFlag(widget);
		    EZ_DrawWidget(widget);		    
		    while(1)
		      {
			XNextEvent(EZ_Display, &xevent);
			if(EZ_FilterEvent(&xevent))
			  EZ_InvokePrivateEventHandler(&xevent);
			if(xevent.type == Expose || xevent.type == FocusIn || xevent.type == FocusOut) 
			  EZ_WidgetDispatchEvent(&xevent);
			while(XPending(EZ_Display))
			  {
			    if(xevent.type == ButtonRelease && xevent.xbutton.button == button) break;
			    XNextEvent(EZ_Display, &xevent);
			    if(EZ_FilterEvent(&xevent))
			      EZ_InvokePrivateEventHandler(&xevent);
			    if(xevent.type == Expose || xevent.type == FocusIn || xevent.type == FocusOut) 
			      EZ_WidgetDispatchEvent(&xevent); 
			  }
			if(xevent.type == ButtonRelease && xevent.xbutton.button == button)
			  {
			    if(EZ_SliderBorderStyle(widget) == EZ_BORDER_DOWN ||
			       EZ_GetWidgetHighlightFlag(widget))
			      {
				EZ_ClearWidgetHighlightFlag(widget);
				EZ_SliderBorderStyle(widget) = EZ_BORDER_UP; 
				EZ_DrawWidget(widget); 
			      }
			    { EZ_ExecuteWidgetCallBacks(widget);}
			    break;
			  }
			else 
			  {
			    float ff;
			    int             rx,ry,x,y;
			    unsigned int    mask;
			    Window          root,win;
			    XQueryPointer(EZ_Display, RootWindow(EZ_Display, EZ_ScreenNum),
					  &root,
					  &win, 
					  &rx, &ry, 
					  &x,&y, 
					  &mask );
			    x = rx - wox;
			    halflength = (EZ_SliderSliderLength(widget)>>1);
			    if( x < EZ_SliderPositionMin(widget))
			      newpos =  EZ_SliderPositionMin(widget);
			    else if( x > EZ_SliderMaxx(widget) - halflength)
			      newpos =  EZ_SliderMaxx(widget) - halflength;
			    else  newpos = x;
			    EZ_SliderPosition(widget) = newpos;
			    ff = EZ_SliderValue(widget);
			    EZ_SliderValue(widget) = EZ_SliderMinValue(widget) +
			      EZ_SliderFactor(widget) * (newpos - EZ_SliderPositionMin(widget));
			    EZ_FixSliderValue(widget);
			    EZ_DrawWidget(widget); 
			    if(ff != EZ_SliderValue(widget))
			      { EZ_ExecuteWidgetCallBacks(widget);}
			  }
		      }
		  }
		else if(inwindow)
		  {
		    /* must be Button1 and the press is not on slider */
		    /* slide toward pointer */
		    int   first_time = 1, done = 0;
		    int   pos = EZ_SliderPosition(widget);
		    int   m_unit, iincr =(x > pos)? 1: -1;
		    int   halflength = (EZ_SliderSliderLength(widget)>>1);
		    int   minP = EZ_SliderPositionMin(widget);
		    int   maxP = EZ_SliderMaxx(widget) - halflength;
		    float factor = EZ_SliderFactor(widget);
		    float minF = EZ_SliderMinValue(widget);
		    float ff;
		    if(event->xbutton.state & ShiftMask) m_unit =  iincr * 4;
		    else if(event->xbutton.state & ControlMask)  m_unit = iincr * 2;
		    else m_unit = iincr;

		    while(!done) /* wait for a matching ButtonRelease */
		      { 
			int pos = EZ_SliderPosition(widget) ;
			if((iincr > 0 && pos < maxP) || (iincr < 0 && pos > minP))
			  {
			    EZ_SliderPosition(widget) += m_unit;
			    if(EZ_SliderPosition(widget) > maxP)
			      EZ_SliderPosition(widget) = maxP;
			    else if(EZ_SliderPosition(widget) < minP)
			      EZ_SliderPosition(widget) = minP;
			    ff = EZ_SliderValue(widget);
			    EZ_SliderValue(widget) = minF +
			      (EZ_SliderPosition(widget) - minP) * factor;
			    EZ_FixSliderValue(widget);
			    EZ_DrawWidget(widget); 
			    if(ff != EZ_SliderValue(widget))
			      { EZ_ExecuteWidgetCallBacks(widget);}
			  }
			if(first_time)
			  {
			    first_time = 0;
			    XFlush(EZ_Display);
			    EZ_SitForALittleBit(300000); 
			  }
			else EZ_SitForALittleBit(30000); 

			while(XPending(EZ_Display))
			  {
			    XNextEvent(EZ_Display, &xevent);
			    if(EZ_FilterEvent(&xevent))
			      EZ_InvokePrivateEventHandler(&xevent);
			    if(xevent.type == ButtonRelease &&
			       xevent.xbutton.button == button)
			      {
				done = 1;
				break;
			      }
			  }
		      }		    
		  }
	      }
	  }
	  break;
	case EZ_WIDGET_VERTICAL_SLIDER:
	  {
	    int     x,y, onbutton, inwindow, halflength, newpos;
	    XEvent  xevent;

	    x = event->xbutton.x;
	    y = event->xbutton.y;
	    onbutton = 0;
	    inwindow = 0;

	    if(x >= EZ_SliderMinx(widget) && x <= EZ_SliderMaxx(widget))
	      {
		/*--------------------------------------------------
		 * First, check if the button press is on the button
		 *--------------------------------------------------*/
		if(y >= EZ_SliderPosition(widget) - (EZ_SliderSliderLength(widget)>>1) &&
		   y <= EZ_SliderPosition(widget) +(EZ_SliderSliderLength(widget)>>1))
		  {
		    onbutton = 1;
		    /*----------------------------------------------
		     * Press is on the button. Update button 
		     * appearence immediately. But don't update
		     * the slider position yet.
		     *---------------------------------------------*/
		    if(EZ_DepresionDisabled == 0)
		      EZ_SliderBorderStyle(widget) = EZ_BORDER_DOWN;
		  }
		else if( y >= EZ_SliderMiny(widget) && y <= EZ_SliderMaxy(widget))
		  {
		    inwindow = 1;
		    /*---------------------------------------------
		     * press is in the slider window. Update
		     * slider position and appearance immediately
		     *--------------------------------------------*/
		    if(button == EZ_Btn2)
		      {
			halflength = (EZ_SliderSliderLength(widget)>>1);
			if(y < EZ_SliderPositionMin(widget))
			  newpos =  EZ_SliderPositionMin(widget);
			else if( y > EZ_SliderMaxy(widget) - halflength)
			  newpos =  EZ_SliderMaxy(widget) - halflength;
			else  newpos = y;
			EZ_SliderPosition(widget) = newpos;
			EZ_SliderValue(widget) = EZ_SliderMinValue(widget) +
			  EZ_SliderFactor(widget) * (newpos - EZ_SliderPositionMin(widget));
			EZ_FixSliderValue(widget);
			if(EZ_DepresionDisabled == 0)
			  EZ_SliderBorderStyle(widget) = EZ_BORDER_DOWN;
			onbutton = 1;
		      }
		  }
		if(onbutton)
		  {
		    int wox,woy;
		    Window junkwin;
		    XTranslateCoordinates(EZ_Display, EZ_WidgetWindow(widget),
					  RootWindow(EZ_Display, EZ_ScreenNum),
					  0, 0,
					  &wox,&woy, &junkwin);
		    /*---------------------------------------------
		     *  Now wait for a ButtonRelease event. Process
		     *  all pointer motion event.
		     *--------------------------------------------*/
		    EZ_SetWidgetHighlightFlag(widget);
		    EZ_DrawWidget(widget);		    
		    while(1)
		      {
			XNextEvent(EZ_Display, &xevent);
			if(EZ_FilterEvent(&xevent))
			  EZ_InvokePrivateEventHandler(&xevent);
			if(xevent.type == Expose || xevent.type == FocusIn || xevent.type == FocusOut) 
			  EZ_WidgetDispatchEvent(&xevent); 
			while(XPending(EZ_Display))
			  {
			    if(xevent.type == ButtonRelease && xevent.xbutton.button == button) break;
			    XNextEvent(EZ_Display, &xevent);
			    if(EZ_FilterEvent(&xevent))
			      EZ_InvokePrivateEventHandler(&xevent);
			    if(xevent.type == Expose || xevent.type == FocusIn || xevent.type == FocusOut) 
			      EZ_WidgetDispatchEvent(&xevent); 
			  }
			if(xevent.type == ButtonRelease && xevent.xbutton.button == button)
			  {
			    if(EZ_SliderBorderStyle(widget) == EZ_BORDER_DOWN ||
			       EZ_GetWidgetHighlightFlag(widget))
			      {
				EZ_ClearWidgetHighlightFlag(widget);
				EZ_SliderBorderStyle(widget) = EZ_BORDER_UP; 
				EZ_DrawWidget(widget); 
			      }
			    { EZ_ExecuteWidgetCallBacks(widget);}
			    break;
			  }
			else
			  {
			    float ff;
			    int             rx,ry,x,y;
			    unsigned int    mask;
			    Window          root,win;
			    XQueryPointer(EZ_Display, RootWindow(EZ_Display, EZ_ScreenNum),
					  &root,
					  &win, 
					  &rx, &ry, 
					  &x,&y, 
					  &mask );
			    
			    y = ry - woy;
			    halflength = (EZ_SliderSliderLength(widget)>>1);
			    if( y < EZ_SliderPositionMin(widget))
			      newpos =  EZ_SliderPositionMin(widget);
			    else if( y > EZ_SliderMaxy(widget) - halflength)
			      newpos =  EZ_SliderMaxy(widget) - halflength;
			    else  newpos = y;
			    EZ_SliderPosition(widget) = newpos;
			    ff = EZ_SliderValue(widget);
			    EZ_SliderValue(widget) = EZ_SliderMinValue(widget) +
			      EZ_SliderFactor(widget) * (newpos - EZ_SliderPositionMin(widget));
			    EZ_FixSliderValue(widget);
			    EZ_DrawWidget(widget); 	
			    if(ff != EZ_SliderValue(widget))
			      { EZ_ExecuteWidgetCallBacks(widget);}
			  }
		      }
		  }
		else if(inwindow)
		  {
		    /* must be Button1 and the press is not on slider */
		    /* slide toward pointer */
		    int   first_time = 1, done = 0;
		    int   pos = EZ_SliderPosition(widget);
		    int   m_unit,iincr =(y > pos)? 1: -1;
		    int   halflength = (EZ_SliderSliderLength(widget)>>1);
		    int   minP = EZ_SliderPositionMin(widget);
		    int   maxP = EZ_SliderMaxy(widget) - halflength;
		    float factor = EZ_SliderFactor(widget);
		    float minF = EZ_SliderMinValue(widget);
		    float ff;
		    if(event->xbutton.state & ShiftMask) m_unit =  iincr * 4;
		    else if(event->xbutton.state & ControlMask)  m_unit = iincr * 2;
		    else m_unit = iincr;

		    while(!done) /* wait for a matching ButtonRelease */
		      { 
			int pos = EZ_SliderPosition(widget);

			if((iincr > 0 && pos < maxP) || (iincr < 0 && pos > minP))
			  {
			    EZ_SliderPosition(widget) += m_unit;
			    if(EZ_SliderPosition(widget) > maxP)
			      EZ_SliderPosition(widget) = maxP;
			    else if(EZ_SliderPosition(widget) < minP)
			      EZ_SliderPosition(widget) = minP;
			    ff = EZ_SliderValue(widget);
			    EZ_SliderValue(widget) = minF +
			      (EZ_SliderPosition(widget) - minP) * factor;
			    EZ_FixSliderValue(widget);
			    EZ_DrawWidget(widget); 
			    if(ff != EZ_SliderValue(widget))
			      { EZ_ExecuteWidgetCallBacks(widget);}
			  }
			if(first_time)
			  {
			    first_time = 0;
			    XFlush(EZ_Display);
			    EZ_SitForALittleBit(300000); 
			  }
			else EZ_SitForALittleBit(30000); 

			while(XPending(EZ_Display))
			  {
			    XNextEvent(EZ_Display, &xevent);
			    if(EZ_FilterEvent(&xevent))
			      EZ_InvokePrivateEventHandler(&xevent);
			    if(xevent.type == ButtonRelease &&
			       xevent.xbutton.button == button)
			      {
				done = 1;
				break;
			      }
			  }
		      }		    
		  }
	      }
	  }
	  break;
	default:
	  break;
	}
      break;
    case MotionNotify:
      switch(EZ_WidgetType(widget))
	{
	case EZ_WIDGET_HORIZONTAL_SLIDER:
	  {
	    int  x,y;

	    x = event->xbutton.x;
	    y = event->xbutton.y;

	    if( (y >= EZ_SliderMiny(widget) && y <= EZ_SliderMaxy(widget)) &&
	       (x >= EZ_SliderPosition(widget) - (EZ_SliderSliderLength(widget)>>1) &&
		     x <= EZ_SliderPosition(widget) +(EZ_SliderSliderLength(widget)>>1)) )
	      {
		EZ_SetWidgetHighlightFlag(widget);
		EZ_DrawWidget(widget);	
	      }
	    else if(EZ_GetWidgetHighlightFlag(widget))
	      {
		EZ_ClearWidgetHighlightFlag(widget);
		EZ_DrawWidget(widget);
	      }
	  }
	  break;
	case EZ_WIDGET_VERTICAL_SLIDER:
	  {
	    int  x,y;
	    
	    x = event->xbutton.x;
	    y = event->xbutton.y;

	    if( (x >= EZ_SliderMinx(widget) && x <= EZ_SliderMaxx(widget)) &&
	       (y >= EZ_SliderPosition(widget) - (EZ_SliderSliderLength(widget)>>1) &&
		y <= EZ_SliderPosition(widget) +(EZ_SliderSliderLength(widget)>>1)) )
	      {
		EZ_SetWidgetHighlightFlag(widget);
		EZ_DrawWidget(widget);	
	      }
	    else if(EZ_GetWidgetHighlightFlag(widget))
	      {
		EZ_ClearWidgetHighlightFlag(widget);
		EZ_DrawWidget(widget);
	      }
	  }
	  break;
	default:
	  break;
	}
      break;
    case KeyPress:
      {
	char              tmpbuffer[8];
	int               buffersize = 8, move_unit;
	KeySym            keysym;
	XComposeStatus    compose; 
	int count = XLookupString(&(event->xkey), tmpbuffer, buffersize, &keysym, &compose);
	tmpbuffer[count] = '\0';

	if(EZ_WidgetType(widget) == EZ_WIDGET_VERTICAL_SLIDER)
	  {
	    switch(keysym)
	      {
	      case XK_Down: case XK_n: case XK_j: case XK_N: case XK_J: 
#ifdef XK_KP_Down
	      case XK_KP_Down:
#endif
		move_unit = 1;
		break;
	      case XK_Up: case XK_k:  case XK_p: case XK_K:  case XK_P: 
#ifdef XK_KP_Up
	      case XK_KP_Up:
#endif
		move_unit = -1;
		break;
	      default:
		move_unit = 0;
		break;
	      }
	    if(move_unit)
	      {
		int   halflength = (EZ_SliderSliderLength(widget)>>1);
		int   minP = EZ_SliderPositionMin(widget);
		int   maxP = EZ_SliderMaxy(widget) - halflength;
		float factor = EZ_SliderFactor(widget);
		float minF = EZ_SliderMinValue(widget);
		float ff;
		int pos = EZ_SliderPosition(widget) ;
		if(event->xkey.state & ShiftMask)   move_unit *= 4;
		if(event->xkey.state & ControlMask) move_unit *= 2;

		if((move_unit > 0 && pos < maxP) || (move_unit < 0 && pos > minP))
		  {
		    EZ_SliderPosition(widget) += move_unit;
		    if(EZ_SliderPosition(widget) > maxP)
		      EZ_SliderPosition(widget) = maxP;
		    else if(EZ_SliderPosition(widget) < minP)
		      EZ_SliderPosition(widget) = minP;
		    ff = EZ_SliderValue(widget);
		    EZ_SliderValue(widget) = minF +
		      (EZ_SliderPosition(widget) - minP) * factor;
		    EZ_FixSliderValue(widget);
		    EZ_DrawWidget(widget); 
		    if(ff != EZ_SliderValue(widget))
		      { EZ_ExecuteWidgetCallBacks(widget);}
		  }
	      }
	  }
	else if(EZ_WidgetType(widget) == EZ_WIDGET_HORIZONTAL_SLIDER)
	  {
	    switch(keysym)
	      {
	      case XK_Left: case XK_b:  case XK_h: case XK_B:  case XK_H:  
#ifdef XK_KP_Left
	      case XK_KP_Left:
#endif
		move_unit = -1;
		break;
	      case XK_Right: case XK_f: case XK_l: case XK_F: case XK_L:  
#ifdef XK_KP_Right
	      case XK_KP_Right:
#endif
		move_unit = 1;
		break;
	      default:
		move_unit = 0;
		break;
	      }
	    if(move_unit)
	      {
		int   halflength = (EZ_SliderSliderLength(widget)>>1);
		int   minP = EZ_SliderPositionMin(widget);
		int   maxP = EZ_SliderMaxx(widget) - halflength;
		float factor = EZ_SliderFactor(widget);
		float minF = EZ_SliderMinValue(widget);
		float ff;
		int pos = EZ_SliderPosition(widget) ;
		if(event->xkey.state & ShiftMask)   move_unit *= 4;
		if(event->xkey.state & ControlMask) move_unit *= 2;

		if((move_unit >0 && pos < maxP) || (move_unit < 0 && pos > minP))
		  {
		    EZ_SliderPosition(widget) += move_unit;
		    if(EZ_SliderPosition(widget) > maxP)
		      EZ_SliderPosition(widget) = maxP;
		    else if(EZ_SliderPosition(widget) < minP)
		      EZ_SliderPosition(widget) = minP;

		    ff = EZ_SliderValue(widget);
		    EZ_SliderValue(widget) = minF +
		      (EZ_SliderPosition(widget) - minP) * factor;
		    EZ_FixSliderValue(widget);
		    EZ_DrawWidget(widget); 
		    if(ff != EZ_SliderValue(widget))
		      { EZ_ExecuteWidgetCallBacks(widget);}
		  }
	      }
	  }
	{
	  XEvent tmpevent; 
	  while(XCheckTypedEvent(EZ_Display, KeyPress, &tmpevent))
	    if(EZ_FilterEvent(&tmpevent))
	      EZ_InvokePrivateEventHandler(&tmpevent);
	}
      }
      break;
    default:
      break;
    }
}

/************************************************************
 *
 */
float  EZ_GetSliderValue(widget)
     EZ_Widget *widget;
{
  if(widget == (EZ_Widget *)NULL ||
     (EZ_WidgetType(widget)!= EZ_WIDGET_VERTICAL_SLIDER &&
      EZ_WidgetType(widget)!= EZ_WIDGET_HORIZONTAL_SLIDER))
    {
      (void)fprintf(stderr, "In EZ_GetSliderValue(), wrong type of widget\n");
      return(0.0);
    }
  return(EZ_SliderValue(widget));
}

/************************************************************/
void  EZ_SetSliderValue(widget, value)
     EZ_Widget *widget; 
     float     value;
{
  if(widget != (EZ_Widget *)NULL &&
     (EZ_WidgetType(widget) == EZ_WIDGET_VERTICAL_SLIDER ||
      EZ_WidgetType(widget) == EZ_WIDGET_HORIZONTAL_SLIDER))
    {
      EZ_SliderValue(widget) = value;
      if(EZ_WidgetMapped(widget)) 
	{
	  EZ_SetWidgetSizeMayBeChandedFlag(widget);
	  EZ_DrawWidget(widget);
	}
    }
}
/************************************************************/
static void EZ_FixSliderValue(widget)
     EZ_Widget *widget;
{
  if(EZ_SliderResolution(widget) > 0.0)
    {
      float f = EZ_SliderValue(widget);
      float R = EZ_SliderResolution(widget);
      float R2 = 0.5 * R;
      float r = (float)fmod( (double) f, (double) R);
      
      if( r < 0.0)  r += R;
      if( r > R2)
	f += (R - r);
      else
	f -= r;

      EZ_SliderValue(widget) = f;
    }
}
/************************************************************/
void EZ_SetSliderRange(widget, from, to)
     EZ_Widget *widget; float from, to;
{
  if(widget && (EZ_WidgetType(widget) == EZ_WIDGET_HORIZONTAL_SLIDER ||
     EZ_WidgetType(widget) == EZ_WIDGET_VERTICAL_SLIDER ))
    {
      EZ_SliderMinValue(widget) = (float)from;
      EZ_SliderMaxValue(widget) = (float)to;
      if(EZ_WidgetMapped(widget)) EZ_DisplayWidget(widget);
    }
}
/************************************************************/
#undef _EZ_WIDGET_SLIDER_C_
