Merge pull request #1533 from GarageGames/pr/1334

New color picker - #1334 clone
This commit is contained in:
Anis 2016-02-26 22:02:07 +01:00
commit 9efe22649b
11 changed files with 2501 additions and 738 deletions

View file

@ -39,6 +39,9 @@
#include "core/util/journal/journal.h"
#include "gfx/gfxEnums.h"
#include "core/util/uuid.h"
#include "core/color.h"
#include "math/mPoint3.h"
#include "math/mathTypes.h"
// This is a temporary hack to get tools using the library to
// link in this module which contains no other references.
@ -1018,6 +1021,88 @@ DefineConsoleFunction( strrchrpos, S32, ( const char* str, const char* chr, S32
//----------------------------------------------------------------
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")
{
S32 rgb = dAtoui(hex, 16);
ColorI color;
color.set(rgb & 0x000000FF, (rgb & 0x0000FF00) >> 8, (rgb & 0x00FF0000) >> 16);
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;
}
//----------------------------------------------------------------
DefineConsoleFunction( strToggleCaseToWords, const char*, ( const char* str ),,
"Parse a Toggle Case word into separate words.\n"
"@param str The string to parse.\n"
@ -3068,4 +3153,4 @@ DefineEngineFunction( getMaxDynamicVerts, S32, (),,
"@return the max number of allowable dynamic vertices in a single vertex buffer" )
{
return MAX_DYNAMIC_VERTS / 2;
}
}

View file

@ -30,6 +30,10 @@
#include "math/mPoint4.h"
#endif
#ifndef _ENGINEAPI_H_
#include "console/engineAPI.h"
#endif
class ColorI;
@ -121,9 +125,20 @@ class ColorI
U8 blue;
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:
ColorI() { }
ColorI(const ColorI& in_rCopy);
ColorI(const Hsb& color);
ColorI(const U8 in_r,
const U8 in_g,
const U8 in_b,
@ -132,6 +147,12 @@ class ColorI
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,
const U8 in_g,
const U8 in_b,
@ -176,6 +197,11 @@ class ColorI
U16 get565() const;
U16 get4444() const;
Hsb getHSB() const;
String getHex() const;
S32 convertFromHex(const String& hex) const;
operator ColorF() const;
operator const U8*() const { return &red; }
@ -459,6 +485,174 @@ inline void ColorI::set(const ColorI& in_rCopy,
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)
{
red = in_rCopy.red;
@ -467,6 +661,11 @@ inline ColorI::ColorI(const ColorI& in_rCopy)
alpha = in_rCopy.alpha;
}
inline ColorI::ColorI(const Hsb& color)
{
set(color);
}
inline ColorI::ColorI(const U8 in_r,
const U8 in_g,
const U8 in_b,
@ -648,6 +847,91 @@ inline U16 ColorI::get4444() const
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 ColorF::operator ColorI() const
{

View file

@ -39,13 +39,13 @@ ColorF colorAlpha(0.0f, 0.0f, 0.0f, 0.0f);
ColorF colorAlphaW(1.0f, 1.0f, 1.0f, 0.0f);
ColorI GuiColorPickerCtrl::mColorRange[7] = {
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(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
};
/// @}
@ -57,7 +57,6 @@ ConsoleDocClass( GuiColorPickerCtrl,
"@internal"
);
//--------------------------------------------------------------------------
GuiColorPickerCtrl::GuiColorPickerCtrl()
{
setExtent(140, 30);
@ -70,44 +69,50 @@ GuiColorPickerCtrl::GuiColorPickerCtrl()
mPositionChanged = false;
mSelectorGap = 1;
mActionOnMove = false;
mShowReticle = true;
mShowReticle = true;
mSelectColor = false;
mSetColor = mSetColor.BLACK;
mBitmap = NULL;
}
//--------------------------------------------------------------------------
GuiColorPickerCtrl::~GuiColorPickerCtrl()
{
if (mBitmap)
{
delete mBitmap;
mBitmap = NULL;
}
}
ImplementEnumType( GuiColorPickMode,
"\n\n"
"@ingroup GuiUtil"
"@internal" )
{ GuiColorPickerCtrl::pPallet, "Pallete" },
{ GuiColorPickerCtrl::pHorizColorRange, "HorizColor"},
{ GuiColorPickerCtrl::pVertColorRange, "VertColor" },
{ GuiColorPickerCtrl::pHorizColorBrightnessRange, "HorizBrightnessColor"},
{ GuiColorPickerCtrl::pVertColorBrightnessRange, "VertBrightnessColor" },
{ GuiColorPickerCtrl::pBlendColorRange, "BlendColor"},
{ GuiColorPickerCtrl::pHorizAlphaRange, "HorizAlpha"},
{ GuiColorPickerCtrl::pVertAlphaRange, "VertAlpha" },
{ GuiColorPickerCtrl::pDropperBackground, "Dropper" },
{ GuiColorPickerCtrl::pPallet, "Pallete" },
{ GuiColorPickerCtrl::pHorizColorRange, "HorizColor"},
{ GuiColorPickerCtrl::pVertColorRange, "VertColor" },
{ GuiColorPickerCtrl::pHorizColorBrightnessRange, "HorizBrightnessColor" },
{ GuiColorPickerCtrl::pVertColorBrightnessRange, "VertBrightnessColor" },
{ GuiColorPickerCtrl::pBlendColorRange, "BlendColor" },
{ GuiColorPickerCtrl::pHorizAlphaRange, "HorizAlpha" },
{ GuiColorPickerCtrl::pVertAlphaRange, "VertAlpha" },
{ GuiColorPickerCtrl::pDropperBackground, "Dropper" },
EndImplementEnumType;
//--------------------------------------------------------------------------
void GuiColorPickerCtrl::initPersistFields()
{
addGroup("ColorPicker");
addField("baseColor", TypeColorF, Offset(mBaseColor, GuiColorPickerCtrl));
addField("pickColor", TypeColorF, Offset(mPickColor, GuiColorPickerCtrl));
addField("selectorGap", TypeS32, Offset(mSelectorGap, GuiColorPickerCtrl));
addField("displayMode", TYPEID< PickMode >(), Offset(mDisplayMode, GuiColorPickerCtrl) );
addField("actionOnMove", TypeBool,Offset(mActionOnMove, GuiColorPickerCtrl));
addField("showReticle", TypeBool, Offset(mShowReticle, GuiColorPickerCtrl));
endGroup("ColorPicker");
Parent::initPersistFields();
}
//--------------------------------------------------------------------------
// Function to draw a box which can have 4 different colors in each corner blended together
void GuiColorPickerCtrl::drawBlendBox(RectI &bounds, ColorF &c1, ColorF &c2, ColorF &c3, ColorF &c4)
{
@ -119,54 +124,54 @@ void GuiColorPickerCtrl::drawBlendBox(RectI &bounds, ColorF &c1, ColorF &c2, Col
//A couple of checks to determine if color blend
if(c1 == colorWhite && c3 == colorAlpha && c4 == colorBlack)
{
//Color
PrimBuild::begin( GFXTriangleFan, 4 );
PrimBuild::color( c2 );
PrimBuild::vertex2i( r, t );
//Color
PrimBuild::begin(GFXTriangleFan, 4);
PrimBuild::color( c2 );
PrimBuild::vertex2i( r, t );
PrimBuild::color( c2 );
PrimBuild::vertex2i( r, b );
PrimBuild::color( c2 );
PrimBuild::vertex2i( r, b );
PrimBuild::color( c2 );
PrimBuild::vertex2i( l, b );
PrimBuild::color( c2 );
PrimBuild::vertex2i( l, b );
PrimBuild::color( c2 );
PrimBuild::vertex2i( l, t );
PrimBuild::end();
PrimBuild::color( c2 );
PrimBuild::vertex2i( l, t );
PrimBuild::end();
//White
PrimBuild::begin( GFXTriangleFan, 4 );
PrimBuild::color( colorAlphaW );
PrimBuild::vertex2i( r, t );
//White
PrimBuild::begin( GFXTriangleFan, 4 );
PrimBuild::color( colorAlphaW );
PrimBuild::vertex2i( r, t );
PrimBuild::color( colorAlphaW );
PrimBuild::vertex2i( r, b );
PrimBuild::color( colorAlphaW );
PrimBuild::vertex2i( r, b );
PrimBuild::color( c1 );
PrimBuild::vertex2i( l, b );
PrimBuild::color( c1 );
PrimBuild::vertex2i( l, b );
PrimBuild::color( c1 );
PrimBuild::vertex2i( l, t );
PrimBuild::end();
PrimBuild::color( c1 );
PrimBuild::vertex2i( l, t );
PrimBuild::end();
//Black
PrimBuild::begin( GFXTriangleFan, 4 );
PrimBuild::color( c3 );
PrimBuild::vertex2i( r, t );
//Black
PrimBuild::begin( GFXTriangleFan, 4 );
PrimBuild::color( c3 );
PrimBuild::vertex2i( r, t );
PrimBuild::color( c4 );
PrimBuild::vertex2i( r, b );
PrimBuild::color( c4 );
PrimBuild::vertex2i( r, b );
PrimBuild::color( c4 );
PrimBuild::vertex2i( l, b );
PrimBuild::color( c4 );
PrimBuild::vertex2i( l, b );
PrimBuild::color( c3 );
PrimBuild::vertex2i( l, t );
PrimBuild::end();
PrimBuild::color( c3 );
PrimBuild::vertex2i( l, t );
PrimBuild::end();
}
else
{
PrimBuild::begin( GFXTriangleFan, 4 );
PrimBuild::begin( GFXTriangleFan, 4 );
PrimBuild::color( c1 );
PrimBuild::vertex2i( l, t );
@ -233,31 +238,29 @@ void GuiColorPickerCtrl::drawBlendRangeBox(RectI &bounds, bool vertical, U8 numC
void GuiColorPickerCtrl::drawSelector(RectI &bounds, Point2I &selectorPos, SelectorMode mode)
{
if( !mShowReticle )
return;
if( !mShowReticle )
return;
U16 sMax = mSelectorGap*2;
switch (mode)
{
case sVertical:
// Now draw the vertical selector
// Up -> Pos
if (selectorPos.y != bounds.point.y+1)
GFX->getDrawUtil()->drawLine(selectorPos.x, bounds.point.y, selectorPos.x, selectorPos.y-sMax-1, colorWhiteBlend);
// Down -> Pos
if (selectorPos.y != bounds.point.y+bounds.extent.y)
GFX->getDrawUtil()->drawLine(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)
U16 sMax = mSelectorGap*2;
switch (mode)
{
case sVertical:
// Now draw the vertical selector Up -> Pos
if (selectorPos.y != bounds.point.y+1)
GFX->getDrawUtil()->drawLine(selectorPos.x, bounds.point.y, selectorPos.x, selectorPos.y-sMax-1, colorWhiteBlend);
// Down -> Pos
if (selectorPos.y != bounds.point.y+bounds.extent.y)
GFX->getDrawUtil()->drawLine(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)
GFX->getDrawUtil()->drawLine(bounds.point.x, selectorPos.y-1, selectorPos.x-sMax, selectorPos.y-1, colorWhiteBlend);
// Right -> Pos
if (selectorPos.x != bounds.point.x)
// Right -> Pos
if (selectorPos.x != bounds.point.x)
GFX->getDrawUtil()->drawLine(bounds.point.x+mSelectorPos.x+sMax, selectorPos.y-1, bounds.point.x + bounds.extent.x, selectorPos.y-1, colorWhiteBlend);
break;
}
break;
}
}
//--------------------------------------------------------------------------
@ -269,10 +272,10 @@ void GuiColorPickerCtrl::renderColorBox(RectI &bounds)
pickerBounds.point.y = bounds.point.y+1;
pickerBounds.extent.x = bounds.extent.x-1;
pickerBounds.extent.y = bounds.extent.y-1;
if (mProfile->mBorder)
GFX->getDrawUtil()->drawRect(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
@ -338,56 +341,169 @@ void GuiColorPickerCtrl::onRender(Point2I offset, const RectI& updateRect)
desc.setZReadWrite(false);
desc.zWriteEnable = false;
desc.setCullMode(GFXCullNone);
mStateBlock = GFX->createStateBlock( desc );
mStateBlock = GFX->createStateBlock(desc);
}
RectI boundsRect(offset, getExtent());
RectI boundsRect(offset, getExtent());
renderColorBox(boundsRect);
if (mPositionChanged)
if (mPositionChanged || mBitmap == NULL)
{
bool nullBitmap = false;
if (mPositionChanged == false && mBitmap == NULL)
nullBitmap = true;
mPositionChanged = false;
Point2I extent = getRoot()->getExtent();
// If we are anything but a pallete, change the pick color
if (mDisplayMode != pPallet)
{
Point2I resolution = getRoot()->getExtent();
U32 buf_x = offset.x + mSelectorPos.x + 1;
U32 buf_y = resolution.y - ( extent.y - ( offset.y + mSelectorPos.y + 1 ) );
U32 buf_y = resolution.y - (extent.y - (offset.y + mSelectorPos.y + 1));
GFXTexHandle bb( resolution.x,
resolution.y,
GFXFormatR8G8B8A8, &GFXDefaultRenderTargetProfile, avar("%s() - bb (line %d)", __FUNCTION__, __LINE__) );
Point2I tmpPt( buf_x, buf_y );
GFXTexHandle bb( resolution.x, resolution.y, GFXFormatR8G8B8A8, &GFXDefaultRenderTargetProfile, avar("%s() - bb (line %d)", __FUNCTION__, __LINE__) );
Point2I tmpPt(buf_x, buf_y);
GFXTarget *targ = GFX->getActiveRenderTarget();
targ->resolveTo( bb );
GBitmap bmp( bb.getWidth(), bb.getHeight() );
targ->resolveTo(bb);
bb.copyToBmp( &bmp );
//bmp.writePNGDebug( "foo.png" );
if (mBitmap)
{
delete mBitmap;
mBitmap = NULL;
}
ColorI tmp;
bmp.getColor( buf_x, buf_y, tmp );
mBitmap = new GBitmap(bb.getWidth(), bb.getHeight());
mPickColor = (ColorF)tmp;
bb.copyToBmp(mBitmap);
// Now do onAction() if we are allowed
if (mActionOnMove)
onAction();
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);
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));
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;
}
//--------------------------------------------------------------------------
void GuiColorPickerCtrl::setSelectorPos(const Point2I &pos)
{
Point2I extent = getExtent();
@ -432,7 +548,6 @@ void GuiColorPickerCtrl::setSelectorPos(const Point2I &pos)
}
}
//--------------------------------------------------------------------------
void GuiColorPickerCtrl::onMouseDown(const GuiEvent &event)
{
if (!mActive)
@ -445,14 +560,14 @@ void GuiColorPickerCtrl::onMouseDown(const GuiEvent &event)
if (mProfile->mCanKeyFocus)
setFirstResponder();
if (mActive && (mDisplayMode != pDropperBackground))
if (mActive && (mDisplayMode != pDropperBackground))
onAction();
// Update the picker cross position
if (mDisplayMode != pPallet)
setSelectorPos(globalToLocalCoord(event.mousePoint));
setSelectorPos(globalToLocalCoord(event.mousePoint));
mMouseDown = true;
}
@ -468,10 +583,8 @@ void GuiColorPickerCtrl::onMouseDragged(const GuiEvent &event)
if( !mActionOnMove )
execAltConsoleCallback();
}
//--------------------------------------------------------------------------
void GuiColorPickerCtrl::onMouseMove(const GuiEvent &event)
{
// Only for dropper mode
@ -479,45 +592,40 @@ void GuiColorPickerCtrl::onMouseMove(const GuiEvent &event)
setSelectorPos(globalToLocalCoord(event.mousePoint));
}
//--------------------------------------------------------------------------
void GuiColorPickerCtrl::onMouseEnter(const GuiEvent &event)
{
mMouseOver = true;
}
//--------------------------------------------------------------------------
void GuiColorPickerCtrl::onMouseLeave(const GuiEvent &)
{
// Reset state
mMouseOver = false;
}
//--------------------------------------------------------------------------
void GuiColorPickerCtrl::onMouseUp(const GuiEvent &)
{
//if we released the mouse within this control, perform the action
if (mActive && mMouseDown && (mDisplayMode != pDropperBackground))
if (mActive && mMouseDown && (mDisplayMode != pDropperBackground))
mMouseDown = false;
if (mActive && (mDisplayMode == pDropperBackground))
if (mActive && (mDisplayMode == pDropperBackground))
{
// In a dropper, the alt command executes the mouse up action (to signal stopping)
execAltConsoleCallback();
}
mouseUnlock();
}
//--------------------------------------------------------------------------
const char *GuiColorPickerCtrl::getScriptValue()
{
static char temp[256];
ColorF color = getValue();
dSprintf(temp,256,"%f %f %f %f",color.red, color.green, color.blue, color.alpha);
return temp;
dSprintf( temp, 256, "%f %f %f %f", color.red, color.green, color.blue, color.alpha );
return temp;
}
//--------------------------------------------------------------------------
void GuiColorPickerCtrl::setScriptValue(const char *value)
{
ColorF newValue;
@ -537,5 +645,12 @@ DefineConsoleMethod(GuiColorPickerCtrl, setSelectorPos, void, (Point2I newPos),
DefineConsoleMethod(GuiColorPickerCtrl, updateColor, void, (), , "Forces update of pick color")
{
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);
}

View file

@ -59,29 +59,28 @@ class GuiColorPickerCtrl : public GuiControl
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
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)
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
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
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
void drawBlendBox(RectI &bounds, ColorF &c1, ColorF &c2, ColorF &c3, ColorF &c4);
void drawBlendRangeBox(RectI &bounds, bool vertical, U8 numColors, ColorI *colors);
/// @}
@ -98,7 +97,11 @@ class GuiColorPickerCtrl : public GuiControl
bool mMouseDown; ///< Mouse button down?
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.
@ -107,12 +110,13 @@ class GuiColorPickerCtrl : public GuiControl
static ColorI mColorRange[7]; ///< Color range for pHorizColorRange and pVertColorRange
/// @}
public:
public:
DECLARE_CONOBJECT(GuiColorPickerCtrl);
DECLARE_CATEGORY( "Gui Editor" );
GuiColorPickerCtrl();
~GuiColorPickerCtrl();
static void initPersistFields();
void onRender(Point2I offset, const RectI &updateRect);
@ -122,18 +126,19 @@ class GuiColorPickerCtrl : public GuiControl
/// 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" colours themselves)
ColorF getValue() {return mDisplayMode == pPallet ? mBaseColor : mPickColor;}
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)
void setSelectorPos(const ColorF & color);
Point2I getSelectorPos() {return mSelectorPos;}
/// @}
/// @name Input Events
/// @{
void onMouseDown(const GuiEvent &);

View file

@ -128,6 +128,8 @@ GuiTextEditCtrl::GuiTextEditCtrl()
mActive = true;
mTextValid = true;
mTextOffsetReset = true;
mHistoryDirty = false;
@ -1252,14 +1254,16 @@ void GuiTextEditCtrl::onLoseFirstResponder()
Parent::onLoseFirstResponder();
}
void GuiTextEditCtrl::onRender(Point2I offset, const RectI &updateRect)
void GuiTextEditCtrl::onRender( Point2I offset, const RectI &updateRect )
{
RectI ctrlRect( offset, getExtent() );
//if opaque, fill the update rect with the fill color
if ( mProfile->mOpaque )
{
if(isFirstResponder())
if ( !mTextValid )
GFX->getDrawUtil()->drawRectFill( ctrlRect, mProfile->mFillColorERR );
else if ( isFirstResponder() )
GFX->getDrawUtil()->drawRectFill( ctrlRect, mProfile->mFillColorHL );
else
GFX->getDrawUtil()->drawRectFill( ctrlRect, mProfile->mFillColor );
@ -1267,7 +1271,11 @@ void GuiTextEditCtrl::onRender(Point2I offset, const RectI &updateRect)
//if there's a border, draw the border
if ( mProfile->mBorder )
{
renderBorder( ctrlRect, mProfile );
if ( !mTextValid )
GFX->getDrawUtil()->drawRectFill( ctrlRect, mProfile->mFillColorERR );
}
drawText( ctrlRect, isFirstResponder() );
}
@ -1490,7 +1498,25 @@ void GuiTextEditCtrl::drawText( const RectI &drawRect, bool isFocused )
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()
@ -1520,27 +1546,29 @@ void GuiTextEditCtrl::handleCharInput( U16 ascii )
//see if it's a number field
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 (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) == '-' ) )
{
playDeniedSound();
return;
}
}
// BJTODO: This is probably not unicode safe.
else if ( ascii != '.' && (ascii < '0' || ascii > '9') )
{
playDeniedSound();
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
@ -1748,3 +1776,24 @@ DefineEngineMethod( GuiTextEditCtrl, forceValidateText, void, (),,
{
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();
}

View file

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

View file

@ -269,6 +269,7 @@ GuiControlProfile::GuiControlProfile(void) :
mFillColor(255,0,255,255),
mFillColorHL(255,0,255,255),
mFillColorNA(255,0,255,255),
mFillColorERR(255,0,0,255),
mFillColorSEL(255,0,255,255),
mBorderColor(255,0,255,255),
mBorderColorHL(255,0,255,255),
@ -334,6 +335,7 @@ GuiControlProfile::GuiControlProfile(void) :
mFillColor = def->mFillColor;
mFillColorHL = def->mFillColorHL;
mFillColorNA = def->mFillColorNA;
mFillColorERR = def->mFillColorERR;
mFillColorSEL = def->mFillColorSEL;
mBorder = def->mBorder;
@ -398,6 +400,7 @@ void GuiControlProfile::initPersistFields()
addField("fillColor", TypeColorI, Offset(mFillColor, GuiControlProfile));
addField("fillColorHL", TypeColorI, Offset(mFillColorHL, GuiControlProfile));
addField("fillColorNA", TypeColorI, Offset(mFillColorNA, GuiControlProfile));
addField("fillColorERR", TypeColorI, Offset(mFillColorERR, GuiControlProfile));
addField("fillColorSEL", TypeColorI, Offset(mFillColorSEL, GuiControlProfile));
addField("border", TypeS32, Offset(mBorder, GuiControlProfile),
"Border type (0=no border)." );

View file

@ -385,6 +385,7 @@ public:
ColorI mFillColor; ///< Fill color, this is used to fill the bounds of the control if it is opaque
ColorI mFillColorHL; ///< This is used instead of mFillColor if the object is highlighted
ColorI mFillColorNA; ///< This is used instead of mFillColor if the object is not active or disabled
ColorI mFillColorERR; ///< This is used instead of mFillColor if the object has an error or is invalid
ColorI mFillColorSEL; ///< This is used instead of mFillColor if the object is selected
S32 mBorder; ///< For most controls, if mBorder is > 0 a border will be drawn, some controls use this to draw different types of borders however @see guiDefaultControlRender.cc

View file

@ -103,6 +103,19 @@ DefineConsoleFunction( mRound, S32, ( F32 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 ),,
"Round v up to the nearest integer.\n"
"@param v Number to convert to integer."

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff