You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
692 lines
20 KiB
C++
692 lines
20 KiB
C++
/*
|
|
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates, or
|
|
* a third party where indicated.
|
|
*
|
|
* For complete copyright and license terms please see the LICENSE at the root of this
|
|
* distribution (the "License"). All use of this software is governed by the License,
|
|
* or, if provided, by the license below or the license accompanying this file. Do not
|
|
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
*
|
|
*/
|
|
|
|
#include "EditorDefs.h"
|
|
|
|
#include "ReflectedPropertyItem.h"
|
|
|
|
// AzToolsFramework
|
|
#include <AzToolsFramework/UI/PropertyEditor/PropertyRowWidget.hxx>
|
|
|
|
// Editor
|
|
#include "ReflectedVarWrapper.h"
|
|
#include "ReflectedPropertyCtrl.h"
|
|
#include "Undo/UndoVariableChange.h"
|
|
|
|
// default number of increments to cover the range of a property - determined experimentally by feel
|
|
const float ReflectedPropertyItem::s_DefaultNumStepIncrements = 500.0f;
|
|
|
|
|
|
//A ReflectedVarAdapter for holding IVariableContainers
|
|
|
|
//The extra ReflectedVarAdapter is the extra case of a container (has children) but also has a value itself.
|
|
//An example is an IVariable array whose type is forced to IVariable::DT_TEXTURE. The base Ivariable has a texture,
|
|
//but it also has children that are parameters of the texture. The ReflectedPropertyEditor does not support this case
|
|
//so we work around by adding the base property to the list of children and showing the value of the base property
|
|
//in the container value space instead of "X Elements"
|
|
|
|
static ColorF StringToColor(const QString &value)
|
|
{
|
|
ColorF color;
|
|
float r, g, b, a;
|
|
int res = azsscanf(value.toUtf8().data(), "%f,%f,%f,%f", &r, &g, &b, &a);
|
|
if (res == 4)
|
|
{
|
|
color.Set(r, g, b, a);
|
|
}
|
|
else if (res == 3)
|
|
{
|
|
color.Set(r, g, b);
|
|
}
|
|
else
|
|
{
|
|
unsigned abgr;
|
|
azsscanf(value.toUtf8().data(), "%u", &abgr);
|
|
color = ColorF(abgr);
|
|
}
|
|
return color;
|
|
}
|
|
|
|
class ReflectedVarContainerAdapter : public ReflectedVarAdapter
|
|
{
|
|
public:
|
|
ReflectedVarContainerAdapter(ReflectedPropertyItem *item, ReflectedPropertyControl *control, ReflectedVarAdapter *variableAdapter = nullptr)
|
|
: m_extraVariableAdapter(variableAdapter)
|
|
, m_item(item)
|
|
, m_propertyCtrl(control)
|
|
, m_containerVar(new CPropertyContainer(AZStd::string()))
|
|
{
|
|
m_containerVar->SetAutoExpand(false);
|
|
}
|
|
|
|
void SetVariable(IVariable *pVariable) override
|
|
{
|
|
if (m_extraVariableAdapter)
|
|
m_extraVariableAdapter->SetVariable(pVariable);
|
|
|
|
//Check whether the parent container has autoExpand flag set, and if so, the autoexpand flag for this item
|
|
//We need to do this because the default IVariable flags has the item expanded, so most items are expanded,
|
|
//but the ReflectedPropertyEditor expands all ancestors if any item is expanded.
|
|
//This is not what we want -- the old property editor did not expand ancestors. In case of Material editor,
|
|
//this expansion can be really expensive!
|
|
const bool parentIsAutoExpand = m_item->GetParent() == nullptr || m_item->GetParent()->GetContainer() == nullptr || m_item->GetParent()->GetContainer()->m_containerVar->AutoExpand();
|
|
const bool bDefaultExpand = (pVariable->GetFlags() & IVariable::UI_COLLAPSED) == 0 || (pVariable->GetFlags() & IVariable::UI_AUTO_EXPAND);
|
|
m_containerVar->SetAutoExpand(parentIsAutoExpand && bDefaultExpand);
|
|
|
|
UpdateCommon(pVariable, pVariable);
|
|
}
|
|
|
|
//helps implement ReflectedPropertyControl::ReplaceVarBlock
|
|
void ReplaceVarBlock(CVarBlock *varBlock)
|
|
{
|
|
m_containerVar->Clear();
|
|
UpdateCommon(m_item->GetVariable(), varBlock);
|
|
}
|
|
|
|
void SyncReflectedVarToIVar(IVariable *pVariable) override
|
|
{
|
|
if (m_extraVariableAdapter)
|
|
{
|
|
m_extraVariableAdapter->SyncReflectedVarToIVar(pVariable);
|
|
//update text on parent container. Do not have control update attributes since this will happen anyway as part of updating ReflectedVar
|
|
updateContainerText(pVariable, false);
|
|
}
|
|
};
|
|
|
|
void SyncIVarToReflectedVar(IVariable *pVariable) override
|
|
{
|
|
if (m_extraVariableAdapter)
|
|
{
|
|
m_extraVariableAdapter->SyncIVarToReflectedVar(pVariable);
|
|
//update text on parent container. Force control to update attributes since this doesn't normally happen when updating an IVar from ReflectedVar
|
|
updateContainerText(pVariable, true);
|
|
}
|
|
};
|
|
|
|
CReflectedVar *GetReflectedVar() override { return m_containerVar.data(); }
|
|
|
|
bool Contains(CReflectedVar *var) override { return var == m_containerVar.data() || (m_extraVariableAdapter && m_extraVariableAdapter->GetReflectedVar() == var); }
|
|
|
|
private:
|
|
|
|
void UpdateCommon(IVariable *nameVariable, IVariableContainer *childContainer)
|
|
{
|
|
m_containerVar->m_varName = nameVariable->GetHumanName().toUtf8().data();
|
|
m_containerVar->m_description = nameVariable->GetDescription().toUtf8().data();
|
|
if (m_extraVariableAdapter)
|
|
{
|
|
m_containerVar->AddProperty(m_extraVariableAdapter->GetReflectedVar());
|
|
}
|
|
//Handle adding empty varblock
|
|
if (!childContainer)
|
|
return;
|
|
|
|
for (int i = 0; i < childContainer->GetNumVariables(); i++)
|
|
{
|
|
AddChild(childContainer->GetVariable(i));
|
|
}
|
|
}
|
|
|
|
void AddChild(IVariable *var)
|
|
{
|
|
if (var->GetFlags() & IVariable::UI_INVISIBLE)
|
|
return;
|
|
ReflectedPropertyItemPtr item = new ReflectedPropertyItem(m_propertyCtrl, m_item);
|
|
item->SetVariable(var);
|
|
m_containerVar->AddProperty(item->GetReflectedVar());
|
|
}
|
|
|
|
void updateContainerText(IVariable *pVariable, bool updateAttributes)
|
|
{
|
|
//set text of the container to the value of the main variable. If it's empty, use space, otherwise ReflectedPropertyEditor doesn't update it!
|
|
m_containerVar->SetValueText(pVariable->GetDisplayValue().isEmpty() ? AZStd::string(" ") : AZStd::string(pVariable->GetDisplayValue().toUtf8().data()));
|
|
if (updateAttributes)
|
|
m_propertyCtrl->InvalidateCtrl();
|
|
}
|
|
|
|
private:
|
|
//optional adapter for case where this item contains a variable in addition to a container of variables.
|
|
ReflectedVarAdapter *m_extraVariableAdapter;
|
|
QScopedPointer<CPropertyContainer> m_containerVar;
|
|
ReflectedPropertyItem *m_item;
|
|
ReflectedPropertyControl *m_propertyCtrl;
|
|
};
|
|
|
|
ReflectedPropertyItem::ReflectedPropertyItem(ReflectedPropertyControl *control, ReflectedPropertyItem *parent)
|
|
: m_pVariable(nullptr)
|
|
, m_reflectedVarAdapter(nullptr)
|
|
, m_reflectedVarContainerAdapter(nullptr)
|
|
, m_parent(parent)
|
|
, m_propertyCtrl(control)
|
|
, m_syncingIVar(false)
|
|
, m_strNoScriptDefault("<<undefined>>")
|
|
, m_strScriptDefault(m_strNoScriptDefault)
|
|
{
|
|
m_type = ePropertyInvalid;
|
|
m_modified = false;
|
|
if (parent)
|
|
parent->AddChild(this);
|
|
|
|
m_onSetCallback = AZStd::bind(&ReflectedPropertyItem::OnVariableChange, this, AZStd::placeholders::_1);
|
|
m_onSetEnumCallback = AZStd::bind(&ReflectedPropertyItem::OnVariableEnumChange, this, AZStd::placeholders::_1);
|
|
}
|
|
|
|
ReflectedPropertyItem::~ReflectedPropertyItem()
|
|
{
|
|
// just to make sure we dont double (or infinitely recurse...) delete
|
|
AddRef();
|
|
|
|
if (m_pVariable)
|
|
ReleaseVariable();
|
|
|
|
RemoveAllChildren();
|
|
}
|
|
|
|
void ReflectedPropertyItem::SetVariable(IVariable *var)
|
|
{
|
|
if (var == m_pVariable)
|
|
{
|
|
// Early exit optimization if setting the same var as the current var.
|
|
// A common use case, in Track View for example, is to re-use the save var for a property when switching to a new
|
|
// instance of the same variable. The visible display of the value is often handled by invalidating the property,
|
|
// but the non-visible attributes, i.e. the range values, are usually set using this method. Thus we reset the ranges
|
|
// explicitly here when the Ivariable var is the same
|
|
|
|
if (m_reflectedVarAdapter)
|
|
m_reflectedVarAdapter->UpdateRangeLimits(var);
|
|
return;
|
|
}
|
|
_smart_ptr<IVariable> pInputVar = var;
|
|
// Release previous variable.
|
|
if (m_pVariable)
|
|
ReleaseVariable();
|
|
|
|
m_pVariable = pInputVar;
|
|
assert(m_pVariable != NULL);
|
|
|
|
m_pVariable->AddOnSetCallback(&m_onSetCallback);
|
|
m_pVariable->AddOnSetEnumCallback(&m_onSetEnumCallback);
|
|
|
|
// Fetch base parameter description
|
|
Prop::Description desc(m_pVariable);
|
|
m_type = desc.m_type;
|
|
|
|
switch (m_type)
|
|
{
|
|
case ePropertyVector2:
|
|
m_reflectedVarAdapter = new ReflectedVarVector2Adapter;
|
|
break;
|
|
case ePropertyVector:
|
|
m_reflectedVarAdapter = new ReflectedVarVector3Adapter;
|
|
break;
|
|
case ePropertyVector4:
|
|
m_reflectedVarAdapter = new ReflectedVarVector4Adapter;
|
|
break;
|
|
case ePropertyFloat:
|
|
case ePropertyAngle:
|
|
//if the Description has a valid global enumDB lookup, edit as an enum, otherwise use normal float editor
|
|
if (desc.m_pEnumDBItem)
|
|
m_reflectedVarAdapter = new ReflectedVarDBEnumAdapter;
|
|
else
|
|
m_reflectedVarAdapter = new ReflectedVarFloatAdapter;
|
|
break;
|
|
case ePropertyInt:
|
|
//if the Description has a valid global enumDB lookup, edit as an enum, otherwise use normal int editor
|
|
if (desc.m_pEnumDBItem)
|
|
m_reflectedVarAdapter = new ReflectedVarDBEnumAdapter;
|
|
else
|
|
m_reflectedVarAdapter = new ReflectedVarIntAdapter;
|
|
break;
|
|
case ePropertyBool:
|
|
m_reflectedVarAdapter = new ReflectedVarBoolAdapter;
|
|
break;
|
|
case ePropertyString:
|
|
//if the Description has a valid global enumDB lookup, edit as an enum, otherwise use normal string editor
|
|
if (desc.m_pEnumDBItem)
|
|
m_reflectedVarAdapter = new ReflectedVarDBEnumAdapter;
|
|
else
|
|
m_reflectedVarAdapter = new ReflectedVarStringAdapter;
|
|
break;
|
|
case ePropertySelection:
|
|
m_reflectedVarAdapter = new ReflectedVarEnumAdapter;
|
|
break;
|
|
case ePropertyAnimation:
|
|
m_reflectedVarAdapter = new ReflectedVarAnimationAdapter;
|
|
break;
|
|
case ePropertyColor:
|
|
m_reflectedVarAdapter = new ReflectedVarColorAdapter;
|
|
break;
|
|
case ePropertyUser:
|
|
m_reflectedVarAdapter = new ReflectedVarUserAdapter;
|
|
break;
|
|
case ePropertyShader:
|
|
case ePropertyEquip:
|
|
case ePropertyReverbPreset:
|
|
case ePropertyGameToken:
|
|
case ePropertyMissionObj:
|
|
case ePropertySequence:
|
|
case ePropertySequenceId:
|
|
case ePropertyLocalString:
|
|
case ePropertyLightAnimation:
|
|
case ePropertyParticleName:
|
|
m_reflectedVarAdapter = new ReflectedVarGenericPropertyAdapter(desc.m_type);
|
|
break;
|
|
case ePropertyTexture:
|
|
case ePropertyModel:
|
|
case ePropertyGeomCache:
|
|
case ePropertyAudioTrigger:
|
|
case ePropertyAudioSwitch:
|
|
case ePropertyAudioSwitchState:
|
|
case ePropertyAudioRTPC:
|
|
case ePropertyAudioEnvironment:
|
|
case ePropertyAudioPreloadRequest:
|
|
case ePropertyFile:
|
|
m_reflectedVarAdapter = new ReflectedVarResourceAdapter;
|
|
break;
|
|
case ePropertyFloatCurve:
|
|
case ePropertyColorCurve:
|
|
m_reflectedVarAdapter = new ReflectedVarSplineAdapter(this, m_type);
|
|
break;
|
|
case ePropertyMotion:
|
|
m_reflectedVarAdapter = new ReflectedVarMotionAdapter;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
const bool hasChildren = (m_pVariable->GetNumVariables() > 0 || desc.m_type == ePropertyTable || m_pVariable->GetType() == IVariable::ARRAY);
|
|
//const bool isNotContainerType = (m_pVariable->GetType() != IVariable::ARRAY && desc.m_type != ePropertyTable && desc.m_type != ePropertyInvalid);
|
|
if (hasChildren )
|
|
{
|
|
m_reflectedVarContainerAdapter = new ReflectedVarContainerAdapter(this, m_propertyCtrl, m_reflectedVarAdapter);
|
|
m_reflectedVarAdapter = m_reflectedVarContainerAdapter;
|
|
}
|
|
|
|
if (m_reflectedVarAdapter)
|
|
{
|
|
m_reflectedVarAdapter->SetVariable(m_pVariable);
|
|
m_reflectedVarAdapter->SyncReflectedVarToIVar(m_pVariable);
|
|
}
|
|
|
|
m_modified = false;
|
|
}
|
|
|
|
void ReflectedPropertyItem::ReplaceVarBlock(CVarBlock *varBlock)
|
|
{
|
|
RemoveAllChildren();
|
|
if (m_reflectedVarAdapter)
|
|
m_reflectedVarAdapter->ReplaceVarBlock(varBlock);
|
|
}
|
|
|
|
void ReflectedPropertyItem::AddChild(ReflectedPropertyItem *item)
|
|
{
|
|
assert(item);
|
|
m_childs.push_back(item);
|
|
}
|
|
|
|
void ReflectedPropertyItem::RemoveAllChildren()
|
|
{
|
|
for (int i = 0; i < m_childs.size(); i++)
|
|
{
|
|
m_childs[i]->m_parent = 0;
|
|
}
|
|
|
|
m_childs.clear();
|
|
}
|
|
|
|
void ReflectedPropertyItem::RemoveChild(ReflectedPropertyItem* item)
|
|
{
|
|
for (int i = 0; i < m_childs.size(); i++)
|
|
{
|
|
if (m_childs[i] == item)
|
|
{
|
|
item->m_parent = nullptr;
|
|
m_childs.erase(m_childs.begin() + i);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
CReflectedVar * ReflectedPropertyItem::GetReflectedVar() const
|
|
{
|
|
return m_reflectedVarAdapter ? m_reflectedVarAdapter->GetReflectedVar() : nullptr;
|
|
}
|
|
|
|
ReflectedPropertyItem * ReflectedPropertyItem::findItem(CReflectedVar *var)
|
|
{
|
|
if (m_reflectedVarAdapter && m_reflectedVarAdapter->Contains(var) )
|
|
return this;
|
|
for (auto child : m_childs)
|
|
{
|
|
ReflectedPropertyItem *result = child->findItem(var);
|
|
if (result)
|
|
return result;
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
|
|
ReflectedPropertyItem * ReflectedPropertyItem::findItem(IVariable *var)
|
|
{
|
|
if (m_pVariable == var)
|
|
return this;
|
|
for (auto child : m_childs)
|
|
{
|
|
ReflectedPropertyItem *result = child->findItem(var);
|
|
if (result)
|
|
return result;
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
ReflectedPropertyItem* ReflectedPropertyItem::findItem(const QString &name)
|
|
{
|
|
if (m_pVariable && m_pVariable->GetHumanName() == name)
|
|
return this;
|
|
for (auto child : m_childs)
|
|
{
|
|
ReflectedPropertyItem *result = child->findItem(name);
|
|
if (result)
|
|
return result;
|
|
}
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
ReflectedPropertyItem * ReflectedPropertyItem::FindItemByFullName(const QString& fullName)
|
|
{
|
|
if (GetFullName() == fullName)
|
|
{
|
|
return this;
|
|
}
|
|
for (int i = 0; i < m_childs.size(); ++i)
|
|
{
|
|
auto pFound = m_childs[i]->FindItemByFullName(fullName);
|
|
if (pFound)
|
|
{
|
|
return pFound;
|
|
}
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
QString ReflectedPropertyItem::GetName() const
|
|
{
|
|
return m_pVariable ? m_pVariable->GetHumanName() : QString();
|
|
}
|
|
|
|
QString ReflectedPropertyItem::GetFullName() const
|
|
{
|
|
if (m_parent && m_pVariable)
|
|
{
|
|
return m_parent->GetFullName() + "::" + m_pVariable->GetName();
|
|
}
|
|
else if (m_pVariable)
|
|
{
|
|
return m_pVariable->GetName();
|
|
}
|
|
else
|
|
{
|
|
return {};
|
|
}
|
|
}
|
|
|
|
void ReflectedPropertyItem::OnReflectedVarChanged()
|
|
{
|
|
m_syncingIVar = true;
|
|
if (m_reflectedVarAdapter)
|
|
{
|
|
std::unique_ptr<CUndo> undo;
|
|
if (!CUndo::IsRecording())
|
|
{
|
|
if (!m_propertyCtrl->CallUndoFunc(this))
|
|
undo.reset(new CUndo((m_pVariable->GetHumanName() + " Modified").toUtf8().data()));
|
|
}
|
|
|
|
m_reflectedVarAdapter->SyncIVarToReflectedVar(m_pVariable);
|
|
|
|
if (m_propertyCtrl->IsStoreUndoByItems() && CUndo::IsRecording())
|
|
CUndo::Record(new CUndoVariableChange(m_pVariable, "PropertyChange"));
|
|
|
|
m_modified = true;
|
|
}
|
|
m_syncingIVar = false;
|
|
}
|
|
|
|
void ReflectedPropertyItem::SyncReflectedVarToIVar()
|
|
{
|
|
if (m_reflectedVarAdapter)
|
|
{
|
|
m_reflectedVarAdapter->SyncReflectedVarToIVar(m_pVariable);
|
|
}
|
|
}
|
|
|
|
void ReflectedPropertyItem::ReleaseVariable()
|
|
{
|
|
if (m_pVariable)
|
|
{
|
|
// Unwire all from variable.
|
|
m_pVariable->RemoveOnSetCallback(&m_onSetCallback);
|
|
m_pVariable->RemoveOnSetEnumCallback(&m_onSetEnumCallback);
|
|
}
|
|
m_pVariable = 0;
|
|
delete m_reflectedVarAdapter;
|
|
m_reflectedVarAdapter = nullptr;
|
|
}
|
|
|
|
void ReflectedPropertyItem::OnVariableChange(IVariable* pVar)
|
|
{
|
|
assert(pVar != 0 && pVar == m_pVariable);
|
|
|
|
if (m_syncingIVar)
|
|
return;
|
|
|
|
// When variable changes, invalidate UI.
|
|
m_modified = true;
|
|
|
|
if (m_reflectedVarAdapter)
|
|
{
|
|
m_reflectedVarAdapter->OnVariableChange(pVar);
|
|
}
|
|
SyncReflectedVarToIVar();
|
|
|
|
m_propertyCtrl->InvalidateCtrl();
|
|
}
|
|
|
|
void ReflectedPropertyItem::OnVariableEnumChange([[maybe_unused]] IVariable* pVar)
|
|
{
|
|
|
|
if (m_reflectedVarAdapter && m_reflectedVarAdapter->UpdateReflectedVarEnums())
|
|
{
|
|
m_propertyCtrl->InvalidateCtrl(true);
|
|
}
|
|
}
|
|
|
|
void ReflectedPropertyItem::ReloadValues()
|
|
{
|
|
m_modified = false;
|
|
|
|
if (m_pVariable)
|
|
SetVariable(m_pVariable);
|
|
|
|
for (int i = 0; i < GetChildCount(); i++)
|
|
{
|
|
GetChild(i)->ReloadValues();
|
|
}
|
|
SyncReflectedVarToIVar();
|
|
}
|
|
|
|
|
|
/** Changes value of item.
|
|
*/
|
|
void ReflectedPropertyItem::SetValue(const QString& sValue, bool bRecordUndo, bool bForceModified)
|
|
{
|
|
if (!m_pVariable)
|
|
{
|
|
return;
|
|
}
|
|
|
|
_smart_ptr<ReflectedPropertyItem> holder = this; // Make sure we are not released during this function.
|
|
|
|
QString value = sValue;
|
|
|
|
switch (m_type)
|
|
{
|
|
case ePropertyBool:
|
|
if (QString::compare(value, "true", Qt::CaseInsensitive) == 0 || value.toInt() != 0)
|
|
{
|
|
value = "1";
|
|
}
|
|
else
|
|
{
|
|
value = "0";
|
|
}
|
|
break;
|
|
|
|
case ePropertyVector2:
|
|
if (!value.contains(','))
|
|
{
|
|
value = value + ", " + value;
|
|
}
|
|
break;
|
|
|
|
case ePropertyVector4:
|
|
if (!value.contains(','))
|
|
{
|
|
value = value + ", " + value + ", " + value + ", " + value;
|
|
}
|
|
break;
|
|
|
|
case ePropertyVector:
|
|
if (!value.contains(','))
|
|
{
|
|
value = value + ", " + value + ", " + value;
|
|
}
|
|
break;
|
|
|
|
case ePropertyTexture:
|
|
case ePropertyModel:
|
|
value.replace('\\', '/');
|
|
break;
|
|
}
|
|
|
|
// correct the length of value
|
|
switch (m_type)
|
|
{
|
|
case ePropertyTexture:
|
|
case ePropertyModel:
|
|
case ePropertyFile:
|
|
if (value.length() >= MAX_PATH)
|
|
{
|
|
value = value.left(MAX_PATH);
|
|
}
|
|
break;
|
|
}
|
|
|
|
|
|
bool bModified = bForceModified || m_pVariable->GetDisplayValue() != value;
|
|
bool bStoreUndo = (m_pVariable->GetDisplayValue() != value || bForceModified) && bRecordUndo;
|
|
|
|
std::unique_ptr<CUndo> undo;
|
|
if (bStoreUndo && !CUndo::IsRecording())
|
|
{
|
|
if (!m_propertyCtrl->CallUndoFunc(this))
|
|
{
|
|
undo.reset(new CUndo((GetName() + " Modified").toUtf8().data()));
|
|
}
|
|
}
|
|
|
|
if (m_pVariable)
|
|
{
|
|
if (bModified)
|
|
{
|
|
if (m_propertyCtrl->IsStoreUndoByItems() && bStoreUndo && CUndo::IsRecording())
|
|
{
|
|
CUndo::Record(new CUndoVariableChange(m_pVariable, "PropertyChange"));
|
|
}
|
|
|
|
if (bForceModified)
|
|
{
|
|
m_pVariable->SetForceModified(true);
|
|
}
|
|
|
|
switch (m_type)
|
|
{
|
|
case ePropertyColor:
|
|
{
|
|
ColorF color = StringToColor(value);
|
|
if (m_pVariable->GetType() == IVariable::VECTOR)
|
|
{
|
|
m_pVariable->Set(color.toVec3());
|
|
}
|
|
else
|
|
{
|
|
m_pVariable->Set(static_cast<int>(color.pack_abgr8888()));
|
|
}
|
|
break;
|
|
}
|
|
case ePropertyInvalid:
|
|
break;
|
|
default:
|
|
m_pVariable->SetDisplayValue(value);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (bModified)
|
|
{
|
|
m_modified = true;
|
|
// If Value changed mark document modified.
|
|
// Notify parent that this Item have been modified.
|
|
m_propertyCtrl->OnItemChange(this);
|
|
}
|
|
}
|
|
}
|
|
|
|
void ReflectedPropertyItem::SendOnItemChange()
|
|
{
|
|
m_propertyCtrl->OnItemChange(this);
|
|
}
|
|
|
|
void ReflectedPropertyItem::ExpandAllChildren(bool recursive)
|
|
{
|
|
Expand(true);
|
|
for (auto child : m_childs)
|
|
{
|
|
if (recursive)
|
|
{
|
|
child->ExpandAllChildren(recursive);
|
|
}
|
|
else
|
|
{
|
|
child->Expand(true);
|
|
}
|
|
}
|
|
}
|
|
|
|
void ReflectedPropertyItem::Expand(bool expand)
|
|
{
|
|
AzToolsFramework::PropertyRowWidget *widget = m_propertyCtrl->FindPropertyRowWidget(this);
|
|
if (widget)
|
|
{
|
|
widget->SetExpanded(expand);
|
|
}
|
|
}
|
|
|
|
QString ReflectedPropertyItem::GetPropertyName() const
|
|
{
|
|
return m_pVariable ? m_pVariable->GetHumanName() : QString();
|
|
}
|
|
|