Menu for Display

Hi All,
do you know something simply procedure to implement for inizialize arduino from a keypad and display the on a display ?

I'm trying to find a base code from start to implement it,

thanks in advance,

Andrea

Did the keypad (make/model ?) come with any example programs ?
What do you mean by "inizialize arduino from a keypad" ?

Yes I'm using the Keypad.h with Adafruit Keypad,

So My focus is built a sketch that for example when I push * appear the menu i then i start to set my parameters,

thanks
Andrea

Ok thanks,
what I was thinking to was to implement a case with if etc etc,
but If is there more simply routines to call should better and more inside the software i thinks, i will check and then I'll to you know,

regards,
gnux

I've tried to something with Library Menu but I retrieve several issues with the library ...

:frowning:

I will see the other suggestion ...

regards,
Andrea

liudr has once started a new section in playground:
http://playground.arduino.cc//Main/InterfacingWithHardware#ui

I also made a list of menu tools some time ago:
Library Name: LCDMenu2
Download: http://arduino.cc/forum/index.php/topic,73816.0.html

Library Name: LCDMenu
Download: http://arduino.cc/forum/index.php/topic,96104.0.html

Library Name: MenuBackend
Download: http://wiring.uniandes.edu.co/source/trunk/wiring/firmware/libraries/MenuBackend/

Library Name: LCDMenu
Download: http://www.metalgecko.com/arduino/LCDMenu.zip (does not exist any more)

Library Name: Arduino_LCD_Menu
Download: GitHub - DavidAndrews/Arduino_LCD_Menu: This library creates menu systems primarily useful for 16x2 or 16x4 LCD displays.

Library Name: MENWIZ
Download: GitHub - brunialti/MENWIZ: ARDUINO LCD menu library: short user code to manage complex menu structures

Library Name: phi_prompt
Download: Phi_prompt | LiuDr Electronic Solutions LLC Official Blog

Library Name: MenuSample
Download: Arduino WiFly Driver - Browse /MenuSample at SourceForge.net

Library Name: M2tklib
Download: Google Code Archive - Long-term storage for Google Code Project Hosting.

Library Name: OpenMoCo Menu Manager
Download: http://arduino.cc/forum/index.php/topic,131614.0.html, Dynamic Perception

I can say that discussions on MENWIZ and phi_prompt had been very active on the Display forum. I also get a lot of feedback on my own menu lib (M2tklib) and you are always wellcome to contact me if you have any trouble with M2tklib.

Oliver

If you want I can try to use your library for the menu "M2tklib" in this way will be happy togheter :slight_smile: ... so i'll learn how to use the menu and you maybe you i'll can be to improve your library ...

So, with the menu I'm starting from zero point ... anyway i'll download the library and I'll start try to understand how it's working ...

thanks in advance,

gnux

So, for start I've available 2 kind of display,

  • the first one is a LCD (4 Rows with 20 character) --> 7 pins
  • the second one is a LCD (2 Rows with 16 character) --> 2 pin I2C bus

Which is the best and simple to use :slight_smile: ?

Thanks
Gnux

With M2tklib only LiquidCrystal lib is supported, so you need to use your 7 pin 4x20 LCD.
Also take care to download M2tklib for LiquidCrystal.

Oliver

Hi,
I've downloaded:

  • m2tklib_arduino_lc_1.09.zip

and now I'm looking the examples,

MENU 2L

So, I've understand how structered the menu ..., for the input I've available a keypad that has the characters from 0 to 9 plus * and #

Could i use it ?

if yes how I can define the push button ? and how I can call the right procedure ?

thansk :slight_smile: you see that I'm very young with that :slight_smile:

Hi

Input:

By default M2tklib supports aktive low push buttons: Connect an Arduino pin to a push button and the other end of the push button to ground.

A keypad can be used, but you need to define your own "event source", which is not really described at the moment. Let me know if your really want to use your keypad. In this case we need to study the datasheet for the keypad and write a specific event source.

