/**************************************************************************\
 ibtk (Insomnia's Basic ToolKit)

  By Insomnia (Steaphan Greene)
  (insomnia@core.binghamton.edu)

  Copyright (C) 1999 Steaphan Greene

  This program 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 General Public License for more details.

  You should have received a copy of the GNU General Public License
  along with this program; if not, write to the Free Software
  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.

\**************************************************************************/

#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <X11/keysym.h>
#include "irealbox.h"

IRealBox::~IRealBox()  {
  Win->RemoveClaim(this);
  }

void IRealBox::Increment(IDoDad *wb, int mb)  {
  if(disabled) return;
  SetVal(val+inc);
  Rebuild();
  }

void IRealBox::Decrement(IDoDad *wb, int mb)  {
  if(disabled) return;
  SetVal(val-inc);
  Rebuild();
  }

void __Callback__IRealBox__Increment(IDoDad *p, IDoDad *d, int v) {
  ((IRealBox*)p)->Increment(d,v);
  }

void __Callback__IRealBox__Decrement(IDoDad *p, IDoDad *d, int v) {
  ((IRealBox*)p)->Decrement(d,v);
  }

IRealBox::IRealBox(double v, IWindow *w, int xp, int yp, int xs, int ys, double i){
  val = v; inc = i;
  vmin = -1000000.0;
  vmax = 1000000.0;
  upb = NULL; dnb = NULL;
  char txt[256];
  sprintf(txt, "%f%c", v, 0);
  Init(txt, w, xp, yp, xs+2-((ys+1)/2), ys);
  upb = new IButton("", w, xp+xs-((ys+1)/2), yp, (ys+1)/2, (ys+1)/2);
  dnb = new IButton("", w, xp+xs-((ys+1)/2), yp+((ys+1)/2), (ys+1)/2, ys/2);
  upb->SetParent(this);
//  upb->SetClickCallback((void (*)(IDoDad *, IDoDad *, int))&Increment);
  upb->SetClickCallback(__Callback__IRealBox__Increment);
  dnb->SetParent(this);
//  dnb->SetClickCallback((void (*)(IDoDad *, IDoDad *, int))&Decrement);
  dnb->SetClickCallback(__Callback__IRealBox__Decrement);
  }

void IRealBox::SetIncVal(double i)  {
  inc = i;
  }

void IRealBox::SetVal(double v)  {
  double oval = val;
  val = v;
  if(val > vmax) val = vmax;
  if(val < vmin) val = vmin;
  char txt[256];
  sprintf(txt, "%f%c", val, 0);
  SetText(txt);
  if(oval != val && changecallback != NULL)
    (*changecallback)(parent, this);
  }

void IRealBox::SetText(char *txt)  {
  double v = strtod(txt, NULL);
  if(v != val)  { SetVal(v); return; }
//  printf("Val = %f\n", val);
  Window wind = Win->GetWindowBuffer();
  Display *disp = Win->GetDisplay();
  GC gc = Win->GetGC();

  unsigned int p, b, g, gl, gd;
  p = Win->GetPaperColor();
  b = Win->GetFGColor();
  g = Win->GetBGColor();
  gl = Win->GetLBGColor();
  gd = Win->GetDBGColor();

  sprintf(text, "%s%c", txt, 0);
  if(tcp > (long)strlen(text)) tcp = strlen(text);
  gcp = 0;

  XFontStruct *fs;
  XCharStruct cs;
  int dir, as, des;
  fs = Win->GetFontStruct();
//  Wlen = XTextWidth(fs, text, strlen(text));
  XTextExtents(fs, text, strlen(text), &dir, &as, &des, &cs);
//  printf("dir = %d, as = %d, des = %d\n", dir, as, des);
  Wlen = cs.width+4;
//  int hgt = cs.
  if(Wrk[0] != None) XFreePixmap(disp, Wrk[0]);
  if(Wrk[1] != None) XFreePixmap(disp, Wrk[1]);
  Wrk[0] = XCreatePixmap(disp, wind, Wlen, ysize-4, DefaultDepth(disp, 0));
  Wrk[1] = XCreatePixmap(disp, wind, Wlen, ysize-4, DefaultDepth(disp, 0));
  XSetForeground(disp, gc, p);
  XFillRectangle(disp, Wrk[0], gc, 0, 0, Wlen, ysize-4);
  XSetForeground(disp, gc, g);
  XFillRectangle(disp, Wrk[1], gc, 0, 0, Wlen, ysize-4);
  XSetBackground(disp, gc, p);
  XSetForeground(disp, gc, b);
  XDrawImageString(disp, Wrk[0], gc, 2, ((ysize+ysize-(as+des-2))>>1)-2,
	text, strlen(text));
  XSetBackground(disp, gc, g);
  XSetForeground(disp, gc, gl);
  XDrawImageString(disp, Wrk[1], gc, 3, ((ysize+ysize-(as+des-2))>>1)-1,
        text, strlen(text));
  XSetForeground(disp, gc, gd);  
  XDrawString(disp, Wrk[1], gc, 2, ((ysize+ysize-(as+des-2))>>1)-2,
        text, strlen(text));
  if(tcp > 0) gcp = XTextWidth(fs, text, tcp);
  if(Win->GetFocus() == this && (!disabled))  {
    XDrawLine(disp, Wrk[0], gc, gcp+2, 1, gcp+2, ysize-6);
    XDrawLine(disp, Wrk[0], gc, gcp+1, 1, gcp+3, 1);
    XDrawLine(disp, Wrk[0], gc, gcp+1, ysize-6, gcp+3, ysize-6);
    }
  Rebuild();
  }

