Browse Source

GuiExpandCtrl and GuiPanelCtrl

This revamps the GuiPaneCtrl into the GuiExpandCtrl and GuiPanelCtrl. It also adds easing to the color changes of the GuiButtonCtrl.
Greenfire27 4 years ago
parent
commit
f8bd3c1521
54 changed files with 1524 additions and 852 deletions
  1. 18 33
      editor/AssetAdmin/AssetAdmin.cs
  2. 90 0
      editor/AssetAdmin/AssetDictionary.cs
  3. 7 18
      editor/EditorConsole/EditorConsole.cs
  4. 12 33
      editor/EditorCore/EditorCore.cs
  5. 91 35
      editor/EditorCore/Themes/BaseTheme.cs
  6. 2 0
      editor/EditorCore/Themes/ForestRobeTheme.cs
  7. 2 0
      editor/EditorCore/Themes/LabCoatTheme.cs
  8. 48 28
      editor/EditorCore/Themes/ThemeManager.cs
  9. 2 0
      editor/EditorCore/Themes/TorqueSuitTheme.cs
  10. 2 6
      editor/ProjectManager/ProjectManager.cs
  11. 0 0
      engine/Link/Debug/libogg/libogg.vcxproj.FileListAbsolute.txt
  12. 7 0
      engine/Link/Debug/libogg/libogg_DEBUG.lib.recipe
  13. 0 0
      engine/Link/Debug/libvorbis/libvorbis.vcxproj.FileListAbsolute.txt
  14. 7 0
      engine/Link/Debug/libvorbis/libvorbis_DEBUG.lib.recipe
  15. 0 0
      engine/Link/Debug/ljpeg/ljpeg.vcxproj.FileListAbsolute.txt
  16. 7 0
      engine/Link/Debug/ljpeg/ljpeg_DEBUG.lib.recipe
  17. 0 0
      engine/Link/Debug/lpng/lpng.vcxproj.FileListAbsolute.txt
  18. 7 0
      engine/Link/Debug/lpng/lpng_DEBUG.lib.recipe
  19. 0 0
      engine/Link/Debug/zlib/zlib.vcxproj.FileListAbsolute.txt
  20. 7 0
      engine/Link/Debug/zlib/zlib_DEBUG.lib.recipe
  21. 10 3
      engine/compilers/VisualStudio 2017/Torque 2D.vcxproj
  22. 27 6
      engine/compilers/VisualStudio 2017/Torque 2D.vcxproj.filters
  23. 1 1
      engine/compilers/VisualStudio 2017/libogg.vcxproj
  24. 1 1
      engine/compilers/VisualStudio 2017/libvorbis.vcxproj
  25. 1 1
      engine/compilers/VisualStudio 2017/ljpeg.vcxproj
  26. 1 1
      engine/compilers/VisualStudio 2017/lpng.vcxproj
  27. 1 1
      engine/compilers/VisualStudio 2017/zlib.vcxproj
  28. 5 10
      engine/source/2d/gui/guiSceneObjectCtrl.cc
  29. 12 0
      engine/source/graphics/gColor.h
  30. 107 30
      engine/source/gui/buttons/guiButtonCtrl.cc
  31. 21 2
      engine/source/gui/buttons/guiButtonCtrl.h
  32. 97 0
      engine/source/gui/buttons/guiButtonCtrl_ScriptBinding.h
  33. 188 0
      engine/source/gui/containers/guiExpandCtrl.cc
  34. 75 0
      engine/source/gui/containers/guiExpandCtrl.h
  35. 72 0
      engine/source/gui/containers/guiExpandCtrl_ScriptBinding.h
  36. 1 2
      engine/source/gui/containers/guiFormCtrl.cc
  37. 0 330
      engine/source/gui/containers/guiPaneCtrl.cc
  38. 0 86
      engine/source/gui/containers/guiPaneCtrl.h
  39. 113 0
      engine/source/gui/containers/guiPanelCtrl.cc
  40. 56 0
      engine/source/gui/containers/guiPanelCtrl.h
  41. 27 0
      engine/source/gui/containers/guiPanelCtrl_ScriptBinding.h
  42. 7 1
      engine/source/gui/containers/guiScrollCtrl.cc
  43. 2 3
      engine/source/gui/editor/guiMenuBar.cc
  44. 15 34
      engine/source/gui/guiCanvas.cc
  45. 9 4
      engine/source/gui/guiControl.cc
  46. 10 1
      engine/source/gui/guiControl.h
  47. 10 8
      engine/source/gui/guiDefaultControlRender.cc
  48. 1 0
      engine/source/gui/guiDefaultControlRender.h
  49. 8 40
      engine/source/gui/guiTypes.cc
  50. 9 8
      engine/source/gui/guiTypes.h
  51. 118 0
      engine/source/math/mFluid.cpp
  52. 86 0
      engine/source/math/mFluid.h
  53. 6 7
      toybox/Sandbox/1/gui/guiProfiles.cs
  54. 118 119
      toybox/TruckToy/1/main.cs

+ 18 - 33
editor/AssetAdmin/AssetAdmin.cs

@@ -22,14 +22,12 @@
 
 function AssetAdmin::create(%this)
 {
+	exec("./AssetDictionary.cs");
+
 	%this.guiPage = EditorCore.RegisterEditor("Asset Manager", %this);
 
 	%this.scroller = new GuiScrollCtrl()
 	{
-		Profile=EditorCore.themes.scrollingPanelProfile;
-		ThumbProfile = EditorCore.themes.scrollingPanelThumbProfile;
-		TrackProfile = EditorCore.themes.scrollingPanelTrackProfile;
-		ArrowProfile = EditorCore.themes.scrollingPanelArrowProfile;
 		HorizSizing="left";
 		VertSizing="height";
 		Position="700 0";
@@ -41,33 +39,28 @@ function AssetAdmin::create(%this)
 		showArrowButtons="1";
 		scrollBarThickness="14";
 	};
+	ThemeManager.setProfile(%this.scroller, "scrollingPanelProfile");
+	ThemeManager.setProfile(%this.scroller, "scrollingPanelThumbProfile", ThumbProfile);
+	ThemeManager.setProfile(%this.scroller, "scrollingPanelTrackProfile", TrackProfile);
+	ThemeManager.setProfile(%this.scroller, "scrollingPanelArrowProfile", ArrowProfile);
+
 	%this.guiPage.add(%this.scroller);
 
-	%this.testLogButton = new GuiButtonCtrl()
+	%this.Dictionary["ImageAsset"] = new GuiPanelCtrl()
 	{
-		Profile = EditorCore.themes.buttonProfile;
-		Text="Test";
+		Class = AssetDictionary;
+		Text="Image Assets";
 		command="";
 		HorizSizing="bottom";
 		VertSizing="right";
 		Position="0 0";
-		Extent="100 30";
-		MinExtent="80 20";
+		Extent="310 22";
+		MinExtent="80 22";
+		Type = "ImageAsset";
 	};
-	%this.scroller.add(%this.testLogButton);
-
-	%this.testLogButton2 = new GuiButtonCtrl()
-	{
-		Profile = EditorCore.themes.buttonProfile;
-		Text="Test2";
-		command="";
-		HorizSizing="bottom";
-		VertSizing="right";
-		Position="0 800";
-		Extent="100 30";
-		MinExtent="80 20";
-	};
-	%this.scroller.add(%this.testLogButton2);
+	%this.Dictionary["ImageAsset"].setExpandEase("EaseOutBounce", 1500);
+	ThemeManager.setProfile(%this.Dictionary["ImageAsset"], "panelProfile");
+	%this.scroller.add(%this.Dictionary["ImageAsset"]);
 
 	EditorCore.FinishRegistration(%this.guiPage);
 }
@@ -77,20 +70,12 @@ function AssetAdmin::destroy(%this)
 
 }
 
-function AssetAdmin::onThemeChanged(%this, %theme)
-{
-	%this.scroller.setProfile(%theme.scrollingPanelProfile);
-	%this.scroller.setThumbProfile(%theme.scrollingPanelThumbProfile);
-	%this.scroller.setTrackProfile(%theme.scrollingPanelTrackProfile);
-	%this.scroller.setArrowProfile(%theme.scrollingPanelArrowProfile);
-}
-
 function AssetAdmin::open(%this)
 {
-
+	//%this.Dictionary["ImageAsset"].load();
 }
 
 function AssetAdmin::close(%this)
 {
-
+	//%this.Dictionary["ImageAsset"].unload();
 }

+ 90 - 0
editor/AssetAdmin/AssetDictionary.cs

@@ -0,0 +1,90 @@
+//-----------------------------------------------------------------------------
+// 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.
+//-----------------------------------------------------------------------------
+
+function AssetDictionary::onAdd(%this)
+{
+	%this.grid = new GuiGridCtrl()
+	{
+		Position="0 22";
+		Extent = "310 50";
+		CellSizeX = 60;
+		CellSizeY = 60;
+		CellModeX = variable;
+		CellSpacingX = 4;
+		CellSpacingY = 4;
+		OrderMode = "LRTB";
+	};
+	ThemeManager.setProfile(%this.grid, "emptyProfile");
+	%this.add(%this.grid);
+
+	%this.load();
+}
+
+function AssetDictionary::load(%this)
+{
+	%query = new AssetQuery();
+	AssetDatabase.findAllAssets(%query);
+	AssetDatabase.findAssetType(%query, %this.Type, true);
+
+	for(%i = 0; %i < %query.getCount(); %i++)
+	{
+		%assetID = %query.getAsset(%i);
+
+		if(!AssetDatabase.isAssetInternal(%assetID))
+		{
+			%button = new GuiButtonCtrl()
+			{
+				Class = AssetDictionaryButton;
+				HorizSizing="center";
+				VertSizing="center";
+				Cmd = "OpenAsset";
+				Tooltip = AssetDatabase.getAssetName(%assetID);
+				Text = "";
+			};
+			ThemeManager.setProfile(%button, "buttonProfile");
+			ThemeManager.setProfile(%button, "tipProfile", "TooltipProfile");
+			%this.grid.add(%button);
+
+			%texture = new GuiSpriteCtrl()
+			{
+				HorizSizing="center";
+				VertSizing="bottom";
+				Extent = "50 50";
+				minExtent="8 8";
+				Position = "0 0";
+			};
+			ThemeManager.setProfile(%texture, "spriteProfile");
+			%button.add(%texture);
+			%texture.setImage(%assetID);
+		}
+	}
+	%query.delete();
+}
+
+function AssetDictionary::unload(%this)
+{
+	for(%i = %this.getCoun() - 1; %i >= 0; %i++)
+	{
+		%obj = %this.getObject(%i);
+		%obj.safeDelete();
+	}
+}

+ 7 - 18
editor/EditorConsole/EditorConsole.cs

@@ -26,7 +26,6 @@ function EditorConsole::create(%this)
 
 	%this.consoleEntry = new GuiConsoleEditCtrl()
 	{
-		Profile = EditorCore.themes.textEditProfile;
 		HorizSizing="width";
 		VertSizing="top";
 		Position="0 738";
@@ -41,11 +40,11 @@ function EditorConsole::create(%this)
 		SinkAllKeyEvents="1";
 		UseSiblingScroller="1";
 	};
+	ThemeManager.setProfile(%this.consoleEntry, "textEditProfile");
 	%this.guiPage.add(%this.consoleEntry);
 
 	%this.hideLogButton = new GuiButtonCtrl()
 	{
-		Profile = EditorCore.themes.buttonProfile;
 		Text="Close";
 		command="EditorCore.close();";
 		HorizSizing="left";
@@ -54,14 +53,11 @@ function EditorConsole::create(%this)
 		Extent="100 30";
 		MinExtent="80 20";
 	};
+	ThemeManager.setProfile(%this.hideLogButton, "buttonProfile");
 	%this.guiPage.add(%this.hideLogButton);
 
 	%this.scroller = new GuiScrollCtrl()
 	{
-		Profile=EditorCore.themes.scrollProfile;
-		ThumbProfile = EditorCore.themes.thumbProfile;
-		TrackProfile = EditorCore.themes.trackProfile;
-		ArrowProfile = EditorCore.themes.scrollArrowProfile;
 		HorizSizing="width";
 		VertSizing="height";
 		Position="0 0";
@@ -72,17 +68,21 @@ function EditorConsole::create(%this)
 		constantThumbHeight="0";
 		showArrowButtons="1";
 	};
+	ThemeManager.setProfile(%this.scroller, "scrollProfile");
+	ThemeManager.setProfile(%this.scroller, "thumbProfile", ThumbProfile);
+	ThemeManager.setProfile(%this.scroller, "trackProfile", TrackProfile);
+	ThemeManager.setProfile(%this.scroller, "scrollArrowProfile", ArrowProfile);
 	%this.guiPage.add(%this.scroller);
 
 	%this.consoleLog = new GuiConsole()
 	{
-		Profile=EditorCore.themes.consoleProfile;
 		Position="0 0";
 		Extent="1024 738";
 		HorizSizing="width";
 		VertSizing="height";
 		Visible="1";
 	};
+	ThemeManager.setProfile(%this.consoleLog, "consoleProfile");
 	%this.scroller.add(%this.consoleLog);
 
 	EditorCore.FinishRegistration(%this.guiPage);
@@ -93,17 +93,6 @@ function EditorConsole::destroy(%this)
 
 }
 
-function EditorConsole::onThemeChanged(%this, %theme)
-{
-	%this.consoleEntry.setProfile(%theme.textEditProfile);
-	%this.hideLogButton.setProfile(%theme.buttonProfile);
-	%this.scroller.setProfile(%theme.scrollProfile);
-	%this.scroller.setThumbProfile(%theme.thumbProfile);
-	%this.scroller.setTrackProfile(%theme.trackProfile);
-	%this.scroller.setArrowProfile(%theme.scrollArrowProfile);
-	%this.consoleLog.setProfile(%theme.consoleProfile);
-}
-
 function EditorConsole::open(%this)
 {
 	%this.scroller.scrollToBottom();

+ 12 - 33
editor/EditorCore/EditorCore.cs

@@ -28,11 +28,7 @@ function EditorCore::create( %this )
 	exec("./Themes/ForestRobeTheme.cs");
 	exec("./Themes/TorqueSuitTheme.cs");
 
-	%this.themes = new ScriptObject()
-	{
-		class = "ThemeManager";
-	};
-	%this.startListening(%this.themes);
+	new ScriptObject(ThemeManager);
 
 	%this.initGui();
 
@@ -51,14 +47,16 @@ function EditorCore::initGui(%this)
 {
 	%this.tabBook = new GuiTabBookCtrl()
 	{
-		Profile = %this.themes.tabBookProfileTop;
-		TabProfile = %this.themes.tabProfileTop;
+		Class = EditorCoreTabBook;
 		HorizSizing = width;
 		VertSizing = height;
 		Position = "0 0";
 		Extent = "1024 768";
 		TabPosition = top;
+		Core = %this;
 	};
+	ThemeManager.setProfile(%this.tabBook, "tabBookProfileTop");
+	ThemeManager.setProfile(%this.tabBook, "tabProfileTop", "TabProfile");
 }
 
 function EditorCore::toggleEditor(%this)
@@ -83,7 +81,6 @@ function EditorCore::open(%this)
     Canvas.pushDialog(%this.tabBook);
 
 	%this.tabBook.selectPage(0);
-	EditorConsole.open();
 }
 
 function EditorCore::close(%this)
@@ -97,15 +94,14 @@ function EditorCore::RegisterEditor(%this, %name, %editor)
 {
 	%this.page[%name] = new GuiTabPageCtrl()
 	{
-		Profile = %this.themes.tabPageProfile;
 		HorizSizing = width;
 		VertSizing = height;
 		Position = "0 0";
 		Extent = "1024 768";
 		Text = %name;
+		Editor = %editor;
 	};
-
-	%editor.startListening(%this.themes);
+	ThemeManager.setProfile(%this.page[%name], "tabPageProfile");
 
 	return %this.page[%name];
 }
@@ -115,29 +111,12 @@ function EditorCore::FinishRegistration(%this, %page)
 	%this.tabBook.add(%page);
 }
 
-function EditorCore::onThemeChanged(%this, %theme)
+function EditorCoreTabBook::onTabSelected(%this, %tabText)
 {
-	%this.tabBook.setProfile(%theme.tabBookProfileTop);
-	%this.tabBook.setTabProfile(%theme.tabProfileTop);
-
-	for(%i = 0; %i < %this.tabBook.getCount(); %i++)
+	if(isObject(%this.openEditor))
 	{
-		%page = %this.tabBook.getObject(%i);
-		%page.setProfile(%theme.tabPageProfile);
+		%this.openEditor.close();
 	}
-}
-
-function EditorCore::setTheme(%this, %i)
-{
-	%this.themes.setTheme(%i);
-}
-
-function EditorCore::nextTheme(%this)
-{
-	%this.themes.nextTheme();
-}
-
-function EditorCore::prevTheme(%this)
-{
-	%this.themes.prevTheme();
+	%this.Core.page[%tabText].Editor.open();
+	%this.openEditor = %this.Core.page[%tabText].Editor;
 }

+ 91 - 35
editor/EditorCore/Themes/BaseTheme.cs

