diff --git a/firmware/application/CMakeLists.txt b/firmware/application/CMakeLists.txt index 018fa46c7..85466ef63 100644 --- a/firmware/application/CMakeLists.txt +++ b/firmware/application/CMakeLists.txt @@ -332,6 +332,7 @@ set(CPPSRC ${CPLD_H4M_DATA_CPP} ${HACKRF_CPLD_DATA_CPP} ui_external_items_menu_loader.cpp + view_factory_base.cpp ) set_source_files_properties(${CPPSRC} PROPERTIES COMPILE_FLAGS -flto) # Add lto flag to the non-external sources only diff --git a/firmware/application/ui/ui_btngrid.cpp b/firmware/application/ui/ui_btngrid.cpp index 0b88530ec..b06184c53 100644 --- a/firmware/application/ui/ui_btngrid.cpp +++ b/firmware/application/ui/ui_btngrid.cpp @@ -28,7 +28,6 @@ #include "rtc_time.hpp" #include "sd_card.hpp" #include -#include "ui_external_items_menu_loader.hpp" namespace ui { @@ -61,7 +60,6 @@ BtnGridView::BtnGridView( } BtnGridView::~BtnGridView() { - ExternalItemsMenuLoader::unload_external_items(); } void BtnGridView::set_max_rows(int rows) { @@ -89,7 +87,6 @@ void BtnGridView::set_parent_rect(const Rect new_parent_rect) { remove_child(item.get()); menu_item_views.clear(); - menu_item_views.shrink_to_fit(); } button_w = screen_width / rows_; @@ -138,17 +135,15 @@ void BtnGridView::set_arrow_down_enabled(bool enabled) { }; void BtnGridView::clear() { - // clear vector and release memory, not using swap since it's causing capture to glitch/fault + // clear vector, not using swap since it's causing capture to glitch/fault menu_items.clear(); - menu_items.shrink_to_fit(); // TODO(u-foka): Clean up my mess, move this somewhere to clear memory when the view is not visible, but not to be confused with clearing the menu items... for (auto& item : menu_item_views) remove_child(item.get()); - // clear vector and release memory, not using swap since it's causing capture to glitch/fault + // clear vector, not using swap since it's causing capture to glitch/fault menu_item_views.clear(); - menu_item_views.shrink_to_fit(); } void BtnGridView::add_items(std::initializer_list new_items, bool inhibit_update) { diff --git a/firmware/application/ui_external_items_menu_loader.cpp b/firmware/application/ui_external_items_menu_loader.cpp index b2e064956..568372d8a 100644 --- a/firmware/application/ui_external_items_menu_loader.cpp +++ b/firmware/application/ui_external_items_menu_loader.cpp @@ -9,13 +9,7 @@ namespace ui { -/* static */ std::vector>> ExternalItemsMenuLoader::bitmaps; - -// to save ram when entering an app -void ExternalItemsMenuLoader::unload_external_items() { - bitmaps.clear(); - bitmaps.shrink_to_fit(); -} +/* static */ std::vector> ExternalItemsMenuLoader::bitmaps; // iterates over all possible ext apps-s, and if it is runnable on the current system, it'll call the callback, and pass minimal info. used to print to console, and for autostart setting's app list. where the minimal info is enough // please keep in sync with load_external_items @@ -103,9 +97,8 @@ void ExternalItemsMenuLoader::unload_external_items() { } } -std::vector ExternalItemsMenuLoader::load_external_items(app_location_t app_location, NavigationView& nav) { +/* static */ std::vector ExternalItemsMenuLoader::load_external_items(app_location_t app_location, NavigationView& nav) { bitmaps.clear(); - bitmaps.shrink_to_fit(); std::vector external_apps; @@ -133,8 +126,8 @@ std::vector ExternalItemsMenuLoader::load_e gridItem.color = Color((uint16_t)appInfo->icon_color); - auto dyn_bmp = std::make_unique>(appInfo->bitmap_data); - gridItem.bitmap = dyn_bmp->bitmap(); + auto dyn_bmp = DynamicBitmap<16, 16>{appInfo->bitmap_data}; + gridItem.bitmap = dyn_bmp.bitmap(); bitmaps.push_back(std::move(dyn_bmp)); gridItem.on_select = [&nav, appInfo, i]() { @@ -211,8 +204,8 @@ std::vector ExternalItemsMenuLoader::load_e if (versionMatches) { gridItem.color = Color((uint16_t)application_information.icon_color); - auto dyn_bmp = std::make_unique>(application_information.bitmap_data); - gridItem.bitmap = dyn_bmp->bitmap(); + auto dyn_bmp = DynamicBitmap<16, 16>{application_information.bitmap_data}; + gridItem.bitmap = dyn_bmp.bitmap(); bitmaps.push_back(std::move(dyn_bmp)); gridItem.on_select = [&nav, app_location, filePath]() { @@ -262,8 +255,8 @@ std::vector ExternalItemsMenuLoader::load_e gridItem.color = Color((uint16_t)application_information.icon_color); - auto dyn_bmp = std::make_unique>(application_information.bitmap_data); - gridItem.bitmap = dyn_bmp->bitmap(); + auto dyn_bmp = DynamicBitmap<16, 16>{application_information.bitmap_data}; + gridItem.bitmap = dyn_bmp.bitmap(); bitmaps.push_back(std::move(dyn_bmp)); gridItem.on_select = [&nav, app_location, filePath]() { @@ -357,8 +350,6 @@ std::vector ExternalItemsMenuLoader::load_e if (checksum != EXT_APP_EXPECTED_CHECKSUM) return false; - nav.pop(); - nav.set_last_menu_went_deeper(true); application_information.externalAppEntry(nav); return true; } @@ -395,8 +386,7 @@ std::vector ExternalItemsMenuLoader::load_e } } - nav.set_last_menu_went_deeper(true); - nav.replace(app_image); + nav.push(app_image); return true; } @@ -410,8 +400,7 @@ std::vector ExternalItemsMenuLoader::load_e } } - nav.set_last_menu_went_deeper(true); - nav.replace(app_image); + nav.push(app_image); return true; } diff --git a/firmware/application/ui_external_items_menu_loader.hpp b/firmware/application/ui_external_items_menu_loader.hpp index eadb6717f..ac059ac93 100644 --- a/firmware/application/ui_external_items_menu_loader.hpp +++ b/firmware/application/ui_external_items_menu_loader.hpp @@ -33,38 +33,24 @@ #define EXT_APP_EXPECTED_CHECKSUM 0x00000000 namespace ui { + template class DynamicBitmap { public: - static constexpr size_t buffer_size = Width * Height / (sizeof(uint8_t) * 8); + static constexpr size_t buffer_size = Width * Height / (sizeof(uint8_t) * 8); // one bit per pixel - // Main constructor DynamicBitmap(const uint8_t data[buffer_size]) - : _bitmap{{Width, Height}, _buffer.data()} { - std::memcpy(_buffer.data(), data, buffer_size); + : _buffer(buffer_size, 0), + _bitmap{new Bitmap{{Width, Height}, &_buffer[0]}} { + memcpy(&_buffer[0], data, buffer_size); } - DynamicBitmap(const DynamicBitmap& other) - : _buffer(other._buffer), - _bitmap{{Width, Height}, _buffer.data()} {} - - DynamicBitmap(DynamicBitmap&& other) noexcept - : _buffer(std::move(other._buffer)), - _bitmap{{Width, Height}, _buffer.data()} {} - - DynamicBitmap& operator=(const DynamicBitmap& other) = delete; - DynamicBitmap& operator=(DynamicBitmap&& other) noexcept = delete; - - // Destructor (Default is fine, no heap memory to free manually) - ~DynamicBitmap() = default; - - const Bitmap* bitmap() const { return &_bitmap; } + const Bitmap* bitmap() { return _bitmap.get(); } private: - // Order matters: _buffer must be declared before _bitmap - // so it is initialized first and its .data() pointer is valid. - std::array _buffer{}; - Bitmap _bitmap{}; + // Allocating both members so the class is movable without invalidation. + std::vector _buffer; + std::unique_ptr _bitmap; }; class ExternalItemsMenuLoader { @@ -79,10 +65,9 @@ class ExternalItemsMenuLoader { static bool run_standalone_app(ui::NavigationView&, std::filesystem::path); static bool run_module_app(ui::NavigationView&, uint8_t*, size_t); static void load_all_external_items_callback(std::function callback, bool module_included = false); - static void unload_external_items(); private: - static std::vector>> bitmaps; + static std::vector> bitmaps; }; } // namespace ui diff --git a/firmware/application/ui_navigation.cpp b/firmware/application/ui_navigation.cpp index 7177270ce..5775382d9 100644 --- a/firmware/application/ui_navigation.cpp +++ b/firmware/application/ui_navigation.cpp @@ -85,47 +85,44 @@ namespace ui { // TODO(u-foka): Check consistency of command names (where we add rx/tx postfix) const NavigationView::AppList NavigationView::appList = { /* HOME ******************************************************************/ - {nullptr, "Receive", HOME, Color::cyan(), &bitmap_icon_receivers, [](NavigationView& nav) -> std::unique_ptr { return std::make_unique(nav); }}, - {nullptr, "Transmit", HOME, Color::cyan(), &bitmap_icon_transmit, [](NavigationView& nav) -> std::unique_ptr { return std::make_unique(nav); }}, - {nullptr, "Transceiver", HOME, Color::cyan(), &bitmap_icon_transceivers, [](NavigationView& nav) -> std::unique_ptr { return std::make_unique(nav); }}, - {"recon", "Recon", HOME, Color::green(), &bitmap_icon_scanner, [](NavigationView& nav) -> std::unique_ptr { return std::make_unique(nav); }}, - {"capture", "Capture", HOME, Color::red(), &bitmap_icon_capture, [](NavigationView& nav) -> std::unique_ptr { return std::make_unique(nav); }}, - {"replay", "Replay", HOME, Color::green(), &bitmap_icon_replay, [](NavigationView& nav) -> std::unique_ptr { return std::make_unique(nav); }}, - {"lookingglass", "Looking Glass", HOME, Color::green(), &bitmap_icon_looking, [](NavigationView& nav) -> std::unique_ptr { return std::make_unique(nav); }}, - {nullptr, "Utilities", HOME, Color::cyan(), &bitmap_icon_utilities, [](NavigationView& nav) -> std::unique_ptr { return std::make_unique(nav); }}, - {nullptr, "Games", HOME, Color::cyan(), &bitmap_icon_games, [](NavigationView& nav) -> std::unique_ptr { return std::make_unique(nav); }}, - {nullptr, "Settings", HOME, Color::cyan(), &bitmap_icon_setup, [](NavigationView& nav) -> std::unique_ptr { return std::make_unique(nav); }}, - + {nullptr, "Receive", HOME, Color::cyan(), &bitmap_icon_receivers, new ViewFactory()}, + {nullptr, "Transmit", HOME, Color::cyan(), &bitmap_icon_transmit, new ViewFactory()}, + {nullptr, "Transceiver", HOME, Color::cyan(), &bitmap_icon_transceivers, new ViewFactory()}, + {"recon", "Recon", HOME, Color::green(), &bitmap_icon_scanner, new ViewFactory()}, + {"capture", "Capture", HOME, Color::red(), &bitmap_icon_capture, new ViewFactory()}, + {"replay", "Replay", HOME, Color::green(), &bitmap_icon_replay, new ViewFactory()}, + {"lookingglass", "Looking Glass", HOME, Color::green(), &bitmap_icon_looking, new ViewFactory()}, + {nullptr, "Utilities", HOME, Color::cyan(), &bitmap_icon_utilities, new ViewFactory()}, + {nullptr, "Games", HOME, Color::cyan(), &bitmap_icon_games, new ViewFactory()}, + {nullptr, "Settings", HOME, Color::cyan(), &bitmap_icon_setup, new ViewFactory()}, /* RX ********************************************************************/ - {"adsbrx", "ADS-B", RX, Color::green(), &bitmap_icon_adsb, [](NavigationView& nav) -> std::unique_ptr { return std::make_unique(nav); }}, - {"ais", "AIS Boats", RX, Color::green(), &bitmap_icon_ais, [](NavigationView& nav) -> std::unique_ptr { return std::make_unique(nav); }}, - {"aprsrx", "APRS", RX, Color::green(), &bitmap_icon_aprs, [](NavigationView& nav) -> std::unique_ptr { return std::make_unique(nav); }}, - {"audio", "Audio", RX, Color::green(), &bitmap_icon_speaker, [](NavigationView& nav) -> std::unique_ptr { return std::make_unique(nav); }}, - {"blerx", "BLE Rx", RX, Color::green(), &bitmap_icon_btle, [](NavigationView& nav) -> std::unique_ptr { return std::make_unique(nav); }}, - {"pocsag", "POCSAG", RX, Color::green(), &bitmap_icon_pocsag, [](NavigationView& nav) -> std::unique_ptr { return std::make_unique(nav); }}, - {"radiosonde", "Radiosnde", RX, Color::green(), &bitmap_icon_sonde, [](NavigationView& nav) -> std::unique_ptr { return std::make_unique(nav); }}, - {"search", "Search", RX, Color::yellow(), &bitmap_icon_search, [](NavigationView& nav) -> std::unique_ptr { return std::make_unique(nav); }}, - {"subghzd", "SubGhzD", RX, Color::yellow(), &bitmap_icon_remote, [](NavigationView& nav) -> std::unique_ptr { return std::make_unique(nav); }}, - {"weather", "Weather", RX, Color::green(), &bitmap_icon_thermometer, [](NavigationView& nav) -> std::unique_ptr { return std::make_unique(nav); }}, - + {"adsbrx", "ADS-B", RX, Color::green(), &bitmap_icon_adsb, new ViewFactory()}, + {"ais", "AIS Boats", RX, Color::green(), &bitmap_icon_ais, new ViewFactory()}, + {"aprsrx", "APRS", RX, Color::green(), &bitmap_icon_aprs, new ViewFactory()}, + {"audio", "Audio", RX, Color::green(), &bitmap_icon_speaker, new ViewFactory()}, + {"blerx", "BLE Rx", RX, Color::green(), &bitmap_icon_btle, new ViewFactory()}, + {"pocsag", "POCSAG", RX, Color::green(), &bitmap_icon_pocsag, new ViewFactory()}, + {"radiosonde", "Radiosnde", RX, Color::green(), &bitmap_icon_sonde, new ViewFactory()}, + {"search", "Search", RX, Color::yellow(), &bitmap_icon_search, new ViewFactory()}, + {"subghzd", "SubGhzD", RX, Color::yellow(), &bitmap_icon_remote, new ViewFactory()}, + {"weather", "Weather", RX, Color::green(), &bitmap_icon_thermometer, new ViewFactory()}, /* TX ********************************************************************/ - {"aprstx", "APRS TX", TX, ui::Color::green(), &bitmap_icon_aprs, [](NavigationView& nav) -> std::unique_ptr { return std::make_unique(nav); }}, - {"bletx", "BLE Tx", TX, ui::Color::green(), &bitmap_icon_btle, [](NavigationView& nav) -> std::unique_ptr { return std::make_unique(nav); }}, - {"ooktx", "OOK", TX, ui::Color::yellow(), &bitmap_icon_remote, [](NavigationView& nav) -> std::unique_ptr { return std::make_unique(nav); }}, - {"rdstx", "RDS", TX, ui::Color::green(), &bitmap_icon_rds, [](NavigationView& nav) -> std::unique_ptr { return std::make_unique(nav); }}, - {"touchtune", "TouchTune", TX, ui::Color::green(), &bitmap_icon_touchtunes, [](NavigationView& nav) -> std::unique_ptr { return std::make_unique(nav); }}, - + {"aprstx", "APRS TX", TX, ui::Color::green(), &bitmap_icon_aprs, new ViewFactory()}, + {"bletx", "BLE Tx", TX, ui::Color::green(), &bitmap_icon_btle, new ViewFactory()}, + {"ooktx", "OOK", TX, ui::Color::yellow(), &bitmap_icon_remote, new ViewFactory()}, + {"rdstx", "RDS", TX, ui::Color::green(), &bitmap_icon_rds, new ViewFactory()}, + {"touchtune", "TouchTune", TX, ui::Color::green(), &bitmap_icon_touchtunes, new ViewFactory()}, /* TRX ********************************************************************/ - {"microphone", "Mic", TRX, Color::green(), &bitmap_icon_microphone, [](NavigationView& nav) -> std::unique_ptr { return std::make_unique(nav); }}, - + {"microphone", "Mic", TRX, Color::green(), &bitmap_icon_microphone, new ViewFactory()}, /* UTILITIES *************************************************************/ - {"filemanager", "File Manager", UTILITIES, Color::green(), &bitmap_icon_dir, [](NavigationView& nav) -> std::unique_ptr { return std::make_unique(nav); }}, - {"freqman", "Freq. Manager", UTILITIES, Color::green(), &bitmap_icon_freqman, [](NavigationView& nav) -> std::unique_ptr { return std::make_unique(nav); }}, - {"iqtrim", "IQ Trim", UTILITIES, Color::orange(), &bitmap_icon_trim, [](NavigationView& nav) -> std::unique_ptr { return std::make_unique(nav); }}, - {"notepad", "Notepad", UTILITIES, Color::dark_cyan(), &bitmap_icon_notepad, [](NavigationView& nav) -> std::unique_ptr { return std::make_unique(nav); }}, - {nullptr, "Debug", UTILITIES, Color::light_grey(), &bitmap_icon_debug, [](NavigationView& nav) -> std::unique_ptr { return std::make_unique(nav); }}, + {"filemanager", "File Manager", UTILITIES, Color::green(), &bitmap_icon_dir, new ViewFactory()}, + {"freqman", "Freq. Manager", UTILITIES, Color::green(), &bitmap_icon_freqman, new ViewFactory()}, + {"iqtrim", "IQ Trim", UTILITIES, Color::orange(), &bitmap_icon_trim, new ViewFactory()}, + {"notepad", "Notepad", UTILITIES, Color::dark_cyan(), &bitmap_icon_notepad, new ViewFactory()}, + {nullptr, "Debug", UTILITIES, Color::light_grey(), &bitmap_icon_debug, new ViewFactory()}, + //{"testapp", "Test App", UTILITIES, Color::dark_grey(), nullptr, new ViewFactory()}, // Dangerous apps. - {nullptr, "Flash Utility", UTILITIES, Color::red(), &bitmap_icon_peripherals_details, [](NavigationView& nav) -> std::unique_ptr { return std::make_unique(nav); }}, + {nullptr, "Flash Utility", UTILITIES, Color::red(), &bitmap_icon_peripherals_details, new ViewFactory()}, }; bool NavigationView::StartAppByName(const char* name) { @@ -133,7 +130,7 @@ bool NavigationView::StartAppByName(const char* name) { for (const auto& app : appList) { if (app.id != nullptr && strcmp(app.id, name) == 0) { - push_view(app.producer(*this)); + push_view(app.viewFactory->produce(*this)); return true; } } @@ -633,7 +630,6 @@ void NavigationView::pop(bool trigger_update) { free_view(); view_stack.pop_back(); - view_stack.shrink_to_fit(); // NB: These are executed _after_ the view has been // destroyed. The old view MUST NOT be referenced in @@ -757,22 +753,10 @@ void NavigationView::handle_autostart() { void add_apps(NavigationView& nav, BtnGridView& grid, app_location_t loc) { for (auto& app : NavigationView::appList) { if (app.menuLocation == loc) { - const AppInfo* p_app = &app; grid.add_item({app.displayName, app.iconColor, app.icon, - [&nav, p_app]() { - NavigationView& local_nav = nav; - if (p_app->menuLocation == HOME) { - local_nav.store_last_menu_name(p_app->displayName); - local_nav.set_last_menu_went_deeper(false); - auto new_view = p_app->producer(local_nav); - local_nav.push_view(std::move(new_view)); - } else { - auto new_view = p_app->producer(local_nav); - local_nav.pop(); - local_nav.set_last_menu_went_deeper(true); - local_nav.push_view(std::move(new_view)); - } - }}, + [&nav, &app]() { + i2cdev::I2CDevManager::set_autoscan_interval(0); //if i navigate away from any menu, turn off autoscan + nav.push_view(app.viewFactory->produce(nav)); }}, true); } }; @@ -799,7 +783,7 @@ void add_external_items(NavigationView& nav, app_location_t location, BtnGridVie return a.desired_position < b.desired_position; }); - for (auto & gridItem : externalItems) { + for (auto const& gridItem : externalItems) { if (gridItem.desired_position < 0) { grid.add_item(std::move(gridItem), true); } else { @@ -931,27 +915,6 @@ SystemView::SystemView( {{0, 0}, {parent_rect.width(), status_view_height}}); status_view.on_back = [this]() { - if (this->navigation_view.view_stack_size() == 2) { - const AppInfo* lastmenu = nullptr; - const auto last_menu_name = this->navigation_view.get_last_menu_name(); - this->navigation_view.store_last_menu_name(""); - if (!last_menu_name.empty()) { - for (const auto& app : NavigationView::appList) { - if (app.displayName == last_menu_name) { - lastmenu = &app; - break; - } - } - - if (lastmenu && this->navigation_view.get_last_menu_went_deeper()) { - this->navigation_view.pop(); - this->navigation_view.push_view(lastmenu->producer(this->navigation_view)); - this->navigation_view.store_last_menu_name(lastmenu->displayName); // since we opened it again, store it again - this->navigation_view.set_last_menu_went_deeper(false); // not yet - return; - } - } - } this->navigation_view.pop(); }; @@ -968,7 +931,6 @@ SystemView::SystemView( navigation_view.on_view_changed = [this](const View& new_view) { if (!this->navigation_view.is_top()) { remove_child(&info_view); - i2cdev::I2CDevManager::set_autoscan_interval(0); } else { add_child(&info_view); info_view.refresh(); @@ -1029,15 +991,16 @@ void SystemView::toggle_overlay() { this->set_dirty(); shared_memory.request_m4_performance_counter = last_perf_counter_status; overlay_active = 0; - break; } } void SystemView::paint_overlay() { static bool last_paint_state = false; if (overlay_active) { + // paint background only every other second if ((((chTimeNow() >> 10) & 0x01) == 0x01) == last_paint_state) return; + last_paint_state = !last_paint_state; if (overlay_active == 1 && overlay) overlay->set_dirty(); diff --git a/firmware/application/ui_navigation.hpp b/firmware/application/ui_navigation.hpp index 320a43961..9d958e645 100644 --- a/firmware/application/ui_navigation.hpp +++ b/firmware/application/ui_navigation.hpp @@ -50,6 +50,7 @@ #include "lfsr_random.hpp" #include "sd_card.hpp" #include "external_app.hpp" +#include "view_factory.hpp" #include "battery.hpp" // for incrementing fake date when RTC battery is dead @@ -59,9 +60,6 @@ using namespace sd_card; namespace ui { -class NavigationView; -using ViewProducer = std::unique_ptr (*)(NavigationView&); - void add_apps(NavigationView& nav, BtnGridView& grid, app_location_t loc); void add_external_items(NavigationView& nav, app_location_t location, BtnGridView& grid, uint8_t error_tile_pos, bool show_error_tile = true); @@ -71,7 +69,7 @@ enum modal_t { ABORT }; -// Should only be used as part of the appList in NavigationView. +// Should only be used as part of the appList in NavigationView, the viewFactory will never be destroyed. class AppInfo { public: const char* id; // MUST be unique! Used by serial command to start the app so it also has to make sense @@ -79,7 +77,7 @@ class AppInfo { app_location_t menuLocation; Color iconColor; const Bitmap* icon; - ViewProducer producer; + ViewFactoryBase* viewFactory; // Never destroyed, and I believe it's ok ;) Having a unique_ptr here breaks the initializer list of appList }; struct AppInfoConsole { @@ -140,13 +138,6 @@ class NavigationView : public View { bool StartAppByName(const char* name); // Starts a View (app) by name stored in appListFC. This is to start apps from console void handle_autostart(); - void store_last_menu_name(const std::string& name) { last_menu_name_ = name; } - std::string get_last_menu_name() const { return last_menu_name_; } - size_t view_stack_size() const { return view_stack.size(); } - - bool get_last_menu_went_deeper() { return last_menu_went_deeper; } - void set_last_menu_went_deeper(bool went_deeper) { last_menu_went_deeper = went_deeper; } - private: struct ViewState { std::unique_ptr view; @@ -159,8 +150,6 @@ class NavigationView : public View { void free_view(); void update_view(); - std::string last_menu_name_{}; // this stores the last menu name, when we replace the menu with the app, we'll know, where to navigate back - bool last_menu_went_deeper = false; }; /* Holds widgets and grows dynamically toward the left. diff --git a/firmware/application/view_factory.hpp b/firmware/application/view_factory.hpp new file mode 100644 index 000000000..da6754ae8 --- /dev/null +++ b/firmware/application/view_factory.hpp @@ -0,0 +1,39 @@ +/* + * Copyright 2024 Tamas Eisenberger + * + * This file is part of PortaPack. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#ifndef __VIEW_FACTORY_HPP__ +#define __VIEW_FACTORY_HPP__ + +#include "view_factory_base.hpp" + +namespace ui { + +template +class ViewFactory : public ViewFactoryBase { + public: + virtual std::unique_ptr produce(NavigationView& nav) const override { + return std::unique_ptr(new T(nav)); + } +}; + +} // namespace ui + +#endif //__VIEW_FACTORY_HPP__ diff --git a/firmware/application/view_factory_base.cpp b/firmware/application/view_factory_base.cpp new file mode 100644 index 000000000..4aa9bb300 --- /dev/null +++ b/firmware/application/view_factory_base.cpp @@ -0,0 +1,28 @@ +/* + * Copyright 2024 Tamas Eisenberger + * + * This file is part of PortaPack. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#include "view_factory_base.hpp" + +namespace ui { + +ViewFactoryBase::~ViewFactoryBase() {} + +} // namespace ui diff --git a/firmware/application/view_factory_base.hpp b/firmware/application/view_factory_base.hpp new file mode 100644 index 000000000..f84e0b09d --- /dev/null +++ b/firmware/application/view_factory_base.hpp @@ -0,0 +1,40 @@ +/* + * Copyright 2024 Tamas Eisenberger + * + * This file is part of PortaPack. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#ifndef __VIEW_FACTORY_BASE_HPP__ +#define __VIEW_FACTORY_BASE_HPP__ + +#include +#include "ui_widget.hpp" + +namespace ui { + +class NavigationView; + +class ViewFactoryBase { + public: + virtual ~ViewFactoryBase(); + virtual std::unique_ptr produce(NavigationView& nav) const = 0; +}; + +} // namespace ui + +#endif //__VIEW_FACTORY_BASE_HPP__