You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
115 lines
3.6 KiB
115 lines
3.6 KiB
#include "liquid.h"
|
|
#include "rom/queue.h"
|
|
#include "scenes.h"
|
|
#include <malloc.h>
|
|
#include <assert.h>
|
|
#include <esp_log.h>
|
|
|
|
static const char *TAG = "Liquid";
|
|
|
|
struct RunningScene {
|
|
struct Scene *scene;
|
|
SLIST_ENTRY(RunningScene) next;
|
|
} cmd_item_t;
|
|
|
|
struct Liquid {
|
|
SLIST_HEAD(, RunningScene) stack; // stack with the topmost scene as the first element / head
|
|
};
|
|
|
|
static struct SceneEvent Default_onChildReturn(struct Scene *scene, uint32_t tag, uint32_t status, void *data) {
|
|
if (data) free(data);
|
|
return SceneEvent_Repaint();
|
|
}
|
|
|
|
static void addChild(struct Liquid *container, struct Scene *child) {
|
|
struct RunningScene *elm = calloc(1, sizeof(struct RunningScene));
|
|
if (!child->onChildReturn) child->onChildReturn = Default_onChildReturn;
|
|
assert(child->paint != NULL);
|
|
elm->scene = child;
|
|
SLIST_INSERT_HEAD(&container->stack, elm, next);
|
|
}
|
|
|
|
struct Liquid *Liquid_start() {
|
|
struct Liquid *container = calloc(1, sizeof(struct Liquid));
|
|
|
|
addChild(container, NewScene_Root());
|
|
Liquid_paint(container);
|
|
return container;
|
|
}
|
|
|
|
static struct SceneEvent handleSceneEvent(struct Liquid *container, struct SceneEvent event) {
|
|
struct RunningScene *topmost = SLIST_FIRST(&container->stack);
|
|
switch (event.kind) {
|
|
case SceneEventKind_Close:
|
|
assert(SLIST_NEXT(topmost, next) != NULL);
|
|
SLIST_REMOVE_HEAD(&container->stack, next);
|
|
uint32_t tag = topmost->scene->tag;
|
|
|
|
if (topmost->scene->options) {
|
|
free(topmost->scene->options);
|
|
}
|
|
free(topmost->scene);
|
|
free(topmost);
|
|
|
|
topmost = SLIST_FIRST(&container->stack);
|
|
|
|
// this is always set.
|
|
return topmost->scene->onChildReturn(topmost->scene, tag, event.close.status, event.close.data);
|
|
|
|
case SceneEventKind_OpenChild:;
|
|
if (!event.open.scene) {
|
|
ESP_LOGE(TAG, "Attempt to open NULL scene!");
|
|
return SceneEvent_None();
|
|
}
|
|
struct Scene *newScene = event.open.scene;
|
|
newScene->tag = event.open.tag;
|
|
addChild(container, newScene);
|
|
return SceneEvent_Repaint();
|
|
|
|
case SceneEventKind_RequestRepaint:
|
|
case SceneEventKind_None:
|
|
default:
|
|
// this shouldn't get here
|
|
return event;
|
|
}
|
|
}
|
|
|
|
bool processReturnValue(struct Liquid *container, struct SceneEvent result) {
|
|
while (result.kind != SceneEventKind_None) {
|
|
if (result.kind == SceneEventKind_RequestRepaint) {
|
|
return 1; // repaint
|
|
}
|
|
result = handleSceneEvent(container, result);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
bool Liquid_handleInput(struct Liquid *container, struct InputEvent event) {
|
|
struct RunningScene *topmost = SLIST_FIRST(&container->stack);
|
|
assert(topmost != NULL);
|
|
assert(topmost->scene != NULL);
|
|
if (topmost->scene->onInput) {
|
|
struct SceneEvent result = topmost->scene->onInput(topmost->scene, event);
|
|
return processReturnValue(container, result);
|
|
} else {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
bool Liquid_handleTick(struct Liquid *container) {
|
|
struct RunningScene *topmost = SLIST_FIRST(&container->stack);
|
|
assert(topmost != NULL);
|
|
assert(topmost->scene != NULL);
|
|
if (topmost->scene->onTick) {
|
|
struct SceneEvent result = topmost->scene->onTick(topmost->scene);
|
|
return processReturnValue(container, result);
|
|
} else {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
void Liquid_paint(struct Liquid *container) {
|
|
struct RunningScene *topmost = SLIST_FIRST(&container->stack);
|
|
assert(topmost != NULL);
|
|
topmost->scene->paint(topmost->scene);
|
|
}
|
|
|