[dialogs] Move JoypadConfig to its own class.

This commit is contained in:
Fabrice de Gans 2023-08-13 15:42:31 -07:00 committed by Fabrice de Gans
parent 5f421b53c0
commit 14a4b6f820
10 changed files with 147 additions and 96 deletions

View File

@ -773,6 +773,7 @@ set(
dialogs/game-boy-config.cpp
dialogs/game-maker.cpp
dialogs/gb-rom-info.cpp
dialogs/joypad-config.cpp
widgets/group-check-box.cpp
widgets/keep-on-top-styler.cpp
widgets/option-validator.cpp
@ -826,6 +827,7 @@ set(
dialogs/game-boy-config.h
dialogs/game-maker.h
dialogs/gb-rom-info.h
dialogs/joypad-config.h
dialogs/validated-child.h
widgets/dpi-support.h
widgets/group-check-box.h

View File

@ -2227,18 +2227,22 @@ EVT_HANDLER(EmulatorDirectories, "Directories...")
EVT_HANDLER(JoypadConfigure, "Joypad options...")
{
wxDialog* dlg = GetXRCDialog("JoypadConfig");
joy.PollAllJoysticks();
auto frame = wxGetApp().frame;
bool joy_timer = frame->IsJoyPollTimerRunning();
if (!joy_timer) frame->StartJoyPollTimer();
if (!joy_timer) {
frame->StartJoyPollTimer();
}
if (ShowModal(dlg) == wxID_OK)
update_opts();
if (ShowModal(GetXRCDialog("JoypadConfig")) == wxID_OK) {
update_joypad_opts();
}
if (!joy_timer) frame->StopJoyPollTimer();
if (!joy_timer) {
frame->StopJoyPollTimer();
}
SetJoystick();
}

View File

@ -209,6 +209,9 @@ std::array<Option, kNbOptions>& Option::All() {
bool statusbar = false;
uint32_t ini_version = kIniLatestVersion;
/// Joypad
uint32_t default_stick = 1;
/// Geometry
bool fullscreen = false;
bool window_maximized = false;
@ -289,7 +292,7 @@ std::array<Option, kNbOptions>& Option::All() {
/// Joypad
Option(OptionID::kJoy),
Option(OptionID::kJoyAutofireThrottle, &gopts.autofire_rate, 1, 1000),
Option(OptionID::kJoyDefault, &gopts.default_stick, 1, 4),
Option(OptionID::kJoyDefault, &g_owned_opts.default_stick, 1, 4),
/// Keyboard
Option(OptionID::kKeyboard),

View File

@ -64,7 +64,7 @@ static constexpr std::array<Option::Type, kNbOptions> kOptionsTypes = {
/// Joypad
/*kJoy*/ Option::Type::kNone,
/*kJoyAutofireThrottle*/ Option::Type::kInt,
/*kJoyDefault*/ Option::Type::kInt,
/*kJoyDefault*/ Option::Type::kUnsigned,
/// Keyboard
/*kKeyboard*/ Option::Type::kNone,

View File

@ -0,0 +1,85 @@
#include "dialogs/joypad-config.h"
#include <wx/xrc/xmlres.h>
#include "dialogs/validated-child.h"
#include "opts.h"
#include "widgets/option-validator.h"
#include "widgets/user-input-ctrl.h"
namespace dialogs {
// static
JoypadConfig* JoypadConfig::NewInstance(wxWindow* parent) {
assert(parent);
return new JoypadConfig(parent);
}
JoypadConfig::JoypadConfig(wxWindow* parent) : wxDialog(), keep_on_top_styler_(this) {
#if !wxCHECK_VERSION(3, 1, 0)
// This needs to be set before loading any element on the window. This also
// has no effect since wx 3.1.0, where it became the default.
this->SetExtraStyle(wxWS_EX_VALIDATE_RECURSIVELY);
#endif
wxXmlResource::Get()->LoadDialog(this, parent, "JoypadConfig");
for (int joypad = 0; joypad < 4; joypad++) {
wxWindow* panel = GetValidatedChild(this, wxString::Format("joy%d", joypad + 1));
GetValidatedChild(panel, "DefaultConfig")
->SetValidator(
widgets::OptionSelectedValidator(config::OptionID::kJoyDefault, joypad + 1));
// Set up tab order so input is easy to configure. Note that there are
// two tabs for each panel, so we must check for the parent before
// setting up the tab order.
wxWindow* prev = nullptr;
wxWindow* prev_parent = nullptr;
for (const config::GameKey& game_key : config::kAllGameKeys) {
const wxString game_key_name = config::GameKeyToString(game_key);
widgets::UserInputCtrl* game_key_control =
GetValidatedChild<widgets::UserInputCtrl>(panel, game_key_name);
wxWindow* current_parent = game_key_control->GetParent();
game_key_control->SetValidator(
widgets::UserInputCtrlValidator(config::GameControl(joypad, game_key)));
if (current_parent == prev_parent) {
// The first control will be skipped here, but that's fine since
// we don't care where it fits in the tab order.
assert(prev);
game_key_control->MoveAfterInTabOrder(prev);
}
prev = game_key_control;
prev_parent = current_parent;
// Bind the individual "Clear" key event.
panel->Bind(wxEVT_BUTTON, std::bind(&widgets::UserInputCtrl::Clear, game_key_control),
XRCID(wxString("Clear" + config::GameKeyToString(game_key)).c_str()));
}
// Finally, bind the per-joypad "Defaults" and "Clear" events.
panel->Bind(wxEVT_BUTTON, std::bind(&JoypadConfig::ResetToDefaults, this, panel),
XRCID("Defaults"));
panel->Bind(wxEVT_BUTTON, std::bind(&JoypadConfig::ClearJoypad, this, panel),
XRCID("Clear"));
}
this->Fit();
}
void JoypadConfig::ResetToDefaults(wxWindow* panel) {
for (const config::GameKey& game_key : config::kAllGameKeys) {
GetValidatedChild<widgets::UserInputCtrl>(panel, config::GameKeyToString(game_key))
->SetInputs(kDefaultBindings.find(config::GameControl(0, game_key))->second);
}
}
void JoypadConfig::ClearJoypad(wxWindow* panel) {
for (const config::GameKey& game_key : config::kAllGameKeys) {
GetValidatedChild<widgets::UserInputCtrl>(panel, config::GameKeyToString(game_key))
->Clear();
}
}
} // namespace dialogs

View File

@ -0,0 +1,33 @@
#ifndef VBAM_WX_DIALOGS_JOYPAD_CONFIG_H_
#define VBAM_WX_DIALOGS_JOYPAD_CONFIG_H_
#include <wx/dialog.h>
#include "widgets/keep-on-top-styler.h"
namespace dialogs {
// Manages the Joypad configuration dialog.
class JoypadConfig : public wxDialog {
public:
static JoypadConfig* NewInstance(wxWindow* parent);
~JoypadConfig() override = default;
private:
// The constructor is private so initialization has to be done via the
// static method. This is because this class is destroyed when its
// owner, `parent` is destroyed. This prevents accidental deletion.
JoypadConfig(wxWindow* parent);
// Resets all Joypad controls for `panel` to defaults.
void ResetToDefaults(wxWindow* panel);
// Clears all Joypad controls.
void ClearJoypad(wxWindow* panel);
const widgets::KeepOnTopStyler keep_on_top_styler_;
};
} // namespace dialogs
#endif // VBAM_WX_DIALOGS_JOYPAD_CONFIG_H_

View File

@ -43,6 +43,7 @@
#include "dialogs/display-config.h"
#include "dialogs/game-boy-config.h"
#include "dialogs/gb-rom-info.h"
#include "dialogs/joypad-config.h"
#include "opts.h"
#include "widgets/option-validator.h"
#include "widgets/user-input-ctrl.h"
@ -1604,40 +1605,6 @@ public:
}
};
// manage the joypad prefs' per-panel default/clear buttons
static class JoyPadConfig_t : public wxEvtHandler {
public:
wxWindow* p;
void JoypadConfigButtons(wxCommandEvent& ev)
{
bool clear = ev.GetId() == XRCID("Clear");
// For the individual clear buttons, we assume their name is
// "Clear" + control_name
// ClearUp for Up; ClearR for R etc
for (const config::GameKey& game_key : config::kAllGameKeys) {
const wxString control_name = config::GameKeyToString(game_key);
widgets::UserInputCtrl* tc = XRCCTRL_D(*p, control_name, widgets::UserInputCtrl);
wxString singleClearButton("Clear" + control_name);
if (ev.GetId() == XRCID(singleClearButton.c_str())) {
tc->Clear();
return;
}
}
for (const config::GameKey& game_key : config::kAllGameKeys) {
widgets::UserInputCtrl* tc =
XRCCTRL_D(*p, config::GameKeyToString(game_key), widgets::UserInputCtrl);
if (clear) {
tc->Clear();
} else {
tc->SetInputs(kDefaultBindings.find(config::GameControl(0, game_key))->second);
}
}
}
} JoyPadConfigHandler[4];
// manage throttle spinctrl/canned setting choice interaction
static class ThrottleCtrl_t : public wxEvtHandler {
public:
@ -2775,54 +2742,7 @@ bool MainFrame::BindControls()
d->Fit();
}
dialogs::DirectoriesConfig::NewInstance(this);
wxDialog* joyDialog = LoadXRCropertySheetDialog("JoypadConfig");
for (int i = 0; i < 4; i++) {
wxString pn;
// NOTE: wx2.9.1 behaves differently for referenced nodes
// than 2.8! Unless there is an actual child node, the ID field
// will not be overwritten. This means that there should be a
// dummy child node (e.g. position=(0,0)). If you get
// "Unable to load dialog JoypadConfig from resources", this is
// probably the reason.
pn.Printf(wxT("joy%d"), i + 1);
wxWindow* w = SafeXRCCTRL<wxWindow>(joyDialog, pn);
w->FindWindow("DefaultConfig")
->SetValidator(wxBoolIntValidator(&gopts.default_stick, i + 1));
wxWindow *prev = NULL, *prevp = NULL;
for (const config::GameKey& game_key : config::kAllGameKeys) {
const wxString control_name = config::GameKeyToString(game_key);
widgets::UserInputCtrl* tc = XRCCTRL_D(*w, control_name, widgets::UserInputCtrl);
CheckThrowXRCError(tc, control_name);
wxWindow* p = tc->GetParent();
if (p == prevp)
tc->MoveAfterInTabOrder(prev);
prev = tc;
prevp = p;
tc->SetValidator(widgets::UserInputCtrlValidator(config::GameControl(i, game_key)));
}
JoyPadConfigHandler[i].p = w;
w->Connect(XRCID("Defaults"), wxEVT_COMMAND_BUTTON_CLICKED,
wxCommandEventHandler(JoyPadConfig_t::JoypadConfigButtons),
NULL, &JoyPadConfigHandler[i]);
w->Connect(XRCID("Clear"), wxEVT_COMMAND_BUTTON_CLICKED,
wxCommandEventHandler(JoyPadConfig_t::JoypadConfigButtons),
NULL, &JoyPadConfigHandler[i]);
for (const config::GameKey& game_key : config::kAllGameKeys) {
const wxString control_name = config::GameKeyToString(game_key);
w->Connect(XRCID(wxString("Clear" + control_name).c_str()),
wxEVT_COMMAND_BUTTON_CLICKED,
wxCommandEventHandler(JoyPadConfig_t::JoypadConfigButtons),
NULL, &JoyPadConfigHandler[i]);
}
joyDialog->Fit();
}
dialogs::JoypadConfig::NewInstance(this);
#ifndef NO_LINK
d = LoadXRCDialog("LinkConfig");

View File

@ -531,11 +531,13 @@ void load_opts(bool first_time_launch) {
// Note: run load_opts() first to guarantee all config opts exist
void update_opts() {
wxConfigBase* cfg = wxConfigBase::Get();
for (config::Option& opt : config::Option::All()) {
SaveOption(&opt);
}
}
void update_joypad_opts() {
wxConfigBase* cfg = wxConfigBase::Get();
// For joypad, compare the UserInput sets. Since UserInput guarantees a
// certain ordering, it is possible that the user control in the panel shows
@ -551,6 +553,7 @@ void update_opts() {
cfg->Write(option_name, config::UserInput::SpanToConfigString(iter.second));
}
}
if (game_bindings_changed) {
config::GameControlState::Instance().OnGameBindingsChanged();
}

View File

@ -42,7 +42,6 @@ extern struct opts_t {
std::map<config::GameControl, std::set<config::UserInput>>
game_control_bindings;
int autofire_rate = 1;
int default_stick = 1;
/// Keyboard
config::Shortcuts shortcuts;
@ -85,6 +84,8 @@ void load_opts(bool first_time_launch);
// call whenever opt vars change
// will detect changes and write config if necessary
void update_opts();
// Updates the joypad options.
void update_joypad_opts();
// Updates the shortcut options.
void update_shortcut_opts();
// returns true if option name correct; prints error if val invalid

View File

@ -334,7 +334,7 @@ bool systemReadJoypads()
uint32_t systemReadJoypad(int joy)
{
if (joy < 0 || joy > 3)
joy = gopts.default_stick - 1;
joy = OPTION(kJoyDefault) - 1;
uint32_t ret = config::GameControlState::Instance().GetJoypad(joy);
@ -772,17 +772,17 @@ void systemUpdateMotionSensor()
int systemGetSensorX()
{
return sensorx[gopts.default_stick - 1];
return sensorx[OPTION(kJoyDefault) - 1];
}
int systemGetSensorY()
{
return sensory[gopts.default_stick - 1];
return sensory[OPTION(kJoyDefault) - 1];
}
int systemGetSensorZ()
{
return sensorz[gopts.default_stick - 1] / 10;
return sensorz[OPTION(kJoyDefault) - 1] / 10;
}
class PrintDialog : public wxEvtHandler, public wxPrintout {