From 2d3d836103f1cea3593750c075c97ed260c93219 Mon Sep 17 00:00:00 2001 From: Saas Date: Sat, 7 Mar 2026 16:24:05 +0100 Subject: [PATCH] I need something to diff against --- Source/Editor/Surface/ResizableSurfaceNode.cs | 378 ++++++++++-------- Source/Editor/Surface/SurfaceComment.cs | 2 +- 2 files changed, 217 insertions(+), 163 deletions(-) diff --git a/Source/Editor/Surface/ResizableSurfaceNode.cs b/Source/Editor/Surface/ResizableSurfaceNode.cs index 2a1f549fe..ed79c90d2 100644 --- a/Source/Editor/Surface/ResizableSurfaceNode.cs +++ b/Source/Editor/Surface/ResizableSurfaceNode.cs @@ -13,15 +13,204 @@ namespace FlaxEditor.Surface [HideInEditor] public class ResizableSurfaceNode : SurfaceNode { - private Float2 _resizeWeight; - private Float2 _startResizingSize; - private Float2 _surfaceMouseLocation; - private bool _isMouseOverResizeBorder; + private class ResizeBorder : Control + { + private const float BorderWidth = 15f; + private const float ResizeOnAxisThreshold = 0.85f; - /// - /// Indicates whether the node is currently being resized. - /// - protected bool _isResizing; + public VisjectSurface Surface; + public ResizableSurfaceNode ResizeableNode; + + private Float2 _surfaceMouseLocation; + private Float2 startResizingSize; + + public bool IsMouseOverResizeBorder { get; private set; } + public bool IsResizing { get; private set; } + + public Action StartResize; + public Action EndResize; + + public Float2 ResizeWeight { get; private set; } + public CursorType CursorType + { + get + { + 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 ResizeBorder(VisjectSurface surface, ResizableSurfaceNode resizeableNode) + { + Surface = surface; + ResizeableNode = resizeableNode; + } + + /// + /// Updates location and size to match the resizeable node with the additional padding. + /// + /// The node size. + /// The node location. + public void MatchResizeableNode(Float2 nodeSize, Float2 nodeLocation) + { + Size = nodeSize + new Float2(BorderWidth); + Location = nodeLocation - new Float2(BorderWidth * 0.5f); + } + + private void UpdateSurfaceMouseLocation() + { + _surfaceMouseLocation = Surface.PointFromScreen(Input.MouseScreenPosition); + } + + private void UpdateResizeFlags(Float2 location) + { + var borderRect = Bounds with { Location = Float2.Zero }; + bool onBorder = borderRect.Contains(location); + + Float2 rawResizeWeight = (location - borderRect.Center) / (borderRect.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 && !ResizeableNode.IsMouseOver; + } + + private Float2 GetControlDelta(Control control, ref Float2 start, ref Float2 end) + { + var pointOrigin = control.Parent ?? control; + var startPos = pointOrigin.PointFromParent(ResizeableNode, start); + var endPos = pointOrigin.PointFromParent(ResizeableNode, end); + return endPos - startPos; + } + + private void EndResizing() + { + EndMouseCapture(); + IsResizing = false; + if (startResizingSize != ResizeableNode.Size) + { + var emptySize = ResizeableNode.CalculateNodeSize(0, 0); + ResizeableNode.SizeValue = ResizeableNode.Size - emptySize; + Surface.MarkAsEdited(false); + } + } + + public override void OnMouseLeave() + { + Cursor = CursorType.Default; + IsMouseOverResizeBorder = false; + base.OnMouseLeave(); + } + + /// + public override void OnMouseMove(Float2 location) + { + if (!IsResizing) + { + UpdateResizeFlags(location); + } + else + { + var resizeAxisAbs = ResizeWeight.Absolute; + var resizeAxisPos = Float2.Clamp(ResizeWeight, Float2.Zero, Float2.One); + var resizeAxisNeg = Float2.Clamp(-ResizeWeight, Float2.Zero, Float2.One); + + var currentSurfaceMouse = Surface.PointFromScreen(Input.MouseScreenPosition); + var delta = currentSurfaceMouse - _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 = ResizeableNode.CalculateNodeSize(0, 0); + ResizeableNode.Size += uiControlDelta * resizeAxisPos - uiControlDelta * resizeAxisNeg; + Float2 oldSize = ResizeableNode.Size; + ResizeableNode.Size = new Float2(Mathf.Max(ResizeableNode.Size.X, ResizeableNode.sizeMin.X), Mathf.Max(ResizeableNode.Size.Y, ResizeableNode.sizeMin.Y)); + if (oldSize == ResizeableNode.Size) // Only move if size wasn't clamped + { + ResizeableNode.Location += uiControlDelta * resizeAxisNeg; + } + ResizeableNode.SizeValue = ResizeableNode.Size - emptySize; + ResizeableNode.SizeValue = new Float2(Mathf.Max(ResizeableNode.SizeValue.X, ResizeableNode.sizeMin.X), Mathf.Max(ResizeableNode.SizeValue.Y, ResizeableNode.sizeMin.Y)); + ResizeableNode.CalculateNodeSize(ResizeableNode.Size.X, ResizeableNode.Size.Y); + UpdateSurfaceMouseLocation(); + MatchResizeableNode(ResizeableNode.Size, ResizeableNode.Location); + } + + if (IsMouseOverResizeBorder) + Cursor = CursorType; + else + Cursor = CursorType.Default; + + + + base.OnMouseMove(location); + } + + public override bool OnMouseDown(Float2 location, MouseButton button) + { + if (button == MouseButton.Left && IsMouseOverResizeBorder && !IsResizing) + { + // Start resizing + UpdateSurfaceMouseLocation(); + IsResizing = true; + startResizingSize = ResizeableNode.Size; + StartMouseCapture(); + return true; + } + + return base.OnMouseDown(location, button); + } + + public override bool OnMouseUp(Float2 location, MouseButton button) + { + if (button == MouseButton.Left && IsResizing) + { + Cursor = CursorType.Default; + EndResizing(); + return true; + } + + return base.OnMouseUp(location, button); + } + + /// + public override void OnLostFocus() + { + if (IsResizing) + EndResizing(); + + base.OnLostFocus(); + } + + /// + public override void OnEndMouseCapture() + { + if (IsResizing) + EndResizing(); + + base.OnEndMouseCapture(); + } + + //public override void Draw() + //{ + // Render2D.DrawRectangle(new Rectangle(Float2.Zero, Size), Color.Blue, 1f); + //} + } + + + private ResizeBorder resizeBorder; /// /// Index of the Float2 value in the node values list to store node size. @@ -31,7 +220,7 @@ namespace FlaxEditor.Surface /// /// Minimum node size. /// - protected Float2 _sizeMin = new Float2(240, 160); + protected Float2 sizeMin = new Float2(240, 160); private Float2 SizeValue { @@ -43,12 +232,27 @@ namespace FlaxEditor.Surface public ResizableSurfaceNode(uint id, VisjectSurfaceContext context, NodeArchetype nodeArch, GroupArchetype groupArch) : base(id, context, nodeArch, groupArch) { + CullChildren = false; + ClipChildren = false; + resizeBorder = new ResizeBorder(Surface, this) + { + Parent = Surface.SurfaceRoot, + }; + + resizeBorder.MatchResizeableNode(Size, Location); + } + + /// + protected override void OnLocationChanged() + { + resizeBorder.MatchResizeableNode(Size, Location); + base.OnLocationChanged(); } /// public override bool CanSelect(ref Float2 location) { - return base.CanSelect(ref location);// && !_resizeButtonRect.MakeOffsetted(Location).Contains(ref location); + return base.CanSelect(ref location); } /// @@ -59,6 +263,7 @@ namespace FlaxEditor.Surface if (Surface != null && Surface.GridSnappingEnabled) size = Surface.SnapToGrid(size, true); Resize(size.X, size.Y); + resizeBorder.MatchResizeableNode(Size, Location); base.OnSurfaceLoaded(action); } @@ -77,161 +282,10 @@ namespace FlaxEditor.Surface { base.Draw(); - if (Surface.CanEdit && (_isResizing || _isMouseOverResizeBorder)) + if (Surface.CanEdit && (resizeBorder.IsResizing || resizeBorder.IsMouseOverResizeBorder)) { Render2D.DrawRectangle(new Rectangle(Float2.Zero, Size), Style.Current.Foreground, 2f); } } - - /// - public override void OnLostFocus() - { - if (_isResizing) - EndResizing(); - - base.OnLostFocus(); - } - - /// - public override void OnEndMouseCapture() - { - if (_isResizing) - EndResizing(); - - 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 && UpdateIsOverResizeBorder(location)) - { - // Start resizing - UpdateSurfaceMouseLocation(); - _isResizing = true; - _startResizingSize = Size; - StartMouseCapture(); - 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); - 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; - } - - return base.OnMouseUp(location, button); - } - - private void EndResizing() - { - EndMouseCapture(); - _isResizing = false; - if (_startResizingSize != Size) - { - var emptySize = CalculateNodeSize(0, 0); - SizeValue = Size - emptySize; - Surface.MarkAsEdited(false); - } - } } } diff --git a/Source/Editor/Surface/SurfaceComment.cs b/Source/Editor/Surface/SurfaceComment.cs index aa0b0e811..05e89b705 100644 --- a/Source/Editor/Surface/SurfaceComment.cs +++ b/Source/Editor/Surface/SurfaceComment.cs @@ -56,7 +56,7 @@ namespace FlaxEditor.Surface : base(id, context, nodeArch, groupArch) { _sizeValueIndex = 2; // Index of the Size stored in Values array - _sizeMin = new Float2(140.0f, Constants.NodeHeaderSize); + sizeMin = new Float2(140.0f, Constants.NodeHeaderSize); _renameTextBox = new TextBox(false, 0, 0, Width) { Height = Constants.NodeHeaderSize,