diff --git a/radio/src/gui/colorlcd/layout.cpp b/radio/src/gui/colorlcd/layout.cpp index 3cdcda72e..71c15f5bb 100644 --- a/radio/src/gui/colorlcd/layout.cpp +++ b/radio/src/gui/colorlcd/layout.cpp @@ -46,6 +46,9 @@ const LayoutFactory * getLayoutFactory(const char * name) return nullptr; } +// +// Loads a layout, but does not attach it to any window +// Layout * loadLayout(const char * name, Layout::PersistentData * persistentData) { const LayoutFactory * factory = getLayoutFactory(name); @@ -55,10 +58,12 @@ Layout * loadLayout(const char * name, Layout::PersistentData * persistentData) return nullptr; } +// +// Detaches and deletes all custom screens +// void deleteCustomScreens() { - for (unsigned int i = 0; i < MAX_CUSTOM_SCREENS; i++) { - auto& screen = customScreens[i]; + for (auto& screen : customScreens) { if (screen) { screen->detach(); delete screen; @@ -75,6 +80,7 @@ void loadDefaultLayout() auto& screenData = g_model.screenData[0]; if (screen == nullptr && defaultLayout != nullptr) { + strcpy(screenData.LayoutId, defaultLayout->getId()); screen = defaultLayout->create(&screenData.layoutData); if (screen) { @@ -83,6 +89,9 @@ void loadDefaultLayout() } } +// +// Loads and attaches all configured custom screens +// void loadCustomScreens() { for (unsigned int i = 0; i < MAX_CUSTOM_SCREENS; i++) { @@ -97,6 +106,53 @@ void loadCustomScreens() } } +// +// Creates a new customer screen from factory: +// - the old screen is detached & deleted (including children) +// - new screen is configured into g_model +// - the new screen is returned (not attached) +// +Layout* createCustomScreen(const LayoutFactory* factory, unsigned customScreenIndex) +{ + if (!factory || (customScreenIndex >= MAX_CUSTOM_SCREENS)) + return nullptr; + + if (customScreens[customScreenIndex]) { + customScreens[customScreenIndex]->deleteLater(true, false); + delete customScreens[customScreenIndex]; + } + + auto screen = factory->create(&g_model.screenData[customScreenIndex].layoutData); + customScreens[customScreenIndex] = screen; + + if (screen) { + auto dst = g_model.screenData[customScreenIndex].LayoutId; + auto src = factory->getId(); + strncpy(dst, src, sizeof(CustomScreenData::LayoutId)); + + return screen; + } + + return nullptr; +} + +void disposeCustomScreen(unsigned idx) +{ + // move custom screen data + if (idx >= MAX_CUSTOM_SCREENS) { + return; + } + + auto dst = &g_model.screenData[idx]; + auto src = dst + 1; + auto len = sizeof(CustomScreenData) * (MAX_CUSTOM_SCREENS - idx - 1); + memmove(dst, src, len); + + dst = &g_model.screenData[MAX_CUSTOM_SCREENS - 1]; + len = sizeof(CustomScreenData); + memset(dst, 0, len); +} + void Layout::decorate() { // Check if deco setting are still up-to-date diff --git a/radio/src/gui/colorlcd/layout.h b/radio/src/gui/colorlcd/layout.h index 98239f5ec..2ec985fd2 100644 --- a/radio/src/gui/colorlcd/layout.h +++ b/radio/src/gui/colorlcd/layout.h @@ -68,6 +68,13 @@ class Layout: public LayoutBase decorate(); } +#if defined(DEBUG_WINDOWS) + std::string getName() const override + { + return "Layout"; + } +#endif + void create() override { setOptionValue(OPTION_TOPBAR, OPTION_VALUE_BOOL(true)); @@ -197,4 +204,12 @@ void loadDefaultLayout(); // intended for existing models void loadCustomScreens(); +// delete all custom screens from memory +void deleteCustomScreens(); + +Layout* createCustomScreen(const LayoutFactory* factory, unsigned customScreenIndex); + +// Remove custom screen from the model +void disposeCustomScreen(unsigned idx); + std::list & getRegisteredLayouts(); diff --git a/radio/src/gui/colorlcd/menu_screen.cpp b/radio/src/gui/colorlcd/menu_screen.cpp index 5dc29a2c8..0fe64460d 100644 --- a/radio/src/gui/colorlcd/menu_screen.cpp +++ b/radio/src/gui/colorlcd/menu_screen.cpp @@ -36,7 +36,7 @@ void ScreenMenu::updateTabs() for (int index = 0; index < MAX_CUSTOM_SCREENS; index++) { if (customScreens[index]) { - auto tab = new ScreenSetupPage(this, customScreens[index], g_model.screenData[index]); + auto tab = new ScreenSetupPage(this, getTabs(), index); std::string title(STR_MAIN_VIEW_X); title.back() = index + '1'; tab->setTitle(title); @@ -45,7 +45,7 @@ void ScreenMenu::updateTabs() addTab(tab); } else { - addTab(new ScreenAddPage(this, index)); + addTab(new ScreenAddPage(this, getTabs())); break; } } diff --git a/radio/src/gui/colorlcd/screen_setup.cpp b/radio/src/gui/colorlcd/screen_setup.cpp index 48c6e99a4..59f5e3794 100644 --- a/radio/src/gui/colorlcd/screen_setup.cpp +++ b/radio/src/gui/colorlcd/screen_setup.cpp @@ -26,72 +26,14 @@ #define SET_DIRTY() storageDirty(EE_MODEL) -ScreenUserInterfacePage::ScreenUserInterfacePage(): - PageTab(STR_USER_INTERFACE, ICON_THEME_SETUP) +class LayoutChoice: public FormField { -} - -void ScreenUserInterfacePage::build(FormWindow * window) -{ - FormGridLayout grid; - - // Theme choice - new StaticText(window, grid.getLabelSlot(), STR_THEME, 0, 0); - // TODO: Theme picklist - grid.nextLine(); - - // Theme options ? - - // Top Bar - new StaticText(window, grid.getLabelSlot(), STR_TOP_BAR, 0, 0); - // TODO: enable settings topbar widgets - grid.nextLine(); -} - -ScreenAddPage::ScreenAddPage(ScreenMenu * menu, uint8_t pageIndex): - PageTab(), - menu(menu), - pageIndex(pageIndex) -{ - setTitle(STR_ADD_MAIN_VIEW); - setIcon(ICON_THEME_ADD_VIEW); -} - -void ScreenAddPage::build(FormWindow * window) -{ - rect_t buttonRect = {LCD_W / 2 - 100, (window->height() - 24) / 2, 200, 24}; - auto button = new TextButton(window, buttonRect, STR_ADD_MAIN_VIEW); - button->setPressHandler([=]() -> uint8_t { - - auto& screen = customScreens[pageIndex]; - auto& screenData = g_model.screenData[pageIndex]; - - const LayoutFactory * factory = getRegisteredLayouts().front(); - - screen = factory->create(&screenData.layoutData); - strncpy(screenData.LayoutId, factory->getId(), sizeof(screenData.LayoutId)); - - auto tab = new ScreenSetupPage(menu, screen, screenData); - std::string title(STR_MAIN_VIEW_X); - title.back() = pageIndex + '0'; - tab->setTitle(title); - tab->setIcon(ICON_THEME_VIEW1 + pageIndex); - - menu->removeTab(pageIndex); - menu->addTab(tab); - menu->setCurrentTab(pageIndex); - - if (pageIndex < MAX_CUSTOM_SCREENS - 1) { - menu->addTab(new ScreenAddPage(menu, pageIndex + 1)); - } - storageDirty(EE_MODEL); - return 0; - }); -} - -class LayoutChoice: public FormField { public: - LayoutChoice(Window * parent, const rect_t & rect, std::function getValue, std::function setValue): + + typedef std::function LayoutFactoryGetter; + typedef std::function LayoutFactorySetter; + + LayoutChoice(Window * parent, const rect_t & rect, LayoutFactoryGetter getValue, LayoutFactorySetter setValue): FormField(parent, {rect.x, rect.y, 59, 33}), getValue(std::move(getValue)), setValue(std::move(setValue)) @@ -102,7 +44,9 @@ class LayoutChoice: public FormField { { FormField::paint(dc); auto layout = getValue(); - layout->drawThumb(dc, 4, 4, editMode ? FOCUS_COLOR : LINE_COLOR); + if (layout) { + layout->drawThumb(dc, 4, 4, editMode ? FOCUS_COLOR : LINE_COLOR); + } } #if defined(HARDWARE_KEYS) @@ -162,94 +106,91 @@ class LayoutChoice: public FormField { std::function setValue; }; -ScreenSetupPage::ScreenSetupPage(ScreenMenu * menu, Layout*& screen, CustomScreenData& screenData): - PageTab(), - menu(menu), - screen(screen), - screenData(screenData) -{ -} - class SetupWidgetsPageSlot: public Button { public: SetupWidgetsPageSlot(FormGroup * parent, const rect_t & rect, Layout* screen, uint8_t slotIndex): - Button(parent, rect), - screen(screen), - slotIndex(slotIndex) + Button(parent, rect) { - widget = screen->getWidget(slotIndex); - setPressHandler([=]() -> uint8_t { - if (widget) { - Menu * menu = new Menu(this); - menu->addLine(TR_SELECT_WIDGET, [=]() { - Menu * menu = new Menu(this); - for (auto factory: getRegisteredWidgets()) { - menu->addLine(factory->getName(), [=]() { - if (widget) widget->deleteLater(); - widget = screen->createWidget(slotIndex, factory); - }); - } - }); - menu->addLine(TR_WIDGET_SETTINGS, [=]() { - new WidgetSettings(this, widget); - }); + //auto parent = (Window*)this; + setPressHandler([parent, screen, slotIndex]() -> uint8_t { + Menu * menu = new Menu(parent); + menu->addLine(TR_SELECT_WIDGET, [=]() { + Menu * menu = new Menu(parent); + for (auto factory: getRegisteredWidgets()) { + menu->addLine(factory->getName(), [=]() { + screen->createWidget(slotIndex, factory); + }); + } + }); + + if (screen->getWidget(slotIndex)) { + menu->addLine(TR_WIDGET_SETTINGS, [=]() { + auto widget = screen->getWidget(slotIndex); + new WidgetSettings(parent, widget); + }); menu->addLine(STR_REMOVE_WIDGET, [=]() { - widget->deleteLater(); - widget = nullptr; + screen->removeWidget(slotIndex); }); - return 0; - } - else { - Menu * menu = new Menu(this); - for (auto factory: getRegisteredWidgets()) { - menu->addLine(factory->getName(), [=]() { - if (widget) widget->deleteLater(); - widget = screen->createWidget(slotIndex, factory); - }); - } } + return 0; + // } + // else { + // Menu * menu = new Menu(this); + // for (auto factory: getRegisteredWidgets()) { + // menu->addLine(factory->getName(), [=]() { + // if (widget) widget->deleteLater(); + // widget = screen->createWidget(slotIndex, factory); + // }); + // } + // } + // return 0; }); } void paint(BitmapBuffer * dc) override { if (hasFocus()) { - dc->drawSolidRect(0, 0, width(), height(), 1, DEFAULT_COLOR); - } - else { - dc->drawRect(0, 0, width(), height(), 1, DOTTED, DEFAULT_COLOR); + dc->drawRect(0, 0, width()-2, height()-2, 2, DOTTED, CHECKBOX_COLOR); } } - - protected: - Layout * screen; - uint8_t slotIndex; - Widget * widget = nullptr; }; class SetupWidgetsPage: public FormWindow { public: - SetupWidgetsPage(Layout * screen): - FormWindow(MainWindow::instance(), {0, 0, LCD_W, LCD_H}, OPAQUE | FORM_FORWARD_FOCUS), - screen(screen), - oldParent(screen->getParent()) + SetupWidgetsPage(ScreenMenu* menu, uint8_t customScreenIdx): + FormWindow(ViewMain::instance(), {0, 0, LCD_W, LCD_H}, /*OPAQUE |*/ FORM_FORWARD_FOCUS), + menu(menu), + customScreenIdx(customScreenIdx) { Layer::push(this); - clearFocus(); - // attach this custom screen here so we can display it - screen->attach(this); - + // attach this custom screen here so we can display it + auto screen = customScreens[customScreenIdx]; + if (screen) { + screen->attach(this); + setRect(screen->getRect()); + } + + ViewMain::instance()->bringToTop(); + for (unsigned i = 0; i < screen->getZonesCount(); i++) { auto rect = screen->getZone(i); - new SetupWidgetsPageSlot(this, {rect.x - 1, rect.y - 1, rect.w + 2, rect.h + 2}, screen, i); + auto widget = new SetupWidgetsPageSlot(this, rect, customScreens[customScreenIdx], i); + if (i == 0) widget->setFocus(); } } +#if defined(DEBUG_WINDOWS) + std::string getName() const override + { + return "SetupWidgetPage(idx=" + std::to_string(customScreenIdx) + ")"; + } +#endif + void deleteLater(bool detach = true, bool trash = true) override { Layer::pop(this); @@ -257,12 +198,14 @@ class SetupWidgetsPage: public FormWindow #if defined(HARDWARE_TOUCH) Keyboard::hide(); #endif - if (oldParent) { - // give it back to its old parent before it gets deleted - screen->attach(oldParent); + auto screen = customScreens[customScreenIdx]; + if (screen) { + screen->attach(ViewMain::instance()); } - FormWindow::deleteLater(detach, trash); + + // restore screen setting tab on top + menu->bringToTop(); } #if defined(HARDWARE_KEYS) @@ -279,16 +222,100 @@ class SetupWidgetsPage: public FormWindow #endif protected: - Layout* screen; - Window* oldParent; - - void paint(BitmapBuffer * dc) override - { - dc->clear(DEFAULT_BGCOLOR); - } + ScreenMenu* menu; + uint8_t customScreenIdx; + // void paint(BitmapBuffer * dc) override + // { + // //ViewMain::instance()->fullPaint(dc); + // //dc->clear(DEFAULT_BGCOLOR); + // } }; +ScreenUserInterfacePage::ScreenUserInterfacePage(): + PageTab(STR_USER_INTERFACE, ICON_THEME_SETUP) +{ +} + +void ScreenUserInterfacePage::build(FormWindow * window) +{ + FormGridLayout grid; + + // Theme choice + new StaticText(window, grid.getLabelSlot(), STR_THEME, 0, 0); + // TODO: Theme picklist + grid.nextLine(); + + // Theme options ? + + // Top Bar + new StaticText(window, grid.getLabelSlot(), STR_TOP_BAR, 0, 0); + // TODO: enable settings topbar widgets + grid.nextLine(); +} + +ScreenAddPage::ScreenAddPage(ScreenMenu * menu, uint8_t pageIndex): + PageTab(), + menu(menu), + pageIndex(pageIndex) +{ + setTitle(STR_ADD_MAIN_VIEW); + setIcon(ICON_THEME_ADD_VIEW); +} + +extern const LayoutFactory * defaultLayout; + +void ScreenAddPage::build(FormWindow * window) +{ + rect_t buttonRect = {LCD_W / 2 - 100, (window->height() - 24) / 2, 200, 24}; + auto button = new TextButton(window, buttonRect, STR_ADD_MAIN_VIEW); + + auto pageIndex = this->pageIndex; + auto menu = this->menu; + + button->setPressHandler([menu,pageIndex]() -> uint8_t { + + auto newPageIdx = menu->getTabs(); + auto newIdx = newPageIdx - 2; + + auto& screen = customScreens[newIdx]; + auto& screenData = g_model.screenData[newIdx]; + + const LayoutFactory * factory = defaultLayout; + screen = factory->create(&screenData.layoutData); + strncpy(screenData.LayoutId, factory->getId(), sizeof(screenData.LayoutId)); + + auto tab = new ScreenSetupPage(menu, newPageIdx, newIdx); + std::string title(STR_MAIN_VIEW_X); + title.back() = newIdx + '1'; + tab->setTitle(title); + tab->setIcon(ICON_THEME_VIEW1 + newIdx); + + // remove current tab first + menu->setCurrentTab(0); + menu->removeTab(pageIndex); + + // add the new one + menu->addTab(tab); + menu->setCurrentTab(newPageIdx); + + if (menu->getTabs() < MAX_CUSTOM_SCREENS) { + menu->addTab(new ScreenAddPage(menu, menu->getTabs())); + } + + storageDirty(EE_MODEL); + return 0; + }); +} + +ScreenSetupPage::ScreenSetupPage(ScreenMenu * menu, unsigned pageIndex, unsigned customScreenIndex): + PageTab(), + menu(menu), + pageIndex(pageIndex), + customScreenIndex(customScreenIndex) +{ +} + void ScreenSetupPage::build(FormWindow * window) { FormGridLayout grid; @@ -296,46 +323,95 @@ void ScreenSetupPage::build(FormWindow * window) // Layout choice... new StaticText(window, grid.getLabelSlot(false), STR_LAYOUT); + auto layoutSlot = grid.getFieldSlot(); layoutSlot.h = 2 * PAGE_LINE_HEIGHT - 1; - layoutChoice = new LayoutChoice(window, layoutSlot, GET_VALUE(screen->getFactory()), [=](const LayoutFactory *factory) { - delete screen; - screen = factory->create(&screenData.layoutData); - strncpy(screenData.LayoutId, factory->getId(), sizeof(CustomScreenData::LayoutId)); - SET_DIRTY(); - updateLayoutOptions(); - }); + + auto idx = customScreenIndex; + LayoutChoice::LayoutFactoryGetter getFactory = GET_VALUE(customScreens[idx]->getFactory()); + LayoutChoice::LayoutFactorySetter setLayout = [idx](const LayoutFactory *factory) { + createCustomScreen(factory, idx); + SET_DIRTY(); + }; + + auto layoutChoice = new LayoutChoice(window, layoutSlot, getFactory, setLayout); grid.nextLine(layoutChoice->height()); + TRACE("layoutChoice = %p", layoutChoice); // Setup widgets button... - setupWidgetsButton = new TextButton(window, grid.getFieldSlot(), STR_SETUP_WIDGETS); - setupWidgetsButton->setPressHandler([=]() -> uint8_t { - new SetupWidgetsPage(screen); + auto setupWidgetsButton = new TextButton(window, grid.getFieldSlot(), STR_SETUP_WIDGETS); + TRACE("setupWidgetsButton = %p", setupWidgetsButton); + + auto menu = this->menu; + setupWidgetsButton->setPressHandler([idx,menu]() -> uint8_t { + new SetupWidgetsPage(menu, idx); return 0; }); grid.nextLine(); // Dynamic options window... - optionsWindow = new FormGroup(window, {0, grid.getWindowHeight(), LCD_W, 0}, FORWARD_SCROLL | FORM_FORWARD_FOCUS); - grid.addWindow(optionsWindow); - updateLayoutOptions(); + // rect_t r = {0, grid.getWindowHeight(), LCD_W, 0}; + // auto optionsWindow = new FormGroup(window, r, FORWARD_SCROLL | FORM_FORWARD_FOCUS); + // grid.addWindow(optionsWindow); + // updateLayoutOptions(); + + // Prevent removing the last page + if (customScreens[1] != nullptr) { + auto button = new TextButton(window, grid.getFieldSlot(), STR_REMOVE_SCREEN); + auto menu = this->menu; + button->setPressHandler([menu,idx]() -> uint8_t { + + // Set the current tab to "User interface" to trigger body clearing + menu->setCurrentTab(0); + + // Remove this screen from the model + disposeCustomScreen(idx); + + // Delete all custom screens + deleteCustomScreens(); + + // ... and reload + loadCustomScreens(); + menu->updateTabs(); + + // Let's try to stay on the same page + // (first tab is "User interface") + auto pageIdx = idx + 1; + + // Subtract one more as the last one is "New main screen" + if (pageIdx > menu->getTabs() - 2) { + pageIdx = menu->getTabs() - 2; + } + menu->setCurrentTab(pageIdx); + + // save the changes + storageDirty(EE_MODEL); + return 0; + }); + } + + // optionsWindow->adjustHeight(); + // optionsWindow->getParent()->adjustInnerHeight(); } void ScreenSetupPage::updateLayoutOptions() { +#if 0 FormGridLayout grid; optionsWindow->clear(); // Layout options... int index = 0; - for (auto * option = screen->getFactory()->getOptions(); option->name; option++, index++) { - ZoneOptionValue * value = screen->getOptionValue(index); + auto factory = customScreen[customScreenIndex]->getFactory(); + if (factory) { + for (auto * option = factory->getOptions(); option->name; option++, index++) { + ZoneOptionValue * value = customScreens[customScreenIndex]->getOptionValue(index); - // Option label - new StaticText(optionsWindow, grid.getLabelSlot(false), option->name); + // Option label + new StaticText(optionsWindow, grid.getLabelSlot(false), option->name); - // Option value - switch (option->type) { + // Option value + switch (option->type) { case ZoneOption::Bool: new CheckBox(optionsWindow, grid.getFieldSlot(), GET_SET_DEFAULT(value->boolValue)); break; @@ -346,25 +422,10 @@ void ScreenSetupPage::updateLayoutOptions() default: break; + } + grid.nextLine(); } - grid.nextLine(); } - //if (pageIndex > 0 || customScreens[1]) { - auto button = new TextButton(optionsWindow, grid.getFieldSlot(), STR_REMOVE_SCREEN); - button->setPressHandler([=]() -> uint8_t { - // if (pageIndex < MAX_CUSTOM_SCREENS - 1) { - // memmove(&g_model.screenData[pageIndex], &g_model.screenData[pageIndex + 1], sizeof(CustomScreenData) * (MAX_CUSTOM_SCREENS - pageIndex - 1)); - // } - // memset(&g_model.screenData[MAX_CUSTOM_SCREENS - 1], 0, sizeof(CustomScreenData)); - memset(&screenData, 0, sizeof(CustomScreenData)); - loadCustomScreens(); - menu->updateTabs(); - storageDirty(EE_MODEL); - return 0; - }); - //} - - optionsWindow->adjustHeight(); - optionsWindow->getParent()->adjustInnerHeight(); +#endif } diff --git a/radio/src/gui/colorlcd/screen_setup.h b/radio/src/gui/colorlcd/screen_setup.h index a17f714cc..2d8614672 100644 --- a/radio/src/gui/colorlcd/screen_setup.h +++ b/radio/src/gui/colorlcd/screen_setup.h @@ -44,17 +44,19 @@ class ScreenAddPage: public PageTab { class ScreenSetupPage: public PageTab { public: - ScreenSetupPage(ScreenMenu * menu, Layout*& screen, CustomScreenData& screenData); + ScreenSetupPage(ScreenMenu * menu, unsigned pageIndex, unsigned customScreenIndex); void build(FormWindow * window) override; protected: ScreenMenu * menu; - Layout *& screen; - CustomScreenData& screenData; - FormGroup * optionsWindow = nullptr; - TextButton * setupWidgetsButton = nullptr; - FormField * layoutChoice = nullptr; + unsigned pageIndex; + unsigned customScreenIndex; + + // FormGroup * optionsWindow = nullptr; + // TextButton * setupWidgetsButton = nullptr; + // FormField * layoutChoice = nullptr; void updateLayoutOptions(); + //void disposeCustomScreen(); }; diff --git a/radio/src/gui/colorlcd/tabsgroup.cpp b/radio/src/gui/colorlcd/tabsgroup.cpp index e4e29e7ea..66f73c98c 100644 --- a/radio/src/gui/colorlcd/tabsgroup.cpp +++ b/radio/src/gui/colorlcd/tabsgroup.cpp @@ -94,6 +94,19 @@ void TabsGroup::addTab(PageTab * page) setCurrentTab(0); } header.carousel.updateInnerWidth(); + invalidate(); +} + +int TabsGroup::removeTab(PageTab * page) +{ + auto tabIter = std::find(tabs.begin(), tabs.end(), page); + if (tabIter != tabs.end()) { + auto idx = tabIter - tabs.begin(); + removeTab(idx); + return idx; + } + + return -1; } void TabsGroup::removeTab(unsigned index) @@ -103,6 +116,7 @@ void TabsGroup::removeTab(unsigned index) } tabs.erase(tabs.begin() + index); header.carousel.updateInnerWidth(); + invalidate(); } void TabsGroup::removeAllTabs() @@ -132,6 +146,11 @@ void TabsGroup::setVisibleTab(PageTab * tab) } } +// TODO: add a mechanism to trigger a rebuild of a PageTab +// -> rebuild(): +// - as in setVisibleTab() (clear & build) +// - but without changing tab + void TabsGroup::checkEvents() { Window::checkEvents(); diff --git a/radio/src/gui/colorlcd/tabsgroup.h b/radio/src/gui/colorlcd/tabsgroup.h index ba49076de..a985c111d 100644 --- a/radio/src/gui/colorlcd/tabsgroup.h +++ b/radio/src/gui/colorlcd/tabsgroup.h @@ -193,8 +193,17 @@ class TabsGroup: public Window } #endif + unsigned getTabs() const + { + return tabs.size(); + } + void addTab(PageTab * page); + // Return the index of the found tab + // or -1 if the tab could not be found + int removeTab(PageTab * page); + void removeTab(unsigned index); void removeAllTabs(); @@ -206,7 +215,7 @@ class TabsGroup: public Window setVisibleTab(tabs[index]); } } - + void checkEvents() override; #if defined(HARDWARE_KEYS) diff --git a/radio/src/gui/colorlcd/topbar.h b/radio/src/gui/colorlcd/topbar.h index 34aac2b69..404b0aaac 100644 --- a/radio/src/gui/colorlcd/topbar.h +++ b/radio/src/gui/colorlcd/topbar.h @@ -34,6 +34,13 @@ class TopBar: public WidgetsContainer public: explicit TopBar(Window * parent); +#if defined(DEBUG_WINDOWS) + std::string getName() const override + { + return "TopBar"; + } +#endif + unsigned int getZonesCount() const override; rect_t getZone(unsigned int index) const override; diff --git a/radio/src/gui/colorlcd/view_main.h b/radio/src/gui/colorlcd/view_main.h index ee2b0915c..1cd241dcf 100644 --- a/radio/src/gui/colorlcd/view_main.h +++ b/radio/src/gui/colorlcd/view_main.h @@ -25,6 +25,7 @@ #include class TopBar; +class SetupWidgetsPage; class ViewMain: public FormWindow { @@ -88,6 +89,8 @@ class ViewMain: public FormWindow Window* sliders[SLIDERS_MAX]; Window* trims[TRIMS_MAX]; Window* flightMode; + + friend class SetupWidgetsPage; #if defined(HARDWARE_KEYS) void onEvent(event_t event) override; diff --git a/radio/src/gui/colorlcd/widgets_container.h b/radio/src/gui/colorlcd/widgets_container.h index 3ef16b8c6..c46151fe1 100644 --- a/radio/src/gui/colorlcd/widgets_container.h +++ b/radio/src/gui/colorlcd/widgets_container.h @@ -58,17 +58,38 @@ class WidgetsContainer: public FormGroup, public WidgetsContainerInterface Widget * createWidget(unsigned int index, const WidgetFactory * factory) override { + if (index >= N) + return nullptr; + + // remove old one if existing + removeWidget(index); + Widget * widget = nullptr; - memset(persistentData->zones[index].widgetName, 0, sizeof(persistentData->zones[index].widgetName)); if (factory) { - strncpy(persistentData->zones[index].widgetName, factory->getName(), sizeof(persistentData->zones[index].widgetName)); + strncpy(persistentData->zones[index].widgetName, factory->getName(), sizeof(ZonePersistentData::widgetName)); widget = factory->create(this, getZone(index), &persistentData->zones[index].widgetData); } widgets[index] = widget; + if (widget) + widget->attach(this); + return widget; } + void removeWidget(unsigned int index) + { + if (index >= N) + return; + + if (widgets[index]) + widgets[index]->deleteLater(); + + widgets[index] = nullptr; + memset(persistentData->zones[index].widgetName, 0, sizeof(ZonePersistentData::widgetName)); + memset(&persistentData->zones[index].widgetData, 0, sizeof(Widget::PersistentData)); + } + Widget * getWidget(unsigned int index) override { if (index < N)