📄 guitreeviewctrl.cc
字号:
#include "core/frameAllocator.h"
#include "gui/controls/guiTreeViewCtrl.h"
#include "gui/containers/guiScrollCtrl.h"
#include "console/consoleTypes.h"
#include "console/console.h"
#include "dgl/dgl.h"
#include "gui/core/guiTypes.h"
#include "platform/event.h"
#include "editor/worldEditor.h"
#include "sim/sceneObject.h"
#include "gui/core/guiDefaultControlRender.h"
IMPLEMENT_CONOBJECT(GuiTreeViewCtrl);
GuiTreeViewCtrl::Item::Item()
{
// Just null our memory, it's safest!
mState = 0;
mScriptInfo.mText = 0;
mScriptInfo.mValue = 0;
}
GuiTreeViewCtrl::Item::~Item()
{
if(mState.test(InspectorData))
{
// DO NO THING
}
else
{
if ( getText() )
{
delete [] getText();
setText(NULL);
}
if ( getValue() )
{
delete [] getValue();
setValue( NULL );
}
}
}
void GuiTreeViewCtrl::Item::setNormalImage(S8 id)
{
if(mState.test(InspectorData))
{
Con::errorf("Tried to set normal image %d for item %d, which is InspectorData!", id, mId);
return;
}
mScriptInfo.mNormalImage = id;
}
void GuiTreeViewCtrl::Item::setExpandedImage(S8 id)
{
if(mState.test(InspectorData))
{
Con::errorf("Tried to set expanded image %d for item %d, which is InspectorData!", id, mId);
return;
}
mScriptInfo.mExpandedImage = id;
}
void GuiTreeViewCtrl::Item::setText(char *txt)
{
if(mState.test(InspectorData))
{
Con::errorf("Tried to set text for item %d, which is InspectorData!", mId);
return;
}
mScriptInfo.mText = txt;
}
void GuiTreeViewCtrl::Item::setValue(const char *val)
{
if(mState.test(InspectorData))
{
Con::errorf("Tried to set value for item %d, which is InspectorData!", mId);
return;
}
mScriptInfo.mValue = const_cast<char*>(val); // mValue really ought to be a StringTableEntry
}
const S8 GuiTreeViewCtrl::Item::getNormalImage() const
{
if(mState.test(InspectorData))
{
Con::errorf("Tried to get the normal image for item %d, which is InspectorData!", mId);
return 0; // fail safe for width determinations
}
return mScriptInfo.mNormalImage;
}
const S8 GuiTreeViewCtrl::Item::getExpandedImage() const
{
if(mState.test(InspectorData))
{
Con::errorf("Tried to get the expanded image for item %d, which is InspectorData!", mId);
return 0; // fail safe for width determinations
}
return mScriptInfo.mExpandedImage;
}
char *GuiTreeViewCtrl::Item::getText()
{
if(mState.test(InspectorData))
{
Con::errorf("Tried to get the text for item %d, which is InspectorData!", mId);
return NULL;
}
return mScriptInfo.mText;
}
char *GuiTreeViewCtrl::Item::getValue()
{
if(mState.test(InspectorData))
{
Con::errorf("Tried to get the value for item %d, which is InspectorData!", mId);
return NULL;
}
return mScriptInfo.mValue;
}
void GuiTreeViewCtrl::Item::setObject(SimObject *obj)
{
if(!mState.test(InspectorData))
{
Con::errorf("Tried to set the object for item %d, which is not InspectorData!", mId);
return;
}
mInspectorInfo.mObject = obj;
}
SimObject *GuiTreeViewCtrl::Item::getObject()
{
if(!mState.test(InspectorData))
{
Con::errorf("Tried to get the object for item %d, which is not InspectorData!", mId);
return NULL;
}
return mInspectorInfo.mObject;
}
const U32 GuiTreeViewCtrl::Item::getDisplayTextLength()
{
if(mState.test(Item::InspectorData))
{
SimObject *obj = getObject();
if(!obj)
return 0;
// For the results buffer, it's prefix along with a bunch of other stuff.
// So we'll be mostly accurate and add a bit of fudge.
return (16
+ (obj->getName() ? dStrlen(obj->getName()) : 0) + dStrlen(obj->getClassName())
+ dStrlen(obj->getIdString()) + 20
);
}
else
{
return dStrlen(getText());
}
// Should never be here. (This useful comment provided by BJG)
}
void GuiTreeViewCtrl::Item::getDisplayText(U32 bufLen, char *buf)
{
FrameAllocatorMarker txtAlloc;
char *displayText = NULL;
if(mState.test(Item::InspectorData))
{
// Inspector data!
SimObject *obj = getObject();
if(obj)
{
// For the prefix, max size is 3 + 1 + 3 + 1 = 8, so 16 for safety
char *prefix = (char*)txtAlloc.alloc(16);
// Alright, let's get some info...
bool isH = obj->isHidden();
bool isL = obj->isLocked();
// z - not really used.
// Calculate prefix string. (BJG TODO - simpler to have lookup table?)
dSprintf(prefix, sizeof(prefix), "%s%s%s%s",
(isH ? "" : ""),
(isH && isL ? "" : ""),
(isL ? "" : ""),
(isL || isH ? "" : "")
);
#ifdef TGE_RPG_UI ///
dSprintf(buf, bufLen, "%s%d%s%s(%s)", prefix,
obj->getId(),
obj->getName() ? "," : "",
obj->getName() ? obj->getName() : "",
obj->getClassName()
);
#else
dSprintf(buf, bufLen, "%s%d: %s - %s", prefix,
obj->getId(),
obj->getName() ? obj->getName() : "",
obj->getClassName()
);
#endif
}
}
else
{
// Script data! (copy it in)
dStrncpy(buf, getText(), bufLen);
}
}
const S32 GuiTreeViewCtrl::Item::getDisplayTextWidth(GFont *font)
{
FrameAllocatorMarker txtAlloc;
U32 bufLen = getDisplayTextLength();
char *buf = (char*)txtAlloc.alloc(bufLen);
getDisplayText(bufLen, buf);
return font->getStrWidth(buf);
}
const bool GuiTreeViewCtrl::Item::isParent() const
{
if(mState.test(VirtualParent))
{
if( !isInspectorData() )
return true;
// Does our object have any children?
if(mInspectorInfo.mObject)
{
SimSet *s = dynamic_cast<SimSet*>( (SimObject*)mInspectorInfo.mObject);
if (s->size() > 0)
return s->size();
}
}
// Otherwise, just return whether the child list is populated.
return mChild;
}
const bool GuiTreeViewCtrl::Item::isExpanded() const
{
if(mState.test(InspectorData))
return mInspectorInfo.mObject ? mInspectorInfo.mObject->isExpanded() : false;
else
return mState.test(Expanded);
}
void GuiTreeViewCtrl::Item::setExpanded(bool f)
{
if(mState.test(InspectorData))
mInspectorInfo.mObject->setExpanded(f);
else
mState.set(Expanded, f);
}
void GuiTreeViewCtrl::Item::setVirtualParent( bool value )
{
mState.set(VirtualParent, value);
}
GuiTreeViewCtrl::Item *GuiTreeViewCtrl::Item::findChildByValue(const SimObject *obj)
{
// Iterate over our children and try to find the given
// SimObject
Item *res = mChild;
while(res)
{
// Skip non-inspector data stuff.
if(res->mState.test(InspectorData))
{
if(res->getObject() == obj)
break; // Whoa.
}
res = res->mNext;
}
// If the loop terminated we are NULL, otherwise we have the result in res.
return res;
}
GuiTreeViewCtrl::Item *GuiTreeViewCtrl::Item::findChildByValue( StringTableEntry Value )
{
// Iterate over our children and try to find the given Value
// Note : This is a case-insensitive search
Item *res = mChild;
while(res)
{
// check the script value of the item against the specified value
if( dStricmp( res->mScriptInfo.mValue, Value ) == 0 )
return res;
res = res->mNext;
}
// If the loop terminated we didn't find an item with the specified script value
return NULL;
}
//------------------------------------------------------------------------------
GuiTreeViewCtrl::GuiTreeViewCtrl()
{
VECTOR_SET_ASSOCIATION(mItems);
VECTOR_SET_ASSOCIATION(mVisibleItems);
VECTOR_SET_ASSOCIATION(mSelectedItems);
VECTOR_SET_ASSOCIATION(mSelected);
mItemFreeList = 0;
mRoot = 0;
mInstantGroup = 0;
mItemCount = 0;
mSelectedItem = 0;
mStart = 0;
mDraggedToItem = 0;
mOldDragY = 0;
mCurrentDragCell = 0;
mPreviousDragCell = 0;
mDragMidPoint = NomDragMidPoint;
mMouseDragged = false;
mDebug = false;
// persist info..
mTabSize = 16;
mTextOffset = 2;
mFullRowSelect = false;
mItemHeight = 20;
//
setSize(Point2I(1, 0));
// Set up default state
mFlags.set(ShowTreeLines);
mFlags.set(IsEditable, false);
mFlags.set(IsDeletable);
mDestroyOnSleep = true;
mSupportMouseDragging = true;
mMultipleSelections = true;
}
GuiTreeViewCtrl::~GuiTreeViewCtrl()
{
destroyTree();
}
//------------------------------------------------------------------------------
void GuiTreeViewCtrl::initPersistFields()
{
Parent::initPersistFields();
addGroup("TreeView");
addField("tabSize", TypeS32, Offset(mTabSize, GuiTreeViewCtrl));
addField("textOffset", TypeS32, Offset(mTextOffset, GuiTreeViewCtrl));
addField("fullRowSelect", TypeBool, Offset(mFullRowSelect, GuiTreeViewCtrl));
addField("itemHeight", TypeS32, Offset(mItemHeight, GuiTreeViewCtrl));
addField("destroyTreeOnSleep", TypeBool, Offset(mDestroyOnSleep, GuiTreeViewCtrl));
addField("MouseDragging", TypeBool, Offset(mSupportMouseDragging, GuiTreeViewCtrl));
addField("MultipleSelections", TypeBool, Offset(mMultipleSelections, GuiTreeViewCtrl));
endGroup("TreeView");
}
//------------------------------------------------------------------------------
GuiTreeViewCtrl::Item * GuiTreeViewCtrl::getItem(S32 itemId)
{
if((itemId > 0) && (itemId <= mItems.size()))
return(mItems[itemId-1]);
return(0);
}
//------------------------------------------------------------------------------
GuiTreeViewCtrl::Item * GuiTreeViewCtrl::createItem(S32 icon)
{
Item * item;
// grab from the free list?
if(mItemFreeList)
{
item = mItemFreeList;
mItemFreeList = item->mNext;
// re-add to vector
mItems[item->mId-1] = item;
}
else
{
item = new Item;
mItems.push_back(item);
// set the id
item->mId = mItems.size();
}
// reset
if (icon)
item->mIcon = icon;
else
item->mIcon = Default; //default icon to stick next to an item
item->mNext = item->mPrevious = item->mParent = item->mChild = 0;
item->mState.clear();
item->setText(0);
item->setValue(0);
item->mState = 0;
item->mTabLevel = 0;
mItemCount++;
return(item);
}
//------------------------------------------------------------------------------
void GuiTreeViewCtrl::destroyChildren(Item * item, Item * parent)
{
if (!item || item == parent)
return;
if (item->isParent())
destroyChildren(item->mChild, parent);
else if(item->mNext)
destroyChildren(item->mNext, parent);
else
{
// destroy the item and back up
Item * prevItem = item->mPrevious;
destroyItem(item);
destroyChildren(prevItem, parent);
}
}
void GuiTreeViewCtrl::destroyItem(Item * item)
{
if(!item)
return;
if(item->isInspectorData())
{
// make sure the SimObjectPtr is clean!
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -