Engine directory for ticket #1

This commit is contained in:
DavidWyand-GG 2012-09-19 11:15:01 -04:00
parent 352279af7a
commit 7dbfe6994d
3795 changed files with 1363358 additions and 0 deletions

View file

@ -0,0 +1,79 @@
//-----------------------------------------------------------------------------
// Copyright (c) 2012 GarageGames, LLC
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//-----------------------------------------------------------------------------
#include "platform/platform.h"
#include "gui/editor/editorFunctions.h"
#include "console/simObject.h"
bool validateObjectName( const char *data, const SimObject *object )
{
if( !data || !data[ 0 ] )
return true;
bool isValidId = true;
if( !dIsalpha( data[ 0 ] ) && data[ 0 ] != '_' )
isValidId = false;
else
{
for( U32 i = 1; data[ i ] != '\0'; ++ i )
{
if( !dIsalnum( data[ i ] ) && data[ i ] != '_' )
{
isValidId = false;
break;
}
}
}
if( !isValidId )
{
Platform::AlertOK( "Invalid Object Name", avar( "'%s' is not a valid "
"object name. Please choose a name that begins with a letter or "
"underscore and is otherwise comprised exclusively of letters, "
"digits, and/or underscores.", data ) );
return false;
}
SimObject *pTemp = NULL;
if ( Sim::findObject( data, pTemp ) && pTemp != object )
{
const char* filename = pTemp->getFilename();
if ( !filename || !filename[0] )
filename = "an unknown file";
Platform::AlertOK( "Invalid Object Name", avar( "Object names must be unique, "
"and there is an existing %s object with the name '%s' (defined in %s). "
"Please choose another name.", pTemp->getClassName(), data, filename ) );
return false;
}
if ( AbstractClassRep::findClassRep( data ) )
{
Platform::AlertOK( "Invalid Object Name", avar( "'%s' is the name of an "
"existing TorqueScript class. Please choose another name.", data ) );
return false;
}
return true;
}

View file

@ -0,0 +1,33 @@
//-----------------------------------------------------------------------------
// Copyright (c) 2012 GarageGames, LLC
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//-----------------------------------------------------------------------------
#ifndef _EDITORFUNCTIONS_H_
#define _EDITORFUNCTIONS_H_
class SimObject;
// Returns true if the passed name can be assigned to the passed object.
// This is true if that name is not already in use and it is a valid identifier,
// ( starts with a alpha character ).
bool validateObjectName( const char *name, const SimObject *object );
#endif // _EDITORFUNCTIONS_H_

View file

@ -0,0 +1,705 @@
//-----------------------------------------------------------------------------
// Copyright (c) 2012 GarageGames, LLC
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//-----------------------------------------------------------------------------
#include "platform/platform.h"
#include "gui/editor/guiDebugger.h"
#include "gui/core/guiCanvas.h"
#include "gfx/gfxDrawUtil.h"
#include "core/volume.h"
IMPLEMENT_CONOBJECT(DbgFileView);
ConsoleDocClass( DbgFileView,
"@brief Remnant from ancient script debugger (TGE days?)\n\n"
"Possibly useful for an editor tooltip.\n\n"
"@internal"
);
static const char* itoa(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;
void *data = NULL;
U32 dataSize = 0;
Torque::FS::ReadFile(fileName, data, dataSize, true);
if(data == NULL)
{
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 = (char *)data;
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 [] static_cast<char*>(data);
//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 + getPosition().y >= 0 && yOffset + getPosition().y < parent->getHeight() - mCellSize.y))
{
//reposition the control
S32 newYOffset = getMin(0, getMax(parent->getHeight() - getHeight(), (mCellSize.y * 4) - yOffset));
setPosition(Point2I(getPosition().x, newYOffset));
}
//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("DbgSetCursorWatch", mMouseOverVariable);
}
else
Con::executef("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, "onRemoveBreakPoint", itoa(cell.y + 1));
else
Con::executef(this, "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, "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)
{
GFX->getDrawUtil()->setBitmapModulation(mProfile->mFontColorHL);
GFX->getDrawUtil()->drawText(mFont, cellOffset, "#");
}
else if (mFileView[cell.y].breakPosition)
{
GFX->getDrawUtil()->setBitmapModulation(mProfile->mFontColor);
GFX->getDrawUtil()->drawText(mFont, cellOffset, "-");
}
cellOffset.x += 8;
//draw in the "current line" indicator
if (mFileName == mPCFileName && (cell.y + 1 == mPCCurrentLine))
{
GFX->getDrawUtil()->setBitmapModulation(mProfile->mFontColorHL);
GFX->getDrawUtil()->drawText(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)
{
GFX->getDrawUtil()->drawRectFill(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
GFX->getDrawUtil()->drawRectFill(RectI(cellOffset.x + startPos, cellOffset.y - 3, endPos - startPos + 2, mCellSize.y + 6), mProfile->mFillColorHL);
}
}
//draw the line of text
GFX->getDrawUtil()->setBitmapModulation(mFileView[cell.y].breakOnLine ? mProfile->mFontColorHL : mProfile->mFontColor);
GFX->getDrawUtil()->drawText(mFont, cellOffset, mFileView[cell.y].text);
}

View file

@ -0,0 +1,101 @@
//-----------------------------------------------------------------------------
// Copyright (c) 2012 GarageGames, LLC
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//-----------------------------------------------------------------------------
#ifndef _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);
DECLARE_CATEGORY( "Gui Editor" );
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

View file

@ -0,0 +1,113 @@
//-----------------------------------------------------------------------------
// Copyright (c) 2012 GarageGames, LLC
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//-----------------------------------------------------------------------------
#include "gui/editor/guiEaseViewCtrl.h"
#include "console/consoleTypes.h"
#include "math/mMath.h"
#include "gfx/gfxDrawUtil.h"
IMPLEMENT_CONOBJECT( GuiEaseViewCtrl );
ConsoleDocClass( GuiEaseViewCtrl,
"@brief Control to visualize an EaseF.\n\n"
"Editor use only.\n\n"
"@see EaseF\n\n"
"@internal"
);
//-----------------------------------------------------------------------------
GuiEaseViewCtrl::GuiEaseViewCtrl()
{
mEase.set(Ease::In, Ease::Cubic);
mAxisColor.set(1,1,1,1);
mEaseColor.set(1,1,1,1);
mEaseWidth = 4.0f;
}
//-----------------------------------------------------------------------------
void GuiEaseViewCtrl::initPersistFields()
{
Parent::initPersistFields();
addField("ease", TypeEaseF, Offset( mEase, GuiEaseViewCtrl ) );
addField("easeColor", TypeColorF, Offset( mEaseColor, GuiEaseViewCtrl ) );
addField("easeWidth", TypeF32, Offset(mEaseWidth, GuiEaseViewCtrl ) );
addField("axisColor", TypeColorF, Offset( mAxisColor, GuiEaseViewCtrl ) );
}
//-----------------------------------------------------------------------------
bool GuiEaseViewCtrl::onWake()
{
if (!Parent::onWake())
return false;
setActive(true);
return true;
}
//-----------------------------------------------------------------------------
void GuiEaseViewCtrl::onSleep()
{
setActive(false);
Parent::onSleep();
}
//-----------------------------------------------------------------------------
void GuiEaseViewCtrl::onRender(Point2I offset, const RectI &updateRect)
{
const F32 W = getExtent().x;
const F32 H = getExtent().y;
const F32 plotW = W;
const F32 plotH = H;
const F32 zeroX = offset.x + 1.f;
const F32 zeroY = offset.y;
// Draw axis.
GFX->getDrawUtil()->drawLine( zeroX, zeroY + 0.0f, zeroX, zeroY + plotH, mAxisColor );
GFX->getDrawUtil()->drawLine( zeroX, zeroY + plotH, zeroX + plotW, zeroY + plotH, mAxisColor );
F32 numPoints = W;
F32 lastX = zeroX;
F32 lastY = zeroY + plotH;
// Draw curve.
for( int i = 1; i <= numPoints; ++ i )
{
F32 x = ( F32 ) i / ( F32 ) numPoints;
F32 y = mEase.getValue( x, 0, 1, 1 );
x = zeroX + x * plotW;
y = zeroY + plotH - y * plotH;
GFX->getDrawUtil()->drawLine( lastX, lastY, x, y, mEaseColor );
lastX = x;
lastY = y;
}
}

View file

@ -0,0 +1,63 @@
//-----------------------------------------------------------------------------
// Copyright (c) 2012 GarageGames, LLC
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//-----------------------------------------------------------------------------
#ifndef _GUIEASEVIEWCTRL_H_
#define _GUIEASEVIEWCTRL_H_
#ifndef _GUICONTROL_H_
#include "gui/core/guiControl.h"
#endif
#ifndef _MEASE_H_
#include "math/mEase.h"
#endif
/// Control to visualize an EaseF.
class GuiEaseViewCtrl : public GuiControl
{
public:
typedef GuiControl Parent;
protected:
EaseF mEase; // ease we are visualizing
ColorF mAxisColor; // color to draw axis in
ColorF mEaseColor; // color to draw ease in
F32 mEaseWidth; // width of lines
public:
GuiEaseViewCtrl();
bool onWake();
void onSleep();
void onRender( Point2I, const RectI &);
static void initPersistFields();
DECLARE_CONOBJECT( GuiEaseViewCtrl );
DECLARE_CATEGORY( "Gui Editor" );
DECLARE_DESCRIPTION( "Control that display an EaseF curve." );
};
#endif // !_GUIEASEVIEWCTRL_H_

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,339 @@
//-----------------------------------------------------------------------------
// Copyright (c) 2012 GarageGames, LLC
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//-----------------------------------------------------------------------------
#ifndef _GUIEDITCTRL_H_
#define _GUIEDITCTRL_H_
#ifndef _GUICONTROL_H_
#include "gui/core/guiControl.h"
#endif
#ifndef _UNDO_H_
#include "util/undo.h"
#endif
#ifndef _GFX_GFXDRAWER_H_
#include "gfx/gfxDrawUtil.h"
#endif
/// Native side of the GUI editor.
class GuiEditCtrl : public GuiControl
{
public:
typedef GuiControl Parent;
friend class GuiEditorRuler;
enum Justification
{
JUSTIFY_LEFT,
JUSTIFY_CENTER_VERTICAL,
JUSTIFY_RIGHT,
JUSTIFY_TOP,
JUSTIFY_BOTTOM,
SPACING_VERTICAL,
SPACING_HORIZONTAL,
JUSTIFY_CENTER_HORIZONTAL,
};
enum guideAxis { GuideVertical, GuideHorizontal };
enum mouseModes { Selecting, MovingSelection, SizingSelection, DragSelecting, DragGuide, DragClone };
enum sizingModes { sizingNone = 0, sizingLeft = 1, sizingRight = 2, sizingTop = 4, sizingBottom = 8 };
enum snappingAxis { SnapVertical, SnapHorizontal };
enum snappingEdges { SnapEdgeMin, SnapEdgeMid, SnapEdgeMax };
protected:
enum
{
NUT_SIZE = 4,
MIN_GRID_SIZE = 3
};
typedef Vector< GuiControl* > GuiControlVector;
typedef SimObjectPtr< GuiControl > GuiControlPtr;
bool mDrawBorderLines;
bool mDrawGuides;
bool mFullBoxSelection;
GuiControlVector mSelectedControls;
GuiControlPtr mCurrentAddSet;
GuiControlPtr mContentControl;
Point2I mLastMousePos;
Point2I mLastDragPos;
Point2I mSelectionAnchor;
Point2I mGridSnap;
Point2I mDragBeginPoint;
Vector<Point2I> mDragBeginPoints;
bool mDragAddSelection;
bool mDragMoveUndo;
// Guides.
bool mSnapToGuides; ///< If true, edge and center snapping will work against guides.
bool mDragGuide[ 2 ];
U32 mDragGuideIndex[ 2 ];///< Indices of the guide's being dragged in DragGuide mouse mode.
Vector< U32 > mGuides[ 2 ]; ///< The guides defined on the current content control.
// Snapping
bool mSnapToControls; ///< If true, edge and center snapping will work against controls.
bool mSnapToCanvas; ///< If true, edge and center snapping will work against canvas (= content control).
bool mSnapToEdges; ///< If true, selection edges will snap to other control edges.
bool mSnapToCenters; ///< If true, selection centers will snap to other control centers.
S32 mSnapSensitivity; ///< Snap distance in pixels.
bool mSnapped[ 2 ]; ///< Snap flag for each axis. If true, we are currently snapped in a drag.
S32 mSnapOffset[ 2 ]; ///< Reference point on snap line for each axis.
GuiControlVector mSnapHits[ 2 ]; ///< Hit testing lists for each axis.
snappingEdges mSnapEdge[ 2 ]; ///< Identification of edge being snapped for each axis.
GuiControlPtr mSnapTargets[ 2 ]; ///< Controls providing the snap reference lines on each axis.
// Undo
SimGroup* mTrash;
SimSet* mSelectedSet;
// grid drawing
GFXVertexBufferHandle<GFXVertexPC> mDots;
GFXStateBlockRef mDotSB;
mouseModes mMouseDownMode;
sizingModes mSizingMode;
static StringTableEntry smGuidesPropertyName[ 2 ];
// private methods
void updateSelectedSet();
S32 findGuide( guideAxis axis, const Point2I& point, U32 tolerance = 0 );
RectI getSnapRegion( snappingAxis axis, const Point2I& center ) const;
void findSnaps( snappingAxis axis, const Point2I& mousePoint, const RectI& minRegion, const RectI& midRegion, const RectI& maxRegion );
void registerSnap( snappingAxis axis, const Point2I& mousePoint, const Point2I& point, snappingEdges edge, GuiControl* ctrl = NULL );
void doSnapping( const GuiEvent& event, const RectI& selectionBounds, Point2I& delta );
void doGuideSnap( const GuiEvent& event, const RectI& selectionBounds, const RectI& selectionBoundsGlobal, Point2I& delta );
void doControlSnap( const GuiEvent& event, const RectI& selectionBounds, const RectI& selectionBoundsGlobal, Point2I& delta );
void doGridSnap( const GuiEvent& event, const RectI& selectionBounds, const RectI& selectionBoundsGlobal, Point2I& delta );
void snapToGrid( Point2I& point );
void startDragMove( const Point2I& startPoint );
void startDragRectangle( const Point2I& startPoint );
void startDragClone( const Point2I& startPoint );
void startMouseGuideDrag( guideAxis axis, U32 index, bool lockMouse = true );
void setMouseMode( mouseModes mode );
/// @name Callbacks
/// @{
DECLARE_CALLBACK( void, onHierarchyChanged, () );
DECLARE_CALLBACK( void, onDelete, () );
DECLARE_CALLBACK( void, onPreEdit, ( SimSet* selection ) );
DECLARE_CALLBACK( void, onPostEdit, ( SimSet* selection ) );
DECLARE_CALLBACK( void, onClearSelected, () );
DECLARE_CALLBACK( void, onSelect, ( GuiControl* control ) );
DECLARE_CALLBACK( void, onAddSelected, ( GuiControl* control ) );
DECLARE_CALLBACK( void, onRemoveSelected, ( GuiControl* control ) );
DECLARE_CALLBACK( void, onPreSelectionNudged, ( SimSet* selection ) );
DECLARE_CALLBACK( void, onPostSelectionNudged, ( SimSet* selection ) );
DECLARE_CALLBACK( void, onSelectionMoved, ( GuiControl* control ) ); //FIXME: this should be a selection SimSet
DECLARE_CALLBACK( void, onSelectionCloned, ( SimSet* selection ) );
DECLARE_CALLBACK( void, onTrashSelection, ( SimSet* selection ) );
DECLARE_CALLBACK( void, onAddNewCtrl, ( GuiControl* control ) );
DECLARE_CALLBACK( void, onAddNewCtrlSet, ( SimSet* set ) );
DECLARE_CALLBACK( void, onSelectionResized, ( GuiControl* control ) );
DECLARE_CALLBACK( void, onFitIntoParent, ( bool width, bool height ) );
DECLARE_CALLBACK( void, onMouseModeChange, () );
DECLARE_CALLBACK( void, onControlInspectPreApply, ( GuiControl* control ) );
DECLARE_CALLBACK( void, onControlInspectPostApply, ( GuiControl* control ) );
/// @}
static bool inNut( const Point2I &pt, S32 x, S32 y )
{
S32 dx = pt.x - x;
S32 dy = pt.y - y;
return dx <= NUT_SIZE && dx >= -NUT_SIZE && dy <= NUT_SIZE && dy >= -NUT_SIZE;
}
static void drawCrossSection( U32 axis, S32 offset, const RectI& bounds, ColorI color, GFXDrawUtil* drawer )
{
Point2I start;
Point2I end;
if( axis == 0 )
{
start.x = end.x = offset;
start.y = bounds.point.y;
end.y = bounds.point.y + bounds.extent.y - 1;
}
else
{
start.y = end.y = offset;
start.x = bounds.point.x;
end.x = bounds.point.x + bounds.extent.x - 1;
}
drawer->drawLine( start, end, color );
}
static void snapDelta( snappingAxis axis, snappingEdges edge, S32 offset, const RectI& bounds, Point2I& delta )
{
switch( axis )
{
case SnapVertical:
switch( edge )
{
case SnapEdgeMin:
delta.x = offset - bounds.point.x;
break;
case SnapEdgeMid:
delta.x = offset - bounds.point.x - bounds.extent.x / 2;
break;
case SnapEdgeMax:
delta.x = offset - bounds.point.x - bounds.extent.x + 1;
break;
}
break;
case SnapHorizontal:
switch( edge )
{
case SnapEdgeMin:
delta.y = offset - bounds.point.y;
break;
case SnapEdgeMid:
delta.y = offset - bounds.point.y - bounds.extent.y / 2;
break;
case SnapEdgeMax:
delta.y = offset - bounds.point.y - bounds.extent.y + 1;
break;
}
break;
}
}
public:
GuiEditCtrl();
DECLARE_CONOBJECT(GuiEditCtrl);
DECLARE_CATEGORY( "Gui Editor" );
DECLARE_DESCRIPTION( "Implements the framework for the GUI editor." );
bool onWake();
void onSleep();
static void initPersistFields();
GuiControl* getContentControl() const { return mContentControl; }
void setContentControl(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);
void setCurrentAddSet(GuiControl *ctrl, bool clearSelection = true);
GuiControl* getCurrentAddSet();
// Selections.
void select( GuiControl *ctrl );
bool selectionContains( GuiControl *ctrl );
bool selectionContainsParentOf( GuiControl* ctrl );
void setSelection( GuiControl *ctrl, bool inclusive = false );
RectI getSelectionBounds() const;
RectI getSelectionGlobalBounds() const;
void canHitSelectedControls( bool state = true );
void justifySelection( Justification j );
void moveSelection( const Point2I &delta, bool callback = true );
void moveAndSnapSelection( const Point2I &delta, bool callback = true );
void saveSelection( const char *filename );
void loadSelection( const char *filename );
void addSelection( S32 id );
void addSelection( GuiControl* ctrl );
void removeSelection( S32 id );
void removeSelection( GuiControl* ctrl );
void deleteSelection();
void clearSelection();
void selectAll();
void bringToFront();
void pushToBack();
void moveSelectionToCtrl( GuiControl* ctrl, bool callback = true );
void addSelectControlsInRegion( const RectI& rect, U32 hitTestFlags = 0 );
void addSelectControlAt( const Point2I& pos );
void resizeControlsInSelectionBy( const Point2I& delta, U32 mode );
void fitIntoParents( bool width = true, bool height = true );
void selectParents( bool addToSelection = false );
void selectChildren( bool addToSelection = false );
void cloneSelection();
U32 getNumSelected() const { return mSelectedControls.size(); }
// Guides.
U32 addGuide( guideAxis axis, U32 offset ) { U32 index = mGuides[ axis ].size(); mGuides[ axis ].push_back( offset ); return index; }
void readGuides( guideAxis axis, GuiControl* ctrl );
void writeGuides( guideAxis axis, GuiControl* ctrl );
void clearGuides( guideAxis axis ) { mGuides[ axis ].clear(); }
// Undo Access.
void undo();
void redo();
// When a control is changed by the inspector
void controlInspectPreApply(GuiControl* object);
void controlInspectPostApply(GuiControl* object);
// Sizing Cursors
void getCursor(GuiCursor *&cursor, bool &showCursor, const GuiEvent &lastGuiEvent);
U32 getSelectionSize() const { return mSelectedControls.size(); }
const Vector<GuiControl *>& getSelected() const { return mSelectedControls; }
SimSet* getSelectedSet() { updateSelectedSet(); return mSelectedSet; }
SimGroup* getTrash() { return mTrash; }
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);
mouseModes getMouseMode() const { return mMouseDownMode; }
virtual bool onAdd();
virtual void onRemove();
void setSnapToGrid(U32 gridsize);
};
#endif //_GUI_EDIT_CTRL_H

View file

@ -0,0 +1,293 @@
//-----------------------------------------------------------------------------
// Copyright (c) 2012 GarageGames, LLC
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//-----------------------------------------------------------------------------
#include "platform/platform.h"
#include "gui/editor/guiFilterCtrl.h"
#include "console/console.h"
#include "console/consoleTypes.h"
#include "guiFilterCtrl.h"
#include "math/mMath.h"
#include "gfx/gfxDrawUtil.h"
IMPLEMENT_CONOBJECT(GuiFilterCtrl);
ConsoleDocClass( GuiFilterCtrl,
"@brief A control that displays a Catmull-Rom spline through a number of control points.\n\n"
"Currently editor use only, no real application without extension.\n\n "
"@internal");
GuiFilterCtrl::GuiFilterCtrl()
{
mControlPointRequest = 7;
mFilter.setSize(7);
mShowIdentity = true;
mIdentity.set( 0.0f, 1.0f );
identity();
mCurKnot = -1;
}
void GuiFilterCtrl::initPersistFields()
{
addField("controlPoints", TypeS32, Offset(mControlPointRequest, GuiFilterCtrl),
"Total number of control points in the spline curve." );
addField("filter", TypeF32Vector, Offset(mFilter, GuiFilterCtrl),
"Vector of control points." );
addField("showIdentity", TypeBool, Offset(mShowIdentity, GuiFilterCtrl), "@internal" );
addField("identity", TypePoint2F, Offset(mIdentity, GuiFilterCtrl), "@internal");
Parent::initPersistFields();
}
ConsoleMethod( GuiFilterCtrl, getValue, const char*, 2, 2, "Return a tuple containing all the values in the filter."
"@internal")
{
TORQUE_UNUSED(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."
"@internal")
{
Filter filter;
argc -= 2;
argv += 2;
filter.set(argc, argv);
object->set(filter);
}
ConsoleMethod( GuiFilterCtrl, identity, void, 2, 2, "Reset the filtering."
"@internal")
{
object->identity();
}
bool GuiFilterCtrl::onWake()
{
if (!Parent::onWake())
return false;
if (U32(mControlPointRequest) != mFilter.size())
{
mFilter.setSize(mControlPointRequest);
identity();
}
mCurKnot = -1;
return true;
}
void GuiFilterCtrl::identity()
{
S32 size = mFilter.size()-1;
for (U32 i=0; S32(i) <= size; i++)
{
F32 step = (F32)i/(F32)size;
mFilter[i] = mLerp( mIdentity.x, mIdentity.y, step );
}
}
void GuiFilterCtrl::onMouseDown(const GuiEvent &event)
{
mouseLock();
setFirstResponder();
Point2I p = globalToLocalCoord(event.mousePoint);
// determine which knot (offset same as in onRender)
F32 w = F32(getWidth()-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), getHeight())/(F32)getHeight());
setUpdate();
}
void GuiFilterCtrl::onMouseDragged(const GuiEvent &event)
{
if ( mCurKnot < 0 )
return;
mouseLock();
setFirstResponder();
Point2I p = globalToLocalCoord(event.mousePoint);
mFilter[mCurKnot] = 1.0f - F32(getMin(getMax(0, p.y), getHeight())/(F32)getHeight());
setUpdate();
}
void GuiFilterCtrl::onMouseUp(const GuiEvent &)
{
if ( mCurKnot < 0 )
return;
mouseUnlock();
execConsoleCallback();
}
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 = getExtent();
RectI r(pos, ext);
GFX->getDrawUtil()->drawRectFill(r, ColorI(255,255,255));
GFX->getDrawUtil()->drawRect(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
if ( mShowIdentity )
{
GFX->getDrawUtil()->drawLine( pos.x, pos.y + ( ext.y * ( 1.0f - mIdentity.x ) ),
pos.x + ext.x, pos.y + ( ext.y * ( 1.0f - mIdentity.y ) ),
ColorF( 0.9f, 0.9f, 0.9f ) );
}
// draw the curv
GFXVertexBufferHandle<GFXVertexPC> verts(GFX, ext.x, GFXBufferTypeVolatile);
verts.lock();
F32 scale = 1.f / F32( ext.x );
for ( U32 i = 0; i < ext.x; i++)
{
F32 index = F32(i) * scale;
S32 y = (S32)(ext.y*(1.0f-mFilter.getValue(index)));
verts[i].point.set( (F32)(pos.x + i), (F32)(pos.y + y), 0.0f );
verts[i].color = GFXVertexColor( ColorF( 0.4f, 0.4f, 0.4f ) );
}
verts.unlock();
GFX->setVertexBuffer( verts );
GFX->drawPrimitive( GFXLineStrip, 0, ext.x - 1 );
// 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);
GFX->getDrawUtil()->drawRectFill(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 );
}

View file

@ -0,0 +1,99 @@
//-----------------------------------------------------------------------------
// Copyright (c) 2012 GarageGames, LLC
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//-----------------------------------------------------------------------------
#ifndef _GUIFILTERCTRL_H_
#define _GUIFILTERCTRL_H_
#ifndef _GUICONTROL_H_
#include "gui/core/guiControl.h"
#endif
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
{
protected:
typedef GuiControl Parent;
S32 mControlPointRequest;
S32 mCurKnot;
Filter mFilter;
bool mShowIdentity;
Point2F mIdentity;
public:
//creation methods
DECLARE_CONOBJECT(GuiFilterCtrl);
DECLARE_CATEGORY( "Gui Other" );
DECLARE_DESCRIPTION( "A control that displays a Catmull-Rom spline through a number of control points\n"
"and allows to edit the Y-coordinates of the control points to adjust the curve." );
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[index];
}
inline void GuiFilterCtrl::set(const Filter &f)
{
mControlPointRequest = f.size();
mFilter = f;
}
#endif

View file

