wip text edit GUI (TODO: del/ins in the middle, entering space at the end)
This commit is contained in:
@@ -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;
|
||||
|
||||
@@ -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
|
||||
@@ -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);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user