diff --git a/Source/Core/Core/ConfigManager.cpp b/Source/Core/Core/ConfigManager.cpp index 9eeba47706..56985b1c3d 100644 --- a/Source/Core/Core/ConfigManager.cpp +++ b/Source/Core/Core/ConfigManager.cpp @@ -145,7 +145,7 @@ void SConfig::SaveInterfaceSettings(IniFile& ini) IniFile::Section* interface = ini.GetOrCreateSection("Interface"); interface->Set("ConfirmStop", bConfirmStop); - interface->Set("HideCursor", bHideCursor); + interface->Set("CursorVisibility", m_show_cursor); interface->Set("LockCursor", bLockCursor); interface->Set("LanguageCode", m_InterfaceLanguage); interface->Set("ExtendedFPSInfo", m_InterfaceExtendedFPSInfo); @@ -399,7 +399,7 @@ void SConfig::LoadInterfaceSettings(IniFile& ini) IniFile::Section* interface = ini.GetOrCreateSection("Interface"); interface->Get("ConfirmStop", &bConfirmStop, true); - interface->Get("HideCursor", &bHideCursor, false); + interface->Get("CursorVisibility", &m_show_cursor, ShowCursor::OnMovement); interface->Get("LockCursor", &bLockCursor, false); interface->Get("LanguageCode", &m_InterfaceLanguage, ""); interface->Get("ExtendedFPSInfo", &m_InterfaceExtendedFPSInfo, false); diff --git a/Source/Core/Core/ConfigManager.h b/Source/Core/Core/ConfigManager.h index c6d954a398..50d8ebd3fe 100644 --- a/Source/Core/Core/ConfigManager.h +++ b/Source/Core/Core/ConfigManager.h @@ -146,7 +146,14 @@ struct SConfig // Interface settings bool bConfirmStop = false; - bool bHideCursor = false; + + enum class ShowCursor + { + Never, + Constantly, + OnMovement, + } m_show_cursor; + bool bLockCursor = false; std::string theme_name; diff --git a/Source/Core/DolphinNoGUI/PlatformX11.cpp b/Source/Core/DolphinNoGUI/PlatformX11.cpp index a47d1f0d84..4ba2c1b3b9 100644 --- a/Source/Core/DolphinNoGUI/PlatformX11.cpp +++ b/Source/Core/DolphinNoGUI/PlatformX11.cpp @@ -70,7 +70,7 @@ PlatformX11::~PlatformX11() if (m_display) { - if (SConfig::GetInstance().bHideCursor) + if (SConfig::GetInstance().m_show_cursor == SConfig::ShowCursor::Never) XFreeCursor(m_display, m_blank_cursor); XCloseDisplay(m_display); @@ -115,7 +115,7 @@ bool PlatformX11::Init() m_xrr_config = new X11Utils::XRRConfiguration(m_display, m_window); #endif - if (SConfig::GetInstance().bHideCursor) + if (SConfig::GetInstance().m_show_cursor == SConfig::ShowCursor::Never) { // make a blank cursor Pixmap Blank; @@ -200,13 +200,13 @@ void PlatformX11::ProcessEvents() { if (Core::GetState() == Core::State::Running) { - if (SConfig::GetInstance().bHideCursor) + if (SConfig::GetInstance().m_show_cursor == SConfig::ShowCursor::Never) XUndefineCursor(m_display, m_window); Core::SetState(Core::State::Paused); } else { - if (SConfig::GetInstance().bHideCursor) + if (SConfig::GetInstance().m_show_cursor == SConfig::ShowCursor::Never) XDefineCursor(m_display, m_window, m_blank_cursor); Core::SetState(Core::State::Running); } @@ -243,14 +243,15 @@ void PlatformX11::ProcessEvents() case FocusIn: { m_window_focus = true; - if (SConfig::GetInstance().bHideCursor && Core::GetState() != Core::State::Paused) + if (SConfig::GetInstance().m_show_cursor == SConfig::ShowCursor::Never && + Core::GetState() != Core::State::Paused) XDefineCursor(m_display, m_window, m_blank_cursor); } break; case FocusOut: { m_window_focus = false; - if (SConfig::GetInstance().bHideCursor) + if (SConfig::GetInstance().m_show_cursor == SConfig::ShowCursor::Never) XUndefineCursor(m_display, m_window); } break; diff --git a/Source/Core/DolphinQt/RenderWidget.cpp b/Source/Core/DolphinQt/RenderWidget.cpp index f8dfb4ddd8..0343eda8fa 100644 --- a/Source/Core/DolphinQt/RenderWidget.cpp +++ b/Source/Core/DolphinQt/RenderWidget.cpp @@ -83,7 +83,7 @@ RenderWidget::RenderWidget(QWidget* parent) : QWidget(parent) m_mouse_timer->setSingleShot(true); setMouseTracking(true); - connect(&Settings::Instance(), &Settings::HideCursorChanged, this, + connect(&Settings::Instance(), &Settings::CursorVisibilityChanged, this, &RenderWidget::OnHideCursorChanged); connect(&Settings::Instance(), &Settings::LockCursorChanged, this, &RenderWidget::OnLockCursorChanged); @@ -139,6 +139,7 @@ void RenderWidget::OnHideCursorChanged() { UpdateCursor(); } + void RenderWidget::OnLockCursorChanged() { SetCursorLocked(false); @@ -155,14 +156,16 @@ void RenderWidget::UpdateCursor() // on top of the game window in the background const bool keep_on_top = (windowFlags() & Qt::WindowStaysOnTopHint) != 0; const bool should_hide = - Settings::Instance().GetHideCursor() && + (Settings::Instance().GetCursorVisibility() == SConfig::ShowCursor::Never) && (keep_on_top || SConfig::GetInstance().m_BackgroundInput || isActiveWindow()); setCursor(should_hide ? Qt::BlankCursor : Qt::ArrowCursor); } else { - setCursor((m_cursor_locked && Settings::Instance().GetHideCursor()) ? Qt::BlankCursor : - Qt::ArrowCursor); + setCursor((m_cursor_locked && + Settings::Instance().GetCursorVisibility() == SConfig::ShowCursor::Never) ? + Qt::BlankCursor : + Qt::ArrowCursor); } } @@ -185,7 +188,8 @@ void RenderWidget::HandleCursorTimer() { if (!isActiveWindow()) return; - if (!Settings::Instance().GetLockCursor() || m_cursor_locked) + if ((!Settings::Instance().GetLockCursor() || m_cursor_locked) && + Settings::Instance().GetCursorVisibility() == SConfig::ShowCursor::OnMovement) { setCursor(Qt::BlankCursor); } @@ -268,7 +272,7 @@ void RenderWidget::SetCursorLocked(bool locked, bool follow_aspect_ratio) { m_cursor_locked = true; - if (Settings::Instance().GetHideCursor()) + if (Settings::Instance().GetCursorVisibility() != SConfig::ShowCursor::Constantly) { setCursor(Qt::BlankCursor); } @@ -370,7 +374,7 @@ bool RenderWidget::event(QEvent* event) break; case QEvent::MouseMove: // Unhide on movement - if (!Settings::Instance().GetHideCursor()) + if (Settings::Instance().GetCursorVisibility() == SConfig::ShowCursor::OnMovement) { setCursor(Qt::ArrowCursor); m_mouse_timer->start(MOUSE_HIDE_DELAY); @@ -381,7 +385,8 @@ bool RenderWidget::event(QEvent* event) break; case QEvent::Show: // Don't do if "stay on top" changed (or was true) - if (Settings::Instance().GetLockCursor() && Settings::Instance().GetHideCursor() && + if (Settings::Instance().GetLockCursor() && + Settings::Instance().GetCursorVisibility() != SConfig::ShowCursor::Constantly && !m_dont_lock_cursor_on_show) { // Auto lock when this window is shown (it was hidden) diff --git a/Source/Core/DolphinQt/RenderWidget.h b/Source/Core/DolphinQt/RenderWidget.h index 051ca5de87..c44f673cb2 100644 --- a/Source/Core/DolphinQt/RenderWidget.h +++ b/Source/Core/DolphinQt/RenderWidget.h @@ -35,6 +35,7 @@ signals: private: void HandleCursorTimer(); void OnHideCursorChanged(); + void OnNeverHideCursorChanged(); void OnLockCursorChanged(); void OnKeepOnTopChanged(bool top); void UpdateCursor(); diff --git a/Source/Core/DolphinQt/Settings.cpp b/Source/Core/DolphinQt/Settings.cpp index 964b881bf4..3958a9a255 100644 --- a/Source/Core/DolphinQt/Settings.cpp +++ b/Source/Core/DolphinQt/Settings.cpp @@ -10,6 +10,7 @@ #include #include #include +#include #include #include @@ -325,15 +326,16 @@ void Settings::SetStateSlot(int slot) GetQSettings().setValue(QStringLiteral("Emulation/StateSlot"), slot); } -void Settings::SetHideCursor(bool hide_cursor) +void Settings::SetCursorVisibility(SConfig::ShowCursor hideCursor) { - SConfig::GetInstance().bHideCursor = hide_cursor; - emit HideCursorChanged(); + SConfig::GetInstance().m_show_cursor = hideCursor; + + emit CursorVisibilityChanged(); } -bool Settings::GetHideCursor() const +SConfig::ShowCursor Settings::GetCursorVisibility() const { - return SConfig::GetInstance().bHideCursor; + return SConfig::GetInstance().m_show_cursor; } void Settings::SetLockCursor(bool lock_cursor) diff --git a/Source/Core/DolphinQt/Settings.h b/Source/Core/DolphinQt/Settings.h index 241dacffc8..3ec5e04834 100644 --- a/Source/Core/DolphinQt/Settings.h +++ b/Source/Core/DolphinQt/Settings.h @@ -7,8 +7,10 @@ #include #include +#include #include +#include "Core/ConfigManager.h" #include "DiscIO/Enums.h" namespace Core @@ -97,8 +99,8 @@ public: void SetUSBKeyboardConnected(bool connected); // Graphics - void SetHideCursor(bool hide_cursor); - bool GetHideCursor() const; + void SetCursorVisibility(SConfig::ShowCursor hideCursor); + SConfig::ShowCursor GetCursorVisibility() const; void SetLockCursor(bool lock_cursor); bool GetLockCursor() const; void SetKeepWindowOnTop(bool top); @@ -168,7 +170,7 @@ signals: void MetadataRefreshRequested(); void MetadataRefreshCompleted(); void AutoRefreshToggled(bool enabled); - void HideCursorChanged(); + void CursorVisibilityChanged(); void LockCursorChanged(); void KeepWindowOnTopChanged(bool top); void VolumeChanged(int volume); diff --git a/Source/Core/DolphinQt/Settings/InterfacePane.cpp b/Source/Core/DolphinQt/Settings/InterfacePane.cpp index 05c643a5a4..a42dc90a52 100644 --- a/Source/Core/DolphinQt/Settings/InterfacePane.cpp +++ b/Source/Core/DolphinQt/Settings/InterfacePane.cpp @@ -9,6 +9,7 @@ #include #include #include +#include #include #include @@ -169,23 +170,36 @@ void InterfacePane::CreateInGame() m_checkbox_enable_osd = new QCheckBox(tr("Show On-Screen Display Messages")); m_checkbox_show_active_title = new QCheckBox(tr("Show Active Title in Window Title")); m_checkbox_pause_on_focus_lost = new QCheckBox(tr("Pause on Focus Loss")); - m_checkbox_hide_mouse = new QCheckBox(tr("Always Hide Mouse Cursor")); - m_checkbox_lock_mouse = new QCheckBox(tr("Lock Mouse Cursor")); - m_checkbox_hide_mouse->setToolTip( - tr("Will immediately hide the Mouse Cursor when it hovers on top of the Render Widget, " - "otherwise " - "there is a delay.\nIf \"Lock Mouse Cursor\" is enabled, it will hide on Mouse locked")); + auto* mouse_groupbox = new QGroupBox(tr("Mouse Cursor Visibility")); + auto* m_vboxlayout_hide_mouse = new QVBoxLayout; + mouse_groupbox->setLayout(m_vboxlayout_hide_mouse); + + m_radio_cursor_visible_movement = new QRadioButton(tr("On Movement")); + m_radio_cursor_visible_movement->setToolTip( + tr("Mouse Cursor hides after inactivity and returns upon Mouse Cursor movement.")); + m_radio_cursor_visible_never = new QRadioButton(tr("Never")); + m_radio_cursor_visible_never->setToolTip( + tr("Mouse Cursor will never be visible while a game is running.")); + m_radio_cursor_visible_always = new QRadioButton(tr("Always")); + m_radio_cursor_visible_always->setToolTip(tr("Mouse Cursor will always be visible.")); + + m_vboxlayout_hide_mouse->addWidget(m_radio_cursor_visible_movement); + m_vboxlayout_hide_mouse->addWidget(m_radio_cursor_visible_never); + m_vboxlayout_hide_mouse->addWidget(m_radio_cursor_visible_always); + + m_checkbox_lock_mouse = new QCheckBox(tr("Lock Mouse Cursor")); m_checkbox_lock_mouse->setToolTip(tr("Will lock the Mouse Cursor to the Render Widget as long as " "it has focus. You can set a hotkey to unlock it.")); + mouse_groupbox->setLayout(m_vboxlayout_hide_mouse); groupbox_layout->addWidget(m_checkbox_top_window); groupbox_layout->addWidget(m_checkbox_confirm_on_stop); groupbox_layout->addWidget(m_checkbox_use_panic_handlers); groupbox_layout->addWidget(m_checkbox_enable_osd); groupbox_layout->addWidget(m_checkbox_show_active_title); groupbox_layout->addWidget(m_checkbox_pause_on_focus_lost); - groupbox_layout->addWidget(m_checkbox_hide_mouse); + groupbox_layout->addWidget(mouse_groupbox); #ifdef _WIN32 groupbox_layout->addWidget(m_checkbox_lock_mouse); #endif @@ -211,8 +225,12 @@ void InterfacePane::ConnectLayout() connect(m_checkbox_show_active_title, &QCheckBox::toggled, this, &InterfacePane::OnSaveConfig); connect(m_checkbox_enable_osd, &QCheckBox::toggled, this, &InterfacePane::OnSaveConfig); connect(m_checkbox_pause_on_focus_lost, &QCheckBox::toggled, this, &InterfacePane::OnSaveConfig); - connect(m_checkbox_hide_mouse, &QCheckBox::toggled, &Settings::Instance(), - &Settings::SetHideCursor); + connect(m_radio_cursor_visible_movement, &QRadioButton::toggled, this, + &InterfacePane::OnCursorVisibleMovement); + connect(m_radio_cursor_visible_never, &QRadioButton::toggled, this, + &InterfacePane::OnCursorVisibleNever); + connect(m_radio_cursor_visible_always, &QRadioButton::toggled, this, + &InterfacePane::OnCursorVisibleAlways); connect(m_checkbox_lock_mouse, &QCheckBox::toggled, &Settings::Instance(), &Settings::SetLockCursor); connect(m_checkbox_use_userstyle, &QCheckBox::toggled, this, &InterfacePane::OnSaveConfig); @@ -250,7 +268,13 @@ void InterfacePane::LoadConfig() m_checkbox_pause_on_focus_lost->setChecked(startup_params.m_PauseOnFocusLost); m_checkbox_use_covers->setChecked(Config::Get(Config::MAIN_USE_GAME_COVERS)); m_checkbox_focused_hotkeys->setChecked(Config::Get(Config::MAIN_FOCUSED_HOTKEYS)); - m_checkbox_hide_mouse->setChecked(Settings::Instance().GetHideCursor()); + m_radio_cursor_visible_movement->setChecked(Settings::Instance().GetCursorVisibility() == + SConfig::ShowCursor::OnMovement); + m_radio_cursor_visible_always->setChecked(Settings::Instance().GetCursorVisibility() == + SConfig::ShowCursor::Constantly); + m_radio_cursor_visible_never->setChecked(Settings::Instance().GetCursorVisibility() == + SConfig::ShowCursor::Never); + m_checkbox_lock_mouse->setChecked(Settings::Instance().GetLockCursor()); m_checkbox_disable_screensaver->setChecked(Config::Get(Config::MAIN_DISABLE_SCREENSAVER)); } @@ -300,3 +324,18 @@ void InterfacePane::OnSaveConfig() settings.SaveSettings(); } + +void InterfacePane::OnCursorVisibleMovement() +{ + Settings::Instance().SetCursorVisibility(SConfig::ShowCursor::OnMovement); +} + +void InterfacePane::OnCursorVisibleNever() +{ + Settings::Instance().SetCursorVisibility(SConfig::ShowCursor::Never); +} + +void InterfacePane::OnCursorVisibleAlways() +{ + Settings::Instance().SetCursorVisibility(SConfig::ShowCursor::Constantly); +} diff --git a/Source/Core/DolphinQt/Settings/InterfacePane.h b/Source/Core/DolphinQt/Settings/InterfacePane.h index 405bcced05..d751c507c5 100644 --- a/Source/Core/DolphinQt/Settings/InterfacePane.h +++ b/Source/Core/DolphinQt/Settings/InterfacePane.h @@ -8,6 +8,7 @@ class QCheckBox; class QComboBox; class QLabel; +class QRadioButton; class QVBoxLayout; class InterfacePane final : public QWidget @@ -23,6 +24,9 @@ private: void ConnectLayout(); void LoadConfig(); void OnSaveConfig(); + void OnCursorVisibleMovement(); + void OnCursorVisibleNever(); + void OnCursorVisibleAlways(); QVBoxLayout* m_main_layout; QComboBox* m_combobox_language; @@ -43,6 +47,8 @@ private: QCheckBox* m_checkbox_enable_osd; QCheckBox* m_checkbox_show_active_title; QCheckBox* m_checkbox_pause_on_focus_lost; - QCheckBox* m_checkbox_hide_mouse; + QRadioButton* m_radio_cursor_visible_movement; + QRadioButton* m_radio_cursor_visible_never; + QRadioButton* m_radio_cursor_visible_always; QCheckBox* m_checkbox_lock_mouse; };