/*********************************************************************
 *
 *         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 Led.                                  ***
 ***                                                           ***
 *****************************************************************/
#define _EZ_WIDGET_LED_C_
#include "EZ_Widget.h"

/*********************************************************************
 * 
 *  Functions implemented in this file:
 */
int   EZ_QueueLedAction MY_ANSIARGS((EZ_Widget *led, int type, int delay, int count,
				   char *msg,  char *clr));
void  EZ_RemoveLedAction MY_ANSIARGS((EZ_Widget *led, int action));
void  EZ_SetLedColorFunction MY_ANSIARGS((EZ_Widget *led, EZ_LedPixelColorF f));
void  EZ_SetLedString MY_ANSIARGS((EZ_Widget *parent, char *str, char *clr));
char  *EZ_GetLedString MY_ANSIARGS((EZ_Widget *led));
void  EZ_ClearLed  MY_ANSIARGS((EZ_Widget *lcd));
void  EZ_SetLedForeground  MY_ANSIARGS((EZ_Widget *lcd, char *clr));
void  EZ_SetLedBackground  MY_ANSIARGS((EZ_Widget *lcd, char *clr));
void  EZ_SetLedOffPixelColor  MY_ANSIARGS((EZ_Widget *lcd, char *clr));
void  EZ_SetLedFont  MY_ANSIARGS((EZ_Widget *lcd, char *font));
void  EZ_SetLedWidth  MY_ANSIARGS((EZ_Widget *lcd, int w));
void  EZ_SetLedHeight  MY_ANSIARGS((EZ_Widget *lcd, int h));
void  EZ_SetLedSize    MY_ANSIARGS((EZ_Widget *lcd, int w, int h));
void  EZ_SetLedPixelSize  MY_ANSIARGS((EZ_Widget *lcd, int s));
int   EZ_LedIsFree  MY_ANSIARGS((EZ_Widget *lcd));
/*********************************************************************/
EZ_Widget  *EZ_CreateLed MY_ANSIARGS((EZ_Widget *parent));
void        EZ_DrawWidgetLed MY_ANSIARGS((EZ_Widget *widget));
void        EZ_ComputeWidgetLedSize MY_ANSIARGS((EZ_Widget *widget, int *w, int *h));
void        EZ_FreeWidgetLedData MY_ANSIARGS((EZ_Widget *widget));
void        EZ_LedEventHandle MY_ANSIARGS((EZ_Widget *widget, XEvent *event));
/*********************************************************************/
static void fixLedInitOffsets MY_ANSIARGS((EZ_Widget *led));
static void LedDrawPixel  MY_ANSIARGS((Drawable d, GC gc, int x, int y,int s));
static void LedDrawColumn MY_ANSIARGS((EZ_Widget *led, Drawable d, int idx));
static void LedDrawRow    MY_ANSIARGS((EZ_Widget *led, Drawable d, int idx));
static void LedCreateMask MY_ANSIARGS((EZ_Widget *led));
static void LedCreatePixmapC MY_ANSIARGS((EZ_Widget *led, int w, int h));
static void LedCreatePixmap  MY_ANSIARGS((EZ_Widget *led, int w, int h));
static void TimerSCallBack MY_ANSIARGS((EZ_Timer *timer, void *data));
static void TimerRCallBack MY_ANSIARGS((EZ_Timer *timer, void *data));

static void ledDestroyAction MY_ANSIARGS((EZ_LedAction *at));
static int  ledAddAction  MY_ANSIARGS((EZ_Widget *led, int type, int delay, int cnt, 
				       char *str, char *color));
extern int EZ_CounterUT;
/*********************************************************************
 * 
 *  Local Variables.
 */
static EZ_WidgetHandle EZ_LedHandle =
{ 
  EZ_ComputeWidgetLedSize,
  EZ_DrawWidgetLed,
  EZ_FreeWidgetLedData,
  EZ_LedEventHandle,    /* response only to Expose */
};

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

EZ_Widget  *EZ_CreateLed(parent)
     EZ_Widget  *parent;     /* parent widget    */
{
  EZ_Widget  *tmp;
  
  tmp = EZ_CreateNewWidget(parent);
  /*--------------------------------------------------
   * Register the handling functions for label.
   *  has to be done after  EZ_CreateNewWiget.
   *-------------------------------------------------*/
  EZ_WidgetHandlingFunctions[EZ_WIDGET_LED] = &EZ_LedHandle;

  EZ_SetWidgetTypeAndNames(tmp,EZ_WIDGET_LED);
  EZ_WidgetBorderStyle(tmp)  = EZ_BORDER_NONE;
  EZ_WidgetBorderWidth(tmp)  = 0;
  EZ_WidgetPadB(tmp)  = 0;
  EZ_WidgetFont(tmp) = EZ_GetFontFromId(0); /* 9x15 */
  EZ_WidgetLabelPosition(tmp) = EZ_CENTER;
  EZ_WidgetJustification(tmp) = EZ_CENTER;
  EZ_WidgetForeground(tmp) = EZ_ColorArray[10];

  EZ_LEDAction(tmp) = NULL;
  EZ_LEDBG(tmp)= EZ_ColorArray[0];
  EZ_LEDBGL(tmp)= EZ_ColorArray[2];
  EZ_LEDSize(tmp) = 3;
  EZ_LEDPixmap(tmp) = (Pixmap)NULL;
  EZ_LEDPixmapC(tmp) = (Pixmap)NULL;
  EZ_LEDSRows(tmp) = 10;
  EZ_LEDSCols(tmp) = 60;
  EZ_LEDOldW(tmp) = 0;
  EZ_LEDOldH(tmp) = 0;
  EZ_LEDAdvance(tmp) = 0;
  EZ_LEDDirty(tmp) = LED_ALL_DIRTY;
  EZ_LEDImage(tmp) = (unsigned char *)NULL;
  EZ_LEDStringLength(tmp) = 0;
  EZ_LEDString(tmp) = EZ_AllocCopyString(NULL);
  EZ_LEDNLines(tmp) = 1;
  EZ_LEDLineLength(tmp) = 6000;
  EZ_LEDTextWidth(tmp) = 1;
  EZ_LEDTextHeight(tmp) = 1;
  EZ_LEDMaskW(tmp) = 0;
  EZ_LEDMaskH(tmp) = 0;
  EZ_LEDXOffset(tmp) = 0;
  EZ_LEDYOffset(tmp) = 0;
  EZ_LEDColorF(tmp) = NULL;
  EZ_LEDStatus(tmp) = 0;
  EZ_LEDXYIdx(tmp) = 0;
  EZ_LEDOther(tmp) = 0;
  (void) EZ_CreateTimer(1, 0, -1, (EZ_CallBack)TimerSCallBack, (void *)tmp, 0);
  return(tmp);
}


void EZ_FreeWidgetLedData(widget)
     EZ_Widget *widget;
{
  if(EZ_LEDString(widget) != (char *)NULL)
    my_free((char *)EZ_LEDString(widget));
  if(EZ_LEDPixmap(widget) != (Pixmap)NULL)
    XFreePixmap(EZ_Display, EZ_LEDPixmap(widget));
  if(EZ_LEDPixmapC(widget) != (Pixmap)NULL)
    XFreePixmap(EZ_Display, EZ_LEDPixmapC(widget));
  if(EZ_LEDImage(widget) != NULL) my_free((char *)EZ_LEDImage(widget));
  {
    EZ_LedAction *tmp, *head = EZ_LEDAction(widget);
    while(head) { tmp = head->next; ledDestroyAction(head); head = tmp; }
  }
}

 
/********************************************************************
 *
 *  Figure out the dimension of a lcd widget.
 */
void EZ_ComputeWidgetLedSize(widget, w, h)
    EZ_Widget *widget;
     int             *w, *h;
{
  int      length, height, cw, ch;
	    
  if(!(EZ_GetWidgetSizeComputedFlag(widget))){ EZ_SetWidgetSizeComputedFlag(widget);}
  
  length = EZ_LEDSize(widget) * EZ_LEDSCols(widget);
  height = EZ_LEDSize(widget) * EZ_LEDSRows(widget);

  EZ_WidgetPadX(widget) =0; /* padding does not make too much sense for a led */
  EZ_WidgetPadY(widget) =0; 
  EZ_WidgetPadB(widget) =0;
  cw = EZ_WidgetBorderWidth(widget);  
  ch = EZ_WidgetBorderWidth(widget);
  cw = cw + cw + length;
  ch = ch + ch + height;  

  *w = cw;
  *h = ch;
}

/*******************************************************************
 *
 *  Draw A Led Widget.
 */
void  EZ_DrawWidgetLed(wptr)
     EZ_Widget *wptr;
{
  int       w, h, bw, bw2, ww,hh, rows, cols, size, fixoff=0;
  Pixmap    pixmap, pixb;
  Window    win;

  win = EZ_WidgetWindow(wptr);
  w   = EZ_WidgetWidth(wptr);
  h   = EZ_WidgetHeight(wptr);
  bw = EZ_WidgetBorderWidth(wptr);
  bw2 = bw+bw;
  ww = w - bw2; hh = h - bw2;
  size = EZ_LEDSize(wptr);
  rows = (hh + size -1)/size;
  cols = (ww + size -1)/size; 
  EZ_LEDRows(wptr) = rows;
  EZ_LEDCols(wptr) = cols;

  if(EZ_LEDDirty(wptr) & LED_MASK_DIRTY)
    {
      fixoff = 1;
      LedCreateMask(wptr);
    }
  if((EZ_LEDOldW(wptr) != ww) || (EZ_LEDOldH(wptr) != hh))
    {
      EZ_LEDOldW(wptr) = ww;  EZ_LEDOldH(wptr) = hh;
      if(EZ_LEDPixmap(wptr) != (Pixmap)NULL) XFreePixmap(EZ_Display, EZ_LEDPixmap(wptr));
      if(EZ_LEDPixmapC(wptr) != (Pixmap)NULL)XFreePixmap(EZ_Display, EZ_LEDPixmapC(wptr));
      EZ_LEDPixmap(wptr) = XCreatePixmap(EZ_Display, win, ww, hh, EZ_Depth);       
      EZ_LEDPixmapC(wptr) = XCreatePixmap(EZ_Display, win, ww, hh, EZ_Depth);       
      EZ_LEDDirty(wptr) |= (LED_PIXMAP_DIRTY | LED_PIXMAPC_DIRTY);
      fixoff = 1;
    }
  if(fixoff) fixLedInitOffsets(wptr);

  if(EZ_LEDDirty(wptr) & LED_PIXMAPC_DIRTY)
    LedCreatePixmapC(wptr, ww, hh);
  if(EZ_LEDDirty(wptr) & LED_PIXMAP_DIRTY)  
    LedCreatePixmap(wptr, ww, hh);
  
  pixb = EZ_LEDPixmap(wptr);  
  if(bw2 != 0)
    {
      pixmap = XCreatePixmap(EZ_Display, win, w, h, EZ_Depth); 
      XCopyArea(EZ_Display,pixb,pixmap, EZ_WRITABLEGC,0,0,ww,hh,bw,bw);       
      EZ_DrawRectBorder(wptr, pixmap);     
      XCopyArea(EZ_DisplayForWidgets,pixmap,win, EZ_WRITABLEGC,0,0,w,h,0,0); 
      XFreePixmap(EZ_DisplayForWidgets, pixmap); 
    }
  else
    XCopyArea(EZ_Display,pixb,win, EZ_WRITABLEGC,0,0,ww,hh,0,0);       
}
static void fixLedInitOffsets(wptr)
     EZ_Widget *wptr;
{
  int cols = EZ_LEDCols(wptr);
  int rows = EZ_LEDRows(wptr);
  int xtmp, ytmp;

  xtmp = (EZ_LEDTextWidth(wptr) - cols );
  if(xtmp < 0)
    {
      switch(EZ_WidgetLabelPosition(wptr)) 
	{
	case EZ_CENTER:    EZ_LEDXOffset(wptr) = xtmp/2; break;
	case EZ_RIGHT:  case EZ_TOP_RIGHT: case EZ_BOTTOM_RIGHT:
	  EZ_LEDXOffset(wptr) = xtmp;   break;
	default:  EZ_LEDXOffset(wptr) = 0; break;
	}
    }
  else EZ_LEDXOffset(wptr)  = 0;
  ytmp = EZ_LEDTextHeight(wptr) - rows;
  if(ytmp < 0 )
    {
      switch(EZ_WidgetLabelPosition(wptr)) 
	{
	case EZ_CENTER: EZ_LEDYOffset(wptr) = ytmp/2; break;
	case EZ_BOTTOM: case EZ_BOTTOM_LEFT: case EZ_BOTTOM_RIGHT: 
	  EZ_LEDYOffset(wptr) = ytmp; break;
	default:  EZ_LEDYOffset(wptr) = 0; break;
	}
    }
  else EZ_LEDYOffset(wptr) = 0;
}
/***************************************************************/
void EZ_LedEventHandle(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)
	    {
	      Time  time_stamp = event->xbutton.time;   
	      int   elapsedtime = EZ_LastButton1ClickTime - time_stamp;
	      EZ_LastButton1ClickTime = time_stamp;
	  
	      if(ABSV(elapsedtime) < DOUBLE_CLICK_TIME_INTERVAL)
		{
		  if(EZ_WidgetCallBackFunc(widget))
		    {
		      { EZ_ExecuteWidgetCallBacks(widget);}
		      return;
		    }
		}
	    }
	  else if(event->xbutton.button == EZ_Btn3)
	    {
#include "EZ_DnDHandler1.c"
	      EZ_DnDEventHandler1(widget, event);
	    }
	}
    }
}
/****************************************************************************/

static void LedDrawPixel(pixb,gc,x,y,size)
     Drawable pixb;
     GC gc;
     int x,y,size;
{
  int j = x *size;
  int i = y *size;
  switch(size)
    {
    case 2:
      XDrawPoint(EZ_Display, pixb, gc,j,i);
      break;
    case 3:
      XFillRectangle(EZ_Display, pixb, gc, j,i,2,2);
      break;
    case 4:
      XDrawLine(EZ_Display, pixb,gc,j,i+1,j+2,i+1);		    
      XDrawLine(EZ_Display, pixb, gc,j+1,i,j+1,i+2);		    
      break;
    case 5:
      XFillRectangle(EZ_Display, pixb, gc, j+1,i,2,4);
      XFillRectangle(EZ_Display, pixb,gc, j,i+1,4,2);
      break;
    default:
      break;
    }
}
static void LedCreateMask(wptr)
     EZ_Widget *wptr;
{
  Pixmap pixb;
  GC  gc;
  XImage *image;
  int rows, cols, itmp, jtmp, nlines, height, ascent;
  XFontStruct *font_info = EZ_WidgetFont(wptr);

  if(EZ_LEDStringLength(wptr) > 0)
    {
      EZ_FigureLabelExtent(font_info, EZ_LEDString(wptr),EZ_LEDStringLength(wptr),
			   (int)EZ_LEDLineLength(wptr),
			   &nlines, &cols);
      if(cols == 0) cols = 1;
    }
  else { cols = 1; nlines = 1;}


  EZ_LEDNLines(wptr) = nlines;
  ascent = font_info->ascent;
  height = ascent + font_info->descent;
  rows = height * nlines;

  EZ_LEDTextWidth(wptr) =  cols;
  EZ_LEDTextHeight(wptr) = rows;  

  itmp = ((cols + 7)/8);
  jtmp = itmp * rows;

  if(EZ_LEDMaskW(wptr) < itmp || EZ_LEDMaskH(wptr) < rows )
    {
      if(EZ_LEDImage(wptr) != NULL) my_free((void *)EZ_LEDImage(wptr));
      EZ_LEDImage(wptr) = (unsigned char *)my_malloc(jtmp * sizeof(char), _EZ_LED_DATA_);
      EZ_LEDMaskW(wptr) = itmp;        EZ_LEDMaskH(wptr) = rows;      
    }
  pixb = XCreatePixmap(EZ_Display, EZ_WidgetWindow(wptr), cols, rows, EZ_Depth); 
  gc =  EZ_WRITABLEGC;
  XSetForeground(EZ_Display, EZ_WRITABLEGC, 0);
  XFillRectangle(EZ_Display, pixb, gc, 0,0, cols,rows); 
  XSetForeground(EZ_Display, gc, 1);
  XSetFont(EZ_Display,  gc, EZ_WidgetFont(wptr)->fid);
  if(EZ_LEDStringLength(wptr)> 0)
    EZ_RenderLabelText(pixb,gc,0,ascent,height,EZ_LEDString(wptr),EZ_LEDStringLength(wptr),
		       (int)EZ_LEDLineLength(wptr), nlines,
		       cols, EZ_WidgetJustification(wptr), font_info);
  image = XGetImage(EZ_Display, pixb, 0,0, cols,rows, 1, XYPixmap);
  {
    int x, y, advance, itmp, ktmp;
    unsigned int ch;
    unsigned char *row = EZ_LEDImage(wptr);
    unsigned long pixel;
    advance = EZ_LEDAdvance(wptr);
    
    for(y = 0; y < rows; y++, row += advance)
      {
	for(ch = 0, ktmp = 0, itmp = 0, x = 0; x < cols; x++)
	  {
	    pixel = XGetPixel(image,x,y);
	    if(pixel != 0) ch |= (1 << ktmp);
	    ktmp++;
	    if(ktmp == 8)
	      {
		row[itmp] = (unsigned char)ch;
		itmp++;
		ktmp = 0;
		ch = 0;
	      }
	  }
	if(ktmp != 0){ row[itmp] = (unsigned char)ch;}
      }
  }
  XDestroyImage(image);
  XFreePixmap(EZ_Display, pixb);
  EZ_LEDDirty(wptr) &= ~LED_MASK_DIRTY;
}


