/* $Header: /afs/athena.mit.edu/astaff/project/atdev/src/dialog/RCS/dialog.c,v 3.4 91/07/03 09:21:52 dot Exp Locker: dot $ */

/*******************************************************************
  Copyright (C) 1990 by the Massachusetts Institute of Technology

   Export of this software from the United States of America is assumed
   to require a specific license from the United States Government.
   It is the responsibility of any person or organization contemplating
   export to obtain such a license before exporting.

WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
distribute this software and its documentation for any purpose and
without fee is hereby granted, provided that the above copyright
notice appear in all copies and that both that copyright notice and
this permission notice appear in supporting documentation, and that
the name of M.I.T. not be used in advertising or publicity pertaining
to distribution of the software without specific, written prior
permission.  M.I.T. makes no representations about the suitability of
this software for any purpose.  It is provided "as is" without express
or implied warranty.

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

#ifdef _AtDevelopment_
#include "dialog.h"
#else
#include <At/dialog.h>
#endif

#ifdef SYSV
#define bcopy(s1, s2, l) memcpy (s2, s1, l)
#endif /* SYSV */

extern Widget MuCreateOptionMenu(Widget p, String name);

extern char *MuOptionMenuGetSelectedString(Widget w);

static void getvalue(DialogInfo *di, Widget w, char *value, int len)
{
  Arg a;
  
  switch(di->valuetype) {
  case AtDialogRESOURCE:
    XtSetArg(a, di->value, value);
    XtGetValues(w, &a, 1);
    break;
  case AtDialogIMMEDIATE:
    bcopy((char *)&di->value, value, len);
    break;
  case AtDialogABSOLUTE:
    bcopy(di->value, value, len);
    break;
  case AtDialogOFFSET:
    bcopy(((char *)w) + ((int)di->value), value, len);
    break;
  case AtDialogCOPYSTRING:  /* special case.  value is a char ** */
    *((char **)value) = di->value;
    break;
  }
}

static void storevalue(Dialog *d, DialogInfo *di, Widget w,
		       char *value, int len)
{
  switch(di->valuetype) {
  case AtDialogRESOURCE:
    if (len <= sizeof(XtArgVal))  {
      XtSetArg(d->arglist[d->nargs], di->value, *(XtArgVal *) value);
      d->nargs++;
    }
    else  {
      XtSetArg(d->arglist[d->nargs], di->value, value);
      d->nargs++;
    }
    break;
  case AtDialogIMMEDIATE:
    bcopy(value, (char *)&di->value, len);
    break;
  case AtDialogABSOLUTE:
    bcopy(value, di->value, len);
    break;
  case AtDialogOFFSET:
    bcopy(value, ((char *)w) + ((int)di->value), len);
    break;
  case AtDialogCOPYSTRING:/* value is a char **, di->value points to a buf */
    strcpy(di->value, *(char **)value);
    break;
  }
}

static void doresources(Dialog *d, Widget w)
{
  XtSetValues(w, d->arglist, d->nargs);
  d->nargs = 0;
}

static void create(Widget p, DialogInfo *di)
{
  /*
   * I'd like to use gadgets here, but they don't work with
   * my AtLayout widget.  If I was willing to subclass off of
   * XmManager, they probably would work.
   */
  
  switch (di->widgettype) {
  case AtDialogLABEL:
    di->w = XmCreateLabel(p, di->name, NULL, 0);
    XtManageChild(di->w);
    break;
  case AtDialogDOUBLEPARAMETER:
  case AtDialogINTPARAMETER:
  case AtDialogSHORTPARAMETER:
    di->w = AtParameterCreate(p, di->name, NULL, 0);
    XtManageChild(di->w);
    break;
  case AtDialogINTOPTION:
  case AtDialogSHORTOPTION:
  case AtDialogSTRINGOPTION:
    di->w = MuCreateOptionMenu(p, di->name);
    XtManageChild(di->w);
    break;
  case AtDialogTOGGLE:
    di->w = XmCreateToggleButton(p, di->name, NULL, 0);
    XtManageChild(di->w);
    break;
  case AtDialogTEXT:
    di->w = XmCreateText(p, di->name, NULL, 0);
    XtManageChild(di->w);
    break;
  case AtDialogSEPARATOR:
    di->w = XmCreateSeparator(p, di->name, NULL, 0);
    XtManageChild(di->w);
    break;
  case AtDialogPUSHBUTTON:
    di->w = XmCreatePushButton(p, di->name, NULL, 0);
    XtManageChild(di->w);
    break;
  }
}

Dialog *AtDialogCreate(Widget parent, char *shellname, char *formname,
		       DialogInfo *di, int n)
{
  Dialog *d;
  int i;
  
  d = XtNew(Dialog);
  
  d->shell = XmCreateDialogShell(parent, shellname, NULL, 0);
  d->info = di;
  d->n = n;
  d->form = XtCreateWidget(formname, atLayoutWidgetClass, d->shell, NULL, 0);
  d->nargs = 0;

  for(i = 0; i < n; i++) {
    create(d->form, &d->info[i]);
    if ((d->info[i].widgettype == AtDialogPUSHBUTTON) &&
	(d->info[i].value != NULL))
      XtAddCallback(d->info[i].w, XmNactivateCallback,
		    d->info[i].value, (caddr_t) d);
    if (d->info[i].valuetype == AtDialogRESOURCE)
      d->nargs++;
  }
  d->arglist = (Arg *) XtMalloc(d->nargs * sizeof(Arg));
  d->nargs = 0;
  return d;
}


