using CMM.Language; using CMM.Library.Method; using CMM.Library.ViewModel; using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using System.Windows; using System.Windows.Controls; using System.Windows.Input; namespace DellMonitorControl; /// /// Interaction logic for ControlPanel.xaml /// public partial class ControlPanel : UserControl { public ControlPanel() { InitializeComponent(); } public async Task Refresh() { try { sp.Children.Clear(); await CMMCommand.ScanMonitor(); var monitors = (await CMMCommand.ReadMonitorsData()).ToList(); if (!monitors.Any()) { sp.Children.Add(new TextBlock { Text = "No DDC/CI monitors detected", Foreground = System.Windows.Media.Brushes.White, FontSize = 14 }); return; } foreach (var m in monitors) { var brightness = await CMMCommand.GetBrightness(m.SerialNumber) ?? 50; var contrast = await CMMCommand.GetContrast(m.SerialNumber) ?? 50; var inputSource = await CMMCommand.GetInputSource(m.SerialNumber); var inputOptions = await CMMCommand.GetInputSourceOptions(m.SerialNumber); var powerStatus = await CMMCommand.GetMonPowerStatus(m.SerialNumber) ?? "Unknown"; // Monitor name header sp.Children.Add(new TextBlock { Text = m.MonitorName, Foreground = System.Windows.Media.Brushes.White, FontSize = 14, FontWeight = FontWeights.Bold, Margin = new Thickness(0, 10, 0, 5) }); // Brightness row var brightnessRow = new StackPanel { Orientation = Orientation.Horizontal, Margin = new Thickness(0, 3, 0, 3) }; brightnessRow.Children.Add(new TextBlock { Text = "Brightness", Foreground = System.Windows.Media.Brushes.LightGray, Width = 70, FontSize = 12, VerticalAlignment = VerticalAlignment.Center }); var bSlider = new Slider { Minimum = 0, Maximum = 100, Value = brightness, Width = 140, VerticalAlignment = VerticalAlignment.Center, Tag = m.SerialNumber }; var bValue = new TextBlock { Text = brightness.ToString(), Foreground = System.Windows.Media.Brushes.White, Width = 30, FontSize = 12, Margin = new Thickness(5, 0, 0, 0), VerticalAlignment = VerticalAlignment.Center }; bSlider.ValueChanged += (s, e) => bValue.Text = ((int)e.NewValue).ToString(); bSlider.PreviewMouseUp += async (s, e) => { if (s is Slider sl && sl.Tag is string sn) await CMMCommand.SetBrightness(sn, (int)sl.Value); }; brightnessRow.Children.Add(bSlider); brightnessRow.Children.Add(bValue); sp.Children.Add(brightnessRow); // Contrast row var contrastRow = new StackPanel { Orientation = Orientation.Horizontal, Margin = new Thickness(0, 3, 0, 3) }; contrastRow.Children.Add(new TextBlock { Text = "Contrast", Foreground = System.Windows.Media.Brushes.LightGray, Width = 70, FontSize = 12, VerticalAlignment = VerticalAlignment.Center }); var cSlider = new Slider { Minimum = 0, Maximum = 100, Value = contrast, Width = 140, VerticalAlignment = VerticalAlignment.Center, Tag = m.SerialNumber }; var cValue = new TextBlock { Text = contrast.ToString(), Foreground = System.Windows.Media.Brushes.White, Width = 30, FontSize = 12, Margin = new Thickness(5, 0, 0, 0), VerticalAlignment = VerticalAlignment.Center }; cSlider.ValueChanged += (s, e) => cValue.Text = ((int)e.NewValue).ToString(); cSlider.PreviewMouseUp += async (s, e) => { if (s is Slider sl && sl.Tag is string sn) await CMMCommand.SetContrast(sn, (int)sl.Value); }; contrastRow.Children.Add(cSlider); contrastRow.Children.Add(cValue); sp.Children.Add(contrastRow); // Input source row (if options available) if (inputOptions.Count > 0) { var inputRow = new StackPanel { Orientation = Orientation.Horizontal, Margin = new Thickness(0, 3, 0, 3) }; inputRow.Children.Add(new TextBlock { Text = "Input", Foreground = System.Windows.Media.Brushes.LightGray, Width = 70, FontSize = 12, VerticalAlignment = VerticalAlignment.Center }); var combo = new ComboBox { Width = 170, ItemsSource = inputOptions, DisplayMemberPath = "Name", Tag = m.SerialNumber }; if (inputSource.HasValue) combo.SelectedItem = inputOptions.Find(o => o.Value == inputSource.Value); combo.SelectionChanged += async (s, e) => { if (s is ComboBox cb && cb.Tag is string sn && cb.SelectedItem is InputSourceOption opt) await CMMCommand.SetInputSource(sn, opt.Value); }; inputRow.Children.Add(combo); sp.Children.Add(inputRow); } // Power row var powerRow = new StackPanel { Orientation = Orientation.Horizontal, Margin = new Thickness(0, 3, 0, 3) }; powerRow.Children.Add(new TextBlock { Text = "Power", Foreground = System.Windows.Media.Brushes.LightGray, Width = 70, FontSize = 12, VerticalAlignment = VerticalAlignment.Center }); var powerBtn = new Button { Content = powerStatus, Width = 170, Tag = m.SerialNumber }; powerBtn.Click += async (s, e) => { if (s is Button btn && btn.Tag is string sn) { var status = await CMMCommand.GetMonPowerStatus(sn); if (status == "Sleep" || status == "PowerOff") await CMMCommand.PowerOn(sn); else await CMMCommand.Sleep(sn); await Task.Delay(1000); btn.Content = await CMMCommand.GetMonPowerStatus(sn); } }; powerRow.Children.Add(powerBtn); sp.Children.Add(powerRow); } } catch (Exception ex) { sp.Children.Clear(); sp.Children.Add(new TextBlock { Text = $"Error: {ex.Message}", Foreground = System.Windows.Media.Brushes.Red, FontSize = 12, TextWrapping = TextWrapping.Wrap }); } } private StackPanel CreateControlSimple( XMonitor monitorModel, int? brightness, int? contrast, int? currentInputSource, List inputOptions, string powerStatus) { var container = new StackPanel { Orientation = Orientation.Vertical, Margin = new Thickness(0, 5, 0, 10) }; // Monitor name container.Children.Add(new TextBlock { Text = $"{monitorModel.MonitorName} ({monitorModel.SerialNumber})", Foreground = System.Windows.Media.Brushes.White, FontSize = 14, FontWeight = FontWeights.Bold, Margin = new Thickness(0, 0, 0, 5) }); // Brightness var brightnessPanel = new StackPanel { Orientation = Orientation.Horizontal, Margin = new Thickness(0, 2, 0, 2) }; brightnessPanel.Children.Add(new TextBlock { Text = "Brightness:", Foreground = System.Windows.Media.Brushes.LightGray, Width = 80, FontSize = 12 }); var brightnessSlider = new Slider { Minimum = 0, Maximum = 100, Value = brightness ?? 50, Width = 150, Tag = monitorModel.SerialNumber }; var brightnessValue = new TextBlock { Text = (brightness ?? 50).ToString(), Foreground = System.Windows.Media.Brushes.White, Width = 30, FontSize = 12, Margin = new Thickness(5, 0, 0, 0) }; brightnessSlider.ValueChanged += (s, e) => brightnessValue.Text = ((int)e.NewValue).ToString(); brightnessSlider.PreviewMouseUp += async (s, e) => { var sld = s as Slider; if (sld?.Tag is string sn) await CMMCommand.SetBrightness(sn, (int)sld.Value); }; brightnessPanel.Children.Add(brightnessSlider); brightnessPanel.Children.Add(brightnessValue); container.Children.Add(brightnessPanel); // Contrast var contrastPanel = new StackPanel { Orientation = Orientation.Horizontal, Margin = new Thickness(0, 2, 0, 2) }; contrastPanel.Children.Add(new TextBlock { Text = "Contrast:", Foreground = System.Windows.Media.Brushes.LightGray, Width = 80, FontSize = 12 }); var contrastSlider = new Slider { Minimum = 0, Maximum = 100, Value = contrast ?? 50, Width = 150, Tag = monitorModel.SerialNumber }; var contrastValue = new TextBlock { Text = (contrast ?? 50).ToString(), Foreground = System.Windows.Media.Brushes.White, Width = 30, FontSize = 12, Margin = new Thickness(5, 0, 0, 0) }; contrastSlider.ValueChanged += (s, e) => contrastValue.Text = ((int)e.NewValue).ToString(); contrastSlider.PreviewMouseUp += async (s, e) => { var sld = s as Slider; if (sld?.Tag is string sn) await CMMCommand.SetContrast(sn, (int)sld.Value); }; contrastPanel.Children.Add(contrastSlider); contrastPanel.Children.Add(contrastValue); container.Children.Add(contrastPanel); // Input source (if available) if (inputOptions.Count > 0) { var inputPanel = new StackPanel { Orientation = Orientation.Horizontal, Margin = new Thickness(0, 2, 0, 2) }; inputPanel.Children.Add(new TextBlock { Text = "Input:", Foreground = System.Windows.Media.Brushes.LightGray, Width = 80, FontSize = 12 }); var combo = new ComboBox { Width = 150, ItemsSource = inputOptions, DisplayMemberPath = "Name", Tag = monitorModel.SerialNumber }; if (currentInputSource.HasValue) combo.SelectedItem = inputOptions.Find(o => o.Value == currentInputSource.Value); combo.SelectionChanged += async (s, e) => { var cb = s as ComboBox; if (cb?.Tag is string sn && cb.SelectedItem is InputSourceOption opt) await CMMCommand.SetInputSource(sn, opt.Value); }; inputPanel.Children.Add(combo); container.Children.Add(inputPanel); } // Power var powerPanel = new StackPanel { Orientation = Orientation.Horizontal, Margin = new Thickness(0, 2, 0, 2) }; powerPanel.Children.Add(new TextBlock { Text = "Power:", Foreground = System.Windows.Media.Brushes.LightGray, Width = 80, FontSize = 12 }); var powerBtn = new Button { Content = powerStatus, Width = 150, Tag = monitorModel.SerialNumber }; powerBtn.Click += async (s, e) => { var btn = s as Button; if (btn?.Tag is string sn) { var status = await CMMCommand.GetMonPowerStatus(sn); if (status == "Sleep" || status == "PowerOff") await CMMCommand.PowerOn(sn); else await CMMCommand.Sleep(sn); await Task.Delay(1000); btn.Content = await CMMCommand.GetMonPowerStatus(sn); } }; powerPanel.Children.Add(powerBtn); container.Children.Add(powerPanel); return container; } private StackPanel CreateControl( XMonitor monitorModel, int? brightness, int? contrast, int? currentInputSource, List inputOptions, string powerStatus) { var container = new StackPanel { Orientation = Orientation.Vertical, Margin = new Thickness(10, 5, 10, 10) }; // Monitor name header var header = new TextBlock { Text = $"{monitorModel.MonitorName} ({monitorModel.SerialNumber})", HorizontalAlignment = HorizontalAlignment.Left, Style = (Style)FindResource("LableStyle"), Margin = new Thickness(0, 0, 0, 5) }; container.Children.Add(header); // Brightness slider var brightnessPanel = CreateSliderControl( Lang.Find("Brightness"), brightness ?? 50, monitorModel.SerialNumber, async (sn, value) => await CMMCommand.SetBrightness(sn, value)); container.Children.Add(brightnessPanel); // Contrast slider var contrastPanel = CreateSliderControl( Lang.Find("Contrast"), contrast ?? 50, monitorModel.SerialNumber, async (sn, value) => await CMMCommand.SetContrast(sn, value)); container.Children.Add(contrastPanel); // Input source dropdown if (inputOptions.Count > 0) { var inputPanel = CreateInputSourceControl( monitorModel.SerialNumber, currentInputSource, inputOptions); container.Children.Add(inputPanel); } // Power button var powerPanel = CreatePowerControl(monitorModel.SerialNumber, powerStatus); container.Children.Add(powerPanel); return container; } private StackPanel CreateSliderControl( string label, int currentValue, string monitorSN, Func onValueChanged) { var panel = new StackPanel { Orientation = Orientation.Horizontal, Margin = new Thickness(0, 3, 0, 3) }; var labelBlock = new TextBlock { Text = label, Width = 80, VerticalAlignment = VerticalAlignment.Center, Style = (Style)FindResource("LableStyle") }; var slider = new Slider { Style = (Style)FindResource("Horizontal_Slider"), Minimum = 0, Maximum = 100, Value = currentValue, Tag = monitorSN, Width = 180 }; var valueBlock = new TextBlock { Text = currentValue.ToString(), Width = 35, VerticalAlignment = VerticalAlignment.Center, Style = (Style)FindResource("LableStyle"), TextAlignment = TextAlignment.Right }; // Update value display while dragging slider.ValueChanged += (s, e) => { valueBlock.Text = ((int)e.NewValue).ToString(); }; // Only send command on release (PreviewMouseUp) slider.PreviewMouseUp += async (s, e) => { var sld = s as Slider; var sn = sld?.Tag?.ToString(); if (!string.IsNullOrEmpty(sn) && sld != null) { await onValueChanged(sn, (int)sld.Value); } }; panel.Children.Add(labelBlock); panel.Children.Add(slider); panel.Children.Add(valueBlock); return panel; } private StackPanel CreateInputSourceControl( string monitorSN, int? currentInputSource, List options) { var panel = new StackPanel { Orientation = Orientation.Horizontal, Margin = new Thickness(0, 3, 0, 3) }; var labelBlock = new TextBlock { Text = Lang.Find("InputSource"), Width = 80, VerticalAlignment = VerticalAlignment.Center, Style = (Style)FindResource("LableStyle") }; var comboBox = new ComboBox { Width = 180, Tag = monitorSN, ItemsSource = options, DisplayMemberPath = "Name" }; // Set current selection if (currentInputSource.HasValue) { var currentOption = options.Find(o => o.Value == currentInputSource.Value); if (currentOption != null) { comboBox.SelectedItem = currentOption; } } comboBox.SelectionChanged += async (s, e) => { var cb = s as ComboBox; var sn = cb?.Tag?.ToString(); var selectedOption = cb?.SelectedItem as InputSourceOption; if (!string.IsNullOrEmpty(sn) && selectedOption != null) { await CMMCommand.SetInputSource(sn, selectedOption.Value); } }; panel.Children.Add(labelBlock); panel.Children.Add(comboBox); return panel; } private StackPanel CreatePowerControl(string monitorSN, string powerStatus) { var panel = new StackPanel { Orientation = Orientation.Horizontal, Margin = new Thickness(0, 5, 0, 0) }; var labelBlock = new TextBlock { Text = Lang.Find("Power"), Width = 80, VerticalAlignment = VerticalAlignment.Center, Style = (Style)FindResource("LableStyle") }; var btn = new Button { Tag = monitorSN, Content = GetLocalizedPowerStatus(powerStatus), Style = (Style)FindResource("TextButtonStyle"), Width = 180 }; btn.Click += async (s, e) => await TogglePower(s, e); panel.Children.Add(labelBlock); panel.Children.Add(btn); return panel; } private string GetLocalizedPowerStatus(string status) { return status switch { "PowerOn" => Lang.Find("PowerOn"), "Sleep" => Lang.Find("Sleep"), "PowerOff" => Lang.Find("PowerOff"), _ => status }; } private async Task TogglePower(object sender, RoutedEventArgs e) { var btn = sender as Button; var tag = btn?.Tag?.ToString(); if (string.IsNullOrEmpty(tag)) return; var currentStatus = await CMMCommand.GetMonPowerStatus(tag); if (currentStatus == "Sleep" || currentStatus == "PowerOff") { await CMMCommand.PowerOn(tag); } else { await CMMCommand.Sleep(tag); } await Task.Delay(1000); var newStatus = await CMMCommand.GetMonPowerStatus(tag); btn!.Content = GetLocalizedPowerStatus(newStatus); } private void Border_MouseLeave(object sender, MouseEventArgs e) { } private void UserControl_Loaded(object sender, RoutedEventArgs e) { // Use Dispatcher to let the popup fully render first Dispatcher.BeginInvoke(new Action(async () => { try { await Refresh(); } catch (Exception ex) { sp.Children.Clear(); sp.Children.Add(new TextBlock { Text = $"Error: {ex.Message}", Foreground = System.Windows.Media.Brushes.Red, FontSize = 12, TextWrapping = TextWrapping.Wrap }); } }), System.Windows.Threading.DispatcherPriority.Background); } }