@ -0,0 +1,430 @@
//-----------------------------------------------------------------------------
// Copyright (c) 2012 GarageGames, LLC
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//-----------------------------------------------------------------------------
#include "platform/platform.h"
#include "gui/editor/guiGraphCtrl.h"
#include "console/console.h"
#include "console/consoleTypes.h"
#include "console/engineAPI.h"
#include "gfx/gfxDevice.h"
#include "gfx/gfxDrawUtil.h"
#include "gfx/primBuilder.h"
IMPLEMENT_CONOBJECT( GuiGraphCtrl );
ConsoleDocClass( GuiGraphCtrl,
"@brief A control that plots one or more curves in a chart.\n\n"
"Up to 6 individual curves can be plotted in the graph. Each plotted curve can have its own display style including its "
"own charting style (#plotType) and color (#plotColor).\n\n"
"The data points on each curve can be added in one of two ways:\n\n"
"- Manually by calling addDatum(). This causes new data points to be added to the left end of the plotting curve.\n"
"- Automatically by letting the graph plot the values of a variable over time. This is achieved by calling addAutoPlot "
"and specifying the variable and update frequency.\n\n"
"@tsexample\n"
"// Create a graph that plots a red polyline graph of the FPS counter in a 1 second (1000 milliseconds) interval.\n"
"new GuiGraphCtrl( FPSGraph )\n"
"{\n"
" plotType[ 0 ] = \"PolyLine\";\n"
" plotColor[ 0 ] = \"1 0 0\";\n"
" plotVariable[ 0 ] = \"fps::real\";\n"
" plotInterval[ 0 ] = 1000;\n"
"};\n"
"@endtsexample\n\n"
"@note Each curve has a maximum number of 200 data points it can have at any one time. Adding more data points to a curve "
"will cause older data points to be removed.\n\n"
"@ingroup GuiValues"
);
ImplementEnumType( GuiGraphType,
"The charting style of a single plotting curve in a GuiGraphCtrl.\n\n"
"@ingroup GuiValues" )
{ GuiGraphCtrl::Bar, "Bar", "Plot the curve as a bar chart." },
{ GuiGraphCtrl::Filled, "Filled", "Plot a filled poly graph that connects the data points on the curve." },
{ GuiGraphCtrl::Point, "Point", "Plot each data point on the curve as a single dot." },
{ GuiGraphCtrl::Polyline , "PolyLine", "Plot straight lines through the data points of the curve." },
EndImplementEnumType;
//-----------------------------------------------------------------------------
GuiGraphCtrl::GuiGraphCtrl()
: mCenterY( 1.f )
{
dMemset( mAutoPlot, 0, sizeof( mAutoPlot ) );
dMemset( mAutoPlotDelay, 0, sizeof( mAutoPlotDelay ) );
dMemset( mGraphMax, 0, sizeof( mGraphMax ) );
for( S32 i = 0; i < MaxPlots; ++ i )
{
mGraphType[ i ] = Polyline;
VECTOR_SET_ASSOCIATION( mGraphData[ i ] );
}
AssertWarn( MaxPlots == 6, "Only 6 plot colors initialized. Update following code if you change MaxPlots." );
mGraphColor[ 0 ] = ColorF( 1.0, 1.0, 1.0 );
mGraphColor[ 1 ] = ColorF( 1.0, 0.0, 0.0 );
mGraphColor[ 2 ] = ColorF( 0.0, 1.0, 0.0 );
mGraphColor[ 3 ] = ColorF( 0.0, 0.0, 1.0 );
mGraphColor[ 4 ] = ColorF( 0.0, 1.0, 1.0 );
mGraphColor[ 5 ] = ColorF( 0.0, 0.0, 0.0 );
}
//-----------------------------------------------------------------------------
void GuiGraphCtrl::initPersistFields()
{
addGroup( "Graph" );
addField( "centerY", TypeF32, Offset( mCenterY, GuiGraphCtrl ),
"Ratio of where to place the center coordinate of the graph on the Y axis. 0.5=middle height of control.\n\n"
"This allows to account for graphs that have only positive or only negative data points, for example." );
addField( "plotColor", TypeColorF, Offset( mGraphColor, GuiGraphCtrl ), MaxPlots,
"Color to use for the plotting curves in the graph." );
addField( "plotType", TYPEID< GuiGraphType >(), Offset( mGraphType, GuiGraphCtrl ), MaxPlots,
"Charting type of the plotting curves." );
addField( "plotVariable", TypeString, Offset( mAutoPlot, GuiGraphCtrl ), MaxPlots,
"Name of the variable to automatically plot on the curves. If empty, auto-plotting "
"is disabled for the respective curve." );
addField( "plotInterval", TypeS32, Offset( mAutoPlotDelay, GuiGraphCtrl ), MaxPlots,
"Interval between auto-plots of #plotVariable for the respective curve (in milliseconds)." );
endGroup( "Graph" );
Parent::initPersistFields();
}
//-----------------------------------------------------------------------------
void GuiGraphCtrl::onRender(Point2I offset, const RectI &updateRect)
{
if (mBlendSB.isNull())
{
GFXStateBlockDesc desc;
desc.setBlend(true, GFXBlendSrcColor, GFXBlendInvSrcColor);
mBlendSB = GFX->createStateBlock(desc);
desc.setBlend(false, GFXBlendOne, GFXBlendZero);
mSolidSB = GFX->createStateBlock(desc);
}
GFX->setStateBlock( mBlendSB );
GFX->getDrawUtil()->drawRectFill( updateRect, mProfile->mFillColor );
GFX->setStateBlock( mSolidSB );
const Point2I globalPos = getGlobalBounds().point;
const F32 midPointY = F32( globalPos.y ) + F32( getExtent().y ) * mCenterY;
for( S32 k = 0; k < MaxPlots; ++ k )
{
// Check if there is an autoplot and the proper amount of time has passed, if so add datum.
if( mAutoPlot[ k ] && mAutoPlotDelay[ k ] < (Sim::getCurrentTime() - mAutoPlotLastDisplay[ k ] ) )
{
mAutoPlotLastDisplay[ k ] = Sim::getCurrentTime();
addDatum( k, Con::getFloatVariable( mAutoPlot[ k ] ) );
}
// Nothing to graph
if( mGraphData[ k ].size() == 0 )
continue;
// Adjust scale to max value + 5% so we can see high values
F32 Scale = F32( getExtent().y ) / F32( mGraphMax[ k ] * 1.05 );
const S32 numSamples = mGraphData[ k ].size();
switch( mGraphType[ k ] )
{
case Bar:
{
F32 prevOffset = 0;
for( S32 sample = 0; sample < numSamples; ++ sample )
{
PrimBuild::begin( GFXTriangleFan, 4 );
PrimBuild::color( mGraphColor[ k ] );
F32 offset = F32( getExtent().x ) / F32( MaxDataPoints ) * F32( sample + 1 );
PrimBuild::vertex2f( globalPos.x + prevOffset,
midPointY - ( getDatum( k, sample ) * Scale ) );
PrimBuild::vertex2f( globalPos.x + offset,
midPointY - ( getDatum( k, sample ) * Scale ) );
PrimBuild::vertex2f( globalPos.x + offset,
midPointY );
PrimBuild::vertex2f( globalPos.x + prevOffset,
midPointY );
prevOffset = offset;
PrimBuild::end();
}
break;
}
case Filled:
{
PrimBuild::begin( GFXTriangleStrip, numSamples * 2 ); // Max size correct? -pw
PrimBuild::color( mGraphColor[ k ] );
for( S32 sample = 0; sample < numSamples; ++ sample )
{
F32 offset = F32( getExtent().x ) / F32( MaxDataPoints - 1 ) * F32( sample );
PrimBuild::vertex2f( globalPos.x + offset,
midPointY );
PrimBuild::vertex2f( globalPos.x + offset,
midPointY - ( getDatum( k, sample ) * Scale ) );
}
PrimBuild::end();
break;
}
case Point:
case Polyline:
{
if( mGraphType[ k ] == Point )
PrimBuild::begin( GFXPointList, numSamples ); // Max size correct? -pw
else
PrimBuild::begin( GFXLineStrip, numSamples );
PrimBuild::color( mGraphColor[ k ] );
for( S32 sample = 0; sample < numSamples; ++ sample )
{
F32 offset = F32( getExtent().x ) / F32( MaxDataPoints - 1 ) * F32( sample );
PrimBuild::vertex2f( globalPos.x + offset,
midPointY - ( getDatum( k, sample ) * Scale ) );
}
PrimBuild::end();
break;
}
}
}
if( mProfile->mBorder )
{
RectI rect( offset.x, offset.y, getWidth(), getHeight() );
GFX->getDrawUtil()->drawRect( rect, mProfile->mBorderColor );
}
renderChildControls( offset, updateRect );
}
//-----------------------------------------------------------------------------
void GuiGraphCtrl::addDatum(S32 plotID, F32 v)
{
AssertFatal(plotID > -1 && plotID < MaxPlots, "Invalid plot specified!");
// Add the data and trim the vector...
mGraphData[ plotID ].push_front( v );
if( mGraphData[ plotID ].size() > MaxDataPoints )
mGraphData[ plotID ].pop_back();
// Keep record of maximum data value for scaling purposes.
if( v > mGraphMax[ plotID ] )
mGraphMax[ plotID ] = 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 mGraphData[ plotID ][sample];
}
//-----------------------------------------------------------------------------
void GuiGraphCtrl::addAutoPlot( S32 plotID, const char* variable, S32 update )
{
mAutoPlot[ plotID ] = StringTable->insert( variable );
mAutoPlotDelay[ plotID ] = update;
}
//-----------------------------------------------------------------------------
void GuiGraphCtrl::removeAutoPlot( S32 plotID )
{
mAutoPlot[ plotID ] = NULL;
}
//-----------------------------------------------------------------------------
void GuiGraphCtrl::setGraphType( S32 plotID, GraphType graphType )
{
AssertFatal( plotID > -1 && plotID < MaxPlots, "Invalid plot specified!" );
mGraphType[ plotID ] = graphType;
}
//=============================================================================
// Console Methods.
//=============================================================================
// MARK: ---- Console Methods ----
//-----------------------------------------------------------------------------
DefineEngineMethod( GuiGraphCtrl, addDatum, void, ( S32 plotId, F32 value ),,
"Add a data point to the plot's curve.\n\n"
"@param plotId Index of the plotting curve to which to add the data point. Must be 0<=plotId<6.\n"
"@param value Value of the data point to add to the curve.\n\n"
"@note Data values are added to the @b left end of the plotting curve.\n\n"
"@note A maximum number of 200 data points can be added to any single plotting curve at any one time. If "
"this limit is exceeded, data points on the right end of the curve are culled." )
{
if( plotId > object->MaxPlots )
{
Con::errorf( "GuiGraphCtrl::addDatum - 'plotId' out of range: %i", plotId );
return;
}
object->addDatum( plotId, value );
}
//-----------------------------------------------------------------------------
DefineEngineMethod( GuiGraphCtrl, getDatum, F32, ( S32 plotId, S32 index ),,
"Get a data point on the given plotting curve.\n\n"
"@param plotId Index of the plotting curve from which to fetch the data point. Must be 0<=plotId<6.\n"
"@param index Index of the data point on the curve.\n"
"@return The value of the data point or -1 if @a plotId or @a index are out of range." )
{
if( plotId > object->MaxPlots )
{
Con::errorf( "GuiGraphCtrl::getDatum - 'plotId' out of range: %i", plotId );
return -1.f;
}
if( index > object->MaxDataPoints)
{
Con::errorf( "GuiGraphCtrl::getDatum - Data point index out of range: %i", index );
return -1.f;
}
return object->getDatum( plotId, index );
}
//-----------------------------------------------------------------------------
DefineEngineMethod( GuiGraphCtrl, addAutoPlot, void, ( S32 plotId, const char* variable, S32 updateFrequency ),,
"Sets up the given plotting curve to automatically plot the value of the @a variable with a "
"frequency of @a updateFrequency.\n"
"@param plotId Index of the plotting curve. Must be 0<=plotId<6.\n"
"@param variable Name of the global variable.\n"
"@param updateFrequency Frequency with which to add new data points to the plotting curve (in milliseconds).\n"
"@tsexample\n"
"// Plot FPS counter at 1 second intervals.\n"
"%graph.addAutoPlot( 0, \"fps::real\", 1000 );\n"
"@endtsexample" )
{
if( plotId > object->MaxPlots )
{
Con::errorf( "GuiGraphCtrl::removeAutoPlot - 'plotId' out of range: %i", plotId );
return;
}
object->addAutoPlot( plotId, variable, updateFrequency );
}
//-----------------------------------------------------------------------------
DefineEngineMethod( GuiGraphCtrl, removeAutoPlot, void, ( S32 plotId ),,
"Stop automatic variable plotting for the given curve.\n"
"@param plotId Index of the plotting curve. Must be 0<=plotId<6.\n" )
{
if( plotId > object->MaxPlots )
{
Con::errorf( "GuiGraphCtrl::removeAutoPlot - 'plotId' out of range: %i", plotId );
return;
}
object->removeAutoPlot( plotId );
}
//-----------------------------------------------------------------------------
DefineEngineMethod( GuiGraphCtrl, setGraphType, void, ( S32 plotId, GuiGraphType graphType ),,
"Change the charting type of the given plotting curve.\n"
"@param plotId Index of the plotting curve. Must be 0<=plotId<6.\n"
"@param graphType Charting type to use for the curve.\n"
"@note Instead of calling this method, you can directly assign to #plotType." )
{
if( plotId > object->MaxPlots )
{
Con::errorf( "GuiGraphCtrl::setGraphType - 'plotId' out of range: %i", plotId );
return;
}
object->setGraphType( plotId, graphType );
}
//-----------------------------------------------------------------------------
ConsoleMethod( GuiGraphCtrl, matchScale, void, 3, GuiGraphCtrl::MaxPlots + 2, "( int plotID1, int plotID2, ... ) "
"Set the scale of all specified plots to the maximum scale among them.\n\n"
"@param plotID1 Index of plotting curve.\n"
"@param plotID2 Index of plotting curve." )
{
F32 max = 0;
for( S32 i = 0; i < ( argc - 2 ); ++ i )
{
S32 plotID = dAtoi( argv[ 2 + i ] );
if( plotID > object->MaxPlots )
{
Con::errorf( "GuiGraphCtrl::matchScale - Plot ID out of range: %i", plotID );
return;
}
max = getMax( object->getMax( plotID ), max );
}
for( S32 i = 0; i < ( argc - 2 ); ++ i )
object->setMax( dAtoi( argv[ 2 + i ] ), max );
}

View file

@ -0,0 +1,88 @@
//-----------------------------------------------------------------------------
// Copyright (c) 2012 GarageGames, LLC
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//-----------------------------------------------------------------------------
#ifndef _GUIGRAPHCTRL_H_
#define _GUIGRAPHCTRL_H_
#ifndef _GUICONTROL_H_
#include "gui/core/guiControl.h"
#endif
class GuiGraphCtrl : public GuiControl
{
public:
typedef GuiControl Parent;
enum Constants
{
MaxPlots = 6,
MaxDataPoints = 200
};
enum GraphType {
Point,
Polyline,
Filled,
Bar
};
protected:
F32 mCenterY;
StringTableEntry mAutoPlot[ MaxPlots ];
U32 mAutoPlotDelay[ MaxPlots ];
SimTime mAutoPlotLastDisplay[ MaxPlots ];
ColorF mGraphColor[ MaxPlots ];
Vector< F32 > mGraphData[ MaxPlots ];
F32 mGraphMax[ MaxPlots ];
GraphType mGraphType[ MaxPlots ];
GFXStateBlockRef mSolidSB;
GFXStateBlockRef mBlendSB;
public:
GuiGraphCtrl();
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, GraphType graphType );
F32 getMax( S32 plotID ) const { return mGraphMax[ plotID ]; }
void setMax( S32 plotID, F32 max ) { mGraphMax[ plotID ] = max; }
// GuiControl.
virtual void onRender(Point2I offset, const RectI &updateRect);
DECLARE_CONOBJECT(GuiGraphCtrl);
DECLARE_CATEGORY( "Gui Other" );
DECLARE_DESCRIPTION( "A control that allows to plot curve graphs." );
static void initPersistFields();
};
typedef GuiGraphCtrl::GraphType GuiGraphType;
DefineEnumType( GuiGraphType );
#endif

View file

@ -0,0 +1,259 @@
//-----------------------------------------------------------------------------
// Copyright (c) 2012 GarageGames, LLC
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//-----------------------------------------------------------------------------
#include "platform/platform.h"
#include "console/consoleTypes.h"
#include "console/console.h"
#include "gfx/gfxDevice.h"
#include "gui/editor/guiImageList.h"
#include "console/engineAPI.h"
IMPLEMENT_CONOBJECT(GuiImageList);
ConsoleDocClass( GuiImageList,
"@brief GUI control which displays a list of images.\n\n"
"Used to be a part of an old editor system for previous Torque systems. "
"Doesn't appear to be used anymore, will most likely be deprecated.\n\n"
"@ingroup GuiCore\n"
"@internal");
GuiImageList::GuiImageList()
{
VECTOR_SET_ASSOCIATION(mTextures);
mTextures.clear();
mUniqueId = 0;
}
U32 GuiImageList::Insert( const char* texturePath, GFXTextureProfile *Type )
{
TextureEntry *t = new TextureEntry;
if ( ! t ) return -1;
t->TexturePath = StringTable->insert(texturePath);
if ( *t->TexturePath )
{
t->Handle = GFXTexHandle(t->TexturePath, Type, avar("%s() - t->Handle (line %d)", __FUNCTION__, __LINE__));
if ( t->Handle )
{
t->id = ++mUniqueId;
mTextures.push_back( t );
return t->id;
}
}
// Free Texture Entry.
delete t;
// Return Failure.
return -1;
}
bool GuiImageList::Clear()
{
while ( mTextures.size() )
FreeTextureEntry( mTextures[0] );
mTextures.clear();
mUniqueId = 0;
return true;
}
bool GuiImageList::FreeTextureEntry( U32 Index )
{
U32 Id = IndexFromId( Index );
if ( Id != -1 )
return FreeTextureEntry( mTextures[ Id ] );
else
return false;
}
bool GuiImageList::FreeTextureEntry( PTextureEntry Entry )
{
if ( ! Entry )
return false;
U32 id = IndexFromId( Entry->id );
delete Entry;
mTextures.erase ( id );
return true;
}
U32 GuiImageList::IndexFromId ( U32 Id )
{
if ( !mTextures.size() ) return -1;
Vector<PTextureEntry>::iterator i = mTextures.begin();
U32 j = 0;
for ( ; i != mTextures.end(); i++ )
{
if ( i )
{
if ( (*i)->id == Id )
return j;
j++;
}
}
return -1;
}
U32 GuiImageList::IndexFromPath ( const char* Path )
{
if ( !mTextures.size() ) return -1;
Vector<PTextureEntry>::iterator i = mTextures.begin();
for ( ; i != mTextures.end(); i++ )
{
if ( dStricmp( Path, (*i)->TexturePath ) == 0 )
return (*i)->id;
}
return -1;
}
void GuiImageList::initPersistFields()
{
Parent::initPersistFields();
}
DefineEngineMethod( GuiImageList, getImage, const char*, (int index),,
"@brief Get a path to the texture at the specified index.\n\n"
"@param index Index of the image in the list.\n"
"@tsexample\n"
"// Define the image index/n"
"%index = \"5\";\n\n"
"// Request the image path location from the control.\n"
"%imagePath = %thisGuiImageList.getImage(%index);\n"
"@endtsexample\n\n"
"@return File path to the image map for the specified index.\n\n"
"@see SimObject")
{
return object->GetTexturePath(index);
}
DefineEngineMethod(GuiImageList, clear, bool, (),,
"@brief Clears the imagelist\n\n"
"@tsexample\n"
"// Inform the GuiImageList control to clear itself.\n"
"%isFinished = %thisGuiImageList.clear();\n"
"@endtsexample\n\n"
"@return Returns true when finished.\n\n"
"@see SimObject")
{
return object->Clear();
}
DefineEngineMethod( GuiImageList, count, S32, (),,
"@brief Gets the number of images in the list.\n\n"
"@tsexample\n"
"// Request the number of images from the GuiImageList control.\n"
"%imageCount = %thisGuiImageList.count();\n"
"@endtsexample\n\n"
"@return Number of images in the control.\n\n"
"@see SimObject")
{
return object->Count();
}
DefineEngineMethod( GuiImageList, remove, bool, (int index),,
"@brief Removes an image from the list by index.\n\n"
"@param index Image index to remove.\n"
"@tsexample\n"
"// Define the image index.\n"
"%imageIndex = \"4\";\n\n"
"// Inform the GuiImageList control to remove the image at the defined index.\n"
"%wasSuccessful = %thisGuiImageList.remove(%imageIndex);\n"
"@endtsexample\n\n"
"@return True if the operation was successful, false if it was not.\n\n"
"@see SimObject")
{
return object->FreeTextureEntry( index );
}
DefineEngineMethod( GuiImageList, getIndex, S32, (const char* imagePath),,
"@brief Retrieves the imageindex of a specified texture in the list.\n\n"
"@param imagePath Imagemap including filepath of image to search for\n"
"@tsexample\n"
"// Define the imagemap to search for\n"
"%imagePath = \"./game/client/data/images/thisImage\";\n\n"
"// Request the index entry for the defined imagemap\n"
"%imageIndex = %thisGuiImageList.getIndex(%imagePath);\n"
"@endtsexample\n\n"
"@return Index of the imagemap matching the defined image path.\n\n"
"@see SimObject")
{
return object->IndexFromPath( imagePath );
}
DefineEngineMethod(GuiImageList, insert, S32, (const char* imagePath),,
"@brief Insert an image into imagelist- returns the image index or -1 for failure.\n\n"
"@param imagePath Imagemap, with path, to add to the list.\n"
"@tsexample\n"
"// Define the imagemap to add to the list\n"
"%imagePath = \"./game/client/data/images/thisImage\";\n\n"
"// Request the GuiImageList control to add the defined image to its list.\n"
"%imageIndex = %thisGuiImageList.insert(%imagePath);\n"
"@endtsexample\n\n"
"@return The index of the newly inserted imagemap, or -1 if the insertion failed.\n\n"
"@see SimObject")
{
return object->Insert( imagePath );
}
GFXTexHandle GuiImageList::GetTextureHandle( U32 Index )
{
U32 ItemIndex = IndexFromId(Index);
if ( ItemIndex != -1 )
return mTextures[ItemIndex]->Handle;
else
return NULL;
}
GFXTexHandle GuiImageList::GetTextureHandle( const char* TexturePath )
{
Vector<PTextureEntry>::iterator i = mTextures.begin();
for ( ; i != mTextures.end(); i++ )
{
if ( dStricmp( TexturePath, (*i)->TexturePath ) == 0 )
return (*i)->Handle;
}
return NULL;
}
const char *GuiImageList::GetTexturePath( U32 Index )
{
U32 ItemIndex = IndexFromId(Index);
if ( ItemIndex != -1 )
return mTextures[ItemIndex]->TexturePath;
else
return "";
}

View file

@ -0,0 +1,78 @@
//-----------------------------------------------------------------------------
// Copyright (c) 2012 GarageGames, LLC
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//-----------------------------------------------------------------------------
#ifndef _GUIIMAGELIST_H_
#define _GUIIMAGELIST_H_
#include "console/simDatablock.h"
#ifndef _GUITYPES_H_
#include "gui/core/guiTypes.h"
#endif
class GuiImageList : public SimObject
{
private:
typedef SimObject Parent;
public:
typedef struct tag_TextureEntry
{
StringTableEntry TexturePath;
GFXTexHandle Handle;
U32 id;
}TextureEntry,*PTextureEntry;
Vector<PTextureEntry> mTextures;
protected:
U32 mUniqueId;
public:
GuiImageList();
DECLARE_CONOBJECT(GuiImageList);
static void initPersistFields();
// Image managing functions
bool Clear();
inline U32 Count() { return (U32)mTextures.size(); };
U32 Insert( const char* texturePath , GFXTextureProfile *Type = &GFXDefaultGUIProfile );
bool FreeTextureEntry( U32 Index );
bool FreeTextureEntry( PTextureEntry Entry );
GFXTexHandle GetTextureHandle( U32 Index );
GFXTexHandle GetTextureHandle( const char* TexturePath );
const char * GetTexturePath( U32 Index );
U32 IndexFromId ( U32 Id );
U32 IndexFromPath ( const char* Path );
};
#endif //_GUIIMAGELISTCTRL_H_

View file

