!I (1670414, 1670415, 1670416, 1670424, 1670431):
[CRYENGINE.git] / Code / Sandbox / Plugins / MFCToolsPlugin / Controls / PropertyItem.cpp
blob35010ed7b6f4e34a57ff52a2b219a18dc639426d
1 // Copyright 2001-2018 Crytek GmbH / Crytek Group. All rights reserved.
3 /*
4 Relationship between Variable data, PropertyItem value string, and draw string
6 Variable:
7 holds raw data
8 PropertyItem.m_value string:
9 Converted via Variable.Get/SetDisplayValue
10 = Same as Variable.Get(string) and Variable.Set(string), EXCEPT:
11 Enums converted to enum values
12 Color reformated to 8-bit range
13 SOHelper removes prefix before :
14 Draw string:
15 Same as .m_value, EXCEPT
16 .valueMultiplier conversion applied
17 Bool reformated to "True/False"
18 Curves replaced with "[Curve]"
19 bShowChildren vars add child draw strings
20 Input string:
21 Set to .m_value, EXCEPT
22 Bool converted to "1/0"
23 File text replace \ with /
24 Vector expand single elem to 3 repeated
27 #include "StdAfx.h"
28 #include "PropertyItem.h"
29 #include "PropertyCtrl.h"
30 #include "InPlaceEdit.h"
31 #include "InPlaceComboBox.h"
32 #include "InPlaceButton.h"
33 #include "FillSliderCtrl.h"
34 #include "SplineCtrl.h"
35 #include "ColorGradientCtrl.h"
36 #include "SliderCtrlEx.h"
38 #include "Dialogs/CustomColorDialog.h"
40 #include "Controls/SharedFonts.h"
41 #include "Controls/NumberCtrl.h"
43 #include "UIEnumsDatabase.h"
44 #include "Dialogs/SelectSequenceDialog.h"
45 #include "Dialogs/GenericSelectItemDialog.h"
46 #include "Dialogs/SelectMissionObjectiveDialog.h"
48 #include <CrySystem/ITimer.h>
49 #include <CrySystem/ILocalizationManager.h>
51 #include "ISourceControl.h"
53 #include <CryString/CryName.h>
55 #include "Util/UIEnumerations.h"
56 #include "IDataBaseItem.h"
57 #include "IDataBaseManager.h"
58 #include "Objects/BaseObject.h"
60 #include "IResourceSelectorHost.h"
61 #include <CryString/UnicodeFunctions.h>
62 #include "Controls/QuestionDialog.h"
63 #include "Util/MFCUtil.h"
64 #include "Util/FileUtil.h"
65 #include <CryMovie/IMovieSystem.h>
67 //////////////////////////////////////////////////////////////////////////
68 #define CMD_ADD_CHILD_ITEM 100
69 #define CMD_ADD_ITEM 101
70 #define CMD_DELETE_ITEM 102
72 #define BUTTON_WIDTH (16)
73 #define NUMBER_CTRL_WIDTH 60
75 //////////////////////////////////////////////////////////////////////////
76 //! Undo object for Variable in property control..
77 class CUndoVariableChange : public IUndoObject
79 public:
80 CUndoVariableChange(IVariable* var, const char* undoDescription)
82 // Stores the current state of this object.
83 assert(var != 0);
84 m_undoDescription = undoDescription;
85 m_var = var;
86 m_undo = m_var->Clone(false);
88 protected:
89 virtual int GetSize()
91 int size = sizeof(*this);
92 //if (m_var)
93 //size += m_var->GetSize();
94 if (m_undo)
95 size += m_undo->GetSize();
96 if (m_redo)
97 size += m_redo->GetSize();
98 return size;
100 virtual const char* GetDescription() { return m_undoDescription; };
101 virtual void Undo(bool bUndo)
103 if (bUndo)
105 m_redo = m_var->Clone(false);
107 m_var->CopyValue(m_undo);
109 virtual void Redo()
111 if (m_redo)
112 m_var->CopyValue(m_redo);
115 private:
116 CString m_undoDescription;
117 _smart_ptr<IVariable> m_undo;
118 _smart_ptr<IVariable> m_redo;
119 _smart_ptr<IVariable> m_var;
122 //////////////////////////////////////////////////////////////////////////
123 namespace {
124 struct
126 int dataType;
127 const char* name;
128 PropertyType type;
129 int image;
130 } s_propertyTypeNames[] =
132 { IVariable::DT_SIMPLE, "Bool", ePropertyBool, 2 },
133 { IVariable::DT_SIMPLE, "Int", ePropertyInt, 0 },
134 { IVariable::DT_SIMPLE, "Float", ePropertyFloat, 0 },
135 { IVariable::DT_SIMPLE, "Vector", ePropertyVector2, 10 },
136 { IVariable::DT_SIMPLE, "Vector", ePropertyVector, 10 },
137 { IVariable::DT_SIMPLE, "Vector", ePropertyVector4, 10 },
138 { IVariable::DT_SIMPLE, "String", ePropertyString, 3 },
139 { IVariable::DT_PERCENT, "Float", ePropertyInt, 13 },
140 { IVariable::DT_BOOLEAN, "Boolean", ePropertyBool, 2 },
141 { IVariable::DT_COLOR, "Color", ePropertyColor, 1 },
142 { IVariable::DT_CURVE | IVariable::DT_PERCENT, "FloatCurve", ePropertyFloatCurve, 13 },
143 { IVariable::DT_CURVE | IVariable::DT_COLOR, "ColorCurve", ePropertyColorCurve, 1 },
144 { IVariable::DT_ANGLE, "Angle", ePropertyAngle, 0 },
145 { IVariable::DT_FILE, "File", ePropertyFile, 7 },
146 { IVariable::DT_TEXTURE, "Texture", ePropertyTexture, 4 },
147 { IVariable::DT_ANIMATION, "Animation", ePropertyAnimation, -1 },
148 { IVariable::DT_OBJECT, "Model", ePropertyModel, 5 },
149 { IVariable::DT_SIMPLE, "Selection", ePropertySelection, -1 },
150 { IVariable::DT_SIMPLE, "List", ePropertyList, -1 },
151 { IVariable::DT_SHADER, "Shader", ePropertyShader, 9 },
152 { IVariable::DT_MATERIAL, "Material", ePropertyMaterial, 14 },
153 { IVariable::DT_AI_BEHAVIOR, "AIBehavior", ePropertyAiBehavior, 8 },
154 { IVariable::DT_AI_ANCHOR, "AIAnchor", ePropertyAiAnchor, 8 },
155 #ifdef USE_DEPRECATED_AI_CHARACTER_SYSTEM
156 { IVariable::DT_AI_CHARACTER, "AICharacter", ePropertyAiCharacter, 8 },
157 #endif
158 { IVariable::DT_AI_PFPROPERTIESLIST, "AgentTypeList", ePropertyAiPFPropertiesList, 8 },
159 { IVariable::DT_AIENTITYCLASSES, "AI Entity Classes", ePropertyAiEntityClasses, 8 },
160 { IVariable::DT_EQUIP, "Equip", ePropertyEquip, 11 },
161 { IVariable::DT_REVERBPRESET, "ReverbPreset", ePropertyReverbPreset, 11 },
162 { IVariable::DT_LOCAL_STRING, "LocalString", ePropertyLocalString, 3 },
163 { IVariable::DT_SOCLASS, "Smart Object Class", ePropertySOClass, 8 },
164 { IVariable::DT_SOCLASSES, "Smart Object Classes", ePropertySOClasses, 8 },
165 { IVariable::DT_SOSTATE, "Smart Object State", ePropertySOState, 8 },
166 { IVariable::DT_SOSTATES, "Smart Object States", ePropertySOStates, 8 },
167 { IVariable::DT_SOSTATEPATTERN, "Smart Object State Pattern", ePropertySOStatePattern, 8 },
168 { IVariable::DT_SOACTION, "AI Action", ePropertySOAction, 8 },
169 { IVariable::DT_SOHELPER, "Smart Object Helper", ePropertySOHelper, 8 },
170 { IVariable::DT_SONAVHELPER, "Smart Object Navigation Helper", ePropertySONavHelper, 8 },
171 { IVariable::DT_SOANIMHELPER, "Smart Object Animation Helper", ePropertySOAnimHelper, 8 },
172 { IVariable::DT_SOEVENT, "Smart Object Event", ePropertySOEvent, 8 },
173 { IVariable::DT_SOTEMPLATE, "Smart Object Template", ePropertySOTemplate, 8 },
174 { IVariable::DT_CUSTOMACTION, "Custom Action", ePropertyCustomAction, 7 },
175 { IVariable::DT_VEEDHELPER, "Vehicle Helper", ePropertySelection, -1 },
176 { IVariable::DT_VEEDPART, "Vehicle Part", ePropertySelection, -1 },
177 { IVariable::DT_VEEDCOMP, "Vehicle Component", ePropertySelection, -1 },
178 { IVariable::DT_GAMETOKEN, "Game Token", ePropertyGameToken, -1 },
179 { IVariable::DT_SEQUENCE, "Sequence", ePropertySequence, -1 },
180 { IVariable::DT_MISSIONOBJ, "Mission Objective", ePropertyMissionObj, -1 },
181 { IVariable::DT_USERITEMCB, "User", ePropertyUser, -1 },
182 { IVariable::DT_AITERRITORY, "AITerritory", ePropertyAiTerritory, 8 },
183 { IVariable::DT_AIWAVE, "AIWave", ePropertyAiWave, 8 },
184 { IVariable::DT_SEQUENCE_ID, "SequenceId", ePropertySequenceId, -1 },
185 { IVariable::DT_FLARE, "Flare", ePropertyFlare, 7 },
186 { IVariable::DT_PARTICLE_EFFECT, "ParticleEffect", ePropertyParticleName, 3 },
187 { IVariable::DT_GEOM_CACHE, "Geometry Cache", ePropertyGeomCache, 5 },
188 { IVariable::DT_AUDIO_TRIGGER, "Audio Trigger", ePropertyAudioTrigger, 6 },
189 { IVariable::DT_AUDIO_SWITCH, "Audio Switch", ePropertyAudioSwitch, 6 },
190 { IVariable::DT_AUDIO_SWITCH_STATE, "Audio Switch", ePropertyAudioSwitchState, 6 },
191 { IVariable::DT_AUDIO_RTPC, "Audio Realtime Parameter Control", ePropertyAudioRTPC, 6 },
192 { IVariable::DT_AUDIO_ENVIRONMENT, "Audio Environment", ePropertyAudioEnvironment, 6 },
193 { IVariable::DT_AUDIO_PRELOAD_REQUEST, "Audio Preload Request", ePropertyAudioPreloadRequest, 6 },
194 { IVariable::DT_DYNAMIC_RESPONSE_SIGNAL, "Dynamic Response Signal", ePropertyDynamicResponseSignal, 6 },
196 static int NumPropertyTypes = sizeof(s_propertyTypeNames) / sizeof(s_propertyTypeNames[0]);
198 const char* DISPLAY_NAME_ATTR = "DisplayName";
199 const char* VALUE_ATTR = "Value";
200 const char* TYPE_ATTR = "Type";
201 const char* TIP_ATTR = "Tip";
202 const char* TIP_CVAR_ATTR = "TipCVar";
203 const char* FILEFILTER_ATTR = "FileFilters";
204 const int FLOAT_NUM_DIGITS = 6;
206 static const char* PropertyTypeToResourceType(PropertyType type)
208 // The strings below are names used together with
209 // REGISTER_RESOURCE_SELECTOR. See IResourceSelector.h.
210 switch (type)
212 case ePropertyAnimation:
213 return "CharacterAnimation";
214 case ePropertyModel:
215 return "Model";
216 case ePropertyGeomCache:
217 return "GeometryCache";
218 case ePropertyAudioTrigger:
219 return "AudioTrigger";
220 case ePropertyAudioSwitch:
221 return "AudioSwitch";
222 case ePropertyAudioSwitchState:
223 return "AudioSwitchState";
224 case ePropertyAudioRTPC:
225 return "AudioRTPC";
226 case ePropertyAudioEnvironment:
227 return "AudioEnvironment";
228 case ePropertyAudioPreloadRequest:
229 return "AudioPreloadRequest";
230 case ePropertyDynamicResponseSignal:
231 return "DynamicResponseSignal";
232 default:
233 return 0;
239 HDWP CPropertyItem::s_HDWP = 0;
241 //////////////////////////////////////////////////////////////////////////
243 namespace PropertyItem_Private
245 inline void FormatFloatForUICString(CString& outstr, int significantDigits, double value)
247 string crystr = outstr.GetString();
248 FormatFloatForUI(crystr, significantDigits, value);
249 outstr = crystr.GetString();
253 //////////////////////////////////////////////////////////////////////////
254 // CPropertyItem implementation.
255 //////////////////////////////////////////////////////////////////////////
256 CPropertyItem::CPropertyItem(CPropertyCtrl* pCtrl)
258 m_propertyCtrl = pCtrl;
259 m_pControlsHostWnd = 0;
260 m_parent = 0;
261 m_bExpandable = false;
262 m_bExpanded = false;
263 m_bEditChildren = false;
264 m_bShowChildren = false;
265 m_bSelected = false;
266 m_bNoCategory = false;
268 m_pStaticText = 0;
269 m_cNumber = 0;
270 m_cNumber1 = 0;
271 m_cNumber2 = 0;
272 m_cNumber3 = 0;
274 m_cFillSlider = 0;
275 m_cEdit = 0;
276 m_cCombo = 0;
277 m_cButton = 0;
278 m_cButton2 = 0;
279 m_cButton3 = 0;
280 m_cButton4 = 0;
281 m_cButton5 = 0;
282 m_cExpandButton = 0;
283 m_cCheckBox = 0;
284 m_cSpline = 0;
285 m_cColorSpline = 0;
286 m_cColorButton = 0;
288 m_image = -1;
289 m_bIgnoreChildsUpdate = false;
290 m_value = "";
291 m_type = ePropertyInvalid;
293 m_modified = false;
294 m_bMoveControls = false;
295 m_valueMultiplier = 1;
296 m_pEnumDBItem = 0;
298 m_bForceModified = false;
300 m_nHeight = 14;
302 m_nCategoryPageId = -1;
304 m_strNoScriptDefault = "<<undefined>>";
305 m_strScriptDefault = m_strNoScriptDefault;
308 CPropertyItem::~CPropertyItem()
310 // just to make sure we dont double (or infinitely recurse...) delete
311 AddRef();
313 DestroyInPlaceControl();
315 if (m_pVariable)
316 ReleaseVariable();
318 for (int i = 0; i < m_childs.size(); i++)
320 m_childs[i]->m_parent = 0;
324 //////////////////////////////////////////////////////////////////////////
325 void CPropertyItem::SetXmlNode(XmlNodeRef& node)
327 m_node = node;
328 // No Undo while just creating properties.
329 //GetIEditor()->GetIUndoManager()->Suspend();
330 ParseXmlNode();
331 //GetIEditor()->GetIUndoManager()->Resume();
334 //////////////////////////////////////////////////////////////////////////
335 void CPropertyItem::ParseXmlNode(bool bRecursive /* =true */)
337 if (!m_node->getAttr(DISPLAY_NAME_ATTR, m_name))
339 m_name = m_node->getTag();
342 CString value;
343 bool bHasValue = m_node->getAttr(VALUE_ATTR, value);
345 CString type;
346 m_node->getAttr(TYPE_ATTR, type);
348 m_tip = "";
349 m_node->getAttr(TIP_ATTR, m_tip);
351 // read description from associated console variable
352 CString tipCVarName;
353 m_node->getAttr(TIP_CVAR_ATTR, tipCVarName);
354 if (!tipCVarName.IsEmpty())
356 tipCVarName.Replace("*", m_name);
357 if (ICVar* pCVar = gEnv->pConsole->GetCVar(tipCVarName))
358 m_tip = pCVar->GetHelp();
361 m_image = -1;
362 m_type = ePropertyInvalid;
363 for (int i = 0; i < NumPropertyTypes; i++)
365 if (stricmp(type, s_propertyTypeNames[i].name) == 0)
367 m_type = s_propertyTypeNames[i].type;
368 m_image = s_propertyTypeNames[i].image;
369 break;
373 m_rangeMin = 0;
374 m_rangeMax = 100;
375 m_step = 0.1f;
376 m_bHardMin = m_bHardMax = false;
377 if (m_type == ePropertyFloat || m_type == ePropertyInt)
379 if (m_node->getAttr("Min", m_rangeMin))
380 m_bHardMin = true;
381 if (m_node->getAttr("Max", m_rangeMax))
382 m_bHardMax = true;
384 int nPrecision;
385 if (!m_node->getAttr("Precision", nPrecision))
386 nPrecision = max(3 - int(log(m_rangeMax - m_rangeMin) / log(10.f)), 0);
387 m_step = powf(10.f, -nPrecision);
390 if (bHasValue)
391 SetValue(value, false);
393 m_bNoCategory = false;
395 if ((m_type == ePropertyVector || m_type == ePropertyVector2 || m_type == ePropertyVector4) && !m_propertyCtrl->IsExtenedUI())
397 m_bEditChildren = true;
398 bRecursive = false;
399 m_childs.clear();
401 if (m_type == ePropertyVector)
403 Vec3 vec;
404 m_node->getAttr(VALUE_ATTR, vec);
405 // Create 3 sub elements.
406 XmlNodeRef x = m_node->createNode("X");
407 XmlNodeRef y = m_node->createNode("Y");
408 XmlNodeRef z = m_node->createNode("Z");
409 x->setAttr(TYPE_ATTR, "Float");
410 y->setAttr(TYPE_ATTR, "Float");
411 z->setAttr(TYPE_ATTR, "Float");
413 x->setAttr(VALUE_ATTR, vec.x);
414 y->setAttr(VALUE_ATTR, vec.y);
415 z->setAttr(VALUE_ATTR, vec.z);
417 // Start ignoring all updates comming from childs. (Initializing childs).
418 m_bIgnoreChildsUpdate = true;
420 CPropertyItemPtr itemX = new CPropertyItem(m_propertyCtrl);
421 itemX->SetXmlNode(x);
422 AddChild(itemX);
424 CPropertyItemPtr itemY = new CPropertyItem(m_propertyCtrl);
425 itemY->SetXmlNode(y);
426 AddChild(itemY);
428 CPropertyItemPtr itemZ = new CPropertyItem(m_propertyCtrl);
429 itemZ->SetXmlNode(z);
430 AddChild(itemZ);
432 else if (m_type == ePropertyVector2)
434 Vec2 vec;
435 m_node->getAttr(VALUE_ATTR, vec);
436 // Create 3 sub elements.
437 XmlNodeRef x = m_node->createNode("X");
438 XmlNodeRef y = m_node->createNode("Y");
439 x->setAttr(TYPE_ATTR, "Float");
440 y->setAttr(TYPE_ATTR, "Float");
442 x->setAttr(VALUE_ATTR, vec.x);
443 y->setAttr(VALUE_ATTR, vec.y);
445 // Start ignoring all updates comming from childs. (Initializing childs).
446 m_bIgnoreChildsUpdate = true;
448 CPropertyItemPtr itemX = new CPropertyItem(m_propertyCtrl);
449 itemX->SetXmlNode(x);
450 AddChild(itemX);
452 CPropertyItemPtr itemY = new CPropertyItem(m_propertyCtrl);
453 itemY->SetXmlNode(y);
454 AddChild(itemY);
456 else if (m_type == ePropertyVector4)
458 Vec4 vec;
459 m_node->getAttr(VALUE_ATTR, vec);
460 // Create 3 sub elements.
461 XmlNodeRef x = m_node->createNode("X");
462 XmlNodeRef y = m_node->createNode("Y");
463 XmlNodeRef z = m_node->createNode("Z");
464 XmlNodeRef w = m_node->createNode("W");
465 x->setAttr(TYPE_ATTR, "Float");
466 y->setAttr(TYPE_ATTR, "Float");
467 z->setAttr(TYPE_ATTR, "Float");
468 w->setAttr(TYPE_ATTR, "Float");
470 x->setAttr(VALUE_ATTR, vec.x);
471 y->setAttr(VALUE_ATTR, vec.y);
472 z->setAttr(VALUE_ATTR, vec.z);
473 w->setAttr(VALUE_ATTR, vec.w);
475 // Start ignoring all updates comming from childs. (Initializing childs).
476 m_bIgnoreChildsUpdate = true;
478 CPropertyItemPtr itemX = new CPropertyItem(m_propertyCtrl);
479 itemX->SetXmlNode(x);
480 AddChild(itemX);
482 CPropertyItemPtr itemY = new CPropertyItem(m_propertyCtrl);
483 itemY->SetXmlNode(y);
484 AddChild(itemY);
486 CPropertyItemPtr itemZ = new CPropertyItem(m_propertyCtrl);
487 itemZ->SetXmlNode(z);
488 AddChild(itemZ);
490 CPropertyItemPtr itemW = new CPropertyItem(m_propertyCtrl);
491 itemW->SetXmlNode(w);
492 AddChild(itemW);
494 m_bNoCategory = true;
495 m_bExpandable = true;
496 m_bIgnoreChildsUpdate = false;
498 else if (bRecursive)
500 // If recursive and not vector.
502 m_bExpandable = false;
503 // Create sub-nodes.
504 for (int i = 0; i < m_node->getChildCount(); i++)
506 m_bIgnoreChildsUpdate = true;
508 XmlNodeRef child = m_node->getChild(i);
509 CPropertyItemPtr item = new CPropertyItem(m_propertyCtrl);
510 item->SetXmlNode(m_node->getChild(i));
511 AddChild(item);
512 m_bExpandable = true;
514 m_bIgnoreChildsUpdate = false;
517 m_modified = false;
520 //////////////////////////////////////////////////////////////////////////
521 void CPropertyItem::SetVariable(IVariable* var)
523 if (var == m_pVariable)
524 return;
526 _smart_ptr<IVariable> pInputVar = var;
528 // Release previous variable.
529 if (m_pVariable)
530 ReleaseVariable();
532 m_pVariable = pInputVar;
533 assert(m_pVariable != NULL);
535 m_pVariable->AddOnSetCallback(functor(*this, &CPropertyItem::OnVariableChange));
536 m_pVariable->EnableNotifyWithoutValueChange(m_bForceModified);
538 m_tip = "";
539 m_name = m_pVariable->GetHumanName();
541 int dataType = m_pVariable->GetDataType();
543 m_image = -1;
544 m_type = ePropertyInvalid;
545 int i;
547 if (dataType != IVariable::DT_SIMPLE)
549 for (i = 0; i < NumPropertyTypes; i++)
551 if (dataType == s_propertyTypeNames[i].dataType)
553 m_type = s_propertyTypeNames[i].type;
554 m_image = s_propertyTypeNames[i].image;
555 break;
560 m_enumList = m_pVariable->GetEnumList();
561 if (m_enumList != NULL)
563 m_type = ePropertySelection;
566 if (m_type == ePropertyInvalid)
568 switch (m_pVariable->GetType())
570 case IVariable::INT:
571 m_type = ePropertyInt;
572 break;
573 case IVariable::BOOL:
574 m_type = ePropertyBool;
575 break;
576 case IVariable::FLOAT:
577 m_type = ePropertyFloat;
578 break;
579 case IVariable::VECTOR2:
580 m_type = ePropertyVector2;
581 break;
582 case IVariable::VECTOR4:
583 m_type = ePropertyVector4;
584 break;
585 case IVariable::VECTOR:
586 m_type = ePropertyVector;
587 break;
588 case IVariable::STRING:
589 m_type = ePropertyString;
590 break;
592 for (i = 0; i < NumPropertyTypes; i++)
594 if (m_type == s_propertyTypeNames[i].type)
596 m_image = s_propertyTypeNames[i].image;
597 break;
602 m_valueMultiplier = 1;
603 m_rangeMin = 0;
604 m_rangeMax = 100;
605 m_step = 0.f;
606 m_bHardMin = m_bHardMax = false;
608 // Get variable limits.
609 m_pVariable->GetLimits(m_rangeMin, m_rangeMax, m_step, m_bHardMin, m_bHardMax);
611 // Check if value is percents.
612 if (dataType == IVariable::DT_PERCENT)
614 // Scale all values by 100.
615 m_valueMultiplier = 100;
617 else if (dataType == IVariable::DT_ANGLE)
619 // Scale radians to degrees.
620 m_valueMultiplier = RAD2DEG(1);
621 m_rangeMin = -360;
622 m_rangeMax = 360;
624 else if (dataType == IVariable::DT_UIENUM)
626 m_pEnumDBItem = GetIEditor()->GetUIEnumsDatabase()->FindEnum(m_name.GetString());
629 const bool useExplicitStep = (m_pVariable->GetFlags() & IVariable::UI_EXPLICIT_STEP);
630 if (!useExplicitStep)
632 // Limit step size to 1000.
633 int nPrec = max(3 - int(log(m_rangeMax - m_rangeMin) / log(10.f)), 0);
634 m_step = max(m_step, powf(10.f, -nPrec));
637 //////////////////////////////////////////////////////////////////////////
638 VarToValue();
640 m_bNoCategory = false;
642 switch (m_type)
644 case ePropertyAiPFPropertiesList:
645 m_bEditChildren = true;
646 AddChildrenForPFProperties();
647 m_bNoCategory = true;
648 m_bExpandable = true;
649 break;
651 case ePropertyAiEntityClasses:
652 m_bEditChildren = true;
653 AddChildrenForAIEntityClasses();
654 m_bNoCategory = true;
655 m_bExpandable = true;
656 break;
658 case ePropertyVector2:
659 if (!m_propertyCtrl->IsExtenedUI())
661 m_bEditChildren = true;
662 m_childs.clear();
664 Vec2 vec;
665 m_pVariable->Get(vec);
666 IVariable* pVX = new CVariable<float>;
667 pVX->SetName("x");
668 pVX->SetLimits(m_rangeMin, m_rangeMax, m_step, m_bHardMin, m_bHardMax);
669 pVX->Set(vec.x);
670 IVariable* pVY = new CVariable<float>;
671 pVY->SetName("y");
672 pVY->SetLimits(m_rangeMin, m_rangeMax, m_step, m_bHardMin, m_bHardMax);
673 pVY->Set(vec.y);
675 // Start ignoring all updates coming from childs. (Initializing childs).
676 m_bIgnoreChildsUpdate = true;
678 CPropertyItemPtr itemX = new CPropertyItem(m_propertyCtrl);
679 itemX->SetVariable(pVX);
680 AddChild(itemX);
682 CPropertyItemPtr itemY = new CPropertyItem(m_propertyCtrl);
683 itemY->SetVariable(pVY);
684 AddChild(itemY);
686 m_bNoCategory = true;
687 m_bExpandable = true;
689 m_bIgnoreChildsUpdate = false;
691 break;
693 case ePropertyVector4:
694 if (!m_propertyCtrl->IsExtenedUI())
696 m_bEditChildren = true;
697 m_childs.clear();
699 Vec4 vec;
700 m_pVariable->Get(vec);
701 IVariable* pVX = new CVariable<float>;
702 pVX->SetName("x");
703 pVX->SetLimits(m_rangeMin, m_rangeMax, m_step, m_bHardMin, m_bHardMax);
704 pVX->Set(vec.x);
705 IVariable* pVY = new CVariable<float>;
706 pVY->SetName("y");
707 pVY->SetLimits(m_rangeMin, m_rangeMax, m_step, m_bHardMin, m_bHardMax);
708 pVY->Set(vec.y);
709 IVariable* pVZ = new CVariable<float>;
710 pVZ->SetName("z");
711 pVZ->SetLimits(m_rangeMin, m_rangeMax, m_step, m_bHardMin, m_bHardMax);
712 pVZ->Set(vec.z);
713 IVariable* pVW = new CVariable<float>;
714 pVW->SetName("w");
715 pVW->SetLimits(m_rangeMin, m_rangeMax, m_step, m_bHardMin, m_bHardMax);
716 pVW->Set(vec.w);
718 // Start ignoring all updates coming from childs. (Initializing childs).
719 m_bIgnoreChildsUpdate = true;
721 CPropertyItemPtr itemX = new CPropertyItem(m_propertyCtrl);
722 itemX->SetVariable(pVX);
723 AddChild(itemX);
725 CPropertyItemPtr itemY = new CPropertyItem(m_propertyCtrl);
726 itemY->SetVariable(pVY);
727 AddChild(itemY);
729 CPropertyItemPtr itemZ = new CPropertyItem(m_propertyCtrl);
730 itemZ->SetVariable(pVZ);
731 AddChild(itemZ);
733 CPropertyItemPtr itemW = new CPropertyItem(m_propertyCtrl);
734 itemZ->SetVariable(pVW);
735 AddChild(itemW);
737 m_bNoCategory = true;
738 m_bExpandable = true;
740 m_bIgnoreChildsUpdate = false;
743 case ePropertyVector:
744 if (!m_propertyCtrl->IsExtenedUI())
746 m_bEditChildren = true;
747 m_childs.clear();
749 Vec3 vec;
750 m_pVariable->Get(vec);
751 IVariable* pVX = new CVariable<float>;
752 pVX->SetName("x");
753 pVX->SetLimits(m_rangeMin, m_rangeMax, m_step, m_bHardMin, m_bHardMax);
754 pVX->Set(vec.x);
755 IVariable* pVY = new CVariable<float>;
756 pVY->SetName("y");
757 pVY->SetLimits(m_rangeMin, m_rangeMax, m_step, m_bHardMin, m_bHardMax);
758 pVY->Set(vec.y);
759 IVariable* pVZ = new CVariable<float>;
760 pVZ->SetName("z");
761 pVZ->SetLimits(m_rangeMin, m_rangeMax, m_step, m_bHardMin, m_bHardMax);
762 pVZ->Set(vec.z);
764 // Start ignoring all updates coming from childs. (Initializing childs).
765 m_bIgnoreChildsUpdate = true;
767 CPropertyItemPtr itemX = new CPropertyItem(m_propertyCtrl);
768 itemX->SetVariable(pVX);
769 AddChild(itemX);
771 CPropertyItemPtr itemY = new CPropertyItem(m_propertyCtrl);
772 itemY->SetVariable(pVY);
773 AddChild(itemY);
775 CPropertyItemPtr itemZ = new CPropertyItem(m_propertyCtrl);
776 itemZ->SetVariable(pVZ);
777 AddChild(itemZ);
779 m_bNoCategory = true;
780 m_bExpandable = true;
782 m_bIgnoreChildsUpdate = false;
784 break;
787 if (m_pVariable->GetNumVariables() > 0)
789 if (m_type == ePropertyInvalid)
790 m_type = ePropertyTable;
791 m_bExpandable = true;
792 if (m_pVariable->GetFlags() & IVariable::UI_SHOW_CHILDREN)
793 m_bShowChildren = true;
794 m_bIgnoreChildsUpdate = true;
795 for (i = 0; i < m_pVariable->GetNumVariables(); i++)
797 CPropertyItemPtr item = new CPropertyItem(m_propertyCtrl);
798 item->SetVariable(m_pVariable->GetVariable(i));
799 AddChild(item);
801 m_bIgnoreChildsUpdate = false;
804 m_modified = false;
807 //////////////////////////////////////////////////////////////////////////
808 void CPropertyItem::ReleaseVariable()
810 if (m_pVariable)
812 // Unwire all from variable.
813 m_pVariable->RemoveOnSetCallback(functor(*this, &CPropertyItem::OnVariableChange));
815 m_pVariable = 0;
818 //////////////////////////////////////////////////////////////////////////
819 //! Find item that reference specified property.
820 CPropertyItem* CPropertyItem::FindItemByVar(IVariable* pVar)
822 if (m_pVariable == pVar)
823 return this;
824 for (int i = 0; i < m_childs.size(); i++)
826 CPropertyItem* pFound = m_childs[i]->FindItemByVar(pVar);
827 if (pFound)
828 return pFound;
830 return 0;
833 //////////////////////////////////////////////////////////////////////////
834 CString CPropertyItem::GetFullName() const
836 if (m_parent)
838 return m_parent->GetFullName() + "::" + m_name;
840 else
841 return m_name;
844 //////////////////////////////////////////////////////////////////////////
845 CPropertyItem* CPropertyItem::FindItemByFullName(const CString& name)
847 if (GetFullName() == name)
848 return this;
849 for (int i = 0; i < m_childs.size(); i++)
851 CPropertyItem* pFound = m_childs[i]->FindItemByFullName(name);
852 if (pFound)
853 return pFound;
855 return 0;
858 //////////////////////////////////////////////////////////////////////////
859 void CPropertyItem::AddChild(CPropertyItem* item)
861 assert(item);
862 m_bExpandable = true;
863 item->m_parent = this;
864 m_childs.push_back(item);
867 //////////////////////////////////////////////////////////////////////////
868 void CPropertyItem::RemoveChild(CPropertyItem* item)
870 // Find item and erase it from childs array.
871 for (int i = 0; i < m_childs.size(); i++)
873 if (item == m_childs[i])
875 m_childs.erase(m_childs.begin() + i);
876 break;
881 //////////////////////////////////////////////////////////////////////////
882 void CPropertyItem::RemoveAllChildren()
884 m_childs.clear();
887 //////////////////////////////////////////////////////////////////////////
888 void CPropertyItem::OnChildChanged(CPropertyItem* child)
890 if (m_bIgnoreChildsUpdate)
891 return;
893 if (m_bEditChildren)
895 // Update parent.
896 CString sValue;
897 if ((m_type == ePropertyAiPFPropertiesList) || (m_type == ePropertyAiEntityClasses))
899 for (int i = 0; i < m_childs.size(); i++)
901 CString token;
902 int index = 0;
903 CString value = m_childs[i]->GetValue();
904 while (!(token = value.Tokenize(" ,", index)).IsEmpty())
906 if (!sValue.IsEmpty())
907 sValue += ", ";
908 sValue += token;
912 else
914 for (int i = 0; i < m_childs.size(); i++)
916 if (i > 0)
917 sValue += ", ";
918 sValue += m_childs[i]->GetValue();
921 SetValue(sValue, false);
923 if (m_bEditChildren || m_bShowChildren)
924 SendToControl();
927 //////////////////////////////////////////////////////////////////////////
928 void CPropertyItem::SetSelected(bool selected)
930 m_bSelected = selected;
933 //////////////////////////////////////////////////////////////////////////
934 void CPropertyItem::SetExpanded(bool expanded)
936 if (IsDisabled())
938 m_bExpanded = false;
940 else
941 m_bExpanded = expanded;
944 bool CPropertyItem::IsDisabled() const
946 if (m_pVariable)
948 return m_pVariable->GetFlags() & IVariable::UI_DISABLED;
950 return false;
953 bool CPropertyItem::IsInvisible() const
955 if (m_pVariable)
957 return m_pVariable->GetFlags() & IVariable::UI_INVISIBLE;
959 return false;
962 bool CPropertyItem::IsBold() const
964 if (m_pVariable)
966 return m_pVariable->GetFlags() & IVariable::UI_BOLD;
968 return false;
971 //////////////////////////////////////////////////////////////////////////
972 void CPropertyItem::CreateInPlaceControl(CWnd* pWndParent, CRect& ctrlRect)
974 if (IsDisabled())
975 return;
977 m_controls.clear();
979 m_bMoveControls = true;
980 CRect nullRc(0, 0, 0, 0);
981 DWORD style;
982 switch (m_type)
984 case ePropertyFloat:
985 case ePropertyInt:
986 case ePropertyAngle:
988 if (m_pEnumDBItem)
990 // Combo box.
991 m_cCombo = new CInPlaceComboBox();
992 m_cCombo->SetReadOnly(true);
993 int unsorted = m_pEnumDBItem->strings.size() && !strcmp(m_pEnumDBItem->strings[0], "#unsorted");
994 DWORD nSorting = (unsorted || m_pVariable && m_pVariable->GetFlags() & IVariable::UI_UNSORTED) ? 0 : LBS_SORT;
995 m_cCombo->Create(NULL, "", WS_CHILD | WS_VISIBLE | nSorting, nullRc, pWndParent, 2);
996 m_cCombo->SetUpdateCallback(functor(*this, &CPropertyItem::OnComboSelection));
998 for (int i = unsorted; i < m_pEnumDBItem->strings.size(); i++)
999 m_cCombo->AddString(m_pEnumDBItem->strings[i]);
1001 else
1003 m_cNumber = new CNumberCtrl;
1004 m_cNumber->SetUpdateCallback(functor(*this, &CPropertyItem::OnNumberCtrlUpdate));
1005 m_cNumber->EnableUndo(m_name + " Modified");
1006 m_cNumber->EnableNotifyWithoutValueChange(m_bForceModified);
1007 //m_cNumber->SetBeginUpdateCallback( functor(*this,OnNumberCtrlBeginUpdate) );
1008 //m_cNumber->SetEndUpdateCallback( functor(*this,OnNumberCtrlEndUpdate) );
1010 // (digits behind the comma, only used for floats)
1011 if (m_type == ePropertyFloat)
1013 m_cNumber->SetStep(m_step);
1014 m_cNumber->SetFloatFormatPrecision(FLOAT_NUM_DIGITS);
1016 else if (m_type == ePropertyAngle)
1018 m_cNumber->SetFloatFormatPrecision(FLOAT_NUM_DIGITS);
1021 // Only for integers.
1022 if (m_type == ePropertyInt)
1023 m_cNumber->SetInteger(true);
1024 m_cNumber->SetMultiplier(m_valueMultiplier);
1025 m_cNumber->SetRange(m_bHardMin ? m_rangeMin : -FLT_MAX, m_bHardMax ? m_rangeMax : FLT_MAX);
1027 m_cNumber->Create(pWndParent, nullRc, 1, CNumberCtrl::NOBORDER | CNumberCtrl::LEFTALIGN);
1028 m_cNumber->SetLeftAlign(true);
1030 if (m_bHardMin || m_bHardMax)
1032 m_cFillSlider = new CFillSliderCtrl;
1033 m_cFillSlider->EnableUndo(m_name + " Modified");
1034 m_cFillSlider->Create(WS_VISIBLE | WS_CHILD, nullRc, pWndParent, 2);
1035 m_cFillSlider->SetUpdateCallback(functor(*this, &CPropertyItem::OnFillSliderCtrlUpdate));
1036 m_cFillSlider->SetRangeFloat(m_rangeMin / m_valueMultiplier, m_rangeMax / m_valueMultiplier, m_step / m_valueMultiplier);
1040 break;
1042 case ePropertyTable:
1043 if (!m_bEditChildren)
1044 break;
1046 //These used to be a combo box but right now defaulting back to editbox
1047 case ePropertyAiTerritory:
1048 case ePropertyAiWave:
1050 case ePropertyString:
1051 if (m_pEnumDBItem)
1053 // Combo box.
1054 m_cCombo = new CInPlaceComboBox();
1055 m_cCombo->SetReadOnly(true);
1056 DWORD nSorting = (m_pVariable && m_pVariable->GetFlags() & IVariable::UI_UNSORTED) ? 0 : LBS_SORT;
1057 m_cCombo->Create(NULL, "", WS_CHILD | WS_VISIBLE | nSorting, nullRc, pWndParent, 2);
1058 m_cCombo->SetUpdateCallback(functor(*this, &CPropertyItem::OnComboSelection));
1060 for (int i = 0; i < m_pEnumDBItem->strings.size(); i++)
1061 m_cCombo->AddString(m_pEnumDBItem->strings[i]);
1062 break;
1064 else
1066 // Here we must check the global table to see if this enum should be loaded from the XML.
1067 TDValues* pcValue = (m_pVariable) ? GetEnumValues(m_pVariable->GetName()) : NULL;
1069 // If there is not even this, we THEN fall back to create the edit box.
1070 if (pcValue)
1072 m_cCombo = new CInPlaceComboBox();
1073 m_cCombo->SetReadOnly(true);
1074 DWORD nSorting = (m_pVariable && m_pVariable->GetFlags() & IVariable::UI_UNSORTED) ? 0 : LBS_SORT;
1075 m_cCombo->Create(NULL, "", WS_CHILD | WS_VISIBLE | nSorting, nullRc, pWndParent, 2);
1076 m_cCombo->SetUpdateCallback(functor(*this, &CPropertyItem::OnComboSelection));
1078 for (int i = 0; i < pcValue->size(); i++)
1080 m_cCombo->AddString((*pcValue)[i]);
1082 break;
1085 // ... else, fall through to create edit box.
1087 case ePropertyVector:
1088 case ePropertyVector2:
1089 case ePropertyVector4:
1090 m_cEdit = new CInPlaceEdit(m_value, functor(*this, &CPropertyItem::OnEditChanged));
1091 m_cEdit->Create(WS_CHILD | WS_VISIBLE | ES_AUTOHSCROLL | ES_LEFT, nullRc, pWndParent, 2);
1092 m_cEdit->EnableUpdateOnKillFocus(!m_bForceModified);
1093 break;
1095 case ePropertyMaterial:
1096 case ePropertyAiBehavior:
1097 case ePropertyAiAnchor:
1098 #ifdef USE_DEPRECATED_AI_CHARACTER_SYSTEM
1099 case ePropertyAiCharacter:
1100 #endif
1101 case ePropertyAiPFPropertiesList:
1102 case ePropertyAiEntityClasses:
1103 case ePropertyEquip:
1104 case ePropertyReverbPreset:
1105 case ePropertySOClass:
1106 case ePropertySOClasses:
1107 case ePropertySOState:
1108 case ePropertySOStates:
1109 case ePropertySOStatePattern:
1110 case ePropertySOAction:
1111 case ePropertySOHelper:
1112 case ePropertySONavHelper:
1113 case ePropertySOAnimHelper:
1114 case ePropertySOEvent:
1115 case ePropertySOTemplate:
1116 case ePropertyCustomAction:
1117 case ePropertyGameToken:
1118 case ePropertyMissionObj:
1119 case ePropertySequence:
1120 case ePropertySequenceId:
1121 case ePropertyUser:
1122 case ePropertyLocalString:
1123 case ePropertyParticleName:
1124 case ePropertyFlare:
1125 m_cEdit = new CInPlaceEdit(m_value, functor(*this, &CPropertyItem::OnEditChanged));
1126 style = WS_CHILD | WS_VISIBLE | ES_AUTOHSCROLL | ES_LEFT;
1127 if (m_type == ePropertySequenceId)
1128 style |= ES_READONLY;
1129 m_cEdit->Create(style, nullRc, pWndParent, 2);
1130 m_cEdit->EnableUpdateOnKillFocus(!m_bForceModified);
1131 if (m_type == ePropertyMaterial)
1133 m_cButton = new CInPlaceButton(functor(*this, &CPropertyItem::OnMaterialBrowseButton));
1134 m_cButton->Create("...", WS_CHILD | WS_VISIBLE, nullRc, pWndParent, 4);
1136 m_cButton2 = new CInPlaceButton(functor(*this, &CPropertyItem::OnMaterialPickSelectedButton));
1137 m_cButton2->Create("<", WS_CHILD | WS_VISIBLE, nullRc, pWndParent, 5);
1139 else if (m_type == ePropertySequence)
1141 m_cButton = new CInPlaceButton(functor(*this, &CPropertyItem::OnSequenceBrowseButton));
1142 m_cButton->Create("...", WS_CHILD | WS_VISIBLE, nullRc, pWndParent, 4);
1144 else if (m_type == ePropertySequenceId)
1146 m_cButton = new CInPlaceButton(functor(*this, &CPropertyItem::OnSequenceIdBrowseButton));
1147 m_cButton->Create("...", WS_CHILD | WS_VISIBLE, nullRc, pWndParent, 4);
1149 else if (m_type == ePropertyMissionObj)
1151 m_cButton = new CInPlaceButton(functor(*this, &CPropertyItem::OnMissionObjButton));
1152 m_cButton->Create("...", WS_CHILD | WS_VISIBLE, nullRc, pWndParent, 4);
1154 else if (m_type == ePropertyUser)
1156 m_cButton = new CInPlaceButton(functor(*this, &CPropertyItem::OnUserBrowseButton));
1157 m_cButton->Create("...", WS_CHILD | WS_VISIBLE, nullRc, pWndParent, 4);
1159 else if (m_type == ePropertyLocalString)
1161 m_cButton = new CInPlaceButton(functor(*this, &CPropertyItem::OnLocalStringBrowseButton));
1162 m_cButton->Create("...", WS_CHILD | WS_VISIBLE, nullRc, pWndParent, 4);
1164 else if (GetIEditor()->CanEditDeprecatedProperty(m_type))
1166 //handle with deprecated picker registration system
1167 //this only works for button-style pickers, improve system if necessary
1168 m_cButton = new CInPlaceButton(functor(*this, &CPropertyItem::OnEditDeprecatedProperty));
1169 m_cButton->Create("...", WS_CHILD | WS_VISIBLE, nullRc, pWndParent, 4);
1171 break;
1173 case ePropertySelection:
1175 // Combo box.
1176 m_cCombo = new CInPlaceComboBox();
1177 m_cCombo->SetReadOnly(true);
1178 DWORD nSorting = (m_pVariable && m_pVariable->GetFlags() & IVariable::UI_UNSORTED) ? 0 : LBS_SORT;
1179 m_cCombo->Create(NULL, "", WS_CHILD | WS_VISIBLE | nSorting, nullRc, pWndParent, 2);
1180 m_cCombo->SetUpdateCallback(functor(*this, &CPropertyItem::OnComboSelection));
1182 if (m_enumList)
1184 for (uint i = 0; cstr sEnumName = m_enumList->GetItemName(i); i++)
1186 m_cCombo->AddString(sEnumName);
1189 else
1190 m_cCombo->SetReadOnly(false);
1192 break;
1194 case ePropertyColor:
1196 m_cEdit = new CInPlaceEdit(m_value, functor(*this, &CPropertyItem::OnEditChanged));
1197 m_cEdit->Create(WS_CHILD | WS_VISIBLE | ES_AUTOHSCROLL | ES_LEFT, nullRc, pWndParent, 2);
1198 m_cEdit->EnableUpdateOnKillFocus(!m_bForceModified);
1199 m_cColorButton = new CInPlaceColorButton(functor(*this, &CPropertyItem::OnColorBrowseButton));
1200 m_cColorButton->Create("", WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON | BS_OWNERDRAW, nullRc, pWndParent, 4);
1202 break;
1204 case ePropertyFloatCurve:
1206 m_cSpline = new CSplineCtrl;
1207 m_cSpline->Create(WS_VISIBLE | WS_CHILD, nullRc, pWndParent, 2);
1208 m_cSpline->SetUpdateCallback((CSplineCtrl::UpdateCallback const&)functor(*this, &CPropertyItem::ReceiveFromControl));
1209 m_cSpline->SetTimeRange(0, 1);
1210 m_cSpline->SetValueRange(0, 1);
1211 m_cSpline->SetGrid(12, 12);
1212 m_cSpline->SetSpline(m_pVariable->GetSpline(true));
1214 break;
1216 case ePropertyColorCurve:
1218 m_cColorSpline = new CColorGradientCtrl;
1219 m_cColorSpline->Create(WS_VISIBLE | WS_CHILD, nullRc, pWndParent, 2);
1220 m_cColorSpline->SetUpdateCallback((CColorGradientCtrl::UpdateCallback const&)functor(*this, &CPropertyItem::ReceiveFromControl));
1221 m_cColorSpline->SetTimeRange(0, 1);
1222 m_cColorSpline->SetSpline(m_pVariable->GetSpline(true));
1224 break;
1226 case ePropertyTexture:
1228 m_cEdit = new CInPlaceEdit(m_value, functor(*this, &CPropertyItem::OnEditChanged));
1229 m_cEdit->Create(WS_CHILD | WS_VISIBLE | ES_AUTOHSCROLL | ES_LEFT, nullRc, pWndParent, 2);
1230 m_cEdit->EnableUpdateOnKillFocus(!m_bForceModified);
1232 HICON hButtonIcon(NULL);
1234 hButtonIcon = (HICON)LoadImage(AfxGetInstanceHandle(), MAKEINTRESOURCE(IDI_FILE_BROWSE), IMAGE_ICON, 16, 15, LR_DEFAULTCOLOR | LR_SHARED);
1235 m_cButton3 = new CInPlaceButton(functor(*this, &CPropertyItem::OnFileBrowseButton));
1236 m_cButton3->Create("...", WS_CHILD | WS_VISIBLE, nullRc, pWndParent, 4);
1237 m_cButton3->SetIcon(CSize(16, 15), hButtonIcon);
1238 m_cButton3->SetBorderGap(6);
1240 break;
1242 case ePropertyAnimation:
1243 case ePropertyModel:
1244 case ePropertyGeomCache:
1245 case ePropertyAudioTrigger:
1246 case ePropertyAudioSwitch:
1247 case ePropertyAudioSwitchState:
1248 case ePropertyAudioRTPC:
1249 case ePropertyAudioEnvironment:
1250 case ePropertyAudioPreloadRequest:
1251 case ePropertyDynamicResponseSignal:
1253 m_cEdit = new CInPlaceEdit(m_value, functor(*this, &CPropertyItem::OnEditChanged));
1254 m_cEdit->Create(WS_CHILD | WS_VISIBLE | ES_AUTOHSCROLL | ES_LEFT, nullRc, pWndParent, 2);
1255 m_cEdit->EnableUpdateOnKillFocus(!m_bForceModified);
1257 m_cButton = new CInPlaceButton(functor(*this, &CPropertyItem::OnResourceSelectorButton));
1258 m_cButton->Create("...", WS_CHILD | WS_VISIBLE, nullRc, pWndParent, 4);
1260 // Use file browse icon.
1261 HICON hOpenIcon = (HICON)LoadImage(AfxGetInstanceHandle(), MAKEINTRESOURCE(IDI_FILE_BROWSE), IMAGE_ICON, 16, 15, LR_DEFAULTCOLOR | LR_SHARED);
1262 m_cButton->SetIcon(CSize(16, 15), hOpenIcon);
1263 m_cButton->SetBorderGap(0);
1265 break;
1266 case ePropertyFile:
1267 m_cEdit = new CInPlaceEdit(m_value, functor(*this, &CPropertyItem::OnEditChanged));
1268 m_cEdit->Create(WS_CHILD | WS_VISIBLE | ES_AUTOHSCROLL | ES_LEFT, nullRc, pWndParent, 2);
1269 m_cEdit->EnableUpdateOnKillFocus(!m_bForceModified);
1271 m_cButton = new CInPlaceButton(functor(*this, &CPropertyItem::OnFileBrowseButton));
1272 m_cButton->Create("...", WS_CHILD | WS_VISIBLE, nullRc, pWndParent, 4);
1274 // Use file browse icon.
1275 HICON hOpenIcon = (HICON)LoadImage(AfxGetInstanceHandle(), MAKEINTRESOURCE(IDI_FILE_BROWSE), IMAGE_ICON, 16, 15, LR_DEFAULTCOLOR | LR_SHARED);
1276 //m_cButton->SetIcon( CSize(16,15),IDI_FILE_BROWSE );
1277 m_cButton->SetIcon(CSize(16, 15), hOpenIcon);
1278 m_cButton->SetBorderGap(0);
1279 break;
1281 case ePropertyList:
1283 AddButton( "Add", CWDelegate(this,(TDelegate)OnAddItemButton) );
1285 break;
1289 MoveInPlaceControl(ctrlRect);
1290 SendToControl();
1293 //////////////////////////////////////////////////////////////////////////
1294 void CPropertyItem::CreateControls(CWnd* pWndParent, CRect& textRect, CRect& ctrlRect)
1296 m_pControlsHostWnd = pWndParent;
1297 m_rcText = textRect;
1298 m_rcControl = ctrlRect;
1300 m_bMoveControls = false;
1301 CRect nullRc(0, 0, 0, 0);
1302 DWORD style;
1304 if (IsExpandable() && !m_propertyCtrl->IsCategory(this))
1306 m_cExpandButton = new CInPlaceButton(functor(*this, &CPropertyItem::OnExpandButton));
1307 m_cExpandButton->Create("", WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON, CRect(textRect.left, textRect.top + 2, textRect.left + 12, textRect.top + 14), pWndParent, 5);
1308 m_cExpandButton->SetFlatStyle(TRUE);
1309 if (!IsExpanded())
1310 m_cExpandButton->SetIcon(CSize(8, 8), IDI_EXPAND1);
1311 else
1312 m_cExpandButton->SetIcon(CSize(8, 8), IDI_EXPAND2);
1313 textRect.left += 12;
1314 RegisterCtrl(m_cExpandButton);
1317 // Create static text. Update: put text on left of Bools as well, for UI consistency.
1318 // if (m_type != ePropertyBool)
1320 m_pStaticText = new CColorCtrl<CStatic>;
1321 CString text = GetName();
1322 if (m_type != ePropertyTable)
1324 text += " . . . . . . . . . . . . . . . . . . . . . . . . . .";
1326 m_pStaticText->Create(text, WS_CHILD | WS_VISIBLE | SS_LEFT, textRect, pWndParent);
1327 m_pStaticText->SetFont(CFont::FromHandle((HFONT)gMFCFonts.hSystemFont));
1328 RegisterCtrl(m_pStaticText);
1331 switch (m_type)
1333 case ePropertyBool:
1335 m_cCheckBox = new CInPlaceCheckBox(functor(*this, &CPropertyItem::OnCheckBoxButton));
1336 m_cCheckBox->Create("", WS_CHILD | WS_VISIBLE | BS_AUTOCHECKBOX | WS_TABSTOP, ctrlRect, pWndParent, 0);
1337 m_cCheckBox->SetFont(m_propertyCtrl->GetFont());
1338 RegisterCtrl(m_cCheckBox);
1340 break;
1341 case ePropertyFloat:
1342 case ePropertyInt:
1343 case ePropertyAngle:
1345 m_cNumber = new CNumberCtrl;
1346 m_cNumber->SetUpdateCallback(functor(*this, &CPropertyItem::OnNumberCtrlUpdate));
1347 m_cNumber->EnableUndo(m_name + " Modified");
1348 RegisterCtrl(m_cNumber);
1350 // (digits behind the comma, only used for floats)
1351 if (m_type == ePropertyFloat)
1352 m_cNumber->SetStep(m_step);
1354 // Only for integers.
1355 if (m_type == ePropertyInt)
1356 m_cNumber->SetInteger(true);
1357 m_cNumber->SetMultiplier(m_valueMultiplier);
1358 m_cNumber->SetRange(m_bHardMin ? m_rangeMin : -FLT_MAX, m_bHardMax ? m_rangeMax : FLT_MAX);
1360 m_cNumber->Create(pWndParent, nullRc, 1);
1361 m_cNumber->SetLeftAlign(true);
1364 CSliderCtrlEx *pSlider = new CSliderCtrlEx;
1365 //pSlider->EnableUndo( m_name + " Modified" );
1366 CRect rcSlider = ctrlRect;
1367 rcSlider.left += NUMBER_CTRL_WIDTH;
1368 pSlider->Create( WS_VISIBLE|WS_CHILD,rcSlider,pWndParent,2);
1370 if (m_bHardMin || m_bHardMax)
1372 m_cFillSlider = new CFillSliderCtrl;
1373 m_cFillSlider->SetFilledLook(true);
1374 //m_cFillSlider->SetFillStyle(CFillSliderCtrl::eFillStyle_Background);
1375 m_cFillSlider->EnableUndo(m_name + " Modified");
1376 m_cFillSlider->Create(WS_VISIBLE | WS_CHILD, nullRc, pWndParent, 2);
1377 m_cFillSlider->SetUpdateCallback(functor(*this, &CPropertyItem::OnFillSliderCtrlUpdate));
1378 m_cFillSlider->SetRangeFloat(m_rangeMin / m_valueMultiplier, m_rangeMax / m_valueMultiplier, m_step / m_valueMultiplier);
1379 RegisterCtrl(m_cFillSlider);
1382 break;
1384 case ePropertyVector:
1385 case ePropertyVector2:
1386 case ePropertyVector4:
1388 int numberOfElements = 3;
1389 if (m_type == ePropertyVector2)
1390 numberOfElements = 2;
1391 else if (m_type == ePropertyVector4)
1392 numberOfElements = 4;
1394 CNumberCtrl** cNumber[4] = { &m_cNumber, &m_cNumber1, &m_cNumber2, &m_cNumber3 };
1396 for (int a = 0; a < numberOfElements; a++)
1398 CNumberCtrl* pNumber = *cNumber[a] = new CNumberCtrl;
1399 pNumber->Create(pWndParent, nullRc, 1);
1400 pNumber->SetLeftAlign(true);
1401 pNumber->SetUpdateCallback(functor(*this, &CPropertyItem::OnNumberCtrlUpdate));
1402 pNumber->EnableUndo(m_name + " Modified");
1403 pNumber->SetMultiplier(m_valueMultiplier);
1404 pNumber->SetRange(m_bHardMin ? m_rangeMin : -FLT_MAX, m_bHardMax ? m_rangeMax : FLT_MAX);
1405 RegisterCtrl(pNumber);
1408 break;
1410 case ePropertyTable:
1411 if (!m_bEditChildren)
1412 break;
1413 //These used to be a combo box but right now defaulting back to editbox
1414 case ePropertyAiTerritory:
1415 case ePropertyAiWave:
1417 case ePropertyString:
1418 //case ePropertyVector:
1420 m_cEdit = new CInPlaceEdit(m_value, functor(*this, &CPropertyItem::OnEditChanged));
1421 m_cEdit->Create(WS_CHILD | WS_VISIBLE | ES_AUTOHSCROLL | ES_LEFT | WS_TABSTOP, nullRc, pWndParent, 2);
1422 m_cEdit->EnableUpdateOnKillFocus(!m_bForceModified);
1423 RegisterCtrl(m_cEdit);
1424 break;
1426 case ePropertyMaterial:
1427 case ePropertyAiBehavior:
1428 case ePropertyAiAnchor:
1429 #ifdef USE_DEPRECATED_AI_CHARACTER_SYSTEM
1430 case ePropertyAiCharacter:
1431 #endif
1432 case ePropertyAiPFPropertiesList:
1433 case ePropertyAiEntityClasses:
1434 case ePropertyEquip:
1435 case ePropertyReverbPreset:
1436 case ePropertySOClass:
1437 case ePropertySOClasses:
1438 case ePropertySOState:
1439 case ePropertySOStates:
1440 case ePropertySOStatePattern:
1441 case ePropertySOAction:
1442 case ePropertySOHelper:
1443 case ePropertySONavHelper:
1444 case ePropertySOAnimHelper:
1445 case ePropertyCustomAction:
1446 case ePropertyGameToken:
1447 case ePropertySequence:
1448 case ePropertySequenceId:
1449 case ePropertyUser:
1450 case ePropertyLocalString:
1451 m_cEdit = new CInPlaceEdit(m_value, functor(*this, &CPropertyItem::OnEditChanged));
1452 style = WS_CHILD | WS_VISIBLE | ES_AUTOHSCROLL | ES_LEFT | WS_TABSTOP;
1453 if (m_type == ePropertySequenceId)
1454 style |= ES_READONLY;
1455 m_cEdit->Create(style, nullRc, pWndParent, 2);
1456 m_cEdit->EnableUpdateOnKillFocus(!m_bForceModified);
1457 RegisterCtrl(m_cEdit);
1459 if (m_type == ePropertyMaterial)
1461 m_cButton = new CInPlaceButton(functor(*this, &CPropertyItem::OnMaterialBrowseButton));
1462 m_cButton->Create("...", WS_CHILD | WS_VISIBLE, nullRc, pWndParent, 4);
1464 m_cButton2 = new CInPlaceButton(functor(*this, &CPropertyItem::OnMaterialPickSelectedButton));
1465 m_cButton2->Create("<", WS_CHILD | WS_VISIBLE, nullRc, pWndParent, 5);
1467 else if (m_type == ePropertySequence)
1469 m_cButton = new CInPlaceButton(functor(*this, &CPropertyItem::OnSequenceBrowseButton));
1470 m_cButton->Create("...", WS_CHILD | WS_VISIBLE, nullRc, pWndParent, 4);
1472 else if (m_type == ePropertySequenceId)
1474 m_cButton = new CInPlaceButton(functor(*this, &CPropertyItem::OnSequenceIdBrowseButton));
1475 m_cButton->Create("...", WS_CHILD | WS_VISIBLE, nullRc, pWndParent, 4);
1477 else if (m_type == ePropertyUser)
1479 m_cButton = new CInPlaceButton(functor(*this, &CPropertyItem::OnUserBrowseButton));
1480 m_cButton->Create("...", WS_CHILD | WS_VISIBLE, nullRc, pWndParent, 4);
1482 else if (m_type == ePropertyLocalString)
1484 m_cButton = new CInPlaceButton(functor(*this, &CPropertyItem::OnLocalStringBrowseButton));
1485 m_cButton->Create("...", WS_CHILD | WS_VISIBLE, nullRc, pWndParent, 4);
1487 else if (GetIEditor()->CanEditDeprecatedProperty(m_type))
1489 //handle with deprecated picker registration system
1490 //this only works for button-style pickers, improve system if necessary
1491 m_cButton = new CInPlaceButton(functor(*this, &CPropertyItem::OnEditDeprecatedProperty));
1492 m_cButton->Create("...", WS_CHILD | WS_VISIBLE, nullRc, pWndParent, 4);
1495 if (m_cButton)
1497 RegisterCtrl(m_cButton);
1499 if (m_cButton2)
1501 RegisterCtrl(m_cButton2);
1503 break;
1505 case ePropertySelection:
1508 // Combo box.
1509 m_cCombo = new CInPlaceComboBox();
1510 m_cCombo->SetReadOnly(true);
1511 DWORD nSorting = (m_pVariable && m_pVariable->GetFlags() & IVariable::UI_UNSORTED) ? 0 : LBS_SORT;
1512 m_cCombo->Create(NULL, "", WS_CHILD | WS_VISIBLE | WS_TABSTOP | nSorting, nullRc, pWndParent, 2);
1513 m_cCombo->SetUpdateCallback(functor(*this, &CPropertyItem::OnComboSelection));
1514 RegisterCtrl(m_cCombo);
1516 if (m_enumList)
1518 for (uint i = 0; cstr sEnumName = m_enumList->GetItemName(i); i++)
1520 m_cCombo->AddString(sEnumName);
1523 else
1524 m_cCombo->SetReadOnly(false);
1526 break;
1528 case ePropertyColor:
1530 m_cEdit = new CInPlaceEdit(m_value, functor(*this, &CPropertyItem::OnEditChanged));
1531 m_cEdit->Create(WS_CHILD | WS_VISIBLE | ES_AUTOHSCROLL | ES_LEFT | WS_TABSTOP, nullRc, pWndParent, 2);
1532 m_cEdit->EnableUpdateOnKillFocus(!m_bForceModified);
1533 RegisterCtrl(m_cEdit);
1535 //m_cButton = new CInPlaceButton( functor(*this,OnColorBrowseButton) );
1536 //m_cButton->Create( "",WS_CHILD|WS_VISIBLE,nullRc,pWndParent,4 );
1537 m_cColorButton = new CInPlaceColorButton(functor(*this, &CPropertyItem::OnColorBrowseButton));
1538 m_cColorButton->Create("", WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON | BS_OWNERDRAW, nullRc, pWndParent, 4);
1539 RegisterCtrl(m_cColorButton);
1541 break;
1543 case ePropertyFloatCurve:
1545 m_cSpline = new CSplineCtrl;
1546 m_cSpline->Create(WS_VISIBLE | WS_CHILD, nullRc, pWndParent, 2);
1547 m_cSpline->SetUpdateCallback((CSplineCtrl::UpdateCallback const&)functor(*this, &CPropertyItem::ReceiveFromControl));
1548 m_cSpline->SetTimeRange(0, 1);
1549 m_cSpline->SetValueRange(0, 1);
1550 m_cSpline->SetGrid(12, 12);
1551 m_cSpline->SetSpline(m_pVariable->GetSpline(true));
1552 RegisterCtrl(m_cSpline);
1554 break;
1556 case ePropertyColorCurve:
1558 m_cColorSpline = new CColorGradientCtrl;
1559 m_cColorSpline->Create(WS_VISIBLE | WS_CHILD, nullRc, pWndParent, 2);
1560 m_cColorSpline->SetUpdateCallback((CColorGradientCtrl::UpdateCallback const&)functor(*this, &CPropertyItem::ReceiveFromControl));
1561 m_cColorSpline->SetTimeRange(0, 1);
1562 m_cColorSpline->SetSpline(m_pVariable->GetSpline(true));
1563 RegisterCtrl(m_cColorSpline);
1565 break;
1567 case ePropertyTexture:
1569 m_cEdit = new CInPlaceEdit(m_value, functor(*this, &CPropertyItem::OnEditChanged));
1570 m_cEdit->Create(WS_CHILD | WS_VISIBLE | ES_AUTOHSCROLL | ES_LEFT | WS_TABSTOP, nullRc, pWndParent, 2);
1571 m_cEdit->EnableUpdateOnKillFocus(!m_bForceModified);
1572 RegisterCtrl(m_cEdit);
1574 HICON hButtonIcon(NULL);
1576 hButtonIcon = (HICON)LoadImage(AfxGetInstanceHandle(), MAKEINTRESOURCE(IDI_FILE_BROWSE), IMAGE_ICON, 16, 15, LR_DEFAULTCOLOR | LR_SHARED);
1577 m_cButton3 = new CInPlaceButton(functor(*this, &CPropertyItem::OnFileBrowseButton));
1578 m_cButton3->Create("...", WS_CHILD | WS_VISIBLE, nullRc, pWndParent, 4);
1579 RegisterCtrl(m_cButton3);
1580 //m_cButton3->SetIcon( CSize(16,15),hButtonIcon);
1581 //m_cButton3->SetBorderGap(6);
1583 hButtonIcon = (HICON)LoadImage(AfxGetInstanceHandle(), MAKEINTRESOURCE(IDI_TIFF), IMAGE_ICON, 16, 15, LR_DEFAULTCOLOR | LR_SHARED);
1584 m_cButton4 = new CInPlaceButton(functor(*this, &CPropertyItem::OnTextureEditButton));
1585 m_cButton4->Create("", WS_CHILD | WS_VISIBLE, nullRc, pWndParent, 7); // edit selected texture semantics.
1586 m_cButton4->SetIcon(CSize(16, 15), hButtonIcon);
1587 m_cButton4->SetBorderGap(6);
1588 RegisterCtrl(m_cButton4);
1590 hButtonIcon = (HICON)LoadImage(AfxGetInstanceHandle(), MAKEINTRESOURCE(IDI_PSD), IMAGE_ICON, 16, 15, LR_DEFAULTCOLOR | LR_SHARED);
1591 m_cButton5 = new CInPlaceButton(functor(*this, &CPropertyItem::OnPsdEditButton));
1592 m_cButton5->Create("", WS_CHILD | WS_VISIBLE, nullRc, pWndParent, 8); // edit selected texture semantics.
1593 m_cButton5->SetIcon(CSize(16, 15), hButtonIcon);
1594 m_cButton5->SetBorderGap(6);
1595 RegisterCtrl(m_cButton5);
1597 break;
1599 case ePropertyAnimation:
1600 case ePropertyModel:
1601 case ePropertyAudioTrigger:
1602 case ePropertyAudioSwitch:
1603 case ePropertyAudioSwitchState:
1604 case ePropertyAudioRTPC:
1605 case ePropertyAudioEnvironment:
1606 case ePropertyAudioPreloadRequest:
1607 case ePropertyDynamicResponseSignal:
1609 m_cEdit = new CInPlaceEdit(m_value, functor(*this, &CPropertyItem::OnEditChanged));
1610 m_cEdit->Create(WS_CHILD | WS_VISIBLE | ES_AUTOHSCROLL | ES_LEFT | WS_TABSTOP, nullRc, pWndParent, 2);
1611 m_cEdit->EnableUpdateOnKillFocus(!m_bForceModified);
1612 RegisterCtrl(m_cEdit);
1614 m_cButton = new CInPlaceButton(functor(*this, &CPropertyItem::OnResourceSelectorButton));
1615 m_cButton->Create("", WS_CHILD | WS_VISIBLE, nullRc, pWndParent, 4);
1616 RegisterCtrl(m_cButton);
1618 HICON hOpenIcon = (HICON)LoadImage(AfxGetInstanceHandle(), MAKEINTRESOURCE(IDI_FILE_BROWSE), IMAGE_ICON, 16, 15, LR_DEFAULTCOLOR | LR_SHARED);
1619 m_cButton->SetIcon(CSize(16, 15), hOpenIcon);
1620 m_cButton->SetBorderGap(6);
1622 break;
1623 case ePropertyFile:
1624 m_cEdit = new CInPlaceEdit(m_value, functor(*this, &CPropertyItem::OnEditChanged));
1625 m_cEdit->Create(WS_CHILD | WS_VISIBLE | ES_AUTOHSCROLL | ES_LEFT | WS_TABSTOP, nullRc, pWndParent, 2);
1626 m_cEdit->EnableUpdateOnKillFocus(!m_bForceModified);
1627 RegisterCtrl(m_cEdit);
1629 m_cButton = new CInPlaceButton(functor(*this, &CPropertyItem::OnFileBrowseButton));
1630 m_cButton->Create("", WS_CHILD | WS_VISIBLE, nullRc, pWndParent, 4);
1631 RegisterCtrl(m_cButton);
1633 // Use file browse icon.
1634 HICON hOpenIcon = (HICON)LoadImage(AfxGetInstanceHandle(), MAKEINTRESOURCE(IDI_FILE_BROWSE), IMAGE_ICON, 16, 15, LR_DEFAULTCOLOR | LR_SHARED);
1635 m_cButton->SetIcon(CSize(16, 15), hOpenIcon);
1636 m_cButton->SetBorderGap(6);
1637 break;
1640 if (m_cEdit)
1642 m_cEdit->ModifyStyleEx(0, WS_EX_CLIENTEDGE);
1644 if (m_cCombo)
1646 //m_cCombo->ModifyStyleEx( 0,WS_EX_CLIENTEDGE );
1649 MoveInPlaceControl(ctrlRect);
1650 SendToControl();
1653 //////////////////////////////////////////////////////////////////////////
1654 void CPropertyItem::DestroyInPlaceControl(bool bRecursive)
1656 if (!m_propertyCtrl->IsExtenedUI() && !m_bForceModified)
1657 ReceiveFromControl();
1659 SAFE_DELETE(m_pStaticText);
1660 SAFE_DELETE(m_cNumber);
1661 SAFE_DELETE(m_cNumber1);
1662 SAFE_DELETE(m_cNumber2);
1663 SAFE_DELETE(m_cNumber3);
1664 SAFE_DELETE(m_cFillSlider);
1665 SAFE_DELETE(m_cSpline);
1666 SAFE_DELETE(m_cColorSpline);
1667 SAFE_DELETE(m_cEdit);
1668 SAFE_DELETE(m_cCombo);
1669 SAFE_DELETE(m_cButton);
1670 SAFE_DELETE(m_cButton2);
1671 SAFE_DELETE(m_cButton3);
1672 SAFE_DELETE(m_cButton4);
1673 SAFE_DELETE(m_cButton5);
1674 SAFE_DELETE(m_cExpandButton);
1675 SAFE_DELETE(m_cCheckBox);
1676 SAFE_DELETE(m_cColorButton);
1678 if (bRecursive)
1680 int num = GetChildCount();
1681 for (int i = 0; i < num; i++)
1683 GetChild(i)->DestroyInPlaceControl(bRecursive);
1685 m_controls.clear();
1689 //////////////////////////////////////////////////////////////////////////
1690 void CPropertyItem::MoveInPlaceControl(const CRect& rect)
1692 m_rcControl = rect;
1694 int nButtonWidth = BUTTON_WIDTH;
1695 if (m_propertyCtrl->IsExtenedUI())
1696 nButtonWidth += 10;
1698 CRect rc = rect;
1700 if (m_cButton)
1702 if (m_type == ePropertyColor)
1704 rc.right = rc.left + nButtonWidth + 2;
1705 RepositionWindow(m_cButton, rc);
1706 rc = rect;
1707 rc.left += nButtonWidth + 2 + 4;
1708 if (rc.right > rc.left - 100)
1709 rc.right = rc.left + 100;
1711 else
1713 rc.left = rc.right - nButtonWidth;
1714 RepositionWindow(m_cButton, rc);
1715 rc = rect;
1716 rc.right -= nButtonWidth;
1719 if (m_cColorButton)
1721 rc.right = rc.left + nButtonWidth + 2;
1722 RepositionWindow(m_cColorButton, rc);
1723 rc = rect;
1724 rc.left += nButtonWidth + 2 + 4;
1725 if (rc.right > rc.left - 80)
1726 rc.right = rc.left + 80;
1728 if (m_cButton4)
1730 CRect brc(rc);
1731 brc.left = brc.right - nButtonWidth - 2;
1732 m_cButton4->MoveWindow(brc, FALSE);
1733 rc.right -= nButtonWidth + 4;
1734 m_cButton4->SetFont(m_propertyCtrl->GetFont());
1736 if (m_cButton5)
1738 CRect brc(rc);
1739 brc.left = brc.right - nButtonWidth - 2;
1740 m_cButton5->MoveWindow(brc, FALSE);
1741 rc.right -= nButtonWidth + 4;
1742 m_cButton5->SetFont(m_propertyCtrl->GetFont());
1744 if (m_cButton2)
1746 CRect brc(rc);
1747 brc.left = brc.right - nButtonWidth - 2;
1748 RepositionWindow(m_cButton2, brc);
1749 rc.right -= nButtonWidth + 4;
1751 if (m_cButton3)
1753 CRect brc(rc);
1754 brc.left = brc.right - nButtonWidth - 2;
1755 RepositionWindow(m_cButton3, brc);
1756 rc.right -= nButtonWidth + 4;
1759 if (m_cNumber)
1761 CRect rcn = rc;
1762 if (m_cNumber1 && m_cNumber2 && m_cNumber3)
1764 int x = NUMBER_CTRL_WIDTH + 4;
1765 CRect rc0, rc1, rc2, rc3;
1766 rc0 = CRect(rc.left, rc.top, rc.left + NUMBER_CTRL_WIDTH, rc.bottom);
1767 rc1 = CRect(rc.left + x, rc.top, rc.left + x + NUMBER_CTRL_WIDTH, rc.bottom);
1768 rc2 = CRect(rc.left + x * 2, rc.top, rc.left + x * 2 + NUMBER_CTRL_WIDTH, rc.bottom);
1769 rc3 = CRect(rc.left + x * 3, rc.top, rc.left + x * 3 + NUMBER_CTRL_WIDTH, rc.bottom);
1770 RepositionWindow(m_cNumber, rc0);
1771 RepositionWindow(m_cNumber1, rc1);
1772 RepositionWindow(m_cNumber2, rc2);
1773 RepositionWindow(m_cNumber3, rc3);
1775 else if (m_cNumber1 && m_cNumber2)
1777 int x = NUMBER_CTRL_WIDTH + 4;
1778 CRect rc0, rc1, rc2;
1779 rc0 = CRect(rc.left, rc.top, rc.left + NUMBER_CTRL_WIDTH, rc.bottom);
1780 rc1 = CRect(rc.left + x, rc.top, rc.left + x + NUMBER_CTRL_WIDTH, rc.bottom);
1781 rc2 = CRect(rc.left + x * 2, rc.top, rc.left + x * 2 + NUMBER_CTRL_WIDTH, rc.bottom);
1782 RepositionWindow(m_cNumber, rc0);
1783 RepositionWindow(m_cNumber1, rc1);
1784 RepositionWindow(m_cNumber2, rc2);
1786 else if (m_cNumber1)
1788 int x = NUMBER_CTRL_WIDTH + 4;
1789 CRect rc0, rc1;
1790 rc0 = CRect(rc.left, rc.top, rc.left + NUMBER_CTRL_WIDTH, rc.bottom);
1791 rc1 = CRect(rc.left + x, rc.top, rc.left + x + NUMBER_CTRL_WIDTH, rc.bottom);
1792 RepositionWindow(m_cNumber, rc0);
1793 RepositionWindow(m_cNumber1, rc1);
1795 else
1797 //rcn.right = rc.left + NUMBER_CTRL_WIDTH;
1798 if (rcn.Width() > NUMBER_CTRL_WIDTH)
1799 rcn.right = rc.left + NUMBER_CTRL_WIDTH;
1800 RepositionWindow(m_cNumber, rcn);
1802 if (m_cFillSlider)
1804 CRect rcSlider = rc;
1805 rcSlider.left = rcn.right + 1;
1806 RepositionWindow(m_cFillSlider, rcSlider);
1809 if (m_cEdit)
1811 RepositionWindow(m_cEdit, rc);
1813 if (m_cCombo)
1815 RepositionWindow(m_cCombo, rc);
1817 if (m_cSpline)
1819 // Grow beyond current line.
1820 rc.bottom = rc.top + 48;
1821 rc.right -= 4;
1822 RepositionWindow(m_cSpline, rc);
1824 if (m_cColorSpline)
1826 // Grow beyond current line.
1827 rc.bottom = rc.top + 32;
1828 rc.right -= 4;
1829 RepositionWindow(m_cColorSpline, rc);
1833 //////////////////////////////////////////////////////////////////////////
1834 void CPropertyItem::SetFocus()
1836 if (m_cNumber)
1838 m_cNumber->SetFocus();
1840 if (m_cEdit)
1842 m_cEdit->SetFocus();
1844 if (m_cCombo)
1846 m_cCombo->SetFocus();
1848 if (!m_cNumber && !m_cEdit && !m_cCombo)
1849 m_propertyCtrl->SetFocus();
1852 //////////////////////////////////////////////////////////////////////////
1853 void CPropertyItem::ReceiveFromControl()
1855 if (IsDisabled())
1856 return;
1857 if (m_cEdit)
1859 CString str;
1860 m_cEdit->GetWindowText(str);
1861 SetValue(str);
1863 if (m_cCombo)
1865 if (!CUndo::IsRecording())
1867 if (m_pEnumDBItem)
1868 SetValue(m_pEnumDBItem->NameToValue(m_cCombo->GetSelectedString()));
1869 else
1870 SetValue(m_cCombo->GetSelectedString());
1872 else
1874 if (m_pEnumDBItem)
1875 SetValue(m_pEnumDBItem->NameToValue(m_cCombo->GetSelectedString()));
1876 else
1877 SetValue(m_cCombo->GetSelectedString());
1880 if (m_cNumber)
1882 if (m_cNumber1 && m_cNumber2 && m_cNumber3)
1884 CString val;
1885 val.Format("%g,%g,%g,%g", m_cNumber->GetValue(), m_cNumber1->GetValue(), m_cNumber2->GetValue(), m_cNumber3->GetValue());
1886 SetValue(val);
1888 if (m_cNumber1 && m_cNumber2)
1890 CString val;
1891 val.Format("%g,%g,%g", m_cNumber->GetValue(), m_cNumber1->GetValue(), m_cNumber2->GetValue());
1892 SetValue(val);
1894 else if (m_cNumber1)
1896 CString val;
1897 val.Format("%g,%g", m_cNumber->GetValue(), m_cNumber1->GetValue());
1898 SetValue(val);
1900 else
1902 SetValue(m_cNumber->GetValueAsString());
1905 if (m_cSpline != 0 || m_cColorSpline != 0)
1907 // Variable was already directly updated.
1908 //OnVariableChange(m_pVariable);
1909 m_modified = true;
1910 m_pVariable->Get(m_value);
1911 m_propertyCtrl->OnItemChange(this);
1915 //////////////////////////////////////////////////////////////////////////
1916 void CPropertyItem::SendToControl()
1918 bool bInPlaceCtrl = m_propertyCtrl->IsExtenedUI();
1919 if (m_cButton)
1921 if (m_type == ePropertyColor)
1923 COLORREF clr = StringToColor(m_value);
1924 m_cButton->SetColorFace(clr);
1925 m_cButton->RedrawWindow();
1926 bInPlaceCtrl = true;
1928 m_cButton->Invalidate();
1930 if (m_cColorButton)
1932 COLORREF clr = StringToColor(m_value);
1933 m_cColorButton->SetColor(clr);
1934 m_cColorButton->Invalidate();
1935 bInPlaceCtrl = true;
1937 if (m_cCheckBox)
1939 m_cCheckBox->SetChecked(GetBoolValue() ? BST_CHECKED : BST_UNCHECKED);
1940 m_cCheckBox->Invalidate();
1942 if (m_cEdit)
1944 m_cEdit->SetText(m_value);
1945 bInPlaceCtrl = true;
1946 m_cEdit->Invalidate();
1948 if (m_cCombo)
1950 if (m_type == ePropertyBool)
1951 m_cCombo->SetCurSel(GetBoolValue() ? 0 : 1);
1952 else
1954 if (m_pEnumDBItem)
1955 m_cCombo->SelectString(-1, m_pEnumDBItem->ValueToName(m_value));
1956 else
1957 m_cCombo->SelectString(-1, m_value);
1959 bInPlaceCtrl = true;
1960 m_cCombo->Invalidate();
1962 if (m_cNumber)
1964 if (m_cNumber1 && m_cNumber2 && m_cNumber3)
1966 float x, y, z, w;
1967 sscanf(m_value, "%f,%f,%f,%f", &x, &y, &z, &w);
1968 m_cNumber->SetValue(x);
1969 m_cNumber1->SetValue(y);
1970 m_cNumber2->SetValue(z);
1971 m_cNumber3->SetValue(w);
1973 else if (m_cNumber1 && m_cNumber2)
1975 float x, y, z;
1976 sscanf(m_value, "%f,%f,%f", &x, &y, &z);
1977 m_cNumber->SetValue(x);
1978 m_cNumber1->SetValue(y);
1979 m_cNumber2->SetValue(z);
1981 else if (m_cNumber1)
1983 float x, y;
1984 sscanf(m_value, "%f,%f", &x, &y);
1985 m_cNumber->SetValue(x);
1986 m_cNumber1->SetValue(y);
1988 else
1990 m_cNumber->SetValue(atof(m_value));
1992 bInPlaceCtrl = true;
1993 m_cNumber->Invalidate();
1995 if (m_cFillSlider)
1997 m_cFillSlider->SetValue(atof(m_value));
1998 bInPlaceCtrl = true;
1999 m_cFillSlider->Invalidate();
2001 if (!bInPlaceCtrl)
2003 CRect rc;
2004 m_propertyCtrl->GetItemRect(this, rc);
2005 m_propertyCtrl->InvalidateRect(rc, TRUE);
2007 CWnd* pFocusWindow = CWnd::GetFocus();
2008 if (pFocusWindow && m_propertyCtrl->IsChild(pFocusWindow))
2009 m_propertyCtrl->SetFocus();
2011 if (m_cSpline)
2013 m_cSpline->SetSpline(m_pVariable->GetSpline(true), TRUE);
2015 if (m_cColorSpline)
2017 m_cColorSpline->SetSpline(m_pVariable->GetSpline(true), TRUE);
2019 if (m_pVariable && m_pVariable->GetFlags() & IVariable::UI_HIGHLIGHT_EDITED)
2020 CheckControlActiveColor();
2023 //////////////////////////////////////////////////////////////////////////
2024 bool CPropertyItem::HasDefaultValue(bool bChildren) const
2026 if (m_pVariable && !m_pVariable->HasDefaultValue())
2027 return false;
2029 if (bChildren)
2031 // Evaluate children.
2032 for (int i = 0; i < m_childs.size(); i++)
2034 if (!m_childs[i]->HasDefaultValue(true))
2035 return false;
2039 return true;
2042 //////////////////////////////////////////////////////////////////////////
2043 void CPropertyItem::CheckControlActiveColor()
2045 if (m_pStaticText)
2047 COLORREF clrStaticText = XTPColorManager()->LightColor(GetXtremeColor(COLOR_3DFACE), GetXtremeColor(COLOR_BTNTEXT), 30);
2048 COLORREF nTextColor = HasDefaultValue(true) ? clrStaticText : GetXtremeColor(COLOR_HIGHLIGHT);
2049 if (m_pStaticText->GetTextColor() != nTextColor)
2050 m_pStaticText->SetTextColor(nTextColor);
2053 if (m_cExpandButton)
2055 static COLORREF nDefColor = ::GetSysColor(COLOR_BTNFACE);
2056 static COLORREF nDefTextColor = ::GetSysColor(COLOR_BTNTEXT);
2057 static COLORREF nNondefColor = GetXtremeColor(COLOR_HIGHLIGHT);
2058 static COLORREF nNondefTextColor = GetXtremeColor(COLOR_HIGHLIGHTTEXT);
2059 bool bDefault = HasDefaultValue(true);
2060 COLORREF nColor = bDefault ? nDefColor : nNondefColor;
2062 if (m_cExpandButton->GetColor() != nColor)
2064 m_cExpandButton->SetColor(nColor);
2065 m_cExpandButton->SetTextColor(bDefault ? nDefTextColor : nNondefTextColor);
2070 //////////////////////////////////////////////////////////////////////////
2071 void CPropertyItem::OnComboSelection()
2073 ReceiveFromControl();
2074 SendToControl();
2077 //////////////////////////////////////////////////////////////////////////
2078 void CPropertyItem::DrawValue(CDC* dc, CRect rect)
2080 // Setup text.
2081 dc->SetBkMode(TRANSPARENT);
2083 CString val = GetDrawValue();
2085 if (m_type == ePropertyBool)
2087 int sz = rect.bottom - rect.top - 1;
2088 int borderwidth = (int)(sz * 0.13f); //white frame border
2089 int borderoffset = (int)(sz * 0.1f); //offset from the frameborder
2090 CPoint p1(rect.left, rect.top + 1); // box
2091 CPoint p2(rect.left + borderwidth, rect.top + 1 + borderwidth); //check-mark
2093 const bool bPropertyCtrlIsDisabled = m_propertyCtrl->IsReadOnly() || m_propertyCtrl->IsGrayed() || (m_propertyCtrl->IsWindowEnabled() != TRUE);
2094 const bool bShowInactiveFrame = IsDisabled() || bPropertyCtrlIsDisabled;
2096 CRect rc(p1.x, p1.y, p1.x + sz, p1.y + sz);
2097 dc->DrawFrameControl(rc, DFC_BUTTON, DFCS_BUTTON3STATE | (bShowInactiveFrame ? DFCS_INACTIVE : 0));
2098 if (GetBoolValue())
2100 COLORREF color = StringToColor(val);
2101 if (bShowInactiveFrame)
2103 color = (COLORREF)ColorB::ComputeAvgCol_Fast(RGB(255, 255, 255), color);
2105 CPen pen(PS_SOLID, 1, color);
2106 CPen* pPen = dc->SelectObject(&pen);
2108 //Draw bold check-mark
2109 int number_of_lines = sz / 8;
2110 number_of_lines += 1;
2111 for (int i = 0; i < number_of_lines; i++)
2113 CPoint start = p2 + CPoint(i, 0);
2114 start.y += ((sz - borderwidth * 2) / 2);
2115 start.x += borderoffset;
2117 CPoint middle = p2 + CPoint(i, 0);
2118 middle.y += sz - borderwidth * 2;
2119 middle.x += (sz - borderwidth - number_of_lines) / 2;
2120 middle.y -= borderoffset;
2122 CPoint end = p2 + CPoint(i, 0);
2123 end.x += sz - borderwidth * 2 - number_of_lines;
2124 end.x -= borderoffset;
2125 end.y += borderoffset;
2127 dc->MoveTo(start);
2128 dc->LineTo(middle);
2129 dc->LineTo(end);
2133 //offset text with scaling
2134 rect.left += (int)(sz * 1.25f);
2136 else if (m_type == ePropertyFile || m_type == ePropertyTexture || m_type == ePropertyModel)
2138 // Any file.
2139 // Check if file name fits into the designated rectangle.
2140 CSize textSize = dc->GetTextExtent(val, val.GetLength());
2141 if (textSize.cx > rect.Width())
2143 // Cut file name...
2144 if (strcmp(PathUtil::GetExt(val), "") != 0)
2145 val = CString("...\\") + PathUtil::GetFile(val);
2148 else if (m_type == ePropertyColor)
2150 //CRect rc( CPoint(rect.right-BUTTON_WIDTH,rect.top),CSize(BUTTON_WIDTH,rect.bottom-rect.top) );
2151 CRect rc(CPoint(rect.left, rect.top + 1), CSize(BUTTON_WIDTH + 2, rect.bottom - rect.top - 2));
2152 //CPen pen( PS_SOLID,1,RGB(128,128,128));
2153 CPen pen(PS_SOLID, 1, RGB(0, 0, 0));
2154 CBrush brush(StringToColor(val));
2155 CPen* pOldPen = dc->SelectObject(&pen);
2156 CBrush* pOldBrush = dc->SelectObject(&brush);
2157 dc->Rectangle(rc);
2158 //COLORREF col = StringToColor(m_value);
2159 //rc.DeflateRect( 1,1 );
2160 //dc->FillSolidRect( rc,col );
2161 dc->SelectObject(pOldPen);
2162 dc->SelectObject(pOldBrush);
2163 rect.left = rect.left + BUTTON_WIDTH + 2 + 4;
2165 else if (m_pVariable != 0 && m_pVariable->GetSpline(false) && m_pVariable->GetSpline(false)->GetKeyCount() > 0)
2167 // Draw mini-curve or gradient.
2168 CPen* pOldPen = 0;
2170 ISplineInterpolator* pSpline = m_pVariable->GetSpline(true);
2171 int width = min(rect.Width() - 1, 128);
2172 for (int x = 0; x < width; x++)
2174 float time = float(x) / (width - 1);
2175 ISplineInterpolator::ValueType val;
2176 pSpline->Interpolate(time, val);
2178 if (m_type == ePropertyColorCurve)
2180 COLORREF col = RGB(pos_round(val[0] * 255), pos_round(val[1] * 255), pos_round(val[2] * 255));
2181 CPen pen(PS_SOLID, 1, col);
2182 if (!pOldPen)
2183 pOldPen = dc->SelectObject(&pen);
2184 else
2185 dc->SelectObject(&pen);
2186 dc->MoveTo(CPoint(rect.left + x, rect.bottom));
2187 dc->LineTo(CPoint(rect.left + x, rect.top));
2189 else if (m_type == ePropertyFloatCurve)
2191 CPoint point;
2192 point.x = rect.left + x;
2193 point.y = int_round((rect.bottom - 1) * (1.f - val[0]) + (rect.top + 1) * val[0]);
2194 if (x == 0)
2195 dc->MoveTo(point);
2196 else
2197 dc->LineTo(point);
2200 if (pOldPen)
2201 dc->SelectObject(pOldPen);
2204 // No text.
2205 return;
2209 //////////////////////////////////////////////////////////////////////////
2210 // Draw filled bar like in CFillSliderCtrl.
2211 //////////////////////////////////////////////////////////////////////////
2212 if (m_type == ePropertyFloat || m_type == ePropertyInt || m_type == ePropertyAngle)
2214 CRect rc = rect;
2215 rc.left += NUMBER_CTRL_WIDTH;
2216 rc.top += 1;
2217 rc.bottom -= 1;
2219 float value = atof(m_value);
2220 float min = m_rangeMin/m_valueMultiplier;
2221 float max = m_rangeMax/m_valueMultiplier;
2222 if (min == max)
2223 max = min + 1;
2224 float pos = (value-min) / fabs(max-min);
2225 int splitPos = rc.left + pos * rc.Width();
2227 // Paint filled rect.
2228 CRect fillRc = rc;
2229 fillRc.right = splitPos;
2230 dc->FillRect(fillRc,CBrush::FromHandle((HBRUSH)GetStockObject(LTGRAY_BRUSH)) );
2232 // Paint empty rect.
2233 CRect emptyRc = rc;
2234 emptyRc.left = splitPos+1;
2235 emptyRc.IntersectRect(emptyRc,rc);
2236 dc->FillRect(emptyRc,CBrush::FromHandle((HBRUSH)GetStockObject(WHITE_BRUSH)) );
2240 CRect textRc;
2241 textRc = rect;
2242 ::DrawTextEx(dc->GetSafeHdc(), val.GetBuffer(), val.GetLength(), textRc, DT_END_ELLIPSIS | DT_LEFT | DT_SINGLELINE | DT_VCENTER, NULL);
2245 COLORREF CPropertyItem::StringToColor(const CString& value)
2247 float r, g, b;
2248 int res = 0;
2249 if (res != 3)
2250 res = sscanf(value, "%f,%f,%f", &r, &g, &b);
2251 if (res != 3)
2252 res = sscanf(value, "R:%f,G:%f,B:%f", &r, &g, &b);
2253 if (res != 3)
2254 res = sscanf(value, "R:%f G:%f B:%f", &r, &g, &b);
2255 if (res != 3)
2256 res = sscanf(value, "%f %f %f", &r, &g, &b);
2257 if (res != 3)
2259 sscanf(value, "%f", &r);
2260 return r;
2262 int ir = r;
2263 int ig = g;
2264 int ib = b;
2266 return RGB(ir, ig, ib);
2269 bool CPropertyItem::GetBoolValue()
2271 if (stricmp(m_value, "true") == 0 || atoi(m_value) != 0)
2272 return true;
2273 else
2274 return false;
2277 //////////////////////////////////////////////////////////////////////////
2278 const char* CPropertyItem::GetValue() const
2280 return m_value;
2283 //////////////////////////////////////////////////////////////////////////
2284 void CPropertyItem::SetValue(const char* sValue, bool bRecordUndo, bool bForceModified)
2286 if (bRecordUndo && IsDisabled())
2287 return;
2289 _smart_ptr<CPropertyItem> holder = this; // Make sure we are not released during this function.
2291 CString value = sValue;
2293 switch (m_type)
2295 case ePropertyAiTerritory:
2296 #ifdef USE_SIMPLIFIED_AI_TERRITORY_SHAPE
2297 if ((value == "<None>") || m_value.Compare(value))
2298 #else
2299 if ((value == "<Auto>") || (value == "<None>") || m_value.Compare(value))
2300 #endif
2302 CPropertyItem* pPropertyItem = GetParent()->FindItemByFullName("::AITerritoryAndWave::Wave");
2303 if (pPropertyItem)
2305 pPropertyItem->SetValue("<None>");
2308 break;
2310 case ePropertyBool:
2311 if (stricmp(value, "true") == 0 || atof(value) != 0)
2312 value = "1";
2313 else
2314 value = "0";
2315 break;
2317 case ePropertyVector2:
2318 if (value.Find(',') < 0)
2319 value = value + ", " + value;
2320 break;
2322 case ePropertyVector4:
2323 if (value.Find(',') < 0)
2324 value = value + ", " + value + ", " + value + ", " + value;
2325 break;
2327 case ePropertyVector:
2328 if (value.Find(',') < 0)
2329 value = value + ", " + value + ", " + value;
2330 break;
2332 case ePropertyTexture:
2333 case ePropertyModel:
2334 case ePropertyMaterial:
2335 value.Replace('\\', '/');
2336 break;
2339 // correct the length of value
2340 switch (m_type)
2342 case ePropertyTexture:
2343 case ePropertyModel:
2344 case ePropertyMaterial:
2345 case ePropertyFile:
2346 if (value.GetLength() >= MAX_PATH)
2347 value = value.Left(MAX_PATH);
2348 break;
2351 bool bModified = m_bForceModified || bForceModified || m_value.Compare(value) != 0;
2352 bool bStoreUndo = (m_value.Compare(value) != 0 || bForceModified) && bRecordUndo;
2354 std::unique_ptr<CUndo> undo;
2355 if (bStoreUndo && !CUndo::IsRecording())
2357 if (!m_propertyCtrl->CallUndoFunc(this))
2358 undo.reset(new CUndo(GetName() + " Modified"));
2361 m_value = value;
2363 if (m_pVariable)
2365 if (bModified)
2367 if (m_propertyCtrl->IsStoreUndoByItems() && bStoreUndo && CUndo::IsRecording())
2368 CUndo::Record(new CUndoVariableChange(m_pVariable, "PropertyChange"));
2370 if (m_bForceModified || bForceModified)
2371 m_pVariable->SetForceModified(true);
2372 ValueToVar();
2375 else
2377 //////////////////////////////////////////////////////////////////////////
2378 // DEPRICATED (For XmlNode).
2379 //////////////////////////////////////////////////////////////////////////
2380 if (m_node)
2381 m_node->setAttr(VALUE_ATTR, m_value);
2382 //CString xml = m_node->getXML();
2384 SendToControl();
2386 if (bModified)
2388 m_modified = true;
2389 if (m_bEditChildren)
2391 // Extract child components.
2392 int pos = 0;
2393 for (int i = 0; i < m_childs.size(); i++)
2395 CString elem = m_value.Tokenize(", ", pos);
2396 m_childs[i]->m_value = elem;
2397 m_childs[i]->SendToControl();
2401 if (m_parent)
2402 m_parent->OnChildChanged(this);
2403 // If Value changed mark document modified.
2404 // Notify parent that this Item have been modified.
2405 m_propertyCtrl->OnItemChange(this);
2410 //////////////////////////////////////////////////////////////////////////
2411 void CPropertyItem::VarToValue()
2413 assert(m_pVariable != 0);
2415 if (m_type == ePropertyColor)
2417 if (m_pVariable->GetType() == IVariable::VECTOR)
2419 Vec3 v(0, 0, 0);
2420 m_pVariable->Get(v);
2421 COLORREF col = CMFCUtils::ColorLinearToGamma(ColorF(v.x, v.y, v.z));
2422 m_value.Format("%d,%d,%d", GetRValue(col), GetGValue(col), GetBValue(col));
2424 else
2426 int col(0);
2427 m_pVariable->Get(col);
2428 m_value.Format("%d,%d,%d", GetRValue((uint32)col), GetGValue((uint32)col), GetBValue((uint32)col));
2430 return;
2433 if (m_type == ePropertyFloat)
2435 float value;
2436 m_pVariable->Get(value);
2438 PropertyItem_Private::FormatFloatForUICString(m_value, FLOAT_NUM_DIGITS, value);
2440 else
2442 m_value = m_pVariable->GetDisplayValue();
2445 if (m_type == ePropertySOHelper || m_type == ePropertySONavHelper || m_type == ePropertySOAnimHelper)
2447 // hide smart object class part
2448 int f = m_value.Find(':');
2449 if (f >= 0)
2450 m_value.Delete(0, f + 1);
2454 CString CPropertyItem::GetDrawValue()
2456 CString value = m_value;
2458 if (m_pEnumDBItem)
2459 value = m_pEnumDBItem->ValueToName(value);
2461 if (m_valueMultiplier != 1.f)
2463 float f = atof(m_value) * m_valueMultiplier;
2464 if (m_type == ePropertyInt)
2465 value.Format("%d", int_round(f));
2466 else
2467 value.Format("%g", f);
2468 if (m_valueMultiplier == 100)
2469 value += "%";
2471 else if (m_type == ePropertyBool)
2473 return "";
2475 else if (m_type == ePropertyFloatCurve || m_type == ePropertyColorCurve)
2477 // Don't display actual values in field.
2478 if (!value.IsEmpty())
2479 value = "[Curve]";
2481 else if (m_type == ePropertySequenceId)
2483 uint32 id = (uint32)atoi(value);
2484 IAnimSequence* pSeq = GetIEditor()->GetMovieSystem()->FindSequenceById(id);
2485 if (pSeq) // Show its human-readable name instead of its ID.
2486 return pSeq->GetName();
2489 return value;
2492 //////////////////////////////////////////////////////////////////////////
2493 void CPropertyItem::ValueToVar()
2495 assert(m_pVariable != NULL);
2497 _smart_ptr<CPropertyItem> holder = this; // Make sure we are not released during the call to variable Set.
2499 if (m_type == ePropertyColor)
2501 COLORREF col = StringToColor(m_value);
2502 if (m_pVariable->GetType() == IVariable::VECTOR)
2504 ColorF colLin = CMFCUtils::ColorGammaToLinear(col);
2505 m_pVariable->Set(Vec3(colLin.r, colLin.g, colLin.b));
2507 else
2508 m_pVariable->Set((int)col);
2510 else if (m_type == ePropertySOHelper || m_type == ePropertySONavHelper || m_type == ePropertySOAnimHelper)
2512 // keep smart object class part
2514 CString oldValue;
2515 m_pVariable->Get(oldValue);
2516 int f = oldValue.Find(':');
2517 if (f >= 0)
2518 oldValue.Truncate(f + 1);
2520 CString newValue(m_value);
2521 f = newValue.Find(':');
2522 if (f >= 0)
2523 newValue.Delete(0, f + 1);
2525 m_pVariable->Set(oldValue + newValue);
2527 else if (m_type != ePropertyInvalid)
2529 m_pVariable->SetDisplayValue(m_value);
2533 //////////////////////////////////////////////////////////////////////////
2534 void CPropertyItem::OnVariableChange(IVariable* pVar)
2536 assert(pVar != 0 && pVar == m_pVariable);
2538 // When variable changes, invalidate UI.
2539 m_modified = true;
2541 VarToValue();
2543 // update enum list
2544 if (m_type == ePropertySelection)
2545 m_enumList = m_pVariable->GetEnumList();
2547 SendToControl();
2549 if (m_bEditChildren)
2551 switch (m_type)
2553 case ePropertyAiPFPropertiesList:
2554 AddChildrenForPFProperties();
2555 break;
2557 case ePropertyAiEntityClasses:
2558 AddChildrenForAIEntityClasses();
2559 break;
2561 default:
2563 // Parse comma-separated values, set children.
2564 bool bPrevIgnore = m_bIgnoreChildsUpdate;
2565 m_bIgnoreChildsUpdate = true;
2567 int pos = 0;
2568 for (int i = 0; i < m_childs.size(); i++)
2570 CString sElem = pos >= 0 ? m_value.Tokenize(", ", pos) : CString();
2571 m_childs[i]->SetValue(sElem, false);
2573 m_bIgnoreChildsUpdate = bPrevIgnore;
2578 if (m_parent)
2579 m_parent->OnChildChanged(this);
2581 // If Value changed mark document modified.
2582 // Notify parent that this Item have been modified.
2583 // This may delete this control...
2584 m_propertyCtrl->OnItemChange(this);
2586 //////////////////////////////////////////////////////////////////////////
2587 CPropertyItem::TDValues* CPropertyItem::GetEnumValues(const char* strPropertyName)
2589 TDValuesContainer::iterator itIterator;
2590 TDValuesContainer& cEnumContainer = CUIEnumerations::GetUIEnumerationsInstance().GetStandardNameContainer();
2592 itIterator = cEnumContainer.find(strPropertyName);
2593 if (itIterator == cEnumContainer.end())
2595 return NULL;
2598 return &itIterator->second;
2601 //////////////////////////////////////////////////////////////////////////
2602 void CPropertyItem::OnMouseWheel(UINT nFlags, short zDelta, CPoint point)
2604 if (m_propertyCtrl->IsReadOnly())
2605 return;
2607 if (m_cCombo)
2609 int sel = m_cCombo->GetCurSel();
2610 if (zDelta > 0)
2612 sel++;
2613 if (m_cCombo->SetCurSel(sel) == CB_ERR)
2614 m_cCombo->SetCurSel(0);
2616 else
2618 sel--;
2619 if (m_cCombo->SetCurSel(sel) == CB_ERR)
2620 m_cCombo->SetCurSel(m_cCombo->GetCount() - 1);
2623 else if (m_cNumber)
2625 if (zDelta > 0)
2627 m_cNumber->SetValue(m_cNumber->GetValue() + m_cNumber->GetStep());
2629 else
2631 m_cNumber->SetValue(m_cNumber->GetValue() - m_cNumber->GetStep());
2633 ReceiveFromControl();
2637 //////////////////////////////////////////////////////////////////////////
2638 void CPropertyItem::OnLButtonDblClk(UINT nFlags, CPoint point)
2640 if (m_propertyCtrl->IsReadOnly())
2641 return;
2643 if (IsDisabled())
2644 return;
2646 if (m_type == ePropertyBool)
2648 // Swap boolean value.
2649 if (GetBoolValue())
2650 SetValue("0");
2651 else
2652 SetValue("1");
2654 else
2656 // Simulate button click.
2657 if (m_cButton)
2658 m_cButton->Click();
2662 //////////////////////////////////////////////////////////////////////////
2663 void CPropertyItem::OnLButtonDown(UINT nFlags, CPoint point)
2665 if (m_propertyCtrl->IsReadOnly())
2666 return;
2668 if (m_type == ePropertyBool)
2670 CRect rect;
2671 m_propertyCtrl->GetItemRect(this, rect);
2672 rect = m_propertyCtrl->GetItemValueRect(rect);
2674 CPoint p(rect.left - 2, rect.top + 1);
2675 int sz = rect.bottom - rect.top;
2676 rect = CRect(p.x, p.y, p.x + sz, p.y + sz);
2678 if (rect.PtInRect(point))
2680 // Swap boolean value.
2681 if (GetBoolValue())
2682 SetValue("0");
2683 else
2684 SetValue("1");
2689 //////////////////////////////////////////////////////////////////////////
2690 void CPropertyItem::OnCheckBoxButton()
2692 if (m_cCheckBox)
2693 if (m_cCheckBox->GetChecked() == BST_CHECKED)
2694 SetValue("1");
2695 else
2696 SetValue("0");
2699 //////////////////////////////////////////////////////////////////////////
2700 void CPropertyItem::OnColorBrowseButton()
2703 COLORREF clr = StringToColor(m_value);
2704 if (GetIEditor()->SelectColor(clr,m_propertyCtrl))
2706 int r,g,b;
2707 r = GetRValue(clr);
2708 g = GetGValue(clr);
2709 b = GetBValue(clr);
2710 //val.Format( "R:%d G:%d B:%d",r,g,b );
2711 CString val;
2712 val.Format( "%d,%d,%d",r,g,b );
2713 SetValue( val );
2714 m_propertyCtrl->Invalidate();
2715 //RedrawWindow( OwnerProperties->hWnd,NULL,NULL,RDW_INVALIDATE|RDW_UPDATENOW|RDW_ALLCHILDREN );
2718 if (IsDisabled())
2719 return;
2721 COLORREF orginalColor = StringToColor(m_value);
2722 COLORREF clr = orginalColor;
2723 CCustomColorDialog dlg(orginalColor, CC_FULLOPEN, m_propertyCtrl);
2724 dlg.SetColorChangeCallback(functor(*this, &CPropertyItem::OnColorChange));
2725 if (dlg.DoModal() == IDOK)
2727 clr = dlg.GetColor();
2728 if (clr != orginalColor)
2730 int r, g, b;
2731 CString val;
2732 r = GetRValue(orginalColor);
2733 g = GetGValue(orginalColor);
2734 b = GetBValue(orginalColor);
2735 val.Format("%d,%d,%d", r, g, b);
2736 SetValue(val, false);
2738 r = GetRValue(clr);
2739 g = GetGValue(clr);
2740 b = GetBValue(clr);
2741 val.Format("%d,%d,%d", r, g, b);
2742 SetValue(val);
2743 m_propertyCtrl->InvalidateCtrl();
2746 else
2748 if (StringToColor(m_value) != orginalColor)
2750 int r, g, b;
2751 r = GetRValue(clr);
2752 g = GetGValue(clr);
2753 b = GetBValue(clr);
2754 CString val;
2755 val.Format("%d,%d,%d", r, g, b);
2756 SetValue(val);
2757 m_propertyCtrl->InvalidateCtrl();
2760 if (m_cButton)
2761 m_cButton->Invalidate();
2764 //////////////////////////////////////////////////////////////////////////
2765 void CPropertyItem::OnColorChange(COLORREF clr)
2767 GetIEditor()->GetIUndoManager()->Suspend();
2768 int r, g, b;
2769 r = GetRValue(clr);
2770 g = GetGValue(clr);
2771 b = GetBValue(clr);
2772 //val.Format( "R:%d G:%d B:%d",r,g,b );
2773 CString val;
2774 val.Format("%d,%d,%d", r, g, b);
2775 SetValue(val);
2776 GetIEditor()->UpdateViews(eRedrawViewports);
2777 //GetIEditor()->Notify( eNotify_OnIdleUpdate );
2778 m_propertyCtrl->InvalidateCtrl();
2779 GetIEditor()->GetIUndoManager()->Resume();
2781 if (m_cButton)
2782 m_cButton->Invalidate();
2785 //////////////////////////////////////////////////////////////////////////
2786 void CPropertyItem::OnFileBrowseButton()
2788 CString tempValue("");
2789 CString ext("");
2790 if (m_value.IsEmpty() == false)
2792 if (strcmp(PathUtil::GetExt(m_value), "") == 0)
2794 tempValue = "";
2796 else
2798 tempValue = m_value;
2802 CString startPath = PathUtil::GetPathWithoutFilename(tempValue);
2804 m_propertyCtrl->HideBitmapTooltip();
2806 if (m_type == ePropertyTexture)
2808 dll_string newValue = GetIEditor()->GetResourceSelectorHost()->SelectResource("Texture", tempValue);
2809 SetValue(newValue.c_str(), true, false);
2811 else if (m_type == ePropertyGeomCache)
2813 dll_string newValue = GetIEditor()->GetResourceSelectorHost()->SelectResource("GeometryCache", tempValue);
2814 SetValue(newValue.c_str(), true, true);
2816 else
2818 CString relativeFilename = tempValue;
2819 if (CFileUtil::SelectSingleFile(EFILE_TYPE_ANY, relativeFilename, "", startPath))
2821 SetValue(relativeFilename, true, false);
2826 //////////////////////////////////////////////////////////////////////////
2827 void CPropertyItem::OnResourceSelectorButton()
2829 m_propertyCtrl->HideBitmapTooltip();
2831 dll_string newValue = GetIEditor()->GetResourceSelectorHost()->SelectResource(PropertyTypeToResourceType(m_type), GetValue(), nullptr, m_pVariable->GetUserData());
2832 if (strcmp(GetValue(), newValue.c_str()) != 0)
2834 SetValue(newValue.c_str());
2838 //////////////////////////////////////////////////////////////////////////
2839 void CPropertyItem::OnTextureEditButton()
2841 CFileUtil::EditTextureFile(m_value, true);
2843 //////////////////////////////////////////////////////////////////////////
2844 void CPropertyItem::OnPsdEditButton()
2846 CString dccFilename;
2847 if (CFileUtil::CalculateDccFilename(m_value, dccFilename))
2849 CFileUtil::EditTextureFile(dccFilename, true);
2851 else
2853 char buff[1024];
2854 cry_sprintf(buff, "Failed to find psd file for texture: '%s'", m_value);
2855 CQuestionDialog::SCritical("Error", buff);
2859 //////////////////////////////////////////////////////////////////////////
2860 void CPropertyItem::OnAnimationApplyButton()
2862 CUIEnumerations& roGeneralProxy = CUIEnumerations::GetUIEnumerationsInstance();
2863 std::vector<string> cSelectedAnimations;
2864 size_t nTotalAnimations(0);
2865 size_t nCurrentAnimation(0);
2867 string combinedString = GetIEditor()->GetResourceSelectorHost()->GetGlobalSelection("animation");
2868 SplitString(combinedString, cSelectedAnimations, ',');
2870 nTotalAnimations = cSelectedAnimations.size();
2871 for (nCurrentAnimation = 0; nCurrentAnimation < nTotalAnimations; ++nCurrentAnimation)
2873 string& rstrCurrentAnimAction = cSelectedAnimations[nCurrentAnimation];
2874 if (rstrCurrentAnimAction.GetLength())
2876 m_pVariable->Set(rstrCurrentAnimAction);
2877 return;
2882 //////////////////////////////////////////////////////////////////////////
2883 void CPropertyItem::ReloadValues()
2885 m_modified = false;
2886 if (m_node)
2887 ParseXmlNode(false);
2888 if (m_pVariable)
2889 SetVariable(m_pVariable);
2890 for (int i = 0; i < GetChildCount(); i++)
2892 GetChild(i)->ReloadValues();
2894 SendToControl();
2897 //////////////////////////////////////////////////////////////////////////
2898 CString CPropertyItem::GetTip() const
2900 if (!m_tip.IsEmpty() || m_name.Left(1) == "_")
2901 return m_tip;
2903 CString type;
2904 for (int i = 0; i < NumPropertyTypes; i++)
2906 if (m_type == s_propertyTypeNames[i].type)
2908 type = s_propertyTypeNames[i].name;
2909 break;
2913 CString tip = CString("[") + type + "] " + m_name + " = " + m_value;
2915 if (HasScriptDefault())
2917 tip += " [Script Default: ";
2918 if (m_strScriptDefault.IsEmpty())
2919 tip += "<blank>";
2920 else
2921 tip += m_strScriptDefault;
2922 tip += "]";
2925 if (m_pVariable)
2927 CString description = m_pVariable->GetDescription();
2928 if (!description.IsEmpty())
2930 tip += CString(" ") + description;
2933 return tip;
2936 //////////////////////////////////////////////////////////////////////////
2937 void CPropertyItem::OnEditChanged()
2939 ReceiveFromControl();
2942 //////////////////////////////////////////////////////////////////////////
2943 void CPropertyItem::OnNumberCtrlUpdate(CNumberCtrl* ctrl)
2945 ReceiveFromControl();
2948 //////////////////////////////////////////////////////////////////////////
2949 void CPropertyItem::OnFillSliderCtrlUpdate(CSliderCtrlEx* ctrl)
2951 if (m_cFillSlider)
2953 float fValue = m_cFillSlider->GetValue();
2955 if (m_step != 0.f)
2957 // Round to next power of 10 below step.
2958 float fRound = pow(10.f, floor(log(m_step) / log(10.f))) / m_valueMultiplier;
2959 fValue = int_round(fValue / fRound) * fRound;
2961 fValue = clamp_tpl(fValue, m_rangeMin, m_rangeMax);
2963 CString val;
2964 val.Format("%g", fValue);
2965 SetValue(val, true, true);
2969 //////////////////////////////////////////////////////////////////////////
2970 void CPropertyItem::OnEditDeprecatedProperty()
2972 string new_value;
2973 if (GetIEditor()->EditDeprecatedProperty(m_type, m_value.GetString(), new_value))
2975 SetValue(new_value);
2979 //////////////////////////////////////////////////////////////////////////
2980 void CPropertyItem::OnMaterialBrowseButton()
2982 // Open material browser dialog.
2983 CString name = GetValue();
2984 IDataBaseItem* pItem = GetIEditor()->GetDBItemManager(EDB_TYPE_MATERIAL)->FindItemByName(name.GetBuffer());
2985 GetIEditor()->OpenAndFocusDataBase(EDB_TYPE_MATERIAL, pItem);
2988 //////////////////////////////////////////////////////////////////////////
2989 void CPropertyItem::OnMaterialPickSelectedButton()
2991 // Open material browser dialog.
2992 IDataBaseItem* pItem = GetIEditor()->GetDBItemManager(EDB_TYPE_MATERIAL)->GetSelectedItem();
2993 if (pItem)
2994 SetValue(pItem->GetName());
2995 else
2996 SetValue("");
2999 //////////////////////////////////////////////////////////////////////////
3000 void CPropertyItem::OnSequenceBrowseButton()
3002 CSelectSequenceDialog gtDlg(m_propertyCtrl);
3003 gtDlg.PreSelectItem(GetValue());
3004 if (gtDlg.DoModal() == IDOK)
3005 SetValue(gtDlg.GetSelectedItem());
3008 //////////////////////////////////////////////////////////////////////////
3009 void CPropertyItem::OnSequenceIdBrowseButton()
3011 CSelectSequenceDialog gtDlg(m_propertyCtrl);
3012 uint32 id = (uint32)atoi(GetValue());
3013 IAnimSequence* pSeq = GetIEditor()->GetMovieSystem()->FindSequenceById(id);
3014 if (pSeq)
3015 gtDlg.PreSelectItem(pSeq->GetName());
3016 if (gtDlg.DoModal() == IDOK)
3018 pSeq = GetIEditor()->GetMovieSystem()->FindSequence(gtDlg.GetSelectedItem());
3019 assert(pSeq);
3020 if (pSeq->GetId() > 0) // This sequence is a new one with a valid ID.
3022 CString buf;
3023 buf.Format("%d", pSeq->GetId());
3024 SetValue(buf);
3026 else // This sequence is an old one without an ID.
3028 CQuestionDialog::SCritical(QObject::tr(""), QObject::tr("This is an old sequence without an ID.\nSo it cannot be used with the new ID-based linking."));
3033 void CPropertyItem::OnMissionObjButton()
3035 CSelectMissionObjectiveDialog gtDlg(m_propertyCtrl);
3036 gtDlg.PreSelectItem(GetValue());
3037 if (gtDlg.DoModal() == IDOK)
3038 SetValue(gtDlg.GetSelectedItem());
3041 //////////////////////////////////////////////////////////////////////////
3042 void CPropertyItem::OnUserBrowseButton()
3044 IVariable::IGetCustomItems* pGetCustomItems = static_cast<IVariable::IGetCustomItems*>(m_pVariable->GetUserData());
3045 if (pGetCustomItems != 0)
3047 std::vector<IVariable::IGetCustomItems::SItem> items;
3048 string dlgTitle;
3049 // call the user supplied callback to fill-in items and get dialog title
3050 bool bShowIt = pGetCustomItems->GetItems(m_pVariable, items, dlgTitle);
3051 if (bShowIt) // if func didn't veto, show the dialog
3053 CGenericSelectItemDialog gtDlg(m_propertyCtrl);
3054 if (pGetCustomItems->UseTree())
3056 gtDlg.SetMode(CGenericSelectItemDialog::eMODE_TREE);
3057 const char* szSep = pGetCustomItems->GetTreeSeparator();
3058 if (szSep)
3060 CString sep(szSep);
3061 gtDlg.SetTreeSeparator(sep);
3064 gtDlg.SetItems(items);
3065 if (dlgTitle.IsEmpty() == false)
3066 gtDlg.SetTitle(CString(dlgTitle.GetString()));
3067 gtDlg.PreSelectItem(GetValue());
3068 if (gtDlg.DoModal() == IDOK)
3070 CString selectedItemStr = gtDlg.GetSelectedItem();
3072 if (selectedItemStr.IsEmpty() == false)
3074 SetValue(selectedItemStr);
3081 //////////////////////////////////////////////////////////////////////////
3082 void CPropertyItem::OnLocalStringBrowseButton()
3084 std::vector<IVariable::IGetCustomItems::SItem> items;
3085 ILocalizationManager* pMgr = gEnv->pSystem->GetLocalizationManager();
3086 if (!pMgr)
3087 return;
3088 int nCount = pMgr->GetLocalizedStringCount();
3089 if (nCount <= 0)
3090 return;
3091 items.reserve(nCount);
3092 IVariable::IGetCustomItems::SItem item;
3093 SLocalizedInfoEditor sInfo;
3094 for (int i = 0; i < nCount; ++i)
3096 if (pMgr->GetLocalizedInfoByIndex(i, sInfo))
3098 item.desc = _T("English Text:\r\n");
3099 item.desc += Unicode::Convert<wstring>(sInfo.sUtf8TranslatedText).c_str();
3100 item.name = sInfo.sKey;
3101 items.push_back(item);
3104 CString dlgTitle;
3105 CGenericSelectItemDialog gtDlg(m_propertyCtrl);
3106 const bool bUseTree = true;
3107 if (bUseTree)
3109 gtDlg.SetMode(CGenericSelectItemDialog::eMODE_TREE);
3110 gtDlg.SetTreeSeparator("/");
3112 gtDlg.SetItems(items);
3113 gtDlg.SetTitle(_T("Choose Localized String"));
3114 CString preselect = GetValue();
3115 if (!preselect.IsEmpty() && preselect.GetAt(0) == '@')
3116 preselect = preselect.Mid(1);
3117 gtDlg.PreSelectItem(preselect);
3118 if (gtDlg.DoModal() == IDOK)
3120 preselect = "@";
3121 preselect += gtDlg.GetSelectedItem();
3122 SetValue(preselect);
3126 //////////////////////////////////////////////////////////////////////////
3127 void CPropertyItem::OnExpandButton()
3129 m_propertyCtrl->Expand(this, !IsExpanded(), true);
3132 //////////////////////////////////////////////////////////////////////////
3133 int CPropertyItem::GetHeight()
3135 if (m_propertyCtrl->IsExtenedUI())
3137 //m_nHeight = 20;
3138 switch (m_type)
3140 case ePropertyFloatCurve:
3141 //m_nHeight = 52;
3142 return 52;
3143 break;
3144 case ePropertyColorCurve:
3145 //m_nHeight = 36;
3146 return 36;
3148 return 20;
3150 return m_nHeight;
3153 //////////////////////////////////////////////////////////////////////////
3154 void CPropertyItem::AddChildrenForPFProperties()
3156 assert(m_type == ePropertyAiPFPropertiesList);
3158 for (Childs::iterator it = m_childs.begin(); it != m_childs.end(); ++it)
3159 m_propertyCtrl->DestroyControls(*it);
3161 RemoveAllChildren();
3162 m_propertyCtrl->InvalidateCtrl();
3164 std::set<CString> setSelectedPathTypeNames;
3166 CString token;
3167 int index = 0;
3168 while (!(token = m_value.Tokenize(" ,", index)).IsEmpty())
3169 setSelectedPathTypeNames.insert(token);
3171 int N = 1;
3172 char propertyN[100];
3173 for (std::set<CString>::iterator it = setSelectedPathTypeNames.begin(); it != setSelectedPathTypeNames.end(); ++it)
3175 IVariable* pVar = new CVariable<CString>;
3176 cry_sprintf(propertyN, "AgentType %d", N++);
3177 pVar->SetName(propertyN);
3178 pVar->Set(*it);
3180 CPropertyItemPtr pItem = new CPropertyItem(m_propertyCtrl);
3181 pItem->SetVariable(pVar);
3182 AddChild(pItem);
3186 //////////////////////////////////////////////////////////////////////////
3187 void CPropertyItem::AddChildrenForAIEntityClasses()
3189 assert(m_type == ePropertyAiEntityClasses);
3191 for (Childs::iterator it = m_childs.begin(); it != m_childs.end(); ++it)
3193 m_propertyCtrl->DestroyControls(*it);
3196 RemoveAllChildren();
3197 m_propertyCtrl->InvalidateCtrl();
3199 std::set<CString> setSelectedAIEntityClasses;
3201 CString token;
3202 int index = 0;
3203 while (!(token = m_value.Tokenize(" ,", index)).IsEmpty())
3204 setSelectedAIEntityClasses.insert(token);
3206 int N = 1;
3207 char propertyN[100];
3208 for (std::set<CString>::iterator it = setSelectedAIEntityClasses.begin(); it != setSelectedAIEntityClasses.end(); ++it)
3210 IVariable* pVar = new CVariable<CString>;
3211 cry_sprintf(propertyN, "Entity Class %d", N++);
3212 pVar->SetName(propertyN);
3213 pVar->Set(*it);
3215 CPropertyItemPtr pItem = new CPropertyItem(m_propertyCtrl);
3216 pItem->SetVariable(pVar);
3217 AddChild(pItem);
3221 static inline bool AlphabeticalBaseObjectLess(const CBaseObject* p1, const CBaseObject* p2)
3223 return p1->GetName() < p2->GetName();
3226 //////////////////////////////////////////////////////////////////////////
3228 void CPropertyItem::PopulateAITerritoriesList()
3230 CVariableEnum<string>* pVariable = static_cast<CVariableEnum<string>*>(&*m_pVariable);
3232 pVariable->SetEnumList(0);
3233 #ifndef USE_SIMPLIFIED_AI_TERRITORY_SHAPE
3234 pVariable->AddEnumItem("<Auto>", "<Auto>");
3235 #endif
3236 pVariable->AddEnumItem("<None>", "<None>");
3238 std::vector<CBaseObject*> vTerritories;
3239 GetIEditor()->GetObjectManager()->FindObjectsOfType(RUNTIME_CLASS(CAITerritoryObject), vTerritories);
3240 std::sort(vTerritories.begin(), vTerritories.end(), AlphabeticalBaseObjectLess);
3242 for (std::vector<CBaseObject*>::iterator it = vTerritories.begin(); it != vTerritories.end(); ++it)
3244 const string& name = (*it)->GetName();
3245 pVariable->AddEnumItem(name, name);
3248 m_enumList = pVariable->GetEnumList();
3251 //////////////////////////////////////////////////////////////////////////
3253 void CPropertyItem::PopulateAIWavesList()
3255 CVariableEnum<string>* pVariable = static_cast<CVariableEnum<string>*>(&*m_pVariable);
3257 pVariable->SetEnumList(0);
3258 pVariable->AddEnumItem("<None>", "<None>");
3260 CPropertyItem* pPropertyItem = GetParent()->FindItemByFullName("::AITerritoryAndWave::Territory");
3261 if (pPropertyItem)
3263 CString sTerritoryName = pPropertyItem->GetValue();
3264 #ifdef USE_SIMPLIFIED_AI_TERRITORY_SHAPE
3265 if (sTerritoryName != "<None>")
3266 #else
3267 if ((sTerritoryName != "<Auto>") && (sTerritoryName != "<None>"))
3268 #endif
3270 std::vector<CAIWaveObject*> vLinkedAIWaves;
3272 CBaseObject* pBaseObject = GetIEditor()->GetObjectManager()->FindObject(sTerritoryName);
3273 if (pBaseObject && pBaseObject->IsKindOf(RUNTIME_CLASS(CAITerritoryObject)))
3275 CAITerritoryObject* pTerritory = static_cast<CAITerritoryObject*>(pBaseObject);
3276 pTerritory->GetLinkedWaves(vLinkedAIWaves);
3279 std::sort(vLinkedAIWaves.begin(), vLinkedAIWaves.end(), AlphabeticalBaseObjectLess);
3281 for (std::vector<CAIWaveObject*>::iterator it = vLinkedAIWaves.begin(); it != vLinkedAIWaves.end(); ++it)
3283 const string& name = (*it)->GetName();
3284 pVariable->AddEnumItem(name, name);
3289 m_enumList = pVariable->GetEnumList();
3292 //////////////////////////////////////////////////////////////////////////
3293 void CPropertyItem::RepositionWindow(CWnd* pWnd, CRect rc)
3295 if (!s_HDWP)
3297 pWnd->MoveWindow(rc, FALSE);
3299 else
3301 s_HDWP = DeferWindowPos(s_HDWP, pWnd->GetSafeHwnd(), 0, rc.left, rc.top, rc.Width(), rc.Height(), SWP_NOACTIVATE | SWP_NOZORDER);
3305 //////////////////////////////////////////////////////////////////////////
3306 void CPropertyItem::RegisterCtrl(CWnd* pCtrl)
3308 if (pCtrl)
3310 m_controls.push_back(pCtrl);
3314 //////////////////////////////////////////////////////////////////////////
3315 void CPropertyItem::EnableControls(bool bEnable)
3317 for (int i = 0, num = m_controls.size(); i < num; i++)
3319 CWnd* pWnd = m_controls[i];
3320 if (pWnd && pWnd->GetSafeHwnd())
3322 pWnd->EnableWindow((bEnable) ? TRUE : FALSE);
3327 //////////////////////////////////////////////////////////////////////////
3328 void CPropertyItem::EnableNotifyWithoutValueChange(bool bFlag)
3330 for (int i = 0; i < GetChildCount(); ++i)
3332 CPropertyItem* item = GetChild(i);
3333 item->EnableNotifyWithoutValueChange(bFlag);
3335 m_bForceModified = bFlag;
3336 if (m_pVariable)
3337 m_pVariable->EnableNotifyWithoutValueChange(m_bForceModified);
3338 if (m_cEdit)
3339 m_cEdit->EnableUpdateOnKillFocus(!m_bForceModified);