123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262 |
- //-----------------------------------------------------------------------------
- // 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"
- #include "console/engineAPI.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(StringTable->insert("ToolsModule:iconAdd_image"));
- 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()
- {
- if( !mParent )
- return false;
- // 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();
- }
- DefineEngineMethod(GuiInspectorDynamicGroup, inspectGroup, bool, (), , "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();
- }
- DefineEngineMethod( GuiInspectorDynamicGroup, addDynamicField, void, (), , "obj.addDynamicField();" )
- {
- object->addDynamicField();
- }
- DefineEngineMethod( GuiInspectorDynamicGroup, removeDynamicField, void, (), , "" )
- {
- }
|