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.
932 lines
34 KiB
C++
932 lines
34 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 "UiTooltipDisplayComponent.h"
|
|
|
|
#include <AzCore/Serialization/SerializeContext.h>
|
|
#include <AzCore/Serialization/EditContext.h>
|
|
#include <AzCore/RTTI/BehaviorContext.h>
|
|
#include <AzCore/std/sort.h>
|
|
|
|
#include <LyShine/Bus/UiTransform2dBus.h>
|
|
#include <LyShine/Bus/UiElementBus.h>
|
|
#include <LyShine/Bus/UiTextBus.h>
|
|
#include <LyShine/Bus/UiCanvasBus.h>
|
|
#include <LyShine/Bus/UiTooltipDataPopulatorBus.h>
|
|
#include <LyShine/UiSerializeHelpers.h>
|
|
|
|
#include <ITimer.h>
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
// PUBLIC MEMBER FUNCTIONS
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
UiTooltipDisplayComponent::UiTooltipDisplayComponent()
|
|
: m_triggerMode(TriggerMode::OnHover)
|
|
, m_autoPosition(true)
|
|
, m_autoPositionMode(AutoPositionMode::OffsetFromMouse)
|
|
, m_offset(0.0f, -10.0f)
|
|
, m_autoSize(true)
|
|
, m_delayTime(0.5f)
|
|
, m_displayTime(5.0f)
|
|
, m_state(State::Hidden)
|
|
, m_stateStartTime(-1.0f)
|
|
, m_curDelayTime(-1.0f)
|
|
, m_timeSinceLastShown(-1.0f)
|
|
, m_maxWrapTextWidth(-1.0f)
|
|
, m_showSequence(nullptr)
|
|
, m_hideSequence(nullptr)
|
|
{
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
UiTooltipDisplayComponent::~UiTooltipDisplayComponent()
|
|
{
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
UiTooltipDisplayInterface::TriggerMode UiTooltipDisplayComponent::GetTriggerMode()
|
|
{
|
|
return m_triggerMode;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
void UiTooltipDisplayComponent::SetTriggerMode(TriggerMode triggerMode)
|
|
{
|
|
m_triggerMode = triggerMode;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
bool UiTooltipDisplayComponent::GetAutoPosition()
|
|
{
|
|
return m_autoPosition;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
void UiTooltipDisplayComponent::SetAutoPosition(bool autoPosition)
|
|
{
|
|
m_autoPosition = autoPosition;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
UiTooltipDisplayInterface::AutoPositionMode UiTooltipDisplayComponent::GetAutoPositionMode()
|
|
{
|
|
return m_autoPositionMode;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
void UiTooltipDisplayComponent::SetAutoPositionMode(AutoPositionMode autoPositionMode)
|
|
{
|
|
m_autoPositionMode = autoPositionMode;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
const AZ::Vector2& UiTooltipDisplayComponent::GetOffset()
|
|
{
|
|
return m_offset;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
void UiTooltipDisplayComponent::SetOffset(const AZ::Vector2& offset)
|
|
{
|
|
m_offset = offset;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
bool UiTooltipDisplayComponent::GetAutoSize()
|
|
{
|
|
return m_autoSize;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
void UiTooltipDisplayComponent::SetAutoSize(bool autoSize)
|
|
{
|
|
m_autoSize = autoSize;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
AZ::EntityId UiTooltipDisplayComponent::GetTextEntity()
|
|
{
|
|
return m_textEntity;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
void UiTooltipDisplayComponent::SetTextEntity(AZ::EntityId textEntity)
|
|
{
|
|
m_textEntity = textEntity;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
float UiTooltipDisplayComponent::GetDelayTime()
|
|
{
|
|
return m_delayTime;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
void UiTooltipDisplayComponent::SetDelayTime(float delayTime)
|
|
{
|
|
m_delayTime = delayTime;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
float UiTooltipDisplayComponent::GetDisplayTime()
|
|
{
|
|
return m_displayTime;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
void UiTooltipDisplayComponent::SetDisplayTime(float displayTime)
|
|
{
|
|
m_displayTime = displayTime;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
void UiTooltipDisplayComponent::PrepareToShow(AZ::EntityId tooltipElement)
|
|
{
|
|
m_tooltipElement = tooltipElement;
|
|
|
|
// We should be in the hidden state
|
|
AZ_Assert(((m_state == State::Hiding) || (m_state == State::Hidden)), "State is not hidden when attempting to show tooltip");
|
|
if (m_state != State::Hidden)
|
|
{
|
|
EndTransitionState();
|
|
SetState(State::Hidden);
|
|
}
|
|
|
|
m_curDelayTime = m_delayTime;
|
|
|
|
|
|
SetState(State::DelayBeforeShow);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
void UiTooltipDisplayComponent::Hide()
|
|
{
|
|
switch (m_state)
|
|
{
|
|
case State::Showing:
|
|
{
|
|
// Since sequences can't have keys that represent current values,
|
|
// only play the hide animation if the show animation has completed.
|
|
|
|
m_timeSinceLastShown = gEnv->pTimer->GetCurrTime(ITimer::ETIMER_UI);
|
|
|
|
EndTransitionState();
|
|
|
|
SetState(State::Hidden);
|
|
}
|
|
break;
|
|
|
|
case State::Shown:
|
|
{
|
|
m_timeSinceLastShown = gEnv->pTimer->GetCurrTime(ITimer::ETIMER_UI);
|
|
|
|
// Check if there is a hide animation to play
|
|
IUiAnimationSystem* animSystem = nullptr;
|
|
PrepareSequenceForPlay(m_hideSequenceName, m_hideSequence, animSystem);
|
|
|
|
if (m_hideSequence)
|
|
{
|
|
SetState(State::Hiding);
|
|
|
|
animSystem->PlaySequence(m_hideSequence, nullptr, false, false);
|
|
}
|
|
else
|
|
{
|
|
SetState(State::Hidden);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case State::DelayBeforeShow:
|
|
{
|
|
SetState(State::Hidden);
|
|
}
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
void UiTooltipDisplayComponent::Update()
|
|
{
|
|
if (m_state == State::DelayBeforeShow)
|
|
{
|
|
// Check if it's time to show the tooltip
|
|
if ((gEnv->pTimer->GetCurrTime(ITimer::ETIMER_UI) - m_stateStartTime) >= m_curDelayTime)
|
|
{
|
|
// Make sure nothing has changed with the hover interactable
|
|
if (m_tooltipElement.IsValid() && UiTooltipDataPopulatorBus::FindFirstHandler(m_tooltipElement))
|
|
{
|
|
Show();
|
|
}
|
|
else
|
|
{
|
|
Hide();
|
|
}
|
|
}
|
|
}
|
|
else if (m_state == State::Shown)
|
|
{
|
|
// Check if it's time to hide the tooltip
|
|
if (m_displayTime >= 0.0f)
|
|
{
|
|
if ((gEnv->pTimer->GetCurrTime(ITimer::ETIMER_UI) - m_stateStartTime) >= m_displayTime)
|
|
{
|
|
// Hide tooltip
|
|
Hide();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
void UiTooltipDisplayComponent::InGamePostActivate()
|
|
{
|
|
SetState(State::Hidden);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
void UiTooltipDisplayComponent::OnUiAnimationEvent(EUiAnimationEvent uiAnimationEvent, IUiAnimSequence* animSequence)
|
|
{
|
|
if (m_state == State::Showing && animSequence == m_showSequence)
|
|
{
|
|
if ((uiAnimationEvent == eUiAnimationEvent_Stopped) || (uiAnimationEvent == eUiAnimationEvent_Aborted))
|
|
{
|
|
SetState(State::Shown);
|
|
}
|
|
}
|
|
else if (m_state == State::Hiding && animSequence == m_hideSequence)
|
|
{
|
|
if ((uiAnimationEvent == eUiAnimationEvent_Stopped) || (uiAnimationEvent == eUiAnimationEvent_Aborted))
|
|
{
|
|
SetState(State::Hidden);
|
|
}
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
UiTooltipDisplayComponent::State UiTooltipDisplayComponent::GetState()
|
|
{
|
|
return m_state;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
// PUBLIC STATIC MEMBER FUNCTIONS
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
void UiTooltipDisplayComponent::Reflect(AZ::ReflectContext* context)
|
|
{
|
|
AZ::SerializeContext* serializeContext = azrtti_cast<AZ::SerializeContext*>(context);
|
|
|
|
if (serializeContext)
|
|
{
|
|
serializeContext->Class<UiTooltipDisplayComponent, AZ::Component>()
|
|
->Version(2, &VersionConverter)
|
|
->Field("TriggerMode", &UiTooltipDisplayComponent::m_triggerMode)
|
|
->Field("AutoPosition", &UiTooltipDisplayComponent::m_autoPosition)
|
|
->Field("AutoPositionMode", &UiTooltipDisplayComponent::m_autoPositionMode)
|
|
->Field("Offset", &UiTooltipDisplayComponent::m_offset)
|
|
->Field("AutoSize", &UiTooltipDisplayComponent::m_autoSize)
|
|
->Field("Text", &UiTooltipDisplayComponent::m_textEntity)
|
|
->Field("DelayTime", &UiTooltipDisplayComponent::m_delayTime)
|
|
->Field("DisplayTime", &UiTooltipDisplayComponent::m_displayTime)
|
|
->Field("ShowSequence", &UiTooltipDisplayComponent::m_showSequenceName)
|
|
->Field("HideSequence", &UiTooltipDisplayComponent::m_hideSequenceName);
|
|
|
|
AZ::EditContext* ec = serializeContext->GetEditContext();
|
|
if (ec)
|
|
{
|
|
auto editInfo = ec->Class<UiTooltipDisplayComponent>("TooltipDisplay", "A component that handles how the tooltip element is to be displayed.");
|
|
|
|
editInfo->ClassElement(AZ::Edit::ClassElements::EditorData, "")
|
|
->Attribute(AZ::Edit::Attributes::Category, "UI")
|
|
->Attribute(AZ::Edit::Attributes::Icon, "Editor/Icons/Components/UiTooltipDisplay.png")
|
|
->Attribute(AZ::Edit::Attributes::ViewportIcon, "Editor/Icons/Components/Viewport/UiTooltipDisplay.png")
|
|
->Attribute(AZ::Edit::Attributes::AppearsInAddComponentMenu, AZ_CRC("UI", 0x27ff46b0))
|
|
->Attribute(AZ::Edit::Attributes::AutoExpand, true);
|
|
|
|
editInfo->DataElement(AZ::Edit::UIHandlers::ComboBox, &UiTooltipDisplayComponent::m_triggerMode, "Trigger Mode",
|
|
"Sets the way the tooltip is triggered to display.")
|
|
->EnumAttribute(UiTooltipDisplayInterface::TriggerMode::OnHover, "On Hover")
|
|
->EnumAttribute(UiTooltipDisplayInterface::TriggerMode::OnPress, "On Press")
|
|
->EnumAttribute(UiTooltipDisplayInterface::TriggerMode::OnClick, "On Click");
|
|
editInfo->DataElement(0, &UiTooltipDisplayComponent::m_autoPosition, "Auto position",
|
|
"Whether the element will automatically be positioned.")
|
|
->Attribute(AZ::Edit::Attributes::ChangeNotify, AZ_CRC("RefreshEntireTree", 0xefbc823c));
|
|
editInfo->DataElement(AZ::Edit::UIHandlers::ComboBox, &UiTooltipDisplayComponent::m_autoPositionMode, "Positioning",
|
|
"Sets the positioning behavior of the element.")
|
|
->EnumAttribute(UiTooltipDisplayInterface::AutoPositionMode::OffsetFromMouse, "Offset from mouse")
|
|
->EnumAttribute(UiTooltipDisplayInterface::AutoPositionMode::OffsetFromElement, "Offset from element")
|
|
->Attribute(AZ::Edit::Attributes::Visibility, &UiTooltipDisplayComponent::m_autoPosition);
|
|
editInfo->DataElement(0, &UiTooltipDisplayComponent::m_offset, "Offset",
|
|
"The offset to use when positioning the element.")
|
|
->Attribute(AZ::Edit::Attributes::Visibility, &UiTooltipDisplayComponent::m_autoPosition);
|
|
editInfo->DataElement(0, &UiTooltipDisplayComponent::m_autoSize, "Auto size",
|
|
"Whether the element will automatically be sized so that the text element's size is the same as the size of the tooltip string.\n"
|
|
"If auto size is on, the text element's anchors should be apart.");
|
|
editInfo->DataElement(AZ::Edit::UIHandlers::ComboBox, &UiTooltipDisplayComponent::m_textEntity, "Text",
|
|
"The UI element to hold the main tooltip text. Also used for auto sizing.")
|
|
->Attribute(AZ::Edit::Attributes::EnumValues, &UiTooltipDisplayComponent::PopulateTextEntityList);
|
|
editInfo->DataElement(0, &UiTooltipDisplayComponent::m_delayTime, "Delay Time",
|
|
"The amount of time to wait before displaying the element.");
|
|
editInfo->DataElement(0, &UiTooltipDisplayComponent::m_displayTime, "Display Time",
|
|
"The amount of time the element is to be displayed.");
|
|
editInfo->DataElement(AZ::Edit::UIHandlers::ComboBox, &UiTooltipDisplayComponent::m_showSequenceName, "Show Sequence",
|
|
"The sequence to be played when the element is about to show.")
|
|
->Attribute(AZ::Edit::Attributes::StringList, &UiTooltipDisplayComponent::PopulateSequenceList);
|
|
editInfo->DataElement(AZ::Edit::UIHandlers::ComboBox, &UiTooltipDisplayComponent::m_hideSequenceName, "Hide Sequence",
|
|
"The sequence to be played when the element is about to hide.")
|
|
->Attribute(AZ::Edit::Attributes::StringList, &UiTooltipDisplayComponent::PopulateSequenceList);
|
|
}
|
|
}
|
|
|
|
AZ::BehaviorContext* behaviorContext = azrtti_cast<AZ::BehaviorContext*>(context);
|
|
if (behaviorContext)
|
|
{
|
|
behaviorContext->Enum<(int)UiTooltipDisplayInterface::AutoPositionMode::OffsetFromMouse>("eUiTooltipDisplayAutoPositionMode_OffsetFromMouse")
|
|
->Enum<(int)UiTooltipDisplayInterface::AutoPositionMode::OffsetFromElement>("eUiTooltipDisplayAutoPositionMode_OffsetFromElement");
|
|
|
|
behaviorContext->Enum<(int)UiTooltipDisplayInterface::TriggerMode::OnHover>("eUiTooltipDisplayTriggerMode_OnHover")
|
|
->Enum<(int)UiTooltipDisplayInterface::TriggerMode::OnPress>("eUiTooltipDisplayTriggerMode_OnPress")
|
|
->Enum<(int)UiTooltipDisplayInterface::TriggerMode::OnPress>("eUiTooltipDisplayTriggerMode_OnClick");
|
|
|
|
behaviorContext->EBus<UiTooltipDisplayBus>("UiTooltipDisplayBus")
|
|
->Event("GetTriggerMode", &UiTooltipDisplayBus::Events::GetTriggerMode)
|
|
->Event("SetTriggerMode", &UiTooltipDisplayBus::Events::SetTriggerMode)
|
|
->Event("GetAutoPosition", &UiTooltipDisplayBus::Events::GetAutoPosition)
|
|
->Event("SetAutoPosition", &UiTooltipDisplayBus::Events::SetAutoPosition)
|
|
->Event("GetAutoPositionMode", &UiTooltipDisplayBus::Events::GetAutoPositionMode)
|
|
->Event("SetAutoPositionMode", &UiTooltipDisplayBus::Events::SetAutoPositionMode)
|
|
->Event("GetOffset", &UiTooltipDisplayBus::Events::GetOffset)
|
|
->Event("SetOffset", &UiTooltipDisplayBus::Events::SetOffset)
|
|
->Event("GetAutoSize", &UiTooltipDisplayBus::Events::GetAutoSize)
|
|
->Event("SetAutoSize", &UiTooltipDisplayBus::Events::SetAutoSize)
|
|
->Event("GetTextEntity", &UiTooltipDisplayBus::Events::GetTextEntity)
|
|
->Event("SetTextEntity", &UiTooltipDisplayBus::Events::SetTextEntity)
|
|
->Event("GetDelayTime", &UiTooltipDisplayBus::Events::GetDelayTime)
|
|
->Event("SetDelayTime", &UiTooltipDisplayBus::Events::SetDelayTime)
|
|
->Event("GetDisplayTime", &UiTooltipDisplayBus::Events::GetDisplayTime)
|
|
->Event("SetDisplayTime", &UiTooltipDisplayBus::Events::SetDisplayTime)
|
|
->VirtualProperty("DelayTime", "GetDelayTime", "SetDelayTime")
|
|
->VirtualProperty("DisplayTime", "GetDisplayTime", "SetDisplayTime");
|
|
|
|
behaviorContext->Class<UiTooltipDisplayComponent>()->RequestBus("UiTooltipDisplayBus");
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
// PROTECTED MEMBER FUNCTIONS
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
void UiTooltipDisplayComponent::Activate()
|
|
{
|
|
UiTooltipDisplayBus::Handler::BusConnect(GetEntityId());
|
|
UiInitializationBus::Handler::BusConnect(GetEntityId());
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
void UiTooltipDisplayComponent::Deactivate()
|
|
{
|
|
UiTooltipDisplayBus::Handler::BusDisconnect(GetEntityId());
|
|
UiInitializationBus::Handler::BusDisconnect(GetEntityId());
|
|
|
|
// Stop listening for animation actions. The sequences may have been deleted at this point,
|
|
// so first check if they still exist.
|
|
IUiAnimationSystem* animSystem = nullptr;
|
|
IUiAnimSequence* sequence;
|
|
|
|
if (m_listeningForAnimationEvents)
|
|
{
|
|
m_listeningForAnimationEvents = false;
|
|
sequence = GetSequence(m_showSequenceName, animSystem);
|
|
if (sequence)
|
|
{
|
|
animSystem->RemoveUiAnimationListener(sequence, this);
|
|
}
|
|
|
|
sequence = GetSequence(m_hideSequenceName, animSystem);
|
|
if (sequence)
|
|
{
|
|
animSystem->RemoveUiAnimationListener(sequence, this);
|
|
}
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
void UiTooltipDisplayComponent::SetState(State state)
|
|
{
|
|
m_state = state;
|
|
m_stateStartTime = gEnv->pTimer->GetCurrTime(ITimer::ETIMER_UI);
|
|
|
|
switch (m_state)
|
|
{
|
|
case State::Hiding:
|
|
UiTooltipDisplayNotificationBus::Event(m_tooltipElement, &UiTooltipDisplayNotificationBus::Events::OnHiding);
|
|
break;
|
|
|
|
case State::Hidden:
|
|
UiTooltipDisplayNotificationBus::Event(m_tooltipElement, &UiTooltipDisplayNotificationBus::Events::OnHidden);
|
|
UiElementBus::Event(GetEntityId(), &UiElementBus::Events::SetIsEnabled, false);
|
|
break;
|
|
|
|
case State::Showing:
|
|
case State::Shown:
|
|
UiElementBus::Event(GetEntityId(), &UiElementBus::Events::SetIsEnabled, true);
|
|
if (m_state == State::Showing)
|
|
{
|
|
UiTooltipDisplayNotificationBus::Event(m_tooltipElement, &UiTooltipDisplayNotificationBus::Events::OnShowing);
|
|
}
|
|
else
|
|
{
|
|
UiTooltipDisplayNotificationBus::Event(m_tooltipElement, &UiTooltipDisplayNotificationBus::Events::OnShown);
|
|
}
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
void UiTooltipDisplayComponent::EndTransitionState()
|
|
{
|
|
if (m_state == State::Showing)
|
|
{
|
|
if (m_showSequence)
|
|
{
|
|
IUiAnimationSystem* animSystem = GetAnimationSystem();
|
|
if (animSystem)
|
|
{
|
|
animSystem->StopSequence(m_showSequence);
|
|
}
|
|
}
|
|
|
|
SetState(State::Shown);
|
|
}
|
|
else if (m_state == State::Hiding)
|
|
{
|
|
if (m_hideSequence)
|
|
{
|
|
IUiAnimationSystem* animSystem = GetAnimationSystem();
|
|
if (animSystem)
|
|
{
|
|
animSystem->StopSequence(m_hideSequence);
|
|
}
|
|
}
|
|
|
|
SetState(State::Hidden);
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
void UiTooltipDisplayComponent::Show()
|
|
{
|
|
// It is assumed that current state is DelayBeforeShow
|
|
|
|
if (m_autoSize && m_textEntity.IsValid())
|
|
{
|
|
// Initialize max wrap text width
|
|
if (m_maxWrapTextWidth < 0.0f)
|
|
{
|
|
UiTransformInterface::Rect textRect;
|
|
EBUS_EVENT_ID(m_textEntity, UiTransformBus, GetCanvasSpaceRectNoScaleRotate, textRect);
|
|
|
|
m_maxWrapTextWidth = textRect.GetWidth();
|
|
}
|
|
|
|
// If wrapping is on, reset display element to its original width
|
|
UiTextInterface::WrapTextSetting wrapSetting = UiTextInterface::WrapTextSetting::NoWrap;
|
|
EBUS_EVENT_ID_RESULT(wrapSetting, m_textEntity, UiTextBus, GetWrapText);
|
|
if (wrapSetting != UiTextInterface::WrapTextSetting::NoWrap)
|
|
{
|
|
UiTransformInterface::Rect textRect;
|
|
EBUS_EVENT_ID(m_textEntity, UiTransformBus, GetCanvasSpaceRectNoScaleRotate, textRect);
|
|
|
|
AZ::Vector2 delta(m_maxWrapTextWidth - textRect.GetWidth(), 0.0f);
|
|
|
|
ResizeElementByDelta(GetEntityId(), delta);
|
|
}
|
|
}
|
|
|
|
// Assign tooltip data to the tooltip display element
|
|
EBUS_EVENT_ID(m_tooltipElement, UiTooltipDataPopulatorBus, PushDataToDisplayElement, GetEntityId());
|
|
|
|
// Auto-resize display element so that the text element is the same size as the size of its text string
|
|
if (m_autoSize && m_textEntity.IsValid())
|
|
{
|
|
AutoResize();
|
|
}
|
|
|
|
// Auto-position display element
|
|
if (m_autoPosition)
|
|
{
|
|
AutoPosition();
|
|
}
|
|
|
|
// Check if there is a show animation to play
|
|
IUiAnimationSystem* animSystem = nullptr;
|
|
PrepareSequenceForPlay(m_showSequenceName, m_showSequence, animSystem);
|
|
|
|
if (m_showSequence)
|
|
{
|
|
SetState(State::Showing);
|
|
|
|
animSystem->PlaySequence(m_showSequence, nullptr, false, false);
|
|
}
|
|
else
|
|
{
|
|
SetState(State::Shown);
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
void UiTooltipDisplayComponent::AutoResize()
|
|
{
|
|
// Get the text string size
|
|
AZ::Vector2 stringSize(-1.0f, -1.0f);
|
|
EBUS_EVENT_ID_RESULT(stringSize, m_textEntity, UiTextBus, GetTextSize);
|
|
|
|
if (stringSize.GetX() < 0.0f || stringSize.GetY() < 0.0f)
|
|
{
|
|
return;
|
|
}
|
|
|
|
// Get the text element's rect
|
|
UiTransformInterface::Rect textRect;
|
|
EBUS_EVENT_ID(m_textEntity, UiTransformBus, GetCanvasSpaceRectNoScaleRotate, textRect);
|
|
|
|
// Get the difference between the text element's size and the string size
|
|
AZ::Vector2 delta(stringSize.GetX() - textRect.GetWidth(), stringSize.GetY() - textRect.GetHeight());
|
|
|
|
UiTextInterface::WrapTextSetting wrapSetting;
|
|
EBUS_EVENT_ID_RESULT(wrapSetting, m_textEntity, UiTextBus, GetWrapText);
|
|
if (wrapSetting != UiTextInterface::WrapTextSetting::NoWrap)
|
|
{
|
|
// In order for the wrapping to remain the same after the resize, the
|
|
// text element width would need to match the string width exactly. To accommodate
|
|
// for slight variation in size, add a small value to ensure that the string will fit
|
|
// inside the text element's bounds. The downside to this is there may be extra space
|
|
// at the bottom, but this is unlikely.
|
|
const float epsilon = 0.01f;
|
|
delta.SetX(delta.GetX() + epsilon);
|
|
}
|
|
|
|
// Resize the display element by the difference
|
|
ResizeElementByDelta(GetEntityId(), delta);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
void UiTooltipDisplayComponent::ResizeElementByDelta(AZ::EntityId entityId, const AZ::Vector2& delta)
|
|
{
|
|
if ((delta.GetX() != 0.0f) || (delta.GetY() != 0.0f))
|
|
{
|
|
// Resize the element based on the difference
|
|
UiTransform2dInterface::Offsets offsets;
|
|
EBUS_EVENT_ID_RESULT(offsets, entityId, UiTransform2dBus, GetOffsets);
|
|
|
|
AZ::Vector2 pivot;
|
|
|
|
EBUS_EVENT_ID_RESULT(pivot, entityId, UiTransformBus, GetPivot);
|
|
|
|
if (delta.GetX() != 0.0f)
|
|
{
|
|
float leftOffsetDelta = delta.GetX() * pivot.GetX();
|
|
offsets.m_left -= leftOffsetDelta;
|
|
offsets.m_right += delta.GetX() - leftOffsetDelta;
|
|
}
|
|
if (delta.GetY() != 0.0f)
|
|
{
|
|
float topOffsetDelta = delta.GetY() * pivot.GetY();
|
|
offsets.m_top -= topOffsetDelta;
|
|
offsets.m_bottom += delta.GetY() - topOffsetDelta;
|
|
}
|
|
|
|
EBUS_EVENT_ID(entityId, UiTransform2dBus, SetOffsets, offsets);
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
void UiTooltipDisplayComponent::AutoPosition()
|
|
{
|
|
bool havePosition = false;
|
|
AZ::Vector2 position(-1.0f, -1.0f);
|
|
if (m_autoPositionMode == UiTooltipDisplayInterface::AutoPositionMode::OffsetFromMouse)
|
|
{
|
|
// Get current mouse position
|
|
AZ::EntityId canvasId;
|
|
EBUS_EVENT_ID_RESULT(canvasId, GetEntityId(), UiElementBus, GetCanvasEntityId);
|
|
|
|
EBUS_EVENT_ID_RESULT(position, canvasId, UiCanvasBus, GetMousePosition);
|
|
|
|
if (position.GetX() >= 0.0f && position.GetY() >= 0.0f)
|
|
{
|
|
// Check if the mouse is hovering over the tooltip element
|
|
EBUS_EVENT_ID_RESULT(havePosition, m_tooltipElement, UiTransformBus, IsPointInRect, position);
|
|
}
|
|
}
|
|
|
|
if (!havePosition)
|
|
{
|
|
// Get the pivot position of the tooltip element
|
|
EBUS_EVENT_ID_RESULT(position, m_tooltipElement, UiTransformBus, GetViewportSpacePivot);
|
|
}
|
|
|
|
MoveToPosition(position, m_offset);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
void UiTooltipDisplayComponent::MoveToPosition(const AZ::Vector2& point, const AZ::Vector2& offsetFromPoint)
|
|
{
|
|
// Move the display element so that its pivot is a certain distance from the point
|
|
|
|
UiTransform2dInterface::Offsets offsets;
|
|
EBUS_EVENT_ID_RESULT(offsets, GetEntityId(), UiTransform2dBus, GetOffsets);
|
|
|
|
AZ::Vector2 pivot;
|
|
EBUS_EVENT_ID_RESULT(pivot, GetEntityId(), UiTransformBus, GetViewportSpacePivot);
|
|
|
|
AZ::Vector2 moveDist = (point + offsetFromPoint) - pivot;
|
|
offsets += moveDist;
|
|
|
|
EBUS_EVENT_ID(GetEntityId(), UiTransform2dBus, SetOffsets, offsets);
|
|
|
|
// Make sure that the display element stays within the bounds of its parent
|
|
|
|
// Get parent rect
|
|
UiTransformInterface::Rect parentRect;
|
|
|
|
AZ::Entity* parentEntity = nullptr;
|
|
EBUS_EVENT_ID_RESULT(parentEntity, GetEntityId(), UiElementBus, GetParent);
|
|
|
|
if (parentEntity)
|
|
{
|
|
EBUS_EVENT_ID(parentEntity->GetId(), UiTransformBus, GetCanvasSpaceRectNoScaleRotate, parentRect);
|
|
}
|
|
else
|
|
{
|
|
AZ::EntityId canvasEntityId;
|
|
EBUS_EVENT_ID_RESULT(canvasEntityId, GetEntityId(), UiElementBus, GetCanvasEntityId);
|
|
|
|
AZ::Vector2 size;
|
|
EBUS_EVENT_ID_RESULT(size, canvasEntityId, UiCanvasBus, GetCanvasSize);
|
|
|
|
parentRect.Set(0.0f, size.GetX(), 0.0f, size.GetY());
|
|
}
|
|
|
|
// If the display element exceeds the top/bottom bounds of its parent, the offset
|
|
// is flipped and applied to the top/bottom of the display element.
|
|
// If positioning is to be relative to the tooltip element though, this step is skipped
|
|
// to preserve the original position as much as possible.
|
|
if (m_autoPositionMode != UiTooltipDisplayInterface::AutoPositionMode::OffsetFromElement)
|
|
{
|
|
CheckBoundsAndChangeYPosition(parentRect, point.GetY(), fabs(m_offset.GetY()));
|
|
}
|
|
|
|
ConstrainToBounds(parentRect);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
void UiTooltipDisplayComponent::CheckBoundsAndChangeYPosition(const UiTransformInterface::Rect& boundsRect, float yPoint, float yOffsetFromPoint)
|
|
{
|
|
// Get display element rect
|
|
UiTransformInterface::Rect rect = GetAxisAlignedRect();
|
|
|
|
float yMoveDist = 0.0f;
|
|
|
|
// Check upper and lower bounds
|
|
if (rect.top < boundsRect.top)
|
|
{
|
|
// Move top of display element to an offset below the point
|
|
yMoveDist = (yPoint + yOffsetFromPoint) - rect.top;
|
|
}
|
|
else if (rect.bottom > boundsRect.bottom)
|
|
{
|
|
// Move bottom of display element to an offset above the point
|
|
yMoveDist = (yPoint - yOffsetFromPoint) - rect.bottom;
|
|
}
|
|
|
|
if (yMoveDist != 0.0f)
|
|
{
|
|
UiTransform2dInterface::Offsets offsets;
|
|
EBUS_EVENT_ID_RESULT(offsets, GetEntityId(), UiTransform2dBus, GetOffsets);
|
|
|
|
offsets.m_top += yMoveDist;
|
|
offsets.m_bottom += yMoveDist;
|
|
|
|
EBUS_EVENT_ID(GetEntityId(), UiTransform2dBus, SetOffsets, offsets);
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
void UiTooltipDisplayComponent::ConstrainToBounds(const UiTransformInterface::Rect& boundsRect)
|
|
{
|
|
// Get display element rect
|
|
UiTransformInterface::Rect rect = GetAxisAlignedRect();
|
|
|
|
AZ::Vector2 moveDist(0.0f, 0.0f);
|
|
|
|
// Check left and right bounds
|
|
if (rect.left < boundsRect.left)
|
|
{
|
|
moveDist.SetX(boundsRect.left - rect.left);
|
|
}
|
|
else if (rect.right > boundsRect.right)
|
|
{
|
|
moveDist.SetX(boundsRect.right - rect.right);
|
|
}
|
|
|
|
// Check upper and lower bounds
|
|
if (rect.top < boundsRect.top)
|
|
{
|
|
moveDist.SetY(boundsRect.top - rect.top);
|
|
}
|
|
else if (rect.bottom > boundsRect.bottom)
|
|
{
|
|
moveDist.SetY(boundsRect.bottom - rect.bottom);
|
|
}
|
|
|
|
if (moveDist.GetX() != 0.0f || moveDist.GetY() != 0.0f)
|
|
{
|
|
UiTransform2dInterface::Offsets offsets;
|
|
EBUS_EVENT_ID_RESULT(offsets, GetEntityId(), UiTransform2dBus, GetOffsets);
|
|
|
|
offsets += moveDist;
|
|
|
|
EBUS_EVENT_ID(GetEntityId(), UiTransform2dBus, SetOffsets, offsets);
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
UiTransformInterface::Rect UiTooltipDisplayComponent::GetAxisAlignedRect()
|
|
{
|
|
UiTransformInterface::RectPoints points;
|
|
EBUS_EVENT_ID(GetEntityId(), UiTransformBus, GetCanvasSpacePointsNoScaleRotate, points);
|
|
|
|
AZ::Matrix4x4 transform;
|
|
EBUS_EVENT_ID(GetEntityId(), UiTransformBus, GetLocalTransform, transform);
|
|
|
|
points = points.Transform(transform);
|
|
|
|
UiTransformInterface::Rect rect;
|
|
rect.left = points.GetAxisAlignedTopLeft().GetX();
|
|
rect.right = points.GetAxisAlignedBottomRight().GetX();
|
|
rect.top = points.GetAxisAlignedTopLeft().GetY();
|
|
rect.bottom = points.GetAxisAlignedBottomRight().GetY();
|
|
|
|
return rect;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
IUiAnimationSystem* UiTooltipDisplayComponent::GetAnimationSystem()
|
|
{
|
|
AZ::EntityId canvasId;
|
|
EBUS_EVENT_ID_RESULT(canvasId, GetEntityId(), UiElementBus, GetCanvasEntityId);
|
|
|
|
IUiAnimationSystem* animSystem = nullptr;
|
|
EBUS_EVENT_ID_RESULT(animSystem, canvasId, UiCanvasBus, GetAnimationSystem);
|
|
|
|
return animSystem;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
IUiAnimSequence* UiTooltipDisplayComponent::GetSequence(const AZStd::string& sequenceName, IUiAnimationSystem*& animSystemOut)
|
|
{
|
|
IUiAnimSequence* sequence = nullptr;
|
|
|
|
if (!sequenceName.empty() && (sequenceName != "<None>"))
|
|
{
|
|
IUiAnimationSystem* animSystem = GetAnimationSystem();
|
|
if (animSystem)
|
|
{
|
|
sequence = animSystem->FindSequence(sequenceName.c_str());
|
|
|
|
animSystemOut = animSystem;
|
|
}
|
|
}
|
|
|
|
return sequence;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
void UiTooltipDisplayComponent::PrepareSequenceForPlay(const AZStd::string& sequenceName, IUiAnimSequence*& sequence, IUiAnimationSystem*& animSystemOut)
|
|
{
|
|
IUiAnimationSystem* animSystem = nullptr;
|
|
|
|
if (!sequence)
|
|
{
|
|
sequence = GetSequence(sequenceName, animSystem);
|
|
|
|
if (sequence)
|
|
{
|
|
m_listeningForAnimationEvents = true;
|
|
animSystem->AddUiAnimationListener(sequence, this);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
animSystem = GetAnimationSystem();
|
|
if (!animSystem)
|
|
{
|
|
sequence = nullptr;
|
|
}
|
|
}
|
|
|
|
if (sequence)
|
|
{
|
|
animSystemOut = animSystem;
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
UiTooltipDisplayComponent::EntityComboBoxVec UiTooltipDisplayComponent::PopulateTextEntityList()
|
|
{
|
|
EntityComboBoxVec result;
|
|
|
|
// add a first entry for "None"
|
|
result.push_back(AZStd::make_pair(AZ::EntityId(AZ::EntityId()), "<None>"));
|
|
|
|
// allow the destination to be the same entity as the source by
|
|
// adding this entity (if it has a text component)
|
|
if (UiTextBus::FindFirstHandler(GetEntityId()))
|
|
{
|
|
result.push_back(AZStd::make_pair(AZ::EntityId(GetEntityId()), GetEntity()->GetName()));
|
|
}
|
|
|
|
// Get a list of all descendant elements that support the UiTextBus
|
|
LyShine::EntityArray matchingElements;
|
|
EBUS_EVENT_ID(GetEntityId(), UiElementBus, FindDescendantElements,
|
|
[](const AZ::Entity* entity) { return UiTextBus::FindFirstHandler(entity->GetId()) != nullptr; },
|
|
matchingElements);
|
|
|
|
// add their names to the StringList and their IDs to the id list
|
|
for (auto childEntity : matchingElements)
|
|
{
|
|
result.push_back(AZStd::make_pair(AZ::EntityId(childEntity->GetId()), childEntity->GetName()));
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
UiTooltipDisplayComponent::SequenceComboBoxVec UiTooltipDisplayComponent::PopulateSequenceList()
|
|
{
|
|
SequenceComboBoxVec result;
|
|
|
|
// add a first entry for "None"
|
|
result.push_back("<None>");
|
|
|
|
IUiAnimationSystem* animSystem = GetAnimationSystem();
|
|
if (animSystem)
|
|
{
|
|
for (int i = 0; i < animSystem->GetNumSequences(); i++)
|
|
{
|
|
IUiAnimSequence* sequence = animSystem->GetSequence(i);
|
|
if (sequence)
|
|
{
|
|
result.push_back(sequence->GetName());
|
|
}
|
|
}
|
|
}
|
|
|
|
// Sort the sequence names
|
|
SequenceComboBoxVec::iterator iterBegin = result.begin();
|
|
++iterBegin;
|
|
if (iterBegin < result.end())
|
|
{
|
|
AZStd::sort(iterBegin, result.end(),
|
|
[](const AZStd::string s1, const AZStd::string s2) { return s1 < s2; });
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
// PRIVATE STATIC MEMBER FUNCTIONS
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
bool UiTooltipDisplayComponent::VersionConverter(AZ::SerializeContext& context,
|
|
AZ::SerializeContext::DataElementNode& classElement)
|
|
{
|
|
// conversion from version 1:
|
|
// - Need to convert Vec2 to AZ::Vector2
|
|
if (classElement.GetVersion() <= 1)
|
|
{
|
|
if (!LyShine::ConvertSubElementFromVec2ToVector2(context, classElement, "Offset"))
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|