<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE X3D PUBLIC "ISO//Web3D//DTD X3D 3.0//EN" "http://www.web3d.org/specifications/x3d-3.0.dtd">
<X3D profile='Immersive' version='3.0 xmlns:xsd='http://www.w3.org/2001/XMLSchema-instance' xsd:noNamespaceSchemaLocation =' http://www.web3d.org/specifications/x3d-3.0.xsd '>
<head>
<meta name='titlecontent='SliderIntegerPrototype.x3d'/>
<meta name='descriptioncontent='A Slider prototype enabling mouse input where integer output values are needed. Size, min/max values and color are defined by the author.'/>
<meta name='creatorcontent='Mike Hunsberger, Jane Wu'/>
<meta name='createdcontent='3 August 2001'/>
<meta name='modifiedcontent='28 February 2010'/>
<meta name='subjectcontent='animation slider'/>
<meta name='identifiercontent=' https://savage.nps.edu/Savage/Tools/Animation/SliderIntegerPrototype.x3d '/>
<meta name='generatorcontent='X3D-Edit 3.2, https://savage.nps.edu/X3D-Edit'/>
<meta name='licensecontent=' ../../license.html'/>
</head>
<!-- -->
<Scene>
<ProtoDeclare name='SliderIntegerappinfo='Slider user-interface widget that produces integer output values'>
<ProtoInterface>
<field name='layoutDirectiontype='SFStringvalue='verticalaccessType='initializeOnly'
 appinfo='Allowed values: vertical, horizontal'/>

<field name='heighttype='SFFloatvalue='1.0accessType='initializeOnly'
 appinfo='default value 1.0'/>

<field name='radiustype='SFFloatvalue='0.1accessType='initializeOnly'
 appinfo='default value 0.1'/>

<field name='barRadiustype='SFFloatvalue='0.02accessType='initializeOnly'
 appinfo='default value 0.02'/>

<field name='sliderBarColortype='SFColorvalue='.8 .4 .8accessType='initializeOnly'
 appinfo='default value .8 .4 .8'/>

<field name='sliderBallColortype='SFColorvalue='.3 .4 .8accessType='initializeOnly'
 appinfo='default value .3 .4 .8'/>

<field name='sliderEndColortype='SFColorvalue='.2 .3 .9accessType='initializeOnly'
 appinfo='default value .2 .3 .9'/>

<field name='mintype='SFInt32value='0accessType='initializeOnly'
 appinfo='default value 0'/>

<field name='maxtype='SFInt32value='10accessType='initializeOnly'
 appinfo='default value 10'/>

<field name='valuetype='SFInt32value='0accessType='initializeOnly'
 appinfo='default value 0'/>

<field name='setMintype='SFInt32accessType='inputOnly'
 appinfo='set minimum value for slider bar'/>

<field name='setMaxtype='SFInt32accessType='inputOnly'
 appinfo='set maximum value for slider bar'/>

<field name='setValuetype='SFInt32accessType='inputOnly'
 appinfo='set value for slider bar'/>

<field name='valueChangedtype='SFInt32accessType='outputOnly'
 appinfo='output value for slider bar'/>

<field name='traceEnabledtype='SFBoolvalue='falseaccessType='initializeOnly'
 appinfo='Enable/disable console output for troubleshooting'/>
