using System.Collections.Specialized; using System.ComponentModel; using System.Reflection; using Avalonia; using Avalonia.Controls; using Avalonia.Controls.Primitives; using Avalonia.Interactivity; using Avalonia.Media; using Avalonia.Threading; using VisionBuilder.UI.Common.ViewModel; using VisionBuilder.UI.Common.ViewModel.Classes; namespace VisionBuilder.UI.Avalonia.Uno.Views; public partial class MainWindow : Window { private readonly MainWindowVM _mainWindowVm; private readonly AvaloniaUISettings _avaloniaUiSettings; private readonly Dictionary _dynamicButtonControls = new(); public MainWindow(MainWindowVM mainWindowVm, AvaloniaUISettings avaloniaUiSettings) { _mainWindowVm = mainWindowVm; _avaloniaUiSettings = avaloniaUiSettings; InitializeComponent(); DataContext = _mainWindowVm; SingleCameraView.SetViewModel(_mainWindowVm.SingleCameraVms[0]); BtnMinimize.Click += BtnMinimize_Click; BtnExit.Click += BtnExit_Click; var version = Assembly.GetExecutingAssembly().GetName().Version; LblVersion.Text = version != null ? $"v{version.Major}.{version.Minor}.{version.Build}" : "v0.0.0"; _mainWindowVm.PropertyChanged += MainWindowVm_PropertyChanged; _mainWindowVm.DynamicButtons.CollectionChanged += DynamicButtons_CollectionChanged; foreach (var btn in _mainWindowVm.DynamicButtons) AddDynamicButton(btn); } protected override void OnOpened(EventArgs e) { base.OnOpened(e); _mainWindowVm.OnProgramStarted(); if (_avaloniaUiSettings.FullScreen) { WindowState = WindowState.Maximized; } } protected override void OnClosed(EventArgs e) { base.OnClosed(e); _mainWindowVm.OnProgramClosed(); Environment.Exit(0); } private void MainWindowVm_PropertyChanged(object? sender, PropertyChangedEventArgs e) { if (e.PropertyName == nameof(_mainWindowVm.TestMode)) { // Toggle accent color for test mode visual indication // Green background when test mode is active if (_mainWindowVm.TestMode) { Background = new global::Avalonia.Media.SolidColorBrush( global::Avalonia.Media.Color.FromRgb(0x2E, 0x7D, 0x32)); // Green800 } else { Background = new global::Avalonia.Media.SolidColorBrush( global::Avalonia.Media.Colors.White); } } } private void BtnMinimize_Click(object? sender, RoutedEventArgs e) { WindowState = WindowState.Minimized; } private void BtnExit_Click(object? sender, RoutedEventArgs e) { _mainWindowVm.OnProgramClosed(); Environment.Exit(0); } private void DynamicButtons_CollectionChanged(object? sender, NotifyCollectionChangedEventArgs e) { Dispatcher.UIThread.Post(() => { switch (e.Action) { case NotifyCollectionChangedAction.Add: foreach (ButtonDefinition btn in e.NewItems!) AddDynamicButton(btn); break; case NotifyCollectionChangedAction.Remove: foreach (ButtonDefinition btn in e.OldItems!) RemoveDynamicButton(btn); break; case NotifyCollectionChangedAction.Reset: foreach (var ctrl in _dynamicButtonControls.Values) BottomBarPanel.Children.Remove(ctrl); _dynamicButtonControls.Clear(); break; } }); } private void AddDynamicButton(ButtonDefinition buttonDef) { Control control; if (buttonDef.Type == EButtonType.Toggle) { var toggleBtn = new ToggleButton { Content = buttonDef.Title.ToUpperInvariant(), Width = 176, Height = 48, FontSize = 14, FontWeight = FontWeight.Bold, HorizontalContentAlignment = global::Avalonia.Layout.HorizontalAlignment.Center, VerticalContentAlignment = global::Avalonia.Layout.VerticalAlignment.Center, IsChecked = buttonDef.IsToggled, IsVisible = buttonDef.IsVisible, BorderBrush = new SolidColorBrush(Color.FromRgb(0xD3, 0x2F, 0x2F)), BorderThickness = new Thickness(2), Background = Brushes.White, Foreground = new SolidColorBrush(Color.FromRgb(0xD3, 0x2F, 0x2F)) }; toggleBtn.Click += (_, _) => buttonDef.Execute(); buttonDef.PropertyChanged += (_, args) => { Dispatcher.UIThread.Post(() => { if (args.PropertyName == nameof(ButtonDefinition.IsVisible)) toggleBtn.IsVisible = buttonDef.IsVisible; else if (args.PropertyName == nameof(ButtonDefinition.IsToggled)) toggleBtn.IsChecked = buttonDef.IsToggled; }); }; control = toggleBtn; } else { var btn = new Button { Content = buttonDef.Title.ToUpperInvariant(), Width = 176, Height = 48, FontSize = 14, FontWeight = FontWeight.Bold, HorizontalContentAlignment = global::Avalonia.Layout.HorizontalAlignment.Center, VerticalContentAlignment = global::Avalonia.Layout.VerticalAlignment.Center, IsVisible = buttonDef.IsVisible, BorderBrush = new SolidColorBrush(Color.FromRgb(0xD3, 0x2F, 0x2F)), BorderThickness = new Thickness(2), Background = Brushes.White, Foreground = new SolidColorBrush(Color.FromRgb(0xD3, 0x2F, 0x2F)) }; btn.Click += (_, _) => buttonDef.Execute(); buttonDef.PropertyChanged += (_, args) => { Dispatcher.UIThread.Post(() => { if (args.PropertyName == nameof(ButtonDefinition.IsVisible)) btn.IsVisible = buttonDef.IsVisible; }); }; control = btn; } // Insert before BtnMinimize var minimizeIndex = BottomBarPanel.Children.IndexOf(BtnMinimize); if (minimizeIndex >= 0) BottomBarPanel.Children.Insert(minimizeIndex, control); else BottomBarPanel.Children.Add(control); _dynamicButtonControls[buttonDef.Key] = control; } private void RemoveDynamicButton(ButtonDefinition buttonDef) { if (_dynamicButtonControls.TryGetValue(buttonDef.Key, out var ctrl)) { BottomBarPanel.Children.Remove(ctrl); _dynamicButtonControls.Remove(buttonDef.Key); } } }