OldBlueWater/BlueWater/Assets/Doozy/Editor/Signals/Layouts/SignalsConsoleWindowLayout.cs

455 lines
18 KiB
C#

// Copyright (c) 2015 - 2023 Doozy Entertainment. All Rights Reserved.
// This code can only be used under the standard Unity Asset Store End User License Agreement
// A Copy of the EULA APPENDIX 1 is available at http://unity3d.com/company/legal/as_terms
using System.Collections.Generic;
using System.Linq;
using Doozy.Editor.EditorUI;
using Doozy.Editor.EditorUI.Components;
using Doozy.Editor.EditorUI.Components.Internal;
using Doozy.Editor.EditorUI.ScriptableObjects.Colors;
using Doozy.Editor.EditorUI.Utils;
using Doozy.Editor.UIElements;
using Doozy.Runtime.Signals;
using Doozy.Runtime.UIElements.Extensions;
using UnityEditor;
using UnityEngine;
using UnityEngine.UIElements;
// ReSharper disable ClassNeverInstantiated.Global
// ReSharper disable MemberCanBePrivate.Global
namespace Doozy.Editor.Signals.Layouts
{
public sealed class SignalsConsoleWindowLayout : FluidWindowLayout
{
public override List<Texture2D> animatedIconTextures => EditorSpriteSheets.Signals.Icons.Signal;
public override Color accentColor => EditorColors.Signals.Signal;
public override EditorSelectableColorInfo selectableAccentColor => EditorSelectableColors.Signals.Signal;
private static Color signalColor => EditorColors.Signals.Signal;
private static EditorSelectableColorInfo signalSelectableColor => EditorSelectableColors.Signals.Signal;
private static Color streamColor => EditorColors.Signals.Stream;
private static EditorSelectableColorInfo streamSelectableColor => EditorSelectableColors.Signals.Stream;
private static IEnumerable<Texture2D> signalTextures => EditorSpriteSheets.Signals.Icons.Signal;
private static IEnumerable<Texture2D> streamTextures => EditorSpriteSheets.Signals.Icons.SignalStream;
private static IEnumerable<Texture2D> filterTextures => EditorSpriteSheets.EditorUI.Icons.Filter;
public int consoleHistorySteps { get; private set; } = 20;
private VisualElement toolbarContainer { get; set; }
private FluidButton clearLogButton { get; set; }
private ScrollView consoleScrollableContainer { get; set; }
private List<SignalsConsoleRow> consoleRows { get; set; }
private FluidPlaceholder placeholderOffline { get; set; }
private FluidPlaceholder placeholderNoSignals { get; set; }
#region Filter
private ScrollView filtersScrollView { get; set; }
private Filter sourceGameObjectFilter { get; set; }
private Filter signalProviderFilter { get; set; }
private Filter signalSenderObjectFilter { get; set; }
private Filter messageFilter { get; set; }
private Filter signalValueTypeFilter { get; set; }
private Filter signalValueFilter { get; set; }
private Filter streamSignalProviderFilter { get; set; }
private Filter streamCategoryFilter { get; set; }
private Filter streamNameFilter { get; set; }
private Filter streamInfoMessageFilter { get; set; }
private Filter streamGuidFilter { get; set; }
private bool showGuid { get; set; }
private List<Filter> filters { get; set; }
private bool anyFilterIsActive => filters.Any(f => f.isActive);
private void ApplyFilters()
{
for (int i = consoleRows.Count - 1; i >= 0; i--)
{
SignalsConsoleRow row = consoleRows[i];
if (!DiscardRow(row))
continue;
consoleRows.RemoveAt(i);
row.Recycle();
}
}
private void ClearFilters()
{
filters.ForEach(f => f.Clear());
}
private bool DiscardRow(SignalsConsoleRow row)
{
return
!sourceGameObjectFilter.IsMatch(row.sourceGameObjectLabel.text) ||
!signalProviderFilter.IsMatch(row.signalProviderLabel.text) ||
!signalSenderObjectFilter.IsMatch(row.signalSenderObjectLabel.text) ||
!messageFilter.IsMatch(row.messageLabel.text) ||
!signalValueTypeFilter.IsMatch(row.signalValueTypeLabel.text) ||
!signalValueFilter.IsMatch(row.signalValueLabel.text) ||
!streamSignalProviderFilter.IsMatch(row.streamSignalProviderLabel.text) ||
!streamNameFilter.IsMatch(row.streamNameLabel.text) ||
!streamCategoryFilter.IsMatch(row.streamCategoryLabel.text) ||
!streamInfoMessageFilter.IsMatch(row.streamInfoMessageLabel.text) ||
!streamGuidFilter.IsMatch(row.streamGuidLabel.text);
}
#endregion
private bool initialized { get; set; }
public SignalsConsoleWindowLayout()
{
AddHeader("Signals Console", "Realtime Signals Visualizer", animatedIconTextures);
Initialize();
}
private void Initialize()
{
if (!initialized)
{
filtersScrollView = new ScrollView().SetStyleAlignSelf(Align.Stretch);
sideMenu.toolbarContainer
.SetStyleDisplay(DisplayStyle.Flex)
.SetStyleFlexGrow(1)
.AddChild(filtersScrollView);
sideMenu.buttonsScrollViewContainer
.SetStyleDisplay(DisplayStyle.None);
sideMenu
.RemoveSearch()
.SetMenuLevel(FluidSideMenu.MenuLevel.Level_2)
.SetMenuInfo("Filters", filterTextures)
.HideToolbarWhenCollapsed(true)
.IsCollapsable(true)
.CollapseMenu(false)
.SetAccentColor(selectableAccentColor);
placeholderOffline =
FluidPlaceholder
.Get("Signals is offline", EditorSpriteSheets.Signals.Placeholders.OfflineSignal)
.SetStyleFlexGrow(1)
.Hide();
placeholderNoSignals =
FluidPlaceholder
.Get("No signals detected", EditorSpriteSheets.Signals.Placeholders.OnlineSignal)
.SetStyleFlexGrow(1)
.Hide();
toolbarContainer =
DesignUtils.GetToolbarContainer();
clearLogButton =
FluidButton.Get()
.SetLabelText("Clear")
.SetIcon(EditorSpriteSheets.EditorUI.Icons.Clear)
.SetButtonStyle(ButtonStyle.Contained)
.SetElementSize(ElementSize.Tiny)
.SetOnClick(ClearLog);
consoleScrollableContainer = new ScrollView() { viewDataKey = nameof(consoleScrollableContainer) };
consoleRows = new List<SignalsConsoleRow>();
SignalsService.OnSignal -= AddLogEntry;
SignalsService.OnSignal += AddLogEntry;
EditorApplication.playModeStateChanged += state => UpdatePlayModeDependentElements();
filters = new List<Filter>
{
(sourceGameObjectFilter = new Filter().SetOnPatternChanged(s => ApplyFilters())),
(signalProviderFilter = new Filter().SetOnPatternChanged(s => ApplyFilters())),
(signalSenderObjectFilter = new Filter().SetOnPatternChanged(s => ApplyFilters())),
(messageFilter = new Filter().SetOnPatternChanged(s => ApplyFilters())),
(signalValueTypeFilter = new Filter().SetOnPatternChanged(s => ApplyFilters())),
(signalValueFilter = new Filter().SetOnPatternChanged(s => ApplyFilters())),
(streamSignalProviderFilter = new Filter().SetOnPatternChanged(s => ApplyFilters())),
(streamCategoryFilter = new Filter().SetOnPatternChanged(s => ApplyFilters())),
(streamNameFilter = new Filter().SetOnPatternChanged(s => ApplyFilters())),
(streamInfoMessageFilter = new Filter().SetOnPatternChanged(s => ApplyFilters())),
(streamGuidFilter = new Filter().SetOnPatternChanged(s => ApplyFilters()))
};
FluidField GetFilterField(string labelText, Filter filter)
{
TextField textField =
new TextField()
.ResetLayout()
.SetStyleFlexGrow(1)
.SetStyleMarginRight(DesignUtils.k_Spacing);
FluidButton buttonClear =
FluidButton.Get(EditorSpriteSheets.EditorUI.Icons.Clear)
.SetElementSize(ElementSize.Tiny)
.SetStyleAlignSelf(Align.FlexEnd)
.SetOnClick(() => textField.value = string.Empty);
textField.RegisterValueChangedCallback(evt => filter.SetPattern(evt.newValue));
FluidField field =
FluidField.Get(labelText)
.SetStyleFlexGrow(1)
.SetStyleMinWidth(60)
.ClearBackground()
.SetElementSize(ElementSize.Small)
.AddFieldContent
(
DesignUtils.row
.AddChild(textField)
.AddChild(buttonClear)
);
field.infoContainer.SetStyleJustifyContent(Justify.FlexEnd);
return field;
}
FluidContainer signalFiltersContainer =
FluidContainer.Get()
.SetStyleMargins(DesignUtils.k_Spacing2X, 0, DesignUtils.k_Spacing2X, DesignUtils.k_Spacing)
.SetIcon(filterTextures)
.SetLabelText("Signal Filters")
.SetAccentColor(signalColor)
.AddToFluidContent(GetFilterField("Source GameObject", sourceGameObjectFilter))
.AddToFluidContent(GetFilterField("Signal Provider", signalProviderFilter))
.AddToFluidContent(GetFilterField("Signal Sender Object", signalSenderObjectFilter))
.AddToFluidContent(GetFilterField("Signal Message", messageFilter))
.AddToFluidContent(GetFilterField("Signal Value Type", signalValueTypeFilter))
.AddToFluidContent(GetFilterField("Signal Value", signalValueFilter));
FluidField guidFilter = GetFilterField("Stream Key (Guid)", streamGuidFilter);
FluidToggleSwitch showGuidSwitch =
FluidToggleSwitch.Get()
.SetToggleAccentColor(streamSelectableColor)
.SetTooltip("Show/Hide Stream Key (Guid)")
.SetOnValueChanged(evt =>
{
showGuid = evt.newValue;
streamGuidFilter.Clear();
ClearFilters();
});
FluidContainer streamFiltersContainer =
FluidContainer.Get()
.SetStyleMargins(DesignUtils.k_Spacing2X, DesignUtils.k_Spacing, DesignUtils.k_Spacing2X, 0)
.SetIcon(filterTextures)
.SetLabelText("Stream Filters")
.SetAccentColor(streamColor)
.AddToFluidContent(GetFilterField("Stream Provider", streamSignalProviderFilter))
.AddToFluidContent(GetFilterField("Stream Category", streamCategoryFilter))
.AddToFluidContent(GetFilterField("Stream Name", streamNameFilter))
.AddToFluidContent(GetFilterField("Stream Info Message", streamInfoMessageFilter))
.AddToFluidContent(guidFilter.AddInfoElement(showGuidSwitch));
filtersScrollView.contentContainer
.AddChild(signalFiltersContainer)
.AddChild(streamFiltersContainer);
header
.AddChild
(
toolbarContainer
.AddChild(clearLogButton)
);
content.Clear();
content
.AddChild(placeholderOffline)
.AddChild(placeholderNoSignals)
.AddChild(consoleScrollableContainer);
if (EditorApplication.isPlayingOrWillChangePlaymode)
foreach (SignalStream s in SignalsService.Streams.Values.Where(s => s?.currentSignal != null))
AddLogEntry(s.currentSignal);
initialized = true;
}
UpdatePlayModeDependentElements();
}
private void UpdatePlayModeDependentElements()
{
toolbarContainer.SetStyleDisplay(EditorApplication.isPlaying ? DisplayStyle.Flex : DisplayStyle.None);
consoleScrollableContainer.SetStyleDisplay(EditorApplication.isPlaying ? DisplayStyle.Flex : DisplayStyle.None);
placeholderOffline.Toggle(!EditorApplication.isPlaying);
placeholderNoSignals.Toggle(EditorApplication.isPlaying & consoleRows.Count == 0);
}
public override void OnDestroy()
{
base.OnDestroy();
SignalsService.OnSignal -= AddLogEntry;
placeholderOffline?.Dispose();
placeholderNoSignals?.Dispose();
foreach (SignalsConsoleRow row in consoleRows)
row?.Dispose();
consoleRows.Clear();
}
private void AddLogEntry(Signal signal)
{
if (!anyFilterIsActive)
{
AddToConsole(signal);
return;
}
if (sourceGameObjectFilter.isActive &&
signal.sourceGameObject != null &&
sourceGameObjectFilter.IsMatch(signal.sourceGameObject.name))
{
AddToConsole(signal);
return;
}
if (signalProviderFilter.isActive &&
signal.signalProvider != null &&
signalProviderFilter.IsMatch(signal.signalProvider.name))
{
AddToConsole(signal);
return;
}
if (signalSenderObjectFilter.isActive &&
signal.signalSenderObject != null &&
signalSenderObjectFilter.IsMatch(signal.signalSenderObject.name))
{
AddToConsole(signal);
return;
}
if (signalSenderObjectFilter.isActive &&
signal.signalSenderObject != null &&
signalSenderObjectFilter.IsMatch(signal.signalSenderObject.name))
{
AddToConsole(signal);
return;
}
if (messageFilter.isActive &&
messageFilter.IsMatch(signal.message))
{
AddToConsole(signal);
return;
}
if (signalValueTypeFilter.isActive &&
signalValueTypeFilter.IsMatch(signal.valueType.ToString()))
{
AddToConsole(signal);
return;
}
if (signalValueFilter.isActive &&
signal.hasValue &&
signal.valueAsObject != null &&
signalValueFilter.IsMatch(signal.valueAsObject.ToString()))
{
AddToConsole(signal);
return;
}
if (streamSignalProviderFilter.isActive &&
signal.stream.signalProvider != null &&
streamSignalProviderFilter.IsMatch(signal.stream.signalProvider.name))
{
AddToConsole(signal);
return;
}
if (streamNameFilter.isActive &&
streamNameFilter.IsMatch(signal.stream.name))
{
AddToConsole(signal);
return;
}
if (streamCategoryFilter.isActive &&
streamCategoryFilter.IsMatch(signal.stream.category))
{
AddToConsole(signal);
return;
}
if (streamInfoMessageFilter.isActive &&
streamInfoMessageFilter.IsMatch(signal.stream.infoMessage))
{
AddToConsole(signal);
return;
}
if (streamGuidFilter.isActive &&
streamGuidFilter.IsMatch(signal.stream.key.ToString()))
{
AddToConsole(signal);
return;
}
}
private void AddToConsole(Signal signal)
{
var row = SignalsConsoleRow.Get(signal);
row.streamGuidContainer.SetStyleDisplay(showGuid ? DisplayStyle.Flex : DisplayStyle.None);
consoleRows.Insert(0, row);
consoleScrollableContainer.Insert(0, row);
UpdatePlayModeDependentElements();
if (consoleRows.Count > consoleHistorySteps)
RemoveLastEntry();
}
private void RemoveLastEntry()
{
SignalsConsoleRow row = consoleRows[consoleRows.Count - 1];
if (row == null) return;
row.Recycle();
consoleRows.Remove(row);
UpdatePlayModeDependentElements();
}
//unused
private void CleanLog()
{
for (int i = consoleRows.Count - 1; i >= 0; i--)
{
SignalsConsoleRow row = consoleRows[i];
SignalStream stream = row?.signal.stream;
bool isValid = row != null & stream != null & SignalsService.Streams.Values.Contains(stream);
if (isValid) continue;
consoleRows.RemoveAt(i);
if (row != null) consoleScrollableContainer.Remove(row);
row?.Recycle();
}
UpdatePlayModeDependentElements();
}
public void ClearLog()
{
foreach (SignalsConsoleRow row in consoleRows)
row?.Recycle();
consoleRows.Clear();
consoleScrollableContainer.RecycleAndClear();
UpdatePlayModeDependentElements();
}
}
}