465 lines
15 KiB
C++
Executable File
465 lines
15 KiB
C++
Executable File
//-----------------------------------------------------------------------------
|
|
// Torque Game Engine
|
|
// Copyright (C) GarageGames.com, Inc.
|
|
//-----------------------------------------------------------------------------
|
|
#include "console/console.h"
|
|
#include "dgl/dgl.h"
|
|
#include "console/consoleTypes.h"
|
|
#include "platform/platformAudio.h"
|
|
#include "gui/core/guiCanvas.h"
|
|
#include "gui/controls/guiButtonCtrl.h"
|
|
#include "gui/core/guiDefaultControlRender.h"
|
|
#include "gui/controls/guiColorPicker.h"
|
|
|
|
/// @name Common colors we use
|
|
/// @{
|
|
ColorF colorWhite(1.,1.,1.);
|
|
ColorF colorWhiteBlend(1.,1.,1.,.75);
|
|
ColorF colorBlack(.0,.0,.0);
|
|
ColorF colorAlpha(0.0f, 0.0f, 0.0f, 0.0f);
|
|
|
|
ColorI GuiColorPickerCtrl::mColorRange[9] = {
|
|
ColorI(255,255,255), // White
|
|
ColorI(255,255,255), // White
|
|
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;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------
|
|
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));
|
|
endGroup("ColorPicker");
|
|
}
|
|
|
|
//--------------------------------------------------------------------------
|
|
// Function to draw a box which can have 4 different colors in each corner blended together
|
|
void dglDrawBlendBox(RectI &bounds, ColorF &c1, ColorF &c2, ColorF &c3, ColorF &c4)
|
|
{
|
|
S32 l = bounds.point.x, r = bounds.point.x + bounds.extent.x - 1;
|
|
S32 t = bounds.point.y, b = bounds.point.y + bounds.extent.y - 1;
|
|
|
|
glEnable(GL_BLEND);
|
|
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
|
glDisable(GL_TEXTURE_2D);
|
|
|
|
glBegin(GL_QUADS);
|
|
// Make sure the top row of pixels are the right color.
|
|
glColor4f(c1.red, c1.green, c1.blue, c1.alpha);
|
|
glVertex2f(l, t);
|
|
glColor4f(c2.red, c2.green, c2.blue, c2.alpha);
|
|
glVertex2f(r, t);
|
|
glColor4f(c2.red, c2.green, c2.blue, c2.alpha);
|
|
glVertex2f(r, t + 1);
|
|
glColor4f(c1.red, c1.green, c1.blue, c1.alpha);
|
|
glVertex2f(l, t + 1);
|
|
|
|
// The main blend box.
|
|
glColor4f(c1.red, c1.green, c1.blue, c1.alpha);
|
|
glVertex2f(l, t + 1);
|
|
glColor4f(c2.red, c2.green, c2.blue, c2.alpha);
|
|
glVertex2f(r, t + 1);
|
|
glColor4f(c3.red, c3.green, c3.blue, c3.alpha);
|
|
glVertex2f(r, b - 1);
|
|
glColor4f(c4.red, c4.green, c4.blue, c4.alpha);
|
|
glVertex2f(l, b - 1);
|
|
|
|
// Make sure the bottom row of pixels are the right color.
|
|
glColor4f(c4.red, c4.green, c4.blue, c4.alpha);
|
|
glVertex2f(l, b - 1);
|
|
glColor4f(c3.red, c3.green, c3.blue, c3.alpha);
|
|
glVertex2f(r, b - 1);
|
|
glColor4f(c3.red, c3.green, c3.blue, c3.alpha);
|
|
glVertex2f(r, b);
|
|
glColor4f(c4.red, c4.green, c4.blue, c4.alpha);
|
|
glVertex2f(l, 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)
|
|
{
|
|
S32 l = bounds.point.x, r = bounds.point.x + bounds.extent.x - 1;
|
|
S32 t = bounds.point.y, b = bounds.point.y + bounds.extent.y - 1;
|
|
|
|
// Calculate increment value
|
|
S32 x_inc = int(mFloor((r - l) / (numColors-1)));
|
|
S32 y_inc = int(mFloor((b - t) / (numColors-1)));
|
|
|
|
glEnable(GL_BLEND);
|
|
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
|
glDisable(GL_TEXTURE_2D);
|
|
|
|
glBegin(GL_QUADS);
|
|
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 += r-l-1;
|
|
y_inc += b-t-1;
|
|
}
|
|
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();
|
|
}
|
|
|
|
void GuiColorPickerCtrl::drawSelector(RectI &bounds, Point2I &selectorPos, SelectorMode mode)
|
|
{
|
|
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;
|
|
}
|
|
}
|
|
|
|
//--------------------------------------------------------------------------
|
|
/// 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, 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, colorBlack, colorBlack );
|
|
drawSelector( pickerBounds, selectorPos, sHorizontal );
|
|
drawSelector( pickerBounds, selectorPos, sVertical );
|
|
break;
|
|
case pDropperBackground:
|
|
break;
|
|
case pPallet:
|
|
default:
|
|
dglDrawRectFill( pickerBounds, mBaseColor );
|
|
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()
|
|
GLfloat rBuffer[4];
|
|
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_RGBA, GL_FLOAT, rBuffer);
|
|
|
|
mPickColor.red = rBuffer[0];
|
|
mPickColor.green = rBuffer[1];
|
|
mPickColor.blue = rBuffer[2];
|
|
mPickColor.alpha = rBuffer[3];
|
|
|
|
// Now do onAction() if we are allowed
|
|
if (mActionOnMove)
|
|
onAction();
|
|
}
|
|
}
|
|
|
|
//render the children
|
|
renderChildControls( offset, updateRect);
|
|
}
|
|
|
|
//--------------------------------------------------------------------------
|
|
void GuiColorPickerCtrl::setSelectorPos(const Point2I &pos)
|
|
{
|
|
Point2I extent = mBounds.extent;
|
|
RectI rect;
|
|
if (mDisplayMode != pDropperBackground)
|
|
{
|
|
extent.x -= 3;
|
|
extent.y -= 2;
|
|
rect = RectI(Point2I(1,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();
|
|
}
|
|
}
|
|
|
|
//--------------------------------------------------------------------------
|
|
void GuiColorPickerCtrl::onMouseDown(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;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------
|
|
void GuiColorPickerCtrl::onMouseDragged(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 );
|
|
|
|
}
|
|
|
|
//--------------------------------------------------------------------------
|
|
void GuiColorPickerCtrl::onMouseMove(const GuiEvent &event)
|
|
{
|
|
// Only for dropper mode
|
|
if (mActive && (mDisplayMode == pDropperBackground))
|
|
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))
|
|
{
|
|
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();
|
|
}
|
|
|
|
//--------------------------------------------------------------------------
|
|
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;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------
|
|
void GuiColorPickerCtrl::setScriptValue(const char *value)
|
|
{
|
|
ColorF newValue;
|
|
dSscanf(value, "%f %f %f %f", &newValue.red, &newValue.green, &newValue.blue, &newValue.alpha);
|
|
setValue(newValue);
|
|
}
|
|
|
|
ConsoleMethod(GuiColorPickerCtrl, getSelectorPos, const char*, 2, 2, "Gets the current position of the selector")
|
|
{
|
|
char *temp = Con::getReturnBuffer(256);
|
|
Point2I pos;
|
|
pos = object->getSelectorPos();
|
|
dSprintf(temp,256,"%d %d",pos.x, pos.y);
|
|
return temp;
|
|
}
|
|
|
|
ConsoleMethod(GuiColorPickerCtrl, setSelectorPos, void, 3, 3, "Sets the current position of the selector")
|
|
{
|
|
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")
|
|
{
|
|
object->updateColor();
|
|
}
|