Skip to content

Commit 9ff9bee

Browse files
author
dave
committed
#182 provide access to navigator #172 load and save with size stored
1 parent 48acd73 commit 9ff9bee

12 files changed

+178
-22
lines changed

library.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@
2626
"authors": "DaveTCC"
2727
}
2828
],
29-
"version": "3.0.1",
29+
"version": "3.1.0",
3030
"license": "Apache-2.0",
3131
"frameworks": "arduino, mbed",
3232
"platforms": "*"

library.properties

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
#
55

66
name=tcMenu
7-
version=3.0.1
7+
version=3.1.0
88
maintainer=www.thecoderscorner.com
99
author=davetcc
1010
category=Other

src/EepromItemStorage.cpp

Lines changed: 28 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -9,16 +9,22 @@
99
#include "ScrollChoiceMenuItem.h"
1010
#include "MenuIterator.h"
1111

12+
bool tcMenuUseSizedEeprom = false;
1213

13-
void saveRecursively(EepromAbstraction* eeprom, MenuItem* nextMenuItem) {
14+
uint16_t saveRecursively(EepromAbstraction* eeprom, MenuItem* nextMenuItem) {
15+
uint16_t lastItemSaved = 0;
1416
while (nextMenuItem) {
1517
if (nextMenuItem->getMenuType() == MENUTYPE_SUB_VALUE) {
16-
saveRecursively(eeprom, ((SubMenuItem *) nextMenuItem)->getChild());
18+
lastItemSaved = max(lastItemSaved, saveRecursively(eeprom, ((SubMenuItem *) nextMenuItem)->getChild()));
1719
} else {
1820
saveMenuItem(eeprom, nextMenuItem);
21+
if(nextMenuItem->getEepromPosition() != 0xFFFF) {
22+
lastItemSaved = max(lastItemSaved, nextMenuItem->getEepromPosition());
23+
}
1924
}
2025
nextMenuItem = nextMenuItem->getNext();
2126
}
27+
return lastItemSaved;
2228
}
2329

2430
void saveMenuItem(EepromAbstraction* eeprom, MenuItem* nextMenuItem) {
@@ -76,7 +82,10 @@ void saveMenuItem(EepromAbstraction* eeprom, MenuItem* nextMenuItem) {
7682
void saveMenuStructure(EepromAbstraction* eeprom, uint16_t magicKey) {
7783
serlogF2(SER_TCMENU_INFO, "Save to EEPROM with key ", magicKey);
7884
eeprom->write16(0, magicKey);
79-
saveRecursively(eeprom, menuMgr.getRoot());
85+
uint16_t maxPos = saveRecursively(eeprom, menuMgr.getRoot());
86+
if(tcMenuUseSizedEeprom) {
87+
eeprom->write16(2, maxPos);
88+
}
8089
}
8190

8291
void loadSingleItem(EepromAbstraction* eeprom, MenuItem* nextMenuItem) {
@@ -137,23 +146,29 @@ void loadSingleItem(EepromAbstraction* eeprom, MenuItem* nextMenuItem) {
137146
}
138147
}
139148

140-
void loadRecursively(EepromAbstraction* eeprom, MenuItem* nextMenuItem) {
149+
void loadRecursively(EepromAbstraction* eeprom, MenuItem* nextMenuItem, uint16_t maxLoadPosition) {
141150
while (nextMenuItem) {
142151
if (nextMenuItem->getMenuType() == MENUTYPE_SUB_VALUE) {
143-
loadRecursively(eeprom, ((SubMenuItem*)nextMenuItem)->getChild());
152+
loadRecursively(eeprom, ((SubMenuItem*)nextMenuItem)->getChild(), maxLoadPosition);
144153
}
145154
else {
146-
loadSingleItem(eeprom, nextMenuItem);
155+
uint16_t romLoc = nextMenuItem->getEepromPosition();
156+
if(romLoc <= maxLoadPosition) {
157+
loadSingleItem(eeprom, nextMenuItem);
158+
} else if(romLoc != 0xFFFF) {
159+
serlogF4(SER_TCMENU_DEBUG, "MenuItem EEPROM load skipped ", romLoc, maxLoadPosition, nextMenuItem->getId());
160+
}
147161
}
148162
nextMenuItem = nextMenuItem->getNext();
149163
}
150164
}
151165

152166
bool loadMenuStructure(EepromAbstraction* eeprom, uint16_t magicKey) {
153167
if (eeprom->read16(0) == magicKey) {
168+
uint16_t maxEntry = (tcMenuUseSizedEeprom) ? eeprom->read16(2) : 0xFFFE;
154169
serlogFHex(SER_TCMENU_INFO, "Load from EEPROM key found ", magicKey);
155170
MenuItem* nextMenuItem = menuMgr.getRoot();
156-
loadRecursively(eeprom, nextMenuItem);
171+
loadRecursively(eeprom, nextMenuItem, maxEntry);
157172
return true;
158173
}
159174
else {
@@ -163,7 +178,7 @@ bool loadMenuStructure(EepromAbstraction* eeprom, uint16_t magicKey) {
163178
}
164179

165180
bool loadMenuItem(EepromAbstraction* eeprom, MenuItem* theItem, uint16_t magicKey) {
166-
if (eeprom->read16(0) == magicKey) {
181+
if (eeprom->read16(0) == magicKey && (!tcMenuUseSizedEeprom || eeprom->read16(2) <= theItem->getEepromPosition())) {
167182
loadSingleItem(eeprom, theItem);
168183
return true;
169184
}
@@ -178,4 +193,8 @@ void triggerAllChangedCallbacks() {
178193
item->triggerCallback();
179194
}
180195
});
181-
}
196+
}
197+
198+
void setSizeBasedEEPROMStorageEnabled(bool ena) {
199+
tcMenuUseSizedEeprom = ena;
200+
}

src/EepromItemStorage.h

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,4 +56,10 @@ void saveMenuItem(EepromAbstraction* eeprom, MenuItem* theItem);
5656
*/
5757
void triggerAllChangedCallbacks();
5858

59-
#endif //_EEPROM_ITEM_STORAGE_H_
59+
/**
60+
* This enables the sized EEPROM support. When this is on, new items that are beyond the last saved EEPROM position
61+
* will not attempt to be loaded. This allows new items to initialise properly as long as they are at the end.
62+
*/
63+
void setSizeBasedEEPROMStorageEnabled(bool ena);
64+
65+
#endif //_EEPROM_ITEM_STORAGE_H_

src/MenuHistoryNavigator.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,3 +51,7 @@ MenuItem *tcnav::MenuNavigationStore::popNavigationGetActive() {
5151
bool tcnav::MenuNavigationStore::isShowingRoot() {
5252
return currentRoot == root;
5353
}
54+
55+
void tcnav::MenuNavigationStore::resetStack() {
56+
setRootItem(root);
57+
}

src/MenuHistoryNavigator.h

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,28 @@ namespace tcnav {
6767
MenuItem* popNavigationGetActive();
6868

6969
bool isShowingRoot();
70+
71+
/**
72+
* @return the depth of the navigation stack that is being managed.
73+
*/
74+
int getNavigationDepth() const { return navIdx; }
75+
76+
/**
77+
* The active item at a given zero based position in the stack or nullptr if out of range
78+
* @param i the index
79+
* @return the item or nullptr
80+
*/
81+
MenuItem* getActiveAt(uint8_t i) { return i < navIdx ? activeItems[i] : nullptr; }
82+
83+
/**
84+
* Get the root menu item for the given zero based position in the stack or nullptr if out of range.
85+
* @param i the index
86+
* @return the item or nullptr
87+
*/
88+
MenuItem* getRootAt(uint8_t i) { return i < navIdx ? navItems[i] : nullptr; }
89+
90+
/** Completely reset the navigation back to the initial state where root is on display */
91+
void resetStack();
7092
};
7193
}
7294

src/tcMenu.h

Lines changed: 32 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -397,19 +397,27 @@ class MenuManager {
397397
void resetMenu(bool completeReset);
398398

399399
/**
400-
* Get the first menu item in the linked list that is being rendered
400+
* @return the first menu item in the linked list that is being rendered
401401
*/
402402
MenuItem* getCurrentMenu() { return navigator.getCurrentRoot(); }
403403

404+
/**
405+
* @return the submenu for the currently on display menu. If root is on display it will be nullptr.
406+
*/
404407
MenuItem* getCurrentSubMenu() { return navigator.getCurrentSubMenu(); }
405408

409+
/**
410+
* @return the underlying navigation store that manages navigation activity for this menu manager.
411+
*/
412+
tcnav::MenuNavigationStore& getNavigationStore() { return navigator; }
413+
406414
/**
407-
* Get the parent of the current menu clearing all active flags too
415+
* @return the parent of the current menu clearing all active flags too
408416
*/
409417
MenuItem* getParentAndReset();
410418

411419
/**
412-
* returns the range of the encoder or other device that is providing the
420+
* @return the range of the encoder or other device that is providing the
413421
* equivalent function as the encoder.
414422
*/
415423
int getCurrentRangeValue() {
@@ -423,7 +431,12 @@ class MenuManager {
423431
*/
424432
SecuredMenuPopup* secureMenuInstance();
425433

426-
void stopEditingCurrentItem(bool checkMultiPart);
434+
/**
435+
* Stop editing the current item, if doMultiPartNext is true and we are editing a multi part field , then this will
436+
* instead move editing to the next part. Otherwise, editing will end.
437+
* @param checkMultiPart true to move to the next on multipart instead of ending completely
438+
*/
439+
void stopEditingCurrentItem(bool doMultiPartNext);
427440

428441
/**
429442
* Adds a menu item into the tree directly after the existing item provided. Never add an item that's already in
@@ -453,11 +466,26 @@ class MenuManager {
453466
*/
454467
void recalculateListIfOnDisplay(RuntimeMenuItem* runtimeItem);
455468

469+
/**
470+
* This sets rendering hints, so that the renderer knows that something is being edited. When the rendering hints
471+
* are set, they refer to the item that is currently being edited.
472+
* @param hint the type of edit taking place
473+
* @param start the starting point within the text
474+
* @param end the ending point within the text
475+
*/
456476
void setEditorHints(CurrentEditorRenderingHints::EditorRenderingType hint, size_t start=0, size_t end=0);
457477
const CurrentEditorRenderingHints& getEditorHints() { return renderingHints; }
458478

479+
/**
480+
* Lock the editor hints such that nobody can change them, useful for complex editing where more than one field is
481+
* being edited at once.
482+
* @param locked true to lock, otherwise false.
483+
*/
459484
void setEditorHintsLocked(bool locked);
460485

486+
/**
487+
* Use this with caution. Resets the entire list of observers that have previously been registered.
488+
*/
461489
void resetObservers();
462490

463491
protected:

src/tcMenuVersion.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,8 @@ namespace tccore {
1717

1818
// here we define the version as both a string and separate field
1919
#define TCMENU_MAJOR 3
20-
#define TCMENU_MINOR 0
21-
#define TCMENU_PATCH 1
20+
#define TCMENU_MINOR 1
21+
#define TCMENU_PATCH 0
2222

2323
/**
2424
* A helper to generate the major minor version numbers used in the protocol

tests/tcMenuCoreTests/baseDialogTests.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ void dialogTestCallback(ButtonType buttonPressed, void* yourData) {
5050
}
5151

5252
test(testBaseDialogInfo) {
53+
switches.resetAllSwitches();
5354
NoRenderer noRenderer;
5455
DialogTestImpl dialog(true);
5556
dialog.setButtons(BTNTYPE_NONE, BTNTYPE_CLOSE);

tests/tcMenuCoreTests/menuManagerTests.cpp

Lines changed: 43 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,14 +12,53 @@ extern MockEepromAbstraction eeprom;
1212

1313
const char szCompareData[] = "123456789";
1414

15-
test(saveAndLoadFromMenu) {
15+
test(saveAndLoadFromMenuSized) {
16+
switches.initialise(&mockIo, true);
17+
setSizeBasedEEPROMStorageEnabled(true);
18+
menuMgr.initForUpDownOk(&noRenderer, &textMenuItem1, 0, 1, 2);
19+
20+
eeprom.write16(0, 0xfade);
21+
eeprom.write16(2, 8); // limit is location 8, shouldn't load past there.
22+
eeprom.write16(4, 8);
23+
eeprom.write16(6, 2);
24+
eeprom.write8(8, 1);
25+
eeprom.write16(20, 99);
26+
eeprom.write16(34, 99);
27+
menuMgr.load(eeprom);
28+
29+
// now check the values we've loaded back from eeprom.
30+
assertEquals((int)menuAnalog2.getCurrentValue(), 8);
31+
assertEquals((int)menuEnum1.getCurrentValue(), 2);
32+
assertTrue(boolItem1.getBoolean());
33+
// these items exceed position 8 in the rom and wont load
34+
assertEquals((int)menuAnalog.getCurrentValue(), 0);
35+
assertEquals((int)menuSubAnalog.getCurrentValue(), 0);
36+
assertEquals((int)menuSubAnalog.getCurrentValue(), 0);
37+
38+
menuSubAnalog.setCurrentValue(42);
39+
40+
// save and then make sure the header is right
41+
menuMgr.save(eeprom);
42+
assertEquals(uint16_t(0xfade), eeprom.read16(0));
43+
assertEquals(uint16_t(34), eeprom.read16(2));
44+
45+
// and now the values
46+
assertEquals(eeprom.read16(20), (uint16_t)42);
47+
assertEquals(eeprom.read16(4), (uint16_t)8);
48+
assertEquals(eeprom.read16(6), (uint16_t)2);
49+
assertEquals(eeprom.read8(8), (uint8_t)1);
50+
switches.resetAllSwitches();
51+
}
52+
53+
test(saveAndLoadFromMenuUnsized) {
1654
// initialise the menu manager and switches with basic configuration
1755
switches.initialise(&mockIo, true);
56+
setSizeBasedEEPROMStorageEnabled(false);
1857
menuMgr.initForUpDownOk(&noRenderer, &textMenuItem1, 0, 1, 2);
1958

2059
// now set up the eeprom ready to load.
2160
eeprom.write16(0, 0xfade);
22-
eeprom.write16(2, 100);
61+
eeprom.write16(34, 100);
2362
eeprom.write16(4, 8);
2463
eeprom.write16(6, 2);
2564
eeprom.write8(8, 1);
@@ -51,7 +90,7 @@ test(saveAndLoadFromMenu) {
5190

5291
// now compare back from eeprom what we saved.
5392
assertEquals(eeprom.read16(0), (uint16_t)0xfade);
54-
assertEquals(eeprom.read16(2), (uint16_t)100);
93+
assertEquals(eeprom.read16(34), (uint16_t)100);
5594
assertEquals(eeprom.read16(20), (uint16_t)50);
5695
assertEquals(eeprom.read16(4), (uint16_t)8);
5796
assertEquals(eeprom.read16(6), (uint16_t)2);
@@ -68,6 +107,7 @@ test(saveAndLoadFromMenu) {
68107

69108
// lastly make sure there were no errors in eeprom.
70109
assertFalse(eeprom.hasErrorOccurred());
110+
switches.resetAllSwitches();
71111
}
72112

73113
class TestMenuMgrObserver : public MenuManagerObserver {

0 commit comments

Comments
 (0)