/*
   NAME:     Figlets
   AUTHOR:   Ole Gunnar Westgaard
   DATE:     Jul 28 1995
             
*/

#include "otools.h"
#include "macros.h"
#include "protos.h"

//=============================================================================
// Figlet class functions
//=============================================================================

Figlet::Figlet(uint x1,uint y1,uint x2,uint y2,uchar f,Color *c,int fg,char *m)
{
  xa = x1;
  ya = y1;
  xb = x2;
  yb = y2;
  frame = f;
  color = c;
  message = m;
  flag = fg;
  callback = NULL;
}

void Figlet::DrawFrame(void)
{
  switch (frame) {
  case SINGLE:
    oColor(bd);
    Box(xa-1,ya-1,xb+1,yb+1);
    break;
  case DOUBLE:
    oColor(sd); Box(xa-3,ya-3,xb+1,yb+1);
    oColor(hl); Box(xa-1,ya-1,xb+3,yb+3);
    break;
  case IN:
    oColor(sd);
    Line(xa-2,ya-2,xb+2,ya-2); Line(xa-1,ya-1,xb+1,ya-1);
    Line(xa-2,ya-1,xa-2,yb+1); Line(xa-1,ya  ,xa-1,yb  );
    oColor(hl);
    Line(xa-2,yb+2,xb+2,yb+2); Line(xa-1,yb+1,xb+1,yb+1);
    Line(xb+1,yb  ,xb+1,ya  ); Line(xb+2,yb+1,xb+2,ya-1);
    break;
  case OUT:
    oColor(hl);
    Line(xa-2,ya-2,xb+2,ya-2); Line(xa-1,ya-1,xb+1,ya-1);
    Line(xa-2,ya-1,xa-2,yb+1); Line(xa-1,ya  ,xa-1,yb  );
    oColor(sd);
    Line(xa-2,yb+2,xb+2,yb+2); Line(xa-1,yb+1,xb+1,yb+1);
    Line(xb+1,yb  ,xb+1,ya  ); Line(xb+2,yb+1,xb+2,ya-1);
    break;
  case HEXAGON:
    {
      int x1=xa-3, y1=ya-3, x2=xb+3, y2=yb+3;
      XPoint points[9]={ {x1  ,y2-3}, {x1  ,y1+3}, {x1+3,y1  }, {x2-3,y1  },
                         {x2  ,y1+3}, {x2  ,y2-3}, {x2-3,y2  }, {x1+3,y2  },
                         {x1  ,y2-3} };
      oColor(bd);
      Lines(points,9,CoordModeOrigin);
    }
    break;
  case SHADOW:
    oColor(bd); Box(xa-1,ya-1,xb+1,yb+1);
    oColor(sd); Box(xa+1,yb+2,xb+3,yb+3);
    Box(xb+2,ya+1,xb+3,yb+1);
    break;
  default:
    break;
  }
}

void Figlet::Draw(void)
{
  int w = xa+((xb-xa)-XTextWidth(o_font,message,strlen(message)))/2,
      h = yb-((yb-ya)-o_font->ascent+o_font->descent)/2;
  oColor(bg); Fbox(xa,ya,xb,yb);
  oColor(fg); XDrawString(o_dpy,o_win,o_gc,w,h,message,strlen(message));
}

void Figlet::Show(char *name)
{
  printf("\n\nFiglet '%s' information:\n",name);
  printf("  Colors  : %4lX\n",color);
  printf("  Flag    : %i\n",flag);
  printf("  Size    : %4d %4d %4d %4d\n",xa,ya,xb,yb);
  printf("  Frame   : %3ud\n",frame);
  printf("  Message : %s\n",message);
  printf("  Callback: %4lX\n",callback);
}

char *Figlet::ShowShort(void )
{
  char s[100];
  sprintf(s,"(%4lX,%4lX) %2i (%3d,%3d,%3d,%3d) %3d %s",
	 color,callback,flag,xa,ya,xb,yb,frame,message);
  return s;
}

//=============================================================================
// Figlet CLASS Button
//=============================================================================

Button::Button(uint x1,uint y1,uint x2,uint y2,uchar f,Color *c,int fg,char *m,
               uchar t,uchar s, void (*cb)(void *,int ,int ))
{
  xa = x1;
  ya = y1;
  xb = x2;
  yb = y2;
  frame = f;
  color = c;
  message = m;
  type = t;
  state = s;
  flag = fg;
  callback = cb;
}