void IRealBox::Rebuild()  {
  IBox::Rebuild();
  if(upb != NULL) {
    if(hidden && (!upb->Hidden())) upb->Hide();
    else if((!hidden) && upb->Hidden()) upb->Show();
    else upb->Rebuild();
    }
  if(dnb != NULL) {  
    if(hidden && (!dnb->Hidden())) dnb->Hide();
    else if((!hidden) && dnb->Hidden()) dnb->Show();
    else dnb->Rebuild();
    }
  }

void IRealBox::Redraw()  {
//  printf("Redraw\n");
  IBox::Redraw();
  if(upb != NULL) {
    if(hidden && (!upb->Hidden())) upb->Hide();
    else if((!hidden) && upb->Hidden()) upb->Show();
    else upb->Redraw();
    }
  if(dnb != NULL) {  
    if(hidden && (!dnb->Hidden())) dnb->Hide();
    else if((!hidden) && dnb->Hidden()) dnb->Show();
    else dnb->Redraw();
    }
  }

void IRealBox::Enable()  {
  disabled = 0;
  Rebuild();
  }

void IRealBox::Disable()  {
  disabled = 1;
  Rebuild();
  }

int IRealBox::KeyDown(XKeyEvent ev)  {
  if(disabled) return 0;
  if(disabled) return 0;
  KeySym key = XKeycodeToKeysym(Win->GetDisplay(), ev.keycode, 0);
  switch(key)  {
    case(XK_Down): { Decrement(this, 1); }break;
    case(XK_Up):   { Increment(this, 1); }break;
    case(XK_period): case(XK_KP_Decimal):
    case(XK_Delete): case(XK_BackSpace): case(XK_Left): case(XK_Right):
    case(XK_KP_0): case(XK_KP_Insert):
    case(XK_KP_1): case(XK_KP_End):
    case(XK_KP_2): case(XK_KP_Down):
    case(XK_KP_3): case(XK_KP_Page_Down):
    case(XK_KP_4): case(XK_KP_Left):
    case(XK_KP_5): case(XK_KP_Begin):
    case(XK_KP_6): case(XK_KP_Right):
    case(XK_KP_7): case(XK_KP_Home):
    case(XK_KP_8): case(XK_KP_Up):
    case(XK_KP_9): case(XK_KP_Page_Up):
    case(XK_0): case(XK_1): case(XK_2): case(XK_3): case(XK_4):
    case(XK_5): case(XK_6): case(XK_7): case(XK_8): case(XK_9): {
      return IBox::KeyDown(ev);
      }break;
    default: return 0; break;
    }
  return 1;
  }

int IRealBox::KeyUp(XKeyEvent ev)  {
//  char *key = XKeysymToString(XKeycodeToKeysym(Win->GetDisplay(), k, 0));
//  printf("Got \"%s\"\n", key);
  return 1;
  }

void IRealBox::SetMax(double mx)  {
  vmax = mx;
  if(vmin>vmax) vmin = vmax;
  SetVal(val);
  }

void IRealBox::SetMin(double mn)  {
  vmin = mn;
  if(vmin>vmax) vmax = vmin;
  SetVal(val);
  }
