Browse Source

GuiColorPopupCtrl

This adds a new color control to T2D! The GuiColorPopupCtrl is a fully functional color popup that needs very little configuration to use. Although you could easily build your own color popup using the GuiColorPickerCtrl, this one is ready to use and customizable enough to be useful in most projects.
Peter Robinson 2 years ago
parent
commit
9fbeeb6170

+ 28 - 0
editor/EditorCore/Themes/BaseTheme/BaseTheme.cs

@@ -2245,6 +2245,34 @@ function BaseTheme::makeColorPickerProfile(%this)
 		
 		
 		borderDefault = %selBorder;
 		borderDefault = %selBorder;
 	};
 	};
+
+	%colorPopupBorder = new GuiBorderProfile()
+	{
+		border = 1;
+		borderHL = 1;
+		borderSL = 1;
+		borderNA = 1;
+
+		borderColor = %this.adjustValue(%this.color1, -5);
+		borderColorHL = %this.adjustValue(%this.color1, -5);
+		borderColorSL = %this.adjustValue(%this.color1, -5);
+		borderColorNA = %this.adjustValue(%this.color1, -5);
+
+		padding = 3;
+		paddingHL = 3;
+		paddingSL = 3;
+		paddingNA = 3;
+	};
+
+	%this.colorPopupProfile = new GuiControlProfile()
+	{
+		fillColor = %this.color1;
+		fillColorHL = %this.color1;
+		fillColorSL = %this.color1;
+		fillColorNA = %this.color1;
+
+		borderDefault = %colorPopupBorder;
+	};
 }
 }
 
 
 //Positive values are brighter, negative are darker
 //Positive values are brighter, negative are darker

+ 89 - 0
editor/EditorCore/gui/guiProfiles.cs

@@ -544,4 +544,93 @@ function EditorCore::createGuiProfiles(%this)
 		canKeyFocus = true;
 		canKeyFocus = true;
 		tab = true;
 		tab = true;
 	});
 	});
+
+	%this.SafeCreateNamedObject("GuiColorPopupBorderProfile", new GuiBorderProfile()
+	{
+		border = 1;
+		borderHL = 1;
+		borderSL = 1;
+		borderNA = 1;
+
+		borderColor = %this.AdjustColorValue(%this.color1, -5);
+		borderColorHL = %this.AdjustColorValue(%this.color1, -5);
+		borderColorSL = %this.AdjustColorValue(%this.color1, -5);
+		borderColorNA = %this.AdjustColorValue(%this.color1, -5);
+
+		padding = 3;
+		paddingHL = 3;
+		paddingSL = 3;
+		paddingNA = 3;
+	});
+
+	%this.SafeCreateNamedObject("GuiColorPopupProfile", new GuiControlProfile()
+	{
+		fillColor = %this.color1;
+		fillColorHL = %this.color1;
+		fillColorSL = %this.color1;
+		fillColorNA = %this.color1;
+
+		borderDefault = GuiColorPopupBorderProfile;
+	});
+
+	%this.SafeCreateNamedObject("GuiColorPickerBorderProfile", new GuiBorderProfile()
+	{
+		border = 1;
+		borderHL = 1;
+		borderSL = 1;
+		borderNA = 1;
+
+		borderColor = %this.color1;
+		borderColorHL = %this.color2;
+		borderColorSL = %this.color4;
+		borderColorNA = %this.color1;
+
+		padding = 1;
+		paddingHL = 1;
+		paddingSL = 1;
+		paddingNA = 1;
+
+		margin = 1;
+		marginHL = 1;
+		marginSL = 1;
+		marginNA = 1;
+	});
+
+	%this.SafeCreateNamedObject("GuiColorPickerProfile", new GuiControlProfile()
+	{
+		fillColor = "0 0 0 0";
+		fillColorHL = "0 0 0 0";
+		fillColorSL = "0 0 0 0";
+		fillColorNA = "0 0 0 0";
+		
+		borderDefault = GuiColorPickerBorderProfile;
+
+		tab = false;
+		canKeyFocus = true;
+		underfill = true;
+	});
+
+	%this.SafeCreateNamedObject("GuiColorSelectorBorderProfile", new GuiBorderProfile()
+	{
+		border = 1;
+		borderHL = 1;
+		borderSL = 1;
+
+		borderColor = "0 0 0 180";
+		borderColorHL = "0 0 0 190";
+		borderColorSL = "0 0 0 220";
+
+		//Margin and padding are used to determine the size of the selector ring in the normal state.
+		padding = 2;//Radius of the outer circle minus the inner circle. The meat of the donut.
+		margin = 1;//Radius of the inner circle plus 1. This is different from the normal use of the margin.
+	});
+
+	%this.SafeCreateNamedObject("GuiColorSelectorProfile", new GuiControlProfile()
+	{
+		fillColor = "240 240 240 255";
+		fillColorHL = "250 250 250 255";
+		fillColorSL = %this.color5;
+		
+		borderDefault = GuiColorSelectorBorderProfile;
+	});
 }
 }

+ 34 - 13
editor/GuiEditor/scripts/GuiEditorColorWindow.cs

@@ -8,30 +8,51 @@ function GuiEditorColorWindow::onAdd(%this)
         VertSizing = "height";
         VertSizing = "height";
         Position = "7 10";
         Position = "7 10";
         Extent = (%ext.x - 23) SPC (%ext.y - 43);
         Extent = (%ext.x - 23) SPC (%ext.y - 43);
-        CellSizeX = "50";
-        CellSizeY = "200";
-        CellModeX = "Variable";
+        CellSizeX = "40";
+        CellSizeY = "40";
+        CellModeX = "Absolute";
         CellModeY = "Absolute";
         CellModeY = "Absolute";
-        MaxColCount = "2";
+        MaxColCount = "4";
         IsExtentDynamic = "1";
         IsExtentDynamic = "1";
         OrderMode = "LRTB";
         OrderMode = "LRTB";
     };
     };
     ThemeManager.setProfile(%this.grid, "EmptyProfile");
     ThemeManager.setProfile(%this.grid, "EmptyProfile");
     %this.add(%this.grid);
     %this.add(%this.grid);
 
 