void Button::Draw(void)
{
  int w = xa+((xb-xa)-XTextWidth(o_font,message,strlen(message)))/2,
      h = yb-((yb-ya)-o_font->ascent+o_font->descent)/2;
  oColor(bg); Fbox(xa+2,ya+2,xb-2,yb-2);
  if (state & IN) oColor(dark); else oColor(light);
  if (strlen(message)) DrawString(w,h,message);        
  if (state & IN) oColor(sd); else oColor(hl);
  Line(xa  ,ya  ,xb  ,ya  ); Line(xa+1,ya+1,xb-1,ya+1);
  Line(xa  ,ya+1,xa  ,yb  ); Line(xa+1,ya+2,xa+1,yb-1);
  if (state & IN) oColor(hl); else oColor(sd);
  Line(xa  ,yb  ,xb  ,yb  ); Line(xa+1,yb-1,xb-1,yb-1);
  Line(xb  ,ya+1,xb  ,yb-1); Line(xb-1,ya+2,xb-1,yb-2);    
}

void Button::Press(int x,int y)
{
  state = (state & IN) ? OUT : IN;
  Draw();
}

int Button::Motion(int x,int y)
{
  if ( x<xa || x>xb || y<ya || y>yb) {
    state = (state & IN) ? OUT : IN;
    Draw();
    return 0;
  }
  return 1;
}

void Button::Release(int x,int y)
{
  switch (type) {
  case CLICK:
    state = (state & IN) ? OUT : IN;
    Draw();
  case HOLD:
    if (callback) callback(this,x,y);
  default:
    break;
  }
}

//=============================================================================
// Figlet CLASS Switch
//=============================================================================

Switch::Switch(uint x1,uint y1,uint x2,uint y2,uchar f,Color *c,int fg,char *m,
               uchar t,uchar s,uchar w,void (*cb)(void *,int ,int ))
{
  xa = x1;
  ya = y1;
  xb = x2;
  yb = y2;
  frame = f;
  color = c;
  flag = fg;
  message = m;
  type = t;
  state = s;
  width = (w>4) ? (w/2)*2 : 4;
  callback = cb;
}


void Switch::Draw(void)
{
  int cl = (yb-ya)/width,
      cm = cl * (width/2),
      ch = cl * (width-1),
      ta = (yb-ya) / 4;
  XPoint points[4]={ { xa+cl+3 , ya+cm   },
		     { xa+cm   , ya+cl+2 },
		     { xa+ch-2 , ya+cm   },
		     { xa+cm   , ya+ch-2 } };
  oColor(bg); Fbox(xa,ya,xb,yb);
  if (strlen(message)) {
    int w = xa+(yb-ya),
        h = yb-((yb-ya)-o_font->ascent+o_font->descent)/2;
    oColor(fg);
    DrawString(w,h,message);
  }
  switch (type) {
  case FLIP:
    if (state & IN) oColor(sd); else oColor(hl);
    Line( xa+ta  , ya+ta  , xa+ta*3  , ya+ta   );
    Line( xa+ta+1, ya+ta+1, xa+ta*3-1, ya+ta+1 );
    Line( xa+ta  , ya+ta+1, xa+ta    , yb-ta-1 );
    Line( xa+ta+1, ya+ta+2, xa+ta+1  , yb-ta-2 );
    if (state & IN) oColor(hl); else oColor(sd);
    Line( xa+ta    , yb-ta  , xa+ta*3  , yb-ta   );
    Line( xa+ta  +1, yb-ta-1, xa+ta*3-1, yb-ta-1 );
    Line( xa+ta*3  , yb-ta-1, xa+ta*3  , ya+ta+1 );
    Line( xa+ta*3-1, yb-ta-2, xa+ta*3-1, ya+ta+2 );
    if (state & IN) oColor(dark); else oColor(light);
    Fbox( xa+ta  +2, ya+ta+2, xa+ta*3-2, yb-ta-2 );
    break;
  default:
    if (state & IN) oColor(sd); else oColor(hl);
    Line(xa+cl  ,ya+cm  ,xa+cm  ,ya+cl  );
    Line(xa+cl+1,ya+cm  ,xa+cm  ,ya+cl+1);
    Line(xa+cl+2,ya+cm  ,xa+cm  ,ya+cl+2);
    Line(xa+cm+1,ya+cl+1,xa+ch-1,ya+cm-1);
    Line(xa+cm+1,ya+cl+2,xa+ch-2,ya+cm-1);
    Line(xa+cm+1,ya+cl+3,xa+ch-3,ya+cm-1);
    if (state & IN) oColor(hl); else oColor(sd);
    Line(xa+cl+1,ya+cm+1,xa+cm  ,ya+ch  );
    Line(xa+cl+2,ya+cm+1,xa+cm  ,ya+ch-1);
    Line(xa+cl+3,ya+cm+1,xa+cm  ,ya+ch-2);
    Line(xa+cm+1,ya+ch-1,xa+ch  ,ya+cm  );
    Line(xa+cm+1,ya+ch-2,xa+ch-1,ya+cm  );
    Line(xa+cm+1,ya+ch-3,xa+ch-2,ya+cm  );
    if (state & IN) oColor(dark); else oColor(light);
    FillPoly(points,4,Nonconvex,CoordModeOrigin);
    break;
  }
}

