/*
 * Copyright 1992 the Board of Trustees of the Leland Stanford Junior
 * University. Official permission to use this software is included in
 * the documentation. It authorizes you to use this file for any
 * non-commercial purpose, provided that this copyright notice is not
 * removed and that any modifications made to this file are commented
 * and dated in the style of the example below.
 */

/*
 *
 *  source file:   ./xtpanel/slider.c
 *
 * Steve Cole, Dave Nichols (SEP), August 28 1992
 *      Inserted this sample edit history entry.
 *      Please log any further modifications made to this file:
 * Steve Cole, Dave Nichols (SEP), November 20 1992 -  version 2.00
 * 1) added new objects: toggle, scrollbar, graph.
 * 2) added new actions: ASSIGN, SET.
 * 3) objects can have multiple actions.
 * 4) backquoted strings in actions get executed at action time.
 */

#include <X11/Intrinsic.h>
#include <X11/StringDefs.h>

#include <X11/Xaw/Box.h>
#include <X11/Xaw/Cardinals.h>
#include <X11/Xaw/Command.h>
#include <X11/Xaw/Label.h>
#include <X11/Xaw/Scrollbar.h>

#include "object.h" 
#include "tree.h"
#include "builders.h"

#include <stdio.h>

typedef struct sliderinfo {
    float minval;
    float maxval;
    Widget label;
    char* format;
    char* type;
};

void build_slider(root,parent,type)
     entry *root;
     Widget parent;
     char *type;
{
    Objdef *object;
    entry *curr;
    char* label;
    struct sliderinfo *slider_info;
    Arg args[10];
    int narg;
    Widget box, scrollbar, vlabel, button;
    float valmin,valmax,val,top;
    char text[100];
    int width,height;
    char *orient;
    char defname[12];
    static int numslid=1;
    static int numscroll=1;
    extern void slider_button_callback();
    extern void slider_jump_callback();
    extern void slider_scroll_callback();
    extern void slider_update();
    
    /* slider gets its own box */
    if (!strcmp(type,"slider")) {
      narg = 0;
      box = XtCreateManagedWidget("sliderbox",boxWidgetClass,
                 parent,args,narg);
    }
    else {
      box = parent;
    }
    
    /* create new object */
    object = new_object();

    /* construct default slider name */
    if (!strcmp(type,"slider")) {
       sprintf(defname,"slider%d",numslid++);
    } else {
       sprintf(defname,"scrollbar%d",numscroll++);
    }
    
    /* find label, name, action in tree */
    object->name = get_value(root,"name",defname);
    label = get_value(root,"label",object->name);
    object->action = parse_actions(object->name,root);
    slider_info = (struct sliderinfo*) 
                   malloc( sizeof( struct sliderinfo ) );
    object->info = slider_info;
    slider_info->minval = ((float) atof(get_value(root,"min","0")));
    slider_info->maxval = ((float) atof(get_value(root,"max","1")));
    slider_info->label = (Widget)0;
    /* slider value defaults to minimum */
    val = (float) atof(get_value(root,"value",get_value(root,"min","0")));
    slider_info->format = get_value(root,"format","%f");
    /* save type (scrollbar, slider) for use by callback routines */
    slider_info->type = strdupl(type);
    
    /* the slider label */
    /* for type scrollbar, no label is displayed */
    if (!strcmp(type,"slider")) {
	narg = 0;
	XtSetArg(args[narg], XtNlabel, label); narg++;
	XtSetArg(args[narg], XtNborderWidth, 0); narg++;
	(void) XtCreateManagedWidget(object->name,labelWidgetClass,box,
				     args,narg);
    }
    
    /* determine the correct starting point for the slider */
    narg = 0;
    top = val/slider_info->maxval;
    if (sizeof(float) > sizeof(XtArgVal))
      {
	  XtSetArg(args[narg], XtNtopOfThumb, top); narg++;
      }
    else
      {
	  XtArgVal * l_top = (XtArgVal *) &top;
	  XtSetArg(args[narg], XtNtopOfThumb, *l_top); narg++;
      }

    /* common parameters */
    common_tags(root,args,&narg,SET_FG|SET_BG|SET_BORDER);

    /* height, width, orient */
    /* done here instead of common_tags so we could have defaults */
    height = (int) atoi(get_value(root,"height","25"));
    width = (int) atoi(get_value(root,"width","100"));
    orient = get_value(root,"orientation","horizontal");
    XtSetArg(args[narg], XtNlength, width); narg++;
    XtSetArg(args[narg], XtNthickness, height); narg++;
    /* the SetTag routine in builders.c does the necessary conversion */
    SetTag(box,args,&narg,"orientation",orient);

    /* slider is actually an athena scrollbar widget */
    scrollbar = XtCreateManagedWidget(object->name,scrollbarWidgetClass,
                      box,args,narg);
    
    /* jump callback is for middle mouse button */
    XtAddCallback( scrollbar, XtNjumpProc, slider_jump_callback, 
		  (XtPointer) object );
    
    /* scroll callback is for incremental scrolling with left and 
       right buttons */
    XtAddCallback( scrollbar, XtNscrollProc, slider_scroll_callback, 
		  (XtPointer) object );
    
    /* set to the correct starting point */
    (void) XawScrollbarSetThumb(scrollbar,
    (val-slider_info->minval)/
             (slider_info->maxval-slider_info->minval),-1.);
    
    /* add a button to print out slider value */
    if (!strcmp(type,"slider")) {
	button = XtCreateManagedWidget(object->name,commandWidgetClass,box,
				       NULL,ZERO);
	XtAddCallback(button, XtNcallback, slider_button_callback, 
		      (XtPointer) object );
    }
    
    sprintf( text, slider_info->format, (float) val);
    object->value = strdupl(text);
    object->widgetname = scrollbar;
    object->updater = slider_update;
    
    /* indicate the slider value using another label */
    if (!strcmp(type,"slider")) {
	narg = 0;
	XtSetArg( args[narg], XtNlabel, object->value); narg++;
	vlabel = XtCreateManagedWidget(object->name,labelWidgetClass,box,
				       args,narg);
	slider_info->label = vlabel;
    }
}

