You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
501 lines
22 KiB
C++
501 lines
22 KiB
C++
/*
|
|
* Copyright (c) Contributors to the Open 3D Engine Project.
|
|
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
|
|
*
|
|
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
|
*
|
|
*/
|
|
|
|
#include "EditorWhiteBoxComponentMode.h"
|
|
#include "SubComponentModes/EditorWhiteBoxDefaultMode.h"
|
|
#include "SubComponentModes/EditorWhiteBoxEdgeRestoreMode.h"
|
|
#include "Viewport/WhiteBoxViewportConstants.h"
|
|
|
|
#include <AzCore/Component/TransformBus.h>
|
|
#include <AzCore/std/sort.h>
|
|
#include <AzToolsFramework/Manipulators/ManipulatorSnapping.h>
|
|
#include <AzToolsFramework/Manipulators/ManipulatorView.h>
|
|
#include <AzToolsFramework/Maths/TransformUtils.h>
|
|
#include <AzToolsFramework/ViewportSelection/EditorSelectionUtil.h>
|
|
#include <QApplication> // required for querying modifier keys
|
|
#include <QVBoxLayout>
|
|
#include <WhiteBox/EditorWhiteBoxComponentBus.h>
|
|
|
|
namespace WhiteBox
|
|
{
|
|
AZ_CLASS_ALLOCATOR_IMPL(EditorWhiteBoxComponentMode, AZ::SystemAllocator, 0)
|
|
|
|
// helper function to return what modifier keys move us to restore mode
|
|
static bool RestoreModifier(AzToolsFramework::ViewportInteraction::KeyboardModifiers modifiers)
|
|
{
|
|
return modifiers.Shift() && modifiers.Ctrl();
|
|
}
|
|
|
|
// helper function to return what type of edge selection mode we're in
|
|
static EdgeSelectionType DecideEdgeSelectionMode(const SubMode subMode)
|
|
{
|
|
return subMode == SubMode::EdgeRestore ? EdgeSelectionType::All : EdgeSelectionType::Polygon;
|
|
}
|
|
|
|
EditorWhiteBoxComponentMode::EditorWhiteBoxComponentMode(
|
|
const AZ::EntityComponentIdPair& entityComponentIdPair, const AZ::Uuid componentType)
|
|
: EditorBaseComponentMode(entityComponentIdPair, componentType)
|
|
, m_worldFromLocal(AZ::Transform::Identity())
|
|
{
|
|
AzFramework::EntityDebugDisplayEventBus::Handler::BusConnect(entityComponentIdPair.GetEntityId());
|
|
EditorWhiteBoxComponentModeRequestBus::Handler::BusConnect(entityComponentIdPair);
|
|
AZ::TransformNotificationBus::Handler::BusConnect(entityComponentIdPair.GetEntityId());
|
|
EditorWhiteBoxComponentNotificationBus::Handler::BusConnect(entityComponentIdPair);
|
|
|
|
// default behavior for querying modifier keys (ask the QApplication)
|
|
m_keyboardMofifierQueryFn = []()
|
|
{
|
|
return AzToolsFramework::ViewportInteraction::QueryKeyboardModifiers();
|
|
};
|
|
|
|
m_worldFromLocal = AzToolsFramework::WorldFromLocalWithUniformScale(entityComponentIdPair.GetEntityId());
|
|
CreateSubModeSelectionCluster();
|
|
// start with DefaultMode
|
|
EnterDefaultMode();
|
|
}
|
|
|
|
EditorWhiteBoxComponentMode::~EditorWhiteBoxComponentMode()
|
|
{
|
|
RemoveSubModeSelectionCluster();
|
|
|
|
EditorWhiteBoxComponentNotificationBus::Handler::BusDisconnect();
|
|
AZ::TransformNotificationBus::Handler::BusDisconnect();
|
|
EditorWhiteBoxComponentModeRequestBus::Handler::BusDisconnect();
|
|
AzFramework::EntityDebugDisplayEventBus::Handler::BusDisconnect();
|
|
}
|
|
|
|
void EditorWhiteBoxComponentMode::Refresh()
|
|
{
|
|
MarkWhiteBoxIntersectionDataDirty();
|
|
|
|
AZStd::visit(
|
|
[](auto& mode)
|
|
{
|
|
mode->Refresh();
|
|
},
|
|
m_modes);
|
|
|
|
AzToolsFramework::ComponentModeFramework::ComponentModeSystemRequestBus::Broadcast(
|
|
&AzToolsFramework::ComponentModeFramework::ComponentModeSystemRequests::RefreshActions);
|
|
}
|
|
|
|
static AZStd::optional<VertexIntersection> FindClosestVertexIntersection(
|
|
const GeometryIntersectionData& whiteBoxIntersectionData, const AZ::Vector3& localRayOrigin,
|
|
const AZ::Vector3& localRayDirection, const AZ::Transform& worldFromLocal,
|
|
const AzFramework::CameraState& cameraState)
|
|
{
|
|
VertexIntersection vertexIntersection;
|
|
|
|
const float scaleRecip = AzToolsFramework::ScaleReciprocal(worldFromLocal);
|
|
|
|
// find the closest vertex bound
|
|
for (const auto& vertexBound : whiteBoxIntersectionData.m_vertexBounds)
|
|
{
|
|
const AZ::Vector3 worldCenter = worldFromLocal.TransformPoint(vertexBound.m_bound.m_center);
|
|
|
|
const float screenRadius = vertexBound.m_bound.m_radius *
|
|
AzToolsFramework::CalculateScreenToWorldMultiplier(worldCenter, cameraState) * scaleRecip;
|
|
|
|
float vertexDistance = std::numeric_limits<float>::max();
|
|
const bool intersection = IntersectRayVertex(
|
|
vertexBound.m_bound, screenRadius, localRayOrigin, localRayDirection, vertexDistance);
|
|
|
|
if (intersection && vertexDistance < vertexIntersection.m_intersection.m_closestDistance)
|
|
{
|
|
vertexIntersection.m_closestVertexWithHandle = vertexBound;
|
|
vertexIntersection.m_intersection.m_closestDistance = vertexDistance;
|
|
}
|
|
}
|
|
|
|
if (vertexIntersection.m_intersection.m_closestDistance < std::numeric_limits<float>::max())
|
|
{
|
|
vertexIntersection.m_intersection.m_localIntersectionPoint =
|
|
localRayOrigin + localRayDirection * vertexIntersection.m_intersection.m_closestDistance;
|
|
|
|
return vertexIntersection;
|
|
}
|
|
else
|
|
{
|
|
return AZStd::optional<VertexIntersection>{};
|
|
}
|
|
}
|
|
|
|
static AZStd::optional<EdgeIntersection> FindClosestEdgeIntersection(
|
|
const GeometryIntersectionData& whiteBoxIntersectionData, const AZ::Vector3& localRayOrigin,
|
|
const AZ::Vector3& localRayDirection, const AZ::Transform& worldFromLocal,
|
|
const AzFramework::CameraState& cameraState)
|
|
{
|
|
EdgeIntersection edgeIntersection;
|
|
|
|
const float scaleRecip = AzToolsFramework::ScaleReciprocal(worldFromLocal);
|
|
|
|
// find the closest edge bound
|
|
for (const auto& edgeBound : whiteBoxIntersectionData.m_edgeBounds)
|
|
{
|
|
// degenerate edges cause false positives in the intersection test
|
|
if (edgeBound.m_bound.m_start.IsClose(edgeBound.m_bound.m_end))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
const AZ::Vector3 localMidpoint = (edgeBound.m_bound.m_end + edgeBound.m_bound.m_start) * 0.5f;
|
|
const AZ::Vector3 worldMidpoint = worldFromLocal.TransformPoint(localMidpoint);
|
|
|
|
const float screenRadius = edgeBound.m_bound.m_radius *
|
|
AzToolsFramework::CalculateScreenToWorldMultiplier(worldMidpoint, cameraState) * scaleRecip;
|
|
|
|
float edgeDistance = std::numeric_limits<float>::max();
|
|
const bool intersection =
|
|
IntersectRayEdge(edgeBound.m_bound, screenRadius, localRayOrigin, localRayDirection, edgeDistance);
|
|
|
|
if (intersection && edgeDistance < edgeIntersection.m_intersection.m_closestDistance)
|
|
{
|
|
edgeIntersection.m_closestEdgeWithHandle = edgeBound;
|
|
edgeIntersection.m_intersection.m_closestDistance = edgeDistance;
|
|
}
|
|
}
|
|
|
|
if (edgeIntersection.m_intersection.m_closestDistance < std::numeric_limits<float>::max())
|
|
{
|
|
// calculate closest intersection point
|
|
edgeIntersection.m_intersection.m_localIntersectionPoint =
|
|
localRayOrigin + localRayDirection * edgeIntersection.m_intersection.m_closestDistance;
|
|
|
|
return edgeIntersection;
|
|
}
|
|
else
|
|
{
|
|
return AZStd::optional<EdgeIntersection>{};
|
|
}
|
|
}
|
|
|
|
static AZStd::optional<PolygonIntersection> FindClosestPolygonIntersection(
|
|
const GeometryIntersectionData& whiteBoxIntersectionData, const AZ::Vector3& localRayOrigin,
|
|
const AZ::Vector3& localRayDirection)
|
|
{
|
|
PolygonIntersection polygonIntersection;
|
|
|
|
// find closest polygon bound
|
|
for (const auto& polygonBound : whiteBoxIntersectionData.m_polygonBounds)
|
|
{
|
|
int64_t pickedTriangleIndex;
|
|
float polygonDistance = std::numeric_limits<float>::max();
|
|
const bool intersection = IntersectRayPolygon(
|
|
polygonBound.m_bound, localRayOrigin, localRayDirection, polygonDistance, pickedTriangleIndex);
|
|
|
|
if (intersection && polygonDistance < polygonIntersection.m_intersection.m_closestDistance)
|
|
{
|
|
polygonIntersection.m_pickedFaceHandle = polygonBound.m_handle.m_faceHandles[pickedTriangleIndex];
|
|
polygonIntersection.m_closestPolygonWithHandle = polygonBound;
|
|
polygonIntersection.m_intersection.m_closestDistance = polygonDistance;
|
|
polygonIntersection.m_intersection.m_localIntersectionPoint =
|
|
localRayOrigin + localRayDirection * polygonDistance;
|
|
}
|
|
}
|
|
|
|
return polygonIntersection.m_intersection.m_closestDistance < std::numeric_limits<float>::max()
|
|
? polygonIntersection
|
|
: AZStd::optional<PolygonIntersection>{};
|
|
}
|
|
|
|
bool EditorWhiteBoxComponentMode::HandleMouseInteraction(
|
|
const AzToolsFramework::ViewportInteraction::MouseInteractionEvent& mouseInteraction)
|
|
{
|
|
AZ_PROFILE_FUNCTION(AzToolsFramework);
|
|
|
|
WhiteBoxMesh* whiteBox = nullptr;
|
|
EditorWhiteBoxComponentRequestBus::EventResult(
|
|
whiteBox, GetEntityComponentIdPair(), &EditorWhiteBoxComponentRequests::GetWhiteBoxMesh);
|
|
|
|
// generate mesh to query if it needs to be rebuilt
|
|
if (!m_intersectionAndRenderData.has_value())
|
|
{
|
|
RecalculateWhiteBoxIntersectionData(DecideEdgeSelectionMode(m_currentSubMode));
|
|
}
|
|
|
|
const AZ::Transform localFromWorld = m_worldFromLocal.GetInverse();
|
|
|
|
const AZ::Vector3 localRayOrigin =
|
|
localFromWorld.TransformPoint(mouseInteraction.m_mouseInteraction.m_mousePick.m_rayOrigin);
|
|
const AZ::Vector3 localRayDirection = AzToolsFramework::TransformDirectionNoScaling(
|
|
localFromWorld, mouseInteraction.m_mouseInteraction.m_mousePick.m_rayDirection);
|
|
|
|
const int viewportId = mouseInteraction.m_mouseInteraction.m_interactionId.m_viewportId;
|
|
const AzFramework::CameraState cameraState = AzToolsFramework::GetCameraState(viewportId);
|
|
|
|
const AZStd::optional<EdgeIntersection> edgeIntersection = FindClosestEdgeIntersection(
|
|
m_intersectionAndRenderData->m_whiteBoxIntersectionData, localRayOrigin, localRayDirection,
|
|
m_worldFromLocal, cameraState);
|
|
|
|
const AZStd::optional<PolygonIntersection> polygonIntersection = FindClosestPolygonIntersection(
|
|
m_intersectionAndRenderData->m_whiteBoxIntersectionData, localRayOrigin, localRayDirection);
|
|
|
|
const AZStd::optional<VertexIntersection> vertexIntersection = FindClosestVertexIntersection(
|
|
m_intersectionAndRenderData->m_whiteBoxIntersectionData, localRayOrigin, localRayDirection,
|
|
m_worldFromLocal, cameraState);
|
|
|
|
// interactionHandled will be set to true if the mouse interaction has been handled by this white box component
|
|
// which involves either interacting with a manipulator from this white box or clicking on the white box mesh
|
|
// itself
|
|
bool interactionHandled = AZStd::visit(
|
|
[&mouseInteraction, entityComponentIdPair = GetEntityComponentIdPair(), &edgeIntersection,
|
|
&polygonIntersection, &vertexIntersection](auto& mode)
|
|
{
|
|
return mode->HandleMouseInteraction(
|
|
mouseInteraction, entityComponentIdPair, edgeIntersection, polygonIntersection, vertexIntersection);
|
|
},
|
|
m_modes);
|
|
|
|
if (mouseInteraction.m_mouseInteraction.m_mouseButtons.Left() &&
|
|
mouseInteraction.m_mouseEvent == AzToolsFramework::ViewportInteraction::MouseEvent::Up &&
|
|
(edgeIntersection || polygonIntersection || vertexIntersection))
|
|
{
|
|
interactionHandled = true;
|
|
}
|
|
|
|
return interactionHandled;
|
|
}
|
|
|
|
AZStd::vector<AzToolsFramework::ActionOverride> EditorWhiteBoxComponentMode::PopulateActionsImpl()
|
|
{
|
|
return AZStd::visit(
|
|
[entityComponentIdPair = GetEntityComponentIdPair()](auto& mode)
|
|
{
|
|
return mode->PopulateActions(entityComponentIdPair);
|
|
},
|
|
m_modes);
|
|
}
|
|
|
|
static void SetViewportUiClusterActiveButton(
|
|
AzToolsFramework::ViewportUi::ClusterId clusterId, AzToolsFramework::ViewportUi::ButtonId buttonId)
|
|
{
|
|
AzToolsFramework::ViewportUi::ViewportUiRequestBus::Event(
|
|
AzToolsFramework::ViewportUi::DefaultViewportId,
|
|
&AzToolsFramework::ViewportUi::ViewportUiRequestBus::Events::SetClusterActiveButton, clusterId, buttonId);
|
|
}
|
|
|
|
void EditorWhiteBoxComponentMode::EnterDefaultMode()
|
|
{
|
|
m_modes = AZStd::make_unique<DefaultMode>(GetEntityComponentIdPair());
|
|
m_intersectionAndRenderData = {};
|
|
m_currentSubMode = SubMode::Default;
|
|
SetViewportUiClusterActiveButton(m_modeSelectionClusterId, m_defaultModeButtonId);
|
|
}
|
|
|
|
void EditorWhiteBoxComponentMode::EnterEdgeRestoreMode()
|
|
{
|
|
m_modes = AZStd::make_unique<EdgeRestoreMode>();
|
|
m_intersectionAndRenderData = {};
|
|
m_currentSubMode = SubMode::EdgeRestore;
|
|
SetViewportUiClusterActiveButton(m_modeSelectionClusterId, m_edgeRestoreModeButtonId);
|
|
}
|
|
|
|
void EditorWhiteBoxComponentMode::DisplayEntityViewport(
|
|
[[maybe_unused]] const AzFramework::ViewportInfo& viewportInfo, AzFramework::DebugDisplayRequests& debugDisplay)
|
|
{
|
|
AZ_PROFILE_FUNCTION(AzToolsFramework);
|
|
|
|
const auto modifiers = m_keyboardMofifierQueryFn();
|
|
|
|
// handle mode switch
|
|
{
|
|
auto* defaultMode = AZStd::get_if<AZStd::unique_ptr<DefaultMode>>(&m_modes);
|
|
auto* edgeRestoreMode = AZStd::get_if<AZStd::unique_ptr<EdgeRestoreMode>>(&m_modes);
|
|
|
|
// enter edge restore mode if inside normal mode and restore modifier is held
|
|
if (RestoreModifier(modifiers))
|
|
{
|
|
if (defaultMode != nullptr)
|
|
{
|
|
EnterEdgeRestoreMode();
|
|
}
|
|
|
|
m_restoreModifierHeld = true;
|
|
}
|
|
// enter default mode if restore modifier is not currently held and
|
|
// was held to enter restore mode (as opposed to viewport ui widget)
|
|
else if (!RestoreModifier(modifiers))
|
|
{
|
|
if (m_restoreModifierHeld && edgeRestoreMode != nullptr)
|
|
{
|
|
EnterDefaultMode();
|
|
}
|
|
|
|
m_restoreModifierHeld = false;
|
|
}
|
|
}
|
|
|
|
// generate mesh to query
|
|
if (!m_intersectionAndRenderData.has_value())
|
|
{
|
|
RecalculateWhiteBoxIntersectionData(DecideEdgeSelectionMode(m_currentSubMode));
|
|
}
|
|
|
|
debugDisplay.DepthTestOn();
|
|
debugDisplay.SetColor(cl_whiteBoxEdgeUserColor);
|
|
debugDisplay.SetLineWidth(4.0f);
|
|
|
|
AZStd::visit(
|
|
[entityComponentIdPair = GetEntityComponentIdPair(),
|
|
&whiteBoxIntersectionAndRenderData = m_intersectionAndRenderData, viewportInfo, &debugDisplay,
|
|
&worldFromLocal = m_worldFromLocal](auto& mode)
|
|
{
|
|
mode->Display(
|
|
entityComponentIdPair, worldFromLocal, whiteBoxIntersectionAndRenderData.value(), viewportInfo,
|
|
debugDisplay);
|
|
},
|
|
m_modes);
|
|
|
|
debugDisplay.DepthTestOff();
|
|
}
|
|
|
|
void EditorWhiteBoxComponentMode::MarkWhiteBoxIntersectionDataDirty()
|
|
{
|
|
m_intersectionAndRenderData = {};
|
|
}
|
|
|
|
// combine user and mesh edge handles into a single collection
|
|
static Api::EdgeHandles BuildAllEdgeHandles(const Api::EdgeTypes& edgeHandlesPair)
|
|
{
|
|
Api::EdgeHandles allEdgeHandles;
|
|
allEdgeHandles.reserve(edgeHandlesPair.m_mesh.size() + edgeHandlesPair.m_user.size());
|
|
allEdgeHandles.insert(allEdgeHandles.end(), edgeHandlesPair.m_mesh.cbegin(), edgeHandlesPair.m_mesh.cend());
|
|
allEdgeHandles.insert(allEdgeHandles.end(), edgeHandlesPair.m_user.cbegin(), edgeHandlesPair.m_user.cend());
|
|
return allEdgeHandles;
|
|
}
|
|
|
|
void EditorWhiteBoxComponentMode::RecalculateWhiteBoxIntersectionData(const EdgeSelectionType edgeSelectionMode)
|
|
{
|
|
AZ_PROFILE_FUNCTION(AzToolsFramework);
|
|
|
|
WhiteBoxMesh* whiteBox = nullptr;
|
|
EditorWhiteBoxComponentRequestBus::EventResult(
|
|
whiteBox, GetEntityComponentIdPair(), &EditorWhiteBoxComponentRequests::GetWhiteBoxMesh);
|
|
|
|
m_intersectionAndRenderData = IntersectionAndRenderData{};
|
|
for (const auto& vertexHandle : Api::MeshVertexHandles(*whiteBox))
|
|
{
|
|
const auto vertexPosition = Api::VertexPosition(*whiteBox, vertexHandle);
|
|
m_intersectionAndRenderData->m_whiteBoxIntersectionData.m_vertexBounds.emplace_back(
|
|
VertexBoundWithHandle{{vertexPosition, cl_whiteBoxVertexManipulatorSize}, vertexHandle});
|
|
}
|
|
|
|
for (const auto& polygonHandle : Api::MeshPolygonHandles(*whiteBox))
|
|
{
|
|
const auto triangles = Api::FacesPositions(*whiteBox, polygonHandle.m_faceHandles);
|
|
m_intersectionAndRenderData->m_whiteBoxIntersectionData.m_polygonBounds.emplace_back(
|
|
PolygonBoundWithHandle{{triangles}, polygonHandle});
|
|
}
|
|
|
|
const auto edgeHandlesPair = Api::MeshUserEdgeHandles(*whiteBox);
|
|
|
|
const auto edgeHandles = [edgeSelectionMode, &edgeHandlesPair]()
|
|
{
|
|
switch (edgeSelectionMode)
|
|
{
|
|
case EdgeSelectionType::Polygon:
|
|
return edgeHandlesPair.m_user;
|
|
case EdgeSelectionType::All:
|
|
return BuildAllEdgeHandles(edgeHandlesPair);
|
|
default:
|
|
return Api::EdgeHandles{};
|
|
}
|
|
}();
|
|
|
|
// all edges that are valid to interact with at this time
|
|
for (const auto& edgeHandle : edgeHandles)
|
|
{
|
|
const auto edge = Api::EdgeVertexPositions(*whiteBox, edgeHandle);
|
|
m_intersectionAndRenderData->m_whiteBoxIntersectionData.m_edgeBounds.emplace_back(
|
|
EdgeBoundWithHandle{EdgeBound{edge[0], edge[1], cl_whiteBoxEdgeSelectionWidth}, edgeHandle});
|
|
}
|
|
|
|
// handle drawing 'user' and 'mesh' edges slightly differently
|
|
for (const auto& edgeHandle : edgeHandlesPair.m_user)
|
|
{
|
|
const auto edge = Api::EdgeVertexPositions(*whiteBox, edgeHandle);
|
|
m_intersectionAndRenderData->m_whiteBoxEdgeRenderData.m_bounds.m_user.emplace_back(
|
|
EdgeBoundWithHandle{EdgeBound{edge[0], edge[1], cl_whiteBoxEdgeSelectionWidth}, edgeHandle});
|
|
}
|
|
|
|
for (const auto& edgeHandle : edgeHandlesPair.m_mesh)
|
|
{
|
|
const auto edge = Api::EdgeVertexPositions(*whiteBox, edgeHandle);
|
|
m_intersectionAndRenderData->m_whiteBoxEdgeRenderData.m_bounds.m_mesh.emplace_back(
|
|
EdgeBoundWithHandle{EdgeBound{edge[0], edge[1], cl_whiteBoxEdgeSelectionWidth}, edgeHandle});
|
|
}
|
|
}
|
|
|
|
void EditorWhiteBoxComponentMode::OnTransformChanged(
|
|
[[maybe_unused]] const AZ::Transform& local, const AZ::Transform& world)
|
|
{
|
|
m_worldFromLocal = AzToolsFramework::TransformUniformScale(world);
|
|
}
|
|
|
|
void EditorWhiteBoxComponentMode::OnDefaultShapeTypeChanged([[maybe_unused]] const DefaultShapeType defaultShape)
|
|
{
|
|
// ensure the mode and all modifiers are refreshed
|
|
Refresh();
|
|
}
|
|
|
|
void EditorWhiteBoxComponentMode::OverrideKeyboardModifierQuery(
|
|
const KeyboardModifierQueryFn& keyboardModifierQueryFn)
|
|
{
|
|
m_keyboardMofifierQueryFn = keyboardModifierQueryFn;
|
|
}
|
|
|
|
static AzToolsFramework::ViewportUi::ButtonId RegisterClusterButton(
|
|
AzToolsFramework::ViewportUi::ClusterId clusterId, const char* iconName)
|
|
{
|
|
AzToolsFramework::ViewportUi::ButtonId buttonId;
|
|
AzToolsFramework::ViewportUi::ViewportUiRequestBus::EventResult(
|
|
buttonId, AzToolsFramework::ViewportUi::DefaultViewportId,
|
|
&AzToolsFramework::ViewportUi::ViewportUiRequestBus::Events::CreateClusterButton, clusterId,
|
|
AZStd::string::format(":/stylesheet/img/UI20/toolbar/%s.svg", iconName));
|
|
|
|
return buttonId;
|
|
}
|
|
|
|
void EditorWhiteBoxComponentMode::RemoveSubModeSelectionCluster()
|
|
{
|
|
AzToolsFramework::ViewportUi::ViewportUiRequestBus::Event(
|
|
AzToolsFramework::ViewportUi::DefaultViewportId,
|
|
&AzToolsFramework::ViewportUi::ViewportUiRequestBus::Events::RemoveCluster, m_modeSelectionClusterId);
|
|
}
|
|
|
|
void EditorWhiteBoxComponentMode::CreateSubModeSelectionCluster()
|
|
{
|
|
// create the cluster for changing transform mode
|
|
AzToolsFramework::ViewportUi::ViewportUiRequestBus::EventResult(
|
|
m_modeSelectionClusterId, AzToolsFramework::ViewportUi::DefaultViewportId,
|
|
&AzToolsFramework::ViewportUi::ViewportUiRequestBus::Events::CreateCluster, AzToolsFramework::ViewportUi::Alignment::TopLeft);
|
|
|
|
// create and register the buttons
|
|
m_defaultModeButtonId = RegisterClusterButton(m_modeSelectionClusterId, "SketchMode");
|
|
m_edgeRestoreModeButtonId = RegisterClusterButton(m_modeSelectionClusterId, "RestoreMode");
|
|
|
|
auto onButtonClicked = [this](AzToolsFramework::ViewportUi::ButtonId buttonId)
|
|
{
|
|
if (buttonId == m_defaultModeButtonId)
|
|
{
|
|
EnterDefaultMode();
|
|
}
|
|
else if (buttonId == m_edgeRestoreModeButtonId)
|
|
{
|
|
EnterEdgeRestoreMode();
|
|
}
|
|
};
|
|
|
|
m_modeSelectionHandler = AZ::Event<AzToolsFramework::ViewportUi::ButtonId>::Handler(onButtonClicked);
|
|
AzToolsFramework::ViewportUi::ViewportUiRequestBus::Event(
|
|
AzToolsFramework::ViewportUi::DefaultViewportId,
|
|
&AzToolsFramework::ViewportUi::ViewportUiRequestBus::Events::RegisterClusterEventHandler,
|
|
m_modeSelectionClusterId, m_modeSelectionHandler);
|
|
}
|
|
} // namespace WhiteBox
|