void Switch::Press(int x,int y)
{
  state = (state & IN) ? OUT : IN;
  Draw();
}

int Switch::Motion(int x,int y)
{
  if ( x<xa || x>xb || y<ya || y>yb) {
    state = (state & IN) ? OUT : IN;
    Draw();
    return 0;
  }
  return 1;
}

void Switch::Release(int x,int y)
{
  if (callback) callback(this,x,y);
}

//=============================================================================
// Figlet CLASS Slider
//=============================================================================
Slider::Slider(uint x1,uint y1,uint x2,uint y2,uchar f,Color *c,int fg,char *m,
               uchar t,uchar s,uchar w,void (*cb)(void *,int ,int ),float v)
{
  xa = x1;  ya = y1;  xb = x2;  yb = y2;  frame = f;  color = c;  flag = fg;
  message = m;  type = t;  state = s; width = (w>=6) ? w : 6;  callback = cb;
  value = v;
}

void Slider::Draw(void)
{
  oColor(dark); Fbox(xa,ya,xb,yb);
  switch (type) {
  case SLIDER:
    if ( state & Y) {
      int ta = (int)((float)(yb-ya-width)*(1.0-value));
      oColor(light); Fbox(xa,ya+ta,xb,ya+ta+width);
    } else {
      int ta = (int)((float)(xb-xa-width)*value);
      oColor(light); Fbox(xa+ta,ya,xa+ta+width,yb);
    }
    break;
  case FADER:
    if (state & Y) {
      int ta=(int)((float)(yb-ya-width)*(1.0-value));
      oColor(bg); Fbox(xa+2,ya+ta+2,xb-2,ya+ta+width-2);
      oColor(hl);
      Line(xa  ,ya+ta        ,xb  ,ya+ta         );
      Line(xa+1,ya+ta+1      ,xb-1,ya+ta+1       );
      Line(xa  ,ya+ta+1      ,xa  ,ya+ta+width-1 );
      Line(xa+1,ya+ta+2      ,xa+1,ya+ta+width-2 );
      oColor(sd);
      Line(xa  ,ya+ta+width  ,xb  ,ya+ta+width   );
      Line(xa+1,ya+ta+width-1,xb-1,ya+ta+width-1 );
      Line(xb  ,ya+ta+width-1,xb  ,ya+ta+1       );
      Line(xb-1,ya+ta+width-2,xb-1,ya+ta+2       );
    } else {
      int ta=(int)((float)(xb-xa-width)*value);
      oColor(bg); Fbox(xa+ta+2,ya+2,xa+ta+width-2,yb-2);
      oColor(hl);
      Line(xa+ta        ,ya  ,xa+ta+width  ,ya   );
      Line(xa+ta+1      ,ya+1,xa+ta+width-1,ya+1 );
      Line(xa+ta        ,ya+1,xa+ta        ,yb-1 );
      Line(xa+ta+1      ,ya+2,xa+ta+1      ,yb-2 );
      oColor(sd);
      Line(xa+ta        ,yb  ,xa+ta+width  ,yb   );
      Line(xa+ta+1      ,yb-1,xa+ta+width-1,yb-1 );
      Line(xa+ta+width  ,yb-1,xa+ta+width  ,ya+1 );
      Line(xa+ta+width-1,yb-2,xa+ta+width-1,ya+2 );
    }
    break;
  case FANCY:
    if (state & Y) {
      int ta=(int)((float)(yb-ya-width)*(1.0-value));
      oColor(bg); Fbox(xa+2,ya+ta+2,xb-2,ya+ta+width-2);
      oColor(hl);
      Line(xa  ,ya+ta        ,xb  ,ya+ta         );
      Line(xa+1,ya+ta+1      ,xb-1,ya+ta+1       );
      Line(xa  ,ya+ta+1      ,xa  ,ya+ta+width-1 );
      Line(xa+1,ya+ta+2      ,xa+1,ya+ta+width-2 );
      Line(xa+2,ya+ta+width-2,xb-2,ya+ta+width-2 );
      Line(xb-2,ya+ta+width-3,xb-2,ya+ta+3       );
      oColor(sd);
      Line(xa  ,ya+ta+width  ,xb  ,ya+ta+width   );
      Line(xa+1,ya+ta+width-1,xb-1,ya+ta+width-1 );
      Line(xb  ,ya+ta+width-1,xb  ,ya+ta+1       );
      Line(xb-1,ya+ta+width-2,xb-1,ya+ta+2       );
      Line(xa+2,ya+ta+2      ,xb-2,ya+ta+2       );
      Line(xa+2,ya+ta+3      ,xa+2,ya+ta+width-3 );
    } else {
      int ta=(int)((float)(xb-xa-width)*value);
      oColor(bg); Fbox(xa+ta+2,ya+2,xa+ta+width-2,yb-2);
      oColor(hl);
      Line(xa+ta        ,ya  ,xa+ta+width  ,ya   );
      Line(xa+ta+1      ,ya+1,xa+ta+width-1,ya+1 );
      Line(xa+ta        ,ya+1,xa+ta        ,yb-1 );
      Line(xa+ta+1      ,ya+2,xa+ta+1      ,yb-2 );
      Line(xa+ta+2      ,yb-2,xa+ta+width-2,yb-2 );
      Line(xa+ta+width-2,yb-3,xa+ta+width-2,ya+3 );
      oColor(sd);
      Line(xa+ta        ,yb  ,xa+ta+width  ,yb   );
      Line(xa+ta+1      ,yb-1,xa+ta+width-1,yb-1 );
      Line(xa+ta+width  ,yb-1,xa+ta+width  ,ya+1 );
      Line(xa+ta+width-1,yb-2,xa+ta+width-1,ya+2 );
      Line(xa+ta+2      ,ya+2,xa+ta+width-2,ya+2 );
      Line(xa+ta+2      ,ya+3,xa+ta+2      ,yb-3 );
    }
    break;
  case BAR:
    if (state & Y) {
      int b=(int)((float)(yb-ya-width)*(1.0-value));
      oColor(bg); Fbox(xa+2,ya+b+2,xb-2,yb-2);
      oColor(hl);
      Line(xa  ,ya+b  ,xb  ,ya+b  );
      Line(xa+1,ya+b+1,xb-1,ya+b+1);
      Line(xa  ,ya+b+1,xa  ,yb-1   );
      Line(xa+1,ya+b+2,xa+1,yb-2   );
      oColor(sd);
      Line(xa  ,yb     ,xb  ,yb    );
      Line(xa+1,yb-1   ,xb-1,yb-1  );
      Line(xb  ,yb-1   ,xb  ,ya+b+1);
      Line(xb-1,yb-2   ,xb-1,ya+b+2);
    } else {
      int b=(int)((float)(xb-xa-width)*value);
      oColor(bg); Fbox(xa+2,ya+2,xa+b+width-2,yb-2);
      oColor(hl);
      Line(xa  ,ya  ,xa+b+width  ,ya  );
      Line(xa+1,ya+1,xa+b+width-1,ya+1);
      Line(xa  ,ya+1,xa          ,yb-1);
      Line(xa+1,ya+2,xa+1        ,yb-2);
      oColor(sd);
      Line(xa          ,yb  ,xa+b+width  ,yb  );
      Line(xa+1        ,yb-1,xa+b+width-1,yb-1);
      Line(xa+b+width  ,yb-1,xa+b+width  ,ya+1);
      Line(xa+b+width-1,yb-2,xa+b+width-1,ya+2);
    }
    break;
  default:
    break;
  }
  if (strlen(message)) {
    int w = xa+((xb-xa)-XTextWidth(o_font,message,strlen(message)))/2,
        h = yb-((yb-ya)-o_font->ascent+o_font->descent)/2;
    oColor(fg);
    DrawString(w,h,message);
  }
//  oldvalue = value;
}