Another way is to simulate input by using the serial monitor.
With the serial monitor you can test your menus without extra input hardware. Instead, input on the serial monitor is used to navigate through the menues. For example look at the Combo.pde:
You will find the following line:

M2tk m2(&list_element, m2_es_arduino, m2_eh_2bs, m2_gh_lc);

Add "_serial" to the event source:

M2tk m2(&list_element, m2_es_arduino_serial, m2_eh_2bs, m2_gh_lc);

This enables the serial monitor to navigate through the menu. Remember to activate the serial monitor in your Arduino IDE.
This can be done for all examples, and of course it might be a good starting point for your projects, if you have not yet decided which hardware buttons to use.

Learning M2tklib:

Looking at the examples is a good starting point. And it seems that the examples are already working (I am glad the M2tklib works in your environment). I also suggest to look at the first three tutorials:

Tutorial 1: General setup
Tutorial 2: How to apply the above mentioned push buttons
Tutorial 3: How to build a simple menu/dialog
I also suggest to read
Tutorial 7: How to use the serial monitor interface
as mentioned above for quick success without additional input hardware

Oliver

Thanks Oliver,
Then I need to define 2 push button in arduino correct ?

and I not understood bad i can test my menu into Arduino serial monitor without lcd before to deploy it with the display,
this I think it's very useful ...

So, I will read the documentation and then I'll start immediately ...
So i think that for the moment I can implement 2 button without problem for be more confortable ... what do you mean ? Then when I'll be able to manage it maybe we can pass to keypad ...

Thanks for your precious support,
Andrea

Hi Oliver,
So, after reading your indication I've seen how to proceed more or less but I've some question for you. I'd Like to structure my Menu in this way:

Menu --> Activate pushing "Select"

  • "Date/Time 1"
    ". Set D/T 1-1"
    ". View D/T 1-2"

  • "Timer 2":
    ". E/D 2-1"
    ". Sel. Dev. 2-2"
    ". Start D/T 2-3"
    ". Stop D/T 2-4"

for the moment i think should be enough :slight_smile:

But the problem is how to do that ? How i can call the procedure, Retrive Value etc?

thanks
Gnux

Hi

M2tklib requires at least 2 buttons. Make sure that you use the correct event handler. With two buttons, the "2bs" handler.
Existing event handler are described here Google Code Archive - Long-term storage for Google Code Project Hosting..

With M2tklib you can describe a dialog / user entry form. Such a form is composed of several elements. These elements have a hierarchie, including one element, which is the root element.

In tutorial 2 (Google Code Archive - Long-term storage for Google Code Project Hosting.) you see the following user entry form:

void fn_ok(m2_el_fnarg_p fnarg) {
  /* do something with the number */
}
M2_LABEL(el_label, NULL, "Num: ");
M2_U32NUM(el_num, "a1c4", &number);
M2_BUTTON(el_ok, "", " ok ", fn_ok);
M2_LIST(list) = { &el_label, &el_num, &el_ok };
M2_HLIST(top_el_hlist, NULL, list);

The root element is "top_el_hlist", it contains "list" and list contains "el_label", "el_num" and "el_ok". So, basically it looks like this:
HLIST

  • LABEL
  • U32NUM
  • BUTTON

The toplevel element "top_el_hlist" is the most important element. If you want to display this complete dialog box, you must make the toplevel element "top_el_hlist" the so called "root" element.

Making a toplevel element as a root element is just like jumping to this dialog box. There are several ways to make an element the root element: M2_ROOT or m2.setRoot() are two common options. The 2L-Menu element is another option to make other elements the root element. Just add the root element next to the menu title (including &). See the example pde.

Oliver

Here is an example for a date entry dialog box:

/*=========================================================================*/
/* edit date dialog */

uint8_t dt_day;
uint8_t dt_month;
uint8_t dt_year;

void dt_get_from_RTC(void)
{
  RTC.getTime();
  dt_day = RTC.day;
  dt_month = RTC.month;
  dt_year = (RTC.year-2000);
}

void dt_put_to_RTC(void)
{
  RTC.getTime();
  RTC.fillByYMD(dt_year+2000, dt_month, dt_day);
  RTC.setTime();
  RTC.startClock();  
}

void dt_ok_fn(m2_el_fnarg_p fnarg) 
{
  dt_put_to_RTC();
  m2.setRoot(&el_top);
}

M2_U8NUM(el_dt_day, "c2", 1,31,&dt_day);
M2_LABEL(el_dt_sep1, NULL, ".");
M2_U8NUM(el_dt_month, "c2", 1,12,&dt_month);
M2_LABEL(el_dt_sep2, NULL, ".");
M2_U8NUM(el_dt_year, "c2", 0,99,&dt_year);

M2_LIST(list_date) = { &el_dt_day, &el_dt_sep1, &el_dt_month, &el_dt_sep2, &el_dt_year };
M2_HLIST(el_date, NULL, list_date);

M2_ROOT(el_dt_cancel, NULL, "cancel", &el_top)
M2_BUTTON(el_dt_ok, NULL, "ok", dt_ok_fn);
M2_LIST(list_dt_buttons) = {&el_dt_cancel, &el_dt_ok };
M2_HLIST(el_dt_buttons, NULL, list_dt_buttons);

M2_LIST(list_dt) = {&el_date, &el_dt_buttons };
M2_VLIST(el_top_dt, NULL, list_dt);

The "dt_put_to_RTC" procedure will be different for your, but the element hierarchy might be the same.
The top level element is "el_top_dt".

This means that your data for the 2L-Menu might look like this:

m2_menu_entry m2_2lmenu_data[] = 
{
  { "Date/Time 1", NULL },
   { ". Set Date 1-1", &el_top_dt },
  ...
  { NULL, NULL },
};

The 2L-Menu is another element hierarchy. For example:

M2_2LMENU(el_2lmenu,"l4F3e15W43",&m2_2lmenu_first,&m2_2lmenu_cnt, m2_2lmenu_data,65,102,'\0');
M2_SPACE(el_space, "W1h1");
M2_VSB(el_vsb, "l4W2r1", &m2_2lmenu_first, &m2_2lmenu_cnt);
M2_LIST(list_2lmenu) = { &el_2lmenu, &el_space, &el_vsb };
M2_HLIST(el_hlist, NULL, list_2lmenu);
M2_ALIGN(top_el_expandable_menu, "-1|1W64H64", &el_hlist);

The toplevel (root) element is "top_el_expandable_menu".

Oliver

Hi Oliver,
thanks now I try to do something and then i'll let you know :slight_smile:

gnux

Ciao Oliver, I'm put all my self for try to manage at the best everything related to the menu ... at least im trying with effort :slight_smile: ... it pretty new for me ...

So, from the theory stand-point I've understand the logical is a first step :slight_smile: at list i think/hope ...

So what I've understood right now is:

  • That i can compose a form did with several elements
  • Each Elements have a hierarchy, including the root elements
  • The "Root Elements" contain other object --> List and list contain another 2 object: el_label,el_num
    so should be like this if I not understood bad:

"top_el_hlist"
--> list
--> el_label
--> el_num
--> el_ok

and in order to have a complete menu top_el_hlist must be at the TOP LEVEL.

Now I've tried to play a little bit with the sketch below reported :slight_smile: I've just modify the menu with my label but I cannot call the event that I want ... and inside it put a code that I want ...

So, playing with the sketch I've understand that in the last element of the menu that i choose I can set the value or do something if not understand bad ...

So starting from this sketch,
Could you kindly clean up the code in order to have only one menu with only one sub menu ...
maybe the code will be more clear after :slight_smile: What do you think about that ?

#include <LiquidCrystal.h>	// ensure that the include path is set
#include "M2tk.h"


//=================================================
// Forward declaration of the toplevel element
M2_EXTERN_HLIST(top_el_expandable_menu);


/*======================================================================*/
/* number entry */

uint8_t u8num = 0;
uint32_t u32num = 0;

void fn_num_zero(m2_el_fnarg_p fnarg) 
{
  u8num = 0;
  u32num = 0;
}

