field.cpp

Engine/source/gui/editor/inspector/field.cpp

More...

Public Functions

ConsoleDocClass(GuiInspectorField , "@brief The <a href="/coding/class/classguiinspectorfield/">GuiInspectorField</a> <a href="/coding/file/guieditctrl_8cpp/#guieditctrl_8cpp_1abb04e3738c4c5a96b3ade6fa47013a6c">control</a> is <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> representation of <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> single abstract " "field <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> given <a href="/coding/class/classconsoleobject/">ConsoleObject</a> derived <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">object.\n\n</a>" "Editor use <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">only.\n\n</a>" "@internal" )
DefineEngineMethod(GuiInspectorField , apply , void , (const char *newValue, bool callbacks) , (true) )
DefineEngineMethod(GuiInspectorField , applyWithoutUndo , void , (const char *data) , "() - Set field <a href="/coding/file/pointer_8h/#pointer_8h_1a32aff7c6c4cd253fdf6563677afab5ce">value</a> without recording undo (same as 'apply( <a href="/coding/file/pointer_8h/#pointer_8h_1a32aff7c6c4cd253fdf6563677afab5ce">value</a>, false )')." )
DefineEngineMethod(GuiInspectorField , getData , const char * , () , "() - Return the <a href="/coding/file/pointer_8h/#pointer_8h_1a32aff7c6c4cd253fdf6563677afab5ce">value</a> currently displayed on the field." )
DefineEngineMethod(GuiInspectorField , getInspectedFieldName , const char * , () , "() - Return the name of the field edited by this inspector field." )
DefineEngineMethod(GuiInspectorField , getInspectedFieldType , const char * , () , "() - Return the type of the field edited by this inspector field." )
DefineEngineMethod(GuiInspectorField , getInspector , S32 , () , "() - Return the <a href="/coding/class/classguiinspector/">GuiInspector</a> <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> which this field belongs." )
DefineEngineMethod(GuiInspectorField , reset , void , () , "() - Reset <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> default value." )
DefineEngineMethod(GuiInspectorField , setCaption , void , (String newCaption) , "() - Reset <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> default value." )
DefineEngineMethod(GuiInspectorField , setEditControl , void , (GuiControl *editCtrl) , (nullAsType< GuiControl * >()) , "() - Reset <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> default value." )
DefineEngineMethod(GuiInspectorField , setHeightOverride , void , (bool useOverride, U32 heightOverride) , "" )

Detailed Description

Public Functions

ConsoleDocClass(GuiInspectorField , "@brief The <a href="/coding/class/classguiinspectorfield/">GuiInspectorField</a> <a href="/coding/file/guieditctrl_8cpp/#guieditctrl_8cpp_1abb04e3738c4c5a96b3ade6fa47013a6c">control</a> is <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> representation of <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> single abstract " "field <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> given <a href="/coding/class/classconsoleobject/">ConsoleObject</a> derived <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">object.\n\n</a>" "Editor use <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">only.\n\n</a>" "@internal" )

DefineEngineMethod(GuiInspectorField , apply , void , (const char *newValue, bool callbacks) , (true) )

DefineEngineMethod(GuiInspectorField , applyWithoutUndo , void , (const char *data) , "() - Set field <a href="/coding/file/pointer_8h/#pointer_8h_1a32aff7c6c4cd253fdf6563677afab5ce">value</a> without recording undo (same as 'apply( <a href="/coding/file/pointer_8h/#pointer_8h_1a32aff7c6c4cd253fdf6563677afab5ce">value</a>, false )')." )

DefineEngineMethod(GuiInspectorField , getData , const char * , () , "() - Return the <a href="/coding/file/pointer_8h/#pointer_8h_1a32aff7c6c4cd253fdf6563677afab5ce">value</a> currently displayed on the field." )

DefineEngineMethod(GuiInspectorField , getInspectedFieldName , const char * , () , "() - Return the name of the field edited by this inspector field." )

DefineEngineMethod(GuiInspectorField , getInspectedFieldType , const char * , () , "() - Return the type of the field edited by this inspector field." )

DefineEngineMethod(GuiInspectorField , getInspector , S32 , () , "() - Return the <a href="/coding/class/classguiinspector/">GuiInspector</a> <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> which this field belongs." )

DefineEngineMethod(GuiInspectorField , reset , void , () , "() - Reset <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> default value." )

DefineEngineMethod(GuiInspectorField , setCaption , void , (String newCaption) , "() - Reset <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> default value." )

DefineEngineMethod(GuiInspectorField , setEditControl , void , (GuiControl *editCtrl) , (nullAsType< GuiControl * >()) , "() - Reset <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> default value." )

DefineEngineMethod(GuiInspectorField , setHeightOverride , void , (bool useOverride, U32 heightOverride) , "" )

IMPLEMENT_CONOBJECT(GuiInspectorField )

  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 "console/engineAPI.h"
 25#include "platform/platform.h"
 26#include "gui/editor/inspector/field.h"
 27#include "gui/buttons/guiIconButtonCtrl.h"
 28#include "gui/editor/guiInspector.h"
 29#include "core/util/safeDelete.h"
 30#include "gfx/gfxDrawUtil.h"
 31#include "math/mathTypes.h"
 32#include "core/strings/stringUnit.h"
 33
 34
 35IMPLEMENT_CONOBJECT(GuiInspectorField);
 36
 37ConsoleDocClass( GuiInspectorField,
 38   "@brief The GuiInspectorField control is a representation of a single abstract "
 39   "field for a given ConsoleObject derived object.\n\n"
 40   "Editor use only.\n\n"
 41   "@internal"
 42);
 43
 44//-----------------------------------------------------------------------------
 45
 46GuiInspectorField::GuiInspectorField( GuiInspector* inspector,
 47                                      GuiInspectorGroup* parent, 
 48                                      AbstractClassRep::Field* field ) 
 49 : mParent( parent ),
 50   mInspector( inspector ),
 51   mField( field ), 
 52   mFieldArrayIndex( NULL ), 
 53   mEdit( NULL ),
 54   mTargetObject(NULL),
 55   mUseHeightOverride(false),
 56   mHighlighted(false),
 57   mHeightOverride(18),
 58   mSpecialEditField(false),
 59   mVariableName(StringTable->EmptyString()),
 60   mCallbackName(StringTable->EmptyString())
 61{
 62   if( field != NULL )
 63      mCaption    = field->pFieldname;
 64   else
 65      mCaption    = StringTable->EmptyString();
 66
 67   setCanSave( false );
 68   setBounds(0,0,100,18);
 69   
 70   if( field != NULL )
 71      _setFieldDocs( field->pFieldDocs );
 72}
 73
 74//-----------------------------------------------------------------------------
 75
 76GuiInspectorField::GuiInspectorField() 
 77 : mParent( NULL ),
 78   mInspector( NULL ),
 79   mField( NULL ),
 80   mEdit( NULL ),
 81   mCaption( StringTable->EmptyString() ),
 82   mFieldArrayIndex( NULL ),
 83   mHighlighted( false ),
 84   mTargetObject(NULL),
 85   mVariableName(StringTable->EmptyString()),
 86   mCallbackName(StringTable->EmptyString()),
 87   mSpecialEditField(false),
 88   mUseHeightOverride(false),
 89   mHeightOverride(18)
 90{
 91   setCanSave( false );
 92}
 93
 94//-----------------------------------------------------------------------------
 95
 96GuiInspectorField::~GuiInspectorField()
 97{
 98}
 99
100//-----------------------------------------------------------------------------
101
102void GuiInspectorField::init( GuiInspector *inspector, GuiInspectorGroup *group )
103{   
104   mInspector = inspector;
105   mParent = group;
106}
107
108//-----------------------------------------------------------------------------
109
110bool GuiInspectorField::onAdd()
111{   
112   setInspectorProfile();   
113
114   if ( !Parent::onAdd() )
115      return false;
116
117   if ( !mInspector )
118      return false;   
119
120   mEdit = constructEditControl();
121   if ( mEdit == NULL )
122      return false;
123
124   S32 fieldHeight = 18;
125
126   if (mUseHeightOverride)
127      fieldHeight = mHeightOverride;
128
129   setBounds(0,0,100, fieldHeight);
130
131   // Add our edit as a child
132   addObject( mEdit );
133
134   // Calculate Caption and EditCtrl Rects
135   updateRects();   
136
137   // Force our editField to set it's value
138   updateValue();
139
140   Con::evaluatef("%d.edit = %d;", this->getId(), mEdit->getId());
141   return true;
142}
143
144//-----------------------------------------------------------------------------
145
146bool GuiInspectorField::resize( const Point2I &newPosition, const Point2I &newExtent )
147{
148   if ( !Parent::resize( newPosition, newExtent ) )
149      return false;
150
151   return updateRects();
152}
153
154//-----------------------------------------------------------------------------
155
156void GuiInspectorField::onRender( Point2I offset, const RectI &updateRect )
157{
158   RectI ctrlRect(offset, getExtent());
159   
160   // Render fillcolor...
161   if ( mProfile->mOpaque )
162      GFX->getDrawUtil()->drawRectFill(ctrlRect, mProfile->mFillColor);   
163
164   // Render caption...
165   if ( mCaption && mCaption[0] )
166   {      
167      // Backup current ClipRect
168      RectI clipBackup = GFX->getClipRect();
169
170      RectI clipRect = updateRect;
171
172      // The rect within this control in which our caption must fit.
173      RectI rect( offset + mCaptionRect.point + mProfile->mTextOffset, mCaptionRect.extent + Point2I(1,1) - Point2I(5,0) );
174
175      // Now clipRect is the amount of our caption rect that is actually visible.
176      bool hit = clipRect.intersect( rect );
177
178      if ( hit )
179      {
180         GFX->setClipRect( clipRect );
181         GFXDrawUtil *drawer = GFX->getDrawUtil();
182
183         // Backup modulation color
184         ColorI currColor;
185         drawer->getBitmapModulation( &currColor );
186
187         // Draw caption background...
188         if( !isActive() )
189            GFX->getDrawUtil()->drawRectFill( clipRect, mProfile->mFillColorNA );
190         else if ( mHighlighted )         
191            GFX->getDrawUtil()->drawRectFill( clipRect, mProfile->mFillColorHL );             
192
193         // Draw caption text...
194
195         drawer->setBitmapModulation( !isActive() ? mProfile->mFontColorNA : mHighlighted ? mProfile->mFontColorHL : mProfile->mFontColor );
196         
197         // Clip text with '...' if too long to fit
198         String clippedText( mCaption );
199         clipText( clippedText, clipRect.extent.x );
200
201         renderJustifiedText( offset + mProfile->mTextOffset, getExtent(), clippedText );
202
203         // Restore modulation color
204         drawer->setBitmapModulation( currColor );
205
206         // Restore previous ClipRect
207         GFX->setClipRect( clipBackup );
208      }
209   }
210
211   // Render Children...
212   renderChildControls(offset, updateRect);
213
214   // Render border...
215   if ( mProfile->mBorder )
216      renderBorder(ctrlRect, mProfile);   
217
218   // Render divider...
219   Point2I worldPnt = mEditCtrlRect.point + offset;
220   GFX->getDrawUtil()->drawLine( worldPnt.x - 5,
221      worldPnt.y, 
222      worldPnt.x - 5,
223      worldPnt.y + getHeight(),
224      !isActive() ? mProfile->mBorderColorNA : mHighlighted ? mProfile->mBorderColorHL : mProfile->mBorderColor );
225}
226
227//-----------------------------------------------------------------------------
228
229void GuiInspectorField::setFirstResponder( GuiControl *firstResponder )
230{
231   Parent::setFirstResponder( firstResponder );
232
233   if ( firstResponder == this || firstResponder == mEdit )
234   {
235      mInspector->setHighlightField( this );      
236   }   
237}
238
239//-----------------------------------------------------------------------------
240
241void GuiInspectorField::onMouseDown( const GuiEvent &event )
242{
243   if ( mCaptionRect.pointInRect( globalToLocalCoord( event.mousePoint ) ) )  
244   {
245      if ( mEdit )
246         //mEdit->onMouseDown( event );
247         mInspector->setHighlightField( this );
248   }
249   else
250      Parent::onMouseDown( event );
251}
252
253//-----------------------------------------------------------------------------
254
255void GuiInspectorField::onRightMouseUp( const GuiEvent &event )
256{
257   if ( mCaptionRect.pointInRect( globalToLocalCoord( event.mousePoint ) ) ) 
258      Con::executef( mInspector, "onFieldRightClick", getIdString() );
259   else
260      Parent::onMouseDown( event );
261}
262
263//-----------------------------------------------------------------------------
264
265void GuiInspectorField::setData( const char* data, bool callbacks )
266{
267   if (mSpecialEditField)
268   {
269      if (mTargetObject != nullptr && mVariableName != StringTable->EmptyString())
270      {
271         mTargetObject->setDataField(mVariableName, NULL, data);
272
273         if (mCallbackName != StringTable->EmptyString())
274            Con::executef(mInspector, mCallbackName, mVariableName, data, mTargetObject);
275      }
276      else if (mVariableName != StringTable->EmptyString())
277      {
278         Con::setVariable(mVariableName, data);
279
280         if (mCallbackName != StringTable->EmptyString())
281            Con::executef(mInspector, mCallbackName, mVariableName, data);
282      }
283   }
284
285   if( mField == NULL )
286      return;
287
288   if( verifyData( data ) )
289   {
290      String strData = data;
291      const U32 numTargets = mInspector->getNumInspectObjects();
292      
293      if( callbacks && numTargets > 1 )
294         Con::executef( mInspector, "onBeginCompoundEdit" );
295            
296      for( U32 i = 0; i < numTargets; ++ i )
297      {
298         //For now, for simplicity's sake, you can only edit the components in a simple edit
299         SimObject* target = NULL;
300         if (numTargets == 1)
301         {
302            target = mTargetObject;
303
304            if (!target)
305               target = mInspector->getInspectObject(i);
306         }
307         else
308         {
309            target = mInspector->getInspectObject(i);
310         }
311         
312         String oldValue = target->getDataField( mField->pFieldname, mFieldArrayIndex);
313         
314         // For numeric fields, allow input expressions.
315         
316         String newValue = strData;
317         S32 type= mField->type;
318         if( type == TypeS8 || type == TypeS32 || type == TypeF32 )
319         {
320            char buffer[ 2048 ];
321            expandEscape( buffer, newValue );
322            newValue = (const char*)Con::evaluatef( "%%f = \"%s\"; return ( %s );", oldValue.c_str(), buffer );
323         }
324         else if(    type == TypeS32Vector
325                  || type == TypeF32Vector
326                  || type == TypeColorI
327                  || type == TypeColorF
328                  || type == TypePoint2I
329                  || type == TypePoint2F
330                  || type == TypePoint3F
331                  || type == TypePoint4F
332                  || type == TypeRectI
333                  || type == TypeRectF
334                  || type == TypeMatrixPosition
335                  || type == TypeMatrixRotation
336                  || type == TypeBox3F
337                  || type == TypeRectUV
338                  || type == TypeRotationF)
339         {
340            //TODO: we should actually take strings into account and not chop things up between quotes
341
342            U32 numNewUnits = StringUnit::getUnitCount( newValue, " \t\n\r" );
343            
344            StringBuilder strNew;
345            bool isFirst = true;
346            for( U32 n = 0; n < numNewUnits; ++ n )
347            {
348               char oldComponentVal[ 1024 ];
349               StringUnit::getUnit( oldValue, n, " \t\n\r", oldComponentVal, sizeof( oldComponentVal ) );
350               
351               char newComponentExpr[ 1024 ];
352               StringUnit::getUnit( newValue, n, " \t\n\r", newComponentExpr, sizeof( newComponentExpr ) );
353               
354               char buffer[ 2048 ];
355               expandEscape( buffer, newComponentExpr );
356
357               const char* newComponentVal = Con::evaluatef( "%%f = \"%s\"; %%v = \"%s\"; return ( %s );",
358                  oldComponentVal, oldValue.c_str(), buffer );
359               
360               if( !isFirst )
361                  strNew.append( ' ' );
362               strNew.append( newComponentVal );
363               
364               isFirst = false;
365            }
366            
367            newValue = strNew.end();
368         }
369            
370         target->inspectPreApply();
371         
372         // Fire callback single-object undo.
373         
374         if( callbacks )
375            Con::executef( mInspector, "onInspectorFieldModified", 
376                                          target->getIdString(), 
377                                          mField->pFieldname, 
378                                          mFieldArrayIndex ? mFieldArrayIndex : "(null)", 
379                                          oldValue.c_str(), 
380                                          newValue.c_str() );
381
382         target->setDataField( mField->pFieldname, mFieldArrayIndex, newValue );
383         
384         // Give the target a chance to validate.
385         target->inspectPostApply();
386      }
387      
388      if( callbacks && numTargets > 1 )
389         Con::executef( mInspector, "onEndCompoundEdit" );
390   }
391
392   // Force our edit to update
393   updateValue();
394}
395
396//-----------------------------------------------------------------------------
397
398const char* GuiInspectorField::getData( U32 inspectObjectIndex )
399{
400   if (!mSpecialEditField)
401   {
402      if (mField == NULL)
403         return "";
404
405      if (mTargetObject)
406         return mTargetObject->getDataField(mField->pFieldname, mFieldArrayIndex);
407
408      return mInspector->getInspectObject(inspectObjectIndex)->getDataField(mField->pFieldname, mFieldArrayIndex);
409   }
410   else
411   {
412      if (mTargetObject != nullptr && mVariableName != StringTable->EmptyString())
413      {
414         return mTargetObject->getDataField(mVariableName, NULL);
415      }
416      else if (mVariableName != StringTable->EmptyString())
417      {
418         return Con::getVariable(mVariableName);
419      }
420      else
421      {
422         return "";
423      }
424   }
425}
426
427//-----------------------------------------------------------------------------
428
429void GuiInspectorField::resetData()
430{
431   if( !mField )
432      return;
433      
434   SimObject* inspectObject = getInspector()->getInspectObject();
435   
436   SimObject* tempObject = static_cast< SimObject* >( inspectObject->getClassRep()->create() );
437   setData( tempObject->getDataField( mField->pFieldname, mFieldArrayIndex ) );
438   delete tempObject;
439}
440
441//-----------------------------------------------------------------------------
442
443void GuiInspectorField::setInspectorField( AbstractClassRep::Field *field, StringTableEntry caption, const char*arrayIndex ) 
444{
445   mField = field; 
446
447   if ( arrayIndex != NULL )   
448      mFieldArrayIndex = StringTable->insert( arrayIndex );
449
450   if ( !caption || !caption[0] )
451      mCaption = getFieldName(); 
452   else
453      mCaption = caption;
454
455   if ( mField != NULL )
456      _setFieldDocs( mField->pFieldDocs );
457}
458
459//-----------------------------------------------------------------------------
460
461StringTableEntry GuiInspectorField::getRawFieldName()
462{
463   if( !mField )
464      return StringTable->EmptyString();
465      
466   return mField->pFieldname;
467}
468
469//-----------------------------------------------------------------------------
470
471StringTableEntry GuiInspectorField::getFieldName() 
472{ 
473   // Sanity
474   if ( mField == NULL )
475      return StringTable->EmptyString();
476
477   // Array element?
478   if( mFieldArrayIndex != NULL )
479   {
480      S32 frameTempSize = dStrlen( mField->pFieldname ) + 32;
481      FrameTemp<char> valCopy( frameTempSize );
482      dSprintf( (char *)valCopy, frameTempSize, "%s[%s]", mField->pFieldname, mFieldArrayIndex );
483
484      // Return formatted element
485      return StringTable->insert( valCopy );
486   }
487
488   // Plain field name.
489   return mField->pFieldname;
490}
491
492//-----------------------------------------------------------------------------
493
494StringTableEntry GuiInspectorField::getFieldType()
495{
496   if( !mField )
497      return StringTable->EmptyString();
498      
499   return ConsoleBaseType::getType( mField->type )->getTypeName();
500}
501
502//-----------------------------------------------------------------------------
503
504GuiControl* GuiInspectorField::constructEditControl()
505{
506   GuiControl* retCtrl = new GuiTextEditCtrl();
507
508   static StringTableEntry sProfile = StringTable->insert( "profile" );
509   retCtrl->setDataField( sProfile, NULL, "GuiInspectorTextEditProfile" );
510
511   _registerEditControl( retCtrl );
512
513   char szBuffer[512];
514   dSprintf( szBuffer, 512, "%d.apply(%d.getText());",getId(), retCtrl->getId() );
515   
516   // Suffices to hook on to "validate" as regardless of whether we lose
517   // focus through the user pressing enter or clicking away on another
518   // keyboard control, we will see a validate call.
519   
520   retCtrl->setField("validate", szBuffer );
521
522   return retCtrl;
523}
524
525//-----------------------------------------------------------------------------
526
527void GuiInspectorField::setInspectorProfile()
528{
529   GuiControlProfile *profile = NULL;   
530   
531   if( mInspector && (mInspector->getNumInspectObjects() > 1) )
532   {
533      if( !hasSameValueInAllObjects() )
534         Sim::findObject( "GuiInspectorMultiFieldDifferentProfile", profile );
535      else
536         Sim::findObject( "GuiInspectorMultiFieldProfile", profile );
537   }
538   
539   if( !profile )
540      Sim::findObject( "GuiInspectorFieldProfile", profile );
541   
542   if( profile )
543      setControlProfile( profile );
544}
545
546//-----------------------------------------------------------------------------
547
548void GuiInspectorField::setValue( StringTableEntry newValue )
549{
550   GuiTextEditCtrl *ctrl = dynamic_cast<GuiTextEditCtrl*>( mEdit );
551   if( ctrl != NULL )
552      ctrl->setText( newValue );
553}
554
555//-----------------------------------------------------------------------------
556
557void GuiInspectorField::setEditControl(GuiControl* editCtrl) 
558{ 
559   if (mEdit)
560      mEdit->deleteObject();
561
562   mEdit = editCtrl; 
563   addObject(mEdit);
564}
565
566//-----------------------------------------------------------------------------
567
568bool GuiInspectorField::updateRects()
569{
570   S32 dividerPos, dividerMargin;
571   mInspector->getDivider( dividerPos, dividerMargin );   
572
573   Point2I fieldExtent = getExtent();
574   Point2I fieldPos = getPosition();
575
576   S32 editWidth = dividerPos - dividerMargin;
577
578   mEditCtrlRect.set( fieldExtent.x - dividerPos + dividerMargin, 1, editWidth, fieldExtent.y - 1 );
579   mCaptionRect.set( 0, 0, fieldExtent.x - dividerPos - dividerMargin, fieldExtent.y );
580   
581   if ( !mEdit )
582      return false;
583
584   return mEdit->resize( mEditCtrlRect.point, mEditCtrlRect.extent );
585}
586
587//-----------------------------------------------------------------------------
588
589void GuiInspectorField::updateValue()
590{
591   if( mInspector->getNumInspectObjects() > 1 )
592   {
593      setInspectorProfile();
594         
595      if( !hasSameValueInAllObjects() )
596         setValue( StringTable->EmptyString() );
597      else
598         setValue( getData() );
599   }
600   else
601      setValue( getData() );
602}
603
604//-----------------------------------------------------------------------------
605
606void GuiInspectorField::setHLEnabled( bool enabled )
607{
608   mHighlighted = enabled;
609   if ( mHighlighted )
610   {
611      if ( mEdit && !mEdit->isFirstResponder() )
612      {
613         mEdit->setFirstResponder();
614         GuiTextEditCtrl *edit = dynamic_cast<GuiTextEditCtrl*>( mEdit );
615         if ( edit )
616         {
617            mouseUnlock();
618            edit->mouseLock();
619            edit->setCursorPos(0);
620         }
621      }
622      _executeSelectedCallback();
623   }
624}
625
626//-----------------------------------------------------------------------------
627
628bool GuiInspectorField::hasSameValueInAllObjects()
629{
630   char value1[ 2048 ];
631   
632   // Get field value from first object.
633   
634   const char* data1 = getData( 0 );
635   if( data1 )
636   {
637      dStrncpy( value1, data1, sizeof( value1 ) );
638      value1[ sizeof( value1 ) - 1 ] = 0;
639   }
640   else
641      value1[ 0 ] = 0;
642   
643   // Check if all other objects have the same value.
644
645   const U32 numObjects = mInspector->getNumInspectObjects();
646   for( U32 i = 1; i < numObjects; ++ i )
647   {
648      const char* value2 = getData( i );
649      if( !value2 )
650         value2 = "";
651
652      if( String::compare( value1, value2 ) != 0 )
653         return false;
654   }
655         
656   return true;
657}
658
659//-----------------------------------------------------------------------------
660
661void GuiInspectorField::_executeSelectedCallback()
662{
663   if( mField )
664      Con::executef( mInspector, "onFieldSelected", mField->pFieldname, ConsoleBaseType::getType(mField->type)->getTypeName(), mFieldDocs.c_str() );
665}
666
667//-----------------------------------------------------------------------------
668
669void GuiInspectorField::_registerEditControl( GuiControl *ctrl )
670{
671   char szName[512];
672   if(mInspector->getInspectObject() != nullptr)
673      dSprintf( szName, 512, "IE_%s_%d_%s_Field", ctrl->getClassName(), mInspector->getInspectObject()->getId(), mCaption);
674   else
675      dSprintf(szName, 512, "IE_%s_%s_Field", ctrl->getClassName(), mCaption);
676
677   // Register the object
678   ctrl->registerObject( szName );
679}
680
681//-----------------------------------------------------------------------------
682
683void GuiInspectorField::_setFieldDocs( StringTableEntry docs )
684{
685   mFieldDocs = String();
686   if( docs && docs[ 0 ] )
687   {
688      // Only accept first line of docs for brevity.
689      
690      const char* newline = dStrchr( docs, '\n' );
691      if( newline )
692         mFieldDocs = String( docs, newline - docs );
693      else
694         mFieldDocs = docs;
695   }
696}
697
698void GuiInspectorField::setHeightOverride(bool useOverride, U32 heightOverride)
699{
700   mUseHeightOverride = useOverride;
701
702   if (useOverride)
703      mHeightOverride = heightOverride;
704
705   S32 fieldHeight = 18;
706
707   if (mUseHeightOverride)
708      fieldHeight = mHeightOverride;
709
710   RectI bnds = getBounds();
711   setBounds(bnds.point.x, bnds.point.y, bnds.extent.x, fieldHeight);
712
713   // Calculate Caption and EditCtrl Rects
714   updateRects();
715
716   // Force our editField to set it's value
717   updateValue();
718}
719
720//=============================================================================
721//    Console Methods.
722//=============================================================================
723// MARK: ---- Console Methods ----
724
725//-----------------------------------------------------------------------------
726
727DefineEngineMethod( GuiInspectorField, getInspector, S32, (), , "() - Return the GuiInspector to which this field belongs." )
728{
729   return object->getInspector()->getId();
730}
731
732//-----------------------------------------------------------------------------
733
734DefineEngineMethod( GuiInspectorField, getInspectedFieldName, const char*, (), , "() - Return the name of the field edited by this inspector field." )
735{
736   return object->getFieldName();
737}
738
739//-----------------------------------------------------------------------------
740
741DefineEngineMethod( GuiInspectorField, getInspectedFieldType, const char*, (), , "() - Return the type of the field edited by this inspector field." )
742{
743   return object->getFieldType();
744}
745
746//-----------------------------------------------------------------------------
747
748DefineEngineMethod( GuiInspectorField, apply, void, ( const char * newValue, bool callbacks ), (true), "( string newValue, bool callbacks=true ) - Set the field's value. Suppress callbacks for undo if callbacks=false." )
749{
750   object->setData( newValue, callbacks );
751}
752
753//-----------------------------------------------------------------------------
754
755DefineEngineMethod( GuiInspectorField, applyWithoutUndo, void, (const char * data), , "() - Set field value without recording undo (same as 'apply( value, false )')." )
756{
757   object->setData( data, false );
758}
759
760//-----------------------------------------------------------------------------
761
762DefineEngineMethod( GuiInspectorField, getData, const char*, (), , "() - Return the value currently displayed on the field." )
763{
764   return object->getData();
765}
766
767//-----------------------------------------------------------------------------
768
769DefineEngineMethod( GuiInspectorField, reset, void, (), , "() - Reset to default value." )
770{
771   object->resetData();
772}
773
774DefineEngineMethod(GuiInspectorField, setCaption, void, (String newCaption),, "() - Reset to default value.")
775{
776   object->setCaption(StringTable->insert(newCaption.c_str()));
777}
778
779DefineEngineMethod(GuiInspectorField, setHeightOverride, void, (bool useOverride, U32 heightOverride), , "")
780{
781   object->setHeightOverride(useOverride, heightOverride);
782}
783
784DefineEngineMethod(GuiInspectorField, setEditControl, void, (GuiControl* editCtrl), (nullAsType<GuiControl*>()), "() - Reset to default value.")
785{
786   object->setEditControl(editCtrl);
787}
788