浏览代码

Update to the GuiColorPickerCtrl

Repaired the various display modes. Changed the selector to be profile driven. Moved drawing functions to the dgl file like other drawing functions. Added checkers background to transparent part of the alpha slider. Added support for text and removed support for children controls. Moved script functions to a script file. Added "Ctrl" to the file names. Added a window to the Gui Editor that can test the different modes for the color picker (commented out for now).
Peter Robinson 2 年之前
父节点
当前提交
ecd6dcee49

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

@@ -69,6 +69,7 @@ function BaseTheme::onAdd(%this)
 	%this.makeSubListProfile();
 	%this.makeSubListProfile();
 	%this.makeGuiEditorProfile();
 	%this.makeGuiEditorProfile();
 	%this.makeFrameSetProfile();
 	%this.makeFrameSetProfile();
+	%this.makeColorPickerProfile();
 }
 }
 
 
 function BaseTheme::init(%this)
 function BaseTheme::init(%this)
@@ -2182,6 +2183,70 @@ function BaseTheme::makeFrameSetProfile(%this)
 	};
 	};
 }
 }
 
 
+function BaseTheme::makeColorPickerProfile(%this)
+{
+	%border = 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.colorPickerProfile = new GuiControlProfile()
+	{
+		fillColor = "0 0 0 0";
+		fillColorHL = "0 0 0 0";
+		fillColorSL = "0 0 0 0";
+		fillColorNA = "0 0 0 0";
+		
+		borderDefault = %border;
+
+		tab = false;
+		canKeyFocus = true;
+		underfill = true;
+	};
+
+	%selBorder = 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 = 3;//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.colorPickerSelectorProfile = new GuiControlProfile()
+	{
+		fillColor = "240 240 240 255";
+		fillColorHL = "250 250 250 255";
+		fillColorSL = %this.color5;
+		
+		borderDefault = %selBorder;
+	};
+}
+
 //Positive values are brighter, negative are darker
 //Positive values are brighter, negative are darker
 function BaseTheme::adjustValue(%this, %color, %percent)
 function BaseTheme::adjustValue(%this, %color, %percent)
 {
 {

+ 24 - 0
editor/GuiEditor/GuiEditor.cs

@@ -31,6 +31,7 @@ function GuiEditor::create( %this )
     exec("./scripts/GuiEditorExplorerTree.cs");
     exec("./scripts/GuiEditorExplorerTree.cs");
     exec("./scripts/GuiEditorSaveGuiDialog.cs");
     exec("./scripts/GuiEditorSaveGuiDialog.cs");
     exec("./scripts/GuiEditorGridSizeDialog.cs");
     exec("./scripts/GuiEditorGridSizeDialog.cs");
+    exec("./scripts/GuiEditorColorWindow.cs");
 
 
 	%this.guiPage = EditorCore.RegisterEditor("Gui Editor", %this);
 	%this.guiPage = EditorCore.RegisterEditor("Gui Editor", %this);
 
 
@@ -183,6 +184,29 @@ function GuiEditor::create( %this )
     %this.brain.root = %this.rootGui;
     %this.brain.root = %this.rootGui;
     %this.explorerWindow.inspect(%this.rootGui);
     %this.explorerWindow.inspect(%this.rootGui);
 
 
+    /* %this.colorWindow = new GuiWindowCtrl()
+    {
+        Class = "GuiEditorColorWindow";
+        HorizSizing = "right";
+        VertSizing = "bottom";
+        Position = "610 0";
+        Extent = "400  380";
+        MinExtent = "100 100";
+        text = "Color Test";
+        canMove = true;
+        canClose = false;
+        canMinimize = true;
+        canMaximize = false;
+        resizeWidth = true;
+        resizeHeight = true;
+    };
+    ThemeManager.setProfile(%this.colorWindow, "windowProfile");
+    ThemeManager.setProfile(%this.colorWindow, "windowContentProfile", "ContentProfile");
+    ThemeManager.setProfile(%this.colorWindow, "windowButtonProfile", "CloseButtonProfile");
+    ThemeManager.setProfile(%this.colorWindow, "windowButtonProfile", "MinButtonProfile");
+    ThemeManager.setProfile(%this.colorWindow, "windowButtonProfile", "MaxButtonProfile");
+    %this.guiPage.add(%this.colorWindow); */
+
     EditorCore.FinishRegistration(%this.guiPage);
     EditorCore.FinishRegistration(%this.guiPage);
 }
 }
 
 

+ 46 - 0
editor/GuiEditor/scripts/GuiEditorColorWindow.cs

@@ -0,0 +1,46 @@
+
+function GuiEditorColorWindow::onAdd(%this)
+{
+    %ext = %this.getExtent();
+    %this.grid = new GuiGridCtrl()
+    {
+        HorizSizing = "width";
+        VertSizing = "height";
+        Position = "7 10";
+        Extent = (%ext.x - 23) SPC (%ext.y - 43);
+        CellSizeX = "50";
+        CellSizeY = "200";
+        CellModeX = "Variable";
+        CellModeY = "Absolute";
+        MaxColCount = "2";
+        IsExtentDynamic = "1";
+        OrderMode = "LRTB";
+    };
+    ThemeManager.setProfile(%this.grid, "EmptyProfile");
+    %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");
+}
+
+function GuiEditorColorWindow::addColorCtrl(%this, %i, %mode)
+{
+    %this.colorCtrl[%i] = new GuiColorPickerCtrl()
+    {
+        HorizSizing = "width";
+        VertSizing = "height";
+        DisplayMode = %mode;
+        ShowSelector = "1";
+        SelectorGap = "4";
+    };
+    ThemeManager.setProfile(%this.colorCtrl[%i], "colorPickerProfile");
+    ThemeManager.setProfile(%this.colorCtrl[%i], "colorPickerSelectorProfile", "selectorProfile");
+    %this.grid.add(%this.colorCtrl[%i]);
+}

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

@@ -632,7 +632,7 @@
     <ClCompile Include="..\..\source\gui\editor\guiParticleGraphInspector.cc" />
     <ClCompile Include="..\..\source\gui\editor\guiParticleGraphInspector.cc" />
     <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\guiColorPicker.cc" />
+    <ClCompile Include="..\..\source\gui\guiColorPickerCtrl.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" />
@@ -1130,7 +1130,8 @@
     <ClInclude Include="..\..\source\gui\guiArrayCtrl.h" />
     <ClInclude Include="..\..\source\gui\guiArrayCtrl.h" />
     <ClInclude Include="..\..\source\gui\guiCanvas.h" />
     <ClInclude Include="..\..\source\gui\guiCanvas.h" />
     <ClInclude Include="..\..\source\gui\guiCanvas_ScriptBinding.h" />
     <ClInclude Include="..\..\source\gui\guiCanvas_ScriptBinding.h" />
-    <ClInclude Include="..\..\source\gui\guiColorPicker.h" />
+    <ClInclude Include="..\..\source\gui\guiColorPickerCtrl.h" />
+    <ClInclude Include="..\..\source\gui\guiColorPickerCtrl_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" />

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

@@ -729,7 +729,7 @@
     <ClCompile Include="..\..\source\gui\guiCanvas.cc">
     <ClCompile Include="..\..\source\gui\guiCanvas.cc">
       <Filter>gui</Filter>
       <Filter>gui</Filter>
     </ClCompile>
     </ClCompile>
-    <ClCompile Include="..\..\source\gui\guiColorPicker.cc">
+    <ClCompile Include="..\..\source\gui\guiColorPickerCtrl.cc">
       <Filter>gui</Filter>
       <Filter>gui</Filter>
     </ClCompile>
     </ClCompile>
     <ClCompile Include="..\..\source\gui\guiConsole.cc">
     <ClCompile Include="..\..\source\gui\guiConsole.cc">
@@ -1932,7 +1932,7 @@
     <ClInclude Include="..\..\source\gui\guiCanvas.h">
     <ClInclude Include="..\..\source\gui\guiCanvas.h">
       <Filter>gui</Filter>
       <Filter>gui</Filter>
     </ClInclude>
     </ClInclude>
-    <ClInclude Include="..\..\source\gui\guiColorPicker.h">
+    <ClInclude Include="..\..\source\gui\guiColorPickerCtrl.h">
       <Filter>gui</Filter>
       <Filter>gui</Filter>
     </ClInclude>
     </ClInclude>
     <ClInclude Include="..\..\source\gui\guiConsole.h">
     <ClInclude Include="..\..\source\gui\guiConsole.h">
@@ -3079,6 +3079,9 @@
     <ClInclude Include="..\..\source\gui\containers\guiFrameSetCtrl_ScriptBinding.h">
     <ClInclude Include="..\..\source\gui\containers\guiFrameSetCtrl_ScriptBinding.h">
       <Filter>gui\containers</Filter>
       <Filter>gui\containers</Filter>
     </ClInclude>
     </ClInclude>
+    <ClInclude Include="..\..\source\gui\guiColorPickerCtrl_ScriptBinding.h">
+      <Filter>gui</Filter>
+    </ClInclude>
   </ItemGroup>
   </ItemGroup>
   <ItemGroup>
   <ItemGroup>
     <ResourceCompile Include="Torque 2D.rc" />
     <ResourceCompile Include="Torque 2D.rc" />

+ 251 - 0
engine/source/graphics/dgl.cc