@ -0,0 +1,893 @@
//-----------------------------------------------------------------------------
// Copyright (c) 2012 GarageGames, LLC
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//-----------------------------------------------------------------------------
#include "gui/editor/guiInspector.h"
#include "gui/editor/inspector/field.h"
#include "gui/editor/inspector/group.h"
#include "gui/buttons/guiIconButtonCtrl.h"
#include "gui/editor/inspector/dynamicGroup.h"
#include "gui/containers/guiScrollCtrl.h"
#include "gui/editor/inspector/customField.h"
IMPLEMENT_CONOBJECT(GuiInspector);
ConsoleDocClass( GuiInspector,
"@brief A control that allows to edit the properties of one or more SimObjects.\n\n"
"Editor use only.\n\n"
"@internal"
);
//#define DEBUG_SPEW
//-----------------------------------------------------------------------------
GuiInspector::GuiInspector()
: mDividerPos( 0.35f ),
mDividerMargin( 5 ),
mOverDivider( false ),
mMovingDivider( false ),
mHLField( NULL ),
mShowCustomFields( true )
{
mPadding = 1;
}
//-----------------------------------------------------------------------------
GuiInspector::~GuiInspector()
{
clearGroups();
}
//-----------------------------------------------------------------------------
void GuiInspector::initPersistFields()
{
addGroup( "Inspector" );
addField( "dividerMargin", TypeS32, Offset( mDividerMargin, GuiInspector ) );
addField( "groupFilters", TypeRealString, Offset( mGroupFilters, GuiInspector ),
"Specify groups that should be shown or not. Specifying 'shown' implicitly does 'not show' all other groups. Example string: +name -otherName" );
addField( "showCustomFields", TypeBool, Offset( mShowCustomFields, GuiInspector ),
"If false the custom fields Name, Id, and Source Class will not be shown." );
endGroup( "Inspector" );
Parent::initPersistFields();
}
//-----------------------------------------------------------------------------
void GuiInspector::onRemove()
{
clearGroups();
Parent::onRemove();
}
//-----------------------------------------------------------------------------
void GuiInspector::onDeleteNotify( SimObject *object )
{
Parent::onDeleteNotify( object );
if( isInspectingObject( object ) )
removeInspectObject( object );
}
//-----------------------------------------------------------------------------
void GuiInspector::parentResized(const RectI &oldParentRect, const RectI &newParentRect)
{
GuiControl *parent = getParent();
if ( parent && dynamic_cast<GuiScrollCtrl*>(parent) != NULL )
{
GuiScrollCtrl *scroll = dynamic_cast<GuiScrollCtrl*>(parent);
setWidth( ( newParentRect.extent.x - ( scroll->scrollBarThickness() + 4 ) ) );
}
else
Parent::parentResized(oldParentRect,newParentRect);
}
//-----------------------------------------------------------------------------
bool GuiInspector::resize( const Point2I &newPosition, const Point2I &newExtent )
{
//F32 dividerPerc = (F32)getWidth() / (F32)mDividerPos;
bool result = Parent::resize( newPosition, newExtent );
//mDividerPos = (F32)getWidth() * dividerPerc;
updateDivider();
return result;
}
//-----------------------------------------------------------------------------
GuiControl* GuiInspector::findHitControl( const Point2I &pt, S32 initialLayer )
{
if ( mOverDivider || mMovingDivider )
return this;
return Parent::findHitControl( pt, initialLayer );
}
//-----------------------------------------------------------------------------
void GuiInspector::getCursor( GuiCursor *&cursor, bool &showCursor, const GuiEvent &lastGuiEvent )
{
GuiCanvas *pRoot = getRoot();
if( !pRoot )
return;
S32 desiredCursor = mOverDivider ? PlatformCursorController::curResizeVert : PlatformCursorController::curArrow;
// Bail if we're already at the desired cursor
if ( pRoot->mCursorChanged == desiredCursor )
return;
PlatformWindow *pWindow = static_cast<GuiCanvas*>(getRoot())->getPlatformWindow();
AssertFatal(pWindow != NULL,"GuiControl without owning platform window! This should not be possible.");
PlatformCursorController *pController = pWindow->getCursorController();
AssertFatal(pController != NULL,"PlatformWindow without an owned CursorController!");
// Now change the cursor shape
pController->popCursor();
pController->pushCursor(desiredCursor);
pRoot->mCursorChanged = desiredCursor;
}
//-----------------------------------------------------------------------------
void GuiInspector::onMouseMove(const GuiEvent &event)
{
if ( collideDivider( globalToLocalCoord( event.mousePoint ) ) )
mOverDivider = true;
else
mOverDivider = false;
}
//-----------------------------------------------------------------------------
void GuiInspector::onMouseDown(const GuiEvent &event)
{
if ( mOverDivider )
{
mMovingDivider = true;
}
}
//-----------------------------------------------------------------------------
void GuiInspector::onMouseUp(const GuiEvent &event)
{
mMovingDivider = false;
}
//-----------------------------------------------------------------------------
void GuiInspector::onMouseDragged(const GuiEvent &event)
{
if ( !mMovingDivider )
return;
Point2I localPnt = globalToLocalCoord( event.mousePoint );
S32 inspectorWidth = getWidth();
// Distance from mouse/divider position in local space
// to the right edge of the inspector
mDividerPos = inspectorWidth - localPnt.x;
mDividerPos = mClamp( mDividerPos, 0, inspectorWidth );
// Divide that by the inspectorWidth to get a percentage
mDividerPos /= inspectorWidth;
updateDivider();
}
//-----------------------------------------------------------------------------
GuiInspectorGroup* GuiInspector::findExistentGroup( StringTableEntry groupName )
{
// If we have no groups, it couldn't possibly exist
if( mGroups.empty() )
return NULL;
// Attempt to find it in the group list
Vector<GuiInspectorGroup*>::iterator i = mGroups.begin();
for( ; i != mGroups.end(); i++ )
{
if( dStricmp( (*i)->getGroupName(), groupName ) == 0 )
return *i;
}
return NULL;
}
//-----------------------------------------------------------------------------
void GuiInspector::updateFieldValue( StringTableEntry fieldName, StringTableEntry arrayIdx )
{
// We don't know which group contains the field of this name,
// so ask each group in turn, and break when a group returns true
// signifying it contained and updated that field.
Vector<GuiInspectorGroup*>::iterator groupIter = mGroups.begin();
for( ; groupIter != mGroups.end(); groupIter++ )
{
if ( (*groupIter)->updateFieldValue( fieldName, arrayIdx ) )
break;
}
}
//-----------------------------------------------------------------------------
void GuiInspector::clearGroups()
{
#ifdef DEBUG_SPEW
Platform::outputDebugString( "[GuiInspector] Clearing %i (%s)", getId(), getName() );
#endif
// If we have no groups, there's nothing to clear!
if( mGroups.empty() )
return;
mHLField = NULL;
if( isMethod( "onClear" ) )
Con::executef( this, "onClear" );
Vector<GuiInspectorGroup*>::iterator i = mGroups.begin();
freeze(true);
// Delete Groups
for( ; i != mGroups.end(); i++ )
{
if((*i) && (*i)->isProperlyAdded())
(*i)->deleteObject();
}
mGroups.clear();
freeze(false);
updatePanes();
}
//-----------------------------------------------------------------------------
bool GuiInspector::isInspectingObject( SimObject* object )
{
const U32 numTargets = mTargets.size();
for( U32 i = 0; i < numTargets; ++ i )
if( mTargets[ i ] == object )
return true;
return false;
}
//-----------------------------------------------------------------------------
void GuiInspector::inspectObject( SimObject *object )
{
if( mTargets.size() > 1 || !isInspectingObject( object ) )
clearInspectObjects();
addInspectObject( object );
}
//-----------------------------------------------------------------------------
void GuiInspector::clearInspectObjects()
{
const U32 numTargets = mTargets.size();
for( U32 i = 0; i < numTargets; ++ i )
clearNotify( mTargets[ i ] );
clearGroups();
mTargets.clear();
}
//-----------------------------------------------------------------------------
void GuiInspector::addInspectObject( SimObject* object, bool autoSync )
{
// If we are already inspecting the object, just update the groups.
if( isInspectingObject( object ) )
{
#ifdef DEBUG_SPEW
Platform::outputDebugString( "[GuiInspector] Refreshing view of %i:%s (%s)",
object->getId(), object->getClassName(), object->getName() );
#endif
Vector<GuiInspectorGroup*>::iterator i = mGroups.begin();
for ( ; i != mGroups.end(); i++ )
(*i)->updateAllFields();
return;
}
#ifdef DEBUG_SPEW
Platform::outputDebugString( "[GuiInspector] Adding %i:%s (%s) to inspect set",
object->getId(), object->getClassName(), object->getName() );
#endif
// Give users a chance to customize fields on this object
if( object->isMethod("onDefineFieldTypes") )
Con::executef( object, "onDefineFieldTypes" );
// Set Target
mTargets.push_back( object );
deleteNotify( object );
if( autoSync )
refresh();
}
//-----------------------------------------------------------------------------
void GuiInspector::removeInspectObject( SimObject* object )
{
const U32 numTargets = mTargets.size();
for( U32 i = 0; i < numTargets; ++ i )
if( mTargets[ i ] == object )
{
// Delete all inspector data *before* removing the target so that apply calls
// triggered by edit controls losing focus will not find the inspect object
// gone.
clearGroups();
#ifdef DEBUG_SPEW
Platform::outputDebugString( "[GuiInspector] Removing %i:%s (%s) from inspect set",
object->getId(), object->getClassName(), object->getName() );
#endif
mTargets.erase( i );
clearNotify( object );
// Refresh the inspector except if the system is going down.
if( !Sim::isShuttingDown() )
refresh();
return;
}
}
//-----------------------------------------------------------------------------
void GuiInspector::setName( StringTableEntry newName )
{
if( mTargets.size() != 1 )
return;
StringTableEntry name = StringTable->insert(newName);
// Only assign a new name if we provide one
mTargets[ 0 ]->assignName(name);
}
//-----------------------------------------------------------------------------
bool GuiInspector::collideDivider( const Point2I &localPnt )
{
RectI divisorRect( getWidth() - getWidth() * mDividerPos - mDividerMargin, 0, mDividerMargin * 2, getHeight() );
if ( divisorRect.pointInRect( localPnt ) )
return true;
return false;
}
//-----------------------------------------------------------------------------
void GuiInspector::updateDivider()
{
for ( U32 i = 0; i < mGroups.size(); i++ )
for ( U32 j = 0; j < mGroups[i]->mChildren.size(); j++ )
mGroups[i]->mChildren[j]->updateRects();
//setUpdate();
}
//-----------------------------------------------------------------------------
void GuiInspector::getDivider( S32 &pos, S32 &margin )
{
pos = (F32)getWidth() * mDividerPos;
margin = mDividerMargin;
}
//-----------------------------------------------------------------------------
void GuiInspector::setHighlightField( GuiInspectorField *field )
{
if ( mHLField == field )
return;
if ( mHLField.isValid() )
mHLField->setHLEnabled( false );
mHLField = field;
// We could have been passed a null field, meaning, set no field highlighted.
if ( mHLField.isNull() )
return;
mHLField->setHLEnabled( true );
}
//-----------------------------------------------------------------------------
bool GuiInspector::isGroupFiltered( const char *groupName ) const
{
// Internal and Ungrouped always filtered, we never show them.
if ( dStricmp( groupName, "Internal" ) == 0 ||
dStricmp( groupName, "Ungrouped" ) == 0 ||
dStricmp( groupName, "AdvCoordManipulation" ) == 0)
return true;
// Normal case, determine if filtered by looking at the mGroupFilters string.
String searchStr;
// Is this group explicitly show? Does it immediately follow a + char.
searchStr = String::ToString( "+%s", groupName );
if ( mGroupFilters.find( searchStr ) != String::NPos )
return false;
// Were there any other + characters, if so, we are implicitly hidden.
if ( mGroupFilters.find( "+" ) != String::NPos )
return true;
// Is this group explicitly hidden? Does it immediately follow a - char.
searchStr = String::ToString( "-%s", groupName );
if ( mGroupFilters.find( searchStr ) != String::NPos )
return true;
return false;
}
//-----------------------------------------------------------------------------
bool GuiInspector::isGroupExplicitlyFiltered( const char *groupName ) const
{
String searchStr;
searchStr = String::ToString( "-%s", groupName );
if ( mGroupFilters.find( searchStr ) != String::NPos )
return true;
return false;
}
//-----------------------------------------------------------------------------
void GuiInspector::setObjectField( const char *fieldName, const char *data )
{
GuiInspectorField *field;
for ( S32 i = 0; i < mGroups.size(); i++ )
{
field = mGroups[i]->findField( fieldName );
if( field )
{
field->setData( data );
return;
}
}
}
//-----------------------------------------------------------------------------
static SimObject *sgKeyObj = NULL;
bool findInspectors( GuiInspector *obj )
{
if ( obj->isAwake() && obj->isInspectingObject( sgKeyObj ) )
return true;
return false;
}
//-----------------------------------------------------------------------------
GuiInspector* GuiInspector::findByObject( SimObject *obj )
{
sgKeyObj = obj;
Vector< GuiInspector* > found;
Sim::getGuiGroup()->findObjectByCallback( findInspectors, found );
if ( found.empty() )
return NULL;
return found.first();
}
//-----------------------------------------------------------------------------
void GuiInspector::refresh()
{
clearGroups();
// Remove any inspect object that happened to have
// already been killed.
for( U32 i = 0; i < mTargets.size(); ++ i )
if( !mTargets[ i ] )
{
mTargets.erase( i );
-- i;
}
if( !mTargets.size() )
return;
// Special group for fields which should appear at the top of the
// list outside of a rollout control.
GuiInspectorGroup *ungroup = NULL;
if( mTargets.size() == 1 )
{
ungroup = new GuiInspectorGroup( "Ungrouped", this );
ungroup->setHeaderHidden( true );
ungroup->setCanCollapse( false );
if( ungroup != NULL )
{
ungroup->registerObject();
mGroups.push_back( ungroup );
addObject( ungroup );
}
}
// Put the 'transform' group first
GuiInspectorGroup *transform = new GuiInspectorGroup( "Transform", this );
if( transform != NULL )
{
transform->registerObject();
mGroups.push_back( transform );
addObject( transform );
}
// Always create the 'general' group (for fields without a group)
GuiInspectorGroup *general = new GuiInspectorGroup( "General", this );
if( general != NULL )
{
general->registerObject();
mGroups.push_back( general );
addObject( general );
}
// Create the inspector groups for static fields.
for( TargetVector::iterator iter = mTargets.begin(); iter != mTargets.end(); ++ iter )
{
AbstractClassRep::FieldList &fieldList = ( *iter )->getModifiableFieldList();
// Iterate through, identifying the groups and create necessary GuiInspectorGroups
for( AbstractClassRep::FieldList::iterator itr = fieldList.begin(); itr != fieldList.end(); itr++ )
{
if ( itr->type == AbstractClassRep::StartGroupFieldType )
{
GuiInspectorGroup* group = findExistentGroup( itr->pGroupname );
if( !group && !isGroupFiltered( itr->pGroupname ) )
{
GuiInspectorGroup *group = new GuiInspectorGroup( itr->pGroupname, this );
if( group != NULL )
{
group->registerObject();
if( !group->getNumFields() )
{
#ifdef DEBUG_SPEW
Platform::outputDebugString( "[GuiInspector] Removing empty group '%s'",
group->getCaption().c_str() );
#endif
// The group ended up having no fields. Remove it.
group->deleteObject();
}
else
{
mGroups.push_back( group );
addObject( group );
}
}
}
}
}
}
// Deal with dynamic fields
if ( !isGroupFiltered( "Dynamic Fields" ) )
{
GuiInspectorGroup *dynGroup = new GuiInspectorDynamicGroup( "Dynamic Fields", this);
if( dynGroup != NULL )
{
dynGroup->registerObject();
mGroups.push_back( dynGroup );
addObject( dynGroup );
}
}
if( mShowCustomFields && mTargets.size() == 1 )
{
SimObject* object = mTargets.first();
// Add the SimObjectID field to the ungrouped group.
GuiInspectorCustomField* field = new GuiInspectorCustomField();
field->init( this, ungroup );
if( field->registerObject() )
{
ungroup->mChildren.push_back( field );
ungroup->mStack->addObject( field );
static StringTableEntry sId = StringTable->insert( "id" );
field->setCaption( sId );
field->setData( object->getIdString() );
field->setDoc( "SimObjectId of this object. [Read Only]" );
}
else
delete field;
// Add the Source Class field to the ungrouped group.
field = new GuiInspectorCustomField();
field->init( this, ungroup );
if( field->registerObject() )
{
ungroup->mChildren.push_back( field );
ungroup->mStack->addObject( field );
StringTableEntry sSourceClass = StringTable->insert( "Source Class", true );
field->setCaption( sSourceClass );
field->setData( object->getClassName() );
Namespace* ns = object->getClassRep()->getNameSpace();
field->setToolTip( Con::getNamespaceList( ns ) );
field->setDoc( "Native class of this object. [Read Only]" );
}
else
delete field;
}
// If the general group is still empty at this point ( or filtered ), kill it.
if ( isGroupFiltered( "General" ) || general->mStack->size() == 0 )
{
for(S32 i=0; i<mGroups.size(); i++)
{
if ( mGroups[i] == general )
{
mGroups.erase(i);
general->deleteObject();
updatePanes();
break;
}
}
}
// If transform turns out to be empty or filtered, remove it
if( isGroupFiltered( "Transform" ) || transform->mStack->size() == 0 )
{
for(S32 i=0; i<mGroups.size(); i++)
{
if ( mGroups[i] == transform )
{
mGroups.erase(i);
transform->deleteObject();
updatePanes();
break;
}
}
}
// If ungrouped is empty or explicitly filtered, remove it.
if( ungroup && ( isGroupExplicitlyFiltered( "Ungrouped" ) || ungroup->getNumFields() == 0 ) )
{
for(S32 i=0; i<mGroups.size(); i++)
{
if ( mGroups[i] == ungroup )
{
mGroups.erase(i);
ungroup->deleteObject();
updatePanes();
break;
}
}
}
// If the object cannot be renamed, deactivate the name field if we have it.
if( ungroup && getNumInspectObjects() == 1 && !getInspectObject()->isNameChangeAllowed() )
{
GuiInspectorField* nameField = ungroup->findField( "name" );
if( nameField )
nameField->setActive( false );
}
}
//-----------------------------------------------------------------------------
void GuiInspector::sendInspectPreApply()
{
const U32 numObjects = getNumInspectObjects();
for( U32 i = 0; i < numObjects; ++ i )
getInspectObject( i )->inspectPreApply();
}
//-----------------------------------------------------------------------------
void GuiInspector::sendInspectPostApply()
{
const U32 numObjects = getNumInspectObjects();
for( U32 i = 0; i < numObjects; ++ i )
getInspectObject( i )->inspectPostApply();
}
//=============================================================================
// Console Methods.
//=============================================================================
// MARK: ---- Console Methods ----
//-----------------------------------------------------------------------------
ConsoleMethod( GuiInspector, inspect, void, 3, 3, "Inspect(Object)")
{
SimObject * target = Sim::findObject(argv[2]);
if(!target)
{
if(dAtoi(argv[2]) > 0)
Con::warnf("%s::inspect(): invalid object: %s", argv[0], argv[2]);
object->clearInspectObjects();
return;
}
object->inspectObject(target);
}
//-----------------------------------------------------------------------------
ConsoleMethod( GuiInspector, addInspect, void, 3, 4, "( id object, (bool autoSync = true) ) - Add the object to the list of objects being inspected." )
{
SimObject* obj;
if( !Sim::findObject( argv[ 2 ], obj ) )
{
Con::errorf( "%s::addInspect(): invalid object: %s", argv[ 0 ], argv[ 2 ] );
return;
}
if( argc > 3 )
object->addInspectObject( obj, false );
else
object->addInspectObject( obj );
}
//-----------------------------------------------------------------------------
ConsoleMethod( GuiInspector, removeInspect, void, 3, 3, "( id object ) - Remove the object from the list of objects being inspected." )
{
SimObject* obj;
if( !Sim::findObject( argv[ 2 ], obj ) )
{
Con::errorf( "%s::removeInspect(): invalid object: %s", argv[ 0 ], argv[ 2 ] );
return;
}
object->removeInspectObject( obj );
}
//-----------------------------------------------------------------------------
ConsoleMethod( GuiInspector, refresh, void, 2, 2, "Reinspect the currently selected object." )
{
if ( object->getNumInspectObjects() == 0 )
return;
SimObject *target = object->getInspectObject();
if ( target )
object->inspectObject( target );
}
//-----------------------------------------------------------------------------
ConsoleMethod( GuiInspector, getInspectObject, const char*, 2, 3, "getInspectObject( int index=0 ) - Returns currently inspected object" )
{
U32 index = 0;
if( argc > 2 )
index = dAtoi( argv[ 2 ] );
if( index >= object->getNumInspectObjects() )
{
Con::errorf( "GuiInspector::getInspectObject() - index out of range: %i", index );
return "";
}
return object->getInspectObject( index )->getIdString();
}
//-----------------------------------------------------------------------------
ConsoleMethod( GuiInspector, getNumInspectObjects, S32, 2, 2, "() - Return the number of objects currently being inspected." )
{
return object->getNumInspectObjects();
}
//-----------------------------------------------------------------------------
ConsoleMethod( GuiInspector, setName, void, 3, 3, "setName(NewObjectName)")
{
object->setName(argv[2]);
}
//-----------------------------------------------------------------------------
ConsoleMethod( GuiInspector, apply, void, 2, 2, "apply() - Force application of inspected object's attributes" )
{
object->sendInspectPostApply();
}
//-----------------------------------------------------------------------------
ConsoleMethod( GuiInspector, setObjectField, void, 4, 4,
"setObjectField( fieldname, data ) - Set a named fields value on the inspected object if it exists. This triggers all the usual callbacks that would occur if the field had been changed through the gui." )
{
object->setObjectField( argv[2], argv[3] );
}
//-----------------------------------------------------------------------------
ConsoleStaticMethod( GuiInspector, findByObject, S32, 2, 2,
"findByObject( SimObject ) - returns the id of an awake inspector that is inspecting the passed object if one exists." )
{
SimObject *obj;
if ( !Sim::findObject( argv[1], obj ) )
return NULL;
obj = GuiInspector::findByObject( obj );
if ( !obj )
return NULL;
return obj->getId();
}

View file

