1 #include "../termbox.h"
2 #include <stdlib.h>
3 #include <stdio.h>
4 #include <string.h>
5 
6 static int curCol = 0;
7 static int curRune = 0;
8 static struct tb_cell *backbuf;
9 static int bbw = 0, bbh = 0;
10 
11 static const uint32_t runes[] = {
12     0x20, // ' '
13     0x2591, // '░'
14     0x2592, // '▒'
15     0x2593, // '▓'
16     0x2588, // '█'
17 };
18 
19 #define len(a) (sizeof(a)/sizeof(a[0]))
20 
21 static const uint16_t colors[] = {
22     TB_BLACK,
23     TB_RED,
24     TB_GREEN,
25     TB_YELLOW,
26     TB_BLUE,
27     TB_MAGENTA,
28     TB_CYAN,
29     TB_WHITE,
30 };
31 
updateAndDrawButtons(int * current,int x,int y,int mx,int my,int n,void (* attrFunc)(int,uint32_t *,uint16_t *,uint16_t *))32 void updateAndDrawButtons(int *current, int x, int y, int mx, int my, int n, void (*attrFunc)(int, uint32_t*, uint16_t*, uint16_t*)) {
33     int lx = x;
34     int ly = y;
35     for (int i = 0; i < n; i++) {
36         if (lx <= mx && mx <= lx+3 && ly <= my && my <= ly+1) {
37             *current = i;
38         }
39         uint32_t r;
40         uint16_t fg, bg;
41         (*attrFunc)(i, &r, &fg, &bg);
42                 tb_change_cell(lx+0, ly+0, r, fg, bg);
43                 tb_change_cell(lx+1, ly+0, r, fg, bg);
44                 tb_change_cell(lx+2, ly+0, r, fg, bg);
45                 tb_change_cell(lx+3, ly+0, r, fg, bg);
46                 tb_change_cell(lx+0, ly+1, r, fg, bg);
47                 tb_change_cell(lx+1, ly+1, r, fg, bg);
48                 tb_change_cell(lx+2, ly+1, r, fg, bg);
49                 tb_change_cell(lx+3, ly+1, r, fg, bg);
50                 lx += 4;
51     }
52     lx = x;
53     ly = y;
54         for (int i = 0; i < n; i++) {
55                 if (*current == i) {
56                         uint16_t fg = TB_RED | TB_BOLD;
57                         uint16_t bg = TB_DEFAULT;
58                         tb_change_cell(lx+0, ly+2, '^', fg, bg);
59                         tb_change_cell(lx+1, ly+2, '^', fg, bg);
60                         tb_change_cell(lx+2, ly+2, '^', fg, bg);
61                         tb_change_cell(lx+3, ly+2, '^', fg, bg);
62                 }
63                 lx += 4;
64         }
65 }
66 
runeAttrFunc(int i,uint32_t * r,uint16_t * fg,uint16_t * bg)67 void runeAttrFunc(int i, uint32_t *r, uint16_t *fg, uint16_t *bg) {
68     *r = runes[i];
69     *fg = TB_DEFAULT;
70     *bg = TB_DEFAULT;
71 }
72 
colorAttrFunc(int i,uint32_t * r,uint16_t * fg,uint16_t * bg)73 void colorAttrFunc(int i, uint32_t *r, uint16_t *fg, uint16_t *bg) {
74     *r = ' ';
75     *fg = TB_DEFAULT;
76     *bg = colors[i];
77 }
78 
updateAndRedrawAll(int mx,int my)79 void updateAndRedrawAll(int mx, int my) {
80     tb_clear();
81     if (mx != -1 && my != -1) {
82         backbuf[bbw*my+mx].ch = runes[curRune];
83         backbuf[bbw*my+mx].fg = colors[curCol];
84     }
85     memcpy(tb_cell_buffer(), backbuf, sizeof(struct tb_cell)*bbw*bbh);
86     int h = tb_height();
87     updateAndDrawButtons(&curRune, 0, 0, mx, my, len(runes), runeAttrFunc);
88     updateAndDrawButtons(&curCol, 0, h-3, mx, my, len(colors), colorAttrFunc);
89     tb_present();
90 }
91 
reallocBackBuffer(int w,int h)92 void reallocBackBuffer(int w, int h) {
93     bbw = w;
94     bbh = h;
95     if (backbuf)
96         free(backbuf);
97     backbuf = calloc(sizeof(struct tb_cell), w*h);
98 }
99 
main(int argv,char ** argc)100 int main(int argv, char **argc) {
101     (void)argc; (void)argv;
102     int code = tb_init();
103     if (code < 0) {
104         fprintf(stderr, "termbox init failed, code: %d\n", code);
105         return -1;
106     }
107 
108     tb_select_input_mode(TB_INPUT_ESC | TB_INPUT_MOUSE);
109     int w = tb_width();
110     int h = tb_height();
111     reallocBackBuffer(w, h);
112     updateAndRedrawAll(-1, -1);
113     for (;;) {
114         struct tb_event ev;
115         int mx = -1;
116         int my = -1;
117         int t = tb_poll_event(&ev);
118         if (t == -1) {
119             tb_shutdown();
120             fprintf(stderr, "termbox poll event error\n");
121             return -1;
122         }
123 
124         switch (t) {
125         case TB_EVENT_KEY:
126             if (ev.key == TB_KEY_ESC) {
127                 tb_shutdown();
128                 return 0;
129             }
130             break;
131         case TB_EVENT_MOUSE:
132             if (ev.key == TB_KEY_MOUSE_LEFT) {
133                 mx = ev.x;
134                 my = ev.y;
135             }
136             break;
137         case TB_EVENT_RESIZE:
138             reallocBackBuffer(ev.w, ev.h);
139             break;
140         }
141         updateAndRedrawAll(mx, my);
142     }
143 }
144