Skip to content
olikraus edited this page Oct 24, 2016 · 2 revisions

Tutorial 6 (U8g library): Low Level Graphics

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.

http://wiki.m2tklib.googlecode.com/hg/pic/u8g/u8g_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.

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 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) {
  ...
}

Combine M2tk and Graphics

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.

Combine Specific M2tk Menus and Graphics

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 to draw_rectangle(), but checks the current menu. Depending on the current menu, this draws the low level graphics.
  • update_graphics(): Similar to update_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() );
  }
}

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 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);
  }
}

Return to the Menu

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 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 if the root element is something else than m2_null_element.
  • It is still required to call checkKey and handleKey to keep the key event and menu system aktive.

Conclusion

  • 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().

Links

Clone this wiki locally