using System.Windows; using System.Windows.Input; using System.Windows.Media; using PSLauncher.Core.Localization; namespace PSLauncher.App.Views; /// /// Drop-in pour avec un look qui colle /// au reste de la UI (dark theme, accent ASTERION). API copiée : /// /// ThemedMessageBox.Show("Texte", "Titre", MessageBoxButton.YesNo, MessageBoxImage.Question, MessageBoxResult.No); /// /// /// Notes : /// - est mappé vers une icône emoji + couleur. /// - Les libellés des boutons (OK / Yes / No / Cancel) sont localisés via . /// - Owner = MainWindow par défaut (centrage), peut être passé explicitement. /// - Esc renvoie Cancel ou No selon le bouton défini comme cancel. /// public partial class ThemedMessageBox : Window { public MessageBoxResult Result { get; private set; } = MessageBoxResult.None; private MessageBoxResult _btn1Result = MessageBoxResult.None; private MessageBoxResult _btn2Result = MessageBoxResult.None; private MessageBoxResult _btn3Result = MessageBoxResult.None; private ThemedMessageBox(string message, string title, MessageBoxButton button, MessageBoxImage icon, MessageBoxResult defaultResult) { InitializeComponent(); Title = title; TitleText.Text = title; MessageText.Text = message; SetIcon(icon); SetupButtons(button, defaultResult); // Esc = cancel/no PreviewKeyDown += (_, e) => { if (e.Key == Key.Escape) { Result = button switch { MessageBoxButton.OK => MessageBoxResult.OK, MessageBoxButton.OKCancel => MessageBoxResult.Cancel, MessageBoxButton.YesNo => MessageBoxResult.No, MessageBoxButton.YesNoCancel => MessageBoxResult.Cancel, _ => MessageBoxResult.None, }; DialogResult = false; Close(); } }; } private void SetIcon(MessageBoxImage icon) { // NOTE : MessageBoxImage.Stop ≡ Error (16) et Asterisk ≡ Information (64) // côté enum .NET, donc on ne switche que sur les noms canoniques. switch (icon) { case MessageBoxImage.Error: // = Stop = Hand IconText.Text = "⛔"; IconText.Foreground = new SolidColorBrush(Color.FromRgb(0xEF, 0x44, 0x44)); break; case MessageBoxImage.Warning: // = Exclamation IconText.Text = "⚠"; IconText.Foreground = new SolidColorBrush(Color.FromRgb(0xF5, 0x9E, 0x0B)); break; case MessageBoxImage.Question: IconText.Text = "❓"; break; case MessageBoxImage.Information: // = Asterisk IconText.Text = "ℹ"; IconText.Foreground = new SolidColorBrush(Color.FromRgb(0x3B, 0x82, 0xF6)); break; default: IconText.Visibility = Visibility.Collapsed; break; } } /// /// Configure jusqu'à 3 boutons. L'ordre visuel est gauche → droite, avec /// le bouton "principal" (default) en accent à l'extrême droite. Les autres /// en secondary à gauche. /// private void SetupButtons(MessageBoxButton button, MessageBoxResult defaultResult) { // Liste (label, result) dans l'ordre où on veut les afficher var btns = button switch { MessageBoxButton.OK => new[] { (Strings.ActionOk, MessageBoxResult.OK) }, MessageBoxButton.OKCancel => new[] { (Strings.ActionCancel, MessageBoxResult.Cancel), (Strings.ActionOk, MessageBoxResult.OK), }, MessageBoxButton.YesNo => new[] { (Strings.ActionNo, MessageBoxResult.No), (Strings.ActionYes, MessageBoxResult.Yes), }, MessageBoxButton.YesNoCancel => new[] { (Strings.ActionCancel, MessageBoxResult.Cancel), (Strings.ActionNo, MessageBoxResult.No), (Strings.ActionYes, MessageBoxResult.Yes), }, _ => new[] { (Strings.ActionOk, MessageBoxResult.OK) }, }; // Btn3 = bouton accent (le plus à droite, principal). Toujours rempli. // Btn2 = secondary à sa gauche, optionnel. // Btn1 = secondary tout à gauche, optionnel. // On remplit en partant de la fin pour que l'accent soit toujours sur Btn3. var slots = new[] { Btn1, Btn2, Btn3 }; var resultSetters = new System.Action[] { r => _btn1Result = r, r => _btn2Result = r, r => _btn3Result = r, }; int startSlot = 3 - btns.Length; for (int i = 0; i < btns.Length; i++) { int slotIdx = startSlot + i; slots[slotIdx].Content = btns[i].Item1; slots[slotIdx].Visibility = Visibility.Visible; resultSetters[slotIdx](btns[i].Item2); // Default = celui dont le result match defaultResult if (btns[i].Item2 == defaultResult) slots[slotIdx].IsDefault = true; } // Si aucun match exact pour le default, on prend le bouton principal (Btn3) if (Btn3.Visibility == Visibility.Visible && !Btn1.IsDefault && !Btn2.IsDefault && !Btn3.IsDefault) Btn3.IsDefault = true; } private void OnBtn1Click(object sender, RoutedEventArgs e) => Finish(_btn1Result); private void OnBtn2Click(object sender, RoutedEventArgs e) => Finish(_btn2Result); private void OnBtn3Click(object sender, RoutedEventArgs e) => Finish(_btn3Result); private void Finish(MessageBoxResult result) { Result = result; DialogResult = true; Close(); } // ===================== STATIC SHOW OVERLOADS ===================== public static MessageBoxResult Show(string message) => Show(message, string.Empty, MessageBoxButton.OK, MessageBoxImage.None, MessageBoxResult.OK); public static MessageBoxResult Show(string message, string title) => Show(message, title, MessageBoxButton.OK, MessageBoxImage.None, MessageBoxResult.OK); public static MessageBoxResult Show(string message, string title, MessageBoxButton button) => Show(message, title, button, MessageBoxImage.None, DefaultFor(button)); public static MessageBoxResult Show(string message, string title, MessageBoxButton button, MessageBoxImage icon) => Show(message, title, button, icon, DefaultFor(button)); public static MessageBoxResult Show(string message, string title, MessageBoxButton button, MessageBoxImage icon, MessageBoxResult defaultResult) { var owner = Application.Current?.Windows.OfType().FirstOrDefault(w => w.IsActive) ?? Application.Current?.MainWindow; var dlg = new ThemedMessageBox(message, title, button, icon, defaultResult); if (owner is not null && owner.IsVisible) dlg.Owner = owner; else dlg.WindowStartupLocation = WindowStartupLocation.CenterScreen; dlg.ShowDialog(); return dlg.Result; } private static MessageBoxResult DefaultFor(MessageBoxButton button) => button switch { MessageBoxButton.OK => MessageBoxResult.OK, MessageBoxButton.OKCancel => MessageBoxResult.OK, MessageBoxButton.YesNo => MessageBoxResult.Yes, MessageBoxButton.YesNoCancel => MessageBoxResult.Yes, _ => MessageBoxResult.None, }; }