@ -0,0 +1,155 @@
//-----------------------------------------------------------------------------
// Copyright (c) 2012 GarageGames, LLC
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//-----------------------------------------------------------------------------
#ifndef _GUI_INSPECTOR_H_
#define _GUI_INSPECTOR_H_
#ifndef _GUISTACKCTRL_H_
#include "gui/containers/guiStackCtrl.h"
#endif
class GuiInspectorGroup;
class GuiInspectorField;
class GuiInspectorDatablockField;
/// A control that allows to edit the properties of one or more SimObjects.
class GuiInspector : public GuiStackControl
{
typedef GuiStackControl Parent;
public:
GuiInspector();
virtual ~GuiInspector();
DECLARE_CONOBJECT(GuiInspector);
DECLARE_CATEGORY( "Gui Editor" );
DECLARE_DESCRIPTION( "A control that allows to edit the properties of one or more SimObjects." );
// Console Object
static void initPersistFields();
// SimObject
virtual void onRemove();
virtual void onDeleteNotify( SimObject *object );
// GuiControl
virtual void parentResized( const RectI &oldParentRect, const RectI &newParentRect );
virtual bool resize( const Point2I &newPosition, const Point2I &newExtent );
virtual GuiControl* findHitControl( const Point2I &pt, S32 initialLayer );
virtual void getCursor( GuiCursor *&cursor, bool &showCursor, const GuiEvent &lastGuiEvent );
virtual void onMouseMove( const GuiEvent &event );
virtual void onMouseDown( const GuiEvent &event );
virtual void onMouseUp( const GuiEvent &event );
virtual void onMouseDragged( const GuiEvent &event );
// GuiInspector
/// Return true if "object" is in the inspection set of this inspector.
bool isInspectingObject( SimObject* object );
/// Set the currently inspected object.
virtual void inspectObject( SimObject *object );
/// Add another object to the set of currently inspected objects.
virtual void addInspectObject( SimObject* object, bool autoSync = true );
/// Remove the given object from the set of inspected objects.
virtual void removeInspectObject( SimObject* object );
/// Remove all objects from the inspection set.
virtual void clearInspectObjects();
/// Get the currently inspected object
SimObject* getInspectObject( U32 index = 0 ) { return mTargets[ index ]; }
/// Return the number of objects being inspected by this GuiInspector.
U32 getNumInspectObjects() const { return mTargets.size(); }
/// Call inspectPreApply on all inspected objects.
void sendInspectPreApply();
/// Call inspectPostApply on all inspected objects.
void sendInspectPostApply();
/// Set the currently inspected object name
/// @note Only valid in single-object mode.
void setName( StringTableEntry newName );
/// Deletes all GuiInspectorGroups
void clearGroups();
/// Returns true if the named group exists
/// Helper for inspectObject
GuiInspectorGroup* findExistentGroup( StringTableEntry groupName );
/// Should there be a GuiInspectorField associated with this fieldName,
/// update it to reflect actual/current value of that field in the inspected object.
/// Added to support UndoActions
void updateFieldValue( StringTableEntry fieldName, const char* arrayIdx );
/// Divider position is interpreted as an offset
/// from the right edge of the field control.
/// Divider margin is an offset on both left and right
/// sides of the divider in which it can be selected
/// with the mouse.
void getDivider( S32 &pos, S32 &margin );
void updateDivider();
bool collideDivider( const Point2I &localPnt );
void setHighlightField( GuiInspectorField *field );
// If returns true that group will not be inspected.
bool isGroupFiltered( const char *groupName ) const;
// Returns true only if the group name follows a minus symbol in the filters.
bool isGroupExplicitlyFiltered( const char *groupName ) const;
void setObjectField( const char *fieldName, const char *data );
static GuiInspector* findByObject( SimObject *obj );
protected:
typedef Vector< SimObjectPtr< SimObject > > TargetVector;
Vector<GuiInspectorGroup*> mGroups;
/// Objects being inspected by this GuiInspector.
TargetVector mTargets;
F32 mDividerPos;
S32 mDividerMargin;
bool mOverDivider;
bool mMovingDivider;
SimObjectPtr<GuiInspectorField> mHLField;
String mGroupFilters;
bool mShowCustomFields;
void refresh();
};
#endif

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,580 @@
//-----------------------------------------------------------------------------
// Copyright (c) 2012 GarageGames, LLC
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//-----------------------------------------------------------------------------
#ifndef _GUI_INSPECTOR_TYPES_H_
#define _GUI_INSPECTOR_TYPES_H_
#ifndef _GUI_INSPECTOR_H_
#include "gui/editor/guiInspector.h"
#endif
#ifndef _GUI_INSPECTOR_FIELD_H_
#include "gui/editor/inspector/field.h"
#endif
#ifndef _GUICONTROL_H_
#include "gui/core/guiControl.h"
#endif
#ifndef _GUICHECKBOXCTRL_H_
#include "gui/buttons/guiCheckBoxCtrl.h"
#endif
#ifndef _GUIBITMAPBUTTON_H_
#include "gui/buttons/guiBitmapButtonCtrl.h"
#endif
class GuiPopUpMenuCtrl;
/// A base class for other inspector field types which
/// wish to display a popup/dropdown menu.
class GuiInspectorTypeMenuBase : public GuiInspectorField
{
private:
typedef GuiInspectorField Parent;
public:
DECLARE_CONOBJECT(GuiInspectorTypeMenuBase);
//-----------------------------------------------------------------------------
// Override able methods for custom edit fields
//-----------------------------------------------------------------------------
virtual GuiControl* constructEditControl();
virtual void setValue( StringTableEntry newValue );
virtual void _populateMenu( GuiPopUpMenuCtrl *menu );
};
//-----------------------------------------------------------------------------
// TypeEnum GuiInspectorField Class
//-----------------------------------------------------------------------------
class GuiInspectorTypeEnum : public GuiInspectorTypeMenuBase
{
private:
typedef GuiInspectorTypeMenuBase Parent;
public:
DECLARE_CONOBJECT(GuiInspectorTypeEnum);
static void consoleInit();
virtual void _populateMenu( GuiPopUpMenuCtrl *menu );
};
//-----------------------------------------------------------------------------
// TypeCubemapName GuiInspectorField Class
//-----------------------------------------------------------------------------
class GuiInspectorTypeCubemapName : public GuiInspectorTypeMenuBase
{
private:
typedef GuiInspectorTypeMenuBase Parent;
public:
DECLARE_CONOBJECT(GuiInspectorTypeCubemapName);
static void consoleInit();
virtual void _populateMenu( GuiPopUpMenuCtrl *menu );
};
//--------------------------------------------------------------------------------
// TypeMaterialName GuiInspectorField Class
//--------------------------------------------------------------------------------
class GuiBitmapButtonCtrl;
class GuiInspectorTypeMaterialName : public GuiInspectorField
{
typedef GuiInspectorField Parent;
public:
GuiInspectorTypeMaterialName();
DECLARE_CONOBJECT(GuiInspectorTypeMaterialName);
static void consoleInit();
GuiBitmapButtonCtrl *mBrowseButton;
RectI mBrowseRect;
GuiControl* construct(const char* command);
//-----------------------------------------------------------------------------
// Override able methods for custom edit fields
//-----------------------------------------------------------------------------
virtual GuiControl* constructEditControl();
virtual bool updateRects();
};
class GuiInspectorTypeRegularMaterialName : public GuiInspectorTypeMaterialName
{
typedef GuiInspectorTypeMaterialName Parent;
public:
GuiInspectorTypeRegularMaterialName() {}
DECLARE_CONOBJECT(GuiInspectorTypeRegularMaterialName);
static void consoleInit();
virtual void _populateMenu( GuiPopUpMenuCtrl *menu );
};
//--------------------------------------------------------------------------------
// TypeTerrainMaterialIndex GuiInspectorField Class
//--------------------------------------------------------------------------------
class GuiInspectorTypeTerrainMaterialIndex : public GuiInspectorTypeMaterialName
{
typedef GuiInspectorTypeMaterialName Parent;
public:
GuiInspectorTypeTerrainMaterialIndex() {}
DECLARE_CONOBJECT(GuiInspectorTypeTerrainMaterialIndex);
static void consoleInit();
//-----------------------------------------------------------------------------
// Override able methods for custom edit fields
//-----------------------------------------------------------------------------
virtual GuiControl* constructEditControl();
};
//--------------------------------------------------------------------------------
// TypeTerrainMaterialName GuiInspectorField Class
//--------------------------------------------------------------------------------
class GuiInspectorTypeTerrainMaterialName : public GuiInspectorTypeMaterialName
{
typedef GuiInspectorTypeMaterialName Parent;
public:
GuiInspectorTypeTerrainMaterialName() {}
DECLARE_CONOBJECT(GuiInspectorTypeTerrainMaterialName);
static void consoleInit();
GuiControl* construct(const char* command);
//-----------------------------------------------------------------------------
// Override able methods for custom edit fields
//-----------------------------------------------------------------------------
virtual GuiControl* constructEditControl();
};
//-----------------------------------------------------------------------------
// GuiInspectorTypeGuiProfile Class
//-----------------------------------------------------------------------------
class GuiInspectorTypeGuiProfile : public GuiInspectorTypeMenuBase
{
private:
typedef GuiInspectorTypeMenuBase Parent;
public:
DECLARE_CONOBJECT(GuiInspectorTypeGuiProfile);
static void consoleInit();
virtual void _populateMenu( GuiPopUpMenuCtrl *menu );
};
//-----------------------------------------------------------------------------
// GuiInspectorTypeCheckBox Class
//-----------------------------------------------------------------------------
class GuiInspectorTypeCheckBox : public GuiInspectorField
{
private:
typedef GuiInspectorField Parent;
public:
DECLARE_CONOBJECT(GuiInspectorTypeCheckBox);
static void consoleInit();
//-----------------------------------------------------------------------------
// Override able methods for custom edit fields
//-----------------------------------------------------------------------------
virtual GuiControl* constructEditControl();
virtual void setValue( StringTableEntry newValue );
virtual const char* getValue();
};
//-----------------------------------------------------------------------------
// TypeCommand GuiInspectorField Class
//-----------------------------------------------------------------------------
class GuiInspectorTypeCommand : public GuiInspectorField
{
private:
typedef GuiInspectorField Parent;
StringTableEntry mTextEditorCommand;
void _setCommand( GuiButtonCtrl *ctrl, StringTableEntry command );
public:
DECLARE_CONOBJECT(GuiInspectorTypeCommand);
GuiInspectorTypeCommand();
static void consoleInit();
//-----------------------------------------------------------------------------
// Override able methods for custom edit fields
//-----------------------------------------------------------------------------
virtual GuiControl* constructEditControl();
virtual void setValue( StringTableEntry data );
};
//-----------------------------------------------------------------------------
// TypeFileName GuiInspectorField Class
//-----------------------------------------------------------------------------
class GuiInspectorTypeFileName : public GuiInspectorField
{
private:
typedef GuiInspectorField Parent;
public:
DECLARE_CONOBJECT(GuiInspectorTypeFileName);
static void consoleInit();
SimObjectPtr<GuiButtonCtrl> mBrowseButton;
RectI mBrowseRect;
//-----------------------------------------------------------------------------
// Override able methods for custom edit fields
//-----------------------------------------------------------------------------
virtual GuiControl* constructEditControl();
virtual bool resize(const Point2I &newPosition, const Point2I &newExtent);
virtual bool updateRects();
virtual void updateValue();
};
//-----------------------------------------------------------------------------
// TypeImageFileName GuiInspectorField Class
//-----------------------------------------------------------------------------
class GuiInspectorTypeImageFileName : public GuiInspectorTypeFileName
{
typedef GuiInspectorTypeFileName Parent;
public:
DECLARE_CONOBJECT(GuiInspectorTypeImageFileName);
static void consoleInit();
virtual GuiControl* constructEditControl();
bool renderTooltip( const Point2I &hoverPos, const Point2I &cursorPos, const char *tipText = NULL );
};
//-----------------------------------------------------------------------------
// TypeRectUV GuiInspectorField Class
//-----------------------------------------------------------------------------
class GuiInspectorTypeRectUV : public GuiInspectorField
{
typedef GuiInspectorField Parent;
public:
GuiBitmapButtonCtrl *mBrowseButton;
RectI mBrowseRect;
public:
DECLARE_CONOBJECT(GuiInspectorTypeRectUV);
GuiInspectorTypeRectUV();
static void consoleInit();
//-----------------------------------------------------------------------------
// Override able methods for custom edit fields
//-----------------------------------------------------------------------------
virtual GuiControl* constructEditControl();
virtual bool updateRects();
};
//-----------------------------------------------------------------------------
// TypeEaseF GuiInspectorField Class
//-----------------------------------------------------------------------------
class GuiInspectorTypeEaseF : public GuiInspectorField
{
public:
typedef GuiInspectorField Parent;
protected:
SimObjectPtr<GuiButtonCtrl> mBrowseButton;
RectI mBrowseRect;
public:
GuiInspectorTypeEaseF();
DECLARE_CONOBJECT( GuiInspectorTypeEaseF );
static void consoleInit();
//-----------------------------------------------------------------------------
// Override able methods for custom edit fields
//-----------------------------------------------------------------------------
virtual GuiControl* constructEditControl();
virtual bool resize(const Point2I &newPosition, const Point2I &newExtent);
virtual bool updateRects();
};
//-----------------------------------------------------------------------------
// TypePrefabFilename GuiInspectorField Class
//-----------------------------------------------------------------------------
class GuiInspectorTypePrefabFilename : public GuiInspectorTypeFileName
{
typedef GuiInspectorTypeFileName Parent;
public:
DECLARE_CONOBJECT(GuiInspectorTypePrefabFilename);
static void consoleInit();
virtual GuiControl* constructEditControl();
};
//-----------------------------------------------------------------------------
// TypeShapeFilename GuiInspectorField Class
//-----------------------------------------------------------------------------
class GuiInspectorTypeShapeFilename : public GuiInspectorTypeFileName
{
typedef GuiInspectorTypeFileName Parent;
public:
GuiBitmapButtonCtrl *mShapeEdButton;
DECLARE_CONOBJECT(GuiInspectorTypeShapeFilename);
static void consoleInit();
virtual GuiControl* constructEditControl();
virtual bool updateRects();
};
//-----------------------------------------------------------------------------
// TypeColor GuiInspectorField Class (Base for ColorI/ColorF)
//-----------------------------------------------------------------------------
class GuiSwatchButtonCtrl;
class GuiInspectorTypeColor : public GuiInspectorField
{
typedef GuiInspectorField Parent;
protected:
/// Return the name of a function that will be used to convert the
/// floating-point color of the swatch button to the form used by the
/// data field.
virtual const char* _getColorConversionFunction() const { return NULL; }
public:
GuiInspectorTypeColor();
DECLARE_CONOBJECT(GuiInspectorTypeColor);
StringTableEntry mColorFunction;
GuiSwatchButtonCtrl *mBrowseButton;
RectI mBrowseRect;
//-----------------------------------------------------------------------------
// Override able methods for custom edit fields
//-----------------------------------------------------------------------------
virtual GuiControl* constructEditControl();
virtual bool resize(const Point2I &newPosition, const Point2I &newExtent);
virtual bool updateRects();
};
//-----------------------------------------------------------------------------
// TypeColorI GuiInspectorField Class
//-----------------------------------------------------------------------------
class GuiInspectorTypeColorI : public GuiInspectorTypeColor
{
typedef GuiInspectorTypeColor Parent;
protected:
virtual const char* _getColorConversionFunction() const { return "ColorFloatToInt"; }
public:
GuiInspectorTypeColorI();
DECLARE_CONOBJECT(GuiInspectorTypeColorI);
static void consoleInit();
void setValue( StringTableEntry newValue );
};
//-----------------------------------------------------------------------------
// TypeColorF GuiInspectorField Class
//-----------------------------------------------------------------------------
class GuiInspectorTypeColorF : public GuiInspectorTypeColor
{
typedef GuiInspectorTypeColor Parent;
public:
GuiInspectorTypeColorF();
DECLARE_CONOBJECT(GuiInspectorTypeColorF);
static void consoleInit();
void setValue( StringTableEntry newValue );
};
/* NOTE: Evidently this isn't used anywhere (or implemented) so i commented it out
//------------------------------------------------------------------------------
// TypeString GuiInspectorField class
//------------------------------------------------------------------------------
class GuiInspectorTypeString : public GuiInspectorField
{
private:
typedef GuiInspectorField Parent;
public:
DECLARE_CONOBJECT(GuiInspectorTypeString);
static void consoleInit();
SimObjectPtr<GuiButtonCtrl> mBrowseButton;
virtual GuiControl* constructEditControl();
virtual bool resize(const Point2I &newPosition, const Point2I &newExtent);
virtual bool updateRects();
};
*/
//------------------------------------------------------------------------------
// TypeS32 GuiInspectorField class
//------------------------------------------------------------------------------
class GuiInspectorTypeS32 : public GuiInspectorField
{
private:
typedef GuiInspectorField Parent;
public:
DECLARE_CONOBJECT(GuiInspectorTypeS32);
static void consoleInit();
virtual GuiControl* constructEditControl();
virtual void setValue( StringTableEntry newValue );
};
//------------------------------------------------------------------------------
// TypeBitMask32 GuiInspectorField class
//------------------------------------------------------------------------------
class GuiInspectorTypeBitMask32Helper;
class GuiDynamicCtrlArrayControl;
class GuiInspectorTypeBitMask32 : public GuiInspectorField
{
typedef GuiInspectorField Parent;
public:
GuiInspectorTypeBitMask32();
virtual ~GuiInspectorTypeBitMask32() {}
DECLARE_CONOBJECT( GuiInspectorTypeBitMask32 );
// ConsoleObject
bool onAdd();
static void consoleInit();
// GuiInspectorField
virtual void childResized( GuiControl *child );
virtual bool resize( const Point2I &newPosition, const Point2I &newExtent );
virtual bool updateRects();
virtual void updateData();
virtual StringTableEntry getValue();
virtual void setValue( StringTableEntry value );
protected:
GuiInspectorTypeBitMask32Helper *mHelper;
GuiRolloutCtrl *mRollout;
GuiDynamicCtrlArrayControl *mArrayCtrl;
Vector<GuiInspectorField*> mChildren;
};
class GuiInspectorTypeBitMask32Helper : public GuiInspectorField
{
typedef GuiInspectorField Parent;
public:
GuiInspectorTypeBitMask32Helper();
DECLARE_CONOBJECT( GuiInspectorTypeBitMask32Helper );
GuiBitmapButtonCtrl *mButton;
GuiRolloutCtrl *mParentRollout;
GuiInspectorTypeBitMask32 *mParentField;
RectI mButtonRect;
//-----------------------------------------------------------------------------
// Override able methods for custom edit fields
//-----------------------------------------------------------------------------
virtual GuiControl* constructEditControl();
virtual bool resize( const Point2I &newPosition, const Point2I &newExtent );
virtual bool updateRects();
virtual void setValue( StringTableEntry value );
};
//-----------------------------------------------------------------------------
// TypeName GuiInspectorField Class
//-----------------------------------------------------------------------------
class GuiInspectorTypeName : public GuiInspectorField
{
private:
typedef GuiInspectorField Parent;
public:
DECLARE_CONOBJECT(GuiInspectorTypeName);
static void consoleInit();
virtual bool verifyData( StringTableEntry data );
};
//-----------------------------------------------------------------------------
// TypeSFXParameterName GuiInspectorField Class
//-----------------------------------------------------------------------------
class GuiInspectorTypeSFXParameterName : public GuiInspectorTypeMenuBase
{
private:
typedef GuiInspectorTypeMenuBase Parent;
public:
DECLARE_CONOBJECT(GuiInspectorTypeSFXParameterName);
static void consoleInit();
virtual void _populateMenu( GuiPopUpMenuCtrl *menu );
};
//-----------------------------------------------------------------------------
// TypeSFXStateName GuiInspectorField Class
//-----------------------------------------------------------------------------
class GuiInspectorTypeSFXStateName : public GuiInspectorTypeMenuBase
{
private:
typedef GuiInspectorTypeMenuBase Parent;
public:
DECLARE_CONOBJECT(GuiInspectorTypeSFXStateName);
static void consoleInit();
virtual void _populateMenu( GuiPopUpMenuCtrl *menu );
};
//-----------------------------------------------------------------------------
// TypeSFXSourceName GuiInspectorField Class
//-----------------------------------------------------------------------------
class GuiInspectorTypeSFXSourceName : public GuiInspectorTypeMenuBase
{
private:
typedef GuiInspectorTypeMenuBase Parent;
public:
DECLARE_CONOBJECT(GuiInspectorTypeSFXSourceName);
static void consoleInit();
virtual void _populateMenu( GuiPopUpMenuCtrl *menu );
};
#endif // _GUI_INSPECTOR_TYPES_H_

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,222 @@
//-----------------------------------------------------------------------------
// Copyright (c) 2012 GarageGames, LLC
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//-----------------------------------------------------------------------------
#ifndef _GUIMENUBAR_H_
#define _GUIMENUBAR_H_
#ifndef _GUITEXTLISTCTRL_H_
#include "gui/controls/guiTextListCtrl.h"
#endif
#ifndef _GUITICKCTRL_H_
#include "gui/shiny/guiTickCtrl.h"
#endif
class GuiMenuBar;
class GuiMenuTextListCtrl;
class GuiMenuBackgroundCtrl : public GuiControl
{
typedef GuiControl Parent;
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 GuiSubmenuBackgroundCtrl : public GuiMenuBackgroundCtrl
{
typedef GuiMenuBackgroundCtrl Parent;
public:
GuiSubmenuBackgroundCtrl(GuiMenuBar *ctrl, GuiMenuTextListCtrl* textList);
bool pointInControl(const Point2I & parentCoordPoint);
void onMouseDown(const GuiEvent &event);
};
//------------------------------------------------------------------------------
class GuiMenuTextListCtrl : public GuiTextListCtrl
{
private:
typedef GuiTextListCtrl Parent;
protected:
GuiMenuBar *mMenuBarCtrl;
public:
bool isSubMenu; // Indicates that this text list is in a submenu
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);
virtual void onCellHighlighted(Point2I cell); // Added
};
//------------------------------------------------------------------------------
class GuiMenuBar : public GuiTickCtrl // Was: GuiControl
{
typedef GuiTickCtrl Parent; // Was: GuiControl Parent;
public:
struct Menu;
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
bool isSubmenu; // This menu item has a submenu that will be displayed
MenuItem *firstSubmenuItem; // The first menu item in the submenu
Menu* submenuParentMenu; // For a submenu, this is the parent menu
};
struct Menu
{
char *text;
U32 id;
RectI bounds;
bool visible;
S32 bitmapIndex; // Index of the bitmap in the bitmap array (-1 = no bitmap)
bool drawBitmapOnly; // Draw only the bitmap and not the text
bool drawBorder; // Should a border be drawn around this menu (usually if we only have a bitmap, we don't want a border)
Menu *nextMenu;
MenuItem *firstMenuItem;
};
GuiMenuBackgroundCtrl *mBackground;
GuiMenuTextListCtrl *mTextList;
GuiSubmenuBackgroundCtrl *mSubmenuBackground; // Background for a submenu
GuiMenuTextListCtrl *mSubmenuTextList; // Text list for a submenu
Menu *menuList;
Menu *mouseDownMenu;
Menu *mouseOverMenu;
MenuItem* mouseDownSubmenu; // Stores the menu item that is a submenu that has been selected
MenuItem* mouseOverSubmenu; // Stores the menu item that is a submenu that has been highlighted
bool menuBarDirty;
U32 mCurAcceleratorIndex;
Point2I maxBitmapSize;
S32 mCheckmarkBitmapIndex; // Index in the bitmap array to use for the check mark image
S32 mPadding;
S32 mHorizontalMargin; // Left and right margin around the text of each menu
S32 mVerticalMargin; // Top and bottom margin around the text of each menu
S32 mBitmapMargin; // Margin between a menu's bitmap and text
// Used to keep track of the amount of ticks that the mouse is hovering
// over a menu.
S32 mMouseOverCounter;
bool mCountMouseOver;
S32 mMouseHoverAmount;
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();
// Methods to deal with submenus
MenuItem* findSubmenuItem(Menu *menu, const char *menuItem, const char *submenuItem);
void addSubmenuItem(Menu *menu, MenuItem *submenu, const char *text, U32 id, const char *accelerator, S32 checkGroup);
void removeSubmenuItem(MenuItem *menuItem, MenuItem *submenuItem);
void clearSubmenuItems(MenuItem *menuitem);
void onSubmenuAction(S32 selectionIndex, RectI bounds, Point2I cellSize);
void closeSubmenu();
void checkSubmenuMouseMove(const GuiEvent &event);
MenuItem *findHitMenuItem(Point2I mousePoint);
void highlightedMenuItem(S32 selectionIndex, RectI bounds, Point2I cellSize); // Called whenever a menu item is highlighted by the mouse
// display/mouse functions
Menu *findHitMenu(Point2I mousePoint);
// Called when the GUI theme changes and a bitmap arrary may need updating
// void onThemeChange();
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);
// Added to support 'ticks'
void processTick();
static void initPersistFields();
DECLARE_CONOBJECT(GuiMenuBar);
DECLARE_CALLBACK( void, onMouseInMenu, (bool hasLeftMenu));
DECLARE_CALLBACK( void, onMenuSelect, (const char* menuId, const char* menuText));
DECLARE_CALLBACK( void, onMenuItemSelect, ( const char* menuId, const char* menuText, const char* menuItemId, const char* menuItemText ));
DECLARE_CALLBACK( void, onSubmenuSelect, ( const char* submenuId, const char* submenuText));
};
#endif

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,175 @@
//-----------------------------------------------------------------------------
// Copyright (c) 2012 GarageGames, LLC
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//-----------------------------------------------------------------------------
#ifndef _GUIPARTICLEGRAPHCTRL_H_
#define _GUIPARTICLEGRAPHCTRL_H_
#ifndef _GUICONTROL_H_
#include "gui/core/guiControl.h"
#endif
#ifndef _STRINGTABLE_H_
#include "core/stringTable.h"
#endif
class GuiParticleGraphCtrl : public GuiControl
{
private:
typedef GuiControl Parent;
protected:
/// The color of the nuts.
ColorI mNutColor;
/// The outline color of the nuts.
ColorI mOutlineColor;
/// The rectangle size to check for clicks on nuts (default 8) which is RectI( pointClick - 4, pointClick - 4, 8, 8 )
S32 mVertexClickSize;
Point2I findHitNut( Point2I hitPoint );
public:
enum Constants {
MaxPlots = 32,
MaxDataPoints = 200
};
enum GraphType {
Point,
Polyline,
Filled,
Bar
};
struct PlotInfo
{
ColorF mGraphColor;
Vector<Point2F> mGraphData;
Vector<Point2F> mNutList;
Point2F mGraphMax;
Point2F mGraphMin;
GraphType mGraphType;
StringTableEntry mGraphName;
bool mHidden;
F32 mGraphScale;
};
S32 mSelectedPlot;
S32 mSelectedPoint;
S32 mOriginalSelectedPoint;
S32 mLastSelectedPoint;
S32 mTooltipSelectedPlot;
S32 mAddedPointIndex;
bool mAutoMax;
bool mAutoRemove;
bool mRenderAllPoints;
bool mPointWasAdded;
bool mRenderGraphTooltip;
bool mRenderNextGraphTooltip;
bool mPointXMovementClamped;
Point2F mAddedPoint;
Point2F mLastMousePos;
Point2I mCursorPos;
PlotInfo mPlots[MaxPlots];
//creation methods
DECLARE_CONOBJECT(GuiParticleGraphCtrl);
DECLARE_CATEGORY( "Gui Editor" );
GuiParticleGraphCtrl();
virtual ~GuiParticleGraphCtrl() { };
void onMouseMove(const GuiEvent &event);
void onMouseDown( const GuiEvent &event );
void onMouseUp( const GuiEvent &event );
void onMouseDragged( const GuiEvent &event );
void onRightMouseDown( const GuiEvent &event );
void onRightMouseUp( const GuiEvent &event );
void onRightMouseDragged( const GuiEvent &event );
//Parental methods
bool onWake();
void onRender(Point2I offset, const RectI &updateRect);
bool renderGraphTooltip(Point2I cursorPos, StringTableEntry tooltip);
// Graph interface
S32 addPlotPoint(S32 plotID, Point2F v, bool setAdded = true);
void insertPlotPoint(S32 plotID, S32 i, Point2F v);
S32 changePlotPoint(S32 plotID, S32 i, Point2F v);
S32 removePlotPoint(S32 plotID, S32 i);
Point2F convertToGraphCoord(S32 plotID, Point2I v);
// Set Graph specific functions
void setGraphType(S32 plotID, const char *graphType);
void setSelectedPlot(S32 plotID);
void setSelectedPoint(S32 point);
void resetSelectedPoint();
void setGraphHidden(S32 plotID, bool isHidden);
// Set Global Options
void setAutoGraphMax(bool autoMax);
void setAutoRemove(bool autoRemove);
void setRenderAll(bool renderAll);
void setRenderGraphTooltip(bool renderGraphTooltip);
void setPointXMovementClamped(bool clamped);
// Get Functions
Point2F getGraphExtent(S32 plotID);
ColorF getGraphColor(S32 plotID);
S32 getSelectedPlot();
S32 getSelectedPoint();
Point2F getPlotPoint(S32 plotID, S32 samples);
S32 getPlotIndex(S32 plotID, F32 x, F32 y);
Point2F getGraphMax(S32 plotID);
Point2F getGraphMin(S32 plotID);
bool isExistingPoint(S32 plotID, S32 point);
StringTableEntry getGraphName(S32 plotID);
// Set Graph Min and MaxFunctions
void setGraphMin(S32 plotID, Point2F graphMin);
void setGraphMinX(S32 plotID, F32 graphMinX);
void setGraphMinY(S32 plotID, F32 graphMinY);
void setGraphMax(S32 plotID, Point2F graphMax);
void setGraphMaxX(S32 plotID, F32 graphMaxX);
void setGraphMaxY(S32 plotID, F32 graphMaxY);
// Other set functions for graphs
void setGraphName(S32 plotID, StringTableEntry graphName);
// Clear Functions
void clearGraph(S32 plotID);
void clearAllGraphs();
// Selection nuts.
bool inNut( const Point2I &pt, S32 x, S32 y );
void drawNut( const Point2I &nut, S32 size, ColorI &outlineColor, ColorI &nutColor );
};
typedef GuiParticleGraphCtrl::GraphType GuiParticleGraphType;
DefineEnumType( GuiParticleGraphType );
#endif

View file

@ -0,0 +1,318 @@
//-----------------------------------------------------------------------------
// Copyright (c) 2012 GarageGames, LLC
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//-----------------------------------------------------------------------------
#include "console/console.h"
#include "console/consoleTypes.h"
#include "gfx/gfxDevice.h"
#include "gfx/gfxDrawUtil.h"
#include "gui/editor/guiRectHandles.h"
IMPLEMENT_CONOBJECT(GuiRectHandles);
ConsoleDocClass( GuiRectHandles,
"@brief Draws a box with handles for the user to manipulate.\n\n"
"Editor use only.\n\n"
"@internal"
);
//--------------------------------------------------------------------------
GuiRectHandles::GuiRectHandles() : GuiControl()
{
mHandleRect.set(0.0f, 0.0f, 1.0f, 1.0f);
mHandleSize = 10;
mUseCustomColor = false;
mHandleColor.set(100,100,100);
mHitHandle = 0;
}
GuiRectHandles::~GuiRectHandles()
{
}
//--------------------------------------------------------------------------
void GuiRectHandles::initPersistFields()
{
addField("handleRect", TypeRectF, Offset(mHandleRect, GuiRectHandles), "RectF of handle's box." );
addField("handleSize", TypeS32, Offset(mHandleSize, GuiRectHandles), "Size of handles in pixels." );
addField("useCustomColor", TypeBool, Offset(mUseCustomColor, GuiRectHandles), "Use given custom color for handles." );
addField("handleColor", TypeColorI, Offset(mHandleColor, GuiRectHandles), "Use given custom color for handles." );
Parent::initPersistFields();
}
//--------------------------------------------------------------------------
void GuiRectHandles::onMouseUp(const GuiEvent &event)
{
mHitHandle = 0;
}
void GuiRectHandles::onMouseDown(const GuiEvent &event)
{
// The handles range from 0-1, so scale to fit within the
// control's bounds.
const Point2I& extent = getExtent();
Point2I pos(extent.x*mHandleRect.point.x, extent.y*mHandleRect.point.y);
Point2I size(extent.x*mHandleRect.extent.x, extent.y*mHandleRect.extent.y);
RectI box(pos, size);
Point2I localMousePoint = globalToLocalCoord(event.mousePoint);
// Check if mouse is within handle rect
if(!box.pointInRect(localMousePoint))
{
mHitHandle = 0;
return;
}
Point2I normalizedMouse = localMousePoint - pos;
Point2I halfSize = size / 2;
S32 halfHandleSize = mHandleSize / 2;
if(normalizedMouse.y < mHandleSize)
{
// Top handles
if(normalizedMouse.x < mHandleSize)
mHitHandle = 1;
else if(normalizedMouse.x >= (size.x-mHandleSize))
mHitHandle = 3;
else if(normalizedMouse.x >= (halfSize.x-halfHandleSize) && normalizedMouse.x < (halfSize.x+halfHandleSize))
mHitHandle = 2;
}
else if(normalizedMouse.y >= (size.y-mHandleSize))
{
// Bottom handles
if(normalizedMouse.x < mHandleSize)
mHitHandle = 7;
else if(normalizedMouse.x >= (size.x-mHandleSize))
mHitHandle = 5;
else if(normalizedMouse.x >= (halfSize.x-halfHandleSize) && normalizedMouse.x < (halfSize.x+halfHandleSize))
mHitHandle = 6;
}
else if(normalizedMouse.y >= (halfSize.y-halfHandleSize) && normalizedMouse.y < (halfSize.y+halfHandleSize))
{
// Middle handles
if(normalizedMouse.x < mHandleSize)
mHitHandle = 8;
else if(normalizedMouse.x >= (size.x-mHandleSize))
mHitHandle = 4;
else if(normalizedMouse.x >= (halfSize.x-halfHandleSize) && normalizedMouse.x < (halfSize.x+halfHandleSize))
mHitHandle = 9;
}
mHitPoint = localMousePoint;
}
void GuiRectHandles::onMouseDragged(const GuiEvent &event)
{
if(mHitHandle == 0)
return;
// The handles range from 0-1, so scale to fit within the
// control's bounds.
const Point2I& extent = getExtent();
Point2I localMousePoint = globalToLocalCoord(event.mousePoint);
Point2I diffI = localMousePoint - mHitPoint;
Point2F diffF(diffI.x/F32(extent.x), diffI.y/F32(extent.y));
RectF box(mHandleRect);
bool postMoveExtentX = false;
bool postMoveExtentY = false;
bool keepExtent = false;
switch(mHitHandle)
{
case 1:
{
// Top left
box.point += diffF;
postMoveExtentX = true;
postMoveExtentY = true;
break;
}
case 2:
{
// Top middle
box.point.y += diffF.y;
postMoveExtentY = true;
break;
}
case 3:
{
// Top right
box.point.y += diffF.y;
box.extent.x += diffF.x;
postMoveExtentY = true;
break;
}
case 4:
{
// Middle right
box.extent.x += diffF.x;
break;
}
case 5:
{
// Bottom right
box.extent += diffF;
break;
}
case 6:
{
// Bottom middle
box.extent.y += diffF.y;
break;
}
case 7:
{
// Bottom left
box.point.x += diffF.x;
box.extent.y += diffF.y;
postMoveExtentX = true;
break;
}
case 8:
{
// Middle left
box.point.x += diffF.x;
postMoveExtentX = true;
break;
}
case 9:
{
// Centre
box.point += diffF;
keepExtent = true;
break;
}
default:
break;
}
// Position limits
if(box.point.x < 0.0f)
box.point.x = 0.0f;
else if(box.point.x > 1.0f)
box.point.x = 1.0f;
if(box.point.y < 0.0f)
box.point.y = 0.0f;
else if(box.point.y > 1.0f)
box.point.y = 1.0f;
// Move any extent to counter a change in handle position. Do this
// after the limits above to make sure the extent doesn't accidentally
// grow when the position is clamped.
if(postMoveExtentX)
box.extent.x += mHandleRect.point.x - box.point.x;
if(postMoveExtentY)
box.extent.y += mHandleRect.point.y - box.point.y;
// Extent limits
if(box.extent.x < 0.0f)
box.extent.x = 0.0f;
else if(box.extent.x > 1.0f)
box.extent.x = 1.0f;
if(box.point.x+box.extent.x > 1.0f)
{
if(keepExtent)
box.point.x = 1.0f-box.extent.x;
else
box.extent.x = 1.0f-box.point.x;
}
if(box.extent.y < 0.0f)
box.extent.y = 0.0f;
else if(box.extent.y > 1.0f)
box.extent.y = 1.0f;
if(box.point.y+box.extent.y > 1.0f)
{
if(keepExtent)
box.point.y = 1.0f-box.extent.y;
else
box.extent.y = 1.0f-box.point.y;
}
mHandleRect = box;
mHitPoint = localMousePoint;
if( isMethod( "onHandleRectChange" ) )
Con::executef(this, "onHandleRectChange" );
}
//--------------------------------------------------------------------------
void GuiRectHandles::onRender(Point2I offset, const RectI &updateRect)
{
Parent::onRender( offset, updateRect );
ColorI handleColor = mProfile->mBorderColor;
if(mUseCustomColor)
handleColor = mHandleColor;
// The handles range from 0-1, so scale to fit within the
// control's bounds.
const Point2I& extent = getExtent();
Point2I pos(extent.x*mHandleRect.point.x, extent.y*mHandleRect.point.y);
Point2I size(extent.x*mHandleRect.extent.x, extent.y*mHandleRect.extent.y);
RectI box(offset+pos, size);
// Draw border
GFX->getDrawUtil()->drawRect(box, handleColor);
// Draw each handle
Point2I handleSize(mHandleSize, mHandleSize);
RectI handleRect(box.point, handleSize);
GFX->getDrawUtil()->drawRectFill(handleRect, handleColor); // Upper left
handleRect.point = Point2I(box.point.x+size.x-handleSize.x, box.point.y);
GFX->getDrawUtil()->drawRectFill(handleRect, handleColor); // Upper right
handleRect.point = Point2I(box.point.x, box.point.y+size.y-handleSize.y);
GFX->getDrawUtil()->drawRectFill(handleRect, handleColor); // Lower left
handleRect.point = Point2I(box.point.x+size.x-handleSize.x, box.point.y+size.y-handleSize.y);
GFX->getDrawUtil()->drawRectFill(handleRect, handleColor); // Lower right
Point2I halfSize = size / 2;
Point2I halfHandleSize = handleSize / 2;
handleRect.point = Point2I(box.point.x+halfSize.x-halfHandleSize.x, box.point.y);
GFX->getDrawUtil()->drawRectFill(handleRect, handleColor); // Upper middle
handleRect.point = Point2I(box.point.x+halfSize.x-halfHandleSize.x, box.point.y+size.y-handleSize.y);
GFX->getDrawUtil()->drawRectFill(handleRect, handleColor); // Lower middle
handleRect.point = Point2I(box.point.x, box.point.y+halfSize.y-halfHandleSize.y);
GFX->getDrawUtil()->drawRectFill(handleRect, handleColor); // Left middle
handleRect.point = Point2I(box.point.x+size.x-handleSize.x, box.point.y+halfSize.y-halfHandleSize.y);
GFX->getDrawUtil()->drawRectFill(handleRect, handleColor); // Right middle
handleRect.point = Point2I(box.point.x+halfSize.x-halfHandleSize.x, box.point.y+halfSize.y-halfHandleSize.y);
GFX->getDrawUtil()->drawRectFill(handleRect, handleColor); // Middle
renderChildControls(offset, updateRect);
}

View file

@ -0,0 +1,59 @@
//-----------------------------------------------------------------------------
// Copyright (c) 2012 GarageGames, LLC
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//-----------------------------------------------------------------------------
#ifndef _GUIRECTHANDLES_H_
#define _GUIRECTHANDLES_H_
#ifndef _GUICONTROL_H_
#include "gui/core/guiControl.h"
#endif
class GuiRectHandles : public GuiControl
{
private:
typedef GuiControl Parent;
protected:
RectF mHandleRect;
S32 mHandleSize;
bool mUseCustomColor;
ColorI mHandleColor;
S32 mHitHandle; // 0 = none, 1-8 = clockwise circle starting upper left, 9 = centre
Point2I mHitPoint;
public:
DECLARE_CONOBJECT(GuiRectHandles);
DECLARE_CATEGORY( "Gui Other" );
DECLARE_DESCRIPTION( "Draws a box with handles for the user to manipulate.");
GuiRectHandles();
virtual ~GuiRectHandles();
static void initPersistFields();
virtual void onMouseUp(const GuiEvent &event);
virtual void onMouseDown(const GuiEvent &event);
virtual void onMouseDragged(const GuiEvent &event);
virtual void onRender(Point2I offset, const RectI &updateRect);
};
#endif

View file

@ -0,0 +1,142 @@
//-----------------------------------------------------------------------------
// Copyright (c) 2012 GarageGames, LLC
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//-----------------------------------------------------------------------------
#include "platform/platform.h"
#include "gui/editor/guiSeparatorCtrl.h"
#include "gfx/gfxDevice.h"
#include "gfx/gfxDrawUtil.h"
#include "console/console.h"
#include "console/consoleTypes.h"
#include "gui/core/guiCanvas.h"
#include "gui/core/guiDefaultControlRender.h"
IMPLEMENT_CONOBJECT(GuiSeparatorCtrl);
ConsoleDocClass( GuiSeparatorCtrl,
"@brief A control that renders a horizontal or vertical separator with "
"an optional text label (horizontal only)\n\n"
"@tsexample\n"
"new GuiSeparatorCtrl()\n"
"{\n"
" profile = \"GuiDefaultProfile\";\n"
" position = \"505 0\";\n"
" extent = \"10 17\";\n"
" minExtent = \"10 17\";\n"
" canSave = \"1\";\n"
" visible = \"1\";\n"
" horizSizing = \"left\";\n"
"};\n"
"@endtsexample\n\n"
"@ingroup GuiControls\n");
ImplementEnumType( GuiSeparatorType,
"GuiSeparatorCtrl orientations\n\n"
"@ingroup GuiControls" )
{ GuiSeparatorCtrl::separatorTypeVertical, "Vertical" },
{ GuiSeparatorCtrl::separatorTypeHorizontal,"Horizontal" }
EndImplementEnumType;
//--------------------------------------------------------------------------
GuiSeparatorCtrl::GuiSeparatorCtrl() : GuiControl()
{
mInvisible = false;
mTextLeftMargin = 0;
mMargin = 2;
setExtent( 12, 35 );
mSeparatorType = GuiSeparatorCtrl::separatorTypeVertical;
}
//--------------------------------------------------------------------------
void GuiSeparatorCtrl::initPersistFields()
{
addField("caption", TypeRealString, Offset(mText, GuiSeparatorCtrl),
"Optional text label to display." );
addField("type", TYPEID< separatorTypeOptions >(), Offset(mSeparatorType, GuiSeparatorCtrl),
"Orientation of separator." );
addField("borderMargin", TypeS32, Offset(mMargin, GuiSeparatorCtrl));
addField("invisible", TypeBool, Offset(mInvisible, GuiSeparatorCtrl));// Nonsense. Should use GuiControl's visibility.
addField("leftMargin", TypeS32, Offset(mTextLeftMargin, GuiSeparatorCtrl),
"Left margin of text label." );
Parent::initPersistFields();
}
//--------------------------------------------------------------------------
void GuiSeparatorCtrl::onRender(Point2I offset, const RectI &updateRect)
{
Parent::onRender( offset, updateRect );
if( mInvisible )
return;
if( mText.isNotEmpty() && mSeparatorType != separatorTypeVertical )
{
// If text is present and we have a left margin, then draw some separator, then the
// text, and then the rest of the separator.
S32 posx = offset.x + mMargin;
S32 fontheight = mProfile->mFont->getHeight();
S32 seppos = (fontheight - 2) / 2 + offset.y;
if( mTextLeftMargin > 0 )
{
RectI rect( Point2I( posx, seppos ), Point2I( mTextLeftMargin, 2 ) );
renderSlightlyLoweredBox(rect, mProfile);
posx += mTextLeftMargin;
}
GFX->getDrawUtil()->setBitmapModulation( mProfile->mFontColor );
posx = GFX->getDrawUtil()->drawText(mProfile->mFont, Point2I(posx,offset.y), mText, mProfile->mFontColors);
RectI rect( Point2I( posx, seppos ), Point2I( getWidth() - posx + offset.x, 2 ) );
// Space text and separator a bit apart at right end.
rect.point.x += 2;
rect.extent.x -= 2;
if( rect.extent.x > 0 )
renderSlightlyLoweredBox( rect, mProfile );
}
else
{
if( mSeparatorType == separatorTypeHorizontal )
{
S32 seppos = getHeight() / 2 + offset.y;
RectI rect(Point2I(offset.x + mMargin ,seppos),Point2I(getWidth() - (mMargin * 2),2));
renderSlightlyLoweredBox(rect, mProfile);
}
else
{
S32 seppos = getWidth() / 2 + offset.x;
RectI rect(Point2I(seppos, offset.y + mMargin),Point2I(2, getHeight() - (mMargin * 2)));
renderSlightlyLoweredBox(rect, mProfile);
}
}
renderChildControls(offset, updateRect);
}

View file

@ -0,0 +1,67 @@
//-----------------------------------------------------------------------------
// Copyright (c) 2012 GarageGames, LLC
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//-----------------------------------------------------------------------------
#ifndef _GUISEPARATORCTRL_H_
#define _GUISEPARATORCTRL_H_
#ifndef _GUICONTROL_H_
#include "gui/core/guiControl.h"
#endif
#ifndef _DYNAMIC_CONSOLETYPES_H_
#include "console/dynamicTypes.h"
#endif
/// Renders a separator line with optional text.
class GuiSeparatorCtrl : public GuiControl
{
private:
typedef GuiControl Parent;
public:
bool mInvisible;
String mText;
S32 mTextLeftMargin;
S32 mMargin;
S32 mSeparatorType;
enum separatorTypeOptions
{
separatorTypeVertical = 0, ///< Draw Vertical Separator
separatorTypeHorizontal ///< Horizontal Separator
};
//creation methods
DECLARE_CONOBJECT(GuiSeparatorCtrl);
DECLARE_CATEGORY( "Gui Other" );
DECLARE_DESCRIPTION( "A control that renders a horizontal or vertical separator with\n"
"an optional text label (horizontal only). ");
GuiSeparatorCtrl();
static void initPersistFields();
void onRender(Point2I offset, const RectI &updateRect);
};
typedef GuiSeparatorCtrl::separatorTypeOptions GuiSeparatorType;
DefineEnumType( GuiSeparatorType );
#endif

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,262 @@
//-----------------------------------------------------------------------------
// Copyright (c) 2012 GarageGames, LLC
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//-----------------------------------------------------------------------------
#ifndef _GUISHAPEEDPREVIEW_H_
#define _GUISHAPEEDPREVIEW_H_
#include "gui/worldEditor/editTSCtrl.h"
#include "ts/tsShapeInstance.h"
class LightInfo;
class GuiShapeEdPreview : public EditTSCtrl
{
struct Thread
{
TSThread* key; //!< TSThread key
String seqName; //!< Name of the sequence for this thread
S32 direction; //!< Playback direction: -1 (reverse), 0 (paused), 1 (forward)
bool pingpong; //!< Pingpong flag (auto-reverse direction at start/end)
Thread()
{
init();
}
void init()
{
key = NULL;
direction = 1.0f;
pingpong = false;
}
};
struct MountedShape
{
enum eMountType
{
Object, //!< Mount origin of shape to target node
Image, //!< Mount 'mountPoint' or origin of shape to target node
Wheel, //!< Mount origin of shape to target node, ignore target node rotation
};
TSShapeInstance* mShape; //!< The mounted shape instance
S32 mNode; //!< Index of the node this shape is mounted to
MatrixF mTransform; //!< Mount offset transform
eMountType mType; //!< Type of mount
Thread mThread; //!< Animation thread for the mounted shape
MountedShape() : mShape(0), mNode(-1), mTransform(true), mType(Object) { }
~MountedShape() { delete mShape; }
};
protected:
typedef EditTSCtrl Parent;
// View and node selection
bool mUsingAxisGizmo;
bool mEditingSun; //!< True if editing the sun direction, false otherwise
S32 mGizmoDragID; //!< Used to track transform changes within a single gizmo drag action
S32 mSelectedNode; //!< Index of the selected node
S32 mHoverNode; //!< Index of the node the mouse is over
Vector<Point3F> mProjectedNodes; //!< Projected screen positions of the model nodes
S32 mSelectedObject; //!< Name of the selected object
S32 mSelectedObjDetail; //!< Detail mesh index of the selected object
// Camera
EulerF mCameraRot;
bool mRenderCameraAxes;
Point3F mOrbitPos;
F32 mOrbitDist;
F32 mMoveSpeed;
F32 mZoomSpeed;
// Current Detail
bool mFixedDetail; //!< If false, the detail level will be determined based on camera distance
S32 mCurrentDL; //!< Current detail level
S32 mDetailSize; //!< Size of current detail level
S32 mDetailPolys; //!< Number of polys (triangles) in current detail level
F32 mPixelSize; //!< Current pixel size
S32 mNumMaterials; //!< Number of materials in the current detail level
S32 mNumDrawCalls; //!< Number of draw calls in the current detail level
S32 mNumBones; //!< Number of bones in the current detail level (skins only)
S32 mNumWeights; //!< Number of vertex weights in the current detail level (skins only)
S32 mColMeshes; //!< Number of collision meshes
S32 mColPolys; //!< Number of collision polygons (all meshes)
// Rendering
Point2I mGridDimension; //!< Dimension of grid in perspective view (eg. 30x30)
bool mRenderGhost;
bool mRenderNodes;
bool mRenderBounds;
bool mRenderObjBox;
bool mRenderColMeshes;
bool mRenderMounts;
TSShapeInstance* mModel;
LightInfo* mFakeSun;
EulerF mSunRot;
ColorI mSunDiffuseColor;
ColorI mSunAmbientColor;
// Animation and playback control
Vector<Thread> mThreads;
F32 mTimeScale;
S32 mActiveThread;
S32 mLastRenderTime;
// Mounted objects
Vector<MountedShape*> mMounts;
static bool setFieldCurrentDL( void *object, const char *index, const char *data );
static bool setFieldSunDiffuse( void *object, const char *index, const char *data );
static bool setFieldSunAmbient( void *object, const char *index, const char *data );
static bool setFieldSunAngleX( void *object, const char *index, const char *data );
static bool setFieldSunAngleZ( void *object, const char *index, const char *data );
static bool setFieldThreadPos( void *object, const char *index, const char *data );
static bool setFieldThreadIn( void *object, const char *index, const char *data );
static bool setFieldThreadOut( void *object, const char *index, const char *data );
static bool setFieldThreadDir( void *object, const char *index, const char *data );
static bool setFieldThreadPingPong( void *object, const char *index, const char *data );
static const char *getFieldThreadPos( void *object, const char *data );
static const char *getFieldThreadIn( void *object, const char *data );
static const char *getFieldThreadOut( void *object, const char *data );
static const char *getFieldThreadDir( void *object, const char *data );
static const char *getFieldThreadPingPong( void *object, const char *data );
// Generic mouse event handlers
void handleMouseDown(const GuiEvent& event, GizmoMode mode);
void handleMouseUp(const GuiEvent& event, GizmoMode mode);
void handleMouseMove(const GuiEvent& event, GizmoMode mode);
void handleMouseDragged(const GuiEvent& event, GizmoMode mode);
// Node picking
S32 collideNode(const Gui3DMouseEvent& event) const;
void updateProjectedNodePoints();
void updateSun();
void updateDetailLevel(const SceneRenderState* state);
void updateThreads(F32 delta);
// Rendering
void renderGrid();
void renderNodes() const;
void renderNodeAxes(S32 index, const ColorF& nodeColor) const;
void renderNodeName(S32 index, const ColorF& textColor) const;
void renderSunDirection() const;
void renderCollisionMeshes() const;
public:
bool onWake();
void setDisplayType(S32 type);
/// @name Mouse event handlers
///@{
void onMouseDown(const GuiEvent& event) { handleMouseDown(event, NoneMode); }
void onMouseUp(const GuiEvent& event) { handleMouseUp(event, NoneMode); }
void onMouseMove(const GuiEvent& event) { handleMouseMove(event, NoneMode); }
void onMouseDragged(const GuiEvent& event) { handleMouseDragged(event, NoneMode); }
void onMiddleMouseDown(const GuiEvent& event) { handleMouseDown(event, MoveMode); }
void onMiddleMouseUp(const GuiEvent& event) { handleMouseUp(event, MoveMode); }
void onMiddleMouseDragged(const GuiEvent& event) { handleMouseDragged(event, MoveMode); }
void onRightMouseDown(const GuiEvent& event) { handleMouseDown(event, RotateMode); }
void onRightMouseUp(const GuiEvent& event) { handleMouseUp(event, RotateMode); }
void onRightMouseDragged(const GuiEvent& event) { handleMouseDragged(event, RotateMode); }
void on3DMouseWheelUp(const Gui3DMouseEvent& event);
void on3DMouseWheelDown(const Gui3DMouseEvent& event);
///@}
// Setters/Getters
TSShapeInstance* getModel() { return mModel; }
void setCurrentDetail(S32 dl);
bool setObjectModel(const char * modelName);
/// @name Threads
///@{
void addThread();
void removeThread(S32 slot);
S32 getThreadCount() const { return mThreads.size(); }
void setTimeScale(F32 scale);
void setActiveThreadSequence(const char* seqName, F32 duration, F32 pos, bool play);
void setThreadSequence(Thread& thread, TSShapeInstance* shape, const char * seqName, F32 duration=0.0f, F32 pos=0.0f, bool play=false);
const char* getThreadSequence() const;
void refreshThreadSequences();
DECLARE_CALLBACK( void, onThreadPosChanged, ( F32 pos, bool inTransition ) );
///@}
/// @name Mounting
///@{
bool mountShape(const char* modelName, const char* nodeName, const char* mountType, S32 slot=-1);
void setMountNode(S32 mountSlot, const char* nodeName);
const char* getMountThreadSequence(S32 mountSlot) const;
void setMountThreadSequence(S32 mountSlot, const char* seqName);
F32 getMountThreadPos(S32 mountSlot) const;
void setMountThreadPos(S32 mountSlot, F32 pos);
F32 getMountThreadDir(S32 mountSlot) const;
void setMountThreadDir(S32 mountSlot, F32 dir);
void unmountShape(S32 mountSlot);
void unmountAll();
///@}
void refreshShape();
void updateNodeTransforms();
void get3DCursor(GuiCursor *& cursor, bool& visible, const Gui3DMouseEvent& event_);
void fitToShape();
void setOrbitPos( const Point3F& pos );
void exportToCollada( const String& path );
/// @name Rendering
///@{
bool getCameraTransform(MatrixF* cameraMatrix);
void computeSceneBounds(Box3F& bounds);
bool getMeshHidden(const char* name) const;
void setMeshHidden(const char* name, bool hidden);
void setAllMeshesHidden(bool hidden);
void renderWorld(const RectI& updateRect);
void renderGui(Point2I offset, const RectI& updateRect);
///@}
DECLARE_CONOBJECT(GuiShapeEdPreview);
DECLARE_CATEGORY( "Gui Editor" );
static void initPersistFields();
GuiShapeEdPreview();
~GuiShapeEdPreview();
};
#endif

View file

@ -0,0 +1,129 @@
//-----------------------------------------------------------------------------
// Copyright (c) 2012 GarageGames, LLC
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//-----------------------------------------------------------------------------
#include "gui/editor/inspector/customField.h"
#include "gui/editor/guiInspector.h"
//-----------------------------------------------------------------------------
// GuiInspectorCustomField - Child class of GuiInspectorField
//-----------------------------------------------------------------------------
IMPLEMENT_CONOBJECT( GuiInspectorCustomField );
ConsoleDocClass( GuiInspectorCustomField,
"@brief A control that allows to edit the custom properties (text) of one or more SimObjects.\n\n"
"Editor use only.\n\n"
"@internal"
);
GuiInspectorCustomField::GuiInspectorCustomField( GuiInspector *inspector,
GuiInspectorGroup* parent,
SimFieldDictionary::Entry* field )
{
mInspector = inspector;
mParent = parent;
setBounds(0,0,100,20);
}
GuiInspectorCustomField::GuiInspectorCustomField()
{
mInspector = NULL;
mParent = NULL;
}
void GuiInspectorCustomField::setData( const char* data, bool callbacks )
{
mCustomValue = data;
// Force our edit to update
updateValue();
}
const char* GuiInspectorCustomField::getData( U32 inspectObjectIndex )
{
return mCustomValue;
}
void GuiInspectorCustomField::updateValue()
{
setValue( mCustomValue );
}
void GuiInspectorCustomField::setDoc( const char* doc )
{
mDoc = StringTable->insert( doc, true );
}
void GuiInspectorCustomField::setToolTip( StringTableEntry data )
{
static StringTableEntry sTooltipProfile = StringTable->insert( "tooltipProfile" );
static StringTableEntry sHoverTime = StringTable->insert( "hovertime" );
static StringTableEntry sTooltip = StringTable->insert( "tooltip" );
mEdit->setDataField( sTooltipProfile, NULL, "GuiToolTipProfile" );
mEdit->setDataField( sHoverTime, NULL, "1000" );
mEdit->setDataField( sTooltip, NULL, data );
}
bool GuiInspectorCustomField::onAdd()
{
if( !Parent::onAdd() )
return false;
return true;
}
void GuiInspectorCustomField::setInspectorField( AbstractClassRep::Field *field,
StringTableEntry caption,
const char*arrayIndex )
{
// Override the base just to be sure it doesn't get called.
// We don't use an AbstractClassRep::Field...
// mField = field;
// mCaption = StringTable->EmptyString();
// mRenameCtrl->setText( getFieldName() );
}
GuiControl* GuiInspectorCustomField::constructEditControl()
{
GuiControl* retCtrl = new GuiTextCtrl();
static StringTableEntry sProfile = StringTable->insert( "profile" );
retCtrl->setDataField( sProfile, NULL, "GuiInspectorTextEditProfile" );
// Register the object
retCtrl->registerObject();
return retCtrl;
}
void GuiInspectorCustomField::setValue( const char* newValue )
{
GuiTextCtrl *ctrl = dynamic_cast<GuiTextCtrl*>( mEdit );
if( ctrl != NULL )
ctrl->setText( newValue );
}
void GuiInspectorCustomField::_executeSelectedCallback()
{
Con::executef( mInspector, "onFieldSelected", mCaption, ConsoleBaseType::getType(TypeCaseString)->getTypeName(), mDoc );
}

View file

