2023-10-07 01:59:28 -04:00
|
|
|
|
using System;
|
2024-12-19 00:49:41 -05:00
|
|
|
|
using System.Collections;
|
2023-10-09 11:44:06 -04:00
|
|
|
|
using System.IO;
|
2023-10-07 01:59:28 -04:00
|
|
|
|
using System.Windows;
|
|
|
|
|
|
using System.Windows.Controls;
|
2023-10-09 11:44:06 -04:00
|
|
|
|
using System.Windows.Documents;
|
|
|
|
|
|
using System.Windows.Media;
|
|
|
|
|
|
using System.Windows.Threading;
|
2024-05-27 23:48:48 -04:00
|
|
|
|
using MPF.Frontend;
|
2018-07-14 00:48:35 +02:00
|
|
|
|
|
2024-05-23 21:35:02 -04:00
|
|
|
|
namespace MPF.UI.UserControls
|
2018-07-14 00:48:35 +02:00
|
|
|
|
{
|
2021-02-28 02:28:53 -08:00
|
|
|
|
public partial class LogOutput : UserControl
|
2018-07-14 00:48:35 +02:00
|
|
|
|
{
|
2021-03-11 13:02:48 -08:00
|
|
|
|
/// <summary>
|
2023-10-09 11:44:06 -04:00
|
|
|
|
/// Document representing the text
|
2021-03-11 13:02:48 -08:00
|
|
|
|
/// </summary>
|
2024-12-18 23:30:14 -05:00
|
|
|
|
private readonly FlowDocument _document;
|
2023-10-09 11:44:06 -04:00
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// Paragraph backing the log
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
private readonly Paragraph _paragraph;
|
|
|
|
|
|
|
2024-12-19 00:49:41 -05:00
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// Maximum number of inlines before trimming
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
private const int MaxInlineCount = 5000;
|
|
|
|
|
|
|
2023-11-30 23:34:44 -05:00
|
|
|
|
#if NET35
|
|
|
|
|
|
|
2024-11-21 13:27:57 -05:00
|
|
|
|
private Button? ClearButton => ItemHelper.FindChild<Button>(this, "ClearButton");
|
|
|
|
|
|
private RichTextBox? Output => ItemHelper.FindChild<RichTextBox>(this, "Output");
|
|
|
|
|
|
private ScrollViewer? OutputViewer => ItemHelper.FindChild<ScrollViewer>(this, "OutputViewer");
|
|
|
|
|
|
private Button? SaveButton => ItemHelper.FindChild<Button>(this, "SaveButton");
|
2023-11-30 23:34:44 -05:00
|
|
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
|
|
2021-02-28 02:28:53 -08:00
|
|
|
|
public LogOutput()
|
2018-07-14 00:48:35 +02:00
|
|
|
|
{
|
2023-11-30 23:34:44 -05:00
|
|
|
|
#if NET40_OR_GREATER || NETCOREAPP
|
2018-07-14 00:48:35 +02:00
|
|
|
|
InitializeComponent();
|
2023-11-30 23:34:44 -05:00
|
|
|
|
#endif
|
2023-10-09 11:44:06 -04:00
|
|
|
|
|
|
|
|
|
|
// Update the internal state
|
2024-12-18 23:20:28 -05:00
|
|
|
|
_document = new FlowDocument()
|
2023-10-09 11:44:06 -04:00
|
|
|
|
{
|
|
|
|
|
|
Background = new SolidColorBrush(Color.FromArgb(0xFF, 0x20, 0x20, 0x20))
|
|
|
|
|
|
};
|
|
|
|
|
|
_paragraph = new Paragraph();
|
2024-12-18 23:20:28 -05:00
|
|
|
|
_document.Blocks.Add(_paragraph);
|
2023-10-09 11:44:06 -04:00
|
|
|
|
|
2023-10-07 01:59:28 -04:00
|
|
|
|
// Add handlers
|
2024-11-21 13:27:57 -05:00
|
|
|
|
OutputViewer!.SizeChanged += OutputViewerSizeChanged;
|
|
|
|
|
|
Output!.TextChanged += OnTextChanged;
|
|
|
|
|
|
ClearButton!.Click += OnClearButton;
|
|
|
|
|
|
SaveButton!.Click += OnSaveButton;
|
2023-10-07 01:59:28 -04:00
|
|
|
|
|
|
|
|
|
|
// Update the internal state
|
2024-12-18 23:20:28 -05:00
|
|
|
|
Output.Document = _document;
|
2023-10-07 01:59:28 -04:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#region Logging
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// Enqueue text to the log with formatting
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="logLevel">LogLevel for the log</param>
|
2023-10-08 23:40:56 -04:00
|
|
|
|
/// <param name="text">Text to write to the log</param>
|
|
|
|
|
|
public void EnqueueLog(LogLevel logLevel, string text)
|
2023-10-07 01:59:28 -04:00
|
|
|
|
{
|
|
|
|
|
|
// Null text gets ignored
|
|
|
|
|
|
if (text == null)
|
|
|
|
|
|
return;
|
|
|
|
|
|
|
2024-12-19 00:37:56 -05:00
|
|
|
|
// Create a new log line
|
|
|
|
|
|
var logLine = new LogLine(text, logLevel);
|
2024-12-19 00:13:09 -05:00
|
|
|
|
|
2024-12-19 00:37:56 -05:00
|
|
|
|
#if NET40
|
|
|
|
|
|
Dispatcher.Invoke(() =>
|
|
|
|
|
|
#else
|
|
|
|
|
|
Dispatcher.InvokeAsync(() =>
|
|
|
|
|
|
#endif
|
|
|
|
|
|
{
|
|
|
|
|
|
var run = logLine.GenerateRun();
|
|
|
|
|
|
_paragraph.Inlines.Add(run);
|
2024-12-19 00:49:41 -05:00
|
|
|
|
if (_paragraph.Inlines.Count > MaxInlineCount)
|
|
|
|
|
|
((IList)_paragraph.Inlines).RemoveAt(0);
|
2024-12-19 00:37:56 -05:00
|
|
|
|
});
|
2023-10-09 11:44:06 -04:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// Log line wrapper
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
internal readonly struct LogLine
|
|
|
|
|
|
{
|
|
|
|
|
|
public readonly string Text;
|
|
|
|
|
|
public readonly LogLevel LogLevel;
|
|
|
|
|
|
|
|
|
|
|
|
public LogLine(string text, LogLevel logLevel)
|
|
|
|
|
|
{
|
2024-11-21 11:49:14 -05:00
|
|
|
|
Text = text;
|
|
|
|
|
|
LogLevel = logLevel;
|
2023-10-09 11:44:06 -04:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// Get the foreground Brush for the current LogLevel
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <returns>Brush representing the color</returns>
|
|
|
|
|
|
public Brush GetForegroundColor()
|
|
|
|
|
|
{
|
2024-11-21 11:49:14 -05:00
|
|
|
|
return LogLevel switch
|
2023-10-09 11:44:06 -04:00
|
|
|
|
{
|
2024-12-20 23:56:23 -05:00
|
|
|
|
LogLevel.SECRET => Brushes.DarkGray,
|
2023-12-01 23:58:01 -05:00
|
|
|
|
LogLevel.ERROR => Brushes.Red,
|
|
|
|
|
|
LogLevel.VERBOSE => Brushes.Yellow,
|
|
|
|
|
|
_ => Brushes.White,
|
|
|
|
|
|
};
|
2023-10-09 11:44:06 -04:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// Generate a Run object from the current LogLine
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <returns>Run object based on internal values</returns>
|
|
|
|
|
|
public Run GenerateRun()
|
|
|
|
|
|
{
|
2024-11-21 11:49:14 -05:00
|
|
|
|
return new Run { Text = Text, Foreground = GetForegroundColor() };
|
2023-10-09 11:44:06 -04:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2023-11-30 23:34:44 -05:00
|
|
|
|
#endregion
|
2023-10-07 01:59:28 -04:00
|
|
|
|
|
|
|
|
|
|
#region Helpers
|
|
|
|
|
|
|
2023-10-09 11:44:06 -04:00
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// Clear all inlines of the paragraph
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
private void ClearInlines() => _paragraph.Inlines.Clear();
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// Save all inlines to console.log
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
private void SaveInlines()
|
|
|
|
|
|
{
|
2023-12-01 23:58:01 -05:00
|
|
|
|
using var sw = new StreamWriter(File.OpenWrite("console.log"));
|
|
|
|
|
|
foreach (var inline in _paragraph.Inlines)
|
2023-10-09 11:44:06 -04:00
|
|
|
|
{
|
2023-12-01 23:58:01 -05:00
|
|
|
|
if (inline is Run run)
|
|
|
|
|
|
sw.Write(run.Text);
|
2023-10-09 11:44:06 -04:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2023-10-07 01:59:28 -04:00
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// Scroll the current view to the bottom
|
|
|
|
|
|
/// </summary>
|
2024-11-21 13:27:57 -05:00
|
|
|
|
public void ScrollToBottom() => OutputViewer!.ScrollToBottom();
|
2023-10-07 01:59:28 -04:00
|
|
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
|
|
#region EventHandlers
|
|
|
|
|
|
|
|
|
|
|
|
private void OnClearButton(object sender, EventArgs e)
|
2023-10-09 11:44:06 -04:00
|
|
|
|
=> ClearInlines();
|
2023-10-07 01:59:28 -04:00
|
|
|
|
|
|
|
|
|
|
private void OnSaveButton(object sender, EventArgs e)
|
2023-10-09 11:44:06 -04:00
|
|
|
|
=> SaveInlines();
|
2023-10-07 01:59:28 -04:00
|
|
|
|
|
|
|
|
|
|
private void OnTextChanged(object sender, TextChangedEventArgs e)
|
|
|
|
|
|
=> ScrollToBottom();
|
|
|
|
|
|
|
|
|
|
|
|
private void OutputViewerSizeChanged(object sender, SizeChangedEventArgs e)
|
|
|
|
|
|
=> ScrollToBottom();
|
|
|
|
|
|
|
|
|
|
|
|
#endregion
|
2018-07-14 00:48:35 +02:00
|
|
|
|
}
|
|
|
|
|
|
}
|