Skip to content

Commit

Permalink
[dialogs] Move JoypadConfig to its own class.
Browse files Browse the repository at this point in the history
  • Loading branch information
Steelskin committed Aug 13, 2023
1 parent 5f421b5 commit 14a4b6f
Show file tree
Hide file tree
Showing 10 changed files with 147 additions and 96 deletions.
2 changes: 2 additions & 0 deletions src/wx/CMakeLists.txt
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
14 changes: 9 additions & 5 deletions src/wx/cmdevents.cpp
Expand Up @@ -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();
}
Expand Down
5 changes: 4 additions & 1 deletion src/wx/config/internal/option-internal.cpp
Expand Up @@ -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;
Expand Down Expand Up @@ -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),
Expand Down
2 changes: 1 addition & 1 deletion src/wx/config/option-proxy.h
Expand Up @@ -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,
Expand Down
85 changes: 85 additions & 0 deletions src/wx/dialogs/joypad-config.cpp
@@ -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
33 changes: 33 additions & 0 deletions src/wx/dialogs/joypad-config.h
@@ -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_
84 changes: 2 additions & 82 deletions src/wx/guiinit.cpp
Expand Up @@ -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"
Expand Down Expand Up @@ -1604,40 +1605,6 @@ class SoundConfigLoad : public wxValidator {
}
};

// 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:
Expand Down Expand Up @@ -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");
Expand Down
7 changes: 5 additions & 2 deletions src/wx/opts.cpp
Expand Up @@ -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
Expand All @@ -551,6 +553,7 @@ void update_opts() {
cfg->Write(option_name, config::UserInput::SpanToConfigString(iter.second));
}
}

if (game_bindings_changed) {
config::GameControlState::Instance().OnGameBindingsChanged();
}
Expand Down
3 changes: 2 additions & 1 deletion src/wx/opts.h
Expand Up @@ -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;
Expand Down Expand Up @@ -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
Expand Down
8 changes: 4 additions & 4 deletions src/wx/sys.cpp
Expand Up @@ -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);

Expand Down Expand Up @@ -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 {
Expand Down

0 comments on commit 14a4b6f

Please sign in to comment.