git mv Code\Sandbox\Editor Code/Editor

Signed-off-by: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com>
This commit is contained in:
Esteban Papp
2021-06-29 12:41:59 -07:00
parent 9f0bbf3b74
commit e34e36cb35
1415 changed files with 0 additions and 0 deletions
@@ -0,0 +1,130 @@
/*
* Copyright (c) Contributors to the Open 3D Engine Project
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#include "EditorDefs.h"
#include "PropertyAnimationCtrl.h"
// Qt
#include <QHBoxLayout>
#include <QLabel>
#include <QToolButton>
// Editor
#include "Util/UIEnumerations.h"
#include "IResourceSelectorHost.h"
AnimationPropertyCtrl::AnimationPropertyCtrl(QWidget *pParent)
: QWidget(pParent)
{
m_animationLabel = new QLabel;
m_pApplyButton = new QToolButton;
m_pApplyButton->setIcon(QIcon(":/reflectedPropertyCtrl/img/apply.png"));
m_pApplyButton->setFocusPolicy(Qt::StrongFocus);
QHBoxLayout *pLayout = new QHBoxLayout(this);
pLayout->setContentsMargins(0, 0, 0, 0);
pLayout->addWidget(m_animationLabel, 1);
pLayout->addWidget(m_pApplyButton);
connect(m_pApplyButton, &QAbstractButton::clicked, this, &AnimationPropertyCtrl::OnApplyClicked);
};
AnimationPropertyCtrl::~AnimationPropertyCtrl()
{
}
void AnimationPropertyCtrl::SetValue(const CReflectedVarAnimation &animation)
{
m_animation = animation;
m_animationLabel->setText(animation.m_animation.c_str());
}
CReflectedVarAnimation AnimationPropertyCtrl::value() const
{
return m_animation;
}
void AnimationPropertyCtrl::OnApplyClicked()
{
QStringList cSelectedAnimations;
size_t nTotalAnimations(0);
size_t nCurrentAnimation(0);
QString combinedString = GetIEditor()->GetResourceSelectorHost()->GetGlobalSelection("animation");
SplitString(combinedString, cSelectedAnimations, ',');
nTotalAnimations = cSelectedAnimations.size();
for (nCurrentAnimation = 0; nCurrentAnimation < nTotalAnimations; ++nCurrentAnimation)
{
QString& rstrCurrentAnimAction = cSelectedAnimations[nCurrentAnimation];
if (!rstrCurrentAnimAction.isEmpty())
{
m_animation.m_animation = rstrCurrentAnimAction.toUtf8().data();
m_animationLabel->setText(m_animation.m_animation.c_str());
emit ValueChanged(m_animation);
}
}
}
QWidget* AnimationPropertyCtrl::GetFirstInTabOrder()
{
return m_pApplyButton;
}
QWidget* AnimationPropertyCtrl::GetLastInTabOrder()
{
return m_pApplyButton;
}
void AnimationPropertyCtrl::UpdateTabOrder()
{
setTabOrder(m_pApplyButton, m_pApplyButton);
}
QWidget* AnimationPropertyWidgetHandler::CreateGUI(QWidget *pParent)
{
AnimationPropertyCtrl* newCtrl = aznew AnimationPropertyCtrl(pParent);
connect(newCtrl, &AnimationPropertyCtrl::ValueChanged, newCtrl, [newCtrl]()
{
EBUS_EVENT(AzToolsFramework::PropertyEditorGUIMessages::Bus, RequestWrite, newCtrl);
});
return newCtrl;
}
void AnimationPropertyWidgetHandler::ConsumeAttribute(AnimationPropertyCtrl* GUI, AZ::u32 attrib, AzToolsFramework::PropertyAttributeReader* attrValue, const char* debugName)
{
Q_UNUSED(GUI);
Q_UNUSED(attrib);
Q_UNUSED(attrValue);
Q_UNUSED(debugName);
}
void AnimationPropertyWidgetHandler::WriteGUIValuesIntoProperty(size_t index, AnimationPropertyCtrl* GUI, property_t& instance, AzToolsFramework::InstanceDataNode* node)
{
Q_UNUSED(index);
Q_UNUSED(node);
CReflectedVarAnimation val = GUI->value();
instance = static_cast<property_t>(val);
}
bool AnimationPropertyWidgetHandler::ReadValuesIntoGUI(size_t index, AnimationPropertyCtrl* GUI, const property_t& instance, AzToolsFramework::InstanceDataNode* node)
{
Q_UNUSED(index);
Q_UNUSED(node);
CReflectedVarAnimation val = instance;
GUI->SetValue(val);
return false;
}
#include <Controls/ReflectedPropertyControl/moc_PropertyAnimationCtrl.cpp>
@@ -0,0 +1,77 @@
/*
* Copyright (c) Contributors to the Open 3D Engine Project
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#ifndef CRYINCLUDE_EDITOR_UTILS_PROPERTYANIMATIONCTRL_H
#define CRYINCLUDE_EDITOR_UTILS_PROPERTYANIMATIONCTRL_H
#pragma once
#if !defined(Q_MOC_RUN)
#include <AzCore/base.h>
#include <AzCore/Memory/SystemAllocator.h>
#include <AzToolsFramework/UI/PropertyEditor/PropertyEditorAPI.h>
#include "ReflectedVar.h"
#include <QWidget>
#include <QPointer>
#endif
class QToolButton;
class QLabel;
class QHBoxLayout;
class AnimationPropertyCtrl
: public QWidget
{
Q_OBJECT
public:
AZ_CLASS_ALLOCATOR(AnimationPropertyCtrl, AZ::SystemAllocator, 0);
AnimationPropertyCtrl(QWidget* pParent = nullptr);
virtual ~AnimationPropertyCtrl();
CReflectedVarAnimation value() const;
QWidget* GetFirstInTabOrder();
QWidget* GetLastInTabOrder();
void UpdateTabOrder();
signals:
void ValueChanged(CReflectedVarAnimation value);
public slots:
void SetValue(const CReflectedVarAnimation& animation);
protected slots:
void OnApplyClicked();
private:
QToolButton* m_pApplyButton;
QLabel* m_animationLabel;
CReflectedVarAnimation m_animation;
};
class AnimationPropertyWidgetHandler
: QObject
, public AzToolsFramework::PropertyHandler < CReflectedVarAnimation, AnimationPropertyCtrl >
{
public:
AZ_CLASS_ALLOCATOR(AnimationPropertyWidgetHandler, AZ::SystemAllocator, 0);
virtual AZ::u32 GetHandlerName(void) const override { return AZ_CRC("Animation", 0x8d5284dc); }
virtual bool IsDefaultHandler() const override { return true; }
virtual QWidget* GetFirstInTabOrder(AnimationPropertyCtrl* widget) override { return widget->GetFirstInTabOrder(); }
virtual QWidget* GetLastInTabOrder(AnimationPropertyCtrl* widget) override { return widget->GetLastInTabOrder(); }
virtual void UpdateWidgetInternalTabbing(AnimationPropertyCtrl* widget) override { widget->UpdateTabOrder(); }
virtual QWidget* CreateGUI(QWidget* pParent) override;
virtual void ConsumeAttribute(AnimationPropertyCtrl* GUI, AZ::u32 attrib, AzToolsFramework::PropertyAttributeReader* attrValue, const char* debugName) override;
virtual void WriteGUIValuesIntoProperty(size_t index, AnimationPropertyCtrl* GUI, property_t& instance, AzToolsFramework::InstanceDataNode* node) override;
virtual bool ReadValuesIntoGUI(size_t index, AnimationPropertyCtrl* GUI, const property_t& instance, AzToolsFramework::InstanceDataNode* node) override;
};
#endif // CRYINCLUDE_EDITOR_UTILS_PROPERTYANIMATIONCTRL_H
@@ -0,0 +1,37 @@
/*
* Copyright (c) Contributors to the Open 3D Engine Project
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#include "EditorDefs.h"
// Editor
#include "PropertyCtrl.h"
#include "PropertyAnimationCtrl.h"
#include "PropertyResourceCtrl.h"
#include "PropertyGenericCtrl.h"
#include "PropertyMiscCtrl.h"
#include "PropertyMotionCtrl.h"
void RegisterReflectedVarHandlers()
{
static bool registered = false;
if (!registered)
{
registered = true;
EBUS_EVENT(AzToolsFramework::PropertyTypeRegistrationMessages::Bus, RegisterPropertyType, aznew AnimationPropertyWidgetHandler());
EBUS_EVENT(AzToolsFramework::PropertyTypeRegistrationMessages::Bus, RegisterPropertyType, aznew FileResourceSelectorWidgetHandler());
EBUS_EVENT(AzToolsFramework::PropertyTypeRegistrationMessages::Bus, RegisterPropertyType, aznew ReverbPresetPropertyHandler());
EBUS_EVENT(AzToolsFramework::PropertyTypeRegistrationMessages::Bus, RegisterPropertyType, aznew SequencePropertyHandler());
EBUS_EVENT(AzToolsFramework::PropertyTypeRegistrationMessages::Bus, RegisterPropertyType, aznew SequenceIdPropertyHandler());
EBUS_EVENT(AzToolsFramework::PropertyTypeRegistrationMessages::Bus, RegisterPropertyType, aznew LocalStringPropertyHandler());
EBUS_EVENT(AzToolsFramework::PropertyTypeRegistrationMessages::Bus, RegisterPropertyType, aznew LightAnimationPropertyHandler());
EBUS_EVENT(AzToolsFramework::PropertyTypeRegistrationMessages::Bus, RegisterPropertyType, aznew UserPopupWidgetHandler());
EBUS_EVENT(AzToolsFramework::PropertyTypeRegistrationMessages::Bus, RegisterPropertyType, aznew ColorCurveHandler());
EBUS_EVENT(AzToolsFramework::PropertyTypeRegistrationMessages::Bus, RegisterPropertyType, aznew FloatCurveHandler());
EBUS_EVENT(AzToolsFramework::PropertyTypeRegistrationMessages::Bus, RegisterPropertyType, aznew MotionPropertyWidgetHandler());
}
}
@@ -0,0 +1,17 @@
/*
* Copyright (c) Contributors to the Open 3D Engine Project
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#ifndef CRYINCLUDE_EDITOR_UTILS_PROPERTYCTRL_H
#define CRYINCLUDE_EDITOR_UTILS_PROPERTYCTRL_H
#pragma once
void RegisterReflectedVarHandlers();
#endif // CRYINCLUDE_EDITOR_UTILS_PROPERTYCTRL_H
@@ -0,0 +1,257 @@
/*
* Copyright (c) Contributors to the Open 3D Engine Project
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#include "EditorDefs.h"
#include "PropertyGenericCtrl.h"
// Qt
#include <QMessageBox>
#include <QHBoxLayout>
#include <QtWidgets/QLabel>
#include <QLineEdit>
#include <QStringListModel>
#include <QToolButton>
// CryCommon
#include <CryCommon/ILocalizationManager.h>
// Editor
#include "SelectLightAnimationDialog.h"
#include "SelectSequenceDialog.h"
#include "SelectEAXPresetDlg.h"
#include "QtViewPaneManager.h"
AZ_PUSH_DISABLE_DLL_EXPORT_MEMBER_WARNING
#include <QtWidgets/QListView>
AZ_POP_DISABLE_DLL_EXPORT_MEMBER_WARNING
GenericPopupPropertyEditor::GenericPopupPropertyEditor(QWidget *pParent, bool showTwoButtons)
:QWidget(pParent)
{
m_valueLabel = new QLabel;
QToolButton *mainButton = new QToolButton;
mainButton->setAutoRaise(true);
mainButton->setIcon(QIcon(QStringLiteral(":/stylesheet/img/UI20/browse-edit.svg")));
connect(mainButton, &QToolButton::clicked, this, &GenericPopupPropertyEditor::onEditClicked);
QHBoxLayout *mainLayout = new QHBoxLayout(this);
mainLayout->addWidget(m_valueLabel, 1);
mainLayout->addWidget(mainButton);
mainLayout->setContentsMargins(0, 0, 0, 0);
if (showTwoButtons)
{
QToolButton *button2 = new QToolButton;
button2->setAutoRaise(true);
button2->setIcon(QIcon(QStringLiteral(":/stylesheet/img/UI20/more.svg")));
connect(button2, &QToolButton::clicked, this, &GenericPopupPropertyEditor::onButton2Clicked);
mainLayout->insertWidget(1, button2);
}
}
void GenericPopupPropertyEditor::SetValue(const QString &value, bool notify)
{
if (m_value != value)
{
m_value = value;
m_valueLabel->setText(m_value);
if (notify)
emit ValueChanged(m_value);
}
}
void GenericPopupPropertyEditor::SetPropertyType(PropertyType type)
{
m_propertyType = type;
}
void ReverbPresetPropertyEditor::onEditClicked()
{
CSelectEAXPresetDlg PresetDlg(this);
PresetDlg.SetCurrPreset(GetValue());
if (PresetDlg.exec() == QDialog::Accepted)
{
SetValue(PresetDlg.GetCurrPreset());
}
}
void SequencePropertyEditor::onEditClicked()
{
CSelectSequenceDialog gtDlg(this);
gtDlg.PreSelectItem(GetValue());
if (gtDlg.exec() == QDialog::Accepted)
SetValue(gtDlg.GetSelectedItem());
}
void SequenceIdPropertyEditor::onEditClicked()
{
CSelectSequenceDialog gtDlg;
uint32 id = GetValue().toUInt();
IAnimSequence *pSeq = GetIEditor()->GetMovieSystem()->FindSequenceById(id);
if (pSeq)
gtDlg.PreSelectItem(pSeq->GetName());
if (gtDlg.exec() == QDialog::Accepted)
{
pSeq = GetIEditor()->GetMovieSystem()->FindLegacySequenceByName(gtDlg.GetSelectedItem().toUtf8().data());
assert(pSeq);
if (pSeq->GetId() > 0)
{
// This sequence is a new one with a valid ID.
SetValue(QString::number(pSeq->GetId()));
}
else
{
// This sequence is an old one without an ID.
QMessageBox::warning(this, tr("Old Sequence"), tr("This is an old sequence without an ID.\nSo it cannot be used with the new ID-based linking."));
}
}
}
void LocalStringPropertyEditor::onEditClicked()
{
std::vector<IVariable::IGetCustomItems::SItem> items;
ILocalizationManager* pMgr = gEnv->pSystem->GetLocalizationManager();
if (!pMgr)
return;
int nCount = pMgr->GetLocalizedStringCount();
if (nCount <= 0)
return;
items.reserve(nCount);
IVariable::IGetCustomItems::SItem item;
SLocalizedInfoEditor sInfo;
for (int i = 0; i < nCount; ++i)
{
if (pMgr->GetLocalizedInfoByIndex(i, sInfo))
{
item.desc = tr("English Text:\r\n");
item.desc += QString::fromWCharArray(Unicode::Convert<wstring>(sInfo.sUtf8TranslatedText).c_str());
item.name = sInfo.sKey;
items.push_back(item);
}
}
CGenericSelectItemDialog gtDlg;
const bool bUseTree = true;
if (bUseTree)
{
gtDlg.SetMode(CGenericSelectItemDialog::eMODE_TREE);
gtDlg.SetTreeSeparator("/");
}
gtDlg.SetItems(items);
gtDlg.setWindowTitle(tr("Choose Localized String"));
QString preselect = GetValue();
if (!preselect.isEmpty() && preselect.at(0) == '@')
preselect = preselect.mid(1);
gtDlg.PreSelectItem(preselect);
if (gtDlg.exec() == QDialog::Accepted)
{
preselect = "@";
preselect += gtDlg.GetSelectedItem();
SetValue(preselect);
}
}
void LightAnimationPropertyEditor::onEditClicked()
{
// First, check if there is any light animation defined.
bool bLightAnimationExists = false;
IMovieSystem *pMovieSystem = GetIEditor()->GetMovieSystem();
for (int i = 0; i < pMovieSystem->GetNumSequences(); ++i)
{
IAnimSequence *pSequence = pMovieSystem->GetSequence(i);
if (pSequence->GetFlags() & IAnimSequence::eSeqFlags_LightAnimationSet)
{
bLightAnimationExists = pSequence->GetNodeCount() > 0;
break;
}
}
if (bLightAnimationExists) // If exists, show the selection dialog.
{
CSelectLightAnimationDialog dlg;
dlg.PreSelectItem(GetValue());
if (dlg.exec() == QDialog::Accepted)
SetValue(dlg.GetSelectedItem());
}
else // If not, remind the user of creating one in TrackView.
{
QMessageBox::warning(this, tr("No Available Animation"), tr("There is no available light animation.\nPlease create one in TrackView, first."));
}
}
ListEditWidget::ListEditWidget(QWidget *pParent /*= nullptr*/)
:QWidget(pParent)
{
m_valueEdit = new QLineEdit;
m_model = new QStringListModel(this);
m_listView = new QListView;
m_listView->setModel(m_model);
m_listView->setMaximumHeight(50);
m_listView->setVisible(false);
QToolButton *expandButton = new QToolButton();
expandButton->setCheckable(true);
expandButton->setText("+");
QToolButton *editButton = new QToolButton();
editButton->setText("..");
connect(editButton, &QAbstractButton::clicked, this, &ListEditWidget::OnEditClicked);
connect(expandButton, &QAbstractButton::toggled, m_listView, &QWidget::setVisible);
connect(m_model, &QAbstractItemModel::dataChanged, this, &ListEditWidget::OnModelDataChange);
connect(m_valueEdit, &QLineEdit::editingFinished, this, [this](){SetValue(m_valueEdit->text(), true); } );
QVBoxLayout *mainLayout = new QVBoxLayout(this);
QHBoxLayout *topLayout = new QHBoxLayout;
topLayout->addWidget(expandButton);
topLayout->addWidget(m_valueEdit,1);
topLayout->addWidget(editButton);
mainLayout->addLayout(topLayout);
mainLayout->addWidget(m_listView,1);
mainLayout->setContentsMargins(1,1,1,1);
}
void ListEditWidget::SetValue(const QString &value, bool notify /*= true*/)
{
if (m_value != value)
{
m_value = value;
m_valueEdit->setText(value);
QStringList list = m_value.split(",", Qt::SkipEmptyParts);
m_model->setStringList(list);
if (notify)
emit ValueChanged(m_value);
}
}
void ListEditWidget::OnModelDataChange()
{
m_value = m_model->stringList().join(",");
m_valueEdit->setText(m_value);
emit ValueChanged(m_value);
}
QWidget* ListEditWidget::GetFirstInTabOrder()
{
return m_valueEdit;
}
QWidget* ListEditWidget::GetLastInTabOrder()
{
return m_listView;
}
#include <Controls/ReflectedPropertyControl/moc_PropertyGenericCtrl.cpp>
@@ -0,0 +1,232 @@
/*
* Copyright (c) Contributors to the Open 3D Engine Project
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#ifndef CRYINCLUDE_EDITOR_UTILS_PROPERTYGENERICCTRL_H
#define CRYINCLUDE_EDITOR_UTILS_PROPERTYGENERICCTRL_H
#pragma once
#if !defined(Q_MOC_RUN)
#include <AzCore/base.h>
#include <AzCore/Memory/SystemAllocator.h>
#include <AzToolsFramework/UI/PropertyEditor/PropertyEditorAPI.h>
#include "ReflectedVar.h"
#include "Util/VariablePropertyType.h"
#include <QWidget>
#endif
class QStringListModel;
class QListView;
class QLabel;
class QLineEdit;
class GenericPopupPropertyEditor
: public QWidget
{
Q_OBJECT
public:
AZ_CLASS_ALLOCATOR(GenericPopupPropertyEditor, AZ::SystemAllocator, 0);
GenericPopupPropertyEditor(QWidget* pParent = nullptr, bool showTwoButtons = false);
void SetValue(const QString& value, bool notify = true);
QString GetValue() const { return m_value; }
void SetPropertyType(PropertyType type);
PropertyType GetPropertyType() const { return m_propertyType; }
//override in derived classes to show appropriate editor
virtual void onEditClicked() {};
virtual void onButton2Clicked() {};
signals:
void ValueChanged(const QString& value);
private:
QLabel* m_valueLabel;
PropertyType m_propertyType;
QString m_value;
};
template <class T, AZ::u32 CRC>
class GenericPopupWidgetHandler
: public QObject
, public AzToolsFramework::PropertyHandler < CReflectedVarGenericProperty, GenericPopupPropertyEditor >
{
public:
AZ_CLASS_ALLOCATOR(GenericPopupWidgetHandler, AZ::SystemAllocator, 0);
virtual bool IsDefaultHandler() const override { return false; }
virtual AZ::u32 GetHandlerName(void) const override { return CRC; }
virtual QWidget* CreateGUI(QWidget* pParent) override
{
GenericPopupPropertyEditor* newCtrl = aznew T(pParent);
connect(newCtrl, &GenericPopupPropertyEditor::ValueChanged, newCtrl, [newCtrl]()
{
EBUS_EVENT(AzToolsFramework::PropertyEditorGUIMessages::Bus, RequestWrite, newCtrl);
});
return newCtrl;
}
virtual void ConsumeAttribute(GenericPopupPropertyEditor* GUI, AZ::u32 attrib, AzToolsFramework::PropertyAttributeReader* attrValue, const char* debugName) override
{
Q_UNUSED(GUI);
Q_UNUSED(attrib);
Q_UNUSED(attrValue);
Q_UNUSED(debugName);
}
virtual void WriteGUIValuesIntoProperty(size_t index, GenericPopupPropertyEditor* GUI, property_t& instance, AzToolsFramework::InstanceDataNode* node) override
{
Q_UNUSED(index);
Q_UNUSED(node);
CReflectedVarGenericProperty val = instance;
val.m_propertyType = GUI->GetPropertyType();
val.m_value = GUI->GetValue().toUtf8().data();
instance = static_cast<property_t>(val);
}
virtual bool ReadValuesIntoGUI(size_t index, GenericPopupPropertyEditor* GUI, const property_t& instance, AzToolsFramework::InstanceDataNode* node) override
{
Q_UNUSED(index);
Q_UNUSED(node);
CReflectedVarGenericProperty val = instance;
GUI->SetPropertyType(val.m_propertyType);
GUI->SetValue(val.m_value.c_str(), false);
return false;
}
};
class ReverbPresetPropertyEditor
: public GenericPopupPropertyEditor
{
public:
ReverbPresetPropertyEditor(QWidget* pParent = nullptr)
: GenericPopupPropertyEditor(pParent){}
void onEditClicked() override;
};
class MissionObjPropertyEditor
: public GenericPopupPropertyEditor
{
public:
MissionObjPropertyEditor(QWidget* pParent = nullptr)
: GenericPopupPropertyEditor(pParent){}
void onEditClicked() override;
};
class SequencePropertyEditor
: public GenericPopupPropertyEditor
{
public:
SequencePropertyEditor(QWidget* pParent = nullptr)
: GenericPopupPropertyEditor(pParent){}
void onEditClicked() override;
};
class SequenceIdPropertyEditor
: public GenericPopupPropertyEditor
{
public:
SequenceIdPropertyEditor(QWidget* pParent = nullptr)
: GenericPopupPropertyEditor(pParent){}
void onEditClicked() override;
};
class LocalStringPropertyEditor
: public GenericPopupPropertyEditor
{
public:
LocalStringPropertyEditor(QWidget* pParent = nullptr)
: GenericPopupPropertyEditor(pParent){}
void onEditClicked() override;
};
class LightAnimationPropertyEditor
: public GenericPopupPropertyEditor
{
public:
LightAnimationPropertyEditor(QWidget* pParent = nullptr)
: GenericPopupPropertyEditor(pParent){}
void onEditClicked() override;
};
// AZ_CRC changed recently - it used to be evaluated by the preprocessor to AZ::u32(value); now it evaluates to Az::Crc32, and can't be used as a const template parameter
// So we use our own
#define CONST_AZ_CRC(name, value) AZ::u32(value)
using ReverbPresetPropertyHandler = GenericPopupWidgetHandler<ReverbPresetPropertyEditor, CONST_AZ_CRC("ePropertyReverbPreset", 0x51469f38)>;
using MissionObjPropertyHandler = GenericPopupWidgetHandler<MissionObjPropertyEditor, CONST_AZ_CRC("ePropertyMissionObj", 0x4a2d0dc8)>;
using SequencePropertyHandler = GenericPopupWidgetHandler<SequencePropertyEditor, CONST_AZ_CRC("ePropertySequence", 0xdd1c7d44)>;
using SequenceIdPropertyHandler = GenericPopupWidgetHandler<SequenceIdPropertyEditor, CONST_AZ_CRC("ePropertySequenceId", 0x05983dcc)>;
using LocalStringPropertyHandler = GenericPopupWidgetHandler<LocalStringPropertyEditor, CONST_AZ_CRC("ePropertyLocalString", 0x0cd9609a)>;
using LightAnimationPropertyHandler = GenericPopupWidgetHandler<LightAnimationPropertyEditor, CONST_AZ_CRC("ePropertyLightAnimation", 0x277097da)>;
class ListEditWidget : public QWidget
{
Q_OBJECT
public:
AZ_CLASS_ALLOCATOR(ListEditWidget, AZ::SystemAllocator, 0);
ListEditWidget(QWidget *pParent = nullptr);
void SetValue(const QString &value, bool notify = true);
QString GetValue() const { return m_value; }
QWidget* GetFirstInTabOrder();
QWidget* GetLastInTabOrder();
signals:
void ValueChanged(const QString &value);
private:
void OnModelDataChange();
virtual void OnEditClicked() {};
protected:
QLineEdit *m_valueEdit;
QString m_value;
QListView *m_listView;
QStringListModel *m_model;
};
template <class T, AZ::u32 CRC>
class ListEditWidgetHandler : public QObject, public AzToolsFramework::PropertyHandler < CReflectedVarGenericProperty, ListEditWidget >
{
public:
AZ_CLASS_ALLOCATOR(ListEditWidgetHandler, AZ::SystemAllocator, 0);
virtual bool IsDefaultHandler() const override { return false; }
virtual AZ::u32 GetHandlerName(void) const override { return CRC; }
virtual QWidget* CreateGUI(QWidget *pParent) override
{
ListEditWidget* newCtrl = aznew T(pParent);
connect(newCtrl, &ListEditWidget::ValueChanged, newCtrl, [newCtrl]()
{
EBUS_EVENT(AzToolsFramework::PropertyEditorGUIMessages::Bus, RequestWrite, newCtrl);
});
return newCtrl;
}
virtual void ConsumeAttribute(ListEditWidget* GUI, AZ::u32 attrib, AzToolsFramework::PropertyAttributeReader* attrValue, const char* debugName) override {
Q_UNUSED(GUI); Q_UNUSED(attrib); Q_UNUSED(attrValue); Q_UNUSED(debugName);
}
virtual void WriteGUIValuesIntoProperty(size_t index, ListEditWidget* GUI, property_t& instance, AzToolsFramework::InstanceDataNode* node) override
{
Q_UNUSED(index);
Q_UNUSED(node);
CReflectedVarGenericProperty val = instance;
val.m_value = GUI->GetValue().toUtf8().data();
instance = static_cast<property_t>(val);
}
virtual bool ReadValuesIntoGUI(size_t index, ListEditWidget* GUI, const property_t& instance, AzToolsFramework::InstanceDataNode* node) override
{
Q_UNUSED(index);
Q_UNUSED(node);
CReflectedVarGenericProperty val = instance;
GUI->SetValue(val.m_value.c_str(), false);
return false;
}
QWidget* GetFirstInTabOrder(ListEditWidget* widget) override { return widget->GetFirstInTabOrder(); }
QWidget* GetLastInTabOrder(ListEditWidget* widget) override {return widget->GetLastInTabOrder(); }
};
#endif // CRYINCLUDE_EDITOR_UTILS_PROPERTYGENERICCTRL_H
@@ -0,0 +1,198 @@
/*
* Copyright (c) Contributors to the Open 3D Engine Project
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#include "EditorDefs.h"
#include "PropertyMiscCtrl.h"
// Qt
#include <QHBoxLayout>
#include <QtWidgets/QLabel>
#include <QLineEdit>
#include <QtWidgets/QToolButton>
#include <QtCore/QTimer>
#include <QtUtilWin.h>
// Editor
#include "GenericSelectItemDialog.h"
#include "QtViewPaneManager.h"
UserPropertyEditor::UserPropertyEditor(QWidget *pParent /*= nullptr*/)
: QWidget(pParent)
, m_canEdit(false)
, m_useTree(false)
{
m_valueLabel = new QLabel;
QToolButton *mainButton = new QToolButton;
mainButton->setText("..");
connect(mainButton, &QToolButton::clicked, this, &UserPropertyEditor::onEditClicked);
QHBoxLayout *mainLayout = new QHBoxLayout(this);
mainLayout->addWidget(m_valueLabel, 1);
mainLayout->addWidget(mainButton);
mainLayout->setContentsMargins(1, 1, 1, 1);
}
void UserPropertyEditor::SetValue(const QString &value, bool notify /*= true*/)
{
if (m_value != value)
{
m_value = value;
m_valueLabel->setText(m_value);
if (notify)
{
emit ValueChanged(m_value);
}
}
}
void UserPropertyEditor::SetData(bool canEdit, bool useTree, const QString &treeSeparator, const QString &dialogTitle, const std::vector<IVariable::IGetCustomItems::SItem>& items)
{
m_canEdit = canEdit;
m_useTree = useTree;
m_treeSeparator = treeSeparator;
m_dialogTitle = dialogTitle;
m_items = items;
}
void UserPropertyEditor::onEditClicked()
{
// call the user supplied callback to fill-in items and get dialog title
emit RefreshItems();
if (m_canEdit) // if func didn't veto, show the dialog
{
CGenericSelectItemDialog gtDlg;
if (m_useTree)
{
gtDlg.SetMode(CGenericSelectItemDialog::eMODE_TREE);
if (!m_treeSeparator.isEmpty())
{
gtDlg.SetTreeSeparator(m_treeSeparator);
}
}
gtDlg.SetItems(m_items);
if (m_dialogTitle.isEmpty() == false)
gtDlg.setWindowTitle(m_dialogTitle);
gtDlg.PreSelectItem(GetValue());
if (gtDlg.exec() == QDialog::Accepted)
{
QString selectedItemStr = gtDlg.GetSelectedItem();
if (selectedItemStr.isEmpty() == false)
{
SetValue(selectedItemStr);
}
}
}
}
QWidget* UserPopupWidgetHandler::CreateGUI(QWidget *pParent)
{
UserPropertyEditor* newCtrl = aznew UserPropertyEditor(pParent);
connect(newCtrl, &UserPropertyEditor::ValueChanged, newCtrl, [newCtrl]()
{
EBUS_EVENT(AzToolsFramework::PropertyEditorGUIMessages::Bus, RequestWrite, newCtrl);
});
return newCtrl;
}
void UserPopupWidgetHandler::ConsumeAttribute(UserPropertyEditor* GUI, AZ::u32 attrib, AzToolsFramework::PropertyAttributeReader* attrValue, const char* debugName)
{
Q_UNUSED(GUI);
Q_UNUSED(attrib);
Q_UNUSED(attrValue);
Q_UNUSED(debugName);
}
void UserPopupWidgetHandler::WriteGUIValuesIntoProperty(size_t index, UserPropertyEditor* GUI, property_t& instance, AzToolsFramework::InstanceDataNode* node)
{
Q_UNUSED(index);
Q_UNUSED(node);
CReflectedVarUser val = instance;
val.m_value = GUI->GetValue().toUtf8().data();
instance = static_cast<property_t>(val);
}
bool UserPopupWidgetHandler::ReadValuesIntoGUI(size_t index, UserPropertyEditor* GUI, const property_t& instance, AzToolsFramework::InstanceDataNode* node)
{
Q_UNUSED(index);
Q_UNUSED(node);
CReflectedVarUser val = instance;
assert(val.m_itemNames.size() == val.m_itemDescriptions.size());
std::vector<IVariable::IGetCustomItems::SItem> items(val.m_itemNames.size());
int i = -1;
std::generate(items.begin(), items.end(), [&val, &i]() { ++i; return IVariable::IGetCustomItems::SItem(val.m_itemNames[i].c_str(), val.m_itemDescriptions[i].c_str());});
GUI->SetData(val.m_enableEdit, val.m_useTree, val.m_treeSeparator.c_str(), val.m_dialogTitle.c_str(), items);
GUI->SetValue(val.m_value.c_str(), false);
return false;
}
#include <Controls/ReflectedPropertyControl/moc_PropertyMiscCtrl.cpp>
QWidget* FloatCurveHandler::CreateGUI(QWidget *pParent)
{
CSplineCtrl *cSpline = new CSplineCtrl(pParent);
cSpline->SetUpdateCallback(AZStd::bind(&FloatCurveHandler::OnSplineChange, this, AZStd::placeholders::_1));
cSpline->SetTimeRange(0, 1);
cSpline->SetValueRange(0, 1);
cSpline->SetGrid(12, 12);
cSpline->setFixedHeight(52);
return cSpline;
}
void FloatCurveHandler::OnSplineChange(CSplineCtrl*)
{
// EBUS_EVENT(AzToolsFramework::PropertyEditorGUIMessages::Bus, RequestWrite, splineWidget);
}
void FloatCurveHandler::ConsumeAttribute(CSplineCtrl *, AZ::u32, AzToolsFramework::PropertyAttributeReader*, const char*)
{}
void FloatCurveHandler::WriteGUIValuesIntoProperty([[maybe_unused]] size_t index, [[maybe_unused]] CSplineCtrl* GUI, [[maybe_unused]] property_t& instance, [[maybe_unused]] AzToolsFramework::InstanceDataNode* node)
{
//nothing to do here. the spline itself will have it's new values.
}
bool FloatCurveHandler::ReadValuesIntoGUI([[maybe_unused]] size_t index, CSplineCtrl* GUI, const property_t& instance, [[maybe_unused]] AzToolsFramework::InstanceDataNode* node)
{
GUI->SetSpline(reinterpret_cast<ISplineInterpolator*>(instance.m_spline));
return false;
}
QWidget* ColorCurveHandler::CreateGUI(QWidget *pParent)
{
CColorGradientCtrl* gradientCtrl = new CColorGradientCtrl(pParent);
//connect(gradientCtrl, &CColorGradientCtrl::change, [gradientCtrl]()
//{
// EBUS_EVENT(AzToolsFramework::PropertyEditorGUIMessages::Bus, RequestWrite, gradientCtrl);
//});
gradientCtrl->SetTimeRange(0, 1);
gradientCtrl->setFixedHeight(36);
return gradientCtrl;
}
void ColorCurveHandler::ConsumeAttribute(CColorGradientCtrl*, AZ::u32, AzToolsFramework::PropertyAttributeReader*, const char*)
{}
void ColorCurveHandler::WriteGUIValuesIntoProperty([[maybe_unused]] size_t index, [[maybe_unused]] CColorGradientCtrl* GUI, [[maybe_unused]] property_t& instance, [[maybe_unused]] AzToolsFramework::InstanceDataNode* node)
{}
bool ColorCurveHandler::ReadValuesIntoGUI([[maybe_unused]] size_t index, CColorGradientCtrl* GUI, const property_t& instance, [[maybe_unused]] AzToolsFramework::InstanceDataNode* node)
{
GUI->SetSpline(reinterpret_cast<ISplineInterpolator*>(instance.m_spline));
return false;
}
@@ -0,0 +1,97 @@
/*
* Copyright (c) Contributors to the Open 3D Engine Project
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#ifndef CRYINCLUDE_EDITOR_UTILS_PROPERTYMISCCTRL_H
#define CRYINCLUDE_EDITOR_UTILS_PROPERTYMISCCTRL_H
#pragma once
#if !defined(Q_MOC_RUN)
#include <AzCore/base.h>
#include <AzCore/Memory/SystemAllocator.h>
#include <AzToolsFramework/UI/PropertyEditor/PropertyEditorAPI.h>
#include "ReflectedVar.h"
#include "Util/VariablePropertyType.h"
#include "Controls/ColorGradientCtrl.h"
#include "Controls/SplineCtrl.h"
#include <QWidget>
#endif
class QLabel;
class QLineEdit;
class UserPropertyEditor : public QWidget
{
Q_OBJECT
public:
AZ_CLASS_ALLOCATOR(UserPropertyEditor, AZ::SystemAllocator, 0);
UserPropertyEditor(QWidget *pParent = nullptr);
void SetValue(const QString &value, bool notify = true);
QString GetValue() const { return m_value; }
void SetData(bool canEdit, bool useTree, const QString &treeSeparator, const QString &dialogTitle, const std::vector<IVariable::IGetCustomItems::SItem>& items);
void onEditClicked();
signals:
void ValueChanged(const QString &value);
void RefreshItems();
private:
QLabel *m_valueLabel;
QString m_value;
bool m_canEdit;
bool m_useTree;
QString m_treeSeparator;
QString m_dialogTitle;
std::vector<IVariable::IGetCustomItems::SItem> m_items;
};
class UserPopupWidgetHandler : public QObject, public AzToolsFramework::PropertyHandler < CReflectedVarUser, UserPropertyEditor>
{
public:
AZ_CLASS_ALLOCATOR(UserPopupWidgetHandler, AZ::SystemAllocator, 0);
bool IsDefaultHandler() const override { return false; }
QWidget* CreateGUI(QWidget *pParent) override;
AZ::u32 GetHandlerName(void) const override {return AZ_CRC("ePropertyUser", 0x65b972c0); }
void ConsumeAttribute(UserPropertyEditor* GUI, AZ::u32 attrib, AzToolsFramework::PropertyAttributeReader* attrValue, const char* debugName) override;
void WriteGUIValuesIntoProperty(size_t index, UserPropertyEditor* GUI, property_t& instance, AzToolsFramework::InstanceDataNode* node) override;
bool ReadValuesIntoGUI(size_t index, UserPropertyEditor* GUI, const property_t& instance, AzToolsFramework::InstanceDataNode* node) override;
};
class FloatCurveHandler : public QObject, public AzToolsFramework::PropertyHandler < CReflectedVarSpline, CSplineCtrl>
{
public:
AZ_CLASS_ALLOCATOR(FloatCurveHandler, AZ::SystemAllocator, 0);
bool IsDefaultHandler() const override { return false; }
QWidget* CreateGUI(QWidget *pParent) override;
AZ::u32 GetHandlerName(void) const override { return AZ_CRC("ePropertyFloatCurve", 0x7440ccce); }
void ConsumeAttribute(CSplineCtrl* GUI, AZ::u32 attrib, AzToolsFramework::PropertyAttributeReader* attrValue, const char* debugName) override;
void WriteGUIValuesIntoProperty(size_t index, CSplineCtrl* GUI, property_t& instance, AzToolsFramework::InstanceDataNode* node) override;
bool ReadValuesIntoGUI(size_t index, CSplineCtrl* GUI, const property_t& instance, AzToolsFramework::InstanceDataNode* node) override;
void OnSplineChange(CSplineCtrl*);
};
class ColorCurveHandler : public QObject, public AzToolsFramework::PropertyHandler < CReflectedVarSpline, CColorGradientCtrl>
{
public:
AZ_CLASS_ALLOCATOR(ColorCurveHandler, AZ::SystemAllocator, 0);
bool IsDefaultHandler() const override { return false; }
QWidget* CreateGUI(QWidget *pParent) override;
AZ::u32 GetHandlerName(void) const override { return AZ_CRC("ePropertyColorCurve", 0xa30da4ec); }
void ConsumeAttribute(CColorGradientCtrl* GUI, AZ::u32 attrib, AzToolsFramework::PropertyAttributeReader* attrValue, const char* debugName) override;
void WriteGUIValuesIntoProperty(size_t index, CColorGradientCtrl* GUI, property_t& instance, AzToolsFramework::InstanceDataNode* node) override;
bool ReadValuesIntoGUI(size_t index, CColorGradientCtrl* GUI, const property_t& instance, AzToolsFramework::InstanceDataNode* node) override;
};
#endif // CRYINCLUDE_EDITOR_UTILS_PROPERTYMISCCTRL_H
@@ -0,0 +1,59 @@
/*
* Copyright (c) Contributors to the Open 3D Engine Project
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#include "EditorDefs.h"
#include "PropertyMotionCtrl.h"
// AzToolsFramework
#include <AzToolsFramework/API/ToolsApplicationAPI.h>
#include <AzToolsFramework/AssetBrowser/AssetSelectionModel.h>
QWidget* MotionPropertyWidgetHandler::CreateGUI(QWidget* pParent)
{
AzToolsFramework::PropertyAssetCtrl* newCtrl = aznew AzToolsFramework::PropertyAssetCtrl(pParent);
connect(
newCtrl, &AzToolsFramework::PropertyAssetCtrl::OnAssetIDChanged, this, [newCtrl]([[maybe_unused]] AZ::Data::AssetId newAssetId) {
EBUS_EVENT(AzToolsFramework::PropertyEditorGUIMessages::Bus, RequestWrite, newCtrl);
AzToolsFramework::PropertyEditorGUIMessages::Bus::Broadcast(
&AzToolsFramework::PropertyEditorGUIMessages::Bus::Handler::OnEditingFinished, newCtrl);
});
return newCtrl;
}
void MotionPropertyWidgetHandler::ConsumeAttribute(
[[maybe_unused]] AzToolsFramework::PropertyAssetCtrl* GUI, [[maybe_unused]] AZ::u32 attrib,
[[maybe_unused]] AzToolsFramework::PropertyAttributeReader* attrValue, [[maybe_unused]] const char* debugName)
{
}
void MotionPropertyWidgetHandler::WriteGUIValuesIntoProperty(
[[maybe_unused]] size_t index, [[maybe_unused]] AzToolsFramework::PropertyAssetCtrl* GUI, property_t& instance,
[[maybe_unused]] AzToolsFramework::InstanceDataNode* node)
{
CReflectedVarMotion val;
val.m_motion = GUI->GetCurrentAssetHint();
val.m_assetId = GUI->GetSelectedAssetID();
instance = static_cast<property_t>(val);
}
bool MotionPropertyWidgetHandler::ReadValuesIntoGUI(
[[maybe_unused]] size_t index, [[maybe_unused]] AzToolsFramework::PropertyAssetCtrl* GUI, const property_t& instance,
[[maybe_unused]] AzToolsFramework::InstanceDataNode* node)
{
static const AZ::Data::AssetType emotionFXMotionAssetType(
"{00494B8E-7578-4BA2-8B28-272E90680787}"); // from MotionAsset.h in EMotionFX Gem
GUI->blockSignals(true);
GUI->SetSelectedAssetID(instance.m_assetId);
GUI->SetCurrentAssetType(emotionFXMotionAssetType);
GUI->blockSignals(false);
return false;
}
#include <Controls/ReflectedPropertyControl/moc_PropertyMotionCtrl.cpp>
@@ -0,0 +1,62 @@
/*
* Copyright (c) Contributors to the Open 3D Engine Project
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#pragma once
#if !defined(Q_MOC_RUN)
#include "ReflectedVar.h"
#include <AzCore/Memory/SystemAllocator.h>
#include <AzCore/base.h>
#include <AzToolsFramework/UI/PropertyEditor/PropertyAssetCtrl.hxx>
#include <AzToolsFramework/UI/PropertyEditor/PropertyEditorAPI.h>
#include <QPointer>
#include <QWidget>
#endif
class MotionPropertyWidgetHandler : QObject,
public AzToolsFramework::PropertyHandler<CReflectedVarMotion, AzToolsFramework::PropertyAssetCtrl>
{
Q_OBJECT
public:
AZ_CLASS_ALLOCATOR(MotionPropertyWidgetHandler, AZ::SystemAllocator, 0);
virtual AZ::u32 GetHandlerName(void) const override
{
return AZ_CRC("Motion", 0xf5fea1e8);
}
virtual bool IsDefaultHandler() const override
{
return true;
}
virtual QWidget* GetFirstInTabOrder(AzToolsFramework::PropertyAssetCtrl* widget) override
{
return widget->GetFirstInTabOrder();
}
virtual QWidget* GetLastInTabOrder(AzToolsFramework::PropertyAssetCtrl* widget) override
{
return widget->GetLastInTabOrder();
}
virtual void UpdateWidgetInternalTabbing(AzToolsFramework::PropertyAssetCtrl* widget) override
{
widget->UpdateTabOrder();
}
virtual QWidget* CreateGUI(QWidget* pParent) override;
virtual void ConsumeAttribute(
AzToolsFramework::PropertyAssetCtrl* GUI, AZ::u32 attrib, AzToolsFramework::PropertyAttributeReader* attrValue,
const char* debugName) override;
virtual void WriteGUIValuesIntoProperty(
size_t index, AzToolsFramework::PropertyAssetCtrl* GUI, property_t& instance, AzToolsFramework::InstanceDataNode* node) override;
virtual bool ReadValuesIntoGUI(
size_t index, AzToolsFramework::PropertyAssetCtrl* GUI, const property_t& instance,
AzToolsFramework::InstanceDataNode* node) override;
};
@@ -0,0 +1,392 @@
/*
* Copyright (c) Contributors to the Open 3D Engine Project
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#include "EditorDefs.h"
#include "PropertyResourceCtrl.h"
// Qt
#include <QHBoxLayout>
#include <QLineEdit>
// AzToolsFramework
#include <AzToolsFramework/AssetBrowser/AssetSelectionModel.h>
#include <AzToolsFramework/API/ToolsApplicationAPI.h>
// Editor
#include "IResourceSelectorHost.h"
#include "Controls/QToolTipWidget.h"
#include "Controls/BitmapToolTip.h"
BrowseButton::BrowseButton(PropertyType type, QWidget* parent /*= nullptr*/)
: QToolButton(parent)
, m_propertyType(type)
{
setAutoRaise(true);
setIcon(QIcon(QStringLiteral(":/stylesheet/img/UI20/browse-edit.svg")));
connect(this, &QAbstractButton::clicked, this, &BrowseButton::OnClicked);
}
void BrowseButton::SetPathAndEmit(const QString& path)
{
//only emit if path changes, except for ePropertyGeomCache. Old property control
if (path != m_path || m_propertyType == ePropertyGeomCache)
{
m_path = path;
emit PathChanged(m_path);
}
}
class FileBrowseButton
: public BrowseButton
{
public:
AZ_CLASS_ALLOCATOR(FileBrowseButton, AZ::SystemAllocator, 0);
FileBrowseButton(PropertyType type, QWidget* pParent = nullptr)
: BrowseButton(type, pParent)
{
setToolTip("Browse...");
}
private:
void OnClicked() override
{
QString tempValue("");
QString ext("");
if (m_path.isEmpty() == false)
{
if (Path::GetExt(m_path) == "")
{
tempValue = "";
}
else
{
tempValue = m_path;
}
}
AssetSelectionModel selection;
if (m_propertyType == ePropertyTexture)
{
// Filters for texture.
selection = AssetSelectionModel::AssetGroupSelection("Texture");
}
else if (m_propertyType == ePropertyModel)
{
// Filters for models.
selection = AssetSelectionModel::AssetGroupSelection("Geometry");
}
else if (m_propertyType == ePropertyGeomCache)
{
// Filters for geom caches.
selection = AssetSelectionModel::AssetTypeSelection("Geom Cache");
}
else if (m_propertyType == ePropertyFile)
{
// Filters for files.
selection = AssetSelectionModel::AssetTypeSelection("File");
}
else
{
return;
}
AzToolsFramework::EditorRequests::Bus::Broadcast(&AzToolsFramework::EditorRequests::BrowseForAssets, selection);
if (selection.IsValid())
{
QString newPath = Path::FullPathToGamePath(selection.GetResult()->GetFullPath().c_str()).c_str();
switch (m_propertyType)
{
case ePropertyTexture:
case ePropertyModel:
newPath.replace("\\\\", "/");
}
switch (m_propertyType)
{
case ePropertyTexture:
case ePropertyModel:
case ePropertyFile:
if (newPath.size() > MAX_PATH)
{
newPath.resize(MAX_PATH);
}
}
SetPathAndEmit(newPath);
}
}
};
class ResourceSelectorButton
: public BrowseButton
{
public:
AZ_CLASS_ALLOCATOR(ResourceSelectorButton, AZ::SystemAllocator, 0);
ResourceSelectorButton(PropertyType type, QWidget* pParent = nullptr)
: BrowseButton(type, pParent)
{
setToolTip(tr("Select resource"));
}
private:
void OnClicked() override
{
SResourceSelectorContext x;
x.parentWidget = this;
x.typeName = Prop::GetPropertyTypeToResourceType(m_propertyType);
QString newPath = GetIEditor()->GetResourceSelectorHost()->SelectResource(x, m_path);
SetPathAndEmit(newPath);
}
};
class TextureEditButton
: public BrowseButton
{
public:
AZ_CLASS_ALLOCATOR(TextureEditButton, AZ::SystemAllocator, 0);
TextureEditButton(QWidget* pParent = nullptr)
: BrowseButton(ePropertyTexture, pParent)
{
setIcon(QIcon(QStringLiteral(":/stylesheet/img/UI20/open-in-internal-app.svg")));
setToolTip(tr("Launch default editor"));
}
private:
void OnClicked() override
{
CFileUtil::EditTextureFile(m_path.toUtf8().data(), true);
}
};
FileResourceSelectorWidget::FileResourceSelectorWidget(QWidget* pParent /*= nullptr*/)
: QWidget(pParent)
, m_propertyType(ePropertyInvalid)
, m_tooltip(nullptr)
{
m_pathEdit = new QLineEdit;
m_mainLayout = new QHBoxLayout(this);
m_mainLayout->addWidget(m_pathEdit, 1);
m_mainLayout->setContentsMargins(0, 0, 0, 0);
// KDAB just ported the MFC texture preview tooltip, but looks like Amazon added their own. Not sure which to use.
// To switch to Amazon QToolTipWidget, remove FileResourceSelectorWidget::event and m_previewTooltip
#ifdef USE_QTOOLTIPWIDGET
m_tooltip = new QToolTipWidget(this);
installEventFilter(this);
#endif
connect(m_pathEdit, &QLineEdit::editingFinished, this, [this]() { OnPathChanged(m_pathEdit->text()); });
}
bool FileResourceSelectorWidget::eventFilter([[maybe_unused]] QObject* obj, QEvent* event)
{
if (m_propertyType == ePropertyTexture)
{
if (event->type() == QEvent::ToolTip)
{
QHelpEvent* e = (QHelpEvent*)event;
m_tooltip->AddSpecialContent("TEXTURE", m_path);
m_tooltip->TryDisplay(e->globalPos(), m_pathEdit, QToolTipWidget::ArrowDirection::ARROW_RIGHT);
return true;
}
if (event->type() == QEvent::Leave)
{
m_tooltip->hide();
}
}
return false;
}
void FileResourceSelectorWidget::SetPropertyType(PropertyType type)
{
if (m_propertyType == type)
{
return;
}
//if the property type changed for some reason, delete all the existing widgets
if (!m_buttons.isEmpty())
{
qDeleteAll(m_buttons.begin(), m_buttons.end());
m_buttons.clear();
}
m_previewToolTip.reset();
m_propertyType = type;
switch (type)
{
case ePropertyTexture:
AddButton(new FileBrowseButton(type));
AddButton(new TextureEditButton);
m_previewToolTip.reset(new CBitmapToolTip);
break;
case ePropertyModel:
case ePropertyGeomCache:
case ePropertyAudioTrigger:
case ePropertyAudioSwitch:
case ePropertyAudioSwitchState:
case ePropertyAudioRTPC:
case ePropertyAudioEnvironment:
case ePropertyAudioPreloadRequest:
AddButton(new ResourceSelectorButton(type));
break;
case ePropertyFile:
AddButton(new FileBrowseButton(type));
break;
default:
break;
}
m_mainLayout->invalidate();
}
void FileResourceSelectorWidget::AddButton(BrowseButton* button)
{
m_mainLayout->addWidget(button);
m_buttons.push_back(button);
connect(button, &BrowseButton::PathChanged, this, &FileResourceSelectorWidget::OnPathChanged);
}
void FileResourceSelectorWidget::OnPathChanged(const QString& path)
{
bool changed = SetPath(path);
if (changed)
{
emit PathChanged(m_path);
}
}
bool FileResourceSelectorWidget::SetPath(const QString& path)
{
bool changed = false;
const QString newPath = path.toLower();
if (m_path != newPath)
{
m_path = newPath;
UpdateWidgets();
changed = true;
}
return changed;
}
void FileResourceSelectorWidget::UpdateWidgets()
{
m_pathEdit->setText(m_path);
foreach(BrowseButton * button, m_buttons)
{
button->SetPath(m_path);
}
if (m_previewToolTip)
{
m_previewToolTip->SetTool(this, rect());
}
}
QString FileResourceSelectorWidget::GetPath() const
{
return m_path;
}
QWidget* FileResourceSelectorWidget::GetLastInTabOrder()
{
return m_buttons.empty() ? nullptr : m_buttons.last();
}
QWidget* FileResourceSelectorWidget::GetFirstInTabOrder()
{
return m_buttons.empty() ? nullptr : m_buttons.first();
}
void FileResourceSelectorWidget::UpdateTabOrder()
{
if (m_buttons.count() >= 2)
{
for (int i = 0; i < m_buttons.count() - 1; ++i)
{
setTabOrder(m_buttons[i], m_buttons[i + 1]);
}
}
}
bool FileResourceSelectorWidget::event(QEvent* event)
{
if (event->type() == QEvent::ToolTip && m_previewToolTip && !m_previewToolTip->isVisible())
{
if (!m_path.isEmpty())
{
m_previewToolTip->LoadImage(m_path);
m_previewToolTip->setVisible(true);
}
event->accept();
return true;
}
if (event->type() == QEvent::Resize && m_previewToolTip)
{
m_previewToolTip->SetTool(this, rect());
}
return QWidget::event(event);
}
QWidget* FileResourceSelectorWidgetHandler::CreateGUI(QWidget* pParent)
{
FileResourceSelectorWidget* newCtrl = aznew FileResourceSelectorWidget(pParent);
connect(newCtrl, &FileResourceSelectorWidget::PathChanged, newCtrl, [newCtrl]()
{
EBUS_EVENT(AzToolsFramework::PropertyEditorGUIMessages::Bus, RequestWrite, newCtrl);
});
return newCtrl;
}
void FileResourceSelectorWidgetHandler::ConsumeAttribute(FileResourceSelectorWidget* GUI, AZ::u32 attrib, AzToolsFramework::PropertyAttributeReader* attrValue, const char* debugName)
{
Q_UNUSED(GUI);
Q_UNUSED(attrib);
Q_UNUSED(attrValue);
Q_UNUSED(debugName);
}
void FileResourceSelectorWidgetHandler::WriteGUIValuesIntoProperty(size_t index, FileResourceSelectorWidget* GUI, property_t& instance, AzToolsFramework::InstanceDataNode* node)
{
Q_UNUSED(index);
Q_UNUSED(node);
CReflectedVarResource val = instance;
val.m_propertyType = GUI->GetPropertyType();
val.m_path = GUI->GetPath().toUtf8().data();
instance = static_cast<property_t>(val);
}
bool FileResourceSelectorWidgetHandler::ReadValuesIntoGUI(size_t index, FileResourceSelectorWidget* GUI, const property_t& instance, AzToolsFramework::InstanceDataNode* node)
{
Q_UNUSED(index);
Q_UNUSED(node);
CReflectedVarResource val = instance;
GUI->SetPropertyType(val.m_propertyType);
GUI->SetPath(val.m_path.c_str());
return false;
}
#include <Controls/ReflectedPropertyControl/moc_PropertyResourceCtrl.cpp>
@@ -0,0 +1,116 @@
/*
* Copyright (c) Contributors to the Open 3D Engine Project
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#ifndef CRYINCLUDE_EDITOR_UTILS_PROPERTYRESOURCECTRL_H
#define CRYINCLUDE_EDITOR_UTILS_PROPERTYRESOURCECTRL_H
#pragma once
#if !defined(Q_MOC_RUN)
#include <AzCore/base.h>
#include <AzCore/Memory/SystemAllocator.h>
#include <AzToolsFramework/UI/PropertyEditor/PropertyEditorAPI.h>
#include "ReflectedVar.h"
#include "Util/VariablePropertyType.h"
#include <QWidget>
#include <QtWidgets/QToolButton>
#include <QtCore/QVector>
#endif
class QLineEdit;
class QHBoxLayout;
class CBitmapToolTip;
class QToolTipWidget;
class BrowseButton
: public QToolButton
{
Q_OBJECT
public:
AZ_CLASS_ALLOCATOR(BrowseButton, AZ::SystemAllocator, 0);
BrowseButton(PropertyType type, QWidget* parent = nullptr);
void SetPath(const QString& path) { m_path = path; }
QString GetPath() const { return m_path; }
PropertyType GetPropertyType() const {return m_propertyType; }
signals:
void PathChanged(const QString& path);
protected:
void SetPathAndEmit(const QString& path);
virtual void OnClicked() = 0;
PropertyType m_propertyType;
QString m_path;
};
class FileResourceSelectorWidget
: public QWidget
{
Q_OBJECT
public:
AZ_CLASS_ALLOCATOR(FileResourceSelectorWidget, AZ::SystemAllocator, 0);
FileResourceSelectorWidget(QWidget* pParent = nullptr);
bool SetPath(const QString& path);
QString GetPath() const;
void SetPropertyType(PropertyType type);
PropertyType GetPropertyType() const { return m_propertyType; }
QWidget* GetFirstInTabOrder();
QWidget* GetLastInTabOrder();
void UpdateTabOrder();
bool eventFilter(QObject* obj, QEvent* event) override;
signals:
void PathChanged(const QString& path);
protected:
bool event(QEvent* event) override;
private:
void OnAssignClicked();
void OnMaterialClicked();
void UpdateWidgets();
void AddButton(BrowseButton* button);
void OnPathChanged(const QString& path);
private:
QLineEdit* m_pathEdit;
PropertyType m_propertyType;
QString m_path;
QHBoxLayout* m_mainLayout;
QVector<BrowseButton*> m_buttons;
QScopedPointer<CBitmapToolTip> m_previewToolTip;
QToolTipWidget* m_tooltip;
};
class FileResourceSelectorWidgetHandler
: QObject
, public AzToolsFramework::PropertyHandler < CReflectedVarResource, FileResourceSelectorWidget >
{
public:
AZ_CLASS_ALLOCATOR(FileResourceSelectorWidgetHandler, AZ::SystemAllocator, 0);
virtual AZ::u32 GetHandlerName(void) const override { return AZ_CRC("Resource", 0xbc91f416); }
virtual bool IsDefaultHandler() const override { return true; }
virtual QWidget* GetFirstInTabOrder(FileResourceSelectorWidget* widget) override { return widget->GetFirstInTabOrder(); }
virtual QWidget* GetLastInTabOrder(FileResourceSelectorWidget* widget) override { return widget->GetLastInTabOrder(); }
virtual void UpdateWidgetInternalTabbing(FileResourceSelectorWidget* widget) override { widget->UpdateTabOrder(); }
virtual QWidget* CreateGUI(QWidget* pParent) override;
virtual void ConsumeAttribute(FileResourceSelectorWidget* GUI, AZ::u32 attrib, AzToolsFramework::PropertyAttributeReader* attrValue, const char* debugName) override;
virtual void WriteGUIValuesIntoProperty(size_t index, FileResourceSelectorWidget* GUI, property_t& instance, AzToolsFramework::InstanceDataNode* node) override;
virtual bool ReadValuesIntoGUI(size_t index, FileResourceSelectorWidget* GUI, const property_t& instance, AzToolsFramework::InstanceDataNode* node) override;
};
#endif // CRYINCLUDE_EDITOR_UTILS_PROPERTYRESOURCECTRL_H
@@ -0,0 +1,92 @@
/*
* Copyright (c) Contributors to the Open 3D Engine Project
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
// Description : implementation file
#include "EditorDefs.h"
#include "ReflectedPropertiesPanel.h"
/////////////////////////////////////////////////////////////////////////////
// ReflectedPropertiesPanel dialog
ReflectedPropertiesPanel::ReflectedPropertiesPanel(QWidget* pParent)
: ReflectedPropertyControl(pParent)
{
}
//////////////////////////////////////////////////////////////////////////
void ReflectedPropertiesPanel::DeleteVars()
{
ClearVarBlock();
m_updateCallbacks.clear();
m_varBlock = 0;
}
//////////////////////////////////////////////////////////////////////////
void ReflectedPropertiesPanel::SetVarBlock(class CVarBlock* vb, ReflectedPropertyControl::UpdateVarCallback* updCallback, const char* category)
{
assert(vb);
m_varBlock = vb;
RemoveAllItems();
m_varBlock = vb;
AddVarBlock(m_varBlock, category);
SetUpdateCallback(AZStd::bind(&ReflectedPropertiesPanel::OnPropertyChanged, this, AZStd::placeholders::_1));
// When new object set all previous callbacks freed.
m_updateCallbacks.clear();
if (updCallback)
{
stl::push_back_unique(m_updateCallbacks, updCallback);
}
}
//////////////////////////////////////////////////////////////////////////
void ReflectedPropertiesPanel::AddVars(CVarBlock* vb, ReflectedPropertyControl::UpdateVarCallback* updCallback, const char* category)
{
assert(vb);
bool bNewBlock = false;
// Make a clone of properties.
if (!m_varBlock)
{
RemoveAllItems();
m_varBlock = vb->Clone(true);
AddVarBlock(m_varBlock, category);
bNewBlock = true;
}
m_varBlock->Wire(vb);
if (bNewBlock)
{
SetUpdateCallback(AZStd::bind(&ReflectedPropertiesPanel::OnPropertyChanged, this, AZStd::placeholders::_1));
// When new object set all previous callbacks freed.
m_updateCallbacks.clear();
}
if (updCallback)
{
stl::push_back_unique(m_updateCallbacks, updCallback);
}
}
void ReflectedPropertiesPanel::OnPropertyChanged(IVariable* pVar)
{
std::list<ReflectedPropertyControl::UpdateVarCallback*>::iterator iter;
for (iter = m_updateCallbacks.begin(); iter != m_updateCallbacks.end(); ++iter)
{
(*iter)->operator()(pVar);
}
}
@@ -0,0 +1,45 @@
/*
* Copyright (c) Contributors to the Open 3D Engine Project
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#ifndef CRYINCLUDE_EDITOR_REFLECTEDPROPERTIESPANEL_H
#define CRYINCLUDE_EDITOR_REFLECTEDPROPERTIESPANEL_H
#pragma once
#include "Controls/ReflectedPropertyControl/ReflectedPropertyCtrl.h"
#include "Util/Variable.h"
/////////////////////////////////////////////////////////////////////////////
// ReflectedPropertiesPanel dialog
AZ_PUSH_DISABLE_DLL_EXPORT_BASECLASS_WARNING
//This class is a port of ReflectedPropertiesPanel to use the ReflectedPropertyControl
class SANDBOX_API ReflectedPropertiesPanel
: public ReflectedPropertyControl
{
AZ_POP_DISABLE_DLL_EXPORT_BASECLASS_WARNING
public:
ReflectedPropertiesPanel(QWidget* pParent = nullptr); // standard constructor
void DeleteVars();
void AddVars(class CVarBlock* vb, ReflectedPropertyControl::UpdateVarCallback* func = nullptr, const char* category = nullptr);
void SetVarBlock(class CVarBlock* vb, ReflectedPropertyControl::UpdateVarCallback* func = nullptr, const char* category = nullptr);
protected:
void OnPropertyChanged(IVariable* pVar);
protected:
AZ_PUSH_DISABLE_DLL_EXPORT_MEMBER_WARNING
TSmartPtr<CVarBlock> m_varBlock;
std::list<ReflectedPropertyControl::UpdateVarCallback*> m_updateCallbacks;
AZ_POP_DISABLE_DLL_EXPORT_MEMBER_WARNING
};
#endif // CRYINCLUDE_EDITOR_REFLECTEDPROPERTIESPANEL_H
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,375 @@
/*
* Copyright (c) Contributors to the Open 3D Engine Project
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#ifndef CRYINCLUDE_EDITOR_UTILS_REFLECTEDPROPERTYCTRL_H
#define CRYINCLUDE_EDITOR_UTILS_REFLECTEDPROPERTYCTRL_H
#pragma once
#if !defined(Q_MOC_RUN)
#include <AzToolsFramework/UI/PropertyEditor/PropertyEditorAPI.h>
#include <AzCore/Serialization/SerializeContext.h>
#include <AzCore/std/smart_ptr/unique_ptr.h>
#include "Include/EditorCoreAPI.h"
#include "ReflectedPropertyItem.h"
#include "ReflectedVar.h"
#include <QFrame>
#endif
class QLineEdit;
class QLabel;
class QVBoxLayout;
class PropertyCard;
class QScrollArea;
namespace AzToolsFramework {
class ReflectedPropertyEditor;
class PropertyRowWidget;
class ComponentEditorHeader;
}
AZ_PUSH_DISABLE_DLL_EXPORT_BASECLASS_WARNING
//ReflectedPropertyEditor-based implementation of the MFC CPropertyCtrl API
class EDITOR_CORE_API ReflectedPropertyControl
: public QWidget
, public AzToolsFramework::IPropertyEditorNotify
{
AZ_POP_DISABLE_DLL_EXPORT_BASECLASS_WARNING
Q_OBJECT
public:
//! For alternative undo.
typedef AZStd::function<void(IVariable*)> UndoCallback;
explicit ReflectedPropertyControl(QWidget* parent = nullptr, Qt::WindowFlags windowFlags = Qt::WindowFlags());
void Setup(bool showScrollbars = true, int labelWidth = 150);
ReflectedPropertyItem* AddVarBlock(CVarBlock* varBlock, const char* szCategory = nullptr);
void CreateItems(XmlNodeRef node);
void CreateItems(XmlNodeRef node, CVarBlockPtr& varBlock, IVariable::OnSetCallback* func, bool splitCamelCaseIntoWords = false);
// Replace category item contents with the specified var block.
virtual void ReplaceVarBlock(IVariable* categoryItem, CVarBlock* varBlock);
//replace top-level var block. (used to port ctrl->ReplaceVarBlock(ctrl->GetRootItem(), varBlock);
virtual void ReplaceRootVarBlock(CVarBlock* newVarBlock);
void RemoveAllItems();
bool FindVariable(IVariable* categoryItem) const;
//! When item change, this callback fired variable that changed.
typedef AZStd::function<void(IVariable*)> UpdateVarCallback;
//! When item change, update object.
typedef AZStd::function<void(IVariable*)> UpdateObjectCallback;
//! When selection changes, this callback fired variable that changed.
typedef AZStd::function<void(IVariable*)> SelChangeCallback;
/** Set update callback to be used for this property window.
*/
void SetUpdateCallback(const UpdateVarCallback& callback);
void ClearUpdateCallback() { m_updateVarFunc = nullptr; }
void SetUpdateObjectCallback(UpdateObjectCallback callback) { m_updateObjectFunc = callback; }
void ClearUpdateObjectCallback() { m_updateObjectFunc = nullptr; }
/** Set selchange callback to be used for this property window.
*/
void SetSelChangeCallback(SelChangeCallback callback);
//set a key that can be used to save/restore expanded state.
void SetSavedStateKey(AZ::u32 key);
void ExpandAll();
void CollapseAll();
virtual void Expand(ReflectedPropertyItem* item, bool expand);
void ExpandAllChildren(ReflectedPropertyItem* item, bool recursive);
//IPropertyEditorNotify Interface
void BeforePropertyModified([[maybe_unused]] AzToolsFramework::InstanceDataNode* pNode) override {}
void AfterPropertyModified(AzToolsFramework::InstanceDataNode* pNode) override;
void SetPropertyEditingActive([[maybe_unused]] AzToolsFramework::InstanceDataNode* pNode) override {}
void SetPropertyEditingComplete([[maybe_unused]] AzToolsFramework::InstanceDataNode* pNode) override {}
void SealUndoStack() override {}
void RequestPropertyContextMenu(AzToolsFramework::InstanceDataNode*, const QPoint&) override;
void PropertySelectionChanged(AzToolsFramework::InstanceDataNode *pNode, bool selected) override;
void SetStoreUndoByItems(bool bStoreUndoByItems) { m_bStoreUndoByItems = bStoreUndoByItems; }
bool IsStoreUndoByItems() const { return m_bStoreUndoByItems; }
void ClearSelection();
ReflectedPropertyItem* GetSelectedItem();
virtual void SelectItem(ReflectedPropertyItem* item);
QVector<ReflectedPropertyItem*> GetSelectedItems();
/** Set alternative undo callback.
*/
void SetUndoCallback(UndoCallback& callback);
void ClearUndoCallback();
/** Enable of disable calling update callback when some values change.
*/
void EnableUpdateCallback(bool bEnable);
void SetDeferredUpdateCallback(bool deferred);
// Control is grayed, but is not readonly.
void SetGrayed(bool grayed);
// Sets control to be read only, User cannot modify content of properties.
void SetReadOnly(bool readonly);
void SetMultiSelect(bool multiSelect);
void EnableNotifyWithoutValueChange(bool bFlag);
void CopyItem(XmlNodeRef rootNode, ReflectedPropertyItem* pItem, bool bRecursively);
// set to false if you don't want to receive callbacks when the item is not modified (when items are expanded etc)
void SetCallbackOnNonModified(bool bEnable) { m_bSendCallbackOnNonModified = bEnable; }
void ReloadValues();
//whether to group child properties alphabetically under expanding elements
void SetGroupProperties(bool group);
//whether to sort child properties alphabetically
void SetSortProperties(bool sort);
//whether to show line edit for filtering properties
void SetShowFilterWidget(bool showFilter);
// It doesn't add any property item, but instead it updates all property items with
// a new variable block (sets display value, flags and user data).
virtual void UpdateVarBlock(CVarBlock* pVarBlock);
//! Find item that reference specified property.
ReflectedPropertyItem* FindItemByVar(IVariable* pVar);
ReflectedPropertyItem* GetRootItem();
int GetContentHeight() const;
int GetVisibleHeight() const {return GetContentHeight();}
//whether this control is a section of a TwoColumnPropertyCtrl (so we can show correct copy/paste options)
void SetIsTwoColumnCtrlSection(bool isSection);
struct SCustomPopupItem
{
typedef AZStd::function<void()> Callback;
QString m_text;
Callback m_callback;
SCustomPopupItem(const QString& text, const Callback& callback)
: m_text(text)
, m_callback(callback) {}
};
struct SCustomPopupMenu
{
typedef AZStd::function<void(int)> Callback;
QString m_text;
Callback m_callback;
QStringList m_subMenuText;
SCustomPopupMenu(const QString& text, const Callback& callback, const QStringList& subMenuText)
: m_text(text)
, m_callback(callback)
, m_subMenuText(subMenuText) {}
};
void AddCustomPopupMenuPopup(const QString& text, const AZStd::function<void(int)>& handler, const QStringList& items);
void RemoveCustomPopupMenuPopup(const QString& text);
void AddCustomPopupMenuItem(const QString& text, const SCustomPopupItem::Callback handler);
void RemoveCustomPopupMenuItem(const QString& text);
AzToolsFramework::PropertyRowWidget* FindPropertyRowWidget(ReflectedPropertyItem* item);
QSize sizeHint() const override;
AzToolsFramework::ReflectedPropertyEditor* GetEditor() { return m_editor; }
void SetValuesFromNode(XmlNodeRef rootNode);
public slots:
//invalidates attributes and values
void InvalidateCtrl(bool queued = true);
void RebuildCtrl(bool queued = true);
void SetTitle(const QString &title);
void OnCopy(QVector<ReflectedPropertyItem*> items, bool bRecursively);
void OnCopyAll();
void OnCopyAll(XmlNodeRef node);
void OnPaste();
Q_SIGNALS:
void CopyAllSections();
void PasteAllSections();
protected:
friend class ReflectedPropertyItem;
virtual void OnItemChange(ReflectedPropertyItem* item, bool deferCallbacks = true);
CReflectedVar* GetReflectedVarFromCallbackInstance(AzToolsFramework::InstanceDataNode* pNode);
void RecreateAllItems();
// only shows items containing the string in their name. All items shown if string is empty.
void RestrictToItemsContaining(const QString& searchName);
bool CallUndoFunc(ReflectedPropertyItem* item);
virtual void UpdateVarBlock(ReflectedPropertyItem* pPropertyItem, IVariableContainer* pSourceContainer, IVariableContainer* pTargetContainer);
void ClearVarBlock();
private slots:
void DoUpdateCallback(IVariable *var);
void DoUpdateObjectCallback(IVariable *var);
private:
AzToolsFramework::ReflectedPropertyEditor* m_editor;
QLineEdit* m_filterLineEdit;
QWidget* m_filterWidget;
QLabel* m_titleLabel;
AZ_PUSH_DISABLE_DLL_EXPORT_MEMBER_WARNING
_smart_ptr<CVarBlock> m_pVarBlock;
_smart_ptr<ReflectedPropertyItem> m_root;
AZStd::unique_ptr<CPropertyContainer> m_rootContainer;
AZ_POP_DISABLE_DLL_EXPORT_MEMBER_WARNING
AZ::SerializeContext* m_serializeContext;
bool m_bEnableCallback;
QString m_filterString;
AZ_PUSH_DISABLE_DLL_EXPORT_MEMBER_WARNING
UpdateVarCallback m_updateVarFunc;
UpdateObjectCallback m_updateObjectFunc;
SelChangeCallback m_selChangeFunc;
UndoCallback m_undoFunc;
AZ_POP_DISABLE_DLL_EXPORT_MEMBER_WARNING
bool m_bStoreUndoByItems;
bool m_bForceModified;
bool m_groupProperties;
bool m_sortProperties;
bool m_bSendCallbackOnNonModified;
bool m_initialized;
bool m_isTwoColumnSection;
//custom popup menu
AZ_PUSH_DISABLE_DLL_EXPORT_MEMBER_WARNING
std::vector<SCustomPopupItem> m_customPopupMenuItems;
std::vector<SCustomPopupMenu> m_customPopupMenuPopups;
AZ_POP_DISABLE_DLL_EXPORT_MEMBER_WARNING
template<typename T>
void RemoveCustomPopup(const QString& text, T& customPopup);
};
AZ_PUSH_DISABLE_DLL_EXPORT_BASECLASS_WARNING
class EDITOR_CORE_API TwoColumnPropertyControl
: public QWidget
{
AZ_POP_DISABLE_DLL_EXPORT_BASECLASS_WARNING
Q_OBJECT
public:
TwoColumnPropertyControl(QWidget* parent = nullptr);
void Setup(bool showScrollbars = true, int labelWidth = 150);
void AddVarBlock(CVarBlock* varBlock, const char* szCategory = nullptr);
// Replace category item contents with the specified var block.
virtual void ReplaceVarBlock(IVariable* categoryItem, CVarBlock* varBlock);
void RemoveAllItems();
bool FindVariable(IVariable* categoryItem) const;
void InvalidateCtrl();
void RebuildCtrl();
void SetStoreUndoByItems(bool bStoreUndoByItems);
/** Set alternative undo callback.
*/
void SetUndoCallback(ReflectedPropertyControl::UndoCallback callback);
void ClearUndoCallback();
/** Enable of disable calling update callback when some values change.
*/
void EnableUpdateCallback(bool bEnable);
void SetUpdateCallback(ReflectedPropertyControl::UpdateVarCallback callback);
// Control is grayed, but is not readonly.
void SetGrayed(bool grayed);
//set a key that can be used to save/restore expanded state.
void SetSavedStateKey(const QString& key);
void ExpandAllChildren(ReflectedPropertyItem* item, bool recursive);
void ExpandAllChildren(bool recursive);
void ReloadItems();
void OnCopyAll();
void OnPaste();
protected:
void resizeEvent(QResizeEvent *event) override;
private:
void ToggleTwoColumnLayout();
AZ_PUSH_DISABLE_DLL_EXPORT_MEMBER_WARNING
QVector<PropertyCard*> m_controlList;
QVector<_smart_ptr<CVarBlock>> m_varBlockList;
_smart_ptr<CVarBlock> m_pVarBlock;
AZ_POP_DISABLE_DLL_EXPORT_MEMBER_WARNING
QWidget *m_leftContainer;
QWidget *m_rightContainer;
QScrollArea *m_leftScrollArea;
QScrollArea *m_rightScrollArea;
bool m_twoColumns;
static const int minimumColumnWidth = 320;
static const int minimumTwoColumnWidth = 660;
};
class PropertyCard
: public QFrame
{
Q_OBJECT
public:
PropertyCard(QWidget* parent = nullptr);
void AddVarBlock(CVarBlock *varBlock);
ReflectedPropertyControl* GetControl();
void SetExpanded(bool expanded);
bool IsExpanded() const;
Q_SIGNALS:
void OnExpansionContractionDone();
private:
void OnExpanderChanged(bool expanded);
AzToolsFramework::ComponentEditorHeader* m_header = nullptr;
ReflectedPropertyControl* m_propertyEditor = nullptr;
};
#endif // CRYINCLUDE_EDITOR_UTILS_REFLECTEDPROPERTYCTRL_H
@@ -0,0 +1,6 @@
<RCC>
<qresource prefix="/reflectedPropertyCtrl/img">
<file alias="apply.png">resources/apply.png</file>
<file alias="file_browse.png">resources/file_browse.png</file>
</qresource>
</RCC>
@@ -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();
}
@@ -0,0 +1,170 @@
/*
* Copyright (c) Contributors to the Open 3D Engine Project
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#ifndef CRYINCLUDE_EDITOR_UTILS_REFLECTEDPROPERTYITEM_H
#define CRYINCLUDE_EDITOR_UTILS_REFLECTEDPROPERTYITEM_H
#pragma once
#include "Util/Variable.h"
#include <Util/VariablePropertyType.h>
namespace AzToolsFramework {
class ReflectedPropertyEditor;
}
class CReflectedVar;
class CPropertyContainer;
class ReflectedPropertyControl;
class ReflectedVarAdapter;
class ReflectedVarContainerAdapter;
// Class representing a property inside a ReflectedPropertyCtrl.
// It contains the IVariable and corresponding CReflectedVar for that property
// and any children properties if the IVariable is a container.
// This class is loosely based on the MFC-based CPropertyItem to make porting easier.
// The CPropertyItem created editor widgets for each property type, but this class
// just holds a CReflectedVar and updates it's values. The editing is done by the
// reflection system and registered property handlers for each CReflectedVar.
class EDITOR_CORE_API ReflectedPropertyItem
: public CRefCountBase
{
public:
ReflectedPropertyItem(ReflectedPropertyControl* control, ReflectedPropertyItem* parent);
~ReflectedPropertyItem();
void SetVariable(IVariable* var);
IVariable* GetVariable() const { return m_pVariable; }
void ReplaceVarBlock(CVarBlock* varBlock);
CReflectedVar* GetReflectedVar() const;
ReflectedPropertyItem* findItem(CReflectedVar* var);
ReflectedPropertyItem* findItem(IVariable* var);
ReflectedPropertyItem* findItem(const QString &name);
ReflectedPropertyItem* FindItemByFullName(const QString& fullName);
//update the internal IVariable as result of ReflectedVar changing
void OnReflectedVarChanged();
//update the ReflectedVar to current value of IVar
void SyncReflectedVarToIVar();
//! Return true if this property item is modified.
bool IsModified() const { return m_modified; }
void ReloadValues();
ReflectedVarContainerAdapter* GetContainer() { return m_reflectedVarContainerAdapter; }
ReflectedPropertyItem* GetParent() { return m_parent; }
/** Get script default value of property item.
*/
virtual bool HasScriptDefault() const { return m_strScriptDefault != m_strNoScriptDefault; };
/** Get script default value of property item.
*/
virtual QString GetScriptDefault() const { return m_strScriptDefault; };
/** Set script default value of property item.
*/
virtual void SetScriptDefault(const QString& sScriptDefault) { m_strScriptDefault = sScriptDefault; };
/** Set script default value of property item.
*/
virtual void ClearScriptDefault() { m_strScriptDefault = m_strNoScriptDefault; };
/** Changes value of item.
*/
virtual void SetValue(const QString& sValue, bool bRecordUndo = true, bool bForceModified = false);
//hack for calling ReflectedPropertyControl::OnItemChange from a wrapper class
//this is used because changes to Splines should not actually change anything in the IVariable,
//but we need OnItemChanged as if the IVariable did change.
void SendOnItemChange();
void ExpandAllChildren(bool recursive);
void Expand(bool expand);
QString GetPropertyName() const;
void AddChild(ReflectedPropertyItem* item);
void RemoveAllChildren();
void RemoveChild(ReflectedPropertyItem* item);
// default number of increments to cover the range of a property
static const float s_DefaultNumStepIncrements;
// for a consistent Feel, compute the step size for a numerical slider for the specified min/max, rounded to precision
inline static float ComputeSliderStep(float sliderMin, float sliderMax, const float precision = .01f)
{
float step;
step = int_round(((sliderMax - sliderMin) / ReflectedPropertyItem::s_DefaultNumStepIncrements) / precision) * precision;
// prevent rounding down to zero
return (step > precision) ? step : precision;
}
protected:
friend class ReflectedPropertyControl;
//! Release used variable.
void ReleaseVariable();
//! Callback called when variable change.
void OnVariableChange(IVariable* var);
void OnVariableEnumChange(IVariable* var);
public:
//! Get number of child nodes.
int GetChildCount() const { return m_childs.size(); };
//! Get Child by id.
ReflectedPropertyItem* GetChild(int index) const { return m_childs[index]; }
PropertyType GetType() const { return m_type; }
/** Get name of property item.
*/
virtual QString GetName() const;
QString GetFullName() const;
protected:
PropertyType m_type;
AZ_PUSH_DISABLE_DLL_EXPORT_MEMBER_WARNING
//The variable being edited.
_smart_ptr<IVariable> m_pVariable;
AZ_POP_DISABLE_DLL_EXPORT_MEMBER_WARNING
//holds the CReflectedVar and syncs its value with IVariable when either changes
ReflectedVarAdapter* m_reflectedVarAdapter;
ReflectedVarContainerAdapter* m_reflectedVarContainerAdapter;
ReflectedPropertyItem* m_parent;
AZ_PUSH_DISABLE_DLL_EXPORT_MEMBER_WARNING
std::vector<_smart_ptr<ReflectedPropertyItem> > m_childs;
AZ_POP_DISABLE_DLL_EXPORT_MEMBER_WARNING
ReflectedPropertyControl* m_propertyCtrl;
unsigned int m_modified : 1;
bool m_syncingIVar;
QString m_strNoScriptDefault;
QString m_strScriptDefault;
AZ_PUSH_DISABLE_DLL_EXPORT_MEMBER_WARNING
IVariable::OnSetCallback m_onSetCallback;
IVariable::OnSetEnumCallback m_onSetEnumCallback;
AZ_POP_DISABLE_DLL_EXPORT_MEMBER_WARNING
};
typedef _smart_ptr<ReflectedPropertyItem> ReflectedPropertyItemPtr;
#endif // CRYINCLUDE_EDITOR_UTILS_REFLECTEDPROPERTYITEM_H
@@ -0,0 +1,320 @@
/*
* Copyright (c) Contributors to the Open 3D Engine Project
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#include "EditorDefs.h"
#include "ReflectedVar.h"
// AzCore
#include <AzCore/Serialization/EditContext.h>
bool ReflectedVarInit::s_reflectionDone = false;
void ReflectedVarInit::setupReflection(AZ::SerializeContext* serializeContext)
{
if (!serializeContext)
return;
if (s_reflectionDone)
return;
s_reflectionDone = true;
serializeContext->Class< CReflectedVar>()
->Version(1)
->Field("description", &CReflectedVar::m_description)
->Field("varName", &CReflectedVar::m_varName);
serializeContext->Class <CReflectedVarAnimation, CReflectedVar >()
->Version(1)
->Field("animation", &CReflectedVarAnimation::m_animation)
->Field("entityID", &CReflectedVarAnimation::m_entityID)
;
serializeContext->Class <CReflectedVarResource, CReflectedVar >()
->Version(1)
->Field("path", &CReflectedVarResource::m_path)
->Field("propertyType", &CReflectedVarResource::m_propertyType)
;
serializeContext->Class< CReflectedVarColor, CReflectedVar>()
->Version(1)
->Field("color", &CReflectedVarColor::m_color);
serializeContext->Class< CReflectedVarUser, CReflectedVar>()
->Version(1)
->Field("value", &CReflectedVarUser::m_value)
->Field("enableEdit", &CReflectedVarUser::m_enableEdit)
->Field("title", &CReflectedVarUser::m_dialogTitle)
->Field("useTree", &CReflectedVarUser::m_useTree)
->Field("treeSeparator", &CReflectedVarUser::m_treeSeparator)
->Field("itemNames", &CReflectedVarUser::m_itemNames)
->Field("itemDescriptions", &CReflectedVarUser::m_itemDescriptions);
serializeContext->Class <CReflectedVarSpline, CReflectedVar >()
->Version(1)
->Field("spline", &CReflectedVarSpline::m_spline)
->Field("propertyType", &CReflectedVarSpline::m_propertyType)
;
serializeContext->Class< CPropertyContainer, CReflectedVar>()
->Version(1)
->Field("properties", &CPropertyContainer::m_properties);
serializeContext->Class <CReflectedVarMotion, CReflectedVar >()
->Version(1)
->Field("motion", &CReflectedVarMotion::m_motion)
->Field("assetId", &CReflectedVarMotion::m_assetId)
;
AZ::EditContext* ec = serializeContext->GetEditContext();
if (ec)
{
ec->Class< CReflectedVarAnimation >("VarAnimation", "Animation")
->ClassElement(AZ::Edit::ClassElements::EditorData, "")
->Attribute(AZ::Edit::Attributes::NameLabelOverride, &CReflectedVarAnimation::varName)
->Attribute(AZ::Edit::Attributes::DescriptionTextOverride, &CReflectedVarAnimation::description)
;
ec->Class< CReflectedVarResource >("VarResource", "Resource")
->ClassElement(AZ::Edit::ClassElements::EditorData, "")
->Attribute(AZ::Edit::Attributes::NameLabelOverride, &CReflectedVarResource::varName)
->Attribute(AZ::Edit::Attributes::DescriptionTextOverride, &CReflectedVarResource::description)
;
ec->Class< CReflectedVarUser >("VarUser", "")
->ClassElement(AZ::Edit::ClassElements::EditorData, "")
->Attribute(AZ::Edit::Attributes::NameLabelOverride, &CReflectedVarUser::varName)
->Attribute(AZ::Edit::Attributes::Handler, AZ_CRC("ePropertyUser", 0x65b972c0))
;
ec->Class< CReflectedVarColor >("VarColor", "")
->ClassElement(AZ::Edit::ClassElements::EditorData, "")
->Attribute(AZ::Edit::Attributes::Visibility, AZ_CRC("PropertyVisibility_ShowChildrenOnly", 0xef428f20))
->DataElement(AZ::Edit::UIHandlers::Color, &CReflectedVarColor::m_color, "Color", "")
->Attribute(AZ::Edit::Attributes::NameLabelOverride, &CReflectedVarColor::varName)
->Attribute(AZ::Edit::Attributes::DescriptionTextOverride, &CReflectedVarColor::description)
;
ec->Class< CReflectedVarSpline >("VarSpline", "")
->ClassElement(AZ::Edit::ClassElements::EditorData, "")
->Attribute(AZ::Edit::Attributes::NameLabelOverride, &CReflectedVarSpline::varName)
->Attribute(AZ::Edit::Attributes::Handler, &CReflectedVarSpline::handler)
;
ec->Class< CPropertyContainer >("PropertyContainer", "")
->ClassElement(AZ::Edit::ClassElements::EditorData, "")
->Attribute(AZ::Edit::Attributes::Visibility, AZ_CRC("PropertyVisibility_ShowChildrenOnly", 0xef428f20))
->DataElement(AZ::Edit::UIHandlers::Default, &CPropertyContainer::m_properties, "Properties", "")
->Attribute(AZ::Edit::Attributes::ContainerCanBeModified, false)
->Attribute(AZ::Edit::Attributes::NameLabelOverride, &CPropertyContainer::varName)
->Attribute(AZ::Edit::Attributes::DescriptionTextOverride, &CPropertyContainer::description)
->Attribute(AZ::Edit::Attributes::Visibility, &CPropertyContainer::GetVisibility)
->Attribute(AZ::Edit::Attributes::AutoExpand, &CPropertyContainer::m_autoExpand)
->Attribute(AZ::Edit::Attributes::ValueText, &CPropertyContainer::m_valueText) //will be ignored if blank
;
ec->Class< CReflectedVarMotion >("VarMotion", "Motion")
->ClassElement(AZ::Edit::ClassElements::EditorData, "")
->Attribute(AZ::Edit::Attributes::NameLabelOverride, &CReflectedVarMotion::varName)
->Attribute(AZ::Edit::Attributes::DescriptionTextOverride, &CReflectedVarMotion::description)
;
}
CReflectedVarString::reflect(serializeContext);
CReflectedVarBool::reflect(serializeContext);
CReflectedVarFloat::reflect(serializeContext);
CReflectedVarInt::reflect(serializeContext);
CReflectedVarVector2::reflect(serializeContext);
CReflectedVarVector3::reflect(serializeContext);
CReflectedVarVector4::reflect(serializeContext);
CReflectedVarAny<AZStd::vector<AZStd::string>>::reflect(serializeContext);
CReflectedVarEnum<int>::reflect(serializeContext);
CReflectedVarEnum<AZStd::string>::reflect(serializeContext);
CReflectedVarGenericProperty::reflect(serializeContext);
}
template<class T>
void CReflectedVarAny<T>::reflect(AZ::SerializeContext* serializeContext)
{
static bool reflected = false;
if (reflected)
return;
reflected = true;
serializeContext->Class< CReflectedVarAny<T>, CReflectedVar>()
->Version(1)
->Field("value", &CReflectedVarAny<T>::m_value);
AZ::EditContext* ec = serializeContext->GetEditContext();
if (ec)
{
ec->Class< CReflectedVarAny<T> >("VarAny", "")
->ClassElement(AZ::Edit::ClassElements::EditorData, "")
->Attribute(AZ::Edit::Attributes::Visibility, AZ_CRC("PropertyVisibility_ShowChildrenOnly", 0xef428f20))
->DataElement(AZ::Edit::UIHandlers::Default, &CReflectedVarAny<T>::m_value, "Value", "")
->Attribute(AZ::Edit::Attributes::NameLabelOverride, &CReflectedVarAny<T>::varName)
->Attribute(AZ::Edit::Attributes::DescriptionTextOverride, &CReflectedVarAny<T>::description)
;
}
}
template<class T, class R>
void CReflectedVarRanged<T, R>::reflect(AZ::SerializeContext* serializeContext)
{
static bool reflected = false;
if (reflected)
return;
reflected = true;
serializeContext->Class< CReflectedVarRanged<T, R>, CReflectedVar>()
->Version(1)
->Field("value", &CReflectedVarRanged<T, R>::m_value)
->Field("min", &CReflectedVarRanged<T, R>::m_minVal)
->Field("max", &CReflectedVarRanged<T, R>::m_maxVal)
->Field("step", &CReflectedVarRanged<T, R>::m_stepSize)
->Field("softMin", &CReflectedVarRanged<T, R>::m_softMinVal)
->Field("softMax", &CReflectedVarRanged<T, R>::m_softMaxVal)
;
AZ::EditContext* ec = serializeContext->GetEditContext();
if (ec)
{
ec->Class< CReflectedVarRanged<T, R> >("VarAny", "")
->ClassElement(AZ::Edit::ClassElements::EditorData, "")
->Attribute(AZ::Edit::Attributes::Visibility, AZ_CRC("PropertyVisibility_ShowChildrenOnly", 0xef428f20))
->DataElement(AZ::Edit::UIHandlers::Slider, &CReflectedVarRanged<T, R>::m_value, "Value", "")
->Attribute(AZ::Edit::Attributes::NameLabelOverride, &CReflectedVarRanged<T, R>::varName)
->Attribute(AZ::Edit::Attributes::DescriptionTextOverride, &CReflectedVarRanged<T, R>::description)
->Attribute(AZ::Edit::Attributes::Min, &CReflectedVarRanged<T, R>::minValue)
->Attribute(AZ::Edit::Attributes::Max, &CReflectedVarRanged<T, R>::maxValue)
->Attribute(AZ::Edit::Attributes::Step, &CReflectedVarRanged<T, R>::stepSize)
->Attribute(AZ::Edit::Attributes::SoftMin, &CReflectedVarRanged<T, R>::softMinVal)
->Attribute(AZ::Edit::Attributes::SoftMax, &CReflectedVarRanged<T, R>::softMaxVal)
;
}
}
template<class T>
void CReflectedVarEnum<T>::reflect(AZ::SerializeContext* serializeContext)
{
static bool reflected = false;
if (reflected)
return;
reflected = true;
serializeContext->Class< CReflectedVarEnum<T>, CReflectedVar>()
->Version(1)
->Field("value", &CReflectedVarEnum<T>::m_value)
->Field("selectedName", &CReflectedVarEnum<T>::m_selectedEnumName)
->Field("availableValues", &CReflectedVarEnum<T>::m_enums)
;
AZ::EditContext* ec = serializeContext->GetEditContext();
if (ec)
{
ec->Class< CReflectedVarEnum<T> >("Enum Variable", "")
->ClassElement(AZ::Edit::ClassElements::EditorData, "")
->Attribute(AZ::Edit::Attributes::Visibility, AZ_CRC("PropertyVisibility_ShowChildrenOnly", 0xef428f20))
->DataElement(AZ::Edit::UIHandlers::ComboBox, &CReflectedVarEnum<T>::m_selectedEnumName, "Value", "")
->Attribute(AZ::Edit::Attributes::StringList, &CReflectedVarEnum<T>::GetEnums)
->Attribute(AZ::Edit::Attributes::ChangeNotify, &CReflectedVarEnum<T>::OnEnumChanged)
->Attribute(AZ::Edit::Attributes::NameLabelOverride, &CReflectedVarEnum<T>::varName)
->Attribute(AZ::Edit::Attributes::DescriptionTextOverride, &CReflectedVarEnum<T>::description)
;
}
}
void CReflectedVarGenericProperty::reflect(AZ::SerializeContext* serializeContext)
{
static bool reflected = false;
if (reflected)
return;
reflected = true;
serializeContext->Class< CReflectedVarGenericProperty, CReflectedVar>()
->Version(1)
->Field("value", &CReflectedVarGenericProperty::m_value)
->Field("propertyType", &CReflectedVarGenericProperty::m_propertyType)
;
AZ::EditContext* ec = serializeContext->GetEditContext();
if (ec)
{
ec->Class< CReflectedVarGenericProperty >("GenericProperty", "GenericProperty")
->ClassElement(AZ::Edit::ClassElements::EditorData, "")
->Attribute(AZ::Edit::Attributes::NameLabelOverride, &CReflectedVarGenericProperty::varName)
->Attribute(AZ::Edit::Attributes::DescriptionTextOverride, &CReflectedVarGenericProperty::description)
->Attribute(AZ::Edit::Attributes::Handler, &CReflectedVarGenericProperty::handler)
;
}
}
AZ::u32 CReflectedVarSpline::handler()
{
switch (m_propertyType)
{
case ePropertyFloatCurve:
return AZ_CRC("ePropertyFloatCurve", 0x7440ccce);
case ePropertyColorCurve:
return AZ_CRC("ePropertyColorCurve", 0xa30da4ec);
default:
AZ_Assert(false, "CReflectedVarSpline property type must be ePropertyFloatCurve or ePropertyColorCurve");
return AZ::Edit::UIHandlers::Default;
}
}
AZ::u32 CReflectedVarGenericProperty::handler()
{
switch (m_propertyType)
{
case ePropertyShader:
return AZ_CRC("ePropertyShader", 0xc40932f1);
case ePropertyEquip:
return AZ_CRC("ePropertyEquip", 0x66ffd290);
case ePropertyReverbPreset:
return AZ_CRC("ePropertyReverbPreset", 0x51469f38);
case ePropertyDeprecated0:
return AZ_CRC("ePropertyCustomAction", 0x4ffa5ba5);
case ePropertyGameToken:
return AZ_CRC("ePropertyGameToken", 0x34855b6f);
case ePropertyMissionObj:
return AZ_CRC("ePropertyMissionObj", 0x4a2d0dc8);
case ePropertySequence:
return AZ_CRC("ePropertySequence", 0xdd1c7d44);
case ePropertySequenceId:
return AZ_CRC("ePropertySequenceId", 0x05983dcc);
case ePropertyLocalString:
return AZ_CRC("ePropertyLocalString", 0x0cd9609a);
case ePropertyLightAnimation:
return AZ_CRC("ePropertyLightAnimation", 0x277097da);
case ePropertyParticleName:
return AZ_CRC("ePropertyParticleName", 0xf44c7133);
default:
AZ_Assert(false, "No property handlers defined for the property type");
return AZ_CRC("Default", 0xe35e00df);
}
}
void CPropertyContainer::AddProperty(CReflectedVar *property)
{
if (property)
m_properties.push_back(property);
}
void CPropertyContainer::Clear()
{
m_properties.clear();
}
@@ -0,0 +1,429 @@
/*
* Copyright (c) Contributors to the Open 3D Engine Project
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#ifndef CRYINCLUDE_EDITOR_UTILS_REFLECTEDVAR_H
#define CRYINCLUDE_EDITOR_UTILS_REFLECTEDVAR_H
#pragma once
#include <AzCore/Serialization/SerializeContext.h>
#include <algorithm>
#include <limits>
#include "Util/VariablePropertyType.h"
#include <AzCore/Math/Vector2.h>
#include <AzCore/Math/Vector3.h>
#include <AzCore/Math/Vector4.h>
//Base class for generic reflected variables
class CReflectedVar
{
public:
AZ_RTTI(CReflectedVar, "{9CF461B5-4093-4F7E-9A28-75531F0D046C}")
CReflectedVar() = default;
CReflectedVar(const AZStd::string& name)
: m_varName(name){}
virtual ~CReflectedVar(){}
AZStd::string m_varName;
AZStd::string m_description;
};
// Reflected container of reflected values. Also holds ePropertyTable data
class CPropertyContainer
: public CReflectedVar
{
public:
AZ_RTTI(CPropertyContainer, "{99500790-241A-4274-BAD8-C4510E869FC6}", CReflectedVar)
CPropertyContainer(const AZStd::string& name)
: CReflectedVar(name) {}
CPropertyContainer() = default;
AZStd::string varName() const { return m_varName; }
AZStd::string description() const { return m_description; }
void AddProperty(CReflectedVar* property);
void Clear();
//If we're an unnamed container, just show our children in flat list. Otherwise show the container name with children underneath
AZ::u32 GetVisibility() const
{
return m_varName.empty() ? AZ_CRC("PropertyVisibility_ShowChildrenOnly", 0xef428f20) : AZ_CRC("PropertyVisibility_Show", 0xa43c82dd);
}
void SetAutoExpand(bool autoExpand) { m_autoExpand = autoExpand; }
bool AutoExpand() const { return m_autoExpand; }
AZStd::vector<CReflectedVar*> GetProperties() const { return m_properties; }
void SetValueText(const AZStd::string& valueText) { m_valueText = valueText; }
friend class ReflectedVarInit;
private:
AZStd::vector<CReflectedVar*> m_properties;
bool m_autoExpand = false;
AZStd::string m_valueText;
};
template<class T>
class CReflectedVarAny
: public CReflectedVar
{
public:
AZ_RTTI((CReflectedVarAny<T>, "{EE8293C3-9B1E-470B-9922-2CBB8DA13D78}", T), CReflectedVar)
CReflectedVarAny(const AZStd::string& name, const T& val = T())
: CReflectedVar(name)
, m_value(val) {}
CReflectedVarAny() = default;
AZStd::string varName() const { return m_varName; }
AZStd::string description() const { return m_description; }
static void reflect(AZ::SerializeContext* serializeContext);
T m_value;
};
// Class to hold values that have min/max
// T = data type held in this variable
// R = data type of the range
template<class T, class R>
class CReflectedVarRanged
: public CReflectedVar
{
public:
AZ_RTTI((CReflectedVarRanged, "{6AB4EC29-E17B-4B3B-A153-BFDAA48B8CF8}", T, R), CReflectedVar)
CReflectedVarRanged(const AZStd::string& name, const T& val = T())
: CReflectedVar(name)
, m_value(val)
, m_minVal(std::numeric_limits<R>::lowest())
, m_maxVal(std::numeric_limits<R>::max())
, m_stepSize(1)
, m_softMinVal(std::numeric_limits<R>::lowest())
, m_softMaxVal(std::numeric_limits<R>::max())
{}
CReflectedVarRanged()
: CReflectedVarRanged(AZStd::string(), T()){}
AZStd::string varName() const { return m_varName; }
AZStd::string description() const { return m_description; }
R minValue() const { return m_minVal; }
R maxValue() const { return m_maxVal; }
R stepSize() const { return m_stepSize; }
R softMinVal() const { return m_softMinVal; }
R softMaxVal() const { return m_softMaxVal; }
static void reflect(AZ::SerializeContext* serializeContext);
T m_value;
R m_minVal;
R m_maxVal;
R m_stepSize;
R m_softMinVal;
R m_softMaxVal;
};
//name some commonly-used variable types
template <class T>
using CReflectedVarNumeric = CReflectedVarRanged<T, T>;
//ePropertyFloat
using CReflectedVarFloat = CReflectedVarNumeric<float>;
//ePropertyInt
using CReflectedVarInt = CReflectedVarNumeric<int>;
//ePropertyString
using CReflectedVarString = CReflectedVarAny<AZStd::string>;
//ePropertyBool
using CReflectedVarBool = CReflectedVarAny<bool>;
//ePropertyVector2
using CReflectedVarVector2 = CReflectedVarRanged<AZ::Vector2, float>;
//ePropertyVector
using CReflectedVarVector3 = CReflectedVarRanged<AZ::Vector3, float>;
//ePropertyVector4
using CReflectedVarVector4 = CReflectedVarRanged<AZ::Vector4, float>;
// Class for holding enumerated values, ePropertySelection
// Keeps a key-value pair values (int, string, float, etc) and names corresponding to each value
// The names are displayed to user when editing, the values are used by underlying code.
template<class T>
class CReflectedVarEnum
: public CReflectedVar
{
public:
AZ_RTTI((CReflectedVarEnum<T>, "{40AE7D74-7E3A-41A9-8F71-2BBC3067118B}", T), CReflectedVar)
CReflectedVarEnum(const AZStd::string& name)
: CReflectedVar(name) {}
CReflectedVarEnum() = default;
void setEnums(const AZStd::vector<AZStd::pair<T, AZStd::string> >& enums)
{
m_enums = enums;
if (m_enums.size() > 0)
{
m_value = m_enums.at(0).first;
m_selectedEnumName = m_enums.at(0).second;
}
else
{
m_value = T();
m_selectedEnumName.clear();
}
}
void addEnum(const T& value, const AZStd::string& name)
{
m_enums.push_back(AZStd::pair<T, AZStd::string>(value, name));
if (m_enums.size() == 1)
{
m_selectedEnumName = name;
m_value = value;
}
}
void setEnumValue(const T& value)
{
auto it = std::find_if(m_enums.cbegin(), m_enums.cend(), [value](const AZStd::pair<T, AZStd::string>& item) -> bool { return item.first == value; });
if (it != m_enums.end())
{
m_value = it->first;
m_selectedEnumName = it->second;
}
}
void setEnumByName(const AZStd::string& name)
{
auto it = std::find_if(m_enums.cbegin(), m_enums.cend(), [name](const AZStd::pair<T, AZStd::string>& item) -> bool { return item.second == name; });
if (it != m_enums.end())
{
m_value = it->first;
m_selectedEnumName = it->second;
}
}
void OnEnumChanged()
{
setEnumByName(m_selectedEnumName);
}
AZStd::vector < AZStd::string> GetEnums() const
{
AZStd::vector < AZStd::string> returnVal;
for (const auto& i : m_enums)
{
returnVal.push_back(i.second);
}
return returnVal;
}
AZStd::string varName() const { return m_varName; }
AZStd::string description() const { return m_description; }
static void reflect(AZ::SerializeContext* serializeContext);
T m_value;
AZStd::string m_selectedEnumName;
AZStd::vector<AZStd::pair<T, AZStd::string> > m_enums;
};
//Class to hold ePropertyColor (IVariable::DT_COLOR)
class CReflectedVarColor
: public CReflectedVar
{
public:
AZ_RTTI(CReflectedVarColor, "{CC69E773-B4FA-4B6D-8A46-0B580097B6D2}", CReflectedVar)
CReflectedVarColor(const AZStd::string& name, AZ::Vector3 color = AZ::Vector3())
: CReflectedVar(name)
, m_color(color) {}
CReflectedVarColor() {}
AZStd::string varName() const { return m_varName; }
AZStd::string description() const { return m_description; }
AZ::Vector3 m_color;
};
//Class to hold ePropertyAnimation (IVariable::DT_ANIMATION )
class CReflectedVarAnimation
: public CReflectedVar
{
public:
AZ_RTTI(CReflectedVarAnimation, "{635D982E-23EC-463F-8F33-4FC2C19D5673}", CReflectedVar)
CReflectedVarAnimation(const AZStd::string& name)
: CReflectedVar(name)
, m_entityID(0)
{}
CReflectedVarAnimation()
: m_entityID(0){}
AZStd::string varName() const { return m_varName; }
AZStd::string description() const { return m_description; }
AZStd::string m_animation;
AZ::EntityId m_entityID;
};
//Class to hold:
// ePropertyTexture (IVariable::DT_TEXTURE)
// ePropertyMaterial (IVariable::DT_MATERIAL)
// ePropertyModel (IVariable::DT_OBJECT)
// ePropertyGeomCache (IVariable::DT_GEOM_CACHE)
// ePropertyAudioTrigger (IVariable::DT_AUDIO_TRIGGER)
// ePropertyAudioSwitch (IVariable::DT_AUDIO_SWITCH )
// ePropertyAudioSwitchState (IVariable::DT_AUDIO_SWITCH_STATE)
// ePropertyAudioRTPC (IVariable::DT_AUDIO_RTPC)
// ePropertyAudioEnvironment (IVariable::DT_AUDIO_ENVIRONMENT)
// ePropertyAudioPreloadRequest (IVariable::DT_AUDIO_PRELOAD_REQUEST)
class CReflectedVarResource
: public CReflectedVar
{
public:
AZ_RTTI(CReflectedVarResource, "{162864C2-0C3E-4B6A-84D3-BBAD975B4FD2}", CReflectedVar)
CReflectedVarResource(const AZStd::string& name)
: CReflectedVar(name)
, m_propertyType(ePropertyInvalid)
{}
CReflectedVarResource()
: m_propertyType(ePropertyInvalid){}
AZStd::string varName() const { return m_varName; }
AZStd::string description() const { return m_description; }
AZStd::string m_path;
PropertyType m_propertyType;
};
//Class to hold ePropertyUser (IVariable::DT_USERITEMCB)
class CReflectedVarUser
: public CReflectedVar
{
public:
AZ_RTTI(CReflectedVarUser, "{A901DA91-3893-4848-9AE8-62C0ED074970}", CReflectedVar)
CReflectedVarUser(const AZStd::string &name)
: CReflectedVar(name)
, m_enableEdit(false)
, m_useTree(false)
{}
CReflectedVarUser() : m_enableEdit(false), m_useTree(false) {}
AZStd::string varName() const { return m_varName; }
AZStd::string m_value;
bool m_enableEdit;
bool m_useTree;
AZStd::string m_dialogTitle;
AZStd::string m_treeSeparator;
AZStd::vector<AZStd::string> m_itemNames;
AZStd::vector<AZStd::string> m_itemDescriptions;
};
//Class to hold ePropertyAnimation (IVariable::DT_ANIMATION )
class CReflectedVarSpline
: public CReflectedVar
{
public:
AZ_RTTI(CReflectedVarSpline, "{9A928683-7C84-48BF-8A2E-F7BEC423EE4E}", CReflectedVar)
CReflectedVarSpline(PropertyType propertyType, const AZStd::string &name)
: CReflectedVar(name)
, m_spline(0)
, m_propertyType(propertyType)
{}
CReflectedVarSpline()
: m_spline(0)
, m_propertyType(ePropertyInvalid)
{}
AZStd::string varName() const { return m_varName; }
AZ::u32 handler();
uint64_t m_spline;
PropertyType m_propertyType;
};
//Class to wrap all the many properties that can be represented by a string and edited via a popup
class CReflectedVarGenericProperty
: public CReflectedVar
{
public:
AZ_RTTI(CReflectedVarGenericProperty, "{C4A34C95-3D71-40CE-86D2-DDE314B33CC5}", CReflectedVar)
CReflectedVarGenericProperty(PropertyType pType, const AZStd::string& name = AZStd::string(), const AZStd::string& val = AZStd::string())
: CReflectedVar(name)
, m_propertyType(pType)
, m_value(val) {}
CReflectedVarGenericProperty()
: CReflectedVar()
, m_propertyType(ePropertyInvalid){}
AZStd::string varName() const { return m_varName; }
AZStd::string description() const { return m_description; }
PropertyType propertyType() const { return m_propertyType; }
AZ::u32 handler();
static void reflect(AZ::SerializeContext* serializeContext);
PropertyType m_propertyType;
AZStd::string m_value;
};
class EDITOR_CORE_API ReflectedVarInit
{
public:
static void setupReflection(AZ::SerializeContext* serializeContext);
private:
static bool s_reflectionDone;
};
//Class to hold ePropertyMotion (IVariable::DT_MOTION )
class CReflectedVarMotion
: public CReflectedVar
{
public:
AZ_RTTI(CReflectedVarMotion, "{66397EFB-620A-40B8-8C66-D6AECF690DF5}", CReflectedVar)
CReflectedVarMotion(const AZStd::string& name)
: CReflectedVar(name)
, m_assetId(0) {}
CReflectedVarMotion()
: m_assetId(0) {}
AZStd::string varName() const { return m_varName; }
AZStd::string description() const { return m_description; }
AZStd::string m_motion;
AZ::Data::AssetId m_assetId;
};
#endif // CRYINCLUDE_EDITOR_UTILS_REFLECTEDVAR_H
@@ -0,0 +1,579 @@
/*
* Copyright (c) Contributors to the Open 3D Engine Project
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#include "EditorDefs.h"
#include "ReflectedVarWrapper.h"
// AzCore
#include <AzCore/Asset/AssetManagerBus.h>
// Editor
#include "ReflectedPropertyCtrl.h"
#include "UIEnumsDatabase.h"
namespace {
//setting the IVariable to itself in property items was trigger to update limits for that variable.
//limits were obtained using IVariable::GetLimits instead of from the Prop::Description
template <class T, class R>
void setRangeParams(CReflectedVarRanged<T, R> *reflectedVar, IVariable *pVariable, bool updatingExistingVariable = false)
{
float min, max, step;
bool hardMin, hardMax;
if (updatingExistingVariable)
{
pVariable->GetLimits(min, max, step, hardMin, hardMax);
}
else
{
Prop::Description desc(pVariable);
min = desc.m_rangeMin;
max = desc.m_rangeMax;
step = desc.m_step;
hardMin = desc.m_bHardMin;
hardMax = desc.m_bHardMax;
}
reflectedVar->m_softMinVal = min;
reflectedVar->m_softMaxVal = max;
if (hardMin)
{
reflectedVar->m_minVal = min;
}
else
{
reflectedVar->m_minVal = std::numeric_limits<int>::lowest();
}
if (hardMax)
{
reflectedVar->m_maxVal = max;
}
else
{
// There is an issue with assigning std::numeric_limits<int>::max() to a float
// A float can't actually represent the value of 2147483647 and clang
// compilers actually warn on this fact.
// A static_cast is used here to indicate explicit acceptance of the value change here
/* The clang compiler warning is below
../Code/Sandbox/Editor/Controls/ReflectedPropertyControl/ReflectedVarWrapper.cpp:59:38: error: implicit conversion from 'int' to 'float' changes value from 2147483647 to 2147483648 [-Werror,-Wimplicit-int-float-conversion]
reflectedVar->m_maxVal = std::numeric_limits<int>::max();
*/
reflectedVar->m_maxVal = static_cast<float>(std::numeric_limits<int>::max());
}
reflectedVar->m_stepSize = step;
}
}
void ReflectedVarIntAdapter::SetVariable(IVariable *pVariable)
{
m_reflectedVar.reset(new CReflectedVarInt(pVariable->GetHumanName().toUtf8().data()));
m_reflectedVar->m_description = pVariable->GetDescription().toUtf8().data();
UpdateRangeLimits(pVariable);
Prop::Description desc(pVariable);
m_valueMultiplier = desc.m_valueMultiplier;
}
void ReflectedVarIntAdapter::UpdateRangeLimits(IVariable *pVariable)
{
setRangeParams<int>(m_reflectedVar.data(), pVariable);
}
void ReflectedVarIntAdapter::SyncReflectedVarToIVar(IVariable *pVariable)
{
float value;
if (pVariable->GetType() == IVariable::FLOAT)
{
pVariable->Get(value);
}
else
{
int intValue;
pVariable->Get(intValue);
value = intValue;
}
m_reflectedVar->m_value = std::round(value * m_valueMultiplier);
}
void ReflectedVarIntAdapter::SyncIVarToReflectedVar(IVariable *pVariable)
{
//don't round here. Often the IVariable is actually a float under-the hood
//for example: DT_PERCENT is stored in float (0 to 1) but has ePropertyType::Integer because editor should be an integer editor ranging from 0 to 100.
pVariable->Set(m_reflectedVar->m_value / m_valueMultiplier);
}
void ReflectedVarFloatAdapter::SetVariable(IVariable *pVariable)
{
m_reflectedVar.reset(new CReflectedVarFloat(pVariable->GetHumanName().toUtf8().data()));
m_reflectedVar->m_description = pVariable->GetDescription().toUtf8().data();
UpdateRangeLimits(pVariable);
Prop::Description desc(pVariable);
m_valueMultiplier = desc.m_valueMultiplier;
}
void ReflectedVarFloatAdapter::UpdateRangeLimits(IVariable *pVariable)
{
setRangeParams<float>(m_reflectedVar.data(), pVariable);
}
void ReflectedVarFloatAdapter::SyncReflectedVarToIVar(IVariable *pVariable)
{
float value;
pVariable->Get(value);
m_reflectedVar->m_value = value * m_valueMultiplier;
}
void ReflectedVarFloatAdapter::SyncIVarToReflectedVar(IVariable *pVariable)
{
pVariable->Set(m_reflectedVar->m_value/m_valueMultiplier);
}
void ReflectedVarStringAdapter::SetVariable(IVariable *pVariable)
{
m_reflectedVar.reset(new CReflectedVarString(pVariable->GetHumanName().toUtf8().data()));
m_reflectedVar->m_description = pVariable->GetDescription().toUtf8().data();
}
void ReflectedVarStringAdapter::SyncReflectedVarToIVar(IVariable *pVariable)
{
QString value;
pVariable->Get(value);
m_reflectedVar->m_value = value.toUtf8().data();
}
void ReflectedVarStringAdapter::SyncIVarToReflectedVar(IVariable *pVariable)
{
pVariable->Set(m_reflectedVar->m_value.c_str());
}
void ReflectedVarBoolAdapter::SetVariable(IVariable *pVariable)
{
m_reflectedVar.reset(new CReflectedVarBool(pVariable->GetHumanName().toUtf8().data()));
m_reflectedVar->m_description = pVariable->GetDescription().toUtf8().data();
}
void ReflectedVarBoolAdapter::SyncReflectedVarToIVar(IVariable *pVariable)
{
bool value;
pVariable->Get(value);
m_reflectedVar->m_value = value;
}
void ReflectedVarBoolAdapter::SyncIVarToReflectedVar(IVariable *pVariable)
{
pVariable->Set(m_reflectedVar->m_value);
}
ReflectedVarEnumAdapter::ReflectedVarEnumAdapter()
: m_updatingEnums(false)
, m_pVariable(nullptr)
{}
void ReflectedVarEnumAdapter::SetVariable(IVariable *pVariable)
{
m_pVariable = pVariable;
Prop::Description desc(pVariable);
m_enumList = desc.m_enumList;
m_reflectedVar.reset(new CReflectedVarEnum<AZStd::string>(pVariable->GetHumanName().toUtf8().data()));
m_reflectedVar->m_description = pVariable->GetDescription().toUtf8().data();
UpdateReflectedVarEnums();
}
bool ReflectedVarEnumAdapter::UpdateReflectedVarEnums()
{
if (!m_pVariable || m_updatingEnums)
{
return false;
}
m_updatingEnums = true;
//Allow derived classes to populate the IVariable's enumList
updateIVariableEnumList(m_pVariable);
m_enumList = m_pVariable->GetEnumList();
m_updatingEnums = false;
bool changed = false;
//Copy the updated enums to the ReflecteVar
if (m_enumList)
{
const AZStd::vector<AZStd::string> oldEnums = m_reflectedVar->GetEnums();
AZStd::vector<AZStd::pair<AZStd::string, AZStd::string>> enums;
for (uint i = 0; !m_enumList->GetItemName(i).isNull(); i++)
{
QString sEnumName = m_enumList->GetItemName(i);
enums.push_back(AZStd::pair<AZStd::string, AZStd::string>(sEnumName.toUtf8().data(), sEnumName.toUtf8().data()));
}
m_reflectedVar->setEnums(enums);
changed = m_reflectedVar->GetEnums() != oldEnums;
if (changed)
{
// set the current enum value from the IVariable
SyncReflectedVarToIVar(m_pVariable);
}
}
return changed;
}
void ReflectedVarEnumAdapter::SyncReflectedVarToIVar(IVariable *pVariable)
{
const AZStd::string value = pVariable->GetDisplayValue().toUtf8().data();
m_reflectedVar->setEnumByName(value);
}
void ReflectedVarEnumAdapter::SyncIVarToReflectedVar(IVariable *pVariable)
{
QString iVarVal = m_reflectedVar->m_selectedEnumName.c_str();
pVariable->SetDisplayValue(iVarVal);
}
void ReflectedVarEnumAdapter::OnVariableChange([[maybe_unused]] IVariable* pVariable)
{
//setting the enums on the pVariable will cause the variable to change getting us back here
//The original property editor did need to update things immediately because it did so when creating the in-place editing control
if (!m_updatingEnums)
{
UpdateReflectedVarEnums();
}
}
void ReflectedVarDBEnumAdapter::SetVariable(IVariable *pVariable)
{
Prop::Description desc(pVariable);
m_pEnumDBItem = desc.m_pEnumDBItem;
m_reflectedVar.reset(new CReflectedVarEnum<AZStd::string>(pVariable->GetHumanName().toUtf8().data()));
if (m_pEnumDBItem)
{
for (int i = 0; i < m_pEnumDBItem->strings.size(); i++)
{
QString name = m_pEnumDBItem->strings[i];
m_reflectedVar->addEnum( m_pEnumDBItem->NameToValue(name).toUtf8().data(), name.toUtf8().data() );
}
}
}
void ReflectedVarDBEnumAdapter::SyncReflectedVarToIVar(IVariable *pVariable)
{
const AZStd::string valueStr = pVariable->GetDisplayValue().toUtf8().data();
const AZStd::string value = m_pEnumDBItem ? AZStd::string(m_pEnumDBItem->ValueToName(valueStr.c_str()).toUtf8().data()) : valueStr;
m_reflectedVar->setEnumByName(value);
}
void ReflectedVarDBEnumAdapter::SyncIVarToReflectedVar(IVariable *pVariable)
{
QString iVarVal = m_reflectedVar->m_selectedEnumName.c_str();
if (m_pEnumDBItem)
{
iVarVal = m_pEnumDBItem->NameToValue(iVarVal);
}
pVariable->SetDisplayValue(iVarVal);
}
void ReflectedVarVector2Adapter::SetVariable(IVariable *pVariable)
{
m_reflectedVar.reset(new CReflectedVarVector2(pVariable->GetHumanName().toUtf8().data()));
m_reflectedVar->m_description = pVariable->GetDescription().toUtf8().data();
UpdateRangeLimits(pVariable);
}
void ReflectedVarVector2Adapter::SyncReflectedVarToIVar(IVariable *pVariable)
{
Vec2 vec;
pVariable->Get(vec);
m_reflectedVar->m_value = AZ::Vector2(vec.x, vec.y);
}
void ReflectedVarVector2Adapter::SyncIVarToReflectedVar(IVariable *pVariable)
{
pVariable->Set(Vec2(m_reflectedVar->m_value.GetX(), m_reflectedVar->m_value.GetY()));
}
void ReflectedVarVector3Adapter::SetVariable(IVariable *pVariable)
{
m_reflectedVar.reset(new CReflectedVarVector3(pVariable->GetHumanName().toUtf8().data()));
m_reflectedVar->m_description = pVariable->GetDescription().toUtf8().data();
UpdateRangeLimits(pVariable);
}
void ReflectedVarVector3Adapter::SyncReflectedVarToIVar(IVariable *pVariable)
{
Vec3 vec;
pVariable->Get(vec);
m_reflectedVar->m_value = AZ::Vector3(vec.x, vec.y, vec.z);
}
void ReflectedVarVector3Adapter::SyncIVarToReflectedVar(IVariable *pVariable)
{
pVariable->Set(Vec3(m_reflectedVar->m_value.GetX(), m_reflectedVar->m_value.GetY(), m_reflectedVar->m_value.GetZ()));
}
void ReflectedVarVector4Adapter::SetVariable(IVariable *pVariable)
{
m_reflectedVar.reset(new CReflectedVarVector4(pVariable->GetHumanName().toUtf8().data()));
m_reflectedVar->m_description = pVariable->GetDescription().toUtf8().data();
UpdateRangeLimits(pVariable);
}
void ReflectedVarVector4Adapter::SyncReflectedVarToIVar(IVariable *pVariable)
{
Vec4 vec;
pVariable->Get(vec);
m_reflectedVar->m_value = AZ::Vector4(vec.x, vec.y, vec.z, vec.w);
}
void ReflectedVarVector4Adapter::SyncIVarToReflectedVar(IVariable *pVariable)
{
pVariable->Set(Vec4(m_reflectedVar->m_value.GetX(), m_reflectedVar->m_value.GetY(), m_reflectedVar->m_value.GetZ(), m_reflectedVar->m_value.GetW()));
}
void ReflectedVarColorAdapter::SetVariable(IVariable *pVariable)
{
m_reflectedVar.reset(new CReflectedVarColor(pVariable->GetHumanName().toUtf8().data()));
m_reflectedVar->m_description = pVariable->GetDescription().toUtf8().data();
}
void ReflectedVarColorAdapter::SyncReflectedVarToIVar(IVariable *pVariable)
{
if (pVariable->GetType() == IVariable::VECTOR)
{
Vec3 v(0, 0, 0);
pVariable->Get(v);
const QColor col = ColorLinearToGamma(ColorF(v.x, v.y, v.z));
m_reflectedVar->m_color.Set(col.redF(), col.greenF(), col.blueF());
}
else
{
int col(0);
pVariable->Get(col);
const QColor qcolor = ColorToQColor((uint32)col);
m_reflectedVar->m_color.Set(qcolor.redF(), qcolor.greenF(), qcolor.blueF());
}
}
void ReflectedVarColorAdapter::SyncIVarToReflectedVar(IVariable *pVariable)
{
if (pVariable->GetType() == IVariable::VECTOR)
{
ColorF colLin = ColorGammaToLinear(QColor::fromRgbF(m_reflectedVar->m_color.GetX(), m_reflectedVar->m_color.GetY(), m_reflectedVar->m_color.GetZ()));
pVariable->Set(Vec3(colLin.r, colLin.g, colLin.b));
}
else
{
int ir = m_reflectedVar->m_color.GetX() * 255.0f;
int ig = m_reflectedVar->m_color.GetY() * 255.0f;
int ib = m_reflectedVar->m_color.GetZ() * 255.0f;
pVariable->Set(static_cast<int>(RGB(ir, ig, ib)));
}
}
void ReflectedVarAnimationAdapter::SetVariable(IVariable *pVariable)
{
m_reflectedVar.reset(new CReflectedVarAnimation(pVariable->GetHumanName().toUtf8().data()));
m_reflectedVar->m_description = pVariable->GetDescription().toUtf8().data();
}
void ReflectedVarAnimationAdapter::SyncReflectedVarToIVar(IVariable *pVariable)
{
m_reflectedVar->m_entityID = static_cast<AZ::EntityId>(pVariable->GetUserData().value<AZ::u64>());
m_reflectedVar->m_animation = pVariable->GetDisplayValue().toUtf8().data();
}
void ReflectedVarAnimationAdapter::SyncIVarToReflectedVar(IVariable *pVariable)
{
pVariable->SetUserData(static_cast<AZ::u64>(m_reflectedVar->m_entityID));
pVariable->SetDisplayValue(m_reflectedVar->m_animation.c_str());
}
void ReflectedVarResourceAdapter::SetVariable(IVariable *pVariable)
{
m_reflectedVar.reset(new CReflectedVarResource(pVariable->GetHumanName().toUtf8().data()));
m_reflectedVar->m_description = pVariable->GetDescription().toUtf8().data();
}
void ReflectedVarResourceAdapter::SyncReflectedVarToIVar(IVariable *pVariable)
{
QString path;
pVariable->Get(path);
m_reflectedVar->m_path = path.toUtf8().data();
Prop::Description desc(pVariable);
m_reflectedVar->m_propertyType = desc.m_type;
}
void ReflectedVarResourceAdapter::SyncIVarToReflectedVar(IVariable *pVariable)
{
const bool bForceModified = (m_reflectedVar->m_propertyType == ePropertyGeomCache);
pVariable->SetForceModified(bForceModified);
pVariable->SetDisplayValue(m_reflectedVar->m_path.c_str());
//shouldn't be able to change the type, so ignore m_reflecatedVar->m_properyType
}
ReflectedVarGenericPropertyAdapter::ReflectedVarGenericPropertyAdapter(PropertyType propertyType)
:m_propertyType(propertyType)
{}
void ReflectedVarGenericPropertyAdapter::SetVariable(IVariable *pVariable)
{
m_reflectedVar.reset(new CReflectedVarGenericProperty(m_propertyType, pVariable->GetHumanName().toUtf8().data()));
m_reflectedVar->m_description = pVariable->GetDescription().toUtf8().data();
}
void ReflectedVarGenericPropertyAdapter::SyncReflectedVarToIVar(IVariable *pVariable)
{
QString value;
pVariable->Get(value);
m_reflectedVar->m_value = value.toUtf8().data();
}
void ReflectedVarGenericPropertyAdapter::SyncIVarToReflectedVar(IVariable *pVariable)
{
pVariable->Set(m_reflectedVar->m_value.c_str());
}
void ReflectedVarUserAdapter::SetVariable(IVariable *pVariable)
{
m_reflectedVar.reset(new CReflectedVarUser( pVariable->GetHumanName().toUtf8().data()));
}
void ReflectedVarUserAdapter::SyncReflectedVarToIVar(IVariable *pVariable)
{
QString value;
pVariable->Get(value);
m_reflectedVar->m_value = value.toUtf8().data();
//extract the list of custom items from the IVariable user data
IVariable::IGetCustomItems* pGetCustomItems = static_cast<IVariable::IGetCustomItems*> (pVariable->GetUserData().value<void *>());
if (pGetCustomItems != 0)
{
std::vector<IVariable::IGetCustomItems::SItem> items;
QString dlgTitle;
// call the user supplied callback to fill-in items and get dialog title
bool bShowIt = pGetCustomItems->GetItems(pVariable, items, dlgTitle);
if (bShowIt) // if func didn't veto, show the dialog
{
m_reflectedVar->m_enableEdit = true;
m_reflectedVar->m_useTree = pGetCustomItems->UseTree();
m_reflectedVar->m_treeSeparator = pGetCustomItems->GetTreeSeparator();
m_reflectedVar->m_dialogTitle = dlgTitle.toUtf8().data();
m_reflectedVar->m_itemNames.resize(items.size());
m_reflectedVar->m_itemDescriptions.resize(items.size());
QByteArray ba;
int i = -1;
std::generate(m_reflectedVar->m_itemNames.begin(), m_reflectedVar->m_itemNames.end(), [&items, &i, &ba]() { ++i; ba = items[i].name.toUtf8(); return ba.data(); });
i = -1;
std::generate(m_reflectedVar->m_itemDescriptions.begin(), m_reflectedVar->m_itemDescriptions.end(), [&items, &i, &ba]() { ++i; ba = items[i].desc.toUtf8(); return ba.data(); });
}
}
else
{
m_reflectedVar->m_enableEdit = false;
}
}
void ReflectedVarUserAdapter::SyncIVarToReflectedVar(IVariable *pVariable)
{
pVariable->Set(m_reflectedVar->m_value.c_str());
}
ReflectedVarSplineAdapter::ReflectedVarSplineAdapter(ReflectedPropertyItem *parentItem, PropertyType propertyType)
: m_propertyType(propertyType)
, m_bDontSendToControl(false)
, m_parentItem(parentItem)
{
}
void ReflectedVarSplineAdapter::SetVariable(IVariable* pVariable)
{
m_reflectedVar.reset(new CReflectedVarSpline(m_propertyType, pVariable->GetHumanName().toUtf8().data()));
}
void ReflectedVarSplineAdapter::SyncReflectedVarToIVar(IVariable* pVariable)
{
if (!m_bDontSendToControl)
{
m_reflectedVar->m_spline = reinterpret_cast<uint64_t>(pVariable->GetSpline());
}
}
void ReflectedVarSplineAdapter::SyncIVarToReflectedVar(IVariable* pVariable)
{
// Splines update variables directly so don't call OnVariableChange or SetValue here or values will be overwritten.
// Call OnSetValue to force this field to notify this variable that its model has changed without going through the
// full OnVariableChange pass
//
// Set m_bDontSendToControl to prevent the control's data from being overwritten (as the variable's data won't
// necessarily be up to date vs the controls at the point this happens).
m_bDontSendToControl = true;
pVariable->OnSetValue(false);
m_bDontSendToControl = false;
m_parentItem->SendOnItemChange();
}
void ReflectedVarMotionAdapter::SetVariable(IVariable *pVariable)
{
// Create new reflected var
m_reflectedVar.reset(new CReflectedVarMotion(pVariable->GetHumanName().toLatin1().data()));
m_reflectedVar->m_description = pVariable->GetDescription().toLatin1().data();
// Set the asset id
AZStd::string stringGuid = pVariable->GetDisplayValue().toLatin1().data();
AZ::Uuid guid(stringGuid.c_str(), stringGuid.length());
AZ::u32 subId = pVariable->GetUserData().value<AZ::u32>();
m_reflectedVar->m_assetId = AZ::Data::AssetId(guid, subId);
// Lookup Filename by assetId and get the filename part of the description
EBUS_EVENT_RESULT(m_reflectedVar->m_motion, AZ::Data::AssetCatalogRequestBus, GetAssetPathById, m_reflectedVar->m_assetId);
}
void ReflectedVarMotionAdapter::SyncReflectedVarToIVar(IVariable *pVariable)
{
AZStd::string stringGuid = pVariable->GetDisplayValue().toLatin1().data();
AZ::Uuid guid(stringGuid.c_str(), stringGuid.length());
AZ::u32 subId = pVariable->GetUserData().value<AZ::u32>();
m_reflectedVar->m_assetId = AZ::Data::AssetId(guid, subId);
// Lookup Filename by assetId and get the filename part of the description
EBUS_EVENT_RESULT(m_reflectedVar->m_motion, AZ::Data::AssetCatalogRequestBus, GetAssetPathById, m_reflectedVar->m_assetId);
}
void ReflectedVarMotionAdapter::SyncIVarToReflectedVar(IVariable *pVariable)
{
pVariable->SetUserData(m_reflectedVar->m_assetId.m_subId);
pVariable->SetDisplayValue(m_reflectedVar->m_assetId.m_guid.ToString<AZStd::string>().c_str());
}
@@ -0,0 +1,316 @@
/*
* Copyright (c) Contributors to the Open 3D Engine Project
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#ifndef CRYINCLUDE_EDITOR_UTILS_REFLECTEDVARWRAPPER_H
#define CRYINCLUDE_EDITOR_UTILS_REFLECTEDVARWRAPPER_H
#pragma once
#include "Util/Variable.h"
#include <Util/VariablePropertyType.h>
#include "ReflectedVar.h"
#include <QScopedPointer>
struct CUIEnumsDatabase_SEnum;
class ReflectedPropertyItem;
// Class to wrap the CReflectedVars and sync them with corresponding IVariable.
// Most of this code is ported from CPropertyItem functions that marshal data between
// IVariable and editor widgets.
class EDITOR_CORE_API ReflectedVarAdapter
{
public:
virtual ~ReflectedVarAdapter(){};
// update the range limits in CReflectedVar to range specified in IVariable
virtual void UpdateRangeLimits([[maybe_unused]] IVariable* pVariable) {};
//set IVariable for this property and create a CReflectedVar to represent it
virtual void SetVariable(IVariable* pVariable) = 0;
//update the ReflectedVar to current value of IVar
virtual void SyncReflectedVarToIVar(IVariable* pVariable) = 0;
//update the internal IVariable as result of ReflectedVar changing
virtual void SyncIVarToReflectedVar(IVariable* pVariable) = 0;
// Callback called when variable change. SyncReflectedVarToIVar will be called after
virtual void OnVariableChange([[maybe_unused]] IVariable* var) {};
virtual bool UpdateReflectedVarEnums() { return false; }
virtual CReflectedVar* GetReflectedVar() = 0;
//needed for containers that can have new values filled in
virtual void ReplaceVarBlock([[maybe_unused]] CVarBlock* varBlock) {};
virtual bool Contains(CReflectedVar* var) { return GetReflectedVar() == var; }
};
class EDITOR_CORE_API ReflectedVarIntAdapter
: public ReflectedVarAdapter
{
public:
void SetVariable(IVariable* pVariable) override;
void UpdateRangeLimits(IVariable* pVariable) override;
void SyncReflectedVarToIVar(IVariable* pVariable) override;
void SyncIVarToReflectedVar(IVariable* pVariable) override;
CReflectedVar* GetReflectedVar() override { return m_reflectedVar.data(); }
private:
AZ_PUSH_DISABLE_DLL_EXPORT_MEMBER_WARNING
QScopedPointer<CReflectedVarInt > m_reflectedVar;
AZ_POP_DISABLE_DLL_EXPORT_MEMBER_WARNING
float m_valueMultiplier = 1.0f;
};
class EDITOR_CORE_API ReflectedVarFloatAdapter
: public ReflectedVarAdapter
{
public:
void SetVariable(IVariable* pVariable) override;
void UpdateRangeLimits(IVariable* pVariable) override;
void SyncReflectedVarToIVar(IVariable* pVariable) override;
void SyncIVarToReflectedVar(IVariable* pVariable) override;
CReflectedVar* GetReflectedVar() override { return m_reflectedVar.data(); }
private:
AZ_PUSH_DISABLE_DLL_EXPORT_MEMBER_WARNING
QScopedPointer<CReflectedVarFloat > m_reflectedVar;
AZ_POP_DISABLE_DLL_EXPORT_MEMBER_WARNING
float m_valueMultiplier = 1.0f;
};
class EDITOR_CORE_API ReflectedVarStringAdapter
: public ReflectedVarAdapter
{
public:
void SetVariable(IVariable* pVariable) override;
void SyncReflectedVarToIVar(IVariable* pVariable) override;
void SyncIVarToReflectedVar(IVariable* pVariable) override;
CReflectedVar* GetReflectedVar() override { return m_reflectedVar.data(); }
private:
AZ_PUSH_DISABLE_DLL_EXPORT_MEMBER_WARNING
QScopedPointer<CReflectedVarString > m_reflectedVar;
AZ_POP_DISABLE_DLL_EXPORT_MEMBER_WARNING
};
class EDITOR_CORE_API ReflectedVarBoolAdapter
: public ReflectedVarAdapter
{
public:
void SetVariable(IVariable* pVariable) override;
void SyncReflectedVarToIVar(IVariable* pVariable) override;
void SyncIVarToReflectedVar(IVariable* pVariable) override;
CReflectedVar* GetReflectedVar() override { return m_reflectedVar.data(); }
private:
AZ_PUSH_DISABLE_DLL_EXPORT_MEMBER_WARNING
QScopedPointer<CReflectedVarBool > m_reflectedVar;
AZ_POP_DISABLE_DLL_EXPORT_MEMBER_WARNING
};
class EDITOR_CORE_API ReflectedVarEnumAdapter
: public ReflectedVarAdapter
{
public:
ReflectedVarEnumAdapter();
void SetVariable(IVariable* pVariable) override;
void SyncReflectedVarToIVar(IVariable* pVariable) override;
void SyncIVarToReflectedVar(IVariable* pVariable) override;
virtual void OnVariableChange(IVariable* var);
CReflectedVar* GetReflectedVar() override { return m_reflectedVar.data(); }
protected:
//update the ReflectedVar with the allowable enum options
bool UpdateReflectedVarEnums() override;
//virtual function to allow derived classes to update the enum list before syncing with ReflectedVar.
virtual void updateIVariableEnumList([[maybe_unused]] IVariable* pVariable) {};
private:
AZ_PUSH_DISABLE_DLL_EXPORT_MEMBER_WARNING
QScopedPointer<CReflectedVarEnum<AZStd::string> > m_reflectedVar;
AZ_POP_DISABLE_DLL_EXPORT_MEMBER_WARNING
IVariable* m_pVariable;
AZ_PUSH_DISABLE_DLL_EXPORT_MEMBER_WARNING
IVarEnumListPtr m_enumList;
AZ_POP_DISABLE_DLL_EXPORT_MEMBER_WARNING
bool m_updatingEnums;
};
class EDITOR_CORE_API ReflectedVarDBEnumAdapter
: public ReflectedVarAdapter
{
public:
void SetVariable(IVariable* pVariable) override;
void SyncReflectedVarToIVar(IVariable* pVariable) override;
void SyncIVarToReflectedVar(IVariable* pVariable) override;
CReflectedVar* GetReflectedVar() override { return m_reflectedVar.data(); }
private:
AZ_PUSH_DISABLE_DLL_EXPORT_MEMBER_WARNING
QScopedPointer<CReflectedVarEnum<AZStd::string> > m_reflectedVar;
AZ_POP_DISABLE_DLL_EXPORT_MEMBER_WARNING
CUIEnumsDatabase_SEnum* m_pEnumDBItem;
};
class EDITOR_CORE_API ReflectedVarVector2Adapter
: public ReflectedVarAdapter
{
public:
void SetVariable(IVariable* pVariable) override;
void SyncReflectedVarToIVar(IVariable* pVariable) override;
void SyncIVarToReflectedVar(IVariable* pVariable) override;
CReflectedVar* GetReflectedVar() override { return m_reflectedVar.data(); }
private:
AZ_PUSH_DISABLE_DLL_EXPORT_MEMBER_WARNING
QScopedPointer<CReflectedVarVector2 > m_reflectedVar;
AZ_POP_DISABLE_DLL_EXPORT_MEMBER_WARNING
};
class EDITOR_CORE_API ReflectedVarVector3Adapter
: public ReflectedVarAdapter
{
public:
void SetVariable(IVariable* pVariable) override;
void SyncReflectedVarToIVar(IVariable* pVariable) override;
void SyncIVarToReflectedVar(IVariable* pVariable) override;
CReflectedVar* GetReflectedVar() override { return m_reflectedVar.data(); }
private:
AZ_PUSH_DISABLE_DLL_EXPORT_MEMBER_WARNING
QScopedPointer<CReflectedVarVector3 > m_reflectedVar;
AZ_POP_DISABLE_DLL_EXPORT_MEMBER_WARNING
};
class EDITOR_CORE_API ReflectedVarVector4Adapter
: public ReflectedVarAdapter
{
public:
void SetVariable(IVariable* pVariable) override;
void SyncReflectedVarToIVar(IVariable* pVariable) override;
void SyncIVarToReflectedVar(IVariable* pVariable) override;
CReflectedVar* GetReflectedVar() override { return m_reflectedVar.data(); }
private:
AZ_PUSH_DISABLE_DLL_EXPORT_MEMBER_WARNING
QScopedPointer<CReflectedVarVector4 > m_reflectedVar;
AZ_POP_DISABLE_DLL_EXPORT_MEMBER_WARNING
};
class EDITOR_CORE_API ReflectedVarColorAdapter
: public ReflectedVarAdapter
{
public:
void SetVariable(IVariable* pVariable) override;
void SyncReflectedVarToIVar(IVariable* pVariable) override;
void SyncIVarToReflectedVar(IVariable* pVariable) override;
CReflectedVar* GetReflectedVar() override { return m_reflectedVar.data(); }
private:
AZ_PUSH_DISABLE_DLL_EXPORT_MEMBER_WARNING
QScopedPointer<CReflectedVarColor > m_reflectedVar;
AZ_POP_DISABLE_DLL_EXPORT_MEMBER_WARNING
};
class EDITOR_CORE_API ReflectedVarAnimationAdapter
: public ReflectedVarAdapter
{
public:
void SetVariable(IVariable* pVariable) override;
void SyncReflectedVarToIVar(IVariable* pVariable) override;
void SyncIVarToReflectedVar(IVariable* pVariable) override;
CReflectedVar* GetReflectedVar() override { return m_reflectedVar.data(); }
private:
AZ_PUSH_DISABLE_DLL_EXPORT_MEMBER_WARNING
QScopedPointer<CReflectedVarAnimation > m_reflectedVar;
AZ_POP_DISABLE_DLL_EXPORT_MEMBER_WARNING
};
class EDITOR_CORE_API ReflectedVarResourceAdapter
: public ReflectedVarAdapter
{
public:
void SetVariable(IVariable* pVariable) override;
void SyncReflectedVarToIVar(IVariable* pVariable) override;
void SyncIVarToReflectedVar(IVariable* pVariable) override;
CReflectedVar* GetReflectedVar() override { return m_reflectedVar.data(); }
private:
AZ_PUSH_DISABLE_DLL_EXPORT_MEMBER_WARNING
QScopedPointer<CReflectedVarResource> m_reflectedVar;
AZ_POP_DISABLE_DLL_EXPORT_MEMBER_WARNING
};
class EDITOR_CORE_API ReflectedVarUserAdapter
: public ReflectedVarAdapter
{
public:
void SetVariable(IVariable *pVariable) override;
void SyncReflectedVarToIVar(IVariable *pVariable) override;
void SyncIVarToReflectedVar(IVariable *pVariable) override;
CReflectedVar *GetReflectedVar() override {
return m_reflectedVar.data();
}
private:
AZ_PUSH_DISABLE_DLL_EXPORT_MEMBER_WARNING
QScopedPointer<CReflectedVarUser> m_reflectedVar;
AZ_POP_DISABLE_DLL_EXPORT_MEMBER_WARNING
};
class EDITOR_CORE_API ReflectedVarSplineAdapter
: public ReflectedVarAdapter
{
public:
ReflectedVarSplineAdapter(ReflectedPropertyItem *parentItem, PropertyType propertyType);
void SetVariable(IVariable* pVariable) override;
void SyncReflectedVarToIVar(IVariable* pVariable) override;
void SyncIVarToReflectedVar(IVariable* pVariable) override;
CReflectedVar* GetReflectedVar() override {
return m_reflectedVar.data();
}
private:
AZ_PUSH_DISABLE_DLL_EXPORT_MEMBER_WARNING
QScopedPointer<CReflectedVarSpline > m_reflectedVar;
AZ_POP_DISABLE_DLL_EXPORT_MEMBER_WARNING
bool m_bDontSendToControl;
PropertyType m_propertyType;
ReflectedPropertyItem *m_parentItem;
};
class EDITOR_CORE_API ReflectedVarGenericPropertyAdapter
: public ReflectedVarAdapter
{
public:
ReflectedVarGenericPropertyAdapter(PropertyType propertyType);
void SetVariable(IVariable* pVariable) override;
void SyncReflectedVarToIVar(IVariable* pVariable) override;
void SyncIVarToReflectedVar(IVariable* pVariable) override;
CReflectedVar* GetReflectedVar() override { return m_reflectedVar.data(); }
private:
AZ_PUSH_DISABLE_DLL_EXPORT_MEMBER_WARNING
QScopedPointer<CReflectedVarGenericProperty > m_reflectedVar;
AZ_POP_DISABLE_DLL_EXPORT_MEMBER_WARNING
PropertyType m_propertyType;
};
class EDITOR_CORE_API ReflectedVarMotionAdapter
: public ReflectedVarAdapter
{
public:
void SetVariable(IVariable* pVariable) override;
void SyncReflectedVarToIVar(IVariable* pVariable) override;
void SyncIVarToReflectedVar(IVariable* pVariable) override;
CReflectedVar* GetReflectedVar() override { return m_reflectedVar.data(); }
private:
AZ_PUSH_DISABLE_DLL_EXPORT_MEMBER_WARNING
QScopedPointer<CReflectedVarMotion > m_reflectedVar;
AZ_POP_DISABLE_DLL_EXPORT_MEMBER_WARNING
};
#endif // CRYINCLUDE_EDITOR_UTILS_REFLECTEDVARWRAPPER_H
@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:1e7fb0db541a13f6f6b6f494f133f72e05c847508bdf69e1bc63dcf8eb4aa752
size 311
@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:124de9138d3af8e14a49944245d7245df4065c49ad1e5ec1d8377600933558c5
size 370