157 lines
6.2 KiB
C#
157 lines
6.2 KiB
C#
using UnityEngine;
|
|
using UnityEngine.UIElements;
|
|
|
|
namespace SHI.Modal.NW
|
|
{
|
|
/// <summary>
|
|
/// UI 요소를 수직(Y축)으로만 드래그할 수 있게 해주는 Manipulator입니다.
|
|
///
|
|
/// <para><b>개요:</b></para>
|
|
/// <para>
|
|
/// Unity UI Toolkit의 PointerManipulator를 상속하여 구현된 커스텀 드래그 핸들러입니다.
|
|
/// 좌클릭으로 드래그를 시작하며, Y축 방향으로만 요소를 이동시킵니다.
|
|
/// NWModal에서 모델 뷰와 차트 뷰 사이의 구분선(드래그 버튼)에 사용됩니다.
|
|
/// </para>
|
|
///
|
|
/// <para><b>동작 방식:</b></para>
|
|
/// <list type="number">
|
|
/// <item>드래그 시작 시 요소를 Absolute 포지션으로 변경</item>
|
|
/// <item>마우스 이동에 따라 Y 좌표만 업데이트</item>
|
|
/// <item>X 좌표는 고정 유지</item>
|
|
/// </list>
|
|
///
|
|
/// <para><b>사용 예시:</b></para>
|
|
/// <code>
|
|
/// var dragButton = root.Q<Button>("drag-btn");
|
|
/// dragButton.AddManipulator(new VerticalDragManipulator());
|
|
/// </code>
|
|
///
|
|
/// <para><b>관련 클래스:</b></para>
|
|
/// <list type="bullet">
|
|
/// <item>HorizontalDragManipulator - 수평 드래그용 (ISOP 모달에서 사용)</item>
|
|
/// </list>
|
|
/// </summary>
|
|
public class VerticalDragManipulator : PointerManipulator
|
|
{
|
|
#region 드래그 상태 (Drag State)
|
|
/// <summary>현재 드래그 중인지 여부</summary>
|
|
private bool _isActive;
|
|
|
|
/// <summary>드래그 시작 시점의 포인터 위치 (화면 좌표)</summary>
|
|
private Vector3 _startPointerPosition;
|
|
|
|
/// <summary>드래그 시작 시점의 요소 top 스타일 값</summary>
|
|
private float _startTopStyle;
|
|
#endregion
|
|
|
|
#region 생성자 (Constructor)
|
|
/// <summary>
|
|
/// VerticalDragManipulator를 초기화합니다.
|
|
/// 좌클릭(MouseButton.LeftMouse)을 드래그 활성화 버튼으로 설정합니다.
|
|
/// </summary>
|
|
public VerticalDragManipulator()
|
|
{
|
|
_isActive = false;
|
|
// 좌클릭으로 드래그 활성화
|
|
activators.Add(new ManipulatorActivationFilter { button = MouseButton.LeftMouse });
|
|
}
|
|
#endregion
|
|
|
|
#region 이벤트 등록/해제 (Event Registration)
|
|
/// <summary>
|
|
/// 타겟 요소에 포인터 이벤트 콜백을 등록합니다.
|
|
/// AddManipulator() 호출 시 자동으로 실행됩니다.
|
|
/// </summary>
|
|
protected override void RegisterCallbacksOnTarget()
|
|
{
|
|
// TrickleDown: 부모에서 자식 방향으로 이벤트 전파 (캡처 단계)
|
|
target.RegisterCallback<PointerDownEvent>(OnPointerDown, TrickleDown.TrickleDown);
|
|
target.RegisterCallback<PointerMoveEvent>(OnPointerMove, TrickleDown.TrickleDown);
|
|
target.RegisterCallback<PointerUpEvent>(OnPointerUp, TrickleDown.TrickleDown);
|
|
}
|
|
|
|
/// <summary>
|
|
/// 타겟 요소에서 포인터 이벤트 콜백을 해제합니다.
|
|
/// RemoveManipulator() 호출 시 자동으로 실행됩니다.
|
|
/// </summary>
|
|
protected override void UnregisterCallbacksFromTarget()
|
|
{
|
|
target.UnregisterCallback<PointerDownEvent>(OnPointerDown);
|
|
target.UnregisterCallback<PointerMoveEvent>(OnPointerMove);
|
|
target.UnregisterCallback<PointerUpEvent>(OnPointerUp);
|
|
}
|
|
#endregion
|
|
|
|
#region 포인터 이벤트 핸들러 (Pointer Event Handlers)
|
|
/// <summary>
|
|
/// 포인터 다운(클릭) 이벤트를 처리합니다.
|
|
/// 드래그를 시작하고 포인터를 캡처합니다.
|
|
/// </summary>
|
|
/// <param name="evt">포인터 다운 이벤트</param>
|
|
private void OnPointerDown(PointerDownEvent evt)
|
|
{
|
|
// 이미 드래그 중이면 무시
|
|
if (_isActive) return;
|
|
|
|
// 요소를 Absolute 포지션으로 변경하여 레이아웃 흐름에서 분리
|
|
// 이렇게 해야 top 스타일로 위치를 직접 제어할 수 있음
|
|
if (target.style.position != Position.Absolute)
|
|
{
|
|
// 현재 레이아웃 위치를 Absolute 좌표로 변환 (점프 방지)
|
|
target.style.left = target.layout.x;
|
|
target.style.top = target.layout.y;
|
|
target.style.position = Position.Absolute;
|
|
}
|
|
|
|
_isActive = true;
|
|
|
|
// 포인터 캡처: 마우스가 요소 밖으로 나가도 이벤트 수신
|
|
target.CapturePointer(evt.pointerId);
|
|
|
|
// 시작 위치 저장
|
|
_startPointerPosition = evt.position;
|
|
_startTopStyle = target.layout.y;
|
|
|
|
// 이벤트 버블링 중단 (부모로 전파 방지)
|
|
evt.StopPropagation();
|
|
}
|
|
|
|
/// <summary>
|
|
/// 포인터 이동 이벤트를 처리합니다.
|
|
/// 드래그 중일 때 요소의 Y 좌표를 업데이트합니다.
|
|
/// </summary>
|
|
/// <param name="evt">포인터 이동 이벤트</param>
|
|
private void OnPointerMove(PointerMoveEvent evt)
|
|
{
|
|
// 드래그 중이 아니거나 포인터 캡처가 없으면 무시
|
|
if (!_isActive || !target.HasPointerCapture(evt.pointerId)) return;
|
|
|
|
// 이동 거리 계산 (시작 위치 기준)
|
|
Vector3 delta = evt.position - _startPointerPosition;
|
|
|
|
// 새 Y 좌표 계산 (시작 위치 + 이동량)
|
|
float newY = _startTopStyle + delta.y;
|
|
|
|
// Y 좌표만 업데이트 (X축은 고정)
|
|
target.style.top = newY;
|
|
}
|
|
|
|
/// <summary>
|
|
/// 포인터 업(릴리즈) 이벤트를 처리합니다.
|
|
/// 드래그를 종료하고 포인터 캡처를 해제합니다.
|
|
/// </summary>
|
|
/// <param name="evt">포인터 업 이벤트</param>
|
|
private void OnPointerUp(PointerUpEvent evt)
|
|
{
|
|
if (_isActive)
|
|
{
|
|
_isActive = false;
|
|
// 포인터 캡처 해제
|
|
target.ReleasePointer(evt.pointerId);
|
|
evt.StopPropagation();
|
|
}
|
|
}
|
|
#endregion
|
|
}
|
|
}
|