diff --git a/changelog.md b/changelog.md index b89472e35..007172ac3 100644 --- a/changelog.md +++ b/changelog.md @@ -1,5 +1,11 @@ # MuditaOS changelog +## current + +### Added: + +* `[gui]` Dynamic Windows building and handling implemented + ## [0.42.1 2020-10-12] ### Added diff --git a/module-apps/Application.cpp b/module-apps/Application.cpp index 30dcb8799..1e34ae319 100644 --- a/module-apps/Application.cpp +++ b/module-apps/Application.cpp @@ -26,6 +26,7 @@ #include // for find #include // for distance, next #include // for add_const<>... +#include namespace gui { @@ -66,8 +67,8 @@ namespace app Application::Application( std::string name, std::string parent, bool startBackground, uint32_t stackDepth, sys::ServicePriority priority) - : Service(name, parent, stackDepth, priority), - startBackground{startBackground} + : Service(name, parent, stackDepth, priority), default_window(gui::name::window::main_window), + windowsStack(this), windowsFactory(), startBackground{startBackground} { keyTranslator = std::make_unique(); busChannels.push_back(sys::BusChannels::ServiceCellularNotifications); @@ -79,13 +80,7 @@ namespace app longPressTimer->connect([&](sys::Timer &) { longPressTimerCallback(); }); } - Application::~Application() - { - for (auto it = windows.begin(); it != windows.end(); it++) { - delete it->second; - } - windows.clear(); - } + Application::~Application() = default; Application::State Application::getState() { @@ -169,7 +164,7 @@ namespace app #if DEBUG_APPLICATION_MANAGEMENT == 1 LOG_INFO("switching [%s] to window: %s data description: %s", GetName().c_str(), - windowName.length() ? windowName.c_str() : gui::name::window::main_window.c_str(), + windowName.length() ? windowName.c_str() : default_window.c_str(), data ? data->getDescription().c_str() : ""); #endif @@ -181,7 +176,7 @@ namespace app sys::Bus::SendUnicast(msg, this->GetName(), this); } else { - window = windowName.empty() ? gui::name::window::main_window : windowName; + window = windowName.empty() ? default_window : windowName; auto msg = std::make_shared( window, getCurrentWindow() ? getCurrentWindow()->getName() : "", std::move(data), cmd); sys::Bus::SendUnicast(msg, this->GetName(), this); @@ -392,15 +387,15 @@ namespace app { auto msg = static_cast(msgl); // check if specified window is in the application - auto it = windows.find(msg->getWindowName()); - if (it != windows.end()) { + + if (windowsFactory.isRegistered(msg->getWindowName())) { auto switchData = std::move(msg->getData()); if (switchData && switchData->ignoreCurrentWindowOnStack) { popToWindow(getPrevWindow()); } getCurrentWindow()->onClose(); setActiveWindow(msg->getWindowName()); - + LOG_DEBUG("Current window: %s vs %s", getCurrentWindow()->getName().c_str(), msg->getWindowName().c_str()); getCurrentWindow()->handleSwitchData(switchData.get()); // check if this is case where application is returning to the last visible window. @@ -433,14 +428,9 @@ namespace app sys::Message_t Application::handleAppRebuild(sys::DataMessage *msgl) { LOG_INFO("Application %s rebuilding gui", GetName().c_str()); - for (auto it = windows.begin(); it != windows.end(); it++) { - LOG_DEBUG("Rebuild: %s", it->first.c_str()); - if (!it->second) { - LOG_ERROR("NO SUCH WINDOW"); - } - else { - it->second->rebuild(); - } + for (auto &[name, window] : windowsStack) { + LOG_DEBUG("Rebuild: %s", name.c_str()); + windowsStack.windows[name] = windowsFactory.build(this, name); } LOG_INFO("Refresh app with focus!"); if (state == State::ACTIVE_FORGROUND) { @@ -452,7 +442,7 @@ namespace app sys::Message_t Application::handleAppRefresh(sys::DataMessage *msgl) { - AppRefreshMessage *msg = reinterpret_cast(msgl); + auto *msg = static_cast(msgl); render(msg->getMode()); return msgHandled(); } @@ -467,6 +457,7 @@ namespace app sys::ReturnCodes Application::InitHandler() { bool initState = true; + setState(State::INITIALIZING); // uint32_t start = xTaskGetTickCount(); settings = DBServiceAPI::SettingsGet(this); @@ -483,10 +474,7 @@ namespace app sys::ReturnCodes Application::DeinitHandler() { LOG_INFO("Closing an application: %s", GetName().c_str()); - for (const auto &[windowName, window] : windows) { - LOG_INFO("Closing a window: %s", windowName.c_str()); - window->onClose(); - } + windowsStack.windows.clear(); return sys::ReturnCodes::Success; } @@ -563,18 +551,20 @@ namespace app { if (window == gui::name::window::no_window) { bool ret = false; - if (windowStack.size() <= 1) { - windowStack.clear(); + if (windowsStack.stack.size() <= 1) { + windowsStack.stack.clear(); ret = true; } return ret; } - auto ret = std::find(windowStack.begin(), windowStack.end(), window); - if (ret != windowStack.end()) { - LOG_INFO( - "Pop last window(s) [%d] : %s", static_cast(std::distance(ret, windowStack.end())), ret->c_str()); - windowStack.erase(std::next(ret), windowStack.end()); + auto ret = std::find(windowsStack.stack.begin(), windowsStack.stack.end(), window); + if (ret != windowsStack.stack.end()) { + LOG_INFO("Pop last window(s) [%d] : %s", + static_cast(std::distance(ret, windowsStack.stack.end())), + ret->c_str()); + windowsStack.stack.erase(std::next(ret), windowsStack.stack.end()); + LOG_INFO("Curent window... %s vs %s", ret->c_str(), windowsStack.stack.back().c_str()); return true; } return false; @@ -583,59 +573,46 @@ namespace app void Application::pushWindow(const std::string &newWindow) { // handle if window was already on + LOG_DEBUG("App: %s window %s request", GetName().c_str(), newWindow.c_str()); if (popToWindow(newWindow)) { return; } else { - windowStack.push_back(newWindow); + windowsStack.push(newWindow, windowsFactory.build(this, newWindow)); } #if DEBUG_APPLICATION_MANAGEMENT == 1 - LOG_DEBUG("[%d] newWindow: %s", windowStack.size(), newWindow.c_str()); - for (auto &el : windowStack) { + LOG_DEBUG("[%d] newWindow: %s", (int)windowsStack.stack.size(), newWindow.c_str()); + for (auto &el : windowsStack.stack) { LOG_DEBUG("-> %s", el.c_str()); } - LOG_INFO("\n\n"); #endif }; const std::string Application::getPrevWindow(uint32_t count) const { - if (this->windowStack.size() <= 1 || count > this->windowStack.size()) { + if (this->windowsStack.stack.size() <= 1 || count > this->windowsStack.stack.size()) { return gui::name::window::no_window; } - return *std::prev(windowStack.end(), count + 1); + return *std::prev(windowsStack.stack.end(), count + 1); } void Application::Application::cleanPrevWindw() { - this->windowStack.clear(); - } - - gui::AppWindow *Application::getWindow(const std::string &window) - { - auto it = windows.find(window); - if (it != windows.end()) { - return it->second; - } - return nullptr; + this->windowsStack.stack.clear(); } gui::AppWindow *Application::getCurrentWindow() { - std::string window = ""; - if (windowStack.size() == 0) { - window = gui::name::window::main_window; + if (windowsStack.stack.size() == 0) { + windowsStack.push(default_window, windowsFactory.build(this, default_window)); } - else { - window = windowStack.back(); - } - - return getWindow(window); + /// TODO handle nullptr? if not found on stack -> return default + return windowsStack.get(windowsStack.stack.back()); } - void Application::attachWindow(gui::AppWindow *window) + gui::AppWindow *Application::getWindow(const std::string &name) { - windows.insert({window->getName(), window}); + return windowsStack.get(name); } void Application::connect(std::unique_ptr &&timer, gui::Item *item) diff --git a/module-apps/Application.hpp b/module-apps/Application.hpp index a8901d2eb..a454393ca 100644 --- a/module-apps/Application.hpp +++ b/module-apps/Application.hpp @@ -23,10 +23,13 @@ #include // for string #include // for move, pair #include // for vector +#include "WindowsFactory.hpp" +#include "WindowsStack.hpp" namespace app { class GuiTimer; + class WindowsStack; } // namespace app namespace gui { @@ -106,6 +109,7 @@ namespace app static const char *stateStr(State st); private: + std::string default_window; State state = State::DEACTIVATED; sys::Message_t handleSignalStrengthUpdate(sys::DataMessage *msgl); @@ -130,6 +134,7 @@ namespace app bool startBackground = false, uint32_t stackDepth = 4096, sys::ServicePriority priority = sys::ServicePriority::Idle); + virtual ~Application(); Application::State getState(); @@ -298,17 +303,10 @@ namespace app virtual void createUserInterface() = 0; /// Method closing application's windows. virtual void destroyUserInterface() = 0; - /// Helper method to attach new window to application - void attachWindow(gui::AppWindow *window); - /// Map containing application's windows - /// Right now all application windows are being created on application start in createUserInterface - /// then all windows are removed at the end of application - /// @note right now there is no mechanism to postphone window creation - std::map windows; - /// stack of visited windows in application /// @ingrup AppWindowStack - std::vector windowStack; + WindowsStack windowsStack; + WindowsFactory windowsFactory; public: /// @ingrup AppWindowStack @@ -323,13 +321,11 @@ namespace app /// clears windows stack /// @ingrup AppWindowStack void cleanPrevWindw(); - /// getter to get window by name - /// @note could be possibly used to implement building window on request - /// @ingrup AppWindowStack - gui::AppWindow *getWindow(const std::string &window); /// getter for current wisible window in application /// @ingrup AppWindowStack gui::AppWindow *getCurrentWindow(); + + gui::AppWindow *getWindow(const std::string &name); /// to avoid conflicts with connect below using Service::connect; /// connects item with GuiTimer and stores it in app @@ -361,75 +357,4 @@ namespace app const gui::InputEvent &event); }; - /// used in ApplicationManager to start applications - class ApplicationLauncher - { - protected: - /// name of the application to run - std::string name = ""; - /// name of the application's owner - std::string parent = ""; - /// defines whether application can be closed when it looses focus - bool closeable = true; - /// defines whether application should be run without gaining focus, it will remian in the BACKGROUND state - bool startBackground = false; - /// flag defines whether this application can prevent power manager from changing - bool preventBlocking = false; - - public: - ApplicationLauncher(std::string name, bool isCloseable, bool preventBlocking = false) - : name{name}, closeable{isCloseable}, preventBlocking{preventBlocking} {}; - virtual ~ApplicationLauncher(){}; - std::string getName() - { - return name; - }; - bool isCloseable() - { - return closeable; - }; - bool isBlocking() - { - return preventBlocking; - }; - - // virtual method to run the application - virtual bool run(sys::Service *caller = nullptr) - { - return true; - }; - virtual bool runBackground(sys::Service *caller = nullptr) - { - return true; - }; - std::shared_ptr handle = nullptr; - }; - - /// application launcher boilerplate - template class ApplicationLauncherT : public ApplicationLauncher - { - public: - ApplicationLauncherT(std::string name, bool isCloseable = true) : ApplicationLauncher(name, isCloseable) - {} - virtual bool run(sys::Service *caller) override - { - parent = (caller == nullptr ? "" : caller->GetName()); - handle = std::make_shared(name, parent); - return sys::SystemManager::CreateService(handle, caller); - }; - bool runBackground(sys::Service *caller) override - { - parent = (caller == nullptr ? "" : caller->GetName()); - handle = std::make_shared(name, parent, true); - return sys::SystemManager::CreateService(handle, caller); - }; - }; - - /// creates application launcher per class provided - template - std::unique_ptr> CreateLauncher(std::string name, bool isCloseable = true) - { - return std::move(std::unique_ptr>(new ApplicationLauncherT(name, isCloseable))); - } - } /* namespace app */ diff --git a/module-apps/ApplicationLauncher.hpp b/module-apps/ApplicationLauncher.hpp new file mode 100644 index 000000000..b993d78ce --- /dev/null +++ b/module-apps/ApplicationLauncher.hpp @@ -0,0 +1,84 @@ +#pragma once + +#include "Application.hpp" + +namespace app +{ + + /// used in ApplicationManager to start applications + class ApplicationLauncher + { + protected: + /// name of the application to run + std::string name; + /// name of the application's owner + std::string parent; + /// defines whether application can be closed when it looses focus + bool closeable = true; + /// defines whether application should be run without gaining focus, it will remian in the BACKGROUND state + bool startBackground = false; + /// flag defines whether this application can prevent power manager from changing + bool preventBlocking = false; + + public: + ApplicationLauncher(std::string name, bool isCloseable, bool preventBlocking = false) + : name{name}, closeable{isCloseable}, preventBlocking{preventBlocking} {}; + virtual ~ApplicationLauncher() = default; + + [[nodiscard]] std::string getName() const noexcept + { + return name; + } + + [[nodiscard]] bool isCloseable() const noexcept + { + return closeable; + } + + [[nodiscard]] bool isBlocking() const noexcept + { + return preventBlocking; + } + + virtual bool run(sys::Service *caller = nullptr) + { + return false; + } + + virtual bool runBackground(sys::Service *caller = nullptr) + { + return false; + } + + std::shared_ptr handle = nullptr; + }; + + /// application launcher boilerplate + template class ApplicationLauncherT : public ApplicationLauncher + { + public: + ApplicationLauncherT(std::string name, bool isCloseable = true) : ApplicationLauncher(name, isCloseable) + {} + + bool run(sys::Service *caller) override + { + parent = (caller == nullptr ? "" : caller->GetName()); + handle = std::make_shared(name, parent); + return sys::SystemManager::CreateService(handle, caller); + } + + bool runBackground(sys::Service *caller) override + { + parent = (caller == nullptr ? "" : caller->GetName()); + handle = std::make_shared(name, parent, true); + return sys::SystemManager::CreateService(handle, caller); + } + }; + + /// creates application launcher per class provided + template + std::unique_ptr> CreateLauncher(std::string name, bool isCloseable = true) + { + return std::unique_ptr>(new ApplicationLauncherT(name, isCloseable)); + } +} // namespace app diff --git a/module-apps/CMakeLists.txt b/module-apps/CMakeLists.txt index dd69dcb5c..005c8b602 100644 --- a/module-apps/CMakeLists.txt +++ b/module-apps/CMakeLists.txt @@ -15,9 +15,11 @@ set( SOURCES "Application.cpp" "GuiTimer.cpp" "UiCommonActions.cpp" + "WindowsFactory.cpp" "windows/AppWindow.cpp" "windows/OptionWindow.cpp" "windows/Options.cpp" + "windows/OptionsWindowOption.cpp" "windows/Dialog.cpp" "windows/NoEvents.cpp" "widgets/SearchBox.cpp" diff --git a/module-apps/WindowsFactory.cpp b/module-apps/WindowsFactory.cpp new file mode 100644 index 000000000..0e05ce275 --- /dev/null +++ b/module-apps/WindowsFactory.cpp @@ -0,0 +1,21 @@ +#include "WindowsFactory.hpp" +#include + +namespace app +{ + + void WindowsFactory::attach(const std::string &name, builder builder) + { + builders[name] = builder; + } + + auto WindowsFactory::isRegistered(const std::string &name) const -> bool + { + return builders.find(name) != std::end(builders); + } + + auto WindowsFactory::build(Application *app, const std::string &name) -> handle + { + return builders[name](app, name); + } +} // namespace app diff --git a/module-apps/WindowsFactory.hpp b/module-apps/WindowsFactory.hpp new file mode 100644 index 000000000..175911f7a --- /dev/null +++ b/module-apps/WindowsFactory.hpp @@ -0,0 +1,40 @@ +#pragma once + +#include +#include +#include +#include + +namespace app +{ + class Application; +}; + +namespace gui +{ + class AppWindow; +} + +namespace app +{ + class WindowsFactory + { + public: + using handle = std::unique_ptr; + using builder = std::function; + + private: + std::map builders; + + public: + WindowsFactory() = default; + WindowsFactory(const WindowsFactory &) = delete; + WindowsFactory(WindowsFactory &&) = delete; + WindowsFactory &operator=(const WindowsFactory &) = delete; + WindowsFactory &operator=(WindowsFactory &&) = delete; + + void attach(const std::string &name, builder builder); + [[nodiscard]] auto isRegistered(const std::string &name) const -> bool; + auto build(Application *app, const std::string &name) -> handle; + }; +} // namespace app diff --git a/module-apps/WindowsStack.hpp b/module-apps/WindowsStack.hpp new file mode 100644 index 000000000..89b1fe3ed --- /dev/null +++ b/module-apps/WindowsStack.hpp @@ -0,0 +1,52 @@ +#pragma once + +#include +#include +#include +#include +#include + +namespace app +{ + + class Application; + + class WindowsStack + { + Application *parent; + + public: + WindowsStack(Application *parent) : parent(parent) + {} + + std::vector stack; + std::map> windows; + + std::map>::const_iterator begin() const + { + return std::begin(windows); + } + + std::map>::const_iterator end() const + { + return std::end(windows); + } + + [[nodiscard]] auto getParent() const + { + return parent; + } + + auto push(const std::string &name, std::unique_ptr window) + { + windows[name] = std::move(window); + stack.push_back(name); + } + + gui::AppWindow *get(const std::string &name) + { + auto ret = windows.find(name); + return ret == std::end(windows) ? nullptr : ret->second.get(); + } + }; +} // namespace app diff --git a/module-apps/application-antenna/ApplicationAntenna.cpp b/module-apps/application-antenna/ApplicationAntenna.cpp index 3efae5daf..87579732d 100644 --- a/module-apps/application-antenna/ApplicationAntenna.cpp +++ b/module-apps/application-antenna/ApplicationAntenna.cpp @@ -92,7 +92,7 @@ namespace app if (msgl->messageType == MessageType::CellularGetScanModeResult) { auto msg = dynamic_cast(msgl); if (msg != nullptr) { - auto win = getWindow(gui::name::window::scan_window); + auto win = windowsStack.get(gui::name::window::scan_window); if (win->getName() == gui::name::window::scan_window) { auto window = dynamic_cast(win); @@ -122,7 +122,7 @@ namespace app if (win->getName() == gui::name::window::algo_window) { refresh = true; } - auto window = getWindow(gui::name::window::algo_window); + auto window = windowsStack.get(gui::name::window::algo_window); auto algoWindow = dynamic_cast(window); if (algoWindow != nullptr) { algoWindow->handleAntennaChanged(antenna, refresh); @@ -163,15 +163,16 @@ namespace app void ApplicationAntenna::createUserInterface() { - - gui::AppWindow *win = new gui::AntennaMainWindow(this); - windows.insert(std::pair(gui::name::window::main_window, win)); - - win = new gui::ScanModesWindow(this); - windows.insert(std::pair(gui::name::window::scan_window, win)); - - win = new gui::AlgoParamsWindow(this); - windows.insert(std::pair(gui::name::window::algo_window, win)); + using namespace gui::name::window; + windowsFactory.attach(main_window, [](Application *app, const std::string &name) { + return std::make_unique(app); + }); + windowsFactory.attach(scan_window, [](Application *app, const std::string &name) { + return std::make_unique(app); + }); + windowsFactory.attach(algo_window, [](Application *app, const std::string &name) { + return std::make_unique(app); + }); } void ApplicationAntenna::destroyUserInterface() @@ -196,7 +197,7 @@ namespace app lastFreq = bandFreq; bool refresh = false; - auto win = getWindow(gui::name::window::algo_window); + auto win = windowsStack.get(gui::name::window::algo_window); if (win == getCurrentWindow()) { refresh = true; } diff --git a/module-apps/application-calendar/ApplicationCalendar.cpp b/module-apps/application-calendar/ApplicationCalendar.cpp index 9e13a0b42..5d5cd7baf 100644 --- a/module-apps/application-calendar/ApplicationCalendar.cpp +++ b/module-apps/application-calendar/ApplicationCalendar.cpp @@ -59,7 +59,7 @@ namespace app LOG_DEBUG("Received notification"); // window-specific actions if (msg->interface == db::Interface::Name::Events) { - for (auto &[name, window] : windows) { + for (auto &[name, window] : windowsStack.windows) { window->onDatabaseMessage(msg); } } @@ -112,32 +112,36 @@ namespace app void ApplicationCalendar::createUserInterface() { + using namespace style::window::calendar::name; - windows.insert(std::pair( - gui::name::window::main_window, new gui::CalendarMainWindow(this, gui::name::window::main_window))); - windows.insert(std::pair( - style::window::calendar::name::day_events_window, - new gui::DayEventsWindow(this, style::window::calendar::name::day_events_window))); - windows.insert(std::pair( - style::window::calendar::name::no_events_window, - new gui::NoEvents(this, style::window::calendar::name::no_events_window, gui::NoEvents::Meta()))); - windows.insert(std::pair(style::window::calendar::name::events_options, - new gui::CalendarEventsOptions(this))); - windows.insert(std::pair( - style::window::calendar::name::dialog_yes_no, - new gui::DialogYesNo(this, style::window::calendar::name::dialog_yes_no))); - windows.insert(std::pair( - style::window::calendar::name::all_events_window, - new gui::AllEventsWindow(this, style::window::calendar::name::all_events_window))); - windows.insert(std::pair( - style::window::calendar::name::details_window, - new gui::EventDetailWindow(this, style::window::calendar::name::details_window))); - windows.insert(std::pair( - style::window::calendar::name::new_edit_event, - new gui::NewEditEventWindow(this, style::window::calendar::name::new_edit_event))); - windows.insert(std::pair( - style::window::calendar::name::custom_repeat_window, - new gui::CustomRepeatWindow(this, style::window::calendar::name::custom_repeat_window))); + windowsFactory.attach(gui::name::window::main_window, [](Application *app, const std::string &name) { + return std::make_unique(app, name); + }); + windowsFactory.attach(day_events_window, [](Application *app, const std::string &name) { + return std::make_unique(app); + }); + windowsFactory.attach(no_events_window, [](Application *app, const std::string &name) { + return std::make_unique(app, name, gui::NoEvents::Meta()); + }); + windowsFactory.attach(style::window::calendar::name::events_options, + [](Application *app, const std::string &name) { + return std::make_unique(app); + }); + windowsFactory.attach(dialog_yes_no, [](Application *app, const std::string &name) { + return std::make_unique(app, dialog_yes_no); + }); + windowsFactory.attach(all_events_window, [](Application *app, const std::string &name) { + return std::make_unique(app, all_events_window); + }); + windowsFactory.attach(details_window, [](Application *app, const std::string &name) { + return std::make_unique(app, details_window); + }); + windowsFactory.attach(new_edit_event, [](Application *app, const std::string &name) { + return std::make_unique(app, new_edit_event); + }); + windowsFactory.attach(custom_repeat_window, [](Application *app, const std::string &name) { + return std::make_unique(app, custom_repeat_window); + }); } void ApplicationCalendar::destroyUserInterface() @@ -146,7 +150,7 @@ namespace app void ApplicationCalendar::switchToNoEventsWindow(const std::string &title, const TimePoint &dateFilter) { - auto dialog = dynamic_cast(getWindow(style::window::calendar::name::no_events_window)); + auto dialog = dynamic_cast(windowsStack.get(style::window::calendar::name::no_events_window)); assert(dialog != nullptr); auto meta = dialog->meta; meta.text = "app_calendar_no_events_information"; diff --git a/module-apps/application-calendar/windows/CalendarEventsOptionsWindow.cpp b/module-apps/application-calendar/windows/CalendarEventsOptionsWindow.cpp index f7beb7b63..349670cdb 100644 --- a/module-apps/application-calendar/windows/CalendarEventsOptionsWindow.cpp +++ b/module-apps/application-calendar/windows/CalendarEventsOptionsWindow.cpp @@ -1,4 +1,5 @@ #include "CalendarEventsOptionsWindow.hpp" +#include "DialogMetadataMessage.hpp" #include "application-calendar/widgets/CalendarStyle.hpp" #include "Dialog.hpp" #include @@ -45,17 +46,16 @@ namespace gui eventRecord = item->getData(); clearOptions(); - addOptions(eventsOptionsList()); + options = eventsOptionsList(); + addOptions(options); return true; } auto CalendarEventsOptions::eventDelete() -> bool { LOG_DEBUG("Switch to delete event window"); - auto dialog = dynamic_cast( - this->application->getWindow(style::window::calendar::name::dialog_yes_no)); - assert(dialog != nullptr); - auto meta = dialog->meta; + gui::DialogMetadata meta; + meta.action = [=]() -> bool { LOG_INFO("Delete calendar event %d", static_cast(eventRecord->ID)); DBServiceAPI::GetQuery( @@ -67,8 +67,9 @@ namespace gui meta.text = utils::localize.get("app_calendar_event_delete_confirmation"); meta.title = eventRecord->title; meta.icon = "phonebook_contact_delete_trashcan"; - dialog->update(meta); - this->application->switchWindow(dialog->getName()); + + this->application->switchWindow(style::window::calendar::name::dialog_yes_no, + std::make_unique(meta)); return true; } } // namespace gui diff --git a/module-apps/application-calendar/windows/CalendarMainWindow.cpp b/module-apps/application-calendar/windows/CalendarMainWindow.cpp index 0a1728830..c70b8f270 100644 --- a/module-apps/application-calendar/windows/CalendarMainWindow.cpp +++ b/module-apps/application-calendar/windows/CalendarMainWindow.cpp @@ -13,7 +13,7 @@ namespace gui { - CalendarMainWindow::CalendarMainWindow(app::Application *app, std::string name) : AppWindow(app, name) + CalendarMainWindow::CalendarMainWindow(app::Application *app, const std::string &name) : AppWindow(app, name) { auto appCalendar = dynamic_cast(application); assert(appCalendar != nullptr); diff --git a/module-apps/application-calendar/windows/CalendarMainWindow.hpp b/module-apps/application-calendar/windows/CalendarMainWindow.hpp index 8615a351b..fb3d4123f 100644 --- a/module-apps/application-calendar/windows/CalendarMainWindow.hpp +++ b/module-apps/application-calendar/windows/CalendarMainWindow.hpp @@ -30,7 +30,7 @@ namespace gui std::unique_ptr monthModel; public: - CalendarMainWindow(app::Application *app, std::string name); + CalendarMainWindow(app::Application *app, const std::string &name); ~CalendarMainWindow() override = default; void rebuild() override; diff --git a/module-apps/application-calendar/windows/DayEventsWindow.cpp b/module-apps/application-calendar/windows/DayEventsWindow.cpp index 46ea26f04..654eb05ff 100644 --- a/module-apps/application-calendar/windows/DayEventsWindow.cpp +++ b/module-apps/application-calendar/windows/DayEventsWindow.cpp @@ -16,7 +16,7 @@ namespace gui { - DayEventsWindow::DayEventsWindow(app::Application *app, std::string name) + DayEventsWindow::DayEventsWindow(app::Application *app) : AppWindow(app, style::window::calendar::name::day_events_window), dayEventsModel{std::make_shared(this->application)} { diff --git a/module-apps/application-calendar/windows/DayEventsWindow.hpp b/module-apps/application-calendar/windows/DayEventsWindow.hpp index bcb81b9e2..15debd2ab 100644 --- a/module-apps/application-calendar/windows/DayEventsWindow.hpp +++ b/module-apps/application-calendar/windows/DayEventsWindow.hpp @@ -23,7 +23,7 @@ namespace gui std::shared_ptr dayEventsModel = nullptr; public: - DayEventsWindow(app::Application *app, std::string name); + DayEventsWindow(app::Application *app); bool handleSwitchData(SwitchData *data) override; bool onInput(const gui::InputEvent &inputEvent) override; bool onDatabaseMessage(sys::Message *msgl) override; diff --git a/module-apps/application-call/ApplicationCall.cpp b/module-apps/application-call/ApplicationCall.cpp index 054930c26..20b10e6b4 100644 --- a/module-apps/application-call/ApplicationCall.cpp +++ b/module-apps/application-call/ApplicationCall.cpp @@ -1,5 +1,7 @@ #include "ApplicationCall.hpp" +#include "DialogMetadata.hpp" +#include "DialogMetadataMessage.hpp" #include "data/CallSwitchData.hpp" #include "windows/CallMainWindow.hpp" #include "windows/CallWindow.hpp" @@ -38,8 +40,7 @@ namespace app { callDuration = utils::time::Timestamp() - callStartTime; - auto it = windows.find(window::name_call); - if (getCurrentWindow() == it->second) { + if (getCurrentWindow() == windowsStack.get(window::name_call)) { auto callWindow = dynamic_cast(getCurrentWindow()); if (callWindow != nullptr && callWindow->getState() == gui::CallWindow::State::CALL_IN_PROGRESS) { @@ -47,12 +48,11 @@ namespace app refreshWindow(gui::RefreshModes::GUI_REFRESH_FAST); } } - } void ApplicationCall::CallAbortHandler() { - gui::CallWindow *callWindow = dynamic_cast(windows.find(window::name_call)->second); + auto callWindow = dynamic_cast(windowsStack.get(window::name_call)); assert(callWindow != nullptr); LOG_INFO("---------------------------------CallAborted"); @@ -74,7 +74,7 @@ namespace app void ApplicationCall::CallActiveHandler() { - gui::CallWindow *callWindow = dynamic_cast(windows.find(window::name_call)->second); + auto callWindow = dynamic_cast(windowsStack.get(window::name_call)); assert(callWindow != nullptr); AudioServiceAPI::RoutingStart(this); @@ -87,7 +87,7 @@ namespace app void ApplicationCall::IncomingCallHandler(const CellularCallMessage *const msg) { - gui::CallWindow *callWindow = dynamic_cast(windows.find(window::name_call)->second); + auto callWindow = dynamic_cast(windowsStack.get(window::name_call)); assert(callWindow != nullptr); LOG_INFO("---------------------------------IncomingCall"); @@ -114,7 +114,7 @@ namespace app void ApplicationCall::RingingHandler(const CellularCallMessage *const msg) { - gui::CallWindow *callWindow = dynamic_cast(windows.find(window::name_call)->second); + auto callWindow = dynamic_cast(windowsStack.get(window::name_call)); assert(callWindow != nullptr); LOG_INFO("---------------------------------Ringing"); @@ -134,7 +134,9 @@ namespace app auto retMsg = Application::DataReceivedHandler(msgl); // if message was handled by application's template there is no need to process further. - if ((reinterpret_cast(retMsg.get())->retCode == sys::ReturnCodes::Success)) { + auto response = dynamic_cast(retMsg.get()); + assert(response); + if (response->retCode == sys::ReturnCodes::Success) { return retMsg; } @@ -209,34 +211,30 @@ namespace app void ApplicationCall::createUserInterface() { - gui::AppWindow *window = nullptr; - - window = new gui::CallMainWindow(this); - windows.insert(std::pair(window->getName(), window)); - - window = new gui::EnterNumberWindow(this); - windows.insert(std::pair(window->getName(), window)); - - window = new gui::CallWindow(this); - windows.insert(std::pair(window->getName(), window)); - - window = new gui::EmergencyCallWindow(this); - windows.insert(std::pair(window->getName(), window)); - - window = new gui::DialogConfirm(this, app::window::name_dialogConfirm); - windows.insert(std::pair(app::window::name_dialogConfirm, window)); + windowsFactory.attach(gui::name::window::main_window, [](Application *app, const std::string name) { + return std::make_unique(app); + }); + windowsFactory.attach(app::window::name_enterNumber, [](Application *app, const std::string newname) { + return std::make_unique(app); + }); + windowsFactory.attach(app::window::name_call, [](Application *app, const std::string &name) { + return std::make_unique(app); + }); + windowsFactory.attach(app::window::name_emergencyCall, [](Application *app, const std::string &name) { + return std::make_unique(app); + }); + windowsFactory.attach(app::window::name_dialogConfirm, [](Application *app, const std::string &name) { + return std::make_unique(app, name); + }); } bool ApplicationCall::showNotification(std::function action) { - auto dialog = dynamic_cast(windows[app::window::name_dialogConfirm]); - assert(dialog); - auto meta = dialog->meta; + gui::DialogMetadata meta; meta.icon = "info_big_circle_W_G"; meta.text = utils::localize.get("app_call_no_sim"); meta.action = action; - dialog->update(meta); - switchWindow(dialog->getName()); + switchWindow(app::window::name_dialogConfirm, std::make_unique(meta)); return true; } diff --git a/module-apps/application-calllog/ApplicationCallLog.cpp b/module-apps/application-calllog/ApplicationCallLog.cpp index 574b100cc..a9b7d5fd1 100644 --- a/module-apps/application-calllog/ApplicationCallLog.cpp +++ b/module-apps/application-calllog/ApplicationCallLog.cpp @@ -1,4 +1,6 @@ #include "ApplicationCallLog.hpp" +#include "DialogMetadata.hpp" +#include "DialogMetadataMessage.hpp" #include "data/CallLogInternals.hpp" #include "windows/CallLogDetailsWindow.hpp" #include "windows/CallLogMainWindow.hpp" @@ -84,20 +86,18 @@ namespace app void ApplicationCallLog::createUserInterface() { - - gui::AppWindow *window = nullptr; - - window = new gui::CallLogMainWindow(this); - windows.insert(std::pair(window->getName(), window)); - - window = new gui::CallLogDetailsWindow(this); - windows.insert(std::pair(window->getName(), window)); - - windowOptions = gui::newOptionWindow(this); - windows.insert(std::pair(windowOptions->getName(), windowOptions)); - - window = new gui::DialogYesNo(this, calllog::settings::DialogYesNoStr); - windows.insert(std::pair(window->getName(), window)); + windowsFactory.attach(calllog::settings::MainWindowStr, [](Application *app, const std::string &name) { + return std::make_unique(app); + }); + windowsFactory.attach(calllog::settings::DetailsWindowStr, [](Application *app, const std::string &name) { + return std::make_unique(app); + }); + windowsFactory.attach( + utils::localize.get("app_phonebook_options_title"), + [](Application *app, const std::string &name) { return std::make_unique(app, name); }); + windowsFactory.attach(calllog::settings::DialogYesNoStr, [](Application *app, const std::string &name) { + return std::make_unique(app, name); + }); } void ApplicationCallLog::destroyUserInterface() @@ -106,9 +106,7 @@ namespace app bool ApplicationCallLog::removeCalllogEntry(const CalllogRecord &record) { LOG_DEBUG("Removing CalllogRecord: %" PRIu32, record.ID); - auto dialog = dynamic_cast(windows[calllog::settings::DialogYesNoStr]); - assert(dialog != nullptr); - auto meta = dialog->meta; + gui::DialogMetadata meta; meta.action = [=]() -> bool { if (DBServiceAPI::CalllogRemove(this, record.ID) == false) { LOG_ERROR("CalllogRemove id=%" PRIu32 " failed", record.ID); @@ -120,8 +118,7 @@ namespace app meta.title = record.name; meta.text = utils::localize.get("app_calllog_delete_call_confirmation"); meta.icon = "phonebook_contact_delete_trashcan"; - dialog->update(meta); - switchWindow(dialog->getName()); + switchWindow(calllog::settings::DialogYesNoStr, std::make_unique(meta)); return true; } diff --git a/module-apps/application-calllog/ApplicationCallLog.hpp b/module-apps/application-calllog/ApplicationCallLog.hpp index 5cc9d98e0..83d3dc6d7 100644 --- a/module-apps/application-calllog/ApplicationCallLog.hpp +++ b/module-apps/application-calllog/ApplicationCallLog.hpp @@ -22,9 +22,7 @@ namespace app protected: public: ApplicationCallLog(std::string name = CallLogAppStr, std::string parent = "", bool startBackgound = false); - virtual ~ApplicationCallLog(); - - gui::OptionWindow *windowOptions = nullptr; + ~ApplicationCallLog() override; sys::Message_t DataReceivedHandler(sys::DataMessage *msgl, sys::ResponseMessage *resp) override; sys::ReturnCodes InitHandler() override; diff --git a/module-apps/application-calllog/windows/CallLogDetailsWindow.cpp b/module-apps/application-calllog/windows/CallLogDetailsWindow.cpp index 1b51a3797..4e3578286 100644 --- a/module-apps/application-calllog/windows/CallLogDetailsWindow.cpp +++ b/module-apps/application-calllog/windows/CallLogDetailsWindow.cpp @@ -11,6 +11,7 @@ #include #include +#include "OptionsWindow.hpp" #include "service-appmgr/ApplicationManager.hpp" #include "bsp/rtc/rtc.hpp" @@ -260,12 +261,8 @@ namespace gui (inputEvent.keyCode == KeyCode::KEY_LF)) { auto app = dynamic_cast(application); assert(app != nullptr); - - if (app->windowOptions != nullptr) { - app->windowOptions->clearOptions(); - app->windowOptions->addOptions(calllogWindowOptions(app, record)); - app->switchWindow(app->windowOptions->getName(), nullptr); - } + app->switchWindow(utils::localize.get("app_phonebook_options_title"), + std::make_unique(calllogWindowOptions(app, record))); return true; } diff --git a/module-apps/application-clock/ApplicationClock.cpp b/module-apps/application-clock/ApplicationClock.cpp index 56c7e690f..e8c0ea1a3 100644 --- a/module-apps/application-clock/ApplicationClock.cpp +++ b/module-apps/application-clock/ApplicationClock.cpp @@ -8,6 +8,7 @@ */ // module-gui +#include "AppWindow.hpp" #include "Service/Timer.hpp" #include "gui/widgets/Window.hpp" @@ -39,8 +40,7 @@ namespace app void ApplicationClock::timerClockCallback() { - auto it = windows.find("MainWindow"); - gui::ClockMainWindow *win = reinterpret_cast(it->second); + auto win = reinterpret_cast(windowsStack.get(gui::name::window::main_window)); win->incrementSecond(); win->updateLabels(); render(gui::RefreshModes::GUI_REFRESH_FAST); @@ -52,7 +52,7 @@ namespace app auto retMsg = Application::DataReceivedHandler(msgl); // if message was handled by application's template there is no need to process further. - if ((reinterpret_cast(retMsg.get())->retCode == sys::ReturnCodes::Success)) { + if (reinterpret_cast(retMsg.get())->retCode == sys::ReturnCodes::Success) { return retMsg; } @@ -89,9 +89,9 @@ namespace app void ApplicationClock::createUserInterface() { - - gui::ClockMainWindow *mainWindow = new gui::ClockMainWindow(this); - windows.insert(std::pair(mainWindow->getName(), mainWindow)); + windowsFactory.attach(gui::name::window::main_window, [](Application *app, const std::string &name) { + return std::make_unique(app, name); + }); } void ApplicationClock::destroyUserInterface() diff --git a/module-apps/application-clock/windows/ClockMainWindow.cpp b/module-apps/application-clock/windows/ClockMainWindow.cpp index 72a2a4c1e..585269bf0 100644 --- a/module-apps/application-clock/windows/ClockMainWindow.cpp +++ b/module-apps/application-clock/windows/ClockMainWindow.cpp @@ -22,7 +22,7 @@ namespace gui { - ClockMainWindow::ClockMainWindow(app::Application *app) : gui::AppWindow(app, "MainWindow") + ClockMainWindow::ClockMainWindow(app::Application *app, const std::string &name) : gui::AppWindow(app, name) { uint32_t xOffset = 0; uint32_t yOffset = 0; diff --git a/module-apps/application-clock/windows/ClockMainWindow.hpp b/module-apps/application-clock/windows/ClockMainWindow.hpp index d1f1148c7..3e9c17f28 100644 --- a/module-apps/application-clock/windows/ClockMainWindow.hpp +++ b/module-apps/application-clock/windows/ClockMainWindow.hpp @@ -21,7 +21,7 @@ namespace gui ProgressBar *progressBar = nullptr; public: - ClockMainWindow(app::Application *app); + ClockMainWindow(app::Application *app, const std::string &name); bool handleSwitchData(SwitchData *data) override; diff --git a/module-apps/application-desktop/ApplicationDesktop.cpp b/module-apps/application-desktop/ApplicationDesktop.cpp index c1e5688b2..4f9631b49 100644 --- a/module-apps/application-desktop/ApplicationDesktop.cpp +++ b/module-apps/application-desktop/ApplicationDesktop.cpp @@ -92,8 +92,9 @@ namespace app } } - windows[app::window::name::desktop_menu]->rebuild(); - windows[app::window::name::desktop_main_window]->rebuild(); + /// TODO if current window is this one or was on stack -> requild it + /// windowsFactory.build(this, app::window::name::desktop_menu); + /// windowsFactory.build(this, app::window::name::desktop_main_window); return true; } @@ -112,7 +113,7 @@ namespace app msg->interface == db::Interface::Name::SMS) && msg->type != db::Query::Type::Read) { requestNotReadNotifications(); - windows[app::window::name::desktop_menu]->rebuild(); + windowsFactory.build(this, app::window::name::desktop_menu); } return false; @@ -209,13 +210,24 @@ namespace app void ApplicationDesktop::createUserInterface() { using namespace app::window::name; - windows.insert(std::pair(desktop_main_window, new gui::DesktopMainWindow(this))); - windows.insert(std::pair( - desktop_pin_lock, new gui::PinLockWindow(this, desktop_pin_lock, lockHandler.lock))); - windows.insert(std::pair(desktop_menu, new gui::MenuWindow(this))); - windows.insert(std::pair(desktop_poweroff, new gui::PowerOffWindow(this))); - windows.insert(std::pair(desktop_locked, new gui::LockedInfoWindow(this))); - windows.insert(std::pair(desktop_reboot, new gui::RebootWindow(this))); + windowsFactory.attach(desktop_main_window, [](Application *app, const std::string &name) { + return std::make_unique(app); + }); + windowsFactory.attach(desktop_pin_lock, [&](Application *app, const std::string newname) { + return std::make_unique(app, desktop_pin_lock, lockHandler.lock); + }); + windowsFactory.attach(desktop_menu, [](Application *app, const std::string newname) { + return std::make_unique(app); + }); + windowsFactory.attach(desktop_poweroff, [](Application *app, const std::string newname) { + return std::make_unique(app); + }); + windowsFactory.attach(desktop_locked, [](Application *app, const std::string newname) { + return std::make_unique(app); + }); + windowsFactory.attach(desktop_reboot, [](Application *app, const std::string newname) { + return std::make_unique(app); + }); } void ApplicationDesktop::destroyUserInterface() diff --git a/module-apps/application-meditation/ApplicationMeditation.cpp b/module-apps/application-meditation/ApplicationMeditation.cpp index 092b22efe..a6f27edec 100644 --- a/module-apps/application-meditation/ApplicationMeditation.cpp +++ b/module-apps/application-meditation/ApplicationMeditation.cpp @@ -32,8 +32,9 @@ namespace app void ApplicationMeditation::createUserInterface() { - auto meditationWindow = new gui::MeditationWindow(this); - windows.insert({gui::name::window::main_window, meditationWindow}); + windowsFactory.attach(gui::name::window::main_window, [](Application *app, const std::string &name) { + return std::make_unique(app); + }); } void ApplicationMeditation::destroyUserInterface() diff --git a/module-apps/application-messages/ApplicationMessages.cpp b/module-apps/application-messages/ApplicationMessages.cpp index 27a5665e9..5a84ca1dd 100644 --- a/module-apps/application-messages/ApplicationMessages.cpp +++ b/module-apps/application-messages/ApplicationMessages.cpp @@ -1,5 +1,8 @@ #include "ApplicationMessages.hpp" +#include "DialogMetadata.hpp" +#include "DialogMetadataMessage.hpp" +#include "OptionsWindow.hpp" #include "application-messages/data/SMSTextToSearch.hpp" #include "messages/DBNotificationMessage.hpp" #include "windows/MessagesMainWindow.hpp" @@ -13,6 +16,7 @@ #include #include #include +#include #include #include @@ -25,6 +29,7 @@ #include #include