From 968772cbada68a076800bff47323254198dd097f Mon Sep 17 00:00:00 2001 From: Saas Date: Fri, 6 Mar 2026 22:54:17 +0100 Subject: [PATCH 01/19] 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); } /// From 2d3d836103f1cea3593750c075c97ed260c93219 Mon Sep 17 00:00:00 2001 From: Saas Date: Sat, 7 Mar 2026 16:24:05 +0100 Subject: [PATCH 02/19] 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, From 2805c0dd7b9f69ee8bb9d4e6e7b949d3c21a51b8 Mon Sep 17 00:00:00 2001 From: Saas Date: Sat, 7 Mar 2026 23:48:24 +0100 Subject: [PATCH 03/19] please squash commit history before merge I need sth to diff against again --- Source/Editor/Surface/ResizableSurfaceNode.cs | 167 +++++++++++------- Source/Editor/Surface/SurfaceComment.cs | 13 +- 2 files changed, 103 insertions(+), 77 deletions(-) diff --git a/Source/Editor/Surface/ResizableSurfaceNode.cs b/Source/Editor/Surface/ResizableSurfaceNode.cs index ed79c90d2..6fa7225c5 100644 --- a/Source/Editor/Surface/ResizableSurfaceNode.cs +++ b/Source/Editor/Surface/ResizableSurfaceNode.cs @@ -13,58 +13,73 @@ namespace FlaxEditor.Surface [HideInEditor] public class ResizableSurfaceNode : SurfaceNode { - private class ResizeBorder : Control + /// + /// Helper class for that handles mouse interactions resizing the node itself. + /// + protected class ResizeBorder : Control { + /// + /// Distance to each of the 4 node edges that the cursor has to be so the user can resize along the direction of the edge. + /// private const float BorderWidth = 15f; - private const float ResizeOnAxisThreshold = 0.85f; - - public VisjectSurface Surface; - public ResizableSurfaceNode ResizeableNode; + private readonly VisjectSurface Surface; + private readonly ResizableSurfaceNode ResizableNode; private Float2 _surfaceMouseLocation; private Float2 startResizingSize; + /// + /// True if the mouse is at the border of the resizable node and not further away from the border than . + /// public bool IsMouseOverResizeBorder { get; private set; } + + /// + /// True if is being resized. + /// public bool IsResizing { get; private set; } - public Action StartResize; - public Action EndResize; + /// + /// The direction in which to resize the node. Should be either -1, 0 or 1 on both axes. + /// + public Float2 ResizeDirection { get; private set; } - public Float2 ResizeWeight { get; private set; } + /// + /// The type of cursor to show to hint to the user that they can resize the node in a given direction. + /// public CursorType CursorType { get { - if ((ResizeWeight.X == 1 && ResizeWeight.Y == 0) || (ResizeWeight.X == -1 && ResizeWeight.Y == 0)) + if ((ResizeDirection.X == 1 && ResizeDirection.Y == 0) || (ResizeDirection.X == -1 && ResizeDirection.Y == 0)) return CursorType.SizeWE; - if ((ResizeWeight.X == 0 && ResizeWeight.Y == 1) || (ResizeWeight.X == 0 && ResizeWeight.Y == -1)) + if ((ResizeDirection.X == 0 && ResizeDirection.Y == 1) || (ResizeDirection.X == 0 && ResizeDirection.Y == -1)) return CursorType.SizeNS; - if ((ResizeWeight.X == -1 && ResizeWeight.Y == -1) || (ResizeWeight.X == 1 && ResizeWeight.Y == 1)) + if ((ResizeDirection.X == -1 && ResizeDirection.Y == -1) || (ResizeDirection.X == 1 && ResizeDirection.Y == 1)) return CursorType.SizeNWSE; - if ((ResizeWeight.X == 1 && ResizeWeight.Y == -1) || (ResizeWeight.X == -1 && ResizeWeight.Y == 1)) + if ((ResizeDirection.X == 1 && ResizeDirection.Y == -1) || (ResizeDirection.X == -1 && ResizeDirection.Y == 1)) return CursorType.SizeNESW; return CursorType.Default; } } - - public ResizeBorder(VisjectSurface surface, ResizableSurfaceNode resizeableNode) + /// + public ResizeBorder(VisjectSurface surface, ResizableSurfaceNode resizableNode) { Surface = surface; - ResizeableNode = resizeableNode; + ResizableNode = resizableNode; } /// - /// Updates location and size to match the resizeable node with the additional padding. + /// Updates location and size to match the resizable node with the additional padding. /// /// The node size. /// The node location. - public void MatchResizeableNode(Float2 nodeSize, Float2 nodeLocation) + public void MatchResizableNode(Float2 nodeSize, Float2 nodeLocation) { - Size = nodeSize + new Float2(BorderWidth); - Location = nodeLocation - new Float2(BorderWidth * 0.5f); + Size = nodeSize + new Float2(BorderWidth * 2); + Location = nodeLocation - new Float2(BorderWidth); } private void UpdateSurfaceMouseLocation() @@ -72,23 +87,27 @@ namespace FlaxEditor.Surface _surfaceMouseLocation = Surface.PointFromScreen(Input.MouseScreenPosition); } - private void UpdateResizeFlags(Float2 location) + private void UpdateResizeFlags(Float2 mouseLocation) { var borderRect = Bounds with { Location = Float2.Zero }; - bool onBorder = borderRect.Contains(location); + bool onBorder = borderRect.Contains(mouseLocation); + // Check this the way we do because some resizeable nodes (like comments) have an implementation of `Control.ContainsPoint` + // that does not check for the size you would think they have based on their visual appearance + bool inNode = borderRect.MakeExpanded(-BorderWidth * 2f).Contains(mouseLocation); - 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); + Float2 rawResizeDirection = (mouseLocation - borderRect.Center); + var nodeHalfSizeNoBorder = ResizableNode.Size * 0.5f - BorderWidth; + ResizeDirection = new Float2(Mathf.Abs(rawResizeDirection.X) >= nodeHalfSizeNoBorder.X ? Mathf.Sign(rawResizeDirection.X) : 0, + Mathf.Abs(rawResizeDirection.Y) >= nodeHalfSizeNoBorder.Y ? Mathf.Sign(rawResizeDirection.Y) : 0); - IsMouseOverResizeBorder = onBorder && !ResizeableNode.IsMouseOver; + IsMouseOverResizeBorder = false;// onBorder && !inNode; } 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); + var startPos = pointOrigin.PointFromParent(ResizableNode, start); + var endPos = pointOrigin.PointFromParent(ResizableNode, end); return endPos - startPos; } @@ -96,14 +115,15 @@ namespace FlaxEditor.Surface { EndMouseCapture(); IsResizing = false; - if (startResizingSize != ResizeableNode.Size) + if (startResizingSize != ResizableNode.Size) { - var emptySize = ResizeableNode.CalculateNodeSize(0, 0); - ResizeableNode.SizeValue = ResizeableNode.Size - emptySize; + var emptySize = ResizableNode.CalculateNodeSize(0, 0); + ResizableNode.SizeValue = ResizableNode.Size - emptySize; Surface.MarkAsEdited(false); } } + /// public override void OnMouseLeave() { Cursor = CursorType.Default; @@ -120,44 +140,53 @@ namespace FlaxEditor.Surface } else { - var resizeAxisAbs = ResizeWeight.Absolute; - var resizeAxisPos = Float2.Clamp(ResizeWeight, Float2.Zero, Float2.One); - var resizeAxisNeg = Float2.Clamp(-ResizeWeight, Float2.Zero, Float2.One); + var resizeAxisAbs = ResizeDirection.Absolute; + var resizeAxisPos = Float2.Clamp(ResizeDirection, Float2.Zero, Float2.One); + var resizeAxisNeg = Float2.Clamp(-ResizeDirection, 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); + var emptySize = ResizableNode.CalculateNodeSize(0, 0); + + + // TODO: Fix: Can't move comments anymore + + // TODO: If resize is blocked by min size and the user tries to increase the size again, wait until !blocked by min size to apply delta again + // To do this, just record pos when starting to block by min size and if (cursorLocation > min) { ResizeAgain() } + + ResizableNode.Size += uiControlDelta * resizeAxisPos - uiControlDelta * resizeAxisNeg; + ResizableNode.Size = new Float2(Mathf.Max(ResizableNode.Size.X, ResizableNode.sizeMin.X), Mathf.Max(ResizableNode.Size.Y, ResizableNode.sizeMin.Y)); + ResizableNode.Location += uiControlDelta * resizeAxisNeg; + + // Only move if size wasn't clamped + + + //Debug.Log($"OLD: {oldSize} NEW: {ResizableNode.Size}"); + + ResizableNode.SizeValue = ResizableNode.Size - emptySize; + ResizableNode.SizeValue = new Float2(Mathf.Max(ResizableNode.SizeValue.X, ResizableNode.sizeMin.X), Mathf.Max(ResizableNode.SizeValue.Y, ResizableNode.sizeMin.Y)); + ResizableNode.CalculateNodeSize(ResizableNode.Size.X, ResizableNode.Size.Y); + UpdateSurfaceMouseLocation(); - MatchResizeableNode(ResizeableNode.Size, ResizeableNode.Location); + MatchResizableNode(ResizableNode.Size, ResizableNode.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) @@ -165,7 +194,7 @@ namespace FlaxEditor.Surface // Start resizing UpdateSurfaceMouseLocation(); IsResizing = true; - startResizingSize = ResizeableNode.Size; + startResizingSize = ResizableNode.Size; StartMouseCapture(); return true; } @@ -173,6 +202,7 @@ namespace FlaxEditor.Surface return base.OnMouseDown(location, button); } + /// public override bool OnMouseUp(Float2 location, MouseButton button) { if (button == MouseButton.Left && IsResizing) @@ -203,14 +233,17 @@ namespace FlaxEditor.Surface base.OnEndMouseCapture(); } - //public override void Draw() - //{ - // Render2D.DrawRectangle(new Rectangle(Float2.Zero, Size), Color.Blue, 1f); - //} + /// + public override void Draw() + { + Render2D.DrawRectangle(Bounds with { Location = Float2.Zero }, Color.Green, 1f); + } } - - private ResizeBorder resizeBorder; + /// + /// Represents the border control used for resizing the associated element. + /// + protected ResizeBorder ResizeBorderControl; /// /// Index of the Float2 value in the node values list to store node size. @@ -232,28 +265,26 @@ 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) + ResizeBorderControl = new ResizeBorder(Surface, this) { Parent = Surface.SurfaceRoot, }; - resizeBorder.MatchResizeableNode(Size, Location); + ResizeBorderControl.MatchResizableNode(Size, Location); } /// protected override void OnLocationChanged() { - resizeBorder.MatchResizeableNode(Size, Location); + ResizeBorderControl.MatchResizableNode(Size, Location); base.OnLocationChanged(); } - /// - public override bool CanSelect(ref Float2 location) - { - return base.CanSelect(ref location); - } + ///// + //public override bool CanSelect(ref Float2 location) + //{ + // return base.CanSelect(ref location); + //} /// public override void OnSurfaceLoaded(SurfaceNodeActions action) @@ -263,7 +294,7 @@ namespace FlaxEditor.Surface if (Surface != null && Surface.GridSnappingEnabled) size = Surface.SnapToGrid(size, true); Resize(size.X, size.Y); - resizeBorder.MatchResizeableNode(Size, Location); + ResizeBorderControl.MatchResizableNode(Size, Location); base.OnSurfaceLoaded(action); } @@ -282,9 +313,9 @@ namespace FlaxEditor.Surface { base.Draw(); - if (Surface.CanEdit && (resizeBorder.IsResizing || resizeBorder.IsMouseOverResizeBorder)) + if (Surface.CanEdit && (ResizeBorderControl.IsResizing || ResizeBorderControl.IsMouseOverResizeBorder)) { - Render2D.DrawRectangle(new Rectangle(Float2.Zero, Size), Style.Current.Foreground, 2f); + Render2D.DrawRectangle(new Rectangle(Float2.Zero, Size), Style.Current.Foreground, 0.5f); } } } diff --git a/Source/Editor/Surface/SurfaceComment.cs b/Source/Editor/Surface/SurfaceComment.cs index 05e89b705..3a8416fd3 100644 --- a/Source/Editor/Surface/SurfaceComment.cs +++ b/Source/Editor/Surface/SurfaceComment.cs @@ -130,7 +130,6 @@ 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); _renameTextBox.Width = Width; _renameTextBox.Height = headerSize; } @@ -188,13 +187,9 @@ namespace FlaxEditor.Surface // Color button 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); + // Resize + if (ResizeBorderControl.IsResizing || ResizeBorderControl.IsMouseOverResizeBorder) + Render2D.DrawRectangle(new Rectangle(Float2.Zero, Size), Style.Current.Foreground, 0.5f); } // Selection outline @@ -229,7 +224,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); } /// From 1105e58b066819fac0feb8d3bda321d08144a3c5 Mon Sep 17 00:00:00 2001 From: Saas Date: Sun, 8 Mar 2026 14:53:48 +0100 Subject: [PATCH 04/19] fix not being able to move comments nodes --- Source/Editor/Surface/SurfaceComment.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Source/Editor/Surface/SurfaceComment.cs b/Source/Editor/Surface/SurfaceComment.cs index 3a8416fd3..c257dddd1 100644 --- a/Source/Editor/Surface/SurfaceComment.cs +++ b/Source/Editor/Surface/SurfaceComment.cs @@ -81,12 +81,16 @@ namespace FlaxEditor.Surface if (Values.Length < 4) { if (IndexInParent > 0) + { IndexInParent = 0; + ResizeBorderControl.IndexInParent = - 1; + } OrderValue = IndexInParent; } else if (OrderValue != -1) { IndexInParent = OrderValue; + ResizeBorderControl.IndexInParent = OrderValue - 1; } } From 2c8ade42888cb2520fc63328bfb8e34d8fb80660 Mon Sep 17 00:00:00 2001 From: Saas Date: Sun, 8 Mar 2026 23:11:22 +0100 Subject: [PATCH 05/19] fix comment order and not being able to move around comment nodes --- Source/Editor/Surface/ResizableSurfaceNode.cs | 38 ++++++++++++------- Source/Editor/Surface/SurfaceComment.cs | 30 +++++++-------- Source/Editor/Surface/SurfaceRootControl.cs | 6 +-- .../Editor/Surface/VisjectSurfaceContext.cs | 8 ++-- 4 files changed, 45 insertions(+), 37 deletions(-) diff --git a/Source/Editor/Surface/ResizableSurfaceNode.cs b/Source/Editor/Surface/ResizableSurfaceNode.cs index 6fa7225c5..ea9ceec82 100644 --- a/Source/Editor/Surface/ResizableSurfaceNode.cs +++ b/Source/Editor/Surface/ResizableSurfaceNode.cs @@ -16,7 +16,7 @@ namespace FlaxEditor.Surface /// /// Helper class for that handles mouse interactions resizing the node itself. /// - protected class ResizeBorder : Control + public class ResizeBorder : ContainerControl { /// /// Distance to each of the 4 node edges that the cursor has to be so the user can resize along the direction of the edge. @@ -24,10 +24,14 @@ namespace FlaxEditor.Surface private const float BorderWidth = 15f; private readonly VisjectSurface Surface; - private readonly ResizableSurfaceNode ResizableNode; private Float2 _surfaceMouseLocation; private Float2 startResizingSize; + /// + /// The resizable node that this controls. + /// + public readonly ResizableSurfaceNode ResizableNode; + /// /// True if the mouse is at the border of the resizable node and not further away from the border than . /// @@ -63,7 +67,6 @@ namespace FlaxEditor.Surface } } - /// public ResizeBorder(VisjectSurface surface, ResizableSurfaceNode resizableNode) { @@ -100,7 +103,7 @@ namespace FlaxEditor.Surface ResizeDirection = new Float2(Mathf.Abs(rawResizeDirection.X) >= nodeHalfSizeNoBorder.X ? Mathf.Sign(rawResizeDirection.X) : 0, Mathf.Abs(rawResizeDirection.Y) >= nodeHalfSizeNoBorder.Y ? Mathf.Sign(rawResizeDirection.Y) : 0); - IsMouseOverResizeBorder = false;// onBorder && !inNode; + IsMouseOverResizeBorder = onBorder && !inNode; } private Float2 GetControlDelta(Control control, ref Float2 start, ref Float2 end) @@ -186,6 +189,13 @@ namespace FlaxEditor.Surface base.OnMouseMove(location); } + /// + public override void OnMouseEnter(Float2 location) + { + Cursor = CursorType.Default; + base.OnMouseEnter(location); + } + /// public override bool OnMouseDown(Float2 location, MouseButton button) { @@ -243,7 +253,7 @@ namespace FlaxEditor.Surface /// /// Represents the border control used for resizing the associated element. /// - protected ResizeBorder ResizeBorderControl; + public ResizeBorder ResizeBorderControl; /// /// Index of the Float2 value in the node values list to store node size. @@ -270,6 +280,7 @@ namespace FlaxEditor.Surface Parent = Surface.SurfaceRoot, }; + Parent = ResizeBorderControl; ResizeBorderControl.MatchResizableNode(Size, Location); } @@ -280,13 +291,7 @@ namespace FlaxEditor.Surface base.OnLocationChanged(); } - ///// - //public override bool CanSelect(ref Float2 location) - //{ - // return base.CanSelect(ref location); - //} - - /// + /// public override void OnSurfaceLoaded(SurfaceNodeActions action) { // Reapply the curve node size @@ -314,9 +319,14 @@ namespace FlaxEditor.Surface base.Draw(); if (Surface.CanEdit && (ResizeBorderControl.IsResizing || ResizeBorderControl.IsMouseOverResizeBorder)) - { Render2D.DrawRectangle(new Rectangle(Float2.Zero, Size), Style.Current.Foreground, 0.5f); - } + } + + /// + public override void OnDestroy() + { + ResizeBorderControl.Parent = null; + base.OnDestroy(); } } } diff --git a/Source/Editor/Surface/SurfaceComment.cs b/Source/Editor/Surface/SurfaceComment.cs index c257dddd1..73f280d48 100644 --- a/Source/Editor/Surface/SurfaceComment.cs +++ b/Source/Editor/Surface/SurfaceComment.cs @@ -81,16 +81,12 @@ namespace FlaxEditor.Surface if (Values.Length < 4) { if (IndexInParent > 0) - { IndexInParent = 0; - ResizeBorderControl.IndexInParent = - 1; - } OrderValue = IndexInParent; } else if (OrderValue != -1) { - IndexInParent = OrderValue; - ResizeBorderControl.IndexInParent = OrderValue - 1; + ResizeBorderControl.IndexInParent = OrderValue; } } @@ -103,8 +99,8 @@ namespace FlaxEditor.Surface Color = ColorValue = Color.FromHSV(new Random().NextFloat(0, 360), 0.7f, 0.25f, 0.8f); if (OrderValue == -1) - OrderValue = Context.CommentCount - 1; - IndexInParent = OrderValue; + OrderValue = Context.CommentCount; + ResizeBorderControl.IndexInParent = OrderValue; } /// @@ -333,25 +329,25 @@ namespace FlaxEditor.Surface { cmOrder.ContextMenu.AddButton("Bring Forward", () => { - if (IndexInParent < Context.CommentCount - 1) - IndexInParent++; - OrderValue = IndexInParent; + if (ResizeBorderControl.IndexInParent < Context.CommentCount - 1) + ResizeBorderControl.IndexInParent++; + OrderValue = ResizeBorderControl.IndexInParent; }); cmOrder.ContextMenu.AddButton("Bring to Front", () => { - IndexInParent = Context.CommentCount - 1; - OrderValue = IndexInParent; + ResizeBorderControl.IndexInParent = Context.CommentCount - 1; + OrderValue = ResizeBorderControl.IndexInParent; }); cmOrder.ContextMenu.AddButton("Send Backward", () => { - if (IndexInParent > 0) - IndexInParent--; - OrderValue = IndexInParent; + if (ResizeBorderControl.IndexInParent > 0) + ResizeBorderControl.IndexInParent--; + OrderValue = ResizeBorderControl.IndexInParent; }); cmOrder.ContextMenu.AddButton("Send to Back", () => { - IndexInParent = 0; - OrderValue = IndexInParent; + ResizeBorderControl.IndexInParent = 0; + OrderValue = ResizeBorderControl.IndexInParent; }); } } diff --git a/Source/Editor/Surface/SurfaceRootControl.cs b/Source/Editor/Surface/SurfaceRootControl.cs index 15d4c43cc..c7639a27d 100644 --- a/Source/Editor/Surface/SurfaceRootControl.cs +++ b/Source/Editor/Surface/SurfaceRootControl.cs @@ -46,10 +46,10 @@ namespace FlaxEditor.Surface { var child = _children[i]; - if (child is SurfaceComment && child.Visible) + if (child is ResizableSurfaceNode.ResizeBorder border && border.ResizableNode is SurfaceComment comment2 && comment2.Visible) { - Render2D.PushTransform(ref child._cachedTransform); - child.Draw(); + Render2D.PushTransform(ref comment2._cachedTransform); + comment2.Draw(); Render2D.PopTransform(); } } diff --git a/Source/Editor/Surface/VisjectSurfaceContext.cs b/Source/Editor/Surface/VisjectSurfaceContext.cs index 0d10aa230..be91e02ca 100644 --- a/Source/Editor/Surface/VisjectSurfaceContext.cs +++ b/Source/Editor/Surface/VisjectSurfaceContext.cs @@ -80,8 +80,9 @@ namespace FlaxEditor.Surface var result = new List(); for (int i = 0; i < RootControl.Children.Count; i++) { - if (RootControl.Children[i] is SurfaceComment comment) - result.Add(comment); + var child = RootControl.Children[i]; + if (child is ResizableSurfaceNode.ResizeBorder border && border.ResizableNode is SurfaceComment comment2) + result.Add(comment2); } return result; } @@ -101,7 +102,8 @@ namespace FlaxEditor.Surface int count = 0; for (int i = 0; i < RootControl.Children.Count; i++) { - if (RootControl.Children[i] is SurfaceComment) + var child = RootControl.Children[i]; + if (child is ResizableSurfaceNode.ResizeBorder border && border.ResizableNode is SurfaceComment) count++; } return count; From 20bfc209c59c2f5c86c228749c23262b7ee9a335 Mon Sep 17 00:00:00 2001 From: Saas Date: Sun, 8 Mar 2026 23:29:20 +0100 Subject: [PATCH 06/19] fix auto move new comment to back --- Source/Editor/Surface/VisjectSurface.cs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/Source/Editor/Surface/VisjectSurface.cs b/Source/Editor/Surface/VisjectSurface.cs index e3bb94bcc..69c44ab98 100644 --- a/Source/Editor/Surface/VisjectSurface.cs +++ b/Source/Editor/Surface/VisjectSurface.cs @@ -810,10 +810,11 @@ namespace FlaxEditor.Surface int lowestCommentOrder = int.MaxValue; for (int i = 0; i < selection.Count; i++) { - if (selection[i] is not SurfaceComment || selection[i].IndexInParent >= lowestCommentOrder) - continue; - hasCommentsSelected = true; - lowestCommentOrder = selection[i].IndexInParent; + if (selection[i] is ResizableSurfaceNode node && node is SurfaceComment && node.ResizeBorderControl.IndexInParent < lowestCommentOrder) + { + hasCommentsSelected = true; + lowestCommentOrder = node.ResizeBorderControl.IndexInParent; + } } return _context.CreateComment(ref surfaceArea, string.IsNullOrEmpty(text) ? "Comment" : text, new Color(1.0f, 1.0f, 1.0f, 0.2f), hasCommentsSelected ? lowestCommentOrder : -1); From 681b303f2dc8b144308e449bbb1ef9e40b9461bc Mon Sep 17 00:00:00 2001 From: Saas Date: Mon, 9 Mar 2026 17:04:06 +0100 Subject: [PATCH 07/19] fix cursor shape when there are nested comments --- Source/Editor/Surface/ResizableSurfaceNode.cs | 65 +++++++++++-------- Source/Editor/Surface/SurfaceComment.cs | 2 + Source/Editor/Surface/VisjectSurface.cs | 1 + 3 files changed, 41 insertions(+), 27 deletions(-) diff --git a/Source/Editor/Surface/ResizableSurfaceNode.cs b/Source/Editor/Surface/ResizableSurfaceNode.cs index ea9ceec82..26c64c382 100644 --- a/Source/Editor/Surface/ResizableSurfaceNode.cs +++ b/Source/Editor/Surface/ResizableSurfaceNode.cs @@ -23,10 +23,15 @@ namespace FlaxEditor.Surface /// private const float BorderWidth = 15f; - private readonly VisjectSurface Surface; + private readonly VisjectSurface _surface; private Float2 _surfaceMouseLocation; private Float2 startResizingSize; + /// + /// Wether to ignore the surface index in parent when updating the cursor type. Set to false for nodes that have order like . + /// + internal bool IgnoreSurfaceIndex = true; + /// /// The resizable node that this controls. /// @@ -67,10 +72,14 @@ namespace FlaxEditor.Surface } } - /// + /// + /// Creates a new instance of . + /// + /// The surface. + /// The this controls. public ResizeBorder(VisjectSurface surface, ResizableSurfaceNode resizableNode) { - Surface = surface; + _surface = surface; ResizableNode = resizableNode; } @@ -87,7 +96,7 @@ namespace FlaxEditor.Surface private void UpdateSurfaceMouseLocation() { - _surfaceMouseLocation = Surface.PointFromScreen(Input.MouseScreenPosition); + _surfaceMouseLocation = _surface.PointFromScreen(Input.MouseScreenPosition); } private void UpdateResizeFlags(Float2 mouseLocation) @@ -122,18 +131,10 @@ namespace FlaxEditor.Surface { var emptySize = ResizableNode.CalculateNodeSize(0, 0); ResizableNode.SizeValue = ResizableNode.Size - emptySize; - Surface.MarkAsEdited(false); + _surface.MarkAsEdited(false); } } - /// - public override void OnMouseLeave() - { - Cursor = CursorType.Default; - IsMouseOverResizeBorder = false; - base.OnMouseLeave(); - } - /// public override void OnMouseMove(Float2 location) { @@ -147,7 +148,7 @@ namespace FlaxEditor.Surface var resizeAxisPos = Float2.Clamp(ResizeDirection, Float2.Zero, Float2.One); var resizeAxisNeg = Float2.Clamp(-ResizeDirection, Float2.Zero, Float2.One); - var currentSurfaceMouse = Surface.PointFromScreen(Input.MouseScreenPosition); + var currentSurfaceMouse = _surface.PointFromScreen(Input.MouseScreenPosition); var delta = currentSurfaceMouse - _surfaceMouseLocation; // TODO: scale/size snapping? @@ -159,8 +160,6 @@ namespace FlaxEditor.Surface var emptySize = ResizableNode.CalculateNodeSize(0, 0); - // TODO: Fix: Can't move comments anymore - // TODO: If resize is blocked by min size and the user tries to increase the size again, wait until !blocked by min size to apply delta again // To do this, just record pos when starting to block by min size and if (cursorLocation > min) { ResizeAgain() } @@ -168,23 +167,26 @@ namespace FlaxEditor.Surface ResizableNode.Size = new Float2(Mathf.Max(ResizableNode.Size.X, ResizableNode.sizeMin.X), Mathf.Max(ResizableNode.Size.Y, ResizableNode.sizeMin.Y)); ResizableNode.Location += uiControlDelta * resizeAxisNeg; - // Only move if size wasn't clamped - - - //Debug.Log($"OLD: {oldSize} NEW: {ResizableNode.Size}"); - ResizableNode.SizeValue = ResizableNode.Size - emptySize; ResizableNode.SizeValue = new Float2(Mathf.Max(ResizableNode.SizeValue.X, ResizableNode.sizeMin.X), Mathf.Max(ResizableNode.SizeValue.Y, ResizableNode.sizeMin.Y)); + ResizableNode.CalculateNodeSize(ResizableNode.Size.X, ResizableNode.Size.Y); UpdateSurfaceMouseLocation(); MatchResizableNode(ResizableNode.Size, ResizableNode.Location); } - if (IsMouseOverResizeBorder) - Cursor = CursorType; - else - Cursor = CursorType.Default; + // Update the cursor shape + if (_surface.resizeableNodeIndexInParent <= IndexInParent || IgnoreSurfaceIndex) + { + if (!IgnoreSurfaceIndex) + _surface.resizeableNodeIndexInParent = IndexInParent; + + if (IsMouseOverResizeBorder) + Cursor = CursorType; + else + Cursor = CursorType.Default; + } base.OnMouseMove(location); } @@ -196,6 +198,15 @@ namespace FlaxEditor.Surface base.OnMouseEnter(location); } + /// + public override void OnMouseLeave() + { + Cursor = CursorType.Default; + IsMouseOverResizeBorder = false; + _surface.resizeableNodeIndexInParent = -1; // Will get updated by MouseMove again to match current index + base.OnMouseLeave(); + } + /// public override bool OnMouseDown(Float2 location, MouseButton button) { @@ -291,10 +302,10 @@ namespace FlaxEditor.Surface base.OnLocationChanged(); } - /// + /// public override void OnSurfaceLoaded(SurfaceNodeActions action) { - // Reapply the curve node size + // Reapply the node size var size = SizeValue; if (Surface != null && Surface.GridSnappingEnabled) size = Surface.SnapToGrid(size, true); diff --git a/Source/Editor/Surface/SurfaceComment.cs b/Source/Editor/Surface/SurfaceComment.cs index 73f280d48..4966c83b3 100644 --- a/Source/Editor/Surface/SurfaceComment.cs +++ b/Source/Editor/Surface/SurfaceComment.cs @@ -65,6 +65,8 @@ namespace FlaxEditor.Surface EndEditOnClick = false, // We have to handle this ourselves, otherwise the textbox instantly loses focus when double-clicking the header HorizontalAlignment = TextAlignment.Center, }; + + ResizeBorderControl.IgnoreSurfaceIndex = false; } /// diff --git a/Source/Editor/Surface/VisjectSurface.cs b/Source/Editor/Surface/VisjectSurface.cs index 69c44ab98..352bc1ebe 100644 --- a/Source/Editor/Surface/VisjectSurface.cs +++ b/Source/Editor/Surface/VisjectSurface.cs @@ -62,6 +62,7 @@ namespace FlaxEditor.Surface private int _selectedConnectionIndex; internal int _isUpdatingBoxTypes; + internal int resizeableNodeIndexInParent = -1; /// /// True if surface supports implicit casting of the FlaxEngine.Object types into Boolean value (as simple validate check). From 8488183558b97f4e6ae8a322f0c41a4cf99065d5 Mon Sep 17 00:00:00 2001 From: Saas Date: Mon, 9 Mar 2026 18:29:56 +0100 Subject: [PATCH 08/19] don't show resize hints when connecting --- Source/Editor/Surface/ResizableSurfaceNode.cs | 4 ++-- Source/Editor/Surface/SurfaceComment.cs | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Source/Editor/Surface/ResizableSurfaceNode.cs b/Source/Editor/Surface/ResizableSurfaceNode.cs index 26c64c382..08f0afe5d 100644 --- a/Source/Editor/Surface/ResizableSurfaceNode.cs +++ b/Source/Editor/Surface/ResizableSurfaceNode.cs @@ -177,7 +177,7 @@ namespace FlaxEditor.Surface } // Update the cursor shape - if (_surface.resizeableNodeIndexInParent <= IndexInParent || IgnoreSurfaceIndex) + if ((_surface.resizeableNodeIndexInParent <= IndexInParent || IgnoreSurfaceIndex) && !_surface.IsConnecting) { if (!IgnoreSurfaceIndex) _surface.resizeableNodeIndexInParent = IndexInParent; @@ -329,7 +329,7 @@ namespace FlaxEditor.Surface { base.Draw(); - if (Surface.CanEdit && (ResizeBorderControl.IsResizing || ResizeBorderControl.IsMouseOverResizeBorder)) + if (Surface.CanEdit && !Surface.IsConnecting && (ResizeBorderControl.IsResizing || ResizeBorderControl.IsMouseOverResizeBorder)) Render2D.DrawRectangle(new Rectangle(Float2.Zero, Size), Style.Current.Foreground, 0.5f); } diff --git a/Source/Editor/Surface/SurfaceComment.cs b/Source/Editor/Surface/SurfaceComment.cs index 4966c83b3..a8f3849d5 100644 --- a/Source/Editor/Surface/SurfaceComment.cs +++ b/Source/Editor/Surface/SurfaceComment.cs @@ -190,7 +190,7 @@ namespace FlaxEditor.Surface Render2D.DrawSprite(style.Settings, _colorButtonRect, _colorButtonRect.Contains(_mousePosition) && Surface.CanEdit ? style.Foreground : style.ForegroundGrey); // Resize - if (ResizeBorderControl.IsResizing || ResizeBorderControl.IsMouseOverResizeBorder) + if ((ResizeBorderControl.IsResizing || ResizeBorderControl.IsMouseOverResizeBorder) && !Surface.IsConnecting) Render2D.DrawRectangle(new Rectangle(Float2.Zero, Size), Style.Current.Foreground, 0.5f); } From 5ba8cddd65d6d812447b36fc182b71bec612c981 Mon Sep 17 00:00:00 2001 From: Saas Date: Tue, 17 Mar 2026 19:57:03 +0100 Subject: [PATCH 09/19] improve resizing to behave more like expected --- Source/Editor/Surface/ResizableSurfaceNode.cs | 47 +++++++++---------- 1 file changed, 21 insertions(+), 26 deletions(-) diff --git a/Source/Editor/Surface/ResizableSurfaceNode.cs b/Source/Editor/Surface/ResizableSurfaceNode.cs index 08f0afe5d..2e684a59a 100644 --- a/Source/Editor/Surface/ResizableSurfaceNode.cs +++ b/Source/Editor/Surface/ResizableSurfaceNode.cs @@ -24,11 +24,12 @@ namespace FlaxEditor.Surface private const float BorderWidth = 15f; private readonly VisjectSurface _surface; - private Float2 _surfaceMouseLocation; + private Float2 _lastSurfaceMouseLoc; private Float2 startResizingSize; + private Float2 noClampedSize; /// - /// Wether to ignore the surface index in parent when updating the cursor type. Set to false for nodes that have order like . + /// Whether to ignore the surface index in parent when updating the cursor type. Set to false for nodes that have order like . /// internal bool IgnoreSurfaceIndex = true; @@ -94,16 +95,11 @@ namespace FlaxEditor.Surface Location = nodeLocation - new Float2(BorderWidth); } - private void UpdateSurfaceMouseLocation() - { - _surfaceMouseLocation = _surface.PointFromScreen(Input.MouseScreenPosition); - } - private void UpdateResizeFlags(Float2 mouseLocation) { var borderRect = Bounds with { Location = Float2.Zero }; bool onBorder = borderRect.Contains(mouseLocation); - // Check this the way we do because some resizeable nodes (like comments) have an implementation of `Control.ContainsPoint` + // Check this the way we do because some resizable nodes (like comments) have an implementation of `Control.ContainsPoint` // that does not check for the size you would think they have based on their visual appearance bool inNode = borderRect.MakeExpanded(-BorderWidth * 2f).Contains(mouseLocation); @@ -115,7 +111,7 @@ namespace FlaxEditor.Surface IsMouseOverResizeBorder = onBorder && !inNode; } - private Float2 GetControlDelta(Control control, ref Float2 start, ref Float2 end) + private Float2 GetControlDelta(Control control, Float2 start, Float2 end) { var pointOrigin = control.Parent ?? control; var startPos = pointOrigin.PointFromParent(ResizableNode, start); @@ -148,32 +144,30 @@ namespace FlaxEditor.Surface var resizeAxisPos = Float2.Clamp(ResizeDirection, Float2.Zero, Float2.One); var resizeAxisNeg = Float2.Clamp(-ResizeDirection, Float2.Zero, Float2.One); - var currentSurfaceMouse = _surface.PointFromScreen(Input.MouseScreenPosition); - var delta = currentSurfaceMouse - _surfaceMouseLocation; + var currentSurfaceMouseLoc = _surface.PointFromScreen(Input.MouseScreenPosition); + var delta = currentSurfaceMouseLoc - _lastSurfaceMouseLoc; - // TODO: scale/size snapping? + // TODO: Snapping delta *= resizeAxisAbs; + var moveLocation = currentSurfaceMouseLoc; + var uiControlDelta = GetControlDelta(this, _lastSurfaceMouseLoc, moveLocation); - var moveLocation = _surfaceMouseLocation + delta; - - var uiControlDelta = GetControlDelta(this, ref _surfaceMouseLocation, ref moveLocation); + // This ensures that the node is not resized below min size, but also keeps the resize behavior like expected (which just Max() -ing the value does not) var emptySize = ResizableNode.CalculateNodeSize(0, 0); + var minSize = ResizableNode.sizeMin; + noClampedSize = noClampedSize + uiControlDelta * resizeAxisPos - uiControlDelta * resizeAxisNeg; + if (noClampedSize.X < minSize.X && noClampedSize.X < ResizableNode.Size.X) + resizeAxisAbs.X = resizeAxisPos.X = resizeAxisNeg.X = 0f; + if (noClampedSize.Y < minSize.Y && noClampedSize.Y < ResizableNode.Size.Y) + resizeAxisAbs.Y = resizeAxisPos.Y = resizeAxisNeg.Y = 0f; - - // TODO: If resize is blocked by min size and the user tries to increase the size again, wait until !blocked by min size to apply delta again - // To do this, just record pos when starting to block by min size and if (cursorLocation > min) { ResizeAgain() } - - ResizableNode.Size += uiControlDelta * resizeAxisPos - uiControlDelta * resizeAxisNeg; - ResizableNode.Size = new Float2(Mathf.Max(ResizableNode.Size.X, ResizableNode.sizeMin.X), Mathf.Max(ResizableNode.Size.Y, ResizableNode.sizeMin.Y)); ResizableNode.Location += uiControlDelta * resizeAxisNeg; - ResizableNode.SizeValue = ResizableNode.Size - emptySize; - ResizableNode.SizeValue = new Float2(Mathf.Max(ResizableNode.SizeValue.X, ResizableNode.sizeMin.X), Mathf.Max(ResizableNode.SizeValue.Y, ResizableNode.sizeMin.Y)); ResizableNode.CalculateNodeSize(ResizableNode.Size.X, ResizableNode.Size.Y); - - UpdateSurfaceMouseLocation(); MatchResizableNode(ResizableNode.Size, ResizableNode.Location); + + _lastSurfaceMouseLoc = currentSurfaceMouseLoc; } // Update the cursor shape @@ -213,7 +207,8 @@ namespace FlaxEditor.Surface if (button == MouseButton.Left && IsMouseOverResizeBorder && !IsResizing) { // Start resizing - UpdateSurfaceMouseLocation(); + _lastSurfaceMouseLoc = _surface.PointFromScreen(Input.MouseScreenPosition); + noClampedSize = ResizableNode.Size; IsResizing = true; startResizingSize = ResizableNode.Size; StartMouseCapture(); From 1d18220971d873493813adb3c05009dfb49edd24 Mon Sep 17 00:00:00 2001 From: Saas Date: Tue, 17 Mar 2026 20:17:05 +0100 Subject: [PATCH 10/19] remove debug draw --- Source/Editor/Surface/ResizableSurfaceNode.cs | 6 ------ 1 file changed, 6 deletions(-) diff --git a/Source/Editor/Surface/ResizableSurfaceNode.cs b/Source/Editor/Surface/ResizableSurfaceNode.cs index 2e684a59a..8b06d2966 100644 --- a/Source/Editor/Surface/ResizableSurfaceNode.cs +++ b/Source/Editor/Surface/ResizableSurfaceNode.cs @@ -248,12 +248,6 @@ namespace FlaxEditor.Surface base.OnEndMouseCapture(); } - - /// - public override void Draw() - { - Render2D.DrawRectangle(Bounds with { Location = Float2.Zero }, Color.Green, 1f); - } } /// From 826b7841e6b95a59fc8f6f497d3bbc13d49b2567 Mon Sep 17 00:00:00 2001 From: Saas Date: Tue, 17 Mar 2026 20:22:56 +0100 Subject: [PATCH 11/19] actually resize the node lol --- Source/Editor/Surface/ResizableSurfaceNode.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/Source/Editor/Surface/ResizableSurfaceNode.cs b/Source/Editor/Surface/ResizableSurfaceNode.cs index 8b06d2966..edb6eac18 100644 --- a/Source/Editor/Surface/ResizableSurfaceNode.cs +++ b/Source/Editor/Surface/ResizableSurfaceNode.cs @@ -161,6 +161,7 @@ namespace FlaxEditor.Surface if (noClampedSize.Y < minSize.Y && noClampedSize.Y < ResizableNode.Size.Y) resizeAxisAbs.Y = resizeAxisPos.Y = resizeAxisNeg.Y = 0f; + ResizableNode.Size += uiControlDelta * resizeAxisPos - uiControlDelta * resizeAxisNeg; ResizableNode.Location += uiControlDelta * resizeAxisNeg; ResizableNode.SizeValue = ResizableNode.Size - emptySize; From 7bed68948b40845afa9bbeab4349cbafd68a9e18 Mon Sep 17 00:00:00 2001 From: Saas Date: Tue, 17 Mar 2026 20:28:55 +0100 Subject: [PATCH 12/19] no resizing in non editable Visject surfaces --- Source/Editor/Surface/ResizableSurfaceNode.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Source/Editor/Surface/ResizableSurfaceNode.cs b/Source/Editor/Surface/ResizableSurfaceNode.cs index edb6eac18..9d44b325b 100644 --- a/Source/Editor/Surface/ResizableSurfaceNode.cs +++ b/Source/Editor/Surface/ResizableSurfaceNode.cs @@ -138,7 +138,7 @@ namespace FlaxEditor.Surface { UpdateResizeFlags(location); } - else + else if (_surface.CanEdit) { var resizeAxisAbs = ResizeDirection.Absolute; var resizeAxisPos = Float2.Clamp(ResizeDirection, Float2.Zero, Float2.One); @@ -172,7 +172,7 @@ namespace FlaxEditor.Surface } // Update the cursor shape - if ((_surface.resizeableNodeIndexInParent <= IndexInParent || IgnoreSurfaceIndex) && !_surface.IsConnecting) + if ((_surface.resizeableNodeIndexInParent <= IndexInParent || IgnoreSurfaceIndex) && !_surface.IsConnecting && _surface.CanEdit) { if (!IgnoreSurfaceIndex) _surface.resizeableNodeIndexInParent = IndexInParent; From 7326cf65d8445daee79f5642c9c6d40965549b85 Mon Sep 17 00:00:00 2001 From: Andrei Gagua Date: Wed, 3 Jun 2026 18:49:42 +0300 Subject: [PATCH 13/19] Fix: Editor - use non-jittered projection for post-TAA overlay grid Add a managed `RenderView.GetOverlayProjection()` helper that returns the non-jittered projection once TAA has been resolved, and use it for editor overlay rendering paths. --- Source/Editor/Gizmo/GridGizmo.cs | 3 ++- Source/Engine/Graphics/RenderView.cs | 8 ++++++++ Source/Engine/UI/UICanvas.cs | 2 +- 3 files changed, 11 insertions(+), 2 deletions(-) diff --git a/Source/Editor/Gizmo/GridGizmo.cs b/Source/Editor/Gizmo/GridGizmo.cs index 71f20f8c2..37cbd20ab 100644 --- a/Source/Editor/Gizmo/GridGizmo.cs +++ b/Source/Editor/Gizmo/GridGizmo.cs @@ -113,7 +113,8 @@ namespace FlaxEditor.Gizmo if (cb != IntPtr.Zero) { var data = new Data(); - Matrix.Multiply(ref renderContext.View.View, ref renderContext.View.Projection, out var viewProjection); + var projection = renderContext.View.GetOverlayProjection(); + Matrix.Multiply(ref renderContext.View.View, ref projection, out var viewProjection); Matrix.Transpose(ref viewProjection, out data.ViewProjectionMatrix); data.ViewPos = renderContext.View.WorldPosition; data.GridColor = options.Viewport.ViewportGridColor; diff --git a/Source/Engine/Graphics/RenderView.cs b/Source/Engine/Graphics/RenderView.cs index b71b2d19b..66e3546ff 100644 --- a/Source/Engine/Graphics/RenderView.cs +++ b/Source/Engine/Graphics/RenderView.cs @@ -33,6 +33,14 @@ namespace FlaxEngine NonJitteredProjection = Projection; } + /// + /// Gets projection matrix for overlay geometry rendered after temporal anti-aliasing has been resolved. + /// + public Matrix GetOverlayProjection() + { + return IsTaaResolved ? NonJitteredProjection : Projection; + } + /// /// Initializes render view data. /// diff --git a/Source/Engine/UI/UICanvas.cs b/Source/Engine/UI/UICanvas.cs index 225213dba..a4cf2fd78 100644 --- a/Source/Engine/UI/UICanvas.cs +++ b/Source/Engine/UI/UICanvas.cs @@ -90,7 +90,7 @@ namespace FlaxEngine Matrix.Multiply(ref worldMatrix, ref renderContext.View.View, out Matrix viewMatrix); Matrix projectionMatrix = renderContext.View.Projection; if (worldSpace && (Canvas.RenderLocation == PostProcessEffectLocation.Default || Canvas.RenderLocation == PostProcessEffectLocation.AfterAntiAliasingPass)) - projectionMatrix = renderContext.View.NonJitteredProjection; // Fix TAA jittering when rendering UI in world after TAA resolve + projectionMatrix = renderContext.View.GetOverlayProjection(); // Fix TAA jittering when rendering UI in world after TAA resolve Matrix.Multiply(ref viewMatrix, ref projectionMatrix, out Matrix viewProjectionMatrix); // Pick a depth buffer From 0db92b473b3ebf32ace89e064deef3d3a8fe2b6b Mon Sep 17 00:00:00 2001 From: Andrei Gagua Date: Tue, 9 Jun 2026 23:06:58 +0300 Subject: [PATCH 14/19] Fix prefab Script track remapping in scene animations Store prefab object IDs for Script tracks authored from prefab objects and mark those tracks as prefab object references so SceneAnimationPlayer can remap them for prefab instances. --- .../Editor/GUI/Timeline/Tracks/ScriptTrack.cs | 63 ++++++++++++++++++- 1 file changed, 61 insertions(+), 2 deletions(-) diff --git a/Source/Editor/GUI/Timeline/Tracks/ScriptTrack.cs b/Source/Editor/GUI/Timeline/Tracks/ScriptTrack.cs index ee0bf5c1f..ae2e4e0c1 100644 --- a/Source/Editor/GUI/Timeline/Tracks/ScriptTrack.cs +++ b/Source/Editor/GUI/Timeline/Tracks/ScriptTrack.cs @@ -52,8 +52,67 @@ namespace FlaxEditor.GUI.Timeline.Tracks /// public Script Script { - get => FlaxEngine.Object.TryFind