From ae2c9a745e43a1156405ba84ebf646882a744d71 Mon Sep 17 00:00:00 2001 From: Dmugetsu <168934208+diegolix29@users.noreply.github.com> Date: Wed, 26 Mar 2025 15:50:52 -0600 Subject: [PATCH] Gui: Adding Pause button working, full screen button and labels to buttons on main window gui (#2634) * Adding names to gui buttoms and adjusting spacing. * moving refresh button to last slot. * Changing the implementation to tooltips for hover over them - qstring to detect background color. * Fixing some themes with inverted tooltip base * Suggestions / Fixes - Pause and FullScreen Buttons * Update REUSE.toml * cleaning up * Icons stuff * clang * Buttons toggle - Cleaning code - Fixing Icons * cleaning boolean * Toggle pause and play icons and label to "Resume" when paused. * Simplifying the toggles. * New icons and final Push to review * Reuse * Icon rename, adding f9 press for pause game when no gui is on without needed of debug menu * clang + reuse * clang dosent work on this part * again Clang * Last fix for review. Light theme white resume icon fix. * Proper fix for Resume icon * New Rebase * Fixed Orientation with docking issues and cleaning boxlayout code * Adding spacer to separate actions, sizeslider on top of search bar. And adding margins * Fixed Background not showing on OLED Theme * Fixing check marks * Adding all Daniel Suggestions and fixed F9 not working with debug menu open. * Clang * reverting all OLED theme changes * Final suggestions --- REUSE.toml | 4 +- src/common/config.cpp | 12 +++ src/common/config.h | 2 + src/core/devtools/layer.cpp | 43 +++++--- src/core/devtools/layer.h | 1 + src/images/controller_icon.png | Bin 9102 -> 4142 bytes src/images/fullscreen_icon.png | Bin 0 -> 2590 bytes src/images/pause_icon.png | Bin 965 -> 1972 bytes src/images/play_icon.png | Bin 1150 -> 2875 bytes src/images/refresh_icon.png | Bin 3381 -> 0 bytes src/images/refreshlist_icon.png | Bin 0 -> 3247 bytes src/images/restart_game_icon.png | Bin 0 -> 3935 bytes src/images/settings_icon.png | Bin 2219 -> 4543 bytes src/images/stop_icon.png | Bin 658 -> 1601 bytes src/qt_gui/main_window.cpp | 168 ++++++++++++++++++++++++++++-- src/qt_gui/main_window.h | 12 +++ src/qt_gui/main_window_themes.cpp | 45 ++++---- src/qt_gui/main_window_ui.h | 32 ++++-- src/sdl_window.cpp | 20 ++++ src/sdl_window.h | 2 + src/shadps4.qrc | 74 ++++++------- 21 files changed, 324 insertions(+), 91 deletions(-) create mode 100644 src/images/fullscreen_icon.png delete mode 100644 src/images/refresh_icon.png create mode 100644 src/images/refreshlist_icon.png create mode 100644 src/images/restart_game_icon.png diff --git a/REUSE.toml b/REUSE.toml index 793990bd8..ad2bc3678 100644 --- a/REUSE.toml +++ b/REUSE.toml @@ -49,8 +49,10 @@ path = [ "src/images/pause_icon.png", "src/images/play_icon.png", "src/images/ps4_controller.png", - "src/images/refresh_icon.png", + "src/images/restart_game_icon.png", + "src/images/refreshlist_icon.png", "src/images/settings_icon.png", + "src/images/fullscreen_icon.png", "src/images/stop_icon.png", "src/images/utils_icon.png", "src/images/shadPS4.icns", diff --git a/src/common/config.cpp b/src/common/config.cpp index 16d9e5724..09236f30c 100644 --- a/src/common/config.cpp +++ b/src/common/config.cpp @@ -107,6 +107,7 @@ static bool showBackgroundImage = true; static bool isFullscreen = false; static std::string fullscreenMode = "Windowed"; static bool isHDRAllowed = false; +static bool showLabelsUnderIcons = true; // Language u32 m_language = 1; // english @@ -176,6 +177,14 @@ bool getIsFullscreen() { return isFullscreen; } +bool getShowLabelsUnderIcons() { + return showLabelsUnderIcons; +} + +bool setShowLabelsUnderIcons() { + return false; +} + std::string getFullscreenMode() { return fullscreenMode; } @@ -427,6 +436,9 @@ void setVblankDiv(u32 value) { void setIsFullscreen(bool enable) { isFullscreen = enable; } +static void setShowLabelsUnderIcons(bool enable) { + showLabelsUnderIcons = enable; +} void setFullscreenMode(std::string mode) { fullscreenMode = mode; diff --git a/src/common/config.h b/src/common/config.h index 1025e9956..3a0bf252c 100644 --- a/src/common/config.h +++ b/src/common/config.h @@ -26,6 +26,8 @@ bool GetLoadGameSizeEnabled(); std::filesystem::path GetSaveDataPath(); void setLoadGameSizeEnabled(bool enable); bool getIsFullscreen(); +bool getShowLabelsUnderIcons(); +bool setShowLabelsUnderIcons(); std::string getFullscreenMode(); bool isNeoModeConsole(); bool isDevKitConsole(); diff --git a/src/core/devtools/layer.cpp b/src/core/devtools/layer.cpp index 87fd9ffb3..94b39e801 100644 --- a/src/core/devtools/layer.cpp +++ b/src/core/devtools/layer.cpp @@ -1,6 +1,7 @@ // SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later +#include "SDL3/SDL_log.h" #include "layer.h" #include @@ -117,22 +118,6 @@ void L::DrawMenuBar() { EndMainMenuBar(); } - - if (IsKeyPressed(ImGuiKey_F9, false)) { - if (io.KeyCtrl && io.KeyAlt) { - if (!DebugState.ShouldPauseInSubmit()) { - DebugState.RequestFrameDump(dump_frame_count); - } - } - if (!io.KeyCtrl && !io.KeyAlt) { - if (isSystemPaused) { - DebugState.ResumeGuestThreads(); - } else { - DebugState.PauseGuestThreads(); - } - } - } - if (open_popup_options) { OpenPopup("GPU Tools Options"); just_opened_options = true; @@ -381,6 +366,32 @@ void L::Draw() { visibility_toggled = true; } + if (IsKeyPressed(ImGuiKey_F9, false)) { + if (io.KeyCtrl && io.KeyAlt) { + if (!DebugState.ShouldPauseInSubmit()) { + DebugState.RequestFrameDump(dump_frame_count); + } + } else { + if (DebugState.IsGuestThreadsPaused()) { + DebugState.ResumeGuestThreads(); + SDL_Log("Game resumed from Keyboard"); + show_pause_status = false; + } else { + DebugState.PauseGuestThreads(); + SDL_Log("Game paused from Keyboard"); + show_pause_status = true; + } + visibility_toggled = true; + } + } + + if (show_pause_status) { + ImVec2 pos = ImVec2(10, 10); + ImU32 color = IM_COL32(255, 255, 255, 255); + + ImGui::GetForegroundDrawList()->AddText(pos, color, "Game Paused Press F9 to Resume"); + } + if (show_simple_fps) { if (Begin("Video Info", nullptr, ImGuiWindowFlags_NoNav | ImGuiWindowFlags_NoDecoration | diff --git a/src/core/devtools/layer.h b/src/core/devtools/layer.h index 5bb53fbdb..9e949c8e9 100644 --- a/src/core/devtools/layer.h +++ b/src/core/devtools/layer.h @@ -19,6 +19,7 @@ public: static void SetupSettings(); void Draw() override; + bool show_pause_status = false; }; } // namespace Core::Devtools diff --git a/src/images/controller_icon.png b/src/images/controller_icon.png index 40c92a89bc53a9447d223c3c45286afe3b3d1673..0d5556329e55f8b1854821536a58a1ecd4d4528b 100644 GIT binary patch literal 4142 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 literal 9102 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 Vg{rUqYX$}e22WQ%mvv4FO#qyyIb{F< diff --git a/src/images/fullscreen_icon.png b/src/images/fullscreen_icon.png new file mode 100644 index 0000000000000000000000000000000000000000..719ffe4a19b842f711a4cd6be61fcbfb668b6ef1 GIT binary patch literal 2590 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 diff --git a/src/images/play_icon.png b/src/images/play_icon.png index 2815be39d8594b213fad22e68c7e8ac16872d639..d50d404b79bc4b5f5e7122e2f30cb5663ad3c4ad 100644 GIT binary patch delta 2848 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 UBOv-_9jI04>FVdQ&MBb@04J*$4FCWD delta 1112 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 TH1#3_0|SGntDnm{r-UW|_p(8M diff --git a/src/images/refreshlist_icon.png b/src/images/refreshlist_icon.png new file mode 100644 index 0000000000000000000000000000000000000000..7de6685b27e195b1517d5058f11e48b079f4ee08 GIT binary patch literal 3247 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 W9BozL&C3lMr|@+3b6Mw<&;$T-^fr(H delta 2190 zcmdn5yjpOA%0x$zdX8967srr_IdA7i=7hP59RL4U>r~v44Kq%BTcE1J$bUydq zcjes7oyFE~FP8XXh_I9NcGLZNJZLlDDf#t?=I?gK## zuPt?--Vgooe@fB324yzJ3gH9k40X&G(q?MB=VQockdSaY-Y3ZLufvdIl}jogf3wis zTsb!7+1uI}JI`_UGdrcSD;4lIg!MCDI#tTTBbjtz<#C1@-UU(zviz?8*`3Vxb7fzH zqHt^9lKoR9rUWJh_#K!~e_Uj4#id2;q1Ia?6HU%UE_rd}uh`rlix=rw*|70ME`4#t zs#|VN@RY4aJ#CV%41C&FA7i`yVisw3T~T=IO{JWl%w?Np+vB)lYPSA%-%Wnsoa7>w->kf_u5$`}uiZO*PVoLFotumnhc?+Qw)k(e^ks7)=Qif~+)XuIhZ1*R;J2PEYWeVUwd zm#nydnR^M>gzbx3@xybzD6?ss zFxckoa1Fg_=dt#Ex8I?eZ>A{wHgB9e`%<=@){*)?uGz^vF2A>Q^0(Pl#ICsB{kN`t zk+Bhd>=r&2Qfr+lT3s``FC zH}Ol@6hGz}k2C6LS&1Cvb7bG(=2uT6Q}}>F*TX@WN={Ur$sk7IeH1e<5}A*xba;S8HxKeDt_3B5;r| z?!9B|yocOQyXrC?{??8ATD-Jvdio+e(WA50zSTRexy&V5*goUqhx$E97yhZeTkZ1V zaJ!zTg4G`0?to`LXJ-qh@6*4yM>FusUu7P?Wn24rv)wLa|Bz|mZb~rav*DSo>=&$+ zC%P>9l|%3n_K!^8JtwKP{4ZR;;q-#qpS^9nR(f+vRBN%Cc6YwZUQuw(;%x0iu4f$n zyl>By_=tY$FVuK$v2fn+$%2lGF#Rs z-Wt5IPn0w2Zkgt*sJsc`TX!#E*D75R({y5g_;EJZdt2q6gsfFAS$Cl@ZsK>v7&m4o zzLVRSgJv$+?lXsR;kM;{2B}MXYP*)VU-@RGB~sbHJSXt}$`jtwvqC<)_=uhoQLO(T z(O%Tozw>SF&5x-{`aWVgs=96Lhu<}&KaOhOv`*ab#$BGba;usjO1|sf^DwG3NSkNX zOJ1GMz@}F!U32Cy2`o)o6thJA-!qQXY22w-rP;UxE_U+1ZFG`jBj$_}iJYie5)%OQ+77#5VI1vsh7D z3v*f$n^tD~#M#r1m^{og%1BYw<_cB2^KnnZYdN`3Wm}fc*!%2r+9A`zqJoWIU!M%K zncOxn;cm#ala0%^-sk;%&3c!>6mxac0~56N_bGw;xCT=WmgMLB|_)D(`~XX5-L@Fd#dlSZ0LNp1vt1^V<1pMpx5=$voBVSES+;_8w6GAjuiy9xkIlP>4 zH(s7Qb%1Nzm)r+i=4{>eUGmkkmtA=x5vw->+*jtUv#RX z-FW`>?leVz?c;YhrLJ)lIHN1mnYH$4`= zy}VfN$-bnS8ahWFE>6(=n-iz3{cGFi*Y&TY{#C9|%vkPZw8Zk`qYP6U)!R!xBzkiD zRme>E@G_KpTb0ZNi}=@?5pAE_Rbu&%o$LtgVzT5(5I?(XhM|OXv0cG@tF>>Q`sDwc z#mK5xH+8OXSW(1*vwuDt{kzTdFaDG;q^cL-U}0h`IkSIZ^H00w-`{F8FfcH9y85}W JtaD0e0ssNo0Nwxq diff --git a/src/images/stop_icon.png b/src/images/stop_icon.png index 74c615f65a54bd8380a3e67f689d86038019edc6..55b6b01c7c4c20ce586a0145ccbbfe7db38cfc43 100644 GIT binary patch literal 1601 zcmeAS@N?(olHy`uVBq!ia0y~yU`PRB4mJh`hJr^^Ll_ts7>k44ofy`glX=O&z`&C3 z=3utn7}H7EG-zA7@)cg4GcgEzO6gFMdG?rKLZ2H2TvEr zkczmsbG=uDrb@Jxhi{&Jt2IDTOM9+`rj&?KY{7#Ao%3dy@v`$aE$Ud4F-7=bqlvbb zdyul?rqe4zCd^`SlJ%P|taizD*Zr&Ce}0eb-unIL|Gn4mJ?F8Dde6+iuGHdr&Y!sd z|Nmc;`th~LP!mMM|4;6Jvi{SSIaBAKI6P^6|59It@RMhYy6>pHpTv@Q%-P`h)7zh% zf4)3)eOcPl8jpSYk(0`*?oT$JG|TVk(NC;Dr=F>8m>ZMzbI+1(kzUpIns&PK6U{%e zZq`{d&HQxsQ$tT-1F>^F+g9qQ>ZR^3d9Hf<`qZL^I}7XjYXa>iygTNc{eAnB=3Tdb zh1GxeR=t}cZ4q2{dhyG=#)nLwPRmW!U%K09OM(5#_bR_1o&OYn^QnV{__}F1p4U%? zPI7Mww9)*2a+j){-h;BAJND?`efse5{VDpVl_%ZXeR}ocMXMMOZa8hDRemb4M&bJ@ z=a+iSvJACG`)!^_{_MGFG*Vz@ZoLPQvh0i)%J9YZ^^hk>X zmc~(E_nKdC+W{pDD>IOmU(%r5e@v`@X1Z0p^Z*TsCths|_x*;4cUSN_cU_cTF4 zCDdv~X6E!SL2DidSZB>>o^_qSG6_XYuCRy z8%2&?UAL~*SU{M8U5IC>p`J8_wg1`cjSbhT`SE+rdQUPOqen2`sMCfjeivWzlhgs+L*_qspn^D<{BY;Wu3{Ssk8py*e}EL zWXhkt^)sJVon-NDQ=3&5uv&Lg;2PB%GxxoX=VLQc_y4ZH+2Hon!bNAQOyBNs4KmIO zZ<-bS+r?O5+PUYOOnQ4Acb_S%jW9ZRNqZ^J)|)Dl&HJ3EwTT#4O`UaJ`D+{d9pkq@ z+$^(1@90amoY>&9&C<#BoOoS)_}VN7iSMVDKhd-7>VFblWOldnVOWofK__}lz4&ql{Q%KVv3nWaD&hqKac zz8&^D^Cus_beH4B%ygCJ(w_>u|D5waC$?-g-+_DPJg3_YexyyipOrbSfBnK=wr0(YHj$lY4dX5TTjZ(dLkJdr6{^)O8yhh zpEIBQu1xxF>|tGTE@Ami{rJge7VGbw=jC%r^x~o1spThbt4{u8neHLO*B;GBAM z$N8^IWF+s@q*@(%z4{|-jm^VF_f&aRZMWp`EZ_6pP5jsCBS-gm-I`{y`r9k7TN6#Z z&K#}`7QgKIXA7^PSZLo;mnqAaU7Pgv$aWomj zeY-xMtnfZ_IC8T1mD!I@v=zp@k&7~uTW+&1DUR2AMnRxze{Jf4iSEBlkHwxleDDxs z#2n|P?6Gj&cTvnKevH-UY3`s@)|967h8Pb6Mw<&;$Um{2wF$ diff --git a/src/qt_gui/main_window.cpp b/src/qt_gui/main_window.cpp index 27551e997..3420e933e 100644 --- a/src/qt_gui/main_window.cpp +++ b/src/qt_gui/main_window.cpp @@ -1,6 +1,8 @@ // SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later +#include "SDL3/SDL_events.h" + #include #include #include @@ -132,23 +134,160 @@ void MainWindow::CreateActions() { m_theme_act_group->addAction(ui->setThemeOled); } +void MainWindow::PauseGame() { + SDL_Event event; + SDL_memset(&event, 0, sizeof(event)); + event.type = SDL_EVENT_TOGGLE_PAUSE; + is_paused = !is_paused; + UpdateToolbarButtons(); + SDL_PushEvent(&event); +} + +void MainWindow::toggleLabelsUnderIcons() { + bool showLabels = ui->toggleLabelsAct->isChecked(); + Config::setShowLabelsUnderIcons(); + UpdateToolbarLabels(); + if (isGameRunning) { + UpdateToolbarButtons(); + } +} + +void MainWindow::toggleFullscreen() { + SDL_Event event; + SDL_memset(&event, 0, sizeof(event)); + event.type = SDL_EVENT_TOGGLE_FULLSCREEN; + SDL_PushEvent(&event); +} + +QWidget* MainWindow::createButtonWithLabel(QPushButton* button, const QString& labelText, + bool showLabel) { + QWidget* container = new QWidget(this); + QVBoxLayout* layout = new QVBoxLayout(container); + layout->setAlignment(Qt::AlignCenter | Qt::AlignBottom); + layout->setContentsMargins(0, 0, 0, 0); + layout->addWidget(button); + + QLabel* label = nullptr; + if (showLabel && ui->toggleLabelsAct->isChecked()) { + label = new QLabel(labelText, this); + label->setAlignment(Qt::AlignCenter | Qt::AlignBottom); + layout->addWidget(label); + button->setToolTip(""); + } else { + button->setToolTip(labelText); + } + + container->setLayout(layout); + container->setProperty("buttonLabel", QVariant::fromValue(label)); + return container; +} + +QWidget* createSpacer(QWidget* parent) { + QWidget* spacer = new QWidget(parent); + spacer->setFixedWidth(15); + spacer->setFixedHeight(15); + return spacer; +} + void MainWindow::AddUiWidgets() { // add toolbar widgets QApplication::setStyle("Fusion"); - ui->toolBar->setObjectName("mw_toolbar"); - ui->toolBar->addWidget(ui->playButton); - ui->toolBar->addWidget(ui->pauseButton); - ui->toolBar->addWidget(ui->stopButton); - ui->toolBar->addWidget(ui->refreshButton); - ui->toolBar->addWidget(ui->settingsButton); - ui->toolBar->addWidget(ui->controllerButton); - ui->toolBar->addWidget(ui->keyboardButton); + + bool showLabels = ui->toggleLabelsAct->isChecked(); + ui->toolBar->clear(); + + ui->toolBar->addWidget(createSpacer(this)); + ui->toolBar->addWidget(createButtonWithLabel(ui->playButton, tr("Play"), showLabels)); + ui->toolBar->addWidget(createButtonWithLabel(ui->pauseButton, tr("Pause"), showLabels)); + ui->toolBar->addWidget(createButtonWithLabel(ui->stopButton, tr("Stop"), showLabels)); + ui->toolBar->addWidget(createButtonWithLabel(ui->restartButton, tr("Restart"), showLabels)); + ui->toolBar->addWidget(createSpacer(this)); + ui->toolBar->addWidget(createButtonWithLabel(ui->settingsButton, tr("Settings"), showLabels)); + ui->toolBar->addWidget( + createButtonWithLabel(ui->fullscreenButton, tr("Full Screen"), showLabels)); + ui->toolBar->addWidget(createSpacer(this)); + ui->toolBar->addWidget( + createButtonWithLabel(ui->controllerButton, tr("Controllers"), showLabels)); + ui->toolBar->addWidget(createButtonWithLabel(ui->keyboardButton, tr("Keyboard"), showLabels)); + ui->toolBar->addWidget(createSpacer(this)); QFrame* line = new QFrame(this); - line->setFrameShape(QFrame::StyledPanel); + line->setFrameShape(QFrame::VLine); line->setFrameShadow(QFrame::Sunken); + line->setMinimumWidth(2); ui->toolBar->addWidget(line); - ui->toolBar->addWidget(ui->sizeSliderContainer); - ui->toolBar->addWidget(ui->mw_searchbar); + ui->toolBar->addWidget(createSpacer(this)); + if (showLabels) { + QLabel* pauseButtonLabel = ui->pauseButton->parentWidget()->findChild(); + if (pauseButtonLabel) { + pauseButtonLabel->setVisible(false); + } + } + ui->toolBar->addWidget( + createButtonWithLabel(ui->refreshButton, tr("Refresh List"), showLabels)); + ui->toolBar->addWidget(createSpacer(this)); + + QBoxLayout* toolbarLayout = new QBoxLayout(QBoxLayout::TopToBottom); + toolbarLayout->setSpacing(2); + toolbarLayout->setContentsMargins(2, 2, 2, 2); + ui->sizeSliderContainer->setFixedWidth(150); + + QWidget* searchSliderContainer = new QWidget(this); + QBoxLayout* searchSliderLayout = new QBoxLayout(QBoxLayout::TopToBottom); + searchSliderLayout->setContentsMargins(0, 0, 6, 6); + searchSliderLayout->setSpacing(2); + ui->mw_searchbar->setFixedWidth(150); + + searchSliderLayout->addWidget(ui->sizeSliderContainer); + searchSliderLayout->addWidget(ui->mw_searchbar); + + searchSliderContainer->setLayout(searchSliderLayout); + + ui->toolBar->addWidget(searchSliderContainer); + + if (!showLabels) { + toolbarLayout->addWidget(searchSliderContainer); + } + + ui->playButton->setVisible(true); + ui->pauseButton->setVisible(false); +} + +void MainWindow::UpdateToolbarButtons() { + // add toolbar widgets when game is running + bool showLabels = ui->toggleLabelsAct->isChecked(); + + ui->playButton->setVisible(false); + ui->pauseButton->setVisible(true); + + if (showLabels) { + QLabel* playButtonLabel = ui->playButton->parentWidget()->findChild(); + if (playButtonLabel) + playButtonLabel->setVisible(false); + } + + if (is_paused) { + ui->pauseButton->setIcon(ui->playButton->icon()); + ui->pauseButton->setToolTip(tr("Resume")); + } else { + if (isIconBlack) { + ui->pauseButton->setIcon(QIcon(":images/pause_icon.png")); + } else { + ui->pauseButton->setIcon(RecolorIcon(QIcon(":images/pause_icon.png"), isWhite)); + } + ui->pauseButton->setToolTip(tr("Pause")); + } + + if (showLabels) { + QLabel* pauseButtonLabel = ui->pauseButton->parentWidget()->findChild(); + if (pauseButtonLabel) { + pauseButtonLabel->setText(is_paused ? tr("Resume") : tr("Pause")); + pauseButtonLabel->setVisible(true); + } + } +} + +void MainWindow::UpdateToolbarLabels() { + AddUiWidgets(); } void MainWindow::CreateDockWindows() { @@ -253,6 +392,8 @@ void MainWindow::CreateConnects() { connect(ui->refreshButton, &QPushButton::clicked, this, &MainWindow::RefreshGameTable); connect(ui->showGameListAct, &QAction::triggered, this, &MainWindow::ShowGameList); connect(this, &MainWindow::ExtractionFinished, this, &MainWindow::RefreshGameTable); + connect(ui->toggleLabelsAct, &QAction::toggled, this, &MainWindow::toggleLabelsUnderIcons); + connect(ui->fullscreenButton, &QPushButton::clicked, this, &MainWindow::toggleFullscreen); connect(ui->sizeSlider, &QSlider::valueChanged, this, [this](int value) { if (isTableList) { @@ -276,6 +417,7 @@ void MainWindow::CreateConnects() { }); connect(ui->playButton, &QPushButton::clicked, this, &MainWindow::StartGame); + connect(ui->pauseButton, &QPushButton::clicked, this, &MainWindow::PauseGame); connect(m_game_grid_frame.get(), &QTableWidget::cellDoubleClicked, this, &MainWindow::StartGame); connect(m_game_list_frame.get(), &QTableWidget::cellDoubleClicked, this, @@ -743,6 +885,8 @@ void MainWindow::StartGame() { return; } StartEmulator(path); + + UpdateToolbarButtons(); } } @@ -1217,7 +1361,9 @@ void MainWindow::SetUiIcons(bool isWhite) { ui->pauseButton->setIcon(RecolorIcon(ui->pauseButton->icon(), isWhite)); ui->stopButton->setIcon(RecolorIcon(ui->stopButton->icon(), isWhite)); ui->refreshButton->setIcon(RecolorIcon(ui->refreshButton->icon(), isWhite)); + ui->restartButton->setIcon(RecolorIcon(ui->restartButton->icon(), isWhite)); ui->settingsButton->setIcon(RecolorIcon(ui->settingsButton->icon(), isWhite)); + ui->fullscreenButton->setIcon(RecolorIcon(ui->fullscreenButton->icon(), isWhite)); ui->controllerButton->setIcon(RecolorIcon(ui->controllerButton->icon(), isWhite)); ui->keyboardButton->setIcon(RecolorIcon(ui->keyboardButton->icon(), isWhite)); ui->refreshGameListAct->setIcon(RecolorIcon(ui->refreshGameListAct->icon(), isWhite)); diff --git a/src/qt_gui/main_window.h b/src/qt_gui/main_window.h index 5ac56e44c..bcd5e53ba 100644 --- a/src/qt_gui/main_window.h +++ b/src/qt_gui/main_window.h @@ -5,6 +5,7 @@ #include #include +#include #include #include "background_music_player.h" @@ -38,6 +39,8 @@ public: void InstallDragDropPkg(std::filesystem::path file, int pkgNum, int nPkg); void InstallDirectory(); void StartGame(); + void PauseGame(); + bool showLabels; private Q_SLOTS: void ConfigureGuiFromSettings(); @@ -47,15 +50,21 @@ private Q_SLOTS: void RefreshGameTable(); void HandleResize(QResizeEvent* event); void OnLanguageChanged(const std::string& locale); + void toggleLabelsUnderIcons(); private: Ui_MainWindow* ui; void AddUiWidgets(); + void UpdateToolbarLabels(); + void UpdateToolbarButtons(); + QWidget* createButtonWithLabel(QPushButton* button, const QString& labelText, bool showLabel); void CreateActions(); + void toggleFullscreen(); void CreateRecentGameActions(); void CreateDockWindows(); void GetPhysicalDevices(); void LoadGameLists(); + #ifdef ENABLE_UPDATER void CheckUpdateMain(bool checkSave); #endif @@ -73,6 +82,9 @@ private: bool isIconBlack = false; bool isTableList = true; bool isGameRunning = false; + bool isWhite = false; + bool is_paused = false; + QActionGroup* m_icon_size_act_group = nullptr; QActionGroup* m_list_mode_act_group = nullptr; QActionGroup* m_theme_act_group = nullptr; diff --git a/src/qt_gui/main_window_themes.cpp b/src/qt_gui/main_window_themes.cpp index c5574fca9..624673cba 100644 --- a/src/qt_gui/main_window_themes.cpp +++ b/src/qt_gui/main_window_themes.cpp @@ -19,7 +19,7 @@ void WindowThemes::SetWindowTheme(Theme theme, QLineEdit* mw_searchbar) { themePalette.setColor(QPalette::WindowText, Qt::white); themePalette.setColor(QPalette::Base, QColor(20, 20, 20)); themePalette.setColor(QPalette::AlternateBase, QColor(53, 53, 53)); - themePalette.setColor(QPalette::ToolTipBase, Qt::white); + themePalette.setColor(QPalette::ToolTipBase, QColor(20, 20, 20)); themePalette.setColor(QPalette::ToolTipText, Qt::white); themePalette.setColor(QPalette::Text, Qt::white); themePalette.setColor(QPalette::Button, QColor(53, 53, 53)); @@ -37,18 +37,18 @@ void WindowThemes::SetWindowTheme(Theme theme, QLineEdit* mw_searchbar) { "border-radius: 4px; padding: 5px; }" "QLineEdit:focus {" "border: 1px solid #2A82DA; }"); - themePalette.setColor(QPalette::Window, QColor(240, 240, 240)); // Light gray - themePalette.setColor(QPalette::WindowText, Qt::black); // Black - themePalette.setColor(QPalette::Base, QColor(230, 230, 230, 80)); // Grayish - themePalette.setColor(QPalette::ToolTipBase, Qt::black); // Black - themePalette.setColor(QPalette::ToolTipText, Qt::black); // Black - themePalette.setColor(QPalette::Text, Qt::black); // Black - themePalette.setColor(QPalette::Button, QColor(240, 240, 240)); // Light gray - themePalette.setColor(QPalette::ButtonText, Qt::black); // Black - themePalette.setColor(QPalette::BrightText, Qt::red); // Red - themePalette.setColor(QPalette::Link, QColor(42, 130, 218)); // Blue - themePalette.setColor(QPalette::Highlight, QColor(42, 130, 218)); // Blue - themePalette.setColor(QPalette::HighlightedText, Qt::white); // White + themePalette.setColor(QPalette::Window, QColor(240, 240, 240)); // Light gray + themePalette.setColor(QPalette::WindowText, Qt::black); // Black + themePalette.setColor(QPalette::Base, QColor(230, 230, 230, 80)); // Grayish + themePalette.setColor(QPalette::ToolTipBase, QColor(230, 230, 230, 80)); // Grayish + themePalette.setColor(QPalette::ToolTipText, Qt::black); // Black + themePalette.setColor(QPalette::Text, Qt::black); // Black + themePalette.setColor(QPalette::Button, QColor(240, 240, 240)); // Light gray + themePalette.setColor(QPalette::ButtonText, Qt::black); // Black + themePalette.setColor(QPalette::BrightText, Qt::red); // Red + themePalette.setColor(QPalette::Link, QColor(42, 130, 218)); // Blue + themePalette.setColor(QPalette::Highlight, QColor(42, 130, 218)); // Blue + themePalette.setColor(QPalette::HighlightedText, Qt::white); // White qApp->setPalette(themePalette); break; case Theme::Green: @@ -62,8 +62,9 @@ void WindowThemes::SetWindowTheme(Theme theme, QLineEdit* mw_searchbar) { themePalette.setColor(QPalette::WindowText, Qt::white); // White text themePalette.setColor(QPalette::Base, QColor(25, 40, 25)); // Darker green base themePalette.setColor(QPalette::AlternateBase, - QColor(53, 69, 53)); // Dark green alternate base - themePalette.setColor(QPalette::ToolTipBase, Qt::white); // White tooltip background + QColor(53, 69, 53)); // Dark green alternate base + themePalette.setColor(QPalette::ToolTipBase, + QColor(25, 40, 25)); // White tooltip background themePalette.setColor(QPalette::ToolTipText, Qt::white); // White tooltip text themePalette.setColor(QPalette::Text, Qt::white); // White text themePalette.setColor(QPalette::Button, QColor(53, 69, 53)); // Dark green button @@ -85,8 +86,9 @@ void WindowThemes::SetWindowTheme(Theme theme, QLineEdit* mw_searchbar) { themePalette.setColor(QPalette::WindowText, Qt::white); // White text themePalette.setColor(QPalette::Base, QColor(20, 40, 60)); // Darker blue base themePalette.setColor(QPalette::AlternateBase, - QColor(40, 60, 90)); // Dark blue alternate base - themePalette.setColor(QPalette::ToolTipBase, Qt::white); // White tooltip background + QColor(40, 60, 90)); // Dark blue alternate base + themePalette.setColor(QPalette::ToolTipBase, + QColor(20, 40, 60)); // White tooltip background themePalette.setColor(QPalette::ToolTipText, Qt::white); // White tooltip text themePalette.setColor(QPalette::Text, Qt::white); // White text themePalette.setColor(QPalette::Button, QColor(40, 60, 90)); // Dark blue button @@ -109,8 +111,9 @@ void WindowThemes::SetWindowTheme(Theme theme, QLineEdit* mw_searchbar) { themePalette.setColor(QPalette::WindowText, Qt::white); // White text themePalette.setColor(QPalette::Base, QColor(80, 30, 90)); // Darker violet base themePalette.setColor(QPalette::AlternateBase, - QColor(100, 50, 120)); // Violet alternate base - themePalette.setColor(QPalette::ToolTipBase, Qt::white); // White tooltip background + QColor(100, 50, 120)); // Violet alternate base + themePalette.setColor(QPalette::ToolTipBase, + QColor(80, 30, 90)); // White tooltip background themePalette.setColor(QPalette::ToolTipText, Qt::white); // White tooltip text themePalette.setColor(QPalette::Text, Qt::white); // White text themePalette.setColor(QPalette::Button, QColor(100, 50, 120)); // Violet button @@ -133,7 +136,7 @@ void WindowThemes::SetWindowTheme(Theme theme, QLineEdit* mw_searchbar) { themePalette.setColor(QPalette::WindowText, QColor(249, 245, 215)); themePalette.setColor(QPalette::Base, QColor(29, 32, 33)); themePalette.setColor(QPalette::AlternateBase, QColor(50, 48, 47)); - themePalette.setColor(QPalette::ToolTipBase, QColor(249, 245, 215)); + themePalette.setColor(QPalette::ToolTipBase, QColor(29, 32, 33)); themePalette.setColor(QPalette::ToolTipText, QColor(249, 245, 215)); themePalette.setColor(QPalette::Text, QColor(249, 245, 215)); themePalette.setColor(QPalette::Button, QColor(40, 40, 40)); @@ -155,7 +158,7 @@ void WindowThemes::SetWindowTheme(Theme theme, QLineEdit* mw_searchbar) { themePalette.setColor(QPalette::WindowText, QColor(192, 202, 245)); themePalette.setColor(QPalette::Base, QColor(25, 28, 39)); themePalette.setColor(QPalette::AlternateBase, QColor(36, 40, 59)); - themePalette.setColor(QPalette::ToolTipBase, QColor(192, 202, 245)); + themePalette.setColor(QPalette::ToolTipBase, QColor(25, 28, 39)); themePalette.setColor(QPalette::ToolTipText, QColor(192, 202, 245)); themePalette.setColor(QPalette::Text, QColor(192, 202, 245)); themePalette.setColor(QPalette::Button, QColor(30, 30, 41)); diff --git a/src/qt_gui/main_window_ui.h b/src/qt_gui/main_window_ui.h index 246c2afd6..c4f47b636 100644 --- a/src/qt_gui/main_window_ui.h +++ b/src/qt_gui/main_window_ui.h @@ -20,6 +20,7 @@ public: QAction* setIconSizeSmallAct; QAction* setIconSizeMediumAct; QAction* setIconSizeLargeAct; + QAction* toggleLabelsAct; QAction* setlistModeListAct; QAction* setlistModeGridAct; QAction* setlistElfAct; @@ -50,6 +51,8 @@ public: QPushButton* settingsButton; QPushButton* controllerButton; QPushButton* keyboardButton; + QPushButton* fullscreenButton; + QPushButton* restartButton; QWidget* sizeSliderContainer; QHBoxLayout* sizeSliderContainer_layout; @@ -104,7 +107,15 @@ public: showGameListAct->setCheckable(true); refreshGameListAct = new QAction(MainWindow); refreshGameListAct->setObjectName("refreshGameListAct"); - refreshGameListAct->setIcon(QIcon(":images/refresh_icon.png")); + refreshGameListAct->setIcon(QIcon(":images/refreshlist_icon.png")); + + toggleLabelsAct = new QAction(MainWindow); + toggleLabelsAct->setObjectName("toggleLabelsAct"); + toggleLabelsAct->setText( + QCoreApplication::translate("MainWindow", "Show Labels Under Icons")); + toggleLabelsAct->setCheckable(true); + toggleLabelsAct->setChecked(Config::getShowLabelsUnderIcons()); + setIconSizeTinyAct = new QAction(MainWindow); setIconSizeTinyAct->setObjectName("setIconSizeTinyAct"); setIconSizeTinyAct->setCheckable(true); @@ -210,20 +221,28 @@ public: stopButton->setIconSize(QSize(40, 40)); refreshButton = new QPushButton(centralWidget); refreshButton->setFlat(true); - refreshButton->setIcon(QIcon(":images/refresh_icon.png")); - refreshButton->setIconSize(QSize(32, 32)); + refreshButton->setIcon(QIcon(":images/refreshlist_icon.png")); + refreshButton->setIconSize(QSize(40, 40)); + fullscreenButton = new QPushButton(centralWidget); + fullscreenButton->setFlat(true); + fullscreenButton->setIcon(QIcon(":images/fullscreen_icon.png")); + fullscreenButton->setIconSize(QSize(38, 38)); settingsButton = new QPushButton(centralWidget); settingsButton->setFlat(true); settingsButton->setIcon(QIcon(":images/settings_icon.png")); - settingsButton->setIconSize(QSize(44, 44)); + settingsButton->setIconSize(QSize(40, 40)); controllerButton = new QPushButton(centralWidget); controllerButton->setFlat(true); controllerButton->setIcon(QIcon(":images/controller_icon.png")); - controllerButton->setIconSize(QSize(40, 40)); + controllerButton->setIconSize(QSize(55, 48)); keyboardButton = new QPushButton(centralWidget); keyboardButton->setFlat(true); keyboardButton->setIcon(QIcon(":images/keyboard_icon.png")); - keyboardButton->setIconSize(QSize(48, 44)); + keyboardButton->setIconSize(QSize(50, 50)); + restartButton = new QPushButton(centralWidget); + restartButton->setFlat(true); + restartButton->setIcon(QIcon(":images/restart_game_icon.png")); + restartButton->setIconSize(QSize(40, 40)); sizeSliderContainer = new QWidget(centralWidget); sizeSliderContainer->setObjectName("sizeSliderContainer"); @@ -304,6 +323,7 @@ public: menuView->addAction(refreshGameListAct); menuView->addAction(menuGame_List_Mode->menuAction()); menuView->addAction(menuGame_List_Icons->menuAction()); + menuView->addAction(toggleLabelsAct); menuView->addAction(menuThemes->menuAction()); menuThemes->addAction(setThemeDark); menuThemes->addAction(setThemeLight); diff --git a/src/sdl_window.cpp b/src/sdl_window.cpp index 80d196147..fcdde7240 100644 --- a/src/sdl_window.cpp +++ b/src/sdl_window.cpp @@ -11,6 +11,7 @@ #include "common/config.h" #include "common/elf_info.h" #include "common/version.h" +#include "core/debug_state.h" #include "core/libraries/kernel/time.h" #include "core/libraries/pad/pad.h" #include "imgui/renderer/imgui_core.h" @@ -396,6 +397,25 @@ void WindowSDL::WaitEvent() { case SDL_EVENT_QUIT: is_open = false; break; + case SDL_EVENT_TOGGLE_FULLSCREEN: { + if (SDL_GetWindowFlags(window) & SDL_WINDOW_FULLSCREEN) { + SDL_SetWindowFullscreen(window, 0); + } else { + SDL_SetWindowFullscreen(window, SDL_WINDOW_FULLSCREEN); + } + break; + } + case SDL_EVENT_TOGGLE_PAUSE: + SDL_Log("Received SDL_EVENT_TOGGLE_PAUSE"); + + if (DebugState.IsGuestThreadsPaused()) { + SDL_Log("Game Resumed"); + DebugState.ResumeGuestThreads(); + } else { + SDL_Log("Game Paused"); + DebugState.PauseGuestThreads(); + } + break; default: break; } diff --git a/src/sdl_window.h b/src/sdl_window.h index 03ba0797b..48a9be58c 100644 --- a/src/sdl_window.h +++ b/src/sdl_window.h @@ -7,6 +7,8 @@ #include "core/libraries/pad/pad.h" #include "input/controller.h" #include "string" +#define SDL_EVENT_TOGGLE_FULLSCREEN (SDL_EVENT_USER + 1) +#define SDL_EVENT_TOGGLE_PAUSE (SDL_EVENT_USER + 2) struct SDL_Window; struct SDL_Gamepad; diff --git a/src/shadps4.qrc b/src/shadps4.qrc index 340756f5c..83dea01c4 100644 --- a/src/shadps4.qrc +++ b/src/shadps4.qrc @@ -1,38 +1,40 @@ - - images/shadps4.ico - images/about_icon.png - images/dump_icon.png - images/play_icon.png - images/pause_icon.png - images/stop_icon.png - images/utils_icon.png - images/file_icon.png - images/trophy_icon.png - images/folder_icon.png - images/themes_icon.png - images/iconsize_icon.png - images/list_icon.png - images/grid_icon.png - images/exit_icon.png - images/settings_icon.png - images/controller_icon.png - images/refresh_icon.png - images/update_icon.png - images/list_mode_icon.png - images/flag_jp.png - images/flag_eu.png - images/flag_unk.png - images/flag_us.png - images/flag_world.png - images/flag_china.png - images/github.png - images/discord.png - images/ko-fi.png - images/youtube.png - images/website.png - images/ps4_controller.png - images/keyboard_icon.png - images/KBM.png - + + images/shadps4.ico + images/about_icon.png + images/dump_icon.png + images/play_icon.png + images/pause_icon.png + images/stop_icon.png + images/utils_icon.png + images/file_icon.png + images/folder_icon.png + images/themes_icon.png + images/iconsize_icon.png + images/list_icon.png + images/grid_icon.png + images/exit_icon.png + images/settings_icon.png + images/controller_icon.png + images/restart_game_icon.png + images/update_icon.png + images/list_mode_icon.png + images/flag_jp.png + images/flag_eu.png + images/flag_unk.png + images/flag_us.png + images/flag_world.png + images/flag_china.png + images/github.png + images/discord.png + images/ko-fi.png + images/youtube.png + images/website.png + images/ps4_controller.png + images/keyboard_icon.png + images/KBM.png + images/fullscreen_icon.png + images/refreshlist_icon.png + images/trophy_icon.png +