Horus : improve add widgets (#5189)
[opentx.git] / radio / src / gui / 480x272 / screens_setup.cpp
blobe841ee7fef4c31580944b1741066150dd97028ab
1 /*
2 * Copyright (C) OpenTX
4 * Based on code named
5 * th9x - http://code.google.com/p/th9x
6 * er9x - http://code.google.com/p/er9x
7 * gruvin9x - http://code.google.com/p/gruvin9x
9 * License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License version 2 as
13 * published by the Free Software Foundation.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
21 #include "opentx.h"
23 uint8_t THEME_ICONS[] = {
24 ICON_THEME,
25 ICON_THEME_SETUP,
26 ICON_THEME_VIEW1,
27 ICON_THEME_VIEW2,
28 ICON_THEME_VIEW3,
29 ICON_THEME_VIEW4,
30 ICON_THEME_VIEW5,
31 ICON_THEME_ADD_VIEW,
34 Layout * currentScreen;
35 WidgetsContainerInterface * currentContainer;
36 Widget * currentWidget;
37 uint8_t currentZone;
38 bool widgetNeedsSettings;
40 #define SCREENS_SETUP_2ND_COLUMN 200
42 char fileSelection[LEN_ZONE_OPTION_STRING];
43 uint8_t fileSelectionDone;
45 int updateMainviewsMenu();
46 bool menuScreenAdd(event_t event);
47 void onScreenSetupMenu(const char * result);
49 void onZoneOptionFileSelectionMenu(const char * result)
51 if (result == STR_UPDATE_LIST) {
52 if (!sdListFiles(BITMAPS_PATH, BITMAPS_EXT, LEN_ZONE_OPTION_STRING, NULL)) {
53 POPUP_WARNING(STR_NO_BITMAPS_ON_SD);
56 else {
57 fileSelectionDone = true;
58 memcpy(fileSelection, result, sizeof(fileSelection));
62 uint8_t getZoneOptionColumns(const ZoneOption * option)
64 if (option->type == ZoneOption::Color) {
65 return uint8_t(2 | NAVIGATION_LINE_BY_LINE);
67 else {
68 return 0;
72 uint8_t editColorPart(coord_t x, coord_t y, event_t event, uint8_t part, uint8_t value, LcdFlags attr, uint32_t i_flags)
74 const char * STR_COLOR_PARTS = "\002" "R:" "G:" "B:";
75 uint8_t PART_BITS[] = { 5, 6, 5 };
76 lcdDrawTextAtIndex(x, y, STR_COLOR_PARTS, part, (attr && menuHorizontalPosition < 0) ? TEXT_INVERTED_COLOR : TEXT_COLOR);
77 lcdDrawNumber(x + 20, y, value << (8-PART_BITS[part]), LEFT|TEXT_COLOR|((attr && (menuHorizontalPosition < 0 || menuHorizontalPosition == part)) ? attr : TEXT_COLOR));
78 if (attr && menuHorizontalPosition == part) {
79 value = checkIncDec(event, value, 0, (1 << PART_BITS[part])-1, i_flags);
81 return value;
84 bool editZoneOption(coord_t y, const ZoneOption * option, ZoneOptionValue * value, LcdFlags attr, uint32_t i_flags, event_t event)
86 lcdDrawText(MENUS_MARGIN_LEFT, y, option->name);
88 if (option->type == ZoneOption::Bool) {
89 value->boolValue = editCheckBox(value->boolValue, SCREENS_SETUP_2ND_COLUMN, y, attr, event); // TODO always does storageDirty(EE_MODEL)
91 else if (option->type == ZoneOption::Integer) {
92 lcdDrawNumber(SCREENS_SETUP_2ND_COLUMN, y, value->signedValue, attr | LEFT);
93 if (attr) {
94 CHECK_INCDEC_MODELVAR(event, value->signedValue, option->min.signedValue, option->max.signedValue); // TODO i_flags
97 else if (option->type == ZoneOption::String) {
98 editName(SCREENS_SETUP_2ND_COLUMN, y, value->stringValue, sizeof(value->stringValue), event, attr); // TODO i_flags?
100 else if (option->type == ZoneOption::File) {
101 if (ZEXIST(value->stringValue))
102 lcdDrawSizedText(SCREENS_SETUP_2ND_COLUMN, y, value->stringValue, sizeof(value->stringValue), attr);
103 else
104 lcdDrawTextAtIndex(SCREENS_SETUP_2ND_COLUMN, y, STR_VCSWFUNC, 0, attr); // TODO define
105 if (attr) {
106 if (event==EVT_KEY_FIRST(KEY_ENTER)) {
107 s_editMode = 0;
108 if (sdListFiles(BITMAPS_PATH, BITMAPS_EXT, sizeof(value->stringValue), value->stringValue, LIST_NONE_SD_FILE)) {
109 fileSelectionDone = false;
110 POPUP_MENU_START(onZoneOptionFileSelectionMenu);
112 else {
113 POPUP_WARNING(STR_NO_BITMAPS_ON_SD);
116 else if (fileSelectionDone) {
117 memcpy(value->stringValue, fileSelection, sizeof(fileSelection));
118 fileSelectionDone = false;
119 storageDirty(i_flags);
123 else if (option->type == ZoneOption::TextSize) {
124 lcdDrawTextAtIndex(SCREENS_SETUP_2ND_COLUMN, y, "\010StandardTiny\0 Small\0 Mid\0 Double", value->unsignedValue, attr);
125 if (attr) {
126 value->unsignedValue = checkIncDec(event, value->unsignedValue, 0, 4, i_flags);
129 else if (option->type == ZoneOption::Timer) {
130 drawStringWithIndex(SCREENS_SETUP_2ND_COLUMN, y, STR_TIMER, value->unsignedValue + 1, attr);
131 if (attr) {
132 value->unsignedValue = checkIncDec(event, value->unsignedValue, 0, MAX_TIMERS - 1, i_flags);
135 else if (option->type == ZoneOption::Source) {
136 drawSource(SCREENS_SETUP_2ND_COLUMN, y, value->unsignedValue, attr);
137 if (attr) {
138 CHECK_INCDEC_MODELSOURCE(event, value->unsignedValue, 1, MIXSRC_LAST_TELEM);
141 else if (option->type == ZoneOption::Color) {
142 RGB_SPLIT(value->unsignedValue, r, g, b);
144 if (attr && menuHorizontalPosition < 0) {
145 lcdDrawSolidFilledRect(SCREENS_SETUP_2ND_COLUMN-3, y-1, 230, FH+1, TEXT_INVERTED_BGCOLOR);
148 lcdSetColor(value->unsignedValue);
149 lcdDrawSolidFilledRect(SCREENS_SETUP_2ND_COLUMN-1, y+1, 42, 17, TEXT_COLOR);
150 lcdDrawSolidFilledRect(SCREENS_SETUP_2ND_COLUMN, y+2, 40, 15, CUSTOM_COLOR);
152 r = editColorPart(SCREENS_SETUP_2ND_COLUMN + 50, y, event, 0, r, attr, i_flags);
153 g = editColorPart(SCREENS_SETUP_2ND_COLUMN + 110, y, event, 1, g, attr, i_flags);
154 b = editColorPart(SCREENS_SETUP_2ND_COLUMN + 170, y, event, 2, b, attr, i_flags);
156 if (attr && checkIncDec_Ret) {
157 value->unsignedValue = RGB_JOIN(r, g, b);
161 return (attr && checkIncDec_Ret);
164 int getOptionsCount(const ZoneOption * options)
166 if (options == NULL) {
167 return 0;
169 else {
170 int count = 0;
171 for (const ZoneOption * option = options; option->name; option++) {
172 count++;
174 return count;
178 template <class T>
179 bool menuSettings(const char * title, T * object, uint32_t i_flags, event_t event)
182 if (object->getErrorMessage()) {
183 // display error instead of widget settings
184 // TODO nicer display (proper word-wrap)
185 SIMPLE_SUBMENU("Widget Error", ICON_MODEL_LUA_SCRIPTS, 1);
186 int len = strlen(object->getErrorMessage());
187 int y = 3*FH;
188 const char * p = object->getErrorMessage();
189 while (len > 0) {
190 lcdDrawSizedText(MENUS_MARGIN_LEFT, y, p, 30);
191 p += 30;
192 y += FH;
193 len -= 30;
195 return true;
198 const ZoneOption * options = object->getOptions();
199 linesCount = getOptionsCount(options);
200 uint8_t mstate_tab[MAX_WIDGET_OPTIONS];
201 for (int i=0; i<linesCount; i++) {
202 mstate_tab[i] = getZoneOptionColumns(&options[i]);
205 CUSTOM_SUBMENU_WITH_OPTIONS(title, ICON_THEME, linesCount, OPTION_MENU_TITLE_BAR);
207 for (int i=0; i<NUM_BODY_LINES+1; i++) {
208 coord_t y = MENU_CONTENT_TOP + i * FH;
209 int k = i + menuVerticalOffset;
210 LcdFlags blink = ((s_editMode>0) ? BLINK|INVERS : INVERS);
211 LcdFlags attr = (menuVerticalPosition == k ? blink : 0);
212 if (k < linesCount) {
213 const ZoneOption * option = &options[k];
214 ZoneOptionValue * value = object->getOptionValue(k);
215 if (editZoneOption(y, option, value, attr, i_flags, event)) {
216 object->update();
221 return true;
224 bool menuWidgetSettings(event_t event)
226 return menuSettings<Widget>(STR_WIDGET_SETTINGS, currentWidget, EE_MODEL, event);
229 bool menuWidgetChoice(event_t event)
231 static Widget * previousWidget = NULL;
232 static Widget * currentWidget = NULL;
233 static std::list<const WidgetFactory *>::const_iterator iterator;
234 static Widget::PersistentData tempData;
236 switch (event) {
237 case EVT_ENTRY:
239 previousWidget = currentContainer->getWidget(currentZone);
240 currentContainer->setWidget(currentZone, NULL);
241 iterator = getRegisteredWidgets().cbegin();
242 if (previousWidget) {
243 const WidgetFactory * factory = previousWidget->getFactory();
244 std::list<const WidgetFactory *>::const_iterator it = getRegisteredWidgets().cbegin();
245 for (; it != getRegisteredWidgets().cend(); ++it) {
246 if (factory->getName() == (*it)->getName()) {
247 iterator = it;
248 break;
252 if (iterator != getRegisteredWidgets().cend())
253 currentWidget = (*iterator)->create(currentContainer->getZone(currentZone), &tempData);
254 break;
257 case EVT_KEY_FIRST(KEY_EXIT):
258 if (previousWidget) {
259 if (currentWidget)
260 delete currentWidget;
261 currentContainer->setWidget(currentZone, previousWidget);
263 popMenu();
264 return false;
266 case EVT_KEY_FIRST(KEY_ENTER):
267 if (iterator != getRegisteredWidgets().cend()) {
268 if (previousWidget)
269 delete previousWidget;
270 currentContainer->createWidget(currentZone, *iterator);
271 widgetNeedsSettings = currentContainer->getWidget(currentZone)->getFactory()->getOptions();
272 storageDirty(EE_MODEL);
274 popMenu();
275 return false;
277 case EVT_ROTARY_RIGHT:
278 if (iterator != getRegisteredWidgets().cend() && iterator != --getRegisteredWidgets().cend()) {
279 ++iterator;
280 if (currentWidget)
281 delete currentWidget;
282 currentWidget = (*iterator)->create(currentContainer->getZone(currentZone), &tempData);
284 break;
286 case EVT_ROTARY_LEFT:
287 if (iterator != getRegisteredWidgets().cbegin()) {
288 --iterator;
289 if (currentWidget)
290 delete currentWidget;
291 currentWidget = (*iterator)->create(currentContainer->getZone(currentZone), &tempData);
293 break;
296 currentScreen->refresh();
298 Zone zone = currentContainer->getZone(currentZone);
299 lcdDrawFilledRect(0, 0, zone.x-2, LCD_H, SOLID, OVERLAY_COLOR | (8<<24));
300 lcdDrawFilledRect(zone.x+zone.w+2, 0, LCD_W-zone.x-zone.w-2, LCD_H, SOLID, OVERLAY_COLOR | (8<<24));
301 lcdDrawFilledRect(zone.x-2, 0, zone.w+4, zone.y-2, SOLID, OVERLAY_COLOR | (8<<24));
302 lcdDrawFilledRect(zone.x-2, zone.y+zone.h+2, zone.w+4, LCD_H-zone.y-zone.h-2, SOLID, OVERLAY_COLOR | (8<<24));
304 if (currentWidget)
305 currentWidget->refresh();
307 if (iterator != getRegisteredWidgets().cbegin()) {
308 lcdDrawBitmapPattern(zone.x-10, zone.y+zone.h/2-10, LBM_SWIPE_CIRCLE, TEXT_INVERTED_BGCOLOR);
309 lcdDrawBitmapPattern(zone.x-10, zone.y+zone.h/2-10, LBM_SWIPE_LEFT, TEXT_INVERTED_COLOR);
311 if (iterator != --getRegisteredWidgets().cend()) {
312 lcdDrawBitmapPattern(zone.x+zone.w-9, zone.y+zone.h/2-10, LBM_SWIPE_CIRCLE, TEXT_INVERTED_BGCOLOR);
313 lcdDrawBitmapPattern(zone.x+zone.w-9, zone.y+zone.h/2-10, LBM_SWIPE_RIGHT, TEXT_INVERTED_COLOR);
315 if (currentWidget)
316 lcdDrawText(zone.x + zone.w, zone.y-1, currentWidget->getFactory()->getName(), RIGHT | TEXT_COLOR | SMLSIZE | INVERS);
318 return true;
321 void onZoneMenu(const char * result)
323 if (result == STR_SELECT_WIDGET) {
324 pushMenu(menuWidgetChoice);
326 else if (result == STR_WIDGET_SETTINGS) {
327 pushMenu(menuWidgetSettings);
329 else if (result == STR_REMOVE_WIDGET) {
330 currentContainer->createWidget(currentZone, NULL);
331 storageDirty(EE_MODEL);
335 bool menuWidgetsSetup(event_t event)
337 switch (event) {
338 case EVT_ENTRY:
339 menuVerticalPosition = 0;
340 break;
341 case EVT_KEY_FIRST(KEY_EXIT):
342 killEvents(KEY_EXIT);
343 popMenu();
344 return false;
347 currentScreen->refresh();
349 for (int i=currentContainer->getZonesCount()-1; i>=0; i--) {
350 Zone zone = currentContainer->getZone(i);
351 LcdFlags color;
352 int padding, thickness;
353 if (currentContainer == topbar) {
354 color = MENU_TITLE_COLOR;
355 padding = 2;
356 thickness = 1;
358 else {
359 color = TEXT_INVERTED_BGCOLOR;
360 padding = 4;
361 thickness = 2;
363 if (menuVerticalPosition == i) {
364 lcdDrawSolidRect(zone.x-padding, zone.y-padding, zone.w+2*padding, zone.h+2*padding, thickness, color);
365 if (event == EVT_KEY_FIRST(KEY_ENTER)) {
366 killEvents(KEY_ENTER);
367 currentZone = menuVerticalPosition;
368 currentWidget = currentContainer->getWidget(menuVerticalPosition);
369 if (currentWidget) {
370 POPUP_MENU_ADD_ITEM(STR_SELECT_WIDGET);
371 if (currentWidget->getFactory()->getOptions())
372 POPUP_MENU_ADD_ITEM(STR_WIDGET_SETTINGS);
373 POPUP_MENU_ADD_ITEM(STR_REMOVE_WIDGET);
374 POPUP_MENU_START(onZoneMenu);
376 else {
377 onZoneMenu(STR_SELECT_WIDGET);
381 else {
382 if (widgetNeedsSettings) {
383 currentWidget = currentContainer->getWidget(menuVerticalPosition);
384 if (currentWidget) {
385 widgetNeedsSettings = false;
386 onZoneMenu(STR_WIDGET_SETTINGS);
389 lcdDrawRect(zone.x-padding, zone.y-padding, zone.w+2*padding, zone.h+2*padding, thickness, 0x3F, color);
392 navigate(event, currentContainer->getZonesCount(), currentContainer->getZonesCount(), 1);
393 return true;
396 template <class T>
397 T * editThemeChoice(coord_t x, coord_t y, std::list<T *> & elList, T * current, bool needsOffsetCheck, LcdFlags attr, event_t event)
399 static uint8_t menuHorizontalOffset = 0;
400 uint8_t elCount = elList.size(), last, idx;
401 coord_t pos;
402 int currentIndex = 0;
403 typename std::list<T *>::const_iterator elItr = elList.cbegin();
405 if (!elCount)
406 return NULL;
408 for (; elItr != elList.cend(); ++elItr, ++currentIndex) {
409 if ((*elItr) == current)
410 break;
413 if (event == EVT_ENTRY) {
414 menuHorizontalOffset = 0;
415 needsOffsetCheck = true;
418 if (needsOffsetCheck) {
419 if (currentIndex < menuHorizontalOffset) {
420 menuHorizontalOffset = currentIndex;
422 else if (currentIndex > menuHorizontalOffset + 3) {
423 menuHorizontalOffset = currentIndex - 3;
426 if (attr) {
427 if (menuHorizontalPosition < 0) {
428 lcdDrawSolidFilledRect(x-3, y-1, min<uint8_t>(4, elCount)*56+1, 2*FH-5, TEXT_INVERTED_BGCOLOR);
430 else {
431 if (needsOffsetCheck) {
432 menuHorizontalPosition = currentIndex;
434 else if (menuHorizontalPosition < menuHorizontalOffset) {
435 menuHorizontalOffset = menuHorizontalPosition;
437 else if (menuHorizontalPosition > menuHorizontalOffset + 3) {
438 menuHorizontalOffset = menuHorizontalPosition - 3;
442 last = min<uint8_t>(menuHorizontalOffset + 4, elCount);
443 idx = menuHorizontalOffset;
444 pos = x;
445 elItr = elList.cbegin();
446 std::advance(elItr, min<uint8_t>(menuHorizontalOffset, elCount - 1));
447 for (; idx < last && elItr != elList.cend(); ++idx, ++elItr, pos += 56) {
448 (*elItr)->drawThumb(pos, y+1, current == (*elItr) ? ((attr && menuHorizontalPosition < 0) ? TEXT_INVERTED_COLOR : TEXT_INVERTED_BGCOLOR) : LINE_COLOR);
450 if (elCount > 4) {
451 lcdDrawBitmapPattern(x - 12, y+1, LBM_CARROUSSEL_LEFT, menuHorizontalOffset > 0 ? LINE_COLOR : CURVE_AXIS_COLOR);
452 lcdDrawBitmapPattern(x + 4 * 56, y+1, LBM_CARROUSSEL_RIGHT, last < getRegisteredLayouts().size() ? LINE_COLOR : CURVE_AXIS_COLOR);
454 if (attr && menuHorizontalPosition >= 0) {
455 lcdDrawSolidRect(x + (menuHorizontalPosition - menuHorizontalOffset) * 56 - 3, y - 1, 57, 35, 1, TEXT_INVERTED_BGCOLOR);
456 if (event == EVT_KEY_FIRST(KEY_ENTER)) {
457 s_editMode = 0;
458 elItr = elList.cbegin();
459 if (menuHorizontalPosition < (int)elList.size())
460 std::advance(elItr, menuHorizontalPosition);
461 if (elItr != elList.cend())
462 return (*elItr);
463 else
464 return NULL;
467 return NULL;
470 enum menuScreensThemeItems {
471 ITEM_SCREEN_SETUP_THEME,
472 ITEM_SCREEN_SETUP_THEME_OPTION1 = ITEM_SCREEN_SETUP_THEME+2
475 bool menuScreensTheme(event_t event)
477 bool needsOffsetCheck = (menuVerticalPosition != 0 || menuHorizontalPosition < 0);
478 const ZoneOption * options = theme->getOptions();
479 int optionsCount = getOptionsCount(options);
480 linesCount = ITEM_SCREEN_SETUP_THEME_OPTION1 + optionsCount + 1;
482 menuPageCount = updateMainviewsMenu();
483 uint8_t mstate_tab[2 + MAX_THEME_OPTIONS + 1] = { uint8_t(NAVIGATION_LINE_BY_LINE | uint8_t(getRegisteredThemes().size()-1)), ORPHAN_ROW };
484 for (int i=0; i<optionsCount; i++) {
485 mstate_tab[2+i] = getZoneOptionColumns(&options[i]);
487 mstate_tab[2+optionsCount] = 0; // The button for the Topbar setup
488 CUSTOM_MENU_WITH_OPTIONS(STR_USER_INTERFACE, THEME_ICONS, menuTabScreensSetup, menuPageCount, 0, linesCount);
490 for (int i=0; i<NUM_BODY_LINES; i++) {
491 coord_t y = MENU_CONTENT_TOP + i * FH;
492 int k = i + menuVerticalOffset;
493 LcdFlags blink = ((s_editMode > 0) ? BLINK | INVERS : INVERS);
494 LcdFlags attr = (menuVerticalPosition == k ? blink : 0);
495 switch (k) {
496 case ITEM_SCREEN_SETUP_THEME: {
497 lcdDrawText(MENUS_MARGIN_LEFT, y + FH / 2, STR_THEME);
498 Theme * new_theme = editThemeChoice<Theme>(SCREENS_SETUP_2ND_COLUMN, y, getRegisteredThemes(), theme, needsOffsetCheck, attr, event);
499 if (new_theme) {
500 new_theme->init();
501 loadTheme(new_theme);
502 strncpy(g_eeGeneral.themeName, new_theme->getName(), sizeof(g_eeGeneral.themeName));
503 killEvents(KEY_ENTER);
504 storageDirty(EE_GENERAL);
506 break;
509 case ITEM_SCREEN_SETUP_THEME+1:
510 break;
512 default:
514 uint8_t index = k - ITEM_SCREEN_SETUP_THEME_OPTION1;
515 if (index < optionsCount) {
516 const ZoneOption * option = &options[index];
517 ZoneOptionValue * value = theme->getOptionValue(index);
518 if (editZoneOption(y, option, value, attr, EE_GENERAL, event)) {
519 theme->update();
522 else if (index == optionsCount) {
523 lcdDrawText(MENUS_MARGIN_LEFT, y, STR_TOP_BAR);
524 drawButton(SCREENS_SETUP_2ND_COLUMN, y, STR_SETUP, attr);
525 if (attr && event == EVT_KEY_FIRST(KEY_ENTER)) {
526 currentScreen = customScreens[0];
527 currentContainer = topbar;
528 pushMenu(menuWidgetsSetup);
531 break;
536 return true;
539 enum MenuScreenSetupItems {
540 ITEM_SCREEN_SETUP_LAYOUT,
541 ITEM_SCREEN_SETUP_WIDGETS_SETUP = ITEM_SCREEN_SETUP_LAYOUT+2,
542 ITEM_SCREEN_SETUP_LAYOUT_OPTION1,
545 bool menuScreenSetup(int index, event_t event)
547 if (customScreens[index] == NULL) {
548 return menuScreenAdd(event);
551 currentScreen = customScreens[index];
552 currentContainer = currentScreen;
553 bool needsOffsetCheck = (menuVerticalPosition != 0 || menuHorizontalPosition < 0);
555 char title[] = "Main view X";
556 title[sizeof(title)-2] = '1' + index;
557 menuPageCount = updateMainviewsMenu();
559 const ZoneOption * options = currentScreen->getFactory()->getOptions();
560 int optionsCount = getOptionsCount(options);
561 linesCount = ITEM_SCREEN_SETUP_LAYOUT_OPTION1 + optionsCount;
562 if (menuPageCount > 3)
563 ++linesCount;
565 uint8_t mstate_tab[2 + MAX_LAYOUT_OPTIONS + 1] = { uint8_t(NAVIGATION_LINE_BY_LINE | uint8_t(getRegisteredLayouts().size()-1)), ORPHAN_ROW };
566 for (int i=0; i<optionsCount; i++) {
567 mstate_tab[3+i] = getZoneOptionColumns(&options[i]);
569 mstate_tab[3+optionsCount] = 0; // The remove button
571 CUSTOM_MENU_WITH_OPTIONS(title, THEME_ICONS, menuTabScreensSetup, menuPageCount, index+1, linesCount);
573 for (int i=0; i<NUM_BODY_LINES; i++) {
574 coord_t y = MENU_CONTENT_TOP + i * FH;
575 int k = i + menuVerticalOffset;
576 LcdFlags blink = ((s_editMode>0) ? BLINK|INVERS : INVERS);
577 LcdFlags attr = (menuVerticalPosition == k ? blink : 0);
578 switch(k) {
579 case ITEM_SCREEN_SETUP_LAYOUT:
581 lcdDrawText(MENUS_MARGIN_LEFT, y + FH / 2, STR_LAYOUT);
582 const LayoutFactory * factory = editThemeChoice<const LayoutFactory>(SCREENS_SETUP_2ND_COLUMN, y, getRegisteredLayouts(), currentScreen->getFactory(), needsOffsetCheck, attr, event);
583 if (factory) {
584 delete customScreens[index];
585 currentScreen = customScreens[index] = factory->create(&g_model.screenData[index].layoutData);
586 strncpy(g_model.screenData[index].layoutName, factory->getName(), sizeof(g_model.screenData[index].layoutName));
587 killEvents(KEY_ENTER);
588 storageDirty(EE_MODEL);
590 break;
593 case ITEM_SCREEN_SETUP_LAYOUT+1:
594 break;
596 case ITEM_SCREEN_SETUP_WIDGETS_SETUP:
597 drawButton(SCREENS_SETUP_2ND_COLUMN, y, STR_SETUP_WIDGETS, attr);
598 if (attr && event == EVT_KEY_FIRST(KEY_ENTER)) {
599 pushMenu(menuWidgetsSetup);
601 break;
603 default:
605 uint8_t o = k - ITEM_SCREEN_SETUP_LAYOUT_OPTION1;
606 if (o < optionsCount) {
607 const ZoneOption * option = &options[o];
608 ZoneOptionValue * value = currentScreen->getOptionValue(o);
609 if (editZoneOption(y, option, value, attr, EE_MODEL, event)) {
610 currentScreen->update();
613 else if (menuPageCount > 3 && o == optionsCount) {
614 drawButton(SCREENS_SETUP_2ND_COLUMN, y, STR_REMOVE_SCREEN, attr);
615 if (attr && event == EVT_KEY_LONG(KEY_ENTER)) {
616 delete currentScreen;
617 if (index != MAX_CUSTOM_SCREENS-1) {
618 memmove(&g_model.screenData[index], &g_model.screenData[index + 1], sizeof(CustomScreenData) * (MAX_CUSTOM_SCREENS - index - 1));
619 memmove(&customScreens[index], &customScreens[index + 1], sizeof(Layout *) * (MAX_CUSTOM_SCREENS - index - 1));
621 memset(&g_model.screenData[MAX_CUSTOM_SCREENS-1], 0, sizeof(CustomScreenData));
622 customScreens[MAX_CUSTOM_SCREENS-1] = NULL;
623 loadCustomScreens();
624 killEvents(KEY_ENTER);
625 chainMenu(menuTabScreensSetup[index > 0 ? index : 1]);
626 return false;
629 break;
634 return true;
637 template<int N>
638 bool menuCustomScreenSetup(event_t event)
640 return menuScreenSetup(N, event);
643 const MenuHandlerFunc menuTabScreensSetup[1+MAX_CUSTOM_SCREENS] = {
644 menuScreensTheme,
645 menuCustomScreenSetup<0>,
646 menuCustomScreenSetup<1>,
647 menuCustomScreenSetup<2>,
648 menuCustomScreenSetup<3>,
649 menuCustomScreenSetup<4>
652 int updateMainviewsMenu()
654 for (int index=1; index<MAX_CUSTOM_SCREENS; index++) {
655 if (customScreens[index]) {
656 THEME_ICONS[2+index] = ICON_THEME_VIEW1+index;
658 else {
659 THEME_ICONS[2+index] = ICON_THEME_ADD_VIEW;
660 return 2+index;
663 return 1+MAX_CUSTOM_SCREENS;
666 bool menuScreenAdd(event_t event)
668 menuPageCount = updateMainviewsMenu();
670 if (event == EVT_KEY_FIRST(KEY_ENTER) && getRegisteredLayouts().size()) {
671 const LayoutFactory * lf = getRegisteredLayouts().front();
672 customScreens[menuPageCount-2] = lf->create(&g_model.screenData[menuPageCount-2].layoutData);
673 strncpy(g_model.screenData[menuPageCount-2].layoutName, lf->getName(), sizeof(g_model.screenData[menuPageCount-2].layoutName));
674 s_editMode = 0;
675 menuHorizontalPosition = -1;
676 killEvents(KEY_ENTER);
677 storageDirty(EE_MODEL);
678 return false;
681 SIMPLE_MENU_WITH_OPTIONS(STR_ADDMAINVIEW, THEME_ICONS, menuTabScreensSetup, menuPageCount, menuPageCount-1, 0);
682 return true;