Compare commits
	
		
			1 Commits 
		
	
	
	| Author | SHA1 | Date | 
|---|---|---|
| 
							
							
								
									
								
								 | 
						dd689841bb | 6 years ago | 
@ -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