There is an error in navigation if you use a rotary encoder, can not set textfield.
please try the following code
/********************
Arduino generic menu system
Rui Azevedo - ruihfazevedo(@rrob@)gmail.com
output: Serial
input: Serial
user defined array menu (userMenu plugin)
*/
#include <Wire.h>
#include <LiquidCrystal_I2C.h>//F. Malpartida LCD's driver
#include <menu.h>//menu macros and objects
#include <menuIO/lcdOut.h>//malpartidas lcd menu output
#include <menuIO/serialIn.h>//Serial input
#include <menuIO/encoderIn.h>//quadrature encoder driver and fake stream
#include <menuIO/keyIn.h>//keyboard driver and fake stream (for the encoder button)
#include <menuIO/chainStream.h>
#include <plugin/userMenu.h>
using namespace Menu;
//===========================================================================
LiquidCrystal_I2C lcd(0x27, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE);
//some values for user data record
enum SelTest {Zero=0,One,Two};
enum ChooseTest {First=1,Second=2,Third=3,Last=-1};
constexpr int dataSz=5;
constexpr int nameSz=10;
//some user data record type to be edited by the menu
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;
}
};
//THE DATA <-----------------------------------------
Data myTargets[dataSz];//our data
//a temporary 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 temporary
//menu edit is wired to this temp. and menu events will deal with the copy-call (from/to)
Data target;
//characters allowed on name field
char* constMEM alphaNum MEMMODE=" 0123456789.ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz,\\|!\"#$%&/()=?~*^+-{}[]€";
char* constMEM alphaNumMask[] MEMMODE={alphaNum};
//some enumeration of values allowed on some fields
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)
);
//a function to save the edited data record
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 data record 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
//this will copy the selected recotd into the temp var
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;
}
//the customized print of records
//menu system wil use this to print the list of all records
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 item (len is the availabe space)
Used printItem(menuOut& out, int idx,int len) override {
//just printing the string name to the menu output device
//as an item representative
return len?out.printText(myTargets[idx].name,len):0;
}
};
//build the user menu object, optionally 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)//attach the array edit menu on a macri build nenu
,EXIT("<Back")
);
//////////////////////////////////////////////////////////////////////////////
// menu IO and root navigation control
// Encoder /////////////////////////////////////
#define encA 2
#define encB 3
//this encoder has a button here
#define encBtn 4
encoderIn<encA,encB> encoder;//simple quad encoder driver
#define ENC_SENSIVITY 4
encoderInStream<encA,encB> encStream(encoder,ENC_SENSIVITY);// simple quad encoder fake Stream
//a keyboard with only one key as the encoder button
keyMap encBtn_map[]={{-encBtn,defaultNavCodes[enterCmd].ch}};//negative pin numbers use internal pull-up, this is on when low
keyIn<1> encButton(encBtn_map);//1 is the number of keys
serialIn serial(Serial);
//input from the encoder + encoder button + serial
menuIn* inputsList[]={&encStream,&encButton,&serial};
chainStream<3> in(inputsList);
#define MAX_DEPTH 2
MENU_OUTPUTS(out,MAX_DEPTH
,LCD_OUT(lcd,{0,0,16,2})
,NONE//must have 2 items at least
);
NAVROOT(nav,mainMenu,MAX_DEPTH,in,out);
//function for menu idle/timemout
result idle(menuOut &o, idleEvent e) {
switch(e) {
case idleStart:o.print("suspending menu!");break;
case idling:o.print("suspended...");break;
case idleEnd:o.print("resuming menu.");
nav.reset();
break;
}
return proceed;
}
void setup() {
pinMode(encBtn,INPUT_PULLUP);
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
encoder.begin();
lcd.begin(16,2);
nav.showTitle=false;
lcd.setCursor(0, 0);
lcd.print("Menu 4.x LCD");
lcd.setCursor(0, 1);
lcd.print("r-site.net");
}
void loop() {
nav.poll();
delay(100);//simulate a delay when other tasks are done
}
and this is the result of the implementation picture
in the serial.
in LCD I2C + Rotary encoder
somethink is wrong on navigation, if you use a rotary encoder, can not set textfield.
Hello Sir
There is an error in navigation if you use a rotary encoder, can not set textfield. please try the following code
and this is the result of the implementation picture in the serial.
in LCD I2C + Rotary encoder
somethink is wrong on navigation, if you use a rotary encoder, can not set textfield.
Thanks