/**************************************************************************\
 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 <stdio.h>
#include <string.h>

#include "ilistbox.h"

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

IListBox::IListBox(char **txt, int n, IWindow *w, int xp, int yp, int xs, int ys)  {
  Init(txt, n, w, xp, yp, xs, ys);
  }

void IListBox::Init(char **txt, int n, IWindow *w, int xp, int yp, int xs, int ys)  {
  xpos = xp; ypos = yp; xsize = xs; ysize = ys;
  Win = w;
  Window wind = w->GetWindowBuffer();
  Display *disp = w->GetDisplay();
  unsigned int p, b, g, gl, gd;
  Img = XCreatePixmap(disp, wind, xs, ys, DefaultDepth(disp, 0));
  GC gc = Win->GetGC();

  p = w->GetPaperColor();
  b = w->GetFGColor();
  g = w->GetBGColor();
  gl = w->GetLBGColor();
  gd = w->GetDBGColor();

  XSetForeground(disp, gc, gd);
  XFillRectangle(disp, Img, gc, 0, 0, xs, ys);
  XSetForeground(disp, gc, gl);
  XFillRectangle(disp, Img, gc, 2, 2, xs-2, ys-2);
  XDrawPoint(disp, Img, gc, xs-1, 1);
  XDrawPoint(disp, Img, gc, 1, ys-1);
  XSetForeground(disp, gc, p);
  XFillRectangle(disp, Img, gc, 2, 2, xs-4, ys-4);

  dccallback = NULL;
  selcallback = NULL;
  deselcallback = NULL;
  Wrk = NULL;
  wx = NULL;
  wy = NULL;
  nent = n;
  lines = 0;
  dy = 0;
  selmin = 0;
  selmax = 1;
  if(n>0)  {
    int ctr;
    text = new char*[n];
    Wrk = new Pixmap[n];
    wx = new int[n];
    wy = new int[n];
    sel = new int[selmax];
    for(ctr=0; ctr<selmax; ctr++)  sel[ctr] = -1;
    
    for(ctr=0; ctr<n; ctr++)  {
      text[ctr] = new char[100];
//      int stsz = strlen(txt[ctr])+1;
//      printf("Before\n");
//      text[ctr] = new char[stsz];
//      printf("After\n");
      sprintf(text[ctr], "%s%c", txt[ctr], 0);
      XFontStruct *fs;
      XCharStruct cs;
      int dir, as, des;
      fs = Win->GetFontStruct();
      XTextExtents(fs, txt[ctr], strlen(txt[ctr]), &dir, &as, &des, &cs);
      int ht = as+des;
      int len = cs.width;
      Wrk[ctr] = XCreatePixmap(disp, wind, len, ht, DefaultDepth(disp, 0));
      wx[ctr] = len;  wy[ctr] = ht;
      XSetForeground(disp, gc, p);
      XFillRectangle(disp, Wrk[ctr], gc, 0, 0, len, ht);
      XSetBackground(disp, gc, p);
      XSetForeground(disp, gc, b);
      XDrawImageString(disp, Wrk[ctr], gc, 0, as, txt[ctr], strlen(txt[ctr]));
      dy = dy>?ht;
      }
    }
  if(dy>0) lines = (ysize-6)/dy;
  parent=NULL;

  w->AddClaim(this, xp, yp, xs, ys);

  Rebuild();
  }

void IListBox::Redraw()  {
  if(hidden) { Win->Rebuild(xpos, ypos, xsize, ysize); return; }
  XCopyArea(Win->GetDisplay(), Img, Win->GetWindowBuffer(), Win->GetGC(),
	0, 0, xsize, ysize, xpos, ypos);
  Win->Redraw(xpos, ypos, xsize, ysize);
  }

void IListBox::Rebuild()  {
  int ctr, ctr2;
  Display *disp = Win->GetDisplay();
  GC gc = Win->GetGC();

  XSetForeground(disp, gc, Win->GetPaperColor());
  XFillRectangle(disp, Img, gc, 2, 2, xsize-4, ysize-4);
  XSetForeground(disp, gc, Win->GetSelectColor());
  for(ctr=0; ctr<(lines<?nent); ctr++)  {
    XCopyArea(disp, Wrk[ctr], Img, gc, 0, 0,
	wx[ctr], (wy[ctr])<?(xsize-6), 3, 3+(dy*ctr));
    for(ctr2=0; ctr2<selmax; ctr2++)  {
      if(sel[ctr2] == ctr)  {
	ctr2 = selmax;
	XDrawRectangle(disp, Img, gc, 2, 2+(dy*ctr), xsize-5, dy);
	}
      }
    }
  Redraw();
  }

int IListBox::Press(int b, int x, int y) {
//  printf("x=%d, y=%d\n", x, y);
  int tst = (y-3)/dy;
  if(tst < nent && tst >= 0)  {
    if(sel[0] == tst && (time(NULL) <= (lastclick)))  {
      if(dccallback != NULL) (*dccallback)(parent, this, sel[0]);
      }
    else  {
//      if(sel[0] == -1 && selcallback != NULL)
      if(selcallback != NULL)
	(*selcallback)(parent, this, tst);
      sel[0] = tst;
      lastclick = time(NULL);
      }
    }
  Rebuild();
  return 1;
  }

int IListBox::Release(int b, int x, int y) {
  return 1;
  }

int IListBox::NumSelections()  {
  int ctr;
  for(ctr=0; ctr<selmax && sel[ctr] != -1; ctr++);
  return ctr;
  }

void IListBox::SetDCCallback(void (*cb)(IDoDad *, IDoDad *, int))  {
  dccallback = cb;
  }
 
void IListBox::SetSelCallback(void (*cb)(IDoDad *, IDoDad *, int))  {
  selcallback = cb;
  }
 
void IListBox::SetDeselCallback(void (*cb)(IDoDad *, IDoDad *, int))  {
  deselcallback = cb;
  }

void IListBox::Select(int s) {
  if(selcallback != NULL)
    (*selcallback)(parent, this, s);  
  sel[0] = s;
  lastclick = time(NULL);
  Rebuild();
  }
