diff --git a/main/CMakeLists.txt b/main/CMakeLists.txt index bb1ca89..3479425 100644 --- a/main/CMakeLists.txt +++ b/main/CMakeLists.txt @@ -8,6 +8,7 @@ set(COMPONENT_SRCS "scenes/scene_bootanim.c" "scenes/scene_menu.c" "scenes/scene_number.c" + "scenes/scene_string.c" "scenes/scene_manual_menu.c" "scenes/scene_popup_menu.c" "scenes/scene_popup_test.c" diff --git a/main/analog.c b/main/analog.c index 4029e92..92650cd 100644 --- a/main/analog.c +++ b/main/analog.c @@ -82,12 +82,12 @@ static void __attribute__((noreturn)) analog_service(void *arg) { #define CORRECT -10; mv += CORRECT; - printf("Raw: %d ... Voltage: %dmV ...", adc_reading, mv); +// printf("Raw: %d ... Voltage: %dmV ...", adc_reading, mv); float volts = mv * 0.001f; float celsius = v_to_c(volts); - printf("Celsius: %.1f°C\n", celsius); +// printf("Celsius: %.1f°C\n", celsius); measurement_celsius = celsius; diff --git a/main/firehazard.c b/main/firehazard.c index 0585726..9a63608 100644 --- a/main/firehazard.c +++ b/main/firehazard.c @@ -90,7 +90,7 @@ void fire_regulate(float cels) { if (pid.ctlMode == PID_MANUAL) { pwm_set(0); } else { - printf("PID in %.2f°C, out %.3f, I %.3f\n", cels, pid.Output, pid.ITerm); +// printf("PID in %.2f°C, out %.3f, I %.3f\n", cels, pid.Output, pid.ITerm); pwm_set(pid.Output); } } @@ -126,7 +126,7 @@ static void pwm_set(float duty) { uint32_t max_duty = (1 << PWM_BIT_NUM);// - 1 uint32_t dutycycle = lroundf((duty) * (float)max_duty); - printf("Dutycycle %d\n", dutycycle); +// printf("Dutycycle %d\n", dutycycle); ESP_ERROR_CHECK( ledc_set_duty(LEDC_HIGH_SPEED_MODE, PWM_CHANNEL, dutycycle) ); ESP_ERROR_CHECK( ledc_update_duty(LEDC_HIGH_SPEED_MODE, PWM_CHANNEL) ); diff --git a/main/graphics/drawing.h b/main/graphics/drawing.h index c094c77..d2f6968 100644 --- a/main/graphics/drawing.h +++ b/main/graphics/drawing.h @@ -61,8 +61,8 @@ struct TextStyle { bool bg; //!< Fill the characters background with the opposite color enum TextSize size; //!< Character size enum TextAlign align; //!< Alignment (works only for single line) - int limit; //!< Number of characters to print from the string, if > 0 - int skip; //!< Characters to skip before printing + size_t limit; //!< Number of characters to print from the string, if > 0 + size_t skip; //!< Characters to skip before printing int spacing_x; //!< Additional X spacing int spacing_y; //!< Additional Y spacing bool nowrap; //!< Stop painting when the right edge of the screen is reached diff --git a/main/scenes/scene_manual_menu.c b/main/scenes/scene_manual_menu.c index 6e0ad19..a6cbac4 100644 --- a/main/scenes/scene_manual_menu.c +++ b/main/scenes/scene_manual_menu.c @@ -11,7 +11,6 @@ #include "graphics/display_spec.h" #include "scenes.h" -#include "scene_menu.h" struct Priv { int _placeholder; @@ -35,6 +34,16 @@ static struct SceneEvent onSelect(struct MenuScene *self) { else if (self->selected == 2) { return SceneEvent_OpenChild(NewScene_PopupTest(), 1); } + else if (self->selected == 3) { + struct StringSceneOpts *opts = calloc(1, sizeof(struct StringSceneOpts)); + strcpy(opts->value, ""); + return SceneEvent_OpenChild(NewScene_String(opts), 1); + } + else if (self->selected == 4) { + struct StringSceneOpts *opts = calloc(1, sizeof(struct StringSceneOpts)); + strcpy(opts->value, "AHOJ"); + return SceneEvent_OpenChild(NewScene_String(opts), 1); + } return SceneEvent_None(); } @@ -65,6 +74,8 @@ void print_labels(struct MenuItem *items) { } strncpy(items[2].label, "▶Item with popup", MENUITEM_LABEL_LEN); + strncpy(items[3].label, "▶Empty str", MENUITEM_LABEL_LEN); + strncpy(items[4].label, "▶Filled str", MENUITEM_LABEL_LEN); } static void paint(struct MenuScene *self) @@ -94,11 +105,11 @@ static void paint(struct MenuScene *self) } struct Scene *NewScene_MenuManual() { - struct MenuItem *items = calloc(3, sizeof(struct MenuItem)); + struct MenuItem *items = calloc(5, sizeof(struct MenuItem)); print_labels(items); - struct MenuScene * scene = NewScene_Menu(items, 3); + struct MenuScene * scene = NewScene_Menu(items, 5); scene->onSelect = onSelect; scene->x = XLINE; diff --git a/main/scenes/scene_string.c b/main/scenes/scene_string.c new file mode 100644 index 0000000..37d4294 --- /dev/null +++ b/main/scenes/scene_string.c @@ -0,0 +1,209 @@ +#include +#include +#include +#include + +#include "liquid.h" +#include "liquid/input_event.h" +#include "graphics/drawing.h" +#include "graphics/display_spec.h" +#include "scene_string.h" + +enum Focus { + FOC_CHAR, + FOC_CHAR_EDIT, + FOC_SUBMIT, + FOC_CANCEL, +}; + +struct StringScene { + struct Scene base; + struct StringSceneOpts *opts; + int editedchar; + int length; + enum Focus foc; +}; + +// !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~ +const char SYMBOLS[] = " ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; + +static void onWheel(struct StringScene *self, struct InputEvent event); +static struct SceneEvent onButton(struct StringScene *self, struct InputEvent event); + +static void ensureCharNotNull(struct StringScene *self); +static void trimTailSpaces(struct StringScene *self); + +static struct SceneEvent onInput(struct StringScene *self, struct InputEvent event) { + switch (event.kind) { + case InputEventKind_Wheel: + onWheel(self, event); + return SceneEvent_Repaint(); + case InputEventKind_Button: + return onButton(self, event); + default: + return SceneEvent_None(); + } +} + +static struct SceneEvent onButton(struct StringScene *self, struct InputEvent event) +{ + if (event.button.state) { + switch (self->foc) { + case FOC_CHAR: + printf("start char edit\n"); + self->foc = FOC_CHAR_EDIT; + ensureCharNotNull(self); + return SceneEvent_Repaint(); + + case FOC_CHAR_EDIT: + if (self->editedchar == self->length) { + printf("submit last char\n"); + + if (self->opts->value[self->editedchar] == ' ') { + printf("empty, go to -> submit\n"); + self->foc = FOC_SUBMIT; + } + else { + printf("not empty, advance and keep editing\n"); + self->length += 1; + self->editedchar += 1; + } + } + else { + printf("exit char edit\n"); + self->foc = FOC_CHAR; + } + return SceneEvent_Repaint(); + + case FOC_SUBMIT: + return SceneEvent_Close(1, NULL); // TODO copy str + case FOC_CANCEL: + return SceneEvent_Close(0, NULL); + } + } + + return SceneEvent_None(); +} + +static void onWheel(struct StringScene *self, struct InputEvent event) +{ + switch (self->foc) { + case FOC_CHAR: + self->editedchar += event.wheel.direction; + printf("Move cursor %d\n", event.wheel.direction); + + if (self->editedchar < 0) { + self->editedchar = 0; + self->foc = FOC_CANCEL; + printf("chars -> cancel\n"); + } + else if (self->editedchar > self->length) { + self->editedchar = self->length; + self->foc = FOC_SUBMIT; + printf("chars -> submit\n"); + } + else { + printf("move within chars\n"); + ensureCharNotNull(self); + } + trimTailSpaces(self); + break; + + case FOC_CHAR_EDIT:; + // FIXME this looks buggy + const char *pos = strchr(SYMBOLS, self->opts->value[self->editedchar]) + event.wheel.direction; + if (pos < SYMBOLS) { + pos = SYMBOLS + strlen(SYMBOLS) - 1; + } else if (*pos == 0) { + pos = SYMBOLS; + } + self->opts->value[self->editedchar] = *pos; + printf("char %d change: %c\n", self->editedchar, *pos); + break; + + case FOC_SUBMIT: + if (event.wheel.direction > 0) { + printf("submit -> cancel\n"); + self->foc = FOC_CANCEL; + } else { + printf("submit -> last char\n"); + self->foc = FOC_CHAR; + self->editedchar = self->length; + } + break; + + case FOC_CANCEL: + if (event.wheel.direction > 0) { + printf("cancel -> first char\n"); + self->foc = FOC_CHAR; + self->editedchar = 0; + } else { + printf("cancel -> submit\n"); + self->foc = FOC_SUBMIT; + } + break; + } +} + +static void paint(struct StringScene *self) +{ + struct StringSceneOpts *opts = self->opts; + LCD_clearDisplay(0); + + ensureCharNotNull(self); + + LCD_setStrEx(opts->value, 1, 1, BLACK, (struct TextStyle) { + .limit = MAX(self->editedchar+1, self->length), + }); + + if (self->foc == FOC_CHAR) { + LCD_setRect(self->editedchar*6, 8, self->editedchar*6+5, 8, false, BLACK); + } else if (self->foc == FOC_CHAR_EDIT) { + LCD_setRect(self->editedchar*6, 8, self->editedchar*6+5, 9, false, BLACK); + } + + LCD_setStrEx("Ok", 50, 15, self->foc == FOC_SUBMIT ? WHITE : BLACK, (struct TextStyle) {.size = FONT_BOLD, .bg=1}); + LCD_setStrEx("Cancel", 1, 15, self->foc == FOC_CANCEL ? WHITE : BLACK, (struct TextStyle) {.size = FONT_BOLD, .bg=1}); +} + +static void ensureCharNotNull(struct StringScene *self) +{ + struct StringSceneOpts *opts = self->opts; + // ensure there is something to draw + if (!opts->value[self->editedchar]) { + opts->value[self->editedchar] = ' '; + } +} + +static void trimTailSpaces(struct StringScene *self) +{ + int pos = self->length; + while (pos > 0 && self->opts->value[pos - 1] == ' ') { + pos--; + } + self->length = pos; +} + +static void deinit(struct StringScene *self) +{ + free(self->opts); + self->opts = NULL; +} + +struct Scene *NewScene_String(struct StringSceneOpts *opts) { + struct StringScene *scene = calloc(1, sizeof(struct StringScene)); + 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; + + scene->length = strlen(opts->value); + scene->foc = scene->length==0? FOC_CHAR_EDIT : FOC_CHAR; + scene->editedchar = 0; + + ensureCharNotNull(scene); + + return (struct Scene *) scene; +} diff --git a/main/scenes/scene_string.h b/main/scenes/scene_string.h new file mode 100644 index 0000000..3a07a52 --- /dev/null +++ b/main/scenes/scene_string.h @@ -0,0 +1,35 @@ +/** + * TODO file description + * + * Created on 2020/01/05. + */ + +#ifndef REFLOWER_SCENE_STR_H +#define REFLOWER_SCENE_STR_H + +#include + +#define STR_EDIT_VALUE_MAXLEN 17 + +/** + * Options passed to the StringScene constructor + */ +struct StringSceneOpts { + // Screen title + char label[15]; + // Value + char value[STR_EDIT_VALUE_MAXLEN]; +}; + +/** + * Create string picker. + * + * "opts" must be on heap and will be internally mutated. + * The scene frees them on exit, returning the selected value as data (heap string), or NULL on cancel. + * + * @param opts + * @return + */ +struct Scene *NewScene_String(struct StringSceneOpts *opts); + +#endif //REFLOWER_SCENE_STR_H diff --git a/main/scenes/scenes.h b/main/scenes/scenes.h index 4f59de2..dabefc1 100644 --- a/main/scenes/scenes.h +++ b/main/scenes/scenes.h @@ -17,6 +17,7 @@ struct Scene *NewScene_PopupTest(); #include "scene_menu.h" #include "scene_number.h" +#include "scene_string.h" struct MenuScene *NewScene_PopupMenu(struct MenuItem *items, size_t items_len);