/* * 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 "LyShine_precompiled.h" #include "UiSliderComponent.h" #include "Sprite.h" #include #include #include #include #include #include #include #include #include #include #include #include "UiSerialize.h" #include "UiNavigationHelpers.h" //////////////////////////////////////////////////////////////////////////////////////////////////// //! UiSliderNotificationBus Behavior context handler class class UiSliderNotificationBusBehaviorHandler : public UiSliderNotificationBus::Handler , public AZ::BehaviorEBusHandler { public: AZ_EBUS_BEHAVIOR_BINDER(UiSliderNotificationBusBehaviorHandler, "{13540E5E-5987-4BD9-AC7A-F771F8AD0206}", AZ::SystemAllocator, OnSliderValueChanging, OnSliderValueChanged); void OnSliderValueChanging(float value) override { Call(FN_OnSliderValueChanging, value); } void OnSliderValueChanged(float value) override { Call(FN_OnSliderValueChanged, value); } }; //////////////////////////////////////////////////////////////////////////////////////////////////// // PUBLIC MEMBER FUNCTIONS //////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////// UiSliderComponent::UiSliderComponent() : m_value(0.0f) , m_minValue(0.0f) , m_maxValue(100.0f) , m_stepValue(0.0f) , m_isDragging(false) , m_isActive(false) , m_onValueChanged() , m_onValueChanging() , m_valueChangedActionName() , m_valueChangingActionName() , m_trackEntity() , m_fillEntity() , m_manipulatorEntity() { } //////////////////////////////////////////////////////////////////////////////////////////////////// UiSliderComponent::~UiSliderComponent() { } //////////////////////////////////////////////////////////////////////////////////////////////////// float UiSliderComponent::GetValue() { return m_value; } //////////////////////////////////////////////////////////////////////////////////////////////////// void UiSliderComponent::SetValue(float value) { if (m_minValue < m_maxValue) { m_value = AZ::GetClamp(value, m_minValue, m_maxValue); } else // ( m_minValue >= m_maxValue ) { m_value = AZ::GetClamp(value, m_maxValue, m_minValue); } if (m_stepValue) { m_value += (m_stepValue / 2.0f); ///< Add half the step size to the value before the fmodf so that we round to nearest step rather than flooring to previous step m_value = m_value - fmodf(m_value, m_stepValue); } float valueRange = fabsf(m_maxValue - m_minValue); float unitValue = valueRange > 0.0f ? (fabsf(m_value - m_minValue) / valueRange) : 0.0f; if (m_fillEntity.IsValid()) { // Offsets. { UiTransform2dInterface::Offsets offsets; EBUS_EVENT_ID_RESULT(offsets, m_fillEntity, UiTransform2dBus, GetOffsets); offsets.m_left = offsets.m_right = 0.0f; EBUS_EVENT_ID(m_fillEntity, UiTransform2dBus, SetOffsets, offsets); } // Anchors. { UiTransform2dInterface::Anchors anchors; EBUS_EVENT_ID_RESULT(anchors, m_fillEntity, UiTransform2dBus, GetAnchors); anchors.m_left = 0.0f; anchors.m_right = unitValue; EBUS_EVENT_ID(m_fillEntity, UiTransform2dBus, SetAnchors, anchors, false, true); } } if (m_manipulatorEntity.IsValid()) { // Anchors. { UiTransform2dInterface::Anchors anchors; EBUS_EVENT_ID_RESULT(anchors, m_manipulatorEntity, UiTransform2dBus, GetAnchors); anchors.m_left = anchors.m_right = unitValue; EBUS_EVENT_ID(m_manipulatorEntity, UiTransform2dBus, SetAnchors, anchors, false, true); } } } //////////////////////////////////////////////////////////////////////////////////////////////////// float UiSliderComponent::GetMinValue() { return m_minValue; } //////////////////////////////////////////////////////////////////////////////////////////////////// void UiSliderComponent::SetMinValue(float value) { m_minValue = value; } //////////////////////////////////////////////////////////////////////////////////////////////////// float UiSliderComponent::GetMaxValue() { return m_maxValue; } //////////////////////////////////////////////////////////////////////////////////////////////////// void UiSliderComponent::SetMaxValue(float value) { m_maxValue = value; } //////////////////////////////////////////////////////////////////////////////////////////////////// float UiSliderComponent::GetStepValue() { return m_stepValue; } //////////////////////////////////////////////////////////////////////////////////////////////////// void UiSliderComponent::SetStepValue(float step) { m_stepValue = step; } //////////////////////////////////////////////////////////////////////////////////////////////////// UiSliderComponent::ValueChangeCallback UiSliderComponent::GetValueChangingCallback() { return m_onValueChanging; } //////////////////////////////////////////////////////////////////////////////////////////////////// void UiSliderComponent::SetValueChangingCallback(ValueChangeCallback onChange) { m_onValueChanging = onChange; } //////////////////////////////////////////////////////////////////////////////////////////////////// const LyShine::ActionName& UiSliderComponent::GetValueChangingActionName() { return m_valueChangingActionName; } //////////////////////////////////////////////////////////////////////////////////////////////////// void UiSliderComponent::SetValueChangingActionName(const LyShine::ActionName& actionName) { m_valueChangingActionName = actionName; } //////////////////////////////////////////////////////////////////////////////////////////////////// UiSliderComponent::ValueChangeCallback UiSliderComponent::GetValueChangedCallback() { return m_onValueChanged; } //////////////////////////////////////////////////////////////////////////////////////////////////// void UiSliderComponent::SetValueChangedCallback(ValueChangeCallback onChange) { m_onValueChanged = onChange; } //////////////////////////////////////////////////////////////////////////////////////////////////// const LyShine::ActionName& UiSliderComponent::GetValueChangedActionName() { return m_valueChangedActionName; } //////////////////////////////////////////////////////////////////////////////////////////////////// void UiSliderComponent::SetValueChangedActionName(const LyShine::ActionName& actionName) { m_valueChangedActionName = actionName; } //////////////////////////////////////////////////////////////////////////////////////////////////// void UiSliderComponent::SetTrackEntity(AZ::EntityId entityId) { m_trackEntity = entityId; } //////////////////////////////////////////////////////////////////////////////////////////////////// AZ::EntityId UiSliderComponent::GetTrackEntity() { return m_trackEntity; } //////////////////////////////////////////////////////////////////////////////////////////////////// void UiSliderComponent::SetFillEntity(AZ::EntityId entityId) { m_fillEntity = entityId; } //////////////////////////////////////////////////////////////////////////////////////////////////// AZ::EntityId UiSliderComponent::GetFillEntity() { return m_fillEntity; } //////////////////////////////////////////////////////////////////////////////////////////////////// void UiSliderComponent::SetManipulatorEntity(AZ::EntityId entityId) { m_manipulatorEntity = entityId; } //////////////////////////////////////////////////////////////////////////////////////////////////// AZ::EntityId UiSliderComponent::GetManipulatorEntity() { return m_manipulatorEntity; } //////////////////////////////////////////////////////////////////////////////////////////////////// void UiSliderComponent::InGamePostActivate() { SetValue(m_value); } //////////////////////////////////////////////////////////////////////////////////////////////////// bool UiSliderComponent::HandlePressed(AZ::Vector2 point, bool& shouldStayActive) { bool handled = UiInteractableComponent::HandlePressed(point, shouldStayActive); if (handled) { m_isDragging = false; } return handled; } //////////////////////////////////////////////////////////////////////////////////////////////////// bool UiSliderComponent::HandleReleased(AZ::Vector2 point) { if (m_isPressed && m_isHandlingEvents) { float value = GetValueFromPoint(point); SetValue(value); UiInteractableComponent::TriggerReleasedAction(); DoChangedActions(); } m_isPressed = false; m_isDragging = false; m_pressedPoint = AZ::Vector2(0.0f, 0.0f); return m_isHandlingEvents; } ///////////////////////////////////////////////////////////////// bool UiSliderComponent::HandleEnterPressed(bool& shouldStayActive) { bool handled = UiInteractableComponent::HandleEnterPressed(shouldStayActive); if (handled) { // the slider will stay active after released shouldStayActive = true; m_isActive = true; } return handled; } ///////////////////////////////////////////////////////////////// bool UiSliderComponent::HandleAutoActivation() { if (!m_isHandlingEvents) { return false; } m_isActive = true; return true; } ///////////////////////////////////////////////////////////////// bool UiSliderComponent::HandleKeyInputBegan(const AzFramework::InputChannel::Snapshot& inputSnapshot, AzFramework::ModifierKeyMask activeModifierKeys) { if (!m_isHandlingEvents) { return false; } // don't accept key input while in pressed state if (m_isPressed) { return false; } bool result = false; const UiNavigationHelpers::Command command = UiNavigationHelpers::MapInputChannelIdToUiNavigationCommand(inputSnapshot.m_channelId, activeModifierKeys); if (command == UiNavigationHelpers::Command::Up || command == UiNavigationHelpers::Command::Down || command == UiNavigationHelpers::Command::Left || command == UiNavigationHelpers::Command::Right) { const float keySteps = 10.0f; float delta = (m_stepValue != 0.0f) ? m_stepValue : (m_maxValue - m_minValue) / keySteps; UiTransformInterface::RectPoints points; EBUS_EVENT_ID(GetEntityId(), UiTransformBus, GetViewportSpacePoints, points); AZ::Vector2 dir = points.TopRight() - points.TopLeft(); bool isHorizontal = fabs(dir.GetX()) >= fabs(dir.GetY()); bool isVertical = fabs(dir.GetX()) <= fabs(dir.GetY()); float newValue = m_value; if (isHorizontal && (command == UiNavigationHelpers::Command::Left || command == UiNavigationHelpers::Command::Right)) { newValue += (command == UiNavigationHelpers::Command::Left ? -delta : delta); result = true; } else if (isVertical && (command == UiNavigationHelpers::Command::Up || command == UiNavigationHelpers::Command::Down)) { newValue += (command == UiNavigationHelpers::Command::Down ? -delta : delta); result = true; } if (m_minValue < m_maxValue) { newValue = AZ::GetClamp(newValue, m_minValue, m_maxValue); } else // ( m_minValue >= m_maxValue ) { newValue = AZ::GetClamp(newValue, m_maxValue, m_minValue); } if (newValue != m_value) { SetValue(newValue); AZ::Vector2 point(-1.0f, 1.0f); DoChangingActions(); DoChangedActions(); } } return result; } ///////////////////////////////////////////////////////////////// void UiSliderComponent::InputPositionUpdate(AZ::Vector2 point) { if (m_isPressed && m_trackEntity.IsValid()) { // if we are not yet in the dragging state do some tests to see if we should be if (!m_isDragging) { bool handOffDone = false; bool dragDetected = CheckForDragOrHandOffToParent(GetEntityId(), m_pressedPoint, point, 0.0f, handOffDone); if (dragDetected) { if (handOffDone) { // the drag was handed off to a parent, this slider is no longer active m_isPressed = false; } else { // the drag was valid for this slider, we are now dragging m_isDragging = true; } } } // if we are now in the dragging state do the drag of the slider if (m_isDragging) { float value = GetValueFromPoint(point); SetValue(value); DoChangingActions(); } } } ///////////////////////////////////////////////////////////////// bool UiSliderComponent::DoesSupportDragHandOff(AZ::Vector2 startPoint) { // this component does support hand-off, so long as the start point is in its bounds bool isPointInRect = false; EBUS_EVENT_ID_RESULT(isPointInRect, GetEntityId(), UiTransformBus, IsPointInRect, startPoint); return isPointInRect; } ///////////////////////////////////////////////////////////////// bool UiSliderComponent::OfferDragHandOff(AZ::EntityId currentActiveInteractable, AZ::Vector2 startPoint, AZ::Vector2 currentPoint, float dragThreshold) { bool result = false; bool handedOffToParent = false; bool dragDetected = CheckForDragOrHandOffToParent(currentActiveInteractable, startPoint, currentPoint, dragThreshold, handedOffToParent); if (dragDetected) { if (!handedOffToParent) { // a drag was detected and it was not handed off to a parent, so this slider is now taking the handoff m_isPressed = true; m_pressedPoint = startPoint; m_isDragging = true; // tell the canvas that this is now the active interactable EBUS_EVENT_ID(currentActiveInteractable, UiInteractableActiveNotificationBus, ActiveChanged, GetEntityId(), false); } } return dragDetected; } //////////////////////////////////////////////////////////////////////////////////////////////////// void UiSliderComponent::LostActiveStatus() { UiInteractableComponent::LostActiveStatus(); if (m_isDragging) { if (m_isHandlingEvents) { DoChangedActions(); } m_isDragging = false; } m_isActive = false; } //////////////////////////////////////////////////////////////////////////////////////////////////// // PROTECTED MEMBER FUNCTIONS //////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////// void UiSliderComponent::Activate() { UiInteractableComponent::Activate(); UiSliderBus::Handler::BusConnect(GetEntityId()); UiInitializationBus::Handler::BusConnect(GetEntityId()); } //////////////////////////////////////////////////////////////////////////////////////////////////// void UiSliderComponent::Deactivate() { UiInteractableComponent::Deactivate(); UiSliderBus::Handler::BusDisconnect(GetEntityId()); UiInitializationBus::Handler::BusDisconnect(GetEntityId()); } //////////////////////////////////////////////////////////////////////////////////////////////////// bool UiSliderComponent::IsAutoActivationSupported() { return true; } //////////////////////////////////////////////////////////////////////////////////////////////////// UiInteractableStatesInterface::State UiSliderComponent::ComputeInteractableState() { UiInteractableStatesInterface::State state = UiInteractableStatesInterface::StateNormal; if (!m_isHandlingEvents) { state = UiInteractableStatesInterface::StateDisabled; } else if (m_isPressed || m_isActive) { // Use pressed state regardless of mouse position state = UiInteractableStatesInterface::StatePressed; } else if (m_isHover) { state = UiInteractableStatesInterface::StateHover; } return state; } //////////////////////////////////////////////////////////////////////////////////////////////////// // PROTECTED STATIC MEMBER FUNCTIONS //////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////// void UiSliderComponent::Reflect(AZ::ReflectContext* context) { AZ::SerializeContext* serializeContext = azrtti_cast(context); if (serializeContext) { serializeContext->Class() ->Version(3, &VersionConverter) // Elements group ->Field("TrackEntity", &UiSliderComponent::m_trackEntity) ->Field("FillEntity", &UiSliderComponent::m_fillEntity) ->Field("ManipulatorEntity", &UiSliderComponent::m_manipulatorEntity) // Value group ->Field("Value", &UiSliderComponent::m_value) ->Field("MinValue", &UiSliderComponent::m_minValue) ->Field("MaxValue", &UiSliderComponent::m_maxValue) ->Field("StepValue", &UiSliderComponent::m_stepValue) // Actions group ->Field("ValueChangingActionName", &UiSliderComponent::m_valueChangingActionName) ->Field("ValueChangedActionName", &UiSliderComponent::m_valueChangedActionName); AZ::EditContext* ec = serializeContext->GetEditContext(); if (ec) { auto editInfo = ec->Class("Slider", "An interactable component for modifying a floating point value with a slider."); editInfo->ClassElement(AZ::Edit::ClassElements::EditorData, "") ->Attribute(AZ::Edit::Attributes::Category, "UI") ->Attribute(AZ::Edit::Attributes::Icon, "Editor/Icons/Components/UiSlider.png") ->Attribute(AZ::Edit::Attributes::ViewportIcon, "Editor/Icons/Components/Viewport/UiSlider.png") ->Attribute(AZ::Edit::Attributes::AppearsInAddComponentMenu, AZ_CRC("UI", 0x27ff46b0)) ->Attribute(AZ::Edit::Attributes::AutoExpand, true); // Elements group { editInfo->ClassElement(AZ::Edit::ClassElements::Group, "Elements") ->Attribute(AZ::Edit::Attributes::AutoExpand, true); editInfo->DataElement(AZ::Edit::UIHandlers::ComboBox, &UiSliderComponent::m_trackEntity, "Track", "The child element used to define the range of movement.") ->Attribute(AZ::Edit::Attributes::EnumValues, &UiSliderComponent::PopulateChildEntityList); editInfo->DataElement(AZ::Edit::UIHandlers::ComboBox, &UiSliderComponent::m_fillEntity, "Fill", "The child element used to show the filled part of the range.") ->Attribute(AZ::Edit::Attributes::EnumValues, &UiSliderComponent::PopulateChildEntityList); editInfo->DataElement(AZ::Edit::UIHandlers::ComboBox, &UiSliderComponent::m_manipulatorEntity, "Manipulator", "The child element used as a handle.") ->Attribute(AZ::Edit::Attributes::EnumValues, &UiSliderComponent::PopulateChildEntityList); } // Value group { editInfo->ClassElement(AZ::Edit::ClassElements::Group, "Value") ->Attribute(AZ::Edit::Attributes::AutoExpand, true); editInfo->DataElement(0, &UiSliderComponent::m_value, "Value", "The initial value of the slider."); editInfo->DataElement(0, &UiSliderComponent::m_minValue, "Min", "The minimum slider value."); editInfo->DataElement(0, &UiSliderComponent::m_maxValue, "Max", "The maximum slider value."); editInfo->DataElement(0, &UiSliderComponent::m_stepValue, "Stepping", "The smallest increment allowed between values. Use zero for no restriction."); } // Actions group { editInfo->ClassElement(AZ::Edit::ClassElements::Group, "Actions") ->Attribute(AZ::Edit::Attributes::AutoExpand, true); editInfo->DataElement(0, &UiSliderComponent::m_valueChangingActionName, "Change", "The action triggered while the value is changing."); editInfo->DataElement(0, &UiSliderComponent::m_valueChangedActionName, "End change", "The action triggered when the value is done changing."); } } } AZ::BehaviorContext* behaviorContext = azrtti_cast(context); if (behaviorContext) { behaviorContext->EBus("UiSliderBus") ->Event("GetValue", &UiSliderBus::Events::GetValue) ->Event("SetValue", &UiSliderBus::Events::SetValue) ->Event("GetMinValue", &UiSliderBus::Events::GetMinValue) ->Event("SetMinValue", &UiSliderBus::Events::SetMinValue) ->Event("GetMaxValue", &UiSliderBus::Events::GetMaxValue) ->Event("SetMaxValue", &UiSliderBus::Events::SetMaxValue) ->Event("GetStepValue", &UiSliderBus::Events::GetStepValue) ->Event("SetStepValue", &UiSliderBus::Events::SetStepValue) ->Event("GetTrackEntity", &UiSliderBus::Events::GetTrackEntity) ->Event("SetTrackEntity", &UiSliderBus::Events::SetTrackEntity) ->Event("GetFillEntity", &UiSliderBus::Events::GetFillEntity) ->Event("SetFillEntity", &UiSliderBus::Events::SetFillEntity) ->Event("GetManipulatorEntity", &UiSliderBus::Events::GetManipulatorEntity) ->Event("SetManipulatorEntity", &UiSliderBus::Events::SetManipulatorEntity) ->Event("GetValueChangingActionName", &UiSliderBus::Events::GetValueChangingActionName) ->Event("SetValueChangingActionName", &UiSliderBus::Events::SetValueChangingActionName) ->Event("GetValueChangedActionName", &UiSliderBus::Events::GetValueChangedActionName) ->Event("SetValueChangedActionName", &UiSliderBus::Events::SetValueChangedActionName) ->VirtualProperty("Value", "GetValue", "SetValue") ->VirtualProperty("MinValue", "GetMinValue", "SetMinValue") ->VirtualProperty("MaxValue", "GetMaxValue", "SetMaxValue") ->VirtualProperty("StepValue", "GetStepValue", "SetStepValue"); behaviorContext->Class()->RequestBus("UiSliderBus"); behaviorContext->EBus("UiSliderNotificationBus") ->Handler(); } } //////////////////////////////////////////////////////////////////////////////////////////////////// // PRIVATE MEMBER FUNCTIONS //////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////// UiSliderComponent::EntityComboBoxVec UiSliderComponent::PopulateChildEntityList() { EntityComboBoxVec result; // add a first entry for "None" result.push_back(AZStd::make_pair(AZ::EntityId(AZ::EntityId()), "")); // Get a list of all child elements LyShine::EntityArray matchingElements; EBUS_EVENT_ID(GetEntityId(), UiElementBus, FindDescendantElements, [](const AZ::Entity* entity) { return true; }, 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; } //////////////////////////////////////////////////////////////////////////////////////////////////// float UiSliderComponent::GetValueFromPoint(AZ::Vector2 point) { // Get m_value from point. float value = 0.0f; UiTransformInterface::RectPoints points; EBUS_EVENT_ID(m_trackEntity, UiTransformBus, GetCanvasSpacePointsNoScaleRotate, points); // apply scale and rotation to points EBUS_EVENT_ID(m_trackEntity, UiTransformBus, RotateAndScalePoints, points); const AZ::Vector2& tl = points.TopLeft(); const AZ::Vector2& tr = points.TopRight(); AZ::Vector2 A = tr - tl; float magA = A.GetLength(); AZ::Vector2 normA = A.GetNormalized(); AZ::Vector2 B = point - tl; float magBalongA = B.Dot(normA); float range = fabsf(m_maxValue - m_minValue); float unitValue = (magBalongA / magA); if (m_minValue < m_maxValue) { value = m_minValue + (range * unitValue); } else // ( m_minValue >= m_maxValue ) { value = m_minValue - (range * unitValue); } return value; } //////////////////////////////////////////////////////////////////////////////////////////////////// // calculate how much we have dragged along the axis of the slider float UiSliderComponent::GetValidDragDistanceInPixels(AZ::Vector2 startPoint, AZ::Vector2 endPoint) { const float validDragRatio = 0.5f; // convert the drag vector to local space AZ::Matrix4x4 transformFromViewport; EBUS_EVENT_ID(m_trackEntity, UiTransformBus, GetTransformFromViewport, transformFromViewport); AZ::Vector2 dragVec = endPoint - startPoint; AZ::Vector3 dragVec3(dragVec.GetX(), dragVec.GetY(), 0.0f); AZ::Vector3 localDragVec = transformFromViewport.Multiply3x3(dragVec3); // the slider component only supports drag along the x axis so zero the y axis localDragVec.SetY(0.0f); // convert back to viewport space AZ::Matrix4x4 transformToViewport; EBUS_EVENT_ID(m_trackEntity, UiTransformBus, GetTransformToViewport, transformToViewport); AZ::Vector3 validDragVec = transformToViewport.Multiply3x3(localDragVec); float validDistance = validDragVec.GetLengthSq(); float totalDistance = dragVec.GetLengthSq(); // if they are not dragging mostly in a valid direction then ignore the drag if (validDistance / totalDistance < validDragRatio) { validDistance = 0.0f; } // return the valid drag distance return validDistance; } //////////////////////////////////////////////////////////////////////////////////////////////////// bool UiSliderComponent::CheckForDragOrHandOffToParent(AZ::EntityId currentActiveInteractable, AZ::Vector2 startPoint, AZ::Vector2 currentPoint, float childDragThreshold, bool& handOffDone) { bool result = false; AZ::EntityId parentDraggable; EBUS_EVENT_ID_RESULT(parentDraggable, GetEntityId(), UiElementBus, FindParentInteractableSupportingDrag, startPoint); // if this interactable is inside another interactable that supports drag then we use // a threshold value before starting a drag on this interactable const float normalDragThreshold = 0.0f; const float containedDragThreshold = 5.0f; float dragThreshold = normalDragThreshold; if (childDragThreshold > 0.0f) { dragThreshold = childDragThreshold; } else if (parentDraggable.IsValid()) { dragThreshold = containedDragThreshold; } // calculate how much we have dragged along the axis of the slider float validDragDistance = GetValidDragDistanceInPixels(startPoint, currentPoint); if (validDragDistance > dragThreshold) { // we dragged above the threshold value along axis of slider result = true; } else if (parentDraggable.IsValid()) { // offer the parent draggable the chance to become the active interactable EBUS_EVENT_ID_RESULT(handOffDone, parentDraggable, UiInteractableBus, OfferDragHandOff, currentActiveInteractable, startPoint, currentPoint, containedDragThreshold); if (handOffDone) { // interaction has been handed off to a container entity result = true; } } return result; } //////////////////////////////////////////////////////////////////////////////////////////////////// void UiSliderComponent::DoChangedActions() { if (m_onValueChanged) { m_onValueChanged(GetEntityId(), m_value); } // Tell any action listeners about the event if (!m_valueChangedActionName.empty()) { AZ::EntityId canvasEntityId; EBUS_EVENT_ID_RESULT(canvasEntityId, GetEntityId(), UiElementBus, GetCanvasEntityId); EBUS_EVENT_ID(canvasEntityId, UiCanvasNotificationBus, OnAction, GetEntityId(), m_valueChangedActionName); } EBUS_EVENT_ID(GetEntityId(), UiSliderNotificationBus, OnSliderValueChanged, m_value); } //////////////////////////////////////////////////////////////////////////////////////////////////// void UiSliderComponent::DoChangingActions() { if (m_onValueChanging) { m_onValueChanging(GetEntityId(), m_value); } // Tell any action listeners about the event if (!m_valueChangingActionName.empty()) { AZ::EntityId canvasEntityId; EBUS_EVENT_ID_RESULT(canvasEntityId, GetEntityId(), UiElementBus, GetCanvasEntityId); EBUS_EVENT_ID(canvasEntityId, UiCanvasNotificationBus, OnAction, GetEntityId(), m_valueChangingActionName); } EBUS_EVENT_ID(GetEntityId(), UiSliderNotificationBus, OnSliderValueChanging, m_value); } //////////////////////////////////////////////////////////////////////////////////////////////////// // PRIVATE STATIC MEMBER FUNCTIONS //////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////// bool UiSliderComponent::VersionConverter(AZ::SerializeContext& context, AZ::SerializeContext::DataElementNode& classElement) { // conversion from version 1 to 2: // - Need to convert AZStd::string sprites to AzFramework::SimpleAssetReference if (classElement.GetVersion() < 2) { if (!LyShine::ConvertSubElementFromAzStringToAssetRef(context, classElement, "SelectedSprite")) { return false; } if (!LyShine::ConvertSubElementFromAzStringToAssetRef(context, classElement, "DisabledSprite")) { return false; } } // Conversion from version 2 to 3: if (classElement.GetVersion() < 3) { // find the base class (AZ::Component) // NOTE: in very old versions there may not be a base class because the base class was not serialized int componentBaseClassIndex = classElement.FindElement(AZ_CRC("BaseClass1", 0xd4925735)); // If there was a base class, make a copy and remove it AZ::SerializeContext::DataElementNode componentBaseClassNode; if (componentBaseClassIndex != -1) { // make a local copy of the component base class node componentBaseClassNode = classElement.GetSubElement(componentBaseClassIndex); // remove the component base class from the button classElement.RemoveElement(componentBaseClassIndex); } // Add a new base class (UiInteractableComponent) int interactableBaseClassIndex = classElement.AddElement(context, "BaseClass1"); AZ::SerializeContext::DataElementNode& interactableBaseClassNode = classElement.GetSubElement(interactableBaseClassIndex); // if there was previously a base class... if (componentBaseClassIndex != -1) { // copy the component base class into the new interactable base class // Since AZ::Component is now the base class of UiInteractableComponent interactableBaseClassNode.AddElement(componentBaseClassNode); } // Move the selected/hover state to the base class if (!UiSerialize::MoveToInteractableStateActions(context, classElement, "HoverStateActions", "SelectedColor", "SelectedAlpha", "SelectedSprite")) { return false; } // Move the disabled state to the base class if (!UiSerialize::MoveToInteractableStateActions(context, classElement, "DisabledStateActions", "DisabledColor", "DisabledAlpha", "DisabledSprite")) { return false; } } return true; }