-    %this.addColorCtrl(1, "Pallet");
-    %this.addColorCtrl(6, "BlendColor");
-    %this.addColorCtrl(2, "HorizColor");
-    %this.addColorCtrl(3, "VertColor");
-    %this.addColorCtrl(4, "HorizBrightnessColor");
-    %this.addColorCtrl(5, "VertBrightnessColor");
-    %this.addColorCtrl(7, "HorizAlpha");
-    %this.addColorCtrl(8, "VertAlpha");
-    %this.addColorCtrl(9, "Dropper");
+    //%this.addColorCtrl(1, "Pallet");
+    //%this.addColorCtrl(6, "BlendColor");
+    //%this.addColorCtrl(2, "HorizColor");
+    //%this.addColorCtrl(3, "VertColor");
+    //%this.addColorCtrl(4, "HorizBrightnessColor");
+    //%this.addColorCtrl(5, "VertBrightnessColor");
+    //%this.addColorCtrl(7, "HorizAlpha");
+    //%this.addColorCtrl(8, "VertAlpha");
+    //%this.addColorCtrl(9, "Dropper");
+    %this.addColorCtrl(10, "Popup");
+    %this.addColorCtrl(11, "Popup");
+    %this.addColorCtrl(12, "Popup");
+    %this.addColorCtrl(13, "Popup");
 }
 }
 
 
 function GuiEditorColorWindow::addColorCtrl(%this, %i, %mode)
 function GuiEditorColorWindow::addColorCtrl(%this, %i, %mode)
 {
 {
+    if(%mode $= "Popup")
+    {
+        %this.colorCtrl[%i] = new GuiColorPopupCtrl()
+        {
+            HorizSizing = "width";
+            VertSizing = "height";
+        };
+        ThemeManager.setProfile(%this.colorCtrl[%i], "colorPickerProfile");
+        ThemeManager.setProfile(%this.colorCtrl[%i], "emptyProfile", "backgroundProfile");
+        ThemeManager.setProfile(%this.colorCtrl[%i], "colorPopupProfile", "popupProfile");
+        ThemeManager.setProfile(%this.colorCtrl[%i], "emptyProfile", "pickerProfile");
+        ThemeManager.setProfile(%this.colorCtrl[%i], "colorPickerSelectorProfile", "selectorProfile");
+        %this.grid.add(%this.colorCtrl[%i]);
+
+        return;
+    }
+
     %this.colorCtrl[%i] = new GuiColorPickerCtrl()
     %this.colorCtrl[%i] = new GuiColorPickerCtrl()
     {
     {
         HorizSizing = "width";
         HorizSizing = "width";

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

@@ -633,6 +633,7 @@
     <ClCompile Include="..\..\source\gui\guiArrayCtrl.cc" />
     <ClCompile Include="..\..\source\gui\guiArrayCtrl.cc" />
     <ClCompile Include="..\..\source\gui\guiCanvas.cc" />
     <ClCompile Include="..\..\source\gui\guiCanvas.cc" />
     <ClCompile Include="..\..\source\gui\guiColorPickerCtrl.cc" />
     <ClCompile Include="..\..\source\gui\guiColorPickerCtrl.cc" />
+    <ClCompile Include="..\..\source\gui\guiColorPopupCtrl.cc" />
     <ClCompile Include="..\..\source\gui\guiConsole.cc" />
     <ClCompile Include="..\..\source\gui\guiConsole.cc" />
     <ClCompile Include="..\..\source\gui\guiConsoleEditCtrl.cc" />
     <ClCompile Include="..\..\source\gui\guiConsoleEditCtrl.cc" />
     <ClCompile Include="..\..\source\gui\guiControl.cc" />
     <ClCompile Include="..\..\source\gui\guiControl.cc" />
@@ -1132,6 +1133,8 @@
     <ClInclude Include="..\..\source\gui\guiCanvas_ScriptBinding.h" />
     <ClInclude Include="..\..\source\gui\guiCanvas_ScriptBinding.h" />
     <ClInclude Include="..\..\source\gui\guiColorPickerCtrl.h" />
     <ClInclude Include="..\..\source\gui\guiColorPickerCtrl.h" />
     <ClInclude Include="..\..\source\gui\guiColorPickerCtrl_ScriptBinding.h" />
     <ClInclude Include="..\..\source\gui\guiColorPickerCtrl_ScriptBinding.h" />
+    <ClInclude Include="..\..\source\gui\guiColorPopupCtrl.h" />
+    <ClInclude Include="..\..\source\gui\guiColorPopupCtrl_ScriptBinding.h" />
     <ClInclude Include="..\..\source\gui\guiConsole.h" />
     <ClInclude Include="..\..\source\gui\guiConsole.h" />
     <ClInclude Include="..\..\source\gui\guiConsoleEditCtrl.h" />
     <ClInclude Include="..\..\source\gui\guiConsoleEditCtrl.h" />
     <ClInclude Include="..\..\source\gui\guiControl.h" />
     <ClInclude Include="..\..\source\gui\guiControl.h" />

+ 9 - 0
engine/compilers/VisualStudio 2022/Torque 2D.vcxproj.filters

@@ -1342,6 +1342,9 @@
     <ClCompile Include="..\..\source\gui\containers\guiFrameSetCtrl.cc">
     <ClCompile Include="..\..\source\gui\containers\guiFrameSetCtrl.cc">
       <Filter>gui\containers</Filter>
       <Filter>gui\containers</Filter>
     </ClCompile>
     </ClCompile>
+    <ClCompile Include="..\..\source\gui\guiColorPopupCtrl.cc">
+      <Filter>gui</Filter>
+    </ClCompile>
   </ItemGroup>
   </ItemGroup>
   <ItemGroup>
   <ItemGroup>
     <ClInclude Include="..\..\source\audio\audio.h">
     <ClInclude Include="..\..\source\audio\audio.h">
@@ -3082,6 +3085,12 @@
     <ClInclude Include="..\..\source\gui\guiColorPickerCtrl_ScriptBinding.h">
     <ClInclude Include="..\..\source\gui\guiColorPickerCtrl_ScriptBinding.h">
       <Filter>gui</Filter>
       <Filter>gui</Filter>
     </ClInclude>
     </ClInclude>
+    <ClInclude Include="..\..\source\gui\guiColorPopupCtrl.h">
+      <Filter>gui</Filter>
+    </ClInclude>
+    <ClInclude Include="..\..\source\gui\guiColorPopupCtrl_ScriptBinding.h">
+      <Filter>gui</Filter>
+    </ClInclude>
   </ItemGroup>
   </ItemGroup>
   <ItemGroup>
   <ItemGroup>
     <ResourceCompile Include="Torque 2D.rc" />
     <ResourceCompile Include="Torque 2D.rc" />

+ 5 - 5
engine/source/graphics/dgl.h

@@ -30,12 +30,12 @@
 #include "platform/platformGL.h"
 #include "platform/platformGL.h"
 #endif
 #endif
 
 
+#include "graphics/gColor.h"
+
 class TextureObject;
 class TextureObject;
 class GFont;
 class GFont;
 class MatrixF;
 class MatrixF;
 class RectI;
 class RectI;
-class ColorI;
-class ColorF;
 class Point2I;
 class Point2I;
 class Point2F;
 class Point2F;
 class Point3F;
 class Point3F;
@@ -366,8 +366,8 @@ glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
 #endif
 #endif
 
 
 
 
-#endif // _H_DGL
-
 void dglDrawBlendBox(const RectI& bounds, ColorF& c1, ColorF& c2, ColorF& c3, ColorF& c4);
 void dglDrawBlendBox(const RectI& bounds, ColorF& c1, ColorF& c2, ColorF& c3, ColorF& c4);
 void dglDrawBlendRangeBox(const RectI& bounds, bool vertical, U8 numColors, ColorI* colors);
 void dglDrawBlendRangeBox(const RectI& bounds, bool vertical, U8 numColors, ColorI* colors);
-void dglRenderCheckers(const RectI& bounds, const U8 size, const ColorF& c1, const ColorF& c2);
+void dglRenderCheckers(const RectI& bounds, const U8 size = 12, const ColorF& c1 = ColorF(0.5f, 0.5f, 0.5f, 1.0f), const ColorF& c2 = ColorF(0.63f, 0.63f, 0.63f, 1.0f));
+
+#endif // _H_DGL

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

@@ -111,6 +111,8 @@ class ColorF
                                       (blue  >= 0.0f && blue  <= 1.0f) &&
                                       (blue  >= 0.0f && blue  <= 1.0f) &&
                                       (alpha >= 0.0f && alpha <= 1.0f); }
                                       (alpha >= 0.0f && alpha <= 1.0f); }
    void clamp();
    void clamp();
+   F32 getHue() const; //Returns the hue as a value between [0, 360). With zero as red, 120 as green, and 240 as blue.
+   ColorF getHueColor() const; //Returns a color based on the hue where at least one value is a 1.
 
 
    inline StringTableEntry stringThis(void) const   { char buffer[64]; dSprintf(buffer, 64, "%f %f %f %f", red, green, blue, alpha ); return StringTable->insert(buffer); }
    inline StringTableEntry stringThis(void) const   { char buffer[64]; dSprintf(buffer, 64, "%f %f %f %f", red, green, blue, alpha ); return StringTable->insert(buffer); }
    inline const char* scriptThis(void) const        { char* pBuffer = Con::getReturnBuffer(64); dSprintf(pBuffer, 32, "%.5f %.5f %.5f %.5f", red, green, blue, alpha ); return pBuffer; }
    inline const char* scriptThis(void) const        { char* pBuffer = Con::getReturnBuffer(64); dSprintf(pBuffer, 32, "%.5f %.5f %.5f %.5f", red, green, blue, alpha ); return pBuffer; }
@@ -473,6 +475,72 @@ inline void ColorF::clamp()
 
 
 //-----------------------------------------------------------------------------
 //-----------------------------------------------------------------------------
 
 
+inline F32 ColorF::getHue() const
+{
+	F32 b = mSqrt(3) * (green - blue);
+	F32 a = (2 * red) - green - blue;
+	F32 hue;
+
+	if (b == 0 && a == 0)
+		hue = 0;
+	else
+		hue = mRadToDeg(atan2(b, a));
+
+	while (hue < 0)
+		hue += 360;
+
+	return hue;
+}
+
+//-----------------------------------------------------------------------------
+
+inline ColorF ColorF::getHueColor() const
+{
+	F32 hue = getHue(); //hue is [0, 360)
+
+	F32 r, g, b;
+	if (hue >= 0 && hue < 60)
+	{
+		r = 1.0f;
+		g = hue / 60.0f;
+		b = 0.0f;
+	}
+	else if (hue >= 60 && hue < 120)
+	{
+		r = 1.0f - ((hue - 60.0f) / 60.0f);
+		g = 1.0f;
+		b = 0.0f;
+	}
+	else if (hue >= 120 && hue < 180)
+	{
+		r = 0.0f;
+		g = 1.0f;
+		b = (hue - 120.0f) / 60.0f;
+	}
+	else if (hue >= 180 && hue < 240)
+	{
+		r = 0.0f;
+		g = 1.0f - ((hue - 180.0f) / 60.0f);
+		b = 1.0f;
+	}
+	else if (hue >= 240 && hue < 300)
+	{
+		r = (hue - 240.0f) / 60.0f;
+		g = 0.0f;
+		b = 1.0f;
+	}
+	else //if (hue >= 300 && hue < 360)
+	{
+		r = 1.0f;
+		g = 0.0f;
+		b = 1.0f - ((hue - 300.0f) / 60.0f);
+	}
+
+	return ColorF(r, g, b, 1.0f);
+}
+
+//-----------------------------------------------------------------------------
+
 inline void ColorI::set(const U8 in_r,
 inline void ColorI::set(const U8 in_r,
             const U8 in_g,
             const U8 in_g,
             const U8 in_b,
             const U8 in_b,

+ 79 - 49
engine/source/gui/guiColorPickerCtrl.cc

@@ -37,8 +37,6 @@ ColorF colorWhiteBlend(1., 1., 1., .75);
 ColorF colorBlack(0.0f, 0.0f, 0.0f);
 ColorF colorBlack(0.0f, 0.0f, 0.0f);
 ColorF colorAlpha(0.0f, 0.0f, 0.0f, 0.0f);
 ColorF colorAlpha(0.0f, 0.0f, 0.0f, 0.0f);
 ColorF colorAlphaW(1.0f, 1.0f, 1.0f, 0.0f);
 ColorF colorAlphaW(1.0f, 1.0f, 1.0f, 0.0f);
-ColorF colorGray1(0.5f, 0.5f, 0.5f, 1.0f);
-ColorF colorGray2(0.63f, 0.63f, 0.63f, 1.0f);
 
 
 ColorI GuiColorPickerCtrl::mColorRange[9] = {
 ColorI GuiColorPickerCtrl::mColorRange[9] = {
    ColorI(255,255,255), // White
    ColorI(255,255,255), // White
@@ -167,15 +165,19 @@ void GuiColorPickerCtrl::renderColorBox(const RectI& pickerBounds)
 		dglDrawBlendBox(pickerBounds, colorAlpha, colorBlack, colorBlack, colorAlpha);
 		dglDrawBlendBox(pickerBounds, colorAlpha, colorBlack, colorBlack, colorAlpha);
 		break;
 		break;
 	case pHorizAlphaRange:
 	case pHorizAlphaRange:
-		dglRenderCheckers(pickerBounds, 12, colorGray1, colorGray2);
+		dglRenderCheckers(pickerBounds);
 		dglDrawBlendBox(pickerBounds, baseAlpha, mBaseColor, mBaseColor, baseAlpha);
 		dglDrawBlendBox(pickerBounds, baseAlpha, mBaseColor, mBaseColor, baseAlpha);
 		break;
 		break;
 	case pVertAlphaRange:
 	case pVertAlphaRange:
-		dglRenderCheckers(pickerBounds, 12, colorGray1, colorGray2);
+		dglRenderCheckers(pickerBounds);
 		dglDrawBlendBox(pickerBounds, baseAlpha, baseAlpha, mBaseColor, mBaseColor);
 		dglDrawBlendBox(pickerBounds, baseAlpha, baseAlpha, mBaseColor, mBaseColor);
 		break;
 		break;
 	case pBlendColorRange:
 	case pBlendColorRange:
-		dglDrawBlendBox(pickerBounds, colorWhite, mBaseColor, colorBlack, colorBlack);
+		dglDrawBlendBox(pickerBounds, colorWhite, mBaseColor, mBaseColor, colorWhite);
+		blendRect = pickerBounds;
+		blendRect.point.y++;
+		blendRect.extent.y--;
+		dglDrawBlendBox(blendRect, colorAlpha, colorAlpha, colorBlack, colorBlack);
 		break;
 		break;
 	case pDropperBackground:
 	case pDropperBackground:
 		break;
 		break;
@@ -314,8 +316,7 @@ void GuiColorPickerCtrl::updatePickColor(const Point2I& offset,  const RectI& co
 		else if ((mDisplayMode == pHorizColorRange && (varX == 1.0f || varX == 0.0f)) ||
 		else if ((mDisplayMode == pHorizColorRange && (varX == 1.0f || varX == 0.0f)) ||
 			(mDisplayMode == pVertColorRange && (varY == 1.0f || varY == 0.0f)) ||
 			(mDisplayMode == pVertColorRange && (varY == 1.0f || varY == 0.0f)) ||
 			(mDisplayMode == pHorizColorBrightnessRange && varY == 0.0f && (varX == 1.0f || varX == 0.0f)) ||
 			(mDisplayMode == pHorizColorBrightnessRange && varY == 0.0f && (varX == 1.0f || varX == 0.0f)) ||
-			(mDisplayMode == pVertColorBrightnessRange && varX == 0.0f && (varY == 1.0f || varY == 0.0f)) ||
-			(mDisplayMode == pBlendColorRange && varX == 1.0f && varY == 0.0f))
+			(mDisplayMode == pVertColorBrightnessRange && varX == 0.0f && (varY == 1.0f || varY == 0.0f)))
 		{
 		{
 			mPickColor = mColorRange[1];
 			mPickColor = mColorRange[1];
 		}
 		}
@@ -338,7 +339,11 @@ void GuiColorPickerCtrl::updatePickColor(const Point2I& offset,  const RectI& co
 			{
 			{
 				mPickColor = colorWhite;
 				mPickColor = colorWhite;
 			}
 			}
-			else if(varX < 1.0f)
+			else if (varX == 1.0f)
+			{
+				mPickColor = mBaseColor;
+			}
+			else
 			{
 			{
 				mPickColor.red = 1.0f - ((1.0f - mBaseColor.red) * varX);
 				mPickColor.red = 1.0f - ((1.0f - mBaseColor.red) * varX);
 				mPickColor.green = 1.0f - ((1.0f - mBaseColor.green) * varX);
 				mPickColor.green = 1.0f - ((1.0f - mBaseColor.green) * varX);
@@ -411,28 +416,11 @@ void GuiColorPickerCtrl::setSelectorPos(const Point2I& pos)
 	setUpdate();
 	setUpdate();
 }
 }
 
 
-//--------------------------------------------------------------------------
-F32 colorHue(ColorF color)
-{
-	F32 b = mSqrt(3) * (color.green - color.blue);
-	F32 a = (2 * color.red) - color.green - color.blue;
-	F32 hue;
-
-	if (b == 0 && a == 0)
-		hue = 0;
-	else
-		hue = mRadToDeg(atan2(b, a));
-
-	while (hue < 0)
-		hue += 360;
-
-	return hue;
-}
-
-Point2I GuiColorPickerCtrl::getRangeBoxColorPos(RectI& bounds, bool vertical, ColorF targetColor)
+Point2I GuiColorPickerCtrl::getRangeBoxColorPos(bool vertical, const ColorF& targetColor)
 {
 {
 	// Calculate hue
 	// Calculate hue
-	F32 hue = colorHue(targetColor);
+	F32 hue = targetColor.getHue();
+	RectI contentRect = getInnerRect();
 
 
 	// Transform the hue value to [0-1].
 	// Transform the hue value to [0-1].
 	F32 hueFraction = hue / 360;
 	F32 hueFraction = hue / 360;
@@ -441,23 +429,23 @@ Point2I GuiColorPickerCtrl::getRangeBoxColorPos(RectI& bounds, bool vertical, Co
 	Point2I position;
 	Point2I position;
 	if (vertical)
 	if (vertical)
 	{
 	{
-		position.x = (S32)(0.5f * (bounds.extent.x));
-		position.y = (S32)((1.0f - hueFraction) * (bounds.extent.y));
+		position.x = (S32)(0.5f * (contentRect.extent.x));
+		position.y = (S32)(hueFraction * (contentRect.extent.y));
 	}
 	}
 	else
 	else
 	{
 	{
-		position.x = (S32)((1.0f - hueFraction) * (bounds.extent.x));
-		position.y = (S32)(0.5f * (bounds.extent.y));
+		position.x = (S32)(hueFraction * (contentRect.extent.x));
+		position.y = (S32)(0.5f * (contentRect.extent.y));
 	}
 	}
 
 
 	return position;
 	return position;
 }
 }
 
 
-Point2I GuiColorPickerCtrl::getBlendBoxColorPos(RectI& bounds, ColorF targetColor)
+Point2I GuiColorPickerCtrl::getBlendBoxColorPos(const ColorF& targetColor)
 {
 {
 	// Calculate hue
 	// Calculate hue
-	F32 hue = colorHue(targetColor);
-
+	F32 hue = targetColor.getHue();
+	RectI contentRect = getInnerRect();
 
 
 	// Calculate the largest, smallest RGB components of the hue
 	// Calculate the largest, smallest RGB components of the hue
 	F32 largest, smallest, baseLargest, baseSmallest;
 	F32 largest, smallest, baseLargest, baseSmallest;
@@ -516,27 +504,53 @@ Point2I GuiColorPickerCtrl::getBlendBoxColorPos(RectI& bounds, ColorF targetColo
 	F32 h = 1.0f - (smallest / largest);
 	F32 h = 1.0f - (smallest / largest);
 	F32 v = 1.0f - largest;
 	F32 v = 1.0f - largest;
 
 
-	position.x = (S32)(h * (bounds.extent.x - 1));
-	position.y = (S32)(v * (bounds.extent.y - 1));
+	position.x = (S32)(h * (contentRect.extent.x - 1));
+	position.y = (S32)(v * (contentRect.extent.y - 1));
 
 
 	return position;
 	return position;
 }
 }
 
 
-Point2I GuiColorPickerCtrl::getSelectorPositionForColor(RectI& bounds, ColorF targetColor)
+Point2I GuiColorPickerCtrl::getAlphaBoxColorPos(bool vertical, const ColorF& targetColor)
+{
+	RectI contentRect = getInnerRect();
+	Point2I position;
+
+	if (vertical)
+	{
+		position.x = contentRect.centre().x;
+		position.y = (S32)(targetColor.alpha * (contentRect.extent.y - 1));
+	}
+	else
+	{
+		position.x = (S32)(targetColor.alpha * (contentRect.extent.x - 1));
+		position.y = contentRect.centre().y;
+	}
+
+	return position;
+}
+
+Point2I GuiColorPickerCtrl::getSelectorPositionForColor(const ColorF& targetColor)
 {
 {
 	Point2I position(0, 0);
 	Point2I position(0, 0);
 
 
 	switch (mDisplayMode)
 	switch (mDisplayMode)
 	{
 	{
 	case pHorizColorRange:
 	case pHorizColorRange:
-		position = getRangeBoxColorPos(bounds, false, targetColor);
+		position = getRangeBoxColorPos(false, targetColor);
 		break;
 		break;
 	case pVertColorRange:
 	case pVertColorRange:
-		position = getRangeBoxColorPos(bounds, true, targetColor);
+		position = getRangeBoxColorPos(true, targetColor);
 		break;
 		break;
 
 
 	case pBlendColorRange:
 	case pBlendColorRange:
-		position = getBlendBoxColorPos(bounds, targetColor);
+		position = getBlendBoxColorPos(targetColor);
+		break;
+
+	case pHorizAlphaRange:
+		position = getAlphaBoxColorPos(false, targetColor);
+		break;
+	case pVertAlphaRange:
+		position = getAlphaBoxColorPos(true, targetColor);
 		break;
 		break;
 
 
 	default:
 	default:
@@ -564,11 +578,14 @@ void GuiColorPickerCtrl::onTouchDown(const GuiEvent& event)
 
 
 	// Update the picker cross position
 	// Update the picker cross position
 	if (mDisplayMode != pPallet)
 	if (mDisplayMode != pPallet)
+	{
 		setSelectorPos(globalToLocalCoord(event.mousePoint));
 		setSelectorPos(globalToLocalCoord(event.mousePoint));
+		Canvas->showCursor(false);
+	}
 
 
 	mMouseDown = true;
 	mMouseDown = true;
 
 
-	Con::executef(this, 1, "onTouchDown");
+	Parent::onTouchDown(event);
 }
 }
 
 
 //--------------------------------------------------------------------------
 //--------------------------------------------------------------------------
@@ -584,7 +601,7 @@ void GuiColorPickerCtrl::onTouchDragged(const GuiEvent& event)
 	if (!mActionOnMove && mAltConsoleCommand[0])
 	if (!mActionOnMove && mAltConsoleCommand[0])
 		Con::evaluate(mAltConsoleCommand, false);
 		Con::evaluate(mAltConsoleCommand, false);
 
 
-	Con::executef(this, 1, "onTouchDragged");
+	Parent::onTouchDragged(event);
 }
 }
 
 
 //--------------------------------------------------------------------------
 //--------------------------------------------------------------------------
@@ -594,7 +611,7 @@ void GuiColorPickerCtrl::onTouchMove(const GuiEvent& event)
 	if (mActive && (mDisplayMode == pDropperBackground))
 	if (mActive && (mDisplayMode == pDropperBackground))
 		setSelectorPos(globalToLocalCoord(event.mousePoint));
 		setSelectorPos(globalToLocalCoord(event.mousePoint));
 
 
-	Con::executef(this, 1, "onTouchMove");
+	Parent::onTouchMove(event);
 }
 }
 
 
 //--------------------------------------------------------------------------
 //--------------------------------------------------------------------------
@@ -602,20 +619,20 @@ void GuiColorPickerCtrl::onTouchEnter(const GuiEvent& event)
 {
 {
 	mMouseOver = true;
 	mMouseOver = true;
 
 
-	Con::executef(this, 1, "onTouchEnter");
+	Parent::onTouchEnter(event);
 }
 }
 
 
 //--------------------------------------------------------------------------
 //--------------------------------------------------------------------------
-void GuiColorPickerCtrl::onTouchLeave(const GuiEvent&)
+void GuiColorPickerCtrl::onTouchLeave(const GuiEvent& event)
 {
 {
 	// Reset state
 	// Reset state
 	mMouseOver = false;
 	mMouseOver = false;
 
 
-	Con::executef(this, 1, "onTouchLeave");
+	Parent::onTouchLeave(event);
 }
 }
 
 
 //--------------------------------------------------------------------------
 //--------------------------------------------------------------------------
-void GuiColorPickerCtrl::onTouchUp(const GuiEvent&)
+void GuiColorPickerCtrl::onTouchUp(const GuiEvent& event)
 {
 {
 	//if we released the mouse within this control, perform the action
 	//if we released the mouse within this control, perform the action
 	if (mActive && mMouseDown && (mDisplayMode != pDropperBackground))
 	if (mActive && mMouseDown && (mDisplayMode != pDropperBackground))
@@ -631,8 +648,9 @@ void GuiColorPickerCtrl::onTouchUp(const GuiEvent&)
 	}
 	}
 
 
 	mouseUnlock();
 	mouseUnlock();
+	Canvas->showCursor(true);
 
 
-	Con::executef(this, 1, "onTouchUp");
+	Parent::onTouchUp(event);
 }
 }
 
 
 //--------------------------------------------------------------------------
 //--------------------------------------------------------------------------
@@ -652,3 +670,15 @@ void GuiColorPickerCtrl::setScriptValue(const char* value)
 	setValue(newValue);
 	setValue(newValue);
 }
 }
 
 
+void GuiColorPickerCtrl::setControlSelectorProfile(GuiControlProfile* prof)
+{
+	AssertFatal(prof, "GuiColorPickerCtrl::setControlSelectorProfile: invalid selector profile");
+	if (prof == mSelectorProfile)
+		return;
+	if (mAwake)
+		mSelectorProfile->decRefCount();
+	mSelectorProfile = prof;
+	if (mAwake)
+		mSelectorProfile->incRefCount();
+}
+

+ 10 - 6
engine/source/gui/guiColorPickerCtrl.h

@@ -76,6 +76,9 @@ class GuiColorPickerCtrl : public GuiControl
      sVertical,			///< Vertical selector with small gap
      sVertical,			///< Vertical selector with small gap
 	 sCircle			///< Doughnut shaped circle using the selector profile
 	 sCircle			///< Doughnut shaped circle using the selector profile
    };
    };
+
+   GuiControlProfile* mSelectorProfile; //Used to render the selector.
+   void setControlSelectorProfile(GuiControlProfile* prof);
   
   
   protected:
   protected:
    
    
@@ -84,8 +87,9 @@ class GuiColorPickerCtrl : public GuiControl
    void renderColorBox(const RectI& bounds);			///< Function that draws the actual color box
    void renderColorBox(const RectI& bounds);			///< Function that draws the actual color box
    void renderSelector(const RectI& pickerBounds);
    void renderSelector(const RectI& pickerBounds);
    void drawSelector(const RectI& bounds, Point2I &selectorPos, SelectorMode mode);	///< Function that draws the selection indicator
    void drawSelector(const RectI& bounds, Point2I &selectorPos, SelectorMode mode);	///< Function that draws the selection indicator
-   Point2I getRangeBoxColorPos(RectI &bounds, bool vertical, ColorF targetColor);
-   Point2I getBlendBoxColorPos(RectI &bounds, ColorF targetColor);
+   Point2I getRangeBoxColorPos(bool vertical, const ColorF& targetColor);
+   Point2I getBlendBoxColorPos(const ColorF& targetColor);
+   Point2I getAlphaBoxColorPos(bool vertical, const ColorF& targetColor);
    /// @}
    /// @}
 
 
    /// @name Core Variables
    /// @name Core Variables
@@ -101,8 +105,6 @@ class GuiColorPickerCtrl : public GuiControl
    bool mActionOnMove;		///< Perform onAction() when position has changed?
    bool mActionOnMove;		///< Perform onAction() when position has changed?
    bool mShowSelector; ///< Display the selector lines on the control?
    bool mShowSelector; ///< Display the selector lines on the control?
 
 
-   GuiControlProfile* mSelectorProfile; //Used to render the selector.
-
    static ColorI mColorRange[9]; ///< Color range for pHorizColorRange and pVertColorRange
    static ColorI mColorRange[9]; ///< Color range for pHorizColorRange and pVertColorRange
    /// @}
    /// @}
 
 
@@ -114,8 +116,10 @@ class GuiColorPickerCtrl : public GuiControl
    bool onWake();
    bool onWake();
    void onSleep();
    void onSleep();
    void onRender(Point2I offset, const RectI &updateRect);
    void onRender(Point2I offset, const RectI &updateRect);
-   void updatePickColor(const Point2I& offset, const RectI& contentRect);
+   virtual void updatePickColor(const Point2I& offset, const RectI& contentRect);
    void resize(const Point2I& newPosition, const Point2I& newExtent);
    void resize(const Point2I& newPosition, const Point2I& newExtent);
+   void showSelector() { mShowSelector = true; }
+   void hideSelector() { mShowSelector = false; }
    
    
    /// @name Color Value Functions
    /// @name Color Value Functions
    /// @{
    /// @{
@@ -132,7 +136,7 @@ class GuiColorPickerCtrl : public GuiControl
    /// @{
    /// @{
    void setSelectorPos(const Point2I &pos); ///< Set new pos (in local coords)
    void setSelectorPos(const Point2I &pos); ///< Set new pos (in local coords)
    Point2I getSelectorPos() {return mSelectorPos;}
    Point2I getSelectorPos() {return mSelectorPos;}
-   Point2I getSelectorPositionForColor(RectI &bounds, ColorF color);
+   Point2I getSelectorPositionForColor(const ColorF& color);
    /// @}
    /// @}
    
    
    /// @name Input Events
    /// @name Input Events

+ 1 - 1
engine/source/gui/guiColorPickerCtrl_ScriptBinding.h

@@ -97,7 +97,7 @@ ConsoleMethodWithDocs(GuiColorPickerCtrl, getSelectorPosForColor, ConsoleString,
 
 
 	char* temp = Con::getReturnBuffer(256);
 	char* temp = Con::getReturnBuffer(256);
 	Point2I pos;
 	Point2I pos;
-	pos = object->getSelectorPositionForColor(object->mBounds, ColorF(red, green, blue, alpha));
+	pos = object->getSelectorPositionForColor(ColorF(red, green, blue, alpha));
 	dSprintf(temp, 256, "%d %d", pos.x, pos.y);
 	dSprintf(temp, 256, "%d %d", pos.x, pos.y);
 	return temp;
 	return temp;
 }
 }

+ 485 - 0
engine/source/gui/guiColorPopupCtrl.cc

@@ -0,0 +1,485 @@
+//-----------------------------------------------------------------------------
+// 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/guiColorPopupCtrl.h"
+#include "gui/guiCanvas.h"
+#include "console/consoleTypes.h"
+
+#include "guiColorPopupCtrl_ScriptBinding.h"
+
+ColorI blankColor(0,0,0,0);
+
+#pragma region GuiColorPopupBGCtrl
+GuiColorPopupBGCtrl::GuiColorPopupBGCtrl(GuiColorPopupCtrl* ctrl)
+{
+	mColorPopupCtrl = ctrl;
+	mBounds.point.set(0, 0);
+	setField("profile", "GuiDefaultProfile");
+}
+
+void GuiColorPopupBGCtrl::onTouchUp(const GuiEvent& event)
+{
+	mColorPopupCtrl->closeColorPopup();
+}
+#pragma endregion
+
+#pragma region GuiColorPopupContentCtrl
+GuiColorPopupContentCtrl::GuiColorPopupContentCtrl()
+{
+	setField("profile", "GuiDefaultProfile");
+}
+
+void GuiColorPopupContentCtrl::onTouchUp(const GuiEvent& event) { }
+#pragma endregion
+
+#pragma region GuiColorPopupBlendCtrl
+GuiColorPopupBlendCtrl::GuiColorPopupBlendCtrl(GuiColorPopupCtrl* ctrl, GuiColorPopupAlphaCtrl* alpha)
+{
+	mColorPopupCtrl = ctrl;
+	mAlphaCtrl = alpha;
+	setField("profile", "GuiDefaultProfile");
+}
+
+void GuiColorPopupBlendCtrl::updatePickColor(const Point2I& offset, const RectI& contentRect)
+{
+	if(mPositionChanged)
+	{
+		GuiColorPickerCtrl::updatePickColor(offset, contentRect);
+		mColorPopupCtrl->setColor(mPickColor);
+		mAlphaCtrl->setValue(mPickColor);
+	}
+}
+#pragma endregion
+
+#pragma region GuiColorPopupHueCtrl
+GuiColorPopupHueCtrl::GuiColorPopupHueCtrl(GuiColorPopupBlendCtrl* ctrl)
+{
+	mBlendCtrl = ctrl;
+	setField("profile", "GuiDefaultProfile");
+}
+
+void GuiColorPopupHueCtrl::updatePickColor(const Point2I& offset, const RectI& contentRect)
+{
+	if (mPositionChanged)
+	{
+		GuiColorPickerCtrl::updatePickColor(offset, contentRect);
+		mBlendCtrl->setValue(mPickColor);
+		mBlendCtrl->updateColor();
+	}
+}
+#pragma endregion
+
+#pragma region GuiColorPopupAlphaCtrl
+GuiColorPopupAlphaCtrl::GuiColorPopupAlphaCtrl(GuiColorPopupCtrl* ctrl)
+{
+	mColorPopupCtrl = ctrl;
+	setField("profile", "GuiDefaultProfile");
+}
+
+void GuiColorPopupAlphaCtrl::updatePickColor(const Point2I& offset, const RectI& contentRect)
+{
+	if (mPositionChanged)
+	{
+		GuiColorPickerCtrl::updatePickColor(offset, contentRect);
+		mColorPopupCtrl->setAlpha(mPickColor.alpha);
+	}
+}
+#pragma endregion
+
+IMPLEMENT_CONOBJECT(GuiColorPopupCtrl);
+
+GuiColorPopupCtrl::GuiColorPopupCtrl()
+{
+	mBounds.extent.set(140, 24);
+	mIsOpen = false;
+	mActive = true;
+	mIsContainer = false;
+	mBaseColor = ColorF(0.5f, 0.5f, 0.5f);
+	mPopupSize = Point2I(240, 208);
+	mBlendHeight = 150;
+	mBarHeight = 20;
+	mShowAlphaBar = true;
+	mBounds.extent.set(40, 40);
+
+	setField("profile", "GuiColorPopupProfile");
+
+	mBackground = new GuiColorPopupBGCtrl(this);
+	AssertFatal(mBackground, "GuiColorPopupCtrl: Failed to initialize GuiColorPopupBGCtrl!");
+	mBackgroundProfile = mBackground->mProfile;
+	mBackgroundProfile->incRefCount();
+
+	mContent = new GuiColorPopupContentCtrl();
+	AssertFatal(mContent, "GuiColorPopupCtrl: Failed to initialize GuiControl!");
+	mContent->setField("profile", "GuiDefaultProfile");
+	mPopupProfile = mContent->mProfile;
+	mPopupProfile->incRefCount();
+	mContent->setExtent(mPopupSize);
+	RectI contentRect = mContent->getInnerRect();
+
+	mColorAlphaPicker = new GuiColorPopupAlphaCtrl(this);
+	AssertFatal(mColorAlphaPicker, "GuiColorPopupCtrl: Failed to initialize GuiColorPopupAlphaCtrl!");
+	mColorAlphaPicker->setField("profile", "GuiColorPickerProfile");
+	mColorAlphaPicker->setField("displayMode", "horizAlpha");
+	mColorAlphaPicker->setExtent(Point2I(contentRect.extent.x, mBarHeight));
+	mColorAlphaPicker->showSelector();
+	mPickerProfile = mColorAlphaPicker->mProfile;
+	mPickerProfile->incRefCount();
+
+	mColorAlphaPicker->setField("selectorProfile", "GuiColorSelectorProfile");
+	mSelectorProfile = mColorAlphaPicker->mSelectorProfile;
+	mSelectorProfile->incRefCount();
+
+	mColorBlendPicker = new GuiColorPopupBlendCtrl(this, mColorAlphaPicker);
+	AssertFatal(mColorBlendPicker, "GuiColorPopupCtrl: Failed to initialize GuiColorPopupBlendCtrl!");
+	mColorBlendPicker->setField("profile", "GuiColorPickerProfile");
+	mColorBlendPicker->setField("displayMode", "blendColor");
+	mColorBlendPicker->setExtent(Point2I(contentRect.extent.x, mBlendHeight));
+	mColorBlendPicker->showSelector();
+	mPickerProfile = mColorBlendPicker->mProfile;
+	mPickerProfile->incRefCount();
+
+	mColorBlendPicker->setField("selectorProfile", "GuiColorSelectorProfile");
+	mSelectorProfile = mColorBlendPicker->mSelectorProfile;
+	mSelectorProfile->incRefCount();
+
+	mColorHuePicker = new GuiColorPopupHueCtrl(mColorBlendPicker);
+	AssertFatal(mColorHuePicker, "GuiColorPopupCtrl: Failed to initialize GuiColorPopupHueCtrl!");
+	mColorHuePicker->setField("profile", "GuiColorPickerProfile");
+	mColorHuePicker->setField("displayMode", "horizColor");
+	mColorHuePicker->setExtent(Point2I(contentRect.extent.x, mBarHeight));
+	mColorHuePicker->showSelector();
+	mPickerProfile = mColorHuePicker->mProfile;
+	mPickerProfile->incRefCount();
+
+	mColorHuePicker->setField("selectorProfile", "GuiColorSelectorProfile");
+	mSelectorProfile = mColorHuePicker->mSelectorProfile;
+	mSelectorProfile->incRefCount();
+
+	mContent->addObject(mColorBlendPicker);
+	mContent->addObject(mColorHuePicker);
+	mContent->addObject(mColorAlphaPicker);
+	mBackground->addObject(mContent);
+}
+
+void GuiColorPopupCtrl::initPersistFields()
+{
+	Parent::initPersistFields();
+
+	addGroup("Color Popup");
+	addField("backgroundProfile", TypeGuiProfile, Offset(mBackgroundProfile, GuiColorPopupCtrl));
+	addField("popupProfile", TypeGuiProfile, Offset(mPopupProfile, GuiColorPopupCtrl));
+	addField("pickerProfile", TypeGuiProfile, Offset(mPickerProfile, GuiColorPopupCtrl));
+	addField("selectorProfile", TypeGuiProfile, Offset(mSelectorProfile, GuiColorPopupCtrl));
+	addField("baseColor", TypeColorF, Offset(mBaseColor, GuiColorPopupCtrl));
+	addField("popupSize", TypePoint2I, Offset(mPopupSize, GuiColorPopupCtrl));
+	addField("barHeight", TypeS32, Offset(mBarHeight, GuiColorPopupCtrl));
+	addField("showAlphaBar", TypeBool, Offset(mShowAlphaBar, GuiColorPopupCtrl));
+	endGroup("Color Popup");
+}
+
+void GuiColorPopupCtrl::onTouchUp(const GuiEvent& event)
+{
+	if (!mActive)
+		return;
+
+	Parent::onTouchUp(event);
+
+	mouseUnlock();
+
+	if (!mIsOpen)
+	{
+		openColorPopup();
+	}
+	else
+	{
+		closeColorPopup();
+	}
+}
+
+GuiControlState GuiColorPopupCtrl::getCurrentState()
+{
+	if (!mActive)
+		return GuiControlState::DisabledState;
+	else if (mDepressed || mIsOpen)
+		return GuiControlState::SelectedState;
+	else if (mMouseOver)
+		return GuiControlState::HighlightState;
+	else
+		return GuiControlState::NormalState;
+}
+
+void GuiColorPopupCtrl::onRender(Point2I offset, const RectI& updateRect)
+{
+	GuiControlState currentState = getCurrentState();
+	RectI ctrlRect = applyMargins(offset, mBounds.extent, currentState, mProfile);
+
+	renderUniversalRect(ctrlRect, mProfile, currentState, blankColor, true);
+
+	//Get the content area
+	RectI fillRect = applyBorders(ctrlRect.point, ctrlRect.extent, currentState, mProfile);
+	RectI contentRect = applyPadding(fillRect.point, fillRect.extent, currentState, mProfile);
+
+	if (mBaseColor.alpha < 1.0f)
+	{
+		if (mBounds.extent.x < 50 || mBounds.extent.y < 50)
+		{
+			dglRenderCheckers(contentRect, 8);
+		}
+		else 
+		{
+			dglRenderCheckers(contentRect);
+		}
+	}
+	dglDrawRectFill(contentRect, mBaseColor);
+}
+
+bool GuiColorPopupCtrl::onKeyDown(const GuiEvent& event)
+{
+	//if the control is a dead end, don't process the input:
+	if (!mVisible || !mActive || !mAwake)
+		return false;
+
+	//see if the key down is a <return> or not
+	if (event.keyCode == KEY_RETURN && event.modifier == 0)
+	{
+		if (!mIsOpen)
+		{
+			openColorPopup();
+		}
+		else
+		{
+			closeColorPopup();
+		}
+		return true;
+	}
+
+	return false;
+}
+
+void GuiColorPopupCtrl::onAction() //called when the button is clicked.
+{
+	if (!mActive)
+		return;
+
+	setUpdate();
+}
+
+void GuiColorPopupCtrl::itemSelected()
+{
+	if (mConsoleCommand[0])
+		Con::evaluate(mConsoleCommand, false);
+}
+
+void GuiColorPopupCtrl::openColorPopup()
+{
+	if (mIsOpen)
+		return;
+
+	GuiCanvas* root = getRoot();
+	AssertFatal(root, "GuiColorPopupCtrl::openColorPopup: Unable to optain the Canvas!");
+	mBackground->mBounds.extent = root->mBounds.extent;
+
+	//Update all pass through values
+	mBackground->setControlProfile(mBackgroundProfile);
+	mContent->setControlProfile(mPopupProfile);
+	mColorBlendPicker->setControlProfile(mPickerProfile);
+	mColorBlendPicker->setControlSelectorProfile(mSelectorProfile);
+	mColorHuePicker->setControlProfile(mPickerProfile);
+	mColorHuePicker->setControlSelectorProfile(mSelectorProfile);
+	mColorAlphaPicker->setControlProfile(mPickerProfile);
+	mColorAlphaPicker->setControlSelectorProfile(mSelectorProfile);
+
+	mContent->setExtent(mPopupSize);
+	RectI contentRect = mContent->getInnerRect();
+	mColorBlendPicker->setWidth(contentRect.extent.x);
+	S32 blendHeight = getMin(contentRect.extent.y, mBlendHeight);
+	mColorBlendPicker->setHeight(blendHeight);
+	S32 remainingHeight = contentRect.extent.y - blendHeight;
+
+	U8 barCount = mShowAlphaBar ? 2 : 1;
+	S32 barSpace = remainingHeight / barCount;
+	mColorHuePicker->resize(Point2I(0, blendHeight + barSpace - mBarHeight), Point2I(contentRect.extent.x, mBarHeight));
+	if (mShowAlphaBar)
+	{
+		mColorAlphaPicker->setActive(true);
+		mColorAlphaPicker->resize(Point2I(0, blendHeight + (barSpace * 2) - mBarHeight), Point2I(contentRect.extent.x, mBarHeight));
+	}
+	else
+	{
+		mColorAlphaPicker->setActive(false);
+	}
+
+	Point2I huePos = mColorHuePicker->getSelectorPositionForColor(mBaseColor);
+	mColorHuePicker->setSelectorPos(huePos);
+	ColorF hueColor = mBaseColor.getHueColor();
+	mColorBlendPicker->setValue(hueColor);
+	Point2I selPos = mColorBlendPicker->getSelectorPositionForColor(mBaseColor);
+	mColorBlendPicker->setSelectorPos(selPos);
+	Point2I alphaPos = mColorAlphaPicker->getSelectorPositionForColor(mBaseColor);
+	mColorAlphaPicker->setSelectorPos(alphaPos);
+
+
+	S32 width = mPopupSize.x;
+	S32 height = mPopupSize.y;
+	Point2I pos = localToGlobalCoord(Point2I(0, 0));
+
+	//Is there enough space below?
+	if ((height + pos.y + mBounds.extent.y) <= root->mBounds.extent.y)
+	{
+		pos.y += mBounds.extent.y;
+	}
+	else if (height <= pos.y) //Is there enough space above?
+	{
+		pos.y -= height;
+	}
+	else if (pos.y < (root->mBounds.extent.y - (pos.y + mBounds.extent.y))) //Is there more space below?
+	{
+		pos.y += mBounds.extent.y;
+		height = root->mBounds.extent.y - pos.y;
+	}
+	else //There must be more space above
+	{
+		height = pos.y;
+		pos.y = 0;
+	}
+
+	mContent->resize(pos, Point2I(width, height));
+
+	root->pushDialogControl(mBackground, 99);
+
+	mIsOpen = true;
+
+	setFirstResponder();
+
+	if (isMethod("onOpen"))
+		Con::executef(this, 1, "onOpen");
+}
+
+void GuiColorPopupCtrl::closeColorPopup()
+{
+	if (!mIsOpen)
+		return;
+
+	GuiCanvas* root = mBackground->getRoot();
+	if (!root)
+	{
+		return;
+	}
+	root->popDialogControl(mBackground);
+
+	mIsOpen = false;
+
+	if (isMethod("onClose"))
+		Con::executef(this, 1, "onClose");
+}
+
+bool GuiColorPopupCtrl::onWake()
+{
+	if (!Parent::onWake())
+		return false;
+
+	if (mBackgroundProfile != NULL)
+		mBackgroundProfile->incRefCount();
+
+	if (mPopupProfile != NULL)
+		mPopupProfile->incRefCount();
+
+	if (mPickerProfile != NULL)
+		mPickerProfile->incRefCount();
+
+	if (mSelectorProfile != NULL)
+		mSelectorProfile->incRefCount();
+
+	return true;
+}
+
+void GuiColorPopupCtrl::onSleep()
+{
+	Parent::onSleep();
+
+	if (mBackgroundProfile != NULL)
+		mBackgroundProfile->decRefCount();
+
+	if (mPopupProfile != NULL)
+		mPopupProfile->decRefCount();
+
+	if (mPickerProfile != NULL)
+		mPickerProfile->decRefCount();
+
+	if (mSelectorProfile != NULL)
+		mSelectorProfile->decRefCount();
+}
+
+void GuiColorPopupCtrl::setControlBackgroundProfile(GuiControlProfile* prof)
+{
+	AssertFatal(prof, "GuiColorPopupCtrl::setControlBackgroundProfile: invalid background profile");
+	if (prof == mBackgroundProfile)
+		return;
+	if (mAwake)
+		mBackgroundProfile->decRefCount();
+	mBackgroundProfile = prof;
+	if (mAwake)
+		mBackgroundProfile->incRefCount();
+}
+
+void GuiColorPopupCtrl::setControlPopupProfile(GuiControlProfile* prof)
+{
+	AssertFatal(prof, "GuiColorPopupCtrl::setControlPopupProfile: invalid popup profile");
+	if (prof == mPopupProfile)
+		return;
+	if (mAwake)
+		mPopupProfile->decRefCount();
+	mPopupProfile = prof;
+	if (mAwake)
+		mPopupProfile->incRefCount();
+}
+
+void GuiColorPopupCtrl::setControlPickerProfile(GuiControlProfile* prof)
+{
+	AssertFatal(prof, "GuiColorPopupCtrl::setControlPickerProfile: invalid picker profile");
+	if (prof == mPickerProfile)
+		return;
+	if (mAwake)
+		mPickerProfile->decRefCount();
+	mPickerProfile = prof;
+	if (mAwake)
+		mPickerProfile->incRefCount();
+}
+
+void GuiColorPopupCtrl::setControlSelectorProfile(GuiControlProfile* prof)
+{
+	AssertFatal(prof, "GuiColorPopupCtrl::setControlSelectorProfile: invalid selector profile");
+	if (prof == mSelectorProfile)
+		return;
+	if (mAwake)
+		mSelectorProfile->decRefCount();
+	mSelectorProfile = prof;
+	if (mAwake)
+		mSelectorProfile->incRefCount();
+}
+
+void GuiColorPopupCtrl::setColor(const ColorF& theColor)
+{
+	mBaseColor.red = theColor.red;
+	mBaseColor.green = theColor.green;
+	mBaseColor.blue = theColor.blue;
+}

+ 132 - 0
engine/source/gui/guiColorPopupCtrl.h

@@ -0,0 +1,132 @@
+//-----------------------------------------------------------------------------
+// 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 _GUICOLORPOPUPCTRL_H_
+#define _GUICOLORPOPUPCTRL_H_
+
+#include "gui/guiControl.h"
+#include "gui/buttons/guiButtonCtrl.h"
+#include "gui/guiColorPickerCtrl.h"
+#include "graphics/dgl.h"
+#include "gui/guiDefaultControlRender.h"
+
+class GuiColorPopupCtrl;
+
+class GuiColorPopupBGCtrl : public GuiControl
+{
+protected:
+	GuiColorPopupCtrl* mColorPopupCtrl;
+public:
+	GuiColorPopupBGCtrl(GuiColorPopupCtrl* ctrl);
+	void onTouchUp(const GuiEvent& event);
+};
+
+class GuiColorPopupContentCtrl : public GuiControl
+{
+public:
+	GuiColorPopupContentCtrl();
+	void onTouchUp(const GuiEvent& event);
+};
+
+class GuiColorPopupAlphaCtrl : public GuiColorPickerCtrl
+{
+protected:
+	GuiColorPopupCtrl* mColorPopupCtrl;
+public:
+	GuiColorPopupAlphaCtrl(GuiColorPopupCtrl* ctrl);
+	void updatePickColor(const Point2I& offset, const RectI& contentRect);
+};
+
+class GuiColorPopupBlendCtrl : public GuiColorPickerCtrl
+{
+protected:
+	GuiColorPopupCtrl* mColorPopupCtrl;
+	GuiColorPopupAlphaCtrl* mAlphaCtrl;
+public:
+	GuiColorPopupBlendCtrl(GuiColorPopupCtrl* ctrl, GuiColorPopupAlphaCtrl* alpha);
+	void updatePickColor(const Point2I& offset, const RectI& contentRect);
+};
+
+class GuiColorPopupHueCtrl : public GuiColorPickerCtrl
+{
+protected:
+	GuiColorPopupBlendCtrl* mBlendCtrl;
+public:
+	GuiColorPopupHueCtrl(GuiColorPopupBlendCtrl* ctrl);
+	void updatePickColor(const Point2I& offset, const RectI& contentRect);
+};
+
+class GuiColorPopupCtrl : public GuiButtonCtrl
+{
+private:
+	typedef GuiButtonCtrl Parent;
+	ColorF mBaseColor;
+	bool mIsOpen;
+	Point2I mPopupSize;
+	S32 mBlendHeight;
+	S32 mBarHeight;
+	bool mShowAlphaBar;
+
+	GuiColorPopupBGCtrl* mBackground;
+	GuiControl* mContent;
+	GuiColorPopupBlendCtrl* mColorBlendPicker;
+	GuiColorPopupHueCtrl* mColorHuePicker;
+	GuiColorPopupAlphaCtrl* mColorAlphaPicker;
+
+	GuiControlProfile* mBackgroundProfile; //Used to render the background when the drop down is open
+	GuiControlProfile* mPopupProfile; //Used for the content box of the popup
+	GuiControlProfile* mPickerProfile; //Used for the three color pickers used in the popup
+	GuiControlProfile* mSelectorProfile; //Used for the selectors in the popup
+
+protected:
+
+public:
+	GuiColorPopupCtrl();
+	static void initPersistFields();
+
+	virtual void onTouchUp(const GuiEvent& event);
+	GuiControlState getCurrentState();
+	void onRender(Point2I offset, const RectI& updateRect);
+	void setPopupSize(const Point2I& size) { mPopupSize.set(size.x, size.y); }
+
+	bool onKeyDown(const GuiEvent& event);
+	virtual void onAction();
+	void itemSelected();
+	void openColorPopup();
+	void closeColorPopup();
+
+	bool onWake();
+	void onSleep();
+	void setControlBackgroundProfile(GuiControlProfile* prof);
+	void setControlPopupProfile(GuiControlProfile* prof);
+	void setControlPickerProfile(GuiControlProfile* prof);
+	void setControlSelectorProfile(GuiControlProfile* prof);
+
+	void setColor(const ColorF& theColor);
+	void setAlpha(const F32 alpha) { mBaseColor.alpha = alpha; }
+	void setValue(ColorF& value) { mBaseColor = value; }
+	ColorF getValue() { return mBaseColor; }
+
+	DECLARE_CONOBJECT(GuiColorPopupCtrl);
+};
+
+#endif

+ 89 - 0
engine/source/gui/guiColorPopupCtrl_ScriptBinding.h

@@ -0,0 +1,89 @@
+//-----------------------------------------------------------------------------
+// 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(GuiColorPopupCtrl, GuiControl)
+
+/*! Opens the popup. Does nothing if the popup is already open.
+	@return No return value.
+*/
+ConsoleMethodWithDocs(GuiColorPopupCtrl, openColorPopup, ConsoleVoid, 2, 2, "()")
+{
+	object->openColorPopup();
+}
+
+/*! Closes the popup. Does nothing if the popup is already closed.
+	@return No return value.
+*/
+ConsoleMethodWithDocs(GuiColorPopupCtrl, closeColorPopup, ConsoleVoid, 2, 2, "()")
+{
+	object->closeColorPopup();
+}
+
+/*! Sets the currently used BackgroundProfile for the GuiControl
+	@param p The BackgroundProfile applies to the the entire screen when the list opens.
+	@return No return value
+*/
+ConsoleMethodWithDocs(GuiColorPopupCtrl, setBackgroundProfile, ConsoleVoid, 3, 3, (GuiControlProfile p))
+{
+	GuiControlProfile* profile;
+
+	if (Sim::findObject(argv[2], profile))
+		object->setControlBackgroundProfile(profile);
+}
+
+/*! Sets the currently used PopupProfile for the GuiControl
+	@param p The PopupProfile applies to the the entire screen when the list opens.
+	@return No return value
+*/
+ConsoleMethodWithDocs(GuiColorPopupCtrl, setPopupProfile, ConsoleVoid, 3, 3, (GuiControlProfile p))
+{
+	GuiControlProfile* profile;
+
+	if (Sim::findObject(argv[2], profile))
+		object->setControlPopupProfile(profile);
+}
+
+/*! Sets the currently used PickerProfile for the GuiControl
+	@param p The PickerProfile applies to the the entire screen when the list opens.
+	@return No return value
+*/
+ConsoleMethodWithDocs(GuiColorPopupCtrl, setPickerProfile, ConsoleVoid, 3, 3, (GuiControlProfile p))
+{
+	GuiControlProfile* profile;
+
+	if (Sim::findObject(argv[2], profile))
+		object->setControlPickerProfile(profile);
+}
+
+/*! Sets the currently used SelectorProfile for the GuiControl
+	@param p The SelectorProfile applies to the the entire screen when the list opens.
+	@return No return value
+*/
+ConsoleMethodWithDocs(GuiColorPopupCtrl, setSelectorProfile, ConsoleVoid, 3, 3, (GuiControlProfile p))
+{
+	GuiControlProfile* profile;
+
+	if (Sim::findObject(argv[2], profile))
+		object->setControlSelectorProfile(profile);
+}
+
+ConsoleMethodGroupEndWithDocs(GuiColorPopupCtrl)

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

@@ -1917,16 +1917,18 @@ bool GuiControl::onKeyUp(const GuiEvent &event)
 
 
 void GuiControl::onAction()
 void GuiControl::onAction()
 {
 {
-   if (! mActive)
-      return;
+	if (! mActive)
+		return;
 
 
-   //execute the console command
-   if (mConsoleCommand && mConsoleCommand[0])
-   {
-      execConsoleCallback();
-   }
-   else
-      Con::executef(this, 1, "onAction");
+	//execute the console command
+	if (mConsoleCommand && mConsoleCommand[0])
+	{
+		execConsoleCallback();
+	}
+	else if(isMethod("onAction"))
+	{
+		Con::executef(this, 1, "onAction");
+	}
 }
 }
 
 
 void GuiControl::onMessage(GuiControl *sender, S32 msg)
 void GuiControl::onMessage(GuiControl *sender, S32 msg)

+ 157 - 0
library/AppCore/gui/guiProfiles.cs

@@ -995,4 +995,161 @@ function AppCore::createGuiProfiles(%this)
 		borderTop = GuiMenuItemBorderTopProfile;
 		borderTop = GuiMenuItemBorderTopProfile;
 		borderBottom = GuiMenuItemBorderBottomProfile;
 		borderBottom = GuiMenuItemBorderBottomProfile;
 	});
 	});
