-
Notifications
You must be signed in to change notification settings - Fork 11
t06u8g
How can low level graphics be combined with M2tklib?
This tutorial will show:
- How to show both, a menu and additional (animated) graphics.
- How to switch to a pure graphics page and how to return to a menu
The following picture shows a rectangle combined with a M2tk menu.
This tutorial will be divided into two parts:
- How to combine menus and graphics.
- How to switch between menu and graphics.
Reference: Code for this Tutorial is available in the "Graphics" example.
For further discussion, we will assume that there is a graphics procedure, which directly draws something on the screen. To be consistent with the "Graphics" example, this procedure puts some graphics at the provided x/y position:
void draw_rectangle(uint8_t x, uint8_t y) {
...
}
This procedure shell work completely independent from m2tklib. There is no call to any m2tklib procedures inside "rectangle".
A state machine will animate the graphics (update_rectangle
). If this state machine has modified the appearence of the graphics,
then the update_rectangle
procedure will return a none-zero value:
uint8_t update_rectangle(uint8_t x, uint8_t y) {
...
}
In general it is very easy to combine menus and graphics: Simply draw both, one after the other. For u8glib based graphics,
this is usually done in a draw()
procedure:
void draw(void) {
draw_rectangle(0,0);
m2.draw();
}
This draw()
procedure is called within the picture loop of U8glib. Together with M2tklib, the picture loop is only executed
if there was a change in the menu. Now, because of the animation of the rectangle, there will be an additional condition to update
the graphics screen update_rectangle() != 0
.
void loop() {
m2.checkKey();
if ( m2.handleKey() != 0 || update_rectangle() != 0 ) {
u8g.firstPage();
do {
draw();
} while( u8g.nextPage() );
}
}
This will make all graphics drawn by draw_rectangle()
available in all menus.
In some cases, it could be required to display something for specific menus or to display something different, depending on the current menu. The "getRoot" procedure can be used to get the current toplevel element. Depending on this toplevel-element, the additional graphics might be enabled or disabled. This concept can be implemented with two more procedures:
-
draw_graphics()
: Similar todraw_rectangle()
, but checks the current menu. Depending on the current menu, this draws the low level graphics. -
update_graphics()
: Similar toupdate_rectangle()
, but checks the current menu. This will only animate the graphics, if the graphics is visible.
Here is some code, which checks for a specific top-level menu:
void draw_graphics(void) {
// show the graphics depending on the current toplevel element
if ( m2.getRoot() == &el_combine ) {
// combine is active, add graphics
// menu is on the right, put the rectangle to the left
draw_rectangle(0,y);
}
...
}
The picture loop will now use the update_graphics()
to check for a refresh of the screen:
void loop() {
m2.checkKey();
if ( m2.handleKey() != 0 || update_graphics() != 0 ) {
u8g.firstPage();
do {
draw();
} while( u8g.nextPage() );
}
}
Goal is to disable the menu for some time and to show some custom graphics. This requires the ability to disable the menu, but keep the key detection alive. This will allow the program to wait for a key event, which enables the menu again.
To disable the menu, set&m2_null_element
as root element.
This could be done by the setRoot procedure or by the M2_ROOT element.
As a result, M2_ROOT
could be a button to switch to the graphics screen:
M2_ROOT(el_switch_to_graphics, NULL, "Show Graphics", &m2_null_element); // selecting this, will remove all menues
As discussed in the first part of this tutorial, there must be a parallel procedure, which checks for the menu state.
The graphics is displayed, if there is no other menu aktive (m2.getRoot() == &m2_null_element
).
void draw_graphics(void) {
// show the graphics depending on the current toplevel element
...
if ( m2.getRoot() == &m2_null_element ) {
// all menus are gone, show the rectangle
draw_rectangle(10,10);
}
}
As shown above, the update_graphics()
is called in the picture loop. Additionally we will put another important task
to this update_graphics()
:
- Check for any keypress event by calling
getKey
. - Assign a menu as root menu.
uint8_t update_graphics(void) {
if ( m2.getRoot() == &el_combine ) {
// combine is active, update the rectangle for animation
return update_rectangle();
}
if ( m2.getRoot() == &m2_null_element ) {
// check for any keys and assign a suitable menu again
if ( m2.getKey() != M2_KEY_NONE )
m2.setRoot(&el_top);
// all menus are gone, rectangle is shown, so do update
return update_rectangle();
}
// no update for the graphics required
return 0;
}
There are two important notes here:
-
getKey
must be called only ifm2_null_element
is the root element. Key events are always removed from the queue bygetKey
. As a result the user could not control any visible menu any more if the root element is something else thanm2_null_element
. - It is still required to call
checkKey
andhandleKey
to keep the key event and menu system aktive.
- Draw graphics in parallel to the m2tklib.
- For the combination of menus and graphics, use a xylist element to have a better control of the menu.
- Use "getRoot" to identify the active menu. This will allow to display graphics according to the active menu.
- Set
m2_null_element
as root element to remove all menus. - Only if there is no menu, you may use
getKey()
. - Always make calls to
handleKey()
.
- Previous Tutorial: Tutorial 5: Simultaneous Operation
- Wiki Start Page