/*ScianVisSticks.c
  November 9, 1992
  Eric Pepke
  Numbers visualization object in SciAn*/

#include "Scian.h"
#include "ScianTypes.h"
#include "ScianArrays.h"
#include "ScianWindows.h"
#include "ScianTextBoxes.h"
#include "ScianButtons.h"
#include "ScianTitleBoxes.h"
#include "ScianObjWindows.h"
#include "ScianIcons.h"
#include "ScianColors.h"
#include "ScianControls.h"
#include "ScianLists.h"
#include "ScianSliders.h"
#include "ScianIDs.h"
#include "ScianDatasets.h"
#include "ScianPictures.h"
#include "ScianDialogs.h"
#include "ScianErrors.h"
#include "ScianComplexControls.h"
#include "ScianMethods.h"
#include "ScianStyle.h"
#include "ScianVisObjects.h"
#include "ScianVisNumbers.h"
#include "ScianDraw.h"
#include "ScianTemplates.h"
#include "ScianTemplateHelper.h"
#include "ScianTimers.h"
#include "ScianSpaces.h"
#include "ScianDrawings.h"

ObjPtr visNumbers;	/*Class for numbers object*/

static ObjPtr ChangeNumberFormat(textBox)
ObjPtr textBox;
/*Changes a numeric display's FORMAT according to textBox*/
{
    ObjPtr repObj;
    repObj = GetObjectVar("ChangeNumberFormat", textBox, REPOBJ);
    if (!repObj) return ObjFalse;
    SetVar(repObj, FORMAT, GetValue(textBox));
    ImInvalid(repObj);
    return ObjTrue;
}