@@ -2,7 +2,19 @@ function BaseTheme::onAdd(%this)
 {
 	%this.init();
 
+	%this.emptyProfile = new GuiControlProfile()
+	{
+		fillColor = "0 0 0 0";
+
+		fontType = %this.font;
+		fontSize = %this.fontSize;
+		fontColor = %this.color4;
+		align = center;
+		vAlign = middle;
+	};
+
 	%this.makeTipProfile();
+	%this.makeGeneralProfiles();
 	%this.makePanelProfile();
 	%this.makeButtonProfile();
 	%this.makeTabProfile();
@@ -13,6 +25,7 @@ function BaseTheme::onAdd(%this)
 
 function BaseTheme::init(%this)
 {
+	%this.name = "Construction Vest";
 	//fonts and font sizes
 	%this.font = "monaco";
 	%this.fontSize = 12;
@@ -39,6 +52,11 @@ function BaseTheme::init(%this)
 	%this.borderSize = 3;
 }
 
+function BaseTheme::createProfile(%this, %profileName, %parentName, %settings)
+{
+
+}
+
 function BaseTheme::makeTipProfile(%this)
 {
 	%tipBorder = new GuiBorderProfile()
@@ -50,7 +68,7 @@ function BaseTheme::makeTipProfile(%this)
 
 	%this.tipProfile = new GuiControlProfile()
 	{
-		fillColor = %this.setAlpha(%this.color2, 200);
+		fillColor = %this.setAlpha(%this.color3, 100);
 
 		fontType = %this.font;
 		fontSize = %this.fontSize;
@@ -60,49 +78,95 @@ function BaseTheme::makeTipProfile(%this)
 	};
 }
 
-function BaseTheme::makePanelProfile(%this)
+function BaseTheme::makeGeneralProfiles(%this)
 {
-	%panelBorder = new GuiBorderProfile()
+	//Useful as a background
+	%this.overlayProfile = new GuiControlProfile()
+	{
+		fillColor = %this.setAlpha(%this.color1, 150);
+
+		fontType = %this.font;
+		fontSize = %this.fontSize;
+		fontColor = %this.color4;
+	};
+
+	%simpleBorder = new GuiBorderProfile()
 	{
 		padding = 0;
 		border = %this.borderSize;
 		borderColor = "0 0 0 60";
 	};
-
-	%this.panelProfile = new GuiControlProfile()
+	//A simple, well-rounded profile for text or containers
+	%this.simpleProfile = new GuiControlProfile()
 	{
 		fillColor = %this.color1;
 
 		fontType = %this.font;
-		fontSize = %this.fontSize + 2;
+		fontSize = %this.fontSize;
 		fontColor = %this.color4;
 		align = center;
 		vAlign = middle;
 
-		borderDefault = %panelBorder;
+		borderDefault = %standardBorder;
 	};
 
-	%this.fullPanelProfile = new GuiControlProfile()
+	%this.spriteProfile = new GuiControlProfile()
 	{
-		fillColor = %this.color1;
+		fillColor = "255 255 255 255";
+		useInput = false;
+	};
+}
 
-		fontType = %this.font;
-		fontSize = %this.fontSize;
-		fontColor = %this.color4;
-		align = center;
-		vAlign = middle;
+function BaseTheme::makePanelProfile(%this)
+{
+	%panelBorderH = new GuiBorderProfile()
+	{
+		padding = 10;
+		paddingHL = 10;
+		paddingSL = 10;
+		paddingNA = 10;
 	};
 
-	%this.overlayProfile = new GuiControlProfile()
+	%panelBorderV = new GuiBorderProfile()
 	{
-		fillColor = %this.setAlpha(%this.color1, 150);
+		padding = 4;
+		paddingHL = 4;
+		paddingSL = 4;
+		paddingNA = 4;
+
+		border = 1;
+		borderHL = 1;
+		borderSL = 1;
+		borderNA = 1;
+
+		borderColor = %this.adjustValue(%this.color3, -50);
+		borderColorHL = %this.adjustValue(%this.color3, -60);
+		borderColorSL = %this.adjustValue(%this.color3, -60);
+		borderColorNA = %this.adjustValue(%this.color3, -50);
+	};
+
+	%this.panelProfile = new GuiControlProfile()
+	{
+		fillColor = %this.color2;
+		fillColorHL = %this.adjustValue(%this.color2, 5);
+		fillColorSL = %this.adjustValue(%this.color2, 5);
+		fillColorNA = %this.setAlpha(%this.color2, 80);
 
 		fontType = %this.font;
-		fontSize = %this.fontSize;
-		fontColor = %this.color4;
+		fontSize = 14;
+		fontColor = %this.color5;
+		fontColorHL = %this.adjustValue(%this.color5, 10);
+		fontColorSL = %this.adjustValue(%this.color5, 20);
+		fontColorNA = %this.setAlpha(%this.color4, 100);
+		align = left;
+		vAlign = middle;
+
+		borderDefault = %panelBorderH;
+		borderTop = %panelBorderV;
+		borderBottom = %panelBorderV;
 	};
 
-	//Scrolling panel
+	//Scrolling panel - a less space demanding scroll bar.
 	%this.scrollingPanelTrackProfile = new GuiControlProfile()
 	{
 		fillColor = %this.color2;
@@ -153,14 +217,6 @@ function BaseTheme::makePanelProfile(%this)
 
 		borderDefault = %buttonBorder;
 	};
-
-	%mainBorder = new GuiBorderProfile()
-	{
-		margin = 5;
-		padding = 5;
-		border = 3;
-		borderColor = %this.color5;
-	};
 	%this.scrollingPanelProfile = new GuiControlProfile()
 	{
 	    fillColor = %this.color1;
@@ -171,10 +227,10 @@ function BaseTheme::makeButtonProfile(%this)
 {
 	%buttonBorderV = new GuiBorderProfile()
 	{
-		padding = 6;
-		paddingHL = 6 - %this.borderSize;
-		paddingSL = 6 - %this.borderSize;
-		paddingNA = 6;
+		padding = %this.borderSize;
+		paddingHL = 0;
+		paddingSL = 0;
+		paddingNA = %this.borderSize;
 
 		border = 0;
 		borderHL = %this.borderSize;
@@ -191,10 +247,10 @@ function BaseTheme::makeButtonProfile(%this)
 
 	%buttonBorderH = new GuiBorderProfile()
 	{
-		padding = 20;
-		paddingHL = 20 - %this.borderSize;
-		paddingSL = 20 - %this.borderSize;
-		paddingNA = 20;
+		padding = %this.borderSize;
+		paddingHL = 0;
+		paddingSL = 0;
+		paddingNA = %this.borderSize;
 
 		border = 0;
 		borderHL = %this.borderSize;

+ 2 - 0
editor/EditorCore/Themes/ForestRobeTheme.cs

@@ -1,5 +1,7 @@
 function ForestRobeTheme::init(%this)
 {
+	%this.name = "Forest Robe";
+
 	//fonts and font sizes
 	%this.font = "monaco";
 	%this.fontSize = 12;

+ 2 - 0
editor/EditorCore/Themes/LabCoatTheme.cs

@@ -1,5 +1,7 @@
 function LabCoatTheme::init(%this)
 {
+	%this.name = "Lab Coat";
+
 	//fonts and font sizes
 	%this.font = "monaco";
 	%this.fontSize = 12;

+ 48 - 28
editor/EditorCore/Themes/ThemeManager.cs

@@ -23,6 +23,7 @@
 function ThemeManager::onAdd(%this)
 {
 	%this.themeList = new SimSet();
+	%this.controlList = new SimSet();
 
 	%constructionVest = new ScriptObject()
 	{
@@ -59,7 +60,8 @@ function ThemeManager::setTheme(%this, %i)
 	%i = mClamp(%i, 0, %this.themeList.getCount() - 1);
 	%this.curTheme = %i;
 	%theme = %this.themeList.getObject(%i);
-	%this.activateTheme(%theme);
+	%this.activeTheme = %theme;
+	%this.refreshProfiles();
 }
 
 function ThemeManager::nextTheme(%this)
@@ -77,32 +79,50 @@ function ThemeManager::registerTheme(%this, %theme)
 	%this.themeList.add(%theme);
 }
 
-function ThemeManager::activateTheme(%this, %theme)
+function ThemeManager::refreshProfiles(%this)
 {
-	%this.panelProfile = %theme.panelProfile;
-	%this.fullPanelProfile = %theme.fullPanelProfile;
-	%this.overlayProfile = %theme.overlayProfile;
-	%this.tipProfile = %theme.tipProfile;
-	%this.buttonProfile = %theme.buttonProfile;
-	%this.tabProfileLeft = %theme.tabProfileLeft;
-	%this.tabProfileRight = %theme.tabProfileRight;
-	%this.tabProfileTop = %theme.tabProfileTop;
-	%this.tabProfileBottom = %theme.tabProfileBottom;
-	%this.tabBookProfileLeft = %theme.tabBookProfileLeft;
-	%this.tabBookProfileRight = %theme.tabBookProfileRight;
-	%this.tabBookProfileTop = %theme.tabBookProfileTop;
-	%this.tabBookProfileBottom = %theme.tabBookProfileBottom;
-	%this.tabPageProfile = %theme.tabPageProfile;
-	%this.textEditProfile = %theme.textEditProfile;
-	%this.scrollProfile = %theme.scrollProfile;
-	%this.thumbProfile = %theme.thumbProfile;
-	%this.trackProfile = %theme.trackProfile;
-	%this.scrollArrowProfile = %theme.scrollArrowProfile;
-	%this.consoleProfile = %theme.consoleProfile;
-	%this.scrollingPanelProfile = %theme.scrollingPanelProfile;
-	%this.scrollingPanelThumbProfile = %theme.scrollingPanelThumbProfile;
-	%this.scrollingPanelTrackProfile = %theme.scrollingPanelTrackProfile;
-	%this.scrollingPanelArrowProfile = %theme.scrollingPanelArrowProfile;
-
-	%this.postEvent("ThemeChanged", %this);
+	for (%i = 0; %i < %this.controlList.getCount(); %i++)
+	{
+		%obj = %this.controlList.getObject(%i);
+
+		if(!isObject(%this.activeTheme.getFieldValue(%obj.profileName)))
+		{
+			error("ThemeManager::setProfile - Unable to find profile" SPC %obj.profileName SPC "for theme" SPC %this.activeTheme.name @ "!");
+		}
+
+		%obj.gui.setFieldValue(%obj.profileTag, %this.activeTheme.getFieldValue(%obj.profileName));
+	}
+}
+
+function ThemeManager::setProfile(%this, %gui, %profileName, %profileTag)
+{
+	if(%profileTag $= "")
+	{
+		%profileTag = "Profile";
+	}
+
+	if(!isObject(%this.activeTheme.getFieldValue(%profileName)))
+	{
+		error("ThemeManager::setProfile - Unable to find profile" SPC %profileName SPC "for theme" SPC %this.activeTheme.name @ "!");
+	}
+
+	%gui.setFieldValue(%profileTag, %this.activeTheme.getFieldValue(%profileName));
+	%this.controlList.add(
+		new ScriptObject()
+		{
+			gui = %gui;
+			profileTag = %profileTag;
+			profileName = %profileName;
+		}
+	);
+}
+
+function ThemeManager::createProfile(%this, %profileName, %parentName, %settings)
+{
+	if(!isObject(%this.activeTheme.getFieldValue(%parentName)))
+	{
+		error("ThemeManager::createProfile - Unable to find parent profile" SPC %parentName SPC "for theme" SPC %this.activeTheme.name @ "!");
+	}
+
+	%this.themeList.callOnChildren("createProfile", %profileName, %parentName, %settings);
 }

+ 2 - 0
editor/EditorCore/Themes/TorqueSuitTheme.cs

@@ -1,5 +1,7 @@
 function TorqueSuitTheme::init(%this)
 {
+	%this.name = "Torque Suit";
+
 	//fonts and font sizes
 	%this.font = "monaco";
 	%this.fontSize = 12;

+ 2 - 6
editor/ProjectManager/ProjectManager.cs

@@ -26,7 +26,7 @@ function ProjectManager::create(%this)
 
 	%this.comingSoon = new GuiControl()
 	{
-		Profile = EditorCore.themes.panelProfile;
+		Profile = ThemeManager.activeTheme.panelProfile;
 		HorizSizing="center";
 		VertSizing="center";
 		Position="412 324";
@@ -35,6 +35,7 @@ function ProjectManager::create(%this)
 		Visible="1";
 		Text = "Coming Soon!";
 	};
+	ThemeManager.setProfile(%this.comingSoon, "simpleProfile");
 	%this.guiPage.add(%this.comingSoon);
 
 	EditorCore.FinishRegistration(%this.guiPage);
@@ -45,11 +46,6 @@ function ProjectManager::destroy(%this)
 
 }
 
-function ProjectManager::onThemeChanged(%this, %theme)
-{
-	%this.comingSoon.setProfile(%theme.panelProfile);
-}
-
 function ProjectManager::open(%this)
 {
 

+ 0 - 0
engine/Link/Debug/libogg/libogg.vcxproj.FileListAbsolute.txt


+ 7 - 0
engine/Link/Debug/libogg/libogg_DEBUG.lib.recipe

@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project>
+  <ProjectOutputs></ProjectOutputs>
+  <ContentFiles></ContentFiles>
+  <SatelliteDlls></SatelliteDlls>
+  <NonRecipeFileRefs></NonRecipeFileRefs>
+</Project>

+ 0 - 0
engine/Link/Debug/libvorbis/libvorbis.vcxproj.FileListAbsolute.txt


+ 7 - 0
engine/Link/Debug/libvorbis/libvorbis_DEBUG.lib.recipe

@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project>
+  <ProjectOutputs></ProjectOutputs>
+  <ContentFiles></ContentFiles>
+  <SatelliteDlls></SatelliteDlls>
+  <NonRecipeFileRefs></NonRecipeFileRefs>
+</Project>

+ 0 - 0
engine/Link/Debug/ljpeg/ljpeg.vcxproj.FileListAbsolute.txt


+ 7 - 0
engine/Link/Debug/ljpeg/ljpeg_DEBUG.lib.recipe

@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project>
+  <ProjectOutputs></ProjectOutputs>
+  <ContentFiles></ContentFiles>
+  <SatelliteDlls></SatelliteDlls>
+  <NonRecipeFileRefs></NonRecipeFileRefs>
+</Project>

+ 0 - 0
engine/Link/Debug/lpng/lpng.vcxproj.FileListAbsolute.txt


+ 7 - 0
engine/Link/Debug/lpng/lpng_DEBUG.lib.recipe

@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project>
+  <ProjectOutputs></ProjectOutputs>
+  <ContentFiles></ContentFiles>
+  <SatelliteDlls></SatelliteDlls>
+  <NonRecipeFileRefs></NonRecipeFileRefs>
+</Project>

+ 0 - 0
engine/Link/Debug/zlib/zlib.vcxproj.FileListAbsolute.txt


+ 7 - 0
engine/Link/Debug/zlib/zlib_DEBUG.lib.recipe

@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project>
+  <ProjectOutputs></ProjectOutputs>
+  <ContentFiles></ContentFiles>
+  <SatelliteDlls></SatelliteDlls>
+  <NonRecipeFileRefs></NonRecipeFileRefs>
+</Project>

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

@@ -18,7 +18,7 @@
     <ProjectGuid>{1564A07D-230E-4C90-AEE6-52AC9A58D6C9}</ProjectGuid>
     <RootNamespace>TorqueGame</RootNamespace>
     <ProjectName>Torque2D</ProjectName>
-    <WindowsTargetPlatformVersion>10.0.17763.0</WindowsTargetPlatformVersion>
+    <WindowsTargetPlatformVersion>10.0.18362.0</WindowsTargetPlatformVersion>
   </PropertyGroup>
   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
@@ -395,6 +395,7 @@
     <ClCompile Include="..\..\source\graphics\TextureDictionary.cc" />
     <ClCompile Include="..\..\source\graphics\TextureHandle.cc" />
     <ClCompile Include="..\..\source\graphics\TextureManager.cc" />
+    <ClCompile Include="..\..\source\gui\containers\guiExpandCtrl.cc" />
     <ClCompile Include="..\..\source\gui\containers\guiGridCtrl.cc" />
     <ClCompile Include="..\..\source\gui\containers\guiTabPageCtrl.cc" />
     <ClCompile Include="..\..\source\gui\guiArrayCtrl.cc" />
@@ -452,6 +453,7 @@
     <ClCompile Include="..\..\source\io\zip\zipSubStream.cc" />
     <ClCompile Include="..\..\source\io\zip\zipTempStream.cc" />
     <ClCompile Include="..\..\source\math\math_ScriptBinding.cc" />
+    <ClCompile Include="..\..\source\math\mFluid.cpp" />
     <ClCompile Include="..\..\source\math\mPoint.cpp" />
     <ClCompile Include="..\..\source\math\rectClipper.cpp" />
     <ClCompile Include="..\..\source\memory\dataChunker.cc" />
@@ -649,7 +651,7 @@
     <ClCompile Include="..\..\source\gui\containers\guiAutoScrollCtrl.cc" />
     <ClCompile Include="..\..\source\gui\containers\guiDragAndDropCtrl.cc" />
     <ClCompile Include="..\..\source\gui\containers\guiFormCtrl.cc" />
-    <ClCompile Include="..\..\source\gui\containers\guiPaneCtrl.cc" />
+    <ClCompile Include="..\..\source\gui\containers\guiPanelCtrl.cc" />
     <ClCompile Include="..\..\source\gui\containers\guiRolloutCtrl.cc" />
     <ClCompile Include="..\..\source\gui\containers\guiScrollCtrl.cc" />
     <ClCompile Include="..\..\source\gui\containers\guiTabBookCtrl.cc" />
@@ -925,9 +927,13 @@
     <ClInclude Include="..\..\source\graphics\TextureManager.h" />
     <ClInclude Include="..\..\source\graphics\TextureManager_ScriptBinding.h" />
     <ClInclude Include="..\..\source\graphics\TextureObject.h" />
+    <ClInclude Include="..\..\source\gui\buttons\guiButtonCtrl_ScriptBinding.h" />
     <ClInclude Include="..\..\source\gui\buttons\guiCheckBoxCtrl_ScriptBinding.h" />
+    <ClInclude Include="..\..\source\gui\containers\guiExpandCtrl.h" />
+    <ClInclude Include="..\..\source\gui\containers\guiExpandCtrl_ScriptBinding.h" />
     <ClInclude Include="..\..\source\gui\containers\guiGridCtrl.h" />
     <ClInclude Include="..\..\source\gui\containers\guiGridCtrl_ScriptBinding.h" />
+    <ClInclude Include="..\..\source\gui\containers\guiPanelCtrl_ScriptBinding.h" />
     <ClInclude Include="..\..\source\gui\containers\guiScrollCtrl_ScriptBinding.h" />
     <ClInclude Include="..\..\source\gui\containers\guiTabBookCtrl_ScriptBinding.h" />
     <ClInclude Include="..\..\source\gui\containers\guiTabPageCtrl.h" />
@@ -992,6 +998,7 @@
     <ClInclude Include="..\..\source\io\zip\zipTempStream.h" />
     <ClInclude Include="..\..\source\math\box_ScriptBinding.h" />
     <ClInclude Include="..\..\source\math\matrix_ScriptBinding.h" />
+    <ClInclude Include="..\..\source\math\mFluid.h" />
     <ClInclude Include="..\..\source\math\mNormalDistribution.h" />
     <ClInclude Include="..\..\source\math\random_ScriptBinding.h" />
     <ClInclude Include="..\..\source\math\rectClipper.h" />
@@ -1268,7 +1275,7 @@
     <ClInclude Include="..\..\source\gui\containers\guiAutoScrollCtrl.h" />
     <ClInclude Include="..\..\source\gui\containers\guiDragAndDropCtrl.h" />
     <ClInclude Include="..\..\source\gui\containers\guiFormCtrl.h" />
-    <ClInclude Include="..\..\source\gui\containers\guiPaneCtrl.h" />
+    <ClInclude Include="..\..\source\gui\containers\guiPanelCtrl.h" />
     <ClInclude Include="..\..\source\gui\containers\guiRolloutCtrl.h" />
     <ClInclude Include="..\..\source\gui\containers\guiScrollCtrl.h" />
     <ClInclude Include="..\..\source\gui\containers\guiTabBookCtrl.h" />

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

@@ -471,9 +471,6 @@
     <ClCompile Include="..\..\source\gui\containers\guiFormCtrl.cc">
       <Filter>gui\containers</Filter>
     </ClCompile>
-    <ClCompile Include="..\..\source\gui\containers\guiPaneCtrl.cc">
-      <Filter>gui\containers</Filter>
-    </ClCompile>
     <ClCompile Include="..\..\source\gui\containers\guiRolloutCtrl.cc">
       <Filter>gui\containers</Filter>
     </ClCompile>
@@ -1474,6 +1471,15 @@
     <ClCompile Include="..\..\source\console\arrayObject.cpp">
       <Filter>console</Filter>
     </ClCompile>
+    <ClCompile Include="..\..\source\math\mFluid.cpp">
+      <Filter>math</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\source\gui\containers\guiExpandCtrl.cc">
+      <Filter>gui\containers</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\source\gui\containers\guiPanelCtrl.cc">
+      <Filter>gui\containers</Filter>
+    </ClCompile>
   </ItemGroup>
   <ItemGroup>
     <ClInclude Include="..\..\source\audio\audio.h">
@@ -1764,9 +1770,6 @@
     <ClInclude Include="..\..\source\gui\containers\guiFormCtrl.h">
       <Filter>gui\containers</Filter>
     </ClInclude>
-    <ClInclude Include="..\..\source\gui\containers\guiPaneCtrl.h">
-      <Filter>gui\containers</Filter>
-    </ClInclude>
     <ClInclude Include="..\..\source\gui\containers\guiRolloutCtrl.h">
       <Filter>gui\containers</Filter>
     </ClInclude>
@@ -3304,6 +3307,24 @@
     <ClInclude Include="..\..\source\console\arrayObject_ScriptBinding.h">
       <Filter>console</Filter>
     </ClInclude>
+    <ClInclude Include="..\..\source\math\mFluid.h">
+      <Filter>math</Filter>
+    </ClInclude>
+    <ClInclude Include="..\..\source\gui\containers\guiExpandCtrl.h">
+      <Filter>gui\containers</Filter>
+    </ClInclude>
+    <ClInclude Include="..\..\source\gui\containers\guiExpandCtrl_ScriptBinding.h">
+      <Filter>gui\containers</Filter>
+    </ClInclude>
+    <ClInclude Include="..\..\source\gui\containers\guiPanelCtrl.h">
+      <Filter>gui\containers</Filter>
+    </ClInclude>
+    <ClInclude Include="..\..\source\gui\containers\guiPanelCtrl_ScriptBinding.h">
+      <Filter>gui\containers</Filter>
+    </ClInclude>
+    <ClInclude Include="..\..\source\gui\buttons\guiButtonCtrl_ScriptBinding.h">
+      <Filter>gui\buttons</Filter>
+    </ClInclude>
   </ItemGroup>
   <ItemGroup>
     <CustomBuild Include="..\..\source\math\mMath_ASM.asm">

+ 1 - 1
engine/compilers/VisualStudio 2017/libogg.vcxproj

@@ -30,7 +30,7 @@
     <ProjectGuid>{15CBFEFF-7965-41F5-B4E2-21E8795C9159}</ProjectGuid>
     <RootNamespace>libogg</RootNamespace>
     <Keyword>Win32Proj</Keyword>
-    <WindowsTargetPlatformVersion>10.0.17763.0</WindowsTargetPlatformVersion>
+    <WindowsTargetPlatformVersion>10.0.18362.0</WindowsTargetPlatformVersion>
   </PropertyGroup>
   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">

+ 1 - 1
engine/compilers/VisualStudio 2017/libvorbis.vcxproj

@@ -22,7 +22,7 @@
     <ProjectGuid>{3A214E06-B95E-4D61-A291-1F8DF2EC10FD}</ProjectGuid>
     <RootNamespace>libvorbis</RootNamespace>
     <Keyword>Win32Proj</Keyword>
-    <WindowsTargetPlatformVersion>10.0.17763.0</WindowsTargetPlatformVersion>
+    <WindowsTargetPlatformVersion>10.0.18362.0</WindowsTargetPlatformVersion>
   </PropertyGroup>
   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">

+ 1 - 1
engine/compilers/VisualStudio 2017/ljpeg.vcxproj

@@ -16,7 +16,7 @@
   </ItemGroup>
   <PropertyGroup Label="Globals">
     <ProjectGuid>{0B07BA94-AA53-4FD4-ADB4-79EC2DA53B36}</ProjectGuid>
-    <WindowsTargetPlatformVersion>10.0.17763.0</WindowsTargetPlatformVersion>
+    <WindowsTargetPlatformVersion>10.0.18362.0</WindowsTargetPlatformVersion>
   </PropertyGroup>
   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">

+ 1 - 1
engine/compilers/VisualStudio 2017/lpng.vcxproj

@@ -16,7 +16,7 @@
   </ItemGroup>
   <PropertyGroup Label="Globals">
     <ProjectGuid>{AF1179E3-A838-46A3-A427-1E62AA4C52F4}</ProjectGuid>
-    <WindowsTargetPlatformVersion>10.0.17763.0</WindowsTargetPlatformVersion>
+    <WindowsTargetPlatformVersion>10.0.18362.0</WindowsTargetPlatformVersion>
   </PropertyGroup>
   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">

+ 1 - 1
engine/compilers/VisualStudio 2017/zlib.vcxproj

@@ -46,7 +46,7 @@
   </ItemGroup>
   <PropertyGroup Label="Globals">
     <ProjectGuid>{86CB2525-0CF3-40D3-BF42-A0A95035EE8C}</ProjectGuid>
-    <WindowsTargetPlatformVersion>10.0.17763.0</WindowsTargetPlatformVersion>
+    <WindowsTargetPlatformVersion>10.0.18362.0</WindowsTargetPlatformVersion>
   </PropertyGroup>
   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">

+ 5 - 10
engine/source/2d/gui/guiSceneObjectCtrl.cc

@@ -224,8 +224,6 @@ void GuiSceneObjectCtrl::onRender(Point2I offset, const RectI& updateRect)
    RectI ctrlRect( offset, mBounds.extent );
 
    // Draw Background
-   if( mProfile->mOpaque )
-   {
       if( mDepressed )
       {
          if( mHasTexture )
@@ -247,7 +245,7 @@ void GuiSceneObjectCtrl::onRender(Point2I offset, const RectI& updateRect)
          else
             dglDrawRectFill( ctrlRect, mProfile->mFillColor );
       }
-   }
+   
 
    //// Render Border.
    //if( mProfile->mBorder || mStateOn )    
@@ -263,13 +261,10 @@ void GuiSceneObjectCtrl::onRender(Point2I offset, const RectI& updateRect)
       ctrlRectInset.inset( mMargin, mMargin); 
 
       // Draw Canvas color for object
-      if ( mProfile->mOpaque )
-      {
-         if( mHasTexture )
-            renderSizableBitmapBordersFilled( objRect, 4, mProfile );
-         else
-            dglDrawRectFill( objRect, mProfile->mFillColorNA );
-      }
+	if( mHasTexture )
+		renderSizableBitmapBordersFilled( objRect, 4, mProfile );
+	else
+		dglDrawRectFill( objRect, mProfile->mFillColorNA );
 
       // Yes, so fetch object clip boundary.
       const b2Vec2* pClipBoundary = mSelectedSceneObject->getRenderOOBB();

+ 12 - 0
engine/source/graphics/gColor.h

@@ -179,6 +179,8 @@ class ColorI
    U16 get565()  const;
    U16 get4444() const;
 
+   void clamp();
+
    inline StringTableEntry stringThis(void) const   { char buffer[64]; dSprintf(buffer, 64, "%d %d %d %d", red, green, blue, alpha ); return StringTable->insert(buffer); }
    inline const char* scriptThis(void) const        { char* pBuffer = Con::getReturnBuffer(64); dSprintf(pBuffer, 32, "%d %d %d %d", red, green, blue, alpha ); return pBuffer; }
 };
@@ -552,6 +554,16 @@ inline void ColorI::interpolate(const ColorI& in_rC1,
 
 //-----------------------------------------------------------------------------
 
+inline void ColorI::clamp()
+{
+	red = mClamp(red, 0, 255);
+	green = mClamp(green, 0, 255);
+	blue = mClamp(blue, 0, 255);
+	alpha = mClamp(alpha, 0, 255);
+}
+
+//-----------------------------------------------------------------------------
+
 inline U32 ColorI::getARGBPack() const
 {
    return (U32(alpha) << 24) |

+ 107 - 30
engine/source/gui/buttons/guiButtonCtrl.cc

@@ -28,6 +28,8 @@
 #include "gui/buttons/guiButtonCtrl.h"
 #include "gui/guiDefaultControlRender.h"
 
+#include "guiButtonCtrl_ScriptBinding.h"
+
 IMPLEMENT_CONOBJECT(GuiButtonCtrl);
 
 GuiButtonCtrl::GuiButtonCtrl()
@@ -38,15 +40,26 @@ GuiButtonCtrl::GuiButtonCtrl()
 	mBounds.extent.set(140, 30);
 	mText = StringTable->insert("Button");
 	mTextID = StringTable->EmptyString;
+
+	//fill color
+	mEaseFillColorHL = EasingFunction::Linear;
+	mEaseFillColorSL = EasingFunction::Linear;
+	mEaseTimeFillColorHL = 500;
+	mEaseTimeFillColorSL = 0;
+
+	//control state
+	mPreviousState = GuiControlState::DisabledState;
+	mCurrentState = GuiControlState::DisabledState;
 }
 
-bool GuiButtonCtrl::onWake()
+void GuiButtonCtrl::initPersistFields()
 {
-   if( !Parent::onWake() )
-      return false;
-
-   return true;
+	Parent::initPersistFields();
 
+	addField("easeFillColorHL", TypeEnum, Offset(mEaseFillColorHL, GuiButtonCtrl), 1, &gEasingTable);
+	addField("easeFillColorSL", TypeEnum, Offset(mEaseFillColorSL, GuiButtonCtrl), 1, &gEasingTable);
+	addField("easeTimeFillColorHL", TypeS32, Offset(mEaseTimeFillColorHL, GuiButtonCtrl));
+	addField("easeTimeFillColorSL", TypeS32, Offset(mEaseTimeFillColorSL, GuiButtonCtrl));
 }
 
 void GuiButtonCtrl::acceleratorKeyPress(U32)
@@ -236,41 +249,42 @@ void GuiButtonCtrl::onAction()
 	Parent::onAction();
 }
 
-void GuiButtonCtrl::onRender(Point2I offset, const RectI& updateRect)
+GuiControlState GuiButtonCtrl::getCurrentState()
 {
-
-	GuiControlState currentState = GuiControlState::NormalState;
 	if (!mActive)
-	{
-		currentState = GuiControlState::DisabledState;
-	}
+		return GuiControlState::DisabledState;
 	else if (mDepressed)
-	{
-		currentState = GuiControlState::SelectedState;
-	}
-	else if(mMouseOver)
-	{
-		currentState = GuiControlState::HighlightState;
-	}
+		return GuiControlState::SelectedState;
+	else if (mMouseOver)
+		return GuiControlState::HighlightState;
+	else
+	return GuiControlState::NormalState;
+}
+
+S32 GuiButtonCtrl::getBitmapIndex(const GuiControlState state)
+{
+	if (state == GuiControlState::HighlightState)
+		return 2;
+	else if (state == GuiControlState::SelectedState)
+		return 3;
+	else if (state == GuiControlState::DisabledState)
+		return 4;
+	else 
+		return 1;
+}
 
+void GuiButtonCtrl::onRender(Point2I offset, const RectI& updateRect)
+{
+	GuiControlState currentState = getCurrentState();
 	RectI ctrlRect = applyMargins(offset, mBounds.extent, currentState, mProfile);
-	RectI boundsRect(offset, mBounds.extent);
 
 	if(mProfile->mBitmapName != NULL && mProfile->constructBitmapArray() >= 36)
 	{
-		S32 indexMultiplier = 1;
-		if ( currentState == GuiControlState::HighlightState)
-			indexMultiplier = 2;
-		else if ( currentState == GuiControlState::SelectedState )
-			indexMultiplier = 3;
-		else if ( currentState == GuiControlState::DisabledState )
-			indexMultiplier = 4;
-
-		renderSizableBitmapBordersFilled(ctrlRect, indexMultiplier, mProfile );
+		renderSizableBitmapBordersFilled(ctrlRect, getBitmapIndex(currentState), mProfile );
 	}
 	else
 	{
-		renderBorderedRect(ctrlRect, mProfile, currentState);
+		renderBorderedRect(ctrlRect, mProfile, currentState, getFillColor(currentState));
 	}
 
 	//Render Text
@@ -280,7 +294,7 @@ void GuiButtonCtrl::onRender(Point2I offset, const RectI& updateRect)
 	renderText(contentRect.point, contentRect.extent, mText, mProfile);
 
 	//Render the childen
-	renderChildControls(contentRect.point, contentRect, updateRect);
+	renderChildControls(offset, contentRect, updateRect);
 }
 
 void GuiButtonCtrl::setScriptValue(const char *value)
@@ -300,4 +314,67 @@ const char *GuiButtonCtrl::getScriptValue()
 void GuiButtonCtrl::onMessage(GuiControl *sender, S32 msg)
 {
 	Parent::onMessage(sender, msg);
+}
+
+const ColorI& GuiButtonCtrl::getFillColor(const GuiControlState state)
+{
+	if (state != mCurrentState)
+	{
+		//We have just switched states!
+		mPreviousState = mCurrentState;
+		mCurrentState = state;
+		if (mCurrentState == GuiControlState::DisabledState || mPreviousState == GuiControlState::DisabledState)
+		{
+			mFluidFillColor.stopFluidAnimation();
+			mFluidFillColor.set(mProfile->getFillColor(state));
+		}
+		else if (mCurrentState == GuiControlState::SelectedState || mPreviousState == GuiControlState::SelectedState)
+		{
+			mFluidFillColor.setEasingFunction(mEaseFillColorSL);
+			mFluidFillColor.setAnimationLength(mEaseTimeFillColorSL);
+			mFluidFillColor.startFluidAnimation(mProfile->getFillColor(state));
+		}
+		else if (mCurrentState == GuiControlState::HighlightState || mPreviousState == GuiControlState::HighlightState)
+		{
+			mFluidFillColor.setEasingFunction(mEaseFillColorHL);
+			mFluidFillColor.setAnimationLength(mEaseTimeFillColorHL);
+			mFluidFillColor.startFluidAnimation(mProfile->getFillColor(state));
+		}
+		else
+		{
+			//we should never get here...
+			mFluidFillColor.stopFluidAnimation();
+			mFluidFillColor.set(mProfile->getFillColor(state));
+		}
+	}
+
+	if (mFluidFillColor.isAnimating() && !isProcessingTicks())
+	{
+		setProcessTicks(true);
+	}
+
+	if (!mFluidFillColor.isAnimating())
+	{
+		mFluidFillColor.set(mProfile->getFillColor(state));
+	}
+
+	return mFluidFillColor;
+}
+
+void GuiButtonCtrl::processTick()
+{
+	bool shouldWeContinue = false;
+
+	shouldWeContinue |= mFluidFillColor.processTick();
+
+	if (!shouldWeContinue)
+	{
+		setProcessTicks(false);
+	}
+}
+
+void GuiButtonCtrl::setControlProfile(GuiControlProfile *prof)
+{
+	Parent::setControlProfile(prof);
+	mCurrentState = mCurrentState == DisabledState ? NormalState : DisabledState;
 }

+ 21 - 2
engine/source/gui/buttons/guiButtonCtrl.h

@@ -29,17 +29,30 @@
 
 class GuiButtonCtrl : public GuiControl
 {
+private:
    typedef GuiControl Parent;
+
 protected:
 	bool mDepressed;
 	bool mMouseOver;
-	bool mHasTheme;
+	FluidColorI mFluidFillColor; //The actual fill color as it moves fluidly from one color to another.
+	GuiControlState mPreviousState;
+	GuiControlState mCurrentState;
+	GuiControlState getCurrentState();
+	S32 getBitmapIndex(const GuiControlState state);
+
 public:
 	GuiButtonCtrl();
-	bool onWake();
+	static void initPersistFields();
 
 	DECLARE_CONOBJECT(GuiButtonCtrl);
 
+	EasingFunction mEaseFillColorHL; //Transitioning to or from HL (if SL is not involved)
+	EasingFunction mEaseFillColorSL; //Transitioning to or from SL (over HL)
+
+	S32 mEaseTimeFillColorHL;
+	S32 mEaseTimeFillColorSL;
+
 	void acceleratorKeyPress(U32 index);
 	void acceleratorKeyRelease(U32 index);
 
@@ -60,6 +73,12 @@ public:
 	virtual void onAction();
    
 	virtual void onRender(Point2I offset, const RectI &updateRect);
+	virtual void setControlProfile(GuiControlProfile *prof);
+
+	const ColorI& getFillColor(const GuiControlState state); //Returns the fill color based on the state.
+	virtual void processTick();
+
+	inline const char* getEasingFunctionDescription(const EasingFunction ease) { return mFluidFillColor.getEasingFunctionDescription(ease); };
 };
 
 #endif //_GUI_BUTTON_CTRL_H

+ 97 - 0
engine/source/gui/buttons/guiButtonCtrl_ScriptBinding.h

@@ -0,0 +1,97 @@
+//-----------------------------------------------------------------------------
+// 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.
+//-----------------------------------------------------------------------------
+
+ConsoleMethodGroupBeginWithDocs(GuiButtonCtrl, GuiControl)
+
+/*! Sets the easing that should be used to change the fill color to the highlight color. Time in milliseconds can optionally be provided.
+	@param EaseFunction Name of the selected easing function to use. Defaults to Linear (none).
+	@param EaseTime Optional length of time in milliseconds that it takes to change.
+	@return No return value.
+*/
+ConsoleMethodWithDocs(GuiButtonCtrl, setFillColorHLEase, ConsoleVoid, 3, 4, (EaseFunction, [EaseTime]))
+{
+	if (argc >= 4)
+	{
+		object->mEaseTimeFillColorHL = dAtoi(argv[3]);
+	}
+	EasingFunction f = Linear;
+	for (U32 i = 0; i < (sizeof(easingEnums) / sizeof(EnumTable::Enums)); i++)
+	{
+		if (dStricmp(easingEnums[i].label, argv[2]) == 0)
+			f = (EasingFunction)easingEnums[i].index;
+	}
+	object->mEaseFillColorHL = f;
+}
+
+/*! Sets the easing that should be used to change the fill color to the selected color. Time in milliseconds can optionally be provided.
+	@param EaseFunction Name of the selected easing function to use. Defaults to Linear (none).
+	@param EaseTime Optional length of time in milliseconds that it takes to change.
+	@return No return value.
+*/
+ConsoleMethodWithDocs(GuiButtonCtrl, setFillColorSLEase, ConsoleVoid, 3, 4, (EaseFunction, [EaseTime]))
+{
+	if (argc >= 4)
+	{
+		object->mEaseTimeFillColorSL = dAtoi(argv[3]);
+	}
+	EasingFunction f = Linear;
+	for (U32 i = 0; i < (sizeof(easingEnums) / sizeof(EnumTable::Enums)); i++)
+	{
+		if (dStricmp(easingEnums[i].label, argv[2]) == 0)
+			f = (EasingFunction)easingEnums[i].index;
+	}
+	object->mEaseFillColorSL = f;
+}
+
+/*! Gets the name of the current easing function used to change the fill color to the highlight color.
+	@return Name of the current easing function.
+*/
+ConsoleMethodWithDocs(GuiButtonCtrl, getFillColorHLEaseFunction, ConsoleString, 2, 2, ())
+{
+	return object->getEasingFunctionDescription(object->mEaseFillColorHL);
+}
+
+/*! Gets the name of the current easing function used to change the fill color to the select color.
+	@return Name of the current easing function.
+*/
+ConsoleMethodWithDocs(GuiButtonCtrl, getFillColorSLEaseFunction, ConsoleString, 2, 2, ())
+{
+	return object->getEasingFunctionDescription(object->mEaseFillColorSL);
+}
+
+/*! Gets the amount of time in milliseconds that it takes to change fill color to the highlight color.
+	@return Time in milliseconds.
+*/
+ConsoleMethodWithDocs(GuiButtonCtrl, getFillColorHLEaseTime, ConsoleInt, 2, 2, ())
+{
+	return object->mEaseTimeFillColorHL;
+}
+
+/*! Gets the amount of time in milliseconds that it takes to change fill color to the selected color.
+	@return Time in milliseconds.
+*/
+ConsoleMethodWithDocs(GuiButtonCtrl, getFillColorSLEaseTime, ConsoleInt, 2, 2, ())
+{
+	return object->mEaseTimeFillColorSL;
+}
+
+ConsoleMethodGroupEndWithDocs(GuiButtonCtrl)

+ 188 - 0
engine/source/gui/containers/guiExpandCtrl.cc

@@ -0,0 +1,188 @@
+//-----------------------------------------------------------------------------
+// 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 "gui/containers/guiExpandCtrl.h"
+
+#include "guiExpandCtrl_ScriptBinding.h"
+
+IMPLEMENT_CONOBJECT(GuiExpandCtrl);
+
+GuiExpandCtrl::GuiExpandCtrl()
+{
+   mActive = true;
+   mExpanded = false;
+   mIsContainer = true;
+   mCollapsedExtent.set(64,64);
+   mAnimationProgress = 1;
+   mExpandedExtent.set(64, 64);
+   mEasingFunction = EasingFunction::Linear;
+   mAnimationLength = 500;
+}
+
+void GuiExpandCtrl::initPersistFields()
+{
+  Parent::initPersistFields();
+
+  addField("easeExpand", TypeEnum, Offset(mEasingFunction, GuiExpandCtrl), 1, &gEasingTable);
+  addField("easeTimeExpand", TypeS32, Offset(mAnimationLength, GuiExpandCtrl));
+}
+
+void GuiExpandCtrl::parentResized(const Point2I &oldParentExtent, const Point2I &newParentExtent)
+{
+	Point2I newPosition = getPosition();
+	Point2I newExtent = getExtent();
+
+	S32 deltaX = newParentExtent.x - oldParentExtent.x;
+	S32 deltaY = newParentExtent.y - oldParentExtent.y;
+
+	if (mHorizSizing == horizResizeCenter)
+		newPosition.x = (newParentExtent.x - mBounds.extent.x) >> 1;
+	else if (mHorizSizing == horizResizeWidth)
+	{
+		newExtent.x += deltaX;
+		mCollapsedExtent.x += deltaX;
+	}
+	else if (mHorizSizing == horizResizeLeft)
+		newPosition.x += deltaX;
+	else if (mHorizSizing == horizResizeRelative && oldParentExtent.x != 0)
+	{
+		S32 newLeft = (newPosition.x * newParentExtent.x) / oldParentExtent.x;
+		S32 newRight = ((newPosition.x + newExtent.x) * newParentExtent.x) / oldParentExtent.x;
+
+		newPosition.x = newLeft;
+		newExtent.x = newRight - newLeft;
+
+		S32 collapsedRight = ((newPosition.x + mCollapsedExtent.x) * newParentExtent.x) / oldParentExtent.x;
+		mCollapsedExtent.x = collapsedRight - newLeft;
+	}
+
+	if (mVertSizing == vertResizeCenter)
+		newPosition.y = (newParentExtent.y - mBounds.extent.y) >> 1;
+	else if (mVertSizing == vertResizeHeight)
+	{
+		newExtent.y += deltaY;
+		mCollapsedExtent.y += deltaY;
+	}
+	else if (mVertSizing == vertResizeTop)
+		newPosition.y += deltaY;
+	else if (mVertSizing == vertResizeRelative && oldParentExtent.y != 0)
+	{
+
+		S32 newTop = (newPosition.y * newParentExtent.y) / oldParentExtent.y;
+		S32 newBottom = ((newPosition.y + newExtent.y) * newParentExtent.y) / oldParentExtent.y;
+
+		newPosition.y = newTop;
+		newExtent.y = newBottom - newTop;
+
+		S32 collapsedBottom = ((newPosition.y + mCollapsedExtent.y) * newParentExtent.y) / oldParentExtent.y;
+		mCollapsedExtent.y = collapsedBottom - newTop;
+	}
+
+	if (mAnimationProgress == 1 && !mExpanded)
+	{
+		setCollapsedExtent(newExtent);
+	}
+
+	resize(newPosition, newExtent);
+}
+
+void GuiExpandCtrl::setCollapsedExtent(const Point2I &extent)
+{
+	mCollapsedExtent = extent;
+
+	mExpandedExtent.set(getMax(extent.x, mExpandedExtent.x), getMax(extent.y, mExpandedExtent.y));
+}
+
+bool GuiExpandCtrl::calcExpandedExtent()
+{
+	if (!size())
+		return false;
+
+	mExpandedExtent = Point2I(0, 0);
+	for (iterator itr = begin(); itr != end(); ++itr)
+	{
+		GuiControl* child = dynamic_cast<GuiControl*>(*itr);
+		mExpandedExtent.setMax(child->getExtent() + child->getPosition());
+	}
+
+	mExpandedExtent = getOuterExtent(mExpandedExtent, GuiControlState::NormalState, mProfile);
+	mExpandedExtent.set(getMax(mCollapsedExtent.x, mExpandedExtent.x), getMax(mCollapsedExtent.y, mExpandedExtent.y));
+
+	return true;
+}
+
+void GuiExpandCtrl::setExpanded(bool isExpanded)
+{
+	if ((mExpanded == isExpanded) || (isExpanded && !calcExpandedExtent()))
+	{
+		return;
+	}
+	
+	mAnimationProgress = 1 - mAnimationProgress;
+	mExpanded = isExpanded;
+	setProcessTicks(true);
+}
+
+bool GuiExpandCtrl::processExpansion()
+{
+	F32 progress = getProgress(32.0f);
+
+	setUpdate();
+	if (mExpanded)
+	{
+		//We are growing
+		mBounds.extent.x = processValue(progress, mCollapsedExtent.x, mExpandedExtent.x);
+		mBounds.extent.y = processValue(progress, mCollapsedExtent.y, mExpandedExtent.y);
+	}
+	else
+	{
+		//We are shrinking
+		mBounds.extent.x = processValue(progress, mExpandedExtent.x, mCollapsedExtent.x);
+		mBounds.extent.y = processValue(progress, mExpandedExtent.y, mCollapsedExtent.y);
+	}
+	setUpdate();
+
+	GuiControl *parent = getParent();
+	if (parent)
+		parent->childResized(this);
+
+
+	if (mAnimationProgress >= 1.0f)
+	{
+		mAnimationProgress = 1.0f;
+		return false;
+	}
+	return true;
+}
+
+void GuiExpandCtrl::processTick() 
+{
+	bool shouldWeContinue = false;
+
+	//Expanding
+	shouldWeContinue |= processExpansion();
+
+	if (!shouldWeContinue)
+	{
+		setProcessTicks(false);
+	}
+};

+ 75 - 0
engine/source/gui/containers/guiExpandCtrl.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 _GUIEXPANDCTRL_H_
+#define _GUIEXPANDCTRL_H_
+
+#ifndef _GUICONTROL_H_
+#include "gui/guiControl.h"
+#endif
+
+#ifndef _MFLUID_H_
+#include "math/mFluid.h"
+#endif
+
+#include "graphics/dgl.h"
+#include "console/console.h"
+#include "console/consoleTypes.h"
+
+/// The Amazing Expand Control!
+///
+/// This class has a set size like any other GuiControl or it can expand to fit 
+/// its contents. It can be collapsed again to the set size. Expanding/collapsing
+/// is only done in the right/down directions. In other words, it only affects
+/// the size of the control not the position.
+///
+class GuiExpandCtrl : public GuiControl, public Fluid
+{
+private:
+   typedef GuiControl Parent;
+
+   void setCollapsedExtent(const Point2I &extent);
+
+protected:
+	bool mExpanded;
+	Point2I mCollapsedExtent;
+	Point2I mExpandedExtent;
+
+	virtual bool calcExpandedExtent();
+
+public:
+	GuiExpandCtrl();
+
+   void parentResized(const Point2I &oldParentExtent, const Point2I &newParentExtent);
+
+   inline bool getExpanded() { return mExpanded; };
+   void setExpanded(bool isExpanded);
+
+   static void initPersistFields();
+   DECLARE_CONOBJECT(GuiExpandCtrl);
+
+protected:
+	virtual void processTick();
+	bool processExpansion();
+};
+
+#endif

+ 72 - 0
engine/source/gui/containers/guiExpandCtrl_ScriptBinding.h

@@ -0,0 +1,72 @@
+//-----------------------------------------------------------------------------
+// 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.
+//-----------------------------------------------------------------------------
+
+ConsoleMethodGroupBeginWithDocs(GuiExpandCtrl, GuiControl)
+
+/*! Gets if the extent has changed or is changing to fit all available children in the right or down directions.
+	@return True if the extent is dynamically expanded.
+*/
+ConsoleMethodWithDocs(GuiExpandCtrl, getExpanded, ConsoleBool, 2, 2, ())
+{
+	return object->getExpanded();
+}
+
+/*! Sets if the control should collapse or expand.
+	@param expanded True if the Expand should expand to fit children.
+	@return No return value.
+*/
+ConsoleMethodWithDocs(GuiExpandCtrl, setExpanded, ConsoleVoid, 3, 3, (bool expanded))
+{
+	object->setExpanded(dAtob(argv[2]));
+}
+
+/*! Sets the easing that should be used to expand or collapse. Time in milliseconds can optionally be provided.
+	@param EaseFunction Name of the selected easing function to use. Defaults to Linear (none).
+	@param EaseTime Optional length of time in milliseconds that it takes to expand or collapse.
+	@return No return value.
+*/
+ConsoleMethodWithDocs(GuiExpandCtrl, setExpandEase, ConsoleVoid, 3, 4, (EaseFunction, [EaseTime]))
+{
+	if (argc >= 4)
+	{
+		object->setAnimationLength(dAtoi(argv[3]));
+	}
+	object->setEasingFunction(argv[2]);
+}
+
+/*! Gets the name of the current easing function used for expanding and collapsing.
+	@return Name of the current easing function.
+*/
+ConsoleMethodWithDocs(GuiExpandCtrl, getExpandEaseFunction, ConsoleString, 2, 2, ())
+{
+	return object->getEasingFunctionDescription(object->getEasingFunction());
+}
+
+/*! Gets the amount of time in milliseconds that it takes to expand or collapse.
+	@return Time in milliseconds.
+*/
+ConsoleMethodWithDocs(GuiExpandCtrl, getExpandEaseTime, ConsoleInt, 2, 2, ())
+{
+	return object->getAnimationLength();
+}
+
+ConsoleMethodGroupEndWithDocs(GuiExpandCtrl)

+ 1 - 2
engine/source/gui/containers/guiFormCtrl.cc

@@ -233,8 +233,7 @@ void GuiFormCtrl::onRender(Point2I offset, const RectI &updateRect)
    boundsRect.extent.y -= mThumbSize.y;
 
    // draw the border of the form if specified
-   if (mProfile->mOpaque)
-      dglDrawRectFill(boundsRect, mProfile->mFillColor);
+   dglDrawRectFill(boundsRect, mProfile->mFillColor);
 
    //if (mProfile->mBorder)
       //renderBorder(boundsRect, mProfile);

+ 0 - 330
engine/source/gui/containers/guiPaneCtrl.cc

@@ -1,330 +0,0 @@
-//-----------------------------------------------------------------------------
-// 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 "gui/containers/guiPaneCtrl.h"
-
-IMPLEMENT_CONOBJECT(GuiPaneControl);
-
-GuiPaneControl::GuiPaneControl()
-{
-   mMinExtent.set(10, 10);
-   mActive        = true;
-   mCollapsable   = true;
-   mCollapsed     = false;
-   mBarBehindText = true;
-   mMouseOver     = false;
-   mDepressed     = false;
-   mOriginalExtents.set(10,10);
-   mCaption = StringTable->insert("A Pane");
-   mCaptionID = StringTable->EmptyString;
-   mIsContainer = true;
-}
-
-void GuiPaneControl::initPersistFields()
-{
-  Parent::initPersistFields();
-
-  addField("caption",       TypeString, Offset(mCaption,        GuiPaneControl));
-  addField("captionID",     TypeString, Offset(mCaptionID,      GuiPaneControl));
-  addField("collapsable",   TypeBool,   Offset(mCollapsable,    GuiPaneControl));
-  addField("barBehindText", TypeBool,   Offset(mBarBehindText,  GuiPaneControl));
-}
-
-bool GuiPaneControl::onWake()
-{
-   if ( !Parent::onWake() )
-      return false;
-
-   mFont = mProfile->mFont;
-   AssertFatal(mFont, "GuiPaneControl::onWake: invalid font in profile" );
-   if(mCaptionID && *mCaptionID != 0)
-   {
-		setCaptionID(mCaptionID);
-   }
-
-   mProfile->constructBitmapArray();
-
-   if(mProfile->mBitmapArrayRects.size())
-   {
-      mThumbSize.set(   mProfile->mBitmapArrayRects[0].extent.x, mProfile->mBitmapArrayRects[0].extent.y );
-      mThumbSize.setMax( mProfile->mBitmapArrayRects[1].extent );
-
-      if(mFont->getHeight() > (U32)mThumbSize.y)
-         mThumbSize.y = mFont->getHeight();
-   }
-   else
-   {
-      mThumbSize.set(20, 20);
-   }
-
-   return true;
-}
-
-void GuiPaneControl::onSleep()
-{
-   Parent::onSleep();
-   mFont = NULL;
-}
-
-void GuiPaneControl::setCaptionID(const char *id)
-{
-	S32 n = Con::getIntVariable(id, -1);
-	if(n != -1)
-	{
-		mCaptionID = StringTable->insert(id);
-		setCaptionID(n);
-	}
-}
-
-void GuiPaneControl::setCaptionID(S32 id)
-{
-	const UTF8 *str = getGUIString(id);
-	if(str)
-		mCaption = StringTable->insert((const char*)str);
-}
-
-void GuiPaneControl::resize(const Point2I &newPosition, const Point2I &newExtent)
-{
-
-   //call set update both before and after
-   setUpdate();
-   Point2I actualNewExtent = Point2I(getMax(mMinExtent.x, newExtent.x),
-                                     getMax(mMinExtent.y, newExtent.y));
-
-   mBounds.set(newPosition, actualNewExtent);
-   mOriginalExtents.x = actualNewExtent.x;
-
-   GuiControl *parent = getParent();
-   if (parent)
-      parent->childResized(this);
-   setUpdate();
-
-   // Resize the child control if we're not collapsed
-   if(size() && !mCollapsed)
-   {
-      GuiControl *gc = dynamic_cast<GuiControl*>(operator[](0));
-
-      if(gc)
-      {
-         Point2I offset(0, mThumbSize.y);
-
-         gc->resize(offset, newExtent - offset);
-      }
-   }
-}
-
-void GuiPaneControl::onRender(Point2I offset, const RectI &updateRect)
-{
-   // Render our awesome little doogong
-   if(mProfile->mBitmapArrayRects.size() >= 2 && mCollapsable)
-   {
-      S32 idx = mCollapsed ? 0 : 1;
-
-      dglClearBitmapModulation();
-      dglDrawBitmapStretchSR(
-         mProfile->mTextureHandle,
-         RectI(offset, mProfile->mBitmapArrayRects[idx].extent),
-         mProfile->mBitmapArrayRects[idx]
-      );
-
-   }
-
-   S32 textWidth = 0;
-
-   if(!mBarBehindText)
-   {
-      dglSetBitmapModulation((mMouseOver ? mProfile->mFontColorHL : mProfile->mFontColor));
-      textWidth = dglDrawText(
-            mFont,
-            Point2I(mThumbSize.x, 0) + offset,
-            mCaption,
-            mProfile->mFontColors
-         );
-   }
-
-
-   // Draw our little bar, too
-   if(mProfile->mBitmapArrayRects.size() >= 5)
-   {
-      dglClearBitmapModulation();
-
-      S32 barStart = mThumbSize.x + offset.x + textWidth;
-      S32 barTop   = mThumbSize.y/2 + offset.y - mProfile->mBitmapArrayRects[3].extent.y /2;
-
-      Point2I barOffset(barStart, barTop);
-
-      // Draw the start of the bar...
-      dglDrawBitmapStretchSR(
-         mProfile->mTextureHandle,
-         RectI(barOffset, mProfile->mBitmapArrayRects[2].extent),
-         mProfile->mBitmapArrayRects[2]
-         );
-
-      // Now draw the middle...
-      barOffset.x += mProfile->mBitmapArrayRects[2].extent.x;
-
-      S32 barMiddleSize = (getExtent().x - (barOffset.x - offset.x)) - mProfile->mBitmapArrayRects[4].extent.x;
-
-      if(barMiddleSize>0)
-      {
-         // We have to do this inset to prevent nasty stretching artifacts
-         RectI foo = mProfile->mBitmapArrayRects[3];
-         foo.inset(1,0);
-
-         dglDrawBitmapStretchSR(
-            mProfile->mTextureHandle,
-            RectI(barOffset, Point2I(barMiddleSize, mProfile->mBitmapArrayRects[3].extent.y)),
-            foo
-            );
-      }
-
-      // And the end
-      barOffset.x += barMiddleSize;
-
-      dglDrawBitmapStretchSR(
-         mProfile->mTextureHandle,
-         RectI(barOffset, mProfile->mBitmapArrayRects[4].extent),
-         mProfile->mBitmapArrayRects[4]
-         );
-   }
-
-   if(mBarBehindText)
-   {
-      dglSetBitmapModulation((mMouseOver ? mProfile->mFontColorHL : mProfile->mFontColor));
-      dglDrawText(
-            mFont,
-            Point2I(mThumbSize.x, 0) + offset,
-            mCaption,
-            mProfile->mFontColors
-         );
-   }
-
-   // Draw child controls if appropriate
-   if(!mCollapsed)
-      renderChildControls(offset, mBounds, updateRect);
-}
-
-ConsoleMethod(GuiPaneControl, setCollapsed, void, 3, 3, "(bool collapsed) Sets the controls \"collapsed\" property\n"
-			  "@param collapsed True if the control is to be collapsed"
-			  "@return No return value.")
-{
-   object->setCollapsed(dAtob(argv[2]));
-}
-
-void GuiPaneControl::setCollapsed(bool isCollapsed)
-{
-   // Get the child
-   if(size() == 0 || !mCollapsable) return;
-
-   GuiControl *gc = dynamic_cast<GuiControl*>(operator[](0));
-
-   if(mCollapsed && !isCollapsed)
-   {
-      mCollapsed = false;
-
-      resize(getPosition(), mOriginalExtents);
-
-      if(gc)
-         gc->setVisible(true);
-   }
-   else if(!mCollapsed && isCollapsed)
-   {
-      mCollapsed = true;
-
-      mOriginalExtents = getExtent();
-      resize(getPosition(), Point2I(getExtent().x, mThumbSize.y));
-
-      if(gc)
-         gc->setVisible(false);
-   }
-}
-
-void GuiPaneControl::onMouseMove(const GuiEvent &event)
-{
-   Point2I localMove = globalToLocalCoord(event.mousePoint);
-
-   // If we're clicking in the header then resize
-   mMouseOver = (localMove.y < mThumbSize.y);
-   if(isMouseLocked())
-      mDepressed = mMouseOver;
-
-}
-
-void GuiPaneControl::onMouseEnter(const GuiEvent &event)
-{
-   setUpdate();
-   if(isMouseLocked())
-   {
-      mDepressed = true;
-      mMouseOver = true;
-   }
-   else
-   {
-      mMouseOver = true;
-   }
-
-}
-
-void GuiPaneControl::onMouseLeave(const GuiEvent &event)
-{
-   setUpdate();
-   if(isMouseLocked())
-      mDepressed = false;
-   mMouseOver = false;
-}
-
-void GuiPaneControl::onMouseDown(const GuiEvent &event)
-{
-   if(!mCollapsable)
-      return;
-
-   Point2I localClick = globalToLocalCoord(event.mousePoint);
-
-   // If we're clicking in the header then resize
-   if(localClick.y < mThumbSize.y)
-   {
-      mouseLock();
-      mDepressed = true;
-
-      //update
-      setUpdate();
-   }
-}
-
-void GuiPaneControl::onMouseUp(const GuiEvent &event)
-{
-   // Make sure we only get events we ought to be getting...
-   if (! mActive)
-      return;
-
-   if(!mCollapsable)
-      return;
-
-   mouseUnlock();
-   setUpdate();
-
-   Point2I localClick = globalToLocalCoord(event.mousePoint);
-
-   // If we're clicking in the header then resize
-   if(localClick.y < mThumbSize.y && mDepressed)
-      setCollapsed(!mCollapsed);
-}

+ 0 - 86
engine/source/gui/containers/guiPaneCtrl.h

@@ -1,86 +0,0 @@
-//-----------------------------------------------------------------------------
-// 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 _GUIPANECTRL_H_
-#define _GUIPANECTRL_H_
-
-#ifndef _GUICONTROL_H_
-#include "gui/guiControl.h"
-#endif
-
-#include "graphics/dgl.h"
-#include "console/console.h"
-#include "console/consoleTypes.h"
-
-/// Collapsable pane control.
-///
-/// This class wraps a single child control and displays a header with caption
-/// above it. If you click the header it will collapse or expand. The control
-/// resizes itself based on its collapsed/expanded size.
-///
-/// In the GUI editor, if you just want the header you can make collapsable
-/// false. The caption field lets you set the caption. It expects a bitmap
-/// (from the GuiControlProfile) that contains two images - the first is
-/// displayed when the control is expanded and the second is displayed when
-/// it is collapsed. The header is sized based off of the first image.
-class GuiPaneControl : public GuiControl
-{
-private:
-   typedef GuiControl Parent;
-
-   Resource<GFont>  mFont;
-   bool             mCollapsable;
-   bool             mCollapsed;
-   bool             mBarBehindText;
-   Point2I          mOriginalExtents;
-   StringTableEntry mCaption;
-   StringTableEntry mCaptionID;
-   Point2I          mThumbSize;
-
-   bool mMouseOver;
-   bool mDepressed;
-
-public:
-   GuiPaneControl();
-
-   void resize(const Point2I &newPosition, const Point2I &newExtent);
-   void onRender(Point2I offset, const RectI &updateRect);
-
-   bool getCollapsed() { return mCollapsed; };
-   void setCollapsed(bool isCollapsed);
-
-   bool onWake();
-   void onSleep();
-
-   virtual void setCaptionID(S32 id);
-   virtual void setCaptionID(const char *id);
-   void onMouseDown(const GuiEvent &event);
-   void onMouseUp(const GuiEvent &event);
-   void onMouseMove(const GuiEvent &event);
-   void onMouseLeave(const GuiEvent &event);
-   void onMouseEnter(const GuiEvent &event);
-
-   static void initPersistFields();
-   DECLARE_CONOBJECT(GuiPaneControl);
-};
-
-#endif

+ 113 - 0
engine/source/gui/containers/guiPanelCtrl.cc

@@ -0,0 +1,113 @@
+//-----------------------------------------------------------------------------
+// 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 "gui/containers/guiPanelCtrl.h"
+#include "graphics/dgl.h"
+#include "guiPanelCtrl_ScriptBinding.h"
+#include "gui/guiDefaultControlRender.h"
+
+IMPLEMENT_CONOBJECT(GuiPanelCtrl);
+
+GuiPanelCtrl::GuiPanelCtrl()
+{
+   mActive = true;
+   mIsContainer = true;
+	mHeader = NULL;
+}
+
+GuiPanelCtrl::~GuiPanelCtrl()
+{
+}
+
+void GuiPanelCtrl::initPersistFields()
+{
+  Parent::initPersistFields();
+}
+
+bool GuiPanelCtrl::onAdd()
+{
+	if (!Parent::onAdd())
+		return false;
+
+	if (!mHeader)
+	{
+		mHeader = new GuiButtonCtrl();
+		AssertFatal(mHeader, "GuiPaneCtrl::onAdd() Cannot create a GuiButtonCtrl for the header.");
+		if (mHeader)
+		{
+			mHeader->setField("horizSizing", "right");
+			mHeader->setField("vertSizing", "bottom");
+			mHeader->setField("extent", "64 64");
+			mHeader->setField("minExtent", "16 16");
+			mHeader->setField("position", "0 0");
+			
+			mHeader->registerObject();
+			addObject(mHeader);
+			mHeader->setConsoleCommand(avar("%d.setExpanded(!%d.getExpanded());", getId(), getId()));
+		}
+	}
+
+	return true;
+}
+
+void GuiPanelCtrl::onRender(Point2I offset, const RectI &updateRect)
+{
+	if (mText != mHeader->getText())
+	{
+		mHeader->setText(mText);
+	}
+	if (mCollapsedExtent != mHeader->mBounds.extent)
+	{
+		mHeader->mBounds.extent.set(mCollapsedExtent.x, mCollapsedExtent.y);
+	}
+	if (mHeader->mProfile != mProfile)
+	{
+		mHeader->setControlProfile(mProfile);
+	}
+
+	//Render the childen
+	RectI contentRect = RectI(offset, mBounds.extent);
+	renderChildControls(offset, contentRect, updateRect);
+}
+
+void GuiPanelCtrl::setControlProfile(GuiControlProfile *prof)
+{
+	Parent::setControlProfile(prof);
+	mHeader->setControlProfile(prof);
+}
+
+bool GuiPanelCtrl::calcExpandedExtent()
+{
+	if (!size())
+		return false;
+
+	mExpandedExtent = Point2I(0, 0);
+	for (iterator itr = begin(); itr != end(); ++itr)
+	{
+		GuiControl* child = dynamic_cast<GuiControl*>(*itr);
+		mExpandedExtent.setMax(child->getExtent() + child->getPosition());
+	}
+
+	mExpandedExtent.set(getMax(mCollapsedExtent.x, mExpandedExtent.x), getMax(mCollapsedExtent.y, mExpandedExtent.y));
+
+	return true;
+}

+ 56 - 0
engine/source/gui/containers/guiPanelCtrl.h

@@ -0,0 +1,56 @@
+//-----------------------------------------------------------------------------
+// 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 _GUIPANELCTRL_H_
+#define _GUIPANELCTRL_H_
+
+#ifndef _GUIEXPANDCTRL_H_
+#include "gui/containers/guiExpandCtrl.h"
+#endif
+
+#ifndef _GUIBUTTONCTRL_H_
+#include "gui/buttons/guiButtonCtrl.h"
+#endif
+
+class GuiPanelCtrl : public GuiExpandCtrl
+{
+private:
+   typedef GuiExpandCtrl Parent;
+   GuiButtonCtrl*      mHeader;
+
+protected:
+	virtual bool calcExpandedExtent();
+
+public:
+	GuiPanelCtrl();
+	virtual ~GuiPanelCtrl();
+
+	bool onAdd();
+	virtual void onRender(Point2I offset, const RectI &updateRect);
+
+   static void initPersistFields();
+   DECLARE_CONOBJECT(GuiPanelCtrl);
+
+   virtual void setControlProfile(GuiControlProfile *prof);
+};
+
+#endif

+ 27 - 0
engine/source/gui/containers/guiPanelCtrl_ScriptBinding.h

@@ -0,0 +1,27 @@
+//-----------------------------------------------------------------------------
+// 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.
+//-----------------------------------------------------------------------------
+
+ConsoleMethodGroupBeginWithDocs(GuiPanelCtrl, GuiControl)
+
+//Empty, for now...
+
+ConsoleMethodGroupEndWithDocs(GuiPanelCtrl)

+ 7 - 1
engine/source/gui/containers/guiScrollCtrl.cc

@@ -216,7 +216,7 @@ GuiControl* GuiScrollCtrl::findHitControl(const Point2I& pt, S32 initialLayer)
 				Point2I ptemp = pt - (ctrl->mBounds.point + ctrl->mRenderInsetLT);
 				GuiControl* hitCtrl = ctrl->findHitControl(ptemp);
 
-				if (hitCtrl->mProfile->mModal)
+				if (hitCtrl->mProfile->mUseInput)
 					return hitCtrl;
 			}
 		}
@@ -302,6 +302,12 @@ void GuiScrollCtrl::computeSizes()
 			mHBarEnabled = true;
 		if (mChildExt.y > mContentExt.y)
 			mVBarEnabled = true;
+
+		//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);
 	}
 	// build all the rectangles and such...
 	calcScrollRects();

+ 2 - 3
engine/source/gui/editor/guiMenuBar.cc

@@ -954,9 +954,8 @@ void GuiMenuBar::onRender(Point2I offset, const RectI &updateRect)
 
    RectI ctrlRect(offset, mBounds.extent);
 
-   //if opaque, fill the update rect with the fill color
-   if (mProfile->mOpaque)
-      dglDrawRectFill(RectI(offset, mBounds.extent), mProfile->mFillColor);
+   //fill the update rect with the fill color
+   dglDrawRectFill(RectI(offset, mBounds.extent), mProfile->mFillColor);
 
    //if there's a border, draw the border
    //if (mProfile->mBorder)

+ 15 - 34
engine/source/gui/guiCanvas.cc

@@ -570,10 +570,7 @@ void GuiCanvas::rootMouseDown(const GuiEvent &event)
          GuiControl *ctrl = static_cast<GuiControl *>(*i);
          GuiControl *controlHit = ctrl->findHitControl(event.mousePoint);
 
-         //see if the controlHit is a modeless dialog...
-         if ((! controlHit->mActive) && (! controlHit->mProfile->mModal))
-            continue;
-         else
+         if (controlHit->mProfile->mUseInput)
          {
             controlHit->onTouchDown(event);
             break;
@@ -633,14 +630,11 @@ void GuiCanvas::rootScreenTouchDown(const GuiEvent &event)
                 }  
             }  
               
-            //see if the controlHit is a modeless dialog...  
-            if ((! controlHit->mActive) && (! controlHit->mProfile->mModal))  
-                continue;  
-            else  
-            {  
-                controlHit->onTouchDown(event);  
-                break;  
-            }  
+			if (controlHit->mProfile->mUseInput)
+			{
+				controlHit->onTouchDown(event);
+				break;
+			}
         }  
       
     if (bool(mMouseControl))  
@@ -660,14 +654,11 @@ void GuiCanvas::rootScreenTouchUp(const GuiEvent &event)
         GuiControl *ctrl = static_cast<GuiControl *>(*i);
         GuiControl *controlHit = ctrl->findHitControl(event.mousePoint);
         
-        //see if the controlHit is a modeless dialog...
-        if ((! controlHit->mActive) && (! controlHit->mProfile->mModal))
-            continue;
-        else
-        {
-            controlHit->onTouchUp(event);
-            break;
-        }
+		if (controlHit->mActive && controlHit->mProfile->mUseInput)
+		{
+			controlHit->onTouchUp(event);
+			break;
+		}
     }
 }
 
@@ -945,8 +936,10 @@ void GuiCanvas::setContentControl(GuiControl *gui)
       GuiControl *ctrl = static_cast<GuiControl *>(*i);
       ctrl->buildAcceleratorMap();
 
-      if (ctrl->mProfile->mModal)
-         break;
+	  if (ctrl->mProfile->mUseInput)
+	  {
+		  break;
+	  }
    }
    refreshMouseControl();
 
