Initial pass of ViewportUiSwitcher.

This commit is contained in:
hasareej
2021-04-16 10:27:13 +01:00
parent 9f88698c3a
commit 969f94ffb5
17 changed files with 413 additions and 3 deletions
@@ -440,6 +440,13 @@ namespace AzToolsFramework
&ViewportUi::ViewportUiRequestBus::Events::RemoveCluster,
clusterId);
}
static void RemoveTestSwitcher(const ViewportUi::ClusterId clusterId)
{
ViewportUi::ViewportUiRequestBus::Event(
ViewportUi::DefaultViewportId, &ViewportUi::ViewportUiRequestBus::Events::RemoveCluster,
clusterId);
}
static void SetViewportUiClusterVisible(ViewportUi::ClusterId clusterId, bool visible)
{
@@ -468,6 +475,18 @@ namespace AzToolsFramework
return buttonId;
}
static ViewportUi::ButtonId RegisterSwitcherButton(
ViewportUi::ClusterId clusterId, const char* iconName, const char* buttonName)
{
ViewportUi::ButtonId buttonId;
ViewportUi::ViewportUiRequestBus::EventResult(
buttonId, ViewportUi::DefaultViewportId,
&ViewportUi::ViewportUiRequestBus::Events::CreateSwitcherButton, clusterId,
AZStd::string::format("Editor/Icons/Switcher/%s.svg", iconName), buttonName);
return buttonId;
}
// return either center or entity pivot
static AZ::Vector3 CalculatePivotTranslation(
const AZ::EntityId entityId, const EditorTransformComponentSelectionRequests::Pivot pivot)
@@ -1028,6 +1047,8 @@ namespace AzToolsFramework
RegisterActions();
SetupBoxSelect();
RefreshSelectedEntityIdsAndRegenerateManipulators();
CreateTestSwitcher();
}
EditorTransformComponentSelection::~EditorTransformComponentSelection()
@@ -1038,6 +1059,8 @@ namespace AzToolsFramework
DestroyTransformModeSelectionCluster(m_transformModeClusterId);
UnregisterActions();
RemoveTestSwitcher(m_testSwitcherId);
m_pivotOverrideFrame.Reset();
EditorManipulatorCommandUndoRedoRequestBus::Handler::BusDisconnect();
@@ -2561,6 +2584,50 @@ namespace AzToolsFramework
m_transformModeSelectionHandler);
}
void EditorTransformComponentSelection::CreateTestSwitcher()
{
// Create test switcher
// & Set Current Active Mode
ViewportUi::ViewportUiRequestBus::EventResult(
m_testSwitcherId, ViewportUi::DefaultViewportId, &ViewportUi::ViewportUiRequestBus::Events::CreateSwitcher,
ViewportUi::ButtonId(1));
// create and register the buttons
m_boxShapeButtonId = RegisterSwitcherButton(m_testSwitcherId, "BoxShape", "Box Shape");
m_physxColliderButtonId = RegisterSwitcherButton(m_testSwitcherId, "PhysXCollider", "PhysX Collider");
m_transformButtonId = RegisterSwitcherButton(m_testSwitcherId, "Transform", "Transform");
// Change current active button for now
const auto onButtonClicked = [this](ViewportUi::ButtonId buttonId) {
if (buttonId == m_boxShapeButtonId)
{
ViewportUi::ViewportUiRequestBus::Event(
ViewportUi::DefaultViewportId, &ViewportUi::ViewportUiRequestBus::Events::SetSwitcherActiveButton, m_testSwitcherId,
m_boxShapeButtonId);
AZ_Printf("ViewportUi", "Box Shape");
}
else if (buttonId == m_physxColliderButtonId)
{
ViewportUi::ViewportUiRequestBus::Event(
ViewportUi::DefaultViewportId, &ViewportUi::ViewportUiRequestBus::Events::SetSwitcherActiveButton, m_testSwitcherId,
m_physxColliderButtonId);
AZ_Printf("ViewportUi", "PhysXCollider");
}
else if (buttonId == m_transformButtonId)
{
ViewportUi::ViewportUiRequestBus::Event(
ViewportUi::DefaultViewportId, &ViewportUi::ViewportUiRequestBus::Events::SetSwitcherActiveButton, m_testSwitcherId,
m_transformButtonId);
AZ_Printf("ViewportUi", "Transform");
}
};
m_testSwitcherHandler = AZ::Event<ViewportUi::ButtonId>::Handler(onButtonClicked);
ViewportUi::ViewportUiRequestBus::Event(
ViewportUi::DefaultViewportId, &ViewportUi::ViewportUiRequestBus::Events::RegisterClusterEventHandler, m_testSwitcherId,
m_testSwitcherHandler);
}
EditorTransformComponentSelectionRequests::Mode EditorTransformComponentSelection::GetTransformMode()
{
return m_mode;
@@ -281,6 +281,15 @@ namespace AzToolsFramework
ViewportUi::ButtonId m_rotateButtonId; ///< Id of the Viewport UI button for rotate mode.
ViewportUi::ButtonId m_scaleButtonId; ///< Id of the Viewport UI button for scale mode.
AZ::Event<ViewportUi::ButtonId>::Handler m_transformModeSelectionHandler; ///< Event handler for the Viewport UI cluster.
//! Create the Viewport UI Switcher. TEST
void CreateTestSwitcher();
ViewportUi::ClusterId m_testSwitcherId;
ViewportUi::ButtonId m_boxShapeButtonId;
ViewportUi::ButtonId m_physxColliderButtonId;
ViewportUi::ButtonId m_transformButtonId;
AZ::Event<ViewportUi::ButtonId>::Handler m_testSwitcherHandler;
};
/// The ETCS (EntityTransformComponentSelection) namespace contains functions and data used exclusively by
@@ -22,4 +22,11 @@ namespace AzToolsFramework::ViewportUi::Internal
, m_buttonId(buttonId)
{
}
Button::Button(AZStd::string icon, AZStd::string name, ButtonId buttonId)
: m_icon(AZStd::move(icon))
, m_name(AZStd::move(name))
, m_buttonId(buttonId)
{
}
} // namespace AzToolsFramework::ViewportUi::Internal
@@ -28,9 +28,11 @@ namespace AzToolsFramework::ViewportUi::Internal
};
explicit Button(AZStd::string icon, ButtonId buttonId);
Button(AZStd::string icon, AZStd::string name, ButtonId buttonId);
~Button() = default;
AZStd::string m_icon; //!< The icon for this button, string path to an image.
AZStd::string m_name; //!< The icon for this button, string path to an image.
State m_state = State::Deselected;
ButtonId m_buttonId;
};
@@ -13,6 +13,9 @@
#include <AzToolsFramework/ViewportUi/Button.h>
#include <AzToolsFramework/ViewportUi/Cluster.h>
#pragma optimize("", off)
#pragma inline_depth(0)
namespace AzToolsFramework::ViewportUi::Internal
{
Cluster::Cluster()
@@ -53,11 +56,18 @@ namespace AzToolsFramework::ViewportUi::Internal
}
}
ButtonId Cluster::AddButton(const AZStd::string& icon)
ButtonId Cluster::AddButton(const AZStd::string& icon, const AZStd::string& name)
{
auto buttonId = ButtonId(m_buttons.size() + 1);
m_buttons.insert({buttonId, AZStd::make_unique<Button>(icon, buttonId)});
if (name == AZStd::string())
{
m_buttons.insert({buttonId, AZStd::make_unique<Button>(icon, buttonId)});
}
else
{
m_buttons.insert({buttonId, AZStd::make_unique<Button>(icon, name, buttonId)});
}
return buttonId;
}
@@ -34,7 +34,7 @@ namespace AzToolsFramework::ViewportUi::Internal
void SetClusterId(ClusterId id);
ClusterId GetClusterId() const;
ButtonId AddButton(const AZStd::string& icon);
ButtonId AddButton(const AZStd::string& icon, const AZStd::string& name = AZStd::string());
Button* GetButton(ButtonId buttonId);
AZStd::vector<Button*> GetButtons();
@@ -18,6 +18,7 @@
#include <AzToolsFramework/ViewportSelection/EditorSelectionUtil.h>
#include <AzToolsFramework/ViewportUi/ViewportUiDisplay.h>
#include <AzToolsFramework/ViewportUi/ViewportUiCluster.h>
#include <AzToolsFramework/ViewportUi/ViewportUiSwitcher.h>
#include <AzToolsFramework/ViewportUi/ViewportUiTextField.h>
#include <QWidget>
@@ -93,6 +94,51 @@ namespace AzToolsFramework::ViewportUi::Internal
}
}
void ViewportUiDisplay::AddSwitcher(AZStd::shared_ptr<Cluster> cluster, ButtonId currMode)
{
if (!cluster.get())
{
return;
}
auto viewportUiSwitcher = AZStd::make_shared<ViewportUiSwitcher>(cluster, currMode);
auto id = AddViewportUiElement(viewportUiSwitcher);
cluster->SetViewportUiElementId(id);
PositionViewportUiElementAnchored(id, Qt::AlignTop | Qt::AlignLeft);
}
void ViewportUiDisplay::AddSwitcherButton(const ViewportUiElementId clusterId, Button* button)
{
if (auto viewportUiSwitcher = qobject_cast<ViewportUiSwitcher*>(GetViewportUiElement(clusterId).get()))
{
viewportUiSwitcher->AddButton(button);
}
}
void ViewportUiDisplay::RemoveSwitcherButton(ViewportUiElementId clusterId, ButtonId buttonId)
{
if (auto cluster = qobject_cast<ViewportUiSwitcher*>(GetViewportUiElement(clusterId).get()))
{
cluster->RemoveButton(buttonId);
}
}
void ViewportUiDisplay::UpdateSwitcher(ViewportUiElementId clusterId)
{
if (auto cluster = qobject_cast<ViewportUiSwitcher*>(GetViewportUiElement(clusterId).get()))
{
cluster->Update();
}
}
void ViewportUiDisplay::SetSwitcherActiveMode(ViewportUiElementId clusterId, ButtonId buttonId)
{
if (auto viewportUiSwitcher = qobject_cast<ViewportUiSwitcher*>(GetViewportUiElement(clusterId).get()))
{
viewportUiSwitcher->SetActiveMode(buttonId);
}
}
void ViewportUiDisplay::AddTextField(AZStd::shared_ptr<TextField> textField)
{
if (!textField.get())
@@ -61,6 +61,12 @@ namespace AzToolsFramework::ViewportUi::Internal
void RemoveClusterButton(ViewportUiElementId clusterId, ButtonId buttonId);
void UpdateCluster(const ViewportUiElementId clusterId);
void AddSwitcher(AZStd::shared_ptr<Cluster> cluster, ButtonId currMode);
void AddSwitcherButton(ViewportUiElementId clusterId, Button* button);
void RemoveSwitcherButton(ViewportUiElementId clusterId, ButtonId buttonId);
void UpdateSwitcher(const ViewportUiElementId clusterId);
void SetSwitcherActiveMode(ViewportUiElementId clusterId, ButtonId buttonId);
void AddTextField(AZStd::shared_ptr<TextField> textField);
void UpdateTextField(ViewportUiElementId textFieldId);
@@ -38,6 +38,14 @@ namespace AzToolsFramework::ViewportUi
return RegisterNewCluster(cluster);
}
const ClusterId ViewportUiManager::CreateSwitcher(ButtonId currMode)
{
auto cluster = AZStd::make_shared<Internal::Cluster>();
m_viewportUi->AddSwitcher(cluster, currMode);
return RegisterNewCluster(cluster);
}
void ViewportUiManager::SetClusterActiveButton(const ClusterId clusterId, const ButtonId buttonId)
{
if (auto clusterEntry = m_clusters.find(clusterId); clusterEntry != m_clusters.end())
@@ -48,6 +56,17 @@ namespace AzToolsFramework::ViewportUi
}
}
void ViewportUiManager::SetSwitcherActiveButton(const ClusterId clusterId, const ButtonId buttonId)
{
if (auto clusterEntry = m_clusters.find(clusterId); clusterEntry != m_clusters.end())
{
auto cluster = clusterEntry->second;
cluster->SetHighlightedButton(buttonId);
m_viewportUi->SetSwitcherActiveMode(cluster->GetViewportUiElementId(), buttonId);
UpdateSwitcherUi(cluster.get());
}
}
void ViewportUiManager::RegisterClusterEventHandler(const ClusterId clusterId, AZ::Event<ButtonId>::Handler& handler)
{
if (auto clusterEntry = m_clusters.find(clusterId); clusterEntry != m_clusters.end())
@@ -71,6 +90,20 @@ namespace AzToolsFramework::ViewportUi
return ButtonId(0);
}
const ButtonId ViewportUiManager::CreateSwitcherButton(const ClusterId clusterId, const AZStd::string& icon, const AZStd::string& name)
{
if (auto clusterEntry = m_clusters.find(clusterId); clusterEntry != m_clusters.end())
{
auto cluster = clusterEntry->second;
auto newId = cluster->AddButton(icon, name);
m_viewportUi->AddSwitcherButton(cluster->GetViewportUiElementId(), cluster->GetButton(newId));
return newId;
}
return ButtonId(0);
}
void ViewportUiManager::RemoveCluster(const ClusterId clusterId)
{
if (auto clusterEntry = m_clusters.find(clusterId); clusterEntry != m_clusters.end())
@@ -229,6 +262,11 @@ namespace AzToolsFramework::ViewportUi
m_viewportUi->UpdateCluster(cluster->GetViewportUiElementId());
}
void ViewportUiManager::UpdateSwitcherUi(Internal::Cluster* cluster)
{
m_viewportUi->UpdateSwitcher(cluster->GetViewportUiElementId());
}
void ViewportUiManager::UpdateTextFieldUi(Internal::TextField* textField)
{
m_viewportUi->UpdateTextField(textField->m_viewportId);
@@ -32,8 +32,11 @@ namespace AzToolsFramework::ViewportUi
// ViewportUiRequestBus ...
const ClusterId CreateCluster() override;
const ClusterId CreateSwitcher(ButtonId currMode) override;
void SetClusterActiveButton(ClusterId clusterId, ButtonId buttonId) override;
void SetSwitcherActiveButton(ClusterId clusterId, ButtonId buttonId) override;
const ButtonId CreateClusterButton(ClusterId clusterId, const AZStd::string& icon) override;
const ButtonId CreateSwitcherButton(ClusterId clusterId, const AZStd::string& icon, const AZStd::string& name = AZStd::string()) override;
void RegisterClusterEventHandler(ClusterId clusterId, AZ::Event<ButtonId>::Handler& handler) override;
void RemoveCluster(ClusterId clusterId) override;
void SetClusterVisible(ClusterId clusterId, bool visible);
@@ -71,6 +74,8 @@ namespace AzToolsFramework::ViewportUi
TextFieldId RegisterNewTextField(AZStd::shared_ptr<Internal::TextField>& textField);
//! Update the corresponding ui element for the given cluster.
void UpdateClusterUi(Internal::Cluster* cluster);
//! Update the corresponding ui element for the given cluster.
void UpdateSwitcherUi(Internal::Cluster* cluster);
//! Update the corresponding ui element for the given text field.
void UpdateTextFieldUi(Internal::TextField* textField);
};
@@ -46,10 +46,17 @@ namespace AzToolsFramework::ViewportUi
public:
//! Creates and registers a cluster with the Viewport UI system.
virtual const ClusterId CreateCluster() = 0;
//! Creates and registers a switcher with the Viewport UI system.
virtual const ClusterId CreateSwitcher(ButtonId currMode) = 0;
//! Sets the active button of the cluster. This is the button which will display as highlighted.
virtual void SetClusterActiveButton(ClusterId clusterId, ButtonId buttonId) = 0;
//! Sets the active button of the switcher. This is the button which will display as highlighted.
//! Maybe update this comment
virtual void SetSwitcherActiveButton(ClusterId clusterId, ButtonId buttonId) = 0;
//! Registers a new button onto a cluster.
virtual const ButtonId CreateClusterButton(const ClusterId clusterId, const AZStd::string& icon) = 0;
//! Registers a new button onto a switcher.
virtual const ButtonId CreateSwitcherButton(const ClusterId clusterId, const AZStd::string& icon, const AZStd::string& name = AZStd::string()) = 0;
//! Registers an event handler to handle events from the cluster.
virtual void RegisterClusterEventHandler(ClusterId clusterId, AZ::Event<ButtonId>::Handler& handler) = 0;
//! Removes a cluster from the Viewport UI system.
@@ -0,0 +1,125 @@
#include <AzToolsFramework/ViewportUi/Cluster.h>
#include <AzToolsFramework/ViewportUi/ViewportUiSwitcher.h>
namespace AzToolsFramework::ViewportUi::Internal
{
ViewportUiSwitcher::ViewportUiSwitcher(AZStd::shared_ptr<Cluster> switcher, ButtonId currentMode)
: m_switcher(switcher)
, m_currentMode(currentMode)
{
setOrientation(Qt::Orientation::Horizontal);
setStyleSheet(QString("QToolBar {background-color: none; border: none; spacing: 3px;}"
"QToolButton {background-color: #464646; border: outset; border-color: white; border-radius: 7px; "
"border-width: 2px; padding: 7px; color: white;}"));
const AZStd::vector<Button*> buttons = switcher->GetButtons();
for (auto button : buttons)
{
// add all the other buttons after
if (button->m_buttonId)
{
AddButton(button);
}
}
}
ViewportUiSwitcher::~ViewportUiSwitcher()
{
}
void ViewportUiSwitcher::AddButton(Button* button)
{
QAction* action = new QAction();
action->setCheckable(true);
action->setIcon(QIcon(QString(button->m_icon.c_str())));
if (!action)
{
return;
}
// set hover to true by default
action->setProperty("IconHasHoverEffect", true);
// if its the first button added to the switcher add it as a button instead of action
if (button->m_buttonId == m_currentMode)
{
QString buttonName = (button->m_name).c_str();
QIcon buttonIcon = QString((button->m_icon).c_str());
m_activeButton = new QToolButton();
m_activeButton->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
m_activeButton->setIcon(buttonIcon);
m_activeButton->setText(buttonName);
addWidget(m_activeButton);
}
else
{
// add the action
addAction(action);
}
// resize to fit new action with minimum extra space
resize(minimumSizeHint());
const AZStd::function<void()>&callback = [this, button]() { m_switcher->PressButton(button->m_buttonId); };
const AZStd::function<void(QAction*)>& updateCallback = [button](QAction* action) {
action->setChecked(button->m_state == Button::State::Selected);
};
// connect the callback if provided
if (callback)
{
QObject::connect(action, &QAction::triggered, action, callback);
}
// register the action
m_widgetCallbacks.AddWidget(action, [updateCallback](QPointer<QObject> object)
{
updateCallback(static_cast<QAction*>(object.data()));
});
m_buttonActionMap.insert({button->m_buttonId, action});
}
void ViewportUiSwitcher::RemoveButton(ButtonId buttonId)
{
ButtonId deleteLater = buttonId;
}
void ViewportUiSwitcher::Update()
{
}
void ViewportUiSwitcher::SetActiveMode(ButtonId buttonId)
{
// Change the toolbutton's name and icon to that button
const AZStd::vector<Button*> buttons = m_switcher->GetButtons();
for (auto button : buttons)
{
if (button->m_buttonId == buttonId)
{
QString buttonName = (button->m_name).c_str();
QIcon buttonIcon = QString((button->m_icon).c_str());
m_activeButton->setIcon(buttonIcon);
m_activeButton->setText(buttonName);
}
}
// look up button ID in map then remove it from its current position
auto itr = m_buttonActionMap.find(buttonId);
QAction* action = itr->second;
removeAction(action); // call remove button?
// add the last action removed
if (m_currentMode != buttonId)
{
itr = m_buttonActionMap.find(m_currentMode);
action = itr->second;
addAction(action);
}
m_currentMode = buttonId;
}
} // namespace AzToolsFramework::ViewportUi::Internal
@@ -0,0 +1,41 @@
#pragma once
#include <AzToolsFramework/ViewportUi/Button.h>
#include <AzCore/std/containers/unordered_map.h>
#include <AzCore/std/smart_ptr/shared_ptr.h>
#include <AzToolsFramework/ViewportUi/ViewportUiWidgetCallbacks.h>
#include <functional>
#include <QPointer>
#include <QToolBar>
#include <QToolButton>
class Cluster;
namespace AzToolsFramework::ViewportUi::Internal
{
//! Helper class to make switchers (toolbars) for display in Viewport UI.
class ViewportUiSwitcher : public QToolBar
{
Q_OBJECT
public:
ViewportUiSwitcher(AZStd::shared_ptr<Cluster> switcher, ButtonId currentMode);
~ViewportUiSwitcher();
//! Adds a new button to the cluster.
void AddButton(Button* button);
//! Removes a button from the cluster.
void RemoveButton(ButtonId buttonId);
void Update();
void SetActiveMode(ButtonId buttonId);
private:
QToolButton* m_activeButton;
ButtonId m_currentMode;
AZStd::shared_ptr<Cluster> m_switcher; //!< Data structure which the cluster will be displaying to the Viewport UI.
AZStd::unordered_map<ButtonId, QPointer<QAction>> m_buttonActionMap; //!< Map for buttons to their corresponding actions.
ViewportUiWidgetCallbacks m_widgetCallbacks; //!< Registers actions and manages updates.
};
} // namespace AzToolsFramework::ViewportUi::Internal
@@ -498,6 +498,8 @@ set(FILES
ViewportUi/ViewportUiTextField.cpp
ViewportUi/ViewportUiCluster.h
ViewportUi/ViewportUiCluster.cpp
ViewportUi/ViewportUiSwitcher.h
ViewportUi/ViewportUiSwitcher.cpp
ViewportUi/ViewportUiWidgetCallbacks.h
ViewportUi/ViewportUiWidgetCallbacks.cpp
ViewportUi/ViewportUiDisplayLayout.h