void AtDialogSetValues(Dialog *d, Widget w)
{
  int i;
  Arg a;
  char *string;
  int integer;
  short shortint;
  double floating;
  Boolean boolean;
  
  /*
   * for each item in the dialog, get the value of the resource from
   * w and display it in the appropriate widget in d;
   */
  
  for(i = 0; i < d->n; i++) {
    switch(d->info[i].widgettype) {
    case AtDialogTOGGLE:
      getvalue(&d->info[i], w, (char *)&boolean, sizeof(Boolean));
      XtSetArg(a, XmNset, boolean);
      XtSetValues(d->info[i].w, &a, 1);
      break;
    case AtDialogTEXT:
      getvalue(&d->info[i], w, (char *)&string, sizeof(char *));
      XmTextSetString(d->info[i].w, string);
      break;
    case AtDialogDOUBLEPARAMETER:
      getvalue(&d->info[i], w, (char *)&floating, sizeof(double));
      AtParameterSetValue(d->info[i].w, floating, False);
      break;
    case AtDialogINTPARAMETER:
      getvalue(&d->info[i], w, (char *)&integer, sizeof(int));
      AtParameterSetValue(d->info[i].w, (double)integer, False);
      break;
    case AtDialogSHORTPARAMETER:
      getvalue(&d->info[i], w, (char *)&shortint, sizeof(short));
      AtParameterSetValue(d->info[i].w, (double)shortint, False);
      break;
    case AtDialogINTOPTION:
      getvalue(&d->info[i], w, (char *)&integer, sizeof(int));
      MuOptionMenuSetSelectedItem(d->info[i].w, integer);
      break;
    case AtDialogSHORTOPTION:
      getvalue(&d->info[i], w, (char *)&shortint, sizeof(short));
      MuOptionMenuSetSelectedItem(d->info[i].w, shortint);
      break;
    case AtDialogSTRINGOPTION:
      getvalue(&d->info[i], w, (char *)&string, sizeof(char *));
      MuOptionMenuSetSelectedString(d->info[i].w, string);
      break;
    }
  }
}

void AtDialogGetValues(Dialog *d, Widget w)
{
  int i;
  Arg a;
  Arg b;
  char **freestrings;
  double *floatings;
  int freestringcount = 0, doublecount = 0;
  char *string;
  int integer;
  short shortint;
  Boolean boolean;
  
  freestrings = (char **) XtMalloc(d->n * sizeof(char *));
  floatings = (double *) XtMalloc(d->n * sizeof(double));
  /*
   * for each item in the dialog, get the value from the dialog
   * widget and store it in the appropriate resource in w.
   */
  
  for(i=0; i < d->n; i++) {
    a.name = d->info[i].value;
    switch(d->info[i].widgettype) {
    case AtDialogTOGGLE:
      XtSetArg(b, XmNset, &boolean);
      XtGetValues(d->info[i].w, &b, 1);
      storevalue(d, &d->info[i], w, (char *)&boolean, sizeof(Boolean));
      break;
    case AtDialogTEXT:
      string = XmTextGetString(d->info[i].w);
      storevalue(d, &d->info[i], w, (char *)&string, sizeof(char *));
      if (d->info[i].valuetype == AtDialogRESOURCE)
	freestrings[freestringcount++] = string;
      else if (d->info[i].valuetype == AtDialogCOPYSTRING)
	XtFree(string);
      break;
    case AtDialogDOUBLEPARAMETER:
      floatings[doublecount] = AtParameterGetValue(d->info[i].w);
      storevalue(d, &d->info[i], w, (char *)&floatings[doublecount], 
		 sizeof(double));
      doublecount++;
      break;
    case AtDialogINTPARAMETER:
      integer = (int)AtParameterGetValue(d->info[i].w);
      storevalue(d, &d->info[i], w, (char *)&integer, sizeof(int));
      break;
    case AtDialogSHORTPARAMETER:
      shortint = (short)AtParameterGetValue(d->info[i].w);
      storevalue(d, &d->info[i], w, (char *)&shortint, sizeof(short));
      break;
    case AtDialogINTOPTION:
      integer = MuOptionMenuGetSelectedItem(d->info[i].w);
      storevalue(d, &d->info[i], w, (char *)&integer, sizeof(int));
      break;
    case AtDialogSHORTOPTION:
      shortint = MuOptionMenuGetSelectedItem(d->info[i].w);
      storevalue(d, &d->info[i], w, (char *)&shortint, sizeof(short));
      break;
    case AtDialogSTRINGOPTION:
      string = MuOptionMenuGetSelectedString(d->info[i].w);
      storevalue(d, &d->info[i], w, (char *)&string, sizeof(char *));
      if (d->info[i].valuetype == AtDialogRESOURCE)
	freestrings[freestringcount++] = string;
      else if (d->info[i].valuetype == AtDialogCOPYSTRING)
	XtFree(string);
      break;
    }
  }
  doresources(d, w);

  for (i = 0; i < freestringcount; i++)
    XtFree(freestrings[i]);
  XtFree(freestrings);
  XtFree(floatings);
}

void AtDialogDestroy(Dialog *d)
{
  XtDestroyWidget(d->shell);
  XtFree(d->arglist);
  XtFree(d);
}

void AtDialogDo(Dialog *d, Widget w)
{
  d->w = w;
  AtDialogSetValues(d, w);
  XtManageChild(d->form); 
  XtPopup(d->shell, XtGrabNone);
}

void AtDialogApplyCallback(Widget w, Dialog *d)
{
  AtDialogGetValues(d,d->w);
}

void AtDialogResetCallback(Widget w, Dialog *d)
{
  AtDialogSetValues(d, d->w);
}

void AtDialogDoneCallback(Widget w, Dialog *d)
{
  XtPopdown(d->shell); 
}



