1 #include "dropdown.h"
2
3 #include "draw.h"
4
5 #include "../macros.h"
6 #include "../settings.h"
7 #include "../theme.h"
8
9 #include <stdlib.h>
10 #include <string.h>
11
12 static DROPDOWN *active_dropdown;
13 static int active_x, active_y, active_width, active_height;
14
15 /* Show selected first, then skip selected */
16 #define index(d, i) (i == 0 ? d->selected : ((i > d->selected) ? i : i - 1))
17
18 // Draw background rectangles for a dropdown
dropdown_drawactive(void)19 void dropdown_drawactive(void) {
20 DROPDOWN *drop = active_dropdown;
21 if (!drop) {
22 return;
23 }
24
25 // load colors for this style
26 uint32_t color_bg, color_border, color_aoptbg, color_aopttext, color_text;
27
28 switch (drop->style) {
29 case AUXILIARY_STYLE:
30 color_bg = COLOR_BKGRND_AUX;
31 color_border = COLOR_AUX_EDGE_ACTIVE;
32 color_aoptbg = COLOR_AUX_ACTIVEOPTION_BKGRND;
33 color_aopttext = COLOR_AUX_ACTIVEOPTION_TEXT;
34 color_text = COLOR_AUX_TEXT;
35 break;
36 default:
37 color_bg = COLOR_BKGRND_MAIN;
38 color_border = COLOR_EDGE_ACTIVE;
39 color_aoptbg = COLOR_ACTIVEOPTION_BKGRND;
40 color_aopttext = COLOR_ACTIVEOPTION_TEXT;
41 color_text = COLOR_MAIN_TEXT;
42 break;
43 }
44
45 int x = active_x, y = active_y, w = active_width, h = active_height;
46
47 int i, sign = 1;
48
49 // Increase width if needed, so that all menu items fit.
50 for (i = 0; i != drop->dropcount; i++) {
51 STRING *e = drop->ondisplay(i, drop);
52 int needed_w = textwidth(e->str, e->length) + SCALE(8);
53 if (w < needed_w) {
54 w = needed_w;
55 }
56 }
57
58 if (y + h * drop->dropcount > (int)settings.window_height) {
59 // y -= h * (drop->dropcount - 1);
60 // sign = -1;
61 }
62 y -= h * drop->selected;
63
64 draw_rect_fill(x, y, w, h * drop->dropcount, color_bg);
65 draw_rect_frame(x, y, w, h * drop->dropcount, color_border);
66
67 //if (sign == -1) {
68 // y += h * (drop->dropcount - 1);
69 //}
70
71 for (i = 0; i != drop->dropcount; i++) {
72 // int j = index(drop, i);
73 int j = i;
74 STRING *e = drop->ondisplay(j, drop);
75 if (j == drop->over) {
76 draw_rect_fill(x + 1, y + 1, w - 2, h - 2, color_aoptbg);
77 setcolor(color_aopttext);
78 } else {
79 setcolor(color_text);
80 }
81 setfont(FONT_TEXT);
82 drawtext(x + SCALE(4), y + SCALE(4), e->str, e->length);
83
84 y += sign * h;
85 }
86 }
87
88 // Draw collapsed dropdown
dropdown_draw(DROPDOWN * d,int x,int y,int width,int height)89 void dropdown_draw(DROPDOWN *d, int x, int y, int width, int height) {
90 if (!d->open) {
91 // load colors for this style
92 uint32_t color_bg, color_border, color_border_h, color_text;
93
94 switch (d->style) {
95 case AUXILIARY_STYLE:
96 color_bg = COLOR_BKGRND_AUX;
97 color_border = COLOR_AUX_EDGE_NORMAL;
98 color_border_h = COLOR_AUX_EDGE_HOVER;
99 color_text = COLOR_AUX_TEXT;
100 break;
101 default:
102 color_bg = COLOR_BKGRND_MAIN;
103 color_border = COLOR_EDGE_NORMAL;
104 color_border_h = COLOR_EDGE_HOVER;
105 color_text = COLOR_MAIN_TEXT;
106 break;
107 }
108
109 draw_rect_frame(x, y, width, height, (d->mouseover ? color_border_h : color_border));
110 draw_rect_fill(x + 1, y + 1, width - 2, height - 2, color_bg);
111
112 if (d->dropcount) {
113 setfont(FONT_TEXT);
114 setcolor(color_text);
115 STRING *text = d->ondisplay(d->selected, d);
116 drawtextwidth(x + SCALE(4), width - SCALE(8), y + SCALE(4), text->str, text->length);
117 }
118 } else {
119 active_x = x;
120 active_y = y;
121 active_width = width;
122 active_height = height;
123 }
124 }
125
dropdown_mmove(DROPDOWN * d,int UNUSED (x),int y,int w,int h,int mx,int my,int UNUSED (dx),int UNUSED (dy))126 bool dropdown_mmove(DROPDOWN *d, int UNUSED(x), int y, int w, int h, int mx, int my, int UNUSED(dx), int UNUSED(dy)) {
127 if (d->open) {
128 bool mouseover;
129
130 if (my > 0) {
131 mouseover = inrect(mx, my, 0, 0, w, MIN(h * d->dropcount, (int)settings.window_height));
132 } else {
133 mouseover = mx >= 0 && mx <= w && abs(my) <= h * d->selected;
134 }
135
136 if (d->mouseover != mouseover) {
137 d->mouseover = mouseover;
138 }
139
140 if (mouseover) {
141 d->skip_mup = true;
142 } else {
143 d->over = false;
144 d->skip_mup = false;
145 return true;
146 }
147
148 int over = my / h + d->selected;
149
150 if (y + h * d->dropcount > (int)settings.window_height) {
151 // over = my > 0 ? 0 : ((-my) / h + 1);
152 }
153
154 if (my < 0)
155 over--;
156
157 if (over < d->dropcount) {
158 // over = index(d, over);
159 if (over != d->over) {
160 d->over = over;
161 return true;
162 }
163 }
164 } else {
165 bool mouseover = inrect(mx, my, 0, 0, w, h);
166 if (d->mouseover != mouseover) {
167 d->mouseover = mouseover;
168 return true;
169 }
170 }
171
172 return false;
173 }
174
dropdown_mdown(DROPDOWN * d)175 bool dropdown_mdown(DROPDOWN *d) {
176 if (d->mouseover && d->dropcount) {
177 d->open = true;
178 active_dropdown = d;
179 return true;
180 }
181
182 if (d->skip_mup) {
183 return dropdown_close(d);
184 }
185
186 return false;
187 }
188
dropdown_close(DROPDOWN * d)189 bool dropdown_close(DROPDOWN *d) {
190 d->open = false;
191 active_dropdown = NULL;
192 return true;
193 }
194
dropdown_mright(DROPDOWN * UNUSED (d))195 bool dropdown_mright(DROPDOWN *UNUSED(d)) {
196 return false;
197 }
198
dropdown_mwheel(DROPDOWN * UNUSED (d),int UNUSED (height),double UNUSED (dlta),bool UNUSED (smooth))199 bool dropdown_mwheel(DROPDOWN *UNUSED(d), int UNUSED(height), double UNUSED(dlta), bool UNUSED(smooth)) {
200 return false;
201 }
202
dropdown_mup(DROPDOWN * d)203 bool dropdown_mup(DROPDOWN *d) {
204 if (d->open) {
205 if (!d->mouseover) {
206 return dropdown_close(d);
207 }
208
209 if (d->skip_mup) {
210 d->skip_mup = false;
211 dropdown_close(d);
212
213 if (d->over < d->dropcount) {
214 d->selected = d->over;
215 d->onselect(d->selected, d);
216 }
217
218 return true;
219 } else {
220 d->skip_mup = true;
221 }
222
223 return false;
224 }
225
226 return false;
227 }
228
dropdown_mleave(DROPDOWN * d)229 bool dropdown_mleave(DROPDOWN *d) {
230 if (d->mouseover) {
231 d->mouseover = false;
232 return true;
233 }
234
235 return false;
236 }
237
238 /***** list-based dropdown menu start *****/
239
240 // Appends localization-independent menu item.
dropdown_list_add_hardcoded(DROPDOWN * d,char * name,void * handle)241 void dropdown_list_add_hardcoded(DROPDOWN *d, char *name, void *handle) {
242 void *p = realloc(d->userdata, (d->dropcount + 1) * sizeof(DROP_ELEMENT));
243 if (!p) {
244 return;
245 }
246 d->userdata = p;
247
248 DROP_ELEMENT *e = &((DROP_ELEMENT *)d->userdata)[d->dropcount++];
249 maybe_i18nal_string_set_plain(&e->name, name, strlen((char *)name));
250 e->handle = handle;
251 }
252
253 // Appends localized menu item.
dropdown_list_add_localized(DROPDOWN * d,UTOX_I18N_STR string_id,void * handle)254 void dropdown_list_add_localized(DROPDOWN *d, UTOX_I18N_STR string_id, void *handle) {
255 void *p = realloc(d->userdata, (d->dropcount + 1) * sizeof(DROP_ELEMENT));
256 if (!p) {
257 return;
258 }
259 d->userdata = p;
260
261 DROP_ELEMENT *e = &((DROP_ELEMENT *)d->userdata)[d->dropcount++];
262 maybe_i18nal_string_set_i18nal(&e->name, string_id);
263 e->handle = handle;
264 }
265
266 // Clears menu (removes all menu items of a list-based dropdown).
dropdown_list_clear(DROPDOWN * d)267 void dropdown_list_clear(DROPDOWN *d) {
268 free(d->userdata);
269 d->userdata = NULL;
270 d->dropcount = 0;
271 d->over = false;
272 d->selected = 0;
273 }
274
275 // Generic display function for list-based dropdowns,
276 // userdata of which is an array of DROP_ELEMENTs.
dropdown_list_ondisplay(uint16_t i,const DROPDOWN * dm)277 STRING *dropdown_list_ondisplay(uint16_t i, const DROPDOWN *dm) {
278 DROP_ELEMENT *e = &((DROP_ELEMENT *)dm->userdata)[i];
279 return maybe_i18nal_string_get(&e->name);
280 }
281
282 /***** list-based dropdown menu end *****/
283
284 /***** simple localized dropdown menu start *****/
285
286 // Generic display function for simple dropdowns,
287 // userdata of which is a simple array of UI_STRING_IDs.
simple_dropdown_ondisplay(uint16_t i,const DROPDOWN * dm)288 STRING *simple_dropdown_ondisplay(uint16_t i, const DROPDOWN *dm) {
289 return SPTRFORLANG(settings.language, ((UTOX_I18N_STR *)dm->userdata)[i]);
290 }
291
292 /***** simple localized dropdown menu end *****/
293