void
  slider_jump_callback(widget, client_data, top_ptr)
Widget widget;
XtPointer client_data, top_ptr;
{
    Objdef *object;
    struct sliderinfo *slider_info;
    Arg arg[1];
    char text[20];
    /* top is new location of slider */
    float top = *((float *) top_ptr);
    object = (Objdef *) client_data;
    slider_info = (struct sliderinfo *) object->info;
    /* compute new value */
    sprintf( text, slider_info->format, 
	    (float) slider_info->minval + 
	    top*(slider_info->maxval - slider_info->minval));
    object->value = strdupl(text);
    /* set the label to the new value */
    if (slider_info->label != (Widget) 0) {
	XtSetArg( arg[0], XtNlabel, text );
	XtSetValues( slider_info->label, arg, ONE );
    }
    if (!strcmp(slider_info->type,"scrollbar")) 
       perform_actions(object->name,object->action,1);
}

void
  slider_scroll_callback(widget, client_data, pos_ptr)
Widget widget;
XtPointer client_data, pos_ptr;
{
    Objdef *object;
    struct sliderinfo *slider_info;
    Arg arg[1];
    char text[10];
    float top;
    Dimension len;
    int pos;
    pos = (int) pos_ptr;
    object = (Objdef *) client_data;
    slider_info = (struct sliderinfo *) object->info;
    /* get the current position of the slider */
    XtSetArg( arg[0], XtNtopOfThumb, &top );
    XtGetValues( object->widgetname, arg, ONE );
    /* now compute new position - 5% change */
    top -= pos/abs(pos) * 0.05;
    if (top > 1.) top = 1.;
    if (top < 0.) top = 0.;
    /* compute new value */
    sprintf( text, slider_info->format, 
	    (float) slider_info->minval +
	    top*(slider_info->maxval - slider_info->minval));
    object->value = strdupl(text);
    /* update label */
    if (slider_info->label != (Widget) 0) {
	XtSetArg( arg[0], XtNlabel, text );
	XtSetValues( slider_info->label, arg, ONE );
    }
    /* update the slider */
    if (sizeof(float) > sizeof(XtArgVal))
      {
	  XtSetArg(arg[0], XtNtopOfThumb, top);
      }
    else
      {
	  XtArgVal * l_top = (XtArgVal *) &top;
	  XtSetArg(arg[0], XtNtopOfThumb, *l_top);
      }
    XtSetValues( object->widgetname, arg, ONE );
    if (!strcmp(slider_info->type,"scrollbar")) 
       perform_actions(object->name,object->action,1);
}

/* called when ok button of slider is pressed */
void
  slider_button_callback(widget, client_data, callData)
Widget widget;
XtPointer client_data, callData;
{
    Objdef *object;
    extern int quitflag;
    
    object = (Objdef *) client_data;
    if ( perform_actions(object->name,object->action,1) && !quitflag ) 
      quit_xtpanel();
}

void
  slider_update(object, value)
Objdef *object;
char *value;
{
    struct sliderinfo *slider_info;
    Arg arg[1];
    char text[10];
    float top,val;
    Dimension len;
    int pos;

    slider_info = (struct sliderinfo *) object->info;
    sscanf( value,"%f",&val);
    top = (val - slider_info->minval)/
              (slider_info->maxval-slider_info->minval);
    if (top > 1.) top = 1.;
    if (top < 0.) top = 0.;
    /* compute new value */
    sprintf( text, slider_info->format, 
	    (float) slider_info->minval +
	    top*(slider_info->maxval - slider_info->minval));
    object->value = strdupl(text);
    /* update label */
    if (slider_info->label != (Widget) 0) {
	XtSetArg( arg[0], XtNlabel, text );
	XtSetValues( slider_info->label, arg, ONE );
    }
    /* update the slider */
    if (sizeof(float) > sizeof(XtArgVal))
      {
	  XtSetArg(arg[0], XtNtopOfThumb, top);
      }
    else
      {
	  XtArgVal * l_top = (XtArgVal *) &top;
	  XtSetArg(arg[0], XtNtopOfThumb, *l_top);
      }
    XtSetValues( object->widgetname, arg, ONE );
}
