From eee4e55cf0ee0dae898d38bddc0c49fdba0f9ba8 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Thu, 5 Jun 2025 22:26:45 +0200 Subject: [PATCH 01/37] Fix debug shapes change --- .../Physics/Colliders/CharacterController.cpp | 21 ++++++------------- 1 file changed, 6 insertions(+), 15 deletions(-) diff --git a/Source/Engine/Physics/Colliders/CharacterController.cpp b/Source/Engine/Physics/Colliders/CharacterController.cpp index 74c324bad..a874a9947 100644 --- a/Source/Engine/Physics/Colliders/CharacterController.cpp +++ b/Source/Engine/Physics/Colliders/CharacterController.cpp @@ -262,16 +262,16 @@ void CharacterController::OnDebugDrawSelected() Quaternion rotation = Quaternion::Euler(90, 0, 0); const Vector3 position = GetControllerPosition(); DEBUG_DRAW_WIRE_CAPSULE(position, rotation, _radius, _height, Color::GreenYellow, 0, false); - if (_contactOffset > 0) - DEBUG_DRAW_WIRE_CAPSULE(position, rotation, _radius - _contactOffset, _height, Color::Blue.AlphaMultiplied(0.4f), 0, false); -#if 1 - // More technical visuals debugging if (_controller) { + // Physics backend capsule shape float height, radius; GetControllerSize(height, radius); - Vector3 base = PhysicsBackend::GetControllerBasePosition(_controller); Vector3 pos = PhysicsBackend::GetControllerPosition(_controller); + DEBUG_DRAW_WIRE_CAPSULE(pos, rotation, radius, height, Color::Blue.AlphaMultiplied(0.2f), 0, false); +#if 0 + // More technical visuals debugging + Vector3 base = PhysicsBackend::GetControllerBasePosition(_controller); DEBUG_DRAW_WIRE_SPHERE(BoundingSphere(base, 5.0f), Color::Red, 0, false); DEBUG_DRAW_WIRE_SPHERE(BoundingSphere(pos, 4.0f), Color::Red, 0, false); DEBUG_DRAW_WIRE_SPHERE(BoundingSphere(pos + Vector3(0, height * 0.5f, 0), 2.0f), Color::Red, 0, false); @@ -279,17 +279,8 @@ void CharacterController::OnDebugDrawSelected() DEBUG_DRAW_WIRE_SPHERE(BoundingSphere(pos + Vector3(0, height * 0.5f, 0), radius), Color::Red.AlphaMultiplied(0.5f), 0, false); DEBUG_DRAW_WIRE_SPHERE(BoundingSphere(pos - Vector3(0, height * 0.5f, 0), radius), Color::Red.AlphaMultiplied(0.5f), 0, false); DEBUG_DRAW_WIRE_CYLINDER(pos, Quaternion::Identity, radius, height, Color::Red.AlphaMultiplied(0.2f), 0, false); - } - DEBUG_DRAW_WIRE_SPHERE(BoundingSphere(position, 3.0f), Color::GreenYellow, 0, false); -#else - if (_controller) - { - // Physics backend capsule shape - float height, radius; - GetControllerSize(height, radius); - DEBUG_DRAW_WIRE_CAPSULE(PhysicsBackend::GetControllerPosition(_controller), rotation, radius, height, Color::Blue.AlphaMultiplied(0.2f), 0, false); - } #endif + } // Base Collider::OnDebugDrawSelected(); From 1a77ba455273c0087d595968720549c1db8c933c Mon Sep 17 00:00:00 2001 From: Zode Date: Sat, 7 Jun 2025 13:15:39 +0300 Subject: [PATCH 02/37] Add node alignment formatting options to visject --- Source/Editor/Surface/NodeAlignmentType.cs | 43 +++++++++++++++++++ .../Surface/VisjectSurface.ContextMenu.cs | 23 +++++++++- .../Surface/VisjectSurface.Formatting.cs | 42 ++++++++++++++++++ 3 files changed, 106 insertions(+), 2 deletions(-) create mode 100644 Source/Editor/Surface/NodeAlignmentType.cs diff --git a/Source/Editor/Surface/NodeAlignmentType.cs b/Source/Editor/Surface/NodeAlignmentType.cs new file mode 100644 index 000000000..141235783 --- /dev/null +++ b/Source/Editor/Surface/NodeAlignmentType.cs @@ -0,0 +1,43 @@ +// Copyright (c) Wojciech Figat. All rights reserved. + +using FlaxEngine; + +namespace FlaxEditor.Surface +{ + /// + /// Node Alignment type + /// + [HideInEditor] + public enum NodeAlignmentType + { + /// + /// Align nodes vertically to top, matching top-most node + /// + Top, + + /// + /// Align nodes vertically to middle, using average of all nodes + /// + Middle, + + /// + /// Align nodes vertically to bottom, matching bottom-most node + /// + Bottom, + + /// + /// Align nodes horizontally to left, matching left-most node + /// + Left, + + /// + /// Align nodes horizontally to center, using average of all nodes + /// + Center, + + /// + /// Align nodes horizontally to right, matching right-most node + /// + Right, + } +} \ No newline at end of file diff --git a/Source/Editor/Surface/VisjectSurface.ContextMenu.cs b/Source/Editor/Surface/VisjectSurface.ContextMenu.cs index ee7dd33e5..ae836bb11 100644 --- a/Source/Editor/Surface/VisjectSurface.ContextMenu.cs +++ b/Source/Editor/Surface/VisjectSurface.ContextMenu.cs @@ -191,7 +191,14 @@ namespace FlaxEditor.Surface private ContextMenuButton _cmCopyButton; private ContextMenuButton _cmDuplicateButton; + private ContextMenuChildMenu _cmFormatNodesMenu; private ContextMenuButton _cmFormatNodesConnectionButton; + private ContextMenuButton _cmAlignNodesTopButton; + private ContextMenuButton _cmAlignNodesMiddleButton; + private ContextMenuButton _cmAlignNodesBottomButton; + private ContextMenuButton _cmAlignNodesLeftButton; + private ContextMenuButton _cmAlignNodesCenterButton; + private ContextMenuButton _cmAlignNodesRightButton; private ContextMenuButton _cmRemoveNodeConnectionsButton; private ContextMenuButton _cmRemoveBoxConnectionsButton; private readonly Float2 ContextMenuOffset = new Float2(5); @@ -399,8 +406,20 @@ namespace FlaxEditor.Surface } menu.AddSeparator(); - _cmFormatNodesConnectionButton = menu.AddButton("Format node(s)", () => { FormatGraph(SelectedNodes); }); - _cmFormatNodesConnectionButton.Enabled = CanEdit && HasNodesSelection; + _cmFormatNodesMenu = menu.AddChildMenu("Format node(s)"); + _cmFormatNodesMenu.Enabled = CanEdit && HasNodesSelection; + + _cmFormatNodesConnectionButton = _cmFormatNodesMenu.ContextMenu.AddButton("Auto format", () => { FormatGraph(SelectedNodes); }); + + _cmFormatNodesMenu.ContextMenu.AddSeparator(); + _cmAlignNodesTopButton = _cmFormatNodesMenu.ContextMenu.AddButton("Align top", () => { AlignNodes(SelectedNodes, NodeAlignmentType.Top); }); + _cmAlignNodesMiddleButton = _cmFormatNodesMenu.ContextMenu.AddButton("Align middle", () => { AlignNodes(SelectedNodes, NodeAlignmentType.Middle); }); + _cmAlignNodesBottomButton = _cmFormatNodesMenu.ContextMenu.AddButton("Align bottom", () => { AlignNodes(SelectedNodes, NodeAlignmentType.Bottom); }); + + _cmFormatNodesMenu.ContextMenu.AddSeparator(); + _cmAlignNodesLeftButton = _cmFormatNodesMenu.ContextMenu.AddButton("Align left", () => { AlignNodes(SelectedNodes, NodeAlignmentType.Left); }); + _cmAlignNodesCenterButton = _cmFormatNodesMenu.ContextMenu.AddButton("Align center", () => { AlignNodes(SelectedNodes, NodeAlignmentType.Center); }); + _cmAlignNodesRightButton = _cmFormatNodesMenu.ContextMenu.AddButton("Align right", () => { AlignNodes(SelectedNodes, NodeAlignmentType.Right); }); _cmRemoveNodeConnectionsButton = menu.AddButton("Remove all connections to that node(s)", () => { diff --git a/Source/Editor/Surface/VisjectSurface.Formatting.cs b/Source/Editor/Surface/VisjectSurface.Formatting.cs index c8819a559..6b942f4a1 100644 --- a/Source/Editor/Surface/VisjectSurface.Formatting.cs +++ b/Source/Editor/Surface/VisjectSurface.Formatting.cs @@ -282,5 +282,47 @@ namespace FlaxEditor.Surface return maxOffset; } + + /// + /// Align given nodes on a graph using the given alignment type. + /// Ignores any potential overlap. + /// + /// List of nodes + /// Alignemnt type + public void AlignNodes(List nodes, NodeAlignmentType alignmentType) + { + if(nodes.Count <= 1) + return; + + var undoActions = new List(); + var boundingBox = GetNodesBounds(nodes); + for(int i = 0; i < nodes.Count; i++) + { + var centerY = boundingBox.Center.Y - (nodes[i].Height / 2); + var centerX = boundingBox.Center.X - (nodes[i].Width / 2); + + var newLocation = alignmentType switch + { + NodeAlignmentType.Top => new Float2(nodes[i].Location.X, boundingBox.Top), + NodeAlignmentType.Middle => new Float2(nodes[i].Location.X, centerY), + NodeAlignmentType.Bottom => new Float2(nodes[i].Location.X, boundingBox.Bottom - nodes[i].Height), + + NodeAlignmentType.Left => new Float2(boundingBox.Left, nodes[i].Location.Y), + NodeAlignmentType.Center => new Float2(centerX, nodes[i].Location.Y), + NodeAlignmentType.Right => new Float2(boundingBox.Right - nodes[i].Width, nodes[i].Location.Y), + + _ => throw new NotImplementedException($"Unsupported node alignment type: {alignmentType}"), + }; + + var locationDelta = newLocation - nodes[i].Location; + nodes[i].Location = newLocation; + + if(Undo != null) + undoActions.Add(new MoveNodesAction(Context, new[] { nodes[i].ID }, locationDelta)); + } + + MarkAsEdited(false); + Undo?.AddAction(new MultiUndoAction(undoActions, $"Align nodes ({alignmentType})")); + } } } From 6ee3b232619b7fd0cd5bd6a93b8546f729b15918 Mon Sep 17 00:00:00 2001 From: Zode Date: Sat, 7 Jun 2025 16:57:28 +0300 Subject: [PATCH 03/37] Add highlighting to layers matrix editor to improve UX --- .../Dedicated/LayersMatrixEditor.cs | 79 ++++++++++++++++--- 1 file changed, 70 insertions(+), 9 deletions(-) diff --git a/Source/Editor/CustomEditors/Dedicated/LayersMatrixEditor.cs b/Source/Editor/CustomEditors/Dedicated/LayersMatrixEditor.cs index 4b41db297..f853ccef7 100644 --- a/Source/Editor/CustomEditors/Dedicated/LayersMatrixEditor.cs +++ b/Source/Editor/CustomEditors/Dedicated/LayersMatrixEditor.cs @@ -16,6 +16,11 @@ namespace FlaxEditor.CustomEditors.Dedicated { private int _layersCount; private List _checkBoxes; + private VerticalPanel _upperRightCell; + private VerticalPanel _bottomLeftCell; + private UniformGridPanel _grid; + private Border _horizontalHighlight; + private Border _verticalHighlight; /// public override DisplayStyle Style => DisplayStyle.InlineIntoParent; @@ -37,12 +42,29 @@ namespace FlaxEditor.CustomEditors.Dedicated Parent = panel, }; + var style = FlaxEngine.GUI.Style.Current; + _horizontalHighlight = new Border() + { + Parent = panel, + BorderColor = style.Foreground, + BorderWidth = 1.0f, + Visible = false, + }; + + _verticalHighlight = new Border() + { + Parent = panel, + BorderColor = style.Foreground, + BorderWidth = 1.0f, + Visible = false, + }; + var upperLeftCell = new Label { Parent = gridPanel, }; - var upperRightCell = new VerticalPanel + _upperRightCell = new VerticalPanel { ClipChildren = false, Pivot = new Float2(0.00001f, 0.0f), @@ -54,7 +76,7 @@ namespace FlaxEditor.CustomEditors.Dedicated Parent = gridPanel, }; - var bottomLeftCell = new VerticalPanel + _bottomLeftCell = new VerticalPanel { Pivot = Float2.Zero, Spacing = 0, @@ -63,7 +85,7 @@ namespace FlaxEditor.CustomEditors.Dedicated Parent = gridPanel, }; - var grid = new UniformGridPanel(0) + _grid = new UniformGridPanel(0) { SlotsHorizontally = layersCount, SlotsVertically = layersCount, @@ -74,13 +96,13 @@ namespace FlaxEditor.CustomEditors.Dedicated int layerIndex = 0; for (; layerIndex < layerNames.Length; layerIndex++) { - upperRightCell.AddChild(new Label + _upperRightCell.AddChild(new Label { Height = labelsHeight, Text = layerNames[layerNames.Length - layerIndex - 1], HorizontalAlignment = TextAlignment.Near, }); - bottomLeftCell.AddChild(new Label + _bottomLeftCell.AddChild(new Label { Height = labelsHeight, Text = layerNames[layerIndex], @@ -90,13 +112,13 @@ namespace FlaxEditor.CustomEditors.Dedicated for (; layerIndex < layersCount; layerIndex++) { string name = "Layer " + layerIndex; - upperRightCell.AddChild(new Label + _upperRightCell.AddChild(new Label { Height = labelsHeight, Text = name, HorizontalAlignment = TextAlignment.Near, }); - bottomLeftCell.AddChild(new Label + _bottomLeftCell.AddChild(new Label { Height = labelsHeight, Text = name, @@ -118,7 +140,7 @@ namespace FlaxEditor.CustomEditors.Dedicated var box = new CheckBox(0, 0, true) { Tag = new Float2(_layersCount - column - 1, row), - Parent = grid, + Parent = _grid, Checked = GetBit(column, row), }; box.StateChanged += OnCheckBoxChanged; @@ -126,7 +148,7 @@ namespace FlaxEditor.CustomEditors.Dedicated } for (; column < layersCount; column++) { - grid.AddChild(new Label()); + _grid.AddChild(new Label()); } } } @@ -141,6 +163,12 @@ namespace FlaxEditor.CustomEditors.Dedicated /// public override void Refresh() { + _horizontalHighlight.Visible = false; + _verticalHighlight.Visible = false; + int selectedColumn = -1; + int selectedRow = -1; + var style = FlaxEngine.GUI.Style.Current; + // Sync check boxes for (int i = 0; i < _checkBoxes.Count; i++) { @@ -148,6 +176,39 @@ namespace FlaxEditor.CustomEditors.Dedicated int column = (int)((Float2)box.Tag).X; int row = (int)((Float2)box.Tag).Y; box.Checked = GetBit(column, row); + box.ImageColor = style.BorderSelected * 1.2f; + + if(box.IsMouseOver) + { + selectedColumn = column; + selectedRow = row; + + _horizontalHighlight.X = _grid.X - _bottomLeftCell.Width; + _horizontalHighlight.Y = _grid.Y + box.Y; + _horizontalHighlight.Width = _bottomLeftCell.Width + box.Width + box.X; + _horizontalHighlight.Height = box.Height; + _horizontalHighlight.Visible = true; + + _verticalHighlight.X = _grid.X + box.X; + _verticalHighlight.Y = _grid.Y - _upperRightCell.Height; + _verticalHighlight.Width = box.Width; + _verticalHighlight.Height = _upperRightCell.Height + box.Height + box.Y; + _verticalHighlight.Visible = true; + } + } + + if(selectedColumn > -1 && selectedRow > -1) + { + for (int i = 0; i < _checkBoxes.Count; i++) + { + var box = _checkBoxes[i]; + int column = (int)((Float2)box.Tag).X; + int row = (int)((Float2)box.Tag).Y; + if(column == selectedColumn || row == selectedRow) + continue; + + box.ImageColor = style.BorderSelected * 0.75f; + } } } From 53e3cee1967ddbeb7b7fa8f94b7d60202da15a11 Mon Sep 17 00:00:00 2001 From: Zode Date: Sat, 7 Jun 2025 17:15:54 +0300 Subject: [PATCH 04/37] Scroll selected to view when emptying out search box --- Source/Editor/Windows/SceneTreeWindow.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/Source/Editor/Windows/SceneTreeWindow.cs b/Source/Editor/Windows/SceneTreeWindow.cs index 705976e6e..78aa123ea 100644 --- a/Source/Editor/Windows/SceneTreeWindow.cs +++ b/Source/Editor/Windows/SceneTreeWindow.cs @@ -144,6 +144,7 @@ namespace FlaxEditor.Windows _tree.UnlockChildrenRecursive(); PerformLayout(); PerformLayout(); + ScrollToSelectedNode(); } private void Spawn(Type type) From cce042045e8ebc7d869003f7ccfe525a598b0677 Mon Sep 17 00:00:00 2001 From: xxSeys1 Date: Sat, 7 Jun 2025 17:34:01 +0200 Subject: [PATCH 05/37] wrap scrolling items with arrow keys and simplify scrolling logic --- Source/Editor/GUI/ItemsListContextMenu.cs | 51 +++++++++-------------- 1 file changed, 19 insertions(+), 32 deletions(-) diff --git a/Source/Editor/GUI/ItemsListContextMenu.cs b/Source/Editor/GUI/ItemsListContextMenu.cs index 82699e55c..58f8c2eb4 100644 --- a/Source/Editor/GUI/ItemsListContextMenu.cs +++ b/Source/Editor/GUI/ItemsListContextMenu.cs @@ -563,8 +563,17 @@ namespace FlaxEditor.GUI case KeyboardKeys.Escape: Hide(); return true; + case KeyboardKeys.Backspace: + // Alow the user to quickly focus the searchbar + if (_searchBox != null && !_searchBox.IsFocused) + { + _searchBox.Focus(); + _searchBox.SelectAll(); + return true; + } + break; case KeyboardKeys.ArrowDown: - { + case KeyboardKeys.ArrowUp: if (RootWindow.FocusedControl == null) { // Focus search box if nothing is focused @@ -572,39 +581,17 @@ namespace FlaxEditor.GUI return true; } - // Focus the first visible item or then next one + // Get the next item var items = GetVisibleItems(); var focusedIndex = items.IndexOf(focusedItem); - if (focusedIndex == -1) - focusedIndex = -1; - if (focusedIndex + 1 < items.Count) - { - var item = items[focusedIndex + 1]; - item.Focus(); - _scrollPanel.ScrollViewTo(item); - return true; - } - break; - } - case KeyboardKeys.ArrowUp: - if (focusedItem != null) - { - // Focus the previous visible item or the search box - var items = GetVisibleItems(); - var focusedIndex = items.IndexOf(focusedItem); - if (focusedIndex == 0) - { - _searchBox?.Focus(); - } - else if (focusedIndex > 0) - { - var item = items[focusedIndex - 1]; - item.Focus(); - _scrollPanel.ScrollViewTo(item); - return true; - } - } - break; + int delta = key == KeyboardKeys.ArrowDown ? -1 : 1; + int nextIndex = Mathf.Wrap(focusedIndex - delta, 0, items.Count - 1); + var nextItem = items[nextIndex]; + + // Focus the next item + nextItem.Focus(); + _scrollPanel.ScrollViewTo(nextItem); + return true; case KeyboardKeys.Return: if (focusedItem != null) { From 85fd1389dbb7698ec5defb476c4273fe417f8f35 Mon Sep 17 00:00:00 2001 From: xxSeys1 Date: Sat, 7 Jun 2025 18:17:40 +0200 Subject: [PATCH 06/37] clear content panel search when selecting asset picker asset --- Source/Editor/GUI/AssetPicker.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Source/Editor/GUI/AssetPicker.cs b/Source/Editor/GUI/AssetPicker.cs index b3690e754..bf04aa068 100644 --- a/Source/Editor/GUI/AssetPicker.cs +++ b/Source/Editor/GUI/AssetPicker.cs @@ -299,6 +299,7 @@ namespace FlaxEditor.GUI { // Select asset Editor.Instance.Windows.ContentWin.Select(Validator.SelectedItem); + Editor.Instance.Windows.ContentWin.ClearItemsSearch(); } } else if (Button1Rect.Contains(location)) @@ -312,6 +313,7 @@ namespace FlaxEditor.GUI { // Select asset Editor.Instance.Windows.ContentWin.Select(Validator.SelectedItem); + Editor.Instance.Windows.ContentWin.ClearItemsSearch(); } else if (Button3Rect.Contains(location)) { From 1d6306761476fbfc7f2ca830e9c0422a4c067877 Mon Sep 17 00:00:00 2001 From: Zode Date: Sat, 7 Jun 2025 21:04:59 +0300 Subject: [PATCH 07/37] Add ability to do additive and subtractive selections in visject surfaces using ctrl and shift during selection. --- Source/Editor/Surface/VisjectSurface.Input.cs | 68 ++++++++++++++++--- Source/Editor/Surface/VisjectSurface.cs | 12 ++++ 2 files changed, 69 insertions(+), 11 deletions(-) diff --git a/Source/Editor/Surface/VisjectSurface.Input.cs b/Source/Editor/Surface/VisjectSurface.Input.cs index a874db681..09df195eb 100644 --- a/Source/Editor/Surface/VisjectSurface.Input.cs +++ b/Source/Editor/Surface/VisjectSurface.Input.cs @@ -27,6 +27,7 @@ namespace FlaxEditor.Surface private Float2 _movingNodesDelta; private Float2 _gridRoundingDelta; private HashSet _movingNodes; + private HashSet _temporarySelectedNodes; private readonly Stack _inputBrackets = new Stack(); private class InputBracket @@ -130,13 +131,34 @@ namespace FlaxEditor.Surface if (_rootControl.Children[i] is SurfaceControl control) { var select = control.IsSelectionIntersecting(ref selectionRect); - if (select != control.IsSelected) + + if (Root.GetKey(KeyboardKeys.Shift)) { - control.IsSelected = select; - selectionChanged = true; + if (select == control.IsSelected && _temporarySelectedNodes.Contains(control)) + { + control.IsSelected = !select; + selectionChanged = true; + } + } + else if (Root.GetKey(KeyboardKeys.Control)) + { + if (select != control.IsSelected && !_temporarySelectedNodes.Contains(control)) + { + control.IsSelected = select; + selectionChanged = true; + } + } + else + { + if (select != control.IsSelected) + { + control.IsSelected = select; + selectionChanged = true; + } } } } + if (selectionChanged) SelectionChanged?.Invoke(); } @@ -461,6 +483,19 @@ namespace FlaxEditor.Surface // Cache data _isMovingSelection = false; _mousePos = location; + if(_temporarySelectedNodes == null) + _temporarySelectedNodes = new HashSet(); + else + _temporarySelectedNodes.Clear(); + + for (int i = 0; i < _rootControl.Children.Count; i++) + { + if (_rootControl.Children[i] is SurfaceNode node && node.IsSelected) + { + _temporarySelectedNodes.Add(node); + } + } + if (button == MouseButton.Left) { _leftMouseDown = true; @@ -488,9 +523,11 @@ namespace FlaxEditor.Surface // Check if user is pressing control if (Root.GetKey(KeyboardKeys.Control)) { - // Add/remove from selection - controlUnderMouse.IsSelected = !controlUnderMouse.IsSelected; - SelectionChanged?.Invoke(); + AddToSelection(controlUnderMouse); + } + else if (Root.GetKey(KeyboardKeys.Shift)) + { + RemoveFromSelection(controlUnderMouse); } // Check if node isn't selected else if (!controlUnderMouse.IsSelected) @@ -500,10 +537,14 @@ namespace FlaxEditor.Surface } // Start moving selected nodes - StartMouseCapture(); - _movingSelectionViewPos = _rootControl.Location; - _movingNodesDelta = Float2.Zero; - OnGetNodesToMove(); + if (!Root.GetKey(KeyboardKeys.Shift)) + { + StartMouseCapture(); + _movingSelectionViewPos = _rootControl.Location; + _movingNodesDelta = Float2.Zero; + OnGetNodesToMove(); + } + Focus(); return true; } @@ -515,7 +556,12 @@ namespace FlaxEditor.Surface { // Start selecting or commenting StartMouseCapture(); - ClearSelection(); + + if (!Root.GetKey(KeyboardKeys.Control) && !Root.GetKey(KeyboardKeys.Shift)) + { + ClearSelection(); + } + Focus(); return true; } diff --git a/Source/Editor/Surface/VisjectSurface.cs b/Source/Editor/Surface/VisjectSurface.cs index faecebbd3..69bd276d2 100644 --- a/Source/Editor/Surface/VisjectSurface.cs +++ b/Source/Editor/Surface/VisjectSurface.cs @@ -710,6 +710,18 @@ namespace FlaxEditor.Surface SelectionChanged?.Invoke(); } + /// + /// Removes the specified control from the selection. + /// + /// The control. + public void RemoveFromSelection(SurfaceControl control) + { + if (!control.IsSelected) + return; + control.IsSelected = false; + SelectionChanged?.Invoke(); + } + /// /// Selects the specified control. /// From 74000fa76622597b4183bd50116c6b848e2d7363 Mon Sep 17 00:00:00 2001 From: Zode Date: Sat, 7 Jun 2025 22:53:07 +0300 Subject: [PATCH 08/37] Expand tree if necessary, so the selected node will be shown --- Source/Editor/Windows/SceneTreeWindow.cs | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/Source/Editor/Windows/SceneTreeWindow.cs b/Source/Editor/Windows/SceneTreeWindow.cs index 78aa123ea..8f06008a5 100644 --- a/Source/Editor/Windows/SceneTreeWindow.cs +++ b/Source/Editor/Windows/SceneTreeWindow.cs @@ -142,9 +142,21 @@ namespace FlaxEditor.Windows root.TreeNode.UpdateFilter(query); _tree.UnlockChildrenRecursive(); + + var nodeSelection = _tree.Selection; + if(nodeSelection.Count != 0) + { + var node = nodeSelection[nodeSelection.Count - 1]; + node.Expand(true); + } + PerformLayout(); PerformLayout(); - ScrollToSelectedNode(); + + if(nodeSelection.Count != 0) + { + ScrollToSelectedNode(); + } } private void Spawn(Type type) From 568719b615db6e7a6998c73ac18805328b0be215 Mon Sep 17 00:00:00 2001 From: Zode Date: Sat, 7 Jun 2025 23:21:41 +0300 Subject: [PATCH 09/37] Fix scroll issue caused by tree's defered layout update --- Source/Editor/Windows/SceneTreeWindow.cs | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/Source/Editor/Windows/SceneTreeWindow.cs b/Source/Editor/Windows/SceneTreeWindow.cs index 8f06008a5..20cfa3584 100644 --- a/Source/Editor/Windows/SceneTreeWindow.cs +++ b/Source/Editor/Windows/SceneTreeWindow.cs @@ -34,6 +34,7 @@ namespace FlaxEditor.Windows private DragScriptItems _dragScriptItems; private DragHandlers _dragHandlers; private bool _isDropping = false; + private bool _forceScrollNodeToView = false; /// /// Scene tree panel. @@ -148,13 +149,21 @@ namespace FlaxEditor.Windows { var node = nodeSelection[nodeSelection.Count - 1]; node.Expand(true); + _forceScrollNodeToView = true; } PerformLayout(); PerformLayout(); + } - if(nodeSelection.Count != 0) + /// + public override void Update(float deltaTime) + { + base.Update(deltaTime); + + if(_tree.Selection.Count != 0 && _forceScrollNodeToView) { + _forceScrollNodeToView = false; ScrollToSelectedNode(); } } From 1fa83639c2f1e729c918b4ccd1a181e5f26b0201 Mon Sep 17 00:00:00 2001 From: Zode Date: Sun, 8 Jun 2025 00:38:59 +0300 Subject: [PATCH 10/37] Fix update order inconsistencies between machines by exposing an action for when defered layout happens. --- Source/Editor/GUI/Tree/Tree.cs | 6 ++++++ Source/Editor/Windows/SceneTreeWindow.cs | 19 +++++++------------ 2 files changed, 13 insertions(+), 12 deletions(-) diff --git a/Source/Editor/GUI/Tree/Tree.cs b/Source/Editor/GUI/Tree/Tree.cs index e36f0ccd5..3e1453f03 100644 --- a/Source/Editor/GUI/Tree/Tree.cs +++ b/Source/Editor/GUI/Tree/Tree.cs @@ -73,6 +73,11 @@ namespace FlaxEditor.GUI.Tree /// public bool DrawRootTreeLine = true; + /// + /// Occurs when the defered layouting happens + /// + public event Action OnDeferedLayout; + /// /// Gets or sets the margin for the child tree nodes. /// @@ -375,6 +380,7 @@ namespace FlaxEditor.GUI.Tree if (_deferLayoutUpdate) { base.PerformLayout(); + OnDeferedLayout?.Invoke(); _deferLayoutUpdate = false; } diff --git a/Source/Editor/Windows/SceneTreeWindow.cs b/Source/Editor/Windows/SceneTreeWindow.cs index 20cfa3584..9175a660b 100644 --- a/Source/Editor/Windows/SceneTreeWindow.cs +++ b/Source/Editor/Windows/SceneTreeWindow.cs @@ -92,6 +92,13 @@ namespace FlaxEditor.Windows _tree.SelectedChanged += Tree_OnSelectedChanged; _tree.RightClick += OnTreeRightClick; _tree.Parent = _sceneTreePanel; + _tree.OnDeferedLayout += () => { + if(_tree.Selection.Count != 0 && _forceScrollNodeToView) + { + _forceScrollNodeToView = false; + ScrollToSelectedNode(); + } + }; headerPanel.Parent = this; // Setup input actions @@ -156,18 +163,6 @@ namespace FlaxEditor.Windows PerformLayout(); } - /// - public override void Update(float deltaTime) - { - base.Update(deltaTime); - - if(_tree.Selection.Count != 0 && _forceScrollNodeToView) - { - _forceScrollNodeToView = false; - ScrollToSelectedNode(); - } - } - private void Spawn(Type type) { // Create actor From ecd5559aada8b76b5508254232ee2f5ee36f82aa Mon Sep 17 00:00:00 2001 From: Zode Date: Sun, 8 Jun 2025 00:41:02 +0300 Subject: [PATCH 11/37] Clean up a bit code after moving it around. --- Source/Editor/Windows/SceneTreeWindow.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Source/Editor/Windows/SceneTreeWindow.cs b/Source/Editor/Windows/SceneTreeWindow.cs index 9175a660b..620300485 100644 --- a/Source/Editor/Windows/SceneTreeWindow.cs +++ b/Source/Editor/Windows/SceneTreeWindow.cs @@ -93,12 +93,13 @@ namespace FlaxEditor.Windows _tree.RightClick += OnTreeRightClick; _tree.Parent = _sceneTreePanel; _tree.OnDeferedLayout += () => { - if(_tree.Selection.Count != 0 && _forceScrollNodeToView) + if(_forceScrollNodeToView) { _forceScrollNodeToView = false; ScrollToSelectedNode(); } }; + headerPanel.Parent = this; // Setup input actions From f1945552ab4bff1a0cd083ee143101f7ebd47aa9 Mon Sep 17 00:00:00 2001 From: Zode Date: Sun, 8 Jun 2025 02:42:28 +0300 Subject: [PATCH 12/37] Add horizontal and vertical distribution --- .../Surface/VisjectSurface.ContextMenu.cs | 6 ++ .../Surface/VisjectSurface.Formatting.cs | 75 +++++++++++++++++++ 2 files changed, 81 insertions(+) diff --git a/Source/Editor/Surface/VisjectSurface.ContextMenu.cs b/Source/Editor/Surface/VisjectSurface.ContextMenu.cs index ae836bb11..98508046d 100644 --- a/Source/Editor/Surface/VisjectSurface.ContextMenu.cs +++ b/Source/Editor/Surface/VisjectSurface.ContextMenu.cs @@ -199,6 +199,8 @@ namespace FlaxEditor.Surface private ContextMenuButton _cmAlignNodesLeftButton; private ContextMenuButton _cmAlignNodesCenterButton; private ContextMenuButton _cmAlignNodesRightButton; + private ContextMenuButton _cmDistributeNodesHorizontallyButton; + private ContextMenuButton _cmDistributeNodesVerticallyButton; private ContextMenuButton _cmRemoveNodeConnectionsButton; private ContextMenuButton _cmRemoveBoxConnectionsButton; private readonly Float2 ContextMenuOffset = new Float2(5); @@ -421,6 +423,10 @@ namespace FlaxEditor.Surface _cmAlignNodesCenterButton = _cmFormatNodesMenu.ContextMenu.AddButton("Align center", () => { AlignNodes(SelectedNodes, NodeAlignmentType.Center); }); _cmAlignNodesRightButton = _cmFormatNodesMenu.ContextMenu.AddButton("Align right", () => { AlignNodes(SelectedNodes, NodeAlignmentType.Right); }); + _cmFormatNodesMenu.ContextMenu.AddSeparator(); + _cmDistributeNodesHorizontallyButton = _cmFormatNodesMenu.ContextMenu.AddButton("Distribute horizontally", () => { DistributeNodes(SelectedNodes, false); }); + _cmDistributeNodesVerticallyButton = _cmFormatNodesMenu.ContextMenu.AddButton("Distribute vertically", () => { DistributeNodes(SelectedNodes, true); }); + _cmRemoveNodeConnectionsButton = menu.AddButton("Remove all connections to that node(s)", () => { var nodes = ((List)menu.Tag); diff --git a/Source/Editor/Surface/VisjectSurface.Formatting.cs b/Source/Editor/Surface/VisjectSurface.Formatting.cs index 6b942f4a1..2ff48b290 100644 --- a/Source/Editor/Surface/VisjectSurface.Formatting.cs +++ b/Source/Editor/Surface/VisjectSurface.Formatting.cs @@ -324,5 +324,80 @@ namespace FlaxEditor.Surface MarkAsEdited(false); Undo?.AddAction(new MultiUndoAction(undoActions, $"Align nodes ({alignmentType})")); } + + /// + /// Distribute the given nodes as equally as possible inside the bounding box, if no fit can be done it will use a default pad of 10 pixels between nodes. + /// + /// List of nodes + /// If false will be done horizontally, if true will be done vertically + public void DistributeNodes(List nodes, bool vertically) + { + if(nodes.Count <= 1) + return; + + var undoActions = new List(); + var boundingBox = GetNodesBounds(nodes); + float padding = 10; + float totalSize = 0; + for (int i = 0; i < nodes.Count; i++) + { + if (vertically) + { + totalSize += nodes[i].Height; + } + else + { + totalSize += nodes[i].Width; + } + } + + if(vertically) + { + nodes.Sort((leftValue, rightValue) => { return leftValue.Y.CompareTo(rightValue.Y); }); + + float position = boundingBox.Top; + if(totalSize < boundingBox.Height) + { + padding = (boundingBox.Height - totalSize) / nodes.Count; + } + + for(int i = 0; i < nodes.Count; i++) + { + var newLocation = new Float2(nodes[i].X, position); + var locationDelta = newLocation - nodes[i].Location; + nodes[i].Location = newLocation; + + position += nodes[i].Height + padding; + + if (Undo != null) + undoActions.Add(new MoveNodesAction(Context, new[] { nodes[i].ID }, locationDelta)); + } + } + else + { + nodes.Sort((leftValue, rightValue) => { return leftValue.X.CompareTo(rightValue.X); }); + + float position = boundingBox.Left; + if(totalSize < boundingBox.Width) + { + padding = (boundingBox.Width - totalSize) / nodes.Count; + } + + for(int i = 0; i < nodes.Count; i++) + { + var newLocation = new Float2(position, nodes[i].Y); + var locationDelta = newLocation - nodes[i].Location; + nodes[i].Location = newLocation; + + position += nodes[i].Width + padding; + + if (Undo != null) + undoActions.Add(new MoveNodesAction(Context, new[] { nodes[i].ID }, locationDelta)); + } + } + + MarkAsEdited(false); + Undo?.AddAction(new MultiUndoAction(undoActions, vertically ? "Distribute nodes vertically" : "Distribute nodes horizontally")); + } } } From 9c9d560ce568c1a02afb557def492673c56f939d Mon Sep 17 00:00:00 2001 From: Zode Date: Sun, 8 Jun 2025 03:32:51 +0300 Subject: [PATCH 13/37] Add hotkeys to visject formatting --- Source/Editor/Options/InputOptions.cs | 40 +++++++++++++++++++ .../Surface/VisjectSurface.ContextMenu.cs | 18 ++++----- Source/Editor/Surface/VisjectSurface.cs | 9 +++++ 3 files changed, 58 insertions(+), 9 deletions(-) diff --git a/Source/Editor/Options/InputOptions.cs b/Source/Editor/Options/InputOptions.cs index ff7971667..4683284b8 100644 --- a/Source/Editor/Options/InputOptions.cs +++ b/Source/Editor/Options/InputOptions.cs @@ -647,5 +647,45 @@ namespace FlaxEditor.Options public InputBinding VisualScriptDebuggerWindow = new InputBinding(KeyboardKeys.None); #endregion + + #region Node editors + + [DefaultValue(typeof(InputBinding), "Shift+W")] + [EditorDisplay("Node editors"), EditorOrder(4500)] + public InputBinding NodesAlignTop = new InputBinding(KeyboardKeys.W, KeyboardKeys.Shift); + + [DefaultValue(typeof(InputBinding), "Shift+A")] + [EditorDisplay("Node editors"), EditorOrder(4510)] + public InputBinding NodesAlignLeft = new InputBinding(KeyboardKeys.A, KeyboardKeys.Shift); + + [DefaultValue(typeof(InputBinding), "Shift+S")] + [EditorDisplay("Node editors"), EditorOrder(4520)] + public InputBinding NodesAlignBottom = new InputBinding(KeyboardKeys.S, KeyboardKeys.Shift); + + [DefaultValue(typeof(InputBinding), "Shift+D")] + [EditorDisplay("Node editors"), EditorOrder(4530)] + public InputBinding NodesAlignRight = new InputBinding(KeyboardKeys.D, KeyboardKeys.Shift); + + [DefaultValue(typeof(InputBinding), "Alt+Shift+W")] + [EditorDisplay("Node editors"), EditorOrder(4540)] + public InputBinding NodesAlignMiddle = new InputBinding(KeyboardKeys.W, KeyboardKeys.Shift, KeyboardKeys.Alt); + + [DefaultValue(typeof(InputBinding), "Alt+Shift+S")] + [EditorDisplay("Node editors"), EditorOrder(4550)] + public InputBinding NodesAlignCenter = new InputBinding(KeyboardKeys.S, KeyboardKeys.Shift, KeyboardKeys.Alt); + + [DefaultValue(typeof(InputBinding), "Q")] + [EditorDisplay("Node editors"), EditorOrder(4560)] + public InputBinding NodesAutoFormat = new InputBinding(KeyboardKeys.Q); + + [DefaultValue(typeof(InputBinding), "None")] + [EditorDisplay("Node editors"), EditorOrder(4570)] + public InputBinding NodesDistributeHorizontal = new InputBinding(KeyboardKeys.None); + + [DefaultValue(typeof(InputBinding), "None")] + [EditorDisplay("Node editors"), EditorOrder(4580)] + public InputBinding NodesDistributeVertical = new InputBinding(KeyboardKeys.None); + + #endregion } } diff --git a/Source/Editor/Surface/VisjectSurface.ContextMenu.cs b/Source/Editor/Surface/VisjectSurface.ContextMenu.cs index 98508046d..84055aaf0 100644 --- a/Source/Editor/Surface/VisjectSurface.ContextMenu.cs +++ b/Source/Editor/Surface/VisjectSurface.ContextMenu.cs @@ -411,21 +411,21 @@ namespace FlaxEditor.Surface _cmFormatNodesMenu = menu.AddChildMenu("Format node(s)"); _cmFormatNodesMenu.Enabled = CanEdit && HasNodesSelection; - _cmFormatNodesConnectionButton = _cmFormatNodesMenu.ContextMenu.AddButton("Auto format", () => { FormatGraph(SelectedNodes); }); + _cmFormatNodesConnectionButton = _cmFormatNodesMenu.ContextMenu.AddButton("Auto format", Editor.Instance.Options.Options.Input.NodesAutoFormat, () => { FormatGraph(SelectedNodes); }); _cmFormatNodesMenu.ContextMenu.AddSeparator(); - _cmAlignNodesTopButton = _cmFormatNodesMenu.ContextMenu.AddButton("Align top", () => { AlignNodes(SelectedNodes, NodeAlignmentType.Top); }); - _cmAlignNodesMiddleButton = _cmFormatNodesMenu.ContextMenu.AddButton("Align middle", () => { AlignNodes(SelectedNodes, NodeAlignmentType.Middle); }); - _cmAlignNodesBottomButton = _cmFormatNodesMenu.ContextMenu.AddButton("Align bottom", () => { AlignNodes(SelectedNodes, NodeAlignmentType.Bottom); }); + _cmAlignNodesTopButton = _cmFormatNodesMenu.ContextMenu.AddButton("Align top", Editor.Instance.Options.Options.Input.NodesAlignTop, () => { AlignNodes(SelectedNodes, NodeAlignmentType.Top); }); + _cmAlignNodesMiddleButton = _cmFormatNodesMenu.ContextMenu.AddButton("Align middle", Editor.Instance.Options.Options.Input.NodesAlignMiddle, () => { AlignNodes(SelectedNodes, NodeAlignmentType.Middle); }); + _cmAlignNodesBottomButton = _cmFormatNodesMenu.ContextMenu.AddButton("Align bottom", Editor.Instance.Options.Options.Input.NodesAlignBottom, () => { AlignNodes(SelectedNodes, NodeAlignmentType.Bottom); }); _cmFormatNodesMenu.ContextMenu.AddSeparator(); - _cmAlignNodesLeftButton = _cmFormatNodesMenu.ContextMenu.AddButton("Align left", () => { AlignNodes(SelectedNodes, NodeAlignmentType.Left); }); - _cmAlignNodesCenterButton = _cmFormatNodesMenu.ContextMenu.AddButton("Align center", () => { AlignNodes(SelectedNodes, NodeAlignmentType.Center); }); - _cmAlignNodesRightButton = _cmFormatNodesMenu.ContextMenu.AddButton("Align right", () => { AlignNodes(SelectedNodes, NodeAlignmentType.Right); }); + _cmAlignNodesLeftButton = _cmFormatNodesMenu.ContextMenu.AddButton("Align left", Editor.Instance.Options.Options.Input.NodesAlignLeft, () => { AlignNodes(SelectedNodes, NodeAlignmentType.Left); }); + _cmAlignNodesCenterButton = _cmFormatNodesMenu.ContextMenu.AddButton("Align center", Editor.Instance.Options.Options.Input.NodesAlignCenter, () => { AlignNodes(SelectedNodes, NodeAlignmentType.Center); }); + _cmAlignNodesRightButton = _cmFormatNodesMenu.ContextMenu.AddButton("Align right", Editor.Instance.Options.Options.Input.NodesAlignRight, () => { AlignNodes(SelectedNodes, NodeAlignmentType.Right); }); _cmFormatNodesMenu.ContextMenu.AddSeparator(); - _cmDistributeNodesHorizontallyButton = _cmFormatNodesMenu.ContextMenu.AddButton("Distribute horizontally", () => { DistributeNodes(SelectedNodes, false); }); - _cmDistributeNodesVerticallyButton = _cmFormatNodesMenu.ContextMenu.AddButton("Distribute vertically", () => { DistributeNodes(SelectedNodes, true); }); + _cmDistributeNodesHorizontallyButton = _cmFormatNodesMenu.ContextMenu.AddButton("Distribute horizontally", Editor.Instance.Options.Options.Input.NodesDistributeHorizontal, () => { DistributeNodes(SelectedNodes, false); }); + _cmDistributeNodesVerticallyButton = _cmFormatNodesMenu.ContextMenu.AddButton("Distribute vertically", Editor.Instance.Options.Options.Input.NodesDistributeVertical, () => { DistributeNodes(SelectedNodes, true); }); _cmRemoveNodeConnectionsButton = menu.AddButton("Remove all connections to that node(s)", () => { diff --git a/Source/Editor/Surface/VisjectSurface.cs b/Source/Editor/Surface/VisjectSurface.cs index faecebbd3..cfc5eb900 100644 --- a/Source/Editor/Surface/VisjectSurface.cs +++ b/Source/Editor/Surface/VisjectSurface.cs @@ -405,6 +405,15 @@ namespace FlaxEditor.Surface new InputActionsContainer.Binding(options => options.Paste, Paste), new InputActionsContainer.Binding(options => options.Cut, Cut), new InputActionsContainer.Binding(options => options.Duplicate, Duplicate), + new InputActionsContainer.Binding(options => options.NodesAutoFormat, () => { FormatGraph(SelectedNodes); }), + new InputActionsContainer.Binding(options => options.NodesAlignTop, () => { AlignNodes(SelectedNodes, NodeAlignmentType.Top); }), + new InputActionsContainer.Binding(options => options.NodesAlignMiddle, () => { AlignNodes(SelectedNodes, NodeAlignmentType.Middle); }), + new InputActionsContainer.Binding(options => options.NodesAlignBottom, () => { AlignNodes(SelectedNodes, NodeAlignmentType.Bottom); }), + new InputActionsContainer.Binding(options => options.NodesAlignLeft, () => { AlignNodes(SelectedNodes, NodeAlignmentType.Left); }), + new InputActionsContainer.Binding(options => options.NodesAlignCenter, () => { AlignNodes(SelectedNodes, NodeAlignmentType.Center); }), + new InputActionsContainer.Binding(options => options.NodesAlignRight, () => { AlignNodes(SelectedNodes, NodeAlignmentType.Right); }), + new InputActionsContainer.Binding(options => options.NodesDistributeHorizontal, () => { DistributeNodes(SelectedNodes, false); }), + new InputActionsContainer.Binding(options => options.NodesDistributeVertical, () => { DistributeNodes(SelectedNodes, true); }), }); Context.ControlSpawned += OnSurfaceControlSpawned; From 112e7284655eff9d2424186809b2f6f396bf6fb5 Mon Sep 17 00:00:00 2001 From: xxSeys1 Date: Mon, 9 Jun 2025 13:56:41 +0200 Subject: [PATCH 14/37] fix scroll to node on selection in prefab editor --- Source/Editor/Windows/Assets/PrefabWindow.Selection.cs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/Source/Editor/Windows/Assets/PrefabWindow.Selection.cs b/Source/Editor/Windows/Assets/PrefabWindow.Selection.cs index 03e2a9652..6208aa7a1 100644 --- a/Source/Editor/Windows/Assets/PrefabWindow.Selection.cs +++ b/Source/Editor/Windows/Assets/PrefabWindow.Selection.cs @@ -97,10 +97,7 @@ namespace FlaxEditor.Windows.Assets // For single node selected scroll view so user can see it if (nodes.Count == 1) - { - nodes[0].ExpandAllParents(true); - ScrollViewTo(nodes[0]); - } + ScrollToSelectedNode(); } // Update properties editor From f8daff273a7b7b40ffa27179783e57aee5f92e71 Mon Sep 17 00:00:00 2001 From: Zode Date: Mon, 9 Jun 2025 14:56:54 +0300 Subject: [PATCH 15/37] Add import & export warning messageboxes. --- Source/Engine/ContentImporters/ImportAudio.cpp | 3 +++ Source/Engine/Tools/TextureTool/TextureTool.stb.cpp | 11 +++++++++++ 2 files changed, 14 insertions(+) diff --git a/Source/Engine/ContentImporters/ImportAudio.cpp b/Source/Engine/ContentImporters/ImportAudio.cpp index 6fd0cdc74..2c5b84d49 100644 --- a/Source/Engine/ContentImporters/ImportAudio.cpp +++ b/Source/Engine/ContentImporters/ImportAudio.cpp @@ -18,6 +18,7 @@ #include "Engine/Tools/AudioTool/OggVorbisDecoder.h" #include "Engine/Tools/AudioTool/OggVorbisEncoder.h" #include "Engine/Serialization/JsonWriters.h" +#include "Engine/Platform/MessageBox.h" bool ImportAudio::TryGetImportOptions(const StringView& path, Options& options) { @@ -118,6 +119,7 @@ CreateAssetResult ImportAudio::Import(CreateAssetContext& context, AudioDecoder& } #else #define HANDLE_VORBIS(chunkIndex, dataPtr, dataSize) \ + MessageBox::Show(TEXT("Vorbis format is not supported."), TEXT("Import warning"), MessageBoxButtons::OK, MessageBoxIcon::Warning); LOG(Warning, "Vorbis format is not supported."); \ return CreateAssetResult::Error; #endif @@ -140,6 +142,7 @@ CreateAssetResult ImportAudio::Import(CreateAssetContext& context, AudioDecoder& break; \ default: \ { \ + MessageBox::Show(TEXT("Unknown audio format."), TEXT("Import warning"), MessageBoxButtons::OK, MessageBoxIcon::Warning); \ LOG(Warning, "Unknown audio format."); \ return CreateAssetResult::Error; \ } \ diff --git a/Source/Engine/Tools/TextureTool/TextureTool.stb.cpp b/Source/Engine/Tools/TextureTool/TextureTool.stb.cpp index 6fae6432e..f8f012c15 100644 --- a/Source/Engine/Tools/TextureTool/TextureTool.stb.cpp +++ b/Source/Engine/Tools/TextureTool/TextureTool.stb.cpp @@ -13,6 +13,7 @@ #include "Engine/Graphics/PixelFormatExtensions.h" #include "Engine/Utilities/AnsiPathTempFile.h" #include "Engine/Platform/File.h" +#include "Engine/Platform/MessageBox.h" #define STBI_ASSERT(x) ASSERT(x) #define STBI_MALLOC(sz) Allocator::Allocate(sz) @@ -286,21 +287,27 @@ bool TextureTool::ExportTextureStb(ImageType type, const StringView& path, const break; } case ImageType::GIF: + MessageBox::Show(TEXT("GIF format is not supported."), TEXT("Export warning"), MessageBoxButtons::OK, MessageBoxIcon::Warning); LOG(Warning, "GIF format is not supported."); break; case ImageType::TIFF: + MessageBox::Show(TEXT("TIFF format is not supported."), TEXT("Export warning"), MessageBoxButtons::OK, MessageBoxIcon::Warning); LOG(Warning, "GIF format is not supported."); break; case ImageType::DDS: + MessageBox::Show(TEXT("DDS format is not supported."), TEXT("Export warning"), MessageBoxButtons::OK, MessageBoxIcon::Warning); LOG(Warning, "DDS format is not supported."); break; case ImageType::RAW: + MessageBox::Show(TEXT("RAW format is not supported."), TEXT("Export warning"), MessageBoxButtons::OK, MessageBoxIcon::Warning); LOG(Warning, "RAW format is not supported."); break; case ImageType::EXR: + MessageBox::Show(TEXT("EXR format is not supported."), TEXT("Export warning"), MessageBoxButtons::OK, MessageBoxIcon::Warning); LOG(Warning, "EXR format is not supported."); break; default: + MessageBox::Show(TEXT("Unknown format."), TEXT("Export warning"), MessageBoxButtons::OK, MessageBoxIcon::Warning); LOG(Warning, "Unknown format."); break; } @@ -434,17 +441,21 @@ bool TextureTool::ImportTextureStb(ImageType type, const StringView& path, Textu free(pixels); #else + MessageBox::Show(TEXT("EXR format is not supported."), TEXT("Import warning"), MessageBoxButtons::OK, MessageBoxIcon::Warning); LOG(Warning, "EXR format is not supported."); #endif break; } case ImageType::DDS: + MessageBox::Show(TEXT("DDS format is not supported."), TEXT("Import warning"), MessageBoxButtons::OK, MessageBoxIcon::Warning); LOG(Warning, "DDS format is not supported."); break; case ImageType::TIFF: + MessageBox::Show(TEXT("TIFF format is not supported."), TEXT("Import warning"), MessageBoxButtons::OK, MessageBoxIcon::Warning); LOG(Warning, "TIFF format is not supported."); break; default: + MessageBox::Show(TEXT("Unknown format."), TEXT("Import warning"), MessageBoxButtons::OK, MessageBoxIcon::Warning); LOG(Warning, "Unknown format."); return true; } From 8dfb564fb3db0ecd2fa7600cf7ebea2f16a7ec2f Mon Sep 17 00:00:00 2001 From: Zode Date: Mon, 9 Jun 2025 15:04:34 +0300 Subject: [PATCH 16/37] Add messagebox to windows import too --- Source/Engine/Tools/TextureTool/TextureTool.DirectXTex.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Source/Engine/Tools/TextureTool/TextureTool.DirectXTex.cpp b/Source/Engine/Tools/TextureTool/TextureTool.DirectXTex.cpp index 6d0421e3c..01ed4ca34 100644 --- a/Source/Engine/Tools/TextureTool/TextureTool.DirectXTex.cpp +++ b/Source/Engine/Tools/TextureTool/TextureTool.DirectXTex.cpp @@ -8,6 +8,7 @@ #include "Engine/Platform/File.h" #include "Engine/Platform/CriticalSection.h" #include "Engine/Platform/ConditionVariable.h" +#include "Engine/Platform/MessageBox.h" #include "Engine/Graphics/RenderTools.h" #include "Engine/Graphics/Async/GPUTask.h" #include "Engine/Graphics/Textures/TextureData.h" @@ -358,6 +359,7 @@ HRESULT LoadFromEXRFile(const StringView& path, DirectX::ScratchImage& image) free(pixels); return result; #else + MessageBox::Show(TEXT("EXR format is not supported."), TEXT("Import warning"), MessageBoxButtons::OK, MessageBoxIcon::Warning); LOG(Warning, "EXR format is not supported."); return E_FAIL; #endif From 7fc564a0ac61a007ef5f3a4b7be12ad9af4c0ca6 Mon Sep 17 00:00:00 2001 From: Zode Date: Mon, 9 Jun 2025 15:07:52 +0300 Subject: [PATCH 17/37] Pop error box on lightmap UV generation also --- Source/Engine/Graphics/Models/ModelData.Tool.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Source/Engine/Graphics/Models/ModelData.Tool.cpp b/Source/Engine/Graphics/Models/ModelData.Tool.cpp index 52663c271..f1c84cfb7 100644 --- a/Source/Engine/Graphics/Models/ModelData.Tool.cpp +++ b/Source/Engine/Graphics/Models/ModelData.Tool.cpp @@ -12,6 +12,7 @@ #include "Engine/Tools/ModelTool/VertexTriangleAdjacency.h" #include "Engine/Profiler/ProfilerCPU.h" #include "Engine/Platform/Platform.h" +#include "Engine/Platform/MessageBox.h" #define USE_MIKKTSPACE 1 #include "ThirdParty/MikkTSpace/mikktspace.h" #if USE_ASSIMP @@ -181,6 +182,7 @@ bool MeshData::GenerateLightmapUVs() for (int32 i = 0; i < (int32)vb.size(); i++) lightmapChannel.Get()[i] = *(Float2*)&vb[i].uv; #else + MessageBox::Show(TEXT("Model lightmap UVs generation is not supported on this platform."), TEXT("Import error"), MessageBoxButtons::OK, MessageBoxIcon::Error); LOG(Error, "Model lightmap UVs generation is not supported on this platform."); #endif From 9e50a39ebf5b1adf9ce98b1e8c209e6cc8977fcc Mon Sep 17 00:00:00 2001 From: Zode Date: Mon, 9 Jun 2025 16:19:39 +0300 Subject: [PATCH 18/37] Add define guards so that the messagebox only appears in editor builds --- Source/Engine/Tools/TextureTool/TextureTool.DirectXTex.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Source/Engine/Tools/TextureTool/TextureTool.DirectXTex.cpp b/Source/Engine/Tools/TextureTool/TextureTool.DirectXTex.cpp index 01ed4ca34..bf74213d4 100644 --- a/Source/Engine/Tools/TextureTool/TextureTool.DirectXTex.cpp +++ b/Source/Engine/Tools/TextureTool/TextureTool.DirectXTex.cpp @@ -8,12 +8,12 @@ #include "Engine/Platform/File.h" #include "Engine/Platform/CriticalSection.h" #include "Engine/Platform/ConditionVariable.h" -#include "Engine/Platform/MessageBox.h" #include "Engine/Graphics/RenderTools.h" #include "Engine/Graphics/Async/GPUTask.h" #include "Engine/Graphics/Textures/TextureData.h" #include "Engine/Graphics/PixelFormatExtensions.h" #if USE_EDITOR +#include "Engine/Platform/MessageBox.h" #include "Engine/Graphics/GPUDevice.h" #endif #include "Engine/Utilities/AnsiPathTempFile.h" @@ -359,7 +359,9 @@ HRESULT LoadFromEXRFile(const StringView& path, DirectX::ScratchImage& image) free(pixels); return result; #else +#if USE_EDITOR MessageBox::Show(TEXT("EXR format is not supported."), TEXT("Import warning"), MessageBoxButtons::OK, MessageBoxIcon::Warning); +#endif LOG(Warning, "EXR format is not supported."); return E_FAIL; #endif From 2109a2d26153d163e3da5d5ed0324ec7b58e8489 Mon Sep 17 00:00:00 2001 From: xxSeys1 Date: Mon, 9 Jun 2025 18:40:12 +0200 Subject: [PATCH 19/37] update content finder popup to wrap on keyboard navigation - Fixes auto scroll - Make it wrap - Add pressing backspace to focus search bar and select all text --- Source/Editor/Windows/Search/ContentFinder.cs | 47 +++++++------------ 1 file changed, 18 insertions(+), 29 deletions(-) diff --git a/Source/Editor/Windows/Search/ContentFinder.cs b/Source/Editor/Windows/Search/ContentFinder.cs index e4227e5c4..12b479aea 100644 --- a/Source/Editor/Windows/Search/ContentFinder.cs +++ b/Source/Editor/Windows/Search/ContentFinder.cs @@ -180,39 +180,17 @@ namespace FlaxEditor.Windows.Search switch (key) { case KeyboardKeys.ArrowDown: - { - if (_matchedItems.Count == 0) - return true; - int currentPos; - if (_selectedItem != null) - { - currentPos = _matchedItems.IndexOf(_selectedItem) + 1; - if (currentPos >= _matchedItems.Count) - currentPos--; - } - else - { - currentPos = 0; - } - SelectedItem = _matchedItems[currentPos]; - return true; - } case KeyboardKeys.ArrowUp: { if (_matchedItems.Count == 0) return true; - int currentPos; - if (_selectedItem != null) - { - currentPos = _matchedItems.IndexOf(_selectedItem) - 1; - if (currentPos < 0) - currentPos = 0; - } - else - { - currentPos = 0; - } - SelectedItem = _matchedItems[currentPos]; + + var focusedIndex = _matchedItems.IndexOf(_selectedItem); + int delta = key == KeyboardKeys.ArrowDown ? -1 : 1; + int nextIndex = Mathf.Wrap(focusedIndex - delta, 0, _matchedItems.Count - 1); + var nextItem = _matchedItems[nextIndex]; + + SelectedItem = nextItem; return true; } case KeyboardKeys.Return: @@ -234,6 +212,17 @@ namespace FlaxEditor.Windows.Search Hide(); return true; } + case KeyboardKeys.Backspace: + { + // Alow the user to quickly focus the searchbar + if (_searchBox != null && !_searchBox.IsFocused) + { + _searchBox.Focus(); + _searchBox.SelectAll(); + return true; + } + break; + } } return base.OnKeyDown(key); From 793bc33b2fa272cf9717c336ef62449515ca1da4 Mon Sep 17 00:00:00 2001 From: xxSeys1 Date: Mon, 9 Jun 2025 18:40:33 +0200 Subject: [PATCH 20/37] fix right clicking on item reset search and scroll --- Source/Editor/Windows/Search/ContentFinder.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Source/Editor/Windows/Search/ContentFinder.cs b/Source/Editor/Windows/Search/ContentFinder.cs index 12b479aea..9118739b8 100644 --- a/Source/Editor/Windows/Search/ContentFinder.cs +++ b/Source/Editor/Windows/Search/ContentFinder.cs @@ -42,6 +42,7 @@ namespace FlaxEditor.Windows.Search if (value == _selectedItem || (value != null && !_matchedItems.Contains(value))) return; + // Restore the previous selected item to the non-selected color if (_selectedItem != null) { _selectedItem.BackgroundColor = Color.Transparent; @@ -54,6 +55,7 @@ namespace FlaxEditor.Windows.Search _selectedItem.BackgroundColor = Style.Current.BackgroundSelected; if (_matchedItems.Count > VisibleItemCount) { + _selectedItem.Focus(); _resultPanel.ScrollViewTo(_selectedItem, true); } } From e1a2a369780f215758a62c25484bd86495bbded9 Mon Sep 17 00:00:00 2001 From: Chandler Cox Date: Mon, 9 Jun 2025 15:02:43 -0500 Subject: [PATCH 21/37] Add GetOrAddButton utility for MainMenu. --- Source/Editor/GUI/MainMenu.cs | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/Source/Editor/GUI/MainMenu.cs b/Source/Editor/GUI/MainMenu.cs index 0b959d2c9..bce668451 100644 --- a/Source/Editor/GUI/MainMenu.cs +++ b/Source/Editor/GUI/MainMenu.cs @@ -266,6 +266,19 @@ namespace FlaxEditor.GUI return AddChild(new MainMenuButton(text)); } + /// + /// Gets or adds a button. + /// + /// The button text + /// The existing or created button control. + public MainMenuButton GetOrAddButton(string text) + { + MainMenuButton result = GetButton(text); + if (result == null) + result = AddButton(text); + return result; + } + /// /// Gets the button. /// From c1e782bb32c042617f605b6c3de81869eddd00a9 Mon Sep 17 00:00:00 2001 From: Zode Date: Mon, 9 Jun 2025 23:34:02 +0300 Subject: [PATCH 22/37] Add hotkey to quick focus debug console input --- Source/Editor/Options/InputOptions.cs | 4 ++++ Source/Editor/Utilities/Utils.cs | 1 + Source/Editor/Windows/GameWindow.cs | 1 + Source/Editor/Windows/OutputLogWindow.cs | 9 +++++++++ 4 files changed, 15 insertions(+) diff --git a/Source/Editor/Options/InputOptions.cs b/Source/Editor/Options/InputOptions.cs index ff7971667..ba601052c 100644 --- a/Source/Editor/Options/InputOptions.cs +++ b/Source/Editor/Options/InputOptions.cs @@ -139,6 +139,10 @@ namespace FlaxEditor.Options [EditorDisplay("Common"), EditorOrder(240)] public InputBinding ToggleFullscreen = new InputBinding(KeyboardKeys.F11); + [DefaultValue(typeof(InputBinding), "Ctrl+BackQuote")] + [EditorDisplay("Common"), EditorOrder(250)] + public InputBinding FocusConsoleCommand = new InputBinding(KeyboardKeys.BackQuote, KeyboardKeys.Control); + #endregion #region File diff --git a/Source/Editor/Utilities/Utils.cs b/Source/Editor/Utilities/Utils.cs index 179e50ebb..949479783 100644 --- a/Source/Editor/Utilities/Utils.cs +++ b/Source/Editor/Utilities/Utils.cs @@ -1518,6 +1518,7 @@ namespace FlaxEditor.Utilities inputActions.Add(options => options.OpenScriptsProject, () => Editor.Instance.CodeEditing.OpenSolution()); inputActions.Add(options => options.GenerateScriptsProject, () => Editor.Instance.ProgressReporting.GenerateScriptsProjectFiles.RunAsync()); inputActions.Add(options => options.RecompileScripts, ScriptsBuilder.Compile); + inputActions.Add(options => options.FocusConsoleCommand, () => Editor.Instance.Windows.OutputLogWin.FocusCommand()); } internal static string ToPathProject(string path) diff --git a/Source/Editor/Windows/GameWindow.cs b/Source/Editor/Windows/GameWindow.cs index 4db3bcf0f..e05f0d2db 100644 --- a/Source/Editor/Windows/GameWindow.cs +++ b/Source/Editor/Windows/GameWindow.cs @@ -405,6 +405,7 @@ namespace FlaxEditor.Windows return; Editor.Instance.SceneEditing.Delete(); }); + InputActions.Add(options => options.FocusConsoleCommand, () => Editor.Instance.Windows.OutputLogWin.FocusCommand()); } private void ChangeViewportRatio(ViewportScaleOptions v) diff --git a/Source/Editor/Windows/OutputLogWindow.cs b/Source/Editor/Windows/OutputLogWindow.cs index 6fc0659d7..be6e6ff4d 100644 --- a/Source/Editor/Windows/OutputLogWindow.cs +++ b/Source/Editor/Windows/OutputLogWindow.cs @@ -830,6 +830,15 @@ namespace FlaxEditor.Windows OnOutputTextChanged(); } + /// + /// Focus the debug command line and ensure that the output log window is visible. + /// + public void FocusCommand() + { + FocusOrShow(); + _commandLineBox.Focus(); + } + /// public override void Update(float deltaTime) { From b418ab5275ceec1b3f3e8fb223985bba3234aeb8 Mon Sep 17 00:00:00 2001 From: xxSeys1 Date: Tue, 10 Jun 2025 14:58:31 +0200 Subject: [PATCH 23/37] reduce flickering in highlights and boxes --- .../Dedicated/LayersMatrixEditor.cs | 35 +++++++++++-------- 1 file changed, 20 insertions(+), 15 deletions(-) diff --git a/Source/Editor/CustomEditors/Dedicated/LayersMatrixEditor.cs b/Source/Editor/CustomEditors/Dedicated/LayersMatrixEditor.cs index f853ccef7..7e7f8483e 100644 --- a/Source/Editor/CustomEditors/Dedicated/LayersMatrixEditor.cs +++ b/Source/Editor/CustomEditors/Dedicated/LayersMatrixEditor.cs @@ -1,6 +1,5 @@ // Copyright (c) Wojciech Figat. All rights reserved. -using System; using System.Collections.Generic; using FlaxEditor.Content.Settings; using FlaxEngine; @@ -163,11 +162,17 @@ namespace FlaxEditor.CustomEditors.Dedicated /// public override void Refresh() { - _horizontalHighlight.Visible = false; - _verticalHighlight.Visible = false; int selectedColumn = -1; int selectedRow = -1; var style = FlaxEngine.GUI.Style.Current; + bool mouseOverGrid = _grid.IsMouseOver; + + // Only hide highlights if mouse is not over the grid to reduce flickering + if (!mouseOverGrid) + { + _horizontalHighlight.Visible = false; + _verticalHighlight.Visible = false; + } // Sync check boxes for (int i = 0; i < _checkBoxes.Count; i++) @@ -176,9 +181,8 @@ namespace FlaxEditor.CustomEditors.Dedicated int column = (int)((Float2)box.Tag).X; int row = (int)((Float2)box.Tag).Y; box.Checked = GetBit(column, row); - box.ImageColor = style.BorderSelected * 1.2f; - - if(box.IsMouseOver) + + if (box.IsMouseOver) { selectedColumn = column; selectedRow = row; @@ -197,17 +201,18 @@ namespace FlaxEditor.CustomEditors.Dedicated } } - if(selectedColumn > -1 && selectedRow > -1) + for (int i = 0; i < _checkBoxes.Count; i++) { - for (int i = 0; i < _checkBoxes.Count; i++) - { - var box = _checkBoxes[i]; - int column = (int)((Float2)box.Tag).X; - int row = (int)((Float2)box.Tag).Y; - if(column == selectedColumn || row == selectedRow) - continue; + var box = _checkBoxes[i]; + int column = (int)((Float2)box.Tag).X; + int row = (int)((Float2)box.Tag).Y; - box.ImageColor = style.BorderSelected * 0.75f; + if (!mouseOverGrid) + box.ImageColor = style.BorderSelected; + else if (selectedColumn > -1 && selectedRow > -1) + { + bool isRowOrColumn = column == selectedColumn || row == selectedRow; + box.ImageColor = style.BorderSelected * (isRowOrColumn ? 1.2f : 0.75f); } } } From aa59a6faf7f8a3c9b075ae402f57f0f23290efaf Mon Sep 17 00:00:00 2001 From: Zode Date: Wed, 11 Jun 2025 17:46:37 +0300 Subject: [PATCH 24/37] Extract function to lessen repeat code for debug group buttons, add shift functionality to quick toggle others. --- Source/Editor/Windows/DebugLogWindow.cs | 45 +++++++++++++++---------- 1 file changed, 27 insertions(+), 18 deletions(-) diff --git a/Source/Editor/Windows/DebugLogWindow.cs b/Source/Editor/Windows/DebugLogWindow.cs index fd6b333ef..d0680c3c0 100644 --- a/Source/Editor/Windows/DebugLogWindow.cs +++ b/Source/Editor/Windows/DebugLogWindow.cs @@ -352,24 +352,12 @@ namespace FlaxEditor.Windows editor.Options.Apply(editor.Options.Options); }).SetAutoCheck(true).LinkTooltip("Performs auto pause on error"); toolstrip.AddSeparator(); - _groupButtons[0] = (ToolStripButton)toolstrip.AddButton(editor.Icons.Error32, () => - { - UpdateLogTypeVisibility(LogGroup.Error, _groupButtons[0].Checked); - editor.Options.Options.Interface.DebugLogShowErrorMessages = _groupButtons[0].Checked; - editor.Options.Apply(editor.Options.Options); - }).SetAutoCheck(true).LinkTooltip("Shows/hides error messages"); - _groupButtons[1] = (ToolStripButton)toolstrip.AddButton(editor.Icons.Warning32, () => - { - UpdateLogTypeVisibility(LogGroup.Warning, _groupButtons[1].Checked); - editor.Options.Options.Interface.DebugLogShowWarningMessages = _groupButtons[1].Checked; - editor.Options.Apply(editor.Options.Options); - }).SetAutoCheck(true).LinkTooltip("Shows/hides warning messages"); - _groupButtons[2] = (ToolStripButton)toolstrip.AddButton(editor.Icons.Info32, () => - { - UpdateLogTypeVisibility(LogGroup.Info, _groupButtons[2].Checked); - editor.Options.Options.Interface.DebugLogShowInfoMessages = _groupButtons[2].Checked; - editor.Options.Apply(editor.Options.Options); - }).SetAutoCheck(true).LinkTooltip("Shows/hides info messages"); + _groupButtons[0] = (ToolStripButton)toolstrip.AddButton(editor.Icons.Error32, () => { OnGroupButtonPressed(0); }) + .SetAutoCheck(true).LinkTooltip("Shows/hides error messages"); + _groupButtons[1] = (ToolStripButton)toolstrip.AddButton(editor.Icons.Warning32, () => { OnGroupButtonPressed(1); }) + .SetAutoCheck(true).LinkTooltip("Shows/hides warning messages"); + _groupButtons[2] = (ToolStripButton)toolstrip.AddButton(editor.Icons.Info32, () => { OnGroupButtonPressed(2); }) + .SetAutoCheck(true).LinkTooltip("Shows/hides info messages"); UpdateCount(); // Split panel @@ -418,6 +406,27 @@ namespace FlaxEditor.Windows OnEditorOptionsChanged(Editor.Options.Options); } + private void OnGroupButtonPressed(int index) + { + UpdateLogTypeVisibility((LogGroup)index, _groupButtons[index].Checked); + if(Input.GetKey(KeyboardKeys.Shift)) + { + for(int i = 0; i < (int)LogGroup.Max; i++) + { + if(i == index) + continue; + + _groupButtons[i].Checked = !_groupButtons[index].Checked; + UpdateLogTypeVisibility((LogGroup)i, _groupButtons[i].Checked); + } + } + + Editor.Options.Options.Interface.DebugLogShowErrorMessages = _groupButtons[0].Checked; + Editor.Options.Options.Interface.DebugLogShowWarningMessages = _groupButtons[1].Checked; + Editor.Options.Options.Interface.DebugLogShowInfoMessages = _groupButtons[2].Checked; + Editor.Options.Apply(Editor.Options.Options); + } + private void OnEditorOptionsChanged(EditorOptions options) { _timestampsFormats = options.Interface.DebugLogTimestampsFormat; From 00055ef66329437d044ea290e52a833fe71d35aa Mon Sep 17 00:00:00 2001 From: Zode Date: Wed, 11 Jun 2025 17:47:27 +0300 Subject: [PATCH 25/37] Make tool strip buttons more responsive by also reaction to double left clicks --- Source/Editor/GUI/ToolStripButton.cs | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/Source/Editor/GUI/ToolStripButton.cs b/Source/Editor/GUI/ToolStripButton.cs index 9ef454ccc..56e798a2e 100644 --- a/Source/Editor/GUI/ToolStripButton.cs +++ b/Source/Editor/GUI/ToolStripButton.cs @@ -215,6 +215,22 @@ namespace FlaxEditor.GUI return base.OnMouseUp(location, button); } + /// + public override bool OnMouseDoubleClick(Float2 location, MouseButton button) + { + if(button == MouseButton.Left) + { + if (AutoCheck) + Checked = !Checked; + Clicked?.Invoke(); + (Parent as ToolStrip)?.OnButtonClicked(this); + + return true; + } + + return false; + } + /// public override void OnMouseLeave() { From 27ac755bbefd22b59352ee3f38e58f56e8da7dcf Mon Sep 17 00:00:00 2001 From: Zode Date: Wed, 11 Jun 2025 23:15:11 +0300 Subject: [PATCH 26/37] Make particle emitter editor window source code button disable itself is no source code is available --- .../Windows/Assets/ParticleEmitterWindow.cs | 16 +++++++++++++++- Source/Engine/Particles/ParticleEmitter.cpp | 17 +++++++++++++++++ Source/Engine/Particles/ParticleEmitter.h | 6 ++++++ 3 files changed, 38 insertions(+), 1 deletion(-) diff --git a/Source/Editor/Windows/Assets/ParticleEmitterWindow.cs b/Source/Editor/Windows/Assets/ParticleEmitterWindow.cs index 80eafd9e0..bc1f49443 100644 --- a/Source/Editor/Windows/Assets/ParticleEmitterWindow.cs +++ b/Source/Editor/Windows/Assets/ParticleEmitterWindow.cs @@ -5,6 +5,7 @@ using System.Collections.Generic; using System.Linq; using FlaxEditor.Content; using FlaxEditor.CustomEditors; +using FlaxEditor.GUI; using FlaxEditor.Scripting; using FlaxEditor.Surface; using FlaxEditor.Viewport.Previews; @@ -114,6 +115,7 @@ namespace FlaxEditor.Windows.Assets private readonly PropertiesProxy _properties; private Tab _previewTab; + private ToolStripButton _showSourceCodeButton; /// public ParticleEmitterWindow(Editor editor, AssetItem item) @@ -146,7 +148,8 @@ namespace FlaxEditor.Windows.Assets // Toolstrip SurfaceUtils.PerformCommonSetup(this, _toolstrip, _surface, out _saveButton, out _undoButton, out _redoButton); - _toolstrip.AddButton(editor.Icons.Code64, ShowSourceCode).LinkTooltip("Show generated shader source code"); + _showSourceCodeButton = _toolstrip.AddButton(editor.Icons.Code64, ShowSourceCode); + _showSourceCodeButton.LinkTooltip("Show generated shader source code"); _toolstrip.AddSeparator(); _toolstrip.AddButton(editor.Icons.Docs64, () => Platform.OpenUrl(Utilities.Constants.DocsUrl + "manual/particles/index.html")).LinkTooltip("See documentation to learn more"); } @@ -285,5 +288,16 @@ namespace FlaxEditor.Windows.Assets /// public SearchAssetTypes AssetType => SearchAssetTypes.ParticleEmitter; + + /// + public override void Update(float deltaTime) + { + base.Update(deltaTime); + + if(_asset == null) + return; + + _showSourceCodeButton.Enabled = _asset.HasShaderCode(); + } } } diff --git a/Source/Engine/Particles/ParticleEmitter.cpp b/Source/Engine/Particles/ParticleEmitter.cpp index 452d4560a..4490406bc 100644 --- a/Source/Engine/Particles/ParticleEmitter.cpp +++ b/Source/Engine/Particles/ParticleEmitter.cpp @@ -440,4 +440,21 @@ bool ParticleEmitter::Save(const StringView& path) return SaveSurface(data); } +bool ParticleEmitter::HasShaderCode() +{ + if(SimulationMode != ParticlesSimulationMode::GPU) + { + return false; + } + + #if COMPILE_WITH_PARTICLE_GPU_GRAPH && COMPILE_WITH_SHADER_COMPILER + if(_shaderHeader.ParticleEmitter.GraphVersion == PARTICLE_GPU_GRAPH_VERSION + && HasChunk(SHADER_FILE_CHUNK_SOURCE) + && !HasDependenciesModified()) + return true; + #endif + + return false; +} + #endif diff --git a/Source/Engine/Particles/ParticleEmitter.h b/Source/Engine/Particles/ParticleEmitter.h index b3343da1a..4b27036f7 100644 --- a/Source/Engine/Particles/ParticleEmitter.h +++ b/Source/Engine/Particles/ParticleEmitter.h @@ -173,6 +173,12 @@ public: #if USE_EDITOR void GetReferences(Array& assets, Array& files) const override; bool Save(const StringView& path = StringView::Empty) override; + + /// + /// Determine if the particle emitter has valid shader code present. + /// + /// True if particle emitter has shader code, otherwise false. + API_FUNCTION() bool HasShaderCode(); #endif protected: From 214ec9f2b1fe9de1e545c1399922e6a8245e9e88 Mon Sep 17 00:00:00 2001 From: xxSeys1 Date: Thu, 12 Jun 2025 00:49:39 +0200 Subject: [PATCH 27/37] fix node delete button not checking if the user is performing certain actions on the surface before deleting node --- Source/Editor/Surface/SurfaceNode.cs | 12 +++++++----- Source/Editor/Surface/VisjectSurface.Draw.cs | 2 +- Source/Editor/Surface/VisjectSurface.Input.cs | 3 +++ Source/Editor/Surface/VisjectSurface.cs | 14 ++++++++++++-- 4 files changed, 23 insertions(+), 8 deletions(-) diff --git a/Source/Editor/Surface/SurfaceNode.cs b/Source/Editor/Surface/SurfaceNode.cs index 8a42a7a92..5dedd604f 100644 --- a/Source/Editor/Surface/SurfaceNode.cs +++ b/Source/Editor/Surface/SurfaceNode.cs @@ -912,7 +912,7 @@ namespace FlaxEditor.Surface /// public override bool OnTestTooltipOverControl(ref Float2 location) { - return _headerRect.Contains(ref location) && ShowTooltip; + return _headerRect.Contains(ref location) && ShowTooltip && !Surface.IsConnecting && !Surface.IsBoxSelecting; } /// @@ -1070,7 +1070,7 @@ namespace FlaxEditor.Surface // Header var headerColor = style.BackgroundHighlighted; - if (_headerRect.Contains(ref _mousePosition)) + if (_headerRect.Contains(ref _mousePosition) && !Surface.IsConnecting && !Surface.IsBoxSelecting) headerColor *= 1.07f; Render2D.FillRectangle(_headerRect, headerColor); Render2D.DrawText(style.FontLarge, Title, _headerRect, style.Foreground, TextAlignment.Center, TextAlignment.Center); @@ -1078,7 +1078,8 @@ namespace FlaxEditor.Surface // Close button if ((Archetype.Flags & NodeFlags.NoCloseButton) == 0 && Surface.CanEdit) { - Render2D.DrawSprite(style.Cross, _closeButtonRect, _closeButtonRect.Contains(_mousePosition) ? style.Foreground : style.ForegroundGrey); + bool highlightClose = _closeButtonRect.Contains(_mousePosition) && !Surface.IsConnecting && !Surface.IsBoxSelecting; + Render2D.DrawSprite(style.Cross, _closeButtonRect, highlightClose ? style.Foreground : style.ForegroundGrey); } // Footer @@ -1123,8 +1124,9 @@ namespace FlaxEditor.Surface if (base.OnMouseUp(location, button)) return true; - // Close - if (button == MouseButton.Left && (Archetype.Flags & NodeFlags.NoCloseButton) == 0 && _closeButtonRect.Contains(ref location)) + // Close/ delete + bool canDelete = !Surface.IsConnecting && !Surface.WasBoxSelecting && !Surface.WasMovingSelection; + if (button == MouseButton.Left && canDelete && (Archetype.Flags & NodeFlags.NoCloseButton) == 0 && _closeButtonRect.Contains(ref location)) { Surface.Delete(this); return true; diff --git a/Source/Editor/Surface/VisjectSurface.Draw.cs b/Source/Editor/Surface/VisjectSurface.Draw.cs index 5a63fe4de..01277d0d2 100644 --- a/Source/Editor/Surface/VisjectSurface.Draw.cs +++ b/Source/Editor/Surface/VisjectSurface.Draw.cs @@ -225,7 +225,7 @@ namespace FlaxEditor.Surface _rootControl.DrawComments(); - if (IsSelecting) + if (IsBoxSelecting) { DrawSelection(); } diff --git a/Source/Editor/Surface/VisjectSurface.Input.cs b/Source/Editor/Surface/VisjectSurface.Input.cs index a874db681..ced29d819 100644 --- a/Source/Editor/Surface/VisjectSurface.Input.cs +++ b/Source/Editor/Surface/VisjectSurface.Input.cs @@ -544,6 +544,9 @@ namespace FlaxEditor.Surface // Cache flags and state if (_leftMouseDown && button == MouseButton.Left) { + WasBoxSelecting = IsBoxSelecting; + WasMovingSelection = _isMovingSelection; + _leftMouseDown = false; EndMouseCapture(); Cursor = CursorType.Default; diff --git a/Source/Editor/Surface/VisjectSurface.cs b/Source/Editor/Surface/VisjectSurface.cs index faecebbd3..4a1bad1da 100644 --- a/Source/Editor/Surface/VisjectSurface.cs +++ b/Source/Editor/Surface/VisjectSurface.cs @@ -232,15 +232,25 @@ namespace FlaxEditor.Surface } /// - /// Gets a value indicating whether user is selecting nodes. + /// Gets a value indicating whether user is box selecting nodes. /// - public bool IsSelecting => _leftMouseDown && !_isMovingSelection && _connectionInstigator == null; + public bool IsBoxSelecting => _leftMouseDown && !_isMovingSelection && _connectionInstigator == null; + + /// + /// Gets a value indicating whether user was previously box selecting nodes. + /// + public bool WasBoxSelecting { get; private set; } /// /// Gets a value indicating whether user is moving selected nodes. /// public bool IsMovingSelection => _leftMouseDown && _isMovingSelection && _connectionInstigator == null; + /// + /// Gets a value indicating whether user was previously moving selected nodes. + /// + public bool WasMovingSelection { get; private set; } + /// /// Gets a value indicating whether user is connecting nodes. /// From e2f741cab9c512cdd1c39235af93816342908ae4 Mon Sep 17 00:00:00 2001 From: xxSeys1 Date: Thu, 12 Jun 2025 18:45:02 +0200 Subject: [PATCH 28/37] adjust model window and animated model slider speeds --- Source/Editor/Windows/Assets/ModelBaseWindow.cs | 9 +++++---- Source/Editor/Windows/Assets/ModelWindow.cs | 1 + Source/Engine/Level/Actors/AnimatedModel.h | 4 ++-- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/Source/Editor/Windows/Assets/ModelBaseWindow.cs b/Source/Editor/Windows/Assets/ModelBaseWindow.cs index 14344ef71..09b4606c4 100644 --- a/Source/Editor/Windows/Assets/ModelBaseWindow.cs +++ b/Source/Editor/Windows/Assets/ModelBaseWindow.cs @@ -236,6 +236,7 @@ namespace FlaxEditor.Windows.Assets var group = layout.Group("General"); var minScreenSize = group.FloatValue("Min Screen Size", "The minimum screen size to draw model (the bottom limit). Used to cull small models. Set to 0 to disable this feature."); + minScreenSize.ValueBox.SlideSpeed = 0.005f; minScreenSize.ValueBox.MinValue = 0.0f; minScreenSize.ValueBox.MaxValue = 1.0f; minScreenSize.ValueBox.Value = proxy.Asset.MinScreenSize; @@ -476,12 +477,12 @@ namespace FlaxEditor.Windows.Assets } } - [EditorOrder(1), EditorDisplay(null, "LOD"), Limit(0, Model.MaxLODs), VisibleIf("ShowUVs")] - [Tooltip("Level Of Detail index to preview UVs layout.")] + [EditorOrder(1), EditorDisplay(null, "LOD"), Limit(0, Model.MaxLODs, 0.01f), VisibleIf("ShowUVs")] + [Tooltip("Level Of Detail index to preview UVs layout at.")] public int LOD = 0; - [EditorOrder(2), EditorDisplay(null, "Mesh"), Limit(-1, 1000000), VisibleIf("ShowUVs")] - [Tooltip("Mesh index to preview UVs layout. Use -1 for all meshes")] + [EditorOrder(2), EditorDisplay(null, "Mesh"), Limit(-1, 1000000, 0.01f), VisibleIf("ShowUVs")] + [Tooltip("Mesh index to show UVs layout for. Use -1 to display all UVs of all meshes")] public int Mesh = -1; private bool ShowUVs => _uvChannel != UVChannel.None; diff --git a/Source/Editor/Windows/Assets/ModelWindow.cs b/Source/Editor/Windows/Assets/ModelWindow.cs index 9a0b1ad82..1dc30cae3 100644 --- a/Source/Editor/Windows/Assets/ModelWindow.cs +++ b/Source/Editor/Windows/Assets/ModelWindow.cs @@ -81,6 +81,7 @@ namespace FlaxEditor.Windows.Assets } var resolution = group.FloatValue("Resolution Scale", Window.Editor.CodeDocs.GetTooltip(typeof(ModelTool.Options), nameof(ModelImportSettings.Settings.SDFResolution))); + resolution.ValueBox.SlideSpeed = 0.001f; resolution.ValueBox.MinValue = 0.0001f; resolution.ValueBox.MaxValue = 100.0f; resolution.ValueBox.Value = sdf.Texture != null ? sdf.ResolutionScale : 1.0f; diff --git a/Source/Engine/Level/Actors/AnimatedModel.h b/Source/Engine/Level/Actors/AnimatedModel.h index 89124cb87..859d89212 100644 --- a/Source/Engine/Level/Actors/AnimatedModel.h +++ b/Source/Engine/Level/Actors/AnimatedModel.h @@ -110,7 +110,7 @@ public: /// /// The animation update delta timescale. Can be used to speed up animation playback or create slow motion effect. /// - API_FIELD(Attributes="EditorOrder(45), EditorDisplay(\"Skinned Model\")") + API_FIELD(Attributes="EditorOrder(45), Limit(0, float.MaxValue, 0.025f), EditorDisplay(\"Skinned Model\")") float UpdateSpeed = 1.0f; /// @@ -122,7 +122,7 @@ public: /// /// The master scale parameter for the actor bounding box. Helps to reduce mesh flickering effect on screen edges. /// - API_FIELD(Attributes="EditorOrder(60), DefaultValue(1.5f), Limit(0), EditorDisplay(\"Skinned Model\")") + API_FIELD(Attributes="EditorOrder(60), DefaultValue(1.5f), Limit(0, float.MaxValue, 0.025f), EditorDisplay(\"Skinned Model\")") float BoundsScale = 1.5f; /// From 648504ceb113ba21d46b324f3e56acfd7e7772c6 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Sun, 15 Jun 2025 20:31:04 +0200 Subject: [PATCH 29/37] Format code #3544 --- Source/Editor/GUI/ToolStripButton.cs | 24 ++++++++--------- Source/Editor/Windows/DebugLogWindow.cs | 34 ++++++++++--------------- 2 files changed, 26 insertions(+), 32 deletions(-) diff --git a/Source/Editor/GUI/ToolStripButton.cs b/Source/Editor/GUI/ToolStripButton.cs index 56e798a2e..c49cddcbb 100644 --- a/Source/Editor/GUI/ToolStripButton.cs +++ b/Source/Editor/GUI/ToolStripButton.cs @@ -122,6 +122,14 @@ namespace FlaxEditor.GUI return this; } + private void OnClicked() + { + if (AutoCheck) + Checked = !Checked; + Clicked?.Invoke(); + (Parent as ToolStrip)?.OnButtonClicked(this); + } + /// public override void Draw() { @@ -196,11 +204,7 @@ namespace FlaxEditor.GUI if (button == MouseButton.Left && _primaryMouseDown) { _primaryMouseDown = false; - if (AutoCheck) - Checked = !Checked; - Clicked?.Invoke(); - (Parent as ToolStrip)?.OnButtonClicked(this); - + OnClicked(); return true; } if (button == MouseButton.Right && _secondaryMouseDown) @@ -218,16 +222,12 @@ namespace FlaxEditor.GUI /// public override bool OnMouseDoubleClick(Float2 location, MouseButton button) { - if(button == MouseButton.Left) + if (button == MouseButton.Left) { - if (AutoCheck) - Checked = !Checked; - Clicked?.Invoke(); - (Parent as ToolStrip)?.OnButtonClicked(this); - + OnClicked(); return true; } - + return false; } diff --git a/Source/Editor/Windows/DebugLogWindow.cs b/Source/Editor/Windows/DebugLogWindow.cs index d0680c3c0..b5d71f6a0 100644 --- a/Source/Editor/Windows/DebugLogWindow.cs +++ b/Source/Editor/Windows/DebugLogWindow.cs @@ -318,7 +318,7 @@ namespace FlaxEditor.Windows private Color _colorWarning; private Color _colorError; private bool _colorDebugLogText; - + /// /// Initializes a new instance of the class. /// @@ -353,11 +353,11 @@ namespace FlaxEditor.Windows }).SetAutoCheck(true).LinkTooltip("Performs auto pause on error"); toolstrip.AddSeparator(); _groupButtons[0] = (ToolStripButton)toolstrip.AddButton(editor.Icons.Error32, () => { OnGroupButtonPressed(0); }) - .SetAutoCheck(true).LinkTooltip("Shows/hides error messages"); + .SetAutoCheck(true).LinkTooltip("Shows/hides error messages"); _groupButtons[1] = (ToolStripButton)toolstrip.AddButton(editor.Icons.Warning32, () => { OnGroupButtonPressed(1); }) - .SetAutoCheck(true).LinkTooltip("Shows/hides warning messages"); + .SetAutoCheck(true).LinkTooltip("Shows/hides warning messages"); _groupButtons[2] = (ToolStripButton)toolstrip.AddButton(editor.Icons.Info32, () => { OnGroupButtonPressed(2); }) - .SetAutoCheck(true).LinkTooltip("Shows/hides info messages"); + .SetAutoCheck(true).LinkTooltip("Shows/hides info messages"); UpdateCount(); // Split panel @@ -409,21 +409,21 @@ namespace FlaxEditor.Windows private void OnGroupButtonPressed(int index) { UpdateLogTypeVisibility((LogGroup)index, _groupButtons[index].Checked); - if(Input.GetKey(KeyboardKeys.Shift)) + if (Input.GetKey(KeyboardKeys.Shift)) { - for(int i = 0; i < (int)LogGroup.Max; i++) + for (int i = 0; i < (int)LogGroup.Max; i++) { - if(i == index) + if (i == index) continue; - _groupButtons[i].Checked = !_groupButtons[index].Checked; UpdateLogTypeVisibility((LogGroup)i, _groupButtons[i].Checked); } } - Editor.Options.Options.Interface.DebugLogShowErrorMessages = _groupButtons[0].Checked; - Editor.Options.Options.Interface.DebugLogShowWarningMessages = _groupButtons[1].Checked; - Editor.Options.Options.Interface.DebugLogShowInfoMessages = _groupButtons[2].Checked; + var options = Editor.Options.Options.Interface; + options.DebugLogShowErrorMessages = _groupButtons[0].Checked; + options.DebugLogShowWarningMessages = _groupButtons[1].Checked; + options.DebugLogShowInfoMessages = _groupButtons[2].Checked; Editor.Options.Apply(Editor.Options.Options); } @@ -464,15 +464,9 @@ namespace FlaxEditor.Windows // Create new entry switch (_timestampsFormats) { - case InterfaceOptions.TimestampsFormats.Utc: - desc.Title = $"[{DateTime.UtcNow}] {desc.Title}"; - break; - case InterfaceOptions.TimestampsFormats.LocalTime: - desc.Title = $"[{DateTime.Now}] {desc.Title}"; - break; - case InterfaceOptions.TimestampsFormats.TimeSinceStartup: - desc.Title = string.Format("[{0:g}] ", TimeSpan.FromSeconds(Time.TimeSinceStartup)) + desc.Title; - break; + case InterfaceOptions.TimestampsFormats.Utc: desc.Title = $"[{DateTime.UtcNow}] {desc.Title}"; break; + case InterfaceOptions.TimestampsFormats.LocalTime: desc.Title = $"[{DateTime.Now}] {desc.Title}"; break; + case InterfaceOptions.TimestampsFormats.TimeSinceStartup: desc.Title = string.Format("[{0:g}] ", TimeSpan.FromSeconds(Time.TimeSinceStartup)) + desc.Title; break; } var newEntry = new LogEntry(this, ref desc); From 2f02ec52ed3d42e4f64f1487a36c6408625d57ba Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Sun, 15 Jun 2025 20:48:19 +0200 Subject: [PATCH 30/37] Cleanup code #3546 --- .../Editor/Windows/Assets/ParticleEmitterWindow.cs | 7 +++---- Source/Engine/Particles/ParticleEmitter.cpp | 13 +++++-------- Source/Engine/Particles/ParticleEmitter.h | 5 ++--- 3 files changed, 10 insertions(+), 15 deletions(-) diff --git a/Source/Editor/Windows/Assets/ParticleEmitterWindow.cs b/Source/Editor/Windows/Assets/ParticleEmitterWindow.cs index bc1f49443..6513ac9e0 100644 --- a/Source/Editor/Windows/Assets/ParticleEmitterWindow.cs +++ b/Source/Editor/Windows/Assets/ParticleEmitterWindow.cs @@ -288,16 +288,15 @@ namespace FlaxEditor.Windows.Assets /// public SearchAssetTypes AssetType => SearchAssetTypes.ParticleEmitter; - + /// public override void Update(float deltaTime) { base.Update(deltaTime); - if(_asset == null) + if (_asset == null) return; - - _showSourceCodeButton.Enabled = _asset.HasShaderCode(); + _showSourceCodeButton.Enabled = _asset.HasShaderCode; } } } diff --git a/Source/Engine/Particles/ParticleEmitter.cpp b/Source/Engine/Particles/ParticleEmitter.cpp index 4490406bc..6264ce412 100644 --- a/Source/Engine/Particles/ParticleEmitter.cpp +++ b/Source/Engine/Particles/ParticleEmitter.cpp @@ -440,20 +440,17 @@ bool ParticleEmitter::Save(const StringView& path) return SaveSurface(data); } -bool ParticleEmitter::HasShaderCode() +bool ParticleEmitter::HasShaderCode() const { - if(SimulationMode != ParticlesSimulationMode::GPU) - { + if (SimulationMode != ParticlesSimulationMode::GPU) return false; - } - #if COMPILE_WITH_PARTICLE_GPU_GRAPH && COMPILE_WITH_SHADER_COMPILER - if(_shaderHeader.ParticleEmitter.GraphVersion == PARTICLE_GPU_GRAPH_VERSION +#if COMPILE_WITH_PARTICLE_GPU_GRAPH && COMPILE_WITH_SHADER_COMPILER + if (_shaderHeader.ParticleEmitter.GraphVersion == PARTICLE_GPU_GRAPH_VERSION && HasChunk(SHADER_FILE_CHUNK_SOURCE) && !HasDependenciesModified()) return true; - #endif - +#endif return false; } diff --git a/Source/Engine/Particles/ParticleEmitter.h b/Source/Engine/Particles/ParticleEmitter.h index 4b27036f7..772f5569e 100644 --- a/Source/Engine/Particles/ParticleEmitter.h +++ b/Source/Engine/Particles/ParticleEmitter.h @@ -175,10 +175,9 @@ public: bool Save(const StringView& path = StringView::Empty) override; /// - /// Determine if the particle emitter has valid shader code present. + /// Checks if the particle emitter has valid shader code present. /// - /// True if particle emitter has shader code, otherwise false. - API_FUNCTION() bool HasShaderCode(); + API_PROPERTY() bool HasShaderCode() const; #endif protected: From ea854a0f7b6864ca4c12ffedd8b6679064433755 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Mon, 16 Jun 2025 14:41:43 +0200 Subject: [PATCH 31/37] Fix potential Grid shader accuracy issues #3229 --- Content/Shaders/Editor/Grid.flax | 4 ++-- Source/Shaders/Editor/Grid.shader | 11 +++-------- 2 files changed, 5 insertions(+), 10 deletions(-) diff --git a/Content/Shaders/Editor/Grid.flax b/Content/Shaders/Editor/Grid.flax index 311867604..09ecd00e6 100644 --- a/Content/Shaders/Editor/Grid.flax +++ b/Content/Shaders/Editor/Grid.flax @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:c13729c4ec2ef534271c60fee6fff2e0489bf4445fe91aa8a2bbc3d581715602 -size 4666 +oid sha256:e5671b8b77b460a17d0a3c14174994a05cf1b3d8869d10b350de4a8053419836 +size 4647 diff --git a/Source/Shaders/Editor/Grid.shader b/Source/Shaders/Editor/Grid.shader index f109ddd1a..45bb1ed90 100644 --- a/Source/Shaders/Editor/Grid.shader +++ b/Source/Shaders/Editor/Grid.shader @@ -3,7 +3,7 @@ // Ben Golus // https://bgolus.medium.com/the-best-darn-grid-shader-yet-727f9278b9d8#3e73 -#define USE_FORWARD true; +#define MIN_DERIV 0.00001f #include "./Flax/Common.hlsl" @@ -61,11 +61,6 @@ float remap(float origFrom, float origTo, float targetFrom, float targetTo, floa return lerp(targetFrom, targetTo, rel); } -float ddLength(float a) -{ - return length(float2(ddx(a), ddy(a))); -} - float GetLine(float pos, float scale, float thickness) { float lineWidth = thickness; @@ -73,7 +68,7 @@ float GetLine(float pos, float scale, float thickness) float2 uvDDXY = float2(ddx(coord), ddy(coord)); - float deriv = float(length(uvDDXY.xy)); + float deriv = max(float(length(uvDDXY.xy)), MIN_DERIV); float drawWidth = clamp(lineWidth, deriv, 0.5); float lineAA = deriv * 1.5; float gridUV = abs(coord); @@ -92,7 +87,7 @@ float GetGrid(float3 pos, float scale, float thickness) float4 uvDDXY = float4(ddx(coord), ddy(coord)); - float2 deriv = float2(length(uvDDXY.xz), length(uvDDXY.yw)); + float2 deriv = max(float2(length(uvDDXY.xz), length(uvDDXY.yw)), float2(MIN_DERIV, MIN_DERIV)); float2 drawWidth = clamp(lineWidth, deriv, 0.5); float2 lineAA = deriv * 1.5; float2 gridUV = 1.0 - abs(frac(coord) * 2.0 - 1.0); From a6a2fd2c66c919ac3ad609fbb59b88054083512f Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Mon, 16 Jun 2025 14:48:18 +0200 Subject: [PATCH 32/37] Format code #3526 --- Source/Editor/GUI/Tree/Tree.cs | 6 +++--- Source/Editor/Windows/SceneTreeWindow.cs | 12 +++++++----- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/Source/Editor/GUI/Tree/Tree.cs b/Source/Editor/GUI/Tree/Tree.cs index 3e1453f03..8df26c211 100644 --- a/Source/Editor/GUI/Tree/Tree.cs +++ b/Source/Editor/GUI/Tree/Tree.cs @@ -74,9 +74,9 @@ namespace FlaxEditor.GUI.Tree public bool DrawRootTreeLine = true; /// - /// Occurs when the defered layouting happens + /// Occurs when the deferred layout operation was performed. /// - public event Action OnDeferedLayout; + public event Action AfterDeferredLayout; /// /// Gets or sets the margin for the child tree nodes. @@ -380,7 +380,7 @@ namespace FlaxEditor.GUI.Tree if (_deferLayoutUpdate) { base.PerformLayout(); - OnDeferedLayout?.Invoke(); + AfterDeferredLayout?.Invoke(); _deferLayoutUpdate = false; } diff --git a/Source/Editor/Windows/SceneTreeWindow.cs b/Source/Editor/Windows/SceneTreeWindow.cs index 620300485..3c7583b0e 100644 --- a/Source/Editor/Windows/SceneTreeWindow.cs +++ b/Source/Editor/Windows/SceneTreeWindow.cs @@ -92,14 +92,15 @@ namespace FlaxEditor.Windows _tree.SelectedChanged += Tree_OnSelectedChanged; _tree.RightClick += OnTreeRightClick; _tree.Parent = _sceneTreePanel; - _tree.OnDeferedLayout += () => { - if(_forceScrollNodeToView) + _tree.AfterDeferredLayout += () => + { + if (_forceScrollNodeToView) { _forceScrollNodeToView = false; ScrollToSelectedNode(); } }; - + headerPanel.Parent = this; // Setup input actions @@ -151,9 +152,10 @@ namespace FlaxEditor.Windows root.TreeNode.UpdateFilter(query); _tree.UnlockChildrenRecursive(); - + + // When keep the selected nodes in a view var nodeSelection = _tree.Selection; - if(nodeSelection.Count != 0) + if (nodeSelection.Count != 0) { var node = nodeSelection[nodeSelection.Count - 1]; node.Expand(true); From 90b6293bc279ef4a816b948a3da6351bead6a234 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Mon, 16 Jun 2025 14:56:35 +0200 Subject: [PATCH 33/37] Add `OnPlayEnding` to editor modules and windows #3514 --- Source/Editor/Editor.cs | 2 ++ Source/Editor/Modules/EditorModule.cs | 7 +++++++ Source/Editor/Modules/WindowsModule.cs | 7 +++++++ Source/Editor/Windows/EditorWindow.cs | 7 +++++++ 4 files changed, 23 insertions(+) diff --git a/Source/Editor/Editor.cs b/Source/Editor/Editor.cs index c6ead7a76..8c3256eb9 100644 --- a/Source/Editor/Editor.cs +++ b/Source/Editor/Editor.cs @@ -670,6 +670,8 @@ namespace FlaxEditor { FlaxEngine.Networking.NetworkManager.Stop(); // Shutdown any multiplayer from playmode PlayModeEnding?.Invoke(); + for (int i = 0; i < _modules.Count; i++) + _modules[i].OnPlayEnding(); } internal void OnPlayEnd() diff --git a/Source/Editor/Modules/EditorModule.cs b/Source/Editor/Modules/EditorModule.cs index 8285088fa..410453302 100644 --- a/Source/Editor/Modules/EditorModule.cs +++ b/Source/Editor/Modules/EditorModule.cs @@ -76,6 +76,13 @@ namespace FlaxEditor.Modules { } + /// + /// Called when Editor will leave the play mode. + /// + public virtual void OnPlayEnding() + { + } + /// /// Called when Editor leaves the play mode. /// diff --git a/Source/Editor/Modules/WindowsModule.cs b/Source/Editor/Modules/WindowsModule.cs index 289c5d7e8..5c9c613d2 100644 --- a/Source/Editor/Modules/WindowsModule.cs +++ b/Source/Editor/Modules/WindowsModule.cs @@ -1223,6 +1223,13 @@ namespace FlaxEditor.Modules Windows[i].OnPlayBegin(); } + /// + public override void OnPlayEnding() + { + for (int i = 0; i < Windows.Count; i++) + Windows[i].OnPlayEnding(); + } + /// public override void OnPlayEnd() { diff --git a/Source/Editor/Windows/EditorWindow.cs b/Source/Editor/Windows/EditorWindow.cs index f61f5cce6..6d01432ba 100644 --- a/Source/Editor/Windows/EditorWindow.cs +++ b/Source/Editor/Windows/EditorWindow.cs @@ -219,6 +219,13 @@ namespace FlaxEditor.Windows { } + /// + /// Called when Editor will leave the play mode. + /// + public virtual void OnPlayEnding() + { + } + /// /// Called when Editor leaves the play mode. /// From 97b37b3ce468f8f674ff88e1600670a65cc66f5f Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Mon, 16 Jun 2025 18:00:26 +0200 Subject: [PATCH 34/37] Add `PRAGMA_DISABLE_OPTIMIZATION`/`PRAGMA_ENABLE_OPTIMIZATION` --- Source/Engine/Core/Compiler.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Source/Engine/Core/Compiler.h b/Source/Engine/Core/Compiler.h index fb731930e..a45a4628a 100644 --- a/Source/Engine/Core/Compiler.h +++ b/Source/Engine/Core/Compiler.h @@ -26,6 +26,8 @@ _Pragma("clang diagnostic ignored \"-Wdeprecated-declarations\"") #define PRAGMA_ENABLE_DEPRECATION_WARNINGS \ _Pragma("clang diagnostic pop") +#define PRAGMA_DISABLE_OPTIMIZATION +#define PRAGMA_ENABLE_OPTIMIZATION #pragma clang diagnostic ignored "-Wswitch" #pragma clang diagnostic ignored "-Wmacro-redefined" @@ -54,6 +56,8 @@ #define OFFSET_OF(X, Y) __builtin_offsetof(X, Y) #define PRAGMA_DISABLE_DEPRECATION_WARNINGS #define PRAGMA_ENABLE_DEPRECATION_WARNINGS +#define PRAGMA_DISABLE_OPTIMIZATION +#define PRAGMA_ENABLE_OPTIMIZATION #elif defined(_MSC_VER) @@ -86,6 +90,8 @@ __pragma(warning(disable: 4996)) #define PRAGMA_ENABLE_DEPRECATION_WARNINGS \ __pragma (warning(pop)) +#define PRAGMA_DISABLE_OPTIMIZATION __pragma(optimize("", off)) +#define PRAGMA_ENABLE_OPTIMIZATION __pragma(optimize("", on)) #pragma warning(disable: 4251) From 6a82eb114dcf222ad5093b97d6c5004f7eb7cc67 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Mon, 16 Jun 2025 19:05:44 +0200 Subject: [PATCH 35/37] Fix `BitArray` bit indexing --- Source/Engine/Core/Collections/BitArray.h | 13 ++++----- Source/Engine/Tests/TestCollections.cpp | 32 ++++++++++++++++++++--- 2 files changed, 36 insertions(+), 9 deletions(-) diff --git a/Source/Engine/Core/Collections/BitArray.h b/Source/Engine/Core/Collections/BitArray.h index 8206f2164..6589fa9a1 100644 --- a/Source/Engine/Core/Collections/BitArray.h +++ b/Source/Engine/Core/Collections/BitArray.h @@ -16,6 +16,7 @@ API_CLASS(InBuild) class BitArray public: using ItemType = uint64; using AllocationData = typename AllocationType::template Data; + static constexpr int32 ItemBitCount = 64; private: int32 _count; @@ -209,8 +210,8 @@ public: bool Get(const int32 index) const { ASSERT(index >= 0 && index < _count); - const ItemType offset = index / sizeof(ItemType); - const ItemType bitMask = (ItemType)(int32)(1 << (index & ((int32)sizeof(ItemType) - 1))); + const ItemType offset = index / ItemBitCount; + const ItemType bitMask = (ItemType)(1 << (index & (ItemBitCount - 1))); const ItemType item = ((ItemType*)_allocation.Get())[offset]; return (item & bitMask) != 0; } @@ -223,13 +224,13 @@ public: void Set(const int32 index, const bool value) { ASSERT(index >= 0 && index < _count); - const ItemType offset = index / sizeof(ItemType); - const ItemType bitMask = (ItemType)(int32)(1 << (index & ((int32)sizeof(ItemType) - 1))); + const ItemType offset = index / ItemBitCount; + const ItemType bitMask = (ItemType)(1 << (index & (ItemBitCount - 1))); ItemType& item = ((ItemType*)_allocation.Get())[offset]; if (value) - item |= bitMask; + item |= bitMask; // Set the bit else - item &= ~bitMask; // Clear the bit + item &= ~bitMask; // Unset the bit } public: diff --git a/Source/Engine/Tests/TestCollections.cpp b/Source/Engine/Tests/TestCollections.cpp index fd0f3328d..b477140cf 100644 --- a/Source/Engine/Tests/TestCollections.cpp +++ b/Source/Engine/Tests/TestCollections.cpp @@ -78,6 +78,32 @@ TEST_CASE("Array") TEST_CASE("BitArray") { + SECTION("Test Access") + { + BitArray<> a1; + CHECK(a1.Count() == 0); + for (int32 i = 0; i < 310; i++) + { + a1.Add(false); + } + CHECK(a1.Count() == 310); + a1.Resize(300); + CHECK(a1.Count() == 300); + CHECK(a1.Capacity() >= 300); + a1.SetAll(true); + a1.SetAll(false); + for (int32 i = 0; i < 300; i++) + { + a1.Set(i, true); + for (int32 j = 0; j < 300; j++) + { + bool expected = j == i; + CHECK(a1.Get(j) == expected); + } + a1.Set(i, false); + } + } + SECTION("Test Allocators") { BitArray<> a1; @@ -142,7 +168,7 @@ TEST_CASE("BitArray") // Generate some random data for testing BitArray<> testData; - testData.Resize(32); + testData.Resize(128); RandomStream rand(101); for (int32 i = 0; i < testData.Count(); i++) testData.Set(i, rand.GetBool()); @@ -151,8 +177,8 @@ TEST_CASE("BitArray") { const BitArray<> a1(testData); const BitArray> a2(testData); - const BitArray> a3(testData); - const BitArray> a4(testData); + const BitArray> a3(testData); + const BitArray> a4(testData); CHECK(a1 == testData); CHECK(a2 == testData); CHECK(a3 == testData); From b92c18cf250a7cdc26c75d6867b128975a3871f2 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Mon, 16 Jun 2025 19:10:35 +0200 Subject: [PATCH 36/37] Fix missing/incorrect toolchain exception to log only once --- Source/Tools/Flax.Build/Build/Platform.cs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Source/Tools/Flax.Build/Build/Platform.cs b/Source/Tools/Flax.Build/Build/Platform.cs index 6304cdc4a..59572d669 100644 --- a/Source/Tools/Flax.Build/Build/Platform.cs +++ b/Source/Tools/Flax.Build/Build/Platform.cs @@ -17,6 +17,7 @@ namespace Flax.Build private static Platform _buildPlatform; private static Platform[] _platforms; private Dictionary _toolchains; + private uint _failedArchitectures = 0; /// /// Gets the current target platform that build tool runs on. @@ -251,7 +252,8 @@ namespace Flax.Build public Toolchain TryGetToolchain(TargetArchitecture targetArchitecture) { Toolchain result = null; - if (HasRequiredSDKsInstalled) + uint failedMask = 1u << (int)targetArchitecture; // Skip retrying if it already failed once on this arch + if (HasRequiredSDKsInstalled && (_failedArchitectures & failedMask) != failedMask) { try { @@ -259,6 +261,7 @@ namespace Flax.Build } catch (Exception ex) { + _failedArchitectures |= failedMask; Log.Exception(ex); } } From 5a23060e05623f08a2d67391502e623ac7d40a66 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Mon, 16 Jun 2025 22:35:50 +0200 Subject: [PATCH 37/37] Add `GPUTexture.UploadData` for changing texture contents via `TextureData` container --- Source/Engine/Graphics/Textures/GPUTexture.cpp | 17 +++++++++++++++++ Source/Engine/Graphics/Textures/GPUTexture.h | 12 ++++++++++-- 2 files changed, 27 insertions(+), 2 deletions(-) diff --git a/Source/Engine/Graphics/Textures/GPUTexture.cpp b/Source/Engine/Graphics/Textures/GPUTexture.cpp index 127cf2f5b..59b025b70 100644 --- a/Source/Engine/Graphics/Textures/GPUTexture.cpp +++ b/Source/Engine/Graphics/Textures/GPUTexture.cpp @@ -630,6 +630,23 @@ GPUTask* GPUTexture::UploadMipMapAsync(const BytesContainer& data, int32 mipInde return task; } +bool GPUTexture::UploadData(TextureData& data, bool copyData) +{ + if (!IsAllocated()) + return true; + if (data.Width != Width() || data.Height != Height() || data.Depth != Depth() || data.GetArraySize() != ArraySize() || data.Format != Format()) + return true; + for (int32 arrayIndex = 0; arrayIndex < ArraySize(); arrayIndex++) + { + for (int32 mipLevel = 0; mipLevel < MipLevels(); mipLevel++) + { + TextureMipData* mip = data.GetData(arrayIndex, mipLevel); + UploadMipMapAsync(mip->Data, mipLevel, mip->RowPitch, mip->DepthPitch, copyData); + } + } + return false; +} + class TextureDownloadDataTask : public ThreadPoolTask { private: diff --git a/Source/Engine/Graphics/Textures/GPUTexture.h b/Source/Engine/Graphics/Textures/GPUTexture.h index 977723f26..85ac4ae0b 100644 --- a/Source/Engine/Graphics/Textures/GPUTexture.h +++ b/Source/Engine/Graphics/Textures/GPUTexture.h @@ -499,7 +499,7 @@ public: /// /// Uploads mip map data to the GPU. Creates async GPU task. /// - /// Data to upload (it must be valid for the next a few frames due to GPU latency and async works executing) + /// Data to upload, it must match texture dimensions. It must be valid for the next couple of frames due to GPU async task latency or use data copy. /// Mip level index. /// If true, the data will be copied to the async execution task instead of using the input pointer provided. /// Created async task or null if cannot. @@ -508,7 +508,7 @@ public: /// /// Uploads mip map data to the GPU. Creates async GPU task. /// - /// Data to upload (it must be valid for the next a few frames due to GPU latency and async works executing) + /// Data to upload, it must match texture dimensions. It must be valid for the next couple of frames due to GPU async task latency or use data copy. /// Mip level index. /// The data row pitch. /// The data slice pitch. @@ -516,6 +516,14 @@ public: /// Created async task or null if cannot. GPUTask* UploadMipMapAsync(const BytesContainer& data, int32 mipIndex, int32 rowPitch, int32 slicePitch, bool copyData = false); + /// + /// Uploads texture data to the GPU. Actual data copy to the GPU memory is performed via async task. + /// + /// Data to upload, it must match texture dimensions. It must be valid for the next couple of frames due to GPU async task latency or use data copy. + /// If true, the data will be copied to the async execution task instead of using the input pointer provided. + /// True if cannot upload data, otherwise false. + API_FUNCTION() bool UploadData(TextureData& data, bool copyData = false); + /// /// Downloads the texture data to be accessible from CPU. For frequent access, use staging textures, otherwise current thread will be stalled to wait for the GPU frame to copy data into staging buffer. ///