gfxform.c (4838B)
1 /* gfxform.c - formularios (menus de la app) en pixeles. */ 2 #include <string.h> 3 #include "gfx.h" 4 #include "form.h" 5 6 int (*gfx_form_backdrop)(Surface *s, bool compact); 7 bool gfx_touch; 8 9 void gfx_box(Surface *s, int x, int y, int w, int h, Color bg, Color border) 10 { 11 gfx_rect(s, x, y, w, h, bg); 12 gfx_frame(s, x, y, w, h, border); 13 } 14 15 int gfx_text_center(Surface *s, const Font *f, int x, int y, int w, const char *t, Color c) 16 { 17 int tw = gfx_text_w(f, t); 18 if (tw > w) return gfx_text_fit(s, f, x, y, w, t, c); 19 return gfx_text(s, f, x + (w - tw) / 2, y, t, c); 20 } 21 22 Color gfx_dim(Color c) 23 { 24 int r = (c >> 11) & 31, g = (c >> 5) & 63, b = c & 31; 25 return (Color)(((r / 2) << 11) | ((g / 2) << 5) | (b / 2)); 26 } 27 28 static void cat(char *buf, int n, const char *s) { int p = (int)strlen(buf); str_put(buf, n, p, s); } 29 30 void gfx_form(Surface *s, const struct Form *f, HitList *hits) 31 { 32 if (hits) hits->n = 0; 33 int W = s->w, H = s->h; 34 bool compact = W < 400; 35 int top; 36 if (gfx_form_backdrop) top = gfx_form_backdrop(s, compact); 37 else { gfx_rect(s, 0, 0, W, H, RGB(20, 24, 32)); top = compact ? 8 : 24; } 38 int rowh = gfx_touch ? 26 : compact ? 13 : 16; 39 int shown = 0; 40 for (int i = 0; i < f->n; i++) if (!f->f[i].hidden) shown++; 41 /* si no entra en la pantalla, primero filas mas bajas y despues una ventana de 42 * filas que siga al cursor (nunca filas fuera de la pantalla) */ 43 int maxh = H - 12 - top; 44 while (rowh > 13 && 28 + shown * rowh + 22 > maxh) rowh--; 45 int pad = rowh >= 20 ? (rowh - 14) / 2 : 0; /* el texto centrado en la fila alta */ 46 int vis = shown, first = 0; 47 if (28 + shown * rowh + 22 > maxh) { 48 vis = (maxh - 50) / rowh; 49 if (vis < 1) vis = 1; 50 int ci = 0, k = 0; 51 for (int i = 0; i < f->n; i++) { if (f->f[i].hidden) continue; if (i == f->cur) ci = k; k++; } 52 first = ci - vis + 1 > 0 ? ci - vis + 1 : 0; 53 } 54 int w = compact ? W - 16 : 420, h = 28 + vis * rowh + 22; 55 int x = (W - w) / 2, y = top; 56 if (y + h > H - 12) y = H - 12 - h; 57 if (y < 0) y = 0; 58 gfx_box(s, x, y, w, h, C_PANEL, C_ACCENT); 59 gfx_rect(s, x, y, w, 16, C_ACCENT); 60 gfx_text_fit(s, &font_bold, x + 6, y + 2, w - 12, f->title, C_OUTLINE); 61 if (first > 0) gfx_text(s, &font_small, x + w - 12, y + 4, "^", C_OUTLINE); 62 if (first + vis < shown) gfx_text(s, &font_small, x + w - 12, y + h - 10, "v", C_DIM); 63 int ly = y + 24, lw = compact ? 120 : 170, row = 0; 64 for (int i = 0; i < f->n; i++) { 65 const Field *fd = &f->f[i]; 66 if (fd->hidden) continue; 67 if (row++ < first || row > first + vis) continue; 68 bool sel = i == f->cur; 69 switch (fd->type) { 70 case F_LABEL: 71 gfx_text_fit(s, &font_small, x + 8, ly + 2 + pad, w - 16, fd->label, C_DIM); 72 break; 73 case F_BUTTON: 74 if (sel) gfx_rect(s, x + 4, ly - 2, w - 8, rowh - 1, C_ACCENT); 75 else if (gfx_touch && !fd->disabled) gfx_frame(s, x + 4, ly - 2, w - 8, rowh - 1, C_DIM); /* que se vea que es un boton */ 76 gfx_text_fit(s, sel ? &font_bold : &font_normal, x + 10, ly + pad, w - 20, fd->label, 77 sel ? C_OUTLINE : fd->disabled ? C_DIM : C_TEXT); 78 break; 79 case F_CHOICE: { 80 gfx_text_fit(s, &font_normal, x + 10, ly + pad, lw - 12, fd->label, sel ? C_ACCENT : C_TEXT); 81 if (sel) gfx_rect(s, x + lw, ly - 2, w - lw - 6, rowh - 1, C_ACCENT); 82 char buf[64] = "< "; 83 cat(buf, sizeof buf, fd->nchoices ? fd->choices[fd->value] : ""); 84 cat(buf, sizeof buf, " >"); 85 gfx_text_fit(s, sel ? &font_bold : &font_normal, x + lw + 4, ly + pad, w - lw - 12, buf, sel ? C_OUTLINE : C_TEXT); 86 break; 87 } 88 case F_TEXT: 89 gfx_text_fit(s, &font_normal, x + 10, ly + pad, lw - 12, fd->label, sel ? C_ACCENT : C_TEXT); 90 gfx_rect(s, x + lw, ly - 2, w - lw - 6, rowh - 1, sel ? C_PANEL2 : RGB(40, 44, 56)); 91 if (sel) gfx_frame(s, x + lw, ly - 2, w - lw - 6, rowh - 1, C_ACCENT); 92 { 93 char sh[64]; 94 int tw = gfx_text_fit(s, &font_normal, x + lw + 4, ly + pad, w - lw - 16, form_shown(fd, sh, sizeof sh), C_WHITE); 95 if (sel) gfx_rect(s, x + lw + 4 + tw, ly + pad, 6, 11, C_ACCENT); 96 } 97 break; 98 } 99 hit_add(hits, x + 2, ly - 2, w - 4, rowh, HIT_APP, i); 100 ly += rowh; 101 } 102 if (f->msg[0]) gfx_text_fit(s, &font_normal, x + 8, y + h - 16, w - 16, f->msg, f->msg_err ? C_ERR : C_OK); 103 if (!gfx_touch) 104 gfx_text_fit(s, &font_small, 4, H - 9, W - 8, 105 g_lang ? "Up/Down move, Left/Right change, Enter select, Esc back" : "Arriba/Abajo mover, Izq/Der cambiar, Enter elegir, Esc volver", C_TEXT); 106 }