esp32 firmware for a toaster reflow oven WIP!!!!!
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.
reflower/main/scenes/scene_string.c

210 lines
6.2 KiB

#include <malloc.h>
#include <stdio.h>
#include <string.h>
#include <common_utils/utils.h>
#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;
}