📄 guicontrol.cc
字号:
//-----------------------------------------------------------------------------
// Torque Game Engine
// Copyright (C) GarageGames.com, Inc.
//-----------------------------------------------------------------------------
#include "console/consoleTypes.h"
#include "console/console.h"
#include "console/consoleInternal.h"
#include "platform/event.h"
#include "dgl/gBitmap.h"
#include "dgl/dgl.h"
#include "sim/actionMap.h"
#include "gui/core/guiCanvas.h"
#include "gui/core/guiControl.h"
#include "gui/core/guiDefaultControlRender.h"
#include "gui/editor/guiEditCtrl.h"
//------------------------------------------------------------------------------
IMPLEMENT_CONOBJECT(GuiControl);
#ifdef TGE_RPG
IMPLEMENT_CONSOLETYPE(GuiControl);
IMPLEMENT_SETOBJECTTYPE(GuiControl);
IMPLEMENT_GETOBJECTTYPE(GuiControl);
#endif
//used to locate the next/prev responder when tab is pressed
GuiControl *GuiControl::smPrevResponder = NULL;
GuiControl *GuiControl::smCurResponder = NULL;
GuiEditCtrl *GuiControl::smEditorHandle = NULL;
bool GuiControl::smDesignTime = false;
GuiControl::GuiControl()
{
mLayer = 0;
mBounds.set(0, 0, 64, 64);
mMinExtent.set(8, 2); // MM: Reduced to 8x2 so GuiControl can be used as a seperator.
mProfile = NULL;
mConsoleVariable = StringTable->insert("");
mConsoleCommand = StringTable->insert("");
mAltConsoleCommand = StringTable->insert("");
mAcceleratorKey = StringTable->insert("");
mLangTableName = StringTable->insert("");
mLangTable = NULL;
mFirstResponder = NULL;
mVisible = true;
mActive = false;
mAwake = false;
mHorizSizing = horizResizeRight;
mVertSizing = vertResizeBottom;
mTooltipProfile = NULL;
mTooltip = StringTable->insert("");
#ifdef TGE_RPG
m_bAutoSize = false;
m_marginBottomRight.set(0,0);
m_marginTopLeft.set(0,0);
#endif
}
GuiControl::~GuiControl()
{
}
bool GuiControl::onAdd()
{
if(!Parent::onAdd())
return false;
const char *name = getName();
if(name && name[0] && getClassRep())
{
Namespace *parent = getClassRep()->getNameSpace();
if(Con::linkNamespaces(parent->mName, name))
mNameSpace = Con::lookupNamespace(name);
}
Sim::getGuiGroup()->addObject(this);
Con::executef(this, 1, "onAdd");
return true;
}
void GuiControl::onChildAdded( GuiControl *child )
{
// Base class does not make use of this
}
static EnumTable::Enums horzEnums[] =
{
{ GuiControl::horizResizeRight, "right" },
{ GuiControl::horizResizeWidth, "width" },
{ GuiControl::horizResizeLeft, "left" },
{ GuiControl::horizResizeCenter, "center" },
{ GuiControl::horizResizeRelative, "relative" }
};
static EnumTable gHorizSizingTable(5, &horzEnums[0]);
static EnumTable::Enums vertEnums[] =
{
{ GuiControl::vertResizeBottom, "bottom" },
{ GuiControl::vertResizeHeight, "height" },
{ GuiControl::vertResizeTop, "top" },
{ GuiControl::vertResizeCenter, "center" },
{ GuiControl::vertResizeRelative, "relative" }
};
static EnumTable gVertSizingTable(5, &vertEnums[0]);
void GuiControl::initPersistFields()
{
Parent::initPersistFields();
addGroup("Parent");
addField("Profile", TypeGuiProfile, Offset(mProfile, GuiControl));
addField("HorizSizing", TypeEnum, Offset(mHorizSizing, GuiControl), 1, &gHorizSizingTable);
addField("VertSizing", TypeEnum, Offset(mVertSizing, GuiControl), 1, &gVertSizingTable);
addField("Position", TypePoint2I, Offset(mBounds.point, GuiControl));
addField("Extent", TypePoint2I, Offset(mBounds.extent, GuiControl));
addField("MinExtent", TypePoint2I, Offset(mMinExtent, GuiControl));
#ifdef TGE_RPG
addField("marginTopLeft", TypePoint2I, Offset(m_marginTopLeft, GuiControl));
addField("marginBottomRight", TypePoint2I, Offset(m_marginBottomRight, GuiControl));
addField("autoSize", TypeBool, Offset(m_bAutoSize, GuiControl));
#endif
addField("Visible", TypeBool, Offset(mVisible, GuiControl));
addDepricatedField("Modal");
addDepricatedField("SetFirstResponder");
addField("Variable", TypeString, Offset(mConsoleVariable, GuiControl));
addField("Command", TypeString, Offset(mConsoleCommand, GuiControl));
addField("AltCommand", TypeString, Offset(mAltConsoleCommand, GuiControl));
addField("Accelerator", TypeString, Offset(mAcceleratorKey, GuiControl));
addField("tooltipprofile", TypeGuiProfile, Offset(mTooltipProfile, GuiControl));
addField("tooltip", TypeString, Offset(mTooltip, GuiControl));
endGroup("Parent");
#ifdef TGE_RPG
addGroup("Property");
addField("_x", TypeS32, Offset(mBounds.point.x, GuiControl));
addField("_y", TypeS32, Offset(mBounds.point.y, GuiControl));
addField("_w", TypeS32, Offset(mBounds.extent.x, GuiControl));
addField("_h", TypeS32, Offset(mBounds.extent.y, GuiControl));
//addField("_v", TypeBool, Offset(mVisible, GuiControl));
endGroup("Property");
#endif
addGroup("I18N");
addField("langTableMod", TypeString, Offset(mLangTableName, GuiControl));
endGroup("I18N");
}
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- //
LangTable * GuiControl::getGUILangTable()
{
if(mLangTable)
return mLangTable;
if(mLangTableName && *mLangTableName)
{
mLangTable = (LangTable *)getModLangTable((const UTF8*)mLangTableName);
return mLangTable;
}
GuiControl *parent = getParent();
if(parent)
return parent->getGUILangTable();
return NULL;
}
const UTF8 * GuiControl::getGUIString(S32 id)
{
LangTable *lt = getGUILangTable();
if(lt)
return lt->getString(id);
return NULL;
}
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- //
void GuiControl::addObject(SimObject *object)
{
GuiControl *ctrl = dynamic_cast<GuiControl *>(object);
if(!ctrl)
{
AssertWarn(0, "GuiControl::addObject: attempted to add NON GuiControl to set");
return;
}
if(object->getGroup() == this)
return;
Parent::addObject(object);
AssertFatal(!ctrl->isAwake(), "GuiControl::addObject: object is already awake before add");
if(mAwake)
ctrl->awaken();
// If we are a child, notify our parent that we've been removed
GuiControl *parent = ctrl->getParent();
if( parent )
parent->onChildAdded( ctrl );
}
void GuiControl::removeObject(SimObject *object)
{
AssertFatal(mAwake == static_cast<GuiControl*>(object)->isAwake(), "GuiControl::removeObject: child control wake state is bad");
if (mAwake)
static_cast<GuiControl*>(object)->sleep();
Parent::removeObject(object);
}
GuiControl *GuiControl::getParent()
{
SimObject *obj = getGroup();
if (GuiControl* gui = dynamic_cast<GuiControl*>(obj))
return gui;
return 0;
}
GuiCanvas *GuiControl::getRoot()
{
GuiControl *root = NULL;
GuiControl *parent = getParent();
while (parent)
{
root = parent;
parent = parent->getParent();
}
if (root)
return dynamic_cast<GuiCanvas*>(root);
else
return NULL;
}
void GuiControl::inspectPreApply()
{
// The canvas never sleeps
if(mAwake && dynamic_cast<GuiCanvas*>(this) == NULL )
{
onSleep(); // release all our resources.
mAwake = true;
}
}
void GuiControl::inspectPostApply()
{
// Shhhhhhh, you don't want to wake the canvas!
if(mAwake && dynamic_cast<GuiCanvas*>(this) == NULL )
{
mAwake = false;
onWake();
}
}
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- //
Point2I GuiControl::localToGlobalCoord(const Point2I &src)
{
Point2I ret = src;
ret += mBounds.point;
GuiControl *walk = getParent();
while(walk)
{
ret += walk->getPosition();
walk = walk->getParent();
}
return ret;
}
Point2I GuiControl::globalToLocalCoord(const Point2I &src)
{
Point2I ret = src;
ret -= mBounds.point;
GuiControl *walk = getParent();
while(walk)
{
ret -= walk->getPosition();
walk = walk->getParent();
}
return ret;
}
//----------------------------------------------------------------
void GuiControl::resize(const Point2I &newPosition, const Point2I &newExtent)
{
//call set update both before and after
setUpdate();
Point2I actualNewExtent = Point2I(getMax(mMinExtent.x, newExtent.x),
getMax(mMinExtent.y, newExtent.y));
iterator i;
for(i = begin(); i != end(); i++)
{
GuiControl *ctrl = static_cast<GuiControl *>(*i);
ctrl->parentResized(mBounds.extent, actualNewExtent);
}
mBounds.set(newPosition, actualNewExtent);
GuiControl *parent = getParent();
if (parent)
parent->childResized(this);
setUpdate();
}
void GuiControl::setPosition( const Point2I &newPosition )
{
resize( newPosition, mBounds.extent );
}
void GuiControl::setExtent( const Point2I &newExtent )
{
resize( mBounds.point, newExtent );
}
#ifdef TGE_RPG
void GuiControl::setRight( S32 newRight)
{
resize( Point2I(newRight - mBounds.extent.x, mBounds.point.y),
mBounds.extent );
}
void GuiControl::setRightBy( S32 newRight)
{
GuiControl* pParent = getParent();
if(pParent == NULL)
pParent = Canvas;
if(pParent == NULL)
return;
resize( Point2I( pParent->getWidth() - newRight - mBounds.extent.x, mBounds.point.y),
mBounds.extent );
}
void GuiControl::setBottom( S32 newBottom )
{
resize( Point2I( mBounds.point.x,newBottom - mBounds.extent.y ),
mBounds.extent );
}
void GuiControl::setBottomBy( S32 newBottom )
{
GuiControl* pParent = getParent();
if(pParent == NULL)
pParent = Canvas;
if(pParent == NULL)
return;
resize( Point2I( mBounds.point.x, pParent->getHeight() - newBottom - mBounds.extent.y ),
mBounds.extent );
}
#endif
void GuiControl::setLeft( S32 newLeft )
{
resize( Point2I( newLeft, mBounds.point.y), mBounds.extent );
}
void GuiControl::setTop( S32 newTop )
{
resize( Point2I( mBounds.point.x, newTop ), mBounds.extent );
}
void GuiControl::setWidth( S32 newWidth )
{
resize( mBounds.point, Point2I( newWidth, mBounds.extent.y ) );
}
void GuiControl::setHeight( S32 newHeight )
{
resize( mBounds.point, Point2I( mBounds.extent.x, newHeight ) );
}
void GuiControl::childResized(GuiControl *child)
{
child;
// default to do nothing...
}
void GuiControl::parentResized(const Point2I &oldParentExtent, const Point2I &newParentExtent)
{
Point2I newPosition = getPosition();
Point2I newExtent = getExtent();
S32 deltaX = newParentExtent.x - oldParentExtent.x;
S32 deltaY = newParentExtent.y - oldParentExtent.y;
if (mHorizSizing == horizResizeCenter)
newPosition.x = (newParentExtent.x - mBounds.extent.x) >> 1;
else if (mHorizSizing == horizResizeWidth)
newExtent.x += deltaX;
else if (mHorizSizing == horizResizeLeft)
newPosition.x += deltaX;
else if (mHorizSizing == horizResizeRelative && oldParentExtent.x != 0)
{
S32 newLeft = (newPosition.x * newParentExtent.x) / oldParentExtent.x;
S32 newRight = ((newPosition.x + newExtent.x) * newParentExtent.x) / oldParentExtent.x;
newPosition.x = newLeft;
newExtent.x = newRight - newLeft;
}
if (mVertSizing == vertResizeCenter)
newPosition.y = (newParentExtent.y - mBounds.extent.y) >> 1;
else if (mVertSizing == vertResizeHeight)
newExtent.y += deltaY;
else if (mVertSizing == vertResizeTop)
newPosition.y += deltaY;
else if(mVertSizing == vertResizeRelative && oldParentExtent.y != 0)
{
S32 newTop = (newPosition.y * newParentExtent.y) / oldParentExtent.y;
S32 newBottom = ((newPosition.y + newExtent.y) * newParentExtent.y) / oldParentExtent.y;
newPosition.y = newTop;
newExtent.y = newBottom - newTop;
}
resize(newPosition, newExtent);
}
//----------------------------------------------------------------
void GuiControl::onRender(Point2I offset, const RectI &updateRect)
{
RectI ctrlRect(offset, mBounds.extent);
//if opaque, fill the update rect with the fill color
if (mProfile->mOpaque)
dglDrawRectFill(ctrlRect, mProfile->mFillColor);
//if there's a border, draw the border
if (mProfile->mBorder)
renderBorder(ctrlRect, mProfile);
renderChildControls(offset, updateRect);
}
bool GuiControl::renderTooltip(Point2I cursorPos)
{
//*** Return immediately if we don't need to be here
if (!mAwake) return false;
if (dStrlen(mTooltip) == 0) return false;
GuiCanvas *root = getRoot();
if (!root) return false;
if (!mTooltipProfile)
mTooltipProfile = mProfile;
GFont *font = mTooltipProfile->mFont;
//Vars used:
//Screensize (for position check)
//Offset to get position of cursor
//textBounds for text extent.
Point2I screensize = Platform::getWindowSize();
Point2I offset = cursorPos;
Point2I textBounds;
S32 textWidth = font->getStrWidth(mTooltip);
//Offset below cursor image
offset.y += root->getCursorExtent().y;
//Create text bounds.
textBounds.x = textWidth+8;
textBounds.y = font->getHeight() + 4;
// Check position/width to make sure all of the tooltip will be rendered
// 5 is given as a buffer against the edge
if (screensize.x < offset.x + textBounds.x + 5)
offset.x = screensize.x - textBounds.x - 5;
//*** And ditto for the height
if(screensize.y < offset.y + textBounds.y + 5)
offset.y = cursorPos.y - textBounds.y - 5;
// Set rectangle for the box, and set the clip rectangle.
RectI rect(offset, textBounds);
dglSetClipRect(rect);
// Draw Filler bit, then border on top of that
dglDrawRectFill(rect, mTooltipProfile->mFillColor);
renderBorder(rect, mTooltipProfile);
//*** Draw the text centered in the tool tip box
dglSetBitmapModulation( mTooltipProfile->mFontColor );
Point2I start;
start.set( ( textBounds.x - textWidth) / 2, ( textBounds.y - font->getHeight() ) / 2 );
dglDrawText( font, start + offset, mTooltip, mProfile->mFontColors );
return true;
}
void GuiControl::renderChildControls(Point2I offset, const RectI &updateRect)
{
// offset is the upper-left corner of this control in screen coordinates
// updateRect is the intersection rectangle in screen coords of the control
// hierarchy. This can be set as the clip rectangle in most cases.
RectI clipRect = updateRect;
iterator i;
for(i = begin(); i != end(); i++)
{
GuiControl *ctrl = static_cast<GuiControl *>(*i);
if (ctrl->mVisible)
{
Point2I childPosition = offset + ctrl->getPosition();
RectI childClip(childPosition, ctrl->getExtent());
if (childClip.intersect(clipRect))
{
dglSetClipRect(childClip);
glDisable(GL_CULL_FACE);
ctrl->onRender(childPosition, childClip);
}
}
}
}
void GuiControl::setUpdateRegion(Point2I pos, Point2I ext)
{
Point2I upos = localToGlobalCoord(pos);
GuiCanvas *root = getRoot();
if (root)
{
root->addUpdateRegion(upos, ext);
}
}
void GuiControl::setUpdate()
{
setUpdateRegion(Point2I(0,0), mBounds.extent);
}
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- //
void GuiControl::awaken()
{
AssertFatal(!mAwake, "GuiControl::awaken: control is already awake");
if(mAwake)
return;
iterator i;
for(i = begin(); i != end(); i++)
{
GuiControl *ctrl = static_cast<GuiControl *>(*i);
AssertFatal(!ctrl->isAwake(), "GuiControl::awaken: child control is already awake");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -