mirror of
https://github.com/cemu-project/Cemu.git
synced 2026-07-10 01:24:41 -06:00
The IP and port input boxes are not shown when the DSUController API is first selected when using wayland with kwin. Setting the dialog as wxCAPTION causes kwin to add decorations to the window which for whatever reason causes the toplevel to resize correctly. This may be a bug in wxWidgets or kwin.
327 lines
9.3 KiB
C++
327 lines
9.3 KiB
C++
#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, wxCAPTION), 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, "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, "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);
|
|
}
|
|
|
|
InputAPIAddWindow::~InputAPIAddWindow()
|
|
{
|
|
discard_thread_result();
|
|
}
|
|
|
|
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)
|
|
{
|
|
discard_thread_result();
|
|
|
|
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);
|
|
|
|
m_search_thread_data = std::make_unique<AsyncThreadData>();
|
|
std::thread([this, provider, selected_uuid](std::shared_ptr<AsyncThreadData> data)
|
|
{
|
|
auto available_controllers = provider->get_controllers();
|
|
|
|
{
|
|
std::lock_guard lock{data->mutex};
|
|
if(!data->discardResult)
|
|
{
|
|
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;
|
|
}
|
|
}
|
|
}, m_search_thread_data).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;
|
|
}
|
|
}
|
|
}
|
|
|
|
void InputAPIAddWindow::discard_thread_result()
|
|
{
|
|
m_search_running = false;
|
|
if(m_search_thread_data)
|
|
{
|
|
std::lock_guard lock{m_search_thread_data->mutex};
|
|
m_search_thread_data->discardResult = true;
|
|
}
|
|
}
|