Skip to content

Commit d38e85b

Browse files
committed
UserMenu array menu with easy print by index for menu user extension #293 added plugging for user draw virtual items and std containers + targetSel example
1 parent 8beacd1 commit d38e85b

File tree

12 files changed

+315
-26
lines changed

12 files changed

+315
-26
lines changed

examples/targetSel/include/README

+39
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
2+
This directory is intended for project header files.
3+
4+
A header file is a file containing C declarations and macro definitions
5+
to be shared between several project source files. You request the use of a
6+
header file in your project source file (C, C++, etc) located in `src` folder
7+
by including it, with the C preprocessing directive `#include'.
8+
9+
```src/main.c
10+
11+
#include "header.h"
12+
13+
int main (void)
14+
{
15+
...
16+
}
17+
```
18+
19+
Including a header file produces the same results as copying the header file
20+
into each source file that needs it. Such copying would be time-consuming
21+
and error-prone. With a header file, the related declarations appear
22+
in only one place. If they need to be changed, they can be changed in one
23+
place, and programs that include the header file will automatically use the
24+
new version when next recompiled. The header file eliminates the labor of
25+
finding and changing all the copies as well as the risk that a failure to
26+
find one copy will result in inconsistencies within a program.
27+
28+
In C, the usual convention is to give header files names that end with `.h'.
29+
It is most portable to use only letters, digits, dashes, and underscores in
30+
header file names, and at most one dot.
31+
32+
Read more about using header files in official GCC documentation:
33+
34+
* Include Syntax
35+
* Include Operation
36+
* Once-Only Headers
37+
* Computed Includes
38+
39+
https://gcc.gnu.org/onlinedocs/cpp/Header-Files.html
+164
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,164 @@
1+
/********************
2+
Arduino generic menu system
3+
4+
Rui Azevedo - ruihfazevedo(@rrob@)gmail.com
5+
6+
output: Serial
7+
input: Serial
8+
9+
user defined array menu (userMenu plugin)
10+
*/
11+
12+
#include <menu.h>
13+
#include <menuIO/serialOut.h>
14+
#include <menuIO/serialIn.h>
15+
#include <plugin/userMenu.h>
16+
17+
using namespace Menu;
18+
19+
#define MAX_DEPTH 4
20+
21+
enum SelTest {Zero=0,One,Two};
22+
enum ChooseTest {First=1,Second=2,Third=3,Last=-1};
23+
constexpr int dataSz=3;
24+
constexpr int nameSz=20;
25+
26+
struct Data {
27+
char name[nameSz+1]="<name> ";
28+
bool valid=0;
29+
SelTest selTest=Zero;
30+
ChooseTest chooseTest=First;
31+
//how to copy this data, being a simple data c++ will generate this for you
32+
// Data& operator=(Data& o){
33+
// strcpy(name,o.name);
34+
// valid=o.valid;
35+
// selTest=o.selTest;
36+
// chooseTest=o.chooseTest;
37+
// return o;
38+
// }
39+
};
40+
41+
Data myTargets[dataSz];//our data
42+
//a temp. to be edited
43+
//the data type must have assignment operator
44+
//because we will later on move data back and forth between the actual data and this template
45+
//menu edit is wired to this temp. and menu eventd will deal with the copy-call
46+
Data target;
47+
48+
49+
char* constMEM alphaNum MEMMODE=" 0123456789.ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz,\\|!\"#$%&/()=?~*^+-{}[]€";
50+
char* constMEM alphaNumMask[] MEMMODE={alphaNum};
51+
52+
TOGGLE(target.valid,editValid,"Valid: ",doNothing,noEvent,noStyle//,doExit,enterEvent,noStyle
53+
,VALUE("On",HIGH,doNothing,noEvent)
54+
,VALUE("Off",LOW,doNothing,noEvent)
55+
);
56+
57+
SELECT(target.selTest,selMenu,"Select",doNothing,noEvent,noStyle
58+
,VALUE("Zero",Zero,doNothing,noEvent)
59+
,VALUE("One",One,doNothing,noEvent)
60+
,VALUE("Two",Two,doNothing,noEvent)
61+
);
62+
63+
CHOOSE(target.chooseTest,chooseMenu,"Choose",doNothing,noEvent,noStyle
64+
,VALUE("First",First,doNothing,noEvent)
65+
,VALUE("Second",Second,doNothing,noEvent)
66+
,VALUE("Third",Third,doNothing,noEvent)
67+
,VALUE("Last",Last,doNothing,noEvent)
68+
);
69+
70+
result saveTarget(eventMask e,navNode& nav) {
71+
_trace(MENU_DEBUG_OUT<<"saveTarget"<<endl);
72+
idx_t n=nav.root->path[nav.root->level-1].sel;//get selection of previous level
73+
myTargets[n]=target;
74+
return quit;
75+
}
76+
77+
//if you want to print the recird name as the title,
78+
//then you MUST create a customized print menu to replace this default one
79+
MENU(targetEdit,"Target edit",doNothing,noEvent,wrapStyle
80+
,EDIT("Name",target.name,alphaNumMask,doNothing,noEvent,noStyle)
81+
,SUBMENU(editValid)
82+
,SUBMENU(selMenu)
83+
,SUBMENU(chooseMenu)
84+
,OP("Save",saveTarget,enterEvent)
85+
,EXIT("<Back")
86+
);
87+
88+
//handling the user menu selection
89+
//
90+
result targetEvent(eventMask e,navNode& nav) {
91+
_trace(MENU_DEBUG_OUT<<"copy data to temp.\n");
92+
target=myTargets[nav.sel];
93+
//you can store nav.sel for future reference
94+
return proceed;
95+
}
96+
97+
struct TargetMenu:UserMenu{
98+
using UserMenu::UserMenu;
99+
100+
// override sz() function to have variable/custom size
101+
// inline idx_t sz() const override {return 0;}
102+
103+
//customizing the print of user menu
104+
Used printItem(menuOut& out, int idx,int len) override {
105+
return len?out.printText(myTargets[idx].name,len):0;
106+
}
107+
};
108+
109+
//build the user menu object, optinally giving a sub menu
110+
#ifdef MENU_USERAM
111+
//for non-AVR devices or when MENU_USERAM is defined at compiler level
112+
TargetMenu targetsMenu("Targets",dataSz,targetEdit,targetEvent,enterEvent);
113+
#else
114+
//menu allocation compatible with AVR flash ---------------------------------
115+
constMEM char targetsMenuTitle[] MEMMODE="Targets";
116+
constMEM menuNodeShadowRaw targetsMenuInfoRaw MEMMODE={
117+
(callback)targetEvent,
118+
(systemStyles)(_menuData|_canNav),
119+
targetsMenuTitle,
120+
enterEvent,
121+
wrapStyle,
122+
dataSz,
123+
NULL
124+
};
125+
constMEM menuNodeShadow& targetsMenuInfo=*(menuNodeShadow*)&targetsMenuInfoRaw;
126+
TargetMenu targetsMenu(targetsMenuInfo,targetEdit);
127+
#endif
128+
129+
MENU(mainMenu,"Main menu",doNothing,noEvent,wrapStyle
130+
,OBJ(targetsMenu)//use in a macro built menu
131+
,EXIT("<Back")
132+
);
133+
134+
MENU_OUTPUTS(out,MAX_DEPTH
135+
,SERIAL_OUT(Serial)
136+
,NONE//must have 2 items at least
137+
);
138+
139+
serialIn serial(Serial);
140+
NAVROOT(nav,mainMenu,MAX_DEPTH,serial,out);
141+
142+
result idle(menuOut &o, idleEvent e) {
143+
switch(e) {
144+
case idleStart:o.println("suspending menu!");break;
145+
case idling:o.println("suspended...");break;
146+
case idleEnd:o.println("resuming menu.");
147+
nav.reset();
148+
break;
149+
}
150+
return proceed;
151+
}
152+
153+
void setup() {
154+
Serial.begin(115200);
155+
while(!Serial);
156+
Serial.println("menu 4.x test =================");Serial.flush();
157+
nav.timeOut=3000;
158+
nav.idleTask=idle;//point a function to be used when menu is suspended
159+
}
160+
161+
void loop() {
162+
nav.poll();
163+
delay(100);//simulate a delay when other tasks are done
164+
}