@ -0,0 +1,69 @@
//-----------------------------------------------------------------------------
// Copyright (c) 2012 GarageGames, LLC
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//-----------------------------------------------------------------------------
#ifndef _GUI_INSPECTOR_CUSTOMFIELD_H_
#define _GUI_INSPECTOR_CUSTOMFIELD_H_
#include "console/simFieldDictionary.h"
#include "gui/editor/inspector/field.h"
class GuiInspectorCustomField : public GuiInspectorField
{
typedef GuiInspectorField Parent;
public:
GuiInspectorCustomField( GuiInspector *inspector, GuiInspectorGroup* parent, SimFieldDictionary::Entry* field );
GuiInspectorCustomField();
~GuiInspectorCustomField() {};
DECLARE_CONOBJECT( GuiInspectorCustomField );
virtual void setData( const char* data, bool callbacks = true );
virtual const char* getData( U32 inspectObjectIndex = 0 );
virtual void updateValue();
virtual StringTableEntry getFieldName() { return StringTable->EmptyString(); }
virtual void setDoc( const char* doc );
virtual void setToolTip( StringTableEntry data );
virtual bool onAdd();
virtual void setInspectorField( AbstractClassRep::Field *field,
StringTableEntry caption = NULL,
const char *arrayIndex = NULL );
virtual GuiControl* constructEditControl();
virtual void setValue( const char* newValue );
protected:
virtual void _executeSelectedCallback();
protected:
String mCustomValue;
StringTableEntry mDoc;
};
#endif // _GUI_INSPECTOR_DYNAMICFIELD_H_

View file

@ -0,0 +1,165 @@
//-----------------------------------------------------------------------------
// Copyright (c) 2012 GarageGames, LLC
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//-----------------------------------------------------------------------------
#include "console/simBase.h"
#include "console/simDatablock.h"
#include "gui/editor/guiInspector.h"
#include "gui/editor/inspector/datablockField.h"
#include "gui/editor/inspector/group.h"
#include "gui/buttons/guiIconButtonCtrl.h"
#include "gui/editor/inspector/datablockField.h"
#include "sfx/sfxTypes.h"
#include "sfx/sfxDescription.h"
#include "sfx/sfxEnvironment.h"
#include "sfx/sfxAmbience.h"
#include "sfx/sfxTrack.h"
//-----------------------------------------------------------------------------
// GuiInspectorDatablockField
// Field construction for datablock types
//-----------------------------------------------------------------------------
IMPLEMENT_CONOBJECT(GuiInspectorDatablockField);
ConsoleDocClass( GuiInspectorDatablockField,
"@brief Custom field type for datablock enumeration.\n\n"
"Editor use only.\n\n"
"@internal"
);
GuiInspectorDatablockField::GuiInspectorDatablockField( StringTableEntry className )
{
setClassName( className );
}
void GuiInspectorDatablockField::setClassName( StringTableEntry className )
{
if( !className || !className[ 0 ] )
mDesiredClass = NULL;
else
{
mDesiredClass = AbstractClassRep::findClassRep( className );
if( !mDesiredClass )
Con::errorf( "GuiInspectorDatablockField::setClassName - no class '%s' found!", className );
}
}
void GuiInspectorDatablockField::_populateMenu( GuiPopUpMenuCtrl* menu )
{
menu->addScheme( 1, ColorI( 80, 0, 0, 255 ), ColorI( 80, 0, 0, 255 ), ColorI( 80, 0, 0, 255 ) ); // For client-only coloring.
menu->addEntry( "", 0 ); // For unsetting.
SimSet* set = _getDatablockSet();
U32 id = 1;
for( SimSet::iterator iter = set->begin(); iter != set->end(); ++ iter )
{
SimDataBlock* datablock = dynamic_cast< SimDataBlock* >( *iter );
// Skip non-datablocks if we somehow encounter them.
if( !datablock )
continue;
// Ok, now we have to figure inheritance info.
if( datablock && ( !mDesiredClass || datablock->getClassRep()->isClass( mDesiredClass ) ) )
menu->addEntry( datablock->getName(), id ++, datablock->isClientOnly() ? 1 : 0 );
}
menu->sort();
}
//-----------------------------------------------------------------------------
// GuiInspectorTypeSFXDescriptionName
//-----------------------------------------------------------------------------
IMPLEMENT_CONOBJECT(GuiInspectorTypeSFXDescriptionName);
ConsoleDocClass( GuiInspectorTypeSFXDescriptionName,
"@brief Inspector field type for SFXDescriptionName\n\n"
"Editor use only.\n\n"
"@internal"
);
void GuiInspectorTypeSFXDescriptionName::consoleInit()
{
Parent::consoleInit();
ConsoleBaseType::getType( TypeSFXDescriptionName )->setInspectorFieldType( "GuiInspectorTypeSFXDescriptionName" );
}
//-----------------------------------------------------------------------------
// GuiInspectorTypeSFXTrackName
//-----------------------------------------------------------------------------
IMPLEMENT_CONOBJECT(GuiInspectorTypeSFXTrackName);
ConsoleDocClass( GuiInspectorTypeSFXTrackName,
"@brief Inspector field type for SFXTrackName\n\n"
"Editor use only.\n\n"
"@internal"
);
void GuiInspectorTypeSFXTrackName::consoleInit()
{
Parent::consoleInit();
ConsoleBaseType::getType( TypeSFXTrackName )->setInspectorFieldType( "GuiInspectorTypeSFXTrackName" );
}
//-----------------------------------------------------------------------------
// GuiInspectorTypeSFXEnvironmentName
//-----------------------------------------------------------------------------
IMPLEMENT_CONOBJECT(GuiInspectorTypeSFXEnvironmentName);
ConsoleDocClass( GuiInspectorTypeSFXEnvironmentName,
"@brief Inspector field type for SFXEnvironment\n\n"
"Editor use only.\n\n"
"@internal"
);
void GuiInspectorTypeSFXEnvironmentName::consoleInit()
{
Parent::consoleInit();
ConsoleBaseType::getType( TypeSFXEnvironmentName )->setInspectorFieldType( "GuiInspectorTypeSFXEnvironmentName" );
}
//-----------------------------------------------------------------------------
// GuiInspectorTypeSFXAmbienceName
//-----------------------------------------------------------------------------
IMPLEMENT_CONOBJECT(GuiInspectorTypeSFXAmbienceName);
ConsoleDocClass( GuiInspectorTypeSFXAmbienceName,
"@brief Inspector field type for SFXAmbience\n\n"
"Editor use only.\n\n"
"@internal"
);
void GuiInspectorTypeSFXAmbienceName::consoleInit()
{
Parent::consoleInit();
ConsoleBaseType::getType( TypeSFXAmbienceName )->setInspectorFieldType( "GuiInspectorTypeSFXAmbienceName" );
}

View file

@ -0,0 +1,134 @@
//-----------------------------------------------------------------------------
// Copyright (c) 2012 GarageGames, LLC
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//-----------------------------------------------------------------------------
#ifndef _GUI_INSPECTOR_DATABLOCKFIELD_H_
#define _GUI_INSPECTOR_DATABLOCKFIELD_H_
#include "gui/editor/guiInspectorTypes.h"
//-----------------------------------------------------------------------------
// GuiInspectorDatablockField - custom field type for datablock enumeration
//-----------------------------------------------------------------------------
class GuiInspectorDatablockField : public GuiInspectorTypeMenuBase
{
public:
typedef GuiInspectorTypeMenuBase Parent;
protected:
AbstractClassRep *mDesiredClass;
virtual SimSet* _getDatablockSet() const { return Sim::getDataBlockGroup(); }
virtual void _populateMenu( GuiPopUpMenuCtrl* menu );
public:
DECLARE_CONOBJECT(GuiInspectorDatablockField);
GuiInspectorDatablockField( StringTableEntry className );
GuiInspectorDatablockField() { mDesiredClass = NULL; };
void setClassName( StringTableEntry className );
};
//-----------------------------------------------------------------------------
// TypeSFXDescriptionName GuiInspectorField Class
//-----------------------------------------------------------------------------
class GuiInspectorTypeSFXDescriptionName : public GuiInspectorDatablockField
{
public:
typedef GuiInspectorDatablockField Parent;
protected:
virtual SimSet* _getDatablockSet() const { return Sim::getSFXDescriptionSet(); }
public:
DECLARE_CONOBJECT(GuiInspectorTypeSFXDescriptionName);
static void consoleInit();
};
//-----------------------------------------------------------------------------
// TypeSFXTrackName GuiInspectorField Class
//-----------------------------------------------------------------------------
class GuiInspectorTypeSFXTrackName : public GuiInspectorDatablockField
{
public:
typedef GuiInspectorDatablockField Parent;
protected:
virtual SimSet* _getDatablockSet() const { return Sim::getSFXTrackSet(); }
public:
DECLARE_CONOBJECT(GuiInspectorTypeSFXTrackName);
static void consoleInit();
};
//-----------------------------------------------------------------------------
// TypeSFXEnvironmentName GuiInspectorField Class
//-----------------------------------------------------------------------------
class GuiInspectorTypeSFXEnvironmentName : public GuiInspectorDatablockField
{
public:
typedef GuiInspectorDatablockField Parent;
protected:
virtual SimSet* _getDatablockSet() const { return Sim::getSFXEnvironmentSet(); }
public:
DECLARE_CONOBJECT(GuiInspectorTypeSFXEnvironmentName);
static void consoleInit();
};
//-----------------------------------------------------------------------------
// TypeSFXAmbienceName GuiInspectorField Class
//-----------------------------------------------------------------------------
class GuiInspectorTypeSFXAmbienceName : public GuiInspectorDatablockField
{
public:
typedef GuiInspectorDatablockField Parent;
protected:
virtual SimSet* _getDatablockSet() const { return Sim::getSFXAmbienceSet(); }
public:
DECLARE_CONOBJECT(GuiInspectorTypeSFXAmbienceName);
static void consoleInit();
};
#endif

View file

@ -0,0 +1,321 @@
//-----------------------------------------------------------------------------
// Copyright (c) 2012 GarageGames, LLC
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//-----------------------------------------------------------------------------
#include "gui/editor/inspector/dynamicField.h"
#include "gui/editor/inspector/dynamicGroup.h"
#include "gui/editor/guiInspector.h"
#include "gui/buttons/guiIconButtonCtrl.h"
//-----------------------------------------------------------------------------
// GuiInspectorDynamicField - Child class of GuiInspectorField
//-----------------------------------------------------------------------------
IMPLEMENT_CONOBJECT( GuiInspectorDynamicField );
ConsoleDocClass( GuiInspectorDynamicField,
"@brief Custom field type for dynamic variable modification on SimObjects.\n\n"
"Editor use only.\n\n"
"@internal"
);
GuiInspectorDynamicField::GuiInspectorDynamicField( GuiInspector *inspector,
GuiInspectorGroup* parent,
SimFieldDictionary::Entry* field )
: mRenameCtrl( NULL ),
mDeleteButton( NULL )
{
mInspector = inspector;
mParent = parent;
mDynField = field;
setBounds(0,0,100,20);
}
void GuiInspectorDynamicField::setData( const char* data, bool callbacks )
{
if ( mDynField == NULL )
return;
const U32 numTargets = mInspector->getNumInspectObjects();
if( callbacks && numTargets > 1 )
Con::executef( mInspector, "beginCompoundUndo" );
// Setting an empty string will kill the field.
const bool isRemoval = !data[ 0 ];
for( U32 i = 0; i < numTargets; ++ i )
{
SimObject* target = mInspector->getInspectObject( i );
// Callback on the inspector when the field is modified
// to allow creation of undo/redo actions.
const char *oldData = target->getDataField( mDynField->slotName, NULL );
if ( !oldData )
oldData = "";
if ( dStrcmp( oldData, data ) != 0 )
{
target->inspectPreApply();
if( callbacks )
{
if( isRemoval )
Con::executef( mInspector, "onFieldRemoved", target->getIdString(), mDynField->slotName );
else
Con::executef( mInspector, "onInspectorFieldModified", target->getIdString(), mDynField->slotName, oldData, data );
}
target->setDataField( mDynField->slotName, NULL, data );
// give the target a chance to validate
target->inspectPostApply();
}
}
if( callbacks && numTargets > 1 )
Con::executef( mInspector, "endCompoundUndo" );
// Force our edit to update
updateValue();
}
const char* GuiInspectorDynamicField::getData( U32 inspectObjectIndex )
{
if( mDynField == NULL )
return "";
return mInspector->getInspectObject( inspectObjectIndex )->getDataField( mDynField->slotName, NULL );
}
void GuiInspectorDynamicField::renameField( const char* newFieldName )
{
newFieldName = StringTable->insert( newFieldName );
if ( mDynField == NULL || mParent == NULL || mEdit == NULL )
{
Con::warnf("GuiInspectorDynamicField::renameField - No target object or dynamic field data found!" );
return;
}
if ( !newFieldName )
{
Con::warnf("GuiInspectorDynamicField::renameField - Invalid field name specified!" );
return;
}
// Only proceed if the name has changed
if ( dStricmp( newFieldName, getFieldName() ) == 0 )
return;
// Grab a pointer to our parent and cast it to GuiInspectorDynamicGroup
GuiInspectorDynamicGroup *group = dynamic_cast<GuiInspectorDynamicGroup*>(mParent);
if ( group == NULL )
{
Con::warnf("GuiInspectorDynamicField::renameField - Unable to locate GuiInspectorDynamicGroup parent!" );
return;
}
const U32 numTargets = mInspector->getNumInspectObjects();
if( numTargets > 1 )
Con::executef( mInspector, "onBeginCompoundEdit" );
const char* oldFieldName = getFieldName();
SimFieldDictionary::Entry* newEntry = NULL;
for( U32 i = 0; i < numTargets; ++ i )
{
SimObject* target = mInspector->getInspectObject( i );
// Make sure the new field is not already defined as a static field
// on the object.
if( target->isField( newFieldName ) )
{
// New field is already defined. If we can, let the scripts handle
// the error. Otherwise, just emit an error on the console and proceed.
if( numTargets == 1 && mInspector->isMethod( "onFieldRenameAlreadyDefined" ) )
Con::executef( mInspector, "onFieldRenameAlreadyDefined", target->getIdString(), oldFieldName, newFieldName );
else
Con::errorf( "GuiInspectorDynamicField::renameField - field '%s' is already defined on %i:%s (%s)",
newFieldName, target->getId(), target->getClassName(), target->getName() );
// Reset the text entry.
if( mRenameCtrl )
mRenameCtrl->setText( oldFieldName );
continue;
}
char currentValue[1024] = {0};
// Grab our current dynamic field value (we use a temporary buffer as this gets corrupted upon Con::eval)
dSprintf( currentValue, sizeof( currentValue ), "%s", target->getDataField( oldFieldName, NULL ) );
// Unset the old field and set the new field.
target->setDataField( oldFieldName, NULL, "" );
target->setDataField( newFieldName, NULL, currentValue );
// Notify script.
Con::executef( mInspector, "onFieldRenamed", target->getIdString(), oldFieldName, newFieldName );
// Look up the new SimFieldDictionary entry.
if( !newEntry )
{
newEntry = target->getFieldDictionary()->findDynamicField( newFieldName );
if( !newEntry )
{
Con::warnf( "GuiInspectorDynamicField::renameField - could not find new field '%s' on object %i:%s (%s)",
newFieldName, target->getId(), target->getClassName(), target->getName() );
}
mDynField = newEntry;
}
}
if( numTargets > 1 )
Con::executef( mInspector, "onEndCompoundEdit" );
// Lastly we need to reassign our validate field for our value edit control
char szBuffer[1024];
dSprintf( szBuffer, sizeof( szBuffer ), "%d.apply(%d.getText());", getId(), mEdit->getId() );
mEdit->setField("validate", szBuffer );
if( mDeleteButton )
{
dSprintf(szBuffer, sizeof( szBuffer ), "%d.apply("");%d.inspectGroup();", getId(), newFieldName, group->getId());
mDeleteButton->setField("Command", szBuffer);
}
}
bool GuiInspectorDynamicField::onAdd()
{
if( !Parent::onAdd() )
return false;
//pushObjectToBack(mEdit);
// Create our renaming field
mRenameCtrl = new GuiTextEditCtrl();
mRenameCtrl->setDataField( StringTable->insert("profile"), NULL, "GuiInspectorDynamicFieldProfile" );
char szName[512];
dSprintf( szName, 512, "IE_%s_%d_%s_Rename", mRenameCtrl->getClassName(), mInspector->getInspectObject()->getId(), getFieldName() );
mRenameCtrl->registerObject( szName );
// Our command will evaluate to :
//
// if( (editCtrl).getText() !$= "" )
// (field).renameField((editCtrl).getText());
//
char szBuffer[1024];
dSprintf( szBuffer, sizeof( szBuffer ), "if( %d.getText() !$= \"\" ) %d.renameField(%d.getText());", mRenameCtrl->getId(), getId(), mRenameCtrl->getId() );
mRenameCtrl->setText( getFieldName() );
mRenameCtrl->setField("Validate", szBuffer );
addObject( mRenameCtrl );
// Resize the name control to fit in our caption rect
mRenameCtrl->resize( mCaptionRect.point, mCaptionRect.extent );
// Resize the value control to leave space for the delete button
mEdit->resize( mValueRect.point, mValueRect.extent);
// Clear out any caption set from Parent::onAdd
// since we are rendering the fieldname with our 'rename' control.
mCaption = StringTable->insert( "" );
// Create delete button control
mDeleteButton = new GuiBitmapButtonCtrl();
SimObject* profilePtr = Sim::findObject("InspectorDynamicFieldButton");
if( profilePtr != NULL )
mDeleteButton->setControlProfile( dynamic_cast<GuiControlProfile*>(profilePtr) );
dSprintf( szBuffer, sizeof( szBuffer ),
"%d.apply(\"\");%d.schedule(1,\"inspectGroup\");",
getId(),
mParent->getId() );
// FIXME Hardcoded image
mDeleteButton->setField( "Bitmap", "tools/gui/images/iconDelete" );
mDeleteButton->setField( "Text", "X" );
mDeleteButton->setField( "Command", szBuffer );
mDeleteButton->setSizing( horizResizeLeft, vertResizeCenter );
mDeleteButton->resize(Point2I(getWidth() - 20,2), Point2I(16, 16));
mDeleteButton->registerObject();
addObject(mDeleteButton);
return true;
}
bool GuiInspectorDynamicField::updateRects()
{
Point2I fieldExtent = getExtent();
S32 dividerPos, dividerMargin;
mInspector->getDivider( dividerPos, dividerMargin );
S32 editWidth = dividerPos - dividerMargin;
mEditCtrlRect.set( fieldExtent.x - dividerPos + dividerMargin, 1, editWidth, fieldExtent.y - 1 );
mCaptionRect.set( 0, 0, fieldExtent.x - dividerPos - dividerMargin, fieldExtent.y );
mValueRect.set( mEditCtrlRect.point, mEditCtrlRect.extent - Point2I( 20, 0 ) );
mDeleteRect.set( fieldExtent.x - 20, 2, 16, fieldExtent.y - 4 );
// This is probably being called during Parent::onAdd
// so our special controls haven't been created yet but are just about to
// so we just need to calculate the extents.
if ( mRenameCtrl == NULL )
return false;
bool sized0 = mRenameCtrl->resize( mCaptionRect.point, mCaptionRect.extent );
bool sized1 = mEdit->resize( mValueRect.point, mValueRect.extent );
bool sized2 = mDeleteButton->resize(Point2I(getWidth() - 20,2), Point2I(16, 16));
return ( sized0 || sized1 || sized2 );
}
void GuiInspectorDynamicField::setInspectorField( AbstractClassRep::Field *field,
StringTableEntry caption,
const char*arrayIndex )
{
// Override the base just to be sure it doesn't get called.
// We don't use an AbstractClassRep::Field...
// mField = field;
// mCaption = StringTable->EmptyString();
// mRenameCtrl->setText( getFieldName() );
}
void GuiInspectorDynamicField::_executeSelectedCallback()
{
ConsoleBaseType* type = mDynField->type;
if ( type )
Con::executef( mInspector, "onFieldSelected", mDynField->slotName, type->getTypeName() );
else
Con::executef( mInspector, "onFieldSelected", mDynField->slotName, "TypeDynamicField" );
}
ConsoleMethod( GuiInspectorDynamicField, renameField, void, 3,3, "field.renameField(newDynamicFieldName);" )
{
object->renameField( argv[ 2 ] );
}

View file

@ -0,0 +1,72 @@
//-----------------------------------------------------------------------------
// Copyright (c) 2012 GarageGames, LLC
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//-----------------------------------------------------------------------------
#ifndef _GUI_INSPECTOR_DYNAMICFIELD_H_
#define _GUI_INSPECTOR_DYNAMICFIELD_H_
#include "console/simFieldDictionary.h"
#include "gui/editor/inspector/field.h"
class GuiInspectorDynamicField : public GuiInspectorField
{
typedef GuiInspectorField Parent;
public:
GuiInspectorDynamicField( GuiInspector *inspector, GuiInspectorGroup* parent, SimFieldDictionary::Entry* field );
GuiInspectorDynamicField() {};
~GuiInspectorDynamicField() {};
DECLARE_CONOBJECT( GuiInspectorDynamicField );
virtual void setData( const char* data, bool callbacks = true );
virtual const char* getData( U32 inspectObjectIndex = 0 );
virtual StringTableEntry getFieldName() { return ( mDynField != NULL ) ? mDynField->slotName : StringTable->insert( "" ); }
virtual StringTableEntry getRawFieldName() { return getFieldName(); }
virtual bool onAdd();
void renameField( const char* newFieldName );
GuiControl* constructRenameControl();
virtual bool updateRects();
virtual void setInspectorField( AbstractClassRep::Field *field,
StringTableEntry caption = NULL,
const char *arrayIndex = NULL );
protected:
virtual void _executeSelectedCallback();
protected:
/// Dynamic field dictionary entry for first target object only.
SimFieldDictionary::Entry* mDynField;
SimObjectPtr<GuiTextEditCtrl> mRenameCtrl;
GuiBitmapButtonCtrl* mDeleteButton;
RectI mDeleteRect;
RectI mValueRect;
};
#endif // _GUI_INSPECTOR_DYNAMICFIELD_H_

View file

@ -0,0 +1,258 @@
//-----------------------------------------------------------------------------
// Copyright (c) 2012 GarageGames, LLC
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//-----------------------------------------------------------------------------
#include "gui/buttons/guiIconButtonCtrl.h"
#include "gui/editor/guiInspector.h"
#include "gui/editor/inspector/dynamicGroup.h"
#include "gui/editor/inspector/dynamicField.h"
IMPLEMENT_CONOBJECT(GuiInspectorDynamicGroup);
ConsoleDocClass( GuiInspectorDynamicGroup,
"@brief Used to inspect an object's FieldDictionary (dynamic fields) instead "
"of regular persistent fields.\n\n"
"Editor use only.\n\n"
"@internal"
);
//-----------------------------------------------------------------------------
// GuiInspectorDynamicGroup - add custom controls
//-----------------------------------------------------------------------------
bool GuiInspectorDynamicGroup::createContent()
{
if(!Parent::createContent())
return false;
// encapsulate the button in a dummy control.
GuiControl* shell = new GuiControl();
shell->setDataField( StringTable->insert("profile"), NULL, "GuiTransparentProfile" );
if( !shell->registerObject() )
{
delete shell;
return false;
}
// add a button that lets us add new dynamic fields.
GuiBitmapButtonCtrl* addFieldBtn = new GuiBitmapButtonCtrl();
{
SimObject* profilePtr = Sim::findObject("InspectorDynamicFieldButton");
if( profilePtr != NULL )
addFieldBtn->setControlProfile( dynamic_cast<GuiControlProfile*>(profilePtr) );
// FIXME Hardcoded image
addFieldBtn->setBitmap("tools/gui/images/iconAdd.png");
char commandBuf[64];
dSprintf(commandBuf, 64, "%d.addDynamicField();", this->getId());
addFieldBtn->setField("command", commandBuf);
addFieldBtn->setSizing(horizResizeLeft,vertResizeCenter);
//addFieldBtn->setField("buttonMargin", "2 2");
addFieldBtn->resize(Point2I(getWidth() - 20,2), Point2I(16, 16));
addFieldBtn->registerObject("zAddButton");
}
shell->resize(Point2I(0,0), Point2I(getWidth(), 28));
shell->addObject(addFieldBtn);
// save off the shell control, so we can push it to the bottom of the stack in inspectGroup()
mAddCtrl = shell;
mStack->addObject(shell);
return true;
}
struct FieldEntry
{
SimFieldDictionary::Entry* mEntry;
U32 mNumTargets;
};
static S32 QSORT_CALLBACK compareEntries(const void* a,const void* b)
{
FieldEntry& fa = *((FieldEntry *)a);
FieldEntry& fb = *((FieldEntry *)b);
return dStrnatcmp(fa.mEntry->slotName, fb.mEntry->slotName);
}
//-----------------------------------------------------------------------------
// GuiInspectorDynamicGroup - inspectGroup override
//-----------------------------------------------------------------------------
bool GuiInspectorDynamicGroup::inspectGroup()
{
// clear the first responder if it's set
mStack->clearFirstResponder();
// Clearing the fields and recreating them will more than likely be more
// efficient than looking up existent fields, updating them, and then iterating
// over existent fields and making sure they still exist, if not, deleting them.
clearFields();
// Create a vector of the fields
Vector< FieldEntry > flist;
const U32 numTargets = mParent->getNumInspectObjects();
for( U32 i = 0; i < numTargets; ++ i )
{
SimObject* target = mParent->getInspectObject( i );
// Then populate with fields
SimFieldDictionary * fieldDictionary = target->getFieldDictionary();
for(SimFieldDictionaryIterator ditr(fieldDictionary); *ditr; ++ditr)
{
if( i == 0 )
{
flist.increment();
flist.last().mEntry = *ditr;
flist.last().mNumTargets = 1;
}
else
{
const U32 numFields = flist.size();
for( U32 n = 0; n < numFields; ++ n )
if( flist[ n ].mEntry->slotName == ( *ditr )->slotName )
{
flist[ n ].mNumTargets ++;
break;
}
}
}
}
dQsort( flist.address(), flist.size(), sizeof( FieldEntry ), compareEntries );
for(U32 i = 0; i < flist.size(); i++)
{
if( flist[ i ].mNumTargets != numTargets )
continue;
SimFieldDictionary::Entry* entry = flist[i].mEntry;
// Create a dynamic field inspector. Can't reuse typed GuiInspectorFields as
// these rely on AbstractClassRep::Fields.
GuiInspectorDynamicField *field = new GuiInspectorDynamicField( mParent, this, entry );
// Register the inspector field and add it to our lists
if( field->registerObject() )
{
mChildren.push_back( field );
mStack->addObject( field );
}
else
delete field;
}
mStack->pushObjectToBack(mAddCtrl);
setUpdate();
return true;
}
void GuiInspectorDynamicGroup::updateAllFields()
{
// We overload this to just reinspect the group.
inspectGroup();
}
ConsoleMethod(GuiInspectorDynamicGroup, inspectGroup, bool, 2, 2, "Refreshes the dynamic fields in the inspector.")
{
return object->inspectGroup();
}
void GuiInspectorDynamicGroup::clearFields()
{
// save mAddCtrl
Sim::getGuiGroup()->addObject(mAddCtrl);
// delete everything else
mStack->clear();
// clear the mChildren list.
mChildren.clear();
// and restore.
mStack->addObject(mAddCtrl);
}
SimFieldDictionary::Entry* GuiInspectorDynamicGroup::findDynamicFieldInDictionary( StringTableEntry fieldName )
{
SimFieldDictionary * fieldDictionary = mParent->getInspectObject()->getFieldDictionary();
for(SimFieldDictionaryIterator ditr(fieldDictionary); *ditr; ++ditr)
{
SimFieldDictionary::Entry * entry = (*ditr);
if( entry->slotName == fieldName )
return entry;
}
return NULL;
}
void GuiInspectorDynamicGroup::addDynamicField()
{
// We can't add a field without a target
if( !mStack )
{
Con::warnf("GuiInspectorDynamicGroup::addDynamicField - no target SimObject to add a dynamic field to.");
return;
}
// find a field name that is not in use.
// But we wont try more than 100 times to find an available field.
U32 uid = 1;
char buf[64] = "dynamicField";
SimFieldDictionary::Entry* entry = findDynamicFieldInDictionary(buf);
while(entry != NULL && uid < 100)
{
dSprintf(buf, sizeof(buf), "dynamicField%03d", uid++);
entry = findDynamicFieldInDictionary(buf);
}
const U32 numTargets = mParent->getNumInspectObjects();
if( numTargets > 1 )
Con::executef( mParent, "onBeginCompoundEdit" );
for( U32 i = 0; i < numTargets; ++ i )
{
SimObject* target = mParent->getInspectObject( i );
Con::evaluatef( "%d.dynamicField = \"defaultValue\";", target->getId(), buf );
// Notify script.
Con::executef( mParent, "onFieldAdded", target->getIdString(), buf );
}
if( numTargets > 1 )
Con::executef( mParent, "onEndCompoundEdit" );
// now we simply re-inspect the object, to see the new field.
inspectGroup();
instantExpand();
}
ConsoleMethod( GuiInspectorDynamicGroup, addDynamicField, void, 2, 2, "obj.addDynamicField();" )
{
object->addDynamicField();
}
ConsoleMethod( GuiInspectorDynamicGroup, removeDynamicField, void, 3, 3, "" )
{
}

