From 24db7d5230aa4428721f76e79e941180d501f499 Mon Sep 17 00:00:00 2001 From: ManlyMarco <39247311+ManlyMarco@users.noreply.github.com> Date: Sun, 2 Nov 2025 02:49:14 +0100 Subject: [PATCH 1/6] Reduce memory allocations where convenient --- .../LogViewer/LogViewerWindow.cs | 26 +-- .../PatchInspector/ILViewerWindow.cs | 24 +-- .../PatchInspector/PatchInspector.cs | 18 +- .../Utils/Abstractions/GUILayoutShim.cs | 7 + RuntimeUnityEditor.Core/Utils/IMGUIUtils.cs | 13 +- .../Inspector/Inspector.InspectorTab.cs | 13 +- .../Windows/Inspector/Inspector.cs | 195 ++++++++++-------- .../Windows/Inspector/VariableFieldDrawer.cs | 36 ++-- .../Windows/ObjectTree/ObjectTreeViewer.cs | 126 ++++++----- .../ObjectTree/RootGameObjectSearcher.cs | 69 +++---- RuntimeUnityEditor.Core/Windows/Taskbar.cs | 55 +++-- 11 files changed, 313 insertions(+), 269 deletions(-) diff --git a/RuntimeUnityEditor.Bepin5/LogViewer/LogViewerWindow.cs b/RuntimeUnityEditor.Bepin5/LogViewer/LogViewerWindow.cs index b102dd0..41255f4 100644 --- a/RuntimeUnityEditor.Bepin5/LogViewer/LogViewerWindow.cs +++ b/RuntimeUnityEditor.Bepin5/LogViewer/LogViewerWindow.cs @@ -124,7 +124,7 @@ string GetTrimmedTypeName(ILogSource obj) /// protected override void DrawContents() { - GUILayout.BeginHorizontal(); + GUILayout.BeginHorizontal(IMGUIUtils.EmptyLayoutOptions); { GUILayout.BeginHorizontal(GUI.skin.box, IMGUIUtils.LayoutOptionsExpandWidthTrue); { @@ -141,11 +141,11 @@ protected override void DrawContents() GUILayout.BeginHorizontal(GUI.skin.box, IMGUIUtils.LayoutOptionsExpandWidthFalse); { if (!Capture) GUI.color = Color.red; - Capture = GUILayout.Toggle(Capture, new GUIContent("Enable log capture", "Note: This can hurt performance, especially if there is log spam.")); + Capture = GUILayout.Toggle(Capture, new GUIContent("Enable log capture", "Note: This can hurt performance, especially if there is log spam."),IMGUIUtils.EmptyLayoutOptions); GUI.color = Color.white; - CaptureOnStartup = GUILayout.Toggle(CaptureOnStartup, new GUIContent("Enable on game startup", "Warning: This can hurt performance, especially after running for a while!")); + CaptureOnStartup = GUILayout.Toggle(CaptureOnStartup, new GUIContent("Enable on game startup", "Warning: This can hurt performance, especially after running for a while!"), IMGUIUtils.EmptyLayoutOptions); - if (GUILayout.Button("Clear the list")) + if (GUILayout.Button("Clear the list", IMGUIUtils.EmptyLayoutOptions)) { _logEntries.Clear(); _filteredLogEntries.Clear(); @@ -155,16 +155,16 @@ protected override void DrawContents() } GUILayout.EndHorizontal(); - GUILayout.BeginHorizontal(); + GUILayout.BeginHorizontal(IMGUIUtils.EmptyLayoutOptions); { - GUILayout.BeginHorizontal(GUI.skin.box); + GUILayout.BeginHorizontal(GUI.skin.box,IMGUIUtils.EmptyLayoutOptions); { - GUILayout.Label(new GUIContent("Captured log levels:", "Only new log messages with these levels will be captured, therefore enabling levels will not show past log messages!")); + GUILayout.Label(new GUIContent("Captured log levels:", "Only new log messages with these levels will be captured, therefore enabling levels will not show past log messages!"), IMGUIUtils.EmptyLayoutOptions); var filter = LogLevelFilter; foreach (var logLevel in new[] { LogLevel.Debug, LogLevel.Info, LogLevel.Message, LogLevel.Warning, LogLevel.Error, LogLevel.Fatal, LogLevel.All }) { GUI.changed = false; - var result = GUILayout.Toggle((filter & logLevel) != 0, logLevel.ToString()); + var result = GUILayout.Toggle((filter & logLevel) != 0, logLevel.ToString(), IMGUIUtils.EmptyLayoutOptions); if (GUI.changed) LogLevelFilter = result ? filter | logLevel : filter & ~logLevel; } @@ -173,10 +173,10 @@ protected override void DrawContents() GUILayout.FlexibleSpace(); - GUILayout.BeginHorizontal(GUI.skin.box); + GUILayout.BeginHorizontal(GUI.skin.box, IMGUIUtils.EmptyLayoutOptions); { - if (GUILayout.Button("Sources")) Inspector.Instance.Push(new InstanceStackEntry(BepInEx.Logging.Logger.Sources, "Log Sources"), true); - if (GUILayout.Button("Listeners")) Inspector.Instance.Push(new InstanceStackEntry(BepInEx.Logging.Logger.Listeners, "Log Listeners"), true); + if (GUILayout.Button("Sources", IMGUIUtils.EmptyLayoutOptions)) Inspector.Instance.Push(new InstanceStackEntry(BepInEx.Logging.Logger.Sources, "Log Sources"), true); + if (GUILayout.Button("Listeners", IMGUIUtils.EmptyLayoutOptions)) Inspector.Instance.Push(new InstanceStackEntry(BepInEx.Logging.Logger.Listeners, "Log Listeners"), true); } GUILayout.EndHorizontal(); } @@ -184,7 +184,7 @@ protected override void DrawContents() var heightMeasured = _itemHeight != 0; - _scrollPosition = GUILayout.BeginScrollView(_scrollPosition, false, true); + _scrollPosition = GUILayout.BeginScrollView(_scrollPosition, false, true,IMGUIUtils.EmptyLayoutOptions); { var logEntries = _filteredLogEntries; @@ -197,7 +197,7 @@ protected override void DrawContents() for (var i = skipped; i < skipped + visible; i++) { var entry = logEntries[logEntries.Count - 1 - i]; - GUILayout.BeginHorizontal(GUI.skin.box); + GUILayout.BeginHorizontal(GUI.skin.box, IMGUIUtils.EmptyLayoutOptions); { if (entry.DrawEntry()) { diff --git a/RuntimeUnityEditor.Bepin5/PatchInspector/ILViewerWindow.cs b/RuntimeUnityEditor.Bepin5/PatchInspector/ILViewerWindow.cs index 33c83a2..7728b29 100644 --- a/RuntimeUnityEditor.Bepin5/PatchInspector/ILViewerWindow.cs +++ b/RuntimeUnityEditor.Bepin5/PatchInspector/ILViewerWindow.cs @@ -48,17 +48,17 @@ public ILViewerWindow(int windowId, MethodBase method, string originalIL, List

= 0 && _selectedPatchIndex < _patchMethods.Count) { var selectedPatch = _patchMethods[_selectedPatchIndex]; - GUILayout.BeginHorizontal(); + GUILayout.BeginHorizontal(IMGUIUtils.EmptyLayoutOptions); { GUILayout.Space(3); @@ -160,13 +160,13 @@ protected override void DrawContents() _ilScrollPosition = GUILayout.BeginScrollView(_ilScrollPosition, GUILayoutShim.ExpandHeight(true)); - GUILayout.TextArea(selectedPatch.ILCode); + GUILayout.TextArea(selectedPatch.ILCode, IMGUIUtils.EmptyLayoutOptions); GUILayout.EndScrollView(); } else { - GUILayout.Label("Select a method from the list on the left to view its IL code.", IMGUIUtils.MiddleCenterLabelStyle); + GUILayout.Label("Select a method from the list on the left to view its IL code.", IMGUIUtils.MiddleCenterLabelStyle, IMGUIUtils.EmptyLayoutOptions); } GUILayout.EndVertical(); } diff --git a/RuntimeUnityEditor.Bepin5/PatchInspector/PatchInspector.cs b/RuntimeUnityEditor.Bepin5/PatchInspector/PatchInspector.cs index 661a050..aa8a358 100644 --- a/RuntimeUnityEditor.Bepin5/PatchInspector/PatchInspector.cs +++ b/RuntimeUnityEditor.Bepin5/PatchInspector/PatchInspector.cs @@ -86,7 +86,7 @@ protected override void OnGUI() /// protected override void DrawContents() { - GUILayout.BeginHorizontal(GUI.skin.box); + GUILayout.BeginHorizontal(GUI.skin.box,IMGUIUtils.EmptyLayoutOptions); { GUILayout.Label("Search: ", IMGUIUtils.LayoutOptionsExpandWidthFalse); @@ -109,7 +109,7 @@ protected override void DrawContents() if (_foundPatches.Count > 0) { _scrollPos = GUILayout.BeginScrollView(_scrollPos, GUI.skin.box); - GUILayout.Label($"Found {_foundPatches.Count} patches", IMGUIUtils.UpperCenterLabelStyle); + GUILayout.Label($"Found {_foundPatches.Count} patches", IMGUIUtils.UpperCenterLabelStyle, IMGUIUtils.EmptyLayoutOptions); for (var i = 0; i < _foundPatches.Count; i++) { @@ -118,9 +118,9 @@ protected override void DrawContents() Color prevColor = GUI.color; GUI.color = patch.IsEnabled ? Color.white : new Color(0.8f, 0.8f, 0.8f, 1f); - GUILayout.BeginVertical(GUI.skin.box); + GUILayout.BeginVertical(GUI.skin.box, IMGUIUtils.EmptyLayoutOptions); { - GUILayout.BeginHorizontal(); + GUILayout.BeginHorizontal(IMGUIUtils.EmptyLayoutOptions); { bool newEnabled = GUILayout.Toggle(patch.IsEnabled, "", IMGUIUtils.LayoutOptionsExpandWidthFalse); if (newEnabled != patch.IsEnabled) @@ -141,7 +141,7 @@ protected override void DrawContents() var patchName = $"Patch: [{patch.PatchType}] {patch.Patch?.PatchMethod?.Name ?? "Not applied"}"; if (patch.Patch == null) GUI.enabled = false; - if (GUILayout.Button(new GUIContent(patchName, null, "Click to see more information about the patch method. Right click for more options."), GUI.skin.label)) + if (GUILayout.Button(new GUIContent(patchName, null, "Click to see more information about the patch method. Right click for more options."), GUI.skin.label, IMGUIUtils.EmptyLayoutOptions)) { if (IMGUIUtils.IsMouseRightClick()) ContextMenu.Instance.Show(patch.Patch.PatchMethod, null, $"MethodInfo: {patch.Patch.PatchMethod?.DeclaringType?.Name}.{patch.Patch.PatchMethod?.Name}", null, null); @@ -151,12 +151,12 @@ protected override void DrawContents() GUI.enabled = true; - if (GUILayout.Button(new GUIContent($"Patcher: {patch.PatcherNamespace}", null, "Click to search for types in this namespace."), GUI.skin.label)) + if (GUILayout.Button(new GUIContent($"Patcher: {patch.PatcherNamespace}", null, "Click to search for types in this namespace."), GUI.skin.label, IMGUIUtils.EmptyLayoutOptions)) Inspector.Instance.Push(new InstanceStackEntry(AccessTools.AllTypes().Where(x => x.Namespace == patch.PatcherNamespace).ToArray(), "Types in " + patch.PatcherNamespace), true); if (GUILayout.Button( new GUIContent($"Assembly: {patch.PatcherAssembly}", null, - $"File: {patch.FilePath}\n\nClick to open explorer focused on this file. Right click for to inspect the Assembly instance."), GUI.skin.label)) + $"File: {patch.FilePath}\n\nClick to open explorer focused on this file. Right click for to inspect the Assembly instance."), GUI.skin.label, IMGUIUtils.EmptyLayoutOptions)) { if (IMGUIUtils.IsMouseRightClick()) ContextMenu.Instance.Show(AppDomain.CurrentDomain.GetAssemblies().FirstOrDefault(x => x.GetName().Name == patch.PatcherAssembly), null, "Assembly: " + patch.PatcherAssembly, @@ -188,13 +188,13 @@ protected override void DrawContents() else if (!string.IsNullOrEmpty(SearchInput)) { GUILayout.Space(10); - GUILayout.Label("No patches found.", IMGUIUtils.UpperCenterLabelStyle); + GUILayout.Label("No patches found.", IMGUIUtils.UpperCenterLabelStyle, IMGUIUtils.EmptyLayoutOptions); GUILayout.FlexibleSpace(); } else { GUILayout.Space(10); - GUILayout.Label("Use the search box to search for currently applied Harmony patches by method, class, or namespace.\n\nExamples: 'OnClick', 'method:OnClick class:AddButtonCtrl', 'namespace:SimpleGame'", IMGUIUtils.UpperCenterLabelStyle); + GUILayout.Label("Use the search box to search for currently applied Harmony patches by method, class, or namespace.\n\nExamples: 'OnClick', 'method:OnClick class:AddButtonCtrl', 'namespace:SimpleGame'", IMGUIUtils.UpperCenterLabelStyle, IMGUIUtils.EmptyLayoutOptions); GUILayout.FlexibleSpace(); } } diff --git a/RuntimeUnityEditor.Core/Utils/Abstractions/GUILayoutShim.cs b/RuntimeUnityEditor.Core/Utils/Abstractions/GUILayoutShim.cs index b3e9364..a5fdfc4 100644 --- a/RuntimeUnityEditor.Core/Utils/Abstractions/GUILayoutShim.cs +++ b/RuntimeUnityEditor.Core/Utils/Abstractions/GUILayoutShim.cs @@ -2,8 +2,12 @@ namespace RuntimeUnityEditor.Core { + ///

