Skip to content

Commit

Permalink
UserMenu
Browse files Browse the repository at this point in the history
attay menu with easy print by index for menu user extension
#293
added plugging for user draw virtual items and std containers + 
`targetSel` example
  • Loading branch information
neu-rah committed May 4, 2020
1 parent 8beacd1 commit 5c9710a
Show file tree
Hide file tree
Showing 12 changed files with 315 additions and 26 deletions.
39 changes: 39 additions & 0 deletions examples/targetSel/include/README
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@

This directory is intended for project header files.

A header file is a file containing C declarations and macro definitions
to be shared between several project source files. You request the use of a
header file in your project source file (C, C++, etc) located in `src` folder
by including it, with the C preprocessing directive `#include'.

```src/main.c

#include "header.h"

int main (void)
{
...
}
```

Including a header file produces the same results as copying the header file
into each source file that needs it. Such copying would be time-consuming
and error-prone. With a header file, the related declarations appear
in only one place. If they need to be changed, they can be changed in one
place, and programs that include the header file will automatically use the
new version when next recompiled. The header file eliminates the labor of
finding and changing all the copies as well as the risk that a failure to
find one copy will result in inconsistencies within a program.

In C, the usual convention is to give header files names that end with `.h'.
It is most portable to use only letters, digits, dashes, and underscores in
header file names, and at most one dot.

Read more about using header files in official GCC documentation:

* Include Syntax
* Include Operation
* Once-Only Headers
* Computed Includes

https://gcc.gnu.org/onlinedocs/cpp/Header-Files.html
164 changes: 164 additions & 0 deletions examples/targetSel/targetSel/targetSel.ino
Original file line number Diff line number Diff line change
@@ -0,0 +1,164 @@
/********************
Arduino generic menu system
Rui Azevedo - ruihfazevedo(@rrob@)gmail.com
output: Serial
input: Serial
user defined array menu (userMenu plugin)
*/

#include <menu.h>
#include <menuIO/serialOut.h>
#include <menuIO/serialIn.h>
#include <plugin/userMenu.h>

using namespace Menu;

#define MAX_DEPTH 4

enum SelTest {Zero=0,One,Two};
enum ChooseTest {First=1,Second=2,Third=3,Last=-1};
constexpr int dataSz=3;
constexpr int nameSz=20;

struct Data {
char name[nameSz+1]="<name> ";
bool valid=0;
SelTest selTest=Zero;
ChooseTest chooseTest=First;
//how to copy this data, being a simple data c++ will generate this for you
// Data& operator=(Data& o){
// strcpy(name,o.name);
// valid=o.valid;
// selTest=o.selTest;
// chooseTest=o.chooseTest;
// return o;
// }
};

Data myTargets[dataSz];//our data
//a temp. to be edited
//the data type must have assignment operator
//because we will later on move data back and forth between the actual data and this template
//menu edit is wired to this temp. and menu eventd will deal with the copy-call
Data target;


char* constMEM alphaNum MEMMODE=" 0123456789.ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz,\\|!\"#$%&/()=?~*^+-{}[]€";
char* constMEM alphaNumMask[] MEMMODE={alphaNum};

TOGGLE(target.valid,editValid,"Valid: ",doNothing,noEvent,noStyle//,doExit,enterEvent,noStyle
,VALUE("On",HIGH,doNothing,noEvent)
,VALUE("Off",LOW,doNothing,noEvent)
);

SELECT(target.selTest,selMenu,"Select",doNothing,noEvent,noStyle
,VALUE("Zero",Zero,doNothing,noEvent)
,VALUE("One",One,doNothing,noEvent)
,VALUE("Two",Two,doNothing,noEvent)
);

CHOOSE(target.chooseTest,chooseMenu,"Choose",doNothing,noEvent,noStyle
,VALUE("First",First,doNothing,noEvent)
,VALUE("Second",Second,doNothing,noEvent)
,VALUE("Third",Third,doNothing,noEvent)
,VALUE("Last",Last,doNothing,noEvent)
);

result saveTarget(eventMask e,navNode& nav) {
_trace(MENU_DEBUG_OUT<<"saveTarget"<<endl);
idx_t n=nav.root->path[nav.root->level-1].sel;//get selection of previous level
myTargets[n]=target;
return quit;
}

//if you want to print the recird name as the title,
//then you MUST create a customized print menu to replace this default one
MENU(targetEdit,"Target edit",doNothing,noEvent,wrapStyle
,EDIT("Name",target.name,alphaNumMask,doNothing,noEvent,noStyle)
,SUBMENU(editValid)
,SUBMENU(selMenu)
,SUBMENU(chooseMenu)
,OP("Save",saveTarget,enterEvent)
,EXIT("<Back")
);

//handling the user menu selection
//
result targetEvent(eventMask e,navNode& nav) {
_trace(MENU_DEBUG_OUT<<"copy data to temp.\n");
target=myTargets[nav.sel];
//you can store nav.sel for future reference
return proceed;
}

struct TargetMenu:UserMenu{
using UserMenu::UserMenu;

// override sz() function to have variable/custom size
// inline idx_t sz() const override {return 0;}

//customizing the print of user menu
Used printItem(menuOut& out, int idx,int len) override {
return len?out.printText(myTargets[idx].name,len):0;
}
};

//build the user menu object, optinally giving a sub menu
#ifdef MENU_USERAM
//for non-AVR devices or when MENU_USERAM is defined at compiler level
TargetMenu targetsMenu("Targets",dataSz,targetEdit,targetEvent,enterEvent);
#else
//menu allocation compatible with AVR flash ---------------------------------
constMEM char targetsMenuTitle[] MEMMODE="Targets";
constMEM menuNodeShadowRaw targetsMenuInfoRaw MEMMODE={
(callback)targetEvent,
(systemStyles)(_menuData|_canNav),
targetsMenuTitle,
enterEvent,
wrapStyle,
dataSz,
NULL
};
constMEM menuNodeShadow& targetsMenuInfo=*(menuNodeShadow*)&targetsMenuInfoRaw;
TargetMenu targetsMenu(targetsMenuInfo,targetEdit);
#endif

MENU(mainMenu,"Main menu",doNothing,noEvent,wrapStyle
,OBJ(targetsMenu)//use in a macro built menu
,EXIT("<Back")
);

MENU_OUTPUTS(out,MAX_DEPTH
,SERIAL_OUT(Serial)
,NONE//must have 2 items at least
);

serialIn serial(Serial);
NAVROOT(nav,mainMenu,MAX_DEPTH,serial,out);

result idle(menuOut &o, idleEvent e) {
switch(e) {
case idleStart:o.println("suspending menu!");break;
case idling:o.println("suspended...");break;
case idleEnd:o.println("resuming menu.");
nav.reset();
break;
}
return proceed;
}

void setup() {
Serial.begin(115200);
while(!Serial);
Serial.println("menu 4.x test =================");Serial.flush();
nav.timeOut=3000;
nav.idleTask=idle;//point a function to be used when menu is suspended
}

void loop() {
nav.poll();
delay(100);//simulate a delay when other tasks are done
}
11 changes: 11 additions & 0 deletions examples/targetSel/test/README
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@

This directory is intended for PIO Unit Testing and project tests.

Unit Testing is a software testing method by which individual units of
source code, sets of one or more MCU program modules together with associated
control data, usage procedures, and operating procedures, are tested to
determine whether they are fit for use. Unit testing finds problems early
in the development cycle.

More information about PIO Unit Testing:
- https://docs.platformio.org/page/plus/unit-testing.html
2 changes: 1 addition & 1 deletion library.properties
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
name=ArduinoMenu library
version=4.19.3
version=4.20.0
author=Rui Azevedo, [email protected]
maintainer=neu-rah, [email protected]
sentence=Generic menu/interactivity system
Expand Down
1 change: 1 addition & 0 deletions src/items.h
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@
inline styles style() const {return shadow->_style();}
inline eventMask events() const {return shadow->_events();}

virtual idx_t sz() const {return 0;}
inline bool is(systemStyles chk) const {return (sysStyles()&chk)==chk;}
inline bool has(systemStyles chk) const {return sysStyles()&chk;}
inline bool is(styles chk) const {return (style()&chk)==chk;}
Expand Down
12 changes: 6 additions & 6 deletions src/macros.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,9 @@
#endif
#if defined(USE_PGM) || (defined(pgm_read_ptr_near) && !defined(MENU_USERAM))
//storing some values into avr flash memory (saving ram space)
#ifdef MENU_DEBUG
#warning "Using PGM"
#endif
// #ifdef MENU_DEBUG
// #warning "Using PGM"
// #endif
#define USING_PGM
#define MEMMODE PROGMEM
#define constMEM const
Expand All @@ -39,9 +39,9 @@
#define memEnum(addr) (sizeof(int)==1?memByte(addr):memWord(addr))
#else
//use ram on non-avr devices or when explicit
#ifdef MENU_DEBUG
#warning "Using RAM"
#endif
// #ifdef MENU_DEBUG
// #warning "Using RAM"
// #endif
#define USING_RAM
#define MEMMODE
#define constMEM
Expand Down
14 changes: 7 additions & 7 deletions src/menuBase.h
Original file line number Diff line number Diff line change
Expand Up @@ -70,13 +70,13 @@ www.r-site.net

