added everything
This commit is contained in:
26
engine/gui/controls/guiBackgroundCtrl.cc
Executable file
26
engine/gui/controls/guiBackgroundCtrl.cc
Executable file
@ -0,0 +1,26 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// Torque Game Engine
|
||||
// Copyright (C) GarageGames.com, Inc.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "console/console.h"
|
||||
#include "gui/controls/guiBackgroundCtrl.h"
|
||||
|
||||
IMPLEMENT_CONOBJECT(GuiBackgroundCtrl);
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
GuiBackgroundCtrl::GuiBackgroundCtrl() : GuiControl()
|
||||
{
|
||||
mDraw = false;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
void GuiBackgroundCtrl::onRender(Point2I offset, const RectI &updateRect)
|
||||
{
|
||||
if ( mDraw )
|
||||
Parent::onRender( offset, updateRect );
|
||||
|
||||
renderChildControls(offset, updateRect);
|
||||
}
|
||||
|
||||
|
29
engine/gui/controls/guiBackgroundCtrl.h
Executable file
29
engine/gui/controls/guiBackgroundCtrl.h
Executable file
@ -0,0 +1,29 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// Torque Game Engine
|
||||
// Copyright (C) GarageGames.com, Inc.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#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);
|
||||
GuiBackgroundCtrl();
|
||||
|
||||
void onRender(Point2I offset, const RectI &updateRect);
|
||||
};
|
||||
|
||||
#endif
|
120
engine/gui/controls/guiBitmapBorderCtrl.cc
Executable file
120
engine/gui/controls/guiBitmapBorderCtrl.cc
Executable file
@ -0,0 +1,120 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// Torque Game Engine
|
||||
// Copyright (c) 2002 GarageGames.Com
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "gui/core/guiControl.h"
|
||||
#include "dgl/dgl.h"
|
||||
|
||||
/// 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]
|
||||
TextureHandle mTextureHandle;
|
||||
public:
|
||||
bool onWake();
|
||||
void onSleep();
|
||||
void onRender(Point2I offset, const RectI &updateRect);
|
||||
DECLARE_CONOBJECT(GuiBitmapBorderCtrl);
|
||||
};
|
||||
|
||||
IMPLEMENT_CONOBJECT(GuiBitmapBorderCtrl);
|
||||
|
||||
bool GuiBitmapBorderCtrl::onWake()
|
||||
{
|
||||
if (! Parent::onWake())
|
||||
return false;
|
||||
|
||||
//get the texture for the close, minimize, and maximize buttons
|
||||
mTextureHandle = mProfile->mTextureHandle;
|
||||
bool result = mProfile->constructBitmapArray() >= NumBitmaps;
|
||||
AssertFatal(result, "Failed to create the bitmap array");
|
||||
if(!result)
|
||||
return false;
|
||||
|
||||
mBitmapBounds = mProfile->mBitmapArrayRects.address();
|
||||
return true;
|
||||
}
|
||||
|
||||
void GuiBitmapBorderCtrl::onSleep()
|
||||
{
|
||||
mTextureHandle = NULL;
|
||||
Parent::onSleep();
|
||||
}
|
||||
|
||||
void GuiBitmapBorderCtrl::onRender(Point2I offset, const RectI &updateRect)
|
||||
{
|
||||
renderChildControls( offset, updateRect );
|
||||
dglSetClipRect(updateRect);
|
||||
|
||||
//draw the outline
|
||||
RectI winRect;
|
||||
winRect.point = offset;
|
||||
winRect.extent = mBounds.extent;
|
||||
|
||||
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)
|
||||
dglDrawRectFill(winRect, mProfile->mFillColor);
|
||||
|
||||
dglClearBitmapModulation();
|
||||
dglDrawBitmapSR(mTextureHandle, offset, mBitmapBounds[BorderTopLeft]);
|
||||
dglDrawBitmapSR(mTextureHandle, Point2I(offset.x + mBounds.extent.x - 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 = mBounds.extent.x - mBitmapBounds[BorderTopLeft].extent.x - mBitmapBounds[BorderTopRight].extent.x;
|
||||
destRect.extent.y = mBitmapBounds[BorderTop].extent.y;
|
||||
RectI stretchRect = mBitmapBounds[BorderTop];
|
||||
stretchRect.inset(1,0);
|
||||
dglDrawBitmapStretchSR(mTextureHandle, 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 = mBounds.extent.y - mBitmapBounds[BorderTopLeft].extent.y - mBitmapBounds[BorderBottomLeft].extent.y;
|
||||
stretchRect = mBitmapBounds[BorderLeft];
|
||||
stretchRect.inset(0,1);
|
||||
dglDrawBitmapStretchSR(mTextureHandle, destRect, stretchRect);
|
||||
|
||||
destRect.point.x = offset.x + mBounds.extent.x - mBitmapBounds[BorderRight].extent.x;
|
||||
destRect.extent.x = mBitmapBounds[BorderRight].extent.x;
|
||||
destRect.point.y = offset.y + mBitmapBounds[BorderTopRight].extent.y;
|
||||
destRect.extent.y = mBounds.extent.y - mBitmapBounds[BorderTopRight].extent.y - mBitmapBounds[BorderBottomRight].extent.y;
|
||||
|
||||
stretchRect = mBitmapBounds[BorderRight];
|
||||
stretchRect.inset(0,1);
|
||||
dglDrawBitmapStretchSR(mTextureHandle, destRect, stretchRect);
|
||||
|
||||
dglDrawBitmapSR(mTextureHandle, offset + Point2I(0, mBounds.extent.y - mBitmapBounds[BorderBottomLeft].extent.y), mBitmapBounds[BorderBottomLeft]);
|
||||
dglDrawBitmapSR(mTextureHandle, offset + mBounds.extent - mBitmapBounds[BorderBottomRight].extent, mBitmapBounds[BorderBottomRight]);
|
||||
|
||||
destRect.point.x = offset.x + mBitmapBounds[BorderBottomLeft].extent.x;
|
||||
destRect.extent.x = mBounds.extent.x - mBitmapBounds[BorderBottomLeft].extent.x - mBitmapBounds[BorderBottomRight].extent.x;
|
||||
|
||||
destRect.point.y = offset.y + mBounds.extent.y - mBitmapBounds[BorderBottom].extent.y;
|
||||
destRect.extent.y = mBitmapBounds[BorderBottom].extent.y;
|
||||
stretchRect = mBitmapBounds[BorderBottom];
|
||||
stretchRect.inset(1,0);
|
||||
|
||||
dglDrawBitmapStretchSR(mTextureHandle, destRect, stretchRect);
|
||||
}
|
244
engine/gui/controls/guiBitmapButtonCtrl.cc
Executable file
244
engine/gui/controls/guiBitmapButtonCtrl.cc
Executable file
@ -0,0 +1,244 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// Torque Game Engine
|
||||
//
|
||||
// Copyright (c) 2001 GarageGames.Com
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
|
||||
//-------------------------------------
|
||||
//
|
||||
// Bitmap Button Contrl
|
||||
// Set 'bitmap' comsole field to base name of bitmaps to use. This control will
|
||||
// append '_n' for normal
|
||||
// append '_h' for hilighted
|
||||
// append '_d' for depressed
|
||||
//
|
||||
// if bitmap cannot be found it will use the default bitmap to render.
|
||||
//
|
||||
// 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 normal bitmap (if present)
|
||||
//
|
||||
|
||||
|
||||
#include "console/console.h"
|
||||
#include "dgl/dgl.h"
|
||||
#include "console/consoleTypes.h"
|
||||
#include "platform/platformAudio.h"
|
||||
#include "gui/core/guiCanvas.h"
|
||||
#include "gui/core/guiDefaultControlRender.h"
|
||||
#include "gui/controls/guiBitmapButtonCtrl.h"
|
||||
|
||||
IMPLEMENT_CONOBJECT(GuiBitmapButtonCtrl);
|
||||
|
||||
//-------------------------------------
|
||||
GuiBitmapButtonCtrl::GuiBitmapButtonCtrl()
|
||||
{
|
||||
mBitmapName = StringTable->insert("");
|
||||
mBounds.extent.set(140, 30);
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------
|
||||
void GuiBitmapButtonCtrl::initPersistFields()
|
||||
{
|
||||
Parent::initPersistFields();
|
||||
addField("bitmap", TypeFilename, Offset(mBitmapName, GuiBitmapButtonCtrl));
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------
|
||||
bool GuiBitmapButtonCtrl::onWake()
|
||||
{
|
||||
if (! Parent::onWake())
|
||||
return false;
|
||||
setActive(true);
|
||||
setBitmap(mBitmapName);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------
|
||||
void GuiBitmapButtonCtrl::onSleep()
|
||||
{
|
||||
mTextureNormal = NULL;
|
||||
mTextureHilight = NULL;
|
||||
mTextureDepressed = NULL;
|
||||
Parent::onSleep();
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------
|
||||
|
||||
ConsoleMethod( GuiBitmapButtonCtrl, setBitmap, void, 3, 3, "(filepath name)")
|
||||
{
|
||||
object->setBitmap(argv[2]);
|
||||
}
|
||||
|
||||
//-------------------------------------
|
||||
void GuiBitmapButtonCtrl::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 normal bitmap (if present)
|
||||
Parent::inspectPostApply();
|
||||
|
||||
if ((mBounds.extent.x == 0) && (mBounds.extent.y == 0) && mTextureNormal)
|
||||
{
|
||||
TextureObject *texture = (TextureObject *) mTextureNormal;
|
||||
mBounds.extent.x = texture->bitmapWidth;
|
||||
mBounds.extent.y = texture->bitmapHeight;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------
|
||||
void GuiBitmapButtonCtrl::setBitmap(const char *name)
|
||||
{
|
||||
mBitmapName = StringTable->insert(name);
|
||||
if(!isAwake())
|
||||
return;
|
||||
|
||||
if (*mBitmapName)
|
||||
{
|
||||
char buffer[1024];
|
||||
char *p;
|
||||
dStrcpy(buffer, name);
|
||||
p = buffer + dStrlen(buffer);
|
||||
|
||||
mTextureNormal = TextureHandle(buffer, BitmapTexture, true);
|
||||
if (!mTextureNormal)
|
||||
{
|
||||
dStrcpy(p, "_n");
|
||||
mTextureNormal = TextureHandle(buffer, BitmapTexture, true);
|
||||
}
|
||||
dStrcpy(p, "_h");
|
||||
mTextureHilight = TextureHandle(buffer, BitmapTexture, true);
|
||||
if (!mTextureHilight)
|
||||
mTextureHilight = mTextureNormal;
|
||||
dStrcpy(p, "_d");
|
||||
mTextureDepressed = TextureHandle(buffer, BitmapTexture, true);
|
||||
if (!mTextureDepressed)
|
||||
mTextureDepressed = mTextureHilight;
|
||||
dStrcpy(p, "_i");
|
||||
mTextureInactive = TextureHandle(buffer, BitmapTexture, true);
|
||||
if (!mTextureInactive)
|
||||
mTextureInactive = mTextureNormal;
|
||||
}
|
||||
else
|
||||
{
|
||||
mTextureNormal = NULL;
|
||||
mTextureHilight = NULL;
|
||||
mTextureDepressed = NULL;
|
||||
mTextureInactive = NULL;
|
||||
}
|
||||
setUpdate();
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------
|
||||
void GuiBitmapButtonCtrl::onRender(Point2I offset, const RectI& updateRect)
|
||||
{
|
||||
enum {
|
||||
NORMAL,
|
||||
HILIGHT,
|
||||
DEPRESSED,
|
||||
INACTIVE
|
||||
} state = NORMAL;
|
||||
|
||||
if (mActive)
|
||||
{
|
||||
if (mMouseOver) state = HILIGHT;
|
||||
if (mDepressed || mStateOn) state = DEPRESSED;
|
||||
}
|
||||
else
|
||||
state = INACTIVE;
|
||||
|
||||
switch (state)
|
||||
{
|
||||
case NORMAL: renderButton(mTextureNormal, offset, updateRect); break;
|
||||
case HILIGHT: renderButton(mTextureHilight ? mTextureHilight : mTextureNormal, offset, updateRect); break;
|
||||
case DEPRESSED: renderButton(mTextureDepressed, offset, updateRect); break;
|
||||
case INACTIVE: renderButton(mTextureInactive ? mTextureInactive : mTextureNormal, offset, updateRect); break;
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
void GuiBitmapButtonCtrl::renderButton(TextureHandle &texture, Point2I &offset, const RectI& updateRect)
|
||||
{
|
||||
if (texture)
|
||||
{
|
||||
RectI rect(offset, mBounds.extent);
|
||||
dglClearBitmapModulation();
|
||||
dglDrawBitmapStretch(texture, rect);
|
||||
renderChildControls( offset, updateRect);
|
||||
}
|
||||
else
|
||||
Parent::onRender(offset, updateRect);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
IMPLEMENT_CONOBJECT(GuiBitmapButtonTextCtrl);
|
||||
|
||||
void GuiBitmapButtonTextCtrl::onRender(Point2I offset, const RectI& updateRect)
|
||||
{
|
||||
enum {
|
||||
NORMAL,
|
||||
HILIGHT,
|
||||
DEPRESSED,
|
||||
INACTIVE
|
||||
} state = NORMAL;
|
||||
|
||||
if (mActive)
|
||||
{
|
||||
if (mMouseOver) state = HILIGHT;
|
||||
if (mDepressed || mStateOn) state = DEPRESSED;
|
||||
}
|
||||
else
|
||||
state = INACTIVE;
|
||||
|
||||
ColorI fontColor = mProfile->mFontColor;
|
||||
|
||||
TextureHandle texture;
|
||||
|
||||
switch (state)
|
||||
{
|
||||
case NORMAL:
|
||||
texture = mTextureNormal;
|
||||
fontColor = mProfile->mFontColor;
|
||||
break;
|
||||
case HILIGHT:
|
||||
texture = mTextureHilight;
|
||||
fontColor = mProfile->mFontColorHL;
|
||||
break;
|
||||
case DEPRESSED:
|
||||
texture = mTextureDepressed;
|
||||
fontColor = mProfile->mFontColorSEL;
|
||||
break;
|
||||
case INACTIVE:
|
||||
texture = mTextureInactive;
|
||||
fontColor = mProfile->mFontColorNA;
|
||||
if(!texture)
|
||||
texture = mTextureNormal;
|
||||
break;
|
||||
}
|
||||
if (texture)
|
||||
{
|
||||
RectI rect(offset, mBounds.extent);
|
||||
dglClearBitmapModulation();
|
||||
dglDrawBitmapStretch(texture, rect);
|
||||
|
||||
Point2I textPos = offset;
|
||||
if(mDepressed)
|
||||
textPos += Point2I(1,1);
|
||||
|
||||
// Make sure we take the profile's textOffset into account.
|
||||
textPos += mProfile->mTextOffset;
|
||||
|
||||
dglSetBitmapModulation( fontColor );
|
||||
renderJustifiedText(textPos, mBounds.extent, mButtonText);
|
||||
|
||||
renderChildControls( offset, updateRect);
|
||||
}
|
||||
else
|
||||
Parent::onRender(offset, updateRect);
|
||||
}
|
66
engine/gui/controls/guiBitmapButtonCtrl.h
Executable file
66
engine/gui/controls/guiBitmapButtonCtrl.h
Executable file
@ -0,0 +1,66 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// Torque Game Engine
|
||||
// Copyright (C) GarageGames.com, Inc.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef _GUIBITMAPBUTTON_H_
|
||||
#define _GUIBITMAPBUTTON_H_
|
||||
|
||||
#ifndef _GUIBUTTONCTRL_H_
|
||||
#include "gui/controls/guiButtonCtrl.h"
|
||||
#endif
|
||||
#ifndef _GTEXMANAGER_H_
|
||||
#include "dgl/gTexManager.h"
|
||||
#endif
|
||||
|
||||
///-------------------------------------
|
||||
/// Bitmap Button Contrl
|
||||
/// Set 'bitmap' comsole field to base name of bitmaps to use. This control will
|
||||
/// append '_n' for normal
|
||||
/// append '_h' for hilighted
|
||||
/// append '_d' for depressed
|
||||
///
|
||||
/// if bitmap cannot be found it will use the default bitmap to render.
|
||||
///
|
||||
/// if the extent is set to (0,0) in the gui editor and apply hit, this control will
|
||||
/// set it's extent to be exactly the size of the normal bitmap (if present)
|
||||
///
|
||||
class GuiBitmapButtonCtrl : public GuiButtonCtrl
|
||||
{
|
||||
private:
|
||||
typedef GuiButtonCtrl Parent;
|
||||
|
||||
protected:
|
||||
StringTableEntry mBitmapName;
|
||||
TextureHandle mTextureNormal;
|
||||
TextureHandle mTextureHilight;
|
||||
TextureHandle mTextureDepressed;
|
||||
TextureHandle mTextureInactive;
|
||||
|
||||
void renderButton(TextureHandle &texture, Point2I &offset, const RectI& updateRect);
|
||||
|
||||
public:
|
||||
DECLARE_CONOBJECT(GuiBitmapButtonCtrl);
|
||||
GuiBitmapButtonCtrl();
|
||||
|
||||
static void initPersistFields();
|
||||
|
||||
//Parent methods
|
||||
bool onWake();
|
||||
void onSleep();
|
||||
void inspectPostApply();
|
||||
|
||||
void setBitmap(const char *name);
|
||||
|
||||
void onRender(Point2I offset, const RectI &updateRect);
|
||||
};
|
||||
|
||||
class GuiBitmapButtonTextCtrl : public GuiBitmapButtonCtrl
|
||||
{
|
||||
typedef GuiBitmapButtonCtrl Parent;
|
||||
public:
|
||||
DECLARE_CONOBJECT(GuiBitmapButtonTextCtrl);
|
||||
void onRender(Point2I offset, const RectI &updateRect);
|
||||
};
|
||||
|
||||
#endif //_GUI_BITMAP_BUTTON_CTRL_H
|
178
engine/gui/controls/guiBitmapCtrl.cc
Executable file
178
engine/gui/controls/guiBitmapCtrl.cc
Executable file
@ -0,0 +1,178 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// Torque Game Engine
|
||||
// Copyright (C) GarageGames.com, Inc.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "console/console.h"
|
||||
#include "console/consoleTypes.h"
|
||||
#include "dgl/dgl.h"
|
||||
|
||||
#include "gui/controls/guiBitmapCtrl.h"
|
||||
|
||||
IMPLEMENT_CONOBJECT(GuiBitmapCtrl);
|
||||
|
||||
GuiBitmapCtrl::GuiBitmapCtrl(void)
|
||||
{
|
||||
mBitmapName = StringTable->insert("");
|
||||
startPoint.set(0, 0);
|
||||
mWrap = false;
|
||||
}
|
||||
|
||||
bool GuiBitmapCtrl::setBitmapName( void *obj, 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 *>( obj )->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()
|
||||
{
|
||||
Parent::initPersistFields();
|
||||
addGroup("Misc");
|
||||
addProtectedField( "bitmap", TypeFilename, Offset( mBitmapName, GuiBitmapCtrl ), &setBitmapName, &defaultProtectedGetFn, "" );
|
||||
//addField("bitmap", TypeFilename, Offset(mBitmapName, GuiBitmapCtrl));
|
||||
addField("wrap", TypeBool, Offset(mWrap, GuiBitmapCtrl));
|
||||
endGroup("Misc");
|
||||
}
|
||||
|
||||
ConsoleMethod( GuiBitmapCtrl, setValue, void, 4, 4, "(int xAxis, int yAxis)"
|
||||
"Set the offset of the bitmap.")
|
||||
{
|
||||
object->setValue(dAtoi(argv[2]), dAtoi(argv[3]));
|
||||
}
|
||||
|
||||
ConsoleMethod( GuiBitmapCtrl, setBitmap, void, 3, 3, "(string filename)"
|
||||
"Set the bitmap displayed in the control. Note that it is limited in size, to 256x256.")
|
||||
{
|
||||
object->setBitmap(argv[2]);
|
||||
}
|
||||
|
||||
bool GuiBitmapCtrl::onWake()
|
||||
{
|
||||
if (! Parent::onWake())
|
||||
return false;
|
||||
setActive(true);
|
||||
setBitmap(mBitmapName);
|
||||
return true;
|
||||
}
|
||||
|
||||
void GuiBitmapCtrl::onSleep()
|
||||
{
|
||||
mTextureHandle = 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 && (mBounds.extent.x == 0) && (mBounds.extent.y == 0) && mTextureHandle)
|
||||
{
|
||||
TextureObject *texture = (TextureObject *) mTextureHandle;
|
||||
mBounds.extent.x = texture->bitmapWidth;
|
||||
mBounds.extent.y = texture->bitmapHeight;
|
||||
}
|
||||
}
|
||||
|
||||
void GuiBitmapCtrl::setBitmap(const char *name, bool resize)
|
||||
{
|
||||
mBitmapName = StringTable->insert(name);
|
||||
if (*mBitmapName) {
|
||||
mTextureHandle = TextureHandle(mBitmapName, BitmapTexture, true);
|
||||
|
||||
// Resize the control to fit the bitmap
|
||||
if (resize) {
|
||||
TextureObject* texture = (TextureObject *) mTextureHandle;
|
||||
mBounds.extent.x = texture->bitmapWidth;
|
||||
mBounds.extent.y = texture->bitmapHeight;
|
||||
Point2I extent = getParent()->getExtent();
|
||||
parentResized(extent,extent);
|
||||
}
|
||||
}
|
||||
else
|
||||
mTextureHandle = NULL;
|
||||
setUpdate();
|
||||
}
|
||||
|
||||
|
||||
void GuiBitmapCtrl::setBitmap(const TextureHandle &handle, bool resize)
|
||||
{
|
||||
mTextureHandle = handle;
|
||||
|
||||
// Resize the control to fit the bitmap
|
||||
if (resize) {
|
||||
TextureObject* texture = (TextureObject *) mTextureHandle;
|
||||
mBounds.extent.x = texture->bitmapWidth;
|
||||
mBounds.extent.y = texture->bitmapHeight;
|
||||
Point2I extent = getParent()->getExtent();
|
||||
parentResized(extent,extent);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void GuiBitmapCtrl::onRender(Point2I offset, const RectI &updateRect)
|
||||
{
|
||||
if (mTextureHandle)
|
||||
{
|
||||
dglClearBitmapModulation();
|
||||
if(mWrap)
|
||||
{
|
||||
TextureObject* texture = (TextureObject *) mTextureHandle;
|
||||
RectI srcRegion;
|
||||
RectI dstRegion;
|
||||
float xdone = ((float)mBounds.extent.x/(float)texture->bitmapWidth)+1;
|
||||
float ydone = ((float)mBounds.extent.y/(float)texture->bitmapHeight)+1;
|
||||
|
||||
int xshift = startPoint.x%texture->bitmapWidth;
|
||||
int yshift = startPoint.y%texture->bitmapHeight;
|
||||
for(int y = 0; y < ydone; ++y)
|
||||
for(int x = 0; x < xdone; ++x)
|
||||
{
|
||||
srcRegion.set(0,0,texture->bitmapWidth,texture->bitmapHeight);
|
||||
dstRegion.set( ((texture->bitmapWidth*x)+offset.x)-xshift,
|
||||
((texture->bitmapHeight*y)+offset.y)-yshift,
|
||||
texture->bitmapWidth,
|
||||
texture->bitmapHeight);
|
||||
dglDrawBitmapStretchSR(texture,dstRegion, srcRegion, false);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
RectI rect(offset, mBounds.extent);
|
||||
dglDrawBitmapStretch(mTextureHandle, rect);
|
||||
}
|
||||
}
|
||||
|
||||
if (mProfile->mBorder || !mTextureHandle)
|
||||
{
|
||||
RectI rect(offset.x, offset.y, mBounds.extent.x, mBounds.extent.y);
|
||||
dglDrawRect(rect, mProfile->mBorderColor);
|
||||
}
|
||||
|
||||
renderChildControls(offset, updateRect);
|
||||
}
|
||||
|
||||
void GuiBitmapCtrl::setValue(S32 x, S32 y)
|
||||
{
|
||||
if (mTextureHandle)
|
||||
{
|
||||
TextureObject* texture = (TextureObject *) mTextureHandle;
|
||||
x+=texture->bitmapWidth/2;
|
||||
y+=texture->bitmapHeight/2;
|
||||
}
|
||||
while (x < 0)
|
||||
x += 256;
|
||||
startPoint.x = x % 256;
|
||||
|
||||
while (y < 0)
|
||||
y += 256;
|
||||
startPoint.y = y % 256;
|
||||
}
|
52
engine/gui/controls/guiBitmapCtrl.h
Executable file
52
engine/gui/controls/guiBitmapCtrl.h
Executable file
@ -0,0 +1,52 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// Torque Game Engine
|
||||
// Copyright (C) GarageGames.com, Inc.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef _GUIBITMAPCTRL_H_
|
||||
#define _GUIBITMAPCTRL_H_
|
||||
|
||||
#ifndef _GUICONTROL_H_
|
||||
#include "gui/core/guiControl.h"
|
||||
#endif
|
||||
#ifndef _GTEXMANAGER_H_
|
||||
#include "dgl/gTexManager.h"
|
||||
#endif
|
||||
|
||||
/// Renders a bitmap.
|
||||
class GuiBitmapCtrl : public GuiControl
|
||||
{
|
||||
private:
|
||||
typedef GuiControl Parent;
|
||||
|
||||
protected:
|
||||
static bool setBitmapName( void *obj, const char *data );
|
||||
static const char *getBitmapName( void *obj, const char *data );
|
||||
|
||||
StringTableEntry mBitmapName;
|
||||
TextureHandle mTextureHandle;
|
||||
Point2I startPoint;
|
||||
bool mWrap;
|
||||
|
||||
public:
|
||||
//creation methods
|
||||
DECLARE_CONOBJECT(GuiBitmapCtrl);
|
||||
GuiBitmapCtrl();
|
||||
static void initPersistFields();
|
||||
|
||||
//Parental methods
|
||||
bool onWake();
|
||||
void onSleep();
|
||||
void inspectPostApply();
|
||||
|
||||
void setBitmap(const char *name,bool resize = false);
|
||||
void setBitmap(const TextureHandle &handle,bool resize = false);
|
||||
|
||||
S32 getWidth() const { return(mTextureHandle.getWidth()); }
|
||||
S32 getHeight() const { return(mTextureHandle.getHeight()); }
|
||||
|
||||
void onRender(Point2I offset, const RectI &updateRect);
|
||||
void setValue(S32 x, S32 y);
|
||||
};
|
||||
|
||||
#endif
|
41
engine/gui/controls/guiBorderButton.cc
Executable file
41
engine/gui/controls/guiBorderButton.cc
Executable file
@ -0,0 +1,41 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// Torque Game Engine
|
||||
// Copyright (C) GarageGames.com, Inc.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "dgl/dgl.h"
|
||||
#include "gui/core/guiCanvas.h"
|
||||
#include "gui/controls/guiButtonBaseCtrl.h"
|
||||
|
||||
|
||||
class GuiBorderButtonCtrl : public GuiButtonBaseCtrl
|
||||
{
|
||||
typedef GuiButtonBaseCtrl Parent;
|
||||
|
||||
protected:
|
||||
public:
|
||||
DECLARE_CONOBJECT(GuiBorderButtonCtrl);
|
||||
|
||||
void onRender(Point2I offset, const RectI &updateRect);
|
||||
};
|
||||
|
||||
IMPLEMENT_CONOBJECT(GuiBorderButtonCtrl);
|
||||
|
||||
void GuiBorderButtonCtrl::onRender(Point2I offset, const RectI &updateRect)
|
||||
{
|
||||
RectI bounds(offset, mBounds.extent);
|
||||
if(mActive && mMouseOver)
|
||||
{
|
||||
bounds.inset(2,2);
|
||||
dglDrawRect(bounds, mProfile->mFontColorHL);
|
||||
bounds.inset(-2,-2);
|
||||
}
|
||||
if(mActive && (mStateOn || mDepressed))
|
||||
{
|
||||
dglDrawRect(bounds, mProfile->mFontColorHL);
|
||||
bounds.inset(1,1);
|
||||
dglDrawRect(bounds, mProfile->mFontColorHL);
|
||||
}
|
||||
renderChildControls(offset, updateRect);
|
||||
}
|
||||
|
351
engine/gui/controls/guiButtonBaseCtrl.cc
Executable file
351
engine/gui/controls/guiButtonBaseCtrl.cc
Executable file
@ -0,0 +1,351 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// Torque Engine
|
||||
//
|
||||
// Copyright (C) GarageGames.com, Inc.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "console/console.h"
|
||||
#include "dgl/dgl.h"
|
||||
#include "console/consoleTypes.h"
|
||||
#include "platform/platformAudio.h"
|
||||
#include "gui/core/guiCanvas.h"
|
||||
#include "gui/controls/guiButtonBaseCtrl.h"
|
||||
#include "i18n/lang.h"
|
||||
|
||||
IMPLEMENT_CONOBJECT(GuiButtonBaseCtrl);
|
||||
|
||||
GuiButtonBaseCtrl::GuiButtonBaseCtrl()
|
||||
{
|
||||
mDepressed = false;
|
||||
mMouseOver = false;
|
||||
mActive = true;
|
||||
mButtonText = StringTable->insert("Button");
|
||||
mButtonTextID = StringTable->insert("");
|
||||
mStateOn = false;
|
||||
mRadioGroup = -1;
|
||||
mButtonType = ButtonTypePush;
|
||||
}
|
||||
|
||||
bool GuiButtonBaseCtrl::onWake()
|
||||
{
|
||||
if(!Parent::onWake())
|
||||
return false;
|
||||
|
||||
// is we have a script variable, make sure we're in sync
|
||||
if ( mConsoleVariable[0] )
|
||||
mStateOn = Con::getBoolVariable( mConsoleVariable );
|
||||
if(mButtonTextID && *mButtonTextID != 0)
|
||||
setTextID(mButtonTextID);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
ConsoleMethod( GuiButtonBaseCtrl, performClick, void, 2, 2, "() - simulates a button click from script." )
|
||||
{
|
||||
argc; argv;
|
||||
object->onAction();
|
||||
}
|
||||
|
||||
ConsoleMethod( GuiButtonBaseCtrl, setText, void, 3, 3, "(string text) - sets the text of the button to the string." )
|
||||
{
|
||||
argc;
|
||||
object->setText( argv[2] );
|
||||
}
|
||||
|
||||
ConsoleMethod( GuiButtonBaseCtrl, setTextID, void, 3, 3, "(string id) - sets the text of the button to the localized string." )
|
||||
{
|
||||
argc;
|
||||
object->setTextID(argv[2]);
|
||||
}
|
||||
ConsoleMethod( GuiButtonBaseCtrl, getText, const char *, 2, 2, "() - returns the text of the button." )
|
||||
{
|
||||
argc; argv;
|
||||
return object->getText( );
|
||||
}
|
||||
ConsoleMethod( GuiButtonBaseCtrl, setStateOn, void, 3, 3, "(bool isStateOn) - sets the state on member and updates siblings of the same group." )
|
||||
{
|
||||
argc;
|
||||
object->setStateOn(dAtob(argv[2]));
|
||||
}
|
||||
|
||||
|
||||
static EnumTable::Enums buttonTypeEnums[] =
|
||||
{
|
||||
{ GuiButtonBaseCtrl::ButtonTypePush, "PushButton" },
|
||||
{ GuiButtonBaseCtrl::ButtonTypeCheck, "ToggleButton" },
|
||||
{ GuiButtonBaseCtrl::ButtonTypeRadio, "RadioButton" },
|
||||
};
|
||||
|
||||
static EnumTable gButtonTypeTable(3, &buttonTypeEnums[0]);
|
||||
|
||||
|
||||
|
||||
void GuiButtonBaseCtrl::initPersistFields()
|
||||
{
|
||||
Parent::initPersistFields();
|
||||
addGroup("Misc");
|
||||
addField("text", TypeCaseString, Offset(mButtonText, GuiButtonBaseCtrl));
|
||||
addField("textID", TypeString, Offset(mButtonTextID, GuiButtonBaseCtrl));
|
||||
addField("groupNum", TypeS32, Offset(mRadioGroup, GuiButtonBaseCtrl));
|
||||
addField("buttonType", TypeEnum, Offset(mButtonType, GuiButtonBaseCtrl), 1, &gButtonTypeTable);
|
||||
endGroup("Misc");
|
||||
}
|
||||
|
||||
void GuiButtonBaseCtrl::setText(const char *text)
|
||||
{
|
||||
mButtonText = StringTable->insert(text);
|
||||
}
|
||||
|
||||
void GuiButtonBaseCtrl::setStateOn( bool bStateOn )
|
||||
{
|
||||
if(!mActive)
|
||||
return;
|
||||
|
||||
if(mButtonType == ButtonTypeCheck)
|
||||
{
|
||||
mStateOn = bStateOn;
|
||||
}
|
||||
else if(mButtonType == ButtonTypeRadio)
|
||||
{
|
||||
messageSiblings(mRadioGroup);
|
||||
mStateOn = bStateOn;
|
||||
}
|
||||
setUpdate();
|
||||
}
|
||||
|
||||
void GuiButtonBaseCtrl::setTextID(const char *id)
|
||||
{
|
||||
S32 n = Con::getIntVariable(id, -1);
|
||||
if(n != -1)
|
||||
{
|
||||
mButtonTextID = StringTable->insert(id);
|
||||
setTextID(n);
|
||||
}
|
||||
}
|
||||
void GuiButtonBaseCtrl::setTextID(S32 id)
|
||||
{
|
||||
const UTF8 *str = getGUIString(id);
|
||||
if(str)
|
||||
setText((const char*)str);
|
||||
//mButtonTextID = id;
|
||||
}
|
||||
const char *GuiButtonBaseCtrl::getText()
|
||||
{
|
||||
return mButtonText;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
void GuiButtonBaseCtrl::acceleratorKeyPress(U32)
|
||||
{
|
||||
if (! mActive)
|
||||
return;
|
||||
|
||||
//set the bool
|
||||
mDepressed = true;
|
||||
|
||||
if (mProfile->mTabable)
|
||||
setFirstResponder();
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
void GuiButtonBaseCtrl::acceleratorKeyRelease(U32)
|
||||
{
|
||||
if (! mActive)
|
||||
return;
|
||||
|
||||
if (mDepressed)
|
||||
{
|
||||
//set the bool
|
||||
mDepressed = false;
|
||||
//perform the action
|
||||
onAction();
|
||||
}
|
||||
|
||||
//update
|
||||
setUpdate();
|
||||
}
|
||||
|
||||
void GuiButtonBaseCtrl::onMouseDown(const GuiEvent &event)
|
||||
{
|
||||
if (! mActive)
|
||||
return;
|
||||
|
||||
if (mProfile->mCanKeyFocus)
|
||||
setFirstResponder();
|
||||
|
||||
if (mProfile->mSoundButtonDown)
|
||||
{
|
||||
F32 pan = (F32(event.mousePoint.x)/F32(Canvas->mBounds.extent.x)*2.0f-1.0f)*0.8f;
|
||||
AUDIOHANDLE handle = alxCreateSource(mProfile->mSoundButtonDown);
|
||||
alxPlay(handle);
|
||||
}
|
||||
|
||||
//lock the mouse
|
||||
mouseLock();
|
||||
mDepressed = true;
|
||||
|
||||
//update
|
||||
setUpdate();
|
||||
}
|
||||
|
||||
void GuiButtonBaseCtrl::onMouseEnter(const GuiEvent &event)
|
||||
{
|
||||
setUpdate();
|
||||
if(isMouseLocked())
|
||||
{
|
||||
mDepressed = true;
|
||||
mMouseOver = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( mActive && mProfile->mSoundButtonOver )
|
||||
{
|
||||
F32 pan = (F32(event.mousePoint.x)/F32(Canvas->mBounds.extent.x)*2.0f-1.0f)*0.8f;
|
||||
AUDIOHANDLE handle = alxCreateSource(mProfile->mSoundButtonOver);
|
||||
alxPlay(handle);
|
||||
}
|
||||
mMouseOver = true;
|
||||
}
|
||||
}
|
||||
|
||||
void GuiButtonBaseCtrl::onMouseLeave(const GuiEvent &)
|
||||
{
|
||||
setUpdate();
|
||||
if(isMouseLocked())
|
||||
mDepressed = false;
|
||||
mMouseOver = false;
|
||||
}
|
||||
|
||||
void GuiButtonBaseCtrl::onMouseUp(const GuiEvent &event)
|
||||
{
|
||||
if (! mActive)
|
||||
return;
|
||||
|
||||
mouseUnlock();
|
||||
|
||||
setUpdate();
|
||||
|
||||
//if we released the mouse within this control, perform the action
|
||||
if (mDepressed)
|
||||
onAction();
|
||||
|
||||
mDepressed = false;
|
||||
}
|
||||
|
||||
void GuiButtonBaseCtrl::onRightMouseUp(const GuiEvent &event)
|
||||
{
|
||||
Con::executef( this, 2, "onRightClick" );
|
||||
|
||||
Parent::onRightMouseUp( event );
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
bool GuiButtonBaseCtrl::onKeyDown(const GuiEvent &event)
|
||||
{
|
||||
//if the control is a dead end, kill the event
|
||||
if (!mActive)
|
||||
return true;
|
||||
|
||||
//see if the key down is a return or space or not
|
||||
if ((event.keyCode == KEY_RETURN || event.keyCode == KEY_SPACE)
|
||||
&& event.modifier == 0)
|
||||
{
|
||||
if ( mProfile->mSoundButtonDown )
|
||||
{
|
||||
F32 pan = ( F32( event.mousePoint.x ) / F32( Canvas->mBounds.extent.x ) * 2.0f - 1.0f ) * 0.8f;
|
||||
AUDIOHANDLE handle = alxCreateSource( mProfile->mSoundButtonDown );
|
||||
alxPlay( handle );
|
||||
}
|
||||
return true;
|
||||
}
|
||||
//otherwise, pass the event to it's parent
|
||||
return Parent::onKeyDown(event);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
bool GuiButtonBaseCtrl::onKeyUp(const GuiEvent &event)
|
||||
{
|
||||
//if the control is a dead end, kill the event
|
||||
if (!mActive)
|
||||
return true;
|
||||
|
||||
//see if the key down is a return or space or not
|
||||
if (mDepressed &&
|
||||
(event.keyCode == KEY_RETURN || event.keyCode == KEY_SPACE) &&
|
||||
event.modifier == 0)
|
||||
{
|
||||
onAction();
|
||||
return true;
|
||||
}
|
||||
|
||||
//otherwise, pass the event to it's parent
|
||||
return Parent::onKeyUp(event);
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
void GuiButtonBaseCtrl::setScriptValue(const char *value)
|
||||
{
|
||||
mStateOn = dAtob(value);
|
||||
|
||||
// Update the console variable:
|
||||
if ( mConsoleVariable[0] )
|
||||
Con::setBoolVariable( mConsoleVariable, mStateOn );
|
||||
|
||||
setUpdate();
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
const char *GuiButtonBaseCtrl::getScriptValue()
|
||||
{
|
||||
return mStateOn ? "1" : "0";
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
void GuiButtonBaseCtrl::onAction()
|
||||
{
|
||||
if(!mActive)
|
||||
return;
|
||||
|
||||
if(mButtonType == ButtonTypeCheck)
|
||||
{
|
||||
mStateOn = mStateOn ? false : true;
|
||||
|
||||
// Update the console variable:
|
||||
if ( mConsoleVariable[0] )
|
||||
Con::setBoolVariable( mConsoleVariable, mStateOn );
|
||||
// Execute the console command (if any)
|
||||
if( mConsoleCommand[0] )
|
||||
{
|
||||
char buf[16];
|
||||
dSprintf(buf, sizeof(buf), "%d", getId());
|
||||
Con::setVariable("$ThisControl", buf);
|
||||
Con::evaluate( mConsoleCommand, false );
|
||||
}
|
||||
|
||||
}
|
||||
else if(mButtonType == ButtonTypeRadio)
|
||||
{
|
||||
mStateOn = true;
|
||||
messageSiblings(mRadioGroup);
|
||||
}
|
||||
setUpdate();
|
||||
|
||||
|
||||
// Provide and onClick script callback.
|
||||
if( isMethod("onClick") )
|
||||
Con::executef( this, 2, "onClick" );
|
||||
|
||||
Parent::onAction();
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
void GuiButtonBaseCtrl::onMessage( GuiControl *sender, S32 msg )
|
||||
{
|
||||
Parent::onMessage(sender, msg);
|
||||
if( mRadioGroup == msg && mButtonType == ButtonTypeRadio )
|
||||
{
|
||||
setUpdate();
|
||||
mStateOn = ( sender == this );
|
||||
}
|
||||
}
|
||||
|
71
engine/gui/controls/guiButtonBaseCtrl.h
Executable file
71
engine/gui/controls/guiButtonBaseCtrl.h
Executable file
@ -0,0 +1,71 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// Torque Engine
|
||||
//
|
||||
// Copyright (C) GarageGames.com, Inc.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef _GUIBUTTONBASECTRL_H_
|
||||
#define _GUIBUTTONBASECTRL_H_
|
||||
|
||||
#ifndef _GUICONTROL_H_
|
||||
#include "gui/core/guiControl.h"
|
||||
#endif
|
||||
|
||||
// all the button functionality is moving into buttonBase
|
||||
// thus, all subclasses will just be rendering classes,
|
||||
// and radios and check boxes can be done using pushbuttons
|
||||
// or bitmap buttons.
|
||||
|
||||
class GuiButtonBaseCtrl : public GuiControl
|
||||
{
|
||||
typedef GuiControl Parent;
|
||||
|
||||
protected:
|
||||
StringTableEntry mButtonText;
|
||||
StringTableEntry mButtonTextID;
|
||||
bool mDepressed;
|
||||
bool mMouseOver;
|
||||
bool mStateOn;
|
||||
S32 mButtonType;
|
||||
S32 mRadioGroup;
|
||||
public:
|
||||
enum {
|
||||
ButtonTypePush,
|
||||
ButtonTypeCheck,
|
||||
ButtonTypeRadio,
|
||||
};
|
||||
|
||||
GuiButtonBaseCtrl();
|
||||
bool onWake();
|
||||
|
||||
DECLARE_CONOBJECT(GuiButtonBaseCtrl);
|
||||
static void initPersistFields();
|
||||
|
||||
void setText(const char *text);
|
||||
void setTextID(S32 id);
|
||||
void setTextID(const char *id);
|
||||
const char *getText();
|
||||
void setStateOn( bool bStateOn );
|
||||
|
||||
void acceleratorKeyPress(U32 index);
|
||||
void acceleratorKeyRelease(U32 index);
|
||||
|
||||
void onMouseDown(const GuiEvent &);
|
||||
void onMouseUp(const GuiEvent &);
|
||||
void onRightMouseUp(const GuiEvent &);
|
||||
|
||||
void onMouseEnter(const GuiEvent &);
|
||||
void onMouseLeave(const GuiEvent &);
|
||||
|
||||
bool onKeyDown(const GuiEvent &event);
|
||||
bool onKeyUp(const GuiEvent &event);
|
||||
|
||||
void setScriptValue(const char *value);
|
||||
const char *getScriptValue();
|
||||
|
||||
void onMessage(GuiControl *,S32 msg);
|
||||
void onAction();
|
||||
|
||||
};
|
||||
|
||||
#endif
|
80
engine/gui/controls/guiButtonCtrl.cc
Executable file
80
engine/gui/controls/guiButtonCtrl.cc
Executable file
@ -0,0 +1,80 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// Torque Game Engine
|
||||
// Copyright (C) GarageGames.com, Inc.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "console/console.h"
|
||||
#include "dgl/dgl.h"
|
||||
#include "console/consoleTypes.h"
|
||||
#include "platform/platformAudio.h"
|
||||
#include "gui/core/guiCanvas.h"
|
||||
#include "gui/controls/guiButtonCtrl.h"
|
||||
#include "gui/core/guiDefaultControlRender.h"
|
||||
|
||||
IMPLEMENT_CONOBJECT(GuiButtonCtrl);
|
||||
|
||||
GuiButtonCtrl::GuiButtonCtrl()
|
||||
{
|
||||
mBounds.extent.set(140, 30);
|
||||
mButtonText = StringTable->insert("");
|
||||
}
|
||||
|
||||
bool GuiButtonCtrl::onWake()
|
||||
{
|
||||
if( !Parent::onWake() )
|
||||
return false;
|
||||
|
||||
// Button Theme?
|
||||
if( mProfile->constructBitmapArray() >= 36 )
|
||||
mHasTheme = true;
|
||||
else
|
||||
mHasTheme = false;
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
void GuiButtonCtrl::onRender(Point2I offset,
|
||||
const RectI& updateRect)
|
||||
{
|
||||
bool highlight = mMouseOver;
|
||||
bool depressed = mDepressed;
|
||||
|
||||
ColorI fontColor = mActive ? (highlight ? mProfile->mFontColorHL : mProfile->mFontColor) : mProfile->mFontColorNA;
|
||||
ColorI backColor = mActive ? mProfile->mFillColor : mProfile->mFillColorNA;
|
||||
ColorI borderColor = mActive ? mProfile->mBorderColor : mProfile->mBorderColorNA;
|
||||
|
||||
RectI boundsRect(offset, mBounds.extent);
|
||||
|
||||
if( mProfile->mBorder != 0 && !mHasTheme )
|
||||
{
|
||||
if (mDepressed || mStateOn)
|
||||
renderFilledBorder( boundsRect, mProfile->mBorderColorHL, mProfile->mFillColorHL );
|
||||
else
|
||||
renderFilledBorder( boundsRect, mProfile->mBorderColor, mProfile->mFillColor );
|
||||
}
|
||||
else if( mHasTheme )
|
||||
{
|
||||
S32 indexMultiplier = 1;
|
||||
if ( mMouseOver )
|
||||
indexMultiplier = 3;
|
||||
else if ( mDepressed || mStateOn )
|
||||
indexMultiplier = 2;
|
||||
else if ( !mActive )
|
||||
indexMultiplier = 4;
|
||||
|
||||
renderSizableBitmapBordersFilled( boundsRect, indexMultiplier, mProfile );
|
||||
}
|
||||
|
||||
Point2I textPos = offset;
|
||||
if(depressed)
|
||||
textPos += Point2I(1,1);
|
||||
|
||||
dglSetBitmapModulation( fontColor );
|
||||
renderJustifiedText(textPos, mBounds.extent, mButtonText);
|
||||
|
||||
//render the children
|
||||
renderChildControls( offset, updateRect);
|
||||
}
|
||||
|
25
engine/gui/controls/guiButtonCtrl.h
Executable file
25
engine/gui/controls/guiButtonCtrl.h
Executable file
@ -0,0 +1,25 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// Torque Game Engine
|
||||
// Copyright (C) GarageGames.com, Inc.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef _GUIBUTTONCTRL_H_
|
||||
#define _GUIBUTTONCTRL_H_
|
||||
|
||||
#ifndef _GUIBUTTONBASECTRL_H_
|
||||
#include "gui/controls/guiButtonBaseCtrl.h"
|
||||
#endif
|
||||
|
||||
class GuiButtonCtrl : public GuiButtonBaseCtrl
|
||||
{
|
||||
typedef GuiButtonBaseCtrl Parent;
|
||||
protected:
|
||||
bool mHasTheme;
|
||||
public:
|
||||
DECLARE_CONOBJECT(GuiButtonCtrl);
|
||||
GuiButtonCtrl();
|
||||
bool onWake();
|
||||
void onRender(Point2I offset, const RectI &updateRect);
|
||||
};
|
||||
|
||||
#endif //_GUI_BUTTON_CTRL_H
|
215
engine/gui/controls/guiCheckBoxCtrl.cc
Executable file
215
engine/gui/controls/guiCheckBoxCtrl.cc
Executable file
@ -0,0 +1,215 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// Torque Game Engine
|
||||
// Copyright (C) GarageGames.com, Inc.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "console/console.h"
|
||||
#include "dgl/dgl.h"
|
||||
#include "gui/core/guiCanvas.h"
|
||||
#include "gui/controls/guiCheckBoxCtrl.h"
|
||||
#include "console/consoleTypes.h"
|
||||
|
||||
IMPLEMENT_CONOBJECT(GuiCheckBoxCtrl);
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
GuiCheckBoxCtrl::GuiCheckBoxCtrl()
|
||||
{
|
||||
mBounds.extent.set(140, 30);
|
||||
mStateOn = false;
|
||||
mIndent = 0;
|
||||
mButtonType = ButtonTypeCheck;
|
||||
mUseInactiveState = false;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
void GuiCheckBoxCtrl::initPersistFields()
|
||||
{
|
||||
Parent::initPersistFields();
|
||||
|
||||
addField("useInactiveState", TypeBool, Offset(mUseInactiveState, GuiCheckBoxCtrl));
|
||||
}
|
||||
|
||||
bool GuiCheckBoxCtrl::onWake()
|
||||
{
|
||||
if(!Parent::onWake())
|
||||
return false;
|
||||
|
||||
// make sure there is a bitmap array for this control type
|
||||
// if it is declared as such in the control
|
||||
mProfile->constructBitmapArray();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void GuiCheckBoxCtrl::onMouseDown(const GuiEvent& event)
|
||||
{
|
||||
if (!mUseInactiveState)
|
||||
{
|
||||
Parent::onMouseDown(event);
|
||||
return;
|
||||
}
|
||||
|
||||
if (mProfile->mCanKeyFocus)
|
||||
setFirstResponder();
|
||||
|
||||
if (mProfile->mSoundButtonDown)
|
||||
{
|
||||
F32 pan = (F32(event.mousePoint.x)/F32(Canvas->mBounds.extent.x)*2.0f-1.0f)*0.8f;
|
||||
AUDIOHANDLE handle = alxCreateSource(mProfile->mSoundButtonDown);
|
||||
alxPlay(handle);
|
||||
}
|
||||
|
||||
//lock the mouse
|
||||
mouseLock();
|
||||
mDepressed = true;
|
||||
|
||||
//update
|
||||
setUpdate();
|
||||
}
|
||||
|
||||
void GuiCheckBoxCtrl::onMouseUp(const GuiEvent& event)
|
||||
{
|
||||
if (!mUseInactiveState)
|
||||
{
|
||||
Parent::onMouseUp(event);
|
||||
return;
|
||||
}
|
||||
|
||||
mouseUnlock();
|
||||
|
||||
setUpdate();
|
||||
|
||||
//if we released the mouse within this control, perform the action
|
||||
if (mDepressed)
|
||||
onAction();
|
||||
|
||||
mDepressed = false;
|
||||
}
|
||||
|
||||
void GuiCheckBoxCtrl::onAction()
|
||||
{
|
||||
if (!mUseInactiveState)
|
||||
{
|
||||
Parent::onAction();
|
||||
return;
|
||||
}
|
||||
|
||||
if(mButtonType == ButtonTypeCheck)
|
||||
{
|
||||
if (!mActive)
|
||||
{
|
||||
mActive = true;
|
||||
mStateOn = true;
|
||||
}
|
||||
else if (mStateOn)
|
||||
mStateOn = false;
|
||||
else if (!mStateOn)
|
||||
mActive = false;
|
||||
|
||||
// Update the console variable:
|
||||
if ( mConsoleVariable[0] )
|
||||
Con::setBoolVariable( mConsoleVariable, mStateOn );
|
||||
// Execute the console command (if any)
|
||||
if( mConsoleCommand[0] )
|
||||
{
|
||||
char buf[16];
|
||||
dSprintf(buf, sizeof(buf), "%d", getId());
|
||||
Con::setVariable("$ThisControl", buf);
|
||||
Con::evaluate( mConsoleCommand, false );
|
||||
}
|
||||
}
|
||||
setUpdate();
|
||||
|
||||
// Provide and onClick script callback.
|
||||
if( isMethod("onClick") )
|
||||
Con::executef( this, 2, "onClick" );
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
void GuiCheckBoxCtrl::onRender(Point2I offset, const RectI &updateRect)
|
||||
{
|
||||
ColorI backColor = mActive ? mProfile->mFillColor : mProfile->mFillColorNA;
|
||||
ColorI fontColor = mMouseOver ? mProfile->mFontColorHL : mProfile->mFontColor;
|
||||
ColorI insideBorderColor = isFirstResponder() ? mProfile->mBorderColorHL : mProfile->mBorderColor;
|
||||
|
||||
// just draw the check box and the text:
|
||||
S32 xOffset = 0;
|
||||
dglClearBitmapModulation();
|
||||
if(mProfile->mBitmapArrayRects.size() >= 4)
|
||||
{
|
||||
S32 index = mStateOn;
|
||||
if(!mActive)
|
||||
index = 2;
|
||||
else if(mDepressed)
|
||||
index += 2;
|
||||
xOffset = mProfile->mBitmapArrayRects[0].extent.x + 2 + mIndent;
|
||||
S32 y = (mBounds.extent.y - mProfile->mBitmapArrayRects[0].extent.y) / 2;
|
||||
dglDrawBitmapSR(mProfile->mTextureHandle, offset + Point2I(mIndent, y), mProfile->mBitmapArrayRects[index]);
|
||||
}
|
||||
|
||||
if(mButtonText[0] != NULL)
|
||||
{
|
||||
dglSetBitmapModulation( fontColor );
|
||||
renderJustifiedText(Point2I(offset.x + xOffset, offset.y),
|
||||
Point2I(mBounds.extent.x - mBounds.extent.y, mBounds.extent.y),
|
||||
mButtonText);
|
||||
}
|
||||
//render the children
|
||||
renderChildControls(offset, updateRect);
|
||||
}
|
||||
|
||||
ConsoleMethod(GuiCheckBoxCtrl, setStateOn, void, 3, 3, "(state)")
|
||||
{
|
||||
if (dStricmp(argv[2], "true") == 0)
|
||||
object->setStateOn(1);
|
||||
else if (dStricmp(argv[2], "false") == 0)
|
||||
object->setStateOn(0);
|
||||
else
|
||||
object->setStateOn(dAtoi(argv[2]));
|
||||
}
|
||||
|
||||
void GuiCheckBoxCtrl::setStateOn(S32 state)
|
||||
{
|
||||
if (mUseInactiveState)
|
||||
{
|
||||
if (state < 0)
|
||||
{
|
||||
setActive(false);
|
||||
Parent::setStateOn(false);
|
||||
}
|
||||
else if (state == 0)
|
||||
{
|
||||
setActive(true);
|
||||
Parent::setStateOn(false);
|
||||
}
|
||||
else if (state > 0)
|
||||
{
|
||||
setActive(true);
|
||||
Parent::setStateOn(true);
|
||||
}
|
||||
}
|
||||
else
|
||||
Parent::setStateOn((bool)state);
|
||||
}
|
||||
|
||||
const char* GuiCheckBoxCtrl::getScriptValue()
|
||||
{
|
||||
if (mUseInactiveState)
|
||||
{
|
||||
if (isActive())
|
||||
if (mStateOn)
|
||||
return "1";
|
||||
else
|
||||
return "0";
|
||||
else
|
||||
return "-1";
|
||||
}
|
||||
else
|
||||
return Parent::getScriptValue();
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
// EOF //
|
||||
|
||||
|
37
engine/gui/controls/guiCheckBoxCtrl.h
Executable file
37
engine/gui/controls/guiCheckBoxCtrl.h
Executable file
@ -0,0 +1,37 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// Torque Game Engine
|
||||
// Copyright (C) GarageGames.com, Inc.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef _GUICHECKBOXCTRL_H_
|
||||
#define _GUICHECKBOXCTRL_H_
|
||||
|
||||
#ifndef _GUIBUTTONBASECTRL_H_
|
||||
#include "gui/controls/guiButtonBaseCtrl.h"
|
||||
#endif
|
||||
|
||||
class GuiCheckBoxCtrl : public GuiButtonBaseCtrl
|
||||
{
|
||||
typedef GuiButtonBaseCtrl Parent;
|
||||
|
||||
bool mUseInactiveState;
|
||||
|
||||
protected:
|
||||
public:
|
||||
S32 mIndent;
|
||||
DECLARE_CONOBJECT(GuiCheckBoxCtrl);
|
||||
GuiCheckBoxCtrl();
|
||||
|
||||
void setStateOn(S32 state);
|
||||
virtual const char* getScriptValue();
|
||||
|
||||
virtual void onMouseDown(const GuiEvent& event);
|
||||
virtual void onMouseUp(const GuiEvent& event);
|
||||
virtual void onAction();
|
||||
void onRender(Point2I offset, const RectI &updateRect);
|
||||
bool onWake();
|
||||
|
||||
static void initPersistFields();
|
||||
};
|
||||
|
||||
#endif //_GUI_CHECKBOX_CTRL_H
|
464
engine/gui/controls/guiColorPicker.cc
Executable file
464
engine/gui/controls/guiColorPicker.cc
Executable file
@ -0,0 +1,464 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// Torque Game Engine
|
||||
// Copyright (C) GarageGames.com, Inc.
|
||||
//-----------------------------------------------------------------------------
|
||||
#include "console/console.h"
|
||||
#include "dgl/dgl.h"
|
||||
#include "console/consoleTypes.h"
|
||||
#include "platform/platformAudio.h"
|
||||
#include "gui/core/guiCanvas.h"
|
||||
#include "gui/controls/guiButtonCtrl.h"
|
||||
#include "gui/core/guiDefaultControlRender.h"
|
||||
#include "gui/controls/guiColorPicker.h"
|
||||
|
||||
/// @name Common colors we use
|
||||
/// @{
|
||||
ColorF colorWhite(1.,1.,1.);
|
||||
ColorF colorWhiteBlend(1.,1.,1.,.75);
|
||||
ColorF colorBlack(.0,.0,.0);
|
||||
ColorF colorAlpha(0.0f, 0.0f, 0.0f, 0.0f);
|
||||
|
||||
ColorI GuiColorPickerCtrl::mColorRange[9] = {
|
||||
ColorI(255,255,255), // White
|
||||
ColorI(255,255,255), // White
|
||||
ColorI(255,0,255), // Pink
|
||||
ColorI(0,0,255), // Blue
|
||||
ColorI(0,255,255), // Light blue
|
||||
ColorI(0,255,0), // Green
|
||||
ColorI(255,255,0), // Yellow
|
||||
ColorI(255,0,0), // Red
|
||||
ColorI(0,0,0) // Black
|
||||
};
|
||||
/// @}
|
||||
|
||||
IMPLEMENT_CONOBJECT(GuiColorPickerCtrl);
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
GuiColorPickerCtrl::GuiColorPickerCtrl()
|
||||
{
|
||||
mBounds.extent.set(140, 30);
|
||||
mDisplayMode = pPallet;
|
||||
mBaseColor = ColorF(1.,.0,1.);
|
||||
mPickColor = ColorF(.0,.0,.0);
|
||||
mSelectorPos = Point2I(0,0);
|
||||
mMouseDown = mMouseOver = false;
|
||||
mActive = true;
|
||||
mPositionChanged = false;
|
||||
mSelectorGap = 1;
|
||||
mActionOnMove = false;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
static EnumTable::Enums gColorPickerModeEnums[] =
|
||||
{
|
||||
{ GuiColorPickerCtrl::pPallet, "Pallet" },
|
||||
{ GuiColorPickerCtrl::pHorizColorRange, "HorizColor"},
|
||||
{ GuiColorPickerCtrl::pVertColorRange, "VertColor" },
|
||||
{ GuiColorPickerCtrl::pHorizColorBrightnessRange, "HorizBrightnessColor"},
|
||||
{ GuiColorPickerCtrl::pVertColorBrightnessRange, "VertBrightnessColor" },
|
||||
{ GuiColorPickerCtrl::pBlendColorRange, "BlendColor"},
|
||||
{ GuiColorPickerCtrl::pHorizAlphaRange, "HorizAlpha"},
|
||||
{ GuiColorPickerCtrl::pVertAlphaRange, "VertAlpha" },
|
||||
{ GuiColorPickerCtrl::pDropperBackground, "Dropper" },
|
||||
};
|
||||
|
||||
static EnumTable gColorPickerModeTable( 9, gColorPickerModeEnums );
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
void GuiColorPickerCtrl::initPersistFields()
|
||||
{
|
||||
Parent::initPersistFields();
|
||||
|
||||
addGroup("ColorPicker");
|
||||
addField("BaseColor", TypeColorF, Offset(mBaseColor, GuiColorPickerCtrl));
|
||||
addField("PickColor", TypeColorF, Offset(mPickColor, GuiColorPickerCtrl));
|
||||
addField("SelectorGap", TypeS32, Offset(mSelectorGap, GuiColorPickerCtrl));
|
||||
addField("DisplayMode", TypeEnum, Offset(mDisplayMode, GuiColorPickerCtrl), 1, &gColorPickerModeTable );
|
||||
addField("ActionOnMove", TypeBool,Offset(mActionOnMove, GuiColorPickerCtrl));
|
||||
endGroup("ColorPicker");
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Function to draw a box which can have 4 different colors in each corner blended together
|
||||
void dglDrawBlendBox(RectI &bounds, ColorF &c1, ColorF &c2, ColorF &c3, ColorF &c4)
|
||||
{
|
||||
S32 l = bounds.point.x, r = bounds.point.x + bounds.extent.x - 1;
|
||||
S32 t = bounds.point.y, b = bounds.point.y + bounds.extent.y - 1;
|
||||
|
||||
glEnable(GL_BLEND);
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
glDisable(GL_TEXTURE_2D);
|
||||
|
||||
glBegin(GL_QUADS);
|
||||
// Make sure the top row of pixels are the right color.
|
||||
glColor4f(c1.red, c1.green, c1.blue, c1.alpha);
|
||||
glVertex2f(l, t);
|
||||
glColor4f(c2.red, c2.green, c2.blue, c2.alpha);
|
||||
glVertex2f(r, t);
|
||||
glColor4f(c2.red, c2.green, c2.blue, c2.alpha);
|
||||
glVertex2f(r, t + 1);
|
||||
glColor4f(c1.red, c1.green, c1.blue, c1.alpha);
|
||||
glVertex2f(l, t + 1);
|
||||
|
||||
// The main blend box.
|
||||
glColor4f(c1.red, c1.green, c1.blue, c1.alpha);
|
||||
glVertex2f(l, t + 1);
|
||||
glColor4f(c2.red, c2.green, c2.blue, c2.alpha);
|
||||
glVertex2f(r, t + 1);
|
||||
glColor4f(c3.red, c3.green, c3.blue, c3.alpha);
|
||||
glVertex2f(r, b - 1);
|
||||
glColor4f(c4.red, c4.green, c4.blue, c4.alpha);
|
||||
glVertex2f(l, b - 1);
|
||||
|
||||
// Make sure the bottom row of pixels are the right color.
|
||||
glColor4f(c4.red, c4.green, c4.blue, c4.alpha);
|
||||
glVertex2f(l, b - 1);
|
||||
glColor4f(c3.red, c3.green, c3.blue, c3.alpha);
|
||||
glVertex2f(r, b - 1);
|
||||
glColor4f(c3.red, c3.green, c3.blue, c3.alpha);
|
||||
glVertex2f(r, b);
|
||||
glColor4f(c4.red, c4.green, c4.blue, c4.alpha);
|
||||
glVertex2f(l, b);
|
||||
glEnd();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
/// Function to draw a set of boxes blending throughout an array of colors
|
||||
void dglDrawBlendRangeBox(RectI &bounds, bool vertical, U8 numColors, ColorI *colors)
|
||||
{
|
||||
S32 l = bounds.point.x, r = bounds.point.x + bounds.extent.x - 1;
|
||||
S32 t = bounds.point.y, b = bounds.point.y + bounds.extent.y - 1;
|
||||
|
||||
// Calculate increment value
|
||||
S32 x_inc = int(mFloor((r - l) / (numColors-1)));
|
||||
S32 y_inc = int(mFloor((b - t) / (numColors-1)));
|
||||
|
||||
glEnable(GL_BLEND);
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
glDisable(GL_TEXTURE_2D);
|
||||
|
||||
glBegin(GL_QUADS);
|
||||
for (U16 i=0;i<numColors-1;i++)
|
||||
{
|
||||
// If we are at the end, x_inc and y_inc need to go to the end (otherwise there is a rendering bug)
|
||||
if (i == numColors-2)
|
||||
{
|
||||
x_inc += r-l-1;
|
||||
y_inc += b-t-1;
|
||||
}
|
||||
if (!vertical) // Horizontal (+x)
|
||||
{
|
||||
// First color
|
||||
glColor4ub(colors[i].red, colors[i].green, colors[i].blue, colors[i].alpha);
|
||||
glVertex2f(l, t);
|
||||
glVertex2f(l, b);
|
||||
// Second color
|
||||
glColor4ub(colors[i+1].red, colors[i+1].green, colors[i+1].blue, colors[i+1].alpha);
|
||||
glVertex2f(l+x_inc, b);
|
||||
glVertex2f(l+x_inc, t);
|
||||
l += x_inc;
|
||||
}
|
||||
else // Vertical (+y)
|
||||
{
|
||||
// First color
|
||||
glColor4ub(colors[i].red, colors[i].green, colors[i].blue, colors[i].alpha);
|
||||
glVertex2f(l, t);
|
||||
glVertex2f(r, t);
|
||||
// Second color
|
||||
glColor4ub(colors[i+1].red, colors[i+1].green, colors[i+1].blue, colors[i+1].alpha);
|
||||
glVertex2f(r, t+y_inc);
|
||||
glVertex2f(l, t+y_inc);
|
||||
t += y_inc;
|
||||
}
|
||||
}
|
||||
glEnd();
|
||||
}
|
||||
|
||||
void GuiColorPickerCtrl::drawSelector(RectI &bounds, Point2I &selectorPos, SelectorMode mode)
|
||||
{
|
||||
U16 sMax = mSelectorGap*2;
|
||||
switch (mode)
|
||||
{
|
||||
case sVertical:
|
||||
// Now draw the vertical selector
|
||||
// Up -> Pos
|
||||
if (selectorPos.y != bounds.point.y+1)
|
||||
dglDrawLine(selectorPos.x, bounds.point.y, selectorPos.x, selectorPos.y-sMax-1, colorWhiteBlend);
|
||||
// Down -> Pos
|
||||
if (selectorPos.y != bounds.point.y+bounds.extent.y)
|
||||
dglDrawLine(selectorPos.x, selectorPos.y + sMax, selectorPos.x, bounds.point.y + bounds.extent.y, colorWhiteBlend);
|
||||
break;
|
||||
case sHorizontal:
|
||||
// Now draw the horizontal selector
|
||||
// Left -> Pos
|
||||
if (selectorPos.x != bounds.point.x)
|
||||
dglDrawLine(bounds.point.x, selectorPos.y-1, selectorPos.x-sMax, selectorPos.y-1, colorWhiteBlend);
|
||||
// Right -> Pos
|
||||
if (selectorPos.x != bounds.point.x)
|
||||
dglDrawLine(bounds.point.x+mSelectorPos.x+sMax, selectorPos.y-1, bounds.point.x + bounds.extent.x, selectorPos.y-1, colorWhiteBlend);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
/// Function to invoke calls to draw the picker box and selector
|
||||
void GuiColorPickerCtrl::renderColorBox(RectI &bounds)
|
||||
{
|
||||
RectI pickerBounds;
|
||||
pickerBounds.point.x = bounds.point.x+1;
|
||||
pickerBounds.point.y = bounds.point.y+1;
|
||||
pickerBounds.extent.x = bounds.extent.x-1;
|
||||
pickerBounds.extent.y = bounds.extent.y-1;
|
||||
|
||||
if (mProfile->mBorder)
|
||||
dglDrawRect(bounds, mProfile->mBorderColor);
|
||||
|
||||
Point2I selectorPos = Point2I(bounds.point.x+mSelectorPos.x+1, bounds.point.y+mSelectorPos.y+1);
|
||||
|
||||
// Draw color box differently depending on mode
|
||||
RectI blendRect;
|
||||
switch (mDisplayMode)
|
||||
{
|
||||
case pHorizColorRange:
|
||||
dglDrawBlendRangeBox( pickerBounds, false, 7, mColorRange + 2);
|
||||
drawSelector( pickerBounds, selectorPos, sVertical );
|
||||
break;
|
||||
case pVertColorRange:
|
||||
dglDrawBlendRangeBox( pickerBounds, true, 7, mColorRange + 2);
|
||||
drawSelector( pickerBounds, selectorPos, sHorizontal );
|
||||
break;
|
||||
case pHorizColorBrightnessRange:
|
||||
blendRect = pickerBounds;
|
||||
blendRect.point.y++;
|
||||
blendRect.extent.y -= 2;
|
||||
dglDrawBlendRangeBox( pickerBounds, false, 9, mColorRange);
|
||||
// This is being drawn slightly offset from the larger rect so as to insure 255 and 0
|
||||
// can both be selected for every color.
|
||||
dglDrawBlendBox( blendRect, colorAlpha, colorAlpha, colorBlack, colorBlack );
|
||||
blendRect.point.y += blendRect.extent.y - 1;
|
||||
blendRect.extent.y = 2;
|
||||
dglDrawRect( blendRect, colorBlack);
|
||||
drawSelector( pickerBounds, selectorPos, sHorizontal );
|
||||
drawSelector( pickerBounds, selectorPos, sVertical );
|
||||
break;
|
||||
case pVertColorBrightnessRange:
|
||||
dglDrawBlendRangeBox( pickerBounds, true, 9, mColorRange);
|
||||
dglDrawBlendBox( pickerBounds, colorAlpha, colorBlack, colorBlack, colorAlpha );
|
||||
drawSelector( pickerBounds, selectorPos, sHorizontal );
|
||||
drawSelector( pickerBounds, selectorPos, sVertical );
|
||||
break;
|
||||
case pHorizAlphaRange:
|
||||
dglDrawBlendBox( pickerBounds, colorBlack, colorWhite, colorWhite, colorBlack );
|
||||
drawSelector( pickerBounds, selectorPos, sVertical );
|
||||
break;
|
||||
case pVertAlphaRange:
|
||||
dglDrawBlendBox( pickerBounds, colorBlack, colorBlack, colorWhite, colorWhite );
|
||||
drawSelector( pickerBounds, selectorPos, sHorizontal );
|
||||
break;
|
||||
case pBlendColorRange:
|
||||
dglDrawBlendBox( pickerBounds, colorWhite, mBaseColor, colorBlack, colorBlack );
|
||||
drawSelector( pickerBounds, selectorPos, sHorizontal );
|
||||
drawSelector( pickerBounds, selectorPos, sVertical );
|
||||
break;
|
||||
case pDropperBackground:
|
||||
break;
|
||||
case pPallet:
|
||||
default:
|
||||
dglDrawRectFill( pickerBounds, mBaseColor );
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void GuiColorPickerCtrl::onRender(Point2I offset, const RectI& updateRect)
|
||||
{
|
||||
RectI boundsRect(offset, mBounds.extent);
|
||||
renderColorBox(boundsRect);
|
||||
|
||||
if (mPositionChanged)
|
||||
{
|
||||
mPositionChanged = false;
|
||||
Point2I extent = Canvas->getExtent();
|
||||
// If we are anything but a pallete, change the pick color
|
||||
if (mDisplayMode != pPallet)
|
||||
{
|
||||
// To simplify things a bit, just read the color via glReadPixels()
|
||||
GLfloat rBuffer[4];
|
||||
glReadBuffer(GL_BACK);
|
||||
|
||||
U32 buf_x = offset.x+mSelectorPos.x+1;
|
||||
U32 buf_y = extent.y-(offset.y+mSelectorPos.y+1);
|
||||
glReadPixels(buf_x, buf_y, 1, 1, GL_RGBA, GL_FLOAT, rBuffer);
|
||||
|
||||
mPickColor.red = rBuffer[0];
|
||||
mPickColor.green = rBuffer[1];
|
||||
mPickColor.blue = rBuffer[2];
|
||||
mPickColor.alpha = rBuffer[3];
|
||||
|
||||
// Now do onAction() if we are allowed
|
||||
if (mActionOnMove)
|
||||
onAction();
|
||||
}
|
||||
}
|
||||
|
||||
//render the children
|
||||
renderChildControls( offset, updateRect);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
void GuiColorPickerCtrl::setSelectorPos(const Point2I &pos)
|
||||
{
|
||||
Point2I extent = mBounds.extent;
|
||||
RectI rect;
|
||||
if (mDisplayMode != pDropperBackground)
|
||||
{
|
||||
extent.x -= 3;
|
||||
extent.y -= 2;
|
||||
rect = RectI(Point2I(1,1), extent);
|
||||
}
|
||||
else
|
||||
{
|
||||
rect = RectI(Point2I(0,0), extent);
|
||||
}
|
||||
|
||||
if (rect.pointInRect(pos))
|
||||
{
|
||||
mSelectorPos = pos;
|
||||
mPositionChanged = true;
|
||||
// We now need to update
|
||||
setUpdate();
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
if ((pos.x > rect.point.x) && (pos.x < (rect.point.x + rect.extent.x)))
|
||||
mSelectorPos.x = pos.x;
|
||||
else if (pos.x <= rect.point.x)
|
||||
mSelectorPos.x = rect.point.x;
|
||||
else if (pos.x >= (rect.point.x + rect.extent.x))
|
||||
mSelectorPos.x = rect.point.x + rect.extent.x - 1;
|
||||
|
||||
if ((pos.y > rect.point.y) && (pos.y < (rect.point.y + rect.extent.y)))
|
||||
mSelectorPos.y = pos.y;
|
||||
else if (pos.y <= rect.point.y)
|
||||
mSelectorPos.y = rect.point.y;
|
||||
else if (pos.y >= (rect.point.y + rect.extent.y))
|
||||
mSelectorPos.y = rect.point.y + rect.extent.y - 1;
|
||||
|
||||
mPositionChanged = true;
|
||||
setUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
void GuiColorPickerCtrl::onMouseDown(const GuiEvent &event)
|
||||
{
|
||||
if (!mActive)
|
||||
return;
|
||||
|
||||
if (mDisplayMode == pDropperBackground)
|
||||
return;
|
||||
|
||||
mouseLock(this);
|
||||
|
||||
if (mProfile->mCanKeyFocus)
|
||||
setFirstResponder();
|
||||
|
||||
// Update the picker cross position
|
||||
if (mDisplayMode != pPallet)
|
||||
setSelectorPos(globalToLocalCoord(event.mousePoint));
|
||||
|
||||
mMouseDown = true;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
void GuiColorPickerCtrl::onMouseDragged(const GuiEvent &event)
|
||||
{
|
||||
if ((mActive && mMouseDown) || (mActive && (mDisplayMode == pDropperBackground)))
|
||||
{
|
||||
// Update the picker cross position
|
||||
if (mDisplayMode != pPallet)
|
||||
setSelectorPos(globalToLocalCoord(event.mousePoint));
|
||||
}
|
||||
|
||||
if (!mActionOnMove && mAltConsoleCommand[0] )
|
||||
Con::evaluate( mAltConsoleCommand, false );
|
||||
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
void GuiColorPickerCtrl::onMouseMove(const GuiEvent &event)
|
||||
{
|
||||
// Only for dropper mode
|
||||
if (mActive && (mDisplayMode == pDropperBackground))
|
||||
setSelectorPos(globalToLocalCoord(event.mousePoint));
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
void GuiColorPickerCtrl::onMouseEnter(const GuiEvent &event)
|
||||
{
|
||||
mMouseOver = true;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
void GuiColorPickerCtrl::onMouseLeave(const GuiEvent &)
|
||||
{
|
||||
// Reset state
|
||||
mMouseOver = false;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
void GuiColorPickerCtrl::onMouseUp(const GuiEvent &)
|
||||
{
|
||||
//if we released the mouse within this control, perform the action
|
||||
if (mActive && mMouseDown && (mDisplayMode != pDropperBackground))
|
||||
{
|
||||
onAction();
|
||||
mMouseDown = false;
|
||||
}
|
||||
else if (mActive && (mDisplayMode == pDropperBackground))
|
||||
{
|
||||
// In a dropper, the alt command executes the mouse up action (to signal stopping)
|
||||
if ( mAltConsoleCommand[0] )
|
||||
Con::evaluate( mAltConsoleCommand, false );
|
||||
}
|
||||
|
||||
mouseUnlock();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
const char *GuiColorPickerCtrl::getScriptValue()
|
||||
{
|
||||
static char temp[256];
|
||||
ColorF color = getValue();
|
||||
dSprintf(temp,256,"%f %f %f %f",color.red, color.green, color.blue, color.alpha);
|
||||
return temp;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
void GuiColorPickerCtrl::setScriptValue(const char *value)
|
||||
{
|
||||
ColorF newValue;
|
||||
dSscanf(value, "%f %f %f %f", &newValue.red, &newValue.green, &newValue.blue, &newValue.alpha);
|
||||
setValue(newValue);
|
||||
}
|
||||
|
||||
ConsoleMethod(GuiColorPickerCtrl, getSelectorPos, const char*, 2, 2, "Gets the current position of the selector")
|
||||
{
|
||||
char *temp = Con::getReturnBuffer(256);
|
||||
Point2I pos;
|
||||
pos = object->getSelectorPos();
|
||||
dSprintf(temp,256,"%d %d",pos.x, pos.y);
|
||||
return temp;
|
||||
}
|
||||
|
||||
ConsoleMethod(GuiColorPickerCtrl, setSelectorPos, void, 3, 3, "Sets the current position of the selector")
|
||||
{
|
||||
Point2I newPos;
|
||||
dSscanf(argv[2], "%d %d", &newPos.x, &newPos.y);
|
||||
object->setSelectorPos(newPos);
|
||||
}
|
||||
|
||||
ConsoleMethod(GuiColorPickerCtrl, updateColor, void, 2, 2, "Forces update of pick color")
|
||||
{
|
||||
object->updateColor();
|
||||
}
|
123
engine/gui/controls/guiColorPicker.h
Executable file
123
engine/gui/controls/guiColorPicker.h
Executable file
@ -0,0 +1,123 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// Torque Game Engine
|
||||
// Copyright (C) GarageGames.com, Inc.
|
||||
//-----------------------------------------------------------------------------
|
||||
#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
|
||||
/// @}
|
||||
|
||||
/// @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.
|
||||
|
||||
static ColorI mColorRange[9]; ///< Color range for pHorizColorRange and pVertColorRange
|
||||
/// @}
|
||||
|
||||
public:
|
||||
DECLARE_CONOBJECT(GuiColorPickerCtrl);
|
||||
GuiColorPickerCtrl();
|
||||
|
||||
static void initPersistFields();
|
||||
void onRender(Point2I offset, const RectI &updateRect);
|
||||
|
||||
/// @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 &);
|
||||
/// @}
|
||||
};
|
||||
|
||||
#endif
|
106
engine/gui/controls/guiConsole.cc
Executable file
106
engine/gui/controls/guiConsole.cc
Executable file
@ -0,0 +1,106 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// Torque Game Engine
|
||||
// Copyright (C) GarageGames.com, Inc.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "console/console.h"
|
||||
#include "dgl/dgl.h"
|
||||
#include "gui/core/guiTypes.h"
|
||||
#include "gui/core/guiControl.h"
|
||||
#include "gui/controls/guiConsole.h"
|
||||
#include "gui/containers/guiScrollCtrl.h"
|
||||
|
||||
IMPLEMENT_CONOBJECT(GuiConsole);
|
||||
|
||||
GuiConsole::GuiConsole()
|
||||
{
|
||||
mBounds.extent.set(1, 1);
|
||||
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 = mBounds.extent.y / 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
|
||||
resize(mBounds.point, 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: dglSetBitmapModulation(mProfile->mFontColor); break;
|
||||
case ConsoleLogEntry::Warning: dglSetBitmapModulation(mProfile->mFontColorHL); break;
|
||||
case ConsoleLogEntry::Error: dglSetBitmapModulation(mProfile->mFontColorNA); break;
|
||||
}
|
||||
dglDrawText(mFont, Point2I(offset.x + 3, offset.y), entry.mString, mProfile->mFontColors);
|
||||
|
||||
Con::unlockLog();
|
||||
}
|
32
engine/gui/controls/guiConsole.h
Executable file
32
engine/gui/controls/guiConsole.h
Executable file
@ -0,0 +1,32 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// Torque Game Engine
|
||||
// Copyright (C) GarageGames.com, Inc.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef _GUICONSOLE_H_
|
||||
#define _GUICONSOLE_H_
|
||||
|
||||
#ifndef _GUIARRAYCTRL_H_
|
||||
#include "gui/core/guiArrayCtrl.h"
|
||||
#endif
|
||||
|
||||
class GuiConsole : public GuiArrayCtrl
|
||||
{
|
||||
private:
|
||||
typedef GuiArrayCtrl Parent;
|
||||
|
||||
Resource<GFont> mFont;
|
||||
|
||||
S32 getMaxWidth(S32 startIndex, S32 endIndex);
|
||||
|
||||
public:
|
||||
GuiConsole();
|
||||
DECLARE_CONOBJECT(GuiConsole);
|
||||
|
||||
bool onWake();
|
||||
|
||||
void onPreRender();
|
||||
void onRenderCell(Point2I offset, Point2I cell, bool selected, bool mouseOver);
|
||||
};
|
||||
|
||||
#endif
|
84
engine/gui/controls/guiConsoleEditCtrl.cc
Executable file
84
engine/gui/controls/guiConsoleEditCtrl.cc
Executable file
@ -0,0 +1,84 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// Torque Game Engine
|
||||
// Copyright (C) GarageGames.com, Inc.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "console/consoleTypes.h"
|
||||
#include "console/console.h"
|
||||
#include "dgl/dgl.h"
|
||||
#include "gui/core/guiCanvas.h"
|
||||
#include "gui/controls/guiConsoleEditCtrl.h"
|
||||
#include "core/frameAllocator.h"
|
||||
|
||||
IMPLEMENT_CONOBJECT(GuiConsoleEditCtrl);
|
||||
|
||||
GuiConsoleEditCtrl::GuiConsoleEditCtrl()
|
||||
{
|
||||
mSinkAllKeyEvents = true;
|
||||
mSiblingScroller = NULL;
|
||||
mUseSiblingScroller = true;
|
||||
}
|
||||
|
||||
void GuiConsoleEditCtrl::initPersistFields()
|
||||
{
|
||||
Parent::initPersistFields();
|
||||
|
||||
addGroup("Misc");
|
||||
addField("useSiblingScroller", TypeBool, Offset(mUseSiblingScroller, GuiConsoleEditCtrl));
|
||||
endGroup("Misc");
|
||||
}
|
||||
|
||||
bool GuiConsoleEditCtrl::onKeyDown(const GuiEvent &event)
|
||||
{
|
||||
S32 stringLen = dStrlen(mText);
|
||||
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;
|
||||
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)
|
||||
{
|
||||
if (mSiblingScroller = dynamic_cast<GuiScrollCtrl*>(*itr))
|
||||
{
|
||||
return mSiblingScroller->onKeyDown(event);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// No luck... so don't try, next time.
|
||||
mUseSiblingScroller = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return Parent::onKeyDown(event);
|
||||
}
|
||||
|
37
engine/gui/controls/guiConsoleEditCtrl.h
Executable file
37
engine/gui/controls/guiConsoleEditCtrl.h
Executable file
@ -0,0 +1,37 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// Torque Game Engine
|
||||
// Copyright (C) GarageGames.com, Inc.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#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);
|
||||
|
||||
static void initPersistFields();
|
||||
|
||||
bool onKeyDown(const GuiEvent &event);
|
||||
};
|
||||
|
||||
#endif //_GUI_TEXTEDIT_CTRL_H
|
158
engine/gui/controls/guiConsoleTextCtrl.cc
Executable file
158
engine/gui/controls/guiConsoleTextCtrl.cc
Executable file
@ -0,0 +1,158 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// Torque Game Engine
|
||||
// Copyright (C) GarageGames.com, Inc.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "console/consoleTypes.h"
|
||||
#include "console/console.h"
|
||||
#include "core/color.h"
|
||||
#include "gui/controls/guiConsoleTextCtrl.h"
|
||||
#include "dgl/dgl.h"
|
||||
|
||||
IMPLEMENT_CONOBJECT(GuiConsoleTextCtrl);
|
||||
|
||||
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- //
|
||||
|
||||
GuiConsoleTextCtrl::GuiConsoleTextCtrl()
|
||||
{
|
||||
//default fonts
|
||||
mConsoleExpression = NULL;
|
||||
mResult = NULL;
|
||||
}
|
||||
|
||||
void GuiConsoleTextCtrl::initPersistFields()
|
||||
{
|
||||
Parent::initPersistFields();
|
||||
addGroup("Misc");
|
||||
addField("expression", TypeCaseString, Offset(mConsoleExpression, GuiConsoleTextCtrl));
|
||||
endGroup("Misc");
|
||||
}
|
||||
|
||||
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- //
|
||||
|
||||
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 = StringTable->insert(txt);
|
||||
else
|
||||
mConsoleExpression = NULL;
|
||||
|
||||
//Make sure we have a font
|
||||
mProfile->incRefCount();
|
||||
mFont = mProfile->mFont;
|
||||
|
||||
setUpdate();
|
||||
|
||||
//decrement the profile referrence
|
||||
mProfile->decRefCount();
|
||||
}
|
||||
|
||||
void GuiConsoleTextCtrl::calcResize()
|
||||
{
|
||||
if (!mResult)
|
||||
return;
|
||||
|
||||
//resize
|
||||
if (mProfile->mAutoSizeWidth)
|
||||
{
|
||||
if (mProfile->mAutoSizeHeight)
|
||||
resize(mBounds.point, Point2I(mFont->getStrWidth((const UTF8 *)mResult) + 4, mFont->getHeight() + 4));
|
||||
else
|
||||
resize(mBounds.point, Point2I(mFont->getStrWidth((const UTF8 *)mResult) + 4, mBounds.extent.y));
|
||||
}
|
||||
else if (mProfile->mAutoSizeHeight)
|
||||
{
|
||||
resize(mBounds.point, Point2I(mBounds.extent.x, mFont->getHeight() + 4));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void GuiConsoleTextCtrl::onPreRender()
|
||||
{
|
||||
if (mConsoleExpression)
|
||||
mResult = Con::evaluatef("$temp = %s;", mConsoleExpression);
|
||||
calcResize();
|
||||
}
|
||||
|
||||
|
||||
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- //
|
||||
|
||||
void GuiConsoleTextCtrl::onRender(Point2I offset, const RectI &updateRect)
|
||||
{
|
||||
// draw the background rectangle
|
||||
RectI r(offset, mBounds.extent);
|
||||
dglDrawRectFill(r, ColorI(255,255,255));
|
||||
|
||||
// draw the border
|
||||
r.extent += r.point;
|
||||
glColor4ub(0, 0, 0, 0);
|
||||
glBegin(GL_LINE_LOOP);
|
||||
glVertex2i(r.point.x, r.point.y);
|
||||
glVertex2i(r.extent.x-1, r.point.y);
|
||||
glVertex2i(r.extent.x-1, r.extent.y-1);
|
||||
glVertex2i(r.point.x, r.extent.y-1);
|
||||
glEnd();
|
||||
|
||||
if (mResult)
|
||||
{
|
||||
S32 txt_w = mFont->getStrWidth((const UTF8 *)mResult);
|
||||
Point2I localStart;
|
||||
switch (mProfile->mAlignment)
|
||||
{
|
||||
case GuiControlProfile::RightJustify:
|
||||
localStart.set(mBounds.extent.x - txt_w-2, 0);
|
||||
break;
|
||||
case GuiControlProfile::CenterJustify:
|
||||
localStart.set((mBounds.extent.x - txt_w) / 2, 0);
|
||||
break;
|
||||
default:
|
||||
// GuiControlProfile::LeftJustify
|
||||
localStart.set(2,0);
|
||||
break;
|
||||
}
|
||||
|
||||
Point2I globalStart = localToGlobalCoord(localStart);
|
||||
|
||||
//draw the text
|
||||
dglSetBitmapModulation(mProfile->mFontColor);
|
||||
dglDrawText(mFont, globalStart, mResult, mProfile->mFontColors);
|
||||
}
|
||||
|
||||
//render the child controls
|
||||
renderChildControls(offset, updateRect);
|
||||
}
|
||||
|
||||
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- //
|
||||
|
||||
const char *GuiConsoleTextCtrl::getScriptValue()
|
||||
{
|
||||
return getText();
|
||||
}
|
||||
|
||||
void GuiConsoleTextCtrl::setScriptValue(const char *val)
|
||||
{
|
||||
setText(val);
|
||||
}
|
||||
|
||||
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- //
|
||||
// EOF //
|
58
engine/gui/controls/guiConsoleTextCtrl.h
Executable file
58
engine/gui/controls/guiConsoleTextCtrl.h
Executable file
@ -0,0 +1,58 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// Torque Game Engine
|
||||
// Copyright (C) GarageGames.com, Inc.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef _GUICONSOLETEXTCTRL_H_
|
||||
#define _GUICONSOLETEXTCTRL_H_
|
||||
|
||||
#ifndef _GFONT_H_
|
||||
#include "dgl/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:
|
||||
const char *mConsoleExpression;
|
||||
const char *mResult;
|
||||
Resource<GFont> mFont;
|
||||
|
||||
public:
|
||||
|
||||
//creation methods
|
||||
DECLARE_CONOBJECT(GuiConsoleTextCtrl);
|
||||
GuiConsoleTextCtrl();
|
||||
static void initPersistFields();
|
||||
|
||||
//Parental methods
|
||||
bool onWake();
|
||||
void onSleep();
|
||||
|
||||
//text methods
|
||||
virtual void setText(const char *txt = NULL);
|
||||
const char *getText() { return mConsoleExpression; }
|
||||
|
||||
//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_
|
175
engine/gui/controls/guiDirectoryFileListCtrl.cc
Executable file
175
engine/gui/controls/guiDirectoryFileListCtrl.cc
Executable file
@ -0,0 +1,175 @@
|
||||
#include "core/findMatch.h"
|
||||
#include "gui/controls/guiDirectoryFileListCtrl.h"
|
||||
|
||||
|
||||
IMPLEMENT_CONOBJECT( GuiDirectoryFileListCtrl );
|
||||
|
||||
GuiDirectoryFileListCtrl::GuiDirectoryFileListCtrl()
|
||||
{
|
||||
}
|
||||
|
||||
bool GuiDirectoryFileListCtrl::onWake()
|
||||
{
|
||||
if( !Parent::onWake() )
|
||||
return false;
|
||||
|
||||
setCurrentPath( "/", "*.*" );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void GuiDirectoryFileListCtrl::onMouseDown(const GuiEvent &event)
|
||||
{
|
||||
Parent::onMouseDown( event );
|
||||
|
||||
if( event.mouseClickCount == 2 && isMethod("onDoubleClick") )
|
||||
Con::executef(this, 1, "onDoubleClick");
|
||||
|
||||
}
|
||||
|
||||
|
||||
void GuiDirectoryFileListCtrl::openDirectory()
|
||||
{
|
||||
Vector<Platform::FileInfo> fileVector;
|
||||
Platform::dumpPath( mFilePath, 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( FindMatch::isMatchMultipleExprs( mFilter, (*i).pFileName,false ) )
|
||||
addItem( (*i).pFileName );
|
||||
}
|
||||
|
||||
//Done!
|
||||
}
|
||||
|
||||
|
||||
void GuiDirectoryFileListCtrl::setCurrentFilter( const char* filter )
|
||||
{
|
||||
if( ! filter )
|
||||
return;
|
||||
|
||||
mFilter = StringTable->insert( filter );
|
||||
|
||||
// Update our view
|
||||
openDirectory();
|
||||
|
||||
}
|
||||
|
||||
ConsoleMethod( GuiDirectoryFileListCtrl, setFilter, void, 3, 3, "%obj.setFilter([mask space delimited])")
|
||||
{
|
||||
object->setCurrentFilter( argv[2] );
|
||||
}
|
||||
|
||||
bool GuiDirectoryFileListCtrl::setCurrentPath( const char* path, const char* filter )
|
||||
{
|
||||
// Oops, gotta give us a path to work with
|
||||
if( !path )
|
||||
return false;
|
||||
|
||||
char ExpandedPath[512];
|
||||
char FullPath[512];
|
||||
dMemset( ExpandedPath, 0, 512 );
|
||||
dMemset( FullPath, 0, 512 );
|
||||
|
||||
Con::expandScriptFilename( ExpandedPath, 512, path );
|
||||
|
||||
if( ExpandedPath[0] != '/' )
|
||||
dSprintf( FullPath, 512, "%s/%s", Platform::getWorkingDirectory(), ExpandedPath );
|
||||
else
|
||||
dSprintf( FullPath, 512, "%s%s", Platform::getWorkingDirectory(), ExpandedPath );
|
||||
|
||||
// Platform::isDirectory expects no trailing / so make sure we conform
|
||||
if( FullPath[ dStrlen( FullPath ) - 1 ] == '/' )
|
||||
FullPath[ dStrlen( FullPath ) - 1 ] = 0x00;
|
||||
|
||||
// A bad path!? For shame...
|
||||
if( !Platform::isDirectory( FullPath ) && !Platform::hasSubDirectory( FullPath ) )
|
||||
return false;
|
||||
|
||||
// Store our new info
|
||||
mFilePath = StringTable->insert( FullPath );
|
||||
|
||||
if( filter && dStricmp( filter, "" ) )
|
||||
mFilter = StringTable->insert( filter );
|
||||
|
||||
// Update our view
|
||||
openDirectory();
|
||||
|
||||
// Peace out!
|
||||
return true;
|
||||
}
|
||||
|
||||
ConsoleMethod( GuiDirectoryFileListCtrl, setPath, bool, 3, 4, "setPath(path,filter) - directory to enumerate files from (without trailing slash)" )
|
||||
{
|
||||
return object->setCurrentPath( argv[2], argv[3] );
|
||||
}
|
||||
|
||||
|
||||
ConsoleMethod( GuiDirectoryFileListCtrl, getSelectedFiles, const char*, 2, 2, "getSelectedFiles () - returns a word separated list of selected file(s)" )
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
ConsoleMethod( GuiDirectoryFileListCtrl, getSelectedFile, const char*, 2, 2, "getSelectedFile () - returns the currently selected file name" )
|
||||
{
|
||||
return object->getSelectedFileName();
|
||||
}
|
||||
|
40
engine/gui/controls/guiDirectoryFileListCtrl.h
Executable file
40
engine/gui/controls/guiDirectoryFileListCtrl.h
Executable file
@ -0,0 +1,40 @@
|
||||
#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();
|
||||
public:
|
||||
GuiDirectoryFileListCtrl();
|
||||
DECLARE_CONOBJECT(GuiDirectoryFileListCtrl);
|
||||
|
||||
/// 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);
|
||||
|
||||
|
||||
bool onWake();
|
||||
};
|
||||
|
||||
|
||||
#endif
|
382
engine/gui/controls/guiDirectoryTreeCtrl.cc
Executable file
382
engine/gui/controls/guiDirectoryTreeCtrl.cc
Executable file
@ -0,0 +1,382 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// Torque Game Engine
|
||||
// Copyright (C) GarageGames.com, Inc.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "gui/controls/guiDirectoryTreeCtrl.h"
|
||||
|
||||
IMPLEMENT_CONOBJECT(GuiDirectoryTreeCtrl);
|
||||
|
||||
GuiDirectoryTreeCtrl::GuiDirectoryTreeCtrl(): GuiTreeViewCtrl()
|
||||
{
|
||||
// Parent configuration
|
||||
mBounds.set( 0,0,200,100 );
|
||||
mDestroyOnSleep = false;
|
||||
mSupportMouseDragging = false;
|
||||
mMultipleSelections = false;
|
||||
|
||||
mSelPath = StringTable->insert("");
|
||||
}
|
||||
|
||||
bool GuiDirectoryTreeCtrl::onAdd()
|
||||
{
|
||||
if( !Parent::onAdd() )
|
||||
return false;
|
||||
|
||||
// Specify our icons
|
||||
buildIconTable( NULL );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool GuiDirectoryTreeCtrl::onWake()
|
||||
{
|
||||
if( !Parent::onWake() )
|
||||
return false;
|
||||
|
||||
// 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.
|
||||
|
||||
ResourceManager->initExcludedDirectories();
|
||||
|
||||
StringTableEntry RootPath = ResourceManager->getModPaths();
|
||||
//getUnit(argv[1], dAtoi(argv[2]), " \t\n");
|
||||
S32 modCount = getUnitCount( RootPath, ";" );
|
||||
for( S32 i = 0; i < modCount; i++ )
|
||||
{
|
||||
// Compose full mod path location, and dump the path to our vector
|
||||
StringTableEntry currentMod = getUnit( RootPath, i, ";" );
|
||||
char fullModPath [512];
|
||||
dMemset( fullModPath, 0, 512 );
|
||||
dSprintf( fullModPath, 512, "%s/%s/", Platform::getWorkingDirectory(), currentMod );
|
||||
|
||||
Vector<StringTableEntry> pathVec;
|
||||
Platform::dumpDirectories( fullModPath, pathVec, 0, true);
|
||||
if( ! pathVec.empty() )
|
||||
{
|
||||
// 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", currentMod, (*j) );
|
||||
addPathToTree( fullModPathSub );
|
||||
}
|
||||
}
|
||||
else
|
||||
addPathToTree( fullModPath );
|
||||
}
|
||||
|
||||
// Success!
|
||||
return true;
|
||||
}
|
||||
|
||||
bool GuiDirectoryTreeCtrl::onVirtualParentExpand(Item *item)
|
||||
{
|
||||
if( !item || !item->isExpanded() )
|
||||
return true;
|
||||
|
||||
StringTableEntry pathToExpand = item->getValue();
|
||||
|
||||
if( !pathToExpand )
|
||||
{
|
||||
Con::errorf("GuiDirectoryTreeCtrl::onVirtualParentExpand - Unable to retrieve item value!");
|
||||
return false;
|
||||
}
|
||||
|
||||
Vector<StringTableEntry> pathVec;
|
||||
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;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool GuiDirectoryTreeCtrl::buildIconTable(const char * icons)
|
||||
{
|
||||
// Icons should be designated by the bitmap/png file names (minus the file extensions)
|
||||
// and separated by colons (:).
|
||||
if (!icons)
|
||||
icons = StringTable->insert("common/ui/folder:common/ui/folder:common/ui/folder_closed");
|
||||
|
||||
return Parent::buildIconTable( icons );
|
||||
}
|
||||
|
||||
void GuiDirectoryTreeCtrl::addPathToTree( StringTableEntry path )
|
||||
{
|
||||
if( !path )
|
||||
{
|
||||
Con::errorf("GuiDirectoryTreeCtrl::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 = getUnit( path, 0, "//" );
|
||||
// There are no current roots, we can safely create one
|
||||
if( root == 0 )
|
||||
{
|
||||
recurseInsert( NULL, path );
|
||||
}
|
||||
else
|
||||
{
|
||||
while( root != 0 )
|
||||
{
|
||||
if( dStrcmp( 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 GuiDirectoryTreeCtrl::onItemSelected( Item *item )
|
||||
{
|
||||
Con::executef( this, 2, "onSelectPath", avar("%s",item->getValue()) );
|
||||
|
||||
mSelPath = StringTable->insert( item->getValue() );
|
||||
|
||||
if( Platform::hasSubDirectory( item->getValue() ) )
|
||||
item->setVirtualParent( true );
|
||||
}
|
||||
|
||||
void GuiDirectoryTreeCtrl::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 *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 );
|
||||
getItem( itemIndex )->setNormalImage( Icon_FolderClosed );
|
||||
getItem( itemIndex )->setExpandedImage( Icon_Folder );
|
||||
}
|
||||
else
|
||||
{
|
||||
Item *item = parent;
|
||||
|
||||
char *szValue = new char[ 1024 ];
|
||||
dMemset( szValue, 0, 1024 );
|
||||
dSprintf( szValue, 1024, "%s/%s", parent->getValue(), curPos );
|
||||
Item *exists = item->findChildByValue( szValue );
|
||||
if( !exists && dStrcmp( curPos, "" ) != 0 )
|
||||
{
|
||||
// Since we're adding a child this parent can't be a virtual parent, so clear that flag
|
||||
item->setVirtualParent( false );
|
||||
|
||||
itemIndex = insertItem( item->getID(), curPos);
|
||||
|
||||
getItem( itemIndex )->setValue( szValue );
|
||||
getItem( itemIndex )->setNormalImage( Icon_FolderClosed );
|
||||
getItem( itemIndex )->setExpandedImage( Icon_Folder );
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
delete []szValue;
|
||||
itemIndex = ( item != NULL ) ? ( ( exists != NULL ) ? exists->getID() : -1 ) : -1;
|
||||
}
|
||||
}
|
||||
|
||||
// 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( delim )
|
||||
{
|
||||
if( ( dStrcmp( delim, "" ) == 0 ) && item )
|
||||
{
|
||||
item->setExpanded( false );
|
||||
if( parent && Platform::hasSubDirectory( item->getValue() ) )
|
||||
item->setVirtualParent( true );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if( item )
|
||||
{
|
||||
item->setExpanded( false );
|
||||
if( parent && Platform::hasSubDirectory( item->getValue() ) )
|
||||
item->setVirtualParent( true );
|
||||
}
|
||||
}
|
||||
|
||||
// Down the rabbit hole we go
|
||||
recurseInsert( getItem( itemIndex ), delim );
|
||||
|
||||
}
|
||||
|
||||
|
||||
StringTableEntry GuiDirectoryTreeCtrl::getUnit(const char *string, U32 index, const char *set)
|
||||
{
|
||||
U32 sz;
|
||||
while(index--)
|
||||
{
|
||||
if(!*string)
|
||||
return "";
|
||||
sz = dStrcspn(string, set);
|
||||
if (string[sz] == 0)
|
||||
return "";
|
||||
string += (sz + 1);
|
||||
}
|
||||
sz = dStrcspn(string, set);
|
||||
if (sz == 0)
|
||||
return "";
|
||||
char *ret = Con::getReturnBuffer(sz+1);
|
||||
dStrncpy(ret, string, sz);
|
||||
ret[sz] = '\0';
|
||||
return ret;
|
||||
}
|
||||
StringTableEntry GuiDirectoryTreeCtrl::getUnits(const char *string, S32 startIndex, S32 endIndex, const char *set)
|
||||
{
|
||||
S32 sz;
|
||||
S32 index = startIndex;
|
||||
while(index--)
|
||||
{
|
||||
if(!*string)
|
||||
return "";
|
||||
sz = dStrcspn(string, set);
|
||||
if (string[sz] == 0)
|
||||
return "";
|
||||
string += (sz + 1);
|
||||
}
|
||||
const char *startString = string;
|
||||
while(startIndex <= endIndex--)
|
||||
{
|
||||
sz = dStrcspn(string, set);
|
||||
string += sz;
|
||||
if (*string == 0)
|
||||
break;
|
||||
string++;
|
||||
}
|
||||
if(!*string)
|
||||
string++;
|
||||
U32 totalSize = (U32(string - startString));
|
||||
char *ret = Con::getReturnBuffer(totalSize);
|
||||
dStrncpy(ret, startString, totalSize - 1);
|
||||
ret[totalSize-1] = '\0';
|
||||
return ret;
|
||||
}
|
||||
|
||||
U32 GuiDirectoryTreeCtrl::getUnitCount(const char *string, const char *set)
|
||||
{
|
||||
U32 count = 0;
|
||||
U8 last = 0;
|
||||
while(*string)
|
||||
{
|
||||
last = *string++;
|
||||
|
||||
for(U32 i =0; set[i]; i++)
|
||||
{
|
||||
if(last == set[i])
|
||||
{
|
||||
count++;
|
||||
last = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(last)
|
||||
count++;
|
||||
return count;
|
||||
}
|
||||
|
||||
|
||||
ConsoleMethod( GuiDirectoryTreeCtrl, getSelectedPath, const char*, 2,2, "getSelectedPath() - returns the currently selected path in the tree")
|
||||
{
|
||||
return object->getSelectedPath();
|
||||
}
|
||||
|
||||
StringTableEntry GuiDirectoryTreeCtrl::getSelectedPath()
|
||||
{
|
||||
return mSelPath;
|
||||
}
|
||||
|
||||
ConsoleMethod( GuiDirectoryTreeCtrl, setSelectedPath, bool, 3, 3, "setSelectedPath(path) - expands the tree to the specified path")
|
||||
{
|
||||
return object->setSelectedPath( argv[2] );
|
||||
}
|
||||
|
||||
bool GuiDirectoryTreeCtrl::setSelectedPath( StringTableEntry 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( Platform::isDirectory( 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,"GuiDirectoryTreeCtrl::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;
|
||||
}
|
58
engine/gui/controls/guiDirectoryTreeCtrl.h
Executable file
58
engine/gui/controls/guiDirectoryTreeCtrl.h
Executable file
@ -0,0 +1,58 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// Torque Game Engine
|
||||
// Copyright (C) GarageGames.com, Inc.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef _GUI_DIRECTORYTREECTRL_H_
|
||||
#define _GUI_DIRECTORYTREECTRL_H_
|
||||
|
||||
#ifndef _PLATFORM_H_
|
||||
#include "platform/platform.h"
|
||||
#endif
|
||||
|
||||
#ifndef _RESMANAGER_H_
|
||||
#include "core/resManager.h"
|
||||
#endif
|
||||
|
||||
#ifndef _GUI_TREEVIEWCTRL_H
|
||||
#include "gui/controls/guiTreeViewCtrl.h"
|
||||
#endif
|
||||
|
||||
class GuiDirectoryTreeCtrl : public GuiTreeViewCtrl
|
||||
{
|
||||
private:
|
||||
typedef GuiTreeViewCtrl Parent;
|
||||
|
||||
// Utility functions
|
||||
void recurseInsert( Item* parent, StringTableEntry path );
|
||||
void addPathToTree( StringTableEntry path );
|
||||
|
||||
protected:
|
||||
StringTableEntry mSelPath;
|
||||
|
||||
public:
|
||||
enum
|
||||
{
|
||||
Icon_Folder = 1,
|
||||
Icon_FolderClosed
|
||||
};
|
||||
GuiDirectoryTreeCtrl();
|
||||
|
||||
bool onWake();
|
||||
bool onAdd();
|
||||
bool onVirtualParentExpand(Item *item);
|
||||
void onItemSelected( Item *item );
|
||||
StringTableEntry getSelectedPath();
|
||||
bool setSelectedPath( StringTableEntry path );
|
||||
bool buildIconTable(const char * icons);
|
||||
|
||||
// Mod Path Parsing
|
||||
StringTableEntry getUnit(const char *string, U32 index, const char *set);
|
||||
StringTableEntry getUnits(const char *string, S32 startIndex, S32 endIndex, const char *set);
|
||||
U32 getUnitCount(const char *string, const char *set);
|
||||
|
||||
|
||||
DECLARE_CONOBJECT(GuiDirectoryTreeCtrl);
|
||||
};
|
||||
|
||||
#endif
|
996
engine/gui/controls/guiListBoxCtrl.cc
Executable file
996
engine/gui/controls/guiListBoxCtrl.cc
Executable file
@ -0,0 +1,996 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// Torque Game Engine
|
||||
// Copyright (C) GarageGames.com, Inc.
|
||||
//-----------------------------------------------------------------------------
|
||||
#include "gui/controls/guiListBoxCtrl.h"
|
||||
|
||||
IMPLEMENT_CONOBJECT(GuiListBoxCtrl);
|
||||
|
||||
GuiListBoxCtrl::GuiListBoxCtrl()
|
||||
{
|
||||
mItems.clear();
|
||||
mSelectedItems.clear();
|
||||
mMultipleSelections = true;
|
||||
mFitParentWidth = true;
|
||||
mItemSize = Point2I(10,20);
|
||||
mLastClickItem = NULL;
|
||||
}
|
||||
|
||||
GuiListBoxCtrl::~GuiListBoxCtrl()
|
||||
{
|
||||
clearItems();
|
||||
}
|
||||
|
||||
void GuiListBoxCtrl::initPersistFields()
|
||||
{
|
||||
Parent::initPersistFields();
|
||||
|
||||
addField( "AllowMultipleSelections", TypeBool, Offset( mMultipleSelections, GuiListBoxCtrl) );
|
||||
addField( "FitParentWidth", TypeBool, Offset( mFitParentWidth, GuiListBoxCtrl) );
|
||||
}
|
||||
|
||||
bool GuiListBoxCtrl::onWake()
|
||||
{
|
||||
if( !Parent::onWake() )
|
||||
return false;
|
||||
|
||||
updateSize();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Item Accessors
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
ConsoleMethod( GuiListBoxCtrl, setMultipleSelection, void, 3, 3, "listBox.setMultipleSelection([true/false])" )
|
||||
{
|
||||
object->setMultipleSelection( dAtob( argv[2] ) );
|
||||
}
|
||||
|
||||
|
||||
ConsoleMethod( GuiListBoxCtrl, clearItems, void, 2, 2, "clearItems() - Clears all the items in the listbox" )
|
||||
{
|
||||
object->clearItems();
|
||||
}
|
||||
|
||||
void GuiListBoxCtrl::clearItems()
|
||||
{
|
||||
// Free item list allocated memory
|
||||
while( mItems.size() )
|
||||
deleteItem( 0 );
|
||||
|
||||
// Free our vector lists
|
||||
mItems.clear();
|
||||
mSelectedItems.clear();
|
||||
}
|
||||
|
||||
|
||||
ConsoleMethod( GuiListBoxCtrl, clearSelection, void, 2, 2, "clearSelection() - sets all currently selected items to unselected" )
|
||||
{
|
||||
object->clearSelection();
|
||||
}
|
||||
void GuiListBoxCtrl::clearSelection()
|
||||
{
|
||||
if( !mSelectedItems.size() )
|
||||
return;
|
||||
|
||||
VectorPtr<LBItem*>::iterator i = mSelectedItems.begin();
|
||||
for( ; i != mSelectedItems.end(); i++ )
|
||||
(*i)->isSelected = false;
|
||||
|
||||
mSelectedItems.clear();
|
||||
}
|
||||
|
||||
|
||||
ConsoleMethod( GuiListBoxCtrl, setSelected, void, 3, 4, "setSelected(index, [true]/false) - sets the item at the index specified to selected or not")
|
||||
{
|
||||
bool value = true;
|
||||
if( argc == 4 )
|
||||
value = dAtob( argv[3] );
|
||||
|
||||
if( value == true )
|
||||
object->addSelection( dAtoi( argv[2] ) );
|
||||
else
|
||||
object->removeSelection( dAtoi( argv[2] ) );
|
||||
}
|
||||
|
||||
void GuiListBoxCtrl::removeSelection( S32 index )
|
||||
{
|
||||
// Range Check
|
||||
if( index >= mItems.size() || index < 0 )
|
||||
{
|
||||
Con::warnf("GuiListBoxCtrl::removeSelection - index out of range!" );
|
||||
return;
|
||||
}
|
||||
|
||||
removeSelection( mItems[index], index );
|
||||
}
|
||||
void GuiListBoxCtrl::removeSelection( LBItem *item, S32 index )
|
||||
{
|
||||
if( !mSelectedItems.size() )
|
||||
return;
|
||||
|
||||
if( !item )
|
||||
return;
|
||||
|
||||
for( S32 i = 0 ; i < mSelectedItems.size(); i++ )
|
||||
{
|
||||
if( mSelectedItems[i] == item )
|
||||
{
|
||||
mSelectedItems.erase( &mSelectedItems[i] );
|
||||
item->isSelected = false;
|
||||
Con::executef(this, 3, "onUnSelect", Con::getIntArg( index ), item->itemText);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GuiListBoxCtrl::addSelection( S32 index )
|
||||
{
|
||||
// Range Check
|
||||
if( index >= mItems.size() || index < 0 )
|
||||
{
|
||||
Con::warnf("GuiListBoxCtrl::addSelection- index out of range!" );
|
||||
return;
|
||||
}
|
||||
|
||||
addSelection( mItems[index], index );
|
||||
|
||||
}
|
||||
void GuiListBoxCtrl::addSelection( LBItem *item, S32 index )
|
||||
{
|
||||
if( !mMultipleSelections )
|
||||
{
|
||||
if( !mSelectedItems.empty() )
|
||||
{
|
||||
LBItem* selItem = mSelectedItems.front();
|
||||
if( selItem != item )
|
||||
clearSelection();
|
||||
else
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if( !mSelectedItems.empty() )
|
||||
{
|
||||
for( S32 i = 0; i < mSelectedItems.size(); i++ )
|
||||
{
|
||||
if( mSelectedItems[ i ] == item )
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
item->isSelected = true;
|
||||
mSelectedItems.push_front( item );
|
||||
|
||||
Con::executef(this, 3, "onSelect", Con::getIntArg( index ), item->itemText);
|
||||
|
||||
}
|
||||
|
||||
S32 GuiListBoxCtrl::getItemIndex( LBItem *item )
|
||||
{
|
||||
if( mItems.empty() )
|
||||
return -1;
|
||||
|
||||
// Lookup the index of an item in our list, by the pointer to the item
|
||||
for( S32 i = 0; i < mItems.size(); i++ )
|
||||
if( mItems[i] == item )
|
||||
return i;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
ConsoleMethod( GuiListBoxCtrl, getItemCount, S32, 2, 2, "getItemCount() - returns the number of items in the list")
|
||||
{
|
||||
return object->getItemCount();
|
||||
}
|
||||
|
||||
S32 GuiListBoxCtrl::getItemCount()
|
||||
{
|
||||
return mItems.size();
|
||||
}
|
||||
|
||||
ConsoleMethod( GuiListBoxCtrl, getSelCount, S32, 2, 2, "getSelCount() - returns the number of items currently selected")
|
||||
{
|
||||
return object->getSelCount();
|
||||
}
|
||||
S32 GuiListBoxCtrl::getSelCount()
|
||||
{
|
||||
return mSelectedItems.size();
|
||||
}
|
||||
|
||||
ConsoleMethod( GuiListBoxCtrl, getSelectedItem, S32, 2, 2, "getSelectedItem() - returns the selected items index. "
|
||||
"If multiple selections exist it returns the first selected item" )
|
||||
{
|
||||
return object->getSelectedItem();
|
||||
}
|
||||
S32 GuiListBoxCtrl::getSelectedItem()
|
||||
{
|
||||
if( mSelectedItems.empty() || mItems.empty() )
|
||||
return -1;
|
||||
|
||||
S32 i = 0;
|
||||
for( S32 i = 0 ; i < mItems.size(); i++ )
|
||||
if( mItems[i]->isSelected )
|
||||
return i;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
ConsoleMethod( GuiListBoxCtrl, getSelectedItems, const char*, 2, 2, "getSelectedItems() - returns a space delimited list "
|
||||
"of the selected items indexes in the list")
|
||||
{
|
||||
S32 selCount = object->getSelCount();
|
||||
if( selCount == -1 || selCount == 0 )
|
||||
return StringTable->lookup("-1");
|
||||
else if( selCount == 1 )
|
||||
return Con::getIntArg(object->getSelectedItem());
|
||||
|
||||
Vector<S32> selItems;
|
||||
object->getSelectedItems( selItems );
|
||||
|
||||
if( selItems.empty() )
|
||||
return StringTable->lookup("-1");
|
||||
|
||||
UTF8 *retBuffer = Con::getReturnBuffer( selItems.size() * 4 );
|
||||
dMemset( retBuffer, 0, selItems.size() * 4 );
|
||||
Vector<S32>::iterator i = selItems.begin();
|
||||
for( ; i != selItems.end(); i++ )
|
||||
{
|
||||
UTF8 retFormat[12];
|
||||
dSprintf( retFormat, 12, "%d ", (*i) );
|
||||
dStrcat( retBuffer, retFormat );
|
||||
}
|
||||
|
||||
return retBuffer;
|
||||
}
|
||||
void GuiListBoxCtrl::getSelectedItems( Vector<S32> &Items )
|
||||
{
|
||||
// Clear our return vector
|
||||
Items.clear();
|
||||
|
||||
// If there are no selected items, return an empty vector
|
||||
if( mSelectedItems.empty() )
|
||||
return;
|
||||
|
||||
for( S32 i = 0; i < mItems.size(); i++ )
|
||||
if( mItems[i]->isSelected )
|
||||
Items.push_back( i );
|
||||
}
|
||||
|
||||
ConsoleMethod(GuiListBoxCtrl, findItemText, S32, 3, 4, "listBox.findItemText( myItemText, [?caseSensitive - false] ) - Returns index of item with matching text")
|
||||
{
|
||||
bool bCaseSensitive = false;
|
||||
|
||||
if( argc == 4 )
|
||||
bCaseSensitive = dAtob( argv[3] );
|
||||
|
||||
return object->findItemText( argv[2], bCaseSensitive );
|
||||
}
|
||||
|
||||
S32 GuiListBoxCtrl::findItemText( StringTableEntry text, bool caseSensitive )
|
||||
{
|
||||
// Check Proper Arguments
|
||||
if( !text || !text[0] || text == StringTable->lookup("") )
|
||||
{
|
||||
Con::warnf("GuiListBoxCtrl::findItemText - No Text Specified!");
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Check Items Exist.
|
||||
if( mItems.empty() )
|
||||
return -1;
|
||||
|
||||
// Lookup the index of an item in our list, by the pointer to the item
|
||||
for( S32 i = 0; i < mItems.size(); i++ )
|
||||
{
|
||||
// Case Sensitive Compare?
|
||||
if( caseSensitive && ( dStrcmp( mItems[i]->itemText, text ) == 0 ) )
|
||||
return i;
|
||||
else if (!caseSensitive && ( dStricmp( mItems[i]->itemText, text ) == 0 ))
|
||||
return i;
|
||||
}
|
||||
|
||||
// Not Found!
|
||||
return -1;
|
||||
}
|
||||
|
||||
ConsoleMethod(GuiListBoxCtrl, setCurSel, void, 3, 3, "setCurSel(index) - sets the currently selected item at the specified index")
|
||||
{
|
||||
object->setCurSel( dAtoi( argv[2] ) );
|
||||
}
|
||||
void GuiListBoxCtrl::setCurSel( S32 index )
|
||||
{
|
||||
// Range Check
|
||||
if( index >= mItems.size() )
|
||||
{
|
||||
Con::warnf("GuiListBoxCtrl::setCurSel - index out of range!" );
|
||||
return;
|
||||
}
|
||||
|
||||
// If index -1 is specified, we clear the selection
|
||||
if( index == -1 )
|
||||
{
|
||||
mSelectedItems.clear();
|
||||
return;
|
||||
}
|
||||
|
||||
// Add the selection
|
||||
addSelection( mItems[ index ], index );
|
||||
|
||||
}
|
||||
|
||||
ConsoleMethod( GuiListBoxCtrl, setCurSelRange, void, 3, 4, "setCurSelRange(start,[stop]) - sets the current selection range from"
|
||||
" index start to stop. if no stop is specified it sets from start index to the end of the list")
|
||||
{
|
||||
if( argc == 4 )
|
||||
object->setCurSelRange( dAtoi(argv[2]) , dAtoi( argv[3] ) );
|
||||
else
|
||||
object->setCurSelRange( dAtoi(argv[2]), 999999 );
|
||||
}
|
||||
void GuiListBoxCtrl::setCurSelRange( S32 start, S32 stop )
|
||||
{
|
||||
// Verify Selection Range
|
||||
if( start < 0 )
|
||||
start = 0;
|
||||
else if( start > mItems.size() )
|
||||
start = mItems.size();
|
||||
|
||||
if( stop < 0 )
|
||||
stop = 0;
|
||||
else if( stop > mItems.size() )
|
||||
stop = mItems.size();
|
||||
|
||||
S32 iterStart = ( start < stop ) ? start : stop;
|
||||
S32 iterStop = ( start < stop ) ? stop : start;
|
||||
|
||||
for( ; iterStart <= iterStop; iterStart++ )
|
||||
addSelection( mItems[iterStart], iterStart );
|
||||
}
|
||||
|
||||
|
||||
ConsoleMethod( GuiListBoxCtrl, addItem, void, 3, 4, "addItem(text, color) - adds an item to the end of the list with an optional color" )
|
||||
{
|
||||
if(argc == 3)
|
||||
{
|
||||
object->addItem( argv[2] );
|
||||
} else if(argc == 4)
|
||||
{
|
||||
U32 elementCount = GuiListBoxCtrl::getStringElementCount(argv[3]);
|
||||
|
||||
if(elementCount == 3)
|
||||
{
|
||||
F32 red, green, blue;
|
||||
|
||||
red = dAtof(GuiListBoxCtrl::getStringElement( argv[3], 0 ));
|
||||
green = dAtof(GuiListBoxCtrl::getStringElement( argv[3], 1 ));
|
||||
blue = dAtof(GuiListBoxCtrl::getStringElement( argv[3], 2 ));
|
||||
|
||||
object->addItemWithColor( argv[2], ColorF(red, green, blue) );
|
||||
} else
|
||||
{
|
||||
Con::warnf("GuiListBoxCtrl::addItem() - Invalid number of parameters for the color!");
|
||||
}
|
||||
|
||||
} else
|
||||
{
|
||||
Con::warnf("GuiListBoxCtrl::addItem() - Invalid number of parameters!");
|
||||
}
|
||||
}
|
||||
S32 GuiListBoxCtrl::addItem( StringTableEntry text, void *itemData )
|
||||
{
|
||||
// This just calls insert item at the end of the list
|
||||
return insertItem( mItems.size(), text, itemData );
|
||||
}
|
||||
|
||||
S32 GuiListBoxCtrl::addItemWithColor( StringTableEntry text, ColorF color, void *itemData )
|
||||
{
|
||||
// This just calls insert item at the end of the list
|
||||
return insertItemWithColor( mItems.size(), text, color, itemData );
|
||||
}
|
||||
|
||||
ConsoleMethod(GuiListBoxCtrl, setItemColor, void, 4, 4, "(index, color)")
|
||||
{
|
||||
U32 elementCount = GuiListBoxCtrl::getStringElementCount(argv[3]);
|
||||
|
||||
if(elementCount == 3)
|
||||
{
|
||||
F32 red = dAtof(GuiListBoxCtrl::getStringElement( argv[3], 0 ));
|
||||
F32 green = dAtof(GuiListBoxCtrl::getStringElement( argv[3], 1 ));
|
||||
F32 blue = dAtof(GuiListBoxCtrl::getStringElement( argv[3], 2 ));
|
||||
|
||||
object->setItemColor( dAtoi(argv[2]), ColorF(red, green, blue) );
|
||||
}
|
||||
else
|
||||
Con::warnf("GuiListBoxCtrl::addItem() - Invalid number of parameters for the color!");
|
||||
}
|
||||
|
||||
void GuiListBoxCtrl::setItemColor( S32 index, ColorF color )
|
||||
{
|
||||
if ((index >= mItems.size()) || index < 0)
|
||||
{
|
||||
Con::warnf("GuiListBoxCtrl::setItemColor - invalid index");
|
||||
return;
|
||||
}
|
||||
|
||||
LBItem* item = mItems[index];
|
||||
item->hasColor = true;
|
||||
item->color = color;
|
||||
}
|
||||
|
||||
ConsoleMethod(GuiListBoxCtrl, clearItemColor, void, 3, 3, "(index)")
|
||||
{
|
||||
object->clearItemColor(dAtoi(argv[2]));
|
||||
}
|
||||
|
||||
void GuiListBoxCtrl::clearItemColor( S32 index )
|
||||
{
|
||||
if ((index >= mItems.size()) || index < 0)
|
||||
{
|
||||
Con::warnf("GuiListBoxCtrl::setItemColor - invalid index");
|
||||
return;
|
||||
}
|
||||
|
||||
LBItem* item = mItems[index];
|
||||
item->hasColor = false;
|
||||
}
|
||||
|
||||
ConsoleMethod( GuiListBoxCtrl, insertItem, void, 4, 4, "insertItem( text, index ) - inserts an item into the list at the specified index")
|
||||
{
|
||||
object->insertItem( dAtoi( argv[3] ), argv[2] );
|
||||
}
|
||||
S32 GuiListBoxCtrl::insertItem( S32 index, StringTableEntry text, void *itemData )
|
||||
{
|
||||
// If the index is greater than our list size, insert it at the end
|
||||
if( index >= mItems.size() )
|
||||
index = mItems.size();
|
||||
|
||||
// Sanity checking
|
||||
if( !text )
|
||||
{
|
||||
Con::warnf("GuiListBoxCtrl::insertItem - cannot add NULL string" );
|
||||
return -1;
|
||||
}
|
||||
|
||||
LBItem *newItem = new LBItem;
|
||||
if( !newItem )
|
||||
{
|
||||
Con::warnf("GuiListBoxCtrl::insertItem - error allocating item memory!" );
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Assign item data
|
||||
newItem->itemText = StringTable->insert(text);
|
||||
newItem->itemData = itemData;
|
||||
newItem->isSelected = false;
|
||||
newItem->hasColor = false;
|
||||
|
||||
// Add to list
|
||||
mItems.insert(&mItems[index], newItem );
|
||||
|
||||
// Resize our list to fit our items
|
||||
updateSize();
|
||||
|
||||
// Return our index in list (last)
|
||||
return index;
|
||||
|
||||
}
|
||||
|
||||
S32 GuiListBoxCtrl::insertItemWithColor( S32 index, StringTableEntry text, ColorF color, void *itemData )
|
||||
{
|
||||
// If the index is greater than our list size, insert it at the end
|
||||
if( index >= mItems.size() )
|
||||
index = mItems.size();
|
||||
|
||||
// Sanity checking
|
||||
if( !text )
|
||||
{
|
||||
Con::warnf("GuiListBoxCtrl::insertItem - cannot add NULL string" );
|
||||
return -1;
|
||||
}
|
||||
|
||||
if( color == ColorF(-1, -1, -1) )
|
||||
{
|
||||
Con::warnf("GuiListBoxCtrl::insertItem - cannot add NULL color" );
|
||||
return -1;
|
||||
}
|
||||
|
||||
LBItem *newItem = new LBItem;
|
||||
if( !newItem )
|
||||
{
|
||||
Con::warnf("GuiListBoxCtrl::insertItem - error allocating item memory!" );
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Assign item data
|
||||
newItem->itemText = StringTable->insert(text);
|
||||
newItem->itemData = itemData;
|
||||
newItem->isSelected = false;
|
||||
newItem->hasColor = true;
|
||||
newItem->color = color;
|
||||
|
||||
// Add to list
|
||||
mItems.insert(&mItems[index], newItem );
|
||||
|
||||
// Resize our list to fit our items
|
||||
updateSize();
|
||||
|
||||
// Return our index in list (last)
|
||||
return index;
|
||||
|
||||
}
|
||||
|
||||
ConsoleMethod ( GuiListBoxCtrl, deleteItem, void, 3, 3, "deleteItem(itemIndex)" )
|
||||
{
|
||||
object->deleteItem( dAtoi( argv[2] ) );
|
||||
}
|
||||
|
||||
void GuiListBoxCtrl::deleteItem( S32 index )
|
||||
{
|
||||
// Range Check
|
||||
if( index >= mItems.size() || index < 0 )
|
||||
{
|
||||
Con::warnf("GuiListBoxCtrl::deleteItem - index out of range!" );
|
||||
return;
|
||||
}
|
||||
|
||||
// Grab our item
|
||||
LBItem* item = mItems[ index ];
|
||||
if( !item )
|
||||
{
|
||||
Con::warnf("GuiListBoxCtrl::deleteItem - Bad Item Data!" );
|
||||
return;
|
||||
}
|
||||
|
||||
// Remove it from the selected list.
|
||||
if( item->isSelected )
|
||||
{
|
||||
for( VectorPtr<LBItem*>::iterator i = mSelectedItems.begin(); i != mSelectedItems.end(); i++ )
|
||||
{
|
||||
if( item == *i )
|
||||
{
|
||||
mSelectedItems.erase_fast( i );
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Remove it from the list
|
||||
mItems.erase( &mItems[ index ] );
|
||||
|
||||
// Free the memory associated with it
|
||||
delete item;
|
||||
}
|
||||
|
||||
|
||||
ConsoleMethod( GuiListBoxCtrl, getItemText, const char*, 3, 3, "getItemText(index) - returns the text of the item at the specified index")
|
||||
{
|
||||
return object->getItemText( dAtoi( argv[2] ) );
|
||||
}
|
||||
|
||||
StringTableEntry GuiListBoxCtrl::getItemText( S32 index )
|
||||
{
|
||||
// Range Checking
|
||||
if( index > mItems.size() || index < 0 )
|
||||
{
|
||||
Con::warnf( "GuiListBoxCtrl::getItemText - index out of range!" );
|
||||
return StringTable->lookup("");
|
||||
}
|
||||
|
||||
return mItems[ index ]->itemText;
|
||||
}
|
||||
|
||||
|
||||
ConsoleMethod( GuiListBoxCtrl, setItemText, void, 4, 4, "setItemText(index, newtext) - sets the items text at the specified index" )
|
||||
{
|
||||
object->setItemText( dAtoi( argv[2] ), argv[3] );
|
||||
}
|
||||
void GuiListBoxCtrl::setItemText( S32 index, StringTableEntry text )
|
||||
{
|
||||
// Sanity Checking
|
||||
if( !text )
|
||||
{
|
||||
Con::warnf("GuiListBoxCtrl::setItemText - Invalid Text Specified!" );
|
||||
return;
|
||||
}
|
||||
// Range Checking
|
||||
if( index > mItems.size() || index < 0 )
|
||||
{
|
||||
Con::warnf( "GuiListBoxCtrl::getItemText - index out of range!" );
|
||||
return;
|
||||
}
|
||||
|
||||
mItems[ index ]->itemText = StringTable->insert( text );
|
||||
}
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Sizing Functions
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
void GuiListBoxCtrl::updateSize()
|
||||
{
|
||||
if( !mProfile )
|
||||
return;
|
||||
|
||||
GFont *font = mProfile->mFont;
|
||||
GuiScrollCtrl* parent = dynamic_cast<GuiScrollCtrl *>(getParent());
|
||||
|
||||
if ( mFitParentWidth && parent )
|
||||
mItemSize.x = parent->getContentExtent().x;
|
||||
else
|
||||
{
|
||||
// Find the maximum width cell:
|
||||
S32 maxWidth = 1;
|
||||
for ( U32 i = 0; i < mItems.size(); i++ )
|
||||
{
|
||||
S32 width = font->getStrWidth( mItems[i]->itemText );
|
||||
if( width > maxWidth )
|
||||
maxWidth = width;
|
||||
}
|
||||
mItemSize.x = maxWidth + 6;
|
||||
}
|
||||
|
||||
mItemSize.y = font->getHeight() + 2;
|
||||
|
||||
Point2I newExtent( mItemSize.x, mItemSize.y * mItems.size() );
|
||||
resize( mBounds.point, newExtent );
|
||||
|
||||
}
|
||||
|
||||
void GuiListBoxCtrl::parentResized(const Point2I &oldParentExtent, const Point2I &newParentExtent)
|
||||
{
|
||||
Parent::parentResized( oldParentExtent, newParentExtent );
|
||||
|
||||
updateSize();
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Overrides
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
void GuiListBoxCtrl::onRender( Point2I offset, const RectI &updateRect )
|
||||
{
|
||||
RectI clipRect(updateRect.point, updateRect.extent);
|
||||
|
||||
if( !mProfile )
|
||||
return;
|
||||
|
||||
// Save our original clip rect
|
||||
RectI oldClipRect = clipRect;
|
||||
|
||||
for ( S32 i = 0; i < mItems.size(); i++)
|
||||
{
|
||||
S32 colorBoxSize = 0;
|
||||
ColorI boxColor = ColorI(0, 0, 0);
|
||||
// Only render visible items
|
||||
if ((i + 1) * mItemSize.y + offset.y < updateRect.point.y)
|
||||
continue;
|
||||
|
||||
// Break our once we're no longer in visible item range
|
||||
if( i * mItemSize.y + offset.y >= updateRect.point.y + updateRect.extent.y)
|
||||
break;
|
||||
|
||||
// Render color box if needed
|
||||
if(mItems[i]->hasColor)
|
||||
{
|
||||
// Set the size of the color box to be drawn next to the item text
|
||||
colorBoxSize = 3;
|
||||
boxColor = ColorI(mItems[i]->color);
|
||||
// Draw the box first
|
||||
ColorI black = ColorI(0, 0, 0);
|
||||
drawBox( Point2I(offset.x + mProfile->mTextOffset.x + colorBoxSize, offset.y + ( i * mItemSize.y ) + 8), colorBoxSize, black, boxColor );
|
||||
}
|
||||
|
||||
RectI itemRect = RectI( offset.x + mProfile->mTextOffset.x + (colorBoxSize * 2), offset.y + ( i * mItemSize.y ), mItemSize.x, mItemSize.y );
|
||||
|
||||
// Render our item
|
||||
onRenderItem( itemRect, mItems[i] );
|
||||
}
|
||||
|
||||
dglSetClipRect( oldClipRect );
|
||||
}
|
||||
|
||||
|
||||
void GuiListBoxCtrl::onRenderItem( RectI itemRect, LBItem *item )
|
||||
{
|
||||
if( item->isSelected )
|
||||
dglDrawRectFill( itemRect, mProfile->mFillColor );
|
||||
|
||||
dglSetBitmapModulation(mProfile->mFontColor);
|
||||
renderJustifiedText(itemRect.point + Point2I( 2, 0 ), itemRect.extent, item->itemText);
|
||||
}
|
||||
|
||||
void GuiListBoxCtrl::drawBox(const Point2I &box, S32 size, ColorI &outlineColor, ColorI &boxColor)
|
||||
{
|
||||
RectI r(box.x - size, box.y - size, 2 * size + 1, 2 * size + 1);
|
||||
r.inset(1, 1);
|
||||
dglDrawRectFill(r, boxColor);
|
||||
r.inset(-1, -1);
|
||||
dglDrawRect(r, outlineColor);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Item Selections
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void GuiListBoxCtrl::onMouseDown( const GuiEvent &event )
|
||||
{
|
||||
Point2I localPoint = globalToLocalCoord(event.mousePoint);
|
||||
|
||||
S32 itemHit = ( localPoint.y < 0 ) ? -1 : (S32)mFloor( (F32)localPoint.y / (F32)mItemSize.y );
|
||||
|
||||
if ( itemHit >= mItems.size() || itemHit == -1 )
|
||||
return;
|
||||
|
||||
LBItem *hitItem = mItems[ itemHit ];
|
||||
if ( hitItem == NULL )
|
||||
return;
|
||||
|
||||
// If we're not a multiple selection listbox, we simply select/unselect an item
|
||||
if( !mMultipleSelections )
|
||||
{
|
||||
// No current selection? Just select the cell and move on
|
||||
S32 selItem = getSelectedItem();
|
||||
|
||||
if ( selItem != itemHit && selItem != -1 )
|
||||
clearSelection();
|
||||
|
||||
// Set the current selection
|
||||
setCurSel( itemHit );
|
||||
|
||||
if( itemHit == selItem && event.mouseClickCount == 2 && isMethod("onDoubleClick") )
|
||||
Con::executef( this, 2, "onDoubleClick" );
|
||||
|
||||
// Store the clicked item
|
||||
mLastClickItem = hitItem;
|
||||
|
||||
// Evaluate the console command if we clicked the same item twice
|
||||
if( selItem == itemHit && event.mouseClickCount > 1 && mAltConsoleCommand[0] )
|
||||
Con::evaluate( mAltConsoleCommand, false );
|
||||
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
// Deal with multiple selections
|
||||
if( event.modifier & SI_CTRL)
|
||||
{
|
||||
// Ctrl-Click toggles selection
|
||||
if( hitItem->isSelected )
|
||||
{
|
||||
removeSelection( hitItem, itemHit );
|
||||
|
||||
// We return here when we deselect an item because we don't store last clicked when we deselect
|
||||
return;
|
||||
}
|
||||
else
|
||||
addSelection( hitItem, itemHit );
|
||||
}
|
||||
else if( event.modifier & SI_SHIFT )
|
||||
{
|
||||
if( !mLastClickItem )
|
||||
addSelection( hitItem, itemHit );
|
||||
else
|
||||
setCurSelRange( getItemIndex( mLastClickItem ), itemHit );
|
||||
}
|
||||
else
|
||||
{
|
||||
if( getSelCount() != 0 )
|
||||
{
|
||||
S32 selItem = getSelectedItem();
|
||||
if( selItem != -1 && mItems[selItem] != hitItem )
|
||||
clearSelection();
|
||||
}
|
||||
addSelection( hitItem, itemHit );
|
||||
}
|
||||
|
||||
if( hitItem == mLastClickItem && event.mouseClickCount == 2 && isMethod("onDoubleClick") )
|
||||
Con::executef( this, 2, "onDoubleClick" );
|
||||
|
||||
mLastClickItem = hitItem;
|
||||
|
||||
|
||||
}
|
||||
|
||||
U32 GuiListBoxCtrl::getStringElementCount( const char* inString )
|
||||
{
|
||||
// Non-whitespace chars.
|
||||
static const char* set = " \t\n";
|
||||
|
||||
// End of string.
|
||||
if ( *inString == 0 )
|
||||
return 0;
|
||||
|
||||
U32 wordCount = 0;
|
||||
U8 search = 0;
|
||||
|
||||
// Search String.
|
||||
while( *inString )
|
||||
{
|
||||
// Get string element.
|
||||
search = *inString;
|
||||
|
||||
// End of string?
|
||||
if ( search == 0 )
|
||||
break;
|
||||
|
||||
// Move to next element.
|
||||
inString++;
|
||||
|
||||
// Search for seperators.
|
||||
for( U32 i = 0; set[i]; i++ )
|
||||
{
|
||||
// Found one?
|
||||
if( search == set[i] )
|
||||
{
|
||||
// Yes...
|
||||
search = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Found a seperator?
|
||||
if ( search == 0 )
|
||||
continue;
|
||||
|
||||
// We've found a non-seperator.
|
||||
wordCount++;
|
||||
|
||||
// Search for end of non-seperator.
|
||||
while( 1 )
|
||||
{
|
||||
// Get string element.
|
||||
search = *inString;
|
||||
|
||||
// End of string?
|
||||
if ( search == 0 )
|
||||
break;
|
||||
|
||||
// Move to next element.
|
||||
inString++;
|
||||
|
||||
// Search for seperators.
|
||||
for( U32 i = 0; set[i]; i++ )
|
||||
{
|
||||
// Found one?
|
||||
if( search == set[i] )
|
||||
{
|
||||
// Yes...
|
||||
search = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Found Seperator?
|
||||
if ( search == 0 )
|
||||
break;
|
||||
}
|
||||
|
||||
// End of string?
|
||||
if ( *inString == 0 )
|
||||
{
|
||||
// Bah!
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// We've finished.
|
||||
return wordCount;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Get String Element.
|
||||
//------------------------------------------------------------------------------
|
||||
const char* GuiListBoxCtrl::getStringElement( const char* inString, const U32 index )
|
||||
{
|
||||
// Non-whitespace chars.
|
||||
static const char* set = " \t\n";
|
||||
|
||||
U32 wordCount = 0;
|
||||
U8 search = 0;
|
||||
const char* pWordStart = NULL;
|
||||
|
||||
// End of string?
|
||||
if ( *inString != 0 )
|
||||
{
|
||||
// No, so search string.
|
||||
while( *inString )
|
||||
{
|
||||
// Get string element.
|
||||
search = *inString;
|
||||
|
||||
// End of string?
|
||||
if ( search == 0 )
|
||||
break;
|
||||
|
||||
// Move to next element.
|
||||
inString++;
|
||||
|
||||
// Search for seperators.
|
||||
for( U32 i = 0; set[i]; i++ )
|
||||
{
|
||||
// Found one?
|
||||
if( search == set[i] )
|
||||
{
|
||||
// Yes...
|
||||
search = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Found a seperator?
|
||||
if ( search == 0 )
|
||||
continue;
|
||||
|
||||
// Found are word?
|
||||
if ( wordCount == index )
|
||||
{
|
||||
// Yes, so mark it.
|
||||
pWordStart = inString-1;
|
||||
}
|
||||
|
||||
// We've found a non-seperator.
|
||||
wordCount++;
|
||||
|
||||
// Search for end of non-seperator.
|
||||
while( 1 )
|
||||
{
|
||||
// Get string element.
|
||||
search = *inString;
|
||||
|
||||
// End of string?
|
||||
if ( search == 0 )
|
||||
break;
|
||||
|
||||
// Move to next element.
|
||||
inString++;
|
||||
|
||||
// Search for seperators.
|
||||
for( U32 i = 0; set[i]; i++ )
|
||||
{
|
||||
// Found one?
|
||||
if( search == set[i] )
|
||||
{
|
||||
// Yes...
|
||||
search = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Found Seperator?
|
||||
if ( search == 0 )
|
||||
break;
|
||||
}
|
||||
|
||||
// Have we found our word?
|
||||
if ( pWordStart )
|
||||
{
|
||||
// Yes, so we've got our word...
|
||||
|
||||
// Result Buffer.
|
||||
static char buffer[4096];
|
||||
|
||||
// Calculate word length.
|
||||
const U32 length = inString - pWordStart - ((*inString)?1:0);
|
||||
|
||||
// Copy Word.
|
||||
dStrncpy( buffer, pWordStart, length);
|
||||
buffer[length] = '\0';
|
||||
|
||||
// Return Word.
|
||||
return buffer;
|
||||
}
|
||||
|
||||
// End of string?
|
||||
if ( *inString == 0 )
|
||||
{
|
||||
// Bah!
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Sanity!
|
||||
AssertFatal( false, "t2dSceneObject::getStringElement() - Couldn't find specified string element!" );
|
||||
// Didn't find it
|
||||
return " ";
|
||||
}
|
108
engine/gui/controls/guiListBoxCtrl.h
Executable file
108
engine/gui/controls/guiListBoxCtrl.h
Executable file
@ -0,0 +1,108 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// Torque Game Engine
|
||||
// Copyright (C) GarageGames.com, Inc.
|
||||
//-----------------------------------------------------------------------------
|
||||
#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 "dgl/dgl.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);
|
||||
|
||||
struct LBItem
|
||||
{
|
||||
StringTableEntry itemText;
|
||||
bool isSelected;
|
||||
void* itemData;
|
||||
ColorF color;
|
||||
bool hasColor;
|
||||
};
|
||||
|
||||
VectorPtr<LBItem*> mItems;
|
||||
VectorPtr<LBItem*> mSelectedItems;
|
||||
bool mMultipleSelections;
|
||||
Point2I mItemSize;
|
||||
bool mFitParentWidth;
|
||||
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 );
|
||||
|
||||
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; };
|
||||
|
||||
// Sizing
|
||||
void updateSize();
|
||||
virtual void parentResized(const Point2I &oldParentExtent, const Point2I &newParentExtent);
|
||||
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 );
|
||||
|
||||
// Selections
|
||||
virtual void onMouseDown( const GuiEvent &event );
|
||||
|
||||
// String Utility
|
||||
static U32 getStringElementCount( const char *string );
|
||||
static const char* getStringElement( const char* inString, const U32 index );
|
||||
|
||||
|
||||
};
|
||||
|
||||
#endif
|
2122
engine/gui/controls/guiMLTextCtrl.cc
Executable file
2122
engine/gui/controls/guiMLTextCtrl.cc
Executable file
File diff suppressed because it is too large
Load Diff
275
engine/gui/controls/guiMLTextCtrl.h
Executable file
275
engine/gui/controls/guiMLTextCtrl.h
Executable file
@ -0,0 +1,275 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// Torque Game Engine
|
||||
// Copyright (C) GarageGames.com, Inc.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#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 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 {
|
||||
const char *bitmapName;
|
||||
U32 bitmapNameLen;
|
||||
TextureHandle bitmapHandle;
|
||||
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();
|
||||
|
||||
// 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);
|
||||
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;
|
||||
U32 mMinSensibleWidth;
|
||||
|
||||
// Console settable parameters
|
||||
U32 mLineSpacingPixels;
|
||||
bool mAllowColorChars;
|
||||
|
||||
// Too many chars sound:
|
||||
AudioProfile* 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 maintainance
|
||||
bool isSelectionActive() const;
|
||||
void clearSelection();
|
||||
|
||||
// Pixel -> textposition mappings
|
||||
S32 getTextPosition(const Point2I& localPosition);
|
||||
|
||||
// Gui control overrides
|
||||
bool onAdd();
|
||||
bool onWake();
|
||||
void onSleep();
|
||||
void onPreRender();
|
||||
void onRender(Point2I offset, const RectI &updateRect);
|
||||
void getCursorPositionAndColor(Point2I &cursorTop, Point2I &cursorBottom, ColorI &color);
|
||||
void inspectPostApply();
|
||||
void resize(const Point2I &newPosition, const Point2I &newExtent);
|
||||
void parentResized(const Point2I &oldParentExtent, const Point2I &newParentExtent);
|
||||
bool onKeyDown(const GuiEvent& event);
|
||||
void onMouseDown(const GuiEvent&);
|
||||
void onMouseDragged(const GuiEvent&);
|
||||
void onMouseUp(const GuiEvent&);
|
||||
|
||||
public:
|
||||
void setSelectionStart( U32 start ) { clearSelection(); mSelectionStart = start; };
|
||||
void setSelectionEnd( U32 end ) { mSelectionEnd = end;};
|
||||
void setSelectionActive(bool active) { mSelectionActive = active; };
|
||||
S32 getCursorPosition() { return( mCursorPosition ); }
|
||||
};
|
||||
|
||||
#endif // _H_GUIMLTEXTCTRL_
|
365
engine/gui/controls/guiMLTextEditCtrl.cc
Executable file
365
engine/gui/controls/guiMLTextEditCtrl.cc
Executable file
@ -0,0 +1,365 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// Torque Game Engine
|
||||
// Copyright (C) GarageGames.com, Inc.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "gui/controls/guiMLTextEditCtrl.h"
|
||||
#include "gui/containers/guiScrollCtrl.h"
|
||||
#include "dgl/dgl.h"
|
||||
#include "console/consoleTypes.h"
|
||||
#include "platform/event.h"
|
||||
#include "core/frameAllocator.h"
|
||||
#include "core/stringBuffer.h"
|
||||
#include "core/unicode.h"
|
||||
|
||||
IMPLEMENT_CONOBJECT(GuiMLTextEditCtrl);
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
GuiMLTextEditCtrl::GuiMLTextEditCtrl()
|
||||
{
|
||||
mEscapeCommand = StringTable->insert( "" );
|
||||
|
||||
mIsEditCtrl = true;
|
||||
|
||||
mActive = true;
|
||||
|
||||
mVertMoveAnchorValid = false;
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
GuiMLTextEditCtrl::~GuiMLTextEditCtrl()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
void 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->mBounds.extent.y, newExt.y );
|
||||
|
||||
Parent::resize( newPosition, newExt );
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
void GuiMLTextEditCtrl::initPersistFields()
|
||||
{
|
||||
Parent::initPersistFields();
|
||||
addField( "escapeCommand", TypeString, Offset( mEscapeCommand, GuiMLTextEditCtrl ) );
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Key events...
|
||||
bool GuiMLTextEditCtrl::onKeyDown(const GuiEvent& event)
|
||||
{
|
||||
setUpdate();
|
||||
//handle modifiers first...
|
||||
if (event.modifier & SI_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;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if ( event.modifier & SI_SHIFT )
|
||||
{
|
||||
switch ( event.keyCode )
|
||||
{
|
||||
case KEY_TAB:
|
||||
return( Parent::onKeyDown( event ) );
|
||||
}
|
||||
}
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
if (event.ascii != 0)
|
||||
{
|
||||
// Normal ascii keypress. Go ahead and add the chars...
|
||||
if (mSelectionActive == true)
|
||||
{
|
||||
mSelectionActive = false;
|
||||
deleteChars(mSelectionStart, mSelectionEnd);
|
||||
mCursorPosition = mSelectionStart;
|
||||
}
|
||||
|
||||
UTF16 inData[2] = { event.ascii, 0 };
|
||||
UTF8 *data = convertUTF16toUTF8( inData );
|
||||
U32 dataLen = dStrlen( data );
|
||||
|
||||
insertChars(data, dataLen, mCursorPosition);
|
||||
|
||||
delete [] data;
|
||||
|
||||
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);
|
||||
dglDrawLine(top + offset, bottom + offset, mProfile->mCursorColor);
|
||||
}
|
||||
}
|
||||
|
41
engine/gui/controls/guiMLTextEditCtrl.h
Executable file
41
engine/gui/controls/guiMLTextEditCtrl.h
Executable file
@ -0,0 +1,41 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// Torque Game Engine
|
||||
// Copyright (C) GarageGames.com, Inc.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#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();
|
||||
|
||||
void resize(const Point2I &newPosition, const Point2I &newExtent);
|
||||
|
||||
DECLARE_CONOBJECT(GuiMLTextEditCtrl);
|
||||
static void initPersistFields();
|
||||
};
|
||||
|
||||
#endif // _H_GUIMLTEXTEDITCTRL_
|
821
engine/gui/controls/guiPopUpCtrl.cc
Executable file
821
engine/gui/controls/guiPopUpCtrl.cc
Executable file
@ -0,0 +1,821 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// Torque Game Engine
|
||||
// Copyright (C) GarageGames.com, Inc.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "dgl/dgl.h"
|
||||
#include "gui/core/guiCanvas.h"
|
||||
#include "gui/controls/guiPopUpCtrl.h"
|
||||
#include "console/consoleTypes.h"
|
||||
#include "gui/core/guiDefaultControlRender.h"
|
||||
|
||||
IMPLEMENT_CONOBJECT(GuiPopUpMenuCtrl);
|
||||
|
||||
GuiPopUpBackgroundCtrl::GuiPopUpBackgroundCtrl(GuiPopUpMenuCtrl *ctrl, GuiPopUpTextListCtrl *textList)
|
||||
{
|
||||
mPopUpCtrl = ctrl;
|
||||
mTextList = textList;
|
||||
}
|
||||
|
||||
void GuiPopUpBackgroundCtrl::onMouseDown(const GuiEvent &event)
|
||||
{
|
||||
mTextList->setSelectedCell(Point2I(-1,-1));
|
||||
mPopUpCtrl->closePopUp();
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
GuiPopUpTextListCtrl::GuiPopUpTextListCtrl()
|
||||
{
|
||||
mPopUpCtrl = NULL;
|
||||
}
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
GuiPopUpTextListCtrl::GuiPopUpTextListCtrl(GuiPopUpMenuCtrl *ctrl)
|
||||
{
|
||||
mPopUpCtrl = ctrl;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
void GuiPopUpTextListCtrl::onCellSelected( Point2I /*cell*/ )
|
||||
{
|
||||
// Do nothing, the parent control will take care of everything...
|
||||
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
bool GuiPopUpTextListCtrl::onKeyDown(const GuiEvent &event)
|
||||
{
|
||||
//if the control is a dead end, don't process the input:
|
||||
if ( !mVisible || !mActive || !mAwake )
|
||||
return false;
|
||||
|
||||
//see if the key down is a <return> or not
|
||||
if ( event.modifier == 0 )
|
||||
{
|
||||
if ( event.keyCode == KEY_RETURN )
|
||||
{
|
||||
mPopUpCtrl->closePopUp();
|
||||
return true;
|
||||
}
|
||||
else if ( event.keyCode == KEY_ESCAPE )
|
||||
{
|
||||
mSelectedCell.set( -1, -1 );
|
||||
mPopUpCtrl->closePopUp();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
//otherwise, pass the event to it's parent
|
||||
return Parent::onKeyDown(event);
|
||||
}
|
||||
|
||||
void GuiPopUpTextListCtrl::onMouseDown(const GuiEvent &event)
|
||||
{
|
||||
Parent::onMouseDown(event);
|
||||
mPopUpCtrl->closePopUp();
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
void GuiPopUpTextListCtrl::onRenderCell(Point2I offset, Point2I cell, bool selected, bool mouseOver)
|
||||
{
|
||||
ColorI fontColor;
|
||||
mPopUpCtrl->getFontColor( fontColor, mList[cell.y].id, selected, mouseOver );
|
||||
|
||||
dglSetBitmapModulation( fontColor );
|
||||
dglDrawText( mFont, Point2I( offset.x + 4, offset.y ), mList[cell.y].text );
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
//------------------------------------------------------------------------------
|
||||
GuiPopUpMenuCtrl::GuiPopUpMenuCtrl(void)
|
||||
{
|
||||
VECTOR_SET_ASSOCIATION(mEntries);
|
||||
VECTOR_SET_ASSOCIATION(mSchemes);
|
||||
|
||||
mSelIndex = -1;
|
||||
mActive = true;
|
||||
mMaxPopupHeight = 200;
|
||||
mScrollDir = GuiScrollCtrl::None;
|
||||
mScrollCount = 0;
|
||||
mLastYvalue = 0;
|
||||
mIncValue = 0;
|
||||
mRevNum = 0;
|
||||
mInAction = false;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
GuiPopUpMenuCtrl::~GuiPopUpMenuCtrl()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
void GuiPopUpMenuCtrl::initPersistFields(void)
|
||||
{
|
||||
Parent::initPersistFields();
|
||||
|
||||
addField("maxPopupHeight", TypeS32, Offset(mMaxPopupHeight, GuiPopUpMenuCtrl));
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
ConsoleMethod( GuiPopUpMenuCtrl, add, void, 4, 5, "(string name, int idNum, int scheme=0)")
|
||||
{
|
||||
if ( argc > 4 )
|
||||
object->addEntry(argv[2],dAtoi(argv[3]),dAtoi(argv[4]));
|
||||
else
|
||||
object->addEntry(argv[2],dAtoi(argv[3]),0);
|
||||
}
|
||||
|
||||
ConsoleMethod( GuiPopUpMenuCtrl, addScheme, void, 6, 6, "(int id, ColorI fontColor, ColorI fontColorHL, ColorI fontColorSEL)")
|
||||
{
|
||||
ColorI fontColor, fontColorHL, fontColorSEL;
|
||||
U32 r, g, b;
|
||||
char buf[64];
|
||||
|
||||
dStrcpy( buf, argv[3] );
|
||||
char* temp = dStrtok( buf, " \0" );
|
||||
r = temp ? dAtoi( temp ) : 0;
|
||||
temp = dStrtok( NULL, " \0" );
|
||||
g = temp ? dAtoi( temp ) : 0;
|
||||
temp = dStrtok( NULL, " \0" );
|
||||
b = temp ? dAtoi( temp ) : 0;
|
||||
fontColor.set( r, g, b );
|
||||
|
||||
dStrcpy( buf, argv[4] );
|
||||
temp = dStrtok( buf, " \0" );
|
||||
r = temp ? dAtoi( temp ) : 0;
|
||||
temp = dStrtok( NULL, " \0" );
|
||||
g = temp ? dAtoi( temp ) : 0;
|
||||
temp = dStrtok( NULL, " \0" );
|
||||
b = temp ? dAtoi( temp ) : 0;
|
||||
fontColorHL.set( r, g, b );
|
||||
|
||||
dStrcpy( buf, argv[5] );
|
||||
temp = dStrtok( buf, " \0" );
|
||||
r = temp ? dAtoi( temp ) : 0;
|
||||
temp = dStrtok( NULL, " \0" );
|
||||
g = temp ? dAtoi( temp ) : 0;
|
||||
temp = dStrtok( NULL, " \0" );
|
||||
b = temp ? dAtoi( temp ) : 0;
|
||||
fontColorSEL.set( r, g, b );
|
||||
|
||||
object->addScheme( dAtoi( argv[2] ), fontColor, fontColorHL, fontColorSEL );
|
||||
}
|
||||
|
||||
ConsoleMethod( GuiPopUpMenuCtrl, setText, void, 3, 3, "(string text)")
|
||||
{
|
||||
object->setText(argv[2]);
|
||||
}
|
||||
|
||||
ConsoleMethod( GuiPopUpMenuCtrl, getText, const char*, 2, 2, "")
|
||||
{
|
||||
return object->getText();
|
||||
}
|
||||
|
||||
ConsoleMethod( GuiPopUpMenuCtrl, clear, void, 2, 2, "Clear the popup list.")
|
||||
{
|
||||
object->clear();
|
||||
}
|
||||
|
||||
ConsoleMethod(GuiPopUpMenuCtrl, sort, void, 2, 2, "Sort the list alphabetically.")
|
||||
{
|
||||
object->sort();
|
||||
}
|
||||
|
||||
ConsoleMethod( GuiPopUpMenuCtrl, forceOnAction, void, 2, 2, "")
|
||||
{
|
||||
object->onAction();
|
||||
}
|
||||
|
||||
ConsoleMethod( GuiPopUpMenuCtrl, forceClose, void, 2, 2, "")
|
||||
{
|
||||
object->closePopUp();
|
||||
}
|
||||
|
||||
ConsoleMethod( GuiPopUpMenuCtrl, getSelected, S32, 2, 2, "")
|
||||
{
|
||||
return object->getSelected();
|
||||
}
|
||||
|
||||
ConsoleMethod( GuiPopUpMenuCtrl, setSelected, void, 3, 3, "(int id)")
|
||||
{
|
||||
object->setSelected(dAtoi(argv[2]));
|
||||
}
|
||||
|
||||
ConsoleMethod( GuiPopUpMenuCtrl, getTextById, const char*, 3, 3, "(int id)")
|
||||
{
|
||||
return(object->getTextById(dAtoi(argv[2])));
|
||||
}
|
||||
|
||||
ConsoleMethod( GuiPopUpMenuCtrl, setEnumContent, void, 4, 4, "(string class, string enum)"
|
||||
"This fills the popup with a classrep's field enumeration type info.\n\n"
|
||||
"More of a helper function than anything. If console access to the field list is added, "
|
||||
"at least for the enumerated types, then this should go away..")
|
||||
{
|
||||
AbstractClassRep * classRep = AbstractClassRep::getClassList();
|
||||
|
||||
// walk the class list to get our class
|
||||
while(classRep)
|
||||
{
|
||||
if(!dStricmp(classRep->getClassName(), argv[2]))
|
||||
break;
|
||||
classRep = classRep->getNextClass();
|
||||
}
|
||||
|
||||
// get it?
|
||||
if(!classRep)
|
||||
{
|
||||
Con::warnf(ConsoleLogEntry::General, "failed to locate class rep for '%s'", argv[2]);
|
||||
return;
|
||||
}
|
||||
|
||||
// walk the fields to check for this one (findField checks StringTableEntry ptrs...)
|
||||
U32 i;
|
||||
for(i = 0; i < classRep->mFieldList.size(); i++)
|
||||
if(!dStricmp(classRep->mFieldList[i].pFieldname, argv[3]))
|
||||
break;
|
||||
|
||||
// found it?
|
||||
if(i == classRep->mFieldList.size())
|
||||
{
|
||||
Con::warnf(ConsoleLogEntry::General, "failed to locate field '%s' for class '%s'", argv[3], argv[2]);
|
||||
return;
|
||||
}
|
||||
|
||||
const AbstractClassRep::Field & field = classRep->mFieldList[i];
|
||||
|
||||
// check the type
|
||||
if(field.type != TypeEnum)
|
||||
{
|
||||
Con::warnf(ConsoleLogEntry::General, "field '%s' is not an enumeration for class '%s'", argv[3], argv[2]);
|
||||
return;
|
||||
}
|
||||
|
||||
AssertFatal(field.table, avar("enumeration '%s' for class '%s' with NULL ", argv[3], argv[2]));
|
||||
|
||||
// fill it
|
||||
for(i = 0; i < field.table->size; i++)
|
||||
object->addEntry(field.table->table[i].label, field.table->table[i].index);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
ConsoleMethod( GuiPopUpMenuCtrl, findText, S32, 3, 3, "(string text)"
|
||||
"Returns the position of the first entry containing the specified text.")
|
||||
{
|
||||
return( object->findText( argv[2] ) );
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
ConsoleMethod( GuiPopUpMenuCtrl, size, S32, 2, 2, "Get the size of the menu - the number of entries in it.")
|
||||
{
|
||||
return( object->getNumEntries() );
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
ConsoleMethod( GuiPopUpMenuCtrl, replaceText, void, 3, 3, "(bool doReplaceText)")
|
||||
{
|
||||
object->replaceText(dAtoi(argv[2]));
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
bool GuiPopUpMenuCtrl::onAdd()
|
||||
{
|
||||
if (!Parent::onAdd())
|
||||
return false;
|
||||
mSelIndex = -1;
|
||||
mReplaceText = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
void GuiPopUpMenuCtrl::onSleep()
|
||||
{
|
||||
Parent::onSleep();
|
||||
closePopUp(); // Tests in function.
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
void GuiPopUpMenuCtrl::clear()
|
||||
{
|
||||
mEntries.setSize(0);
|
||||
setText("");
|
||||
mSelIndex = -1;
|
||||
mRevNum = 0;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
static S32 QSORT_CALLBACK textCompare(const void *a,const void *b)
|
||||
{
|
||||
GuiPopUpMenuCtrl::Entry *ea = (GuiPopUpMenuCtrl::Entry *) (a);
|
||||
GuiPopUpMenuCtrl::Entry *eb = (GuiPopUpMenuCtrl::Entry *) (b);
|
||||
return (dStricmp(ea->buf, eb->buf));
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
void GuiPopUpMenuCtrl::sort()
|
||||
{
|
||||
dQsort((void *)&(mEntries[0]), mEntries.size(), sizeof(Entry), textCompare);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
void GuiPopUpMenuCtrl::addEntry(const char *buf, S32 id, U32 scheme)
|
||||
{
|
||||
Entry e;
|
||||
dStrcpy(e.buf, buf);
|
||||
e.id = id;
|
||||
e.scheme = scheme;
|
||||
|
||||
// see if there is a shortcut key
|
||||
char * cp = dStrchr(e.buf, '~');
|
||||
e.ascii = cp ? cp[1] : 0;
|
||||
|
||||
mEntries.push_back(e);
|
||||
|
||||
if ( mInAction && mTl )
|
||||
{
|
||||
// Add the new entry:
|
||||
mTl->addEntry( e.id, e.buf );
|
||||
repositionPopup();
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
void GuiPopUpMenuCtrl::addScheme( U32 id, ColorI fontColor, ColorI fontColorHL, ColorI fontColorSEL )
|
||||
{
|
||||
if ( !id )
|
||||
return;
|
||||
|
||||
Scheme newScheme;
|
||||
newScheme.id = id;
|
||||
newScheme.fontColor = fontColor;
|
||||
newScheme.fontColorHL = fontColorHL;
|
||||
newScheme.fontColorSEL = fontColorSEL;
|
||||
|
||||
mSchemes.push_back( newScheme );
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
S32 GuiPopUpMenuCtrl::getSelected()
|
||||
{
|
||||
if (mSelIndex == -1)
|
||||
return 0;
|
||||
return mEntries[mSelIndex].id;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
const char* GuiPopUpMenuCtrl::getTextById(S32 id)
|
||||
{
|
||||
for ( U32 i = 0; i < mEntries.size(); i++ )
|
||||
{
|
||||
if ( mEntries[i].id == id )
|
||||
return( mEntries[i].buf );
|
||||
}
|
||||
|
||||
return( "" );
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
S32 GuiPopUpMenuCtrl::findText( const char* text )
|
||||
{
|
||||
for ( U32 i = 0; i < mEntries.size(); i++ )
|
||||
{
|
||||
if ( dStrcmp( text, mEntries[i].buf ) == 0 )
|
||||
return( mEntries[i].id );
|
||||
}
|
||||
return( -1 );
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
void GuiPopUpMenuCtrl::setSelected(S32 id)
|
||||
{
|
||||
S32 i;
|
||||
for (i = 0; U32(i) < mEntries.size(); i++)
|
||||
if (id == mEntries[i].id)
|
||||
{
|
||||
//i = (mRevNum > i) ? mRevNum - i : i;
|
||||
mSelIndex = i;
|
||||
setText(mEntries[i].buf);
|
||||
|
||||
// Now perform the popup action:
|
||||
char idval[24];
|
||||
dSprintf( idval, sizeof(idval), "%d", mEntries[mSelIndex].id );
|
||||
Con::executef( this, 3, "onSelect", idval, mEntries[mSelIndex].buf );
|
||||
return;
|
||||
}
|
||||
|
||||
setText("");
|
||||
mSelIndex = -1;
|
||||
|
||||
Con::executef( this, 1, "onCancel" );
|
||||
|
||||
// Execute the popup console command:
|
||||
if ( mConsoleCommand[0] )
|
||||
{
|
||||
char buf[16];
|
||||
dSprintf(buf, sizeof(buf), "%d", getId());
|
||||
Con::setVariable("$ThisControl", buf);
|
||||
Con::evaluate( mConsoleCommand, false );
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
const char *GuiPopUpMenuCtrl::getScriptValue()
|
||||
{
|
||||
return getText();
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
void GuiPopUpMenuCtrl::onRender(Point2I offset, const RectI &updateRect)
|
||||
{
|
||||
updateRect;
|
||||
Point2I localStart;
|
||||
|
||||
if(mScrollDir != GuiScrollCtrl::None)
|
||||
autoScroll();
|
||||
|
||||
RectI r(offset, mBounds.extent);
|
||||
RectI buttonRect( ( r.point.x + r.extent.x ) - 18, r.point.y + 2, 16, r.extent.y - 4);
|
||||
if( mProfile->mBorder && mProfile->mOpaque)
|
||||
{
|
||||
if(mInAction)
|
||||
{
|
||||
renderFilledBorder(r, mProfile->mBorderColorHL, mProfile->mFillColor);
|
||||
renderFilledBorder( buttonRect, mProfile->mBorderColorHL, mProfile->mFillColorNA);
|
||||
}
|
||||
else
|
||||
{
|
||||
renderFilledBorder(r, mProfile->mBorderColorHL, mProfile->mFillColor);
|
||||
renderFilledBorder( buttonRect, mProfile->mBorderColorHL, mProfile->mFillColorNA);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
S32 txt_w = mFont->getStrWidth((const UTF8 *)mText);
|
||||
localStart.x = 0;
|
||||
localStart.y = (mBounds.extent.y - (mFont->getHeight())) / 2;
|
||||
|
||||
// align the horizontal
|
||||
switch (mProfile->mAlignment)
|
||||
{
|
||||
case GuiControlProfile::RightJustify:
|
||||
localStart.x = mBounds.extent.x - txt_w;
|
||||
break;
|
||||
case GuiControlProfile::CenterJustify:
|
||||
localStart.x = (mBounds.extent.x - txt_w) / 2;
|
||||
break;
|
||||
default: // GuiControlProfile::LeftJustify
|
||||
localStart.x = 4;
|
||||
break;
|
||||
}
|
||||
Point2I globalStart = localToGlobalCoord(localStart);
|
||||
dglSetBitmapModulation(mProfile->mFontColor);
|
||||
dglDrawText(mFont, globalStart, mText, mProfile->mFontColors);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
void GuiPopUpMenuCtrl::closePopUp()
|
||||
{
|
||||
if ( !mInAction )
|
||||
return;
|
||||
|
||||
// Get the selection from the text list:
|
||||
mSelIndex = mTl->getSelectedCell().y;
|
||||
mSelIndex = (mRevNum >= mSelIndex && mSelIndex != -1) ? mRevNum - mSelIndex : mSelIndex;
|
||||
if ( mSelIndex != -1 )
|
||||
{
|
||||
if(mReplaceText)
|
||||
setText( mEntries[mSelIndex].buf );
|
||||
setIntVariable( mEntries[mSelIndex].id );
|
||||
}
|
||||
|
||||
// Release the mouse:
|
||||
mInAction = false;
|
||||
mTl->mouseUnlock();
|
||||
|
||||
// Pop the background:
|
||||
getRoot()->popDialogControl(mBackground);
|
||||
|
||||
// Kill the popup:
|
||||
mBackground->removeObject( mSc );
|
||||
mTl->deleteObject();
|
||||
mSc->deleteObject();
|
||||
mBackground->deleteObject();
|
||||
|
||||
// Set this as the first responder:
|
||||
setFirstResponder();
|
||||
|
||||
// Now perform the popup action:
|
||||
if ( mSelIndex != -1 )
|
||||
{
|
||||
char idval[24];
|
||||
dSprintf( idval, sizeof(idval), "%d", mEntries[mSelIndex].id );
|
||||
Con::executef( this, 3, "onSelect", idval, mEntries[mSelIndex].buf );
|
||||
}
|
||||
else
|
||||
Con::executef( this, 1, "onCancel" );
|
||||
|
||||
// Execute the popup console command:
|
||||
if ( mConsoleCommand[0] )
|
||||
{
|
||||
char buf[16];
|
||||
dSprintf(buf, sizeof(buf), "%d", getId());
|
||||
Con::setVariable("$ThisControl", buf);
|
||||
Con::evaluate( mConsoleCommand, false );
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
bool GuiPopUpMenuCtrl::onKeyDown(const GuiEvent &event)
|
||||
{
|
||||
//if the control is a dead end, don't process the input:
|
||||
if ( !mVisible || !mActive || !mAwake )
|
||||
return false;
|
||||
|
||||
//see if the key down is a <return> or not
|
||||
if ( event.keyCode == KEY_RETURN && event.modifier == 0 )
|
||||
{
|
||||
onAction();
|
||||
return true;
|
||||
}
|
||||
|
||||
S32 selected = mSelIndex;
|
||||
switch( event.keyCode )
|
||||
{
|
||||
case KEY_RIGHT:
|
||||
case KEY_DOWN:
|
||||
if( ( selected + 1 ) < mEntries.size() )
|
||||
setSelected( mEntries[selected + 1].id );
|
||||
break;
|
||||
case KEY_UP:
|
||||
case KEY_LEFT:
|
||||
if( ( selected - 1 ) > 0 )
|
||||
setSelected( mEntries[selected - 1].id );
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
//otherwise, pass the event to its parent
|
||||
return Parent::onKeyDown( event );
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
void GuiPopUpMenuCtrl::onAction()
|
||||
{
|
||||
GuiControl *canCtrl = getParent();
|
||||
|
||||
addChildren();
|
||||
|
||||
GuiCanvas *root = getRoot();
|
||||
Point2I windowExt = root->mBounds.extent;
|
||||
|
||||
mBackground->mBounds.point.set(0,0);
|
||||
mBackground->mBounds.extent = root->mBounds.extent;
|
||||
|
||||
S32 textWidth = 0, width = mBounds.extent.x;
|
||||
const S32 menuSpace = 5;
|
||||
const S32 textSpace = 2;
|
||||
bool setScroll = false;
|
||||
|
||||
for(U32 i=0; i<mEntries.size(); ++i)
|
||||
if(S32(mFont->getStrWidth((const UTF8 *)mEntries[i].buf)) > textWidth)
|
||||
textWidth = mFont->getStrWidth((const UTF8 *)mEntries[i].buf);
|
||||
|
||||
if(textWidth > mBounds.extent.x)
|
||||
{
|
||||
textWidth +=10;
|
||||
width = textWidth;
|
||||
}
|
||||
|
||||
mTl->setCellSize(Point2I(width, mFont->getHeight()+3));
|
||||
|
||||
for(U32 j=0; j<mEntries.size(); ++j)
|
||||
mTl->addEntry(mEntries[j].id, mEntries[j].buf);
|
||||
|
||||
Point2I pointInGC = canCtrl->localToGlobalCoord(mBounds.point);
|
||||
Point2I scrollPoint(pointInGC.x, pointInGC.y + mBounds.extent.y);
|
||||
|
||||
//Calc max Y distance, so Scroll Ctrl will fit on window
|
||||
S32 maxYdis = windowExt.y - pointInGC.y - mBounds.extent.y - menuSpace;
|
||||
|
||||
//If scroll bars need to be added
|
||||
if(maxYdis < mTl->mBounds.extent.y + textSpace)
|
||||
{
|
||||
//Should we pop menu list above the button
|
||||
if(maxYdis < pointInGC.y - menuSpace)
|
||||
{
|
||||
reverseTextList();
|
||||
maxYdis = pointInGC.y - menuSpace;
|
||||
//Does the menu need a scroll bar
|
||||
if(maxYdis < mTl->mBounds.extent.y + textSpace)
|
||||
{
|
||||
//Calc for the width of the scroll bar
|
||||
if(textWidth >= width)
|
||||
width += 20;
|
||||
mTl->setCellSize(Point2I(width,mFont->getHeight() + textSpace));
|
||||
//Pop menu list above the button
|
||||
scrollPoint.set(pointInGC.x, menuSpace - 1);
|
||||
setScroll = true;
|
||||
}
|
||||
//No scroll bar needed
|
||||
else
|
||||
{
|
||||
maxYdis = mTl->mBounds.extent.y + textSpace;
|
||||
scrollPoint.set(pointInGC.x, pointInGC.y - maxYdis -1);
|
||||
}
|
||||
}
|
||||
//Scroll bar needed but Don't pop above button
|
||||
else
|
||||
{
|
||||
mRevNum = 0;
|
||||
//Calc for the width of the scroll bar
|
||||
if(textWidth >= width)
|
||||
width += 20;
|
||||
mTl->setCellSize(Point2I(width,mFont->getHeight() + textSpace));
|
||||
setScroll = true;
|
||||
}
|
||||
}
|
||||
//No scroll bar needed
|
||||
else
|
||||
maxYdis = mTl->mBounds.extent.y + textSpace;
|
||||
|
||||
//offset it from the background so it lines up properly
|
||||
mSc->mBounds.point = mBackground->globalToLocalCoord(scrollPoint);
|
||||
|
||||
if(mSc->mBounds.point.x + width > mBackground->mBounds.extent.x)
|
||||
if(width - mBounds.extent.x > 0)
|
||||
mSc->mBounds.point.x -= width - mBounds.extent.x;
|
||||
|
||||
mSc->mBounds.extent.set(width-1, maxYdis);
|
||||
|
||||
mSc->registerObject();
|
||||
mTl->registerObject();
|
||||
mBackground->registerObject();
|
||||
|
||||
mSc->addObject( mTl );
|
||||
mBackground->addObject( mSc );
|
||||
|
||||
// JDD - push the popup dialog to the topmost layer, so it's never under anything
|
||||
root->pushDialogControl(mBackground,99);
|
||||
|
||||
if ( setScroll )
|
||||
{
|
||||
if ( mSelIndex )
|
||||
mTl->scrollCellVisible( Point2I(0, mSelIndex));
|
||||
else
|
||||
mTl->scrollCellVisible( Point2I( 0, 0 ) );
|
||||
}
|
||||
|
||||
mTl->setFirstResponder();
|
||||
|
||||
mInAction = true;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
void GuiPopUpMenuCtrl::addChildren()
|
||||
{
|
||||
mTl = new GuiPopUpTextListCtrl(this);
|
||||
AssertFatal(mTl, "Failed to create the GuiPopUpTextListCtrl for the PopUpMenu");
|
||||
mTl->mProfile = mProfile;
|
||||
mTl->setField("noDuplicates", "false");
|
||||
|
||||
mSc = new GuiScrollCtrl;
|
||||
AssertFatal(mSc, "Failed to create the GuiScrollCtrl for the PopUpMenu");
|
||||
mSc->mProfile = mProfile;
|
||||
mSc->setField("hScrollBar","AlwaysOff");
|
||||
mSc->setField("vScrollBar","dynamic");
|
||||
|
||||
mBackground = new GuiPopUpBackgroundCtrl(this, mTl);
|
||||
AssertFatal(mBackground, "Failed to create the GuiBackgroundCtrl for the PopUpMenu");
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
void GuiPopUpMenuCtrl::repositionPopup()
|
||||
{
|
||||
if ( !mInAction || !mSc || !mTl )
|
||||
return;
|
||||
|
||||
// I'm not concerned with this right now...
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
void GuiPopUpMenuCtrl::reverseTextList()
|
||||
{
|
||||
mTl->clear();
|
||||
for(S32 i=mEntries.size()-1; i >= 0; --i)
|
||||
mTl->addEntry(mEntries[i].id, mEntries[i].buf);
|
||||
|
||||
// Don't lose the selected cell:
|
||||
if ( mSelIndex >= 0 )
|
||||
mTl->setSelectedCell( Point2I( 0, mEntries.size() - mSelIndex - 1 ) );
|
||||
|
||||
mRevNum = mEntries.size() - 1;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
bool GuiPopUpMenuCtrl::getFontColor( ColorI &fontColor, S32 id, bool selected, bool mouseOver )
|
||||
{
|
||||
U32 i;
|
||||
Entry* entry = NULL;
|
||||
for ( i = 0; i < mEntries.size(); i++ )
|
||||
{
|
||||
if ( mEntries[i].id == id )
|
||||
{
|
||||
entry = &mEntries[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ( !entry )
|
||||
return( false );
|
||||
|
||||
if ( entry->scheme != 0 )
|
||||
{
|
||||
// Find the entry's color scheme:
|
||||
for ( i = 0; i < mSchemes.size(); i++ )
|
||||
{
|
||||
if ( mSchemes[i].id == entry->scheme )
|
||||
{
|
||||
fontColor = selected ? mSchemes[i].fontColorSEL : mouseOver ? mSchemes[i].fontColorHL : mSchemes[i].fontColor;
|
||||
return( true );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Default color scheme...
|
||||
fontColor = selected ? mProfile->mFontColorSEL : mouseOver ? mProfile->mFontColorHL : mProfile->mFontColor;
|
||||
|
||||
return( true );
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
void GuiPopUpMenuCtrl::onMouseDown(const GuiEvent &event)
|
||||
{
|
||||
event;
|
||||
onAction();
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
void GuiPopUpMenuCtrl::onMouseUp(const GuiEvent &event)
|
||||
{
|
||||
event;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
void GuiPopUpMenuCtrl::setupAutoScroll(const GuiEvent &event)
|
||||
{
|
||||
GuiControl *parent = getParent();
|
||||
if (! parent) return;
|
||||
|
||||
Point2I mousePt = mSc->globalToLocalCoord(event.mousePoint);
|
||||
|
||||
mEventSave = event;
|
||||
|
||||
if(mLastYvalue != mousePt.y)
|
||||
{
|
||||
mScrollDir = GuiScrollCtrl::None;
|
||||
if(mousePt.y > mSc->mBounds.extent.y || mousePt.y < 0)
|
||||
{
|
||||
S32 topOrBottom = (mousePt.y > mSc->mBounds.extent.y) ? 1 : 0;
|
||||
mSc->scrollTo(0, topOrBottom);
|
||||
return;
|
||||
}
|
||||
|
||||
F32 percent = (F32)mousePt.y / (F32)mSc->mBounds.extent.y;
|
||||
if(percent > 0.7f && mousePt.y > mLastYvalue)
|
||||
{
|
||||
mIncValue = percent - 0.5f;
|
||||
mScrollDir = GuiScrollCtrl::DownArrow;
|
||||
}
|
||||
else if(percent < 0.3f && mousePt.y < mLastYvalue)
|
||||
{
|
||||
mIncValue = 0.5f - percent;
|
||||
mScrollDir = GuiScrollCtrl::UpArrow;
|
||||
}
|
||||
mLastYvalue = mousePt.y;
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
void GuiPopUpMenuCtrl::autoScroll()
|
||||
{
|
||||
mScrollCount += mIncValue;
|
||||
|
||||
while(mScrollCount > 1)
|
||||
{
|
||||
mSc->autoScroll(mScrollDir);
|
||||
mScrollCount -= 1;
|
||||
}
|
||||
mTl->onMouseMove(mEventSave);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
void GuiPopUpMenuCtrl::replaceText(S32 boolVal)
|
||||
{
|
||||
mReplaceText = boolVal;
|
||||
}
|
||||
// EOF //
|
131
engine/gui/controls/guiPopUpCtrl.h
Executable file
131
engine/gui/controls/guiPopUpCtrl.h
Executable file
@ -0,0 +1,131 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// Torque Game Engine
|
||||
// Copyright (C) GarageGames.com, Inc.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#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/controls/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 onMouseDown(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;
|
||||
};
|
||||
|
||||
struct Scheme
|
||||
{
|
||||
U32 id;
|
||||
ColorI fontColor;
|
||||
ColorI fontColorHL;
|
||||
ColorI fontColorSEL;
|
||||
};
|
||||
|
||||
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;
|
||||
|
||||
virtual void addChildren();
|
||||
virtual void repositionPopup();
|
||||
|
||||
public:
|
||||
GuiPopUpMenuCtrl(void);
|
||||
~GuiPopUpMenuCtrl();
|
||||
GuiScrollCtrl::Region mScrollDir;
|
||||
bool onAdd();
|
||||
void onSleep();
|
||||
void sort();
|
||||
void addEntry(const char *buf, S32 id, 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 onMouseDown(const GuiEvent &event);
|
||||
void onMouseUp(const GuiEvent &event);
|
||||
void setupAutoScroll(const GuiEvent &event);
|
||||
void autoScroll();
|
||||
bool onKeyDown(const GuiEvent &event);
|
||||
void reverseTextList();
|
||||
bool getFontColor(ColorI &fontColor, S32 id, bool selected, bool mouseOver);
|
||||
|
||||
S32 getSelected();
|
||||
void setSelected(S32 id);
|
||||
const char *getScriptValue();
|
||||
const char *getTextById(S32 id);
|
||||
S32 findText( const char* text );
|
||||
S32 getNumEntries() { return( mEntries.size() ); }
|
||||
void replaceText(S32);
|
||||
|
||||
DECLARE_CONOBJECT(GuiPopUpMenuCtrl);
|
||||
static void initPersistFields(void);
|
||||
};
|
||||
|
||||
#endif //_GUI_POPUPMENU_CTRL_H
|
18
engine/gui/controls/guiRadioCtrl.cc
Executable file
18
engine/gui/controls/guiRadioCtrl.cc
Executable file
@ -0,0 +1,18 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// Torque Game Engine
|
||||
// Copyright (C) GarageGames.com, Inc.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "console/console.h"
|
||||
#include "dgl/dgl.h"
|
||||
#include "gui/core/guiCanvas.h"
|
||||
#include "gui/controls/guiRadioCtrl.h"
|
||||
#include "console/consoleTypes.h"
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
IMPLEMENT_CONOBJECT(GuiRadioCtrl);
|
||||
|
||||
GuiRadioCtrl::GuiRadioCtrl()
|
||||
{
|
||||
mButtonType = ButtonTypeRadio;
|
||||
}
|
26
engine/gui/controls/guiRadioCtrl.h
Executable file
26
engine/gui/controls/guiRadioCtrl.h
Executable file
@ -0,0 +1,26 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// Torque Game Engine
|
||||
// Copyright (C) GarageGames.com, Inc.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef _GUIRADIOCTRL_H_
|
||||
#define _GUIRADIOCTRL_H_
|
||||
|
||||
#ifndef _GUICHECKBOXCTRLL_H_
|
||||
#include "gui/controls/guiCheckBoxCtrl.h"
|
||||
#endif
|
||||
|
||||
// the radio button renders exactly the same as the check box
|
||||
// the only difference is it sends messages to its siblings to
|
||||
// turn themselves off.
|
||||
|
||||
class GuiRadioCtrl : public GuiCheckBoxCtrl
|
||||
{
|
||||
typedef GuiCheckBoxCtrl Parent;
|
||||
|
||||
public:
|
||||
DECLARE_CONOBJECT(GuiRadioCtrl);
|
||||
GuiRadioCtrl();
|
||||
};
|
||||
|
||||
#endif //_GUI_RADIO_CTRL_H
|
319
engine/gui/controls/guiSliderCtrl.cc
Executable file
319
engine/gui/controls/guiSliderCtrl.cc
Executable file
@ -0,0 +1,319 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// Torque Game Engine
|
||||
// Copyright (C) GarageGames.com, Inc.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "console/console.h"
|
||||
#include "console/consoleTypes.h"
|
||||
#include "dgl/dgl.h"
|
||||
#include "dgl/gTexManager.h"
|
||||
#include "gui/controls/guiSliderCtrl.h"
|
||||
#include "gui/core/guiDefaultControlRender.h"
|
||||
#include "platform/event.h"
|
||||
|
||||
IMPLEMENT_CONOBJECT(GuiSliderCtrl);
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
GuiSliderCtrl::GuiSliderCtrl(void)
|
||||
{
|
||||
mActive = true;
|
||||
mRange.set( 0.0f, 1.0f );
|
||||
mTicks = 10;
|
||||
mValue = 0.5f;
|
||||
mThumbSize.set(8,20);
|
||||
mShiftPoint = 5;
|
||||
mShiftExtent = 10;
|
||||
mDisplayValue = false;
|
||||
mMouseOver = false;
|
||||
mDepressed = false;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
void GuiSliderCtrl::initPersistFields()
|
||||
{
|
||||
Parent::initPersistFields();
|
||||
|
||||
addGroup( "Slider" );
|
||||
addField("range", TypePoint2F, Offset(mRange, GuiSliderCtrl));
|
||||
addField("ticks", TypeS32, Offset(mTicks, GuiSliderCtrl));
|
||||
addField("value", TypeF32, Offset(mValue, GuiSliderCtrl));
|
||||
endGroup( "Slider" );
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
ConsoleMethod( GuiSliderCtrl, getValue, F32, 2, 2, "Get the position of the slider.")
|
||||
{
|
||||
return object->getValue();
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
void GuiSliderCtrl::setScriptValue(const char *val)
|
||||
{
|
||||
mValue = dAtof(val);
|
||||
updateThumb(mValue);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
bool GuiSliderCtrl::onWake()
|
||||
{
|
||||
if (! Parent::onWake())
|
||||
return false;
|
||||
|
||||
if(mThumbSize.y + mProfile->mFont->getHeight()-4 <= mBounds.extent.y)
|
||||
mDisplayValue = true;
|
||||
else
|
||||
mDisplayValue = false;
|
||||
|
||||
updateThumb( mValue, true );
|
||||
|
||||
mHasTexture = mProfile->constructBitmapArray() >= NumBitmaps;
|
||||
if( mHasTexture )
|
||||
mBitmapBounds = mProfile->mBitmapArrayRects.address();
|
||||
|
||||
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 (mBounds.extent.x >= mBounds.extent.y)
|
||||
value = F32(curMousePos.x-mShiftPoint) / F32(mBounds.extent.x-mShiftExtent)*(mRange.y-mRange.x) + mRange.x;
|
||||
else
|
||||
value = F32(curMousePos.y) / F32(mBounds.extent.y)*(mRange.y-mRange.x) + mRange.x;
|
||||
updateThumb(value);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
void GuiSliderCtrl::onMouseDragged(const GuiEvent &event)
|
||||
{
|
||||
if ( !mActive || !mAwake || !mVisible )
|
||||
return;
|
||||
|
||||
Point2I curMousePos = globalToLocalCoord(event.mousePoint);
|
||||
F32 value;
|
||||
if (mBounds.extent.x >= mBounds.extent.y)
|
||||
value = F32(curMousePos.x-mShiftPoint) / F32(mBounds.extent.x-mShiftExtent)*(mRange.y-mRange.x) + mRange.x;
|
||||
else
|
||||
value = F32(curMousePos.y) / F32(mBounds.extent.y)*(mRange.y-mRange.x) + mRange.x;
|
||||
|
||||
if (value > mRange.y)
|
||||
value = mRange.y;
|
||||
else if (value < mRange.x)
|
||||
value = mRange.x;
|
||||
|
||||
if ((event.modifier & SI_SHIFT) && mTicks > 2) {
|
||||
// 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");
|
||||
}
|
||||
|
||||
Con::executef(this, 1, "onMouseDragged");
|
||||
|
||||
updateThumb(value);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
void GuiSliderCtrl::onMouseUp(const GuiEvent &)
|
||||
{
|
||||
if ( !mActive || !mAwake || !mVisible )
|
||||
return;
|
||||
mDepressed = false;
|
||||
mouseUnlock();
|
||||
if (mConsoleCommand[0])
|
||||
{
|
||||
char buf[16];
|
||||
dSprintf(buf, sizeof(buf), "%d", getId());
|
||||
Con::setVariable("$ThisControl", buf);
|
||||
Con::evaluate(mConsoleCommand, false);
|
||||
}
|
||||
}
|
||||
|
||||
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(Canvas->mBounds.extent.x)*2.0f-1.0f)*0.8f;
|
||||
AUDIOHANDLE handle = alxCreateSource(mProfile->mSoundButtonOver);
|
||||
alxPlay(handle);
|
||||
}
|
||||
mMouseOver = true;
|
||||
}
|
||||
}
|
||||
|
||||
void GuiSliderCtrl::onMouseLeave(const GuiEvent &)
|
||||
{
|
||||
setUpdate();
|
||||
if(isMouseLocked())
|
||||
mDepressed = false;
|
||||
mMouseOver = false;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
void GuiSliderCtrl::updateThumb( F32 value, bool onWake )
|
||||
{
|
||||
mValue = value;
|
||||
// clamp the thumb to legal values
|
||||
if (mValue < mRange.x) mValue = mRange.x;
|
||||
if (mValue > mRange.y) mValue = mRange.y;
|
||||
|
||||
Point2I ext = mBounds.extent;
|
||||
ext.x -= ( mShiftExtent + mThumbSize.x ) / 2;
|
||||
// update the bounding thumb rect
|
||||
if (mBounds.extent.x >= mBounds.extent.y)
|
||||
{ // 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 && mAltConsoleCommand[0] )
|
||||
Con::evaluate( mAltConsoleCommand, false );
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
void GuiSliderCtrl::onRender(Point2I offset, const RectI &updateRect)
|
||||
{
|
||||
Point2I pos(offset.x+mShiftPoint, offset.y);
|
||||
Point2I ext(mBounds.extent.x - mShiftExtent, mBounds.extent.y);
|
||||
RectI thumb = mThumb;
|
||||
|
||||
|
||||
if( mHasTexture )
|
||||
{
|
||||
S32 index = SliderButtonNormal;
|
||||
if(mMouseOver)
|
||||
index = SliderButtonHighlight;
|
||||
dglClearBitmapModulation();
|
||||
|
||||
//left border
|
||||
dglDrawBitmapSR(mProfile->mTextureHandle, Point2I(offset.x,offset.y + (mBounds.extent.y / 4)), mBitmapBounds[SliderLineLeft]);
|
||||
//right border
|
||||
dglDrawBitmapSR(mProfile->mTextureHandle, Point2I(offset.x + mBounds.extent.x - mBitmapBounds[SliderLineRight].extent.x, offset.y + (mBounds.extent.y / 4)), 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 = mBounds.extent.x - mBitmapBounds[SliderLineLeft].extent.x - mBitmapBounds[SliderLineRight].extent.x;
|
||||
destRect.point.y = offset.y + (mBounds.extent.y / 4);
|
||||
destRect.extent.y = mBitmapBounds[SliderLineCenter].extent.y;
|
||||
|
||||
RectI stretchRect;
|
||||
stretchRect = mBitmapBounds[SliderLineCenter];
|
||||
stretchRect.inset(1,0);
|
||||
|
||||
dglDrawBitmapStretchSR(mProfile->mTextureHandle, destRect, stretchRect);
|
||||
|
||||
//draw our control slider button
|
||||
thumb.point += pos;
|
||||
dglDrawBitmapSR(mProfile->mTextureHandle,Point2I(thumb.point.x,offset.y),mBitmapBounds[index]);
|
||||
|
||||
}
|
||||
else if (mBounds.extent.x >= mBounds.extent.y)
|
||||
{
|
||||
Point2I mid(ext.x, ext.y/2);
|
||||
if(mDisplayValue)
|
||||
mid.set(ext.x, mThumbSize.y/2);
|
||||
|
||||
glColor4f(mProfile->mFontColor.red, mProfile->mFontColor.green, mProfile->mFontColor.blue, 1);
|
||||
glBegin(GL_LINES);
|
||||
// horz rule
|
||||
glVertex2i(pos.x, pos.y+mid.y);
|
||||
glVertex2i(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));
|
||||
glVertex2i(pos.x+x, pos.y+mid.y-mShiftPoint);
|
||||
glVertex2i(pos.x+x, pos.y+mid.y+mShiftPoint);
|
||||
}
|
||||
glEnd();
|
||||
}
|
||||
else
|
||||
{
|
||||
Point2I mid(ext.x/2, ext.y);
|
||||
|
||||
glColor4f(mProfile->mFontColor.red, mProfile->mFontColor.green, mProfile->mFontColor.blue, 1);
|
||||
glBegin(GL_LINES);
|
||||
// horz rule
|
||||
glVertex2i(pos.x+mid.x, pos.y);
|
||||
glVertex2i(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));
|
||||
glVertex2i(pos.x+mid.x-mShiftPoint, pos.y+y);
|
||||
glVertex2i(pos.x+mid.x+mShiftPoint, pos.y+y);
|
||||
}
|
||||
glEnd();
|
||||
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+mBounds.extent.x)
|
||||
textStart.x -=((textStart.x + txt_w) - (offset.x+mBounds.extent.x));
|
||||
|
||||
dglSetBitmapModulation(mProfile->mFontColor);
|
||||
dglDrawText(mProfile->mFont, textStart, buf, mProfile->mFontColors);
|
||||
}
|
||||
renderChildControls(offset, updateRect);
|
||||
}
|
||||
|
63
engine/gui/controls/guiSliderCtrl.h
Executable file
63
engine/gui/controls/guiSliderCtrl.h
Executable file
@ -0,0 +1,63 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// Torque Game Engine
|
||||
// Copyright (C) GarageGames.com, Inc.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef _GUISLIDERCTRL_H_
|
||||
#define _GUISLIDERCTRL_H_
|
||||
|
||||
#ifndef _GUICONTROL_H_
|
||||
#include "gui/core/guiControl.h"
|
||||
#endif
|
||||
|
||||
class GuiSliderCtrl : public GuiControl
|
||||
{
|
||||
private:
|
||||
typedef GuiControl Parent;
|
||||
|
||||
protected:
|
||||
Point2F mRange;
|
||||
U32 mTicks;
|
||||
F32 mValue;
|
||||
RectI mThumb;
|
||||
Point2I mThumbSize;
|
||||
void updateThumb( F32 value, bool onWake = false );
|
||||
S32 mShiftPoint;
|
||||
S32 mShiftExtent;
|
||||
bool mDisplayValue;
|
||||
bool mDepressed;
|
||||
bool mMouseOver;
|
||||
bool mHasTexture;
|
||||
|
||||
enum
|
||||
{
|
||||
SliderLineLeft = 0,
|
||||
SliderLineCenter,
|
||||
SliderLineRight,
|
||||
SliderButtonNormal,
|
||||
SliderButtonHighlight,
|
||||
NumBitmaps
|
||||
};
|
||||
RectI *mBitmapBounds;
|
||||
|
||||
public:
|
||||
//creation methods
|
||||
DECLARE_CONOBJECT(GuiSliderCtrl);
|
||||
GuiSliderCtrl();
|
||||
static void initPersistFields();
|
||||
|
||||
//Parental methods
|
||||
bool onWake();
|
||||
|
||||
void onMouseDown(const GuiEvent &event);
|
||||
void onMouseDragged(const GuiEvent &event);
|
||||
void onMouseUp(const GuiEvent &);
|
||||
void onMouseLeave(const GuiEvent &);
|
||||
void onMouseEnter(const GuiEvent &);
|
||||
F32 getValue() { return mValue; }
|
||||
void setScriptValue(const char *val);
|
||||
|
||||
void onRender(Point2I offset, const RectI &updateRect);
|
||||
};
|
||||
|
||||
#endif
|
204
engine/gui/controls/guiTabPageCtrl.cc
Executable file
204
engine/gui/controls/guiTabPageCtrl.cc
Executable file
@ -0,0 +1,204 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// Justin DuJardin
|
||||
// Gui Tab Page Control Class
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "console/consoleTypes.h"
|
||||
#include "console/console.h"
|
||||
#include "dgl/dgl.h"
|
||||
#include "gui/core/guiCanvas.h"
|
||||
#include "gui/controls/guiTabPageCtrl.h"
|
||||
#include "gui/core/guiDefaultControlRender.h"
|
||||
#include "gui/editor/guiEditCtrl.h"
|
||||
|
||||
IMPLEMENT_CONOBJECT(GuiTabPageCtrl);
|
||||
|
||||
GuiTabPageCtrl::GuiTabPageCtrl(void)
|
||||
{
|
||||
mBounds.extent.set(100, 200);
|
||||
mMinSize.set(50, 50);
|
||||
dStrcpy(mText,(UTF8*)"TabPage");
|
||||
mActive = true;
|
||||
}
|
||||
|
||||
void GuiTabPageCtrl::initPersistFields()
|
||||
{
|
||||
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 )
|
||||
{
|
||||
// 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 );
|
||||
}
|
||||
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
bool GuiTabPageCtrl::onKeyDown(const GuiEvent &event)
|
||||
{
|
||||
|
||||
if ((event.keyCode == KEY_TAB) && (event.modifier & SI_CTRL))
|
||||
{
|
||||
//find the next sibling window, and select it
|
||||
GuiControl *parent = getParent();
|
||||
if (parent)
|
||||
{
|
||||
GuiTabPageCtrl *firstWindow = NULL;
|
||||
iterator i;
|
||||
for (i = parent->begin(); i != parent->end(); i++)
|
||||
{
|
||||
GuiTabPageCtrl *ctrl = dynamic_cast<GuiTabPageCtrl *>(*i);
|
||||
if (ctrl && ctrl->getTabIndex() == mTabIndex + 1)
|
||||
{
|
||||
ctrl->selectWindow();
|
||||
return true;
|
||||
}
|
||||
else if (ctrl && ctrl->getTabIndex() == 0)
|
||||
{
|
||||
firstWindow = ctrl;
|
||||
}
|
||||
}
|
||||
//recycle from the beginning
|
||||
if (firstWindow != this)
|
||||
{
|
||||
firstWindow->selectWindow();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return Parent::onKeyDown(event);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
GuiControl::onRender( offset, updateRect );
|
||||
}
|
49
engine/gui/controls/guiTabPageCtrl.h
Executable file
49
engine/gui/controls/guiTabPageCtrl.h
Executable file
@ -0,0 +1,49 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// Justin DuJardin
|
||||
// Gui Tab Page Control Class
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef _GUITABPAGECTRL_H_
|
||||
#define _GUITABPAGECTRL_H_
|
||||
|
||||
#ifndef _GUITEXTCTRL_H_
|
||||
#include "gui/controls/guiTextCtrl.h"
|
||||
#endif
|
||||
|
||||
class GuiTabPageCtrl : public GuiTextCtrl
|
||||
{
|
||||
private:
|
||||
typedef GuiTextCtrl Parent;
|
||||
|
||||
Point2I mMinSize;
|
||||
S32 mTabIndex;
|
||||
|
||||
public:
|
||||
GuiTabPageCtrl();
|
||||
DECLARE_CONOBJECT(GuiTabPageCtrl);
|
||||
static void initPersistFields();
|
||||
|
||||
bool onWake(); ///< The page awakens (becomes active)!
|
||||
void onSleep(); ///< The page sleeps (zzzzZZ - becomes inactive)
|
||||
|
||||
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);
|
||||
|
||||
bool onKeyDown(const GuiEvent &event); ///< Called when a keyDown event occurs
|
||||
|
||||
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
|
198
engine/gui/controls/guiTextCtrl.cc
Executable file
198
engine/gui/controls/guiTextCtrl.cc
Executable file
@ -0,0 +1,198 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// Torque Game Engine
|
||||
// Copyright (C) GarageGames.com, Inc.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "console/consoleTypes.h"
|
||||
#include "console/console.h"
|
||||
#include "core/color.h"
|
||||
#include "gui/controls/guiTextCtrl.h"
|
||||
#include "dgl/dgl.h"
|
||||
#include "i18n/lang.h"
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
IMPLEMENT_CONOBJECT(GuiTextCtrl);
|
||||
|
||||
GuiTextCtrl::GuiTextCtrl()
|
||||
{
|
||||
//default fonts
|
||||
mInitialText = StringTable->insert("");
|
||||
mInitialTextID = StringTable->insert("");
|
||||
mText[0] = '\0';
|
||||
mMaxStrLen = GuiTextCtrl::MAX_STRING_LENGTH;
|
||||
}
|
||||
|
||||
ConsoleMethod( GuiTextCtrl, setText, void, 3, 3, "obj.setText( newText )" )
|
||||
{
|
||||
argc;
|
||||
object->setText( argv[2] );
|
||||
}
|
||||
|
||||
ConsoleMethod( GuiTextCtrl, setTextID, void, 3, 3, "obj.setTextID( newText )" )
|
||||
{
|
||||
argc;
|
||||
object->setTextID( argv[2] );
|
||||
}
|
||||
void GuiTextCtrl::initPersistFields()
|
||||
{
|
||||
Parent::initPersistFields();
|
||||
//addField( "text", TypeCaseString, Offset( mInitialText, GuiTextCtrl ) );
|
||||
addProtectedField("text", TypeCaseString, Offset(mInitialText, GuiTextCtrl), setText, getTextProperty, "");
|
||||
addField( "textID", TypeString, Offset( mInitialTextID, GuiTextCtrl ) );
|
||||
addField( "maxLength", TypeS32, Offset( mMaxStrLen, GuiTextCtrl ) );
|
||||
}
|
||||
|
||||
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- //
|
||||
|
||||
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
|
||||
setText(mInitialText);
|
||||
}
|
||||
|
||||
bool GuiTextCtrl::onWake()
|
||||
{
|
||||
if ( !Parent::onWake() )
|
||||
return false;
|
||||
|
||||
mFont = mProfile->mFont;
|
||||
AssertFatal(mFont, "GuiTextCtrl::onWake: invalid font in profile" );
|
||||
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
|
||||
if ( mProfile->mAutoSizeWidth )
|
||||
{
|
||||
if ( mProfile->mAutoSizeHeight )
|
||||
resize( mBounds.point, Point2I( mFont->getStrWidth((const UTF8 *) mText ), mFont->getHeight() + 4 ) );
|
||||
else
|
||||
resize( mBounds.point, Point2I( mFont->getStrWidth((const UTF8 *) mText ), mBounds.extent.y ) );
|
||||
}
|
||||
else if ( mProfile->mAutoSizeHeight )
|
||||
resize( mBounds.point, Point2I( mBounds.extent.x, mFont->getHeight() + 4 ) );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void GuiTextCtrl::onSleep()
|
||||
{
|
||||
Parent::onSleep();
|
||||
mFont = NULL;
|
||||
}
|
||||
|
||||
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- //
|
||||
|
||||
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';
|
||||
|
||||
//Make sure we have a font
|
||||
mProfile->incRefCount();
|
||||
mFont = mProfile->mFont;
|
||||
|
||||
//resize
|
||||
if (mProfile->mAutoSizeWidth)
|
||||
{
|
||||
if (mProfile->mAutoSizeHeight)
|
||||
resize(mBounds.point, Point2I(mFont->getStrWidth((const UTF8 *)mText), mFont->getHeight() + 4));
|
||||
else
|
||||
resize(mBounds.point, Point2I(mFont->getStrWidth((const UTF8 *)mText), mBounds.extent.y));
|
||||
}
|
||||
else if (mProfile->mAutoSizeHeight)
|
||||
{
|
||||
resize(mBounds.point, Point2I(mBounds.extent.x, mFont->getHeight() + 4));
|
||||
}
|
||||
|
||||
setVariable((char*)mText);
|
||||
setUpdate();
|
||||
|
||||
//decrement the profile referrence
|
||||
mProfile->decRefCount();
|
||||
}
|
||||
|
||||
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()
|
||||
{
|
||||
const char * var = getVariable();
|
||||
if(var && var[0] && dStricmp((char*)mText, var))
|
||||
setText(var);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
void GuiTextCtrl::onRender(Point2I offset, const RectI &updateRect)
|
||||
{
|
||||
|
||||
dglSetBitmapModulation( mProfile->mFontColor );
|
||||
renderJustifiedText(offset, mBounds.extent, (char*)mText);
|
||||
|
||||
//render the child controls
|
||||
renderChildControls(offset, updateRect);
|
||||
}
|
||||
|
||||
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- //
|
||||
|
||||
const char *GuiTextCtrl::getScriptValue()
|
||||
{
|
||||
return getText();
|
||||
}
|
||||
|
||||
void GuiTextCtrl::setScriptValue(const char *val)
|
||||
{
|
||||
setText(val);
|
||||
}
|
||||
|
||||
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- //
|
||||
// EOF //
|
69
engine/gui/controls/guiTextCtrl.h
Executable file
69
engine/gui/controls/guiTextCtrl.h
Executable file
@ -0,0 +1,69 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// Torque Game Engine
|
||||
// Copyright (C) GarageGames.com, Inc.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef _GUITEXTCTRL_H_
|
||||
#define _GUITEXTCTRL_H_
|
||||
|
||||
#ifndef _GFONT_H_
|
||||
#include "dgl/gFont.h"
|
||||
#endif
|
||||
#ifndef _GUITYPES_H_
|
||||
#include "gui/core/guiTypes.h"
|
||||
#endif
|
||||
#ifndef _GUICONTROL_H_
|
||||
#include "gui/core/guiControl.h"
|
||||
#endif
|
||||
|
||||
class GuiTextCtrl : public GuiControl
|
||||
{
|
||||
private:
|
||||
typedef GuiControl 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
|
||||
Resource<GFont> mFont;
|
||||
|
||||
public:
|
||||
|
||||
//creation methods
|
||||
DECLARE_CONOBJECT(GuiTextCtrl);
|
||||
GuiTextCtrl();
|
||||
static void initPersistFields();
|
||||
|
||||
//Parental methods
|
||||
bool onAdd();
|
||||
virtual bool onWake();
|
||||
virtual void onSleep();
|
||||
|
||||
//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* obj, const char* data) { static_cast<GuiTextCtrl*>(obj)->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 );
|
||||
|
||||
//Console methods
|
||||
const char *getScriptValue();
|
||||
void setScriptValue(const char *value);
|
||||
};
|
||||
|
||||
#endif //_GUI_TEXT_CONTROL_H_
|
1369
engine/gui/controls/guiTextEditCtrl.cc
Executable file
1369
engine/gui/controls/guiTextEditCtrl.cc
Executable file
File diff suppressed because it is too large
Load Diff
125
engine/gui/controls/guiTextEditCtrl.h
Executable file
125
engine/gui/controls/guiTextEditCtrl.h
Executable file
@ -0,0 +1,125 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// Torque Game Engine
|
||||
// Copyright (C) GarageGames.com, Inc.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#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 GuiTextEditCtrl : public GuiTextCtrl
|
||||
{
|
||||
private:
|
||||
typedef GuiTextCtrl Parent;
|
||||
|
||||
static U32 smNumAwake;
|
||||
|
||||
protected:
|
||||
|
||||
StringBuffer mTextBuffer;
|
||||
|
||||
StringTableEntry mValidateCommand;
|
||||
StringTableEntry mEscapeCommand;
|
||||
AudioProfile* mDeniedSound;
|
||||
|
||||
// for animating the cursor
|
||||
S32 mNumFramesElapsed;
|
||||
U32 mTimeLastCursorFlipped;
|
||||
ColorI mCursorColor;
|
||||
bool mCursorOn;
|
||||
|
||||
//Edit Cursor
|
||||
GuiCursor* mEditCursor;
|
||||
|
||||
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;
|
||||
S32 setCursorPos(const Point2I &offset);
|
||||
|
||||
bool mHistoryDirty;
|
||||
S32 mHistoryLast;
|
||||
S32 mHistoryIndex;
|
||||
S32 mHistorySize;
|
||||
bool mPasswordText;
|
||||
StringTableEntry mPasswordMask;
|
||||
|
||||
bool mSinkAllKeyEvents; // any non-ESC key is handled here or not at all
|
||||
UTF16 **mHistoryBuf;
|
||||
void updateHistory(StringBuffer *txt, bool moveIndex);
|
||||
|
||||
void playDeniedSound();
|
||||
void execConsoleCallback();
|
||||
|
||||
public:
|
||||
GuiTextEditCtrl();
|
||||
~GuiTextEditCtrl();
|
||||
DECLARE_CONOBJECT(GuiTextEditCtrl);
|
||||
static void initPersistFields();
|
||||
|
||||
bool onAdd();
|
||||
bool onWake();
|
||||
void onSleep();
|
||||
|
||||
void getText(char *dest); // dest must be of size
|
||||
// StructDes::MAX_STRING_LEN + 1
|
||||
bool initCursors();
|
||||
void getCursor(GuiCursor *&cursor, bool &showCursor, const GuiEvent &lastGuiEvent);
|
||||
|
||||
void setText(S32 tag);
|
||||
virtual void setText(const UTF8* txt);
|
||||
virtual void setText(const UTF16* txt);
|
||||
S32 getCursorPos() { return( mCursorPos ); }
|
||||
void reallySetCursorPos( const S32 newPos );
|
||||
|
||||
void selectAllText(); //*** DAW: Added
|
||||
void forceValidateText(); //*** DAW: Added
|
||||
const char *getScriptValue();
|
||||
void setScriptValue(const char *value);
|
||||
|
||||
bool onKeyDown(const GuiEvent &event);
|
||||
void onMouseDown(const GuiEvent &event);
|
||||
void onMouseDragged(const GuiEvent &event);
|
||||
void onMouseUp(const GuiEvent &event);
|
||||
|
||||
void onCopy(bool andCut);
|
||||
void onPaste();
|
||||
void onUndo();
|
||||
|
||||
virtual void setFirstResponder();
|
||||
virtual void onLoseFirstResponder();
|
||||
|
||||
void parentResized(const Point2I &oldParentExtent, const Point2I &newParentExtent);
|
||||
bool hasText();
|
||||
|
||||
void onStaticModified(const char* slotName);
|
||||
|
||||
void onPreRender();
|
||||
void onRender(Point2I offset, const RectI &updateRect);
|
||||
virtual void drawText( const RectI &drawRect, bool isFocused );
|
||||
};
|
||||
|
||||
#endif //_GUI_TEXTEDIT_CTRL_H
|
272
engine/gui/controls/guiTextEditSliderCtrl.cc
Executable file
272
engine/gui/controls/guiTextEditSliderCtrl.cc
Executable file
@ -0,0 +1,272 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// Torque Game Engine
|
||||
// Copyright (C) GarageGames.com, Inc.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "console/consoleTypes.h"
|
||||
#include "console/console.h"
|
||||
#include "dgl/dgl.h"
|
||||
#include "gui/core/guiCanvas.h"
|
||||
#include "gui/controls/guiTextEditSliderCtrl.h"
|
||||
|
||||
IMPLEMENT_CONOBJECT(GuiTextEditSliderCtrl);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
GuiTextEditSliderCtrl::~GuiTextEditSliderCtrl()
|
||||
{
|
||||
}
|
||||
|
||||
void GuiTextEditSliderCtrl::initPersistFields()
|
||||
{
|
||||
Parent::initPersistFields();
|
||||
|
||||
addField("format", TypeString, Offset(mFormat, GuiTextEditSliderCtrl));
|
||||
addField("range", TypePoint2F, Offset(mRange, GuiTextEditSliderCtrl));
|
||||
addField("increment", TypeF32, Offset(mIncAmount, GuiTextEditSliderCtrl));
|
||||
}
|
||||
|
||||
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];
|
||||
dSprintf(buf,sizeof(buf),mFormat, mValue);
|
||||
Parent::setText(buf);
|
||||
}
|
||||
|
||||
void GuiTextEditSliderCtrl::onMouseDown(const GuiEvent &event)
|
||||
{
|
||||
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(mBounds.point);
|
||||
|
||||
if(camPos.x > point.x + mBounds.extent.x - 14)
|
||||
{
|
||||
if(camPos.y > point.y + (mBounds.extent.y/2))
|
||||
{
|
||||
mValue -=mIncAmount;
|
||||
mTextAreaHit = ArrowDown;
|
||||
mMulInc = -0.15f;
|
||||
}
|
||||
else
|
||||
{
|
||||
mValue +=mIncAmount;
|
||||
mTextAreaHit = ArrowUp;
|
||||
mMulInc = 0.15f;
|
||||
}
|
||||
|
||||
checkRange();
|
||||
setValue();
|
||||
mouseLock();
|
||||
return;
|
||||
}
|
||||
Parent::onMouseDown(event);
|
||||
}
|
||||
|
||||
void GuiTextEditSliderCtrl::onMouseDragged(const GuiEvent &event)
|
||||
{
|
||||
if(mTextAreaHit == None || mTextAreaHit == Slider)
|
||||
{
|
||||
mTextAreaHit = Slider;
|
||||
GuiControl *parent = getParent();
|
||||
if(!parent)
|
||||
return;
|
||||
Point2I camPos = event.mousePoint;
|
||||
Point2I point = parent->localToGlobalCoord(mBounds.point);
|
||||
F32 maxDis = 100;
|
||||
F32 val;
|
||||
if(camPos.y < point.y)
|
||||
{
|
||||
if(point.y < maxDis)
|
||||
maxDis = 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 + mBounds.extent.y)
|
||||
{
|
||||
GuiCanvas *root = getRoot();
|
||||
val = root->mBounds.extent.y - (point.y + mBounds.extent.y);
|
||||
if(val < maxDis)
|
||||
maxDis = val;
|
||||
if( val > 0)
|
||||
mMulInc= -(float)(camPos.y - (point.y + mBounds.extent.y))/maxDis;
|
||||
else
|
||||
mMulInc = -1.0f;
|
||||
checkIncValue();
|
||||
return;
|
||||
}
|
||||
mTextAreaHit = None;
|
||||
Parent::onMouseDragged(event);
|
||||
}
|
||||
}
|
||||
|
||||
void GuiTextEditSliderCtrl::onMouseUp(const GuiEvent &event)
|
||||
{
|
||||
mMulInc = 0.0f;
|
||||
mouseUnlock();
|
||||
|
||||
// Let the parent have at pass the the mouseUp event
|
||||
Parent::onMouseUp(event);
|
||||
|
||||
// Now execute our "command" and update our "variable"
|
||||
execConsoleCallback();
|
||||
|
||||
mTextAreaHit = None;
|
||||
}
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
||||
Parent::onRender(offset, updateRect);
|
||||
|
||||
Point2I start(offset.x + mBounds.extent.x - 14, offset.y);
|
||||
Point2I midPoint(start.x + 7, start.y + (mBounds.extent.y/2));
|
||||
|
||||
dglDrawRectFill(Point2I(start.x+1,start.y+1), Point2I(start.x+13,start.y+mBounds.extent.y-1) , mProfile->mFillColor);
|
||||
|
||||
dglDrawLine(start, Point2I(start.x, start.y+mBounds.extent.y),mProfile->mFontColor);
|
||||
dglDrawLine(Point2I(start.x,midPoint.y),
|
||||
Point2I(start.x+14,midPoint.y),
|
||||
mProfile->mFontColor);
|
||||
|
||||
glColor3i(0,0,0);
|
||||
|
||||
glBegin(GL_TRIANGLES);
|
||||
if(mTextAreaHit == ArrowUp)
|
||||
{
|
||||
glVertex2i(midPoint.x, start.y+1);
|
||||
glVertex2i(start.x+11,midPoint.y-2);
|
||||
glVertex2i(start.x+3,midPoint.y-2);
|
||||
}
|
||||
else
|
||||
{
|
||||
glVertex2i(midPoint.x, start.y+2);
|
||||
glVertex2i(start.x+11,midPoint.y-1);
|
||||
glVertex2i(start.x+3,midPoint.y-1);
|
||||
}
|
||||
if(mTextAreaHit == ArrowDown)
|
||||
{
|
||||
glVertex2i(midPoint.x, start.y+mBounds.extent.y-1);
|
||||
glVertex2i(start.x+11,midPoint.y+3);
|
||||
glVertex2i(start.x+3,midPoint.y+3);
|
||||
}
|
||||
else
|
||||
{
|
||||
glVertex2i(midPoint.x, start.y+mBounds.extent.y-2);
|
||||
glVertex2i(start.x+11,midPoint.y+2);
|
||||
glVertex2i(start.x+3,midPoint.y+2);
|
||||
}
|
||||
glEnd();
|
||||
}
|
||||
|
||||
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++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
67
engine/gui/controls/guiTextEditSliderCtrl.h
Executable file
67
engine/gui/controls/guiTextEditSliderCtrl.h
Executable file
@ -0,0 +1,67 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// Torque Game Engine
|
||||
// Copyright (C) GarageGames.com, Inc.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#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
|
||||
{
|
||||
private:
|
||||
typedef GuiTextEditCtrl Parent;
|
||||
Point2F mRange;
|
||||
F32 mIncAmount;
|
||||
F32 mValue;
|
||||
F32 mIncCounter;
|
||||
F32 mMulInc;
|
||||
StringTableEntry mFormat;
|
||||
U32 mMouseDownTime;
|
||||
// max string len, must be less then or equal to 255
|
||||
public:
|
||||
enum CtrlArea
|
||||
{
|
||||
None,
|
||||
Slider,
|
||||
ArrowUp,
|
||||
ArrowDown
|
||||
};
|
||||
private:
|
||||
CtrlArea mTextAreaHit;
|
||||
public:
|
||||
GuiTextEditSliderCtrl();
|
||||
~GuiTextEditSliderCtrl();
|
||||
DECLARE_CONOBJECT(GuiTextEditSliderCtrl);
|
||||
static void initPersistFields();
|
||||
|
||||
void getText(char *dest); // dest must be of size
|
||||
// StructDes::MAX_STRING_LEN + 1
|
||||
|
||||
void setText(S32 tag);
|
||||
void setText(const char *txt);
|
||||
|
||||
void setValue();
|
||||
void checkRange();
|
||||
void checkIncValue();
|
||||
void timeInc(U32 elapseTime);
|
||||
|
||||
bool onKeyDown(const GuiEvent &event);
|
||||
void onMouseDown(const GuiEvent &event);
|
||||
void onMouseDragged(const GuiEvent &event);
|
||||
void onMouseUp(const GuiEvent &event);
|
||||
|
||||
|
||||
void onPreRender();
|
||||
void onRender(Point2I offset, const RectI &updateRect);
|
||||
|
||||
|
||||
};
|
||||
|
||||
#endif //_GUI_TEXTEDIT_CTRL_H
|
596
engine/gui/controls/guiTextListCtrl.cc
Executable file
596
engine/gui/controls/guiTextListCtrl.cc
Executable file
@ -0,0 +1,596 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// Torque Game Engine
|
||||
// Copyright (C) GarageGames.com, Inc.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "platform/platform.h"
|
||||
#include "console/consoleTypes.h"
|
||||
#include "console/console.h"
|
||||
#include "dgl/dgl.h"
|
||||
#include "gui/controls/guiTextListCtrl.h"
|
||||
#include "gui/containers/guiScrollCtrl.h"
|
||||
#include "gui/core/guiDefaultControlRender.h"
|
||||
|
||||
IMPLEMENT_CONOBJECT(GuiTextListCtrl);
|
||||
|
||||
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 = dStricmp( 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;
|
||||
mEnumerate = false;
|
||||
mResizeCell = true;
|
||||
mSize.set(1, 0);
|
||||
mColumnOffsets.push_back(0);
|
||||
mFitParentWidth = true;
|
||||
mClipColumnText = false;
|
||||
}
|
||||
|
||||
void GuiTextListCtrl::initPersistFields()
|
||||
{
|
||||
Parent::initPersistFields();
|
||||
addField("enumerate", TypeBool, Offset(mEnumerate, GuiTextListCtrl));
|
||||
addField("resizeCell", TypeBool, Offset(mResizeCell, GuiTextListCtrl));
|
||||
addField("columns", TypeS32Vector, Offset(mColumnOffsets, GuiTextListCtrl));
|
||||
addField("fitParentWidth", TypeBool, Offset(mFitParentWidth, GuiTextListCtrl));
|
||||
addField("clipColumnText", TypeBool, Offset(mClipColumnText, GuiTextListCtrl));
|
||||
}
|
||||
|
||||
ConsoleMethod(GuiTextListCtrl, getSelectedId, S32, 2, 2, "Get the ID of the currently selected item.")
|
||||
{
|
||||
return object->getSelectedId();
|
||||
}
|
||||
|
||||
ConsoleMethod( GuiTextListCtrl, setSelectedById, void, 3, 3, "(int id)"
|
||||
"Finds the specified entry by id, then marks its row as selected.")
|
||||
{
|
||||
S32 index = object->findEntryById(dAtoi(argv[2]));
|
||||
if(index < 0)
|
||||
return ;
|
||||
|
||||
object->setSelectedCell(Point2I(0, index));
|
||||
}
|
||||
|
||||
ConsoleMethod( GuiTextListCtrl, setSelectedRow, void, 3, 3, "(int rowNum)"
|
||||
"Selects the specified row.")
|
||||
{
|
||||
object->setSelectedCell( Point2I( 0, dAtoi( argv[2] ) ) );
|
||||
}
|
||||
|
||||
ConsoleMethod( GuiTextListCtrl, getSelectedRow, S32, 2, 2, "getSelectedRow - returns row index (not ID)")
|
||||
{
|
||||
return object->getSelectedRow();
|
||||
}
|
||||
ConsoleMethod( GuiTextListCtrl, clearSelection, void, 2, 2, "Set the selection to nothing.")
|
||||
{
|
||||
object->setSelectedCell(Point2I(-1, -1));
|
||||
}
|
||||
|
||||
ConsoleMethod(GuiTextListCtrl, addRow, S32, 4, 5, "(int id, string text, int index=0)"
|
||||
"Returns row number of the new item.")
|
||||
{
|
||||
S32 ret = object->mList.size();
|
||||
if(argc < 5)
|
||||
object->addEntry(dAtoi(argv[2]), argv[3]);
|
||||
else
|
||||
object->insertEntry(dAtoi(argv[2]), argv[3], dAtoi(argv[4]));
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
ConsoleMethod( GuiTextListCtrl, setRowById, void, 4, 4, "(int id, string text)")
|
||||
{
|
||||
object->setEntry(dAtoi(argv[2]), argv[3]);
|
||||
}
|
||||
|
||||
ConsoleMethod( GuiTextListCtrl, sort, void, 3, 4, "(int columnID, bool increasing=false)"
|
||||
"Performs a standard (alphabetical) sort on the values in the specified column.")
|
||||
{
|
||||
if ( argc == 3 )
|
||||
object->sort(dAtoi(argv[2]));
|
||||
else
|
||||
object->sort( dAtoi( argv[2] ), dAtob( argv[3] ) );
|
||||
}
|
||||
|
||||
ConsoleMethod(GuiTextListCtrl, sortNumerical, void, 3, 4, "(int columnID, bool increasing=false)"
|
||||
"Perform a numerical sort on the values in the specified column.")
|
||||
{
|
||||
if ( argc == 3 )
|
||||
object->sortNumerical( dAtoi( argv[2] ) );
|
||||
else
|
||||
object->sortNumerical( dAtoi( argv[2] ), dAtob( argv[3] ) );
|
||||
}
|
||||
|
||||
ConsoleMethod( GuiTextListCtrl, clear, void, 2, 2, "Clear the list.")
|
||||
{
|
||||
object->clear();
|
||||
}
|
||||
|
||||
ConsoleMethod( GuiTextListCtrl, rowCount, S32, 2, 2, "Get the number of rows.")
|
||||
{
|
||||
return object->getNumEntries();
|
||||
}
|
||||
|
||||
ConsoleMethod( GuiTextListCtrl, getRowId, S32, 3, 3, "(int index)"
|
||||
"Get the row ID for an index.")
|
||||
{
|
||||
U32 index = dAtoi(argv[2]);
|
||||
if(index >= object->getNumEntries())
|
||||
return -1;
|
||||
|
||||
return object->mList[index].id;
|
||||
}
|
||||
|
||||
ConsoleMethod( GuiTextListCtrl, getRowTextById, const char*, 3, 3, "(int id)"
|
||||
"Get the text of a row with the specified id.")
|
||||
{
|
||||
S32 index = object->findEntryById(dAtoi(argv[2]));
|
||||
if(index < 0)
|
||||
return "";
|
||||
return object->mList[index].text;
|
||||
}
|
||||
|
||||
ConsoleMethod( GuiTextListCtrl, getRowNumById, S32, 3, 3, "(int id)"
|
||||
"Get the row number for a specified id.")
|
||||
{
|
||||
S32 index = object->findEntryById(dAtoi(argv[2]));
|
||||
if(index < 0)
|
||||
return -1;
|
||||
return index;
|
||||
}
|
||||
|
||||
ConsoleMethod( GuiTextListCtrl, getRowText, const char*, 3, 3, "(int index)"
|
||||
"Get the text of the row with the specified index.")
|
||||
{
|
||||
U32 index = dAtoi(argv[2]);
|
||||
if(index < 0 || index >= object->mList.size())
|
||||
return "";
|
||||
return object->mList[index].text;
|
||||
}
|
||||
|
||||
ConsoleMethod( GuiTextListCtrl, removeRowById, void, 3, 3,"(int id)"
|
||||
"Remove row with the specified id.")
|
||||
{
|
||||
object->removeEntry(dAtoi(argv[2]));
|
||||
}
|
||||
|
||||
ConsoleMethod( GuiTextListCtrl, removeRow, void, 3, 3, "(int index)"
|
||||
"Remove a row from the table, based on its index.")
|
||||
{
|
||||
U32 index = dAtoi(argv[2]);
|
||||
object->removeEntryByIndex(index);
|
||||
}
|
||||
|
||||
ConsoleMethod( GuiTextListCtrl, scrollVisible, void, 3, 3, "(int rowNum)"
|
||||
"Scroll so the specified row is visible.")
|
||||
{
|
||||
object->scrollCellVisible(Point2I(0, dAtoi(argv[2])));
|
||||
}
|
||||
|
||||
ConsoleMethod( GuiTextListCtrl, findTextIndex, S32, 3, 3, "(string needle)"
|
||||
"Find needle in the list, and return the row number it was found in.")
|
||||
{
|
||||
return( object->findEntryByText( argv[2] ) );
|
||||
}
|
||||
|
||||
ConsoleMethod( GuiTextListCtrl, setRowActive, void, 4, 4, "(int rowNum, bool active)"
|
||||
"Mark a specified row as active/not.")
|
||||
{
|
||||
object->setEntryActive( U32( dAtoi( argv[2] ) ), dAtob( argv[3] ) );
|
||||
}
|
||||
|
||||
ConsoleMethod( GuiTextListCtrl, isRowActive, bool, 3, 3, "(int rowNum)"
|
||||
"Is the specified row currently active?")
|
||||
{
|
||||
return( object->isEntryActive( U32( dAtoi( argv[2] ) ) ) );
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
void GuiTextListCtrl::onCellSelected(Point2I cell)
|
||||
{
|
||||
Con::executef(this, 3, "onSelect", Con::getIntArg(mList[cell.y].id), mList[cell.y].text);
|
||||
|
||||
if (mConsoleCommand[0])
|
||||
{
|
||||
char buf[16];
|
||||
dSprintf(buf, sizeof(buf), "%d", getId());
|
||||
Con::setVariable("$ThisControl", buf);
|
||||
Con::evaluate(mConsoleCommand, false);
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
dglSetBitmapModulation(mProfile->mFontColorHL);
|
||||
}
|
||||
else
|
||||
dglSetBitmapModulation(mouseOver ? mProfile->mFontColorHL : mProfile->mFontColor);
|
||||
}
|
||||
else
|
||||
dglSetBitmapModulation( 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 = dglGetClipRect();
|
||||
|
||||
RectI clipRect(pos, Point2I(mColumnOffsets[index+1] - mColumnOffsets[index] - 4, mCellSize.y));
|
||||
if(clipRect.intersect(saveClipRect))
|
||||
{
|
||||
clipped = true;
|
||||
dglSetClipRect(clipRect);
|
||||
}
|
||||
}
|
||||
|
||||
dglDrawTextN(mFont, pos, text, slen, mProfile->mFontColors);
|
||||
|
||||
if(clipped)
|
||||
dglSetClipRect(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(&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 );
|
||||
resize( mBounds.point, 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:
|
||||
if ( mAltConsoleCommand[0] )
|
||||
Con::evaluate( mAltConsoleCommand, false );
|
||||
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() )
|
||||
Con::executef( this, 2, "onDeleteKey", 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 );
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
93
engine/gui/controls/guiTextListCtrl.h
Executable file
93
engine/gui/controls/guiTextListCtrl.h
Executable file
@ -0,0 +1,93 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// Torque Game Engine
|
||||
// Copyright (C) GarageGames.com, Inc.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#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;
|
||||
|
||||
bool mEnumerate;
|
||||
bool mResizeCell;
|
||||
|
||||
protected:
|
||||
enum ScrollConst
|
||||
{
|
||||
UP = 0,
|
||||
DOWN = 1
|
||||
};
|
||||
enum {
|
||||
InvalidId = 0xFFFFFFFF
|
||||
};
|
||||
Vector<S32> mColumnOffsets;
|
||||
|
||||
bool mFitParentWidth;
|
||||
bool mClipColumnText;
|
||||
|
||||
U32 getRowWidth(Entry *row);
|
||||
void onCellSelected(Point2I cell);
|
||||
|
||||
public:
|
||||
GuiTextListCtrl();
|
||||
|
||||
DECLARE_CONOBJECT(GuiTextListCtrl);
|
||||
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
|
3824
engine/gui/controls/guiTreeViewCtrl.cc
Executable file
3824
engine/gui/controls/guiTreeViewCtrl.cc
Executable file
File diff suppressed because it is too large
Load Diff
404
engine/gui/controls/guiTreeViewCtrl.h
Executable file
404
engine/gui/controls/guiTreeViewCtrl.h
Executable file
@ -0,0 +1,404 @@
|
||||
#ifndef _GUI_TREEVIEWCTRL_H
|
||||
#define _GUI_TREEVIEWCTRL_H
|
||||
|
||||
#include "core/bitSet.h"
|
||||
#include "math/mRect.h"
|
||||
#include "gui/core/guiControl.h"
|
||||
#include "gui/core/guiArrayCtrl.h"
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
class GuiTreeViewCtrl : public GuiArrayCtrl
|
||||
{
|
||||
private:
|
||||
typedef GuiArrayCtrl Parent;
|
||||
|
||||
public:
|
||||
/// @section GuiControl_Intro Introduction
|
||||
/// @nosubgrouping
|
||||
|
||||
///
|
||||
struct Item
|
||||
{
|
||||
|
||||
enum ItemState
|
||||
{
|
||||
Selected = BIT(0),
|
||||
Expanded = BIT(1),
|
||||
Focus = BIT(2),
|
||||
MouseOverBmp = BIT(3),
|
||||
MouseOverText = BIT(4),
|
||||
InspectorData = BIT(5), ///< Set if we're representing some inspector
|
||||
/// info (ie, use mInspectorInfo, not mScriptInfo)
|
||||
VirtualParent = BIT(6), ///< 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).
|
||||
};
|
||||
|
||||
BitSet32 mState;
|
||||
SimObjectPtr<GuiControlProfile> mProfile;
|
||||
S16 mId;
|
||||
U16 mTabLevel;
|
||||
Item * mParent;
|
||||
Item * mChild;
|
||||
Item * mNext;
|
||||
Item * mPrevious;
|
||||
|
||||
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( GuiControlProfile *pProfile );
|
||||
~Item();
|
||||
|
||||
struct ScriptTag
|
||||
{
|
||||
S8 mNormalImage;
|
||||
S8 mExpandedImage;
|
||||
char* mText;
|
||||
char* mValue;
|
||||
} mScriptInfo;
|
||||
struct InspectorTag
|
||||
{
|
||||
SimObjectPtr<SimObject> mObject;
|
||||
} mInspectorInfo;
|
||||
|
||||
/// @name Get Methods
|
||||
/// @{
|
||||
|
||||
///
|
||||
const S8 getNormalImage() const;
|
||||
const S8 getExpandedImage() const;
|
||||
char *getText();
|
||||
char *getValue();
|
||||
inline const S16 getID() const { return mId; };
|
||||
SimObject *getObject();
|
||||
const U32 getDisplayTextLength();
|
||||
const S32 getDisplayTextWidth(GFont *font);
|
||||
void getDisplayText(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);
|
||||
/// 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(char *txt);
|
||||
/// Set the items script value (data)
|
||||
void setValue(const char *val);
|
||||
/// Set the items virtual parent flag
|
||||
void setVirtualParent( bool value );
|
||||
/// @}
|
||||
|
||||
|
||||
/// @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.
|
||||
const bool isExpanded() const;
|
||||
|
||||
/// Returns true if an item is inspector data
|
||||
/// or false if it's just an item.
|
||||
inline const 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.
|
||||
const bool isParent() const;
|
||||
/// @}
|
||||
|
||||
/// @name Searching Methods
|
||||
/// @{
|
||||
|
||||
/// 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);
|
||||
/// @}
|
||||
|
||||
};
|
||||
|
||||
/// @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,
|
||||
Audio,
|
||||
Camera,
|
||||
fxFoliageReplicator,
|
||||
fxLight,
|
||||
fxShapeReplicator,
|
||||
fxSunLight,
|
||||
Hidden,
|
||||
Interior,
|
||||
Lightning,
|
||||
Lock1,
|
||||
Lock2,
|
||||
MissionArea,
|
||||
Particle,
|
||||
Path,
|
||||
Pathmarker,
|
||||
PhysicalArea,
|
||||
Precipitation,
|
||||
Shape,
|
||||
Sky,
|
||||
StaticShape,
|
||||
Sun,
|
||||
Terrain,
|
||||
Trigger,
|
||||
Water,
|
||||
Default,
|
||||
Icon31,
|
||||
Icon32
|
||||
};
|
||||
|
||||
enum mDragMidPointFlags
|
||||
{
|
||||
NomDragMidPoint,
|
||||
AbovemDragMidPoint,
|
||||
BelowmDragMidPoint
|
||||
};
|
||||
|
||||
///
|
||||
enum HitFlags
|
||||
{
|
||||
OnIndent = BIT(0),
|
||||
OnImage = BIT(1),
|
||||
OnText = BIT(2),
|
||||
OnRow = BIT(3),
|
||||
};
|
||||
|
||||
///
|
||||
enum BmpIndices
|
||||
{
|
||||
BmpDunno,
|
||||
BmpLastChild,
|
||||
BmpChild,
|
||||
BmpExp,
|
||||
BmpExpN,
|
||||
BmpExpP,
|
||||
BmpExpPN,
|
||||
BmpCon,
|
||||
BmpConN,
|
||||
BmpConP,
|
||||
BmpConPN,
|
||||
BmpLine,
|
||||
BmpGlow,
|
||||
};
|
||||
|
||||
|
||||
/// @}
|
||||
public:
|
||||
|
||||
///
|
||||
Vector<Item*> mItems;
|
||||
Vector<Item*> mVisibleItems;
|
||||
Vector<Item*> mSelectedItems;
|
||||
Vector<S32> mSelected; ///< Used for tracking stuff that was
|
||||
/// selected, but may not have been
|
||||
/// created at time of selection
|
||||
S32 mItemCount;
|
||||
Item * mItemFreeList; ///< We do our own free list, as we
|
||||
/// we want to be able to recycle
|
||||
/// item ids and do some other clever
|
||||
/// things.
|
||||
Item * mRoot;
|
||||
S32 mInstantGroup;
|
||||
S32 mMaxWidth;
|
||||
S32 mSelectedItem;
|
||||
S32 mDraggedToItem;
|
||||
S32 mTempItem;
|
||||
S32 mStart;
|
||||
BitSet32 mFlags;
|
||||
|
||||
protected:
|
||||
TextureHandle mIconTable[MaxIcons];
|
||||
|
||||
// for debugging
|
||||
bool mDebug;
|
||||
|
||||
S32 mTabSize;
|
||||
S32 mTextOffset;
|
||||
bool mFullRowSelect;
|
||||
S32 mItemHeight;
|
||||
bool mDestroyOnSleep;
|
||||
bool mSupportMouseDragging;
|
||||
bool mMultipleSelections;
|
||||
bool mDeleteObjectAllowed;
|
||||
bool mDragToItemAllowed;
|
||||
|
||||
S32 mOldDragY;
|
||||
S32 mCurrentDragCell;
|
||||
S32 mPreviousDragCell;
|
||||
S32 mDragMidPoint;
|
||||
bool mMouseDragged;
|
||||
|
||||
StringTableEntry mBitmapBase;
|
||||
TextureHandle mTexRollover;
|
||||
TextureHandle mTexSelected;
|
||||
|
||||
// Hack to get passed always recursively building tree EVERY TICK!
|
||||
S32 mTicksPassed;
|
||||
S32 mTreeRefreshInterval;
|
||||
|
||||
ColorI mAltFontColor;
|
||||
ColorI mAltFontColorHL;
|
||||
ColorI mAltFontColorSE;
|
||||
|
||||
SimObjectPtr<SimObject> mRootObject;
|
||||
|
||||
void destroyChildren(Item * item, Item * parent);
|
||||
void destroyItem(Item * item);
|
||||
void destroyTree();
|
||||
|
||||
void deleteItem(Item *item);
|
||||
|
||||
void buildItem(Item * item, U32 tabLevel, bool bForceFullUpdate = false);
|
||||
|
||||
bool hitTest(const Point2I & pnt, Item* & item, BitSet32 & flags);
|
||||
|
||||
virtual bool onVirtualParentBuild(Item *item, bool bForceFullUpdate = false);
|
||||
virtual bool onVirtualParentExpand(Item *item);
|
||||
virtual bool onVirtualParentCollapse(Item *item);
|
||||
virtual void onItemSelected( Item *item );
|
||||
|
||||
void addInspectorDataItem(Item *parent, SimObject *obj);
|
||||
|
||||
public:
|
||||
GuiTreeViewCtrl();
|
||||
virtual ~GuiTreeViewCtrl();
|
||||
|
||||
/// Used for syncing the mSelected and mSelectedItems lists.
|
||||
void syncSelection();
|
||||
|
||||
void lockSelection(bool lock);
|
||||
void hideSelection(bool hide);
|
||||
void addSelection(S32 itemId);
|
||||
|
||||
/// 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 * getItem(S32 itemId);
|
||||
Item * createItem(S32 icon);
|
||||
bool editItem( S32 itemId, const char* newText, const char* newValue );
|
||||
|
||||
// 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);
|
||||
void removeAllChildren(S32 itemId); // Remove all children of the given item
|
||||
|
||||
bool buildIconTable(const char * icons);
|
||||
|
||||
void setInstantGroup(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 );
|
||||
|
||||
void deleteSelection();
|
||||
void clearSelection();
|
||||
|
||||
S32 findItemByName(const char *name);
|
||||
S32 findItemByObjectId(S32 iObjId);
|
||||
|
||||
// GuiControl
|
||||
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 onMouseDragged(const GuiEvent &event);
|
||||
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);
|
||||
|
||||
// GuiArrayCtrl
|
||||
void onRenderCell(Point2I offset, Point2I cell, bool, bool);
|
||||
void onRender(Point2I offset, const RectI &updateRect);
|
||||
|
||||
static void initPersistFields();
|
||||
|
||||
void inspectObject(SimObject * obj, bool okToEdit);
|
||||
void buildVisibleTree(bool bForceFullUpdate = false);
|
||||
|
||||
DECLARE_CONOBJECT(GuiTreeViewCtrl);
|
||||
};
|
||||
|
||||
#endif
|
Reference in New Issue
Block a user