Initial commit
This commit is contained in:
37
engine/gui/editor/guiControlListPopup.cc
Executable file
37
engine/gui/editor/guiControlListPopup.cc
Executable file
@ -0,0 +1,37 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// Torque Game Engine
|
||||
// Copyright (C) GarageGames.com, Inc.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "gui/controls/guiPopUpCtrl.h"
|
||||
|
||||
class GuiControlListPopUp : public GuiPopUpMenuCtrl
|
||||
{
|
||||
typedef GuiPopUpMenuCtrl Parent;
|
||||
public:
|
||||
bool onAdd();
|
||||
|
||||
DECLARE_CONOBJECT(GuiControlListPopUp);
|
||||
};
|
||||
|
||||
IMPLEMENT_CONOBJECT(GuiControlListPopUp);
|
||||
|
||||
bool GuiControlListPopUp::onAdd()
|
||||
{
|
||||
if(!Parent::onAdd())
|
||||
return false;
|
||||
clear();
|
||||
|
||||
for(AbstractClassRep *rep = AbstractClassRep::getClassList(); rep; rep = rep->getNextClass())
|
||||
{
|
||||
ConsoleObject *obj = rep->create();
|
||||
if(obj && dynamic_cast<GuiControl *>(obj))
|
||||
addEntry(rep->getClassName(), 0);
|
||||
delete obj;
|
||||
}
|
||||
|
||||
// We want to be alphabetical!
|
||||
sort();
|
||||
|
||||
return true;
|
||||
}
|
702
engine/gui/editor/guiDebugger.cc
Executable file
702
engine/gui/editor/guiDebugger.cc
Executable file
@ -0,0 +1,702 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// Torque Game Engine
|
||||
// Copyright (C) GarageGames.com, Inc.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "console/console.h"
|
||||
#include "dgl/dgl.h"
|
||||
#include "gui/core/guiCanvas.h"
|
||||
#include "gui/editor/guiDebugger.h"
|
||||
#include "core/stream.h"
|
||||
|
||||
IMPLEMENT_CONOBJECT(DbgFileView);
|
||||
|
||||
static const char* itoa(S32 i)
|
||||
{
|
||||
static char buf[32];
|
||||
dSprintf(buf, sizeof(buf), "%d", i);
|
||||
return buf;
|
||||
}
|
||||
|
||||
static const char* itoa2(S32 i)
|
||||
{
|
||||
static char buf[32];
|
||||
dSprintf(buf, sizeof(buf), "%d", i);
|
||||
return buf;
|
||||
}
|
||||
|
||||
DbgFileView::~DbgFileView()
|
||||
{
|
||||
clear();
|
||||
}
|
||||
|
||||
DbgFileView::DbgFileView()
|
||||
{
|
||||
VECTOR_SET_ASSOCIATION(mFileView);
|
||||
|
||||
mFileName = NULL;
|
||||
mPCFileName = NULL;
|
||||
mPCCurrentLine = -1;
|
||||
|
||||
mBlockStart = -1;
|
||||
mBlockEnd = -1;
|
||||
|
||||
mFindString[0] = '\0';
|
||||
mFindLineNumber = -1;
|
||||
|
||||
mSize.set(1, 0);
|
||||
}
|
||||
|
||||
ConsoleMethod(DbgFileView, setCurrentLine, void, 4, 4, "(int line, bool selected)"
|
||||
"Set the current highlighted line.")
|
||||
{
|
||||
object->setCurrentLine(dAtoi(argv[2]), dAtob(argv[3]));
|
||||
}
|
||||
|
||||
ConsoleMethod(DbgFileView, getCurrentLine, const char *, 2, 2, "()"
|
||||
"Get the currently executing file and line, if any.\n\n"
|
||||
"@returns A string containing the file, a tab, and then the line number."
|
||||
" Use getField() with this.")
|
||||
{
|
||||
S32 lineNum;
|
||||
const char *file = object->getCurrentLine(lineNum);
|
||||
char* ret = Con::getReturnBuffer(256);
|
||||
dSprintf(ret, sizeof(ret), "%s\t%d", file, lineNum);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ConsoleMethod(DbgFileView, open, bool, 3, 3, "(string filename)"
|
||||
"Open a file for viewing.\n\n"
|
||||
"@note This loads the file from the local system.")
|
||||
{
|
||||
return object->openFile(argv[2]);
|
||||
}
|
||||
|
||||
ConsoleMethod(DbgFileView, clearBreakPositions, void, 2, 2, "()"
|
||||
"Clear all break points in the current file.")
|
||||
{
|
||||
object->clearBreakPositions();
|
||||
}
|
||||
|
||||
ConsoleMethod(DbgFileView, setBreakPosition, void, 3, 3, "(int line)"
|
||||
"Set a breakpoint at the specified line.")
|
||||
{
|
||||
object->setBreakPosition(dAtoi(argv[2]));
|
||||
}
|
||||
|
||||
ConsoleMethod(DbgFileView, setBreak, void, 3, 3, "(int line)"
|
||||
"Set a breakpoint at the specified line.")
|
||||
{
|
||||
object->setBreakPointStatus(dAtoi(argv[2]), true);
|
||||
}
|
||||
|
||||
ConsoleMethod(DbgFileView, removeBreak, void, 3, 3, "(int line)"
|
||||
"Remove a breakpoint from the specified line.")
|
||||
{
|
||||
object->setBreakPointStatus(dAtoi(argv[2]), false);
|
||||
}
|
||||
|
||||
ConsoleMethod(DbgFileView, findString, bool, 3, 3, "(string findThis)"
|
||||
"Find the specified string in the currently viewed file and "
|
||||
"scroll it into view.")
|
||||
{
|
||||
return object->findString(argv[2]);
|
||||
}
|
||||
|
||||
//this value is the offset used in the ::onRender() method...
|
||||
static S32 gFileXOffset = 44;
|
||||
|
||||
void DbgFileView::AdjustCellSize()
|
||||
{
|
||||
if (! bool(mFont))
|
||||
return;
|
||||
S32 maxWidth = 1;
|
||||
for (U32 i = 0; i < mFileView.size(); i++)
|
||||
{
|
||||
S32 cellWidth = gFileXOffset + mFont->getStrWidth((const UTF8 *)mFileView[i].text);
|
||||
maxWidth = getMax(maxWidth, cellWidth);
|
||||
}
|
||||
|
||||
mCellSize.set(maxWidth, mFont->getHeight() + 2);
|
||||
setSize(mSize);
|
||||
}
|
||||
|
||||
bool DbgFileView::onWake()
|
||||
{
|
||||
if (! Parent::onWake())
|
||||
return false;
|
||||
|
||||
//clear the mouse over var
|
||||
mMouseOverVariable[0] = '\0';
|
||||
mbMouseDragging = false;
|
||||
|
||||
//adjust the cellwidth to the maximum line length
|
||||
AdjustCellSize();
|
||||
mSize.set(1, mFileView.size());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void DbgFileView::addLine(const char *string, U32 strLen)
|
||||
{
|
||||
// first compute the size
|
||||
U32 size = 1; // for null
|
||||
for(U32 i = 0; i < strLen; i++)
|
||||
{
|
||||
if(string[i] == '\t')
|
||||
size += 3;
|
||||
else if(string[i] != '\r')
|
||||
size++;
|
||||
}
|
||||
FileLine fl;
|
||||
fl.breakPosition = false;
|
||||
fl.breakOnLine = false;
|
||||
if(size)
|
||||
{
|
||||
fl.text = (char *) dMalloc(size);
|
||||
|
||||
U32 dstIndex = 0;
|
||||
for(U32 i = 0; i < strLen; i++)
|
||||
{
|
||||
if(string[i] == '\t')
|
||||
{
|
||||
fl.text[dstIndex] = ' ';
|
||||
fl.text[dstIndex + 1] = ' ';
|
||||
fl.text[dstIndex + 2] = ' ';
|
||||
dstIndex += 3;
|
||||
}
|
||||
else if(string[i] != '\r')
|
||||
fl.text[dstIndex++] = string[i];
|
||||
}
|
||||
fl.text[dstIndex] = 0;
|
||||
}
|
||||
else
|
||||
fl.text = NULL;
|
||||
mFileView.push_back(fl);
|
||||
}
|
||||
|
||||
void DbgFileView::clear()
|
||||
{
|
||||
for(Vector<FileLine>::iterator i = mFileView.begin(); i != mFileView.end(); i++)
|
||||
dFree(i->text);
|
||||
mFileView.clear();
|
||||
}
|
||||
|
||||
bool DbgFileView::findString(const char *text)
|
||||
{
|
||||
//make sure we have a valid string to find
|
||||
if (!text || !text[0])
|
||||
return false;
|
||||
|
||||
//see which line we start searching from
|
||||
S32 curLine = 0;
|
||||
bool searchAgain = false;
|
||||
if (mFindLineNumber >= 0 && !dStricmp(mFindString, text))
|
||||
{
|
||||
searchAgain = true;
|
||||
curLine = mFindLineNumber;
|
||||
}
|
||||
else
|
||||
mFindLineNumber = -1;
|
||||
|
||||
//copy the search text
|
||||
dStrncpy(mFindString, text, 255);
|
||||
S32 length = dStrlen(mFindString);
|
||||
|
||||
//loop through looking for the next instance
|
||||
while (curLine < mFileView.size())
|
||||
{
|
||||
char *curText;
|
||||
if (curLine == mFindLineNumber && mBlockStart >= 0)
|
||||
curText = &mFileView[curLine].text[mBlockStart + 1];
|
||||
else
|
||||
curText = &mFileView[curLine].text[0];
|
||||
|
||||
//search for the string (the hard way... - apparently dStrupr is broken...
|
||||
char *found = NULL;
|
||||
char *curTextPtr = curText;
|
||||
while (*curTextPtr != '\0')
|
||||
{
|
||||
if (!dStrnicmp(mFindString, curTextPtr, length))
|
||||
{
|
||||
found = curTextPtr;
|
||||
break;
|
||||
}
|
||||
else
|
||||
curTextPtr++;
|
||||
}
|
||||
|
||||
//did we find it?
|
||||
if (found)
|
||||
{
|
||||
//scroll first
|
||||
mFindLineNumber = curLine;
|
||||
scrollToLine(mFindLineNumber + 1);
|
||||
|
||||
//then hilite
|
||||
mBlockStart = (S32)(found - &mFileView[curLine].text[0]);
|
||||
mBlockEnd = mBlockStart + length;
|
||||
|
||||
return true;
|
||||
}
|
||||
else
|
||||
curLine++;
|
||||
}
|
||||
|
||||
//didn't find anything - reset the vars for the next search
|
||||
mBlockStart = -1;
|
||||
mBlockEnd = -1;
|
||||
mFindLineNumber = -1;
|
||||
|
||||
setSelectedCell(Point2I(-1, -1));
|
||||
return false;
|
||||
}
|
||||
|
||||
void DbgFileView::setCurrentLine(S32 lineNumber, bool setCurrentLine)
|
||||
{
|
||||
//update the line number
|
||||
if (setCurrentLine)
|
||||
{
|
||||
mPCFileName = mFileName;
|
||||
mPCCurrentLine = lineNumber;
|
||||
mBlockStart = -1;
|
||||
mBlockEnd = -1;
|
||||
if (lineNumber >= 0)
|
||||
scrollToLine(mPCCurrentLine);
|
||||
}
|
||||
else
|
||||
{
|
||||
scrollToLine(lineNumber);
|
||||
}
|
||||
}
|
||||
|
||||
const char* DbgFileView::getCurrentLine(S32 &lineNumber)
|
||||
{
|
||||
lineNumber = mPCCurrentLine;
|
||||
return mPCFileName;
|
||||
}
|
||||
|
||||
bool DbgFileView::openFile(const char *fileName)
|
||||
{
|
||||
if ((! fileName) || (! fileName[0]))
|
||||
return false;
|
||||
|
||||
StringTableEntry newFile = StringTable->insert(fileName);
|
||||
if (mFileName == newFile)
|
||||
return true;
|
||||
|
||||
U32 fileSize = ResourceManager->getSize(fileName);
|
||||
char *fileBuf;
|
||||
if (fileSize)
|
||||
{
|
||||
fileBuf = new char [fileSize+1];
|
||||
Stream *s = ResourceManager->openStream(fileName);
|
||||
if (s)
|
||||
{
|
||||
s->read(fileSize, fileBuf);
|
||||
ResourceManager->closeStream(s);
|
||||
fileBuf[fileSize] = '\0';
|
||||
}
|
||||
else
|
||||
{
|
||||
delete [] fileBuf;
|
||||
fileBuf = NULL;
|
||||
}
|
||||
}
|
||||
if (!fileSize || !fileBuf)
|
||||
{
|
||||
Con::printf("DbgFileView: unable to open file %s.", fileName);
|
||||
return false;
|
||||
}
|
||||
|
||||
//copy the file name
|
||||
mFileName = newFile;
|
||||
|
||||
//clear the old mFileView
|
||||
clear();
|
||||
setSize(Point2I(1, 0));
|
||||
|
||||
//begin reading and parsing at each '\n'
|
||||
char *parsePtr = fileBuf;
|
||||
for(;;) {
|
||||
char *tempPtr = dStrchr(parsePtr, '\n');
|
||||
if(tempPtr)
|
||||
addLine(parsePtr, tempPtr - parsePtr);
|
||||
else if(parsePtr[0])
|
||||
addLine(parsePtr, dStrlen(parsePtr));
|
||||
if(!tempPtr)
|
||||
break;
|
||||
parsePtr = tempPtr + 1;
|
||||
}
|
||||
//delete the buffer
|
||||
delete [] fileBuf;
|
||||
|
||||
//set the file size
|
||||
AdjustCellSize();
|
||||
setSize(Point2I(1, mFileView.size()));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void DbgFileView::scrollToLine(S32 lineNumber)
|
||||
{
|
||||
GuiControl *parent = getParent();
|
||||
if (! parent)
|
||||
return;
|
||||
|
||||
S32 yOffset = (lineNumber - 1) * mCellSize.y;
|
||||
|
||||
//see if the line is already visible
|
||||
if (! (yOffset + mBounds.point.y >= 0 && yOffset + mBounds.point.y < parent->mBounds.extent.y - mCellSize.y))
|
||||
{
|
||||
//reposition the control
|
||||
S32 newYOffset = getMin(0, getMax(parent->mBounds.extent.y - mBounds.extent.y, (mCellSize.y * 4) - yOffset));
|
||||
resize(Point2I(mBounds.point.x, newYOffset), mBounds.extent);
|
||||
}
|
||||
|
||||
//hilite the line
|
||||
cellSelected(Point2I(0, lineNumber - 1));
|
||||
}
|
||||
|
||||
S32 DbgFileView::findMouseOverChar(const char *text, S32 stringPosition)
|
||||
{
|
||||
static char tempBuf[512];
|
||||
char *bufPtr = &tempBuf[1];
|
||||
|
||||
// Handle the empty string correctly.
|
||||
if (text[0] == '\0') {
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Copy the line's text into the scratch buffer.
|
||||
dStrncpy(tempBuf, text, 512);
|
||||
|
||||
// Make sure we have a null terminator.
|
||||
tempBuf[511] = '\0';
|
||||
|
||||
// Loop over the characters...
|
||||
bool found = false;
|
||||
bool finished = false;
|
||||
do {
|
||||
// Note the current character, then replace it with EOL.
|
||||
char c = *bufPtr;
|
||||
*bufPtr = '\0';
|
||||
// Is the resulting string long enough to include the current
|
||||
// mouse position?
|
||||
if ((S32)mFont->getStrWidth((const UTF8 *)tempBuf) > stringPosition) {
|
||||
// Yep.
|
||||
// Restore the character.
|
||||
*bufPtr = c;
|
||||
// Set bufPtr to point to the char under the mouse.
|
||||
bufPtr--;
|
||||
// Bail.
|
||||
found = true;
|
||||
finished = true;
|
||||
}
|
||||
else {
|
||||
// Nope.
|
||||
// Restore the character.
|
||||
*bufPtr = c;
|
||||
// Move on to the next character.
|
||||
bufPtr++;
|
||||
// Bail if EOL.
|
||||
if (*bufPtr == '\0') finished = true;
|
||||
}
|
||||
} while (!finished);
|
||||
|
||||
// Did we find a character under the mouse?
|
||||
if (found) {
|
||||
// If so, return its position.
|
||||
return bufPtr - tempBuf;
|
||||
}
|
||||
// If not, return -1.
|
||||
else return -1;
|
||||
}
|
||||
|
||||
bool DbgFileView::findMouseOverVariable()
|
||||
{
|
||||
GuiCanvas *root = getRoot();
|
||||
AssertFatal(root, "Unable to get the root Canvas.");
|
||||
|
||||
Point2I curMouse = root->getCursorPos();
|
||||
Point2I pt = globalToLocalCoord(curMouse);
|
||||
|
||||
//find out which cell was hit
|
||||
Point2I cell((pt.x < 0 ? -1 : pt.x / mCellSize.x), (pt.y < 0 ? -1 : pt.y / mCellSize.y));
|
||||
if(cell.x >= 0 && cell.x < mSize.x && cell.y >= 0 && cell.y < mSize.y)
|
||||
{
|
||||
S32 stringPosition = pt.x - gFileXOffset;
|
||||
char tempBuf[256], *varNamePtr = &tempBuf[1];
|
||||
dStrcpy(tempBuf, mFileView[cell.y].text);
|
||||
|
||||
//find the current mouse over char
|
||||
S32 charNum = findMouseOverChar(mFileView[cell.y].text, stringPosition);
|
||||
if (charNum >= 0)
|
||||
{
|
||||
varNamePtr = &tempBuf[charNum];
|
||||
}
|
||||
else
|
||||
{
|
||||
mMouseOverVariable[0] = '\0';
|
||||
mMouseOverValue[0] = '\0';
|
||||
return false;
|
||||
}
|
||||
|
||||
//now make sure we can go from the current cursor mPosition to the beginning of a var name
|
||||
bool found = false;
|
||||
while (varNamePtr >= &tempBuf[0])
|
||||
{
|
||||
if (*varNamePtr == '%' || *varNamePtr == '$')
|
||||
{
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
else if ((dToupper(*varNamePtr) >= 'A' && dToupper(*varNamePtr) <= 'Z') ||
|
||||
(*varNamePtr >= '0' && *varNamePtr <= '9') || *varNamePtr == '_' || *varNamePtr == ':')
|
||||
{
|
||||
varNamePtr--;
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//mouse wasn't over a possible variable name
|
||||
if (! found)
|
||||
{
|
||||
mMouseOverVariable[0] = '\0';
|
||||
mMouseOverValue[0] = '\0';
|
||||
return false;
|
||||
}
|
||||
|
||||
//set the var char start positions
|
||||
mMouseVarStart = varNamePtr - tempBuf;
|
||||
|
||||
//now copy the (possible) var name into the buf
|
||||
char *tempPtr = &mMouseOverVariable[0];
|
||||
|
||||
//copy the leading '%' or '$'
|
||||
*tempPtr++ = *varNamePtr++;
|
||||
|
||||
//now copy letters and numbers until the end of the name
|
||||
while ((dToupper(*varNamePtr) >= 'A' && dToupper(*varNamePtr) <= 'Z') ||
|
||||
(*varNamePtr >= '0' && *varNamePtr <= '9') || *varNamePtr == '_' || *varNamePtr == ':')
|
||||
{
|
||||
*tempPtr++ = *varNamePtr++;
|
||||
}
|
||||
*tempPtr = '\0';
|
||||
|
||||
//set the var char end positions
|
||||
mMouseVarEnd = varNamePtr - tempBuf;
|
||||
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void DbgFileView::clearBreakPositions()
|
||||
{
|
||||
for(Vector<FileLine>::iterator i = mFileView.begin(); i != mFileView.end(); i++)
|
||||
{
|
||||
i->breakPosition = false;
|
||||
i->breakOnLine = false;
|
||||
}
|
||||
}
|
||||
|
||||
void DbgFileView::setBreakPosition(U32 line)
|
||||
{
|
||||
if(line > mFileView.size())
|
||||
return;
|
||||
mFileView[line-1].breakPosition = true;
|
||||
}
|
||||
|
||||
void DbgFileView::setBreakPointStatus(U32 line, bool set)
|
||||
{
|
||||
if(line > mFileView.size())
|
||||
return;
|
||||
mFileView[line-1].breakOnLine = set;
|
||||
}
|
||||
|
||||
void DbgFileView::onPreRender()
|
||||
{
|
||||
setUpdate();
|
||||
char oldVar[256];
|
||||
dStrcpy(oldVar, mMouseOverVariable);
|
||||
bool found = findMouseOverVariable();
|
||||
if (found && mPCCurrentLine >= 0)
|
||||
{
|
||||
//send the query only when the var changes
|
||||
if (dStricmp(oldVar, mMouseOverVariable))
|
||||
Con::executef(2, "DbgSetCursorWatch", mMouseOverVariable);
|
||||
}
|
||||
else
|
||||
Con::executef(2, "DbgSetCursorWatch", "");
|
||||
}
|
||||
|
||||
void DbgFileView::onMouseDown(const GuiEvent &event)
|
||||
{
|
||||
if (! mActive)
|
||||
{
|
||||
Parent::onMouseDown(event);
|
||||
return;
|
||||
}
|
||||
|
||||
Point2I pt = globalToLocalCoord(event.mousePoint);
|
||||
bool doubleClick = (event.mouseClickCount > 1);
|
||||
|
||||
//find out which cell was hit
|
||||
Point2I cell((pt.x < 0 ? -1 : pt.x / mCellSize.x), (pt.y < 0 ? -1 : pt.y / mCellSize.y));
|
||||
if(cell.x >= 0 && cell.x < mSize.x && cell.y >= 0 && cell.y < mSize.y)
|
||||
{
|
||||
//if we clicked on the breakpoint mark
|
||||
if (pt.x >= 0 && pt.x <= 12)
|
||||
{
|
||||
//toggle the break point
|
||||
if (mFileView[cell.y].breakPosition)
|
||||
{
|
||||
if (mFileView[cell.y].breakOnLine)
|
||||
Con::executef(this, 2, "onRemoveBreakPoint", itoa(cell.y + 1));
|
||||
else
|
||||
Con::executef(this, 2, "onSetBreakPoint", itoa(cell.y + 1));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Point2I prevSelected = mSelectedCell;
|
||||
Parent::onMouseDown(event);
|
||||
mBlockStart= -1;
|
||||
mBlockEnd = -1;
|
||||
|
||||
//open the file view
|
||||
if (mSelectedCell.y == prevSelected.y && doubleClick && mMouseOverVariable[0])
|
||||
{
|
||||
Con::executef(this, 2, "onSetWatch", mMouseOverVariable);
|
||||
mBlockStart = mMouseVarStart;
|
||||
mBlockEnd = mMouseVarEnd;
|
||||
}
|
||||
else
|
||||
{
|
||||
S32 stringPosition = pt.x - gFileXOffset;
|
||||
|
||||
//find which character we're over
|
||||
S32 charNum = findMouseOverChar(mFileView[mSelectedCell.y].text, stringPosition);
|
||||
if (charNum >= 0)
|
||||
{
|
||||
//lock the mouse
|
||||
mouseLock();
|
||||
setFirstResponder();
|
||||
|
||||
//set the block hilite start and end
|
||||
mbMouseDragging = true;
|
||||
mMouseDownChar = charNum;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Parent::onMouseDown(event);
|
||||
}
|
||||
}
|
||||
|
||||
void DbgFileView::onMouseDragged(const GuiEvent &event)
|
||||
{
|
||||
if (mbMouseDragging)
|
||||
{
|
||||
Point2I pt = globalToLocalCoord(event.mousePoint);
|
||||
S32 stringPosition = pt.x - gFileXOffset;
|
||||
|
||||
//find which character we're over
|
||||
S32 charNum = findMouseOverChar(mFileView[mSelectedCell.y].text, stringPosition);
|
||||
if (charNum >= 0)
|
||||
{
|
||||
if (charNum < mMouseDownChar)
|
||||
{
|
||||
|
||||
mBlockEnd = mMouseDownChar + 1;
|
||||
mBlockStart = charNum;
|
||||
}
|
||||
else
|
||||
{
|
||||
mBlockEnd = charNum + 1;
|
||||
mBlockStart = mMouseDownChar;
|
||||
}
|
||||
}
|
||||
|
||||
//otherwise, the cursor is past the end of the string
|
||||
else
|
||||
{
|
||||
mBlockStart = mMouseDownChar;
|
||||
mBlockEnd = dStrlen(mFileView[mSelectedCell.y].text) + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DbgFileView::onMouseUp(const GuiEvent &)
|
||||
{
|
||||
//unlock the mouse
|
||||
mouseUnlock();
|
||||
|
||||
mbMouseDragging = false;
|
||||
}
|
||||
|
||||
void DbgFileView::onRenderCell(Point2I offset, Point2I cell, bool selected, bool)
|
||||
{
|
||||
Point2I cellOffset = offset;
|
||||
cellOffset.x += 4;
|
||||
|
||||
//draw the break point marks
|
||||
if (mFileView[cell.y].breakOnLine)
|
||||
{
|
||||
dglSetBitmapModulation(mProfile->mFontColorHL);
|
||||
dglDrawText(mFont, cellOffset, "#");
|
||||
}
|
||||
else if (mFileView[cell.y].breakPosition)
|
||||
{
|
||||
dglSetBitmapModulation(mProfile->mFontColor);
|
||||
dglDrawText(mFont, cellOffset, "-");
|
||||
}
|
||||
cellOffset.x += 8;
|
||||
|
||||
//draw in the "current line" indicator
|
||||
if (mFileName == mPCFileName && (cell.y + 1 == mPCCurrentLine))
|
||||
{
|
||||
dglSetBitmapModulation(mProfile->mFontColorHL);
|
||||
dglDrawText(mFont, cellOffset, "=>");
|
||||
}
|
||||
|
||||
//by this time, the cellOffset has been incremented by 44 - the value of gFileXOffset
|
||||
cellOffset.x += 32;
|
||||
|
||||
//hilite the line if selected
|
||||
if (selected)
|
||||
{
|
||||
if (mBlockStart == -1)
|
||||
{
|
||||
dglDrawRectFill(RectI(cellOffset.x - 2, cellOffset.y - 3,
|
||||
mCellSize.x + 4, mCellSize.y + 6), mProfile->mFillColorHL);
|
||||
}
|
||||
else if (mBlockStart >= 0 && mBlockEnd > mBlockStart && mBlockEnd <= S32(dStrlen(mFileView[cell.y].text) + 1))
|
||||
{
|
||||
S32 startPos, endPos;
|
||||
char tempBuf[256];
|
||||
dStrcpy(tempBuf, mFileView[cell.y].text);
|
||||
|
||||
//get the end coord
|
||||
tempBuf[mBlockEnd] = '\0';
|
||||
endPos = mFont->getStrWidth((const UTF8 *)tempBuf);
|
||||
|
||||
//get the start coord
|
||||
tempBuf[mBlockStart] = '\0';
|
||||
startPos = mFont->getStrWidth((const UTF8 *)tempBuf);
|
||||
|
||||
//draw the hilite
|
||||
dglDrawRectFill(RectI(cellOffset.x + startPos, cellOffset.y - 3, endPos - startPos + 2, mCellSize.y + 6), mProfile->mFillColorHL);
|
||||
}
|
||||
}
|
||||
|
||||
//draw the line of text
|
||||
dglSetBitmapModulation(mFileView[cell.y].breakOnLine ? mProfile->mFontColorHL : mProfile->mFontColor);
|
||||
dglDrawText(mFont, cellOffset, mFileView[cell.y].text);
|
||||
}
|
82
engine/gui/editor/guiDebugger.h
Executable file
82
engine/gui/editor/guiDebugger.h
Executable file
@ -0,0 +1,82 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// Torque Game Engine
|
||||
// Copyright (C) GarageGames.com, Inc.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef _GUIDEBUGGER_H_
|
||||
#define _GUIDEBUGGER_H_
|
||||
|
||||
#ifndef _GUIARRAYCTRL_H_
|
||||
#include "gui/core/guiArrayCtrl.h"
|
||||
#endif
|
||||
|
||||
class DbgFileView : public GuiArrayCtrl
|
||||
{
|
||||
private:
|
||||
|
||||
typedef GuiArrayCtrl Parent;
|
||||
|
||||
struct FileLine
|
||||
{
|
||||
bool breakPosition;
|
||||
bool breakOnLine;
|
||||
char *text;
|
||||
};
|
||||
|
||||
Vector<FileLine> mFileView;
|
||||
|
||||
StringTableEntry mFileName;
|
||||
|
||||
void AdjustCellSize();
|
||||
|
||||
//used to display the program counter
|
||||
StringTableEntry mPCFileName;
|
||||
S32 mPCCurrentLine;
|
||||
|
||||
//vars used to highlight the selected line segment for copying
|
||||
bool mbMouseDragging;
|
||||
S32 mMouseDownChar;
|
||||
S32 mBlockStart;
|
||||
S32 mBlockEnd;
|
||||
|
||||
char mMouseOverVariable[256];
|
||||
char mMouseOverValue[256];
|
||||
S32 findMouseOverChar(const char *text, S32 stringPosition);
|
||||
bool findMouseOverVariable();
|
||||
S32 mMouseVarStart;
|
||||
S32 mMouseVarEnd;
|
||||
|
||||
//find vars
|
||||
char mFindString[256];
|
||||
S32 mFindLineNumber;
|
||||
|
||||
public:
|
||||
|
||||
DbgFileView();
|
||||
~DbgFileView();
|
||||
DECLARE_CONOBJECT(DbgFileView);
|
||||
|
||||
bool onWake();
|
||||
|
||||
void clear();
|
||||
void clearBreakPositions();
|
||||
|
||||
void setCurrentLine(S32 lineNumber, bool setCurrentLine);
|
||||
const char *getCurrentLine(S32 &lineNumber);
|
||||
bool openFile(const char *fileName);
|
||||
void scrollToLine(S32 lineNumber);
|
||||
void setBreakPointStatus(U32 lineNumber, bool value);
|
||||
void setBreakPosition(U32 line);
|
||||
void addLine(const char *text, U32 textLen);
|
||||
|
||||
bool findString(const char *text);
|
||||
|
||||
void onMouseDown(const GuiEvent &event);
|
||||
void onMouseDragged(const GuiEvent &event);
|
||||
void onMouseUp(const GuiEvent &event);
|
||||
|
||||
void onPreRender();
|
||||
void onRenderCell(Point2I offset, Point2I cell, bool selected, bool mouseOver);
|
||||
};
|
||||
|
||||
#endif //_GUI_DEBUGGER_H
|
1139
engine/gui/editor/guiEditCtrl.cc
Executable file
1139
engine/gui/editor/guiEditCtrl.cc
Executable file
File diff suppressed because it is too large
Load Diff
98
engine/gui/editor/guiEditCtrl.h
Executable file
98
engine/gui/editor/guiEditCtrl.h
Executable file
@ -0,0 +1,98 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// Torque Game Engine
|
||||
// Copyright (C) GarageGames.com, Inc.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef _GUIEDITCTRL_H_
|
||||
#define _GUIEDITCTRL_H_
|
||||
|
||||
#ifndef _GUICONTROL_H_
|
||||
#include "gui/core/guiControl.h"
|
||||
#endif
|
||||
|
||||
class GuiEditCtrl : public GuiControl
|
||||
{
|
||||
typedef GuiControl Parent;
|
||||
|
||||
Vector<GuiControl *> mSelectedControls;
|
||||
GuiControl* mCurrentAddSet;
|
||||
GuiControl* mContentControl;
|
||||
Point2I mLastMousePos;
|
||||
Point2I mSelectionAnchor;
|
||||
Point2I mGridSnap;
|
||||
Point2I mDragBeginPoint;
|
||||
Vector<Point2I> mDragBeginPoints;
|
||||
|
||||
// Sizing Cursors
|
||||
GuiCursor* mDefaultCursor;
|
||||
GuiCursor* mLeftRightCursor;
|
||||
GuiCursor* mUpDownCursor;
|
||||
GuiCursor* mNWSECursor;
|
||||
GuiCursor* mNESWCursor;
|
||||
GuiCursor* mMoveCursor;
|
||||
|
||||
enum mouseModes { Selecting, MovingSelection, SizingSelection, DragSelecting };
|
||||
enum sizingModes { sizingNone = 0, sizingLeft = 1, sizingRight = 2, sizingTop = 4, sizingBottom = 8 };
|
||||
|
||||
mouseModes mMouseDownMode;
|
||||
sizingModes mSizingMode;
|
||||
|
||||
public:
|
||||
GuiEditCtrl();
|
||||
DECLARE_CONOBJECT(GuiEditCtrl);
|
||||
|
||||
bool onWake();
|
||||
void onSleep();
|
||||
|
||||
void select(GuiControl *ctrl);
|
||||
void setRoot(GuiControl *ctrl);
|
||||
void setEditMode(bool value);
|
||||
S32 getSizingHitKnobs(const Point2I &pt, const RectI &box);
|
||||
void getDragRect(RectI &b);
|
||||
void drawNut(const Point2I &nut, ColorI &outlineColor, ColorI &nutColor);
|
||||
void drawNuts(RectI &box, ColorI &outlineColor, ColorI &nutColor);
|
||||
void onPreRender();
|
||||
void onRender(Point2I offset, const RectI &updateRect);
|
||||
void addNewControl(GuiControl *ctrl);
|
||||
bool selectionContains(GuiControl *ctrl);
|
||||
void setCurrentAddSet(GuiControl *ctrl);
|
||||
void setSelection(GuiControl *ctrl, bool inclusive = false);
|
||||
|
||||
// Sizing Cursors
|
||||
bool initCursors();
|
||||
void getCursor(GuiCursor *&cursor, bool &showCursor, const GuiEvent &lastGuiEvent);
|
||||
|
||||
|
||||
const Vector<GuiControl *> *getSelected() const { return &mSelectedControls; }
|
||||
const GuiControl *getAddSet() const { return mCurrentAddSet; }; //JDD
|
||||
|
||||
bool onKeyDown(const GuiEvent &event);
|
||||
void onMouseDown(const GuiEvent &event);
|
||||
void onMouseUp(const GuiEvent &event);
|
||||
void onMouseDragged(const GuiEvent &event);
|
||||
void onRightMouseDown(const GuiEvent &event);
|
||||
|
||||
enum Justification {
|
||||
JUSTIFY_LEFT,
|
||||
JUSTIFY_CENTER,
|
||||
JUSTIFY_RIGHT,
|
||||
JUSTIFY_TOP,
|
||||
JUSTIFY_BOTTOM,
|
||||
SPACING_VERTICAL,
|
||||
SPACING_HORIZONTAL
|
||||
};
|
||||
|
||||
void justifySelection( Justification j);
|
||||
void moveSelection(const Point2I &delta);
|
||||
void saveSelection(const char *filename);
|
||||
void loadSelection(const char *filename);
|
||||
void addSelection(S32 id);
|
||||
void removeSelection(S32 id);
|
||||
void deleteSelection();
|
||||
void clearSelection();
|
||||
void selectAll();
|
||||
void bringToFront();
|
||||
void pushToBack();
|
||||
};
|
||||
|
||||
#endif //_GUI_EDIT_CTRL_H
|
241
engine/gui/editor/guiFilterCtrl.cc
Executable file
241
engine/gui/editor/guiFilterCtrl.cc
Executable file
@ -0,0 +1,241 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// 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/editor/guiFilterCtrl.h"
|
||||
#include "platform/event.h"
|
||||
#include "math/mMath.h"
|
||||
|
||||
IMPLEMENT_CONOBJECT(GuiFilterCtrl);
|
||||
|
||||
GuiFilterCtrl::GuiFilterCtrl()
|
||||
{
|
||||
mControlPointRequest = 7;
|
||||
mFilter.setSize(7);
|
||||
identity();
|
||||
}
|
||||
|
||||
|
||||
void GuiFilterCtrl::initPersistFields()
|
||||
{
|
||||
Parent::initPersistFields();
|
||||
addField("controlPoints", TypeS32, Offset(mControlPointRequest, GuiFilterCtrl));
|
||||
addField("filter", TypeF32Vector, Offset(mFilter, GuiFilterCtrl));
|
||||
}
|
||||
|
||||
ConsoleMethod( GuiFilterCtrl, getValue, const char*, 2, 2, "Return a tuple containing all the values in the filter.")
|
||||
{
|
||||
argv;
|
||||
static char buffer[512];
|
||||
const Filter *filter = object->get();
|
||||
*buffer = 0;
|
||||
|
||||
for (U32 i=0; i < filter->size(); i++)
|
||||
{
|
||||
char value[32];
|
||||
dSprintf(value, 31, "%1.5f ", *(filter->begin()+i) );
|
||||
dStrcat(buffer, value);
|
||||
}
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
ConsoleMethod( GuiFilterCtrl, setValue, void, 3, 20, "(f1, f2, ...)"
|
||||
"Reset the filter to use the specified points, spread equidistantly across the domain.")
|
||||
{
|
||||
Filter filter;
|
||||
|
||||
argc -= 2;
|
||||
argv += 2;
|
||||
|
||||
filter.set(argc, argv);
|
||||
object->set(filter);
|
||||
}
|
||||
|
||||
ConsoleMethod( GuiFilterCtrl, identity, void, 2, 2, "Reset the filtering.")
|
||||
{
|
||||
object->identity();
|
||||
}
|
||||
|
||||
bool GuiFilterCtrl::onWake()
|
||||
{
|
||||
if (!Parent::onWake())
|
||||
return false;
|
||||
|
||||
if (U32(mControlPointRequest) != mFilter.size())
|
||||
{
|
||||
mFilter.setSize(mControlPointRequest);
|
||||
identity();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void GuiFilterCtrl::identity()
|
||||
{
|
||||
S32 size = mFilter.size()-1;
|
||||
for (U32 i=0; S32(i) <= size; i++)
|
||||
mFilter[i] = (F32)i/(F32)size;
|
||||
}
|
||||
|
||||
|
||||
void GuiFilterCtrl::onMouseDown(const GuiEvent &event)
|
||||
{
|
||||
mouseLock();
|
||||
setFirstResponder();
|
||||
|
||||
Point2I p = globalToLocalCoord(event.mousePoint);
|
||||
|
||||
// determine which knot (offset same as in onRender)
|
||||
F32 w = F32(mBounds.extent.x-4) / F32(mFilter.size()-1);
|
||||
F32 val = (F32(p.x) + (w / 2.f)) / w;
|
||||
mCurKnot = S32(val);
|
||||
|
||||
mFilter[mCurKnot] = 1.0f - F32(getMin(getMax(0, p.y), mBounds.extent.y)/(F32)mBounds.extent.y);
|
||||
setUpdate();
|
||||
}
|
||||
|
||||
|
||||
void GuiFilterCtrl::onMouseDragged(const GuiEvent &event)
|
||||
{
|
||||
mouseLock();
|
||||
setFirstResponder();
|
||||
|
||||
Point2I p = globalToLocalCoord(event.mousePoint);
|
||||
mFilter[mCurKnot] = 1.0f - F32(getMin(getMax(0, p.y), mBounds.extent.y)/(F32)mBounds.extent.y);
|
||||
setUpdate();
|
||||
}
|
||||
|
||||
void GuiFilterCtrl::onMouseUp(const GuiEvent &)
|
||||
{
|
||||
mouseUnlock();
|
||||
if (mConsoleCommand[0])
|
||||
Con::evaluate(mConsoleCommand, false);
|
||||
}
|
||||
|
||||
void GuiFilterCtrl::onPreRender()
|
||||
{
|
||||
if(U32(mControlPointRequest) != mFilter.size())
|
||||
{
|
||||
mFilter.setSize(mControlPointRequest);
|
||||
identity();
|
||||
setUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
void GuiFilterCtrl::onRender(Point2I offset, const RectI &updateRect)
|
||||
{
|
||||
Point2I pos = offset;
|
||||
Point2I ext = mBounds.extent;
|
||||
|
||||
RectI r(pos, ext);
|
||||
dglDrawRectFill(r, ColorI(255,255,255));
|
||||
dglDrawRect(r, ColorI(0,0,0));
|
||||
|
||||
// shrink by 2 pixels
|
||||
pos.x += 2;
|
||||
pos.y += 2;
|
||||
ext.x -= 4;
|
||||
ext.y -= 4;
|
||||
|
||||
// draw the identity line
|
||||
glColor3f(0.9, 0.9, 0.9);
|
||||
glBegin(GL_LINES);
|
||||
glVertex2i(pos.x, pos.y+ext.y);
|
||||
glVertex2i(pos.x+ext.x, pos.y);
|
||||
glEnd();
|
||||
|
||||
// draw the curv
|
||||
glColor3f(0.4, 0.4, 0.4);
|
||||
glBegin(GL_LINE_STRIP);
|
||||
|
||||
F32 scale = 1.0f/F32(ext.x);
|
||||
for (U32 i=0; S32(i) < ext.x; i++)
|
||||
{
|
||||
F32 index = F32(i)*scale;
|
||||
S32 y = (S32)(ext.y*(1.0f-mFilter.getValue(index)));
|
||||
glVertex2i(pos.x+i, pos.y+y );
|
||||
}
|
||||
glEnd();
|
||||
|
||||
// draw the knots
|
||||
for (U32 k=0; k < mFilter.size(); k++)
|
||||
{
|
||||
RectI r;
|
||||
r.point.x = (S32)(((F32)ext.x/(F32)(mFilter.size()-1)*(F32)k));
|
||||
r.point.y = (S32)(ext.y - ((F32)ext.y * mFilter[k]));
|
||||
r.point += pos + Point2I(-2,-2);
|
||||
r.extent = Point2I(5,5);
|
||||
|
||||
dglDrawRectFill(r, ColorI(255,0,0));
|
||||
}
|
||||
|
||||
renderChildControls(offset, updateRect);
|
||||
}
|
||||
|
||||
|
||||
|
||||
//--------------------------------------
|
||||
void Filter::set(S32 argc, const char *argv[])
|
||||
{
|
||||
setSize(0);
|
||||
if (argc == 1)
|
||||
{ // in the form of one string "1.0 1.0 1.0"
|
||||
char list[1024];
|
||||
dStrcpy(list, *argv); // strtok modifies the string so we need to copy it
|
||||
char *value = dStrtok(list, " ");
|
||||
while (value)
|
||||
{
|
||||
push_back(dAtof(value));
|
||||
value = dStrtok(NULL, " ");
|
||||
}
|
||||
}
|
||||
else
|
||||
{ // in the form of seperate strings "1.0" "1.0" "1.0"
|
||||
for (; argc ; argc--, argv++)
|
||||
push_back(dAtof(*argv));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------
|
||||
F32 Filter::getValue(F32 x) const
|
||||
{
|
||||
if (size() < 2)
|
||||
return 0.0f;
|
||||
|
||||
x = mClampF(x, 0.0f, 1.0f);
|
||||
x *= F32(size()-1);
|
||||
|
||||
F32 p0,p1,p2,p3;
|
||||
S32 i1 = (S32)mFloor(x);
|
||||
S32 i2 = i1+1;
|
||||
F32 dt = x - F32(i1);
|
||||
|
||||
p1 = *(begin()+i1);
|
||||
p2 = *(begin()+i2);
|
||||
|
||||
if (i1 == 0)
|
||||
p0 = p1 + (p1 - p2);
|
||||
else
|
||||
p0 = *(begin()+i1-1);
|
||||
|
||||
if (i2 == S32(size()-1))
|
||||
p3 = p2 + (p2 - p1);
|
||||
else
|
||||
p3 = *(begin()+i2+1);
|
||||
|
||||
return mClampF( mCatmullrom(dt, p0, p1, p2, p3), 0.0f, 1.0f );
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
74
engine/gui/editor/guiFilterCtrl.h
Executable file
74
engine/gui/editor/guiFilterCtrl.h
Executable file
@ -0,0 +1,74 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// Torque Game Engine
|
||||
// Copyright (C) GarageGames.com, Inc.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef _GUIFILTERCTRL_H_
|
||||
#define _GUIFILTERCTRL_H_
|
||||
|
||||
#ifndef _GUICONTROL_H_
|
||||
#include "gui/core/guiControl.h"
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
//--------------------------------------
|
||||
// helper class
|
||||
class Filter: public Vector<F32>
|
||||
{
|
||||
public:
|
||||
Filter() : Vector<F32>(__FILE__, __LINE__) { }
|
||||
|
||||
void set(S32 argc, const char *argv[]);
|
||||
F32 getValue(F32 t) const;
|
||||
};
|
||||
|
||||
|
||||
//--------------------------------------
|
||||
class GuiFilterCtrl : public GuiControl
|
||||
{
|
||||
private:
|
||||
typedef GuiControl Parent;
|
||||
|
||||
S32 mControlPointRequest;
|
||||
S32 mCurKnot;
|
||||
Filter mFilter;
|
||||
|
||||
public:
|
||||
//creation methods
|
||||
DECLARE_CONOBJECT(GuiFilterCtrl);
|
||||
GuiFilterCtrl();
|
||||
static void initPersistFields();
|
||||
|
||||
//Parental methods
|
||||
bool onWake();
|
||||
|
||||
void onMouseDown(const GuiEvent &event);
|
||||
void onMouseDragged(const GuiEvent &event);
|
||||
void onMouseUp(const GuiEvent &);
|
||||
|
||||
F32 getValue(S32 n);
|
||||
const Filter* get() { return &mFilter; }
|
||||
void set(const Filter &f);
|
||||
S32 getNumControlPoints() {return mFilter.size(); }
|
||||
void identity();
|
||||
|
||||
void onPreRender();
|
||||
void onRender(Point2I offset, const RectI &updateRect );
|
||||
};
|
||||
|
||||
|
||||
inline F32 GuiFilterCtrl::getValue(S32 n)
|
||||
{
|
||||
S32 index = getMin(getMax(n,0), (S32)mFilter.size()-1);
|
||||
return mFilter[n];
|
||||
}
|
||||
|
||||
|
||||
inline void GuiFilterCtrl::set(const Filter &f)
|
||||
{
|
||||
mControlPointRequest = f.size();
|
||||
mFilter = f;
|
||||
}
|
||||
|
||||
#endif
|
350
engine/gui/editor/guiGraphCtrl.cc
Executable file
350
engine/gui/editor/guiGraphCtrl.cc
Executable file
@ -0,0 +1,350 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// Torque Game Engine
|
||||
// Copyright (C) GarageGames.com, Inc.
|
||||
//-----------------------------------------------------------------------------
|
||||
#include "console/console.h"
|
||||
#include "console/consoleTypes.h"
|
||||
#include "dgl/dgl.h"
|
||||
|
||||
#include "gui/editor/guiGraphCtrl.h"
|
||||
|
||||
IMPLEMENT_CONOBJECT(GuiGraphCtrl);
|
||||
|
||||
GuiGraphCtrl::GuiGraphCtrl()
|
||||
{
|
||||
|
||||
for(int i = 0; i < MaxPlots; i++)
|
||||
{
|
||||
mPlots[i].mAutoPlot = NULL;
|
||||
mPlots[i].mAutoPlotDelay = 0;
|
||||
mPlots[i].mGraphColor = ColorF(1.0, 1.0, 1.0);
|
||||
VECTOR_SET_ASSOCIATION(mPlots[i].mGraphData);
|
||||
mPlots[i].mGraphMax = 1;
|
||||
mPlots[i].mGraphType = Polyline;
|
||||
for(int j = 0; j < MaxDataPoints; j++)
|
||||
mPlots[i].mGraphData.push_front(0.0);
|
||||
}
|
||||
|
||||
AssertWarn(MaxPlots == 6, "Only 6 plot colors initialized. Update following code if you change MaxPlots.");
|
||||
|
||||
mPlots[0].mGraphColor = ColorF(1.0, 1.0, 1.0);
|
||||
mPlots[1].mGraphColor = ColorF(1.0, 0.0, 0.0);
|
||||
mPlots[2].mGraphColor = ColorF(0.0, 1.0, 0.0);
|
||||
mPlots[3].mGraphColor = ColorF(0.0, 0.0, 1.0);
|
||||
mPlots[4].mGraphColor = ColorF(0.0, 1.0, 1.0);
|
||||
mPlots[5].mGraphColor = ColorF(0.0, 0.0, 0.0);
|
||||
}
|
||||
|
||||
static EnumTable::Enums enumGraphTypes[] = {
|
||||
{ GuiGraphCtrl::Bar, "bar" },
|
||||
{ GuiGraphCtrl::Filled, "filled" },
|
||||
{ GuiGraphCtrl::Point, "point" },
|
||||
{ GuiGraphCtrl::Polyline , "polyline" },
|
||||
};
|
||||
|
||||
static EnumTable gGraphTypeTable( 4, &enumGraphTypes[0] );
|
||||
|
||||
bool GuiGraphCtrl::onWake()
|
||||
{
|
||||
if (! Parent::onWake())
|
||||
return false;
|
||||
setActive(true);
|
||||
return true;
|
||||
}
|
||||
|
||||
void GuiGraphCtrl::onRender(Point2I offset, const RectI &updateRect)
|
||||
{
|
||||
if (mProfile->mBorder)
|
||||
{
|
||||
RectI rect(offset.x, offset.y, mBounds.extent.x, mBounds.extent.y);
|
||||
dglDrawRect(rect, mProfile->mBorderColor);
|
||||
}
|
||||
|
||||
glBlendFunc(GL_SRC_COLOR, GL_ONE_MINUS_SRC_COLOR);
|
||||
glEnable(GL_BLEND);
|
||||
ColorF color(1.0, 1.0, 1.0, 0.5);
|
||||
dglDrawRectFill(updateRect, color);
|
||||
glDisable(GL_BLEND);
|
||||
glBlendFunc(GL_ONE, GL_ZERO);
|
||||
|
||||
for (int k = 0; k < MaxPlots; k++)
|
||||
{
|
||||
|
||||
|
||||
// Check if there is an autoplot and the proper amount of time has passed, if so add datum.
|
||||
if((mPlots[k].mAutoPlot!=NULL) &&
|
||||
(mPlots[k].mAutoPlotDelay < (Sim::getCurrentTime() - mPlots[k].mAutoPlotLastDisplay)))
|
||||
{
|
||||
mPlots[k].mAutoPlotLastDisplay = Sim::getCurrentTime();
|
||||
addDatum(k, Con::getFloatVariable(mPlots[k].mAutoPlot));
|
||||
Con::setIntVariable(mPlots[k].mAutoPlot, 0);
|
||||
}
|
||||
|
||||
// Adjust scale to max value + 5% so we can see high values
|
||||
F32 Scale = (F32(getExtent().y) / (F32(mPlots[k].mGraphMax*1.05)));
|
||||
|
||||
// Nothing to graph
|
||||
if (mPlots[k].mGraphData.size() == 0)
|
||||
continue;
|
||||
|
||||
// Bar graph
|
||||
if(mPlots[k].mGraphType == Bar)
|
||||
{
|
||||
|
||||
glBegin(GL_QUADS);
|
||||
|
||||
glColor3fv(mPlots[k].mGraphColor);
|
||||
|
||||
S32 temp1,temp2;
|
||||
temp1 = 0;
|
||||
|
||||
for (S32 sample = 0; sample < getExtent().x; sample++)
|
||||
{
|
||||
if(mPlots[k].mGraphData.size() >= getExtent().x)
|
||||
temp2 = sample;
|
||||
else
|
||||
temp2 = (S32)(((F32)getExtent().x / (F32)mPlots[k].mGraphData.size()) * (F32)sample);
|
||||
|
||||
glVertex2i(getPosition().x + temp1,
|
||||
(getPosition().y + getExtent().y) - (S32)(getDatum(k, sample) * Scale));
|
||||
|
||||
glVertex2i(getPosition().x + temp2,
|
||||
(getPosition().y + getExtent().y) - (S32)(getDatum(k, sample) * Scale));
|
||||
|
||||
glVertex2i(getPosition().x + temp2,
|
||||
getPosition().y + getExtent().y);
|
||||
|
||||
glVertex2i(getPosition().x + temp1,
|
||||
getPosition().y + getExtent().y);
|
||||
|
||||
temp1 = temp2;
|
||||
}
|
||||
|
||||
glEnd();
|
||||
}
|
||||
|
||||
// Filled graph
|
||||
else if(mPlots[k].mGraphType == Filled)
|
||||
{
|
||||
glBegin(GL_QUADS);
|
||||
|
||||
glColor3fv(mPlots[k].mGraphColor);
|
||||
|
||||
S32 temp1,temp2;
|
||||
temp1 = 0;
|
||||
|
||||
for (S32 sample = 0; sample < (getExtent().x-1); sample++)
|
||||
{
|
||||
if(mPlots[k].mGraphData.size() >= getExtent().x)
|
||||
temp2 = sample;
|
||||
else
|
||||
temp2 = (S32)(((F32)getExtent().x / (F32)mPlots[k].mGraphData.size()) * (F32)sample);
|
||||
|
||||
glVertex2i(getPosition().x + temp1,
|
||||
(getPosition().y + getExtent().y) - (S32)(getDatum(k, sample) * Scale));
|
||||
|
||||
glVertex2i(getPosition().x + temp2,
|
||||
(getPosition().y + getExtent().y) - (S32)(getDatum(k, sample+1) * Scale));
|
||||
|
||||
glVertex2i(getPosition().x + temp2,
|
||||
getPosition().y + getExtent().y);
|
||||
|
||||
glVertex2i(getPosition().x + temp1,
|
||||
getPosition().y + getExtent().y);
|
||||
|
||||
temp1 = temp2;
|
||||
}
|
||||
|
||||
|
||||
// last point
|
||||
S32 sample = getExtent().x;
|
||||
|
||||
if(mPlots[k].mGraphData.size() >= getExtent().x)
|
||||
temp2 = sample;
|
||||
else
|
||||
temp2 = (S32)(((F32)getExtent().x / (F32)mPlots[k].mGraphData.size()) * (F32)sample);
|
||||
|
||||
glVertex2i(getPosition().x + temp1,
|
||||
(getPosition().y + getExtent().y) - (S32)(getDatum(k, sample) * Scale));
|
||||
|
||||
glVertex2i(getPosition().x + temp2,
|
||||
(getPosition().y + getExtent().y) - (S32)(getDatum(k, sample) * Scale));
|
||||
|
||||
glVertex2i(getPosition().x + temp2,
|
||||
getPosition().y + getExtent().y);
|
||||
|
||||
glVertex2i(getPosition().x + temp1,
|
||||
getPosition().y + getExtent().y);
|
||||
|
||||
glEnd();
|
||||
}
|
||||
|
||||
|
||||
// Point or Polyline graph
|
||||
else if((mPlots[k].mGraphType == Point) || (mPlots[k].mGraphType == Polyline))
|
||||
{
|
||||
if(mPlots[k].mGraphType == Point)
|
||||
glBegin(GL_POINTS);
|
||||
else
|
||||
glBegin(GL_LINE_STRIP);
|
||||
|
||||
glColor3fv(mPlots[k].mGraphColor);
|
||||
|
||||
for (S32 sample = 0; sample < getExtent().x; sample++)
|
||||
{
|
||||
S32 temp;
|
||||
if(mPlots[k].mGraphData.size() >= getExtent().x)
|
||||
temp = sample;
|
||||
else
|
||||
temp = (S32)(((F32)getExtent().x / (F32)mPlots[k].mGraphData.size()) * (F32)sample);
|
||||
|
||||
glVertex2i(getPosition().x + temp,
|
||||
(getPosition().y + getExtent().y) - (S32)(getDatum(k, sample) * Scale));
|
||||
}
|
||||
|
||||
glEnd();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void GuiGraphCtrl::addDatum(S32 plotID, F32 v)
|
||||
{
|
||||
AssertFatal(plotID > -1 && plotID < MaxPlots, "Invalid plot specified!");
|
||||
|
||||
// Add the data and trim the vector...
|
||||
mPlots[plotID].mGraphData.push_front( v );
|
||||
|
||||
if(mPlots[plotID].mGraphData.size() > MaxDataPoints)
|
||||
mPlots[plotID].mGraphData.pop_back();
|
||||
|
||||
// Keep record of maximum data value for scaling purposes.
|
||||
if(v > mPlots[plotID].mGraphMax)
|
||||
mPlots[plotID].mGraphMax = v;
|
||||
}
|
||||
|
||||
float GuiGraphCtrl::getDatum( int plotID, int sample)
|
||||
{
|
||||
AssertFatal(plotID > -1 && plotID < MaxPlots, "Invalid plot specified!");
|
||||
AssertFatal(sample > -1 && sample < MaxDataPoints, "Invalid sample specified!");
|
||||
return mPlots[plotID].mGraphData[sample];
|
||||
}
|
||||
|
||||
void GuiGraphCtrl::addAutoPlot(S32 plotID, const char *variable, S32 update)
|
||||
{
|
||||
mPlots[plotID].mAutoPlot = StringTable->insert(variable);
|
||||
mPlots[plotID].mAutoPlotDelay = update;
|
||||
Con::setIntVariable(mPlots[plotID].mAutoPlot, 0);
|
||||
}
|
||||
|
||||
void GuiGraphCtrl::removeAutoPlot(S32 plotID)
|
||||
{
|
||||
mPlots[plotID].mAutoPlot = NULL;
|
||||
}
|
||||
|
||||
void GuiGraphCtrl::setGraphType(S32 plotID, const char *graphType)
|
||||
{
|
||||
AssertFatal(plotID > -1 && plotID < MaxPlots, "Invalid plot specified!");
|
||||
if(!dStricmp(graphType,"Bar"))
|
||||
mPlots[plotID].mGraphType = Bar;
|
||||
else if(!dStricmp(graphType,"Filled"))
|
||||
mPlots[plotID].mGraphType = Filled;
|
||||
else if(!dStricmp(graphType,"Point"))
|
||||
mPlots[plotID].mGraphType = Point;
|
||||
else if(!dStricmp(graphType,"Polyline"))
|
||||
mPlots[plotID].mGraphType = Polyline;
|
||||
else AssertWarn(true, "Invalid graph type!");
|
||||
}
|
||||
|
||||
ConsoleMethod(GuiGraphCtrl, addDatum, void, 4, 4, "(int plotID, float v)"
|
||||
"Add a data point to the given plot.")
|
||||
{
|
||||
S32 plotID = dAtoi(argv[2]);
|
||||
if(plotID > object->MaxPlots)
|
||||
{
|
||||
Con::errorf("Invalid plotID.");
|
||||
return;
|
||||
}
|
||||
object->addDatum( plotID, dAtof(argv[3]));
|
||||
}
|
||||
|
||||
ConsoleMethod(GuiGraphCtrl, getDatum, F32, 4, 4, "(int plotID, int samples)"
|
||||
"Get a data point from the plot specified, samples from the start of the graph.")
|
||||
{
|
||||
S32 plotID = dAtoi(argv[2]);
|
||||
S32 samples = dAtoi(argv[3]);
|
||||
|
||||
if(plotID > object->MaxPlots)
|
||||
{
|
||||
Con::errorf("Invalid plotID.");
|
||||
return -1;
|
||||
}
|
||||
if(samples > object->MaxDataPoints)
|
||||
{
|
||||
Con::errorf("Invalid sample.");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return object->getDatum(plotID, samples);
|
||||
}
|
||||
|
||||
ConsoleMethod(GuiGraphCtrl, addAutoPlot, void, 5, 5, "(int plotID, string variable, int update)"
|
||||
"Adds a data point with value variable, every update ms.")
|
||||
{
|
||||
S32 plotID = dAtoi(argv[2]);
|
||||
|
||||
if(plotID > object->MaxPlots)
|
||||
{
|
||||
Con::errorf("Invalid plotID.");
|
||||
return;
|
||||
}
|
||||
|
||||
object->addAutoPlot(plotID,argv[3],dAtoi(argv[4]));
|
||||
}
|
||||
|
||||
ConsoleMethod(GuiGraphCtrl, removeAutoPlot, void, 3, 3, "(int plotID)"
|
||||
"Stops automatic pointing over set interval.")
|
||||
{
|
||||
S32 plotID = dAtoi(argv[2]);
|
||||
|
||||
if(plotID > object->MaxPlots)
|
||||
{
|
||||
Con::errorf("Invalid plotID.");
|
||||
return;
|
||||
}
|
||||
|
||||
object->removeAutoPlot(plotID);
|
||||
}
|
||||
|
||||
ConsoleMethod(GuiGraphCtrl, setGraphType, void, 4, 4, "(int plotID, string graphType)"
|
||||
"Change GraphType of plot plotID.")
|
||||
{
|
||||
S32 plotID = dAtoi(argv[2]);
|
||||
|
||||
if(plotID > object->MaxPlots)
|
||||
{
|
||||
Con::errorf("Invalid plotID.");
|
||||
return;
|
||||
}
|
||||
|
||||
object->setGraphType(dAtoi(argv[2]), argv[3]);
|
||||
}
|
||||
|
||||
ConsoleMethod(GuiGraphCtrl, matchScale, void, 3, GuiGraphCtrl::MaxPlots+2, "(int plotID, int plotID, ...)"
|
||||
"Sets the scale of all specified plots to the maximum scale among them.")
|
||||
{
|
||||
F32 Max = 0;
|
||||
for(int i=0; i < (argc-2); i++)
|
||||
{
|
||||
if(dAtoi(argv[2+i]) > object->MaxPlots)
|
||||
{
|
||||
Con::errorf("Invalid plotID.");
|
||||
return;
|
||||
}
|
||||
if (object->mPlots[dAtoi(argv[2+i])].mGraphMax > Max)
|
||||
Max = object->mPlots[dAtoi(argv[2+i])].mGraphMax;
|
||||
}
|
||||
for(int i=0; i < (argc-2); i++)
|
||||
object->mPlots[dAtoi(argv[2+i])].mGraphMax = Max;
|
||||
}
|
65
engine/gui/editor/guiGraphCtrl.h
Executable file
65
engine/gui/editor/guiGraphCtrl.h
Executable file
@ -0,0 +1,65 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// Torque Game Engine
|
||||
// Copyright (C) GarageGames.com, Inc.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef _GUIGRAPHCTRL_H_
|
||||
#define _GUIGRAPHCTRL_H_
|
||||
|
||||
#ifndef _GUICONTROL_H_
|
||||
#include "gui/core/guiControl.h"
|
||||
#endif
|
||||
#ifndef _GTEXMANAGER_H_
|
||||
#include "dgl/gTexManager.h"
|
||||
#endif
|
||||
|
||||
|
||||
class GuiGraphCtrl : public GuiControl
|
||||
{
|
||||
private:
|
||||
typedef GuiControl Parent;
|
||||
|
||||
public:
|
||||
enum Constants {
|
||||
MaxPlots = 6,
|
||||
MaxDataPoints = 200
|
||||
};
|
||||
|
||||
enum GraphType {
|
||||
Point,
|
||||
Polyline,
|
||||
Filled,
|
||||
Bar
|
||||
};
|
||||
|
||||
struct PlotInfo
|
||||
{
|
||||
const char *mAutoPlot;
|
||||
U32 mAutoPlotDelay;
|
||||
SimTime mAutoPlotLastDisplay;
|
||||
ColorF mGraphColor;
|
||||
Vector<F32> mGraphData;
|
||||
F32 mGraphMax;
|
||||
GraphType mGraphType;
|
||||
};
|
||||
|
||||
PlotInfo mPlots[MaxPlots];
|
||||
|
||||
//creation methods
|
||||
DECLARE_CONOBJECT(GuiGraphCtrl);
|
||||
GuiGraphCtrl();
|
||||
|
||||
//Parental methods
|
||||
bool onWake();
|
||||
|
||||
void onRender(Point2I offset, const RectI &updateRect);
|
||||
|
||||
// Graph interface
|
||||
void addDatum(S32 plotID, F32 v);
|
||||
F32 getDatum(S32 plotID, S32 samples);
|
||||
void addAutoPlot(S32 plotID, const char *variable, S32 update);
|
||||
void removeAutoPlot(S32 plotID);
|
||||
void setGraphType(S32 plotID, const char *graphType);
|
||||
};
|
||||
|
||||
#endif
|
1273
engine/gui/editor/guiInspector.cc
Executable file
1273
engine/gui/editor/guiInspector.cc
Executable file
File diff suppressed because it is too large
Load Diff
258
engine/gui/editor/guiInspector.h
Executable file
258
engine/gui/editor/guiInspector.h
Executable file
@ -0,0 +1,258 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// Torque Game Engine
|
||||
// Copyright (C) GarageGames.com, Inc.
|
||||
//-----------------------------------------------------------------------------
|
||||
#ifndef _GUI_INSPECTOR_H_
|
||||
#define _GUI_INSPECTOR_H_
|
||||
|
||||
#ifndef _DYNAMIC_CONSOLETYPES_H_
|
||||
#include "console/dynamicTypes.h"
|
||||
#endif
|
||||
|
||||
#ifndef _GUICONTROL_H_
|
||||
#include "gui/core/guiControl.h"
|
||||
#endif
|
||||
|
||||
#ifndef _GUISTACKCTRL_H_
|
||||
#include "gui/containers/guiStackCtrl.h"
|
||||
#endif
|
||||
|
||||
#ifndef _H_GUIDEFAULTCONTROLRENDER_
|
||||
#include "gui/core/guiDefaultControlRender.h"
|
||||
#endif
|
||||
|
||||
#ifndef _GUITICKCTRL_H_
|
||||
#include "gui/shiny/guiTickCtrl.h"
|
||||
#endif
|
||||
|
||||
#ifndef _GUISCROLLCTRL_H_
|
||||
#include "gui/containers/guiScrollCtrl.h"
|
||||
#endif
|
||||
|
||||
#ifndef _GUITEXTEDITCTRL_H_
|
||||
#include "gui/controls/guiTextEditCtrl.h"
|
||||
#endif
|
||||
|
||||
#ifndef _GUIBITMAPBUTTON_H_
|
||||
#include "gui/controls/guiBitmapButtonCtrl.h"
|
||||
#endif
|
||||
|
||||
#ifndef _GUIPOPUPCTRL_H_
|
||||
#include "gui/controls/guiPopUpCtrl.h"
|
||||
#endif
|
||||
|
||||
|
||||
// Forward Declare GuiInspectorGroup
|
||||
class GuiInspectorGroup;
|
||||
// Forward Declare GuiInspectorField
|
||||
class GuiInspectorField;
|
||||
// Forward Declare GuiInspectorDatablockField
|
||||
class GuiInspectorDatablockField;
|
||||
|
||||
class GuiInspector : public GuiStackControl
|
||||
{
|
||||
private:
|
||||
typedef GuiStackControl Parent;
|
||||
public:
|
||||
// Members
|
||||
Vector<GuiInspectorGroup*> mGroups;
|
||||
SimObjectPtr<SimObject> mTarget;
|
||||
|
||||
GuiInspector();
|
||||
~GuiInspector();
|
||||
DECLARE_CONOBJECT(GuiInspector);
|
||||
|
||||
virtual void parentResized(const Point2I &oldParentExtent, const Point2I &newParentExtent);
|
||||
void inspectObject( SimObject *object );
|
||||
void setName( StringTableEntry newName );
|
||||
void clearGroups();
|
||||
bool onAdd();
|
||||
bool findExistentGroup( StringTableEntry groupName );
|
||||
};
|
||||
|
||||
class GuiInspectorField : public GuiControl
|
||||
{
|
||||
private:
|
||||
typedef GuiControl Parent;
|
||||
public:
|
||||
// Static Caption Width (in percentage) for all inspector fields
|
||||
static S32 smCaptionWidth;
|
||||
|
||||
// Members
|
||||
StringTableEntry mCaption;
|
||||
GuiInspectorGroup* mParent;
|
||||
SimObjectPtr<SimObject> mTarget;
|
||||
AbstractClassRep::Field* mField;
|
||||
|
||||
// Constructed Field Edit Control
|
||||
GuiControl* mEdit;
|
||||
|
||||
GuiInspectorField( GuiInspectorGroup* parent, SimObjectPtr<SimObject> target, AbstractClassRep::Field* field );
|
||||
GuiInspectorField();
|
||||
~GuiInspectorField();
|
||||
DECLARE_CONOBJECT(GuiInspectorField);
|
||||
|
||||
virtual void setTarget( SimObjectPtr<SimObject> target ) { mTarget = target; };
|
||||
virtual void setParent( GuiInspectorGroup* parent ) { mParent = parent; };
|
||||
virtual void setField( AbstractClassRep::Field *field ) { mField = field; mCaption = field->pFieldname; };
|
||||
|
||||
protected:
|
||||
void registerEditControl( GuiControl *ctrl );
|
||||
public:
|
||||
virtual GuiControl* constructEditControl();
|
||||
virtual void updateValue( StringTableEntry newValue );
|
||||
virtual StringTableEntry getFieldName() { return ( mField != NULL ) ? mField->pFieldname : ""; };
|
||||
virtual void setData( StringTableEntry data );
|
||||
virtual StringTableEntry getData();
|
||||
|
||||
virtual void resize(const Point2I &newPosition, const Point2I &newExtent);
|
||||
virtual bool onAdd();
|
||||
virtual void onRender(Point2I offset, const RectI &updateRect);
|
||||
};
|
||||
|
||||
class GuiInspectorGroup : public GuiTickCtrl
|
||||
{
|
||||
private:
|
||||
typedef GuiControl Parent;
|
||||
public:
|
||||
// Members
|
||||
StringTableEntry mCaption;
|
||||
Point2I mBarWidth;
|
||||
bool mIsExpanded;
|
||||
bool mIsAnimating;
|
||||
bool mCollapsing;
|
||||
S32 mAnimateDestHeight;
|
||||
S32 mAnimateStep;
|
||||
S32 mChildHeight;
|
||||
SimObjectPtr<SimObject> mTarget;
|
||||
SimObjectPtr<GuiInspector> mParent;
|
||||
Vector<GuiInspectorField*> mChildren;
|
||||
GuiStackControl* mStack;
|
||||
|
||||
// Constructor/Destructor/Conobject Declaration
|
||||
GuiInspectorGroup();
|
||||
GuiInspectorGroup( SimObjectPtr<SimObject> target, StringTableEntry groupName, SimObjectPtr<GuiInspector> parent );
|
||||
~GuiInspectorGroup();
|
||||
DECLARE_CONOBJECT(GuiInspectorGroup);
|
||||
|
||||
// Persistence ( Inspector Exposed Fields )
|
||||
static void initPersistFields();
|
||||
|
||||
// Mouse Events
|
||||
virtual void onMouseDown( const GuiEvent &event );
|
||||
|
||||
// Sizing Helpers
|
||||
virtual S32 getExpandedHeight();
|
||||
void resize( const Point2I &newPosition, const Point2I &newExtent );
|
||||
|
||||
// Sizing Animation Functions
|
||||
void animateTo( S32 height );
|
||||
virtual void processTick();
|
||||
|
||||
virtual GuiInspectorField* constructField( S32 fieldType );
|
||||
virtual GuiInspectorField* findField( StringTableEntry fieldName );
|
||||
|
||||
// Control Rendering
|
||||
virtual void onRender(Point2I offset, const RectI &updateRect);
|
||||
|
||||
// Publicly Accessible Information about this group
|
||||
StringTableEntry getGroupName() { return mCaption; };
|
||||
SimObjectPtr<SimObject> getGroupTarget() { return mTarget; };
|
||||
SimObjectPtr<GuiInspector> getContentCtrl() { return mParent; };
|
||||
|
||||
bool onAdd();
|
||||
virtual bool inspectGroup();
|
||||
|
||||
};
|
||||
|
||||
class GuiInspectorDynamicField : public GuiInspectorField
|
||||
{
|
||||
private:
|
||||
typedef GuiInspectorField Parent;
|
||||
SimObjectPtr<GuiControl> mRenameCtrl;
|
||||
public:
|
||||
SimFieldDictionary::Entry* mDynField;
|
||||
|
||||
GuiInspectorDynamicField( GuiInspectorGroup* parent, SimObjectPtr<SimObject> target, SimFieldDictionary::Entry* field );
|
||||
GuiInspectorDynamicField() {};
|
||||
~GuiInspectorDynamicField() {};
|
||||
DECLARE_CONOBJECT(GuiInspectorDynamicField);
|
||||
|
||||
virtual void setData( StringTableEntry data );
|
||||
virtual StringTableEntry getData();
|
||||
|
||||
virtual StringTableEntry getFieldName() { return ( mDynField != NULL ) ? mDynField->slotName : ""; };
|
||||
|
||||
// Override onAdd so we can construct our custom field name edit control
|
||||
virtual bool onAdd();
|
||||
// Rename a dynamic field
|
||||
void renameField( StringTableEntry newFieldName );
|
||||
// Create an edit control to overlay the field name (for renaming dynamic fields)
|
||||
GuiControl* constructRenameControl();
|
||||
// Rendering (We custom render this field type because it contains no caption rendering)
|
||||
virtual void onRender(Point2I offset, const RectI &updateRect);
|
||||
// Override parentResized so we can resize our renaming control
|
||||
virtual void resize(const Point2I &newPosition, const Point2I &newExtent);
|
||||
};
|
||||
|
||||
class GuiInspectorDynamicGroup : public GuiInspectorGroup
|
||||
{
|
||||
private:
|
||||
typedef GuiInspectorGroup Parent;
|
||||
public:
|
||||
GuiInspectorDynamicGroup( SimObjectPtr<SimObject> target, StringTableEntry groupName, SimObjectPtr<GuiInspector> parent ) : GuiInspectorGroup( target, groupName, parent) {};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// inspectGroup is overridden in GuiInspectorDynamicGroup to inspect an
|
||||
// objects FieldDictionary (dynamic fields) instead of regular persistent
|
||||
// fields.
|
||||
bool inspectGroup();
|
||||
|
||||
// For scriptable dynamic field additions
|
||||
void addDynamicField();
|
||||
|
||||
// To make sure we expand to show add field 'button'
|
||||
virtual S32 getExpandedHeight();
|
||||
|
||||
// Clear our fields (delete them)
|
||||
void clearFields();
|
||||
|
||||
// For handling creation of dynamic fields
|
||||
virtual void onMouseDown( const GuiEvent &event );
|
||||
|
||||
// Find an already existent field by name in the dictionary
|
||||
virtual SimFieldDictionary::Entry* findDynamicFieldInDictionary( StringTableEntry fieldName );
|
||||
|
||||
// Find an already existent field by name in the stack control
|
||||
virtual GuiInspectorDynamicField* findDynamicField( StringTableEntry fieldName );
|
||||
|
||||
|
||||
// Override onRender to add an 'Add Field' button
|
||||
virtual void onRender(Point2I offset, const RectI &updateRect);
|
||||
};
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// GuiInspectorDatablockField - custom field type for datablock enumeration
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
class GuiInspectorDatablockField : public GuiInspectorField
|
||||
{
|
||||
private:
|
||||
typedef GuiInspectorField Parent;
|
||||
|
||||
AbstractClassRep *mDesiredClass;
|
||||
public:
|
||||
DECLARE_CONOBJECT(GuiInspectorDatablockField);
|
||||
GuiInspectorDatablockField( StringTableEntry className );
|
||||
GuiInspectorDatablockField() { mDesiredClass = NULL; };
|
||||
|
||||
void setClassName( StringTableEntry className );
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Override able methods for custom edit fields (Both are REQUIRED)
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
virtual GuiControl* constructEditControl();
|
||||
|
||||
};
|
||||
|
||||
#endif
|
350
engine/gui/editor/guiInspectorTypes.cc
Executable file
350
engine/gui/editor/guiInspectorTypes.cc
Executable file
@ -0,0 +1,350 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// Torque Game Engine
|
||||
// Copyright (C) GarageGames.com, Inc.
|
||||
//-----------------------------------------------------------------------------
|
||||
#include "gui/editor/guiInspectorTypes.h"
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// GuiInspectorTypeEnum
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
IMPLEMENT_CONOBJECT(GuiInspectorTypeEnum);
|
||||
|
||||
GuiControl* GuiInspectorTypeEnum::constructEditControl()
|
||||
{
|
||||
GuiControl* retCtrl = new GuiPopUpMenuCtrl();
|
||||
|
||||
// If we couldn't construct the control, bail!
|
||||
if( retCtrl == NULL )
|
||||
return retCtrl;
|
||||
|
||||
GuiPopUpMenuCtrl *menu = dynamic_cast<GuiPopUpMenuCtrl*>(retCtrl);
|
||||
|
||||
// Let's make it look pretty.
|
||||
retCtrl->setField( "profile", "InspectorTypeEnumProfile" );
|
||||
|
||||
menu->setField("text", getData());
|
||||
|
||||
registerEditControl( retCtrl );
|
||||
|
||||
// Configure it to update our value when the popup is closed
|
||||
char szBuffer[512];
|
||||
dSprintf( szBuffer, 512, "%d.apply(%d.getText());",getId(),menu->getId() );
|
||||
menu->setField("Command", szBuffer );
|
||||
|
||||
//now add the entries
|
||||
for(S32 i = 0; i < mField->table->size; i++)
|
||||
menu->addEntry(mField->table->table[i].label, mField->table->table[i].index);
|
||||
|
||||
return retCtrl;
|
||||
}
|
||||
|
||||
void GuiInspectorTypeEnum::consoleInit()
|
||||
{
|
||||
Parent::consoleInit();
|
||||
|
||||
ConsoleBaseType::getType(TypeEnum)->setInspectorFieldType("GuiInspectorTypeEnum");
|
||||
}
|
||||
|
||||
void GuiInspectorTypeEnum::updateValue( StringTableEntry newValue )
|
||||
{
|
||||
GuiPopUpMenuCtrl *ctrl = dynamic_cast<GuiPopUpMenuCtrl*>( mEdit );
|
||||
if( ctrl != NULL )
|
||||
ctrl->setText( newValue );
|
||||
}
|
||||
|
||||
void GuiInspectorTypeEnum::setData( StringTableEntry data )
|
||||
{
|
||||
if( mField == NULL || mTarget == NULL )
|
||||
return;
|
||||
|
||||
mTarget->setDataField( mField->pFieldname, NULL, data );
|
||||
|
||||
// Force our edit to update
|
||||
updateValue( data );
|
||||
}
|
||||
|
||||
StringTableEntry GuiInspectorTypeEnum::getData()
|
||||
{
|
||||
if( mField == NULL || mTarget == NULL )
|
||||
return "";
|
||||
|
||||
return mTarget->getDataField( mField->pFieldname, NULL );
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// GuiInspectorTypeCheckBox
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
IMPLEMENT_CONOBJECT(GuiInspectorTypeCheckBox);
|
||||
|
||||
GuiControl* GuiInspectorTypeCheckBox::constructEditControl()
|
||||
{
|
||||
GuiControl* retCtrl = new GuiCheckBoxCtrl();
|
||||
|
||||
// If we couldn't construct the control, bail!
|
||||
if( retCtrl == NULL )
|
||||
return retCtrl;
|
||||
|
||||
GuiCheckBoxCtrl *check = dynamic_cast<GuiCheckBoxCtrl*>(retCtrl);
|
||||
|
||||
// Let's make it look pretty.
|
||||
retCtrl->setField( "profile", "InspectorTypeCheckboxProfile" );
|
||||
retCtrl->setField( "text", "" );
|
||||
|
||||
check->mIndent = 4;
|
||||
|
||||
retCtrl->setScriptValue( getData() );
|
||||
|
||||
registerEditControl( retCtrl );
|
||||
|
||||
// Configure it to update our value when the popup is closed
|
||||
char szBuffer[512];
|
||||
dSprintf( szBuffer, 512, "%d.apply(%d.getValue());",getId(),check->getId() );
|
||||
check->setField("Command", szBuffer );
|
||||
|
||||
return retCtrl;
|
||||
}
|
||||
|
||||
|
||||
void GuiInspectorTypeCheckBox::consoleInit()
|
||||
{
|
||||
Parent::consoleInit();
|
||||
|
||||
ConsoleBaseType::getType(TypeBool)->setInspectorFieldType("GuiInspectorTypeCheckBox");
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// GuiInspectorTypeGuiProfile
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
IMPLEMENT_CONOBJECT(GuiInspectorTypeGuiProfile);
|
||||
|
||||
void GuiInspectorTypeGuiProfile::consoleInit()
|
||||
{
|
||||
Parent::consoleInit();
|
||||
|
||||
ConsoleBaseType::getType(TypeGuiProfile)->setInspectorFieldType("GuiInspectorTypeGuiProfile");
|
||||
}
|
||||
|
||||
static S32 QSORT_CALLBACK stringCompare(const void *a,const void *b)
|
||||
{
|
||||
StringTableEntry sa = *(StringTableEntry*)a;
|
||||
StringTableEntry sb = *(StringTableEntry*)b;
|
||||
return(dStricmp(sb, sa));
|
||||
}
|
||||
|
||||
GuiControl* GuiInspectorTypeGuiProfile::constructEditControl()
|
||||
{
|
||||
GuiControl* retCtrl = new GuiPopUpMenuCtrl();
|
||||
|
||||
// If we couldn't construct the control, bail!
|
||||
if( retCtrl == NULL )
|
||||
return retCtrl;
|
||||
|
||||
GuiPopUpMenuCtrl *menu = dynamic_cast<GuiPopUpMenuCtrl*>(retCtrl);
|
||||
|
||||
// Let's make it look pretty.
|
||||
retCtrl->setField( "profile", "InspectorTypeEnumProfile" );
|
||||
|
||||
menu->setField("text", getData());
|
||||
|
||||
registerEditControl( retCtrl );
|
||||
|
||||
// Configure it to update our value when the popup is closed
|
||||
char szBuffer[512];
|
||||
dSprintf( szBuffer, 512, "%d.apply(%d.getText());",getId(),menu->getId() );
|
||||
menu->setField("Command", szBuffer );
|
||||
|
||||
Vector<StringTableEntry> entries;
|
||||
|
||||
SimGroup * grp = Sim::getGuiDataGroup();
|
||||
for(SimGroup::iterator i = grp->begin(); i != grp->end(); i++)
|
||||
{
|
||||
GuiControlProfile * profile = dynamic_cast<GuiControlProfile *>(*i);
|
||||
if(profile)
|
||||
entries.push_back(profile->getName());
|
||||
}
|
||||
|
||||
// sort the entries
|
||||
dQsort(entries.address(), entries.size(), sizeof(StringTableEntry), stringCompare);
|
||||
for(U32 j = 0; j < entries.size(); j++)
|
||||
menu->addEntry(entries[j], 0);
|
||||
|
||||
return retCtrl;
|
||||
}
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// GuiInspectorTypeFileName
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
IMPLEMENT_CONOBJECT(GuiInspectorTypeFileName);
|
||||
|
||||
void GuiInspectorTypeFileName::consoleInit()
|
||||
{
|
||||
Parent::consoleInit();
|
||||
|
||||
ConsoleBaseType::getType(TypeFilename)->setInspectorFieldType("GuiInspectorTypeFileName");
|
||||
}
|
||||
|
||||
GuiControl* GuiInspectorTypeFileName::constructEditControl()
|
||||
{
|
||||
GuiControl* retCtrl = new GuiTextEditCtrl();
|
||||
|
||||
// If we couldn't construct the control, bail!
|
||||
if( retCtrl == NULL )
|
||||
return retCtrl;
|
||||
|
||||
// Let's make it look pretty.
|
||||
retCtrl->setField( "profile", "GuiInspectorTextEditProfile" );
|
||||
|
||||
// Don't forget to register ourselves
|
||||
registerEditControl( retCtrl );
|
||||
|
||||
char szBuffer[512];
|
||||
dSprintf( szBuffer, 512, "%d.apply(%d.getText());",getId(),retCtrl->getId() );
|
||||
retCtrl->setField("AltCommand", szBuffer );
|
||||
retCtrl->setField("Validate", szBuffer );
|
||||
|
||||
mBrowseButton = new GuiButtonCtrl();
|
||||
|
||||
if( mBrowseButton != NULL )
|
||||
{
|
||||
RectI browseRect( Point2I( ( mBounds.point.x + mBounds.extent.x) - 26, mBounds.point.y + 2), Point2I(20, mBounds.extent.y - 4) );
|
||||
char szBuffer[512];
|
||||
dSprintf( szBuffer, 512, "getLoadFilename(\"*.*\", \"%d.apply\", \"%s\");",getId(), getData());
|
||||
mBrowseButton->setField( "Command", szBuffer );
|
||||
mBrowseButton->setField( "text", "..." );
|
||||
mBrowseButton->setField( "Profile", "GuiInspectorTypeFileNameProfile" );
|
||||
mBrowseButton->registerObject();
|
||||
addObject( mBrowseButton );
|
||||
|
||||
// Position
|
||||
mBrowseButton->resize( browseRect.point, browseRect.extent );
|
||||
}
|
||||
|
||||
return retCtrl;
|
||||
}
|
||||
|
||||
void GuiInspectorTypeFileName::resize( const Point2I &newPosition, const Point2I &newExtent )
|
||||
{
|
||||
Parent::resize( newPosition, newExtent );
|
||||
|
||||
if( mEdit != NULL )
|
||||
{
|
||||
// Calculate Caption Rect
|
||||
RectI captionRect( mBounds.point , Point2I( mFloor( mBounds.extent.x * (F32)( (F32)GuiInspectorField::smCaptionWidth / 100.0 ) ) - 2, mBounds.extent.y ) );
|
||||
|
||||
// Calculate Edit Field Rect
|
||||
RectI editFieldRect( Point2I( captionRect.extent.x + 1, 0 ) , Point2I( mBounds.extent.x - ( captionRect.extent.x + 25 ) , mBounds.extent.y ) );
|
||||
|
||||
mEdit->resize( editFieldRect.point, editFieldRect.extent );
|
||||
|
||||
if( mBrowseButton != NULL )
|
||||
{
|
||||
RectI browseRect( Point2I( ( mBounds.point.x + mBounds.extent.x) - 26, 2), Point2I(20, mBounds.extent.y - 4) );
|
||||
mBrowseButton->resize( browseRect.point, browseRect.extent );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// GuiInspectorTypeColor (Base for ColorI/ColorF)
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
IMPLEMENT_CONOBJECT(GuiInspectorTypeColor);
|
||||
|
||||
GuiControl* GuiInspectorTypeColor::constructEditControl()
|
||||
{
|
||||
GuiControl* retCtrl = new GuiTextEditCtrl();
|
||||
|
||||
// If we couldn't construct the control, bail!
|
||||
if( retCtrl == NULL )
|
||||
return retCtrl;
|
||||
|
||||
// Let's make it look pretty.
|
||||
retCtrl->setField( "profile", "GuiInspectorTextEditProfile" );
|
||||
|
||||
// Don't forget to register ourselves
|
||||
registerEditControl( retCtrl );
|
||||
|
||||
char szBuffer[512];
|
||||
dSprintf( szBuffer, 512, "%d.apply(%d.getText());",getId(), retCtrl->getId() );
|
||||
retCtrl->setField("AltCommand", szBuffer );
|
||||
retCtrl->setField("Validate", szBuffer );
|
||||
|
||||
mBrowseButton = new GuiButtonCtrl();
|
||||
|
||||
if( mBrowseButton != NULL )
|
||||
{
|
||||
RectI browseRect( Point2I( ( mBounds.point.x + mBounds.extent.x) - 26, mBounds.point.y + 2), Point2I(20, mBounds.extent.y - 4) );
|
||||
char szBuffer[512];
|
||||
dSprintf( szBuffer, 512, "%s(\"%s\", \"%d.apply\");", mColorFunction, getData(), getId());
|
||||
mBrowseButton->setField( "Command", szBuffer );
|
||||
mBrowseButton->setField( "text", "..." );
|
||||
mBrowseButton->setField( "Profile", "GuiInspectorTypeFileNameProfile" );
|
||||
mBrowseButton->registerObject();
|
||||
addObject( mBrowseButton );
|
||||
|
||||
// Position
|
||||
mBrowseButton->resize( browseRect.point, browseRect.extent );
|
||||
}
|
||||
|
||||
return retCtrl;
|
||||
}
|
||||
|
||||
void GuiInspectorTypeColor::resize( const Point2I &newPosition, const Point2I &newExtent )
|
||||
{
|
||||
Parent::resize( newPosition, newExtent );
|
||||
|
||||
if( mEdit != NULL )
|
||||
{
|
||||
// Calculate Caption Rect
|
||||
RectI captionRect( mBounds.point , Point2I( mFloor( mBounds.extent.x * (F32)( (F32)GuiInspectorField::smCaptionWidth / 100.0 ) ) - 2, mBounds.extent.y ) );
|
||||
|
||||
// Calculate Edit Field Rect
|
||||
RectI editFieldRect( Point2I( captionRect.extent.x + 1, 0 ) , Point2I( mBounds.extent.x - ( captionRect.extent.x + 25 ) , mBounds.extent.y ) );
|
||||
|
||||
mEdit->resize( editFieldRect.point, editFieldRect.extent );
|
||||
|
||||
if( mBrowseButton != NULL )
|
||||
{
|
||||
RectI browseRect( Point2I( ( mBounds.point.x + mBounds.extent.x) - 26, 2), Point2I(20, mBounds.extent.y - 4) );
|
||||
mBrowseButton->resize( browseRect.point, browseRect.extent );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// GuiInspectorTypeColorI
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
IMPLEMENT_CONOBJECT(GuiInspectorTypeColorI);
|
||||
|
||||
void GuiInspectorTypeColorI::consoleInit()
|
||||
{
|
||||
Parent::consoleInit();
|
||||
|
||||
ConsoleBaseType::getType(TypeColorI)->setInspectorFieldType("GuiInspectorTypeColorI");
|
||||
}
|
||||
|
||||
GuiInspectorTypeColorI::GuiInspectorTypeColorI()
|
||||
{
|
||||
mColorFunction = StringTable->insert("getColorI");
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// GuiInspectorTypeColorF
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
IMPLEMENT_CONOBJECT(GuiInspectorTypeColorF);
|
||||
|
||||
void GuiInspectorTypeColorF::consoleInit()
|
||||
{
|
||||
Parent::consoleInit();
|
||||
|
||||
ConsoleBaseType::getType(TypeColorF)->setInspectorFieldType("GuiInspectorTypeColorF");
|
||||
}
|
||||
|
||||
GuiInspectorTypeColorF::GuiInspectorTypeColorF()
|
||||
{
|
||||
mColorFunction = StringTable->insert("getColorF");
|
||||
}
|
||||
|
||||
|
||||
|
162
engine/gui/editor/guiInspectorTypes.h
Executable file
162
engine/gui/editor/guiInspectorTypes.h
Executable file
@ -0,0 +1,162 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// Torque Game Engine
|
||||
// Copyright (C) GarageGames.com, Inc.
|
||||
//-----------------------------------------------------------------------------
|
||||
#ifndef _GUI_INSPECTOR_TYPES_H_
|
||||
#define _GUI_INSPECTOR_TYPES_H_
|
||||
|
||||
#ifndef _GUI_INSPECTOR_H_
|
||||
#include "gui/editor/guiInspector.h"
|
||||
#endif
|
||||
|
||||
#ifndef _GUICONTROL_H_
|
||||
#include "gui/core/guiControl.h"
|
||||
#endif
|
||||
|
||||
#ifndef _H_GUIDEFAULTCONTROLRENDER_
|
||||
#include "gui/core/guiDefaultControlRender.h"
|
||||
#endif
|
||||
|
||||
#ifndef _GUISCROLLCTRL_H_
|
||||
#include "gui/containers/guiScrollCtrl.h"
|
||||
#endif
|
||||
|
||||
#ifndef _GUITEXTEDITCTRL_H_
|
||||
#include "gui/controls/guiTextEditCtrl.h"
|
||||
#endif
|
||||
|
||||
#ifndef _GUIPOPUPCTRL_H_
|
||||
#include "gui/controls/guiPopUpCtrl.h"
|
||||
#endif
|
||||
|
||||
#ifndef _GUICHECKBOXCTRL_H_
|
||||
#include "gui/controls/guiCheckBoxCtrl.h"
|
||||
#endif
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// TypeEnum GuiInspectorField Class
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
class GuiInspectorTypeEnum : public GuiInspectorField
|
||||
{
|
||||
private:
|
||||
typedef GuiInspectorField Parent;
|
||||
public:
|
||||
DECLARE_CONOBJECT(GuiInspectorTypeEnum);
|
||||
static void consoleInit();
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Override able methods for custom edit fields
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
virtual GuiControl* constructEditControl();
|
||||
virtual void setData( StringTableEntry data );
|
||||
virtual StringTableEntry getData();
|
||||
virtual void updateValue( StringTableEntry newValue );
|
||||
};
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// GuiInspectorTypeCheckBox Class
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
class GuiInspectorTypeCheckBox : public GuiInspectorField
|
||||
{
|
||||
private:
|
||||
typedef GuiInspectorField Parent;
|
||||
public:
|
||||
DECLARE_CONOBJECT(GuiInspectorTypeCheckBox);
|
||||
static void consoleInit();
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Override able methods for custom edit fields (Both are REQUIRED)
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
virtual GuiControl* constructEditControl();
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// GuiInspectorTypeGuiProfile Class
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
class GuiInspectorTypeGuiProfile : public GuiInspectorTypeEnum
|
||||
{
|
||||
private:
|
||||
typedef GuiInspectorTypeEnum Parent;
|
||||
public:
|
||||
DECLARE_CONOBJECT(GuiInspectorTypeGuiProfile);
|
||||
static void consoleInit();
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Override able methods for custom edit fields (Both are REQUIRED)
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
virtual GuiControl* constructEditControl();
|
||||
};
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// TypeFileName GuiInspectorField Class
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
class GuiInspectorTypeFileName : public GuiInspectorField
|
||||
{
|
||||
private:
|
||||
typedef GuiInspectorField Parent;
|
||||
public:
|
||||
DECLARE_CONOBJECT(GuiInspectorTypeFileName);
|
||||
static void consoleInit();
|
||||
|
||||
SimObjectPtr<GuiButtonCtrl> mBrowseButton;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Override able methods for custom edit fields
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
virtual GuiControl* constructEditControl();
|
||||
virtual void resize(const Point2I &newPosition, const Point2I &newExtent);
|
||||
};
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// TypeColor GuiInspectorField Class (Base for ColorI/ColorF)
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
class GuiInspectorTypeColor : public GuiInspectorField
|
||||
{
|
||||
private:
|
||||
typedef GuiInspectorField Parent;
|
||||
public:
|
||||
DECLARE_CONOBJECT(GuiInspectorTypeColor);
|
||||
|
||||
StringTableEntry mColorFunction;
|
||||
SimObjectPtr<GuiButtonCtrl> mBrowseButton;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Override able methods for custom edit fields
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
virtual GuiControl* constructEditControl();
|
||||
virtual void resize(const Point2I &newPosition, const Point2I &newExtent);
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// TypeColorI GuiInspectorField Class
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
class GuiInspectorTypeColorI : public GuiInspectorTypeColor
|
||||
{
|
||||
private:
|
||||
typedef GuiInspectorTypeColor Parent;
|
||||
public:
|
||||
GuiInspectorTypeColorI();
|
||||
|
||||
DECLARE_CONOBJECT(GuiInspectorTypeColorI);
|
||||
static void consoleInit();
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// TypeColorF GuiInspectorField Class
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
class GuiInspectorTypeColorF : public GuiInspectorTypeColor
|
||||
{
|
||||
private:
|
||||
typedef GuiInspectorTypeColor Parent;
|
||||
public:
|
||||
GuiInspectorTypeColorF();
|
||||
|
||||
DECLARE_CONOBJECT(GuiInspectorTypeColorF);
|
||||
static void consoleInit();
|
||||
};
|
||||
|
||||
#endif
|
851
engine/gui/editor/guiMenuBar.cc
Executable file
851
engine/gui/editor/guiMenuBar.cc
Executable file
@ -0,0 +1,851 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// 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/core/guiDefaultControlRender.h"
|
||||
#include "gui/controls/guiTextListCtrl.h"
|
||||
#include "sim/actionMap.h"
|
||||
#include "gui/editor/guiMenuBar.h"
|
||||
|
||||
// menu bar:
|
||||
// basic idea - fixed height control bar at the top of a window, placed and sized in gui editor
|
||||
// menu text for menus or menu items should not begin with a digit
|
||||
// all menus can be removed via the clearMenus() console command
|
||||
// each menu is added via the addMenu(menuText, menuId) console command
|
||||
// each menu is added with a menu id
|
||||
// menu items are added to menus via that addMenuItem(menu, menuItemText, menuItemId, accelerator, checkGroup) console command
|
||||
// each menu item is added with a menu item id and an optional accelerator
|
||||
// menu items are initially enabled, but can be disabled/re-enabled via the setMenuItemEnable(menu,menuItem,bool)
|
||||
// menu text can be set via the setMenuText(menu, newMenuText) console method
|
||||
// menu item text can be set via the setMenuItemText console method
|
||||
// menu items can be removed via the removeMenuItem(menu, menuItem) console command
|
||||
// menu items can be cleared via the clearMenuItems(menu) console command
|
||||
// menus can be hidden or shown via the setMenuVisible(menu, bool) console command
|
||||
// menu items can be hidden or shown via the setMenuItemVisible(menu, menuItem, bool) console command
|
||||
// menu items can be check'd via the setMenuItemChecked(menu, menuItem, bool) console command
|
||||
// if the bool is true, any other items in that menu item's check group become unchecked.
|
||||
//
|
||||
// menu items can have a bitmap set on them via the setMenuItemBitmap(menu, menuItem, bitmapIndex)
|
||||
// passing -1 for the bitmap index will result in no bitmap being shown
|
||||
// the index paramater is an index into the bitmap array of the associated profile
|
||||
// this can be used, for example, to display a check next to a selected menu item
|
||||
// bitmap indices are actually multiplied by 3 when indexing into the bitmap
|
||||
// since bitmaps have normal, selected and disabled states.
|
||||
//
|
||||
// menus can be removed via the removeMenu console command
|
||||
// specification arguments for menus and menu items can be either the id or the text of the menu or menu item
|
||||
// adding the menu item "-" will add an un-selectable seperator to the menu
|
||||
// callbacks:
|
||||
// when a menu is clicked, before it is displayed, the menu calls its onMenuSelect(menuId, menuText) method -
|
||||
// this allows the callback to enable/disable menu items, or add menu items in a context-sensitive way
|
||||
// when a menu item is clicked, the menu removes itself from display, then calls onMenuItemSelect(menuId, menuText, menuItemId, menuItemText)
|
||||
|
||||
// the initial implementation does not support:
|
||||
// hierarchal menus
|
||||
// keyboard accelerators on menu text (i.e. via alt-key combos)
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
IMPLEMENT_CONOBJECT(GuiMenuBar);
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// console methods
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
ConsoleMethod(GuiMenuBar, clearMenus, void, 2, 2, "() - clears all the menus from the menu bar.")
|
||||
{
|
||||
object->clearMenus();
|
||||
}
|
||||
|
||||
ConsoleMethod(GuiMenuBar, addMenu, void, 4, 4, "(string menuText, int menuId) - adds a new menu to the menu bar.")
|
||||
{
|
||||
if(dIsdigit(argv[2][0]))
|
||||
{
|
||||
Con::errorf("Cannot add menu %s (id = %s). First character of a menu's text cannot be a digit.", argv[2], argv[3]);
|
||||
return;
|
||||
}
|
||||
object->addMenu(argv[2], dAtoi(argv[3]));
|
||||
}
|
||||
|
||||
ConsoleMethod(GuiMenuBar, addMenuItem, void, 5, 7, "(string menu, string menuItemText, int menuItemId, string accelerator = NULL, int checkGroup = -1) - adds a menu item to the specified menu. The menu argument can be either the text of a menu or its id.")
|
||||
{
|
||||
if(dIsdigit(argv[3][0]))
|
||||
{
|
||||
Con::errorf("Cannot add menu item %s (id = %s). First character of a menu item's text cannot be a digit.", argv[3], argv[4]);
|
||||
return;
|
||||
}
|
||||
GuiMenuBar::Menu *menu = object->findMenu(argv[2]);
|
||||
if(!menu)
|
||||
{
|
||||
Con::errorf("Cannot find menu %s for addMenuItem.", argv[2]);
|
||||
return;
|
||||
}
|
||||
object->addMenuItem(menu, argv[3], dAtoi(argv[4]), argc == 5 ? "" : argv[5], argc < 7 ? -1 : dAtoi(argv[6]));
|
||||
}
|
||||
|
||||
ConsoleMethod(GuiMenuBar, setMenuItemEnable, void, 5, 5, "(string menu, string menuItem, bool enabled) - sets the menu item to enabled or disabled based on the enable parameter. The specified menu and menu item can either be text or ids.")
|
||||
{
|
||||
GuiMenuBar::Menu *menu = object->findMenu(argv[2]);
|
||||
if(!menu)
|
||||
{
|
||||
Con::errorf("Cannot find menu %s for setMenuItemEnable.", argv[2]);
|
||||
return;
|
||||
}
|
||||
GuiMenuBar::MenuItem *menuItem = object->findMenuItem(menu, argv[3]);
|
||||
if(!menuItem)
|
||||
{
|
||||
Con::errorf("Cannot find menu item %s for setMenuItemEnable.", argv[3]);
|
||||
return;
|
||||
}
|
||||
menuItem->enabled = dAtob(argv[4]);
|
||||
}
|
||||
|
||||
ConsoleMethod(GuiMenuBar, setMenuItemChecked, void, 5, 5, "(string menu, string menuItem, bool checked) - sets the menu item bitmap to a check mark, which must be the first element in the bitmap array. Any other menu items in the menu with the same check group become unchecked if they are checked.")
|
||||
{
|
||||
GuiMenuBar::Menu *menu = object->findMenu(argv[2]);
|
||||
if(!menu)
|
||||
{
|
||||
Con::errorf("Cannot find menu %s for setMenuItemChecked.", argv[2]);
|
||||
return;
|
||||
}
|
||||
GuiMenuBar::MenuItem *menuItem = object->findMenuItem(menu, argv[3]);
|
||||
if(!menuItem)
|
||||
{
|
||||
Con::errorf("Cannot find menu item %s for setMenuItemChecked.", argv[3]);
|
||||
return;
|
||||
}
|
||||
bool checked = dAtob(argv[4]);
|
||||
if(checked && menuItem->checkGroup != -1)
|
||||
{
|
||||
// first, uncheck everything in the group:
|
||||
for(GuiMenuBar::MenuItem *itemWalk = menu->firstMenuItem; itemWalk; itemWalk = itemWalk->nextMenuItem)
|
||||
if(itemWalk->checkGroup == menuItem->checkGroup && itemWalk->bitmapIndex == 0)
|
||||
itemWalk->bitmapIndex = -1;
|
||||
}
|
||||
menuItem->bitmapIndex = checked ? 0 : -1;
|
||||
}
|
||||
|
||||
ConsoleMethod(GuiMenuBar, setMenuText, void, 4, 4, "(string menu, string newMenuText) - sets the text of the specified menu to the new string.")
|
||||
{
|
||||
if(dIsdigit(argv[3][0]))
|
||||
{
|
||||
Con::errorf("Cannot name menu %s to %s. First character of a menu's text cannot be a digit.", argv[2], argv[3]);
|
||||
return;
|
||||
}
|
||||
GuiMenuBar::Menu *menu = object->findMenu(argv[2]);
|
||||
if(!menu)
|
||||
{
|
||||
Con::errorf("Cannot find menu %s for setMenuText.", argv[2]);
|
||||
return;
|
||||
}
|
||||
dFree(menu->text);
|
||||
menu->text = dStrdup(argv[3]);
|
||||
object->menuBarDirty = true;
|
||||
}
|
||||
|
||||
ConsoleMethod(GuiMenuBar, setMenuVisible, void, 4, 4, "(string menu, bool visible) - sets the whether or not to display the specified menu.")
|
||||
{
|
||||
GuiMenuBar::Menu *menu = object->findMenu(argv[2]);
|
||||
if(!menu)
|
||||
{
|
||||
Con::errorf("Cannot find menu %s for setMenuVisible.", argv[2]);
|
||||
return;
|
||||
}
|
||||
menu->visible = dAtob(argv[3]);
|
||||
object->menuBarDirty = true;
|
||||
object->setUpdate();
|
||||
}
|
||||
|
||||
ConsoleMethod(GuiMenuBar, setMenuItemText, void, 5, 5, "(string menu, string menuItem, string newMenuItemText) - sets the text of the specified menu item to the new string.")
|
||||
{
|
||||
if(dIsdigit(argv[4][0]))
|
||||
{
|
||||
Con::errorf("Cannot name menu item %s to %s. First character of a menu item's text cannot be a digit.", argv[3], argv[4]);
|
||||
return;
|
||||
}
|
||||
GuiMenuBar::Menu *menu = object->findMenu(argv[2]);
|
||||
if(!menu)
|
||||
{
|
||||
Con::errorf("Cannot find menu %s for setMenuItemText.", argv[2]);
|
||||
return;
|
||||
}
|
||||
GuiMenuBar::MenuItem *menuItem = object->findMenuItem(menu, argv[3]);
|
||||
if(!menuItem)
|
||||
{
|
||||
Con::errorf("Cannot find menu item %s for setMenuItemText.", argv[3]);
|
||||
return;
|
||||
}
|
||||
dFree(menuItem->text);
|
||||
menuItem->text = dStrdup(argv[4]);
|
||||
}
|
||||
|
||||
ConsoleMethod(GuiMenuBar, setMenuItemVisible, void, 5, 5, "(string menu, string menuItem, bool isVisible) - sets the specified menu item to be either visible or not.")
|
||||
{
|
||||
GuiMenuBar::Menu *menu = object->findMenu(argv[2]);
|
||||
if(!menu)
|
||||
{
|
||||
Con::errorf("Cannot find menu %s for setMenuItemVisible.", argv[2]);
|
||||
return;
|
||||
}
|
||||
GuiMenuBar::MenuItem *menuItem = object->findMenuItem(menu, argv[3]);
|
||||
if(!menuItem)
|
||||
{
|
||||
Con::errorf("Cannot find menu item %s for setMenuItemVisible.", argv[3]);
|
||||
return;
|
||||
}
|
||||
menuItem->visible = dAtob(argv[4]);
|
||||
}
|
||||
|
||||
ConsoleMethod(GuiMenuBar, setMenuItemBitmap, void, 5, 5, "(string menu, string menuItem, int bitmapIndex) - sets the specified menu item bitmap index in the bitmap array. Setting the item's index to -1 will remove any bitmap.")
|
||||
{
|
||||
GuiMenuBar::Menu *menu = object->findMenu(argv[2]);
|
||||
if(!menu)
|
||||
{
|
||||
Con::errorf("Cannot find menu %s for setMenuItemBitmap.", argv[2]);
|
||||
return;
|
||||
}
|
||||
GuiMenuBar::MenuItem *menuItem = object->findMenuItem(menu, argv[3]);
|
||||
if(!menuItem)
|
||||
{
|
||||
Con::errorf("Cannot find menu item %s for setMenuItemBitmap.", argv[3]);
|
||||
return;
|
||||
}
|
||||
menuItem->bitmapIndex = dAtoi(argv[4]);
|
||||
}
|
||||
|
||||
ConsoleMethod(GuiMenuBar, removeMenuItem, void, 4, 4, "(string menu, string menuItem) - removes the specified menu item from the menu.")
|
||||
{
|
||||
GuiMenuBar::Menu *menu = object->findMenu(argv[2]);
|
||||
if(!menu)
|
||||
{
|
||||
Con::errorf("Cannot find menu %s for removeMenuItem.", argv[2]);
|
||||
return;
|
||||
}
|
||||
GuiMenuBar::MenuItem *menuItem = object->findMenuItem(menu, argv[3]);
|
||||
if(!menuItem)
|
||||
{
|
||||
Con::errorf("Cannot find menu item %s for removeMenuItem.", argv[3]);
|
||||
return;
|
||||
}
|
||||
object->removeMenuItem(menu, menuItem);
|
||||
}
|
||||
|
||||
ConsoleMethod(GuiMenuBar, clearMenuItems, void, 3, 3, "(string menu) - removes all the menu items from the specified menu.")
|
||||
{
|
||||
GuiMenuBar::Menu *menu = object->findMenu(argv[2]);
|
||||
if(!menu)
|
||||
{
|
||||
Con::errorf("Cannot find menu %s for clearMenuItems.", argv[2]);
|
||||
return;
|
||||
}
|
||||
object->clearMenuItems(menu);
|
||||
}
|
||||
|
||||
ConsoleMethod(GuiMenuBar, removeMenu, void, 3, 3, "(string menu) - removes the specified menu from the menu bar.")
|
||||
{
|
||||
GuiMenuBar::Menu *menu = object->findMenu(argv[2]);
|
||||
if(!menu)
|
||||
{
|
||||
Con::errorf("Cannot find menu %s for removeMenu.", argv[2]);
|
||||
return;
|
||||
}
|
||||
object->clearMenuItems(menu);
|
||||
object->menuBarDirty = true;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// menu management methods
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
void GuiMenuBar::addMenu(const char *menuText, U32 menuId)
|
||||
{
|
||||
// allocate the menu
|
||||
Menu *newMenu = new Menu;
|
||||
newMenu->text = dStrdup(menuText);
|
||||
newMenu->id = menuId;
|
||||
newMenu->nextMenu = NULL;
|
||||
newMenu->firstMenuItem = NULL;
|
||||
newMenu->visible = true;
|
||||
|
||||
// add it to the menu list
|
||||
menuBarDirty = true;
|
||||
Menu **walk;
|
||||
for(walk = &menuList; *walk; walk = &(*walk)->nextMenu)
|
||||
;
|
||||
*walk = newMenu;
|
||||
}
|
||||
|
||||
GuiMenuBar::Menu *GuiMenuBar::findMenu(const char *menu)
|
||||
{
|
||||
if(dIsdigit(menu[0]))
|
||||
{
|
||||
U32 id = dAtoi(menu);
|
||||
for(Menu *walk = menuList; walk; walk = walk->nextMenu)
|
||||
if(id == walk->id)
|
||||
return walk;
|
||||
return NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
for(Menu *walk = menuList; walk; walk = walk->nextMenu)
|
||||
if(!dStricmp(menu, walk->text))
|
||||
return walk;
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
GuiMenuBar::MenuItem *GuiMenuBar::findMenuItem(Menu *menu, const char *menuItem)
|
||||
{
|
||||
if(dIsdigit(menuItem[0]))
|
||||
{
|
||||
U32 id = dAtoi(menuItem);
|
||||
for(MenuItem *walk = menu->firstMenuItem; walk; walk = walk->nextMenuItem)
|
||||
if(id == walk->id)
|
||||
return walk;
|
||||
return NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
for(MenuItem *walk = menu->firstMenuItem; walk; walk = walk->nextMenuItem)
|
||||
if(!dStricmp(menuItem, walk->text))
|
||||
return walk;
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void GuiMenuBar::removeMenu(Menu *menu)
|
||||
{
|
||||
menuBarDirty = true;
|
||||
clearMenuItems(menu);
|
||||
for(Menu **walk = &menuList; *walk; walk = &(*walk)->nextMenu)
|
||||
{
|
||||
if(*walk == menu)
|
||||
{
|
||||
*walk = menu->nextMenu;
|
||||
break;
|
||||
}
|
||||
}
|
||||
dFree(menu->text);
|
||||
delete menu;
|
||||
}
|
||||
|
||||
void GuiMenuBar::removeMenuItem(Menu *menu, MenuItem *menuItem)
|
||||
{
|
||||
for(MenuItem **walk = &menu->firstMenuItem; *walk; walk = &(*walk)->nextMenuItem)
|
||||
{
|
||||
if(*walk == menuItem)
|
||||
{
|
||||
*walk = menuItem->nextMenuItem;
|
||||
break;
|
||||
}
|
||||
}
|
||||
dFree(menuItem->text);
|
||||
dFree(menuItem->accelerator);
|
||||
delete menuItem;
|
||||
}
|
||||
|
||||
void GuiMenuBar::addMenuItem(Menu *menu, const char *text, U32 id, const char *accelerator, S32 checkGroup)
|
||||
{
|
||||
// allocate the new menu item
|
||||
MenuItem *newMenuItem = new MenuItem;
|
||||
newMenuItem->text = dStrdup(text);
|
||||
if(accelerator[0])
|
||||
newMenuItem->accelerator = dStrdup(accelerator);
|
||||
else
|
||||
newMenuItem->accelerator = NULL;
|
||||
newMenuItem->id = id;
|
||||
newMenuItem->checkGroup = checkGroup;
|
||||
newMenuItem->nextMenuItem = NULL;
|
||||
newMenuItem->acceleratorIndex = 0;
|
||||
newMenuItem->enabled = text[0] != '-';
|
||||
newMenuItem->visible = true;
|
||||
newMenuItem->bitmapIndex = -1;
|
||||
|
||||
// link it into the menu's menu item list
|
||||
MenuItem **walk = &menu->firstMenuItem;
|
||||
while(*walk)
|
||||
walk = &(*walk)->nextMenuItem;
|
||||
*walk = newMenuItem;
|
||||
|
||||
}
|
||||
|
||||
void GuiMenuBar::clearMenuItems(Menu *menu)
|
||||
{
|
||||
while(menu->firstMenuItem)
|
||||
removeMenuItem(menu, menu->firstMenuItem);
|
||||
}
|
||||
|
||||
void GuiMenuBar::clearMenus()
|
||||
{
|
||||
while(menuList)
|
||||
removeMenu(menuList);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// initialization, input and render methods
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
GuiMenuBar::GuiMenuBar()
|
||||
{
|
||||
menuList = NULL;
|
||||
menuBarDirty = true;
|
||||
mouseDownMenu = NULL;
|
||||
mouseOverMenu = NULL;
|
||||
mCurAcceleratorIndex = 0;
|
||||
mBackground = NULL;
|
||||
}
|
||||
|
||||
bool GuiMenuBar::onWake()
|
||||
{
|
||||
if(!Parent::onWake())
|
||||
return false;
|
||||
mProfile->constructBitmapArray(); // if a bitmap was specified...
|
||||
maxBitmapSize.set(0,0);
|
||||
S32 numBitmaps = mProfile->mBitmapArrayRects.size();
|
||||
if(numBitmaps)
|
||||
{
|
||||
RectI *bitmapBounds = mProfile->mBitmapArrayRects.address();
|
||||
for(S32 i = 0; i < numBitmaps; i++)
|
||||
{
|
||||
if(bitmapBounds[i].extent.x > maxBitmapSize.x)
|
||||
maxBitmapSize.x = bitmapBounds[i].extent.x;
|
||||
if(bitmapBounds[i].extent.y > maxBitmapSize.y)
|
||||
maxBitmapSize.y = bitmapBounds[i].extent.y;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
GuiMenuBar::Menu *GuiMenuBar::findHitMenu(Point2I mousePoint)
|
||||
{
|
||||
Point2I pos = globalToLocalCoord(mousePoint);
|
||||
|
||||
for(Menu *walk = menuList; walk; walk = walk->nextMenu)
|
||||
if(walk->visible && walk->bounds.pointInRect(pos))
|
||||
return walk;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void GuiMenuBar::onPreRender()
|
||||
{
|
||||
Parent::onPreRender();
|
||||
if(menuBarDirty)
|
||||
{
|
||||
menuBarDirty = false;
|
||||
U32 curX = 0;
|
||||
for(Menu *walk = menuList; walk; walk = walk->nextMenu)
|
||||
{
|
||||
if(!walk->visible)
|
||||
continue;
|
||||
walk->bounds.set(curX, 1, mProfile->mFont->getStrWidth((const UTF8 *)walk->text) + 12, mBounds.extent.y - 2);
|
||||
curX += walk->bounds.extent.x;
|
||||
}
|
||||
mouseOverMenu = NULL;
|
||||
mouseDownMenu = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void GuiMenuBar::checkMenuMouseMove(const GuiEvent &event)
|
||||
{
|
||||
Menu *hit = findHitMenu(event.mousePoint);
|
||||
if(hit && hit != mouseDownMenu)
|
||||
{
|
||||
// gotta close out the current menu...
|
||||
mTextList->setSelectedCell(Point2I(-1, -1));
|
||||
closeMenu();
|
||||
mouseOverMenu = mouseDownMenu = hit;
|
||||
setUpdate();
|
||||
onAction();
|
||||
}
|
||||
}
|
||||
|
||||
void GuiMenuBar::onMouseMove(const GuiEvent &event)
|
||||
{
|
||||
Menu *hit = findHitMenu(event.mousePoint);
|
||||
if(hit != mouseOverMenu)
|
||||
{
|
||||
mouseOverMenu = hit;
|
||||
setUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
void GuiMenuBar::onMouseLeave(const GuiEvent &event)
|
||||
{
|
||||
if(mouseOverMenu)
|
||||
setUpdate();
|
||||
mouseOverMenu = NULL;
|
||||
}
|
||||
|
||||
void GuiMenuBar::onMouseDragged(const GuiEvent &event)
|
||||
{
|
||||
Menu *hit = findHitMenu(event.mousePoint);
|
||||
|
||||
if(hit != mouseOverMenu)
|
||||
{
|
||||
mouseOverMenu = hit;
|
||||
mouseDownMenu = hit;
|
||||
setUpdate();
|
||||
onAction();
|
||||
}
|
||||
}
|
||||
|
||||
void GuiMenuBar::onMouseDown(const GuiEvent &event)
|
||||
{
|
||||
mouseDownMenu = mouseOverMenu = findHitMenu(event.mousePoint);
|
||||
setUpdate();
|
||||
onAction();
|
||||
}
|
||||
|
||||
void GuiMenuBar::onMouseUp(const GuiEvent &event)
|
||||
{
|
||||
mouseDownMenu = NULL;
|
||||
setUpdate();
|
||||
}
|
||||
|
||||
void GuiMenuBar::onRender(Point2I offset, const RectI &updateRect)
|
||||
{
|
||||
//if opaque, fill the update rect with the fill color
|
||||
if (mProfile->mOpaque)
|
||||
dglDrawRectFill(RectI(offset, mBounds.extent), mProfile->mFillColor);
|
||||
|
||||
for(Menu *walk = menuList; walk; walk = walk->nextMenu)
|
||||
{
|
||||
if(!walk->visible)
|
||||
continue;
|
||||
ColorI fontColor = mProfile->mFontColor;
|
||||
RectI bounds = walk->bounds;
|
||||
bounds.point += offset;
|
||||
|
||||
Point2I start;
|
||||
|
||||
start.x = walk->bounds.point.x + 6;
|
||||
start.y = walk->bounds.point.y + ( walk->bounds.extent.y - ( mProfile->mFont->getHeight() - 2 ) ) / 2;
|
||||
|
||||
if(walk == mouseDownMenu)
|
||||
renderSlightlyLoweredBox(bounds, mProfile);
|
||||
else if(walk == mouseOverMenu && mouseDownMenu == NULL)
|
||||
renderSlightlyRaisedBox(bounds, mProfile);
|
||||
|
||||
dglSetBitmapModulation( fontColor );
|
||||
|
||||
dglDrawText( mProfile->mFont, start + offset, walk->text, mProfile->mFontColors );
|
||||
}
|
||||
}
|
||||
|
||||
void GuiMenuBar::buildAcceleratorMap()
|
||||
{
|
||||
Parent::buildAcceleratorMap();
|
||||
// ok, accelerator map is cleared...
|
||||
// add all our keys:
|
||||
mCurAcceleratorIndex = 1;
|
||||
|
||||
for(Menu *menu = menuList; menu; menu = menu->nextMenu)
|
||||
{
|
||||
for(MenuItem *item = menu->firstMenuItem; item; item = item->nextMenuItem)
|
||||
{
|
||||
if(!item->accelerator)
|
||||
{
|
||||
item->accelerator = 0;
|
||||
continue;
|
||||
}
|
||||
EventDescriptor accelEvent;
|
||||
ActionMap::createEventDescriptor(item->accelerator, &accelEvent);
|
||||
|
||||
//now we have a modifier, and a key, add them to the canvas
|
||||
GuiCanvas *root = getRoot();
|
||||
if (root)
|
||||
root->addAcceleratorKey(this, mCurAcceleratorIndex, accelEvent.eventCode, accelEvent.flags);
|
||||
item->acceleratorIndex = mCurAcceleratorIndex;
|
||||
mCurAcceleratorIndex++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GuiMenuBar::acceleratorKeyPress(U32 index)
|
||||
{
|
||||
// loop through all the menus
|
||||
// and find the item that corresponds to the accelerator index
|
||||
for(Menu *menu = menuList; menu; menu = menu->nextMenu)
|
||||
{
|
||||
if(!menu->visible)
|
||||
continue;
|
||||
|
||||
for(MenuItem *item = menu->firstMenuItem; item; item = item->nextMenuItem)
|
||||
{
|
||||
if(item->acceleratorIndex == index)
|
||||
{
|
||||
// first, call the script callback for menu selection:
|
||||
Con::executef( this, 4, "onMenuSelect", Con::getIntArg(menu->id),
|
||||
menu->text);
|
||||
if(item->visible)
|
||||
menuItemSelected(menu, item);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Menu display class methods
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
GuiMenuBackgroundCtrl::GuiMenuBackgroundCtrl(GuiMenuBar *ctrl, GuiMenuTextListCtrl *textList)
|
||||
{
|
||||
mMenuBarCtrl = ctrl;
|
||||
mTextList = textList;
|
||||
}
|
||||
|
||||
void GuiMenuBackgroundCtrl::onMouseDown(const GuiEvent &event)
|
||||
{
|
||||
mTextList->setSelectedCell(Point2I(-1,-1));
|
||||
mMenuBarCtrl->closeMenu();
|
||||
}
|
||||
|
||||
void GuiMenuBackgroundCtrl::onMouseMove(const GuiEvent &event)
|
||||
{
|
||||
GuiCanvas *root = getRoot();
|
||||
GuiControl *ctrlHit = root->findHitControl(event.mousePoint, mLayer - 1);
|
||||
if(ctrlHit == mMenuBarCtrl) // see if the current mouse over menu is right...
|
||||
mMenuBarCtrl->checkMenuMouseMove(event);
|
||||
}
|
||||
|
||||
void GuiMenuBackgroundCtrl::onMouseDragged(const GuiEvent &event)
|
||||
{
|
||||
GuiCanvas *root = getRoot();
|
||||
GuiControl *ctrlHit = root->findHitControl(event.mousePoint, mLayer - 1);
|
||||
if(ctrlHit == mMenuBarCtrl) // see if the current mouse over menu is right...
|
||||
mMenuBarCtrl->checkMenuMouseMove(event);
|
||||
}
|
||||
|
||||
GuiMenuTextListCtrl::GuiMenuTextListCtrl(GuiMenuBar *ctrl)
|
||||
{
|
||||
mMenuBarCtrl = ctrl;
|
||||
}
|
||||
|
||||
void GuiMenuTextListCtrl::onRenderCell(Point2I offset, Point2I cell, bool selected, bool mouseOver)
|
||||
{
|
||||
if(dStrcmp(mList[cell.y].text + 2, "-\t"))
|
||||
Parent::onRenderCell(offset, cell, selected, mouseOver);
|
||||
else
|
||||
{
|
||||
S32 yp = offset.y + mCellSize.y / 2;
|
||||
dglDrawLine(offset.x, yp, offset.x + mCellSize.x, yp, ColorI(128,128,128));
|
||||
dglDrawLine(offset.x, yp+1, offset.x + mCellSize.x, yp+1, ColorI(255,255,255));
|
||||
}
|
||||
// now see if there's a bitmap...
|
||||
U8 idx = mList[cell.y].text[0];
|
||||
if(idx != 1)
|
||||
{
|
||||
// there's a bitmap...
|
||||
U32 index = U32(idx - 2) * 3;
|
||||
if(!mList[cell.y].active)
|
||||
index += 2;
|
||||
else if(selected || mouseOver)
|
||||
index ++;
|
||||
|
||||
RectI rect = mProfile->mBitmapArrayRects[index];
|
||||
Point2I off = mMenuBarCtrl->maxBitmapSize - rect.extent;
|
||||
off /= 2;
|
||||
|
||||
dglClearBitmapModulation();
|
||||
dglDrawBitmapSR(mProfile->mTextureHandle, offset + off, rect);
|
||||
}
|
||||
}
|
||||
|
||||
bool GuiMenuTextListCtrl::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 )
|
||||
{
|
||||
mMenuBarCtrl->closeMenu();
|
||||
return true;
|
||||
}
|
||||
else if ( event.keyCode == KEY_ESCAPE )
|
||||
{
|
||||
mSelectedCell.set( -1, -1 );
|
||||
mMenuBarCtrl->closeMenu();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
//otherwise, pass the event to it's parent
|
||||
return Parent::onKeyDown(event);
|
||||
}
|
||||
|
||||
void GuiMenuTextListCtrl::onMouseDown(const GuiEvent &event)
|
||||
{
|
||||
Parent::onMouseDown(event);
|
||||
mMenuBarCtrl->closeMenu();
|
||||
}
|
||||
|
||||
void GuiMenuTextListCtrl::onMouseUp(const GuiEvent &event)
|
||||
{
|
||||
// ok, this is kind of strange... but!
|
||||
// here's the deal: if we get a mouse up in this control
|
||||
// it means the mouse was dragged from the initial menu mouse click
|
||||
// so: activate the menu result as though this event were,
|
||||
// instead, a mouse down.
|
||||
|
||||
onMouseDown(event);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
void GuiMenuBar::menuItemSelected(GuiMenuBar::Menu *menu, GuiMenuBar::MenuItem *item)
|
||||
{
|
||||
if(item->enabled)
|
||||
Con::executef( this, 6, "onMenuItemSelect", Con::getIntArg(menu->id),
|
||||
menu->text, Con::getIntArg(item->id), item->text);
|
||||
}
|
||||
|
||||
void GuiMenuBar::onSleep()
|
||||
{
|
||||
if(mBackground) // a menu is up?
|
||||
{
|
||||
mTextList->setSelectedCell(Point2I(-1, -1));
|
||||
closeMenu();
|
||||
}
|
||||
Parent::onSleep();
|
||||
}
|
||||
|
||||
void GuiMenuBar::closeMenu()
|
||||
{
|
||||
// Get the selection from the text list:
|
||||
S32 selectionIndex = mTextList->getSelectedCell().y;
|
||||
|
||||
// Pop the background:
|
||||
getRoot()->popDialogControl(mBackground);
|
||||
|
||||
// Kill the popup:
|
||||
mBackground->deleteObject();
|
||||
mBackground = NULL;
|
||||
|
||||
// Now perform the popup action:
|
||||
if ( selectionIndex != -1 )
|
||||
{
|
||||
MenuItem *list = mouseDownMenu->firstMenuItem;
|
||||
|
||||
while(selectionIndex && list)
|
||||
{
|
||||
list = list->nextMenuItem;
|
||||
selectionIndex--;
|
||||
}
|
||||
if(list)
|
||||
menuItemSelected(mouseDownMenu, list);
|
||||
}
|
||||
mouseDownMenu = NULL;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
void GuiMenuBar::onAction()
|
||||
{
|
||||
if(!mouseDownMenu)
|
||||
return;
|
||||
|
||||
// first, call the script callback for menu selection:
|
||||
Con::executef( this, 4, "onMenuSelect", Con::getIntArg(mouseDownMenu->id),
|
||||
mouseDownMenu->text);
|
||||
|
||||
MenuItem *visWalk = mouseDownMenu->firstMenuItem;
|
||||
while(visWalk)
|
||||
{
|
||||
if(visWalk->visible)
|
||||
break;
|
||||
visWalk = visWalk->nextMenuItem;
|
||||
}
|
||||
if(!visWalk)
|
||||
{
|
||||
mouseDownMenu = NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
mTextList = new GuiMenuTextListCtrl(this);
|
||||
mTextList->mProfile = mProfile;
|
||||
|
||||
mBackground = new GuiMenuBackgroundCtrl(this, mTextList);
|
||||
|
||||
GuiCanvas *root = getRoot();
|
||||
Point2I windowExt = root->mBounds.extent;
|
||||
|
||||
mBackground->mBounds.point.set(0,0);
|
||||
mBackground->mBounds.extent = root->mBounds.extent;
|
||||
|
||||
S32 textWidth = 0, width = 0;
|
||||
S32 acceleratorWidth = 0;
|
||||
|
||||
GFont *font = mProfile->mFont;
|
||||
|
||||
for(MenuItem *walk = mouseDownMenu->firstMenuItem; walk; walk = walk->nextMenuItem)
|
||||
{
|
||||
if(!walk->visible)
|
||||
continue;
|
||||
|
||||
S32 iTextWidth = font->getStrWidth((const UTF8 *)walk->text);
|
||||
S32 iAcceleratorWidth = walk->accelerator ? font->getStrWidth((const UTF8 *)walk->accelerator) : 0;
|
||||
|
||||
if(iTextWidth > textWidth)
|
||||
textWidth = iTextWidth;
|
||||
if(iAcceleratorWidth > acceleratorWidth)
|
||||
acceleratorWidth = iAcceleratorWidth;
|
||||
}
|
||||
width = textWidth + acceleratorWidth + maxBitmapSize.x * 2 + 2 + 4;
|
||||
|
||||
mTextList->setCellSize(Point2I(width, font->getHeight()+3));
|
||||
mTextList->clearColumnOffsets();
|
||||
mTextList->addColumnOffset(-1); // add an empty column in for the bitmap index.
|
||||
mTextList->addColumnOffset(maxBitmapSize.x + 1);
|
||||
mTextList->addColumnOffset(maxBitmapSize.x + 1 + textWidth + 4);
|
||||
|
||||
U32 entryCount = 0;
|
||||
|
||||
for(MenuItem *walk = mouseDownMenu->firstMenuItem; walk; walk = walk->nextMenuItem)
|
||||
{
|
||||
if(!walk->visible)
|
||||
continue;
|
||||
|
||||
char buf[512];
|
||||
char bitmapIndex = 1;
|
||||
if(walk->bitmapIndex >= 0 && (walk->bitmapIndex * 3 <= mProfile->mBitmapArrayRects.size()))
|
||||
bitmapIndex = walk->bitmapIndex + 2;
|
||||
dSprintf(buf, sizeof(buf), "%c\t%s\t%s", bitmapIndex, walk->text, walk->accelerator ? walk->accelerator : "");
|
||||
mTextList->addEntry(entryCount, buf);
|
||||
|
||||
if(!walk->enabled)
|
||||
mTextList->setEntryActive(entryCount, false);
|
||||
|
||||
entryCount++;
|
||||
}
|
||||
Point2I menuPoint = localToGlobalCoord(mouseDownMenu->bounds.point);
|
||||
menuPoint.y += mouseDownMenu->bounds.extent.y + 2;
|
||||
|
||||
GuiControl *ctrl = new GuiControl;
|
||||
ctrl->mBounds.point = menuPoint;
|
||||
ctrl->mBounds.extent = mTextList->mBounds.extent + Point2I(6, 6);
|
||||
ctrl->mProfile = mProfile;
|
||||
mTextList->mBounds.point += Point2I(3,3);
|
||||
|
||||
//mTextList->mBounds.point = Point2I(3,3);
|
||||
|
||||
mTextList->registerObject();
|
||||
mBackground->registerObject();
|
||||
ctrl->registerObject();
|
||||
|
||||
mBackground->addObject( ctrl );
|
||||
ctrl->addObject( mTextList );
|
||||
|
||||
root->pushDialogControl(mBackground, mLayer + 1);
|
||||
mTextList->setFirstResponder();
|
||||
}
|
||||
|
||||
|
131
engine/gui/editor/guiMenuBar.h
Executable file
131
engine/gui/editor/guiMenuBar.h
Executable file
@ -0,0 +1,131 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// Torque Game Engine
|
||||
// Copyright (C) GarageGames.com, Inc.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef _GUIMENUBAR_H_
|
||||
#define _GUIMENUBAR_H_
|
||||
|
||||
#ifndef _GUITEXTLISTCTRL_H_
|
||||
#include "gui/guiTextListCtrl.h"
|
||||
#endif
|
||||
|
||||
class GuiMenuBar;
|
||||
class GuiMenuTextListCtrl;
|
||||
|
||||
class GuiMenuBackgroundCtrl : public GuiControl
|
||||
{
|
||||
protected:
|
||||
GuiMenuBar *mMenuBarCtrl;
|
||||
GuiMenuTextListCtrl *mTextList;
|
||||
public:
|
||||
GuiMenuBackgroundCtrl(GuiMenuBar *ctrl, GuiMenuTextListCtrl* textList);
|
||||
void onMouseDown(const GuiEvent &event);
|
||||
void onMouseMove(const GuiEvent &event);
|
||||
void onMouseDragged(const GuiEvent &event);
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
class GuiMenuTextListCtrl : public GuiTextListCtrl
|
||||
{
|
||||
private:
|
||||
typedef GuiTextListCtrl Parent;
|
||||
|
||||
protected:
|
||||
GuiMenuBar *mMenuBarCtrl;
|
||||
|
||||
public:
|
||||
GuiMenuTextListCtrl(); // for inheritance
|
||||
GuiMenuTextListCtrl(GuiMenuBar *ctrl);
|
||||
|
||||
// GuiControl overloads:
|
||||
bool onKeyDown(const GuiEvent &event);
|
||||
void onMouseDown(const GuiEvent &event);
|
||||
void onMouseUp(const GuiEvent &event);
|
||||
void onRenderCell(Point2I offset, Point2I cell, bool selected, bool mouseOver);
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
class GuiMenuBar : public GuiControl
|
||||
{
|
||||
typedef GuiControl Parent;
|
||||
public:
|
||||
|
||||
struct MenuItem // an individual item in a pull-down menu
|
||||
{
|
||||
char *text; // the text of the menu item
|
||||
U32 id; // a script-assigned identifier
|
||||
char *accelerator; // the keyboard accelerator shortcut for the menu item
|
||||
U32 acceleratorIndex; // index of this accelerator
|
||||
bool enabled; // true if the menu item is selectable
|
||||
bool visible; // true if the menu item is visible
|
||||
S32 bitmapIndex; // index of the bitmap in the bitmap array
|
||||
S32 checkGroup; // the group index of the item visa vi check marks -
|
||||
// only one item in the group can be checked.
|
||||
MenuItem *nextMenuItem; // next menu item in the linked list
|
||||
};
|
||||
struct Menu
|
||||
{
|
||||
char *text;
|
||||
U32 id;
|
||||
RectI bounds;
|
||||
bool visible;
|
||||
|
||||
Menu *nextMenu;
|
||||
MenuItem *firstMenuItem;
|
||||
};
|
||||
|
||||
GuiMenuBackgroundCtrl *mBackground;
|
||||
GuiMenuTextListCtrl *mTextList;
|
||||
|
||||
Menu *menuList;
|
||||
Menu *mouseDownMenu;
|
||||
Menu *mouseOverMenu;
|
||||
|
||||
bool menuBarDirty;
|
||||
U32 mCurAcceleratorIndex;
|
||||
Point2I maxBitmapSize;
|
||||
|
||||
GuiMenuBar();
|
||||
bool onWake();
|
||||
void onSleep();
|
||||
|
||||
// internal menu handling functions
|
||||
// these are used by the script manipulation functions to add/remove/change menu items
|
||||
|
||||
void addMenu(const char *menuText, U32 menuId);
|
||||
Menu *findMenu(const char *menu); // takes either a menu text or a string id
|
||||
MenuItem *findMenuItem(Menu *menu, const char *menuItem); // takes either a menu text or a string id
|
||||
void removeMenu(Menu *menu);
|
||||
void removeMenuItem(Menu *menu, MenuItem *menuItem);
|
||||
void addMenuItem(Menu *menu, const char *text, U32 id, const char *accelerator, S32 checkGroup);
|
||||
void clearMenuItems(Menu *menu);
|
||||
void clearMenus();
|
||||
|
||||
// display/mouse functions
|
||||
|
||||
Menu *findHitMenu(Point2I mousePoint);
|
||||
|
||||
void onPreRender();
|
||||
void onRender(Point2I offset, const RectI &updateRect);
|
||||
|
||||
void checkMenuMouseMove(const GuiEvent &event);
|
||||
void onMouseMove(const GuiEvent &event);
|
||||
void onMouseLeave(const GuiEvent &event);
|
||||
void onMouseDown(const GuiEvent &event);
|
||||
void onMouseDragged(const GuiEvent &event);
|
||||
void onMouseUp(const GuiEvent &event);
|
||||
|
||||
void onAction();
|
||||
void closeMenu();
|
||||
void buildAcceleratorMap();
|
||||
void acceleratorKeyPress(U32 index);
|
||||
|
||||
void menuItemSelected(Menu *menu, MenuItem *item);
|
||||
|
||||
DECLARE_CONOBJECT(GuiMenuBar);
|
||||
};
|
||||
|
||||
#endif
|
Reference in New Issue
Block a user