git mv Code\Sandbox\Editor Code/Editor
Signed-off-by: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com>
This commit is contained in:
@@ -0,0 +1,685 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#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 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();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user