- added libdrawtext
[demo_prior] / src / imtk / listbox.c
1 #include <string.h>
2 #include <stdarg.h>
3 #include <assert.h>
4 #include "imtk.h"
5 #include "state.h"
6 #include "draw.h"
7
8 #define ITEM_HEIGHT             18
9 #define PAD                             3
10
11 static int list_radio(int id, const char *list, int sel, int x, int y, void (*draw)());
12 static void draw_listbox(int id, const char *list, int sel, int x, int y, int width, int nitems, int over);
13 static void draw_radio(int id, const char *list, int sel, int x, int y, int width, int nitems, int over);
14
15 int imtk_listbox(int id, const char *list, int sel, int x, int y)
16 {
17         return list_radio(id, list, sel, x, y, draw_listbox);
18 }
19
20 int imtk_radiogroup(int id, const char *list, int sel, int x, int y)
21 {
22         return list_radio(id, list, sel, x, y, draw_radio);
23 }
24
25 static int list_radio(int id, const char *list, int sel, int x, int y, void (*draw)())
26 {
27         int i, max_width, nitems, over;
28         const char *ptr;
29
30         assert(id >= 0);
31
32         if(x == IMTK_AUTO || y == IMTK_AUTO) {
33                 imtk_layout_get_pos(&x, &y);
34         }
35
36         max_width = 0;
37         over = 0;
38
39         ptr = list;
40         for(i=0; *ptr; i++) {
41                 int strsz = imtk_string_size(ptr) + 2 * PAD;
42                 if(strsz > max_width) {
43                         max_width = strsz;
44                 }
45                 ptr += strlen(ptr) + 1;
46
47                 if(imtk_hit_test(x, y + i * ITEM_HEIGHT, max_width, ITEM_HEIGHT)) {
48                         imtk_set_hot(id);
49                         over = i + 1;
50                 }
51         }
52         nitems = i;
53
54         if(imtk_button_state(IMTK_LEFT_BUTTON)) {
55                 if(over) {
56                         imtk_set_active(id);
57                 }
58         } else {
59                 if(imtk_is_active(id)) {
60                         imtk_set_active(-1);
61                         if(imtk_is_hot(id) && over) {
62                                 sel = over - 1;
63                         }
64                 }
65         }
66
67         draw(id, list, sel, x, y, max_width, nitems, over);
68         imtk_layout_advance(max_width, ITEM_HEIGHT * nitems);
69         return sel;
70 }
71
72 char *imtk_create_list(const char *first, ...)
73 {
74         int sz;
75         char *buf, *item;
76         va_list ap;
77
78         if(!first) {
79                 return 0;
80         }
81
82         sz = strlen(first) + 2;
83         if(!(buf = malloc(sz))) {
84                 return 0;
85         }
86         memcpy(buf, first, sz - 2);
87         buf[sz - 1] = buf[sz - 2] = 0;
88
89         va_start(ap, first);
90         while((item = va_arg(ap, char*))) {
91                 int len = strlen(item);
92                 char *tmp = realloc(buf, sz + len + 1);
93                 if(!tmp) {
94                         free(buf);
95                         return 0;
96                 }
97                 buf = tmp;
98
99                 memcpy(buf + sz - 1, item, len);
100                 sz += len + 1;
101                 buf[sz - 1] = buf[sz - 2] = 0;
102         }
103         va_end(ap);
104
105         return buf;
106 }
107
108 void imtk_free_list(char *list)
109 {
110         free(list);
111 }
112
113 static void draw_listbox(int id, const char *list, int sel, int x, int y, int width, int nitems, int over)
114 {
115         int i;
116         const char *item = list;
117
118         glColor4fv(imtk_get_color(IMTK_TEXT_COLOR));
119
120         for(i=0; i<nitems; i++) {
121                 int item_y = i * ITEM_HEIGHT + y;
122                 unsigned int attr = 0;
123                 float tcol[4], bcol[4];
124
125                 if(over - 1 == i) {
126                         attr |= IMTK_FOCUS_BIT;
127                 }
128
129                 if(sel == i) {
130                         attr |= IMTK_SEL_BIT;
131                         memcpy(tcol, imtk_get_color(IMTK_TOP_COLOR | attr), sizeof tcol);
132                         memcpy(bcol, imtk_get_color(IMTK_BOTTOM_COLOR | attr), sizeof bcol);
133                 } else {
134                         memcpy(tcol, imtk_get_color(IMTK_BOTTOM_COLOR | attr), sizeof tcol);
135                         memcpy(bcol, imtk_get_color(IMTK_BOTTOM_COLOR | attr), sizeof bcol);
136                 }
137
138                 imtk_draw_rect(x, item_y, width, ITEM_HEIGHT, tcol, bcol);
139
140                 glColor4fv(imtk_get_color(IMTK_TEXT_COLOR));
141                 imtk_draw_string(x + 3, item_y + ITEM_HEIGHT - 5, item);
142                 item += strlen(item) + 1;
143         }
144
145         imtk_draw_frame(x, y, width, ITEM_HEIGHT * nitems, FRAME_INSET);
146 }
147
148 static void draw_radio(int id, const char *list, int sel, int x, int y, int width, int nitems, int over)
149 {
150         int i;
151         const char *item = list;
152         float rad = ITEM_HEIGHT * 0.5;
153
154         for(i=0; i<nitems; i++) {
155                 int item_y = i * ITEM_HEIGHT + y;
156                 unsigned int attr = 0;
157                 float tcol[4], bcol[4];
158
159                 if(over - 1 == i) {
160                         attr |= IMTK_FOCUS_BIT;
161                 }
162
163                 imtk_draw_disc_frame(x + rad, item_y + rad, rad * 0.9, rad * 0.75, 5, FRAME_INSET);
164
165                 memcpy(tcol, imtk_get_color(IMTK_BOTTOM_COLOR | attr), sizeof tcol);
166                 memcpy(bcol, imtk_get_color(IMTK_TOP_COLOR | attr), sizeof bcol);
167                 imtk_draw_disc(x + rad, item_y + rad, rad * 0.75, 5, tcol, bcol);
168
169                 if(i == sel) {
170                         attr |= IMTK_SEL_BIT;
171                         memcpy(tcol, imtk_get_color(IMTK_TOP_COLOR | attr), sizeof tcol);
172                         memcpy(bcol, imtk_get_color(IMTK_BOTTOM_COLOR | attr), sizeof bcol);
173
174                         imtk_draw_disc(x + rad, item_y + ITEM_HEIGHT / 2, rad * 0.6, 5, tcol, bcol);
175                 }
176
177                 glColor4fv(imtk_get_color(IMTK_TEXT_COLOR));
178                 imtk_draw_string(x + rad * 2.0 + 3, item_y + ITEM_HEIGHT - 5, item);
179                 item += strlen(item) + 1;
180         }
181 }