/** * GUI framework * * Created on 2020/01/03. */ #ifndef REFLOWER_LIQUID_H #define REFLOWER_LIQUID_H #include #include struct Liquid; enum InputEvent_Kind { InputEventKind_Wheel, InputEventKind_Button, }; struct InputEvent { enum InputEvent_Kind kind; union { struct { // Wheel delta int32_t delta; } wheel; struct { // Button state bool state; } button; }; }; static inline struct InputEvent InputEvent_Wheel(int32_t delta) { return (struct InputEvent) { .kind = InputEventKind_Wheel, .wheel = {.delta = delta} }; } /** * Button event (push, release) * * @param state - pushed * @return event */ static inline struct InputEvent InputEvent_Button(bool state) { return (struct InputEvent) { .kind = InputEventKind_Button, .button = {.state = state}, }; } enum SceneEvent_Kind { SceneEventKind_Close, SceneEventKind_OpenChild, SceneEventKind_RequestRepaint, SceneEventKind_None, }; // forward declaration struct Scene; /** * Scene event, returned from some scene methods. * * Use the constructor functions to create this struct. */ struct SceneEvent { /** Event kind enum */ enum SceneEvent_Kind kind; union { /* data for Close event kind */ struct { // Status code int32_t status; // Return data on heap void *data; } close; /* Data for Open event kind */ struct { // Scene (initialized, with options loaded in through the constructor) struct Scene *scene; // Tag used by parent to identify the open child uint32_t tag; } open; }; }; /** * Create empty (null object) scene event. * * @return event */ static inline struct SceneEvent SceneEvent_None(void) { return (struct SceneEvent) { .kind = SceneEventKind_None, }; } /** * Request scene repaint * * @return event */ static inline struct SceneEvent SceneEvent_Repaint(void) { return (struct SceneEvent) { .kind = SceneEventKind_RequestRepaint }; } /** * Request a sub-scene to be opened * * @param child - child scene * @param tag - scene tag * @return event */ static inline struct SceneEvent SceneEvent_OpenChild(struct Scene *child, uint32_t tag) { return (struct SceneEvent) { .kind = SceneEventKind_OpenChild, .open = { .scene = child, .tag=tag }, }; } /** * Close this scene, returning to parent. * * @param status - status number for the parent * @param data - heap-allocated data for parent, can be NULL; e.g. user input as string. * @return event */ static inline struct SceneEvent SceneEvent_Close(int32_t status, void *data) { return (struct SceneEvent) { .kind = SceneEventKind_Close, .close = {.status = status, .data=data}, }; } /** * Scene::onInput fp type - handle user input * * @param scene - self * @param event - the input event * @return follow-up scene event, can be SceneEvent_None() if not used. */ typedef struct SceneEvent (*Scene_onInput_t)(struct Scene *scene, struct InputEvent event); /** * Scene::onChildReturn fp type * * @param scene - self * @param tag - child's tag * @param status - status code returned from the child * @param data - data returned from the child, must be heap-allocated if not NULL. * @return follow-up scene event, can be SceneEvent_None() if not used. */ typedef struct SceneEvent (*Scene_onChildReturn_t)(struct Scene *scene, uint32_t tag, int32_t status, void *data); /** * Scene::onTick fp type * * @param scene - self * @return follow-up scene event, can be SceneEvent_None() if not used. */ typedef struct SceneEvent (*Scene_onTick_t)(struct Scene *scene); /** * Scene::paint fp type * * @param scene - self */ typedef void (*Scene_paint_t)(struct Scene *scene); /** * Scene::free fp type. * Release internally allocated resources. * This is called by the GUI engine when the scene is closed. * * @param scene - self */ typedef void (*Scene_free_t)(struct Scene *scene); /** * Scene instance in the framework */ struct Scene { /** * Tag given to the scene by its parent to identify its close event. */ uint32_t tag; /** * Handle input event. * Can return a follow-up scene event, e.g. repaint request. * Nullable field. */ Scene_onInput_t onInput; /** * Child scene closed, handle its return value and data, if any. * Can return a follow-up scene event. * In any case, the scene will be re-painted, if it stays open and on top. * Nullable field. */ Scene_onChildReturn_t onChildReturn; /** * Handle a periodic tick (10ms). * Can return a follow-up scene event, e.g. repaint request. * Nullable field. */ Scene_onTick_t onTick; /** * Draw the scene to the LCD buffer. * DO NOT write to the display yet, it will be done by the GUI engine. * * MANDATORY FIELD */ Scene_paint_t paint; /** * Release internally allocated resources, if any. Called on close. * Nullable field. */ Scene_free_t free; }; /** return 1 if repaint requested */ bool Liquid_handleInput(struct Liquid *container, struct InputEvent event); /** return 1 if repaint requested */ bool Liquid_handleTick(struct Liquid *container); /** render the active scene */ void Liquid_paint(struct Liquid *container); /** Initialize the GUI system with a root scene */ struct Liquid *Liquid_start(void); #endif //REFLOWER_LIQUID_H