dynamicField.cpp
Engine/source/gui/editor/inspector/dynamicField.cpp
Public Functions
ConsoleDocClass(GuiInspectorDynamicField , "@brief Custom field type <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> dynamic variable modification on <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">SimObjects.\n\n</a>" "Editor use <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">only.\n\n</a>" "@internal" )
DefineEngineMethod(GuiInspectorDynamicField , renameField , void , (const char *newDynamicFieldName) , "field.renameField(newDynamicFieldName);" )
Detailed Description
Public Functions
ConsoleDocClass(GuiInspectorDynamicField , "@brief Custom field type <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> dynamic variable modification on <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">SimObjects.\n\n</a>" "Editor use <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">only.\n\n</a>" "@internal" )
DefineEngineMethod(GuiInspectorDynamicField , renameField , void , (const char *newDynamicFieldName) , "field.renameField(newDynamicFieldName);" )
IMPLEMENT_CONOBJECT(GuiInspectorDynamicField )
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/editor/inspector/dynamicField.h" 25#include "gui/editor/inspector/dynamicGroup.h" 26#include "gui/editor/guiInspector.h" 27#include "gui/buttons/guiIconButtonCtrl.h" 28#include "console/engineAPI.h" 29 30//----------------------------------------------------------------------------- 31// GuiInspectorDynamicField - Child class of GuiInspectorField 32//----------------------------------------------------------------------------- 33IMPLEMENT_CONOBJECT( GuiInspectorDynamicField ); 34 35ConsoleDocClass( GuiInspectorDynamicField, 36 "@brief Custom field type for dynamic variable modification on SimObjects.\n\n" 37 "Editor use only.\n\n" 38 "@internal" 39); 40 41GuiInspectorDynamicField::GuiInspectorDynamicField( GuiInspector *inspector, 42 GuiInspectorGroup* parent, 43 SimFieldDictionary::Entry* field ) 44 : mRenameCtrl( NULL ), 45 mDeleteButton( NULL ) 46{ 47 mInspector = inspector; 48 mParent = parent; 49 mDynField = field; 50 setBounds(0,0,100,20); 51} 52 53void GuiInspectorDynamicField::setData( const char* data, bool callbacks ) 54{ 55 if ( mDynField == NULL ) 56 return; 57 58 const U32 numTargets = mInspector->getNumInspectObjects(); 59 if( callbacks && numTargets > 1 ) 60 Con::executef( mInspector, "beginCompoundUndo" ); 61 62 // Setting an empty string will kill the field. 63 const bool isRemoval = !data[ 0 ]; 64 65 for( U32 i = 0; i < numTargets; ++ i ) 66 { 67 SimObject* target = mInspector->getInspectObject( i ); 68 69 // Callback on the inspector when the field is modified 70 // to allow creation of undo/redo actions. 71 const char *oldData = target->getDataField( mDynField->slotName, NULL ); 72 if ( !oldData ) 73 oldData = ""; 74 if ( String::compare( oldData, data ) != 0 ) 75 { 76 target->inspectPreApply(); 77 78 if( callbacks ) 79 { 80 if( isRemoval ) 81 Con::executef( mInspector, "onFieldRemoved", target->getIdString(), mDynField->slotName ); 82 else 83 Con::executef( mInspector, "onInspectorFieldModified", target->getIdString(), mDynField->slotName, oldData, data ); 84 } 85 86 target->setDataField( mDynField->slotName, NULL, data ); 87 88 // give the target a chance to validate 89 target->inspectPostApply(); 90 } 91 } 92 93 if( callbacks && numTargets > 1 ) 94 Con::executef( mInspector, "endCompoundUndo" ); 95 96 // Force our edit to update 97 updateValue(); 98} 99 100const char* GuiInspectorDynamicField::getData( U32 inspectObjectIndex ) 101{ 102 if( mDynField == NULL ) 103 return ""; 104 105 return mInspector->getInspectObject( inspectObjectIndex )->getDataField( mDynField->slotName, NULL ); 106} 107 108void GuiInspectorDynamicField::renameField( const char* newFieldName ) 109{ 110 newFieldName = StringTable->insert( newFieldName ); 111 112 if ( mDynField == NULL || mParent == NULL || mEdit == NULL ) 113 { 114 Con::warnf("GuiInspectorDynamicField::renameField - No target object or dynamic field data found!" ); 115 return; 116 } 117 118 if ( !newFieldName ) 119 { 120 Con::warnf("GuiInspectorDynamicField::renameField - Invalid field name specified!" ); 121 return; 122 } 123 124 // Only proceed if the name has changed 125 if ( dStricmp( newFieldName, getFieldName() ) == 0 ) 126 return; 127 128 // Grab a pointer to our parent and cast it to GuiInspectorDynamicGroup 129 GuiInspectorDynamicGroup *group = dynamic_cast<GuiInspectorDynamicGroup*>(mParent); 130 if ( group == NULL ) 131 { 132 Con::warnf("GuiInspectorDynamicField::renameField - Unable to locate GuiInspectorDynamicGroup parent!" ); 133 return; 134 } 135 136 const U32 numTargets = mInspector->getNumInspectObjects(); 137 if( numTargets > 1 ) 138 Con::executef( mInspector, "onBeginCompoundEdit" ); 139 140 const char* oldFieldName = getFieldName(); 141 SimFieldDictionary::Entry* newEntry = NULL; 142 143 for( U32 i = 0; i < numTargets; ++ i ) 144 { 145 SimObject* target = mInspector->getInspectObject( i ); 146 147 // Make sure the new field is not already defined as a static field 148 // on the object. 149 150 if( target->isField( newFieldName ) ) 151 { 152 // New field is already defined. If we can, let the scripts handle 153 // the error. Otherwise, just emit an error on the console and proceed. 154 155 if( numTargets == 1 && mInspector->isMethod( "onFieldRenameAlreadyDefined" ) ) 156 Con::executef( mInspector, "onFieldRenameAlreadyDefined", target->getIdString(), oldFieldName, newFieldName ); 157 else 158 Con::errorf( "GuiInspectorDynamicField::renameField - field '%s' is already defined on %i:%s (%s)", 159 newFieldName, target->getId(), target->getClassName(), target->getName() ); 160 161 // Reset the text entry. 162 163 if( mRenameCtrl ) 164 mRenameCtrl->setText( oldFieldName ); 165 166 continue; 167 } 168 169 char currentValue[1024] = {0}; 170 // Grab our current dynamic field value (we use a temporary buffer as this gets corrupted upon Con::eval) 171 dSprintf( currentValue, sizeof( currentValue ), "%s", target->getDataField( oldFieldName, NULL ) ); 172 173 // Unset the old field and set the new field. 174 175 target->setDataField( oldFieldName, NULL, "" ); 176 target->setDataField( newFieldName, NULL, currentValue ); 177 178 // Notify script. 179 180 Con::executef( mInspector, "onFieldRenamed", target->getIdString(), oldFieldName, newFieldName ); 181 182 // Look up the new SimFieldDictionary entry. 183 184 if( !newEntry ) 185 { 186 newEntry = target->getFieldDictionary()->findDynamicField( newFieldName ); 187 if( !newEntry ) 188 { 189 Con::warnf( "GuiInspectorDynamicField::renameField - could not find new field '%s' on object %i:%s (%s)", 190 newFieldName, target->getId(), target->getClassName(), target->getName() ); 191 } 192 193 mDynField = newEntry; 194 } 195 } 196 197 if( numTargets > 1 ) 198 Con::executef( mInspector, "onEndCompoundEdit" ); 199 200 // Lastly we need to reassign our validate field for our value edit control 201 char szBuffer[1024]; 202 dSprintf( szBuffer, sizeof( szBuffer ), "%d.apply(%d.getText());", getId(), mEdit->getId() ); 203 mEdit->setField("validate", szBuffer ); 204 205 if( mDeleteButton ) 206 { 207 dSprintf(szBuffer, sizeof( szBuffer ), "%d.apply("");%d.inspectGroup();", getId(), newFieldName, group->getId()); 208 mDeleteButton->setField("Command", szBuffer); 209 } 210} 211 212bool GuiInspectorDynamicField::onAdd() 213{ 214 if( !Parent::onAdd() ) 215 return false; 216 217 //pushObjectToBack(mEdit); 218 219 // Create our renaming field 220 mRenameCtrl = new GuiTextEditCtrl(); 221 mRenameCtrl->setDataField( StringTable->insert("profile"), NULL, "GuiInspectorDynamicFieldProfile" ); 222 223 char szName[512]; 224 dSprintf( szName, 512, "IE_%s_%d_%s_Rename", mRenameCtrl->getClassName(), mInspector->getInspectObject()->getId(), getFieldName() ); 225 mRenameCtrl->registerObject( szName ); 226 227 // Our command will evaluate to : 228 // 229 // if( (editCtrl).getText() !$= "" ) 230 // (field).renameField((editCtrl).getText()); 231 // 232 char szBuffer[1024]; 233 dSprintf( szBuffer, sizeof( szBuffer ), "if( %d.getText() !$= \"\" ) %d.renameField(%d.getText());", mRenameCtrl->getId(), getId(), mRenameCtrl->getId() ); 234 mRenameCtrl->setText( getFieldName() ); 235 mRenameCtrl->setField("Validate", szBuffer ); 236 addObject( mRenameCtrl ); 237 238 // Resize the name control to fit in our caption rect 239 mRenameCtrl->resize( mCaptionRect.point, mCaptionRect.extent ); 240 241 // Resize the value control to leave space for the delete button 242 mEdit->resize( mValueRect.point, mValueRect.extent); 243 244 // Clear out any caption set from Parent::onAdd 245 // since we are rendering the fieldname with our 'rename' control. 246 mCaption = StringTable->insert( "" ); 247 248 // Create delete button control 249 mDeleteButton = new GuiBitmapButtonCtrl(); 250 251 SimObject* profilePtr = Sim::findObject("InspectorDynamicFieldButton"); 252 if( profilePtr != NULL ) 253 mDeleteButton->setControlProfile( dynamic_cast<GuiControlProfile*>(profilePtr) ); 254 255 dSprintf( szBuffer, sizeof( szBuffer ), 256 "%d.apply(\"\");%d.schedule(1,\"inspectGroup\");", 257 getId(), 258 mParent->getId() ); 259 260 // FIXME Hardcoded image 261 mDeleteButton->setField( "Bitmap", "tools/gui/images/iconDelete" ); 262 mDeleteButton->setField( "Text", "X" ); 263 mDeleteButton->setField( "Command", szBuffer ); 264 mDeleteButton->setSizing( horizResizeLeft, vertResizeCenter ); 265 mDeleteButton->resize(Point2I(getWidth() - 20,2), Point2I(16, 16)); 266 mDeleteButton->registerObject(); 267 268 addObject(mDeleteButton); 269 270 return true; 271} 272 273bool GuiInspectorDynamicField::updateRects() 274{ 275 Point2I fieldExtent = getExtent(); 276 S32 dividerPos, dividerMargin; 277 mInspector->getDivider( dividerPos, dividerMargin ); 278 279 S32 editWidth = dividerPos - dividerMargin; 280 281 mEditCtrlRect.set( fieldExtent.x - dividerPos + dividerMargin, 1, editWidth, fieldExtent.y - 1 ); 282 mCaptionRect.set( 0, 0, fieldExtent.x - dividerPos - dividerMargin, fieldExtent.y ); 283 mValueRect.set( mEditCtrlRect.point, mEditCtrlRect.extent - Point2I( 20, 0 ) ); 284 mDeleteRect.set( fieldExtent.x - 20, 2, 16, fieldExtent.y - 4 ); 285 286 // This is probably being called during Parent::onAdd 287 // so our special controls haven't been created yet but are just about to 288 // so we just need to calculate the extents. 289 if ( mRenameCtrl == NULL ) 290 return false; 291 292 bool sized0 = mRenameCtrl->resize( mCaptionRect.point, mCaptionRect.extent ); 293 bool sized1 = mEdit->resize( mValueRect.point, mValueRect.extent ); 294 bool sized2 = mDeleteButton->resize(Point2I(getWidth() - 20,2), Point2I(16, 16)); 295 296 return ( sized0 || sized1 || sized2 ); 297} 298 299void GuiInspectorDynamicField::setInspectorField( AbstractClassRep::Field *field, 300 StringTableEntry caption, 301 const char*arrayIndex ) 302{ 303 // Override the base just to be sure it doesn't get called. 304 // We don't use an AbstractClassRep::Field... 305 306// mField = field; 307// mCaption = StringTable->EmptyString(); 308// mRenameCtrl->setText( getFieldName() ); 309} 310 311void GuiInspectorDynamicField::_executeSelectedCallback() 312{ 313 ConsoleBaseType* type = mDynField->type; 314 if ( type ) 315 Con::executef( mInspector, "onFieldSelected", mDynField->slotName, type->getTypeName() ); 316 else 317 Con::executef( mInspector, "onFieldSelected", mDynField->slotName, "TypeDynamicField" ); 318} 319 320DefineEngineMethod( GuiInspectorDynamicField, renameField, void, (const char* newDynamicFieldName),, "field.renameField(newDynamicFieldName);" ) 321{ 322 object->renameField( newDynamicFieldName ); 323} 324