static void LedCreatePixmapC(wptr, ww, hh)
     EZ_Widget *wptr; int ww, hh;
{
  int  xx, yy, size, rows, cols;
  unsigned long pixel;
  Pixmap  pixb = EZ_LEDPixmapC(wptr);
  GC   gc;
  pixel = EZ_LEDBG(wptr);	
  if(pixel != ~0)
    {
      gc = EZ_WRITABLEGC;
      XSetForeground(EZ_Display, gc, pixel);
    }
  else EZ_GetBackgroundGC(wptr, &gc, &pixel, 0, 0);
  XFillRectangle(EZ_Display, pixb, gc, 0,0, ww, hh); 

  pixel = EZ_LEDBGL(wptr);
  if(pixel != ~0)	
    {
      gc = EZ_WRITABLEGC;
      XSetForeground(EZ_Display, gc, pixel);
    }
  else EZ_GetBrightBDGC(wptr, &gc);

  rows = EZ_LEDRows(wptr);
  cols = EZ_LEDCols(wptr);
  size = EZ_LEDSize(wptr);
  for(yy = 0; yy < rows; yy++)
    for(xx = 0; xx < cols; xx++)
      LedDrawPixel(pixb,gc,xx,yy,size); 
  EZ_LEDDirty(wptr) &= ~LED_PIXMAPC_DIRTY;
}
/**************************************************************/

static void LedCreatePixmap(wptr, ww, hh)
     EZ_Widget *wptr; int ww, hh;
{
  Pixmap  pixb = EZ_LEDPixmap(wptr);      
  Pixmap  pixc = EZ_LEDPixmapC(wptr);
  XCopyArea(EZ_Display, pixc, pixb, EZ_WRITABLEGC,0,0,ww,hh,0,0);       

  if(EZ_LEDStringLength(wptr)> 0)      
    {
      int x, y,  cnt, rows, cols, size, xoff, yoff;
      int tw, th, px, py,ix,iy, ii, jj, kk, flag;
      unsigned int mask;
      int advance = EZ_LEDAdvance(wptr);
      unsigned char *masks = EZ_LEDImage(wptr);
      GC   gc = EZ_WRITABLEGC;
      unsigned long pixel, tpixel;
      EZ_LedPixelColorF colorf;

      pixel = EZ_WidgetForeground(wptr);
      XSetForeground(EZ_Display, gc, pixel);
      
      rows = EZ_LEDRows(wptr);
      cols = EZ_LEDCols(wptr);
      tw = EZ_LEDTextWidth(wptr);
      th = EZ_LEDTextHeight(wptr);
      size = EZ_LEDSize(wptr);
      xoff = EZ_LEDXOffset(wptr);
      yoff = EZ_LEDYOffset(wptr);
      colorf = EZ_LEDColorF(wptr);

      if(xoff < 0) { px = -xoff; ix = 0;}
      else { px = 0; ix = xoff; }
      if(yoff < 0) { py = -yoff; iy = 0;}
      else { py = 0; iy = yoff; }

      for(y=py, jj=iy, masks +=(iy *advance); y<rows && jj<th;  y++, jj++, masks += advance)
	{
	  for(x = px, ii = ix; x < cols && ii < tw; x++, ii++)
	    {
	      if(colorf)
		{
		  tpixel = (colorf)(x,y);
		  if(tpixel != pixel)
		    {
		      pixel = tpixel;
		      XSetForeground(EZ_Display, gc, pixel);
		    }
		}
	      cnt = (ii >> 3);  kk = (ii & 0x7); flag = 1 << kk;
	      mask= (unsigned int)(masks[cnt]);
	      if(mask&flag)  LedDrawPixel(pixb,gc,x,y,size);
	    }
	}
    }
  EZ_LEDDirty(wptr) &= ~LED_PIXMAP_DIRTY;
}
/***********************************************************************/
void EZ_SetLedColorFunction(widget, f)
     EZ_Widget *widget; EZ_LedPixelColorF f;
{
  if(widget && EZ_WidgetType(widget) == EZ_WIDGET_LED)
    {
      EZ_LEDStatus(widget) |= LED_BLOCKED;
      EZ_LEDColorF(widget) = f;
      if(EZ_WidgetIsViewable(widget)) EZ_DrawWidget(widget);
      EZ_LEDStatus(widget) &= ~LED_BLOCKED;
    }
}

void EZ_SetLedString(widget, str, clr)
     EZ_Widget *widget; char *str, *clr;
{
  if(widget && EZ_WidgetType(widget) == EZ_WIDGET_LED)
    {
      unsigned long  pixel_value;
      EZ_LEDStatus(widget) |= LED_BLOCKED;
      pixel_value = EZ_AllocateColorFromName(clr);
      if(pixel_value != 0 && EZ_WidgetForeground(widget) != pixel_value)
	EZ_WidgetForeground(widget) = pixel_value;
      EZ_SetWidgetLabelString(widget,str);
      if(EZ_WidgetIsViewable(widget)) EZ_DrawWidget(widget);
      EZ_LEDStatus(widget) &= ~LED_BLOCKED;
    }
}

char  *EZ_GetLedString(led)
     EZ_Widget *led;
{
  if(led && EZ_WidgetType(led) == EZ_WIDGET_LED)
    return(EZ_LEDString(led));
  return(NULL);
}

void EZ_SetLedForeground(widget, str)
     EZ_Widget *widget; char *str;
{
  if(widget && EZ_WidgetType(widget) == EZ_WIDGET_LED)
    {
      unsigned long  pixel_value;
      pixel_value = EZ_AllocateColorFromName(str);
      if(pixel_value != 0 && EZ_WidgetForeground(widget) != pixel_value)
	{
	  EZ_LEDStatus(widget) |= LED_BLOCKED;
	  EZ_WidgetForeground(widget) = pixel_value;
	  if(EZ_WidgetIsViewable(widget)) EZ_DrawWidget(widget);  
	  EZ_LEDStatus(widget) &= ~LED_BLOCKED;
	}
    }
}
void EZ_SetLedBackground(widget, str)
     EZ_Widget *widget; char *str;
{
  if(widget && EZ_WidgetType(widget) == EZ_WIDGET_LED)
    {
      unsigned long  pixel_value;
      pixel_value = EZ_AllocateColorFromName(str);
      if(EZ_LEDBG(widget) != pixel_value)
	{
	  EZ_LEDStatus(widget) |= LED_BLOCKED;
	  EZ_LEDBG(widget) = pixel_value;
	  EZ_LEDDirty(widget) |= (LED_PIXMAP_DIRTY | LED_PIXMAPC_DIRTY);
	  if(EZ_WidgetIsViewable(widget)) EZ_DrawWidget(widget);  
	  EZ_LEDStatus(widget) &= ~LED_BLOCKED;
	}
    }
}
void EZ_SetLedOffPixelColor(widget, str)
     EZ_Widget *widget; char *str;
{
  if(widget && EZ_WidgetType(widget) == EZ_WIDGET_LED)
    {
      unsigned long  pixel_value;
      pixel_value = EZ_AllocateColorFromName(str);
      if(EZ_LEDBGL(widget) != pixel_value)
	{
	  EZ_LEDStatus(widget) |= LED_BLOCKED;
	  EZ_LEDBGL(widget) = pixel_value;
	  EZ_LEDDirty(widget) |= (LED_PIXMAP_DIRTY | LED_PIXMAPC_DIRTY);
	  if(EZ_WidgetIsViewable(widget)) EZ_DrawWidget(widget);  
	  EZ_LEDStatus(widget) &= ~LED_BLOCKED;
	}
    }
}
void EZ_SetLedFont(widget, name)
     EZ_Widget *widget; char *name;
{
  if(widget && EZ_WidgetType(widget) == EZ_WIDGET_LED)
    {  
      int font = EZ_LoadXFont(name);
      XFontStruct *fontstruct = EZ_GetFontFromId(font);
      if(EZ_WidgetFont(widget) != fontstruct)
	{
	  EZ_LEDStatus(widget) |= LED_BLOCKED;
	  EZ_WidgetFont(widget) = fontstruct;
	  EZ_LEDDirty(widget) |= (LED_PIXMAP_DIRTY | LED_MASK_DIRTY);      
	  if(EZ_WidgetIsViewable(widget)) EZ_DrawWidget(widget);  
	  EZ_LEDStatus(widget) &= ~LED_BLOCKED;
	}
    }
}

