/********************************************************************
This file is part of the abs 0.907 distribution.  abs is a spreadsheet
with graphical user interface.

Copyright (C) 1998-2001  André Bertin (Andre.Bertin@ping.be) 

This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version if in the same spirit as version 2.

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., 675 Mass Ave, Cambridge, MA 02139, USA.

Concact: abs@pi.be
         http://home.pi.be/bertin/abs.shtml

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



























#include "entrypop.h"
#include "param.h"
#include "list.xpm"
#include "rollup.xpm"
#include "rolldown.xpm"
#include "memory.h"
#include "popnindex.h"
#include "button.h"

static XtActionsRec entrypop_actionsTable[] =
{
  {"entrypopEnter", cb_entrypopEnter},
  {"entrypopEdit", cb_entrypopEdit},
};


static char entrypop_Translations[] = "\
<Key>Return:    entrypopEnter()\n\
<Key>KP_Enter:  entrypopEnter()\n\
";


static Entry_Pop **record;
static int nrecord = 0;

int
entrypop_setrange (Entry_Pop * pop, double val, double step, double vmin, double vmax)
{
  char buf[64];
  pop->val = val;
  pop->step = step;
  pop->vmin = vmin;
  pop->vmax = vmax;
  sprintf (buf, "%g", val);
  SetEntryString (pop->entry, buf);
  EntrySetInsertionPosition (pop->entry, 0);
  return 0;
}

double
entrypop_getvalue (Entry_Pop * ep_obj)
{
  char *name;

  if (ep_obj->type == roll)
    {
      XtVaGetValues (ep_obj->entry, XtNstring, &name, NULL);
      sscanf (name, "%lf", &(ep_obj->val));
      if (ep_obj->val > ep_obj->vmax)
	ep_obj->val = ep_obj->vmax;
      if (ep_obj->val < ep_obj->vmin)
	ep_obj->val = ep_obj->vmin;
      return ep_obj->val;
    }
  return 0.0;
}

char *
entrypop_gettext (Entry_Pop * ep_obj)
{
  char *name;

  if (ep_obj != NULL)
    {
      XtVaGetValues (ep_obj->entry, XtNstring, &name, NULL);
      return name;
    }
  return NULL;
}

int
entrypop_which (Entry_Pop * ep_obj)
{
  char *name;
  int i;

  if (ep_obj != NULL)
    if (ep_obj->type == roll)
      {
	XtVaGetValues (ep_obj->entry, XtNstring, &name, NULL);
	for (i = 0; i < ep_obj->nitem; i++)
	  if (strcmp (XtName (ep_obj->items[i]), name))
	    return i;
      }
  return 0;
}


void 
cb_entrypopEnter (w, event, params, num_params)
     Widget w;
     XEvent *event;
     String *params;
     int *num_params;
{				
  int i = 0;
  char *val;
  Widget item;
  EntrySetEditable (w, False);

  while (i < nrecord)
    {
      if (record[i]->entry == w)
	{
	  XtVaGetValues (w, XtNstring, &val, NULL);
	  item = entrypop_add_item (record[i], val);
	  if (record[i]->callback != NULL)
	    (*(record[i]->callback)) (item, XtName (item), NULL);
	  return;
	}
      i++;
    }
  return;
}

void
cb_entrypopEnterWin (Widget w, XtPointer pointer, XEvent * event, Boolean * ctd)
{
  Entry_Pop *ep_obj = (Entry_Pop *) pointer;

  if (ep_obj->Editable)
    EntrySetEditable (w, True);
}

void
cb_entrypopLeaveWin (Widget w, XtPointer pointer, XEvent * event, Boolean * ctd)
{
  
  
  EntrySetEditable (w, False);
}



void 
cb_entrypopEdit (w, event, params, num_params)
     Widget w;
     XEvent *event;
     String *params;
     int *num_params;
{
}

int
entrypop_callback (pop, cbfunc)
     Entry_Pop *pop;
     void (*cbfunc) ();
{
  pop->callback = cbfunc;
  return 0;
}


void
nextentry (widget, pointer, junk)
     Widget widget;
     XtPointer pointer;
     XtPointer junk;		
{
  int i = 0;
  char buf[64];
  Entry_Pop *ep_obj = (Entry_Pop *) pointer;
  entrypop_getvalue (ep_obj);	
  ep_obj->val -= ep_obj->step;
  if (ep_obj->val < ep_obj->vmin)
    ep_obj->val = ep_obj->vmin;
  sprintf (buf, "%g", ep_obj->val);
  SetEntryString (ep_obj->entry, buf);
  EntrySetInsertionPosition (ep_obj->entry, 0);

  if (ep_obj->callback != NULL)
    (*(ep_obj->callback)) (ep_obj->items[i], XtName (ep_obj->items[i]), NULL
      );
}

void
previousentry (widget, pointer, junk)
     Widget widget;
     XtPointer pointer;
     XtPointer junk;		
{
  int i = 0;
  char buf[64];
  Entry_Pop *ep_obj = (Entry_Pop *) pointer;
  entrypop_getvalue (ep_obj);	
  ep_obj->val += ep_obj->step;
  if (ep_obj->val > ep_obj->vmax)
    ep_obj->val = ep_obj->vmax;
  sprintf (buf, "%g", ep_obj->val);

  SetEntryString (ep_obj->entry, buf);
  EntrySetInsertionPosition (ep_obj->entry, 0);

  if (ep_obj->callback != NULL)
    (*(ep_obj->callback)) (ep_obj->items[i], XtName (ep_obj->items[i]), NULL
      );
}


void
changeentry (widget, pointer, junk)
     Widget widget;
     XtPointer pointer;
     XtPointer junk;		
{
  int i = 0;
  Entry_Pop *ep_obj = (Entry_Pop *) pointer;
  while (widget != ep_obj->items[i] && i < ep_obj->nitem)
    i++;

  if (i == ep_obj->nitem)
    return;

  SetEntryString (ep_obj->entry, XtName (ep_obj->items[i]));
  EntrySetInsertionPosition (widget, 0);

  if (ep_obj->callback != NULL)
    (*(ep_obj->callback)) (ep_obj->items[i], XtName (ep_obj->items[i]), NULL);

}

int
entrypop_set_val (ep_obj, name)
     Entry_Pop *ep_obj;
     char *name;
{
  SetEntryString (ep_obj->entry, name);
  EntrySetInsertionPosition (ep_obj->entry, 0);
  return 0;
}

int
entrypop_init_val (ep_obj, name)
     Entry_Pop *ep_obj;
     char *name;
{
  SetEntryString (ep_obj->entry, name);
  return 0;
}

int
entrypop_add_items (ep_obj, name)
     Entry_Pop *ep_obj;
     char **name;
{
  int i = 0;
  if (ep_obj == NULL || name == NULL)
    return -1;
  while (name[i] != NULL)
    {
      entrypop_add_item (ep_obj, name[i]);
      i++;
    }
  return 0;
}

Widget
entrypop_add_item (ep_obj, name)
     Entry_Pop *ep_obj;
     char *name;
{
  Widget item = NULL;
  int pos = -1;
  int i;

  if (ep_obj->type == roll)
    {
      sscanf (name, "%lf", &(ep_obj->val));
      if (ep_obj->val > ep_obj->vmax)
	ep_obj->val = ep_obj->vmax;
      if (ep_obj->val < ep_obj->vmin)
	ep_obj->val = ep_obj->vmin;
      return item;
    }

  if (ep_obj->type != popdown)
    return item;

  
  for (i = 0; i < ep_obj->nitem; i++)
    {
      int cmp = strcmp (XtName (ep_obj->items[i]), name);
      if (cmp == 0)
	return ep_obj->items[i];
      if (cmp > 0 && pos < 0)
	pos = i;
    }


  item = XtCreateManagedWidget (name,
				smeBSBObjectClass, ep_obj->popuplist,
				NULL, (Cardinal) 0);

  XtAddCallback (item, XtNcallback, changeentry, (caddr_t) ep_obj);

  ep_obj->nitem++;
  ep_obj->items = (Widget *) realloc (ep_obj->items, sizeof (Widget) * ep_obj->nitem);

  if (pos > 0)
    {
      for (i = ep_obj->nitem - 1; i > pos; i--)
	ep_obj->items[i] = ep_obj->items[i - 1];
      ep_obj->items[pos] = item;
    }
  else
    ep_obj->items[ep_obj->nitem - 1] = item;

  return item;
}

int
entrypop_remove_item (Entry_Pop * ep_obj, char *name)
{
  int j;
  int i = 0;

  if (ep_obj->type != popdown)
    return 0;

  while (i < ep_obj->nitem && strcmp (XtName (ep_obj->items[i]), name))
    i++;

  if (i == ep_obj->nitem)
    return 0;

  XtUnmanageChild (ep_obj->items[i]);
  XtDestroyWidget (ep_obj->items[i]);

  ep_obj->nitem--;

  for (j = i; j < ep_obj->nitem; j++)
    ep_obj->items[j] = ep_obj->items[j + 1];

  return 0;
}


Entry_Pop *
newentrypop (Widget parent, char *name, poptype type, int textw, int texth)
{
  Entry_Pop *ep_obj;
  XtTranslations trans_table;
  Arg args[2];
  ep_obj = (Entry_Pop *) absmalloc (sizeof (Entry_Pop), "newentrypop:ep_obj ");

  record = (Entry_Pop **) absmalloc (sizeof (Entry_Pop *) * (nrecord + 1), "newentrypop:record ");
  record[nrecord] = ep_obj;;
  nrecord++;
  ep_obj->Editable = 1;
  ep_obj->parent = parent;
  ep_obj->type = type;


  w_n = 0;
  w_dim (textw + 20, texth);
  w_bord (0);
  w_inbord (0);
  w_noresize ();
  ep_obj->baseform = XtCreateManagedWidget ("entrypopbase", formWidgetClass, ep_obj->parent, w_args, w_n);



  ep_obj->entry = CreateEntry (ep_obj->baseform, "entry", 0, 15, textw, texth, "test");
  w_n = 0;
  w_rel (NULL, 0, 0);
  w_bONw ();

  w_set (ep_obj->entry);

  EntrySetEditable (ep_obj->entry, False);

  if (type == popdown)
    {
      ep_obj->arrowbtndown = (Widget) make_menu_button_pixmap (ep_obj->baseform, "list", list_xpm, NULL, NULL);
      w_n = 0;
      w_relv (NULL, texth - 15);
      w_bONw ();
      w_relh (ep_obj->entry, 0);
      w_set (ep_obj->arrowbtndown);


      XtSetArg (args[0], XtNmenuName, name);
      XtSetValues (ep_obj->arrowbtndown, args, (Cardinal) 1);



      ep_obj->popuplist = XtCreatePopupShell (name, simpleMenuWidgetClass, ep_obj->arrowbtndown, NULL, 0);
      w_n = 0;
      w_bONw ();
      w_set (ep_obj->popuplist);
    }
  if (type == roll)
    {
      ep_obj->arrowbtnup = (Widget) make_repeater_pixmap (ep_obj->baseform, "rollup", rollup_xpm, previousentry, (caddr_t) ep_obj);
      w_n = 0;
      w_relv (NULL, 0);
      w_bONw ();
      w_relh (ep_obj->entry, 0);
      w_set (ep_obj->arrowbtnup);

      ep_obj->arrowbtndown = (Widget) make_repeater_pixmap (ep_obj->baseform, "rolldown", rolldown_xpm, nextentry, (caddr_t) ep_obj);
      w_n = 0;
      w_relv (ep_obj->arrowbtnup, 0);
      w_bONw ();
      w_relh (ep_obj->entry, 0);
      w_set (ep_obj->arrowbtndown);

    }
  ep_obj->nitem = 0;
  ep_obj->items = NULL;
  ep_obj->callback = NULL;



  XtAppAddActions (XtWidgetToApplicationContext (ep_obj->entry)
		   ,entrypop_actionsTable, XtNumber (entrypop_actionsTable));

  trans_table = XtParseTranslationTable (entrypop_Translations);
  XtOverrideTranslations (ep_obj->entry, trans_table);

  XtAddEventHandler (ep_obj->entry, EnterWindowMask, True, cb_entrypopEnterWin, (caddr_t) ep_obj);
  XtAddEventHandler (ep_obj->entry, LeaveWindowMask, True, cb_entrypopLeaveWin, (caddr_t) ep_obj);

  return ep_obj;

}