static ObjPtr AddNumbersControls(object, panelContents)
ObjPtr object, panelContents;
/*Adds controls to a numbers object*/
{
    ObjPtr titleBox, textBox, checkBox, slider, colorWheel;
    ObjPtr var;
    real rgb[3], hsv[3];
    Bool hasBackground;
    ObjPtr corral, icon, name;
    ObjPtr numbersField;
    ObjPtr defaultIcon;

    /*Add in the corral*/
    corral = NewIconCorral(NULLOBJ,
			   MAJORBORDER, MAJORBORDER + ONECORRALWIDTH,
			   CWINHEIGHT - MAJORBORDER - ONECORRALHEIGHT,
			   CWINHEIGHT - MAJORBORDER, 0);
    SetVar(corral, SINGLECORRAL, ObjTrue);
    SetVar(corral, TOPDOWN, ObjTrue);
    SetVar(corral, NAME, NewString("Number Field"));
    SetVar(corral, HELPSTRING,
	NewString("This corral shows the dataset that is being used to make \
the numeric display.  The value shown and the position display, if any, is \
calculated from this field.  The color of the position display is calculated \
using the Color Field, available in the Color control set."));
    PrefixList(panelContents, corral);
    SetVar(corral, PARENT, panelContents);
    SetVar(corral, REPOBJ, object);
    SetMethod(corral, DROPINCONTENTS, DropInMainDatasetCorral);


    /*Create the numbers source text box*/
    textBox = NewTextBox(MAJORBORDER, MAJORBORDER + ONECORRALWIDTH, 
			 CWINHEIGHT - MAJORBORDER - ONECORRALHEIGHT - TEXTBOXSEP - TEXTBOXHEIGHT,
			 CWINHEIGHT - MAJORBORDER - ONECORRALHEIGHT - TEXTBOXSEP,
			 0, "Number Field Text", "Number Field");
    PrefixList(panelContents, textBox);
    SetVar(textBox, PARENT, panelContents);
    SetTextAlign(textBox, CENTERALIGN);

    /*Put in an icon that represents the field*/
    numbersField = GetVar(object, NUMBERSFIELD);
    name = GetVar(numbersField, NAME);
    defaultIcon = GetVar(numbersField, DEFAULTICON);
    if (defaultIcon)
    {
	icon = NewObject(defaultIcon, 0);
	SetVar(icon, NAME, name);
    }
    else
    {
	icon = NewIcon(0, 0, ICONQUESTION, GetString(name));
    }
    SetVar(icon, ICONLOC, NULLOBJ);
    SetVar(icon, REPOBJ, numbersField);
    DropIconInCorral(corral, icon);

    /*Add in the group of controls for text color*/
    titleBox = TemplateTitleBox(VisNumbersTemplate, "Text");
    SetVar(titleBox, PARENT, panelContents);
    PrefixList(panelContents, titleBox);

    /*Get the color for priming the controls*/
    MakeVar(object, COLOR);
    var = GetVar(object, COLOR);
    if (IsArray(var) && RANK(var) == 1 && DIMS(var)[0] == 3)
    {
	Array2CArray(rgb, var);
    }
    else if (IsInt(var))
    {
	rgb[0] = uiColors[GetInt(var)][0] / 255.0;
	rgb[1] = uiColors[GetInt(var)][1] / 255.0;
	rgb[2] = uiColors[GetInt(var)][2] / 255.0;
    }
    else
    {
	ReportError("AddNumbersControls", "Bad color");
	rgb[0] = rgb[1] = rgb[2] = 1.0;
    }
    RGB2HSV(&(hsv[0]), &(hsv[1]), &(hsv[2]), (rgb[0]), (rgb[1]), (rgb[2]));

    /*Make the color wheel*/
    colorWheel = TemplateColorWheel(VisNumbersTemplate, "Text Color");
    var = NewRealArray(1, 2L);
    CArray2Array(var, hsv);
    SetValue(colorWheel, var);
    SetVar(colorWheel, PARENT, panelContents);
    SetVar(colorWheel, REPOBJ, object);
    PrefixList(panelContents, colorWheel);
    SetMethod(colorWheel, CHANGEDVALUE, ChangeTextColorWheel);
    SetVar(colorWheel, HELPSTRING, NewString("This color wheel controls the \
hue and saturation of the color used to draw the text in the numeric display.  \
The final color is a combination of this hue and saturation and the value, or brightness, \
given by the Value slider."));
    
    /*Make the text box below*/
    textBox = TemplateTextBox(VisNumbersTemplate, "Text Color Label", PLAIN, "Color");
    SetVar(textBox, PARENT, panelContents);
    PrefixList(panelContents, textBox);
    SetTextAlign(textBox, CENTERALIGN);

    /*Make the brightness slider*/
    slider = TemplateSlider(VisNumbersTemplate, "Text Color Value", PLAIN);
    SetVar(slider, PARENT, panelContents);
    PrefixList(panelContents, slider);
    SetSliderRange(slider, 1.0, 0.0, 0.0);
    SetSliderValue(slider, hsv[2]);
    SetVar(slider, REPOBJ, object);
    SetMethod(slider, CHANGEDVALUE, ChangeTextColorSlider);
    SetVar(slider, HELPSTRING, NewString("This slider controls the \
value, or brightness, of the color used to draw the text in the numeric display.  \
The final color is a combination of this value and the hue and saturation \
given by the Color color wheel."));

    /*Make the text box below*/
    textBox = TemplateTextBox(VisNumbersTemplate, "Text Value Label", PLAIN, "Value");
    SetVar(textBox, PARENT, panelContents);
    PrefixList(panelContents, textBox);
    SetTextAlign(textBox, CENTERALIGN);

    /*Cross link the slider and color wheel*/
    SetVar(colorWheel, SLIDER, slider);
    SetVar(slider, COLORWHEEL, colorWheel);

    /*Make the background controls*/
    titleBox = TemplateTitleBox(VisNumbersTemplate, "Background");
    SetVar(titleBox, PARENT, panelContents);
    PrefixList(panelContents, titleBox);

    /*Get the color for priming the controls*/
    MakeVar(object, BACKGROUND);
    var = GetVar(object, BACKGROUND);
    if (var && IsArray(var) && RANK(var) == 1 && DIMS(var)[0] == 3)
    {
	Array2CArray(rgb, var);
	hasBackground = true;
    }
    else if (var && IsInt(var))
    {
	rgb[0] = uiColors[GetInt(var)][0] / 255.0;
	rgb[1] = uiColors[GetInt(var)][1] / 255.0;
	rgb[2] = uiColors[GetInt(var)][2] / 255.0;
	hasBackground = true;
    }
    else
    {
	rgb[0] = rgb[1] = rgb[2] = 0.5;
	hasBackground = false;
    }
    RGB2HSV(&(hsv[0]), &(hsv[1]), &(hsv[2]), (rgb[0]), (rgb[1]), (rgb[2]));

    /*Make the color wheel*/
    colorWheel = TemplateColorWheel(VisNumbersTemplate, "Background Color");
    var = NewRealArray(1, 2L);
    CArray2Array(var, hsv);
    SetValue(colorWheel, var);
    SetVar(colorWheel, PARENT, panelContents);
    SetVar(colorWheel, REPOBJ, object);
    PrefixList(panelContents, colorWheel);
    SetMethod(colorWheel, CHANGEDVALUE, ChangeBackgroundColorWheel);
    SetVar(colorWheel, HELPSTRING, NewString("This color wheel controls the \
hue and saturation of the color used to draw the background of the numeric display.  \
The final color is a combination of this hue and saturation and the value, or brightness, \
given by the Value slider."));
    
    /*Make the text box below*/
    textBox = TemplateTextBox(VisNumbersTemplate, "Background Color Label", PLAIN, "Color");
    SetVar(textBox, PARENT, panelContents);
    PrefixList(panelContents, textBox);
    SetTextAlign(textBox, CENTERALIGN);

    /*Make the brightness slider*/
    slider = TemplateSlider(VisNumbersTemplate, "Background Value", PLAIN);
    SetVar(slider, PARENT, panelContents);
    PrefixList(panelContents, slider);
    SetSliderRange(slider, 1.0, 0.0, 0.0);
    SetSliderValue(slider, hsv[2]);
    SetVar(slider, REPOBJ, object);
    SetMethod(slider, CHANGEDVALUE, ChangeBackgroundColorSlider);
    SetVar(slider, HELPSTRING, NewString("This slider controls the \
value, or brightness, of the color used to draw the background of the numeric display.  \
The final color is a combination of this value and the hue and saturation \
given by the Color color wheel."));

    /*Make the text box below*/
    textBox = TemplateTextBox(VisNumbersTemplate, "Background Value Label", PLAIN, "Value");
    SetVar(textBox, PARENT, panelContents);
    PrefixList(panelContents, textBox);
    SetTextAlign(textBox, CENTERALIGN);

    /*Cross link the slider and color wheel*/
    SetVar(colorWheel, SLIDER, slider);
    SetVar(slider, COLORWHEEL, colorWheel);

    /*Make the check box*/
    checkBox = TemplateCheckBox(VisNumbersTemplate, "No background", hasBackground ? false : true);
    SetVar(checkBox, PARENT, panelContents);
    SetVar(checkBox, REPOBJ, object);
    SetVar(checkBox, SLIDER, slider);
    SetVar(checkBox, COLORWHEEL, colorWheel);
    PrefixList(panelContents, checkBox);
    SetMethod(checkBox, CHANGEDVALUE, ChangeNoBackground);
    SetVar(checkBox, HELPSTRING, NewString("This checkbox controls whether \
a background is shown.  If it is selected, no background is shown, and the \
objects behind can be seen."));

    /*Link the checkbox to the slider and color wheel*/
    SetVar(colorWheel, CHECKBOX, checkBox);
    SetVar(slider, CHECKBOX, checkBox);

    /*Create the format text box*/
    textBox = TemplateTextBox(VisNumbersTemplate, "Format:", PLAIN, "Format:");
    PrefixList(panelContents, textBox);
    SetVar(textBox, PARENT, panelContents);

    /*Create the enter format text box*/
    MakeVar(object, FORMAT);
    var = GetVar(object, FORMAT);
    textBox = TemplateTextBox(VisNumbersTemplate, "Format Text",
	EDITABLE + WITH_PIT + ONE_LINE, 
	var ? GetString(var): "");
    PrefixList(panelContents, textBox);
    SetVar(textBox, PARENT, panelContents);
    SetVar(textBox, REPOBJ, object);
    SetMethod(textBox, CHANGEDVALUE, ChangeNumberFormat);
    SetVar(textBox, HELPSTRING, NewString(
	"This text box contains the format used to print the numeric value \
in the field.  It works very much like the UNIX function printf, except that \
all conversions in the field refer to the same number."));
    

    return ObjTrue;
}