void EZ_SetLedWidth(widget, w)
     EZ_Widget *widget; int w;
{
  if(widget && EZ_WidgetType(widget) == EZ_WIDGET_LED && w > 0)
    {
      if(EZ_LEDSCols(widget) != w)
	{
	  EZ_LEDStatus(widget) |= LED_BLOCKED;
	  EZ_LEDSCols(widget) = w;
	  EZ_LEDDirty(widget) |= (LED_PIXMAP_DIRTY | LED_PIXMAPC_DIRTY);
	  if(EZ_WidgetIsViewable(widget)) EZ_ReDisplayWidget(widget);
	  EZ_LEDStatus(widget) &= ~LED_BLOCKED;
	}
    }
}
void EZ_SetLedHeight(widget, h)
     EZ_Widget *widget; int h;
{
  if(widget && EZ_WidgetType(widget) == EZ_WIDGET_LED && h > 0)
    {
      if(EZ_LEDSRows(widget) != h)
	{
	  EZ_LEDStatus(widget) |= LED_BLOCKED;
	  EZ_LEDSRows(widget) = h;
	  EZ_LEDDirty(widget) |= (LED_PIXMAP_DIRTY | LED_PIXMAPC_DIRTY);
	  if(EZ_WidgetIsViewable(widget)) EZ_ReDisplayWidget(widget);
	  EZ_LEDStatus(widget) &= ~LED_BLOCKED;
	}
    }
}
void EZ_SetLedSize(widget, w, h)
     EZ_Widget *widget; int w, h;
{
  if(widget && EZ_WidgetType(widget) == EZ_WIDGET_LED && w > 0 && h > 0)
    {
      EZ_LEDStatus(widget) |= LED_BLOCKED;
      EZ_LEDSCols(widget) = w;
      EZ_LEDSRows(widget) = h;
      EZ_LEDDirty(widget) |= (LED_PIXMAP_DIRTY | LED_PIXMAPC_DIRTY); 
      if(EZ_WidgetIsViewable(widget)) EZ_ReDisplayWidget(widget);
      EZ_LEDStatus(widget) &= ~LED_BLOCKED;
    }
}
void EZ_SetLedPixelSize(widget, s)
     EZ_Widget *widget; int s;
{
  if(widget && EZ_WidgetType(widget) == EZ_WIDGET_LED)
    {
      if(s < 0) s = 1; else if(s>4) s = 4; s++;
      if(EZ_LEDSize(widget) != s)
	{
	  EZ_LEDStatus(widget) |= LED_BLOCKED;
	  EZ_LEDSize(widget) = s;
	  EZ_LEDDirty(widget) |= (LED_PIXMAP_DIRTY | LED_PIXMAPC_DIRTY); 
	  if(EZ_WidgetIsViewable(widget)) EZ_ReDisplayWidget(widget);
	  EZ_LEDStatus(widget) &= ~LED_BLOCKED;
	}
    }
}
/***********************************************************************/
void EZ_ClearLed(widget)
     EZ_Widget *widget;
{
  if(widget && EZ_WidgetType(widget) == EZ_WIDGET_LED)
    {
      EZ_LEDStatus(widget) |= LED_BLOCKED;
      if(EZ_LEDStringLength(widget) != 0)
	{
	  EZ_LEDStringLength(widget) = 0;
	  EZ_LEDDirty(widget) |= (LED_MASK_DIRTY | LED_PIXMAP_DIRTY);      
	  if(EZ_WidgetIsViewable(widget)) EZ_DrawWidget(widget);
	}
      /* clear the action queue */
      {
	EZ_LedAction *tmp, *head = EZ_LEDAction(widget);
	while(head) { tmp = head->next; ledDestroyAction(head); head = tmp; }
	EZ_LEDAction(widget) = NULL;
      }      
      EZ_LEDStatus(widget) &= ~LED_BLOCKED;
    }
}
/***********************************************************************/
static void LedDrawColumn(widget, drawable, idx)
     EZ_Widget *widget; Drawable drawable; int idx;
{
  int size, nrows, ncols, x, y, advance, xoff, yoff;
  int px, py, ix, iy, ii, jj, kk, th, cnt, flag;
  unsigned int mask;
  unsigned char *masks;
  GC   gc = EZ_WRITABLEGC;
  unsigned long pixel, tpixel;
  EZ_LedPixelColorF colorf;

  nrows = EZ_LEDRows(widget);
  ncols = EZ_LEDCols(widget);
  size = EZ_LEDSize(widget);
  xoff = EZ_LEDXOffset(widget);
  yoff = EZ_LEDYOffset(widget);

  if(xoff < 0) { px = -xoff; ix = 0;}
  else { px = 0; ix = xoff; }
  if(yoff < 0) { py = -yoff; iy = 0;}
  else { py = 0; iy = yoff; }

  ii = idx - px + ix;
  if(idx < px || idx > ncols || (ii) > EZ_LEDTextWidth(widget)) {return;}
  pixel = EZ_WidgetForeground(widget);
  XSetForeground(EZ_Display, gc, pixel);

  th = EZ_LEDTextHeight(widget);
  cnt = (ii >> 3); kk = (ii & 0x7); flag= 1<<kk;
  masks = EZ_LEDImage(widget);
  advance = EZ_LEDAdvance(widget);
  colorf = EZ_LEDColorF(widget);
  x = idx;
  for(y=py, jj=iy, masks +=(iy *advance); y<nrows && jj<th;  y++, jj++, masks += advance)
    {
      if(colorf)
	{
	  tpixel = (colorf)(x,y);
	  if(tpixel != pixel)
	    {
	      pixel = tpixel;
	      XSetForeground(EZ_Display, gc, pixel);
	    }	  
	}
      mask= (unsigned int)(masks[cnt]);
      if(mask&flag) {  LedDrawPixel(drawable,gc,x,y,size); }
    }
}

static void LedDrawRow(widget, drawable, idx)
     EZ_Widget *widget; Drawable drawable; int idx;
{
  int size, nrows, ncols, x, y, advance, xoff, yoff;
  int px, py, ix, iy, ii, kk, cnt, flag,tw;
  unsigned int mask;
  unsigned char *masks;
  GC   gc = EZ_WRITABLEGC;
  unsigned long pixel, tpixel;
  EZ_LedPixelColorF colorf;

  nrows = EZ_LEDRows(widget);
  ncols = EZ_LEDCols(widget);
  size = EZ_LEDSize(widget);
  xoff = EZ_LEDXOffset(widget);
  yoff = EZ_LEDYOffset(widget);
  
  if(xoff < 0) { px = -xoff; ix = 0;}
  else { px = 0; ix = xoff; }
  if(yoff < 0) { py = -yoff; iy = 0;}
  else { py = 0; iy = yoff; }

  if(idx < py || idx >= nrows || (iy+idx-py) >= EZ_LEDTextHeight(widget)) return;
  pixel = EZ_WidgetForeground(widget);
  XSetForeground(EZ_Display, gc, pixel);

  tw = EZ_LEDTextWidth(widget);
  advance = EZ_LEDAdvance(widget);
  masks = EZ_LEDImage(widget) + ((iy + (idx -py) ) * advance);
  colorf = EZ_LEDColorF(widget);
  y = idx;
  for(x = px, ii = ix; x < ncols && ii < tw; x++, ii++)
    {
      if(colorf)
	{
	  tpixel = (colorf)(x,y);
	  if(tpixel != pixel)
	    {
	      pixel = tpixel;
	      XSetForeground(EZ_Display, gc, pixel);
	    }	  
	}
      cnt = (ii >> 3);  kk = (ii & 0x7); flag = 1 << kk;
      mask= (unsigned int)(masks[cnt]);
      if(mask&flag)  { LedDrawPixel(drawable,gc,x,y,size); }
    }
}
/***********************************************************************/

