diff --git a/main/CMakeLists.txt b/main/CMakeLists.txt index 324bd0e..3aac623 100644 --- a/main/CMakeLists.txt +++ b/main/CMakeLists.txt @@ -8,6 +8,8 @@ set(COMPONENT_SRCS "scenes/scene_car.c" "scenes/scene_demo.c" "scenes/scene_bootanim.c" + "scenes/scene_menu.c" + "scenes/scene_test_menu.c" "graphics/nokia.c" "graphics/utf8.c" "graphics/font.c" diff --git a/main/liquid/gui.c b/main/liquid/gui.c index ffee3ee..63573ac 100644 --- a/main/liquid/gui.c +++ b/main/liquid/gui.c @@ -52,14 +52,17 @@ static void __attribute__((noreturn)) gui_thread(void *arg) { uint32_t last_wheel_time = 0; + uint32_t last_time = xTaskGetTickCount(); while (1) { bool want_repaint = false; uint32_t value = 0; xTaskNotifyWait(0, ULONG_MAX, &value, pdMS_TO_TICKS(10)); + uint32_t time = xTaskGetTickCount(); if (value & 0b10000) { // TICK - want_repaint |= Liquid_handleTick(liquid); + want_repaint |= Liquid_handleTick(liquid, time - last_time); + last_time = time; } if (value & 0b1000) { @@ -69,7 +72,6 @@ static void __attribute__((noreturn)) gui_thread(void *arg) { } if (value & 0b11) { - uint32_t time = xTaskGetTickCount(); uint32_t increment = 1; // wheel delta changes with speed if (last_wheel_time != 0) { diff --git a/main/liquid/input_event.h b/main/liquid/input_event.h index 8758c19..5316fa3 100644 --- a/main/liquid/input_event.h +++ b/main/liquid/input_event.h @@ -7,6 +7,8 @@ #ifndef LIQUID_INPUT_EVENT_H #define LIQUID_INPUT_EVENT_H +#include + enum InputEvent_Kind { InputEventKind_Wheel, InputEventKind_Button, @@ -18,6 +20,7 @@ struct InputEvent { struct { // Wheel delta int32_t delta; + int8_t direction; } wheel; struct { // Button state @@ -30,7 +33,10 @@ static inline struct InputEvent InputEvent_Wheel(int32_t delta) { return (struct InputEvent) { .kind = InputEventKind_Wheel, - .wheel = {.delta = delta} + .wheel = { + .delta = delta, + .direction = delta > 0 ? 1 : -1, + } }; } diff --git a/main/liquid/liquid.c b/main/liquid/liquid.c index ee5e65d..3e3c70d 100644 --- a/main/liquid/liquid.c +++ b/main/liquid/liquid.c @@ -119,12 +119,12 @@ bool Liquid_handleInput(struct Liquid *container, struct InputEvent event) { } } -bool Liquid_handleTick(struct Liquid *container) { +bool Liquid_handleTick(struct Liquid *container, uint32_t elapsed_millis) { 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); + struct SceneEvent result = topmost->scene->onTick(topmost->scene, elapsed_millis); return processReturnValue(container, result); } else { return false; diff --git a/main/liquid/liquid.h b/main/liquid/liquid.h index e969619..2fd291a 100644 --- a/main/liquid/liquid.h +++ b/main/liquid/liquid.h @@ -19,7 +19,7 @@ struct Liquid; bool Liquid_handleInput(struct Liquid *container, struct InputEvent event); /** return 1 if repaint requested */ -bool Liquid_handleTick(struct Liquid *container); +bool Liquid_handleTick(struct Liquid *container, uint32_t elapsed_millis); /** render the active scene */ void Liquid_paint(struct Liquid *container); diff --git a/main/liquid/scene_type.h b/main/liquid/scene_type.h index 4d9ab82..ab03b3d 100644 --- a/main/liquid/scene_type.h +++ b/main/liquid/scene_type.h @@ -38,7 +38,7 @@ typedef struct SceneEvent (*Scene_onChildReturn_t)(struct Scene *scene, uint32_t * @param scene - self * @return follow-up scene event, can be SceneEvent_None() if not used. */ -typedef struct SceneEvent (*Scene_onTick_t)(struct Scene *scene); +typedef struct SceneEvent (*Scene_onTick_t)(struct Scene *scene, uint32_t millis); /** * Scene::init fp type diff --git a/main/scenes/scene_bootanim.c b/main/scenes/scene_bootanim.c index e6921d4..edc0ae1 100644 --- a/main/scenes/scene_bootanim.c +++ b/main/scenes/scene_bootanim.c @@ -2,27 +2,26 @@ #include #include -#include "scenes.h" #include "liquid.h" -#include "analog.h" -#include "graphics/nokia.h" #include "graphics/drawing.h" +#define BOOTANIM_TIME_MS 100 + struct BootScene { struct Scene base; uint32_t cnt; }; -static struct SceneEvent Boot_onTick(struct BootScene *self) { - self->cnt += 10; // ms - if (self->cnt == 2000) { +static struct SceneEvent onTick(struct BootScene *self, uint32_t millis) { + self->cnt += millis; // ms + if (self->cnt >= BOOTANIM_TIME_MS) { return SceneEvent_Close(0, NULL); } return SceneEvent_None(); } -static void Boot_paint(struct BootScene *self) +static void paint(struct BootScene *self) { LCD_clearDisplay(0); LCD_setBitmap(Bitmap_Get("boot_logo")->bytes); @@ -30,7 +29,7 @@ static void Boot_paint(struct BootScene *self) struct Scene *NewScene_Boot(void) { struct BootScene *scene = calloc(1, sizeof(struct BootScene)); - scene->base.paint = (Scene_paint_t) Boot_paint; - scene->base.onTick = (Scene_onTick_t) Boot_onTick; + scene->base.paint = (Scene_paint_t) paint; + scene->base.onTick = (Scene_onTick_t) onTick; return (struct Scene *) scene; } diff --git a/main/scenes/scene_car.c b/main/scenes/scene_car.c index fee175e..f84eb17 100644 --- a/main/scenes/scene_car.c +++ b/main/scenes/scene_car.c @@ -9,7 +9,7 @@ struct CarScene { int32_t pos; }; -static struct SceneEvent Car_onInput(struct CarScene *self, struct InputEvent event) { +static struct SceneEvent onInput(struct CarScene *self, struct InputEvent event) { switch (event.kind) { case InputEventKind_Wheel: self->pos += event.wheel.delta; @@ -27,7 +27,7 @@ static struct SceneEvent Car_onInput(struct CarScene *self, struct InputEvent ev } } -static void Car_paint(struct CarScene *self) +static void paint(struct CarScene *self) { LCD_clearDisplay(0); LCD_setRect(self->pos, LCD_HEIGHT/2-10, self->pos+20,LCD_HEIGHT/2+10,0,1); @@ -38,7 +38,7 @@ struct Scene *NewScene_Car(void) { struct CarScene *scene = calloc(1, sizeof(struct CarScene)); if (!scene) return NULL; - scene->base.onInput = (Scene_onInput_t) Car_onInput; - scene->base.paint = (Scene_paint_t) Car_paint; + scene->base.onInput = (Scene_onInput_t) onInput; + scene->base.paint = (Scene_paint_t) paint; return (struct Scene *) scene; } diff --git a/main/scenes/scene_demo.c b/main/scenes/scene_demo.c index 027a325..b57d9a0 100644 --- a/main/scenes/scene_demo.c +++ b/main/scenes/scene_demo.c @@ -19,7 +19,7 @@ struct DemoScene { uint32_t timer_prescale; }; -static struct SceneEvent Demo_onInput(struct DemoScene *self, struct InputEvent event) { +static struct SceneEvent onInput(struct DemoScene *self, struct InputEvent event) { switch (event.kind) { case InputEventKind_Wheel: self->pos += event.wheel.delta; @@ -35,11 +35,11 @@ static struct SceneEvent Demo_onInput(struct DemoScene *self, struct InputEvent return SceneEvent_Repaint(); } -static struct SceneEvent Demo_onTick(struct DemoScene *self) { +static struct SceneEvent onTick(struct DemoScene *self, uint32_t millis) { // top text anim - self->timer_prescale += 1; + self->timer_prescale += millis; - if (self->timer_prescale == 100) { + if (self->timer_prescale == 1000) { self->timer_prescale = 0; self->timer_phase += 1; self->timer_phase = self->timer_phase & 0b11; // 0..3 @@ -50,7 +50,7 @@ static struct SceneEvent Demo_onTick(struct DemoScene *self) { return SceneEvent_None(); } -static void Demo_paint(struct DemoScene *self) +static void paint(struct DemoScene *self) { LCD_clearDisplay(0); @@ -85,8 +85,9 @@ static void Demo_paint(struct DemoScene *self) struct Scene *NewScene_Demo(void) { struct DemoScene *scene = calloc(1, sizeof(struct DemoScene)); - scene->base.onInput = (Scene_onInput_t) Demo_onInput; - scene->base.paint = (Scene_paint_t) Demo_paint; - scene->base.onTick = (Scene_onTick_t) Demo_onTick; + scene->base.onInput = (Scene_onInput_t) onInput; + scene->base.paint = (Scene_paint_t) paint; + scene->base.onTick = (Scene_onTick_t) onTick; + scene->base.onInput = (Scene_onInput_t) onInput; return (struct Scene *) scene; } diff --git a/main/scenes/scene_menu.c b/main/scenes/scene_menu.c new file mode 100644 index 0000000..f947054 --- /dev/null +++ b/main/scenes/scene_menu.c @@ -0,0 +1,68 @@ +#include +#include +#include +#include +#include + +#include "liquid.h" +#include "graphics/drawing.h" + +#include "scene_menu.h" + +static void paint(struct MenuScene *self) +{ + LCD_clearDisplay(0); + + int row = 0; + for (int i = self->scroll_up; i < MIN(self->items_len, self->scroll_up + 6); i++, row++) { + bool selected = self->selected==i; + LCD_setStrEx(self->items[i].label, 0, row * 8, selected?WHITE:BLACK,FONT_NORMAL|(selected?FONT_BG:0)); + } +} + +static struct SceneEvent onInput(struct MenuScene *self, struct InputEvent event) { + switch (event.kind) { + case InputEventKind_Wheel:; + self->selected += event.wheel.direction; + if (self->selected < 0) { + self->selected = 0; + } + else if (self->selected >= self->items_len) { + self->selected = self->items_len - 1; + } + + // hacky scroll adjust + while (self->selected - self->scroll_up < 1 && self->scroll_up > 0) { + self->scroll_up--; + } + + while (self->selected - self->scroll_up >= 5 && self->scroll_up < self->items_len - 6) { + self->scroll_up++; + } + + return SceneEvent_Repaint(); + + case InputEventKind_Button: + if (event.button.state) { + if (self->onSelect) { + return self->onSelect(self); + } + return SceneEvent_Close(0, NULL); + } + // fall through + default: + return SceneEvent_None(); + } +} + +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->items = items; + scene->items_len = items_len; + + return scene; +} diff --git a/main/scenes/scene_menu.h b/main/scenes/scene_menu.h new file mode 100644 index 0000000..e0ae98a --- /dev/null +++ b/main/scenes/scene_menu.h @@ -0,0 +1,37 @@ +/** + * TODO file description + * + * Created on 2020/01/05. + */ + +#ifndef REFLOWER_SCENE_MENU_H +#define REFLOWER_SCENE_MENU_H + +#define MENUITEM_LABEL_LEN 30 + +struct MenuItem { + char label[MENUITEM_LABEL_LEN]; + uint32_t tag; +}; + +struct MenuScene; + +typedef struct SceneEvent (*MenuScene_onSelect_t)(struct MenuScene *scene); + +struct MenuScene { + struct Scene base; + // items array + struct MenuItem *items; + // items count + size_t items_len; + // Vertical scroll offset (how many steps is the topmost item moved above the screen) + int32_t scroll_up; + // Selected item number + int32_t selected; + // selection handler + MenuScene_onSelect_t onSelect; +}; + +struct MenuScene *NewScene_Menu(struct MenuItem *items, size_t items_len); + +#endif //REFLOWER_SCENE_MENU_H diff --git a/main/scenes/scene_root.c b/main/scenes/scene_root.c index 7f3e5e4..5e541f7 100644 --- a/main/scenes/scene_root.c +++ b/main/scenes/scene_root.c @@ -16,29 +16,34 @@ struct RootScene { struct Scene base; }; -static struct SceneEvent Root_init(struct RootScene *self) +static struct SceneEvent init(struct RootScene *self) { return SceneEvent_OpenChild(NewScene_Boot(), 1); } -struct SceneEvent Root_onChildReturn( - struct RootScene *self, - uint32_t tag, - int32_t status, - void *data) +struct SceneEvent onChildReturn(struct RootScene *self, uint32_t tag, int32_t status, void *data) { if (tag == 1) { - return SceneEvent_OpenChild(NewScene_Demo(), 0); + return SceneEvent_OpenChild(NewScene_MenuTest(), 0); } // this should be unreachable return SceneEvent_None(); } +static void paint(struct Scene *self) +{ + LCD_clearDisplay(0); + + LCD_setStrEx("Press DEL to enter setup", 0, 0, 1, 0x3); +} + struct Scene *NewScene_Root(void) { struct RootScene *scene = calloc(1, sizeof(struct RootScene)); - scene->base.init = (Scene_init_t) Root_init; - scene->base.onChildReturn = (Scene_onChildReturn_t) Root_onChildReturn; + scene->base.init = (Scene_init_t) init; + scene->base.onChildReturn = (Scene_onChildReturn_t) onChildReturn; + scene->base.paint = paint; + return (struct Scene *) scene; } diff --git a/main/scenes/scene_test_menu.c b/main/scenes/scene_test_menu.c new file mode 100644 index 0000000..e2ade1d --- /dev/null +++ b/main/scenes/scene_test_menu.c @@ -0,0 +1,52 @@ +#include +#include +#include +#include +#include + +#include "liquid.h" +#include "graphics/drawing.h" + +#include "scenes.h" +#include "scene_menu.h" + + +static struct SceneEvent onSelect(struct MenuScene *self) { + if (self->selected == 0) { + return SceneEvent_Close(0, NULL); + } + + if (self->selected == 8) { + return SceneEvent_OpenChild(NewScene_Car(), 0); + } + if (self->selected == 9) { + return SceneEvent_OpenChild(NewScene_Demo(), 0); + } + if (self->selected == 5) { + self->items[5].tag++; + snprintf(self->items[5].label, MENUITEM_LABEL_LEN, "Count = %d", self->items[5].tag); + return SceneEvent_Repaint(); + } + + 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[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[6].label, "▶#6", MENUITEM_LABEL_LEN); + strncpy(items[7].label, "▶#7", MENUITEM_LABEL_LEN); + strncpy(items[8].label, "Car", MENUITEM_LABEL_LEN); + strncpy(items[9].label, "Demo Scene", MENUITEM_LABEL_LEN); + + struct MenuScene * scene = NewScene_Menu(items, 10); + scene->onSelect = onSelect; + + return (struct Scene *) scene; +} diff --git a/main/scenes/scenes.h b/main/scenes/scenes.h index f9fd69b..8e01735 100644 --- a/main/scenes/scenes.h +++ b/main/scenes/scenes.h @@ -12,4 +12,6 @@ struct Scene *NewScene_Boot(void); struct Scene *NewScene_Demo(void); struct Scene *NewScene_Car(void); +struct Scene *NewScene_MenuTest(void); + #endif //REFLOWER_SCENES_H