M2TKLIB - Dynamic Menu structure

Hi there,
I'm building a lillte Menu for a programm of a friend and got a little bit lost will figureing out the structure of M2TKLIB.
What I need is a Menü to set the time of RTC and a large number of lights with values and times.

Mainscreen
-- Set Clock
-- -- Time / Date
-- Dimming
-- -- Light 1
-- -- -- Time 1
-- -- -- -- Set time / value 
-- -- -- Time 2
-- -- -- -- Set time / value 
-- -- -- Time 3
-- -- -- -- Set time / value 
.....
-- -- -- Time 10
-- -- -- -- Set time / value 
-- -- Light 2
-- -- -- Time 1
-- -- -- -- Set time / value 
-- -- -- Time 2
-- -- -- -- Set time / value 
-- -- -- Time 3
-- -- -- -- Set time / value 
.....
-- -- -- Time 10
-- -- -- -- Set time / value 
...
-- -- Light 8

Allright,
so I have 2 main Menu Points and dimming has 8 Lights with 10 times the same "Set" Screen. I can programm this without problems as a static Menu, but I want to save space so my try is:
declare 1 Light Menu-point, 1 time, 1 setScreen, then let the menu handle the rest. :wink:
I tried M2_STRLIST to generate the menu but this only worked for 1 level and i can't find out how to jump to deeper level or back.
With 2LMENU I can hardcode it but this is not what i want...
Also, and this is last need i have to know where i am within the menu so i can save the changes to 2 2dimension array:
mylight[Light][Time].time="settime";
mylight[Light][Time].time="value";

Can someone point me into the right direction which elements to use to build a menu like this?

THX in advance,
Moritz

Hi

Did you had a look at the PWMPinList example?
There is also a tutorial for this: Google Code Archive - Long-term storage for Google Code Project Hosting.

Source for PWMPinList is here:
https://code.google.com/p/m2tklib/source/browse/arduino/u8g/PWMPinList/PWMPinList.pde

Idea is similar: Have one dialog, that controlls different I/O pins.

Oliver

