/*
 * A simple form-fillout function that lets you pass an array of
 * Tag's that describe a form and it will pop up a window and let
 * a user fill out a form that describes the values you'd like.
 *
 * The main function is GetValues().  See the demo program in this
 * same directory (main.c, in the function edit()) for a more
 * detailed example.
 *
 * Written by Allen Martin, (amartin@cs.wpi.edu).
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "libsx.h"
#include "multireq.h"

#define MIN(a,b) (((a)<(b))?(a):(b))
#define MAX(a,b) (((a)>(b))?(a):(b))

typedef struct {
  Widget window;
  int cancelled;

  Widget *w;
  TagList *tags;
  
} MReqData;



/* protos */
static void mreq_ok(Widget w, MReqData *mdata);
static void mreq_cancel(Widget w, MReqData *mdata);
     
int GetValues(TagList *tags)
{
  MReqData mdata;
  int num_tags=0, num_widg=0, num_labels=0;
  int i, w, l;
  Widget *label_w, ok_w, cancel_w;
  char string[256], window_name[256]="Requestor";
  int maxwidth=0, widest_label=-1;
  
  /* first count the number of tag items and required widgets */
  for(; tags[num_tags].tag != TAG_DONE; num_tags++)
    {
      if(tags[num_tags].tag == TAG_LABEL)
	{
	  num_labels++;
	  continue;
	}
      else if(tags[num_tags].tag == TAG_WINDOW_LABEL)
	{
	  if(!tags[num_tags].label)
	    {
	      fprintf(stderr, "Invalid window name passed to GetValues()\n");
	      return(TRUE);
	    }

	  strcpy(window_name, tags[num_tags].label);
	  continue;
	}
      
      /* determine the widest label */
      if(strlen(tags[num_tags].label) > maxwidth)
	{
	  maxwidth = strlen(tags[num_tags].label);
	  widest_label = num_labels;
	}

      num_labels++;
      num_widg++;
    }
      
  /* allocate mem for the widgets */
  if(!(mdata.w = (Widget *)malloc(num_widg * sizeof(Widget))))
    return(TRUE);
  if(!(label_w = (Widget *)malloc(num_labels * sizeof(Widget))))
    {
      free(mdata.w);
      return(TRUE);
    }
  
  mdata.window = MakeWindow(window_name, SAME_DISPLAY, EXCLUSIVE_WINDOW);
  mdata.tags = tags;

  /* create the label widgets first */
  for(i=0, l=0; i<num_tags; i++)
    {
      if(tags[i].tag == TAG_WINDOW_LABEL)
	continue;
      
      label_w[l] = MakeLabel(tags[i].label);
      if(l)
	SetWidgetPos(label_w[l], PLACE_UNDER, label_w[l-1], NO_CARE, NULL);
      l++;
    }
  
  for(i=0, w=0, l=0; i<num_tags; i++)
    {
      switch(tags[i].tag)
	{
	case TAG_STRING:
	  if(tags[i].init)
	    mdata.w[w]=MakeStringEntry((char *)tags[i].data, 250, NULL, NULL);
	  else
	    mdata.w[w] = MakeStringEntry(NULL, 250, NULL, NULL);
	  
	  if(l)
	    SetWidgetPos(mdata.w[w], PLACE_UNDER, label_w[l-1],
			 PLACE_RIGHT, label_w[widest_label]);
	  else
	    SetWidgetPos(mdata.w[w], PLACE_RIGHT, label_w[widest_label],
			 NO_CARE, NULL);

	  l++;
	  w++;
	  break;

	case TAG_INT:
	  if(tags[i].init)
	    {
	      sprintf(string, "%d", *((int *)tags[i].data));
	      mdata.w[w] = MakeStringEntry(string, 250, NULL, NULL);
	    }
	  else
	    mdata.w[w] = MakeStringEntry(NULL, 250, NULL, NULL);
	  
	  if(l)
	    SetWidgetPos(mdata.w[w], PLACE_UNDER, label_w[l-1],
			 PLACE_RIGHT, label_w[widest_label]);
	  else
	    SetWidgetPos(mdata.w[w], PLACE_RIGHT, label_w[widest_label],
			 NO_CARE, NULL);

	  l++;
	  w++;
	  break;

	case TAG_FLOAT:
	  if(tags[i].init)
	    {
	      sprintf(string, "%f", *((float *)tags[i].data));
	      mdata.w[w] = MakeStringEntry(string, 250, NULL, NULL);
	    }
	  else
	    mdata.w[w] = MakeStringEntry(NULL, 250, NULL, NULL);
	  
	  if(l)
	    SetWidgetPos(mdata.w[w], PLACE_UNDER, label_w[l-1],
			 PLACE_RIGHT, label_w[widest_label]);
	  else
	    SetWidgetPos(mdata.w[w], PLACE_RIGHT, label_w[widest_label],
			 NO_CARE, NULL);

	  w++;
	  l++;
	  break;

	case TAG_LABEL:
	  l++;
	  break;
	case TAG_WINDOW_LABEL:
	  break;
	  
	default:
	  fprintf(stderr, "GetValues() : Invalid tag item %d\n", tags[i].tag);
	}
    }
  
  ok_w = MakeButton("Ok", (void *)mreq_ok, &mdata);
  SetWidgetPos(ok_w, PLACE_UNDER, label_w[num_labels-1], NO_CARE, NULL);

  cancel_w = MakeButton("Cancel", (void *)mreq_cancel, &mdata);
  SetWidgetPos(cancel_w, PLACE_UNDER, label_w[num_labels-1],
	       PLACE_RIGHT, ok_w);

  ShowDisplay();
  MainLoop();
  
  SetCurrentWindow(ORIGINAL_WINDOW);

  /* check for cancel */
  if(mdata.cancelled)
    return(TRUE);

  free(mdata.w);
  free(label_w);
  
  return(FALSE);
}

static void mreq_ok(Widget w, MReqData *mdata)
{
  int widg_num;
  TagList *tagptr;
  char *cptr;
  
  /* extract the info from the widgets */
  for(widg_num=0, tagptr=mdata->tags; tagptr->tag != TAG_DONE; tagptr++)
    {
      switch(tagptr->tag)
	{
	case TAG_STRING:
	  cptr = GetStringEntry(mdata->w[widg_num++]);
	  strcpy(tagptr->data, cptr);
	  break;
	case TAG_INT:
	  cptr = GetStringEntry(mdata->w[widg_num++]);
	  *((int *)tagptr->data) = atoi(cptr);
	  break;
	case TAG_FLOAT:
	  cptr = GetStringEntry(mdata->w[widg_num++]);
	  *((float *)tagptr->data) = atof(cptr);
	  break;
	case TAG_WINDOW_LABEL:
	case TAG_LABEL:
	  break;
	default:
	  fprintf(stderr, "GetValues() : Invalid tag item %d\n", tagptr->tag);
	}
    }
  
  mdata->cancelled = FALSE;
  SetCurrentWindow(mdata->window);
  CloseWindow();
}

static void mreq_cancel(Widget w, MReqData *mdata)
{
  mdata->cancelled = TRUE;
  SetCurrentWindow(mdata->window);
  CloseWindow();
}


syntax highlighted by Code2HTML, v. 0.9.1