📄 guiinspector.cc
字号:
mIsExpanded = true;
mIsAnimating = false;
mCollapsing = true;
mAnimateDestHeight = mBarWidth.y;
mAnimateStep = 1;
mChildHeight = 32;
mCaption = StringTable->insert(groupName);
mTarget = target;
mParent = parent;
}
GuiInspectorGroup::~GuiInspectorGroup()
{
if( !mChildren.empty() )
{
Vector<GuiInspectorField*>::iterator i = mChildren.begin();
for( ; i != mChildren.end(); i++ );
}
}
//////////////////////////////////////////////////////////////////////////
// Persistence
//////////////////////////////////////////////////////////////////////////
void GuiInspectorGroup::initPersistFields()
{
Parent::initPersistFields();
addField("Caption", TypeString, Offset(mCaption, GuiInspectorGroup));
}
//////////////////////////////////////////////////////////////////////////
// Scene Events
//////////////////////////////////////////////////////////////////////////
bool GuiInspectorGroup::onAdd()
{
if( !Parent::onAdd() )
return false;
// Create our field stack control
mStack = new GuiStackControl();
if( !mStack )
return false;
addObject( mStack );
mStack->setField( "padding", "1.0" );
mStack->resize( mBarWidth + Point2I(1,1), mBounds.extent - ( mBarWidth + Point2I(1,1) ) );
inspectGroup();
return true;
}
//////////////////////////////////////////////////////////////////////////
// Mouse Events
//////////////////////////////////////////////////////////////////////////
void GuiInspectorGroup::onMouseDown( const GuiEvent &event )
{
// Calculate Group Caption Rect ( Clip rect within 4 units of the outer bounds so we don't render into border )
RectI captionRect( Point2I(mBarWidth.x, 0), Point2I( mBounds.extent.x - 4, mBarWidth.y ) );
// Calculate Y Offset to center vertically the caption
U32 captionYOffset = mFloor( (F32)( captionRect.extent.y - mProfile->mFont->getHeight() ) / 2 );
// Calculate Expand/Collapse Button Rect
RectI toggleRect( Point2I( captionYOffset, captionYOffset ), mBarWidth - Point2I(captionYOffset * 2, captionYOffset * 2) );
toggleRect.inset( 1,1 );
if( toggleRect.pointInRect( globalToLocalCoord( event.mousePoint ) ) && !mIsAnimating )
{
if( !mIsExpanded )
animateTo( getExpandedHeight() );
else
animateTo( mBarWidth.y );
}
}
//////////////////////////////////////////////////////////////////////////
// Control Sizing Helpers
//////////////////////////////////////////////////////////////////////////
S32 GuiInspectorGroup::getExpandedHeight()
{
if( mStack != NULL && mStack->getCount() != 0 )
return mStack->getHeight() + mBarWidth.y + 1;
return mBarWidth.y;
}
void GuiInspectorGroup::resize( const Point2I &newPosition, const Point2I &newExtent )
{
Parent::resize( newPosition, newExtent );
if( mStack != NULL && !mIsAnimating && mIsExpanded )
mStack->setExtent( mBounds.extent - ( mBarWidth + Point2I(1,1) ) );
}
//////////////////////////////////////////////////////////////////////////
// Control Sizing Animation Functions
//////////////////////////////////////////////////////////////////////////
void GuiInspectorGroup::animateTo( S32 height )
{
// We do nothing if we're already animating
if( mIsAnimating )
return;
bool collapsing = (bool)( mBounds.extent.y > height );
// If we're already at the destination height, bail
if( mBounds.extent.y >= height && !collapsing )
return;
// If we're already at the destination height, bail
if( mBounds.extent.y <= height && collapsing )
return;
// Set destination height
mAnimateDestHeight = height;
// Set Animation Mode
mCollapsing = collapsing;
// Set Animation Step (Increment)
if( collapsing )
mAnimateStep = mFloor( (F32)( mBounds.extent.y - height ) / 2 );
else
mAnimateStep = mFloor( (F32)( height - mBounds.extent.y ) / 2 );
// Start our animation
mIsAnimating = true;
}
void GuiInspectorGroup::processTick()
{
// We do nothing here if we're NOT animating
if( !mIsAnimating )
return;
// We're collapsing ourself down (Hiding our contents)
if( mCollapsing )
{
if( mBounds.extent.y < mAnimateDestHeight )
mBounds.extent.y = mAnimateDestHeight;
else if( ( mBounds.extent.y - mAnimateStep ) < mAnimateDestHeight )
mBounds.extent.y = mAnimateDestHeight;
if( mBounds.extent.y == mAnimateDestHeight )
mIsAnimating = false;
else
mBounds.extent.y -= mAnimateStep;
if( !mIsAnimating )
mIsExpanded = false;
}
else // We're expanding ourself (Showing our contents)
{
if( mBounds.extent.y > mAnimateDestHeight )
mBounds.extent.y = mAnimateDestHeight;
else if( ( mBounds.extent.y + mAnimateStep ) > mAnimateDestHeight )
mBounds.extent.y = mAnimateDestHeight;
if( mBounds.extent.y == mAnimateDestHeight )
mIsAnimating = false;
else
mBounds.extent.y += mAnimateStep;
if( !mIsAnimating )
mIsExpanded = true;
}
GuiControl* parent = getParent();
if( parent )
parent->childResized( this );
}
//////////////////////////////////////////////////////////////////////////
// Control Rendering
//////////////////////////////////////////////////////////////////////////
void GuiInspectorGroup::onRender(Point2I offset, const RectI &updateRect)
{
//////////////////////////////////////////////////////////////////////////
// Calculate Necessary Rendering Rectangles
//////////////////////////////////////////////////////////////////////////
// Calculate actual world bounds for rendering
RectI worldBounds( offset, mBounds.extent );
// Calculate rendering rectangle for the groups content
RectI contentRect( offset + mBarWidth, mBounds.extent - ( mBarWidth + Point2I(1,1) ));
// Calculate Group Caption Rect ( Clip rect within 4 units of the outer bounds so we don't render into border )
RectI captionRect( offset + Point2I(mBarWidth.x, 0), Point2I( mBounds.extent.x - ( mBarWidth.x + 4 ), mBarWidth.y ) );
// Calculate Y Offset to center vertically the caption
U32 captionYOffset = mFloor( (F32)( captionRect.extent.y - mProfile->mFont->getHeight() ) / 2 );
// Calculate Expand/Collapse Button Rect
RectI toggleRect( offset + Point2I( captionYOffset, captionYOffset ), mBarWidth - Point2I(captionYOffset * 2, captionYOffset * 2) );
toggleRect.inset( 1,1 );
// Draw Border
renderFilledBorder( worldBounds, mProfile );
// Draw Content Background
if( mIsExpanded || ( mIsAnimating && !mCollapsing ) )
dglDrawRectFill( contentRect, ColorI(255,255,255) );
// Backup Bitmap Modulation
ColorI currColor;
dglGetBitmapModulation( &currColor );
dglSetBitmapModulation( mProfile->mFontColor );
// Draw Caption ( Vertically Centered )
dglDrawText( mProfile->mFont, Point2I( captionRect.point.x, captionRect.point.y + captionYOffset ), mCaption, &mProfile->mFontColor );
dglSetBitmapModulation( currColor );
// Draw Expand/Collapse Button
if( mIsExpanded )
renderFilledBorder( toggleRect, mProfile->mFillColorNA, mProfile->mBorderColorNA );
else
renderFilledBorder( toggleRect, mProfile->mBorderColorNA, mProfile->mFillColorNA );
Parent::onRender( offset, updateRect );
}
GuiInspectorField* GuiInspectorGroup::constructField( S32 fieldType )
{
ConsoleBaseType *cbt = ConsoleBaseType::getType(fieldType);
AssertFatal(cbt, "GuiInspectorGroup::constructField - could not resolve field type!");
// Alright, is it a datablock?
if(cbt->isDatablock())
{
// This is fairly straightforward to deal with.
GuiInspectorDatablockField *dbFieldClass = new GuiInspectorDatablockField( cbt->getTypeClassName() );
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( StringTableEntry 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;
}
bool GuiInspectorGroup::inspectGroup()
{
// We can't inspect a group without a target!
if( !mTarget )
return false;
bool bNoGroup = false;
// Un-grouped fields are all sorted into the 'general' group
if ( dStricmp( mCaption, "General" ) == 0 )
bNoGroup = true;
AbstractClassRep::FieldList &fieldList = mTarget->getModifiableFieldList();
AbstractClassRep::FieldList::iterator itr;
bool bGrabItems = false;
bool bNewItems = false;
for(itr = fieldList.begin(); itr != fieldList.end(); itr++)
{
if( itr->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( itr->pGroupname != NULL && dStricmp( itr->pGroupname, mCaption ) == 0 )
bGrabItems = true;
continue;
}
else if ( itr->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( itr->pGroupname != NULL && dStricmp( itr->pGroupname, mCaption ) == 0 )
bGrabItems = false;
continue;
}
if( ( bGrabItems == true || ( bNoGroup == true && bGrabItems == false ) ) && itr->type != AbstractClassRep::DepricatedFieldType )
{
if( bNoGroup == true && bGrabItems == true )
continue;
// If the field already exists, just update it
GuiInspectorField *field = findField( itr->pFieldname );
if( field != NULL )
{
field->updateValue( field->getData() );
continue;
}
bNewItems = true;
field = constructField( itr->type );
if( field == NULL )
field = new GuiInspectorField( this, mTarget, itr );
else
{
field->setTarget( mTarget );
field->setParent( this );
field->setField( itr );
}
field->registerObject();
mChildren.push_back( field );
mStack->addObject( field );
}
}
// If we've no new items, there's no need to resize anything!
if( bNewItems == false && !mChildren.empty() )
return true;
if( mIsExpanded && getHeight() != getExpandedHeight() )
setHeight( getExpandedHeight() );
if( mChildren.empty() && getHeight() != mBarWidth.y )
setHeight( mBarWidth.y );
setUpdate();
return true;
}
//////////////////////////////////////////////////////////////////////////
// GuiInspectorDynamicGroup - inspectGroup override
//////////////////////////////////////////////////////////////////////////
bool GuiInspectorDynamicGroup::inspectGroup()
{
// We can't inspect a group without a target!
if( !mTarget )
return false;
// 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();
// Then populate with fields
SimFieldDictionary * fieldDictionary = mTarget->getFieldDictionary();
for(SimFieldDictionaryIterator ditr(fieldDictionary); *ditr; ++ditr)
{
SimFieldDictionary::Entry * entry = (*ditr);
GuiInspectorField *field = new GuiInspectorDynamicField( this, mTarget, entry );
if( field != NULL )
{
field->registerObject();
mChildren.push_back( field );
mStack->addObject( field );
}
}
if( mIsExpanded && getHeight() != getExpandedHeight() )
setHeight( getExpandedHeight() );
setUpdate();
return true;
}
void GuiInspectorDynamicGroup::clearFields()
{
// If we have no groups, it couldn't possibly exist
if( mChildren.empty() )
return;
// Attempt to find it in the group list
Vector<GuiInspectorField*>::iterator i = mChildren.begin();
for( ; i != mChildren.end(); i++ )
if( (*i)->isProperlyAdded() )
(*i)->deleteObject();
mChildren.clear();
}
SimFieldDictionary::Entry* GuiInspectorDynamicGroup::findDynamicFieldInDictionary( StringTableEntry fieldName )
{
if( !mTarget )
return false;
SimFieldDictionary * fieldDictionary = mTarget->getFieldDictionary();
for(SimFieldDictionaryIterator ditr(fieldDictionary); *ditr; ++ditr)
{
SimFieldDictionary::Entry * entry = (*ditr);
if( dStricmp( entry->slotName, fieldName ) == 0 )
return entry;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -