/*********************************************************************
 *
 *         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
 */
/*****************************************************************
***                                                           ***
***              Status Meter                                 ***
***                                                           ***
*****************************************************************/
#define _EZ_WIDGET_SMETER_C_
#include "EZ_Widget.h"

/*********************************************************************
 * 
 *  Functions implemented in this file:
 */
EZ_Widget   *EZ_CreateStatusMeter  MY_ANSIARGS((EZ_Widget *parent)); 
void         EZ_SetStatusMeterValue  MY_ANSIARGS((EZ_Widget *widget, float value));
void         EZ_SetStatusMeterRange MY_ANSIARGS((EZ_Widget *widget, float f, float t));
float        EZ_GetStatusMeterValue  MY_ANSIARGS((EZ_Widget *widget));
void         EZ_StopStatusMeter MY_ANSIARGS((EZ_Widget *widget));
void         EZ_StartStatusMeter MY_ANSIARGS((EZ_Widget *widget));
void         EZ_SetStatusMeterForeground MY_ANSIARGS((EZ_Widget *widget, char *clr));
void         EZ_SetStatusMeterBackground MY_ANSIARGS((EZ_Widget *widget, char *clr));

void         EZ_SetStatusMeterForegroundN MY_ANSIARGS((EZ_Widget *widget, int idx, char *clr));
void         EZ_SetStatusMeterValueN  MY_ANSIARGS((EZ_Widget *widget, int idx, float value));
void         EZ_SetStatusMeterRangeN MY_ANSIARGS((EZ_Widget *widget, int idx, float f, float t));
float        EZ_GetStatusMeterValueN  MY_ANSIARGS((EZ_Widget *widget, int idx));

/*********************************************************************/
void         EZ_SMeterEventHandle  MY_ANSIARGS((EZ_Widget *widget, XEvent *event));
void         EZ_ComputeWidgetSMeterSize  MY_ANSIARGS((EZ_Widget *widget, int *w, int *h));
void         EZ_DrawWidgetSMeter   MY_ANSIARGS((EZ_Widget *widget));
void         EZ_FreeWidgetSMeterData  MY_ANSIARGS((EZ_Widget *widget));
/*********************************************************************
 * 
 *  Local Variables.
 */
static EZ_WidgetHandle EZ_SMeterHandle =
{
  EZ_ComputeWidgetSMeterSize,
  EZ_DrawWidgetSMeter,
  EZ_FreeWidgetSMeterData,
  EZ_SMeterEventHandle,
};

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

EZ_Widget  *EZ_CreateStatusMeter(parent)
     EZ_Widget  *parent;     /* parent widget    */
{
  EZ_Widget  *wptr;
  unsigned long *clrs;
  int i;
  float    *f;

  wptr = EZ_CreateNewWidget(parent);
  EZ_WidgetHandlingFunctions[EZ_WIDGET_STATUS_METER] = &EZ_SMeterHandle;
  EZ_SetWidgetTypeAndNames(wptr, EZ_WIDGET_STATUS_METER);
  EZ_WidgetBorderStyle(wptr) = EZ_BORDER_DOWN;
  EZ_WidgetBorderWidth(wptr) = 2;
  EZ_WidgetPadX(wptr) = 0;
  EZ_WidgetPadY(wptr) = 0;
  EZ_WidgetSepX(wptr) = 0;
  EZ_WidgetSepY(wptr) = 0;
  EZ_WidgetFont(wptr) = EZ_GetFontFromId(EZ_LABEL_FONT);  
  clrs = EZ_SMeterFColor(wptr);
  clrs[0] = EZ_ColorArray[BLUE];
  clrs[1] = EZ_ColorArray[YELLOW];
  clrs[2] = EZ_ColorArray[RED];
  clrs[3] = EZ_ColorArray[GREEN];
  clrs[4] = EZ_ColorArray[MAGENTA];
  EZ_SMeterBColor(wptr) = ~0;
  f = EZ_SMeterValues(wptr);
  for(i = 0; i < 15; i++) f[i] = 0.0;
  f = EZ_SMeterRange(wptr);
  f[0] = f[1] = 0.0;
  EZ_SMeterNControls(wptr) = 1;
  EZ_SMeterPosition(wptr) = 0;
  EZ_SMeterOrientation(wptr) = EZ_HORIZONTAL;
  EZ_SMeterStyle(wptr) = 0;
  EZ_SMeterShowValue(wptr) = 0;
  EZ_SMeterStoped(wptr) = 0;
  EZ_SMeterBarWidth(wptr)  = 8;
  EZ_SMeterBarSep(wptr) = 2;
  
  return(wptr);
}

/***********************************************************************/
void   EZ_FreeWidgetSMeterData(widget)    EZ_Widget *widget;
{

}
/***********************************************************************/
void EZ_SMeterEventHandle(widget, event)
     EZ_Widget *widget;    XEvent *event;
{
  if(widget)
    {
      if(event->type == Expose)	EZ_DrawWidget(widget);      
      else if(event->type == ButtonPress)
	{
	  if(event->xbutton.button == EZ_Btn1)
	    { EZ_ExecuteWidgetCallBacks(widget);}
	  else if(event->xbutton.button == EZ_Btn3)
	    {
#include "EZ_DnDHandler1.c"
	      EZ_DnDEventHandler1(widget, event);
	    }
	}
    }
}
/***********************************************************************/
void EZ_ComputeWidgetSMeterSize(widget, w, h)
    EZ_Widget *widget;
     int             *w, *h;
{
  int      length, height, cw, ch;

  EZ_SetWidgetSizeComputedFlag(widget);
      
  cw = EZ_WidgetPadX(widget) + EZ_WidgetBorderWidth(widget) + EZ_WidgetPadB(widget);
  ch = EZ_WidgetPadY(widget) + EZ_WidgetBorderWidth(widget) + EZ_WidgetPadB(widget);

  if(EZ_SMeterOrientation(widget) <= EZ_HORIZONTAL_CENTER)
    { length = 32; height = 8;   }
  else
    { length = 8; height = 32;   }
  *w = cw + cw + length;
  *h = ch + ch + height;
}

/*******************************************************************
 *
 *  Draw A SMeter.
 */
void  EZ_DrawWidgetSMeter(wptr)
     EZ_Widget *wptr;
{
  int       w, h,x,y, padb, padb2, bwpdx, bwpdy, filled = 0;
  Pixmap    pixmap;
  Window    win;
  GC        gc;
  unsigned  long   bgpv, bgpva, *pv = EZ_SMeterFColor(wptr);
  int  i,j, ncontrols = EZ_SMeterNControls(wptr);
  float stotal, total, *fptr, *ff = EZ_SMeterValues(wptr);

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

  pixmap = XCreatePixmap(EZ_Display, win, w, h, EZ_Depth); 
  if(padb > 0)
    {
      EZ_GetParentBgGCN(wptr, &gc,&bgpva);
      XFillRectangle(EZ_DisplayForWidgets, pixmap, gc, 0,0, w, h); 
      filled = 1;
    }
  else bgpva = 0;  
  if(EZ_SMeterBColor(wptr) != ~0)
    {
      gc = EZ_WRITABLEGC;
      XSetForeground(EZ_Display, gc, EZ_SMeterBColor(wptr));
      XFillRectangle(EZ_DisplayForWidgets, pixmap, gc, padb,padb, w-padb2, h-padb2); 
    }
  else
    {
      EZ_GetBackgroundGC(wptr, &gc, &bgpv, 0, 0);
      if(filled == 0 || bgpva != bgpv)
	XFillRectangle(EZ_DisplayForWidgets, pixmap, gc, padb,padb, w-padb2, h-padb2); 
    }

  if(EZ_SMeterStoped(wptr)) goto finish;

  bwpdx = EZ_WidgetPadX(wptr) + EZ_WidgetBorderWidth(wptr) + padb;
  bwpdy = EZ_WidgetPadY(wptr) + EZ_WidgetBorderWidth(wptr) + padb;

  fptr = EZ_SMeterRange(wptr);
  total = fptr[1] - fptr[0];
  if(total < 0.0) total = - total;
  stotal = 0.0;
  for(i = 0, j=0; i < ncontrols; i++, j += 3)
    {
      float ftmp = ff[j+1] - ff[j];
      stotal += (ftmp >= 0.0 ? ftmp : -ftmp);
    }
  if(total < stotal) total = stotal;

  gc = EZ_WRITABLEGC;
  if(total == 0.0)
    {
      if(EZ_SMeterOrientation(wptr)<= EZ_HORIZONTAL_CENTER)
	{
	  int ww, hh, ss, pos;
	  hh = h - (bwpdy +bwpdy);
	  ww = w - (bwpdx +bwpdx);
	  if(ww > 60) ss = 16;
	  else ss = ww >> 2;
	  pos = EZ_SMeterPosition(wptr);
	  if(pos >= 0)
	    {
	      if(pos + ss < ww) EZ_SMeterPosition(wptr) += 5;
	      else EZ_SMeterPosition(wptr) = - pos;
	    }
	  else
	    {
	      if(pos < 0) EZ_SMeterPosition(wptr) += 5;
	      else EZ_SMeterPosition(wptr) = -pos;
	    }
	  y = bwpdy;
	  x = (pos> 0 ? pos : -pos);
	  if(x < 0) x = 0; else if(x > ww -ss) x = ww-ss;
	  x += bwpdx; 
	  XSetForeground(EZ_Display, gc, pv[0]);
	  XFillRectangle(EZ_Display, pixmap, gc, x,y, ss, hh);
	}
      else
	{
	  int ww, hh, ss, pos;
	  hh = h - (bwpdy +bwpdy);
	  ww = w - (bwpdx +bwpdx);
	  if(hh > 60) ss = 16;
	  else ss = hh >> 2;
	  pos = EZ_SMeterPosition(wptr);
	  if(pos >= 0)
	    {
	      if(pos < hh) EZ_SMeterPosition(wptr) += 5;
	      else EZ_SMeterPosition(wptr) = - pos;
	    }
	  else
	    {
	      if(pos - ss < 0) EZ_SMeterPosition(wptr) += 5;
	      else EZ_SMeterPosition(wptr) = -pos;
	    }
	  x = bwpdx;
	  y = hh - (pos> 0 ? pos : -pos);
	  if(y < 0) y = 0;
	  else if(y > hh -ss) y = h -ss;
	  y += bwpdy; 
	  
	  XSetForeground(EZ_Display, gc, pv[0]);
	  XFillRectangle(EZ_Display, pixmap, gc, x,y, ww, ss);
	}
    }
  else 
    {
      if(EZ_SMeterOrientation(wptr)<= EZ_HORIZONTAL_CENTER)
	{
	  float flen = (float)( w - bwpdx - bwpdx);
	  float ftmp, factor = flen / total;
	  float ftotal = 0.0;
	  int ww, hh;
	  x = bwpdx; 
	  y = bwpdy;
	  hh = h - (bwpdy +bwpdy);

	  if(EZ_SMeterStyle(wptr) == 0)
	    {
	      for(i = 0, j=0; i < ncontrols; i++, j += 3) 
		{
		  if(ff[j] != ff[j+2])
		    {
		      ftmp =  ff[j+2] - ff[j];
		      if(ftmp < 0.0) ftmp = -ftmp;
		      ftotal += ftmp;
		      ww = (int) ( factor * ftmp + 0.5);
		      if(ww > 0)
			{
			  XSetForeground(EZ_Display, gc, pv[i]);
			  XFillRectangle(EZ_Display, pixmap, gc, x,y, ww, hh);
			  x += ww;
			}
		    }
		}
	    }
	  else 
	    {
	      int k, nbars, BAR_WIDTH, BAR_SEP;
	      BAR_WIDTH = (int)EZ_SMeterBarWidth(wptr);
	      BAR_SEP = (int)EZ_SMeterBarSep(wptr);
	      for(i = 0, j=0; i < ncontrols; i++, j += 3) 
		{
		  if(ff[j] != ff[j+2])
		    {
		      ftmp =  ff[j+2] - ff[j];
		      if(ftmp < 0.0) ftmp = -ftmp;
		      ftotal += ftmp;
		      ww = (int) ( factor * ftmp + 0.5);
		      if(ww > 0)
			{
			  XSetForeground(EZ_Display, gc, pv[i]);
			  nbars = (ww + BAR_WIDTH + BAR_SEP-1)/(BAR_WIDTH + BAR_SEP);
			  for(k = 0; k < nbars; k++)
			    {
			      XFillRectangle(EZ_Display, pixmap, gc, x,y, BAR_WIDTH, hh);
			      x += BAR_WIDTH + BAR_SEP;
			    }
			}
		    }	      
		}
	    }
	  if(EZ_SMeterShowValue(wptr))
	    {
	      char str[8]; int tlen, ascent,dscent;
	      XFontStruct *fnt = EZ_WidgetFont(wptr);
	      gc = EZ_WRITABLEGC;
	      XSetFont(EZ_Display, gc, fnt->fid);
	      XSetFunction(EZ_Display, gc, GXinvert);
	      sprintf(str, "%3d%%", (int)(ftotal * 100.0/total));
	      tlen = XTextWidth(fnt, str, 3);
	      ascent = fnt->ascent;
	      dscent = fnt->descent;
	      x = ((w - tlen) >> 1);
	      y = (h - ascent -dscent)/2 + ascent;
	      XDrawString(EZ_Display, pixmap, gc, x, y, str, 4);
	      XSetFunction(EZ_Display, gc, GXcopy);
	    }
	}
      else
	{
	  float flen = (float)( h - bwpdy - bwpdy);
	  float ftmp, factor = flen / total;
	  float ftotal = 0.0;
	  int ww, hh;
	  ww = w - (bwpdx +bwpdx);
	  y = h - bwpdy;
	  x = bwpdx; 
	  if(EZ_SMeterStyle(wptr) == 0)
	    {
	      for(i = 0, j=0; i < ncontrols; i++, j += 3) 
		{
		  if(ff[j] != ff[j+2])
		    {
		      ftmp =  ff[j+2] - ff[j];
		      if(ftmp < 0.0) ftmp = -ftmp;
		      ftotal += ftmp;
		      hh = (int) ( factor * ftmp + 0.5);
		      if(hh > 0)
			{
			  XSetForeground(EZ_Display, gc, pv[i]);
			  XFillRectangle(EZ_Display, pixmap, gc, x,y-hh, ww, hh);
			  y -= hh;
			}
		    }
		}
	    }
	  else
	    {
	      int k, nbars, BAR_WIDTH, BAR_SEP;
	      BAR_WIDTH = (int)EZ_SMeterBarWidth(wptr);
	      BAR_SEP = (int)EZ_SMeterBarSep(wptr);
	      for(i = 0, j=0; i < ncontrols; i++, j += 3) 
		{
		  if(ff[j] != ff[j+2])
		    {
		      ftmp =  ff[j+2] - ff[j];
		      if(ftmp < 0.0) ftmp = -ftmp;
		      ftotal += ftmp;
		      hh = (int) ( factor * ftmp + 0.5);
		      if(hh > 0)
			{
			  XSetForeground(EZ_Display, gc, pv[i]);
			  nbars = (hh + BAR_WIDTH + BAR_SEP-1)/(BAR_WIDTH + BAR_SEP);
			  for(k = 0; k < nbars; k++)
			    {
			      XFillRectangle(EZ_Display, pixmap, gc, x,y, ww, BAR_WIDTH);
			      y -= BAR_WIDTH + BAR_SEP;
			    }
			}
		    }
		}
	    }
	  if(EZ_SMeterShowValue(wptr))
	    {
	      char str[8]; int tlen, ascent,dscent;
	      XFontStruct *fnt = EZ_WidgetFont(wptr);
	      if( ww > 2 * (fnt->max_bounds. width))
		{
		  gc = EZ_WRITABLEGC;
		  XSetFunction(EZ_Display, gc, GXinvert);
		  XSetFont(EZ_Display, gc, fnt->fid);
		  sprintf(str, "%3d%%", (int)(ftotal * 100.0/total));
		  tlen = XTextWidth(fnt, str, 3);
		  ascent = fnt->ascent;
		  dscent = fnt->descent;
		  x = bwpdx + (w - tlen)/2;
		  y = (h - ascent -dscent)/2 + ascent;
		  XDrawString(EZ_Display, pixmap, gc, x, y, str, 4);
		  XSetFunction(EZ_Display, gc, GXcopy);
		}
	    }
	}
    }
 finish:
  EZ_DrawRectBorder(wptr, pixmap);     
  XCopyArea(EZ_Display,pixmap,win, EZ_WRITABLEGC,0,0,w,h,0,0); 
  XFreePixmap(EZ_Display, pixmap); 
}
/*********************************************************************************/
void  EZ_SetStatusMeterValue(widget, value)
     EZ_Widget *widget; float value;
{
  if(widget && EZ_WidgetType(widget) == EZ_WIDGET_STATUS_METER)
    {
      float *ff = EZ_SMeterValues(widget);
      ff[2] = value;
      if(EZ_SMeterStoped(widget) == 0)  EZ_DrawWidget(widget);
    }
}
void  EZ_SetStatusMeterRange (widget, frm, to)
     EZ_Widget *widget; float frm, to;
{
  if(widget && EZ_WidgetType(widget) == EZ_WIDGET_STATUS_METER)
    {
      float *ff = EZ_SMeterRange(widget);
      ff[0] = frm; ff[1] = to;
      if(EZ_SMeterStoped(widget) == 0)  EZ_DrawWidget(widget);
    }
}
float EZ_GetStatusMeterValue(widget)
     EZ_Widget *widget;
{
  if(widget && EZ_WidgetType(widget) == EZ_WIDGET_STATUS_METER)
    {
      float *ff = EZ_SMeterValues(widget);
      return(ff[2]);
    }
  return(0.0);
}
/*****************************************************/
void  EZ_SetStatusMeterValueN(widget, idx, value)
     EZ_Widget *widget; float value; int idx;
{
  if(widget && EZ_WidgetType(widget) == EZ_WIDGET_STATUS_METER)
    {
      if(idx >= 0 && idx < 5)
	{
	  float *ff = EZ_SMeterValues(widget);
	  ff[3*idx + 2] = value;
	  idx++;
	  if(EZ_SMeterNControls(widget) <= idx) EZ_SMeterNControls(widget) = idx+1;
	  if(EZ_SMeterStoped(widget) == 0)  EZ_DrawWidget(widget);
	}
    }
}
void  EZ_SetStatusMeterRangeN(widget, idx, frm, to)
     EZ_Widget *widget; float frm, to; int idx;
{
  if(widget && EZ_WidgetType(widget) == EZ_WIDGET_STATUS_METER)
    {
      if(idx >= 0 && idx < 5)
	{
	  float *ff = EZ_SMeterValues(widget);
	  ff[3*idx] = frm; ff[3*idx +1] = to;
	  idx++;
	  if(EZ_SMeterNControls(widget) <= idx) EZ_SMeterNControls(widget) = idx+1;
	  if(EZ_SMeterStoped(widget) == 0)  EZ_DrawWidget(widget);
	}
    }
}
float EZ_GetStatusMeterValueN(widget, idx)
     EZ_Widget *widget; int idx;
{
  if(widget && EZ_WidgetType(widget) == EZ_WIDGET_STATUS_METER)
    {
      if(idx >= 0 && idx < 5)
	{
	  float *ff = EZ_SMeterValues(widget);
	  return(ff[3*idx + 2]);
	}
    }
  return(0.0);
}

void EZ_StopStatusMeter(widget)
     EZ_Widget *widget;
{
  if(widget && EZ_WidgetType(widget) == EZ_WIDGET_STATUS_METER)  
    { EZ_SMeterStoped(widget) = 1; }
}
void EZ_StartStatusMeter(widget)
     EZ_Widget *widget;
{
  if(widget && EZ_WidgetType(widget) == EZ_WIDGET_STATUS_METER &&
     EZ_SMeterStoped(widget) == 1)
    {
      EZ_SMeterStoped(widget) = 0;
      EZ_DrawWidget(widget);
    }
}
/****************************************************************/
void EZ_SetStatusMeterBackground(widget, clr) 
     EZ_Widget *widget; char *clr;
{
  if(widget && EZ_WidgetType(widget) == EZ_WIDGET_STATUS_METER)  
    {
      unsigned long  pixel_value = EZ_AllocateColorFromName(clr);
      if(EZ_SMeterBColor(widget) != pixel_value)
	{
	  EZ_SMeterBColor(widget) = pixel_value;
	  if(EZ_SMeterStoped(widget) == 0)  EZ_DrawWidget(widget);
	}
    }
}

void EZ_SetStatusMeterForeground(widget, clr) 
     EZ_Widget *widget; char *clr;
{
  if(widget && EZ_WidgetType(widget) == EZ_WIDGET_STATUS_METER)  
    {
      unsigned long  pixel_value = EZ_AllocateColorFromName(clr);
      if(EZ_SMeterFColor(widget)[0] != pixel_value)
	{
	  EZ_SMeterFColor(widget)[0] = pixel_value;
	  if(EZ_SMeterStoped(widget) == 0)  EZ_DrawWidget(widget);
	}
    }
}
void EZ_SetStatusMeterForegroundN(widget, idx, clr)
     EZ_Widget *widget; char *clr; int idx;
{
  if(widget && EZ_WidgetType(widget) == EZ_WIDGET_STATUS_METER)  
    {
      if(idx >=0 && idx < 5)
	{
	  unsigned long  pixel_value = EZ_AllocateColorFromName(clr);
	  if(EZ_SMeterFColor(widget)[idx] != pixel_value)
	    {
	      EZ_SMeterFColor(widget)[idx] = pixel_value;
	      if(EZ_SMeterStoped(widget) == 0)  EZ_DrawWidget(widget);
	    }
	}
    }
}
/**********************************************************************************/
#undef _EZ_WIDGET_SMETER_C_
