using System; using System.IO; using System.Windows; using System.Windows.Controls; using MPF.Core; using MPF.Core.UI.ViewModels; using SabreTools.RedumpLib.Data; using WPFCustomMessageBox; using WinForms = System.Windows.Forms; namespace MPF.UI.Core.Windows { public partial class MainWindow : WindowBase { /// /// Read-only access to the current main view model /// public MainViewModel MainViewModel => DataContext as MainViewModel ?? new MainViewModel(); /// /// Constructor /// public MainWindow() => InitializeComponent(); /// /// Handler for MainWindow OnContentRendered event /// protected override void OnContentRendered(EventArgs e) { base.OnContentRendered(e); // Disable buttons until we load fully MainViewModel.StartStopButtonEnabled = false; MainViewModel.MediaScanButtonEnabled = false; MainViewModel.UpdateVolumeLabelEnabled = false; MainViewModel.CopyProtectScanButtonEnabled = false; // Add the click handlers to the UI AddEventHandlers(); // Display the debug option in the menu, if necessary if (MainViewModel.Options.ShowDebugViewMenuItem) DebugViewMenuItem.Visibility = Visibility.Visible; MainViewModel.Init(LogOutput.EnqueueLog, DisplayUserMessage, ShowDiscInformationWindow); // Set the UI color scheme according to the options if (MainViewModel.Options.EnableDarkMode) EnableDarkMode(); else EnableLightMode(); // Check for updates, if necessary if (MainViewModel.Options.CheckForUpdatesOnStartup) CheckForUpdates(showIfSame: false); } #region UI Functionality /// /// Add all event handlers /// public void AddEventHandlers() { // Menu Bar Click AboutMenuItem.Click += AboutClick; AppExitMenuItem.Click += AppExitClick; CheckForUpdatesMenuItem.Click += CheckForUpdatesClick; DebugViewMenuItem.Click += DebugViewClick; OptionsMenuItem.Click += OptionsMenuItemClick; // User Area Click CopyProtectScanButton.Click += CopyProtectScanButtonClick; EnableParametersCheckBox.Click += EnableParametersCheckBoxClick; MediaScanButton.Click += MediaScanButtonClick; UpdateVolumeLabel.Click += UpdateVolumeLabelClick; OutputPathBrowseButton.Click += OutputPathBrowseButtonClick; StartStopButton.Click += StartStopButtonClick; // User Area SelectionChanged SystemTypeComboBox.SelectionChanged += SystemTypeComboBoxSelectionChanged; MediaTypeComboBox.SelectionChanged += MediaTypeComboBoxSelectionChanged; DriveLetterComboBox.SelectionChanged += DriveLetterComboBoxSelectionChanged; DriveSpeedComboBox.SelectionChanged += DriveSpeedComboBoxSelectionChanged; DumpingProgramComboBox.SelectionChanged += DumpingProgramComboBoxSelectionChanged; // User Area TextChanged OutputPathTextBox.TextChanged += OutputPathTextBoxTextChanged; } /// /// Browse for an output file path /// public void BrowseFile() { // Get the current path, if possible string currentPath = MainViewModel.OutputPath; if (string.IsNullOrWhiteSpace(currentPath) && !string.IsNullOrWhiteSpace(MainViewModel.Options.DefaultOutputPath)) currentPath = Path.Combine(MainViewModel.Options.DefaultOutputPath, "track.bin"); else if (string.IsNullOrWhiteSpace(currentPath)) currentPath = "track.bin"; if (string.IsNullOrWhiteSpace(currentPath)) currentPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "track.bin"); // Get the full path currentPath = Path.GetFullPath(currentPath); // Get the directory var directory = Path.GetDirectoryName(currentPath); // Get the filename string filename = Path.GetFileName(currentPath); WinForms.FileDialog fileDialog = new WinForms.SaveFileDialog { FileName = filename, InitialDirectory = directory, }; WinForms.DialogResult result = fileDialog.ShowDialog(); if (result == WinForms.DialogResult.OK) { MainViewModel.OutputPath = fileDialog.FileName; } } /// /// Check for available updates /// /// True to show the box even if it's the same, false to only show if it's different public void CheckForUpdates(bool showIfSame) { (bool different, string message, var url) = MainViewModel.CheckForUpdates(); // If we have a new version, put it in the clipboard if (different) Clipboard.SetText(url); if (showIfSame || different) CustomMessageBox.Show(this, message, "Version Update Check", MessageBoxButton.OK, different ? MessageBoxImage.Exclamation : MessageBoxImage.Information); } /// /// Display a user message using a CustomMessageBox /// /// Title to display to the user /// Message to display to the user /// Number of options to display /// true for inquiry, false otherwise /// true for positive, false for negative, null for neutral public bool? DisplayUserMessage(string title, string message, int optionCount, bool flag) { // Set the correct button style MessageBoxButton button; switch (optionCount) { case 1: button = MessageBoxButton.OK; break; case 2: button = MessageBoxButton.YesNo; break; case 3: button = MessageBoxButton.YesNoCancel; break; // This should not happen, but default to "OK" default: button = MessageBoxButton.OK; break; } // Set the correct icon MessageBoxImage image = flag ? MessageBoxImage.Question : MessageBoxImage.Exclamation; // Display and get the result MessageBoxResult result = CustomMessageBox.Show(this, message, title, button, image); switch (result) { case MessageBoxResult.OK: case MessageBoxResult.Yes: return true; case MessageBoxResult.No: return false; case MessageBoxResult.Cancel: case MessageBoxResult.None: default: return null; } } /// /// Build a dummy SubmissionInfo and display it for testing /// public void ShowDebugDiscInfoWindow() { var submissionInfo = MainViewModel.CreateDebugSubmissionInfo(); var result = ShowDiscInformationWindow(submissionInfo); InfoTool.ProcessSpecialFields(result.Item2); } /// /// Show the disc information window /// /// SubmissionInfo object to display and possibly change /// Dialog open result #if NET48 public (bool?, SubmissionInfo) ShowDiscInformationWindow(SubmissionInfo submissionInfo) #else public (bool?, SubmissionInfo?) ShowDiscInformationWindow(SubmissionInfo? submissionInfo) #endif { if (MainViewModel.Options.ShowDiscEjectReminder) CustomMessageBox.Show(this, "It is now safe to eject the disc", "Eject", MessageBoxButton.OK, MessageBoxImage.Information); var discInformationWindow = new DiscInformationWindow(MainViewModel.Options, submissionInfo) { Focusable = true, Owner = this, ShowActivated = true, ShowInTaskbar = true, WindowStartupLocation = WindowStartupLocation.CenterOwner, }; bool? result = discInformationWindow.ShowDialog(); // Copy back the submission info changes, if necessary if (result == true) #if NET48 submissionInfo = discInformationWindow.DiscInformationViewModel.SubmissionInfo.Clone() as SubmissionInfo; #else submissionInfo = (discInformationWindow.DiscInformationViewModel.SubmissionInfo.Clone() as SubmissionInfo)!; #endif #if NET48 return (result, submissionInfo); #else return (result, submissionInfo!); #endif } /// /// Show the Options window /// public void ShowOptionsWindow() { var optionsWindow = new OptionsWindow(MainViewModel.Options) { Focusable = true, Owner = this, ShowActivated = true, ShowInTaskbar = true, WindowStartupLocation = WindowStartupLocation.CenterOwner, }; optionsWindow.Closed += OnOptionsUpdated; optionsWindow.Show(); } /// /// Recolor all UI elements for light mode /// private static void EnableLightMode() { var theme = new LightModeTheme(); theme.Apply(); } /// /// Recolor all UI elements for dark mode /// private static void EnableDarkMode() { var theme = new DarkModeTheme(); theme.Apply(); } #endregion #region Event Handlers /// /// Handler for OptionsWindow OnUpdated event /// #if NET48 public void OnOptionsUpdated(object sender, EventArgs e) #else public void OnOptionsUpdated(object? sender, EventArgs e) #endif { bool savedSettings = (sender as OptionsWindow)?.OptionsViewModel?.SavedSettings ?? false; var options = (sender as OptionsWindow)?.OptionsViewModel?.Options; MainViewModel.UpdateOptions(savedSettings, options); } #region Menu Bar /// /// Handler for AboutMenuItem Click event /// public void AboutClick(object sender, RoutedEventArgs e) { string aboutText = MainViewModel.CreateAboutText(); CustomMessageBox.Show(this, aboutText, "About", MessageBoxButton.OK, MessageBoxImage.Information); } /// /// Handler for AppExitMenuItem Click event /// public void AppExitClick(object sender, RoutedEventArgs e) => Application.Current.Shutdown(); /// /// Handler for CheckForUpdatesMenuItem Click event /// public void CheckForUpdatesClick(object sender, RoutedEventArgs e) => CheckForUpdates(showIfSame: true); /// /// Handler for DebugViewMenuItem Click event /// public void DebugViewClick(object sender, RoutedEventArgs e) => ShowDebugDiscInfoWindow(); /// /// Handler for OptionsMenuItem Click event /// public void OptionsMenuItemClick(object sender, RoutedEventArgs e) => ShowOptionsWindow(); #endregion #region User Area /// /// Handler for CopyProtectScanButton Click event /// public async void CopyProtectScanButtonClick(object sender, RoutedEventArgs e) { var (output, error) = await MainViewModel.ScanAndShowProtection(); if (!MainViewModel.LogPanelExpanded) { if (!string.IsNullOrEmpty(output) && string.IsNullOrEmpty(error)) CustomMessageBox.Show(this, output, "Detected Protection(s)", MessageBoxButton.OK, MessageBoxImage.Information); else CustomMessageBox.Show(this, "An exception occurred, see the log for details", "Error!", MessageBoxButton.OK, MessageBoxImage.Error); } } /// /// Handler for DriveLetterComboBox SelectionChanged event /// public void DriveLetterComboBoxSelectionChanged(object sender, SelectionChangedEventArgs e) { if (MainViewModel.CanExecuteSelectionChanged) MainViewModel.InitializeUIValues(removeEventHandlers: true, rescanDrives: false); } /// /// Handler for DriveSpeedComboBox SelectionChanged event /// public void DriveSpeedComboBoxSelectionChanged(object sender, SelectionChangedEventArgs e) { if (MainViewModel.CanExecuteSelectionChanged) MainViewModel.EnsureDiscInformation(); } /// /// Handler for DumpingProgramComboBox SelectionChanged event /// public void DumpingProgramComboBoxSelectionChanged(object sender, SelectionChangedEventArgs e) { if (MainViewModel.CanExecuteSelectionChanged) MainViewModel.ChangeDumpingProgram(); } /// /// Handler for EnableParametersCheckBox Click event /// public void EnableParametersCheckBoxClick(object sender, RoutedEventArgs e) { if (MainViewModel.CanExecuteSelectionChanged) MainViewModel.ToggleParameters(); } /// /// Handler for MediaScanButton Click event /// public void MediaScanButtonClick(object sender, RoutedEventArgs e) => MainViewModel.InitializeUIValues(removeEventHandlers: true, rescanDrives: true); /// /// Handler for MediaTypeComboBox SelectionChanged event /// public void MediaTypeComboBoxSelectionChanged(object sender, SelectionChangedEventArgs e) { if (MainViewModel.CanExecuteSelectionChanged) MainViewModel.ChangeMediaType(e.RemovedItems, e.AddedItems); } /// /// Handler for OutputPathBrowseButton Click event /// public void OutputPathBrowseButtonClick(object sender, RoutedEventArgs e) { BrowseFile(); MainViewModel.EnsureDiscInformation(); } /// /// Handler for OutputPathTextBox TextChanged event /// public void OutputPathTextBoxTextChanged(object sender, TextChangedEventArgs e) { if (MainViewModel.CanExecuteSelectionChanged) MainViewModel.EnsureDiscInformation(); } /// /// Handler for StartStopButton Click event /// public void StartStopButtonClick(object sender, RoutedEventArgs e) => MainViewModel.ToggleStartStop(); /// /// Handler for SystemTypeComboBox SelectionChanged event /// public void SystemTypeComboBoxSelectionChanged(object sender, SelectionChangedEventArgs e) { if (MainViewModel.CanExecuteSelectionChanged) MainViewModel.ChangeSystem(); } /// /// Handler for UpdateVolumeLabel Click event /// public void UpdateVolumeLabelClick(object sender, RoutedEventArgs e) { if (MainViewModel.CanExecuteSelectionChanged) { if (MainViewModel.Options.FastUpdateLabel) MainViewModel.FastUpdateLabel(removeEventHandlers: true); else MainViewModel.InitializeUIValues(removeEventHandlers: true, rescanDrives: false); } } #endregion #endregion // Event Handlers } }