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.
209 lines
6.2 KiB
209 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;
|
|
}
|
|
|