dynamicGroup.cpp
Engine/source/gui/editor/inspector/dynamicGroup.cpp
Classes:
class
Public Functions
compareEntries(const void * a, const void * b)
ConsoleDocClass(GuiInspectorDynamicGroup , "@brief Used <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> inspect an object's FieldDictionary (dynamic fields) instead " "of regular persistent <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">fields.\n\n</a>" "Editor use <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">only.\n\n</a>" "@internal" )
DefineConsoleMethod(GuiInspectorDynamicGroup , addDynamicField , void , () , "obj.addDynamicField();" )
DefineConsoleMethod(GuiInspectorDynamicGroup , inspectGroup , bool , () , "Refreshes the dynamic fields in the inspector." )
DefineConsoleMethod(GuiInspectorDynamicGroup , removeDynamicField , void , () , "" )
Detailed Description
Public Functions
compareEntries(const void * a, const void * b)
ConsoleDocClass(GuiInspectorDynamicGroup , "@brief Used <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> inspect an object's FieldDictionary (dynamic fields) instead " "of regular persistent <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">fields.\n\n</a>" "Editor use <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">only.\n\n</a>" "@internal" )
DefineConsoleMethod(GuiInspectorDynamicGroup , addDynamicField , void , () , "obj.addDynamicField();" )
DefineConsoleMethod(GuiInspectorDynamicGroup , inspectGroup , bool , () , "Refreshes the dynamic fields in the inspector." )
DefineConsoleMethod(GuiInspectorDynamicGroup , removeDynamicField , void , () , "" )
IMPLEMENT_CONOBJECT(GuiInspectorDynamicGroup )
1 2//----------------------------------------------------------------------------- 3// Copyright (c) 2012 GarageGames, LLC 4// 5// Permission is hereby granted, free of charge, to any person obtaining a copy 6// of this software and associated documentation files (the "Software"), to 7// deal in the Software without restriction, including without limitation the 8// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 9// sell copies of the Software, and to permit persons to whom the Software is 10// furnished to do so, subject to the following conditions: 11// 12// The above copyright notice and this permission notice shall be included in 13// all copies or substantial portions of the Software. 14// 15// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 21// IN THE SOFTWARE. 22//----------------------------------------------------------------------------- 23 24#include "gui/buttons/guiIconButtonCtrl.h" 25#include "gui/editor/guiInspector.h" 26#include "gui/editor/inspector/dynamicGroup.h" 27#include "gui/editor/inspector/dynamicField.h" 28#include "console/engineAPI.h" 29 30#ifdef TORQUE_EXPERIMENTAL_EC 31#include "T3D/components/component.h" 32#endif 33 34IMPLEMENT_CONOBJECT(GuiInspectorDynamicGroup); 35 36ConsoleDocClass( GuiInspectorDynamicGroup, 37 "@brief Used to inspect an object's FieldDictionary (dynamic fields) instead " 38 "of regular persistent fields.\n\n" 39 "Editor use only.\n\n" 40 "@internal" 41); 42 43//----------------------------------------------------------------------------- 44// GuiInspectorDynamicGroup - add custom controls 45//----------------------------------------------------------------------------- 46bool GuiInspectorDynamicGroup::createContent() 47{ 48 if(!Parent::createContent()) 49 return false; 50 51 // encapsulate the button in a dummy control. 52 GuiControl* shell = new GuiControl(); 53 shell->setDataField( StringTable->insert("profile"), NULL, "GuiTransparentProfile" ); 54 if( !shell->registerObject() ) 55 { 56 delete shell; 57 return false; 58 } 59 60 // add a button that lets us add new dynamic fields. 61 GuiBitmapButtonCtrl* addFieldBtn = new GuiBitmapButtonCtrl(); 62 { 63 SimObject* profilePtr = Sim::findObject("InspectorDynamicFieldButton"); 64 if( profilePtr != NULL ) 65 addFieldBtn->setControlProfile( dynamic_cast<GuiControlProfile*>(profilePtr) ); 66 67 // FIXME Hardcoded image 68 addFieldBtn->setBitmap("tools/gui/images/iconAdd.png"); 69 70 char commandBuf[64]; 71 dSprintf(commandBuf, 64, "%d.addDynamicField();", this->getId()); 72 addFieldBtn->setField("command", commandBuf); 73 addFieldBtn->setSizing(horizResizeLeft,vertResizeCenter); 74 //addFieldBtn->setField("buttonMargin", "2 2"); 75 addFieldBtn->resize(Point2I(getWidth() - 20,2), Point2I(16, 16)); 76 addFieldBtn->registerObject("zAddButton"); 77 } 78 79 shell->resize(Point2I(0,0), Point2I(getWidth(), 28)); 80 shell->addObject(addFieldBtn); 81 82 // save off the shell control, so we can push it to the bottom of the stack in inspectGroup() 83 mAddCtrl = shell; 84 mStack->addObject(shell); 85 86 return true; 87} 88 89struct FieldEntry 90{ 91 SimFieldDictionary::Entry* mEntry; 92 U32 mNumTargets; 93}; 94 95static S32 QSORT_CALLBACK compareEntries(const void* a,const void* b) 96{ 97 FieldEntry& fa = *((FieldEntry *)a); 98 FieldEntry& fb = *((FieldEntry *)b); 99 return dStrnatcmp(fa.mEntry->slotName, fb.mEntry->slotName); 100} 101 102//----------------------------------------------------------------------------- 103// GuiInspectorDynamicGroup - inspectGroup override 104//----------------------------------------------------------------------------- 105bool GuiInspectorDynamicGroup::inspectGroup() 106{ 107 if( !mParent ) 108 return false; 109 110 // clear the first responder if it's set 111 mStack->clearFirstResponder(); 112 113 // Clearing the fields and recreating them will more than likely be more 114 // efficient than looking up existent fields, updating them, and then iterating 115 // over existent fields and making sure they still exist, if not, deleting them. 116 clearFields(); 117 118 // Create a vector of the fields 119 Vector< FieldEntry> flist; 120 121 const U32 numTargets = mParent->getNumInspectObjects(); 122 for( U32 i = 0; i < numTargets; ++ i ) 123 { 124 SimObject* target = mParent->getInspectObject( i ); 125 126 // Then populate with fields 127 SimFieldDictionary * fieldDictionary = target->getFieldDictionary(); 128 for(SimFieldDictionaryIterator ditr(fieldDictionary); *ditr; ++ditr) 129 { 130#ifdef TORQUE_EXPERIMENTAL_EC 131 if (target->getClassRep()->isSubclassOf("Component")) 132 { 133 Component* compTarget = dynamic_cast<Component*>(target); 134 135 ComponentField* compField = compTarget->getComponentField((*ditr)->slotName); 136 if (compField) 137 continue; 138 } 139#endif 140 if( i == 0 ) 141 { 142 flist.increment(); 143 flist.last().mEntry = *ditr; 144 flist.last().mNumTargets = 1; 145 } 146 else 147 { 148 const U32 numFields = flist.size(); 149 for( U32 n = 0; n < numFields; ++ n ) 150 if( flist[ n ].mEntry->slotName == ( *ditr )->slotName ) 151 { 152 flist[ n ].mNumTargets ++; 153 break; 154 } 155 } 156 } 157 } 158 159 dQsort( flist.address(), flist.size(), sizeof( FieldEntry ), compareEntries ); 160 161 for(U32 i = 0; i < flist.size(); i++) 162 { 163 if( flist[ i ].mNumTargets != numTargets ) 164 continue; 165 166 SimFieldDictionary::Entry* entry = flist[i].mEntry; 167 168 // Create a dynamic field inspector. Can't reuse typed GuiInspectorFields as 169 // these rely on AbstractClassRep::Fields. 170 GuiInspectorDynamicField *field = new GuiInspectorDynamicField( mParent, this, entry ); 171 172 // Register the inspector field and add it to our lists 173 if( field->registerObject() ) 174 { 175 mChildren.push_back( field ); 176 mStack->addObject( field ); 177 } 178 else 179 delete field; 180 } 181 182 mStack->pushObjectToBack(mAddCtrl); 183 184 setUpdate(); 185 186 return true; 187} 188 189void GuiInspectorDynamicGroup::updateAllFields() 190{ 191 // We overload this to just reinspect the group. 192 inspectGroup(); 193} 194 195DefineConsoleMethod(GuiInspectorDynamicGroup, inspectGroup, bool, (), , "Refreshes the dynamic fields in the inspector.") 196{ 197 return object->inspectGroup(); 198} 199 200void GuiInspectorDynamicGroup::clearFields() 201{ 202 // save mAddCtrl 203 Sim::getGuiGroup()->addObject(mAddCtrl); 204 // delete everything else 205 mStack->clear(); 206 // clear the mChildren list. 207 mChildren.clear(); 208 // and restore. 209 mStack->addObject(mAddCtrl); 210} 211 212SimFieldDictionary::Entry* GuiInspectorDynamicGroup::findDynamicFieldInDictionary( StringTableEntry fieldName ) 213{ 214 SimFieldDictionary * fieldDictionary = mParent->getInspectObject()->getFieldDictionary(); 215 216 for(SimFieldDictionaryIterator ditr(fieldDictionary); *ditr; ++ditr) 217 { 218 SimFieldDictionary::Entry * entry = (*ditr); 219 220 if( entry->slotName == fieldName ) 221 return entry; 222 } 223 224 return NULL; 225} 226 227void GuiInspectorDynamicGroup::addDynamicField() 228{ 229 // We can't add a field without a target 230 if( !mStack ) 231 { 232 Con::warnf("GuiInspectorDynamicGroup::addDynamicField - no target SimObject to add a dynamic field to."); 233 return; 234 } 235 236 // find a field name that is not in use. 237 // But we wont try more than 100 times to find an available field. 238 U32 uid = 1; 239 char buf[64] = "dynamicField"; 240 SimFieldDictionary::Entry* entry = findDynamicFieldInDictionary(buf); 241 while(entry != NULL && uid < 100) 242 { 243 dSprintf(buf, sizeof(buf), "dynamicField%03d", uid++); 244 entry = findDynamicFieldInDictionary(buf); 245 } 246 247 const U32 numTargets = mParent->getNumInspectObjects(); 248 if( numTargets > 1 ) 249 Con::executef( mParent, "onBeginCompoundEdit" ); 250 251 for( U32 i = 0; i < numTargets; ++ i ) 252 { 253 SimObject* target = mParent->getInspectObject( i ); 254 255 Con::evaluatef( "%d.dynamicField = \"defaultValue\";", target->getId(), buf ); 256 257 // Notify script. 258 259 Con::executef( mParent, "onFieldAdded", target->getIdString(), buf ); 260 } 261 262 if( numTargets > 1 ) 263 Con::executef( mParent, "onEndCompoundEdit" ); 264 265 // now we simply re-inspect the object, to see the new field. 266 inspectGroup(); 267 instantExpand(); 268} 269 270DefineConsoleMethod( GuiInspectorDynamicGroup, addDynamicField, void, (), , "obj.addDynamicField();" ) 271{ 272 object->addDynamicField(); 273} 274 275DefineConsoleMethod( GuiInspectorDynamicGroup, removeDynamicField, void, (), , "" ) 276{ 277} 278
