This commit is contained in:
Raphael Coeffic
2021-04-18 07:57:41 +02:00
parent 99018ce726
commit bf144290f3
10 changed files with 376 additions and 183 deletions
+58 -2
View File
@@ -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
+15
View File
@@ -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<const LayoutFactory *> & getRegisteredLayouts();
+2 -2
View File
@@ -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;
}
}
+231 -170
View File
@@ -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<const LayoutFactory *()> getValue, std::function<void(const LayoutFactory *)> setValue):
typedef std::function<const LayoutFactory *()> LayoutFactoryGetter;
typedef std::function<void(const LayoutFactory *)> 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<void(const LayoutFactory *)> 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
}
+8 -6
View File
@@ -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();
};
+19
View File
@@ -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();
+10 -1
View File
@@ -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)
+7
View File
@@ -34,6 +34,13 @@ class TopBar: public WidgetsContainer<MAX_TOPBAR_ZONES, MAX_TOPBAR_OPTIONS>
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;
+3
View File
@@ -25,6 +25,7 @@
#include <memory>
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;
+23 -2
View File
@@ -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)