fix a thinko in big endian support (forgot to use defined() in a #elif)
[divverent/darkplaces.git] / ui.c
1
2 #include "quakedef.h"
3
4 /*cvar_t ui_showname = {0, "ui_showname", "0"};
5
6 #define ITEM_CLICKABLE 1
7 #define ITEM_DRAWABLE 2
8
9 #define UIKEY_LEFT 1
10 #define UIKEY_RIGHT 2
11 #define UIKEY_UP 3
12 #define UIKEY_DOWN 4
13 #define UIKEY_ENTER 5
14
15 #define UI_MOUSEBUTTONS 3
16
17 static int ui_alive, ui_active;
18 static float ui_mouse_x, ui_mouse_y;
19 static int ui_mousebutton[UI_MOUSEBUTTONS], ui_mouseclick;
20 static int ui_keyui, ui_keyitem;
21 static ui_item_t *ui_keyrealitem;
22
23 static ui_t *ui_list[MAX_UI_COUNT];
24
25 static void ui_start(void)
26 {       
27         ui_mouse_x = vid.conwidth * 0.5;
28         ui_mouse_y = vid.conheight * 0.5;
29         ui_alive = true;
30 }
31
32 static void ui_shutdown(void)
33 {
34         ui_alive = false;
35 }
36
37 static void ui_newmap(void)
38 {
39 }
40
41 static mempool_t *uimempool;
42
43 void ui_init(void)
44 {
45         uimempool = Mem_AllocPool("UI");
46
47         Cvar_RegisterVariable(&ui_showname);
48
49         R_RegisterModule("UI", ui_start, ui_shutdown, ui_newmap);
50 }
51
52 void ui_mouseupdate(float x, float y)
53 {
54         if (ui_alive)
55         {
56                 ui_mouse_x = bound(0, x, vid.conwidth);
57                 ui_mouse_y = bound(0, y, vid.conheight);
58         }
59 }
60
61 void ui_mouseupdaterelative(float x, float y)
62 {
63         if (ui_alive)
64         {
65                 ui_mouse_x += x;
66                 ui_mouse_y += y;
67                 ui_mouse_x = bound(0, ui_mouse_x, vid.conwidth);
68                 ui_mouse_y = bound(0, ui_mouse_y, vid.conheight);
69         }
70 }
71
72 ui_t *ui_create(void)
73 {
74         ui_t *ui;
75         ui = Mem_Alloc(uimempool, sizeof(*ui));
76         if (ui == NULL)
77                 Sys_Error("ui_create: unable to allocate memory for new ui\n");
78         memset(ui, 0, sizeof(*ui));
79         return ui;
80 }
81
82 void ui_free(ui_t *ui)
83 {
84         if (ui)
85                 Mem_Free(ui);
86 }
87
88 void ui_clear(ui_t *ui)
89 {
90         ui->item_count = 0;
91 }
92
93 void ui_item
94 (
95         ui_t *ui, char *basename, int number,
96         float x, float y, char *picname, char *string,
97         float left, float top, float width, float height,
98         void(*leftkey)(void *nativedata1, void *nativedata2, float data1, float data2),
99         void(*rightkey)(void *nativedata1, void *nativedata2, float data1, float data2),
100         void(*enterkey)(void *nativedata1, void *nativedata2, float data1, float data2),
101         void(*mouseclick)(void *nativedata1, void *nativedata2, float data1, float data2, float xfrac, float yfrac),
102         void *nativedata1, void *nativedata2, float data1, float data2
103 )
104 {
105         int i;
106         ui_item_t *it;
107         char itemname[32];
108         snprintf(itemname, sizeof(itemname), "%s%04d", basename, number);
109         for (it = ui->items, i = 0;i < ui->item_count;it++, i++)
110                 if (it->name == NULL || !strncmp(itemname, it->name, 32))
111                         break;
112         if (i == ui->item_count)
113         {
114                 if (i == MAX_UI_ITEMS)
115                 {
116                         Con_Printf("ui_item: ran out of UI item slots\n");
117                         return;
118                 }
119                 ui->item_count++;
120         }
121         memset(it, 0, sizeof(ui_item_t));
122         strlcpy (it->name, itemname, sizeof (it->name));
123         it->flags = 0;
124         if (picname || string)
125         {
126                 it->flags |= ITEM_DRAWABLE;
127                 it->draw_picname = picname;
128                 it->draw_string = string;
129                 it->draw_x = x;
130                 it->draw_y = y;
131         }
132         if (leftkey || rightkey || enterkey || mouseclick)
133         {
134                 it->flags |= ITEM_CLICKABLE;
135                 it->click_x = x + left;
136                 it->click_y = y + top;
137                 it->click_x2 = it->click_x + width;
138                 it->click_y2 = it->click_y + height;
139                 it->leftkey = leftkey;
140                 it->rightkey = rightkey;
141                 it->enterkey = enterkey;
142                 it->mouseclick = mouseclick;
143                 if (it->mouseclick == NULL)
144                         it->mouseclick = (void *)it->enterkey;
145                 if (it->leftkey == NULL)
146                         it->leftkey = it->enterkey;
147                 if (it->rightkey == NULL)
148                         it->rightkey = it->enterkey;
149                 it->nativedata1 = nativedata1;
150                 it->nativedata2 = nativedata2;
151         }
152 }
153
154 void ui_item_remove(ui_t *ui, char *basename, int number)
155 {
156         int i;
157         ui_item_t *it;
158         char itemname[32];
159         snprintf(itemname, sizeof(itemname), "%s%04d", basename, number);
160         for (it = ui->items, i = 0;i < ui->item_count;it++, i++)
161                 if (it->name && !strncmp(itemname, it->name, 32))
162                         break;
163         if (i < ui->item_count)
164                 it->name[0] = 0;
165 }
166
167 ui_item_t *ui_hititem(float x, float y)
168 {
169         int i, j;
170         ui_item_t *it;
171         ui_t *ui;
172         for (j = 0;j < MAX_UI_COUNT;j++)
173                 if ((ui = ui_list[j]))
174                         for (it = ui->items, i = 0;i < ui->item_count;it++, i++)
175                                 if (it->name[0] && (it->flags & ITEM_CLICKABLE))
176                                         if (x >= it->click_x && y >= it->click_y && x < it->click_x2 && y < it->click_y2)
177                                                 return it;
178         return NULL;
179 }
180
181 int ui_uiactive(ui_t *ui)
182 {
183         int i;
184         for (i = 0;i < MAX_UI_COUNT;i++)
185                 if (ui_list[i] == ui)
186                         return true;
187         return false;
188 }
189
190 void ui_activate(ui_t *ui, int yes)
191 {
192         int i;
193         if (yes)
194         {
195                 if (ui_uiactive(ui))
196                         return;
197
198                 for (i = 0;i < MAX_UI_COUNT;i++)
199                 {
200                         if (ui_list[i] == NULL)
201                         {
202                                 ui_list[i] = ui;
203                                 return;
204                         }
205                 }
206
207                 Con_Printf("ui_activate: ran out of active ui list items\n");
208         }
209         else
210         {
211                 for (i = 0;i < MAX_UI_COUNT;i++)
212                 {
213                         if (ui_list[i] == ui)
214                         {
215                                 ui_list[i] = NULL;
216                                 return;
217                         }
218                 }
219         }
220 }
221
222 int ui_isactive(void)
223 {
224         int j;
225         ui_t *ui;
226         if (ui_alive)
227         {
228                 for (j = 0;j < MAX_UI_COUNT;j++)
229                         if ((ui = ui_list[j]))
230                                 if (ui->item_count)
231                                         return true;
232         }
233         return false;
234 }
235
236 #define UI_QUEUE_SIZE 256
237 static qbyte ui_keyqueue[UI_QUEUE_SIZE];
238 static int ui_keyqueuepos = 0;
239
240 void ui_leftkeyupdate(int pressed)
241 {
242         static int key = false;
243         if (pressed && !key && ui_keyqueuepos < UI_QUEUE_SIZE)
244                 ui_keyqueue[ui_keyqueuepos++] = UIKEY_LEFT;
245         key = pressed;
246 }
247
248 void ui_rightkeyupdate(int pressed)
249 {
250         static int key = false;
251         if (pressed && !key && ui_keyqueuepos < UI_QUEUE_SIZE)
252                 ui_keyqueue[ui_keyqueuepos++] = UIKEY_RIGHT;
253         key = pressed;
254 }
255
256 void ui_upkeyupdate(int pressed)
257 {
258         static int key = false;
259         if (pressed && !key && ui_keyqueuepos < UI_QUEUE_SIZE)
260                 ui_keyqueue[ui_keyqueuepos++] = UIKEY_UP;
261         key = pressed;
262 }
263
264 void ui_downkeyupdate(int pressed)
265 {
266         static int key = false;
267         if (pressed && !key && ui_keyqueuepos < UI_QUEUE_SIZE)
268                 ui_keyqueue[ui_keyqueuepos++] = UIKEY_DOWN;
269         key = pressed;
270 }
271
272 void ui_mousebuttonupdate(int button, int pressed)
273 {
274         if (button < 0 || button >= UI_MOUSEBUTTONS)
275                 return;
276         if (button == 0 && ui_mousebutton[button] && !pressed)
277                 ui_mouseclick = true;
278         ui_mousebutton[button] = pressed;
279 }
280
281 void ui_update(void)
282 {
283         ui_item_t *startitem, *it;
284         if (ui_alive)
285         {
286                 ui_mouse_x = bound(0, ui_mouse_x, vid.conwidth);
287                 ui_mouse_y = bound(0, ui_mouse_y, vid.conheight);
288
289                 if ((ui_active = ui_isactive()))
290                 {
291                         // validate currently selected item
292                         if(ui_list[ui_keyui] == NULL)
293                         {
294                                 while (ui_list[ui_keyui] == NULL)
295                                         ui_keyui = (ui_keyui + 1) % MAX_UI_COUNT;
296                                 ui_keyitem = 0;
297                         }
298                         ui_keyitem = bound(0, ui_keyitem, ui_list[ui_keyui]->item_count - 1);
299                         startitem = ui_keyrealitem = &ui_list[ui_keyui]->items[ui_keyitem];
300                         if ((ui_keyrealitem->flags & ITEM_CLICKABLE) == 0)
301                         {
302                                 do
303                                 {
304                                         // FIXME: cycle through UIs as well as items in a UI
305                                         ui_keyitem = (ui_keyitem - 1) % ui_list[ui_keyui]->item_count - 1;
306                                         ui_keyrealitem = &ui_list[ui_keyui]->items[ui_keyitem];
307                                 }
308                                 while (ui_keyrealitem != startitem && (ui_keyrealitem->flags & ITEM_CLICKABLE) == 0);
309                         }
310
311                         if (ui_keyqueuepos)
312                         {
313                                 int i;
314                                 for (i = 0;i < ui_keyqueuepos;i++)
315                                 {
316                                         startitem = ui_keyrealitem;
317                                         switch(ui_keyqueue[i])
318                                         {
319                                         case UIKEY_UP:
320                                                 do
321                                                 {
322                                                         ui_keyitem--;
323                                                         if (ui_keyitem < 0)
324                                                         {
325                                                                 do
326                                                                         ui_keyui = (ui_keyui - 1) % MAX_UI_COUNT;
327                                                                 while(ui_list[ui_keyui] == NULL);
328                                                                 ui_keyitem = ui_list[ui_keyui]->item_count - 1;
329                                                         }
330                                                         ui_keyrealitem = &ui_list[ui_keyui]->items[ui_keyitem];
331                                                 }
332                                                 while (ui_keyrealitem != startitem && (ui_keyrealitem->flags & ITEM_CLICKABLE) == 0);
333                                                 break;
334                                         case UIKEY_DOWN:
335                                                 do
336                                                 {
337                                                         ui_keyitem++;
338                                                         if (ui_keyitem >= ui_list[ui_keyui]->item_count)
339                                                         {
340                                                                 do
341                                                                         ui_keyui = (ui_keyui + 1) % MAX_UI_COUNT;
342                                                                 while(ui_list[ui_keyui] == NULL);
343                                                                 ui_keyitem = 0;
344                                                         }
345                                                         ui_keyrealitem = &ui_list[ui_keyui]->items[ui_keyitem];
346                                                 }
347                                                 while (ui_keyrealitem != startitem && (ui_keyrealitem->flags & ITEM_CLICKABLE) == 0);
348                                                 break;
349                                         case UIKEY_LEFT:
350                                                 if (ui_keyrealitem->leftkey)
351                                                         ui_keyrealitem->leftkey(ui_keyrealitem->nativedata1, ui_keyrealitem->nativedata2, ui_keyrealitem->data1, ui_keyrealitem->data2);
352                                                 break;
353                                         case UIKEY_RIGHT:
354                                                 if (ui_keyrealitem->rightkey)
355                                                         ui_keyrealitem->rightkey(ui_keyrealitem->nativedata1, ui_keyrealitem->nativedata2, ui_keyrealitem->data1, ui_keyrealitem->data2);
356                                                 break;
357                                         case UIKEY_ENTER:
358                                                 if (ui_keyrealitem->enterkey)
359                                                         ui_keyrealitem->enterkey(ui_keyrealitem->nativedata1, ui_keyrealitem->nativedata2, ui_keyrealitem->data1, ui_keyrealitem->data2);
360                                                 break;
361                                         }
362                                 }
363                         }
364                         ui_keyqueuepos = 0;
365
366                         if (ui_mouseclick && (it = ui_hititem(ui_mouse_x, ui_mouse_y)) && it->mouseclick)
367                                 it->mouseclick(it->nativedata1, it->nativedata2, it->data1, it->data2, ui_mouse_x - it->click_x, ui_mouse_y - it->click_y);
368         }
369         }
370         ui_mouseclick = false;
371 }
372
373 void ui_draw(void)
374 {
375         int i, j;
376         ui_item_t *it;
377         ui_t *ui;
378         if (ui_alive && ui_active)
379         {
380                 for (j = 0;j < MAX_UI_COUNT;j++)
381                         if ((ui = ui_list[j]))
382                                 if (ui->item_count)
383                                         for (i = 0, it = ui->items;i < ui->item_count;i++, it++)
384                                                 if (it->flags & ITEM_DRAWABLE)
385                                                 {
386                                                         if (it->draw_picname)
387                                                                 DrawQ_Pic(it->draw_x, it->draw_y, it->draw_picname, 0, 0, 1, 1, 1, 1, 0);
388                                                         if (it->draw_string)
389                                                                 DrawQ_String(it->draw_x, it->draw_y, it->draw_string, 0, 8, 8, 1, 1, 1, 1, 0);
390                                                 }
391
392                 if ((it = ui_hititem(ui_mouse_x, ui_mouse_y)))
393                 {
394                         if (it->draw_picname)
395                                 DrawQ_Pic(it->draw_x, it->draw_y, it->draw_picname, 0, 0, 1, 1, 1, 1, DRAWFLAG_ADDITIVE);
396                         if (it->draw_string)
397                                 DrawQ_String(it->draw_x, it->draw_y, it->draw_string, 0, 8, 8, 1, 1, 1, 1, DRAWFLAG_ADDITIVE);
398                         if (ui_showname.integer)
399                                 DrawQ_String(ui_mouse_x, ui_mouse_y + 16, it->name, 0, 8, 8, 1, 1, 1, 1, 0);
400         }
401
402                 it = ui_keyrealitem;
403                 if (it->draw_picname)
404                         DrawQ_Pic(it->draw_x, it->draw_y, it->draw_picname, 0, 0, 1, 1, 1, 1, DRAWFLAG_ADDITIVE);
405                 if (it->draw_string)
406                         DrawQ_String(it->draw_x, it->draw_y, it->draw_string, 0, 8, 8, 1, 1, 1, 1, DRAWFLAG_ADDITIVE);
407
408                 DrawQ_Pic(ui_mouse_x, ui_mouse_y, "ui/mousepointer.tga", 0, 0, 1, 1, 1, 1, 0);
409         }
410 }*/
411
412 #define FRAME_THICKNESS 2
413 #define FRAME_COLOR1    0.2, 0.2, 0.5, 0, 0
414 #define FRAME_COLOR2    0, 0, 0, 0.6, 0
415 #define TEXT_FONTSIZE   10, 10
416
417 #if 0
418 static void UIG_DrawFrame(float x, float y, float w, float h)
419 {
420         // bottom
421         DrawQ_Fill(x - FRAME_THICKNESS, y - FRAME_THICKNESS, w + 2 * FRAME_THICKNESS, FRAME_THICKNESS, FRAME_COLOR1);
422         // top
423         DrawQ_Fill(x - FRAME_THICKNESS, y + h, w + 2 * FRAME_THICKNESS, FRAME_THICKNESS, FRAME_COLOR1);
424         // left
425         DrawQ_Fill(x - FRAME_THICKNESS, y, FRAME_THICKNESS, h, FRAME_COLOR1);
426         // right
427         DrawQ_Fill(x + w, y, FRAME_THICKNESS, h, FRAME_COLOR1);
428         // area
429         DrawQ_Fill(x, y, w, h, FRAME_COLOR2);
430
431
432 static void UIG_DrawText(const char *text, float x, float y, float w, float h, float r, float g, float b, float a, float f)
433 {
434         if(w != 0 && h != 0)
435                 DrawQ_SetClipArea(x, y, w, h);
436         DrawQ_String(x, y, text, 0, TEXT_FONTSIZE, r, g, b, a , f);
437         if(w != 0 && h != 0)    
438                 DrawQ_ResetClipArea();
439 }
440 #endif
441
442 void UI_Init(void)
443 {
444 }
445
446 void UI_Key(ui_itemlist_t list, int key, int ascii)
447 {
448 }
449
450 void UI_Draw(ui_itemlist_t list)
451 {
452 }
453
454 void UI_SetFocus(ui_itemlist_t list, ui_item_t item)
455 {
456 }
457
458 void UI_SetNeighbors(ui_item_t left, ui_item_t right, ui_item_t up, ui_item_t down)
459 {
460 }
461
462 // item stuff
463 ui_item_t UI_CreateButton(const char *caption, float x, float y, void(*action)(ui_item_t))
464 {
465         return NULL;
466 }
467
468 ui_item_t UI_CreateLabel(const char *caption, float x, float y)
469 {
470         return NULL;
471 }
472
473 ui_item_t UI_CreateText(const char *caption, float x, float y, const char *allowed, int maxlen, int scrolllen)
474 {
475         return NULL;
476 }
477
478 void UI_FreeItem(ui_item_t item)
479 {
480 }
481
482 const char* UI_GetCaption(ui_item_t item)
483 {
484         return NULL;
485 }
486
487 void UI_SetCaption(ui_item_t item, const char * caption)
488 {
489 }
490
491 // itemlist stuff
492 ui_itemlist_t UI_CreateItemList(float x, float y)
493 {
494         return NULL;
495 }
496
497 void UI_FreeItemList(ui_itemlist_t list)
498 {
499 }
500
501 void UI_AddItem(ui_itemlist_t list, ui_item_t item)
502 {
503 }
504
505 // AK: callback system stuff
506 static ui_callback_t ui_callback_list[UI_MAX_CALLBACK_COUNT];
507
508 void UI_Callback_Init(void)
509 {
510         memset(ui_callback_list, 0, sizeof(ui_callback_list));
511 }
512
513 int  UI_Callback_GetFreeSlot(void)
514 {
515         int i;
516         for(i = 0; ui_callback_list[i].flag & UI_SLOTUSED && i < UI_MAX_CALLBACK_COUNT; i++);
517
518         if(i == UI_MAX_CALLBACK_COUNT)
519                 return -1;
520         else
521                 return i;
522 }
523
524 int UI_Callback_IsSlotUsed(int slotnr)
525 {
526         if(slotnr < 0 || slotnr >= UI_MAX_CALLBACK_COUNT)
527                 return false;
528         return (ui_callback_list[slotnr].flag & UI_SLOTUSED);
529 }
530
531 void UI_Callback_SetupSlot(int slotnr, void(*keydownf)(int num, char ascii), void(*drawf)(void))
532 {
533         ui_callback_list[slotnr].flag = UI_SLOTUSED;
534         ui_callback_list[slotnr].draw = drawf;
535         ui_callback_list[slotnr].keydown = keydownf;
536 }
537
538 void UI_Callback_ResetSlot(int slotnr)
539 {
540         ui_callback_list[slotnr].flag = 0;
541 }
542
543 void UI_Callback_Draw(void)
544 {
545         int i;
546         for(i = 0; i < UI_MAX_CALLBACK_COUNT; i++)
547                 if(ui_callback_list[i].flag & UI_SLOTUSED && ui_callback_list[i].draw)
548                         ui_callback_list[i].draw();
549 }
550
551 void UI_Callback_KeyDown(int num, char ascii)
552 {
553         if(ui_callback_list[key_dest - 3].flag & UI_SLOTUSED && ui_callback_list[key_dest - 3].keydown)
554                 ui_callback_list[key_dest - 3].keydown(num, ascii);
555 }