static void TimerSCallBack(timer, data)
     EZ_Timer *timer; void *data;
{
  /* this is the action schedular, wake up once a second */
  EZ_Widget *led = (EZ_Widget *)data;
  if(EZ_WidgetExist(led) && EZ_WidgetType(led) == EZ_WIDGET_LED)
    {
      EZ_LedAction *at;
      int tw, th, rows, cols;
      if(EZ_LEDStatus(led) & LED_BLOCKED) return; 
      if(EZ_WidgetIsViewable(led) == 0) return;

      at = EZ_LEDAction(led);
      if(at == NULL || at->status != LED_AT_WAITING) return;

      at->status = LED_AT_RUNNING; 
      if(at->color != 0)
	{
	  at->colorf = EZ_LEDColorF(led);
	  EZ_LEDColorF(led) = NULL;
	  EZ_WidgetForeground(led) = at->color;
	}
      
      /* now do the set up */
      if(at->str != NULL)
	{
	  if( EZ_LEDString(led) == NULL ||  strcmp(at->str,EZ_LEDString(led)) != 0)
	    {
	      EZ_SetWidgetLabelString(led, at->str);
	      EZ_LEDStatus(led) &=  ~LED_BLOCKED;
	      /* make mask, set initial offset */
	      LedCreateMask(led);	
	      EZ_LEDDirty(led) &= ~LED_MASK_DIRTY;       
	    }
	}
      tw = EZ_LEDTextWidth(led);
      th = EZ_LEDTextHeight(led);
      rows = EZ_LEDRows(led);
      cols = EZ_LEDCols(led);
      fixLedInitOffsets(led);
      switch(at->type)
	{
	case LED_SB_LEFT:
	case LED_SC_LEFT:
	  EZ_LEDXOffset(led) = -cols;
	  break;
	case LED_SB_RIGHT:
	case LED_SC_RIGHT:
	  EZ_LEDXOffset(led) = tw;
	  break;
	case LED_SC_UP: 
	  EZ_LEDYOffset(led) = -rows;
	  break;
	case LED_SC_DOWN: 
	  EZ_LEDYOffset(led) = th;
	  break;
	case LED_SW_LEFT:
	  EZ_LEDXYIdx(led) = 0;
	  break;	  
	case LED_SW_RIGHT:
	  EZ_LEDXYIdx(led) = cols;
	  break;
	case LED_SW_UP:
	  EZ_LEDXYIdx(led) = rows;
	  break;
	case LED_SW_DOWN:
	  EZ_LEDXYIdx(led) = 0;
	  break;
	case LED_BLINK:
	  EZ_LEDXYIdx(led) = 0;
	  break;
	case LED_SC_CENTER:
	case LED_SC_CENTER_V:
	  EZ_LEDXYIdx(led) = 0;
	  break;
	case LED_SW_CENTER:
	case LED_SW_CENTER_V:
	  EZ_LEDXYIdx(led) = 0;
	  break;
	case LED_BOUNCE:
	  if(EZ_LEDDirty(led) & LED_PIXMAP_DIRTY)	  
	    LedCreatePixmap(led, EZ_LEDOldW(led),EZ_LEDOldH(led));
	  EZ_LEDXYIdx(led) = EZ_LEDXOffset(led);
	  EZ_LEDOther(led) = 0;
	  break;
	case LED_BOUNCE_V:
	  if(EZ_LEDDirty(led) & LED_PIXMAP_DIRTY)	  
	    LedCreatePixmap(led, EZ_LEDOldW(led),EZ_LEDOldH(led));
	  EZ_LEDXYIdx(led) = EZ_LEDYOffset(led);
	  EZ_LEDOther(led) = 0;
	  break;
	case LED_SLEEP:
	  if(EZ_LEDDirty(led) & LED_PIXMAP_DIRTY)	  
	    LedCreatePixmap(led, EZ_LEDOldW(led),EZ_LEDOldH(led));	  
	  break;
	default:
	  break;
	}
      (void) EZ_CreateTimer(0, (long)at->delay, -1, (EZ_CallBack)TimerRCallBack, 
			    (void *)led, at->serial);
    }
  else EZ_CancelTimer(timer);
}