View file

@ -0,0 +1,65 @@
//-----------------------------------------------------------------------------
// Copyright (c) 2012 GarageGames, LLC
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//-----------------------------------------------------------------------------
#ifndef _GUI_INSPECTOR_DYNAMICGROUP_H_
#define _GUI_INSPECTOR_DYNAMICGROUP_H_
#include "gui/editor/inspector/group.h"
#include "console/simFieldDictionary.h"
class GuiInspectorDynamicGroup : public GuiInspectorGroup
{
private:
typedef GuiInspectorGroup Parent;
GuiControl* mAddCtrl;
public:
DECLARE_CONOBJECT(GuiInspectorDynamicGroup);
GuiInspectorDynamicGroup() { /*mNeedScroll=false;*/ };
GuiInspectorDynamicGroup( StringTableEntry groupName, SimObjectPtr<GuiInspector> parent )
: GuiInspectorGroup( groupName, parent) { /*mNeedScroll=false;*/};
//-----------------------------------------------------------------------------
// inspectGroup is overridden in GuiInspectorDynamicGroup to inspect an
// objects FieldDictionary (dynamic fields) instead of regular persistent
// fields.
bool inspectGroup();
virtual void updateAllFields();
// For scriptable dynamic field additions
void addDynamicField();
// Clear our fields (delete them)
void clearFields();
// Find an already existent field by name in the dictionary
virtual SimFieldDictionary::Entry* findDynamicFieldInDictionary( StringTableEntry fieldName );
protected:
// create our inner controls when we add
virtual bool createContent();
};
#endif // _GUI_INSPECTOR_DYNAMICGROUP_H_

View file

@ -0,0 +1,666 @@
//-----------------------------------------------------------------------------
// Copyright (c) 2012 GarageGames, LLC
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//-----------------------------------------------------------------------------
#include "platform/platform.h"
#include "gui/editor/inspector/field.h"
#include "gui/buttons/guiIconButtonCtrl.h"
#include "gui/editor/guiInspector.h"
#include "core/util/safeDelete.h"
#include "gfx/gfxDrawUtil.h"
#include "math/mathTypes.h"
#include "core/strings/stringUnit.h"
IMPLEMENT_CONOBJECT(GuiInspectorField);
ConsoleDocClass( GuiInspectorField,
"@brief The GuiInspectorField control is a representation of a single abstract "
"field for a given ConsoleObject derived object.\n\n"
"Editor use only.\n\n"
"@internal"
);
//-----------------------------------------------------------------------------
GuiInspectorField::GuiInspectorField( GuiInspector* inspector,
GuiInspectorGroup* parent,
AbstractClassRep::Field* field )
: mInspector( inspector ),
mParent( parent ),
mField( field ),
mFieldArrayIndex( NULL ),
mEdit( NULL )
{
if( field != NULL )
mCaption = field->pFieldname;
else
mCaption = StringTable->EmptyString();
setCanSave( false );
setBounds(0,0,100,18);
if( field )
_setFieldDocs( field->pFieldDocs );
}
//-----------------------------------------------------------------------------
GuiInspectorField::GuiInspectorField()
: mInspector( NULL ),
mParent( NULL ),
mEdit( NULL ),
mField( NULL ),
mFieldArrayIndex( NULL ),
mCaption( StringTable->EmptyString() ),
mHighlighted( false )
{
setCanSave( false );
}
//-----------------------------------------------------------------------------
GuiInspectorField::~GuiInspectorField()
{
}
//-----------------------------------------------------------------------------
void GuiInspectorField::init( GuiInspector *inspector, GuiInspectorGroup *group )
{
mInspector = inspector;
mParent = group;
}
//-----------------------------------------------------------------------------
bool GuiInspectorField::onAdd()
{
setInspectorProfile();
if ( !Parent::onAdd() )
return false;
if ( !mInspector )
return false;
mEdit = constructEditControl();
if ( mEdit == NULL )
return false;
setBounds(0,0,100,18);
// Add our edit as a child
addObject( mEdit );
// Calculate Caption and EditCtrl Rects
updateRects();
// Force our editField to set it's value
updateValue();
return true;
}
//-----------------------------------------------------------------------------
bool GuiInspectorField::resize( const Point2I &newPosition, const Point2I &newExtent )
{
if ( !Parent::resize( newPosition, newExtent ) )
return false;
return updateRects();
}
//-----------------------------------------------------------------------------
void GuiInspectorField::onRender( Point2I offset, const RectI &updateRect )
{
RectI ctrlRect(offset, getExtent());
// Render fillcolor...
if ( mProfile->mOpaque )
GFX->getDrawUtil()->drawRectFill(ctrlRect, mProfile->mFillColor);
// Render caption...
if ( mCaption && mCaption[0] )
{
// Backup current ClipRect
RectI clipBackup = GFX->getClipRect();
RectI clipRect = updateRect;
// The rect within this control in which our caption must fit.
RectI rect( offset + mCaptionRect.point + mProfile->mTextOffset, mCaptionRect.extent + Point2I(1,1) - Point2I(5,0) );
// Now clipRect is the amount of our caption rect that is actually visible.
bool hit = clipRect.intersect( rect );
if ( hit )
{
GFX->setClipRect( clipRect );
GFXDrawUtil *drawer = GFX->getDrawUtil();
// Backup modulation color
ColorI currColor;
drawer->getBitmapModulation( &currColor );
// Draw caption background...
if( !isActive() )
GFX->getDrawUtil()->drawRectFill( clipRect, mProfile->mFillColorNA );
else if ( mHighlighted )
GFX->getDrawUtil()->drawRectFill( clipRect, mProfile->mFillColorHL );
// Draw caption text...
drawer->setBitmapModulation( !isActive() ? mProfile->mFontColorNA : mHighlighted ? mProfile->mFontColorHL : mProfile->mFontColor );
// Clip text with '...' if too long to fit
String clippedText( mCaption );
clipText( clippedText, clipRect.extent.x );
renderJustifiedText( offset + mProfile->mTextOffset, getExtent(), clippedText );
// Restore modulation color
drawer->setBitmapModulation( currColor );
// Restore previous ClipRect
GFX->setClipRect( clipBackup );
}
}
// Render Children...
renderChildControls(offset, updateRect);
// Render border...
if ( mProfile->mBorder )
renderBorder(ctrlRect, mProfile);
// Render divider...
Point2I worldPnt = mEditCtrlRect.point + offset;
GFX->getDrawUtil()->drawLine( worldPnt.x - 5,
worldPnt.y,
worldPnt.x - 5,
worldPnt.y + getHeight(),
!isActive() ? mProfile->mBorderColorNA : mHighlighted ? mProfile->mBorderColorHL : mProfile->mBorderColor );
}
//-----------------------------------------------------------------------------
void GuiInspectorField::setFirstResponder( GuiControl *firstResponder )
{
Parent::setFirstResponder( firstResponder );
if ( firstResponder == this || firstResponder == mEdit )
{
mInspector->setHighlightField( this );
}
}
//-----------------------------------------------------------------------------
void GuiInspectorField::onMouseDown( const GuiEvent &event )
{
if ( mCaptionRect.pointInRect( globalToLocalCoord( event.mousePoint ) ) )
{
if ( mEdit )
//mEdit->onMouseDown( event );
mInspector->setHighlightField( this );
}
else
Parent::onMouseDown( event );
}
//-----------------------------------------------------------------------------
void GuiInspectorField::onRightMouseUp( const GuiEvent &event )
{
if ( mCaptionRect.pointInRect( globalToLocalCoord( event.mousePoint ) ) )
Con::executef( mInspector, "onFieldRightClick", getIdString() );
else
Parent::onMouseDown( event );
}
//-----------------------------------------------------------------------------
void GuiInspectorField::setData( const char* data, bool callbacks )
{
if( mField == NULL )
return;
if( verifyData( data ) )
{
String strData = data;
const U32 numTargets = mInspector->getNumInspectObjects();
if( callbacks && numTargets > 1 )
Con::executef( mInspector, "onBeginCompoundEdit" );
for( U32 i = 0; i < numTargets; ++ i )
{
SimObject* target = mInspector->getInspectObject( i );
String oldValue = target->getDataField( mField->pFieldname, mFieldArrayIndex);
// For numeric fields, allow input expressions.
String newValue = strData;
S32 type= mField->type;
if( type == TypeS8 || type == TypeS32 || type == TypeF32 )
{
char buffer[ 2048 ];
expandEscape( buffer, newValue );
newValue = Con::evaluatef( "%%f = \"%s\"; return ( %s );", oldValue.c_str(), buffer );
}
else if( type == TypeS32Vector
|| type == TypeF32Vector
|| type == TypeColorI
|| type == TypeColorF
|| type == TypePoint2I
|| type == TypePoint2F
|| type == TypePoint3F
|| type == TypePoint4F
|| type == TypeRectI
|| type == TypeRectF
|| type == TypeMatrixPosition
|| type == TypeMatrixRotation
|| type == TypeBox3F
|| type == TypeRectUV )
{
//TODO: we should actually take strings into account and not chop things up between quotes
U32 numNewUnits = StringUnit::getUnitCount( newValue, " \t\n\r" );
StringBuilder strNew;
bool isFirst = true;
for( U32 n = 0; n < numNewUnits; ++ n )
{
char oldComponentVal[ 1024 ];
StringUnit::getUnit( oldValue, n, " \t\n\r", oldComponentVal, sizeof( oldComponentVal ) );
char newComponentExpr[ 1024 ];
StringUnit::getUnit( newValue, n, " \t\n\r", newComponentExpr, sizeof( newComponentExpr ) );
char buffer[ 2048 ];
expandEscape( buffer, newComponentExpr );
const char* newComponentVal = Con::evaluatef( "%%f = \"%s\"; %%v = \"%s\"; return ( %s );",
oldComponentVal, oldValue.c_str(), buffer );
if( !isFirst )
strNew.append( ' ' );
strNew.append( newComponentVal );
isFirst = false;
}
newValue = strNew.end();
}
target->inspectPreApply();
// Fire callback single-object undo.
if( callbacks )
Con::executef( mInspector, "onInspectorFieldModified",
target->getIdString(),
mField->pFieldname,
mFieldArrayIndex ? mFieldArrayIndex : "(null)",
oldValue.c_str(),
newValue.c_str() );
target->setDataField( mField->pFieldname, mFieldArrayIndex, newValue );
// Give the target a chance to validate.
target->inspectPostApply();
}
if( callbacks && numTargets > 1 )
Con::executef( mInspector, "onEndCompoundEdit" );
}
// Force our edit to update
updateValue();
}
//-----------------------------------------------------------------------------
const char* GuiInspectorField::getData( U32 inspectObjectIndex )
{
if( mField == NULL )
return "";
return mInspector->getInspectObject( inspectObjectIndex )->getDataField( mField->pFieldname, mFieldArrayIndex );
}
//-----------------------------------------------------------------------------
void GuiInspectorField::resetData()
{
if( !mField )
return;
SimObject* inspectObject = getInspector()->getInspectObject();
SimObject* tempObject = static_cast< SimObject* >( inspectObject->getClassRep()->create() );
setData( tempObject->getDataField( mField->pFieldname, mFieldArrayIndex ) );
delete tempObject;
}
//-----------------------------------------------------------------------------
void GuiInspectorField::setInspectorField( AbstractClassRep::Field *field, StringTableEntry caption, const char*arrayIndex )
{
mField = field;
if ( arrayIndex != NULL )
mFieldArrayIndex = StringTable->insert( arrayIndex );
if ( !caption || !caption[0] )
mCaption = getFieldName();
else
mCaption = caption;
_setFieldDocs( mField->pFieldDocs );
}
//-----------------------------------------------------------------------------
StringTableEntry GuiInspectorField::getRawFieldName()
{
if( !mField )
return StringTable->EmptyString();
return mField->pFieldname;
}
//-----------------------------------------------------------------------------
StringTableEntry GuiInspectorField::getFieldName()
{
// Sanity
if ( mField == NULL )
return StringTable->EmptyString();
// Array element?
if( mFieldArrayIndex != NULL )
{
S32 frameTempSize = dStrlen( mField->pFieldname ) + 32;
FrameTemp<char> valCopy( frameTempSize );
dSprintf( (char *)valCopy, frameTempSize, "%s[%s]", mField->pFieldname, mFieldArrayIndex );
// Return formatted element
return StringTable->insert( valCopy );
}
// Plain field name.
return mField->pFieldname;
}
//-----------------------------------------------------------------------------
StringTableEntry GuiInspectorField::getFieldType()
{
if( !mField )
return StringTable->EmptyString();
return ConsoleBaseType::getType( mField->type )->getTypeName();
}
//-----------------------------------------------------------------------------
GuiControl* GuiInspectorField::constructEditControl()
{
GuiControl* retCtrl = new GuiTextEditCtrl();
static StringTableEntry sProfile = StringTable->insert( "profile" );
retCtrl->setDataField( sProfile, NULL, "GuiInspectorTextEditProfile" );
_registerEditControl( retCtrl );
char szBuffer[512];
dSprintf( szBuffer, 512, "%d.apply(%d.getText());",getId(), retCtrl->getId() );
// Suffices to hook on to "validate" as regardless of whether we lose
// focus through the user pressing enter or clicking away on another
// keyboard control, we will see a validate call.
retCtrl->setField("validate", szBuffer );
return retCtrl;
}
//-----------------------------------------------------------------------------
void GuiInspectorField::setInspectorProfile()
{
GuiControlProfile *profile = NULL;
if( mInspector->getNumInspectObjects() > 1 )
{
if( !hasSameValueInAllObjects() )
Sim::findObject( "GuiInspectorMultiFieldDifferentProfile", profile );
else
Sim::findObject( "GuiInspectorMultiFieldProfile", profile );
}
if( !profile )
Sim::findObject( "GuiInspectorFieldProfile", profile );
if( profile )
setControlProfile( profile );
}
//-----------------------------------------------------------------------------
void GuiInspectorField::setValue( StringTableEntry newValue )
{
GuiTextEditCtrl *ctrl = dynamic_cast<GuiTextEditCtrl*>( mEdit );
if( ctrl != NULL )
ctrl->setText( newValue );
}
//-----------------------------------------------------------------------------
bool GuiInspectorField::updateRects()
{
S32 dividerPos, dividerMargin;
mInspector->getDivider( dividerPos, dividerMargin );
Point2I fieldExtent = getExtent();
Point2I fieldPos = getPosition();
S32 editWidth = dividerPos - dividerMargin;
mEditCtrlRect.set( fieldExtent.x - dividerPos + dividerMargin, 1, editWidth, fieldExtent.y - 1 );
mCaptionRect.set( 0, 0, fieldExtent.x - dividerPos - dividerMargin, fieldExtent.y );
if ( !mEdit )
return false;
return mEdit->resize( mEditCtrlRect.point, mEditCtrlRect.extent );
}
//-----------------------------------------------------------------------------
void GuiInspectorField::updateValue()
{
if( mInspector->getNumInspectObjects() > 1 )
{
setInspectorProfile();
if( !hasSameValueInAllObjects() )
setValue( StringTable->EmptyString() );
else
setValue( getData() );
}
else
setValue( getData() );
}
//-----------------------------------------------------------------------------
void GuiInspectorField::setHLEnabled( bool enabled )
{
mHighlighted = enabled;
if ( mHighlighted )
{
if ( mEdit && !mEdit->isFirstResponder() )
{
mEdit->setFirstResponder();
GuiTextEditCtrl *edit = dynamic_cast<GuiTextEditCtrl*>( mEdit );
if ( edit )
{
mouseUnlock();
edit->mouseLock();
edit->setCursorPos(0);
}
}
_executeSelectedCallback();
}
}
//-----------------------------------------------------------------------------
bool GuiInspectorField::hasSameValueInAllObjects()
{
char value1[ 2048 ];
// Get field value from first object.
const char* data1 = getData( 0 );
if( data1 )
{
dStrncpy( value1, data1, sizeof( value1 ) );
value1[ sizeof( value1 ) - 1 ] = 0;
}
else
value1[ 0 ] = 0;
// Check if all other objects have the same value.
const U32 numObjects = mInspector->getNumInspectObjects();
for( U32 i = 1; i < numObjects; ++ i )
{
const char* value2 = getData( i );
if( !value2 )
value2 = "";
if( dStrcmp( value1, value2 ) != 0 )
return false;
}
return true;
}
//-----------------------------------------------------------------------------
void GuiInspectorField::_executeSelectedCallback()
{
if( mField )
Con::executef( mInspector, "onFieldSelected", mField->pFieldname, ConsoleBaseType::getType(mField->type)->getTypeName(), mFieldDocs.c_str() );
}
//-----------------------------------------------------------------------------
void GuiInspectorField::_registerEditControl( GuiControl *ctrl )
{
char szName[512];
dSprintf( szName, 512, "IE_%s_%d_%s_Field", ctrl->getClassName(), mInspector->getInspectObject()->getId(), mCaption);
// Register the object
ctrl->registerObject( szName );
}
//-----------------------------------------------------------------------------
void GuiInspectorField::_setFieldDocs( StringTableEntry docs )
{
mFieldDocs = String();
if( docs && docs[ 0 ] )
{
// Only accept first line of docs for brevity.
const char* newline = dStrchr( docs, '\n' );
if( newline )
mFieldDocs = String( docs, newline - docs );
else
mFieldDocs = docs;
}
}
//=============================================================================
// Console Methods.
//=============================================================================
// MARK: ---- Console Methods ----
//-----------------------------------------------------------------------------
ConsoleMethod( GuiInspectorField, getInspector, S32, 2, 2, "() - Return the GuiInspector to which this field belongs." )
{
return object->getInspector()->getId();
}
//-----------------------------------------------------------------------------
ConsoleMethod( GuiInspectorField, getInspectedFieldName, const char*, 2, 2, "() - Return the name of the field edited by this inspector field." )
{
return object->getFieldName();
}
//-----------------------------------------------------------------------------
ConsoleMethod( GuiInspectorField, getInspectedFieldType, const char*, 2, 2, "() - Return the type of the field edited by this inspector field." )
{
return object->getFieldType();
}
//-----------------------------------------------------------------------------
ConsoleMethod( GuiInspectorField, apply, void, 3, 4, "( string newValue, bool callbacks=true ) - Set the field's value. Suppress callbacks for undo if callbacks=false." )
{
bool callbacks = true;
if( argc > 3 )
callbacks = dAtob( argv[ 3 ] );
object->setData( argv[ 2 ], callbacks );
}
//-----------------------------------------------------------------------------
ConsoleMethod( GuiInspectorField, applyWithoutUndo, void, 3, 3, "() - Set field value without recording undo (same as 'apply( value, false )')." )
{
object->setData( argv[ 2 ], false );
}
//-----------------------------------------------------------------------------
ConsoleMethod( GuiInspectorField, getData, const char*, 2, 2, "() - Return the value currently displayed on the field." )
{
return object->getData();
}
//-----------------------------------------------------------------------------
ConsoleMethod( GuiInspectorField, reset, void, 2, 2, "() - Reset to default value." )
{
object->resetData();
}

View file

@ -0,0 +1,194 @@
//-----------------------------------------------------------------------------
// Copyright (c) 2012 GarageGames, LLC
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//-----------------------------------------------------------------------------
#ifndef _GUI_INSPECTOR_FIELD_H_
#define _GUI_INSPECTOR_FIELD_H_
#include "gui/core/guiCanvas.h"
#include "gui/shiny/guiTickCtrl.h"
#include "gui/controls/guiTextEditCtrl.h"
#include "gui/buttons/guiBitmapButtonCtrl.h"
#include "gui/controls/guiPopUpCtrl.h"
#include "gui/containers/guiRolloutCtrl.h"
class GuiInspectorGroup;
class GuiInspector;
/// The GuiInspectorField control is a representation of a single abstract
/// field for a given ConsoleObject derived object. It handles creation
/// getting and setting of it's fields data and editing control.
///
/// Creation of custom edit controls is done through this class and is
/// dependent upon the dynamic console type, which may be defined to be
/// custom for different types.
///
/// @note GuiInspectorField controls must have a GuiInspectorGroup as their
/// parent.
class GuiInspectorField : public GuiControl
{
public:
typedef GuiControl Parent;
friend class GuiInspectorGroup;
protected:
/// The text to display as the field name.
StringTableEntry mCaption;
/// The group to which this field belongs.
GuiInspectorGroup* mParent;
/// The GuiInspector that the group is in to which this field belongs.
GuiInspector* mInspector;
///
AbstractClassRep::Field* mField;
///
StringTableEntry mFieldArrayIndex;
///
String mFieldDocs;
///
GuiControl* mEdit;
///
RectI mCaptionRect;
///
RectI mEditCtrlRect;
///
bool mHighlighted;
virtual void _registerEditControl( GuiControl *ctrl );
virtual void _executeSelectedCallback();
void _setFieldDocs( StringTableEntry docs );
public:
explicit GuiInspectorField();
///
GuiInspectorField( GuiInspector *inspector, GuiInspectorGroup* parent, AbstractClassRep::Field* field );
virtual ~GuiInspectorField();
///
virtual void init( GuiInspector *inspector, GuiInspectorGroup *group );
///
virtual void setInspectorField( AbstractClassRep::Field *field,
StringTableEntry caption = NULL,
const char *arrayIndex = NULL );
///
virtual GuiControl* constructEditControl();
/// Chooses and sets the GuiControlProfile.
virtual void setInspectorProfile();
/// Sets this control's caption text, usually set within setInspectorField,
/// this is exposed in case someone wants to override the normal caption.
virtual void setCaption( StringTableEntry caption ) { mCaption = caption; }
/// Returns pointer to this InspectorField's edit ctrl.
virtual GuiControl* getEditCtrl() { return mEdit; }
/// Sets the value of this GuiInspectorField (not the actual field)
/// This means the EditCtrl unless overridden.
virtual void setValue( const char* newValue );
/// Get the currently value of this control (not the actual field)
virtual const char* getValue() { return NULL; }
/// Update this controls value to reflect that of the inspected field.
virtual void updateValue();
/// Return the name of the field being edited.
virtual StringTableEntry getFieldName();
/// Return the name of the console type that this field uses.
virtual StringTableEntry getFieldType();
/// Return the name without the array index that may potentially be present.
virtual StringTableEntry getRawFieldName();
///
StringTableEntry getArrayIndex() const { return mFieldArrayIndex; }
/// Called from within setData to allow child classes
/// to perform their own verification.
virtual bool verifyData( StringTableEntry data ) { return true; }
/// Set value of the field we are inspecting
virtual void setData( const char* data, bool callbacks = true );
/// Reset the field value to its default value based on default-constructed objects.
///
/// @note If multiple objects are inspected, this will take the default value from
/// the first object and set all fields to this value.
virtual void resetData();
/// Get value of the field we are inspecting.
///
/// @note The string returned by this method may be a transient string allocated
/// internally by the console. For any non-transient needs, this string has
/// to be copied to locally owned memory.
/// @note This method always returns the value of the field in the first
/// inspected object.
virtual const char* getData( U32 inspectObjectIndex = 0 );
/// Update the inspected field to match the value of this control.
virtual void updateData() {};
///
virtual bool updateRects();
///
virtual void setHLEnabled( bool enabled );
/// Return true if all inspected objects have the same value for this
/// field.
bool hasSameValueInAllObjects();
/// Return the inspector object that this field belongs to.
GuiInspector* getInspector() const { return mInspector; }
// GuiControl.
virtual bool onAdd();
virtual bool resize(const Point2I &newPosition, const Point2I &newExtent);
virtual void onRender(Point2I offset, const RectI &updateRect);
virtual void setFirstResponder( GuiControl *firstResponder );
virtual void onMouseDown( const GuiEvent &event );
virtual void onRightMouseUp( const GuiEvent &event );
DECLARE_CONOBJECT( GuiInspectorField );
DECLARE_CATEGORY( "Gui Editor" );
};
#endif // _GUI_INSPECTOR_FIELD_H_

View file

@ -0,0 +1,567 @@
//-----------------------------------------------------------------------------
// Copyright (c) 2012 GarageGames, LLC
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//-----------------------------------------------------------------------------
#include "gui/editor/guiInspector.h"
#include "gui/editor/inspector/group.h"
#include "gui/editor/inspector/dynamicField.h"
#include "gui/editor/inspector/datablockField.h"
#include "gui/buttons/guiIconButtonCtrl.h"
IMPLEMENT_CONOBJECT(GuiInspectorGroup);
ConsoleDocClass( GuiInspectorGroup,
"@brief The GuiInspectorGroup control is a helper control that the inspector "
"makes use of which houses a collapsible pane type control for separating "
"inspected objects fields into groups.\n\n"
"Editor use only.\n\n"
"@internal"
);
//#define DEBUG_SPEW
//-----------------------------------------------------------------------------
GuiInspectorGroup::GuiInspectorGroup()
: mParent( NULL ),
mStack(NULL)
{
setBounds(0,0,200,20);
mChildren.clear();
setCanSave( false );
// Make sure we receive our ticks.
setProcessTicks();
mMargin.set(0,0,5,0);
}
//-----------------------------------------------------------------------------
GuiInspectorGroup::GuiInspectorGroup( const String& groupName,
SimObjectPtr<GuiInspector> parent )
: mParent( parent ),
mStack(NULL)
{
setBounds(0,0,200,20);
mCaption = groupName;
setCanSave( false );
mChildren.clear();
mMargin.set(0,0,4,0);
}
//-----------------------------------------------------------------------------
GuiInspectorGroup::~GuiInspectorGroup()
{
}
//-----------------------------------------------------------------------------
bool GuiInspectorGroup::onAdd()
{
setDataField( StringTable->insert("profile"), NULL, "GuiInspectorGroupProfile" );
if( !Parent::onAdd() )
return false;
// Create our inner controls. Allow subclasses to provide other content.
if(!createContent())
return false;
inspectGroup();
return true;
}
//-----------------------------------------------------------------------------
bool GuiInspectorGroup::createContent()
{
// Create our field stack control
mStack = new GuiStackControl();
// Prefer GuiTransperantProfile for the stack.
mStack->setDataField( StringTable->insert("profile"), NULL, "GuiInspectorStackProfile" );
if( !mStack->registerObject() )
{
SAFE_DELETE( mStack );
return false;
}
addObject( mStack );
mStack->setField( "padding", "0" );
return true;
}
//-----------------------------------------------------------------------------
void GuiInspectorGroup::animateToContents()
{
calculateHeights();
if(size() > 0)
animateTo( mExpanded.extent.y );
else
animateTo( mHeader.extent.y );
}
//-----------------------------------------------------------------------------
GuiInspectorField* GuiInspectorGroup::constructField( S32 fieldType )
{
// See if we can construct a field of this type
ConsoleBaseType *cbt = ConsoleBaseType::getType(fieldType);
if( !cbt )
return NULL;
// Alright, is it a datablock?
if(cbt->isDatablock())
{
// Default to GameBaseData
StringTableEntry typeClassName = cbt->getTypeClassName();
if( mParent->getNumInspectObjects() == 1 && !dStricmp(typeClassName, "GameBaseData") )
{
// Try and setup the classname based on the object type
char className[256];
dSprintf(className,256,"%sData", mParent->getInspectObject( 0 )->getClassName());
// Walk the ACR list and find a matching class if any.
AbstractClassRep *walk = AbstractClassRep::getClassList();
while(walk)
{
if(!dStricmp(walk->getClassName(), className))
break;
walk = walk->getNextClass();
}
// We found a valid class
if (walk)
typeClassName = walk->getClassName();
}
GuiInspectorDatablockField *dbFieldClass = new GuiInspectorDatablockField( typeClassName );
if( dbFieldClass != NULL )
{
// return our new datablock field with correct datablock type enumeration info
return dbFieldClass;
}
}
// Nope, not a datablock. So maybe it has a valid inspector field override we can use?
if(!cbt->getInspectorFieldType())
// Nothing, so bail.
return NULL;
// Otherwise try to make it!
ConsoleObject *co = create(cbt->getInspectorFieldType());
GuiInspectorField *gif = dynamic_cast<GuiInspectorField*>(co);
if(!gif)
{
// Wasn't appropriate type, bail.
delete co;
return NULL;
}
return gif;
}
//-----------------------------------------------------------------------------
GuiInspectorField *GuiInspectorGroup::findField( const char *fieldName )
{
// If we don't have any field children we can't very well find one then can we?
if( mChildren.empty() )
return NULL;
Vector<GuiInspectorField*>::iterator i = mChildren.begin();
for( ; i != mChildren.end(); i++ )
{
if( (*i)->getFieldName() != NULL && dStricmp( (*i)->getFieldName(), fieldName ) == 0 )
return (*i);
}
return NULL;
}
//-----------------------------------------------------------------------------
void GuiInspectorGroup::clearFields()
{
// Deallocates all field related controls.
mStack->clear();
// Then just cleanup our vectors which also point to children
// that we keep for our own convenience.
mArrayCtrls.clear();
mChildren.clear();
}
//-----------------------------------------------------------------------------
bool GuiInspectorGroup::inspectGroup()
{
// We can't inspect a group without a target!
if( !mParent->getNumInspectObjects() )
return false;
// to prevent crazy resizing, we'll just freeze our stack for a sec..
mStack->freeze(true);
bool bNoGroup = false;
// Un-grouped fields are all sorted into the 'general' group
if ( dStricmp( mCaption, "General" ) == 0 )
bNoGroup = true;
// Just delete all fields and recreate them (like the dynamicGroup)
// because that makes creating controls for array fields a lot easier
clearFields();
bool bNewItems = false;
bool bMakingArray = false;
GuiStackControl *pArrayStack = NULL;
GuiRolloutCtrl *pArrayRollout = NULL;
bool bGrabItems = false;
AbstractClassRep* commonAncestorClass = findCommonAncestorClass();
AbstractClassRep::FieldList& fieldList = commonAncestorClass->mFieldList;
for( AbstractClassRep::FieldList::iterator itr = fieldList.begin();
itr != fieldList.end(); ++ itr )
{
AbstractClassRep::Field* field = &( *itr );
if( field->type == AbstractClassRep::StartGroupFieldType )
{
// If we're dealing with general fields, always set grabItems to true (to skip them)
if( bNoGroup == true )
bGrabItems = true;
else if( dStricmp( field->pGroupname, mCaption ) == 0 )
bGrabItems = true;
continue;
}
else if ( field->type == AbstractClassRep::EndGroupFieldType )
{
// If we're dealing with general fields, always set grabItems to false (to grab them)
if( bNoGroup == true )
bGrabItems = false;
else if( dStricmp( field->pGroupname, mCaption ) == 0 )
bGrabItems = false;
continue;
}
// Skip field if it has the HideInInspectors flag set.
if( field->flag.test( AbstractClassRep::FIELD_HideInInspectors ) )
continue;
if( ( bGrabItems == true || ( bNoGroup == true && bGrabItems == false ) ) && itr->type != AbstractClassRep::DeprecatedFieldType )
{
if( bNoGroup == true && bGrabItems == true )
continue;
if ( field->type == AbstractClassRep::StartArrayFieldType )
{
#ifdef DEBUG_SPEW
Platform::outputDebugString( "[GuiInspectorGroup] Beginning array '%s'",
field->pFieldname );
#endif
// Starting an array...
// Create a rollout for the Array, give it the array's name.
GuiRolloutCtrl *arrayRollout = new GuiRolloutCtrl();
GuiControlProfile *arrayRolloutProfile = dynamic_cast<GuiControlProfile*>( Sim::findObject( "GuiInspectorRolloutProfile0" ) );
arrayRollout->setControlProfile(arrayRolloutProfile);
//arrayRollout->mCaption = StringTable->insert( String::ToString( "%s (%i)", field->pGroupname, field->elementCount ) );
arrayRollout->setCaption( field->pGroupname );
//arrayRollout->setMargin( 14, 0, 0, 0 );
arrayRollout->registerObject();
GuiStackControl *arrayStack = new GuiStackControl();
arrayStack->registerObject();
arrayStack->freeze(true);
arrayRollout->addObject(arrayStack);
// Allocate a rollout for each element-count in the array
// Give it the element count name.
for ( U32 i = 0; i < field->elementCount; i++ )
{
GuiRolloutCtrl *elementRollout = new GuiRolloutCtrl();
GuiControlProfile *elementRolloutProfile = dynamic_cast<GuiControlProfile*>( Sim::findObject( "GuiInspectorRolloutProfile0" ) );
char buf[256];
dSprintf( buf, 256, " [%i]", i );
elementRollout->setControlProfile(elementRolloutProfile);
elementRollout->setCaption(buf);
//elementRollout->setMargin( 14, 0, 0, 0 );
elementRollout->registerObject();
GuiStackControl *elementStack = new GuiStackControl();
elementStack->registerObject();
elementRollout->addObject(elementStack);
elementRollout->instantCollapse();
arrayStack->addObject( elementRollout );
}
pArrayRollout = arrayRollout;
pArrayStack = arrayStack;
arrayStack->freeze(false);
pArrayRollout->instantCollapse();
mStack->addObject(arrayRollout);
bMakingArray = true;
continue;
}
else if ( field->type == AbstractClassRep::EndArrayFieldType )
{
#ifdef DEBUG_SPEW
Platform::outputDebugString( "[GuiInspectorGroup] Ending array '%s'",
field->pFieldname );
#endif
bMakingArray = false;
continue;
}
if ( bMakingArray )
{
// Add a GuiInspectorField for this field,
// for every element in the array...
for ( U32 i = 0; i < pArrayStack->size(); i++ )
{
FrameTemp<char> intToStr( 64 );
dSprintf( intToStr, 64, "%d", i );
// The array stack should have a rollout for each element
// as children...
GuiRolloutCtrl *pRollout = dynamic_cast<GuiRolloutCtrl*>(pArrayStack->at(i));
// And the each of those rollouts should have a stack for
// fields...
GuiStackControl *pStack = dynamic_cast<GuiStackControl*>(pRollout->at(0));
// And we add a new GuiInspectorField to each of those stacks...
GuiInspectorField *fieldGui = constructField( field->type );
if ( fieldGui == NULL )
fieldGui = new GuiInspectorField();
fieldGui->init( mParent, this );
StringTableEntry caption = field->pFieldname;
fieldGui->setInspectorField( field, caption, intToStr );
if( fieldGui->registerObject() )
{
#ifdef DEBUG_SPEW
Platform::outputDebugString( "[GuiInspectorGroup] Adding array element '%s[%i]'",
field->pFieldname, i );
#endif
mChildren.push_back( fieldGui );
pStack->addObject( fieldGui );
}
else
delete fieldGui;
}
continue;
}
// This is weird, but it should work for now. - JDD
// We are going to check to see if this item is an array
// if so, we're going to construct a field for each array element
if( field->elementCount > 1 )
{
// Make a rollout control for this array
//
GuiRolloutCtrl *rollout = new GuiRolloutCtrl();
rollout->setDataField( StringTable->insert("profile"), NULL, "GuiInspectorRolloutProfile0" );
rollout->setCaption(String::ToString( "%s (%i)", field->pFieldname, field->elementCount));
rollout->setMargin( 14, 0, 0, 0 );
rollout->registerObject();
mArrayCtrls.push_back(rollout);
// Put a stack control within the rollout
//
GuiStackControl *stack = new GuiStackControl();
stack->setDataField( StringTable->insert("profile"), NULL, "GuiInspectorStackProfile" );
stack->registerObject();
stack->freeze(true);
rollout->addObject(stack);
mStack->addObject(rollout);
// Create each field and add it to the stack.
//
for (S32 nI = 0; nI < field->elementCount; nI++)
{
FrameTemp<char> intToStr( 64 );
dSprintf( intToStr, 64, "%d", nI );
// Construct proper ValueName[nI] format which is "ValueName0" for index 0, etc.
String fieldName = String::ToString( "%s%d", field->pFieldname, nI );
// If the field already exists, just update it
GuiInspectorField *fieldGui = findField( fieldName );
if( fieldGui != NULL )
{
fieldGui->updateValue();
continue;
}
bNewItems = true;
fieldGui = constructField( field->type );
if ( fieldGui == NULL )
fieldGui = new GuiInspectorField();
fieldGui->init( mParent, this );
StringTableEntry caption = StringTable->insert( String::ToString(" [%i]",nI) );
fieldGui->setInspectorField( field, caption, intToStr );
if ( fieldGui->registerObject() )
{
mChildren.push_back( fieldGui );
stack->addObject( fieldGui );
}
else
delete fieldGui;
}
stack->freeze(false);
stack->updatePanes();
rollout->instantCollapse();
}
else
{
// If the field already exists, just update it
GuiInspectorField *fieldGui = findField( field->pFieldname );
if ( fieldGui != NULL )
{
fieldGui->updateValue();
continue;
}
bNewItems = true;
fieldGui = constructField( field->type );
if ( fieldGui == NULL )
fieldGui = new GuiInspectorField();
fieldGui->init( mParent, this );
fieldGui->setInspectorField( field );
if( fieldGui->registerObject() )
{
#ifdef DEBUG_SPEW
Platform::outputDebugString( "[GuiInspectorGroup] Adding field '%s'",
field->pFieldname );
#endif
mChildren.push_back( fieldGui );
mStack->addObject( fieldGui );
}
else
{
SAFE_DELETE( fieldGui );
}
}
}
}
mStack->freeze(false);
mStack->updatePanes();
// If we've no new items, there's no need to resize anything!
if( bNewItems == false && !mChildren.empty() )
return true;
sizeToContents();
setUpdate();
return true;
}
//-----------------------------------------------------------------------------
bool GuiInspectorGroup::updateFieldValue( StringTableEntry fieldName, StringTableEntry arrayIdx )
{
// Check if we contain a field of this name,
// if so update its value and return true.
Vector<GuiInspectorField*>::iterator iter = mChildren.begin();
if( arrayIdx == StringTable->EmptyString() )
arrayIdx = NULL;
for( ; iter != mChildren.end(); iter++ )
{
GuiInspectorField *field = (*iter);
if ( field->mField &&
field->mField->pFieldname == fieldName &&
field->mFieldArrayIndex == arrayIdx )
{
field->updateValue();
return true;
}
}
return false;
}
//-----------------------------------------------------------------------------
void GuiInspectorGroup::updateAllFields()
{
Vector<GuiInspectorField*>::iterator iter = mChildren.begin();
for( ; iter != mChildren.end(); iter++ )
(*iter)->updateValue();
}
//-----------------------------------------------------------------------------
AbstractClassRep* GuiInspectorGroup::findCommonAncestorClass()
{
AbstractClassRep* classRep = getInspector()->getInspectObject( 0 )->getClassRep();
const U32 numInspectObjects = getInspector()->getNumInspectObjects();
for( U32 i = 1; i < numInspectObjects; ++ i )
{
SimObject* object = getInspector()->getInspectObject( i );
while( !object->getClassRep()->isClass( classRep ) )
{
classRep = classRep->getParentClass();
AssertFatal( classRep, "GuiInspectorGroup::findcommonAncestorClass - Walked above ConsoleObject!" );
}
}
return classRep;
}

View file

@ -0,0 +1,87 @@
//-----------------------------------------------------------------------------
// Copyright (c) 2012 GarageGames, LLC
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//-----------------------------------------------------------------------------
#ifndef _GUI_INSPECTOR_GROUP_H_
#define _GUI_INSPECTOR_GROUP_H_
#include "gui/core/guiCanvas.h"
#include "gui/controls/guiTextEditCtrl.h"
#include "gui/buttons/guiBitmapButtonCtrl.h"
#include "gui/containers/guiRolloutCtrl.h"
// Forward refs
class GuiInspector;
class GuiInspectorField;
/// The GuiInspectorGroup control is a helper control that the inspector
/// makes use of which houses a collapsible pane type control for separating
/// inspected objects fields into groups. The content of the inspector is
/// made up of zero or more GuiInspectorGroup controls inside of a GuiStackControl
///
class GuiInspectorGroup : public GuiRolloutCtrl
{
private:
typedef GuiRolloutCtrl Parent;
public:
// Members
SimObjectPtr<GuiInspector> mParent;
Vector<GuiInspectorField*> mChildren;
GuiStackControl* mStack;
Vector<GuiRolloutCtrl*> mArrayCtrls;
// Constructor/Destructor/Conobject Declaration
GuiInspectorGroup();
GuiInspectorGroup( const String& groupName, SimObjectPtr<GuiInspector> parent );
virtual ~GuiInspectorGroup();
DECLARE_CONOBJECT(GuiInspectorGroup);
DECLARE_CATEGORY( "Gui Editor" );
virtual GuiInspectorField* constructField( S32 fieldType );
virtual GuiInspectorField* findField( const char *fieldName );
// Publicly Accessible Information about this group
const String& getGroupName() const { return mCaption; };
SimObjectPtr<GuiInspector> getInspector() { return mParent; };
bool onAdd();
virtual bool inspectGroup();
virtual void animateToContents();
void clearFields();
virtual bool updateFieldValue( StringTableEntry fieldName, const char *arrayIdx );
virtual void updateAllFields();
U32 getNumFields() const { return mChildren.size(); }
protected:
// overridable method that creates our inner controls.
virtual bool createContent();
/// Determine the class that is a common ancestor to all inspected objects.
AbstractClassRep* findCommonAncestorClass();
};
#endif // _GUI_INSPECTOR_GROUP_H_

View file

@ -0,0 +1,120 @@
//-----------------------------------------------------------------------------
// Copyright (c) 2012 GarageGames, LLC
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//-----------------------------------------------------------------------------
#include "platform/platform.h"
#include "gui/editor/inspector/variableField.h"
#include "gui/buttons/guiIconButtonCtrl.h"
#include "gui/editor/guiInspector.h"
#include "core/util/safeDelete.h"
#include "gfx/gfxDrawUtil.h"
//-----------------------------------------------------------------------------
// GuiInspectorVariableField
//-----------------------------------------------------------------------------
IMPLEMENT_CONOBJECT(GuiInspectorVariableField);
ConsoleDocClass( GuiInspectorVariableField,
"@brief Inspector support for variables in a GuiVariableInspector.\n\n"
"Editor use only.\n\n"
"@internal"
);
GuiInspectorVariableField::GuiInspectorVariableField()
{
}
GuiInspectorVariableField::~GuiInspectorVariableField()
{
}
bool GuiInspectorVariableField::onAdd()
{
setInspectorProfile();
// Hack: skip our immediate parent
if ( !Parent::Parent::onAdd() )
return false;
{
GuiTextEditCtrl *edit = new GuiTextEditCtrl();
edit->setDataField( StringTable->insert("profile"), NULL, "GuiInspectorTextEditProfile" );
edit->registerObject();
char szBuffer[512];
dSprintf( szBuffer, 512, "%d.apply(%d.getText());",getId(), edit->getId() );
edit->setField("AltCommand", szBuffer );
edit->setField("Validate", szBuffer );
mEdit = edit;
}
setBounds(0,0,100,18);
// Add our edit as a child
addObject( mEdit );
// Calculate Caption and EditCtrl Rects
updateRects();
// Force our editField to set it's value
updateValue();
return true;
}
void GuiInspectorVariableField::setData( const char* data, bool callbacks )
{
if ( !mCaption || mCaption[0] == 0 )
return;
Con::setVariable( mCaption, data );
// Force our edit to update
updateValue();
}
const char* GuiInspectorVariableField::getData( U32 inspectObjectIndex )
{
if ( !mCaption || mCaption[0] == 0 )
return "";
return Con::getVariable( mCaption );
}
void GuiInspectorVariableField::setValue( const char* newValue )
{
GuiTextEditCtrl *ctrl = dynamic_cast<GuiTextEditCtrl*>( mEdit );
if( ctrl != NULL )
ctrl->setText( newValue );
}
void GuiInspectorVariableField::updateValue()
{
if ( !mCaption || mCaption[0] == 0 )
return;
setValue( getData() );
}

View file

@ -0,0 +1,62 @@
//-----------------------------------------------------------------------------
// Copyright (c) 2012 GarageGames, LLC
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//-----------------------------------------------------------------------------
#ifndef _GUI_INSPECTOR_VARIABLEFIELD_H_
#define _GUI_INSPECTOR_VARIABLEFIELD_H_
#ifndef _GUI_INSPECTOR_FIELD_H_
#include "gui/editor/inspector/field.h"
#endif
class GuiInspectorGroup;
class GuiInspector;
class GuiInspectorVariableField : public GuiInspectorField
{
friend class GuiInspectorField;
public:
typedef GuiInspectorField Parent;
GuiInspectorVariableField();
virtual ~GuiInspectorVariableField();
DECLARE_CONOBJECT( GuiInspectorVariableField );
DECLARE_CATEGORY( "Gui Editor" );
virtual bool onAdd();
virtual void setValue( const char* newValue );
virtual const char* getValue() { return NULL; }
virtual void updateValue();
virtual void setData( const char* data, bool callbacks = true );
virtual const char* getData( U32 inspectObjectIndex = 0 );
virtual void updateData() {};
protected:
};
#endif // _GUI_INSPECTOR_VARIABLEFIELD_H_

View file

@ -0,0 +1,109 @@
//-----------------------------------------------------------------------------
// Copyright (c) 2012 GarageGames, LLC
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//-----------------------------------------------------------------------------
#include "platform/platform.h"
#include "gui/editor/inspector/variableGroup.h"
#include "gui/editor/inspector/variableField.h"
#include "gui/editor/guiInspector.h"
#include "gui/buttons/guiIconButtonCtrl.h"
#include "console/consoleInternal.h"
extern ExprEvalState gEvalState;
//-----------------------------------------------------------------------------
// GuiInspectorVariableGroup
//-----------------------------------------------------------------------------
//
//
IMPLEMENT_CONOBJECT(GuiInspectorVariableGroup);
ConsoleDocClass( GuiInspectorVariableGroup,
"@brief Inspector support for variable groups in a GuiVariableInspector.\n\n"
"Editor use only.\n\n"
"@internal"
);
GuiInspectorVariableGroup::GuiInspectorVariableGroup()
{
}
GuiInspectorVariableGroup::~GuiInspectorVariableGroup()
{
}
GuiInspectorField* GuiInspectorVariableGroup::constructField( S32 fieldType )
{
return NULL;
}
bool GuiInspectorVariableGroup::inspectGroup()
{
// to prevent crazy resizing, we'll just freeze our stack for a sec..
mStack->freeze(true);
clearFields();
Vector<String> names;
gEvalState.globalVars.exportVariables( mSearchString, &names, NULL );
bool bNewItems = false;
for ( U32 i = 0; i < names.size(); i++ )
{
const String &varName = names[i];
// If the field already exists, just update it
GuiInspectorVariableField *field = dynamic_cast<GuiInspectorVariableField*>( findField( varName ) );
if ( field != NULL )
{
field->updateValue();
continue;
}
bNewItems = true;
field = new GuiInspectorVariableField();
field->init( mParent, this );
field->setInspectorField( NULL, StringTable->insert( varName ) );
if ( field->registerObject() )
{
mChildren.push_back( field );
mStack->addObject( field );
}
else
delete field;
}
mStack->freeze(false);
mStack->updatePanes();
// If we've no new items, there's no need to resize anything!
if( bNewItems == false && !mChildren.empty() )
return true;
sizeToContents();
setUpdate();
return true;
}

View file

@ -0,0 +1,55 @@
//-----------------------------------------------------------------------------
// Copyright (c) 2012 GarageGames, LLC
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//-----------------------------------------------------------------------------
#ifndef _GUI_INSPECTOR_VARIABLEGROUP_H_
#define _GUI_INSPECTOR_VARIABLEGROUP_H_
#ifndef _GUI_INSPECTOR_GROUP_H_
#include "gui/editor/inspector/group.h"
#endif
// Forward refs
class GuiInspector;
class GuiInspectorField;
class GuiInspectorVariableGroup : public GuiInspectorGroup
{
public:
typedef GuiInspectorGroup Parent;
String mSearchString;
GuiInspectorVariableGroup();
virtual ~GuiInspectorVariableGroup();
DECLARE_CONOBJECT(GuiInspectorVariableGroup);
DECLARE_CATEGORY( "Gui Editor" );
virtual GuiInspectorField* constructField( S32 fieldType );
virtual bool inspectGroup();
protected:
};
#endif // _GUI_INSPECTOR_VARIABLEGROUP_H_

View file

@ -0,0 +1,67 @@
//-----------------------------------------------------------------------------
// Copyright (c) 2012 GarageGames, LLC
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//-----------------------------------------------------------------------------
#include "gui/editor/inspector/variableInspector.h"
#include "gui/editor/inspector/variableGroup.h"
GuiVariableInspector::GuiVariableInspector()
{
}
GuiVariableInspector::~GuiVariableInspector()
{
}
IMPLEMENT_CONOBJECT(GuiVariableInspector);
ConsoleDocClass( GuiVariableInspector,
"@brief GUI dedicated to variable viewing/manipulation\n\n"
"Mostly used in console system, internal use only.\n\n"
"@internal"
);
void GuiVariableInspector::loadVars( String searchStr )
{
clearGroups();
GuiInspectorVariableGroup *group = new GuiInspectorVariableGroup();
group->setHeaderHidden( true );
group->setCanCollapse( false );
group->mParent = this;
group->setCaption( "Global Variables" );
group->mSearchString = searchStr;
if( group != NULL )
{
group->registerObject();
mGroups.push_back( group );
addObject( group );
}
//group->inspectGroup();
}
ConsoleMethod( GuiVariableInspector, loadVars, void, 3, 3, "loadVars( searchString )" )
{
object->loadVars( argv[2] );
}

View file

@ -0,0 +1,52 @@
//-----------------------------------------------------------------------------
// Copyright (c) 2012 GarageGames, LLC
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//-----------------------------------------------------------------------------
#ifndef _GUI_VARIABLEINSPECTOR_H_
#define _GUI_VARIABLEINSPECTOR_H_
#ifndef _GUI_INSPECTOR_H_
#include "gui/editor/guiInspector.h"
#endif
class GuiVariableInspector : public GuiInspector
{
typedef GuiInspector Parent;
public:
GuiVariableInspector();
virtual ~GuiVariableInspector();
DECLARE_CONOBJECT( GuiVariableInspector );
DECLARE_CATEGORY( "Gui Editor" );
virtual void inspectObject( SimObject *object ) {}
virtual void loadVars( String searchString );
protected:
};
#endif // _GUI_VARIABLEINSPECTOR_H_