@@ -1006,11 +999,6 @@ void GuiCanvas::pushDialogControl(GuiControl *gui, S32 layer)
       ctrl->buildAcceleratorMap();
    }
    refreshMouseControl();
-   if(gui->mProfile && gui->mProfile->mModal)
-   {
-      Input::pushCursor(CursorManager::curArrow);
-
-   }
 }
 
 void GuiCanvas::popDialogControl(GuiControl *gui)
@@ -1022,13 +1010,6 @@ void GuiCanvas::popDialogControl(GuiControl *gui)
    GuiControl *ctrl = NULL;
    if (gui)
    {
-      //*** DAW: For modal dialogs, reset the mouse cursor and enable the appropriate platform menus
-      if(gui->mProfile && gui->mProfile->mModal)
-      {
-         Input::popCursor();
-
-      }
-
       //make sure the gui really exists on the stack
       iterator i;
       bool found = false;

+ 9 - 4
engine/source/gui/guiControl.cc

@@ -119,7 +119,12 @@ bool GuiControl::onAdd()
 
 void GuiControl::onChildAdded( GuiControl *child )
 {
-   // Base class does not make use of this
+	if(mProfile)
+	{
+		//This will cause the child control to be centered if it needs to be.
+		RectI innerRect = this->getInnerRect(mBounds.point, mBounds.extent, GuiControlState::NormalState, mProfile);
+		child->parentResized(innerRect.extent, innerRect.extent);
+	}
 }
 
 static EnumTable::Enums horzEnums[] =
@@ -242,7 +247,7 @@ void GuiControl::addObject(SimObject *object)
    if(mAwake)
       ctrl->awaken();
 
-  // If we are a child, notify our parent that we've been removed
+  // If we are a child, notify our parent that we've been added
   GuiControl *parent = ctrl->getParent();
   if( parent )
      parent->onChildAdded( ctrl );
@@ -403,7 +408,7 @@ void GuiControl::setHeight( S32 newHeight )
 
 void GuiControl::childResized(GuiControl *child)
 {
-   // default to do nothing...
+   // Default to do nothing. Do not call resize from here as it will create an infinite loop.
 }
 
 void GuiControl::parentResized(const Point2I &oldParentExtent, const Point2I &newParentExtent)
@@ -1150,7 +1155,7 @@ GuiControl* GuiControl::findHitControl(const Point2I &pt, S32 initialLayer)
          Point2I ptemp = pt - (ctrl->mBounds.point + ctrl->mRenderInsetLT);
          GuiControl *hitCtrl = ctrl->findHitControl(ptemp);
 
-         if(hitCtrl->mProfile->mModal)
+         if(hitCtrl->mProfile->mUseInput)
             return hitCtrl;
       }
    }

