From 915e0929fbf3edc3c53d696b38ef3becb0c9214d Mon Sep 17 00:00:00 2001 From: Alexander Yee Date: Sat, 5 Sep 2026 21:30:47 -0700 Subject: [PATCH] Fix more UI issues with controller selection. --- .../Source/Controllers/ControllerDescriptor.h | 5 ++ .../Source/Controllers/ControllerOption.cpp | 11 ++++ .../Source/Controllers/ControllerOption.h | 2 + .../Controllers/ControllerSelectorWidget.cpp | 54 +++++++------------ .../Controllers/ControllerSelectorWidget.h | 4 +- .../Source/Controllers/ControllerSession.cpp | 39 ++++++++++++++ .../Source/Controllers/ControllerSession.h | 1 + .../Controllers/ControllerTypeStrings.cpp | 2 +- .../Source/Controllers/ControllerTypes.h | 2 +- .../SerialPABotBase2_SelectorWidget.cpp | 5 +- 10 files changed, 83 insertions(+), 42 deletions(-) diff --git a/SerialPrograms/Source/Controllers/ControllerDescriptor.h b/SerialPrograms/Source/Controllers/ControllerDescriptor.h index 94ab6b3cb9..f0ef3bf13a 100644 --- a/SerialPrograms/Source/Controllers/ControllerDescriptor.h +++ b/SerialPrograms/Source/Controllers/ControllerDescriptor.h @@ -39,6 +39,8 @@ class InterfaceType{ public: virtual ~InterfaceType() = default; + virtual std::unique_ptr make() const = 0; + // Construct a descriptor from a JSON config. (reloading saved controller settings) virtual std::unique_ptr make(const JsonValue& json) const = 0; @@ -56,6 +58,9 @@ class InterfaceType{ template class InterfaceType_t : public InterfaceType{ public: + virtual std::unique_ptr make() const override{ + return std::make_unique(); + } virtual std::unique_ptr make(const JsonValue& json) const override{ std::unique_ptr ptr(new DescriptorType()); ptr->load_json(json); diff --git a/SerialPrograms/Source/Controllers/ControllerOption.cpp b/SerialPrograms/Source/Controllers/ControllerOption.cpp index 16953888b7..cfe095ab9a 100644 --- a/SerialPrograms/Source/Controllers/ControllerOption.cpp +++ b/SerialPrograms/Source/Controllers/ControllerOption.cpp @@ -49,6 +49,17 @@ ControllerOption::ControllerOption(bool default_enable_mode) {} +void ControllerOption::set_interface(ControllerInterface interface_type){ + m_sanitizer.check_scope(); + + m_descriptor_cache[m_descriptor->interface_type] = m_descriptor; + auto iter = m_descriptor_cache.find(interface_type); + if (iter != m_descriptor_cache.end()){ + m_descriptor = iter->second; + }else{ + m_descriptor = ALL_CONTROLLER_INTERFACES().find(interface_type)->second->make(); + } +} void ControllerOption::set_descriptor(std::shared_ptr descriptor){ m_sanitizer.check_scope(); diff --git a/SerialPrograms/Source/Controllers/ControllerOption.h b/SerialPrograms/Source/Controllers/ControllerOption.h index 1c823efffc..c695c249a8 100644 --- a/SerialPrograms/Source/Controllers/ControllerOption.h +++ b/SerialPrograms/Source/Controllers/ControllerOption.h @@ -21,6 +21,8 @@ class ControllerOption{ public: ControllerOption(bool default_enable_mode); + void set_interface(ControllerInterface interface_type); + std::shared_ptr descriptor() const{ return m_descriptor; } diff --git a/SerialPrograms/Source/Controllers/ControllerSelectorWidget.cpp b/SerialPrograms/Source/Controllers/ControllerSelectorWidget.cpp index 25524d4006..edb904f191 100644 --- a/SerialPrograms/Source/Controllers/ControllerSelectorWidget.cpp +++ b/SerialPrograms/Source/Controllers/ControllerSelectorWidget.cpp @@ -11,12 +11,7 @@ #include "Common/Qt/NoWheelComboBox.h" #include "CommonFramework/Panels/ConsoleSettingsStretch.h" #include "Controllers/ControllerTypeStrings.h" -#include "NullController.h" #include "ControllerSelectorWidget.h" -//#include "NintendoSwitch/NintendoSwitch_Settings.h" - -#include "PABotBase2/SerialPABotBase2_SelectorWidget.h" -#include "NintendoSwitch/Controllers/SysbotBase/SysbotBase_SelectorWidget.h" //#include //using std::cout; @@ -40,6 +35,8 @@ ControllerSelectorWidget::ControllerSelectorWidget( : QWidget(&parent) , m_session(session) { +// cout << "ControllerSelectorWidget()" << endl; + QHBoxLayout* layoutL = new QHBoxLayout(this); layoutL->setContentsMargins(0, 0, 0, 0); @@ -98,20 +95,13 @@ ControllerSelectorWidget::ControllerSelectorWidget( // m_interface_dropdown->setHidden(true); - auto current = session.descriptor(); - if (current == nullptr){ - current = null_controller_descriptor(); - session.set_device(std::move(current)); - } - update_interface_dropdown(current->interface_type); - m_selector = &static_cast(*current->make_ui_component(this)).widget(); - m_dropdowns->addWidget(m_selector, 1); + refresh_selection(); - m_dropdowns->addSpacing(5); +// m_dropdowns->addSpacing(5); m_controllers_dropdown = new NoWheelCompactComboBox(this); - m_controllers_dropdown->setSizeAdjustPolicy(QComboBox::AdjustToContents); - m_dropdowns->addWidget(m_controllers_dropdown, 5); +// m_controllers_dropdown->setSizeAdjustPolicy(QComboBox::AdjustToContents); + m_dropdowns->addWidget(m_controllers_dropdown, 3); refresh_controllers(session.controller_type(), session.available_controllers()); m_status_text = new QLabel(this); @@ -155,7 +145,9 @@ ControllerSelectorWidget::ControllerSelectorWidget( return; } - refresh_selection(incoming); + m_session.set_interface(incoming); + + refresh_selection(); } ); connect( @@ -228,30 +220,20 @@ void ControllerSelectorWidget::update_interface_dropdown(ControllerInterface int // m_session.set_controller(ControllerType::None); m_interface_dropdown->setCurrentIndex(-1); } -void ControllerSelectorWidget::refresh_selection(ControllerInterface interface_type){ -// cout << "refresh_selection(): " << CONTROLLER_INTERFACE_STRINGS.get_string(interface_type) << endl; - - update_interface_dropdown(interface_type); +void ControllerSelectorWidget::refresh_selection(){ +// cout << "refresh_selection()" << endl; delete m_selector; m_selector = nullptr; -// m_status_text->setText(QString::fromStdString(html_color_text("Not Connected", COLOR_RED))); - - switch (interface_type){ - case ControllerInterface::SerialPABotBase2: - m_selector = new SerialPABotBase::SerialPABotBase2_SelectorWidget(*this, m_session.descriptor().get()); - break; - - case ControllerInterface::TcpSysbotBase: - m_selector = new SysbotBase::TcpSysbotBase_SelectorWidget(*this, m_session.descriptor().get()); - break; - - default:;; + auto current = m_session.descriptor(); + if (current == nullptr){ m_selector = new QWidget(this); + }else{ + update_interface_dropdown(current->interface_type); + m_selector = &static_cast(*current->make_ui_component(this)).widget(); + m_dropdowns->insertWidget(1, m_selector, 1); } - - m_dropdowns->insertWidget(1, m_selector, 1); } void ControllerSelectorWidget::refresh_controllers( @@ -283,7 +265,7 @@ void ControllerSelectorWidget::descriptor_changed( ){ // cout << "descriptor_changed()" << endl; QMetaObject::invokeMethod(this, [=, this]{ - refresh_selection(descriptor->interface_type); + refresh_selection(); refresh_controllers(ControllerType::None, {}); }, Qt::QueuedConnection); } diff --git a/SerialPrograms/Source/Controllers/ControllerSelectorWidget.h b/SerialPrograms/Source/Controllers/ControllerSelectorWidget.h index fe149cfe64..4ef08dcf4d 100644 --- a/SerialPrograms/Source/Controllers/ControllerSelectorWidget.h +++ b/SerialPrograms/Source/Controllers/ControllerSelectorWidget.h @@ -20,7 +20,7 @@ namespace PokemonAutomation{ -class ControllerSelectorWidget +class ControllerSelectorWidget final : public QWidget , public UiComponentQtWidget , private ControllerSession::Listener @@ -53,7 +53,7 @@ class ControllerSelectorWidget private: void update_interface_dropdown(ControllerInterface interface_type); - void refresh_selection(ControllerInterface interface_type); + void refresh_selection(); void refresh_controllers( ControllerType controller_type, const std::vector& available_controllers diff --git a/SerialPrograms/Source/Controllers/ControllerSession.cpp b/SerialPrograms/Source/Controllers/ControllerSession.cpp index a55082dfab..ba663335d3 100644 --- a/SerialPrograms/Source/Controllers/ControllerSession.cpp +++ b/SerialPrograms/Source/Controllers/ControllerSession.cpp @@ -206,6 +206,45 @@ void ControllerSession::make_controller( + +bool ControllerSession::set_interface(ControllerInterface controller_interface){ + std::shared_ptr device; + { + std::lock_guard lg0(m_reset_lock); + + // Destroy the current connection+controller. + std::unique_ptr controller; + std::unique_ptr connection; + { + WriteSpinLock lg1(m_state_lock); + if (m_options_locked){ + return false; + } + if (controller_interface == m_descriptor->interface_type){ + return true; + } + + // Move these out to indicate that we should no longer access them. + controller = std::move(m_controller); + connection = std::move(m_connection); + + m_option.set_interface(controller_interface); + m_descriptor = m_option.descriptor(); + } + + // With the lock released, it is now safe to destroy them. + // We cannot destroy these under (m_state_lock) due to their asynchronous + // callbacks into this class which will also acquire the same lock. + controller.reset(); + connection.reset(); + + make_controller({}, false); + } +// cout << "ControllerSession::set_interface() - signal"<< endl; + signal_descriptor_changed(device); + signal_status_text_changed(status_text()); + return true; +} bool ControllerSession::set_device(const std::shared_ptr& device){ // cout << "ControllerSession::set_device() = " << device->display_name() << endl; { diff --git a/SerialPrograms/Source/Controllers/ControllerSession.h b/SerialPrograms/Source/Controllers/ControllerSession.h index 8a8e12c376..3e0532b9fa 100644 --- a/SerialPrograms/Source/Controllers/ControllerSession.h +++ b/SerialPrograms/Source/Controllers/ControllerSession.h @@ -90,6 +90,7 @@ class ControllerSession final public: + bool set_interface(ControllerInterface controller_interface); bool set_device(const std::shared_ptr& device); bool set_controller(ControllerType controller_type); diff --git a/SerialPrograms/Source/Controllers/ControllerTypeStrings.cpp b/SerialPrograms/Source/Controllers/ControllerTypeStrings.cpp index e92b15c9cb..bbdddf11be 100644 --- a/SerialPrograms/Source/Controllers/ControllerTypeStrings.cpp +++ b/SerialPrograms/Source/Controllers/ControllerTypeStrings.cpp @@ -15,7 +15,7 @@ const EnumStringMap CONTROLLER_INTERFACE_STRINGS{ // {ControllerInterface::SerialPABotBase, "Serial: PABotBase"}, {ControllerInterface::SerialPABotBase2, "Serial: PABotBase2"}, {ControllerInterface::TcpSysbotBase, "TCP: sys-botbase"}, - {ControllerInterface::UsbSysbotBase, "USB: sys-botbase"}, +// {ControllerInterface::UsbSysbotBase, "USB: sys-botbase"}, }; const EnumStringMap CONTROLLER_TYPE_STRINGS{ diff --git a/SerialPrograms/Source/Controllers/ControllerTypes.h b/SerialPrograms/Source/Controllers/ControllerTypes.h index 0a32cd16d4..8a03518c01 100644 --- a/SerialPrograms/Source/Controllers/ControllerTypes.h +++ b/SerialPrograms/Source/Controllers/ControllerTypes.h @@ -16,7 +16,7 @@ enum class ControllerInterface{ // SerialPABotBase, SerialPABotBase2, TcpSysbotBase, - UsbSysbotBase, +// UsbSysbotBase, }; enum class ControllerPerformanceClass{ diff --git a/SerialPrograms/Source/Controllers/PABotBase2/SerialPABotBase2_SelectorWidget.cpp b/SerialPrograms/Source/Controllers/PABotBase2/SerialPABotBase2_SelectorWidget.cpp index 37b4c94524..5bb08a689a 100644 --- a/SerialPrograms/Source/Controllers/PABotBase2/SerialPABotBase2_SelectorWidget.cpp +++ b/SerialPrograms/Source/Controllers/PABotBase2/SerialPABotBase2_SelectorWidget.cpp @@ -67,9 +67,10 @@ SerialPABotBase2_SelectorWidget::SerialPABotBase2_SelectorWidget( { SerialPortPoller::instance().begin_refresh_now(); -// cout << "SerialPABotBase(): " << current << endl; +// cout << "SerialPABotBase(): " << current << endl; this->setMaxVisibleItems(32); - this->setPlaceholderText("(invalid or still loading...)"); +// this->setPlaceholderText("invalid/loading..."); +// this->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum); if (current == nullptr || current->interface_type != ControllerInterface::SerialPABotBase2){ std::shared_ptr descriptor =