void Slider::Press(int x,int y)
{
  int tmp;
  float old=value;
  switch (state) {
  case Y:
    tmp = (y-ya-width/2);
    if (tmp <= 0) { value=1.0; break; }
    if (tmp >= (yb-ya-width)) { value=0.0; break; }
    value =1-((float)tmp/(float)(yb-ya-width));
    break;
  default:
    tmp = (x-xa-width/2);
    if (tmp <= 0) { value=0.0; break; }
    if (tmp > (xb-xa-width)) { value=1.0; break; }
    value = (float)tmp/(float)(xb-xa-width);
    break;
  }
  if (old != value) {
    Draw();
    if (callback) callback(this,x,y);
  }
}

int Slider::Motion(int x,int y)
{
  int tmp;
  float old=value;
  switch (state) {
  case Y:
    tmp = (y-ya-width/2);
    if (tmp <= 0) { value=1.0; break; }
    if (tmp >= (yb-ya-width)) { value=0.0; break; }
    value =1-((float)tmp/(float)(yb-ya-width));
    break;
  default:
    tmp = (x-xa-width/2);
    if (tmp <= 0) { value=0.0; break; }
    if (tmp > (xb-xa-width)) { value=1.0; break; }
    value = (float)tmp/(float)(xb-xa-width);
    break;
  }
  if (old != value) {
    Draw();
    if (callback) callback(this,x,y);
  }
  return 1;
}