/* execute led actions */
static void TimerRCallBack(timer, data) 
     EZ_Timer *timer; void *data;
{
  EZ_Widget *led = (EZ_Widget *)data;
  if(EZ_WidgetExist(led) && EZ_WidgetType(led) == EZ_WIDGET_LED)
    {
      EZ_LedAction *at;
      int idata;
      if(EZ_WidgetIsViewable(led) == 0) return;   /* later */
      if(EZ_LEDStatus(led) & LED_BLOCKED) return; 

      idata = EZ_GetTimerIntData(timer);      
      at = EZ_LEDAction(led);
      if(at && at->serial == idata)
	{
	  int type = at->type;
	  int finished = 0;
	  Window win = EZ_WidgetWindow(led);
	  int bw = EZ_WidgetBorderWidth(led);
	  int size = EZ_LEDSize(led);
	  Pixmap pixmap = EZ_LEDPixmap(led);
	  Pixmap pixtmp;
	  int tw = EZ_LEDTextWidth(led);
	  int th = EZ_LEDTextHeight(led);
	  int ww = EZ_LEDOldW(led);
	  int hh = EZ_LEDOldH(led);
	  int rows = EZ_LEDRows(led);
	  int cols = EZ_LEDCols(led);
	  switch(type)
	    {
	    case LED_BOUNCE:
	      if(tw < cols)
		{
		  if(EZ_LEDOther(led) < 3) /* going left */
		    {
		      if(EZ_LEDOther(led) == 0) /* going left */ 
			{
			  if(EZ_LEDXOffset(led) > 0) EZ_LEDOther(led) += 1;
			  else
			    {
			      EZ_LEDXOffset(led) += 1;
			      pixtmp = XCreatePixmap(EZ_Display, win, ww, hh, EZ_Depth);       
			      XCopyArea(EZ_Display, pixmap, pixtmp, EZ_WRITABLEGC,
					size,0,ww-size, hh, 0, 0);
			      XCopyArea(EZ_Display, EZ_LEDPixmapC(led),pixtmp,EZ_WRITABLEGC,
					ww-size,0, size, hh, ww-size, 0);
			      XCopyArea(EZ_Display, pixtmp,pixmap,EZ_WRITABLEGC,
					0,0, ww, hh, 0, 0);
			      XCopyArea(EZ_Display, pixmap,win,EZ_WRITABLEGC,
					0,0,ww,hh,bw,bw);
			      XFreePixmap(EZ_Display, pixtmp);
			    }
			}
		      else if(EZ_LEDOther(led) == 1) /* going right */
			{
			  if(EZ_LEDXOffset(led) <= (tw -cols)) EZ_LEDOther(led) += 1;
			  else
			    {
			      EZ_LEDXOffset(led) -= 1;
			      pixtmp = XCreatePixmap(EZ_Display, win, ww, hh, EZ_Depth);       
			      XCopyArea(EZ_Display, pixmap, pixtmp, EZ_WRITABLEGC,
					0,0,ww-size, hh, size, 0);
			      XCopyArea(EZ_Display, EZ_LEDPixmapC(led),pixtmp,EZ_WRITABLEGC,
					0,0, size, hh, 0, 0);
			      XCopyArea(EZ_Display, pixtmp,pixmap,EZ_WRITABLEGC,
					0,0, ww, hh, 0, 0);
			      XCopyArea(EZ_Display, pixmap,win,EZ_WRITABLEGC,
					0,0,ww,hh,bw,bw);
			      XFreePixmap(EZ_Display, pixtmp);
			    }
			}
		      else  /* coming back to its original location */
			{
			  int tmp = EZ_LEDXOffset(led) - EZ_LEDXYIdx(led);
			  if(tmp < 0)
			    {
			      EZ_LEDXOffset(led) += 1;
			      pixtmp = XCreatePixmap(EZ_Display, win, ww, hh, EZ_Depth);       
			      XCopyArea(EZ_Display, pixmap, pixtmp, EZ_WRITABLEGC,
					size,0,ww-size, hh, 0, 0);
			      XCopyArea(EZ_Display, EZ_LEDPixmapC(led),pixtmp,EZ_WRITABLEGC,
					ww-size,0, size, hh, ww-size, 0);
			      XCopyArea(EZ_Display, pixtmp,pixmap,EZ_WRITABLEGC,
					0,0, ww, hh, 0, 0);
			      XCopyArea(EZ_Display, pixmap,win,EZ_WRITABLEGC,
					0,0,ww,hh,bw,bw);
			      XFreePixmap(EZ_Display, pixtmp);
			    }
			  else  EZ_LEDOther(led) += 1;
			}
		    }
		  else  finished = 1;
		  if(finished && --(at->count) > 0) 
		    {
		      EZ_LEDXYIdx(led) = EZ_LEDXOffset(led);
		      finished = 0; EZ_LEDOther(led) = 0; 
		    }
		}
	      else finished = 1;
	      break;
	    case LED_BOUNCE_V:
	      if(th < rows)
		{
		  if(EZ_LEDOther(led) < 3) 
		    {
		      if(EZ_LEDOther(led) == 0) /* going up */ 
			{
			  if(EZ_LEDYOffset(led) > 0) EZ_LEDOther(led) += 1;
			  else
			    {
			      EZ_LEDYOffset(led) += 1;
			      pixtmp = XCreatePixmap(EZ_Display, win, ww, hh, EZ_Depth);       
			      XCopyArea(EZ_Display, pixmap, pixtmp, EZ_WRITABLEGC,
					0, size,ww, hh-size, 0, 0);
			      XCopyArea(EZ_Display, EZ_LEDPixmapC(led),pixtmp,EZ_WRITABLEGC,
					0,hh-size, ww, size, 0, hh-size);
			      XCopyArea(EZ_Display, pixtmp,pixmap,EZ_WRITABLEGC,
					0,0, ww, hh, 0, 0);
			      XCopyArea(EZ_Display, pixmap,win,EZ_WRITABLEGC,
					0,0,ww,hh,bw,bw);
			      XFreePixmap(EZ_Display, pixtmp);
			    }
			}
		      else if(EZ_LEDOther(led) == 1) /* going down */
			{
			  if(EZ_LEDYOffset(led) <= (th -rows)) EZ_LEDOther(led) += 1;
			  else
			    {
			      EZ_LEDYOffset(led) -= 1;
			      pixtmp = XCreatePixmap(EZ_Display, win, ww, hh, EZ_Depth);       
			      XCopyArea(EZ_Display, pixmap, pixtmp, EZ_WRITABLEGC,
					0,0,ww, hh-size, 0, size);
			      XCopyArea(EZ_Display, EZ_LEDPixmapC(led),pixtmp,EZ_WRITABLEGC,
					0,0, ww, size, 0, 0);
			      XCopyArea(EZ_Display, pixtmp,pixmap,EZ_WRITABLEGC,
					0,0, ww, hh, 0, 0);
			      XCopyArea(EZ_Display, pixmap,win,EZ_WRITABLEGC,
					0,0,ww,hh,bw,bw);
			      XFreePixmap(EZ_Display, pixtmp);
			    }
			}
		      else  /* coming back to its original location */
			{
			  int tmp = EZ_LEDYOffset(led) - EZ_LEDXYIdx(led);
			  if(tmp < 0)
			    {
			      EZ_LEDYOffset(led) += 1;
			      pixtmp = XCreatePixmap(EZ_Display, win, ww, hh, EZ_Depth);       
			      XCopyArea(EZ_Display, pixmap, pixtmp, EZ_WRITABLEGC,
					0, size,ww, hh-size, 0, 0);
			      XCopyArea(EZ_Display, EZ_LEDPixmapC(led),pixtmp,EZ_WRITABLEGC,
					0,hh-size, ww, size, 0, hh-size);
			      XCopyArea(EZ_Display, pixtmp,pixmap,EZ_WRITABLEGC,
					0,0, ww, hh, 0, 0);
			      XCopyArea(EZ_Display, pixmap,win,EZ_WRITABLEGC,
					0,0,ww,hh,bw,bw);
			      XFreePixmap(EZ_Display, pixtmp);
			    }
			  else  EZ_LEDOther(led) += 1;
			}
		    }
		  else finished = 1;
		  if(finished && --(at->count) > 0) 
		    {
		      EZ_LEDXYIdx(led) = EZ_LEDXOffset(led);
		      finished = 0; EZ_LEDOther(led) = 0; 
		    }
		}
	      else finished = 1;
	      break;
	    case LED_SHOW:
	      LedCreatePixmap(led, ww, hh);
	      XCopyArea(EZ_Display, pixmap,win,EZ_WRITABLEGC,
			0,0,ww,hh,bw,bw);	      
	      finished = 1;
	      break;
	    case LED_SC_LEFT:
	      {
		int itmp = (cols -2)*size;
		EZ_LEDXOffset(led) += 1;
		pixtmp = XCreatePixmap(EZ_Display, win, ww, hh, EZ_Depth);       
		XCopyArea(EZ_Display, pixmap, pixtmp, EZ_WRITABLEGC,
			  size,0,itmp, hh, 0, 0);
		XCopyArea(EZ_Display, EZ_LEDPixmapC(led),pixtmp,EZ_WRITABLEGC,
			  itmp,0, ww-itmp, hh, itmp, 0);
		LedDrawColumn(led, pixtmp, cols-2);
		XCopyArea(EZ_Display, pixtmp,pixmap,EZ_WRITABLEGC,
			  0,0, ww, hh, 0, 0);
		XCopyArea(EZ_Display, pixmap,win,EZ_WRITABLEGC,
			  0,0,ww,hh,bw,bw);
		XFreePixmap(EZ_Display, pixtmp);
		if(EZ_LEDXOffset(led) >= MAXV(0, tw -cols) ) finished = 1;
	      }
	    break;
	    case LED_SB_LEFT:
	      {
		int itmp = (cols -2)*size;
		EZ_LEDXOffset(led) += 1;
		if(EZ_LEDOther(led) >= 24) EZ_LEDOther(led) =0;
		pixtmp = XCreatePixmap(EZ_Display, win, ww, hh, EZ_Depth);       
		XCopyArea(EZ_Display, pixmap, pixtmp, EZ_WRITABLEGC,
			  size,0,itmp, hh, 0, 0);
		XCopyArea(EZ_Display, EZ_LEDPixmapC(led),pixtmp,EZ_WRITABLEGC,
			  itmp,0, ww-itmp, hh, itmp, 0);
		LedDrawColumn(led, pixtmp, cols-2);
		XCopyArea(EZ_Display, pixtmp,pixmap,EZ_WRITABLEGC,
			  0,0, ww, hh, 0, 0);
		EZ_LEDOther(led) += 1; 
		if(EZ_LEDXOffset(led) >= MAXV(0, tw -cols) ) finished = 1;
		if(EZ_LEDOther(led) < 16 || (finished && at->count <= 1)) 
		  XCopyArea(EZ_Display, pixmap,win,EZ_WRITABLEGC, 0,0,ww,hh,bw,bw);
		else 
		  XCopyArea(EZ_Display, EZ_LEDPixmapC(led), win,EZ_WRITABLEGC, 0,0,ww,hh,bw,bw);

		XFreePixmap(EZ_Display, pixtmp);
	      }
	    break;
	    case LED_SB_RIGHT:  
	      {
		EZ_LEDXOffset(led) -= 1;
		if(EZ_LEDOther(led) >= 30) EZ_LEDOther(led) =0;
		pixtmp = XCreatePixmap(EZ_Display, win, ww, hh, EZ_Depth);       
		XCopyArea(EZ_Display, pixmap,pixtmp,EZ_WRITABLEGC,
			  0,0,ww-size, hh, size, 0);
		XCopyArea(EZ_Display, EZ_LEDPixmapC(led),pixtmp,EZ_WRITABLEGC,
			  0,0, size, hh, 0, 0);
		LedDrawColumn(led, pixtmp, 0);
		XCopyArea(EZ_Display, pixtmp,pixmap,EZ_WRITABLEGC,
			  0,0, ww, hh, 0, 0);
		EZ_LEDOther(led) += 1; 
		if(EZ_LEDXOffset(led) <= MINV(0, tw -cols)) finished = 1;
		if(EZ_LEDOther(led) < 16 || (finished && at->count <= 1)) 
		  XCopyArea(EZ_Display, pixmap,win,EZ_WRITABLEGC, 0,0,ww,hh,bw,bw);
		else 
		  XCopyArea(EZ_Display, EZ_LEDPixmapC(led), win,EZ_WRITABLEGC, 0,0,ww,hh,bw,bw);
		XFreePixmap(EZ_Display, pixtmp);
	      }
	    break;
	    case LED_SC_RIGHT:  
	      {
		EZ_LEDXOffset(led) -= 1;
		pixtmp = XCreatePixmap(EZ_Display, win, ww, hh, EZ_Depth);       
		XCopyArea(EZ_Display, pixmap,pixtmp,EZ_WRITABLEGC,
			  0,0,ww-size, hh, size, 0);
		XCopyArea(EZ_Display, EZ_LEDPixmapC(led),pixtmp,EZ_WRITABLEGC,
			  0,0, size, hh, 0, 0);
		LedDrawColumn(led, pixtmp, 0);
		XCopyArea(EZ_Display, pixtmp,pixmap,EZ_WRITABLEGC,
			  0,0, ww, hh, 0, 0);
		XCopyArea(EZ_Display, pixmap,win,EZ_WRITABLEGC,
			  0,0,ww,hh,bw,bw);
		XFreePixmap(EZ_Display, pixtmp);
		if(EZ_LEDXOffset(led) <= MINV(0, tw -cols)) finished = 1;
	      }
	    break;
	    case LED_SC_UP:
	      {
		int itmp = size+size;
		EZ_LEDYOffset(led) += 1;
		pixtmp = XCreatePixmap(EZ_Display, win, ww, hh, EZ_Depth);       
		XCopyArea(EZ_Display, pixmap,pixtmp,EZ_WRITABLEGC,
			  0,size,ww, hh-itmp, 0, 0);
		XCopyArea(EZ_Display, EZ_LEDPixmapC(led),pixtmp,EZ_WRITABLEGC,
			  0,hh-itmp, ww, itmp, 0, hh-itmp);
		LedDrawRow(led, pixtmp, rows-2);
		XCopyArea(EZ_Display, pixtmp,pixmap,EZ_WRITABLEGC,
			  0,0, ww, hh, 0, 0);
		XCopyArea(EZ_Display, pixmap,win,EZ_WRITABLEGC,
			  0,0,ww,hh,bw,bw);
		XFreePixmap(EZ_Display, pixtmp);
		if(EZ_LEDYOffset(led)> MAXV(0, th -rows)) finished = 1;
	      }
	    break;
	    case LED_SC_DOWN:
	      {
		EZ_LEDYOffset(led) -= 1;
		pixtmp = XCreatePixmap(EZ_Display, win, ww, hh, EZ_Depth);       
		XCopyArea(EZ_Display, pixmap,pixtmp,EZ_WRITABLEGC,
			  0,0,ww, hh-size, 0, size);
		XCopyArea(EZ_Display, EZ_LEDPixmapC(led),pixtmp,EZ_WRITABLEGC,
			  0,0, ww, size, 0, 0);
		LedDrawRow(led, pixtmp, 0);
		XCopyArea(EZ_Display, pixtmp,pixmap,EZ_WRITABLEGC,
			  0,0, ww, hh, 0, 0);
		XCopyArea(EZ_Display, pixmap,win,EZ_WRITABLEGC,
			  0,0,ww,hh,bw,bw);
		XFreePixmap(EZ_Display, pixtmp);
		if(EZ_LEDYOffset(led) <= MINV(0, th - rows)) finished = 1;
	      }
	    break;
	    case LED_SC_CENTER:
	      {
		int bd, ktmp, jtmp, itmp = EZ_LEDXYIdx(led);
		if(itmp <= (tw)/2) 
		  {
		    pixtmp = XCreatePixmap(EZ_Display, win, ww, hh, EZ_Depth);  
		    bd = (cols+1)/2;
		    ktmp = bd*size ;
		    jtmp = bd;
		    XCopyArea(EZ_Display, pixmap, pixtmp, EZ_WRITABLEGC,
			      size, 0, ktmp-size, hh, 0, 0);
		    XCopyArea(EZ_Display, pixmap, pixtmp, EZ_WRITABLEGC,
			      ktmp, 0, ww - ktmp -2*size , hh, ktmp + size, 0);
		    XCopyArea(EZ_Display, EZ_LEDPixmapC(led), pixtmp, EZ_WRITABLEGC,
			      ktmp-size, 0, size+size , hh, ktmp-size, 0);
		    EZ_LEDXOffset(led) = itmp - jtmp;
		    LedDrawColumn(led, pixtmp, bd-1);
		    EZ_LEDXOffset(led) = tw - jtmp - itmp ;
		    LedDrawColumn(led, pixtmp, bd);
		    XCopyArea(EZ_Display, pixtmp, pixmap,EZ_WRITABLEGC,
			      0,0,ww,hh,0,0);
		    XCopyArea(EZ_Display, pixmap,win,EZ_WRITABLEGC,
			      0,0,ww,hh,bw,bw);
		    XFreePixmap(EZ_Display, pixtmp);
		    EZ_LEDXYIdx(led) = itmp+1;
		  }
		else 
		  {
		    if(itmp< (cols+1)/2)
		      {
			bd = (cols - tw +1)/2;
			ktmp = bd * size;
			
			XCopyArea(EZ_Display, EZ_LEDPixmapC(led), pixmap, EZ_WRITABLEGC,
				  0, 0, ktmp, hh, 0, 0);
			XCopyArea(EZ_Display, EZ_LEDPixmapC(led), pixmap, EZ_WRITABLEGC,
				  ww - ktmp, 0, ww-ktmp, hh, ww-ktmp, 0);
			XCopyArea(EZ_Display, pixmap,win,EZ_WRITABLEGC,
				  0,0,ww,hh,bw,bw);
		      }
		    finished = 1;
		  }
	      }
	      break;
	    case LED_SC_CENTER_V:
	      {
		int bd, ktmp, jtmp, itmp = EZ_LEDXYIdx(led);
		if(itmp <= (th)/2) 
		  {
		    pixtmp = XCreatePixmap(EZ_Display, win, ww, hh, EZ_Depth);  
		    bd = (rows+1)/2;
		    ktmp = bd*size ;
		    jtmp = bd;
		    XCopyArea(EZ_Display, pixmap, pixtmp, EZ_WRITABLEGC,
			      0, size, ww, ktmp-size, 0, 0);
		    XCopyArea(EZ_Display, pixmap, pixtmp, EZ_WRITABLEGC,
			      0, ktmp, ww, hh - ktmp -2*size , 0, ktmp + size);
		    XCopyArea(EZ_Display, EZ_LEDPixmapC(led), pixtmp, EZ_WRITABLEGC,
			      0, ktmp-size, ww, size+size, 0, ktmp-size);
		    EZ_LEDYOffset(led) = itmp - jtmp;
		    LedDrawRow(led, pixtmp, bd-1);
		    EZ_LEDYOffset(led) = th - jtmp - itmp ;
		    LedDrawRow(led, pixtmp, bd);
		    XCopyArea(EZ_Display, pixtmp, pixmap,EZ_WRITABLEGC,
			      0,0,ww,hh,0,0);
		    XCopyArea(EZ_Display, pixmap,win,EZ_WRITABLEGC,
			      0,0,ww,hh,bw,bw);
		    XFreePixmap(EZ_Display, pixtmp);
		    EZ_LEDXYIdx(led) = itmp+1;
		  }
		else 
		  {
		    if(itmp< (rows+1)/2)
		      {
			bd = (rows - th +1)/2;
			ktmp = bd * size;
			
			XCopyArea(EZ_Display, EZ_LEDPixmapC(led), pixmap, EZ_WRITABLEGC,
				  0, 0, ww, ktmp, 0, 0);
			XCopyArea(EZ_Display, EZ_LEDPixmapC(led), pixmap, EZ_WRITABLEGC,
				  0, hh - ktmp, ww, hh-ktmp,  0, hh-ktmp);
			XCopyArea(EZ_Display, pixmap,win,EZ_WRITABLEGC,
				  0,0,ww,hh,bw,bw);
		      }
		    finished = 1;
		  }
	      }
	    break;
	    case LED_SW_UP:
	      {
		int itmp = EZ_LEDXYIdx(led) -1;
		if(itmp >= rows) itmp = rows-1;
		if(itmp >= 0)
		  {
		    int jtmp = itmp * size;
		    EZ_LEDXYIdx(led) = itmp;
		    XCopyArea(EZ_Display, EZ_LEDPixmapC(led),pixmap,EZ_WRITABLEGC,
			      0,jtmp, ww, size, 0, jtmp);
		    LedDrawRow(led, pixmap, itmp);
		    XCopyArea(EZ_Display, pixmap,win,EZ_WRITABLEGC,
			      0,0,ww,hh,bw,bw);
		  }
		else finished = 1;
	      }
	    break;
	    case LED_SW_LEFT:
	      {
		int itmp = EZ_LEDXYIdx(led) +1;
		if(itmp < cols)
		  {
		    int jtmp = itmp * size;
		    EZ_LEDXYIdx(led) = itmp;
		    XCopyArea(EZ_Display, EZ_LEDPixmapC(led),pixmap,EZ_WRITABLEGC,
			      jtmp, 0, size, hh, jtmp, 0);
		    LedDrawColumn(led, pixmap, itmp);
		    XCopyArea(EZ_Display, pixmap,win,EZ_WRITABLEGC,
			      0,0,ww,hh,bw,bw);
		  }
		else finished = 1;
	      }
	    break;
	    case LED_SW_RIGHT:
	      {
		int itmp = EZ_LEDXYIdx(led) -1;
		if(itmp >= cols) itmp = cols -1;
		if(itmp >= 0)
		  {
		    int jtmp = itmp * size;
		    EZ_LEDXYIdx(led) = itmp;
		    XCopyArea(EZ_Display, EZ_LEDPixmapC(led),pixmap,EZ_WRITABLEGC,
			      jtmp, 0, size, hh, jtmp, 0);
		    LedDrawColumn(led, pixmap, itmp);
		    XCopyArea(EZ_Display, pixmap,win,EZ_WRITABLEGC,
			      0,0,ww,hh,bw,bw);
		  }
		else finished = 1;
	      }
	    break;
	    case LED_SW_DOWN:
	      {
		int itmp = EZ_LEDXYIdx(led) +1;
		if(itmp < rows) 
		  {
		    int jtmp = itmp * size;
		    EZ_LEDXYIdx(led) = itmp;
		    XCopyArea(EZ_Display, EZ_LEDPixmapC(led),pixmap,EZ_WRITABLEGC,
			      0,jtmp, ww, size, 0, jtmp);
		    LedDrawRow(led, pixmap, itmp);
		    XCopyArea(EZ_Display, pixmap,win,EZ_WRITABLEGC,
			      0,0,ww,hh,bw,bw);
		  }
		else finished = 1;
	      }
	    break;
	    case LED_SW_CENTER:
	      {
		int ktmp, jtmp, itmp = EZ_LEDXYIdx(led);
		int bd = (cols+1)/2;
		if(itmp <= bd) 
		  {
		    ktmp = bd - itmp;
		    jtmp = ktmp * size;
		    XCopyArea(EZ_Display, EZ_LEDPixmapC(led),pixmap,EZ_WRITABLEGC,
			      jtmp, 0,  size, hh, jtmp, 0);
		    LedDrawColumn(led, pixmap, ktmp);
		    ktmp = bd + itmp;
		    if(ktmp < cols)
		      {
			jtmp = ktmp * size;
			XCopyArea(EZ_Display, EZ_LEDPixmapC(led),pixmap,EZ_WRITABLEGC,
				  jtmp, 0,  size, hh, jtmp, 0);
			LedDrawColumn(led, pixmap, ktmp);
		      }
		    XCopyArea(EZ_Display, pixmap,win,EZ_WRITABLEGC,
			      0,0,ww,hh,bw,bw);
		    EZ_LEDXYIdx(led) = itmp+1;
		  }
		else finished = 1;
	      }
	      break;
	    case LED_SW_CENTER_V:
	      {
		int ktmp, jtmp, itmp = EZ_LEDXYIdx(led);
		int bd = (rows+1)/2;
		if(itmp <= bd) 
		  {
		    ktmp = bd - itmp;
		    jtmp = ktmp * size;
		    XCopyArea(EZ_Display, EZ_LEDPixmapC(led),pixmap,EZ_WRITABLEGC,
			      0, jtmp, ww, size, 0, jtmp);
		    LedDrawRow(led, pixmap, ktmp);
		    ktmp = bd + itmp;
		    if(ktmp < rows)
		      {
			jtmp = ktmp * size;
			XCopyArea(EZ_Display, EZ_LEDPixmapC(led),pixmap,EZ_WRITABLEGC,
				  0, jtmp, ww, size, 0, jtmp);
			LedDrawRow(led, pixmap, ktmp);
		      }
		    XCopyArea(EZ_Display, pixmap,win,EZ_WRITABLEGC,
			      0,0,ww,hh,bw,bw);
		    EZ_LEDXYIdx(led) = itmp+1;
		  }
		else finished = 1;
	      }
	      break;
	    case LED_BLINK:
	      {
		at->count--;
		if(EZ_LEDXYIdx(led) != 0 || at->count <= 0)
		  {
		    if( EZ_LEDDirty(led) & LED_PIXMAP_DIRTY)
		      LedCreatePixmap(led, ww, hh);
		    XCopyArea(EZ_Display, EZ_LEDPixmap(led), win,EZ_WRITABLEGC,
			      0,0,ww,hh,bw,bw);
		    XFlush(EZ_Display);
		    EZ_LEDXYIdx(led) = 0;
		  }
		else
		  {
		    XCopyArea(EZ_Display, EZ_LEDPixmapC(led), win,EZ_WRITABLEGC,
			      0,0,ww,hh,bw,bw);
		    EZ_LEDXYIdx(led) = 1;
		  }
		if(at->count <= 0) finished = 1;
	      }
	    break;
	    case LED_SLEEP:
	      XCopyArea(EZ_Display, EZ_LEDPixmap(led), win,EZ_WRITABLEGC,
			0,0,ww,hh,bw,bw);
	      if( --(at->count) <= 0) finished = 1;
	      break;
	    default:
	      finished = 1;
	      break;
	    }
	  if(finished == 0) return;
	  at->count--;
	  if(at->count > 0) /* set it up immediately */
	    { 
	      at->status = LED_AT_WAITING;
	      TimerSCallBack(NULL, led);
	    }
	  else
	    {
	      EZ_LEDAction(led) = at->next;
	      if(at->colorf != NULL) EZ_LEDColorF(led) = at->colorf;
	      ledDestroyAction(at);
	    }
	}
    }
  EZ_CancelTimer(timer);
}
/***********************************************************************/
static int ledAddAction(led, type, delay, cnt, str, color)
     EZ_Widget *led; int type, delay, cnt; char *str; char *color;     
{
  EZ_LedAction *at, *head;
  at = (EZ_LedAction *)my_malloc(sizeof(EZ_LedAction), _LED_AT_);
  at->led = led;
  at->type = type;
  if(str != NULL)  at->str = EZ_AllocCopyString(str);
  else  at->str = NULL;
  at->delay = (delay<1000? 1000: delay);
  at->color = (color == NULL? 0:
	       EZ_AllocateColorFromName(color));
  at->colorf = NULL;
  at->serial = EZ_CounterUT++;
  at->count = (cnt<0? 0: cnt);
  at->status = LED_AT_WAITING; /* new action */
  at->next = NULL;
  head = EZ_LEDAction(led);
  if(head == NULL) EZ_LEDAction(led) = at;
  else
    {
      while(head->next != NULL) head = head->next;
      head->next = at;
    }
  return(at->serial);
}