Hi Oliver,
thx for the quick respons. Well, yes I checked also the PWMPinList but as far as I figured out it is a M2_STRLIST with callback const char pin_list_cb(**). Then I got lost and tried the other M"_STRLIST Example. :smiley:
But, to get it right (I'm at work atm):
I have the

M2_STRLIST(el_pin_list_strlist, "l3W56", &pin_list_first, &pin_list_cnt, pin_list_cb);

which sets up the Channels (Light 1-8) and within the callback

 if ( msg == M2_STRLIST_MSG_SELECT ) {
........ /*somecode */
    // give control to the pwm dialog
    m2.setRoot(&el_top_pwm_menu);

I set up a new M2_STRLIST for Time 1-10.

As a quick draw of the menu:

/* setup last level */
M2_LABEL(el_time_label, NULL, "Zeit:");
M2_U8NUM(el_time_num, "r1c2", 0, 255, &time_menu_pin);
M2_LABEL(el_time_value_label, NULL, "Value: ");
M2_U8NUM(el_time_value, "r1c2", 0, 255, pwm_fn_duty);
M2_ROOT(el_time_cancel, "f4", "Cancel", &top_el_time_list);
M2_BUTTON(el_time_ok, "f4", "Ok", time_fn_ok);

/* define numbers of elements */
uint8_t light_list_first = 0;
uint8_t light_list_cnt = 8;
uint8_t time_list_first = 0;
uint8_t time_list_cnt = 10;

/* callback procedure for STRLIST element Light -> menulevel2 */
const char *light_list_cb(uint8_t idx, uint8_t msg) {
  static char s[12];
  s[0] = '\0';
  if ( msg == M2_STRLIST_MSG_SELECT ) {
    light_menu_current_index = idx;
    light_prepare_user_input();
    m2.setRoot(&top_el_time_list);        // On Select call List for times
  } else {
    // convert the idx into some readable line for the user
    strcpy(s, "light ");
    strcpy(s+4, m2_utl_u8d(light_light_array[idx], 2));
  }
  return s;
}
/* callback procedure for STRLIST element time-> menulevel3 */
const char *time_list_cb(uint8_t idx, uint8_t msg) {
  static char s[12];
  s[0] = '\0';
  if ( msg == M2_STRLIST_MSG_SELECT ) {
    time_menu_current_index = idx;
    time_prepare_user_input();
    m2.setRoot(&el_top_value_menu);
  } else {
    strcpy(s, "time ");
    strcpy(s+4, m2_utl_u8d(time_time_array[idx], 2));
  }
  return s;
}

// selection menu for the lights, composed of a STRLIST 
M2_STRLIST(el_light_list_strlist, "l3W56", &light_list_first, &light_list_cnt, light_list_cb);
M2_SPACE(el_light_list_space, "W1h1");
M2_VSB(el_light_list_vsb, "l3W4r1", &light_list_first, &light_list_cnt);
M2_LIST(list_light_list) = { &el_light_list_strlist, &el_light_list_space, &el_light_list_vsb };
M2_HLIST(el_light_list_hlist, NULL, list_light_list);
M2_ALIGN(top_el_light_list, "-1|1W64H64", &el_light_list_hlist);

// selection menu for the Times, composed of a STRLIST 
M2_STRLIST(el_time_list_strlist, "l3W56", &time_list_first, &time_list_cnt, time_list_cb);
M2_SPACE(el_time_list_space, "W1h1");
M2_VSB(el_time_list_vsb, "l3W4r1", &time_list_first, &time_list_cnt);
M2_LIST(list_time_list) = { &el_time_list_strlist, &el_time_list_space, &el_time_list_vsb };
M2_HLIST(el_time_list_hlist, NULL, list_time_list);
M2_ALIGN(top_el_time_list, "-1|1W64H64", &el_time_list_hlist);

// Root Element
M2_LABEL(el_goto_title, NULL, "Menu");
M2_ROOT(el_goto_setClock, NULL, "Clock", &el_setClock);
M2_ROOT(el_goto_setLights, NULL, "Dim", &top_el_light_list);
M2_LIST(list_menu) = {&el_goto_title, &el_goto_setLights, &el_goto_setClock};
M2_VLIST(el_menu_vlist, NULL, list_menu);
M2_ALIGN(el_top, "W64H64", &el_menu_vlist);

I know there is still missing a lot and this will not work, but just for my basic understanding of how to structure it:
Mainmenu ->el_top
-- Setup Clock ->el_setClock
-- List for Lights -> top_el_light_list
-- -- List of times ->top_el_time_list
-- -- -- Change values ->el_top_value_menu

onSave -> time_fn_ok

void pwm_fn_ok(m2_el_fnarg_p fnarg) {
mylights[light_menu_current_index][time_menu_current_index].value = ????;
mylights[light_menu_current_index][time_menu_current_index].time = ????;
  
  // go back to parent menu
  m2.setRoot(&top_el_time_list);
}

greetings Moritz

Hi Moritz

It is a little bit difficult for me to understand your nested graphcs. Mybe you should just draw some pictures on some paper and implement menues according to them.

The main difference to your initial approach should be, that you have an additional index for each light or time.

Assume you have a list of 10 light (not sure whether i understood your application). You select a specific time from the M2_STRLIST (of course you could also let the user enter a number between 1 and 10 with M2_U8NUM)

Then, based on this selected STRLIST entry or the selected U8NUM number, you jump to a sub menu, where the user can modify and store the parameters for the specified light (index).

Oliver

Hi Oliver,
I have a root Level with 2 Entrys: Clock and Light. Clock is no problem so let's talk just about menu point light:
I have 8 lights and each light has 10 times where i can set a time and a value. For example:
light1->time1->10:00/100%,time2->11:00/70%,time3->15:00/10%...
light2->time1->9:00/80%,time2->13:00/100%,time3->17:00/30%...
up to light8

I'll try with my understanding and your hints and if I get it I show you or ask for more help. :smiley:

Sure, please ask.
Another way is to implement dialog boxes according to the data structures:

struct timevalue
{
uint8_t hour;
uint8_t min;
uint8_t value;
}

struct light
{
struct timevalue tv_array[10];
};

struct light light_array[8];

The main menu should allow you to select one of the lights (e.g. STRLIST).
Another menu is for the light. It probably is only another STRLIST for the selection of the timevalue dialog.
Finally there is one more dialog for the time and value (percent).

So, only three dialog boxes are requred.

Oliver

I'm done just this moment. :smiley:
It's not perfect and not everything is working 100% but here it is:

#include "U8glib.h"
#include "M2tk.h"
#include "utility/m2utl.h"
#include "utility/m2ghu8g.h"
#include "config.h"

U8GLIB_SSD1306_128X32 u8g(U8G_I2C_OPT_NONE); // HW SPI Com: CS = 10, A0 = 9 (Hardware Pins are  SCK = 13 and MOSI = 11)
uint8_t hour=0;
uint8_t minute=0;
uint8_t value=0;
uint8_t led_menu_current_index = 0;
uint8_t time_menu_current_index = 0;

#define LED_NUM 4
#define TIME_NUM 10
//=================================================
// forward declaration
extern M2tk m2;
M2_EXTERN_ALIGN(top_el_time_list);
M2_EXTERN_GRIDLIST(set_led_grid);
M2_EXTERN_ALIGN(top_el_led_list);
M2_EXTERN_GRIDLIST(top_el_clock_screen);
M2_EXTERN_ALIGN(el_top_menu);


/************        Set LED Screen             *************/

void dt_ok_set_led(m2_el_fnarg_p fnarg)  {
  m2_SetRoot(&top_el_time_list);
}
// Zeit       
M2_U8NUM(el_li_hour, "c2", 1,31,&hour);
M2_LABEL(el_li_sep1, "b1", ":");                // dot is drawn on the baseline
M2_U8NUM(el_li_minute, "c2", 1,12,&minute);
M2_LIST(list_time) = { &el_li_hour, &el_li_sep1, &el_li_minute};
M2_HLIST(el_time, NULL, list_time);
// Value
M2_U8NUM(el_li_val, "r1c2", 0, 100, &value);
M2_LABEL(el_li_sep2, "b1", "%");    
M2_LIST(list_value) = { &el_li_val, &el_li_sep2};
M2_HLIST(el_value, NULL, list_value);    
// Buttons
M2_ROOT(el_dt_cancel, NULL, "cancel", &top_el_time_list);
M2_BUTTON(el_dt_ok, NULL, "ok", dt_ok_set_led);

M2_LABEL(el_dt_time, "b1", "Zeit"); 
M2_LABEL(el_dt_level, "b1", "Level"); 
M2_LIST(set_led_grid_list) = { 
    &el_dt_time, &el_time, 
    &el_dt_level, &el_value, 
    &el_dt_ok, &el_dt_cancel 
};
M2_GRIDLIST(set_led_grid, "c2",set_led_grid_list);
/*********************       END LED SCREEN         ***********************************/

/*********************       Liste Zeiten           ***********************************/
uint8_t time_list_first = 0;
uint8_t time_list_cnt = TIME_NUM;

// callback procedure for the STRLIST element
const char *time_list_cb(uint8_t idx, uint8_t msg) {
  static char s[12];
  s[0] = '\0';
  if ( msg == M2_STRLIST_MSG_SELECT ) {
    time_menu_current_index = idx;
    // Call Werte setzen Grid
    m2.setRoot(&set_led_grid);
  } else {
    strcpy(s, "Zeit ");
    strcpy(s+5, m2_utl_u8d(idx+1,2));
  }
  return s;
}

// selection menu for the pins, composed of a STRLIST element with a scroll bar
M2_STRLIST(el_time_list_strlist, "l3W56", &time_list_first, &time_list_cnt, time_list_cb);
M2_SPACE(el_time_list_space, "W1h1");
M2_VSB(el_time_list_vsb, "l3W4r1", &time_list_first, &time_list_cnt);
M2_LIST(list_time_list) = { &el_time_list_strlist, &el_time_list_space, &el_time_list_vsb };
M2_HLIST(el_time_list_hlist, NULL, list_time_list);
M2_ALIGN(top_el_time_list, "-1|1W64H64", &el_time_list_hlist);

/*********************       END ZEIT LISTE         ***********************************/

/*********************       Liste LED's           ***********************************/
uint8_t led_list_first = 0;
uint8_t led_list_cnt = LED_NUM;

// callback procedure for the STRLIST element
const char *led_list_cb(uint8_t idx, uint8_t msg) {
  static char s[6];
  s[0] = '\0';
  if ( msg == M2_STRLIST_MSG_SELECT ) {
    led_menu_current_index = idx;
    // call time List
    m2.setRoot(&top_el_time_list);
  } else {
    // convert the idx into some readable line for the user
    strcpy(s, "LED ");
    strcpy(s+4, m2_utl_u8d(idx+1,2));
  }
  return s;
}

// selection menu for the pins, composed of a STRLIST element with a scroll bar
M2_STRLIST(el_led_list_strlist, "l3W56", &led_list_first, &led_list_cnt, led_list_cb);
M2_SPACE(el_led_list_space, "W1h1");
M2_VSB(el_led_list_vsb, "l3W4r1", &led_list_first, &led_list_cnt);
M2_LIST(list_led_list) = { &el_led_list_strlist, &el_led_list_space, &el_led_list_vsb };
M2_HLIST(el_led_list_hlist, NULL, list_led_list);
M2_ALIGN(top_el_led_list, "-1|1W64H64", &el_led_list_hlist);

/*********************       END LED LISTE         ***********************************/


/*********************       Zeit Einstellen           ***********************************/

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

void dt_clock_ok(m2_el_fnarg_p fnarg)  {
  m2_SetRoot(&el_top_menu);
}
// Zeit
M2_U8NUM(el_clock_hour, "c2", 0,24,&dt_hour);
M2_LABEL(el_clock_sep1, "b1", ":");
M2_U8NUM(el_clock_minute, "c2", 0,59,&dt_minute);

M2_LIST(list_clock_time) = { &el_clock_hour, &el_clock_sep1, &el_clock_minute };
M2_HLIST(el_clock_time, NULL, list_clock_time);

// Datum
M2_U8NUM(el_clock_day, "c2", 1,31,&dt_day);
M2_LABEL(el_clock_sep2, "b1", ".");                // dot is drawn on the baseline
M2_U8NUM(el_clock_month, "c2", 1,12,&dt_month);
M2_LABEL(el_clock_sep3, "b0", ".");                // dot will be too low 
M2_U8NUM(el_clock_year, "c2", 0,99,&dt_year);

M2_LIST(list_clock_date) = { &el_clock_day, &el_clock_sep2, &el_clock_month, &el_clock_sep3, &el_clock_year };
M2_HLIST(el_clock_date, NULL, list_clock_date);

M2_ROOT(el_clock_cancel, NULL, "cancel", &el_top_menu);
M2_BUTTON(el_clock_ok, NULL, "ok", dt_clock_ok);

M2_LABEL(el_dt_clock_time, "b1", "Zeit"); 
M2_LABEL(el_dt_clock_date, "b1", "Datum"); 
M2_LIST(set_clock_grid_list) = { 
    &el_dt_clock_time, &el_clock_time, 
    &el_dt_clock_date, &el_clock_date, 
    &el_clock_ok, &el_clock_cancel 
};
M2_GRIDLIST(top_el_clock_screen, "c2",set_clock_grid_list);

/*********************       END ZEIT EINSTELLEN         ***********************************/


//=================================================
M2_LABEL(el_menu_title, NULL, "Menu");
M2_ROOT(el_menu_itm1, NULL, "Zeit", &top_el_clock_screen);
M2_ROOT(el_menu_itm2, NULL, "Licht", &top_el_led_list);
M2_LIST(list_menu) = {&el_menu_title, &el_menu_itm1, &el_menu_itm2};
M2_VLIST(el_menu_vlist, NULL, list_menu);
M2_ALIGN(el_top_menu, "W64H64", &el_menu_vlist);

// m2 object and constructor
M2tk m2(&el_top_menu, m2_es_arduino_rotary_encoder, m2_eh_4bd, m2_gh_u8g_bf);

//=================================================
// Draw procedure, Arduino Setup & Loop


void draw(void) {
  m2.draw();
}

void setup(void) {
  // Connect u8glib with m2tklib
  m2_SetU8g(u8g.getU8g(), m2_u8g_box_icon);

  // Assign u8g font to index 0
  m2.setFont(0, u8g_font_7x13r);

  // define button for the select message
  m2.setPin(M2_KEY_SELECT, 2);          // dogm128 shield, 2nd from top
  
  // The incremental rotary encoder is conected to these two pins
  m2.setPin(M2_KEY_ROT_ENC_A, A1);
  m2.setPin(M2_KEY_ROT_ENC_B, A0);
}

void loop() {
  // check rotary encoder also inside the picture loop
  m2.checkKey();  
  // process events and redraw menu if required
  if ( m2.handleKey() != 0 ) {
    u8g.firstPage();  
    do {
      // check rotary encoder also inside the picture loop
      m2.checkKey();
      // draw menu
      m2.draw();
    } while( u8g.nextPage() );
  }
}

atm I can't select the value or get one level up from strlst, but this will be easy to figure out.
I'm kinda scared this "small" menu takes up 22.144 Bytes. I have just a Nano and I think there is not enough space for the rest of the code. Maybe it needs some tweaking or i try your solution with 2 dialoges next.
But at least it works now.

One more the display is a lilbit "off". do you know how to fix this? (see picture)
Nevermind... found it:
To modify the offset of the display, modify line 191 in u8g_dev_ssd1306_128x32.c:
0x000, / set lower 4 bit of the col adr. to 4 /
Try 0x002 or 0x004 instead of the 0x000

You can reduce the space between the elements. See here: Google Code Archive - Long-term storage for Google Code Project Hosting.
You may also need to use a smaller font to make your dialog box fit to the display.

To save some RAM/ROM you could reuse the format strings, like "b1".

Oliver

useing the right constructor fixed my display problem. :wink: U8GLIB_SSD1306_128X64 instead of U8GLIB_SSD1306_128X32...

with the rom i have to see. maybe it fits. But how to jump up on level from M2_STRLIST? I think I have to declare a new element of type M2_ROOT with callback to the upper menu level. Within Rapunzel you used a M2_INFOP with callback to go up, atm I search M2_STRLIST_MSG_GET_EXTENDED_STR and similar for a way. This libary is just massive and has so many optins... Awesome work you did! I own you a beer whenever you're close to Ruhrgebiet. :smiley:

Ruhrgebiet... I see..

Grüße vom Exilfranken im Schwabenland

Hey,
just merged my exiting code with the menu and: 39.014 Bytes (126%) of Maximum 30.720 Bytes. :-X Not so good... I def have to reduse a lot of space, but how? I tried using u8g_font_5x8r instead of 7x13r, but this saved only 100bytes. So I def have to save ~4kb within the menu structure...
Atm I have:

void loop()
{

  time = rtc.getTime();
  setLight(); // Calls Dimming and other stuff

  // check rotary encoder also inside the picture loop
  m2.checkKey();
  // Mainscreen
 
  if ( m2.getRoot() == &m2_null_element ) {
    do {
      m2.checkKey();
      draw_main_screen();

    } while (u8g.nextPage());
    if (m2.getKey()== M2_KEY_SELECT){
        m2.setRoot(&el_top_menu);
    }
  } else if ( m2.handleKey() != 0 ) {
      u8g.firstPage();
      do {
        // check rotary encoder also inside the picture loop
        m2.checkKey();
        // draw menu
        m2.draw();
      } while ( u8g.nextPage() );
    }
}

and menu.h (menu structure file):

//=================================================
// forward declaration
extern M2tk m2;
M2_EXTERN_ALIGN(top_el_time_list);
M2_EXTERN_GRIDLIST(set_led_grid);
M2_EXTERN_ALIGN(top_el_led_list);
M2_EXTERN_GRIDLIST(top_el_clock_screen);
M2_EXTERN_ALIGN(el_top_menu);
/************        Set LED Screen             *************/

void dt_ok_set_led(m2_el_fnarg_p fnarg)  {
  light_channels[led_menu_current_index][time_menu_current_index].time=get_ts(time.hour,time.min,0);
  light_channels[led_menu_current_index][time_menu_current_index].level;
  m2_SetRoot(&top_el_time_list);
}
M2_LABEL(label_sep1, "b1", ":");
M2_LABEL(label_sep2, "b1", ".");    
M2_LABEL(label_sep3, "b1", "%");    
// Zeit       
M2_U8NUM(el_li_hour, "c2", 0,24,&time.hour);      // dot is drawn on the baseline
M2_U8NUM(el_li_minute, "c2", 0,59,&time.min);
M2_LIST(list_time) = { &el_li_hour, &label_sep1, &el_li_minute};
M2_HLIST(el_time, NULL, list_time);
// Value
M2_U8NUM(el_li_val, "c3", 0, 100, &curLedVal[led_menu_current_index]);
M2_LIST(list_value) = { &el_li_val, &label_sep3};
M2_HLIST(el_value, "b1", list_value);    
// Buttons
M2_ROOT(el_dt_cancel, "b1", "cancel", &top_el_time_list);
M2_BUTTON(el_dt_ok, "b1", "ok", dt_ok_set_led);

M2_LABEL(el_dt_time, "b1", "Zeit"); 
M2_LABEL(el_dt_level, "b1", "Level"); 
M2_LIST(set_led_grid_list) = { 
    &el_dt_time, &el_time, 
    &el_dt_level, &el_value, 
    &el_dt_ok, &el_dt_cancel 
};
M2_GRIDLIST(set_led_grid, "c2",set_led_grid_list);
/*********************       END LED SCREEN         ***********************************/

/*********************       Liste Zeiten           ***********************************/
uint8_t time_list_first = 0;
uint8_t time_list_cnt = LIGHT_VALUES;

// callback procedure for the STRLIST element
const char *time_list_cb(uint8_t idx, uint8_t msg) {
  static char s[12];
  s[0] = '\0';
  if ( msg == M2_STRLIST_MSG_SELECT ) {
    time_menu_current_index = idx;
    // Call Werte setzen Grid
    m2.setRoot(&set_led_grid);
  } else {
    strcpy(s, "Zeit ");
    strcpy(s+5, m2_utl_u8d(idx+1,2));
  }
  return s;
}

// selection menu for the pins, composed of a STRLIST element with a scroll bar
M2_STRLIST(el_time_list_strlist, "l3W56", &time_list_first, &time_list_cnt, time_list_cb);
M2_SPACE(el_time_list_space, "W1h1");
M2_VSB(el_time_list_vsb, "l3W4r1", &time_list_first, &time_list_cnt);
M2_LIST(list_time_list) = { &el_time_list_strlist, &el_time_list_space, &el_time_list_vsb };
M2_HLIST(el_time_list_hlist, NULL, list_time_list);
M2_ALIGN(top_el_time_list, "-1|1W64H64", &el_time_list_hlist);

/*********************       END ZEIT LISTE         ***********************************/

/*********************       Liste LED's           ***********************************/
uint8_t led_list_first = 0;
uint8_t led_list_cnt = LIGHT_CHANEL;

// callback procedure for the STRLIST element
const char *led_list_cb(uint8_t idx, uint8_t msg) {
  static char s[6];
  s[0] = '\0';
  if ( msg == M2_STRLIST_MSG_SELECT ) {
    led_menu_current_index = idx;
    // call time List
    m2.setRoot(&top_el_time_list);
  } else {
    // convert the idx into some readable line for the user
    strcpy(s, "LED ");
    strcpy(s+4, m2_utl_u8d(idx+1,2));
  }
  return s;
}

// selection menu for the pins, composed of a STRLIST element with a scroll bar
M2_STRLIST(el_led_list_strlist, "l3W56", &led_list_first, &led_list_cnt, led_list_cb);
M2_SPACE(el_led_list_space, "W1h1");
M2_VSB(el_led_list_vsb, "l3W4r1", &led_list_first, &led_list_cnt);
M2_LIST(list_led_list) = { &el_led_list_strlist, &el_led_list_space, &el_led_list_vsb };
M2_HLIST(el_led_list_hlist, NULL, list_led_list);
M2_ALIGN(top_el_led_list, "-1|1W64H64", &el_led_list_hlist);

/*********************       END LED LISTE         ***********************************/

void dt_clock_ok(m2_el_fnarg_p fnarg)  {
  m2_SetRoot(&el_top_menu);
}
// Zeit
M2_U8NUM(el_clock_hour, "c2", 0,24,&time.hour);
M2_U8NUM(el_clock_minute, "c2", 0,59,&time.min);

M2_LIST(list_clock_time) = { &el_clock_hour, &label_sep1, &el_clock_minute };
M2_HLIST(el_clock_time, NULL, list_clock_time);

// Datum
M2_U8NUM(el_clock_day, "c2", 1,31,&time.date);
M2_U8NUM(el_clock_month, "c2", 1,12,&time.mon);
M2_U32NUM(el_clock_year, "c4",&time.year);

M2_LIST(list_clock_date) = { &el_clock_day, &label_sep2, &el_clock_month, &label_sep2, &el_clock_year };
M2_HLIST(el_clock_date, NULL, list_clock_date);

M2_ROOT(el_clock_cancel, "b1", "cancel", &el_top_menu);
M2_BUTTON(el_clock_ok, "b1", "ok", dt_clock_ok);

M2_LABEL(el_dt_clock_time, "b1", "Zeit"); 
M2_LABEL(el_dt_clock_date, "b1", "Datum"); 
M2_LIST(set_clock_grid_list) = { 
    &el_dt_clock_time, &el_clock_time, 
    &el_dt_clock_date, &el_clock_date, 
    &el_clock_ok, &el_clock_cancel 
};
M2_GRIDLIST(top_el_clock_screen, "c2",set_clock_grid_list);

/*********************       END ZEIT EINSTELLEN         ***********************************/


//=================================================
M2_LABEL(el_menu_title, "b1", "Menu");
M2_ROOT(el_menu_itm1, "b1", "Zeit", &top_el_clock_screen);
M2_ROOT(el_menu_itm2, "b1", "Licht", &top_el_led_list);
M2_LIST(list_menu) = {&el_menu_title, &el_menu_itm1, &el_menu_itm2};
M2_VLIST(el_menu_vlist, NULL, list_menu);
M2_ALIGN(el_top_menu, "W64H64", &el_menu_vlist);

How to save space within this? Maybe reduse to 1 menu for "Licht" and use a L2MENU or some other scrollable list wich takes less programm memory? I tried a lot within the structure now but every effort didn't save enough.

THX again for hints into right direction. :wink:

Hi

Let us analyse the problem more closely. First we need to know what is actually inside the code.
For this please locate the .elf file in the build directory.
The build dir is given in the log files, when you enable verbose mode in the GUI for compilation.
Output will be like this (ok, i use the german version on a linux system):

/home/kraus/prg/arduino-1.6.0/hardware/tools/avr/bin/avr-ar rcs /tmp/build222651609606791210.tmp/core.a /tmp/build222651609606791210.tmp/WMath.cpp.o 
/home/kraus/prg/arduino-1.6.0/hardware/tools/avr/bin/avr-ar rcs /tmp/build222651609606791210.tmp/core.a /tmp/build222651609606791210.tmp/HardwareSerial3.cpp.o 
/home/kraus/prg/arduino-1.6.0/hardware/tools/avr/bin/avr-gcc -w -Os -Wl,--gc-sections -mmcu=atmega328p -o /tmp/build222651609606791210.tmp/Blink.cpp.elf /tmp/build222651609606791210.tmp/Blink.cpp.o /tmp/build222651609606791210.tmp/core.a -L/tmp/build222651609606791210.tmp -lm 
/home/kraus/prg/arduino-1.6.0/hardware/tools/avr/bin/avr-objcopy -O ihex -j .eeprom --set-section-flags=.eeprom=alloc,load --no-change-warnings --change-section-lma .eeprom=0 /tmp/build222651609606791210.tmp/Blink.cpp.elf /tmp/build222651609606791210.tmp/Blink.cpp.eep 
/home/kraus/prg/arduino-1.6.0/hardware/tools/avr/bin/avr-objcopy -O ihex -R .eeprom /tmp/build222651609606791210.tmp/Blink.cpp.elf /tmp/build222651609606791210.tmp/Blink.cpp.hex 

Der Sketch verwendet 1.030 Bytes (3%) des Programmspeicherplatzes. Das Maximum sind 32.256 Bytes.
Globale Variablen verwenden 9 Bytes (0%) des dynamischen Speichers, 2.039 Bytes für lokale Variablen verbleiben. Das Maximum sind 2.048 Bytes.

So the build is done inside /tmp/build....
There you find the .elf file.

Then create the disassembly file:
/hardware/tools/avr/bin/avr-objdump -d .elf > output.dis

Attach the result (output.dis) here. We should analyse this more closely to see where we can save some space.

Oliver

To bad, I sit at a Windows Machine... :angry: allways have errors while try to dump -d "a.out:no such file".
I'll send you a pn with complete temp build folder. :wink:

I also tested yesterday to do a Flat Menü strukture with a X2LMENU. This was also 40kb, so 2 kb more then 2 STRLST and ROOT item. With just one large STRLST with 42 entries I had 39kb.