tge/engine/editor/creator.cc
2017-04-17 06:17:10 -06:00

443 lines
12 KiB
C++
Executable File

//-----------------------------------------------------------------------------
// Torque Game Engine
// Copyright (C) GarageGames.com, Inc.
//-----------------------------------------------------------------------------
#include "editor/creator.h"
#include "dgl/dgl.h"
IMPLEMENT_CONOBJECT(CreatorTree);
//------------------------------------------------------------------------------
// Class CreatorTree::Node
//------------------------------------------------------------------------------
CreatorTree::Node::Node() :
mFlags(0),
mParent(0),
mName(0),
mValue(0),
mId(0),
mTab(0)
{
VECTOR_SET_ASSOCIATION(mChildren);
}
CreatorTree::Node::~Node()
{
for(U32 i = 0; i < mChildren.size(); i++)
delete mChildren[i];
}
//------------------------------------------------------------------------------
void CreatorTree::Node::expand(bool exp)
{
if(exp)
{
if(mParent)
mParent->expand(exp);
mFlags.set(Node::Expanded);
}
else if(!isRoot())
{
if(isGroup())
for(U32 i = 0; i < mChildren.size(); i++)
mChildren[i]->expand(exp);
mFlags.clear(Selected);
mFlags.clear(Expanded);
}
}
//------------------------------------------------------------------------------
CreatorTree::Node * CreatorTree::Node::find(S32 id)
{
if(mId == id)
return(this);
if(!isGroup())
return(0);
for(U32 i = 0; i < mChildren.size(); i++)
{
Node * node = mChildren[i]->find(id);
if(node)
return(node);
}
return(0);
}
//------------------------------------------------------------------------------
bool CreatorTree::Node::isFirst()
{
AssertFatal(!isRoot(), "CreatorTree::Node::isFirst - cannot call on root node");
return(this == mParent->mChildren[0]);
}
bool CreatorTree::Node::isLast()
{
AssertFatal(!isRoot(), "CreatorTree::Node::isLast - cannot call on root node");
return(this == mParent->mChildren[mParent->mChildren.size()-1]);
}
bool CreatorTree::Node::hasChildItem()
{
for(U32 i = 0; i < mChildren.size(); i++)
{
if(mChildren[i]->isGroup() && mChildren[i]->hasChildItem())
return(true);
if(!mChildren[i]->isGroup())
return(true);
}
return(false);
}
S32 CreatorTree::Node::getSelected()
{
for(U32 i = 0; i < mChildren.size(); i++)
{
if(mChildren[i]->isSelected())
return(mChildren[i]->mId);
else if(mChildren[i]->isGroup())
{
S32 ret = mChildren[i]->getSelected();
if(ret != -1)
return(ret);
}
}
return(-1);
}
//------------------------------------------------------------------------------
// Class CreatorTree
//------------------------------------------------------------------------------
CreatorTree::CreatorTree() :
mCurId(0),
mTxtOffset(5),
mRoot(0)
{
VECTOR_SET_ASSOCIATION(mNodeList);
clear();
}
CreatorTree::~CreatorTree()
{
delete mRoot;
}
//------------------------------------------------------------------------------
CreatorTree::Node * CreatorTree::createNode(const char * name, const char * value, bool group, Node * parent)
{
Node * node = new Node();
node->mId = mCurId++;
node->mName = name ? StringTable->insert(name) : 0;
node->mValue = value ? StringTable->insert(value) : 0;
node->mFlags.set(Node::Group, group);
// add to the parent group
if(parent)
{
node->mParent = parent;
if(!addNode(parent, node))
{
delete node;
return(0);
}
}
return(node);
}
//------------------------------------------------------------------------------
void CreatorTree::clear()
{
delete mRoot;
mCurId = 0;
mRoot = createNode(0, 0, true);
mRoot->mFlags.set(Node::Root | Node::Expanded);
mSize = Point2I(1,0);
}
//------------------------------------------------------------------------------
bool CreatorTree::addNode(Node * parent, Node * node)
{
if(!parent->isGroup())
return(false);
//
parent->mChildren.push_back(node);
return(true);
}
//------------------------------------------------------------------------------
CreatorTree::Node * CreatorTree::findNode(S32 id)
{
return(mRoot->find(id));
}
//------------------------------------------------------------------------------
void CreatorTree::sort()
{
// groups then items by alpha
}
//------------------------------------------------------------------------------
ConsoleMethod( CreatorTree, addGroup, S32, 4, 4, "(string group, string name, string value)")
{
CreatorTree::Node * grp = object->findNode(dAtoi(argv[2]));
if(!grp || !grp->isGroup())
return(-1);
// return same named group if found...
for(U32 i = 0; i < grp->mChildren.size(); i++)
if(!dStricmp(argv[3], grp->mChildren[i]->mName))
return(grp->mChildren[i]->mId);
CreatorTree::Node * node = object->createNode(argv[3], 0, true, grp);
object->build();
return(node ? node->getId() : -1);
}
ConsoleMethod( CreatorTree, addItem, S32, 5, 5, "(Node group, string name, string value)")
{
CreatorTree::Node * grp = object->findNode(dAtoi(argv[2]));
if(!grp || !grp->isGroup())
return -1;
CreatorTree::Node * node = object->createNode(argv[3], argv[4], false, grp);
object->build();
return(node ? node->getId() : -1);
}
//------------------------------------------------------------------------------
ConsoleMethod( CreatorTree, fileNameMatch, bool, 5, 5, "(string world, string type, string filename)"){
// argv[2] - world short
// argv[3] - type short
// argv[4] - filename
// interior filenames
// 0 - world short ('b', 'x', ...)
// 1-> - type short ('towr', 'bunk', ...)
U32 typeLen = dStrlen(argv[3]);
if(dStrlen(argv[4]) < (typeLen + 1))
return(false);
// world
if(dToupper(argv[4][0]) != dToupper(argv[2][0]))
return(false);
return(!dStrnicmp(argv[4]+1, argv[3], typeLen));
}
ConsoleMethod( CreatorTree, getSelected, S32, 2, 2, "Return a handle to the currently selected item.")
{
return(object->getSelected());
}
ConsoleMethod( CreatorTree, isGroup, bool, 3, 3, "(Group g)")
{
CreatorTree::Node * node = object->findNode(dAtoi(argv[2]));
if(node && node->isGroup())
return(true);
return(false);
}
ConsoleMethod( CreatorTree, getName, const char*, 3, 3, "(Node item)")
{
CreatorTree::Node * node = object->findNode(dAtoi(argv[2]));
return(node ? node->mName : 0);
}
ConsoleMethod( CreatorTree, getValue, const char*, 3, 3, "(Node n)")
{
CreatorTree::Node * node = object->findNode(dAtoi(argv[2]));
return(node ? node->mValue : 0);
}
ConsoleMethod( CreatorTree, clear, void, 2, 2, "Clear the tree.")
{
object->clear();
}
ConsoleMethod( CreatorTree, getParent, S32, 3, 3, "(Node n)")
{
CreatorTree::Node * node = object->findNode(dAtoi(argv[2]));
if(node && node->mParent)
return(node->mParent->getId());
else
return(-1);
}
//------------------------------------------------------------------------------
void CreatorTree::buildNode(Node * node, U32 tab)
{
if(node->isExpanded())
for(U32 i = 0; i < node->mChildren.size(); i++)
{
Node * child = node->mChildren[i];
child->mTab = tab;
child->select(false);
mNodeList.push_back(child);
// grab width
if(bool(mProfile->mFont) && child->mName)
{
S32 width = (tab + 1) * mTabSize + mProfile->mFont->getStrWidth(child->mName) + mTxtOffset;
if(width > mMaxWidth)
mMaxWidth = width;
}
if(node->mChildren[i]->isGroup())
buildNode(node->mChildren[i], tab+1);
}
}
//------------------------------------------------------------------------------
void CreatorTree::build()
{
mMaxWidth = 0;
mNodeList.clear();
buildNode(mRoot, 0);
mCellSize.set( mMaxWidth + 1, 11 );
setSize(Point2I(1, mNodeList.size()));
}
//------------------------------------------------------------------------------
bool CreatorTree::onWake()
{
if(!Parent::onWake())
return(false);
mTabSize = 11;
//
build();
mCellSize.set( mMaxWidth + 1, 11 );
setSize(Point2I(1, mNodeList.size()));
return true;
}
//------------------------------------------------------------------------------
void CreatorTree::onMouseUp(const GuiEvent & event)
{
onAction();
}
void CreatorTree::onMouseDown(const GuiEvent & event)
{
Point2I pos = globalToLocalCoord(event.mousePoint);
bool dblClick = event.mouseClickCount > 1;
// determine cell
Point2I cell(pos.x < 0 ? -1 : pos.x / mCellSize.x, pos.y < 0 ? -1 : pos.y / mCellSize.y);
if(cell.x >= 0 && cell.x < mSize.x && cell.y >= 0 && cell.y < mSize.y)
{
Node * node = mNodeList[cell.y];
S32 offset = mTabSize * node->mTab;
if(node->isGroup() && node->mChildren.size() && pos.x >= offset && pos.x <= (offset + mTabSize))
{
node->expand(!node->isExpanded());
build();
dblClick = false;
}
if(pos.x >= offset)
{
if(dblClick)
node->expand(!node->isExpanded());
build();
node->select(true);
}
}
}
//------------------------------------------------------------------------------
void CreatorTree::onMouseDragged(const GuiEvent & event)
{
event;
}
//------------------------------------------------------------------------------
void CreatorTree::onRenderCell(Point2I offset, Point2I cell, bool, bool) {
Point2I cellOffset = offset;
Node *node = mNodeList[cell.y];
// Get our points
Point2I boxStart( cellOffset.x + mTabSize * node->mTab, cellOffset.y );
boxStart.x += 2;
boxStart.y += 1;
Point2I boxEnd = Point2I( boxStart );
boxEnd.x += 8;
boxEnd.y += 8;
// Start drawing stuff
if( node->isGroup() ) { // If we need a box...
dglDrawRectFill( boxStart, boxEnd, mProfile->mFillColor ); // Box background
dglDrawRect( boxStart, boxEnd, mProfile->mFontColor ); // Border
// Cross line
dglDrawLine( boxStart.x + 2, boxStart.y + 4, boxStart.x + 7, boxStart.y + 4, mProfile->mFontColor );
if( !node->isExpanded() ) // If it's a [+] draw down line
dglDrawLine( boxStart.x + 4, boxStart.y + 2, boxStart.x + 4, boxStart.y + 7, mProfile->mFontColor );
}
else {
// Draw horizontal line
dglDrawLine( boxStart.x + 4, boxStart.y + 4, boxStart.x + 9, boxStart.y + 4, mProfile->mFontColor );
if( !node->isLast() ) // If it's a continuing one, draw a long down line
dglDrawLine( boxStart.x + 4, boxStart.y - 6, boxStart.x + 4, boxStart.y + 10, mProfile->mFontColor );
else // Otherwise, just a small one
dglDrawLine( boxStart.x + 4, boxStart.y - 2, boxStart.x + 4, boxStart.y + 4, mProfile->mFontColor );
}
//draw in all the required continuation lines
Node *parent = node->mParent;
while( !parent->isRoot() ) {
if( !parent->isLast() ) {
dglDrawLine( cellOffset.x + ( parent->mTab * mTabSize ) + 6,
cellOffset.y - 2,
cellOffset.x + ( parent->mTab * mTabSize ) + 6,
cellOffset.y + 11,
mProfile->mFontColor );
}
parent = parent->mParent;
}
ColorI fontColor = mProfile->mFontColor;
if( node->isSelected() )
fontColor = mProfile->mFontColorHL;
else if( node->isGroup() && node->hasChildItem() )
fontColor.set( 128, 0, 0 );
else if( !node->isGroup() )
fontColor.set( 0, 0, 128 );
dglSetBitmapModulation(fontColor); //node->isSelected() ? mProfile->mFontColorHL : mProfile->mFontColor);
dglDrawText( mProfile->mFont,
Point2I( offset.x + mTxtOffset + mTabSize * ( node->mTab + 1 ), offset.y ),
node->mName);
}