static void ledDestroyAction(at)
     EZ_LedAction *at;
{
  if(at)
    {
      if(at->str) (void)my_free((char *)at->str);
      (void)my_free((char *)at);
    }
}

void EZ_RemoveLedAction(led, action)
     EZ_Widget *led; int action;
{
  if(led && action > 0 && EZ_WidgetType(led) == EZ_WIDGET_LED )
    {
      EZ_LedAction *atptr = EZ_LEDAction(led);
      if(atptr != NULL)
	{
	  EZ_LedAction *found = NULL;
	  /* removing the current action is not allowed */
	  if(atptr->serial == action) return; 
	  while(atptr->next)
	    {
	      EZ_LedAction *tmp = atptr->next;
	      if( tmp->serial == action)
		{
		  atptr->next = tmp->next;
		  found = tmp;
		  break;
		}
	      atptr = atptr->next;
	    }
	  if(found) ledDestroyAction(found);
	}
    }
}

/***********************************************************************/
int EZ_QueueLedAction(led, type, delay, count, msg, color)
     EZ_Widget *led; int type; char *msg; int delay; int count;
     char *color;
{
  if(led && EZ_WidgetType(led) == EZ_WIDGET_LED)
    {
      if(count < 0 || delay < 0 || type <= 0 || type > LED_LAST_ACTION) return(-1);
      return(ledAddAction(led, type, delay, count, msg, color)); 
    }
  return(-1);
}
/***********************************************************************/
int  EZ_LedIsFree (led) EZ_Widget *led;
{
  if(led && EZ_WidgetType(led) == EZ_WIDGET_LED)
    return( EZ_LEDAction(led) == NULL);
  return(0);
}

#ifdef EZ_DEBUG 
void EZ_DumpLedActionTable(led) EZ_Widget *led;
{
  if(led && EZ_WidgetType(led) == EZ_WIDGET_LED)
    {
      EZ_LedAction *atptr = EZ_LEDAction(led);
      printf("==Led Action Table For %lx ==\n", (unsigned long)led);  
      while(atptr)
	{
	  fprintf(stderr, "[%d %s]\n", atptr->serial, atptr->str);
	  atptr = atptr->next;
	}
    }
}
#endif
/***********************************************************************/
#undef _EZ_WIDGET_LED_C_


