mirror of
https://github.com/RetroDECK/Duckstation.git
synced 2024-11-23 06:15:38 +00:00
ccb76d1451
Largely inspired by https://github.com/PCSX2/pcsx2/pull/9330, but almost entirely rewritten.
323 lines
11 KiB
C++
323 lines
11 KiB
C++
// SPDX-FileCopyrightText: 2019-2024 Connor McLaughlin <stenzek@gmail.com>
|
|
// SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0)
|
|
|
|
#pragma once
|
|
|
|
#include "controllersettingswindow.h"
|
|
#include "displaywidget.h"
|
|
#include "settingswindow.h"
|
|
#include "ui_mainwindow.h"
|
|
|
|
#include "core/types.h"
|
|
|
|
#include "util/window_info.h"
|
|
|
|
#include <QtCore/QThread>
|
|
#include <QtWidgets/QLabel>
|
|
#include <QtWidgets/QMainWindow>
|
|
#include <QtWidgets/QMenu>
|
|
#include <QtWidgets/QStackedWidget>
|
|
#include <memory>
|
|
#include <optional>
|
|
|
|
class QLabel;
|
|
class QThread;
|
|
class QProgressBar;
|
|
|
|
class MainWindow;
|
|
class GameListWidget;
|
|
class EmuThread;
|
|
class AutoUpdaterDialog;
|
|
class MemoryCardEditorWindow;
|
|
class CheatManagerWindow;
|
|
class DebuggerWindow;
|
|
class MemoryScannerWindow;
|
|
|
|
struct SystemBootParameters;
|
|
|
|
class GPUDevice;
|
|
namespace Achievements {
|
|
enum class LoginRequestReason;
|
|
}
|
|
namespace GameList {
|
|
struct Entry;
|
|
}
|
|
|
|
class MainWindow final : public QMainWindow
|
|
{
|
|
Q_OBJECT
|
|
|
|
public:
|
|
/// This class is a scoped lock on the system, which prevents it from running while
|
|
/// the object exists. Its purpose is to be used for blocking/modal popup boxes,
|
|
/// where the VM needs to exit fullscreen temporarily.
|
|
class SystemLock
|
|
{
|
|
public:
|
|
SystemLock(SystemLock&& lock);
|
|
SystemLock(const SystemLock&) = delete;
|
|
~SystemLock();
|
|
|
|
/// Returns the parent widget, which can be used for any popup dialogs.
|
|
ALWAYS_INLINE QWidget* getDialogParent() const { return m_dialog_parent; }
|
|
|
|
/// Cancels any pending unpause/fullscreen transition.
|
|
/// Call when you're going to destroy the system anyway.
|
|
void cancelResume();
|
|
|
|
private:
|
|
SystemLock(QWidget* dialog_parent, bool was_paused, bool was_fullscreen);
|
|
friend MainWindow;
|
|
|
|
QWidget* m_dialog_parent;
|
|
bool m_was_paused;
|
|
bool m_was_fullscreen;
|
|
};
|
|
|
|
public:
|
|
explicit MainWindow();
|
|
~MainWindow();
|
|
|
|
/// Sets application theme according to settings.
|
|
static void updateApplicationTheme();
|
|
|
|
/// Performs update check if enabled in settings.
|
|
void startupUpdateCheck();
|
|
|
|
/// Opens memory card editor with the specified paths.
|
|
void openMemoryCardEditor(const QString& card_a_path, const QString& card_b_path);
|
|
|
|
/// Locks the system by pausing it, while a popup dialog is displayed.
|
|
SystemLock pauseAndLockSystem();
|
|
|
|
/// Force quits the application.
|
|
void quit();
|
|
|
|
/// Accessors for the status bar widgets, updated by the emulation thread.
|
|
ALWAYS_INLINE QLabel* getStatusRendererWidget() const { return m_status_renderer_widget; }
|
|
ALWAYS_INLINE QLabel* getStatusResolutionWidget() const { return m_status_resolution_widget; }
|
|
ALWAYS_INLINE QLabel* getStatusFPSWidget() const { return m_status_fps_widget; }
|
|
ALWAYS_INLINE QLabel* getStatusVPSWidget() const { return m_status_vps_widget; }
|
|
|
|
/// Accessors for child windows.
|
|
CheatManagerWindow* getCheatManagerWindow() const { return m_cheat_manager_window; }
|
|
|
|
public Q_SLOTS:
|
|
/// Updates debug menu visibility (hides if disabled).
|
|
void updateDebugMenuVisibility();
|
|
|
|
void refreshGameList(bool invalidate_cache);
|
|
void refreshGameListModel();
|
|
void cancelGameListRefresh();
|
|
|
|
void runOnUIThread(const std::function<void()>& func);
|
|
bool requestShutdown(bool allow_confirm = true, bool allow_save_to_state = true, bool save_state = true);
|
|
void requestExit(bool allow_confirm = true);
|
|
void checkForSettingChanges();
|
|
std::optional<WindowInfo> getWindowInfo();
|
|
|
|
void checkForUpdates(bool display_message);
|
|
void recreate();
|
|
|
|
void* getNativeWindowId();
|
|
|
|
private Q_SLOTS:
|
|
void reportError(const QString& title, const QString& message);
|
|
bool confirmMessage(const QString& title, const QString& message);
|
|
void onStatusMessage(const QString& message);
|
|
|
|
std::optional<WindowInfo> acquireRenderWindow(bool recreate_window, bool fullscreen, bool render_to_main,
|
|
bool surfaceless, bool use_main_window_pos);
|
|
void displayResizeRequested(qint32 width, qint32 height);
|
|
void releaseRenderWindow();
|
|
void focusDisplayWidget();
|
|
void onMouseModeRequested(bool relative_mode, bool hide_cursor);
|
|
|
|
void onSettingsResetToDefault(bool system, bool controller);
|
|
void onSystemStarting();
|
|
void onSystemStarted();
|
|
void onSystemDestroyed();
|
|
void onSystemPaused();
|
|
void onSystemResumed();
|
|
void onRunningGameChanged(const QString& filename, const QString& game_serial, const QString& game_title);
|
|
void onAchievementsLoginRequested(Achievements::LoginRequestReason reason);
|
|
void onAchievementsChallengeModeChanged(bool enabled);
|
|
void onApplicationStateChanged(Qt::ApplicationState state);
|
|
|
|
void onStartFileActionTriggered();
|
|
void onStartDiscActionTriggered();
|
|
void onStartBIOSActionTriggered();
|
|
void onChangeDiscFromFileActionTriggered();
|
|
void onChangeDiscFromGameListActionTriggered();
|
|
void onChangeDiscFromDeviceActionTriggered();
|
|
void onChangeDiscMenuAboutToShow();
|
|
void onChangeDiscMenuAboutToHide();
|
|
void onLoadStateMenuAboutToShow();
|
|
void onSaveStateMenuAboutToShow();
|
|
void onCheatsActionTriggered();
|
|
void onCheatsMenuAboutToShow();
|
|
void onStartFullscreenUITriggered();
|
|
void onFullscreenUIStateChange(bool running);
|
|
void onRemoveDiscActionTriggered();
|
|
void onViewToolbarActionToggled(bool checked);
|
|
void onViewLockToolbarActionToggled(bool checked);
|
|
void onViewStatusBarActionToggled(bool checked);
|
|
void onViewGameListActionTriggered();
|
|
void onViewGameGridActionTriggered();
|
|
void onViewSystemDisplayTriggered();
|
|
void onViewGamePropertiesActionTriggered();
|
|
void onGitHubRepositoryActionTriggered();
|
|
void onIssueTrackerActionTriggered();
|
|
void onDiscordServerActionTriggered();
|
|
void onAboutActionTriggered();
|
|
void onCheckForUpdatesActionTriggered();
|
|
void onToolsMemoryCardEditorTriggered();
|
|
void onToolsMemoryScannerTriggered();
|
|
void onToolsCoverDownloaderTriggered();
|
|
void onToolsOpenDataDirectoryTriggered();
|
|
void onSettingsTriggeredFromToolbar();
|
|
|
|
void onGameListRefreshComplete();
|
|
void onGameListRefreshProgress(const QString& status, int current, int total);
|
|
void onGameListSelectionChanged();
|
|
void onGameListEntryActivated();
|
|
void onGameListEntryContextMenuRequested(const QPoint& point);
|
|
|
|
void onUpdateCheckComplete();
|
|
|
|
void openCheatManager();
|
|
void openCPUDebugger();
|
|
|
|
protected:
|
|
void showEvent(QShowEvent* event) override;
|
|
void closeEvent(QCloseEvent* event) override;
|
|
void changeEvent(QEvent* event) override;
|
|
void dragEnterEvent(QDragEnterEvent* event) override;
|
|
void dropEvent(QDropEvent* event) override;
|
|
void moveEvent(QMoveEvent* event) override;
|
|
void resizeEvent(QResizeEvent* event) override;
|
|
|
|
#ifdef _WIN32
|
|
bool nativeEvent(const QByteArray& eventType, void* message, qintptr* result) override;
|
|
#endif
|
|
|
|
private:
|
|
static void setStyleFromSettings();
|
|
static void setIconThemeFromSettings();
|
|
|
|
/// Initializes the window. Call once at startup.
|
|
void initialize();
|
|
|
|
void setupAdditionalUi();
|
|
void connectSignals();
|
|
|
|
void updateEmulationActions(bool starting, bool running, bool cheevos_challenge_mode);
|
|
void updateStatusBarWidgetVisibility();
|
|
void updateWindowTitle();
|
|
void updateWindowState(bool force_visible = false);
|
|
void updateCheatActionsVisibility();
|
|
|
|
void setProgressBar(int current, int total);
|
|
void clearProgressBar();
|
|
|
|
QWidget* getContentParent();
|
|
QWidget* getDisplayContainer() const;
|
|
bool isShowingGameList() const;
|
|
bool isRenderingFullscreen() const;
|
|
bool isRenderingToMain() const;
|
|
bool shouldHideMouseCursor() const;
|
|
bool shouldHideMainWindow() const;
|
|
|
|
void switchToGameListView();
|
|
void switchToEmulationView();
|
|
void saveStateToConfig();
|
|
void restoreStateFromConfig();
|
|
void saveDisplayWindowGeometryToConfig();
|
|
void restoreDisplayWindowGeometryFromConfig();
|
|
void createDisplayWidget(bool fullscreen, bool render_to_main, bool use_main_window_pos);
|
|
void destroyDisplayWidget(bool show_game_list);
|
|
void updateDisplayWidgetCursor();
|
|
void updateDisplayRelatedActions(bool has_surface, bool render_to_main, bool fullscreen);
|
|
|
|
SettingsWindow* getSettingsDialog();
|
|
void doSettings(const char* category = nullptr);
|
|
|
|
void doControllerSettings(ControllerSettingsWindow::Category category = ControllerSettingsWindow::Category::Count);
|
|
|
|
void updateDebugMenuCPUExecutionMode();
|
|
void updateDebugMenuGPURenderer();
|
|
void updateDebugMenuCropMode();
|
|
void updateMenuSelectedTheme();
|
|
std::string getDeviceDiscPath(const QString& title);
|
|
void setGameListEntryCoverImage(const GameList::Entry* entry);
|
|
void clearGameListEntryPlayTime(const GameList::Entry* entry);
|
|
void setTheme(const QString& theme);
|
|
void updateTheme();
|
|
void reloadThemeSpecificImages();
|
|
void destroySubWindows();
|
|
|
|
void registerForDeviceNotifications();
|
|
void unregisterForDeviceNotifications();
|
|
|
|
/// Fills menu with save state info and handlers.
|
|
void populateGameListContextMenu(const GameList::Entry* entry, QWidget* parent_window, QMenu* menu);
|
|
|
|
void populateLoadStateMenu(const char* game_serial, QMenu* menu);
|
|
void populateSaveStateMenu(const char* game_serial, QMenu* menu);
|
|
|
|
/// Fills menu with the current playlist entries. The disc index is marked as checked.
|
|
void populateChangeDiscSubImageMenu(QMenu* menu, QActionGroup* action_group);
|
|
|
|
/// Fills menu with the current cheat options.
|
|
void populateCheatsMenu(QMenu* menu);
|
|
|
|
const GameList::Entry* resolveDiscSetEntry(const GameList::Entry* entry,
|
|
std::unique_lock<std::recursive_mutex>& lock);
|
|
std::shared_ptr<SystemBootParameters> getSystemBootParameters(std::string file);
|
|
std::optional<bool> promptForResumeState(const std::string& save_state_path);
|
|
void startFile(std::string path, std::optional<std::string> save_path, std::optional<bool> fast_boot);
|
|
void startFileOrChangeDisc(const QString& path);
|
|
void promptForDiscChange(const QString& path);
|
|
|
|
Ui::MainWindow m_ui;
|
|
|
|
GameListWidget* m_game_list_widget = nullptr;
|
|
|
|
DisplayWidget* m_display_widget = nullptr;
|
|
DisplayContainer* m_display_container = nullptr;
|
|
|
|
QProgressBar* m_status_progress_widget = nullptr;
|
|
QLabel* m_status_renderer_widget = nullptr;
|
|
QLabel* m_status_fps_widget = nullptr;
|
|
QLabel* m_status_vps_widget = nullptr;
|
|
QLabel* m_status_resolution_widget = nullptr;
|
|
|
|
QMenu* m_settings_toolbar_menu = nullptr;
|
|
|
|
SettingsWindow* m_settings_window = nullptr;
|
|
ControllerSettingsWindow* m_controller_settings_window = nullptr;
|
|
|
|
AutoUpdaterDialog* m_auto_updater_dialog = nullptr;
|
|
MemoryCardEditorWindow* m_memory_card_editor_window = nullptr;
|
|
CheatManagerWindow* m_cheat_manager_window = nullptr;
|
|
DebuggerWindow* m_debugger_window = nullptr;
|
|
MemoryScannerWindow* m_memory_scanner_window = nullptr;
|
|
|
|
bool m_was_paused_by_focus_loss = false;
|
|
bool m_open_debugger_on_start = false;
|
|
bool m_relative_mouse_mode = false;
|
|
bool m_hide_mouse_cursor = false;
|
|
|
|
bool m_display_created = false;
|
|
bool m_save_states_invalidated = false;
|
|
bool m_was_paused_on_surface_loss = false;
|
|
bool m_was_disc_change_request = false;
|
|
bool m_is_closing = false;
|
|
|
|
#ifdef _WIN32
|
|
void* m_device_notification_handle = nullptr;
|
|
#endif
|
|
};
|
|
|
|
extern MainWindow* g_main_window;
|