examples/targetSel/test/README

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
2+
This directory is intended for PIO Unit Testing and project tests.
3+
4+
Unit Testing is a software testing method by which individual units of
5+
source code, sets of one or more MCU program modules together with associated
6+
control data, usage procedures, and operating procedures, are tested to
7+
determine whether they are fit for use. Unit testing finds problems early
8+
in the development cycle.
9+
10+
More information about PIO Unit Testing:
11+
- https://docs.platformio.org/page/plus/unit-testing.html

library.properties

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
name=ArduinoMenu library
2-
version=4.19.3
2+
version=4.20.0
33
author=Rui Azevedo, [email protected]
44
maintainer=neu-rah, [email protected]
55
sentence=Generic menu/interactivity system

src/items.h

+1
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@
5252
inline styles style() const {return shadow->_style();}
5353
inline eventMask events() const {return shadow->_events();}
5454

55+
virtual idx_t sz() const {return 0;}
5556
inline bool is(systemStyles chk) const {return (sysStyles()&chk)==chk;}
5657
inline bool has(systemStyles chk) const {return sysStyles()&chk;}
5758
inline bool is(styles chk) const {return (style()&chk)==chk;}

src/macros.h

+6-6
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,9 @@
2020
#endif
2121
#if defined(USE_PGM) || (defined(pgm_read_ptr_near) && !defined(MENU_USERAM))
2222
//storing some values into avr flash memory (saving ram space)
23-
#ifdef MENU_DEBUG
24-
#warning "Using PGM"
25-
#endif
23+
// #ifdef MENU_DEBUG
24+
// #warning "Using PGM"
25+
// #endif
2626
#define USING_PGM
2727
#define MEMMODE PROGMEM
2828
#define constMEM const
@@ -39,9 +39,9 @@
3939
#define memEnum(addr) (sizeof(int)==1?memByte(addr):memWord(addr))
4040
#else
4141
//use ram on non-avr devices or when explicit
42-
#ifdef MENU_DEBUG
43-
#warning "Using RAM"
44-
#endif
42+
// #ifdef MENU_DEBUG
43+
// #warning "Using RAM"
44+
// #endif
4545
#define USING_RAM
4646
#define MEMMODE
4747
#define constMEM