static ObjPtr NumbersInit(numbers)
ObjPtr numbers;
/*Initializes a numbers object*/
{
    ObjPtr repObj, var;

    /*Set the format to the dataset name*/
    repObj = GetVar(numbers, NUMBERSFIELD);
    if (repObj)
    {
	ObjPtr ds;
	ds = repObj;
	while (repObj = GetVar(ds, MAINDATASET))
	{
	    ds = repObj;
	}
	MakeVar(ds, NAME);
	var = GetVar(ds, NAME);
	if (var)
	{
	    sprintf(tempStr, "%s=%%g", GetString(var));
	    SetVar(numbers, FORMAT, NewString(tempStr));
	}

	if (0 == (GetDatasetInfo(repObj) &  DS_HASFORM))
	{
	    SetVar(numbers, ABORTCONTROLS, ObjTrue);
	}
    }

    return ObjTrue;
}

static ObjPtr SetNumbersMainDataset(visObj, dataSet)
ObjPtr visObj, dataSet;
/*Sets the main data set of visObj to dataSet*/
{
    SetVar(visObj, MAINDATASET, dataSet);
    SetVar(visObj, NUMBERSFIELD, dataSet);
    return ObjTrue;
}

static ObjPtr MakeReadoutValue(readout)
ObjPtr readout;
/*Makes the VALUE of a readout*/
{
    ObjPtr var, format, repObj;
    real value;
    char s[400];

    repObj = GetObjectVar("MakeReadoutValue", readout, REPOBJ);
    if (!repObj)
    {
	return ObjFalse;
    }

    MakeVar(repObj, VALUE);
    var = GetVar(repObj, VALUE);
    if (!var)
    {
	value = 0.0;
    }
    else
    {
	value = GetReal(var);
    }

    MakeVar(readout, FORMAT);
    format = GetVar(readout, FORMAT);
    if (format)
    {
	PrintClock(s, GetString(format), value);
    }
    else
    {
        sprintf(s, "%#.2f", time);
    }

    SetVar(readout, VALUE, NewString(s));

    return ObjTrue;
}

