By dave | November 12, 2020

Taking over the display from a renderer

TcMenu allows you to take over the display from the renderer very easily, once you own the display, you will be called back at regular intervals by the rendering class, and it is your responsibility to update the display at this time (if there are changes that require redrawing). You should never update the screen outside of these callbacks, as doing so would interfere with TcMenu rendering.

There are two choices in this case, a functional approach based on providing a callback function, or an object oriented approach, where you provide an extension of CustomDrawing to the renderer. Below we discuss both.

Functional approach to take over display

To use a regular function callback to take over the display:

renderer.takeOverDisplay(myDisplayCallback);

In this case must provide a method with the following signature:

// This will be called frequently by the renderer class
// here we give control back when the button is clicked.
void myDisplayCallback(unsigned int encoderValue, RenderPressMode clicked) {
    // At this point clicked is the status of the select button
    // it can be RPRESS_NONE, RPRESS_PRESSED or RPRESS_HELD
    // encoderValue is the current value of the rotary encoder
}

Once you own the display, the provided function will be called frequently by the renderer, you can check if anything needs drawing, and if so draw it at this point. You also have the current value of the rotary encoder available to you in encoderValue, along with the state of the encoder switch in clicked which is one of the values listed in the comment above.

When conditions change such that you no longer need display control:

renderer.giveBackDisplay();

Functional approach to capturing display timeout / reset

You can also add a callback function that will be informed when the menu is reset after timing out, by default this happens after 30 seconds of inactivity. This is useful if you don’t want to display the menu all the time. First define the function:

// this function will be called when the menu becomes inactive.
void onMenuBeingReset() {
    // for example in here we could take over the display when the
    // menu is inactive.
    renderer.takeOverDisplay(myDisplayFunction);
}

Then add the function as the callback:

renderer.setResetCallback(myResetCallback); 

If you want to change the threshold for becoming inactive:

renderer.setResetIntervalTimeSeconds(newResetTimeInSeconds);

Object oriented approach to display management

If we extend the class CustomDrawing and provide that instance to the renderer, then we can both handle taking over the display and reset events at the same time. See custom drawing class in reference docs. Here we present a simple way to extend it.

class MyCustomDrawing : public CustomDrawing {
public:
    virtual ~CustomDrawing() = default;

    void reset() override {
        // if we get here the display has been reset because
        // of a timeout of the user interface for example to
        // take over the display
        renderer.takeOverDisplay();
    }

    void started(BaseMenuRenderer* currentRenderer) override {
        // take over display has just been called, and we
        // now need to do any initial activity
        // for example here we may clear the display and 
        // print the title
        lcd.clear();
        lcd.print("Super Device");
    }

    void renderLoop(unsigned int currentValue, RenderPressMode userClick) override {
        // At this point clicked is the status of the select button
        // it can be RPRESS_NONE, RPRESS_PRESSED or RPRESS_HELD
        // encoderValue is the current value of the rotary encoder
        // for example to exit when the user clicks
        if(userClick) renderer.giveBackDisplay();
        // for example to update a menu based on current value of the encoder.
        // don't forget you could call changePrecision in started(..) 
        menuAnalogToAlter.setCurrentValue(currentValue);
    }
} myDrawingClass;

Once we’ve created an instance of the class (always at global scope), then we can pass this reference to the renderer as follows:

renderer.setCustomDrawingHandler(&myDrawingClass);

Then to take over the display, use the no parameter version of the method:

renderer.takeOverDisplay(); 

Other pages within this category

comments powered by Disqus

We use cookies to analyse traffic and to personalise content. We also embed Twitter, Youtube and Disqus content on some pages, these companies have their own privacy policies.

Please see our privacy policy should you need more information or wish to adjust your settings.