diff --git a/main/CMakeLists.txt b/main/CMakeLists.txt index 3aac623..ae6cf28 100644 --- a/main/CMakeLists.txt +++ b/main/CMakeLists.txt @@ -9,6 +9,7 @@ set(COMPONENT_SRCS "scenes/scene_demo.c" "scenes/scene_bootanim.c" "scenes/scene_menu.c" + "scenes/scene_number.c" "scenes/scene_test_menu.c" "graphics/nokia.c" "graphics/utf8.c" diff --git a/main/liquid/liquid.c b/main/liquid/liquid.c index 3e3c70d..05352d7 100644 --- a/main/liquid/liquid.c +++ b/main/liquid/liquid.c @@ -56,8 +56,8 @@ static struct SceneEvent handleSceneEvent(struct Liquid *container, struct Scene SLIST_REMOVE_HEAD(&container->stack, next); tag = topmost->scene->tag; - if (topmost->scene->free) { - topmost->scene->free(topmost->scene); + if (topmost->scene->deinit) { + topmost->scene->deinit(topmost->scene); } free(topmost->scene); free(topmost); diff --git a/main/liquid/scene_type.h b/main/liquid/scene_type.h index ab03b3d..e254dfd 100644 --- a/main/liquid/scene_type.h +++ b/main/liquid/scene_type.h @@ -56,13 +56,13 @@ typedef struct SceneEvent (*Scene_init_t)(struct Scene *scene); typedef void (*Scene_paint_t)(struct Scene *scene); /** - * Scene::free fp type. + * Scene::deinit 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); +typedef void (*Scene_deinit_t)(struct Scene *scene); /** * Scene instance in the framework @@ -112,7 +112,7 @@ struct Scene { * Release internally allocated resources, if any. Called on close. * Nullable field. */ - Scene_free_t free; + Scene_deinit_t deinit; }; #endif //LIQUID_SCENE_TYPE_H diff --git a/main/scenes/scene_car.c b/main/scenes/scene_car.c index f84eb17..ba1f303 100644 --- a/main/scenes/scene_car.c +++ b/main/scenes/scene_car.c @@ -1,8 +1,9 @@ -#include "scenes.h" -#include "liquid.h" #include +#include #include "graphics/nokia.h" #include "graphics/drawing.h" +#include "scenes.h" +#include "liquid.h" struct CarScene { struct Scene base; diff --git a/main/scenes/scene_menu.c b/main/scenes/scene_menu.c index f947054..17a5eb8 100644 --- a/main/scenes/scene_menu.c +++ b/main/scenes/scene_menu.c @@ -55,11 +55,18 @@ static struct SceneEvent onInput(struct MenuScene *self, struct InputEvent event } } +static void deinit(struct MenuScene *self) +{ + free(self->items); + self->items = NULL; +} + struct MenuScene *NewScene_Menu(struct MenuItem *items, size_t items_len) { struct MenuScene *scene = calloc(1, sizeof(struct MenuScene)); scene->base.paint = (Scene_paint_t) paint; scene->base.onInput = (Scene_onInput_t) onInput; + scene->base.deinit = (Scene_deinit_t) deinit; scene->items = items; scene->items_len = items_len; diff --git a/main/scenes/scene_menu.h b/main/scenes/scene_menu.h index e0ae98a..c649c1d 100644 --- a/main/scenes/scene_menu.h +++ b/main/scenes/scene_menu.h @@ -7,6 +7,9 @@ #ifndef REFLOWER_SCENE_MENU_H #define REFLOWER_SCENE_MENU_H +#include +#include + #define MENUITEM_LABEL_LEN 30 struct MenuItem { @@ -30,6 +33,8 @@ struct MenuScene { int32_t selected; // selection handler MenuScene_onSelect_t onSelect; + // Extra field for the instance's private use. + void *private; }; struct MenuScene *NewScene_Menu(struct MenuItem *items, size_t items_len); diff --git a/main/scenes/scene_number.c b/main/scenes/scene_number.c new file mode 100644 index 0000000..058d86a --- /dev/null +++ b/main/scenes/scene_number.c @@ -0,0 +1,66 @@ +#include "scenes.h" +#include "liquid.h" +#include +#include +#include "graphics/nokia.h" +#include "graphics/drawing.h" +#include "scene_number.h" + +struct NumberScene { + struct Scene base; + struct NumberSceneOpts *opts; +}; + +static struct SceneEvent onInput(struct NumberScene *self, struct InputEvent event) { + struct NumberSceneOpts *opts = self->opts; + switch (event.kind) { + case InputEventKind_Wheel: + opts->value += event.wheel.delta; + + if (opts->value < opts->min) { + opts->value = opts->min; + } + else if (opts->value > opts->max) { + opts->value = opts->max; + } + + return SceneEvent_Repaint(); + + case InputEventKind_Button: + if (event.button.state) { + return SceneEvent_Close(opts->value, NULL); + } + // fall through + default: + return SceneEvent_None(); + } +} + +static void paint(struct NumberScene *self) +{ + struct NumberSceneOpts *opts = self->opts; + + LCD_clearDisplay(0); + LCD_setStrEx(opts->label, 1, 1, BLACK, FONT_BOLD); + + char buf[10]; + snprintf(buf, 10, "%d%s", opts->value, opts->unit); + LCD_setStrEx(buf, 1, 9, BLACK, FONT_DOUBLE); +} + +static void deinit(struct NumberScene *self) +{ + free(self->opts); + self->opts = NULL; +} + +struct Scene *NewScene_Number(struct NumberSceneOpts *opts) { + struct NumberScene *scene = calloc(1, sizeof(struct NumberScene)); + if (!scene) return NULL; + + scene->opts = opts; + scene->base.onInput = (Scene_onInput_t) onInput; + scene->base.paint = (Scene_paint_t) paint; + scene->base.deinit = (Scene_deinit_t) deinit; + return (struct Scene *) scene; +} diff --git a/main/scenes/scene_number.h b/main/scenes/scene_number.h new file mode 100644 index 0000000..a215cf8 --- /dev/null +++ b/main/scenes/scene_number.h @@ -0,0 +1,32 @@ +/** + * TODO file description + * + * Created on 2020/01/05. + */ + +#ifndef REFLOWER_SCENE_NUMBER_H +#define REFLOWER_SCENE_NUMBER_H + +#include + +struct NumberSceneOpts { + char label[15]; + char unit[8]; + int32_t value; + int32_t min; + int32_t max; +}; + +/** + * Create number picker. + * + * The result is passed back as status. + * + * "opts" must be on heap and will be internally mutated. + * + * @param opts + * @return + */ +struct Scene *NewScene_Number(struct NumberSceneOpts *opts); + +#endif //REFLOWER_SCENE_NUMBER_H diff --git a/main/scenes/scene_root.c b/main/scenes/scene_root.c index 5e541f7..839753e 100644 --- a/main/scenes/scene_root.c +++ b/main/scenes/scene_root.c @@ -21,7 +21,7 @@ static struct SceneEvent init(struct RootScene *self) return SceneEvent_OpenChild(NewScene_Boot(), 1); } -struct SceneEvent onChildReturn(struct RootScene *self, uint32_t tag, int32_t status, void *data) +static struct SceneEvent onChildReturn(struct RootScene *self, uint32_t tag, int32_t status, void *data) { if (tag == 1) { return SceneEvent_OpenChild(NewScene_MenuTest(), 0); diff --git a/main/scenes/scene_test_menu.c b/main/scenes/scene_test_menu.c index e2ade1d..8602f82 100644 --- a/main/scenes/scene_test_menu.c +++ b/main/scenes/scene_test_menu.c @@ -10,8 +10,14 @@ #include "scenes.h" #include "scene_menu.h" +struct Priv { + int32_t number; + Scene_deinit_t parent_deinit; +}; static struct SceneEvent onSelect(struct MenuScene *self) { + struct Priv *priv = self->private; + if (self->selected == 0) { return SceneEvent_Close(0, NULL); } @@ -22,24 +28,55 @@ static struct SceneEvent onSelect(struct MenuScene *self) { if (self->selected == 9) { return SceneEvent_OpenChild(NewScene_Demo(), 0); } + if (self->selected == 2) { + struct NumberSceneOpts *opts = calloc(1, sizeof(struct NumberSceneOpts)); + strcpy(opts->unit, "°C"); + strcpy(opts->label, "Setpoint"); + opts->value = priv->number; + opts->min = 0; + opts->max = 350; + return SceneEvent_OpenChild(NewScene_Number(opts), 99); + } if (self->selected == 5) { self->items[5].tag++; - snprintf(self->items[5].label, MENUITEM_LABEL_LEN, "Count = %d", self->items[5].tag); + snprintf(self->items[5].label, MENUITEM_LABEL_LEN, "Clicked %dx", self->items[5].tag); return SceneEvent_Repaint(); } return SceneEvent_None(); } +static void deinit(struct MenuScene *self) +{ + struct Priv *priv = self->private; + if (priv->parent_deinit) { + priv->parent_deinit((struct Scene *) self); + } + free(self->private); + self->private = NULL; +} + +static struct SceneEvent onChildReturn(struct MenuScene *self, uint32_t tag, int32_t status, void *data) +{ + struct Priv *priv = self->private; + if (tag == 99) { + priv->number = status; + snprintf(self->items[2].label, MENUITEM_LABEL_LEN, "Set=%d°C", priv->number); + } + + // this should be unreachable + return SceneEvent_None(); +} + struct Scene *NewScene_MenuTest() { struct MenuItem *items = calloc(10, sizeof(struct MenuItem)); strncpy(items[0].label, "🔙Back", MENUITEM_LABEL_LEN); strncpy(items[1].label, "▶#1", MENUITEM_LABEL_LEN); - strncpy(items[2].label, "▶#2", MENUITEM_LABEL_LEN); + strncpy(items[2].label, "Set=0°C", MENUITEM_LABEL_LEN); strncpy(items[3].label, "▶#3", MENUITEM_LABEL_LEN); strncpy(items[4].label, "▶#4", MENUITEM_LABEL_LEN); - strncpy(items[5].label, "Count = 0", MENUITEM_LABEL_LEN); + strncpy(items[5].label, "Clicked 0x", MENUITEM_LABEL_LEN); strncpy(items[6].label, "▶#6", MENUITEM_LABEL_LEN); strncpy(items[7].label, "▶#7", MENUITEM_LABEL_LEN); strncpy(items[8].label, "Car", MENUITEM_LABEL_LEN); @@ -48,5 +85,14 @@ struct Scene *NewScene_MenuTest() { struct MenuScene * scene = NewScene_Menu(items, 10); scene->onSelect = onSelect; + // private data added by the subclass + struct Priv *priv = calloc(1, sizeof(struct Priv)); + priv->number = 0; + priv->parent_deinit = scene->base.deinit; + scene->private = priv; + + scene->base.deinit = (Scene_deinit_t) deinit; + scene->base.onChildReturn = (Scene_onChildReturn_t) onChildReturn; + return (struct Scene *) scene; } diff --git a/main/scenes/scenes.h b/main/scenes/scenes.h index 8e01735..1bf2809 100644 --- a/main/scenes/scenes.h +++ b/main/scenes/scenes.h @@ -7,11 +7,15 @@ #ifndef REFLOWER_SCENES_H #define REFLOWER_SCENES_H +#include "scene_type.h" + struct Scene *NewScene_Root(void); struct Scene *NewScene_Boot(void); struct Scene *NewScene_Demo(void); struct Scene *NewScene_Car(void); - struct Scene *NewScene_MenuTest(void); +#include "scene_menu.h" +#include "scene_number.h" + #endif //REFLOWER_SCENES_H