diff --git a/Source/Editor/GUI/ItemsListContextMenu.cs b/Source/Editor/GUI/ItemsListContextMenu.cs
index 23f493c65..8eeccf288 100644
--- a/Source/Editor/GUI/ItemsListContextMenu.cs
+++ b/Source/Editor/GUI/ItemsListContextMenu.cs
@@ -248,26 +248,30 @@ namespace FlaxEditor.GUI
///
/// The control width.
/// The control height.
- public ItemsListContextMenu(float width = 320, float height = 220)
+ /// Enables search field.
+ public ItemsListContextMenu(float width = 320, float height = 220, bool withSearch = true)
{
// Context menu dimensions
Size = new Float2(width, height);
- // Search box
- _searchBox = new SearchBox(false, 1, 1)
+ if (withSearch)
{
- Parent = this,
- Width = Width - 3,
- };
- _searchBox.TextChanged += OnSearchFilterChanged;
- _searchBox.ClearSearchButton.Clicked += () => PerformLayout();
+ // Search box
+ _searchBox = new SearchBox(false, 1, 1)
+ {
+ Parent = this,
+ Width = Width - 3,
+ };
+ _searchBox.TextChanged += OnSearchFilterChanged;
+ _searchBox.ClearSearchButton.Clicked += () => PerformLayout();
+ }
// Panel with scrollbar
_scrollPanel = new Panel(ScrollBars.Vertical)
{
Parent = this,
AnchorPreset = AnchorPresets.StretchAll,
- Bounds = new Rectangle(0, _searchBox.Bottom + 1, Width, Height - _searchBox.Bottom - 2),
+ Bounds = withSearch ? new Rectangle(0, _searchBox.Bottom + 1, Width, Height - _searchBox.Bottom - 2) : new Rectangle(Float2.Zero, Size),
};
// Items list panel
@@ -446,7 +450,7 @@ namespace FlaxEditor.GUI
}
}
- _searchBox.Clear();
+ _searchBox?.Clear();
UnlockChildrenRecursive();
PerformLayout(true);
}
@@ -510,7 +514,7 @@ namespace FlaxEditor.GUI
if (RootWindow.FocusedControl == null)
{
// Focus search box if nothing is focused
- _searchBox.Focus();
+ _searchBox?.Focus();
return true;
}
@@ -536,7 +540,7 @@ namespace FlaxEditor.GUI
var focusedIndex = items.IndexOf(focusedItem);
if (focusedIndex == 0)
{
- _searchBox.Focus();
+ _searchBox?.Focus();
}
else if (focusedIndex > 0)
{
@@ -556,7 +560,7 @@ namespace FlaxEditor.GUI
break;
}
- if (_waitingForInput)
+ if (_waitingForInput && _searchBox != null)
{
_waitingForInput = false;
_searchBox.Focus();
diff --git a/Source/Editor/Windows/OutputLogWindow.cs b/Source/Editor/Windows/OutputLogWindow.cs
index 86d0f060d..361f2e4b1 100644
--- a/Source/Editor/Windows/OutputLogWindow.cs
+++ b/Source/Editor/Windows/OutputLogWindow.cs
@@ -3,10 +3,12 @@
using System;
using System.Collections.Generic;
using System.IO;
+using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Text.RegularExpressions;
using System.Xml;
+using FlaxEditor.GUI;
using FlaxEditor.GUI.ContextMenu;
using FlaxEditor.GUI.Input;
using FlaxEditor.Options;
@@ -127,10 +129,13 @@ namespace FlaxEditor.Windows
///
private class CommandLineBox : TextBox
{
- public CommandLineBox(float x, float y, float width)
+ private OutputLogWindow _window;
+
+ public CommandLineBox(float x, float y, float width, OutputLogWindow window)
: base(false, x, y, width)
{
WatermarkText = ">";
+ _window = window;
}
///
@@ -141,8 +146,22 @@ namespace FlaxEditor.Windows
case KeyboardKeys.Return:
{
// Run command
- DebugCommands.Execute(Text);
+ var command = Text.Trim();
+ if (command.Length == 0)
+ return true;
+ DebugCommands.Execute(command);
SetText(string.Empty);
+
+ // Update history buffer
+ if (_window._commandHistory == null)
+ _window._commandHistory = new List();
+ else if (_window._commandHistory.Count != 0 && _window._commandHistory.Last() == command)
+ _window._commandHistory.RemoveAt(_window._commandHistory.Count - 1);
+ _window._commandHistory.Add(command);
+ if (_window._commandHistory.Count > CommandHistoryLimit)
+ _window._commandHistory.RemoveAt(0);
+ _window.SaveHistory();
+
return true;
}
case KeyboardKeys.Tab:
@@ -189,6 +208,48 @@ namespace FlaxEditor.Windows
}
return true;
}
+ case KeyboardKeys.ArrowUp:
+ {
+ if (TextLength == 0)
+ {
+ if (_window._commandHistory != null && _window._commandHistory.Count != 0)
+ {
+ // Show command history popup
+ var cm = new ItemsListContextMenu(180, 220, false);
+ ItemsListContextMenu.Item lastItem = null;
+ var count = _window._commandHistory.Count;
+ for (int i = 0; i < count; i++)
+ {
+ var command = _window._commandHistory[i];
+ cm.AddItem(lastItem = new ItemsListContextMenu.Item
+ {
+ Name = command,
+ });
+ }
+ cm.ItemClicked += item =>
+ {
+ SetText(item.Name);
+ SetSelection(Text.Length);
+ };
+ var totalHeight = count * lastItem.Height + cm.ItemsPanel.Margin.Height + cm.ItemsPanel.Spacing * (count - 1);
+ if (cm.Height > totalHeight)
+ cm.Height = totalHeight; // Limit popup height if history is small
+ cm.Show(this, Float2.Zero, ContextMenuDirection.RightUp);
+ lastItem.Focus();
+ cm.ScrollViewTo(lastItem);
+ }
+ }
+ else
+ {
+ // TODO: focus similar commands (via popup)
+ }
+ return true;
+ }
+ case KeyboardKeys.ArrowDown:
+ {
+ // Ignore
+ return true;
+ }
}
return base.OnKeyDown(key);
}
@@ -210,6 +271,9 @@ namespace FlaxEditor.Windows
private List _textBlocks = new List();
private DateTime _startupTime;
private Regex _compileRegex = new Regex("(?^(?:[a-zA-Z]\\:|\\\\\\\\[ \\-\\.\\w\\.]+\\\\[ \\-\\.\\w.$]+)\\\\(?:[ \\-\\.\\w]+\\\\)*\\w([ \\w.])+)\\((?\\d{1,}),\\d{1,},\\d{1,},\\d{1,}\\): (?error|warning) (?.*)", RegexOptions.Compiled);
+ private List _commandHistory;
+ private const string CommandHistoryKey = "CommandHistory";
+ private const int CommandHistoryLimit = 30;
private Button _viewDropdown;
private TextBox _searchBox;
@@ -267,7 +331,7 @@ namespace FlaxEditor.Windows
};
_output.TargetViewOffsetChanged += OnOutputTargetViewOffsetChanged;
_output.TextChanged += OnOutputTextChanged;
- _commandLineBox = new CommandLineBox(2, Height - 2 - TextBox.DefaultHeight, Width - 4)
+ _commandLineBox = new CommandLineBox(2, Height - 2 - TextBox.DefaultHeight, Width - 4, this)
{
Parent = this,
};
@@ -394,6 +458,14 @@ namespace FlaxEditor.Windows
FocusOrShow();
}
+ private void SaveHistory()
+ {
+ if (_commandHistory == null || _commandHistory.Count == 0)
+ Editor.ProjectCache.RemoveCustomData(CommandHistoryKey);
+ else
+ Editor.ProjectCache.SetCustomData(CommandHistoryKey, FlaxEngine.Json.JsonSerializer.Serialize(_commandHistory));
+ }
+
///
/// Refreshes the log output.
///
@@ -710,6 +782,25 @@ namespace FlaxEditor.Windows
public override void OnInit()
{
_startupTime = Time.StartupTime;
+
+ // Load debug commands history
+ if (Editor.ProjectCache.TryGetCustomData(CommandHistoryKey, out string history))
+ {
+ try
+ {
+ _commandHistory = (List)FlaxEngine.Json.JsonSerializer.Deserialize(history, typeof(List));
+ for (int i = _commandHistory.Count - 1; i >= 0; i--)
+ {
+ if (string.IsNullOrEmpty(_commandHistory[i]))
+ _commandHistory.RemoveAt(i);
+ }
+ }
+ catch
+ {
+ // Ignore errors
+ _commandHistory = null;
+ }
+ }
}
///
@@ -750,6 +841,7 @@ namespace FlaxEditor.Windows
_outLogTypes = null;
_outLogTimes = null;
_compileRegex = null;
+ _commandHistory = null;
// Unlink controls
_viewDropdown = null;