mirror of
https://github.com/cemu-project/Cemu.git
synced 2025-07-15 19:28:29 +12:00
Add all the files
This commit is contained in:
parent
e3db07a16a
commit
d60742f52b
1445 changed files with 430238 additions and 0 deletions
303
src/gui/input/InputAPIAddWindow.cpp
Normal file
303
src/gui/input/InputAPIAddWindow.cpp
Normal file
|
@ -0,0 +1,303 @@
|
|||
#include "gui/input/InputAPIAddWindow.h"
|
||||
|
||||
#include "input/InputManager.h"
|
||||
#include "gui/helpers/wxCustomData.h"
|
||||
#include "gui/helpers/wxHelpers.h"
|
||||
#include "input/api/Controller.h"
|
||||
|
||||
#include <wx/sizer.h>
|
||||
#include <wx/stattext.h>
|
||||
#include <wx/choice.h>
|
||||
#include <wx/statline.h>
|
||||
#include <wx/button.h>
|
||||
#include <wx/combobox.h>
|
||||
#include <wx/msgdlg.h>
|
||||
#include <wx/wupdlock.h>
|
||||
|
||||
#include "input/ControllerFactory.h"
|
||||
|
||||
wxDEFINE_EVENT(wxControllersRefreshed, wxCommandEvent);
|
||||
|
||||
using wxTypeData = wxCustomData<InputAPI::Type>;
|
||||
using wxControllerData = wxCustomData<ControllerPtr>;
|
||||
|
||||
InputAPIAddWindow::InputAPIAddWindow(wxWindow* parent, const wxPoint& position,
|
||||
const std::vector<ControllerPtr>& controllers)
|
||||
: wxDialog(parent, wxID_ANY, _("Add input API"), position, wxDefaultSize, 0), m_controllers(controllers)
|
||||
{
|
||||
this->SetSizeHints(wxDefaultSize, wxDefaultSize);
|
||||
|
||||
auto* sizer = new wxBoxSizer(wxVERTICAL);
|
||||
|
||||
{
|
||||
auto* api_row = new wxFlexGridSizer(2);
|
||||
|
||||
// API
|
||||
api_row->Add(new wxStaticText(this, wxID_ANY, _("API")), 0, wxALIGN_CENTER_VERTICAL | wxALL, 5);
|
||||
|
||||
m_input_api = new wxChoice(this, wxID_ANY);
|
||||
auto& providers = InputManager::instance().get_api_providers();
|
||||
for (const auto& p : providers)
|
||||
{
|
||||
if (p.empty())
|
||||
continue;
|
||||
|
||||
const auto provider = *p.begin();
|
||||
m_input_api->Append(to_wxString(provider->api_name()), new wxTypeData(provider->api()));
|
||||
}
|
||||
|
||||
m_input_api->Bind(wxEVT_CHOICE, &InputAPIAddWindow::on_api_selected, this);
|
||||
api_row->Add(m_input_api, 1, wxALL | wxEXPAND, 5);
|
||||
|
||||
// Controller
|
||||
api_row->Add(new wxStaticText(this, wxID_ANY, _("Controller")), 0, wxALIGN_CENTER_VERTICAL | wxALL, 5);
|
||||
|
||||
m_controller_list = new wxComboBox(this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0, nullptr,
|
||||
wxCB_READONLY);
|
||||
m_controller_list->Bind(wxEVT_COMBOBOX_DROPDOWN, &InputAPIAddWindow::on_controller_dropdown, this);
|
||||
m_controller_list->Bind(wxEVT_COMBOBOX, &InputAPIAddWindow::on_controller_selected, this);
|
||||
m_controller_list->SetMinSize(wxSize(240, -1));
|
||||
m_controller_list->Disable();
|
||||
api_row->Add(m_controller_list, 1, wxALL | wxEXPAND, 5);
|
||||
|
||||
sizer->Add(api_row, 0, wxEXPAND, 5);
|
||||
}
|
||||
|
||||
sizer->Add(new wxStaticLine(this), 0, wxEXPAND);
|
||||
|
||||
{
|
||||
auto* end_row = new wxBoxSizer(wxHORIZONTAL);
|
||||
|
||||
m_ok_button = new wxButton(this, wxID_ANY, _("Add"));
|
||||
m_ok_button->Bind(wxEVT_BUTTON, &InputAPIAddWindow::on_add_button, this);
|
||||
m_ok_button->Disable();
|
||||
end_row->Add(m_ok_button, 0, wxALL, 5);
|
||||
|
||||
auto* cancel_button = new wxButton(this, wxID_ANY, _("Cancel"));
|
||||
cancel_button->Bind(wxEVT_BUTTON, &InputAPIAddWindow::on_close_button, this);
|
||||
end_row->Add(cancel_button, 0, wxALL, 5);
|
||||
|
||||
sizer->Add(end_row, 0, wxEXPAND, 5);
|
||||
}
|
||||
|
||||
{
|
||||
// optional settings
|
||||
m_settings_panel = new wxPanel(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL);
|
||||
auto* panel_sizer = new wxBoxSizer(wxVERTICAL);
|
||||
panel_sizer->Add(new wxStaticLine(m_settings_panel), 0, wxEXPAND, 0);
|
||||
|
||||
{
|
||||
auto* row = new wxBoxSizer(wxHORIZONTAL);
|
||||
// we only have dsu settings atm, so add elements now
|
||||
row->Add(new wxStaticText(m_settings_panel, wxID_ANY, _("IP")), 0, wxALIGN_CENTER_VERTICAL | wxALL, 5);
|
||||
m_ip = new wxTextCtrl(m_settings_panel, wxID_ANY, wxT("127.0.0.1"));
|
||||
row->Add(m_ip, 0, wxALL, 5);
|
||||
|
||||
row->Add(new wxStaticText(m_settings_panel, wxID_ANY, _("Port")), 0, wxALIGN_CENTER_VERTICAL | wxALL, 5);
|
||||
m_port = new wxTextCtrl(m_settings_panel, wxID_ANY, wxT("26760"));
|
||||
row->Add(m_port, 0, wxALL, 5);
|
||||
|
||||
panel_sizer->Add(row, 0, wxEXPAND);
|
||||
}
|
||||
|
||||
m_settings_panel->SetSizer(panel_sizer);
|
||||
m_settings_panel->Layout();
|
||||
m_settings_panel->Hide();
|
||||
|
||||
sizer->Add(m_settings_panel, 1, wxEXPAND);
|
||||
}
|
||||
|
||||
this->SetSizer(sizer);
|
||||
this->Layout();
|
||||
sizer->Fit(this);
|
||||
|
||||
this->Bind(wxControllersRefreshed, &InputAPIAddWindow::on_controllers_refreshed, this);
|
||||
}
|
||||
|
||||
void InputAPIAddWindow::on_add_button(wxCommandEvent& event)
|
||||
{
|
||||
const auto selection = m_input_api->GetSelection();
|
||||
if (selection == wxNOT_FOUND)
|
||||
{
|
||||
cemu_assert_debug(false);
|
||||
EndModal(wxID_CANCEL);
|
||||
return;
|
||||
}
|
||||
|
||||
for (const auto& c : m_controllers)
|
||||
{
|
||||
if (*c == *m_controller)
|
||||
{
|
||||
wxMessageBox(_("The controller is already added!"), _("Error"), wxOK | wxCENTRE | wxICON_ERROR, this);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
m_type = static_cast<wxTypeData*>(m_input_api->GetClientObject(selection))->get();
|
||||
EndModal(wxID_OK);
|
||||
}
|
||||
|
||||
void InputAPIAddWindow::on_close_button(wxCommandEvent& event)
|
||||
{
|
||||
EndModal(wxID_CANCEL);
|
||||
}
|
||||
|
||||
bool InputAPIAddWindow::has_custom_settings() const
|
||||
{
|
||||
const auto selection = m_input_api->GetStringSelection();
|
||||
return selection == to_wxString(to_string(InputAPI::DSUClient));
|
||||
}
|
||||
|
||||
std::unique_ptr<ControllerProviderSettings> InputAPIAddWindow::get_settings() const
|
||||
{
|
||||
if (!has_custom_settings())
|
||||
return {};
|
||||
|
||||
return std::make_unique<DSUProviderSettings>(m_ip->GetValue().ToStdString(),
|
||||
ConvertString<uint16>(m_port->GetValue().ToStdString()));
|
||||
}
|
||||
|
||||
void InputAPIAddWindow::on_api_selected(wxCommandEvent& event)
|
||||
{
|
||||
if (m_input_api->GetSelection() == wxNOT_FOUND)
|
||||
return;
|
||||
|
||||
m_controller_list->Enable();
|
||||
m_controller_list->SetSelection(wxNOT_FOUND);
|
||||
|
||||
const auto selection = m_input_api->GetStringSelection();
|
||||
// keyboard is a special case, as theres only one device supported atm
|
||||
if (selection == to_wxString(to_string(InputAPI::Keyboard)))
|
||||
{
|
||||
const auto controllers = InputManager::instance().get_api_provider(InputAPI::Keyboard)->get_controllers();
|
||||
if (!controllers.empty())
|
||||
{
|
||||
m_controller = controllers[0];
|
||||
m_ok_button->Enable();
|
||||
|
||||
m_controller_list->Clear();
|
||||
const auto display_name = controllers[0]->display_name();
|
||||
const auto index = m_controller_list->Append(display_name, new wxCustomData(controllers[0]));
|
||||
m_controller_list->SetSelection(index);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
#if BOOST_OS_LINUX
|
||||
// We rely on the wxEVT_COMBOBOX_DROPDOWN event to trigger filling the controller list,
|
||||
// but on wxGTK the dropdown button cannot be clicked if the list is empty
|
||||
// so as a quick and dirty workaround we fill the list here
|
||||
wxCommandEvent tmpCmdEvt;
|
||||
on_controller_dropdown(tmpCmdEvt);
|
||||
#endif
|
||||
}
|
||||
|
||||
const auto show_settings = has_custom_settings();
|
||||
// dsu has special settings for ip/port
|
||||
if (show_settings != m_settings_panel->IsShown())
|
||||
{
|
||||
wxWindowUpdateLocker locker(this);
|
||||
m_settings_panel->Show(show_settings);
|
||||
Layout();
|
||||
Fit();
|
||||
}
|
||||
}
|
||||
|
||||
void InputAPIAddWindow::on_controller_dropdown(wxCommandEvent& event)
|
||||
{
|
||||
if (m_search_running)
|
||||
return;
|
||||
|
||||
int selection = m_input_api->GetSelection();
|
||||
if (selection == wxNOT_FOUND)
|
||||
return;
|
||||
|
||||
const auto type = static_cast<wxAPIType*>(m_input_api->GetClientObject(selection))->get();
|
||||
auto settings = get_settings();
|
||||
|
||||
ControllerProviderPtr provider;
|
||||
if (settings)
|
||||
provider = InputManager::instance().get_api_provider(type, *settings);
|
||||
else
|
||||
provider = InputManager::instance().get_api_provider(type);
|
||||
|
||||
if (!provider)
|
||||
return;
|
||||
|
||||
std::string selected_uuid;
|
||||
selection = m_controller_list->GetSelection();
|
||||
if (selection != wxNOT_FOUND)
|
||||
{
|
||||
// TODO selected_uuid
|
||||
}
|
||||
|
||||
m_search_running = true;
|
||||
|
||||
wxWindowUpdateLocker lock(m_controller_list);
|
||||
m_controller_list->Clear();
|
||||
|
||||
m_controller_list->Append(_("Searching for controllers..."), (wxClientData*)nullptr);
|
||||
m_controller_list->SetSelection(wxNOT_FOUND);
|
||||
|
||||
std::thread([this, provider, selected_uuid]()
|
||||
{
|
||||
auto available_controllers = provider->get_controllers();
|
||||
|
||||
wxCommandEvent event(wxControllersRefreshed);
|
||||
event.SetEventObject(m_controller_list);
|
||||
event.SetClientObject(new wxCustomData(std::move(available_controllers)));
|
||||
event.SetInt(provider->api());
|
||||
event.SetString(selected_uuid);
|
||||
wxPostEvent(this, event);
|
||||
|
||||
m_search_running = false;
|
||||
}).detach();
|
||||
}
|
||||
|
||||
void InputAPIAddWindow::on_controller_selected(wxCommandEvent& event)
|
||||
{
|
||||
if (m_search_running)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
const auto selection = m_controller_list->GetSelection();
|
||||
if (selection == wxNOT_FOUND)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (auto* controller = (wxControllerData*)m_controller_list->GetClientObject(selection))
|
||||
{
|
||||
m_controller = controller->ref();
|
||||
m_ok_button->Enable();
|
||||
}
|
||||
}
|
||||
|
||||
void InputAPIAddWindow::on_controllers_refreshed(wxCommandEvent& event)
|
||||
{
|
||||
const auto type = event.GetInt();
|
||||
wxASSERT(0 <= type && type < InputAPI::MAX);
|
||||
|
||||
auto* controllers = dynamic_cast<wxComboBox*>(event.GetEventObject());
|
||||
wxASSERT(controllers);
|
||||
|
||||
const auto available_controllers = static_cast<wxCustomData<std::vector<std::shared_ptr<ControllerBase>>>*>(event.
|
||||
GetClientObject())->get();
|
||||
const auto selected_uuid = event.GetString().ToStdString();
|
||||
bool item_selected = false;
|
||||
|
||||
wxWindowUpdateLocker lock(controllers);
|
||||
controllers->Clear();
|
||||
for (const auto& c : available_controllers)
|
||||
{
|
||||
const auto display_name = c->display_name();
|
||||
const auto uuid = c->uuid();
|
||||
const auto index = controllers->Append(display_name, new wxCustomData(c));
|
||||
if (!item_selected && selected_uuid == uuid)
|
||||
{
|
||||
controllers->SetSelection(index);
|
||||
item_selected = true;
|
||||
}
|
||||
}
|
||||
}
|
53
src/gui/input/InputAPIAddWindow.h
Normal file
53
src/gui/input/InputAPIAddWindow.h
Normal file
|
@ -0,0 +1,53 @@
|
|||
#pragma once
|
||||
|
||||
#include "input/api/InputAPI.h"
|
||||
|
||||
#include <optional>
|
||||
#include <wx/dialog.h>
|
||||
#include <wx/panel.h>
|
||||
|
||||
#include "gui/helpers/wxCustomData.h"
|
||||
#include "input/api/Controller.h"
|
||||
|
||||
class wxComboBox;
|
||||
class wxChoice;
|
||||
class wxTextCtrl;
|
||||
|
||||
using wxAPIType = wxCustomData<InputAPI::Type>;
|
||||
|
||||
class InputAPIAddWindow : public wxDialog
|
||||
{
|
||||
public:
|
||||
InputAPIAddWindow(wxWindow* parent, const wxPoint& position, const std::vector<ControllerPtr>& controllers);
|
||||
|
||||
bool is_valid() const { return m_type.has_value() && m_controller != nullptr; }
|
||||
InputAPI::Type get_type() const { return m_type.value(); }
|
||||
std::shared_ptr<ControllerBase> get_controller() const { return m_controller; }
|
||||
|
||||
bool has_custom_settings() const;
|
||||
std::unique_ptr<ControllerProviderSettings> get_settings() const;
|
||||
|
||||
private:
|
||||
void on_add_button(wxCommandEvent& event);
|
||||
void on_close_button(wxCommandEvent& event);
|
||||
|
||||
|
||||
void on_api_selected(wxCommandEvent& event);
|
||||
|
||||
void on_controller_dropdown(wxCommandEvent& event);
|
||||
void on_controller_selected(wxCommandEvent& event);
|
||||
void on_controllers_refreshed(wxCommandEvent& event);
|
||||
|
||||
wxChoice* m_input_api;
|
||||
wxComboBox* m_controller_list;
|
||||
wxButton* m_ok_button;
|
||||
|
||||
wxPanel* m_settings_panel;
|
||||
wxTextCtrl* m_ip, * m_port;
|
||||
|
||||
std::optional<InputAPI::Type> m_type;
|
||||
std::shared_ptr<ControllerBase> m_controller;
|
||||
|
||||
std::vector<ControllerPtr> m_controllers;
|
||||
std::atomic_bool m_search_running = false;
|
||||
};
|
979
src/gui/input/InputSettings2.cpp
Normal file
979
src/gui/input/InputSettings2.cpp
Normal file
|
@ -0,0 +1,979 @@
|
|||
#include "gui/input/InputSettings2.h"
|
||||
|
||||
#include <wx/gbsizer.h>
|
||||
|
||||
#include "input/InputManager.h"
|
||||
#include "gui/helpers/wxHelpers.h"
|
||||
#include "gui/helpers/wxControlObject.h"
|
||||
#include "gui/helpers/wxCustomData.h"
|
||||
|
||||
#include <wx/sizer.h>
|
||||
#include <wx/notebook.h>
|
||||
#include <wx/wupdlock.h>
|
||||
#include <wx/stattext.h>
|
||||
#include <wx/combobox.h>
|
||||
#include <wx/button.h>
|
||||
#include <wx/statline.h>
|
||||
#include <wx/bmpbuttn.h>
|
||||
|
||||
#include "config/ActiveSettings.h"
|
||||
#include "gui/input/InputAPIAddWindow.h"
|
||||
#include "input/ControllerFactory.h"
|
||||
|
||||
#include "gui/input/panels/VPADInputPanel.h"
|
||||
#include "gui/input/panels/ProControllerInputPanel.h"
|
||||
|
||||
#include "gui/input/settings/DefaultControllerSettings.h"
|
||||
#include "gui/input/panels/ClassicControllerInputPanel.h"
|
||||
#include "gui/input/panels/WiimoteInputPanel.h"
|
||||
#include "gui/input/settings/WiimoteControllerSettings.h"
|
||||
#include "util/EventService.h"
|
||||
|
||||
#if BOOST_OS_LINUX
|
||||
#include "resource/linux/resources.h"
|
||||
#endif
|
||||
|
||||
bool g_inputConfigWindowHasFocus = false;
|
||||
|
||||
// _("<profile name>")
|
||||
const wxString kDefaultProfileName = "<profile name>";
|
||||
|
||||
using wxTypeData = wxCustomData<EmulatedController::Type>;
|
||||
using wxControllerData = wxCustomData<ControllerPtr>;
|
||||
|
||||
struct ControllerPage
|
||||
{
|
||||
EmulatedControllerPtr m_controller;
|
||||
|
||||
// profiles
|
||||
wxComboBox* m_profiles;
|
||||
wxButton* m_profile_load, * m_profile_save, * m_profile_delete;
|
||||
wxStaticText* m_profile_status;
|
||||
|
||||
// emulated controller
|
||||
wxComboBox* m_emulated_controller;
|
||||
|
||||
// controller api
|
||||
wxComboBox* m_controllers;
|
||||
wxButton* m_controller_api_add, *m_controller_api_remove;
|
||||
|
||||
wxButton* m_controller_settings, * m_controller_calibrate, *m_controller_clear;
|
||||
wxBitmapButton* m_controller_connected;
|
||||
|
||||
// panel
|
||||
std::array<InputPanel*, EmulatedController::Type::MAX> m_panels{};
|
||||
};
|
||||
using wxControllerPageData = wxCustomData<ControllerPage>;
|
||||
|
||||
|
||||
InputSettings2::InputSettings2(wxWindow* parent)
|
||||
: wxDialog(parent, wxID_ANY, _("Input settings"))
|
||||
{
|
||||
this->SetSizeHints(wxDefaultSize, wxDefaultSize);
|
||||
|
||||
g_inputConfigWindowHasFocus = true;
|
||||
|
||||
m_connected = wxBITMAP_PNG(INPUT_CONNECTED);
|
||||
m_disconnected = wxBITMAP_PNG(INPUT_DISCONNECTED);
|
||||
m_low_battery = wxBITMAP_PNG(INPUT_LOW_BATTERY);
|
||||
|
||||
auto* sizer = new wxBoxSizer(wxVERTICAL);
|
||||
|
||||
m_notebook = new wxNotebook(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, 0);
|
||||
for(size_t i = 0; i < InputManager::kMaxController; ++i)
|
||||
{
|
||||
auto* page = new wxPanel(m_notebook, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL);
|
||||
page->SetClientObject(nullptr); // force internal type to client object
|
||||
m_notebook->AddPage(page, wxStringFormat2(_("Controller {}"), i + 1));
|
||||
}
|
||||
|
||||
m_notebook->Bind(wxEVT_NOTEBOOK_PAGE_CHANGED, &InputSettings2::on_controller_page_changed, this);
|
||||
sizer->Add(m_notebook, 1, wxEXPAND);
|
||||
|
||||
m_notebook->SetSelection(0);
|
||||
auto* first_page = initialize_page(0);
|
||||
|
||||
// init first/default page for fitting size
|
||||
auto* page_data = (wxControllerPageData*)first_page->GetClientObject();
|
||||
auto* panel = new VPADInputPanel(first_page);
|
||||
page_data->ref().m_panels[EmulatedController::Type::VPAD] = panel;
|
||||
|
||||
auto* first_page_sizer = dynamic_cast<wxGridBagSizer*>(first_page->GetSizer());
|
||||
auto* panel_sizer = first_page_sizer->FindItemAtPosition(wxGBPosition(7, 0))->GetSizer();
|
||||
panel_sizer->Add(panel, 0, wxEXPAND);
|
||||
|
||||
panel->Show();
|
||||
first_page->Layout();
|
||||
|
||||
SetSizer(sizer);
|
||||
Layout();
|
||||
Fit();
|
||||
|
||||
panel->Hide();
|
||||
|
||||
update_state();
|
||||
|
||||
Bind(wxEVT_TIMER, &InputSettings2::on_timer, this);
|
||||
|
||||
m_timer = new wxTimer(this);
|
||||
m_timer->Start(100);
|
||||
|
||||
m_controller_changed = EventService::instance().connect<Events::ControllerChanged>(&InputSettings2::on_controller_changed, this);
|
||||
}
|
||||
|
||||
InputSettings2::~InputSettings2()
|
||||
{
|
||||
m_controller_changed.disconnect();
|
||||
|
||||
g_inputConfigWindowHasFocus = false;
|
||||
m_timer->Stop();
|
||||
InputManager::instance().save();
|
||||
}
|
||||
|
||||
|
||||
wxWindow* InputSettings2::initialize_page(size_t index)
|
||||
{
|
||||
auto* page = m_notebook->GetPage(index);
|
||||
if (page->GetClientObject()) // already initialized
|
||||
return page;
|
||||
|
||||
page->Bind(wxEVT_LEFT_UP, &InputSettings2::on_left_click, this);
|
||||
|
||||
ControllerPage page_data{};
|
||||
const auto emulated_controller = InputManager::instance().get_controller(index);
|
||||
page_data.m_controller = emulated_controller;
|
||||
|
||||
wxWindowUpdateLocker lock(page);
|
||||
auto* sizer = new wxGridBagSizer();
|
||||
|
||||
{
|
||||
// profile
|
||||
sizer->Add(new wxStaticText(page, wxID_ANY, _("Profile"), wxDefaultPosition, wxDefaultSize, 0), wxGBPosition(0, 0), wxDefaultSpan, wxALIGN_CENTER_VERTICAL | wxALL, 5);
|
||||
auto* profiles = new wxComboBox(page, wxID_ANY, _(kDefaultProfileName));
|
||||
sizer->Add(profiles, wxGBPosition(0, 1), wxDefaultSpan, wxALIGN_CENTER_VERTICAL | wxALL | wxEXPAND, 5);
|
||||
|
||||
if (emulated_controller && emulated_controller->has_profile_name())
|
||||
{
|
||||
profiles->SetValue(emulated_controller->get_profile_name());
|
||||
}
|
||||
|
||||
auto* load_bttn = new wxButton(page, wxID_ANY, _("Load"));
|
||||
load_bttn->Disable();
|
||||
sizer->Add(load_bttn, wxGBPosition(0, 2), wxDefaultSpan, wxALIGN_CENTER_VERTICAL | wxALL, 5);
|
||||
|
||||
auto* save_bttn = new wxButton(page, wxID_ANY, _("Save"));
|
||||
save_bttn->Disable();
|
||||
sizer->Add(save_bttn, wxGBPosition(0, 3), wxDefaultSpan, wxALIGN_CENTER_VERTICAL | wxALL, 5);
|
||||
|
||||
auto* delete_bttn = new wxButton(page, wxID_ANY, _("Delete"));
|
||||
delete_bttn->Disable();
|
||||
sizer->Add(delete_bttn, wxGBPosition(0, 4), wxDefaultSpan, wxALIGN_CENTER_VERTICAL | wxALL, 5);
|
||||
|
||||
auto* profile_status = new wxStaticText(page, wxID_ANY, _("controller set by gameprofile. changes won't be saved permanently!"), wxDefaultPosition, wxDefaultSize, 0);
|
||||
profile_status->SetMinSize(wxSize(200, -1));
|
||||
profile_status->Wrap(200);
|
||||
sizer->Add(profile_status, wxGBPosition(0, 5), wxDefaultSpan, wxALIGN_CENTER_VERTICAL | wxALL | wxRESERVE_SPACE_EVEN_IF_HIDDEN, 5);
|
||||
|
||||
if(InputManager::instance().is_gameprofile_set(index))
|
||||
{
|
||||
profile_status->SetForegroundColour(wxTheColourDatabase->Find("ERROR"));
|
||||
}
|
||||
else
|
||||
{
|
||||
profile_status->Hide();
|
||||
}
|
||||
|
||||
load_bttn->Bind(wxEVT_BUTTON, &InputSettings2::on_profile_load, this);
|
||||
save_bttn->Bind(wxEVT_BUTTON, &InputSettings2::on_profile_save, this);
|
||||
delete_bttn->Bind(wxEVT_BUTTON, &InputSettings2::on_profile_delete, this);
|
||||
|
||||
profiles->Bind(wxEVT_COMBOBOX_DROPDOWN, &InputSettings2::on_profile_dropdown, this);
|
||||
profiles->Bind(wxEVT_TEXT, &InputSettings2::on_profile_text_changed, this);
|
||||
|
||||
page_data.m_profiles = profiles;
|
||||
page_data.m_profile_load = load_bttn;
|
||||
page_data.m_profile_save = save_bttn;
|
||||
page_data.m_profile_delete = delete_bttn;
|
||||
page_data.m_profile_status = profile_status;
|
||||
}
|
||||
|
||||
sizer->Add(new wxStaticLine(page), wxGBPosition(1, 0), wxGBSpan(1, 6), wxEXPAND);
|
||||
|
||||
{
|
||||
// emulated controller
|
||||
sizer->Add(new wxStaticText(page, wxID_ANY, _("Emulated controller")), wxGBPosition(2, 0), wxDefaultSpan, wxALIGN_CENTER_VERTICAL | wxALL, 5);
|
||||
|
||||
auto* econtroller_box = new wxComboBox(page, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0, nullptr, wxCB_READONLY);
|
||||
econtroller_box->SetMinSize(wxSize(200, -1));
|
||||
econtroller_box->Bind(wxEVT_COMBOBOX_DROPDOWN, &InputSettings2::on_emulated_controller_dropdown, this);
|
||||
econtroller_box->Bind(wxEVT_COMBOBOX, &InputSettings2::on_emulated_controller_selected, this);
|
||||
|
||||
econtroller_box->AppendString(_("Disabled"));
|
||||
econtroller_box->SetSelection(0);
|
||||
|
||||
sizer->Add(econtroller_box, wxGBPosition(2, 1), wxDefaultSpan, wxALIGN_CENTER_VERTICAL | wxALL | wxEXPAND, 5);
|
||||
page_data.m_emulated_controller = econtroller_box;
|
||||
}
|
||||
|
||||
sizer->Add(new wxStaticLine(page), wxGBPosition(3, 0), wxGBSpan(1, 6), wxEXPAND);
|
||||
|
||||
{
|
||||
// controller api
|
||||
sizer->Add(new wxStaticText(page, wxID_ANY, _("Controller")), wxGBPosition(4, 0), wxDefaultSpan, wxALIGN_CENTER_VERTICAL | wxALL, 5);
|
||||
|
||||
auto* controllers = new wxComboBox(page, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0, nullptr, wxCB_READONLY);
|
||||
controllers->Bind(wxEVT_COMBOBOX, &InputSettings2::on_controller_selected, this);
|
||||
controllers->Bind(wxEVT_COMBOBOX_DROPDOWN, &InputSettings2::on_controller_dropdown, this);
|
||||
controllers->SetMinSize(wxSize(300, -1));
|
||||
|
||||
page_data.m_controllers = controllers;
|
||||
|
||||
sizer->Add(controllers, wxGBPosition(4, 1), wxDefaultSpan, wxALIGN_CENTER_VERTICAL | wxALL | wxEXPAND, 5);
|
||||
|
||||
{
|
||||
// add/remove buttons
|
||||
auto* bttn_sizer = new wxBoxSizer(wxHORIZONTAL);
|
||||
|
||||
auto* add_api = new wxButton(page, wxID_ANY, wxT(" + "), wxDefaultPosition, wxDefaultSize, wxBU_EXACTFIT);
|
||||
add_api->Bind(wxEVT_BUTTON, &InputSettings2::on_controller_add, this);
|
||||
bttn_sizer->Add(add_api, 0, wxALL, 5);
|
||||
|
||||
auto* remove_api = new wxButton(page, wxID_ANY, wxT(" - "), wxDefaultPosition, wxDefaultSize, wxBU_EXACTFIT);
|
||||
remove_api->Bind(wxEVT_BUTTON, &InputSettings2::on_controller_remove, this);
|
||||
bttn_sizer->Add(remove_api, 0, wxALL, 5);
|
||||
|
||||
sizer->Add(bttn_sizer, wxGBPosition(4, 2), wxDefaultSpan, wxEXPAND, 5);
|
||||
|
||||
page_data.m_controller_api_add = add_api;
|
||||
page_data.m_controller_api_remove = remove_api;
|
||||
}
|
||||
|
||||
// controller
|
||||
auto* controller_bttns = new wxBoxSizer(wxHORIZONTAL);
|
||||
auto* settings = new wxButton(page, wxID_ANY, _("Settings"), wxDefaultPosition, wxDefaultSize, 0);
|
||||
settings->Bind(wxEVT_BUTTON, &InputSettings2::on_controller_settings, this);
|
||||
settings->Disable();
|
||||
controller_bttns->Add(settings, 0, wxALL, 5);
|
||||
|
||||
auto* calibrate = new wxButton(page, wxID_ANY, _("Calibrate"), wxDefaultPosition, wxDefaultSize, 0);
|
||||
calibrate->Bind(wxEVT_BUTTON, &InputSettings2::on_controller_calibrate, this);
|
||||
calibrate->Disable();
|
||||
controller_bttns->Add(calibrate, 0, wxALL, 5);
|
||||
|
||||
auto* clear = new wxButton(page, wxID_ANY, _("Clear"), wxDefaultPosition, wxDefaultSize, 0);
|
||||
clear->Bind(wxEVT_BUTTON, &InputSettings2::on_controller_clear, this);
|
||||
controller_bttns->Add(clear, 0, wxALL, 5);
|
||||
|
||||
sizer->Add(controller_bttns, wxGBPosition(5, 1), wxDefaultSpan, wxALIGN_CENTER_VERTICAL);
|
||||
|
||||
auto* connected_button = new wxBitmapButton(page, wxID_ANY, m_disconnected);
|
||||
connected_button->Bind(wxEVT_BUTTON, &InputSettings2::on_controller_connect, this);
|
||||
connected_button->SetToolTip(_("Test if the controller is connected"));
|
||||
sizer->Add(connected_button, wxGBPosition(5, 2), wxDefaultSpan, wxALIGN_CENTER_VERTICAL | wxALL, 5); // TODO replace with icon
|
||||
|
||||
page_data.m_controller_settings = settings;
|
||||
page_data.m_controller_calibrate = calibrate;
|
||||
page_data.m_controller_clear = clear;
|
||||
page_data.m_controller_connected = connected_button;
|
||||
|
||||
}
|
||||
|
||||
sizer->Add(new wxStaticLine(page), wxGBPosition(6, 0), wxGBSpan(1, 6), wxEXPAND);
|
||||
|
||||
auto* panel_sizer = new wxBoxSizer(wxVERTICAL);
|
||||
sizer->Add(panel_sizer, wxGBPosition(7, 0), wxGBSpan(1, 6), wxEXPAND | wxALL, 5);
|
||||
|
||||
page->SetSizer(sizer);
|
||||
page->Layout();
|
||||
|
||||
page->SetClientObject(new wxCustomData(page_data));
|
||||
|
||||
return page;
|
||||
}
|
||||
|
||||
std::pair<size_t, size_t> InputSettings2::get_emulated_controller_types() const
|
||||
{
|
||||
size_t vpad = 0, wpad = 0;
|
||||
for(size_t i = 0; i < m_notebook->GetPageCount(); ++i)
|
||||
{
|
||||
auto* page = m_notebook->GetPage(i);
|
||||
auto* page_data = (wxControllerPageData*)page->GetClientObject();
|
||||
if (!page_data)
|
||||
continue;
|
||||
|
||||
if (!page_data->ref().m_controller) // = disabled
|
||||
continue;
|
||||
|
||||
const auto api_type = page_data->ref().m_controller->type();
|
||||
if (api_type)
|
||||
continue;
|
||||
|
||||
if (api_type == EmulatedController::VPAD)
|
||||
++vpad;
|
||||
else
|
||||
++wpad;
|
||||
}
|
||||
|
||||
return std::make_pair(vpad, wpad);
|
||||
}
|
||||
|
||||
std::shared_ptr<ControllerBase> InputSettings2::get_active_controller() const
|
||||
{
|
||||
auto& page_data = get_current_page_data();
|
||||
|
||||
const auto selection = page_data.m_controllers->GetSelection();
|
||||
if(selection != wxNOT_FOUND)
|
||||
{
|
||||
if(auto* controller = (wxControllerData*)page_data.m_controllers->GetClientObject(selection))
|
||||
return controller->ref();
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
bool InputSettings2::has_settings(InputAPI::Type type)
|
||||
{
|
||||
switch(type)
|
||||
{
|
||||
case InputAPI::Keyboard:
|
||||
return false;
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
void InputSettings2::update_state()
|
||||
{
|
||||
auto* page = m_notebook->GetCurrentPage();
|
||||
wxWindowUpdateLocker lock(page);
|
||||
|
||||
auto* page_data_ptr = (wxControllerPageData*)page->GetClientObject();
|
||||
wxASSERT(page_data_ptr);
|
||||
auto& page_data = page_data_ptr->ref();
|
||||
|
||||
page_data.m_profile_status->Hide();
|
||||
|
||||
EmulatedControllerPtr emulated_controller = page_data.m_controller;
|
||||
auto has_controllers = false;
|
||||
|
||||
// update emulated
|
||||
if(emulated_controller)
|
||||
{
|
||||
has_controllers = !emulated_controller->get_controllers().empty();
|
||||
|
||||
const auto emulated_type = emulated_controller->type();
|
||||
int index = page_data.m_emulated_controller->Append(to_wxString(emulated_controller->type_to_string(emulated_type)));
|
||||
page_data.m_emulated_controller->SetSelection(index);
|
||||
|
||||
const auto controller_selection = page_data.m_controllers->GetStringSelection();
|
||||
page_data.m_controllers->Clear();
|
||||
if (has_controllers)
|
||||
{
|
||||
for (const auto& c : emulated_controller->get_controllers())
|
||||
{
|
||||
page_data.m_controllers->Append(fmt::format("{} [{}]", c->display_name(), c->api_name()), new wxCustomData(c));
|
||||
}
|
||||
|
||||
if (page_data.m_controllers->GetCount() > 0)
|
||||
{
|
||||
page_data.m_controllers->SetSelection(0);
|
||||
if (!controller_selection.empty())
|
||||
page_data.m_controllers->SetStringSelection(controller_selection);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
page_data.m_emulated_controller->SetValue(_("Disabled"));
|
||||
}
|
||||
|
||||
ControllerPtr controller;
|
||||
if (page_data.m_controllers->GetSelection() != wxNOT_FOUND)
|
||||
{
|
||||
if (const auto data = (wxControllerData*)page_data.m_controllers->GetClientObject(page_data.m_controllers->GetSelection()))
|
||||
controller = data->ref();
|
||||
}
|
||||
|
||||
if (controller && controller->is_connected())
|
||||
page_data.m_controller_connected->SetBitmap(m_connected);
|
||||
else
|
||||
page_data.m_controller_connected->SetBitmap(m_disconnected);
|
||||
|
||||
// update controller
|
||||
page_data.m_controller_calibrate->Enable(has_controllers);
|
||||
page_data.m_controller_api_remove->Enable(has_controllers);
|
||||
page_data.m_controller_settings->Enable(controller && has_settings(controller->api()));
|
||||
|
||||
// update settings
|
||||
// update panel
|
||||
// test if we need to update to correct panel
|
||||
std::optional<EmulatedController::Type> active_api{};
|
||||
for(auto i = 0; i < EmulatedController::Type::MAX; ++i)
|
||||
{
|
||||
if(page_data.m_panels[i] && page_data.m_panels[i]->IsShown())
|
||||
{
|
||||
active_api = (EmulatedController::Type)i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// disabled and no emulated controller
|
||||
if (!active_api && !emulated_controller)
|
||||
return;
|
||||
|
||||
// enabled correct panel for active controller
|
||||
if (active_api && emulated_controller && emulated_controller->type() == active_api.value())
|
||||
return;
|
||||
|
||||
// hide all panels
|
||||
for (auto* panel : page_data.m_panels)
|
||||
{
|
||||
if (panel)
|
||||
panel->Hide();
|
||||
}
|
||||
|
||||
// show required panel
|
||||
if (emulated_controller)
|
||||
{
|
||||
auto* sizer = dynamic_cast<wxGridBagSizer*>(page->GetSizer());
|
||||
wxASSERT(sizer);
|
||||
|
||||
const auto type = page_data.m_controller->type();
|
||||
InputPanel* panel = page_data.m_panels[type];
|
||||
if (!panel)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case EmulatedController::Type::VPAD:
|
||||
panel = new VPADInputPanel(page);
|
||||
break;
|
||||
case EmulatedController::Pro:
|
||||
panel = new ProControllerInputPanel(page);
|
||||
break;
|
||||
case EmulatedController::Classic:
|
||||
panel = new ClassicControllerInputPanel(page);
|
||||
break;
|
||||
case EmulatedController::Wiimote:
|
||||
panel = new WiimoteInputPanel(page);
|
||||
break;
|
||||
default:
|
||||
cemu_assert_debug(false);
|
||||
return;
|
||||
}
|
||||
|
||||
page_data.m_panels[type] = panel;
|
||||
|
||||
auto* panel_sizer = sizer->FindItemAtPosition(wxGBPosition(7, 0))->GetSizer();
|
||||
wxASSERT(panel_sizer);
|
||||
panel_sizer->Add(panel, 0, wxEXPAND);
|
||||
}
|
||||
|
||||
panel->load_controller(page_data.m_controller);
|
||||
if (has_controllers)
|
||||
panel->set_selected_controller(emulated_controller, emulated_controller->get_controllers()[0]);
|
||||
|
||||
panel->Show();
|
||||
page->wxWindowBase::Layout();
|
||||
page->wxWindow::Update();
|
||||
}
|
||||
}
|
||||
|
||||
void InputSettings2::on_controller_changed()
|
||||
{
|
||||
for(auto i = 0 ; i < m_notebook->GetPageCount(); ++i)
|
||||
{
|
||||
auto* page = m_notebook->GetPage(i);
|
||||
if (!page)
|
||||
continue;
|
||||
|
||||
auto* page_data_ptr = (wxControllerPageData*)page->GetClientObject();
|
||||
if (!page_data_ptr)
|
||||
continue;
|
||||
|
||||
const auto& page_data = page_data_ptr->ref();
|
||||
if (page_data.m_controllers->GetSelection() != wxNOT_FOUND)
|
||||
{
|
||||
if (const auto data = (wxControllerData*)page_data.m_controllers->GetClientObject(page_data.m_controllers->GetSelection()))
|
||||
{
|
||||
if (const auto controller = data->ref())
|
||||
{
|
||||
if (controller->connect())
|
||||
page_data.m_controller_connected->SetBitmap(m_connected);
|
||||
else
|
||||
page_data.m_controller_connected->SetBitmap(m_disconnected);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void InputSettings2::on_notebook_page_changed(wxBookCtrlEvent& event)
|
||||
{
|
||||
initialize_page(event.GetSelection());
|
||||
update_state();
|
||||
event.Skip();
|
||||
}
|
||||
|
||||
void InputSettings2::on_timer(wxTimerEvent&)
|
||||
{
|
||||
auto& page_data = get_current_page_data();
|
||||
if (!page_data.m_controller) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto* panel = page_data.m_panels[page_data.m_controller->type()];
|
||||
if (!panel)
|
||||
return;
|
||||
|
||||
auto controller = get_active_controller();
|
||||
if (controller) {
|
||||
panel->on_timer(page_data.m_controller, controller);
|
||||
}
|
||||
}
|
||||
|
||||
void InputSettings2::on_left_click(wxMouseEvent& event)
|
||||
{
|
||||
event.Skip();
|
||||
|
||||
auto& page_data = get_current_page_data();
|
||||
if (!page_data.m_controller) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto* panel = page_data.m_panels[page_data.m_controller->type()];
|
||||
if (!panel)
|
||||
return;
|
||||
|
||||
panel->on_left_click(event);
|
||||
}
|
||||
|
||||
void InputSettings2::on_profile_dropdown(wxCommandEvent& event)
|
||||
{
|
||||
auto* profile_names = dynamic_cast<wxComboBox*>(event.GetEventObject());
|
||||
wxASSERT(profile_names);
|
||||
wxWindowUpdateLocker lock(profile_names);
|
||||
|
||||
const auto selected_value = profile_names->GetStringSelection();
|
||||
profile_names->Clear();
|
||||
|
||||
for(const auto& profile : InputManager::get_profiles())
|
||||
{
|
||||
profile_names->Append(wxString::FromUTF8(profile));
|
||||
}
|
||||
|
||||
profile_names->SetStringSelection(selected_value);
|
||||
}
|
||||
|
||||
void InputSettings2::on_profile_text_changed(wxCommandEvent& event)
|
||||
{
|
||||
auto* profile_names = dynamic_cast<wxComboBox*>(event.GetEventObject());
|
||||
wxASSERT(profile_names);
|
||||
|
||||
auto& page_data = get_current_page_data();
|
||||
|
||||
const auto selection = page_data.m_emulated_controller->GetStringSelection();
|
||||
|
||||
// load_bttn, save_bttn, delete_bttn, profile_status
|
||||
const auto text = event.GetString();
|
||||
const auto text_str = from_wxString(text);
|
||||
|
||||
const bool valid_name = InputManager::is_valid_profilename(text_str);
|
||||
const bool name_exists = profile_names->FindString(text) != wxNOT_FOUND;
|
||||
|
||||
page_data.m_profile_load->Enable(name_exists);
|
||||
page_data.m_profile_save->Enable(valid_name);
|
||||
page_data.m_profile_delete->Enable(name_exists);
|
||||
page_data.m_profile_status->Hide();
|
||||
}
|
||||
|
||||
void InputSettings2::on_profile_load(wxCommandEvent& event)
|
||||
{
|
||||
auto& page_data = get_current_page_data();
|
||||
|
||||
auto* profile_names = page_data.m_profiles;
|
||||
auto* text = page_data.m_profile_status;
|
||||
|
||||
const auto selection = from_wxString(profile_names->GetValue());
|
||||
text->Show();
|
||||
if (selection.empty() || !InputManager::is_valid_profilename(selection))
|
||||
{
|
||||
text->SetLabelText(_("invalid profile name"));
|
||||
text->SetForegroundColour(wxTheColourDatabase->Find("ERROR"));
|
||||
text->Refresh();
|
||||
return;
|
||||
}
|
||||
|
||||
const auto page_index = m_notebook->GetSelection();
|
||||
if (InputManager::instance().load(page_index, selection))
|
||||
{
|
||||
text->SetLabelText(_("profile loaded"));
|
||||
text->SetForegroundColour(wxTheColourDatabase->Find("SUCCESS"));
|
||||
}
|
||||
else
|
||||
{
|
||||
text->SetLabelText(_("couldn't load profile"));
|
||||
text->SetForegroundColour(wxTheColourDatabase->Find("ERROR"));
|
||||
}
|
||||
|
||||
text->Refresh();
|
||||
|
||||
// update controller info
|
||||
page_data.m_controller = InputManager::instance().get_controller(page_index);
|
||||
update_state();
|
||||
}
|
||||
|
||||
void InputSettings2::on_profile_save(wxCommandEvent& event)
|
||||
{
|
||||
auto& page_data = get_current_page_data();
|
||||
|
||||
auto* profile_names = page_data.m_profiles;
|
||||
auto* text = page_data.m_profile_status;
|
||||
|
||||
const auto selection = from_wxString(profile_names->GetValue());
|
||||
text->Show();
|
||||
if (selection.empty() || !InputManager::is_valid_profilename(selection))
|
||||
{
|
||||
text->SetLabelText(_("invalid profile name"));
|
||||
text->SetForegroundColour(wxTheColourDatabase->Find("ERROR"));
|
||||
text->Refresh();
|
||||
return;
|
||||
}
|
||||
|
||||
if(InputManager::instance().save(m_notebook->GetSelection(), selection))
|
||||
{
|
||||
text->SetLabelText(_("profile saved"));
|
||||
text->SetForegroundColour(wxTheColourDatabase->Find("SUCCESS"));
|
||||
}
|
||||
else
|
||||
{
|
||||
text->SetLabelText(_("couldn't save profile"));
|
||||
text->SetForegroundColour(wxTheColourDatabase->Find("ERROR"));
|
||||
}
|
||||
|
||||
text->Refresh();
|
||||
}
|
||||
|
||||
void InputSettings2::on_profile_delete(wxCommandEvent& event)
|
||||
{
|
||||
auto& page_data = get_current_page_data();
|
||||
|
||||
auto* profile_names = page_data.m_profiles;
|
||||
auto* text = page_data.m_profile_status;
|
||||
|
||||
const auto selection = from_wxString(profile_names->GetStringSelection());
|
||||
|
||||
text->Show();
|
||||
if (selection.empty() || !InputManager::is_valid_profilename(selection))
|
||||
{
|
||||
text->SetLabelText(_("invalid profile name"));
|
||||
text->SetForegroundColour(wxTheColourDatabase->Find("ERROR"));
|
||||
text->Refresh();
|
||||
return;
|
||||
}
|
||||
try
|
||||
{
|
||||
const fs::path old_path = ActiveSettings::GetPath(fmt::format("controllerProfiles/{}.txt", selection));
|
||||
fs::remove(old_path);
|
||||
|
||||
const fs::path path = ActiveSettings::GetPath(fmt::format("controllerProfiles/{}.xml", selection));
|
||||
fs::remove(path);
|
||||
|
||||
profile_names->ChangeValue(_(kDefaultProfileName));
|
||||
text->SetLabelText(_("profile deleted"));
|
||||
text->SetForegroundColour(wxTheColourDatabase->Find("SUCCESS"));
|
||||
|
||||
page_data.m_profile_load->Disable();
|
||||
page_data.m_profile_save->Disable();
|
||||
page_data.m_profile_delete->Disable();
|
||||
}
|
||||
catch (const std::exception&)
|
||||
{
|
||||
text->SetLabelText(_("can't delete profile"));
|
||||
text->SetForegroundColour(wxTheColourDatabase->Find("ERROR"));
|
||||
}
|
||||
text->Refresh();
|
||||
}
|
||||
|
||||
|
||||
void InputSettings2::on_controller_page_changed(wxBookCtrlEvent& event)
|
||||
{
|
||||
initialize_page(event.GetSelection());
|
||||
update_state();
|
||||
event.Skip();
|
||||
}
|
||||
|
||||
void InputSettings2::on_emulated_controller_selected(wxCommandEvent& event)
|
||||
{
|
||||
const auto page_index = m_notebook->GetSelection();
|
||||
auto& page_data = get_current_page_data();
|
||||
|
||||
const auto selection = event.GetSelection();
|
||||
if(selection == 0) // disabled selected
|
||||
{
|
||||
page_data.m_controller = {};
|
||||
InputManager::instance().delete_controller(page_index, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
const auto type_str = from_wxString(event.GetString());
|
||||
try
|
||||
{
|
||||
const auto type = EmulatedController::type_from_string(type_str);
|
||||
// same has already been selected
|
||||
if (page_data.m_controller && page_data.m_controller->type() == type)
|
||||
return;
|
||||
|
||||
// set new controller
|
||||
const auto new_controller = InputManager::instance().set_controller(page_index, type);
|
||||
page_data.m_controller = new_controller;
|
||||
|
||||
// append controllers if some were already added before
|
||||
if (new_controller->get_controllers().empty())
|
||||
{
|
||||
// test if we had no emulated controller before but still assigned controllers we want to transfer now
|
||||
for (uint32 i = 0; i < page_data.m_controllers->GetCount(); ++i)
|
||||
{
|
||||
if (auto* controller = (wxControllerData*)page_data.m_controllers->GetClientObject(i))
|
||||
{
|
||||
new_controller->add_controller(controller->ref());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// set default mappings if any controllers available
|
||||
for(const auto& c: new_controller->get_controllers())
|
||||
{
|
||||
new_controller->set_default_mapping(c);
|
||||
}
|
||||
}
|
||||
catch (const std::exception&)
|
||||
{
|
||||
cemu_assert_debug(false);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
update_state();
|
||||
}
|
||||
|
||||
void InputSettings2::on_emulated_controller_dropdown(wxCommandEvent& event)
|
||||
{
|
||||
auto* emulated_controllers = dynamic_cast<wxComboBox*>(event.GetEventObject());
|
||||
wxASSERT(emulated_controllers);
|
||||
|
||||
wxWindowUpdateLocker lock(emulated_controllers);
|
||||
|
||||
bool is_gamepad_selected = false;
|
||||
const auto selected = emulated_controllers->GetSelection();
|
||||
const auto selected_value = emulated_controllers->GetStringSelection();
|
||||
if(selected != wxNOT_FOUND)
|
||||
{
|
||||
is_gamepad_selected = selected_value == to_wxString(EmulatedController::type_to_string(EmulatedController::Type::VPAD));
|
||||
}
|
||||
|
||||
const auto [vpad_count, wpad_count] = get_emulated_controller_types();
|
||||
|
||||
emulated_controllers->Clear();
|
||||
emulated_controllers->AppendString(_("Disabled"));
|
||||
|
||||
if (vpad_count < InputManager::kMaxVPADControllers || is_gamepad_selected)
|
||||
emulated_controllers->Append(to_wxString(EmulatedController::type_to_string(EmulatedController::Type::VPAD)));
|
||||
|
||||
if (wpad_count < InputManager::kMaxWPADControllers || !is_gamepad_selected)
|
||||
{
|
||||
emulated_controllers->AppendString(to_wxString(EmulatedController::type_to_string(EmulatedController::Type::Pro)));
|
||||
emulated_controllers->AppendString(to_wxString(EmulatedController::type_to_string(EmulatedController::Type::Classic)));
|
||||
emulated_controllers->AppendString(to_wxString(EmulatedController::type_to_string(EmulatedController::Type::Wiimote)));
|
||||
}
|
||||
|
||||
emulated_controllers->SetStringSelection(selected_value);
|
||||
}
|
||||
|
||||
void InputSettings2::on_controller_selected(wxCommandEvent& event)
|
||||
{
|
||||
auto& page_data = get_current_page_data();
|
||||
|
||||
const auto enabled = event.GetSelection() != wxNOT_FOUND;
|
||||
page_data.m_controller_api_remove->Enable(enabled);
|
||||
// page_data->ref().m_controller_list->Clear();
|
||||
if(enabled)
|
||||
{
|
||||
// get selected controller if any todo
|
||||
if (auto* controller = (wxControllerData*)page_data.m_controllers->GetClientObject(event.GetSelection()))
|
||||
{
|
||||
page_data.m_controller_settings->Enable(has_settings(controller->ref()->api()));
|
||||
|
||||
if(page_data.m_controller)
|
||||
{
|
||||
page_data.m_panels[page_data.m_controller->type()]->set_selected_controller(page_data.m_controller, controller->ref());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void InputSettings2::on_controller_dropdown(wxCommandEvent& event)
|
||||
{
|
||||
if(auto* controllers = dynamic_cast<wxComboBox*>(event.GetEventObject()))
|
||||
{
|
||||
if(controllers->GetCount()== 0)
|
||||
{
|
||||
on_controller_add(event);
|
||||
controllers->SetSelection(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ControllerPage& InputSettings2::get_current_page_data() const
|
||||
{
|
||||
auto* page = m_notebook->GetCurrentPage();
|
||||
auto* page_data_ptr = (wxControllerPageData*)page->GetClientObject();
|
||||
wxASSERT(page_data_ptr);
|
||||
return page_data_ptr->ref();
|
||||
}
|
||||
|
||||
void InputSettings2::on_controller_connect(wxCommandEvent& event)
|
||||
{
|
||||
auto& page_data = get_current_page_data();
|
||||
|
||||
if (page_data.m_controllers->GetSelection() != wxNOT_FOUND)
|
||||
{
|
||||
if (const auto data = (wxControllerData*)page_data.m_controllers->GetClientObject(page_data.m_controllers->GetSelection()))
|
||||
{
|
||||
if(const auto controller = data->ref())
|
||||
{
|
||||
if(controller->connect())
|
||||
page_data.m_controller_connected->SetBitmap(m_connected);
|
||||
else
|
||||
page_data.m_controller_connected->SetBitmap(m_disconnected);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void InputSettings2::on_controller_add(wxCommandEvent& event)
|
||||
{
|
||||
auto& page_data = get_current_page_data();
|
||||
|
||||
std::vector<ControllerPtr> controllers;
|
||||
controllers.reserve(page_data.m_controllers->GetCount());
|
||||
for(uint32 i = 0; i < page_data.m_controllers->GetCount(); ++i)
|
||||
{
|
||||
if (auto* controller = (wxControllerData*)page_data.m_controllers->GetClientObject(i))
|
||||
controllers.emplace_back(controller->ref());
|
||||
}
|
||||
|
||||
InputAPIAddWindow wnd(this, wxGetMousePosition() + wxSize(5, 5), controllers);
|
||||
if (wnd.ShowModal() != wxID_OK)
|
||||
return;
|
||||
|
||||
wxASSERT(wnd.is_valid());
|
||||
|
||||
const auto controller = wnd.get_controller();
|
||||
|
||||
const auto api_type = wnd.get_type();
|
||||
controller->connect();
|
||||
const int index = page_data.m_controllers->Append(fmt::format("{} [{}]", controller->display_name(), to_string(api_type)), new wxCustomData(controller));
|
||||
|
||||
page_data.m_controllers->Select(index);
|
||||
|
||||
if(page_data.m_controller)
|
||||
{
|
||||
page_data.m_controller->add_controller(controller);
|
||||
|
||||
const auto type = page_data.m_controller->type();
|
||||
// if first controller and we got no mappings, add default mappings
|
||||
if(page_data.m_controller->set_default_mapping(controller))
|
||||
page_data.m_panels[type]->load_controller(page_data.m_controller);
|
||||
|
||||
page_data.m_panels[type]->set_selected_controller(page_data.m_controller, controller);
|
||||
}
|
||||
|
||||
update_state();
|
||||
}
|
||||
|
||||
void InputSettings2::on_controller_remove(wxCommandEvent& event)
|
||||
{
|
||||
auto& page_data = get_current_page_data();
|
||||
|
||||
auto* api_box = page_data.m_controllers;
|
||||
int selection = api_box->GetSelection();
|
||||
if (selection == wxNOT_FOUND)
|
||||
return;
|
||||
|
||||
if (page_data.m_controller) {
|
||||
if (auto* controller = (wxControllerData*)page_data.m_controllers->GetClientObject(selection))
|
||||
{
|
||||
page_data.m_controller->remove_controller(controller->ref());
|
||||
page_data.m_panels[page_data.m_controller->type()]->load_controller(page_data.m_controller);
|
||||
}
|
||||
}
|
||||
|
||||
page_data.m_panels[page_data.m_controller->type()]->reset_colours();
|
||||
|
||||
api_box->Delete(selection);
|
||||
api_box->Refresh();
|
||||
|
||||
update_state();
|
||||
|
||||
if (api_box->GetCount() > 0)
|
||||
{
|
||||
selection = selection > 0 ? (selection - 1) : 0;
|
||||
api_box->SetSelection(selection);
|
||||
}
|
||||
|
||||
update_state();
|
||||
}
|
||||
|
||||
void InputSettings2::on_controller_calibrate(wxCommandEvent& event)
|
||||
{
|
||||
if(const auto controller = get_active_controller())
|
||||
controller->calibrate();
|
||||
}
|
||||
|
||||
void InputSettings2::on_controller_clear(wxCommandEvent& event)
|
||||
{
|
||||
auto& page_data = get_current_page_data();
|
||||
if (page_data.m_controller) {
|
||||
const auto type = page_data.m_controller->type();
|
||||
|
||||
page_data.m_panels[type]->reset_configuration();
|
||||
page_data.m_controller->clear_mappings();
|
||||
}
|
||||
}
|
||||
|
||||
void InputSettings2::on_controller_settings(wxCommandEvent& event)
|
||||
{
|
||||
auto controller = get_active_controller();
|
||||
if (!controller)
|
||||
return;
|
||||
|
||||
switch(controller->api())
|
||||
{
|
||||
|
||||
case InputAPI::DirectInput:
|
||||
case InputAPI::XInput:
|
||||
case InputAPI::GameCube:
|
||||
case InputAPI::WGIGamepad:
|
||||
case InputAPI::WGIRawController:
|
||||
case InputAPI::SDLController:
|
||||
case InputAPI::DSUClient:
|
||||
{
|
||||
DefaultControllerSettings wnd(this, wxGetMousePosition() + wxSize(5, 5), controller);
|
||||
wnd.ShowModal();
|
||||
break;
|
||||
}
|
||||
|
||||
case InputAPI::Keyboard: break;
|
||||
|
||||
#if BOOST_OS_WINDOWS
|
||||
case InputAPI::Wiimote: {
|
||||
const auto wiimote = std::dynamic_pointer_cast<NativeWiimoteController>(controller);
|
||||
wxASSERT(wiimote);
|
||||
WiimoteControllerSettings wnd(this, wxGetMousePosition() + wxSize(5, 5), wiimote);
|
||||
wnd.ShowModal();
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
74
src/gui/input/InputSettings2.h
Normal file
74
src/gui/input/InputSettings2.h
Normal file
|
@ -0,0 +1,74 @@
|
|||
#pragma once
|
||||
|
||||
#include <wx/dialog.h>
|
||||
#include <wx/notebook.h>
|
||||
#include <wx/timer.h>
|
||||
|
||||
#include "input/api/InputAPI.h"
|
||||
|
||||
#include <boost/signals2/connection.hpp>
|
||||
|
||||
struct ControllerPage;
|
||||
class ControllerBase;
|
||||
|
||||
class InputSettings2 : public wxDialog
|
||||
{
|
||||
public:
|
||||
InputSettings2(wxWindow* parent);
|
||||
~InputSettings2();
|
||||
|
||||
private:
|
||||
wxNotebook* m_notebook;
|
||||
wxTimer* m_timer;
|
||||
|
||||
wxBitmap m_connected, m_disconnected, m_low_battery;
|
||||
|
||||
wxWindow* initialize_page(size_t index);
|
||||
|
||||
// count active <vpad, wpad> controllers
|
||||
std::pair<size_t, size_t> get_emulated_controller_types() const;
|
||||
|
||||
// currently selected controller from active tab
|
||||
std::shared_ptr<ControllerBase> get_active_controller() const;
|
||||
|
||||
bool has_settings(InputAPI::Type type);
|
||||
ControllerPage& get_current_page_data() const;
|
||||
void update_state();
|
||||
|
||||
boost::signals2::connection m_controller_changed;
|
||||
void on_controller_changed();
|
||||
|
||||
// events
|
||||
void on_notebook_page_changed(wxBookCtrlEvent& event);
|
||||
void on_timer(wxTimerEvent& event);
|
||||
|
||||
void on_left_click(wxMouseEvent& event);
|
||||
|
||||
void on_controller_page_changed(wxBookCtrlEvent& event);
|
||||
|
||||
void on_profile_dropdown(wxCommandEvent& event);
|
||||
void on_profile_text_changed(wxCommandEvent& event);
|
||||
|
||||
void on_profile_load(wxCommandEvent& event);
|
||||
void on_profile_save(wxCommandEvent& event);
|
||||
void on_profile_delete(wxCommandEvent& event);
|
||||
|
||||
void on_emulated_controller_selected(wxCommandEvent& event);
|
||||
void on_emulated_controller_dropdown(wxCommandEvent& event);
|
||||
|
||||
void on_controller_selected(wxCommandEvent& event);
|
||||
void on_controller_dropdown(wxCommandEvent& event);
|
||||
void on_controller_connect(wxCommandEvent& event);
|
||||
|
||||
void on_controller_add(wxCommandEvent& event);
|
||||
void on_controller_remove(wxCommandEvent& event);
|
||||
|
||||
void on_controller_calibrate(wxCommandEvent& event);
|
||||
void on_controller_clear(wxCommandEvent& event);
|
||||
void on_controller_settings(wxCommandEvent& event);
|
||||
|
||||
// void on_controller_dropdown(wxCommandEvent& event);
|
||||
// void on_controllers_refreshed(wxCommandEvent& event);
|
||||
|
||||
};
|
||||
|
139
src/gui/input/panels/ClassicControllerInputPanel.cpp
Normal file
139
src/gui/input/panels/ClassicControllerInputPanel.cpp
Normal file
|
@ -0,0 +1,139 @@
|
|||
#include "gui/input/panels/ClassicControllerInputPanel.h"
|
||||
|
||||
#include <wx/gbsizer.h>
|
||||
#include <wx/stattext.h>
|
||||
#include <wx/statline.h>
|
||||
#include <wx/textctrl.h>
|
||||
#include <wx/slider.h>
|
||||
|
||||
#include "gui/helpers/wxControlObject.h"
|
||||
#include "input/emulated/ClassicController.h"
|
||||
#include "gui/helpers/wxHelpers.h"
|
||||
#include "gui/components/wxInputDraw.h"
|
||||
|
||||
constexpr ClassicController::ButtonId g_kFirstColumnItems[] = { ClassicController::kButtonId_A, ClassicController::kButtonId_B, ClassicController::kButtonId_X, ClassicController::kButtonId_Y, ClassicController::kButtonId_L, ClassicController::kButtonId_R, ClassicController::kButtonId_ZL, ClassicController::kButtonId_ZR, ClassicController::kButtonId_Plus, ClassicController::kButtonId_Minus };
|
||||
constexpr ClassicController::ButtonId g_kSecondColumnItems[] = { ClassicController::kButtonId_StickL_Up, ClassicController::kButtonId_StickL_Down, ClassicController::kButtonId_StickL_Left, ClassicController::kButtonId_StickL_Right };
|
||||
constexpr ClassicController::ButtonId g_kThirdColumnItems[] = { ClassicController::kButtonId_StickR_Up, ClassicController::kButtonId_StickR_Down, ClassicController::kButtonId_StickR_Left, ClassicController::kButtonId_StickR_Right };
|
||||
constexpr ClassicController::ButtonId g_kFourthRowItems[] = { ClassicController::kButtonId_Up, ClassicController::kButtonId_Down, ClassicController::kButtonId_Left, ClassicController::kButtonId_Right };
|
||||
|
||||
|
||||
ClassicControllerInputPanel::ClassicControllerInputPanel(wxWindow* parent)
|
||||
: InputPanel(parent)
|
||||
{
|
||||
auto bold_font = GetFont();
|
||||
bold_font.MakeBold();
|
||||
|
||||
auto* main_sizer = new wxGridBagSizer();
|
||||
sint32 row = 0;
|
||||
sint32 column = 0;
|
||||
for (const auto& id : g_kFirstColumnItems)
|
||||
{
|
||||
row++;
|
||||
|
||||
main_sizer->Add(new wxStaticText(this, wxID_ANY, to_wxString(ClassicController::get_button_name(id))), wxGBPosition(row, column), wxDefaultSpan, wxALL | wxALIGN_CENTER_VERTICAL, 5);
|
||||
|
||||
auto* text_ctrl = new wxTextCtrl(this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL | wxTE_PROCESS_ENTER | wxTE_PROCESS_TAB);
|
||||
text_ctrl->SetClientData(reinterpret_cast<void*>(id));
|
||||
text_ctrl->SetMinSize(wxSize(150, -1));
|
||||
text_ctrl->SetEditable(false);
|
||||
text_ctrl->SetBackgroundColour(kKeyColourNormalMode);
|
||||
bind_hotkey_events(text_ctrl);
|
||||
main_sizer->Add(text_ctrl, wxGBPosition(row, column + 1), wxDefaultSpan, wxALL | wxEXPAND, 5);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////
|
||||
|
||||
main_sizer->Add(new wxStaticLine(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxVERTICAL), wxGBPosition(0, column + 2), wxGBSpan(11, 1), wxALL | wxEXPAND, 5);
|
||||
|
||||
row = 0;
|
||||
column += 3;
|
||||
|
||||
auto text = new wxStaticText(this, wxID_ANY, _("Left Axis"));
|
||||
text->SetFont(bold_font);
|
||||
main_sizer->Add(text, wxGBPosition(row, column), wxGBSpan(1, 3), wxALL | wxEXPAND, 5);
|
||||
|
||||
for (const auto& id : g_kSecondColumnItems)
|
||||
{
|
||||
row++;
|
||||
|
||||
main_sizer->Add(new wxStaticText(this, wxID_ANY, to_wxString(ClassicController::get_button_name(id))), wxGBPosition(row, column), wxDefaultSpan, wxALL | wxALIGN_CENTER_VERTICAL, 5);
|
||||
|
||||
auto* text_ctrl = new wxTextCtrl(this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL | wxTE_PROCESS_ENTER | wxTE_PROCESS_TAB);
|
||||
text_ctrl->SetClientData(reinterpret_cast<void*>(id));
|
||||
text_ctrl->SetMinSize(wxSize(150, -1));
|
||||
text_ctrl->SetEditable(false);
|
||||
text_ctrl->SetBackgroundColour(kKeyColourNormalMode);
|
||||
bind_hotkey_events(text_ctrl);
|
||||
main_sizer->Add(text_ctrl, wxGBPosition(row, column + 1), wxDefaultSpan, wxALL | wxEXPAND, 5);
|
||||
}
|
||||
|
||||
row++;
|
||||
|
||||
// input drawer
|
||||
m_left_draw = new wxInputDraw(this, wxID_ANY, wxDefaultPosition, { 60, 60 });
|
||||
main_sizer->Add(m_left_draw, wxGBPosition(row, column + 1), wxGBSpan(2, 1), wxTOP | wxBOTTOM | wxEXPAND | wxALIGN_CENTER, 5);
|
||||
|
||||
main_sizer->Add(new wxStaticLine(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxVERTICAL), wxGBPosition(0, column + 3), wxGBSpan(11, 1), wxALL | wxEXPAND, 5);
|
||||
|
||||
//////////////////////////////////////////////////////////////////
|
||||
|
||||
row = 0;
|
||||
column += 4;
|
||||
|
||||
text = new wxStaticText(this, wxID_ANY, _("Right Axis"));
|
||||
text->SetFont(bold_font);
|
||||
main_sizer->Add(text, wxGBPosition(row, column), wxGBSpan(1, 3), wxALL | wxEXPAND, 5);
|
||||
|
||||
for (const auto& id : g_kThirdColumnItems)
|
||||
{
|
||||
row++;
|
||||
|
||||
main_sizer->Add(new wxStaticText(this, wxID_ANY, to_wxString(ClassicController::get_button_name(id))), wxGBPosition(row, column), wxDefaultSpan, wxALL | wxALIGN_CENTER_VERTICAL, 5);
|
||||
|
||||
auto* text_ctrl = new wxTextCtrl(this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL | wxTE_PROCESS_ENTER | wxTE_PROCESS_TAB);
|
||||
text_ctrl->SetClientData(reinterpret_cast<void*>(id));
|
||||
text_ctrl->SetMinSize(wxSize(150, -1));
|
||||
text_ctrl->SetEditable(false);
|
||||
text_ctrl->SetBackgroundColour(kKeyColourNormalMode);
|
||||
bind_hotkey_events(text_ctrl);
|
||||
main_sizer->Add(text_ctrl, wxGBPosition(row, column + 1), wxDefaultSpan, wxALL | wxEXPAND, 5);
|
||||
}
|
||||
|
||||
row++;
|
||||
|
||||
// input drawer
|
||||
m_right_draw = new wxInputDraw(this, wxID_ANY, wxDefaultPosition, { 60, 60 });
|
||||
main_sizer->Add(m_right_draw, wxGBPosition(row, column + 1), wxGBSpan(2, 1), wxTOP | wxBOTTOM | wxEXPAND | wxALIGN_CENTER, 5);
|
||||
|
||||
main_sizer->Add(new wxStaticLine(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxVERTICAL), wxGBPosition(0, column + 3), wxGBSpan(11, 1), wxALL | wxEXPAND, 5);
|
||||
|
||||
//////////////////////////////////////////////////////////////////
|
||||
|
||||
row = 0;
|
||||
column += 4;
|
||||
|
||||
text = new wxStaticText(this, wxID_ANY, _("D-pad"));
|
||||
text->SetFont(bold_font);
|
||||
main_sizer->Add(text, wxGBPosition(row, column), wxGBSpan(1, 3), wxALL | wxEXPAND, 5);
|
||||
|
||||
for (auto id : g_kFourthRowItems)
|
||||
{
|
||||
row++;
|
||||
|
||||
main_sizer->Add(new wxStaticText(this, wxID_ANY, to_wxString(ClassicController::get_button_name(id))), wxGBPosition(row, column), wxDefaultSpan, wxALL | wxALIGN_CENTER_VERTICAL, 5);
|
||||
|
||||
auto* text_ctrl = new wxTextCtrl(this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL | wxTE_PROCESS_ENTER | wxTE_PROCESS_TAB);
|
||||
text_ctrl->SetClientData(reinterpret_cast<void*>(id));
|
||||
text_ctrl->SetMinSize(wxSize(150, -1));
|
||||
text_ctrl->SetEditable(false);
|
||||
text_ctrl->SetBackgroundColour(kKeyColourNormalMode);
|
||||
bind_hotkey_events(text_ctrl);
|
||||
main_sizer->Add(text_ctrl, wxGBPosition(row, column + 1), wxDefaultSpan, wxALL | wxEXPAND, 5);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
SetSizer(main_sizer);
|
||||
Layout();
|
||||
}
|
15
src/gui/input/panels/ClassicControllerInputPanel.h
Normal file
15
src/gui/input/panels/ClassicControllerInputPanel.h
Normal file
|
@ -0,0 +1,15 @@
|
|||
#pragma once
|
||||
|
||||
#include "gui/input/panels/InputPanel.h"
|
||||
|
||||
class wxInputDraw;
|
||||
|
||||
class ClassicControllerInputPanel : public InputPanel
|
||||
{
|
||||
public:
|
||||
ClassicControllerInputPanel(wxWindow* parent);
|
||||
|
||||
private:
|
||||
wxInputDraw* m_left_draw, * m_right_draw;
|
||||
};
|
||||
|
287
src/gui/input/panels/InputPanel.cpp
Normal file
287
src/gui/input/panels/InputPanel.cpp
Normal file
|
@ -0,0 +1,287 @@
|
|||
#include "gui/input/panels/InputPanel.h"
|
||||
|
||||
#include <wx/textctrl.h>
|
||||
#include <wx/wupdlock.h>
|
||||
|
||||
#include "gui/helpers/wxHelpers.h"
|
||||
|
||||
InputPanel::InputPanel(wxWindow* parent)
|
||||
: wxPanel(parent, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL | wxNO_BORDER | wxWANTS_CHARS)
|
||||
{
|
||||
Bind(wxEVT_LEFT_UP, &InputPanel::on_left_click, this);
|
||||
}
|
||||
|
||||
void InputPanel::on_timer(const EmulatedControllerPtr& emulated_controller, const ControllerPtr& controller)
|
||||
{
|
||||
const auto& state = controller->update_state();
|
||||
|
||||
if(m_focused_element == wxID_NONE)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
const auto element = dynamic_cast<wxTextCtrl*>(FindWindow(m_focused_element));
|
||||
wxASSERT(element);
|
||||
|
||||
const auto mapping = reinterpret_cast<uint64>(element->GetClientData());
|
||||
|
||||
// reset mapping
|
||||
if(std::exchange(m_right_down, false) || wxGetKeyState(WXK_ESCAPE))
|
||||
{
|
||||
element->SetBackgroundColour(kKeyColourNormalMode);
|
||||
m_color_backup[element->GetId()] = kKeyColourNormalMode;
|
||||
|
||||
emulated_controller->delete_mapping(mapping);
|
||||
if(element->IsEmpty())
|
||||
reset_focused_element();
|
||||
else
|
||||
element->SetValue(wxEmptyString);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static bool s_was_idle = true;
|
||||
if (state.buttons.none()) {
|
||||
s_was_idle = true;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!s_was_idle) {
|
||||
return;
|
||||
}
|
||||
|
||||
s_was_idle = false;
|
||||
for (size_t i = 0; i < state.buttons.size(); ++i)
|
||||
{
|
||||
if (state.buttons[i])
|
||||
{
|
||||
if (controller->has_axis()) {
|
||||
// test if one axis direction is pressed more than the other
|
||||
if ((i == kAxisXP || i == kAxisXN) && (state.buttons[kAxisYP] || state.buttons[kAxisYN]))
|
||||
{
|
||||
if (std::abs(state.axis.y) > std::abs(state.axis.x))
|
||||
continue;
|
||||
}
|
||||
else if ((i == kAxisYP || i == kAxisYN) && (state.buttons[kAxisXP] || state.buttons[kAxisXN]))
|
||||
{
|
||||
if (std::abs(state.axis.x) > std::abs(state.axis.y))
|
||||
continue;
|
||||
}
|
||||
else if ((i == kRotationXP || i == kRotationXN) && (state.buttons[kRotationYP] || state.buttons[kRotationYN]))
|
||||
{
|
||||
if (std::abs(state.rotation.y) > std::abs(state.rotation.x))
|
||||
continue;
|
||||
}
|
||||
else if ((i == kRotationYP || i == kRotationYN) && (state.buttons[kRotationXP] || state.buttons[kRotationXN]))
|
||||
{
|
||||
if (std::abs(state.rotation.x) > std::abs(state.rotation.y))
|
||||
continue;
|
||||
}
|
||||
else if ((i == kTriggerXP || i == kTriggerXN) && (state.buttons[kTriggerYP] || state.buttons[kTriggerYN]))
|
||||
{
|
||||
if (std::abs(state.trigger.y) > std::abs(state.trigger.x))
|
||||
continue;
|
||||
}
|
||||
else if ((i == kTriggerYP || i == kTriggerYN) && (state.buttons[kTriggerXP] || state.buttons[kTriggerXN]))
|
||||
{
|
||||
if (std::abs(state.trigger.x) > std::abs(state.trigger.y))
|
||||
continue;
|
||||
}
|
||||
|
||||
// ignore too low button values on configuration
|
||||
if (i >= kButtonAxisStart)
|
||||
{
|
||||
if (controller->get_axis_value(i) < 0.33f) {
|
||||
forceLogDebug_printf("skipping since value too low %f", controller->get_axis_value(i));
|
||||
s_was_idle = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
emulated_controller->set_mapping(mapping, controller, i);
|
||||
element->SetValue(controller->get_button_name(i));
|
||||
element->SetBackgroundColour(kKeyColourNormalMode);
|
||||
m_color_backup[element->GetId()] = kKeyColourNormalMode;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (const auto sibling = get_next_sibling(element))
|
||||
sibling->SetFocus();
|
||||
else // last element reached
|
||||
{
|
||||
reset_focused_element();
|
||||
this->SetFocusIgnoringChildren();
|
||||
}
|
||||
}
|
||||
|
||||
void InputPanel::reset_configuration()
|
||||
{
|
||||
m_color_backup.clear();
|
||||
|
||||
wxWindowUpdateLocker lock(this);
|
||||
for (const auto& c : GetChildren())
|
||||
{
|
||||
if (auto* text = dynamic_cast<wxTextCtrl*>(c))
|
||||
{
|
||||
text->SetValue(wxEmptyString);
|
||||
text->SetBackgroundColour(kKeyColourNormalMode);
|
||||
text->Refresh();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void InputPanel::reset_colours()
|
||||
{
|
||||
m_color_backup.clear();
|
||||
|
||||
wxWindowUpdateLocker lock(this);
|
||||
for (const auto& c : GetChildren())
|
||||
{
|
||||
if (auto* text = dynamic_cast<wxTextCtrl*>(c))
|
||||
{
|
||||
text->SetBackgroundColour(kKeyColourNormalMode);
|
||||
text->Refresh();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void InputPanel::load_controller(const EmulatedControllerPtr& controller)
|
||||
{
|
||||
reset_configuration();
|
||||
if(!controller)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if(controller->get_controllers().empty())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
wxWindowUpdateLocker lock(this);
|
||||
for (auto* child : this->GetChildren())
|
||||
{
|
||||
const auto text = dynamic_cast<wxTextCtrl*>(child);
|
||||
if (text == nullptr)
|
||||
continue;
|
||||
|
||||
|
||||
const auto mapping = reinterpret_cast<sint64>(text->GetClientData());
|
||||
if (mapping <= 0)
|
||||
continue;
|
||||
|
||||
auto button_name = controller->get_mapping_name(mapping);
|
||||
#if BOOST_OS_WINDOWS
|
||||
text->SetLabelText(button_name);
|
||||
#else
|
||||
// SetLabelText doesn't seem to work here for some reason on wxGTK
|
||||
text->ChangeValue(button_name);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
void InputPanel::set_selected_controller(const EmulatedControllerPtr& emulated_controller, const ControllerPtr& controller)
|
||||
{
|
||||
wxWindowUpdateLocker lock(this);
|
||||
for (auto* child : this->GetChildren())
|
||||
{
|
||||
const auto text = dynamic_cast<wxTextCtrl*>(child);
|
||||
if (text == nullptr)
|
||||
continue;
|
||||
|
||||
if (text->GetId() == m_focused_element)
|
||||
continue;
|
||||
|
||||
const auto mapping = reinterpret_cast<sint64>(text->GetClientData());
|
||||
if (mapping <= 0)
|
||||
continue;
|
||||
|
||||
const auto mapping_controller = emulated_controller->get_mapping_controller(mapping);
|
||||
if (!mapping_controller)
|
||||
continue;
|
||||
|
||||
text->SetBackgroundColour(*mapping_controller == *controller ? kKeyColourNormalMode : kKeyColourActiveMode);
|
||||
text->Refresh();
|
||||
}
|
||||
}
|
||||
|
||||
void InputPanel::bind_hotkey_events(wxTextCtrl* text_ctrl)
|
||||
{
|
||||
text_ctrl->Bind(wxEVT_SET_FOCUS, &InputPanel::on_edit_key_focus, this);
|
||||
text_ctrl->Bind(wxEVT_KILL_FOCUS, &InputPanel::on_edit_key_kill_focus, this);
|
||||
text_ctrl->Bind(wxEVT_RIGHT_DOWN, &InputPanel::on_right_click, this);
|
||||
}
|
||||
|
||||
void InputPanel::on_left_click(wxMouseEvent& event)
|
||||
{
|
||||
if (m_focused_element == wxID_NONE)
|
||||
return;
|
||||
|
||||
const auto focuses_element = FindWindow(m_focused_element);
|
||||
wxASSERT(focuses_element);
|
||||
|
||||
wxFocusEvent focus(wxEVT_KILL_FOCUS, m_focused_element);
|
||||
focus.SetWindow(focuses_element);
|
||||
focuses_element->GetEventHandler()->ProcessEvent(focus);
|
||||
|
||||
this->SetFocusIgnoringChildren();
|
||||
}
|
||||
|
||||
void InputPanel::on_edit_key_focus(wxFocusEvent& event)
|
||||
{
|
||||
auto* text = dynamic_cast<wxTextCtrl*>(event.GetEventObject());
|
||||
wxASSERT(text);
|
||||
|
||||
m_color_backup[text->GetId()] = text->GetBackgroundColour();
|
||||
|
||||
text->SetBackgroundColour(kKeyColourEditMode);
|
||||
#if BOOST_OS_WINDOWS
|
||||
text->HideNativeCaret();
|
||||
#endif
|
||||
text->Refresh();
|
||||
|
||||
m_focused_element = text->GetId();
|
||||
event.Skip();
|
||||
}
|
||||
|
||||
void InputPanel::on_edit_key_kill_focus(wxFocusEvent& event)
|
||||
{
|
||||
reset_focused_element();
|
||||
event.Skip();
|
||||
}
|
||||
|
||||
void InputPanel::on_right_click(wxMouseEvent& event)
|
||||
{
|
||||
m_right_down = true;
|
||||
if(m_focused_element == wxID_NONE)
|
||||
{
|
||||
auto* text = dynamic_cast<wxTextCtrl*>(event.GetEventObject());
|
||||
wxASSERT(text);
|
||||
text->SetFocus();
|
||||
}
|
||||
}
|
||||
|
||||
bool InputPanel::reset_focused_element()
|
||||
{
|
||||
if (m_focused_element == wxID_NONE)
|
||||
return false;
|
||||
|
||||
auto* prev_element = dynamic_cast<wxTextCtrl*>(FindWindow(m_focused_element));
|
||||
wxASSERT(prev_element);
|
||||
|
||||
if(m_color_backup.find(prev_element->GetId()) != m_color_backup.cend())
|
||||
prev_element->SetBackgroundColour(m_color_backup[prev_element->GetId()]);
|
||||
else
|
||||
prev_element->SetBackgroundColour(kKeyColourNormalMode);
|
||||
|
||||
#if BOOST_OS_WINDOWS
|
||||
prev_element->HideNativeCaret();
|
||||
#endif
|
||||
prev_element->Refresh();
|
||||
|
||||
m_focused_element = wxID_NONE;
|
||||
return true;
|
||||
}
|
45
src/gui/input/panels/InputPanel.h
Normal file
45
src/gui/input/panels/InputPanel.h
Normal file
|
@ -0,0 +1,45 @@
|
|||
#pragma once
|
||||
|
||||
#include <wx/panel.h>
|
||||
|
||||
#include "input/emulated/EmulatedController.h"
|
||||
#include "input/api/Controller.h"
|
||||
|
||||
class ControllerBase;
|
||||
class wxTextCtrl;
|
||||
class wxComboBox;
|
||||
|
||||
class InputPanel : public wxPanel
|
||||
{
|
||||
public:
|
||||
const wxColour kKeyColourNormalMode = 0xfafafa;
|
||||
const wxColour kKeyColourEditMode = 0x99ccff;
|
||||
const wxColour kKeyColourActiveMode = 0xE0E0E0;
|
||||
|
||||
InputPanel(wxWindow* parent);
|
||||
|
||||
ControllerPtr get_active_controller() const;
|
||||
|
||||
virtual void on_timer(const EmulatedControllerPtr& emulated_controller, const ControllerPtr& controller);
|
||||
void on_left_click(wxMouseEvent& event);
|
||||
|
||||
void reset_configuration();
|
||||
virtual void load_controller(const EmulatedControllerPtr& controller);
|
||||
|
||||
void set_selected_controller(const EmulatedControllerPtr& emulated_controller, const ControllerPtr& controller_base);
|
||||
void reset_colours();
|
||||
|
||||
protected:
|
||||
void bind_hotkey_events(wxTextCtrl* text_ctrl);
|
||||
|
||||
void on_edit_key_focus(wxFocusEvent& event);
|
||||
void on_edit_key_kill_focus(wxFocusEvent& event);
|
||||
void on_right_click(wxMouseEvent& event);
|
||||
|
||||
bool reset_focused_element();
|
||||
|
||||
bool m_right_down = false;
|
||||
int m_focused_element = wxID_NONE;
|
||||
std::unordered_map<int, wxColour> m_color_backup;
|
||||
};
|
||||
|
156
src/gui/input/panels/ProControllerInputPanel.cpp
Normal file
156
src/gui/input/panels/ProControllerInputPanel.cpp
Normal file
|
@ -0,0 +1,156 @@
|
|||
#include "gui/input/panels/ProControllerInputPanel.h"
|
||||
|
||||
#include <wx/gbsizer.h>
|
||||
#include <wx/stattext.h>
|
||||
#include <wx/statline.h>
|
||||
#include <wx/textctrl.h>
|
||||
#include <wx/slider.h>
|
||||
|
||||
#include "gui/helpers/wxControlObject.h"
|
||||
#include "input/emulated/ProController.h"
|
||||
#include "gui/helpers/wxHelpers.h"
|
||||
#include "gui/components/wxInputDraw.h"
|
||||
|
||||
const ProController::ButtonId g_kFirstColumnItems[] = { ProController::kButtonId_A, ProController::kButtonId_B, ProController::kButtonId_X, ProController::kButtonId_Y, ProController::kButtonId_L, ProController::kButtonId_R, ProController::kButtonId_ZL, ProController::kButtonId_ZR, ProController::kButtonId_Plus, ProController::kButtonId_Minus };
|
||||
const ProController::ButtonId g_kSecondColumnItems[] = { ProController::kButtonId_StickL, ProController::kButtonId_StickL_Up, ProController::kButtonId_StickL_Down, ProController::kButtonId_StickL_Left, ProController::kButtonId_StickL_Right };
|
||||
const ProController::ButtonId g_kThirdColumnItems[] = { ProController::kButtonId_StickR, ProController::kButtonId_StickR_Up, ProController::kButtonId_StickR_Down, ProController::kButtonId_StickR_Left, ProController::kButtonId_StickR_Right };
|
||||
const ProController::ButtonId g_kFourthRowItems[] = { ProController::kButtonId_Up, ProController::kButtonId_Down, ProController::kButtonId_Left, ProController::kButtonId_Right };
|
||||
|
||||
|
||||
ProControllerInputPanel::ProControllerInputPanel(wxWindow* parent)
|
||||
: InputPanel(parent)
|
||||
{
|
||||
auto bold_font = GetFont();
|
||||
bold_font.MakeBold();
|
||||
|
||||
auto main_sizer = new wxGridBagSizer();
|
||||
|
||||
sint32 row = 0;
|
||||
sint32 column = 0;
|
||||
for (auto id : g_kFirstColumnItems)
|
||||
{
|
||||
row++;
|
||||
|
||||
main_sizer->Add(new wxStaticText(this, wxID_ANY, to_wxString(ProController::get_button_name(id))), wxGBPosition(row, column), wxDefaultSpan, wxALL | wxALIGN_CENTER_VERTICAL, 5);
|
||||
|
||||
auto text_ctrl = new wxTextCtrl(this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL | wxTE_PROCESS_ENTER | wxTE_PROCESS_TAB);
|
||||
text_ctrl->SetClientData((void*)id);
|
||||
text_ctrl->SetMinSize(wxSize(150, -1));
|
||||
text_ctrl->SetEditable(false);
|
||||
text_ctrl->SetBackgroundColour(kKeyColourNormalMode);
|
||||
bind_hotkey_events(text_ctrl);
|
||||
main_sizer->Add(text_ctrl, wxGBPosition(row, column + 1), wxDefaultSpan, wxALL | wxEXPAND, 5);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////
|
||||
|
||||
main_sizer->Add(new wxStaticLine(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxVERTICAL), wxGBPosition(0, column + 2), wxGBSpan(11, 1), wxALL | wxEXPAND, 5);
|
||||
|
||||
row = 0;
|
||||
column += 3;
|
||||
|
||||
auto text = new wxStaticText(this, wxID_ANY, _("Left Axis"));
|
||||
text->SetFont(bold_font);
|
||||
main_sizer->Add(text, wxGBPosition(row, column), wxGBSpan(1, 3), wxALL | wxEXPAND, 5);
|
||||
|
||||
for (auto id : g_kSecondColumnItems)
|
||||
{
|
||||
row++;
|
||||
|
||||
main_sizer->Add(new wxStaticText(this, wxID_ANY, to_wxString(ProController::get_button_name(id))), wxGBPosition(row, column), wxDefaultSpan, wxALL | wxALIGN_CENTER_VERTICAL, 5);
|
||||
|
||||
auto text_ctrl = new wxTextCtrl(this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL | wxTE_PROCESS_ENTER | wxTE_PROCESS_TAB);
|
||||
text_ctrl->SetClientData((void*)id);
|
||||
text_ctrl->SetMinSize(wxSize(150, -1));
|
||||
text_ctrl->SetEditable(false);
|
||||
text_ctrl->SetBackgroundColour(kKeyColourNormalMode);
|
||||
bind_hotkey_events(text_ctrl);
|
||||
main_sizer->Add(text_ctrl, wxGBPosition(row, column + 1), wxDefaultSpan, wxALL | wxEXPAND, 5);
|
||||
}
|
||||
|
||||
row++;
|
||||
|
||||
// input drawer
|
||||
m_left_draw = new wxInputDraw(this, wxID_ANY, wxDefaultPosition, { 60, 60 });
|
||||
main_sizer->Add(m_left_draw, wxGBPosition(row, column + 1), wxGBSpan(2, 1), wxTOP | wxBOTTOM | wxEXPAND | wxALIGN_CENTER, 5);
|
||||
|
||||
main_sizer->Add(new wxStaticLine(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxVERTICAL), wxGBPosition(0, column + 3), wxGBSpan(11, 1), wxALL | wxEXPAND, 5);
|
||||
|
||||
//////////////////////////////////////////////////////////////////
|
||||
|
||||
row = 0;
|
||||
column += 4;
|
||||
|
||||
text = new wxStaticText(this, wxID_ANY, _("Right Axis"));
|
||||
text->SetFont(bold_font);
|
||||
main_sizer->Add(text, wxGBPosition(row, column), wxGBSpan(1, 3), wxALL | wxEXPAND, 5);
|
||||
|
||||
for (auto id : g_kThirdColumnItems)
|
||||
{
|
||||
row++;
|
||||
|
||||
main_sizer->Add(new wxStaticText(this, wxID_ANY, to_wxString(ProController::get_button_name(id))), wxGBPosition(row, column), wxDefaultSpan, wxALL | wxALIGN_CENTER_VERTICAL, 5);
|
||||
|
||||
auto text_ctrl = new wxTextCtrl(this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL | wxTE_PROCESS_ENTER | wxTE_PROCESS_TAB);
|
||||
text_ctrl->SetClientData((void*)id);
|
||||
text_ctrl->SetMinSize(wxSize(150, -1));
|
||||
text_ctrl->SetEditable(false);
|
||||
text_ctrl->SetBackgroundColour(kKeyColourNormalMode);
|
||||
bind_hotkey_events(text_ctrl);
|
||||
main_sizer->Add(text_ctrl, wxGBPosition(row, column + 1), wxDefaultSpan, wxALL | wxEXPAND, 5);
|
||||
}
|
||||
|
||||
row++;
|
||||
|
||||
// input drawer
|
||||
m_right_draw = new wxInputDraw(this, wxID_ANY, wxDefaultPosition, { 60, 60 });
|
||||
main_sizer->Add(m_right_draw, wxGBPosition(row, column + 1), wxGBSpan(2, 1), wxTOP | wxBOTTOM | wxEXPAND | wxALIGN_CENTER, 5);
|
||||
|
||||
main_sizer->Add(new wxStaticLine(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxVERTICAL), wxGBPosition(0, column + 3), wxGBSpan(11, 1), wxALL | wxEXPAND, 5);
|
||||
|
||||
//////////////////////////////////////////////////////////////////
|
||||
|
||||
row = 0;
|
||||
column += 4;
|
||||
|
||||
text = new wxStaticText(this, wxID_ANY, _("D-pad"));
|
||||
text->SetFont(bold_font);
|
||||
main_sizer->Add(text, wxGBPosition(row, column), wxGBSpan(1, 3), wxALL | wxEXPAND, 5);
|
||||
|
||||
for (auto id : g_kFourthRowItems)
|
||||
{
|
||||
row++;
|
||||
|
||||
main_sizer->Add(new wxStaticText(this, wxID_ANY, to_wxString(ProController::get_button_name(id))), wxGBPosition(row, column), wxDefaultSpan, wxALL | wxALIGN_CENTER_VERTICAL, 5);
|
||||
|
||||
auto text_ctrl = new wxTextCtrl(this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL | wxTE_PROCESS_ENTER | wxTE_PROCESS_TAB);
|
||||
text_ctrl->SetClientData((void*)id);
|
||||
text_ctrl->SetMinSize(wxSize(150, -1));
|
||||
text_ctrl->SetEditable(false);
|
||||
text_ctrl->SetBackgroundColour(kKeyColourNormalMode);
|
||||
bind_hotkey_events(text_ctrl);
|
||||
main_sizer->Add(text_ctrl, wxGBPosition(row, column + 1), wxDefaultSpan, wxALL | wxEXPAND, 5);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////
|
||||
|
||||
// LoadController(controller);
|
||||
|
||||
SetSizerAndFit(main_sizer);
|
||||
//wxWindow::Show(show);
|
||||
}
|
||||
|
||||
void ProControllerInputPanel::on_timer(const EmulatedControllerPtr& emulated_controller,
|
||||
const ControllerPtr& controller_base)
|
||||
{
|
||||
InputPanel::on_timer(emulated_controller, controller_base);
|
||||
|
||||
if (emulated_controller)
|
||||
{
|
||||
const auto axis = emulated_controller->get_axis();
|
||||
const auto rotation = emulated_controller->get_rotation();
|
||||
|
||||
m_left_draw->SetAxisValue(axis);
|
||||
m_right_draw->SetAxisValue(rotation);
|
||||
}
|
||||
}
|
15
src/gui/input/panels/ProControllerInputPanel.h
Normal file
15
src/gui/input/panels/ProControllerInputPanel.h
Normal file
|
@ -0,0 +1,15 @@
|
|||
#pragma once
|
||||
|
||||
#include "gui/input/panels/InputPanel.h"
|
||||
#include "gui/components/wxInputDraw.h"
|
||||
|
||||
class ProControllerInputPanel : public InputPanel
|
||||
{
|
||||
public:
|
||||
ProControllerInputPanel(wxWindow* parent);
|
||||
|
||||
void on_timer(const EmulatedControllerPtr& emulated_controller, const ControllerPtr& controller) override;
|
||||
|
||||
private:
|
||||
wxInputDraw* m_left_draw, * m_right_draw;
|
||||
};
|
220
src/gui/input/panels/VPADInputPanel.cpp
Normal file
220
src/gui/input/panels/VPADInputPanel.cpp
Normal file
|
@ -0,0 +1,220 @@
|
|||
#include "gui/input/panels/VPADInputPanel.h"
|
||||
|
||||
#include <wx/gbsizer.h>
|
||||
#include <wx/stattext.h>
|
||||
#include <wx/statline.h>
|
||||
#include <wx/textctrl.h>
|
||||
#include <wx/slider.h>
|
||||
|
||||
|
||||
#include "gui/helpers/wxControlObject.h"
|
||||
#include "gui/helpers/wxHelpers.h"
|
||||
#include "gui/components/wxInputDraw.h"
|
||||
#include "input/emulated/VPADController.h"
|
||||
|
||||
constexpr VPADController::ButtonId g_kFirstColumnItems[] =
|
||||
{
|
||||
VPADController::kButtonId_A, VPADController::kButtonId_B, VPADController::kButtonId_X, VPADController::kButtonId_Y,
|
||||
VPADController::kButtonId_L, VPADController::kButtonId_R, VPADController::kButtonId_ZL, VPADController::kButtonId_ZR,
|
||||
VPADController::kButtonId_Plus, VPADController::kButtonId_Minus
|
||||
};
|
||||
|
||||
constexpr VPADController::ButtonId g_kSecondColumnItems[] =
|
||||
{
|
||||
VPADController::kButtonId_StickL, VPADController::kButtonId_StickL_Up, VPADController::kButtonId_StickL_Down, VPADController::kButtonId_StickL_Left, VPADController::kButtonId_StickL_Right
|
||||
};
|
||||
|
||||
constexpr VPADController::ButtonId g_kThirdColumnItems[] =
|
||||
{
|
||||
VPADController::kButtonId_StickR, VPADController::kButtonId_StickR_Up, VPADController::kButtonId_StickR_Down, VPADController::kButtonId_StickR_Left, VPADController::kButtonId_StickR_Right
|
||||
};
|
||||
|
||||
constexpr VPADController::ButtonId g_kFourthRowItems[] =
|
||||
{
|
||||
VPADController::kButtonId_Up, VPADController::kButtonId_Down, VPADController::kButtonId_Left, VPADController::kButtonId_Right
|
||||
};
|
||||
|
||||
|
||||
VPADInputPanel::VPADInputPanel(wxWindow* parent)
|
||||
: InputPanel(parent)
|
||||
{
|
||||
auto bold_font = GetFont();
|
||||
bold_font.MakeBold();
|
||||
|
||||
auto* main_sizer = new wxGridBagSizer();
|
||||
|
||||
sint32 row = 0;
|
||||
sint32 column = 0;
|
||||
for (const auto& id : g_kFirstColumnItems)
|
||||
{
|
||||
row++;
|
||||
|
||||
main_sizer->Add(new wxStaticText(this, wxID_ANY, to_wxString(VPADController::get_button_name(id))), wxGBPosition(row, column), wxDefaultSpan, wxALL | wxALIGN_CENTER_VERTICAL, 5);
|
||||
|
||||
auto* text_ctrl = new wxTextCtrl(this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL | wxTE_PROCESS_ENTER | wxTE_PROCESS_TAB);
|
||||
text_ctrl->SetClientData((void*)id);
|
||||
text_ctrl->SetMinSize(wxSize(150, -1));
|
||||
text_ctrl->SetEditable(false);
|
||||
text_ctrl->SetBackgroundColour(kKeyColourNormalMode);
|
||||
bind_hotkey_events(text_ctrl);
|
||||
main_sizer->Add(text_ctrl, wxGBPosition(row, column + 1), wxDefaultSpan, wxALL | wxEXPAND, 5);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////
|
||||
|
||||
main_sizer->Add(new wxStaticLine(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxVERTICAL), wxGBPosition(0, column + 2), wxGBSpan(11, 1), wxALL | wxEXPAND, 5);
|
||||
|
||||
row = 0;
|
||||
column += 3;
|
||||
|
||||
auto text = new wxStaticText(this, wxID_ANY, _("Left Axis"));
|
||||
text->SetFont(bold_font);
|
||||
main_sizer->Add(text, wxGBPosition(row, column), wxGBSpan(1, 3), wxALL | wxEXPAND, 5);
|
||||
|
||||
for (const auto& id : g_kSecondColumnItems)
|
||||
{
|
||||
row++;
|
||||
|
||||
main_sizer->Add(new wxStaticText(this, wxID_ANY, to_wxString(VPADController::get_button_name(id))), wxGBPosition(row, column), wxDefaultSpan, wxALL | wxALIGN_CENTER_VERTICAL, 5);
|
||||
|
||||
auto* text_ctrl = new wxTextCtrl(this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL | wxTE_PROCESS_ENTER | wxTE_PROCESS_TAB);
|
||||
text_ctrl->SetClientData((void*)id);
|
||||
text_ctrl->SetMinSize(wxSize(150, -1));
|
||||
text_ctrl->SetEditable(false);
|
||||
text_ctrl->SetBackgroundColour(kKeyColourNormalMode);
|
||||
bind_hotkey_events(text_ctrl);
|
||||
main_sizer->Add(text_ctrl, wxGBPosition(row, column + 1), wxDefaultSpan, wxALL | wxEXPAND, 5);
|
||||
}
|
||||
|
||||
row++;
|
||||
|
||||
// input drawer
|
||||
m_left_draw = new wxInputDraw(this, wxID_ANY, wxDefaultPosition, { 60, 60 });
|
||||
main_sizer->Add(m_left_draw, wxGBPosition(row, column + 1), wxGBSpan(2, 1), wxTOP | wxBOTTOM | wxEXPAND | wxALIGN_CENTER, 5);
|
||||
|
||||
main_sizer->Add(new wxStaticLine(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxVERTICAL), wxGBPosition(0, column + 3), wxGBSpan(11, 1), wxALL | wxEXPAND, 5);
|
||||
|
||||
//////////////////////////////////////////////////////////////////
|
||||
|
||||
row = 0;
|
||||
column += 4;
|
||||
|
||||
text = new wxStaticText(this, wxID_ANY, _("Right Axis"));
|
||||
text->SetFont(bold_font);
|
||||
main_sizer->Add(text, wxGBPosition(row, column), wxGBSpan(1, 3), wxALL | wxEXPAND, 5);
|
||||
|
||||
for (const auto& id : g_kThirdColumnItems)
|
||||
{
|
||||
row++;
|
||||
|
||||
main_sizer->Add(new wxStaticText(this, wxID_ANY, to_wxString(VPADController::get_button_name(id))), wxGBPosition(row, column), wxDefaultSpan, wxALL | wxALIGN_CENTER_VERTICAL, 5);
|
||||
|
||||
auto* text_ctrl = new wxTextCtrl(this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL | wxTE_PROCESS_ENTER | wxTE_PROCESS_TAB);
|
||||
text_ctrl->SetClientData((void*)id);
|
||||
text_ctrl->SetMinSize(wxSize(150, -1));
|
||||
text_ctrl->SetEditable(false);
|
||||
text_ctrl->SetBackgroundColour(kKeyColourNormalMode);
|
||||
bind_hotkey_events(text_ctrl);
|
||||
main_sizer->Add(text_ctrl, wxGBPosition(row, column + 1), wxDefaultSpan, wxALL | wxEXPAND, 5);
|
||||
}
|
||||
|
||||
row++;
|
||||
|
||||
// input drawer
|
||||
m_right_draw = new wxInputDraw(this, wxID_ANY, wxDefaultPosition, { 60, 60 });
|
||||
main_sizer->Add(m_right_draw, wxGBPosition(row, column + 1), wxGBSpan(2, 1), wxTOP | wxBOTTOM | wxEXPAND | wxALIGN_CENTER, 5);
|
||||
|
||||
// Volume
|
||||
row = 10;
|
||||
|
||||
text = new wxStaticText(this, wxID_ANY, _("Volume"));
|
||||
text->Disable();
|
||||
main_sizer->Add(text, wxGBPosition(row, column), wxDefaultSpan, wxALL, 5);
|
||||
|
||||
auto*m_volume = new wxSlider(this, wxID_ANY, 0, 0, 100);
|
||||
m_volume->Disable();
|
||||
main_sizer->Add(m_volume, wxGBPosition(row, column + 1), wxDefaultSpan, wxTOP | wxBOTTOM | wxEXPAND, 5);
|
||||
|
||||
const auto volume_text = new wxStaticText(this, wxID_ANY, wxString::Format("%d%%", 0));
|
||||
volume_text->Disable();
|
||||
main_sizer->Add(volume_text, wxGBPosition(row, column + 2), wxDefaultSpan, wxALL, 5);
|
||||
m_volume->Bind(wxEVT_SLIDER, &VPADInputPanel::OnVolumeChange, this, wxID_ANY, wxID_ANY, new wxControlObject(volume_text));
|
||||
|
||||
main_sizer->Add(new wxStaticLine(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxVERTICAL), wxGBPosition(0, column + 3), wxGBSpan(11, 1), wxALL | wxEXPAND, 5);
|
||||
|
||||
//////////////////////////////////////////////////////////////////
|
||||
|
||||
row = 0;
|
||||
column += 4;
|
||||
|
||||
text = new wxStaticText(this, wxID_ANY, _("D-pad"));
|
||||
text->SetFont(bold_font);
|
||||
main_sizer->Add(text, wxGBPosition(row, column), wxGBSpan(1, 3), wxALL | wxEXPAND, 5);
|
||||
|
||||
for (const auto& id : g_kFourthRowItems)
|
||||
{
|
||||
row++;
|
||||
|
||||
main_sizer->Add(new wxStaticText(this, wxID_ANY, to_wxString(VPADController::get_button_name(id))), wxGBPosition(row, column), wxDefaultSpan, wxALL | wxALIGN_CENTER_VERTICAL, 5);
|
||||
|
||||
auto text_ctrl = new wxTextCtrl(this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL | wxTE_PROCESS_ENTER | wxTE_PROCESS_TAB);
|
||||
text_ctrl->SetClientData((void*)id);
|
||||
text_ctrl->SetMinSize(wxSize(150, -1));
|
||||
text_ctrl->SetEditable(false);
|
||||
text_ctrl->SetBackgroundColour(kKeyColourNormalMode);
|
||||
bind_hotkey_events(text_ctrl);
|
||||
main_sizer->Add(text_ctrl, wxGBPosition(row, column + 1), wxDefaultSpan, wxALL | wxEXPAND, 5);
|
||||
}
|
||||
|
||||
// Blow Mic
|
||||
row = 9;
|
||||
main_sizer->Add(new wxStaticText(this, wxID_ANY, _("blow mic")), wxGBPosition(row, column), wxDefaultSpan, wxALL | wxALIGN_CENTER_VERTICAL, 5);
|
||||
|
||||
auto text_ctrl = new wxTextCtrl(this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL | wxTE_PROCESS_ENTER | wxTE_PROCESS_TAB);
|
||||
text_ctrl->SetClientData((void*)VPADController::kButtonId_Mic);
|
||||
text_ctrl->SetMinSize(wxSize(150, -1));
|
||||
text_ctrl->SetEditable(false);
|
||||
text_ctrl->SetBackgroundColour(kKeyColourNormalMode);
|
||||
bind_hotkey_events(text_ctrl);
|
||||
main_sizer->Add(text_ctrl, wxGBPosition(row, column + 1), wxDefaultSpan, wxALL | wxEXPAND, 5);
|
||||
row++;
|
||||
|
||||
main_sizer->Add(new wxStaticText(this, wxID_ANY, _("show screen")), wxGBPosition(row, column), wxDefaultSpan, wxALL | wxALIGN_CENTER_VERTICAL, 5);
|
||||
|
||||
text_ctrl = new wxTextCtrl(this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL | wxTE_PROCESS_ENTER | wxTE_PROCESS_TAB);
|
||||
text_ctrl->SetClientData((void*)VPADController::kButtonId_Screen);
|
||||
text_ctrl->SetMinSize(wxSize(150, -1));
|
||||
text_ctrl->SetEditable(false);
|
||||
text_ctrl->SetBackgroundColour(kKeyColourNormalMode);
|
||||
bind_hotkey_events(text_ctrl);
|
||||
main_sizer->Add(text_ctrl, wxGBPosition(row, column + 1), wxDefaultSpan, wxALL | wxEXPAND, 5);
|
||||
|
||||
//////////////////////////////////////////////////////////////////
|
||||
|
||||
//LoadController(controller);
|
||||
|
||||
SetSizer(main_sizer);
|
||||
Layout();
|
||||
|
||||
//SetSizerAndFit(main_sizer);
|
||||
//wxWindow::Show(show);
|
||||
}
|
||||
|
||||
void VPADInputPanel::on_timer(const EmulatedControllerPtr& emulated_controller, const ControllerPtr& controller_base)
|
||||
{
|
||||
InputPanel::on_timer(emulated_controller, controller_base);
|
||||
|
||||
if(emulated_controller)
|
||||
{
|
||||
const auto axis = emulated_controller->get_axis();
|
||||
const auto rotation = emulated_controller->get_rotation();
|
||||
|
||||
m_left_draw->SetAxisValue(axis);
|
||||
m_right_draw->SetAxisValue(rotation);
|
||||
}
|
||||
}
|
||||
|
||||
void VPADInputPanel::OnVolumeChange(wxCommandEvent& event)
|
||||
{
|
||||
|
||||
}
|
18
src/gui/input/panels/VPADInputPanel.h
Normal file
18
src/gui/input/panels/VPADInputPanel.h
Normal file
|
@ -0,0 +1,18 @@
|
|||
#pragma once
|
||||
|
||||
#include "gui/input/panels/InputPanel.h"
|
||||
|
||||
class wxInputDraw;
|
||||
|
||||
class VPADInputPanel : public InputPanel
|
||||
{
|
||||
public:
|
||||
VPADInputPanel(wxWindow* parent);
|
||||
|
||||
void on_timer(const EmulatedControllerPtr& emulated_controller, const ControllerPtr& controller) override;
|
||||
|
||||
private:
|
||||
void OnVolumeChange(wxCommandEvent& event);
|
||||
|
||||
wxInputDraw* m_left_draw, * m_right_draw;
|
||||
};
|
257
src/gui/input/panels/WiimoteInputPanel.cpp
Normal file
257
src/gui/input/panels/WiimoteInputPanel.cpp
Normal file
|
@ -0,0 +1,257 @@
|
|||
#include "gui/input/panels/WiimoteInputPanel.h"
|
||||
|
||||
#include <wx/gbsizer.h>
|
||||
#include <wx/stattext.h>
|
||||
#include <wx/statline.h>
|
||||
#include <wx/textctrl.h>
|
||||
#include <wx/slider.h>
|
||||
#include <wx/checkbox.h>
|
||||
|
||||
#include "gui/helpers/wxControlObject.h"
|
||||
#include "input/emulated/WiimoteController.h"
|
||||
#include "gui/helpers/wxHelpers.h"
|
||||
#include "gui/components/wxInputDraw.h"
|
||||
|
||||
constexpr WiimoteController::ButtonId g_kFirstColumnItems[] =
|
||||
{
|
||||
WiimoteController::kButtonId_A, WiimoteController::kButtonId_B, WiimoteController::kButtonId_1, WiimoteController::kButtonId_2, WiimoteController::kButtonId_Plus, WiimoteController::kButtonId_Minus, WiimoteController::kButtonId_Home
|
||||
};
|
||||
|
||||
constexpr WiimoteController::ButtonId g_kSecondColumnItems[] =
|
||||
{
|
||||
WiimoteController::kButtonId_Up, WiimoteController::kButtonId_Down, WiimoteController::kButtonId_Left, WiimoteController::kButtonId_Right
|
||||
};
|
||||
|
||||
constexpr WiimoteController::ButtonId g_kThirdColumnItems[] =
|
||||
{
|
||||
WiimoteController::kButtonId_Nunchuck_C, WiimoteController::kButtonId_Nunchuck_Z,
|
||||
WiimoteController::kButtonId_None,
|
||||
WiimoteController::kButtonId_Nunchuck_Up,WiimoteController::kButtonId_Nunchuck_Down,WiimoteController::kButtonId_Nunchuck_Left,WiimoteController::kButtonId_Nunchuck_Right
|
||||
};
|
||||
|
||||
WiimoteInputPanel::WiimoteInputPanel(wxWindow* parent)
|
||||
: InputPanel(parent)
|
||||
{
|
||||
auto bold_font = GetFont();
|
||||
bold_font.MakeBold();
|
||||
|
||||
auto* main_sizer = new wxBoxSizer(wxVERTICAL);
|
||||
|
||||
auto* extensions_sizer = new wxBoxSizer(wxHORIZONTAL);
|
||||
extensions_sizer->Add(new wxStaticText(this, wxID_ANY, _("Extensions:")));
|
||||
extensions_sizer->AddSpacer(10);
|
||||
|
||||
m_motion_plus = new wxCheckBox(this, wxID_ANY, _("MotionPlus"));
|
||||
m_motion_plus->Bind(wxEVT_CHECKBOX, &WiimoteInputPanel::on_extension_change, this);
|
||||
extensions_sizer->Add(m_motion_plus);
|
||||
|
||||
m_nunchuck = new wxCheckBox(this, wxID_ANY, _("Nunchuck"));
|
||||
m_nunchuck->Bind(wxEVT_CHECKBOX, &WiimoteInputPanel::on_extension_change, this);
|
||||
extensions_sizer->Add(m_nunchuck);
|
||||
|
||||
m_classic = new wxCheckBox(this, wxID_ANY, _("Classic"));
|
||||
m_classic->Bind(wxEVT_CHECKBOX, &WiimoteInputPanel::on_extension_change, this);
|
||||
m_classic->Hide();
|
||||
extensions_sizer->Add(m_classic);
|
||||
|
||||
main_sizer->Add(extensions_sizer, 0, wxEXPAND | wxALL, 5);
|
||||
main_sizer->Add(new wxStaticLine(this), 0, wxLEFT | wxRIGHT | wxTOP | wxEXPAND, 5);
|
||||
|
||||
m_item_sizer = new wxGridBagSizer();
|
||||
|
||||
sint32 row = 0;
|
||||
sint32 column = 0;
|
||||
for (const auto& id : g_kFirstColumnItems)
|
||||
{
|
||||
row++;
|
||||
|
||||
m_item_sizer->Add(new wxStaticText(this, wxID_ANY, to_wxString(WiimoteController::get_button_name(id))), wxGBPosition(row, column), wxDefaultSpan, wxALL | wxALIGN_CENTER_VERTICAL, 5);
|
||||
|
||||
auto* text_ctrl = new wxTextCtrl(this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL | wxTE_PROCESS_ENTER | wxTE_PROCESS_TAB);
|
||||
text_ctrl->SetClientData((void*)id);
|
||||
text_ctrl->SetMinSize(wxSize(150, -1));
|
||||
text_ctrl->SetEditable(false);
|
||||
text_ctrl->SetBackgroundColour(kKeyColourNormalMode);
|
||||
bind_hotkey_events(text_ctrl);
|
||||
m_item_sizer->Add(text_ctrl, wxGBPosition(row, column + 1), wxDefaultSpan, wxALL | wxEXPAND, 5);
|
||||
}
|
||||
|
||||
m_item_sizer->Add(new wxStaticLine(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxVERTICAL), wxGBPosition(0, column + 2), wxGBSpan(11, 1), wxLEFT | wxRIGHT | wxBOTTOM | wxEXPAND, 5);
|
||||
|
||||
//////////////////////////////////////////////////////////////////
|
||||
|
||||
row = 0;
|
||||
column += 3;
|
||||
|
||||
auto text = new wxStaticText(this, wxID_ANY, _("D-pad"));
|
||||
text->SetFont(bold_font);
|
||||
m_item_sizer->Add(text, wxGBPosition(row, column), wxGBSpan(1, 3), wxALL | wxEXPAND, 5);
|
||||
|
||||
for (const auto& id : g_kSecondColumnItems)
|
||||
{
|
||||
row++;
|
||||
|
||||
m_item_sizer->Add(new wxStaticText(this, wxID_ANY, to_wxString(WiimoteController::get_button_name(id))), wxGBPosition(row, column), wxDefaultSpan, wxALL | wxALIGN_CENTER_VERTICAL, 5);
|
||||
|
||||
auto* text_ctrl = new wxTextCtrl(this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL | wxTE_PROCESS_ENTER | wxTE_PROCESS_TAB);
|
||||
text_ctrl->SetClientData((void*)id);
|
||||
text_ctrl->SetMinSize(wxSize(150, -1));
|
||||
text_ctrl->SetEditable(false);
|
||||
text_ctrl->SetBackgroundColour(kKeyColourNormalMode);
|
||||
bind_hotkey_events(text_ctrl);
|
||||
m_item_sizer->Add(text_ctrl, wxGBPosition(row, column + 1), wxDefaultSpan, wxALL | wxEXPAND, 5);
|
||||
}
|
||||
|
||||
row = 8;
|
||||
// Volume
|
||||
text = new wxStaticText(this, wxID_ANY, _("Volume"));
|
||||
text->Disable();
|
||||
m_item_sizer->Add(text, wxGBPosition(row, column), wxDefaultSpan, wxALL, 5);
|
||||
|
||||
m_volume = new wxSlider(this, wxID_ANY, 0, 0, 100);
|
||||
m_volume->Disable();
|
||||
m_item_sizer->Add(m_volume, wxGBPosition(row, column + 1), wxDefaultSpan, wxTOP | wxBOTTOM | wxEXPAND, 5);
|
||||
|
||||
const auto volume_text = new wxStaticText(this, wxID_ANY, wxString::Format("%d%%", 0));
|
||||
volume_text->Disable();
|
||||
m_item_sizer->Add(volume_text, wxGBPosition(row, column + 2), wxDefaultSpan, wxALL, 5);
|
||||
m_volume->Bind(wxEVT_SLIDER, &WiimoteInputPanel::on_volume_change, this, wxID_ANY, wxID_ANY, new wxControlObject(volume_text));
|
||||
row++;
|
||||
|
||||
m_item_sizer->Add(new wxStaticLine(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxVERTICAL), wxGBPosition(0, column + 3), wxGBSpan(11, 1), wxLEFT | wxRIGHT | wxBOTTOM | wxEXPAND, 5);
|
||||
|
||||
//////////////////////////////////////////////////////////////////
|
||||
|
||||
row = 0;
|
||||
column += 4;
|
||||
|
||||
text = new wxStaticText(this, wxID_ANY, _("Nunchuck"));
|
||||
text->SetFont(bold_font);
|
||||
m_item_sizer->Add(text, wxGBPosition(row, column), wxGBSpan(1, 3), wxALL | wxEXPAND, 5);
|
||||
|
||||
for (const auto& id : g_kThirdColumnItems)
|
||||
{
|
||||
row++;
|
||||
if (id == WiimoteController::kButtonId_None)
|
||||
continue;
|
||||
|
||||
m_item_sizer->Add(new wxStaticText(this, wxID_ANY, to_wxString(WiimoteController::get_button_name(id))), wxGBPosition(row, column), wxDefaultSpan, wxALL | wxALIGN_CENTER_VERTICAL, 5);
|
||||
|
||||
auto* text_ctrl = new wxTextCtrl(this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL | wxTE_PROCESS_ENTER | wxTE_PROCESS_TAB);
|
||||
text_ctrl->SetClientData((void*)id);
|
||||
text_ctrl->SetMinSize(wxSize(150, -1));
|
||||
text_ctrl->SetEditable(false);
|
||||
text_ctrl->SetBackgroundColour(kKeyColourNormalMode);
|
||||
bind_hotkey_events(text_ctrl);
|
||||
text_ctrl->Enable(m_nunchuck->GetValue());
|
||||
m_item_sizer->Add(text_ctrl, wxGBPosition(row, column + 1), wxDefaultSpan, wxALL | wxEXPAND, 5);
|
||||
|
||||
m_nunchuck_items.push_back(text_ctrl);
|
||||
}
|
||||
|
||||
|
||||
// input drawer
|
||||
m_draw = new wxInputDraw(this, wxID_ANY, wxDefaultPosition, { 60, 60 });
|
||||
m_draw->Enable(m_nunchuck->GetValue());
|
||||
m_item_sizer->Add(5, 0, wxGBPosition(3, column + 3), wxDefaultSpan, wxTOP | wxBOTTOM | wxEXPAND | wxALIGN_CENTER, 5);
|
||||
m_item_sizer->Add(m_draw, wxGBPosition(3, column + 4), wxGBSpan(4, 1), wxTOP | wxBOTTOM | wxEXPAND | wxALIGN_CENTER, 5);
|
||||
|
||||
m_nunchuck_items.push_back(m_draw);
|
||||
|
||||
//////////////////////////////////////////////////////////////////
|
||||
|
||||
main_sizer->Add(m_item_sizer, 1, wxEXPAND | wxLEFT | wxRIGHT | wxTOP, 5);
|
||||
|
||||
SetSizer(main_sizer);
|
||||
Layout();
|
||||
}
|
||||
|
||||
void WiimoteInputPanel::set_active_device_type(WPADDeviceType type)
|
||||
{
|
||||
m_device_type = type;
|
||||
|
||||
m_motion_plus->SetValue(type == kWAPDevMPLS || type == kWAPDevMPLSFreeStyle || type == kWAPDevMPLSClassic);
|
||||
switch(type)
|
||||
{
|
||||
case kWAPDevFreestyle:
|
||||
case kWAPDevMPLSFreeStyle:
|
||||
m_nunchuck->SetValue(true);
|
||||
m_classic->SetValue(false);
|
||||
for (const auto& item : m_nunchuck_items)
|
||||
{
|
||||
item->Enable(true);
|
||||
}
|
||||
break;
|
||||
|
||||
case kWAPDevClassic:
|
||||
case kWAPDevMPLSClassic:
|
||||
m_nunchuck->SetValue(false);
|
||||
m_classic->SetValue(true);
|
||||
for (const auto& item : m_nunchuck_items)
|
||||
{
|
||||
item->Enable(false);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
m_nunchuck->SetValue(false);
|
||||
m_classic->SetValue(false);
|
||||
for (const auto& item : m_nunchuck_items)
|
||||
{
|
||||
item->Enable(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void WiimoteInputPanel::on_volume_change(wxCommandEvent& event)
|
||||
{
|
||||
}
|
||||
|
||||
void WiimoteInputPanel::on_extension_change(wxCommandEvent& event)
|
||||
{
|
||||
const auto obj = dynamic_cast<wxCheckBox*>(event.GetEventObject());
|
||||
wxASSERT(obj);
|
||||
|
||||
if(m_motion_plus->GetValue() && m_nunchuck->GetValue())
|
||||
set_active_device_type(kWAPDevMPLSFreeStyle);
|
||||
else if(m_motion_plus->GetValue() && m_classic->GetValue())
|
||||
set_active_device_type(kWAPDevMPLSClassic);
|
||||
else if (m_motion_plus->GetValue())
|
||||
set_active_device_type(kWAPDevMPLS);
|
||||
else if (m_nunchuck->GetValue())
|
||||
set_active_device_type(kWAPDevFreestyle);
|
||||
else if (m_classic->GetValue())
|
||||
set_active_device_type(kWAPDevClassic);
|
||||
else
|
||||
set_active_device_type(kWAPDevCore);
|
||||
}
|
||||
|
||||
void WiimoteInputPanel::on_timer(const EmulatedControllerPtr& emulated_controller, const ControllerPtr& controller)
|
||||
{
|
||||
if (emulated_controller)
|
||||
{
|
||||
const auto wiimote = std::dynamic_pointer_cast<WiimoteController>(emulated_controller);
|
||||
wxASSERT(wiimote);
|
||||
|
||||
wiimote->set_device_type(m_device_type);
|
||||
}
|
||||
|
||||
InputPanel::on_timer(emulated_controller, controller);
|
||||
|
||||
if (emulated_controller)
|
||||
{
|
||||
const auto axis = emulated_controller->get_axis();
|
||||
m_draw->SetAxisValue(axis);
|
||||
}
|
||||
}
|
||||
|
||||
void WiimoteInputPanel::load_controller(const EmulatedControllerPtr& emulated_controller)
|
||||
{
|
||||
InputPanel::load_controller(emulated_controller);
|
||||
|
||||
if (emulated_controller) {
|
||||
const auto wiimote = std::dynamic_pointer_cast<WiimoteController>(emulated_controller);
|
||||
wxASSERT(wiimote);
|
||||
set_active_device_type(wiimote->get_device_type());
|
||||
}
|
||||
}
|
41
src/gui/input/panels/WiimoteInputPanel.h
Normal file
41
src/gui/input/panels/WiimoteInputPanel.h
Normal file
|
@ -0,0 +1,41 @@
|
|||
#pragma once
|
||||
|
||||
#include "gui/input/panels/InputPanel.h"
|
||||
#include <wx/slider.h>
|
||||
|
||||
class wxCheckBox;
|
||||
class wxGridBagSizer;
|
||||
class wxInputDraw;
|
||||
|
||||
class WiimoteInputPanel : public InputPanel
|
||||
{
|
||||
public:
|
||||
WiimoteInputPanel(wxWindow* parent);
|
||||
|
||||
void on_timer(const EmulatedControllerPtr& emulated_controller, const ControllerPtr& controller) override;
|
||||
|
||||
void load_controller(const EmulatedControllerPtr& emulated_controller) override;
|
||||
|
||||
private:
|
||||
wxInputDraw* m_draw;
|
||||
|
||||
WPADDeviceType m_device_type = kWAPDevCore;
|
||||
void set_active_device_type(WPADDeviceType type);
|
||||
|
||||
void on_volume_change(wxCommandEvent& event);
|
||||
void on_extension_change(wxCommandEvent& event);
|
||||
|
||||
wxGridBagSizer* m_item_sizer;
|
||||
|
||||
wxCheckBox* m_nunchuck, * m_classic;
|
||||
wxCheckBox* m_motion_plus;
|
||||
|
||||
wxSlider* m_volume;
|
||||
|
||||
std::vector<wxWindow*> m_nunchuck_items;
|
||||
bool m_extensions_changed;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
312
src/gui/input/settings/DefaultControllerSettings.cpp
Normal file
312
src/gui/input/settings/DefaultControllerSettings.cpp
Normal file
|
@ -0,0 +1,312 @@
|
|||
#include "gui/input/settings/DefaultControllerSettings.h"
|
||||
|
||||
#include <wx/sizer.h>
|
||||
#include <wx/stattext.h>
|
||||
#include <wx/slider.h>
|
||||
#include <wx/button.h>
|
||||
#include <wx/gbsizer.h>
|
||||
#include <wx/statline.h>
|
||||
#include <wx/checkbox.h>
|
||||
#include <wx/statbox.h>
|
||||
|
||||
#include "gui/helpers/wxControlObject.h"
|
||||
#include "gui/helpers/wxHelpers.h"
|
||||
#include "gui/components/wxInputDraw.h"
|
||||
#include "gui/input/InputAPIAddWindow.h"
|
||||
|
||||
|
||||
DefaultControllerSettings::DefaultControllerSettings(wxWindow* parent, const wxPoint& position, std::shared_ptr<ControllerBase> controller)
|
||||
: wxDialog(parent, wxID_ANY, _("Controller settings"), position, wxDefaultSize,
|
||||
wxDEFAULT_DIALOG_STYLE), m_controller(std::move(controller))
|
||||
{
|
||||
m_settings = m_controller->get_settings();
|
||||
m_rumble_backup = m_settings.rumble;
|
||||
|
||||
this->SetSizeHints(wxDefaultSize, wxDefaultSize);
|
||||
|
||||
auto* sizer = new wxBoxSizer(wxVERTICAL);
|
||||
|
||||
// options
|
||||
{
|
||||
auto* box = new wxStaticBox(this, wxID_ANY, _("Options"));
|
||||
auto* box_sizer = new wxStaticBoxSizer(box, wxVERTICAL);
|
||||
|
||||
// Motion
|
||||
m_use_motion = new wxCheckBox(box, wxID_ANY, _("Use motion"));
|
||||
m_use_motion->SetValue(m_settings.motion);
|
||||
m_use_motion->Enable(m_controller->has_motion());
|
||||
box_sizer->Add(m_use_motion, 0, wxEXPAND | wxALL, 5);
|
||||
|
||||
// Vibration
|
||||
auto* rumbleSizer = new wxBoxSizer(wxHORIZONTAL);
|
||||
|
||||
const auto rumble = (int)(m_settings.rumble * 100);
|
||||
rumbleSizer->Add(new wxStaticText(box, wxID_ANY, _("Rumble")), 0, wxALL | wxALIGN_CENTER_VERTICAL, 5);
|
||||
m_rumble = new wxSlider(box, wxID_ANY, rumble, 0, 100);
|
||||
rumbleSizer->Add(m_rumble, 1, wxALL | wxEXPAND, 5);
|
||||
|
||||
const auto text = new wxStaticText(box, wxID_ANY, wxString::Format("%d%%", rumble));
|
||||
rumbleSizer->Add(text, 0, wxALL | wxALIGN_CENTER_VERTICAL, 5);
|
||||
m_rumble->Bind(wxEVT_SLIDER, &DefaultControllerSettings::on_rumble_change, this, wxID_ANY, wxID_ANY, new wxControlObject(text));
|
||||
|
||||
box_sizer->Add(rumbleSizer);
|
||||
|
||||
sizer->Add(box_sizer, 1, wxALL|wxEXPAND, 5);
|
||||
}
|
||||
|
||||
auto* row_sizer = new wxBoxSizer(wxHORIZONTAL);
|
||||
// Axis
|
||||
{
|
||||
auto* box = new wxStaticBox(this, wxID_ANY, _("Axis"));
|
||||
auto* box_sizer = new wxStaticBoxSizer(box, wxVERTICAL);
|
||||
|
||||
{
|
||||
auto* content_sizer = new wxFlexGridSizer(0, 3, 0, 0);
|
||||
|
||||
// Deadzone
|
||||
const auto deadzone = (int)(m_settings.axis.deadzone * 100);
|
||||
content_sizer->Add(new wxStaticText(box, wxID_ANY, _("Deadzone")), 0, wxALL | wxALIGN_CENTER_VERTICAL, 5);
|
||||
m_axis_deadzone = new wxSlider(box, wxID_ANY, deadzone, 0, 100);
|
||||
content_sizer->Add(m_axis_deadzone, 1, wxALL | wxEXPAND, 5);
|
||||
|
||||
const auto deadzone_text = new wxStaticText(box, wxID_ANY, wxString::Format("%d%%", deadzone));
|
||||
content_sizer->Add(deadzone_text, 0, wxALL | wxALIGN_CENTER_VERTICAL, 5);
|
||||
|
||||
m_axis_deadzone->Bind(wxEVT_SLIDER, &DefaultControllerSettings::on_deadzone_change, this, wxID_ANY, wxID_ANY,
|
||||
new wxControlObject(deadzone_text));
|
||||
|
||||
|
||||
// Range
|
||||
const auto range = (int)(m_settings.axis.range * 100);
|
||||
content_sizer->Add(new wxStaticText(box, wxID_ANY, _("Range")), 0, wxALL | wxALIGN_CENTER_VERTICAL, 5);
|
||||
m_axis_range = new wxSlider(box, wxID_ANY, range, 50, 200);
|
||||
content_sizer->Add(m_axis_range, 1, wxALL | wxEXPAND, 5);
|
||||
|
||||
const auto range_text = new wxStaticText(box, wxID_ANY, wxString::Format("%d%%", range));
|
||||
content_sizer->Add(range_text, 0, wxALL | wxALIGN_CENTER_VERTICAL, 5);
|
||||
|
||||
m_axis_range->Bind(wxEVT_SLIDER, &DefaultControllerSettings::on_range_change, this, wxID_ANY, wxID_ANY,
|
||||
new wxControlObject(range_text));
|
||||
|
||||
content_sizer->AddSpacer(1);
|
||||
m_axis_draw = new wxInputDraw(box, wxID_ANY, wxDefaultPosition, { 60, 60 });
|
||||
content_sizer->Add(m_axis_draw, 0, wxTOP | wxBOTTOM | wxALIGN_CENTER, 5);
|
||||
|
||||
box_sizer->Add(content_sizer, 1, wxEXPAND, 0);
|
||||
}
|
||||
|
||||
row_sizer->Add(box_sizer, 0, wxALL | wxEXPAND, 5);
|
||||
}
|
||||
|
||||
// Rotation
|
||||
{
|
||||
auto* box = new wxStaticBox(this, wxID_ANY, _("Rotation"));
|
||||
auto* box_sizer = new wxStaticBoxSizer(box, wxVERTICAL);
|
||||
|
||||
{
|
||||
auto* content_sizer = new wxFlexGridSizer(0, 3, 0, 0);
|
||||
|
||||
// Deadzone
|
||||
const auto deadzone = (int)(m_settings.rotation.deadzone * 100);
|
||||
content_sizer->Add(new wxStaticText(box, wxID_ANY, _("Deadzone")), 0, wxALL | wxALIGN_CENTER_VERTICAL, 5);
|
||||
m_rotation_deadzone = new wxSlider(box, wxID_ANY, deadzone, 0, 100);
|
||||
content_sizer->Add(m_rotation_deadzone, 1, wxALL | wxEXPAND, 5);
|
||||
|
||||
const auto deadzone_text = new wxStaticText(box, wxID_ANY, wxString::Format("%d%%", deadzone));
|
||||
content_sizer->Add(deadzone_text, 0, wxALL | wxALIGN_CENTER_VERTICAL, 5);
|
||||
|
||||
m_rotation_deadzone->Bind(wxEVT_SLIDER, &DefaultControllerSettings::on_deadzone_change, this, wxID_ANY, wxID_ANY,
|
||||
new wxControlObject(deadzone_text));
|
||||
|
||||
|
||||
// Range
|
||||
const auto range = (int)(m_settings.rotation.range * 100);
|
||||
content_sizer->Add(new wxStaticText(box, wxID_ANY, _("Range")), 0, wxALL | wxALIGN_CENTER_VERTICAL, 5);
|
||||
m_rotation_range = new wxSlider(box, wxID_ANY, range, 50, 200);
|
||||
content_sizer->Add(m_rotation_range, 1, wxALL | wxEXPAND, 5);
|
||||
|
||||
const auto range_text = new wxStaticText(box, wxID_ANY, wxString::Format("%d%%", range));
|
||||
content_sizer->Add(range_text, 0, wxALL | wxALIGN_CENTER_VERTICAL, 5);
|
||||
|
||||
m_rotation_range->Bind(wxEVT_SLIDER, &DefaultControllerSettings::on_range_change, this, wxID_ANY, wxID_ANY,
|
||||
new wxControlObject(range_text));
|
||||
|
||||
content_sizer->AddSpacer(1);
|
||||
m_rotation_draw = new wxInputDraw(box, wxID_ANY, wxDefaultPosition, { 60, 60 });
|
||||
content_sizer->Add(m_rotation_draw, 0, wxTOP | wxBOTTOM | wxALIGN_CENTER, 5);
|
||||
|
||||
box_sizer->Add(content_sizer, 1, wxEXPAND, 0);
|
||||
}
|
||||
|
||||
row_sizer->Add(box_sizer, 0, wxALL | wxEXPAND, 5);
|
||||
}
|
||||
|
||||
// Trigger
|
||||
{
|
||||
auto* box = new wxStaticBox(this, wxID_ANY, _("Trigger"));
|
||||
auto* box_sizer = new wxStaticBoxSizer(box, wxVERTICAL);
|
||||
|
||||
{
|
||||
auto* content_sizer = new wxFlexGridSizer(0, 3, 0, 0);
|
||||
|
||||
// Deadzone
|
||||
const auto deadzone = (int)(m_settings.trigger.deadzone * 100);
|
||||
content_sizer->Add(new wxStaticText(box, wxID_ANY, _("Deadzone")), 0, wxALL | wxALIGN_CENTER_VERTICAL, 5);
|
||||
m_trigger_deadzone = new wxSlider(box, wxID_ANY, deadzone, 0, 100);
|
||||
content_sizer->Add(m_trigger_deadzone, 1, wxALL | wxEXPAND, 5);
|
||||
|
||||
const auto deadzone_text = new wxStaticText(box, wxID_ANY, wxString::Format("%d%%", deadzone));
|
||||
content_sizer->Add(deadzone_text, 0, wxALL | wxALIGN_CENTER_VERTICAL, 5);
|
||||
|
||||
m_trigger_deadzone->Bind(wxEVT_SLIDER, &DefaultControllerSettings::on_deadzone_change, this, wxID_ANY, wxID_ANY,
|
||||
new wxControlObject(deadzone_text));
|
||||
|
||||
|
||||
// Range
|
||||
const auto range = (int)(m_settings.trigger.range * 100);
|
||||
content_sizer->Add(new wxStaticText(box, wxID_ANY, _("Range")), 0, wxALL | wxALIGN_CENTER_VERTICAL, 5);
|
||||
m_trigger_range = new wxSlider(box, wxID_ANY, range, 50, 200);
|
||||
content_sizer->Add(m_trigger_range, 1, wxALL | wxEXPAND, 5);
|
||||
|
||||
const auto range_text = new wxStaticText(box, wxID_ANY, wxString::Format("%d%%", range));
|
||||
content_sizer->Add(range_text, 0, wxALL | wxALIGN_CENTER_VERTICAL, 5);
|
||||
|
||||
m_trigger_range->Bind(wxEVT_SLIDER, &DefaultControllerSettings::on_range_change, this, wxID_ANY, wxID_ANY,
|
||||
new wxControlObject(range_text));
|
||||
|
||||
content_sizer->AddSpacer(1);
|
||||
m_trigger_draw = new wxInputDraw(box, wxID_ANY, wxDefaultPosition, { 60, 60 });
|
||||
content_sizer->Add(m_trigger_draw, 0, wxTOP | wxBOTTOM | wxALIGN_CENTER, 5);
|
||||
|
||||
box_sizer->Add(content_sizer, 1, wxEXPAND, 0);
|
||||
}
|
||||
|
||||
row_sizer->Add(box_sizer, 0, wxALL | wxEXPAND, 5);
|
||||
}
|
||||
sizer->Add(row_sizer);
|
||||
|
||||
{
|
||||
auto* control_sizer = new wxFlexGridSizer(0, 4, 0, 0);
|
||||
control_sizer->AddGrowableCol(3);
|
||||
|
||||
auto* ok_button = new wxButton(this, wxID_ANY, _("OK"));
|
||||
ok_button->Bind(wxEVT_BUTTON, [this](auto&) { update_settings(); EndModal(wxID_OK); });
|
||||
control_sizer->Add(ok_button, 0, wxALL, 5);
|
||||
|
||||
control_sizer->Add(0, 0, 0, wxEXPAND, 5);
|
||||
|
||||
auto* cancel_button = new wxButton(this, wxID_ANY, _("Cancel"));
|
||||
cancel_button->Bind(wxEVT_BUTTON, [this](auto&) { EndModal(wxID_CANCEL); });
|
||||
control_sizer->Add(cancel_button, 0, wxALL, 5);
|
||||
|
||||
auto* calibrate_button = new wxButton(this, wxID_ANY, _("Calibrate"));
|
||||
calibrate_button->Bind(wxEVT_BUTTON, [this](auto&) { m_controller->calibrate(); });
|
||||
control_sizer->Add(calibrate_button, 0, wxALL | wxALIGN_RIGHT, 5);
|
||||
|
||||
sizer->Add(control_sizer, 0, wxEXPAND, 5);
|
||||
}
|
||||
|
||||
|
||||
|
||||
this->SetSizer(sizer);
|
||||
this->Layout();
|
||||
this->Fit();
|
||||
|
||||
this->Bind(wxEVT_CLOSE_WINDOW, &DefaultControllerSettings::on_close, this);
|
||||
|
||||
m_timer = new wxTimer(this);
|
||||
Bind(wxEVT_TIMER, &DefaultControllerSettings::on_timer, this);
|
||||
m_timer->Start();
|
||||
}
|
||||
|
||||
DefaultControllerSettings::~DefaultControllerSettings()
|
||||
{
|
||||
m_controller->stop_rumble();
|
||||
m_timer->Stop();
|
||||
}
|
||||
|
||||
void DefaultControllerSettings::update_settings()
|
||||
{
|
||||
// update settings
|
||||
m_controller->set_settings(m_settings);
|
||||
if (m_use_motion)
|
||||
m_controller->set_use_motion(m_use_motion->GetValue());
|
||||
}
|
||||
|
||||
void DefaultControllerSettings::on_timer(wxTimerEvent& event)
|
||||
{
|
||||
if (m_rumble_time.has_value() && std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::steady_clock::now() - m_rumble_time.value()).count() > 500 )
|
||||
{
|
||||
m_controller->stop_rumble();
|
||||
m_rumble_time = {};
|
||||
}
|
||||
|
||||
const auto& default_state = m_controller->get_default_state();
|
||||
|
||||
auto state = m_controller->raw_state();
|
||||
m_controller->apply_axis_setting(state.axis, default_state.axis, m_settings.axis);
|
||||
m_controller->apply_axis_setting(state.rotation, default_state.rotation, m_settings.rotation);
|
||||
m_controller->apply_axis_setting(state.trigger, default_state.trigger, m_settings.trigger);
|
||||
|
||||
m_axis_draw->SetDeadzone(m_settings.axis.deadzone);
|
||||
m_axis_draw->SetAxisValue(state.axis);
|
||||
|
||||
m_rotation_draw->SetDeadzone(m_settings.rotation.deadzone);
|
||||
m_rotation_draw->SetAxisValue(state.rotation);
|
||||
|
||||
m_trigger_draw->SetDeadzone(m_settings.trigger.deadzone);
|
||||
m_trigger_draw->SetAxisValue(state.trigger);
|
||||
}
|
||||
|
||||
void DefaultControllerSettings::on_close(wxCloseEvent& event)
|
||||
{
|
||||
if (this->GetReturnCode() == 0 || this->GetReturnCode() == wxID_OK)
|
||||
update_settings();
|
||||
|
||||
event.Skip();
|
||||
}
|
||||
|
||||
void DefaultControllerSettings::on_deadzone_change(wxCommandEvent& event)
|
||||
{
|
||||
update_slider_text(event);
|
||||
const auto new_value = (float)event.GetInt() / 100.0f;
|
||||
|
||||
if (event.GetEventObject() == m_axis_deadzone)
|
||||
m_settings.axis.deadzone = new_value;
|
||||
else if (event.GetEventObject() == m_rotation_deadzone)
|
||||
m_settings.rotation.deadzone = new_value;
|
||||
else if (event.GetEventObject() == m_trigger_deadzone)
|
||||
m_settings.trigger.deadzone = new_value;
|
||||
}
|
||||
|
||||
void DefaultControllerSettings::on_range_change(wxCommandEvent& event)
|
||||
{
|
||||
update_slider_text(event);
|
||||
|
||||
const auto new_value = (float)event.GetInt() / 100.0f;
|
||||
|
||||
if (event.GetEventObject() == m_axis_range)
|
||||
m_settings.axis.range = new_value;
|
||||
else if (event.GetEventObject() == m_rotation_range)
|
||||
m_settings.rotation.range = new_value;
|
||||
else if (event.GetEventObject() == m_trigger_range)
|
||||
m_settings.trigger.range = new_value;
|
||||
}
|
||||
|
||||
void DefaultControllerSettings::on_rumble_change(wxCommandEvent& event)
|
||||
{
|
||||
update_slider_text(event);
|
||||
|
||||
const auto rumble_value = event.GetInt();
|
||||
m_settings.rumble = (float)rumble_value / 100.0f;
|
||||
|
||||
m_controller->set_rumble(m_settings.rumble);
|
||||
if (rumble_value != 0)
|
||||
m_controller->start_rumble();
|
||||
else
|
||||
m_controller->stop_rumble();
|
||||
|
||||
m_controller->set_rumble(m_rumble_backup);
|
||||
|
||||
m_rumble_time = std::chrono::steady_clock::now();
|
||||
}
|
42
src/gui/input/settings/DefaultControllerSettings.h
Normal file
42
src/gui/input/settings/DefaultControllerSettings.h
Normal file
|
@ -0,0 +1,42 @@
|
|||
#pragma once
|
||||
|
||||
#include <wx/dialog.h>
|
||||
#include <wx/timer.h>
|
||||
#include <wx/slider.h>
|
||||
|
||||
#include "input/api/Controller.h"
|
||||
|
||||
class wxCheckBox;
|
||||
class wxInputDraw;
|
||||
|
||||
class DefaultControllerSettings : public wxDialog
|
||||
{
|
||||
public:
|
||||
DefaultControllerSettings(wxWindow* parent, const wxPoint& position, ControllerPtr controller);
|
||||
~DefaultControllerSettings();
|
||||
|
||||
private:
|
||||
void update_settings();
|
||||
|
||||
ControllerPtr m_controller;
|
||||
ControllerBase::Settings m_settings;
|
||||
float m_rumble_backup;
|
||||
|
||||
wxTimer* m_timer;
|
||||
std::optional<std::chrono::steady_clock::time_point> m_rumble_time{};
|
||||
|
||||
wxSlider* m_axis_deadzone, *m_axis_range;
|
||||
wxSlider* m_rotation_deadzone, *m_rotation_range;
|
||||
wxSlider* m_trigger_deadzone, *m_trigger_range;
|
||||
wxSlider* m_rumble;
|
||||
|
||||
wxCheckBox* m_use_motion = nullptr;
|
||||
|
||||
wxInputDraw* m_axis_draw, * m_rotation_draw, *m_trigger_draw;
|
||||
|
||||
void on_timer(wxTimerEvent& event);
|
||||
void on_close(wxCloseEvent& event);
|
||||
void on_deadzone_change(wxCommandEvent& event);
|
||||
void on_range_change(wxCommandEvent& event);
|
||||
void on_rumble_change(wxCommandEvent& event);
|
||||
};
|
369
src/gui/input/settings/WiimoteControllerSettings.cpp
Normal file
369
src/gui/input/settings/WiimoteControllerSettings.cpp
Normal file
|
@ -0,0 +1,369 @@
|
|||
#include "gui/input/settings/WiimoteControllerSettings.h"
|
||||
|
||||
#include <wx/sizer.h>
|
||||
#include <wx/stattext.h>
|
||||
#include <wx/slider.h>
|
||||
#include <wx/button.h>
|
||||
#include <wx/gbsizer.h>
|
||||
#include <wx/statline.h>
|
||||
#include <wx/checkbox.h>
|
||||
#include <wx/statbox.h>
|
||||
|
||||
#include "gui/helpers/wxControlObject.h"
|
||||
#include "gui/helpers/wxHelpers.h"
|
||||
#include "gui/components/wxInputDraw.h"
|
||||
#include "gui/input/InputAPIAddWindow.h"
|
||||
|
||||
#if BOOST_OS_WINDOWS
|
||||
|
||||
WiimoteControllerSettings::WiimoteControllerSettings(wxWindow* parent, const wxPoint& position, std::shared_ptr<NativeWiimoteController> controller)
|
||||
: wxDialog(parent, wxID_ANY, _("Controller settings"), position, wxDefaultSize,
|
||||
wxDEFAULT_DIALOG_STYLE), m_controller(std::move(controller))
|
||||
{
|
||||
m_settings = m_controller->get_settings();
|
||||
m_rumble_backup = m_settings.rumble;
|
||||
m_packet_delay_backup = m_controller->get_packet_delay();
|
||||
|
||||
this->SetSizeHints(wxDefaultSize, wxDefaultSize);
|
||||
|
||||
auto* sizer = new wxBoxSizer(wxVERTICAL);
|
||||
|
||||
// extension info
|
||||
{
|
||||
auto* box = new wxStaticBox(this, wxID_ANY, _("Connected extension"));
|
||||
auto* box_sizer = new wxStaticBoxSizer(box, wxVERTICAL);
|
||||
|
||||
m_extension_text = new wxStaticText(box, wxID_ANY, _("None"));
|
||||
box_sizer->Add(m_extension_text, 0, wxALL, 5);
|
||||
|
||||
sizer->Add(box_sizer, 0, wxALL | wxEXPAND, 5);
|
||||
}
|
||||
|
||||
// options
|
||||
{
|
||||
auto* box = new wxStaticBox(this, wxID_ANY, _("Options"));
|
||||
auto* box_sizer = new wxStaticBoxSizer(box, wxVERTICAL);
|
||||
|
||||
{
|
||||
auto* row_sizer = new wxBoxSizer(wxHORIZONTAL);
|
||||
// Rumble
|
||||
m_rumble = new wxCheckBox(box, wxID_ANY, _("Rumble"));
|
||||
m_rumble->SetValue(m_settings.rumble > 0);
|
||||
row_sizer->Add(m_rumble, 0, wxALL, 5);
|
||||
|
||||
m_rumble->Bind(wxEVT_CHECKBOX, &WiimoteControllerSettings::on_rumble_change, this);
|
||||
|
||||
// Motion
|
||||
m_use_motion = new wxCheckBox(box, wxID_ANY, _("Use motion"));
|
||||
m_use_motion->SetValue(m_settings.motion);
|
||||
m_use_motion->Enable(m_controller->has_motion());
|
||||
row_sizer->Add(m_use_motion, 0, wxALL, 5);
|
||||
|
||||
box_sizer->Add(row_sizer);
|
||||
}
|
||||
{
|
||||
auto* row_sizer = new wxBoxSizer(wxHORIZONTAL);
|
||||
|
||||
// Delay
|
||||
row_sizer->Add(new wxStaticText(box, wxID_ANY, _("Packet delay")), 0, wxALL | wxALIGN_CENTER_VERTICAL, 5);
|
||||
m_package_delay = new wxSlider(box, wxID_ANY, m_packet_delay_backup, 1, 100);
|
||||
row_sizer->Add(m_package_delay, 1, wxALL | wxEXPAND, 5);
|
||||
|
||||
const auto range_text = new wxStaticText(box, wxID_ANY, wxString::Format("%dms", m_packet_delay_backup));
|
||||
row_sizer->Add(range_text, 0, wxALL | wxALIGN_CENTER_VERTICAL, 5);
|
||||
|
||||
m_package_delay->Bind(wxEVT_SLIDER, &WiimoteControllerSettings::on_delay_change, this, wxID_ANY, wxID_ANY,
|
||||
new wxControlObject(range_text));
|
||||
|
||||
box_sizer->Add(row_sizer);
|
||||
}
|
||||
|
||||
sizer->Add(box_sizer, 0, wxALL | wxEXPAND, 5);
|
||||
}
|
||||
|
||||
// Nunchuck
|
||||
{
|
||||
m_nunchuck_settings = new wxStaticBox(this, wxID_ANY, _("Nunchuck"));
|
||||
auto* box_sizer = new wxStaticBoxSizer(m_nunchuck_settings, wxVERTICAL);
|
||||
|
||||
{
|
||||
auto* content_sizer = new wxFlexGridSizer(0, 3, 0, 0);
|
||||
|
||||
// Deadzone
|
||||
const auto deadzone = (int)(m_settings.axis.deadzone * 100);
|
||||
content_sizer->Add(new wxStaticText(m_nunchuck_settings, wxID_ANY, _("Deadzone")), 0, wxALL | wxALIGN_CENTER_VERTICAL, 5);
|
||||
m_nunchuck_deadzone = new wxSlider(m_nunchuck_settings, wxID_ANY, deadzone, 0, 100);
|
||||
content_sizer->Add(m_nunchuck_deadzone, 1, wxALL | wxEXPAND, 5);
|
||||
|
||||
const auto deadzone_text = new wxStaticText(m_nunchuck_settings, wxID_ANY, wxString::Format("%d%%", deadzone));
|
||||
content_sizer->Add(deadzone_text, 0, wxALL | wxALIGN_CENTER_VERTICAL, 5);
|
||||
|
||||
m_nunchuck_deadzone->Bind(wxEVT_SLIDER, &WiimoteControllerSettings::on_slider_change, this, wxID_ANY, wxID_ANY,
|
||||
new wxControlObject(deadzone_text));
|
||||
|
||||
|
||||
// Range
|
||||
const auto range = (int)(m_settings.axis.range * 100);
|
||||
content_sizer->Add(new wxStaticText(m_nunchuck_settings, wxID_ANY, _("Range")), 0, wxALL | wxALIGN_CENTER_VERTICAL, 5);
|
||||
m_nunchuck_range = new wxSlider(m_nunchuck_settings, wxID_ANY, range, 50, 200);
|
||||
content_sizer->Add(m_nunchuck_range, 1, wxALL | wxEXPAND, 5);
|
||||
|
||||
const auto range_text = new wxStaticText(m_nunchuck_settings, wxID_ANY, wxString::Format("%d%%", range));
|
||||
content_sizer->Add(range_text, 0, wxALL | wxALIGN_CENTER_VERTICAL, 5);
|
||||
|
||||
m_nunchuck_range->Bind(wxEVT_SLIDER, &WiimoteControllerSettings::on_slider_change, this, wxID_ANY, wxID_ANY,
|
||||
new wxControlObject(range_text));
|
||||
|
||||
content_sizer->AddSpacer(1);
|
||||
m_nunchuck_draw = new wxInputDraw(m_nunchuck_settings, wxID_ANY, wxDefaultPosition, { 60, 60 });
|
||||
content_sizer->Add(m_nunchuck_draw, 0, wxTOP | wxBOTTOM | wxALIGN_CENTER, 5);
|
||||
|
||||
box_sizer->Add(content_sizer, 1, wxEXPAND, 0);
|
||||
}
|
||||
|
||||
sizer->Add(box_sizer, 0, wxALL | wxEXPAND, 5);
|
||||
}
|
||||
|
||||
// Classic
|
||||
{
|
||||
m_classic_settings = new wxStaticBox(this, wxID_ANY, _("Classic"));
|
||||
auto* box_sizer = new wxStaticBoxSizer(m_classic_settings, wxVERTICAL);
|
||||
|
||||
{
|
||||
auto* content_sizer = new wxFlexGridSizer(0, 6, 0, 0);
|
||||
|
||||
// Deadzone
|
||||
{
|
||||
// Axis
|
||||
const auto deadzone = (int)(m_settings.axis.deadzone * 100);
|
||||
content_sizer->Add(new wxStaticText(m_classic_settings, wxID_ANY, _("Deadzone")), 0, wxALL | wxALIGN_CENTER_VERTICAL, 5);
|
||||
m_classic_axis_deadzone = new wxSlider(m_classic_settings, wxID_ANY, deadzone, 0, 100);
|
||||
content_sizer->Add(m_classic_axis_deadzone, 1, wxALL | wxEXPAND, 5);
|
||||
|
||||
const auto deadzone_text = new wxStaticText(m_classic_settings, wxID_ANY, wxString::Format("%d%%", deadzone));
|
||||
content_sizer->Add(deadzone_text, 0, wxALL | wxALIGN_CENTER_VERTICAL, 5);
|
||||
|
||||
m_classic_axis_deadzone->Bind(wxEVT_SLIDER, &WiimoteControllerSettings::on_slider_change, this, wxID_ANY, wxID_ANY,
|
||||
new wxControlObject(deadzone_text));
|
||||
}
|
||||
{
|
||||
// Range
|
||||
const auto deadzone = (int)(m_settings.rotation.deadzone * 100);
|
||||
content_sizer->Add(new wxStaticText(m_classic_settings, wxID_ANY, _("Deadzone")), 0, wxALL | wxALIGN_CENTER_VERTICAL, 5);
|
||||
m_classic_rotation_deadzone = new wxSlider(m_classic_settings, wxID_ANY, deadzone, 0, 100);
|
||||
content_sizer->Add(m_classic_rotation_deadzone, 1, wxALL | wxEXPAND, 5);
|
||||
|
||||
const auto deadzone_text = new wxStaticText(m_classic_settings, wxID_ANY, wxString::Format("%d%%", deadzone));
|
||||
content_sizer->Add(deadzone_text, 0, wxALL | wxALIGN_CENTER_VERTICAL, 5);
|
||||
|
||||
m_classic_rotation_deadzone->Bind(wxEVT_SLIDER, &WiimoteControllerSettings::on_slider_change, this, wxID_ANY, wxID_ANY,
|
||||
new wxControlObject(deadzone_text));
|
||||
}
|
||||
|
||||
// Range
|
||||
{
|
||||
// Axis
|
||||
const auto range = (int)(m_settings.axis.range * 100);
|
||||
content_sizer->Add(new wxStaticText(m_classic_settings, wxID_ANY, _("Range")), 0, wxALL | wxALIGN_CENTER_VERTICAL, 5);
|
||||
m_classic_axis_range = new wxSlider(m_classic_settings, wxID_ANY, range, 50, 200);
|
||||
content_sizer->Add(m_classic_axis_range, 1, wxALL | wxEXPAND, 5);
|
||||
|
||||
const auto range_text = new wxStaticText(m_classic_settings, wxID_ANY, wxString::Format("%d%%", range));
|
||||
content_sizer->Add(range_text, 0, wxALL | wxALIGN_CENTER_VERTICAL, 5);
|
||||
|
||||
m_classic_axis_range->Bind(wxEVT_SLIDER, &WiimoteControllerSettings::on_slider_change, this, wxID_ANY, wxID_ANY,
|
||||
new wxControlObject(range_text));
|
||||
}
|
||||
{
|
||||
// Rotation
|
||||
const auto range = (int)(m_settings.rotation.range * 100);
|
||||
content_sizer->Add(new wxStaticText(m_classic_settings, wxID_ANY, _("Range")), 0, wxALL | wxALIGN_CENTER_VERTICAL, 5);
|
||||
m_classic_rotation_range = new wxSlider(m_classic_settings, wxID_ANY, range, 50, 200);
|
||||
content_sizer->Add(m_classic_rotation_range, 1, wxALL | wxEXPAND, 5);
|
||||
|
||||
const auto range_text = new wxStaticText(m_classic_settings, wxID_ANY, wxString::Format("%d%%", range));
|
||||
content_sizer->Add(range_text, 0, wxALL | wxALIGN_CENTER_VERTICAL, 5);
|
||||
|
||||
m_classic_rotation_range->Bind(wxEVT_SLIDER, &WiimoteControllerSettings::on_slider_change, this, wxID_ANY, wxID_ANY,
|
||||
new wxControlObject(range_text));
|
||||
}
|
||||
|
||||
content_sizer->AddSpacer(1);
|
||||
m_classic_axis_draw = new wxInputDraw(m_classic_settings, wxID_ANY, wxDefaultPosition, { 60, 60 });
|
||||
content_sizer->Add(m_classic_axis_draw, 0, wxTOP | wxBOTTOM | wxALIGN_CENTER, 5);
|
||||
content_sizer->AddSpacer(1);
|
||||
|
||||
content_sizer->AddSpacer(1);
|
||||
m_classic_rotation_draw = new wxInputDraw(m_classic_settings, wxID_ANY, wxDefaultPosition, { 60, 60 });
|
||||
content_sizer->Add(m_classic_rotation_draw, 0, wxTOP | wxBOTTOM | wxALIGN_CENTER, 5);
|
||||
|
||||
box_sizer->Add(content_sizer, 1, wxEXPAND, 0);
|
||||
}
|
||||
|
||||
sizer->Add(box_sizer, 0, wxALL | wxEXPAND, 5);
|
||||
}
|
||||
|
||||
{
|
||||
auto* control_sizer = new wxFlexGridSizer(0, 4, 0, 0);
|
||||
control_sizer->AddGrowableCol(3);
|
||||
|
||||
auto* ok_button = new wxButton(this, wxID_ANY, _("OK"));
|
||||
ok_button->Bind(wxEVT_BUTTON, [this](auto&) { update_settings(); EndModal(wxID_OK); });
|
||||
control_sizer->Add(ok_button, 0, wxALL, 5);
|
||||
|
||||
control_sizer->Add(0, 0, 0, wxEXPAND, 5);
|
||||
|
||||
auto* cancel_button = new wxButton(this, wxID_ANY, _("Cancel"));
|
||||
cancel_button->Bind(wxEVT_BUTTON, [this](auto&) { EndModal(wxID_CANCEL); });
|
||||
control_sizer->Add(cancel_button, 0, wxALL, 5);
|
||||
|
||||
auto* calibrate_button = new wxButton(this, wxID_ANY, _("Calibrate"));
|
||||
calibrate_button->Bind(wxEVT_BUTTON, [this](auto&) { m_controller->calibrate(); });
|
||||
control_sizer->Add(calibrate_button, 0, wxALL | wxALIGN_RIGHT, 5);
|
||||
|
||||
sizer->Add(control_sizer, 0, wxEXPAND, 5);
|
||||
}
|
||||
|
||||
|
||||
|
||||
this->SetSizer(sizer);
|
||||
this->Layout();
|
||||
this->Fit();
|
||||
|
||||
this->Bind(wxEVT_CLOSE_WINDOW, &WiimoteControllerSettings::on_close, this);
|
||||
|
||||
m_timer = new wxTimer(this);
|
||||
Bind(wxEVT_TIMER, &WiimoteControllerSettings::on_timer, this);
|
||||
m_timer->Start();
|
||||
}
|
||||
|
||||
WiimoteControllerSettings::~WiimoteControllerSettings()
|
||||
{
|
||||
m_controller->stop_rumble();
|
||||
m_timer->Stop();
|
||||
}
|
||||
|
||||
void WiimoteControllerSettings::update_settings()
|
||||
{
|
||||
// update settings
|
||||
m_controller->set_settings(m_settings);
|
||||
if (m_use_motion)
|
||||
m_controller->set_use_motion(m_use_motion->GetValue());
|
||||
|
||||
m_controller->set_packet_delay(m_package_delay->GetValue());
|
||||
}
|
||||
|
||||
void WiimoteControllerSettings::on_timer(wxTimerEvent& event)
|
||||
{
|
||||
if (m_rumble_time.has_value() && std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::steady_clock::now() - m_rumble_time.value()).count() > 500)
|
||||
{
|
||||
m_controller->stop_rumble();
|
||||
m_rumble_time = {};
|
||||
}
|
||||
|
||||
const auto& default_state = m_controller->get_default_state();
|
||||
|
||||
auto state = m_controller->raw_state();
|
||||
m_controller->apply_axis_setting(state.axis, default_state.axis, m_settings.axis);
|
||||
m_controller->apply_axis_setting(state.rotation, default_state.rotation, m_settings.rotation);
|
||||
m_controller->apply_axis_setting(state.trigger, default_state.trigger, m_settings.trigger);
|
||||
|
||||
if (m_nunchuck_settings->IsEnabled())
|
||||
{
|
||||
m_nunchuck_draw->SetDeadzone(m_settings.axis.deadzone);
|
||||
m_nunchuck_draw->SetAxisValue(state.axis);
|
||||
}
|
||||
|
||||
if (m_classic_settings->IsEnabled())
|
||||
{
|
||||
m_classic_axis_draw->SetDeadzone(m_settings.axis.deadzone);
|
||||
m_classic_axis_draw->SetAxisValue(state.axis);
|
||||
|
||||
m_classic_rotation_draw->SetDeadzone(m_settings.rotation.deadzone);
|
||||
m_classic_rotation_draw->SetAxisValue(state.rotation);
|
||||
}
|
||||
|
||||
wxString label;
|
||||
switch (m_controller->get_extension())
|
||||
{
|
||||
case NativeWiimoteController::Nunchuck:
|
||||
label = _("Nunchuck");
|
||||
m_nunchuck_settings->Enable();
|
||||
m_classic_settings->Disable();
|
||||
break;
|
||||
case NativeWiimoteController::Classic:
|
||||
label = _("Classic");
|
||||
m_nunchuck_settings->Disable();
|
||||
m_classic_settings->Enable();
|
||||
break;
|
||||
default:
|
||||
m_nunchuck_settings->Disable();
|
||||
m_classic_settings->Disable();
|
||||
}
|
||||
|
||||
if(m_controller->is_mpls_attached())
|
||||
{
|
||||
const bool empty = label.empty();
|
||||
if (!empty)
|
||||
label.Append(" (");
|
||||
|
||||
label.Append(_("MotionPlus"));
|
||||
|
||||
if (!empty)
|
||||
label.Append(")");
|
||||
}
|
||||
|
||||
if(label.empty())
|
||||
{
|
||||
label = _("None");
|
||||
}
|
||||
|
||||
m_extension_text->SetLabelText(label);
|
||||
}
|
||||
|
||||
void WiimoteControllerSettings::on_close(wxCloseEvent& event)
|
||||
{
|
||||
if (this->GetReturnCode() == 0 || this->GetReturnCode() == wxID_OK)
|
||||
update_settings();
|
||||
|
||||
event.Skip();
|
||||
}
|
||||
|
||||
void WiimoteControllerSettings::on_slider_change(wxCommandEvent& event)
|
||||
{
|
||||
update_slider_text(event);
|
||||
const auto new_value = (float)event.GetInt() / 100.0f;
|
||||
|
||||
auto* obj = event.GetEventObject();
|
||||
if (obj == m_nunchuck_deadzone || obj == m_classic_axis_deadzone)
|
||||
m_settings.axis.deadzone = new_value;
|
||||
else if (obj == m_nunchuck_range || obj == m_classic_axis_range)
|
||||
m_settings.axis.range = new_value;
|
||||
else if (obj == m_classic_rotation_deadzone)
|
||||
m_settings.rotation.deadzone = new_value;
|
||||
else if (obj == m_classic_rotation_range)
|
||||
m_settings.rotation.range = new_value;
|
||||
}
|
||||
|
||||
void WiimoteControllerSettings::on_rumble_change(wxCommandEvent& event)
|
||||
{
|
||||
const auto rumble_value = m_rumble->GetValue();
|
||||
m_settings.rumble = rumble_value ? 1.0f : 0.0f;
|
||||
|
||||
m_controller->set_rumble(m_settings.rumble);
|
||||
if (rumble_value)
|
||||
m_controller->start_rumble();
|
||||
else
|
||||
m_controller->stop_rumble();
|
||||
|
||||
m_controller->set_rumble(m_rumble_backup);
|
||||
|
||||
m_rumble_time = std::chrono::steady_clock::now();
|
||||
}
|
||||
|
||||
void WiimoteControllerSettings::on_delay_change(wxCommandEvent& event)
|
||||
{
|
||||
update_slider_text(event, "%dms");
|
||||
}
|
||||
|
||||
#endif
|
61
src/gui/input/settings/WiimoteControllerSettings.h
Normal file
61
src/gui/input/settings/WiimoteControllerSettings.h
Normal file
|
@ -0,0 +1,61 @@
|
|||
#pragma once
|
||||
|
||||
#if BOOST_OS_WINDOWS
|
||||
|
||||
#include <wx/dialog.h>
|
||||
#include <wx/timer.h>
|
||||
#include <wx/slider.h>
|
||||
|
||||
#include "input/api/Controller.h"
|
||||
#include "input/api/Wiimote/NativeWiimoteController.h"
|
||||
|
||||
class wxStaticBox;
|
||||
class wxStaticText;
|
||||
class wxCheckBox;
|
||||
class wxInputDraw;
|
||||
|
||||
class WiimoteControllerSettings : public wxDialog
|
||||
{
|
||||
public:
|
||||
WiimoteControllerSettings(wxWindow* parent, const wxPoint& position, std::shared_ptr<NativeWiimoteController> controller);
|
||||
~WiimoteControllerSettings();
|
||||
|
||||
private:
|
||||
void update_settings();
|
||||
|
||||
std::shared_ptr<NativeWiimoteController> m_controller;
|
||||
ControllerBase::Settings m_settings;
|
||||
float m_rumble_backup;
|
||||
uint32 m_packet_delay_backup;
|
||||
|
||||
wxTimer* m_timer;
|
||||
std::optional<std::chrono::steady_clock::time_point> m_rumble_time{};
|
||||
|
||||
wxStaticText* m_extension_text;
|
||||
|
||||
wxSlider* m_package_delay;
|
||||
wxCheckBox* m_rumble = nullptr;
|
||||
wxCheckBox* m_use_motion = nullptr;
|
||||
|
||||
wxStaticBox* m_nunchuck_settings;
|
||||
wxSlider* m_nunchuck_deadzone, * m_nunchuck_range;
|
||||
wxInputDraw* m_nunchuck_draw;
|
||||
|
||||
wxStaticBox* m_classic_settings;
|
||||
wxSlider* m_classic_axis_deadzone, * m_classic_axis_range;
|
||||
wxInputDraw* m_classic_axis_draw;
|
||||
wxSlider* m_classic_rotation_deadzone, * m_classic_rotation_range;
|
||||
wxInputDraw* m_classic_rotation_draw;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void on_timer(wxTimerEvent& event);
|
||||
void on_close(wxCloseEvent& event);
|
||||
void on_slider_change(wxCommandEvent& event);
|
||||
void on_rumble_change(wxCommandEvent& event);
|
||||
void on_delay_change(wxCommandEvent& event);
|
||||
};
|
||||
|
||||
#endif
|
Loading…
Add table
Add a link
Reference in a new issue