m2tklib - exit button question

Hi!

I am using this amazing m2tklib for Arduino for my project, but there's one thing I can't figure out. The exit button - is there a way to make it go back to previous menu (sort of like M2_ROOT)? For me it just deselects anything that has been selected.

Thanks!

is there a way to make it go back to previous menu

Yes. My crystal ball says your problem is on line 4236324725782585246461347634. Fix that, and all will be good.

PaulS:
Yes. My crystal ball says your problem is on line 4236324725782585246461347634. Fix that, and all will be good.

I'm sorry, I didn't think it was important since it's not really a bug but a matter of configuring the library (if it supports that at all).

This is the code with the menu (I had to use pastebin because the post only allowed 9000 characters).

The menu looks like this:

Nothing special / complex for now, but an exit button would be really handy instead of clicking multiple times to reach a virtual button.

Library links:
forum
google code
github

I had to use pastebin because the post only allowed 9000 characters

I don't (can't) do rubbish bin, looking for code. Using Reply (not the Quick Reply field). Below the text entry field, use the Additional Options link (yes, I know it doesn't look like a link) to attach your code here.

Okay, here it is.

UserInteface.h (8.93 KB)

Hi

There is no "Go to the previous Menu" button/function. Instead M2tklib only has goto-like jumps. But maybe you should more precisly descibe your problem, so that i can give more precise answers.

Oliver

PS: I usually only monitor the Display subsection of this forum.

olikraus:
Hi

There is no "Go to the previous Menu" button/function. Instead M2tklib only has goto-like jumps. But maybe you should more precisly descibe your problem, so that i can give more precise answers.

Oliver

PS: I usually only monitor the Display subsection of this forum.

Im sorry, only after I already posted the thread have I realized that it would be more appropriate to post it into display subsection, but I couldnt't find a delete thread button and I didn't want to doublepost :\

Oh, I see. I thought there was something to configure (like adding info to each submenu were "back/exit" actually should lead).
What I need is to be able to go back to previous menu by pressing "exit" button. I am adding a graphics only "page" that will come before that first menu and I would really like to avoid adding an entry named "exit" at the end of menu. It just seems unpractical. And for the other menus I would like to save the space for that "exit" or "cancel" button.

Would I be right to think that this functionality can be added somewhere by

if (m2.getKey() == M2_KEY_EXIT) {
 if (m2.getRoot() == &top_el_mellody_menu) {
 m2.setRoot(&top_el_main_menu);
 }
 else if (m2.getRoot() == &top_el_ring_menu) {
 m2.setRoot(&top_el_main_menu);
 }
 else if (m2.getRoot() == &top_el_manual_strike_menu) {
 m2.setRoot(&top_el_main_menu);
 }
 }

P.S.: I struggled a bit at first but when I put everything together in my mind I realized how awesome your library really is. Thank you!

Im sorry, only after I already posted the thread have I realized that it would be more appropriate to post it into display subsection, but I couldnt't find a delete thread button and I didn't want to doublepost :\

You can click the "Report to moderator" link in any post in a thread, and ask that the thread be moved to another section.

PaulS:
You can click the "Report to moderator" link in any post in a thread, and ask that the thread be moved to another section.

Thanks, I'll remember this one!

Hi

Several solution come in to my mind:

Home-Menu
If M2_KEY_HOME is pressed, m2tklib will jump to the element, specified with

void M2tk::setHome(m2_rom_void_p element)

Drawback: This is only one fixed menu.

Root-Change-Function
You can register a root change function with

void M2tk::setRootChangeCallback(m2_root_change_fnptr cb)

This function is always called if root changes. It would be easy to store the last menu here...

m2_rom_void_p  last_menu;
void root_change_cb(m2_rom_void_p new_root, m2_rom_void_p old_root, uint8_t change_value)
{
  last_menu = old_root;
}

Then just jump to the last menu: m2.setRoot(last_menu);

There should be the "Bookmarks" example which demonstrates these things.

Oliver

Edit: Fixed setHome2

olikraus:
Hi

Several solution come in to my mind:

Home-Menu
If M2_KEY_HOME is pressed, m2tklib will jump to the element, specified with

void M2tk::setHome2(m2_rom_void_p element)

Drawback: This is only one fixed menu.

Root-Change-Function
You can register a root change function with

void M2tk::setRootChangeCallback(m2_root_change_fnptr cb)

This function is always called if root changes. It would be easy to store the last menu here...

m2_rom_void_p  last_menu;

void root_change_cb(m2_rom_void_p new_root, m2_rom_void_p old_root, uint8_t change_value)
{
  last_menu = old_root;
}




Then just jump to the last menu: m2.setRoot(last_menu);

There should be the "Bookmarks" example which demonstrates these things.

Oliver

Hmm, so if I understand correctly:

  1. Home button is pressed
  2. The callback function is called
  3. I can "redirect" the home button to another menu (previous menu in my case)

Can I use m2.checkKey() within that callback function to check whether Home button triggered the event or not and only act in that case?

You assign a menu with

void M2tk::setHome(my_toplevel_menu);

The HOME button will always automatically jump to that menu once the HOME button is pressed. Nothing else needs to be done.

However, you may need to use the six button handler.

Of course you could assign the last menu at any time with setHome()

Oliver

olikraus:
You assign a menu with

void M2tk::setHome(my_toplevel_menu);

The HOME button will always automatically jump to that menu once the HOME button is pressed. Nothing else needs to be done.

However, you may need to use the six button handler.

Of course you could assign the last menu at any time with setHome()

Oliver

Thanks! With your help I managed to achieve what I wanted. Now the home button serves as "back" button.

m2_rom_void_p getParent(m2_rom_void_p root)
{
	if (root == &top_el_main_menu)
		return &m2_null_element;
	else if (root == &top_el_mellody_menu)
		return &top_el_main_menu;
	else if (root == &top_el_ring_menu)
		return &top_el_main_menu;
	else if (root == &top_el_manual_strike_menu)
		return &top_el_main_menu;
	return &m2_null_element;
}

void root_change_cb(m2_rom_void_p new_root, m2_rom_void_p old_root, uint8_t change_value)
{
	m2.setHome(getParent(new_root));
}

void setupUI()
{
	// Setup pins
	pinMode(uiKeyUpPin, INPUT_PULLUP);
	pinMode(uiKeyDownPin, INPUT_PULLUP);
	pinMode(uiKeySelectPin, INPUT_PULLUP);
	pinMode(uiKeyHomePin, INPUT_PULLUP);

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

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

	// Setup keys
	m2.setPin(M2_KEY_SELECT, uiKeySelectPin);
	m2.setPin(M2_KEY_PREV, uiKeyUpPin);
	m2.setPin(M2_KEY_NEXT, uiKeyDownPin);
	m2.setPin(M2_KEY_HOME, uiKeyHomePin);

	// Set menu for the HOME key
	m2.setHome(&m2_null_element);

	// Register a root change callback procedure
	m2.setRootChangeCallback(root_change_cb);
}

There's just one more thing that's giving me trouble. I can't make it to default to the null root at start (the graphics page). I tried

M2tk m2(&m2_null_element, m2_es_arduino, m2_eh_4bs, m2_gh_u8g_fb);

but it still showed me the menu first. Then I tried

void setupUI()
{
	...
	m2.setRoot(&m2_null_element);
}

and still, didn't work. Am I missing something?

Quite frankly I don't completely understand the importance of

M2_EXTERN_ALIGN(top_el_main_menu);

Does this have to be used on the top element?

Hi

If the initial null element does not work, then maybe you overwrite this somewhere after the init.

The M2_EXTERN is required if you want to use an element before it is defined. It is not related to the top element. However it is related to the sequence of elements. If you define the child elements first and the top element at the end, you may want to jump to the top element from the child elements. However the name of the top element is not yet known, because it is defined after the child element in the Arduino code. To solve this, you have to use the M2_EXTERN declaration. It you change the sequence and define the top element first and then the child elements, then you have to apply the extern declaration to all of the child elements.

For more precise definitions see here:

Oliver

olikraus:
Hi

If the initial null element does not work, then maybe you overwrite this somewhere after the init.

The M2_EXTERN is required if you want to use an element before it is defined. It is not related to the top element. However it is related to the sequence of elements. If you define the child elements first and the top element at the end, you may want to jump to the top element from the child elements. However the name of the top element is not yet known, because it is defined after the child element in the Arduino code. To solve this, you have to use the M2_EXTERN declaration. It you change the sequence and define the top element first and then the child elements, then you have to apply the extern declaration to all of the child elements.

For more precise definitions see here:
http://www.geeksforgeeks.org/understanding-extern-keyword-in-c/

Oliver

Well I looked through the code again and the only potentially problematic part is this one (for switching between graphical page and menus). But I dont see how it could be causing the menu to be forced first :confused:. Is it possible that during initialization the button is registered as pressed and swiches to the menu?

// update graphics, will return none-zero if an update is required
uint8_t update_graphics(void)
{
	if (m2.getRoot() == &m2_null_element) {
		// check for any keys and assign a suitable menu again
		if (m2.getKey() != M2_KEY_NONE) {
			m2.setRoot(&top_el_main_menu);
		}

		// all menus are gone, graphic(s) is/are shown, so do update
		return update_clock();
	}

	// no update for the graphics required
	return 0;
}

Ah, I understand this extern_align now, thanks for the explanation!

UserInteface.h (12.3 KB)