You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
239 lines
10 KiB
239 lines
10 KiB
using System;
|
|
using UnityEditor.ShaderGraph.Drawing.Interfaces;
|
|
using UnityEditor.ShaderGraph.Drawing.Views;
|
|
using UnityEngine;
|
|
using UnityEngine.UIElements;
|
|
|
|
namespace UnityEditor.ShaderGraph.Drawing
|
|
{
|
|
class ElementResizer : Manipulator
|
|
{
|
|
bool m_IsEnabled = true;
|
|
public bool isEnabled
|
|
{
|
|
get => m_IsEnabled;
|
|
set => m_IsEnabled = value;
|
|
}
|
|
|
|
public readonly ResizableElement.Resizer direction;
|
|
|
|
public readonly VisualElement resizedElement;
|
|
|
|
public ElementResizer(VisualElement resizedElement, ResizableElement.Resizer direction)
|
|
{
|
|
this.direction = direction;
|
|
this.resizedElement = resizedElement;
|
|
}
|
|
|
|
protected override void RegisterCallbacksOnTarget()
|
|
{
|
|
target.RegisterCallback<MouseDownEvent>(OnMouseDown);
|
|
target.RegisterCallback<MouseUpEvent>(OnMouseUp);
|
|
}
|
|
|
|
protected override void UnregisterCallbacksFromTarget()
|
|
{
|
|
target.UnregisterCallback<MouseDownEvent>(OnMouseDown);
|
|
target.UnregisterCallback<MouseUpEvent>(OnMouseUp);
|
|
}
|
|
|
|
Vector2 m_StartMouse;
|
|
Vector2 m_StartSize;
|
|
|
|
Vector2 m_MinSize;
|
|
Vector2 m_MaxSize;
|
|
|
|
Vector2 m_StartPosition;
|
|
|
|
bool m_DragStarted = false;
|
|
|
|
void OnMouseDown(MouseDownEvent e)
|
|
{
|
|
if (!isEnabled)
|
|
return;
|
|
|
|
if (e.button == 0 && e.clickCount == 1)
|
|
{
|
|
VisualElement resizedTarget = resizedElement.parent;
|
|
if (resizedTarget != null)
|
|
{
|
|
VisualElement resizedBase = resizedTarget.parent;
|
|
if (resizedBase != null)
|
|
{
|
|
target.RegisterCallback<MouseMoveEvent>(OnMouseMove);
|
|
e.StopPropagation();
|
|
target.CaptureMouse();
|
|
m_StartMouse = resizedBase.WorldToLocal(e.mousePosition);
|
|
m_StartSize = new Vector2(resizedTarget.resolvedStyle.width, resizedTarget.resolvedStyle.height);
|
|
m_StartPosition = new Vector2(resizedTarget.resolvedStyle.left, resizedTarget.resolvedStyle.top);
|
|
|
|
bool minWidthDefined = resizedTarget.resolvedStyle.minWidth != StyleKeyword.Auto;
|
|
bool maxWidthDefined = resizedTarget.resolvedStyle.maxWidth != StyleKeyword.None;
|
|
bool minHeightDefined = resizedTarget.resolvedStyle.minHeight != StyleKeyword.Auto;
|
|
bool maxHeightDefined = resizedTarget.resolvedStyle.maxHeight != StyleKeyword.None;
|
|
m_MinSize = new Vector2(
|
|
minWidthDefined ? resizedTarget.resolvedStyle.minWidth.value : Mathf.NegativeInfinity,
|
|
minHeightDefined ? resizedTarget.resolvedStyle.minHeight.value : Mathf.NegativeInfinity);
|
|
m_MaxSize = new Vector2(
|
|
maxWidthDefined ? resizedTarget.resolvedStyle.maxWidth.value : Mathf.Infinity,
|
|
maxHeightDefined ? resizedTarget.resolvedStyle.maxHeight.value : Mathf.Infinity);
|
|
|
|
m_DragStarted = false;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void OnMouseMove(MouseMoveEvent e)
|
|
{
|
|
if (!isEnabled)
|
|
return;
|
|
|
|
VisualElement resizedTarget = resizedElement.parent;
|
|
VisualElement resizedBase = resizedTarget.parent;
|
|
|
|
// Top left position of the parent visual element
|
|
var parentRootPosition = resizedBase.worldBound;
|
|
// Top left of the target visual element for resizing
|
|
var targetRootPosition = resizedTarget.worldBound;
|
|
var canResizePastParentBounds = ((ISGResizable)resizedTarget).CanResizePastParentBounds();
|
|
|
|
Vector2 mousePos = resizedBase.WorldToLocal(e.mousePosition);
|
|
|
|
if (!m_DragStarted)
|
|
{
|
|
if (resizedTarget is ISGResizable resizable)
|
|
resizable.OnStartResize();
|
|
m_DragStarted = true;
|
|
}
|
|
|
|
if ((direction & ResizableElement.Resizer.Right) != 0)
|
|
{
|
|
var newWidth = m_StartSize.x + mousePos.x - m_StartMouse.x;
|
|
var parentRightBoundary = parentRootPosition.x + resizedBase.layout.width;
|
|
// Also ensure resizing does not happen past edge of parent views boundaries if the target does not allow it
|
|
if (!canResizePastParentBounds)
|
|
{
|
|
if ((targetRootPosition.x + newWidth) > parentRightBoundary)
|
|
{
|
|
var targetToRightBoundaryDelta = parentRightBoundary - targetRootPosition.x;
|
|
newWidth = targetToRightBoundaryDelta;
|
|
}
|
|
var newLayoutLeft = targetRootPosition.x - parentRootPosition.x;
|
|
// When resizing to right, make sure to calculate and set the target elements Style.left before resizing to ensure correct resizing behavior
|
|
// If Style.left is NaNpx it results in scaling towards the left
|
|
// This is due to how the WindowDockingLayout code affects GraphSubWindows
|
|
resizedTarget.style.left = newLayoutLeft;
|
|
}
|
|
|
|
resizedTarget.style.width = Mathf.Clamp(newWidth, m_MinSize.x, m_MaxSize.x);
|
|
}
|
|
else if ((direction & ResizableElement.Resizer.Left) != 0)
|
|
{
|
|
float delta = mousePos.x - m_StartMouse.x;
|
|
|
|
if (m_StartSize.x - delta < m_MinSize.x)
|
|
{
|
|
delta = -m_MinSize.x + m_StartSize.x;
|
|
}
|
|
else if (m_StartSize.x - delta > m_MaxSize.x)
|
|
{
|
|
delta = -m_MaxSize.x + m_StartSize.x;
|
|
}
|
|
|
|
var newWidth = -delta + m_StartSize.x;
|
|
var targetToLeftBoundaryDelta = delta + m_StartPosition.x;
|
|
|
|
if (!canResizePastParentBounds)
|
|
{
|
|
// This ensures that the left side of the resizing target never can get pushed past the parent boundary even if mouse is moving really fast
|
|
targetToLeftBoundaryDelta = Mathf.Clamp(targetToLeftBoundaryDelta, 2.5f, targetToLeftBoundaryDelta);
|
|
|
|
// Clamps width to max out at left edge of parent window
|
|
if (Mathf.Approximately(targetToLeftBoundaryDelta, 2.5f))
|
|
newWidth = (m_StartPosition.x + m_StartSize.x);
|
|
|
|
newWidth = Mathf.Clamp(newWidth, m_MinSize.x, m_MaxSize.x);
|
|
}
|
|
|
|
resizedTarget.style.left = targetToLeftBoundaryDelta;
|
|
resizedTarget.style.width = newWidth;
|
|
}
|
|
|
|
if ((direction & ResizableElement.Resizer.Bottom) != 0)
|
|
{
|
|
var delta = mousePos.y - m_StartMouse.y;
|
|
var newHeight = m_StartSize.y + delta;
|
|
|
|
var parentBottomBoundary = parentRootPosition.y + resizedBase.layout.height;
|
|
if (!canResizePastParentBounds)
|
|
{
|
|
if ((targetRootPosition.y + newHeight) > parentBottomBoundary)
|
|
{
|
|
var targetToBottomBoundaryDelta = parentBottomBoundary - targetRootPosition.y;
|
|
newHeight = targetToBottomBoundaryDelta;
|
|
}
|
|
var targetToTopBoundaryDelta = targetRootPosition.y - parentRootPosition.y;
|
|
// When resizing to bottom, make sure to calculate and set the target elements Style.top before resizing to ensure correct resizing behavior
|
|
// If Style.top is NaNpx it results in scaling towards the bottom
|
|
// This is due to how the WindowDockingLayout code affects GraphSubWindows
|
|
resizedTarget.style.top = targetToTopBoundaryDelta;
|
|
|
|
newHeight = Mathf.Clamp(newHeight, m_MinSize.y, m_MaxSize.y);
|
|
}
|
|
|
|
resizedTarget.style.height = newHeight;
|
|
}
|
|
else if ((direction & ResizableElement.Resizer.Top) != 0)
|
|
{
|
|
float delta = mousePos.y - m_StartMouse.y;
|
|
|
|
if (m_StartSize.y - delta < m_MinSize.y)
|
|
{
|
|
delta = -m_MinSize.y + m_StartSize.y;
|
|
}
|
|
else if (m_StartSize.y - delta > m_MaxSize.y)
|
|
{
|
|
delta = -m_MaxSize.y + m_StartSize.y;
|
|
}
|
|
|
|
var newHeight = -delta + m_StartSize.y;
|
|
var targetToTopBoundaryDelta = m_StartPosition.y + delta;
|
|
if (!canResizePastParentBounds)
|
|
{
|
|
// This ensures that the top of the resizing target never can get pushed past the parent boundary even if mouse is moving really fast
|
|
targetToTopBoundaryDelta = Mathf.Clamp(targetToTopBoundaryDelta, 2.5f, targetToTopBoundaryDelta);
|
|
|
|
// Clamps height to max out at top edge of parent window
|
|
if (Mathf.Approximately(targetToTopBoundaryDelta, 2.5f))
|
|
newHeight = (m_StartPosition.y + m_StartSize.y);
|
|
|
|
newHeight = Mathf.Clamp(newHeight, m_MinSize.y, m_MaxSize.y);
|
|
}
|
|
|
|
resizedTarget.style.top = targetToTopBoundaryDelta;
|
|
resizedTarget.style.height = newHeight;
|
|
}
|
|
e.StopPropagation();
|
|
}
|
|
|
|
void OnMouseUp(MouseUpEvent e)
|
|
{
|
|
if (!isEnabled)
|
|
return;
|
|
|
|
if (e.button == 0)
|
|
{
|
|
VisualElement resizedTarget = resizedElement.parent;
|
|
if (resizedTarget.style.width != m_StartSize.x || resizedTarget.style.height != m_StartSize.y)
|
|
{
|
|
if (resizedTarget is ISGResizable resizable)
|
|
resizable.OnResized();
|
|
}
|
|
target.UnregisterCallback<MouseMoveEvent>(OnMouseMove);
|
|
target.ReleaseMouse();
|
|
e.StopPropagation();
|
|
}
|
|
}
|
|
}
|
|
}
|