From 968772cbada68a076800bff47323254198dd097f Mon Sep 17 00:00:00 2001 From: Saas Date: Fri, 6 Mar 2026 22:54:17 +0100 Subject: [PATCH] resize node in all directions --- Source/Editor/Surface/ResizableSurfaceNode.cs | 119 +++++++++++++----- Source/Editor/Surface/SurfaceComment.cs | 16 +-- 2 files changed, 95 insertions(+), 40 deletions(-) diff --git a/Source/Editor/Surface/ResizableSurfaceNode.cs b/Source/Editor/Surface/ResizableSurfaceNode.cs index 259c29836..2a1f549fe 100644 --- a/Source/Editor/Surface/ResizableSurfaceNode.cs +++ b/Source/Editor/Surface/ResizableSurfaceNode.cs @@ -1,19 +1,22 @@ // Copyright (c) Wojciech Figat. All rights reserved. +using System; using FlaxEngine; using FlaxEngine.GUI; namespace FlaxEditor.Surface { /// - /// Visject Surface node control that cna be resized. + /// Visject Surface node control that can be resized. /// /// [HideInEditor] public class ResizableSurfaceNode : SurfaceNode { + private Float2 _resizeWeight; private Float2 _startResizingSize; - private Float2 _startResizingCornerOffset; + private Float2 _surfaceMouseLocation; + private bool _isMouseOverResizeBorder; /// /// Indicates whether the node is currently being resized. @@ -30,11 +33,6 @@ namespace FlaxEditor.Surface /// protected Float2 _sizeMin = new Float2(240, 160); - /// - /// Node resizing rectangle bounds. - /// - protected Rectangle _resizeButtonRect; - private Float2 SizeValue { get => (Float2)Values[_sizeValueIndex]; @@ -50,7 +48,7 @@ namespace FlaxEditor.Surface /// public override bool CanSelect(ref Float2 location) { - return base.CanSelect(ref location) && !_resizeButtonRect.MakeOffsetted(Location).Contains(ref location); + return base.CanSelect(ref location);// && !_resizeButtonRect.MakeOffsetted(Location).Contains(ref location); } /// @@ -79,15 +77,9 @@ namespace FlaxEditor.Surface { base.Draw(); - if (Surface.CanEdit) + if (Surface.CanEdit && (_isResizing || _isMouseOverResizeBorder)) { - var style = Style.Current; - if (_isResizing) - { - Render2D.FillRectangle(_resizeButtonRect, style.Selection); - Render2D.DrawRectangle(_resizeButtonRect, style.SelectionBorder); - } - Render2D.DrawSprite(style.Scale, _resizeButtonRect, _resizeButtonRect.Contains(_mousePosition) ? style.Foreground : style.ForegroundGrey); + Render2D.DrawRectangle(new Rectangle(Float2.Zero, Size), Style.Current.Foreground, 2f); } } @@ -109,46 +101,120 @@ namespace FlaxEditor.Surface base.OnEndMouseCapture(); } + private bool UpdateIsOverResizeBorder(Float2 location) + { + const float ResizeBorderHalfWidth = 20f; + const float ResizeOnAxisThreshold = 0.85f; + + var nodeRect = new Rectangle(Float2.Zero, Size); + bool onBorder = nodeRect.MakeExpanded(ResizeBorderHalfWidth).Contains(location); + var inNodeRect = nodeRect.MakeExpanded(-ResizeBorderHalfWidth); + bool inNode = inNodeRect.Contains(location); + + Float2 rawResizeWeight = (location - nodeRect.Center) / (nodeRect.Size * 0.5f); + _resizeWeight = new Float2(Mathf.Abs(rawResizeWeight.X) >= ResizeOnAxisThreshold ? Mathf.Sign(rawResizeWeight.X) : 0, + Mathf.Abs(rawResizeWeight.Y) >= ResizeOnAxisThreshold ? Mathf.Sign(rawResizeWeight.Y) : 0); + + _isMouseOverResizeBorder = onBorder && !inNode; + return onBorder && !inNode; + } + + private CursorType ResizeWeightToCursorType() + { + if ((_resizeWeight.X == 1 && _resizeWeight.Y == 0) || (_resizeWeight.X == -1 && _resizeWeight.Y == 0)) + return CursorType.SizeWE; + if ((_resizeWeight.X == 0 && _resizeWeight.Y == 1) || (_resizeWeight.X == 0 && _resizeWeight.Y == -1)) + return CursorType.SizeNS; + if ((_resizeWeight.X == -1 && _resizeWeight.Y == -1) || (_resizeWeight.X == 1 && _resizeWeight.Y == 1)) + return CursorType.SizeNWSE; + if ((_resizeWeight.X == 1 && _resizeWeight.Y == -1) || (_resizeWeight.X == -1 && _resizeWeight.Y == 1)) + return CursorType.SizeNESW; + return CursorType.Default; + } + /// public override bool OnMouseDown(Float2 location, MouseButton button) { if (base.OnMouseDown(location, button)) return true; - if (button == MouseButton.Left && _resizeButtonRect.Contains(ref location) && Surface.CanEdit) + if (button == MouseButton.Left && UpdateIsOverResizeBorder(location)) { // Start resizing + UpdateSurfaceMouseLocation(); _isResizing = true; _startResizingSize = Size; - _startResizingCornerOffset = Size - location; StartMouseCapture(); - Cursor = CursorType.SizeNWSE; return true; } return false; } + private Float2 GetControlDelta(Control control, ref Float2 start, ref Float2 end) + { + var pointOrigin = control.Parent ?? control; + var startPos = pointOrigin.PointFromParent(this, start); + var endPos = pointOrigin.PointFromParent(this, end); + return endPos - startPos; + } + + private void UpdateSurfaceMouseLocation() + { + _surfaceMouseLocation = Surface.PointFromScreen(Input.MouseScreenPosition); + } + /// public override void OnMouseMove(Float2 location) { if (_isResizing) { + var resizeAxisAbs = _resizeWeight.Absolute; + var resizeAxisPos = Float2.Clamp(_resizeWeight, Float2.Zero, Float2.One); + var resizeAxisNeg = Float2.Clamp(-_resizeWeight, Float2.Zero, Float2.One); + + var delta = PointToParent(Surface, location) - _surfaceMouseLocation; + // TODO: scale/size snapping? + delta *= resizeAxisAbs; + + var moveLocation = _surfaceMouseLocation + delta; + + // TODO: Do I need GetControlDelta? + var uiControlDelta = GetControlDelta(this, ref _surfaceMouseLocation, ref moveLocation); var emptySize = CalculateNodeSize(0, 0); - var size = Float2.Max(location - emptySize + _startResizingCornerOffset, _sizeMin); - Resize(size.X, size.Y); + Location += uiControlDelta * resizeAxisNeg; + Size += uiControlDelta * resizeAxisPos - uiControlDelta * resizeAxisNeg; + Size = new Float2(Mathf.Max(Size.X, _sizeMin.X), Mathf.Max(Size.Y, _sizeMin.Y)); + SizeValue = Size - emptySize; + SizeValue = new Float2(Mathf.Max(SizeValue.X, _sizeMin.X), Mathf.Max(SizeValue.Y, _sizeMin.Y)); + CalculateNodeSize(Size.X, Size.Y); + UpdateSurfaceMouseLocation(); + } + else if (UpdateIsOverResizeBorder(location)) + { + Cursor = ResizeWeightToCursorType(); } else { + Cursor = CursorType.Default; base.OnMouseMove(location); } } + /// + public override void OnMouseLeave() + { + Cursor = CursorType.Default; + _isMouseOverResizeBorder = false; + base.OnMouseLeave(); + } + /// public override bool OnMouseUp(Float2 location, MouseButton button) { if (button == MouseButton.Left && _isResizing) { + Cursor = CursorType.Default; EndResizing(); return true; } @@ -156,19 +222,8 @@ namespace FlaxEditor.Surface return base.OnMouseUp(location, button); } - /// - protected override void UpdateRectangles() - { - base.UpdateRectangles(); - - const float buttonMargin = Constants.NodeCloseButtonMargin; - const float buttonSize = Constants.NodeCloseButtonSize; - _resizeButtonRect = new Rectangle(_closeButtonRect.Left, Height - buttonSize - buttonMargin - 4, buttonSize, buttonSize); - } - private void EndResizing() { - Cursor = CursorType.Default; EndMouseCapture(); _isResizing = false; if (_startResizingSize != Size) diff --git a/Source/Editor/Surface/SurfaceComment.cs b/Source/Editor/Surface/SurfaceComment.cs index a76fa245d..aa0b0e811 100644 --- a/Source/Editor/Surface/SurfaceComment.cs +++ b/Source/Editor/Surface/SurfaceComment.cs @@ -130,7 +130,7 @@ namespace FlaxEditor.Surface _headerRect = new Rectangle(0, 0, Width, headerSize); _closeButtonRect = new Rectangle(Width - buttonSize - buttonMargin, buttonMargin, buttonSize, buttonSize); _colorButtonRect = new Rectangle(_closeButtonRect.Left - buttonSize - buttonMargin, buttonMargin, buttonSize, buttonSize); - _resizeButtonRect = new Rectangle(_closeButtonRect.Left, Height - buttonSize - buttonMargin, buttonSize, buttonSize); + //_resizeButtonRect = new Rectangle(_closeButtonRect.Left, Height - buttonSize - buttonMargin, buttonSize, buttonSize); _renameTextBox.Width = Width; _renameTextBox.Height = headerSize; } @@ -189,12 +189,12 @@ namespace FlaxEditor.Surface Render2D.DrawSprite(style.Settings, _colorButtonRect, _colorButtonRect.Contains(_mousePosition) && Surface.CanEdit ? style.Foreground : style.ForegroundGrey); // Resize button - if (_isResizing) - { - Render2D.FillRectangle(_resizeButtonRect, style.Selection); - Render2D.DrawRectangle(_resizeButtonRect, style.SelectionBorder); - } - Render2D.DrawSprite(style.Scale, _resizeButtonRect, _resizeButtonRect.Contains(_mousePosition) ? style.Foreground : style.ForegroundGrey); + //if (_isResizing) + //{ + // Render2D.FillRectangle(_resizeButtonRect, style.Selection); + // Render2D.DrawRectangle(_resizeButtonRect, style.SelectionBorder); + //} + //Render2D.DrawSprite(style.Scale, _resizeButtonRect, _resizeButtonRect.Contains(_mousePosition) ? style.Foreground : style.ForegroundGrey); } // Selection outline @@ -229,7 +229,7 @@ namespace FlaxEditor.Surface /// public override bool ContainsPoint(ref Float2 location, bool precise) { - return _headerRect.Contains(ref location) || _resizeButtonRect.Contains(ref location); + return _headerRect.Contains(ref location);// || _resizeButtonRect.Contains(ref location); } ///