static ObjPtr MakeNumbersReadoutAppearance(readout)
ObjPtr readout;
/*Dummy make for numbers readout appearance*/
{
    SetVar(readout, APPEARANCE, ObjTrue);
    ImInvalid(readout);
    return ObjTrue;
}

static ObjPtr MakeNumbersReadoutColor(readout)
ObjPtr readout;
/*Makes the COLOR of a numbers readout*/
{
    ObjPtr repObj;
    repObj = GetVar(readout, REPOBJ);
    if (repObj)
    {
	SetVar(readout, COLOR, GetVar(repObj, COLOR));
    }
    return ObjTrue;
}

static ObjPtr MakeNumbersReadoutBackground(readout)
ObjPtr readout;
/*Makes the BACKGROUND of a numbers readout*/
{
    ObjPtr repObj;
    repObj = GetVar(readout, REPOBJ);
    if (repObj)
    {
	SetVar(readout, BACKGROUND, GetVar(repObj, BACKGROUND));
    }
    return ObjTrue;
}

static ObjPtr MakeNumbersReadoutFormat(readout)
ObjPtr readout;
/*Makes the FORMAT of a numbers readout*/
{
    ObjPtr repObj;
    repObj = GetVar(readout, REPOBJ);
    if (repObj)
    {
	SetVar(readout, FORMAT, GetVar(repObj, FORMAT));
    }
    return ObjTrue;
}

#ifdef PROTO
static ObjPtr NewNumericReadout(int left, int right, int bottom, int top, char *name, ObjPtr space)
#else
static ObjPtr NewNumericReadout(left, right, bottom, top, name, space)
int left, right, bottom, top;
char *name;
ObjPtr space;
/*Returns a new numeric readout*/
#endif
{
    ObjPtr readout;
    readout = NewTextBox(left, right, bottom, top, ADJUSTABLE, name, "");
#if 0
    SetMethod(readout, DELETEICON, DeleteClockReadout);
#endif
    DeclareDependency(readout, VALUE, FORMAT);
    SetVar(readout, SPACE, space);
    SetVar(readout, REPOBJONLY, ObjTrue);

    DeclareIndirectDependency(readout, VALUE, SPACE, TIME);
    DeclareIndirectDependency(readout, VALUE, REPOBJ, VALUE);

#if 0
    SetMethod(clockThere, NEWCTLWINDOW, ShowClockDisplayControls);
#endif
    SetMethod(readout, VALUE, MakeReadoutValue);

    SetVar(readout, HELPSTRING, NewString("This numeric readout displays \
a single scalar value from a dataset.  The display format is controlled by the Format \
text box in the readout's control panel.\n"));
    DeclareIndirectDependency(readout, APPEARANCE, REPOBJ, SELECTED);
    DeclareDependency(readout, APPEARANCE, COLOR);
    DeclareDependency(readout, APPEARANCE, BACKGROUND);
    DeclareIndirectDependency(readout, APPEARANCE, REPOBJ, SELECTED);
    SetMethod(readout, APPEARANCE, MakeNumbersReadoutAppearance);

    DeclareIndirectDependency(readout, COLOR, REPOBJ, COLOR);
    SetMethod(readout, COLOR, MakeNumbersReadoutColor);

    DeclareIndirectDependency(readout, FORMAT, REPOBJ, FORMAT);
    SetMethod(readout, FORMAT, MakeNumbersReadoutFormat);

    DeclareIndirectDependency(readout, BACKGROUND, REPOBJ, BACKGROUND);
    SetMethod(readout, BACKGROUND, MakeNumbersReadoutBackground);

    return readout;
}

