Browse Source

SceneWindows with ScrollBars!

SceneWindows can now activate scrollbars to allow the user to easily move the camera around a scene. Although this might not be useful in every circumstance, it will certainly be useful in sprite based menus and editors. The AssetAdmin makes use of this by allowing the user to easily zoom in and scroll when looking at an asset by using the mouse wheel and scroll bars.
Peter Robinson 4 years ago
parent
commit
6ee61d916b

+ 15 - 5
editor/AssetAdmin/AssetAdmin.cs

@@ -132,24 +132,34 @@ function AssetAdmin::buildAssetWindow(%this)
 		minExtent = "0 0";
 		minExtent = "0 0";
 		cameraPosition = "0 0";
 		cameraPosition = "0 0";
 		cameraSize = "175 111";
 		cameraSize = "175 111";
-		useWindowInputEvents = false;
+		useWindowInputEvents = true;
 		useObjectInputEvents = true;
 		useObjectInputEvents = true;
+		constantThumbHeight = false;
+		scrollBarThickness = 14;
+		 showArrowButtons = false;
 	};
 	};
+	ThemeManager.setProfile(%this.assetWindow, "thumbProfile", ThumbProfile);
+	ThemeManager.setProfile(%this.assetWindow, "trackProfile", TrackProfile);
+	ThemeManager.setProfile(%this.assetWindow, "scrollArrowProfile", ArrowProfile);
+
 	%this.assetWindow.setScene(%this.assetScene);
 	%this.assetWindow.setScene(%this.assetScene);
+	%this.assetWindow.setViewLimitOn("-87.5 -55.5 87.5 55.5");
+	%this.assetWindow.setShowScrollBar(true);
+	%this.assetWindow.setMouseWheelScrolls(false);
 
 
 	return %this.assetWindow;
 	return %this.assetWindow;
 }
 }
 
 
 function AssetAdmin::buildAudioPlayButton(%this)
 function AssetAdmin::buildAudioPlayButton(%this)
 {
 {
-	%container = new GuiControl()
+	%this.audioPlayButtonContainer = new GuiControl()
 	{
 	{
 		position = "0 0";
 		position = "0 0";
 		extent = "700 444";
 		extent = "700 444";
 		HorizSizing="width";
 		HorizSizing="width";
 		VertSizing="height";
 		VertSizing="height";
 	};
 	};
-	ThemeManager.setProfile(%container, "emptyProfile");
+	ThemeManager.setProfile(%this.audioPlayButtonContainer, "emptyProfile");
 
 
 	%this.audioPlayButton = new GuiButtonCtrl()
 	%this.audioPlayButton = new GuiButtonCtrl()
 	{
 	{
@@ -161,9 +171,9 @@ function AssetAdmin::buildAudioPlayButton(%this)
 		Text = "Play";
 		Text = "Play";
 	};
 	};
 	ThemeManager.setProfile(%this.audioPlayButton, "buttonProfile");
 	ThemeManager.setProfile(%this.audioPlayButton, "buttonProfile");
-	%container.add(%this.audioPlayButton);
+	%this.audioPlayButtonContainer.add(%this.audioPlayButton);
 
 
-	return %container;
+	return %this.audioPlayButtonContainer;
 }
 }
 
 
 function AssetAdmin::destroy(%this)
 function AssetAdmin::destroy(%this)

+ 1 - 1
editor/AssetAdmin/AssetDictionaryButton.cs

@@ -140,7 +140,7 @@ function AssetDictionaryButton::onClick(%this)
 		ThemeManager.setProfile(%this, "itemSelectedProfile");
 		ThemeManager.setProfile(%this, "itemSelectedProfile");
 	}
 	}
 
 
-	AssetAdmin.audioPlayButton.setVisible(false);
+	AssetAdmin.audioPlayButtonContainer.setVisible(false);
 	AssetAdmin.AssetWindow.setVisible(true);
 	AssetAdmin.AssetWindow.setVisible(true);
 
 
 	if(isObject(%this.AnimationAsset) && %this.AnimationAssetID !$= "")
 	if(isObject(%this.AnimationAsset) && %this.AnimationAssetID !$= "")

+ 38 - 1
editor/AssetAdmin/AssetWindow.cs

@@ -29,6 +29,7 @@ function AssetWindow::displayImageAsset(%this, %imageAsset, %assetID)
 {
 {
 	AssetAdmin.AssetScene.clear(true);
 	AssetAdmin.AssetScene.clear(true);
 
 
+	%this.setCameraPosition("0 0");
 	%this.setCameraZoom(1);
 	%this.setCameraZoom(1);
 	if(!%imageAsset.getExplicitMode() && %imageAsset.getFrameCount() == 1)
 	if(!%imageAsset.getExplicitMode() && %imageAsset.getFrameCount() == 1)
 	{
 	{
@@ -89,6 +90,7 @@ function AssetWindow::displayAnimationAsset(%this, %imageAsset, %animationAsset,
 {
 {
 	AssetAdmin.AssetScene.clear(true);
 	AssetAdmin.AssetScene.clear(true);
 
 
+	%this.setCameraPosition("0 0");
 	%this.setCameraZoom(1);
 	%this.setCameraZoom(1);
 	%size = %this.getWorldSize(%imageAsset.getFrameSize(0));
 	%size = %this.getWorldSize(%imageAsset.getFrameSize(0));
 	new Sprite()
 	new Sprite()
@@ -107,6 +109,7 @@ function AssetWindow::displayParticleAsset(%this, %particleAsset, %assetID)
 {
 {
 	AssetAdmin.AssetScene.clear(true);
 	AssetAdmin.AssetScene.clear(true);
 
 
+	%this.setCameraPosition("0 0");
 	%this.setCameraZoom(5);
 	%this.setCameraZoom(5);
 	new ParticlePlayer()
 	new ParticlePlayer()
 	{
 	{
@@ -124,6 +127,7 @@ function AssetWindow::displayFontAsset(%this, %fontAsset, %assetID)
 {
 {
 	AssetAdmin.AssetScene.clear(true);
 	AssetAdmin.AssetScene.clear(true);
 
 
+	%this.setCameraPosition("0 0");
 	%this.setCameraZoom(1);
 	%this.setCameraZoom(1);
 	%size = %this.getWorldSize("10 10");
 	%size = %this.getWorldSize("10 10");
 	new TextSprite()
 	new TextSprite()
@@ -148,7 +152,7 @@ function AssetWindow::displayAudioAsset(%this, %audioAsset, %assetID)
 {
 {
 	AssetAdmin.AssetScene.clear(true);
 	AssetAdmin.AssetScene.clear(true);
 
 
-	AssetAdmin.audioPlayButton.setVisible(true);
+	AssetAdmin.audioPlayButtonContainer.setVisible(true);
 	AssetAdmin.AssetWindow.setVisible(false);
 	AssetAdmin.AssetWindow.setVisible(false);
 
 
 	AssetAdmin.audioPlayButton.resetSound();
 	AssetAdmin.audioPlayButton.resetSound();
@@ -214,9 +218,42 @@ function AssetWindow::onExtentChange(%this, %d)
 	}
 	}
 	%area = %topLeft SPC %bottomRight;
 	%area = %topLeft SPC %bottomRight;
 	%this.setCameraArea(%area);
 	%this.setCameraArea(%area);
+	%this.setViewLimitOn(%area);
 
 
 	if(isObject(AssetAdmin.chosenButton))
 	if(isObject(AssetAdmin.chosenButton))
 	{
 	{
 		AssetAdmin.chosenButton.onClick();
 		AssetAdmin.chosenButton.onClick();
 	}
 	}
 }
 }
+
+function AssetWindow::onMouseWheelUp(%this)
+{
+	%zoom = %this.getTargetCameraZoom();
+	if(%zoom > 1)
+	{
+		//prevent gradual rounding errors
+		%zoom = mRound(%zoom);
+	}
+	if(%zoom == 1)
+	{
+		%this.setTargetCameraPosition("0 0");
+	}
+	%this.setTargetCameraZoom(mGetMin(16, %zoom * 2));
+	%this.startCameraMove(0.2);
+}
+
+function AssetWindow::onMouseWheelDown(%this)
+{
+	%zoom = %this.getTargetCameraZoom();
+	if(%zoom > 1)
+	{
+		//prevent gradual rounding errors
+		%zoom = mRound(%zoom);
+	}
+	if(%zoom == 1)
+	{
+		%this.setTargetCameraPosition("0 0");
+	}
+	%this.setTargetCameraZoom(mGetMax(0.0625, %zoom / 2));
+	%this.startCameraMove(0.2);
+}

+ 2 - 0
engine/compilers/VisualStudio 2017/Torque 2D.vcxproj

@@ -617,6 +617,7 @@
     <ClCompile Include="..\..\source\gui\containers\guiExpandCtrl.cc" />
     <ClCompile Include="..\..\source\gui\containers\guiExpandCtrl.cc" />
     <ClCompile Include="..\..\source\gui\containers\guiFrameCtrl.cc" />
     <ClCompile Include="..\..\source\gui\containers\guiFrameCtrl.cc" />
     <ClCompile Include="..\..\source\gui\containers\guiGridCtrl.cc" />
     <ClCompile Include="..\..\source\gui\containers\guiGridCtrl.cc" />
+    <ClCompile Include="..\..\source\gui\containers\guiSceneScrollCtrl.cc" />
     <ClCompile Include="..\..\source\gui\containers\guiTabPageCtrl.cc" />
     <ClCompile Include="..\..\source\gui\containers\guiTabPageCtrl.cc" />
     <ClCompile Include="..\..\source\gui\editor\guiMenuBarCtrl.cc" />
     <ClCompile Include="..\..\source\gui\editor\guiMenuBarCtrl.cc" />
     <ClCompile Include="..\..\source\gui\guiArrayCtrl.cc" />
     <ClCompile Include="..\..\source\gui\guiArrayCtrl.cc" />
@@ -1151,6 +1152,7 @@
     <ClInclude Include="..\..\source\gui\containers\guiGridCtrl.h" />
     <ClInclude Include="..\..\source\gui\containers\guiGridCtrl.h" />
     <ClInclude Include="..\..\source\gui\containers\guiGridCtrl_ScriptBinding.h" />
     <ClInclude Include="..\..\source\gui\containers\guiGridCtrl_ScriptBinding.h" />
     <ClInclude Include="..\..\source\gui\containers\guiPanelCtrl_ScriptBinding.h" />
     <ClInclude Include="..\..\source\gui\containers\guiPanelCtrl_ScriptBinding.h" />
+    <ClInclude Include="..\..\source\gui\containers\guiSceneScrollCtrl.h" />
     <ClInclude Include="..\..\source\gui\containers\guiScrollCtrl_ScriptBinding.h" />
     <ClInclude Include="..\..\source\gui\containers\guiScrollCtrl_ScriptBinding.h" />
     <ClInclude Include="..\..\source\gui\containers\guiTabBookCtrl_ScriptBinding.h" />
     <ClInclude Include="..\..\source\gui\containers\guiTabBookCtrl_ScriptBinding.h" />
     <ClInclude Include="..\..\source\gui\containers\guiTabPageCtrl.h" />
     <ClInclude Include="..\..\source\gui\containers\guiTabPageCtrl.h" />

+ 6 - 0
engine/compilers/VisualStudio 2017/Torque 2D.vcxproj.filters

@@ -1465,6 +1465,9 @@
     <ClCompile Include="..\..\source\gui\editor\guiMenuBarCtrl.cc">
     <ClCompile Include="..\..\source\gui\editor\guiMenuBarCtrl.cc">
       <Filter>gui\editor</Filter>
       <Filter>gui\editor</Filter>
     </ClCompile>
     </ClCompile>
+    <ClCompile Include="..\..\source\gui\containers\guiSceneScrollCtrl.cc">
+      <Filter>gui\containers</Filter>
+    </ClCompile>
   </ItemGroup>
   </ItemGroup>
   <ItemGroup>
   <ItemGroup>
     <ClInclude Include="..\..\source\audio\audio.h">
     <ClInclude Include="..\..\source\audio\audio.h">
@@ -3322,6 +3325,9 @@
     <ClInclude Include="..\..\source\gui\guiTextEditCtrl_ScriptBinding.h">
     <ClInclude Include="..\..\source\gui\guiTextEditCtrl_ScriptBinding.h">
       <Filter>gui</Filter>
       <Filter>gui</Filter>
     </ClInclude>
     </ClInclude>
+    <ClInclude Include="..\..\source\gui\containers\guiSceneScrollCtrl.h">
+      <Filter>gui\containers</Filter>
+    </ClInclude>
   </ItemGroup>
   </ItemGroup>
   <ItemGroup>
   <ItemGroup>
     <ResourceCompile Include="Torque 2D.rc" />
     <ResourceCompile Include="Torque 2D.rc" />

+ 290 - 3
engine/source/2d/gui/SceneWindow.cc

@@ -29,6 +29,7 @@
 #include "2d/sceneobject/SceneObject.h"
 #include "2d/sceneobject/SceneObject.h"
 #include "2d/core/Utility.h"
 #include "2d/core/Utility.h"
 #include "2d/gui/SceneWindow.h"
 #include "2d/gui/SceneWindow.h"
+#include "gui/containers/guiSceneScrollCtrl.h"
 
 
 #ifndef _ASSET_MANAGER_H_
 #ifndef _ASSET_MANAGER_H_
 #include "assets/assetManager.h"
 #include "assets/assetManager.h"
@@ -59,8 +60,8 @@ static StringTableEntry mouseEventRightMouseDraggedName= StringTable->insert("on
 static StringTableEntry mouseEventWheelUpName          = StringTable->insert("onMouseWheelUp");
 static StringTableEntry mouseEventWheelUpName          = StringTable->insert("onMouseWheelUp");
 static StringTableEntry mouseEventWheelDownName        = StringTable->insert("onMouseWheelDown");
 static StringTableEntry mouseEventWheelDownName        = StringTable->insert("onMouseWheelDown");
 
 
-static StringTableEntry mouseEventEnterName            = StringTable->insert("onMouseEnter");
-static StringTableEntry mouseEventLeaveName            = StringTable->insert("onMouseLeave");
+static StringTableEntry mouseEventEnterName            = StringTable->insert("onTouchEnter");
+static StringTableEntry mouseEventLeaveName            = StringTable->insert("onTouchLeave");
 
 
 //-----------------------------------------------------------------------------
 //-----------------------------------------------------------------------------
 
 
@@ -114,7 +115,9 @@ SceneWindow::SceneWindow() :    mpScene(NULL),
                                 mInputEventGroupMaskFilter(MASK_ALL),
                                 mInputEventGroupMaskFilter(MASK_ALL),
                                 mInputEventLayerMaskFilter(MASK_ALL),
                                 mInputEventLayerMaskFilter(MASK_ALL),
                                 mInputEventInvisibleFilter( true ),
                                 mInputEventInvisibleFilter( true ),
-                                mProcessAudioListener(false)
+                                mProcessAudioListener(false),
+								mShowScrollBar(false),
+								mMouseWheelScrolls(false)
 {
 {
     // Set Vector Associations.
     // Set Vector Associations.
     VECTOR_SET_ASSOCIATION( mCameraQueue );
     VECTOR_SET_ASSOCIATION( mCameraQueue );
@@ -124,12 +127,31 @@ SceneWindow::SceneWindow() :    mpScene(NULL),
 
 
     // Turn-on Tick Processing.
     // Turn-on Tick Processing.
     setProcessTicks( true );
     setProcessTicks( true );
+
+	mThumbProfile = NULL;
+	mTrackProfile = NULL;
+	mArrowProfile = NULL;
+
+	mScrollBar = new GuiSceneScrollCtrl(this);
+	mScrollBar->mForceVScrollBar = GuiScrollCtrl::ScrollBarDynamic;
+	mScrollBar->mForceHScrollBar = GuiScrollCtrl::ScrollBarDynamic;
+	mUseConstantHeightThumb = false;
+	mScrollBarThickness = 16;
+	mShowArrowButtons = true;
+
+	mThumbProfile = mScrollBar->mThumbProfile;
+	mThumbProfile->incRefCount();
+	mTrackProfile = mScrollBar->mTrackProfile;
+	mThumbProfile->incRefCount();
+	mArrowProfile = mScrollBar->mArrowProfile;
+	mThumbProfile->incRefCount();
 }
 }
 
 
 //-----------------------------------------------------------------------------
 //-----------------------------------------------------------------------------
 
 
 SceneWindow::~SceneWindow()
 SceneWindow::~SceneWindow()
 {
 {
+	delete mScrollBar;
 }
 }
 
 
 //-----------------------------------------------------------------------------
 //-----------------------------------------------------------------------------
@@ -190,6 +212,124 @@ void SceneWindow::initPersistFields()
     // Background color.
     // Background color.
     addField("UseBackgroundColor", TypeBool, Offset(mUseBackgroundColor, SceneWindow), &writeUseBackgroundColor, "" );
     addField("UseBackgroundColor", TypeBool, Offset(mUseBackgroundColor, SceneWindow), &writeUseBackgroundColor, "" );
     addField("BackgroundColor", TypeColorF, Offset(mBackgroundColor, SceneWindow), &writeBackgroundColor, "" );
     addField("BackgroundColor", TypeColorF, Offset(mBackgroundColor, SceneWindow), &writeBackgroundColor, "" );
+
+	//Standard scroll bar settings
+	addProtectedField("constantThumbHeight", TypeBool, Offset(mUseConstantHeightThumb, GuiScrollCtrl), &setConstantThumbFn, &defaultProtectedGetFn, &writeScrollSettingFn, "");
+	addProtectedField("scrollBarThickness", TypeS32, Offset(mScrollBarThickness, GuiScrollCtrl), &setScrollBarThicknessFn, &defaultProtectedGetFn, &writeScrollSettingFn, "");
+	addProtectedField("showArrowButtons", TypeBool, Offset(mShowArrowButtons, GuiScrollCtrl), &setShowArrowButtonsFn, &defaultProtectedGetFn, &writeScrollSettingFn, "");
+	addProtectedField("thumbProfile", TypeGuiProfile, Offset(mThumbProfile, GuiScrollCtrl), &setThumbProfileFn, &defaultProtectedGetFn, &writeScrollSettingFn, "");
+	addProtectedField("trackProfile", TypeGuiProfile, Offset(mTrackProfile, GuiScrollCtrl), &setTrackProfileFn, &defaultProtectedGetFn, &writeScrollSettingFn, "");
+	addProtectedField("arrowProfile", TypeGuiProfile, Offset(mArrowProfile, GuiScrollCtrl), &setArrowProfileFn, &defaultProtectedGetFn, &writeScrollSettingFn, "");
+}
+
+bool SceneWindow::onWake()
+{
+	if (!Parent::onWake())
+	{
+		return false;
+	}
+
+	if (mThumbProfile != NULL)
+		mThumbProfile->incRefCount();
+
+	if (mTrackProfile != NULL)
+		mTrackProfile->incRefCount();
+
+	if (mArrowProfile != NULL)
+		mArrowProfile->incRefCount();
+
+	if(mShowScrollBar)
+	{
+		mScrollBar->onWake();
+	}
+}
+
+void SceneWindow::onSleep()
+{
+	Parent::onSleep();
+
+	if (mThumbProfile != NULL)
+		mThumbProfile->decRefCount();
+
+	if (mTrackProfile != NULL)
+		mTrackProfile->decRefCount();
+
+	if (mArrowProfile != NULL)
+		mArrowProfile->decRefCount();
+
+	if(mScrollBar->mAwake)
+	{
+		mScrollBar->onSleep();
+	}
+}
+
+void SceneWindow::setUseConstantThumbHeight(const bool setting)
+{
+	if (setting == mUseConstantHeightThumb)
+		return;
+
+	mUseConstantHeightThumb = setting;
+	mScrollBar->mUseConstantHeightThumb = setting;
+} 
+
+void SceneWindow::setScrollBarThickness(const S32 thickness)
+{
+	if (thickness == mScrollBarThickness)
+		return;
+
+	mScrollBarThickness = thickness;
+	mScrollBar->mScrollBarThickness = thickness;
+}
+
+void SceneWindow::setShowArrowButtons(const bool setting)
+{
+	if (setting == mShowArrowButtons)
+		return;
+
+	mShowArrowButtons = setting;
+	mScrollBar->mShowArrowButtons = setting;
+}
+
+void SceneWindow::setControlThumbProfile(GuiControlProfile* prof)
+{
+	AssertFatal(prof, "SceneWindow::setControlThumbProfile: invalid thumb profile");
+	if (prof == mThumbProfile)
+		return;
+	if (mAwake && mThumbProfile->mRefCount > 0)
+		mThumbProfile->decRefCount();
+	mThumbProfile = prof;
+	if (mAwake)
+		mThumbProfile->incRefCount();
+
+	mScrollBar->setControlThumbProfile(prof);
+}
+
+void SceneWindow::setControlTrackProfile(GuiControlProfile* prof)
+{
+	AssertFatal(prof, "SceneWindow::setControlTrackProfile: invalid track profile");
+	if (prof == mTrackProfile)
+		return;
+	if (mAwake && mTrackProfile->mRefCount > 0)
+		mTrackProfile->decRefCount();
+	mTrackProfile = prof;
+	if (mAwake)
+		mTrackProfile->incRefCount();
+
+	mScrollBar->setControlTrackProfile(prof);
+}
+
+void SceneWindow::setControlArrowProfile(GuiControlProfile* prof)
+{
+	AssertFatal(prof, "SceneWindow::setControlArrowProfile: invalid Arrow profile");
+	if (prof == mArrowProfile)
+		return;
+	if (mAwake && mArrowProfile->mRefCount > 0)
+		mArrowProfile->decRefCount();
+	mArrowProfile = prof;
+	if (mAwake)
+		mArrowProfile->incRefCount();
+
+	mScrollBar->setControlArrowProfile(prof);
 }
 }
 
 
 //-----------------------------------------------------------------------------
 //-----------------------------------------------------------------------------
@@ -254,6 +394,9 @@ void SceneWindow::setCameraPosition( const Vector2& position )
 
 
     // Set Camera Target to Current.
     // Set Camera Target to Current.
     mCameraTarget = mCameraCurrent;
     mCameraTarget = mCameraCurrent;
+
+	//Update the Scroll Bar
+	updateScrollBar();
 }
 }
 
 
 //-----------------------------------------------------------------------------
 //-----------------------------------------------------------------------------
@@ -271,6 +414,9 @@ void SceneWindow::setCameraSize( const Vector2& size )
 
 
     // Set Camera Target to Current.
     // Set Camera Target to Current.
     mCameraTarget = mCameraCurrent;
     mCameraTarget = mCameraCurrent;
+
+	//Update the Scroll Bar
+	updateScrollBar();
 }
 }
 
 
 //-----------------------------------------------------------------------------
 //-----------------------------------------------------------------------------
@@ -295,6 +441,9 @@ void SceneWindow::setCameraArea( const RectF& cameraWindow )
 
 
     // Set Camera Target to Current.
     // Set Camera Target to Current.
     mCameraTarget = mCameraCurrent;
     mCameraTarget = mCameraCurrent;
+
+	//Update the Scroll Bar
+	updateScrollBar();
 }
 }
 
 
 //-----------------------------------------------------------------------------
 //-----------------------------------------------------------------------------
@@ -309,6 +458,9 @@ void SceneWindow::setCameraZoom( const F32 zoomFactor )
 
 
     // Set Camera Target to Current.
     // Set Camera Target to Current.
     mCameraTarget = mCameraCurrent;
     mCameraTarget = mCameraCurrent;
+
+	//Update the Scroll Bar
+	updateScrollBar();
 }
 }
 
 
 //-----------------------------------------------------------------------------
 //-----------------------------------------------------------------------------
@@ -323,6 +475,9 @@ void SceneWindow::setCameraAngle( const F32 cameraAngle )
 
 
     // Set Camera Target to Current.
     // Set Camera Target to Current.
     mCameraTarget = mCameraCurrent;
     mCameraTarget = mCameraCurrent;
+
+	//Update the Scroll Bar
+	updateScrollBar();
 }
 }
 
 
 //-----------------------------------------------------------------------------
 //-----------------------------------------------------------------------------
@@ -345,6 +500,9 @@ void SceneWindow::setTargetCameraPosition( const Vector2& position )
 
 
     // Set Camera Target.
     // Set Camera Target.
     mCameraTarget.mSourceArea = RectF( position.x - (cameraSize.x*0.5f), position.y - (cameraSize.y*0.5f), cameraSize.x, cameraSize.y );
     mCameraTarget.mSourceArea = RectF( position.x - (cameraSize.x*0.5f), position.y - (cameraSize.y*0.5f), cameraSize.x, cameraSize.y );
+
+	//Update the Scroll Bar
+	updateScrollBar();
 }
 }
 
 
 //-----------------------------------------------------------------------------
 //-----------------------------------------------------------------------------
@@ -359,6 +517,9 @@ void SceneWindow::setTargetCameraSize( const Vector2& size )
 
 
     // Set Camera Target.
     // Set Camera Target.
     mCameraTarget.mSourceArea = RectF( position.x - (size.x * 0.5f), position.y - (size.y * 0.5f), size.x, size.y );
     mCameraTarget.mSourceArea = RectF( position.x - (size.x * 0.5f), position.y - (size.y * 0.5f), size.x, size.y );
+
+	//Update the Scroll Bar
+	updateScrollBar();
 }
 }
 
 
 //-----------------------------------------------------------------------------
 //-----------------------------------------------------------------------------
@@ -378,6 +539,9 @@ void SceneWindow::setTargetCameraArea( const RectF& cameraWindow )
 
 
     // Set Camera Target.
     // Set Camera Target.
     mCameraTarget.mSourceArea = cameraWindow;
     mCameraTarget.mSourceArea = cameraWindow;
+
+	//Update the Scroll Bar
+	updateScrollBar();
 }
 }
 
 
 //-----------------------------------------------------------------------------
 //-----------------------------------------------------------------------------
@@ -389,6 +553,9 @@ void SceneWindow::setTargetCameraZoom( const F32 zoomFactor )
 
 
     // Set Camera Target.
     // Set Camera Target.
     mCameraTarget.mCameraZoom = getMax( zoomFactor, 0.000001f );
     mCameraTarget.mCameraZoom = getMax( zoomFactor, 0.000001f );
+
+	//Update the Scroll Bar
+	updateScrollBar();
 }
 }
 
 
 //-----------------------------------------------------------------------------
 //-----------------------------------------------------------------------------
@@ -400,6 +567,9 @@ void SceneWindow::setTargetCameraAngle( const F32 cameraAngle )
 
 
     // Set Camera Target.
     // Set Camera Target.
     mCameraTarget.mCameraAngle = mFmod( cameraAngle, b2_pi2 );
     mCameraTarget.mCameraAngle = mFmod( cameraAngle, b2_pi2 );
+
+	//Update the Scroll Bar
+	updateScrollBar();
 }
 }
 
 
 //-----------------------------------------------------------------------------
 //-----------------------------------------------------------------------------
@@ -478,6 +648,9 @@ void SceneWindow::startCameraMove( const F32 interpolationTime )
     mCameraQueue.push_back( mCameraCurrent );
     mCameraQueue.push_back( mCameraCurrent );
     // Clamp Queue Size.
     // Clamp Queue Size.
     if ( mCameraQueue.size() > mMaxQueueItems ) mCameraQueue.pop_front();
     if ( mCameraQueue.size() > mMaxQueueItems ) mCameraQueue.pop_front();
+
+	//Update the Scroll Bar
+	updateScrollBar();
 }
 }
 
 
 //-----------------------------------------------------------------------------
 //-----------------------------------------------------------------------------
@@ -495,6 +668,9 @@ void SceneWindow::stopCameraMove( void )
 
 
     // Reset Camera Move.
     // Reset Camera Move.
     mMovingCamera = false;
     mMovingCamera = false;
+
+	//Update the Scroll Bar
+	updateScrollBar();
 }
 }
 
 
 //-----------------------------------------------------------------------------
 //-----------------------------------------------------------------------------
@@ -512,6 +688,9 @@ void SceneWindow::completeCameraMove( void )
 
 
     // Reset Camera Move.
     // Reset Camera Move.
     mMovingCamera = false;
     mMovingCamera = false;
+
+	//Update the Scroll Bar
+	updateScrollBar();
 }
 }
 
 
 //-----------------------------------------------------------------------------
 //-----------------------------------------------------------------------------
@@ -551,6 +730,9 @@ void SceneWindow::undoCameraMove( const F32 interpolationTime )
 
 
     // Complete camera move if interpolate time is zero.
     // Complete camera move if interpolate time is zero.
     if ( mIsZero(mCameraTransitionTime) ) completeCameraMove();
     if ( mIsZero(mCameraTransitionTime) ) completeCameraMove();
+
+	//Update the Scroll Bar
+	updateScrollBar();
 }
 }
 
 
 //-----------------------------------------------------------------------------
 //-----------------------------------------------------------------------------
@@ -576,6 +758,9 @@ void SceneWindow::updateCamera( void )
     mCameraCurrent.mSourceArea.extent.y   = interpolate( mCameraSource.mSourceArea.extent.y, mCameraTarget.mSourceArea.extent.y, normCameraTime );
     mCameraCurrent.mSourceArea.extent.y   = interpolate( mCameraSource.mSourceArea.extent.y, mCameraTarget.mSourceArea.extent.y, normCameraTime );
     mCameraCurrent.mCameraZoom            = interpolate( mCameraSource.mCameraZoom, mCameraTarget.mCameraZoom, normCameraTime );
     mCameraCurrent.mCameraZoom            = interpolate( mCameraSource.mCameraZoom, mCameraTarget.mCameraZoom, normCameraTime );
     mCameraCurrent.mCameraAngle           = interpolate( mCameraSource.mCameraAngle, mCameraTarget.mCameraAngle, normCameraTime );
     mCameraCurrent.mCameraAngle           = interpolate( mCameraSource.mCameraAngle, mCameraTarget.mCameraAngle, normCameraTime );
+
+	//Update the Scroll Bar
+	updateScrollBar();
 }
 }
 
 
 //-----------------------------------------------------------------------------
 //-----------------------------------------------------------------------------
@@ -678,6 +863,9 @@ void SceneWindow::mount( SceneObject* pSceneObject, const Vector2& mountOffset,
         if ( mMovingCamera ) stopCameraMove();
         if ( mMovingCamera ) stopCameraMove();
     }
     }
 
 
+	//Are we using scroll bars? If so that's done now.
+	mShowScrollBar = false;
+
     // Set Mount Object Reference.
     // Set Mount Object Reference.
     mpMountedTo = pSceneObject;
     mpMountedTo = pSceneObject;
 
 
@@ -737,6 +925,22 @@ void SceneWindow::dismount( void )
 
 
 //-----------------------------------------------------------------------------
 //-----------------------------------------------------------------------------
 
 
+void SceneWindow::dismountMe(SceneObject* pSceneObject)
+{
+	// Are we mounted to the specified object?
+	if (isCameraMounted() && pSceneObject != mpMountedTo)
+	{
+		// No, so warn.
+		Con::warnf("SceneWindow::dismountMe() - Object is not mounted by the camera!");
+		return;
+	}
+
+	// Dismount Object.
+	dismount();
+}
+
+//-----------------------------------------------------------------------------
+
 void SceneWindow::setViewLimitOn( const Vector2& limitMin, const Vector2& limitMax )
 void SceneWindow::setViewLimitOn( const Vector2& limitMin, const Vector2& limitMax )
 {
 {
     // Activate View Limit.
     // Activate View Limit.
@@ -748,6 +952,9 @@ void SceneWindow::setViewLimitOn( const Vector2& limitMin, const Vector2& limitM
 
 
     // Calculate Camera Area.
     // Calculate Camera Area.
     mViewLimitArea = mViewLimitMax - mViewLimitMin;
     mViewLimitArea = mViewLimitMax - mViewLimitMin;
+
+	//Update the Scroll Bar
+	updateScrollBar();
 }
 }
 
 
 //-----------------------------------------------------------------------------
 //-----------------------------------------------------------------------------
@@ -775,6 +982,44 @@ void SceneWindow::clampCameraViewLimit( void )
 
 
 //-----------------------------------------------------------------------------
 //-----------------------------------------------------------------------------
 
 
+void SceneWindow::setShowScrollBar(bool setting)
+{
+	//Warn if we don't have a view limit
+	if(setting && !mViewLimitActive)
+	{
+		Con::warnf("SceneWindow::setShowScrollBar - View Limit must be turned off for scroll bars to appear!");
+	}
+
+	// Unmount the camera if it is mounted
+	if(setting && isCameraMounted())
+	{
+		dismount();
+	}
+
+	mShowScrollBar = setting;
+
+	if(setting)
+	{
+		//now wake the scrollbar
+		if(mAwake)
+		{
+			mScrollBar->onWake();
+		}
+
+		updateScrollBar();
+	}
+}
+
+void SceneWindow::updateScrollBar()
+{
+	if (mShowScrollBar)
+	{
+		mScrollBar->computeSizes();
+	}
+}
+
+//-----------------------------------------------------------------------------
+
 void SceneWindow::setObjectInputEventFilter( const U32 groupMask, const U32 layerMask, const bool useInvisible )
 void SceneWindow::setObjectInputEventFilter( const U32 groupMask, const U32 layerMask, const bool useInvisible )
 {
 {
     // Set Object Mouse Event Filter.
     // Set Object Mouse Event Filter.
@@ -1154,6 +1399,11 @@ void SceneWindow::onTouchEnter( const GuiEvent& event )
 
 
 void SceneWindow::onTouchLeave( const GuiEvent& event )
 void SceneWindow::onTouchLeave( const GuiEvent& event )
 {
 {
+	if (mShowScrollBar)
+	{
+		mScrollBar->onTouchLeave(event);
+	}
+
     // Dispatch input event.
     // Dispatch input event.
     dispatchInputEvent(mouseEventLeaveName, event);
     dispatchInputEvent(mouseEventLeaveName, event);
 }
 }
@@ -1162,6 +1412,17 @@ void SceneWindow::onTouchLeave( const GuiEvent& event )
 
 
 void SceneWindow::onTouchDown( const GuiEvent& event )
 void SceneWindow::onTouchDown( const GuiEvent& event )
 {
 {
+	if (mShowScrollBar)
+	{
+		mScrollBar->curHitRegion = mScrollBar->findHitRegion(mScrollBar->globalToLocalCoord(event.mousePoint));
+		if (mScrollBar->curHitRegion != GuiScrollCtrl::None)
+		{
+			setUpdate();
+			mScrollBar->onTouchDown(event);
+			return;
+		}
+	}
+
     // Lock Mouse (if necessary).
     // Lock Mouse (if necessary).
     if(mLockMouse)
     if(mLockMouse)
         mouseLock();
         mouseLock();
@@ -1186,6 +1447,11 @@ void SceneWindow::onTouchUp( const GuiEvent& event )
 
 
 void SceneWindow::onTouchMove( const GuiEvent& event )
 void SceneWindow::onTouchMove( const GuiEvent& event )
 {
 {
+	if (mShowScrollBar)
+	{
+		mScrollBar->onTouchMove(event);
+	}
+
     // Dispatch input event.
     // Dispatch input event.
     dispatchInputEvent(inputEventMovedName, event);
     dispatchInputEvent(inputEventMovedName, event);
 }
 }
@@ -1266,6 +1532,12 @@ void SceneWindow::onRightMouseDragged( const GuiEvent& event )
 
 
 bool SceneWindow::onMouseWheelUp( const GuiEvent& event )
 bool SceneWindow::onMouseWheelUp( const GuiEvent& event )
 {
 {
+	if (mShowScrollBar && ((mMouseWheelScrolls && !(event.modifier & SI_SHIFT)) || (!mMouseWheelScrolls && (event.modifier & SI_SHIFT))))
+	{
+		mScrollBar->onMouseWheelUp(event);
+		return true;
+	}
+
    // Call Parent.
    // Call Parent.
    Parent::onMouseWheelUp( event );
    Parent::onMouseWheelUp( event );
 
 
@@ -1280,6 +1552,12 @@ bool SceneWindow::onMouseWheelUp( const GuiEvent& event )
 
 
 bool SceneWindow::onMouseWheelDown( const GuiEvent& event )
 bool SceneWindow::onMouseWheelDown( const GuiEvent& event )
 {
 {
+	if (mShowScrollBar && ((mMouseWheelScrolls && !(event.modifier & SI_SHIFT)) || (!mMouseWheelScrolls && (event.modifier & SI_SHIFT))))
+	{
+		mScrollBar->onMouseWheelDown(event);
+		return true;
+	}
+
    // Call Parent.
    // Call Parent.
    Parent::onMouseWheelDown( event );
    Parent::onMouseWheelDown( event );
 
 
@@ -1453,6 +1731,9 @@ void SceneWindow::resize(const Point2I &newPosition, const Point2I &newExtent)
     // Resize Parent.
     // Resize Parent.
     Parent::resize( newPosition, newExtent);
     Parent::resize( newPosition, newExtent);
 
 
+	//Update the Scroll Bar
+	updateScrollBar();
+
     // Argument Buffer.
     // Argument Buffer.
     char argBuffer[64];
     char argBuffer[64];
 
 
@@ -1725,6 +2006,12 @@ void SceneWindow::onRender( Point2I offset, const RectI& updateRect )
     // Render the metrics.
     // Render the metrics.
     renderMetricsOverlay( offset, updateRect );
     renderMetricsOverlay( offset, updateRect );
 
 
+	// Render scrollBar.
+	if (mShowScrollBar)
+	{
+		mScrollBar->onRender(offset, updateRect);
+	}
+
     // Render Children.
     // Render Children.
     renderChildControls( offset, mBounds, updateRect );
     renderChildControls( offset, mBounds, updateRect );
 
 

+ 84 - 3
engine/source/2d/gui/SceneWindow.h

@@ -43,13 +43,19 @@
 #include "2d/core/Utility.h"
 #include "2d/core/Utility.h"
 #endif
 #endif
 
 
-//-----------------------------------------------------------------------------
+class GuiSceneScrollCtrl;
 
 
 class SceneWindow : public GuiControl, public virtual Tickable
 class SceneWindow : public GuiControl, public virtual Tickable
 {
 {
     typedef GuiControl Parent;
     typedef GuiControl Parent;
 
 
 public:
 public:
+	virtual bool onWake();
+	virtual void onSleep();
+	virtual void setControlThumbProfile(GuiControlProfile* prof);
+	virtual void setControlTrackProfile(GuiControlProfile* prof);
+	virtual void setControlArrowProfile(GuiControlProfile* prof);
+
     /// Camera View.
     /// Camera View.
     struct CameraView
     struct CameraView
     {
     {
@@ -106,6 +112,11 @@ private:
     F32                 mMountForce;
     F32                 mMountForce;
     bool                mMountAngle;
     bool                mMountAngle;
 
 
+	/// Camera Scroll bar
+	bool				mShowScrollBar;
+	GuiSceneScrollCtrl* mScrollBar;
+	bool				mMouseWheelScrolls;
+
     /// View Limit.
     /// View Limit.
     bool                mViewLimitActive;
     bool                mViewLimitActive;
     Vector2             mViewLimitMin;
     Vector2             mViewLimitMin;
@@ -153,6 +164,13 @@ private:
 
 
     void calculateCameraView( CameraView* pCameraView );
     void calculateCameraView( CameraView* pCameraView );
 
 
+	//Standard Scrolling settings
+	bool mUseConstantHeightThumb;
+	S32 mScrollBarThickness;
+	bool mShowArrowButtons;
+	GuiControlProfile *mThumbProfile;
+	GuiControlProfile *mTrackProfile;
+	GuiControlProfile *mArrowProfile;
 public:
 public:
 
 
     /// Camera Interpolation Mode.
     /// Camera Interpolation Mode.
@@ -227,7 +245,12 @@ public:
     inline bool isViewLimitOn( void ) const { return mViewLimitActive; }
     inline bool isViewLimitOn( void ) const { return mViewLimitActive; }
     inline Vector2 getViewLimitMin( void ) const { return mViewLimitMin; }
     inline Vector2 getViewLimitMin( void ) const { return mViewLimitMin; }
     inline Vector2 getViewLimitMax( void ) const { return mViewLimitMax; }
     inline Vector2 getViewLimitMax( void ) const { return mViewLimitMax; }
-    inline void clampCameraViewLimit( void );
+    void clampCameraViewLimit( void );
+	void setShowScrollBar(bool setting);
+	inline bool getShowScrollBar() { return mShowScrollBar; }
+	void updateScrollBar();
+	inline void setMouseWheelScrolls(bool setting) { mMouseWheelScrolls = setting; }
+	inline bool getMouseWheelScrolls() { return mMouseWheelScrolls; }
 
 
     /// Tick Processing.
     /// Tick Processing.
     void zeroCameraTime( void );
     void zeroCameraTime( void );
@@ -319,6 +342,10 @@ public:
     virtual bool onMouseWheelDown( const GuiEvent &event );
     virtual bool onMouseWheelDown( const GuiEvent &event );
     virtual bool onMouseWheelUp( const GuiEvent &event );
     virtual bool onMouseWheelUp( const GuiEvent &event );
 
 
+	void setUseConstantThumbHeight(const bool setting);
+	void setScrollBarThickness(const S32 thickness);
+	void setShowArrowButtons(const bool setting);
+
     void renderMetricsOverlay( Point2I offset, const RectI& updateRect );
     void renderMetricsOverlay( Point2I offset, const RectI& updateRect );
 
 
     static CameraInterpolationMode getInterpolationModeEnum(const char* label);
     static CameraInterpolationMode getInterpolationModeEnum(const char* label);
@@ -331,7 +358,61 @@ protected:
     static bool writeUseWindowInputEvents( void* obj, StringTableEntry pFieldName ) { return static_cast<SceneWindow*>(obj)->mUseWindowInputEvents == false; }
     static bool writeUseWindowInputEvents( void* obj, StringTableEntry pFieldName ) { return static_cast<SceneWindow*>(obj)->mUseWindowInputEvents == false; }
     static bool writeUseObjectInputEvents( void* obj, StringTableEntry pFieldName ) { return static_cast<SceneWindow*>(obj)->mUseObjectInputEvents == true; }
     static bool writeUseObjectInputEvents( void* obj, StringTableEntry pFieldName ) { return static_cast<SceneWindow*>(obj)->mUseObjectInputEvents == true; }
     static bool writeBackgroundColor( void* obj, StringTableEntry pFieldName )      { return static_cast<SceneWindow*>(obj)->mUseBackgroundColor == true; }
     static bool writeBackgroundColor( void* obj, StringTableEntry pFieldName )      { return static_cast<SceneWindow*>(obj)->mUseBackgroundColor == true; }
-    static bool writeUseBackgroundColor( void* obj, StringTableEntry pFieldName )   { return static_cast<SceneWindow*>(obj)->mUseBackgroundColor == true; }
+	static bool writeUseBackgroundColor(void* obj, StringTableEntry pFieldName) { return static_cast<SceneWindow*>(obj)->mUseBackgroundColor == true; }
+	static bool writeScrollSettingFn(void* obj, StringTableEntry pFieldName) { return static_cast<SceneWindow*>(obj)->mShowScrollBar == true; }
+
+	static bool setConstantThumbFn(void* obj, const char* data) { SceneWindow* ctrl = static_cast<SceneWindow*>(obj); ctrl->setUseConstantThumbHeight(dAtob(data)); return false; }
+	static bool setScrollBarThicknessFn(void* obj, const char* data) { SceneWindow* ctrl = static_cast<SceneWindow*>(obj); ctrl->setScrollBarThickness(dAtoi(data)); return false; }
+	static bool setShowArrowButtonsFn(void* obj, const char* data) { SceneWindow* ctrl = static_cast<SceneWindow*>(obj); ctrl->setShowArrowButtons(dAtob(data)); return false; }
+
+	static bool setThumbProfileFn(void* obj, const char* data) 
+	{ 
+		SceneWindow* ctrl = static_cast<SceneWindow*>(obj); 
+		SimObject* simObj = Sim::findObject(data);
+		if (simObj)
+		{
+			GuiControlProfile* profile = dynamic_cast<GuiControlProfile*>(simObj);
+			if(profile)
+			{
+				ctrl->setControlThumbProfile(profile);
+				return false;
+			}
+		}
+		Con::warnf("SceneWindow::setThumbProfileFn - Unable to find requested profile.");
+		return true; 
+	}
+	static bool setTrackProfileFn(void* obj, const char* data)
+	{
+		SceneWindow* ctrl = static_cast<SceneWindow*>(obj);
+		SimObject* simObj = Sim::findObject(data);
+		if (simObj)
+		{
+			GuiControlProfile* profile = dynamic_cast<GuiControlProfile*>(simObj);
+			if (profile)
+			{
+				ctrl->setControlTrackProfile(profile);
+				return false;
+			}
+		}
+		Con::warnf("SceneWindow::setTrackProfileFn - Unable to find requested profile.");
+		return true;
+	}
+	static bool setArrowProfileFn(void* obj, const char* data)
+	{
+		SceneWindow* ctrl = static_cast<SceneWindow*>(obj);
+		SimObject* simObj = Sim::findObject(data);
+		if (simObj)
+		{
+			GuiControlProfile* profile = dynamic_cast<GuiControlProfile*>(simObj);
+			if (profile)
+			{
+				ctrl->setControlArrowProfile(profile);
+				return false;
+			}
+		}
+		Con::warnf("SceneWindow::setArrowProfileFn - Unable to find requested profile.");
+		return true;
+	}
 };
 };
 
 
 #endif // _SCENE_WINDOW_H_
 #endif // _SCENE_WINDOW_H_

+ 69 - 24
engine/source/2d/gui/SceneWindow_ScriptBinding.h

@@ -22,10 +22,10 @@
 
 
 ConsoleMethodGroupBeginWithDocs(SceneWindow, GuiControl)
 ConsoleMethodGroupBeginWithDocs(SceneWindow, GuiControl)
 
 
-/*! Fetch Window Extents (Position/Size).
+/*! Returns the windows position and extent.
     @return Returns the window dimensions as a string formatted as follows: <position.x> <position.y> <width> <height>
     @return Returns the window dimensions as a string formatted as follows: <position.x> <position.y> <width> <height>
 */
 */
-ConsoleMethodWithDocs(SceneWindow, getWindowExtents, ConsoleString, 2, 2, ())
+ConsoleMethodWithDocs(SceneWindow, getWindowArea, ConsoleString, 2, 2, ())
 {
 {
     // Get Size Argument Buffer.
     // Get Size Argument Buffer.
     char* pExtentsBuffer = Con::getReturnBuffer(64);
     char* pExtentsBuffer = Con::getReturnBuffer(64);
@@ -374,8 +374,8 @@ ConsoleMethodWithDocs(SceneWindow, getTargetCameraSize, ConsoleString, 2, 2, ())
 //-----------------------------------------------------------------------------
 //-----------------------------------------------------------------------------
 
 
 /*! Set the target camera area.
 /*! Set the target camera area.
-    @param x1 / y1 Coordinates of the upper left corner of the target area.
-    @param x2 / y2 Coordinates of the lower right corner of the target area.
+    @param x1 / y1 Coordinates of the lower left corner of the target area.
+    @param x2 / y2 Coordinates of the upper right corner of the target area.
     @return No return value.
     @return No return value.
 */
 */
 ConsoleMethodWithDocs(SceneWindow, setTargetCameraArea, ConsoleVoid, 3, 6, (x1 / y1 / x2 / y2))
 ConsoleMethodWithDocs(SceneWindow, setTargetCameraArea, ConsoleVoid, 3, 6, (x1 / y1 / x2 / y2))
@@ -491,6 +491,7 @@ ConsoleMethodWithDocs(SceneWindow, getTargetCameraAngle, ConsoleFloat, 2, 2, ())
 //-----------------------------------------------------------------------------
 //-----------------------------------------------------------------------------
 
 
 /*! Set camera interpolation time.
 /*! Set camera interpolation time.
+    @param interpolationTime Time to animate given in seconds.
     @return No return value
     @return No return value
 */
 */
 ConsoleMethodWithDocs(SceneWindow, setCameraInterpolationTime, ConsoleVoid, 3, 3, (interpolationTime))
 ConsoleMethodWithDocs(SceneWindow, setCameraInterpolationTime, ConsoleVoid, 3, 3, (interpolationTime))
@@ -502,6 +503,7 @@ ConsoleMethodWithDocs(SceneWindow, setCameraInterpolationTime, ConsoleVoid, 3, 3
 //-----------------------------------------------------------------------------
 //-----------------------------------------------------------------------------
 
 
 /*! Set camera interpolation mode.
 /*! Set camera interpolation mode.
+    @param interpolationMode Posible values are Linear and Sigmoid.
     @return No return value.
     @return No return value.
 */
 */
 ConsoleMethodWithDocs(SceneWindow, setCameraInterpolationMode, ConsoleVoid, 3, 3, (interpolationMode))
 ConsoleMethodWithDocs(SceneWindow, setCameraInterpolationMode, ConsoleVoid, 3, 3, (interpolationMode))
@@ -699,23 +701,8 @@ ConsoleMethodWithDocs(SceneWindow, dismount, ConsoleVoid, 2, 2, ())
 
 
 //-----------------------------------------------------------------------------
 //-----------------------------------------------------------------------------
 
 
-void SceneWindow::dismountMe( SceneObject* pSceneObject )
-{
-    // Are we mounted to the specified object?
-    if ( isCameraMounted() && pSceneObject != mpMountedTo )
-    {
-        // No, so warn.
-        Con::warnf("SceneWindow::dismountMe() - Object is not mounted by the camera!");
-        return;
-    }
-
-    // Dismount Object.
-    dismount();
-}
-
-//-----------------------------------------------------------------------------
-
 /*! Set View Limit On.
 /*! Set View Limit On.
+	@param [minX / minY / maxX / maxY] Optionally supplies the limits for the view.
     @return No return value
     @return No return value
 */
 */
 ConsoleMethodWithDocs(SceneWindow, setViewLimitOn, ConsoleVoid, 3, 6, ([minX / minY / maxX / maxY]))
 ConsoleMethodWithDocs(SceneWindow, setViewLimitOn, ConsoleVoid, 3, 6, ([minX / minY / maxX / maxY]))
@@ -791,6 +778,28 @@ ConsoleMethodWithDocs(SceneWindow, clampCameraViewLimit, ConsoleVoid, 2, 2, ())
 
 
 //-----------------------------------------------------------------------------
 //-----------------------------------------------------------------------------
 
 
+/*! Sets the scroll bars on. View Limits should be set prior to turning on scroll bars. 
+	@param setting If true, scroll bars will be on. 
+	@return No return value
+*/
+ConsoleMethodWithDocs(SceneWindow, setShowScrollBar, ConsoleVoid, 3, 3, (setting))
+{
+	object->setShowScrollBar(dAtob(argv[2]));
+}
+
+//-----------------------------------------------------------------------------
+
+/*! When true, allows the mouse wheel to move the scroll bar when it's turned on.
+	@param setting If true, the scroll bars will consume the mouse wheel events instead of being passed to the scene. Holding shift will reverse this behavior.
+	@return No return value
+*/
+ConsoleMethodWithDocs(SceneWindow, setMouseWheelScrolls, ConsoleVoid, 3, 3, (setting))
+{
+	object->setMouseWheelScrolls(dAtob(argv[2]));
+}
+
+//-----------------------------------------------------------------------------
+
 /*! Sets the render group(s).
 /*! Sets the render group(s).
     @param groups The list of groups you wish to set.
     @param groups The list of groups you wish to set.
     @return No return value.
     @return No return value.
@@ -952,10 +961,10 @@ ConsoleMethodWithDocs(SceneWindow, getRenderGroupMask, ConsoleInt, 2, 2, ())
 //-----------------------------------------------------------------------------
 //-----------------------------------------------------------------------------
 
 
 /*! or ( stockColorName )  - Sets the background color for the scene.
 /*! or ( stockColorName )  - Sets the background color for the scene.
-    @param red The red value.
-    @param green The green value.
-    @param blue The blue value.
-    @param alpha The alpha value.
+    @param red The red value as floating point value between 0 and 1.
+    @param green The green value as floating point value between 0 and 1.
+    @param blue The blue value as floating point value between 0 and 1.
+    @param alpha The alpha value as floating point value between 0 and 1.
     @return No return Value.
     @return No return Value.
 */
 */
 ConsoleMethodWithDocs(SceneWindow, setBackgroundColor, ConsoleVoid, 3, 6, (float red, float green, float blue, [float alpha = 1.0]))
 ConsoleMethodWithDocs(SceneWindow, setBackgroundColor, ConsoleVoid, 3, 6, (float red, float green, float blue, [float alpha = 1.0]))
@@ -1557,4 +1566,40 @@ ConsoleMethodWithDocs(SceneWindow, setAudioListener, ConsoleVoid, 2, 3, ())
     object->setProcessAudioListener(onoff);
     object->setProcessAudioListener(onoff);
 }
 }
 
 
+/*! Sets the currently used ThumbProfile for the GuiControl
+	@param p The Thumbprofile you wish to set the control to use
+	@return No return value
+*/
+ConsoleMethodWithDocs(SceneWindow, setThumbProfile, ConsoleVoid, 3, 3, (GuiControlProfile p))
+{
+	GuiControlProfile* profile;
+
+	if (Sim::findObject(argv[2], profile))
+		object->setControlThumbProfile(profile);
+}
+
+/*! Sets the currently used TrackProfile for the GuiControl
+	@param p The Trackprofile you wish to set the control to use
+	@return No return value
+*/
+ConsoleMethodWithDocs(SceneWindow, setTrackProfile, ConsoleVoid, 3, 3, (GuiControlProfile p))
+{
+	GuiControlProfile* profile;
+
+	if (Sim::findObject(argv[2], profile))
+		object->setControlTrackProfile(profile);
+}
+
+/*! Sets the currently used ArrowProfile for the GuiControl
+	@param p The Arrowprofile you wish to set the control to use
+	@return No return value
+*/
+ConsoleMethodWithDocs(SceneWindow, setArrowProfile, ConsoleVoid, 3, 3, (GuiControlProfile p))
+{
+	GuiControlProfile* profile;
+
+	if (Sim::findObject(argv[2], profile))
+		object->setControlArrowProfile(profile);
+}
+
 ConsoleMethodGroupEndWithDocs(SceneWindow)
 ConsoleMethodGroupEndWithDocs(SceneWindow)

+ 387 - 0
engine/source/gui/containers/guiSceneScrollCtrl.cc

@@ -0,0 +1,387 @@
+//-----------------------------------------------------------------------------
+// Copyright (c) 2013 GarageGames, LLC
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to
+// deal in the Software without restriction, including without limitation the
+// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+// IN THE SOFTWARE.
+//-----------------------------------------------------------------------------
+
+#include "console/consoleTypes.h"
+#include "console/console.h"
+#include "graphics/gBitmap.h"
+#include "graphics/TextureManager.h"
+#include "io/resource/resourceManager.h"
+#include "platform/event.h"
+#include "graphics/dgl.h"
+#include "gui/guiArrayCtrl.h"
+#include "gui/containers/guiSceneScrollCtrl.h"
+#include "gui/guiDefaultControlRender.h"
+#include "gui/guiCanvas.h"
+
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- //
+
+GuiSceneScrollCtrl::GuiSceneScrollCtrl(SceneWindow* window) : GuiScrollCtrl()
+{
+   mWindow = window;
+}
+
+void GuiSceneScrollCtrl::initPersistFields()
+{
+	//Not a con object...
+}
+
+bool GuiSceneScrollCtrl::onWake()
+{
+	if (mAwake)
+		return false;
+
+	if (mProfile != NULL)
+		mProfile->incRefCount();
+
+	if (mThumbProfile != NULL)
+		mThumbProfile->incRefCount();
+
+	if (mTrackProfile != NULL)
+		mTrackProfile->incRefCount();
+
+	if (mArrowProfile != NULL)
+		mArrowProfile->incRefCount();
+
+	mAwake = true;
+
+	return true;
+}
+
+void GuiSceneScrollCtrl::onSleep()
+{
+	if (!mAwake)
+		return;
+
+	if (mProfile != NULL)
+		mProfile->decRefCount();
+
+	if (mThumbProfile != NULL)
+		mThumbProfile->decRefCount();
+
+	if (mTrackProfile != NULL)
+		mTrackProfile->decRefCount();
+
+	if (mArrowProfile != NULL)
+		mArrowProfile->decRefCount();
+
+	mAwake = false;
+}
+
+#pragma region CalculationFunctions
+void GuiSceneScrollCtrl::calcContentExtents()
+{
+	Vector2 v = mWindow->getCameraSize();
+	mContentExt = Point2I(mCeil(v.x), mCeil(v.y));
+
+	F32 zoom = getMax(mWindow->getCameraZoom(), 0.0000001f);
+	mContentExt.x /= zoom;
+	mContentExt.y /= zoom;
+
+	//This will be removed later so we are countering it now.
+	if (mHasVScrollBar)
+		mContentExt.x += mScrollBarThickness;
+	if (mHasHScrollBar)
+		mContentExt.y += mScrollBarThickness;
+}
+
+bool GuiSceneScrollCtrl::calcChildExtents()
+{
+	if (!mWindow->isViewLimitOn())
+		return false;
+
+	Vector2 v = mWindow->getViewLimitMax() - mWindow->getViewLimitMin();
+	mChildExt = Point2I(mFloor(v.x), mFloor(v.y));
+	return true;
+}
+
+void GuiSceneScrollCtrl::calcScrollOffset()
+{
+	//Set the offset based on the position of the visible area of the window
+	RectF cameraArea = mWindow->getCameraArea();
+	F32 zoom = getMax(mWindow->getCameraZoom(), 0.0000001f);
+	Point2F actualExtent = Point2F(cameraArea.extent);
+	cameraArea.extent.x /= zoom;
+	cameraArea.extent.y /= zoom;
+	cameraArea.point.x += ((actualExtent.x - cameraArea.extent.x) / 2);
+	cameraArea.point.y += ((actualExtent.y - cameraArea.extent.y) / 2);
+
+	Vector2 min = mWindow->getViewLimitMin();
+	Vector2 max = mWindow->getViewLimitMax();
+	mScrollOffset.x = mRound(cameraArea.point.x - min.x);
+	mScrollOffset.y = mRound(max.y - (cameraArea.point.y + cameraArea.extent.y));
+}
+
+void GuiSceneScrollCtrl::calcScrollRects(RectI &fillRect)
+{
+	RectI rect = RectI(Point2I(0,0), mWindow->mBounds.extent);
+	Parent::calcScrollRects(rect);
+}
+#pragma endregion
+
+#pragma region ScrollingFunctions
+void GuiSceneScrollCtrl::scrollDelta(S32 deltaX, S32 deltaY)
+{
+	Vector2 pos = mWindow->getCameraPosition();
+	Vector2 size = mWindow->getCameraSize() / mWindow->getCameraZoom();
+	pos.x += deltaX;
+	pos.y -= deltaY;
+
+	Vector2 min = mWindow->getViewLimitMin();
+	Vector2 max = mWindow->getViewLimitMax();
+
+	pos.x = getMax(pos.x, min.x + (size.x / 2));
+	pos.y = getMax(pos.y, min.y + (size.y / 2));
+
+	pos.x = getMin(pos.x, max.x - (size.x / 2));
+	pos.y = getMin(pos.y, max.y - (size.y / 2));
+
+	mWindow->setTargetCameraPosition(pos);
+	mWindow->startCameraMove(0.2);
+}
+
+void GuiSceneScrollCtrl::scrollTo(S32 x, S32 y)
+{
+	Vector2 pos = mWindow->getCameraPosition();
+	Vector2 size = mWindow->getCameraSize() / mWindow->getCameraZoom();
+
+	Vector2 min = mWindow->getViewLimitMin();
+	Vector2 max = mWindow->getViewLimitMax();
+
+	if (x != mScrollOffset.x)
+	{
+		F32 halfW = size.x / 2;
+		pos.x = getMin(getMax(x + halfW + min.x, min.x + halfW), max.x - halfW);
+	}
+
+	if (y != mScrollOffset.y)
+	{
+		F32 halfH = size.y / 2;
+		pos.y = getMin(getMax(max.y - (y + halfH), min.y + halfH), max.y - halfH);
+	}
+
+	mWindow->setCameraPosition(pos);
+}
+
+void GuiSceneScrollCtrl::scrollByRegion(Region reg)
+{
+	Vector2 v = mWindow->getCameraSize() / mWindow->getCameraZoom();
+	U32 pageWidth = mCeil(v.x * 0.8);
+	U32 pageHeight = mCeil(v.y * 0.8);
+	U32 columnWidth = mCeil(v.x * 0.1);
+	U32 rowHeight = mCeil(v.y * 0.1);
+
+	if (mVBarEnabled)
+	{
+		switch (reg)
+		{
+		case UpPage:
+			scrollDelta(0, -(S32)pageHeight);
+			break;
+		case DownPage:
+			scrollDelta(0, pageHeight);
+			break;
+		case UpArrow:
+			scrollDelta(0, -(S32)rowHeight);
+			break;
+		case DownArrow:
+			scrollDelta(0, rowHeight);
+			break;
+		case LeftArrow:
+		case RightArrow:
+		case LeftPage:
+		case RightPage:
+		case VertThumb:
+		case HorizThumb:
+		case None:
+			//Con::errorf("Unhandled case in GuiSceneScrollCtrl::scrollByRegion");
+			break;
+		}
+	}
+
+	if (mHBarEnabled)
+	{
+		switch (reg)
+		{
+		case LeftPage:
+			scrollDelta(-(S32)pageWidth, 0);
+			break;
+		case RightPage:
+			scrollDelta(pageWidth, 0);
+			break;
+		case LeftArrow:
+			scrollDelta(-(S32)columnWidth, 0);
+			break;
+		case RightArrow:
+			scrollDelta(columnWidth, 0);
+			break;
+		case UpArrow:
+		case DownArrow:
+		case UpPage:
+		case DownPage:
+		case VertThumb:
+		case HorizThumb:
+		case None:
+			//Con::errorf("Unhandled case in GuiSceneScrollCtrl::scrollByRegion");
+			break;
+		}
+	}
+}
+
+void GuiSceneScrollCtrl::scrollRectVisible(RectI rect)
+{
+	//We don't do this...
+}
+#pragma endregion
+
+#pragma region Event_Processing
+Point2I GuiSceneScrollCtrl::localToGlobalCoord(const Point2I &src)
+{
+	return mWindow->localToGlobalCoord(src);
+}
+
+Point2I GuiSceneScrollCtrl::globalToLocalCoord(const Point2I &src)
+{
+	return mWindow->globalToLocalCoord(src);
+}
+
+void GuiSceneScrollCtrl::onTouchDown(const GuiEvent &event)
+{
+	Point2I curMousePos = globalToLocalCoord(event.mousePoint);
+	mDepressed = true;
+	mouseLock();
+
+	// Set a 0.5 second delay before we start scrolling
+	mLastUpdated = Platform::getVirtualMilliseconds() + 500;
+
+	scrollByRegion(curHitRegion);
+
+	if (curHitRegion == VertThumb)
+	{
+		mScrollOffsetAnchor = mScrollOffset;
+		mThumbMouseDelta = curMousePos.y - mVThumbPos;
+	}
+	else if (curHitRegion == HorizThumb)
+	{
+		mScrollOffsetAnchor = mScrollOffset;
+		mThumbMouseDelta = curMousePos.x - mHThumbPos;
+	}
+}
+
+void GuiSceneScrollCtrl::onTouchDragged(const GuiEvent &event)
+{
+	Point2I curMousePos = globalToLocalCoord(event.mousePoint);
+	mWindow->setUpdate();
+
+	if ((curHitRegion != VertThumb) && (curHitRegion != HorizThumb))
+	{
+		Region hit = findHitRegion(curMousePos);
+		if (hit != curHitRegion)
+			mDepressed = false;
+		else
+			mDepressed = true;
+		return;
+	}
+
+	// ok... if the mouse is 'near' the scroll bar, scroll with it
+	// otherwise, snap back to the previous position.
+
+	if (curHitRegion == VertThumb)
+	{
+		if (curMousePos.x >= mVTrackRect.point.x - mScrollBarDragTolerance &&
+			curMousePos.x <= mVTrackRect.point.x + mVTrackRect.extent.x - 1 + mScrollBarDragTolerance &&
+			curMousePos.y >= mVTrackRect.point.y - mScrollBarDragTolerance &&
+			curMousePos.y <= mVTrackRect.point.y + mVTrackRect.extent.y - 1 + mScrollBarDragTolerance)
+		{
+			S32 newVThumbPos = curMousePos.y - mThumbMouseDelta;
+			if (newVThumbPos != mVThumbPos)
+			{
+				S32 newVPos = (newVThumbPos) *
+					(mChildExt.y - mContentExt.y) /
+					(mVTrackRect.extent.y - mVThumbSize);
+
+				scrollTo(mScrollOffset.x, newVPos);
+			}
+		}
+		else
+			scrollTo(mScrollOffset.x, mScrollOffsetAnchor.y);
+	}
+	else if (curHitRegion == HorizThumb)
+	{
+		if (curMousePos.x >= mHTrackRect.point.x - mScrollBarDragTolerance &&
+			curMousePos.x <= mHTrackRect.point.x + mHTrackRect.extent.x - 1 + mScrollBarDragTolerance &&
+			curMousePos.y >= mHTrackRect.point.y - mScrollBarDragTolerance &&
+			curMousePos.y <= mHTrackRect.point.y + mHTrackRect.extent.y - 1 + mScrollBarDragTolerance)
+		{
+			S32 newHThumbPos = curMousePos.x - mThumbMouseDelta;
+			if (newHThumbPos != mHThumbPos)
+			{
+				S32 newHPos = (newHThumbPos) *
+					(mChildExt.x - mContentExt.x) /
+					(mHTrackRect.extent.x - mHThumbSize);
+
+				scrollTo(newHPos, mScrollOffset.y);
+			}
+		}
+		else
+			scrollTo(mScrollOffsetAnchor.x, mScrollOffset.y);
+	}
+}
+
+bool GuiSceneScrollCtrl::isMouseLocked()
+{
+	GuiCanvas *root = mWindow->getRoot();
+	return root ? root->getMouseLockedControl() == this : false;
+}
+
+void GuiSceneScrollCtrl::mouseLock(GuiControl *lockingControl)
+{
+	GuiCanvas *root = mWindow->getRoot();
+	if (root)
+		root->mouseLock(lockingControl);
+}
+
+void GuiSceneScrollCtrl::mouseLock()
+{
+	GuiCanvas *root = mWindow->getRoot();
+	if (root)
+		root->mouseLock(this);
+}
+
+void GuiSceneScrollCtrl::mouseUnlock()
+{
+	GuiCanvas *root = mWindow->getRoot();
+	if (root)
+		root->mouseUnlock(this);
+}
+#pragma endregion
+
+#pragma region rendering
+void GuiSceneScrollCtrl::onRender(Point2I offset, const RectI &updateRect)
+{
+	RectI contentRect = applyScrollBarSpacing(offset, mBounds.extent);
+	mChildArea.set(contentRect.point, contentRect.extent);
+
+	renderVScrollBar(offset);
+	renderHScrollBar(offset);
+}
+#pragma endregion
+

+ 75 - 0
engine/source/gui/containers/guiSceneScrollCtrl.h

@@ -0,0 +1,75 @@
+//-----------------------------------------------------------------------------
+// Copyright (c) 2013 GarageGames, LLC
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to
+// deal in the Software without restriction, including without limitation the
+// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+// IN THE SOFTWARE.
+//-----------------------------------------------------------------------------
+
+#ifndef _GUISCENESCROLLCTRL_H_
+#define _GUISCENESCROLLCTRL_H_
+
+#ifndef _GUICONTROL_H_
+#include "gui/guiControl.h"
+#endif
+
+#ifndef _GUISCROLLCTRL_H_
+#include "gui/containers/guiScrollCtrl.h"
+#endif
+
+#ifndef _SCENE_WINDOW_H_
+#include "2d/gui/SceneWindow.h"
+#endif
+
+class GuiSceneScrollCtrl : public GuiScrollCtrl
+{
+private:
+   typedef GuiScrollCtrl Parent;
+
+public:
+   GuiSceneScrollCtrl(SceneWindow* window);
+   static void initPersistFields();
+   virtual bool onWake();
+   virtual void onSleep();
+
+   virtual void scrollTo(S32 x, S32 y);
+   virtual void scrollByRegion(Region reg);
+   virtual void scrollRectVisible(RectI rect);
+   virtual void scrollDelta(S32 x, S32 y);
+   virtual void onTouchDown(const GuiEvent &event);
+   virtual void onTouchDragged(const GuiEvent &event);
+
+   virtual Point2I localToGlobalCoord(const Point2I &src);
+   virtual Point2I globalToLocalCoord(const Point2I &src);
+
+   void onRender(Point2I offset, const RectI &updateRect);
+   
+protected:
+	SceneWindow* mWindow;
+
+	virtual void calcContentExtents();
+	virtual bool calcChildExtents();
+	virtual void calcScrollRects(RectI &fillRect);
+	virtual void calcScrollOffset();
+
+	virtual void mouseLock(GuiControl *lockingControl);
+	virtual void mouseLock();
+	virtual void mouseUnlock();
+	virtual bool isMouseLocked();
+};
+
+#endif //_GUISCENESCROLLCTRL_H_

+ 12 - 12
engine/source/gui/containers/guiScrollCtrl.cc

@@ -283,13 +283,12 @@ void GuiScrollCtrl::computeSizes()
 			mVBarEnabled = true;
 			mVBarEnabled = true;
 
 
 		//Are we now over-scrolled?
 		//Are we now over-scrolled?
-		if ((mScrollOffset.x + mContentExt.x) > mChildExt.x)
-			mScrollOffset.x = getMax(mChildExt.x - mContentExt.x, 0);
-		if ((mScrollOffset.y + mContentExt.y) > mChildExt.y)
-			mScrollOffset.y = getMax(mChildExt.y - mContentExt.y, 0);
+		calcScrollOffset();
 	}
 	}
 	// build all the rectangles and such...
 	// build all the rectangles and such...
-	calcScrollRects();
+	RectI ctrlRect = applyMargins(mBounds.point.Zero, mBounds.extent, NormalState, mProfile);
+	RectI fillRect = applyBorders(ctrlRect.point, ctrlRect.extent, NormalState, mProfile);
+	calcScrollRects(fillRect);
 	calcThumbs();
 	calcThumbs();
 }
 }
 
 
@@ -315,12 +314,16 @@ bool GuiScrollCtrl::calcChildExtents()
 	return true;
 	return true;
 }
 }
 
 
-
-void GuiScrollCtrl::calcScrollRects(void)
+void GuiScrollCtrl::calcScrollOffset()
 {
 {
-	RectI ctrlRect = applyMargins(mBounds.point.Zero, mBounds.extent, NormalState, mProfile);
-	RectI fillRect = applyBorders(ctrlRect.point, ctrlRect.extent, NormalState, mProfile);
+	if ((mScrollOffset.x + mContentExt.x) > mChildExt.x)
+		mScrollOffset.x = getMax(mChildExt.x - mContentExt.x, 0);
+	if ((mScrollOffset.y + mContentExt.y) > mChildExt.y)
+		mScrollOffset.y = getMax(mChildExt.y - mContentExt.y, 0);
+}
 
 
+void GuiScrollCtrl::calcScrollRects(RectI &fillRect)
+{
 	if (mHasVScrollBar)
 	if (mHasVScrollBar)
 	{
 	{
 		RectI vScrollRect = RectI(fillRect.point.x + fillRect.extent.x - mScrollBarThickness, fillRect.point.y, mScrollBarThickness, fillRect.extent.y);
 		RectI vScrollRect = RectI(fillRect.point.x + fillRect.extent.x - mScrollBarThickness, fillRect.point.y, mScrollBarThickness, fillRect.extent.y);
@@ -421,9 +424,6 @@ void GuiScrollCtrl::scrollTo(S32 x, S32 y)
    if(!size())
    if(!size())
       return;
       return;
 
 
-    // keep scroll start state
-    Point2I startPoint = Point2I(0,0);
-
    setUpdate();
    setUpdate();
    if (x > mChildExt.x - mContentExt.x)
    if (x > mChildExt.x - mContentExt.x)
       x = mChildExt.x - mContentExt.x;
       x = mChildExt.x - mContentExt.x;

+ 46 - 44
engine/source/gui/containers/guiScrollCtrl.h

@@ -114,8 +114,9 @@ protected:
 
 
 	virtual void calcContentExtents();
 	virtual void calcContentExtents();
    virtual bool calcChildExtents();
    virtual bool calcChildExtents();
-   virtual void calcScrollRects(void);
-   void calcThumbs();
+   virtual void calcScrollRects(RectI &fillRect);
+   virtual void calcThumbs();
+   virtual void calcScrollOffset();
 
 
    //--------------------------------------
    //--------------------------------------
 
 
@@ -124,50 +125,51 @@ protected:
 public:
 public:
    GuiScrollCtrl();
    GuiScrollCtrl();
    DECLARE_CONOBJECT(GuiScrollCtrl);
    DECLARE_CONOBJECT(GuiScrollCtrl);
-   void scrollByRegion(Region reg);
+   
    static void initPersistFields();
    static void initPersistFields();
 
 
-   void scrollTo(S32 x, S32 y);
-   void scrollDelta(S32 x, S32 y);
-   void scrollRectVisible(RectI rect);
-
-   void computeSizes();
-
-   void addObject(SimObject *obj);
-   void resize(const Point2I &newPosition, const Point2I &newExtent);
-   void childResized(GuiControl *child);
-   S32 scrollBarThickness() const                        { return(mScrollBarThickness); }
-   bool hasHScrollBar() const                            { return(mHasHScrollBar); }
-   bool hasVScrollBar() const                            { return(mHasVScrollBar); }
-   bool enabledHScrollBar() const                        { return(mHBarEnabled); }
-   bool enabledVScrollBar() const                        { return(mVBarEnabled); }
-
-   bool isScrolledToBottom() { return mChildExt.y <= mScrollOffset.y + mContentExt.y; }
-
-   Region getCurHitRegion(void) { return curHitRegion; }
-
-   void onTouchMove(const GuiEvent &event);
-   bool onKeyDown(const GuiEvent &event);
-   void onTouchDown(const GuiEvent &event);
-   void onTouchUp(const GuiEvent &event);
-   void onTouchDragged(const GuiEvent &event);
-   void onTouchLeave(const GuiEvent &event);
-   bool onMouseWheelUp(const GuiEvent &event);
-   bool onMouseWheelDown(const GuiEvent &event);
-
-   bool onWake();
-   void onSleep();
-   void setControlThumbProfile(GuiControlProfile* prof);
-   void setControlTrackProfile(GuiControlProfile* prof);
-   void setControlArrowProfile(GuiControlProfile* prof);
-
-   void onPreRender();
-   void onRender(Point2I offset, const RectI &updateRect);
-   RectI applyScrollBarSpacing(Point2I offset, Point2I extent);
-   GuiControlState getRegionCurrentState(GuiScrollCtrl::Region region);
-   void renderBorderedRectWithArrow(RectI& bounds, GuiControlProfile* profile, GuiControlState state, GuiDirection direction);
-   void renderVScrollBar(const Point2I& offset);
-   void renderHScrollBar(const Point2I& offset);
+   virtual void scrollTo(S32 x, S32 y);
+   virtual void scrollDelta(S32 x, S32 y);
+   virtual void scrollRectVisible(RectI rect);
+   virtual void scrollByRegion(Region reg);
+
+   virtual void computeSizes();
+
+   virtual void addObject(SimObject *obj);
+   virtual void resize(const Point2I &newPosition, const Point2I &newExtent);
+   virtual void childResized(GuiControl *child);
+   virtual S32 scrollBarThickness() const                        { return(mScrollBarThickness); }
+   virtual bool hasHScrollBar() const                            { return(mHasHScrollBar); }
+   virtual bool hasVScrollBar() const                            { return(mHasVScrollBar); }
+   virtual bool enabledHScrollBar() const                        { return(mHBarEnabled); }
+   virtual bool enabledVScrollBar() const                        { return(mVBarEnabled); }
+
+   virtual bool isScrolledToBottom() { return mChildExt.y <= mScrollOffset.y + mContentExt.y; }
+
+   virtual Region getCurHitRegion(void) { return curHitRegion; }
+
+   virtual void onTouchMove(const GuiEvent &event);
+   virtual bool onKeyDown(const GuiEvent &event);
+   virtual void onTouchDown(const GuiEvent &event);
+   virtual void onTouchUp(const GuiEvent &event);
+   virtual void onTouchDragged(const GuiEvent &event);
+   virtual void onTouchLeave(const GuiEvent &event);
+   virtual bool onMouseWheelUp(const GuiEvent &event);
+   virtual bool onMouseWheelDown(const GuiEvent &event);
+
+   virtual bool onWake();
+   virtual void onSleep();
+   virtual void setControlThumbProfile(GuiControlProfile* prof);
+   virtual void setControlTrackProfile(GuiControlProfile* prof);
+   virtual void setControlArrowProfile(GuiControlProfile* prof);
+
+   virtual void onPreRender();
+   virtual void onRender(Point2I offset, const RectI &updateRect);
+   virtual RectI applyScrollBarSpacing(Point2I offset, Point2I extent);
+   virtual GuiControlState getRegionCurrentState(GuiScrollCtrl::Region region);
+   virtual void renderBorderedRectWithArrow(RectI& bounds, GuiControlProfile* profile, GuiControlState state, GuiDirection direction);
+   virtual void renderVScrollBar(const Point2I& offset);
+   virtual void renderHScrollBar(const Point2I& offset);
    virtual GuiControl* findHitControl(const Point2I &pt, S32 initialLayer = -1);
    virtual GuiControl* findHitControl(const Point2I &pt, S32 initialLayer = -1);
    virtual void renderChildControls(Point2I offset, RectI content, const RectI& updateRect);
    virtual void renderChildControls(Point2I offset, RectI content, const RectI& updateRect);
 };
 };

+ 6 - 6
engine/source/gui/guiControl.h

@@ -370,12 +370,12 @@ public:
     /// Translates local coordinates (wrt this object) into global coordinates
     /// Translates local coordinates (wrt this object) into global coordinates
     ///
     ///
     /// @param   src   Local coordinates to translate
     /// @param   src   Local coordinates to translate
-    Point2I localToGlobalCoord(const Point2I &src);
+    virtual Point2I localToGlobalCoord(const Point2I &src);
 
 
     /// Returns global coordinates translated into local space
     /// Returns global coordinates translated into local space
     ///
     ///
     /// @param   src   Global coordinates to translate
     /// @param   src   Global coordinates to translate
-    Point2I globalToLocalCoord(const Point2I &src);
+    virtual Point2I globalToLocalCoord(const Point2I &src);
     /// @}
     /// @}
 
 
     /// @name Resizing
     /// @name Resizing
@@ -514,16 +514,16 @@ public:
 
 
     /// Lock the mouse within the provided control
     /// Lock the mouse within the provided control
     /// @param   lockingControl   Control to lock the mouse within
     /// @param   lockingControl   Control to lock the mouse within
-    void mouseLock(GuiControl *lockingControl);
+    virtual void mouseLock(GuiControl *lockingControl);
 
 
     /// Turn on mouse locking with last used lock control
     /// Turn on mouse locking with last used lock control
-    void mouseLock();
+    virtual void mouseLock();
 
 
     /// Unlock the mouse
     /// Unlock the mouse
-    void mouseUnlock();
+    virtual void mouseUnlock();
 
 
     /// Returns true if the mouse is locked
     /// Returns true if the mouse is locked
-    bool isMouseLocked();
+    virtual bool isMouseLocked();
     /// @}
     /// @}