Created a toggle switch to enable and disable groups through the EditContext

Signed-off-by: Jose <jotamkin@amazon.com>
monroegm-disable-blank-issue-2
Jose 5 years ago
parent ab354f2e9b
commit 0502475fa6

@ -235,6 +235,17 @@ namespace AZ
*/
ClassBuilder* ClassElement(Crc32 elementIdCrc, const char* description);
/**
* Declare element with attributes that belong to the class SerializeContext::Class, this is a logical structure, you can have one or more ClassElements.
* \uiId is the logical element ID (for instance "Group" when you want to group certain elements this class.
* then in each DataElement you can attach the appropriate group attribute.
* \param memberVariable - reference to the member variable to we can bind to serializations data.
*/
template<class T>
ClassBuilder* ClassElement(Crc32 elementIdCrc, const char* description, T memberVariable);
/**
* Declare element with an associated UI handler that does not represent a specific class member variable.
* \param uiId - name of a UI handler used to display the element
@ -514,6 +525,54 @@ namespace AZ
return this;
}
//=========================================================================
// ClassElement
//=========================================================================
template<class T>
inline EditContext::ClassBuilder* EditContext::ClassBuilder::ClassElement(Crc32 elementIdCrc, const char* description, T memberVariable)
{
if (IsValid())
{
using ElementTypeInfo = typename SerializeInternal::ElementInfo<T>;
AZ_Assert(
m_classData->m_typeId == AzTypeInfo<typename ElementTypeInfo::ClassType>::Uuid(),
"Data element (%s) belongs to a different class!", description);
// Not really portable but works for the supported compilers
size_t offset =
reinterpret_cast<size_t>(&(reinterpret_cast<typename ElementTypeInfo::ClassType const volatile*>(0)->*memberVariable));
// offset = or pass it to the function with offsetof(typename ElementTypeInfo::ClassType,memberVariable);
SerializeContext::ClassElement* classElement = nullptr;
for (size_t i = 0; i < m_classData->m_elements.size(); ++i)
{
SerializeContext::ClassElement* element = &m_classData->m_elements[i];
if (element->m_offset == offset)
{
classElement = element;
break;
}
}
// We cannot continue past this point, we must alert the user to fix their serialization config and crash
AZ_Assert(
classElement,
"Class element for editor data element reflection '%s' was NOT found in the serialize context! This member MUST be "
"serializable to be editable!",
description);
m_classElement->m_elements.push_back();
Edit::ElementData& ed = m_classElement->m_elements.back();
classElement->m_editData = &ed;
m_editElement = &ed;
ed.m_elementId = elementIdCrc;
ed.m_name = description;
ed.m_description = description;
ed.m_serializeClassElement = classElement;
}
return this;
}
//=========================================================================
// UIElement
//=========================================================================

@ -546,7 +546,7 @@ namespace AzToolsFramework
for (auto& element : nodeEditData->m_elements)
{
if (element.IsClassElement() && element.m_elementId == AZ::Edit::ClassElements::Group)
if (element.m_elementId == AZ::Edit::ClassElements::Group)
{
groupData = (element.m_description && element.m_description[0]) ? &element : nullptr;
continue;
@ -1112,13 +1112,13 @@ namespace AzToolsFramework
const AZ::Edit::ElementData* groupData = nullptr;
for (const AZ::Edit::ElementData& elementData : parentEditData->m_elements)
{
if (node->m_elementEditData == &elementData) // this element matches this node
if ((node->m_elementEditData == &elementData) && (elementData.m_elementId != AZ::Edit::ClassElements::Group)) // this element matches this node
{
// Record the last found group data
node->m_groupElementData = groupData;
break;
}
else if (elementData.IsClassElement() && elementData.m_elementId == AZ::Edit::ClassElements::Group)
else if (elementData.m_elementId == AZ::Edit::ClassElements::Group)
{
if (!elementData.m_description || !elementData.m_description[0])
{ // close the group

@ -12,6 +12,7 @@
#include <AzFramework/StringFunc/StringFunc.h>
#include <AzToolsFramework/UI/UICore/WidgetHelpers.h>
#include <AzToolsFramework/UI/PropertyEditor/PropertyCheckBoxCtrl.hxx>
AZ_PUSH_DISABLE_WARNING(4244 4251 4800, "-Wunknown-warning-option") // 4244: conversion from 'int' to 'float', possible loss of data
// 4251: class '...' needs to have dll-interface to be used by clients of class 'QInputEvent'
@ -141,6 +142,11 @@ namespace AzToolsFramework
m_treeDepth = 0;
delete m_dropDownArrow;
if (m_toggleSwitch)
{
m_handler->DestroyGUI(m_toggleSwitch);
m_toggleSwitch = nullptr;
}
if (m_childWidget)
{
@ -387,6 +393,13 @@ namespace AzToolsFramework
setUpdatesEnabled(true);
}
void PropertyRowWidget::InitializeToggleGroup(const char* groupName, PropertyRowWidget* pParent, int depth, InstanceDataNode* node, int labelWidth)
{
Initialize(groupName, pParent, depth, labelWidth);
ChangeSourceNode(node);
CreateGroupToggleSwitch();
}
void PropertyRowWidget::Initialize(const char* groupName, PropertyRowWidget* pParent, int depth, int labelWidth)
{
Initialize(pParent, nullptr, depth, labelWidth);
@ -1102,6 +1115,19 @@ namespace AzToolsFramework
}
}
void PropertyRowWidget::CreateGroupToggleSwitch()
{
if (!m_toggleSwitch)
{
m_handlerName = AZ::Edit::UIHandlers::CheckBox;
EBUS_EVENT_RESULT(m_handler, PropertyTypeRegistrationMessages::Bus, ResolvePropertyHandler, m_handlerName, azrtti_typeid<bool>());
m_toggleSwitch = m_handler->CreateGUI(this);
m_middleLayout->insertWidget(0, m_toggleSwitch, 1);
auto checkBoxCtrl = reinterpret_cast<AzToolsFramework::PropertyCheckBoxCtrl*>(m_toggleSwitch);
QObject::connect(checkBoxCtrl, &AzToolsFramework::PropertyCheckBoxCtrl::valueChanged, this, &PropertyRowWidget::OnClickedToggleButton);
}
}
void PropertyRowWidget::SetIndentSize(int w)
{
m_indent->changeSize(w, 1, QSizePolicy::Fixed, QSizePolicy::Fixed);
@ -1110,6 +1136,18 @@ namespace AzToolsFramework
m_leftHandSideLayout->activate();
}
void PropertyRowWidget::OnClickedToggleButton(bool checked)
{
if ((m_expanded && !checked) || (!m_expanded && checked))
{
DoExpandOrContract(!IsExpanded(), 0 != (QGuiApplication::keyboardModifiers() & Qt::ControlModifier));
}
}
void PropertyRowWidget::ChangeSourceNode(InstanceDataNode* node)
{
m_sourceNode = node;
}
void PropertyRowWidget::SetExpanded(bool expanded)
{

@ -48,6 +48,7 @@ namespace AzToolsFramework
virtual void Initialize(PropertyRowWidget* pParent, InstanceDataNode* dataNode, int depth, int labelWidth = 200);
virtual void Initialize(const char* groupName, PropertyRowWidget* pParent, int depth, int labelWidth = 200);
virtual void InitializeToggleGroup(const char* groupName, PropertyRowWidget* pParent, int depth, InstanceDataNode* node, int labelWidth = 200);
virtual void Clear(); // for pooling
// --- NOT A UNIQUE IDENTIFIER ---
@ -141,11 +142,13 @@ namespace AzToolsFramework
QVBoxLayout* GetLeftHandSideLayoutParent() { return m_leftHandSideLayoutParent; }
QToolButton* GetIndicatorButton() { return m_indicatorButton; }
QLabel* GetNameLabel() { return m_nameLabel; }
QWidget* GetToggle() { return m_toggleSwitch; }
void SetIndentSize(int w);
void SetAsCustom(bool custom) { m_custom = custom; }
bool CanChildrenBeReordered() const;
bool CanBeReordered() const;
protected:
int CalculateLabelWidth() const;
@ -175,6 +178,8 @@ namespace AzToolsFramework
QLabel* m_defaultLabel; // if there is no handler, we use a m_defaultLabel label
InstanceDataNode* m_sourceNode;
QWidget* m_toggleSwitch = nullptr;
QString m_currentFilterString;
struct ChangeNotification
@ -239,6 +244,8 @@ namespace AzToolsFramework
void mouseDoubleClickEvent(QMouseEvent* event) override;
void UpdateDropDownArrow();
void CreateGroupToggleSwitch();
void ChangeSourceNode(InstanceDataNode* node);
void UpdateDefaultLabel(InstanceDataNode* node);
void createContainerButtons();
@ -257,6 +264,7 @@ namespace AzToolsFramework
private slots:
void OnClickedExpansionButton();
void OnClickedToggleButton(bool checked);
void OnClickedAddElementButton();
void OnClickedRemoveElementButton();
void OnClickedClearContainerButton();

@ -167,6 +167,8 @@ namespace AzToolsFramework
InstanceDataHierarchyList m_instances; ///< List of instance sets to display, other one can aggregate other instances.
InstanceDataHierarchy::ValueComparisonFunction m_valueComparisonFunction;
ReflectedPropertyEditor::WidgetList m_widgets;
ReflectedPropertyEditor::SpecialGroupWidgetList m_specialGroupWidgets;
InstanceDataNode* groupSourceNode = nullptr;
RowContainerType m_widgetsInDisplayOrder;
UserWidgetToDataMap m_userWidgetsToData;
VisibilityCallback m_visibilityCallback;
@ -507,7 +509,25 @@ namespace AzToolsFramework
{
widgetEntry = CreateOrPullFromPool();
widgetEntry->SetFilterString(m_editor->GetFilterString());
widgetEntry->Initialize(groupName, parent, depth, m_propertyLabelWidth);
// Initialized normally if the group does not have a member variable attached to it,
// otherwise initialize it as a group that will have a toggle switch.
if (groupElementData->IsClassElement())
{
widgetEntry->Initialize(groupName, parent, depth, m_propertyLabelWidth);
}
else
{
widgetEntry->InitializeToggleGroup(groupName, parent, depth, groupSourceNode, m_propertyLabelWidth);
QWidget* toggleSwitch = widgetEntry->GetToggle();
PropertyHandlerBase* pHandler = widgetEntry->GetHandler();
m_userWidgetsToData[toggleSwitch] = groupSourceNode;
m_specialGroupWidgets[groupSourceNode] = widgetEntry;
pHandler->ConsumeAttributes_Internal(toggleSwitch, groupSourceNode);
pHandler->ReadValuesIntoGUI_Internal(toggleSwitch, groupSourceNode);
widgetEntry->OnValuesUpdated();
}
widgetEntry->SetLeafIndentation(m_leafIndentation);
widgetEntry->SetTreeIndentation(m_treeIndentation);
widgetEntry->setObjectName(groupName);
@ -606,7 +626,7 @@ namespace AzToolsFramework
// creates and populates the GUI to edit the property if not already created
void ReflectedPropertyEditor::Impl::CreateEditorWidget(PropertyRowWidget* pWidget)
{
if (!pWidget->HasChildWidgetAlready())
if ((!pWidget->HasChildWidgetAlready()) && (!pWidget->GetToggle()))
{
PropertyHandlerBase* pHandler = pWidget->GetHandler();
if (pHandler)
@ -733,36 +753,44 @@ namespace AzToolsFramework
}
}
}
if ((!node->GetElementEditMetadata()) || (node->GetElementEditMetadata()->m_elementId != AZ::Edit::ClassElements::Group))
{
pWidget = CreateOrPullFromPool();
pWidget->show();
pWidget = CreateOrPullFromPool();
pWidget->show();
pWidget->SetFilterString(m_editor->GetFilterString());
pWidget->Initialize(pParent, node, depth, m_propertyLabelWidth);
pWidget->SetFilterString(m_editor->GetFilterString());
pWidget->Initialize(pParent, node, depth, m_propertyLabelWidth);
if (labelOverride != "")
{
pWidget->SetNameLabel(labelOverride.data());
}
if (labelOverride != "")
{
pWidget->SetNameLabel(labelOverride.data());
}
pWidget->setObjectName(pWidget->label());
pWidget->SetSelectionEnabled(m_selectionEnabled);
pWidget->SetLeafIndentation(m_leafIndentation);
pWidget->SetTreeIndentation(m_treeIndentation);
pWidget->setObjectName(pWidget->label());
pWidget->SetSelectionEnabled(m_selectionEnabled);
pWidget->SetLeafIndentation(m_leafIndentation);
pWidget->SetTreeIndentation(m_treeIndentation);
m_widgets[node] = pWidget;
m_widgetsInDisplayOrder.insert(widgetDisplayOrder, pWidget);
m_widgets[node] = pWidget;
m_widgetsInDisplayOrder.insert(widgetDisplayOrder, pWidget);
if (pParent)
{
pParent->AddedChild(pWidget);
}
if (pParent)
{
pParent->AddedChild(pWidget);
if (pParent || !m_hideRootProperties)
{
depth += 1;
}
pParent = pWidget;
}
if (pParent || !m_hideRootProperties)
// Save the last InstanceDataNode that is a Group ClassElement so that we can use it as the source node for its widget.
if ((node->GetElementEditMetadata()) && (node->GetElementEditMetadata()->m_elementId == AZ::Edit::ClassElements::Group))
{
depth += 1;
groupSourceNode = node;
}
pParent = pWidget;
}
}
@ -1000,6 +1028,26 @@ namespace AzToolsFramework
pWidget->UpdateIndicator(m_impl->m_indicatorQueryFunction(pWidget->GetNode()));
}
}
for (auto it = m_impl->m_specialGroupWidgets.begin(); it != m_impl->m_specialGroupWidgets.end(); ++it)
{
PropertyRowWidget* pWidget = it->second;
QWidget* childWidget = pWidget->GetChildWidget();
if (pWidget->GetHandler() && childWidget)
{
pWidget->GetHandler()->ConsumeAttributes_Internal(childWidget, it->first);
pWidget->GetHandler()->ReadValuesIntoGUI_Internal(childWidget, it->first);
pWidget->OnValuesUpdated();
}
pWidget->RefreshAttributesFromNode(false);
if (m_impl->m_indicatorQueryFunction)
{
pWidget->UpdateIndicator(m_impl->m_indicatorQueryFunction(pWidget->GetNode()));
}
}
}
void ReflectedPropertyEditor::InvalidateValues()
@ -1356,8 +1404,14 @@ namespace AzToolsFramework
// get the property editor
auto rowWidget = m_widgets.find(it->second);
if (rowWidget != m_widgets.end())
auto rowWidgetGroup = m_specialGroupWidgets.find(it->second);
if (rowWidget != m_widgets.end() || rowWidgetGroup != m_specialGroupWidgets.end())
{
if (rowWidget == m_widgets.end())
{
rowWidget = rowWidgetGroup;
}
InstanceDataNode* node = rowWidget->first;
PropertyRowWidget* widget = rowWidget->second;
PropertyHandlerBase* handler = widget->GetHandler();

@ -50,6 +50,8 @@ namespace AzToolsFramework
typedef AZStd::unordered_map<InstanceDataNode*, PropertyRowWidget*> WidgetList;
typedef AZStd::unordered_map<InstanceDataNode*, PropertyRowWidget*> SpecialGroupWidgetList;
ReflectedPropertyEditor(QWidget* pParent);
virtual ~ReflectedPropertyEditor();
@ -61,6 +63,7 @@ namespace AzToolsFramework
bool AddInstance(void* instance, const AZ::Uuid& classId, void* aggregateInstance = nullptr, void* compareInstance = nullptr);
void SetCompareInstance(void* instance, const AZ::Uuid& classId);
void ClearInstances();
void ReadValuesIntoGui(QWidget* widget, InstanceDataNode* node);
template<class T>
bool AddInstance(T* instance, void* aggregateInstance = nullptr, void* compareInstance = nullptr)
{

@ -61,8 +61,9 @@ namespace GradientSignal
->DataElement(0, &GradientSampler::m_invertInput, "Invert Input", "")
->Attribute(AZ::Edit::Attributes::ChangeNotify, &GradientSampler::ChangeNotify)
->DataElement(0, &GradientSampler::m_enableTransform, "Enable Transform", "")
->Attribute(AZ::Edit::Attributes::ChangeNotify, &GradientSampler::ChangeNotify)
->ClassElement(AZ::Edit::ClassElements::Group, "Enable Transform", &GradientSampler::m_enableTransform)
->Attribute(AZ::Edit::Attributes::AutoExpand, false)
->DataElement(0, &GradientSampler::m_translate, "Translate", "")
->Attribute(AZ::Edit::Attributes::ReadOnly, &GradientSampler::AreTransformSettingsDisabled)
->Attribute(AZ::Edit::Attributes::ChangeNotify, &GradientSampler::ChangeNotify)
@ -73,8 +74,8 @@ namespace GradientSignal
->Attribute(AZ::Edit::Attributes::ReadOnly, &GradientSampler::AreTransformSettingsDisabled)
->Attribute(AZ::Edit::Attributes::ChangeNotify, &GradientSampler::ChangeNotify)
->DataElement(0, &GradientSampler::m_enableLevels, "Enable Levels", "")
->Attribute(AZ::Edit::Attributes::ChangeNotify, &GradientSampler::ChangeNotify)
->ClassElement(AZ::Edit::ClassElements::Group, "Enable Levels", &GradientSampler::m_enableLevels)
->Attribute(AZ::Edit::Attributes::AutoExpand, false)
->DataElement(AZ::Edit::UIHandlers::Slider, &GradientSampler::m_inputMid, "Input Mid", "")
->Attribute(AZ::Edit::Attributes::Min, 0.0f)
->Attribute(AZ::Edit::Attributes::Max, 10.0f)

Loading…
Cancel
Save