M2_LABEL(el_num_label1, NULL, "U8:");
M2_U8NUM(el_num_1, NULL, 0, 255, &u8num);

M2_LABEL(el_num_label2, NULL, "U32:");
M2_U32NUM(el_num_2, "c5", &u32num);

M2_BUTTON(el_num_zero, "f4", " zero ", fn_num_zero);
M2_ROOT(el_num_goto_top, "f4", " back ", &top_el_expandable_menu);

M2_LIST(num_list) = 
{ 
    &el_num_label1, &el_num_1, 
    &el_num_label2, &el_num_2,  
    &el_num_zero, &el_num_goto_top
};

M2_GRIDLIST(el_num_menu, "c2", num_list);

/*=========================================================================*/
/* edit date dialog */

uint8_t dt_day = 1;
uint8_t dt_month = 1;
uint8_t dt_year = 12;

void dt_ok_fn(m2_el_fnarg_p fnarg)  
{
  m2_SetRoot(&top_el_expandable_menu);
}

M2_U8NUM(el_dt_year, "c2", 0,99,&dt_year);
M2_LABEL(el_dt_sep1, "b1", "-");
M2_U8NUM(el_dt_month, "c2", 1,12,&dt_month);
M2_LABEL(el_dt_sep2, "b1", "-");
M2_U8NUM(el_dt_day, "c2", 1,31,&dt_day);

M2_LIST(list_date) = { &el_dt_year, &el_dt_sep1, &el_dt_month, &el_dt_sep2, &el_dt_day };
M2_HLIST(el_date, NULL, list_date);

M2_ROOT(el_dt_cancel, NULL, "cancel", &top_el_expandable_menu);
M2_BUTTON(el_dt_ok, NULL, "ok", dt_ok_fn);
M2_LIST(list_dt_buttons) = {&el_dt_cancel, &el_dt_ok };
M2_HLIST(el_dt_buttons, NULL, list_dt_buttons);

M2_LIST(list_dt) = {&el_date, &el_dt_buttons };
M2_VLIST(el_top_dt, NULL, list_dt);

/*=========================================================================*/
/* radio */

uint8_t select_color = 0;

void fn_radio_ok(m2_el_fnarg_p fnarg) 
{
  /* accept selection */
  m2_SetRoot(&top_el_expandable_menu);
}

void fn_radio_cancel(m2_el_fnarg_p fnarg) 
{
  /* discard selection */
  m2_SetRoot(&top_el_expandable_menu);
}

M2_LABEL(el_radio_label1, NULL, "red");
M2_RADIO(el_radio_radio1, "v0", &select_color);

M2_LABEL(el_radio_label2, NULL, "green");
M2_RADIO(el_radio_radio2, "v1", &select_color);

M2_LABEL(el_radio_label3, NULL, "blue");
M2_RADIO(el_radio_radio3, "v2", &select_color);

M2_BUTTON(el_radio_cancel, NULL, "cancel", fn_radio_cancel);
M2_BUTTON(el_radio_ok, NULL, "ok", fn_radio_ok);

M2_LIST(list_radio) = 
{ 
    &el_radio_label1, &el_radio_radio1, 
    &el_radio_label2, &el_radio_radio2,  
    &el_radio_label3, &el_radio_radio3, 
    &el_radio_cancel, &el_radio_ok 
};
M2_GRIDLIST(top_el_radio, "c2",list_radio);

/*=========================================================================*/
/* combo */

uint8_t select_priority = 0;

void fn_combo_ok(m2_el_fnarg_p fnarg) 
{
  /* accept selection */
  m2_SetRoot(&top_el_expandable_menu);
}

void fn_combo_cancel(m2_el_fnarg_p fnarg) 
{
  /* discard selection */
  m2_SetRoot(&top_el_expandable_menu);
}

const char *fn_idx_to_color(uint8_t idx)
{
  if ( idx == 0 )
    return "red";
  else if (idx == 1 )
    return "green";
  return "blue";
}

