using System.Collections.Specialized; using Avalonia; using Avalonia.Controls; using Avalonia.Controls.Documents; using Avalonia.Controls.Shapes; using Avalonia.Input; using Avalonia.Media; using Automata.Core; using Automata.Ui.ViewModels; namespace Automata.Ui.Views; public partial class MainWindow : Window { private ConfigStore? _store; private static readonly IBrush TimeBrush = new SolidColorBrush(Color.Parse("#484f58")); private static readonly IBrush InfoBrush = new SolidColorBrush(Color.Parse("#58a6ff")); private static readonly IBrush WarnBrush = new SolidColorBrush(Color.Parse("#d29922")); private static readonly IBrush ErrorBrush = new SolidColorBrush(Color.Parse("#f85149")); private static readonly IBrush DebugBrush = new SolidColorBrush(Color.Parse("#8b949e")); private static readonly IBrush DefaultBrush = new SolidColorBrush(Color.Parse("#e6edf3")); public MainWindow() { InitializeComponent(); } public void SetConfigStore(ConfigStore store) { _store = store; var s = store.Settings; if (s.WindowWidth.HasValue && s.WindowHeight.HasValue) { Width = s.WindowWidth.Value; Height = s.WindowHeight.Value; } if (s.WindowX.HasValue && s.WindowY.HasValue) { Position = new PixelPoint((int)s.WindowX.Value, (int)s.WindowY.Value); WindowStartupLocation = WindowStartupLocation.Manual; } else { WindowStartupLocation = WindowStartupLocation.CenterScreen; } } protected override void OnDataContextChanged(EventArgs e) { base.OnDataContextChanged(e); if (DataContext is MainWindowViewModel vm) { vm.Logs.CollectionChanged += (_, args) => { var block = this.FindControl("LogBlock"); var scroll = this.FindControl("LogScroll"); if (block == null) return; if (args.Action == NotifyCollectionChangedAction.Add && args.NewItems != null) { foreach (LogEntry entry in args.NewItems) AppendLogEntry(block, entry); } else if (args.Action == NotifyCollectionChangedAction.Remove) { // Rebuild when old entries trimmed RebuildLog(block, vm); } scroll?.ScrollToEnd(); }; } } private static void AppendLogEntry(SelectableTextBlock block, LogEntry entry) { if (block.Inlines?.Count > 0) block.Inlines.Add(new Run("\n")); block.Inlines ??= []; block.Inlines.Add(new Run(entry.Time + " ") { Foreground = TimeBrush }); block.Inlines.Add(new Run(entry.Message) { Foreground = LevelBrush(entry.Level) }); } private static void RebuildLog(SelectableTextBlock block, MainWindowViewModel vm) { block.Inlines?.Clear(); block.Inlines ??= []; for (var i = 0; i < vm.Logs.Count; i++) { if (i > 0) block.Inlines.Add(new Run("\n")); var entry = vm.Logs[i]; block.Inlines.Add(new Run(entry.Time + " ") { Foreground = TimeBrush }); block.Inlines.Add(new Run(entry.Message) { Foreground = LevelBrush(entry.Level) }); } } private static IBrush LevelBrush(string level) => level switch { "INFO" => InfoBrush, "WARN" or "WARNING" => WarnBrush, "ERROR" => ErrorBrush, "DEBUG" => DebugBrush, _ => DefaultBrush, }; public void CurrencyImage_PointerPressed(object? sender, PointerPressedEventArgs e) { if (sender is not Control grid) return; if (DataContext is not MainWindowViewModel mainVm) return; var settingsVm = mainVm.SettingsVm; if (settingsVm?.CurrencyTabImage == null) return; // Viewbox puts us in image-pixel space — coords are already image pixels var pos = e.GetPosition(grid); settingsVm.OnCurrencyImageClick((int)pos.X, (int)pos.Y); UpdateHoverMarker(settingsVm.SelectedCurrency); } public void CurrencyItem_PointerEntered(object? sender, PointerEventArgs e) { if (sender is Control { DataContext: CurrencyPositionViewModel vm }) UpdateHoverMarker(vm); } public void CurrencyItem_PointerExited(object? sender, PointerEventArgs e) { var marker = this.FindControl("HoverMarker"); if (marker != null) marker.IsVisible = false; } private void UpdateHoverMarker(CurrencyPositionViewModel? vm) { var marker = this.FindControl("HoverMarker"); if (marker == null) return; if (vm == null || !vm.IsPositioned) { marker.IsVisible = false; return; } // Canvas is in image-pixel space thanks to Viewbox Canvas.SetLeft(marker, vm.X - marker.Width / 2); Canvas.SetTop(marker, vm.Y - marker.Height / 2); marker.IsVisible = true; } public void BrowserRow_PointerPressed(object? sender, PointerPressedEventArgs e) { if (sender is not Control { DataContext: FieldRowViewModel row }) return; if (!row.IsPointer) return; if (DataContext is not MainWindowViewModel mainVm) return; mainVm.BrowserVm?.NavigateToPointer(row); } protected override void OnClosing(WindowClosingEventArgs e) { if (_store != null) { _store.UpdateSettings(s => { s.WindowX = Position.X; s.WindowY = Position.Y; s.WindowWidth = Width; s.WindowHeight = Height; }); } base.OnClosing(e); } }