diff --git a/SerialPrograms/Source/GameConsole/MultiConsoleSystemOption.cpp b/SerialPrograms/Source/GameConsole/MultiConsoleSystemOption.cpp index e0f15e0e7d..6d93c83a39 100644 --- a/SerialPrograms/Source/GameConsole/MultiConsoleSystemOption.cpp +++ b/SerialPrograms/Source/GameConsole/MultiConsoleSystemOption.cpp @@ -22,7 +22,7 @@ MultiConsoleSystemOption::MultiConsoleSystemOption( size_t min_consoles, size_t max_consoles, size_t consoles, - std::function()> console_factory + std::function()> factory ) : m_min_consoles(std::max(min_consoles, (size_t)1)) , m_max_consoles(std::min(max_consoles, (size_t)MAX_CONSOLES)) @@ -30,7 +30,7 @@ MultiConsoleSystemOption::MultiConsoleSystemOption( , m_consoles(m_max_consoles) { for (size_t c = 0; c < m_max_consoles; c++){ - m_consoles.emplace_back(console_factory()); + m_consoles.emplace_back(factory()); } consoles = std::max(consoles, m_min_consoles); consoles = std::min(consoles, m_max_consoles); @@ -40,9 +40,9 @@ MultiConsoleSystemOption::MultiConsoleSystemOption( size_t min_consoles, size_t max_consoles, const JsonValue& json, - std::function()> console_factory + std::function()> factory ) - : MultiConsoleSystemOption(min_consoles, max_consoles, 0, std::move(console_factory)) + : MultiConsoleSystemOption(min_consoles, max_consoles, 0, std::move(factory)) { MultiConsoleSystemOption::load_json(json); } diff --git a/SerialPrograms/Source/GameConsole/MultiConsoleSystemOption.h b/SerialPrograms/Source/GameConsole/MultiConsoleSystemOption.h index 9ee72a72c3..638cefdf33 100644 --- a/SerialPrograms/Source/GameConsole/MultiConsoleSystemOption.h +++ b/SerialPrograms/Source/GameConsole/MultiConsoleSystemOption.h @@ -4,8 +4,8 @@ * */ -#ifndef PokemonAutomation_ConsoleInfra_MultiConsoleSystemOption_H -#define PokemonAutomation_ConsoleInfra_MultiConsoleSystemOption_H +#ifndef PokemonAutomation_GameConsole_MultiConsoleSystemOption_H +#define PokemonAutomation_GameConsole_MultiConsoleSystemOption_H #include #include "Common/Cpp/Containers/FixedLimitVector.h" @@ -25,13 +25,17 @@ class MultiConsoleSystemOption{ size_t min_consoles, size_t max_consoles, size_t consoles, - std::function()> console_factory + std::function()> factory = []{ + return std::make_unique(1); + } ); MultiConsoleSystemOption( size_t min_consoles, size_t max_consoles, const JsonValue& json, - std::function()> console_factory + std::function()> factory = []{ + return std::make_unique(1); + } ); void resize(size_t count){ diff --git a/SerialPrograms/Source/GameConsole/MultiConsoleSystemSession.cpp b/SerialPrograms/Source/GameConsole/MultiConsoleSystemSession.cpp new file mode 100644 index 0000000000..f2a967eabe --- /dev/null +++ b/SerialPrograms/Source/GameConsole/MultiConsoleSystemSession.cpp @@ -0,0 +1,159 @@ +/* Multi-Console System Session + * + * From: https://github.com/PokemonAutomation/ + * + */ + +#include "Common/Cpp/Logging/GlobalLogger.h" +#include "Common/Cpp/EarlyShutdown.h" +#include "Common/Cpp/Containers/FixedLimitVector.tpp" +#include "CommonFramework/Logging/Logger.h" +#include "MultiConsoleSystemSession.h" + +//#include +//using std::cout; +//using std::endl; + +namespace PokemonAutomation{ +namespace GameConsole{ + + +void MultiConsoleSystemSession::add_listener(Listener& listener){ + m_listeners.add(listener); +} +void MultiConsoleSystemSession::remove_listener(Listener& listener){ + m_listeners.remove(listener); +} + +bool MultiConsoleSystemSession::try_shutdown(){ + bool success = true; + for (std::unique_ptr& console : m_consoles){ + success &= console->try_shutdown(); + } + return success; +} +MultiConsoleSystemSession::~MultiConsoleSystemSession(){ + blocking_shutdown( + global_logger_tagged(), + "MultiConsoleSystemSession", + [this]{ return try_shutdown(); } + ); +} + +MultiConsoleSystemSession::MultiConsoleSystemSession( + MultiConsoleSystemOption& option, + bool allow_commands_while_locked, + std::optional program_tracking_id +) + : MultiConsoleSystemSession( + option, + [allow_commands_while_locked, program_tracking_id](ConsoleSystemOption& option, size_t console_index){ + return std::make_unique( + global_logger_raw(), + option, + allow_commands_while_locked, + console_index, + program_tracking_id + ); + } + ) +{} +MultiConsoleSystemSession::MultiConsoleSystemSession( + MultiConsoleSystemOption& option, + std::function< + std::unique_ptr( + ConsoleSystemOption& option, + size_t console_index + ) + > factory +) + : m_option(option) + , m_consoles(option.active_consoles()) + , m_factory(std::move(factory)) +{ + size_t count = option.active_consoles(); + for (size_t c = 0; c < count; c++){ + m_consoles.emplace_back(m_factory(option[c], c)); + } +} + +void MultiConsoleSystemSession::lock_controllers(const std::string& reason){ + std::unique_lock lg1(m_state_lock); + m_listeners.run_method(&Listener::on_console_count_lock, true); + for (std::unique_ptr& console : m_consoles){ + console->lock_controllers(reason); + } +} +void MultiConsoleSystemSession::unlock_controllers(){ + std::unique_lock lg1(m_state_lock); + for (std::unique_ptr& console : m_consoles){ + console->unlock_controllers(); + } + m_listeners.run_method(&Listener::on_console_count_lock, false); +} + + +void MultiConsoleSystemSession::add_console_count_lock(Listener& listener){ +// cout << "add_console_count_lock()" << endl; + std::lock_guard lg(m_state_lock); + m_count_locks.insert(&listener); +} +void MultiConsoleSystemSession::remove_console_count_lock(Listener& listener){ +// cout << "remove_console_count_lock()" << endl; + std::lock_guard lg(m_state_lock); + m_count_locks.erase(&listener); +} + +void MultiConsoleSystemSession::set_active_consoles(size_t count){ + { + std::lock_guard lg(m_state_lock); + if (count == m_option.active_consoles() && + count == m_consoles.size() + ){ + return; + } + } + + std::lock_guard lg0(m_resize_lock); + + // Signal all listeners to drop locks. + m_listeners.run_method(&Listener::shutdown); + + { + std::unique_lock lg1(m_state_lock); + + // Wait for all locks to be dropped. + m_cv.wait(lg1, [this]{ + return m_count_locks.empty(); + }); + + m_consoles.reset(count); + m_option.resize(count); + for (size_t c = 0; c < count; c++){ + m_consoles.emplace_back(m_factory(m_option[c], c)); + } + } + + // Signal all listeners it's ok to re-lock. + m_listeners.run_method(&Listener::startup, count); +} + + +JsonValue MultiConsoleSystemSession::to_json() const{ + std::lock_guard lg(m_state_lock); + return m_option.to_json(); +} +void MultiConsoleSystemSession::load_json(const JsonValue& json){ +// cout << "MultiConsoleSystemSession::load_json()" << endl; + { + std::lock_guard lg(m_state_lock); + m_option.load_json(json); + } + set_active_consoles(m_option.active_consoles()); +} + + + + +} +} diff --git a/SerialPrograms/Source/GameConsole/MultiConsoleSystemSession.h b/SerialPrograms/Source/GameConsole/MultiConsoleSystemSession.h new file mode 100644 index 0000000000..3747d4e547 --- /dev/null +++ b/SerialPrograms/Source/GameConsole/MultiConsoleSystemSession.h @@ -0,0 +1,113 @@ +/* Multi-Console System Session + * + * From: https://github.com/PokemonAutomation/ + * + */ + +#ifndef PokemonAutomation_GameConsole_MultiConsoleSystemSession_H +#define PokemonAutomation_GameConsole_MultiConsoleSystemSession_H + +#include "Common/Cpp/ListenerSet.h" +#include "Common/Cpp/UiWrapper.h" +#include "Common/Cpp/Containers/FixedLimitVector.h" +#include "GameConsole/ConsoleSystemSession.h" +#include "MultiConsoleSystemOption.h" + +namespace PokemonAutomation{ +namespace GameConsole{ + + +class MultiConsoleSystemSession : public UiState{ +public: + struct Listener{ + // Called when the console count is locked or unlocked. + virtual void on_console_count_lock(bool locked) = 0; + + // Sent before the console sessions are destroyed. Listeners should + // drop their references to them before returning. + virtual void shutdown() = 0; + + // Sent after new consoles are started up. + // This is called immediately when attaching a listener to give the + // current console count. The listener must drop all references to the + // console sessions before detaching. + virtual void startup(size_t console_count) = 0; + }; + void add_listener(Listener& listener); + void remove_listener(Listener& listener); + + +public: + bool try_shutdown(); + virtual ~MultiConsoleSystemSession(); + + MultiConsoleSystemSession( + MultiConsoleSystemOption& option, + bool allow_commands_while_locked, + std::optional program_tracking_id = {} + ); + MultiConsoleSystemSession( + MultiConsoleSystemOption& option, + std::function< + std::unique_ptr( + ConsoleSystemOption& option, + size_t console_index + ) + > factory + ); + + +public: + // These are not thread-safe with "resize()". + size_t min_consoles() const{ return m_option.min_consoles(); } + size_t max_consoles() const{ return m_option.max_consoles(); } + + size_t active_consoles() const{ return m_consoles.size(); } + ConsoleSystemSession& operator[](size_t index){ return *m_consoles[index]; } + + +public: + void lock_controllers(const std::string& reason); + void unlock_controllers(); + + +public: + // Lock/unlock the console count. + void add_console_count_lock(Listener& listener); + void remove_console_count_lock(Listener& listener); + + void set_active_consoles(size_t count); + + +public: + JsonValue to_json() const; + void load_json(const JsonValue& json); + + +private: + MultiConsoleSystemOption& m_option; + + Mutex m_resize_lock; + FixedLimitVector> m_consoles; + + std::function< + std::unique_ptr( + ConsoleSystemOption& option, + size_t console_index + ) + > m_factory; + + // Listeners who are currently locking the console count. + // It is not safe to change the console count if this is not zero. + mutable Mutex m_state_lock; + ConditionVariable m_cv; + std::set m_count_locks; + + ListenerSet m_listeners; +}; + + + +} +} +#endif diff --git a/SerialPrograms/Source/GameConsole/UI/MultiConsoleSystemWidget.cpp b/SerialPrograms/Source/GameConsole/UI/MultiConsoleSystemWidget.cpp new file mode 100644 index 0000000000..78f391080c --- /dev/null +++ b/SerialPrograms/Source/GameConsole/UI/MultiConsoleSystemWidget.cpp @@ -0,0 +1,145 @@ +/* Multi-Console System Widget + * + * From: https://github.com/PokemonAutomation/ + * + */ + +#include +#include +#include +#include "Common/Qt/Redispatch.h" +#include "Common/Qt/NoWheelComboBox.h" +#include "MultiConsoleSystemWidget.h" + +//#include +//using std::cout; +//using std::endl; + +namespace PokemonAutomation{ + +template class RegisterUiStateQtWidget; + +namespace GameConsole{ + + +MultiConsoleSystemWidget::~MultiConsoleSystemWidget(){ + m_session.remove_console_count_lock(*this); + m_session.remove_listener(*this); + + delete m_videos; +} +MultiConsoleSystemWidget::MultiConsoleSystemWidget( + QWidget& parent, + MultiConsoleSystemSession& session +) + : QWidget(&parent) + , m_session(session) +{ + QVBoxLayout* vbox = new QVBoxLayout(this); + vbox->setContentsMargins(0, 0, 0, 0); + + QHBoxLayout* row = new QHBoxLayout(); + vbox->addLayout(row, 0); + row->setContentsMargins(0, 0, 0, 0); + row->addStretch(2); + row->addWidget(new QLabel("Console Count:", this), 0); + m_console_count_box = new NoWheelCompactComboBox(this); + row->addWidget(m_console_count_box, 1); + row->addStretch(2); + + for (size_t c = session.min_consoles(); c <= session.max_consoles(); c++){ + m_console_count_box->addItem(QString::number(c)); + } + + m_session.add_listener(*this); + + redraw_videos(); + + connect( + m_console_count_box, static_cast(&QComboBox::currentIndexChanged), + this, [this](int index){ + if (index < 0 || index > (int)(m_session.max_consoles() - m_session.min_consoles())){ + return; + } + m_session.set_active_consoles(index + m_session.min_consoles()); + } + ); +} + + +void MultiConsoleSystemWidget::on_console_count_lock(bool locked){ +// cout << "MultiConsoleSystemWidget::on_console_count_lock(): " << locked << endl; + QMetaObject::invokeMethod(this, [=, this]{ + m_console_count_box->setEnabled(!locked); + }, Qt::QueuedConnection); +} +void MultiConsoleSystemWidget::shutdown(){ + run_on_main_thread_and_wait([this]{ + delete m_videos; + m_videos = nullptr; + }); + m_session.remove_console_count_lock(*this); +} +void MultiConsoleSystemWidget::startup(size_t console_count){ + QMetaObject::invokeMethod(this, [this]{ + redraw_videos(); + }, Qt::QueuedConnection); +} + +void MultiConsoleSystemWidget::redraw_videos(){ + int old_index = m_console_count_box->currentIndex(); + int new_index = (int)(m_session.active_consoles() - m_session.min_consoles()); + if (new_index != old_index){ + m_console_count_box->setCurrentIndex(new_index); + } + + delete m_videos; + + m_videos = new QWidget(this); + this->layout()->addWidget(m_videos); + QVBoxLayout* vbox = new QVBoxLayout(m_videos); + vbox->setContentsMargins(0, 0, 0, 0); + + std::vector consoles; + consoles.reserve(m_session.active_consoles()); + + m_session.add_console_count_lock(*this); + + for (size_t c = 0; c < m_session.active_consoles(); c++){ + UiWrapper wrapper = m_session[c].make_ui_component(this); + consoles.emplace_back(dynamic_cast(wrapper.release())); + } + + QHBoxLayout* vrow0 = new QHBoxLayout(); + vbox->addLayout(vrow0, 1); + vrow0->setContentsMargins(0, 0, 0, 0); + + vrow0->addWidget(consoles[0], 1); + if (consoles.size() >= 2){ + vrow0->addWidget(consoles[1], 1); + } + if (consoles.size() >= 3){ + QHBoxLayout* vrow1 = new QHBoxLayout(); + vbox->addLayout(vrow1, 1); + vrow1->setContentsMargins(0, 0, 0, 0); + vrow1->addWidget(consoles[2], 1); + if (consoles.size() >= MultiConsoleSystemOption::MAX_CONSOLES){ + vrow1->addWidget(consoles[3], 1); + }else{ + vrow1->addWidget(new QWidget(), 1); + } + } + static_assert( + MultiConsoleSystemOption::MAX_CONSOLES <= 4, + "Can't display more than 4 consoles." + ); +} + + + + + + + +} +} diff --git a/SerialPrograms/Source/GameConsole/UI/MultiConsoleSystemWidget.h b/SerialPrograms/Source/GameConsole/UI/MultiConsoleSystemWidget.h new file mode 100644 index 0000000000..8a778fe9e4 --- /dev/null +++ b/SerialPrograms/Source/GameConsole/UI/MultiConsoleSystemWidget.h @@ -0,0 +1,59 @@ +/* Multi-Console System Widget + * + * From: https://github.com/PokemonAutomation/ + * + */ + +#ifndef PokemonAutomationn_GameConsole_MultiConsoleSystemWidget_H +#define PokemonAutomationn_GameConsole_MultiConsoleSystemWidget_H + +#include +#include +#include "Common/Qt/UiStateQtWidget.h" +#include "GameConsole/MultiConsoleSystemSession.h" + +namespace PokemonAutomation{ +namespace GameConsole{ + + +class MultiConsoleSystemWidget final + : public QWidget + , public UiComponentQtWidget + , private MultiConsoleSystemSession::Listener +{ +public: + using ParentState = MultiConsoleSystemSession; + + +public: + virtual ~MultiConsoleSystemWidget(); + + MultiConsoleSystemWidget( + QWidget& parent, + MultiConsoleSystemSession& session + ); + + virtual QWidget& widget() override{ + return *this; + } + + +private: + virtual void on_console_count_lock(bool locked) override; + virtual void shutdown() override; + virtual void startup(size_t console_count) override; + + void redraw_videos(); + + +private: + MultiConsoleSystemSession& m_session; + QComboBox* m_console_count_box; + QWidget* m_videos = nullptr; +}; + + + +} +} +#endif diff --git a/SerialPrograms/Source/NintendoSwitch/Framework/NintendoSwitch_MultiSwitchProgramSession.cpp b/SerialPrograms/Source/NintendoSwitch/Framework/NintendoSwitch_MultiSwitchProgramSession.cpp index c1e2a7fcf0..c61792972a 100644 --- a/SerialPrograms/Source/NintendoSwitch/Framework/NintendoSwitch_MultiSwitchProgramSession.cpp +++ b/SerialPrograms/Source/NintendoSwitch/Framework/NintendoSwitch_MultiSwitchProgramSession.cpp @@ -122,7 +122,7 @@ void MultiSwitchProgramSession::run_program_instance(MultiSwitchProgramEnvironme } std::deque> contexts; - size_t consoles = m_system.count(); + size_t consoles = m_system.active_consoles(); for (size_t console = 0; console < consoles; console++){ // Startup Checks m_instance->start_program_controller_check( @@ -206,8 +206,8 @@ void MultiSwitchProgramSession::internal_run_program(){ SleepSuppressScope sleep_scope(GlobalSettings::instance().SLEEP_SUPPRESS->PROGRAM_RUNNING); - // Lock the system to prevent the # of Switches from changing. - std::lock_guard lg(m_system); +// // Lock the system to prevent the # of Switches from changing. +// std::lock_guard lg(m_system); ProgramInfo program_info( identifier(), @@ -216,7 +216,7 @@ void MultiSwitchProgramSession::internal_run_program(){ timestamp() ); - size_t consoles = m_system.count(); + size_t consoles = m_system.active_consoles(); FixedLimitVector handles(consoles); for (size_t c = 0; c < consoles; c++){ SwitchSystemSession& session = m_system[c]; diff --git a/SerialPrograms/Source/NintendoSwitch/Framework/NintendoSwitch_MultiSwitchProgramSession.h b/SerialPrograms/Source/NintendoSwitch/Framework/NintendoSwitch_MultiSwitchProgramSession.h index a3fa9711fe..af847b89ce 100644 --- a/SerialPrograms/Source/NintendoSwitch/Framework/NintendoSwitch_MultiSwitchProgramSession.h +++ b/SerialPrograms/Source/NintendoSwitch/Framework/NintendoSwitch_MultiSwitchProgramSession.h @@ -56,6 +56,7 @@ class MultiSwitchProgramSession final virtual void internal_run_program() override; virtual void internal_stop_program() override; + virtual void on_console_count_lock(bool locked) override{} virtual void shutdown() override; virtual void startup(size_t switch_count) override; diff --git a/SerialPrograms/Source/NintendoSwitch/Framework/NintendoSwitch_MultiSwitchSystemSession.cpp b/SerialPrograms/Source/NintendoSwitch/Framework/NintendoSwitch_MultiSwitchSystemSession.cpp deleted file mode 100644 index 9e3a952103..0000000000 --- a/SerialPrograms/Source/NintendoSwitch/Framework/NintendoSwitch_MultiSwitchSystemSession.cpp +++ /dev/null @@ -1,104 +0,0 @@ -/* Multi-Switch System Session - * - * From: https://github.com/PokemonAutomation/ - * - */ - -#include "Common/Cpp/EarlyShutdown.h" -#include "Common/Cpp/Containers/FixedLimitVector.tpp" -#include "CommonFramework/Logging/Logger.h" -#include "NintendoSwitch_MultiSwitchSystemSession.h" - -namespace PokemonAutomation{ -namespace NintendoSwitch{ - - - -void MultiSwitchSystemSession::add_listener(Listener& listener){ - std::lock_guard lg(m_lock); - m_listeners.insert(&listener); - listener.startup(m_consoles.size()); -} -void MultiSwitchSystemSession::remove_listener(Listener& listener){ - std::lock_guard lg(m_lock); - m_listeners.erase(&listener); -} - - -bool MultiSwitchSystemSession::try_shutdown(){ - bool success = true; - for (SwitchSystemSession& console : m_consoles){ - success &= console.try_shutdown(); - } - return success; -} -MultiSwitchSystemSession::~MultiSwitchSystemSession(){ - blocking_shutdown( - global_logger_tagged(), - "MultiSwitchSystemSession", - [this]{ return try_shutdown(); } - ); -} - -MultiSwitchSystemSession::MultiSwitchSystemSession( - MultiSwitchSystemOption& option, - bool allow_commands_while_locked, - uint64_t program_id -) - : m_option(option) - , m_allow_commands_while_locked(allow_commands_while_locked) - , m_program_id(program_id) - , m_switch_count_locked(false) - , m_consoles(option.active_consoles()) -{ - size_t count = option.active_consoles(); - for (size_t c = 0; c < count; c++){ - m_consoles.emplace_back(option[c], allow_commands_while_locked, c, program_id); - } -} - -void MultiSwitchSystemSession::lock(){ - std::lock_guard lg(m_lock); - m_switch_count_locked = true; -} -void MultiSwitchSystemSession::unlock(){ - std::lock_guard lg(m_lock); - m_switch_count_locked = false; -} -bool MultiSwitchSystemSession::set_switch_count(size_t count){ - std::lock_guard lg(m_lock); - if (m_switch_count_locked){ - return false; - } - - for (Listener* listener : m_listeners){ - listener->shutdown(); - } - m_consoles.reset(count); - m_option.resize(count); - for (size_t c = 0; c < count; c++){ - m_consoles.emplace_back(m_option[c], m_allow_commands_while_locked, c, m_program_id); - } - for (Listener* listener : m_listeners){ - listener->startup(count); - } - - return true; -} - - - -JsonValue MultiSwitchSystemSession::to_json() const{ - return m_option.to_json(); -} -void MultiSwitchSystemSession::load_json(const JsonValue& json){ - m_option.load_json(json); - set_switch_count(m_option.active_consoles()); -} - - - - - -} -} diff --git a/SerialPrograms/Source/NintendoSwitch/Framework/NintendoSwitch_MultiSwitchSystemSession.h b/SerialPrograms/Source/NintendoSwitch/Framework/NintendoSwitch_MultiSwitchSystemSession.h index 6c16ccf8d8..71f224c1f5 100644 --- a/SerialPrograms/Source/NintendoSwitch/Framework/NintendoSwitch_MultiSwitchSystemSession.h +++ b/SerialPrograms/Source/NintendoSwitch/Framework/NintendoSwitch_MultiSwitchSystemSession.h @@ -15,7 +15,7 @@ #ifndef PokemonAutomationn_NintendoSwitch_MultiSwitchSystemSession_H #define PokemonAutomationn_NintendoSwitch_MultiSwitchSystemSession_H -#include "Common/Cpp/Containers/FixedLimitVector.h" +#include "GameConsole/MultiConsoleSystemSession.h" #include "NintendoSwitch_SwitchSystemSession.h" #include "NintendoSwitch_MultiSwitchSystemOption.h" @@ -23,61 +23,29 @@ namespace PokemonAutomation{ namespace NintendoSwitch{ -class MultiSwitchSystemSession{ +class MultiSwitchSystemSession : public GameConsole::MultiConsoleSystemSession{ public: - struct Listener{ - // Sent before the Switch sessions are destroyed. Listeners should - // drop their references to them before returning. - virtual void shutdown() = 0; - - // Sent after new Switches are started up. - // This is called immediately when attaching a listener to give the - // current switch count. The listener must drop all references to the - // switch sessions before detaching. - virtual void startup(size_t switch_count) = 0; - }; - void add_listener(Listener& listener); - void remove_listener(Listener& listener); - - -public: - bool try_shutdown(); - ~MultiSwitchSystemSession(); MultiSwitchSystemSession( MultiSwitchSystemOption& option, bool allow_commands_while_locked, uint64_t program_id - ); - - // Lock/unlock the Switch count. - void lock(); - void unlock(); - - // Returns true only on success. - bool set_switch_count(size_t count); - - size_t min_switches() const{ return m_option.min_consoles(); } - size_t max_switches() const{ return m_option.max_consoles(); } - - -public: - // Note that these are not thread-safe with changing the # of switches. - size_t count() const{ return m_consoles.size(); } - SwitchSystemSession& operator[](size_t index){ return m_consoles[index]; } - - JsonValue to_json() const; - void load_json(const JsonValue& json); - - -private: - MultiSwitchSystemOption& m_option; - const bool m_allow_commands_while_locked; - const uint64_t m_program_id; - - Mutex m_lock; - bool m_switch_count_locked; - FixedLimitVector m_consoles; - std::set m_listeners; + ) + : GameConsole::MultiConsoleSystemSession( + option, + [=](GameConsole::ConsoleSystemOption& option, size_t console_index){ + return std::make_unique( + static_cast(option), + allow_commands_while_locked, + console_index, + program_id + ); + } + ) + {} + + SwitchSystemSession& operator[](size_t index){ + return static_cast(MultiConsoleSystemSession::operator[](index)); + } }; diff --git a/SerialPrograms/Source/NintendoSwitch/Framework/UI/NintendoSwitch_MultiSwitchProgramWidget.cpp b/SerialPrograms/Source/NintendoSwitch/Framework/UI/NintendoSwitch_MultiSwitchProgramWidget.cpp index 6feab5f41b..fb1630efec 100644 --- a/SerialPrograms/Source/NintendoSwitch/Framework/UI/NintendoSwitch_MultiSwitchProgramWidget.cpp +++ b/SerialPrograms/Source/NintendoSwitch/Framework/UI/NintendoSwitch_MultiSwitchProgramWidget.cpp @@ -34,6 +34,7 @@ namespace NintendoSwitch{ MultiSwitchProgramWidget2::~MultiSwitchProgramWidget2(){ auto ScopeCheck = m_sanitizer.check_scope(); + m_session.system().remove_console_count_lock(*this); m_session.ProgramSession::remove_listener(*this); m_session.remove_listener(*this); } @@ -84,8 +85,8 @@ MultiSwitchProgramWidget2::MultiSwitchProgramWidget2( QVBoxLayout* scroll_layout = new QVBoxLayout(scroll_inner); scroll_layout->setAlignment(Qt::AlignTop); - m_system = new MultiSwitchSystemWidget(*this, m_session.system(), m_session.instance_id()); - scroll_layout->addWidget(m_system); + UiWrapper wrapper = m_session.system().make_ui_component(this); + scroll_layout->addWidget(dynamic_cast(wrapper.release())); m_options = ConfigWidget::make_from_option(m_session.options(), this); scroll_layout->addWidget(&m_options->widget()); @@ -139,8 +140,16 @@ MultiSwitchProgramWidget2::MultiSwitchProgramWidget2( void MultiSwitchProgramWidget2::state_change(ProgramState state){ auto ScopeCheck = m_sanitizer.check_scope(); QMetaObject::invokeMethod(this, [this, state]{ - m_system->update_ui(state); + + if (state != ProgramState::STOPPED){ + m_session.system().add_console_count_lock(*this); + m_session.system().lock_controllers("Program is Running"); + }else{ + m_session.system().unlock_controllers(); + m_session.system().remove_console_count_lock(*this); + } m_options->option().report_program_state(state != ProgramState::STOPPED); + // cout << "state = " << (state != ProgramState::STOPPED) << endl; // if (m_option.descriptor().lock_options_while_running()){ // m_options->widget().setEnabled(state == ProgramState::STOPPED); diff --git a/SerialPrograms/Source/NintendoSwitch/Framework/UI/NintendoSwitch_MultiSwitchProgramWidget.h b/SerialPrograms/Source/NintendoSwitch/Framework/UI/NintendoSwitch_MultiSwitchProgramWidget.h index 03a8075a62..524dc62d34 100644 --- a/SerialPrograms/Source/NintendoSwitch/Framework/UI/NintendoSwitch_MultiSwitchProgramWidget.h +++ b/SerialPrograms/Source/NintendoSwitch/Framework/UI/NintendoSwitch_MultiSwitchProgramWidget.h @@ -22,7 +22,6 @@ #include "CommonFramework/Panels/UI/PanelElements.h" #include "NintendoSwitch/NintendoSwitch_MultiSwitchProgram.h" #include "NintendoSwitch/Framework/NintendoSwitch_MultiSwitchProgramSession.h" -#include "NintendoSwitch_MultiSwitchSystemWidget.h" QT_FORWARD_DECLARE_CLASS(QVBoxLayout) namespace PokemonAutomation{ @@ -36,6 +35,7 @@ class MultiSwitchProgramWidget2 : public QWidget , public UiComponentQtWidget , private ProgramSession::Listener + , private GameConsole::MultiConsoleSystemSession::Listener , private MultiSwitchProgramSession::Listener { public: @@ -50,6 +50,10 @@ class MultiSwitchProgramWidget2 } private: + virtual void on_console_count_lock(bool locked) override{} + virtual void shutdown() override{} + virtual void startup(size_t console_count) override{} + virtual void state_change(ProgramState state) override; virtual void stats_update(const StatsTracker* current_stats, const StatsTracker* historical_stats) override; virtual void error(const std::string& message) override; @@ -64,7 +68,6 @@ class MultiSwitchProgramWidget2 private: MultiSwitchProgramSession& m_session; QVBoxLayout* m_layout; - MultiSwitchSystemWidget* m_system; ConfigWidget* m_options; StatsBar* m_stats_bar; RunnablePanelActionBar* m_actions_bar; diff --git a/SerialPrograms/Source/NintendoSwitch/Framework/UI/NintendoSwitch_MultiSwitchSystemWidget.cpp b/SerialPrograms/Source/NintendoSwitch/Framework/UI/NintendoSwitch_MultiSwitchSystemWidget.cpp deleted file mode 100644 index 4b791d1330..0000000000 --- a/SerialPrograms/Source/NintendoSwitch/Framework/UI/NintendoSwitch_MultiSwitchSystemWidget.cpp +++ /dev/null @@ -1,179 +0,0 @@ -/* Multi-Switch System Widget - * - * From: https://github.com/PokemonAutomation/ - * - */ - -#include -#include -#include "Common/Qt/NoWheelComboBox.h" -#include "NintendoSwitch_SwitchSystemWidget.h" -#include "NintendoSwitch_MultiSwitchSystemWidget.h" - -#include -using std::cout; -using std::endl; - -namespace PokemonAutomation{ -namespace NintendoSwitch{ - - -MultiSwitchSystemWidget::~MultiSwitchSystemWidget(){ - { - std::lock_guard lg(m_lock); - for (SwitchSystemWidget* console : m_switches){ - delete console; - } - m_switches.clear(); - delete m_videos; - m_videos = nullptr; - m_shutting_down = true; - } - m_session.remove_listener(*this); -} -MultiSwitchSystemWidget::MultiSwitchSystemWidget( - QWidget& parent, - MultiSwitchSystemSession& session, - uint64_t program_id -) - : QWidget(&parent) - , m_program_id(program_id) - , m_session(session) - , m_videos(nullptr) -{ - QVBoxLayout* vbox = new QVBoxLayout(this); - vbox->setContentsMargins(0, 0, 0, 0); - - QHBoxLayout* row = new QHBoxLayout(); - vbox->addLayout(row, 0); - row->setContentsMargins(0, 0, 0, 0); - row->addStretch(2); - row->addWidget(new QLabel("Switch Count:", this), 0); - m_console_count_box = new NoWheelCompactComboBox(this); - row->addWidget(m_console_count_box, 1); - row->addStretch(2); - - for (size_t c = session.min_switches(); c <= session.max_switches(); c++){ - m_console_count_box->addItem(QString::number(c)); - } - m_console_count_box->setCurrentIndex((int)(m_session.count() - m_session.min_switches())); - - connect( - m_console_count_box, static_cast(&QComboBox::currentIndexChanged), - this, [this](int index){ - if (index < 0 || index > (int)(m_session.max_switches() - m_session.min_switches())){ - return; - } - m_session.set_switch_count(index + m_session.min_switches()); - } - ); - - -#if 0 - // Acquire the lock now and attach listener. This will block the session - // from changing the # of switches while we draw everything. - std::lock_guard lg(m_lock); - m_session.add_listener(*this); - - m_console_count_box->setCurrentIndex((int)(m_session.count() - m_session.min_switches())); - - redraw_videos(m_session.count()); -#endif - m_session.add_listener(*this); -} - -void MultiSwitchSystemWidget::shutdown(){ -// cout << "MultiSwitchSystemWidget::shutdown()" << endl; - std::lock_guard lg(m_lock); - for (SwitchSystemWidget* console : m_switches){ - delete console; - } - m_switches.clear(); - delete m_videos; - m_videos = nullptr; -} -void MultiSwitchSystemWidget::startup(size_t switch_count){ -// cout << "MultiSwitchSystemWidget::startup()" << endl; - std::lock_guard lg(m_lock); - redraw_videos(switch_count); -} - -void MultiSwitchSystemWidget::redraw_videos(size_t count){ -// cout << "MultiSwitchSystemWidget::redraw_videos()" << endl; -// std::lock_guard lg(m_lock); -// if (count == m_switches.size()){ -// return; -// } - if (m_shutting_down){ - return; - } - - int old_index = m_console_count_box->currentIndex(); - int new_index = (int)(m_session.count() - m_session.min_switches()); - if (new_index != old_index){ - m_console_count_box->setCurrentIndex(new_index); - } - - QVBoxLayout* layout = static_cast(this->layout()); - m_switches.clear(); - if (m_videos != nullptr){ - layout->removeWidget(m_videos); - delete m_videos; - m_videos = nullptr; - } - - m_videos = new QWidget(this); - this->layout()->addWidget(m_videos); - QVBoxLayout* vbox = new QVBoxLayout(m_videos); - vbox->setContentsMargins(0, 0, 0, 0); - -// m_option.resize(count); - for (size_t c = 0; c < m_session.count(); c++){ -// const auto& item = m_option.m_switches[c]; -// m_switches.emplace_back(item->make_ui(*this, m_logger, m_program_id)); - m_switches.emplace_back( - new SwitchSystemWidget( - *m_videos, - m_session[c] - ) - ); - } - - QHBoxLayout* vrow0 = new QHBoxLayout(); - vbox->addLayout(vrow0, 1); - vrow0->setContentsMargins(0, 0, 0, 0); - - vrow0->addWidget(m_switches[0], 1); - if (m_switches.size() >= 2){ - vrow0->addWidget(m_switches[1], 1); - } - if (m_switches.size() >= 3){ - QHBoxLayout* vrow1 = new QHBoxLayout(); - vbox->addLayout(vrow1, 1); - vrow1->setContentsMargins(0, 0, 0, 0); - vrow1->addWidget(m_switches[2], 1); - if (m_switches.size() >= MultiSwitchSystemOption::MAX_CONSOLES){ - vrow1->addWidget(m_switches[3], 1); - }else{ - vrow1->addWidget(new QWidget(), 1); - } - } - static_assert(MultiSwitchSystemOption::MAX_CONSOLES <= 4, "Can't display more than 4 Switches."); -} - -void MultiSwitchSystemWidget::update_ui(ProgramState state){ - m_console_count_box->setEnabled(state == ProgramState::STOPPED); - for (SwitchSystemWidget* item : m_switches){ - if (state != ProgramState::STOPPED){ - item->session().lock_controllers("Program is Running"); - }else{ - item->session().unlock_controllers(); - } - } -} - - - - -} -} diff --git a/SerialPrograms/Source/NintendoSwitch/Framework/UI/NintendoSwitch_MultiSwitchSystemWidget.h b/SerialPrograms/Source/NintendoSwitch/Framework/UI/NintendoSwitch_MultiSwitchSystemWidget.h deleted file mode 100644 index 28fa54c0b4..0000000000 --- a/SerialPrograms/Source/NintendoSwitch/Framework/UI/NintendoSwitch_MultiSwitchSystemWidget.h +++ /dev/null @@ -1,72 +0,0 @@ -/* Multi-Switch System Widget - * - * From: https://github.com/PokemonAutomation/ - * - * This is the Qt Widget implementation of the UI for MultiSwitchSystemSession. - * - * On construction, this class attaches itself to the session it is constructed - * with and automatically detaches on destruction. Therefore, this class must - * not outlive the session it is constructed with. While not useful, it is also - * safe to construct multiple UI classes attached to the same session. - * - * Modifications directly to the session object will automatically update this - * UI class. For example, if you use Discord to change the volume of the - * audio playback, it will move the slider as shown by this UI. - * - */ - -#ifndef PokemonAutomationn_NintendoSwitch_SwitchSystem4Widget_H -#define PokemonAutomationn_NintendoSwitch_SwitchSystem4Widget_H - -#include -#include "NintendoSwitch/Framework/NintendoSwitch_MultiSwitchSystemOption.h" -#include "NintendoSwitch/Framework/NintendoSwitch_MultiSwitchSystemSession.h" - -class QComboBox; - -namespace PokemonAutomation{ -namespace NintendoSwitch{ - -class SwitchSystemWidget; - - -class MultiSwitchSystemWidget final : public QWidget, private MultiSwitchSystemSession::Listener{ - Q_OBJECT - -public: - ~MultiSwitchSystemWidget(); - MultiSwitchSystemWidget( - QWidget& parent, - MultiSwitchSystemSession& session, - uint64_t program_id - ); - - size_t switch_count() const{ return m_switches.size(); } - SwitchSystemWidget& operator[](size_t index){ return *m_switches[index]; } - -public: - void update_ui(ProgramState state); - -private: - virtual void shutdown() override; - virtual void startup(size_t switch_count) override; - - void redraw_videos(size_t count); - -private: - uint64_t m_program_id; - MultiSwitchSystemSession& m_session; - - Mutex m_lock; - bool m_shutting_down = false; - - QComboBox* m_console_count_box; - std::vector m_switches; - QWidget* m_videos; -// std::map m_active_ports; -}; - - -} -} -#endif diff --git a/SerialPrograms/Source/NintendoSwitch/Framework/UI/NintendoSwitch_SingleSwitchProgramWidget.cpp b/SerialPrograms/Source/NintendoSwitch/Framework/UI/NintendoSwitch_SingleSwitchProgramWidget.cpp index d2ac92f43b..1528b8a36b 100644 --- a/SerialPrograms/Source/NintendoSwitch/Framework/UI/NintendoSwitch_SingleSwitchProgramWidget.cpp +++ b/SerialPrograms/Source/NintendoSwitch/Framework/UI/NintendoSwitch_SingleSwitchProgramWidget.cpp @@ -86,8 +86,7 @@ SingleSwitchProgramWidget2::SingleSwitchProgramWidget2( scroll_layout->setAlignment(Qt::AlignTop); UiWrapper wrapper = m_session.system().make_ui_component(this); - m_system = dynamic_cast(wrapper.release()); - scroll_layout->addWidget(m_system); + scroll_layout->addWidget(dynamic_cast(wrapper.release())); m_options = ConfigWidget::make_from_option(session.options(), this); scroll_layout->addWidget(&m_options->widget()); diff --git a/SerialPrograms/Source/NintendoSwitch/Framework/UI/NintendoSwitch_SingleSwitchProgramWidget.h b/SerialPrograms/Source/NintendoSwitch/Framework/UI/NintendoSwitch_SingleSwitchProgramWidget.h index 081fd6ef0c..a08bab5138 100644 --- a/SerialPrograms/Source/NintendoSwitch/Framework/UI/NintendoSwitch_SingleSwitchProgramWidget.h +++ b/SerialPrograms/Source/NintendoSwitch/Framework/UI/NintendoSwitch_SingleSwitchProgramWidget.h @@ -59,7 +59,6 @@ class SingleSwitchProgramWidget2 private: SingleSwitchProgramSession& m_session; QVBoxLayout* m_layout; - QWidget* m_system; ConfigWidget* m_options; StatsBar* m_stats_bar; RunnablePanelActionBar* m_actions_bar; diff --git a/SerialPrograms/Source/NintendoSwitch/Framework/UI/NintendoSwitch_SwitchSystemWidget.cpp b/SerialPrograms/Source/NintendoSwitch/Framework/UI/NintendoSwitch_SwitchSystemWidget.cpp deleted file mode 100644 index de4de629d4..0000000000 --- a/SerialPrograms/Source/NintendoSwitch/Framework/UI/NintendoSwitch_SwitchSystemWidget.cpp +++ /dev/null @@ -1,41 +0,0 @@ -/* Switch System - * - * From: https://github.com/PokemonAutomation/ - * - */ - -#include "NintendoSwitch_CommandRow.h" -#include "NintendoSwitch_SwitchSystemWidget.h" - -//#include -//using std::cout; -//using std::endl; - -namespace PokemonAutomation{ - -template class RegisterUiStateQtWidget; - -namespace NintendoSwitch{ - - - - -SwitchSystemWidget::SwitchSystemWidget( - QWidget& parent, - SwitchSystemSession& session -) - : ConsoleSystemWidget(parent, session, false) -{ - m_group_layout->addWidget( - new CommandRow(*m_group_box->widget(), session) - ); -} - - - - - - - -} -} diff --git a/SerialPrograms/Source/NintendoSwitch/Framework/UI/NintendoSwitch_SwitchSystemWidget.h b/SerialPrograms/Source/NintendoSwitch/Framework/UI/NintendoSwitch_SwitchSystemWidget.h index c4c7c80681..325babf22b 100644 --- a/SerialPrograms/Source/NintendoSwitch/Framework/UI/NintendoSwitch_SwitchSystemWidget.h +++ b/SerialPrograms/Source/NintendoSwitch/Framework/UI/NintendoSwitch_SwitchSystemWidget.h @@ -18,8 +18,9 @@ #ifndef PokemonAutomation_NintendoSwitch_SwitchSystemWidget_H #define PokemonAutomation_NintendoSwitch_SwitchSystemWidget_H -#include "NintendoSwitch/Framework/NintendoSwitch_SwitchSystemSession.h" #include "GameConsole/UI/ConsoleSystemWidget.h" +#include "NintendoSwitch/Framework/NintendoSwitch_SwitchSystemSession.h" +#include "NintendoSwitch_CommandRow.h" namespace PokemonAutomation{ namespace NintendoSwitch{ @@ -33,7 +34,13 @@ class SwitchSystemWidget final : public GameConsole::ConsoleSystemWidget{ SwitchSystemWidget( QWidget& parent, SwitchSystemSession& session - ); + ) + : ConsoleSystemWidget(parent, session, false) + { + m_group_layout->addWidget( + new CommandRow(*m_group_box->widget(), session) + ); + } }; diff --git a/SerialPrograms/Source/NintendoSwitch/NintendoSwitch_Panels.cpp b/SerialPrograms/Source/NintendoSwitch/NintendoSwitch_Panels.cpp index 15b355f9b6..d24bff6208 100644 --- a/SerialPrograms/Source/NintendoSwitch/NintendoSwitch_Panels.cpp +++ b/SerialPrograms/Source/NintendoSwitch/NintendoSwitch_Panels.cpp @@ -6,6 +6,7 @@ #include "CommonFramework/StaticGlobals.h" #include "CommonFramework/GlobalAutoPaths.h" +#include "NintendoSwitch/Framework/NintendoSwitch_SwitchSystemSession.h" #include "NintendoSwitch_Panels.h" #include "NintendoSwitch_SettingsPanel.h" diff --git a/SerialPrograms/Source/NintendoSwitch/Programs/NintendoSwitch_SwitchViewer.cpp b/SerialPrograms/Source/NintendoSwitch/Programs/NintendoSwitch_SwitchViewer.cpp index 96a09daf6c..c926b0c858 100644 --- a/SerialPrograms/Source/NintendoSwitch/Programs/NintendoSwitch_SwitchViewer.cpp +++ b/SerialPrograms/Source/NintendoSwitch/Programs/NintendoSwitch_SwitchViewer.cpp @@ -7,8 +7,8 @@ #include #include #include "Common/Cpp/Json/JsonValue.h" +#include "Common/Qt/UiStateQtWidget.h" #include "Common/Qt/CollapsibleGroupBox.h" -#include "NintendoSwitch/Framework/UI/NintendoSwitch_MultiSwitchSystemWidget.h" #include "NintendoSwitch_SwitchViewer.h" namespace PokemonAutomation{ @@ -32,26 +32,25 @@ SwitchViewer_Descriptor::SwitchViewer_Descriptor() SwitchViewer::SwitchViewer(const SwitchViewer_Descriptor& descriptor) : UiState(descriptor) - , m_switches(1, 4, 1) + , m_option(1, 4, 1) + , m_session(m_option, true) {} JsonValue SwitchViewer::to_json() const{ - return m_switches.to_json(); + return m_session.to_json(); } void SwitchViewer::load_json(const JsonValue& json){ - m_switches.load_json(json); + m_session.load_json(json); } SwitchViewer_Widget::~SwitchViewer_Widget(){ - delete m_switches; } SwitchViewer_Widget::SwitchViewer_Widget( QWidget& parent, SwitchViewer& session ) : PanelWidget(parent, session) - , m_session(session.m_switches, true, 0) { QVBoxLayout* layout = new QVBoxLayout(this); layout->setContentsMargins(0, 0, 0, 0); @@ -66,8 +65,8 @@ SwitchViewer_Widget::SwitchViewer_Widget( QVBoxLayout* scroll_layout = new QVBoxLayout(scroll_inner); scroll_layout->setAlignment(Qt::AlignTop); - m_switches = new MultiSwitchSystemWidget(*this, m_session, 0); - scroll_layout->addWidget(m_switches); + UiWrapper wrapper = session.m_session.make_ui_component(this); + scroll_layout->addWidget(dynamic_cast(wrapper.release())); scroll_layout->addStretch(1); } diff --git a/SerialPrograms/Source/NintendoSwitch/Programs/NintendoSwitch_SwitchViewer.h b/SerialPrograms/Source/NintendoSwitch/Programs/NintendoSwitch_SwitchViewer.h index 53624a5c70..37239fbe0a 100644 --- a/SerialPrograms/Source/NintendoSwitch/Programs/NintendoSwitch_SwitchViewer.h +++ b/SerialPrograms/Source/NintendoSwitch/Programs/NintendoSwitch_SwitchViewer.h @@ -9,14 +9,11 @@ #include "CommonFramework/Panels/PanelSession.h" #include "CommonFramework/Panels/UI/PanelWidget.h" -#include "NintendoSwitch/Framework/NintendoSwitch_MultiSwitchSystemOption.h" -#include "NintendoSwitch/Framework/NintendoSwitch_MultiSwitchSystemSession.h" +#include "GameConsole/MultiConsoleSystemSession.h" namespace PokemonAutomation{ namespace NintendoSwitch{ -class MultiSwitchSystemWidget; - class SwitchViewer_Descriptor : public PanelDescriptor{ public: @@ -37,7 +34,8 @@ class SwitchViewer : public UiState{ private: friend class SwitchViewer_Widget; - MultiSwitchSystemOption m_switches; + GameConsole::MultiConsoleSystemOption m_option; + GameConsole::MultiConsoleSystemSession m_session; }; @@ -53,10 +51,6 @@ class SwitchViewer_Widget final : public PanelWidget{ virtual QWidget& widget() override{ return *this; } - -private: - MultiSwitchSystemSession m_session; - MultiSwitchSystemWidget* m_switches; }; diff --git a/SerialPrograms/Source/StaticRegistrationQt.cpp b/SerialPrograms/Source/StaticRegistrationQt.cpp index 2ea57f012d..1637417ab8 100644 --- a/SerialPrograms/Source/StaticRegistrationQt.cpp +++ b/SerialPrograms/Source/StaticRegistrationQt.cpp @@ -61,6 +61,7 @@ // Consoles #include "GameConsole/UI/ConsoleSystemWidget.h" #include "GameConsole/UI/ConsolePanelWidget.h" +#include "GameConsole/UI/MultiConsoleSystemWidget.h" // Nintendo Switch #include "NintendoSwitch/Controllers/SysbotBase/SysbotBase_SelectorWidget.h" @@ -151,6 +152,7 @@ void register_all_statics(){ // Consoles RegisterUiStateQtWidget(); RegisterUiStateQtWidget(); + RegisterUiStateQtWidget(); // Nintendo Switch RegisterUiStateQtWidget(); diff --git a/SerialPrograms/cmake/SourceFiles.cmake b/SerialPrograms/cmake/SourceFiles.cmake index 81d82882fd..dac3999197 100644 --- a/SerialPrograms/cmake/SourceFiles.cmake +++ b/SerialPrograms/cmake/SourceFiles.cmake @@ -927,6 +927,8 @@ file(GLOB LIBRARY_SOURCES Source/GameConsole/ConsoleSystemSession.h Source/GameConsole/MultiConsoleSystemOption.cpp Source/GameConsole/MultiConsoleSystemOption.h + Source/GameConsole/MultiConsoleSystemSession.cpp + Source/GameConsole/MultiConsoleSystemSession.h Source/GameConsole/Panels/BoxDraw.cpp Source/GameConsole/Panels/BoxDraw.h Source/GameConsole/Panels/VirtualConsole.h @@ -936,6 +938,8 @@ file(GLOB LIBRARY_SOURCES Source/GameConsole/UI/ConsolePanelWidget.h Source/GameConsole/UI/ConsoleSystemWidget.cpp Source/GameConsole/UI/ConsoleSystemWidget.h + Source/GameConsole/UI/MultiConsoleSystemWidget.cpp + Source/GameConsole/UI/MultiConsoleSystemWidget.h Source/Kernels/AbsFFT/Kernels_AbsFFT.cpp Source/Kernels/AbsFFT/Kernels_AbsFFT.h Source/Kernels/AbsFFT/Kernels_AbsFFT_Arch.h @@ -1189,7 +1193,6 @@ file(GLOB LIBRARY_SOURCES Source/NintendoSwitch/Framework/NintendoSwitch_MultiSwitchProgramSession.cpp Source/NintendoSwitch/Framework/NintendoSwitch_MultiSwitchProgramSession.h Source/NintendoSwitch/Framework/NintendoSwitch_MultiSwitchSystemOption.h - Source/NintendoSwitch/Framework/NintendoSwitch_MultiSwitchSystemSession.cpp Source/NintendoSwitch/Framework/NintendoSwitch_MultiSwitchSystemSession.h Source/NintendoSwitch/Framework/NintendoSwitch_SingleSwitchProgramSession.cpp Source/NintendoSwitch/Framework/NintendoSwitch_SingleSwitchProgramSession.h @@ -1201,11 +1204,8 @@ file(GLOB LIBRARY_SOURCES Source/NintendoSwitch/Framework/UI/NintendoSwitch_CommandRow.h Source/NintendoSwitch/Framework/UI/NintendoSwitch_MultiSwitchProgramWidget.cpp Source/NintendoSwitch/Framework/UI/NintendoSwitch_MultiSwitchProgramWidget.h - Source/NintendoSwitch/Framework/UI/NintendoSwitch_MultiSwitchSystemWidget.cpp - Source/NintendoSwitch/Framework/UI/NintendoSwitch_MultiSwitchSystemWidget.h Source/NintendoSwitch/Framework/UI/NintendoSwitch_SingleSwitchProgramWidget.cpp Source/NintendoSwitch/Framework/UI/NintendoSwitch_SingleSwitchProgramWidget.h - Source/NintendoSwitch/Framework/UI/NintendoSwitch_SwitchSystemWidget.cpp Source/NintendoSwitch/Framework/UI/NintendoSwitch_SwitchSystemWidget.h Source/NintendoSwitch/Inference/NintendoSwitch2_BinarySliderDetector.cpp Source/NintendoSwitch/Inference/NintendoSwitch2_BinarySliderDetector.h