t06glcd - olikraus/m2tklib GitHub Wiki

Tutorial 6: Low Level Graphics

How can low level graphics be combined with M2tklib?

This tutorial will show:

  • How to show both, a menu and additional graphics.
  • How to switch to a pure graphics page and how to return to a menu (requires v1.04)

The following picture shows a rectangle combined with a M2tk menu.

https://github.com/bj0rky/m2tklibwiki/blob/master/glcd_combined_graphics.jpg

This tutorial will be divided into two parts:

  1. How to combine menus and graphics.
  2. How to switch between menu and graphics.

Reference: Code for this Tutorial is available in the "Graphics" example (v1.04).

A simple graphics procedure

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 rectangle(uint8_t x, uint8_t y) {
  ...
}

This procedure shell work completely independent from m2tklib. There is not call to any m2tklib procedures inside "rectangle".

Combine Menues and Graphics

In general it is very easy to combine menus and graphics: Simply draw both, one after the other:

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

void loop(void) {
  menu();
  rectangle(0, 0);
}

This will make all graphics drawn by "rectangle" available in all menus.

In some cases, it could be required not 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:

void 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
      rectangle(0,y);
  }
  ...
}

Now, the graphics and menu can be combined:

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

In this loop, the following happens:

  1. Draw low-level graphics on the screen (see procedure above)
  2. Execute event loop for the menu

Switch to Graphics Page

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.

Disable the Menu

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

Show Graphics

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 graphics(void) {
  // show the graphics depending on the current toplevel element
  
  ...
  
  if ( m2.getRoot() == &m2_null_element ) {
      // all menus are gone, show the rectangle
      rectangle(10,10);
      // now check for any keys and assign a suitable menu again
      if ( m2.getKey() != M2_KEY_NONE )
        m2.setRoot(&el_top);
  }
}

Return to the Menu

The example above already shows how to return to a menu:

  • Check for any keypress event by calling getKey.
  • Assign a menu as root menu.

There are two important notes here:

  • getKey must be called only if m2_null_element is the root element. Key events are always removed from the queue by getKey. As a result the user could not control any visible menu any more.
  • It is still required to call checkKey and handleKey to keep the key event and menu system aktive. This means, the following code is wrong:
// THIS CODE IS WRONG, THIS WILL NOT WORK
m2.checkKey();
if ( m2.getRoot() == &m2_null_element ) {
  // do something else on the screen
  if ( m2.getKey() != M2_KEY_NONE )
    m2.setRoot(&el_top);
} 
else {
  if ( m2.handleKey() ) {
      m2.draw();
  }
}

Instead, use the following:

if ( m2.getRoot() == &m2_null_element ) {
  // do something else on the screen
  if ( m2.getKey() != M2_KEY_NONE )
    m2.setRoot(&el_top);
} 

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

Conclusion

  • Draw graphics in parallel to the m2tklib "draw()" procedure.
  • 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().

Links