9409a8c6f1b923aaea3f166080eff51b9f25e04d
[neverball] / ball / util.c
1 /*
2  * Copyright (C) 2003 Robert Kooima
3  *
4  * NEVERBALL is  free software; you can redistribute  it and/or modify
5  * it under the  terms of the GNU General  Public License as published
6  * by the Free  Software Foundation; either version 2  of the License,
7  * or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful, but
10  * WITHOUT  ANY  WARRANTY;  without   even  the  implied  warranty  of
11  * MERCHANTABILITY or  FITNESS FOR A PARTICULAR PURPOSE.   See the GNU
12  * General Public License for more details.
13  */
14
15 #include <ctype.h>
16 #include <string.h>
17 #include <assert.h>
18
19 #include "gui.h"
20 #include "util.h"
21 #include "config.h"
22
23 /*---------------------------------------------------------------------------*/
24
25 static int is_special_name(const char *n)
26 {
27     return (strcmp(n, N_("Hard"))   == 0 ||
28             strcmp(n, N_("Medium")) == 0 ||
29             strcmp(n, N_("Easy"))   == 0);
30 }
31
32 /*---------------------------------------------------------------------------*/
33
34 static int coin_btn_id;
35 static int time_btn_id;
36 static int goal_btn_id;
37
38 static void set_score_color(int id, int hi,
39                             const GLfloat *c0,
40                             const GLfloat *c1)
41 {
42     if (hi >= RANK_HARD)
43     {
44         if (hi < RANK_LAST)
45             gui_set_color(id, c0, c0);
46         else
47             gui_set_color(id, c1, c1);
48     }
49 }
50
51 /*---------------------------------------------------------------------------*/
52
53 static int score_label;
54
55 static int score_coin[4];
56 static int score_name[4];
57 static int score_time[4];
58
59 static int score_extra_row;
60
61 /* Build a top three score list with default values. */
62
63 static void gui_scores(int id, int e)
64 {
65     const char *s = "1234567";
66
67     int j, jd, kd, ld, md;
68
69     score_extra_row = e;
70
71     if ((jd = gui_hstack(id)))
72     {
73         gui_filler(jd);
74
75         if ((kd = gui_vstack(jd)))
76         {
77             score_label = gui_label(kd, _("Unavailable"),
78                                     GUI_SML, GUI_TOP, 0, 0);
79
80             if ((ld = gui_hstack(kd)))
81             {
82                 if ((md = gui_vstack(ld)))
83                 {
84                     for (j = RANK_HARD; j < RANK_EASY; j++)
85                         score_coin[j] = gui_count(md, 1000, GUI_SML, 0);
86
87                     score_coin[j++] = gui_count(md, 1000, GUI_SML, GUI_SE);
88
89                     if (e)
90                     {
91                         gui_space(md);
92                         score_coin[j++] = gui_count(md, 1000, GUI_SML, GUI_RGT);
93                     }
94                 }
95
96                 if ((md = gui_vstack(ld)))
97                 {
98                     for (j = RANK_HARD; j < RANK_LAST; j++)
99                     {
100                         score_name[j] = gui_label(md, s, GUI_SML, 0,
101                                                   gui_yel, gui_wht);
102                         gui_set_trunc(score_name[j], TRUNC_TAIL);
103                     }
104
105                     if (e)
106                     {
107                         gui_space(md);
108                         score_name[j++] = gui_label(md, s, GUI_SML, 0,
109                                                     gui_yel, gui_wht);
110                         gui_set_trunc(score_name[j - 1], TRUNC_TAIL);
111                     }
112                 }
113
114                 if ((md = gui_vstack(ld)))
115                 {
116                     for (j = RANK_HARD; j < RANK_EASY; j++)
117                         score_time[j] = gui_clock(md, 359999, GUI_SML, 0);
118
119                     score_time[j++] = gui_clock(md, 359999, GUI_SML, GUI_SW);
120
121                     if (e)
122                     {
123                         gui_space(md);
124                         score_time[j++] = gui_clock(md, 359999, GUI_SML, GUI_LFT);
125                     }
126                 }
127             }
128         }
129         gui_filler(jd);
130     }
131 }
132
133 /* Set the top three score list values. */
134
135 static void gui_set_scores(const char *label, const struct score *s, int hilite)
136 {
137     const char *name;
138     int j, n = score_extra_row ? RANK_LAST : RANK_EASY;
139
140     if (s == NULL)
141     {
142         gui_set_label(score_label, _("Unavailable"));
143
144         for (j = RANK_HARD; j <= n; j++)
145         {
146             gui_set_count(score_coin[j], -1);
147             gui_set_label(score_name[j], "");
148             gui_set_clock(score_time[j], -1);
149         }
150     }
151     else
152     {
153         gui_set_label(score_label, label);
154
155         for (j = RANK_HARD; j <= n; j++)
156         {
157             name = s->player[j];
158
159             if (j == hilite)
160                 set_score_color(score_name[j], j, gui_grn, gui_red);
161             else
162                 gui_set_color(score_name[j], gui_yel, gui_wht);
163
164             gui_set_count(score_coin[j], s->coins[j]);
165             gui_set_label(score_name[j], is_special_name(name) ? _(name) : name);
166             gui_set_clock(score_time[j], s->timer[j]);
167         }
168     }
169 }
170
171 /*---------------------------------------------------------------------------*/
172
173 static int score_type = GUI_SCORE_COIN;
174
175 void gui_score_board(int pd, unsigned int types, int e, int h)
176 {
177     int id, jd, kd, ld;
178
179     assert((types & GUI_SCORE_COIN)  == GUI_SCORE_COIN ||
180            (types & GUI_SCORE_TIME)  == GUI_SCORE_TIME ||
181            (types & GUI_SCORE_GOAL) == GUI_SCORE_GOAL );
182
183     /* Make sure current score type matches the spec. */
184
185     while ((types & score_type) != score_type)
186         score_type = gui_score_next(score_type);
187
188     if ((id = gui_hstack(pd)))
189     {
190         gui_filler(id);
191
192         if ((jd = gui_hstack(id)))
193         {
194             gui_filler(jd);
195
196             if ((kd = gui_vstack(jd)))
197             {
198                 gui_filler(kd);
199
200                 if ((types & GUI_SCORE_COIN) == GUI_SCORE_COIN)
201                 {
202                     coin_btn_id = gui_state(kd, _("Most Coins"),
203                                             GUI_SML, GUI_SCORE_COIN,
204                                             score_type == GUI_SCORE_COIN);
205                 }
206                 if ((types & GUI_SCORE_TIME) == GUI_SCORE_TIME)
207                 {
208                     time_btn_id = gui_state(kd, _("Best Times"),
209                                             GUI_SML, GUI_SCORE_TIME,
210                                             score_type == GUI_SCORE_TIME);
211                 }
212                 if ((types & GUI_SCORE_GOAL) == GUI_SCORE_GOAL)
213                 {
214                     goal_btn_id = gui_state(kd, _("Fast Unlock"),
215                                             GUI_SML, GUI_SCORE_GOAL,
216                                             score_type == GUI_SCORE_GOAL);
217                 }
218
219                 if (h)
220                 {
221                     gui_space(kd);
222
223                     if ((ld = gui_hstack(kd)))
224                     {
225                         gui_filler(ld);
226                         gui_state(ld, _("Change Name"), GUI_SML, GUI_NAME, 0);
227                         gui_filler(ld);
228                     }
229                 }
230
231                 gui_filler(kd);
232             }
233
234             gui_filler(jd);
235         }
236
237         gui_filler(id);
238         gui_scores(id, e);
239         gui_filler(id);
240     }
241 }
242
243 void set_score_board(const struct score *sc, int hc,
244                      const struct score *st, int ht,
245                      const struct score *sg, int hg)
246 {
247     switch (score_type)
248     {
249     case GUI_SCORE_COIN:
250         gui_set_scores(_("Most Coins"), sc, hc);
251         break;
252
253     case GUI_SCORE_TIME:
254         gui_set_scores(_("Best Times"), st, ht);
255         break;
256
257     case GUI_SCORE_GOAL:
258         gui_set_scores(_("Fast Unlock"), sg, hg);
259         break;
260     }
261
262     set_score_color(coin_btn_id, hc, gui_grn, gui_wht);
263     set_score_color(time_btn_id, ht, gui_grn, gui_wht);
264     set_score_color(goal_btn_id, hg, gui_grn, gui_wht);
265 }
266
267 void gui_score_set(int t)
268 {
269     score_type = t;
270 }
271
272 int  gui_score_get(void)
273 {
274     return score_type;
275 }
276
277 int  gui_score_next(int t)
278 {
279     switch (t)
280     {
281     case GUI_SCORE_COIN:  return GUI_SCORE_TIME;
282     case GUI_SCORE_TIME:  return GUI_SCORE_GOAL;
283     case GUI_SCORE_GOAL: return GUI_SCORE_COIN;
284
285     default:
286         return GUI_SCORE_COIN;
287     }
288 }
289
290 /*---------------------------------------------------------------------------*/
291
292 static int lock = 1;
293 static int keyd[127];
294
295 void gui_keyboard(int id)
296 {
297     int jd, kd, ld;
298
299     lock = 1;
300
301     if ((jd = gui_hstack(id)))
302     {
303         gui_filler(jd);
304
305         if ((kd = gui_vstack(jd)))
306         {
307             if ((ld = gui_hstack(kd)))
308             {
309                 gui_filler(ld);
310
311                 keyd['9'] = gui_state(ld, "9", GUI_SML, '9', 0);
312                 keyd['8'] = gui_state(ld, "8", GUI_SML, '8', 0);
313                 keyd['7'] = gui_state(ld, "7", GUI_SML, '7', 0);
314                 keyd['6'] = gui_state(ld, "6", GUI_SML, '6', 0);
315                 keyd['5'] = gui_state(ld, "5", GUI_SML, '5', 0);
316                 keyd['4'] = gui_state(ld, "4", GUI_SML, '4', 0);
317                 keyd['3'] = gui_state(ld, "3", GUI_SML, '3', 0);
318                 keyd['2'] = gui_state(ld, "2", GUI_SML, '2', 0);
319                 keyd['1'] = gui_state(ld, "1", GUI_SML, '1', 0);
320                 keyd['0'] = gui_state(ld, "0", GUI_SML, '0', 0);
321                 gui_filler(ld);
322             }
323             if ((ld = gui_hstack(kd)))
324             {
325                 gui_filler(ld);
326                 keyd['J'] = gui_state(ld, "J", GUI_SML, 'J', 0);
327                 keyd['I'] = gui_state(ld, "I", GUI_SML, 'I', 0);
328                 keyd['H'] = gui_state(ld, "H", GUI_SML, 'H', 0);
329                 keyd['G'] = gui_state(ld, "G", GUI_SML, 'G', 0);
330                 keyd['F'] = gui_state(ld, "F", GUI_SML, 'F', 0);
331                 keyd['E'] = gui_state(ld, "E", GUI_SML, 'E', 0);
332                 keyd['D'] = gui_state(ld, "D", GUI_SML, 'D', 0);
333                 keyd['C'] = gui_state(ld, "C", GUI_SML, 'C', 0);
334                 keyd['B'] = gui_state(ld, "B", GUI_SML, 'B', 0);
335                 keyd['A'] = gui_state(ld, "A", GUI_SML, 'A', 0);
336                 gui_filler(ld);
337             }
338             if ((ld = gui_hstack(kd)))
339             {
340                 gui_filler(ld);
341                 keyd['T'] = gui_state(ld, "T", GUI_SML, 'T', 0);
342                 keyd['S'] = gui_state(ld, "S", GUI_SML, 'S', 0);
343                 keyd['R'] = gui_state(ld, "R", GUI_SML, 'R', 0);
344                 keyd['Q'] = gui_state(ld, "Q", GUI_SML, 'Q', 0);
345                 keyd['P'] = gui_state(ld, "P", GUI_SML, 'P', 0);
346                 keyd['O'] = gui_state(ld, "O", GUI_SML, 'O', 0);
347                 keyd['N'] = gui_state(ld, "N", GUI_SML, 'N', 0);
348                 keyd['M'] = gui_state(ld, "M", GUI_SML, 'M', 0);
349                 keyd['L'] = gui_state(ld, "L", GUI_SML, 'L', 0);
350                 keyd['K'] = gui_state(ld, "K", GUI_SML, 'K', 0);
351                 gui_filler(ld);
352             }
353             if ((ld = gui_hstack(kd)))
354             {
355                 gui_filler(ld);
356                 gui_state(ld, "<", GUI_SML, GUI_BS, 0);
357                 keyd['Z'] = gui_state(ld, "Z", GUI_SML, 'Z', 0);
358                 keyd['Y'] = gui_state(ld, "Y", GUI_SML, 'Y', 0);
359                 keyd['X'] = gui_state(ld, "X", GUI_SML, 'X', 0);
360                 keyd['W'] = gui_state(ld, "W", GUI_SML, 'W', 0);
361                 keyd['V'] = gui_state(ld, "V", GUI_SML, 'V', 0);
362                 keyd['U'] = gui_state(ld, "U", GUI_SML, 'U', 0);
363                 gui_state(ld, _("caps"), GUI_SML, GUI_CL, 0);
364                 gui_filler(ld);
365             }
366         }
367         gui_filler(jd);
368     }
369 }
370
371 void gui_keyboard_lock(void)
372 {
373     lock = lock ? 0 : 1;
374
375     gui_set_label(keyd['A'], lock ? "A" : "a");
376     gui_set_label(keyd['B'], lock ? "B" : "b");
377     gui_set_label(keyd['C'], lock ? "C" : "c");
378     gui_set_label(keyd['D'], lock ? "D" : "d");
379     gui_set_label(keyd['E'], lock ? "E" : "e");
380     gui_set_label(keyd['F'], lock ? "F" : "f");
381     gui_set_label(keyd['G'], lock ? "G" : "g");
382     gui_set_label(keyd['H'], lock ? "H" : "h");
383     gui_set_label(keyd['I'], lock ? "I" : "i");
384     gui_set_label(keyd['J'], lock ? "J" : "j");
385     gui_set_label(keyd['K'], lock ? "K" : "k");
386     gui_set_label(keyd['L'], lock ? "L" : "l");
387     gui_set_label(keyd['M'], lock ? "M" : "m");
388     gui_set_label(keyd['N'], lock ? "N" : "n");
389     gui_set_label(keyd['O'], lock ? "O" : "o");
390     gui_set_label(keyd['P'], lock ? "P" : "p");
391     gui_set_label(keyd['Q'], lock ? "Q" : "q");
392     gui_set_label(keyd['R'], lock ? "R" : "r");
393     gui_set_label(keyd['S'], lock ? "S" : "s");
394     gui_set_label(keyd['T'], lock ? "T" : "t");
395     gui_set_label(keyd['U'], lock ? "U" : "u");
396     gui_set_label(keyd['V'], lock ? "V" : "v");
397     gui_set_label(keyd['W'], lock ? "W" : "w");
398     gui_set_label(keyd['X'], lock ? "X" : "x");
399     gui_set_label(keyd['Y'], lock ? "Y" : "y");
400     gui_set_label(keyd['Z'], lock ? "Z" : "z");
401 }
402
403 char gui_keyboard_char(char c)
404 {
405     return lock ? toupper(c) : tolower(c);
406 }
407
408 /*---------------------------------------------------------------------------*/
409
410 /*
411  * XXX Watch  out when  using these  functions. Be  sure to  check for
412  * GUI_NULL in addition to GUI_NEXT and GUI_PREV when using the latter
413  * two as labels for a switch with a default label.
414  */
415
416 int gui_navig(int id, int prev, int next)
417 {
418     int jd;
419
420     if ((jd = gui_hstack(id)))
421     {
422         if (next || prev)
423         {
424             gui_maybe(jd, _("Next"), GUI_NEXT, GUI_NULL, next);
425             gui_maybe(jd, _("Prev"), GUI_PREV, GUI_NULL, prev);
426         }
427
428         gui_space(jd);
429
430         gui_start(jd, _("Back"), GUI_SML, GUI_BACK, 0);
431     }
432     return jd;
433 }
434
435 int gui_maybe(int id, const char *label, int etoken, int dtoken, int enabled)
436 {
437     int bd;
438
439     if (!enabled)
440     {
441         bd = gui_state(id, label, GUI_SML, dtoken, 0);
442         gui_set_color(bd, gui_gry, gui_gry);
443     }
444     else
445         bd = gui_state(id, label, GUI_SML, etoken, 0);
446
447     return bd;
448 }
449
450 /*---------------------------------------------------------------------------*/