129 lines
5.3 KiB
C#
129 lines
5.3 KiB
C#
#nullable enable
|
|
using UnityEngine;
|
|
using UnityEngine.EventSystems;
|
|
using UnityEngine.UI;
|
|
|
|
namespace SHI.modal
|
|
{
|
|
/// <summary>
|
|
/// 두 개의 RectTransform 가로 분할을 드래그 버튼으로 조절하는 간단한 스플리터.
|
|
/// 레이아웃 그룹(수평) + LayoutElement.flexibleWidth 기반으로 동작합니다.
|
|
/// </summary>
|
|
public class HorizontalSplitDrag : MonoBehaviour, IBeginDragHandler, IDragHandler, IEndDragHandler
|
|
{
|
|
private RectTransform _left;
|
|
private RectTransform _right;
|
|
private LayoutElement _leftLayout;
|
|
private LayoutElement _rightLayout;
|
|
private RectTransform _parent;
|
|
private RectTransform _handleRect; // this splitter's rect
|
|
private float _parentWidth; // cached on begin drag
|
|
private float _handleY = 42; // keep original y
|
|
private RectTransform _leftFixedPanel; // e.g., ModelDetailListView root
|
|
|
|
private bool _lastLeftPanelActive;
|
|
private float _lastParentWidth;
|
|
|
|
public void Initialize(RectTransform left, RectTransform right, RectTransform? leftFixedPanel = null)
|
|
{
|
|
_left = left;
|
|
_right = right;
|
|
_leftFixedPanel = leftFixedPanel;
|
|
_parent = left != null ? left.parent as RectTransform : null;
|
|
_handleRect = transform as RectTransform;
|
|
|
|
_leftLayout = _left.GetComponent<LayoutElement>();
|
|
if (_leftLayout == null) _leftLayout = _left.gameObject.AddComponent<LayoutElement>();
|
|
_rightLayout = _right.GetComponent<LayoutElement>();
|
|
if (_rightLayout == null) _rightLayout = _right.gameObject.AddComponent<LayoutElement>();
|
|
|
|
_lastLeftPanelActive = _leftFixedPanel != null && _leftFixedPanel.gameObject.activeInHierarchy;
|
|
_lastParentWidth = _parent != null ? _parent.rect.width : 0f;
|
|
RefreshPosition();
|
|
}
|
|
|
|
public void OnBeginDrag(PointerEventData eventData)
|
|
{
|
|
if (_parent != null) _parentWidth = _parent.rect.width;
|
|
if (_handleRect != null) _handleY = _handleRect.anchoredPosition.y;
|
|
}
|
|
|
|
public void OnDrag(PointerEventData eventData)
|
|
{
|
|
if (_parent == null) return;
|
|
Vector2 local;
|
|
if (!RectTransformUtility.ScreenPointToLocalPointInRectangle(_parent, eventData.position, eventData.pressEventCamera, out local))
|
|
return;
|
|
|
|
float width = _parent.rect.width;
|
|
if (width <= 0f) return;
|
|
|
|
// 계산 범위: 좌측 고정 패널(보이는 경우)의 폭만큼 좌측 경계를 오른쪽으로 이동
|
|
float leftOffset = 0f;
|
|
if (_leftFixedPanel != null && _leftFixedPanel.gameObject.activeSelf)
|
|
{
|
|
leftOffset = _leftFixedPanel.rect.width;
|
|
}
|
|
|
|
float minX = -width * 0.5f + leftOffset; // 사용 가능한 작업 영역의 좌측 경계
|
|
float maxX = width * 0.5f; // 우측 경계
|
|
// 현재 포인터 위치를 작업 영역 비율[0..1]로 변환 후 범위 제한
|
|
float t = Mathf.InverseLerp(minX, maxX, local.x);
|
|
t = Mathf.Clamp01(t);
|
|
|
|
// LayoutElement 비율 (양 끝 과도값 방지하여10%~90% 사이 유지)
|
|
float leftWeight = Mathf.Clamp(t, 0.1f, 0.9f);
|
|
float rightWeight = 1f - leftWeight;
|
|
_leftLayout.flexibleWidth = leftWeight;
|
|
_rightLayout.flexibleWidth = rightWeight;
|
|
|
|
// 스플리터 핸들도 같은 좌표계에서 이동
|
|
if (_handleRect != null)
|
|
{
|
|
float clampedX = Mathf.Lerp(minX, maxX, leftWeight);
|
|
_handleRect.anchoredPosition = new Vector2(clampedX, _handleY);
|
|
}
|
|
}
|
|
|
|
// 외부에서 강제로 현재 레이아웃 기준으로 핸들 위치를 동기화합니다.
|
|
public void RefreshPosition()
|
|
{
|
|
if (_parent == null || _handleRect == null || _leftLayout == null || _rightLayout == null)
|
|
return;
|
|
|
|
float width = _parent.rect.width;
|
|
if (width <= 0f) return;
|
|
|
|
float leftOffset = 0f;
|
|
if (_leftFixedPanel != null && _leftFixedPanel.gameObject.activeSelf)
|
|
leftOffset = _leftFixedPanel.rect.width;
|
|
|
|
float minX = -width * 0.5f + leftOffset;
|
|
float maxX = width * 0.5f;
|
|
|
|
float totalFlex = Mathf.Max(0.0001f, _leftLayout.flexibleWidth + _rightLayout.flexibleWidth);
|
|
float leftWeight = Mathf.Clamp01(_leftLayout.flexibleWidth / totalFlex);
|
|
leftWeight = Mathf.Clamp(leftWeight, 0.1f, 0.9f);
|
|
|
|
if (_handleRect != null)
|
|
{
|
|
_handleRect.anchoredPosition = new Vector2(Mathf.Lerp(minX, maxX, leftWeight), _handleY);
|
|
}
|
|
}
|
|
|
|
private void LateUpdate()
|
|
{
|
|
bool nowActive = _leftFixedPanel != null && _leftFixedPanel.gameObject.activeInHierarchy;
|
|
float nowWidth = _parent != null ? _parent.rect.width : 0f;
|
|
if (nowActive != _lastLeftPanelActive || !Mathf.Approximately(nowWidth, _lastParentWidth))
|
|
{
|
|
_lastLeftPanelActive = nowActive;
|
|
_lastParentWidth = nowWidth;
|
|
RefreshPosition();
|
|
}
|
|
}
|
|
|
|
public void OnEndDrag(PointerEventData eventData) { }
|
|
}
|
|
}
|