src/menuBase.h

+7-7
Original file line numberDiff line numberDiff line change
@@ -70,13 +70,13 @@ www.r-site.net
7070

7171
enum result {proceed=0,quit};
7272
enum systemStyles {
73-
_noStyle=0,
74-
_menuData=1,
75-
_canNav=1<<1,
76-
_parentDraw=1<<2,
77-
_isVariant=1<<3,
78-
_asPad=1<<4,
79-
_Exit=1<<5
73+
_noStyle=0,// 000000
74+
_menuData=1,// 000001
75+
_canNav=1<<1,// 000010
76+
_parentDraw=1<<2,//000100
77+
_isVariant=1<<3,// 001000
78+
_asPad=1<<4,// 010000
79+
_Exit=1<<5// 100000
8080
};
8181
//showTitle and noTitle override the default
8282
enum styles {

src/menuIO/serialOut.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33

44
namespace Menu {
55
#ifdef MENU_DEBUG
6-
constexpr idx_t w=16;
6+
constexpr idx_t w=20;
77
#else
88
constexpr idx_t w=40;
99
#endif

src/menuIo.cpp

+9-3
Original file line numberDiff line numberDiff line change
@@ -44,12 +44,18 @@ menuOut& menuOut::fill(
4444

4545
idx_t menuOut::printRaw(const char* at,idx_t len) {
4646
trace(MENU_DEBUG_OUT<<"menuOut::printRaw"<<endl);
47-
const char* p=at;
47+
const char* p=(const char*)at;
4848
uint8_t ch;
49-
for(int n=0;(ch=memByte(at++))&&(len==0||n<len);n++) {
49+
for(int n=0;(ch=memByte(p++))&&(len==0||n<len);n++) {
5050
write(ch);
5151
}
52-
return at-p-1;
52+
return p-((const char*)at)-1;
53+
}
54+
55+
idx_t menuOut::printText(const char* at,idx_t len) {
56+
for(int n=0;at[n]&&(len==0||n<len);n++)
57+
write(at[n]);
58+
return len;
5359
}
5460

5561
void menuOut::doNav(navCmd cmd,navNode &nav) {

src/menuIo.h

+3-1
Original file line numberDiff line numberDiff line change
@@ -75,10 +75,12 @@
7575
idx_t maxY(idx_t i=0) const;
7676
idx_t& top(navNode& nav) const;
7777
// inline void reset() {panelsList.reset();}
78+
idx_t printRaw(const char* at,idx_t len);
7879
inline idx_t printRaw(const __FlashStringHelper* at,idx_t len) {
7980
return printRaw((const char*)at,len);
8081
}
81-
virtual idx_t printRaw(const char* at,idx_t len);
82+
idx_t printText(const __FlashStringHelper* at,idx_t len) {return printRaw(at,len);}
83+
idx_t printText(const char* at,idx_t len);
8284
#if defined(MENU_DEBUG) || defined(MENU_ASYNC)
8385
virtual menuOut& operator<<(prompt const &p);
8486
#ifdef ESP8266

src/nav.cpp

+11-7
Original file line numberDiff line numberDiff line change
@@ -44,18 +44,22 @@ navCmd navNode::doNavigation(navCmd cmd) {
4444
root->out.doNav(cmd,*this);*/
4545
case upCmd:
4646
// trace(MENU_DEBUG_OUT<<"up"<<endl;);
47-
nsel++;
48-
if (nsel>=sz()) {if(wrap()) nsel=0; else nsel=sz()-1;}
49-
// trace(MENU_DEBUG_OUT<<"new sel:"<<nsel<<endl);
47+
if(sz()) {
48+
nsel++;
49+
if (nsel>=sz()) {if(wrap()) nsel=0; else nsel=sz()-1;}
50+
// trace(MENU_DEBUG_OUT<<"new sel:"<<nsel<<endl);
51+
}
5052
break;
5153
/*case scrlUpCmd:
5254
if (!target->isVariant())
5355
root->out.doNav(cmd,*this);*/
5456
case downCmd:
55-
// trace(MENU_DEBUG_OUT<<"down"<<endl);
57+
trace(MENU_DEBUG_OUT<<"down"<<endl);
5658
if (nsel||!target->is(_asPad)) {
57-
nsel--;
58-
if (nsel<0) {if(wrap()) nsel=sz()-1; else nsel=0;}
59+
if(sz()) {
60+
nsel--;
61+
if (nsel<0) {if(wrap()) nsel=sz()-1; else nsel=0;}
62+
}
5963
break;
6064
}
6165
case escCmd:
@@ -180,7 +184,7 @@ void navRoot::doNav(navCmd cmd) {
180184
}
181185

182186
navCmd navRoot::enter() {
183-
trace(MENU_DEBUG_OUT<<"navRoot::enter"<<endl);
187+
_trace(MENU_DEBUG_OUT<<"navRoot::enter"<<endl);
184188
if (
185189
selected().enabled
186190
&&selected().sysHandler(activateEvent,node(),selected())==proceed

0 commit comments

Comments
 (0)