int nNumericReadouts = 0;

static ObjPtr DroppedNumbersInSpace(numbers, space)
ObjPtr numbers, space;
/*Called when a numbers object is dropped in a space*/
{
    ObjPtr frontPanel;
    ObjPtr screenObject;
    char name[256];
    ObjPtr var;

    frontPanel = GetVar(space, FRONTPANEL);
    if (!frontPanel)
    {
	return ObjFalse;
    }

    sprintf(name, "Numeric readout text %d", ++nNumericReadouts);

    screenObject = NewNumericReadout(20, 380, 20, 80, name, space);
    SetMethod(screenObject, PUSHTOBOTTOM, PushDrawingToBottom);
    SetMethod(screenObject, BRINGTOTOP, BringDrawingToTop);
    SetMethod(screenObject, MOVETOBACKPANEL, MoveDrawingToBackPanel);
    SetMethod(screenObject, MOVETOFRONTPANEL, MoveDrawingToFrontPanel);

    SetVar(screenObject, REPOBJ, numbers);
    SetTextColor(screenObject, NewInt(UIWHITE));
    ImInvalid(screenObject);
    SetTextFont(screenObject, ANNOTFONT);
    SetTextSize(screenObject, ANNOTFONTSIZE);
    SetVar(screenObject, STICKINESS, NewInt(FLOATINGLEFT + FLOATINGRIGHT + FLOATINGTOP + FLOATINGBOTTOM));
    PrefixList(GetVar(frontPanel, CONTENTS), screenObject);
    SetVar(screenObject, PARENT, frontPanel);
    SetVar(numbers, READOUT, screenObject);

    return ObjTrue;
}

static ObjPtr MakeNumbersValue(readout)
ObjPtr readout;
/*Makes a readout's value*/
{
    ObjPtr value;
    ObjPtr field;
    long dummy;
    real sample;

    field = GetVar(readout, NUMBERSFIELD);
    if (!field)
    {
	return ObjFalse;
    }
    SetCurField(FIELD1, field);
    sample = SelectFieldScalar(FIELD1, &dummy);
    SetVar(readout, VALUE, NewReal(sample));
    return ObjTrue;
}

void InitNumbers()
/*Initializes numbers visualization object*/
{
    ObjPtr icon;

    /*Class for a numberic display*/
    visNumbers = NewObject(visLines, 0);
    AddToReferenceList(visNumbers);
    SetVar(visNumbers, NAME, NewString("Number"));
    SetVar(visNumbers, COLOR, NewInt(UIWHITE));
    SetMethod(visNumbers, INITIALIZE, NumbersInit);
    SetVar(visNumbers, DEFAULTICON, icon = NewObject(visIcon, 0));
    SetVar(icon, WHICHICON, NewInt(ICONANNOTATION));
    SetVar(icon, NAME, NewString("Number"));
    SetVar(icon, HELPSTRING,
	NewString("This icon represents a numberic value display object.  \
This object can show the numeric value of any single value in a scalar dataset."));

    SetMethod(visNumbers, SETMAINDATASET, SetNumbersMainDataset);

    SetMethod(visNumbers, ADDCONTROLS, AddNumbersControls);
    icon = NewIcon(0, 0, ICONANNOTATION, "Number");
    SetVar(icon, HELPSTRING,
	NewString("Click on this icon to see a panel of controls for the numeric display."));
    SetVar(visNumbers, CONTROLICON, icon);
    SetMethod(visNumbers, DROPPEDINSPACE, DroppedNumbersInSpace);
    DeclareIndirectDependency(visNumbers, VALUE, NUMBERSFIELD, CURDATA);
    SetMethod(visNumbers, VALUE, MakeNumbersValue);

    DefineVisMapping(DS_HASFIELD | DS_HASFORM | DS_UNSTRUCTURED, 0, -1, 1, visNumbers);
    DefineVisMapping(DS_HASFIELD | DS_UNSTRUCTURED, 0, -1, 1, visNumbers);
    DefineVisMapping(DS_HASFIELD | DS_HASFORM, 0, -1, 1, visNumbers);
    DefineVisMapping(DS_HASFIELD, 0, -1, 1, visNumbers);
}

void KillNumbers()
/*Kills sticks visualization*/
{
    DeleteThing(visNumbers);
}
