Skip to content

Multi-Screen App

This example shows how to build a small application with two separate screens and navigate between them.
The key function is mgui_widget_free_screen() — it destroys the current screen and all its children, freeing the memory so the next screen can be created cleanly.


Screenshot


Overview

┌─────────────────────┐         button click          ┌─────────────────────┐
│       App 1         │  ─────────────────────────►  │       App 2         │
│  "Go to App 2"      │                               │  "Go to App 1"      │
│      [Button]       │  ◄─────────────────────────  │      [Button]       │
└─────────────────────┘         button click          └─────────────────────┘

mgui_widget_free_screen() tears down the current screen before the next one is initialised.


Full Example

#include "gui/inc/mgui_hal.h"
#include "gui/inc/mgui_interface.h"

#define SCREEN_WIDTH  240
#define SCREEN_HEIGHT 240

/* ── Forward declarations ───────────────────────────────────────── */
void app1_init(void);
void app2_init(void);

/* ── Screens (only one is alive at a time) ──────────────────────── */
static mgui_widget_t* screen1 = NULL;
static mgui_widget_t* screen2 = NULL;

/* ══════════════════════════════════════════════════════════════════
   APP 1
   ══════════════════════════════════════════════════════════════════ */

static void go_to_app2(mgui_widget_t* obj, mgui_event_t event)
{
    (void)obj;
    if (event != MGUI_EVENT_CLICKED) return;

    /* Free App 1 and its entire widget tree */
    mgui_widget_free_screen(&screen1);

    /* Build App 2 */
    app2_init();
}

void app1_init(void)
{
    screen1 = mgui_allocate_widget(
        NULL,
        MGUI_WIDGET_BOX,
        (mgui_area_t){0, 0, SCREEN_WIDTH, SCREEN_HEIGHT},
        MGUI_COLOR_DARK_GRAY
    );

    /* Title label */
    mgui_widget_t* title = mgui_allocate_widget(
        screen1, MGUI_WIDGET_LABEL,
        (mgui_area_t){0, 60, SCREEN_WIDTH, 30},
        MGUI_COLOR_WHITE
    );
    mgui_widget_align(title, MGUI_ALIGN_TOP_CENTER);
    mgui_widget_label_set_text(title, "App 1");

    /* Navigation button */
    mgui_widget_t* btn = mgui_allocate_widget(
        screen1, MGUI_WIDGET_BUTTON,
        (mgui_area_t){70, 140, 100, 40},
        MGUI_COLOR_DEFAULT
    );
    mgui_widget_button_text(btn, "Go to App 2");
    mgui_widget_click_handler(btn, go_to_app2);
}

/* ══════════════════════════════════════════════════════════════════
   APP 2
   ══════════════════════════════════════════════════════════════════ */

static void go_to_app1(mgui_widget_t* obj, mgui_event_t event)
{
    (void)obj;
    if (event != MGUI_EVENT_CLICKED) return;

    /* Free App 2 */
    mgui_widget_free_screen(&screen2);

    /* Rebuild App 1 */
    app1_init();
}

void app2_init(void)
{
    screen2 = mgui_allocate_widget(
        NULL,
        MGUI_WIDGET_BOX,
        (mgui_area_t){0, 0, SCREEN_WIDTH, SCREEN_HEIGHT},
        MGUI_COLOR_NAVY
    );

    /* Title label */
    mgui_widget_t* title = mgui_allocate_widget(
        screen2, MGUI_WIDGET_LABEL,
        (mgui_area_t){0, 60, SCREEN_WIDTH, 30},
        MGUI_COLOR_WHITE
    );
    mgui_widget_align(title, MGUI_ALIGN_TOP_CENTER);
    mgui_widget_label_set_text(title, "App 2");

    /* Navigation button */
    mgui_widget_t* btn = mgui_allocate_widget(
        screen2, MGUI_WIDGET_BUTTON,
        (mgui_area_t){70, 140, 100, 40},
        MGUI_COLOR_DEFAULT
    );
    mgui_widget_button_text(btn, "Go to App 1");
    mgui_widget_click_handler(btn, go_to_app1);
}

/* ══════════════════════════════════════════════════════════════════
   ENTRY POINT
   ══════════════════════════════════════════════════════════════════ */

int main(void)
{
    mgui_init(SCREEN_WIDTH, SCREEN_HEIGHT, MGUI_BUFFER_SIZE_KB, 30);

    app1_init();    /* start with App 1 */

    while (1) {
        mgui_task_execute();
        delay_ms(33);
    }

    return 0;
}

Key Points

mgui_widget_free_screen(&screen)

void mgui_widget_free_screen(mgui_widget_t** screen);
  • Frees the screen widget and every child in the tree (buttons, labels, images, …).
  • Sets *screen to NULL so stale pointers are detected immediately.
  • Call this before creating the next screen to avoid running out of widget memory.

One screen at a time

Only one screen should exist at any moment.
The pattern is always:

mgui_widget_free_screen(&current_screen);   /* destroy old screen */
next_screen_init();                          /* build new screen   */

See Also