parent
e22d4fb9e2
commit
dd689841bb
@ -0,0 +1,209 @@ |
|||||||
|
#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; |
||||||
|
} |
@ -0,0 +1,35 @@ |
|||||||
|
/**
|
||||||
|
* TODO file description |
||||||
|
*
|
||||||
|
* Created on 2020/01/05. |
||||||
|
*/ |
||||||
|
|
||||||
|
#ifndef REFLOWER_SCENE_STR_H |
||||||
|
#define REFLOWER_SCENE_STR_H |
||||||
|
|
||||||
|
#include <stdint.h> |
||||||
|
|
||||||
|
#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
|
Loading…
Reference in new issue