</ProtoInterface>
<ProtoBody>
<Group>
<!-- ROUTE information for LayoutDirectionTransform node:  [from LayoutDirectionScript.directionRotation to set_rotation ] -->
<Transform DEF='LayoutDirectionTransform'>
<Transform DEF='SliderBarTransform'>
<Shape>
<Appearance>
<Material DEF='SliderBarMaterial'>
<IS>
<connect nodeField='diffuseColorprotoField='sliderBarColor'/>
<connect nodeField='emissiveColorprotoField='sliderBarColor'/>
</IS>
</Material>
</Appearance>
<Cylinder DEF='SliderBar'>
<IS>
<connect nodeField='heightprotoField='height'/>
<connect nodeField='radiusprotoField='barRadius'/>
</IS>
</Cylinder>
</Shape>
</Transform>
<!-- ROUTE information for SliderBallTransform node:  [from SliderScript.ballPositionChanged to set_translation ] -->
<Transform DEF='SliderBallTransform'>
<!-- ROUTE information for SliderBallPlaneSensor node:  [from SliderScript.minBallPositionChanged to set_minPosition ] [from SliderScript.maxBallPositionChanged to set_maxPosition ] [from isActive to SliderScript.setDragActive ] [from translation_changed to SliderScript.setBallPosition ] -->
<PlaneSensor DEF='SliderBallPlaneSensordescription='select and drag to change values'/>
<Shape>
<Appearance>
<Material DEF='SliderBallMaterial'>
<IS>
<connect nodeField='diffuseColorprotoField='sliderBallColor'/>
</IS>
</Material>
</Appearance>
<Sphere DEF='SliderBall'>
<IS>
<connect nodeField='radiusprotoField='radius'/>
</IS>
</Sphere>
</Shape>
</Transform>
<!-- ROUTE information for BottomEndTransform node:  [from SliderScript.bottomEndPositionChanged to set_translation ] -->
<Transform DEF='BottomEndTransform'>
<!-- ROUTE information for BottomEndSensor node:  [from isActive to SliderScript.bottomEndTouched ] -->
<TouchSensor DEF='BottomEndSensordescription='touch bottom end to decrement'/>
<Shape DEF='EndShape'>
<Appearance>
<Material DEF='EndMaterial'>
<IS>
<connect nodeField='diffuseColorprotoField='sliderEndColor'/>
</IS>
</Material>
</Appearance>
<Cylinder height='.05radius='.1'/>
</Shape>
<Transform translation='0 -0.1 0'>
<Shape DEF='TransparentEndShape'>
<Appearance>
<Material transparency='1'/>
</Appearance>
<Box size='0.2 0.2 0.01'/>
</Shape>
</Transform>
</Transform>
<!-- ROUTE information for TopEndTransform node:  [from SliderScript.topEndPositionChanged to set_translation ] -->
<Transform DEF='TopEndTransform'>
<!-- ROUTE information for TopEndSensor node:  [from isActive to SliderScript.topEndTouched ] -->
<TouchSensor DEF='TopEndSensordescription='touch top end to increment'/>
<Shape USE='EndShape'/>
<Transform translation='0 0.1 0'>
<Shape USE='TransparentEndShape'/>
</Transform>
</Transform>
<!-- ROUTE information for SliderScript node:  [from SliderBallPlaneSensor.isActive to setDragActive ] [from SliderBallPlaneSensor.translation_changed to setBallPosition ] [from BottomEndSensor.isActive to bottomEndTouched ] [from TopEndSensor.isActive to topEndTouched ] [from minBallPositionChanged to SliderBallPlaneSensor.set_minPosition ] [from maxBallPositionChanged to SliderBallPlaneSensor.set_maxPosition ] [from bottomEndPositionChanged to BottomEndTransform.set_translation ] [from topEndPositionChanged to TopEndTransform.set_translation ] [from ballPositionChanged to SliderBallTransform.set_translation ] -->
<Script DEF='SliderScript'>
<field name='heighttype='SFFloataccessType='initializeOnly'/>
<field name='radiustype='SFFloataccessType='initializeOnly'/>
<field name='mintype='SFInt32accessType='initializeOnly'/>
<field name='maxtype='SFInt32accessType='initializeOnly'/>
<field name='valuetype='SFInt32accessType='initializeOnly'/>
<field name='dragActivetype='SFBoolvalue='falseaccessType='initializeOnly'/>
<field name='lastBallPositiontype='SFVec3fvalue='0 0 0accessType='initializeOnly'/>
<field name='beginPositiontype='SFVec3fvalue='0 0 0accessType='initializeOnly'/>
<field name='endPositiontype='SFVec3fvalue='0 0 0accessType='initializeOnly'/>
<field name='incrementIntervaltype='SFFloatvalue='1accessType='initializeOnly'/>
<field name='setMintype='SFInt32accessType='inputOnly'/>
<field name='setMaxtype='SFInt32accessType='inputOnly'/>
<field name='setValuetype='SFInt32accessType='inputOnly'/>
<field name='valueChangedtype='SFInt32accessType='outputOnly'/>
<field name='bottomEndTouchedtype='SFBoolaccessType='inputOnly'/>
<field name='topEndTouchedtype='SFBoolaccessType='inputOnly'/>
<field name='setBallPositiontype='SFVec3faccessType='inputOnly'/>
<field name='setDragActivetype='SFBoolaccessType='inputOnly'/>
<field name='bottomEndPositionChangedtype='SFVec3faccessType='outputOnly'/>
<field name='topEndPositionChangedtype='SFVec3faccessType='outputOnly'/>
<field name='ballPositionChangedtype='SFVec3faccessType='outputOnly'/>
<field name='minBallPositionChangedtype='SFVec2faccessType='outputOnly'/>
<field name='maxBallPositionChangedtype='SFVec2faccessType='outputOnly'/>
<field name='traceEnabledtype='SFBoolaccessType='initializeOnly'/>
<IS>
<connect nodeField='heightprotoField='height'/>
<connect nodeField='radiusprotoField='radius'/>
<connect nodeField='minprotoField='min'/>
<connect nodeField='maxprotoField='max'/>
<connect nodeField='valueprotoField='value'/>
<connect nodeField='setMinprotoField='setMin'/>
<connect nodeField='setMaxprotoField='setMax'/>
<connect nodeField='setValueprotoField='setValue'/>
<connect nodeField='valueChangedprotoField='valueChanged'/>
<connect nodeField='traceEnabledprotoField='traceEnabled'/>
</IS>
<![CDATA[
              
ecmascript:
function initialize()
{
        tracePrint('initialize() commenced...');

	beginPosition = new SFVec3f(0, (height/2) * (-1) + radius, 0);
	endPosition   = new SFVec3f(0, (height/2) - radius, 0);
	tracePrint('beginPosition=' + beginPosition.toString() + ', endPosition=' + endPosition.toString());
	incrementInterval = (height - (2 * radius)) / (max - min);
	tracePrint('incrementInterval=' + incrementInterval.toString());

	bottomEndPositionChanged = new SFVec3f(0, (height/2) * (-1), 0);
	topEndPositionChanged = new SFVec3f(0, (height/2), 0);
	tracePrint('bottomEndPositionChanged=' + bottomEndPositionChanged.toString() + ', topEndPositionChanged=' + topEndPositionChanged.toString());

        minBallPositionChanged = new SFVec2f(0, bottomEndPositionChanged.y + radius);
	maxBallPositionChanged = new SFVec2f(0, topEndPositionChanged.y - radius);
	tracePrint('minBallPositionChanged=' + minBallPositionChanged.toString() + ', maxBallPositionChanged=' + maxBallPositionChanged.toString());

	ballPositionChanged = new SFVec3f(0, beginPosition.y + (incrementInterval * (value - min)), 0);
	lastBallPosition = ballPositionChanged;

	if (value < min) value = min;
	if (value > max) value = max;

	valueChanged = value;
	tracePrint('value=' + value.toString());
	tracePrint('...initialize() complete');
}

function setDragActive(inputValue, timeStamp)
{
	dragActive = inputValue;
}

function setMin(inputValue, timeStamp)
{
	min = inputValue;
	if (value < min) value = min;

	incrementInterval = (height - (2 * radius)) / (max - min);
	tracePrint('incrementInterval=' + incrementInterval.toString());

	ballPositionChanged = new SFVec3f(0, beginPosition.y + (incrementInterval * (value - min)), 0);
	lastBallPosition = ballPositionChanged;

	valueChanged = value;
	tracePrint('min=' + min + ', valueChanged=' + valueChanged);
}

function setMax(inputValue, timeStamp)
{
	max = inputValue;
	if (value > max) value = max;

	incrementInterval = (height - (2 * radius)) / (max - min);

	ballPositionChanged = new SFVec3f(0, beginPosition.y + (incrementInterval * (value - min)), 0);
	lastBallPosition = ballPositionChanged;

	valueChanged = value;
	tracePrint('max=' + max + ', valueChanged=' + valueChanged);
}

function setValue(inputValue, timeStamp)
{
	if (inputValue <= min)
	{
		valueChanged = value = min;
		ballPositionChanged = beginPosition;
		lastBallPosition = ballPositionChanged;
	}
	else if (inputValue >= max)
	{
		valueChanged = value = max;
		ballPositionChanged = endPosition;
		lastBallPosition = ballPositionChanged;
	}
	else
	{
		if (inputValue > value) //getting bigger
		{
			ballPositionChanged = new SFVec3f(0, lastBallPosition.y + (incrementInterval * (inputValue - value)), 0);
			lastBallPosition = ballPositionChanged;
		}
		else if (inputValue < value) //getting smaller
		{
			ballPositionChanged = new SFVec3f(0, lastBallPosition.y - (incrementInterval * (value - inputValue)), 0);
			lastBallPosition = ballPositionChanged;
		}
		valueChanged = value = inputValue;
	}
}

function bottomEndTouched(inputValue, timeStamp)
{
	tracePrint('bottomEndTouched(' + inputValue.toString() + ')');
	if (inputValue == false) return; // ignore deselection

	if (value > min)
	{
		valueChanged = --value;
		ballPositionChanged = new SFVec3f(0, lastBallPosition.y - incrementInterval, 0);
		lastBallPosition = ballPositionChanged;
	}
}

function topEndTouched(inputValue, timeStamp)
{
	tracePrint('topEndTouched(' + inputValue.toString() + ')');
	if (inputValue == false) return; // ignore deselection

	if (value < max)
	{
		valueChanged = ++value;
		ballPositionChanged = new SFVec3f(0, lastBallPosition.y + incrementInterval, 0);
		lastBallPosition = ballPositionChanged;
	}
}

function setBallPosition(inputValue, timeStamp)
{
	tracePrint('setBallPosition(' + inputValue.toString() + '), dragActive=' + dragActive);
//	if (!dragActive)
//		return;

	if (inputValue.y > lastBallPosition.y) // moving upwards
	{
		if (inputValue.y >= (beginPosition.y + (incrementInterval * ((value + 1) - min))))
		{
			if (value == max - 1)
			{
				value = max;
				lastBallPosition = endPosition;
			}
			else
			{
				value = value + 1;
				lastBallPosition = new SFVec3f(0, beginPosition.y + (incrementInterval * (value - min)), 0);
			}
			valueChanged = value;
			ballPositionChanged = lastBallPosition;
		}
	}
	else if (inputValue.y < lastBallPosition.y) // moving downwards
	{
		if (inputValue.y <= (endPosition.y - (incrementInterval * (max - (value - 1)))))
		{
			if (value == (min + 1))
			{
				value = min;
				lastBallPosition = beginPosition;
			}
			else
			{
				value = value - 1;
				lastBallPosition = new SFVec3f(0, endPosition.y - (incrementInterval * (max - value)), 0);
			}
			valueChanged = value;
			ballPositionChanged = lastBallPosition;
		}
	}
}

function tracePrint (text)
{
	if (traceEnabled) Browser.print ('[SliderFloat SliderScript] ' + text + '\n');
}

            
]]>
</Script>
<ROUTE fromNode='SliderBallPlaneSensorfromField='isActivetoNode='SliderScripttoField='setDragActive'/>
<ROUTE fromNode='SliderBallPlaneSensorfromField='translation_changedtoNode='SliderScripttoField='setBallPosition'/>
<ROUTE fromNode='BottomEndSensorfromField='isActivetoNode='SliderScripttoField='bottomEndTouched'/>
<ROUTE fromNode='TopEndSensorfromField='isActivetoNode='SliderScripttoField='topEndTouched'/>
<ROUTE fromNode='SliderScriptfromField='minBallPositionChangedtoNode='SliderBallPlaneSensortoField='set_minPosition'/>
<ROUTE fromNode='SliderScriptfromField='maxBallPositionChangedtoNode='SliderBallPlaneSensortoField='set_maxPosition'/>
<ROUTE fromNode='SliderScriptfromField='bottomEndPositionChangedtoNode='BottomEndTransformtoField='set_translation'/>
<ROUTE fromNode='SliderScriptfromField='topEndPositionChangedtoNode='TopEndTransformtoField='set_translation'/>
<ROUTE fromNode='SliderScriptfromField='ballPositionChangedtoNode='SliderBallTransformtoField='set_translation'/>
</Transform>
<!-- ROUTE information for LayoutDirectionScript node:  [from directionRotation to LayoutDirectionTransform.set_rotation ] -->
<Script DEF='LayoutDirectionScript'>
<field name='directiontype='SFStringaccessType='initializeOnly'/>
<field name='directionRotationtype='SFRotationaccessType='outputOnly'/>
<field name='traceEnabledtype='SFBoolaccessType='initializeOnly'/>
<IS>
<connect nodeField='directionprotoField='layoutDirection'/>
<connect nodeField='traceEnabledprotoField='traceEnabled'/>
</IS>
<![CDATA[
            
ecmascript:

function initialize ()
{
    if      ((direction=='vertical') || (direction=='Vertical') || (direction=='VERTICAL'))
    {
        directionRotation = new SFRotation(0, 0, 1, 0);
    }
    else if ((direction=='horizontal') || (direction=='Horizontal') || (direction=='HORIZONTAL'))
    {
        directionRotation = new SFRotation(0, 0, 1, -1.57);
    }
    else
    {
        Browser.print ('[SliderFloat LayoutDirectionScript] unrecognized direction: ' + direction + ', using vertical\n');
        directionRotation = new SFRotation(0, 0, 1, 0);
    }
    tracePrint ('direction=' + direction);
}
function tracePrint (text)
{
	if (traceEnabled) Browser.print ('[SliderFloat LayoutDirectionScript] ' + text + '\n');
}

          
]]>
</Script>
<ROUTE fromNode='LayoutDirectionScriptfromField='directionRotationtoNode='LayoutDirectionTransformtoField='set_rotation'/>
</Group>
</ProtoBody>
</ProtoDeclare>
<Anchor description='SliderIntegerExampleparameter='"target=_blank"'
  url=' "SliderIntegerExample.x3d" "https://savage.nps.edu/Savage/Tools/Animation/SliderIntegerExample.x3d" "SliderIntegerExample.wrl" "https://savage.nps.edu/Savage/Tools/Animation/SliderIntegerExample.wrl" '>
<Shape>
<Appearance>
<Material diffuseColor='0 1 1emissiveColor='0 1 1'/>
</Appearance>
<Text string='"SliderIntegerPrototype is a" "Prototype definition file." "" "To see an example scene" "using this new node" "click this text and view" "SliderIntegerExample.x3d"'>
<FontStyle justify='"MIDDLE" "MIDDLE"size='0.8'/>
</Text>
</Shape>
</Anchor>
</Scene>
</X3D>
<!--

Index for ProtoDeclare definition : SliderInteger

Index for DEF nodes : BottomEndSensor, BottomEndTransform, EndMaterial, EndShape, LayoutDirectionScript, LayoutDirectionTransform, SliderBall, SliderBallMaterial, SliderBallPlaneSensor, SliderBallTransform, SliderBar, SliderBarMaterial, SliderBarTransform, SliderScript, TopEndSensor, TopEndTransform, TransparentEndShape
-->

<!-- Color key: <X3dNode DEF='idName' field='value'/> matches <XmlElement DEF='idName' attribute='value'/>
(Light blue background: behavior node) (Grey background: inserted documentation) (Magenta background: X3D Extensibility)
    <Prototype name='ProtoName'> <field name='fieldName'/> </Prototype> -->

<!-- Additional help information about X3D scenes: X3D Resources, X3D Scene Authoring Hints and X3D Tooltips -->