浏览代码

Color Picker

Lopuska 10 年之前
父节点
当前提交
03109c9d6d

+ 83 - 0
Engine/source/console/consoleFunctions.cpp

@@ -33,6 +33,9 @@
 #include "platform/platformInput.h"
 #include "platform/platformInput.h"
 #include "core/util/journal/journal.h"
 #include "core/util/journal/journal.h"
 #include "core/util/uuid.h"
 #include "core/util/uuid.h"
+#include "core/color.h"
+#include "math/mPoint3.h"
+#include "math/mathTypes.h"
 
 
 #ifdef TORQUE_DEMO_PURCHASE
 #ifdef TORQUE_DEMO_PURCHASE
 #include "gui/core/guiCanvas.h"
 #include "gui/core/guiCanvas.h"
@@ -815,6 +818,86 @@ DefineConsoleFunction( strrchrpos, S32, ( const char* str, const char* chr, S32
    return index;
    return index;
 }
 }
 
 
+//----------------------------------------------------------------
+
+DefineConsoleFunction(ColorFloatToInt, ColorI, (ColorF color), ,
+	"Convert from a float color to an integer color (0.0 - 1.0 to 0 to 255).\n"
+	"@param color Float color value to be converted in the form \"R G B A\", where R is red, G is green, B is blue, and A is alpha.\n"
+	"@return Converted color value (0 - 255)\n\n"
+	"@tsexample\n"
+	"ColorFloatToInt( \"0 0 1 0.5\" ) // Returns \"0 0 255 128\".\n"
+	"@endtsexample\n"
+	"@ingroup Strings")
+{
+	return (ColorI)color;
+}
+
+DefineConsoleFunction(ColorIntToFloat, ColorF, (ColorI color), ,
+	"Convert from a integer color to an float color (0 to 255 to 0.0 - 1.0).\n"
+	"@param color Integer color value to be converted in the form \"R G B A\", where R is red, G is green, B is blue, and A is alpha.\n"
+	"@return Converted color value (0.0 - 1.0)\n\n"
+	"@tsexample\n"
+	"ColorIntToFloat( \"0 0 255 128\" ) // Returns \"0 0 1 0.5\".\n"
+	"@endtsexample\n"
+	"@ingroup Strings")
+{
+	return (ColorF)color;
+}
+
+DefineConsoleFunction(ColorRGBToHEX, const char*, (ColorI color), ,
+	"Convert from a integer RGB (red, green, blue) color to hex color value (0 to 255 to 00 - FF).\n"
+	"@param color Integer color value to be converted in the form \"R G B A\", where R is red, G is green, B is blue, and A is alpha. It excepts an alpha, but keep in mind this will not be converted.\n"
+	"@return Hex color value (#000000 - #FFFFFF), alpha isn't handled/converted so it is only the RGB value\n\n"
+	"@tsexample\n"
+	"ColorRBGToHEX( \"0 0 255 128\" ) // Returns \"#0000FF\".\n"
+	"@endtsexample\n"
+	"@ingroup Strings")
+{
+	return Con::getReturnBuffer(color.getHex());
+}
+
+DefineConsoleFunction(ColorRGBToHSB, const char*, (ColorI color), ,
+	"Convert from a integer RGB (red, green, blue) color to HSB (hue, saturation, brightness). HSB is also know as HSL or HSV as well, with the last letter standing for lightness or value.\n"
+	"@param color Integer color value to be converted in the form \"R G B A\", where R is red, G is green, B is blue, and A is alpha. It excepts an alpha, but keep in mind this will not be converted.\n"
+	"@return HSB color value, alpha isn't handled/converted so it is only the RGB value\n\n"
+	"@tsexample\n"
+	"ColorRBGToHSB( \"0 0 255 128\" ) // Returns \"240 100 100\".\n"
+	"@endtsexample\n"
+	"@ingroup Strings")
+{
+	ColorI::Hsb hsb(color.getHSB());
+	String s(String::ToString(hsb.hue) + " " + String::ToString(hsb.sat) + " " + String::ToString(hsb.brightness));
+	return Con::getReturnBuffer(s);
+}
+
+DefineConsoleFunction(ColorHEXToRGB, ColorI, (const char* hex), ,
+	"Convert from a hex color value to an integer RGB (red, green, blue) color (00 - FF to 0 to 255).\n"
+	"@param hex Hex color value (#000000 - #FFFFFF) to be converted to an RGB (red, green, blue) value.\n"
+	"@return Integer color value to be converted in the form \"R G B A\", where R is red, G is green, B is blue, and A is alpha. Alpha isn't handled/converted so only pay attention to the RGB value\n\n"
+	"@tsexample\n"
+	"ColorHEXToRGB( \"#0000FF\" ) // Returns \"0 0 255 0\".\n"
+	"@endtsexample\n"
+	"@ingroup Strings")
+{
+	ColorI color;
+	color.set(hex);
+	return color;
+}
+
+DefineConsoleFunction(ColorHSBToRGB, ColorI, (Point3I hsb), ,
+	"Convert from a HSB (hue, saturation, brightness) to an integer RGB (red, green, blue) color. HSB is also know as HSL or HSV as well, with the last letter standing for lightness or value.\n"
+	"@param hsb HSB (hue, saturation, brightness) value to be converted.\n"
+	"@return Integer color value to be converted in the form \"R G B A\", where R is red, G is green, B is blue, and A is alpha. Alpha isn't handled/converted so only pay attention to the RGB value\n\n"
+	"@tsexample\n"
+	"ColorHSBToRGB( \"240 100 100\" ) // Returns \"0 0 255 0\".\n"
+	"@endtsexample\n"
+	"@ingroup Strings")
+{
+	ColorI color;
+	color.set(ColorI::Hsb(hsb.x, hsb.y, hsb.z));
+	return color;
+}
+
 //=============================================================================
 //=============================================================================
 //    Field Manipulators.
 //    Field Manipulators.
 //=============================================================================
 //=============================================================================

