form.c (3622B)
1 /* form.c - navegacion y edicion de formularios. */ 2 #include <string.h> 3 #include "form.h" 4 #include "str.h" 5 6 void form_begin(Form *f, const char *title) 7 { 8 memset(f, 0, sizeof *f); 9 str_put(f->title, sizeof f->title, 0, title); 10 } 11 12 static Field *add(Form *f, int type, int id, const char *label) 13 { 14 if (f->n >= (int)(sizeof f->f / sizeof f->f[0])) return &f->f[f->n - 1]; 15 Field *x = &f->f[f->n++]; 16 memset(x, 0, sizeof *x); 17 x->type = (uint8_t)type; 18 x->id = (int16_t)id; 19 str_put(x->label, sizeof x->label, 0, label); 20 return x; 21 } 22 23 Field *form_button(Form *f, int id, const char *label) { return add(f, F_BUTTON, id, label); } 24 Field *form_label(Form *f, const char *text) { return add(f, F_LABEL, -1, text); } 25 26 Field *form_choice(Form *f, int id, const char *label, const char *const *choices, int n, int value) 27 { 28 Field *x = add(f, F_CHOICE, id, label); 29 x->choices = choices; 30 x->nchoices = (uint8_t)n; 31 x->value = (int8_t)value; 32 return x; 33 } 34 35 Field *form_text(Form *f, int id, const char *label, const char *init, int maxlen) 36 { 37 Field *x = add(f, F_TEXT, id, label); 38 str_put(x->text, sizeof x->text, 0, init ? init : ""); 39 x->maxlen = (uint8_t)(maxlen < (int)sizeof x->text - 1 ? maxlen : (int)sizeof x->text - 1); 40 return x; 41 } 42 43 Field *form_get(Form *f, int id) 44 { 45 for (int i = 0; i < f->n; i++) if (f->f[i].id == id) return &f->f[i]; 46 return 0; 47 } 48 49 void form_msg(Form *f, const char *msg, bool err) 50 { 51 str_put(f->msg, sizeof f->msg, 0, msg); 52 f->msg_err = err; 53 } 54 55 static bool selectable(const Field *x) { return !x->hidden && !x->disabled && x->type != F_LABEL; } 56 57 static void fix_cursor(Form *f, int dir) 58 { 59 for (int k = 0; k < f->n; k++) { 60 if (f->cur < 0) f->cur = f->n - 1; 61 if (f->cur >= f->n) f->cur = 0; 62 if (selectable(&f->f[f->cur])) return; 63 f->cur += dir; 64 } 65 } 66 67 int form_key(Form *f, int key) 68 { 69 if (!f->n) return key == K_BACK ? FORM_CANCEL : FORM_NONE; 70 fix_cursor(f, 1); 71 Field *x = &f->f[f->cur]; 72 switch (key) { 73 case K_UP: f->cur--; fix_cursor(f, -1); return FORM_NONE; 74 case K_DOWN: case K_TAB: f->cur++; fix_cursor(f, 1); return FORM_NONE; 75 case K_BACK: return FORM_CANCEL; 76 case K_LEFT: case K_RIGHT: 77 if (x->type == F_CHOICE && x->nchoices) 78 x->value = (int8_t)((x->value + (key == K_RIGHT ? 1 : x->nchoices - 1)) % x->nchoices); 79 return FORM_NONE; 80 case K_OK: 81 if (x->type == F_BUTTON) return x->id; 82 if (x->type == F_CHOICE && x->nchoices) { x->value = (int8_t)((x->value + 1) % x->nchoices); return FORM_NONE; } 83 f->cur++; fix_cursor(f, 1); 84 return FORM_NONE; 85 case K_BKSP: 86 if (x->type == F_TEXT) { 87 int n = (int)strlen(x->text); 88 while (n > 0 && ((unsigned char)x->text[n - 1] & 0xC0) == 0x80) n--; /* utf-8 */ 89 if (n > 0) x->text[n - 1] = 0; 90 } 91 return FORM_NONE; 92 default: 93 if (x->type == F_TEXT && key >= 32 && key < 256 && (int)strlen(x->text) < x->maxlen) { 94 int n = (int)strlen(x->text); 95 if (key < 128) { x->text[n] = (char)key; x->text[n + 1] = 0; } 96 else if (n + 2 <= x->maxlen) { /* latin-1 -> utf-8 */ 97 x->text[n] = (char)(0xC0 | (key >> 6)); 98 x->text[n + 1] = (char)(0x80 | (key & 0x3F)); 99 x->text[n + 2] = 0; 100 } 101 } 102 return FORM_NONE; 103 } 104 } 105 106 int form_click(Form *f, int index) 107 { 108 if (index < 0 || index >= f->n || !selectable(&f->f[index])) return FORM_NONE; 109 f->cur = index; 110 return form_key(f, K_OK); 111 }