123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183 |
- using System;
- using UnityEngine;
- using UnityEngine.EventSystems;
- using UnityEngine.UI;
- namespace SoftMasking.Samples {
- [RequireComponent(typeof(RectTransform))]
- public class RectManipulator : UIBehaviour,
- IPointerEnterHandler,
- IPointerExitHandler,
- IBeginDragHandler,
- IDragHandler,
- IEndDragHandler {
- [Flags] public enum ManipulationType {
- None = 0,
- Move = 1 << 0,
- ResizeLeft = 1 << 1,
- ResizeUp = 1 << 2,
- ResizeRight = 1 << 3,
- ResizeDown = 1 << 4,
- ResizeUpLeft = ResizeUp | ResizeLeft,
- ResizeUpRight = ResizeUp | ResizeRight,
- ResizeDownLeft = ResizeDown | ResizeLeft,
- ResizeDownRight = ResizeDown | ResizeRight,
- Rotate = 1 << 5
- }
- public RectTransform targetTransform;
- public ManipulationType manipulation;
- public ShowOnHover showOnHover;
-
- [Header("Limits")]
- public Vector2 minSize;
- [Header("Display")]
- public Graphic icon;
- public float normalAlpha = 0.2f;
- public float selectedAlpha = 1f;
- public float transitionDuration = 0.2f;
- bool _isManipulatedNow;
- Vector2 _startAnchoredPosition;
- Vector2 _startSizeDelta;
- float _startRotation;
-
- public void OnPointerEnter(PointerEventData eventData) {
- HighlightIcon(true);
- }
- public void OnPointerExit(PointerEventData eventData) {
- if (!_isManipulatedNow)
- HighlightIcon(false);
- }
- void HighlightIcon(bool highlight, bool instant = false) {
- if (icon) {
- var targetAlpha = highlight ? selectedAlpha : normalAlpha;
- var duration = instant ? 0f : transitionDuration;
- icon.CrossFadeAlpha(targetAlpha, duration, true);
- }
- if (showOnHover)
- showOnHover.forcedVisible = highlight;
- }
- protected override void Start() {
- base.Start();
- HighlightIcon(false, instant: true);
- }
- public void OnBeginDrag(PointerEventData eventData) {
- _isManipulatedNow = true;
- RememberStartTransform();
- }
- void RememberStartTransform() {
- if (targetTransform) {
- _startAnchoredPosition = targetTransform.anchoredPosition;
- _startSizeDelta = targetTransform.sizeDelta;
- _startRotation = targetTransform.localRotation.eulerAngles.z;
- }
- }
- public void OnDrag(PointerEventData eventData) {
- if (targetTransform == null || parentTransform == null || !_isManipulatedNow)
- return;
- var startPoint = ToParentSpace(eventData.pressPosition, eventData.pressEventCamera);
- var curPoint = ToParentSpace(eventData.position, eventData.pressEventCamera);
- DoRotate(startPoint, curPoint);
- var parentSpaceMovement = curPoint - startPoint;
- DoMove(parentSpaceMovement);
- DoResize(parentSpaceMovement);
- }
- Vector2 ToParentSpace(Vector2 position, Camera eventCamera) {
- Vector2 localPosition;
- RectTransformUtility.ScreenPointToLocalPointInRectangle(
- parentTransform, position, eventCamera, out localPosition);
- return localPosition;
- }
-
- RectTransform parentTransform {
- get { return targetTransform.parent as RectTransform; }
- }
- void DoMove(Vector2 parentSpaceMovement) {
- if (Is(ManipulationType.Move))
- MoveTo(_startAnchoredPosition + parentSpaceMovement);
- }
- bool Is(ManipulationType expected) {
- return (manipulation & expected) == expected;
- }
- void MoveTo(Vector2 desiredAnchoredPosition) {
- targetTransform.anchoredPosition = ClampPosition(desiredAnchoredPosition);
- }
- Vector2 ClampPosition(Vector2 position) {
- var parentSize = parentTransform.rect.size;
- var halfSize = parentSize / 2;
- return new Vector2(
- Mathf.Clamp(position.x, -halfSize.x, halfSize.x),
- Mathf.Clamp(position.y, -halfSize.y, halfSize.y));
- }
- void DoRotate(Vector2 startParentPoint, Vector2 targetParentPoint) {
- if (Is(ManipulationType.Rotate)) {
- var startLever = startParentPoint - (Vector2)targetTransform.localPosition;
- var targetLever = targetParentPoint - (Vector2)targetTransform.localPosition;
- var additionalRotation = DeltaRotation(startLever, targetLever);
- targetTransform.localRotation = Quaternion.AngleAxis(_startRotation + additionalRotation, Vector3.forward);
- }
- }
- float DeltaRotation(Vector2 startLever, Vector2 endLever) {
- var startAngle = Mathf.Atan2(startLever.y, startLever.x) * Mathf.Rad2Deg;
- var endAngle = Mathf.Atan2(endLever.y, endLever.x) * Mathf.Rad2Deg;
- return Mathf.DeltaAngle(startAngle, endAngle);
- }
- void DoResize(Vector2 parentSpaceMovement) {
- var localSpaceMovement = Quaternion.Inverse(targetTransform.rotation) * parentSpaceMovement;
- var projectedOffset = ProjectResizeOffset(localSpaceMovement);
- if (projectedOffset.sqrMagnitude > 0f)
- SetSizeDirected(projectedOffset, ResizeSign());
- }
- Vector2 ProjectResizeOffset(Vector2 localOffset) {
- var isHorizontal = Is(ManipulationType.ResizeLeft) || Is(ManipulationType.ResizeRight);
- var isVertical = Is(ManipulationType.ResizeUp) || Is(ManipulationType.ResizeDown);
- return new Vector2(
- isHorizontal ? localOffset.x : 0f,
- isVertical ? localOffset.y : 0f);
- }
- Vector2 ResizeSign() {
- return new Vector2(
- Is(ManipulationType.ResizeLeft) ? -1f : 1f,
- Is(ManipulationType.ResizeDown) ? -1f : 1f);
- }
-
- void SetSizeDirected(Vector2 localOffset, Vector2 sizeSign) {
- var newSize = ClampSize(_startSizeDelta + Vector2.Scale(localOffset, sizeSign));
- targetTransform.sizeDelta = newSize;
- var actualSizeOffset = newSize - _startSizeDelta;
- var localMoveOffset = Vector2.Scale(actualSizeOffset / 2, sizeSign);
- MoveTo(_startAnchoredPosition + (Vector2)targetTransform.TransformVector(localMoveOffset));
- }
- Vector2 ClampSize(Vector2 size) {
- return new Vector2(
- Mathf.Max(size.x, minSize.x),
- Mathf.Max(size.y, minSize.y));
- }
- public void OnEndDrag(PointerEventData eventData) {
- _isManipulatedNow = false;
- if (!eventData.hovered.Contains(gameObject))
- HighlightIcon(false);
- }
- }
- }
|