const char *fn_idx_to_priority(uint8_t idx)
{
  switch(idx)
  {
    case 0: return "lowest";
    case 1: return "low";
    case 2: return "medium";
    case 3: return "high";
    case 4: return "highest";
  }
  return "";
}


M2_LABEL(el_combo_label1, NULL, "Color:");
M2_COMBO(el_combo_combo1, NULL, &select_color, 3, fn_idx_to_color);

M2_LABEL(el_combo_label2, NULL, "Prio.: ");
M2_COMBO(el_combo_combo2, "v1", &select_priority, 5, fn_idx_to_priority);

M2_BUTTON(el_combo_cancel, NULL, "cancel", fn_combo_cancel);
M2_BUTTON(el_combo_ok, NULL, " ok ", fn_combo_ok);

M2_LIST(list_combo) = { 
    &el_combo_label1, &el_combo_combo1, 
    &el_combo_label2, &el_combo_combo2,  
    &el_combo_cancel, &el_combo_ok 
};
M2_GRIDLIST(top_el_combo, "c2",list_combo);

/*=========================================================================*/
/* main menu */


// Left entry: Menu name. Submenus must have a '.' at the beginning
// Right entry: Reference to the target dialog box (In this example all menus call the toplevel element again
m2_menu_entry m2_2lmenu_data[] = 
{
  { "Date/Time 1", NULL },
  { ". Set Date 1-1", &el_num_menu },
  { ". Set Time 1-2", &el_top_dt },
  { ". View Date 1-3", &el_top_dt },
  { ". View Time 1-4", &el_top_dt },
  { "Radio", &top_el_radio },
  { "Combo", &top_el_combo },
  { NULL, NULL },
};

// The first visible line and the total number of visible lines.
// Both values are written by M2_2LMENU and read by M2_VSB
uint8_t m2_2lmenu_first;
uint8_t m2_2lmenu_cnt;

// M2_2LMENU definition
// Option l4 = four visible lines
// Option e1 = first column has a width of 1 char
// Option w12 = second column has a width of 12 chars

M2_2LMENU(el_2lmenu,"l4e1w12",&m2_2lmenu_first,&m2_2lmenu_cnt, m2_2lmenu_data,'+','-','\0');
M2_VSB(el_vsb, "l4w1r1", &m2_2lmenu_first, &m2_2lmenu_cnt);
M2_LIST(list_2lmenu) = { &el_2lmenu, &el_vsb };
M2_HLIST(top_el_expandable_menu, NULL, list_2lmenu);

// m2 object and constructor
M2tk m2(&top_el_expandable_menu, m2_es_arduino_serial, m2_eh_4bs, m2_gh_arduino_serial);

void setup() 
{
}

void loop() 
{
  m2.checkKey();
  m2.checkKey();
  if ( m2.handleKey() )
    m2.draw();
  m2.checkKey();
}

thanks 10000 for the support !!! I very appreciate it
Gnux

Your menu is working great. Here is a log file with your menu and my key strokes ('s' and 'n'):

m2tklib serial (press 'h' for help)

m2tklib LCD simulator

[+Date/Time 1 ]
Radio
Combo

