Compare commits

...

4 Commits

Author SHA1 Message Date
cristian64
068ab1df2e DolphinQt: Use vertical tabs in Hotkey Settings dialog.
At this time, only the **Hotkey Settings** dialog will use vertical
tabs. This dialog happens to feature many tabs that, when horizontal
tabs are used, require horizontal scroll. Also, with these many tabs,
it can make good use of the vertical space that the vertical tabs
require.

| Before | After |
| ------ | ----- |
| <img width="918" height="679" alt="[Dolphin Emulator] Hotkey Settings dialog" title="[Dolphin Emulator] Hotkey Settings dialog" src="https://github.com/user-attachments/assets/7c9d9964-f36b-4872-ab52-6ebbe974a8ca" /> | <img width="1041" height="653" alt="[Dolphin Emulator] Hotkey Settings dialog with vertical tabs" title="[Dolphin Emulator] Hotkey Settings dialog with vertical tabs" src="https://github.com/user-attachments/assets/c6d875f9-f52d-4564-9d68-0555521a77fa" /> |
2025-08-31 11:06:54 +01:00
cristian64
42eea4073e DolphinQt: Add tab widget with vertical tabs.
The new `VerticalTabsTabWidget` class extends `QTabWidget`, with a
custom tab bar that paint tabs with a _west_ orientation and
_horizontal_ text labels.
2025-08-31 11:06:54 +01:00
Tilka
033a0540f7
Merge pull request #13899 from SuperSamus/patch-cheats-osd
PatchEngine: OSD message showing number of enabled patches and cheats
2025-08-31 00:27:23 +01:00
Martino Fontana
64a20c74fc PatchEngine: OSD message showing number of enabled patches and cheats 2025-08-30 16:51:51 +02:00
10 changed files with 143 additions and 2 deletions

View File

@ -174,6 +174,15 @@ void AddCode(ARCode code)
}
}
size_t CountEnabledCodes()
{
if (!Config::AreCheatsEnabled())
return 0;
std::lock_guard guard(s_lock);
return s_active_codes.size();
}
void LoadAndApplyCodes(const Common::IniFile& global_ini, const Common::IniFile& local_ini,
const std::string& game_id, u16 revision)
{

View File

@ -50,6 +50,7 @@ void SetSyncedCodesAsActive();
void UpdateSyncedCodes(std::span<const ARCode> codes);
std::vector<ARCode> ApplyAndReturnCodes(std::span<const ARCode> codes);
void AddCode(ARCode new_code);
size_t CountEnabledCodes();
void LoadAndApplyCodes(const Common::IniFile& global_ini, const Common::IniFile& local_ini,
const std::string& game_id, u16 revision);

View File

@ -50,6 +50,15 @@ static std::vector<GeckoCode> s_active_codes;
static std::vector<GeckoCode> s_synced_codes;
static std::mutex s_active_codes_lock;
size_t CountEnabledCodes()
{
if (!Config::AreCheatsEnabled())
return 0;
std::lock_guard guard(s_active_codes_lock);
return s_active_codes.size();
}
void SetActiveCodes(std::span<const GeckoCode> gcodes, const std::string& game_id, u16 revision)
{
std::lock_guard lk(s_active_codes_lock);

View File

@ -60,6 +60,7 @@ constexpr u32 HLE_TRAMPOLINE_ADDRESS = INSTALLER_END_ADDRESS - 4;
// preserve the emulation performance.
constexpr u32 MAGIC_GAMEID = 0xD01F1BAD;
size_t CountEnabledCodes();
void SetActiveCodes(std::span<const GeckoCode> gcodes, const std::string& game_id, u16 revision);
void SetSyncedCodesAsActive();
void UpdateSyncedCodes(std::span<const GeckoCode> gcodes);

View File

@ -35,6 +35,7 @@
#include "Core/PowerPC/MMU.h"
#include "Core/PowerPC/PowerPC.h"
#include "Core/System.h"
#include "VideoCommon/OnScreenDisplay.h"
namespace PatchEngine
{
@ -200,6 +201,18 @@ void LoadPatches()
ActionReplay::LoadAndApplyCodes(globalIni, localIni, sconfig.GetGameID(),
sconfig.GetRevision());
}
const size_t enabled_patch_count =
std::ranges::count_if(s_on_frame, [](Patch patch) { return patch.enabled; });
if (enabled_patch_count > 0)
{
OSD::AddMessage(fmt::format("{} game patch(es) enabled", enabled_patch_count),
OSD::Duration::NORMAL);
}
const size_t enabled_cheat_count = ActionReplay::CountEnabledCodes() + Gecko::CountEnabledCodes();
if (enabled_cheat_count > 0)
OSD::AddMessage(fmt::format("{} cheat(s) enabled", enabled_cheat_count), OSD::Duration::NORMAL);
}
static void ApplyPatches(const Core::CPUThreadGuard& guard, const std::vector<Patch>& patches)

View File

@ -334,6 +334,8 @@ add_executable(dolphin-emu
QtUtils/SignalBlocking.h
QtUtils/UTF8CodePointCountValidator.cpp
QtUtils/UTF8CodePointCountValidator.h
QtUtils/VerticalTabsTabWidget.cpp
QtUtils/VerticalTabsTabWidget.h
QtUtils/WindowActivationEventFilter.cpp
QtUtils/WindowActivationEventFilter.h
QtUtils/WrapInScrollArea.cpp

View File

@ -51,6 +51,7 @@
#include "DolphinQt/QtUtils/ModalMessageBox.h"
#include "DolphinQt/QtUtils/NonDefaultQPushButton.h"
#include "DolphinQt/QtUtils/QtUtils.h"
#include "DolphinQt/QtUtils/VerticalTabsTabWidget.h"
#include "DolphinQt/QtUtils/WindowActivationEventFilter.h"
#include "DolphinQt/QtUtils/WrapInScrollArea.h"
#include "DolphinQt/Settings.h"
@ -61,7 +62,7 @@
#include "InputCommon/InputConfig.h"
MappingWindow::MappingWindow(QWidget* parent, Type type, int port_num)
: QDialog(parent), m_port(port_num)
: QDialog(parent), m_mapping_type(type), m_port(port_num)
{
setWindowTitle(tr("Port %1").arg(port_num + 1));
@ -179,7 +180,14 @@ void MappingWindow::CreateMainLayout()
{
m_main_layout = new QVBoxLayout();
m_config_layout = new QHBoxLayout();
m_tab_widget = new QTabWidget();
if (m_mapping_type == MappingWindow::Type::MAPPING_HOTKEYS)
{
m_tab_widget = new QtUtils::VerticalTabsTabWidget;
}
else
{
m_tab_widget = new QTabWidget;
}
m_button_box = new QDialogButtonBox(QDialogButtonBox::Close);
m_tab_widget->setTabBarAutoHide(true);

View File

@ -204,6 +204,7 @@
<ClCompile Include="QtUtils\QtUtils.cpp" />
<ClCompile Include="QtUtils\SetWindowDecorations.cpp" />
<ClCompile Include="QtUtils\UTF8CodePointCountValidator.cpp" />
<ClCompile Include="QtUtils\VerticalTabsTabWidget.cpp" />
<ClCompile Include="QtUtils\WindowActivationEventFilter.cpp" />
<ClCompile Include="QtUtils\WrapInScrollArea.cpp" />
<ClCompile Include="RenderWidget.cpp" />
@ -265,6 +266,7 @@
<ClInclude Include="QtUtils\QueueOnObject.h" />
<ClInclude Include="QtUtils\RunOnObject.h" />
<ClInclude Include="QtUtils\SignalBlocking.h" />
<ClInclude Include="QtUtils\VerticalTabsTabWidget.h" />
<ClInclude Include="QtUtils\WrapInScrollArea.h" />
<ClInclude Include="ResourcePackManager.h" />
<ClInclude Include="Resources.h" />

View File

@ -0,0 +1,77 @@
// Copyright 2025 Dolphin Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "DolphinQt/QtUtils/VerticalTabsTabWidget.h"
#include <QStyleOptionTab>
#include <QStylePainter>
namespace
{
class HorizontalTabBar : public QTabBar
{
public:
explicit HorizontalTabBar(QWidget* const parent = nullptr) : QTabBar(parent)
{
setUsesScrollButtons(false);
}
protected:
QSize tabSizeHint(const int index) const override
{
return QTabBar::tabSizeHint(index).transposed();
}
void paintEvent(QPaintEvent* const event) override
{
QStylePainter painter(this);
const int current_tab_index{currentIndex()};
const int tab_count{count()};
for (int i{0}; i < tab_count; ++i)
{
if (i != current_tab_index)
PaintTab(painter, i);
}
// Current tab is painted last as, depending on the [system] style, it is possible that the
// decoration is required to occlude the adjacent tab underneath.
PaintTab(painter, current_tab_index);
}
private:
void PaintTab(QStylePainter& painter, const int tab_index)
{
painter.save();
QStyleOptionTab option;
initStyleOption(&option, tab_index);
painter.drawControl(QStyle::CE_TabBarTabShape, option);
const QSize size{option.rect.size().transposed()};
QRect rect(QPoint(), size);
rect.moveCenter(option.rect.center());
option.rect = rect;
const QPoint center{tabRect(tab_index).center()};
painter.translate(center);
painter.rotate(90.0);
painter.translate(-center);
painter.drawControl(QStyle::CE_TabBarTabLabel, option);
painter.restore();
}
};
} // namespace
namespace QtUtils
{
VerticalTabsTabWidget::VerticalTabsTabWidget(QWidget* const parent) : QTabWidget(parent)
{
setTabBar(new HorizontalTabBar);
setTabPosition(QTabWidget::TabPosition::West);
}
} // namespace QtUtils

View File

@ -0,0 +1,19 @@
// Copyright 2025 Dolphin Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include <QTabWidget>
#include <QWidget>
namespace QtUtils
{
// A tab widget where tabs are drawn to the left of the pages with horizontal text.
class VerticalTabsTabWidget : public QTabWidget
{
public:
explicit VerticalTabsTabWidget(QWidget* parent = nullptr);
};
} // namespace QtUtils