Initial commit

This commit is contained in:
alexpete
2021-03-05 11:26:34 -08:00
commit a10351f38d
27091 changed files with 5521199 additions and 0 deletions
@@ -0,0 +1,88 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#include <AzCore/EBus/EBus.h>
#include <AzToolsFramework/Debug/TraceContext.h>
#include <SceneAPI/SceneUI/RowWidgets/HeaderHandler.h>
namespace AZ
{
namespace SceneAPI
{
namespace UI
{
AZ_CLASS_ALLOCATOR_IMPL(HeaderHandler, SystemAllocator, 0)
HeaderHandler* HeaderHandler::s_instance = nullptr;
QWidget* HeaderHandler::CreateGUI(QWidget* parent)
{
return aznew HeaderWidget(parent);
}
u32 HeaderHandler::GetHandlerName() const
{
return AZ_CRC("Header", 0x6e72a8c1);
}
bool HeaderHandler::AutoDelete() const
{
return false;
}
bool HeaderHandler::IsDefaultHandler() const
{
return true;
}
void HeaderHandler::ConsumeAttribute(HeaderWidget* /*widget*/, u32 /*attrib*/,
AzToolsFramework::PropertyAttributeReader* /*attrValue*/, const char* /*debugName*/)
{
// No attributes are used by this handler, but the function is mandatory.
}
void HeaderHandler::WriteGUIValuesIntoProperty(size_t /*index*/, HeaderWidget* GUI,
property_t& instance, AzToolsFramework::InstanceDataNode* /*node*/)
{
instance = *GUI->GetManifestObject();
}
bool HeaderHandler::ReadValuesIntoGUI(size_t /*index*/, HeaderWidget* GUI, const property_t& instance,
AzToolsFramework::InstanceDataNode* /*node*/)
{
GUI->SetManifestObject(&instance);
return false;
}
void HeaderHandler::Register()
{
if (!s_instance)
{
s_instance = aznew HeaderHandler();
EBUS_EVENT(AzToolsFramework::PropertyTypeRegistrationMessages::Bus, RegisterPropertyType, s_instance);
}
}
void HeaderHandler::Unregister()
{
if (s_instance)
{
EBUS_EVENT(AzToolsFramework::PropertyTypeRegistrationMessages::Bus, UnregisterPropertyType, s_instance);
delete s_instance;
s_instance = nullptr;
}
}
} // UI
} // SceneAPI
} // AZ
#include <RowWidgets/moc_HeaderHandler.cpp>
@@ -0,0 +1,69 @@
#pragma once
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#if !defined(Q_MOC_RUN)
#include <AzCore/Math/Crc.h>
#include <AzCore/Memory/SystemAllocator.h>
#include <AzToolsFramework/UI/PropertyEditor/PropertyEditorAPI.h>
#include <SceneAPI/SceneUI/RowWidgets/HeaderWidget.h>
#include <SceneAPI/SceneData/Groups/MeshGroup.h>
#endif
class QWidget;
/*
=============================================================
= Handler Documentation =
=============================================================
Handler Name: "Header"
*/
namespace AZ
{
namespace SceneAPI
{
namespace UI
{
class HeaderHandler
: public QObject, public AzToolsFramework::PropertyHandler<DataTypes::IManifestObject, HeaderWidget>
{
Q_OBJECT
public:
AZ_CLASS_ALLOCATOR_DECL
QWidget* CreateGUI(QWidget* parent) override;
u32 GetHandlerName() const override;
bool AutoDelete() const override;
bool IsDefaultHandler() const override;
void ConsumeAttribute(HeaderWidget* widget, u32 attrib,
AzToolsFramework::PropertyAttributeReader* attrValue, const char* debugName) override;
void WriteGUIValuesIntoProperty(size_t index, HeaderWidget* GUI, property_t& instance,
AzToolsFramework::InstanceDataNode* node) override;
bool ReadValuesIntoGUI(size_t index, HeaderWidget* GUI, const property_t& instance,
AzToolsFramework::InstanceDataNode* node) override;
static void Register();
static void Unregister();
private:
static HeaderHandler* s_instance;
};
} // UI
} // SceneAPI
} // AZ
@@ -0,0 +1,205 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#include <QEvent>
#include <RowWidgets/ui_HeaderWidget.h>
#include <AzCore/EBus/EBus.h>
#include <AzCore/Component/ComponentApplicationBus.h>
#include <AzCore/Serialization/SerializeContext.h>
#include <AzToolsFramework/UI/PropertyEditor/PropertyEditorAPI.h>
#include <AzToolsFramework/Debug/TraceContext.h>
#include <SceneAPI/SceneCore/Containers/Scene.h>
#include <SceneAPI/SceneCore/Containers/SceneManifest.h>
#include <SceneAPI/SceneCore/Utilities/Reporting.h>
#include <SceneAPI/SceneCore/Events/ManifestMetaInfoBus.h>
#include <SceneAPI/SceneUI/RowWidgets/HeaderWidget.h>
#include <SceneAPI/SceneUI/RowWidgets/ManifestVectorWidget.h>
#include <SceneAPI/SceneUI/SceneWidgets/ManifestWidget.h>
static void InitSceneUIHeaderWidgetResources()
{
Q_INIT_RESOURCE(Icons);
}
namespace AZ
{
namespace SceneAPI
{
namespace UI
{
AZ_CLASS_ALLOCATOR_IMPL(HeaderWidget, SystemAllocator, 0)
HeaderWidget::HeaderWidget(QWidget* parent)
: QWidget(parent)
, ui(new Ui::HeaderWidget())
, m_target(nullptr)
, m_nameIsEditable(false)
, m_sceneManifest(nullptr)
{
InitSceneUIHeaderWidgetResources();
ui->setupUi(this);
ui->m_icon->hide();
ui->m_deleteButton->setIcon(QIcon(":/PropertyEditor/Resources/cross-small.png"));
connect(ui->m_deleteButton, &QToolButton::clicked, this, &HeaderWidget::DeleteObject);
ui->m_deleteButton->hide();
ManifestWidget* root = ManifestWidget::FindRoot(this);
AZ_Assert(root, "HeaderWidget is not a child of the ManifestWidget");
if (root)
{
m_sceneManifest = &root->GetScene()->GetManifest();
}
}
void HeaderWidget::SetManifestObject(const DataTypes::IManifestObject* target)
{
AZ_TraceContext("New target", GetSerializedName(target));
m_target = target;
ui->m_nameLabel->setText(GetSerializedName(target));
UpdateDeletable();
SetIcon(target);
}
const DataTypes::IManifestObject* HeaderWidget::GetManifestObject() const
{
return m_target;
}
void HeaderWidget::DeleteObject()
{
AZ_TraceContext("Delete target", GetSerializedName(m_target));
if (m_sceneManifest)
{
Containers::SceneManifest::Index index = m_sceneManifest->FindIndex(m_target);
if (index != Containers::SceneManifest::s_invalidIndex)
{
AZ_TraceContext("Manifest index", static_cast<int>(index));
ManifestWidget* root = ManifestWidget::FindRoot(this);
// The manifest object could be a root element at the manifest page level so it needs to be
// removed from there as well in that case.
if (root->RemoveObject(m_sceneManifest->GetValue(index)) && m_sceneManifest->RemoveEntry(m_target))
{
m_target = nullptr;
// Hide and disable the button so when users spam the delete button only a single click is recorded.
ui->m_deleteButton->hide();
ui->m_deleteButton->setEnabled(false);
return;
}
else
{
AZ_TracePrintf(Utilities::LogWindow, "Unable to delete manifest object from manifest.");
}
}
}
QObject* widget = this->parent();
while (widget != nullptr)
{
ManifestVectorWidget* manifestVectorWidget = qobject_cast<ManifestVectorWidget*>(widget);
if (manifestVectorWidget)
{
if (manifestVectorWidget->RemoveManifestObject(m_target))
{
m_target = nullptr;
// Hide and disable the button so when users spam the delete button only a single click is recorded.
ui->m_deleteButton->hide();
ui->m_deleteButton->setEnabled(false);
}
else
{
AZ_TracePrintf(Utilities::WarningWindow, "Parent collection did not contain this ManifestObject");
}
return;
}
widget = widget->parent();
}
AZ_TracePrintf(Utilities::ErrorWindow, "No parent valid parent collection found.");
}
void HeaderWidget::UpdateDeletable()
{
ui->m_deleteButton->hide();
if (m_sceneManifest)
{
Containers::SceneManifest::Index index = m_sceneManifest->FindIndex(m_target);
if (index != Containers::SceneManifest::s_invalidIndex)
{
ui->m_deleteButton->show();
return;
}
}
QObject* widget = this->parent();
while(widget != nullptr)
{
ManifestVectorWidget* manifestVectorWidget = qobject_cast<ManifestVectorWidget*>(widget);
if (manifestVectorWidget && manifestVectorWidget->ContainsManifestObject(m_target))
{
ui->m_deleteButton->show();
break;
}
widget = widget->parent();
}
}
const char* HeaderWidget::GetSerializedName(const DataTypes::IManifestObject* target) const
{
SerializeContext* context = nullptr;
EBUS_EVENT_RESULT(context, ComponentApplicationBus, GetSerializeContext);
if (context)
{
const SerializeContext::ClassData* classData = context->FindClassData(target->RTTI_GetType());
if (classData)
{
if (classData->m_editData)
{
return classData->m_editData->m_name;
}
return classData->m_name;
}
}
return "<type not registered>";
}
void HeaderWidget::SetIcon(const DataTypes::IManifestObject* target)
{
if (!target)
{
return;
}
AZStd::string iconPath;
EBUS_EVENT(Events::ManifestMetaInfoBus, GetIconPath, iconPath, *target);
if (iconPath.empty())
{
ui->m_icon->hide();
}
else
{
ui->m_icon->setPixmap(QPixmap(iconPath.c_str()));
ui->m_icon->show();
}
}
} // UI
} // SceneAPI
} // AZ
#include <RowWidgets/moc_HeaderWidget.cpp>
@@ -0,0 +1,74 @@
#pragma once
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#if !defined(Q_MOC_RUN)
#include <QWidget>
#include <AzCore/std/string/string.h>
#include <AzCore/Memory/SystemAllocator.h>
#endif
namespace AZ
{
namespace SceneAPI
{
namespace Containers
{
class SceneManifest;
}
namespace DataTypes
{
class IManifestObject;
}
namespace UI
{
// QT space
namespace Ui
{
class HeaderWidget;
}
class HeaderWidget : public QWidget
{
Q_OBJECT
public:
AZ_CLASS_ALLOCATOR_DECL
enum NameStack
{
Label,
EditField
};
explicit HeaderWidget(QWidget* parent);
void SetManifestObject(const DataTypes::IManifestObject* target);
const DataTypes::IManifestObject* GetManifestObject() const;
protected:
bool InitSceneManifest();
virtual void DeleteObject();
virtual void UpdateDeletable();
virtual const char* GetSerializedName(const DataTypes::IManifestObject* target) const;
virtual void SetIcon(const DataTypes::IManifestObject* target);
AZStd::string m_objectName;
QScopedPointer<Ui::HeaderWidget> ui;
Containers::SceneManifest* m_sceneManifest; // Reference only, does not point to a local instance.
const DataTypes::IManifestObject* m_target; // Reference only, does not point to a local instance.
bool m_nameIsEditable;
};
} // namespace UI
} // namespace SceneAPI
} // namespace AZ
@@ -0,0 +1,78 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>AZ::SceneAPI::UI::HeaderWidget</class>
<widget class="QWidget" name="AZ::SceneAPI::UI::HeaderWidget">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>150</width>
<height>20</height>
</rect>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>20</verstretch>
</sizepolicy>
</property>
<layout class="QHBoxLayout" name="horizontalLayout">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QLabel" name="m_icon">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>16</horstretch>
<verstretch>16</verstretch>
</sizepolicy>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="m_nameLabel">
<property name="text">
<string>Name label</string>
</property>
</widget>
</item>
<item>
<widget class="QToolButton" name="m_deleteButton">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>16</horstretch>
<verstretch>16</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>16</width>
<height>16</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>16</width>
<height>16</height>
</size>
</property>
<property name="toolTip">
<string>Delete this entry</string>
</property>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>
@@ -0,0 +1,108 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#include <AzCore/EBus/EBus.h>
#include <AzToolsFramework/Debug/TraceContext.h>
#include <SceneAPI/SceneUI/RowWidgets/ManifestNameHandler.h>
namespace AZ
{
namespace SceneAPI
{
namespace SceneUI
{
AZ_CLASS_ALLOCATOR_IMPL(ManifestNameHandler, SystemAllocator, 0)
ManifestNameHandler* ManifestNameHandler::s_instance = nullptr;
QWidget* ManifestNameHandler::CreateGUI(QWidget* parent)
{
ManifestNameWidget* instance = aznew ManifestNameWidget(parent);
connect(instance, &ManifestNameWidget::valueChanged, this,
[instance]()
{
EBUS_EVENT(AzToolsFramework::PropertyEditorGUIMessages::Bus, RequestWrite, instance);
});
return instance;
}
u32 ManifestNameHandler::GetHandlerName() const
{
return AZ_CRC("ManifestName", 0x5215b349);
}
bool ManifestNameHandler::AutoDelete() const
{
return false;
}
void ManifestNameHandler::ConsumeAttribute(ManifestNameWidget* widget, u32 attrib,
AzToolsFramework::PropertyAttributeReader* attrValue, const char* debugName)
{
AZ_TraceContext("Attribute name", debugName);
if (attrib == AZ_CRC("FilterType", 0x2661cf01))
{
ConsumeFilterTypeAttribute(widget, attrValue);
}
}
void ManifestNameHandler::WriteGUIValuesIntoProperty(size_t /*index*/, ManifestNameWidget* GUI,
property_t& instance, AzToolsFramework::InstanceDataNode* /*node*/)
{
instance = static_cast<property_t>(GUI->GetName());
}
bool ManifestNameHandler::ReadValuesIntoGUI(size_t /*index*/, ManifestNameWidget* GUI, const property_t& instance,
AzToolsFramework::InstanceDataNode* /*node*/)
{
GUI->SetName(instance);
return false;
}
void ManifestNameHandler::Register()
{
if (!s_instance)
{
s_instance = aznew ManifestNameHandler();
EBUS_EVENT(AzToolsFramework::PropertyTypeRegistrationMessages::Bus, RegisterPropertyType, s_instance);
}
}
void ManifestNameHandler::Unregister()
{
if (s_instance)
{
EBUS_EVENT(AzToolsFramework::PropertyTypeRegistrationMessages::Bus, UnregisterPropertyType, s_instance);
delete s_instance;
s_instance = nullptr;
}
}
void ManifestNameHandler::ConsumeFilterTypeAttribute(ManifestNameWidget* widget,
AzToolsFramework::PropertyAttributeReader* attrValue)
{
Uuid filterType;
if (attrValue->Read<Uuid>(filterType))
{
widget->SetFilterType(filterType);
}
else
{
AZ_Assert(false, "Failed to read uuid from 'FilterType' attribute.");
}
}
} // SceneUI
} // SceneAPI
} // AZ
#include <RowWidgets/moc_ManifestNameHandler.cpp>
@@ -0,0 +1,62 @@
#pragma once
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#if !defined(Q_MOC_RUN)
#include <AzCore/Memory/SystemAllocator.h>
#include <AzToolsFramework/UI/PropertyEditor/PropertyEditorAPI.h>
#include <SceneAPI/SceneUI/RowWidgets/ManifestNameWidget.h>
#endif
class QWidget;
namespace AZ
{
namespace SceneAPI
{
namespace SceneUI
{
//Available Attributes:
// - "FilterType" - Uuid for the type(s) to filter for. If set, the name will only be unique for
// classes of this type or derived classes.
class ManifestNameHandler
: public QObject, public AzToolsFramework::PropertyHandler<AZStd::string, ManifestNameWidget>
{
Q_OBJECT
public:
AZ_CLASS_ALLOCATOR_DECL
QWidget* CreateGUI(QWidget* parent) override;
u32 GetHandlerName() const override;
bool AutoDelete() const;
void ConsumeAttribute(ManifestNameWidget* widget, u32 attrib,
AzToolsFramework::PropertyAttributeReader* attrValue, const char* debugName) override;
void WriteGUIValuesIntoProperty(size_t index, ManifestNameWidget* GUI, property_t& instance,
AzToolsFramework::InstanceDataNode* node) override;
bool ReadValuesIntoGUI(size_t index, ManifestNameWidget* GUI, const property_t& instance,
AzToolsFramework::InstanceDataNode* node) override;
static void Register();
static void Unregister();
protected:
virtual void ConsumeFilterTypeAttribute(ManifestNameWidget* widget,
AzToolsFramework::PropertyAttributeReader* attrValue);
private:
static ManifestNameHandler* s_instance;
};
} // SceneUI
} // SceneAPI
} // AZ
@@ -0,0 +1,118 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#include <QStyle>
#include <AzFramework/StringFunc/StringFunc.h>
#include <SceneAPI/SceneCore/Containers/Scene.h>
#include <SceneAPI/SceneCore/Containers/SceneManifest.h>
#include <SceneAPI/SceneCore/DataTypes/DataTypeUtilities.h>
#include <SceneAPI/SceneCore/DataTypes/IManifestObject.h>
#include <SceneAPI/SceneUI/SceneWidgets/ManifestWidget.h>
#include <SceneAPI/SceneUI/RowWidgets/ManifestNameWidget.h>
namespace AZ
{
namespace SceneAPI
{
namespace SceneUI
{
AZ_CLASS_ALLOCATOR_IMPL(ManifestNameWidget, SystemAllocator, 0)
ManifestNameWidget::ManifestNameWidget(QWidget* parent)
: QLineEdit(parent)
, m_filterType(DataTypes::IManifestObject::TYPEINFO_Uuid())
, m_inFailureState(false)
{
connect(this, &QLineEdit::textChanged, this, &ManifestNameWidget::OnTextChanged);
}
void ManifestNameWidget::SetName(const char* name)
{
setText(name);
UpdateStatus(name, false);
}
void ManifestNameWidget::SetName(const AZStd::string& name)
{
setText(name.c_str());
UpdateStatus(name, false);
}
const AZStd::string& ManifestNameWidget::GetName() const
{
return m_name;
}
void ManifestNameWidget::SetFilterType(const Uuid& type)
{
m_filterType = type;
}
void ManifestNameWidget::OnTextChanged(const QString& textValue)
{
m_name = textValue.toStdString().c_str();
UpdateStatus(m_name, true);
emit valueChanged(m_name);
}
void ManifestNameWidget::UpdateStatus(const AZStd::string& newName, bool checkAvailability)
{
AZStd::string error;
bool isValid = AzFramework::StringFunc::Path::IsValid(newName.c_str(), false, false, &error);
if (isValid && checkAvailability)
{
isValid = IsAvailableName(error, newName);
}
if (!isValid && !m_inFailureState)
{
m_originalToolTip = toolTip();
setToolTip(error.c_str());
setProperty("inputValid", "false");
m_inFailureState = true;
style()->unpolish(this);
style()->polish(this);
}
else if (isValid && m_inFailureState)
{
setToolTip(m_originalToolTip);
setProperty("inputValid", "true");
m_inFailureState = false;
style()->unpolish(this);
style()->polish(this);
}
}
bool ManifestNameWidget::IsAvailableName(AZStd::string& error, const AZStd::string& name) const
{
const UI::ManifestWidget* manifestWidget = UI::ManifestWidget::FindRoot(this);
if (!manifestWidget)
{
error = "ManifestNameWidget is not a child of a ManifestWidget. For correct name checking this is required.";
return false;
}
const SceneAPI::Containers::SceneManifest& manifest = manifestWidget->GetScene()->GetManifest();
if (!DataTypes::Utilities::IsNameAvailable(name, manifest, m_filterType))
{
error = "Name is already in use.";
return false;
}
return true;
}
} // SceneUI
} // SceneAPI
} // AZ
#include <RowWidgets/moc_ManifestNameWidget.cpp>
@@ -0,0 +1,59 @@
#pragma once
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#if !defined(Q_MOC_RUN)
#include <QString>
#include <QLineEdit>
#include <AzCore/Math/Uuid.h>
#include <AzCore/std/string/string.h>
#include <AzCore/Memory/SystemAllocator.h>
#endif
namespace AZ
{
namespace SceneAPI
{
namespace SceneUI
{
class ManifestNameWidget : public QLineEdit
{
Q_OBJECT
public:
AZ_CLASS_ALLOCATOR_DECL
explicit ManifestNameWidget(QWidget* parent);
void SetName(const char* name);
void SetName(const AZStd::string& name);
const AZStd::string& GetName() const;
void SetFilterType(const Uuid& type);
signals:
void valueChanged(const AZStd::string& newValue);
protected:
void OnTextChanged(const QString& textValue);
void UpdateStatus(const AZStd::string& newName, bool checkAvailability);
bool IsAvailableName(AZStd::string& error, const AZStd::string& name) const;
QString m_originalToolTip;
Uuid m_filterType;
AZStd::string m_name;
bool m_inFailureState;
};
} // SceneUI
} // SceneAPI
} // AZ
@@ -0,0 +1,185 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#include <AzCore/EBus/EBus.h>
#include <AzCore/Component/ComponentApplicationBus.h>
#include <AzToolsFramework/Debug/TraceContext.h>
#include <SceneAPI/SceneCore/DataTypes/Groups/IGroup.h>
#include <SceneAPI/SceneCore/Utilities/Reporting.h>
#include <SceneAPI/SceneUI/RowWidgets/ManifestVectorHandler.h>
namespace AZ
{
namespace SceneAPI
{
namespace UI
{
AZ_CLASS_ALLOCATOR_IMPL_INTERNAL(IManifestVectorHandler<ManifestType>, SystemAllocator, 0, template<typename ManifestType>)
template<typename ManifestType> SerializeContext* IManifestVectorHandler<ManifestType>::s_serializeContext = nullptr;
template<typename ManifestType> IManifestVectorHandler<ManifestType>* IManifestVectorHandler<ManifestType>::s_instance = nullptr;
template<typename ManifestType>
QWidget* IManifestVectorHandler<ManifestType>::CreateGUI(QWidget* parent)
{
if(IManifestVectorHandler::s_serializeContext)
{
ManifestVectorWidget* instance = aznew ManifestVectorWidget(IManifestVectorHandler::s_serializeContext, parent);
connect(instance, &ManifestVectorWidget::valueChanged, this,
[instance]()
{
EBUS_EVENT(AzToolsFramework::PropertyEditorGUIMessages::Bus, RequestWrite, instance);
});
return instance;
}
else
{
return nullptr;
}
}
template<typename ManifestType>
u32 IManifestVectorHandler<ManifestType>::GetHandlerName() const
{
return AZ_CRC("ManifestVector", 0x895aa9aa);
}
template<typename ManifestType>
bool IManifestVectorHandler<ManifestType>::AutoDelete() const
{
return false;
}
template<typename ManifestType>
void IManifestVectorHandler<ManifestType>::ConsumeAttribute(ManifestVectorWidget* widget, u32 attrib,
AzToolsFramework::PropertyAttributeReader* attrValue, const char* debugName)
{
AZ_TraceContext("Attribute name", debugName);
if (attrib == AZ_CRC("ObjectTypeName", 0x6559e0c0))
{
AZStd::string name;
if (attrValue->Read<AZStd::string>(name))
{
widget->SetCollectionTypeName(name);
}
}
else if (attrib == AZ_CRC("CollectionName", 0xbbc1c898))
{
AZStd::string name;
if (attrValue->Read<AZStd::string>(name))
{
widget->SetCollectionName(name);
}
}
// Sets the number of entries the user can add through this widget. It doesn't limit
// the amount of entries that can be stored.
else if (attrib == AZ_CRC("Cap", 0x993387b1))
{
size_t cap;
if (attrValue->Read<size_t>(cap))
{
widget->SetCapSize(cap);
}
}
}
template<typename ManifestType>
void IManifestVectorHandler<ManifestType>::WriteGUIValuesIntoProperty(size_t /*index*/, ManifestVectorWidget* GUI,
typename IManifestVectorHandler::property_t& instance, AzToolsFramework::InstanceDataNode* /*node*/)
{
instance.clear();
AZStd::vector<AZStd::shared_ptr<DataTypes::IManifestObject> > manifestVector = GUI->GetManifestVector();
for (auto& manifestObject : manifestVector)
{
instance.push_back(AZStd::static_pointer_cast<ManifestType>(manifestObject));
}
}
template<typename ManifestType>
bool IManifestVectorHandler<ManifestType>::ReadValuesIntoGUI(size_t /*index*/, ManifestVectorWidget* GUI, const typename IManifestVectorHandler::property_t& instance,
AzToolsFramework::InstanceDataNode* node)
{
AzToolsFramework::InstanceDataNode* parentNode = node->GetParent();
if (parentNode && parentNode->GetClassMetadata() && parentNode->GetClassMetadata()->m_azRtti)
{
AZ_TraceContext("Parent UUID", parentNode->GetClassMetadata()->m_azRtti->GetTypeId());
if (parentNode->GetClassMetadata()->m_azRtti->IsTypeOf(DataTypes::IManifestObject::RTTI_Type()))
{
DataTypes::IManifestObject* owner = static_cast<DataTypes::IManifestObject*>(parentNode->FirstInstance());
GUI->SetManifestVector(instance.begin(), instance.end(), owner);
}
else if (parentNode->GetClassMetadata()->m_azRtti->IsTypeOf(Containers::RuleContainer::RTTI_Type()))
{
AzToolsFramework::InstanceDataNode* manifestObject = parentNode->GetParent();
if (manifestObject && manifestObject->GetClassMetadata()->m_azRtti->IsTypeOf(DataTypes::IManifestObject::RTTI_Type()))
{
DataTypes::IManifestObject* owner = static_cast<DataTypes::IManifestObject*>(manifestObject->FirstInstance());
GUI->SetManifestVector(instance.begin(), instance.end(), owner);
}
else
{
AZ_TracePrintf(Utilities::WarningWindow, "RuleContainer requires a ManifestObject parent.");
}
}
else
{
AZ_TracePrintf(Utilities::WarningWindow, "ManifestVectorWidget requires a ManifestObject parent.");
}
}
else
{
AZ_TracePrintf(Utilities::WarningWindow, "ManifestVectorWidget requires valid parent with RTTI data specified");
}
return false;
}
template<typename ManifestType>
void IManifestVectorHandler<ManifestType>::Register()
{
if (!IManifestVectorHandler::s_instance)
{
IManifestVectorHandler::s_instance = aznew IManifestVectorHandler();
EBUS_EVENT(AzToolsFramework::PropertyTypeRegistrationMessages::Bus, RegisterPropertyType, IManifestVectorHandler::s_instance);
EBUS_EVENT_RESULT(s_serializeContext, AZ::ComponentApplicationBus, GetSerializeContext);
AZ_Assert(s_serializeContext, "Serialization context not available");
}
}
template<typename ManifestType>
void IManifestVectorHandler<ManifestType>::Unregister()
{
if (IManifestVectorHandler::s_instance)
{
EBUS_EVENT(AzToolsFramework::PropertyTypeRegistrationMessages::Bus, UnregisterPropertyType, IManifestVectorHandler::s_instance);
delete IManifestVectorHandler::s_instance;
IManifestVectorHandler::s_instance = nullptr;
}
}
void ManifestVectorHandler::Register()
{
IManifestVectorHandler<DataTypes::IManifestObject>::Register();
IManifestVectorHandler<DataTypes::IRule>::Register();
}
void ManifestVectorHandler::Unregister()
{
IManifestVectorHandler<DataTypes::IManifestObject>::Unregister();
IManifestVectorHandler<DataTypes::IRule>::Unregister();
}
} // UI
} // SceneAPI
} // AZ
@@ -0,0 +1,72 @@
#pragma once
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#if !defined(Q_MOC_RUN)
#include <AzCore/Math/Crc.h>
#include <AzCore/Memory/SystemAllocator.h>
#include <AzCore/std/containers/vector.h>
#include <AzToolsFramework/UI/PropertyEditor/PropertyEditorAPI.h>
#include <SceneAPI/SceneCore/DataTypes/IManifestObject.h>
#include <SceneAPI/SceneUI/RowWidgets/ManifestVectorWidget.h>
#endif
class QWidget;
namespace AZ
{
class SerializeContext;
namespace SceneAPI
{
namespace UI
{
class ManifestVectorHandler
{
public:
static void Register();
static void Unregister();
};
// This class only has two specializations, that are defined in the cpp file
template<typename ManifestType>
class IManifestVectorHandler
: public QObject
, public AzToolsFramework::PropertyHandler<AZStd::vector<AZStd::shared_ptr<ManifestType>>, ManifestVectorWidget>
{
static_assert((AZStd::is_base_of<DataTypes::IManifestObject, ManifestType>::value), "Manifest type class must inherit from DataTypes::IManifestObject");
public:
AZ_CLASS_ALLOCATOR_DECL
QWidget* CreateGUI(QWidget* parent) override;
u32 GetHandlerName() const override;
bool AutoDelete() const override;
void ConsumeAttribute(ManifestVectorWidget* widget, u32 attrib,
AzToolsFramework::PropertyAttributeReader* attrValue, const char* debugName) override;
void WriteGUIValuesIntoProperty(size_t index, ManifestVectorWidget* GUI, typename IManifestVectorHandler::property_t& instance,
AzToolsFramework::InstanceDataNode* node) override;
bool ReadValuesIntoGUI(size_t index, ManifestVectorWidget* GUI, const typename IManifestVectorHandler::property_t& instance,
AzToolsFramework::InstanceDataNode* node) override;
static void Register();
static void Unregister();
private:
static SerializeContext* s_serializeContext;
static IManifestVectorHandler* s_instance;
};
} // UI
} // SceneAPI
} // AZ
@@ -0,0 +1,321 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#include <QEvent>
#include <QMenu>
#include <QTimer>
#include <QMessageBox>
#include <RowWidgets/ui_ManifestVectorWidget.h>
#include <AzCore/EBus/EBus.h>
#include <AzCore/Component/ComponentApplicationBus.h>
#include <AzCore/Serialization/SerializeContext.h>
#include <AzCore/std/smart_ptr/shared_ptr.h>
#include <AzToolsFramework/UI/PropertyEditor/PropertyEditorAPI.h>
#include <AzToolsFramework/UI/PropertyEditor/PropertyRowWidget.hxx>
#include <AzToolsFramework/UI/PropertyEditor/ReflectedPropertyEditor.hxx>
#include <AzToolsFramework/Debug/TraceContext.h>
#include <SceneAPI/SceneCore/Containers/Scene.h>
#include <SceneAPI/SceneCore/Containers/SceneManifest.h>
#include <SceneAPI/SceneCore/DataTypes/IManifestObject.h>
#include <SceneAPI/SceneCore/Utilities/Reporting.h>
#include <SceneAPI/SceneCore/Events/ManifestMetaInfoBus.h>
#include <SceneAPI/SceneUI/RowWidgets/ManifestVectorWidget.h>
#include <SceneAPI/SceneUI/SceneWidgets/ManifestWidget.h>
namespace AZ
{
namespace SceneAPI
{
namespace UI
{
AZ_CLASS_ALLOCATOR_IMPL(ManifestVectorWidget, SystemAllocator, 0)
ManifestVectorWidget::ManifestVectorWidget(SerializeContext* serializeContext, QWidget* parent)
: QWidget(parent)
, m_serializeContext(serializeContext)
, m_propertyEditor(nullptr)
, m_ui(new Ui::ManifestVectorWidget())
, m_capSize(50)
{
m_ui->setupUi(this);
m_propertyEditor = new AzToolsFramework::ReflectedPropertyEditor(this);
m_propertyEditor->Setup(m_serializeContext, this, false, 175);
m_propertyEditor->show();
m_ui->m_mainLayout->insertWidget(1, m_propertyEditor);
m_ui->m_addObjectButton->setProperty("class", "FixedMenu");
connect(m_ui->m_addObjectButton, &QPushButton::pressed, this, &ManifestVectorWidget::DisplayAddPrompt);
// Add empty menu for visual consistency.
m_ui->m_addObjectButton->setMenu(new QMenu(this));
BusConnect();
}
ManifestVectorWidget::~ManifestVectorWidget()
{
BusDisconnect();
}
void ManifestVectorWidget::SetManifestVector(const ManifestVectorType& manifestVector, DataTypes::IManifestObject* ownerObject)
{
AZ_Assert(ownerObject, "ManifestVectorWidgets must be initialized with a non-null owner object.");
m_manifestVector = manifestVector;
m_ownerObject = ownerObject;
UpdatePropertyGrid();
}
ManifestVectorWidget::ManifestVectorType ManifestVectorWidget::GetManifestVector()
{
return m_manifestVector;
}
void ManifestVectorWidget::SetCollectionName(const AZStd::string& name)
{
m_ui->m_containerTitle->setText(name.c_str());
}
void ManifestVectorWidget::SetCapSize(size_t cap)
{
m_capSize = cap;
}
void ManifestVectorWidget::SetCollectionTypeName(const AZStd::string& typeName)
{
QString addString = QString("Add ") + typeName.c_str();
m_ui->m_addObjectButton->setText(addString);
}
bool ManifestVectorWidget::ContainsManifestObject(const DataTypes::IManifestObject* object) const
{
for (auto& containedObject : m_manifestVector)
{
if (containedObject.get() == object)
{
return true;
}
}
return false;
}
bool ManifestVectorWidget::RemoveManifestObject(const DataTypes::IManifestObject* object)
{
AZ_TraceContext("Remove object type", object->RTTI_GetTypeName());
for (auto it = m_manifestVector.begin(); it < m_manifestVector.end(); ++it)
{
if ((*it).get() == object)
{
object->OnUserRemoved();
m_manifestVector.erase(it);
QTimer::singleShot(0, this,
[this]()
{
UpdatePropertyGrid();
EmitObjectChanged(m_ownerObject);
});
return true;
}
}
AZ_TracePrintf(Utilities::WarningWindow, "Tried to remove an object that was not contained in the vector.");
return false;
}
void ManifestVectorWidget::DisplayAddPrompt()
{
Events::ManifestMetaInfo::ModifiersList availableManifestUUIDs;
ManifestWidget* root = ManifestWidget::FindRoot(this);
AZ_Assert(root, "ManifestVectorWidget is not a child of a ManifestWidget.");
if (!root)
{
return;
}
AZStd::shared_ptr<Containers::Scene> scene = root->GetScene();
if (!scene)
{
return;
}
EBUS_EVENT(Events::ManifestMetaInfoBus, GetAvailableModifiers, availableManifestUUIDs, *scene, *m_ownerObject);
AZ_TraceContext("Parent manifest object type", m_ownerObject->RTTI_GetTypeName());
QMenu* objectMenu = m_ui->m_addObjectButton->menu();
objectMenu->clear();
for (auto& manifestUUID : availableManifestUUIDs)
{
const AZ::SerializeContext::ClassData* manifestClassData = m_serializeContext->FindClassData(manifestUUID);
AZ_TraceContext("Child manifest object UUID", manifestUUID.ToString<AZStd::string>());
if (!manifestClassData)
{
AZ_TracePrintf(Utilities::WarningWindow, "Class data was not registered for class, it will not be available as an option");
continue;
}
AZStd::string displayName;
if (manifestClassData->m_editData && manifestClassData->m_editData->m_name[0] != '\0')
{
displayName = manifestClassData->m_editData->m_name;
}
else if(manifestClassData->m_name[0] != '\0')
{
displayName = manifestClassData->m_name;
}
else
{
AZ_TracePrintf(Utilities::WarningWindow, "Class data did not contain a human readable name for class, it will not be available as an option");
continue;
}
QAction* objectCreateAction = new QAction(displayName.c_str(), m_ui->m_addObjectButton);
connect(objectCreateAction, &QAction::triggered, this,
[this, manifestClassData, displayName]()
{
this->AddNewObject(manifestClassData->m_factory, displayName);
});
objectMenu->addAction(objectCreateAction);
}
}
void ManifestVectorWidget::AddNewObject(SerializeContext::IObjectFactory* factory, const AZStd::string& objectName)
{
if (m_manifestVector.size() >= m_capSize)
{
QMessageBox::warning(this, "Cap reached", QString("The %1 container reached its cap of %2 entries.\nPlease remove entries to free up space.").
arg(m_ui->m_containerTitle->text()).arg(m_capSize));
return;
}
AZ_TraceContext("Object name", objectName);
AZStd::shared_ptr<DataTypes::IManifestObject> newObject(static_cast<DataTypes::IManifestObject*>(factory->Create(objectName.c_str())));
if (newObject)
{
newObject->OnUserAdded();
}
ManifestWidget* root = ManifestWidget::FindRoot(this);
AZ_Assert(root, "ManifestVectorWidget is not a child of a ManifestWidget.");
if (!root)
{
return;
}
AZ_TraceContext("Object type", newObject->RTTI_GetTypeName());
AZStd::shared_ptr<Containers::Scene> scene = root->GetScene();
EBUS_EVENT(Events::ManifestMetaInfoBus, InitializeObject, *scene, *newObject);
m_manifestVector.push_back(newObject);
UpdatePropertyGrid();
EmitObjectChanged(m_ownerObject);
}
void ManifestVectorWidget::UpdatePropertyGrid()
{
QSignalBlocker(this);
m_propertyEditor->ClearInstances();
for (auto &object : m_manifestVector)
{
if(object)
{
m_propertyEditor->AddInstance(object.get(), object->RTTI_GetType());
}
}
m_propertyEditor->InvalidateAll();
m_propertyEditor->ExpandAll();
}
void ManifestVectorWidget::EmitObjectChanged(const DataTypes::IManifestObject* object)
{
emit valueChanged();
ManifestWidget* root = ManifestWidget::FindRoot(this);
AZ_Assert(root, "ManifestVectorWidget is not a child of a ManifestWidget.");
if (!root)
{
return;
}
AZStd::shared_ptr<Containers::Scene> scene = root->GetScene();
if (!scene)
{
return;
}
Events::ManifestMetaInfoBus::Broadcast(&Events::ManifestMetaInfoBus::Events::ObjectUpdated, *scene, object, this);
}
void ManifestVectorWidget::AfterPropertyModified(AzToolsFramework::InstanceDataNode* node)
{
if (node && node->GetParent())
{
AzToolsFramework::InstanceDataNode* owner = node->GetParent();
const AZ::SerializeContext::ClassData* classData = owner->GetClassMetadata();
if (classData && classData->m_azRtti)
{
const DataTypes::IManifestObject* cast = classData->m_azRtti->Cast<DataTypes::IManifestObject>(owner->FirstInstance());
if (cast)
{
AZ_Assert(AZStd::find_if(m_manifestVector.begin(), m_manifestVector.end(),
[cast](const AZStd::shared_ptr<DataTypes::IManifestObject>& object)
{
return object.get() == cast;
}) != m_manifestVector.end(), "ManifestVectorWidget detected an update of a field it doesn't own.");
EmitObjectChanged(cast);
}
}
}
}
void ManifestVectorWidget::RequestPropertyContextMenu(AzToolsFramework::InstanceDataNode* /*node*/, const QPoint& /*point*/)
{
}
void ManifestVectorWidget::BeforePropertyModified(AzToolsFramework::InstanceDataNode* /*node*/)
{
}
void ManifestVectorWidget::SetPropertyEditingActive(AzToolsFramework::InstanceDataNode* /*node*/)
{
}
void ManifestVectorWidget::SetPropertyEditingComplete(AzToolsFramework::InstanceDataNode* /*node*/)
{
}
void ManifestVectorWidget::SealUndoStack()
{
}
void ManifestVectorWidget::ObjectUpdated([[maybe_unused]] const Containers::Scene& scene, const DataTypes::IManifestObject* target, void* sender)
{
if (sender != this && target != nullptr && m_propertyEditor)
{
if (AZStd::find_if(m_manifestVector.begin(), m_manifestVector.end(),
[target](const AZStd::shared_ptr<DataTypes::IManifestObject>& object)
{
return object.get() == target;
}) != m_manifestVector.end())
{
m_propertyEditor->InvalidateAttributesAndValues();
}
}
}
} // namespace UI
} // namespace SceneAPI
} // namespace AZ
#include <RowWidgets/moc_ManifestVectorWidget.cpp>
@@ -0,0 +1,127 @@
#pragma once
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#if !defined(Q_MOC_RUN)
#include <QWidget>
#include <AzCore/Memory/SystemAllocator.h>
#include <AzCore/std/containers/vector.h>
#include <AzToolsFramework/UI/PropertyEditor/PropertyEditorAPI.h>
#include <SceneAPI/SceneCore/Events/ManifestMetaInfoBus.h>
#endif
namespace AZStd
{
template<class T>
class shared_ptr;
}
namespace AzToolsFramework
{
class ReflectedPropertyEditor;
class InstanceDataNode;
}
namespace SerializeContext
{
class IObjectFactory;
}
namespace AZ
{
class SerializeContext;
namespace SceneAPI
{
namespace DataTypes
{
class IManifestObject;
class IGroup;
}
namespace SceneData
{
template<class T>
class VectorWrapper;
}
namespace UI
{
// QT space
namespace Ui
{
class ManifestVectorWidget;
}
class ManifestVectorWidget
: public QWidget
, public AzToolsFramework::IPropertyEditorNotify
, public Events::ManifestMetaInfoBus::Handler
{
Q_OBJECT
public:
AZ_CLASS_ALLOCATOR_DECL
using ManifestVectorType = AZStd::vector<AZStd::shared_ptr<DataTypes::IManifestObject> >;
ManifestVectorWidget(SerializeContext* serializeContext, QWidget* parent);
~ManifestVectorWidget() override;
template<typename InputIterator>
void SetManifestVector(InputIterator first, InputIterator last, DataTypes::IManifestObject* ownerObject)
{
AZ_Assert(ownerObject, "ManifestVectorWidgets must be initialized with a non-null owner object.");
m_manifestVector.assign(first, last);
m_ownerObject = ownerObject;
UpdatePropertyGrid();
}
void SetManifestVector(const ManifestVectorType& manifestVector, DataTypes::IManifestObject* ownerObject);
ManifestVectorType GetManifestVector();
void SetCollectionName(const AZStd::string& name);
void SetCollectionTypeName(const AZStd::string& typeName);
// Sets the number of entries the user can add through this widget. It doesn't limit
// the amount of entries that can be stored.
void SetCapSize(size_t cap);
bool ContainsManifestObject(const DataTypes::IManifestObject* object) const;
bool RemoveManifestObject(const DataTypes::IManifestObject* object);
signals:
void valueChanged();
protected:
void DisplayAddPrompt();
void AddNewObject(SerializeContext::IObjectFactory* factory, const AZStd::string& typeName);
void UpdatePropertyGrid();
void UpdatePropertyGridSize();
void EmitObjectChanged(const DataTypes::IManifestObject* object);
// IPropertyEditorNotify
void AfterPropertyModified(AzToolsFramework::InstanceDataNode* /*node*/) override;
void RequestPropertyContextMenu(AzToolsFramework::InstanceDataNode* /*node*/, const QPoint& /*point*/) override;
void BeforePropertyModified(AzToolsFramework::InstanceDataNode* /*node*/) override;
void SetPropertyEditingActive(AzToolsFramework::InstanceDataNode* /*node*/) override;
void SetPropertyEditingComplete(AzToolsFramework::InstanceDataNode* /*node*/) override;
void SealUndoStack() override;
// ManifestMetaInfoBus
void ObjectUpdated(const Containers::Scene& scene, const DataTypes::IManifestObject* target, void* sender) override;
SerializeContext* m_serializeContext;
AzToolsFramework::ReflectedPropertyEditor* m_propertyEditor;
QScopedPointer<Ui::ManifestVectorWidget> m_ui;
DataTypes::IManifestObject* m_ownerObject;
ManifestVectorType m_manifestVector;
size_t m_capSize;
};
} // namespace UI
} // namespace SceneAPI
} // namespace AZ
@@ -0,0 +1,92 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>AZ::SceneAPI::UI::ManifestVectorWidget</class>
<widget class="QWidget" name="AZ::SceneAPI::UI::ManifestVectorWidget">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>20</verstretch>
</sizepolicy>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<layout class="QVBoxLayout" name="m_mainLayout">
<property name="sizeConstraint">
<enum>QLayout::SetDefaultConstraint</enum>
</property>
<item>
<widget class="QFrame" name="frame">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="frameShape">
<enum>QFrame::StyledPanel</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Raised</enum>
</property>
<layout class="QHBoxLayout" name="horizontalLayout">
<property name="leftMargin">
<number>3</number>
</property>
<property name="topMargin">
<number>3</number>
</property>
<property name="rightMargin">
<number>3</number>
</property>
<property name="bottomMargin">
<number>3</number>
</property>
<item>
<widget class="QLabel" name="m_containerTitle">
<property name="text">
<string></string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QPushButton" name="m_addObjectButton">
<property name="text">
<string>Add Object</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>
@@ -0,0 +1,200 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#include <AzCore/EBus/EBus.h>
#include <AzToolsFramework/Debug/TraceContext.h>
#include <SceneAPI/SceneUI/RowWidgets/NodeListSelectionHandler.h>
namespace AZ
{
namespace SceneAPI
{
namespace UI
{
AZ_CLASS_ALLOCATOR_IMPL(NodeListSelectionHandler, SystemAllocator, 0)
NodeListSelectionHandler* NodeListSelectionHandler::s_instance = nullptr;
QWidget* NodeListSelectionHandler::CreateGUI(QWidget* parent)
{
NodeListSelectionWidget* instance = aznew NodeListSelectionWidget(parent);
connect(instance, &NodeListSelectionWidget::valueChanged, this,
[instance]()
{
EBUS_EVENT(AzToolsFramework::PropertyEditorGUIMessages::Bus, RequestWrite, instance);
});
return instance;
}
u32 NodeListSelectionHandler::GetHandlerName() const
{
return AZ_CRC("NodeListSelection", 0x45c54909);
}
bool NodeListSelectionHandler::AutoDelete() const
{
return false;
}
void NodeListSelectionHandler::ConsumeAttribute(NodeListSelectionWidget* widget, u32 attrib,
AzToolsFramework::PropertyAttributeReader* attrValue, const char* debugName)
{
AZ_TraceContext("Attribute name", debugName);
if (attrib == AZ_CRC("DisabledOption", 0x6cd17278))
{
ConsumeDisabledOptionAttribute(widget, attrValue);
}
else if (attrib == AZ_CRC("ClassTypeIdFilter", 0x21c301f1))
{
ConsumeClassTypeIdAttribute(widget, attrValue);
}
else if (attrib == AZ_CRC("RequiresExactTypeId", 0x9adf9b0d))
{
ConsumeRequiredExactTypeIdAttribute(widget, attrValue);
}
else if (attrib == AZ_CRC("UseShortNames", 0xf6a37fd3))
{
ConsumeUseShortNameAttribute(widget, attrValue);
}
else if (attrib == AZ_CRC("ExcludeEndPoints", 0x53bd29cc))
{
ConsumeExcludeEndPointsAttribute(widget, attrValue);
}
else if (attrib == AZ_CRC("DefaultToDisabled", 0xa2d03bd1))
{
ConsumeDefaultToDisabledAttribute(widget, attrValue);
}
else if (attrib == AZ_CRC("ComboBoxEditable", 0x7ee76669))
{
bool editable;
if (attrValue->Read<bool>(editable))
{
widget->setEditable(editable);
}
}
}
void NodeListSelectionHandler::WriteGUIValuesIntoProperty(size_t /*index*/, NodeListSelectionWidget* GUI,
property_t& instance, AzToolsFramework::InstanceDataNode* /*node*/)
{
instance = static_cast<property_t>(GUI->GetCurrentSelection());
}
bool NodeListSelectionHandler::ReadValuesIntoGUI(size_t /*index*/, NodeListSelectionWidget* GUI, const property_t& instance,
AzToolsFramework::InstanceDataNode* /*node*/)
{
GUI->SetCurrentSelection(instance);
return false;
}
void NodeListSelectionHandler::Register()
{
if (!s_instance)
{
s_instance = aznew NodeListSelectionHandler();
EBUS_EVENT(AzToolsFramework::PropertyTypeRegistrationMessages::Bus, RegisterPropertyType, s_instance);
}
}
void NodeListSelectionHandler::Unregister()
{
if (s_instance)
{
EBUS_EVENT(AzToolsFramework::PropertyTypeRegistrationMessages::Bus, UnregisterPropertyType, s_instance);
delete s_instance;
s_instance = nullptr;
}
}
void NodeListSelectionHandler::ConsumeDisabledOptionAttribute(NodeListSelectionWidget* widget, AzToolsFramework::PropertyAttributeReader* attrValue)
{
AZStd::string disabledOption;
if (attrValue->Read<AZStd::string>(disabledOption))
{
widget->AddDisabledOption(AZStd::move(disabledOption));
}
else
{
AZ_Assert(false, "Failed to read string from 'DisabledOption' attribute.");
}
}
void NodeListSelectionHandler::ConsumeClassTypeIdAttribute(NodeListSelectionWidget* widget, AzToolsFramework::PropertyAttributeReader* attrValue)
{
Uuid classTypeId;
if (attrValue->Read<Uuid>(classTypeId))
{
widget->SetClassTypeId(classTypeId);
}
else
{
AZ_Assert(false, "Failed to read uuid from 'ClassTypeIdFilter' attribute.");
}
}
void NodeListSelectionHandler::ConsumeRequiredExactTypeIdAttribute(NodeListSelectionWidget* widget, AzToolsFramework::PropertyAttributeReader* attrValue)
{
bool exactMatch;
if (attrValue->Read<bool>(exactMatch))
{
widget->UseExactClassTypeMatch(exactMatch);
}
else
{
AZ_Assert(false, "Failed to read boolean from 'RequiresExactTypeId' attribute.");
}
}
void NodeListSelectionHandler::ConsumeUseShortNameAttribute(NodeListSelectionWidget* widget, AzToolsFramework::PropertyAttributeReader* attrValue)
{
bool use;
if (attrValue->Read<bool>(use))
{
widget->UseShortNames(use);
}
else
{
AZ_Assert(false, "Failed to read boolean from 'UseShortNames' attribute.");
}
}
void NodeListSelectionHandler::ConsumeExcludeEndPointsAttribute(NodeListSelectionWidget* widget, AzToolsFramework::PropertyAttributeReader* attrValue)
{
bool exclude;
if (attrValue->Read<bool>(exclude))
{
widget->ExcludeEndPoints(exclude);
}
else
{
AZ_Assert(false, "Failed to read boolean from 'ExcludeEndPoints' attribute.");
}
}
void NodeListSelectionHandler::ConsumeDefaultToDisabledAttribute(NodeListSelectionWidget* widget, AzToolsFramework::PropertyAttributeReader* attrValue)
{
bool defaultToDisabled;
if (attrValue->Read<bool>(defaultToDisabled))
{
widget->DefaultToDisabled(defaultToDisabled);
}
else
{
AZ_Assert(false, "Failed to read boolean from 'DefaultToDisabled' attribute.");
}
}
} // UI
} // SceneAPI
} // AZ
#include <RowWidgets/moc_NodeListSelectionHandler.cpp>
@@ -0,0 +1,95 @@
#pragma once
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#if !defined(Q_MOC_RUN)
#include <AzCore/Math/Crc.h>
#include <AzCore/std/string/string.h>
#include <AzCore/Memory/SystemAllocator.h>
#include <AzToolsFramework/UI/PropertyEditor/PropertyEditorAPI.h>
#include <SceneAPI/SceneUI/RowWidgets/NodeListSelectionWidget.h>
#endif
class QWidget;
/*
=============================================================
= Handler Documentation =
=============================================================
Handler Name: "NodeListSelection"
Available Attributes:
o "DisabledOption" - Option presented to the user as the first option which will generally be interpreted
as the default or disabled option. For instance, "Disable Vertex Coloring" as the
default for selecting available vertex coloring options.
o "ClassTypeIdFilter" - The UUID of the graph object class type to be listed. If not set all available graph
objects will be listed.
o "RequiresExactTypeId" - When 'ClassTypeIdFilter' is set setting this to true will cause only instances of
the exact class to be listed, otherwise any class derived from the given UUID will be used.
o "UseShortNames" - Whether or not to display the full scene graph path or only the short name.
o "ExcludeEndPoints" - Whether or not graph nodes marked as end-points should be considered for displaying.
o "DefaultToDisabled" - Whether or not the default option is the disabled option or the first entry if the value
hasn't not been set or has become invalid. This requires 'DisabledOption' to be set,
otherwise the first entry will be choosen.
*/
namespace AZ
{
namespace SceneAPI
{
namespace UI
{
class NodeListSelectionHandler
: public QObject, public AzToolsFramework::PropertyHandler<AZStd::string, NodeListSelectionWidget>
{
Q_OBJECT
public:
AZ_CLASS_ALLOCATOR_DECL
QWidget* CreateGUI(QWidget* parent) override;
u32 GetHandlerName() const override;
bool AutoDelete() const;
void ConsumeAttribute(NodeListSelectionWidget* widget, u32 attrib,
AzToolsFramework::PropertyAttributeReader* attrValue, const char* debugName) override;
void WriteGUIValuesIntoProperty(size_t index, NodeListSelectionWidget* GUI, property_t& instance,
AzToolsFramework::InstanceDataNode* node) override;
bool ReadValuesIntoGUI(size_t index, NodeListSelectionWidget* GUI, const property_t& instance,
AzToolsFramework::InstanceDataNode* node) override;
static void Register();
static void Unregister();
protected:
virtual void ConsumeDisabledOptionAttribute(NodeListSelectionWidget* widget,
AzToolsFramework::PropertyAttributeReader* attrValue);
virtual void ConsumeClassTypeIdAttribute(NodeListSelectionWidget* widget,
AzToolsFramework::PropertyAttributeReader* attrValue);
virtual void ConsumeRequiredExactTypeIdAttribute(NodeListSelectionWidget* widget,
AzToolsFramework::PropertyAttributeReader* attrValue);
virtual void ConsumeUseShortNameAttribute(NodeListSelectionWidget* widget,
AzToolsFramework::PropertyAttributeReader* attrValue);
virtual void ConsumeExcludeEndPointsAttribute(NodeListSelectionWidget* widget,
AzToolsFramework::PropertyAttributeReader* attrValue);
virtual void ConsumeDefaultToDisabledAttribute(NodeListSelectionWidget* widget,
AzToolsFramework::PropertyAttributeReader* attrValue);
private:
static NodeListSelectionHandler* s_instance;
};
} // UI
} // SceneAPI
} // AZ
@@ -0,0 +1,273 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#include <SceneAPI/SceneCore/Containers/Scene.h>
#include <SceneAPI/SceneCore/Containers/SceneGraph.h>
#include <SceneAPI/SceneCore/Containers/Views/PairIterator.h>
#include <SceneAPI/SceneCore/DataTypes/IGraphObject.h>
#include <SceneAPI/SceneUI/SceneWidgets/ManifestWidget.h>
#include <SceneAPI/SceneUI/RowWidgets/NodeListSelectionWidget.h>
namespace AZ
{
namespace SceneAPI
{
namespace UI
{
AZ_CLASS_ALLOCATOR_IMPL(NodeListSelectionWidget, SystemAllocator, 0)
NodeListSelectionWidget::NodeListSelectionWidget(QWidget* parent)
: QComboBox(parent)
, m_classTypeId(Uuid::CreateNull())
, m_exactClassTypeMatch(false)
, m_hasDirtyList(true)
, m_useShortNames(false)
, m_excludeEndPoints(false)
, m_defaultToDisabled(false)
{
connect(this, &QComboBox::currentTextChanged, this, &NodeListSelectionWidget::OnTextChange);
}
void NodeListSelectionWidget::SetCurrentSelection(const AZStd::string& selection)
{
m_currentSelection = selection;
if (!m_hasDirtyList)
{
SetSelection();
}
}
AZStd::string NodeListSelectionWidget::GetCurrentSelection() const
{
return currentText().toStdString().c_str();
}
void NodeListSelectionWidget::AddDisabledOption(const AZStd::string& option)
{
m_disabledOption = option;
m_hasDirtyList = true;
}
void NodeListSelectionWidget::AddDisabledOption(AZStd::string&& option)
{
m_disabledOption = AZStd::move(option);
m_hasDirtyList = true;
}
const AZStd::string& NodeListSelectionWidget::GetDisabledOption() const
{
return m_disabledOption;
}
void NodeListSelectionWidget::UseShortNames(bool use)
{
m_useShortNames = use;
m_hasDirtyList = true;
}
void NodeListSelectionWidget::ExcludeEndPoints(bool exclude)
{
m_excludeEndPoints = exclude;
m_hasDirtyList = true;
}
void NodeListSelectionWidget::DefaultToDisabled(bool value)
{
m_defaultToDisabled = value;
m_hasDirtyList = true;
}
void NodeListSelectionWidget::SetClassTypeId(const Uuid& classTypeId)
{
m_classTypeId = classTypeId;
m_hasDirtyList = true;
}
void NodeListSelectionWidget::ClearClassTypeId()
{
m_classTypeId = Uuid::CreateNull();
m_hasDirtyList = true;
}
void NodeListSelectionWidget::UseExactClassTypeMatch(bool exactMatch)
{
m_exactClassTypeMatch = exactMatch;
m_hasDirtyList = true;
}
void NodeListSelectionWidget::OnTextChange(const QString& text)
{
if (!m_hasDirtyList)
{
m_currentSelection = text.toStdString().c_str();
emit valueChanged(m_currentSelection);
}
}
void NodeListSelectionWidget::showEvent(QShowEvent* event)
{
if (m_hasDirtyList)
{
clear();
ManifestWidget* mainWidget = ManifestWidget::FindRoot(this);
AZ_Assert(mainWidget, "NodeListSelectionWidget is not an (in)direct child of the ManifestWidget.");
if (!mainWidget)
{
return;
}
const Containers::SceneGraph& graph = mainWidget->GetScene()->GetGraph();
BuildList(graph);
AddDisabledOption();
SetSelection();
setEnabled(count() > 1);
m_hasDirtyList = false;
}
QComboBox::showEvent(event);
}
void NodeListSelectionWidget::BuildList(const Containers::SceneGraph& graph)
{
EntrySet entries;
auto view = Containers::Views::MakePairView(graph.GetNameStorage(), graph.GetContentStorage());
for (auto it = view.begin(); it != view.end(); ++it)
{
if (!it->second || it->first.GetPathLength() == 0)
{
continue;
}
if (!IsCorrectType(*it->second))
{
continue;
}
if (m_excludeEndPoints)
{
Containers::SceneGraph::NodeIndex index = graph.ConvertToNodeIndex(it.GetFirstIterator());
if (graph.IsNodeEndPoint(index))
{
continue;
}
}
AddEntry(entries, it->first);
}
}
bool NodeListSelectionWidget::IsCorrectType(const DataTypes::IGraphObject& object) const
{
if (m_classTypeId.IsNull())
{
return true;
}
if (m_exactClassTypeMatch)
{
return object.RTTI_GetType() == m_classTypeId;
}
else
{
return object.RTTI_IsTypeOf(m_classTypeId);
}
}
void NodeListSelectionWidget::AddEntry(EntrySet& entries, const Containers::SceneGraph::Name& name)
{
if (m_useShortNames)
{
const char* shortName = name.GetName();
if (entries.find(shortName) == entries.end())
{
entries.insert(shortName);
addItem(shortName);
}
}
else
{
const char* pathName = name.GetPath();
if (entries.find(pathName) == entries.end())
{
entries.insert(pathName);
addItem(pathName);
}
}
}
void NodeListSelectionWidget::SetSelection()
{
QString entryName = m_currentSelection.c_str();
int index = findText(entryName);
if (m_disabledOption.empty())
{
if (index >= 0)
{
setCurrentIndex(index);
}
else
{
if (!isEditable())
{
// If not freeform editable, and no disabled option available to set to first entry.
setCurrentIndex(0);
}
else
{
setEditText(entryName);
}
}
}
else
{
// Check against index 1 as an empty string will return the separator.
if (index >= 0 && index != 1)
{
setCurrentIndex(index);
}
else if (!m_defaultToDisabled && count() >= 2)
{
// Pick third option as the first is the default followed
// by the separator.
setCurrentIndex(2);
}
else if (!isEditable())
{
// If not editable and no match was found, set to first entry.
setCurrentIndex(0);
}
else
{
setEditText(entryName);
}
}
}
void NodeListSelectionWidget::AddDisabledOption()
{
if (!m_disabledOption.empty())
{
insertItem(0, m_disabledOption.c_str());
// Only add a separator if the disabled option isn't the only entry.
if (count() > 1)
{
insertSeparator(1);
}
}
}
} // UI
} // SceneAPI
} // AZ
#include <RowWidgets/moc_NodeListSelectionWidget.cpp>
@@ -0,0 +1,97 @@
#pragma once
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#if !defined(Q_MOC_RUN)
#include <QComboBox>
#include <AzCore/Math/Uuid.h>
#include <AzCore/std/string/string.h>
#include <AzCore/std/containers/unordered_set.h>
#include <AzCore/Memory/SystemAllocator.h>
#include <SceneAPI/SceneUI/SceneUIConfiguration.h>
#include <SceneAPI/SceneCore/Containers/SceneGraph.h>
#endif
namespace AZ
{
namespace SceneAPI
{
namespace DataTypes
{
class IGraphObject;
}
namespace UI
{
class NodeListSelectionWidget : public QComboBox
{
Q_OBJECT
public:
AZ_CLASS_ALLOCATOR_DECL
explicit NodeListSelectionWidget(QWidget* parent);
void SetCurrentSelection(const AZStd::string& selection);
AZStd::string GetCurrentSelection() const;
void AddDisabledOption(const AZStd::string& option);
void AddDisabledOption(AZStd::string&& option);
const AZStd::string& GetDisabledOption() const;
void UseShortNames(bool use);
// Sets the class type id to filter against.
void SetClassTypeId(const Uuid& classTypeId);
void ClearClassTypeId();
// When the classTypeId is set as this is true, the nodes it the tree
// must have the exact same type id, if set to false all types
// matching the type id and derived classes will be listed.
void UseExactClassTypeMatch(bool exactMatch);
void ExcludeEndPoints(bool exclude);
// If the assigned selection is missing the selection will default to
// the disabled value if present and true, otherwise the alphabetically
// first entry is used.
void DefaultToDisabled(bool value);
signals:
void valueChanged(const AZStd::string& newValue);
protected slots:
void OnTextChange(const QString& text);
protected:
using EntrySet = AZStd::unordered_set<AZStd::string>;
void showEvent(QShowEvent* event) override;
void BuildList(const Containers::SceneGraph& graph);
bool IsCorrectType(const DataTypes::IGraphObject& object) const;
void AddEntry(EntrySet& entries, const Containers::SceneGraph::Name& name);
void SetSelection();
void AddDisabledOption();
AZStd::string m_disabledOption;
AZStd::string m_currentSelection;
Uuid m_classTypeId;
// Set to true if only a specific class type should be in the filter, otherwise
// all classes that derive from the given type will be listed.
bool m_exactClassTypeMatch;
// Attributes come in after widget has been created and this requires the
// list to be rebuild. This flag keeps track of any changes and
// whether or not the list should be repopulated.
bool m_hasDirtyList;
bool m_useShortNames;
bool m_excludeEndPoints;
bool m_defaultToDisabled;
};
} // UI
} // SceneAPI
} // AZ
@@ -0,0 +1,172 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#include <AzCore/EBus/EBus.h>
#include <AzToolsFramework/Debug/TraceContext.h>
#include <SceneAPI/SceneCore/Containers/SceneGraph.h>
#include <SceneAPI/SceneUI/RowWidgets/NodeTreeSelectionHandler.h>
namespace AZ
{
namespace SceneAPI
{
namespace UI
{
AZ_CLASS_ALLOCATOR_IMPL(NodeTreeSelectionHandler, SystemAllocator, 0)
NodeTreeSelectionHandler* NodeTreeSelectionHandler::s_instance = nullptr;
QWidget* NodeTreeSelectionHandler::CreateGUI(QWidget* parent)
{
NodeTreeSelectionWidget* instance = aznew NodeTreeSelectionWidget(parent);
connect(instance, &NodeTreeSelectionWidget::valueChanged, this,
[instance]()
{
EBUS_EVENT(AzToolsFramework::PropertyEditorGUIMessages::Bus, RequestWrite, instance);
});
return instance;
}
u32 NodeTreeSelectionHandler::GetHandlerName() const
{
return AZ_CRC("NodeTreeSelection", 0x58649112);
}
bool NodeTreeSelectionHandler::AutoDelete() const
{
return false;
}
bool NodeTreeSelectionHandler::IsDefaultHandler() const
{
return true;
}
void NodeTreeSelectionHandler::ConsumeAttribute(NodeTreeSelectionWidget* widget, u32 attrib,
AzToolsFramework::PropertyAttributeReader* attrValue, const char* debugName)
{
AZ_TraceContext("Attribute name", debugName);
if (attrib == AZ_CRC("FilterName", 0xf49ce62e))
{
ConsumeFilterNameAttribute(widget, attrValue);
}
else if (attrib == AZ_CRC("FilterType", 0x2661cf01))
{
ConsumeFilterTypeAttribute(widget, attrValue);
}
else if (attrib == AZ_CRC("FilterVirtualType", 0x972bc6a4))
{
ConsumeFilterVirtualTypeAttribute(widget, attrValue);
}
else if (attrib == AZ_CRC("NarrowSelection", 0xdc8002ec))
{
ConsumeNarrowSelectionAttribute(widget, attrValue);
}
}
void NodeTreeSelectionHandler::WriteGUIValuesIntoProperty(size_t /*index*/, NodeTreeSelectionWidget* GUI,
property_t& instance, AzToolsFramework::InstanceDataNode* /*node*/)
{
GUI->CopyListTo(instance);
GUI->UpdateSelectionLabel();
}
bool NodeTreeSelectionHandler::ReadValuesIntoGUI(size_t /*index*/, NodeTreeSelectionWidget* GUI, const property_t& instance,
AzToolsFramework::InstanceDataNode* /*node*/)
{
GUI->SetList(instance);
GUI->UpdateSelectionLabel();
return false;
}
void NodeTreeSelectionHandler::Register()
{
if (!s_instance)
{
s_instance = aznew NodeTreeSelectionHandler();
EBUS_EVENT(AzToolsFramework::PropertyTypeRegistrationMessages::Bus, RegisterPropertyType, s_instance);
}
}
void NodeTreeSelectionHandler::Unregister()
{
if (s_instance)
{
EBUS_EVENT(AzToolsFramework::PropertyTypeRegistrationMessages::Bus, UnregisterPropertyType, s_instance);
delete s_instance;
s_instance = nullptr;
}
}
void NodeTreeSelectionHandler::ConsumeFilterNameAttribute(NodeTreeSelectionWidget* widget, AzToolsFramework::PropertyAttributeReader* attrValue)
{
AZStd::string filterName;
if (attrValue->Read<AZStd::string>(filterName))
{
widget->SetFilterName(AZStd::move(filterName));
}
else
{
AZ_Assert(false, "Failed to read string from 'FilterName' attribute.");
}
}
void NodeTreeSelectionHandler::ConsumeFilterTypeAttribute(NodeTreeSelectionWidget* widget, AzToolsFramework::PropertyAttributeReader* attrValue)
{
Uuid filterType;
if (attrValue->Read<Uuid>(filterType))
{
widget->AddFilterType(filterType);
}
else
{
AZ_Assert(false, "Failed to read Uuid from 'FilterType' attribute.");
}
}
void NodeTreeSelectionHandler::ConsumeFilterVirtualTypeAttribute(NodeTreeSelectionWidget* widget, AzToolsFramework::PropertyAttributeReader* attrValue)
{
Crc32 filterVirtualType;
if (!attrValue->Read<Crc32>(filterVirtualType))
{
AZStd::string filterFilterTypeName;
if (attrValue->Read<AZStd::string>(filterFilterTypeName))
{
filterVirtualType = Crc32(filterFilterTypeName.c_str());
}
else
{
AZ_Assert(false, "Failed to read crc value or string from 'VirtualFilterName' attribute.");
return;
}
}
widget->AddFilterVirtualType(filterVirtualType);
}
void NodeTreeSelectionHandler::ConsumeNarrowSelectionAttribute(NodeTreeSelectionWidget* widget, AzToolsFramework::PropertyAttributeReader* attrValue)
{
bool narrowSelection;
if (attrValue->Read<bool>(narrowSelection))
{
widget->UseNarrowSelection(narrowSelection);
}
else
{
AZ_Assert(false, "Failed to read boolean from 'NarrowSelection' attribute.");
}
}
} // UI
} // SceneAPI
} // AZ
#include <RowWidgets/moc_NodeTreeSelectionHandler.cpp>
@@ -0,0 +1,92 @@
#pragma once
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#if !defined(Q_MOC_RUN)
#include <AzCore/Math/Crc.h>
#include <AzCore/std/string/string.h>
#include <AzCore/Memory/SystemAllocator.h>
#include <AzToolsFramework/UI/PropertyEditor/PropertyEditorAPI.h>
#include <SceneAPI/SceneUI/RowWidgets/NodeTreeSelectionWidget.h>
#include <SceneAPI/SceneCore/DataTypes/ManifestBase/ISceneNodeSelectionList.h>
#endif
class QWidget;
/*
=============================================================
= Handler Documentation =
=============================================================
Handler Name: "NodeTreeSelection"
Available Attributes:
FilterName - Name of the filter type used in the summary label.
FilterType - Uuid for the type(s) to filter for. This attribute can be added multiple times. By default all
types will be considered but by adding one or more of filters only classes that match the uuid
of the given type or are derived of that type will be used for the selected and total count.
The object is an end-point it will also show in the selection graph, otherwise end-points are hidden.
FilterVirtualType - Crc32 or name (string) for the type(s) to filter for. This attribute can be added multiple
times. By default all types will be considered but by adding one or more of filters only objects
that match any of the virtual types will be used for the selected and total count.
The object is an end-point it will also show in the selection graph, otherwise end-points are hidden.
NarrowSelection - If set to true only filter types will have a checkbox, otherwise all entries can be selected.
*/
namespace AZ
{
namespace SceneAPI
{
namespace UI
{
AZ_PUSH_DISABLE_DLL_EXPORT_BASECLASS_WARNING
class SCENE_UI_API NodeTreeSelectionHandler
: public QObject
, public AzToolsFramework::PropertyHandler<DataTypes::ISceneNodeSelectionList, NodeTreeSelectionWidget>
{
AZ_POP_DISABLE_DLL_EXPORT_BASECLASS_WARNING
Q_OBJECT
public:
AZ_CLASS_ALLOCATOR_DECL
QWidget* CreateGUI(QWidget* parent) override;
u32 GetHandlerName() const override;
bool AutoDelete() const override;
bool IsDefaultHandler() const override;
void ConsumeAttribute(NodeTreeSelectionWidget* widget, u32 attrib,
AzToolsFramework::PropertyAttributeReader* attrValue, const char* debugName) override;
void WriteGUIValuesIntoProperty(size_t index, NodeTreeSelectionWidget* GUI, property_t& instance,
AzToolsFramework::InstanceDataNode* node) override;
bool ReadValuesIntoGUI(size_t index, NodeTreeSelectionWidget* GUI, const property_t& instance,
AzToolsFramework::InstanceDataNode* node) override;
static void Register();
static void Unregister();
protected:
virtual void ConsumeFilterNameAttribute(NodeTreeSelectionWidget* widget,
AzToolsFramework::PropertyAttributeReader* attrValue);
virtual void ConsumeFilterTypeAttribute(NodeTreeSelectionWidget* widget,
AzToolsFramework::PropertyAttributeReader* attrValue);
virtual void ConsumeFilterVirtualTypeAttribute(NodeTreeSelectionWidget* widget,
AzToolsFramework::PropertyAttributeReader* attrValue);
virtual void ConsumeNarrowSelectionAttribute(NodeTreeSelectionWidget* widget,
AzToolsFramework::PropertyAttributeReader* attrValue);
private:
static NodeTreeSelectionHandler* s_instance;
};
} // UI
} // SceneAPI
} // AZ
@@ -0,0 +1,338 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#include <QLabel>
#include <QToolButton>
#include <AzCore/std/bind/bind.h>
#include <RowWidgets/ui_NodeTreeSelectionWidget.h>
#include <SceneAPI/SceneCore/Containers/Scene.h>
#include <SceneAPI/SceneCore/DataTypes/IGraphObject.h>
#include <SceneAPI/SceneCore/DataTypes/ManifestBase/ISceneNodeSelectionList.h>
#include <SceneAPI/SceneCore/Events/GraphMetaInfoBus.h>
#include <SceneAPI/SceneCore/Utilities/SceneGraphSelector.h>
#include <SceneAPI/SceneUI/RowWidgets/NodeTreeSelectionWidget.h>
#include <SceneAPI/SceneUI/SceneWidgets/ManifestWidget.h>
#include <SceneAPI/SceneUI/CommonWidgets/OverlayWidget.h>
namespace AZ
{
namespace SceneAPI
{
namespace UI
{
AZ_CLASS_ALLOCATOR_IMPL(NodeTreeSelectionWidget, SystemAllocator, 0)
NodeTreeSelectionWidget::NodeTreeSelectionWidget(QWidget* parent)
: QWidget(parent)
, ui(new Ui::NodeTreeSelectionWidget())
, m_narrowSelection(false)
, m_filterName("nodes")
{
ui->setupUi(this);
ui->m_selectButton->setIcon(QIcon(":/SceneUI/Manifest/TreeIcon.png"));
connect(ui->m_selectButton, &QToolButton::clicked, this, &NodeTreeSelectionWidget::SelectButtonClicked);
}
NodeTreeSelectionWidget::~NodeTreeSelectionWidget() = default;
void NodeTreeSelectionWidget::SetList(const DataTypes::ISceneNodeSelectionList& list)
{
m_list = list.Copy();
}
void NodeTreeSelectionWidget::CopyListTo(DataTypes::ISceneNodeSelectionList& target)
{
if (m_list)
{
m_list->CopyTo(target);
}
}
void NodeTreeSelectionWidget::SetFilterName(const AZStd::string& name)
{
ui->m_selectButton->setToolTip(QString::asprintf("Select %s", name.c_str()));
m_filterName = name;
}
void NodeTreeSelectionWidget::SetFilterName(AZStd::string&& name)
{
ui->m_selectButton->setToolTip(QString::asprintf("Select %s", name.c_str()));
m_filterName = AZStd::move(name);
}
void NodeTreeSelectionWidget::AddFilterType(const Uuid& idProperty)
{
if (m_filterTypes.find(idProperty) == m_filterTypes.end())
{
m_filterTypes.insert(idProperty);
}
}
void NodeTreeSelectionWidget::AddFilterVirtualType(Crc32 name)
{
if (m_filterVirtualTypes.find(name) == m_filterVirtualTypes.end())
{
m_filterVirtualTypes.insert(name);
}
}
void NodeTreeSelectionWidget::UseNarrowSelection(bool enable)
{
m_narrowSelection = enable;
}
void NodeTreeSelectionWidget::SelectButtonClicked()
{
AZ_Assert(!m_treeWidget, "Node tree already active, NodeTreeSelectionWidget button pressed multiple times.");
AZ_Assert(m_list, "Requested updating of selection list before it was set.");
ManifestWidget* root = ManifestWidget::FindRoot(this);
AZ_Assert(root, "NodeTreeSelectionWidget is not a child of a ManifestWidget.");
if (!m_list || !root)
{
return;
}
AZStd::shared_ptr<Containers::Scene> scene = root->GetScene();
if (!scene)
{
return;
}
OverlayWidgetButtonList buttons;
OverlayWidgetButton acceptButton;
acceptButton.m_text = "Select";
acceptButton.m_callback = AZStd::bind(&NodeTreeSelectionWidget::ListChangesAccepted, this);
acceptButton.m_triggersPop = true;
OverlayWidgetButton cancelButton;
cancelButton.m_text = "Cancel";
cancelButton.m_callback = AZStd::bind(&NodeTreeSelectionWidget::ListChangesCanceled, this);
cancelButton.m_triggersPop = true;
cancelButton.m_isCloseButton = true;
buttons.push_back(&acceptButton);
buttons.push_back(&cancelButton);
ResetNewTreeWidget(*scene);
for (const Uuid& filterType : m_filterTypes)
{
m_treeWidget->AddFilterType(filterType);
}
for (Crc32 virtualTypeName : m_filterVirtualTypes)
{
m_treeWidget->AddVirtualFilterType(virtualTypeName);
}
if (m_narrowSelection)
{
m_treeWidget->MakeCheckable(SceneGraphWidget::CheckableOption::OnlyFilterTypesCheckable);
}
m_treeWidget->Build();
QLabel* label = new QLabel("Finish selecting nodes to continue editing settings.");
label->setAlignment(Qt::AlignCenter);
OverlayWidget::PushLayerToContainingOverlay(this, label, m_treeWidget.get(), "Select nodes", buttons);
}
void NodeTreeSelectionWidget::ResetNewTreeWidget(const Containers::Scene& scene)
{
m_treeWidget.reset(aznew SceneGraphWidget(scene, *m_list));
}
void NodeTreeSelectionWidget::ListChangesAccepted()
{
m_list = m_treeWidget->ClaimTargetList();
m_treeWidget.reset();
emit valueChanged();
}
void NodeTreeSelectionWidget::ListChangesCanceled()
{
m_treeWidget.reset();
}
void NodeTreeSelectionWidget::UpdateSelectionLabel()
{
if (m_list)
{
size_t selected = CalculateSelectedCount();
size_t total = CalculateTotalCount();
AZ_Assert(selected <= total, "Selected count of nodes should not be greater than the total count");
if (total == 0)
{
ui->m_statusLabel->setText("Default selection");
}
else if (selected == total)
{
ui->m_statusLabel->setText(QString::asprintf("All %s selected", m_filterName.c_str()));
}
else
{
ui->m_statusLabel->setText(
QString("%1 of %2 %3 selected").arg(selected).arg(total).arg(m_filterName.c_str()));
}
}
else
{
ui->m_statusLabel->setText("No list assigned");
}
}
size_t NodeTreeSelectionWidget::CalculateSelectedCount()
{
if (!m_list)
{
return 0;
}
const ManifestWidget* root = ManifestWidget::FindRoot(this);
AZ_Assert(root, "NodeTreeSelectionWidget is not a child of a ManifestWidget.");
if (!m_list || !root)
{
return 0;
}
const Containers::SceneGraph& graph = root->GetScene()->GetGraph();
size_t result = 0;
AZStd::unique_ptr<DataTypes::ISceneNodeSelectionList> tempList(m_list->Copy());
Utilities::SceneGraphSelector::UpdateNodeSelection(graph, *tempList);
size_t selectedCount = tempList->GetSelectedNodeCount();
for (size_t i = 0; i < selectedCount; ++i)
{
Containers::SceneGraph::NodeIndex index = graph.Find(tempList->GetSelectedNode(i));
if (!index.IsValid())
{
continue;
}
AZStd::shared_ptr<const DataTypes::IGraphObject> object = graph.GetNodeContent(index);
if (!object)
{
continue;
}
if (m_filterTypes.empty() && m_filterVirtualTypes.empty())
{
result++;
continue;
}
bool foundType = false;
for (const Uuid& type : m_filterTypes)
{
if (object->RTTI_IsTypeOf(type))
{
result++;
foundType = true;
break;
}
}
if (foundType)
{
continue;
}
// Check if the object is one of the registered virtual types.
AZStd::set<Crc32> virtualTypes;
Events::GraphMetaInfoBus::Broadcast(&Events::GraphMetaInfo::GetVirtualTypes, virtualTypes, *root->GetScene(), index);
for (Crc32 name : virtualTypes)
{
if (m_filterVirtualTypes.find(name) != m_filterVirtualTypes.end())
{
result++;
break;
}
}
}
return result;
}
size_t NodeTreeSelectionWidget::CalculateTotalCount()
{
const ManifestWidget* root = ManifestWidget::FindRoot(this);
AZ_Assert(root, "NodeTreeSelectionWidget is not a child of a ManifestWidget.");
if (!m_list || !root)
{
return 0;
}
const Containers::SceneGraph& graph = root->GetScene()->GetGraph();
size_t total = 0;
if (m_filterTypes.empty() && m_filterVirtualTypes.empty())
{
Containers::SceneGraph::HierarchyStorageConstData view = graph.GetHierarchyStorage();
if (!graph.GetNodeContent(graph.GetRoot()) && graph.GetNodeName(graph.GetRoot()).GetPathLength() == 0)
{
view = Containers::SceneGraph::HierarchyStorageConstData(view.begin() + 1, view.end());
}
for (auto& it : view)
{
if (!it.IsEndPoint())
{
total++;
}
}
}
else
{
for (auto it = graph.GetContentStorage().begin(); it != graph.GetContentStorage().end(); ++it)
{
if (!(*it))
{
continue;
}
Containers::SceneGraph::NodeIndex index = graph.ConvertToNodeIndex(it);
bool foundType = false;
for (const Uuid& type : m_filterTypes)
{
if ((*it)->RTTI_IsTypeOf(type))
{
total++;
foundType = true;
break;
}
}
if (foundType)
{
continue;
}
// Check if the object is one of the registered virtual types.
AZStd::set<Crc32> virtualTypes;
Events::GraphMetaInfoBus::Broadcast(&Events::GraphMetaInfo::GetVirtualTypes, virtualTypes, *root->GetScene(), index);
for (Crc32 name : virtualTypes)
{
if (m_filterVirtualTypes.find(name) != m_filterVirtualTypes.end())
{
total++;
break;
}
}
}
}
return total;
}
} // namespace UI
} // namespace SceneAPI
} // namespace AZ
#include <RowWidgets/moc_NodeTreeSelectionWidget.cpp>
@@ -0,0 +1,87 @@
#pragma once
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#if !defined(Q_MOC_RUN)
#include <QWidget>
#include <AzCore/Math/Uuid.h>
#include <AzCore/std/string/string.h>
#include <AzCore/std/smart_ptr/unique_ptr.h>
#include <AzCore/std/containers/set.h>
#include <AzCore/Memory/SystemAllocator.h>
#include <AzToolsFramework/UI/PropertyEditor/PropertyEditorAPI.h>
#include <SceneAPI/SceneUI/SceneUIConfiguration.h>
#include <SceneAPI/SceneUI/SceneWidgets/SceneGraphWidget.h>
#endif
namespace AZ
{
namespace SceneAPI
{
namespace DataTypes
{
class ISceneNodeSelectionList;
}
namespace UI
{
// QT space
namespace Ui
{
class NodeTreeSelectionWidget;
}
class SCENE_UI_API NodeTreeSelectionWidget : public QWidget
{
Q_OBJECT
public:
AZ_CLASS_ALLOCATOR_DECL
explicit NodeTreeSelectionWidget(QWidget* parent);
~NodeTreeSelectionWidget() override;
void SetList(const DataTypes::ISceneNodeSelectionList& list);
void CopyListTo(DataTypes::ISceneNodeSelectionList& target);
void SetFilterName(const AZStd::string& name);
void SetFilterName(AZStd::string&& name);
void AddFilterType(const Uuid& idProperty);
void AddFilterVirtualType(Crc32 name);
void UseNarrowSelection(bool enable);
void UpdateSelectionLabel();
signals:
void valueChanged();
protected:
void SelectButtonClicked();
void ListChangesAccepted();
void ListChangesCanceled();
virtual void ResetNewTreeWidget(const Containers::Scene& scene);
size_t CalculateSelectedCount();
size_t CalculateTotalCount();
AZ_PUSH_DISABLE_DLL_EXPORT_MEMBER_WARNING
AZStd::set<Uuid> m_filterTypes;
AZStd::set<Crc32> m_filterVirtualTypes;
AZStd::string m_filterName;
QScopedPointer<Ui::NodeTreeSelectionWidget> ui;
AZStd::unique_ptr<SceneGraphWidget> m_treeWidget;
AZStd::unique_ptr<DataTypes::ISceneNodeSelectionList> m_list;
AZ_POP_DISABLE_DLL_EXPORT_MEMBER_WARNING
bool m_narrowSelection;
};
} // UI
} // SceneAPI
} // AZ
@@ -0,0 +1,66 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>AZ::SceneAPI::UI::NodeTreeSelectionWidget</class>
<widget class="QWidget" name="AZ::SceneAPI::UI::NodeTreeSelectionWidget">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<layout class="QHBoxLayout" name="horizontalLayout">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QLabel" name="m_statusLabel">
<property name="frameShape">
<enum>QFrame::Panel</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Sunken</enum>
</property>
<property name="text">
<string>All nodes selected</string>
</property>
</widget>
</item>
<item>
<widget class="QToolButton" name="m_selectButton">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>20</width>
<height>20</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>20</width>
<height>20</height>
</size>
</property>
<property name="toolTip">
<string>Select Nodes</string>
</property>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>
@@ -0,0 +1,112 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#include <AzCore/EBus/EBus.h>
#include <AzToolsFramework/Debug/TraceContext.h>
#include <AzToolsFramework/UI/PropertyEditor/PropertyVectorCtrl.hxx>
#include <SceneAPI/SceneUI/RowWidgets/TransformRowHandler.h>
namespace AZ
{
namespace SceneAPI
{
namespace SceneUI
{
AZ_CLASS_ALLOCATOR_IMPL(TranformRowHandler, SystemAllocator, 0)
TranformRowHandler* TranformRowHandler::s_instance = nullptr;
QWidget* TranformRowHandler::CreateGUI(QWidget* parent)
{
return aznew TransformRowWidget(parent);
}
u32 TranformRowHandler::GetHandlerName() const
{
return AZ_CRC("TranformRow", 0x795295be);
}
bool TranformRowHandler::AutoDelete() const
{
return false;
}
bool TranformRowHandler::IsDefaultHandler() const
{
return true;
}
void TranformRowHandler::ConsumeAttribute(TransformRowWidget* widget, u32 attrib,
AzToolsFramework::PropertyAttributeReader* attrValue, const char* debugName)
{
if (attrib == AZ::Edit::Attributes::ReadOnly)
{
bool value;
if (attrValue->Read<bool>(value))
{
widget->SetEnableEdit(!value);
}
}
else
{
AzToolsFramework::Vector3PropertyHandler handler;
handler.ConsumeAttribute(widget->GetTranslationWidget(), attrib, attrValue, debugName);
handler.ConsumeAttribute(widget->GetRotationWidget(), attrib, attrValue, debugName);
handler.ConsumeAttribute(widget->GetScaleWidget(), attrib, attrValue, debugName);
}
}
void TranformRowHandler::WriteGUIValuesIntoProperty(size_t /*index*/, TransformRowWidget* GUI,
property_t& instance, AzToolsFramework::InstanceDataNode* /*node*/)
{
GUI->GetTransform(instance);
}
bool TranformRowHandler::ReadValuesIntoGUI(size_t /*index*/, TransformRowWidget* GUI, const property_t& instance,
AzToolsFramework::InstanceDataNode* /*node*/)
{
GUI->SetTransform(instance);
return false;
}
void TranformRowHandler::Register()
{
using namespace AzToolsFramework;
if (!s_instance)
{
s_instance = aznew TranformRowHandler();
PropertyTypeRegistrationMessages::Bus::Broadcast(&PropertyTypeRegistrationMessages::Bus::Events::RegisterPropertyType, s_instance);
}
}
void TranformRowHandler::Unregister()
{
using namespace AzToolsFramework;
if (s_instance)
{
PropertyTypeRegistrationMessages::Bus::Broadcast(&PropertyTypeRegistrationMessages::Bus::Events::UnregisterPropertyType, s_instance);
delete s_instance;
s_instance = nullptr;
}
}
void TranformRowHandler::ConsumeFilterTypeAttribute(TransformRowWidget* /*widget*/,
AzToolsFramework::PropertyAttributeReader* /*attrValue*/)
{
}
} // namespace SceneUI
} // namespace SceneAPI
} // namespace AZ
#include <RowWidgets/moc_TransformRowHandler.cpp>
@@ -0,0 +1,63 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#pragma once
#if !defined(Q_MOC_RUN)
#include <AzCore/Math/Transform.h>
#include <AzCore/Memory/SystemAllocator.h>
#include <AzToolsFramework/UI/PropertyEditor/PropertyEditorAPI.h>
#include <SceneAPI/SceneUI/RowWidgets/TransformRowWidget.h>
#endif
class QWidget;
namespace AZ
{
namespace SceneAPI
{
namespace SceneUI
{
class TranformRowHandler
: public QObject
, public AzToolsFramework::PropertyHandler<AZ::Transform, TransformRowWidget>
{
Q_OBJECT
public:
AZ_CLASS_ALLOCATOR_DECL
QWidget* CreateGUI(QWidget* parent) override;
u32 GetHandlerName() const override;
bool AutoDelete() const;
bool IsDefaultHandler() const override;
void ConsumeAttribute(TransformRowWidget* widget, u32 attrib,
AzToolsFramework::PropertyAttributeReader* attrValue, const char* debugName) override;
void WriteGUIValuesIntoProperty(size_t index, TransformRowWidget* GUI, property_t& instance,
AzToolsFramework::InstanceDataNode* node) override;
bool ReadValuesIntoGUI(size_t index, TransformRowWidget* GUI, const property_t& instance,
AzToolsFramework::InstanceDataNode* node) override;
static void Register();
static void Unregister();
protected:
virtual void ConsumeFilterTypeAttribute(TransformRowWidget* widget,
AzToolsFramework::PropertyAttributeReader* attrValue);
private:
static TranformRowHandler* s_instance;
};
} // namespace SceneUI
} // namespace SceneAPI
} // namespace AZ
@@ -0,0 +1,262 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#include <QLabel>
#include <QStyle>
#include <QGridLayout>
#include <SceneAPI/SceneUI/RowWidgets/TransformRowWidget.h>
#include <AzQtComponents/Components/Widgets/VectorInput.h>
#include <AzToolsFramework/UI/PropertyEditor/PropertyEditorAPI.h>
#include <AzToolsFramework/UI/PropertyEditor/PropertyRowWidget.hxx>
namespace AZ
{
namespace SceneAPI
{
namespace SceneUI
{
AZ_CLASS_ALLOCATOR_IMPL(ExpandedTransform, SystemAllocator, 0);
void PopulateVector3(AzQtComponents::VectorInput* vectorProperty, AZ::Vector3& vector)
{
AZ_Assert(vectorProperty->getSize() == 3, "Trying to populate a Vector3 from an invalidly sized Vector PropertyCtrl");
if (vectorProperty->getSize() < 3)
{
return;
}
AzQtComponents::VectorElement** elements = vectorProperty->getElements();
for (int i = 0; i < vectorProperty->getSize(); ++i)
{
AzQtComponents::VectorElement* currentElement = elements[i];
vector.SetElement(i, aznumeric_cast<float>(currentElement->getValue()));
}
}
ExpandedTransform::ExpandedTransform()
: m_translation(0, 0, 0)
, m_rotation(0, 0, 0)
, m_scale(1, 1, 1)
{
}
ExpandedTransform::ExpandedTransform(const Transform& transform)
{
SetTransform(transform);
}
void ExpandedTransform::SetTransform(const AZ::Transform& transform)
{
m_translation = transform.GetTranslation();
m_rotation = transform.GetEulerDegrees();
m_scale = transform.GetScale();
}
void ExpandedTransform::GetTransform(AZ::Transform& transform) const
{
transform = Transform::CreateTranslation(m_translation);
transform *= AZ::ConvertEulerDegreesToTransform(m_rotation);
transform.MultiplyByScale(m_scale);
}
const AZ::Vector3& ExpandedTransform::GetTranslation() const
{
return m_translation;
}
void ExpandedTransform::SetTranslation(const AZ::Vector3& translation)
{
m_translation = translation;
}
const AZ::Vector3& ExpandedTransform::GetRotation() const
{
return m_rotation;
}
void ExpandedTransform::SetRotation(const AZ::Vector3& rotation)
{
m_rotation = rotation;
}
const AZ::Vector3& ExpandedTransform::GetScale() const
{
return m_scale;
}
void ExpandedTransform::SetScale(const AZ::Vector3& scale)
{
m_scale = scale;
}
AZ_CLASS_ALLOCATOR_IMPL(TransformRowWidget, SystemAllocator, 0);
TransformRowWidget::TransformRowWidget(QWidget* parent)
: QWidget(parent)
{
QWidget* hider = new QWidget();
QGridLayout* layout = new QGridLayout();
layout->setMargin(0);
QGridLayout* layout2 = new QGridLayout();
setLayout(layout);
AzToolsFramework::PropertyRowWidget* parentWidget = reinterpret_cast<AzToolsFramework::PropertyRowWidget*>(parent);
QToolButton* toolButton = parentWidget->GetIndicatorButton();
QVBoxLayout* layoutOriginal = parentWidget->GetLeftHandSideLayoutParent();
parentWidget->SetAsCustom(true);
parentWidget->GetNameLabel()->setContentsMargins(0, 0, 0, 0);
m_translationWidget = new AzQtComponents::VectorInput(this, 3);
m_translationWidget->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
m_translationWidget->setMinimum(-9999999);
m_translationWidget->setMaximum(9999999);
m_rotationWidget = new AzQtComponents::VectorInput(this, 3);
m_rotationWidget->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
m_rotationWidget->setLabel(0, "P");
m_rotationWidget->setLabel(1, "R");
m_rotationWidget->setLabel(2, "Y");
m_rotationWidget->setMinimum(0);
m_rotationWidget->setMaximum(360);
m_rotationWidget->setSuffix(" degrees");
m_scaleWidget = new AzQtComponents::VectorInput(this, 3);
m_scaleWidget->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
m_scaleWidget->setMinimum(0);
m_scaleWidget->setMaximum(10000);
layout2->addWidget(new AzQtComponents::ElidingLabel("Position"), 0, 1);
layout->addWidget(m_translationWidget, 1, 1);
layout2->addWidget(new AzQtComponents::ElidingLabel("Rotation"), 1, 1);
layout->addWidget(m_rotationWidget, 2, 1);
layout2->addWidget(new AzQtComponents::ElidingLabel("Scale"), 2, 1);
layout->addWidget(m_scaleWidget, 3, 1);
layout->setRowMinimumHeight(0,16);
layout2->setColumnMinimumWidth(0, 30);
toolButton->setArrowType(Qt::DownArrow);
parentWidget->SetIndentSize(1);
toolButton->setVisible(true);
hider->setLayout(layout2);
layoutOriginal->addWidget(hider);
connect(toolButton, &QToolButton::clicked, this, [this, hider, parentWidget, toolButton]
{
m_expanded = !m_expanded;
if (m_expanded)
{
this->show();
hider->show();
toolButton->setArrowType(Qt::DownArrow);
}
else
{
this->hide();
hider->hide();
toolButton->setArrowType(Qt::RightArrow);
}
});
QObject::connect(m_translationWidget, &AzQtComponents::VectorInput::valueChanged, this, [this]
{
AzQtComponents::VectorInput* widget = this->GetTranslationWidget();
AZ::Vector3 translation;
PopulateVector3(widget, translation);
m_transform.SetTranslation(translation);
AzToolsFramework::PropertyEditorGUIMessages::Bus::Broadcast(&AzToolsFramework::PropertyEditorGUIMessages::RequestWrite, this);
});
QObject::connect(m_rotationWidget, &AzQtComponents::VectorInput::valueChanged, this, [this]
{
AzQtComponents::VectorInput* widget = this->GetRotationWidget();
AZ::Vector3 rotation;
PopulateVector3(widget, rotation);
m_transform.SetRotation(rotation);
AzToolsFramework::PropertyEditorGUIMessages::Bus::Broadcast(&AzToolsFramework::PropertyEditorGUIMessages::RequestWrite, this);
});
QObject::connect(m_scaleWidget, &AzQtComponents::VectorInput::valueChanged, this, [this]
{
AzQtComponents::VectorInput* widget = this->GetScaleWidget();
AZ::Vector3 scale;
PopulateVector3(widget, scale);
m_transform.SetScale(scale);
AzToolsFramework::PropertyEditorGUIMessages::Bus::Broadcast(&AzToolsFramework::PropertyEditorGUIMessages::RequestWrite, this);
});
}
void TransformRowWidget::SetEnableEdit(bool enableEdit)
{
m_translationWidget->setEnabled(enableEdit);
m_rotationWidget->setEnabled(enableEdit);
m_scaleWidget->setEnabled(enableEdit);
}
void TransformRowWidget::SetTransform(const AZ::Transform& transform)
{
blockSignals(true);
m_transform.SetTransform(transform);
m_translationWidget->setValuebyIndex(m_transform.GetTranslation().GetX(), 0);
m_translationWidget->setValuebyIndex(m_transform.GetTranslation().GetY(), 1);
m_translationWidget->setValuebyIndex(m_transform.GetTranslation().GetZ(), 2);
m_rotationWidget->setValuebyIndex(m_transform.GetRotation().GetX(), 0);
m_rotationWidget->setValuebyIndex(m_transform.GetRotation().GetY(), 1);
m_rotationWidget->setValuebyIndex(m_transform.GetRotation().GetZ(), 2);
m_scaleWidget->setValuebyIndex(m_transform.GetScale().GetX(), 0);
m_scaleWidget->setValuebyIndex(m_transform.GetScale().GetY(), 1);
m_scaleWidget->setValuebyIndex(m_transform.GetScale().GetZ(), 2);
blockSignals(false);
}
void TransformRowWidget::GetTransform(AZ::Transform& transform) const
{
m_transform.GetTransform(transform);
}
const ExpandedTransform& TransformRowWidget::GetExpandedTransform() const
{
return m_transform;
}
AzQtComponents::VectorInput* TransformRowWidget::GetTranslationWidget()
{
return m_translationWidget;
}
AzQtComponents::VectorInput* TransformRowWidget::GetRotationWidget()
{
return m_rotationWidget;
}
AzQtComponents::VectorInput* TransformRowWidget::GetScaleWidget()
{
return m_scaleWidget;
}
} // namespace SceneUI
} // namespace SceneAPI
} // namespace AZ
#include <RowWidgets/moc_TransformRowWidget.cpp>
@@ -0,0 +1,94 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#pragma once
#if !defined(Q_MOC_RUN)
#include <QString>
#include <QLineEdit>
#include <AzCore/Math/Transform.h>
#include <AzCore/Math/Vector3.h>
#include <AzCore/Math/Vector3.h>
#include <AzCore/Math/Uuid.h>
#include <AzCore/Memory/SystemAllocator.h>
#include <SceneAPI/SceneUI/SceneUIConfiguration.h>
#endif
namespace AzQtComponents
{
class VectorInput;
}
namespace AZ
{
namespace SceneAPI
{
namespace SceneUI
{
class SCENE_UI_API ExpandedTransform
{
public:
AZ_CLASS_ALLOCATOR_DECL;
ExpandedTransform();
explicit ExpandedTransform(const Transform& transform);
void GetTransform(AZ::Transform& transform) const;
void SetTransform(const AZ::Transform& transform);
const AZ::Vector3& GetTranslation() const;
void SetTranslation(const AZ::Vector3& translation);
const AZ::Vector3& GetRotation() const;
void SetRotation(const AZ::Vector3& translation);
const AZ::Vector3& GetScale() const;
void SetScale(const AZ::Vector3& scale);
private:
AZ_PUSH_DISABLE_DLL_EXPORT_MEMBER_WARNING
AZ::Vector3 m_translation;
AZ::Vector3 m_rotation;
AZ::Vector3 m_scale;
AZ_POP_DISABLE_DLL_EXPORT_MEMBER_WARNING
};
class TransformRowWidget : public QWidget
{
Q_OBJECT
public:
AZ_CLASS_ALLOCATOR_DECL;
explicit TransformRowWidget(QWidget* parent = nullptr);
void SetEnableEdit(bool enableEdit);
void SetTransform(const AZ::Transform& transform);
void GetTransform(AZ::Transform& transform) const;
const ExpandedTransform& GetExpandedTransform() const;
AzQtComponents::VectorInput* GetTranslationWidget();
AzQtComponents::VectorInput* GetRotationWidget();
AzQtComponents::VectorInput* GetScaleWidget();
protected:
ExpandedTransform m_transform;
bool m_expanded = true;
AzQtComponents::VectorInput* m_translationWidget;
AzQtComponents::VectorInput* m_rotationWidget;
AzQtComponents::VectorInput* m_scaleWidget;
};
} // namespace SceneUI
} // namespace SceneAPI
} // namespace AZ