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" )
DefineEngineMethod(GuiInspectorDynamicGroup , addDynamicField , void , () , "obj.addDynamicField();" )
DefineEngineMethod(GuiInspectorDynamicGroup , inspectGroup , bool , () , "Refreshes the dynamic fields in the inspector." )
DefineEngineMethod(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" )
DefineEngineMethod(GuiInspectorDynamicGroup , addDynamicField , void , () , "obj.addDynamicField();" )
DefineEngineMethod(GuiInspectorDynamicGroup , inspectGroup , bool , () , "Refreshes the dynamic fields in the inspector." )
DefineEngineMethod(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 30IMPLEMENT_CONOBJECT(GuiInspectorDynamicGroup); 31 32ConsoleDocClass( GuiInspectorDynamicGroup, 33 "@brief Used to inspect an object's FieldDictionary (dynamic fields) instead " 34 "of regular persistent fields.\n\n" 35 "Editor use only.\n\n" 36 "@internal" 37); 38 39//----------------------------------------------------------------------------- 40// GuiInspectorDynamicGroup - add custom controls 41//----------------------------------------------------------------------------- 42bool GuiInspectorDynamicGroup::createContent() 43{ 44 if(!Parent::createContent()) 45 return false; 46 47 // encapsulate the button in a dummy control. 48 GuiControl* shell = new GuiControl(); 49 shell->setDataField( StringTable->insert("profile"), NULL, "GuiTransparentProfile" ); 50 if( !shell->registerObject() ) 51 { 52 delete shell; 53 return false; 54 } 55 56 // add a button that lets us add new dynamic fields. 57 GuiBitmapButtonCtrl* addFieldBtn = new GuiBitmapButtonCtrl(); 58 { 59 SimObject* profilePtr = Sim::findObject("InspectorDynamicFieldButton"); 60 if( profilePtr != NULL ) 61 addFieldBtn->setControlProfile( dynamic_cast<GuiControlProfile*>(profilePtr) ); 62 63 // FIXME Hardcoded image 64 addFieldBtn->setBitmap("tools/gui/images/iconAdd.png"); 65 66 char commandBuf[64]; 67 dSprintf(commandBuf, 64, "%d.addDynamicField();", this->getId()); 68 addFieldBtn->setField("command", commandBuf); 69 addFieldBtn->setSizing(horizResizeLeft,vertResizeCenter); 70 //addFieldBtn->setField("buttonMargin", "2 2"); 71 addFieldBtn->resize(Point2I(getWidth() - 20,2), Point2I(16, 16)); 72 addFieldBtn->registerObject("zAddButton"); 73 } 74 75 shell->resize(Point2I(0,0), Point2I(getWidth(), 28)); 76 shell->addObject(addFieldBtn); 77 78 // save off the shell control, so we can push it to the bottom of the stack in inspectGroup() 79 mAddCtrl = shell; 80 mStack->addObject(shell); 81 82 return true; 83} 84 85struct FieldEntry 86{ 87 SimFieldDictionary::Entry* mEntry; 88 U32 mNumTargets; 89}; 90 91static S32 QSORT_CALLBACK compareEntries(const void* a,const void* b) 92{ 93 FieldEntry& fa = *((FieldEntry *)a); 94 FieldEntry& fb = *((FieldEntry *)b); 95 return dStrnatcmp(fa.mEntry->slotName, fb.mEntry->slotName); 96} 97 98//----------------------------------------------------------------------------- 99// GuiInspectorDynamicGroup - inspectGroup override 100//----------------------------------------------------------------------------- 101bool GuiInspectorDynamicGroup::inspectGroup() 102{ 103 if( !mParent ) 104 return false; 105 106 // clear the first responder if it's set 107 mStack->clearFirstResponder(); 108 109 // Clearing the fields and recreating them will more than likely be more 110 // efficient than looking up existent fields, updating them, and then iterating 111 // over existent fields and making sure they still exist, if not, deleting them. 112 clearFields(); 113 114 // Create a vector of the fields 115 Vector< FieldEntry> flist; 116 117 const U32 numTargets = mParent->getNumInspectObjects(); 118 for( U32 i = 0; i < numTargets; ++ i ) 119 { 120 SimObject* target = mParent->getInspectObject( i ); 121 122 // Then populate with fields 123 SimFieldDictionary * fieldDictionary = target->getFieldDictionary(); 124 for(SimFieldDictionaryIterator ditr(fieldDictionary); *ditr; ++ditr) 125 { 126 if( i == 0 ) 127 { 128 flist.increment(); 129 flist.last().mEntry = *ditr; 130 flist.last().mNumTargets = 1; 131 } 132 else 133 { 134 const U32 numFields = flist.size(); 135 for( U32 n = 0; n < numFields; ++ n ) 136 if( flist[ n ].mEntry->slotName == ( *ditr )->slotName ) 137 { 138 flist[ n ].mNumTargets ++; 139 break; 140 } 141 } 142 } 143 } 144 145 dQsort( flist.address(), flist.size(), sizeof( FieldEntry ), compareEntries ); 146 147 for(U32 i = 0; i < flist.size(); i++) 148 { 149 if( flist[ i ].mNumTargets != numTargets ) 150 continue; 151 152 SimFieldDictionary::Entry* entry = flist[i].mEntry; 153 154 // Create a dynamic field inspector. Can't reuse typed GuiInspectorFields as 155 // these rely on AbstractClassRep::Fields. 156 GuiInspectorDynamicField *field = new GuiInspectorDynamicField( mParent, this, entry ); 157 158 // Register the inspector field and add it to our lists 159 if( field->registerObject() ) 160 { 161 mChildren.push_back( field ); 162 mStack->addObject( field ); 163 } 164 else 165 delete field; 166 } 167 168 mStack->pushObjectToBack(mAddCtrl); 169 170 setUpdate(); 171 172 return true; 173} 174 175void GuiInspectorDynamicGroup::updateAllFields() 176{ 177 // We overload this to just reinspect the group. 178 inspectGroup(); 179} 180 181DefineEngineMethod(GuiInspectorDynamicGroup, inspectGroup, bool, (), , "Refreshes the dynamic fields in the inspector.") 182{ 183 return object->inspectGroup(); 184} 185 186void GuiInspectorDynamicGroup::clearFields() 187{ 188 // save mAddCtrl 189 Sim::getGuiGroup()->addObject(mAddCtrl); 190 // delete everything else 191 mStack->clear(); 192 // clear the mChildren list. 193 mChildren.clear(); 194 // and restore. 195 mStack->addObject(mAddCtrl); 196} 197 198SimFieldDictionary::Entry* GuiInspectorDynamicGroup::findDynamicFieldInDictionary( StringTableEntry fieldName ) 199{ 200 SimFieldDictionary * fieldDictionary = mParent->getInspectObject()->getFieldDictionary(); 201 202 for(SimFieldDictionaryIterator ditr(fieldDictionary); *ditr; ++ditr) 203 { 204 SimFieldDictionary::Entry * entry = (*ditr); 205 206 if( entry->slotName == fieldName ) 207 return entry; 208 } 209 210 return NULL; 211} 212 213void GuiInspectorDynamicGroup::addDynamicField() 214{ 215 // We can't add a field without a target 216 if( !mStack ) 217 { 218 Con::warnf("GuiInspectorDynamicGroup::addDynamicField - no target SimObject to add a dynamic field to."); 219 return; 220 } 221 222 // find a field name that is not in use. 223 // But we wont try more than 100 times to find an available field. 224 U32 uid = 1; 225 char buf[64] = "dynamicField"; 226 SimFieldDictionary::Entry* entry = findDynamicFieldInDictionary(buf); 227 while(entry != NULL && uid < 100) 228 { 229 dSprintf(buf, sizeof(buf), "dynamicField%03d", uid++); 230 entry = findDynamicFieldInDictionary(buf); 231 } 232 233 const U32 numTargets = mParent->getNumInspectObjects(); 234 if( numTargets > 1 ) 235 Con::executef( mParent, "onBeginCompoundEdit" ); 236 237 for( U32 i = 0; i < numTargets; ++ i ) 238 { 239 SimObject* target = mParent->getInspectObject( i ); 240 241 Con::evaluatef( "%d.dynamicField = \"defaultValue\";", target->getId(), buf ); 242 243 // Notify script. 244 245 Con::executef( mParent, "onFieldAdded", target->getIdString(), buf ); 246 } 247 248 if( numTargets > 1 ) 249 Con::executef( mParent, "onEndCompoundEdit" ); 250 251 // now we simply re-inspect the object, to see the new field. 252 inspectGroup(); 253 instantExpand(); 254} 255 256DefineEngineMethod( GuiInspectorDynamicGroup, addDynamicField, void, (), , "obj.addDynamicField();" ) 257{ 258 object->addDynamicField(); 259} 260 261DefineEngineMethod( GuiInspectorDynamicGroup, removeDynamicField, void, (), , "" ) 262{ 263} 264