+ /// Provides a shim for GUILayout methods that are often missing in IL2CPP. + /// public static class GUILayoutShim { + /// public static GUILayoutOption MaxWidth(float width) { #if IL2CPP @@ -14,6 +18,7 @@ public static GUILayoutOption MaxWidth(float width) #endif } + /// public static GUILayoutOption ExpandWidth(bool expand) { #if IL2CPP @@ -24,6 +29,7 @@ public static GUILayoutOption ExpandWidth(bool expand) #endif } + /// public static GUILayoutOption ExpandHeight(bool expand) { #if IL2CPP @@ -35,6 +41,7 @@ public static GUILayoutOption ExpandHeight(bool expand) } + /// public static GUILayoutOption MinWidth(float width) { #if IL2CPP diff --git a/RuntimeUnityEditor.Core/Utils/IMGUIUtils.cs b/RuntimeUnityEditor.Core/Utils/IMGUIUtils.cs index bcc365e..48f6125 100644 --- a/RuntimeUnityEditor.Core/Utils/IMGUIUtils.cs +++ b/RuntimeUnityEditor.Core/Utils/IMGUIUtils.cs @@ -8,15 +8,14 @@ namespace RuntimeUnityEditor.Core.Utils /// public static class IMGUIUtils { - /// - /// Options with GUILayout.ExpandWidth(true). Useful for avoiding allocations. - /// + /// Options with GUILayout.ExpandWidth(true). Useful for avoiding allocations. public static readonly GUILayoutOption[] LayoutOptionsExpandWidthTrue = { GUILayoutShim.ExpandWidth(true) }; - - /// - /// Options with GUILayout.ExpandWidth(false). Useful for avoiding allocations. - /// + /// Options with GUILayout.ExpandWidth(false). Useful for avoiding allocations. public static readonly GUILayoutOption[] LayoutOptionsExpandWidthFalse = { GUILayoutShim.ExpandWidth(false) }; + /// Options with GUILayout.ExpandWidth(false), GUILayout.ExpandHeight(false). Useful for avoiding allocations. + public static readonly GUILayoutOption[] LayoutOptionsNoExpansion = { GUILayoutShim.ExpandWidth(false), GUILayoutShim.ExpandHeight(false) }; + /// Empty layout options array. Useful for avoiding allocations. + public static readonly GUILayoutOption[] EmptyLayoutOptions = new GUILayoutOption[0]; private static Texture2D SolidBoxTex { get; set; } diff --git a/RuntimeUnityEditor.Core/Windows/Inspector/Inspector.InspectorTab.cs b/RuntimeUnityEditor.Core/Windows/Inspector/Inspector.InspectorTab.cs index 1c37a4c..2a2622b 100644 --- a/RuntimeUnityEditor.Core/Windows/Inspector/Inspector.InspectorTab.cs +++ b/RuntimeUnityEditor.Core/Windows/Inspector/Inspector.InspectorTab.cs @@ -1,18 +1,7 @@ -using System; -using System.Collections; -using System.Collections.Generic; +using System.Collections.Generic; using System.ComponentModel; -using System.Linq; -using System.Reflection; -using System.Runtime.CompilerServices; -using HarmonyLib; using RuntimeUnityEditor.Core.Inspector.Entries; -using RuntimeUnityEditor.Core.ObjectTree; -using RuntimeUnityEditor.Core.Utils; -using RuntimeUnityEditor.Core.Utils.Abstractions; -using RuntimeUnityEditor.Core.Utils.ObjectDumper; using UnityEngine; -using Component = UnityEngine.Component; namespace RuntimeUnityEditor.Core.Inspector { diff --git a/RuntimeUnityEditor.Core/Windows/Inspector/Inspector.cs b/RuntimeUnityEditor.Core/Windows/Inspector/Inspector.cs index 42e1b06..bd2dcf0 100644 --- a/RuntimeUnityEditor.Core/Windows/Inspector/Inspector.cs +++ b/RuntimeUnityEditor.Core/Windows/Inspector/Inspector.cs @@ -8,6 +8,7 @@ using RuntimeUnityEditor.Core.Utils; using RuntimeUnityEditor.Core.Utils.Abstractions; using UnityEngine; +using Object = UnityEngine.Object; namespace RuntimeUnityEditor.Core.Inspector { @@ -191,9 +192,9 @@ protected override void DrawContents() if (tab.InspectorStack.Count == 0) RemoveTab(tab); } - GUILayout.BeginVertical(); + GUILayout.BeginVertical(IMGUIUtils.EmptyLayoutOptions); { - GUILayout.BeginHorizontal(); + GUILayout.BeginHorizontal(IMGUIUtils.EmptyLayoutOptions); { GUILayout.BeginHorizontal(GUI.skin.box, IMGUIUtils.LayoutOptionsExpandWidthTrue); { @@ -209,17 +210,17 @@ protected override void DrawContents() _focusSearchBox = false; } - _showFields = GUILayout.Toggle(_showFields, "Fields"); - _showProperties = GUILayout.Toggle(_showProperties, "Properties"); - _showMethods = GUILayout.Toggle(_showMethods, "Methods"); - _showEvents = GUILayout.Toggle(_showEvents, "Events"); + _showFields = GUILayout.Toggle(_showFields, "Fields", IMGUIUtils.EmptyLayoutOptions); + _showProperties = GUILayout.Toggle(_showProperties, "Properties", IMGUIUtils.EmptyLayoutOptions); + _showMethods = GUILayout.Toggle(_showMethods, "Methods", IMGUIUtils.EmptyLayoutOptions); + _showEvents = GUILayout.Toggle(_showEvents, "Events", IMGUIUtils.EmptyLayoutOptions); #if IL2CPP GUI.color = _il2CPPMemberColor; - _showNative = GUILayout.Toggle(_showNative, new GUIContent("Native", null, "Display members from the IL2CPP runtime (i.e. the game code).")); + _showNative = GUILayout.Toggle(_showNative, new GUIContent("Native", null, "Display members from the IL2CPP runtime (i.e. the game code)."), IMGUIUtils.EmptyLayoutOptions); GUI.color = Color.white; - _showManaged = GUILayout.Toggle(_showManaged, new GUIContent("Managed", null, "Display members from the BepInEx's runtime (i.e. interop and plugin code).")); + _showManaged = GUILayout.Toggle(_showManaged, new GUIContent("Managed", null, "Display members from the BepInEx's runtime (i.e. interop and plugin code)."), IMGUIUtils.EmptyLayoutOptions); #endif - _showDeclaredOnly = GUILayout.Toggle(_showDeclaredOnly, "Only declared"); + _showDeclaredOnly = GUILayout.Toggle(_showDeclaredOnly, "Only declared", IMGUIUtils.EmptyLayoutOptions); /* todo GUILayout.Label("Find:", IMGUIUtils.LayoutOptionsExpandWidthFalse); @@ -242,16 +243,16 @@ protected override void DrawContents() GUILayout.BeginHorizontal(GUI.skin.box, GUILayout.Width(80)); { if (_tabs.Count == 0) GUI.enabled = false; - if (GUILayout.Button("Close all tabs")) + if (GUILayout.Button("Close all tabs", IMGUIUtils.EmptyLayoutOptions)) { _tabs.Clear(); _currentTab = null; } GUI.enabled = true; - _showTooltips = GUILayout.Toggle(_showTooltips, "Tooltips"); + _showTooltips = GUILayout.Toggle(_showTooltips, "Tooltips", IMGUIUtils.EmptyLayoutOptions); - if (GUILayout.Button("Help")) + if (GUILayout.Button("Help", IMGUIUtils.EmptyLayoutOptions)) Push(InspectorHelpObject.Create(), true); } GUILayout.EndHorizontal(); @@ -263,9 +264,9 @@ protected override void DrawContents() if (_tabs.Count >= 2) { _tabScrollPos = GUILayout.BeginScrollView(_tabScrollPos, false, false, - GUI.skin.horizontalScrollbar, GUIStyle.none, GUIStyle.none); //, GUILayout.Height(46) + GUI.skin.horizontalScrollbar, GUIStyle.none, GUIStyle.none, IMGUIUtils.EmptyLayoutOptions); { - GUILayout.BeginHorizontal(GUILayoutShim.ExpandWidth(false), GUILayoutShim.ExpandHeight(false)); + GUILayout.BeginHorizontal(IMGUIUtils.LayoutOptionsNoExpansion); for (var index = 0; index < _tabs.Count; index++) { var tab = _tabs[index]; @@ -298,9 +299,9 @@ protected override void DrawContents() if (currentTab != null) { currentTab.InspectorStackScrollPos = GUILayout.BeginScrollView(currentTab.InspectorStackScrollPos, false, false, - GUI.skin.horizontalScrollbar, GUIStyle.none, GUIStyle.none); //, GUILayout.Height(46) + GUI.skin.horizontalScrollbar, GUIStyle.none, GUIStyle.none, IMGUIUtils.EmptyLayoutOptions); { - GUILayout.BeginHorizontal(GUI.skin.box, GUILayoutShim.ExpandWidth(false), GUILayoutShim.ExpandHeight(false)); + GUILayout.BeginHorizontal(GUI.skin.box, IMGUIUtils.LayoutOptionsNoExpansion); var stackEntries = currentTab.InspectorStack.Reverse().ToArray(); for (var i = 0; i < stackEntries.Length; i++) { @@ -329,9 +330,9 @@ protected override void DrawContents() } GUILayout.EndScrollView(); - GUILayout.BeginVertical(GUI.skin.box); + GUILayout.BeginVertical(GUI.skin.box, IMGUIUtils.EmptyLayoutOptions); { - GUILayout.BeginHorizontal(); + GUILayout.BeginHorizontal(IMGUIUtils.EmptyLayoutOptions); { GUILayout.Space(1); GUILayout.Label("Value/return type", GUI.skin.box, _inspectorTypeWidth); @@ -368,14 +369,14 @@ protected override void DrawContents() else { // Nothing to show - GUILayout.BeginHorizontal(GUI.skin.box); + GUILayout.BeginHorizontal(GUI.skin.box, IMGUIUtils.EmptyLayoutOptions); { GUILayout.Space(8); - GUILayout.BeginVertical(); + GUILayout.BeginVertical(IMGUIUtils.EmptyLayoutOptions); { GUILayout.Space(8); - GUILayout.Label("Nothing to show. You can inspect objects by clicking the \"Inspect\" buttons in other windows. Each object will be opened in a new tab. You can also send instances or types to be inspected from repl by using the \"seti(instance)\" and \"setis(type)\" commands."); - GUILayout.Label("Tip: You can right click on a member inside inspector to open it in a new tab instead of opening it in the current tab. You can also right click on tabs to close them."); + GUILayout.Label("Nothing to show. You can inspect objects by clicking the \"Inspect\" buttons in other windows. Each object will be opened in a new tab. You can also send instances or types to be inspected from repl by using the \"seti(instance)\" and \"setis(type)\" commands.", IMGUIUtils.EmptyLayoutOptions); + GUILayout.Label("Tip: You can right click on a member inside inspector to open it in a new tab instead of opening it in the current tab. You can also right click on tabs to close them.", IMGUIUtils.EmptyLayoutOptions); GUILayout.Space(8); } GUILayout.EndVertical(); @@ -400,6 +401,84 @@ private static string LimitStringLengthForPreview(string name, int maxLetters) return name; } + #region Entry list filtering + + private readonly List _filteredListEntries = new List(); + + /// + protected override void Update() + { + base.Update(); + + _filteredListEntries.Clear(); + + var tab = GetCurrentTab(); + if (tab == null) return; + + var searchStr = SearchString; + for (var i = 0; i < tab.FieldCache.Count; i++) + { + var cacheEntry = tab.FieldCache[i]; + if (searchStr.Length > 0 && !EntryMatchesSearchString(cacheEntry, searchStr)) + continue; + + if (!EntryTypeIsVisible(cacheEntry)) + continue; + + _filteredListEntries.Add(cacheEntry); + } + } + + private static bool EntryMatchesSearchString(ICacheEntry x, string searchString) + { + try + { + var name = x.Name(); + if (name != null && name.Contains(searchString, StringComparison.OrdinalIgnoreCase)) return true; + var typeName = x.TypeName(); + if (typeName != null && typeName.Contains(searchString, StringComparison.OrdinalIgnoreCase)) return true; + var value = x.GetValue(); + if (value == null || (value is Object obj && !obj)) return false; + return value.ToString().Contains(searchString, StringComparison.OrdinalIgnoreCase); + } + catch + { + return false; + } + } + + private bool EntryTypeIsVisible(ICacheEntry x) + { + // TODO add filtering option + if (x is IFakeCacheEntry) return true; +#if IL2CPP + if (IL2CPPCacheEntryHelper.IsIl2CppCacheEntry(x)) + { + if (!_showNative) + return false; + } + else + { + if (!_showManaged) + return false; + } + if (x is IL2CPPFieldCacheEntry cf) + return _showFields && (!_showDeclaredOnly || cf.IsDeclared); +#endif + switch (x) + { + case PropertyCacheEntry p when !_showProperties || _showDeclaredOnly && !p.IsDeclared: + case FieldCacheEntry f when !_showFields || _showDeclaredOnly && !f.IsDeclared: + case MethodCacheEntry m when !_showMethods || _showDeclaredOnly && !m.IsDeclared: + case EventCacheEntry e when !_showEvents || _showDeclaredOnly && !e.IsDeclared: + return false; + default: + return true; + } + } + + #endregion + private void DrawContentScrollView(InspectorTab tab) { if (tab == null || tab.InspectorStack.Count == 0) @@ -409,64 +488,10 @@ private void DrawContentScrollView(InspectorTab tab) } var currentItem = tab.CurrentStackItem; - currentItem.ScrollPosition = GUILayout.BeginScrollView(currentItem.ScrollPosition); + currentItem.ScrollPosition = GUILayout.BeginScrollView(currentItem.ScrollPosition, IMGUIUtils.EmptyLayoutOptions); { - GUILayout.BeginVertical(); + GUILayout.BeginVertical(IMGUIUtils.EmptyLayoutOptions); { - //todo optimize gc - IEnumerable visibleFieldsQuery = tab.FieldCache; - if (!string.IsNullOrEmpty(SearchString)) - { - visibleFieldsQuery = visibleFieldsQuery.Where(x => - { - try - { - var name = x.Name(); - if (name != null && name.Contains(SearchString, StringComparison.OrdinalIgnoreCase)) return true; - var typeName = x.TypeName(); - if (typeName != null && typeName.Contains(SearchString, StringComparison.OrdinalIgnoreCase)) return true; - var value = x.GetValue(); - if (value == null || (value is UnityEngine.Object obj && !obj)) return false; - return value.ToString().Contains(SearchString, StringComparison.OrdinalIgnoreCase); - } - catch - { - return false; - } - }); - } - visibleFieldsQuery = visibleFieldsQuery.Where(x => - { - // TODO add filtering option - if (x is IFakeCacheEntry) - return true; -#if IL2CPP - if (IL2CPPCacheEntryHelper.IsIl2CppCacheEntry(x)) - { - if (!_showNative) - return false; - } - else - { - if (!_showManaged) - return false; - } - if (x is IL2CPPFieldCacheEntry cf) - return _showFields && (!_showDeclaredOnly || cf.IsDeclared); -#endif - switch (x) - { - case PropertyCacheEntry p when !_showProperties || _showDeclaredOnly && !p.IsDeclared: - case FieldCacheEntry f when !_showFields || _showDeclaredOnly && !f.IsDeclared: - case MethodCacheEntry m when !_showMethods || _showDeclaredOnly && !m.IsDeclared: - case EventCacheEntry e when !_showEvents || _showDeclaredOnly && !e.IsDeclared: - return false; - default: - return true; - } - }); - var visibleFields = visibleFieldsQuery.ToList(); - var scrollPositionY = (int)currentItem.ScrollPosition.y; var scrollMaxVisibleY = scrollPositionY + ((int)WindowRect.height - 130); // TODO conservative value, properly measure at runtime for less overdraw @@ -474,9 +499,9 @@ private void DrawContentScrollView(InspectorTab tab) var index = 0; // Empty space at the top - for (; index < visibleFields.Count; index++) + for (; index < _filteredListEntries.Count; index++) { - var newHeight = topCombinedHeight + visibleFields[index].ItemHeight; + var newHeight = topCombinedHeight + _filteredListEntries[index].ItemHeight; if (newHeight >= scrollPositionY) break; else topCombinedHeight = newHeight; } @@ -485,9 +510,9 @@ private void DrawContentScrollView(InspectorTab tab) GUILayout.Space(topCombinedHeight); // Actual entries - for (; index < visibleFields.Count; index++) + for (; index < _filteredListEntries.Count; index++) { - var entry = visibleFields[index]; + var entry = _filteredListEntries[index]; DrawSingleContentEntry(entry); @@ -508,8 +533,8 @@ private void DrawContentScrollView(InspectorTab tab) // Empty space at the bottom var bottomCombinedHeight = 0; - for (; index < visibleFields.Count; index++) - bottomCombinedHeight += visibleFields[index].ItemHeight; + for (; index < _filteredListEntries.Count; index++) + bottomCombinedHeight += _filteredListEntries[index].ItemHeight; try { @@ -544,7 +569,7 @@ private void DrawSingleContentEntry(ICacheEntry entry) } catch (Exception ex) { - RuntimeUnityEditorCore.Logger.Log(LogLevel.Error, $"[{Title}] Failed to draw setting {entry?.Name()} - {ex.Message}"); + RuntimeUnityEditorCore.Logger.Log(LogLevel.Error, $"[{Title}] Failed to draw setting {entry.Name()} - {ex.Message}"); } } GUILayout.EndHorizontal(); diff --git a/RuntimeUnityEditor.Core/Windows/Inspector/VariableFieldDrawer.cs b/RuntimeUnityEditor.Core/Windows/Inspector/VariableFieldDrawer.cs index 9f203ad..e8bd842 100644 --- a/RuntimeUnityEditor.Core/Windows/Inspector/VariableFieldDrawer.cs +++ b/RuntimeUnityEditor.Core/Windows/Inspector/VariableFieldDrawer.cs @@ -138,7 +138,7 @@ private static void DrawFlagsField(ICacheEntry setting, IList enumValues, object { for (var index = 0; index < allValues.Length;) { - GUILayout.BeginHorizontal(); + GUILayout.BeginHorizontal(IMGUIUtils.EmptyLayoutOptions); { var currentWidth = 0; for (; index < allValues.Length; index++) @@ -340,7 +340,7 @@ private static void DrawAnyTexture(object obj) if (tex is Texture2D t2d) extraData = $"\nFormat={t2d.format} Mips={t2d.mipmapCount}"; else if (tex is RenderTexture rt) extraData = $"\nFormat={rt.format} Mips={rt.useMipMap} AA={rt.antiAliasing} Depth={rt.depth} Cube={rt.isCubemap} Volume={rt.isVolume}"; - GUILayout.Label($"Name={tex.name} Size={tex.width}x{tex.height} Filter={tex.filterMode} Wrap={tex.wrapMode} {extraData}"); + GUILayout.Label($"Name={tex.name} Size={tex.width}x{tex.height} Filter={tex.filterMode} Wrap={tex.wrapMode} {extraData}", IMGUIUtils.EmptyLayoutOptions); GUILayout.FlexibleSpace(); @@ -360,7 +360,7 @@ private static void DrawSprite(Sprite spr, string objectName) var isNullOrDestroyed = spr.IsNullOrDestroyedStr(); if (isNullOrDestroyed != null) { - GUILayout.Label(isNullOrDestroyed); + GUILayout.Label(isNullOrDestroyed, IMGUIUtils.EmptyLayoutOptions); GUILayout.FlexibleSpace(); return; } @@ -377,7 +377,7 @@ private static void DrawSprite(Sprite spr, string objectName) GUILayout.Label($"Name={spr.name} Rect={spr.rect} Pivot={spr.pivot} Packed={spr.packed} {extraData}"); #else // pivot is not supported in Unity 4.x - GUILayout.Label($"Name={spr.name} Rect={spr.rect} Pivot={spr.TryGetPropertyValue(nameof(Sprite.pivot)) ?? "UNSUPPORTED"} Packed={spr.packed} {extraData}"); + GUILayout.Label($"Name={spr.name} Rect={spr.rect} Pivot={spr.TryGetPropertyValue(nameof(Sprite.pivot)) ?? "UNSUPPORTED"} Packed={spr.packed} {extraData}", IMGUIUtils.EmptyLayoutOptions); #endif GUILayout.FlexibleSpace(); @@ -439,7 +439,7 @@ private static void DrawEventInvokeField(EventCacheEntry @event) // ShowInvokeWindow(backingDelegate.DynamicInvoke(), @event.Instance); var invocationList = backingDelegate.GetInvocationList(); - if (GUILayout.Button(invocationList.Length + " listener(s)")) + if (GUILayout.Button(invocationList.Length + " listener(s)", IMGUIUtils.EmptyLayoutOptions)) Inspector.Instance.Push(new InstanceStackEntry(invocationList, @event.Name() + " Invocation List", @event), false); } @@ -517,12 +517,12 @@ public static void DrawInvokeWindow() GUI.FocusWindow(_currentlyInvokingWindowId); } - _currentlyInvokingRect = GUILayout.Window(_currentlyInvokingWindowId, _currentlyInvokingRect, (GUI.WindowFunction)DrawInvokeWindowFunc, "Invoke " + _currentlyInvoking.Name); + _currentlyInvokingRect = GUILayout.Window(_currentlyInvokingWindowId, _currentlyInvokingRect, (GUI.WindowFunction)DrawInvokeWindowFunc, "Invoke " + _currentlyInvoking.Name, IMGUIUtils.EmptyLayoutOptions); } private static void DrawInvokeWindowFunc(int id) { - GUILayout.BeginVertical(); + GUILayout.BeginVertical(IMGUIUtils.EmptyLayoutOptions); { _currentlyInvokingPos = GUILayout.BeginScrollView(_currentlyInvokingPos, GUI.skin.box); { @@ -531,12 +531,12 @@ private static void DrawInvokeWindowFunc(int id) var generics = _currentlyInvokingArgs; if (generics.Length > 0) { - GUILayout.Label("Generic arguments (Input a Type name, or pick a Type object from clipboard by typing #0, #1, #2...)"); + GUILayout.Label("Generic arguments (Input a Type name, or pick a Type object from clipboard by typing #0, #1, #2...)", IMGUIUtils.EmptyLayoutOptions); for (var index = 0; index < generics.Length; index++) { var genericArg = generics[index]; - GUILayout.BeginHorizontal(); + GUILayout.BeginHorizontal(IMGUIUtils.EmptyLayoutOptions); GUILayout.Label("#" + index, GUILayout.Width(indexColWidth)); GUILayout.Label(genericArg.FullDescription(), GUILayout.Width((_currentlyInvokingRect.width - indexColWidth) / 2.3f)); _currentlyInvokingArgsValues[index] = GUILayout.TextField(_currentlyInvokingArgsValues[index], IMGUIUtils.LayoutOptionsExpandWidthTrue); @@ -547,12 +547,12 @@ private static void DrawInvokeWindowFunc(int id) var parameters = _currentlyInvokingParams; if (parameters.Length > 0) { - GUILayout.Label("Parameters (Input a value, or pick a value from clipboard by typing #0, #1, #2...)"); + GUILayout.Label("Parameters (Input a value, or pick a value from clipboard by typing #0, #1, #2...)", IMGUIUtils.EmptyLayoutOptions); for (var index = 0; index < parameters.Length; index++) { var parameter = parameters[index]; - GUILayout.BeginHorizontal(); + GUILayout.BeginHorizontal(IMGUIUtils.EmptyLayoutOptions); GUILayout.Label("#" + index, GUILayout.Width(indexColWidth)); GUILayout.Label(parameter.ParameterType.FullDescription() + " " + parameter.Name, GUILayout.Width((_currentlyInvokingRect.width - indexColWidth) / 2.3f)); _currentlyInvokingParamsValues[index] = GUILayout.TextField(_currentlyInvokingParamsValues[index], IMGUIUtils.LayoutOptionsExpandWidthTrue); @@ -561,21 +561,21 @@ private static void DrawInvokeWindowFunc(int id) } if (generics.Length == 0 && parameters.Length == 0) - GUILayout.Label("This method has no parameters, click Invoke to run it."); + GUILayout.Label("This method has no parameters, click Invoke to run it.", IMGUIUtils.EmptyLayoutOptions); } GUILayout.EndScrollView(); - GUILayout.BeginHorizontal(GUI.skin.box); + GUILayout.BeginHorizontal(GUI.skin.box, IMGUIUtils.EmptyLayoutOptions); { GUILayout.Label("Invoke result: ", IMGUIUtils.LayoutOptionsExpandWidthFalse); GUILayout.TextArea(_currentlyInvokingException != null ? _currentlyInvokingException.GetType().Name + " - " + _currentlyInvokingException.Message : _currentlyInvokingResult == null ? "None / NULL" : _currentlyInvokingResult.ToString(), GUI.skin.label, IMGUIUtils.LayoutOptionsExpandWidthTrue); } GUILayout.EndHorizontal(); - GUILayout.BeginHorizontal(GUI.skin.box); + GUILayout.BeginHorizontal(GUI.skin.box, IMGUIUtils.EmptyLayoutOptions); { //todo - if (GUILayout.Button("Invoke")) + if (GUILayout.Button("Invoke", IMGUIUtils.EmptyLayoutOptions)) { try { @@ -655,12 +655,12 @@ private static void DrawInvokeWindowFunc(int id) GUILayout.FlexibleSpace(); GUI.enabled = _currentlyInvokingResult != null; - if (GUILayout.Button("Inspect result")) + if (GUILayout.Button("Inspect result", IMGUIUtils.EmptyLayoutOptions)) { Inspector.Instance.Push(new InstanceStackEntry(_currentlyInvokingResult, "Invoke " + _currentlyInvoking.Name), false); _currentlyInvoking = null; } - if (GUILayout.Button("Copy result to clipboard")) + if (GUILayout.Button("Copy result to clipboard", IMGUIUtils.EmptyLayoutOptions)) { ClipboardWindow.Contents.Add(_currentlyInvokingResult); } @@ -668,7 +668,7 @@ private static void DrawInvokeWindowFunc(int id) GUILayout.FlexibleSpace(); - if (GUILayout.Button("Close")) + if (GUILayout.Button("Close", IMGUIUtils.EmptyLayoutOptions)) _currentlyInvoking = null; } GUILayout.EndHorizontal(); diff --git a/RuntimeUnityEditor.Core/Windows/ObjectTree/ObjectTreeViewer.cs b/RuntimeUnityEditor.Core/Windows/ObjectTree/ObjectTreeViewer.cs index 69e5e82..ff9c310 100644 --- a/RuntimeUnityEditor.Core/Windows/ObjectTree/ObjectTreeViewer.cs +++ b/RuntimeUnityEditor.Core/Windows/ObjectTree/ObjectTreeViewer.cs @@ -40,8 +40,12 @@ public sealed class ObjectTreeViewer : Window private readonly Dictionary _imagePreviewCache = new Dictionary(); private static readonly GUILayoutOption _drawVector3FieldWidth = GUILayout.Width(38); private static readonly GUILayoutOption _drawVector3FieldHeight = GUILayout.Height(19); - private static readonly GUILayoutOption _drawVector3SliderHeight = GUILayout.Height(10); + private static readonly GUILayoutOption[] _drawVector3FieldOptions = { _drawVector3FieldWidth, _drawVector3FieldHeight }; private static readonly GUILayoutOption _drawVector3SliderWidth = GUILayout.Width(33); + private static readonly GUILayoutOption _drawVector3SliderHeight = GUILayout.Height(10); + private static readonly GUILayoutOption[] _drawVector3SliderOptions = { _drawVector3SliderWidth, _drawVector3SliderHeight }; + + private static readonly GUILayoutOption[] _goListEntryLayoutOptions = { GUILayoutShim.ExpandWidth(true), GUILayoutShim.MinWidth(200), GUILayoutShim.ExpandHeight(false) }; /// /// Invoked whenever a new Transform is selected in the tree. @@ -166,11 +170,11 @@ private void DisplayObjectTreeHelper(GameObject go, int indent, ref int currentC GUI.color = new Color(1, 1, 1, 0.6f); } - GUILayout.BeginHorizontal(); + GUILayout.BeginHorizontal(IMGUIUtils.EmptyLayoutOptions); { GUILayout.Space(indent * 20f); - GUILayout.BeginHorizontal(); + GUILayout.BeginHorizontal(IMGUIUtils.EmptyLayoutOptions); { if (go.transform.childCount != 0) { @@ -184,7 +188,7 @@ private void DisplayObjectTreeHelper(GameObject go, int indent, ref int currentC GUILayout.Space(20f); } - if (GUILayout.Button(go.name, GUI.skin.label, GUILayoutShim.ExpandWidth(true), GUILayoutShim.MinWidth(200), GUILayoutShim.ExpandHeight(false))) + if (GUILayout.Button(go.name, GUI.skin.label, _goListEntryLayoutOptions)) { if (IMGUIUtils.IsMouseRightClick()) { @@ -201,6 +205,7 @@ private void DisplayObjectTreeHelper(GameObject go, int indent, ref int currentC else { SelectedTransform = go.transform; + _componentNameContentCache.Clear(); } } } @@ -235,7 +240,7 @@ private void DisplayObjectTreeHelper(GameObject go, int indent, ref int currentC /// protected override void DrawContents() { - GUILayout.BeginVertical(); + GUILayout.BeginVertical(IMGUIUtils.EmptyLayoutOptions); { DisplayObjectTree(); @@ -252,13 +257,13 @@ private void DisplayObjectProperties() { if (!SelectedTransform) { - GUILayout.Label("No object selected"); + GUILayout.Label("No object selected", IMGUIUtils.EmptyLayoutOptions); } else { DrawTransformControls(); - GUILayout.BeginHorizontal(); + GUILayout.BeginHorizontal(IMGUIUtils.EmptyLayoutOptions); { GUILayout.Label("Search components ", IMGUIUtils.LayoutOptionsExpandWidthFalse); @@ -286,21 +291,21 @@ private void DisplayObjectProperties() private void DrawTransformControls() { - GUILayout.BeginVertical(GUI.skin.box); + GUILayout.BeginVertical(GUI.skin.box, IMGUIUtils.EmptyLayoutOptions); { var transform = SelectedTransform; var fullTransfromPath = transform.GetFullTransfromPath(); - GUILayout.TextArea(fullTransfromPath, GUI.skin.label); + GUILayout.TextArea(fullTransfromPath, GUI.skin.label, IMGUIUtils.EmptyLayoutOptions); - GUILayout.BeginHorizontal(); + GUILayout.BeginHorizontal(IMGUIUtils.EmptyLayoutOptions); { var selectedGameObject = transform.gameObject; - GUILayout.Label($"Layer {selectedGameObject.layer} ({LayerMask.LayerToName(selectedGameObject.layer)})"); + GUILayout.Label($"Layer {selectedGameObject.layer} ({LayerMask.LayerToName(selectedGameObject.layer)})", IMGUIUtils.EmptyLayoutOptions); GUILayout.Space(8); - GUILayout.Toggle(selectedGameObject.isStatic, "isStatic"); + GUILayout.Toggle(selectedGameObject.isStatic, "isStatic", IMGUIUtils.EmptyLayoutOptions); GUI.changed = false; var newVal = GUILayout.Toggle(selectedGameObject.activeSelf, "Active", IMGUIUtils.LayoutOptionsExpandWidthFalse); @@ -309,10 +314,10 @@ private void DrawTransformControls() GUILayout.FlexibleSpace(); - if (GUILayout.Button("Inspect")) + if (GUILayout.Button("Inspect", IMGUIUtils.EmptyLayoutOptions)) OnInspectorOpen(new InstanceStackEntry(selectedGameObject, selectedGameObject.name)); - if (GUILayout.Button("X")) + if (GUILayout.Button("X", IMGUIUtils.EmptyLayoutOptions)) Change.Action("Object.Destroy({0})", selectedGameObject, Object.Destroy); } GUILayout.EndHorizontal(); @@ -338,15 +343,15 @@ private static void DrawVector3(string memberName, Transform transform, Action _componentNameContentCache = new Dictionary(); private void DrawSingleComponent(Component component) { - GUILayout.BeginHorizontal(GUI.skin.box); + GUILayout.BeginHorizontal(GUI.skin.box, IMGUIUtils.EmptyLayoutOptions); { if (component is Behaviour bh) { @@ -384,8 +390,13 @@ private void DrawSingleComponent(Component component) Change.MemberAssignment(bh, enabledNew, b => b.enabled); } - var type = component.GetType(); - if (GUILayout.Button(new GUIContent(type.Name, null, $"{component}\n\nFull type: {type.GetFancyDescription()}\n\nLeft click to open in Inspector\nRight click to for more options"), GUI.skin.label)) + if (!_componentNameContentCache.TryGetValue(component, out var componentName)) + { + var type = component.GetType(); + componentName = new GUIContent(type.Name, null, $"{component}\n\nFull type: {type.GetFancyDescription()}\n\nLeft click to open in Inspector\nRight click to for more options"); + _componentNameContentCache.Add(component, componentName); + } + if (GUILayout.Button(componentName, GUI.skin.label, IMGUIUtils.EmptyLayoutOptions)) { if (IMGUIUtils.IsMouseRightClick()) { @@ -395,7 +406,7 @@ private void DrawSingleComponent(Component component) { var transform = component.transform; OnInspectorOpen(new InstanceStackEntry(transform, transform.name), - new InstanceStackEntry(component, type.GetSourceCodeRepresentation())); + new InstanceStackEntry(component, component.GetType().GetSourceCodeRepresentation())); } } @@ -406,7 +417,7 @@ private void DrawSingleComponent(Component component) var imgSprite = img.sprite; if (imgSprite != null) { - GUILayout.Label(imgSprite.name); + GUILayout.Label(imgSprite.name, IMGUIUtils.EmptyLayoutOptions); var texture = imgSprite.texture; if (texture != null) { @@ -427,7 +438,7 @@ private void DrawSingleComponent(Component component) if (tex != null) { - if (GUILayout.Button(tex, GUI.skin.box)) + if (GUILayout.Button(tex, GUI.skin.box, IMGUIUtils.EmptyLayoutOptions)) ObjectViewWindow.Instance.SetShownObject(tex, imgSprite.name); texShown = true; } @@ -436,50 +447,50 @@ private void DrawSingleComponent(Component component) if (!texShown && img.mainTexture != null) { - if (GUILayout.Button(img.mainTexture, GUI.skin.box)) + if (GUILayout.Button(img.mainTexture, GUI.skin.box, IMGUIUtils.EmptyLayoutOptions)) ObjectViewWindow.Instance.SetShownObject(img.mainTexture, img.ToString()); texShown = true; } if (!texShown) - GUILayout.Label("Can't display texture"); + GUILayout.Label("Can't display texture", IMGUIUtils.EmptyLayoutOptions); GUILayout.FlexibleSpace(); break; case Slider b: { for (var i = 0; i < b.onValueChanged.GetPersistentEventCount(); ++i) - GUILayout.Label(ToStringConverter.EventEntryToString(b.onValueChanged, i)); + GUILayout.Label(ToStringConverter.EventEntryToString(b.onValueChanged, i), IMGUIUtils.EmptyLayoutOptions); GUILayout.FlexibleSpace(); - if (GUILayout.Button("?")) + if (GUILayout.Button("?", IMGUIUtils.EmptyLayoutOptions)) ObjectViewWindow.Instance.SetShownObject(ReflectionUtils.GetEventDetails(b.onValueChanged), $"{b} / {b.onValueChanged} - Event details"); break; } case Text text: - GUILayout.Label($"{text.text} {text.font} {text.fontStyle} {text.fontSize} {text.alignment} {text.resizeTextForBestFit} {text.color}"); + GUILayout.Label($"{text.text} {text.font} {text.fontStyle} {text.fontSize} {text.alignment} {text.resizeTextForBestFit} {text.color}", IMGUIUtils.EmptyLayoutOptions); GUILayout.FlexibleSpace(); break; case RawImage r: var rMainTexture = r.mainTexture; if (rMainTexture != null) { - if (GUILayout.Button(rMainTexture, GUI.skin.box)) + if (GUILayout.Button(rMainTexture, GUI.skin.box, IMGUIUtils.EmptyLayoutOptions)) ObjectViewWindow.Instance.SetShownObject(rMainTexture, r.ToString()); } else { - GUILayout.Label("Can't display texture"); + GUILayout.Label("Can't display texture", IMGUIUtils.EmptyLayoutOptions); } GUILayout.FlexibleSpace(); break; case Renderer re: var reMaterial = re.sharedMaterial ?? re.material; - GUILayout.Label(reMaterial != null ? reMaterial.shader.name : "[No material]"); + GUILayout.Label(reMaterial != null ? reMaterial.shader.name : "[No material]", IMGUIUtils.EmptyLayoutOptions); if (reMaterial != null && reMaterial.mainTexture != null) { - if (GUILayout.Button(reMaterial.mainTexture, GUI.skin.box)) + if (GUILayout.Button(reMaterial.mainTexture, GUI.skin.box, IMGUIUtils.EmptyLayoutOptions)) ObjectViewWindow.Instance.SetShownObject(reMaterial.mainTexture, re.ToString()); } GUILayout.FlexibleSpace(); @@ -488,13 +499,13 @@ private void DrawSingleComponent(Component component) { var eventObj = b.onClick; for (var i = 0; i < eventObj.GetPersistentEventCount(); ++i) - GUILayout.Label(ToStringConverter.EventEntryToString(eventObj, i)); + GUILayout.Label(ToStringConverter.EventEntryToString(eventObj, i), IMGUIUtils.EmptyLayoutOptions); try { var calls = eventObj.GetPrivateExplicit("m_Calls").GetPrivate("m_RuntimeCalls").CastToEnumerable(); foreach (var call in calls) - GUILayout.Label(ToStringConverter.ObjectToString(call.GetPrivate("Delegate"))); + GUILayout.Label(ToStringConverter.ObjectToString(call.GetPrivate("Delegate")), IMGUIUtils.EmptyLayoutOptions); } catch (NullReferenceException) { } #if IL2CPP @@ -503,7 +514,7 @@ private void DrawSingleComponent(Component component) catch (Exception e) { RuntimeUnityEditorCore.Logger.Log(LogLevel.Error, e); } GUILayout.FlexibleSpace(); - if (GUILayout.Button("?")) + if (GUILayout.Button("?", IMGUIUtils.EmptyLayoutOptions)) ObjectViewWindow.Instance.SetShownObject(ReflectionUtils.GetEventDetails(b.onClick), $"{b} / {b.onClick} - Event details"); break; } @@ -511,13 +522,13 @@ private void DrawSingleComponent(Component component) { var eventObj = b.onValueChanged; for (var i = 0; i < eventObj.GetPersistentEventCount(); ++i) - GUILayout.Label(ToStringConverter.EventEntryToString(b.onValueChanged, i)); + GUILayout.Label(ToStringConverter.EventEntryToString(b.onValueChanged, i), IMGUIUtils.EmptyLayoutOptions); try { var calls = b.onValueChanged.GetPrivateExplicit("m_Calls").GetPrivate("m_RuntimeCalls").CastToEnumerable(); foreach (var call in calls) - GUILayout.Label(ToStringConverter.ObjectToString(call.GetPrivate("Delegate"))); + GUILayout.Label(ToStringConverter.ObjectToString(call.GetPrivate("Delegate")), IMGUIUtils.EmptyLayoutOptions); } catch (NullReferenceException) { } #if IL2CPP @@ -526,19 +537,19 @@ private void DrawSingleComponent(Component component) catch (Exception e) { RuntimeUnityEditorCore.Logger.Log(LogLevel.Error, e); } GUILayout.FlexibleSpace(); - if (GUILayout.Button("?")) + if (GUILayout.Button("?", IMGUIUtils.EmptyLayoutOptions)) ObjectViewWindow.Instance.SetShownObject(ReflectionUtils.GetEventDetails(b.onValueChanged), $"{b} / {b.onValueChanged} - Event details"); break; } case RectTransform rt: - GUILayout.BeginVertical(); + GUILayout.BeginVertical(IMGUIUtils.EmptyLayoutOptions); { DrawVector2(nameof(RectTransform.anchorMin), rt, (t, vector2) => ((RectTransform)t).anchorMin = vector2, t => ((RectTransform)t).anchorMin, 0, 1); DrawVector2(nameof(RectTransform.anchorMax), rt, (t, vector2) => ((RectTransform)t).anchorMax = vector2, t => ((RectTransform)t).anchorMax, 0, 1); DrawVector2(nameof(RectTransform.offsetMin), rt, (t, vector2) => ((RectTransform)t).offsetMin = vector2, t => ((RectTransform)t).offsetMin, -1000, 1000); DrawVector2(nameof(RectTransform.offsetMax), rt, (t, vector2) => ((RectTransform)t).offsetMax = vector2, t => ((RectTransform)t).offsetMax, -1000, 1000); DrawVector2(nameof(RectTransform.sizeDelta), rt, (t, vector2) => ((RectTransform)t).sizeDelta = vector2, t => ((RectTransform)t).sizeDelta, -1000, 1000); - GUILayout.Label("rect " + rt.rect); + GUILayout.Label("rect " + rt.rect, IMGUIUtils.EmptyLayoutOptions); } GUILayout.EndVertical(); break; @@ -554,7 +565,7 @@ private void DrawSingleComponent(Component component) private string _searchTextComponents = string.Empty; private void DisplayObjectTree() { - GUILayout.BeginVertical(GUI.skin.box); + GUILayout.BeginVertical(GUI.skin.box, IMGUIUtils.EmptyLayoutOptions); { DisplayTreeSearchBox(); @@ -597,9 +608,9 @@ private void DisplayTreeSearchBox() // add info markings to list items on right // scene, prefab, etc - GUILayout.BeginVertical(GUI.skin.box); + GUILayout.BeginVertical(GUI.skin.box, IMGUIUtils.EmptyLayoutOptions); { - GUILayout.BeginHorizontal(); + GUILayout.BeginHorizontal(IMGUIUtils.EmptyLayoutOptions); { GUILayout.Label(_searchLabelContent, IMGUIUtils.LayoutOptionsExpandWidthFalse); @@ -623,12 +634,12 @@ private void DisplayTreeSearchBox() } GUILayout.EndHorizontal(); - GUILayout.BeginHorizontal(); + GUILayout.BeginHorizontal(IMGUIUtils.EmptyLayoutOptions); { GUI.changed = false; - _searchNames = GUILayout.Toggle(_searchNames, _searchNamesContent); - _searchComponents.Value = GUILayout.Toggle(_searchComponents.Value, _searchComponentsContent); - _searchProperties.Value = GUILayout.Toggle(_searchProperties.Value, _searchPropertiesContent); + _searchNames = GUILayout.Toggle(_searchNames, _searchNamesContent, IMGUIUtils.EmptyLayoutOptions); + _searchComponents.Value = GUILayout.Toggle(_searchComponents.Value, _searchComponentsContent, IMGUIUtils.EmptyLayoutOptions); + _searchProperties.Value = GUILayout.Toggle(_searchProperties.Value, _searchPropertiesContent, IMGUIUtils.EmptyLayoutOptions); if (GUI.changed) UpdateSearch(); @@ -683,11 +694,12 @@ private void DisplayTreeSearchBox() private readonly GUIContent _sceneLabelContent = new GUIContent("Scene: ", null, "Multiple scenes can be loaded at the same time, in which case objects that belong to them all exist at the same time." + "\nThe dropdown lists all currently loaded scenes. Select one of them to only show objects that belong to it." + "\n\nWhen a scene is unloaded, all of its objects are marked to be destroyed (in some cases they are not cleaned up until Resources.UnloadUnusedResources)."); + private void DisplaySceneControls() { if (!UnityFeatureHelper.SupportsScenes) return; - GUILayout.BeginHorizontal(GUI.skin.box); + GUILayout.BeginHorizontal(GUI.skin.box, IMGUIUtils.EmptyLayoutOptions); { GUILayout.Label(_sceneLabelContent, IMGUIUtils.LayoutOptionsExpandWidthFalse); diff --git a/RuntimeUnityEditor.Core/Windows/ObjectTree/RootGameObjectSearcher.cs b/RuntimeUnityEditor.Core/Windows/ObjectTree/RootGameObjectSearcher.cs index 6e178e9..bb01b0a 100644 --- a/RuntimeUnityEditor.Core/Windows/ObjectTree/RootGameObjectSearcher.cs +++ b/RuntimeUnityEditor.Core/Windows/ObjectTree/RootGameObjectSearcher.cs @@ -223,6 +223,16 @@ public void Search(string searchString, bool searchNames, bool searchComponents, } } + private static readonly HashSet _searchMemberBlacklist = new HashSet + { + "parent", "parentInternal", "root", "transform", "gameObject", + // Animator properties inaccessible outside of OnAnimatorIK + "bodyPosition", "bodyRotation", + // AudioSource obsolete properties + "minVolume", "maxVolume", "rolloffFactor", + // NavMeshAgent properties often spewing errors + "destination", "remainingDistance" + }; /// /// Search for a string inside a given component. Component name is always searched. /// @@ -234,54 +244,41 @@ public static bool SearchInComponent(string searchString, Component c, bool sear if (c == null) return false; var type = c.GetType(); - if (type.Name.Contains(searchString, StringComparison.InvariantCultureIgnoreCase)) + if (type.Name.Contains(searchString, StringComparison.OrdinalIgnoreCase)) return true; if (!searchProperties) return false; - var nameBlacklist = new HashSet - { - "parent", "parentInternal", "root", "transform", "gameObject", - // Animator properties inaccessible outside of OnAnimatorIK - "bodyPosition", "bodyRotation", - // AudioSource obsolete properties - "minVolume", "maxVolume", "rolloffFactor", - // NavMeshAgent properties often spewing errors - "destination", "remainingDistance" - }; - var typeBlacklist = new[] { typeof(bool) }; - - foreach (var prop in type - .GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic) - .Where(x => x.CanRead && !nameBlacklist.Contains(x.Name) && - !typeBlacklist.Contains(x.PropertyType))) + foreach (var prop in type.GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)) { - try - { - if (prop.GetValue(c, null).ToString() - .Contains(searchString, StringComparison.InvariantCultureIgnoreCase)) - return true; - } - catch + if (prop.PropertyType != typeof(bool) && prop.CanRead && !_searchMemberBlacklist.Contains(prop.Name)) { - // Skip invalid values + try + { + if (prop.GetValue(c, null).ToString().Contains(searchString, StringComparison.InvariantCultureIgnoreCase)) + return true; + } + catch + { + // Skip invalid values + } } } - foreach (var field in type - .GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic) - .Where(x => !nameBlacklist.Contains(x.Name) && !typeBlacklist.Contains(x.FieldType))) + foreach (var field in type.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)) { - try + if (field.FieldType != typeof(bool) && !_searchMemberBlacklist.Contains(field.Name)) { - if (field.GetValue(c).ToString() - .Contains(searchString, StringComparison.InvariantCultureIgnoreCase)) - return true; - } - catch - { - // Skip invalid values + try + { + if (field.GetValue(c).ToString().Contains(searchString, StringComparison.InvariantCultureIgnoreCase)) + return true; + } + catch + { + // Skip invalid values + } } } diff --git a/RuntimeUnityEditor.Core/Windows/Taskbar.cs b/RuntimeUnityEditor.Core/Windows/Taskbar.cs index 32e5e70..a467d6e 100644 --- a/RuntimeUnityEditor.Core/Windows/Taskbar.cs +++ b/RuntimeUnityEditor.Core/Windows/Taskbar.cs @@ -15,19 +15,20 @@ public class Taskbar : IFeature { private int _windowId; private Rect _windowRect; + + private readonly GUILayoutOption[] _taskbarLayoutOptions = { GUILayoutShim.MaxWidth(Screen.width), GUILayoutShim.ExpandHeight(false), GUILayoutShim.ExpandWidth(false) }; + private readonly GUILayoutOption[] _timescaleTextfieldOptions = { GUILayout.Width(38) }; + private List _orderedFeatures; private string _title; + private string _titleFull; + private bool _enabled; /// /// Current instance. /// public static Taskbar Instance { get; private set; } - /// - /// Text shown in the title bar of the taskbar. - /// - protected string GetTitle() => RuntimeUnityEditorCore.Instance.ShowHotkey == KeyCode.None ? _title : _title + $" / Press {RuntimeUnityEditorCore.Instance.ShowHotkey} to show/hide"; - /// /// Height of the taskbar. /// @@ -62,10 +63,8 @@ void IFeature.OnOnGUI() _windowId, _windowRect, (GUI.WindowFunction)DrawTaskbar, - GetTitle(), - GUILayoutShim.ExpandHeight(false), - GUILayoutShim.ExpandWidth(false), - GUILayoutShim.MaxWidth(Screen.width) + _titleFull, + _taskbarLayoutOptions ); IMGUIUtils.EatInputInRect(_windowRect); _windowRect.x = (int)((Screen.width - _windowRect.width) / 2); @@ -74,15 +73,16 @@ void IFeature.OnOnGUI() private void DrawTaskbar(int id) { - GUILayout.BeginHorizontal(); + GUILayout.BeginHorizontal(IMGUIUtils.EmptyLayoutOptions); var firstFeature = true; - foreach (var feature in _orderedFeatures) + for (var i = 0; i < _orderedFeatures.Count; i++) { + var feature = _orderedFeatures[i]; if (feature.DisplayType == FeatureDisplayType.Window) { GUI.color = feature.Enabled ? Color.cyan : Color.white; - if (GUILayout.Button(feature.DisplayName)) + if (GUILayout.Button(feature.DisplayName, IMGUIUtils.EmptyLayoutOptions)) feature.Enabled = !feature.Enabled; } else if (feature.DisplayType == FeatureDisplayType.Feature) @@ -90,7 +90,7 @@ private void DrawTaskbar(int id) if (firstFeature) { GUI.color = new Color(1f, 1f, 1f, 0.75f); - if (GUILayout.Button("Reset")) + if (GUILayout.Button("Reset", IMGUIUtils.EmptyLayoutOptions)) { // Needed to avoid WindowManager.ResetWindowRect using old rects as reference to where new windows should be placed. foreach (var window in _orderedFeatures.OfType()) @@ -103,15 +103,17 @@ private void DrawTaskbar(int id) WindowManager.ResetWindowRect(window); } } + firstFeature = false; GUI.color = Color.white; - GUILayout.Label("|"); + GUILayout.Label("|", IMGUIUtils.EmptyLayoutOptions); } - feature.Enabled = GUILayout.Toggle(feature.Enabled, feature.DisplayName); + + feature.Enabled = GUILayout.Toggle(feature.Enabled, feature.DisplayName, IMGUIUtils.EmptyLayoutOptions); } } - GUILayout.Label("|"); + GUILayout.Label("|", IMGUIUtils.EmptyLayoutOptions); GUILayout.Label("Time", IMGUIUtils.LayoutOptionsExpandWidthFalse); @@ -120,14 +122,14 @@ private void DrawTaskbar(int id) if (GUILayout.Button("||", IMGUIUtils.LayoutOptionsExpandWidthFalse)) Time.timeScale = 0; - if (float.TryParse(GUILayout.TextField(Time.timeScale.ToString("F2", CultureInfo.InvariantCulture), GUILayout.Width(38)), NumberStyles.Any, CultureInfo.InvariantCulture, out var newVal)) + if (float.TryParse(GUILayout.TextField(Time.timeScale.ToString("F2", CultureInfo.InvariantCulture), _timescaleTextfieldOptions), NumberStyles.Any, CultureInfo.InvariantCulture, out var newVal)) Time.timeScale = newVal; GUI.changed = false; - var n = GUILayout.Toggle(Application.runInBackground, "in BG"); + var n = GUILayout.Toggle(Application.runInBackground, "in BG", IMGUIUtils.EmptyLayoutOptions); if (GUI.changed) Application.runInBackground = n; - GUILayout.Label("|"); + GUILayout.Label("|", IMGUIUtils.EmptyLayoutOptions); if (GUILayout.Button("Log", IMGUIUtils.LayoutOptionsExpandWidthFalse)) UnityFeatureHelper.OpenLog(); @@ -140,7 +142,20 @@ private void DrawTaskbar(int id) /// /// Show the taskbar, and by extension entire RUE interface. Use instead. /// - public bool Enabled { get; set; } + public bool Enabled + { + get => _enabled; + set + { + if (value) + { + _taskbarLayoutOptions[0] = GUILayoutShim.MaxWidth(Screen.width); + _titleFull = RuntimeUnityEditorCore.Instance.ShowHotkey == KeyCode.None ? _title : $"{_title} / Press {RuntimeUnityEditorCore.Instance.ShowHotkey} to show/hide"; + } + _enabled = value; + } + } + void IFeature.OnUpdate() { } void IFeature.OnLateUpdate() { } void IFeature.OnEditorShownChanged(bool visible) { } From 45f49452ff29173fa7ada97af87f475d01cd5240 Mon Sep 17 00:00:00 2001 From: ManlyMarco <39247311+ManlyMarco@users.noreply.github.com> Date: Sun, 2 Nov 2025 02:55:34 +0100 Subject: [PATCH 2/6] Update RuntimeUnityEditor.Bepin5/PatchInspector/PatchInspector.cs Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- RuntimeUnityEditor.Bepin5/PatchInspector/PatchInspector.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/RuntimeUnityEditor.Bepin5/PatchInspector/PatchInspector.cs b/RuntimeUnityEditor.Bepin5/PatchInspector/PatchInspector.cs index aa8a358..cfe154e 100644 --- a/RuntimeUnityEditor.Bepin5/PatchInspector/PatchInspector.cs +++ b/RuntimeUnityEditor.Bepin5/PatchInspector/PatchInspector.cs @@ -86,7 +86,7 @@ protected override void OnGUI() /// protected override void DrawContents() { - GUILayout.BeginHorizontal(GUI.skin.box,IMGUIUtils.EmptyLayoutOptions); + GUILayout.BeginHorizontal(GUI.skin.box, IMGUIUtils.EmptyLayoutOptions); { GUILayout.Label("Search: ", IMGUIUtils.LayoutOptionsExpandWidthFalse); From dc80cc4be2a58098caf22272658358bed689e2c8 Mon Sep 17 00:00:00 2001 From: ManlyMarco <39247311+ManlyMarco@users.noreply.github.com> Date: Sun, 2 Nov 2025 02:55:49 +0100 Subject: [PATCH 3/6] Update RuntimeUnityEditor.Bepin5/LogViewer/LogViewerWindow.cs Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- RuntimeUnityEditor.Bepin5/LogViewer/LogViewerWindow.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/RuntimeUnityEditor.Bepin5/LogViewer/LogViewerWindow.cs b/RuntimeUnityEditor.Bepin5/LogViewer/LogViewerWindow.cs index 41255f4..6d4fbea 100644 --- a/RuntimeUnityEditor.Bepin5/LogViewer/LogViewerWindow.cs +++ b/RuntimeUnityEditor.Bepin5/LogViewer/LogViewerWindow.cs @@ -141,7 +141,7 @@ protected override void DrawContents() GUILayout.BeginHorizontal(GUI.skin.box, IMGUIUtils.LayoutOptionsExpandWidthFalse); { if (!Capture) GUI.color = Color.red; - Capture = GUILayout.Toggle(Capture, new GUIContent("Enable log capture", "Note: This can hurt performance, especially if there is log spam."),IMGUIUtils.EmptyLayoutOptions); + Capture = GUILayout.Toggle(Capture, new GUIContent("Enable log capture", "Note: This can hurt performance, especially if there is log spam."), IMGUIUtils.EmptyLayoutOptions); GUI.color = Color.white; CaptureOnStartup = GUILayout.Toggle(CaptureOnStartup, new GUIContent("Enable on game startup", "Warning: This can hurt performance, especially after running for a while!"), IMGUIUtils.EmptyLayoutOptions); From fcd879369e613d756244ede53114f67c9ecef13d Mon Sep 17 00:00:00 2001 From: ManlyMarco <39247311+ManlyMarco@users.noreply.github.com> Date: Sun, 2 Nov 2025 02:57:35 +0100 Subject: [PATCH 4/6] Update RuntimeUnityEditor.Core/Windows/Inspector/Inspector.cs Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- RuntimeUnityEditor.Core/Windows/Inspector/Inspector.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/RuntimeUnityEditor.Core/Windows/Inspector/Inspector.cs b/RuntimeUnityEditor.Core/Windows/Inspector/Inspector.cs index bd2dcf0..f52f512 100644 --- a/RuntimeUnityEditor.Core/Windows/Inspector/Inspector.cs +++ b/RuntimeUnityEditor.Core/Windows/Inspector/Inspector.cs @@ -569,7 +569,7 @@ private void DrawSingleContentEntry(ICacheEntry entry) } catch (Exception ex) { - RuntimeUnityEditorCore.Logger.Log(LogLevel.Error, $"[{Title}] Failed to draw setting {entry.Name()} - {ex.Message}"); + RuntimeUnityEditorCore.Logger.Log(LogLevel.Error, $"[{Title}] Failed to draw setting {entry?.Name()} - {ex.Message}"); } } GUILayout.EndHorizontal(); From ad37cc29dd8ded30031844fba503aab0367a22bb Mon Sep 17 00:00:00 2001 From: ManlyMarco <39247311+ManlyMarco@users.noreply.github.com> Date: Sun, 2 Nov 2025 02:57:44 +0100 Subject: [PATCH 5/6] Update RuntimeUnityEditor.Bepin5/LogViewer/LogViewerWindow.cs Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- RuntimeUnityEditor.Bepin5/LogViewer/LogViewerWindow.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/RuntimeUnityEditor.Bepin5/LogViewer/LogViewerWindow.cs b/RuntimeUnityEditor.Bepin5/LogViewer/LogViewerWindow.cs index 6d4fbea..741327e 100644 --- a/RuntimeUnityEditor.Bepin5/LogViewer/LogViewerWindow.cs +++ b/RuntimeUnityEditor.Bepin5/LogViewer/LogViewerWindow.cs @@ -184,7 +184,7 @@ protected override void DrawContents() var heightMeasured = _itemHeight != 0; - _scrollPosition = GUILayout.BeginScrollView(_scrollPosition, false, true,IMGUIUtils.EmptyLayoutOptions); + _scrollPosition = GUILayout.BeginScrollView(_scrollPosition, false, true, IMGUIUtils.EmptyLayoutOptions); { var logEntries = _filteredLogEntries; From 2e9b2957ec0cb0697a9a07a05adfd711032f801d Mon Sep 17 00:00:00 2001 From: ManlyMarco <39247311+ManlyMarco@users.noreply.github.com> Date: Sun, 2 Nov 2025 02:57:51 +0100 Subject: [PATCH 6/6] Update RuntimeUnityEditor.Bepin5/LogViewer/LogViewerWindow.cs Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- RuntimeUnityEditor.Bepin5/LogViewer/LogViewerWindow.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/RuntimeUnityEditor.Bepin5/LogViewer/LogViewerWindow.cs b/RuntimeUnityEditor.Bepin5/LogViewer/LogViewerWindow.cs index 741327e..ec0898a 100644 --- a/RuntimeUnityEditor.Bepin5/LogViewer/LogViewerWindow.cs +++ b/RuntimeUnityEditor.Bepin5/LogViewer/LogViewerWindow.cs @@ -157,7 +157,7 @@ protected override void DrawContents() GUILayout.BeginHorizontal(IMGUIUtils.EmptyLayoutOptions); { - GUILayout.BeginHorizontal(GUI.skin.box,IMGUIUtils.EmptyLayoutOptions); + GUILayout.BeginHorizontal(GUI.skin.box, IMGUIUtils.EmptyLayoutOptions); { GUILayout.Label(new GUIContent("Captured log levels:", "Only new log messages with these levels will be captured, therefore enabling levels will not show past log messages!"), IMGUIUtils.EmptyLayoutOptions); var filter = LogLevelFilter;