enum result {proceed=0,quit};
enum systemStyles {
_noStyle=0,
_menuData=1,
_canNav=1<<1,
_parentDraw=1<<2,
_isVariant=1<<3,
_asPad=1<<4,
_Exit=1<<5
_noStyle=0,// 000000
_menuData=1,// 000001
_canNav=1<<1,// 000010
_parentDraw=1<<2,//000100
_isVariant=1<<3,// 001000
_asPad=1<<4,// 010000
_Exit=1<<5// 100000
};
//showTitle and noTitle override the default
enum styles {
Expand Down
2 changes: 1 addition & 1 deletion src/menuIO/serialOut.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

namespace Menu {
#ifdef MENU_DEBUG
constexpr idx_t w=16;
constexpr idx_t w=20;
#else
constexpr idx_t w=40;
#endif
Expand Down
12 changes: 9 additions & 3 deletions src/menuIo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -44,12 +44,18 @@ menuOut& menuOut::fill(

idx_t menuOut::printRaw(const char* at,idx_t len) {
trace(MENU_DEBUG_OUT<<"menuOut::printRaw"<<endl);
const char* p=at;
const char* p=(const char*)at;
uint8_t ch;
for(int n=0;(ch=memByte(at++))&&(len==0||n<len);n++) {
for(int n=0;(ch=memByte(p++))&&(len==0||n<len);n++) {
write(ch);
}
return at-p-1;
return p-((const char*)at)-1;
}

idx_t menuOut::printText(const char* at,idx_t len) {
for(int n=0;at[n]&&(len==0||n<len);n++)
write(at[n]);
return len;
}

void menuOut::doNav(navCmd cmd,navNode &nav) {
Expand Down
4 changes: 3 additions & 1 deletion src/menuIo.h
Original file line number Diff line number Diff line change
Expand Up @@ -75,10 +75,12 @@
idx_t maxY(idx_t i=0) const;
idx_t& top(navNode& nav) const;
// inline void reset() {panelsList.reset();}
idx_t printRaw(const char* at,idx_t len);
inline idx_t printRaw(const __FlashStringHelper* at,idx_t len) {
return printRaw((const char*)at,len);
}
virtual idx_t printRaw(const char* at,idx_t len);
idx_t printText(const __FlashStringHelper* at,idx_t len) {return printRaw(at,len);}
idx_t printText(const char* at,idx_t len);
#if defined(MENU_DEBUG) || defined(MENU_ASYNC)
virtual menuOut& operator<<(prompt const &p);
#ifdef ESP8266
Expand Down
18 changes: 11 additions & 7 deletions src/nav.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -44,18 +44,22 @@ navCmd navNode::doNavigation(navCmd cmd) {
root->out.doNav(cmd,*this);*/
case upCmd:
// trace(MENU_DEBUG_OUT<<"up"<<endl;);
nsel++;
if (nsel>=sz()) {if(wrap()) nsel=0; else nsel=sz()-1;}
// trace(MENU_DEBUG_OUT<<"new sel:"<<nsel<<endl);
if(sz()) {
nsel++;
if (nsel>=sz()) {if(wrap()) nsel=0; else nsel=sz()-1;}
// trace(MENU_DEBUG_OUT<<"new sel:"<<nsel<<endl);
}
break;
/*case scrlUpCmd:
if (!target->isVariant())
root->out.doNav(cmd,*this);*/
case downCmd:
// trace(MENU_DEBUG_OUT<<"down"<<endl);
trace(MENU_DEBUG_OUT<<"down"<<endl);
if (nsel||!target->is(_asPad)) {
nsel--;
if (nsel<0) {if(wrap()) nsel=sz()-1; else nsel=0;}
if(sz()) {
nsel--;
if (nsel<0) {if(wrap()) nsel=sz()-1; else nsel=0;}
}
break;
}
case escCmd:
Expand Down Expand Up @@ -180,7 +184,7 @@ void navRoot::doNav(navCmd cmd) {
}

navCmd navRoot::enter() {
trace(MENU_DEBUG_OUT<<"navRoot::enter"<<endl);
_trace(MENU_DEBUG_OUT<<"navRoot::enter"<<endl);
if (
selected().enabled
&&selected().sysHandler(activateEvent,node(),selected())==proceed
Expand Down
Loading

0 comments on commit 5c9710a

Please sign in to comment.