@@ -1179,6 +1179,11 @@ void dglSolidCube(const Point3F & extent, const Point3F & center)
 //http://slabode.exofire.net/circle_draw.shtml
 //http://slabode.exofire.net/circle_draw.shtml
 void dglDrawCircle(const Point2I &center, const F32 radius, const ColorI &color, const F32 &lineWidth)
 void dglDrawCircle(const Point2I &center, const F32 radius, const ColorI &color, const F32 &lineWidth)
 {
 {
+	if(lineWidth <= 0)
+	{
+		return;
+	}
+
 	F32 adjustedRadius = radius - (lineWidth/2);
 	F32 adjustedRadius = radius - (lineWidth/2);
 	const S32 num_segments = (const S32)round(10 * sqrtf(adjustedRadius));
 	const S32 num_segments = (const S32)round(10 * sqrtf(adjustedRadius));
 	F32 theta = 2 * 3.1415926f / F32(num_segments);
 	F32 theta = 2 * 3.1415926f / F32(num_segments);
@@ -1594,3 +1599,249 @@ bool dglCheckState(const S32 mvDepth, const S32 pDepth,
 GLfloat gVertexFloats[8];
 GLfloat gVertexFloats[8];
 GLfloat gTextureVerts[8];
 GLfloat gTextureVerts[8];
 #endif
 #endif
+
+//--------------------------------------------------------------------------
+// Function to draw a box which can have 4 different colors in each corner blended together
+#if defined(TORQUE_OS_IOS) || defined(TORQUE_OS_ANDROID) || defined(TORQUE_OS_EMSCRIPTEN)
+void dglDrawBlendBox(RectI& bounds, ColorF& c1, ColorF& c2, ColorF& c3, ColorF& c4)
+{
+	GLfloat left = bounds.point.x, right = bounds.point.x + bounds.extent.x - 1;
+	GLfloat top = bounds.point.y, bottom = bounds.point.y + bounds.extent.y - 1;
+
+	glEnable(GL_BLEND);
+	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+	glDisable(GL_TEXTURE_2D);
+
+	const GLfloat verts[] = {
+		left, top,
+		right,  top,
+		left,  bottom,
+		right,   bottom,
+	};
+	const GLubyte squareColors[] = {
+		static_cast<GLubyte>(255 * c1.red),  static_cast<GLubyte>(255 * c1.green),  static_cast<GLubyte>(255 * c1.blue),  static_cast<GLubyte>(255 * c1.alpha),
+		static_cast<GLubyte>(255 * c2.red),  static_cast<GLubyte>(255 * c2.green),  static_cast<GLubyte>(255 * c2.blue),  static_cast<GLubyte>(255 * c2.alpha),
+		static_cast<GLubyte>(255 * c3.red),  static_cast<GLubyte>(255 * c3.green),  static_cast<GLubyte>(255 * c3.blue),  static_cast<GLubyte>(255 * c3.alpha),
+		static_cast<GLubyte>(255 * c4.red),  static_cast<GLubyte>(255 * c4.green),  static_cast<GLubyte>(255 * c4.blue),  static_cast<GLubyte>(255 * c4.alpha),
+	};
+	glVertexPointer(2, GL_FLOAT, 0, verts);
+	glEnableClientState(GL_VERTEX_ARRAY);
+	glColorPointer(4, GL_UNSIGNED_BYTE, 0, squareColors);
+	glEnableClientState(GL_COLOR_ARRAY);
+
+	glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
+}
+
+//--------------------------------------------------------------------------
+/// Function to draw a set of boxes blending throughout an array of colors
+void dglDrawBlendRangeBox(RectI& bounds, bool vertical, U8 numColors, ColorI* colors)
+{
+	S32 left = bounds.point.x, right = bounds.point.x + bounds.extent.x - 1;
+	S32 top = bounds.point.y, bottom = bounds.point.y + bounds.extent.y - 1;
+
+	// Calculate increment value
+	S32 x_inc = S32(mFloor((right - left) / (numColors - 1)));
+	S32 y_inc = S32(mFloor((bottom - top) / (numColors - 1)));
+
+
+	glEnable(GL_BLEND);
+	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+	glDisable(GL_TEXTURE_2D);
+
+	GLfloat verts[] = {
+		0.0f,	0.0f,	0.0f,	0.0f,
+		0.0f,	0.0f,	0.0f,	0.0f,
+	};
+
+	glVertexPointer(2, GL_FLOAT, 0, verts);
+	glEnableClientState(GL_VERTEX_ARRAY);
+
+	for (U16 i = 0; i < numColors - 1; i++)
+	{
+		// If we are at the end, x_inc and y_inc need to go to the end (otherwise there is a rendering bug)
+		if (i == numColors - 2)
+		{
+			x_inc += right - left - 1;
+			y_inc += bottom - top - 1;
+		}
+
+		if (vertical)  // Vertical (+y)		colors go up and down
+		{
+			// First color
+			glColor4ub(colors[i].red, colors[i].green, colors[i].blue, colors[i].alpha);
+			verts[0] = (F32)left;
+			verts[1] = (F32)top;
+			verts[2] = (F32)(left + x_inc);
+			verts[3] = (F32)top;
+			// Second color
+			glColor4ub(colors[i + 1].red, colors[i + 1].green, colors[i + 1].blue, colors[i + 1].alpha);
+
+			verts[4] = (F32)left;
+			verts[5] = (F32)bottom;
+			verts[6] = (F32)(left + x_inc);
+			verts[7] = (F32)bottom;
+			glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
+			left += x_inc;
+		}
+		else  // Horizontal (+x)	colors go lateral
+		{
+			// First color
+			glColor4ub(colors[i].red, colors[i].green, colors[i].blue, colors[i].alpha);
+			verts[0] = (F32)left;
+			verts[1] = (F32)(top + y_inc);
+			verts[2] = (F32)right;
+			verts[3] = (F32)(top + y_inc);
+
+			// Second color
+			glColor4ub(colors[i + 1].red, colors[i + 1].green, colors[i + 1].blue, colors[i + 1].alpha);
+			verts[4] = (F32)left;
+			verts[5] = (F32)top;
+			verts[6] = (F32)right;
+			verts[7] = (F32)top;
+			glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
+			top += y_inc;
+		}
+	}
+}
+
+#else
+
+void dglDrawBlendBox(const RectI& bounds, ColorF& c1, ColorF& c2, ColorF& c3, ColorF& c4)
+{
+	F32 l = (F32)bounds.point.x;
+	F32 r = (F32)(bounds.point.x + bounds.extent.x);
+	F32 t = (F32)bounds.point.y;
+	F32 b = (F32)(bounds.point.y + bounds.extent.y);
+
+	glEnable(GL_BLEND);
+	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+	glDisable(GL_TEXTURE_2D);
+
+	glBegin(GL_QUADS);
+
+	// Color
+	glColor4fv(c1.address());
+	glVertex2f(l, t);
+	glColor4fv(c4.address());
+	glVertex2f(l, b);
+	glColor4fv(c3.address());
+	glVertex2f(r, b);
+	glColor4fv(c2.address());
+	glVertex2f(r, t);
+
+	glEnd();
+}
+
+//--------------------------------------------------------------------------
+/// Function to draw a set of boxes blending throughout an array of colors
+void dglDrawBlendRangeBox(const RectI& bounds, bool vertical, U8 numColors, ColorI* colors)
+{
+	F32 l = (F32)bounds.point.x;
+	F32 r = (F32)(bounds.point.x + bounds.extent.x);
+	F32 t = (F32)bounds.point.y;
+	F32 b = (F32)(bounds.point.y + bounds.extent.y);
+
+	// Calculate increment value
+	F32 x_inc = F32((r - l) / (numColors - 1));
+	F32 y_inc = F32((b - t) / (numColors - 1));
+
+	glEnable(GL_BLEND);
+	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+	glDisable(GL_TEXTURE_2D);
+
+	glBegin(GL_QUADS);
+	if (!vertical)  // Horizontal (+x)
+	{
+		glColor4ub(colors[0].red, colors[0].green, colors[0].blue, colors[0].alpha);
+		glVertex2f(l, t);
+		glVertex2f(l, b);
+		glVertex2f(l - 1, b);
+		glVertex2f(l - 1, t);
+		glVertex2f(r, t);
+		glVertex2f(r, b);
+		glVertex2f(r + 1, b);
+		glVertex2f(r + 1, t);
+	}
+	else   // Vertical (+y)
+	{
+		glColor4ub(colors[0].red, colors[0].green, colors[0].blue, colors[0].alpha);
+		glVertex2f(l, t);
+		glVertex2f(r, t);
+		glVertex2f(r, t - 1);
+		glVertex2f(l, t - 1);
+		glVertex2f(l, b);
+		glVertex2f(r, b);
+		glVertex2f(r, b + 1);
+		glVertex2f(l, b + 1);
+	}
+
+	for (U16 i = 0; i < numColors - 1; i++)
+	{
+		if (!vertical)  // Horizontal (+x)
+		{
+			// First color
+			glColor4ub(colors[i].red, colors[i].green, colors[i].blue, colors[i].alpha);
+			glVertex2f(l, t);
+			glVertex2f(l, b);
+			// Second color
+			glColor4ub(colors[i + 1].red, colors[i + 1].green, colors[i + 1].blue, colors[i + 1].alpha);
+			glVertex2f(l + x_inc, b);
+			glVertex2f(l + x_inc, t);
+			l += x_inc;
+		}
+		else  // Vertical (+y)
+		{
+			// First color
+			glColor4ub(colors[i].red, colors[i].green, colors[i].blue, colors[i].alpha);
+			glVertex2f(l, t);
+			glVertex2f(r, t);
+			// Second color
+			glColor4ub(colors[i + 1].red, colors[i + 1].green, colors[i + 1].blue, colors[i + 1].alpha);
+			glVertex2f(r, t + y_inc);
+			glVertex2f(l, t + y_inc);
+			t += y_inc;
+		}
+	}
+	glEnd();
+}
+
+#endif
+
+void dglRenderCheckers(const RectI& bounds, const U8 size, const ColorF& c1, const ColorF& c2)
+{
+	F32 l = (F32)bounds.point.x;
+	F32 r = (F32)(bounds.point.x + bounds.extent.x);
+	F32 t = (F32)bounds.point.y;
+	F32 b = (F32)(bounds.point.y + bounds.extent.y);
+
+	glDisable(GL_BLEND);
+	glDisable(GL_TEXTURE_2D);
+
+	glBegin(GL_QUADS);
+	glColor4fv(c2.address());
+	glVertex2f(l, t);
+	glColor4fv(c2.address());
+	glVertex2f(l, b);
+	glColor4fv(c2.address());
+	glVertex2f(r, b);
+	glColor4fv(c2.address());
+	glVertex2f(r, t);
+	glEnd();
+
+	for (U32 y = 0; y < bounds.extent.y; y += size)
+	{
+		for (U32 x = ((y / size) % 2 == 0 ? 0 : size); x < bounds.extent.x; x += (size * 2))
+		{
+			glBegin(GL_QUADS);
+			glColor4fv(c1.address());
+			glVertex2f(l + x, t + y);
+			glColor4fv(c1.address());
+			glVertex2f(l + x, getMin(b, t + y + size));
+			glColor4fv(c1.address());
+			glVertex2f(getMin(r, l + x + size), getMin(b, t + y + size));
+			glColor4fv(c1.address());
+			glVertex2f(getMin(r, l + x + size), t + y);
+			glEnd();
+		}
+	}
+}

+ 4 - 0
engine/source/graphics/dgl.h

@@ -367,3 +367,7 @@ glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
 
 
 
 
 #endif // _H_DGL
 #endif // _H_DGL
+
+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 dglRenderCheckers(const RectI& bounds, const U8 size, const ColorF& c1, const ColorF& c2);

+ 1 - 1
engine/source/gui/editor/guiInspectorTypes.h

@@ -68,7 +68,7 @@
 #endif
 #endif
 
 
 #ifndef _GUICOLORPICKERCTRL_H_
 #ifndef _GUICOLORPICKERCTRL_H_
-#include "gui/guiColorPicker.h"
+#include "gui/guiColorPickerCtrl.h"
 #endif // !_GUICOLORPICKERCTRL_H_
 #endif // !_GUICOLORPICKERCTRL_H_
 
 
 
 

+ 0 - 1000
engine/source/gui/guiColorPicker.cc

@@ -1,1000 +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 "console/console.h"
-#include "graphics/dgl.h"
-#include "console/consoleTypes.h"
-#include "platform/platformAudio.h"
-#include "gui/guiCanvas.h"
-#include "gui/buttons/guiButtonCtrl.h"
-#include "gui/guiDefaultControlRender.h"
-#include "gui/guiColorPicker.h"
-
-/// @name Common colors we use
-/// @{
-ColorF colorWhite(1.,1.,1.);
-ColorF colorWhiteBlend(1.,1.,1.,.75);
-ColorF colorBlack(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);
-
-ColorI GuiColorPickerCtrl::mColorRange[9] = {
-   ColorI(255,255,255), // White
-   ColorI(255,0,0),     // Red
-    ColorI(255,0,255),   // Pink
-    ColorI(0,0,255),     // Blue
-    ColorI(0,255,255),   // Light blue
-    ColorI(0,255,0),     // Green
-    ColorI(255,255,0),   // Yellow
-    ColorI(255,0,0),     // Red
-   ColorI(0,0,0)        // Black
-};
-/// @}
-
-IMPLEMENT_CONOBJECT(GuiColorPickerCtrl);
-
-//--------------------------------------------------------------------------
-GuiColorPickerCtrl::GuiColorPickerCtrl()
-{
-   mBounds.extent.set(140, 30);
-   mDisplayMode = pPallet;
-   mBaseColor = ColorF(1.,.0,1.);
-   mPickColor = ColorF(.0,.0,.0);
-   mSelectorPos = Point2I(0,0);
-   mMouseDown = mMouseOver = false;
-   mActive = true;
-   mPositionChanged = false;
-   mSelectorGap = 1;
-   mActionOnMove = false;
-   mShowSelector = false;
-   mIsContainer = false;
-}
-
-//--------------------------------------------------------------------------
-static EnumTable::Enums gColorPickerModeEnums[] =
-{
-   { GuiColorPickerCtrl::pPallet,		"Pallet"   },
-   { GuiColorPickerCtrl::pHorizColorRange,	"HorizColor"},
-   { GuiColorPickerCtrl::pVertColorRange,	"VertColor" },
-   { GuiColorPickerCtrl::pHorizColorBrightnessRange,	"HorizBrightnessColor"},
-   { GuiColorPickerCtrl::pVertColorBrightnessRange,	"VertBrightnessColor" },
-   { GuiColorPickerCtrl::pBlendColorRange,	"BlendColor"},
-   { GuiColorPickerCtrl::pHorizAlphaRange,	"HorizAlpha"},
-   { GuiColorPickerCtrl::pVertAlphaRange,	"VertAlpha" },
-   { GuiColorPickerCtrl::pDropperBackground,	"Dropper" },
-};
-
-static EnumTable gColorPickerModeTable( 9, gColorPickerModeEnums );
-
-//--------------------------------------------------------------------------
-void GuiColorPickerCtrl::initPersistFields()
-{
-   Parent::initPersistFields();
-   
-   addGroup("ColorPicker");
-   addField("BaseColor", TypeColorF, Offset(mBaseColor, GuiColorPickerCtrl));
-   addField("PickColor", TypeColorF, Offset(mPickColor, GuiColorPickerCtrl));
-   addField("SelectorGap", TypeS32,  Offset(mSelectorGap, GuiColorPickerCtrl)); 
-   addField("DisplayMode", TypeEnum, Offset(mDisplayMode, GuiColorPickerCtrl), 1, &gColorPickerModeTable );
-   addField("ActionOnMove", TypeBool,Offset(mActionOnMove, GuiColorPickerCtrl));
-   addField("ShowSelector", TypeBool, Offset(mShowSelector, GuiColorPickerCtrl));
-   endGroup("ColorPicker");
-}
-
-//--------------------------------------------------------------------------
-// Function to draw a box which can have 4 different colors in each corner blended together
-#if defined(TORQUE_OS_IOS) || defined(TORQUE_OS_ANDROID) || defined(TORQUE_OS_EMSCRIPTEN)
-void dglDrawBlendBox(RectI &bounds, ColorF &c1, ColorF &c2, ColorF &c3, ColorF &c4)
-{
-   GLfloat left = bounds.point.x, right = bounds.point.x + bounds.extent.x - 1;
-   GLfloat top = bounds.point.y, bottom = bounds.point.y + bounds.extent.y - 1;
-   
-   glEnable(GL_BLEND);
-   glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
-   glDisable(GL_TEXTURE_2D);
-    
-    const GLfloat verts[] = {
-        left, top,
-        right,  top,
-        left,  bottom,
-        right,   bottom,
-    };
-    const GLubyte squareColors[] = {
-        static_cast<GLubyte>(255 * c1.red),  static_cast<GLubyte>(255 * c1.green),  static_cast<GLubyte>(255 * c1.blue),  static_cast<GLubyte>(255 * c1.alpha),
-        static_cast<GLubyte>(255 * c2.red),  static_cast<GLubyte>(255 * c2.green),  static_cast<GLubyte>(255 * c2.blue),  static_cast<GLubyte>(255 * c2.alpha),
-        static_cast<GLubyte>(255 * c3.red),  static_cast<GLubyte>(255 * c3.green),  static_cast<GLubyte>(255 * c3.blue),  static_cast<GLubyte>(255 * c3.alpha),
-        static_cast<GLubyte>(255 * c4.red),  static_cast<GLubyte>(255 * c4.green),  static_cast<GLubyte>(255 * c4.blue),  static_cast<GLubyte>(255 * c4.alpha),
-    };
-    glVertexPointer(2, GL_FLOAT, 0, verts);
-    glEnableClientState(GL_VERTEX_ARRAY);
-    glColorPointer(4, GL_UNSIGNED_BYTE, 0, squareColors);
-    glEnableClientState(GL_COLOR_ARRAY);
-    
-    glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
-}
-
-//--------------------------------------------------------------------------
-/// Function to draw a set of boxes blending throughout an array of colors
-void dglDrawBlendRangeBox(RectI &bounds, bool vertical, U8 numColors, ColorI *colors)
-{
-   S32 left = bounds.point.x, right = bounds.point.x + bounds.extent.x - 1;
-   S32 top = bounds.point.y, bottom = bounds.point.y + bounds.extent.y - 1;
-
-   // Calculate increment value
-   S32 x_inc = S32(mFloor((right - left) / (numColors-1)));
-   S32 y_inc = S32(mFloor((bottom - top) / (numColors-1)));
-   
-
-   glEnable(GL_BLEND);
-   glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
-   glDisable(GL_TEXTURE_2D);
-
-    GLfloat verts[] = {
-        0.0f,	0.0f,	0.0f,	0.0f,
-        0.0f,	0.0f,	0.0f,	0.0f,
-    };	
-    
-    glVertexPointer(2, GL_FLOAT, 0, verts);
-    glEnableClientState(GL_VERTEX_ARRAY);
-
-    for (U16 i=0;i<numColors-1;i++) 
-    {
-        // If we are at the end, x_inc and y_inc need to go to the end (otherwise there is a rendering bug)
-        if (i == numColors-2) 
-        {
-            x_inc += right-left-1;
-            y_inc += bottom-top-1;
-        }
-        
-        if (vertical)  // Vertical (+y)		colors go up and down
-        {
-            // First color
-            glColor4ub(colors[i].red, colors[i].green, colors[i].blue, colors[i].alpha);
-            verts[0] = (F32)left;
-            verts[1] = (F32)top;
-            verts[2] = (F32)(left+x_inc);
-            verts[3] = (F32)top;
-            // Second color
-            glColor4ub(colors[i+1].red, colors[i+1].green, colors[i+1].blue, colors[i+1].alpha);
-            
-            verts[4] = (F32)left;
-            verts[5] = (F32)bottom;
-            verts[6] = (F32)(left+x_inc);
-            verts[7] = (F32)bottom;			
-            glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
-            left += x_inc;
-        }
-        else  // Horizontal (+x)	colors go lateral
-        {
-            // First color
-            glColor4ub(colors[i].red, colors[i].green, colors[i].blue, colors[i].alpha);
-            verts[0] = (F32)left;
-            verts[1] = (F32)(top+y_inc);
-            verts[2] = (F32)right;
-            verts[3] = (F32)(top+y_inc);
-            
-            // Second color
-            glColor4ub(colors[i+1].red, colors[i+1].green, colors[i+1].blue, colors[i+1].alpha);
-            verts[4] = (F32)left;
-            verts[5] = (F32)top;
-            verts[6] = (F32)right;
-            verts[7] = (F32)top;			
-            glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
-            top += y_inc;
-        }
-    }	
-}
-//--------------------------------------------------------------------------
-/// Function to invoke calls to draw the picker box and selector
-void GuiColorPickerCtrl::renderColorBox(RectI &bounds)
-{
-   RectI pickerBounds;
-   pickerBounds.point.x = bounds.point.x+1;
-   pickerBounds.point.y = bounds.point.y+1;
-   pickerBounds.extent.x = bounds.extent.x-1;
-   pickerBounds.extent.y = bounds.extent.y-1;
-   
-   //if (mProfile->mBorder)
-   //   dglDrawRect(bounds, mProfile->mBorderColor);
-      
-   Point2I selectorPos = Point2I(bounds.point.x+mSelectorPos.x+1, bounds.point.y+mSelectorPos.y+1);
-
-   // Draw color box differently depending on mode
-   RectI blendRect;
-   switch (mDisplayMode)
-   {
-   case pHorizColorRange:
-      dglDrawBlendRangeBox( pickerBounds, false, 7, mColorRange + 2);
-      drawSelector( pickerBounds, selectorPos, sVertical );
-   break;
-   case pVertColorRange:
-      dglDrawBlendRangeBox( pickerBounds, true, 7, mColorRange + 2);
-      drawSelector( pickerBounds, selectorPos, sHorizontal );
-   break;
-   case pHorizColorBrightnessRange:
-      blendRect = pickerBounds;
-      blendRect.point.y++;
-      blendRect.extent.y += 2;
-      dglDrawBlendRangeBox( pickerBounds, false, 9, mColorRange);
-      // This is being drawn slightly offset from the larger rect so as to insure 255 and 0
-      // can both be selected for every color.
-      dglDrawBlendBox( blendRect, colorAlpha, colorAlpha, colorBlack, colorBlack );
-      blendRect.point.y += blendRect.extent.y - 1;
-      //blendRect.extent.y = 2;
-      dglDrawRect( blendRect, colorBlack);
-      drawSelector( pickerBounds, selectorPos, sVertical );
-      drawSelector( pickerBounds, selectorPos, sHorizontal );
-   break;
-   case pVertColorBrightnessRange:
-      dglDrawBlendRangeBox( pickerBounds, true, 9, mColorRange);
-      dglDrawBlendBox( pickerBounds, colorAlpha, colorAlpha, colorBlack, colorBlack );
-      drawSelector( pickerBounds, selectorPos, sHorizontal );
-      drawSelector( pickerBounds, selectorPos, sVertical );
-   break;
-   case pHorizAlphaRange:
-      dglDrawBlendBox( pickerBounds, colorBlack, colorWhite, colorBlack, colorWhite );
-      drawSelector( pickerBounds, selectorPos, sVertical );
-   break;
-   case pVertAlphaRange:
-      dglDrawBlendBox( pickerBounds, colorBlack, colorBlack, colorWhite, colorWhite );
-      drawSelector( pickerBounds, selectorPos, sHorizontal ); 
-   break;
-   case pBlendColorRange:
-      dglDrawBlendBox( pickerBounds, colorWhite, mBaseColor, colorBlack, colorBlack );
-      drawSelector( pickerBounds, selectorPos, sHorizontal );      
-      drawSelector( pickerBounds, selectorPos, sVertical );
-   break;
-   case pDropperBackground:
-   break;
-   case pPallet:
-   default:
-      dglDrawRectFill( pickerBounds, mBaseColor );
-   break;
-   }
-}
-
-#else
-
-void dglDrawBlendBox(RectI &bounds, ColorF &c1, ColorF &c2, ColorF &c3, ColorF &c4)
-{
-   F32 l = (F32)(bounds.point.x + 1);
-   F32 r =(F32)(bounds.point.x + bounds.extent.x - 2);
-   F32 t = (F32)(bounds.point.y + 1);
-   F32 b = (F32)(bounds.point.y + bounds.extent.y - 2);
-   
-   glEnable(GL_BLEND);
-   glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
-   glDisable(GL_TEXTURE_2D);
-
-   glBegin(GL_QUADS);
-
-      // Color
-      glColor4fv(c2.address());
-      glVertex2f(l, t);
-      glColor4fv(c2.address());
-      glVertex2f(r, t);
-      glColor4fv(c2.address());
-      glVertex2f(r, b);
-      glColor4fv(c2.address());
-      glVertex2f(l, b);
-
-      // White
-      glColor4fv(c1.address());
-      glVertex2f(l, t);
-      glColor4fv(colorAlphaW.address());
-      glVertex2f(r, t);
-      glColor4fv(colorAlphaW.address());
-      glVertex2f(r, b);
-      glColor4fv(c1.address());
-      glVertex2f(l, b);
-
-      // Black
-      glColor4fv(c3.address());
-      glVertex2f(l, t);
-      glColor4fv(c3.address());
-      glVertex2f(r, t);
-      glColor4fv(c4.address());
-      glVertex2f(r, b);
-      glColor4fv(c4.address());
-      glVertex2f(l, b);
-
-      // Top right
-      glColor4fv(c2.address());
-      glVertex2f(r, t);
-      glColor4fv(c2.address());
-      glVertex2f(r, t+1);
-      glColor4fv(c2.address());
-      glVertex2f(r-1, t+1);
-      glColor4fv(c2.address());
-      glVertex2f(r-1, t);
-      
-      // Top-Right Corner
-      glColor4fv(c2.address());
-      glVertex2f(r, t);
-      glColor4fv(c2.address());
-      glVertex2f(r, t-1);
-      glColor4fv(c2.address());
-      glVertex2f(r+1, t-1);
-      glColor4fv(c2.address());
-      glVertex2f(r+1, t);
-
-      // Top-Right Corner
-      glColor4fv(c1.address());
-      glVertex2f(l, t);
-      glColor4fv(c1.address());
-      glVertex2f(l, t-1);
-      glColor4fv(c1.address());
-      glVertex2f(l-1, t-1);
-      glColor4fv(c1.address());
-      glVertex2f(l-1, t);
-
-      // Top row
-      glColor4fv(c1.address());
-      glVertex2f(l, t);
-      glColor4fv(c1.address());
-      glVertex2f(l, t-1);
-      glColor4fv(c2.address());
-      glVertex2f(r, t-1);
-      glColor4fv(c2.address());
-      glVertex2f(r, t);
-      
-
-      // Right side
-      glColor4fv(c2.address());
-      glVertex2f(r, t);
-      glColor4fv(c2.address());
-      glVertex2f(r+1, t);
-      glColor4fv(c4.address());
-      glVertex2f(r+1, b);
-      glColor4fv(c4.address());
-      glVertex2f(r, b);
-
-      // Left side
-      glColor4fv(c1.address());
-      glVertex2f(l, t);
-      glColor4fv(c1.address());
-      glVertex2f(l-1, t);
-      glColor4fv(c4.address());
-      glVertex2f(l-1, b);
-      glColor4fv(c4.address());
-      glVertex2f(l, b);
-
-      // Bottom row
-      glColor4fv(c4.address());
-      glVertex2f(l-1, b);
-      glColor4fv(c4.address());
-      glVertex2f(l-1, b+1);
-      glColor4fv(c4.address());
-      glVertex2f(r+1, b+1);
-      glColor4fv(c4.address());
-      glVertex2f(r+1, b);
-
-   glEnd();
-}
-
-//--------------------------------------------------------------------------
-/// Function to draw a set of boxes blending throughout an array of colors
-void dglDrawBlendRangeBox(RectI &bounds, bool vertical, U8 numColors, ColorI *colors)
-{
-   F32 l = (F32)bounds.point.x;
-   F32 r = (F32)(bounds.point.x + bounds.extent.x - 1);
-   F32 t = (F32)bounds.point.y + 1;
-   F32 b = (F32)(bounds.point.y + bounds.extent.y - 2);
-   
-   // Calculate increment value
-   F32 x_inc = F32((r - l) / (numColors-1));
-   F32 y_inc = F32((b - t) / (numColors-1));
-   
-   glEnable(GL_BLEND);
-   glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
-   glDisable(GL_TEXTURE_2D);
-
-   glBegin(GL_QUADS);
-      if (!vertical)  // Horizontal (+x)
-      {
-            glColor4ub(colors[0].red, colors[0].green, colors[0].blue, colors[0].alpha);
-            glVertex2f(l, t);
-            glVertex2f(l, b);
-            glVertex2f(l-1, b);
-            glVertex2f(l-1, t);
-            glVertex2f(r, t);
-            glVertex2f(r, b);
-            glVertex2f(r+1, b);
-            glVertex2f(r+1, t);
-      }
-      else   // Vertical (+y)
-      {
-            glColor4ub(colors[0].red, colors[0].green, colors[0].blue, colors[0].alpha);
-            glVertex2f(l, t);
-            glVertex2f(r, t);
-            glVertex2f(r, t-1);
-            glVertex2f(l, t-1);
-            glVertex2f(l, b);
-            glVertex2f(r, b);
-            glVertex2f(r, b+1);
-            glVertex2f(l, b+1);
-      }
-
-      for (U16 i=0;i<numColors-1;i++) 
-      {
-         if (!vertical)  // Horizontal (+x)
-         {
-            // First color
-            glColor4ub(colors[i].red, colors[i].green, colors[i].blue, colors[i].alpha);
-            glVertex2f(l, t);
-            glVertex2f(l, b);
-            // Second color
-            glColor4ub(colors[i+1].red, colors[i+1].green, colors[i+1].blue, colors[i+1].alpha);
-            glVertex2f(l+x_inc, b);
-            glVertex2f(l+x_inc, t);
-            l += x_inc;
-         }
-         else  // Vertical (+y)
-         {
-            // First color
-            glColor4ub(colors[i].red, colors[i].green, colors[i].blue, colors[i].alpha);
-            glVertex2f(l, t);
-            glVertex2f(r, t);
-            // Second color
-            glColor4ub(colors[i+1].red, colors[i+1].green, colors[i+1].blue, colors[i+1].alpha);
-            glVertex2f(r, t+y_inc);
-            glVertex2f(l, t+y_inc);
-            t += y_inc;
-        }
-     }
-   glEnd();
-}
-
-//--------------------------------------------------------------------------
-/// Function to invoke calls to draw the picker box and selector
-void GuiColorPickerCtrl::renderColorBox(RectI &bounds)
-{
-   RectI pickerBounds;
-   pickerBounds.point.x = bounds.point.x+1;
-   pickerBounds.point.y = bounds.point.y+1;
-   pickerBounds.extent.x = bounds.extent.x-1;
-   pickerBounds.extent.y = bounds.extent.y-1;
-   
-   if (mProfile->mBorderDefault && mProfile->mBorderDefault->mBorder[0] > 0)
-      dglDrawRect(bounds, mProfile->mBorderDefault->mBorderColor[0]);
-      
-   Point2I selectorPos = Point2I(bounds.point.x+mSelectorPos.x+1, bounds.point.y+mSelectorPos.y+1);
-
-   // Draw color box differently depending on mode
-   RectI blendRect;
-   switch (mDisplayMode)
-   {
-   case pHorizColorRange:
-      dglDrawBlendRangeBox( pickerBounds, false, 7, mColorRange + 1);
-      drawSelector( pickerBounds, selectorPos, sVertical );
-   break;
-   case pVertColorRange:
-      dglDrawBlendRangeBox( pickerBounds, true, 7, mColorRange + 1);
-      drawSelector( pickerBounds, selectorPos, sHorizontal );
-   break;
-   case pHorizColorBrightnessRange:
-      blendRect = pickerBounds;
-      blendRect.point.y++;
-      blendRect.extent.y -= 2;
-      dglDrawBlendRangeBox( pickerBounds, false, 9, mColorRange);
-      // This is being drawn slightly offset from the larger rect so as to insure 255 and 0
-      // can both be selected for every color.
-      dglDrawBlendBox( blendRect, colorAlpha, colorAlpha, colorBlack, colorBlack );
-      blendRect.point.y += blendRect.extent.y - 1;
-      blendRect.extent.y = 2;
-      dglDrawRect( blendRect, colorBlack);
-      drawSelector( pickerBounds, selectorPos, sHorizontal );
-      drawSelector( pickerBounds, selectorPos, sVertical );
-   break;
-   case pVertColorBrightnessRange:
-      dglDrawBlendRangeBox( pickerBounds, true, 9, mColorRange);
-      dglDrawBlendBox( pickerBounds, colorAlpha, colorBlack, colorBlack, colorAlpha );
-      drawSelector( pickerBounds, selectorPos, sHorizontal );
-      drawSelector( pickerBounds, selectorPos, sVertical );
-   break;
-   case pHorizAlphaRange:
-      dglDrawBlendBox( pickerBounds, colorBlack, colorWhite, colorWhite, colorBlack );
-      drawSelector( pickerBounds, selectorPos, sVertical );
-   break;
-   case pVertAlphaRange:
-      dglDrawBlendBox( pickerBounds, colorBlack, colorBlack, colorWhite, colorWhite );
-      drawSelector( pickerBounds, selectorPos, sHorizontal ); 
-   break;
-   case pBlendColorRange:
-      dglDrawBlendBox( pickerBounds, colorWhite, mBaseColor, colorAlpha, colorBlack );
-      drawSelector( pickerBounds, selectorPos, sHorizontal );      
-      drawSelector( pickerBounds, selectorPos, sVertical );
-   break;
-   case pDropperBackground:
-   break;
-   case pPallet:
-   default:
-      dglDrawRectFill( pickerBounds, mBaseColor );
-   break;
-   }
-}
-#endif
-
-void GuiColorPickerCtrl::drawSelector(RectI &bounds, Point2I &selectorPos, SelectorMode mode)
-{
-    if (!mShowSelector)
-        return;
-
-    U16 sMax = mSelectorGap*2;
-    switch (mode)
-    {
-        case sVertical:
-            // Now draw the vertical selector
-            // Up -> Pos
-            if (selectorPos.y != bounds.point.y+1)
-                dglDrawLine(selectorPos.x, bounds.point.y, selectorPos.x, selectorPos.y-sMax-1, colorWhiteBlend);
-            // Down -> Pos
-            if (selectorPos.y != bounds.point.y+bounds.extent.y) 
-                dglDrawLine(selectorPos.x,	selectorPos.y + sMax, selectorPos.x, bounds.point.y + bounds.extent.y, colorWhiteBlend);
-        break;
-        case sHorizontal:
-            // Now draw the horizontal selector
-            // Left -> Pos
-            if (selectorPos.x != bounds.point.x) 
-            dglDrawLine(bounds.point.x, selectorPos.y-1, selectorPos.x-sMax, selectorPos.y-1, colorWhiteBlend);
-            // Right -> Pos
-            if (selectorPos.x != bounds.point.x) 
-            dglDrawLine(bounds.point.x+mSelectorPos.x+sMax, selectorPos.y-1, bounds.point.x + bounds.extent.x, selectorPos.y-1, colorWhiteBlend);
-        break;
-    }
-}
-
-void GuiColorPickerCtrl::onRender(Point2I offset, const RectI& updateRect)
-{
-   RectI boundsRect(offset, mBounds.extent); 
-   renderColorBox(boundsRect);
-
-   if (mPositionChanged) 
-   {
-      mPositionChanged = false;
-      Point2I extent = Canvas->getExtent();
-      // If we are anything but a pallete, change the pick color
-      if (mDisplayMode != pPallet) 
-      {
-         // To simplify things a bit, just read the color via glReadPixels()
-
-         // [neo, 5/30/2007 - #3175]
-         // glReadPixels does not even look at the format passed in, it just assumes 
-         // GL_RGBA and a dword buffer, so we  can't use GL_FLOAT, etc. glReadPixels
-         // was borked in D3D and not calculating the correct offset rectangle etc 
-         // so I changed it to match the OGL version functionality exactly.
-         // [see glReadPixels in OpenGL2D3C.cc]
-         
-         // glFloat rBuffer[4];
-         //glReadPixels( buf_x, buf_y, 1, 1, GL_RGBA, GL_FLOAT, rBuffer);
-         //mPickColor.red = rBuffer[0];
-         //mPickColor.green = rBuffer[1];
-         //mPickColor.blue = rBuffer[2];
-         //mPickColor.alpha = rBuffer[3]; 
-
-         GLubyte rBuffer[4] = { 255, 255, 255, 255 };
-
-         glReadBuffer( GL_BACK );
-
-         U32 buf_x = offset.x + mSelectorPos.x + 1;
-         U32 buf_y = extent.y - ( offset.y + mSelectorPos.y + 1 );
-                  
-         glReadPixels( buf_x, buf_y, 1, 1, GL_RGB, GL_UNSIGNED_BYTE, rBuffer );
-      
-         mPickColor = ColorI( rBuffer[ 0 ], rBuffer[ 1 ], rBuffer[ 2 ], 255 );
-
-         // Now do onAction() if we are allowed
-         if (mActionOnMove) 
-            onAction();
-      }
-   }
-   
-   //render the children
-   renderChildControls( offset, mBounds, updateRect);
-}
-
-//--------------------------------------------------------------------------
-void GuiColorPickerCtrl::setSelectorPos(const Point2I &pos)
-{
-   Point2I extent = mBounds.extent;
-   RectI rect;
-   if (mDisplayMode != pDropperBackground) 
-   {
-      extent.x -= 2;
-      extent.y -= 2;
-      rect = RectI(Point2I(0,1), extent);
-   }
-   else
-   {
-      rect = RectI(Point2I(0,0), extent);
-   }
-   
-   if (rect.pointInRect(pos)) 
-   {
-      mSelectorPos = pos;
-      mPositionChanged = true;
-      // We now need to update
-      setUpdate();
-   }
-
-   else
-   {
-      if ((pos.x > rect.point.x) && (pos.x < (rect.point.x + rect.extent.x)))
-         mSelectorPos.x = pos.x;
-      else if (pos.x <= rect.point.x)
-         mSelectorPos.x = rect.point.x;
-      else if (pos.x >= (rect.point.x + rect.extent.x))
-         mSelectorPos.x = rect.point.x + rect.extent.x - 1;
-
-      if ((pos.y > rect.point.y) && (pos.y < (rect.point.y + rect.extent.y)))
-         mSelectorPos.y = pos.y;
-      else if (pos.y <= rect.point.y)
-         mSelectorPos.y = rect.point.y;
-      else if (pos.y >= (rect.point.y + rect.extent.y))
-         mSelectorPos.y = rect.point.y + rect.extent.y - 1;
-
-      mPositionChanged = true;
-      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)
-{
-    // Calculate hue
-    F32 hue = colorHue(targetColor);
-
-    // Transform the hue value to [0-1].
-    F32 hueFraction = hue / 360;
-
-    // Calculate position in range box
-    Point2I position;
-    if (vertical)
-    {
-        position.x = (S32)(0.5f * (bounds.extent.x));
-        position.y = (S32)((1.0f - hueFraction) * (bounds.extent.y));
-    }
-    else
-    {
-        position.x = (S32)((1.0f - hueFraction) * (bounds.extent.x));
-        position.y = (S32)(0.5f * (bounds.extent.y));
-    }
-
-    return position;
-}
-
-Point2I GuiColorPickerCtrl::getBlendBoxColorPos(RectI &bounds, ColorF targetColor)
-{
-    // Calculate hue
-    F32 hue = colorHue(targetColor);
-
-    
-    // Calculate the largest, smallest RGB components of the hue
-    F32 largest, smallest, baseLargest, baseSmallest;
-    if (hue >= 0 && hue < 60)
-    {
-        largest = targetColor.red;
-        smallest = targetColor.blue;
-        baseLargest = mBaseColor.red;
-        baseSmallest = mBaseColor.blue;
-    }
-    else if (hue >= 60 && hue < 120)
-    {
-        largest = targetColor.green;
-        smallest = targetColor.blue;
-        baseLargest = mBaseColor.green;
-        baseSmallest = mBaseColor.blue;
-    }
-    else if (hue >= 120 && hue < 180)
-    {
-        largest = targetColor.green;
-        smallest = targetColor.red;
-        baseLargest = mBaseColor.green;
-        baseSmallest = mBaseColor.red;
-    }
-    else if (hue >= 180 && hue < 240)
-    {
-        largest = targetColor.blue;
-        smallest = targetColor.red;
-        baseLargest = mBaseColor.blue;
-        baseSmallest = mBaseColor.red;
-    }
-    else if (hue >= 240 && hue < 300)
-    {
-        largest = targetColor.blue;
-        smallest = targetColor.green;
-        baseLargest = mBaseColor.blue;
-        baseSmallest = mBaseColor.green;
-    }
-    else if (hue >= 300 && hue < 360)
-    {
-        largest = targetColor.red;
-        smallest = targetColor.green;
-        baseLargest = mBaseColor.red;
-        baseSmallest = mBaseColor.green;
-    }
-    else
-    {
-        // Color hue must be between 0 and 360.
-        Con::errorf("getBlendBoxColorPos - Color hue is outside allowable range.");
-        return Point2I(0,0);
-    }
-
-    // Calculate position in range box
-    Point2I position;
-
-    F32 h = 1.0f - (smallest / largest);
-    F32 v = 1.0f - largest;
-
-    position.x = (S32)(h * (bounds.extent.x - 1));
-    position.y = (S32)(v * (bounds.extent.y - 1));
-
-    return position;
-}
-
-Point2I GuiColorPickerCtrl::getSelectorPositionForColor(RectI &bounds, ColorF targetColor)
-{
-    Point2I position(0,0);
-
-    switch (mDisplayMode)
-    {
-        case pHorizColorRange:
-            position = getRangeBoxColorPos(bounds, false, targetColor);
-            break;
-        case pVertColorRange:
-            position = getRangeBoxColorPos(bounds, true, targetColor);
-            break;
-
-        case pBlendColorRange:
-            position = getBlendBoxColorPos(bounds, targetColor);
-            break;
-
-        default:
-             Con::errorf("Display mode does not support the function: getSelectorPositionForColor().");
-            break;
-    }
-
-    return position;
-}
-
-
-//--------------------------------------------------------------------------
-void GuiColorPickerCtrl::onTouchDown(const GuiEvent &event)
-{
-   if (!mActive)
-      return;
-   
-   if (mDisplayMode == pDropperBackground)
-      return;
-
-   mouseLock(this);
-   
-   if (mProfile->mCanKeyFocus)
-      setFirstResponder();
-
-   // Update the picker cross position
-   if (mDisplayMode != pPallet)
-      setSelectorPos(globalToLocalCoord(event.mousePoint)); 
-   
-   mMouseDown = true;
-
-   Con::executef(this, 1, "onTouchDown");
-}
-
-//--------------------------------------------------------------------------
-void GuiColorPickerCtrl::onTouchDragged(const GuiEvent &event)
-{
-   if ((mActive && mMouseDown) || (mActive && (mDisplayMode == pDropperBackground)))
-   {
-      // Update the picker cross position
-      if (mDisplayMode != pPallet)
-         setSelectorPos(globalToLocalCoord(event.mousePoint));
-   }
-
-   if (!mActionOnMove && mAltConsoleCommand[0] )
-      Con::evaluate( mAltConsoleCommand, false );
-
-   Con::executef(this, 1, "onTouchDragged");
-}
-
-//--------------------------------------------------------------------------
-void GuiColorPickerCtrl::onTouchMove(const GuiEvent &event)
-{
-   // Only for dropper mode
-   if (mActive && (mDisplayMode == pDropperBackground))
-      setSelectorPos(globalToLocalCoord(event.mousePoint));
-
-   Con::executef(this, 1, "onTouchMove");
-}
-
-//--------------------------------------------------------------------------
-void GuiColorPickerCtrl::onTouchEnter(const GuiEvent &event)
-{
-   mMouseOver = true;
-
-   Con::executef(this, 1, "onTouchEnter");
-}
-
-//--------------------------------------------------------------------------
-void GuiColorPickerCtrl::onTouchLeave(const GuiEvent &)
-{
-   // Reset state
-   mMouseOver = false;
-
-   Con::executef(this, 1, "onTouchLeave");
-}
-
-//--------------------------------------------------------------------------
-void GuiColorPickerCtrl::onTouchUp(const GuiEvent &)
-{
-   //if we released the mouse within this control, perform the action
-   if (mActive && mMouseDown && (mDisplayMode != pDropperBackground)) 
-   {
-      onAction();
-      mMouseDown = false;
-   }
-   else if (mActive && (mDisplayMode == pDropperBackground)) 
-   {
-      // In a dropper, the alt command executes the mouse up action (to signal stopping)
-      if ( mAltConsoleCommand[0] )
-         Con::evaluate( mAltConsoleCommand, false );
-   }
-   
-   mouseUnlock();
-
-   Con::executef(this, 1, "onTouchUp");
-}
-
-//--------------------------------------------------------------------------
-const char *GuiColorPickerCtrl::getScriptValue()
-{
-   static char temp[256];
-   ColorF color = getValue();
-   dSprintf(temp,256,"%g %g %g %g",color.red, color.green, color.blue, color.alpha);
-   return temp; 
-}
-
-//--------------------------------------------------------------------------    
-void GuiColorPickerCtrl::setScriptValue(const char *value)
-{
-   ColorF newValue;
-   dSscanf(value, "%g %g %g %g", &newValue.red, &newValue.green, &newValue.blue, &newValue.alpha);
-   setValue(newValue);
-}
-
-ConsoleMethod(GuiColorPickerCtrl, getSelectorPos, const char*, 2, 2, "() Gets the current position of the selector\n"
-              "@return Returns the position of the selector as space-separted x,y coordinates.")
-{
-   char *temp = Con::getReturnBuffer(256);
-   Point2I pos;
-   pos = object->getSelectorPos();
-   dSprintf(temp,256,"%d %d",pos.x, pos.y); 
-   return temp;
-}
-
-ConsoleMethod(GuiColorPickerCtrl, getSelectorPos2, const char*, 2, 2, "() Gets the current position of the selector\n"
-              "@return Returns the position of the selector as space-separted x,y coordinates.")
-{
-   char *temp = Con::getReturnBuffer(256);
-   Point2I pos;
-   pos = object->getSelectorPos();
-   dSprintf(temp,256,"%d %d",pos.x, pos.y); 
-   return temp;
-}
-
-ConsoleMethod(GuiColorPickerCtrl, getSelectorPosForColor, const char*, 3, 6, "(float red, float green, float blue, [float alpha = 1.0]) - Gets the selector position for the specified color."
-                                                          "The display mode must be pHorizColorRange, pVertColorRange, or pBlendColorRange.\n"
-                                                          "@param red The red value.\n"
-                                                          "@param green The green value.\n"
-                                                          "@param blue The blue value.\n"
-                                                          "@param alpha The alpha value.\n"
-              "@return Returns the position of the selector as space-separted x,y coordinates.")
-{
-    // The colors.
-    F32 red;
-    F32 green;
-    F32 blue;
-    F32 alpha = 1.0f;
-
-    // Grab the element count.
-    U32 elementCount = Utility::mGetStringElementCount(argv[2]);
-
-    // Space separated.
-    if (argc < 4)
-    {
-        // ("R G B [A]")
-        if ((elementCount == 3) || (elementCount == 4))
-        {
-            // Extract the color.
-            red   = dAtof(Utility::mGetStringElement(argv[2], 0));
-            green = dAtof(Utility::mGetStringElement(argv[2], 1));
-            blue  = dAtof(Utility::mGetStringElement(argv[2], 2));
-
-            // Grab the alpha if it's there.
-            if (elementCount > 3)
-            alpha = dAtof(Utility::mGetStringElement(argv[2], 3));
-        }
-
-        // Invalid.
-        else
-        {
-            Con::warnf("GuiColorPickerCtrl::getSelectorPosForColor() - Invalid Number of parameters!");
-            return StringTable->EmptyString;
-        }
-    }
-
-    // (R, G, B)
-    else if (argc >= 5)
-    {
-        red   = dAtof(argv[2]);
-        green = dAtof(argv[3]);
-        blue  = dAtof(argv[4]);
-
-        // Grab the alpha if it's there.
-        if (argc > 5)
-            alpha = dAtof(argv[5]);
-    }
-
-    // Invalid.
-    else
-    {
-        Con::warnf("GuiColorPickerCtrl::getSelectorPosForColor() - Invalid Number of parameters!");
-        return StringTable->EmptyString;
-    }
-
-    char *temp = Con::getReturnBuffer(256);
-    Point2I pos;
-    pos = object->getSelectorPositionForColor(object->mBounds, ColorF(red, green, blue, alpha));
-    dSprintf(temp,256,"%d %d",pos.x, pos.y); 
-    return temp;
-}
-
-ConsoleMethod(GuiColorPickerCtrl, setSelectorPos, void, 3, 3, "(\"x y\")Sets the current position of the selector"
-              "@param The coordinates with space-separated formating.\n"
-              "@return No return value.")
-{
-   Point2I newPos;
-   dSscanf(argv[2], "%d %d", &newPos.x, &newPos.y);
-   object->setSelectorPos(newPos);
-}
-
-ConsoleMethod(GuiColorPickerCtrl, updateColor, void, 2, 2, "() Forces update of pick color\n"
-              "@return No return value.")
-{
-    object->updateColor();
-}

+ 654 - 0
engine/source/gui/guiColorPickerCtrl.cc

@@ -0,0 +1,654 @@
+//-----------------------------------------------------------------------------
+// Copyright (c) 2013 GarageGames, LLC
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to
+// deal in the Software without restriction, including without limitation the
+// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+// IN THE SOFTWARE.
+//-----------------------------------------------------------------------------
+#include "console/console.h"
+#include "graphics/dgl.h"
+#include "console/consoleTypes.h"
+#include "platform/platformAudio.h"
+#include "gui/guiCanvas.h"
+#include "gui/buttons/guiButtonCtrl.h"
+#include "gui/guiDefaultControlRender.h"
+#include "gui/guiColorPickerCtrl.h"
+
+#include "gui/guiColorPickerCtrl_ScriptBinding.h"
+
+/// @name Common colors we use
+/// @{
+ColorF colorWhite(1., 1., 1.);
+ColorF colorWhiteBlend(1., 1., 1., .75);
+ColorF colorBlack(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 colorGray1(0.5f, 0.5f, 0.5f, 1.0f);
+ColorF colorGray2(0.63f, 0.63f, 0.63f, 1.0f);
+
+ColorI GuiColorPickerCtrl::mColorRange[9] = {
+   ColorI(255,255,255), // White
+   ColorI(255,0,0),     // Red
+	ColorI(255,255,0),   // Yellow
+	ColorI(0,255,0),     // Green
+	ColorI(0,255,255),   // Light blue
+	ColorI(0,0,255),     // Blue
+	ColorI(255,0,255),   // Pink
+	ColorI(255,0,0),     // Red
+   ColorI(0,0,0)        // Black
+};
+/// @}
+
+IMPLEMENT_CONOBJECT(GuiColorPickerCtrl);
+
+//--------------------------------------------------------------------------
+GuiColorPickerCtrl::GuiColorPickerCtrl()
+{
+	mBounds.extent.set(60, 30);
+	mDisplayMode = pPallet;
+	mBaseColor = ColorF(0.475, 0.494, 0.965); //Cornflower Blue ;)
+	mPickColor = ColorF(0.475, 0.494, 0.965);
+	mSelectorPos = Point2I(0, 0);
+	mMouseDown = mMouseOver = false;
+	mActive = true;
+	mPositionChanged = true;
+	mActionOnMove = false;
+	mShowSelector = false;
+	mIsContainer = false;
+
+	mProfile = NULL;
+	mSelectorProfile = NULL;
+
+	setField("profile", "GuiDefaultProfile");
+	setField("SelectorProfile", "GuiColorSelectorProfile");
+}
+
+//--------------------------------------------------------------------------
+static EnumTable::Enums gColorPickerModeEnums[] =
+{
+   { GuiColorPickerCtrl::pPallet,		"Pallet"   },
+   { GuiColorPickerCtrl::pHorizColorRange,	"HorizColor"},
+   { GuiColorPickerCtrl::pVertColorRange,	"VertColor" },
+   { GuiColorPickerCtrl::pHorizColorBrightnessRange,	"HorizBrightnessColor"},
+   { GuiColorPickerCtrl::pVertColorBrightnessRange,	"VertBrightnessColor" },
+   { GuiColorPickerCtrl::pBlendColorRange,	"BlendColor"},
+   { GuiColorPickerCtrl::pHorizAlphaRange,	"HorizAlpha"},
+   { GuiColorPickerCtrl::pVertAlphaRange,	"VertAlpha" },
+   { GuiColorPickerCtrl::pDropperBackground,	"Dropper" },
+};
+
+static EnumTable gColorPickerModeTable(9, gColorPickerModeEnums);
+
+//--------------------------------------------------------------------------
+void GuiColorPickerCtrl::initPersistFields()
+{
+	Parent::initPersistFields();
+
+	addGroup("ColorPicker");
+	addField("BaseColor", TypeColorF, Offset(mBaseColor, GuiColorPickerCtrl));
+	addField("PickColor", TypeColorF, Offset(mPickColor, GuiColorPickerCtrl));
+	addField("DisplayMode", TypeEnum, Offset(mDisplayMode, GuiColorPickerCtrl), 1, &gColorPickerModeTable);
+	addField("ActionOnMove", TypeBool, Offset(mActionOnMove, GuiColorPickerCtrl));
+	addField("ShowSelector", TypeBool, Offset(mShowSelector, GuiColorPickerCtrl));
+	addField("SelectorProfile", TypeGuiProfile, Offset(mSelectorProfile, GuiColorPickerCtrl));
+	endGroup("ColorPicker");
+}
+
+
+bool GuiColorPickerCtrl::onWake()
+{
+	if (!Parent::onWake())
+		return false;
+
+	//increment the tab profile
+	if (mSelectorProfile != NULL)
+		mSelectorProfile->incRefCount();
+
+	return true;
+}
+
+void GuiColorPickerCtrl::onSleep()
+{
+	Parent::onSleep();
+
+	//decrement the tab profile referrence
+	if (mSelectorProfile != NULL)
+		mSelectorProfile->decRefCount();
+}
+
+//--------------------------------------------------------------------------
+/// Function to invoke calls to draw the picker box and selector
+void GuiColorPickerCtrl::renderColorBox(const RectI& pickerBounds)
+{
+	RectI oldClip = dglGetClipRect();
+	RectI clipRect = RectI(pickerBounds);
+	clipRect.intersect(oldClip);
+	dglSetClipRect(clipRect);
+
+	ColorF baseAlpha = ColorF(mBaseColor);
+	baseAlpha.alpha = 0.0f;
+
+	// Draw color box differently depending on mode
+	RectI blendRect;
+	switch (mDisplayMode)
+	{
+	case pHorizColorRange:
+		dglDrawBlendRangeBox(pickerBounds, false, 7, mColorRange + 1);
+		break;
+	case pVertColorRange:
+		dglDrawBlendRangeBox(pickerBounds, true, 7, mColorRange + 1);
+		break;
+	case pHorizColorBrightnessRange:
+		dglDrawBlendRangeBox(pickerBounds, false, 7, mColorRange + 1);
+		blendRect = pickerBounds;
+		blendRect.point.y++;
+		blendRect.extent.y--;
+		dglDrawBlendBox(blendRect, colorAlpha, colorAlpha, colorBlack, colorBlack);
+		break;
+	case pVertColorBrightnessRange:
+		dglDrawBlendRangeBox(pickerBounds, true, 7, mColorRange + 1);
+		blendRect = pickerBounds;
+		blendRect.point.x++;
+		blendRect.extent.x--;
+		dglDrawBlendBox(pickerBounds, colorAlpha, colorBlack, colorBlack, colorAlpha);
+		break;
+	case pHorizAlphaRange:
+		dglRenderCheckers(pickerBounds, 12, colorGray1, colorGray2);
+		dglDrawBlendBox(pickerBounds, baseAlpha, mBaseColor, mBaseColor, baseAlpha);
+		break;
+	case pVertAlphaRange:
+		dglRenderCheckers(pickerBounds, 12, colorGray1, colorGray2);
+		dglDrawBlendBox(pickerBounds, baseAlpha, baseAlpha, mBaseColor, mBaseColor);
+		break;
+	case pBlendColorRange:
+		dglDrawBlendBox(pickerBounds, colorWhite, mBaseColor, colorBlack, colorBlack);
+		break;
+	case pDropperBackground:
+		break;
+	case pPallet:
+	default:
+		dglDrawRectFill(pickerBounds, mBaseColor);
+		break;
+	}
+	dglSetClipRect(oldClip);
+}
+
+void GuiColorPickerCtrl::renderSelector(const RectI& pickerBounds)
+{
+	RectI oldClip = dglGetClipRect();
+	RectI clipRect = RectI(pickerBounds);
+	clipRect.intersect(oldClip);
+	dglSetClipRect(clipRect);
+
+	Point2I selectorPos = localToGlobalCoord(mSelectorPos);
+
+	if (mDisplayMode != pPallet && mDisplayMode != pDropperBackground)
+	{
+		if (mDisplayMode == pHorizColorBrightnessRange ||
+			mDisplayMode == pVertColorBrightnessRange ||
+			mDisplayMode == pBlendColorRange)
+		{
+			drawSelector(pickerBounds, selectorPos, sHorizontal);
+			drawSelector(pickerBounds, selectorPos, sVertical);
+		}
+		drawSelector(pickerBounds, selectorPos, sCircle);
+	}
+	dglSetClipRect(oldClip);
+}
+
+void GuiColorPickerCtrl::drawSelector(const RectI& bounds, Point2I& selectorPos, SelectorMode mode)
+{
+	//bounds is a global rect. The clip rect has been set to the bounds.
+	//selectorPos is a global position.
+	if (!mShowSelector || !mSelectorProfile)
+		return;
+
+
+	GuiBorderProfile* selProfile = mSelectorProfile->getTopProfile();
+	S32 padding = selProfile->getPadding(NormalState);
+	S32 margin = selProfile->getMargin(NormalState);
+	S32 inner = (margin * 2) + 1;
+	S32 diameter = (padding * 2) + inner;
+
+	switch (mode)
+	{
+	case sVertical:
+		// Up -> Pos
+		if (selectorPos.y != bounds.point.y)
+			dglDrawLine(selectorPos.x, bounds.point.y, selectorPos.x, selectorPos.y - diameter, colorWhiteBlend);
+		// Down -> Pos
+		if (selectorPos.y != bounds.point.y + bounds.extent.y)
+			dglDrawLine(selectorPos.x, selectorPos.y + diameter, selectorPos.x, bounds.point.y + bounds.extent.y, colorWhiteBlend);
+		break;
+	case sHorizontal:
+		// Left -> Pos
+		if (selectorPos.x != bounds.point.x)
+			dglDrawLine(bounds.point.x, selectorPos.y, selectorPos.x - diameter, selectorPos.y, colorWhiteBlend);
+		// Right -> Pos
+		if (selectorPos.x != bounds.point.x + bounds.extent.x)
+			dglDrawLine(selectorPos.x + diameter, selectorPos.y, bounds.point.x + bounds.extent.x, selectorPos.y, colorWhiteBlend);
+		break;
+	case sCircle:
+		GuiControlState currentState = NormalState;
+		if (mMouseDown)
+		{
+			currentState = SelectedState;
+		}
+		else
+		{
+			GuiCanvas* canvas = getRoot();
+			if (canvas)
+			{
+				Point2I curPos = canvas->getCursorPos();
+				S32 dist = (curPos - selectorPos).len();
+				if (dist <= diameter)
+				{
+					currentState = HighlightState;
+				}
+			}
+		}
+		renderBorderedRing(selectorPos, diameter, inner, mSelectorProfile, currentState);
+		break;
+	}
+}
+
+void GuiColorPickerCtrl::onRender(Point2I offset, const RectI& updateRect)
+{
+	if(mDisplayMode != pDropperBackground)
+	{
+		RectI ctrlRect = applyMargins(offset, mBounds.extent, NormalState, mProfile);
+
+		renderUniversalRect(ctrlRect, mProfile, NormalState);
+
+		RectI fillRect = applyBorders(ctrlRect.point, ctrlRect.extent, NormalState, mProfile);
+		RectI contentRect = applyPadding(fillRect.point, fillRect.extent, NormalState, mProfile);
+
+		renderColorBox(contentRect);
+		updatePickColor(offset, contentRect);
+		renderText(offset, updateRect.extent, mText, mProfile);
+		renderSelector(contentRect);
+	}
+	else
+	{
+		updatePickColor(offset, updateRect);
+	}
+}
+
+void GuiColorPickerCtrl::updatePickColor(const Point2I& offset,  const RectI& contentRect)
+{
+	if (mPositionChanged && mDisplayMode != pPallet)
+	{
+		mPositionChanged = false;
+		Point2I extent = Canvas->getExtent();
+		U32 buf_x = offset.x + mSelectorPos.x;
+		U32 buf_y = extent.y - (offset.y + mSelectorPos.y + 1);
+
+		S32 xDelta = (contentRect.point.x - offset.x);
+		S32 yDelta = (contentRect.point.y - offset.y);
+		F32 numeratorX = mSelectorPos.x - xDelta;
+		F32 denominatorX = contentRect.extent.x - 1;
+		F32 numeratorY = mSelectorPos.y - yDelta;
+		F32 denominatorY = contentRect.extent.y - 1;
+		F32 varX = numeratorX / getMax(denominatorX, 1.0f);
+		F32 varY = numeratorY / getMax(denominatorY, 1.0f);
+
+		if (mDisplayMode == pHorizAlphaRange || mDisplayMode == pVertAlphaRange)
+		{
+			mPickColor = mBaseColor;
+			mPickColor.alpha = mDisplayMode == pHorizAlphaRange ? varX : varY;
+		}
+		else if ((mDisplayMode == pHorizColorRange && (varX == 1.0f || varX == 0.0f)) ||
+			(mDisplayMode == pVertColorRange && (varY == 1.0f || varY == 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))
+		{
+			mPickColor = mColorRange[1];
+		}
+		else if ((mDisplayMode == pBlendColorRange && varY == 1.0f) ||
+			(mDisplayMode == pHorizColorBrightnessRange && varY == 1.0f) ||
+			(mDisplayMode == pVertColorBrightnessRange && varX == 1.0f))
+		{
+			mPickColor = colorBlack;
+		}
+		else if ((mDisplayMode == pHorizColorBrightnessRange && (varX == 0.0f || varX == 1.0f)) ||
+			(mDisplayMode == pVertColorBrightnessRange && (varY == 0.0f || varY == 1.0f)))
+		{
+			mPickColor.red = mDisplayMode == pHorizColorBrightnessRange ? (mColorRange[1].red / 255) * (1.0f - varY) : (mColorRange[1].red / 255) * (1.0f - varX);
+			mPickColor.green = mDisplayMode == pHorizColorBrightnessRange ? (mColorRange[1].green / 255) * (1.0f - varY) : (mColorRange[1].green / 255) * (1.0f - varX);
+			mPickColor.blue = mDisplayMode == pHorizColorBrightnessRange ? (mColorRange[1].blue / 255) * (1.0f - varY) : (mColorRange[1].blue / 255) * (1.0f - varX);
+		}
+		else if (mDisplayMode == pBlendColorRange && varY == 0.0f)
+		{
+			if(varX == 0.0f)
+			{
+				mPickColor = colorWhite;
+			}
+			else if(varX < 1.0f)
+			{
+				mPickColor.red = 1.0f - ((1.0f - mBaseColor.red) * varX);
+				mPickColor.green = 1.0f - ((1.0f - mBaseColor.green) * varX);
+				mPickColor.blue = 1.0f - ((1.0f - mBaseColor.blue) * varX);
+			}
+		}
+		else
+		{
+			GLubyte rBuffer[4] = { 255, 255, 255, 255 };
+			glReadBuffer(GL_BACK);
+			glReadPixels(buf_x, buf_y, 1, 1, GL_RGB, GL_UNSIGNED_BYTE, rBuffer);
+			mPickColor = ColorI(rBuffer[0], rBuffer[1], rBuffer[2], 255);
+		}
+
+		if (mActionOnMove)
+			onAction();
+
+		//char buffer[1024];
+		//dSprintf(buffer, 1024, "%f, %f, %f, %f, local:(%d %d) global:(%d %d)", mPickColor.red, mPickColor.green, mPickColor.blue, mPickColor.alpha, mSelectorPos.x, mSelectorPos.y, buf_x, buf_y);
+
+		//setText(buffer);
+	}
+}
+
+void GuiColorPickerCtrl::resize(const Point2I& newPosition, const Point2I& newExtent)
+{
+	Point2F pos = Point2F((F32)mSelectorPos.x / (F32)mBounds.extent.x, (F32)mSelectorPos.y / (F32)mBounds.extent.y);
+
+	Parent::resize(newPosition, newExtent);
+
+	mSelectorPos.x = mRound(newExtent.x * pos.x);
+	mSelectorPos.y = mRound(newExtent.y * pos.y);
+}
+
+//--------------------------------------------------------------------------
+void GuiColorPickerCtrl::setSelectorPos(const Point2I& pos)
+{
+	Point2I zero = Point2I::Zero;
+	RectI rect = getInnerRect(zero);
+
+	mSelectorPos = pos;
+	if (pos.x < rect.point.x)
+	{
+		mSelectorPos.x = rect.point.x;
+	}
+	else if (pos.x >= (rect.point.x + rect.extent.x))
+	{
+		mSelectorPos.x = rect.point.x + rect.extent.x - 1;
+	}
+
+	if (pos.y < rect.point.y)
+	{
+		mSelectorPos.y = rect.point.y;
+	}
+	else if (pos.y >= (rect.point.y + rect.extent.y))
+	{
+		mSelectorPos.y = rect.point.y + rect.extent.y - 1;
+	}
+
+	if (mDisplayMode == pHorizColorRange || mDisplayMode == pHorizAlphaRange)
+	{
+		mSelectorPos.y = rect.centre().y;
+	}
+	else if (mDisplayMode == pVertColorRange || mDisplayMode == pVertAlphaRange)
+	{
+		mSelectorPos.x = rect.centre().x;
+	}
+
+	mPositionChanged = true;
+	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)
+{
+	// Calculate hue
+	F32 hue = colorHue(targetColor);
+
+	// Transform the hue value to [0-1].
+	F32 hueFraction = hue / 360;
+
+	// Calculate position in range box
+	Point2I position;
+	if (vertical)
+	{
+		position.x = (S32)(0.5f * (bounds.extent.x));
+		position.y = (S32)((1.0f - hueFraction) * (bounds.extent.y));
+	}
+	else
+	{
+		position.x = (S32)((1.0f - hueFraction) * (bounds.extent.x));
+		position.y = (S32)(0.5f * (bounds.extent.y));
+	}
+
+	return position;
+}
+
+Point2I GuiColorPickerCtrl::getBlendBoxColorPos(RectI& bounds, ColorF targetColor)
+{
+	// Calculate hue
+	F32 hue = colorHue(targetColor);
+
+
+	// Calculate the largest, smallest RGB components of the hue
+	F32 largest, smallest, baseLargest, baseSmallest;
+	if (hue >= 0 && hue < 60)
+	{
+		largest = targetColor.red;
+		smallest = targetColor.blue;
+		baseLargest = mBaseColor.red;
+		baseSmallest = mBaseColor.blue;
+	}
+	else if (hue >= 60 && hue < 120)
+	{
+		largest = targetColor.green;
+		smallest = targetColor.blue;
+		baseLargest = mBaseColor.green;
+		baseSmallest = mBaseColor.blue;
+	}
+	else if (hue >= 120 && hue < 180)
+	{
+		largest = targetColor.green;
+		smallest = targetColor.red;
+		baseLargest = mBaseColor.green;
+		baseSmallest = mBaseColor.red;
+	}
+	else if (hue >= 180 && hue < 240)
+	{
+		largest = targetColor.blue;
+		smallest = targetColor.red;
+		baseLargest = mBaseColor.blue;
+		baseSmallest = mBaseColor.red;
+	}
+	else if (hue >= 240 && hue < 300)
+	{
+		largest = targetColor.blue;
+		smallest = targetColor.green;
+		baseLargest = mBaseColor.blue;
+		baseSmallest = mBaseColor.green;
+	}
+	else if (hue >= 300 && hue < 360)
+	{
+		largest = targetColor.red;
+		smallest = targetColor.green;
+		baseLargest = mBaseColor.red;
+		baseSmallest = mBaseColor.green;
+	}
+	else
+	{
+		// Color hue must be between 0 and 360.
+		Con::errorf("getBlendBoxColorPos - Color hue is outside allowable range.");
+		return Point2I(0, 0);
+	}
+
+	// Calculate position in range box
+	Point2I position;
+
+	F32 h = 1.0f - (smallest / largest);
+	F32 v = 1.0f - largest;
+
+	position.x = (S32)(h * (bounds.extent.x - 1));
+	position.y = (S32)(v * (bounds.extent.y - 1));
+
+	return position;
+}
+
+Point2I GuiColorPickerCtrl::getSelectorPositionForColor(RectI& bounds, ColorF targetColor)
+{
+	Point2I position(0, 0);
+
+	switch (mDisplayMode)
+	{
+	case pHorizColorRange:
+		position = getRangeBoxColorPos(bounds, false, targetColor);
+		break;
+	case pVertColorRange:
+		position = getRangeBoxColorPos(bounds, true, targetColor);
+		break;
+
+	case pBlendColorRange:
+		position = getBlendBoxColorPos(bounds, targetColor);
+		break;
+
+	default:
+		Con::errorf("Display mode does not support the function: getSelectorPositionForColor().");
+		break;
+	}
+
+	return position;
+}
+
+
+//--------------------------------------------------------------------------
+void GuiColorPickerCtrl::onTouchDown(const GuiEvent& event)
+{
+	if (!mActive)
+		return;
+
+	if (mDisplayMode == pDropperBackground)
+		return;
+
+	mouseLock(this);
+
+	if (mProfile->mCanKeyFocus)
+		setFirstResponder();
+
+	// Update the picker cross position
+	if (mDisplayMode != pPallet)
+		setSelectorPos(globalToLocalCoord(event.mousePoint));
+
+	mMouseDown = true;
+
+	Con::executef(this, 1, "onTouchDown");
+}
+
+//--------------------------------------------------------------------------
+void GuiColorPickerCtrl::onTouchDragged(const GuiEvent& event)
+{
+	if ((mActive && mMouseDown) || (mActive && (mDisplayMode == pDropperBackground)))
+	{
+		// Update the picker cross position
+		if (mDisplayMode != pPallet)
+			setSelectorPos(globalToLocalCoord(event.mousePoint));
+	}
+
+	if (!mActionOnMove && mAltConsoleCommand[0])
+		Con::evaluate(mAltConsoleCommand, false);
+
+	Con::executef(this, 1, "onTouchDragged");
+}
+
+//--------------------------------------------------------------------------
+void GuiColorPickerCtrl::onTouchMove(const GuiEvent& event)
+{
+	// Only for dropper mode
+	if (mActive && (mDisplayMode == pDropperBackground))
+		setSelectorPos(globalToLocalCoord(event.mousePoint));
+
+	Con::executef(this, 1, "onTouchMove");
+}
+
+//--------------------------------------------------------------------------
+void GuiColorPickerCtrl::onTouchEnter(const GuiEvent& event)
+{
+	mMouseOver = true;
+
+	Con::executef(this, 1, "onTouchEnter");
+}
+
+//--------------------------------------------------------------------------
+void GuiColorPickerCtrl::onTouchLeave(const GuiEvent&)
+{
+	// Reset state
+	mMouseOver = false;
+
+	Con::executef(this, 1, "onTouchLeave");
+}
+
+//--------------------------------------------------------------------------
+void GuiColorPickerCtrl::onTouchUp(const GuiEvent&)
+{
+	//if we released the mouse within this control, perform the action
+	if (mActive && mMouseDown && (mDisplayMode != pDropperBackground))
+	{
+		onAction();
+		mMouseDown = false;
+	}
+	else if (mActive && (mDisplayMode == pDropperBackground))
+	{
+		// In a dropper, the alt command executes the mouse up action (to signal stopping)
+		if (mAltConsoleCommand[0])
+			Con::evaluate(mAltConsoleCommand, false);
+	}
+
+	mouseUnlock();
+
+	Con::executef(this, 1, "onTouchUp");
+}
+
+//--------------------------------------------------------------------------
+const char* GuiColorPickerCtrl::getScriptValue()
+{
+	static char temp[256];
+	ColorF color = getValue();
+	dSprintf(temp, 256, "%g %g %g %g", color.red, color.green, color.blue, color.alpha);
+	return temp;
+}
+
+//--------------------------------------------------------------------------    
+void GuiColorPickerCtrl::setScriptValue(const char* value)
+{
+	ColorF newValue;
+	dSscanf(value, "%g %g %g %g", &newValue.red, &newValue.green, &newValue.blue, &newValue.alpha);
+	setValue(newValue);
+}
+

+ 150 - 144
engine/source/gui/guiColorPicker.h → engine/source/gui/guiColorPickerCtrl.h

@@ -1,144 +1,150 @@
-//-----------------------------------------------------------------------------
-// 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 _GUICOLORPICKER_H_
-#define _GUICOLORPICKER_H_
-
-#ifndef _GUICONTROL_H_
-#include "gui/guiControl.h"
-#endif
-
-//----------------------------
-/// GuiColorPickerCtrl
-///
-/// This control draws a box containing a color specified by mPickColor, 
-/// in a way according to one of the PickMode enum's, stored as mDisplayMode.
-/// 
-/// The color the box represents is stored as mBasecolor (for pPallete, pBlendColorRange), 
-/// whilst the color chosen by the box is stored as mPickColor.
-///
-/// Whenever the control is clicked, it will do one of many things :
-///
-/// -# If its in pPallete mode, execute the regular "command"
-/// -# If its in pBlendColorRange mode, update the selector position. The position will be re-read upon the next render. In addition, a cross will be drawn where the color has been selected from. As with 1, "command" will be executed.
-/// -# If its in pHorizColorRange or pVertColorRange mode, it will function in a similar manner to 2, but the selector will resemble a horizontal or vertical bar.
-/// -# If its in pHorizAlphaRange or pVertAlphaRange mode, it will also function the same way as 3
-/// -# If its in pDropperBackground mode, nothing will happen
-///
-/// colors are drawn in different ways according to mDisplayMode:
-///
-/// -# With pPallete, a box with a blank color, mBaseColor is drawn.
-/// -# With pHorizColorRange, a horizontal box with colors blending in the range, mColorRange.
-/// -# With pVertColorRange, a vertical box with colors blending in the range, mColorRange.
-/// -# With pBlendColorRange, a box, the bottom colors being black, but the top left being white, and the top right being mBaseColor.
-/// -# With pHorizAlphaRange, a horizontal box with black blending with an alpha from 0 to 255
-/// -# With pVertAlphaRange, a vertical box with black blending with an apha from 0 to 255
-/// -# With pDropperBackground, nothing is drawn
-class GuiColorPickerCtrl : public GuiControl
-{
-   typedef GuiControl Parent;
-   
-  public:
-   enum PickMode
-   {
-     pPallet = 0,		///< We just have a solid color; We just act like a pallet 
-     pHorizColorRange,		///< We have a range of base colors going horizontally
-     pVertColorRange,		///< We have a range of base colors going vertically
-     pHorizColorBrightnessRange, ///< HorizColorRange with brightness
-     pVertColorBrightnessRange, ///< VertColorRange with brightness
-     pBlendColorRange,		///< We have a box which shows a range in brightness of the color
-     pHorizAlphaRange,		///< We have a box which shows a range in alpha going horizontally
-     pVertAlphaRange,		///< We have a box which shows a range in alpha going vertically
-     pDropperBackground		///< The control does not draw anything; Only does something when you click, or move the mouse (when active)
-   };
-   
-   enum SelectorMode
-   {
-     sHorizontal = 0,		///< Horizontal selector with small gap
-     sVertical,			///< Vertical selector with small gap
-   };
-  
-  protected:
-   
-   /// @name Core Rendering functions
-   /// @{
-   void renderColorBox(RectI &bounds);			///< Function that draws the actual color box
-   void drawSelector(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);
-   /// @}
-
-   /// @name Core Variables
-   /// @{
-   ColorF mPickColor;		///< Color that has been picked from control
-   ColorF mBaseColor;		///< color we display (in case of pallet and blend mode)
-   PickMode mDisplayMode;	///< Current color display mode of the selector
-   
-   Point2I mSelectorPos;	///< Current position of the selector
-   bool mPositionChanged;	///< Current position has changed since last render?
-   bool mMouseOver;		///< Mouse is over?
-   bool mMouseDown;		///< Mouse button down?
-   bool mActionOnMove;		///< Perform onAction() when position has changed?
-   bool mShowSelector; ///< Display the selector lines on the control?
-   
-   S32   mSelectorGap;		///< The half-way "gap" between the selector pos and where the selector is allowed to draw. 
-
-   static ColorI mColorRange[9]; ///< Color range for pHorizColorRange and pVertColorRange
-   /// @}
-
-  public:   
-   DECLARE_CONOBJECT(GuiColorPickerCtrl);
-   GuiColorPickerCtrl();
-
-   static void initPersistFields();
-   void onRender(Point2I offset, const RectI &updateRect);
-   
-   /// @name Color Value Functions
-   /// @{
-   /// NOTE: setValue only sets baseColor, since setting pickColor wouldn't be useful
-   void setValue(ColorF &value) {mBaseColor = value;}
-   /// NOTE: getValue() returns baseColor if pallet (since pallet controls can't "pick" colors themselves)
-   ColorF getValue() {return mDisplayMode == pPallet ? mBaseColor : mPickColor;}
-   const char *getScriptValue();
-   void setScriptValue(const char *value);
-   void updateColor() {mPositionChanged = true;}
-   /// @}
-   
-   /// @name Selector Functions
-   /// @{
-   void setSelectorPos(const Point2I &pos); ///< Set new pos (in local coords)
-   Point2I getSelectorPos() {return mSelectorPos;}
-   Point2I getSelectorPositionForColor(RectI &bounds, ColorF color);
-   /// @}
-   
-   /// @name Input Events
-   /// @{
-   void onTouchDown(const GuiEvent &);
-   void onTouchUp(const GuiEvent &);
-   void onTouchMove(const GuiEvent &event);
-   void onTouchDragged(const GuiEvent &event);
-
-   void onTouchEnter(const GuiEvent &);
-   void onTouchLeave(const GuiEvent &);
-   /// @}
-};
-
-#endif
+//-----------------------------------------------------------------------------
+// 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 _GUICOLORPICKER_H_
+#define _GUICOLORPICKER_H_
+
+#ifndef _GUICONTROL_H_
+#include "gui/guiControl.h"
+#endif
+
+//----------------------------
+/// GuiColorPickerCtrl
+///
+/// This control draws a box containing a color specified by mPickColor, 
+/// in a way according to one of the PickMode enum's, stored as mDisplayMode.
+/// 
+/// The color the box represents is stored as mBasecolor (for pPallete, pBlendColorRange), 
+/// whilst the color chosen by the box is stored as mPickColor.
+///
+/// Whenever the control is clicked, it will do one of many things :
+///
+/// -# If its in pPallete mode, execute the regular "command"
+/// -# If its in pBlendColorRange mode, update the selector position. The position will be re-read upon the next render. In addition, a cross will be drawn where the color has been selected from. As with 1, "command" will be executed.
+/// -# If its in pHorizColorRange or pVertColorRange mode, it will function in a similar manner to 2, but the selector will resemble a horizontal or vertical bar.
+/// -# If its in pHorizAlphaRange or pVertAlphaRange mode, it will also function the same way as 3
+/// -# If its in pDropperBackground mode, nothing will happen
+///
+/// colors are drawn in different ways according to mDisplayMode:
+///
+/// -# With pPallete, a box with a blank color, mBaseColor is drawn.
+/// -# With pHorizColorRange, a horizontal box with colors blending in the range, mColorRange.
+/// -# With pVertColorRange, a vertical box with colors blending in the range, mColorRange.
+/// -# With pBlendColorRange, a box, the bottom colors being black, but the top left being white, and the top right being mBaseColor.
+/// -# With pHorizAlphaRange, a horizontal box with black blending with an alpha from 0 to 255
+/// -# With pVertAlphaRange, a vertical box with black blending with an apha from 0 to 255
+/// -# With pDropperBackground, nothing is drawn
+class GuiColorPickerCtrl : public GuiControl
+{
+   typedef GuiControl Parent;
+   
+  public:
+   enum PickMode
+   {
+     pPallet = 0,		///< We just have a solid color; We just act like a pallet 
+     pHorizColorRange,		///< We have a range of base colors going horizontally
+     pVertColorRange,		///< We have a range of base colors going vertically
+     pHorizColorBrightnessRange, ///< HorizColorRange with brightness
+     pVertColorBrightnessRange, ///< VertColorRange with brightness
+     pBlendColorRange,		///< We have a box which shows a range in brightness of the color
+     pHorizAlphaRange,		///< We have a box which shows a range in alpha going horizontally
+     pVertAlphaRange,		///< We have a box which shows a range in alpha going vertically
+     pDropperBackground		///< The control does not draw anything; Only does something when you click, or move the mouse (when active)
+   };
+   
+   enum SelectorMode
+   {
+     sHorizontal = 0,		///< Horizontal selector with small gap
+     sVertical,			///< Vertical selector with small gap
+	 sCircle			///< Doughnut shaped circle using the selector profile
+   };
+  
+  protected:
+   
+   /// @name Core Rendering functions
+   /// @{
+   void renderColorBox(const RectI& bounds);			///< Function that draws the actual color box
+   void renderSelector(const RectI& pickerBounds);
+   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);
+   /// @}
+
+   /// @name Core Variables
+   /// @{
+   ColorF mPickColor;		///< Color that has been picked from control
+   ColorF mBaseColor;		///< color we display (in case of pallet and blend mode)
+   PickMode mDisplayMode;	///< Current color display mode of the selector
+   
+   Point2I mSelectorPos;	///< Current position of the selector
+   bool mPositionChanged;	///< Current position has changed since last render?
+   bool mMouseOver;		///< Mouse is over?
+   bool mMouseDown;		///< Mouse button down?
+   bool mActionOnMove;		///< Perform onAction() when position has changed?
+   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
+   /// @}
+
+  public:   
+   DECLARE_CONOBJECT(GuiColorPickerCtrl);
+   GuiColorPickerCtrl();
+
+   static void initPersistFields();
+   bool onWake();
+   void onSleep();
+   void onRender(Point2I offset, const RectI &updateRect);
+   void updatePickColor(const Point2I& offset, const RectI& contentRect);
+   void resize(const Point2I& newPosition, const Point2I& newExtent);
+   
+   /// @name Color Value Functions
+   /// @{
+   /// NOTE: setValue only sets baseColor, since setting pickColor wouldn't be useful
+   void setValue(ColorF &value) {mBaseColor = value;}
+   /// NOTE: getValue() returns baseColor if pallet (since pallet controls can't "pick" colors themselves)
+   ColorF getValue() {return mDisplayMode == pPallet ? mBaseColor : mPickColor;}
+   const char *getScriptValue();
+   void setScriptValue(const char *value);
+   void updateColor() {mPositionChanged = true;}
+   /// @}
+   
+   /// @name Selector Functions
+   /// @{
+   void setSelectorPos(const Point2I &pos); ///< Set new pos (in local coords)
+   Point2I getSelectorPos() {return mSelectorPos;}
+   Point2I getSelectorPositionForColor(RectI &bounds, ColorF color);
+   /// @}
+   
+   /// @name Input Events
+   /// @{
+   void onTouchDown(const GuiEvent &);
+   void onTouchUp(const GuiEvent &);
+   void onTouchMove(const GuiEvent &event);
+   void onTouchDragged(const GuiEvent &event);
+
+   void onTouchEnter(const GuiEvent &);
+   void onTouchLeave(const GuiEvent &);
+   /// @}
+};
+
+#endif

+ 124 - 0
engine/source/gui/guiColorPickerCtrl_ScriptBinding.h

@@ -0,0 +1,124 @@
+//-----------------------------------------------------------------------------
+// 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(GuiColorPickerCtrl, GuiControl)
+
+/*! Gets the current position of the selector.
+	@return (int x/int y) The position of the selector as a space-separated x, y coordinate.
+*/
+ConsoleMethodWithDocs(GuiColorPickerCtrl, getSelectorPos, ConsoleString, 2, 2, ())
+{
+	char* temp = Con::getReturnBuffer(256);
+	Point2I pos;
+	pos = object->getSelectorPos();
+	dSprintf(temp, 256, "%d %d", pos.x, pos.y);
+	return temp;
+}
+
+/*! Gets the selector position for the specified color. The display mode must be Horiz Color Range, Vert Color Range, or Blend Color Range.
+	@param red The red value between 0 and 1.
+	@param green The green value between 0 and 1.
+	@param blue The blue value between 0 and 1.
+	@param alpha The alpha value between 0 and 1. Alpha values control transparency.
+	@return (int x/int y) The position of the selector as a space-separated x, y coordinate.
+*/
+ConsoleMethodWithDocs(GuiColorPickerCtrl, getSelectorPosForColor, ConsoleString, 3, 6, (red | r/g/b/[a], green, blue, [alpha]))
+{
+	// The colors.
+	F32 red;
+	F32 green;
+	F32 blue;
+	F32 alpha = 1.0f;
+
+	// Grab the element count.
+	U32 elementCount = Utility::mGetStringElementCount(argv[2]);
+
+	// Space separated.
+	if (argc < 4)
+	{
+		// ("R G B [A]")
+		if ((elementCount == 3) || (elementCount == 4))
+		{
+			// Extract the color.
+			red = dAtof(Utility::mGetStringElement(argv[2], 0));
+			green = dAtof(Utility::mGetStringElement(argv[2], 1));
+			blue = dAtof(Utility::mGetStringElement(argv[2], 2));
+
+			// Grab the alpha if it's there.
+			if (elementCount > 3)
+				alpha = dAtof(Utility::mGetStringElement(argv[2], 3));
+		}
+
+		// Invalid.
+		else
+		{
+			Con::warnf("GuiColorPickerCtrl::getSelectorPosForColor() - Invalid Number of parameters!");
+			return StringTable->EmptyString;
+		}
+	}
+
+	// (R, G, B)
+	else if (argc >= 5)
+	{
+		red = dAtof(argv[2]);
+		green = dAtof(argv[3]);
+		blue = dAtof(argv[4]);
+
+		// Grab the alpha if it's there.
+		if (argc > 5)
+			alpha = dAtof(argv[5]);
+	}
+
+	// Invalid.
+	else
+	{
+		Con::warnf("GuiColorPickerCtrl::getSelectorPosForColor() - Invalid Number of parameters!");
+		return StringTable->EmptyString;
+	}
+
+	char* temp = Con::getReturnBuffer(256);
+	Point2I pos;
+	pos = object->getSelectorPositionForColor(object->mBounds, ColorF(red, green, blue, alpha));
+	dSprintf(temp, 256, "%d %d", pos.x, pos.y);
+	return temp;
+}
+
+/*! Set the selector by position.
+	@param (x/y) The space-separated coordinate to set the selector at.
+	@return No return value.
+*/
+ConsoleMethodWithDocs(GuiColorPickerCtrl, setSelectorPos, ConsoleVoid, 3, 3, (x/y))
+{
+	Point2I newPos;
+	dSscanf(argv[2], "%d %d", &newPos.x, &newPos.y);
+	object->setSelectorPos(newPos);
+}
+
+/*! Forces an update of the pick color.
+	@return No return value.
+*/
+ConsoleMethodWithDocs(GuiColorPickerCtrl, updateColor, ConsoleVoid, 2, 2, ())
+{
+	object->updateColor();
+}
+
+ConsoleMethodGroupEndWithDocs(GuiColorPickerCtrl)

+ 38 - 5
engine/source/gui/guiDefaultControlRender.cc

@@ -165,11 +165,8 @@ void renderBorderedRect(RectI &bounds, GuiControlProfile *profile, GuiControlSta
 	}
 	}
 }
 }
 
 
-void renderBorderedCircle(Point2I &center, S32 radius, GuiControlProfile *profile, GuiControlState state)
+void renderBorderedCircle(Point2I& center, S32 radius, GuiControlProfile* profile, GuiControlState state = NormalState)
 {
 {
-	//Get the border profiles
-	GuiBorderProfile *borderProfile = profile->mBorderDefault;
-
 	//Get the colors
 	//Get the colors
 	ColorI fillColor = profile->getFillColor(state);
 	ColorI fillColor = profile->getFillColor(state);
 	ColorI borderColor = (profile->mBorderDefault) ? profile->mBorderDefault->getBorderColor(state) : ColorI();
 	ColorI borderColor = (profile->mBorderDefault) ? profile->mBorderDefault->getBorderColor(state) : ColorI();
@@ -180,7 +177,7 @@ void renderBorderedCircle(Point2I &center, S32 radius, GuiControlProfile *profil
 	dglDrawCircleFill(center, (F32)fillRadius, fillColor);
 	dglDrawCircleFill(center, (F32)fillRadius, fillColor);
 
 
 	//Draw the border
 	//Draw the border
-	dglDrawCircle(center, (F32)radius, borderColor, (F32)borderSize);
+	renderRing(center, (F32)radius, borderColor, (F32)borderSize);
 
 
 	if (state > 3 && radius >= 8)
 	if (state > 3 && radius >= 8)
 	{
 	{
@@ -188,6 +185,42 @@ void renderBorderedCircle(Point2I &center, S32 radius, GuiControlProfile *profil
 	}
 	}
 }
 }
 
 
+void renderBorderedRing(Point2I& center, S32 outerRadius, S32 innerRadius, GuiControlProfile* profile, GuiControlState state = NormalState)
+{
+	if (innerRadius <= 0)
+	{
+		renderBorderedCircle(center, outerRadius, profile, state);
+		return;
+	}
+	
+	//Get the colors
+	ColorI fillColor = profile->getFillColor(state);
+	ColorI borderColor = (profile->mBorderDefault) ? profile->mBorderDefault->getBorderColor(state) : ColorI();
+	S32 borderSize = (profile->mBorderDefault) ? profile->mBorderDefault->getBorder(state) : 0;
+
+	//Draw the fill
+	S32 fillRadius = (profile->mBorderDefault && profile->mBorderDefault->mUnderfill) ? outerRadius : outerRadius - borderSize;
+	renderRing(center, (F32)fillRadius, fillColor, (F32)(outerRadius - innerRadius));
+
+	//Draw the border
+	renderRing(center, (F32)outerRadius, borderColor, (F32)borderSize);
+}
+
+void renderRing(const Point2I& center, const F32 radius, const ColorI& color, F32 borderSize)
+{
+	for (S32 i = 0; i < borderSize; i++)
+	{
+		if(i < (borderSize - 1))
+		{
+			dglDrawCircle(center, radius - i, color, 2);
+		}
+		else
+		{
+			dglDrawCircle(center, radius - i, color, 1);
+		}
+	}
+}
+
 // Based on the 'Skinnable GUI Controls in TGE' resource by Justin DuJardin
 // Based on the 'Skinnable GUI Controls in TGE' resource by Justin DuJardin
 void renderSizableBorderedImageAsset(RectI &bounds, U8 frame, ImageAsset *imageAsset, S32 frameCount)
 void renderSizableBorderedImageAsset(RectI &bounds, U8 frame, ImageAsset *imageAsset, S32 frameCount)
 {
 {

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

@@ -33,6 +33,8 @@ void renderUniversalRect(RectI &bounds, GuiControlProfile *profile, GuiControlSt
 void renderBorderedRect(RectI &bounds, GuiControlProfile *profile, GuiControlState state);
 void renderBorderedRect(RectI &bounds, GuiControlProfile *profile, GuiControlState state);
 void renderBorderedRect(RectI &bounds, GuiControlProfile *profile, GuiControlState state, const ColorI &fillColor);
 void renderBorderedRect(RectI &bounds, GuiControlProfile *profile, GuiControlState state, const ColorI &fillColor);
 void renderBorderedCircle(Point2I &center, S32 radius, GuiControlProfile *profile, GuiControlState state);
 void renderBorderedCircle(Point2I &center, S32 radius, GuiControlProfile *profile, GuiControlState state);
+void renderBorderedRing(Point2I& center, S32 outerRadius, S32 innerRadius, GuiControlProfile* profile, GuiControlState state);
+void renderRing(const Point2I& center, const F32 radius, const ColorI& color, F32 borderSize);
 void renderSizableBorderedImageAsset(RectI &bounds, U8 frame, ImageAsset *mImageAsset, S32 frameCount);
 void renderSizableBorderedImageAsset(RectI &bounds, U8 frame, ImageAsset *mImageAsset, S32 frameCount);
 void renderSizableBorderedBitmap(RectI &bounds, U8 frame, TextureHandle &texture, RectI *bitmapBounds, S32 frameCount);
 void renderSizableBorderedBitmap(RectI &bounds, U8 frame, TextureHandle &texture, RectI *bitmapBounds, S32 frameCount);
 void renderSizableBorderedTexture(RectI &bounds, TextureHandle &texture, RectI &TopLeft, RectI &Top, RectI &TopRight, RectI &Left, RectI &Fill, RectI &Right, RectI &BottomLeft, RectI &Bottom, RectI &BottomRight);
 void renderSizableBorderedTexture(RectI &bounds, TextureHandle &texture, RectI &TopLeft, RectI &Top, RectI &TopRight, RectI &Left, RectI &Fill, RectI &Right, RectI &BottomLeft, RectI &Bottom, RectI &BottomRight);