mirror of
https://github.com/TorqueGameEngines/Torque3D.git
synced 2026-04-26 14:55:39 +00:00
Engine directory for ticket #1
This commit is contained in:
parent
352279af7a
commit
7dbfe6994d
3795 changed files with 1363358 additions and 0 deletions
54
Engine/source/gui/controls/guiBackgroundCtrl.cpp
Normal file
54
Engine/source/gui/controls/guiBackgroundCtrl.cpp
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// Copyright (c) 2012 GarageGames, LLC
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to
|
||||
// deal in the Software without restriction, including without limitation the
|
||||
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
// sell copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
// IN THE SOFTWARE.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "console/console.h"
|
||||
#include "gui/controls/guiBackgroundCtrl.h"
|
||||
|
||||
IMPLEMENT_CONOBJECT(GuiBackgroundCtrl);
|
||||
|
||||
ConsoleDocClass( GuiBackgroundCtrl,
|
||||
"@brief Renders a background, so you can have a backdrop for your GUI.\n\n"
|
||||
|
||||
"Deprecated\n\n"
|
||||
|
||||
"@ingroup GuiImages\n"
|
||||
|
||||
"@internal"
|
||||
);
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
GuiBackgroundCtrl::GuiBackgroundCtrl() : GuiControl()
|
||||
{
|
||||
mDraw = false;
|
||||
mIsContainer = true;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
void GuiBackgroundCtrl::onRender(Point2I offset, const RectI &updateRect)
|
||||
{
|
||||
if ( mDraw )
|
||||
Parent::onRender( offset, updateRect );
|
||||
|
||||
renderChildControls(offset, updateRect);
|
||||
}
|
||||
|
||||
|
||||
48
Engine/source/gui/controls/guiBackgroundCtrl.h
Normal file
48
Engine/source/gui/controls/guiBackgroundCtrl.h
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// Copyright (c) 2012 GarageGames, LLC
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to
|
||||
// deal in the Software without restriction, including without limitation the
|
||||
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
// sell copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
// IN THE SOFTWARE.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef _GUIBACKGROUNDCTRL_H_
|
||||
#define _GUIBACKGROUNDCTRL_H_
|
||||
|
||||
#ifndef _GUICONTROL_H_
|
||||
#include "gui/core/guiControl.h"
|
||||
#endif
|
||||
|
||||
/// Renders a background, so you can have a backdrop for your GUI.
|
||||
class GuiBackgroundCtrl : public GuiControl
|
||||
{
|
||||
private:
|
||||
typedef GuiControl Parent;
|
||||
|
||||
public:
|
||||
bool mDraw;
|
||||
|
||||
//creation methods
|
||||
DECLARE_CONOBJECT(GuiBackgroundCtrl);
|
||||
DECLARE_CATEGORY( "Gui Containers" );
|
||||
|
||||
GuiBackgroundCtrl();
|
||||
|
||||
void onRender(Point2I offset, const RectI &updateRect);
|
||||
};
|
||||
|
||||
#endif
|
||||
197
Engine/source/gui/controls/guiBitmapBorderCtrl.cpp
Normal file
197
Engine/source/gui/controls/guiBitmapBorderCtrl.cpp
Normal file
|
|
@ -0,0 +1,197 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// Copyright (c) 2012 GarageGames, LLC
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to
|
||||
// deal in the Software without restriction, including without limitation the
|
||||
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
// sell copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
// IN THE SOFTWARE.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "platform/platform.h"
|
||||
|
||||
#include "gui/core/guiControl.h"
|
||||
#include "gfx/gfxDevice.h"
|
||||
#include "gfx/gfxDrawUtil.h"
|
||||
|
||||
|
||||
// [rene 11/09/09] Why does this not use the bitmap array from its profile?
|
||||
|
||||
|
||||
/// Renders a skinned border.
|
||||
class GuiBitmapBorderCtrl : public GuiControl
|
||||
{
|
||||
typedef GuiControl Parent;
|
||||
|
||||
enum {
|
||||
BorderTopLeft,
|
||||
BorderTopRight,
|
||||
BorderTop,
|
||||
BorderLeft,
|
||||
BorderRight,
|
||||
BorderBottomLeft,
|
||||
BorderBottom,
|
||||
BorderBottomRight,
|
||||
NumBitmaps
|
||||
};
|
||||
RectI *mBitmapBounds; ///< bmp is [3*n], bmpHL is [3*n + 1], bmpNA is [3*n + 2]
|
||||
GFXTexHandle mTextureObject;
|
||||
public:
|
||||
bool onWake();
|
||||
void onSleep();
|
||||
void onRender(Point2I offset, const RectI &updateRect);
|
||||
DECLARE_CONOBJECT(GuiBitmapBorderCtrl);
|
||||
DECLARE_CATEGORY( "Gui Images" );
|
||||
DECLARE_DESCRIPTION( "A control that renders a skinned border." );
|
||||
};
|
||||
|
||||
IMPLEMENT_CONOBJECT(GuiBitmapBorderCtrl);
|
||||
|
||||
ConsoleDocClass( GuiBitmapBorderCtrl,
|
||||
"@brief A control that renders a skinned border specified in its profile.\n\n"
|
||||
|
||||
"This control uses the bitmap specified in it's profile (GuiControlProfile::bitmapName). It takes this image and breaks up aspects of it "
|
||||
"to skin the border of this control with. It is also important to set GuiControlProfile::hasBitmapArray to true on the profile as well.\n\n"
|
||||
|
||||
"The bitmap referenced should be broken up into a 3 x 3 grid (using the top left color pixel as a border color between each of the images) "
|
||||
"in which it will map to the following places:\n"
|
||||
"1 = Top Left Corner\n"
|
||||
"2 = Top Right Corner\n"
|
||||
"3 = Top Center\n"
|
||||
"4 = Left Center\n"
|
||||
"5 = Right Center\n"
|
||||
"6 = Bottom Left Corner\n"
|
||||
"7 = Bottom Center\n"
|
||||
"8 = Bottom Right Corner\n"
|
||||
"0 = Nothing\n\n"
|
||||
|
||||
"1 2 3\n"
|
||||
"4 5 0\n"
|
||||
"6 7 8\n\n"
|
||||
|
||||
"@tsexample\n"
|
||||
"singleton GuiControlProfile (BorderGUIProfile)\n"
|
||||
"{\n"
|
||||
" bitmap = \"core/art/gui/images/borderArray\";\n"
|
||||
" hasBitmapArray = true;\n"
|
||||
" opaque = false;\n"
|
||||
"};\n\n"
|
||||
|
||||
"new GuiBitmapBorderCtrl(BitmapBorderGUI)\n"
|
||||
"{\n"
|
||||
" profile = \"BorderGUIProfile\";\n"
|
||||
" position = \"0 0\";\n"
|
||||
" extent = \"400 40\";\n"
|
||||
" visible = \"1\";\n"
|
||||
"};"
|
||||
"@endtsexample\n\n"
|
||||
|
||||
"@see GuiControlProfile::bitmapName\n"
|
||||
"@see GuiControlProfile::hasBitmapArray\n\n"
|
||||
|
||||
"@ingroup GuiImages"
|
||||
);
|
||||
|
||||
bool GuiBitmapBorderCtrl::onWake()
|
||||
{
|
||||
if (! Parent::onWake())
|
||||
return false;
|
||||
|
||||
//get the texture for the close, minimize, and maximize buttons
|
||||
mBitmapBounds = NULL;
|
||||
mTextureObject = mProfile->mTextureObject;
|
||||
if( mProfile->constructBitmapArray() >= NumBitmaps )
|
||||
mBitmapBounds = mProfile->mBitmapArrayRects.address();
|
||||
else
|
||||
Con::errorf( "GuiBitmapBorderCtrl: Could not construct bitmap array for profile '%s'", mProfile->getName() );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void GuiBitmapBorderCtrl::onSleep()
|
||||
{
|
||||
mTextureObject = NULL;
|
||||
mBitmapBounds = NULL;
|
||||
|
||||
Parent::onSleep();
|
||||
}
|
||||
|
||||
void GuiBitmapBorderCtrl::onRender(Point2I offset, const RectI &updateRect)
|
||||
{
|
||||
renderChildControls( offset, updateRect );
|
||||
|
||||
if( mBitmapBounds )
|
||||
{
|
||||
GFX->setClipRect(updateRect);
|
||||
|
||||
//draw the outline
|
||||
RectI winRect;
|
||||
winRect.point = offset;
|
||||
winRect.extent = getExtent();
|
||||
|
||||
winRect.point.x += mBitmapBounds[BorderLeft].extent.x;
|
||||
winRect.point.y += mBitmapBounds[BorderTop].extent.y;
|
||||
|
||||
winRect.extent.x -= mBitmapBounds[BorderLeft].extent.x + mBitmapBounds[BorderRight].extent.x;
|
||||
winRect.extent.y -= mBitmapBounds[BorderTop].extent.y + mBitmapBounds[BorderBottom].extent.y;
|
||||
|
||||
if(mProfile->mOpaque)
|
||||
GFX->getDrawUtil()->drawRectFill(winRect, mProfile->mFillColor);
|
||||
|
||||
GFX->getDrawUtil()->clearBitmapModulation();
|
||||
GFX->getDrawUtil()->drawBitmapSR(mTextureObject, offset, mBitmapBounds[BorderTopLeft]);
|
||||
GFX->getDrawUtil()->drawBitmapSR(mTextureObject, Point2I(offset.x + getWidth() - mBitmapBounds[BorderTopRight].extent.x, offset.y),
|
||||
mBitmapBounds[BorderTopRight]);
|
||||
|
||||
RectI destRect;
|
||||
destRect.point.x = offset.x + mBitmapBounds[BorderTopLeft].extent.x;
|
||||
destRect.point.y = offset.y;
|
||||
destRect.extent.x = getWidth() - mBitmapBounds[BorderTopLeft].extent.x - mBitmapBounds[BorderTopRight].extent.x;
|
||||
destRect.extent.y = mBitmapBounds[BorderTop].extent.y;
|
||||
RectI stretchRect = mBitmapBounds[BorderTop];
|
||||
stretchRect.inset(1,0);
|
||||
GFX->getDrawUtil()->drawBitmapStretchSR(mTextureObject, destRect, stretchRect);
|
||||
|
||||
destRect.point.x = offset.x;
|
||||
destRect.point.y = offset.y + mBitmapBounds[BorderTopLeft].extent.y;
|
||||
destRect.extent.x = mBitmapBounds[BorderLeft].extent.x;
|
||||
destRect.extent.y = getHeight() - mBitmapBounds[BorderTopLeft].extent.y - mBitmapBounds[BorderBottomLeft].extent.y;
|
||||
stretchRect = mBitmapBounds[BorderLeft];
|
||||
stretchRect.inset(0,1);
|
||||
GFX->getDrawUtil()->drawBitmapStretchSR(mTextureObject, destRect, stretchRect);
|
||||
|
||||
destRect.point.x = offset.x + getWidth() - mBitmapBounds[BorderRight].extent.x;
|
||||
destRect.extent.x = mBitmapBounds[BorderRight].extent.x;
|
||||
destRect.point.y = offset.y + mBitmapBounds[BorderTopRight].extent.y;
|
||||
destRect.extent.y = getHeight() - mBitmapBounds[BorderTopRight].extent.y - mBitmapBounds[BorderBottomRight].extent.y;
|
||||
|
||||
stretchRect = mBitmapBounds[BorderRight];
|
||||
stretchRect.inset(0,1);
|
||||
GFX->getDrawUtil()->drawBitmapStretchSR(mTextureObject, destRect, stretchRect);
|
||||
|
||||
GFX->getDrawUtil()->drawBitmapSR(mTextureObject, offset + Point2I(0, getHeight() - mBitmapBounds[BorderBottomLeft].extent.y), mBitmapBounds[BorderBottomLeft]);
|
||||
GFX->getDrawUtil()->drawBitmapSR(mTextureObject, offset + getExtent() - mBitmapBounds[BorderBottomRight].extent, mBitmapBounds[BorderBottomRight]);
|
||||
|
||||
destRect.point.x = offset.x + mBitmapBounds[BorderBottomLeft].extent.x;
|
||||
destRect.extent.x = getWidth() - mBitmapBounds[BorderBottomLeft].extent.x - mBitmapBounds[BorderBottomRight].extent.x;
|
||||
|
||||
destRect.point.y = offset.y + getHeight() - mBitmapBounds[BorderBottom].extent.y;
|
||||
destRect.extent.y = mBitmapBounds[BorderBottom].extent.y;
|
||||
stretchRect = mBitmapBounds[BorderBottom];
|
||||
stretchRect.inset(1,0);
|
||||
|
||||
GFX->getDrawUtil()->drawBitmapStretchSR(mTextureObject, destRect, stretchRect);
|
||||
}
|
||||
}
|
||||
266
Engine/source/gui/controls/guiBitmapCtrl.cpp
Normal file
266
Engine/source/gui/controls/guiBitmapCtrl.cpp
Normal file
|
|
@ -0,0 +1,266 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// Copyright (c) 2012 GarageGames, LLC
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to
|
||||
// deal in the Software without restriction, including without limitation the
|
||||
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
// sell copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
// IN THE SOFTWARE.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "platform/platform.h"
|
||||
#include "gui/controls/guiBitmapCtrl.h"
|
||||
|
||||
#include "console/console.h"
|
||||
#include "console/consoleTypes.h"
|
||||
#include "console/engineAPI.h"
|
||||
#include "gfx/gfxDevice.h"
|
||||
#include "gfx/gfxDrawUtil.h"
|
||||
|
||||
|
||||
IMPLEMENT_CONOBJECT(GuiBitmapCtrl);
|
||||
|
||||
ConsoleDocClass( GuiBitmapCtrl,
|
||||
"@brief A gui control that is used to display an image.\n\n"
|
||||
|
||||
"The image is stretched to the constraints of the control by default. However, the control can also\n"
|
||||
"tile the image as well.\n\n"
|
||||
|
||||
"The image itself is stored inside the GuiBitmapCtrl::bitmap field. The boolean value that decides\n"
|
||||
"whether the image is stretched or tiled is stored inside the GuiBitmapCtrl::wrap field.\n"
|
||||
|
||||
"@tsexample\n"
|
||||
"// Create a tiling GuiBitmapCtrl that displays \"myImage.png\"\n"
|
||||
"%bitmapCtrl = new GuiBitmapCtrl()\n"
|
||||
"{\n"
|
||||
" bitmap = \"myImage.png\";\n"
|
||||
" wrap = \"true\";\n"
|
||||
"};\n"
|
||||
"@endtsexample\n\n"
|
||||
|
||||
"@ingroup GuiControls"
|
||||
);
|
||||
|
||||
GuiBitmapCtrl::GuiBitmapCtrl(void)
|
||||
: mBitmapName(),
|
||||
mStartPoint( 0, 0 ),
|
||||
mWrap( false )
|
||||
{
|
||||
}
|
||||
|
||||
bool GuiBitmapCtrl::setBitmapName( void *object, const char *index, const char *data )
|
||||
{
|
||||
// Prior to this, you couldn't do bitmap.bitmap = "foo.jpg" and have it work.
|
||||
// With protected console types you can now call the setBitmap function and
|
||||
// make it load the image.
|
||||
static_cast<GuiBitmapCtrl *>( object )->setBitmap( data );
|
||||
|
||||
// Return false because the setBitmap method will assign 'mBitmapName' to the
|
||||
// argument we are specifying in the call.
|
||||
return false;
|
||||
}
|
||||
|
||||
void GuiBitmapCtrl::initPersistFields()
|
||||
{
|
||||
addGroup( "Bitmap" );
|
||||
|
||||
addProtectedField( "bitmap", TypeImageFilename, Offset( mBitmapName, GuiBitmapCtrl ),
|
||||
&setBitmapName, &defaultProtectedGetFn,
|
||||
"The bitmap file to display in the control." );
|
||||
addField( "wrap", TypeBool, Offset( mWrap, GuiBitmapCtrl ),
|
||||
"If true, the bitmap is tiled inside the control rather than stretched to fit." );
|
||||
|
||||
endGroup( "Bitmap" );
|
||||
|
||||
Parent::initPersistFields();
|
||||
}
|
||||
|
||||
bool GuiBitmapCtrl::onWake()
|
||||
{
|
||||
if (! Parent::onWake())
|
||||
return false;
|
||||
setActive(true);
|
||||
setBitmap(mBitmapName);
|
||||
return true;
|
||||
}
|
||||
|
||||
void GuiBitmapCtrl::onSleep()
|
||||
{
|
||||
if ( !mBitmapName.equal("texhandle", String::NoCase) )
|
||||
mTextureObject = NULL;
|
||||
|
||||
Parent::onSleep();
|
||||
}
|
||||
|
||||
//-------------------------------------
|
||||
void GuiBitmapCtrl::inspectPostApply()
|
||||
{
|
||||
// if the extent is set to (0,0) in the gui editor and appy hit, this control will
|
||||
// set it's extent to be exactly the size of the bitmap (if present)
|
||||
Parent::inspectPostApply();
|
||||
|
||||
if (!mWrap && (getExtent().x == 0) && (getExtent().y == 0) && mTextureObject)
|
||||
{
|
||||
setExtent( mTextureObject->getWidth(), mTextureObject->getHeight());
|
||||
}
|
||||
}
|
||||
|
||||
void GuiBitmapCtrl::setBitmap( const char *name, bool resize )
|
||||
{
|
||||
mBitmapName = name;
|
||||
if ( !isAwake() )
|
||||
return;
|
||||
|
||||
if ( mBitmapName.isNotEmpty() )
|
||||
{
|
||||
if ( !mBitmapName.equal("texhandle", String::NoCase) )
|
||||
mTextureObject.set( mBitmapName, &GFXDefaultGUIProfile, avar("%s() - mTextureObject (line %d)", __FUNCTION__, __LINE__) );
|
||||
|
||||
// Resize the control to fit the bitmap
|
||||
if ( mTextureObject && resize )
|
||||
{
|
||||
setExtent( mTextureObject->getWidth(), mTextureObject->getHeight() );
|
||||
updateSizing();
|
||||
}
|
||||
}
|
||||
else
|
||||
mTextureObject = NULL;
|
||||
|
||||
setUpdate();
|
||||
}
|
||||
|
||||
void GuiBitmapCtrl::updateSizing()
|
||||
{
|
||||
if(!getParent())
|
||||
return;
|
||||
// updates our bounds according to our horizSizing and verSizing rules
|
||||
RectI fakeBounds( getPosition(), getParent()->getExtent());
|
||||
parentResized( fakeBounds, fakeBounds);
|
||||
}
|
||||
|
||||
void GuiBitmapCtrl::setBitmapHandle(GFXTexHandle handle, bool resize)
|
||||
{
|
||||
mTextureObject = handle;
|
||||
|
||||
mBitmapName = String("texhandle");
|
||||
|
||||
// Resize the control to fit the bitmap
|
||||
if (resize)
|
||||
{
|
||||
setExtent(mTextureObject->getWidth(), mTextureObject->getHeight());
|
||||
updateSizing();
|
||||
}
|
||||
}
|
||||
|
||||
void GuiBitmapCtrl::onRender(Point2I offset, const RectI &updateRect)
|
||||
{
|
||||
if (mTextureObject)
|
||||
{
|
||||
GFX->getDrawUtil()->clearBitmapModulation();
|
||||
if(mWrap)
|
||||
{
|
||||
// We manually draw each repeat because non power of two textures will
|
||||
// not tile correctly when rendered with GFX->drawBitmapTile(). The non POT
|
||||
// bitmap will be padded by the hardware, and we'll see lots of slack
|
||||
// in the texture. So... lets do what we must: draw each repeat by itself:
|
||||
GFXTextureObject* texture = mTextureObject;
|
||||
RectI srcRegion;
|
||||
RectI dstRegion;
|
||||
float xdone = ((float)getExtent().x/(float)texture->mBitmapSize.x)+1;
|
||||
float ydone = ((float)getExtent().y/(float)texture->mBitmapSize.y)+1;
|
||||
|
||||
int xshift = mStartPoint.x%texture->mBitmapSize.x;
|
||||
int yshift = mStartPoint.y%texture->mBitmapSize.y;
|
||||
for(int y = 0; y < ydone; ++y)
|
||||
for(int x = 0; x < xdone; ++x)
|
||||
{
|
||||
srcRegion.set(0,0,texture->mBitmapSize.x,texture->mBitmapSize.y);
|
||||
dstRegion.set( ((texture->mBitmapSize.x*x)+offset.x)-xshift,
|
||||
((texture->mBitmapSize.y*y)+offset.y)-yshift,
|
||||
texture->mBitmapSize.x,
|
||||
texture->mBitmapSize.y);
|
||||
GFX->getDrawUtil()->drawBitmapStretchSR(texture,dstRegion, srcRegion, GFXBitmapFlip_None, GFXTextureFilterLinear);
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
RectI rect(offset, getExtent());
|
||||
GFX->getDrawUtil()->drawBitmapStretch(mTextureObject, rect, GFXBitmapFlip_None, GFXTextureFilterLinear, false);
|
||||
}
|
||||
}
|
||||
|
||||
if (mProfile->mBorder || !mTextureObject)
|
||||
{
|
||||
RectI rect(offset.x, offset.y, getExtent().x, getExtent().y);
|
||||
GFX->getDrawUtil()->drawRect(rect, mProfile->mBorderColor);
|
||||
}
|
||||
|
||||
renderChildControls(offset, updateRect);
|
||||
}
|
||||
|
||||
void GuiBitmapCtrl::setValue(S32 x, S32 y)
|
||||
{
|
||||
if (mTextureObject)
|
||||
{
|
||||
x += mTextureObject->getWidth() / 2;
|
||||
y += mTextureObject->getHeight() / 2;
|
||||
}
|
||||
while (x < 0)
|
||||
x += 256;
|
||||
mStartPoint.x = x % 256;
|
||||
|
||||
while (y < 0)
|
||||
y += 256;
|
||||
mStartPoint.y = y % 256;
|
||||
}
|
||||
|
||||
DefineEngineMethod( GuiBitmapCtrl, setValue, void, ( S32 x, S32 y ),,
|
||||
"Set the offset of the bitmap within the control.\n"
|
||||
"@param x The x-axis offset of the image.\n"
|
||||
"@param y The y-axis offset of the image.\n")
|
||||
{
|
||||
object->setValue(x, y);
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
|
||||
static ConsoleDocFragment _sGuiBitmapCtrlSetBitmap1(
|
||||
"@brief Assign an image to the control.\n\n"
|
||||
"Child controls with resize according to their layout settings.\n"
|
||||
"@param filename The filename of the image.\n"
|
||||
"@param resize Optional parameter. If true, the GUI will resize to fit the image.",
|
||||
"GuiBitmapCtrl", // The class to place the method in; use NULL for functions.
|
||||
"void setBitmap( String filename, bool resize );" ); // The definition string.
|
||||
|
||||
static ConsoleDocFragment _sGuiBitmapCtrlSetBitmap2(
|
||||
"@brief Assign an image to the control.\n\n"
|
||||
"Child controls will resize according to their layout settings.\n"
|
||||
"@param filename The filename of the image.\n"
|
||||
"@param resize A boolean value that decides whether the ctrl refreshes or not.",
|
||||
"GuiBitmapCtrl", // The class to place the method in; use NULL for functions.
|
||||
"void setBitmap( String filename );" ); // The definition string.
|
||||
|
||||
|
||||
//"Set the bitmap displayed in the control. Note that it is limited in size, to 256x256."
|
||||
ConsoleMethod( GuiBitmapCtrl, setBitmap, void, 3, 4,
|
||||
"( String filename | String filename, bool resize ) Assign an image to the control.\n\n"
|
||||
"@hide" )
|
||||
{
|
||||
char filename[1024];
|
||||
Con::expandScriptFilename(filename, sizeof(filename), argv[2]);
|
||||
object->setBitmap(filename, argc > 3 ? dAtob( argv[3] ) : false );
|
||||
}
|
||||
78
Engine/source/gui/controls/guiBitmapCtrl.h
Normal file
78
Engine/source/gui/controls/guiBitmapCtrl.h
Normal file
|
|
@ -0,0 +1,78 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// Copyright (c) 2012 GarageGames, LLC
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to
|
||||
// deal in the Software without restriction, including without limitation the
|
||||
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
// sell copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
// IN THE SOFTWARE.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef _GUIBITMAPCTRL_H_
|
||||
#define _GUIBITMAPCTRL_H_
|
||||
|
||||
#ifndef _GUICONTROL_H_
|
||||
#include "gui/core/guiControl.h"
|
||||
#endif
|
||||
|
||||
/// Renders a bitmap.
|
||||
class GuiBitmapCtrl : public GuiControl
|
||||
{
|
||||
public:
|
||||
|
||||
typedef GuiControl Parent;
|
||||
|
||||
protected:
|
||||
|
||||
/// Name of the bitmap file. If this is 'texhandle' the bitmap is not loaded
|
||||
/// from a file but rather set explicitly on the control.
|
||||
String mBitmapName;
|
||||
|
||||
/// Loaded texture.
|
||||
GFXTexHandle mTextureObject;
|
||||
|
||||
Point2I mStartPoint;
|
||||
|
||||
/// If true, bitmap tiles inside control. Otherwise stretches.
|
||||
bool mWrap;
|
||||
|
||||
static bool setBitmapName( void *object, const char *index, const char *data );
|
||||
static const char *getBitmapName( void *obj, const char *data );
|
||||
|
||||
public:
|
||||
|
||||
GuiBitmapCtrl();
|
||||
static void initPersistFields();
|
||||
|
||||
void setBitmap(const char *name,bool resize = false);
|
||||
void setBitmapHandle(GFXTexHandle handle, bool resize = false);
|
||||
|
||||
// GuiControl.
|
||||
bool onWake();
|
||||
void onSleep();
|
||||
void inspectPostApply();
|
||||
|
||||
void updateSizing();
|
||||
|
||||
void onRender(Point2I offset, const RectI &updateRect);
|
||||
void setValue(S32 x, S32 y);
|
||||
|
||||
DECLARE_CONOBJECT( GuiBitmapCtrl );
|
||||
DECLARE_CATEGORY( "Gui Images" );
|
||||
DECLARE_DESCRIPTION( "A control that displays a single, static image from a file.\n"
|
||||
"The bitmap can either be tiled or stretched inside the control." );
|
||||
};
|
||||
|
||||
#endif
|
||||
548
Engine/source/gui/controls/guiColorPicker.cpp
Normal file
548
Engine/source/gui/controls/guiColorPicker.cpp
Normal file
|
|
@ -0,0 +1,548 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// Copyright (c) 2012 GarageGames, LLC
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to
|
||||
// deal in the Software without restriction, including without limitation the
|
||||
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
// sell copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
// IN THE SOFTWARE.
|
||||
//-----------------------------------------------------------------------------
|
||||
#include "console/console.h"
|
||||
#include "gfx/gfxDevice.h"
|
||||
#include "console/consoleTypes.h"
|
||||
#include "gui/core/guiCanvas.h"
|
||||
#include "gui/buttons/guiButtonCtrl.h"
|
||||
#include "gui/core/guiDefaultControlRender.h"
|
||||
#include "gui/controls/guiColorPicker.h"
|
||||
#include "gfx/primBuilder.h"
|
||||
#include "gfx/gfxDrawUtil.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);
|
||||
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
|
||||
};
|
||||
/// @}
|
||||
|
||||
IMPLEMENT_CONOBJECT(GuiColorPickerCtrl);
|
||||
|
||||
ConsoleDocClass( GuiColorPickerCtrl,
|
||||
"@brief Editor GUI used for picking a ColorF from a palette.\n\n"
|
||||
"@note Editor use only.\n\n"
|
||||
"@internal"
|
||||
);
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
GuiColorPickerCtrl::GuiColorPickerCtrl()
|
||||
{
|
||||
setExtent(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;
|
||||
mShowReticle = true;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
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" },
|
||||
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)
|
||||
{
|
||||
GFX->setStateBlock(mStateBlock);
|
||||
|
||||
S32 l = bounds.point.x, r = bounds.point.x + bounds.extent.x;
|
||||
S32 t = bounds.point.y, b = bounds.point.y + bounds.extent.y;
|
||||
|
||||
//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 );
|
||||
|
||||
PrimBuild::color( c2 );
|
||||
PrimBuild::vertex2i( r, b );
|
||||
|
||||
PrimBuild::color( c2 );
|
||||
PrimBuild::vertex2i( l, b );
|
||||
|
||||
PrimBuild::color( c2 );
|
||||
PrimBuild::vertex2i( l, t );
|
||||
PrimBuild::end();
|
||||
|
||||
//White
|
||||
PrimBuild::begin( GFXTriangleFan, 4 );
|
||||
PrimBuild::color( colorAlphaW );
|
||||
PrimBuild::vertex2i( r, t );
|
||||
|
||||
PrimBuild::color( colorAlphaW );
|
||||
PrimBuild::vertex2i( r, b );
|
||||
|
||||
PrimBuild::color( c1 );
|
||||
PrimBuild::vertex2i( l, b );
|
||||
|
||||
PrimBuild::color( c1 );
|
||||
PrimBuild::vertex2i( l, t );
|
||||
PrimBuild::end();
|
||||
|
||||
//Black
|
||||
PrimBuild::begin( GFXTriangleFan, 4 );
|
||||
PrimBuild::color( c3 );
|
||||
PrimBuild::vertex2i( r, t );
|
||||
|
||||
PrimBuild::color( c4 );
|
||||
PrimBuild::vertex2i( r, b );
|
||||
|
||||
PrimBuild::color( c4 );
|
||||
PrimBuild::vertex2i( l, b );
|
||||
|
||||
PrimBuild::color( c3 );
|
||||
PrimBuild::vertex2i( l, t );
|
||||
PrimBuild::end();
|
||||
}
|
||||
else
|
||||
{
|
||||
PrimBuild::begin( GFXTriangleFan, 4 );
|
||||
PrimBuild::color( c1 );
|
||||
PrimBuild::vertex2i( l, t );
|
||||
|
||||
PrimBuild::color( c2 );
|
||||
PrimBuild::vertex2i( r, t );
|
||||
|
||||
PrimBuild::color( c3 );
|
||||
PrimBuild::vertex2i( r, b );
|
||||
|
||||
PrimBuild::color( c4 );
|
||||
PrimBuild::vertex2i( l, b );
|
||||
PrimBuild::end();
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
/// Function to draw a set of boxes blending throughout an array of colors
|
||||
void GuiColorPickerCtrl::drawBlendRangeBox(RectI &bounds, bool vertical, U8 numColors, ColorI *colors)
|
||||
{
|
||||
|
||||
GFX->setStateBlock(mStateBlock);
|
||||
|
||||
S32 l = bounds.point.x, r = bounds.point.x + bounds.extent.x + 4;
|
||||
S32 t = bounds.point.y, b = bounds.point.y + bounds.extent.y + 4;
|
||||
|
||||
// Calculate increment value
|
||||
S32 x_inc = int(mFloor((r - l) / F32(numColors-1)));
|
||||
S32 y_inc = int(mFloor((b - t) / F32(numColors-1)));
|
||||
|
||||
for( U16 i = 0;i < numColors - 1; i++ )
|
||||
{
|
||||
// This is not efficent, but then again it doesn't really need to be. -pw
|
||||
PrimBuild::begin( GFXTriangleFan, 4 );
|
||||
|
||||
if (!vertical) // Horizontal (+x)
|
||||
{
|
||||
// First color
|
||||
PrimBuild::color( colors[i] );
|
||||
PrimBuild::vertex2i( l, t );
|
||||
PrimBuild::vertex2i( l, b );
|
||||
|
||||
// Second color
|
||||
PrimBuild::color( colors[i+1] );
|
||||
PrimBuild::vertex2i( l + x_inc, b );
|
||||
PrimBuild::vertex2i( l + x_inc, t );
|
||||
l += x_inc;
|
||||
}
|
||||
else // Vertical (+y)
|
||||
{
|
||||
// First color
|
||||
PrimBuild::color( colors[i] );
|
||||
PrimBuild::vertex2i( l, t );
|
||||
PrimBuild::vertex2i( r, t );
|
||||
|
||||
// Second color
|
||||
PrimBuild::color( colors[i+1] );
|
||||
PrimBuild::vertex2i( r, t + y_inc );
|
||||
PrimBuild::vertex2i( l, t + y_inc );
|
||||
t += y_inc;
|
||||
}
|
||||
PrimBuild::end();
|
||||
}
|
||||
}
|
||||
|
||||
void GuiColorPickerCtrl::drawSelector(RectI &bounds, Point2I &selectorPos, SelectorMode mode)
|
||||
{
|
||||
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)
|
||||
GFX->getDrawUtil()->drawLine(bounds.point.x, selectorPos.y-1, selectorPos.x-sMax, selectorPos.y-1, colorWhiteBlend);
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
/// 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)
|
||||
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
|
||||
RectI blendRect;
|
||||
switch (mDisplayMode)
|
||||
{
|
||||
case pHorizColorRange:
|
||||
drawBlendRangeBox( pickerBounds, false, 7, mColorRange);
|
||||
drawSelector( pickerBounds, selectorPos, sVertical );
|
||||
break;
|
||||
case pVertColorRange:
|
||||
drawBlendRangeBox( pickerBounds, true, 7, mColorRange);
|
||||
drawSelector( pickerBounds, selectorPos, sHorizontal );
|
||||
break;
|
||||
case pHorizColorBrightnessRange:
|
||||
blendRect = pickerBounds;
|
||||
blendRect.point.y++;
|
||||
blendRect.extent.y -= 2;
|
||||
drawBlendRangeBox( pickerBounds, false, 7, 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.
|
||||
drawBlendBox( blendRect, colorAlpha, colorAlpha, colorBlack, colorBlack );
|
||||
blendRect.point.y += blendRect.extent.y - 1;
|
||||
blendRect.extent.y = 2;
|
||||
GFX->getDrawUtil()->drawRect( blendRect, colorBlack);
|
||||
drawSelector( pickerBounds, selectorPos, sHorizontal );
|
||||
drawSelector( pickerBounds, selectorPos, sVertical );
|
||||
break;
|
||||
case pVertColorBrightnessRange:
|
||||
drawBlendRangeBox( pickerBounds, true, 7, mColorRange);
|
||||
drawBlendBox( pickerBounds, colorAlpha, colorBlack, colorBlack, colorAlpha );
|
||||
drawSelector( pickerBounds, selectorPos, sHorizontal );
|
||||
drawSelector( pickerBounds, selectorPos, sVertical );
|
||||
break;
|
||||
case pHorizAlphaRange:
|
||||
drawBlendBox( pickerBounds, colorBlack, colorWhite, colorWhite, colorBlack );
|
||||
drawSelector( pickerBounds, selectorPos, sVertical );
|
||||
break;
|
||||
case pVertAlphaRange:
|
||||
drawBlendBox( pickerBounds, colorBlack, colorBlack, colorWhite, colorWhite );
|
||||
drawSelector( pickerBounds, selectorPos, sHorizontal );
|
||||
break;
|
||||
case pBlendColorRange:
|
||||
drawBlendBox( pickerBounds, colorWhite, mBaseColor, colorAlpha, colorBlack );
|
||||
drawSelector( pickerBounds, selectorPos, sHorizontal );
|
||||
drawSelector( pickerBounds, selectorPos, sVertical );
|
||||
break;
|
||||
case pDropperBackground:
|
||||
break;
|
||||
case pPallet:
|
||||
default:
|
||||
GFX->getDrawUtil()->drawRectFill( pickerBounds, mBaseColor );
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
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 );
|
||||
}
|
||||
|
||||
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();
|
||||
|
||||
U32 buf_x = offset.x + mSelectorPos.x + 1;
|
||||
U32 buf_y = ( extent.y - ( offset.y + mSelectorPos.y + 1 ) );
|
||||
if(GFX->getAdapterType() != OpenGL)
|
||||
buf_y = resolution.y - 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() );
|
||||
|
||||
bb.copyToBmp( &bmp );
|
||||
|
||||
//bmp.writePNGDebug( "foo.png" );
|
||||
|
||||
ColorI tmp;
|
||||
bmp.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 Point2I &pos)
|
||||
{
|
||||
Point2I extent = getExtent();
|
||||
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();
|
||||
|
||||
if (mActive && (mDisplayMode != pDropperBackground))
|
||||
onAction();
|
||||
|
||||
// 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 )
|
||||
execAltConsoleCallback();
|
||||
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
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))
|
||||
mMouseDown = false;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
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();
|
||||
}
|
||||
152
Engine/source/gui/controls/guiColorPicker.h
Normal file
152
Engine/source/gui/controls/guiColorPicker.h
Normal file
|
|
@ -0,0 +1,152 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// Copyright (c) 2012 GarageGames, LLC
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to
|
||||
// deal in the Software without restriction, including without limitation the
|
||||
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
// sell copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
// IN THE SOFTWARE.
|
||||
//-----------------------------------------------------------------------------
|
||||
#ifndef _GUICOLORPICKER_H_
|
||||
#define _GUICOLORPICKER_H_
|
||||
|
||||
#ifndef _GUICONTROL_H_
|
||||
#include "gui/core/guiControl.h"
|
||||
#endif
|
||||
|
||||
//----------------------------
|
||||
/// GuiColorPickerCtrl
|
||||
///
|
||||
/// This control draws a box containing a color specified by mPickColor,
|
||||
/// in a way according to one of the PickMode enum's, stored as mDisplayMode.
|
||||
///
|
||||
/// The color the box represents is stored as mBaseColour (for pPallete, pBlendColorRange),
|
||||
/// whilst the color chosen by the box is stored as mPickColor.
|
||||
///
|
||||
/// Whenever the control is clicked, it will do one of many things :
|
||||
///
|
||||
/// -# If its in pPallete mode, execute the regular "command"
|
||||
/// -# If its in pBlendColorRange mode, update the selector position. The position will be re-read upon the next render. In addition, a cross will be drawn where the color has been selected from. As with 1, "command" will be executed.
|
||||
/// -# If its in pHorizColorRange or pVertColorRange mode, it will function in a similar manner to 2, but the selector will resemble a horizontal or vertical bar.
|
||||
/// -# If its in pHorizAlphaRange or pVertAlphaRange mode, it will also function the same way as 3
|
||||
/// -# If its in pDropperBackground mode, nothing will happen
|
||||
///
|
||||
/// Colours are drawn in different ways according to mDisplayMode:
|
||||
///
|
||||
/// -# With pPallete, a box with a blank color, mBaseColor is drawn.
|
||||
/// -# With pHorizColorRange, a horizontal box with colors blending in the range, mColorRange.
|
||||
/// -# With pVertColorRange, a vertical box with colors blending in the range, mColorRange.
|
||||
/// -# With pBlendColorRange, a box, the bottom colors being black, but the top left being white, and the top right being mBaseColor.
|
||||
/// -# With pHorizAlphaRange, a horizontal box with black blending with an alpha from 0 to 255
|
||||
/// -# With pVertAlphaRange, a vertical box with black blending with an apha from 0 to 255
|
||||
/// -# With pDropperBackground, nothing is drawn
|
||||
class GuiColorPickerCtrl : public GuiControl
|
||||
{
|
||||
typedef GuiControl Parent;
|
||||
|
||||
public:
|
||||
enum PickMode
|
||||
{
|
||||
pPallet = 0, ///< We just have a solid color; We just act like a pallet
|
||||
pHorizColorRange, ///< We have a range of base colors going horizontally
|
||||
pVertColorRange, ///< We have a range of base colors going vertically
|
||||
pHorizColorBrightnessRange, ///< HorizColorRange with brightness
|
||||
pVertColorBrightnessRange, ///< VertColorRange with brightness
|
||||
pBlendColorRange, ///< We have a box which shows a range in brightness of the color
|
||||
pHorizAlphaRange, ///< We have a box which shows a range in alpha going horizontally
|
||||
pVertAlphaRange, ///< We have a box which shows a range in alpha going vertically
|
||||
pDropperBackground ///< The control does not draw anything; Only does something when you click, or move the mouse (when active)
|
||||
};
|
||||
|
||||
enum SelectorMode
|
||||
{
|
||||
sHorizontal = 0, ///< Horizontal selector with small gap
|
||||
sVertical, ///< Vertical selector with small gap
|
||||
};
|
||||
|
||||
protected:
|
||||
|
||||
/// @name Core Rendering functions
|
||||
/// @{
|
||||
void renderColorBox(RectI &bounds); ///< Function that draws the actual color box
|
||||
void drawSelector(RectI &bounds, Point2I &selectorPos, SelectorMode mode); ///< Function that draws the selection indicator
|
||||
void drawBlendBox(RectI &bounds, ColorF &c1, ColorF &c2, ColorF &c3, ColorF &c4);
|
||||
void drawBlendRangeBox(RectI &bounds, bool vertical, U8 numColors, ColorI *colors);
|
||||
/// @}
|
||||
|
||||
/// @name Core Variables
|
||||
/// @{
|
||||
ColorF mPickColor; ///< Color that has been picked from control
|
||||
ColorF mBaseColor; ///< Colour we display (in case of pallet and blend mode)
|
||||
PickMode mDisplayMode; ///< Current color display mode of the selector
|
||||
|
||||
Point2I mSelectorPos; ///< Current position of the selector
|
||||
bool mPositionChanged; ///< Current position has changed since last render?
|
||||
bool mMouseOver; ///< Mouse is over?
|
||||
bool mMouseDown; ///< Mouse button down?
|
||||
bool mActionOnMove; ///< Perform onAction() when position has changed?
|
||||
|
||||
|
||||
|
||||
S32 mSelectorGap; ///< The half-way "gap" between the selector pos and where the selector is allowed to draw.
|
||||
|
||||
GFXStateBlockRef mStateBlock;
|
||||
|
||||
static ColorI mColorRange[7]; ///< Color range for pHorizColorRange and pVertColorRange
|
||||
/// @}
|
||||
|
||||
public:
|
||||
|
||||
DECLARE_CONOBJECT(GuiColorPickerCtrl);
|
||||
DECLARE_CATEGORY( "Gui Editor" );
|
||||
|
||||
GuiColorPickerCtrl();
|
||||
|
||||
static void initPersistFields();
|
||||
void onRender(Point2I offset, const RectI &updateRect);
|
||||
bool mShowReticle; ///< Show reticle on render
|
||||
/// @name Color Value Functions
|
||||
/// @{
|
||||
/// NOTE: setValue only sets baseColor, since setting pickColor wouldn't be useful
|
||||
void setValue(ColorF &value) {mBaseColor = value;}
|
||||
/// NOTE: getValue() returns baseColor if pallet (since pallet controls can't "pick" colours themselves)
|
||||
ColorF getValue() {return mDisplayMode == pPallet ? mBaseColor : mPickColor;}
|
||||
const char *getScriptValue();
|
||||
void setScriptValue(const char *value);
|
||||
void updateColor() {mPositionChanged = true;}
|
||||
/// @}
|
||||
|
||||
/// @name Selector Functions
|
||||
/// @{
|
||||
void setSelectorPos(const Point2I &pos); ///< Set new pos (in local coords)
|
||||
Point2I getSelectorPos() {return mSelectorPos;}
|
||||
/// @}
|
||||
|
||||
/// @name Input Events
|
||||
/// @{
|
||||
void onMouseDown(const GuiEvent &);
|
||||
void onMouseUp(const GuiEvent &);
|
||||
void onMouseMove(const GuiEvent &event);
|
||||
void onMouseDragged(const GuiEvent &event);
|
||||
|
||||
void onMouseEnter(const GuiEvent &);
|
||||
void onMouseLeave(const GuiEvent &);
|
||||
/// @}
|
||||
};
|
||||
|
||||
typedef GuiColorPickerCtrl::PickMode GuiColorPickMode;
|
||||
DefineEnumType( GuiColorPickMode );
|
||||
|
||||
#endif
|
||||
173
Engine/source/gui/controls/guiConsole.cpp
Normal file
173
Engine/source/gui/controls/guiConsole.cpp
Normal file
|
|
@ -0,0 +1,173 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// Copyright (c) 2012 GarageGames, LLC
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to
|
||||
// deal in the Software without restriction, including without limitation the
|
||||
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
// sell copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
// IN THE SOFTWARE.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "console/console.h"
|
||||
#include "gfx/gfxDrawUtil.h"
|
||||
#include "gui/core/guiTypes.h"
|
||||
#include "gui/core/guiControl.h"
|
||||
#include "gui/controls/guiConsole.h"
|
||||
#include "gui/containers/guiScrollCtrl.h"
|
||||
#include "console/engineAPI.h"
|
||||
|
||||
IMPLEMENT_CONOBJECT(GuiConsole);
|
||||
|
||||
ConsoleDocClass( GuiConsole,
|
||||
"@brief The on-screen, in-game console. Calls getLog() to get the on-screen console entries, then renders them as needed.\n\n"
|
||||
|
||||
"@tsexample\n"
|
||||
" new GuiConsole()\n"
|
||||
" {\n"
|
||||
" //Properties not specific to this control have been omitted from this example.\n"
|
||||
" };\n"
|
||||
"@endtsexample\n\n"
|
||||
|
||||
"@see GuiControl\n\n"
|
||||
|
||||
"@ingroup GuiCore"
|
||||
);
|
||||
|
||||
IMPLEMENT_CALLBACK( GuiConsole, onMessageSelected, void, ( ConsoleLogEntry::Level level, const char* message ), ( level, message ),
|
||||
"Called when a message in the log is clicked.\n\n"
|
||||
"@param level Diagnostic level of the message.\n"
|
||||
"@param message Message text.\n" );
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
GuiConsole::GuiConsole()
|
||||
{
|
||||
setExtent(64, 64);
|
||||
mCellSize.set(1, 1);
|
||||
mSize.set(1, 0);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
bool GuiConsole::onWake()
|
||||
{
|
||||
if (! Parent::onWake())
|
||||
return false;
|
||||
|
||||
//get the font
|
||||
mFont = mProfile->mFont;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
S32 GuiConsole::getMaxWidth(S32 startIndex, S32 endIndex)
|
||||
{
|
||||
//sanity check
|
||||
U32 size;
|
||||
ConsoleLogEntry *log;
|
||||
|
||||
Con::getLockLog(log, size);
|
||||
|
||||
if(startIndex < 0 || (U32)endIndex >= size || startIndex > endIndex)
|
||||
return 0;
|
||||
|
||||
S32 result = 0;
|
||||
for(S32 i = startIndex; i <= endIndex; i++)
|
||||
result = getMax(result, (S32)(mFont->getStrWidth((const UTF8 *)log[i].mString)));
|
||||
|
||||
Con::unlockLog();
|
||||
|
||||
return(result + 6);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void GuiConsole::onPreRender()
|
||||
{
|
||||
//see if the size has changed
|
||||
U32 prevSize = getHeight() / mCellSize.y;
|
||||
U32 size;
|
||||
ConsoleLogEntry *log;
|
||||
|
||||
Con::getLockLog(log, size);
|
||||
Con::unlockLog(); // we unlock immediately because we only use size here, not log.
|
||||
|
||||
if(size != prevSize)
|
||||
{
|
||||
//first, find out if the console was scrolled up
|
||||
bool scrolled = false;
|
||||
GuiScrollCtrl *parent = dynamic_cast<GuiScrollCtrl*>(getParent());
|
||||
|
||||
if(parent)
|
||||
scrolled = parent->isScrolledToBottom();
|
||||
|
||||
//find the max cell width for the new entries
|
||||
S32 newMax = getMaxWidth(prevSize, size - 1);
|
||||
if(newMax > mCellSize.x)
|
||||
mCellSize.set(newMax, mFont->getHeight());
|
||||
|
||||
//set the array size
|
||||
mSize.set(1, size);
|
||||
|
||||
//resize the control
|
||||
setExtent( Point2I(mCellSize.x, mCellSize.y * size));
|
||||
|
||||
//if the console was not scrolled, make the last entry visible
|
||||
if (scrolled)
|
||||
scrollCellVisible(Point2I(0,mSize.y - 1));
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void GuiConsole::onRenderCell(Point2I offset, Point2I cell, bool /*selected*/, bool /*mouseOver*/)
|
||||
{
|
||||
U32 size;
|
||||
ConsoleLogEntry *log;
|
||||
|
||||
Con::getLockLog(log, size);
|
||||
|
||||
ConsoleLogEntry &entry = log[cell.y];
|
||||
switch (entry.mLevel)
|
||||
{
|
||||
case ConsoleLogEntry::Normal: GFX->getDrawUtil()->setBitmapModulation(mProfile->mFontColor); break;
|
||||
case ConsoleLogEntry::Warning: GFX->getDrawUtil()->setBitmapModulation(mProfile->mFontColorHL); break;
|
||||
case ConsoleLogEntry::Error: GFX->getDrawUtil()->setBitmapModulation(mProfile->mFontColorNA); break;
|
||||
default: AssertFatal(false, "GuiConsole::onRenderCell - Unrecognized ConsoleLogEntry type, update this.");
|
||||
}
|
||||
GFX->getDrawUtil()->drawText(mFont, Point2I(offset.x + 3, offset.y), entry.mString, mProfile->mFontColors);
|
||||
|
||||
Con::unlockLog();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void GuiConsole::onCellSelected( Point2I cell )
|
||||
{
|
||||
Parent::onCellSelected( cell );
|
||||
|
||||
U32 size;
|
||||
ConsoleLogEntry* log;
|
||||
|
||||
Con::getLockLog(log, size);
|
||||
|
||||
ConsoleLogEntry& entry = log[ cell.y ];
|
||||
onMessageSelected_callback( entry.mLevel, entry.mString );
|
||||
|
||||
Con::unlockLog();
|
||||
}
|
||||
68
Engine/source/gui/controls/guiConsole.h
Normal file
68
Engine/source/gui/controls/guiConsole.h
Normal file
|
|
@ -0,0 +1,68 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// Copyright (c) 2012 GarageGames, LLC
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to
|
||||
// deal in the Software without restriction, including without limitation the
|
||||
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
// sell copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
// IN THE SOFTWARE.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef _GUICONSOLE_H_
|
||||
#define _GUICONSOLE_H_
|
||||
|
||||
#ifndef _GUIARRAYCTRL_H_
|
||||
#include "gui/core/guiArrayCtrl.h"
|
||||
#endif
|
||||
|
||||
#ifndef _CONSOLE_LOGGER_H_
|
||||
#include "console/consoleLogger.h"
|
||||
#endif
|
||||
|
||||
|
||||
class GuiConsole : public GuiArrayCtrl
|
||||
{
|
||||
private:
|
||||
typedef GuiArrayCtrl Parent;
|
||||
|
||||
Resource<GFont> mFont;
|
||||
|
||||
S32 getMaxWidth(S32 startIndex, S32 endIndex);
|
||||
|
||||
protected:
|
||||
|
||||
/// @name Callbacks
|
||||
/// @{
|
||||
|
||||
DECLARE_CALLBACK( void, onMessageSelected, ( ConsoleLogEntry::Level level, const char* message ) );
|
||||
|
||||
/// @}
|
||||
|
||||
// GuiArrayCtrl.
|
||||
virtual void onCellSelected( Point2I cell );
|
||||
|
||||
public:
|
||||
GuiConsole();
|
||||
DECLARE_CONOBJECT(GuiConsole);
|
||||
DECLARE_CATEGORY( "Gui Editor" );
|
||||
DECLARE_DESCRIPTION( "Control that displays the console log text." );
|
||||
|
||||
// GuiArrayCtrl.
|
||||
virtual bool onWake();
|
||||
virtual void onPreRender();
|
||||
virtual void onRenderCell(Point2I offset, Point2I cell, bool selected, bool mouseOver);
|
||||
};
|
||||
|
||||
#endif
|
||||
145
Engine/source/gui/controls/guiConsoleEditCtrl.cpp
Normal file
145
Engine/source/gui/controls/guiConsoleEditCtrl.cpp
Normal file
|
|
@ -0,0 +1,145 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// Copyright (c) 2012 GarageGames, LLC
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to
|
||||
// deal in the Software without restriction, including without limitation the
|
||||
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
// sell copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
// IN THE SOFTWARE.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "console/consoleTypes.h"
|
||||
#include "console/console.h"
|
||||
#include "gui/core/guiCanvas.h"
|
||||
#include "gui/controls/guiConsoleEditCtrl.h"
|
||||
#include "core/frameAllocator.h"
|
||||
|
||||
IMPLEMENT_CONOBJECT(GuiConsoleEditCtrl);
|
||||
|
||||
ConsoleDocClass( GuiConsoleEditCtrl,
|
||||
"@brief Text entry element of a GuiConsole.\n\n"
|
||||
"@tsexample\n"
|
||||
"new GuiConsoleEditCtrl(ConsoleEntry)\n"
|
||||
"{\n"
|
||||
" profile = \"ConsoleTextEditProfile\";\n"
|
||||
" horizSizing = \"width\";\n"
|
||||
" vertSizing = \"top\";\n"
|
||||
" position = \"0 462\";\n"
|
||||
" extent = \"640 18\";\n"
|
||||
" minExtent = \"8 8\";\n"
|
||||
" visible = \"1\";\n"
|
||||
" altCommand = \"ConsoleEntry::eval();\";\n"
|
||||
" helpTag = \"0\";\n"
|
||||
" maxLength = \"255\";\n"
|
||||
" historySize = \"40\";\n"
|
||||
" password = \"0\";\n"
|
||||
" tabComplete = \"0\";\n"
|
||||
" sinkAllKeyEvents = \"1\";\n"
|
||||
" useSiblingScroller = \"1\";\n"
|
||||
"};\n"
|
||||
"@endtsexample\n\n"
|
||||
"@ingroup GuiCore"
|
||||
);
|
||||
|
||||
GuiConsoleEditCtrl::GuiConsoleEditCtrl()
|
||||
{
|
||||
mSinkAllKeyEvents = true;
|
||||
mSiblingScroller = NULL;
|
||||
mUseSiblingScroller = true;
|
||||
}
|
||||
|
||||
void GuiConsoleEditCtrl::initPersistFields()
|
||||
{
|
||||
addGroup("GuiConsoleEditCtrl");
|
||||
addField("useSiblingScroller", TypeBool, Offset(mUseSiblingScroller, GuiConsoleEditCtrl));
|
||||
endGroup("GuiConsoleEditCtrl");
|
||||
|
||||
Parent::initPersistFields();
|
||||
}
|
||||
|
||||
bool GuiConsoleEditCtrl::onKeyDown(const GuiEvent &event)
|
||||
{
|
||||
setUpdate();
|
||||
|
||||
if (event.keyCode == KEY_TAB)
|
||||
{
|
||||
// Get a buffer that can hold the completed text...
|
||||
FrameTemp<UTF8> tmpBuff(GuiTextCtrl::MAX_STRING_LENGTH);
|
||||
// And copy the text to be completed into it.
|
||||
mTextBuffer.getCopy8(tmpBuff, GuiTextCtrl::MAX_STRING_LENGTH);
|
||||
|
||||
// perform the completion
|
||||
bool forward = (event.modifier & SI_SHIFT) == 0;
|
||||
mCursorPos = Con::tabComplete(tmpBuff, mCursorPos, GuiTextCtrl::MAX_STRING_LENGTH, forward);
|
||||
|
||||
// place results in our buffer.
|
||||
mTextBuffer.set(tmpBuff);
|
||||
return true;
|
||||
}
|
||||
else if ((event.keyCode == KEY_PAGE_UP) || (event.keyCode == KEY_PAGE_DOWN))
|
||||
{
|
||||
// See if there's some other widget that can scroll the console history.
|
||||
if (mUseSiblingScroller)
|
||||
{
|
||||
if (mSiblingScroller)
|
||||
{
|
||||
return mSiblingScroller->onKeyDown(event);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Let's see if we can find it...
|
||||
SimGroup* pGroup = getGroup();
|
||||
if (pGroup)
|
||||
{
|
||||
// Find the first scroll control in the same group as us.
|
||||
for (SimSetIterator itr(pGroup); *itr; ++itr)
|
||||
{
|
||||
mSiblingScroller = dynamic_cast<GuiScrollCtrl*>(*itr);
|
||||
if (mSiblingScroller != NULL)
|
||||
{
|
||||
return mSiblingScroller->onKeyDown(event);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// No luck... so don't try, next time.
|
||||
mUseSiblingScroller = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if( event.keyCode == KEY_RETURN || event.keyCode == KEY_NUMPADENTER )
|
||||
{
|
||||
if ( event.modifier & SI_SHIFT &&
|
||||
mTextBuffer.length() + dStrlen("echo();") <= GuiTextCtrl::MAX_STRING_LENGTH )
|
||||
{
|
||||
// Wrap the text with echo( %s );
|
||||
|
||||
char buf[GuiTextCtrl::MAX_STRING_LENGTH];
|
||||
getText( buf );
|
||||
|
||||
String text( buf );
|
||||
text.replace( ";", "" );
|
||||
|
||||
text = String::ToString( "echo(%s);", text.c_str() );
|
||||
|
||||
setText( text );
|
||||
}
|
||||
|
||||
return Parent::dealWithEnter(false);
|
||||
}
|
||||
|
||||
return Parent::onKeyDown(event);
|
||||
}
|
||||
|
||||
56
Engine/source/gui/controls/guiConsoleEditCtrl.h
Normal file
56
Engine/source/gui/controls/guiConsoleEditCtrl.h
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// Copyright (c) 2012 GarageGames, LLC
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to
|
||||
// deal in the Software without restriction, including without limitation the
|
||||
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
// sell copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
// IN THE SOFTWARE.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef _GUICONSOLEEDITCTRL_H_
|
||||
#define _GUICONSOLEEDITCTRL_H_
|
||||
|
||||
#ifndef _GUITYPES_H_
|
||||
#include "gui/core/guiTypes.h"
|
||||
#endif
|
||||
#ifndef _GUITEXTEDITCTRL_H_
|
||||
#include "gui/controls/guiTextEditCtrl.h"
|
||||
#endif
|
||||
#ifndef _GUISCROLLCTRL_H_
|
||||
#include "gui/containers/guiScrollCtrl.h"
|
||||
#endif
|
||||
|
||||
class GuiConsoleEditCtrl : public GuiTextEditCtrl
|
||||
{
|
||||
private:
|
||||
typedef GuiTextEditCtrl Parent;
|
||||
|
||||
protected:
|
||||
bool mUseSiblingScroller;
|
||||
GuiScrollCtrl* mSiblingScroller;
|
||||
|
||||
public:
|
||||
GuiConsoleEditCtrl();
|
||||
|
||||
DECLARE_CONOBJECT(GuiConsoleEditCtrl);
|
||||
DECLARE_CATEGORY( "Gui Editor" );
|
||||
|
||||
static void initPersistFields();
|
||||
|
||||
bool onKeyDown(const GuiEvent &event);
|
||||
};
|
||||
|
||||
#endif //_GUI_TEXTEDIT_CTRL_H
|
||||
171
Engine/source/gui/controls/guiConsoleTextCtrl.cpp
Normal file
171
Engine/source/gui/controls/guiConsoleTextCtrl.cpp
Normal file
|
|
@ -0,0 +1,171 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// Copyright (c) 2012 GarageGames, LLC
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to
|
||||
// deal in the Software without restriction, including without limitation the
|
||||
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
// sell copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
// IN THE SOFTWARE.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "platform/platform.h"
|
||||
#include "gui/controls/guiConsoleTextCtrl.h"
|
||||
|
||||
#include "console/consoleTypes.h"
|
||||
#include "console/console.h"
|
||||
#include "core/color.h"
|
||||
#include "gfx/gfxDrawUtil.h"
|
||||
#include "gui/core/guiDefaultControlRender.h"
|
||||
|
||||
IMPLEMENT_CONOBJECT(GuiConsoleTextCtrl);
|
||||
|
||||
ConsoleDocClass( GuiConsoleTextCtrl,
|
||||
"@brief Used by GUIConsole system internally.\n\n"
|
||||
"@internal"
|
||||
);
|
||||
|
||||
GuiConsoleTextCtrl::GuiConsoleTextCtrl()
|
||||
{
|
||||
}
|
||||
|
||||
GuiConsoleTextCtrl::~GuiConsoleTextCtrl()
|
||||
{
|
||||
}
|
||||
|
||||
void GuiConsoleTextCtrl::initPersistFields()
|
||||
{
|
||||
addGroup("GuiConsoleTextCtrl");
|
||||
addField("expression", TypeRealString, Offset(mConsoleExpression, GuiConsoleTextCtrl));
|
||||
endGroup("GuiConsoleTextCtrl");
|
||||
Parent::initPersistFields();
|
||||
}
|
||||
|
||||
bool GuiConsoleTextCtrl::onWake()
|
||||
{
|
||||
if (! Parent::onWake())
|
||||
return false;
|
||||
|
||||
mFont = mProfile->mFont;
|
||||
return true;
|
||||
}
|
||||
|
||||
void GuiConsoleTextCtrl::onSleep()
|
||||
{
|
||||
Parent::onSleep();
|
||||
mFont = NULL;
|
||||
}
|
||||
|
||||
void GuiConsoleTextCtrl::setText(const char *txt)
|
||||
{
|
||||
//make sure we don't call this before onAdd();
|
||||
AssertFatal(mProfile, "Can't call setText() until setProfile() has been called.");
|
||||
|
||||
if (txt)
|
||||
mConsoleExpression = txt;
|
||||
else
|
||||
mConsoleExpression = String::EmptyString;
|
||||
|
||||
// make sure we have a font
|
||||
mProfile->incLoadCount();
|
||||
mFont = mProfile->mFont;
|
||||
|
||||
setUpdate();
|
||||
|
||||
// decrement the profile reference
|
||||
mProfile->decLoadCount();
|
||||
}
|
||||
|
||||
void GuiConsoleTextCtrl::calcResize()
|
||||
{
|
||||
if ( mResult.isEmpty() )
|
||||
return;
|
||||
|
||||
// The width is the longest line.
|
||||
U32 ctrlWidth = 0;
|
||||
for ( U32 i = 0; i < mLineLen.size(); i++ )
|
||||
{
|
||||
U32 width = mFont->getStrNWidth( mResult.c_str() + mStartLineOffset[i], mLineLen[i] );
|
||||
|
||||
if ( width > ctrlWidth )
|
||||
ctrlWidth = width;
|
||||
}
|
||||
|
||||
// The height is the number of lines times the height of the font.
|
||||
U32 ctrlHeight = mLineLen.size() * mFont->getHeight();
|
||||
|
||||
setExtent( Point2I( ctrlWidth, ctrlHeight ) + mProfile->mTextOffset * 2 );
|
||||
}
|
||||
|
||||
|
||||
void GuiConsoleTextCtrl::onPreRender()
|
||||
{
|
||||
if ( mConsoleExpression.isNotEmpty() )
|
||||
{
|
||||
mResult = Con::evaluatef( "$guiConsoleTextCtrlTemp = %s;", mConsoleExpression.c_str() );
|
||||
|
||||
// Of the resulting string we will be printing,
|
||||
// Find the number of lines and length of each.
|
||||
mProfile->mFont->wrapString( mResult, U32_MAX, mStartLineOffset, mLineLen );
|
||||
}
|
||||
else
|
||||
mResult = String::EmptyString;
|
||||
|
||||
calcResize();
|
||||
}
|
||||
|
||||
void GuiConsoleTextCtrl::onRender( Point2I offset, const RectI &updateRect )
|
||||
{
|
||||
RectI ctrlRect( offset, getExtent() );
|
||||
|
||||
// if opaque, fill the update rect with the fill color
|
||||
if ( mProfile->mOpaque )
|
||||
GFX->getDrawUtil()->drawRectFill( ctrlRect, mProfile->mFillColor );
|
||||
|
||||
// if there's a border, draw the border
|
||||
if ( mProfile->mBorder )
|
||||
renderBorder( ctrlRect, mProfile );
|
||||
|
||||
// If we have text to render.
|
||||
if ( mResult.isNotEmpty() )
|
||||
{
|
||||
GFont *font = mProfile->mFont;
|
||||
|
||||
GFX->getDrawUtil()->setBitmapModulation( mProfile->mFontColor );
|
||||
|
||||
for ( U32 i = 0; i < mLineLen.size(); i++ )
|
||||
{
|
||||
Point2I tempOffset = offset;
|
||||
tempOffset += mProfile->mTextOffset;
|
||||
tempOffset.y += i * font->getHeight();
|
||||
|
||||
const UTF8 *line = mResult.c_str() + mStartLineOffset[i];
|
||||
U32 lineLen = mLineLen[i];
|
||||
GFX->getDrawUtil()->drawTextN( font, tempOffset, line, lineLen, mProfile->mFontColors );
|
||||
}
|
||||
}
|
||||
|
||||
// render the child controlsmResult
|
||||
renderChildControls(offset, updateRect);
|
||||
}
|
||||
|
||||
const char *GuiConsoleTextCtrl::getScriptValue()
|
||||
{
|
||||
return getText();
|
||||
}
|
||||
|
||||
void GuiConsoleTextCtrl::setScriptValue(const char *val)
|
||||
{
|
||||
setText(val);
|
||||
}
|
||||
82
Engine/source/gui/controls/guiConsoleTextCtrl.h
Normal file
82
Engine/source/gui/controls/guiConsoleTextCtrl.h
Normal file
|
|
@ -0,0 +1,82 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// Copyright (c) 2012 GarageGames, LLC
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to
|
||||
// deal in the Software without restriction, including without limitation the
|
||||
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
// sell copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
// IN THE SOFTWARE.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef _GUICONSOLETEXTCTRL_H_
|
||||
#define _GUICONSOLETEXTCTRL_H_
|
||||
|
||||
#ifndef _GFONT_H_
|
||||
#include "gfx/gFont.h"
|
||||
#endif
|
||||
#ifndef _GUITYPES_H_
|
||||
#include "gui/core/guiTypes.h"
|
||||
#endif
|
||||
#ifndef _GUICONTROL_H_
|
||||
#include "gui/core/guiControl.h"
|
||||
#endif
|
||||
|
||||
class GuiConsoleTextCtrl : public GuiControl
|
||||
{
|
||||
private:
|
||||
typedef GuiControl Parent;
|
||||
|
||||
public:
|
||||
enum Constants { MAX_STRING_LENGTH = 255 };
|
||||
|
||||
|
||||
protected:
|
||||
|
||||
String mConsoleExpression;
|
||||
String mResult;
|
||||
Resource<GFont> mFont;
|
||||
|
||||
Vector<U32> mStartLineOffset;
|
||||
Vector<U32> mLineLen;
|
||||
|
||||
public:
|
||||
|
||||
//creation methods
|
||||
DECLARE_CONOBJECT(GuiConsoleTextCtrl);
|
||||
DECLARE_CATEGORY( "Gui Editor" );
|
||||
|
||||
GuiConsoleTextCtrl();
|
||||
virtual ~GuiConsoleTextCtrl();
|
||||
static void initPersistFields();
|
||||
|
||||
//Parental methods
|
||||
bool onWake();
|
||||
void onSleep();
|
||||
|
||||
//text methods
|
||||
virtual void setText( const char *txt = NULL );
|
||||
const char* getText() { return mConsoleExpression.c_str(); }
|
||||
|
||||
//rendering methods
|
||||
void calcResize();
|
||||
void onPreRender(); // do special pre render processing
|
||||
void onRender( Point2I offset, const RectI &updateRect );
|
||||
|
||||
//Console methods
|
||||
const char* getScriptValue();
|
||||
void setScriptValue( const char *value );
|
||||
};
|
||||
|
||||
#endif //_GUI_TEXT_CONTROL_H_
|
||||
238
Engine/source/gui/controls/guiDecoyCtrl.cpp
Normal file
238
Engine/source/gui/controls/guiDecoyCtrl.cpp
Normal file
|
|
@ -0,0 +1,238 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// Copyright (c) 2012 GarageGames, LLC
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to
|
||||
// deal in the Software without restriction, including without limitation the
|
||||
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
// sell copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
// IN THE SOFTWARE.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "platform/platform.h"
|
||||
#include "gui/controls/guiDecoyCtrl.h"
|
||||
#include "gui/buttons/guiButtonBaseCtrl.h"
|
||||
|
||||
#include "console/consoleTypes.h"
|
||||
#include "gfx/primBuilder.h"
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// GuiDecoyCtrl
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
/*
|
||||
So far this control has been designed in mind solely for button controls. I'm pretty sure
|
||||
it can be used for other things, but to do anything more in depth; it has to be extended.
|
||||
Make sure you know a little about how guiCanvas hands out signals to gui controls before you tinker
|
||||
in this class.
|
||||
|
||||
Been thinking about this class a little more. I tried pretty hard to protect this class into being
|
||||
guiControl like agnostic. But I ended up adding a check specifically for buttons in the
|
||||
onMouseUp function. Its been protected with a dynamic_cast and a NULL check; but in the end, the only way
|
||||
too solve the main problem, that GuiCanvas cannot process more than one mouse action for more than one
|
||||
gui control at a time, is for it to get a rewrite.
|
||||
*/
|
||||
|
||||
IMPLEMENT_CONOBJECT(GuiDecoyCtrl);
|
||||
|
||||
ConsoleDocClass( GuiDecoyCtrl,
|
||||
"@brief Designed soley for buttons, primarily used in editor.\n\n"
|
||||
"Currently editor use only, no real application without extension.\n\n "
|
||||
"@internal");
|
||||
|
||||
GuiDecoyCtrl::GuiDecoyCtrl() : mIsDecoy(true),
|
||||
mMouseOver(false),
|
||||
mDecoyReference(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
GuiDecoyCtrl::~GuiDecoyCtrl()
|
||||
{
|
||||
}
|
||||
|
||||
void GuiDecoyCtrl::initPersistFields()
|
||||
{
|
||||
addField("isDecoy", TypeBool, Offset(mIsDecoy, GuiDecoyCtrl), "Sets this control to decoy mode");
|
||||
|
||||
Parent::initPersistFields();
|
||||
}
|
||||
|
||||
void GuiDecoyCtrl::onMouseUp(const GuiEvent &event)
|
||||
{
|
||||
mouseUnlock();
|
||||
setUpdate();
|
||||
|
||||
//this code is pretty hacky. right now there is no way that guiCanvas will allow sending more than
|
||||
//one signal to one gui control at a time.
|
||||
if(mIsDecoy == true)
|
||||
{
|
||||
mVisible = false;
|
||||
|
||||
GuiControl *parent = getParent();
|
||||
Point2I localPoint = parent->globalToLocalCoord(event.mousePoint);
|
||||
GuiControl *tempControl = parent->findHitControl(localPoint);
|
||||
|
||||
//the decoy control has the responsibility of keeping track of the decoyed controls status
|
||||
if( mDecoyReference != NULL && tempControl == mDecoyReference)
|
||||
tempControl->onMouseUp(event);
|
||||
else if(mDecoyReference != NULL && tempControl != mDecoyReference)
|
||||
{
|
||||
//as explained earlier, this control was written in the mindset for buttons.
|
||||
//nothing bad should ever happen if not a button due to the checks in this function though.
|
||||
GuiButtonBaseCtrl *unCastCtrl = NULL;
|
||||
unCastCtrl = dynamic_cast<GuiButtonBaseCtrl *>( mDecoyReference );
|
||||
if(unCastCtrl != NULL)
|
||||
unCastCtrl->resetState();
|
||||
}
|
||||
mVisible = true;
|
||||
}
|
||||
}
|
||||
|
||||
void GuiDecoyCtrl::onMouseDown(const GuiEvent &event)
|
||||
{
|
||||
if ( !mVisible || !mAwake )
|
||||
return;
|
||||
|
||||
mouseLock();
|
||||
|
||||
if(mIsDecoy == true)
|
||||
{
|
||||
mVisible = false;
|
||||
|
||||
GuiControl *parent = getParent();
|
||||
Point2I localPoint = parent->globalToLocalCoord(event.mousePoint);
|
||||
|
||||
GuiControl *tempControl = parent->findHitControl(localPoint);
|
||||
tempControl->onMouseDown(event);
|
||||
|
||||
mVisible = true;
|
||||
}
|
||||
|
||||
execConsoleCallback();
|
||||
setUpdate();
|
||||
}
|
||||
|
||||
void GuiDecoyCtrl::onMouseMove(const GuiEvent &event)
|
||||
{
|
||||
//if this control is a dead end, make sure the event stops here
|
||||
if ( !mVisible || !mAwake )
|
||||
return;
|
||||
|
||||
//pass the event to the parent
|
||||
GuiControl *parent = getParent();
|
||||
if ( parent )
|
||||
parent->onMouseMove( event );
|
||||
|
||||
Point2I localPoint = parent->globalToLocalCoord(event.mousePoint);
|
||||
|
||||
//also pretty hacky. since guiCanvas, *NOT* GuiControl, distributes the calls for onMouseEnter
|
||||
//and onMouseLeave, we simulate those calls here through a series of checks.
|
||||
if(mIsDecoy == true)
|
||||
{
|
||||
mVisible = false;
|
||||
GuiControl *parent = getParent();
|
||||
GuiControl *tempControl = parent->findHitControl(localPoint);
|
||||
|
||||
//the decoy control has the responsibility of keeping track of the decoyed controls status
|
||||
if(mMouseOverDecoy == false && mDecoyReference != NULL)
|
||||
{
|
||||
tempControl->onMouseEnter(event);
|
||||
mMouseOverDecoy = true;
|
||||
}
|
||||
else if(tempControl != mDecoyReference && mDecoyReference != NULL)
|
||||
{
|
||||
mDecoyReference->onMouseLeave(event);
|
||||
mMouseOverDecoy = false;
|
||||
}
|
||||
|
||||
mDecoyReference = tempControl;
|
||||
mVisible = true;
|
||||
}
|
||||
}
|
||||
|
||||
void GuiDecoyCtrl::onMouseDragged(const GuiEvent &event)
|
||||
{
|
||||
}
|
||||
|
||||
void GuiDecoyCtrl::onMouseEnter(const GuiEvent &event)
|
||||
{
|
||||
if ( !mVisible || !mAwake )
|
||||
return;
|
||||
|
||||
setUpdate();
|
||||
Con::executef( this , "onMouseEnter" );
|
||||
mMouseOver = true;
|
||||
}
|
||||
|
||||
void GuiDecoyCtrl::onMouseLeave(const GuiEvent &event)
|
||||
{
|
||||
if ( !mVisible || !mAwake )
|
||||
return;
|
||||
|
||||
setUpdate();
|
||||
Con::executef( this , "onMouseLeave" );
|
||||
mMouseOver = false;
|
||||
}
|
||||
|
||||
bool GuiDecoyCtrl::onMouseWheelUp( const GuiEvent &event )
|
||||
{
|
||||
//if this control is a dead end, make sure the event stops here
|
||||
if ( !mVisible || !mAwake )
|
||||
return true;
|
||||
|
||||
//pass the event to the parent
|
||||
GuiControl *parent = getParent();
|
||||
if ( parent )
|
||||
return parent->onMouseWheelUp( event );
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
bool GuiDecoyCtrl::onMouseWheelDown( const GuiEvent &event )
|
||||
{
|
||||
//if this control is a dead end, make sure the event stops here
|
||||
if ( !mVisible || !mAwake )
|
||||
return true;
|
||||
|
||||
//pass the event to the parent
|
||||
GuiControl *parent = getParent();
|
||||
if ( parent )
|
||||
return parent->onMouseWheelDown( event );
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
void GuiDecoyCtrl::onRightMouseDown(const GuiEvent &)
|
||||
{
|
||||
}
|
||||
|
||||
void GuiDecoyCtrl::onRightMouseUp(const GuiEvent &)
|
||||
{
|
||||
}
|
||||
|
||||
void GuiDecoyCtrl::onRightMouseDragged(const GuiEvent &)
|
||||
{
|
||||
}
|
||||
|
||||
void GuiDecoyCtrl::onMiddleMouseDown(const GuiEvent &)
|
||||
{
|
||||
}
|
||||
|
||||
void GuiDecoyCtrl::onMiddleMouseUp(const GuiEvent &)
|
||||
{
|
||||
}
|
||||
|
||||
void GuiDecoyCtrl::onMiddleMouseDragged(const GuiEvent &)
|
||||
{
|
||||
}
|
||||
69
Engine/source/gui/controls/guiDecoyCtrl.h
Normal file
69
Engine/source/gui/controls/guiDecoyCtrl.h
Normal file
|
|
@ -0,0 +1,69 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// Copyright (c) 2012 GarageGames, LLC
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to
|
||||
// deal in the Software without restriction, including without limitation the
|
||||
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
// sell copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
// IN THE SOFTWARE.
|
||||
//-----------------------------------------------------------------------------
|
||||
#ifndef _GUIDECOYCTRL_H_
|
||||
#define _GUIDECOYCTRL_H_
|
||||
|
||||
#ifndef _GUICONTROL_H_
|
||||
#include "gui/core/guiControl.h"
|
||||
#endif
|
||||
|
||||
class GuiDecoyCtrl : public GuiControl
|
||||
{
|
||||
private:
|
||||
typedef GuiControl Parent;
|
||||
|
||||
public:
|
||||
// Constructor/Destructor/ConObject Declaration
|
||||
GuiDecoyCtrl();
|
||||
virtual ~GuiDecoyCtrl();
|
||||
|
||||
DECLARE_CONOBJECT(GuiDecoyCtrl);
|
||||
DECLARE_CATEGORY( "Gui Other" );
|
||||
|
||||
static void initPersistFields();
|
||||
|
||||
bool mMouseOver;
|
||||
bool mIsDecoy;
|
||||
GuiControl* mDecoyReference;
|
||||
bool mMouseOverDecoy;
|
||||
Point2I mMouseDownPosition;
|
||||
|
||||
|
||||
virtual void onMouseUp(const GuiEvent &event);
|
||||
virtual void onMouseDown(const GuiEvent &event);
|
||||
virtual void onMouseMove(const GuiEvent &event);
|
||||
virtual void onMouseDragged(const GuiEvent &event);
|
||||
virtual void onMouseEnter(const GuiEvent &event);
|
||||
virtual void onMouseLeave(const GuiEvent &event);
|
||||
|
||||
virtual bool onMouseWheelUp(const GuiEvent &event);
|
||||
virtual bool onMouseWheelDown(const GuiEvent &event);
|
||||
|
||||
virtual void onRightMouseDown(const GuiEvent &event);
|
||||
virtual void onRightMouseUp(const GuiEvent &event);
|
||||
virtual void onRightMouseDragged(const GuiEvent &event);
|
||||
|
||||
virtual void onMiddleMouseDown(const GuiEvent &event);
|
||||
virtual void onMiddleMouseUp(const GuiEvent &event);
|
||||
virtual void onMiddleMouseDragged(const GuiEvent &event);
|
||||
};
|
||||
#endif
|
||||
222
Engine/source/gui/controls/guiDirectoryFileListCtrl.cpp
Normal file
222
Engine/source/gui/controls/guiDirectoryFileListCtrl.cpp
Normal file
|
|
@ -0,0 +1,222 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// Copyright (c) 2012 GarageGames, LLC
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to
|
||||
// deal in the Software without restriction, including without limitation the
|
||||
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
// sell copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
// IN THE SOFTWARE.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "console/engineAPI.h"
|
||||
#include "core/strings/findMatch.h"
|
||||
#include "gui/controls/guiDirectoryFileListCtrl.h"
|
||||
|
||||
|
||||
IMPLEMENT_CONOBJECT( GuiDirectoryFileListCtrl );
|
||||
|
||||
ConsoleDocClass( GuiDirectoryFileListCtrl,
|
||||
"@brief A control that displays a list of files from within a single directory "
|
||||
"in the game file system.\n\n"
|
||||
|
||||
"@tsexample\n\n"
|
||||
"new GuiDirectoryFileListCtrl()\n"
|
||||
"{\n"
|
||||
" filePath = \"art/shapes\";\n"
|
||||
" fileFilter = \"*.dts\" TAB \"*.dae\";\n"
|
||||
" //Properties not specific to this control have been omitted from this example.\n"
|
||||
"};\n"
|
||||
"@endtsexample\n\n"
|
||||
|
||||
"@ingroup GuiControls\n"
|
||||
);
|
||||
|
||||
GuiDirectoryFileListCtrl::GuiDirectoryFileListCtrl()
|
||||
{
|
||||
mFilePath = StringTable->insert( "" );
|
||||
mFilter = StringTable->insert( "*.*" );
|
||||
}
|
||||
|
||||
void GuiDirectoryFileListCtrl::initPersistFields()
|
||||
{
|
||||
addProtectedField( "filePath", TypeString, Offset( mFilePath, GuiDirectoryFileListCtrl ),
|
||||
&_setFilePath, &defaultProtectedGetFn, "Path in game directory from which to list files." );
|
||||
addProtectedField( "fileFilter", TypeString, Offset( mFilter, GuiDirectoryFileListCtrl ),
|
||||
&_setFilter, &defaultProtectedGetFn, "Tab-delimited list of file name patterns. Only matched files will be displayed." );
|
||||
|
||||
Parent::initPersistFields();
|
||||
}
|
||||
|
||||
bool GuiDirectoryFileListCtrl::onWake()
|
||||
{
|
||||
if( !Parent::onWake() )
|
||||
return false;
|
||||
|
||||
update();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void GuiDirectoryFileListCtrl::onMouseDown(const GuiEvent &event)
|
||||
{
|
||||
Parent::onMouseDown( event );
|
||||
|
||||
if( event.mouseClickCount == 2 )
|
||||
onDoubleClick_callback();
|
||||
}
|
||||
|
||||
|
||||
void GuiDirectoryFileListCtrl::openDirectory()
|
||||
{
|
||||
String path;
|
||||
if( mFilePath && mFilePath[ 0 ] )
|
||||
path = String::ToString( "%s/%s", Platform::getMainDotCsDir(), mFilePath );
|
||||
else
|
||||
path = Platform::getMainDotCsDir();
|
||||
|
||||
Vector<Platform::FileInfo> fileVector;
|
||||
Platform::dumpPath( path, fileVector, 0 );
|
||||
|
||||
// Clear the current file listing
|
||||
clearItems();
|
||||
|
||||
// Does this dir have any files?
|
||||
if( fileVector.empty() )
|
||||
return;
|
||||
|
||||
// If so, iterate through and list them
|
||||
Vector<Platform::FileInfo>::iterator i = fileVector.begin();
|
||||
for( S32 j=0 ; i != fileVector.end(); i++, j++ )
|
||||
{
|
||||
if( !mFilter[ 0 ] || FindMatch::isMatchMultipleExprs( mFilter, (*i).pFileName,false ) )
|
||||
addItem( (*i).pFileName );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void GuiDirectoryFileListCtrl::setCurrentFilter( const char* filter )
|
||||
{
|
||||
if( !filter )
|
||||
filter = "";
|
||||
|
||||
mFilter = StringTable->insert( filter );
|
||||
|
||||
// Update our view
|
||||
openDirectory();
|
||||
}
|
||||
|
||||
DefineEngineMethod( GuiDirectoryFileListCtrl, setFilter, void, ( const char* filter ),,
|
||||
"Set the file filter.\n\n"
|
||||
"@param filter Tab-delimited list of file name patterns. Only matched files will be displayed.\n" )
|
||||
{
|
||||
object->setCurrentFilter( filter );
|
||||
}
|
||||
|
||||
bool GuiDirectoryFileListCtrl::setCurrentPath( const char* path, const char* filter )
|
||||
{
|
||||
if( !path )
|
||||
return false;
|
||||
|
||||
const U32 pathLen = dStrlen( path );
|
||||
if( pathLen > 0 && path[ pathLen - 1 ] == '/' )
|
||||
mFilePath = StringTable->insertn( path, pathLen - 1 );
|
||||
else
|
||||
mFilePath = StringTable->insert( path );
|
||||
|
||||
if( filter )
|
||||
mFilter = StringTable->insert( filter );
|
||||
|
||||
// Update our view
|
||||
openDirectory();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
DefineEngineMethod( GuiDirectoryFileListCtrl, reload, void, (),,
|
||||
"Update the file list." )
|
||||
{
|
||||
object->update();
|
||||
}
|
||||
|
||||
DefineEngineMethod( GuiDirectoryFileListCtrl, setPath, bool, ( const char* path, const char* filter ),,
|
||||
"Set the search path and file filter.\n\n"
|
||||
"@param path Path in game directory from which to list files.\n"
|
||||
"@param filter Tab-delimited list of file name patterns. Only matched files will be displayed.\n" )
|
||||
{
|
||||
return object->setCurrentPath( path, filter );
|
||||
}
|
||||
|
||||
DefineEngineMethod( GuiDirectoryFileListCtrl, getSelectedFiles, const char*, (),,
|
||||
"Get the list of selected files.\n\n"
|
||||
"@return A space separated list of selected files" )
|
||||
{
|
||||
Vector<S32> ItemVector;
|
||||
object->getSelectedItems( ItemVector );
|
||||
|
||||
if( ItemVector.empty() )
|
||||
return StringTable->insert( "" );
|
||||
|
||||
// Get an adequate buffer
|
||||
char itemBuffer[256];
|
||||
dMemset( itemBuffer, 0, 256 );
|
||||
|
||||
char* returnBuffer = Con::getReturnBuffer( ItemVector.size() * 64 );
|
||||
dMemset( returnBuffer, 0, ItemVector.size() * 64 );
|
||||
|
||||
// Fetch the first entry
|
||||
StringTableEntry itemText = object->getItemText( ItemVector[0] );
|
||||
if( !itemText )
|
||||
return StringTable->lookup("");
|
||||
dSprintf( returnBuffer, ItemVector.size() * 64, "%s", itemText );
|
||||
|
||||
// If only one entry, return it.
|
||||
if( ItemVector.size() == 1 )
|
||||
return returnBuffer;
|
||||
|
||||
// Fetch the remaining entries
|
||||
for( S32 i = 1; i < ItemVector.size(); i++ )
|
||||
{
|
||||
StringTableEntry itemText = object->getItemText( ItemVector[i] );
|
||||
if( !itemText )
|
||||
continue;
|
||||
|
||||
dMemset( itemBuffer, 0, 256 );
|
||||
dSprintf( itemBuffer, 256, " %s", itemText );
|
||||
dStrcat( returnBuffer, itemBuffer );
|
||||
}
|
||||
|
||||
return returnBuffer;
|
||||
|
||||
}
|
||||
|
||||
StringTableEntry GuiDirectoryFileListCtrl::getSelectedFileName()
|
||||
{
|
||||
S32 item = getSelectedItem();
|
||||
if( item == -1 )
|
||||
return StringTable->lookup("");
|
||||
|
||||
StringTableEntry itemText = getItemText( item );
|
||||
if( !itemText )
|
||||
return StringTable->lookup("");
|
||||
|
||||
return itemText;
|
||||
}
|
||||
|
||||
DefineEngineMethod( GuiDirectoryFileListCtrl, getSelectedFile, const char*, (),,
|
||||
"Get the currently selected filename.\n\n"
|
||||
"@return The filename of the currently selected file\n" )
|
||||
{
|
||||
return object->getSelectedFileName();
|
||||
}
|
||||
79
Engine/source/gui/controls/guiDirectoryFileListCtrl.h
Normal file
79
Engine/source/gui/controls/guiDirectoryFileListCtrl.h
Normal file
|
|
@ -0,0 +1,79 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// Copyright (c) 2012 GarageGames, LLC
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to
|
||||
// deal in the Software without restriction, including without limitation the
|
||||
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
// sell copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
// IN THE SOFTWARE.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef _GUI_DIRECTORYFILELISTCTRL_H_
|
||||
#define _GUI_DIRECTORYFILELISTCTRL_H_
|
||||
|
||||
#ifndef _PLATFORM_H_
|
||||
#include "platform/platform.h"
|
||||
#endif
|
||||
|
||||
#ifndef _GUI_LISTBOXCTRL_H_
|
||||
#include "gui/controls/guiListBoxCtrl.h"
|
||||
#endif
|
||||
|
||||
class GuiDirectoryFileListCtrl : public GuiListBoxCtrl
|
||||
{
|
||||
private:
|
||||
typedef GuiListBoxCtrl Parent;
|
||||
protected:
|
||||
StringTableEntry mFilePath;
|
||||
StringTableEntry mFilter;
|
||||
|
||||
void openDirectory();
|
||||
|
||||
static bool _setFilePath( void *object, const char *index, const char *data )
|
||||
{
|
||||
GuiDirectoryFileListCtrl* ctrl = ( GuiDirectoryFileListCtrl* ) object;
|
||||
ctrl->setCurrentPath( data, ctrl->mFilter );
|
||||
return false;
|
||||
}
|
||||
static bool _setFilter( void *object, const char *index, const char *data )
|
||||
{
|
||||
GuiDirectoryFileListCtrl* ctrl = ( GuiDirectoryFileListCtrl* ) object;
|
||||
ctrl->setCurrentFilter( data );
|
||||
return false;
|
||||
}
|
||||
|
||||
public:
|
||||
GuiDirectoryFileListCtrl();
|
||||
|
||||
DECLARE_CONOBJECT(GuiDirectoryFileListCtrl);
|
||||
DECLARE_DESCRIPTION( "A control that displays a list of files from within a single\n"
|
||||
"directory in the game file system." );
|
||||
|
||||
static void initPersistFields();
|
||||
|
||||
void update() { openDirectory(); }
|
||||
|
||||
/// Set the current path to grab files from
|
||||
bool setCurrentPath( const char* path, const char* filter );
|
||||
void setCurrentFilter( const char* filter );
|
||||
|
||||
/// Get the currently selected file's name
|
||||
StringTableEntry getSelectedFileName();
|
||||
|
||||
virtual void onMouseDown(const GuiEvent &event);
|
||||
virtual bool onWake();
|
||||
};
|
||||
|
||||
#endif
|
||||
430
Engine/source/gui/controls/guiFileTreeCtrl.cpp
Normal file
430
Engine/source/gui/controls/guiFileTreeCtrl.cpp
Normal file
|
|
@ -0,0 +1,430 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// Copyright (c) 2012 GarageGames, LLC
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to
|
||||
// deal in the Software without restriction, including without limitation the
|
||||
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
// sell copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
// IN THE SOFTWARE.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "gui/controls/guiFileTreeCtrl.h"
|
||||
#include "core/strings/findMatch.h"
|
||||
#include "core/frameAllocator.h"
|
||||
#include "core/strings/stringUnit.h"
|
||||
#include "console/consoleTypes.h"
|
||||
|
||||
|
||||
IMPLEMENT_CONOBJECT(GuiFileTreeCtrl);
|
||||
|
||||
ConsoleDocClass( GuiFileTreeCtrl,
|
||||
"@brief A control that displays a hierarchical tree view of a path in the game file system.\n\n"
|
||||
"@note Currently not used, most likely existed for editors. Possibly deprecated.\n\n"
|
||||
"@internal"
|
||||
);
|
||||
|
||||
|
||||
static bool _isDirInMainDotCsPath(const char* dir)
|
||||
{
|
||||
StringTableEntry cs = Platform::getMainDotCsDir();
|
||||
U32 len = dStrlen(cs) + dStrlen(dir) + 2;
|
||||
FrameTemp<UTF8> fullpath(len);
|
||||
dSprintf(fullpath, len, "%s/%s", cs, dir);
|
||||
|
||||
return Platform::isDirectory(fullpath);
|
||||
}
|
||||
|
||||
static bool _hasChildren(const char* path)
|
||||
{
|
||||
if( Platform::hasSubDirectory(path))
|
||||
return true;
|
||||
|
||||
Vector<StringTableEntry> dummy;
|
||||
Platform::dumpDirectories( path, dummy, 0, true);
|
||||
|
||||
return dummy.size() > 0;
|
||||
}
|
||||
|
||||
GuiFileTreeCtrl::GuiFileTreeCtrl()
|
||||
: Parent()
|
||||
{
|
||||
// Parent configuration
|
||||
setBounds(0,0,200,100);
|
||||
mDestroyOnSleep = false;
|
||||
mSupportMouseDragging = false;
|
||||
mMultipleSelections = false;
|
||||
|
||||
mFileFilter = "*.cs *.gui *.ed.cs";
|
||||
_initFilters();
|
||||
}
|
||||
|
||||
void GuiFileTreeCtrl::initPersistFields()
|
||||
{
|
||||
addGroup( "File Tree" );
|
||||
addField( "rootPath", TypeRealString, Offset( mRootPath, GuiFileTreeCtrl ), "Path in game directory that should be displayed in the control." );
|
||||
addProtectedField( "fileFilter", TypeRealString, Offset( mFileFilter, GuiFileTreeCtrl ),
|
||||
&_setFileFilterValue, &defaultProtectedGetFn, "Vector of file patterns. If not empty, only files matching the pattern will be shown in the control." );
|
||||
endGroup( "File Tree" );
|
||||
|
||||
Parent::initPersistFields();
|
||||
}
|
||||
|
||||
static void _dumpFiles(const char *path, Vector<StringTableEntry> &directoryVector, S32 depth = 0)
|
||||
{
|
||||
Vector<Platform::FileInfo> fileVec;
|
||||
Platform::dumpPath( path, fileVec, depth);
|
||||
|
||||
for(U32 i = 0; i < fileVec.size(); i++)
|
||||
{
|
||||
directoryVector.push_back( StringTable->insert(fileVec[i].pFileName) );
|
||||
}
|
||||
}
|
||||
|
||||
void GuiFileTreeCtrl::updateTree()
|
||||
{
|
||||
// Kill off any existing items
|
||||
_destroyTree();
|
||||
|
||||
// Here we're going to grab our system volumes from the platform layer and create them as roots
|
||||
//
|
||||
// Note : that we're passing a 1 as the last parameter to Platform::dumpDirectories, which tells it
|
||||
// how deep to dump in recursion. This is an optimization to keep from dumping the whole file system
|
||||
// to the tree. The tree will dump more paths as necessary when the virtual parents are expanded,
|
||||
// much as windows does.
|
||||
|
||||
// Determine the root path.
|
||||
|
||||
String rootPath = Platform::getMainDotCsDir();
|
||||
if( !mRootPath.isEmpty() )
|
||||
rootPath = String::ToString( "%s/%s", rootPath.c_str(), mRootPath.c_str() );
|
||||
|
||||
// get the files in the main.cs dir
|
||||
Vector<StringTableEntry> pathVec;
|
||||
Platform::dumpDirectories( rootPath, pathVec, 0, true);
|
||||
_dumpFiles( rootPath, pathVec, 0);
|
||||
if( ! pathVec.empty() )
|
||||
{
|
||||
// get the last folder in the path.
|
||||
char *dirname = dStrdup(rootPath);
|
||||
U32 last = dStrlen(dirname)-1;
|
||||
if(dirname[last] == '/')
|
||||
dirname[last] = '\0';
|
||||
char* lastPathComponent = dStrrchr(dirname,'/');
|
||||
if(lastPathComponent)
|
||||
*lastPathComponent++ = '\0';
|
||||
else
|
||||
lastPathComponent = dirname;
|
||||
|
||||
// Iterate through the returned paths and add them to the tree
|
||||
Vector<StringTableEntry>::iterator j = pathVec.begin();
|
||||
for( ; j != pathVec.end(); j++ )
|
||||
{
|
||||
char fullModPathSub [512];
|
||||
dMemset( fullModPathSub, 0, 512 );
|
||||
dSprintf( fullModPathSub, 512, "%s/%s", lastPathComponent, (*j) );
|
||||
addPathToTree( *j );
|
||||
}
|
||||
dFree(dirname);
|
||||
}
|
||||
}
|
||||
|
||||
bool GuiFileTreeCtrl::onWake()
|
||||
{
|
||||
if( !Parent::onWake() )
|
||||
return false;
|
||||
|
||||
updateTree();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool GuiFileTreeCtrl::onVirtualParentExpand(Item *item)
|
||||
{
|
||||
if( !item || !item->isExpanded() )
|
||||
return true;
|
||||
|
||||
const char* pathToExpand = item->getValue();
|
||||
if( !pathToExpand )
|
||||
{
|
||||
Con::errorf("GuiFileTreeCtrl::onVirtualParentExpand - Unable to retrieve item value!");
|
||||
return false;
|
||||
}
|
||||
|
||||
Vector<StringTableEntry> pathVec;
|
||||
_dumpFiles( pathToExpand, pathVec, 0 );
|
||||
Platform::dumpDirectories( pathToExpand, pathVec, 0, true);
|
||||
if( ! pathVec.empty() )
|
||||
{
|
||||
// Iterate through the returned paths and add them to the tree
|
||||
Vector<StringTableEntry>::iterator i = pathVec.begin();
|
||||
for( ; i != pathVec.end(); i++ )
|
||||
recurseInsert(item, (*i) );
|
||||
|
||||
item->setExpanded( true );
|
||||
}
|
||||
|
||||
item->setVirtualParent( false );
|
||||
|
||||
// Update our tree view
|
||||
buildVisibleTree();
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
void GuiFileTreeCtrl::addPathToTree( StringTableEntry path )
|
||||
{
|
||||
if( !path )
|
||||
{
|
||||
Con::errorf("GuiFileTreeCtrl::addPathToTree - Invalid Path!");
|
||||
return;
|
||||
}
|
||||
|
||||
// Identify which root (volume) this path belongs to (if any)
|
||||
S32 root = getFirstRootItem();
|
||||
StringTableEntry ourPath = &path[ dStrcspn( path, "/" ) + 1];
|
||||
StringTableEntry ourRoot = StringUnit::getUnit( path, 0, "/" );
|
||||
// There are no current roots, we can safely create one
|
||||
if( root == 0 )
|
||||
{
|
||||
recurseInsert( NULL, path );
|
||||
}
|
||||
else
|
||||
{
|
||||
while( root != 0 )
|
||||
{
|
||||
if( dStricmp( getItemValue( root ), ourRoot ) == 0 )
|
||||
{
|
||||
recurseInsert( getItem( root ), ourPath );
|
||||
break;
|
||||
}
|
||||
root = this->getNextSiblingItem( root );
|
||||
}
|
||||
// We found none so we'll create one
|
||||
if ( root == 0 )
|
||||
{
|
||||
recurseInsert( NULL, path );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GuiFileTreeCtrl::onItemSelected( Item *item )
|
||||
{
|
||||
Con::executef( this, "onSelectPath", avar("%s",item->getValue()) );
|
||||
|
||||
mSelPath = item->getValue();
|
||||
if( _hasChildren( mSelPath ) )
|
||||
item->setVirtualParent( true );
|
||||
}
|
||||
|
||||
bool GuiFileTreeCtrl::_setFileFilterValue( void *object, const char *index, const char *data )
|
||||
{
|
||||
GuiFileTreeCtrl* ctrl = ( GuiFileTreeCtrl* ) object;
|
||||
|
||||
ctrl->mFileFilter = data;
|
||||
ctrl->_initFilters();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void GuiFileTreeCtrl::_initFilters()
|
||||
{
|
||||
mFilters.clear();
|
||||
|
||||
U32 index = 0;
|
||||
while( true )
|
||||
{
|
||||
const char* pattern = StringUnit::getUnit( mFileFilter, index, " " );
|
||||
if( !pattern[ 0 ] )
|
||||
break;
|
||||
|
||||
mFilters.push_back( pattern );
|
||||
++ index;
|
||||
}
|
||||
}
|
||||
|
||||
bool GuiFileTreeCtrl::matchesFilters(const char* filename)
|
||||
{
|
||||
if( !mFilters.size() )
|
||||
return true;
|
||||
|
||||
for(int i = 0; i < mFilters.size(); i++)
|
||||
{
|
||||
if(FindMatch::isMatch( mFilters[i], filename))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void GuiFileTreeCtrl::recurseInsert( Item* parent, StringTableEntry path )
|
||||
{
|
||||
if( !path )
|
||||
return;
|
||||
|
||||
char szPathCopy [ 1024 ];
|
||||
dMemset( szPathCopy, 0, 1024 );
|
||||
dStrcpy( szPathCopy, path );
|
||||
|
||||
// Jump over the first character if it's a root /
|
||||
char *curPos = szPathCopy;
|
||||
if( *curPos == '/' )
|
||||
curPos++;
|
||||
|
||||
char szValue[1024];
|
||||
dMemset( szValue, 0, 1024 );
|
||||
if( parent )
|
||||
{
|
||||
dMemset( szValue, 0, sizeof( szValue ) );
|
||||
dSprintf( szValue, sizeof( szValue ), "%s/%s", parent->getValue(), curPos );
|
||||
}
|
||||
else
|
||||
{
|
||||
dStrncpy( szValue, curPos, sizeof( szValue ) );
|
||||
szValue[ sizeof( szValue ) - 1 ] = 0;
|
||||
}
|
||||
|
||||
const U32 valueLen = dStrlen( szValue );
|
||||
char* value = new char[ valueLen + 1 ];
|
||||
dMemcpy( value, szValue, valueLen + 1 );
|
||||
|
||||
char *delim = dStrchr( curPos, '/' );
|
||||
if ( delim )
|
||||
{
|
||||
// terminate our / and then move our pointer to the next character (rest of the path)
|
||||
*delim = 0x00;
|
||||
delim++;
|
||||
}
|
||||
S32 itemIndex = 0;
|
||||
// only insert blindly if we have no root
|
||||
if( !parent )
|
||||
itemIndex = insertItem( 0, curPos, curPos );
|
||||
else
|
||||
{
|
||||
bool allowed = (_isDirInMainDotCsPath(value) || matchesFilters(value));
|
||||
Item *exists = parent->findChildByValue( szValue );
|
||||
if( allowed && !exists && dStrcmp( curPos, "" ) != 0 )
|
||||
{
|
||||
// Since we're adding a child this parent can't be a virtual parent, so clear that flag
|
||||
parent->setVirtualParent( false );
|
||||
|
||||
itemIndex = insertItem( parent->getID(), curPos);
|
||||
Item *newitem = getItem(itemIndex);
|
||||
newitem->setValue( value );
|
||||
}
|
||||
else
|
||||
{
|
||||
itemIndex = ( parent != NULL ) ? ( ( exists != NULL ) ? exists->getID() : -1 ) : -1;
|
||||
}
|
||||
}
|
||||
|
||||
Item *newitem = getItem(itemIndex);
|
||||
if(newitem)
|
||||
{
|
||||
newitem->setValue( value );
|
||||
if( _isDirInMainDotCsPath( value ) )
|
||||
{
|
||||
newitem->setNormalImage( Icon_FolderClosed );
|
||||
newitem->setExpandedImage( Icon_Folder );
|
||||
newitem->setVirtualParent(true);
|
||||
newitem->setExpanded(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
newitem->setNormalImage( Icon_Doc );
|
||||
}
|
||||
}
|
||||
// since we're only dealing with volumes and directories, all end nodes will be virtual parents
|
||||
// so if we are at the bottom of the rabbit hole, set the item to be a virtual parent
|
||||
Item* item = getItem( itemIndex );
|
||||
if(item)
|
||||
{
|
||||
item->setExpanded(false);
|
||||
if(parent && _isDirInMainDotCsPath(item->getValue()) && Platform::hasSubDirectory(item->getValue()))
|
||||
item->setVirtualParent(true);
|
||||
}
|
||||
if( delim )
|
||||
{
|
||||
if( ( dStrcmp( delim, "" ) == 0 ) && item )
|
||||
{
|
||||
item->setExpanded( false );
|
||||
if( parent && _hasChildren( item->getValue() ) )
|
||||
item->setVirtualParent( true );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if( item )
|
||||
{
|
||||
item->setExpanded( false );
|
||||
if( parent && _hasChildren( item->getValue() ) )
|
||||
item->setVirtualParent( true );
|
||||
}
|
||||
}
|
||||
|
||||
// Down the rabbit hole we go
|
||||
recurseInsert( getItem( itemIndex ), delim );
|
||||
|
||||
}
|
||||
|
||||
ConsoleMethod( GuiFileTreeCtrl, getSelectedPath, const char*, 2, 2, "getSelectedPath() - returns the currently selected path in the tree")
|
||||
{
|
||||
const String& path = object->getSelectedPath();
|
||||
return Con::getStringArg( path );
|
||||
}
|
||||
|
||||
ConsoleMethod( GuiFileTreeCtrl, setSelectedPath, bool, 3, 3, "setSelectedPath(path) - expands the tree to the specified path")
|
||||
{
|
||||
return object->setSelectedPath( argv[ 2 ] );
|
||||
}
|
||||
|
||||
ConsoleMethod( GuiFileTreeCtrl, reload, void, 2, 2, "() - Reread the directory tree hierarchy." )
|
||||
{
|
||||
object->updateTree();
|
||||
}
|
||||
|
||||
bool GuiFileTreeCtrl::setSelectedPath( const char* path )
|
||||
{
|
||||
if( !path )
|
||||
return false;
|
||||
|
||||
// Since we only list one deep on paths, we need to add the path to the tree just incase it isn't already indexed in the tree
|
||||
// or else we wouldn't be able to select a path we hadn't previously browsed to. :)
|
||||
if( _isDirInMainDotCsPath( path ) )
|
||||
addPathToTree( path );
|
||||
|
||||
// see if we have a child that matches what we want
|
||||
for(U32 i = 0; i < mItems.size(); i++)
|
||||
{
|
||||
if( dStricmp( mItems[i]->getValue(), path ) == 0 )
|
||||
{
|
||||
Item* item = mItems[i];
|
||||
AssertFatal(item,"GuiFileTreeCtrl::setSelectedPath - Item Index Bad, Fatal Mistake!!!");
|
||||
item->setExpanded( true );
|
||||
clearSelection();
|
||||
setItemSelected( item->getID(), true );
|
||||
// make sure all of it's parents are expanded
|
||||
S32 parent = getParentItem( item->getID() );
|
||||
while( parent != 0 )
|
||||
{
|
||||
setItemExpanded( parent, true );
|
||||
parent = getParentItem( parent );
|
||||
}
|
||||
// Rebuild our tree just incase we've oops'd
|
||||
buildVisibleTree();
|
||||
scrollVisible( item );
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
77
Engine/source/gui/controls/guiFileTreeCtrl.h
Normal file
77
Engine/source/gui/controls/guiFileTreeCtrl.h
Normal file
|
|
@ -0,0 +1,77 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// Copyright (c) 2012 GarageGames, LLC
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to
|
||||
// deal in the Software without restriction, including without limitation the
|
||||
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
// sell copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
// IN THE SOFTWARE.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef _GUI_FILETREECTRL_H_
|
||||
#define _GUI_FILETREECTRL_H_
|
||||
|
||||
#include "platform/platform.h"
|
||||
#include "gui/controls/guiTreeViewCtrl.h"
|
||||
|
||||
class GuiFileTreeCtrl : public GuiTreeViewCtrl
|
||||
{
|
||||
private:
|
||||
|
||||
// Utility functions
|
||||
void recurseInsert( Item* parent, StringTableEntry path );
|
||||
void addPathToTree( StringTableEntry path );
|
||||
|
||||
protected:
|
||||
String mSelPath;
|
||||
String mFileFilter;
|
||||
String mRootPath;
|
||||
Vector< String > mFilters;
|
||||
|
||||
void _initFilters();
|
||||
|
||||
static bool _setFileFilterValue( void *object, const char *index, const char *data );
|
||||
|
||||
public:
|
||||
|
||||
typedef GuiTreeViewCtrl Parent;
|
||||
|
||||
enum
|
||||
{
|
||||
Icon_Folder = 1,
|
||||
Icon_FolderClosed = 2,
|
||||
Icon_Doc = 3
|
||||
};
|
||||
|
||||
GuiFileTreeCtrl();
|
||||
|
||||
bool onWake();
|
||||
bool onVirtualParentExpand(Item *item);
|
||||
void onItemSelected( Item *item );
|
||||
const String& getSelectedPath() { return mSelPath; }
|
||||
bool setSelectedPath( const char* path );
|
||||
|
||||
bool matchesFilters(const char* filename);
|
||||
void updateTree();
|
||||
|
||||
DECLARE_CONOBJECT( GuiFileTreeCtrl );
|
||||
DECLARE_DESCRIPTION( "A control that displays a hierarchical tree view of a path in the game file system.\n"
|
||||
"Note that to enable expanding/collapsing of directories, the control must be\n"
|
||||
"placed inside a GuiScrollCtrl." );
|
||||
|
||||
static void initPersistFields();
|
||||
};
|
||||
|
||||
#endif //_GUI_FILETREECTRL_H_
|
||||
877
Engine/source/gui/controls/guiGameListMenuCtrl.cpp
Normal file
877
Engine/source/gui/controls/guiGameListMenuCtrl.cpp
Normal file
|
|
@ -0,0 +1,877 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// Copyright (c) 2012 GarageGames, LLC
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to
|
||||
// deal in the Software without restriction, including without limitation the
|
||||
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
// sell copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
// IN THE SOFTWARE.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "guiGameListMenuCtrl.h"
|
||||
|
||||
#include "console/consoleTypes.h"
|
||||
#include "console/engineAPI.h"
|
||||
#include "gfx/gfxDrawUtil.h"
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// GuiGameListMenuCtrl
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
GuiGameListMenuCtrl::GuiGameListMenuCtrl()
|
||||
: mSelected(NO_ROW),
|
||||
mHighlighted(NO_ROW),
|
||||
mDebugRender(false)
|
||||
{
|
||||
VECTOR_SET_ASSOCIATION(mRows);
|
||||
|
||||
// initialize the control callbacks
|
||||
mCallbackOnA = StringTable->insert("");
|
||||
mCallbackOnB = mCallbackOnA;
|
||||
mCallbackOnX = mCallbackOnA;
|
||||
mCallbackOnY = mCallbackOnA;
|
||||
}
|
||||
|
||||
GuiGameListMenuCtrl::~GuiGameListMenuCtrl()
|
||||
{
|
||||
for (S32 i = 0; i < mRows.size(); ++i)
|
||||
{
|
||||
delete mRows[i];
|
||||
}
|
||||
}
|
||||
|
||||
void GuiGameListMenuCtrl::onRender(Point2I offset, const RectI &updateRect)
|
||||
{
|
||||
GuiGameListMenuProfile * profile = (GuiGameListMenuProfile *) mProfile;
|
||||
|
||||
F32 xScale = (float) getWidth() / profile->getRowWidth();
|
||||
|
||||
bool profileHasIcons = profile->hasArrows();
|
||||
|
||||
S32 rowHeight = profile->getRowHeight();
|
||||
|
||||
Point2I currentOffset = offset;
|
||||
Point2I extent = getExtent();
|
||||
Point2I rowExtent(extent.x, rowHeight);
|
||||
Point2I textOffset(profile->mTextOffset.x * xScale, profile->mTextOffset.y);
|
||||
Point2I textExtent(extent.x - textOffset.x, rowHeight);
|
||||
Point2I iconExtent, iconOffset(0.0f, 0.0f);
|
||||
if (profileHasIcons)
|
||||
{
|
||||
iconExtent = profile->getIconExtent();
|
||||
|
||||
// icon is centered vertically plus any specified offset
|
||||
S32 iconOffsetY = (rowHeight - iconExtent.y) >> 1;
|
||||
iconOffsetY += profile->mIconOffset.y;
|
||||
iconOffset = Point2I(profile->mIconOffset.x * xScale, iconOffsetY);
|
||||
}
|
||||
for (Vector<Row *>::iterator row = mRows.begin(); row < mRows.end(); ++row)
|
||||
{
|
||||
if (row != mRows.begin())
|
||||
{
|
||||
// rows other than the first can have padding above them
|
||||
currentOffset.y += (*row)->mHeightPad;
|
||||
currentOffset.y += rowHeight;
|
||||
}
|
||||
|
||||
// select appropriate colors and textures
|
||||
ColorI fontColor;
|
||||
U32 buttonTextureIndex;
|
||||
S32 iconIndex = (*row)->mIconIndex;
|
||||
bool useHighlightIcon = (*row)->mUseHighlightIcon;
|
||||
if (! (*row)->mEnabled)
|
||||
{
|
||||
buttonTextureIndex = Profile::TEX_DISABLED;
|
||||
fontColor = profile->mFontColorNA;
|
||||
}
|
||||
else if (row == &mRows[mSelected])
|
||||
{
|
||||
if (iconIndex != NO_ICON)
|
||||
{
|
||||
iconIndex++;
|
||||
}
|
||||
buttonTextureIndex = Profile::TEX_SELECTED;
|
||||
fontColor = profile->mFontColorSEL;
|
||||
}
|
||||
else if ((mHighlighted != NO_ROW) && (row == &mRows[mHighlighted]))
|
||||
{
|
||||
if (iconIndex != NO_ICON && useHighlightIcon)
|
||||
{
|
||||
iconIndex++;
|
||||
}
|
||||
buttonTextureIndex = Profile::TEX_HIGHLIGHT;
|
||||
fontColor = profile->mFontColorHL;
|
||||
}
|
||||
else
|
||||
{
|
||||
buttonTextureIndex = Profile::TEX_NORMAL;
|
||||
fontColor = profile->mFontColor;
|
||||
}
|
||||
|
||||
// render the row bitmap
|
||||
GFX->getDrawUtil()->clearBitmapModulation();
|
||||
GFX->getDrawUtil()->drawBitmapStretchSR(profile->mTextureObject, RectI(currentOffset, rowExtent), profile->getBitmapArrayRect(buttonTextureIndex));
|
||||
|
||||
// render the row icon if it has one
|
||||
if ((iconIndex != NO_ICON) && profileHasIcons && (! profile->getBitmapArrayRect((U32)iconIndex).extent.isZero()))
|
||||
{
|
||||
iconIndex += Profile::TEX_FIRST_ICON;
|
||||
GFX->getDrawUtil()->clearBitmapModulation();
|
||||
GFX->getDrawUtil()->drawBitmapStretchSR(profile->mTextureObject, RectI(currentOffset + iconOffset, iconExtent), profile->getBitmapArrayRect(iconIndex));
|
||||
}
|
||||
|
||||
// render the row text
|
||||
GFX->getDrawUtil()->setBitmapModulation(fontColor);
|
||||
renderJustifiedText(currentOffset + textOffset, textExtent, (*row)->mLabel);
|
||||
}
|
||||
|
||||
if (mDebugRender)
|
||||
{
|
||||
onDebugRender(offset);
|
||||
}
|
||||
|
||||
renderChildControls(offset, updateRect);
|
||||
}
|
||||
|
||||
void GuiGameListMenuCtrl::onDebugRender(Point2I offset)
|
||||
{
|
||||
GuiGameListMenuProfile * profile = (GuiGameListMenuProfile *) mProfile;
|
||||
|
||||
F32 xScale = (float) getWidth() / profile->getRowWidth();
|
||||
|
||||
ColorI controlBorderColor(200, 200, 200); // gray
|
||||
ColorI rowBorderColor(255, 127, 255); // magenta
|
||||
ColorI hitBorderColor(255, 0, 0); // red
|
||||
Point2I shrinker(-1, -1);
|
||||
Point2I extent = getExtent();
|
||||
|
||||
// render a border around the entire control
|
||||
RectI borderRect(offset, extent + shrinker);
|
||||
GFX->getDrawUtil()->drawRect(borderRect, controlBorderColor);
|
||||
|
||||
S32 rowHeight = profile->getRowHeight();
|
||||
Point2I currentOffset(offset);
|
||||
Point2I rowExtent(extent.x, rowHeight);
|
||||
rowExtent += shrinker;
|
||||
Point2I hitAreaExtent(profile->getHitAreaExtent());
|
||||
hitAreaExtent.x *= xScale;
|
||||
hitAreaExtent += shrinker;
|
||||
Point2I hitAreaOffset = profile->mHitAreaUpperLeft;
|
||||
hitAreaOffset.x *= xScale;
|
||||
Point2I upperLeft;
|
||||
for (Vector<Row *>::iterator row = mRows.begin(); row < mRows.end(); ++row)
|
||||
{
|
||||
// set the top of the current row
|
||||
if (row != mRows.begin())
|
||||
{
|
||||
// rows other than the first can have padding above them
|
||||
currentOffset.y += (*row)->mHeightPad;
|
||||
currentOffset.y += rowHeight;
|
||||
}
|
||||
|
||||
// draw the box around the whole row's extent
|
||||
upperLeft = currentOffset;
|
||||
borderRect.point = upperLeft;
|
||||
borderRect.extent = rowExtent;
|
||||
GFX->getDrawUtil()->drawRect(borderRect, rowBorderColor);
|
||||
|
||||
// draw the box around the hit area of the row
|
||||
upperLeft = currentOffset + hitAreaOffset;
|
||||
borderRect.point = upperLeft;
|
||||
borderRect.extent = hitAreaExtent;
|
||||
GFX->getDrawUtil()->drawRect(borderRect, hitBorderColor);
|
||||
}
|
||||
}
|
||||
|
||||
void GuiGameListMenuCtrl::addRow(const char* label, const char* callback, S32 icon, S32 yPad, bool useHighlightIcon, bool enabled)
|
||||
{
|
||||
Row * row = new Row();
|
||||
addRow(row, label, callback, icon, yPad, useHighlightIcon, enabled);
|
||||
}
|
||||
|
||||
void GuiGameListMenuCtrl::addRow(Row * row, const char* label, const char* callback, S32 icon, S32 yPad, bool useHighlightIcon, bool enabled)
|
||||
{
|
||||
row->mLabel = StringTable->insert(label, true);
|
||||
row->mScriptCallback = (dStrlen(callback) > 0) ? StringTable->insert(callback, true) : NULL;
|
||||
row->mIconIndex = (icon < 0) ? NO_ICON : icon;
|
||||
row->mHeightPad = yPad;
|
||||
row->mUseHighlightIcon = useHighlightIcon;
|
||||
row->mEnabled = enabled;
|
||||
|
||||
mRows.push_back(row);
|
||||
|
||||
updateHeight();
|
||||
|
||||
if (mSelected == NO_ROW)
|
||||
{
|
||||
selectFirstEnabledRow();
|
||||
}
|
||||
}
|
||||
|
||||
Point2I GuiGameListMenuCtrl::getMinExtent() const
|
||||
{
|
||||
Point2I parentMin = Parent::getMinExtent();
|
||||
|
||||
GuiGameListMenuProfile * profile = (GuiGameListMenuProfile *) mProfile;
|
||||
|
||||
S32 minHeight = 0;
|
||||
S32 rowHeight = profile->getRowHeight();
|
||||
|
||||
for (Vector<Row *>::const_iterator row = mRows.begin(); row < mRows.end(); ++row)
|
||||
{
|
||||
minHeight += rowHeight;
|
||||
if (row != mRows.begin())
|
||||
{
|
||||
minHeight += (*row)->mHeightPad;
|
||||
}
|
||||
}
|
||||
|
||||
if (minHeight > parentMin.y)
|
||||
parentMin.y = minHeight;
|
||||
|
||||
return parentMin;
|
||||
}
|
||||
|
||||
bool GuiGameListMenuCtrl::onAdd()
|
||||
{
|
||||
if( !Parent::onAdd() )
|
||||
return false;
|
||||
|
||||
// If we have a non-GuiGameListMenuProfile profile, try to
|
||||
// substitute it for DefaultListMenuProfile.
|
||||
|
||||
if( !hasValidProfile() )
|
||||
{
|
||||
GuiGameListMenuProfile* profile;
|
||||
if( !Sim::findObject( "DefaultListMenuProfile", profile ) )
|
||||
{
|
||||
Con::errorf( "GuiGameListMenuCtrl: %s can't be created with a profile of type %s. Please create it with a profile of type GuiGameListMenuProfile.",
|
||||
getName(), mProfile->getClassName() );
|
||||
return false;
|
||||
}
|
||||
else
|
||||
Con::warnf( "GuiGameListMenuCtrl: substituted non-GuiGameListMenuProfile in %s for DefaultListMenuProfile", getName() );
|
||||
|
||||
setControlProfile( profile );
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool GuiGameListMenuCtrl::onWake()
|
||||
{
|
||||
if( !Parent::onWake() )
|
||||
return false;
|
||||
|
||||
if( !hasValidProfile() )
|
||||
return false;
|
||||
|
||||
if( mRows.empty() )
|
||||
{
|
||||
Con::errorf( "GuiGameListMenuCtrl: %s can't be woken up without any rows. Please use \"addRow\" to add at least one row to the control before pushing it to the canvas.",
|
||||
getName() );
|
||||
return false;
|
||||
}
|
||||
|
||||
enforceConstraints();
|
||||
|
||||
selectFirstEnabledRow();
|
||||
|
||||
setFirstResponder();
|
||||
|
||||
mHighlighted = NO_ROW;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool GuiGameListMenuCtrl::hasValidProfile() const
|
||||
{
|
||||
GuiGameListMenuProfile * profile = dynamic_cast<GuiGameListMenuProfile *>(mProfile);
|
||||
return profile;
|
||||
}
|
||||
|
||||
void GuiGameListMenuCtrl::enforceConstraints()
|
||||
{
|
||||
if( hasValidProfile() )
|
||||
{
|
||||
((GuiGameListMenuProfile *)mProfile)->enforceConstraints();
|
||||
}
|
||||
updateHeight();
|
||||
}
|
||||
|
||||
void GuiGameListMenuCtrl::updateHeight()
|
||||
{
|
||||
S32 minHeight = getMinExtent().y;
|
||||
if (getHeight() < minHeight)
|
||||
{
|
||||
setHeight(minHeight);
|
||||
}
|
||||
}
|
||||
|
||||
void GuiGameListMenuCtrl::onMouseDown(const GuiEvent &event)
|
||||
{
|
||||
S32 hitRow = getRow(event.mousePoint);
|
||||
if (hitRow != NO_ROW)
|
||||
{
|
||||
S32 delta = (mSelected != NO_ROW) ? (hitRow - mSelected) : (mSelected + 1);
|
||||
changeRow(delta);
|
||||
}
|
||||
}
|
||||
|
||||
void GuiGameListMenuCtrl::onMouseLeave(const GuiEvent &event)
|
||||
{
|
||||
mHighlighted = NO_ROW;
|
||||
}
|
||||
|
||||
void GuiGameListMenuCtrl::onMouseMove(const GuiEvent &event)
|
||||
{
|
||||
S32 hitRow = getRow(event.mousePoint);
|
||||
// allow mHighligetd to be set to NO_ROW so rows can be unhighlighted
|
||||
mHighlighted = hitRow;
|
||||
}
|
||||
|
||||
void GuiGameListMenuCtrl::onMouseUp(const GuiEvent &event)
|
||||
{
|
||||
S32 hitRow = getRow(event.mousePoint);
|
||||
if ((hitRow != NO_ROW) && isRowEnabled(hitRow) && (hitRow == getSelected()))
|
||||
{
|
||||
activateRow();
|
||||
}
|
||||
}
|
||||
|
||||
void GuiGameListMenuCtrl::activateRow()
|
||||
{
|
||||
S32 row = getSelected();
|
||||
if ((row != NO_ROW) && isRowEnabled(row) && (mRows[row]->mScriptCallback != NULL))
|
||||
{
|
||||
setThisControl();
|
||||
if (Con::isFunction(mRows[row]->mScriptCallback))
|
||||
{
|
||||
Con::executef(mRows[row]->mScriptCallback);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
S32 GuiGameListMenuCtrl::getRow(Point2I globalPoint)
|
||||
{
|
||||
Point2I localPoint = globalToLocalCoord(globalPoint);
|
||||
GuiGameListMenuProfile * profile = (GuiGameListMenuProfile *) mProfile;
|
||||
|
||||
F32 xScale = (float) getWidth() / profile->getRowWidth();
|
||||
|
||||
S32 rowHeight = profile->getRowHeight();
|
||||
Point2I currentOffset(0, 0);
|
||||
Point2I hitAreaUpperLeft = profile->mHitAreaUpperLeft;
|
||||
hitAreaUpperLeft.x *= xScale;
|
||||
Point2I hitAreaLowerRight = profile->mHitAreaLowerRight;
|
||||
hitAreaLowerRight.x *= xScale;
|
||||
|
||||
Point2I upperLeft, lowerRight;
|
||||
for (Vector<Row *>::iterator row = mRows.begin(); row < mRows.end(); ++row)
|
||||
{
|
||||
if (row != mRows.begin())
|
||||
{
|
||||
// rows other than the first can have padding above them
|
||||
currentOffset.y += (*row)->mHeightPad;
|
||||
}
|
||||
|
||||
upperLeft = currentOffset + hitAreaUpperLeft;
|
||||
lowerRight = currentOffset + hitAreaLowerRight;
|
||||
|
||||
if ((upperLeft.x <= localPoint.x) && (localPoint.x < lowerRight.x) &&
|
||||
(upperLeft.y <= localPoint.y) && (localPoint.y < lowerRight.y))
|
||||
{
|
||||
return row - mRows.begin();
|
||||
}
|
||||
|
||||
currentOffset.y += rowHeight;
|
||||
}
|
||||
|
||||
return NO_ROW;
|
||||
}
|
||||
|
||||
void GuiGameListMenuCtrl::setSelected(S32 index)
|
||||
{
|
||||
if (index == NO_ROW)
|
||||
{
|
||||
// deselection
|
||||
mSelected = NO_ROW;
|
||||
return;
|
||||
}
|
||||
|
||||
if (! isValidRowIndex(index))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (! isRowEnabled(index))
|
||||
{
|
||||
// row is disabled, it can't be selected
|
||||
return;
|
||||
}
|
||||
|
||||
mSelected = mClamp(index, 0, mRows.size() - 1);
|
||||
}
|
||||
|
||||
bool GuiGameListMenuCtrl::isRowEnabled(S32 index) const
|
||||
{
|
||||
if (! isValidRowIndex(index))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return mRows[index]->mEnabled;
|
||||
}
|
||||
|
||||
void GuiGameListMenuCtrl::setRowEnabled(S32 index, bool enabled)
|
||||
{
|
||||
if (! isValidRowIndex(index))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
mRows[index]->mEnabled = enabled;
|
||||
|
||||
if (getSelected() == index)
|
||||
{
|
||||
selectFirstEnabledRow();
|
||||
}
|
||||
}
|
||||
|
||||
bool GuiGameListMenuCtrl::isValidRowIndex(S32 index) const
|
||||
{
|
||||
return ((0 <= index) && (index < mRows.size()));
|
||||
}
|
||||
|
||||
void GuiGameListMenuCtrl::selectFirstEnabledRow()
|
||||
{
|
||||
setSelected(NO_ROW);
|
||||
for (Vector<Row *>::iterator row = mRows.begin(); row < mRows.end(); ++row)
|
||||
{
|
||||
if ((*row)->mEnabled)
|
||||
{
|
||||
setSelected(row - mRows.begin());
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool GuiGameListMenuCtrl::onKeyDown(const GuiEvent &event)
|
||||
{
|
||||
switch (event.keyCode)
|
||||
{
|
||||
case KEY_UP:
|
||||
changeRow(-1);
|
||||
return true;
|
||||
|
||||
case KEY_DOWN:
|
||||
changeRow(1);
|
||||
return true;
|
||||
|
||||
case KEY_A:
|
||||
case KEY_RETURN:
|
||||
case KEY_NUMPADENTER:
|
||||
case KEY_SPACE:
|
||||
case XI_A:
|
||||
case XI_START:
|
||||
doScriptCommand(mCallbackOnA);
|
||||
return true;
|
||||
|
||||
case KEY_B:
|
||||
case KEY_ESCAPE:
|
||||
case KEY_BACKSPACE:
|
||||
case KEY_DELETE:
|
||||
case XI_B:
|
||||
case XI_BACK:
|
||||
doScriptCommand(mCallbackOnB);
|
||||
return true;
|
||||
|
||||
case KEY_X:
|
||||
case XI_X:
|
||||
doScriptCommand(mCallbackOnX);
|
||||
return true;
|
||||
|
||||
case KEY_Y:
|
||||
case XI_Y:
|
||||
doScriptCommand(mCallbackOnY);
|
||||
return true;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return Parent::onKeyDown(event);
|
||||
}
|
||||
|
||||
bool GuiGameListMenuCtrl::onGamepadAxisUp(const GuiEvent &event)
|
||||
{
|
||||
changeRow(-1);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool GuiGameListMenuCtrl::onGamepadAxisDown(const GuiEvent &event)
|
||||
{
|
||||
changeRow(1);
|
||||
return true;
|
||||
}
|
||||
|
||||
void GuiGameListMenuCtrl::doScriptCommand(StringTableEntry command)
|
||||
{
|
||||
if (command && command[0])
|
||||
{
|
||||
setThisControl();
|
||||
Con::evaluate(command, false, __FILE__);
|
||||
}
|
||||
}
|
||||
|
||||
void GuiGameListMenuCtrl::changeRow(S32 delta)
|
||||
{
|
||||
S32 oldRowIndex = getSelected();
|
||||
S32 newRowIndex = oldRowIndex;
|
||||
do
|
||||
{
|
||||
newRowIndex += delta;
|
||||
if (newRowIndex >= mRows.size())
|
||||
{
|
||||
newRowIndex = 0;
|
||||
}
|
||||
else if (newRowIndex < 0)
|
||||
{
|
||||
newRowIndex = mRows.size() - 1;
|
||||
}
|
||||
}
|
||||
while ((! mRows[newRowIndex]->mEnabled) && (newRowIndex != oldRowIndex));
|
||||
|
||||
setSelected(newRowIndex);
|
||||
|
||||
// do the callback
|
||||
onChange_callback();
|
||||
}
|
||||
|
||||
void GuiGameListMenuCtrl::setThisControl()
|
||||
{
|
||||
smThisControl = this;
|
||||
}
|
||||
|
||||
StringTableEntry GuiGameListMenuCtrl::getRowLabel(S32 rowIndex) const
|
||||
{
|
||||
AssertFatal(isValidRowIndex(rowIndex), avar("GuiGameListMenuCtrl: You can't get the label from row %d of %s because it is not a valid row index. Please specify a valid row index in the range [0, %d).", rowIndex, getName(), getRowCount()));
|
||||
if (! isValidRowIndex(rowIndex))
|
||||
{
|
||||
// not a valid row index, don't do anything
|
||||
return StringTable->insert("");
|
||||
}
|
||||
return mRows[rowIndex]->mLabel;
|
||||
}
|
||||
|
||||
void GuiGameListMenuCtrl::setRowLabel(S32 rowIndex, const char * label)
|
||||
{
|
||||
AssertFatal(isValidRowIndex(rowIndex), avar("GuiGameListMenuCtrl: You can't set the label on row %d of %s because it is not a valid row index. Please specify a valid row index in the range [0, %d).", rowIndex, getName(), getRowCount()));
|
||||
if (! isValidRowIndex(rowIndex))
|
||||
{
|
||||
// not a valid row index, don't do anything
|
||||
return;
|
||||
}
|
||||
|
||||
mRows[rowIndex]->mLabel = StringTable->insert(label, true);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Console stuff (GuiGameListMenuCtrl)
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
IMPLEMENT_CONOBJECT(GuiGameListMenuCtrl);
|
||||
|
||||
ConsoleDocClass( GuiGameListMenuCtrl,
|
||||
"@brief A base class for cross platform menu controls that are gamepad friendly.\n\n"
|
||||
|
||||
"This class is used to build row-based menu GUIs that can be easily navigated "
|
||||
"using the keyboard, mouse or gamepad. The desired row can be selected using "
|
||||
"the mouse, or by navigating using the Up and Down buttons.\n\n"
|
||||
|
||||
"@tsexample\n\n"
|
||||
"new GuiGameListMenuCtrl()\n"
|
||||
"{\n"
|
||||
" debugRender = \"0\";\n"
|
||||
" callbackOnA = \"applyOptions();\";\n"
|
||||
" callbackOnB = \"Canvas.setContent(MainMenuGui);\";\n"
|
||||
" callbackOnX = \"\";\n"
|
||||
" callbackOnY = \"revertOptions();\";\n"
|
||||
" //Properties not specific to this control have been omitted from this example.\n"
|
||||
"};\n"
|
||||
"@endtsexample\n\n"
|
||||
|
||||
"@see GuiGameListMenuProfile\n\n"
|
||||
|
||||
"@ingroup GuiGame"
|
||||
);
|
||||
|
||||
IMPLEMENT_CALLBACK( GuiGameListMenuCtrl, onChange, void, (), (),
|
||||
"Called when the selected row changes." );
|
||||
|
||||
void GuiGameListMenuCtrl::initPersistFields()
|
||||
{
|
||||
addField("debugRender", TypeBool, Offset(mDebugRender, GuiGameListMenuCtrl),
|
||||
"Enable debug rendering" );
|
||||
|
||||
addField("callbackOnA", TypeString, Offset(mCallbackOnA, GuiGameListMenuCtrl),
|
||||
"Script callback when the 'A' button is pressed. 'A' inputs are Keyboard: A, Return, Space; Gamepad: A, Start" );
|
||||
|
||||
addField("callbackOnB", TypeString, Offset(mCallbackOnB, GuiGameListMenuCtrl),
|
||||
"Script callback when the 'B' button is pressed. 'B' inputs are Keyboard: B, Esc, Backspace, Delete; Gamepad: B, Back" );
|
||||
|
||||
addField("callbackOnX", TypeString, Offset(mCallbackOnX, GuiGameListMenuCtrl),
|
||||
"Script callback when the 'X' button is pressed. 'X' inputs are Keyboard: X; Gamepad: X" );
|
||||
|
||||
addField("callbackOnY", TypeString, Offset(mCallbackOnY, GuiGameListMenuCtrl),
|
||||
"Script callback when the 'Y' button is pressed. 'Y' inputs are Keyboard: Y; Gamepad: Y" );
|
||||
|
||||
Parent::initPersistFields();
|
||||
}
|
||||
|
||||
DefineEngineMethod( GuiGameListMenuCtrl, addRow, void,
|
||||
( const char* label, const char* callback, S32 icon, S32 yPad, bool useHighlightIcon, bool enabled ),
|
||||
( -1, 0, true, true ),
|
||||
"Add a row to the list control.\n\n"
|
||||
"@param label The text to display on the row as a label.\n"
|
||||
"@param callback Name of a script function to use as a callback when this row is activated.\n"
|
||||
"@param icon [optional] Index of the icon to use as a marker.\n"
|
||||
"@param yPad [optional] An extra amount of height padding before the row. Does nothing on the first row.\n"
|
||||
"@param useHighlightIcon [optional] Does this row use the highlight icon?.\n"
|
||||
"@param enabled [optional] If this row is initially enabled." )
|
||||
{
|
||||
object->addRow( label, callback, icon, yPad, useHighlightIcon, enabled );
|
||||
}
|
||||
|
||||
DefineEngineMethod( GuiGameListMenuCtrl, isRowEnabled, bool, ( S32 row ),,
|
||||
"Determines if the specified row is enabled or disabled.\n\n"
|
||||
"@param row The row to set the enabled status of.\n"
|
||||
"@return True if the specified row is enabled. False if the row is not enabled or the given index was not valid." )
|
||||
{
|
||||
return object->isRowEnabled( row );
|
||||
}
|
||||
|
||||
DefineEngineMethod( GuiGameListMenuCtrl, setRowEnabled, void, ( S32 row, bool enabled ),,
|
||||
"Sets a row's enabled status according to the given parameters.\n\n"
|
||||
"@param row The index to check for validity.\n"
|
||||
"@param enabled Indicate true to enable the row or false to disable it." )
|
||||
{
|
||||
object->setRowEnabled( row, enabled );
|
||||
}
|
||||
|
||||
DefineEngineMethod( GuiGameListMenuCtrl, activateRow, void, (),,
|
||||
"Activates the current row. The script callback of the current row will be called (if it has one)." )
|
||||
{
|
||||
object->activateRow();
|
||||
}
|
||||
|
||||
DefineEngineMethod( GuiGameListMenuCtrl, getRowCount, S32, (),,
|
||||
"Gets the number of rows on the control.\n\n"
|
||||
"@return (int) The number of rows on the control." )
|
||||
{
|
||||
return object->getRowCount();
|
||||
}
|
||||
|
||||
DefineEngineMethod( GuiGameListMenuCtrl, getRowLabel, const char *, ( S32 row ),,
|
||||
"Gets the label displayed on the specified row.\n\n"
|
||||
"@param row Index of the row to get the label of.\n"
|
||||
"@return The label for the row." )
|
||||
{
|
||||
return object->getRowLabel( row );
|
||||
}
|
||||
|
||||
DefineEngineMethod( GuiGameListMenuCtrl, setRowLabel, void, ( S32 row, const char* label ),,
|
||||
"Sets the label on the given row.\n\n"
|
||||
"@param row Index of the row to set the label on.\n"
|
||||
"@param label Text to set as the label of the row.\n" )
|
||||
{
|
||||
object->setRowLabel( row, label );
|
||||
}
|
||||
|
||||
DefineEngineMethod( GuiGameListMenuCtrl, setSelected, void, ( S32 row ),,
|
||||
"Sets the selected row. Only rows that are enabled can be selected.\n\n"
|
||||
"@param row Index of the row to set as selected." )
|
||||
{
|
||||
object->setSelected( row );
|
||||
}
|
||||
|
||||
DefineEngineMethod( GuiGameListMenuCtrl, getSelectedRow, S32, (),,
|
||||
"Gets the index of the currently selected row.\n\n"
|
||||
"@return Index of the selected row." )
|
||||
{
|
||||
return object->getSelected();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// GuiGameListMenuProfile
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
GuiGameListMenuProfile::GuiGameListMenuProfile()
|
||||
: mHitAreaUpperLeft(0, 0),
|
||||
mHitAreaLowerRight(0, 0),
|
||||
mIconOffset(0, 0),
|
||||
mRowSize(0, 0),
|
||||
mRowScale(1.0f, 1.0f)
|
||||
{
|
||||
}
|
||||
|
||||
bool GuiGameListMenuProfile::onAdd()
|
||||
{
|
||||
if (! Parent::onAdd())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// We can't call enforceConstraints() here because incRefCount initializes
|
||||
// some of the things to enforce. Do a basic sanity check here instead.
|
||||
|
||||
if( !dStrlen(mBitmapName) )
|
||||
{
|
||||
Con::errorf( "GuiGameListMenuProfile: %s can't be created without a bitmap. Please add a 'Bitmap' property to the object definition.", getName() );
|
||||
return false;
|
||||
}
|
||||
|
||||
if( mRowSize.x < 0 )
|
||||
{
|
||||
Con::errorf( "GuiGameListMenuProfile: %s can't have a negative row width. Please change the row width to be non-negative.", getName() );
|
||||
return false;
|
||||
}
|
||||
|
||||
if( mRowSize.y < 0 )
|
||||
{
|
||||
Con::errorf( "GuiGameListMenuProfile: %s can't have a negative row height. Please change the row height to be non-negative.", getName() );
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void GuiGameListMenuProfile::enforceConstraints()
|
||||
{
|
||||
if( getBitmapArrayRect(0).extent.isZero() )
|
||||
Con::errorf( "GuiGameListMenuCtrl: %s can't be created without a bitmap. Please add a bitmap to the profile's definition.", getName() );
|
||||
|
||||
if( mRowSize.x < 0 )
|
||||
Con::errorf( "GuiGameListMenuProfile: %s can't have a negative row width. Please change the row width to be non-negative.", getName() );
|
||||
mRowSize.x = getMax(mRowSize.x, 0);
|
||||
|
||||
if( mRowSize.y < 0 )
|
||||
Con::errorf( "GuiGameListMenuProfile: %s can't have a negative row height. Please change the row height to be non-negative.", getName() );
|
||||
mRowSize.y = getMax(mRowSize.y, 0);
|
||||
|
||||
Point2I rowTexExtent = getBitmapArrayRect(TEX_NORMAL).extent;
|
||||
mRowScale.x = (float) getRowWidth() / rowTexExtent.x;
|
||||
mRowScale.y = (float) getRowHeight() / rowTexExtent.y;
|
||||
}
|
||||
|
||||
Point2I GuiGameListMenuProfile::getIconExtent()
|
||||
{
|
||||
Point2I iconExtent = getBitmapArrayRect(TEX_FIRST_ICON).extent;
|
||||
|
||||
// scale both by y to keep the aspect ratio
|
||||
iconExtent.x *= mRowScale.y;
|
||||
iconExtent.y *= mRowScale.y;
|
||||
|
||||
return iconExtent;
|
||||
}
|
||||
|
||||
Point2I GuiGameListMenuProfile::getArrowExtent()
|
||||
{
|
||||
Point2I arrowExtent = getBitmapArrayRect(TEX_FIRST_ARROW).extent;
|
||||
|
||||
// scale both by y to keep the aspect ratio
|
||||
arrowExtent.x *= mRowScale.y;
|
||||
arrowExtent.y *= mRowScale.y;
|
||||
|
||||
return arrowExtent;
|
||||
}
|
||||
|
||||
Point2I GuiGameListMenuProfile::getHitAreaExtent()
|
||||
{
|
||||
if (mHitAreaLowerRight == mHitAreaUpperLeft)
|
||||
{
|
||||
return mRowSize;
|
||||
}
|
||||
else
|
||||
{
|
||||
return mHitAreaLowerRight - mHitAreaUpperLeft;
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Console stuff (GuiGameListMenuProfile)
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
IMPLEMENT_CONOBJECT(GuiGameListMenuProfile);
|
||||
|
||||
ConsoleDocClass( GuiGameListMenuProfile,
|
||||
"@brief A GuiControlProfile with additional fields specific to GuiGameListMenuCtrl.\n\n"
|
||||
|
||||
"@tsexample\n"
|
||||
"new GuiGameListMenuProfile()\n"
|
||||
"{\n"
|
||||
" hitAreaUpperLeft = \"10 2\";\n"
|
||||
" hitAreaLowerRight = \"190 18\";\n"
|
||||
" iconOffset = \"10 2\";\n"
|
||||
" rowSize = \"200 20\";\n"
|
||||
" //Properties not specific to this control have been omitted from this example.\n"
|
||||
"};\n"
|
||||
"@endtsexample\n\n"
|
||||
|
||||
"@ingroup GuiGame"
|
||||
);
|
||||
|
||||
void GuiGameListMenuProfile::initPersistFields()
|
||||
{
|
||||
addField( "hitAreaUpperLeft", TypePoint2I, Offset(mHitAreaUpperLeft, GuiGameListMenuProfile),
|
||||
"Position of the upper left corner of the row hit area (relative to row's top left corner)" );
|
||||
|
||||
addField( "hitAreaLowerRight", TypePoint2I, Offset(mHitAreaLowerRight, GuiGameListMenuProfile),
|
||||
"Position of the lower right corner of the row hit area (relative to row's top left corner)" );
|
||||
|
||||
addField( "iconOffset", TypePoint2I, Offset(mIconOffset, GuiGameListMenuProfile),
|
||||
"Offset from the row's top left corner at which to render the row icon" );
|
||||
|
||||
addField( "rowSize", TypePoint2I, Offset(mRowSize, GuiGameListMenuProfile),
|
||||
"The base size (\"width height\") of a row" );
|
||||
|
||||
Parent::initPersistFields();
|
||||
|
||||
removeField("tab");
|
||||
removeField("mouseOverSelected");
|
||||
|
||||
removeField("modal");
|
||||
removeField("opaque");
|
||||
removeField("fillColor");
|
||||
removeField("fillColorHL");
|
||||
removeField("fillColorNA");
|
||||
removeField("border");
|
||||
removeField("borderThickness");
|
||||
removeField("borderColor");
|
||||
removeField("borderColorHL");
|
||||
removeField("borderColorNA");
|
||||
|
||||
removeField("bevelColorHL");
|
||||
removeField("bevelColorLL");
|
||||
|
||||
removeField("fontColorLink");
|
||||
removeField("fontColorLinkHL");
|
||||
|
||||
removeField("justify");
|
||||
removeField("returnTab");
|
||||
removeField("numbersOnly");
|
||||
removeField("cursorColor");
|
||||
|
||||
removeField("profileForChildren");
|
||||
}
|
||||
354
Engine/source/gui/controls/guiGameListMenuCtrl.h
Normal file
354
Engine/source/gui/controls/guiGameListMenuCtrl.h
Normal file
|
|
@ -0,0 +1,354 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// Copyright (c) 2012 GarageGames, LLC
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to
|
||||
// deal in the Software without restriction, including without limitation the
|
||||
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
// sell copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
// IN THE SOFTWARE.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef _GuiGameListMenuCtrl_H_
|
||||
#define _GuiGameListMenuCtrl_H_
|
||||
|
||||
#include "gui/core/guiControl.h"
|
||||
|
||||
class GuiGameListMenuProfile;
|
||||
|
||||
/// \class GuiGameListMenuCtrl
|
||||
/// A base class for cross platform menu controls that are gamepad friendly.
|
||||
class GuiGameListMenuCtrl : public GuiControl
|
||||
{
|
||||
public:
|
||||
typedef GuiControl Parent;
|
||||
typedef GuiGameListMenuProfile Profile;
|
||||
|
||||
protected:
|
||||
/// \struct Row
|
||||
/// Internal data representation of a single row in the control.
|
||||
struct Row
|
||||
{
|
||||
StringTableEntry mLabel; ///< Text to display in the row as a label
|
||||
StringTableEntry mScriptCallback; ///< Script callback when row is activated
|
||||
S32 mIconIndex; ///< Index of the icon to display on the row (-1 = no icon)
|
||||
S32 mHeightPad; ///< Extra amount to pad above this row
|
||||
bool mUseHighlightIcon; ///< Toggle the use of the highlight icon
|
||||
bool mEnabled; ///< If this row is enabled or not (grayed out)
|
||||
|
||||
virtual ~Row() {}
|
||||
};
|
||||
|
||||
public:
|
||||
/// \return The index of the highlighted row or NO_ROW if none of the rows
|
||||
/// are currently highlighted.
|
||||
virtual S32 getHighlighted() const { return mHighlighted; }
|
||||
|
||||
/// \return The index of the selected row or NO_ROW if none of the rows are
|
||||
/// currently selected.
|
||||
virtual S32 getSelected() const { return mSelected; }
|
||||
|
||||
/// Sets the selected row. Only rows that are enabled can be selected. Input is
|
||||
/// clamped to [0, mRows.size())
|
||||
///
|
||||
/// \param index The index to set as selected.
|
||||
virtual void setSelected(S32 index);
|
||||
|
||||
/// Determines if the specified row is enabled or disabled.
|
||||
///
|
||||
/// \param index Index of the row to check.
|
||||
/// \return True if the specified row is enabled. False if the row is not
|
||||
/// enabled or the given index was not valid.
|
||||
virtual bool isRowEnabled(S32 index) const;
|
||||
|
||||
/// Sets a row's enabled status according to the given parameters.
|
||||
///
|
||||
/// \param index The row to set the enabled status of.
|
||||
/// \param enabled Indicate true to enable the row or false to disable it.
|
||||
virtual void setRowEnabled(S32 index, bool enabled);
|
||||
|
||||
/// Gets the label displayed on the specified row.
|
||||
///
|
||||
/// \param rowIndex Index of the row to get the label of.
|
||||
/// \return The label for the row.
|
||||
virtual StringTableEntry getRowLabel(S32 rowIndex) const;
|
||||
|
||||
/// Sets the label on the given row.
|
||||
///
|
||||
/// \param rowIndex Index of the row to set the label on.
|
||||
/// \param label Text to set as the label of the row.
|
||||
virtual void setRowLabel(S32 rowIndex, const char * label);
|
||||
|
||||
/// Adds a row to the control.
|
||||
///
|
||||
/// \param label The text to display on the row as a label.
|
||||
/// \param callback Name of a script function to use as a callback when this
|
||||
/// row is activated.
|
||||
/// \param icon [optional] Index of the icon to use as a marker. Default -1
|
||||
/// means no icon will be shown on this row.
|
||||
/// \param yPad [optional] An extra amount of height padding before the row.
|
||||
/// \param enabled [optional] If this row is initially enabled. Default true.
|
||||
virtual void addRow(const char* label, const char* callback, S32 icon = -1, S32 yPad = 0, bool useHighlightIcon = true, bool enabled = true);
|
||||
|
||||
/// Activates the current row. The script callback of the current row will
|
||||
/// be called (if it has one).
|
||||
virtual void activateRow();
|
||||
|
||||
/// Gets the number of rows in the control.
|
||||
///
|
||||
/// \return The number of rows in this control.
|
||||
virtual S32 getRowCount() const { return mRows.size(); }
|
||||
|
||||
GuiGameListMenuCtrl();
|
||||
~GuiGameListMenuCtrl();
|
||||
|
||||
void onRender(Point2I offset, const RectI &updateRect);
|
||||
|
||||
/// Callback when the object is registered with the sim.
|
||||
///
|
||||
/// \return True if the profile was successfully added, false otherwise.
|
||||
bool onAdd();
|
||||
|
||||
/// Callback when the control wakes up.
|
||||
bool onWake();
|
||||
|
||||
/// Callback when a key is pressed.
|
||||
///
|
||||
/// \param event The event that triggered this callback.
|
||||
bool onKeyDown(const GuiEvent &event);
|
||||
|
||||
/// Callback when a key is repeating.
|
||||
///
|
||||
/// \param event The event that triggered this callback.
|
||||
bool onKeyRepeat(const GuiEvent &event){ return onKeyDown(event); }
|
||||
|
||||
/// Callback when the mouse button is clicked on the control.
|
||||
///
|
||||
/// \param event A reference to the event that triggered the callback.
|
||||
void onMouseDown(const GuiEvent &event);
|
||||
|
||||
/// Callback when the mouse is dragged on the control.
|
||||
///
|
||||
/// \param event A reference to the event that triggered the callback.
|
||||
void onMouseDragged(const GuiEvent &event){ onMouseDown(event); }
|
||||
|
||||
/// Callback when the mouse leaves the control.
|
||||
///
|
||||
/// \param event A reference to the event that triggered the callback.
|
||||
void onMouseLeave(const GuiEvent &event);
|
||||
|
||||
/// Callback when the mouse is moving over this control
|
||||
///
|
||||
/// \param event A reference to the event that triggered the callback.
|
||||
void onMouseMove(const GuiEvent &event);
|
||||
|
||||
/// Callback when the mouse button is released.
|
||||
///
|
||||
/// \param event A reference to the event that triggered the callback.
|
||||
void onMouseUp(const GuiEvent &event);
|
||||
|
||||
/// Callback when the gamepad axis is activated.
|
||||
///
|
||||
/// \param event A reference to the event that triggered the callback.
|
||||
virtual bool onGamepadAxisUp(const GuiEvent & event);
|
||||
|
||||
/// Callback when the gamepad axis is activated.
|
||||
///
|
||||
/// \param event A reference to the event that triggered the callback.
|
||||
virtual bool onGamepadAxisDown(const GuiEvent & event);
|
||||
|
||||
DECLARE_CONOBJECT(GuiGameListMenuCtrl);
|
||||
DECLARE_CATEGORY( "Gui Game" );
|
||||
DECLARE_DESCRIPTION( "Base class for cross platform menu controls that are gamepad friendly." );
|
||||
|
||||
/// Initializes fields accessible through the console.
|
||||
static void initPersistFields();
|
||||
|
||||
static const S32 NO_ROW = -1; ///< Indicates a query result of no row found.
|
||||
static const S32 NO_ICON = -1; ///< Indicates a row has no extra icon available
|
||||
|
||||
protected:
|
||||
/// Adds a row to the control.
|
||||
///
|
||||
/// \param row A reference to the row object to fill.
|
||||
/// \param label The text to display on the row as a label.
|
||||
/// \param callback Name of a script function to use as a callback when this
|
||||
/// row is activated.
|
||||
/// \param icon [optional] Index of the icon to use as a marker. Default -1
|
||||
/// means no icon will be shown on this row.
|
||||
/// \param yPad [optional] An extra amount of height padding before the row.
|
||||
/// \param enabled [optional] If this row is initially enabled. Default true.
|
||||
virtual void addRow(Row * row, const char* label, const char* callback, S32 icon, S32 yPad, bool useHighlightIcon, bool enabled);
|
||||
|
||||
/// Determines if the given index is a valid row index. Any index pointing at
|
||||
/// an existing row is valid.
|
||||
///
|
||||
/// \param index The index to check for validity.
|
||||
/// \return True if the index points at a valid row, false otherwise.
|
||||
virtual bool isValidRowIndex(S32 index) const;
|
||||
|
||||
/// Sets the script variable $ThisControl to reflect this control.
|
||||
virtual void setThisControl();
|
||||
|
||||
/// Called to implement debug rendering which displays colored lines to
|
||||
/// provide visual feedback on extents and hit zones.
|
||||
virtual void onDebugRender(Point2I offset);
|
||||
|
||||
/// Looks up the row having a hit area at the given global point.
|
||||
///
|
||||
/// \param globalPoint The point we want to check for hitting a row.
|
||||
/// \return The index of the hit row or NO_ROW if no row was hit.
|
||||
virtual S32 getRow(Point2I globalPoint);
|
||||
|
||||
/// Checks to make sure our control has a profile of the correct type.
|
||||
///
|
||||
/// \return True if the profile is of type GuiGameListMenuProfile or false if
|
||||
/// the profile is of any other type.
|
||||
virtual bool hasValidProfile() const;
|
||||
|
||||
/// Enforces the validity of the fields on this control and its profile (if
|
||||
/// the profile is valid, see: hasValidProfile).
|
||||
virtual void enforceConstraints();
|
||||
|
||||
/// @name Callbacks
|
||||
/// @{
|
||||
DECLARE_CALLBACK( void, onChange, () );
|
||||
/// @}
|
||||
|
||||
/// Evaluates some script. If the command is empty then nothing is evaluated.
|
||||
///
|
||||
/// \param command The script to evaluate.
|
||||
void doScriptCommand(StringTableEntry command);
|
||||
|
||||
StringTableEntry mCallbackOnA; ///< Script callback when the 'A' button is pressed
|
||||
StringTableEntry mCallbackOnB; ///< Script callback when the 'B' button is pressed
|
||||
StringTableEntry mCallbackOnX; ///< Script callback when the 'X' button is pressed
|
||||
StringTableEntry mCallbackOnY; ///< Script callback when the 'Y' button is pressed
|
||||
|
||||
bool mDebugRender; ///< Determines when to show debug render lines
|
||||
Vector<Row *> mRows; ///< Holds data wrappers on all the rows we have
|
||||
|
||||
private:
|
||||
/// Recalculates the height of this control based on the stored row height and
|
||||
/// and padding on the rows.
|
||||
virtual Point2I getMinExtent() const;
|
||||
|
||||
/// Makes sure the height will allow all rows to be displayed without being
|
||||
/// truncated.
|
||||
void updateHeight();
|
||||
|
||||
/// Sets the first enabled row as selected. If there are no enabled rows then
|
||||
/// selected will be set to NO_ROW.
|
||||
void selectFirstEnabledRow();
|
||||
|
||||
/// Changes the currently selected row.
|
||||
///
|
||||
/// \param delta The amount to change the row selection by. Typically this will
|
||||
/// be 1 or -1.
|
||||
void changeRow(S32 delta);
|
||||
|
||||
S32 mSelected; ///< index of the currently selected row
|
||||
S32 mHighlighted; ///< index of the currently highlighted row
|
||||
};
|
||||
|
||||
/// \class GuiGameListMenuProfile
|
||||
/// A gui profile with additional fields specific to GuiGameListMenuCtrl.
|
||||
class GuiGameListMenuProfile : public GuiControlProfile
|
||||
{
|
||||
typedef GuiControlProfile Parent;
|
||||
|
||||
public:
|
||||
/// Enforces range constraints on all required fields.
|
||||
virtual void enforceConstraints();
|
||||
|
||||
/// Get the height of rows in this profile. All rows are considered to be the
|
||||
/// same base height. Rows can have an extra amount of y padding defined when
|
||||
/// they are added to the control.
|
||||
///
|
||||
/// \return The height of rows in this profile.
|
||||
S32 getRowHeight() { return (mRowSize.y) ? mRowSize.y : getBitmapArrayRect(TEX_NORMAL).extent.y; }
|
||||
|
||||
/// Get the width of rows in this profile. All rows are considered to be the
|
||||
/// same width.
|
||||
///
|
||||
/// \return The width of rows in this profile.
|
||||
S32 getRowWidth() { return (mRowSize.x) ? mRowSize.x : getBitmapArrayRect(TEX_NORMAL).extent.x; }
|
||||
|
||||
/// Row scale is the ratio between the defined row size and the raw size of
|
||||
/// the bitmap.
|
||||
///
|
||||
/// \return The row scale.
|
||||
const Point2F & getRowScale() const { return mRowScale; }
|
||||
|
||||
/// Gets the extent of icons for this profile. If there are no icons you will
|
||||
/// get a point of (0, 0);
|
||||
///
|
||||
/// \return The extent of icons or (0, 0) if there aren't any.
|
||||
Point2I getIconExtent();
|
||||
|
||||
/// Gets the extent of arrows for this profile. If there are no arrows you
|
||||
/// will get a point of (0, 0).
|
||||
///
|
||||
/// \return The extent of icons or (0, 0) if there aren't any.
|
||||
Point2I getArrowExtent();
|
||||
|
||||
/// Gets the extent of the defined hit area for this profile. If the hit area
|
||||
/// is not defined then it defaults to the full size of a row.
|
||||
///
|
||||
/// \return The extents of the defined hit area or the full size of the row.
|
||||
Point2I getHitAreaExtent();
|
||||
|
||||
/// Determines if this profile has textures for the left and right arrows.
|
||||
///
|
||||
/// \return True if the profile's bitmap has textures for the arrows, false
|
||||
/// otherwise.
|
||||
bool hasArrows(){ return (! getBitmapArrayRect(TEX_FIRST_ARROW).extent.isZero()); }
|
||||
|
||||
/// Callback when the object is registered with the sim.
|
||||
///
|
||||
/// \return True if the profile was successfully added, false otherwise.
|
||||
bool onAdd();
|
||||
|
||||
Point2I mHitAreaUpperLeft; ///< Offset for the upper left corner of the hit area
|
||||
Point2I mHitAreaLowerRight; ///< Offset for the lower right corner of the hit area
|
||||
Point2I mIconOffset; ///< Offset for a row's extra icon
|
||||
Point2I mRowSize; ///< The base size of a row
|
||||
|
||||
GuiGameListMenuProfile();
|
||||
|
||||
DECLARE_CONOBJECT(GuiGameListMenuProfile);
|
||||
|
||||
/// Initializes fields accessible through the console.
|
||||
static void initPersistFields();
|
||||
|
||||
enum
|
||||
{
|
||||
TEX_NORMAL = 0, ///< texture index for a normal, unselected row
|
||||
TEX_SELECTED = 1, ///< texture index for a selected row
|
||||
TEX_HIGHLIGHT = 2, ///< texture index for a highlighted row (moused over, not selected)
|
||||
TEX_DISABLED = 3, ///< texture index for a disabled row
|
||||
TEX_L_ARROW_OFF = 4, ///< texture index for the left arrow of an unselected row
|
||||
TEX_L_ARROW_ON = 5, ///< texture index for the left arrow of a selected row
|
||||
TEX_R_ARROW_OFF = 6, ///< texture index for the right arrow of an unselected row
|
||||
TEX_R_ARROW_ON = 7, ///< texture index for the right arrow of a selected row
|
||||
|
||||
TEX_FIRST_ARROW = 4, ///< texture index for the first arrow
|
||||
TEX_FIRST_ICON = 8, ///< texture index for the first row marker icon
|
||||
};
|
||||
|
||||
private:
|
||||
Point2F mRowScale; ///< Ratio of row size to actual bitmap size
|
||||
};
|
||||
|
||||
#endif
|
||||
538
Engine/source/gui/controls/guiGameListOptionsCtrl.cpp
Normal file
538
Engine/source/gui/controls/guiGameListOptionsCtrl.cpp
Normal file
|
|
@ -0,0 +1,538 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// Copyright (c) 2012 GarageGames, LLC
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to
|
||||
// deal in the Software without restriction, including without limitation the
|
||||
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
// sell copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
// IN THE SOFTWARE.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "guiGameListOptionsCtrl.h"
|
||||
#include "gfx/gfxDrawUtil.h"
|
||||
#include "console/consoleTypes.h"
|
||||
#include "console/engineAPI.h"
|
||||
#include "core/strings/stringUnit.h"
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// GuiGameListOptionsCtrl
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
GuiGameListOptionsCtrl::GuiGameListOptionsCtrl()
|
||||
{
|
||||
}
|
||||
|
||||
GuiGameListOptionsCtrl::~GuiGameListOptionsCtrl()
|
||||
{
|
||||
}
|
||||
|
||||
bool GuiGameListOptionsCtrl::onAdd()
|
||||
{
|
||||
if( !Parent::onAdd() )
|
||||
return false;
|
||||
|
||||
if( !hasValidProfile() )
|
||||
{
|
||||
GuiGameListOptionsProfile* profile;
|
||||
if( !Sim::findObject( "DefaultOptionsMenuProfile", profile ) )
|
||||
{
|
||||
Con::errorf( "GuiGameListOptionsCtrl: %s can't be created with a profile of type %s. Please create it with a profile of type GuiGameListOptionsProfile.",
|
||||
getName(), mProfile->getClassName() );
|
||||
return false;
|
||||
}
|
||||
else
|
||||
Con::warnf( "GuiGameListOptionsCtrl: substituted non-GuiGameListOptionsProfile in %s for DefaultOptionsMenuProfile", getName() );
|
||||
|
||||
setControlProfile( profile );
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void GuiGameListOptionsCtrl::onRender(Point2I offset, const RectI &updateRect)
|
||||
{
|
||||
Parent::onRender(offset, updateRect);
|
||||
GuiGameListOptionsProfile * profile = (GuiGameListOptionsProfile *) mProfile;
|
||||
|
||||
F32 xScale = (float) getWidth() / profile->getRowWidth();
|
||||
|
||||
S32 rowHeight = profile->getRowHeight();
|
||||
|
||||
bool profileHasArrows = profile->hasArrows();
|
||||
Point2I arrowExtent;
|
||||
S32 arrowOffsetY(0);
|
||||
if (profileHasArrows)
|
||||
{
|
||||
arrowExtent = profile->getArrowExtent();
|
||||
|
||||
// icon is centered vertically
|
||||
arrowOffsetY = (rowHeight - arrowExtent.y) >> 1;
|
||||
}
|
||||
|
||||
GFXDrawUtil *drawer = GFX->getDrawUtil();
|
||||
|
||||
Point2I currentOffset = offset;
|
||||
Point2I arrowOffset;
|
||||
S32 columnSplit = profile->mColumnSplit * xScale;
|
||||
S32 iconIndex;
|
||||
for (Vector<Parent::Row *>::iterator row = mRows.begin(); row < mRows.end(); ++row)
|
||||
{
|
||||
Row * myRow = (Row *) *row;
|
||||
if (row != mRows.begin())
|
||||
{
|
||||
// rows other than the first can have padding above them
|
||||
currentOffset.y += myRow->mHeightPad;
|
||||
currentOffset.y += rowHeight;
|
||||
}
|
||||
|
||||
bool hasOptions = (myRow->mOptions.size() > 0) && myRow->mSelectedOption > -1;
|
||||
if (hasOptions)
|
||||
{
|
||||
bool isRowSelected = (getSelected() != NO_ROW) && (row == &mRows[getSelected()]);
|
||||
bool isRowHighlighted = (getHighlighted() != NO_ROW) ? ((row == &mRows[getHighlighted()]) && ((*row)->mEnabled)) : false;
|
||||
if (profileHasArrows)
|
||||
{
|
||||
// render the left arrow
|
||||
bool arrowOnL = (isRowSelected || isRowHighlighted) && (myRow->mWrapOptions || (myRow->mSelectedOption > 0));
|
||||
iconIndex = (arrowOnL) ? Profile::TEX_L_ARROW_ON : Profile::TEX_L_ARROW_OFF;
|
||||
arrowOffset.x = currentOffset.x + columnSplit;
|
||||
arrowOffset.y = currentOffset.y + arrowOffsetY;
|
||||
|
||||
drawer->clearBitmapModulation();
|
||||
drawer->drawBitmapStretchSR(profile->mTextureObject, RectI(arrowOffset, arrowExtent), profile->getBitmapArrayRect((U32)iconIndex));
|
||||
|
||||
// render the right arrow
|
||||
bool arrowOnR = (isRowSelected || isRowHighlighted) && (myRow->mWrapOptions || (myRow->mSelectedOption < myRow->mOptions.size() - 1));
|
||||
iconIndex = (arrowOnR) ? Profile::TEX_R_ARROW_ON : Profile::TEX_R_ARROW_OFF;
|
||||
arrowOffset.x = currentOffset.x + (profile->mHitAreaLowerRight.x - profile->mRightPad) * xScale - arrowExtent.x;
|
||||
arrowOffset.y = currentOffset.y + arrowOffsetY;
|
||||
|
||||
drawer->clearBitmapModulation();
|
||||
drawer->drawBitmapStretchSR(profile->mTextureObject, RectI(arrowOffset, arrowExtent), profile->getBitmapArrayRect((U32)iconIndex));
|
||||
}
|
||||
|
||||
// get the appropriate font color
|
||||
ColorI fontColor;
|
||||
if (! myRow->mEnabled)
|
||||
{
|
||||
fontColor = profile->mFontColorNA;
|
||||
}
|
||||
else if (isRowSelected)
|
||||
{
|
||||
fontColor = profile->mFontColorSEL;
|
||||
}
|
||||
else if (isRowHighlighted)
|
||||
{
|
||||
fontColor = profile->mFontColorHL;
|
||||
}
|
||||
else
|
||||
{
|
||||
fontColor = profile->mFontColor;
|
||||
}
|
||||
|
||||
// calculate text to be at the center between the arrows
|
||||
GFont * font = profile->mFont;
|
||||
StringTableEntry text = myRow->mOptions[myRow->mSelectedOption];
|
||||
S32 textWidth = font->getStrWidth(text);
|
||||
S32 columnWidth = profile->mHitAreaLowerRight.x * xScale - profile->mRightPad - columnSplit;
|
||||
S32 columnCenter = columnSplit + (columnWidth >> 1);
|
||||
S32 textStartX = columnCenter - (textWidth >> 1);
|
||||
Point2I textOffset(textStartX, 0);
|
||||
|
||||
// render the option text itself
|
||||
Point2I textExtent(columnWidth, rowHeight);
|
||||
drawer->setBitmapModulation(fontColor);
|
||||
renderJustifiedText(currentOffset + textOffset, textExtent, text);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GuiGameListOptionsCtrl::onDebugRender(Point2I offset)
|
||||
{
|
||||
Parent::onDebugRender(offset);
|
||||
GuiGameListOptionsProfile * profile = (GuiGameListOptionsProfile *) mProfile;
|
||||
|
||||
F32 xScale = (float) getWidth() / profile->getRowWidth();
|
||||
|
||||
ColorI column1Color(255, 255, 0); // yellow
|
||||
ColorI column2Color(0, 255, 0); // green
|
||||
Point2I shrinker(-1, -1);
|
||||
|
||||
S32 rowHeight = profile->getRowHeight();
|
||||
Point2I currentOffset(offset);
|
||||
Point2I rowExtent(getExtent().x, rowHeight);
|
||||
Point2I hitAreaExtent(profile->getHitAreaExtent());
|
||||
hitAreaExtent.x *= xScale;
|
||||
hitAreaExtent += shrinker;
|
||||
Point2I column1Extent((profile->mColumnSplit - profile->mHitAreaUpperLeft.x) * xScale - 1, hitAreaExtent.y);
|
||||
Point2I column2Extent(hitAreaExtent.x - column1Extent.x - 1, hitAreaExtent.y);
|
||||
Point2I hitAreaOffset = profile->mHitAreaUpperLeft;
|
||||
hitAreaOffset.x *= xScale;
|
||||
|
||||
RectI borderRect;
|
||||
Point2I upperLeft;
|
||||
for (Vector<Parent::Row *>::iterator row = mRows.begin(); row < mRows.end(); ++row)
|
||||
{
|
||||
// set the top of the current row
|
||||
if (row != mRows.begin())
|
||||
{
|
||||
// rows other than the first can have padding above them
|
||||
currentOffset.y += (*row)->mHeightPad;
|
||||
currentOffset.y += rowHeight;
|
||||
}
|
||||
|
||||
// draw the box around column 1
|
||||
upperLeft = currentOffset + hitAreaOffset;
|
||||
borderRect.point = upperLeft;
|
||||
borderRect.extent = column1Extent;
|
||||
GFX->getDrawUtil()->drawRect(borderRect, column1Color);
|
||||
|
||||
// draw the box around column 2
|
||||
upperLeft.x += column1Extent.x + 1;
|
||||
borderRect.point = upperLeft;
|
||||
borderRect.extent = column2Extent;
|
||||
GFX->getDrawUtil()->drawRect(borderRect, column2Color);
|
||||
}
|
||||
}
|
||||
|
||||
void GuiGameListOptionsCtrl::addRow(const char* label, const char* optionsList, bool wrapOptions, const char* callback, S32 icon, S32 yPad, bool enabled)
|
||||
{
|
||||
static StringTableEntry DELIM = StringTable->insert("\t", true);
|
||||
Row * row = new Row();
|
||||
Vector<StringTableEntry> options( __FILE__, __LINE__ );
|
||||
S32 count = StringUnit::getUnitCount(optionsList, DELIM);
|
||||
for (int i = 0; i < count; ++i)
|
||||
{
|
||||
const char * option = StringUnit::getUnit(optionsList, i, DELIM);
|
||||
options.push_back(StringTable->insert(option, true));
|
||||
}
|
||||
row->mOptions = options;
|
||||
bool hasOptions = row->mOptions.size() > 0;
|
||||
row->mSelectedOption = (hasOptions) ? 0 : NO_OPTION;
|
||||
row->mWrapOptions = wrapOptions;
|
||||
Parent::addRow(row, label, callback, icon, yPad, true, (hasOptions) ? enabled : false);
|
||||
}
|
||||
|
||||
void GuiGameListOptionsCtrl::setOptions(S32 rowIndex, const char * optionsList)
|
||||
{
|
||||
static StringTableEntry DELIM = StringTable->insert("\t", true);
|
||||
|
||||
if (! isValidRowIndex(rowIndex))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Row * row = (Row *)mRows[rowIndex];
|
||||
|
||||
S32 count = StringUnit::getUnitCount(optionsList, DELIM);
|
||||
row->mOptions.setSize(count);
|
||||
for (int i = 0; i < count; ++i)
|
||||
{
|
||||
const char * option = StringUnit::getUnit(optionsList, i, DELIM);
|
||||
row->mOptions[i] = StringTable->insert(option, true);
|
||||
}
|
||||
|
||||
if (row->mSelectedOption >= row->mOptions.size())
|
||||
{
|
||||
row->mSelectedOption = row->mOptions.size() - 1;
|
||||
}
|
||||
}
|
||||
|
||||
bool GuiGameListOptionsCtrl::hasValidProfile() const
|
||||
{
|
||||
GuiGameListOptionsProfile * profile = dynamic_cast<GuiGameListOptionsProfile *>(mProfile);
|
||||
return profile;
|
||||
}
|
||||
|
||||
void GuiGameListOptionsCtrl::enforceConstraints()
|
||||
{
|
||||
Parent::enforceConstraints();
|
||||
}
|
||||
|
||||
void GuiGameListOptionsCtrl::onMouseUp(const GuiEvent &event)
|
||||
{
|
||||
S32 hitRow = getRow(event.mousePoint);
|
||||
if ((hitRow != NO_ROW) && isRowEnabled(hitRow) && (hitRow == getSelected()))
|
||||
{
|
||||
S32 xPos = globalToLocalCoord(event.mousePoint).x;
|
||||
clickOption((Row *) mRows[getSelected()], xPos);
|
||||
}
|
||||
}
|
||||
|
||||
void GuiGameListOptionsCtrl::clickOption(Row * row, S32 xPos)
|
||||
{
|
||||
GuiGameListOptionsProfile * profile = (GuiGameListOptionsProfile *) mProfile;
|
||||
if (! profile->hasArrows())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
F32 xScale = (float) getWidth() / profile->getRowWidth();
|
||||
|
||||
S32 bitmapArrowWidth = mProfile->getBitmapArrayRect(Profile::TEX_FIRST_ARROW).extent.x;
|
||||
|
||||
S32 leftArrowX1 = profile->mColumnSplit * xScale;
|
||||
S32 leftArrowX2 = leftArrowX1 + bitmapArrowWidth;
|
||||
|
||||
S32 rightArrowX2 = (profile->mHitAreaLowerRight.x - profile->mRightPad) * xScale;
|
||||
S32 rightArrowX1 = rightArrowX2 - bitmapArrowWidth;
|
||||
|
||||
if ((leftArrowX1 <= xPos) && (xPos <= leftArrowX2))
|
||||
{
|
||||
changeOption(row, -1);
|
||||
}
|
||||
else if ((rightArrowX1 <= xPos) && (xPos <= rightArrowX2))
|
||||
{
|
||||
changeOption(row, 1);
|
||||
}
|
||||
}
|
||||
|
||||
bool GuiGameListOptionsCtrl::onKeyDown(const GuiEvent &event)
|
||||
{
|
||||
switch (event.keyCode)
|
||||
{
|
||||
case KEY_LEFT:
|
||||
changeOption(-1);
|
||||
return true;
|
||||
|
||||
case KEY_RIGHT:
|
||||
changeOption(1);
|
||||
return true;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return Parent::onKeyDown(event);
|
||||
}
|
||||
|
||||
bool GuiGameListOptionsCtrl::onGamepadAxisLeft( const GuiEvent &event )
|
||||
{
|
||||
changeOption(-1);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool GuiGameListOptionsCtrl::onGamepadAxisRight( const GuiEvent &event )
|
||||
{
|
||||
changeOption(1);
|
||||
return true;
|
||||
}
|
||||
|
||||
void GuiGameListOptionsCtrl::changeOption(S32 delta)
|
||||
{
|
||||
if (getSelected() != NO_ROW)
|
||||
{
|
||||
Row * row = (Row *) mRows[getSelected()];
|
||||
changeOption(row, delta);
|
||||
}
|
||||
}
|
||||
|
||||
void GuiGameListOptionsCtrl::changeOption(Row * row, S32 delta)
|
||||
{
|
||||
S32 optionCount = row->mOptions.size();
|
||||
|
||||
S32 newSelection = row->mSelectedOption + delta;
|
||||
if (optionCount == 0)
|
||||
{
|
||||
newSelection = NO_OPTION;
|
||||
}
|
||||
else if (! row->mWrapOptions)
|
||||
{
|
||||
newSelection = mClamp(newSelection, 0, optionCount - 1);
|
||||
}
|
||||
else if (newSelection < 0)
|
||||
{
|
||||
newSelection = optionCount - 1;
|
||||
}
|
||||
else if (newSelection >= optionCount)
|
||||
{
|
||||
newSelection = 0;
|
||||
}
|
||||
row->mSelectedOption = newSelection;
|
||||
|
||||
static StringTableEntry LEFT = StringTable->insert("LEFT", true);
|
||||
static StringTableEntry RIGHT = StringTable->insert("RIGHT", true);
|
||||
|
||||
if (row->mScriptCallback != NULL)
|
||||
{
|
||||
setThisControl();
|
||||
StringTableEntry direction = NULL;
|
||||
if (delta < 0)
|
||||
{
|
||||
direction = LEFT;
|
||||
}
|
||||
else if (delta > 0)
|
||||
{
|
||||
direction = RIGHT;
|
||||
}
|
||||
if ((direction != NULL) && (Con::isFunction(row->mScriptCallback)))
|
||||
{
|
||||
Con::executef(row->mScriptCallback, direction);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
StringTableEntry GuiGameListOptionsCtrl::getCurrentOption(S32 rowIndex) const
|
||||
{
|
||||
if (isValidRowIndex(rowIndex))
|
||||
{
|
||||
Row * row = (Row *) mRows[rowIndex];
|
||||
if (row->mSelectedOption != NO_OPTION)
|
||||
{
|
||||
return row->mOptions[row->mSelectedOption];
|
||||
}
|
||||
}
|
||||
return StringTable->insert("", false);
|
||||
}
|
||||
|
||||
bool GuiGameListOptionsCtrl::selectOption(S32 rowIndex, const char * theOption)
|
||||
{
|
||||
if (! isValidRowIndex(rowIndex))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
Row * row = (Row *) mRows[rowIndex];
|
||||
|
||||
for (Vector<StringTableEntry>::iterator anOption = row->mOptions.begin(); anOption < row->mOptions.end(); ++anOption)
|
||||
{
|
||||
if (dStrcmp(*anOption, theOption) == 0)
|
||||
{
|
||||
S32 newIndex = anOption - row->mOptions.begin();
|
||||
row->mSelectedOption = newIndex;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Console stuff (GuiGameListOptionsCtrl)
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
IMPLEMENT_CONOBJECT(GuiGameListOptionsCtrl);
|
||||
|
||||
ConsoleDocClass( GuiGameListOptionsCtrl,
|
||||
"@brief A control for showing pages of options that are gamepad friendly.\n\n"
|
||||
|
||||
"Each row in this control allows the selection of one value from a set of "
|
||||
"options using the keyboard, gamepad or mouse. The row is rendered as 2 "
|
||||
"columns: the first column contains the row label, the second column "
|
||||
"contains left and right arrows (for mouse picking) and the currently "
|
||||
"selected value.\n\n"
|
||||
|
||||
"@see GuiGameListOptionsProfile\n\n"
|
||||
|
||||
"@ingroup GuiGame"
|
||||
);
|
||||
|
||||
void GuiGameListOptionsCtrl::initPersistFields()
|
||||
{
|
||||
Parent::initPersistFields();
|
||||
}
|
||||
|
||||
DefineEngineMethod( GuiGameListOptionsCtrl, addRow, void,
|
||||
( const char* label, const char* options, bool wrapOptions, const char* callback, S32 icon, S32 yPad, bool enabled ),
|
||||
( -1, 0, true ),
|
||||
"Add a row to the list control.\n\n"
|
||||
"@param label The text to display on the row as a label.\n"
|
||||
"@param options A tab separated list of options.\n"
|
||||
"@param wrapOptions Specify true to allow options to wrap at each end or false to prevent wrapping.\n"
|
||||
"@param callback Name of a script function to use as a callback when this row is activated.\n"
|
||||
"@param icon [optional] Index of the icon to use as a marker.\n"
|
||||
"@param yPad [optional] An extra amount of height padding before the row. Does nothing on the first row.\n"
|
||||
"@param enabled [optional] If this row is initially enabled." )
|
||||
{
|
||||
object->addRow( label, options, wrapOptions, callback, icon, yPad, enabled );
|
||||
}
|
||||
|
||||
DefineEngineMethod( GuiGameListOptionsCtrl, getCurrentOption, const char *, ( S32 row ),,
|
||||
"Gets the text for the currently selected option of the given row.\n\n"
|
||||
"@param row Index of the row to get the option from.\n"
|
||||
"@return A string representing the text currently displayed as the selected option on the given row. If there is no such displayed text then the empty string is returned." )
|
||||
{
|
||||
return object->getCurrentOption( row );
|
||||
}
|
||||
|
||||
DefineEngineMethod( GuiGameListOptionsCtrl, selectOption, bool, ( S32 row, const char* option ),,
|
||||
"Set the row's current option to the one specified\n\n"
|
||||
"@param row Index of the row to set an option on.\n"
|
||||
"@param option The option to be made active.\n"
|
||||
"@return True if the row contained the option and was set, false otherwise." )
|
||||
{
|
||||
return object->selectOption( row, option );
|
||||
}
|
||||
|
||||
DefineEngineMethod( GuiGameListOptionsCtrl, setOptions, void, ( S32 row, const char* optionsList ),,
|
||||
"Sets the list of options on the given row.\n\n"
|
||||
"@param row Index of the row to set options on."
|
||||
"@param optionsList A tab separated list of options for the control." )
|
||||
{
|
||||
object->setOptions( row, optionsList );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// GuiGameListOptionsProfile
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
GuiGameListOptionsProfile::GuiGameListOptionsProfile()
|
||||
: mColumnSplit(0),
|
||||
mRightPad(0)
|
||||
{
|
||||
}
|
||||
|
||||
void GuiGameListOptionsProfile::enforceConstraints()
|
||||
{
|
||||
Parent::enforceConstraints();
|
||||
|
||||
if( mHitAreaUpperLeft.x > mColumnSplit || mColumnSplit > mHitAreaLowerRight.x )
|
||||
Con::errorf( "GuiGameListOptionsProfile: You can't create %s with a ColumnSplit outside the hit area. You set the split to %d. Please change the ColumnSplit to be in the range [%d, %d].",
|
||||
getName(), mColumnSplit, mHitAreaUpperLeft.x, mHitAreaLowerRight.x);
|
||||
|
||||
mColumnSplit = mClamp(mColumnSplit, mHitAreaUpperLeft.x, mHitAreaLowerRight.x);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Console stuff (GuiGameListOptionsProfile)
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
IMPLEMENT_CONOBJECT(GuiGameListOptionsProfile);
|
||||
|
||||
ConsoleDocClass( GuiGameListOptionsProfile,
|
||||
"@brief A GuiControlProfile with additional fields specific to GuiGameListOptionsCtrl.\n\n"
|
||||
|
||||
"@tsexample\n"
|
||||
"new GuiGameListOptionsProfile()\n"
|
||||
"{\n"
|
||||
" columnSplit = \"100\";\n"
|
||||
" rightPad = \"4\";\n"
|
||||
" //Properties not specific to this control have been omitted from this example.\n"
|
||||
"};\n"
|
||||
"@endtsexample\n\n"
|
||||
|
||||
"@ingroup GuiGame"
|
||||
);
|
||||
|
||||
void GuiGameListOptionsProfile::initPersistFields()
|
||||
{
|
||||
addField( "columnSplit", TypeS32, Offset(mColumnSplit, GuiGameListOptionsProfile),
|
||||
"Padding between the leftmost edge of the control, and the row's left arrow." );
|
||||
|
||||
addField( "rightPad", TypeS32, Offset(mRightPad, GuiGameListOptionsProfile),
|
||||
"Padding between the rightmost edge of the control and the row's right arrow." );
|
||||
|
||||
Parent::initPersistFields();
|
||||
}
|
||||
188
Engine/source/gui/controls/guiGameListOptionsCtrl.h
Normal file
188
Engine/source/gui/controls/guiGameListOptionsCtrl.h
Normal file
|
|
@ -0,0 +1,188 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// Copyright (c) 2012 GarageGames, LLC
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to
|
||||
// deal in the Software without restriction, including without limitation the
|
||||
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
// sell copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
// IN THE SOFTWARE.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef _GuiGameListOptionsCtrl_H_
|
||||
#define _GuiGameListOptionsCtrl_H_
|
||||
|
||||
#include "gui/controls/guiGameListMenuCtrl.h"
|
||||
|
||||
/// \class GuiGameListOptionsCtrl
|
||||
/// A control for showing pages of options that are gamepad friendly.
|
||||
class GuiGameListOptionsCtrl : public GuiGameListMenuCtrl
|
||||
{
|
||||
typedef GuiGameListMenuCtrl Parent;
|
||||
|
||||
protected:
|
||||
/// \struct Row
|
||||
/// An extension to the parent's row, adding the ability to keep a collection
|
||||
/// of options and track status related to them.
|
||||
struct Row : public Parent::Row
|
||||
{
|
||||
Vector<StringTableEntry> mOptions; ///< Collection of options available to display
|
||||
S32 mSelectedOption; ///< Index into mOptions pointing at the selected option
|
||||
bool mWrapOptions; ///< Determines if options should "wrap around" at the ends
|
||||
|
||||
Row()
|
||||
{
|
||||
VECTOR_SET_ASSOCIATION( mOptions );
|
||||
}
|
||||
};
|
||||
|
||||
public:
|
||||
/// Gets the text for the currently selected option of the given row.
|
||||
///
|
||||
/// \param rowIndex Index of the row to get the option from.
|
||||
/// \return A string representing the text currently displayed as the selected
|
||||
/// option on the given row. If there is no such displayed text then the empty
|
||||
/// string is returned.
|
||||
StringTableEntry getCurrentOption(S32 rowIndex) const;
|
||||
|
||||
/// Attempts to set the given row to the specified selected option. The option
|
||||
/// will only be set if the option exists in the control.
|
||||
///
|
||||
/// \param rowIndex Index of the row to set an option on.
|
||||
/// \param option The option to be made active.
|
||||
/// \return True if the row contained the option and was set, false otherwise.
|
||||
bool selectOption(S32 rowIndex, StringTableEntry option);
|
||||
|
||||
/// Sets the list of options on the given row.
|
||||
///
|
||||
/// \param rowIndex Index of the row to set options on.
|
||||
/// \param optionsList A tab separated list of options for the control.
|
||||
void setOptions(S32 rowIndex, const char * optionsList);
|
||||
|
||||
/// Adds a row to the control.
|
||||
///
|
||||
/// \param label The text to display on the row as a label.
|
||||
/// \param optionsList A tab separated list of options for the control.
|
||||
/// \param wrapOptions Specify true to allow options to wrap at the ends or
|
||||
/// false to prevent wrapping.
|
||||
/// \param callback [optional] Name of a script function to use as a callback
|
||||
/// when this row is activated. Default NULL means no callback.
|
||||
/// \param icon [optional] Index of the icon to use as a marker. Default -1
|
||||
/// means no icon will be shown on this row.
|
||||
/// \param yPad [optional] An extra amount of height padding before the row.
|
||||
/// \param enabled [optional] If this row is initially enabled. Default true.
|
||||
void addRow(const char* label, const char* optionsList, bool wrapOptions, const char* callback, S32 icon = -1, S32 yPad = 0, bool enabled = true);
|
||||
|
||||
void onRender(Point2I offset, const RectI &updateRect);
|
||||
|
||||
/// Callback when the mouse button is released.
|
||||
///
|
||||
/// \param event A reference to the event that triggered the callback.
|
||||
void onMouseUp(const GuiEvent &event);
|
||||
|
||||
/// Callback when a key is pressed.
|
||||
///
|
||||
/// \param event The event that triggered this callback.
|
||||
bool onKeyDown(const GuiEvent &event);
|
||||
|
||||
/// Callback when a key is repeating.
|
||||
///
|
||||
/// \param event The event that triggered this callback.
|
||||
bool onKeyRepeat(const GuiEvent &event){ return onKeyDown(event); }
|
||||
|
||||
/// Callback when the gamepad axis is activated.
|
||||
///
|
||||
/// \param event A reference to the event that triggered the callback.
|
||||
virtual bool onGamepadAxisLeft(const GuiEvent &event);
|
||||
|
||||
/// Callback when the gamepad axis is activated.
|
||||
///
|
||||
/// \param event A reference to the event that triggered the callback.
|
||||
virtual bool onGamepadAxisRight(const GuiEvent &event);
|
||||
|
||||
GuiGameListOptionsCtrl();
|
||||
~GuiGameListOptionsCtrl();
|
||||
|
||||
DECLARE_CONOBJECT(GuiGameListOptionsCtrl);
|
||||
DECLARE_DESCRIPTION( "A control for showing pages of options that are gamepad friendly." );
|
||||
|
||||
virtual bool onAdd();
|
||||
|
||||
/// Initializes fields accessible through the console.
|
||||
static void initPersistFields();
|
||||
|
||||
static const S32 NO_OPTION = -1; ///< Indicates there is no option
|
||||
|
||||
protected:
|
||||
/// Checks to make sure our control has a profile of the correct type.
|
||||
///
|
||||
/// \return True if the profile is of type GuiGameListOptionsProfile or false
|
||||
/// if the profile is of any other type.
|
||||
bool hasValidProfile() const;
|
||||
|
||||
/// Enforces the validity of the fields on this control and its profile (if the
|
||||
/// profile is valid, see: hasValidProfile).
|
||||
void enforceConstraints();
|
||||
|
||||
/// Adds lines around the column divisions to the feedback already provided
|
||||
/// in the Parent.
|
||||
void onDebugRender(Point2I offset);
|
||||
|
||||
private:
|
||||
/// Performs a click on the current option row. The x position is used to
|
||||
/// determine if the left or right arrow were clicked. If one was clicked, the
|
||||
/// option will be changed. If neither was clicked, the option is unaffected.
|
||||
/// This method should only be called when there is an actively selected row.
|
||||
///
|
||||
/// \param row The row to perform the click on.
|
||||
/// \param xPos The x position of the the click, relative to the control.
|
||||
void clickOption(Row * row, S32 xPos);
|
||||
|
||||
/// Changes the option on the currently selected row. If there is no row
|
||||
/// selected, this method does nothing.
|
||||
///
|
||||
/// \param delta The amount to change the option selection by. Typically this
|
||||
/// will be 1 or -1.
|
||||
void changeOption(S32 delta);
|
||||
|
||||
/// Changes the option on the given row.
|
||||
///
|
||||
/// \param row The row to change the option on.
|
||||
/// \param delta The amount to change the option selection by. Typically this
|
||||
/// will be 1 or -1.
|
||||
void changeOption(Row * row, S32 delta);
|
||||
};
|
||||
|
||||
/// \class GuiGameListOptionsProfile
|
||||
/// A gui profile with additional fields specific to GuiGameListOptionsCtrl.
|
||||
class GuiGameListOptionsProfile : public GuiGameListMenuProfile
|
||||
{
|
||||
typedef GuiGameListMenuProfile Parent;
|
||||
|
||||
public:
|
||||
/// Enforces range constraints on all required fields.
|
||||
void enforceConstraints();
|
||||
|
||||
GuiGameListOptionsProfile();
|
||||
|
||||
S32 mColumnSplit; ///< Absolute position of the split between columns
|
||||
S32 mRightPad; ///< Extra padding between the right arrow and the hit area
|
||||
|
||||
DECLARE_CONOBJECT(GuiGameListOptionsProfile);
|
||||
|
||||
/// Initializes fields accessible through the console.
|
||||
static void initPersistFields();
|
||||
};
|
||||
|
||||
#endif
|
||||
652
Engine/source/gui/controls/guiGradientCtrl.cpp
Normal file
652
Engine/source/gui/controls/guiGradientCtrl.cpp
Normal file
|
|
@ -0,0 +1,652 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// Copyright (c) 2012 GarageGames, LLC
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to
|
||||
// deal in the Software without restriction, including without limitation the
|
||||
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
// sell copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
// IN THE SOFTWARE.
|
||||
//-----------------------------------------------------------------------------
|
||||
#include "console/console.h"
|
||||
#include "gfx/gfxDevice.h"
|
||||
#include "console/consoleTypes.h"
|
||||
#include "gui/core/guiCanvas.h"
|
||||
#include "gui/buttons/guiButtonCtrl.h"
|
||||
#include "gui/core/guiDefaultControlRender.h"
|
||||
#include "gui/controls/guiGradientCtrl.h"
|
||||
#include "gui/controls/guiColorPicker.h"
|
||||
#include "gfx/primBuilder.h"
|
||||
#include "gfx/gfxDrawUtil.h"
|
||||
#include "console/engineAPI.h"
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// GuiGradientSwatchCtrl
|
||||
|
||||
IMPLEMENT_CONOBJECT(GuiGradientSwatchCtrl);
|
||||
|
||||
ConsoleDocClass( GuiGradientSwatchCtrl,
|
||||
"@brief Swatch selector that appears inside the GuiGradientCtrl object. These objects are automatically created by GuiGradientCtrl. \n\n"
|
||||
"Currently only appears to be editor specific\n\n"
|
||||
"@see GuiSwatchButtonCtrl\n"
|
||||
"@see GuiGradientCtrl\n\n"
|
||||
"@ingroup GuiCore\n"
|
||||
"@internal"
|
||||
);
|
||||
|
||||
IMPLEMENT_CALLBACK( GuiGradientSwatchCtrl, onMouseDown, void, (),(),
|
||||
"@brief Called whenever the left mouse button has entered the down state while in this control.\n\n"
|
||||
"@tsexample\n"
|
||||
"// The left mouse button is down on the control, causing the callback to occur.\n"
|
||||
"GuiGradientSwatchCtrl::onMouseDown(%this)\n"
|
||||
" {\n"
|
||||
" // Code to run when the callback occurs\n"
|
||||
" }\n"
|
||||
"@endtsexample\n\n"
|
||||
"@see GuiControl\n"
|
||||
"@see GuiSwatchButtonCtrl\n\n"
|
||||
"@internal"
|
||||
);
|
||||
|
||||
IMPLEMENT_CALLBACK( GuiGradientSwatchCtrl, onDoubleClick, void, (),(),
|
||||
"@brief Called whenever the left mouse button performs a double click while in this control.\n\n"
|
||||
"@tsexample\n"
|
||||
"// The left mouse button has performed a double click on the control, causing the callback to occur.\n"
|
||||
"GuiGradientSwatchCtrl::onDoubleClick(%this)\n"
|
||||
" {\n"
|
||||
" // Code to run when the callback occurs\n"
|
||||
" }\n"
|
||||
"@endtsexample\n\n"
|
||||
"@see GuiControl\n"
|
||||
"@see GuiSwatchButtonCtrl\n\n"
|
||||
"@internal"
|
||||
);
|
||||
|
||||
|
||||
GuiGradientSwatchCtrl::GuiGradientSwatchCtrl()
|
||||
{
|
||||
setPosition(0, 0);
|
||||
setExtent(14, 14);
|
||||
mMouseDownPosition = Point2I(0, 0);
|
||||
mSwatchColor = ColorI( 1, 1, 1, 1 );
|
||||
mColorFunction = StringTable->insert("getColorF");
|
||||
setDataField( StringTable->insert("Profile"), NULL, "GuiInspectorSwatchButtonProfile" );
|
||||
}
|
||||
|
||||
bool GuiGradientSwatchCtrl::onWake()
|
||||
{
|
||||
if ( !Parent::onWake() )
|
||||
return false;
|
||||
|
||||
if ( mPointer.isNull() )
|
||||
mPointer.set( "core/art/gui/images/arrowbtn_d", &GFXDefaultGUIProfile, avar("%s() - mGrid (line %d)", __FUNCTION__, __LINE__) );
|
||||
|
||||
char* altCommand = Con::getReturnBuffer(512);
|
||||
dSprintf( altCommand, 512, "%s(%i.color, \"%i.setColor\");", mColorFunction, getId(), getId() );
|
||||
setField( "altCommand", altCommand );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void GuiGradientSwatchCtrl::onRender( Point2I offset, const RectI &updateRect )
|
||||
{
|
||||
bool highlight = mMouseOver;
|
||||
|
||||
ColorI backColor = mSwatchColor;
|
||||
ColorI borderColor = mActive ? ( highlight ? mProfile->mBorderColorHL : mProfile->mBorderColor ) : mProfile->mBorderColorNA;
|
||||
RectI renderRect( offset, getExtent() );
|
||||
|
||||
if ( !highlight )
|
||||
renderRect.inset( 1, 1 );
|
||||
|
||||
GFXDrawUtil *drawer = GFX->getDrawUtil();
|
||||
drawer->clearBitmapModulation();
|
||||
|
||||
// Draw background transparency grid texture...
|
||||
if ( mGrid.isValid() )
|
||||
drawer->drawBitmapStretch( mGrid, renderRect );
|
||||
|
||||
// Draw swatch color as fill...
|
||||
drawer->drawRectFill( renderRect, mSwatchColor );
|
||||
|
||||
// Draw any borders...
|
||||
drawer->drawRect( renderRect, borderColor );
|
||||
}
|
||||
|
||||
void GuiGradientSwatchCtrl::onMouseDown(const GuiEvent &event)
|
||||
{
|
||||
if (! mActive)
|
||||
return;
|
||||
|
||||
if (mProfile->mCanKeyFocus)
|
||||
setFirstResponder();
|
||||
|
||||
//capture current bounds and mouse down position
|
||||
mOrigBounds = getBounds();
|
||||
mMouseDownPosition = event.mousePoint;
|
||||
|
||||
if(mUseMouseEvents)
|
||||
onMouseDown_callback();
|
||||
|
||||
//lock the mouse
|
||||
mouseLock();
|
||||
mDepressed = true;
|
||||
|
||||
// If we have a double click then execute the alt command.
|
||||
if ( event.mouseClickCount == 2 )
|
||||
{
|
||||
onDoubleClick_callback();
|
||||
|
||||
execAltConsoleCallback();
|
||||
}
|
||||
|
||||
setUpdate();
|
||||
}
|
||||
|
||||
void GuiGradientSwatchCtrl::onMouseDragged(const GuiEvent &event)
|
||||
{
|
||||
//gradientCtrl owns the y, x here however is regulated by the extent currently
|
||||
//dirty, please fix
|
||||
GuiGradientCtrl* parent = dynamic_cast<GuiGradientCtrl*>(getParent());
|
||||
if( !parent )
|
||||
return;
|
||||
|
||||
//use bounds and delta to move the ctrl
|
||||
Point2I newPosition = mMouseDownPosition;
|
||||
Point2I deltaMousePosition = event.mousePoint - mMouseDownPosition;
|
||||
|
||||
newPosition.x = mOrigBounds.point.x + deltaMousePosition.x;
|
||||
|
||||
// default position but it needs to be standard; currently using this cops out a static y value
|
||||
newPosition.y = mOrigBounds.point.y;
|
||||
|
||||
if( newPosition.x + parent->mSwatchFactor >= parent->mBlendRangeBox.point.x &&
|
||||
newPosition.x + parent->mSwatchFactor <= parent->mBlendRangeBox.extent.x )
|
||||
{
|
||||
setPosition(newPosition);
|
||||
if( parent )
|
||||
parent->sortColorRange();
|
||||
}
|
||||
}
|
||||
|
||||
void GuiGradientSwatchCtrl::onRightMouseDown(const GuiEvent &event)
|
||||
{
|
||||
GuiGradientCtrl* parent = dynamic_cast<GuiGradientCtrl*>(getParent());
|
||||
if( parent )
|
||||
parent->removeColorRange( this );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// GuiGradientCtrl
|
||||
|
||||
static S32 QSORT_CALLBACK _numIncreasing( const void* a, const void* b )
|
||||
{
|
||||
GuiGradientCtrl::ColorRange *crA = (GuiGradientCtrl::ColorRange *) (a);
|
||||
GuiGradientCtrl::ColorRange *crB = (GuiGradientCtrl::ColorRange *) (b);
|
||||
S32 posA = crA->swatch->getPosition().x;
|
||||
S32 posB = crB->swatch->getPosition().x;
|
||||
return ( (posA < posB) ? -1 : ((posA > posB) ? 1 : 0) );
|
||||
}
|
||||
|
||||
ImplementEnumType( GuiGradientPickMode,
|
||||
"\n\n"
|
||||
"@ingroup GuiCore"
|
||||
"@internal")
|
||||
{ GuiGradientCtrl::pHorizColorRange, "HorizColor"},
|
||||
{ GuiGradientCtrl::pHorizAlphaRange, "HorizAlpha"},
|
||||
EndImplementEnumType;
|
||||
|
||||
IMPLEMENT_CONOBJECT(GuiGradientCtrl);
|
||||
|
||||
ConsoleDocClass( GuiGradientCtrl,
|
||||
"@brief Visual representation of color box used with the GuiColorPickerCtrl\n\n"
|
||||
"Editor use only.\n\n"
|
||||
"@internal"
|
||||
);
|
||||
|
||||
|
||||
GuiGradientCtrl::GuiGradientCtrl()
|
||||
{
|
||||
setExtent(140, 30);
|
||||
mDisplayMode = pHorizColorRange;
|
||||
mSaveDisplayMode = pHorizColorRange;
|
||||
mBaseColor = ColorF(1.,.0,1.);
|
||||
mPickColor = ColorF(.0,.0,.0);
|
||||
mMouseDown = mMouseOver = false;
|
||||
mActive = true;
|
||||
mPositionChanged = false;
|
||||
mActionOnMove = false;
|
||||
mShowReticle = true;
|
||||
colorWhiteBlend = ColorF(1.,1.,1.,.75);
|
||||
mSwatchFactor = 7;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
void GuiGradientCtrl::initPersistFields()
|
||||
{
|
||||
addGroup("ColorPicker");
|
||||
addField("baseColor", TypeColorF, Offset(mBaseColor, GuiGradientCtrl));
|
||||
addField("pickColor", TypeColorF, Offset(mPickColor, GuiGradientCtrl));
|
||||
addField("displayMode", TYPEID< PickMode >(), Offset(mDisplayMode, GuiGradientCtrl) );
|
||||
addField("actionOnMove", TypeBool,Offset(mActionOnMove, GuiGradientCtrl));
|
||||
addField("showReticle", TypeBool, Offset(mShowReticle, GuiGradientCtrl));
|
||||
addField("swatchFactor", TypeS32, Offset(mSwatchFactor, GuiGradientCtrl));
|
||||
endGroup("ColorPicker");
|
||||
|
||||
Parent::initPersistFields();
|
||||
}
|
||||
|
||||
bool GuiGradientCtrl::onAdd()
|
||||
{
|
||||
Parent::onAdd();
|
||||
|
||||
S32 l = getBounds().point.x + mSwatchFactor, r = getBounds().point.x + getBounds().extent.x - mSwatchFactor;
|
||||
S32 t = getBounds().point.y, b = getBounds().point.y + getBounds().extent.y - mSwatchFactor;
|
||||
mBlendRangeBox = RectI( Point2I(l, t), Point2I(r, b) );
|
||||
|
||||
setupDefaultRange();
|
||||
reInitSwatches( mDisplayMode );
|
||||
return true;
|
||||
}
|
||||
|
||||
void GuiGradientCtrl::inspectPreApply()
|
||||
{
|
||||
mSaveDisplayMode = mDisplayMode;
|
||||
}
|
||||
|
||||
void GuiGradientCtrl::inspectPostApply()
|
||||
{
|
||||
if((mSaveDisplayMode != mDisplayMode) )
|
||||
reInitSwatches( mDisplayMode );
|
||||
|
||||
// Apply any transformations set in the editor
|
||||
Parent::inspectPostApply();
|
||||
}
|
||||
|
||||
void GuiGradientCtrl::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 );
|
||||
}
|
||||
|
||||
RectI boundsRect(offset, getExtent());
|
||||
renderColorBox(boundsRect);
|
||||
|
||||
if (mPositionChanged)
|
||||
{
|
||||
mPositionChanged = false;
|
||||
|
||||
// Now do onAction() if we are allowed
|
||||
if (mActionOnMove)
|
||||
onAction();
|
||||
}
|
||||
|
||||
//render the children
|
||||
renderChildControls( offset, updateRect);
|
||||
}
|
||||
|
||||
/// Function to invoke calls to draw the picker box and swatch controls
|
||||
void GuiGradientCtrl::renderColorBox(RectI &bounds)
|
||||
{
|
||||
// Draw color box differently depending on mode
|
||||
if( mDisplayMode == pHorizColorRange )
|
||||
{
|
||||
drawBlendRangeBox( bounds, false, mColorRange);
|
||||
}
|
||||
else if( mDisplayMode == pHorizAlphaRange )
|
||||
{
|
||||
drawBlendRangeBox( bounds, false, mAlphaRange);
|
||||
}
|
||||
}
|
||||
|
||||
/// Function to draw a set of boxes blending throughout an array of colors
|
||||
void GuiGradientCtrl::drawBlendRangeBox(RectI &bounds, bool vertical, Vector<ColorRange> colorRange)
|
||||
{
|
||||
GFX->setStateBlock(mStateBlock);
|
||||
|
||||
// Create new global dimensions
|
||||
S32 l = bounds.point.x + mSwatchFactor, r = bounds.point.x + bounds.extent.x - mSwatchFactor;
|
||||
S32 t = bounds.point.y, b = bounds.point.y + bounds.extent.y - mSwatchFactor;
|
||||
|
||||
// Draw border using new global dimensions
|
||||
if (mProfile->mBorder)
|
||||
GFX->getDrawUtil()->drawRect( RectI( Point2I(l,t),Point2I(r,b) ), mProfile->mBorderColor);
|
||||
|
||||
// Update local dimensions
|
||||
mBlendRangeBox.point = globalToLocalCoord(Point2I(l, t));
|
||||
mBlendRangeBox.extent = globalToLocalCoord(Point2I(r, b));
|
||||
|
||||
if(colorRange.size() == 1) // Only one color to draw
|
||||
{
|
||||
PrimBuild::begin( GFXTriangleFan, 4 );
|
||||
|
||||
PrimBuild::color( colorRange.first().swatch->getColor() );
|
||||
PrimBuild::vertex2i( l, t );
|
||||
PrimBuild::vertex2i( l, b );
|
||||
|
||||
PrimBuild::color( colorRange.first().swatch->getColor() );
|
||||
PrimBuild::vertex2i( r, b );
|
||||
PrimBuild::vertex2i( r, t );
|
||||
|
||||
PrimBuild::end();
|
||||
}
|
||||
else
|
||||
{
|
||||
PrimBuild::begin( GFXTriangleFan, 4 );
|
||||
|
||||
PrimBuild::color( colorRange.first().swatch->getColor() );
|
||||
PrimBuild::vertex2i( l, t );
|
||||
PrimBuild::vertex2i( l, b );
|
||||
|
||||
PrimBuild::color( colorRange.first().swatch->getColor() );
|
||||
PrimBuild::vertex2i( l + colorRange.first().swatch->getPosition().x, b );
|
||||
PrimBuild::vertex2i( l + colorRange.first().swatch->getPosition().x, t );
|
||||
|
||||
PrimBuild::end();
|
||||
|
||||
for( U16 i = 0;i < colorRange.size() - 1; i++ )
|
||||
{
|
||||
PrimBuild::begin( GFXTriangleFan, 4 );
|
||||
if (!vertical) // Horizontal (+x)
|
||||
{
|
||||
// First color
|
||||
PrimBuild::color( colorRange[i].swatch->getColor() );
|
||||
PrimBuild::vertex2i( l + colorRange[i].swatch->getPosition().x, t );
|
||||
PrimBuild::vertex2i( l + colorRange[i].swatch->getPosition().x, b );
|
||||
|
||||
// First color
|
||||
PrimBuild::color( colorRange[i+1].swatch->getColor() );
|
||||
PrimBuild::vertex2i( l + colorRange[i+1].swatch->getPosition().x, b );
|
||||
PrimBuild::vertex2i( l + colorRange[i+1].swatch->getPosition().x, t );
|
||||
}
|
||||
PrimBuild::end();
|
||||
}
|
||||
|
||||
PrimBuild::begin( GFXTriangleFan, 4 );
|
||||
|
||||
PrimBuild::color( colorRange.last().swatch->getColor() );
|
||||
PrimBuild::vertex2i( l + colorRange.last().swatch->getPosition().x, t );
|
||||
PrimBuild::vertex2i( l + colorRange.last().swatch->getPosition().x, b );
|
||||
|
||||
PrimBuild::color( colorRange.last().swatch->getColor() );
|
||||
PrimBuild::vertex2i( r, b );
|
||||
PrimBuild::vertex2i( r, t );
|
||||
|
||||
PrimBuild::end();
|
||||
}
|
||||
}
|
||||
|
||||
void GuiGradientCtrl::onMouseDown(const GuiEvent &event)
|
||||
{
|
||||
if (!mActive)
|
||||
return;
|
||||
|
||||
mouseLock(this);
|
||||
|
||||
if (mProfile->mCanKeyFocus)
|
||||
setFirstResponder();
|
||||
|
||||
if (mActive)
|
||||
onAction();
|
||||
|
||||
Point2I extent = getRoot()->getExtent();
|
||||
Point2I resolution = getRoot()->getExtent();
|
||||
GFXTexHandle bb( resolution.x,
|
||||
resolution.y,
|
||||
GFXFormatR8G8B8A8, &GFXDefaultRenderTargetProfile, avar("%s() - bb (line %d)", __FUNCTION__, __LINE__) );
|
||||
|
||||
Point2I tmpPt( event.mousePoint.x, event.mousePoint.y );
|
||||
GFXTarget *targ = GFX->getActiveRenderTarget();
|
||||
targ->resolveTo( bb );
|
||||
GBitmap bmp( bb.getWidth(), bb.getHeight() );
|
||||
bb.copyToBmp( &bmp );
|
||||
ColorI tmp;
|
||||
bmp.getColor( event.mousePoint.x, event.mousePoint.y, tmp );
|
||||
|
||||
addColorRange( globalToLocalCoord(event.mousePoint), ColorF(tmp) );
|
||||
|
||||
mMouseDown = true;
|
||||
}
|
||||
|
||||
void GuiGradientCtrl::onMouseUp(const GuiEvent &)
|
||||
{
|
||||
//if we released the mouse within this control, perform the action
|
||||
if (mActive && mMouseDown )
|
||||
mMouseDown = false;
|
||||
|
||||
mouseUnlock();
|
||||
}
|
||||
|
||||
void GuiGradientCtrl::onMouseEnter(const GuiEvent &event)
|
||||
{
|
||||
mMouseOver = true;
|
||||
}
|
||||
|
||||
void GuiGradientCtrl::onMouseLeave(const GuiEvent &)
|
||||
{
|
||||
// Reset state
|
||||
mMouseOver = false;
|
||||
}
|
||||
|
||||
void GuiGradientCtrl::setupDefaultRange()
|
||||
{
|
||||
S32 l = mBlendRangeBox.point.x - mSwatchFactor;
|
||||
S32 r = mBlendRangeBox.extent.x - mSwatchFactor;
|
||||
|
||||
//setup alpha range (white/black only)
|
||||
ColorRange crW;
|
||||
crW.pos = l;
|
||||
crW.color = ColorI(255,255,255);
|
||||
crW.swatch = NULL;
|
||||
mAlphaRange.push_back( crW );
|
||||
|
||||
ColorRange crB;
|
||||
crB.pos = r;
|
||||
crB.color = ColorI(0,0,0);
|
||||
crB.swatch = NULL;
|
||||
mAlphaRange.push_back( crB );
|
||||
|
||||
//setup color range (only 1 color necessary)
|
||||
ColorRange crD;
|
||||
crD.pos = l;
|
||||
crD.color = ColorI(255,0,0);
|
||||
crD.swatch = NULL;
|
||||
mColorRange.push_back( crD );
|
||||
}
|
||||
|
||||
void GuiGradientCtrl::reInitSwatches( GuiGradientCtrl::PickMode )
|
||||
{
|
||||
//liable to crash in the guiEditor, needs fix
|
||||
for( S32 i = 0;i < mColorRange.size(); i++ )
|
||||
{
|
||||
if(mColorRange[i].swatch != NULL)
|
||||
{
|
||||
mColorRange[i].pos = mColorRange[i].swatch->getPosition().x;
|
||||
mColorRange[i].color = mColorRange[i].swatch->getColor();
|
||||
mColorRange[i].swatch->deleteObject();
|
||||
mColorRange[i].swatch = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
for( S32 i = 0;i < mAlphaRange.size(); i++ )
|
||||
{
|
||||
if(mAlphaRange[i].swatch != NULL)
|
||||
{
|
||||
mAlphaRange[i].pos = mAlphaRange[i].swatch->getPosition().x;
|
||||
mAlphaRange[i].color = mAlphaRange[i].swatch->getColor();
|
||||
mAlphaRange[i].swatch->deleteObject();
|
||||
mAlphaRange[i].swatch = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
S32 b = mBlendRangeBox.extent.y - mSwatchFactor;
|
||||
|
||||
if( mDisplayMode == pHorizColorRange )
|
||||
{
|
||||
for( S32 i = 0;i < mColorRange.size(); i++ )
|
||||
{
|
||||
mColorRange[i].swatch = new GuiGradientSwatchCtrl();
|
||||
mColorRange[i].swatch->registerObject();
|
||||
addObject(mColorRange[i].swatch);
|
||||
mColorRange[i].swatch->setPosition( Point2I( mColorRange[i].pos, b ) );// needs to be adjusted
|
||||
mColorRange[i].swatch->setColor(ColorF(mColorRange[i].color));
|
||||
}
|
||||
}
|
||||
|
||||
else if( mDisplayMode == pHorizAlphaRange )
|
||||
{
|
||||
for( S32 i = 0;i < mAlphaRange.size(); i++ )
|
||||
{
|
||||
mAlphaRange[i].swatch = new GuiGradientSwatchCtrl();
|
||||
mAlphaRange[i].swatch->registerObject();
|
||||
addObject(mAlphaRange[i].swatch);
|
||||
mAlphaRange[i].swatch->setPosition( Point2I( mAlphaRange[i].pos, b ) );// needs to be adjusted
|
||||
mAlphaRange[i].swatch->setColor(ColorF(mAlphaRange[i].color));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GuiGradientCtrl::addColorRange( Point2I pos, ColorF color )
|
||||
{
|
||||
if( pos.x + mSwatchFactor < mBlendRangeBox.point.x &&
|
||||
pos.x + mSwatchFactor > mBlendRangeBox.extent.x )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
ColorRange range;
|
||||
range.pos = pos.x - mSwatchFactor;
|
||||
range.color = color;
|
||||
|
||||
S32 b = mBlendRangeBox.extent.y - mSwatchFactor;
|
||||
|
||||
range.swatch = new GuiGradientSwatchCtrl();
|
||||
range.swatch->registerObject();
|
||||
addObject( range.swatch );
|
||||
range.swatch->setPosition( pos.x - mSwatchFactor, b );//swatch factor and default location is going to have to be placed
|
||||
range.swatch->setColor( color );
|
||||
|
||||
if( mDisplayMode == pHorizColorRange )
|
||||
{
|
||||
mColorRange.push_back( range );
|
||||
S32 size = mColorRange.size();
|
||||
if( size > 0 )
|
||||
dQsort( mColorRange.address(), size, sizeof(ColorRange), _numIncreasing);
|
||||
}
|
||||
else if( mDisplayMode == pHorizAlphaRange )
|
||||
{
|
||||
mAlphaRange.push_back( range );
|
||||
S32 size = mAlphaRange.size();
|
||||
if( size > 0 )
|
||||
dQsort( mAlphaRange.address(), size, sizeof(ColorRange), _numIncreasing);
|
||||
}
|
||||
}
|
||||
|
||||
void GuiGradientCtrl::removeColorRange( GuiGradientSwatchCtrl* swatch )
|
||||
{
|
||||
if( mDisplayMode == pHorizColorRange )
|
||||
{
|
||||
if( mColorRange.size() <= 1 )
|
||||
return;
|
||||
|
||||
for( S32 i = 0;i < mColorRange.size(); i++ )
|
||||
{
|
||||
if( mColorRange[i].swatch == swatch )
|
||||
{
|
||||
mColorRange.erase( U32(i) );
|
||||
swatch->safeDeleteObject();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if( mDisplayMode == pHorizAlphaRange )
|
||||
{
|
||||
if( mAlphaRange.size() <= 1 )
|
||||
return;
|
||||
|
||||
for( S32 i = 0;i < mAlphaRange.size(); i++ )
|
||||
{
|
||||
if( mAlphaRange[i].swatch == swatch )
|
||||
{
|
||||
mAlphaRange.erase( U32(i) );
|
||||
swatch->safeDeleteObject();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GuiGradientCtrl::sortColorRange()
|
||||
{
|
||||
if( mDisplayMode == pHorizColorRange )
|
||||
dQsort( mColorRange.address(), mColorRange.size(), sizeof(ColorRange), _numIncreasing);
|
||||
else if( mDisplayMode == pHorizAlphaRange )
|
||||
dQsort( mAlphaRange.address(), mAlphaRange.size(), sizeof(ColorRange), _numIncreasing);
|
||||
}
|
||||
|
||||
ConsoleMethod(GuiGradientCtrl, getColorCount, S32, 2, 2, "Get color count")
|
||||
{
|
||||
if( object->getDisplayMode() == GuiGradientCtrl::pHorizColorRange )
|
||||
return object->mColorRange.size();
|
||||
else if( object->getDisplayMode() == GuiGradientCtrl::pHorizColorRange )
|
||||
return object->mColorRange.size();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
ConsoleMethod(GuiGradientCtrl, getColor, const char*, 3, 3, "Get color value")
|
||||
{
|
||||
S32 idx = dAtoi(argv[2]);
|
||||
|
||||
if( object->getDisplayMode() == GuiGradientCtrl::pHorizColorRange )
|
||||
{
|
||||
if ( idx >= 0 && idx < object->mColorRange.size() )
|
||||
{
|
||||
char* rColor = Con::getReturnBuffer(256);
|
||||
rColor[0] = 0;
|
||||
|
||||
dSprintf(rColor, 256, "%f %f %f %f",
|
||||
object->mColorRange[idx].swatch->getColor().red,
|
||||
object->mColorRange[idx].swatch->getColor().green,
|
||||
object->mColorRange[idx].swatch->getColor().blue,
|
||||
object->mColorRange[idx].swatch->getColor().alpha);
|
||||
|
||||
return rColor;
|
||||
}
|
||||
}
|
||||
else if( object->getDisplayMode() == GuiGradientCtrl::pHorizColorRange )
|
||||
{
|
||||
if ( idx >= 0 && idx < object->mAlphaRange.size() )
|
||||
{
|
||||
char* rColor = Con::getReturnBuffer(256);
|
||||
rColor[0] = 0;
|
||||
|
||||
dSprintf(rColor, 256, "%f %f %f %f",
|
||||
object->mAlphaRange[idx].swatch->getColor().red,
|
||||
object->mAlphaRange[idx].swatch->getColor().green,
|
||||
object->mAlphaRange[idx].swatch->getColor().blue,
|
||||
object->mAlphaRange[idx].swatch->getColor().alpha);
|
||||
|
||||
return rColor;
|
||||
}
|
||||
}
|
||||
|
||||
return "1 1 1 1";
|
||||
}
|
||||
162
Engine/source/gui/controls/guiGradientCtrl.h
Normal file
162
Engine/source/gui/controls/guiGradientCtrl.h
Normal file
|
|
@ -0,0 +1,162 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// Copyright (c) 2012 GarageGames, LLC
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to
|
||||
// deal in the Software without restriction, including without limitation the
|
||||
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
// sell copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
// IN THE SOFTWARE.
|
||||
//-----------------------------------------------------------------------------
|
||||
#ifndef _GUIGRADIENTCTRL_H_
|
||||
#define _GUIGRADIENTCTRL_H_
|
||||
|
||||
#ifndef _GUICONTROL_H_
|
||||
#include "gui/core/guiControl.h"
|
||||
#endif
|
||||
|
||||
#ifndef _GUISWATCHBUTTONCTRL_H_
|
||||
#include "gui/buttons/guiSwatchButtonCtrl.h"
|
||||
#endif
|
||||
|
||||
class GuiGradientSwatchCtrl : public GuiSwatchButtonCtrl
|
||||
{
|
||||
private:
|
||||
typedef GuiSwatchButtonCtrl Parent;
|
||||
private:
|
||||
Point2I mMouseDownPosition;
|
||||
RectI mOrigBounds;
|
||||
public:
|
||||
DECLARE_CONOBJECT(GuiGradientSwatchCtrl);
|
||||
DECLARE_CALLBACK( void, onMouseDown, ());
|
||||
DECLARE_CALLBACK( void, onDoubleClick, ());
|
||||
GuiGradientSwatchCtrl();
|
||||
void onMouseDown(const GuiEvent &);
|
||||
void onRightMouseDown(const GuiEvent &);
|
||||
void onMouseDragged(const GuiEvent &event);
|
||||
void onRender(Point2I offset, const RectI &updateRect);
|
||||
bool onWake();
|
||||
protected:
|
||||
GFXTexHandle mPointer;
|
||||
StringTableEntry mColorFunction;
|
||||
};
|
||||
//----------------------------
|
||||
/// GuiGradientCtrl
|
||||
|
||||
class GuiGradientCtrl : public GuiControl
|
||||
{
|
||||
typedef GuiControl Parent;
|
||||
|
||||
public:
|
||||
enum PickMode
|
||||
{
|
||||
pHorizColorRange, ///< We have a range of base colors going horizontally
|
||||
pHorizAlphaRange, ///< We have a box which shows a range in alpha going horizontally
|
||||
};
|
||||
|
||||
enum SelectorMode
|
||||
{
|
||||
sHorizontal = 0, ///< Horizontal selector with small gap
|
||||
sVertical, ///< Vertical selector with small gap
|
||||
};
|
||||
|
||||
struct ColorRange
|
||||
{
|
||||
GuiGradientSwatchCtrl* swatch;
|
||||
S32 pos;
|
||||
ColorF color;
|
||||
};
|
||||
|
||||
Vector<ColorRange> mColorRange;
|
||||
Vector<ColorRange> mAlphaRange;
|
||||
S32 mSwatchFactor;
|
||||
RectI mBlendRangeBox;
|
||||
|
||||
private:
|
||||
|
||||
/// @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 drawBlendRangeBox(RectI &bounds, bool vertical, Vector<ColorRange> colorRange);
|
||||
/// @}
|
||||
|
||||
/// @name Core Variables
|
||||
/// @{
|
||||
ColorF mPickColor; ///< Color that has been picked from control
|
||||
ColorF mBaseColor; ///< Colour we display (in case of pallet and blend mode)
|
||||
PickMode mDisplayMode; ///< Current color display mode of the selector
|
||||
PickMode mSaveDisplayMode;
|
||||
|
||||
bool mPositionChanged; ///< Current position has changed since last render?
|
||||
bool mMouseOver; ///< Mouse is over?
|
||||
bool mMouseDown; ///< Mouse button down?
|
||||
bool mActionOnMove; ///< Perform onAction() when position has changed?
|
||||
|
||||
GFXStateBlockRef mStateBlock;
|
||||
|
||||
ColorF colorWhite;
|
||||
ColorF colorWhiteBlend;
|
||||
ColorF colorBlack;
|
||||
ColorF colorAlpha;
|
||||
ColorF colorAlphaW;
|
||||
/// @}
|
||||
String mColorFunction;
|
||||
|
||||
public:
|
||||
|
||||
DECLARE_CONOBJECT(GuiGradientCtrl);
|
||||
DECLARE_CATEGORY( "Gui Editor" );
|
||||
|
||||
GuiGradientCtrl();
|
||||
|
||||
static void initPersistFields();
|
||||
void onRender(Point2I offset, const RectI &updateRect);
|
||||
bool mShowReticle; ///< Show reticle on render
|
||||
/// @name Color Value Functions
|
||||
/// @{
|
||||
/// NOTE: setValue only sets baseColor, since setting pickColor wouldn't be useful
|
||||
void setValue(ColorF &value) {mBaseColor = value;}
|
||||
/// NOTE: getValue() returns baseColor if pallet (since pallet controls can't "pick" colours themselves)
|
||||
ColorF getValue() {return mPickColor;}
|
||||
void updateColor() {mPositionChanged = true;}
|
||||
/// @}
|
||||
|
||||
/// @name Input Events
|
||||
/// @{
|
||||
void onMouseDown(const GuiEvent &);
|
||||
void onMouseUp(const GuiEvent &);
|
||||
|
||||
void onMouseEnter(const GuiEvent &);
|
||||
void onMouseLeave(const GuiEvent &);
|
||||
/// @}
|
||||
|
||||
void addColorRange(ColorI color);
|
||||
void setupDefaultRange();
|
||||
|
||||
bool onAdd();
|
||||
void inspectPreApply();
|
||||
void inspectPostApply();
|
||||
void reInitSwatches( GuiGradientCtrl::PickMode );
|
||||
void addColorRange( Point2I pos, ColorF color );
|
||||
void removeColorRange( GuiGradientSwatchCtrl* swatch );
|
||||
void sortColorRange();
|
||||
|
||||
PickMode getDisplayMode() { return mDisplayMode; }
|
||||
};
|
||||
|
||||
typedef GuiGradientCtrl::PickMode GuiGradientPickMode;
|
||||
DefineEnumType( GuiGradientPickMode );
|
||||
|
||||
#endif
|
||||
1646
Engine/source/gui/controls/guiListBoxCtrl.cpp
Normal file
1646
Engine/source/gui/controls/guiListBoxCtrl.cpp
Normal file
File diff suppressed because it is too large
Load diff
155
Engine/source/gui/controls/guiListBoxCtrl.h
Normal file
155
Engine/source/gui/controls/guiListBoxCtrl.h
Normal file
|
|
@ -0,0 +1,155 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// Copyright (c) 2012 GarageGames, LLC
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to
|
||||
// deal in the Software without restriction, including without limitation the
|
||||
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
// sell copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
// IN THE SOFTWARE.
|
||||
//-----------------------------------------------------------------------------
|
||||
#ifndef _GUI_LISTBOXCTRL_H_
|
||||
#define _GUI_LISTBOXCTRL_H_
|
||||
|
||||
#ifndef _CONSOLETYPES_H_
|
||||
#include "console/consoleTypes.h"
|
||||
#endif
|
||||
|
||||
#ifndef _GUICONTROL_H_
|
||||
#include "gui/core/guiControl.h"
|
||||
#endif
|
||||
|
||||
#ifndef _DGL_H_
|
||||
#include "gfx/gfxDevice.h"
|
||||
#endif
|
||||
|
||||
#ifndef _H_GUIDEFAULTCONTROLRENDER_
|
||||
#include "gui/core/guiDefaultControlRender.h"
|
||||
#endif
|
||||
|
||||
#ifndef _GUISCROLLCTRL_H_
|
||||
#include "gui/containers/guiScrollCtrl.h"
|
||||
#endif
|
||||
|
||||
|
||||
class GuiListBoxCtrl : public GuiControl
|
||||
{
|
||||
private:
|
||||
typedef GuiControl Parent;
|
||||
public:
|
||||
|
||||
GuiListBoxCtrl();
|
||||
~GuiListBoxCtrl();
|
||||
DECLARE_CONOBJECT(GuiListBoxCtrl);
|
||||
DECLARE_CATEGORY( "Gui Lists" );
|
||||
DECLARE_DESCRIPTION( "Linear list of text items." );
|
||||
|
||||
DECLARE_CALLBACK( void, onMouseDragged, ());
|
||||
DECLARE_CALLBACK( void, onClearSelection, ());
|
||||
DECLARE_CALLBACK( void, onUnSelect, ( const char* index, const char* itemText));
|
||||
DECLARE_CALLBACK( void, onSelect, ( const char* index , const char* itemText ));
|
||||
DECLARE_CALLBACK( void, onDoubleClick, ());
|
||||
DECLARE_CALLBACK( void, onMouseUp, (const char* itemHit, const char* mouseClickCount));
|
||||
DECLARE_CALLBACK( void, onDeleteKey, ());
|
||||
DECLARE_CALLBACK( bool, isObjectMirrored, ( const char* indexIdString ));
|
||||
|
||||
struct LBItem
|
||||
{
|
||||
StringTableEntry itemText;
|
||||
String itemTooltip;
|
||||
bool isSelected;
|
||||
void* itemData;
|
||||
ColorF color;
|
||||
bool hasColor;
|
||||
};
|
||||
|
||||
VectorPtr<LBItem*> mItems;
|
||||
VectorPtr<LBItem*> mSelectedItems;
|
||||
|
||||
VectorPtr<LBItem*> mFilteredItems;
|
||||
|
||||
bool mMultipleSelections;
|
||||
Point2I mItemSize;
|
||||
bool mFitParentWidth;
|
||||
bool mColorBullet;
|
||||
LBItem* mLastClickItem;
|
||||
|
||||
// Persistence
|
||||
static void initPersistFields();
|
||||
|
||||
// Item Accessors
|
||||
S32 getItemCount();
|
||||
S32 getSelCount();
|
||||
S32 getSelectedItem();
|
||||
void getSelectedItems( Vector<S32> &Items );
|
||||
S32 getItemIndex( LBItem *item );
|
||||
StringTableEntry getItemText( S32 index );
|
||||
SimObject* getItemObject( S32 index );
|
||||
|
||||
void setCurSel( S32 index );
|
||||
void setCurSelRange( S32 start, S32 stop );
|
||||
void setItemText( S32 index, StringTableEntry text );
|
||||
|
||||
S32 addItem( StringTableEntry text, void *itemData = NULL );
|
||||
S32 addItemWithColor( StringTableEntry text, ColorF color = ColorF(-1, -1, -1), void *itemData = NULL);
|
||||
S32 insertItem( S32 index, StringTableEntry text, void *itemData = NULL );
|
||||
S32 insertItemWithColor( S32 index, StringTableEntry text, ColorF color = ColorF(-1, -1, -1), void *itemData = NULL);
|
||||
S32 findItemText( StringTableEntry text, bool caseSensitive = false );
|
||||
|
||||
void setItemColor(S32 index, ColorF color);
|
||||
void clearItemColor(S32 index);
|
||||
|
||||
void deleteItem( S32 index );
|
||||
void clearItems();
|
||||
void clearSelection();
|
||||
void removeSelection( LBItem *item, S32 index );
|
||||
void removeSelection( S32 index );
|
||||
void addSelection( LBItem *item, S32 index );
|
||||
void addSelection( S32 index );
|
||||
inline void setMultipleSelection( bool allowMultipleSelect = true ) { mMultipleSelections = allowMultipleSelect; };
|
||||
|
||||
bool hitTest( const Point2I& point, S32& outItem );
|
||||
|
||||
// Sizing
|
||||
void updateSize();
|
||||
virtual void parentResized(const RectI& oldParentRect, const RectI& newParentRect);
|
||||
virtual bool onWake();
|
||||
|
||||
// Rendering
|
||||
virtual void onRender( Point2I offset, const RectI &updateRect );
|
||||
virtual void onRenderItem( RectI itemRect, LBItem *item );
|
||||
void drawBox( const Point2I &box, S32 size, ColorI &outlineColor, ColorI &boxColor );
|
||||
bool renderTooltip( const Point2I &hoverPos, const Point2I& cursorPos, const char* tipText );
|
||||
void addFilteredItem( String item );
|
||||
void removeFilteredItem( String item );
|
||||
// Mouse/Key Events
|
||||
virtual void onMouseDown( const GuiEvent &event );
|
||||
virtual void onMouseDragged(const GuiEvent &event);
|
||||
virtual void onMouseUp( const GuiEvent& event );
|
||||
virtual bool onKeyDown( const GuiEvent &event );
|
||||
|
||||
// String Utility
|
||||
static U32 getStringElementCount( const char *string );
|
||||
static const char* getStringElement( const char* inString, const U32 index );
|
||||
|
||||
// SimSet Mirroring Stuff
|
||||
void setMirrorObject( SimSet *inObj );
|
||||
void _mirror();
|
||||
StringTableEntry _makeMirrorItemName( SimObject *inObj );
|
||||
|
||||
String mMirrorSetName;
|
||||
String mMakeNameCallback;
|
||||
};
|
||||
|
||||
#endif
|
||||
2379
Engine/source/gui/controls/guiMLTextCtrl.cpp
Normal file
2379
Engine/source/gui/controls/guiMLTextCtrl.cpp
Normal file
File diff suppressed because it is too large
Load diff
305
Engine/source/gui/controls/guiMLTextCtrl.h
Normal file
305
Engine/source/gui/controls/guiMLTextCtrl.h
Normal file
|
|
@ -0,0 +1,305 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// Copyright (c) 2012 GarageGames, LLC
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to
|
||||
// deal in the Software without restriction, including without limitation the
|
||||
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
// sell copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
// IN THE SOFTWARE.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef _GUIMLTEXTCTRL_H_
|
||||
#define _GUIMLTEXTCTRL_H_
|
||||
|
||||
#ifndef _GUICONTROL_H_
|
||||
#include "gui/core/guiControl.h"
|
||||
#endif
|
||||
|
||||
#ifndef _STRINGBUFFER_H_
|
||||
#include "core/stringBuffer.h"
|
||||
#endif
|
||||
|
||||
class GFont;
|
||||
class SFXTrack;
|
||||
|
||||
GFX_DeclareTextureProfile(GFXMLTextureProfile);
|
||||
class GuiMLTextCtrl : public GuiControl
|
||||
{
|
||||
typedef GuiControl Parent;
|
||||
|
||||
//-------------------------------------- Public interfaces...
|
||||
public:
|
||||
enum Justification
|
||||
{
|
||||
LeftJustify,
|
||||
RightJustify,
|
||||
CenterJustify,
|
||||
};
|
||||
|
||||
struct Font {
|
||||
char *faceName;
|
||||
U32 faceNameLen;
|
||||
U32 size;
|
||||
Resource<GFont> fontRes;
|
||||
Font *next;
|
||||
};
|
||||
|
||||
struct Bitmap {
|
||||
char bitmapName[1024];
|
||||
U32 bitmapNameLen;
|
||||
GFXTexHandle bitmapObject;
|
||||
Bitmap *next;
|
||||
};
|
||||
|
||||
struct URL
|
||||
{
|
||||
bool mouseDown;
|
||||
U32 textStart;
|
||||
U32 len;
|
||||
bool noUnderline;
|
||||
};
|
||||
|
||||
struct Style
|
||||
{
|
||||
ColorI color;
|
||||
ColorI shadowColor;
|
||||
ColorI linkColor;
|
||||
ColorI linkColorHL;
|
||||
Point2I shadowOffset;
|
||||
Font *font;
|
||||
bool used;
|
||||
Style *next;
|
||||
};
|
||||
|
||||
struct Atom
|
||||
{
|
||||
U32 textStart;
|
||||
U32 len;
|
||||
U32 xStart;
|
||||
U32 yStart;
|
||||
U32 width;
|
||||
U32 baseLine;
|
||||
U32 descent;
|
||||
Style *style;
|
||||
bool isClipped;
|
||||
|
||||
URL *url;
|
||||
Atom *next;
|
||||
};
|
||||
|
||||
struct Line {
|
||||
U32 y;
|
||||
U32 height;
|
||||
U32 divStyle;
|
||||
U32 textStart;
|
||||
U32 len;
|
||||
Atom *atomList;
|
||||
Line *next;
|
||||
};
|
||||
|
||||
struct BitmapRef : public RectI
|
||||
{
|
||||
BitmapRef *nextBlocker;
|
||||
U32 textStart;
|
||||
U32 len;
|
||||
Bitmap *bitmap;
|
||||
BitmapRef *next;
|
||||
};
|
||||
|
||||
struct LineTag {
|
||||
U32 id;
|
||||
S32 y;
|
||||
LineTag *next;
|
||||
};
|
||||
|
||||
GuiMLTextCtrl();
|
||||
~GuiMLTextCtrl();
|
||||
|
||||
DECLARE_CALLBACK( void, onURL, (const char* url));
|
||||
DECLARE_CALLBACK( void, onResize, ( const char* width, const char* maxY ));
|
||||
|
||||
// Text retrieval functions
|
||||
U32 getNumChars() const;
|
||||
U32 getText(char* pBuffer, const U32 bufferSize) const;
|
||||
U32 getWrappedText(char* pBuffer, const U32 bufferSize) const;
|
||||
const char* getTextContent();
|
||||
void insertChars(const char* inputChars,
|
||||
const U32 numInputChars,
|
||||
const U32 position);
|
||||
|
||||
// Text substitution functions
|
||||
void setText(const char* textBuffer, const U32 numChars);
|
||||
void addText(const char* textBuffer, const U32 numChars, bool reformat);
|
||||
|
||||
void setAlpha(F32 alpha) { mAlpha = alpha;}
|
||||
|
||||
bool setCursorPosition(const S32);
|
||||
void ensureCursorOnScreen();
|
||||
|
||||
// Scroll functions
|
||||
void scrollToTag( U32 id );
|
||||
void scrollToTop();
|
||||
void scrollToBottom();
|
||||
|
||||
virtual void reflow();
|
||||
|
||||
DECLARE_CONOBJECT(GuiMLTextCtrl);
|
||||
DECLARE_CATEGORY( "Gui Text" );
|
||||
DECLARE_DESCRIPTION( "A control that displays multiple lines of text." );
|
||||
|
||||
static void initPersistFields();
|
||||
|
||||
void setScriptValue(const char *value);
|
||||
const char *getScriptValue();
|
||||
|
||||
static char *stripControlChars(const char *inString);
|
||||
|
||||
//-------------------------------------- Protected Structures and constants
|
||||
protected:
|
||||
bool mIsEditCtrl;
|
||||
|
||||
U32 *mTabStops;
|
||||
U32 mTabStopCount;
|
||||
U32 mCurTabStop;
|
||||
|
||||
F32 mAlpha;
|
||||
|
||||
DataChunker mViewChunker;
|
||||
DataChunker mResourceChunker;
|
||||
Line *mLineList;
|
||||
Bitmap *mBitmapList;
|
||||
BitmapRef *mBitmapRefList;
|
||||
Font *mFontList;
|
||||
LineTag *mTagList;
|
||||
bool mDirty;
|
||||
Style *mCurStyle;
|
||||
|
||||
U32 mCurLMargin;
|
||||
U32 mCurRMargin;
|
||||
U32 mCurJustify;
|
||||
U32 mCurDiv;
|
||||
U32 mCurY;
|
||||
U32 mCurClipX;
|
||||
Atom *mLineAtoms;
|
||||
Atom **mLineAtomPtr;
|
||||
|
||||
Atom *mEmitAtoms;
|
||||
Atom **mEmitAtomPtr;
|
||||
|
||||
BitmapRef mSentinel;
|
||||
Line **mLineInsert;
|
||||
BitmapRef *mBlockList;
|
||||
U32 mScanPos;
|
||||
U32 mCurX;
|
||||
U32 mMaxY;
|
||||
URL *mCurURL;
|
||||
|
||||
URL *mHitURL;
|
||||
|
||||
void freeLineBuffers();
|
||||
void freeResources();
|
||||
|
||||
Bitmap *allocBitmap(const char *bitmapName, U32 bitmapNameLen);
|
||||
Font *allocFont(const char *faceName, U32 faceNameLen, U32 size);
|
||||
LineTag *allocLineTag(U32 id);
|
||||
void emitNewLine(U32 textStart);
|
||||
Atom *buildTextAtom(U32 start, U32 len, U32 left, U32 right, URL *url);
|
||||
void emitTextToken(U32 textStart, U32 len);
|
||||
void emitBitmapToken(Bitmap *bmp, U32 textStart, bool bitmapBreak);
|
||||
void processEmitAtoms();
|
||||
Atom *splitAtomListEmit(Atom *list, U32 width);
|
||||
void drawAtomText(bool sel, U32 start, U32 end, Atom *atom, Line *line, Point2I offset);
|
||||
Atom *findHitAtom(const Point2I localCoords);
|
||||
Style *allocStyle(Style *style);
|
||||
|
||||
static const U32 csmTextBufferGrowthSize;
|
||||
|
||||
//-------------------------------------- Data...
|
||||
protected:
|
||||
// Cursor position should always be <= mCurrTextSize
|
||||
U32 mCursorPosition;
|
||||
|
||||
// Actual text data. The line buffer is rebuilt from the linear text
|
||||
// given a specific width. TextBuffer is /not/ \0 terminated
|
||||
StringBuffer mTextBuffer;
|
||||
U32 mLineStart;
|
||||
S32 mMaxBufferSize;
|
||||
StringTableEntry mInitialText;
|
||||
|
||||
// Selection information
|
||||
bool mSelectionActive;
|
||||
U32 mSelectionStart;
|
||||
U32 mSelectionEnd;
|
||||
|
||||
U32 mVertMoveAnchor;
|
||||
bool mVertMoveAnchorValid;
|
||||
|
||||
S32 mSelectionAnchor;
|
||||
Point2I mSelectionAnchorDropped;
|
||||
|
||||
// Font resource
|
||||
Resource<GFont> mFont;
|
||||
|
||||
// Console settable parameters
|
||||
U32 mLineSpacingPixels;
|
||||
bool mAllowColorChars;
|
||||
bool mUseURLMouseCursor;
|
||||
|
||||
// Too many chars sound:
|
||||
SFXTrack* mDeniedSound;
|
||||
|
||||
//-------------------------------------- Protected interface
|
||||
protected:
|
||||
// Inserting and deleting character blocks...
|
||||
void deleteChars(const U32 rangeStart,
|
||||
const U32 rangeEnd);
|
||||
void copyToClipboard(const U32 rangeStart,
|
||||
const U32 rangeEnd);
|
||||
|
||||
// Selection maintainence
|
||||
bool isSelectionActive() const;
|
||||
void clearSelection();
|
||||
|
||||
// Pixel -> text position mappings
|
||||
S32 getTextPosition(const Point2I& localPosition);
|
||||
|
||||
// Gui control overrides
|
||||
bool onWake();
|
||||
void onSleep();
|
||||
void onPreRender();
|
||||
void onRender(Point2I offset, const RectI &updateRect);
|
||||
void getCursorPositionAndColor(Point2I &cursorTop, Point2I &cursorBottom, ColorI &color);
|
||||
void inspectPostApply();
|
||||
void parentResized(const RectI& oldParentRect, const RectI& newParentRect);
|
||||
bool onKeyDown(const GuiEvent& event);
|
||||
void onMouseDown(const GuiEvent&);
|
||||
void onMouseDragged(const GuiEvent&);
|
||||
void onMouseUp(const GuiEvent&);
|
||||
|
||||
virtual void getCursor(GuiCursor *&cursor, bool &showCursor, const GuiEvent &lastGuiEvent);
|
||||
|
||||
public:
|
||||
// Gui control overrides
|
||||
bool onAdd();
|
||||
|
||||
void setSelectionStart( U32 start ) { clearSelection(); mSelectionStart = start; };
|
||||
void setSelectionEnd( U32 end ) { mSelectionEnd = end;};
|
||||
void setSelectionActive(bool active) { mSelectionActive = active; };
|
||||
S32 getCursorPosition() { return( mCursorPosition ); }
|
||||
|
||||
virtual bool resize(const Point2I &newPosition, const Point2I &newExtent);
|
||||
};
|
||||
|
||||
#endif // _H_GUIMLTEXTCTRL_
|
||||
468
Engine/source/gui/controls/guiMLTextEditCtrl.cpp
Normal file
468
Engine/source/gui/controls/guiMLTextEditCtrl.cpp
Normal file
|
|
@ -0,0 +1,468 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// Copyright (c) 2012 GarageGames, LLC
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to
|
||||
// deal in the Software without restriction, including without limitation the
|
||||
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
// sell copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
// IN THE SOFTWARE.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "gui/controls/guiMLTextEditCtrl.h"
|
||||
#include "gui/containers/guiScrollCtrl.h"
|
||||
#include "gui/core/guiCanvas.h"
|
||||
#include "console/consoleTypes.h"
|
||||
#include "platform/event.h"
|
||||
#include "core/frameAllocator.h"
|
||||
#include "core/stringBuffer.h"
|
||||
#include "gfx/gfxDrawUtil.h"
|
||||
#include "console/engineAPI.h"
|
||||
|
||||
IMPLEMENT_CONOBJECT(GuiMLTextEditCtrl);
|
||||
|
||||
ConsoleDocClass( GuiMLTextEditCtrl,
|
||||
"@brief A text entry control that accepts the Gui Markup Language ('ML') tags and multiple lines.\n\n"
|
||||
|
||||
"@tsexample\n"
|
||||
"new GuiMLTextEditCtrl()\n"
|
||||
" {\n"
|
||||
" lineSpacing = \"2\";\n"
|
||||
" allowColorChars = \"0\";\n"
|
||||
" maxChars = \"-1\";\n"
|
||||
" deniedSound = \"DeniedSoundProfile\";\n"
|
||||
" text = \"\";\n"
|
||||
" escapeCommand = \"onEscapeScriptFunction();\";\n"
|
||||
" //Properties not specific to this control have been omitted from this example.\n"
|
||||
" };\n"
|
||||
"@endtsexample\n\n"
|
||||
|
||||
"@see GuiMLTextCtrl\n"
|
||||
"@see GuiControl\n\n"
|
||||
|
||||
"@ingroup GuiControls\n"
|
||||
);
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
GuiMLTextEditCtrl::GuiMLTextEditCtrl()
|
||||
{
|
||||
mEscapeCommand = StringTable->insert( "" );
|
||||
|
||||
mIsEditCtrl = true;
|
||||
|
||||
mActive = true;
|
||||
|
||||
mVertMoveAnchorValid = false;
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
GuiMLTextEditCtrl::~GuiMLTextEditCtrl()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
bool GuiMLTextEditCtrl::resize(const Point2I &newPosition, const Point2I &newExtent)
|
||||
{
|
||||
// We don't want to get any smaller than our parent:
|
||||
Point2I newExt = newExtent;
|
||||
GuiControl* parent = getParent();
|
||||
if ( parent )
|
||||
newExt.y = getMax( parent->getHeight(), newExt.y );
|
||||
|
||||
return Parent::resize( newPosition, newExt );
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
void GuiMLTextEditCtrl::initPersistFields()
|
||||
{
|
||||
addField( "escapeCommand", TypeString, Offset( mEscapeCommand, GuiMLTextEditCtrl ), "Script function to run whenever the 'escape' key is pressed when this control is in focus.\n");
|
||||
Parent::initPersistFields();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
void GuiMLTextEditCtrl::setFirstResponder()
|
||||
{
|
||||
Parent::setFirstResponder();
|
||||
|
||||
GuiCanvas *root = getRoot();
|
||||
if (root != NULL)
|
||||
{
|
||||
root->enableKeyboardTranslation();
|
||||
|
||||
// If the native OS accelerator keys are not disabled
|
||||
// then some key events like Delete, ctrl+V, etc may
|
||||
// not make it down to us.
|
||||
root->setNativeAcceleratorsEnabled( false );
|
||||
}
|
||||
}
|
||||
|
||||
void GuiMLTextEditCtrl::onLoseFirstResponder()
|
||||
{
|
||||
GuiCanvas *root = getRoot();
|
||||
if (root != NULL)
|
||||
{
|
||||
root->setNativeAcceleratorsEnabled( true );
|
||||
root->disableKeyboardTranslation();
|
||||
}
|
||||
|
||||
// Redraw the control:
|
||||
setUpdate();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
bool GuiMLTextEditCtrl::onWake()
|
||||
{
|
||||
if( !Parent::onWake() )
|
||||
return false;
|
||||
|
||||
getRoot()->enableKeyboardTranslation();
|
||||
return true;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Key events...
|
||||
bool GuiMLTextEditCtrl::onKeyDown(const GuiEvent& event)
|
||||
{
|
||||
if ( !isActive() )
|
||||
return false;
|
||||
|
||||
setUpdate();
|
||||
//handle modifiers first...
|
||||
if (event.modifier & SI_PRIMARY_CTRL)
|
||||
{
|
||||
switch(event.keyCode)
|
||||
{
|
||||
//copy/cut
|
||||
case KEY_C:
|
||||
case KEY_X:
|
||||
{
|
||||
//make sure we actually have something selected
|
||||
if (mSelectionActive)
|
||||
{
|
||||
copyToClipboard(mSelectionStart, mSelectionEnd);
|
||||
|
||||
//if we're cutting, also delete the selection
|
||||
if (event.keyCode == KEY_X)
|
||||
{
|
||||
mSelectionActive = false;
|
||||
deleteChars(mSelectionStart, mSelectionEnd);
|
||||
mCursorPosition = mSelectionStart;
|
||||
}
|
||||
else
|
||||
mCursorPosition = mSelectionEnd + 1;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
//paste
|
||||
case KEY_V:
|
||||
{
|
||||
const char *clipBuf = Platform::getClipboard();
|
||||
if (dStrlen(clipBuf) > 0)
|
||||
{
|
||||
// Normal ascii keypress. Go ahead and add the chars...
|
||||
if (mSelectionActive == true)
|
||||
{
|
||||
mSelectionActive = false;
|
||||
deleteChars(mSelectionStart, mSelectionEnd);
|
||||
mCursorPosition = mSelectionStart;
|
||||
}
|
||||
|
||||
insertChars(clipBuf, dStrlen(clipBuf), mCursorPosition);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if ( event.modifier & SI_SHIFT )
|
||||
{
|
||||
switch ( event.keyCode )
|
||||
{
|
||||
case KEY_TAB:
|
||||
return( Parent::onKeyDown( event ) );
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if ( event.modifier == 0 )
|
||||
{
|
||||
switch (event.keyCode)
|
||||
{
|
||||
// Escape:
|
||||
case KEY_ESCAPE:
|
||||
if ( mEscapeCommand[0] )
|
||||
{
|
||||
Con::evaluate( mEscapeCommand );
|
||||
return( true );
|
||||
}
|
||||
return( Parent::onKeyDown( event ) );
|
||||
|
||||
// Deletion
|
||||
case KEY_BACKSPACE:
|
||||
case KEY_DELETE:
|
||||
handleDeleteKeys(event);
|
||||
return true;
|
||||
|
||||
// Cursor movement
|
||||
case KEY_LEFT:
|
||||
case KEY_RIGHT:
|
||||
case KEY_UP:
|
||||
case KEY_DOWN:
|
||||
case KEY_HOME:
|
||||
case KEY_END:
|
||||
handleMoveKeys(event);
|
||||
return true;
|
||||
|
||||
// Special chars...
|
||||
case KEY_TAB:
|
||||
// insert 3 spaces
|
||||
if (mSelectionActive == true)
|
||||
{
|
||||
mSelectionActive = false;
|
||||
deleteChars(mSelectionStart, mSelectionEnd);
|
||||
mCursorPosition = mSelectionStart;
|
||||
}
|
||||
insertChars( "\t", 1, mCursorPosition );
|
||||
return true;
|
||||
|
||||
case KEY_RETURN:
|
||||
// insert carriage return
|
||||
if (mSelectionActive == true)
|
||||
{
|
||||
mSelectionActive = false;
|
||||
deleteChars(mSelectionStart, mSelectionEnd);
|
||||
mCursorPosition = mSelectionStart;
|
||||
}
|
||||
insertChars( "\n", 1, mCursorPosition );
|
||||
return true;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ( (mFont && mFont->isValidChar(event.ascii)) || (!mFont && event.ascii != 0) )
|
||||
{
|
||||
// Normal ascii keypress. Go ahead and add the chars...
|
||||
if (mSelectionActive == true)
|
||||
{
|
||||
mSelectionActive = false;
|
||||
deleteChars(mSelectionStart, mSelectionEnd);
|
||||
mCursorPosition = mSelectionStart;
|
||||
}
|
||||
|
||||
UTF8 *outString = NULL;
|
||||
U32 outStringLen = 0;
|
||||
|
||||
#ifdef TORQUE_UNICODE
|
||||
|
||||
UTF16 inData[2] = { event.ascii, 0 };
|
||||
StringBuffer inBuff(inData);
|
||||
|
||||
FrameTemp<UTF8> outBuff(4);
|
||||
inBuff.getCopy8(outBuff, 4);
|
||||
|
||||
outString = outBuff;
|
||||
outStringLen = dStrlen(outBuff);
|
||||
#else
|
||||
char ascii = char(event.ascii);
|
||||
outString = &ascii;
|
||||
outStringLen = 1;
|
||||
#endif
|
||||
|
||||
insertChars(outString, outStringLen, mCursorPosition);
|
||||
mVertMoveAnchorValid = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Otherwise, let the parent have the event...
|
||||
return Parent::onKeyDown(event);
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------
|
||||
void GuiMLTextEditCtrl::handleDeleteKeys(const GuiEvent& event)
|
||||
{
|
||||
if ( isSelectionActive() )
|
||||
{
|
||||
mSelectionActive = false;
|
||||
deleteChars(mSelectionStart, mSelectionEnd+1);
|
||||
mCursorPosition = mSelectionStart;
|
||||
}
|
||||
else
|
||||
{
|
||||
switch ( event.keyCode )
|
||||
{
|
||||
case KEY_BACKSPACE:
|
||||
if (mCursorPosition != 0)
|
||||
{
|
||||
// delete one character left
|
||||
deleteChars(mCursorPosition-1, mCursorPosition);
|
||||
setUpdate();
|
||||
}
|
||||
break;
|
||||
|
||||
case KEY_DELETE:
|
||||
if (mCursorPosition != mTextBuffer.length())
|
||||
{
|
||||
// delete one character right
|
||||
deleteChars(mCursorPosition, mCursorPosition+1);
|
||||
setUpdate();
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
AssertFatal(false, "Unknown key code received!");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------
|
||||
void GuiMLTextEditCtrl::handleMoveKeys(const GuiEvent& event)
|
||||
{
|
||||
if ( event.modifier & SI_SHIFT )
|
||||
return;
|
||||
|
||||
mSelectionActive = false;
|
||||
|
||||
switch ( event.keyCode )
|
||||
{
|
||||
case KEY_LEFT:
|
||||
mVertMoveAnchorValid = false;
|
||||
// move one left
|
||||
if ( mCursorPosition != 0 )
|
||||
{
|
||||
mCursorPosition--;
|
||||
setUpdate();
|
||||
}
|
||||
break;
|
||||
|
||||
case KEY_RIGHT:
|
||||
mVertMoveAnchorValid = false;
|
||||
// move one right
|
||||
if ( mCursorPosition != mTextBuffer.length() )
|
||||
{
|
||||
mCursorPosition++;
|
||||
setUpdate();
|
||||
}
|
||||
break;
|
||||
|
||||
case KEY_UP:
|
||||
case KEY_DOWN:
|
||||
{
|
||||
Line* walk;
|
||||
for ( walk = mLineList; walk->next; walk = walk->next )
|
||||
{
|
||||
if ( mCursorPosition <= ( walk->textStart + walk->len ) )
|
||||
break;
|
||||
}
|
||||
|
||||
if ( !walk )
|
||||
return;
|
||||
|
||||
if ( event.keyCode == KEY_UP )
|
||||
{
|
||||
if ( walk == mLineList )
|
||||
return;
|
||||
}
|
||||
else if ( walk->next == NULL )
|
||||
return;
|
||||
|
||||
Point2I newPos;
|
||||
newPos.set( 0, walk->y );
|
||||
|
||||
// Find the x-position:
|
||||
if ( !mVertMoveAnchorValid )
|
||||
{
|
||||
Point2I cursorTopP, cursorBottomP;
|
||||
ColorI color;
|
||||
getCursorPositionAndColor(cursorTopP, cursorBottomP, color);
|
||||
mVertMoveAnchor = cursorTopP.x;
|
||||
mVertMoveAnchorValid = true;
|
||||
}
|
||||
|
||||
newPos.x = mVertMoveAnchor;
|
||||
|
||||
// Set the new y-position:
|
||||
if (event.keyCode == KEY_UP)
|
||||
newPos.y--;
|
||||
else
|
||||
newPos.y += (walk->height + 1);
|
||||
|
||||
if (setCursorPosition(getTextPosition(newPos)))
|
||||
mVertMoveAnchorValid = false;
|
||||
break;
|
||||
}
|
||||
|
||||
case KEY_HOME:
|
||||
case KEY_END:
|
||||
{
|
||||
mVertMoveAnchorValid = false;
|
||||
Line* walk;
|
||||
for (walk = mLineList; walk->next; walk = walk->next)
|
||||
{
|
||||
if (mCursorPosition <= (walk->textStart + walk->len))
|
||||
break;
|
||||
}
|
||||
|
||||
if (walk)
|
||||
{
|
||||
if (event.keyCode == KEY_HOME)
|
||||
{
|
||||
//place the cursor at the beginning of the first atom if there is one
|
||||
if (walk->atomList)
|
||||
mCursorPosition = walk->atomList->textStart;
|
||||
else
|
||||
mCursorPosition = walk->textStart;
|
||||
}
|
||||
else
|
||||
{
|
||||
mCursorPosition = walk->textStart;
|
||||
mCursorPosition += walk->len;
|
||||
}
|
||||
setUpdate();
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
AssertFatal(false, "Unknown move key code was received!");
|
||||
}
|
||||
|
||||
ensureCursorOnScreen();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
void GuiMLTextEditCtrl::onRender(Point2I offset, const RectI& updateRect)
|
||||
{
|
||||
Parent::onRender(offset, updateRect);
|
||||
|
||||
// We are the first responder, draw our cursor in the appropriate position...
|
||||
if (isFirstResponder())
|
||||
{
|
||||
Point2I top, bottom;
|
||||
ColorI color;
|
||||
getCursorPositionAndColor(top, bottom, color);
|
||||
GFX->getDrawUtil()->drawLine(top + offset, bottom + offset, mProfile->mCursorColor);
|
||||
}
|
||||
}
|
||||
|
||||
64
Engine/source/gui/controls/guiMLTextEditCtrl.h
Normal file
64
Engine/source/gui/controls/guiMLTextEditCtrl.h
Normal file
|
|
@ -0,0 +1,64 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// Copyright (c) 2012 GarageGames, LLC
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to
|
||||
// deal in the Software without restriction, including without limitation the
|
||||
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
// sell copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
// IN THE SOFTWARE.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef _GUIMLTEXTEDITCTRL_H_
|
||||
#define _GUIMLTEXTEDITCTRL_H_
|
||||
|
||||
#ifndef _GUIMLTEXTCTRL_H_
|
||||
#include "gui/controls/guiMLTextCtrl.h"
|
||||
#endif
|
||||
|
||||
class GuiMLTextEditCtrl : public GuiMLTextCtrl
|
||||
{
|
||||
typedef GuiMLTextCtrl Parent;
|
||||
|
||||
//-------------------------------------- Overrides
|
||||
protected:
|
||||
StringTableEntry mEscapeCommand;
|
||||
|
||||
// Events
|
||||
bool onKeyDown(const GuiEvent&event);
|
||||
|
||||
// Event forwards
|
||||
void handleMoveKeys(const GuiEvent&);
|
||||
void handleDeleteKeys(const GuiEvent&);
|
||||
|
||||
// rendering
|
||||
void onRender(Point2I offset, const RectI &updateRect);
|
||||
|
||||
public:
|
||||
GuiMLTextEditCtrl();
|
||||
~GuiMLTextEditCtrl();
|
||||
|
||||
virtual void setFirstResponder();
|
||||
virtual void onLoseFirstResponder();
|
||||
|
||||
bool onWake();
|
||||
bool resize(const Point2I &newPosition, const Point2I &newExtent);
|
||||
|
||||
DECLARE_CONOBJECT(GuiMLTextEditCtrl);
|
||||
DECLARE_DESCRIPTION( "A control that allows to edit multiple lines of text." );
|
||||
|
||||
static void initPersistFields();
|
||||
};
|
||||
|
||||
#endif // _H_GUIMLTEXTEDITCTRL_
|
||||
173
Engine/source/gui/controls/guiMaterialCtrl.cpp
Normal file
173
Engine/source/gui/controls/guiMaterialCtrl.cpp
Normal file
|
|
@ -0,0 +1,173 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// Copyright (c) 2012 GarageGames, LLC
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to
|
||||
// deal in the Software without restriction, including without limitation the
|
||||
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
// sell copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
// IN THE SOFTWARE.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "platform/platform.h"
|
||||
#include "gui/controls/guiMaterialCtrl.h"
|
||||
|
||||
#include "materials/baseMatInstance.h"
|
||||
#include "materials/materialManager.h"
|
||||
#include "materials/sceneData.h"
|
||||
#include "core/util/safeDelete.h"
|
||||
#include "console/console.h"
|
||||
#include "console/consoleTypes.h"
|
||||
#include "gfx/gfxDevice.h"
|
||||
#include "math/util/matrixSet.h"
|
||||
#include "scene/sceneRenderState.h"
|
||||
|
||||
IMPLEMENT_CONOBJECT( GuiMaterialCtrl );
|
||||
|
||||
ConsoleDocClass( GuiMaterialCtrl,
|
||||
"@brief Container for GuiMaterialPreview\n\n"
|
||||
"Editor use only.\n\n"
|
||||
"@internal"
|
||||
);
|
||||
|
||||
GuiMaterialCtrl::GuiMaterialCtrl()
|
||||
: mMaterialInst( NULL )
|
||||
{
|
||||
}
|
||||
|
||||
void GuiMaterialCtrl::initPersistFields()
|
||||
{
|
||||
addGroup( "Material" );
|
||||
addProtectedField( "materialName", TypeStringFilename, Offset( mMaterialName, GuiMaterialCtrl ), &GuiMaterialCtrl::_setMaterial, &defaultProtectedGetFn, "" );
|
||||
endGroup( "Material" );
|
||||
|
||||
Parent::initPersistFields();
|
||||
}
|
||||
|
||||
bool GuiMaterialCtrl::onWake()
|
||||
{
|
||||
if ( !Parent::onWake() )
|
||||
return false;
|
||||
|
||||
setActive( true );
|
||||
setMaterial( mMaterialName );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void GuiMaterialCtrl::onSleep()
|
||||
{
|
||||
SAFE_DELETE( mMaterialInst );
|
||||
|
||||
Parent::onSleep();
|
||||
}
|
||||
|
||||
bool GuiMaterialCtrl::_setMaterial( void *object, const char *index, const char *data )
|
||||
{
|
||||
static_cast<GuiMaterialCtrl *>( object )->setMaterial( data );
|
||||
|
||||
// Return false to keep the caller from setting the field.
|
||||
return false;
|
||||
}
|
||||
|
||||
bool GuiMaterialCtrl::setMaterial( const String &materialName )
|
||||
{
|
||||
SAFE_DELETE( mMaterialInst );
|
||||
mMaterialName = materialName;
|
||||
|
||||
if ( mMaterialName.isNotEmpty() && isAwake() )
|
||||
mMaterialInst = MATMGR->createMatInstance( mMaterialName, getGFXVertexFormat<GFXVertexPCT>() );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void GuiMaterialCtrl::inspectPostApply()
|
||||
{
|
||||
Parent::inspectPostApply();
|
||||
}
|
||||
|
||||
void GuiMaterialCtrl::onRender( Point2I offset, const RectI &updateRect )
|
||||
{
|
||||
Parent::onRender( offset, updateRect );
|
||||
|
||||
if ( !mMaterialInst )
|
||||
return;
|
||||
|
||||
// Draw a quad with the material assigned
|
||||
GFXVertexBufferHandle<GFXVertexPCT> verts( GFX, 4, GFXBufferTypeVolatile );
|
||||
verts.lock();
|
||||
|
||||
F32 screenLeft = updateRect.point.x;
|
||||
F32 screenRight = (updateRect.point.x + updateRect.extent.x);
|
||||
F32 screenTop = updateRect.point.y;
|
||||
F32 screenBottom = (updateRect.point.y + updateRect.extent.y);
|
||||
|
||||
const F32 fillConv = GFX->getFillConventionOffset();
|
||||
verts[0].point.set( screenLeft - fillConv, screenTop - fillConv, 0.f );
|
||||
verts[1].point.set( screenRight - fillConv, screenTop - fillConv, 0.f );
|
||||
verts[2].point.set( screenLeft - fillConv, screenBottom - fillConv, 0.f );
|
||||
verts[3].point.set( screenRight - fillConv, screenBottom - fillConv, 0.f );
|
||||
|
||||
verts[0].color = verts[1].color = verts[2].color = verts[3].color = ColorI( 255, 255, 255, 255 );
|
||||
|
||||
verts[0].texCoord.set( 0.0f, 0.0f );
|
||||
verts[1].texCoord.set( 1.0f, 0.0f );
|
||||
verts[2].texCoord.set( 0.0f, 1.0f );
|
||||
verts[3].texCoord.set( 1.0f, 1.0f );
|
||||
|
||||
verts.unlock();
|
||||
|
||||
GFX->setVertexBuffer( verts );
|
||||
|
||||
MatrixSet matSet;
|
||||
matSet.setWorld(GFX->getWorldMatrix());
|
||||
matSet.setView(GFX->getViewMatrix());
|
||||
matSet.setProjection(GFX->getProjectionMatrix());
|
||||
|
||||
MatrixF cameraMatrix( true );
|
||||
F32 left, right, top, bottom, nearPlane, farPlane;
|
||||
bool isOrtho;
|
||||
GFX->getFrustum( &left, &right, &bottom, &top, &nearPlane, &farPlane, &isOrtho );
|
||||
Frustum frust( isOrtho, left, right, top, bottom, nearPlane, farPlane, cameraMatrix );
|
||||
|
||||
SceneRenderState state
|
||||
(
|
||||
gClientSceneGraph,
|
||||
SPT_Diffuse,
|
||||
SceneCameraState( GFX->getViewport(), frust, GFX->getWorldMatrix(), GFX->getProjectionMatrix() ),
|
||||
gClientSceneGraph->getDefaultRenderPass(),
|
||||
false
|
||||
);
|
||||
|
||||
SceneData sgData;
|
||||
sgData.init( &state );
|
||||
sgData.wireframe = false; // Don't wireframe this.
|
||||
|
||||
while( mMaterialInst->setupPass( &state, sgData ) )
|
||||
{
|
||||
mMaterialInst->setSceneInfo( &state, sgData );
|
||||
mMaterialInst->setTransforms( matSet, &state );
|
||||
GFX->drawPrimitive( GFXTriangleStrip, 0, 2 );
|
||||
}
|
||||
|
||||
// Clean up
|
||||
GFX->setShader( NULL );
|
||||
GFX->setTexture( 0, NULL );
|
||||
}
|
||||
|
||||
ConsoleMethod( GuiMaterialCtrl, setMaterial, bool, 3, 3, "( string materialName )"
|
||||
"Set the material to be displayed in the control." )
|
||||
{
|
||||
return object->setMaterial( argv[2] );
|
||||
}
|
||||
67
Engine/source/gui/controls/guiMaterialCtrl.h
Normal file
67
Engine/source/gui/controls/guiMaterialCtrl.h
Normal file
|
|
@ -0,0 +1,67 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// Copyright (c) 2012 GarageGames, LLC
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to
|
||||
// deal in the Software without restriction, including without limitation the
|
||||
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
// sell copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
// IN THE SOFTWARE.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef _GUIMATERIALCTRL_H_
|
||||
#define _GUIMATERIALCTRL_H_
|
||||
|
||||
#ifndef _GUICONTAINER_H_
|
||||
#include "gui/containers/guiContainer.h"
|
||||
#endif
|
||||
|
||||
class BaseMatInstance;
|
||||
|
||||
|
||||
///
|
||||
class GuiMaterialCtrl : public GuiContainer
|
||||
{
|
||||
private:
|
||||
typedef GuiContainer Parent;
|
||||
|
||||
protected:
|
||||
|
||||
String mMaterialName;
|
||||
|
||||
BaseMatInstance *mMaterialInst;
|
||||
|
||||
static bool _setMaterial( void *object, const char *index, const char *data );
|
||||
|
||||
public:
|
||||
|
||||
GuiMaterialCtrl();
|
||||
|
||||
// ConsoleObject
|
||||
static void initPersistFields();
|
||||
void inspectPostApply();
|
||||
|
||||
DECLARE_CONOBJECT(GuiMaterialCtrl);
|
||||
DECLARE_CATEGORY( "Gui Editor" );
|
||||
|
||||
// GuiControl
|
||||
bool onWake();
|
||||
void onSleep();
|
||||
|
||||
bool setMaterial( const String &materialName );
|
||||
|
||||
void onRender( Point2I offset, const RectI &updateRect );
|
||||
};
|
||||
|
||||
#endif // _GUIMATERIALCTRL_H_
|
||||
1535
Engine/source/gui/controls/guiPopUpCtrl.cpp
Normal file
1535
Engine/source/gui/controls/guiPopUpCtrl.cpp
Normal file
File diff suppressed because it is too large
Load diff
174
Engine/source/gui/controls/guiPopUpCtrl.h
Normal file
174
Engine/source/gui/controls/guiPopUpCtrl.h
Normal file
|
|
@ -0,0 +1,174 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// Copyright (c) 2012 GarageGames, LLC
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to
|
||||
// deal in the Software without restriction, including without limitation the
|
||||
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
// sell copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
// IN THE SOFTWARE.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef _GUIPOPUPCTRL_H_
|
||||
#define _GUIPOPUPCTRL_H_
|
||||
|
||||
#ifndef _GUITEXTCTRL_H_
|
||||
#include "gui/controls/guiTextCtrl.h"
|
||||
#endif
|
||||
#ifndef _GUITEXTLISTCTRL_H_
|
||||
#include "gui/controls/guiTextListCtrl.h"
|
||||
#endif
|
||||
#ifndef _GUIBUTTONCTRL_H_
|
||||
#include "gui/buttons/guiButtonCtrl.h"
|
||||
#endif
|
||||
#ifndef _GUIBACKGROUNDCTRL_H_
|
||||
#include "gui/controls/guiBackgroundCtrl.h"
|
||||
#endif
|
||||
#ifndef _GUISCROLLCTRL_H_
|
||||
#include "gui/containers/guiScrollCtrl.h"
|
||||
#endif
|
||||
class GuiPopUpMenuCtrl;
|
||||
class GuiPopupTextListCtrl;
|
||||
|
||||
class GuiPopUpBackgroundCtrl : public GuiControl
|
||||
{
|
||||
protected:
|
||||
GuiPopUpMenuCtrl *mPopUpCtrl;
|
||||
GuiPopupTextListCtrl *mTextList;
|
||||
public:
|
||||
GuiPopUpBackgroundCtrl(GuiPopUpMenuCtrl *ctrl, GuiPopupTextListCtrl* textList);
|
||||
void onMouseDown(const GuiEvent &event);
|
||||
};
|
||||
|
||||
class GuiPopupTextListCtrl : public GuiTextListCtrl
|
||||
{
|
||||
private:
|
||||
typedef GuiTextListCtrl Parent;
|
||||
|
||||
protected:
|
||||
GuiPopUpMenuCtrl *mPopUpCtrl;
|
||||
|
||||
public:
|
||||
GuiPopupTextListCtrl(); // for inheritance
|
||||
GuiPopupTextListCtrl(GuiPopUpMenuCtrl *ctrl);
|
||||
|
||||
// GuiArrayCtrl overload:
|
||||
void onCellSelected(Point2I cell);
|
||||
|
||||
// GuiControl overloads:
|
||||
bool onKeyDown(const GuiEvent &event);
|
||||
void onMouseUp(const GuiEvent &event);
|
||||
void onRenderCell(Point2I offset, Point2I cell, bool selected, bool mouseOver);
|
||||
};
|
||||
|
||||
class GuiPopUpMenuCtrl : public GuiTextCtrl
|
||||
{
|
||||
typedef GuiTextCtrl Parent;
|
||||
|
||||
public:
|
||||
struct Entry
|
||||
{
|
||||
char buf[256];
|
||||
S32 id;
|
||||
U16 ascii;
|
||||
U16 scheme;
|
||||
bool usesColorBox; // Added
|
||||
ColorI colorbox; // Added
|
||||
};
|
||||
|
||||
struct Scheme
|
||||
{
|
||||
U32 id;
|
||||
ColorI fontColor;
|
||||
ColorI fontColorHL;
|
||||
ColorI fontColorSEL;
|
||||
};
|
||||
|
||||
bool mBackgroundCancel; // Added
|
||||
|
||||
protected:
|
||||
GuiPopupTextListCtrl *mTl;
|
||||
GuiScrollCtrl *mSc;
|
||||
GuiPopUpBackgroundCtrl *mBackground;
|
||||
Vector<Entry> mEntries;
|
||||
Vector<Scheme> mSchemes;
|
||||
S32 mSelIndex;
|
||||
S32 mMaxPopupHeight;
|
||||
F32 mIncValue;
|
||||
F32 mScrollCount;
|
||||
S32 mLastYvalue;
|
||||
GuiEvent mEventSave;
|
||||
S32 mRevNum;
|
||||
bool mInAction;
|
||||
bool mReplaceText;
|
||||
bool mMouseOver; // Added
|
||||
bool mRenderScrollInNA; // Added
|
||||
bool mReverseTextList; // Added - Should we reverse the text list if we display up?
|
||||
StringTableEntry mBitmapName; // Added
|
||||
Point2I mBitmapBounds; // Added
|
||||
GFXTexHandle mTextureNormal; // Added
|
||||
GFXTexHandle mTextureDepressed; // Added
|
||||
S32 mIdMax;
|
||||
|
||||
virtual void addChildren();
|
||||
virtual void repositionPopup();
|
||||
|
||||
public:
|
||||
GuiPopUpMenuCtrl(void);
|
||||
~GuiPopUpMenuCtrl();
|
||||
GuiScrollCtrl::Region mScrollDir;
|
||||
bool onWake(); // Added
|
||||
bool onAdd();
|
||||
void onSleep();
|
||||
void setBitmap(const char *name); // Added
|
||||
void sort();
|
||||
void sortID(); // Added
|
||||
void addEntry(const char *buf, S32 id = -1, U32 scheme = 0);
|
||||
void addScheme(U32 id, ColorI fontColor, ColorI fontColorHL, ColorI fontColorSEL);
|
||||
void onRender(Point2I offset, const RectI &updateRect);
|
||||
void onAction();
|
||||
virtual void closePopUp();
|
||||
void clear();
|
||||
void clearEntry( S32 entry ); // Added
|
||||
void onMouseDown(const GuiEvent &event);
|
||||
void onMouseUp(const GuiEvent &event);
|
||||
void onMouseEnter(const GuiEvent &event); // Added
|
||||
void onMouseLeave(const GuiEvent &); // Added
|
||||
void setupAutoScroll(const GuiEvent &event);
|
||||
void autoScroll();
|
||||
bool onKeyDown(const GuiEvent &event);
|
||||
void reverseTextList();
|
||||
bool getFontColor(ColorI &fontColor, S32 id, bool selected, bool mouseOver);
|
||||
bool getColoredBox(ColorI &boxColor, S32 id); // Added
|
||||
bool setEntryText( S32 id, const char* buf );
|
||||
|
||||
S32 getSelected();
|
||||
void setSelected(S32 id, bool bNotifyScript = true);
|
||||
void setFirstSelected(bool bNotifyScript = true); // Added
|
||||
void setNoneSelected(); // Added
|
||||
const char *getScriptValue();
|
||||
const char *getTextById(S32 id);
|
||||
S32 findText( const char* text );
|
||||
S32 getNumEntries() { return( mEntries.size() ); }
|
||||
void replaceText(S32);
|
||||
|
||||
DECLARE_CONOBJECT( GuiPopUpMenuCtrl );
|
||||
DECLARE_CATEGORY( "Gui Lists" );
|
||||
DECLARE_DESCRIPTION( "A control that allows to select a value from a drop-down list." );
|
||||
|
||||
static void initPersistFields(void);
|
||||
|
||||
};
|
||||
|
||||
#endif //_GUI_POPUPMENU_CTRL_H
|
||||
1728
Engine/source/gui/controls/guiPopUpCtrlEx.cpp
Normal file
1728
Engine/source/gui/controls/guiPopUpCtrlEx.cpp
Normal file
File diff suppressed because it is too large
Load diff
173
Engine/source/gui/controls/guiPopUpCtrlEx.h
Normal file
173
Engine/source/gui/controls/guiPopUpCtrlEx.h
Normal file
|
|
@ -0,0 +1,173 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// Copyright (c) 2012 GarageGames, LLC
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to
|
||||
// deal in the Software without restriction, including without limitation the
|
||||
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
// sell copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
// IN THE SOFTWARE.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef _GUIPOPUPCTRLEX_H_
|
||||
#define _GUIPOPUPCTRLEX_H_
|
||||
|
||||
#ifndef _GUITEXTCTRL_H_
|
||||
#include "gui/controls/guiTextCtrl.h"
|
||||
#endif
|
||||
#ifndef _GUITEXTLISTCTRL_H_
|
||||
#include "gui/controls/guiTextListCtrl.h"
|
||||
#endif
|
||||
#ifndef _GUIBUTTONCTRL_H_
|
||||
#include "gui/buttons/guiButtonCtrl.h"
|
||||
#endif
|
||||
#ifndef _GUISCROLLCTRL_H_
|
||||
#include "gui/containers/guiScrollCtrl.h"
|
||||
#endif
|
||||
class GuiPopUpMenuCtrlEx;
|
||||
class GuiPopupTextListCtrlEx;
|
||||
|
||||
class GuiPopUpBackgroundCtrlEx : public GuiControl
|
||||
{
|
||||
protected:
|
||||
GuiPopUpMenuCtrlEx *mPopUpCtrl;
|
||||
GuiPopupTextListCtrlEx *mTextList;
|
||||
public:
|
||||
GuiPopUpBackgroundCtrlEx(GuiPopUpMenuCtrlEx *ctrl, GuiPopupTextListCtrlEx* textList);
|
||||
void onMouseDown(const GuiEvent &event);
|
||||
};
|
||||
|
||||
class GuiPopupTextListCtrlEx : public GuiTextListCtrl
|
||||
{
|
||||
private:
|
||||
typedef GuiTextListCtrl Parent;
|
||||
|
||||
bool hasCategories();
|
||||
|
||||
protected:
|
||||
GuiPopUpMenuCtrlEx *mPopUpCtrl;
|
||||
|
||||
public:
|
||||
GuiPopupTextListCtrlEx(); // for inheritance
|
||||
GuiPopupTextListCtrlEx(GuiPopUpMenuCtrlEx *ctrl);
|
||||
|
||||
// GuiArrayCtrl overload:
|
||||
void onCellSelected(Point2I cell);
|
||||
|
||||
// GuiControl overloads:
|
||||
bool onKeyDown(const GuiEvent &event);
|
||||
void onMouseUp(const GuiEvent &event);
|
||||
void onMouseMove(const GuiEvent &event);
|
||||
void onRenderCell(Point2I offset, Point2I cell, bool selected, bool mouseOver);
|
||||
};
|
||||
|
||||
class GuiPopUpMenuCtrlEx : public GuiTextCtrl
|
||||
{
|
||||
typedef GuiTextCtrl Parent;
|
||||
|
||||
public:
|
||||
struct Entry
|
||||
{
|
||||
char buf[256];
|
||||
S32 id;
|
||||
U16 ascii;
|
||||
U16 scheme;
|
||||
bool usesColorBox; // Added
|
||||
ColorI colorbox; // Added
|
||||
};
|
||||
|
||||
struct Scheme
|
||||
{
|
||||
U32 id;
|
||||
ColorI fontColor;
|
||||
ColorI fontColorHL;
|
||||
ColorI fontColorSEL;
|
||||
};
|
||||
|
||||
bool mBackgroundCancel; // Added
|
||||
|
||||
protected:
|
||||
GuiPopupTextListCtrlEx *mTl;
|
||||
GuiScrollCtrl *mSc;
|
||||
GuiPopUpBackgroundCtrlEx *mBackground;
|
||||
Vector<Entry> mEntries;
|
||||
Vector<Scheme> mSchemes;
|
||||
S32 mSelIndex;
|
||||
S32 mMaxPopupHeight;
|
||||
F32 mIncValue;
|
||||
F32 mScrollCount;
|
||||
S32 mLastYvalue;
|
||||
GuiEvent mEventSave;
|
||||
S32 mRevNum;
|
||||
bool mInAction;
|
||||
bool mReplaceText;
|
||||
bool mMouseOver; // Added
|
||||
bool mRenderScrollInNA; // Added
|
||||
bool mReverseTextList; // Added - Should we reverse the text list if we display up?
|
||||
bool mHotTrackItems;
|
||||
StringTableEntry mBitmapName; // Added
|
||||
Point2I mBitmapBounds; // Added
|
||||
GFXTexHandle mTextureNormal; // Added
|
||||
GFXTexHandle mTextureDepressed; // Added
|
||||
S32 mIdMax;
|
||||
|
||||
virtual void addChildren();
|
||||
virtual void repositionPopup();
|
||||
|
||||
public:
|
||||
GuiPopUpMenuCtrlEx(void);
|
||||
~GuiPopUpMenuCtrlEx();
|
||||
GuiScrollCtrl::Region mScrollDir;
|
||||
bool onWake(); // Added
|
||||
bool onAdd();
|
||||
void onSleep();
|
||||
void setBitmap(const char *name); // Added
|
||||
void sort();
|
||||
void sortID(); // Added
|
||||
void addEntry(const char *buf, S32 id = -1, U32 scheme = 0);
|
||||
void addScheme(U32 id, ColorI fontColor, ColorI fontColorHL, ColorI fontColorSEL);
|
||||
void onRender(Point2I offset, const RectI &updateRect);
|
||||
void onAction();
|
||||
virtual void closePopUp();
|
||||
void clear();
|
||||
void clearEntry( S32 entry ); // Added
|
||||
void onMouseDown(const GuiEvent &event);
|
||||
void onMouseUp(const GuiEvent &event);
|
||||
void onMouseEnter(const GuiEvent &event); // Added
|
||||
void onMouseLeave(const GuiEvent &); // Added
|
||||
void setupAutoScroll(const GuiEvent &event);
|
||||
void autoScroll();
|
||||
bool onKeyDown(const GuiEvent &event);
|
||||
void reverseTextList();
|
||||
bool getFontColor(ColorI &fontColor, S32 id, bool selected, bool mouseOver);
|
||||
bool getColoredBox(ColorI &boxColor, S32 id); // Added
|
||||
|
||||
S32 getSelected();
|
||||
void setSelected(S32 id, bool bNotifyScript = true);
|
||||
void setFirstSelected(bool bNotifyScript = true); // Added
|
||||
void setNoneSelected(); // Added
|
||||
const char *getScriptValue();
|
||||
const char *getTextById(S32 id);
|
||||
S32 findText( const char* text );
|
||||
S32 getNumEntries() { return( mEntries.size() ); }
|
||||
void replaceText(S32);
|
||||
|
||||
DECLARE_CONOBJECT(GuiPopUpMenuCtrlEx);
|
||||
DECLARE_CATEGORY( "Gui Lists" );
|
||||
DECLARE_DESCRIPTION( "A control that allows to select a value from a drop-down list." );
|
||||
|
||||
static void initPersistFields(void);
|
||||
};
|
||||
|
||||
#endif //_GUIIMPROVEDPOPUPCTRL_H_
|
||||
584
Engine/source/gui/controls/guiSliderCtrl.cpp
Normal file
584
Engine/source/gui/controls/guiSliderCtrl.cpp
Normal file
|
|
@ -0,0 +1,584 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// Copyright (c) 2012 GarageGames, LLC
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to
|
||||
// deal in the Software without restriction, including without limitation the
|
||||
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
// sell copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
// IN THE SOFTWARE.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "console/console.h"
|
||||
#include "console/consoleTypes.h"
|
||||
#include "console/engineAPI.h"
|
||||
#include "gfx/gfxTextureManager.h"
|
||||
#include "gui/controls/guiSliderCtrl.h"
|
||||
#include "gui/core/guiDefaultControlRender.h"
|
||||
#include "platform/event.h"
|
||||
#include "gfx/primBuilder.h"
|
||||
#include "gfx/gfxDrawUtil.h"
|
||||
#include "sfx/sfxSystem.h"
|
||||
#include "sfx/sfxTrack.h"
|
||||
|
||||
|
||||
IMPLEMENT_CONOBJECT( GuiSliderCtrl );
|
||||
|
||||
ConsoleDocClass( GuiSliderCtrl,
|
||||
"@brief A control that displays a value between its minimal and maximal bounds using a slider placed on a vertical "
|
||||
"or horizontal axis.\n\n"
|
||||
|
||||
"A slider displays a value and allows that value to be changed by dragging a thumb control along the axis of the "
|
||||
"slider. In this way, the value is changed between its allowed minimum and maximum.\n\n"
|
||||
|
||||
"To hook up script code to the value changes of a slider, use the #command and #altCommand properties. #command is "
|
||||
"executed once the thumb is released by the user whereas #altCommand is called any time the slider value changes. "
|
||||
"When changing the slider value from script, however, trigger of #altCommand is suppressed by default.\n\n"
|
||||
|
||||
"The orientation of a slider is automatically determined from the ratio of its width to its height. If a slider is "
|
||||
"taller than it is wide, it will be rendered with a vertical orientation. If it is wider than it is tall, it will be "
|
||||
"rendered with a horizontal orientation.\n\n"
|
||||
|
||||
"The rendering of a slider depends on the bitmap in the slider's profile. This bitmap must be a bitmap array comprised "
|
||||
"of at least five bitmap rectangles. The rectangles are used such that:\n\n"
|
||||
|
||||
"- Rectangle #1: Left edge of slider\n"
|
||||
"- Rectangle #2: Center piece of slider; this is stretched between the left and right edge\n"
|
||||
"- Rectangle #3: Right edge of slider\n"
|
||||
"- Rectangle #4: Thumb button in normal state\n"
|
||||
"- Rectangle #5: Thumb button in highlighted (mouse-over) state\n\n"
|
||||
|
||||
"@tsexample\n"
|
||||
"// Create a sound source and a slider that changes the volume of the source.\n"
|
||||
"\n"
|
||||
"%source = sfxPlayOnce( \"art/sound/testing\", AudioLoop2D );\n"
|
||||
"\n"
|
||||
"new GuiSlider()\n"
|
||||
"{\n"
|
||||
" // Update the sound source volume when the slider is being dragged and released.\n"
|
||||
" command = %source @ \".setVolume( $ThisControl.value );\";\n"
|
||||
"\n"
|
||||
" // Limit the range to 0..1 since that is the allowable range for sound volumes.\n"
|
||||
" range = \"0 1\";\n"
|
||||
"};\n"
|
||||
"@endtsexample\n\n"
|
||||
|
||||
"@see GuiTextEditSliderCtrl\n"
|
||||
"@see GuiTextEditSliderBitmapCtrl\n\n"
|
||||
|
||||
"@ingroup GuiValues"
|
||||
);
|
||||
|
||||
|
||||
IMPLEMENT_CALLBACK( GuiSliderCtrl, onMouseDragged, void, (), (),
|
||||
"Called when the left mouse button is dragged across the slider." );
|
||||
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
GuiSliderCtrl::GuiSliderCtrl()
|
||||
: mRange( 0., 1.f ),
|
||||
mTicks( 10 ),
|
||||
mSnap( false ),
|
||||
mValue( 0.5f ),
|
||||
mThumbSize( 8, 20 ),
|
||||
mShiftPoint( 5 ),
|
||||
mShiftExtent( 10 ),
|
||||
mIncAmount( 0.f ),
|
||||
mDisplayValue( false ),
|
||||
mMouseOver( false ),
|
||||
mMouseDragged( false ),
|
||||
mDepressed( false )
|
||||
{
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
void GuiSliderCtrl::initPersistFields()
|
||||
{
|
||||
addGroup( "Slider" );
|
||||
|
||||
addField( "range", TypePoint2F, Offset( mRange, GuiSliderCtrl ),
|
||||
"Min and max values corresponding to left and right slider position." );
|
||||
addField( "ticks", TypeS32, Offset( mTicks, GuiSliderCtrl ),
|
||||
"Spacing between tick marks in pixels. 0=off." );
|
||||
addField( "snap", TypeBool, Offset( mSnap, GuiSliderCtrl ),
|
||||
"Whether to snap the slider to tick marks." );
|
||||
addProtectedField( "value", TypeF32, Offset( mValue, GuiSliderCtrl ),
|
||||
_setValue, defaultProtectedGetFn,
|
||||
"The value corresponding to the current slider position." );
|
||||
|
||||
endGroup( "Slider" );
|
||||
|
||||
Parent::initPersistFields();
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
void GuiSliderCtrl::setValue(F32 val, bool doCallback)
|
||||
{
|
||||
_updateThumb( val, mSnap, false, doCallback );
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
void GuiSliderCtrl::setActive( bool value )
|
||||
{
|
||||
if( !value && mDepressed )
|
||||
{
|
||||
// We're in the middle of a drag. Finish it here as once we've
|
||||
// been deactivated, we are not going to see a mouse-up event.
|
||||
|
||||
mDepressed = false;
|
||||
mouseUnlock();
|
||||
execConsoleCallback();
|
||||
}
|
||||
|
||||
Parent::setActive( value );
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
bool GuiSliderCtrl::onWake()
|
||||
{
|
||||
if( !Parent::onWake() )
|
||||
return false;
|
||||
|
||||
mHasTexture = mProfile->constructBitmapArray() >= NumBitmaps;
|
||||
if( mHasTexture )
|
||||
{
|
||||
mBitmapBounds = mProfile->mBitmapArrayRects.address();
|
||||
mThumbSize = Point2I( mBitmapBounds[ SliderButtonNormal ].extent.x, mBitmapBounds[ SliderButtonNormal ].extent.y );
|
||||
}
|
||||
|
||||
F32 value;
|
||||
if( mConsoleVariable[ 0 ] )
|
||||
value = getFloatVariable();
|
||||
else
|
||||
value = mValue;
|
||||
|
||||
mValue = mClampF( value, mRange.x, mRange.y );
|
||||
|
||||
// mouse scroll increment percentage is 5% of the range
|
||||
mIncAmount = ( ( mRange.y - mRange.x ) * 0.05 );
|
||||
|
||||
if( ( mThumbSize.y + mProfile->mFont->getHeight() - 4 ) <= getExtent().y )
|
||||
mDisplayValue = true;
|
||||
else
|
||||
mDisplayValue = false;
|
||||
|
||||
_updateThumb( mValue, mSnap, true );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
void GuiSliderCtrl::onMouseDown(const GuiEvent &event)
|
||||
{
|
||||
if ( !mActive || !mAwake || !mVisible )
|
||||
return;
|
||||
|
||||
mouseLock();
|
||||
setFirstResponder();
|
||||
mDepressed = true;
|
||||
|
||||
Point2I curMousePos = globalToLocalCoord( event.mousePoint );
|
||||
F32 value;
|
||||
if (getWidth() >= getHeight())
|
||||
value = F32(curMousePos.x-mShiftPoint) / F32(getWidth()-mShiftExtent)*(mRange.y-mRange.x) + mRange.x;
|
||||
else
|
||||
value = F32(curMousePos.y) / F32(getHeight())*(mRange.y-mRange.x) + mRange.x;
|
||||
|
||||
_updateThumb( value, mSnap || ( event.modifier & SI_SHIFT ) );
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
void GuiSliderCtrl::onMouseDragged( const GuiEvent &event )
|
||||
{
|
||||
if ( !mActive || !mAwake || !mVisible )
|
||||
return;
|
||||
|
||||
mMouseDragged = true;
|
||||
|
||||
F32 value = _getThumbValue( event );
|
||||
_updateThumb( value, mSnap || ( event.modifier & SI_SHIFT ) );
|
||||
|
||||
onMouseDragged_callback();
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
void GuiSliderCtrl::onMouseUp( const GuiEvent& event )
|
||||
{
|
||||
if ( !mActive || !mAwake || !mVisible )
|
||||
return;
|
||||
|
||||
mouseUnlock();
|
||||
|
||||
mDepressed = false;
|
||||
mMouseDragged = false;
|
||||
|
||||
_updateThumb( _getThumbValue( event ), event.modifier & SI_SHIFT );
|
||||
|
||||
execConsoleCallback();
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
void GuiSliderCtrl::onMouseEnter(const GuiEvent &event)
|
||||
{
|
||||
setUpdate();
|
||||
if( isMouseLocked() )
|
||||
{
|
||||
mDepressed = true;
|
||||
mMouseOver = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
if( mActive && mProfile->mSoundButtonOver )
|
||||
{
|
||||
//F32 pan = (F32(event.mousePoint.x)/F32(getRoot()->getWidth())*2.0f-1.0f)*0.8f;
|
||||
SFX->playOnce( mProfile->mSoundButtonOver );
|
||||
}
|
||||
|
||||
mMouseOver = true;
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
void GuiSliderCtrl::onMouseLeave(const GuiEvent &)
|
||||
{
|
||||
setUpdate();
|
||||
if( isMouseLocked() )
|
||||
mDepressed = false;
|
||||
mMouseOver = false;
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
bool GuiSliderCtrl::onMouseWheelUp(const GuiEvent &event)
|
||||
{
|
||||
if ( !mActive || !mAwake || !mVisible )
|
||||
return Parent::onMouseWheelUp(event);
|
||||
|
||||
_updateThumb( mValue + mIncAmount, ( event.modifier & SI_SHIFT ) );
|
||||
execConsoleCallback();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
bool GuiSliderCtrl::onMouseWheelDown(const GuiEvent &event)
|
||||
{
|
||||
if ( !mActive || !mAwake || !mVisible )
|
||||
return Parent::onMouseWheelUp(event);
|
||||
|
||||
_updateThumb( mValue - mIncAmount, ( event.modifier & SI_SHIFT ) );
|
||||
execConsoleCallback();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
void GuiSliderCtrl::_updateThumb( F32 _value, bool snap, bool onWake, bool doCallback )
|
||||
{
|
||||
if( snap && mTicks > 0 )
|
||||
{
|
||||
// If the shift key is held, snap to the nearest tick, if any are being drawn
|
||||
|
||||
F32 tickStep = (mRange.y - mRange.x) / F32(mTicks + 1);
|
||||
|
||||
F32 tickSteps = (_value - mRange.x) / tickStep;
|
||||
S32 actualTick = S32(tickSteps + 0.5);
|
||||
|
||||
_value = actualTick * tickStep + mRange.x;
|
||||
}
|
||||
|
||||
// Clamp the thumb to legal values.
|
||||
|
||||
if( _value < mRange.x )
|
||||
_value = mRange.x;
|
||||
if( _value > mRange.y )
|
||||
_value = mRange.y;
|
||||
|
||||
// If value hasn't changed and this isn't the initial update on
|
||||
// waking, do nothing.
|
||||
|
||||
if( mValue == _value && !onWake )
|
||||
return;
|
||||
|
||||
mValue = _value;
|
||||
|
||||
Point2I ext = getExtent();
|
||||
ext.x -= ( mShiftExtent + mThumbSize.x ) / 2;
|
||||
// update the bounding thumb rect
|
||||
if (getWidth() >= getHeight())
|
||||
{ // HORZ thumb
|
||||
S32 mx = (S32)((F32(ext.x) * (mValue-mRange.x) / (mRange.y-mRange.x)));
|
||||
S32 my = ext.y/2;
|
||||
if(mDisplayValue)
|
||||
my = mThumbSize.y/2;
|
||||
|
||||
mThumb.point.x = mx - (mThumbSize.x/2);
|
||||
mThumb.point.y = my - (mThumbSize.y/2);
|
||||
mThumb.extent = mThumbSize;
|
||||
}
|
||||
else
|
||||
{ // VERT thumb
|
||||
S32 mx = ext.x/2;
|
||||
S32 my = (S32)((F32(ext.y) * (mValue-mRange.x) / (mRange.y-mRange.x)));
|
||||
mThumb.point.x = mx - (mThumbSize.y/2);
|
||||
mThumb.point.y = my - (mThumbSize.x/2);
|
||||
mThumb.extent.x = mThumbSize.y;
|
||||
mThumb.extent.y = mThumbSize.x;
|
||||
}
|
||||
|
||||
setFloatVariable(mValue);
|
||||
setUpdate();
|
||||
|
||||
// Use the alt console command if you want to continually update:
|
||||
if ( !onWake && doCallback )
|
||||
execAltConsoleCallback();
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
void GuiSliderCtrl::onRender(Point2I offset, const RectI &updateRect)
|
||||
{
|
||||
Point2I pos(offset.x+mShiftPoint, offset.y);
|
||||
Point2I ext(getWidth() - mShiftExtent, getHeight());
|
||||
RectI thumb = mThumb;
|
||||
|
||||
if( mHasTexture )
|
||||
{
|
||||
if(mTicks > 0)
|
||||
{
|
||||
// TODO: tick marks should be positioned based on the bitmap dimensions.
|
||||
Point2I mid(ext.x, ext.y/2);
|
||||
Point2I oldpos = pos;
|
||||
pos += Point2I(1, 0);
|
||||
|
||||
PrimBuild::color4f( 0.f, 0.f, 0.f, 1.f );
|
||||
PrimBuild::begin( GFXLineList, ( mTicks + 2 ) * 2 );
|
||||
// tick marks
|
||||
for (U32 t = 0; t <= (mTicks+1); t++)
|
||||
{
|
||||
S32 x = (S32)(F32(mid.x+1)/F32(mTicks+1)*F32(t)) + pos.x;
|
||||
S32 y = pos.y + mid.y;
|
||||
PrimBuild::vertex2i(x, y + mShiftPoint);
|
||||
PrimBuild::vertex2i(x, y + mShiftPoint*2 + 2);
|
||||
}
|
||||
PrimBuild::end();
|
||||
// TODO: it would be nice, if the primitive builder were a little smarter,
|
||||
// so that we could change colors midstream.
|
||||
PrimBuild::color4f(0.9f, 0.9f, 0.9f, 1.0f);
|
||||
PrimBuild::begin( GFXLineList, ( mTicks + 2 ) * 2 );
|
||||
// tick marks
|
||||
for (U32 t = 0; t <= (mTicks+1); t++)
|
||||
{
|
||||
S32 x = (S32)(F32(mid.x+1)/F32(mTicks+1)*F32(t)) + pos.x + 1;
|
||||
S32 y = pos.y + mid.y + 1;
|
||||
PrimBuild::vertex2i(x, y + mShiftPoint );
|
||||
PrimBuild::vertex2i(x, y + mShiftPoint * 2 + 3);
|
||||
}
|
||||
PrimBuild::end();
|
||||
pos = oldpos;
|
||||
}
|
||||
|
||||
S32 index = SliderButtonNormal;
|
||||
if(mMouseOver)
|
||||
index = SliderButtonHighlight;
|
||||
GFX->getDrawUtil()->clearBitmapModulation();
|
||||
|
||||
//left border
|
||||
GFX->getDrawUtil()->drawBitmapSR(mProfile->mTextureObject, Point2I(offset.x,offset.y), mBitmapBounds[SliderLineLeft]);
|
||||
//right border
|
||||
GFX->getDrawUtil()->drawBitmapSR(mProfile->mTextureObject, Point2I(offset.x + getWidth() - mBitmapBounds[SliderLineRight].extent.x, offset.y), mBitmapBounds[SliderLineRight]);
|
||||
|
||||
|
||||
//draw our center piece to our slider control's border and stretch it
|
||||
RectI destRect;
|
||||
destRect.point.x = offset.x + mBitmapBounds[SliderLineLeft].extent.x;
|
||||
destRect.extent.x = getWidth() - mBitmapBounds[SliderLineLeft].extent.x - mBitmapBounds[SliderLineRight].extent.x;
|
||||
destRect.point.y = offset.y;
|
||||
destRect.extent.y = mBitmapBounds[SliderLineCenter].extent.y;
|
||||
|
||||
RectI stretchRect;
|
||||
stretchRect = mBitmapBounds[SliderLineCenter];
|
||||
stretchRect.inset(1,0);
|
||||
|
||||
GFX->getDrawUtil()->drawBitmapStretchSR(mProfile->mTextureObject, destRect, stretchRect);
|
||||
|
||||
//draw our control slider button
|
||||
thumb.point += pos;
|
||||
GFX->getDrawUtil()->drawBitmapSR(mProfile->mTextureObject,Point2I(thumb.point.x,offset.y ),mBitmapBounds[index]);
|
||||
|
||||
}
|
||||
else if (getWidth() >= getHeight())
|
||||
{
|
||||
Point2I mid(ext.x, ext.y/2);
|
||||
if(mDisplayValue)
|
||||
mid.set(ext.x, mThumbSize.y/2);
|
||||
|
||||
PrimBuild::color4f( 0.f, 0.f, 0.f, 1.f );
|
||||
PrimBuild::begin( GFXLineList, ( mTicks + 2 ) * 2 + 2);
|
||||
// horz rule
|
||||
PrimBuild::vertex2i( pos.x, pos.y + mid.y );
|
||||
PrimBuild::vertex2i( pos.x + mid.x, pos.y + mid.y );
|
||||
|
||||
// tick marks
|
||||
for( U32 t = 0; t <= ( mTicks + 1 ); t++ )
|
||||
{
|
||||
S32 x = (S32)( F32( mid.x - 1 ) / F32( mTicks + 1 ) * F32( t ) );
|
||||
PrimBuild::vertex2i( pos.x + x, pos.y + mid.y - mShiftPoint );
|
||||
PrimBuild::vertex2i( pos.x + x, pos.y + mid.y + mShiftPoint );
|
||||
}
|
||||
PrimBuild::end();
|
||||
}
|
||||
else
|
||||
{
|
||||
Point2I mid(ext.x/2, ext.y);
|
||||
|
||||
PrimBuild::color4f( 0.f, 0.f, 0.f, 1.f );
|
||||
PrimBuild::begin( GFXLineList, ( mTicks + 2 ) * 2 + 2);
|
||||
// horz rule
|
||||
PrimBuild::vertex2i( pos.x + mid.x, pos.y );
|
||||
PrimBuild::vertex2i( pos.x + mid.x, pos.y + mid.y );
|
||||
|
||||
// tick marks
|
||||
for( U32 t = 0; t <= ( mTicks + 1 ); t++ )
|
||||
{
|
||||
S32 y = (S32)( F32( mid.y - 1 ) / F32( mTicks + 1 ) * F32( t ) );
|
||||
PrimBuild::vertex2i( pos.x + mid.x - mShiftPoint, pos.y + y );
|
||||
PrimBuild::vertex2i( pos.x + mid.x + mShiftPoint, pos.y + y );
|
||||
}
|
||||
PrimBuild::end();
|
||||
mDisplayValue = false;
|
||||
}
|
||||
// draw the thumb
|
||||
thumb.point += pos;
|
||||
renderRaisedBox(thumb, mProfile);
|
||||
|
||||
if(mDisplayValue)
|
||||
{
|
||||
char buf[20];
|
||||
dSprintf(buf,sizeof(buf),"%0.3f",mValue);
|
||||
|
||||
Point2I textStart = thumb.point;
|
||||
|
||||
S32 txt_w = mProfile->mFont->getStrWidth((const UTF8 *)buf);
|
||||
|
||||
textStart.x += (S32)((thumb.extent.x/2.0f));
|
||||
textStart.y += thumb.extent.y - 2; //19
|
||||
textStart.x -= (txt_w/2);
|
||||
if(textStart.x < offset.x)
|
||||
textStart.x = offset.x;
|
||||
else if(textStart.x + txt_w > offset.x+getWidth())
|
||||
textStart.x -=((textStart.x + txt_w) - (offset.x+getWidth()));
|
||||
|
||||
GFX->getDrawUtil()->setBitmapModulation(mProfile->mFontColor);
|
||||
GFX->getDrawUtil()->drawText(mProfile->mFont, textStart, buf, mProfile->mFontColors);
|
||||
}
|
||||
renderChildControls(offset, updateRect);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
bool GuiSliderCtrl::resize( const Point2I& newPosition, const Point2I& newSize )
|
||||
{
|
||||
if( !Parent::resize( newPosition, newSize ) )
|
||||
return false;
|
||||
|
||||
_updateThumb( mValue, false, true, false );
|
||||
return true;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
void GuiSliderCtrl::parentResized( const RectI& oldParentRect, const RectI& newParentRect )
|
||||
{
|
||||
Parent::parentResized( oldParentRect, newParentRect );
|
||||
|
||||
_updateThumb( mValue, false, true, false );
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
F32 GuiSliderCtrl::_getThumbValue( const GuiEvent& event )
|
||||
{
|
||||
Point2I curMousePos = globalToLocalCoord( event.mousePoint );
|
||||
|
||||
F32 value;
|
||||
if( getWidth() >= getHeight() )
|
||||
value = F32( curMousePos.x - mShiftPoint ) / F32( getWidth() - mShiftExtent ) * ( mRange.y - mRange.x ) + mRange.x;
|
||||
else
|
||||
value = F32( curMousePos.y ) / F32( getHeight() ) * ( mRange.y - mRange.x ) + mRange.x;
|
||||
|
||||
if(value > mRange.y )
|
||||
value = mRange.y;
|
||||
else if( value < mRange.x )
|
||||
value = mRange.x;
|
||||
|
||||
if( mSnap || ( event.modifier & SI_SHIFT && mTicks >= 1 ) )
|
||||
{
|
||||
// If the shift key is held, snap to the nearest tick, if any are being drawn
|
||||
|
||||
F32 tickStep = ( mRange.y - mRange.x ) / F32( mTicks + 1 );
|
||||
|
||||
F32 tickSteps = (value - mRange.x ) / tickStep;
|
||||
S32 actualTick = S32( tickSteps + 0.5 );
|
||||
|
||||
value = actualTick * tickStep + mRange.x;
|
||||
AssertFatal( value <= mRange.y && value >= mRange.x, "Error, out of bounds value generated from shift-snap of slider" );
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
// Console Methods.
|
||||
//=============================================================================
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
DefineEngineMethod( GuiSliderCtrl, getValue, F32, (),,
|
||||
"Get the current value of the slider based on the position of the thumb.\n"
|
||||
"@return Slider position (from range.x to range.y)." )
|
||||
{
|
||||
return object->getValue();
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
DefineEngineMethod( GuiSliderCtrl, setValue, void, ( F32 pos, bool doCallback ), ( false ),
|
||||
"Set position of the thumb on the slider.\n"
|
||||
"@param pos New slider position (from range.x to range.y)\n"
|
||||
"@param doCallback If true, the altCommand callback will be invoked\n" )
|
||||
{
|
||||
object->setValue( pos, doCallback );
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
DefineEngineMethod( GuiSliderCtrl, isThumbBeingDragged, bool, (),,
|
||||
"Returns true if the thumb is currently being dragged by the user. This method is mainly useful "
|
||||
"for scrubbing type sliders where the slider position is sync'd to a changing value. When the "
|
||||
"user is dragging the thumb, however, the sync'ing should pause and not get in the way of the user." )
|
||||
{
|
||||
return object->isThumbBeingDragged();
|
||||
}
|
||||
116
Engine/source/gui/controls/guiSliderCtrl.h
Normal file
116
Engine/source/gui/controls/guiSliderCtrl.h
Normal file
|
|
@ -0,0 +1,116 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// Copyright (c) 2012 GarageGames, LLC
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to
|
||||
// deal in the Software without restriction, including without limitation the
|
||||
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
// sell copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
// IN THE SOFTWARE.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef _GUISLIDERCTRL_H_
|
||||
#define _GUISLIDERCTRL_H_
|
||||
|
||||
#ifndef _GUICONTROL_H_
|
||||
#include "gui/core/guiControl.h"
|
||||
#endif
|
||||
|
||||
|
||||
/// A slider control that selects out of a floating-point value range.
|
||||
class GuiSliderCtrl : public GuiControl
|
||||
{
|
||||
public:
|
||||
|
||||
typedef GuiControl Parent;
|
||||
|
||||
protected:
|
||||
|
||||
Point2F mRange;
|
||||
U32 mTicks;
|
||||
bool mSnap;
|
||||
F32 mValue;
|
||||
RectI mThumb;
|
||||
Point2I mThumbSize;
|
||||
S32 mShiftPoint;
|
||||
S32 mShiftExtent;
|
||||
F32 mIncAmount;
|
||||
bool mDisplayValue;
|
||||
bool mDepressed;
|
||||
bool mMouseOver;
|
||||
bool mMouseDragged;
|
||||
bool mHasTexture;
|
||||
|
||||
enum
|
||||
{
|
||||
SliderLineLeft = 0,
|
||||
SliderLineCenter,
|
||||
SliderLineRight,
|
||||
SliderButtonNormal,
|
||||
SliderButtonHighlight,
|
||||
NumBitmaps
|
||||
};
|
||||
RectI *mBitmapBounds;
|
||||
|
||||
F32 _getThumbValue( const GuiEvent& event );
|
||||
void _updateThumb( F32 value, bool snap = true, bool onWake = false, bool doCallback = true );
|
||||
|
||||
/// @name Callbacks
|
||||
/// @{
|
||||
|
||||
DECLARE_CALLBACK( void, onMouseDragged, () );
|
||||
|
||||
/// @}
|
||||
|
||||
static bool _setValue( void* object, const char* index, const char* data ) { static_cast< GuiSliderCtrl* >( object )->setValue( dAtof( data ) ); return false; }
|
||||
|
||||
public:
|
||||
|
||||
GuiSliderCtrl();
|
||||
|
||||
bool isThumbBeingDragged() const { return mDepressed; }
|
||||
|
||||
const Point2F& getRange() const { return mRange; }
|
||||
|
||||
// GuiControl.
|
||||
bool onWake();
|
||||
|
||||
void onMouseDown(const GuiEvent &event);
|
||||
void onMouseDragged(const GuiEvent &event);
|
||||
void onMouseUp(const GuiEvent &);
|
||||
void onMouseLeave(const GuiEvent &);
|
||||
void onMouseEnter(const GuiEvent &);
|
||||
bool onMouseWheelUp(const GuiEvent &event);
|
||||
bool onMouseWheelDown(const GuiEvent &event);
|
||||
|
||||
void setActive( bool value );
|
||||
|
||||
F32 getValue() const { return mValue; }
|
||||
void setScriptValue(const char *val) { setValue(dAtof(val)); }
|
||||
void setValue(F32 val, bool doCallback=false);
|
||||
|
||||
void onRender(Point2I offset, const RectI &updateRect);
|
||||
|
||||
virtual bool resize( const Point2I& newSize, const Point2I& newExtent );
|
||||
virtual void parentResized( const RectI& oldParentRect, const RectI& newParentRect );
|
||||
|
||||
static void initPersistFields();
|
||||
|
||||
DECLARE_CONOBJECT(GuiSliderCtrl);
|
||||
DECLARE_CATEGORY( "Gui Values" );
|
||||
DECLARE_DESCRIPTION( "A control that implements a horizontal or vertical slider to\n"
|
||||
"select/represent values in a certain range." )
|
||||
};
|
||||
|
||||
#endif
|
||||
234
Engine/source/gui/controls/guiTabPageCtrl.cpp
Normal file
234
Engine/source/gui/controls/guiTabPageCtrl.cpp
Normal file
|
|
@ -0,0 +1,234 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// Copyright (c) 2012 GarageGames, LLC
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to
|
||||
// deal in the Software without restriction, including without limitation the
|
||||
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
// sell copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
// IN THE SOFTWARE.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "console/consoleTypes.h"
|
||||
#include "console/console.h"
|
||||
#include "console/engineAPI.h"
|
||||
#include "gfx/gfxDevice.h"
|
||||
#include "gui/core/guiCanvas.h"
|
||||
#include "gui/controls/guiTabPageCtrl.h"
|
||||
#include "gui/containers/guiTabBookCtrl.h"
|
||||
#include "gui/core/guiDefaultControlRender.h"
|
||||
#include "gui/editor/guiEditCtrl.h"
|
||||
|
||||
IMPLEMENT_CONOBJECT(GuiTabPageCtrl);
|
||||
|
||||
ConsoleDocClass( GuiTabPageCtrl,
|
||||
"@brief A single page in a GuiTabBookCtrl.\n\n"
|
||||
|
||||
"@tsexample\n\n"
|
||||
"new GuiTabPageCtrl()\n"
|
||||
"{\n"
|
||||
" fitBook = \"1\";\n"
|
||||
" //Properties not specific to this control have been omitted from this example.\n"
|
||||
"};\n"
|
||||
"@endtsexample\n\n"
|
||||
|
||||
"@ingroup GuiContainers"
|
||||
);
|
||||
|
||||
GuiTabPageCtrl::GuiTabPageCtrl(void)
|
||||
{
|
||||
setExtent(Point2I(100, 200));
|
||||
mFitBook = false;
|
||||
dStrcpy(mText,(UTF8*)"TabPage");
|
||||
mActive = true;
|
||||
mIsContainer = true;
|
||||
}
|
||||
|
||||
void GuiTabPageCtrl::initPersistFields()
|
||||
{
|
||||
addField( "fitBook", TypeBool, Offset( mFitBook, GuiTabPageCtrl ),
|
||||
"Determines whether to resize this page when it is added to the tab book. "
|
||||
"If true, the page will be resized according to the tab book extents and "
|
||||
"<i>tabPosition</i> property." );
|
||||
|
||||
Parent::initPersistFields();
|
||||
}
|
||||
|
||||
bool GuiTabPageCtrl::onWake()
|
||||
{
|
||||
if (! Parent::onWake())
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void GuiTabPageCtrl::onSleep()
|
||||
{
|
||||
Parent::onSleep();
|
||||
}
|
||||
|
||||
GuiControl* GuiTabPageCtrl::findHitControl(const Point2I &pt, S32 initialLayer)
|
||||
{
|
||||
return Parent::findHitControl(pt, initialLayer);
|
||||
}
|
||||
|
||||
void GuiTabPageCtrl::onMouseDown(const GuiEvent &event)
|
||||
{
|
||||
setUpdate();
|
||||
Point2I localPoint = globalToLocalCoord( event.mousePoint );
|
||||
|
||||
GuiControl *ctrl = findHitControl(localPoint);
|
||||
if (ctrl && ctrl != this)
|
||||
{
|
||||
ctrl->onMouseDown(event);
|
||||
}
|
||||
}
|
||||
|
||||
bool GuiTabPageCtrl::onMouseDownEditor(const GuiEvent &event, Point2I offset )
|
||||
{
|
||||
#ifdef TORQUE_TOOLS
|
||||
// This shouldn't be called if it's not design time, but check just incase
|
||||
if ( GuiControl::smDesignTime )
|
||||
{
|
||||
GuiEditCtrl* edit = GuiControl::smEditorHandle;
|
||||
if( edit )
|
||||
edit->select( this );
|
||||
}
|
||||
|
||||
return Parent::onMouseDownEditor( event, offset );
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
GuiControl *GuiTabPageCtrl::findNextTabable(GuiControl *curResponder, bool firstCall)
|
||||
{
|
||||
//set the global if this is the first call (directly from the canvas)
|
||||
if (firstCall)
|
||||
{
|
||||
GuiControl::smCurResponder = NULL;
|
||||
}
|
||||
|
||||
//if the window does not already contain the first responder, return false
|
||||
//ie. Can't tab into or out of a window
|
||||
if (! controlIsChild(curResponder))
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
//loop through, checking each child to see if it is the one that follows the firstResponder
|
||||
GuiControl *tabCtrl = NULL;
|
||||
iterator i;
|
||||
for (i = begin(); i != end(); i++)
|
||||
{
|
||||
GuiControl *ctrl = static_cast<GuiControl *>(*i);
|
||||
tabCtrl = ctrl->findNextTabable(curResponder, false);
|
||||
if (tabCtrl) break;
|
||||
}
|
||||
|
||||
//to ensure the tab cycles within the current window...
|
||||
if (! tabCtrl)
|
||||
{
|
||||
tabCtrl = findFirstTabable();
|
||||
}
|
||||
|
||||
mFirstResponder = tabCtrl;
|
||||
return tabCtrl;
|
||||
}
|
||||
|
||||
GuiControl *GuiTabPageCtrl::findPrevTabable(GuiControl *curResponder, bool firstCall)
|
||||
{
|
||||
if (firstCall)
|
||||
{
|
||||
GuiControl::smPrevResponder = NULL;
|
||||
}
|
||||
|
||||
//if the window does not already contain the first responder, return false
|
||||
//ie. Can't tab into or out of a window
|
||||
if (! controlIsChild(curResponder))
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
//loop through, checking each child to see if it is the one that follows the firstResponder
|
||||
GuiControl *tabCtrl = NULL;
|
||||
iterator i;
|
||||
for (i = begin(); i != end(); i++)
|
||||
{
|
||||
GuiControl *ctrl = static_cast<GuiControl *>(*i);
|
||||
tabCtrl = ctrl->findPrevTabable(curResponder, false);
|
||||
if (tabCtrl) break;
|
||||
}
|
||||
|
||||
//to ensure the tab cycles within the current window...
|
||||
if (! tabCtrl)
|
||||
{
|
||||
tabCtrl = findLastTabable();
|
||||
}
|
||||
|
||||
mFirstResponder = tabCtrl;
|
||||
return tabCtrl;
|
||||
}
|
||||
|
||||
void GuiTabPageCtrl::setText(const char *txt)
|
||||
{
|
||||
Parent::setText( txt );
|
||||
|
||||
GuiControl *parent = getParent();
|
||||
if( parent )
|
||||
parent->setUpdate();
|
||||
};
|
||||
|
||||
|
||||
void GuiTabPageCtrl::selectWindow(void)
|
||||
{
|
||||
//first make sure this window is the front most of its siblings
|
||||
GuiControl *parent = getParent();
|
||||
if (parent)
|
||||
{
|
||||
parent->pushObjectToBack(this);
|
||||
}
|
||||
|
||||
//also set the first responder to be the one within this window
|
||||
setFirstResponder(mFirstResponder);
|
||||
}
|
||||
|
||||
void GuiTabPageCtrl::onRender(Point2I offset,const RectI &updateRect)
|
||||
{
|
||||
// Call directly into GuiControl to skip the GuiTextCtrl parent render
|
||||
GuiControl::onRender( offset, updateRect );
|
||||
}
|
||||
|
||||
void GuiTabPageCtrl::inspectPostApply()
|
||||
{
|
||||
Parent::inspectPostApply();
|
||||
|
||||
if( mFitBook )
|
||||
{
|
||||
GuiTabBookCtrl* book = dynamic_cast< GuiTabBookCtrl* >( getParent() );
|
||||
if( book )
|
||||
book->fitPage( this );
|
||||
}
|
||||
}
|
||||
|
||||
DefineEngineMethod( GuiTabPageCtrl, select, void, (),,
|
||||
"Select this page in its tab book." )
|
||||
{
|
||||
GuiTabBookCtrl* book = dynamic_cast< GuiTabBookCtrl* >( object->getParent() );
|
||||
if( !book )
|
||||
return;
|
||||
|
||||
book->selectPage( object );
|
||||
}
|
||||
72
Engine/source/gui/controls/guiTabPageCtrl.h
Normal file
72
Engine/source/gui/controls/guiTabPageCtrl.h
Normal file
|
|
@ -0,0 +1,72 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// Copyright (c) 2012 GarageGames, LLC
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to
|
||||
// deal in the Software without restriction, including without limitation the
|
||||
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
// sell copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
// IN THE SOFTWARE.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef _GUITABPAGECTRL_H_
|
||||
#define _GUITABPAGECTRL_H_
|
||||
|
||||
#ifndef _GUITEXTCTRL_H_
|
||||
#include "gui/controls/guiTextCtrl.h"
|
||||
#endif
|
||||
|
||||
class GuiTabPageCtrl : public GuiTextCtrl
|
||||
{
|
||||
private:
|
||||
typedef GuiTextCtrl Parent;
|
||||
|
||||
bool mFitBook; ///< Resize to fit book when first added
|
||||
S32 mTabIndex;
|
||||
|
||||
public:
|
||||
GuiTabPageCtrl();
|
||||
|
||||
DECLARE_CONOBJECT(GuiTabPageCtrl);
|
||||
DECLARE_CATEGORY( "Gui Containers" );
|
||||
DECLARE_DESCRIPTION( "A page in a GuiTabBookCtrl." );
|
||||
|
||||
static void initPersistFields();
|
||||
|
||||
bool onWake(); ///< The page awakens (becomes active)!
|
||||
void onSleep(); ///< The page sleeps (zzzzZZ - becomes inactive)
|
||||
void inspectPostApply();
|
||||
|
||||
bool getFitBook() { return mFitBook; }
|
||||
void setFitBook(bool state) { mFitBook = state; }
|
||||
|
||||
GuiControl* findHitControl(const Point2I &pt, S32 initialLayer = -1); ///< Find which control is hit by the mouse starting at a specified layer
|
||||
|
||||
void onMouseDown(const GuiEvent &event); ///< Called when a mouseDown event occurs
|
||||
bool onMouseDownEditor(const GuiEvent &event, Point2I offset ); ///< Called when a mouseDown event occurs and the GUI editor is active
|
||||
|
||||
S32 getTabIndex(void) { return mTabIndex; } ///< Get the tab index of this control
|
||||
|
||||
//only cycle tabs through the current window, so overwrite the method
|
||||
GuiControl* findNextTabable(GuiControl *curResponder, bool firstCall = true);
|
||||
GuiControl* findPrevTabable(GuiControl *curResponder, bool firstCall = true);
|
||||
|
||||
void selectWindow(void); ///< Select this window
|
||||
|
||||
virtual void setText(const char *txt = NULL); ///< Override setText function to signal parent we need to update.
|
||||
|
||||
void onRender(Point2I offset, const RectI &updateRect); ///< Called when it's time to render this page to the scene
|
||||
};
|
||||
|
||||
#endif //_GUI_WINDOW_CTRL_H
|
||||
246
Engine/source/gui/controls/guiTextCtrl.cpp
Normal file
246
Engine/source/gui/controls/guiTextCtrl.cpp
Normal file
|
|
@ -0,0 +1,246 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// Copyright (c) 2012 GarageGames, LLC
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to
|
||||
// deal in the Software without restriction, including without limitation the
|
||||
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
// sell copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
// IN THE SOFTWARE.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "platform/platform.h"
|
||||
#include "gui/controls/guiTextCtrl.h"
|
||||
|
||||
#include "gui/core/guiDefaultControlRender.h"
|
||||
#include "console/consoleTypes.h"
|
||||
#include "console/console.h"
|
||||
#include "core/color.h"
|
||||
#include "i18n/lang.h"
|
||||
#include "gfx/gfxDrawUtil.h"
|
||||
#include "console/engineAPI.h"
|
||||
|
||||
IMPLEMENT_CONOBJECT( GuiTextCtrl );
|
||||
|
||||
ConsoleDocClass( GuiTextCtrl,
|
||||
"@brief GUI control object this displays a single line of text, without TorqueML.\n\n"
|
||||
|
||||
"@tsexample\n"
|
||||
" new GuiTextCtrl()\n"
|
||||
" {\n"
|
||||
" text = \"Hello World\";\n"
|
||||
" textID = \"\"STR_HELLO\"\";\n"
|
||||
" maxlength = \"1024\";\n"
|
||||
" //Properties not specific to this control have been omitted from this example.\n"
|
||||
" };\n"
|
||||
"@endtsexample\n\n"
|
||||
|
||||
"@see GuiControl\n"
|
||||
"@see Localization\n\n"
|
||||
"@ingroup GuiCore\n"
|
||||
);
|
||||
|
||||
GuiTextCtrl::GuiTextCtrl()
|
||||
{
|
||||
//default fonts
|
||||
mInitialText = StringTable->insert("");
|
||||
mInitialTextID = StringTable->insert("");
|
||||
mText[0] = '\0';
|
||||
mMaxStrLen = GuiTextCtrl::MAX_STRING_LENGTH;
|
||||
}
|
||||
|
||||
DefineEngineMethod( GuiTextCtrl, setText, void, (const char* text),,
|
||||
"@brief Sets the text in the control.\n\n"
|
||||
"@param text Text to display in the control.\n"
|
||||
"@tsexample\n"
|
||||
"// Set the text to show in the control\n"
|
||||
"%text = \"Gideon - Destroyer of World\";\n\n"
|
||||
"// Inform the GuiTextCtrl control to change its text to the defined value\n"
|
||||
"%thisGuiTextCtrl.setText(%text);\n"
|
||||
"@endtsexample\n\n"
|
||||
"@see GuiControl")
|
||||
{
|
||||
object->setText( text );
|
||||
}
|
||||
|
||||
DefineEngineMethod( GuiTextCtrl, setTextID, void, (const char* textID),,
|
||||
"@brief Maps the text ctrl to a variable used in localization, rather than raw text.\n\n"
|
||||
"@param textID Name of variable text should be mapped to\n"
|
||||
"@tsexample\n"
|
||||
"// Inform the GuiTextCtrl control of the textID to use\n"
|
||||
"%thisGuiTextCtrl.setTextID(\"STR_QUIT\");\n"
|
||||
"@endtsexample\n\n"
|
||||
"@see GuiControl"
|
||||
"@see Localization")
|
||||
{
|
||||
object->setTextID( textID );
|
||||
}
|
||||
|
||||
void GuiTextCtrl::initPersistFields()
|
||||
{
|
||||
addProtectedField("text", TypeCaseString, Offset(mInitialText, GuiTextCtrl), setText, getTextProperty,
|
||||
"The text to show on the control.");
|
||||
|
||||
addField( "textID", TypeString, Offset( mInitialTextID, GuiTextCtrl ),
|
||||
"Maps the text of this control to a variable used in localization, rather than raw text.");
|
||||
|
||||
addField( "maxLength", TypeS32, Offset( mMaxStrLen, GuiTextCtrl ),
|
||||
"Defines the maximum length of the text. The default is 1024." );
|
||||
|
||||
Parent::initPersistFields();
|
||||
}
|
||||
|
||||
bool GuiTextCtrl::onAdd()
|
||||
{
|
||||
if(!Parent::onAdd())
|
||||
return false;
|
||||
|
||||
dStrncpy(mText, (UTF8*)mInitialText, MAX_STRING_LENGTH);
|
||||
mText[MAX_STRING_LENGTH] = '\0';
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void GuiTextCtrl::inspectPostApply()
|
||||
{
|
||||
Parent::inspectPostApply();
|
||||
if(mInitialTextID && *mInitialTextID != 0)
|
||||
setTextID(mInitialTextID);
|
||||
else if( mConsoleVariable[ 0 ] )
|
||||
setText( getVariable() );
|
||||
else
|
||||
setText(mInitialText);
|
||||
}
|
||||
|
||||
bool GuiTextCtrl::onWake()
|
||||
{
|
||||
if ( !Parent::onWake() )
|
||||
return false;
|
||||
|
||||
if( !mProfile->mFont )
|
||||
{
|
||||
Con::errorf( "GuiTextCtrl::onWake() - no valid font in profile '%s'", mProfile->getName() );
|
||||
return false;
|
||||
}
|
||||
if(mInitialTextID && *mInitialTextID != 0)
|
||||
setTextID(mInitialTextID);
|
||||
|
||||
if ( mConsoleVariable[0] )
|
||||
{
|
||||
const char *txt = Con::getVariable( mConsoleVariable );
|
||||
if ( txt )
|
||||
{
|
||||
if ( dStrlen( txt ) > mMaxStrLen )
|
||||
{
|
||||
char* buf = new char[mMaxStrLen + 1];
|
||||
dStrncpy( buf, txt, mMaxStrLen );
|
||||
buf[mMaxStrLen] = 0;
|
||||
setScriptValue( buf );
|
||||
delete [] buf;
|
||||
}
|
||||
else
|
||||
setScriptValue( txt );
|
||||
}
|
||||
}
|
||||
|
||||
//resize
|
||||
autoResize();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void GuiTextCtrl::autoResize()
|
||||
{
|
||||
if( mProfile->mAutoSizeWidth || mProfile->mAutoSizeHeight)
|
||||
{
|
||||
if( !mProfile->mFont )
|
||||
{
|
||||
mProfile->loadFont();
|
||||
if( !mProfile->mFont )
|
||||
return;
|
||||
}
|
||||
|
||||
Point2I newExtents = getExtent();
|
||||
if ( mProfile->mAutoSizeWidth )
|
||||
newExtents.x = mProfile->mFont->getStrWidth((const UTF8 *) mText );
|
||||
if ( mProfile->mAutoSizeHeight )
|
||||
newExtents.y = mProfile->mFont->getHeight() + 4;
|
||||
|
||||
setExtent( newExtents );
|
||||
}
|
||||
}
|
||||
|
||||
void GuiTextCtrl::setText(const char *txt)
|
||||
{
|
||||
//make sure we don't call this before onAdd();
|
||||
if( !mProfile )
|
||||
return;
|
||||
|
||||
if (txt)
|
||||
dStrncpy(mText, (UTF8*)txt, MAX_STRING_LENGTH);
|
||||
mText[MAX_STRING_LENGTH] = '\0';
|
||||
|
||||
setVariable((char*)mText);
|
||||
setUpdate();
|
||||
|
||||
autoResize();
|
||||
}
|
||||
|
||||
void GuiTextCtrl::setTextID(const char *id)
|
||||
{
|
||||
S32 n = Con::getIntVariable(id, -1);
|
||||
if(n != -1)
|
||||
{
|
||||
mInitialTextID = StringTable->insert(id);
|
||||
setTextID(n);
|
||||
}
|
||||
}
|
||||
void GuiTextCtrl::setTextID(S32 id)
|
||||
{
|
||||
const UTF8 *str = getGUIString(id);
|
||||
if(str)
|
||||
setText((const char*)str);
|
||||
//mInitialTextID = id;
|
||||
}
|
||||
|
||||
void GuiTextCtrl::onPreRender()
|
||||
{
|
||||
Parent::onPreRender();
|
||||
|
||||
const char * var = getVariable();
|
||||
if(var && var[0] && dStricmp((char*)mText, var))
|
||||
setText(var);
|
||||
}
|
||||
|
||||
void GuiTextCtrl::onRender(Point2I offset, const RectI &updateRect)
|
||||
{
|
||||
renderBorder( RectI( offset, getExtent() ), mProfile );
|
||||
|
||||
GFX->getDrawUtil()->setBitmapModulation( mProfile->mFontColor );
|
||||
renderJustifiedText(offset, getExtent(), (char*)mText);
|
||||
|
||||
//render the child controls
|
||||
renderChildControls(offset, updateRect);
|
||||
}
|
||||
|
||||
const char *GuiTextCtrl::getScriptValue()
|
||||
{
|
||||
return getText();
|
||||
}
|
||||
|
||||
void GuiTextCtrl::setScriptValue(const char *val)
|
||||
{
|
||||
setText(val);
|
||||
}
|
||||
92
Engine/source/gui/controls/guiTextCtrl.h
Normal file
92
Engine/source/gui/controls/guiTextCtrl.h
Normal file
|
|
@ -0,0 +1,92 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// Copyright (c) 2012 GarageGames, LLC
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to
|
||||
// deal in the Software without restriction, including without limitation the
|
||||
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
// sell copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
// IN THE SOFTWARE.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef _GUITEXTCTRL_H_
|
||||
#define _GUITEXTCTRL_H_
|
||||
|
||||
#ifndef _GFONT_H_
|
||||
#include "gfx/gFont.h"
|
||||
#endif
|
||||
#ifndef _GUITYPES_H_
|
||||
#include "gui/core/guiTypes.h"
|
||||
#endif
|
||||
#ifndef _GUICONTAINER_H_
|
||||
#include "gui/containers/guiContainer.h"
|
||||
#endif
|
||||
|
||||
class GuiTextCtrl : public GuiContainer
|
||||
{
|
||||
private:
|
||||
typedef GuiContainer Parent;
|
||||
|
||||
public:
|
||||
enum Constants { MAX_STRING_LENGTH = 1024 };
|
||||
|
||||
|
||||
protected:
|
||||
StringTableEntry mInitialText;
|
||||
StringTableEntry mInitialTextID;
|
||||
UTF8 mText[MAX_STRING_LENGTH + 1];
|
||||
S32 mMaxStrLen; // max string len, must be less then or equal to 255
|
||||
|
||||
public:
|
||||
|
||||
//creation methods
|
||||
DECLARE_CONOBJECT(GuiTextCtrl);
|
||||
DECLARE_CATEGORY( "Gui Text" );
|
||||
DECLARE_DESCRIPTION( "A control that displays a single line of text." );
|
||||
|
||||
GuiTextCtrl();
|
||||
static void initPersistFields();
|
||||
|
||||
//Parental methods
|
||||
bool onAdd();
|
||||
virtual bool onWake();
|
||||
|
||||
//text methods
|
||||
virtual void setText(const char *txt = NULL);
|
||||
virtual void setTextID(S32 id);
|
||||
virtual void setTextID(const char *id);
|
||||
const char *getText() { return (const char*)mText; }
|
||||
|
||||
// Text Property Accessors
|
||||
static bool setText(void *object, const char *index, const char *data)
|
||||
{ static_cast<GuiTextCtrl*>(object)->setText(data); return true; }
|
||||
static const char* getTextProperty(void* obj, const char* data)
|
||||
{ return static_cast<GuiTextCtrl*>(obj)->getText(); }
|
||||
|
||||
|
||||
void inspectPostApply();
|
||||
//rendering methods
|
||||
void onPreRender();
|
||||
void onRender(Point2I offset, const RectI &updateRect);
|
||||
void displayText( S32 xOffset, S32 yOffset );
|
||||
|
||||
// resizing
|
||||
void autoResize();
|
||||
|
||||
//Console methods
|
||||
const char *getScriptValue();
|
||||
void setScriptValue(const char *value);
|
||||
};
|
||||
|
||||
#endif //_GUI_TEXT_CONTROL_H_
|
||||
1748
Engine/source/gui/controls/guiTextEditCtrl.cpp
Normal file
1748
Engine/source/gui/controls/guiTextEditCtrl.cpp
Normal file
File diff suppressed because it is too large
Load diff
156
Engine/source/gui/controls/guiTextEditCtrl.h
Normal file
156
Engine/source/gui/controls/guiTextEditCtrl.h
Normal file
|
|
@ -0,0 +1,156 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// Copyright (c) 2012 GarageGames, LLC
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to
|
||||
// deal in the Software without restriction, including without limitation the
|
||||
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
// sell copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
// IN THE SOFTWARE.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef _GUITEXTEDITCTRL_H_
|
||||
#define _GUITEXTEDITCTRL_H_
|
||||
|
||||
#ifndef _GUITYPES_H_
|
||||
#include "gui/core/guiTypes.h"
|
||||
#endif
|
||||
#ifndef _GUITEXTCTRL_H_
|
||||
#include "gui/controls/guiTextCtrl.h"
|
||||
#endif
|
||||
#ifndef _STRINGBUFFER_H_
|
||||
#include "core/stringBuffer.h"
|
||||
#endif
|
||||
|
||||
class SFXTrack;
|
||||
|
||||
class GuiTextEditCtrl : public GuiTextCtrl
|
||||
{
|
||||
private:
|
||||
typedef GuiTextCtrl Parent;
|
||||
|
||||
protected:
|
||||
|
||||
DECLARE_CALLBACK( void, onTabComplete, (const char* val));
|
||||
DECLARE_CALLBACK( void, onReturn, ());
|
||||
DECLARE_CALLBACK( void, onValidate, ());
|
||||
|
||||
StringBuffer mTextBuffer;
|
||||
|
||||
String mValidateCommand;
|
||||
String mEscapeCommand;
|
||||
SFXTrack* mDeniedSound;
|
||||
|
||||
// for animating the cursor
|
||||
S32 mNumFramesElapsed;
|
||||
U32 mTimeLastCursorFlipped;
|
||||
ColorI mCursorColor;
|
||||
bool mCursorOn;
|
||||
|
||||
bool mInsertOn;
|
||||
S32 mMouseDragStart;
|
||||
Point2I mTextOffset;
|
||||
bool mTextOffsetReset;
|
||||
bool mDragHit;
|
||||
bool mTabComplete;
|
||||
S32 mScrollDir;
|
||||
|
||||
//undo members
|
||||
StringBuffer mUndoText;
|
||||
S32 mUndoBlockStart;
|
||||
S32 mUndoBlockEnd;
|
||||
S32 mUndoCursorPos;
|
||||
void saveUndoState();
|
||||
|
||||
S32 mBlockStart;
|
||||
S32 mBlockEnd;
|
||||
S32 mCursorPos;
|
||||
virtual S32 calculateCursorPos( const Point2I &globalPos );
|
||||
|
||||
bool mHistoryDirty;
|
||||
S32 mHistoryLast;
|
||||
S32 mHistoryIndex;
|
||||
S32 mHistorySize;
|
||||
bool mPasswordText;
|
||||
StringTableEntry mPasswordMask;
|
||||
|
||||
/// If set, any non-ESC key is handled here or not at all
|
||||
bool mSinkAllKeyEvents;
|
||||
UTF16 **mHistoryBuf;
|
||||
void updateHistory(StringBuffer *txt, bool moveIndex);
|
||||
|
||||
void playDeniedSound();
|
||||
void execConsoleCallback();
|
||||
|
||||
virtual void handleCharInput( U16 ascii );
|
||||
|
||||
S32 findNextWord();
|
||||
S32 findPrevWord();
|
||||
|
||||
public:
|
||||
GuiTextEditCtrl();
|
||||
~GuiTextEditCtrl();
|
||||
DECLARE_CONOBJECT(GuiTextEditCtrl);
|
||||
DECLARE_DESCRIPTION( "A control that allows to edit a single line of text. ");
|
||||
static void initPersistFields();
|
||||
|
||||
bool onAdd();
|
||||
|
||||
/// Get the contents of the control.
|
||||
///
|
||||
/// dest should be of size GuiTextCtrl::MAX_STRING_LENGTH+1.
|
||||
void getText(char *dest);
|
||||
virtual void getRenderText(char *dest);
|
||||
|
||||
void setText(S32 tag);
|
||||
virtual void setText(const UTF8* txt);
|
||||
virtual void setText(const UTF16* txt);
|
||||
S32 getCursorPos() { return( mCursorPos ); }
|
||||
void setCursorPos( const S32 newPos );
|
||||
|
||||
bool isAllTextSelected();
|
||||
void selectAllText();
|
||||
void clearSelectedText();
|
||||
|
||||
void forceValidateText();
|
||||
const char *getScriptValue();
|
||||
void setScriptValue(const char *value);
|
||||
|
||||
bool getSinkAllKeys() { return mSinkAllKeyEvents; }
|
||||
void setSinkAllKeys(bool state) { mSinkAllKeyEvents = state; }
|
||||
|
||||
virtual bool onKeyDown(const GuiEvent &event);
|
||||
virtual void onMouseDown(const GuiEvent &event);
|
||||
virtual void onMouseDragged(const GuiEvent &event);
|
||||
virtual void onMouseUp(const GuiEvent &event);
|
||||
|
||||
void onCopy(bool andCut);
|
||||
void onPaste();
|
||||
void onUndo();
|
||||
|
||||
virtual void setFirstResponder();
|
||||
virtual void onLoseFirstResponder();
|
||||
|
||||
bool hasText();
|
||||
|
||||
void onStaticModified(const char* slotName, const char* newValue = NULL);
|
||||
|
||||
void onPreRender();
|
||||
void onRender(Point2I offset, const RectI &updateRect);
|
||||
virtual void drawText( const RectI &drawRect, bool isFocused );
|
||||
|
||||
bool dealWithEnter( bool clearResponder );
|
||||
};
|
||||
|
||||
#endif //_GUI_TEXTEDIT_CTRL_H
|
||||
447
Engine/source/gui/controls/guiTextEditSliderBitmapCtrl.cpp
Normal file
447
Engine/source/gui/controls/guiTextEditSliderBitmapCtrl.cpp
Normal file
|
|
@ -0,0 +1,447 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// Copyright (c) 2012 GarageGames, LLC
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to
|
||||
// deal in the Software without restriction, including without limitation the
|
||||
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
// sell copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
// IN THE SOFTWARE.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "platform/platform.h"
|
||||
#include "gui/controls/guiTextEditSliderBitmapCtrl.h"
|
||||
|
||||
#include "console/consoleTypes.h"
|
||||
#include "console/console.h"
|
||||
#include "gui/core/guiCanvas.h"
|
||||
#include "gfx/gfxDevice.h"
|
||||
#include "gfx/gfxDrawUtil.h"
|
||||
|
||||
|
||||
IMPLEMENT_CONOBJECT(GuiTextEditSliderBitmapCtrl);
|
||||
|
||||
ConsoleDocClass( GuiTextEditSliderBitmapCtrl,
|
||||
"@brief GUI Control which displays a numerical value which can be increased "
|
||||
"or decreased using a pair of bitmap up/down buttons. \n\n"
|
||||
|
||||
"This control uses the bitmap specified in it's profile "
|
||||
"(GuiControlProfile::bitmapName). It takes this image and breaks up aspects "
|
||||
"of it to render the up and down arrows. It is also important to set "
|
||||
"GuiControlProfile::hasBitmapArray to true on the profile as well.\n\n"
|
||||
|
||||
"The bitmap referenced should be broken up into a 1 x 4 grid (using the top "
|
||||
"left color pixel as a border color between each of the images) in which it "
|
||||
"will map to the following places:\n"
|
||||
"<ol>\n"
|
||||
"<li>Up arrow active</li>\n"
|
||||
"<li>Up arrow inactive</li>\n"
|
||||
"<li>Down arrow active</li>\n"
|
||||
"<li>Down arrow inactive</li>\n"
|
||||
"</ol>\n\n"
|
||||
|
||||
"<pre>\n"
|
||||
"1\n"
|
||||
"2\n"
|
||||
"3\n"
|
||||
"4</pre>\n\n"
|
||||
|
||||
"@tsexample\n"
|
||||
"singleton GuiControlProfile (SliderBitmapGUIProfile)\n"
|
||||
"{\n"
|
||||
" bitmap = \"core/art/gui/images/sliderArray\";\n"
|
||||
" hasBitmapArray = true;\n"
|
||||
" opaque = false;\n"
|
||||
"};\n\n"
|
||||
|
||||
"new GuiTextEditSliderBitmapCtrl()\n"
|
||||
"{\n"
|
||||
" profile = \"SliderBitmapGUIProfile\";\n"
|
||||
" format = \"%3.2f\";\n"
|
||||
" range = \"-1e+03 1e+03\";\n"
|
||||
" increment = \"0.1\";\n"
|
||||
" focusOnMouseWheel = \"0\";\n"
|
||||
" bitmap = \"\";\n"
|
||||
" //Properties not specific to this control have been omitted from this example.\n"
|
||||
"};\n"
|
||||
"@endtsexample\n\n"
|
||||
|
||||
"@see GuiTextEditSliderCtrl\n\n"
|
||||
"@see GuiTextEditCtrl\n\n"
|
||||
|
||||
"@ingroup GuiCore\n"
|
||||
);
|
||||
|
||||
|
||||
GuiTextEditSliderBitmapCtrl::GuiTextEditSliderBitmapCtrl()
|
||||
{
|
||||
mRange.set(0.0f, 1.0f);
|
||||
mIncAmount = 1.0f;
|
||||
mValue = 0.0f;
|
||||
mMulInc = 0;
|
||||
mIncCounter = 0.0f;
|
||||
mFormat = StringTable->insert("%3.2f");
|
||||
mTextAreaHit = None;
|
||||
mFocusOnMouseWheel = false;
|
||||
mBitmapName = StringTable->insert( "" );
|
||||
}
|
||||
|
||||
GuiTextEditSliderBitmapCtrl::~GuiTextEditSliderBitmapCtrl()
|
||||
{
|
||||
}
|
||||
|
||||
void GuiTextEditSliderBitmapCtrl::initPersistFields()
|
||||
{
|
||||
addField("format", TypeString, Offset(mFormat, GuiTextEditSliderBitmapCtrl), "Character format type to place in the control.\n");
|
||||
addField("range", TypePoint2F, Offset(mRange, GuiTextEditSliderBitmapCtrl), "Maximum vertical and horizontal range to allow in the control.\n");
|
||||
addField("increment", TypeF32, Offset(mIncAmount, GuiTextEditSliderBitmapCtrl), "How far to increment the slider on each step.\n");
|
||||
addField("focusOnMouseWheel", TypeBool, Offset(mFocusOnMouseWheel, GuiTextEditSliderBitmapCtrl), "If true, the control will accept giving focus to the user when the mouse wheel is used.\n");
|
||||
addField("bitmap", TypeFilename,Offset(mBitmapName, GuiTextEditSliderBitmapCtrl), "Unused" );
|
||||
|
||||
Parent::initPersistFields();
|
||||
}
|
||||
|
||||
void GuiTextEditSliderBitmapCtrl::getText(char *dest)
|
||||
{
|
||||
Parent::getText(dest);
|
||||
}
|
||||
|
||||
void GuiTextEditSliderBitmapCtrl::setText(const char *txt)
|
||||
{
|
||||
mValue = dAtof(txt);
|
||||
checkRange();
|
||||
setValue();
|
||||
}
|
||||
|
||||
bool GuiTextEditSliderBitmapCtrl::onKeyDown(const GuiEvent &event)
|
||||
{
|
||||
return Parent::onKeyDown(event);
|
||||
}
|
||||
|
||||
void GuiTextEditSliderBitmapCtrl::checkRange()
|
||||
{
|
||||
if(mValue < mRange.x)
|
||||
mValue = mRange.x;
|
||||
else if(mValue > mRange.y)
|
||||
mValue = mRange.y;
|
||||
}
|
||||
|
||||
void GuiTextEditSliderBitmapCtrl::setValue()
|
||||
{
|
||||
char buf[20];
|
||||
// For some reason this sprintf is failing to convert
|
||||
// a floating point number to anything with %d, so cast it.
|
||||
if( dStricmp( mFormat, "%d" ) == 0 )
|
||||
dSprintf(buf,sizeof(buf),mFormat, (S32)mValue);
|
||||
else
|
||||
dSprintf(buf,sizeof(buf),mFormat, mValue);
|
||||
Parent::setText(buf);
|
||||
}
|
||||
|
||||
void GuiTextEditSliderBitmapCtrl::onMouseDown(const GuiEvent &event)
|
||||
{
|
||||
// If we're not active then skip out.
|
||||
if ( !mActive || !mAwake || !mVisible )
|
||||
{
|
||||
Parent::onMouseDown(event);
|
||||
return;
|
||||
}
|
||||
|
||||
char txt[20];
|
||||
Parent::getText(txt);
|
||||
mValue = dAtof(txt);
|
||||
|
||||
mMouseDownTime = Sim::getCurrentTime();
|
||||
GuiControl *parent = getParent();
|
||||
if(!parent)
|
||||
return;
|
||||
Point2I camPos = event.mousePoint;
|
||||
Point2I point = parent->localToGlobalCoord(getPosition());
|
||||
|
||||
if(camPos.x > point.x + getExtent().x - 14)
|
||||
{
|
||||
if(camPos.y > point.y + (getExtent().y/2))
|
||||
{
|
||||
mValue -=mIncAmount;
|
||||
mTextAreaHit = ArrowDown;
|
||||
mMulInc = -0.15f;
|
||||
}
|
||||
else
|
||||
{
|
||||
mValue +=mIncAmount;
|
||||
mTextAreaHit = ArrowUp;
|
||||
mMulInc = 0.15f;
|
||||
}
|
||||
|
||||
checkRange();
|
||||
setValue();
|
||||
mouseLock();
|
||||
|
||||
// We should get the focus and set the
|
||||
// cursor to the start of the text to
|
||||
// mimic the standard Windows behavior.
|
||||
setFirstResponder();
|
||||
mCursorPos = mBlockStart = mBlockEnd = 0;
|
||||
setUpdate();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
Parent::onMouseDown(event);
|
||||
}
|
||||
|
||||
void GuiTextEditSliderBitmapCtrl::onMouseDragged(const GuiEvent &event)
|
||||
{
|
||||
// If we're not active then skip out.
|
||||
if ( !mActive || !mAwake || !mVisible )
|
||||
{
|
||||
Parent::onMouseDragged(event);
|
||||
return;
|
||||
}
|
||||
|
||||
if(mTextAreaHit == None || mTextAreaHit == Slider)
|
||||
{
|
||||
mTextAreaHit = Slider;
|
||||
GuiControl *parent = getParent();
|
||||
if(!parent)
|
||||
return;
|
||||
Point2I camPos = event.mousePoint;
|
||||
Point2I point = parent->localToGlobalCoord(getPosition());
|
||||
F32 maxDis = 100;
|
||||
F32 val;
|
||||
if(camPos.y < point.y)
|
||||
{
|
||||
if((F32)point.y < maxDis)
|
||||
maxDis = (F32)point.y;
|
||||
|
||||
val = point.y - maxDis;
|
||||
|
||||
if(point.y > 0)
|
||||
mMulInc= 1.0f-(((float)camPos.y - val) / maxDis);
|
||||
else
|
||||
mMulInc = 1.0f;
|
||||
|
||||
checkIncValue();
|
||||
|
||||
return;
|
||||
}
|
||||
else if(camPos.y > point.y + getExtent().y)
|
||||
{
|
||||
GuiCanvas *root = getRoot();
|
||||
val = (F32)(root->getHeight() - (point.y + getHeight()));
|
||||
if(val < maxDis)
|
||||
maxDis = val;
|
||||
if( val > 0)
|
||||
mMulInc= -(F32)(camPos.y - (point.y + getHeight()))/maxDis;
|
||||
else
|
||||
mMulInc = -1.0f;
|
||||
checkIncValue();
|
||||
return;
|
||||
}
|
||||
mTextAreaHit = None;
|
||||
Parent::onMouseDragged(event);
|
||||
}
|
||||
}
|
||||
|
||||
void GuiTextEditSliderBitmapCtrl::onMouseUp(const GuiEvent &event)
|
||||
{
|
||||
// If we're not active then skip out.
|
||||
if ( !mActive || !mAwake || !mVisible )
|
||||
{
|
||||
Parent::onMouseUp(event);
|
||||
return;
|
||||
}
|
||||
|
||||
mMulInc = 0.0f;
|
||||
mouseUnlock();
|
||||
|
||||
if ( mTextAreaHit != None )
|
||||
|
||||
//if we released the mouse within this control, then the parent will call
|
||||
//the mConsoleCommand other wise we have to call it.
|
||||
Parent::onMouseUp(event);
|
||||
|
||||
//if we didn't release the mouse within this control, then perform the action
|
||||
// if (!cursorInControl())
|
||||
execConsoleCallback();
|
||||
|
||||
execAltConsoleCallback();
|
||||
|
||||
mTextAreaHit = None;
|
||||
}
|
||||
|
||||
bool GuiTextEditSliderBitmapCtrl::onMouseWheelUp(const GuiEvent &event)
|
||||
{
|
||||
if ( !mActive || !mAwake || !mVisible )
|
||||
return Parent::onMouseWheelUp(event);
|
||||
|
||||
if ( !isFirstResponder() && !mFocusOnMouseWheel )
|
||||
return false;
|
||||
|
||||
mValue += mIncAmount;
|
||||
|
||||
checkRange();
|
||||
setValue();
|
||||
|
||||
setFirstResponder();
|
||||
mCursorPos = mBlockStart = mBlockEnd = 0;
|
||||
setUpdate();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool GuiTextEditSliderBitmapCtrl::onMouseWheelDown(const GuiEvent &event)
|
||||
{
|
||||
if ( !mActive || !mAwake || !mVisible )
|
||||
return Parent::onMouseWheelDown(event);
|
||||
|
||||
if ( !isFirstResponder() && !mFocusOnMouseWheel )
|
||||
return false;
|
||||
|
||||
mValue -= mIncAmount;
|
||||
|
||||
checkRange();
|
||||
setValue();
|
||||
|
||||
setFirstResponder();
|
||||
mCursorPos = mBlockStart = mBlockEnd = 0;
|
||||
setUpdate();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void GuiTextEditSliderBitmapCtrl::checkIncValue()
|
||||
{
|
||||
if(mMulInc > 1.0f)
|
||||
mMulInc = 1.0f;
|
||||
else if(mMulInc < -1.0f)
|
||||
mMulInc = -1.0f;
|
||||
}
|
||||
|
||||
void GuiTextEditSliderBitmapCtrl::timeInc(U32 elapseTime)
|
||||
{
|
||||
S32 numTimes = elapseTime / 750;
|
||||
if(mTextAreaHit != Slider && numTimes > 0)
|
||||
{
|
||||
if(mTextAreaHit == ArrowUp)
|
||||
mMulInc = 0.15f * numTimes;
|
||||
else
|
||||
mMulInc = -0.15f * numTimes;
|
||||
|
||||
checkIncValue();
|
||||
}
|
||||
}
|
||||
bool GuiTextEditSliderBitmapCtrl::onWake()
|
||||
{
|
||||
if(!Parent::onWake())
|
||||
return false;
|
||||
|
||||
mNumberOfBitmaps = mProfile->constructBitmapArray();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void GuiTextEditSliderBitmapCtrl::onPreRender()
|
||||
{
|
||||
if (isFirstResponder())
|
||||
{
|
||||
U32 timeElapsed = Platform::getVirtualMilliseconds() - mTimeLastCursorFlipped;
|
||||
mNumFramesElapsed++;
|
||||
if ((timeElapsed > 500) && (mNumFramesElapsed > 3))
|
||||
{
|
||||
mCursorOn = !mCursorOn;
|
||||
mTimeLastCursorFlipped = Sim::getCurrentTime();
|
||||
mNumFramesElapsed = 0;
|
||||
setUpdate();
|
||||
}
|
||||
|
||||
//update the cursor if the text is scrolling
|
||||
if (mDragHit)
|
||||
{
|
||||
if ((mScrollDir < 0) && (mCursorPos > 0))
|
||||
{
|
||||
mCursorPos--;
|
||||
}
|
||||
else if ((mScrollDir > 0) && (mCursorPos < (S32)dStrlen(mText)))
|
||||
{
|
||||
mCursorPos++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GuiTextEditSliderBitmapCtrl::onRender(Point2I offset, const RectI &updateRect)
|
||||
{
|
||||
if(mTextAreaHit != None)
|
||||
{
|
||||
U32 elapseTime = Sim::getCurrentTime() - mMouseDownTime;
|
||||
if(elapseTime > 750 || mTextAreaHit == Slider)
|
||||
{
|
||||
timeInc(elapseTime);
|
||||
mIncCounter += mMulInc;
|
||||
if(mIncCounter >= 1.0f || mIncCounter <= -1.0f)
|
||||
{
|
||||
mValue = (mMulInc > 0.0f) ? mValue+mIncAmount : mValue-mIncAmount;
|
||||
mIncCounter = (mIncCounter > 0.0f) ? mIncCounter-1 : mIncCounter+1;
|
||||
checkRange();
|
||||
setValue();
|
||||
mCursorPos = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Parent::onRender(offset, updateRect);
|
||||
|
||||
// Arrow placement coordinates
|
||||
Point2I arrowUpStart(offset.x + getWidth() - 14, offset.y + 1 );
|
||||
Point2I arrowUpEnd(13, getExtent().y/2);
|
||||
|
||||
Point2I arrowDownStart(offset.x + getWidth() - 14, offset.y + 1 + getExtent().y/2);
|
||||
Point2I arrowDownEnd(13, getExtent().y/2);
|
||||
|
||||
// Draw the line that splits the number and bitmaps
|
||||
GFX->getDrawUtil()->drawLine(Point2I(offset.x + getWidth() - 14 -2, offset.y + 1 ),
|
||||
Point2I(arrowUpStart.x -2, arrowUpStart.y + getExtent().y),
|
||||
mProfile->mBorderColor);
|
||||
|
||||
GFX->getDrawUtil()->clearBitmapModulation();
|
||||
|
||||
if(mNumberOfBitmaps == 0)
|
||||
Con::warnf("No image provided for GuiTextEditSliderBitmapCtrl; do not render");
|
||||
else
|
||||
{
|
||||
// This control needs 4 images in order to render correctly
|
||||
if(mTextAreaHit == ArrowUp)
|
||||
GFX->getDrawUtil()->drawBitmapStretchSR( mProfile->mTextureObject, RectI(arrowUpStart,arrowUpEnd), mProfile->mBitmapArrayRects[0] );
|
||||
else
|
||||
GFX->getDrawUtil()->drawBitmapStretchSR( mProfile->mTextureObject, RectI(arrowUpStart,arrowUpEnd), mProfile->mBitmapArrayRects[1] );
|
||||
|
||||
if(mTextAreaHit == ArrowDown)
|
||||
GFX->getDrawUtil()->drawBitmapStretchSR( mProfile->mTextureObject, RectI(arrowDownStart,arrowDownEnd), mProfile->mBitmapArrayRects[2] );
|
||||
else
|
||||
GFX->getDrawUtil()->drawBitmapStretchSR( mProfile->mTextureObject, RectI(arrowDownStart,arrowDownEnd), mProfile->mBitmapArrayRects[3] );
|
||||
}
|
||||
}
|
||||
|
||||
void GuiTextEditSliderBitmapCtrl::setBitmap(const char *name)
|
||||
{
|
||||
bool awake = mAwake;
|
||||
if(awake)
|
||||
onSleep();
|
||||
|
||||
mBitmapName = StringTable->insert(name);
|
||||
if(awake)
|
||||
onWake();
|
||||
setUpdate();
|
||||
}
|
||||
95
Engine/source/gui/controls/guiTextEditSliderBitmapCtrl.h
Normal file
95
Engine/source/gui/controls/guiTextEditSliderBitmapCtrl.h
Normal file
|
|
@ -0,0 +1,95 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// Copyright (c) 2012 GarageGames, LLC
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to
|
||||
// deal in the Software without restriction, including without limitation the
|
||||
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
// sell copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
// IN THE SOFTWARE.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef _GUITEXTEDITSLIDERBITMAPCTRL_H_
|
||||
#define _GUITEXTEDITSLIDERBITMAPCTRL_H_
|
||||
|
||||
#ifndef _GUITYPES_H_
|
||||
#include "gui/core/guiTypes.h"
|
||||
#endif
|
||||
#ifndef _GUITEXTEDITCTRL_H_
|
||||
#include "gui/controls/guiTextEditCtrl.h"
|
||||
#endif
|
||||
|
||||
class GuiTextEditSliderBitmapCtrl : public GuiTextEditCtrl
|
||||
{
|
||||
typedef GuiTextEditCtrl Parent;
|
||||
|
||||
public:
|
||||
|
||||
enum CtrlArea
|
||||
{
|
||||
None,
|
||||
Slider,
|
||||
ArrowUp,
|
||||
ArrowDown
|
||||
};
|
||||
|
||||
GuiTextEditSliderBitmapCtrl();
|
||||
~GuiTextEditSliderBitmapCtrl();
|
||||
|
||||
DECLARE_CONOBJECT(GuiTextEditSliderBitmapCtrl);
|
||||
DECLARE_CATEGORY( "Gui Values" );
|
||||
DECLARE_DESCRIPTION( "A text control that display a numeric value and bitmapped up/down sliders." );
|
||||
|
||||
static void initPersistFields();
|
||||
|
||||
virtual void getText(char *dest); // dest must be of size
|
||||
// StructDes::MAX_STRING_LEN + 1
|
||||
|
||||
virtual void setText(const char *txt);
|
||||
|
||||
void setValue();
|
||||
void checkRange();
|
||||
void checkIncValue();
|
||||
void timeInc(U32 elapseTime);
|
||||
|
||||
virtual bool onKeyDown(const GuiEvent &event);
|
||||
virtual void onMouseDown(const GuiEvent &event);
|
||||
virtual void onMouseDragged(const GuiEvent &event);
|
||||
virtual void onMouseUp(const GuiEvent &event);
|
||||
virtual bool onMouseWheelUp(const GuiEvent &event);
|
||||
virtual bool onMouseWheelDown(const GuiEvent &event);
|
||||
|
||||
bool onWake();
|
||||
virtual void onPreRender();
|
||||
virtual void onRender(Point2I offset, const RectI &updateRect);
|
||||
|
||||
void setBitmap(const char *name);
|
||||
|
||||
protected:
|
||||
|
||||
Point2F mRange;
|
||||
F32 mIncAmount;
|
||||
F32 mValue;
|
||||
F32 mIncCounter;
|
||||
F32 mMulInc;
|
||||
StringTableEntry mFormat;
|
||||
U32 mMouseDownTime;
|
||||
bool mFocusOnMouseWheel;
|
||||
S32 mNumberOfBitmaps;
|
||||
StringTableEntry mBitmapName;
|
||||
|
||||
CtrlArea mTextAreaHit;
|
||||
};
|
||||
|
||||
#endif //_GUITEXTEDITSLIDERBITMAPCTRL_H_
|
||||
429
Engine/source/gui/controls/guiTextEditSliderCtrl.cpp
Normal file
429
Engine/source/gui/controls/guiTextEditSliderCtrl.cpp
Normal file
|
|
@ -0,0 +1,429 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// Copyright (c) 2012 GarageGames, LLC
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to
|
||||
// deal in the Software without restriction, including without limitation the
|
||||
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
// sell copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
// IN THE SOFTWARE.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "platform/platform.h"
|
||||
#include "gui/controls/guiTextEditSliderCtrl.h"
|
||||
|
||||
#include "console/consoleTypes.h"
|
||||
#include "console/console.h"
|
||||
#include "gui/core/guiCanvas.h"
|
||||
#include "gfx/gfxDevice.h"
|
||||
#include "gfx/gfxDrawUtil.h"
|
||||
#include "console/engineAPI.h"
|
||||
|
||||
IMPLEMENT_CONOBJECT(GuiTextEditSliderCtrl);
|
||||
|
||||
ConsoleDocClass( GuiTextEditSliderCtrl,
|
||||
"@brief GUI Control which displays a numerical value which can be increased or "
|
||||
"decreased using a pair of arrows.\n\n"
|
||||
|
||||
"@tsexample\n"
|
||||
"new GuiTextEditSliderCtrl()\n"
|
||||
"{\n"
|
||||
" format = \"%3.2f\";\n"
|
||||
" range = \"-1e+03 1e+03\";\n"
|
||||
" increment = \"0.1\";\n"
|
||||
" focusOnMouseWheel = \"0\";\n"
|
||||
" //Properties not specific to this control have been omitted from this example.\n"
|
||||
"};\n"
|
||||
"@endtsexample\n\n"
|
||||
|
||||
"@see GuiTextEditCtrl\n\n"
|
||||
|
||||
"@ingroup GuiCore\n"
|
||||
);
|
||||
|
||||
GuiTextEditSliderCtrl::GuiTextEditSliderCtrl()
|
||||
{
|
||||
mRange.set(0.0f, 1.0f);
|
||||
mIncAmount = 1.0f;
|
||||
mValue = 0.0f;
|
||||
mMulInc = 0;
|
||||
mIncCounter = 0.0f;
|
||||
mFormat = StringTable->insert("%3.2f");
|
||||
mTextAreaHit = None;
|
||||
mFocusOnMouseWheel = false;
|
||||
}
|
||||
|
||||
GuiTextEditSliderCtrl::~GuiTextEditSliderCtrl()
|
||||
{
|
||||
}
|
||||
|
||||
void GuiTextEditSliderCtrl::initPersistFields()
|
||||
{
|
||||
addField("format", TypeString, Offset(mFormat, GuiTextEditSliderCtrl), "Character format type to place in the control.\n");
|
||||
addField("range", TypePoint2F, Offset(mRange, GuiTextEditSliderCtrl), "Maximum vertical and horizontal range to allow in the control.\n");
|
||||
addField("increment", TypeF32, Offset(mIncAmount, GuiTextEditSliderCtrl), "How far to increment the slider on each step.\n");
|
||||
addField("focusOnMouseWheel", TypeBool, Offset(mFocusOnMouseWheel, GuiTextEditSliderCtrl), "If true, the control will accept giving focus to the user when the mouse wheel is used.\n");
|
||||
|
||||
Parent::initPersistFields();
|
||||
}
|
||||
|
||||
void GuiTextEditSliderCtrl::getText(char *dest)
|
||||
{
|
||||
Parent::getText(dest);
|
||||
}
|
||||
|
||||
void GuiTextEditSliderCtrl::setText(const char *txt)
|
||||
{
|
||||
mValue = dAtof(txt);
|
||||
checkRange();
|
||||
setValue();
|
||||
}
|
||||
|
||||
bool GuiTextEditSliderCtrl::onKeyDown(const GuiEvent &event)
|
||||
{
|
||||
return Parent::onKeyDown(event);
|
||||
}
|
||||
|
||||
void GuiTextEditSliderCtrl::checkRange()
|
||||
{
|
||||
if(mValue < mRange.x)
|
||||
mValue = mRange.x;
|
||||
else if(mValue > mRange.y)
|
||||
mValue = mRange.y;
|
||||
}
|
||||
|
||||
void GuiTextEditSliderCtrl::setValue()
|
||||
{
|
||||
char buf[20];
|
||||
// For some reason this sprintf is failing to convert
|
||||
// a floating point number to anything with %d, so cast it.
|
||||
if( dStricmp( mFormat, "%d" ) == 0 )
|
||||
dSprintf(buf,sizeof(buf),mFormat, (S32)mValue);
|
||||
else
|
||||
dSprintf(buf,sizeof(buf),mFormat, mValue);
|
||||
Parent::setText(buf);
|
||||
}
|
||||
|
||||
void GuiTextEditSliderCtrl::onMouseDown(const GuiEvent &event)
|
||||
{
|
||||
// If we're not active then skip out.
|
||||
if ( !mActive || !mAwake || !mVisible )
|
||||
{
|
||||
Parent::onMouseDown(event);
|
||||
return;
|
||||
}
|
||||
|
||||
char txt[20];
|
||||
Parent::getText(txt);
|
||||
mValue = dAtof(txt);
|
||||
|
||||
mMouseDownTime = Sim::getCurrentTime();
|
||||
GuiControl *parent = getParent();
|
||||
if(!parent)
|
||||
return;
|
||||
Point2I camPos = event.mousePoint;
|
||||
Point2I point = parent->localToGlobalCoord(getPosition());
|
||||
|
||||
if(camPos.x > point.x + getExtent().x - 14)
|
||||
{
|
||||
if(camPos.y > point.y + (getExtent().y/2))
|
||||
{
|
||||
mValue -=mIncAmount;
|
||||
mTextAreaHit = ArrowDown;
|
||||
mMulInc = -0.15f;
|
||||
}
|
||||
else
|
||||
{
|
||||
mValue +=mIncAmount;
|
||||
mTextAreaHit = ArrowUp;
|
||||
mMulInc = 0.15f;
|
||||
}
|
||||
|
||||
checkRange();
|
||||
setValue();
|
||||
mouseLock();
|
||||
|
||||
// We should get the focus and set the
|
||||
// cursor to the start of the text to
|
||||
// mimic the standard Windows behavior.
|
||||
setFirstResponder();
|
||||
mCursorPos = mBlockStart = mBlockEnd = 0;
|
||||
setUpdate();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
Parent::onMouseDown(event);
|
||||
}
|
||||
|
||||
void GuiTextEditSliderCtrl::onMouseDragged(const GuiEvent &event)
|
||||
{
|
||||
// If we're not active then skip out.
|
||||
if ( !mActive || !mAwake || !mVisible )
|
||||
{
|
||||
Parent::onMouseDragged(event);
|
||||
return;
|
||||
}
|
||||
|
||||
if(mTextAreaHit == None || mTextAreaHit == Slider)
|
||||
{
|
||||
mTextAreaHit = Slider;
|
||||
GuiControl *parent = getParent();
|
||||
if(!parent)
|
||||
return;
|
||||
Point2I camPos = event.mousePoint;
|
||||
Point2I point = parent->localToGlobalCoord(getPosition());
|
||||
F32 maxDis = 100;
|
||||
F32 val;
|
||||
if(camPos.y < point.y)
|
||||
{
|
||||
if((F32)point.y < maxDis)
|
||||
maxDis = (F32)point.y;
|
||||
|
||||
val = point.y - maxDis;
|
||||
|
||||
if(point.y > 0)
|
||||
mMulInc= 1.0f-(((float)camPos.y - val) / maxDis);
|
||||
else
|
||||
mMulInc = 1.0f;
|
||||
|
||||
checkIncValue();
|
||||
|
||||
return;
|
||||
}
|
||||
else if(camPos.y > point.y + getExtent().y)
|
||||
{
|
||||
GuiCanvas *root = getRoot();
|
||||
val = (F32)(root->getHeight() - (point.y + getHeight()));
|
||||
if(val < maxDis)
|
||||
maxDis = val;
|
||||
if( val > 0)
|
||||
mMulInc= -(F32)(camPos.y - (point.y + getHeight()))/maxDis;
|
||||
else
|
||||
mMulInc = -1.0f;
|
||||
checkIncValue();
|
||||
return;
|
||||
}
|
||||
mTextAreaHit = None;
|
||||
Parent::onMouseDragged(event);
|
||||
}
|
||||
}
|
||||
|
||||
void GuiTextEditSliderCtrl::onMouseUp(const GuiEvent &event)
|
||||
{
|
||||
// If we're not active then skip out.
|
||||
if ( !mActive || !mAwake || !mVisible )
|
||||
{
|
||||
Parent::onMouseUp(event);
|
||||
return;
|
||||
}
|
||||
|
||||
mMulInc = 0.0f;
|
||||
mouseUnlock();
|
||||
|
||||
if ( mTextAreaHit != None )
|
||||
selectAllText();
|
||||
|
||||
//if we released the mouse within this control, then the parent will call
|
||||
//the mConsoleCommand other wise we have to call it.
|
||||
Parent::onMouseUp(event);
|
||||
|
||||
//if we didn't release the mouse within this control, then perform the action
|
||||
// if (!cursorInControl())
|
||||
execConsoleCallback();
|
||||
execAltConsoleCallback();
|
||||
|
||||
//Set the cursor position to where the user clicked
|
||||
mCursorPos = calculateCursorPos( event.mousePoint );
|
||||
|
||||
mTextAreaHit = None;
|
||||
}
|
||||
|
||||
bool GuiTextEditSliderCtrl::onMouseWheelUp(const GuiEvent &event)
|
||||
{
|
||||
if ( !mActive || !mAwake || !mVisible )
|
||||
return Parent::onMouseWheelUp(event);
|
||||
|
||||
if ( !isFirstResponder() && !mFocusOnMouseWheel )
|
||||
{
|
||||
GuiControl *parent = getParent();
|
||||
if ( parent )
|
||||
return parent->onMouseWheelUp( event );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
mValue += mIncAmount;
|
||||
|
||||
checkRange();
|
||||
setValue();
|
||||
|
||||
setFirstResponder();
|
||||
mCursorPos = mBlockStart = mBlockEnd = 0;
|
||||
setUpdate();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool GuiTextEditSliderCtrl::onMouseWheelDown(const GuiEvent &event)
|
||||
{
|
||||
if ( !mActive || !mAwake || !mVisible )
|
||||
return Parent::onMouseWheelDown(event);
|
||||
|
||||
if ( !isFirstResponder() && !mFocusOnMouseWheel )
|
||||
{
|
||||
GuiControl *parent = getParent();
|
||||
if ( parent )
|
||||
return parent->onMouseWheelUp( event );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
mValue -= mIncAmount;
|
||||
|
||||
checkRange();
|
||||
setValue();
|
||||
|
||||
setFirstResponder();
|
||||
mCursorPos = mBlockStart = mBlockEnd = 0;
|
||||
setUpdate();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void GuiTextEditSliderCtrl::checkIncValue()
|
||||
{
|
||||
if(mMulInc > 1.0f)
|
||||
mMulInc = 1.0f;
|
||||
else if(mMulInc < -1.0f)
|
||||
mMulInc = -1.0f;
|
||||
}
|
||||
|
||||
void GuiTextEditSliderCtrl::timeInc(U32 elapseTime)
|
||||
{
|
||||
S32 numTimes = elapseTime / 750;
|
||||
if(mTextAreaHit != Slider && numTimes > 0)
|
||||
{
|
||||
if(mTextAreaHit == ArrowUp)
|
||||
mMulInc = 0.15f * numTimes;
|
||||
else
|
||||
mMulInc = -0.15f * numTimes;
|
||||
|
||||
checkIncValue();
|
||||
}
|
||||
}
|
||||
|
||||
void GuiTextEditSliderCtrl::onRender(Point2I offset, const RectI &updateRect)
|
||||
{
|
||||
if(mTextAreaHit != None)
|
||||
{
|
||||
U32 elapseTime = Sim::getCurrentTime() - mMouseDownTime;
|
||||
if(elapseTime > 750 || mTextAreaHit == Slider)
|
||||
{
|
||||
timeInc(elapseTime);
|
||||
mIncCounter += mMulInc;
|
||||
if(mIncCounter >= 1.0f || mIncCounter <= -1.0f)
|
||||
{
|
||||
mValue = (mMulInc > 0.0f) ? mValue+mIncAmount : mValue-mIncAmount;
|
||||
mIncCounter = (mIncCounter > 0.0f) ? mIncCounter-1 : mIncCounter+1;
|
||||
checkRange();
|
||||
setValue();
|
||||
mCursorPos = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
Parent::onRender(offset, updateRect);
|
||||
|
||||
Point2I start(offset.x + getWidth() - 14, offset.y);
|
||||
Point2I midPoint(start.x + 7, start.y + (getExtent().y/2));
|
||||
|
||||
GFX->getDrawUtil()->drawRectFill(Point2I(start.x+1,start.y+1), Point2I(start.x+13,start.y+getExtent().y-1) , mProfile->mFillColor);
|
||||
|
||||
GFX->getDrawUtil()->drawLine(start, Point2I(start.x, start.y+getExtent().y),mProfile->mFontColor);
|
||||
GFX->getDrawUtil()->drawLine(Point2I(start.x,midPoint.y),
|
||||
Point2I(start.x+14,midPoint.y),
|
||||
mProfile->mFontColor);
|
||||
|
||||
GFXVertexBufferHandle<GFXVertexPC> verts(GFX, 6, GFXBufferTypeVolatile);
|
||||
verts.lock();
|
||||
|
||||
verts[0].color.set( 0, 0, 0 );
|
||||
verts[1].color.set( 0, 0, 0 );
|
||||
verts[2].color.set( 0, 0, 0 );
|
||||
verts[3].color.set( 0, 0, 0 );
|
||||
verts[4].color.set( 0, 0, 0 );
|
||||
verts[5].color.set( 0, 0, 0 );
|
||||
|
||||
if(mTextAreaHit == ArrowUp)
|
||||
{
|
||||
verts[0].point.set( (F32)midPoint.x, (F32)start.y + 1.0f, 0.0f );
|
||||
verts[1].point.set( (F32)start.x + 11.0f, (F32)midPoint.y - 2.0f, 0.0f );
|
||||
verts[2].point.set( (F32)start.x + 3.0f, (F32)midPoint.y - 2.0f, 0.0f );
|
||||
}
|
||||
else
|
||||
{
|
||||
verts[0].point.set( (F32)midPoint.x, (F32)start.y + 2.0f, 0.0f );
|
||||
verts[1].point.set( (F32)start.x + 11.0f, (F32)midPoint.y - 1.0f, 0.0f );
|
||||
verts[2].point.set( (F32)start.x + 3.0f, (F32)midPoint.y - 1.0f, 0.0f );
|
||||
}
|
||||
|
||||
if(mTextAreaHit == ArrowDown)
|
||||
{
|
||||
verts[3].point.set( (F32)midPoint.x, (F32)(start.y + getExtent().y - 1), 0.0f );
|
||||
verts[4].point.set( (F32)start.x + 11.0f, (F32)midPoint.y + 3.0f, 0.0f );
|
||||
verts[5].point.set( (F32)start.x + 3.0f, (F32)midPoint.y + 3.0f, 0.0f );
|
||||
}
|
||||
else
|
||||
{
|
||||
verts[3].point.set( (F32)midPoint.x, (F32)(start.y + getExtent().y - 2), 0.0f );
|
||||
verts[4].point.set( (F32)start.x + 11.0f, (F32)midPoint.y + 2.0f, 0.0f );
|
||||
verts[5].point.set( (F32)start.x + 3.0f, (F32)midPoint.y + 2.0f, 0.0f );
|
||||
}
|
||||
|
||||
verts.unlock();
|
||||
|
||||
GFX->setVertexBuffer( verts );
|
||||
GFX->drawPrimitive( GFXTriangleList, 0, 2 );
|
||||
}
|
||||
|
||||
void GuiTextEditSliderCtrl::onPreRender()
|
||||
{
|
||||
if (isFirstResponder())
|
||||
{
|
||||
U32 timeElapsed = Platform::getVirtualMilliseconds() - mTimeLastCursorFlipped;
|
||||
mNumFramesElapsed++;
|
||||
if ((timeElapsed > 500) && (mNumFramesElapsed > 3))
|
||||
{
|
||||
mCursorOn = !mCursorOn;
|
||||
mTimeLastCursorFlipped = Sim::getCurrentTime();
|
||||
mNumFramesElapsed = 0;
|
||||
setUpdate();
|
||||
}
|
||||
|
||||
//update the cursor if the text is scrolling
|
||||
if (mDragHit)
|
||||
{
|
||||
if ((mScrollDir < 0) && (mCursorPos > 0))
|
||||
{
|
||||
mCursorPos--;
|
||||
}
|
||||
else if ((mScrollDir > 0) && (mCursorPos < (S32)dStrlen(mText)))
|
||||
{
|
||||
mCursorPos++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
91
Engine/source/gui/controls/guiTextEditSliderCtrl.h
Normal file
91
Engine/source/gui/controls/guiTextEditSliderCtrl.h
Normal file
|
|
@ -0,0 +1,91 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// Copyright (c) 2012 GarageGames, LLC
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to
|
||||
// deal in the Software without restriction, including without limitation the
|
||||
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
// sell copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
// IN THE SOFTWARE.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef _GUITEXTEDITSLIDERCTRL_H_
|
||||
#define _GUITEXTEDITSLIDERCTRL_H_
|
||||
|
||||
#ifndef _GUITYPES_H_
|
||||
#include "gui/core/guiTypes.h"
|
||||
#endif
|
||||
#ifndef _GUITEXTEDITCTRL_H_
|
||||
#include "gui/controls/guiTextEditCtrl.h"
|
||||
#endif
|
||||
|
||||
class GuiTextEditSliderCtrl : public GuiTextEditCtrl
|
||||
{
|
||||
typedef GuiTextEditCtrl Parent;
|
||||
|
||||
public:
|
||||
|
||||
enum CtrlArea
|
||||
{
|
||||
None,
|
||||
Slider,
|
||||
ArrowUp,
|
||||
ArrowDown
|
||||
};
|
||||
|
||||
GuiTextEditSliderCtrl();
|
||||
~GuiTextEditSliderCtrl();
|
||||
|
||||
DECLARE_CONOBJECT(GuiTextEditSliderCtrl);
|
||||
DECLARE_CATEGORY( "Gui Values" );
|
||||
DECLARE_DESCRIPTION( "A text that shows a numeric value and up/down arrows to\n"
|
||||
"increase/decrease the value." );
|
||||
|
||||
static void initPersistFields();
|
||||
|
||||
virtual void getText(char *dest); // dest must be of size
|
||||
// StructDes::MAX_STRING_LEN + 1
|
||||
|
||||
virtual void setText(const char *txt);
|
||||
|
||||
void setValue();
|
||||
void checkRange();
|
||||
void checkIncValue();
|
||||
void timeInc(U32 elapseTime);
|
||||
|
||||
virtual bool onKeyDown(const GuiEvent &event);
|
||||
virtual void onMouseDown(const GuiEvent &event);
|
||||
virtual void onMouseDragged(const GuiEvent &event);
|
||||
virtual void onMouseUp(const GuiEvent &event);
|
||||
virtual bool onMouseWheelUp(const GuiEvent &event);
|
||||
virtual bool onMouseWheelDown(const GuiEvent &event);
|
||||
|
||||
virtual void onPreRender();
|
||||
virtual void onRender(Point2I offset, const RectI &updateRect);
|
||||
|
||||
protected:
|
||||
|
||||
Point2F mRange;
|
||||
F32 mIncAmount;
|
||||
F32 mValue;
|
||||
F32 mIncCounter;
|
||||
F32 mMulInc;
|
||||
StringTableEntry mFormat;
|
||||
U32 mMouseDownTime;
|
||||
bool mFocusOnMouseWheel;
|
||||
|
||||
CtrlArea mTextAreaHit;
|
||||
};
|
||||
|
||||
#endif //_GUITEXTEDITSLIDERCTRL_H_
|
||||
846
Engine/source/gui/controls/guiTextListCtrl.cpp
Normal file
846
Engine/source/gui/controls/guiTextListCtrl.cpp
Normal file
|
|
@ -0,0 +1,846 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// Copyright (c) 2012 GarageGames, LLC
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to
|
||||
// deal in the Software without restriction, including without limitation the
|
||||
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
// sell copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
// IN THE SOFTWARE.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "platform/platform.h"
|
||||
#include "gui/controls/guiTextListCtrl.h"
|
||||
|
||||
#include "console/consoleTypes.h"
|
||||
#include "console/console.h"
|
||||
#include "gui/containers/guiScrollCtrl.h"
|
||||
#include "gui/core/guiDefaultControlRender.h"
|
||||
#include "gfx/gfxDrawUtil.h"
|
||||
#include "console/engineAPI.h"
|
||||
|
||||
IMPLEMENT_CONOBJECT(GuiTextListCtrl);
|
||||
|
||||
ConsoleDocClass( GuiTextListCtrl,
|
||||
"@brief GUI control that displays a list of text. Text items in the list can be individually selected.\n\n"
|
||||
|
||||
"@tsexample\n"
|
||||
|
||||
" new GuiTextListCtrl(EndGameGuiList)\n"
|
||||
" {\n"
|
||||
" columns = \"0 256\";\n"
|
||||
" fitParentWidth = \"1\";\n"
|
||||
" clipColumnText = \"0\";\n"
|
||||
" //Properties not specific to this control have been omitted from this example.\n"
|
||||
" };\n"
|
||||
"@endtsexample\n\n"
|
||||
|
||||
"@see Reference\n\n"
|
||||
|
||||
"@ingroup GuiControls\n"
|
||||
);
|
||||
|
||||
|
||||
IMPLEMENT_CALLBACK( GuiTextListCtrl, onSelect, void, (const char* cellid, const char* text),( cellid , text ),
|
||||
"@brief Called whenever an item in the list is selected.\n\n"
|
||||
"@param cellid The ID of the cell that was selected\n"
|
||||
"@param text The text in the selected cel\n\n"
|
||||
"@tsexample\n"
|
||||
"// A cel in the control was selected, causing the callback to occur\n"
|
||||
"GuiTextListCtrl::onSelect(%this,%callid,%text)\n"
|
||||
" {\n"
|
||||
" // Code to run when a cel item is selected\n"
|
||||
" }\n"
|
||||
"@endtsexample\n\n"
|
||||
"@see GuiControl\n\n"
|
||||
);
|
||||
|
||||
IMPLEMENT_CALLBACK( GuiTextListCtrl, onDeleteKey, void, ( const char* id ),( id ),
|
||||
"@brief Called when the delete key has been pressed.\n\n"
|
||||
"@param id Id of the selected item in the list\n"
|
||||
"@tsexample\n"
|
||||
"// The delete key was pressed while the GuiTextListCtrl was in focus, causing the callback to occur.\n"
|
||||
"GuiTextListCtrl::onDeleteKey(%this,%id)\n"
|
||||
" {\n"
|
||||
" // Code to run when the delete key is pressed\n"
|
||||
" }\n"
|
||||
"@endtsexample\n\n"
|
||||
"@see GuiControl\n\n"
|
||||
);
|
||||
|
||||
static int sortColumn;
|
||||
static bool sIncreasing;
|
||||
|
||||
static const char *getColumn(const char *text)
|
||||
{
|
||||
int ct = sortColumn;
|
||||
while(ct--)
|
||||
{
|
||||
text = dStrchr(text, '\t');
|
||||
if(!text)
|
||||
return "";
|
||||
text++;
|
||||
}
|
||||
return text;
|
||||
}
|
||||
|
||||
static S32 QSORT_CALLBACK textCompare( const void* a, const void* b )
|
||||
{
|
||||
GuiTextListCtrl::Entry *ea = (GuiTextListCtrl::Entry *) (a);
|
||||
GuiTextListCtrl::Entry *eb = (GuiTextListCtrl::Entry *) (b);
|
||||
S32 result = dStrnatcasecmp( getColumn( ea->text ), getColumn( eb->text ) );
|
||||
return ( sIncreasing ? result : -result );
|
||||
}
|
||||
|
||||
static S32 QSORT_CALLBACK numCompare(const void *a,const void *b)
|
||||
{
|
||||
GuiTextListCtrl::Entry *ea = (GuiTextListCtrl::Entry *) (a);
|
||||
GuiTextListCtrl::Entry *eb = (GuiTextListCtrl::Entry *) (b);
|
||||
const char* aCol = getColumn( ea->text );
|
||||
const char* bCol = getColumn( eb->text );
|
||||
F32 result = dAtof(aCol) - dAtof(bCol);
|
||||
S32 res = result < 0 ? -1 : (result > 0 ? 1 : 0);
|
||||
|
||||
return ( sIncreasing ? res : -res );
|
||||
}
|
||||
|
||||
GuiTextListCtrl::GuiTextListCtrl()
|
||||
{
|
||||
VECTOR_SET_ASSOCIATION(mList);
|
||||
VECTOR_SET_ASSOCIATION(mColumnOffsets);
|
||||
|
||||
mActive = true;
|
||||
mSize.set(1, 0);
|
||||
mColumnOffsets.push_back(0);
|
||||
mFitParentWidth = true;
|
||||
mClipColumnText = false;
|
||||
}
|
||||
|
||||
void GuiTextListCtrl::initPersistFields()
|
||||
{
|
||||
addField("columns", TypeS32Vector, Offset(mColumnOffsets, GuiTextListCtrl), "A vector of column offsets. The number of values determines the number of columns in the table.\n" );
|
||||
addField("fitParentWidth", TypeBool, Offset(mFitParentWidth, GuiTextListCtrl), "If true, the width of this control will match the width of its parent.\n");
|
||||
addField("clipColumnText", TypeBool, Offset(mClipColumnText, GuiTextListCtrl), "If true, text exceeding a column's given width will get clipped.\n" );
|
||||
Parent::initPersistFields();
|
||||
}
|
||||
|
||||
bool GuiTextListCtrl::onWake()
|
||||
{
|
||||
if(!Parent::onWake())
|
||||
return false;
|
||||
|
||||
setSize(mSize);
|
||||
return true;
|
||||
}
|
||||
|
||||
U32 GuiTextListCtrl::getSelectedId()
|
||||
{
|
||||
if (mSelectedCell.y == -1)
|
||||
return InvalidId;
|
||||
|
||||
return mList[mSelectedCell.y].id;
|
||||
}
|
||||
|
||||
U32 GuiTextListCtrl::getSelectedRow()
|
||||
{
|
||||
return mSelectedCell.y;
|
||||
}
|
||||
|
||||
bool GuiTextListCtrl::cellSelected(Point2I cell)
|
||||
{
|
||||
// Is the selection being cleared?
|
||||
if( cell.x == -1 && cell.y == -1)
|
||||
return Parent::cellSelected(cell);
|
||||
|
||||
// Do not allow selection of inactive cells
|
||||
if (cell.y >= 0 && cell.y < mSize.y && mList[cell.y].active)
|
||||
return Parent::cellSelected(cell);
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
void GuiTextListCtrl::onCellSelected(Point2I cell)
|
||||
{
|
||||
onSelect_callback(Con::getIntArg(mList[cell.y].id), mList[cell.y].text);
|
||||
execConsoleCallback();
|
||||
}
|
||||
|
||||
void GuiTextListCtrl::onRenderCell(Point2I offset, Point2I cell, bool selected, bool mouseOver)
|
||||
{
|
||||
if ( mList[cell.y].active )
|
||||
{
|
||||
if (selected || (mProfile->mMouseOverSelected && mouseOver))
|
||||
{
|
||||
RectI highlightRect = RectI(offset.x, offset.y, mCellSize.x, mCellSize.y);
|
||||
highlightRect.inset( 0, -1 );
|
||||
renderFilledBorder( highlightRect, mProfile->mBorderColorHL, mProfile->mFillColorHL);
|
||||
GFX->getDrawUtil()->setBitmapModulation(mProfile->mFontColorHL);
|
||||
}
|
||||
else
|
||||
GFX->getDrawUtil()->setBitmapModulation(mouseOver ? mProfile->mFontColorHL : mProfile->mFontColor);
|
||||
}
|
||||
else
|
||||
GFX->getDrawUtil()->setBitmapModulation( mProfile->mFontColorNA );
|
||||
|
||||
const char *text = mList[cell.y].text;
|
||||
for(U32 index = 0; index < mColumnOffsets.size(); index++)
|
||||
{
|
||||
const char *nextCol = dStrchr(text, '\t');
|
||||
if(mColumnOffsets[index] >= 0)
|
||||
{
|
||||
dsize_t slen;
|
||||
if(nextCol)
|
||||
slen = nextCol - text;
|
||||
else
|
||||
slen = dStrlen(text);
|
||||
|
||||
Point2I pos(offset.x + 4 + mColumnOffsets[index], offset.y);
|
||||
|
||||
RectI saveClipRect;
|
||||
bool clipped = false;
|
||||
|
||||
if(mClipColumnText && (index != (mColumnOffsets.size() - 1)))
|
||||
{
|
||||
saveClipRect = GFX->getClipRect();
|
||||
|
||||
RectI clipRect(pos, Point2I(mColumnOffsets[index+1] - mColumnOffsets[index] - 4, mCellSize.y));
|
||||
if(clipRect.intersect(saveClipRect))
|
||||
{
|
||||
clipped = true;
|
||||
GFX->setClipRect( clipRect );
|
||||
}
|
||||
}
|
||||
|
||||
GFX->getDrawUtil()->drawTextN(mFont, pos, text, slen, mProfile->mFontColors);
|
||||
|
||||
if(clipped)
|
||||
GFX->setClipRect( saveClipRect );
|
||||
}
|
||||
if(!nextCol)
|
||||
break;
|
||||
text = nextCol+1;
|
||||
}
|
||||
}
|
||||
|
||||
U32 GuiTextListCtrl::getRowWidth(Entry *row)
|
||||
{
|
||||
U32 width = 1;
|
||||
const char *text = row->text;
|
||||
for(U32 index = 0; index < mColumnOffsets.size(); index++)
|
||||
{
|
||||
const char *nextCol = dStrchr(text, '\t');
|
||||
U32 textWidth;
|
||||
if(nextCol)
|
||||
textWidth = mFont->getStrNWidth((const UTF8*)text, nextCol - text);
|
||||
else
|
||||
textWidth = mFont->getStrWidth((const UTF8*)text);
|
||||
if(mColumnOffsets[index] >= 0)
|
||||
width = getMax(width, mColumnOffsets[index] + textWidth);
|
||||
if(!nextCol)
|
||||
break;
|
||||
text = nextCol+1;
|
||||
}
|
||||
return width;
|
||||
}
|
||||
|
||||
void GuiTextListCtrl::insertEntry(U32 id, const char *text, S32 index)
|
||||
{
|
||||
Entry e;
|
||||
e.text = dStrdup(text);
|
||||
e.id = id;
|
||||
e.active = true;
|
||||
if(!mList.size())
|
||||
mList.push_back(e);
|
||||
else
|
||||
{
|
||||
if(index > mList.size())
|
||||
index = mList.size();
|
||||
mList.insert(index);
|
||||
mList[index] = e;
|
||||
}
|
||||
setSize(Point2I(1, mList.size()));
|
||||
}
|
||||
|
||||
void GuiTextListCtrl::addEntry(U32 id, const char *text)
|
||||
{
|
||||
Entry e;
|
||||
e.text = dStrdup(text);
|
||||
e.id = id;
|
||||
e.active = true;
|
||||
mList.push_back(e);
|
||||
setSize(Point2I(1, mList.size()));
|
||||
}
|
||||
|
||||
void GuiTextListCtrl::setEntry(U32 id, const char *text)
|
||||
{
|
||||
S32 e = findEntryById(id);
|
||||
if(e == -1)
|
||||
addEntry(id, text);
|
||||
else
|
||||
{
|
||||
dFree(mList[e].text);
|
||||
mList[e].text = dStrdup(text);
|
||||
|
||||
// Still have to call this to make sure cells are wide enough for new values:
|
||||
setSize( Point2I( 1, mList.size() ) );
|
||||
}
|
||||
setUpdate();
|
||||
}
|
||||
|
||||
void GuiTextListCtrl::setEntryActive(U32 id, bool active)
|
||||
{
|
||||
S32 index = findEntryById( id );
|
||||
if ( index == -1 )
|
||||
return;
|
||||
|
||||
if ( mList[index].active != active )
|
||||
{
|
||||
mList[index].active = active;
|
||||
|
||||
// You can't have an inactive entry selected...
|
||||
if ( !active && mSelectedCell.y >= 0 && mSelectedCell.y < mList.size()
|
||||
&& mList[mSelectedCell.y].id == id )
|
||||
setSelectedCell( Point2I( -1, -1 ) );
|
||||
|
||||
setUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
S32 GuiTextListCtrl::findEntryById(U32 id)
|
||||
{
|
||||
for(U32 i = 0; i < mList.size(); i++)
|
||||
if(mList[i].id == id)
|
||||
return i;
|
||||
return -1;
|
||||
}
|
||||
|
||||
S32 GuiTextListCtrl::findEntryByText(const char *text)
|
||||
{
|
||||
for(U32 i = 0; i < mList.size(); i++)
|
||||
if(!dStricmp(mList[i].text, text))
|
||||
return i;
|
||||
return -1;
|
||||
}
|
||||
|
||||
bool GuiTextListCtrl::isEntryActive(U32 id)
|
||||
{
|
||||
S32 index = findEntryById( id );
|
||||
if ( index == -1 )
|
||||
return( false );
|
||||
|
||||
return( mList[index].active );
|
||||
}
|
||||
|
||||
void GuiTextListCtrl::setSize(Point2I newSize)
|
||||
{
|
||||
mSize = newSize;
|
||||
|
||||
if ( bool( mFont ) )
|
||||
{
|
||||
if ( mSize.x == 1 && mFitParentWidth )
|
||||
{
|
||||
GuiScrollCtrl* parent = dynamic_cast<GuiScrollCtrl *>(getParent());
|
||||
if ( parent )
|
||||
mCellSize.x = parent->getContentExtent().x;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Find the maximum width cell:
|
||||
S32 maxWidth = 1;
|
||||
for ( U32 i = 0; i < mList.size(); i++ )
|
||||
{
|
||||
U32 rWidth = getRowWidth( &mList[i] );
|
||||
if ( rWidth > maxWidth )
|
||||
maxWidth = rWidth;
|
||||
}
|
||||
|
||||
mCellSize.x = maxWidth + 8;
|
||||
}
|
||||
|
||||
mCellSize.y = mFont->getHeight() + 2;
|
||||
}
|
||||
|
||||
Point2I newExtent( newSize.x * mCellSize.x + mHeaderDim.x, newSize.y * mCellSize.y + mHeaderDim.y );
|
||||
setExtent( newExtent );
|
||||
}
|
||||
|
||||
void GuiTextListCtrl::clear()
|
||||
{
|
||||
while (mList.size())
|
||||
removeEntry(mList[0].id);
|
||||
|
||||
mMouseOverCell.set( -1, -1 );
|
||||
setSelectedCell(Point2I(-1, -1));
|
||||
}
|
||||
|
||||
void GuiTextListCtrl::sort(U32 column, bool increasing)
|
||||
{
|
||||
if (getNumEntries() < 2)
|
||||
return;
|
||||
sortColumn = column;
|
||||
sIncreasing = increasing;
|
||||
dQsort((void *)&(mList[0]), mList.size(), sizeof(Entry), textCompare);
|
||||
}
|
||||
|
||||
void GuiTextListCtrl::sortNumerical( U32 column, bool increasing )
|
||||
{
|
||||
if ( getNumEntries() < 2 )
|
||||
return;
|
||||
|
||||
sortColumn = column;
|
||||
sIncreasing = increasing;
|
||||
dQsort( (void*) &( mList[0] ), mList.size(), sizeof( Entry ), numCompare );
|
||||
}
|
||||
|
||||
void GuiTextListCtrl::onRemove()
|
||||
{
|
||||
clear();
|
||||
Parent::onRemove();
|
||||
}
|
||||
|
||||
U32 GuiTextListCtrl::getNumEntries()
|
||||
{
|
||||
return mList.size();
|
||||
}
|
||||
|
||||
void GuiTextListCtrl::removeEntryByIndex(S32 index)
|
||||
{
|
||||
if(index < 0 || index >= mList.size())
|
||||
return;
|
||||
dFree(mList[index].text);
|
||||
mList.erase(index);
|
||||
|
||||
setSize(Point2I( 1, mList.size()));
|
||||
setSelectedCell(Point2I(-1, -1));
|
||||
}
|
||||
|
||||
void GuiTextListCtrl::removeEntry(U32 id)
|
||||
{
|
||||
S32 index = findEntryById(id);
|
||||
removeEntryByIndex(index);
|
||||
}
|
||||
|
||||
const char *GuiTextListCtrl::getSelectedText()
|
||||
{
|
||||
if (mSelectedCell.y == -1)
|
||||
return NULL;
|
||||
|
||||
return mList[mSelectedCell.y].text;
|
||||
}
|
||||
|
||||
const char *GuiTextListCtrl::getScriptValue()
|
||||
{
|
||||
return getSelectedText();
|
||||
}
|
||||
|
||||
void GuiTextListCtrl::setScriptValue(const char *val)
|
||||
{
|
||||
S32 e = findEntryByText(val);
|
||||
if(e == -1)
|
||||
setSelectedCell(Point2I(-1, -1));
|
||||
else
|
||||
setSelectedCell(Point2I(0, e));
|
||||
}
|
||||
|
||||
bool GuiTextListCtrl::onKeyDown( const GuiEvent &event )
|
||||
{
|
||||
//if this control is a dead end, make sure the event stops here
|
||||
if ( !mVisible || !mActive || !mAwake )
|
||||
return true;
|
||||
|
||||
S32 yDelta = 0;
|
||||
switch( event.keyCode )
|
||||
{
|
||||
case KEY_RETURN:
|
||||
execAltConsoleCallback();
|
||||
break;
|
||||
case KEY_LEFT:
|
||||
case KEY_UP:
|
||||
if ( mSelectedCell.y > 0 )
|
||||
{
|
||||
mSelectedCell.y--;
|
||||
yDelta = -mCellSize.y;
|
||||
}
|
||||
break;
|
||||
case KEY_DOWN:
|
||||
case KEY_RIGHT:
|
||||
if ( mSelectedCell.y < ( mList.size() - 1 ) )
|
||||
{
|
||||
mSelectedCell.y++;
|
||||
yDelta = mCellSize.y;
|
||||
}
|
||||
break;
|
||||
case KEY_HOME:
|
||||
if ( mList.size() )
|
||||
{
|
||||
mSelectedCell.y = 0;
|
||||
yDelta = -(mCellSize.y * mList.size() + 1 );
|
||||
}
|
||||
break;
|
||||
case KEY_END:
|
||||
if ( mList.size() )
|
||||
{
|
||||
mSelectedCell.y = mList.size() - 1;
|
||||
yDelta = (mCellSize.y * mList.size() + 1 );
|
||||
}
|
||||
break;
|
||||
case KEY_DELETE:
|
||||
if ( mSelectedCell.y >= 0 && mSelectedCell.y < mList.size() )
|
||||
onDeleteKey_callback(Con::getIntArg( mList[mSelectedCell.y].id ) );
|
||||
break;
|
||||
default:
|
||||
return( Parent::onKeyDown( event ) );
|
||||
break;
|
||||
};
|
||||
|
||||
GuiScrollCtrl* parent = dynamic_cast<GuiScrollCtrl *>(getParent());
|
||||
if ( parent )
|
||||
parent->scrollDelta( 0, yDelta );
|
||||
|
||||
return ( true );
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Console Methods
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
DefineEngineMethod( GuiTextListCtrl, getSelectedId, S32, (),,
|
||||
"@brief Get the ID of the currently selected item.\n\n"
|
||||
"@tsexample\n"
|
||||
"// Acquire the ID of the selected item in the list.\n"
|
||||
"%id = %thisGuiTextListCtrl.getSelectedId();\n"
|
||||
"@endtsexample\n\n"
|
||||
"@return The id of the selected item in the list.\n\n"
|
||||
"@see GuiControl")
|
||||
{
|
||||
return object->getSelectedId();
|
||||
}
|
||||
|
||||
DefineEngineMethod( GuiTextListCtrl, setSelectedById, void, (int id),,
|
||||
"@brief Finds the specified entry by id, then marks its row as selected.\n\n"
|
||||
"@param id Entry within the text list to make selected.\n"
|
||||
"@tsexample\n"
|
||||
"// Define the id\n"
|
||||
"%id = \"5\";\n\n"
|
||||
"// Inform the GuiTextListCtrl control to set the defined id entry as selected\n"
|
||||
"%thisGuiTextListCtrl.setSelectedById(%id);\n"
|
||||
"@endtsexample\n\n"
|
||||
"@see GuiControl")
|
||||
{
|
||||
S32 index = object->findEntryById(id);
|
||||
if(index < 0)
|
||||
return ;
|
||||
|
||||
object->setSelectedCell(Point2I(0, index));
|
||||
}
|
||||
|
||||
DefineEngineMethod( GuiTextListCtrl, setSelectedRow, void, (int rowNum),,
|
||||
"@briefSelects the specified row.\n\n"
|
||||
"@param rowNum Row number to set selected.\n"
|
||||
"@tsexample\n"
|
||||
"// Define the row number to set selected\n"
|
||||
"%rowNum = \"4\";\n\n"
|
||||
"%guiTextListCtrl.setSelectedRow(%rowNum);\n"
|
||||
"@endtsexample\n\n"
|
||||
"@see GuiControl")
|
||||
{
|
||||
object->setSelectedCell( Point2I( 0, rowNum ) );
|
||||
}
|
||||
|
||||
DefineEngineMethod( GuiTextListCtrl, getSelectedRow, S32, (),,
|
||||
"@brief Returns the selected row index (not the row ID).\n\n"
|
||||
"@tsexample\n"
|
||||
"// Acquire the selected row index\n"
|
||||
"%rowIndex = %thisGuiTextListCtrl.getSelectedRow();\n"
|
||||
"@endtsexample\n\n"
|
||||
"@return Index of the selected row\n\n"
|
||||
"@see GuiControl")
|
||||
{
|
||||
return object->getSelectedRow();
|
||||
}
|
||||
|
||||
DefineEngineMethod( GuiTextListCtrl, clearSelection, void, (),,
|
||||
"@brief Set the selection to nothing.\n\n"
|
||||
"@tsexample\n"
|
||||
"// Deselect anything that is currently selected\n"
|
||||
"%thisGuiTextListCtrl.clearSelection();\n"
|
||||
"@endtsexample\n\n"
|
||||
"@see GuiControl")
|
||||
{
|
||||
object->setSelectedCell(Point2I(-1, -1));
|
||||
}
|
||||
|
||||
DefineEngineMethod( GuiTextListCtrl, addRow, S32, (int id, const char* text, int index),(0,"",-1),
|
||||
"@brief Adds a new row at end of the list with the defined id and text.\n"
|
||||
"If index is used, then the new row is inserted at the row location of 'index'.\n\n"
|
||||
"@param id Id of the new row.\n"
|
||||
"@param text Text to display at the new row.\n"
|
||||
"@param index Index to insert the new row at. If not used, new row will be placed at the end of the list.\n"
|
||||
"@tsexample\n"
|
||||
"// Define the id\n"
|
||||
"%id = \"4\";\n\n"
|
||||
"// Define the text to display\n"
|
||||
"%text = \"Display Text\"\n\n"
|
||||
"// Define the index (optional)\n"
|
||||
"%index = \"2\"\n\n"
|
||||
"// Inform the GuiTextListCtrl control to add the new row with the defined information.\n"
|
||||
"%rowIndex = %thisGuiTextListCtrl.addRow(%id,%text,%index);\n"
|
||||
"@endtsexample\n\n"
|
||||
"@return Returns the row index of the new row. If 'index' was defined, then this just returns the number of rows in the list.\n\n"
|
||||
"@see References")
|
||||
{
|
||||
S32 ret = object->mList.size();
|
||||
if(index == -1)
|
||||
object->addEntry(id, text);
|
||||
else
|
||||
object->insertEntry(id, text, index);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
DefineEngineMethod( GuiTextListCtrl, setRowById, void, (int id, const char* text),,
|
||||
"@brief Sets the text at the defined id.\n\n"
|
||||
"@param id Id to change.\n"
|
||||
"@param text Text to use at the Id.\n"
|
||||
"@tsexample\n"
|
||||
"// Define the id\n"
|
||||
"%id = \"4\";\n\n"
|
||||
"// Define the text\n"
|
||||
"%text = \"Text To Display\";\n\n"
|
||||
"// Inform the GuiTextListCtrl control to display the defined text at the defined id\n"
|
||||
"%thisGuiTextListCtrl.setRowById(%id,%text);\n"
|
||||
"@endtsexample\n\n"
|
||||
"@see GuiControl")
|
||||
{
|
||||
object->setEntry(id, text);
|
||||
}
|
||||
|
||||
DefineEngineMethod( GuiTextListCtrl, sort, void, ( int columnId, bool increasing ), ( true ),
|
||||
"@brief Performs a standard (alphabetical) sort on the values in the specified column.\n\n"
|
||||
"@param columnId Column ID to perform the sort on.\n"
|
||||
"@param increasing If false, sort will be performed in reverse.\n"
|
||||
"@tsexample\n"
|
||||
"// Define the columnId\n"
|
||||
"%id = \"1\";\n\n"
|
||||
"// Define if we are increasing or not\n"
|
||||
"%increasing = \"false\";\n\n"
|
||||
"// Inform the GuiTextListCtrl to perform the sort operation\n"
|
||||
"%thisGuiTextListCtrl.sort(%id,%increasing);\n"
|
||||
"@endtsexample\n\n"
|
||||
"@see GuiControl")
|
||||
{
|
||||
object->sort( columnId, increasing );
|
||||
}
|
||||
|
||||
DefineEngineMethod( GuiTextListCtrl, sortNumerical, void, (int columnID, bool increasing), ( true ),
|
||||
"@brief Perform a numerical sort on the values in the specified column.\n\n"
|
||||
"Detailed description\n\n"
|
||||
"@param columnId Column ID to perform the sort on.\n"
|
||||
"@param increasing If false, sort will be performed in reverse.\n"
|
||||
"@tsexample\n"
|
||||
"// Define the columnId\n"
|
||||
"%id = \"1\";\n\n"
|
||||
"// Define if we are increasing or not\n"
|
||||
"%increasing = \"false\";\n\n"
|
||||
"// Inform the GuiTextListCtrl to perform the sort operation\n"
|
||||
"%thisGuiTextListCtrl.sortNumerical(%id,%increasing);\n"
|
||||
"@endtsexample\n\n"
|
||||
"@see GuiControl")
|
||||
{
|
||||
object->sortNumerical( columnID, increasing );
|
||||
}
|
||||
|
||||
DefineEngineMethod( GuiTextListCtrl, clear, void, (),,
|
||||
"@brief Clear the list.\n\n"
|
||||
"@tsexample\n"
|
||||
"// Inform the GuiTextListCtrl control to clear its contents\n"
|
||||
"%thisGuiTextListCtrl.clear();\n"
|
||||
"@endtsexample\n\n"
|
||||
"@see GuiControl")
|
||||
{
|
||||
object->clear();
|
||||
}
|
||||
|
||||
DefineEngineMethod( GuiTextListCtrl, rowCount, S32, (),,
|
||||
"@brief Get the number of rows.\n\n"
|
||||
"@tsexample\n"
|
||||
"// Get the number of rows in the list\n"
|
||||
"%rowCount = %thisGuiTextListCtrl.rowCount();\n"
|
||||
"@endtsexample\n\n"
|
||||
"@return Number of rows in the list.\n\n"
|
||||
"@see GuiControl")
|
||||
{
|
||||
return object->getNumEntries();
|
||||
}
|
||||
|
||||
DefineEngineMethod( GuiTextListCtrl, getRowId, S32, (int index),,
|
||||
"@brief Get the row ID for an index.\n\n"
|
||||
"@param index Index to get the RowID at\n"
|
||||
"@tsexample\n"
|
||||
"// Define the index\n"
|
||||
"%index = \"3\";\n\n"
|
||||
"// Request the row ID at the defined index\n"
|
||||
"%rowId = %thisGuiTextListCtrl.getRowId(%index);\n"
|
||||
"@endtsexample\n\n"
|
||||
"@return RowId at the defined index.\n\n"
|
||||
"@see GuiControl")
|
||||
{
|
||||
if(index >= object->getNumEntries())
|
||||
return -1;
|
||||
|
||||
return object->mList[index].id;
|
||||
}
|
||||
|
||||
DefineEngineMethod( GuiTextListCtrl, getRowTextById, const char*, (int id),,
|
||||
"@brief Get the text of a row with the specified id.\n\n"
|
||||
"@tsexample\n"
|
||||
"// Define the id\n"
|
||||
"%id = \"4\";\n\n"
|
||||
"// Inform the GuiTextListCtrl control to return the text at the defined row id\n"
|
||||
"%rowText = %thisGuiTextListCtrl.getRowTextById(%id);\n"
|
||||
"@endtsexample\n\n"
|
||||
"@return Row text at the requested row id.\n\n"
|
||||
"@see GuiControl")
|
||||
{
|
||||
S32 index = object->findEntryById(id);
|
||||
if(index < 0)
|
||||
return "";
|
||||
return object->mList[index].text;
|
||||
}
|
||||
|
||||
DefineEngineMethod( GuiTextListCtrl, getRowNumById, S32, (int id),,
|
||||
"@brief Get the row number for a specified id.\n\n"
|
||||
"@param id Id to get the row number at\n"
|
||||
"@tsexample\n"
|
||||
"// Define the id\n"
|
||||
"%id = \"4\";\n\n"
|
||||
"// Request the row number from the GuiTextListCtrl control at the defined id.\n"
|
||||
"%rowNumber = %thisGuiTextListCtrl.getRowNumById(%id);\n"
|
||||
"@endtsexample\n\n"
|
||||
"@see GuiControl")
|
||||
{
|
||||
S32 index = object->findEntryById(id);
|
||||
if(index < 0)
|
||||
return -1;
|
||||
return index;
|
||||
}
|
||||
|
||||
DefineEngineMethod( GuiTextListCtrl, getRowText, const char*, (int index),,
|
||||
"@brief Get the text of the row with the specified index.\n\n"
|
||||
"@param index Row index to acquire the text at.\n"
|
||||
"@tsexample\n"
|
||||
"// Define the row index\n"
|
||||
"%index = \"5\";\n\n"
|
||||
"// Request the text from the row at the defined index\n"
|
||||
"%rowText = %thisGuiTextListCtrl.getRowText(%index);\n"
|
||||
"@endtsexample\n\n"
|
||||
"@return Text at the defined row index.\n\n"
|
||||
"@see GuiControl")
|
||||
{
|
||||
if(index < 0 || index >= object->mList.size())
|
||||
return "";
|
||||
return object->mList[index].text;
|
||||
}
|
||||
|
||||
DefineEngineMethod( GuiTextListCtrl, removeRowById, void, (int id),,
|
||||
"@brief Remove row with the specified id.\n\n"
|
||||
"@param id Id to remove the row entry at\n"
|
||||
"@tsexample\n"
|
||||
"// Define the id\n"
|
||||
"%id = \"4\";\n\n"
|
||||
"// Inform the GuiTextListCtrl control to remove the row at the defined id\n"
|
||||
"%thisGuiTextListCtrl.removeRowById(%id);\n"
|
||||
"@endtsexample\n\n"
|
||||
"@see GuiControl")
|
||||
{
|
||||
object->removeEntry(id);
|
||||
}
|
||||
|
||||
DefineEngineMethod( GuiTextListCtrl, removeRow, void, (int index),,
|
||||
"@brief Remove a row from the table, based on its index.\n\n"
|
||||
"@param index Row index to remove from the list.\n"
|
||||
"@tsexample\n"
|
||||
"// Define the row index\n"
|
||||
"%index = \"4\";\n\n"
|
||||
"// Inform the GuiTextListCtrl control to remove the row at the defined row index\n"
|
||||
"%thisGuiTextListCtrl.removeRow(%index);\n"
|
||||
"@endtsexample\n\n"
|
||||
"@see GuiControl")
|
||||
{
|
||||
object->removeEntryByIndex(index);
|
||||
}
|
||||
|
||||
DefineEngineMethod( GuiTextListCtrl, scrollVisible, void, (int rowNum),,
|
||||
"@brief Scroll so the specified row is visible\n\n"
|
||||
"@param rowNum Row number to make visible\n"
|
||||
"@tsexample\n"
|
||||
"// Define the row number to make visible\n"
|
||||
"%rowNum = \"4\";\n\n"
|
||||
"// Inform the GuiTextListCtrl control to scroll the list so the defined rowNum is visible.\n"
|
||||
"%thisGuiTextListCtrl.scrollVisible(%rowNum);\n"
|
||||
"@endtsexample\n\n"
|
||||
"@see GuiControl")
|
||||
{
|
||||
object->scrollCellVisible(Point2I(0, rowNum));
|
||||
}
|
||||
|
||||
DefineEngineMethod( GuiTextListCtrl, findTextIndex, S32, (const char* needle),,
|
||||
"@brief Find needle in the list, and return the row number it was found in.\n\n"
|
||||
"@param needle Text to find in the list.\n"
|
||||
"@tsexample\n"
|
||||
"// Define the text to find in the list\n"
|
||||
"%needle = \"Text To Find\";\n\n"
|
||||
"// Request the row number that contains the defined text to find\n\n"
|
||||
"%rowNumber = %thisGuiTextListCtrl.findTextIndex(%needle);\n\n"
|
||||
"@endtsexample\n\n"
|
||||
"@return Row number that the defined text was found in,\n\n"
|
||||
"@see GuiControl")
|
||||
{
|
||||
return( object->findEntryByText(needle) );
|
||||
}
|
||||
|
||||
DefineEngineMethod( GuiTextListCtrl, setRowActive, void, (int rowNum, bool active),,
|
||||
"@brief Mark a specified row as active/not.\n\n"
|
||||
"@param rowNum Row number to change the active state.\n"
|
||||
"@param active Boolean active state to set the row number.\n"
|
||||
"@tsexample\n"
|
||||
"// Define the row number\n"
|
||||
"%rowNum = \"4\";\n\n"
|
||||
"// Define the boolean active state\n"
|
||||
"%active = \"true\";\n\n"
|
||||
"// Informthe GuiTextListCtrl control to set the defined active state at the defined row number.\n"
|
||||
"%thisGuiTextListCtrl.setRowActive(%rowNum,%active);\n"
|
||||
"@endtsexample\n\n"
|
||||
"@see GuiControl")
|
||||
{
|
||||
object->setEntryActive( U32( rowNum ), active );
|
||||
}
|
||||
|
||||
DefineEngineMethod( GuiTextListCtrl, isRowActive, bool, (int rowNum),,
|
||||
"@brief Check if the specified row is currently active or not.\n\n"
|
||||
"@param rowNum Row number to check the active state.\n"
|
||||
"@tsexample\n"
|
||||
"// Define the row number\n"
|
||||
"%rowNum = \"5\";\n\n"
|
||||
"// Request the active state of the defined row number from the GuiTextListCtrl control.\n"
|
||||
"%rowActiveState = %thisGuiTextListCtrl.isRowActive(%rowNum);\n"
|
||||
"@endtsexample\n\n"
|
||||
"@return Active state of the defined row number.\n\n"
|
||||
"@see GuiControl")
|
||||
{
|
||||
return( object->isEntryActive( U32( rowNum ) ) );
|
||||
}
|
||||
114
Engine/source/gui/controls/guiTextListCtrl.h
Normal file
114
Engine/source/gui/controls/guiTextListCtrl.h
Normal file
|
|
@ -0,0 +1,114 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// Copyright (c) 2012 GarageGames, LLC
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to
|
||||
// deal in the Software without restriction, including without limitation the
|
||||
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
// sell copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
// IN THE SOFTWARE.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef _GUITEXTLISTCTRL_H_
|
||||
#define _GUITEXTLISTCTRL_H_
|
||||
|
||||
#ifndef _GUIARRAYCTRL_H_
|
||||
#include "gui/core/guiArrayCtrl.h"
|
||||
#endif
|
||||
|
||||
class GuiTextListCtrl : public GuiArrayCtrl
|
||||
{
|
||||
private:
|
||||
typedef GuiArrayCtrl Parent;
|
||||
|
||||
public:
|
||||
struct Entry
|
||||
{
|
||||
char *text;
|
||||
U32 id;
|
||||
bool active;
|
||||
};
|
||||
|
||||
Vector<Entry> mList;
|
||||
|
||||
protected:
|
||||
enum ScrollConst
|
||||
{
|
||||
UP = 0,
|
||||
DOWN = 1
|
||||
};
|
||||
enum {
|
||||
InvalidId = 0xFFFFFFFF
|
||||
};
|
||||
Vector<S32> mColumnOffsets;
|
||||
|
||||
bool mFitParentWidth;
|
||||
bool mClipColumnText;
|
||||
|
||||
U32 getRowWidth(Entry *row);
|
||||
bool cellSelected(Point2I cell);
|
||||
void onCellSelected(Point2I cell);
|
||||
|
||||
public:
|
||||
GuiTextListCtrl();
|
||||
|
||||
DECLARE_CONOBJECT(GuiTextListCtrl);
|
||||
DECLARE_CATEGORY( "Gui Lists" );
|
||||
DECLARE_DESCRIPTION( "A control that displays text in tabular form." );
|
||||
|
||||
DECLARE_CALLBACK( void, onSelect, (const char* cellid, const char* text));
|
||||
DECLARE_CALLBACK( void, onDeleteKey, ( const char* id ));
|
||||
|
||||
static void initPersistFields();
|
||||
|
||||
virtual void setCellSize( const Point2I &size ){ mCellSize = size; }
|
||||
virtual void getCellSize( Point2I &size ){ size = mCellSize; }
|
||||
|
||||
const char *getScriptValue();
|
||||
void setScriptValue(const char *value);
|
||||
|
||||
U32 getNumEntries();
|
||||
|
||||
void clear();
|
||||
virtual void addEntry(U32 id, const char *text);
|
||||
virtual void insertEntry(U32 id, const char *text, S32 index);
|
||||
void setEntry(U32 id, const char *text);
|
||||
void setEntryActive(U32 id, bool active);
|
||||
S32 findEntryById(U32 id);
|
||||
S32 findEntryByText(const char *text);
|
||||
bool isEntryActive(U32 id);
|
||||
|
||||
U32 getEntryId(U32 index);
|
||||
|
||||
bool onWake();
|
||||
void removeEntry(U32 id);
|
||||
virtual void removeEntryByIndex(S32 id);
|
||||
virtual void sort(U32 column, bool increasing = true);
|
||||
virtual void sortNumerical(U32 column, bool increasing = true);
|
||||
|
||||
U32 getSelectedId();
|
||||
U32 getSelectedRow();
|
||||
const char *getSelectedText();
|
||||
|
||||
bool onKeyDown(const GuiEvent &event);
|
||||
|
||||
virtual void onRenderCell(Point2I offset, Point2I cell, bool selected, bool mouseOver);
|
||||
|
||||
void setSize(Point2I newSize);
|
||||
void onRemove();
|
||||
void addColumnOffset(S32 offset) { mColumnOffsets.push_back(offset); }
|
||||
void clearColumnOffsets() { mColumnOffsets.clear(); }
|
||||
};
|
||||
|
||||
#endif //_GUI_TEXTLIST_CTRL_H
|
||||
5397
Engine/source/gui/controls/guiTreeViewCtrl.cpp
Normal file
5397
Engine/source/gui/controls/guiTreeViewCtrl.cpp
Normal file
File diff suppressed because it is too large
Load diff
606
Engine/source/gui/controls/guiTreeViewCtrl.h
Normal file
606
Engine/source/gui/controls/guiTreeViewCtrl.h
Normal file
|
|
@ -0,0 +1,606 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// Copyright (c) 2012 GarageGames, LLC
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to
|
||||
// deal in the Software without restriction, including without limitation the
|
||||
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
// sell copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
// IN THE SOFTWARE.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef _GUI_TREEVIEWCTRL_H
|
||||
#define _GUI_TREEVIEWCTRL_H
|
||||
|
||||
#include "core/bitSet.h"
|
||||
#include "math/mRect.h"
|
||||
#include "gfx/gFont.h"
|
||||
#include "gui/core/guiControl.h"
|
||||
#include "gui/core/guiArrayCtrl.h"
|
||||
|
||||
|
||||
class GuiTextEditCtrl;
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
class GuiTreeViewCtrl : public GuiArrayCtrl
|
||||
{
|
||||
private:
|
||||
typedef GuiArrayCtrl Parent;
|
||||
|
||||
public:
|
||||
/// @section GuiControl_Intro Introduction
|
||||
/// @nosubgrouping
|
||||
|
||||
///
|
||||
class Item
|
||||
{
|
||||
public:
|
||||
|
||||
enum ItemState
|
||||
{
|
||||
Selected = BIT( 0 ),
|
||||
Expanded = BIT( 1 ),
|
||||
Marked = BIT( 2 ), ///< Marked items are drawn with a border around them. This is
|
||||
/// different than "Selected" because it can only be set by script.
|
||||
Filtered = BIT( 3 ), ///< Whether the item is currently filtered out.
|
||||
MouseOverBmp = BIT( 4 ),
|
||||
MouseOverText = BIT( 5 ),
|
||||
MouseOverIcon = BIT( 6 ),
|
||||
InspectorData = BIT( 7 ), ///< Set if we're representing some inspector
|
||||
/// info (ie, use mInspectorInfo, not mScriptInfo)
|
||||
|
||||
VirtualParent = BIT( 8 ), ///< This indicates that we should be rendered as
|
||||
/// a parent even though we don't have any children.
|
||||
/// This is useful for preventing scenarios where
|
||||
/// we might want to create thousands of
|
||||
/// Items that might never be shown (for instance
|
||||
/// if we're browsing the object hierarchy in
|
||||
/// Torque, which might have thousands of objects).
|
||||
|
||||
RebuildVisited = BIT( 9 ), ///< Rebuild traversal for virtual parents has visited and validated this item.
|
||||
|
||||
ShowObjectId = BIT( 10 ),
|
||||
ShowClassName = BIT( 11 ),
|
||||
ShowObjectName = BIT( 12 ),
|
||||
ShowInternalName = BIT( 13 ),
|
||||
ShowClassNameForUnnamed = BIT( 14 )
|
||||
};
|
||||
|
||||
GuiTreeViewCtrl* mParentControl;
|
||||
BitSet32 mState;
|
||||
SimObjectPtr< GuiControlProfile > mProfile;
|
||||
S16 mId;
|
||||
U16 mTabLevel;
|
||||
Item* mParent;
|
||||
Item* mChild;
|
||||
Item* mNext;
|
||||
Item* mPrevious;
|
||||
String mTooltip;
|
||||
S32 mIcon; //stores the icon that will represent the item in the tree
|
||||
S32 mDataRenderWidth; /// this stores the pixel width needed
|
||||
/// to render the item's data in the
|
||||
/// onRenderCell function to optimize
|
||||
/// for speed.
|
||||
|
||||
Item( GuiTreeViewCtrl* parent, GuiControlProfile *pProfile );
|
||||
~Item();
|
||||
|
||||
struct ScriptTag
|
||||
{
|
||||
S8 mNormalImage;
|
||||
S8 mExpandedImage;
|
||||
StringTableEntry mText;
|
||||
StringTableEntry mValue;
|
||||
} mScriptInfo;
|
||||
struct InspectorTag
|
||||
{
|
||||
SimObjectPtr<SimObject> mObject;
|
||||
} mInspectorInfo;
|
||||
|
||||
/// @name Get Methods
|
||||
/// @{
|
||||
|
||||
///
|
||||
S8 getNormalImage() const;
|
||||
S8 getExpandedImage() const;
|
||||
StringTableEntry getText();
|
||||
StringTableEntry getValue();
|
||||
inline const S16 getID() const { return mId; };
|
||||
SimObject *getObject();
|
||||
U32 getDisplayTextLength();
|
||||
S32 getDisplayTextWidth(GFont *font);
|
||||
void getDisplayText(U32 bufLen, char *buf);
|
||||
bool hasObjectBasedTooltip();
|
||||
void getTooltipText(U32 bufLen, char *buf);
|
||||
|
||||
/// @}
|
||||
|
||||
|
||||
/// @name Set Methods
|
||||
/// @{
|
||||
|
||||
/// Set whether an item is expanded or not (showing children or having them hidden)
|
||||
void setExpanded( const bool f = true );
|
||||
/// Set the image to display when an item IS expanded
|
||||
void setExpandedImage(const S8 id);
|
||||
/// Set the image to display when an item is NOT expanded
|
||||
void setNormalImage(const S8 id);
|
||||
/// Assign a SimObject pointer to an inspector data item
|
||||
void setObject(SimObject *obj);
|
||||
/// Set the items displayable text (caption)
|
||||
void setText(StringTableEntry txt);
|
||||
/// Set the items script value (data)
|
||||
void setValue(StringTableEntry val);
|
||||
/// Set the items virtual parent flag
|
||||
void setVirtualParent( bool value );
|
||||
/// Set whether the item is filtered out or not.
|
||||
void setFiltered( bool value ) { mState.set( Filtered ); }
|
||||
|
||||
/// @}
|
||||
|
||||
|
||||
/// @name State Retrieval
|
||||
/// @{
|
||||
|
||||
/// Returns true if this item is expanded. For
|
||||
/// inspector objects, the expansion is stored
|
||||
/// on the SimObject, for other things we use our
|
||||
/// bit vector.
|
||||
bool isExpanded() const;
|
||||
|
||||
/// Return whether the item is current filtered out or not.
|
||||
/// @note Parent items may be filtered and yet still be visible if they have
|
||||
/// children that are not filtered.
|
||||
bool isFiltered() const { return mState.test( Filtered ); }
|
||||
|
||||
/// Returns true if an item is inspector data
|
||||
/// or false if it's just an item.
|
||||
bool isInspectorData() const { return mState.test(InspectorData); };
|
||||
|
||||
/// Returns true if we should show the expand art
|
||||
/// and make the item interact with the mouse as if
|
||||
/// it were a parent.
|
||||
bool isParent() const;
|
||||
|
||||
/// Return true if text label for inspector item should include internal name only.
|
||||
bool showInternalNameOnly() const { return mState.test( ShowInternalName ) && !mState.test( ShowObjectName | ShowClassName | ShowObjectId ); }
|
||||
|
||||
/// Return true if text label for inspector item should include object name only.
|
||||
bool showObjectNameOnly() const { return mState.test( ShowObjectName ) && !mState.test( ShowInternalName | ShowClassName | ShowObjectId ); }
|
||||
|
||||
/// @}
|
||||
|
||||
/// @name Searching Methods
|
||||
/// @{
|
||||
|
||||
/// Find a regular data item by it's script name.
|
||||
Item* findChildByName( const char* name );
|
||||
|
||||
/// Find an inspector data item by it's SimObject pointer
|
||||
Item* findChildByValue(const SimObject *obj);
|
||||
|
||||
/// Find a regular data item by it's script value
|
||||
Item* findChildByValue(StringTableEntry Value);
|
||||
|
||||
/// @}
|
||||
|
||||
/// Sort the childs of the item by their text.
|
||||
///
|
||||
/// @param caseSensitive If true, sorting is case-sensitive.
|
||||
/// @param traverseHierarchy If true, also triggers a sort() on all child items.
|
||||
/// @param parentsFirst If true, parents are grouped before children in the resulting sort.
|
||||
void sort( bool caseSensitive = true, bool traverseHierarchy = false, bool parentsFirst = false );
|
||||
|
||||
private:
|
||||
void _connectMonitors();
|
||||
void _disconnectMonitors();
|
||||
};
|
||||
|
||||
friend class Item; // _onInspectorSetObjectModified
|
||||
|
||||
/// @name Enums
|
||||
/// @{
|
||||
|
||||
///
|
||||
enum TreeState
|
||||
{
|
||||
RebuildVisible = BIT(0), ///< Temporary flag, we have to rebuild the tree.
|
||||
IsInspector = BIT(1), ///< We are mapping a SimObject hierarchy.
|
||||
IsEditable = BIT(2), ///< We allow items to be moved around.
|
||||
ShowTreeLines = BIT(3), ///< Should we render tree lines or just icons?
|
||||
BuildingVisTree = BIT(4), ///< We are currently building the visible tree (prevent recursion)
|
||||
};
|
||||
|
||||
protected:
|
||||
|
||||
enum
|
||||
{
|
||||
MaxIcons = 32,
|
||||
};
|
||||
|
||||
enum Icons
|
||||
{
|
||||
Default1 = 0,
|
||||
SimGroup1,
|
||||
SimGroup2,
|
||||
SimGroup3,
|
||||
SimGroup4,
|
||||
Hidden,
|
||||
Lock1,
|
||||
Lock2,
|
||||
Default,
|
||||
Icon31,
|
||||
Icon32
|
||||
};
|
||||
|
||||
enum mDragMidPointFlags
|
||||
{
|
||||
NomDragMidPoint,
|
||||
AbovemDragMidPoint,
|
||||
BelowmDragMidPoint
|
||||
};
|
||||
|
||||
///
|
||||
enum HitFlags
|
||||
{
|
||||
OnIndent = BIT(0),
|
||||
OnImage = BIT(1),
|
||||
OnIcon = BIT(2),
|
||||
OnText = BIT(3),
|
||||
OnRow = BIT(4),
|
||||
};
|
||||
|
||||
///
|
||||
enum BmpIndices
|
||||
{
|
||||
BmpFirstChild,
|
||||
BmpLastChild,
|
||||
BmpChild,
|
||||
BmpExp,
|
||||
BmpExpN,
|
||||
BmpExpP,
|
||||
BmpExpPN,
|
||||
BmpCon,
|
||||
BmpConN,
|
||||
BmpConP,
|
||||
BmpConPN,
|
||||
BmpLine,
|
||||
BmpGlow,
|
||||
};
|
||||
|
||||
/// @}
|
||||
|
||||
/// @name Callbacks
|
||||
/// @{
|
||||
|
||||
DECLARE_CALLBACK( bool, onDeleteObject, ( SimObject* object ) );
|
||||
DECLARE_CALLBACK( bool, isValidDragTarget, ( S32 id, const char* value ) );
|
||||
DECLARE_CALLBACK( void, onDefineIcons, () );
|
||||
DECLARE_CALLBACK( void, onAddGroupSelected, ( SimGroup* group ) );
|
||||
DECLARE_CALLBACK( void, onAddSelection, ( S32 itemOrObjectId, bool isLastSelection ) );
|
||||
DECLARE_CALLBACK( void, onSelect, ( S32 itemOrObjectId ) );
|
||||
DECLARE_CALLBACK( void, onInspect, ( S32 itemOrObjectId ) );
|
||||
DECLARE_CALLBACK( void, onRemoveSelection, ( S32 itemOrObjectId ) );
|
||||
DECLARE_CALLBACK( void, onUnselect, ( S32 itemOrObjectId ) );
|
||||
DECLARE_CALLBACK( void, onDeleteSelection, () );
|
||||
DECLARE_CALLBACK( void, onObjectDeleteCompleted, () );
|
||||
DECLARE_CALLBACK( void, onKeyDown, ( S32 modifier, S32 keyCode ) );
|
||||
DECLARE_CALLBACK( void, onMouseUp, ( S32 hitItemId, S32 mouseClickCount ) );
|
||||
DECLARE_CALLBACK( void, onMouseDragged, () );
|
||||
DECLARE_CALLBACK( void, onRightMouseDown, ( S32 itemId, const Point2I& mousePos, SimObject* object = NULL ) );
|
||||
DECLARE_CALLBACK( void, onRightMouseUp, ( S32 itemId, const Point2I& mousePos, SimObject* object = NULL ) );
|
||||
DECLARE_CALLBACK( void, onBeginReparenting, () );
|
||||
DECLARE_CALLBACK( void, onEndReparenting, () );
|
||||
DECLARE_CALLBACK( void, onReparent, ( S32 itemOrObjectId, S32 oldParentItemOrObjectId, S32 newParentItemOrObjectId ) );
|
||||
DECLARE_CALLBACK( void, onDragDropped, () );
|
||||
DECLARE_CALLBACK( void, onAddMultipleSelectionBegin, () );
|
||||
DECLARE_CALLBACK( void, onAddMultipleSelectionEnd, () );
|
||||
DECLARE_CALLBACK( bool, canRenameObject, ( SimObject* object ) );
|
||||
DECLARE_CALLBACK( bool, handleRenameObject, ( const char* newName, SimObject* object ) );
|
||||
DECLARE_CALLBACK( void, onClearSelection, () );
|
||||
|
||||
/// @}
|
||||
|
||||
///
|
||||
Vector<Item*> mItems;
|
||||
Vector<Item*> mVisibleItems;
|
||||
Vector<Item*> mSelectedItems;
|
||||
|
||||
/// Used for tracking stuff that was selected, but may not have been
|
||||
/// created at time of selection.
|
||||
Vector<S32> mSelected;
|
||||
|
||||
S32 mItemCount;
|
||||
|
||||
/// We do our own free list, as we we want to be able to recycle
|
||||
/// item ids and do some other clever things.
|
||||
Item* mItemFreeList;
|
||||
|
||||
Item* mRoot;
|
||||
S32 mMaxWidth;
|
||||
S32 mSelectedItem;
|
||||
S32 mDraggedToItem;
|
||||
S32 mStart;
|
||||
|
||||
/// A combination of TreeState flags.
|
||||
BitSet32 mFlags;
|
||||
|
||||
Item* mPossibleRenameItem;
|
||||
Item* mRenamingItem;
|
||||
Item* mTempItem;
|
||||
GuiTextEditCtrl* mRenameCtrl;
|
||||
|
||||
/// Current filter that determines which items in the tree are displayed and which are hidden.
|
||||
String mFilterText;
|
||||
|
||||
/// If true, a trace of actions taken by the control is logged to the console. Can
|
||||
/// be turned on with the setDebug() script method.
|
||||
bool mDebug;
|
||||
|
||||
GFXTexHandle mIconTable[MaxIcons];
|
||||
|
||||
S32 mTabSize;
|
||||
S32 mTextOffset;
|
||||
bool mFullRowSelect;
|
||||
S32 mItemHeight;
|
||||
bool mDestroyOnSleep;
|
||||
bool mSupportMouseDragging;
|
||||
bool mMultipleSelections;
|
||||
bool mDeleteObjectAllowed;
|
||||
bool mDragToItemAllowed;
|
||||
bool mClearAllOnSingleSelection; ///< When clicking on an already selected item, clear all other selections
|
||||
bool mCompareToObjectID;
|
||||
|
||||
/// Used to hide the root tree element, defaults to true.
|
||||
bool mShowRoot;
|
||||
|
||||
/// If true, object IDs will be included in inspector tree item labels.
|
||||
bool mShowObjectIds;
|
||||
|
||||
/// If true, class names will be included in inspector tree item labels.
|
||||
bool mShowClassNames;
|
||||
|
||||
/// If true, object names will be included in inspector tree item labels.
|
||||
bool mShowObjectNames;
|
||||
|
||||
/// If true, internal names will be included in inspector tree item labels.
|
||||
bool mShowInternalNames;
|
||||
|
||||
/// If true, class names will be used as object names for unnamed objects.
|
||||
bool mShowClassNameForUnnamedObjects;
|
||||
|
||||
/// If true then tooltips will be automatically
|
||||
/// generated for all Inspector items
|
||||
bool mUseInspectorTooltips;
|
||||
|
||||
/// If true then only render item tooltips if the item
|
||||
/// extends past the displayable width
|
||||
bool mTooltipOnWidthOnly;
|
||||
|
||||
/// If true clicking on a selected item ( that is an object )
|
||||
/// will allow you to rename it.
|
||||
bool mCanRenameObjects;
|
||||
|
||||
/// If true then object renaming operates on the internalName rather than
|
||||
/// the object name.
|
||||
bool mRenameInternal;
|
||||
|
||||
S32 mCurrentDragCell;
|
||||
S32 mPreviousDragCell;
|
||||
S32 mDragMidPoint;
|
||||
bool mMouseDragged;
|
||||
bool mDragStartInSelection;
|
||||
Point2I mMouseDownPoint;
|
||||
|
||||
StringTableEntry mBitmapBase;
|
||||
GFXTexHandle mTexRollover;
|
||||
GFXTexHandle mTexSelected;
|
||||
|
||||
ColorI mAltFontColor;
|
||||
ColorI mAltFontColorHL;
|
||||
ColorI mAltFontColorSE;
|
||||
|
||||
SimObjectPtr<SimObject> mRootObject;
|
||||
|
||||
void _destroyChildren( Item* item, Item* parent, bool deleteObjects=true);
|
||||
void _destroyItem( Item* item, bool deleteObject=true);
|
||||
void _destroyTree();
|
||||
|
||||
void _deleteItem(Item* item);
|
||||
|
||||
void _buildItem(Item* item, U32 tabLevel, bool bForceFullUpdate = false);
|
||||
|
||||
Item* _findItemByAmbiguousId( S32 itemOrObjectId, bool buildVirtual = true );
|
||||
|
||||
void _expandObjectHierarchy( SimGroup* group );
|
||||
|
||||
bool _hitTest(const Point2I & pnt, Item* & item, BitSet32 & flags);
|
||||
|
||||
S32 getInspectorItemIconsWidth(Item* & item);
|
||||
|
||||
virtual bool onVirtualParentBuild(Item *item, bool bForceFullUpdate = false);
|
||||
virtual bool onVirtualParentExpand(Item *item);
|
||||
virtual bool onVirtualParentCollapse(Item *item);
|
||||
virtual void onItemSelected( Item *item );
|
||||
virtual void onRemoveSelection( Item *item );
|
||||
virtual void onClearSelection() {};
|
||||
|
||||
Item* addInspectorDataItem(Item *parent, SimObject *obj);
|
||||
|
||||
virtual bool isValidDragTarget( Item* item );
|
||||
|
||||
bool _isRootLevelItem( Item* item ) const
|
||||
{
|
||||
return ( item == mRoot && mShowRoot ) || ( item->mParent == mRoot && !mShowRoot );
|
||||
}
|
||||
|
||||
/// For inspector tree views, this is hooked to the SetModificationSignal of sets
|
||||
/// so that the tree view knows when it needs to refresh.
|
||||
void _onInspectorSetObjectModified( SetModification modification, SimSet* set, SimObject* object );
|
||||
|
||||
public:
|
||||
GuiTreeViewCtrl();
|
||||
virtual ~GuiTreeViewCtrl();
|
||||
|
||||
/// Used for syncing the mSelected and mSelectedItems lists.
|
||||
void syncSelection();
|
||||
|
||||
void lockSelection(bool lock);
|
||||
void hideSelection(bool hide);
|
||||
void toggleLockSelection();
|
||||
void toggleHideSelection();
|
||||
virtual bool canAddSelection( Item *item ) { return true; };
|
||||
void addSelection(S32 itemId, bool update = true, bool isLastSelection = true);
|
||||
const Vector< Item* >& getSelectedItems() const { return mSelectedItems; }
|
||||
const Vector< S32 >& getSelected() const { return mSelected; }
|
||||
|
||||
bool isSelected(S32 itemId)
|
||||
{
|
||||
return isSelected( getItem( itemId ) );
|
||||
}
|
||||
bool isSelected(Item *item)
|
||||
{
|
||||
if ( !item )
|
||||
return false;
|
||||
return mSelectedItems.contains( item );
|
||||
}
|
||||
|
||||
void setDebug( bool value ) { mDebug = value; }
|
||||
|
||||
/// Should use addSelection and removeSelection when calling from script
|
||||
/// instead of setItemSelected. Use setItemSelected when you want to select
|
||||
/// something in the treeview as it has script call backs.
|
||||
void removeSelection(S32 itemId);
|
||||
|
||||
/// Sets the flag of the item with the matching itemId.
|
||||
bool setItemSelected(S32 itemId, bool select);
|
||||
bool setItemExpanded(S32 itemId, bool expand);
|
||||
bool setItemValue(S32 itemId, StringTableEntry Value);
|
||||
|
||||
const char * getItemText(S32 itemId);
|
||||
const char * getItemValue(S32 itemId);
|
||||
StringTableEntry getTextToRoot(S32 itemId, const char *delimiter = "");
|
||||
|
||||
Item* getRootItem() const { return mRoot; }
|
||||
Item * getItem(S32 itemId) const;
|
||||
Item * createItem(S32 icon);
|
||||
bool editItem( S32 itemId, const char* newText, const char* newValue );
|
||||
|
||||
bool markItem( S32 itemId, bool mark );
|
||||
|
||||
bool isItemSelected( S32 itemId );
|
||||
|
||||
// insertion/removal
|
||||
void unlinkItem(Item * item);
|
||||
S32 insertItem(S32 parentId, const char * text, const char * value = "", const char * iconString = "", S16 normalImage = 0, S16 expandedImage = 1);
|
||||
bool removeItem(S32 itemId, bool deleteObjects=true);
|
||||
void removeAllChildren(S32 itemId); // Remove all children of the given item
|
||||
|
||||
bool buildIconTable(const char * icons);
|
||||
|
||||
bool setAddGroup(SimObject * obj);
|
||||
|
||||
S32 getIcon(const char * iconString);
|
||||
|
||||
// tree items
|
||||
const S32 getFirstRootItem() const;
|
||||
S32 getChildItem(S32 itemId);
|
||||
S32 getParentItem(S32 itemId);
|
||||
S32 getNextSiblingItem(S32 itemId);
|
||||
S32 getPrevSiblingItem(S32 itemId);
|
||||
S32 getItemCount();
|
||||
S32 getSelectedItem();
|
||||
S32 getSelectedItem(S32 index); // Given an item's index in the selection list, return its itemId
|
||||
S32 getSelectedItemsCount() {return mSelectedItems.size();} // Returns the number of selected items
|
||||
void moveItemUp( S32 itemId );
|
||||
void moveItemDown( S32 itemId );
|
||||
|
||||
// misc.
|
||||
bool scrollVisible( Item *item );
|
||||
bool scrollVisible( S32 itemId );
|
||||
bool scrollVisibleByObjectId( S32 objID );
|
||||
|
||||
void deleteSelection();
|
||||
void clearSelection();
|
||||
|
||||
S32 findItemByName(const char *name);
|
||||
S32 findItemByValue(const char *name);
|
||||
S32 findItemByObjectId(S32 iObjId);
|
||||
|
||||
void sortTree( bool caseSensitive, bool traverseHierarchy, bool parentsFirst );
|
||||
|
||||
/// @name Filtering
|
||||
/// @{
|
||||
|
||||
/// Get the current filter expression. Only tree items whose text matches this expression
|
||||
/// are displayed. By default, the expression is empty and all items are shown.
|
||||
const String& getFilterText() const { return mFilterText; }
|
||||
|
||||
/// Set the pattern by which to filter items in the tree. Only items in the tree whose text
|
||||
/// matches this pattern are displayed.
|
||||
void setFilterText( const String& text );
|
||||
|
||||
/// Clear the current item filtering pattern.
|
||||
void clearFilterText() { setFilterText( String::EmptyString ); }
|
||||
|
||||
/// @}
|
||||
|
||||
// GuiControl
|
||||
bool onAdd();
|
||||
bool onWake();
|
||||
void onSleep();
|
||||
void onPreRender();
|
||||
bool onKeyDown( const GuiEvent &event );
|
||||
void onMouseDown(const GuiEvent &event);
|
||||
void onMiddleMouseDown(const GuiEvent &event);
|
||||
void onMouseMove(const GuiEvent &event);
|
||||
void onMouseEnter(const GuiEvent &event);
|
||||
void onMouseLeave(const GuiEvent &event);
|
||||
void onRightMouseDown(const GuiEvent &event);
|
||||
void onRightMouseUp(const GuiEvent &event);
|
||||
void onMouseDragged(const GuiEvent &event);
|
||||
virtual void onMouseUp(const GuiEvent &event);
|
||||
|
||||
/// Returns false if the object is a child of one of the inner items.
|
||||
bool childSearch(Item * item, SimObject *obj, bool yourBaby);
|
||||
|
||||
/// Find immediately available inspector items (eg ones that aren't children of other inspector items)
|
||||
/// and then update their sets
|
||||
void inspectorSearch(Item * item, Item * parent, SimSet * parentSet, SimSet * newParentSet);
|
||||
|
||||
/// Find the Item associated with a sceneObject, returns true if it found one
|
||||
bool objectSearch( const SimObject *object, Item **item );
|
||||
|
||||
// GuiArrayCtrl
|
||||
void onRenderCell(Point2I offset, Point2I cell, bool, bool);
|
||||
void onRender(Point2I offset, const RectI &updateRect);
|
||||
|
||||
bool renderTooltip( const Point2I &hoverPos, const Point2I& cursorPos, const char* tipText );
|
||||
|
||||
static void initPersistFields();
|
||||
|
||||
void inspectObject(SimObject * obj, bool okToEdit);
|
||||
void buildVisibleTree(bool bForceFullUpdate = false);
|
||||
|
||||
void cancelRename();
|
||||
void onRenameValidate();
|
||||
void showItemRenameCtrl( Item* item );
|
||||
|
||||
DECLARE_CONOBJECT(GuiTreeViewCtrl);
|
||||
DECLARE_CATEGORY( "Gui Lists" );
|
||||
DECLARE_DESCRIPTION( "Hierarchical list of text items with optional icons.\nCan also be used to inspect SimObject hierarchies." );
|
||||
};
|
||||
|
||||
#endif
|
||||
Loading…
Add table
Add a link
Reference in a new issue