+ 10 - 1
engine/source/gui/guiControl.h

@@ -56,6 +56,10 @@
 #include "platform/Tickable.h"
 #endif
 
+#ifndef _MFLUID_H_
+#include "math/mFluid.h"
+#endif
+
 class GuiCanvas;
 class GuiEditCtrl;
 
@@ -184,6 +188,11 @@ public:
 		tRotateRight
 	};
 
+	ColorI mFillColor; //Replaces the default fill color provided by the profile.
+	ColorI mFillColorHL; //The highlight fill color used when the cursor enters the control.
+	ColorI mFillColorSL; //Color used when the control is selected.
+	ColorI mFillColorNA; //Used if the object is not active or disabled.
+
 protected:
     /// @name Control State
     /// @{
@@ -672,7 +681,7 @@ public:
     ///
     /// @see GuiControlProfile
     /// @param   prof   Control profile to apply
-    void setControlProfile(GuiControlProfile *prof);
+    virtual void setControlProfile(GuiControlProfile *prof);
 
     /// Occurs when this control performs its "action"
     virtual void onAction();

+ 10 - 8
engine/source/gui/guiDefaultControlRender.cc

@@ -26,7 +26,13 @@
 #include "graphics/gColor.h"
 #include "math/mRect.h"
 
-void renderBorderedRect(RectI &bounds, GuiControlProfile *profile, GuiControlState state )
+void renderBorderedRect(RectI &bounds, GuiControlProfile *profile, GuiControlState state)
+{
+	ColorI fillColor = profile->getFillColor(state);
+	renderBorderedRect(bounds, profile, state, fillColor);
+}
+
+void renderBorderedRect(RectI &bounds, GuiControlProfile *profile, GuiControlState state, const ColorI &fillColor)
 {
 	//Get the border profiles
 	GuiBorderProfile *leftProfile = profile->getLeftBorder();
@@ -35,7 +41,6 @@ void renderBorderedRect(RectI &bounds, GuiControlProfile *profile, GuiControlSta
 	GuiBorderProfile *bottomProfile = profile->getBottomBorder();
 
 	//Get the colors
-	ColorI fillColor = profile->getFillColor(state);
 	ColorI leftColor = (leftProfile) ? leftProfile->getBorderColor(state) : ColorI();
 	ColorI rightColor = (rightProfile) ? rightProfile->getBorderColor(state) : ColorI();
 	ColorI topColor = (topProfile) ? topProfile->getBorderColor(state) : ColorI();
@@ -50,7 +55,7 @@ void renderBorderedRect(RectI &bounds, GuiControlProfile *profile, GuiControlSta
 	RectI innerRect = RectI(bounds.point.x + leftSize, bounds.point.y + topSize, (bounds.extent.x - leftSize) - rightSize, (bounds.extent.y - topSize) - bottomSize);
 
 	//Draw the fill
-	if(profile->mOpaque)
+	if(fillColor.alpha > 0)
 	{
 		S32 fillWidth = innerRect.extent.x + ((leftProfile && leftProfile->mUnderfill) ? leftSize : 0) + ((rightProfile && rightProfile->mUnderfill) ? rightSize : 0);
 		S32 fillHeight = innerRect.extent.y + ((topProfile && topProfile->mUnderfill) ? topSize : 0) + ((bottomProfile && bottomProfile->mUnderfill) ? bottomSize : 0);
@@ -101,11 +106,8 @@ void renderBorderedCircle(Point2I &center, S32 radius, GuiControlProfile *profil
 	S32 borderSize = (profile->mBorderDefault) ? profile->mBorderDefault->getBorder(state) : 0;
 
 	//Draw the fill
-	if (profile->mOpaque)
-	{
-		S32 fillRadius = (profile->mBorderDefault && profile->mBorderDefault->mUnderfill) ? radius : radius - borderSize;
-		dglDrawCircleFill(center, (F32)fillRadius, fillColor);
-	}
+	S32 fillRadius = (profile->mBorderDefault && profile->mBorderDefault->mUnderfill) ? radius : radius - borderSize;
+	dglDrawCircleFill(center, (F32)fillRadius, fillColor);
 
 	//Draw the border
 	dglDrawCircle(center, (F32)radius, borderColor, (F32)borderSize);

+ 1 - 0
engine/source/gui/guiDefaultControlRender.h

@@ -30,6 +30,7 @@
 class GuiControlProfile;
 
 void renderBorderedRect(RectI &bounds, GuiControlProfile *profile, GuiControlState state);
+void renderBorderedRect(RectI &bounds, GuiControlProfile *profile, GuiControlState state, const ColorI &fillColor);
 void renderBorderedCircle(Point2I &center, S32 radius, GuiControlProfile *profile, GuiControlState state);
 void renderSizableBitmapBordersFilled(RectI &bounds, S32 baseMultiplier, GuiControlProfile *profile); 
 void renderSizableBitmapBordersFilledIndex(RectI &bounds, S32 startIndex, GuiControlProfile *profile);

+ 8 - 40
engine/source/gui/guiTypes.cc

@@ -234,8 +234,7 @@ GuiControlProfile::GuiControlProfile(void) :
     
     mTabable       = false;
     mCanKeyFocus   = false;
-    
-    mOpaque        = true;
+	mUseInput      = true;
 
 	mBorderDefault = NULL;
 	mBorderLeft = NULL;
@@ -253,47 +252,17 @@ GuiControlProfile::GuiControlProfile(void) :
     mBitmapName    = NULL;
     mTextOffset.set(0,0);
     
-    //used by GuiTextCtrl
-    mModal         = true;
     mAlignment     = LeftAlign;
 	mVAlignment    = MiddleVAlign;
     mReturnTab     = false;
     mNumbersOnly   = false;
     mProfileForChildren = NULL;
-/*
-   GuiControlProfile *def = dynamic_cast<GuiControlProfile*>(Sim::findObject("GuiDefaultProfile"));
-   if (def)
-   {
-      mTabable       = def->mTabable;
-      mCanKeyFocus   = def->mCanKeyFocus;
-      mMouseOverSelected = def->mMouseOverSelected;
-
-      mOpaque        = def->mOpaque;
-      mFillColor     = def->mFillColor;
-      mFillColorHL   = def->mFillColorHL;
-      mFillColorNA   = def->mFillColorNA;
-
-      // default font
-      mFontType      = def->mFontType;
-      mFontSize      = def->mFontSize;
-      mFontCharset   = def->mFontCharset;
-
-      for(U32 i = 0; i < 10; i++)
-         mFontColors[i] = def->mFontColors[i];
-
-      // default bitmap
-      mTextOffset    = def->mTextOffset;
-
-      //used by GuiTextCtrl
-      mModal         = def->mModal;
-      mAlignment     = def->mAlignment;
-      mAutoSizeWidth = def->mAutoSizeWidth;
-      mAutoSizeHeight= def->mAutoSizeHeight;
-      mReturnTab     = def->mReturnTab;
-      mNumbersOnly   = def->mNumbersOnly;
-      mCursorColor   = def->mCursorColor;
-      mProfileForChildren = def->mProfileForChildren;
-   }*/
+
+	//fill color
+	mFillColor.set(0, 0, 0, 0);
+	mFillColorHL.set(0, 0, 0, 0);
+	mFillColorSL.set(0, 0, 0, 0);
+	mFillColorNA.set(0, 0, 0, 0);
 }
 
 GuiControlProfile::~GuiControlProfile()
@@ -307,10 +276,9 @@ void GuiControlProfile::initPersistFields()
 
    addField("tab",           TypeBool,       Offset(mTabable, GuiControlProfile));
    addField("canKeyFocus",   TypeBool,       Offset(mCanKeyFocus, GuiControlProfile));
+   addField("useInput",      TypeBool,       Offset(mUseInput, GuiControlProfile));
    addField("mouseOverSelected", TypeBool,   Offset(mMouseOverSelected, GuiControlProfile));
 
-   addField("modal",         TypeBool,       Offset(mModal, GuiControlProfile));
-   addField("opaque",        TypeBool,       Offset(mOpaque, GuiControlProfile));
    addField("fillColor",     TypeColorI,     Offset(mFillColor, GuiControlProfile));
    addField("fillColorHL",   TypeColorI,     Offset(mFillColorHL, GuiControlProfile));
    addField("fillColorSL",   TypeColorI,     Offset(mFillColorSL, GuiControlProfile));

+ 9 - 8
engine/source/gui/guiTypes.h

@@ -35,6 +35,10 @@
 #include "graphics/gColor.h"
 #endif
 
+#ifndef _FLUID_H_
+#include "math/mFluid.h"
+#endif
+
 #ifndef _SIMBASE_H_
 #include "sim/simBase.h"
 #endif
@@ -77,8 +81,6 @@ enum GuiControlState
 	StateCount					//Not an actual state! Should always be at the end of the list.
 };
 
-
-
 enum class GuiDirection
 {
 	Up,				
@@ -156,13 +158,12 @@ public:
 
    static StringTableEntry  sFontCacheDirectory;
    bool mCanKeyFocus;                              ///< True if the object can be given keyboard focus (in other words, made a first responder @see GuiControl)
-   bool mModal;                                    ///< True if this is a Modeless dialog meaning it will pass input through instead of taking it all
+   bool mUseInput;                                 ///< True if input events like a click can be passed to this object. False will pass events to the parent and this object and its children will not be evaluated.
 
-   bool mOpaque;                                   ///< True if this object should render its fill color
-   ColorI mFillColor;                              ///< Fill color, this is used to fill the bounds of the control if it is opaque
-   ColorI mFillColorHL;                            ///< This is used insetead of mFillColor if the object is highlited
-   ColorI mFillColorSL;								//Color used when the control is selected.
-   ColorI mFillColorNA;                            ///< This is used to instead of mFillColor if the object is not active or disabled
+   ColorI mFillColor; //Normal fill color used to fill the control area inside (and possibly under) the border.
+   ColorI mFillColorHL; //The highlight fill color used when the cursor enters the control.
+   ColorI mFillColorSL;	//Color used when the control is selected.
+   ColorI mFillColorNA; //Used if the object is not active or disabled.
 
    GuiBorderProfile *mBorderDefault;					//The default border settings.
    GuiBorderProfile *mBorderTop;

+ 118 - 0
engine/source/math/mFluid.cpp

@@ -0,0 +1,118 @@
+//-----------------------------------------------------------------------------
+// Copyright (c) 2012 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 "platform/platform.h"
+#include "math/mFluid.h"
+
+Fluid::Fluid()
+{
+	mAnimationLength = 1000;
+	mAnimationProgress = 1.0f;
+	mEasingFunction = EasingFunction::Linear;
+}
+
+Fluid::~Fluid() { }
+
+void Fluid::startFluidAnimation()
+{
+	mAnimationProgress = 0.0f;
+}
+
+F32 Fluid::getProgress(const S32 time)
+{
+	mAnimationProgress += (F32)((F32)time / (F32)mAnimationLength);
+
+	F32 progress = 1.0f;
+	if (mAnimationProgress < 1.0f)
+	{
+		progress = mEase(mEasingFunction, mAnimationProgress);
+	}
+	return progress;
+}
+
+void Fluid::setEasingFunction(const char* label)
+{
+	EasingFunction f = Linear;
+	for (U32 i = 0; i < (sizeof(easingEnums) / sizeof(EnumTable::Enums)); i++)
+	{
+		if (dStricmp(easingEnums[i].label, label) == 0)
+			f = (EasingFunction)easingEnums[i].index;
+	}
+
+	mEasingFunction = f;
+}
+
+const char* Fluid::getEasingFunctionDescription(const EasingFunction ease)
+{
+	for (U32 i = 0; i < (sizeof(easingEnums) / sizeof(EnumTable::Enums)); i++)
+	{
+		if (easingEnums[i].index == ease)
+			return easingEnums[i].label;
+	}
+
+	return StringTable->EmptyString;
+}
+
+//------------------------------------------------------------------------
+
+void FluidColorI::startFluidAnimation(const ColorI &color)
+{
+	mAnimationProgress = 0.0f;
+
+	redStart = red;
+	greenStart = green;
+	blueStart = blue;
+	alphaStart = alpha;
+
+	redTarget = color.red;
+	greenTarget = color.green;
+	blueTarget = color.blue;
+	alphaTarget = color.alpha;
+}
+
+//Returns true if we should continue to processTicks 
+bool FluidColorI::processTick()
+{
+	F32 progress = getProgress(32.0f);
+
+	red = processValue(progress, redStart, redTarget);
+	green = processValue(progress, greenStart, greenTarget);
+	blue = processValue(progress, blueStart, blueTarget);
+	alpha = processValue(progress, alphaStart, alphaTarget);
+
+	clamp();
+
+	if (mAnimationProgress >= 1.0f)
+	{
+		mAnimationProgress = 1.0f;
+		return false;
+	}
+	return true;
+}
+
+void FluidColorI::set(const ColorI& in_rCopy)
+{
+	red = in_rCopy.red;
+	green = in_rCopy.green;
+	blue = in_rCopy.blue;
+	alpha = in_rCopy.alpha;
+}

+ 86 - 0
engine/source/math/mFluid.h

@@ -0,0 +1,86 @@
+//-----------------------------------------------------------------------------
+// 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 _MFLUID_H_
+#define _MFLUID_H_
+
+#ifndef _PLATFORM_H_
+#include "platform/platform.h"
+#endif
+
+#ifndef _MMATHFN_H_
+#include "math/mMathFn.h"
+#endif
+
+#ifndef _COLOR_H_
+#include "graphics/gColor.h"
+#endif
+
+class Fluid
+{
+protected:
+	F32 mAnimationProgress; //a time value between 0 and 1 
+	S32 mAnimationLength; //Length of the currently playing animation in milliseconds.
+	EasingFunction mEasingFunction;
+
+public:
+	Fluid();
+	~Fluid();
+
+	inline S32 getAnimationLength() { return mAnimationLength; }
+	inline void setAnimationLength(S32 time) { mAnimationLength = time; }
+
+	inline EasingFunction getEasingFunction() { return mEasingFunction; }
+	inline void setEasingFunction(EasingFunction ease) { mEasingFunction = ease; }
+	void setEasingFunction(const char* label);
+	const char* getEasingFunctionDescription(const EasingFunction ease);
+
+	virtual void startFluidAnimation(); //starts an animation.
+	inline void stopFluidAnimation() { mAnimationProgress = 1.0f; }
+	inline bool isAnimating() { return mAnimationProgress < 1.0f; }
+	F32 getProgress(const S32 time); //Returns the progress to the target with 0 as starting and 1 as the target.
+
+	inline U8 processValue(const F32 progress, const U8 start, const U8 target) { return start + (U8)mRound((target - start) * progress); };
+	inline S32 processValue(const F32 progress, const S32 start, const S32 target) { return start + (S32)mRound((target - start) * progress); };
+	inline F32 processValue(const F32 progress, const F32 start, const F32 target) { return start + ((target - start) * progress); };
+};
+
+class FluidColorI : public ColorI, public Fluid
+{
+protected:
+	U8 redStart;
+	U8 greenStart;
+	U8 blueStart;
+	U8 alphaStart;
+
+	U8 redTarget;
+	U8 greenTarget;
+	U8 blueTarget;
+	U8 alphaTarget;
+
+public:
+	virtual void startFluidAnimation(const ColorI &color);
+	virtual bool processTick(); //Returns true if we should continue to processTicks
+	void set(const ColorI& in_rCopy);
+};
+
+#endif // _MFLUID_H_

+ 6 - 7
toybox/Sandbox/1/gui/guiProfiles.cs

@@ -37,7 +37,7 @@ else
 
 new GuiCursor(DefaultCursor)
 {
-    hotSpot = "4 4";
+    hotSpot = "3 3";
     renderOffset = "0 0";
     bitmapName = "^Sandbox/gui/images/defaultCursor";
 };
@@ -54,16 +54,15 @@ if(!isObject(GuiDefaultProfile)) new GuiControlProfile (GuiDefaultProfile)
     mouseOverSelected = false;
 
     // fill color
-    opaque = false;
-    fillColor = "211 211 211";
-    fillColorHL = "244 244 244";
-    fillColorNA = "244 244 244";
+    fillColor = "211 211 211 0";
+    fillColorHL = "244 244 244 0";
+    fillColorNA = "244 244 244 0";
 
     // border color
     border = 0;
     borderColor   = "100 100 100 255";
-    borderColorHL = "128 128 128";
-    borderColorNA = "64 64 64";
+    borderColorHL = "128 128 128 255";
+    borderColorNA = "64 64 64 255";
 
     // font
     fontType = $platformFontType;

+ 118 - 119
toybox/TruckToy/1/main.cs

@@ -21,7 +21,7 @@
 //-----------------------------------------------------------------------------
 
 function TruckToy::create( %this )
-{        
+{
     TruckToy.ObstacleFriction = 1.5;
     TruckToy.CameraWidth = 20;
     TruckToy.CameraHeight = 15;
@@ -35,7 +35,7 @@ function TruckToy::create( %this )
     TruckToy.GroundDomain = 18;
     TruckToy.ObstacleDomain = 15;
     TruckToy.ProjectileDomain = 16;
-    TruckToy.ForegroundDomain = 10;    
+    TruckToy.ForegroundDomain = 10;
 
     TruckToy.WheelSpeed = 400;
     TruckToy.WheelFriction = 1;
@@ -45,9 +45,9 @@ function TruckToy::create( %this )
     TruckToy.RearWheelDrive = true;
     TruckToy.ProjectileRate = 3000;
     TruckToy.ExplosionScale = 1;
-    
+
     TruckToy.RotateCamera = true;
-    
+
     // Add the custom controls.
     addNumericOption( "Wheel Speed", 100, 1000, 50, "setWheelSpeed", TruckToy.WheelSpeed, false, "Sets the rotational speed of the wheel when it is put into drive." );
     addNumericOption( "Wheel Friction", 0, 10, 1, "setWheelFriction", TruckToy.WheelFriction, true, "Sets the friction for the surface of each wheel." );
@@ -63,7 +63,7 @@ function TruckToy::create( %this )
 
     // Reset the toy.
     %this.reset();
-	
+
 }
 
 //-----------------------------------------------------------------------------
@@ -77,12 +77,12 @@ function TruckToy::destroy( %this )
 //-----------------------------------------------------------------------------
 
 function TruckToy::reset( %this )
-{   
+{
     // Clear the scene.
-    SandboxScene.clear();    
-    
+    SandboxScene.clear();
+
     // Set a typical Earth gravity.
-    SandboxScene.setGravity( 0, -9.8 );  
+    SandboxScene.setGravity( 0, -9.8 );
 
     // Camera Configuration
     SandboxWindow.setCameraPosition( TruckToy.WorldLeft + (TruckToy.CameraWidth/2) - 10, 0 );
@@ -90,27 +90,27 @@ function TruckToy::reset( %this )
     SandboxWindow.setCameraSize( TruckToy.CameraWidth, TruckToy.CameraHeight );
     SandboxWindow.setViewLimitOn( TruckToy.WorldLeft, TruckToy.CameraHeight/-2, TruckToy.WorldRight, TruckToy.CameraHeight/2 );
 
-    // Create the scene contents in a roughly left to right order.      
+    // Create the scene contents in a roughly left to right order.
 
     // Background.
     %this.createBackground();
 
     // Floor.
     %this.createFloor();
-     
+
     // Wrecked cars at start.
     %this.createWreckedCar( 1, -90, TruckToy.FloorLevel + 0.75, 0, true );
     %this.createWreckedCar( 2, -85, TruckToy.FloorLevel + 0.75, 0, true );
     %this.createWreckedCar( 3, -82, TruckToy.FloorLevel + 0.75, 0, true );
     %this.createWreckedCar( 1, -87.123, -2.478, 2.537, true );
-    %this.createBrick( 3, -87.5, TruckToy.FloorLevel + 0.25, true );     
-    %this.createBrick( 4, -87.5, TruckToy.FloorLevel + 0.75, true );     
-    %this.createBrick( 2, -79, TruckToy.FloorLevel + 0.25, true );     
+    %this.createBrick( 3, -87.5, TruckToy.FloorLevel + 0.25, true );
+    %this.createBrick( 4, -87.5, TruckToy.FloorLevel + 0.75, true );
+    %this.createBrick( 2, -79, TruckToy.FloorLevel + 0.25, true );
     %this.createBonfire( -91.5, TruckToy.FloorLevel + 0.5, 1, TruckToy.BackgroundDomain-1 );
 
-    // Building with chains.   
-    %this.createForegroundWall( 2, -99, -5 );   
-    %this.createForegroundWall( 1, -75.5, -6.5 );  
+    // Building with chains.
+    %this.createForegroundWall( 2, -99, -5 );
+    %this.createForegroundWall( 1, -75.5, -6.5 );
     %this.createBrokenCementWall( -78, -1.5 );
     %this.createWreckedBuilding( -71.5, -1 );
     %this.createWoodPile( -65, -2.5 );
@@ -118,7 +118,7 @@ function TruckToy::reset( %this )
     %this.createForegroundBrickWall( 1, -61, -6 );
     %this.createBonfire( -82, TruckToy.FloorLevel + 0.5, 1.5, TruckToy.ObstacleDomain+1 );
 
-    // Start of bridge.   
+    // Start of bridge.
     %this.createPlank( 1, -53, TruckToy.FloorLevel + 0.5, 0, true );
     %this.createPlank( 1, -50.1522, -2.3, 21.267, true );
     %this.createWreckedCar( 2, -47, TruckToy.FloorLevel + 1.9, -100, true );
@@ -126,14 +126,14 @@ function TruckToy::reset( %this )
     %this.createPlank( 2, -44, TruckToy.FloorLevel + 2, -90, true );
     %this.createPlank( 1, -43, TruckToy.FloorLevel + 2, -90, true );
     %this.createPlank( 2, -42, TruckToy.FloorLevel + 2, -90, true );
-    %this.createPlank( 1, -41, TruckToy.FloorLevel + 2, -90, true );  
-    %this.createForegroundWall( 2, -42, -4.5 );  
+    %this.createPlank( 1, -41, TruckToy.FloorLevel + 2, -90, true );
+    %this.createForegroundWall( 2, -42, -4.5 );
     %this.createBridge( -41, TruckToy.FloorLevel + 4, 40 );
     for ( %n = 0; %n < 10; %n++ )
     {
-      %brick = %this.createBrickStack( getRandom(1,5), -39 + getRandomF(0,16), TruckToy.FloorLevel + 5, false );     
+      %brick = %this.createBrickStack( getRandom(1,5), -39 + getRandomF(0,16), TruckToy.FloorLevel + 5, false );
       %brick.setAwake(true);
-    }   
+    }
     %this.createPlank( 1, -20.5, TruckToy.FloorLevel + 1.5, -90, true );
     %this.createPlank( 3, -19, TruckToy.FloorLevel + 4, 0, true );
     %this.createPlank( 1, -16.5, TruckToy.FloorLevel + 1.5, -90, true );
@@ -146,25 +146,25 @@ function TruckToy::reset( %this )
     %this.createWreckedCar( 2, -7, TruckToy.FloorLevel + 0.75, 0, true );
     %this.createWreckedCar( 3, -4, TruckToy.FloorLevel + 0.75, 0, true );
     %this.createBonfire( -5, TruckToy.FloorLevel + 0.5, 1, TruckToy.BackgroundDomain-1 );
-     
-     
-    // ************************************************************************   
+
+
+    // ************************************************************************
     // Start of pyramid.
-    // ************************************************************************   
-    %this.createPyramid( 2, TruckToy.FloorLevel + 0.25, 19, true );   
+    // ************************************************************************
+    %this.createPyramid( 2, TruckToy.FloorLevel + 0.25, 19, true );
     %this.createForegroundWall( 1, 9, -6 );
     %this.createPyramid( 2+21, TruckToy.FloorLevel + 0.25, 13, true );
     %this.createForegroundBrickWall( 1, 9, -7 );
     %this.createBonfire( 21, TruckToy.FloorLevel, 3, TruckToy.BackgroundDomain-1 );
 
 
-    // ************************************************************************   
+    // ************************************************************************
     // Start of brick stacks.
-    // ************************************************************************      
+    // ************************************************************************
     %this.createBrickStack( 45, TruckToy.FloorLevel + 0.25, 10, false );
     %this.createBrickStack( 47, TruckToy.FloorLevel + 0.25, 1, true );
     %this.createBrickStack( 49, TruckToy.FloorLevel + 0.25, 10, false );
-     
+
     %this.createBrickStack( 72, TruckToy.FloorLevel + 0.25, 1, true );
     %this.createBrickStack( 74, TruckToy.FloorLevel + 0.25, 10, false );
     %this.createBrickStack( 76, TruckToy.FloorLevel + 0.25, 1, true );
@@ -175,9 +175,9 @@ function TruckToy::reset( %this )
 
     // Truck.
     %truckStartX = TruckToy.WorldLeft + (TruckToy.CameraWidth/6);
-    %truckStartY = 3;   
-    %this.createTruck( %truckStartX, %truckStartY );    
-    
+    %truckStartY = 3;
+    %this.createTruck( %truckStartX, %truckStartY );
+
     // Start the timer.
     TruckToy.startTimer( "createProjectile", TruckToy.ProjectileRate );
 }
@@ -185,7 +185,7 @@ function TruckToy::reset( %this )
 // -----------------------------------------------------------------------------
 
 function TruckToy::createBackground(%this)
-{  
+{
     // Atmosphere
     %obj = new Sprite();
     %obj.setBodyType( "static" );
@@ -197,7 +197,7 @@ function TruckToy::createBackground(%this)
     %obj.setCollisionSuppress();
     %obj.setAwake( false );
     %obj.setActive( false );
-    SandboxScene.add( %obj );  
+    SandboxScene.add( %obj );
 
 
     // Industrial Background
@@ -206,26 +206,26 @@ function TruckToy::createBackground(%this)
     %obj.setImage( "TruckToy:industrial_02" );
     %obj.setPosition( 0, -1 );
     %obj.setSize( TruckToy.WorldWidth, 8 );
-    %obj.setRepeatX( TruckToy.WorldWidth / 8 );   
+    %obj.setRepeatX( TruckToy.WorldWidth / 8 );
     %obj.setSceneLayer( TruckToy.BackgroundDomain);
     %obj.setSceneGroup( TruckToy.BackgroundDomain);
     %obj.setCollisionSuppress();
     %obj.setAwake( false );
     %obj.setActive( false );
-    SandboxScene.add( %obj );    
+    SandboxScene.add( %obj );
 }
 
 // -----------------------------------------------------------------------------
 
 function TruckToy::createFloor(%this)
 {
-    // Ground  
+    // Ground
     %obj = new Scroller();
     %obj.setBodyType( "static" );
     %obj.setImage( "ToyAssets:woodGround" );
     %obj.setSize( TruckToy.WorldWidth, 3 );
     %obj.setPosition( 0, TruckToy.FloorLevel - (%obj.getSizeY()/2) );
-    %obj.setRepeatX( TruckToy.WorldWidth / 12 );   
+    %obj.setRepeatX( TruckToy.WorldWidth / 12 );
     %obj.setSceneLayer( TruckToy.ObstacleDomain );
     %obj.setSceneGroup( TruckToy.GroundDomain );
     %obj.setDefaultFriction( TruckToy.ObstacleFriction );
@@ -235,14 +235,14 @@ function TruckToy::createFloor(%this)
     %obj.createEdgeCollisionShape( TruckToy.WorldWidth/2, 3, TruckToy.WorldWidth/2, 50 );
     %obj.CollisionCallback = true;
     %obj.setAwake( false );
-    SandboxScene.add( %obj );   
+    SandboxScene.add( %obj );
 }
 
 // -----------------------------------------------------------------------------
 
 function TruckToy::createBrokenCementWall( %this, %posX, %posY )
 {
-    %obj = new Sprite();   
+    %obj = new Sprite();
     %obj.setBodyType( "static" );
     %obj.setImage( "TruckToy:brokenCementWall" );
     %obj.setPosition( %posX, %posY );
@@ -254,14 +254,14 @@ function TruckToy::createBrokenCementWall( %this, %posX, %posY )
     %obj.setActive( false );
     SandboxScene.add( %obj );
 
-    return %obj;   
+    return %obj;
 }
 
 // -----------------------------------------------------------------------------
 
 function TruckToy::createWoodPile( %this, %posX, %posY )
 {
-    %obj = new Sprite();   
+    %obj = new Sprite();
     %obj.setBodyType( "static" );
     %obj.setImage( "TruckToy:woodPile" );
     %obj.setPosition( %posX, %posY );
@@ -273,7 +273,7 @@ function TruckToy::createWoodPile( %this, %posX, %posY )
     %obj.setActive( false );
     SandboxScene.add( %obj );
 
-    return %obj;   
+    return %obj;
 }
 
 // -----------------------------------------------------------------------------
@@ -282,8 +282,8 @@ function TruckToy::createBrickStack( %this, %posX, %posY, %brickCount, %static )
 {
     for ( %n = 0; %n < %brickCount; %n++ )
     {
-        %this.createBrick( getRandom(1,5), %posX, %posY + (%n*0.5), %static );     
-    }      
+        %this.createBrick( getRandom(1,5), %posX, %posY + (%n*0.5), %static );
+    }
 }
 
 // -----------------------------------------------------------------------------
@@ -312,11 +312,11 @@ function TruckToy::createPyramid( %this, %posX, %posY, %brickBaseCount, %static
 
 function TruckToy::createBridge( %this, %posX, %posY, %linkCount )
 {
-   
+
    %linkWidth = 0.5;
    %linkHeight = %linkWidth * 0.5;
    %halfLinkWidth = %linkWidth * 0.5;
-   
+
    %rootObj = new Sprite();
    %rootObj.setBodyType( "static" );
    %rootObj.setImage( "ToyAssets:cable" );
@@ -328,24 +328,24 @@ function TruckToy::createBridge( %this, %posX, %posY, %linkCount )
    SandboxScene.add( %rootObj );
 
    %lastLinkObj = %rootObj;
-   
+
    for ( %n = 1; %n <= %linkCount; %n++ )
    {
       %obj = new Sprite();
-         
+
       %obj.setImage( "ToyAssets:cable" );
       %obj.setPosition( %posX + (%n*%linkWidth), %posY );
       %obj.setSize( %linkWidth, %linkHeight );
       %obj.setSceneLayer( TruckToy.BackgroundDomain-3 );
       %obj.setSceneGroup( TruckToy.ObstacleDomain );
-      
+
       if ( %n == %linkCount )
       {
          %obj.setBodyType( "static" );
          %obj.setCollisionSuppress();
       }
       else
-      {      
+      {
          %obj.setCollisionGroups( none );
          %obj.setDefaultDensity( 1 );
          %obj.setDefaultFriction( TruckToy.ObstacleFriction );
@@ -354,19 +354,19 @@ function TruckToy::createBridge( %this, %posX, %posY, %linkCount )
          %obj.setLinearDamping( 1.0 );
       }
       //%obj.setDebugOn( 5 );
-      SandboxScene.add( %obj );   
-      
+      SandboxScene.add( %obj );
+
       SandboxScene.createRevoluteJoint( %lastLinkObj, %obj, %halfLinkWidth, 0, -%halfLinkWidth, 0 );
       %joint = SandboxScene.createMotorJoint( %lastLinkObj, %obj );
       SandboxScene.setMotorJointMaxForce( %joint, 1000 );
       %obj.setAwake( false );
       %lastLinkObj.setAwake( false );
       //%obj.setDebugOn( 5 );
-      
+
       %lastLinkObj = %obj;
    }
-   
-   return %lastLinkObj;        
+
+   return %lastLinkObj;
 }
 
 // -----------------------------------------------------------------------------
@@ -395,16 +395,16 @@ function TruckToy::createChain( %this, %posX, %posY, %linkCount )
         {
             %obj = new Sprite();
             %obj.setImage( "ToyAssets:chain" );
-            %obj.setPosition( %posX, %posY - (%n*%linkHeight) );        
+            %obj.setPosition( %posX, %posY - (%n*%linkHeight) );
             %obj.setSize( %linkWidth, %linkHeight );
-            SandboxScene.add( %obj );   
+            SandboxScene.add( %obj );
         }
         else
         {
-            %obj = %this.createBonfire( %posX, %posY - (%n*%linkHeight), 0.5, TruckToy.BackgroundDomain-1 );                    
+            %obj = %this.createBonfire( %posX, %posY - (%n*%linkHeight), 0.5, TruckToy.BackgroundDomain-1 );
             %obj.BodyType = dynamic;
         }
-        
+
         %obj.setSceneLayer( TruckToy.BackgroundDomain-1 );
         %obj.setSceneGroup( TruckToy.ObstacleDomain );
         %obj.setCollisionGroups( none );
@@ -421,14 +421,14 @@ function TruckToy::createChain( %this, %posX, %posY, %linkCount )
 
     %lastLinkObj.setAwake(false);
 
-    return %lastLinkObj;        
+    return %lastLinkObj;
 }
 
 // -----------------------------------------------------------------------------
 
 function TruckToy::createWreckedBuilding( %this, %posX, %posY )
 {
-    %obj = new Sprite();   
+    %obj = new Sprite();
     %obj.setBodyType( "static" );
     %obj.setImage( "TruckToy:wreckedBuilding" );
     %obj.setPosition( %posX, %posY );
@@ -440,10 +440,10 @@ function TruckToy::createWreckedBuilding( %this, %posX, %posY )
     %obj.setActive( false );
     SandboxScene.add( %obj );
 
-    %this.createChain( %posX - 3, %posY + 3.4, 10 );   
-    %this.createChain( %posX - 1, %posY + 3.2, 10 );   
-    %this.createChain( %posX + 1, %posY + 3.0, 10 );   
-    %this.createChain( %posX + 3, %posY + 2.8, 10 );   
+    %this.createChain( %posX - 3, %posY + 3.4, 10 );
+    %this.createChain( %posX - 1, %posY + 3.2, 10 );
+    %this.createChain( %posX + 1, %posY + 3.0, 10 );
+    %this.createChain( %posX + 3, %posY + 2.8, 10 );
 }
 
 // -----------------------------------------------------------------------------
@@ -457,10 +457,10 @@ function TruckToy::createForegroundBrickWall( %this, %wallNumber, %posX, %posY )
     }
 
     %image = "TruckToy:brickWall_0" @ %wallNumber;
-      
-    %obj = new Sprite();   
+
+    %obj = new Sprite();
     %obj.setBodyType( "static" );
-      
+
     %obj.setImage( %image );
     %obj.setPosition( %posX, %posY );
     %obj.setSize( 10, 5 );
@@ -470,9 +470,9 @@ function TruckToy::createForegroundBrickWall( %this, %wallNumber, %posX, %posY )
     %obj.setAwake( false );
     %obj.setActive( false );
     SandboxScene.add( %obj );
-      
 
-    return %obj;   
+
+    return %obj;
 }
 
 // -----------------------------------------------------------------------------
@@ -486,10 +486,10 @@ function TruckToy::createForegroundWall( %this, %wallNumber, %posX, %posY )
     }
 
     %image = "TruckToy:foregroundWall_0" @ %wallNumber;
-      
-    %obj = new Sprite();   
+
+    %obj = new Sprite();
     %obj.setBodyType( "static" );
-      
+
     %obj.setImage( %image );
     %obj.setPosition( %posX, %posY );
     %obj.setSize( 6, 6 );
@@ -500,7 +500,7 @@ function TruckToy::createForegroundWall( %this, %wallNumber, %posX, %posY )
     %obj.setActive( false );
     SandboxScene.add( %obj );
 
-    return %obj;   
+    return %obj;
 }
 
 // -----------------------------------------------------------------------------
@@ -515,7 +515,7 @@ function TruckToy::createBrick( %this, %brickNumber, %posX, %posY, %static )
 
     %image = "ToyAssets:brick_0" @ %brickNumber;
 
-    %obj = new Sprite();   
+    %obj = new Sprite();
     if ( %static ) %obj.setBodyType( "static" );
     %obj.setImage( %image );
     %obj.setPosition( %posX, %posY );
@@ -535,7 +535,7 @@ function TruckToy::createBrick( %this, %brickNumber, %posX, %posY, %static )
 
 function TruckToy::createBrickPile( %this, %posX, %posY )
 {
-    %obj = new Sprite();   
+    %obj = new Sprite();
     %obj.setBodyType( "static" );
     %obj.setImage( "TruckToy:brickPile" );
     %obj.setPosition( %posX, %posY );
@@ -545,7 +545,7 @@ function TruckToy::createBrickPile( %this, %posX, %posY )
     %obj.setCollisionSuppress();
     %obj.setAwake( false );
     %obj.setActive( false );
-    SandboxScene.add( %obj );   
+    SandboxScene.add( %obj );
 }
 
 // -----------------------------------------------------------------------------
@@ -560,12 +560,12 @@ function TruckToy::createPlank( %this, %plankNumber, %posX, %posY, %angle, %stat
 
     %image = "TruckToy:plank_0" @ %plankNumber;
 
-    %obj = new Sprite();   
+    %obj = new Sprite();
     if ( %static ) %obj.setBodyType( "static" );
     %obj.setImage( %image );
     %obj.setAngle( %angle );
     %obj.setPosition( %posX, %posY );
-    %obj.setSize( 5, 1 );   
+    %obj.setSize( 5, 1 );
     %obj.setSceneLayer( TruckToy.ObstacleDomain );
     %obj.setSceneGroup( TruckToy.ObstacleDomain );
     %obj.setDefaultFriction( TruckToy.ObstacleFriction );
@@ -574,8 +574,8 @@ function TruckToy::createPlank( %this, %plankNumber, %posX, %posY, %angle, %stat
     %obj.setDefaultFriction( 1.0 );
 
     switch$( %plankNumber )
-    {  
-        case 1: 
+    {
+        case 1:
             %obj.createPolygonCollisionShape( "-2.5 -0.5 2.5 -0.5 2.5 -0.2 2.0 0.5 -2.5 -0.2" );
         case 2:
             %obj.createPolygonCollisionShape( "-2.5 -0.4 2.4 -0.5 2.4 0.5 0 0.5 -2.1 0.1 -2.5 -0.2" );
@@ -585,7 +585,7 @@ function TruckToy::createPlank( %this, %plankNumber, %posX, %posY, %angle, %stat
 
     SandboxScene.add( %obj );
 
-    return %obj;   
+    return %obj;
 }
 
 // -----------------------------------------------------------------------------
@@ -600,12 +600,12 @@ function TruckToy::createWreckedCar( %this, %carNumber, %posX, %posY, %angle, %s
 
     %image = "TruckToy:wreckedCar_0" @ %carNumber;
 
-    %obj = new Sprite();   
+    %obj = new Sprite();
     if ( %static ) %obj.setBodyType( "static" );
     %obj.setImage( %image );
     %obj.setAngle( %angle );
     %obj.setPosition( %posX, %posY );
-    %obj.setSize( 4, 1.5 );   
+    %obj.setSize( 4, 1.5 );
     %obj.setSceneLayer( TruckToy.ObstacleDomain );
     %obj.setSceneGroup( TruckToy.ObstacleDomain );
     %obj.setCollisionGroups( TruckToy.GroundDomain, TruckToy.ObstacleDomain );
@@ -613,8 +613,8 @@ function TruckToy::createWreckedCar( %this, %carNumber, %posX, %posY, %angle, %s
     %obj.setDefaultFriction( TruckToy.ObstacleFriction );
 
     switch$( %carNumber )
-    {  
-        case 1: 
+    {
+        case 1:
             %obj.createPolygonCollisionShape( "-2 -0.65 0.5 -0.75 2 -0.45 1.9 0.2 0.5 0.65 -0.5 0.6 -2 -0.3" );
         case 2:
             %obj.createPolygonCollisionShape( "-2 -0.75 2 -0.75 2 -0.2 0.4 0.65 -0.9 0.7 -2 0.0" );
@@ -640,9 +640,9 @@ function TruckToy::createBonfire(%this, %x, %y, %scale, %layer)
     %particlePlayer.Particle = "ToyAssets:bonfire";
     %particlePlayer.SizeScale = %scale;
     %particlePlayer.CameraIdleDistance = TruckToy.CameraWidth * 0.8;
-    SandboxScene.add( %particlePlayer ); 
+    SandboxScene.add( %particlePlayer );
     return %particlePlayer;
-    
+
 }
 
 // -----------------------------------------------------------------------------
@@ -651,7 +651,7 @@ function TruckToy::createProjectile(%this)
 {
     // Fetch the truck position.
     %truckPositionX = TruckToy.TruckBody.Position.x;
-    
+
     %projectile = new Sprite() { class = "TruckProjectile"; };
     %projectile.Animation = "ToyAssets:Projectile_FireballAnim";
     %projectile.setPosition( getRandom( %truckPositionX - (TruckToy.CameraWidth * 0.2), %truckPositionX + (TruckToy.CameraWidth * 0.5) ), 12 );
@@ -660,32 +660,32 @@ function TruckToy::createProjectile(%this)
     %projectile.FlipY = true;
     %projectile.Size = getRandom(0.5, 2);
     %projectile.Lifetime = 2.5;
-    %projectile.createCircleCollisionShape( 0.2 ); 
+    %projectile.createCircleCollisionShape( 0.2 );
     %projectile.setCollisionGroups( TruckToy.GroundDomain );
     %projectile.CollisionCallback = true;
-    SandboxScene.add( %projectile ); 
+    SandboxScene.add( %projectile );
 }
 
 // -----------------------------------------------------------------------------
 
 function TruckProjectile::onCollision(%this, %object, %collisionDetails)
-{   
+{
     // Create an impact explosion at the projectiles position.
     %particlePlayer = new ParticlePlayer();
     %particlePlayer.BodyType = Static;
-    %particlePlayer.Position = %this.Position;    
+    %particlePlayer.Position = %this.Position;
     %particlePlayer.Size = 10;
     %particlePlayer.SceneLayer = TruckToy.BackgroundDomain-1;
     %particlePlayer.ParticleInterpolation = true;
     %particlePlayer.Particle = "ToyAssets:ImpactExplosion";
     %particlePlayer.SizeScale = getRandom(TruckToy.ExplosionScale, TruckToy.ExplosionScale * 1.5);
-    SandboxScene.add( %particlePlayer ); 
-    
+    SandboxScene.add( %particlePlayer );
+
     // Start the camera shaking.
     SandboxWindow.startCameraShake( 10 + (3 * TruckToy.ExplosionScale), 1 );
-    
+
     // Delete the projectile.
-    %this.safeDelete();   
+    %this.safeDelete();
 }
 
 // -----------------------------------------------------------------------------
@@ -711,11 +711,11 @@ function TruckToy::createTruck( %this, %posX, %posY )
     TruckToy.TruckBody.setSceneLayer( TruckToy.TruckDomain );
     TruckToy.TruckBody.setSceneGroup( TruckToy.ObstacleDomain);
     TruckToy.TruckBody.setCollisionGroups( TruckToy.ObstacleDomain, TruckToy.ObstacleDomain-1, TruckToy.GroundDomain );
-    TruckToy.TruckBody.createPolygonCollisionShape( "-2 0.2 -2 -0.5 0 -.95 2 -0.5 2 0.0 0 0.7 -1.5 0.7" ); 
+    TruckToy.TruckBody.createPolygonCollisionShape( "-2 0.2 -2 -0.5 0 -.95 2 -0.5 2 0.0 0 0.7 -1.5 0.7" );
     //TruckToy.TruckBody.setDebugOn( 5 );
     SandboxScene.add( TruckToy.TruckBody );
 
-    // Attach the exhaust output to the truck body.   
+    // Attach the exhaust output to the truck body.
     %joint = SandboxScene.createRevoluteJoint( TruckToy.TruckBody, TruckToy.TruckExhaust, "-2.3 -0.6", "0 0" );
     SandboxScene.setRevoluteJointLimit( %joint, 0, 0 );
 
@@ -724,9 +724,9 @@ function TruckToy::createTruck( %this, %posX, %posY )
     SandboxWindow.mount( TruckToy.TruckBody, "0 0", 3, true, TruckToy.RotateCamera );
 
     // Tires.
-    // Suspension = -1.0 : -1.5   
+    // Suspension = -1.0 : -1.5
 
-    // Rear tire.   
+    // Rear tire.
     %tireRear = new Sprite();
     %tireRear.setPosition( %posX-1.4, %posY-1.0 );
     %tireRear.setImage( "ToyAssets:tires" );
@@ -736,10 +736,10 @@ function TruckToy::createTruck( %this, %posX, %posY )
     %tireRear.setCollisionGroups( TruckToy.ObstacleDomain, TruckToy.GroundDomain );
     %tireRear.setDefaultFriction( TruckToy.WheelFriction );
     %tireRear.setDefaultDensity( TruckToy.RearWheelDensity );
-    %tireRear.createCircleCollisionShape( 0.8 ); 
+    %tireRear.createCircleCollisionShape( 0.8 );
     SandboxScene.add( %tireRear );
     TruckToy.RearWheel = %tireRear;
-    
+
     // Front tire.
     %tireFront = new Sprite();
     %tireFront.setPosition( %posX+1.7, %posY-1.0 );
@@ -750,13 +750,13 @@ function TruckToy::createTruck( %this, %posX, %posY )
     %tireFront.setCollisionGroups( TruckToy.ObstacleDomain, TruckToy.GroundDomain );
     %tireFront.setDefaultFriction( TruckToy.WheelFriction );
     %tireFront.setDefaultDensity( TruckToy.FrontWheelDensity );
-    %tireFront.createCircleCollisionShape( 0.8 ); 
-    SandboxScene.add( %tireFront );   
+    %tireFront.createCircleCollisionShape( 0.8 );
+    SandboxScene.add( %tireFront );
     TruckToy.FrontWheel = %tireFront;
 
     // Suspension joints.
     TruckToy.RearMotorJoint = SandboxScene.createWheelJoint( TruckToy.TruckBody, %tireRear, "-1.4 -1.25", "0 0", "0 1" );
-    TruckToy.FrontMotorJoint = SandboxScene.createWheelJoint( TruckToy.TruckBody, %tireFront, "1.7 -1.25", "0 0", "0 1" );     
+    TruckToy.FrontMotorJoint = SandboxScene.createWheelJoint( TruckToy.TruckBody, %tireFront, "1.7 -1.25", "0 0", "0 1" );
 }
 
 // -----------------------------------------------------------------------------
@@ -764,7 +764,7 @@ function TruckToy::createTruck( %this, %posX, %posY )
 function truckForward(%val)
 {
     if(%val)
-    { 
+    {
         if ( !TruckToy.TruckMoving )
         {
             %driveActive = false;
@@ -777,7 +777,7 @@ function truckForward(%val)
             {
                 SandboxScene.setWheelJointMotor( TruckToy.FrontMotorJoint, false );
             }
-            
+
             if ( TruckToy.RearWheelDrive )
             {
                 SandboxScene.setWheelJointMotor( TruckToy.RearMotorJoint, true, -TruckToy.WheelSpeed, 10000 );
@@ -786,15 +786,15 @@ function truckForward(%val)
             else
             {
                 SandboxScene.setWheelJointMotor( TruckToy.RearMotorJoint, false );
-            }            
-            
+            }
+
             if ( %driveActive )
             {
                 TruckToy.TruckExhaust.SizeScale *= 4;
                 TruckToy.TruckExhaust.ForceScale /= 2;
             }
         }
-              
+
         TruckToy.TruckMoving = true;
     }
     else
@@ -830,14 +830,14 @@ function truckReverse(%val)
             {
                 SandboxScene.setWheelJointMotor( TruckToy.RearMotorJoint, false );
             }
-            
+
             if ( %driveActive )
             {
                 TruckToy.TruckExhaust.SizeScale *= 4;
                 TruckToy.TruckExhaust.ForceScale /= 2;
-            }            
+            }
         }
-              
+
         TruckToy.TruckMoving = true;
     }
     else
@@ -860,7 +860,7 @@ function TruckToy::truckStop(%this)
     TruckToy.TruckExhaust.SizeScale /= 4;
     TruckToy.TruckExhaust.ForceScale *= 2;
 
-    // Flag truck as not moving.    
+    // Flag truck as not moving.
     TruckToy.TruckMoving = false;
 }
 
@@ -911,7 +911,7 @@ function TruckToy::setRearWheelDrive( %this, %value )
 function TruckToy::setProjectileRate( %this, %value )
 {
     %this.ProjectileRate = %value;
-    
+
     // Start the timer.
     TruckToy.startTimer( "createProjectile", TruckToy.ProjectileRate );
 }
@@ -956,4 +956,3 @@ function TruckToy::onTouchUp(%this, %touchID, %worldPosition)
     // Stop the truck.
     TruckToy.truckStop();
 }
-