juegos

Juegos de terminal de Pancho: Catan (TUI, GUI, web, servidor, PicoCalc), ajedrez, calculadora y minijuegos
git clone https://git.lu3dhn.xyz/juegos.git
Log | Files | Refs

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 }