+
+	%this.SafeCreateNamedObject("GuiTextEditProfile", new GuiControlProfile()
+	{
+		fillColor = %this.color4;
+		fillColorHL = %this.AdjustColorValue(%this.color4, 10);
+		fillColorSL = %this.color4;
+		fillColorNA = %this.AdjustColorValue(%this.color4, 80);
+		fillColorTextSL = %this.color5;
+
+		fontColor = %this.SetColorAlpha(%this.color1, 220);
+		fontColorHL = %this.AdjustColorValue(%this.color1, 10);
+		fontColorSL = %this.color1;
+		fontColorNA = %this.SetColorAlpha(%this.color1, 100);
+		fontColorTextSL = %this.color1;
+		align = left;
+		vAlign = middle;
+		cursorColor = %this.color2;
+
+		tab = true;
+		canKeyFocus = true;
+		returnTab = true;
+	});
+
+	%this.SafeCreateNamedObject("GuiButtonProfile", new GuiControlProfile()
+	{
+		fillColor = %this.color4;
+		fillColorHL = %this.AdjustColorValue(%this.color4, 10);
+		fillColorSL = %this.color5;
+		fillColorNA = %this.SetColorAlpha(%this.color4, 80);
+
+		fontColor = %this.color1;
+		fontColorHL = %this.AdjustColorValue(%this.color1, 10);
+		fontColorSL = %this.color1;
+		fontColorNA = %this.SetColorAlpha(%this.color1, 100);
+		align = center;
+		vAlign = middle;
+
+		borderLeft = GuiBrightBorderProfile;
+		borderRight = GuiDarkBorderProfile;
+		borderTop = GuiBrightBorderProfile;
+		borderBottom = GuiDarkBorderProfile;
+
+		canKeyFocus = true;
+		tab = true;
+	});
+
+	%this.SafeCreateNamedObject("GuiCheckboxProfile", new GuiControlProfile()
+	{
+		fillColor = %this.color4;
+		fillColorHL = %this.AdjustColorValue(%this.color4, 10);
+		fillColorSL = %this.color5;
+		fillColorNA = %this.SetColorAlpha(%this.color4, 80);
+
+		fontColor = %this.color1;
+		fontColorHL = %this.AdjustColorValue(%this.color1, 10);
+		fontColorSL = %this.color1;
+		fontColorNA = %this.SetColorAlpha(%this.color1, 100);
+		align = center;
+		vAlign = middle;
+
+		borderLeft = GuiBrightBorderProfile;
+		borderRight = GuiDarkBorderProfile;
+		borderTop = GuiBrightBorderProfile;
+		borderBottom = GuiDarkBorderProfile;
+
+		canKeyFocus = true;
+		tab = true;
+	});
+
+	%this.SafeCreateNamedObject("GuiColorPopupBorderProfile", new GuiBorderProfile()
+	{
+		border = 1;
+		borderHL = 1;
+		borderSL = 1;
+		borderNA = 1;
+
+		borderColor = %this.AdjustColorValue(%this.color1, -5);
+		borderColorHL = %this.AdjustColorValue(%this.color1, -5);
+		borderColorSL = %this.AdjustColorValue(%this.color1, -5);
+		borderColorNA = %this.AdjustColorValue(%this.color1, -5);
+
+		padding = 3;
+		paddingHL = 3;
+		paddingSL = 3;
+		paddingNA = 3;
+	});
+
+	%this.SafeCreateNamedObject("GuiColorPopupProfile", new GuiControlProfile()
+	{
+		fillColor = %this.color1;
+		fillColorHL = %this.color1;
+		fillColorSL = %this.color1;
+		fillColorNA = %this.color1;
+
+		borderDefault = GuiColorPopupBorderProfile;
+	});
+
+	%this.SafeCreateNamedObject("GuiColorPickerBorderProfile", new GuiBorderProfile()
+	{
+		border = 1;
+		borderHL = 1;
+		borderSL = 1;
+		borderNA = 1;
+
+		borderColor = %this.color1;
+		borderColorHL = %this.color2;
+		borderColorSL = %this.color4;
+		borderColorNA = %this.color1;
+
+		padding = 1;
+		paddingHL = 1;
+		paddingSL = 1;
+		paddingNA = 1;
+
+		margin = 1;
+		marginHL = 1;
+		marginSL = 1;
+		marginNA = 1;
+	});
+
+	%this.SafeCreateNamedObject("GuiColorPickerProfile", new GuiControlProfile()
+	{
+		fillColor = "0 0 0 0";
+		fillColorHL = "0 0 0 0";
+		fillColorSL = "0 0 0 0";
+		fillColorNA = "0 0 0 0";
+		
+		borderDefault = GuiColorPickerBorderProfile;
+
+		tab = false;
+		canKeyFocus = true;
+		underfill = true;
+	});
+
+	%this.SafeCreateNamedObject("GuiColorSelectorBorderProfile", new GuiBorderProfile()
+	{
+		border = 1;
+		borderHL = 1;
+		borderSL = 1;
+
+		borderColor = "0 0 0 180";
+		borderColorHL = "0 0 0 190";
+		borderColorSL = "0 0 0 220";
+
+		//Margin and padding are used to determine the size of the selector ring in the normal state.
+		padding = 2;//Radius of the outer circle minus the inner circle. The meat of the donut.
+		margin = 1;//Radius of the inner circle plus 1. This is different from the normal use of the margin.
+	});
+
+	%this.SafeCreateNamedObject("GuiColorSelectorProfile", new GuiControlProfile()
+	{
+		fillColor = "240 240 240 255";
+		fillColorHL = "250 250 250 255";
+		fillColorSL = %this.color5;
+		
+		borderDefault = GuiColorSelectorBorderProfile;
+	});
 }
 }

+ 1 - 1
library/AppCore/module.taml

@@ -1,7 +1,7 @@
 <ModuleDefinition
 <ModuleDefinition
 	ModuleId="AppCore"
 	ModuleId="AppCore"
 	VersionId="1"
 	VersionId="1"
-	BuildID="1"
+	BuildID="2"
 	Description="Provides critical initialization and functionality needed for every project."
 	Description="Provides critical initialization and functionality needed for every project."
 	ScriptFile="appCore.cs"
 	ScriptFile="appCore.cs"
 	CreateFunction="create"
 	CreateFunction="create"