s
[-Date/Time 1 ]
Set Date 1-1
Set Time 1-2
View Date 1-3
n
-Date/Time 1
[ Set Date 1-1
Set Time 1-2
View Date 1-3
n
-Date/Time 1
Set Date 1-1
[ Set Time 1-2
View Date 1-3
s

[12]- 01 - 01
cancel ok
n

12 -[01]- 01
cancel ok
s

12 -[02]- 01
cancel ok
s

12 -[03]- 01
cancel ok
n

12 - 03 -[01]
cancel ok
n

12 - 03 - 01
[cancel] ok
n

12 - 03 - 01
cancel [ok]
s
[-Date/Time 1 ]
Set Date 1-1
Set Time 1-2
View Date 1-3

Could you kindly clean up the code in order to have only one menu with only one sub menu ...

Not sure if i understood you correctly, but you could simply remove most of the lines from the m2_menu_entry array:

Instead of

m2_menu_entry m2_2lmenu_data[] = 
{
  { "Date/Time 1", NULL },
  { ". Set Date 1-1", &el_num_menu },
  { ". Set Time 1-2", &el_top_dt },
  { ". View Date 1-3", &el_top_dt },
  { ". View Time 1-4", &el_top_dt },
  { "Radio", &top_el_radio },
  { "Combo", &top_el_combo },
  { NULL, NULL },
};

use

m2_menu_entry m2_2lmenu_data[] = 
{
  { "Date/Time 1", NULL },
  { ". Set Date 1-1", &el_num_menu },
  { NULL, NULL },
};

Of course you probably want to call the date entry if you pess the "set date" menu:

m2_menu_entry m2_2lmenu_data[] = 
{
  { "Date/Time 1", NULL },
  { ". Set Date 1-1", &el_top_dt },
  { NULL, NULL },
};

Does this answer your question?

Oliver

So now im doing this Im checking the menu into serial monitor ...and in the meantime I'm see the part of the code for the sketch: for example: looking the standard example "Serial" the part "edit date dialog" there is this code:

uint8_t dt_day = 1;
uint8_t dt_month = 1;
uint8_t dt_year = 12;

void dt_ok_fn(m2_el_fnarg_p fnarg)  {
  m2_SetRoot(&top_el_expandable_menu);
}

M2_U8NUM(el_dt_year, "c2", 0,99,&dt_year);
M2_LABEL(el_dt_sep1, "b1", "-");
M2_U8NUM(el_dt_month, "c2", 1,12,&dt_month);
M2_LABEL(el_dt_sep2, "b1", "-");
M2_U8NUM(el_dt_day, "c2", 1,31,&dt_day);

M2_LIST(list_date) = { &el_dt_year, &el_dt_sep1, &el_dt_month, &el_dt_sep2, &el_dt_day };
M2_HLIST(el_date, NULL, list_date);

M2_ROOT(el_dt_cancel, NULL, "cancel", &top_el_expandable_menu);
M2_BUTTON(el_dt_ok, NULL, "ok", dt_ok_fn);
M2_LIST(list_dt_buttons) = {&el_dt_cancel, &el_dt_ok };
M2_HLIST(el_dt_buttons, NULL, list_dt_buttons);

M2_LIST(list_dt) = {&el_date, &el_dt_buttons };
M2_VLIST(el_top_dt, NULL, list_dt);

with this output: in attachment .
well starting from declaration
uint8_t dt_day = 1;
uint8_t dt_month = 1;
uint8_t dt_year = 12;
are ok initialize the date, no problem

void dt_ok_fn(m2_el_fnarg_p fnarg)
{
m2_SetRoot(&top_el_expandable_menu);
}
is a function that want a variable "fnarg" declared ad "m2_el_fnarg_p"

  • Where is defined the type variable "m2_el_fnarg_p" ?

Then this function call "m2_SetRoot" with "&top_el_expandable_menu"

  • Where are defined "m2_SetRoot"" and "&top_el_expandable_menu" ?

Then after there is a sort of initialization, where do you set the separator date,how many years (0-99),how many months(1-12),how many day(1-31).So also here I don't know where are defined in which library i mean :-):

Please correct me if i wrong because Im trying to understand :slight_smile:

M2_U8NUM(el_dt_year, "c2", 0,99,&dt_year);
// M2_U8NUM where is defined ?el_dt_year ?, "C2" what means,0-99 is the range, &dt_year is the variable by ref . the same for the rest ...

M2_LABEL(el_dt_sep1, "b1", "-");
M2_U8NUM(el_dt_month, "c2", 1,12,&dt_month);
M2_LABEL(el_dt_sep2, "b1", "-");
M2_U8NUM(el_dt_day, "c2", 1,31,&dt_day);

Next piece of code:

M2_LIST(list_date) = { &el_dt_year, &el_dt_sep1, &el_dt_month, &el_dt_sep2, &el_dt_day };
M2_HLIST(el_date, NULL, list_date);

M2_LIST(list_date) --> should be the function that display the current date set but also here you know which will be the question :slight_smile:

M2_HLIST(el_date, NULL, list_date); --> should be the root for this menu ? which is the scope :slight_smile:

next piece of code:
M2_ROOT(el_dt_cancel, NULL, "cancel", &top_el_expandable_menu); --> Call something that bring you to the root ?
M2_BUTTON(el_dt_ok, NULL, "ok", dt_ok_fn); --> Call something that confirm the date and bring you to root ?

next piece of code:
M2_LIST(list_dt_buttons) = {&el_dt_cancel, &el_dt_ok };
M2_HLIST(el_dt_buttons, NULL, list_dt_buttons);
M2_LIST(list_dt) = {&el_date, &el_dt_buttons };
M2_VLIST(el_top_dt, NULL, list_dt);

So I think that my difficult is know the correct event to use and where use ...
So thanks again for teaching me :slight_smile: it's important for me ...

usually we I develop with .net is more simple because is graphically and you can search the function etc etc :slight_smile: thanks gnux

Schermata 2013-01-19 a 16.20.59.png

Hi

Well, ".net". You have unlimited memory for data and code. But here on the Arduino... everything has to fit into a very small amount of RAM and ROM. In fact, M2tklib puts all of the elements into PROGMEM to save RAM area. This makes the menu definition look a little bit strange.

void dt_ok_fn(m2_el_fnarg_p fnarg) 
{
  m2_SetRoot(&top_el_expandable_menu);
}

"m2_el_fnarg_p fnarg" can be ignored. But it is importent to have a proper function definition for the BUTTON callback, so for the BUTTON callback it must be there. There are some m2tklib procedures, which might get use of the fnarg pointer.
This callback is described here:
http://code.google.com/p/m2tklib/wiki/elref#BUTTON

"m2_SetRoot(&top_el_expandable_menu);" is the C interface. It is fully equivalent to m2.setRoot(&top_el_expandable_menu).
The set root procedure is described here:
http://code.google.com/p/m2tklib/wiki/fnref#setRoot

M2_U8NUM(el_dt_year, "c2", 0,99,&dt_year);

"c2" is the so called format string. It is described here: Google Code Archive - Long-term storage for Google Code Project Hosting.

The format option "c", which is used here depends on the actual element. Overview is given here: Google Code Archive - Long-term storage for Google Code Project Hosting.. But in this case we have a unsigned 8 bit data entry field, which is described (along with the "c2" format option) here: Google Code Archive - Long-term storage for Google Code Project Hosting.. Especially the last link explains "c2": It tells the element to display two digits.
"0,99" is the range (also described in the wiki)
"&dt_year" is a reference to the variable, so that m2tklib can modify the variable directly. Any user input is directly written into this variable.

M2_LIST(list_date) = { &el_dt_year, &el_dt_sep1, &el_dt_month, &el_dt_sep2, &el_dt_day };
M2_HLIST(el_date, NULL, list_date);

M2_LIST is not an element. It defines a list for a container element.
M2_HLIST is a container element. Elements refered in the corresponding list, are shown from left to right in a row. Again full description to gether with example is here: Google Code Archive - Long-term storage for Google Code Project Hosting.

M2_LIST and all other elements are macros (no function calls). They have all file local scope, but can be made global visible with the extern macro: M2_EXTERN_HLIST

BTW: Is the documentation clearly enough? Or do you see some optimization? For sure there is some optimization possible, but probably i need some advice how to improve the documentation.

M2_ROOT(el_dt_cancel, NULL, "cancel", &top_el_expandable_menu); --> Call something that bring you to the root ?

M2_ROOT appears as a push button. Once selected by the user it assignes the provided root element to the display. This makes top_el_expandable_menu visible to the user.

M2_BUTTON(el_dt_ok, NULL, "ok", dt_ok_fn); --> Call something that confirm the date and bring you to root ?

Same as M2_ROOT, but calls a procedure once selected. This is more flexible than M2_ROOT.

Hope this clarifies things a little bit

Oliver