//----------------------------------------------------------------------------- // 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 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(); }