📄 guiinspector.cc
字号:
//-----------------------------------------------------------------------------
// Torque Game Engine
// Copyright (C) GarageGames.com, Inc.
//-----------------------------------------------------------------------------
#include "gui/editor/guiInspector.h"
#include "core/frameAllocator.h"
//////////////////////////////////////////////////////////////////////////
// GuiInspector
//////////////////////////////////////////////////////////////////////////
// The GuiInspector Control houses the body of the inspector.
// It is not exposed as a conobject because it merely does the grunt work
// and is only meant to be used when housed by a scroll control. Therefore
// the GuiInspector control is a scroll control that creates it's own
// content. That content being of course, the GuiInspector control.
IMPLEMENT_CONOBJECT(GuiInspector);
GuiInspector::GuiInspector()
{
mGroups.clear();
mTarget = NULL;
}
GuiInspector::~GuiInspector()
{
clearGroups();
}
bool GuiInspector::onAdd()
{
if( !Parent::onAdd() )
return false;
return true;
}
//////////////////////////////////////////////////////////////////////////
// Handle Parent Sizing (We constrain ourself to our parents width)
//////////////////////////////////////////////////////////////////////////
void GuiInspector::parentResized(const Point2I &oldParentExtent, const Point2I &newParentExtent)
{
GuiControl *parent = getParent();
if( parent && dynamic_cast<GuiScrollCtrl*>(parent) != NULL )
{
GuiScrollCtrl *scroll = dynamic_cast<GuiScrollCtrl*>(parent);
setWidth( ( newParentExtent.x - ( scroll->scrollBarThickness() + 4 ) ) );
}
else
Parent::parentResized(oldParentExtent,newParentExtent);
}
bool GuiInspector::findExistentGroup( StringTableEntry groupName )
{
// If we have no groups, it couldn't possibly exist
if( mGroups.empty() )
return false;
// 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 true;
}
return false;
}
void GuiInspector::clearGroups()
{
// If we have no groups, there's nothing to clear!
if( mGroups.empty() )
return;
// Attempt to find it in the group list
Vector<GuiInspectorGroup*>::iterator i = mGroups.begin();
for( ; i != mGroups.end(); i++ )
if( (*i)->isProperlyAdded() )
(*i)->deleteObject();
mGroups.clear();
}
void GuiInspector::inspectObject( SimObject *object )
{
// If our target is the same as our current target, just update the groups.
if( mTarget == object )
{
Vector<GuiInspectorGroup*>::iterator i = mGroups.begin();
for ( ; i != mGroups.end(); i++ )
(*i)->inspectGroup();
return;
}
// Clear our current groups
clearGroups();
// Set Target
mTarget = object;
// Always create the 'general' group (for un-grouped fields)
GuiInspectorGroup* general = new GuiInspectorGroup( mTarget, "General", this );
if( general != NULL )
{
general->registerObject();
mGroups.push_back( general );
addObject( general );
}
// Grab this objects field list
AbstractClassRep::FieldList &fieldList = mTarget->getModifiableFieldList();
AbstractClassRep::FieldList::iterator itr;
// Iterate through, identifying the groups and create necessary GuiInspectorGroups
for(itr = fieldList.begin(); itr != fieldList.end(); itr++)
{
if(itr->type == AbstractClassRep::StartGroupFieldType && !findExistentGroup( itr->pGroupname ) )
{
GuiInspectorGroup *group = new GuiInspectorGroup( mTarget, itr->pGroupname, this );
if( group != NULL )
{
group->registerObject();
mGroups.push_back( group );
addObject( group );
}
}
}
// Deal with dynamic fields
GuiInspectorGroup *dynGroup = new GuiInspectorDynamicGroup( mTarget, "Dynamic Fields", this);
if( dynGroup != NULL )
{
dynGroup->registerObject();
mGroups.push_back( dynGroup );
addObject( dynGroup );
}
// If the general group is still empty at this point, kill it.
for(S32 i=0; i<mGroups.size(); i++)
{
if(mGroups[i] == general && general->mStack->size() == 0)
{
mGroups.erase(i);
general->deleteObject();
updatePanes();
}
}
}
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->clearGroups();
return;
}
object->inspectObject(target);
}
void GuiInspector::setName( StringTableEntry newName )
{
if( mTarget == NULL )
{
Con::warnf("GuiInspector::setName - No Target!" );
return;
}
StringTableEntry name = StringTable->insert(newName);
// Only assign a new name if we provide one
mTarget->assignName(name);
}
ConsoleMethod( GuiInspector, setName, void, 3, 3, "setName(NewObjectName)")
{
object->setName(argv[2]);
}
//////////////////////////////////////////////////////////////////////////
// GuiInspectorField
//////////////////////////////////////////////////////////////////////////
// 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.
IMPLEMENT_CONOBJECT(GuiInspectorField);
// Caption width is in percentage of total width
S32 GuiInspectorField::smCaptionWidth = 35;
GuiInspectorField::GuiInspectorField( GuiInspectorGroup* parent, SimObjectPtr<SimObject> target, AbstractClassRep::Field* field )
{
if( field != NULL )
mCaption = StringTable->insert( field->pFieldname );
else
mCaption = StringTable->insert( "" );
mParent = parent;
mTarget = target;
mField = field;
mBounds.set(0,0,100,20);
}
GuiInspectorField::GuiInspectorField()
{
mCaption = StringTable->insert( "" );
mParent = NULL;
mTarget = NULL;
mField = NULL;
mBounds.set(0,0,100,20);
}
GuiInspectorField::~GuiInspectorField()
{
}
//////////////////////////////////////////////////////////////////////////
// Get/Set Data Functions
//////////////////////////////////////////////////////////////////////////
void GuiInspectorField::setData( StringTableEntry data )
{
if( mField == NULL || mTarget == NULL )
return;
mTarget->inspectPreApply();
mTarget->setDataField( getFieldName(), NULL, data );
// Force our edit to update
updateValue( data );
mTarget->inspectPostApply();
}
StringTableEntry GuiInspectorField::getData()
{
if( mField == NULL || mTarget == NULL )
return "";
return mTarget->getDataField( getFieldName(), NULL );
}
//////////////////////////////////////////////////////////////////////////
// Overrideables for custom edit fields
//////////////////////////////////////////////////////////////////////////
GuiControl* GuiInspectorField::constructEditControl()
{
GuiControl* retCtrl = new GuiTextEditCtrl();
// If we couldn't construct the control, bail!
if( retCtrl == NULL )
return retCtrl;
// Let's make it look pretty.
retCtrl->setField( "profile", "GuiInspectorTextEditProfile" );
// Don't forget to register ourselves
registerEditControl( retCtrl );
char szBuffer[512];
dSprintf( szBuffer, 512, "%d.apply(%d.getText());",getId(), retCtrl->getId() );
retCtrl->setField("AltCommand", szBuffer );
retCtrl->setField("Validate", szBuffer );
return retCtrl;
}
void GuiInspectorField::registerEditControl( GuiControl *ctrl )
{
char szName[512];
dSprintf( szName, 512, "IE_%s_%d_Field", ctrl->getClassName(), mTarget->getId());
// Register the object
ctrl->registerObject( szName );
}
void GuiInspectorField::onRender(Point2I offset, const RectI &updateRect)
{
RectI worldRect( offset, mBounds.extent );
// Calculate Caption Rect
RectI captionRect( offset , Point2I( mFloor( mBounds.extent.x * (F32)( (F32)GuiInspectorField::smCaptionWidth / 100.0 ) ), mBounds.extent.y ) );
// Calculate Edit Field Rect
RectI editFieldRect( offset + Point2I( captionRect.extent.x + 1, 0 ) , Point2I( mBounds.extent.x - ( captionRect.extent.x + 5 ) , mBounds.extent.y ) );
// Calculate Y Offset to center vertically the caption
U32 captionYOffset = mFloor( (F32)( captionRect.extent.y - mProfile->mFont->getHeight() ) / 2 );
renderFilledBorder( captionRect, mProfile->mBorderColor, mProfile->mFillColor );
renderFilledBorder( editFieldRect, mProfile->mBorderColor, mProfile->mFillColor );
RectI clipRect = dglGetClipRect();
if( clipRect.intersect( captionRect ) )
{
// Backup Bitmap Modulation
ColorI currColor;
dglGetBitmapModulation( &currColor );
dglSetBitmapModulation( mProfile->mFontColor );
dglSetClipRect( RectI( clipRect.point, Point2I( captionRect.extent.x, clipRect.extent.y ) ));
// Draw Caption ( Vertically Centered )
dglDrawText( mProfile->mFont, Point2I( captionRect.point.x + 6 , captionRect.point.y + captionYOffset ), mCaption, &mProfile->mFontColor );
dglSetBitmapModulation( currColor );
dglSetClipRect( clipRect );
}
Parent::onRender( offset, updateRect );
}
bool GuiInspectorField::onAdd()
{
if( !Parent::onAdd() )
return false;
mEdit = constructEditControl();
if( mEdit == NULL )
return false;
// Add our edit as a child
addObject( mEdit );
// Calculate Caption Rect
RectI captionRect( mBounds.point , Point2I( mFloor( mBounds.extent.x * (F32)( (F32)GuiInspectorField::smCaptionWidth / 100.0 ) ), mBounds.extent.y ) );
// Calculate Edit Field Rect
RectI editFieldRect( Point2I( captionRect.extent.x + 1, 0 ) , Point2I( mBounds.extent.x - ( captionRect.extent.x + 5 ) , mBounds.extent.y ) );
// Resize to fit properly in allotted space
mEdit->resize( editFieldRect.point, editFieldRect.extent );
// Prefer GuiInspectorFieldProfile
SimObject *profilePtr = Sim::findObject("GuiInspectorFieldProfile");
if( profilePtr != NULL )
setControlProfile( dynamic_cast<GuiControlProfile*>(profilePtr) );
// Force our editField to set it's value
updateValue( getData() );
return true;
}
void GuiInspectorField::updateValue( StringTableEntry newValue )
{
GuiTextEditCtrl *ctrl = dynamic_cast<GuiTextEditCtrl*>( mEdit );
if( ctrl != NULL )
ctrl->setText( newValue );
}
ConsoleMethod( GuiInspectorField, apply, void, 3,3, "apply(newValue);" )
{
object->setData( argv[2] );
}
void GuiInspectorField::resize( const Point2I &newPosition, const Point2I &newExtent )
{
Parent::resize( newPosition, newExtent );
if( mEdit != NULL )
{
// Calculate Caption Rect
RectI captionRect( mBounds.point , Point2I( mFloor( mBounds.extent.x * (F32)( (F32)GuiInspectorField::smCaptionWidth / 100.0 ) ), mBounds.extent.y ) );
// Calculate Edit Field Rect
RectI editFieldRect( Point2I( captionRect.extent.x + 1, 0 ) , Point2I( mBounds.extent.x - ( captionRect.extent.x + 5 ) , mBounds.extent.y ) );
mEdit->resize( editFieldRect.point, editFieldRect.extent );
}
}
//////////////////////////////////////////////////////////////////////////
// GuiInspectorGroup
//////////////////////////////////////////////////////////////////////////
//
// 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
//
//
//
IMPLEMENT_CONOBJECT(GuiInspectorGroup);
GuiInspectorGroup::GuiInspectorGroup()
{
mBounds.set(0,0,200,20);
mBarWidth.set(18,18);
mChildren.clear();
mCaption = StringTable->insert("");
mTarget = NULL;
mParent = NULL;
mIsExpanded = true;
mIsAnimating = false;
mCollapsing = true;
mAnimateDestHeight = mBarWidth.y;
mAnimateStep = 1;
}
GuiInspectorGroup::GuiInspectorGroup( SimObjectPtr<SimObject> target, StringTableEntry groupName, SimObjectPtr<GuiInspector> parent )
{
mBounds.set(0,0,200,20);
mBarWidth.set(18,18);
mChildren.clear();
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -