diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index ada5e5fa5..7f91b6ddc 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -26,7 +26,7 @@ Go check out our [Trello](https://trello.com/b/NQjLXRCP/flax-roadmap).
* For feature PR's the first thing you should evaluate is the value of your contribution, as in, what would it bring to this engine? Is it really required?
If its a small change you could preferably suggest it to us on our discord, else feel free to open up a PR for it.
-* Ensure when creating a PR that your contribution is well explained with a adequate description and title.
+* Ensure when creating a PR that your contribution is well explained with an adequate description and title.
* Generally, good code quality is expected, make sure your contribution works as intended and is appropriately commented where necessary.
diff --git a/Flax.flaxproj b/Flax.flaxproj
index ed79458d2..e6d7badcc 100644
--- a/Flax.flaxproj
+++ b/Flax.flaxproj
@@ -4,7 +4,7 @@
"Major": 1,
"Minor": 12,
"Revision": 0,
- "Build": 6914
+ "Build": 6915
},
"Company": "Flax",
"Copyright": "Copyright (c) 2012-2026 Wojciech Figat. All rights reserved.",
diff --git a/Source/Editor/CustomEditors/CustomEditorPresenter.cs b/Source/Editor/CustomEditors/CustomEditorPresenter.cs
index c7832cfe1..94496c334 100644
--- a/Source/Editor/CustomEditors/CustomEditorPresenter.cs
+++ b/Source/Editor/CustomEditors/CustomEditorPresenter.cs
@@ -8,6 +8,7 @@ using FlaxEditor.Scripting;
using FlaxEngine;
using FlaxEngine.GUI;
using FlaxEngine.Utilities;
+using FlaxEditor.CustomEditors.GUI;
namespace FlaxEditor.CustomEditors
{
@@ -244,10 +245,15 @@ namespace FlaxEditor.CustomEditors
protected readonly RootEditor Editor;
///
- /// The selected objects list (read-only).
+ /// The current selection.
///
public readonly ValueContainer Selection = new ValueContainer(ScriptMemberInfo.Null);
+ ///
+ /// The current properties search query.
+ ///
+ public string SearchText = string.Empty;
+
///
/// The undo object used by this editor.
///
@@ -529,6 +535,256 @@ namespace FlaxEditor.CustomEditors
Editor?.RefreshInternal();
}
+ ///
+ /// Applies search filter query to the presenter layout controls.
+ ///
+ public void ApplySearchFilter(string query)
+ {
+ SearchText = query;
+ if (Root == null)
+ return;
+
+ var isQueryEmpty = string.IsNullOrEmpty(query);
+ var groupMatchCache = new Dictionary();
+ UpdateFilter(Root, query, isQueryEmpty, groupMatchCache);
+ UpdatePropertiesListsVisibility(Panel, query);
+ UpdateGroupsVisibility(Panel, query);
+ Panel.PerformLayout();
+ }
+
+ ///
+ /// Updates the visibility of properties lists and drop panels based on the current search query.
+ ///
+ public void UpdateGroupsAndListsVisibility()
+ {
+ if (string.IsNullOrEmpty(SearchText))
+ {
+ RestoreVisibilities(Panel);
+ }
+ else
+ {
+ UpdatePropertiesListsVisibility(Panel, SearchText);
+ UpdateGroupsVisibility(Panel, SearchText);
+ }
+ Panel.PerformLayout();
+ }
+
+ private void RestoreVisibilities(Control control)
+ {
+ if (control is DropPanel dropPanel)
+ {
+ dropPanel.SearchText = string.Empty;
+ dropPanel.Visible = true;
+ }
+ else if (control is PropertiesList list)
+ {
+ list.Visible = true;
+ }
+
+ if (control is ContainerControl container)
+ {
+ for (int i = 0; i < container.ChildrenCount; i++)
+ {
+ RestoreVisibilities(container.GetChild(i));
+ }
+ }
+ }
+
+ private void UpdatePropertiesListsVisibility(Control control, string query)
+ {
+ if (control is PropertiesList list)
+ {
+ if (string.IsNullOrEmpty(query))
+ {
+ list.Visible = true;
+ }
+ else
+ {
+ bool anyVisible = false;
+ foreach (var label in list.Element.Labels)
+ {
+ if (label.Visible)
+ {
+ anyVisible = true;
+ break;
+ }
+ }
+ list.Visible = anyVisible;
+ }
+ }
+
+ if (control is ContainerControl container)
+ {
+ for (int i = 0; i < container.ChildrenCount; i++)
+ {
+ UpdatePropertiesListsVisibility(container.GetChild(i), query);
+ }
+ }
+ }
+
+ private void UpdateGroupsVisibility(Control control, string query)
+ {
+ if (control is DropPanel dropPanel)
+ {
+ dropPanel.SearchText = query;
+ for (int i = 0; i < dropPanel.ChildrenCount; i++)
+ {
+ UpdateGroupsVisibility(dropPanel.GetChild(i), query);
+ }
+
+ if (string.IsNullOrEmpty(query))
+ {
+ dropPanel.Visible = true;
+ }
+ else
+ {
+ dropPanel.Visible = HasVisibleDescendants(dropPanel);
+ }
+ }
+ else if (control is ContainerControl container)
+ {
+ for (int i = 0; i < container.ChildrenCount; i++)
+ {
+ UpdateGroupsVisibility(container.GetChild(i), query);
+ }
+ }
+ }
+
+ private bool HasVisibleDescendants(ContainerControl container)
+ {
+ for (int i = 0; i < container.ChildrenCount; i++)
+ {
+ var child = container.GetChild(i);
+ if (child is PropertyNameLabel label && label.Visible)
+ {
+ return true;
+ }
+ if (child is DropPanel dropPanel && dropPanel.Visible)
+ {
+ return true;
+ }
+ if (child is ContainerControl subContainer && subContainer.Visible && HasVisibleDescendants(subContainer))
+ {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private bool IsInMatchingGroup(Control control, string query, Dictionary groupMatchCache)
+ {
+ if (string.IsNullOrEmpty(query))
+ return false;
+
+ var p = control.Parent;
+ while (p != null)
+ {
+ if (p is DropPanel dropPanel)
+ {
+ if (!groupMatchCache.TryGetValue(dropPanel, out bool matches))
+ {
+ var headerText = dropPanel.HeaderText;
+ matches = headerText != null && headerText.IndexOf(query, StringComparison.OrdinalIgnoreCase) >= 0;
+ groupMatchCache[dropPanel] = matches;
+ }
+ if (matches)
+ return true;
+ }
+ p = p.Parent;
+ }
+ return false;
+ }
+
+ private bool UpdateFilter(CustomEditor editor, string query, bool forceVisible, Dictionary groupMatchCache)
+ {
+ bool isVisible = false;
+
+ bool labelMatches = false;
+ if (editor.LinkedLabel != null)
+ {
+ editor.LinkedLabel.SearchText = query;
+ if (forceVisible)
+ {
+ labelMatches = true;
+ }
+ else if (!string.IsNullOrEmpty(query))
+ {
+ var labelText = editor.LinkedLabel.Text.ToString();
+ if (labelText.IndexOf(query, StringComparison.OrdinalIgnoreCase) >= 0)
+ {
+ labelMatches = true;
+ }
+ else if (IsInMatchingGroup(editor.LinkedLabel, query, groupMatchCache))
+ {
+ labelMatches = true;
+ }
+ }
+ }
+
+ bool isThisEditorVisible = forceVisible || labelMatches;
+
+ bool anyChildVisible = false;
+ bool forceChildrenVisible = isThisEditorVisible;
+
+ foreach (var child in editor.ChildrenEditors)
+ {
+ if (UpdateFilter(child, query, forceChildrenVisible, groupMatchCache))
+ {
+ anyChildVisible = true;
+ }
+ }
+
+ isVisible = isThisEditorVisible || anyChildVisible;
+
+ if (editor.LinkedLabel != null)
+ {
+ SetLabelAndControlsVisible(editor.LinkedLabel, isVisible);
+ }
+
+ if (editor.Style == DisplayStyle.Group && editor.Layout != null && editor.Layout.Control != null)
+ {
+ editor.Layout.Control.Visible = isVisible;
+ }
+
+ return isVisible;
+ }
+
+ private void SetLabelAndControlsVisible(PropertyNameLabel label, bool visible)
+ {
+ label.Visible = visible;
+ var container = label.FirstChildControlContainer ?? label.Parent as PropertiesList;
+ if (container != null)
+ {
+ int startIndex = label.FirstChildControlIndex;
+ if (startIndex >= 0)
+ {
+ int endIndex = container.Children.Count;
+ var labels = container.Element.Labels;
+ int labelIndex = labels.IndexOf(label);
+ if (labelIndex >= 0 && labelIndex < labels.Count - 1)
+ {
+ for (int i = labelIndex + 1; i < labels.Count; i++)
+ {
+ var nextContainer = labels[i].FirstChildControlContainer ?? labels[i].Parent as PropertiesList;
+ if (nextContainer == container)
+ {
+ endIndex = labels[i].FirstChildControlIndex - 1;
+ break;
+ }
+ }
+ }
+
+ for (int i = startIndex; i < endIndex; i++)
+ {
+ if (i < container.Children.Count)
+ {
+ container.Children[i].Visible = visible;
+ }
+ }
+ }
+ }
+ }
+
///
public override ContainerControl ContainerControl => Panel;
}
diff --git a/Source/Editor/CustomEditors/Editors/GenericEditor.cs b/Source/Editor/CustomEditors/Editors/GenericEditor.cs
index a20b41f8c..900fc6c8d 100644
--- a/Source/Editor/CustomEditors/Editors/GenericEditor.cs
+++ b/Source/Editor/CustomEditors/Editors/GenericEditor.cs
@@ -868,6 +868,28 @@ namespace FlaxEditor.CustomEditors.Editors
if (c.LabelIndex != -1 && c.PropertiesList != null && c.PropertiesList.Labels.Count > c.LabelIndex)
{
var label = c.PropertiesList.Labels[c.LabelIndex];
+ if (visible && Presenter != null && !string.IsNullOrEmpty(Presenter.SearchText))
+ {
+ bool match = label.Text.ToString().IndexOf(Presenter.SearchText, StringComparison.OrdinalIgnoreCase) >= 0;
+ if (!match)
+ {
+ var p = label.Parent;
+ while (p != null)
+ {
+ if (p is DropPanel dropPanel)
+ {
+ var headerText = dropPanel.HeaderText;
+ if (headerText != null && headerText.IndexOf(Presenter.SearchText, StringComparison.OrdinalIgnoreCase) >= 0)
+ {
+ match = true;
+ break;
+ }
+ }
+ p = p.Parent;
+ }
+ }
+ visible = match;
+ }
label.Visible = visible;
for (int j = label.FirstChildControlIndex; j < c.PropertiesList.Properties.Children.Count; j++)
{
@@ -908,6 +930,10 @@ namespace FlaxEditor.CustomEditors.Editors
_visibleIfCaches = null;
}
}
+ if (Presenter != null && !string.IsNullOrEmpty(Presenter.SearchText))
+ {
+ Presenter.UpdateGroupsAndListsVisibility();
+ }
base.Refresh();
}
diff --git a/Source/Editor/CustomEditors/GUI/PropertyNameLabel.cs b/Source/Editor/CustomEditors/GUI/PropertyNameLabel.cs
index c509dd1d2..3108d0a7e 100644
--- a/Source/Editor/CustomEditors/GUI/PropertyNameLabel.cs
+++ b/Source/Editor/CustomEditors/GUI/PropertyNameLabel.cs
@@ -1,6 +1,7 @@
// Copyright (c) Wojciech Figat. All rights reserved.
using FlaxEditor.GUI.ContextMenu;
+using FlaxEditor.Utilities;
using FlaxEngine;
using FlaxEngine.GUI;
@@ -45,6 +46,34 @@ namespace FlaxEditor.CustomEditors.GUI
///
public Color HighlightStripColor;
+ ///
+ /// The active search text query used to highlight matching parts of the label.
+ ///
+ public string SearchText = string.Empty;
+
+ private string _lastSearchText;
+ private string _lastText;
+ private QueryFilterHelper.Range[] _highlightRanges;
+
+ private void UpdateHighlights()
+ {
+ var text = Text?.ToString() ?? string.Empty;
+ if (_lastSearchText == SearchText && _lastText == text)
+ return;
+
+ _lastSearchText = SearchText;
+ _lastText = text;
+
+ if (!string.IsNullOrEmpty(SearchText))
+ {
+ QueryFilterHelper.Match(SearchText, text, out _highlightRanges);
+ }
+ else
+ {
+ _highlightRanges = null;
+ }
+ }
+
///
/// Occurs when label creates the context menu popup for th property. Can be used to add some custom logic per property editor.
///
@@ -83,6 +112,31 @@ namespace FlaxEditor.CustomEditors.GUI
{
Render2D.FillRectangle(new Rectangle(0, 0, 2, Height), HighlightStripColor);
}
+
+ UpdateHighlights();
+
+ if (_highlightRanges != null && _highlightRanges.Length > 0)
+ {
+ var text = Text.ToString();
+ var font = Font?.GetFont();
+ if (font != null)
+ {
+ var style = Style.Current;
+ var color = style.ProgressNormal * 0.6f;
+ var margin = Margin;
+ var textSize = font.MeasureText(text);
+ var textX = margin.Left;
+ var textY = margin.Top + (Height - margin.Height - textSize.Y) * 0.5f;
+
+ for (int i = 0; i < _highlightRanges.Length; i++)
+ {
+ var start = font.GetCharPosition(text, _highlightRanges[i].StartIndex);
+ var end = font.GetCharPosition(text, _highlightRanges[i].EndIndex);
+ var highlightRect = new Rectangle(start.X + textX, textY, end.X - start.X, textSize.Y);
+ Render2D.FillRectangle(highlightRect, color);
+ }
+ }
+ }
}
///
diff --git a/Source/Editor/Editor.cs b/Source/Editor/Editor.cs
index a1b1873ba..7e624efd3 100644
--- a/Source/Editor/Editor.cs
+++ b/Source/Editor/Editor.cs
@@ -1337,10 +1337,7 @@ namespace FlaxEditor
{
var scenes = Level.Scenes;
for (int i = 0; i < scenes.Length; i++)
- {
scenes[i].ClearLightmaps();
- }
-
Scene.MarkSceneEdited(scenes);
}
@@ -1384,6 +1381,7 @@ namespace FlaxEditor
var scenes = Level.Scenes;
Navigation.BuildNavMesh();
Scene.MarkSceneEdited(scenes);
+ ProgressReporting.NavMeshBuilding.DirtyScenesOnEnd = true;
}
///
diff --git a/Source/Editor/GUI/Table.cs b/Source/Editor/GUI/Table.cs
index 71b01aa0f..bcb4dd163 100644
--- a/Source/Editor/GUI/Table.cs
+++ b/Source/Editor/GUI/Table.cs
@@ -82,6 +82,53 @@ namespace FlaxEditor.GUI
}
}
+ private bool _alternateRows = true;
+
+ ///
+ /// Gets or sets a value indicating whether alternate row background colors should be applied.
+ ///
+ public bool AlternateRows
+ {
+ get => _alternateRows;
+ set
+ {
+ if (_alternateRows != value)
+ {
+ _alternateRows = value;
+ PerformLayout();
+ }
+ }
+ }
+
+ private Color? _rowColorEven;
+ private Color? _rowColorOdd;
+
+ ///
+ /// Gets or sets the background color of even rows.
+ ///
+ public Color RowColorEven
+ {
+ get => _rowColorEven ?? Color.Transparent;
+ set
+ {
+ _rowColorEven = value;
+ PerformLayout();
+ }
+ }
+
+ ///
+ /// Gets or sets the background color of odd rows.
+ ///
+ public Color RowColorOdd
+ {
+ get => _rowColorOdd ?? (Style.Current != null ? Style.Current.Background * 1.4f : Color.Transparent);
+ set
+ {
+ _rowColorOdd = value;
+ PerformLayout();
+ }
+ }
+
///
/// Initializes a new instance of the class.
///
@@ -250,6 +297,7 @@ namespace FlaxEditor.GUI
// Arrange rows
float y = _headerHeight;
+ int visibleRowIndex = 0;
for (int i = 0; i < Children.Count; i++)
{
var c = Children[i];
@@ -260,6 +308,12 @@ namespace FlaxEditor.GUI
bounds.Y = y;
c.Bounds = bounds;
y += bounds.Height + 1;
+
+ if (_alternateRows && c is Row row)
+ {
+ row.BackgroundColor = visibleRowIndex % 2 == 1 ? RowColorOdd : RowColorEven;
+ visibleRowIndex++;
+ }
}
}
diff --git a/Source/Editor/Progress/Handlers/NavMeshBuildingProgress.cs b/Source/Editor/Progress/Handlers/NavMeshBuildingProgress.cs
index c722929fc..21a7b684f 100644
--- a/Source/Editor/Progress/Handlers/NavMeshBuildingProgress.cs
+++ b/Source/Editor/Progress/Handlers/NavMeshBuildingProgress.cs
@@ -12,6 +12,8 @@ namespace FlaxEditor.Progress.Handlers
{
private bool _isActive;
+ internal bool DirtyScenesOnEnd;
+
///
/// Initializes a new instance of the class.
///
@@ -34,6 +36,11 @@ namespace FlaxEditor.Progress.Handlers
}
else
{
+ if (DirtyScenesOnEnd)
+ {
+ DirtyScenesOnEnd = false;
+ Editor.Instance.Scene.MarkAllScenesEdited();
+ }
OnEnd();
}
}
diff --git a/Source/Editor/States/BuildingScenesState.cs b/Source/Editor/States/BuildingScenesState.cs
index 9ebf58fe2..52cc5ac81 100644
--- a/Source/Editor/States/BuildingScenesState.cs
+++ b/Source/Editor/States/BuildingScenesState.cs
@@ -73,6 +73,14 @@ namespace FlaxEditor.States
{
StateMachine.GoToState();
}
+
+ protected void ConditionalDirtyScenes()
+ {
+ if (((SubStateMachine)StateMachine).States.Any(x => ((SubState)x).DirtyScenes))
+ {
+ Editor.Instance.Scene.MarkAllScenesEdited();
+ }
+ }
}
private sealed class BeginState : SubState
@@ -83,18 +91,12 @@ namespace FlaxEditor.States
{
public override void OnEnter()
{
- var stateMachine = (SubStateMachine)StateMachine;
- var scenesDirty = false;
- foreach (var state in stateMachine.States)
+ var states = ((SubStateMachine)StateMachine).States;
+ foreach (var state in states)
{
((SubState)state).Before();
- scenesDirty |= ((SubState)state).DirtyScenes;
- }
- if (scenesDirty)
- {
- foreach (var scene in Level.Scenes)
- Editor.Instance.Scene.MarkSceneEdited(scene);
}
+ ConditionalDirtyScenes();
Done();
}
}
@@ -262,6 +264,7 @@ namespace FlaxEditor.States
{
public override void OnEnter()
{
+ ConditionalDirtyScenes();
Editor.Instance.StateMachine.GoToState();
}
}
diff --git a/Source/Editor/Surface/VisjectSurfaceWindow.cs b/Source/Editor/Surface/VisjectSurfaceWindow.cs
index 3151f9b17..3f3a76302 100644
--- a/Source/Editor/Surface/VisjectSurfaceWindow.cs
+++ b/Source/Editor/Surface/VisjectSurfaceWindow.cs
@@ -42,6 +42,12 @@ namespace FlaxEditor.Surface
///
IEnumerable NewParameterTypes { get; }
+ ///
+ /// Index of the parameter to start renaming once the properties panel is next rebuilt, or -1 if none.
+ /// Used to auto-start renaming of a freshly added parameter.
+ ///
+ int ParamToRename { get; set; }
+
///
/// Event called when surface gets loaded (eg. after opening the window).
///
@@ -589,6 +595,7 @@ namespace FlaxEditor.Surface
if (Utilities.Utils.OnAssetProperties(layout, asset))
return;
var parameters = window.VisjectSurface.Parameters;
+ ParameterPropertyNameLabel labelToRename = null;
CustomEditors.Editors.GenericEditor.OnGroupsBegin();
for (int i = 0; i < parameters.Count; i++)
{
@@ -643,6 +650,8 @@ namespace FlaxEditor.Surface
tooltipText += '\n' + tooltip.Text;
propertyLabel.MouseLeftDoubleClick += (label, location) => StartParameterRenaming(pIndex, label);
propertyLabel.SetupContextMenu += OnPropertyLabelSetupContextMenu;
+ if (pIndex == window.ParamToRename)
+ labelToRename = propertyLabel;
var property = itemLayout.AddPropertyItem(propertyLabel, tooltipText);
property.Property("Value", propertyValue);
}
@@ -657,6 +666,21 @@ namespace FlaxEditor.Surface
newParam.Button.ButtonClicked += OnAddParameterButtonClicked;
layout.Space(10);
}
+ // Defer renaming a newly added param once its label is built and laid out
+ // Adding a param can rebuild the panel more than once (disposing earlier labels)
+ // Because of this every rebuild recaptures the current label, only the surviving one actually calls StartParameterRenaming
+ if (labelToRename != null)
+ {
+ var index = window.ParamToRename;
+ var label = labelToRename;
+ FlaxEngine.Scripting.InvokeOnUpdate(() =>
+ {
+ if (label.IsDisposing)
+ return; // A latter rebuild replaced this label, its own callback will handle it
+ window.ParamToRename = -1;
+ StartParameterRenaming(index, label);
+ });
+ }
}
private void OnAddParameterButtonClicked(Button button)
@@ -695,6 +719,7 @@ namespace FlaxEditor.Surface
};
window.VisjectSurface.Undo.AddAction(action);
action.Do();
+ window.ParamToRename = action.Index;
}
private DragData OnDragParameter(DraggablePropertyNameLabel label)
@@ -1276,6 +1301,9 @@ namespace FlaxEditor.Surface
///
public abstract IEnumerable NewParameterTypes { get; }
+ ///
+ public int ParamToRename { get; set; } = -1;
+
///
public event Action SurfaceLoaded;
diff --git a/Source/Editor/Undo/Actions/ParentActorsAction.cs b/Source/Editor/Undo/Actions/ParentActorsAction.cs
index aed85cb3c..c4a6c7f29 100644
--- a/Source/Editor/Undo/Actions/ParentActorsAction.cs
+++ b/Source/Editor/Undo/Actions/ParentActorsAction.cs
@@ -148,8 +148,7 @@ namespace FlaxEditor.Actions
// Prefab links are broken by the C++ backend on actor reparenting
// Mark scenes as edited
- foreach (var scene in scenes)
- Editor.Instance.Scene.MarkSceneEdited(scene);
+ Editor.Instance.Scene.MarkSceneEdited(scenes);
}
public void Undo()
diff --git a/Source/Editor/Windows/Assets/BehaviorTreeWindow.cs b/Source/Editor/Windows/Assets/BehaviorTreeWindow.cs
index 1317300c3..7772d59b2 100644
--- a/Source/Editor/Windows/Assets/BehaviorTreeWindow.cs
+++ b/Source/Editor/Windows/Assets/BehaviorTreeWindow.cs
@@ -602,6 +602,9 @@ namespace FlaxEditor.Windows.Assets
///
public IEnumerable NewParameterTypes => Editor.CodeEditing.VisualScriptPropertyTypes.Get();
+ ///
+ public int ParamToRename { get; set; } = -1;
+
///
public event Action SurfaceLoaded;
diff --git a/Source/Editor/Windows/Assets/JsonAssetWindow.cs b/Source/Editor/Windows/Assets/JsonAssetWindow.cs
index c2722ed9d..4d9c04942 100644
--- a/Source/Editor/Windows/Assets/JsonAssetWindow.cs
+++ b/Source/Editor/Windows/Assets/JsonAssetWindow.cs
@@ -5,6 +5,7 @@ using FlaxEditor.Content;
using FlaxEditor.CustomEditors;
using FlaxEditor.GUI;
using FlaxEditor.GUI.ContextMenu;
+using FlaxEditor.GUI.Input;
using FlaxEngine;
using FlaxEngine.GUI;
using FlaxEngine.Json;
@@ -67,6 +68,8 @@ namespace FlaxEditor.Windows.Assets
}
private readonly CustomEditorPresenter _presenter;
+ private SearchBox _searchBox;
+ private Panel _scrollingPanel;
private readonly ToolStripButton _saveButton;
private readonly ToolStripButton _undoButton;
private readonly ToolStripButton _redoButton;
@@ -100,18 +103,35 @@ namespace FlaxEditor.Windows.Assets
_undoButton = _toolstrip.AddButton(Editor.Icons.Undo64, _undo.PerformUndo).LinkTooltip("Undo", ref inputOptions.Undo);
_redoButton = _toolstrip.AddButton(Editor.Icons.Redo64, _undo.PerformRedo).LinkTooltip("Redo", ref inputOptions.Redo);
- // Panel
- var panel = new Panel(ScrollBars.Vertical)
+ // Header panel for search
+ var headerPanel = new ContainerControl
+ {
+ AnchorPreset = AnchorPresets.HorizontalStretchTop,
+ BackgroundColor = Style.Current.Background,
+ IsScrollable = false,
+ Offsets = new Margin(0, 0, _toolstrip.Bottom, 18 + 6),
+ Parent = this,
+ };
+ _searchBox = new SearchBox
+ {
+ AnchorPreset = AnchorPresets.HorizontalStretchMiddle,
+ Parent = headerPanel,
+ Bounds = new Rectangle(4, 4, headerPanel.Width - 8, 18),
+ };
+ _searchBox.TextChanged += ApplySearchFilter;
+
+ _scrollingPanel = new Panel(ScrollBars.Vertical)
{
AnchorPreset = AnchorPresets.StretchAll,
- Offsets = new Margin(0, 0, _toolstrip.Bottom, 0),
- Parent = this
+ Offsets = new Margin(0, 0, headerPanel.Bottom, 0),
+ Parent = this,
};
// Properties
_presenter = new CustomEditorPresenter(_undo, "Loading...");
- _presenter.Panel.Parent = panel;
+ _presenter.Panel.Parent = _scrollingPanel;
_presenter.Modified += MarkAsEdited;
+ _presenter.AfterLayout += OnPresenterAfterLayout;
// Setup input actions
InputActions.Add(options => options.Undo, _undo.PerformUndo);
@@ -349,5 +369,15 @@ namespace FlaxEditor.Windows.Assets
_optionsCM?.Dispose();
_typeText = null;
}
+
+ private void OnPresenterAfterLayout(LayoutElementsContainer layout)
+ {
+ ApplySearchFilter();
+ }
+
+ private void ApplySearchFilter()
+ {
+ _presenter.ApplySearchFilter(_searchBox.Text);
+ }
}
}
diff --git a/Source/Editor/Windows/Assets/PrefabWindow.cs b/Source/Editor/Windows/Assets/PrefabWindow.cs
index 1d6d827ab..06e007a17 100644
--- a/Source/Editor/Windows/Assets/PrefabWindow.cs
+++ b/Source/Editor/Windows/Assets/PrefabWindow.cs
@@ -5,6 +5,7 @@ using System.Collections.Generic;
using System.Xml;
using FlaxEditor.Content;
using FlaxEditor.CustomEditors;
+using FlaxEditor.CustomEditors.GUI;
using FlaxEditor.Gizmo;
using FlaxEditor.GUI;
using FlaxEditor.GUI.Input;
@@ -29,6 +30,8 @@ namespace FlaxEditor.Windows.Assets
private readonly PrefabTree _tree;
private readonly PrefabWindowViewport _viewport;
private readonly CustomEditorPresenter _propertiesEditor;
+ private SearchBox _propertiesSearchBox;
+ private Panel _propertiesScrollingPanel;
private readonly ToolStripButton _saveButton;
private readonly ToolStripButton _toolStripUndo;
@@ -142,7 +145,7 @@ namespace FlaxEditor.Windows.Assets
};
// Split Panel 2
- _split2 = new SplitPanel(Orientation.Horizontal, ScrollBars.None, ScrollBars.Vertical)
+ _split2 = new SplitPanel(Orientation.Horizontal, ScrollBars.None, ScrollBars.None)
{
AnchorPreset = AnchorPresets.StretchAll,
Offsets = Margin.Zero,
@@ -197,9 +200,33 @@ namespace FlaxEditor.Windows.Assets
_viewport.TransformGizmo.ModeChanged += UpdateToolstrip;
// Prefab properties editor
+ var propHeaderPanel = new ContainerControl
+ {
+ AnchorPreset = AnchorPresets.HorizontalStretchTop,
+ BackgroundColor = Style.Current.Background,
+ IsScrollable = false,
+ Offsets = new Margin(0, 0, 0, 18 + 6),
+ Parent = _split2.Panel2,
+ };
+ _propertiesSearchBox = new SearchBox
+ {
+ AnchorPreset = AnchorPresets.HorizontalStretchMiddle,
+ Parent = propHeaderPanel,
+ Bounds = new Rectangle(4, 4, propHeaderPanel.Width - 8, 18),
+ };
+ _propertiesSearchBox.TextChanged += ApplyPropertiesSearchFilter;
+
+ _propertiesScrollingPanel = new Panel(ScrollBars.Vertical)
+ {
+ AnchorPreset = AnchorPresets.StretchAll,
+ Offsets = new Margin(0, 0, propHeaderPanel.Bottom, 0),
+ Parent = _split2.Panel2,
+ };
+
_propertiesEditor = new CustomEditorPresenter(_undo, null, this);
- _propertiesEditor.Panel.Parent = _split2.Panel2;
+ _propertiesEditor.Panel.Parent = _propertiesScrollingPanel;
_propertiesEditor.Modified += MarkAsEdited;
+ _propertiesEditor.AfterLayout += OnPresenterAfterLayout;
// Toolstrip
_saveButton = _toolstrip.AddButton(Editor.Icons.Save64, Save).LinkTooltip("Save", ref inputOptions.Save);
@@ -580,6 +607,16 @@ namespace FlaxEditor.Windows.Assets
///
public EditorViewport PresenterViewport => _viewport;
+ private void OnPresenterAfterLayout(LayoutElementsContainer layout)
+ {
+ ApplyPropertiesSearchFilter();
+ }
+
+ private void ApplyPropertiesSearchFilter()
+ {
+ _propertiesEditor.ApplySearchFilter(_propertiesSearchBox.Text);
+ }
+
///
EditorViewport ISceneEditingContext.Viewport => Viewport;
}
diff --git a/Source/Editor/Windows/Assets/VisualScriptWindow.cs b/Source/Editor/Windows/Assets/VisualScriptWindow.cs
index 35b2d927d..708fd9319 100644
--- a/Source/Editor/Windows/Assets/VisualScriptWindow.cs
+++ b/Source/Editor/Windows/Assets/VisualScriptWindow.cs
@@ -1398,6 +1398,9 @@ namespace FlaxEditor.Windows.Assets
///
public IEnumerable NewParameterTypes => Editor.CodeEditing.VisualScriptPropertyTypes.Get();
+ ///
+ public int ParamToRename { get; set; } = -1;
+
///
public event Action SurfaceLoaded;
diff --git a/Source/Editor/Windows/EditorOptionsWindow.cs b/Source/Editor/Windows/EditorOptionsWindow.cs
index c6bf2fd16..dc12885a5 100644
--- a/Source/Editor/Windows/EditorOptionsWindow.cs
+++ b/Source/Editor/Windows/EditorOptionsWindow.cs
@@ -4,6 +4,7 @@ using System;
using System.Collections.Generic;
using FlaxEditor.CustomEditors;
using FlaxEditor.GUI;
+using FlaxEditor.GUI.Input;
using FlaxEditor.GUI.Tabs;
using FlaxEditor.Options;
using FlaxEngine;
@@ -25,6 +26,7 @@ namespace FlaxEditor.Windows
private ToolStripButton _saveButton;
private readonly Undo _undo;
private readonly List _customTabs = new List();
+ private SearchBox _searchBox;
///
/// Initializes a new instance of the class.
@@ -48,15 +50,33 @@ namespace FlaxEditor.Windows
_saveButton = (ToolStripButton)toolstrip.AddButton(editor.Icons.Save64, SaveData).LinkTooltip("Save.");
_saveButton.Enabled = false;
+ // Header panel for search
+ var headerPanel = new ContainerControl
+ {
+ AnchorPreset = AnchorPresets.HorizontalStretchTop,
+ BackgroundColor = Style.Current.Background,
+ IsScrollable = false,
+ Offsets = new Margin(0, 0, toolstrip.Bottom, 18 + 6),
+ Parent = this,
+ };
+ _searchBox = new SearchBox
+ {
+ AnchorPreset = AnchorPresets.HorizontalStretchMiddle,
+ Parent = headerPanel,
+ Bounds = new Rectangle(4, 4, headerPanel.Width - 8, 18),
+ };
+ _searchBox.TextChanged += ApplySearchFilter;
+
_tabs = new Tabs
{
Orientation = Orientation.Vertical,
AnchorPreset = AnchorPresets.StretchAll,
- Offsets = new Margin(0, 0, toolstrip.Bottom, 0),
+ Offsets = new Margin(0, 0, headerPanel.Bottom, 0),
TabsSize = new Float2(120, 32),
UseScroll = true,
Parent = this
};
+ _tabs.SelectedTabChanged += OnSelectedTabChanged;
CreateTab("General", () => _options.General);
CreateTab("Interface", () => _options.Interface);
@@ -94,6 +114,13 @@ namespace FlaxEditor.Windows
settings.Panel.Parent = panel;
settings.Panel.Tag = getValue;
settings.Modified += MarkAsEdited;
+ settings.AfterLayout += layout =>
+ {
+ if (_tabs.SelectedTab == tab)
+ {
+ ApplySearchFilter();
+ }
+ };
return tab;
}
@@ -280,5 +307,25 @@ namespace FlaxEditor.Windows
return base.OnClosing(reason);
}
+
+ private void OnSelectedTabChanged(Tabs tabs)
+ {
+ ApplySearchFilter();
+ }
+
+ private CustomEditorPresenter GetTabPresenter(Tab tab)
+ {
+ if (tab == null)
+ return null;
+ var panel = tab.GetChild();
+ var settingsPanel = panel?.GetChild();
+ return settingsPanel?.Presenter;
+ }
+
+ private void ApplySearchFilter()
+ {
+ var presenter = GetTabPresenter(_tabs.SelectedTab);
+ presenter?.ApplySearchFilter(_searchBox.Text);
+ }
}
}
diff --git a/Source/Editor/Windows/Profiler/Assets.cs b/Source/Editor/Windows/Profiler/Assets.cs
index e4e41c668..8ee6f5f6d 100644
--- a/Source/Editor/Windows/Profiler/Assets.cs
+++ b/Source/Editor/Windows/Profiler/Assets.cs
@@ -80,6 +80,8 @@ namespace FlaxEditor.Windows.Profiler
var textColor = style.Foreground;
_table = new Table
{
+ RowColorEven = Color.Transparent,
+ RowColorOdd = style.Background * 1.4f,
Columns = new[]
{
new ColumnDefinition
@@ -242,8 +244,6 @@ namespace FlaxEditor.Windows.Profiler
var resourcesOrdered = resources.OrderByDescending(x => x.MemoryUsage);
// Add rows
- var rowColor2 = Style.Current.Background * 1.4f;
- int rowIndex = 0;
foreach (var e in resourcesOrdered)
{
ClickableRow row;
@@ -271,9 +271,7 @@ namespace FlaxEditor.Windows.Profiler
// Add row to the table
row.Width = _table.Width;
- row.BackgroundColor = rowIndex % 2 == 1 ? rowColor2 : Color.Transparent;
row.Parent = _table;
- rowIndex++;
}
}
diff --git a/Source/Editor/Windows/Profiler/CPU.cs b/Source/Editor/Windows/Profiler/CPU.cs
index d034a058b..fad7c4de8 100644
--- a/Source/Editor/Windows/Profiler/CPU.cs
+++ b/Source/Editor/Windows/Profiler/CPU.cs
@@ -106,6 +106,8 @@ namespace FlaxEditor.Windows.Profiler
var textColor = style.Foreground;
_table = new Table
{
+ RowColorEven = Color.Transparent,
+ RowColorOdd = style.Background * 1.4f,
Columns = new[]
{
new ColumnDefinition
@@ -464,7 +466,6 @@ namespace FlaxEditor.Windows.Profiler
float totalTimeMs = _mainChart.SelectedSample;
// Add rows
- var rowColor2 = Style.Current.Background * 1.4f;
for (int j = 0; j < data.Length; j++)
{
var events = data[j].Events;
@@ -540,7 +541,6 @@ namespace FlaxEditor.Windows.Profiler
row.Depth = e.Depth;
row.Width = _table.Width;
row.Visible = e.Depth < 2;
- row.BackgroundColor = i % 2 == 1 ? rowColor2 : Color.Transparent;
row.Parent = _table;
}
}
diff --git a/Source/Editor/Windows/Profiler/GPU.cs b/Source/Editor/Windows/Profiler/GPU.cs
index 5cc9cd681..6abfef5e1 100644
--- a/Source/Editor/Windows/Profiler/GPU.cs
+++ b/Source/Editor/Windows/Profiler/GPU.cs
@@ -83,6 +83,8 @@ namespace FlaxEditor.Windows.Profiler
var textColor = style.Foreground;
_table = new Table
{
+ RowColorEven = Color.Transparent,
+ RowColorOdd = style.Background * 1.4f,
Columns = new[]
{
new ColumnDefinition
@@ -339,7 +341,6 @@ namespace FlaxEditor.Windows.Profiler
float totalTimeMs = _drawTimeGPU.SelectedSample;
// Add rows
- var rowColor2 = Style.Current.Background * 1.4f;
for (int i = 0; i < data.Length; i++)
{
var e = data[i];
@@ -386,7 +387,6 @@ namespace FlaxEditor.Windows.Profiler
row.Depth = e.Depth;
row.Width = _table.Width;
row.Visible = e.Depth < 3;
- row.BackgroundColor = i % 2 == 1 ? rowColor2 : Color.Transparent;
row.Parent = _table;
}
}
diff --git a/Source/Editor/Windows/Profiler/Memory.cs b/Source/Editor/Windows/Profiler/Memory.cs
index a74472a8c..56178acf2 100644
--- a/Source/Editor/Windows/Profiler/Memory.cs
+++ b/Source/Editor/Windows/Profiler/Memory.cs
@@ -84,6 +84,8 @@ namespace FlaxEditor.Windows.Profiler
var textColor = style.Foreground;
_table = new Table
{
+ RowColorEven = Color.Transparent,
+ RowColorOdd = style.Background * 1.4f,
Columns = new[]
{
new ColumnDefinition
@@ -236,7 +238,6 @@ namespace FlaxEditor.Windows.Profiler
});
// Add rows
- var rowColor2 = Style.Current.Background * 1.4f;
for (int i = 0; i < (int)ProfilerMemory.Groups.MAX; i++)
{
var group = _groupOrder[i];
@@ -278,7 +279,6 @@ namespace FlaxEditor.Windows.Profiler
row.BackgroundColors[3] = Color.Red.AlphaMultiplied(Mathf.Min(1, (float)groupCount / totalCount) * 0.5f);
}
row.Width = _table.Width;
- row.BackgroundColor = i % 2 == 1 ? rowColor2 : Color.Transparent;
row.Parent = _table;
var useBackground = group != (int)ProfilerMemory.Groups.Total &&
diff --git a/Source/Editor/Windows/Profiler/MemoryGPU.cs b/Source/Editor/Windows/Profiler/MemoryGPU.cs
index 11b8a1980..76c02888b 100644
--- a/Source/Editor/Windows/Profiler/MemoryGPU.cs
+++ b/Source/Editor/Windows/Profiler/MemoryGPU.cs
@@ -81,6 +81,8 @@ namespace FlaxEditor.Windows.Profiler
var textColor = style.Foreground;
_table = new Table
{
+ RowColorEven = Color.Transparent,
+ RowColorOdd = style.Background * 1.4f,
Columns = new[]
{
new ColumnDefinition
@@ -299,8 +301,6 @@ namespace FlaxEditor.Windows.Profiler
var resourcesOrdered = resources.OrderByDescending(x => x?.MemoryUsage ?? 0);
// Add rows
- var rowColor2 = Style.Current.Background * 1.4f;
- int rowIndex = 0;
foreach (var e in resourcesOrdered)
{
if (e == null)
@@ -335,9 +335,7 @@ namespace FlaxEditor.Windows.Profiler
// Add row to the table
row.Width = _table.Width;
- row.BackgroundColor = rowIndex % 2 == 1 ? rowColor2 : Color.Transparent;
row.Parent = _table;
- rowIndex++;
}
}
diff --git a/Source/Editor/Windows/Profiler/Network.cs b/Source/Editor/Windows/Profiler/Network.cs
index 988398b0c..2a2d542f5 100644
--- a/Source/Editor/Windows/Profiler/Network.cs
+++ b/Source/Editor/Windows/Profiler/Network.cs
@@ -190,7 +190,6 @@ namespace FlaxEditor.Windows.Profiler
var rowCount = Int2.Zero;
if (events != null && events.Length != 0)
{
- var rowColor2 = Style.Current.Background * 1.4f;
for (int i = 0; i < events.Length; i++)
{
var e = events[i];
@@ -230,7 +229,6 @@ namespace FlaxEditor.Windows.Profiler
var table = isRpc ? _tableRpc : _tableRep;
row.Width = table.Width;
- row.BackgroundColor = rowCount[isRpc ? 0 : 1] % 2 == 1 ? rowColor2 : Color.Transparent;
row.Parent = table;
if (isRpc)
rowCount.X++;
@@ -266,6 +264,8 @@ namespace FlaxEditor.Windows.Profiler
var textColor = style.Foreground;
var table = new Table
{
+ RowColorEven = Color.Transparent,
+ RowColorOdd = style.Background * 1.4f,
Columns = new[]
{
new ColumnDefinition
diff --git a/Source/Editor/Windows/PropertiesWindow.cs b/Source/Editor/Windows/PropertiesWindow.cs
index 03316a221..a62f7508b 100644
--- a/Source/Editor/Windows/PropertiesWindow.cs
+++ b/Source/Editor/Windows/PropertiesWindow.cs
@@ -5,6 +5,9 @@ using System.Collections.Generic;
using System.Linq;
using System.Xml;
using FlaxEditor.CustomEditors;
+using FlaxEditor.CustomEditors.Elements;
+using FlaxEditor.CustomEditors.GUI;
+using FlaxEditor.GUI.Input;
using FlaxEditor.SceneGraph;
using FlaxEditor.Viewport;
using FlaxEngine;
@@ -23,6 +26,8 @@ namespace FlaxEditor.Windows
private readonly Dictionary _actorScrollValues = new Dictionary();
private bool _lockObjects = false;
+ private SearchBox _searchBox;
+ private Panel _scrollingPanel;
///
public override bool UseLayoutData => true;
@@ -66,18 +71,42 @@ namespace FlaxEditor.Windows
///
/// The editor.
public PropertiesWindow(Editor editor)
- : base(editor, true, ScrollBars.Vertical)
+ : base(editor, true, ScrollBars.None)
{
Title = "Properties";
Icon = editor.Icons.Build64;
AutoFocus = true;
+ var headerPanel = new ContainerControl
+ {
+ AnchorPreset = AnchorPresets.HorizontalStretchTop,
+ BackgroundColor = Style.Current.Background,
+ IsScrollable = false,
+ Offsets = new Margin(0, 0, 0, 18 + 6),
+ Parent = this,
+ };
+ _searchBox = new SearchBox
+ {
+ AnchorPreset = AnchorPresets.HorizontalStretchMiddle,
+ Parent = headerPanel,
+ Bounds = new Rectangle(4, 4, headerPanel.Width - 8, 18),
+ };
+ _searchBox.TextChanged += ApplySearchFilter;
+
+ _scrollingPanel = new Panel(ScrollBars.Vertical)
+ {
+ AnchorPreset = AnchorPresets.StretchAll,
+ Offsets = new Margin(0, 0, headerPanel.Bottom, 0),
+ Parent = this,
+ };
+
Presenter = new CustomEditorPresenter(editor.Undo, null, this);
- Presenter.Panel.Parent = this;
+ Presenter.Panel.Parent = _scrollingPanel;
Presenter.GetUndoObjects += GetUndoObjects;
Presenter.Features |= FeatureFlags.CacheExpandedGroups;
+ Presenter.AfterLayout += OnPresenterAfterLayout;
- VScrollBar.ValueChanged += OnScrollValueChanged;
+ _scrollingPanel.VScrollBar.ValueChanged += OnScrollValueChanged;
Editor.SceneEditing.SelectionChanged += OnSelectionChanged;
}
@@ -115,7 +144,8 @@ namespace FlaxEditor.Windows
}
}
- _actorScrollValues[Editor.SceneEditing.Selection[0].ID] = VScrollBar.TargetValue;
+ if (_scrollingPanel.VScrollBar != null)
+ _actorScrollValues[Editor.SceneEditing.Selection[0].ID] = _scrollingPanel.VScrollBar.TargetValue;
}
private IEnumerable