+ 284 - 0
Engine/source/core/color.h

@@ -30,6 +30,10 @@
 #include "math/mPoint4.h" 
 #include "math/mPoint4.h" 
 #endif
 #endif
 
 
+#ifndef _ENGINEAPI_H_
+#include "console/engineAPI.h"
+#endif
+
 class ColorI;
 class ColorI;
 
 
 
 
@@ -121,9 +125,20 @@ class ColorI
    U8 blue;
    U8 blue;
    U8 alpha;
    U8 alpha;
 
 
+   struct Hsb
+   {
+	   Hsb() :hue(0), sat(0), brightness(0){};
+	   Hsb(U32 h, U32 s, U32 b) :hue(h), sat(s), brightness(b){};
+
+	   U32 hue;			///Hue
+	   U32 sat;			///Saturation
+	   U32 brightness;	//Brightness/Value/Lightness
+   };
+
   public:
   public:
    ColorI() { }
    ColorI() { }
    ColorI(const ColorI& in_rCopy);
    ColorI(const ColorI& in_rCopy);
+   ColorI(const Hsb& color);
    ColorI(const U8 in_r,
    ColorI(const U8 in_r,
           const U8 in_g,
           const U8 in_g,
           const U8 in_b,
           const U8 in_b,
@@ -132,6 +147,12 @@ class ColorI
 
 
    ColorI( const char* pStockColorName );
    ColorI( const char* pStockColorName );
 
 
+   void set(const Hsb& color);
+
+   void HSLtoRGB_Subfunction(U32& c, const F64& temp1, const F64& temp2, const F64& temp3);
+
+   void set(const String& hex);
+
    void set(const U8 in_r,
    void set(const U8 in_r,
             const U8 in_g,
             const U8 in_g,
             const U8 in_b,
             const U8 in_b,
@@ -176,6 +197,11 @@ class ColorI
    U16 get565()  const;
    U16 get565()  const;
    U16 get4444() const;
    U16 get4444() const;
 
 
+   Hsb getHSB() const;
+
+   String getHex() const;
+   S32 convertFromHex(const String& hex) const;
+
    operator ColorF() const;
    operator ColorF() const;
 
 
    operator const U8*() const { return &red; }
    operator const U8*() const { return &red; }
@@ -459,6 +485,174 @@ inline void ColorI::set(const ColorI& in_rCopy,
    alpha = in_a;
    alpha = in_a;
 }
 }
 
 
+inline void ColorI::set(const Hsb& color)
+{
+	U32 r = 0;
+	U32 g = 0;
+	U32 b = 0;
+
+	F64 L = ((F64)color.brightness) / 100.0;
+	F64 S = ((F64)color.sat) / 100.0;
+	F64 H = ((F64)color.hue) / 360.0;
+
+	if (color.sat == 0)
+	{
+		r = color.brightness;
+		g = color.brightness;
+		b = color.brightness;
+	}
+	else
+	{
+		F64 temp1 = 0;
+		if (L < 0.50)
+		{
+			temp1 = L*(1 + S);
+		}
+		else
+		{
+			temp1 = L + S - (L*S);
+		}
+
+		F64 temp2 = 2.0*L - temp1;
+
+		F64 temp3 = 0;
+		for (S32 i = 0; i < 3; i++)
+		{
+			switch (i)
+			{
+			case 0: // red
+			{
+				temp3 = H + 0.33333;
+				if (temp3 > 1.0)
+					temp3 -= 1.0;
+				HSLtoRGB_Subfunction(r, temp1, temp2, temp3);
+				break;
+			}
+			case 1: // green
+			{
+				temp3 = H;
+				HSLtoRGB_Subfunction(g, temp1, temp2, temp3);
+				break;
+			}
+			case 2: // blue
+			{
+				temp3 = H - 0.33333;
+				if (temp3 < 0)
+					temp3 += 1;
+				HSLtoRGB_Subfunction(b, temp1, temp2, temp3);
+				break;
+			}
+			default:
+			{
+
+			}
+			}
+		}
+	}
+	red = (U32)((((F64)r) / 100) * 255);
+	green = (U32)((((F64)g) / 100) * 255);
+	blue = (U32)((((F64)b) / 100) * 255);
+}
+
+// This is a subfunction of HSLtoRGB
+inline void ColorI::HSLtoRGB_Subfunction(U32& c, const F64& temp1, const F64& temp2, const F64& temp3)
+{
+	if ((temp3 * 6.0) < 1.0)
+		c = (U32)((temp2 + (temp1 - temp2)*6.0*temp3)*100.0);
+	else
+		if ((temp3 * 2.0) < 1.0)
+			c = (U32)(temp1*100.0);
+		else
+			if ((temp3 * 3.0) < 2.0)
+				c = (U32)((temp2 + (temp1 - temp2)*(0.66666 - temp3)*6.0)*100.0);
+			else
+				c = (U32)(temp2*100.0);
+	return;
+}
+
+inline void ColorI::set(const String& hex)
+{
+	String redString;
+	String greenString;
+	String blueString;
+
+	//if the prefix # was attached to hex
+	if (hex[0] == '#')
+	{
+		redString = hex.substr(1, 2);
+		greenString = hex.substr(3, 2);
+		blueString = hex.substr(5, 2);
+	}
+	else
+	{
+		// since there is no prefix attached to hex
+		redString = hex.substr(0, 2);
+		greenString = hex.substr(2, 2);
+		blueString = hex.substr(4, 2);
+	}
+
+	red = (U8)(convertFromHex(redString));
+	green = (U8)(convertFromHex(greenString));
+	blue = (U8)(convertFromHex(blueString));
+}
+
+inline S32 ColorI::convertFromHex(const String& hex) const
+{
+	S32 hexValue = 0;
+
+	S32 a = 0;
+	S32 b = hex.length() - 1;
+
+	for (; b >= 0; a++, b--)
+	{
+		if (hex[b] >= '0' && hex[b] <= '9')
+		{
+			hexValue += (hex[b] - '0') * (1 << (a * 4));
+		}
+		else
+		{
+			switch (hex[b])
+			{
+			case 'A':
+			case 'a':
+				hexValue += 10 * (1 << (a * 4));
+				break;
+
+			case 'B':
+			case 'b':
+				hexValue += 11 * (1 << (a * 4));
+				break;
+
+			case 'C':
+			case 'c':
+				hexValue += 12 * (1 << (a * 4));
+				break;
+
+			case 'D':
+			case 'd':
+				hexValue += 13 * (1 << (a * 4));
+				break;
+
+			case 'E':
+			case 'e':
+				hexValue += 14 * (1 << (a * 4));
+				break;
+
+			case 'F':
+			case 'f':
+				hexValue += 15 * (1 << (a * 4));
+				break;
+
+			default:
+				Con::errorf("Error, invalid character '%c' in hex number", hex[a]);
+				break;
+			}
+		}
+	}
+
+	return hexValue;
+}
+
 inline ColorI::ColorI(const ColorI& in_rCopy)
 inline ColorI::ColorI(const ColorI& in_rCopy)
 {
 {
    red   = in_rCopy.red;
    red   = in_rCopy.red;
@@ -467,6 +661,11 @@ inline ColorI::ColorI(const ColorI& in_rCopy)
    alpha = in_rCopy.alpha;
    alpha = in_rCopy.alpha;
 }
 }
 
 
+inline ColorI::ColorI(const Hsb& color)
+{
+	set(color);
+}
+
 inline ColorI::ColorI(const U8 in_r,
 inline ColorI::ColorI(const U8 in_r,
                const U8 in_g,
                const U8 in_g,
                const U8 in_b,
                const U8 in_b,
@@ -647,6 +846,91 @@ inline U16 ColorI::get4444() const
               U16(U16(blue  >> 4) <<  0));
               U16(U16(blue  >> 4) <<  0));
 }
 }
 
 
+inline ColorI::Hsb ColorI::getHSB() const
+{
+	F64 rPercent = ((F64)red) / 255;
+	F64 gPercent = ((F64)green) / 255;
+	F64 bPercent = ((F64)blue) / 255;
+
+	F64 maxColor = 0.0;
+	if ((rPercent >= gPercent) && (rPercent >= bPercent))
+		maxColor = rPercent;
+	if ((gPercent >= rPercent) && (gPercent >= bPercent))
+		maxColor = gPercent;
+	if ((bPercent >= rPercent) && (bPercent >= gPercent))
+		maxColor = bPercent;
+
+	F64 minColor = 0.0;
+	if ((rPercent <= gPercent) && (rPercent <= bPercent))
+		minColor = rPercent;
+	if ((gPercent <= rPercent) && (gPercent <= bPercent))
+		minColor = gPercent;
+	if ((bPercent <= rPercent) && (bPercent <= gPercent))
+		minColor = bPercent;
+
+	F64 H = 0.0;
+	F64 S = 0.0;
+	F64 B = 0.0;
+
+	B = (maxColor + minColor) / 2.0;
+
+	if (maxColor == minColor)
+	{
+		H = 0.0;
+		S = 0.0;
+	}
+	else
+	{
+		if (B < 0.50)
+		{
+			S = (maxColor - minColor) / (maxColor + minColor);
+		}
+		else
+		{
+			S = (maxColor - minColor) / (2.0 - maxColor - minColor);
+		}
+		if (maxColor == rPercent)
+		{
+			H = (gPercent - bPercent) / (maxColor - minColor);
+		}
+		if (maxColor == gPercent)
+		{
+			H = 2.0 + (bPercent - rPercent) / (maxColor - minColor);
+		}
+		if (maxColor == bPercent)
+		{
+			H = 4.0 + (rPercent - gPercent) / (maxColor - minColor);
+		}
+	}
+
+	ColorI::Hsb val;
+	val.sat = (U32)(S * 100);
+	val.brightness = (U32)(B * 100);
+	H = H*60.0;
+	if (H < 0.0)
+		H += 360.0;
+	val.hue = (U32)H;
+
+	return val;
+}
+
+inline String ColorI::getHex() const
+{
+	char r[255];
+	dSprintf(r, sizeof(r), "%.2X", red);
+	String result(r);
+
+	char g[255];
+	dSprintf(g, sizeof(g), "%.2X", green);
+	result += g;
+
+	char b[255];
+	dSprintf(b, sizeof(b), "%.2X", blue);
+	result += b;
+
+	return result;
+}
+
 //-------------------------------------- INLINE CONVERSION OPERATORS
 //-------------------------------------- INLINE CONVERSION OPERATORS
 inline ColorF::operator ColorI() const
 inline ColorF::operator ColorI() const
 {
 {

+ 184 - 45
Engine/source/gui/controls/guiColorPicker.cpp

@@ -71,6 +71,18 @@ GuiColorPickerCtrl::GuiColorPickerCtrl()
    mSelectorGap = 1;
    mSelectorGap = 1;
    mActionOnMove = false;
    mActionOnMove = false;
 	mShowReticle = true;
 	mShowReticle = true;
+	mSelectColor = false;
+	mSetColor = mSetColor.BLACK;
+	mBitmap = NULL;
+}
+
+GuiColorPickerCtrl::~GuiColorPickerCtrl()
+{
+	if (mBitmap)
+	{
+		delete mBitmap;
+		mBitmap = NULL;
+	}
 }
 }
 
 
 //--------------------------------------------------------------------------
 //--------------------------------------------------------------------------
@@ -331,60 +343,180 @@ void GuiColorPickerCtrl::renderColorBox(RectI &bounds)
 
 
 void GuiColorPickerCtrl::onRender(Point2I offset, const RectI& updateRect)
 void GuiColorPickerCtrl::onRender(Point2I offset, const RectI& updateRect)
 {
 {
-   if (mStateBlock.isNull())
-   {
-      GFXStateBlockDesc desc;
-      desc.setBlend(true, GFXBlendSrcAlpha, GFXBlendInvSrcAlpha);
-      desc.setZReadWrite(false);
-      desc.zWriteEnable = false;
-      desc.setCullMode(GFXCullNone);
-      mStateBlock = GFX->createStateBlock( desc );
-   }
+	if (mStateBlock.isNull())
+	{
+		GFXStateBlockDesc desc;
+		desc.setBlend(true, GFXBlendSrcAlpha, GFXBlendInvSrcAlpha);
+		desc.setZReadWrite(false);
+		desc.zWriteEnable = false;
+		desc.setCullMode(GFXCullNone);
+		mStateBlock = GFX->createStateBlock(desc);
+	}
 
 
-   RectI boundsRect(offset, getExtent()); 
-   renderColorBox(boundsRect);
+	RectI boundsRect(offset, getExtent());
+	renderColorBox(boundsRect);
 
 
-   if (mPositionChanged) 
-   {
-      mPositionChanged = false;
-      Point2I extent = getRoot()->getExtent();
-      // If we are anything but a pallete, change the pick color
-      if (mDisplayMode != pPallet)
-      {
-         Point2I resolution = getRoot()->getExtent();
+	if (mPositionChanged || mBitmap == NULL)
+	{
+		bool nullBitmap = false;
 
 
-         U32 buf_x = offset.x + mSelectorPos.x + 1;
-         U32 buf_y = resolution.y - ( extent.y - ( offset.y + mSelectorPos.y + 1 ) );
+		if (mPositionChanged == false && mBitmap == NULL)
+			nullBitmap = true;
 
 
-         GFXTexHandle bb( resolution.x, 
-                          resolution.y, 
-                          GFXFormatR8G8B8A8, &GFXDefaultRenderTargetProfile, avar("%s() - bb (line %d)", __FUNCTION__, __LINE__) );
-         
-         Point2I tmpPt( buf_x, buf_y );
+		mPositionChanged = false;
+		Point2I extent = getRoot()->getExtent();
+		// If we are anything but a pallete, change the pick color
+		if (mDisplayMode != pPallet)
+		{
+			Point2I resolution = getRoot()->getExtent();
 
 
-         GFXTarget *targ = GFX->getActiveRenderTarget();
-         targ->resolveTo( bb );
-         
-         GBitmap bmp( bb.getWidth(), bb.getHeight() );
+			U32 buf_x = offset.x + mSelectorPos.x + 1;
+			U32 buf_y = resolution.y - (extent.y - (offset.y + mSelectorPos.y + 1));
 
 
-         bb.copyToBmp( &bmp );
-         
-         //bmp.writePNGDebug( "foo.png" );
+			GFXTexHandle bb(resolution.x,
+				resolution.y,
+				GFXFormatR8G8B8A8, &GFXDefaultRenderTargetProfile, avar("%s() - bb (line %d)", __FUNCTION__, __LINE__));
 
 
-         ColorI tmp;
-         bmp.getColor( buf_x, buf_y, tmp );
+			Point2I tmpPt(buf_x, buf_y);
 
 
-         mPickColor = (ColorF)tmp;
+			GFXTarget *targ = GFX->getActiveRenderTarget();
+			targ->resolveTo(bb);
 
 
-         // Now do onAction() if we are allowed
-         if (mActionOnMove) 
-            onAction();
-      }
-      
-   }
-   
-   //render the children
-   renderChildControls( offset, updateRect);
+			if (mBitmap)
+			{
+				delete mBitmap;
+				mBitmap = NULL;
+			}
+
+			mBitmap = new GBitmap(bb.getWidth(), bb.getHeight());
+
+			bb.copyToBmp(mBitmap);
+
+			//bmp.writePNGDebug( "foo.png" );
+
+			if (!nullBitmap)
+			{
+				if (mSelectColor)
+				{
+					Point2I pos = findColor(mSetColor, offset, resolution, *mBitmap);
+					mSetColor = mSetColor.BLACK;
+					mSelectColor = false;
+
+					setSelectorPos(pos);
+				}
+				else
+				{
+					ColorI tmp;
+					mBitmap->getColor(buf_x, buf_y, tmp);
+
+					mPickColor = (ColorF)tmp;
+
+					// Now do onAction() if we are allowed
+					if (mActionOnMove)
+						onAction();
+				}
+			}
+		}
+
+	}
+
+	//render the children
+	renderChildControls(offset, updateRect);
+}
+
+void GuiColorPickerCtrl::setSelectorPos(const ColorF & color)
+{
+	if (mBitmap && !mPositionChanged)
+	{
+		Point2I resolution = getRoot() ? getRoot()->getExtent() : Point2I(1024, 768);
+		RectI rect(getGlobalBounds());
+		Point2I pos = findColor(color, rect.point, resolution, *mBitmap);
+		mSetColor = mSetColor.BLACK;
+		mSelectColor = false;
+
+		setSelectorPos(pos);
+	}
+	else
+	{
+		mSetColor = color;
+		mSelectColor = true;
+		mPositionChanged = true;
+	}
+}
+
+Point2I GuiColorPickerCtrl::findColor(const ColorF & color, const Point2I& offset, const Point2I& resolution, GBitmap& bmp)
+{
+	RectI rect;
+	Point2I ext = getExtent();
+	if (mDisplayMode != pDropperBackground)
+	{
+		ext.x -= 3;
+		ext.y -= 2;
+		rect = RectI(Point2I(1, 1), ext);
+	}
+	else
+	{
+		rect = RectI(Point2I(0, 0), ext);
+	}
+
+	Point2I closestPos(-1, -1);
+
+	/* Debugging
+	char filename[256];
+	dSprintf( filename, 256, "%s.%s", "colorPickerTest", "png" );
+
+	// Open up the file on disk.
+	FileStream fs;
+	if ( !fs.open( filename, Torque::FS::File::Write ) )
+	Con::errorf( "GuiObjectView::saveAsImage() - Failed to open output file '%s'!", filename );
+	else
+	{
+	// Write it and close.
+	bmp.writeBitmap( "png", fs );
+
+	fs.close();
+	}
+	*/
+
+	ColorI tmp;
+	U32 buf_x;
+	U32 buf_y;
+	ColorF curColor;
+	F32 val(10000.0f);
+	F32 closestVal(10000.0f);
+	bool closestSet = false;
+
+	for (S32 x = rect.point.x; x <= rect.extent.x; x++)
+	{
+		for (S32 y = rect.point.y; y <= rect.extent.y; y++)
+		{
+			buf_x = offset.x + x + 1;
+			buf_y = (resolution.y - (offset.y + y + 1));
+			if (GFX->getAdapterType() != OpenGL)
+				buf_y = resolution.y - buf_y;
+
+			//Get the color at that position
+			bmp.getColor(buf_x, buf_y, tmp);
+			curColor = (ColorF)tmp;
+
+			//Evaluate how close the color is to our desired color
+			val = mFabs(color.red - curColor.red) + mFabs(color.green - curColor.green) + mFabs(color.blue - curColor.blue);
+
+			if (!closestSet)
+			{
+				closestVal = val;
+				closestPos.set(x, y);
+				closestSet = true;
+			}
+			else if (val < closestVal)
+			{
+				closestVal = val;
+				closestPos.set(x, y);
+			}
+		}
+	}
+
+	return closestPos;
 }
 }
 
 
 //--------------------------------------------------------------------------
 //--------------------------------------------------------------------------
@@ -539,3 +671,10 @@ DefineConsoleMethod(GuiColorPickerCtrl, updateColor, void, (), , "Forces update
 {
 {
 	object->updateColor();
 	object->updateColor();
 }
 }
+
+DefineEngineMethod(GuiColorPickerCtrl, setSelectorColor, void, (ColorF color), ,
+	"Sets the current position of the selector based on a color.n"
+	"@param color Color to look for.n")
+{
+	object->setSelectorPos(color);
+}

+ 7 - 1
Engine/source/gui/controls/guiColorPicker.h

@@ -98,7 +98,11 @@ class GuiColorPickerCtrl : public GuiControl
    bool mMouseDown;		///< Mouse button down?
    bool mMouseDown;		///< Mouse button down?
    bool mActionOnMove;		///< Perform onAction() when position has changed?
    bool mActionOnMove;		///< Perform onAction() when position has changed?
 
 
-	
+   bool mSelectColor;
+   ColorF mSetColor;
+   GBitmap* mBitmap;
+
+   Point2I findColor(const ColorF & color, const Point2I& offset, const Point2I& resolution, GBitmap& bmp);
    
    
    S32   mSelectorGap;		///< The half-way "gap" between the selector pos and where the selector is allowed to draw. 
    S32   mSelectorGap;		///< The half-way "gap" between the selector pos and where the selector is allowed to draw. 
 
 
@@ -113,6 +117,7 @@ class GuiColorPickerCtrl : public GuiControl
    DECLARE_CATEGORY( "Gui Editor" );
    DECLARE_CATEGORY( "Gui Editor" );
    
    
    GuiColorPickerCtrl();
    GuiColorPickerCtrl();
+   ~GuiColorPickerCtrl();
 
 
    static void initPersistFields();
    static void initPersistFields();
    void onRender(Point2I offset, const RectI &updateRect);
    void onRender(Point2I offset, const RectI &updateRect);
@@ -131,6 +136,7 @@ class GuiColorPickerCtrl : public GuiControl
    /// @name Selector Functions
    /// @name Selector Functions
    /// @{
    /// @{
    void setSelectorPos(const Point2I &pos); ///< Set new pos (in local coords)
    void setSelectorPos(const Point2I &pos); ///< Set new pos (in local coords)
+   void setSelectorPos(const ColorF & color);
    Point2I getSelectorPos() {return mSelectorPos;}
    Point2I getSelectorPos() {return mSelectorPos;}
    /// @}
    /// @}
    
    

+ 76 - 27
Engine/source/gui/controls/guiTextEditCtrl.cpp

@@ -128,6 +128,8 @@ GuiTextEditCtrl::GuiTextEditCtrl()
 
 
    mActive = true;
    mActive = true;
 
 
+   mTextValid = true;
+
    mTextOffsetReset = true;
    mTextOffsetReset = true;
 
 
    mHistoryDirty = false;
    mHistoryDirty = false;
@@ -1257,15 +1259,21 @@ void GuiTextEditCtrl::onRender(Point2I offset, const RectI &updateRect)
    //if opaque, fill the update rect with the fill color
    //if opaque, fill the update rect with the fill color
    if ( mProfile->mOpaque )
    if ( mProfile->mOpaque )
    {
    {
-      if(isFirstResponder())
-         GFX->getDrawUtil()->drawRectFill( ctrlRect, mProfile->mFillColorHL );
-      else
-         GFX->getDrawUtil()->drawRectFill( ctrlRect, mProfile->mFillColor );
+	   if (!mTextValid)
+		   GFX->getDrawUtil()->drawRectFill(ctrlRect, mProfile->mFillColorNA);
+	   else if (isFirstResponder())
+		   GFX->getDrawUtil()->drawRectFill(ctrlRect, mProfile->mFillColorHL);
+	   else
+		   GFX->getDrawUtil()->drawRectFill(ctrlRect, mProfile->mFillColor);
    }
    }
 
 
    //if there's a border, draw the border
    //if there's a border, draw the border
-   if ( mProfile->mBorder )
-      renderBorder( ctrlRect, mProfile );
+   if (mProfile->mBorder)
+   {
+	   renderBorder(ctrlRect, mProfile);
+	   if (!mTextValid)
+		   GFX->getDrawUtil()->drawRectFill(ctrlRect, mProfile->mFillColorNA);
+   }
 
 
    drawText( ctrlRect, isFirstResponder() );
    drawText( ctrlRect, isFirstResponder() );
 }
 }
@@ -1491,6 +1499,24 @@ bool GuiTextEditCtrl::hasText()
    return (mTextBuffer.length());
    return (mTextBuffer.length());
 }
 }
 
 
+void GuiTextEditCtrl::invalidText(bool playSound)
+{
+	mTextValid = false;
+
+	if (playSound)
+		playDeniedSound();
+}
+
+void GuiTextEditCtrl::validText()
+{
+	mTextValid = true;
+}
+
+bool GuiTextEditCtrl::isValidText()
+{
+	return mTextValid;
+}
+
 void GuiTextEditCtrl::playDeniedSound()
 void GuiTextEditCtrl::playDeniedSound()
 {
 {
    if ( mDeniedSound )
    if ( mDeniedSound )
@@ -1518,27 +1544,29 @@ void GuiTextEditCtrl::handleCharInput( U16 ascii )
    //see if it's a number field
    //see if it's a number field
    if ( mProfile->mNumbersOnly )
    if ( mProfile->mNumbersOnly )
    {
    {
-      if ( ascii == '-')
-      {
-         //a minus sign only exists at the beginning, and only a single minus sign
-         if ( mCursorPos != 0 && !isAllTextSelected() )
-         {
-            playDeniedSound();
-            return;
-         }
-
-         if ( mInsertOn && ( mTextBuffer.getChar(0) == '-' ) ) 
-         {
-            playDeniedSound();
-            return;
-         }
-      }
-      // BJTODO: This is probably not unicode safe.
-      else if (  ascii != '.' && (ascii < '0' || ascii > '9')  )
-      {
-         playDeniedSound();
-         return;
-      }
+	   if (ascii == '-')
+	   {
+		   //a minus sign only exists at the beginning, and only a single minus sign
+		   if (mCursorPos != 0 && !isAllTextSelected())
+		   {
+			   invalidText();
+			   return;
+		   }
+
+		   if (mInsertOn && (mTextBuffer.getChar(0) == '-'))
+		   {
+			   invalidText();
+			   return;
+		   }
+	   }
+	   // BJTODO: This is probably not unicode safe.
+	   else if (ascii != '.' && (ascii < '0' || ascii > '9'))
+	   {
+		   invalidText();
+		   return;
+	   }
+	   else
+		   validText();
    }
    }
 
 
    //save the current state
    //save the current state
@@ -1746,3 +1774,24 @@ DefineEngineMethod( GuiTextEditCtrl, forceValidateText, void, (),,
 {
 {
    object->forceValidateText();
    object->forceValidateText();
 }
 }
+
+DefineEngineMethod(GuiTextEditCtrl, invalidText, void, (bool playSound), (true),
+	"@brief Trigger the invalid sound and make the box red.nn"
+	"@param playSound Play the invalid text sound or not.n")
+{
+	object->invalidText(playSound);
+}
+
+
+DefineEngineMethod(GuiTextEditCtrl, validText, void, (), ,
+	"@brief Restores the box to normal color.nn")
+{
+	object->validText();
+}
+
+DefineEngineMethod(GuiTextEditCtrl, isValidText, bool, (), ,
+	"@brief Returns if the text is set to valid or not.n"
+	"@Return true if text is set to valid, false if not.nn")
+{
+	return object->isValidText();
+}

+ 6 - 0
Engine/source/gui/controls/guiTextEditCtrl.h

@@ -93,6 +93,8 @@ protected:
    void playDeniedSound();
    void playDeniedSound();
    void execConsoleCallback();
    void execConsoleCallback();
 
 
+   bool mTextValid;
+
    virtual void handleCharInput( U16 ascii );
    virtual void handleCharInput( U16 ascii );
 
 
    S32 findNextWord();   
    S32 findNextWord();   
@@ -119,6 +121,10 @@ public:
    S32   getCursorPos()   { return( mCursorPos ); }
    S32   getCursorPos()   { return( mCursorPos ); }
    void  setCursorPos( const S32 newPos );
    void  setCursorPos( const S32 newPos );
    
    
+   void invalidText(bool playSound = true);
+   void validText();
+   bool isValidText();
+
    bool isAllTextSelected();
    bool isAllTextSelected();
    void selectAllText();
    void selectAllText();
    void clearSelectedText();
    void clearSelectedText();

+ 13 - 0
Engine/source/math/mConsoleFunctions.cpp

@@ -103,6 +103,19 @@ DefineConsoleFunction( mRound, S32, ( F32 v  ),,
    return mRound(v);
    return mRound(v);
 }
 }
 
 
+DefineConsoleFunction( mRoundColour, F32, ( F32 v, S32 n ), (0),
+	"Round v to the nth decimal place or the nearest whole number by default."
+	"@param v Value to roundn"
+	"@param n Number of decimal places to round to, 0 by defaultn"
+	"@return The rounded value as a S32."
+	"@ingroup Math")
+{
+	if (n <= 0)
+		return mRound(v);
+	else
+		return mRound(v, n);
+}
+
 DefineConsoleFunction( mCeil, S32, ( F32 v ),,
 DefineConsoleFunction( mCeil, S32, ( F32 v ),,
     "Round v up to the nearest integer.\n"
     "Round v up to the nearest integer.\n"
     "@param v Number to convert to integer."
     "@param v Number to convert to integer."

文件差异内容过多而无法显示
+ 682 - 266
Templates/Empty/game/tools/gui/colorPicker.ed.gui


文件差异内容过多而无法显示
+ 682 - 266
Templates/Full/game/tools/gui/colorPicker.ed.gui


部分文件因为文件数量过多而无法显示