Qt: Implement per-game controller configuration
This commit is contained in:
parent
9e3507e0f4
commit
bda6869084
|
@ -10,7 +10,6 @@ class LayeredSettingsInterface final : public SettingsInterface
|
||||||
public:
|
public:
|
||||||
enum Layer : u32
|
enum Layer : u32
|
||||||
{
|
{
|
||||||
LAYER_CMDLINE,
|
|
||||||
LAYER_GAME,
|
LAYER_GAME,
|
||||||
LAYER_INPUT,
|
LAYER_INPUT,
|
||||||
LAYER_BASE,
|
LAYER_BASE,
|
||||||
|
@ -66,7 +65,7 @@ public:
|
||||||
using SettingsInterface::GetUIntValue;
|
using SettingsInterface::GetUIntValue;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static constexpr Layer FIRST_LAYER = LAYER_CMDLINE;
|
static constexpr Layer FIRST_LAYER = LAYER_GAME;
|
||||||
static constexpr Layer LAST_LAYER = LAYER_BASE;
|
static constexpr Layer LAST_LAYER = LAYER_BASE;
|
||||||
|
|
||||||
std::array<SettingsInterface*, NUM_LAYERS> m_layers{};
|
std::array<SettingsInterface*, NUM_LAYERS> m_layers{};
|
||||||
|
|
|
@ -10,7 +10,7 @@ class MemorySettingsInterface final : public SettingsInterface
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
MemorySettingsInterface();
|
MemorySettingsInterface();
|
||||||
~MemorySettingsInterface();
|
~MemorySettingsInterface() override;
|
||||||
|
|
||||||
bool Save(Error* error = nullptr) override;
|
bool Save(Error* error = nullptr) override;
|
||||||
|
|
||||||
|
|
|
@ -2798,7 +2798,7 @@ void FullscreenUI::DoCopyGameSettings()
|
||||||
return;
|
return;
|
||||||
|
|
||||||
Settings temp_settings;
|
Settings temp_settings;
|
||||||
temp_settings.Load(*GetEditingSettingsInterface(false));
|
temp_settings.Load(*GetEditingSettingsInterface(false), *GetEditingSettingsInterface(false));
|
||||||
temp_settings.Save(*s_game_settings_interface, true);
|
temp_settings.Save(*s_game_settings_interface, true);
|
||||||
SetSettingsChanged(s_game_settings_interface.get());
|
SetSettingsChanged(s_game_settings_interface.get());
|
||||||
|
|
||||||
|
@ -3652,20 +3652,20 @@ void FullscreenUI::DrawControllerSettingsPage()
|
||||||
if (IsEditingGameSettings(bsi))
|
if (IsEditingGameSettings(bsi))
|
||||||
{
|
{
|
||||||
if (DrawToggleSetting(bsi, FSUI_ICONSTR(ICON_FA_COG, "Per-Game Configuration"),
|
if (DrawToggleSetting(bsi, FSUI_ICONSTR(ICON_FA_COG, "Per-Game Configuration"),
|
||||||
FSUI_CSTR("Uses game-specific settings for controllers for this game."), "Pad",
|
FSUI_CSTR("Uses game-specific settings for controllers for this game."), "ControllerPorts",
|
||||||
"UseGameSettingsForController", false, IsEditingGameSettings(bsi), false))
|
"UseGameSettingsForController", false, IsEditingGameSettings(bsi), false))
|
||||||
{
|
{
|
||||||
// did we just enable per-game for the first time?
|
// did we just enable per-game for the first time?
|
||||||
if (bsi->GetBoolValue("Pad", "UseGameSettingsForController", false) &&
|
if (bsi->GetBoolValue("ControllerPorts", "UseGameSettingsForController", false) &&
|
||||||
!bsi->GetBoolValue("Pad", "GameSettingsInitialized", false))
|
!bsi->GetBoolValue("ControllerPorts", "GameSettingsInitialized", false))
|
||||||
{
|
{
|
||||||
bsi->SetBoolValue("Pad", "GameSettingsInitialized", true);
|
bsi->SetBoolValue("ControllerPorts", "GameSettingsInitialized", true);
|
||||||
CopyGlobalControllerSettingsToGame();
|
CopyGlobalControllerSettingsToGame();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (IsEditingGameSettings(bsi) && !bsi->GetBoolValue("Pad", "UseGameSettingsForController", false))
|
if (IsEditingGameSettings(bsi) && !bsi->GetBoolValue("ControllerPorts", "UseGameSettingsForController", false))
|
||||||
{
|
{
|
||||||
// nothing to edit..
|
// nothing to edit..
|
||||||
EndMenuButtons();
|
EndMenuButtons();
|
||||||
|
|
|
@ -134,7 +134,7 @@ void Settings::UpdateOverclockActive()
|
||||||
cpu_overclock_active = (cpu_overclock_enable && (cpu_overclock_numerator != 1 || cpu_overclock_denominator != 1));
|
cpu_overclock_active = (cpu_overclock_enable && (cpu_overclock_numerator != 1 || cpu_overclock_denominator != 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
void Settings::Load(SettingsInterface& si)
|
void Settings::Load(SettingsInterface& si, SettingsInterface& controller_si)
|
||||||
{
|
{
|
||||||
region =
|
region =
|
||||||
ParseConsoleRegionName(
|
ParseConsoleRegionName(
|
||||||
|
@ -364,7 +364,8 @@ void Settings::Load(SettingsInterface& si)
|
||||||
|
|
||||||
multitap_mode =
|
multitap_mode =
|
||||||
ParseMultitapModeName(
|
ParseMultitapModeName(
|
||||||
si.GetStringValue("ControllerPorts", "MultitapMode", GetMultitapModeName(DEFAULT_MULTITAP_MODE)).c_str())
|
controller_si.GetStringValue("ControllerPorts", "MultitapMode", GetMultitapModeName(DEFAULT_MULTITAP_MODE))
|
||||||
|
.c_str())
|
||||||
.value_or(DEFAULT_MULTITAP_MODE);
|
.value_or(DEFAULT_MULTITAP_MODE);
|
||||||
|
|
||||||
const std::array<bool, 2> mtap_enabled = {{IsPort1MultitapEnabled(), IsPort2MultitapEnabled()}};
|
const std::array<bool, 2> mtap_enabled = {{IsPort1MultitapEnabled(), IsPort2MultitapEnabled()}};
|
||||||
|
@ -379,7 +380,7 @@ void Settings::Load(SettingsInterface& si)
|
||||||
}
|
}
|
||||||
|
|
||||||
const ControllerType default_type = (i == 0) ? DEFAULT_CONTROLLER_1_TYPE : DEFAULT_CONTROLLER_2_TYPE;
|
const ControllerType default_type = (i == 0) ? DEFAULT_CONTROLLER_1_TYPE : DEFAULT_CONTROLLER_2_TYPE;
|
||||||
const Controller::ControllerInfo* cinfo = Controller::GetControllerInfo(si.GetTinyStringValue(
|
const Controller::ControllerInfo* cinfo = Controller::GetControllerInfo(controller_si.GetTinyStringValue(
|
||||||
Controller::GetSettingsSection(i).c_str(), "Type", Controller::GetControllerInfo(default_type)->name));
|
Controller::GetSettingsSection(i).c_str(), "Type", Controller::GetControllerInfo(default_type)->name));
|
||||||
controller_types[i] = cinfo ? cinfo->type : default_type;
|
controller_types[i] = cinfo ? cinfo->type : default_type;
|
||||||
}
|
}
|
||||||
|
|
|
@ -354,7 +354,7 @@ struct Settings
|
||||||
DEFAULT_VRAM_WRITE_DUMP_HEIGHT_THRESHOLD = 128,
|
DEFAULT_VRAM_WRITE_DUMP_HEIGHT_THRESHOLD = 128,
|
||||||
};
|
};
|
||||||
|
|
||||||
void Load(SettingsInterface& si);
|
void Load(SettingsInterface& si, SettingsInterface& controller_si);
|
||||||
void Save(SettingsInterface& si, bool ignore_base) const;
|
void Save(SettingsInterface& si, bool ignore_base) const;
|
||||||
static void Clear(SettingsInterface& si);
|
static void Clear(SettingsInterface& si);
|
||||||
|
|
||||||
|
|
|
@ -54,6 +54,7 @@
|
||||||
#include "common/dynamic_library.h"
|
#include "common/dynamic_library.h"
|
||||||
#include "common/error.h"
|
#include "common/error.h"
|
||||||
#include "common/file_system.h"
|
#include "common/file_system.h"
|
||||||
|
#include "common/layered_settings_interface.h"
|
||||||
#include "common/log.h"
|
#include "common/log.h"
|
||||||
#include "common/path.h"
|
#include "common/path.h"
|
||||||
#include "common/string_util.h"
|
#include "common/string_util.h"
|
||||||
|
@ -136,7 +137,8 @@ struct MemorySaveState
|
||||||
static void CheckCacheLineSize();
|
static void CheckCacheLineSize();
|
||||||
static void LogStartupInformation();
|
static void LogStartupInformation();
|
||||||
|
|
||||||
static void LoadInputBindings(SettingsInterface& si, std::unique_lock<std::mutex>& lock);
|
static LayeredSettingsInterface GetControllerSettingsLayers(std::unique_lock<std::mutex>& lock);
|
||||||
|
static LayeredSettingsInterface GetHotkeySettingsLayer(std::unique_lock<std::mutex>& lock);
|
||||||
|
|
||||||
static std::string GetExecutableNameForImage(IsoReader& iso, bool strip_subdirectories);
|
static std::string GetExecutableNameForImage(IsoReader& iso, bool strip_subdirectories);
|
||||||
static bool ReadExecutableFromImage(IsoReader& iso, std::string* out_executable_name,
|
static bool ReadExecutableFromImage(IsoReader& iso, std::string* out_executable_name,
|
||||||
|
@ -1202,12 +1204,14 @@ void System::LoadSettings(bool display_osd_messages)
|
||||||
{
|
{
|
||||||
std::unique_lock<std::mutex> lock = Host::GetSettingsLock();
|
std::unique_lock<std::mutex> lock = Host::GetSettingsLock();
|
||||||
SettingsInterface& si = *Host::GetSettingsInterface();
|
SettingsInterface& si = *Host::GetSettingsInterface();
|
||||||
g_settings.Load(si);
|
LayeredSettingsInterface controller_si = GetControllerSettingsLayers(lock);
|
||||||
|
LayeredSettingsInterface hotkey_si = GetHotkeySettingsLayer(lock);
|
||||||
|
g_settings.Load(si, controller_si);
|
||||||
g_settings.UpdateLogSettings();
|
g_settings.UpdateLogSettings();
|
||||||
|
|
||||||
Host::LoadSettings(si, lock);
|
Host::LoadSettings(si, lock);
|
||||||
InputManager::ReloadSources(si, lock);
|
InputManager::ReloadSources(controller_si, lock);
|
||||||
LoadInputBindings(si, lock);
|
InputManager::ReloadBindings(controller_si, hotkey_si);
|
||||||
WarnAboutUnsafeSettings();
|
WarnAboutUnsafeSettings();
|
||||||
|
|
||||||
// apply compatibility settings
|
// apply compatibility settings
|
||||||
|
@ -1224,12 +1228,15 @@ void System::LoadSettings(bool display_osd_messages)
|
||||||
void System::ReloadInputSources()
|
void System::ReloadInputSources()
|
||||||
{
|
{
|
||||||
std::unique_lock<std::mutex> lock = Host::GetSettingsLock();
|
std::unique_lock<std::mutex> lock = Host::GetSettingsLock();
|
||||||
SettingsInterface* si = Host::GetSettingsInterface();
|
LayeredSettingsInterface controller_si = GetControllerSettingsLayers(lock);
|
||||||
InputManager::ReloadSources(*si, lock);
|
InputManager::ReloadSources(controller_si, lock);
|
||||||
|
|
||||||
// skip loading bindings if we're not running, since it'll get done on startup anyway
|
// skip loading bindings if we're not running, since it'll get done on startup anyway
|
||||||
if (IsValid())
|
if (IsValid())
|
||||||
LoadInputBindings(*si, lock);
|
{
|
||||||
|
LayeredSettingsInterface hotkey_si = GetHotkeySettingsLayer(lock);
|
||||||
|
InputManager::ReloadBindings(controller_si, hotkey_si);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void System::ReloadInputBindings()
|
void System::ReloadInputBindings()
|
||||||
|
@ -1239,37 +1246,43 @@ void System::ReloadInputBindings()
|
||||||
return;
|
return;
|
||||||
|
|
||||||
std::unique_lock<std::mutex> lock = Host::GetSettingsLock();
|
std::unique_lock<std::mutex> lock = Host::GetSettingsLock();
|
||||||
SettingsInterface* si = Host::GetSettingsInterface();
|
LayeredSettingsInterface controller_si = GetControllerSettingsLayers(lock);
|
||||||
LoadInputBindings(*si, lock);
|
LayeredSettingsInterface hotkey_si = GetHotkeySettingsLayer(lock);
|
||||||
|
InputManager::ReloadBindings(controller_si, hotkey_si);
|
||||||
}
|
}
|
||||||
|
|
||||||
void System::LoadInputBindings(SettingsInterface& si, std::unique_lock<std::mutex>& lock)
|
LayeredSettingsInterface System::GetControllerSettingsLayers(std::unique_lock<std::mutex>& lock)
|
||||||
{
|
{
|
||||||
// Hotkeys use the base configuration, except if the custom hotkeys option is enabled.
|
LayeredSettingsInterface ret;
|
||||||
|
ret.SetLayer(LayeredSettingsInterface::Layer::LAYER_BASE, Host::Internal::GetBaseSettingsLayer());
|
||||||
|
|
||||||
|
// Select input profile _or_ game settings, not both.
|
||||||
if (SettingsInterface* isi = Host::Internal::GetInputSettingsLayer())
|
if (SettingsInterface* isi = Host::Internal::GetInputSettingsLayer())
|
||||||
{
|
{
|
||||||
const bool use_profile_hotkeys = isi->GetBoolValue("ControllerPorts", "UseProfileHotkeyBindings", false);
|
ret.SetLayer(LayeredSettingsInterface::Layer::LAYER_INPUT, Host::Internal::GetInputSettingsLayer());
|
||||||
if (use_profile_hotkeys)
|
|
||||||
{
|
|
||||||
InputManager::ReloadBindings(si, *isi, *isi);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Temporarily disable the input profile layer, so it doesn't take precedence.
|
|
||||||
Host::Internal::SetInputSettingsLayer(nullptr, lock);
|
|
||||||
InputManager::ReloadBindings(si, *isi, si);
|
|
||||||
Host::Internal::SetInputSettingsLayer(s_input_settings_interface.get(), lock);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else if (SettingsInterface* gsi = Host::Internal::GetGameSettingsLayer();
|
else if (SettingsInterface* gsi = Host::Internal::GetGameSettingsLayer();
|
||||||
gsi && gsi->GetBoolValue("ControllerPorts", "UseGameSettingsForController", false))
|
gsi && gsi->GetBoolValue("ControllerPorts", "UseGameSettingsForController", false))
|
||||||
{
|
{
|
||||||
InputManager::ReloadBindings(si, *gsi, si);
|
ret.SetLayer(LayeredSettingsInterface::Layer::LAYER_GAME, gsi);
|
||||||
}
|
}
|
||||||
else
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
LayeredSettingsInterface System::GetHotkeySettingsLayer(std::unique_lock<std::mutex>& lock)
|
||||||
|
{
|
||||||
|
LayeredSettingsInterface ret;
|
||||||
|
ret.SetLayer(LayeredSettingsInterface::Layer::LAYER_BASE, Host::Internal::GetBaseSettingsLayer());
|
||||||
|
|
||||||
|
// Only add input profile layer if the option is enabled.
|
||||||
|
if (SettingsInterface* isi = Host::Internal::GetInputSettingsLayer();
|
||||||
|
isi && isi->GetBoolValue("ControllerPorts", "UseProfileHotkeyBindings", false))
|
||||||
{
|
{
|
||||||
InputManager::ReloadBindings(si, si, si);
|
ret.SetLayer(LayeredSettingsInterface::Layer::LAYER_INPUT, Host::Internal::GetInputSettingsLayer());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
void System::SetDefaultSettings(SettingsInterface& si)
|
void System::SetDefaultSettings(SettingsInterface& si)
|
||||||
|
|
|
@ -247,7 +247,7 @@ void ControllerBindingWidget::onTypeChanged()
|
||||||
m_controller_info = Controller::GetControllerInfo(static_cast<ControllerType>(index));
|
m_controller_info = Controller::GetControllerInfo(static_cast<ControllerType>(index));
|
||||||
DebugAssert(m_controller_info);
|
DebugAssert(m_controller_info);
|
||||||
|
|
||||||
SettingsInterface* sif = m_dialog->getProfileSettingsInterface();
|
SettingsInterface* sif = m_dialog->getEditingSettingsInterface();
|
||||||
if (sif)
|
if (sif)
|
||||||
{
|
{
|
||||||
sif->SetStringValue(m_config_section.c_str(), "Type", m_controller_info->name);
|
sif->SetStringValue(m_config_section.c_str(), "Type", m_controller_info->name);
|
||||||
|
@ -307,7 +307,7 @@ void ControllerBindingWidget::onClearBindingsClicked()
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
InputManager::ClearPortBindings(*m_dialog->getProfileSettingsInterface(), m_port_number);
|
InputManager::ClearPortBindings(*m_dialog->getEditingSettingsInterface(), m_port_number);
|
||||||
}
|
}
|
||||||
|
|
||||||
saveAndRefresh();
|
saveAndRefresh();
|
||||||
|
@ -358,8 +358,8 @@ void ControllerBindingWidget::doDeviceAutomaticBinding(const QString& device)
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
result = InputManager::MapController(*m_dialog->getProfileSettingsInterface(), m_port_number, mapping);
|
result = InputManager::MapController(*m_dialog->getEditingSettingsInterface(), m_port_number, mapping);
|
||||||
QtHost::SaveGameSettings(m_dialog->getProfileSettingsInterface(), false);
|
QtHost::SaveGameSettings(m_dialog->getEditingSettingsInterface(), false);
|
||||||
g_emu_thread->reloadInputBindings();
|
g_emu_thread->reloadInputBindings();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -377,7 +377,7 @@ void ControllerBindingWidget::saveAndRefresh()
|
||||||
|
|
||||||
void ControllerBindingWidget::createBindingWidgets(QWidget* parent)
|
void ControllerBindingWidget::createBindingWidgets(QWidget* parent)
|
||||||
{
|
{
|
||||||
SettingsInterface* sif = getDialog()->getProfileSettingsInterface();
|
SettingsInterface* sif = getDialog()->getEditingSettingsInterface();
|
||||||
DebugAssert(m_controller_info);
|
DebugAssert(m_controller_info);
|
||||||
|
|
||||||
QGroupBox* axis_gbox = nullptr;
|
QGroupBox* axis_gbox = nullptr;
|
||||||
|
@ -471,7 +471,7 @@ void ControllerBindingWidget::createBindingWidgets(QWidget* parent)
|
||||||
|
|
||||||
void ControllerBindingWidget::bindBindingWidgets(QWidget* parent)
|
void ControllerBindingWidget::bindBindingWidgets(QWidget* parent)
|
||||||
{
|
{
|
||||||
SettingsInterface* sif = getDialog()->getProfileSettingsInterface();
|
SettingsInterface* sif = getDialog()->getEditingSettingsInterface();
|
||||||
DebugAssert(m_controller_info);
|
DebugAssert(m_controller_info);
|
||||||
|
|
||||||
const std::string& config_section = getConfigSection();
|
const std::string& config_section = getConfigSection();
|
||||||
|
@ -601,12 +601,12 @@ ControllerMacroEditWidget::ControllerMacroEditWidget(ControllerMacroWidget* pare
|
||||||
}
|
}
|
||||||
|
|
||||||
m_frequency = dialog->getIntValue(section.c_str(), TinyString::from_format("Macro{}Frequency", index + 1u), 0);
|
m_frequency = dialog->getIntValue(section.c_str(), TinyString::from_format("Macro{}Frequency", index + 1u), 0);
|
||||||
ControllerSettingWidgetBinder::BindWidgetToInputProfileBool(dialog->getProfileSettingsInterface(), m_ui.triggerToggle,
|
ControllerSettingWidgetBinder::BindWidgetToInputProfileBool(dialog->getEditingSettingsInterface(), m_ui.triggerToggle,
|
||||||
section.c_str(), fmt::format("Macro{}Toggle", index + 1u),
|
section.c_str(), fmt::format("Macro{}Toggle", index + 1u),
|
||||||
false);
|
false);
|
||||||
updateFrequencyText();
|
updateFrequencyText();
|
||||||
|
|
||||||
m_ui.trigger->initialize(dialog->getProfileSettingsInterface(), InputBindingInfo::Type::Macro, section,
|
m_ui.trigger->initialize(dialog->getEditingSettingsInterface(), InputBindingInfo::Type::Macro, section,
|
||||||
fmt::format("Macro{}", index + 1u));
|
fmt::format("Macro{}", index + 1u));
|
||||||
|
|
||||||
connect(m_ui.increaseFrequency, &QAbstractButton::clicked, this, [this]() { modFrequency(1); });
|
connect(m_ui.increaseFrequency, &QAbstractButton::clicked, this, [this]() { modFrequency(1); });
|
||||||
|
@ -747,7 +747,7 @@ void ControllerCustomSettingsWidget::createSettingWidgets(ControllerBindingWidge
|
||||||
QGridLayout* layout, const Controller::ControllerInfo* cinfo)
|
QGridLayout* layout, const Controller::ControllerInfo* cinfo)
|
||||||
{
|
{
|
||||||
const std::string& section = parent->getConfigSection();
|
const std::string& section = parent->getConfigSection();
|
||||||
SettingsInterface* sif = parent->getDialog()->getProfileSettingsInterface();
|
SettingsInterface* sif = parent->getDialog()->getEditingSettingsInterface();
|
||||||
int current_row = 0;
|
int current_row = 0;
|
||||||
|
|
||||||
for (const SettingInfo& si : cinfo->settings)
|
for (const SettingInfo& si : cinfo->settings)
|
||||||
|
|
|
@ -14,7 +14,7 @@ ControllerGlobalSettingsWidget::ControllerGlobalSettingsWidget(QWidget* parent,
|
||||||
{
|
{
|
||||||
m_ui.setupUi(this);
|
m_ui.setupUi(this);
|
||||||
|
|
||||||
SettingsInterface* sif = dialog->getProfileSettingsInterface();
|
SettingsInterface* sif = dialog->getEditingSettingsInterface();
|
||||||
|
|
||||||
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.enableSDLSource, "InputSources", "SDL", true);
|
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.enableSDLSource, "InputSources", "SDL", true);
|
||||||
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.enableSDLEnhancedMode, "InputSources",
|
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.enableSDLEnhancedMode, "InputSources",
|
||||||
|
@ -28,10 +28,10 @@ ControllerGlobalSettingsWidget::ControllerGlobalSettingsWidget(QWidget* parent,
|
||||||
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.enableSDLMFIDriver, "InputSources", "SDLMFIDriver", true);
|
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.enableSDLMFIDriver, "InputSources", "SDLMFIDriver", true);
|
||||||
#else
|
#else
|
||||||
m_ui.sdlGridLayout->removeWidget(m_ui.enableSDLIOKitDriver);
|
m_ui.sdlGridLayout->removeWidget(m_ui.enableSDLIOKitDriver);
|
||||||
m_ui.enableSDLIOKitDriver->deleteLater();
|
delete m_ui.enableSDLIOKitDriver;
|
||||||
m_ui.enableSDLIOKitDriver = nullptr;
|
m_ui.enableSDLIOKitDriver = nullptr;
|
||||||
m_ui.sdlGridLayout->removeWidget(m_ui.enableSDLMFIDriver);
|
m_ui.sdlGridLayout->removeWidget(m_ui.enableSDLMFIDriver);
|
||||||
m_ui.enableSDLMFIDriver->deleteLater();
|
delete m_ui.enableSDLMFIDriver;
|
||||||
m_ui.enableSDLMFIDriver = nullptr;
|
m_ui.enableSDLMFIDriver = nullptr;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -41,10 +41,10 @@ ControllerGlobalSettingsWidget::ControllerGlobalSettingsWidget(QWidget* parent,
|
||||||
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.enableRawInput, "InputSources", "RawInput", false);
|
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.enableRawInput, "InputSources", "RawInput", false);
|
||||||
#else
|
#else
|
||||||
m_ui.mainLayout->removeWidget(m_ui.xinputGroup);
|
m_ui.mainLayout->removeWidget(m_ui.xinputGroup);
|
||||||
m_ui.xinputGroup->deleteLater();
|
delete m_ui.xinputGroup;
|
||||||
m_ui.xinputGroup = nullptr;
|
m_ui.xinputGroup = nullptr;
|
||||||
m_ui.mainLayout->removeWidget(m_ui.dinputGroup);
|
m_ui.mainLayout->removeWidget(m_ui.dinputGroup);
|
||||||
m_ui.dinputGroup->deleteLater();
|
delete m_ui.dinputGroup;
|
||||||
m_ui.dinputGroup = nullptr;
|
m_ui.dinputGroup = nullptr;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -71,10 +71,13 @@ ControllerGlobalSettingsWidget::ControllerGlobalSettingsWidget(QWidget* parent,
|
||||||
{
|
{
|
||||||
// remove profile options from the UI.
|
// remove profile options from the UI.
|
||||||
m_ui.mainLayout->removeWidget(m_ui.profileSettings);
|
m_ui.mainLayout->removeWidget(m_ui.profileSettings);
|
||||||
m_ui.profileSettings->deleteLater();
|
delete m_ui.profileSettings;
|
||||||
m_ui.profileSettings = nullptr;
|
m_ui.profileSettings = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (dialog->isEditingGameSettings())
|
||||||
|
m_ui.deviceListGroup->setEnabled(false);
|
||||||
|
|
||||||
connect(m_ui.multitapMode, &QComboBox::currentIndexChanged, this, [this]() { emit bindingSetupChanged(); });
|
connect(m_ui.multitapMode, &QComboBox::currentIndexChanged, this, [this]() { emit bindingSetupChanged(); });
|
||||||
|
|
||||||
connect(m_ui.pointerXScale, &QSlider::valueChanged, this,
|
connect(m_ui.pointerXScale, &QSlider::valueChanged, this,
|
||||||
|
@ -134,9 +137,10 @@ ControllerLEDSettingsDialog::ControllerLEDSettingsDialog(QWidget* parent, Contro
|
||||||
linkButton(m_ui.SDL2LED, 2);
|
linkButton(m_ui.SDL2LED, 2);
|
||||||
linkButton(m_ui.SDL3LED, 3);
|
linkButton(m_ui.SDL3LED, 3);
|
||||||
|
|
||||||
SettingsInterface* sif = dialog->getProfileSettingsInterface();
|
SettingsInterface* sif = dialog->getEditingSettingsInterface();
|
||||||
|
|
||||||
ControllerSettingWidgetBinder::BindWidgetToInputProfileBool(sif, m_ui.enableSDLPS5PlayerLED, "InputSources", "SDLPS5PlayerLED", false);
|
ControllerSettingWidgetBinder::BindWidgetToInputProfileBool(sif, m_ui.enableSDLPS5PlayerLED, "InputSources",
|
||||||
|
"SDLPS5PlayerLED", false);
|
||||||
connect(m_ui.buttonBox->button(QDialogButtonBox::Close), &QPushButton::clicked, this, &QDialog::accept);
|
connect(m_ui.buttonBox->button(QDialogButtonBox::Close), &QPushButton::clicked, this, &QDialog::accept);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -50,7 +50,7 @@
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="0" column="1" rowspan="7">
|
<item row="0" column="1" rowspan="7">
|
||||||
<widget class="QGroupBox" name="groupBox_3">
|
<widget class="QGroupBox" name="deviceListGroup">
|
||||||
<property name="title">
|
<property name="title">
|
||||||
<string>Detected Devices</string>
|
<string>Detected Devices</string>
|
||||||
</property>
|
</property>
|
||||||
|
@ -162,8 +162,7 @@
|
||||||
<string>Controller LED Settings</string>
|
<string>Controller LED Settings</string>
|
||||||
</property>
|
</property>
|
||||||
<property name="icon">
|
<property name="icon">
|
||||||
<iconset theme="lightbulb-line">
|
<iconset theme="lightbulb-line"/>
|
||||||
<normaloff>.</normaloff>.</iconset>
|
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
@ -284,7 +283,7 @@
|
||||||
<number>30</number>
|
<number>30</number>
|
||||||
</property>
|
</property>
|
||||||
<property name="orientation">
|
<property name="orientation">
|
||||||
<enum>Qt::Horizontal</enum>
|
<enum>Qt::Orientation::Horizontal</enum>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
@ -339,7 +338,7 @@
|
||||||
<number>30</number>
|
<number>30</number>
|
||||||
</property>
|
</property>
|
||||||
<property name="orientation">
|
<property name="orientation">
|
||||||
<enum>Qt::Horizontal</enum>
|
<enum>Qt::Orientation::Horizontal</enum>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
@ -388,7 +387,7 @@
|
||||||
<item row="6" column="0">
|
<item row="6" column="0">
|
||||||
<spacer name="verticalSpacer">
|
<spacer name="verticalSpacer">
|
||||||
<property name="orientation">
|
<property name="orientation">
|
||||||
<enum>Qt::Vertical</enum>
|
<enum>Qt::Orientation::Vertical</enum>
|
||||||
</property>
|
</property>
|
||||||
<property name="sizeHint" stdset="0">
|
<property name="sizeHint" stdset="0">
|
||||||
<size>
|
<size>
|
||||||
|
|
|
@ -23,41 +23,87 @@
|
||||||
|
|
||||||
static constexpr const std::array<char, 4> s_mtap_slot_names = {{'A', 'B', 'C', 'D'}};
|
static constexpr const std::array<char, 4> s_mtap_slot_names = {{'A', 'B', 'C', 'D'}};
|
||||||
|
|
||||||
ControllerSettingsWindow::ControllerSettingsWindow() : QWidget()
|
ControllerSettingsWindow::ControllerSettingsWindow(SettingsInterface* game_sif /* = nullptr */,
|
||||||
|
QWidget* parent /* = nullptr */)
|
||||||
|
: QWidget(parent), m_editing_settings_interface(game_sif)
|
||||||
{
|
{
|
||||||
m_ui.setupUi(this);
|
m_ui.setupUi(this);
|
||||||
|
|
||||||
setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
|
setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
|
||||||
|
|
||||||
refreshProfileList();
|
|
||||||
createWidgets();
|
|
||||||
|
|
||||||
m_ui.settingsCategory->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
|
m_ui.settingsCategory->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
|
||||||
|
|
||||||
connect(m_ui.settingsCategory, &QListWidget::currentRowChanged, this,
|
connect(m_ui.settingsCategory, &QListWidget::currentRowChanged, this,
|
||||||
&ControllerSettingsWindow::onCategoryCurrentRowChanged);
|
&ControllerSettingsWindow::onCategoryCurrentRowChanged);
|
||||||
connect(m_ui.currentProfile, &QComboBox::currentIndexChanged, this,
|
|
||||||
&ControllerSettingsWindow::onCurrentProfileChanged);
|
|
||||||
connect(m_ui.buttonBox, &QDialogButtonBox::rejected, this, &ControllerSettingsWindow::close);
|
connect(m_ui.buttonBox, &QDialogButtonBox::rejected, this, &ControllerSettingsWindow::close);
|
||||||
connect(m_ui.newProfile, &QPushButton::clicked, this, &ControllerSettingsWindow::onNewProfileClicked);
|
|
||||||
connect(m_ui.applyProfile, &QPushButton::clicked, this, &ControllerSettingsWindow::onApplyProfileClicked);
|
|
||||||
connect(m_ui.deleteProfile, &QPushButton::clicked, this, &ControllerSettingsWindow::onDeleteProfileClicked);
|
|
||||||
connect(m_ui.restoreDefaults, &QPushButton::clicked, this, &ControllerSettingsWindow::onRestoreDefaultsClicked);
|
|
||||||
|
|
||||||
connect(g_emu_thread, &EmuThread::onInputDevicesEnumerated, this,
|
if (!game_sif)
|
||||||
&ControllerSettingsWindow::onInputDevicesEnumerated);
|
{
|
||||||
connect(g_emu_thread, &EmuThread::onInputDeviceConnected, this, &ControllerSettingsWindow::onInputDeviceConnected);
|
refreshProfileList();
|
||||||
connect(g_emu_thread, &EmuThread::onInputDeviceDisconnected, this,
|
|
||||||
&ControllerSettingsWindow::onInputDeviceDisconnected);
|
|
||||||
connect(g_emu_thread, &EmuThread::onVibrationMotorsEnumerated, this,
|
|
||||||
&ControllerSettingsWindow::onVibrationMotorsEnumerated);
|
|
||||||
|
|
||||||
// trigger a device enumeration to populate the device list
|
m_ui.editProfileLayout->removeWidget(m_ui.copyGlobalSettings);
|
||||||
g_emu_thread->enumerateInputDevices();
|
delete m_ui.copyGlobalSettings;
|
||||||
g_emu_thread->enumerateVibrationMotors();
|
m_ui.copyGlobalSettings = nullptr;
|
||||||
|
|
||||||
|
connect(m_ui.currentProfile, &QComboBox::currentIndexChanged, this,
|
||||||
|
&ControllerSettingsWindow::onCurrentProfileChanged);
|
||||||
|
connect(m_ui.newProfile, &QPushButton::clicked, this, &ControllerSettingsWindow::onNewProfileClicked);
|
||||||
|
connect(m_ui.applyProfile, &QPushButton::clicked, this, &ControllerSettingsWindow::onApplyProfileClicked);
|
||||||
|
connect(m_ui.deleteProfile, &QPushButton::clicked, this, &ControllerSettingsWindow::onDeleteProfileClicked);
|
||||||
|
connect(m_ui.restoreDefaults, &QPushButton::clicked, this, &ControllerSettingsWindow::onRestoreDefaultsClicked);
|
||||||
|
|
||||||
|
connect(g_emu_thread, &EmuThread::onInputDevicesEnumerated, this,
|
||||||
|
&ControllerSettingsWindow::onInputDevicesEnumerated);
|
||||||
|
connect(g_emu_thread, &EmuThread::onInputDeviceConnected, this, &ControllerSettingsWindow::onInputDeviceConnected);
|
||||||
|
connect(g_emu_thread, &EmuThread::onInputDeviceDisconnected, this,
|
||||||
|
&ControllerSettingsWindow::onInputDeviceDisconnected);
|
||||||
|
connect(g_emu_thread, &EmuThread::onVibrationMotorsEnumerated, this,
|
||||||
|
&ControllerSettingsWindow::onVibrationMotorsEnumerated);
|
||||||
|
|
||||||
|
// trigger a device enumeration to populate the device list
|
||||||
|
g_emu_thread->enumerateInputDevices();
|
||||||
|
g_emu_thread->enumerateVibrationMotors();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_ui.editProfileLayout->removeWidget(m_ui.editProfileLabel);
|
||||||
|
delete m_ui.editProfileLabel;
|
||||||
|
m_ui.editProfileLabel = nullptr;
|
||||||
|
m_ui.editProfileLayout->removeWidget(m_ui.currentProfile);
|
||||||
|
delete m_ui.currentProfile;
|
||||||
|
m_ui.currentProfile = nullptr;
|
||||||
|
m_ui.editProfileLayout->removeWidget(m_ui.newProfile);
|
||||||
|
delete m_ui.newProfile;
|
||||||
|
m_ui.newProfile = nullptr;
|
||||||
|
m_ui.editProfileLayout->removeWidget(m_ui.applyProfile);
|
||||||
|
delete m_ui.applyProfile;
|
||||||
|
m_ui.applyProfile = nullptr;
|
||||||
|
m_ui.editProfileLayout->removeWidget(m_ui.deleteProfile);
|
||||||
|
delete m_ui.deleteProfile;
|
||||||
|
m_ui.deleteProfile = nullptr;
|
||||||
|
|
||||||
|
connect(m_ui.copyGlobalSettings, &QPushButton::clicked, this,
|
||||||
|
&ControllerSettingsWindow::onCopyGlobalSettingsClicked);
|
||||||
|
connect(m_ui.restoreDefaults, &QPushButton::clicked, this,
|
||||||
|
&ControllerSettingsWindow::onRestoreDefaultsForGameClicked);
|
||||||
|
}
|
||||||
|
|
||||||
|
createWidgets();
|
||||||
}
|
}
|
||||||
|
|
||||||
ControllerSettingsWindow::~ControllerSettingsWindow() = default;
|
ControllerSettingsWindow::~ControllerSettingsWindow() = default;
|
||||||
|
|
||||||
|
void ControllerSettingsWindow::editControllerSettingsForGame(QWidget* parent, SettingsInterface* sif)
|
||||||
|
{
|
||||||
|
ControllerSettingsWindow* dlg = new ControllerSettingsWindow(sif, parent);
|
||||||
|
dlg->setWindowFlag(Qt::Window);
|
||||||
|
dlg->setAttribute(Qt::WA_DeleteOnClose);
|
||||||
|
dlg->setWindowModality(Qt::WindowModality::WindowModal);
|
||||||
|
dlg->setWindowTitle(parent->windowTitle());
|
||||||
|
dlg->setWindowIcon(parent->windowIcon());
|
||||||
|
dlg->show();
|
||||||
|
}
|
||||||
|
|
||||||
int ControllerSettingsWindow::getHotkeyCategoryIndex() const
|
int ControllerSettingsWindow::getHotkeyCategoryIndex() const
|
||||||
{
|
{
|
||||||
const std::array<bool, 2> mtap_enabled = getEnabledMultitaps();
|
const std::array<bool, 2> mtap_enabled = getEnabledMultitaps();
|
||||||
|
@ -103,20 +149,26 @@ void ControllerSettingsWindow::onCategoryCurrentRowChanged(int row)
|
||||||
|
|
||||||
void ControllerSettingsWindow::onCurrentProfileChanged(int index)
|
void ControllerSettingsWindow::onCurrentProfileChanged(int index)
|
||||||
{
|
{
|
||||||
switchProfile((index == 0) ? 0 : m_ui.currentProfile->itemText(index));
|
std::string profile_name;
|
||||||
|
if (index > 0)
|
||||||
|
profile_name = m_ui.currentProfile->itemText(index).toStdString();
|
||||||
|
|
||||||
|
switchProfile(profile_name);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ControllerSettingsWindow::onNewProfileClicked()
|
void ControllerSettingsWindow::onNewProfileClicked()
|
||||||
{
|
{
|
||||||
const QString profile_name(
|
const std::string profile_name =
|
||||||
QInputDialog::getText(this, tr("Create Input Profile"), tr("Enter the name for the new input profile:")));
|
QInputDialog::getText(this, tr("Create Input Profile"), tr("Enter the name for the new input profile:"))
|
||||||
if (profile_name.isEmpty())
|
.toStdString();
|
||||||
|
if (profile_name.empty())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
std::string profile_path(System::GetInputProfilePath(profile_name.toStdString()));
|
std::string profile_path = System::GetInputProfilePath(profile_name);
|
||||||
if (FileSystem::FileExists(profile_path.c_str()))
|
if (FileSystem::FileExists(profile_path.c_str()))
|
||||||
{
|
{
|
||||||
QMessageBox::critical(this, tr("Error"), tr("A profile with the name '%1' already exists.").arg(profile_name));
|
QMessageBox::critical(this, tr("Error"),
|
||||||
|
tr("A profile with the name '%1' already exists.").arg(QString::fromStdString(profile_name)));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -131,7 +183,7 @@ void ControllerSettingsWindow::onNewProfileClicked()
|
||||||
if (res == QMessageBox::Yes)
|
if (res == QMessageBox::Yes)
|
||||||
{
|
{
|
||||||
// copy from global or the current profile
|
// copy from global or the current profile
|
||||||
if (!m_profile_interface)
|
if (!m_editing_settings_interface)
|
||||||
{
|
{
|
||||||
const int hkres = QMessageBox::question(
|
const int hkres = QMessageBox::question(
|
||||||
this, tr("Create Input Profile"),
|
this, tr("Create Input Profile"),
|
||||||
|
@ -153,9 +205,9 @@ void ControllerSettingsWindow::onNewProfileClicked()
|
||||||
{
|
{
|
||||||
// from profile
|
// from profile
|
||||||
const bool copy_hotkey_bindings =
|
const bool copy_hotkey_bindings =
|
||||||
m_profile_interface->GetBoolValue("ControllerPorts", "UseProfileHotkeyBindings", false);
|
m_editing_settings_interface->GetBoolValue("ControllerPorts", "UseProfileHotkeyBindings", false);
|
||||||
temp_si.SetBoolValue("ControllerPorts", "UseProfileHotkeyBindings", copy_hotkey_bindings);
|
temp_si.SetBoolValue("ControllerPorts", "UseProfileHotkeyBindings", copy_hotkey_bindings);
|
||||||
InputManager::CopyConfiguration(&temp_si, *m_profile_interface, true, true, copy_hotkey_bindings);
|
InputManager::CopyConfiguration(&temp_si, *m_editing_settings_interface, true, true, copy_hotkey_bindings);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -184,9 +236,9 @@ void ControllerSettingsWindow::onApplyProfileClicked()
|
||||||
|
|
||||||
{
|
{
|
||||||
const bool copy_hotkey_bindings =
|
const bool copy_hotkey_bindings =
|
||||||
m_profile_interface->GetBoolValue("ControllerPorts", "UseProfileHotkeyBindings", false);
|
m_editing_settings_interface->GetBoolValue("ControllerPorts", "UseProfileHotkeyBindings", false);
|
||||||
auto lock = Host::GetSettingsLock();
|
auto lock = Host::GetSettingsLock();
|
||||||
InputManager::CopyConfiguration(Host::Internal::GetBaseSettingsLayer(), *m_profile_interface, true, true,
|
InputManager::CopyConfiguration(Host::Internal::GetBaseSettingsLayer(), *m_editing_settings_interface, true, true,
|
||||||
copy_hotkey_bindings);
|
copy_hotkey_bindings);
|
||||||
QtHost::QueueSettingsSave();
|
QtHost::QueueSettingsSave();
|
||||||
}
|
}
|
||||||
|
@ -236,6 +288,36 @@ void ControllerSettingsWindow::onRestoreDefaultsClicked()
|
||||||
switchProfile({});
|
switchProfile({});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ControllerSettingsWindow::onCopyGlobalSettingsClicked()
|
||||||
|
{
|
||||||
|
DebugAssert(isEditingGameSettings());
|
||||||
|
|
||||||
|
{
|
||||||
|
const auto lock = Host::GetSettingsLock();
|
||||||
|
InputManager::CopyConfiguration(m_editing_settings_interface, *Host::Internal::GetBaseSettingsLayer(), true, true,
|
||||||
|
false);
|
||||||
|
}
|
||||||
|
|
||||||
|
m_editing_settings_interface->Save();
|
||||||
|
g_emu_thread->reloadGameSettings();
|
||||||
|
createWidgets();
|
||||||
|
|
||||||
|
QMessageBox::information(QtUtils::GetRootWidget(this), tr("DuckStation Controller Settings"),
|
||||||
|
tr("Per-game controller configuration reset to global settings."));
|
||||||
|
}
|
||||||
|
|
||||||
|
void ControllerSettingsWindow::onRestoreDefaultsForGameClicked()
|
||||||
|
{
|
||||||
|
DebugAssert(isEditingGameSettings());
|
||||||
|
Settings::SetDefaultControllerConfig(*m_editing_settings_interface);
|
||||||
|
m_editing_settings_interface->Save();
|
||||||
|
g_emu_thread->reloadGameSettings();
|
||||||
|
createWidgets();
|
||||||
|
|
||||||
|
QMessageBox::information(QtUtils::GetRootWidget(this), tr("DuckStation Controller Settings"),
|
||||||
|
tr("Per-game controller configuration reset to default settings."));
|
||||||
|
}
|
||||||
|
|
||||||
void ControllerSettingsWindow::onInputDevicesEnumerated(const std::vector<std::pair<std::string, std::string>>& devices)
|
void ControllerSettingsWindow::onInputDevicesEnumerated(const std::vector<std::pair<std::string, std::string>>& devices)
|
||||||
{
|
{
|
||||||
m_device_list = devices;
|
m_device_list = devices;
|
||||||
|
@ -280,16 +362,16 @@ void ControllerSettingsWindow::onVibrationMotorsEnumerated(const QList<InputBind
|
||||||
|
|
||||||
bool ControllerSettingsWindow::getBoolValue(const char* section, const char* key, bool default_value) const
|
bool ControllerSettingsWindow::getBoolValue(const char* section, const char* key, bool default_value) const
|
||||||
{
|
{
|
||||||
if (m_profile_interface)
|
if (m_editing_settings_interface)
|
||||||
return m_profile_interface->GetBoolValue(section, key, default_value);
|
return m_editing_settings_interface->GetBoolValue(section, key, default_value);
|
||||||
else
|
else
|
||||||
return Host::GetBaseBoolSettingValue(section, key, default_value);
|
return Host::GetBaseBoolSettingValue(section, key, default_value);
|
||||||
}
|
}
|
||||||
|
|
||||||
s32 ControllerSettingsWindow::getIntValue(const char* section, const char* key, s32 default_value) const
|
s32 ControllerSettingsWindow::getIntValue(const char* section, const char* key, s32 default_value) const
|
||||||
{
|
{
|
||||||
if (m_profile_interface)
|
if (m_editing_settings_interface)
|
||||||
return m_profile_interface->GetIntValue(section, key, default_value);
|
return m_editing_settings_interface->GetIntValue(section, key, default_value);
|
||||||
else
|
else
|
||||||
return Host::GetBaseIntSettingValue(section, key, default_value);
|
return Host::GetBaseIntSettingValue(section, key, default_value);
|
||||||
}
|
}
|
||||||
|
@ -298,8 +380,8 @@ std::string ControllerSettingsWindow::getStringValue(const char* section, const
|
||||||
const char* default_value) const
|
const char* default_value) const
|
||||||
{
|
{
|
||||||
std::string value;
|
std::string value;
|
||||||
if (m_profile_interface)
|
if (m_editing_settings_interface)
|
||||||
value = m_profile_interface->GetStringValue(section, key, default_value);
|
value = m_editing_settings_interface->GetStringValue(section, key, default_value);
|
||||||
else
|
else
|
||||||
value = Host::GetBaseStringSettingValue(section, key, default_value);
|
value = Host::GetBaseStringSettingValue(section, key, default_value);
|
||||||
return value;
|
return value;
|
||||||
|
@ -307,9 +389,9 @@ std::string ControllerSettingsWindow::getStringValue(const char* section, const
|
||||||
|
|
||||||
void ControllerSettingsWindow::setBoolValue(const char* section, const char* key, bool value)
|
void ControllerSettingsWindow::setBoolValue(const char* section, const char* key, bool value)
|
||||||
{
|
{
|
||||||
if (m_profile_interface)
|
if (m_editing_settings_interface)
|
||||||
{
|
{
|
||||||
m_profile_interface->SetBoolValue(section, key, value);
|
m_editing_settings_interface->SetBoolValue(section, key, value);
|
||||||
saveAndReloadGameSettings();
|
saveAndReloadGameSettings();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -322,9 +404,9 @@ void ControllerSettingsWindow::setBoolValue(const char* section, const char* key
|
||||||
|
|
||||||
void ControllerSettingsWindow::setIntValue(const char* section, const char* key, s32 value)
|
void ControllerSettingsWindow::setIntValue(const char* section, const char* key, s32 value)
|
||||||
{
|
{
|
||||||
if (m_profile_interface)
|
if (m_editing_settings_interface)
|
||||||
{
|
{
|
||||||
m_profile_interface->SetIntValue(section, key, value);
|
m_editing_settings_interface->SetIntValue(section, key, value);
|
||||||
saveAndReloadGameSettings();
|
saveAndReloadGameSettings();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -337,9 +419,9 @@ void ControllerSettingsWindow::setIntValue(const char* section, const char* key,
|
||||||
|
|
||||||
void ControllerSettingsWindow::setStringValue(const char* section, const char* key, const char* value)
|
void ControllerSettingsWindow::setStringValue(const char* section, const char* key, const char* value)
|
||||||
{
|
{
|
||||||
if (m_profile_interface)
|
if (m_editing_settings_interface)
|
||||||
{
|
{
|
||||||
m_profile_interface->SetStringValue(section, key, value);
|
m_editing_settings_interface->SetStringValue(section, key, value);
|
||||||
saveAndReloadGameSettings();
|
saveAndReloadGameSettings();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -352,17 +434,17 @@ void ControllerSettingsWindow::setStringValue(const char* section, const char* k
|
||||||
|
|
||||||
void ControllerSettingsWindow::saveAndReloadGameSettings()
|
void ControllerSettingsWindow::saveAndReloadGameSettings()
|
||||||
{
|
{
|
||||||
DebugAssert(m_profile_interface);
|
DebugAssert(m_editing_settings_interface);
|
||||||
QtHost::SaveGameSettings(m_profile_interface.get(), false);
|
QtHost::SaveGameSettings(m_editing_settings_interface, false);
|
||||||
g_emu_thread->reloadGameSettings(false);
|
g_emu_thread->reloadGameSettings(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ControllerSettingsWindow::clearSettingValue(const char* section, const char* key)
|
void ControllerSettingsWindow::clearSettingValue(const char* section, const char* key)
|
||||||
{
|
{
|
||||||
if (m_profile_interface)
|
if (m_editing_settings_interface)
|
||||||
{
|
{
|
||||||
m_profile_interface->DeleteValue(section, key);
|
m_editing_settings_interface->DeleteValue(section, key);
|
||||||
m_profile_interface->Save();
|
m_editing_settings_interface->Save();
|
||||||
g_emu_thread->reloadGameSettings();
|
g_emu_thread->reloadGameSettings();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -434,7 +516,8 @@ void ControllerSettingsWindow::createWidgets()
|
||||||
}
|
}
|
||||||
|
|
||||||
// only add hotkeys if we're editing global settings
|
// only add hotkeys if we're editing global settings
|
||||||
if (!m_profile_interface || m_profile_interface->GetBoolValue("ControllerPorts", "UseProfileHotkeyBindings", false))
|
if (!m_editing_settings_interface ||
|
||||||
|
m_editing_settings_interface->GetBoolValue("ControllerPorts", "UseProfileHotkeyBindings", false))
|
||||||
{
|
{
|
||||||
QListWidgetItem* item = new QListWidgetItem();
|
QListWidgetItem* item = new QListWidgetItem();
|
||||||
item->setText(tr("Hotkeys"));
|
item->setText(tr("Hotkeys"));
|
||||||
|
@ -444,9 +527,18 @@ void ControllerSettingsWindow::createWidgets()
|
||||||
m_ui.settingsContainer->addWidget(m_hotkey_settings);
|
m_ui.settingsContainer->addWidget(m_hotkey_settings);
|
||||||
}
|
}
|
||||||
|
|
||||||
m_ui.applyProfile->setEnabled(isEditingProfile());
|
if (!isEditingGameSettings())
|
||||||
m_ui.deleteProfile->setEnabled(isEditingProfile());
|
{
|
||||||
m_ui.restoreDefaults->setEnabled(isEditingGlobalSettings());
|
m_ui.applyProfile->setEnabled(isEditingProfile());
|
||||||
|
m_ui.deleteProfile->setEnabled(isEditingProfile());
|
||||||
|
m_ui.restoreDefaults->setEnabled(isEditingGlobalSettings());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ControllerSettingsWindow::closeEvent(QCloseEvent* event)
|
||||||
|
{
|
||||||
|
QWidget::closeEvent(event);
|
||||||
|
emit windowClosed();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ControllerSettingsWindow::updateListDescription(u32 global_slot, ControllerBindingWidget* widget)
|
void ControllerSettingsWindow::updateListDescription(u32 global_slot, ControllerBindingWidget* widget)
|
||||||
|
@ -501,30 +593,36 @@ void ControllerSettingsWindow::refreshProfileList()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ControllerSettingsWindow::switchProfile(const QString& name)
|
void ControllerSettingsWindow::switchProfile(const std::string_view name)
|
||||||
{
|
{
|
||||||
QSignalBlocker sb(m_ui.currentProfile);
|
QSignalBlocker sb(m_ui.currentProfile);
|
||||||
|
|
||||||
if (!name.isEmpty())
|
if (!name.empty())
|
||||||
{
|
{
|
||||||
std::string path(System::GetInputProfilePath(name.toStdString()));
|
const QString name_qstr = QtUtils::StringViewToQString(name);
|
||||||
|
|
||||||
|
std::string path = System::GetInputProfilePath(name);
|
||||||
if (!FileSystem::FileExists(path.c_str()))
|
if (!FileSystem::FileExists(path.c_str()))
|
||||||
{
|
{
|
||||||
QMessageBox::critical(this, tr("Error"), tr("The input profile named '%1' cannot be found.").arg(name));
|
QMessageBox::critical(this, tr("Error"), tr("The input profile named '%1' cannot be found.").arg(name_qstr));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<INISettingsInterface> sif(std::make_unique<INISettingsInterface>(std::move(path)));
|
std::unique_ptr<INISettingsInterface> sif = std::make_unique<INISettingsInterface>(std::move(path));
|
||||||
sif->Load();
|
sif->Load();
|
||||||
m_profile_interface = std::move(sif);
|
|
||||||
m_ui.currentProfile->setCurrentIndex(m_ui.currentProfile->findText(name));
|
m_profile_settings_interface = std::move(sif);
|
||||||
|
m_editing_settings_interface = m_profile_settings_interface.get();
|
||||||
|
m_ui.currentProfile->setCurrentIndex(m_ui.currentProfile->findText(name_qstr));
|
||||||
|
m_profile_name = name_qstr;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
m_profile_interface.reset();
|
m_profile_settings_interface.reset();
|
||||||
|
m_editing_settings_interface = nullptr;
|
||||||
m_ui.currentProfile->setCurrentIndex(0);
|
m_ui.currentProfile->setCurrentIndex(0);
|
||||||
|
m_profile_name = QString();
|
||||||
}
|
}
|
||||||
|
|
||||||
m_profile_name = name;
|
|
||||||
createWidgets();
|
createWidgets();
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,6 +20,8 @@
|
||||||
#include <utility>
|
#include <utility>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
class Error;
|
||||||
|
|
||||||
class ControllerGlobalSettingsWidget;
|
class ControllerGlobalSettingsWidget;
|
||||||
class ControllerBindingWidget;
|
class ControllerBindingWidget;
|
||||||
class HotkeySettingsWidget;
|
class HotkeySettingsWidget;
|
||||||
|
@ -44,22 +46,33 @@ public:
|
||||||
MAX_PORTS = 8
|
MAX_PORTS = 8
|
||||||
};
|
};
|
||||||
|
|
||||||
ControllerSettingsWindow();
|
ControllerSettingsWindow(SettingsInterface* game_sif = nullptr, QWidget* parent = nullptr);
|
||||||
~ControllerSettingsWindow();
|
~ControllerSettingsWindow();
|
||||||
|
|
||||||
|
static void editControllerSettingsForGame(QWidget* parent, SettingsInterface* sif);
|
||||||
|
|
||||||
ALWAYS_INLINE HotkeySettingsWidget* getHotkeySettingsWidget() const { return m_hotkey_settings; }
|
ALWAYS_INLINE HotkeySettingsWidget* getHotkeySettingsWidget() const { return m_hotkey_settings; }
|
||||||
|
|
||||||
ALWAYS_INLINE const std::vector<std::pair<std::string, std::string>>& getDeviceList() const { return m_device_list; }
|
ALWAYS_INLINE const std::vector<std::pair<std::string, std::string>>& getDeviceList() const { return m_device_list; }
|
||||||
ALWAYS_INLINE const QStringList& getVibrationMotors() const { return m_vibration_motors; }
|
ALWAYS_INLINE const QStringList& getVibrationMotors() const { return m_vibration_motors; }
|
||||||
|
|
||||||
ALWAYS_INLINE bool isEditingGlobalSettings() const { return m_profile_name.isEmpty(); }
|
ALWAYS_INLINE bool isEditingGlobalSettings() const
|
||||||
|
{
|
||||||
|
return (m_profile_name.isEmpty() && !m_editing_settings_interface);
|
||||||
|
}
|
||||||
|
ALWAYS_INLINE bool isEditingGameSettings() const
|
||||||
|
{
|
||||||
|
return (m_profile_name.isEmpty() && m_editing_settings_interface);
|
||||||
|
}
|
||||||
ALWAYS_INLINE bool isEditingProfile() const { return !m_profile_name.isEmpty(); }
|
ALWAYS_INLINE bool isEditingProfile() const { return !m_profile_name.isEmpty(); }
|
||||||
ALWAYS_INLINE SettingsInterface* getProfileSettingsInterface() { return m_profile_interface.get(); }
|
ALWAYS_INLINE SettingsInterface* getEditingSettingsInterface() { return m_editing_settings_interface; }
|
||||||
|
|
||||||
Category getCurrentCategory() const;
|
Category getCurrentCategory() const;
|
||||||
|
|
||||||
void updateListDescription(u32 global_slot, ControllerBindingWidget* widget);
|
void updateListDescription(u32 global_slot, ControllerBindingWidget* widget);
|
||||||
|
|
||||||
|
void switchProfile(const std::string_view name);
|
||||||
|
|
||||||
// Helper functions for updating setting values globally or in the profile.
|
// Helper functions for updating setting values globally or in the profile.
|
||||||
bool getBoolValue(const char* section, const char* key, bool default_value) const;
|
bool getBoolValue(const char* section, const char* key, bool default_value) const;
|
||||||
s32 getIntValue(const char* section, const char* key, s32 default_value) const;
|
s32 getIntValue(const char* section, const char* key, s32 default_value) const;
|
||||||
|
@ -71,6 +84,7 @@ public:
|
||||||
void saveAndReloadGameSettings();
|
void saveAndReloadGameSettings();
|
||||||
|
|
||||||
Q_SIGNALS:
|
Q_SIGNALS:
|
||||||
|
void windowClosed();
|
||||||
void inputProfileSwitched();
|
void inputProfileSwitched();
|
||||||
|
|
||||||
public Q_SLOTS:
|
public Q_SLOTS:
|
||||||
|
@ -83,6 +97,8 @@ private Q_SLOTS:
|
||||||
void onApplyProfileClicked();
|
void onApplyProfileClicked();
|
||||||
void onDeleteProfileClicked();
|
void onDeleteProfileClicked();
|
||||||
void onRestoreDefaultsClicked();
|
void onRestoreDefaultsClicked();
|
||||||
|
void onCopyGlobalSettingsClicked();
|
||||||
|
void onRestoreDefaultsForGameClicked();
|
||||||
|
|
||||||
void onInputDevicesEnumerated(const std::vector<std::pair<std::string, std::string>>& devices);
|
void onInputDevicesEnumerated(const std::vector<std::pair<std::string, std::string>>& devices);
|
||||||
void onInputDeviceConnected(const std::string& identifier, const std::string& device_name);
|
void onInputDeviceConnected(const std::string& identifier, const std::string& device_name);
|
||||||
|
@ -91,15 +107,19 @@ private Q_SLOTS:
|
||||||
|
|
||||||
void createWidgets();
|
void createWidgets();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void closeEvent(QCloseEvent* event) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
int getHotkeyCategoryIndex() const;
|
int getHotkeyCategoryIndex() const;
|
||||||
void refreshProfileList();
|
void refreshProfileList();
|
||||||
void switchProfile(const QString& name);
|
|
||||||
|
|
||||||
std::array<bool, 2> getEnabledMultitaps() const;
|
std::array<bool, 2> getEnabledMultitaps() const;
|
||||||
|
|
||||||
Ui::ControllerSettingsWindow m_ui;
|
Ui::ControllerSettingsWindow m_ui;
|
||||||
|
|
||||||
|
SettingsInterface* m_editing_settings_interface = nullptr;
|
||||||
|
|
||||||
ControllerGlobalSettingsWidget* m_global_settings = nullptr;
|
ControllerGlobalSettingsWidget* m_global_settings = nullptr;
|
||||||
std::array<ControllerBindingWidget*, MAX_PORTS> m_port_bindings{};
|
std::array<ControllerBindingWidget*, MAX_PORTS> m_port_bindings{};
|
||||||
HotkeySettingsWidget* m_hotkey_settings = nullptr;
|
HotkeySettingsWidget* m_hotkey_settings = nullptr;
|
||||||
|
@ -108,5 +128,5 @@ private:
|
||||||
QStringList m_vibration_motors;
|
QStringList m_vibration_motors;
|
||||||
|
|
||||||
QString m_profile_name;
|
QString m_profile_name;
|
||||||
std::unique_ptr<SettingsInterface> m_profile_interface;
|
std::unique_ptr<SettingsInterface> m_profile_settings_interface;
|
||||||
};
|
};
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
<rect>
|
<rect>
|
||||||
<x>0</x>
|
<x>0</x>
|
||||||
<y>0</y>
|
<y>0</y>
|
||||||
<width>1279</width>
|
<width>1284</width>
|
||||||
<height>672</height>
|
<height>672</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
|
@ -20,7 +20,7 @@
|
||||||
<string>DuckStation Controller Settings</string>
|
<string>DuckStation Controller Settings</string>
|
||||||
</property>
|
</property>
|
||||||
<property name="windowIcon">
|
<property name="windowIcon">
|
||||||
<iconset resource="resources/resources.qrc">
|
<iconset resource="resources/duckstation-qt.qrc">
|
||||||
<normaloff>:/icons/duck.png</normaloff>:/icons/duck.png</iconset>
|
<normaloff>:/icons/duck.png</normaloff>:/icons/duck.png</iconset>
|
||||||
</property>
|
</property>
|
||||||
<layout class="QGridLayout" name="gridLayout">
|
<layout class="QGridLayout" name="gridLayout">
|
||||||
|
@ -65,9 +65,9 @@
|
||||||
<item row="1" column="0" colspan="2">
|
<item row="1" column="0" colspan="2">
|
||||||
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||||
<item>
|
<item>
|
||||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
<layout class="QHBoxLayout" name="editProfileLayout">
|
||||||
<item>
|
<item>
|
||||||
<widget class="QLabel" name="label">
|
<widget class="QLabel" name="editProfileLabel">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Editing Profile:</string>
|
<string>Editing Profile:</string>
|
||||||
</property>
|
</property>
|
||||||
|
@ -106,6 +106,16 @@
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="copyGlobalSettings">
|
||||||
|
<property name="text">
|
||||||
|
<string>Copy Global Settings</string>
|
||||||
|
</property>
|
||||||
|
<property name="icon">
|
||||||
|
<iconset theme="folder-open-line"/>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<widget class="QPushButton" name="restoreDefaults">
|
<widget class="QPushButton" name="restoreDefaults">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
|
@ -130,7 +140,7 @@
|
||||||
</layout>
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
<resources>
|
<resources>
|
||||||
<include location="resources/resources.qrc"/>
|
<include location="resources/duckstation-qt.qrc"/>
|
||||||
</resources>
|
</resources>
|
||||||
<connections/>
|
<connections/>
|
||||||
</ui>
|
</ui>
|
||||||
|
|
|
@ -11,6 +11,7 @@
|
||||||
#include "core/game_database.h"
|
#include "core/game_database.h"
|
||||||
#include "core/game_list.h"
|
#include "core/game_list.h"
|
||||||
|
|
||||||
|
#include "common/error.h"
|
||||||
#include "common/string_util.h"
|
#include "common/string_util.h"
|
||||||
|
|
||||||
#include "fmt/format.h"
|
#include "fmt/format.h"
|
||||||
|
@ -54,6 +55,7 @@ GameSummaryWidget::GameSummaryWidget(const std::string& path, const std::string&
|
||||||
|
|
||||||
connect(m_ui.compatibilityComments, &QToolButton::clicked, this, &GameSummaryWidget::onCompatibilityCommentsClicked);
|
connect(m_ui.compatibilityComments, &QToolButton::clicked, this, &GameSummaryWidget::onCompatibilityCommentsClicked);
|
||||||
connect(m_ui.inputProfile, &QComboBox::currentIndexChanged, this, &GameSummaryWidget::onInputProfileChanged);
|
connect(m_ui.inputProfile, &QComboBox::currentIndexChanged, this, &GameSummaryWidget::onInputProfileChanged);
|
||||||
|
connect(m_ui.editInputProfile, &QAbstractButton::clicked, this, &GameSummaryWidget::onEditInputProfileClicked);
|
||||||
connect(m_ui.computeHashes, &QAbstractButton::clicked, this, &GameSummaryWidget::onComputeHashClicked);
|
connect(m_ui.computeHashes, &QAbstractButton::clicked, this, &GameSummaryWidget::onComputeHashClicked);
|
||||||
|
|
||||||
connect(m_ui.title, &QLineEdit::editingFinished, this, [this]() {
|
connect(m_ui.title, &QLineEdit::editingFinished, this, [this]() {
|
||||||
|
@ -159,15 +161,27 @@ void GameSummaryWidget::populateUi(const std::string& path, const std::string& s
|
||||||
|
|
||||||
m_ui.compatibilityComments->setVisible(!m_compatibility_comments.isEmpty());
|
m_ui.compatibilityComments->setVisible(!m_compatibility_comments.isEmpty());
|
||||||
|
|
||||||
m_ui.inputProfile->addItem(QIcon::fromTheme(QStringLiteral("controller-digital-line")), tr("Use Global Settings"));
|
m_ui.inputProfile->addItem(QIcon::fromTheme(QStringLiteral("global-line")), tr("Use Global Settings"));
|
||||||
|
m_ui.inputProfile->addItem(QIcon::fromTheme(QStringLiteral("controller-digital-line")),
|
||||||
|
tr("Game Specific Configuration"));
|
||||||
for (const std::string& name : InputManager::GetInputProfileNames())
|
for (const std::string& name : InputManager::GetInputProfileNames())
|
||||||
m_ui.inputProfile->addItem(QString::fromStdString(name));
|
m_ui.inputProfile->addItem(QString::fromStdString(name));
|
||||||
|
|
||||||
std::optional<std::string> profile(m_dialog->getStringValue("ControllerPorts", "InputProfileName", std::nullopt));
|
if (m_dialog->getBoolValue("ControllerPorts", "UseGameSettingsForController", std::nullopt).value_or(false))
|
||||||
if (profile.has_value())
|
{
|
||||||
m_ui.inputProfile->setCurrentIndex(m_ui.inputProfile->findText(QString::fromStdString(profile.value())));
|
m_ui.inputProfile->setCurrentIndex(1);
|
||||||
|
}
|
||||||
|
else if (const std::optional<std::string> profile_name =
|
||||||
|
m_dialog->getStringValue("ControllerPorts", "InputProfileName", std::nullopt);
|
||||||
|
profile_name.has_value() && !profile_name->empty())
|
||||||
|
{
|
||||||
|
m_ui.inputProfile->setCurrentIndex(m_ui.inputProfile->findText(QString::fromStdString(profile_name.value())));
|
||||||
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
m_ui.inputProfile->setCurrentIndex(0);
|
m_ui.inputProfile->setCurrentIndex(0);
|
||||||
|
}
|
||||||
|
m_ui.editInputProfile->setEnabled(m_ui.inputProfile->currentIndex() >= 1);
|
||||||
|
|
||||||
populateCustomAttributes();
|
populateCustomAttributes();
|
||||||
populateTracksInfo();
|
populateTracksInfo();
|
||||||
|
@ -221,6 +235,21 @@ void GameSummaryWidget::setCustomRegion(int region)
|
||||||
g_main_window->refreshGameListModel();
|
g_main_window->refreshGameListModel();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void GameSummaryWidget::setRevisionText(const QString& text)
|
||||||
|
{
|
||||||
|
if (text.isEmpty())
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (m_ui.verifySpacer)
|
||||||
|
{
|
||||||
|
m_ui.verifyLayout->removeItem(m_ui.verifySpacer);
|
||||||
|
delete m_ui.verifySpacer;
|
||||||
|
m_ui.verifySpacer = nullptr;
|
||||||
|
}
|
||||||
|
m_ui.revision->setText(text);
|
||||||
|
m_ui.revision->setVisible(true);
|
||||||
|
}
|
||||||
|
|
||||||
static QString MSFTotString(const CDImage::Position& position)
|
static QString MSFTotString(const CDImage::Position& position)
|
||||||
{
|
{
|
||||||
return QStringLiteral("%1:%2:%3 (LBA %4)")
|
return QStringLiteral("%1:%2:%3 (LBA %4)")
|
||||||
|
@ -242,6 +271,11 @@ void GameSummaryWidget::populateTracksInfo()
|
||||||
if (!image)
|
if (!image)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
setRevisionText(tr("%1 tracks covering %2 MB (%3 MB on disk)")
|
||||||
|
.arg(image->GetTrackCount())
|
||||||
|
.arg(((image->GetLBACount() * CDImage::RAW_SECTOR_SIZE) + 1048575) / 1048576)
|
||||||
|
.arg((image->GetSizeOnDisk() + 1048575) / 1048576));
|
||||||
|
|
||||||
const u32 num_tracks = image->GetTrackCount();
|
const u32 num_tracks = image->GetTrackCount();
|
||||||
for (u32 track = 1; track <= num_tracks; track++)
|
for (u32 track = 1; track <= num_tracks; track++)
|
||||||
{
|
{
|
||||||
|
@ -288,10 +322,61 @@ void GameSummaryWidget::onCompatibilityCommentsClicked()
|
||||||
|
|
||||||
void GameSummaryWidget::onInputProfileChanged(int index)
|
void GameSummaryWidget::onInputProfileChanged(int index)
|
||||||
{
|
{
|
||||||
|
|
||||||
|
SettingsInterface* sif = m_dialog->getSettingsInterface();
|
||||||
if (index == 0)
|
if (index == 0)
|
||||||
m_dialog->setStringSettingValue("ControllerPorts", "InputProfileName", std::nullopt);
|
{
|
||||||
|
// Use global settings.
|
||||||
|
sif->DeleteValue("ControllerPorts", "InputProfileName");
|
||||||
|
sif->DeleteValue("ControllerPorts", "UseGameSettingsForController");
|
||||||
|
}
|
||||||
|
else if (index == 1)
|
||||||
|
{
|
||||||
|
// Per-game configuration.
|
||||||
|
sif->DeleteValue("ControllerPorts", "InputProfileName");
|
||||||
|
sif->SetBoolValue("ControllerPorts", "UseGameSettingsForController", true);
|
||||||
|
|
||||||
|
if (!sif->GetBoolValue("ControllerPorts", "GameSettingsInitialized", false))
|
||||||
|
{
|
||||||
|
sif->SetBoolValue("ControllerPorts", "GameSettingsInitialized", true);
|
||||||
|
|
||||||
|
{
|
||||||
|
const auto lock = Host::GetSettingsLock();
|
||||||
|
SettingsInterface* base_sif = Host::Internal::GetBaseSettingsLayer();
|
||||||
|
InputManager::CopyConfiguration(sif, *base_sif, true, true, false);
|
||||||
|
|
||||||
|
QWidget* dlg_parent = QtUtils::GetRootWidget(this);
|
||||||
|
QMessageBox::information(dlg_parent, dlg_parent->windowTitle(),
|
||||||
|
tr("Per-game controller configuration initialized with global settings."));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
else
|
else
|
||||||
m_dialog->setStringSettingValue("ControllerPorts", "InputProfileName", m_ui.inputProfile->itemText(index).toUtf8());
|
{
|
||||||
|
// Input profile.
|
||||||
|
sif->SetStringValue("ControllerPorts", "InputProfileName", m_ui.inputProfile->itemText(index).toUtf8());
|
||||||
|
sif->DeleteValue("ControllerPorts", "UseGameSettingsForController");
|
||||||
|
}
|
||||||
|
|
||||||
|
m_dialog->saveAndReloadGameSettings();
|
||||||
|
m_ui.editInputProfile->setEnabled(index > 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void GameSummaryWidget::onEditInputProfileClicked()
|
||||||
|
{
|
||||||
|
if (m_dialog->getBoolValue("ControllerPorts", "UseGameSettingsForController", std::nullopt).value_or(false))
|
||||||
|
{
|
||||||
|
// Edit game configuration.
|
||||||
|
ControllerSettingsWindow::editControllerSettingsForGame(QtUtils::GetRootWidget(this),
|
||||||
|
m_dialog->getSettingsInterface());
|
||||||
|
}
|
||||||
|
else if (const std::optional<std::string> profile_name =
|
||||||
|
m_dialog->getStringValue("ControllerPorts", "InputProfileName", std::nullopt);
|
||||||
|
profile_name.has_value() && !profile_name->empty())
|
||||||
|
{
|
||||||
|
// Edit input profile.
|
||||||
|
g_main_window->openInputProfileEditor(profile_name.value());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void GameSummaryWidget::onComputeHashClicked()
|
void GameSummaryWidget::onComputeHashClicked()
|
||||||
|
@ -417,17 +502,7 @@ void GameSummaryWidget::onComputeHashClicked()
|
||||||
text = mismatch_str;
|
text = mismatch_str;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!text.isEmpty())
|
setRevisionText(text);
|
||||||
{
|
|
||||||
if (m_ui.verifySpacer)
|
|
||||||
{
|
|
||||||
m_ui.verifyLayout->removeItem(m_ui.verifySpacer);
|
|
||||||
delete m_ui.verifySpacer;
|
|
||||||
m_ui.verifySpacer = nullptr;
|
|
||||||
}
|
|
||||||
m_ui.revision->setText(text);
|
|
||||||
m_ui.revision->setVisible(true);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for (u8 track = 0; track < image->GetTrackCount(); track++)
|
for (u8 track = 0; track < image->GetTrackCount(); track++)
|
||||||
|
|
|
@ -27,6 +27,7 @@ public:
|
||||||
private Q_SLOTS:
|
private Q_SLOTS:
|
||||||
void onCompatibilityCommentsClicked();
|
void onCompatibilityCommentsClicked();
|
||||||
void onInputProfileChanged(int index);
|
void onInputProfileChanged(int index);
|
||||||
|
void onEditInputProfileClicked();
|
||||||
void onComputeHashClicked();
|
void onComputeHashClicked();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -36,6 +37,7 @@ private:
|
||||||
void updateWindowTitle();
|
void updateWindowTitle();
|
||||||
void setCustomTitle(const std::string& text);
|
void setCustomTitle(const std::string& text);
|
||||||
void setCustomRegion(int region);
|
void setCustomRegion(int region);
|
||||||
|
void setRevisionText(const QString& text);
|
||||||
|
|
||||||
void populateTracksInfo();
|
void populateTracksInfo();
|
||||||
|
|
||||||
|
|
|
@ -60,17 +60,17 @@
|
||||||
</item>
|
</item>
|
||||||
<item row="6" column="1">
|
<item row="6" column="1">
|
||||||
<layout class="QHBoxLayout" name="horizontalLayout_6">
|
<layout class="QHBoxLayout" name="horizontalLayout_6">
|
||||||
<item>
|
<item>
|
||||||
<widget class="QComboBox" name="region">
|
<widget class="QComboBox" name="region">
|
||||||
<property name="sizePolicy">
|
<property name="sizePolicy">
|
||||||
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
|
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
|
||||||
<horstretch>0</horstretch>
|
<horstretch>0</horstretch>
|
||||||
<verstretch>0</verstretch>
|
<verstretch>0</verstretch>
|
||||||
</sizepolicy>
|
</sizepolicy>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<widget class="QPushButton" name="restoreRegion">
|
<widget class="QPushButton" name="restoreRegion">
|
||||||
<property name="enabled">
|
<property name="enabled">
|
||||||
<bool>false</bool>
|
<bool>false</bool>
|
||||||
|
@ -79,7 +79,7 @@
|
||||||
<string>Restore</string>
|
<string>Restore</string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</item>
|
</item>
|
||||||
<item row="0" column="0">
|
<item row="0" column="0">
|
||||||
|
@ -106,7 +106,7 @@
|
||||||
<item row="18" column="0" colspan="2">
|
<item row="18" column="0" colspan="2">
|
||||||
<widget class="QTableWidget" name="tracks">
|
<widget class="QTableWidget" name="tracks">
|
||||||
<property name="editTriggers">
|
<property name="editTriggers">
|
||||||
<set>QAbstractItemView::NoEditTriggers</set>
|
<set>QAbstractItemView::EditTrigger::NoEditTriggers</set>
|
||||||
</property>
|
</property>
|
||||||
<property name="cornerButtonEnabled">
|
<property name="cornerButtonEnabled">
|
||||||
<bool>false</bool>
|
<bool>false</bool>
|
||||||
|
@ -216,15 +216,12 @@
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="13" column="1">
|
|
||||||
<widget class="QComboBox" name="inputProfile"/>
|
|
||||||
</item>
|
|
||||||
<item row="16" column="1">
|
<item row="16" column="1">
|
||||||
<layout class="QHBoxLayout" name="verifyLayout" stretch="0,1,0">
|
<layout class="QHBoxLayout" name="verifyLayout" stretch="0,1,0">
|
||||||
<item>
|
<item>
|
||||||
<spacer name="verifySpacer">
|
<spacer name="verifySpacer">
|
||||||
<property name="orientation">
|
<property name="orientation">
|
||||||
<enum>Qt::Horizontal</enum>
|
<enum>Qt::Orientation::Horizontal</enum>
|
||||||
</property>
|
</property>
|
||||||
<property name="sizeHint" stdset="0">
|
<property name="sizeHint" stdset="0">
|
||||||
<size>
|
<size>
|
||||||
|
@ -306,8 +303,21 @@
|
||||||
<string>Comments</string>
|
<string>Comments</string>
|
||||||
</property>
|
</property>
|
||||||
<property name="icon">
|
<property name="icon">
|
||||||
<iconset theme="information-line">
|
<iconset theme="information-line"/>
|
||||||
<normaloff>.</normaloff>.</iconset>
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
<item row="13" column="1">
|
||||||
|
<layout class="QHBoxLayout" name="horizontalLayout_2" stretch="1,0">
|
||||||
|
<item>
|
||||||
|
<widget class="QComboBox" name="inputProfile"/>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="editInputProfile">
|
||||||
|
<property name="text">
|
||||||
|
<string>Edit...</string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
|
|
@ -73,7 +73,7 @@ void HotkeySettingsWidget::createButtons()
|
||||||
QLabel* label = new QLabel(qApp->translate("Hotkeys", hotkey->display_name), m_container);
|
QLabel* label = new QLabel(qApp->translate("Hotkeys", hotkey->display_name), m_container);
|
||||||
layout->addWidget(label, target_row, 0);
|
layout->addWidget(label, target_row, 0);
|
||||||
|
|
||||||
InputBindingWidget* bind = new InputBindingWidget(m_container, m_dialog->getProfileSettingsInterface(),
|
InputBindingWidget* bind = new InputBindingWidget(m_container, m_dialog->getEditingSettingsInterface(),
|
||||||
InputBindingInfo::Type::Button, "Hotkeys", hotkey->name);
|
InputBindingInfo::Type::Button, "Hotkeys", hotkey->name);
|
||||||
bind->setMinimumWidth(300);
|
bind->setMinimumWidth(300);
|
||||||
layout->addWidget(bind, target_row, 1);
|
layout->addWidget(bind, target_row, 1);
|
||||||
|
|
|
@ -2394,6 +2394,13 @@ void MainWindow::doControllerSettings(
|
||||||
dlg->setCategory(category);
|
dlg->setCategory(category);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MainWindow::openInputProfileEditor(const std::string_view name)
|
||||||
|
{
|
||||||
|
ControllerSettingsWindow* dlg = getControllerSettingsWindow();
|
||||||
|
QtUtils::ShowOrRaiseWindow(dlg);
|
||||||
|
dlg->switchProfile(name);
|
||||||
|
}
|
||||||
|
|
||||||
void MainWindow::updateDebugMenuCPUExecutionMode()
|
void MainWindow::updateDebugMenuCPUExecutionMode()
|
||||||
{
|
{
|
||||||
std::optional<CPUExecutionMode> current_mode =
|
std::optional<CPUExecutionMode> current_mode =
|
||||||
|
|
|
@ -99,6 +99,9 @@ public:
|
||||||
/// Accessors for child windows.
|
/// Accessors for child windows.
|
||||||
CheatManagerWindow* getCheatManagerWindow() const { return m_cheat_manager_window; }
|
CheatManagerWindow* getCheatManagerWindow() const { return m_cheat_manager_window; }
|
||||||
|
|
||||||
|
/// Opens the editor for a specific input profile.
|
||||||
|
void openInputProfileEditor(const std::string_view name);
|
||||||
|
|
||||||
public Q_SLOTS:
|
public Q_SLOTS:
|
||||||
/// Updates debug menu visibility (hides if disabled).
|
/// Updates debug menu visibility (hides if disabled).
|
||||||
void updateDebugMenuVisibility();
|
void updateDebugMenuVisibility();
|
||||||
|
|
|
@ -296,7 +296,7 @@ void SettingsWindow::onCopyGlobalSettingsClicked()
|
||||||
{
|
{
|
||||||
auto lock = Host::GetSettingsLock();
|
auto lock = Host::GetSettingsLock();
|
||||||
Settings temp;
|
Settings temp;
|
||||||
temp.Load(*Host::Internal::GetBaseSettingsLayer());
|
temp.Load(*Host::Internal::GetBaseSettingsLayer(), *Host::Internal::GetBaseSettingsLayer());
|
||||||
temp.Save(*m_sif.get(), true);
|
temp.Save(*m_sif.get(), true);
|
||||||
}
|
}
|
||||||
saveAndReloadGameSettings();
|
saveAndReloadGameSettings();
|
||||||
|
|
|
@ -93,6 +93,7 @@ public:
|
||||||
bool containsSettingValue(const char* section, const char* key) const;
|
bool containsSettingValue(const char* section, const char* key) const;
|
||||||
void removeSettingValue(const char* section, const char* key);
|
void removeSettingValue(const char* section, const char* key);
|
||||||
void saveAndReloadGameSettings();
|
void saveAndReloadGameSettings();
|
||||||
|
void reloadGameSettingsFromIni();
|
||||||
|
|
||||||
bool hasGameTrait(GameDatabase::Trait trait);
|
bool hasGameTrait(GameDatabase::Trait trait);
|
||||||
|
|
||||||
|
|
|
@ -74,16 +74,23 @@ INISettingsInterface::~INISettingsInterface()
|
||||||
Save();
|
Save();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool INISettingsInterface::Load()
|
bool INISettingsInterface::Load(Error* error /* = nullptr */)
|
||||||
{
|
{
|
||||||
if (m_filename.empty())
|
if (m_filename.empty())
|
||||||
|
{
|
||||||
|
Error::SetStringView(error, "Filename is not set.");
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
std::unique_lock lock(s_ini_load_save_mutex);
|
std::unique_lock lock(s_ini_load_save_mutex);
|
||||||
SI_Error err = SI_FAIL;
|
SI_Error err = SI_FAIL;
|
||||||
auto fp = FileSystem::OpenManagedCFile(m_filename.c_str(), "rb");
|
auto fp = FileSystem::OpenManagedCFile(m_filename.c_str(), "rb", error);
|
||||||
if (fp)
|
if (fp)
|
||||||
|
{
|
||||||
err = m_ini.LoadFile(fp.get());
|
err = m_ini.LoadFile(fp.get());
|
||||||
|
if (err != SI_OK)
|
||||||
|
Error::SetStringFmt(error, "INI LoadFile() failed: {}", static_cast<int>(err));
|
||||||
|
}
|
||||||
|
|
||||||
return (err == SI_OK);
|
return (err == SI_OK);
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,7 +18,7 @@ public:
|
||||||
|
|
||||||
const std::string& GetFileName() const { return m_filename; }
|
const std::string& GetFileName() const { return m_filename; }
|
||||||
|
|
||||||
bool Load();
|
bool Load(Error* error = nullptr);
|
||||||
bool Save(Error* error = nullptr) override;
|
bool Save(Error* error = nullptr) override;
|
||||||
|
|
||||||
void Clear() override;
|
void Clear() override;
|
||||||
|
|
|
@ -1809,8 +1809,7 @@ bool InputManager::DoEventHook(InputBindingKey key, float value)
|
||||||
// Binding Updater
|
// Binding Updater
|
||||||
// ------------------------------------------------------------------------
|
// ------------------------------------------------------------------------
|
||||||
|
|
||||||
void InputManager::ReloadBindings(SettingsInterface& si, SettingsInterface& binding_si,
|
void InputManager::ReloadBindings(SettingsInterface& binding_si, SettingsInterface& hotkey_binding_si)
|
||||||
SettingsInterface& hotkey_binding_si)
|
|
||||||
{
|
{
|
||||||
PauseVibration();
|
PauseVibration();
|
||||||
|
|
||||||
|
@ -1843,8 +1842,8 @@ void InputManager::ReloadBindings(SettingsInterface& si, SettingsInterface& bind
|
||||||
// From lilypad: 1 mouse pixel = 1/8th way down.
|
// From lilypad: 1 mouse pixel = 1/8th way down.
|
||||||
const float default_scale = (axis <= static_cast<u32>(InputPointerAxis::Y)) ? 8.0f : 1.0f;
|
const float default_scale = (axis <= static_cast<u32>(InputPointerAxis::Y)) ? 8.0f : 1.0f;
|
||||||
s_pointer_axis_scale[axis] =
|
s_pointer_axis_scale[axis] =
|
||||||
1.0f / std::max(si.GetFloatValue("Pad", fmt::format("Pointer{}Scale", s_pointer_axis_names[axis]).c_str(),
|
1.0f / std::max(binding_si.GetFloatValue("Pad", fmt::format("Pointer{}Scale", s_pointer_axis_names[axis]).c_str(),
|
||||||
default_scale),
|
default_scale),
|
||||||
1.0f);
|
1.0f);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -253,7 +253,7 @@ GenericInputBindingMapping GetGenericBindingMapping(std::string_view device);
|
||||||
bool IsInputSourceEnabled(SettingsInterface& si, InputSourceType type);
|
bool IsInputSourceEnabled(SettingsInterface& si, InputSourceType type);
|
||||||
|
|
||||||
/// Re-parses the config and registers all hotkey and pad bindings.
|
/// Re-parses the config and registers all hotkey and pad bindings.
|
||||||
void ReloadBindings(SettingsInterface& si, SettingsInterface& binding_si, SettingsInterface& hotkey_binding_si);
|
void ReloadBindings(SettingsInterface& si, SettingsInterface& hotkey_binding_si);
|
||||||
|
|
||||||
/// Re-parses the sources part of the config and initializes any backends.
|
/// Re-parses the sources part of the config and initializes any backends.
|
||||||
void ReloadSources(SettingsInterface& si, std::unique_lock<std::mutex>& settings_lock);
|
void ReloadSources(SettingsInterface& si, std::unique_lock<std::mutex>& settings_lock);
|
||||||
|
|
Loading…
Reference in New Issue