maug
Quick and dirty C mini-augmentation library.
Loading...
Searching...
No Matches
retrogui.h
Go to the documentation of this file.
1
2#ifndef RETROGUI_H
3#define RETROGUI_H
4
10
11#ifndef RETROFONT_PRESENT
12# error "retrofont not present!"
13#endif /* !RETROFONT_PRESENT */
14
15#ifndef RETROGUI_KEY_ACTIVATE
16# define RETROGUI_KEY_ACTIVATE RETROFLAT_KEY_SPACE
17#endif /* !RETROGUI_KEY_ACTIVATE */
18
19#ifndef RETROGUI_KEY_NEXT
20# define RETROGUI_KEY_NEXT RETROFLAT_KEY_DOWN
21#endif /* !RETROGUI_KEY_NEXT */
22
23#ifndef RETROGUI_KEY_PREV
24# define RETROGUI_KEY_PREV RETROFLAT_KEY_UP
25#endif /* !RETROGUI_KEY_PREV */
26
28#define RETROGUI_FLAGS_DIRTY 0x01
29
30#define RETROGUI_FILLBAR_FLAG_SHOWNUM 0x02
31
32#ifndef RETROGUI_TRACE_LVL
33# define RETROGUI_TRACE_LVL 0
34#endif /* !RETROGUI_TRACE_LVL */
35
36#ifndef RETROGUI_CTL_TEXT_SZ_MAX
37# define RETROGUI_CTL_TEXT_SZ_MAX 128
38#endif /* !RETROGUI_CTL_TEXT_SZ_MAX */
39
40#ifndef RETROGUI_CTL_SZ_MAX_INIT
41# define RETROGUI_CTL_SZ_MAX_INIT 20
42#endif /* !RETROGUI_CTL_SZ_MAX_INIT */
43
44#ifndef RETROGUI_PADDING
45# define RETROGUI_PADDING 5
46#endif /* !RETROGUI_PADDING */
47
48#ifndef RETROGUI_BTN_LBL_SZ_MAX
49# define RETROGUI_BTN_LBL_SZ_MAX 64
50#endif /* !RETROGUI_BTN_LBL_SZ_MAX */
51
52#ifndef RETROGUI_BTN_LBL_PADDED_X
53# define RETROGUI_BTN_LBL_PADDED_X 8
54#endif /* !RETROGUI_BTN_LBL_PADDED_X */
55
56#ifndef RETROGUI_BTN_LBL_PADDED_Y
57# define RETROGUI_BTN_LBL_PADDED_Y 8
58#endif /* !RETROGUI_BTN_LBL_PADDED_Y */
59
60#ifndef RETROGUI_CTL_TEXT_BLINK_FRAMES
61# define RETROGUI_CTL_TEXT_BLINK_FRAMES 15
62#endif /* !RETROGUI_CTL_TEXT_BLINK_FRAMES */
63
64#define retrogui_lock( gui )
65
66#define retrogui_unlock( gui )
67
68#define retrogui_is_locked( gui ) (mdata_vector_is_locked( &((gui)->ctls) ))
69
70#define _retrogui_copy_str( field, src_str, dest_ctl, str_tmp, str_sz ) \
71 /* Sanity checking. */ \
72 assert( NULL != src_str ); \
73 debug_printf( RETROGUI_TRACE_LVL, \
74 "copying string \"%s\" to " #dest_ctl, src_str ); \
75 if( 0 == str_sz ) { \
76 str_sz = maug_strlen( src_str ); \
77 debug_printf( RETROGUI_TRACE_LVL, \
78 "determined str sz of \"%s\": " SIZE_T_FMT, src_str, str_sz ); \
79 } \
80 if( (MAUG_MHANDLE)NULL != dest_ctl. field ## _h ) { \
81 /* Free the existing string. */ \
82 maug_mfree( dest_ctl. field ## _h ); \
83 } \
84 \
85 /* Allocate new string space. */ \
86 dest_ctl. field ## _h = maug_malloc( str_sz + 1, 1 ); \
87 debug_printf( RETROGUI_TRACE_LVL, \
88 "allocated str sz for \"%s\": " SIZE_T_FMT, src_str, str_sz + 1 ); \
89 maug_cleanup_if_null_alloc( MAUG_MHANDLE, dest_ctl. field ## _h ); \
90 maug_mlock( dest_ctl. field ## _h, str_tmp ); \
91 maug_cleanup_if_null_lock( char*, str_tmp ); \
92 \
93 /* Copy the string over. */ \
94 assert( NULL != str_tmp ); \
95 maug_mzero( str_tmp, str_sz + 1 ); \
96 debug_printf( RETROGUI_TRACE_LVL, \
97 "zeroed str sz for \"%s\": " SIZE_T_FMT, src_str, str_sz + 1 ); \
98 maug_strncpy( str_tmp, src_str, str_sz ); \
99 debug_printf( RETROGUI_TRACE_LVL, "copied str as: \"%s\"", str_tmp ); \
100 maug_munlock( dest_ctl. field ## _h, str_tmp );
101
103typedef ssize_t retrogui_idc_t;
104
105#define RETROGUI_IDC_NONE 0
106
111
121#define RETROGUI_CTL_TABLE_BASE( f ) \
122 f( 0, NONE, void* none; ) \
123 f( 1, LISTBOX, MAUG_MHANDLE list_h; char* list; size_t list_sz; size_t list_sz_max; size_t sel_idx; ) \
124 f( 2, BUTTON, MAUG_MHANDLE label_h; char* label; size_t label_sz; int16_t push_frames; uint8_t font_flags; ) \
125 f( 3, LABEL, MAUG_MHANDLE label_h; char* label; size_t label_sz; uint8_t font_flags; ) \
126 f( 4, IMAGE, retroflat_blit_t image; ssize_t image_cache_id; int16_t instance; retroflat_pxxy_t src_x; retroflat_pxxy_t src_y; ) \
127 f( 5, FILLBAR, uint8_t flags; uint16_t cur; uint16_t max; )
128
129#ifdef RETROGUI_NO_TEXTBOX
130# define RETROGUI_CTL_TABLE( f ) RETROGUI_CTL_TABLE_BASE( f )
131#else
132# define RETROGUI_CTL_TABLE( f ) RETROGUI_CTL_TABLE_BASE( f ) \
133 f( 6, TEXTBOX, MAUG_MHANDLE text_h; char* text; size_t text_sz; size_t text_sz_max; size_t text_cur; int16_t blink_frames; )
134#endif /* RETROGUI_NO_TEXTBOX */
135
136#if 0
137 f( 6, SCROLLBAR, size_t min; size_t max; size_t value; )
138#endif
139
142 uint8_t type;
143 retrogui_idc_t idc;
148 RETROFLAT_COLOR bg_color;
149 RETROFLAT_COLOR fg_color;
150 RETROFLAT_COLOR sel_fg;
151 RETROFLAT_COLOR sel_bg;
152#if defined( RETROGUI_NATIVE_WIN )
153 HWND hwnd;
154#endif
155};
156
161#define RETROGUI_CTL_TABLE_FIELDS( idx, c_name, c_fields ) \
162 struct RETROGUI_CTL_ ## c_name { \
163 struct RETROGUI_CTL_BASE base; \
164 c_fields \
165 };
166
167RETROGUI_CTL_TABLE( RETROGUI_CTL_TABLE_FIELDS )
168
169
173#define RETROGUI_CTL_TABLE_TYPES( idx, c_name, c_fields ) \
174 struct RETROGUI_CTL_ ## c_name c_name;
175
177 struct RETROGUI_CTL_BASE base;
178 RETROGUI_CTL_TABLE( RETROGUI_CTL_TABLE_TYPES )
179};
180 /* maug_retrogui_ctl */
182
183typedef void (*retrogui_xy_cb)(
184 retroflat_pxxy_t* x, retroflat_pxxy_t* y, void* data );
185
186struct RETROGUI {
187 uint8_t flags;
192 RETROFLAT_COLOR bg_color;
193 retrogui_idc_t idc_prev;
194 struct MDATA_VECTOR ctls;
195 retrogui_idc_t focus;
196 retroflat_blit_t* draw_bmp;
197#ifdef RETROGXC_PRESENT
198 ssize_t font_idx;
199#else
200 MAUG_MHANDLE font_h;
201#endif /* RETROGXC_PRESENT */
202};
203
204MERROR_RETVAL retrogui_push_listbox_item(
205 struct RETROGUI* gui, retrogui_idc_t idc, const char* item, size_t item_sz );
206
216 struct RETROGUI* gui, RETROFLAT_IN_KEY* p_input,
217 struct RETROFLAT_INPUT* input_evt );
218
219MERROR_RETVAL retrogui_redraw_ctls( struct RETROGUI* gui );
220
221MERROR_RETVAL retrogui_sz_ctl(
222 struct RETROGUI* gui, retrogui_idc_t idc,
224 retroflat_pxxy_t max_w, retroflat_pxxy_t max_h );
225
226MERROR_RETVAL retrogui_pos_ctl(
227 struct RETROGUI* gui, retrogui_idc_t idc,
230
231MERROR_RETVAL retrogui_push_ctl(
232 struct RETROGUI* gui, union RETROGUI_CTL* ctl );
233
234MERROR_RETVAL retrogui_get_ctl_text(
235 struct RETROGUI* gui, retrogui_idc_t idc, char* buffer, size_t buffer_sz );
236
237ssize_t retrogui_get_ctl_sel_idx( struct RETROGUI* gui, retrogui_idc_t idc );
238
239#ifndef RETROGUI_NO_TEXTBOX
240
241/*
242MERROR_RETVAL retrogui_set_ctl_text(
243 struct RETROGUI* gui, retrogui_idc_t idc,
244 const char* buffer, size_t buffer_sz );
245*/
246
247#endif /* !RETROGUI_NO_TEXTBOX */
248
249MERROR_RETVAL retrogui_set_ctl_text(
250 struct RETROGUI* gui, retrogui_idc_t idc, size_t buffer_sz,
251 const char* fmt, ... );
252
253MERROR_RETVAL retrogui_set_ctl_image(
254 struct RETROGUI* gui, retrogui_idc_t idc, const char* path, uint8_t flags );
255
256MERROR_RETVAL retrogui_set_ctl_level(
257 struct RETROGUI* gui, retrogui_idc_t idc, uint16_t level, uint16_t max,
258 uint8_t flags );
259
260MERROR_RETVAL retrogui_init_ctl(
261 union RETROGUI_CTL* ctl, uint8_t type, size_t idc );
262
263retrogui_idc_t retrogui_focus_iter(
264 struct RETROGUI* gui, size_t start, ssize_t incr );
265
266MERROR_RETVAL retrogui_init( struct RETROGUI* gui );
267
268MERROR_RETVAL retrogui_remove_ctl( struct RETROGUI* gui, retrogui_idc_t idc );
269
270MERROR_RETVAL retrogui_free( struct RETROGUI* gui );
271
272#define retrogui_focus_next( gui ) \
273 retrogui_focus_iter( gui, 0, 1 )
274
275#define retrogui_focus_prev( gui ) \
276 retrogui_focus_iter( gui, mdata_vector_ct( &((gui)->ctls) ) - 1, -1 )
277
278#ifdef RETROGUI_C
279
280#define RETROGUI_CTL_TABLE_CONSTS( idx, c_name, c_fields ) \
281 MAUG_CONST uint8_t RETROGUI_CTL_TYPE_ ## c_name = idx;
282
283RETROGUI_CTL_TABLE( RETROGUI_CTL_TABLE_CONSTS )
284
285#define RETROGUI_CTL_TABLE_NAMES( idx, c_name, f_fields ) \
286 #c_name,
287
288MAUG_CONST char* gc_retrogui_ctl_names[] = {
289 RETROGUI_CTL_TABLE( RETROGUI_CTL_TABLE_NAMES )
290 ""
291};
292
293static union RETROGUI_CTL* _retrogui_get_ctl_by_idc(
294 struct RETROGUI* gui, size_t idc );
295
296/* === Control: NONE === */
297
298static retrogui_idc_t retrogui_click_NONE(
299 struct RETROGUI* gui,
300 union RETROGUI_CTL* ctl, RETROFLAT_IN_KEY* p_input,
301 struct RETROFLAT_INPUT* input_evt
302) {
303 retrogui_idc_t idc_out = RETROGUI_IDC_NONE;
304
305 return idc_out;
306}
307
308static retrogui_idc_t retrogui_key_NONE(
309 union RETROGUI_CTL* ctl, RETROFLAT_IN_KEY* p_input,
310 struct RETROFLAT_INPUT* input_evt
311) {
312 retrogui_idc_t idc_out = RETROGUI_IDC_NONE;
313
314 return idc_out;
315}
316
317void retrogui_redraw_NONE( struct RETROGUI* gui, union RETROGUI_CTL* ctl ) {
318}
319
320static MERROR_RETVAL retrogui_push_NONE( union RETROGUI_CTL* ctl ) {
321 MERROR_RETVAL retval = MERROR_GUI;
322
323 return retval;
324}
325
326static MERROR_RETVAL retrogui_sz_NONE(
327 struct RETROGUI* gui, union RETROGUI_CTL* ctl,
330) {
331 return MERROR_OK;
332}
333
334static MERROR_RETVAL retrogui_pos_NONE(
335 struct RETROGUI* gui, union RETROGUI_CTL* ctl,
338) {
339 return MERROR_OK;
340}
341
342static void retrogui_free_NONE( union RETROGUI_CTL* ctl ) {
343}
344
345static MERROR_RETVAL retrogui_init_NONE( union RETROGUI_CTL* ctl ) {
346 MERROR_RETVAL retval = MERROR_GUI;
347
348 return retval;
349}
350
351/* === Control: LISTBOX === */
352
353static retrogui_idc_t retrogui_click_LISTBOX(
354 struct RETROGUI* gui,
355 union RETROGUI_CTL* ctl, RETROFLAT_IN_KEY* p_input,
356 struct RETROFLAT_INPUT* input_evt
357) {
358 retrogui_idc_t idc_out = RETROGUI_IDC_NONE;
359 MERROR_RETVAL retval = MERROR_OK;
360 size_t i = 0,
361 j = 0;
362 retroflat_pxxy_t w = 0,
363 h = 0;
364
365# if defined( RETROGUI_NATIVE_WIN )
366 /* Do nothing. */
367# else
368
369 assert( NULL == ctl->LISTBOX.list );
370 assert( NULL != ctl->LISTBOX.list_h );
371 maug_mlock( ctl->LISTBOX.list_h, ctl->LISTBOX.list );
372 maug_cleanup_if_null_lock( char*, ctl->LISTBOX.list );
373
374 /* Figure out the item clicked. */
375 while( i < ctl->LISTBOX.list_sz ) {
376#ifdef RETROGXC_PRESENT
377 retrogxc_string_sz(
378 gui->draw_bmp, &(ctl->LISTBOX.list[i]), 0, gui->font_idx,
379 ctl->base.w, ctl->base.h, &w, &h, 0 );
380#else
381 retrofont_string_sz(
382 gui->draw_bmp, &(ctl->LISTBOX.list[i]), 0, gui->font_h,
383 ctl->base.w, ctl->base.h, &w, &h, 0 );
384#endif /* RETROGXC_PRESENT */
385
386 if(
387 (retroflat_pxxy_t)(input_evt->mouse_y) <
388 ctl->base.y + ((j + 1) * (h + RETROGUI_PADDING))
389 ) {
390 ctl->LISTBOX.sel_idx = j;
391 break;
392 }
393
394 /* Try next variable-length string. */
395 i += maug_strlen( &(ctl->LISTBOX.list[i]) ) + 1;
396 assert( i <= ctl->LISTBOX.list_sz );
397 j++;
398 }
399
400cleanup:
401
402 if( NULL != ctl->LISTBOX.list ) {
403 maug_munlock( ctl->LISTBOX.list_h, ctl->LISTBOX.list );
404 }
405
406 if( MERROR_OK != retval ) {
407 idc_out = RETROGUI_IDC_NONE;
408 }
409
410#endif
411
412 return idc_out;
413}
414
415static retrogui_idc_t retrogui_key_LISTBOX(
416 union RETROGUI_CTL* ctl, RETROFLAT_IN_KEY* p_input,
417 struct RETROFLAT_INPUT* input_evt
418) {
419 retrogui_idc_t idc_out = RETROGUI_IDC_NONE;
420
421 /* TODO: Move up or down to next/prev item. */
422
423 return idc_out;
424}
425
426static void retrogui_redraw_LISTBOX(
427 struct RETROGUI* gui, union RETROGUI_CTL* ctl
428) {
429 size_t i = 0,
430 j = 0;
431 retroflat_pxxy_t w = 0,
432 h = 0;
433 RETROFLAT_COLOR fg_color;
434
435 assert( NULL == ctl->LISTBOX.list );
436
437# if defined( RETROGUI_NATIVE_WIN )
438 /* TODO: InvalidateRect()? */
439# else
440
441 maug_mlock( ctl->LISTBOX.list_h, ctl->LISTBOX.list );
442 if( NULL == ctl->LISTBOX.list ) {
443 goto cleanup;
444 }
445
446 retroflat_2d_rect( gui->draw_bmp, ctl->base.bg_color,
447 gui->x + ctl->base.x, gui->y + ctl->base.y,
448 ctl->base.w, ctl->base.h, RETROFLAT_FLAGS_FILL );
449
450 /* Parse out variable-length strings. */
451 while( i < ctl->LISTBOX.list_sz ) {
452#ifdef RETROGXC_PRESENT
453 retrogxc_string_sz(
454 gui->draw_bmp, &(ctl->LISTBOX.list[i]), 0, gui->font_idx,
455 ctl->base.w, ctl->base.h, &w, &h, 0 );
456#else
457 retrofont_string_sz(
458 gui->draw_bmp, &(ctl->LISTBOX.list[i]), 0, gui->font_h,
459 ctl->base.w, ctl->base.h, &w, &h, 0 );
460#endif /* RETROGXC_PRESENT */
461 if( j == ctl->LISTBOX.sel_idx ) {
462 /* Draw selection colors. */
463 retroflat_2d_rect( gui->draw_bmp, ctl->base.sel_bg,
464 gui->x + ctl->base.x,
465 gui->y + ctl->base.y + (j * (h + RETROGUI_PADDING)),
466 ctl->base.w, h, RETROFLAT_FLAGS_FILL );
467 fg_color = ctl->base.sel_fg;
468 } else {
469 fg_color = ctl->base.fg_color;
470 }
471
472#ifdef RETROGXC_PRESENT
473 retrogxc_string(
474 gui->draw_bmp, fg_color, &(ctl->LISTBOX.list[i]), 0,
475 gui->font_idx,
476 gui->x + ctl->base.x,
477 gui->y + ctl->base.y + (j * (h + RETROGUI_PADDING)),
478 0, 0, 0 );
479#else
480 retrofont_string(
481 gui->draw_bmp, fg_color, &(ctl->LISTBOX.list[i]), 0,
482 gui->font_h,
483 gui->x + ctl->base.x,
484 gui->y + ctl->base.y + (j * (h + RETROGUI_PADDING)),
485 0, 0, 0 );
486#endif /* RETROGXC_PRESENT */
487
488 /* Move to next variable-length string. */
489 i += maug_strlen( &(ctl->LISTBOX.list[i]) ) + 1;
490 assert( i <= ctl->LISTBOX.list_sz );
491 j++;
492 }
493
494cleanup:
495
496 if( NULL != ctl->LISTBOX.list ) {
497 maug_munlock( ctl->LISTBOX.list_h, ctl->LISTBOX.list );
498 }
499
500# endif
501
502}
503
504MERROR_RETVAL retrogui_select_listbox_item(
505 union RETROGUI_CTL* ctl, size_t item_idx
506) {
507 MERROR_RETVAL retval = MERROR_OK;
508
509# if defined( RETROGUI_NATIVE_WIN )
510
511 /* Select sel_idx. */
512 SendMessage( ctl->base.hwnd, LB_SETCURSEL, item_idx, 0 );
513
514# else
515
516 ctl->LISTBOX.sel_idx = item_idx;
517
518# endif
519
520 return retval;
521}
522
523MERROR_RETVAL retrogui_push_listbox_item(
524 struct RETROGUI* gui, retrogui_idc_t idc, const char* item, size_t item_sz
525) {
526 MERROR_RETVAL retval = MERROR_OK;
527 union RETROGUI_CTL* ctl = NULL;
528 MAUG_MHANDLE listbox_h_new = (MAUG_MHANDLE)NULL;
529
530 retrogui_lock( gui );
531
532 debug_printf( RETROGUI_TRACE_LVL,
533 "pushing item \"%s\" to listbox " SIZE_T_FMT "...", item, idc );
534
535 ctl = _retrogui_get_ctl_by_idc( gui, idc );
536 if( NULL == ctl ) {
538 "Adding item \"%s\" failed: Control missing!", item );
539 retval = MERROR_GUI;
540 goto cleanup;
541 }
542
543# if defined( RETROGUI_NATIVE_WIN )
544
545 SendMessage( ctl->LISTBOX.base.hwnd, LB_ADDSTRING, 0, (LPARAM)item );
546
547# else
548
549 if( 0 == ctl->LISTBOX.list_sz ) {
550 ctl->LISTBOX.list_h = maug_malloc( 255, sizeof( char ) );
551 maug_cleanup_if_null_alloc( MAUG_MHANDLE, ctl->LISTBOX.list_h );
552 ctl->LISTBOX.list_sz_max = 255;
553 }
554
555 if( NULL != ctl->LISTBOX.list ) {
556 maug_munlock( ctl->LISTBOX.list_h, ctl->LISTBOX.list );
557 }
558
559 while( ctl->LISTBOX.list_sz + item_sz + 1 >= ctl->LISTBOX.list_sz_max ) {
560 debug_printf( RETROGUI_TRACE_LVL,
561 "resizing listbox items to " SIZE_T_FMT "...",
562 ctl->LISTBOX.list_sz );
563 maug_mrealloc_test(
564 listbox_h_new, ctl->LISTBOX.list_h,
565 ctl->LISTBOX.list_sz_max * 2, sizeof( char ) );
566 ctl->LISTBOX.list_sz_max *= 2;
567 }
568
569 maug_mlock( ctl->LISTBOX.list_h, ctl->LISTBOX.list );
570 maug_cleanup_if_null_alloc( char*, ctl->LISTBOX.list );
571
572 maug_strncpy( &(ctl->LISTBOX.list[ctl->LISTBOX.list_sz]), item, item_sz );
573 ctl->LISTBOX.list[ctl->LISTBOX.list_sz + item_sz] = '\0';
574 ctl->LISTBOX.list_sz += item_sz + 1;
575
576#endif
577
578cleanup:
579
580 if( NULL != ctl->LISTBOX.list ) {
581 maug_munlock( ctl->LISTBOX.list_h, ctl->LISTBOX.list );
582 }
583
584 return retval;
585}
586
587static MERROR_RETVAL retrogui_push_LISTBOX( union RETROGUI_CTL* ctl ) {
588 MERROR_RETVAL retval = MERROR_OK;
589
590# if defined( RETROGUI_NATIVE_WIN )
591
592 ctl->base.hwnd = CreateWindow(
593 "LISTBOX", NULL, WS_CHILD | WS_VISIBLE | LBS_STANDARD,
594 gui->x + ctl->base.x, gui->y + ctl->base.y, ctl->base.w, ctl->base.h,
595 g_retroflat_state->window, (HMENU)(ctl->base.idc),
596 g_retroflat_instance, NULL );
597 debug_printf( RETROGUI_TRACE_LVL,
598 "listbox hwnd: %p", ctl->LISTBOX.base.hwnd );
599 if( (HWND)NULL == ctl->base.hwnd ) {
600 error_printf( "could not create listbox" );
601 retval = MERROR_GUI;
602 goto cleanup;
603 }
604
605cleanup:
606
607# else
608
609 /* TODO? */
610
611# endif
612
613 return retval;
614}
615
616static MERROR_RETVAL retrogui_sz_LISTBOX(
617 struct RETROGUI* gui, union RETROGUI_CTL* ctl,
620) {
621 MERROR_RETVAL retval = MERROR_GUI;
622 /* TODO */
623 return retval;
624}
625
626static MERROR_RETVAL retrogui_pos_LISTBOX(
627 struct RETROGUI* gui, union RETROGUI_CTL* ctl,
630) {
631 MERROR_RETVAL retval = MERROR_GUI;
632 /* TODO */
633 return retval;
634}
635
636static void retrogui_free_LISTBOX( union RETROGUI_CTL* ctl ) {
637 assert( NULL == ctl->LISTBOX.list );
638 maug_mfree( ctl->LISTBOX.list_h );
639}
640
641static MERROR_RETVAL retrogui_init_LISTBOX( union RETROGUI_CTL* ctl ) {
642 MERROR_RETVAL retval = MERROR_OK;
643
644 debug_printf( RETROGUI_TRACE_LVL,
645 "initializing listbox " SIZE_T_FMT "...", ctl->base.idc );
646
647 ctl->base.fg_color = RETROFLAT_COLOR_BLACK;
648 ctl->base.bg_color = RETROFLAT_COLOR_WHITE;
649 ctl->base.sel_fg = RETROFLAT_COLOR_WHITE;
650 if( 2 < retroflat_screen_colors() ) {
651 ctl->base.sel_bg = RETROFLAT_COLOR_BLUE;
652 } else {
653 ctl->base.sel_bg = RETROFLAT_COLOR_BLACK;
654 }
655
656 return retval;
657}
658
659/* === Control: BUTTON === */
660
661static retrogui_idc_t retrogui_click_BUTTON(
662 struct RETROGUI* gui,
663 union RETROGUI_CTL* ctl, RETROFLAT_IN_KEY* p_input,
664 struct RETROFLAT_INPUT* input_evt
665) {
666 retrogui_idc_t idc_out = RETROGUI_IDC_NONE;
667
668 if( 0 < ctl->BUTTON.push_frames ) {
669 goto cleanup;
670 }
671
672 /* Set the last button clicked. */
673 idc_out = ctl->base.idc;
674
675 /* Set the frames to show the pushed-in view. */
676 /* TODO: Use a constant, here. */
677 ctl->BUTTON.push_frames = 3;
678
679cleanup:
680
681 return idc_out;
682}
683
684static retrogui_idc_t retrogui_key_BUTTON(
685 union RETROGUI_CTL* ctl, RETROFLAT_IN_KEY* p_input,
686 struct RETROFLAT_INPUT* input_evt
687) {
688 retrogui_idc_t idc_out = RETROGUI_IDC_NONE;
689
690 /* Set the last button clicked. */
691 /* TODO: Only set out on ENTER/SPACE. */
692 /* idc_out = ctl->base.idc; */
693
694 return idc_out;
695}
696
697static void retrogui_redraw_BUTTON(
698 struct RETROGUI* gui, union RETROGUI_CTL* ctl
699) {
700 retroflat_pxxy_t w = 0,
701 h = 0,
702 text_offset = 0;
703 RETROFLAT_COLOR fg_color = ctl->base.fg_color;
704 RETROFLAT_COLOR bg_color = ctl->base.bg_color;
705 RETROFLAT_COLOR push_shadow_color = RETROFLAT_COLOR_DARKGRAY;
706
707 if( ctl->base.idc == gui->focus ) {
708 /* Assign selected color if focused. */
709 fg_color = ctl->base.sel_fg;
710 }
711
712 if( ctl->base.idc == gui->focus ) {
713 /* Assign selected color if focused. */
714 bg_color = ctl->base.sel_bg;
715 }
716
717 retroflat_2d_rect(
718 gui->draw_bmp, bg_color, ctl->base.x, ctl->base.y,
719 ctl->base.w, ctl->base.h, RETROFLAT_FLAGS_FILL );
720
721 retroflat_2d_rect( gui->draw_bmp, RETROFLAT_COLOR_BLACK,
722 gui->x + ctl->base.x, gui->y + ctl->base.y,
723 ctl->base.w, ctl->base.h, 0 );
724
725 /* Figure out push shadow color for current color depth. */
726 if( 2 >= retroflat_screen_colors() ) {
727 push_shadow_color = RETROFLAT_COLOR_BLACK;
728 }
729
730 /* Draw the push shadows on top/left or bottom/right, depending on pushed
731 * status.
732 */
733 if( 0 < ctl->BUTTON.push_frames ) {
734 retroflat_2d_line(
735 gui->draw_bmp, push_shadow_color,
736 gui->x + ctl->base.x + 1, gui->y + ctl->base.y + 1,
737 gui->x + ctl->base.x + ctl->base.w - 2, gui->y + ctl->base.y + 1, 0 );
738 retroflat_2d_line(
739 gui->draw_bmp, push_shadow_color,
740 gui->x + ctl->base.x + 1, gui->y + ctl->base.y + 2,
741 gui->x + ctl->base.x + 1, gui->y + ctl->base.y + ctl->base.h - 3, 0 );
742
743 gui->flags |= RETROGUI_FLAGS_DIRTY; /* Mark dirty for push animation. */
744 ctl->BUTTON.push_frames--;
745 text_offset = 1;
746 } else {
747 /* Button is not pushed. */
748 retroflat_2d_line(
749 gui->draw_bmp, RETROFLAT_COLOR_WHITE,
750 gui->x + ctl->base.x + 1, gui->y + ctl->base.y + 1,
751 gui->x + ctl->base.x + ctl->base.w - 2, gui->y + ctl->base.y + 1, 0 );
752 retroflat_2d_line(
753 gui->draw_bmp, RETROFLAT_COLOR_WHITE,
754 gui->x + ctl->base.x + 1, gui->y + ctl->base.y + 2,
755 gui->x + ctl->base.x + 1, gui->y + ctl->base.y + ctl->base.h - 3, 0 );
756 }
757
758 maug_mlock( ctl->BUTTON.label_h, ctl->BUTTON.label );
759 if( NULL == ctl->BUTTON.label ) {
760 error_printf( "could not lock BUTTON label!" );
761 goto cleanup;
762 }
763
764 /* Grab the string size and use it to center the text in the control. */
765#ifdef RETROGXC_PRESENT
766 retrogxc_string_sz(
767#else
768 retrofont_string_sz(
769#endif /* RETROGXC_PRESENT */
770 gui->draw_bmp, ctl->BUTTON.label, 0,
771#ifdef RETROGXC_PRESENT
772 gui->font_idx,
773#else
774 gui->font_h,
775#endif /* RETROGXC_PRESENT */
776 /* TODO: Pad max client area. */
777 ctl->base.w, ctl->base.h, &w, &h, ctl->BUTTON.font_flags );
778
779#ifdef RETROGXC_PRESENT
780 retrogxc_string(
781#else
782 retrofont_string(
783#endif /* RETROGXC_PRESENT */
784 gui->draw_bmp, fg_color, ctl->BUTTON.label, 0,
785#ifdef RETROGXC_PRESENT
786 gui->font_idx,
787#else
788 gui->font_h,
789#endif /* RETROGXC_PRESENT */
790 gui->x + ctl->base.x + ((ctl->base.w >> 1) - (w >> 1)) + text_offset,
791 gui->y + ctl->base.y + ((ctl->base.h >> 1) - (h >> 1)) + text_offset,
792 /* TODO: Pad max client area. */
793 ctl->base.w, ctl->base.h, ctl->BUTTON.font_flags );
794
795 maug_munlock( ctl->BUTTON.label_h, ctl->BUTTON.label );
796
797cleanup:
798
799 return;
800}
801
802static MERROR_RETVAL retrogui_push_BUTTON( union RETROGUI_CTL* ctl ) {
803 MERROR_RETVAL retval = MERROR_OK;
804
805# if defined( RETROGUI_NATIVE_WIN )
806
807 ctl->base.hwnd = CreateWindow(
808 "BUTTON", ctl->BUTTON.label, WS_CHILD | WS_VISIBLE | BS_DEFPUSHBUTTON,
809 gui->x + ctl->base.x, gui->y + ctl->base.y, ctl->base.w, ctl->base.h,
810 g_retroflat_state->window, (HMENU)(ctl->base.idc),
811 g_retroflat_instance, NULL );
812 if( (HWND)NULL == ctl->base.hwnd ) {
814 "Could not create button " SIZE_T_FMT ": %s",
815 ctl->base.idc, ctl->BUTTON.label );
816 retval = MERROR_GUI;
817 goto cleanup;
818 }
819
820# else
821 size_t label_sz = 0;
822 char* label_tmp = NULL;
823
824 debug_printf( RETROGUI_TRACE_LVL, "pushing BUTTON control..." );
825
826 _retrogui_copy_str(
827 label, ctl->BUTTON.label, ctl->BUTTON, label_tmp, label_sz );
828 ctl->BUTTON.label = NULL;
829# endif
830
831cleanup:
832
833 return retval;
834}
835
836static MERROR_RETVAL retrogui_sz_BUTTON(
837 struct RETROGUI* gui, union RETROGUI_CTL* ctl,
840) {
841 MERROR_RETVAL retval = MERROR_OK;
842
843 assert( NULL != ctl );
844 assert( NULL == ctl->BUTTON.label );
845 assert( NULL != ctl->BUTTON.label_h );
846
847 maug_mlock( ctl->BUTTON.label_h, ctl->BUTTON.label );
848 maug_cleanup_if_null_lock( char*, ctl->BUTTON.label );
849
850 /* Get the size of the text-based GUI item. */
851#ifdef RETROGXC_PRESENT
852 retrogxc_string_sz(
853#else
854 retrofont_string_sz(
855#endif /* RETROGXC_PRESENT */
856 NULL,
857 ctl->BUTTON.label,
858 0,
859#ifdef RETROGXC_PRESENT
860 gui->font_idx,
861#else
862 gui->font_h,
863#endif /* RETROGXC_PRESENT */
864 max_w - 8,
865 max_h - 8,
866 p_w,
867 p_h, ctl->BUTTON.font_flags );
868
869 /* Add space for borders and stuff. */
870 *p_w += RETROGUI_BTN_LBL_PADDED_X;
871 *p_h += RETROGUI_BTN_LBL_PADDED_Y;
872
873cleanup:
874
875 maug_munlock( ctl->BUTTON.label_h, ctl->BUTTON.label );
876
877 return retval;
878}
879
880static MERROR_RETVAL retrogui_pos_BUTTON(
881 struct RETROGUI* gui, union RETROGUI_CTL* ctl,
884) {
885 MERROR_RETVAL retval = MERROR_OK;
886
887# if defined( RETROGUI_NATIVE_WIN )
888 /* TODO */
889# else
890 assert( NULL != ctl );
891
892 ctl->base.x = x;
893 ctl->base.y = y;
894 if( 0 < w ) {
895 ctl->base.w = w;
896 }
897 if( 0 < h ) {
898 ctl->base.h = h;
899 }
900# endif /* RETROGUI_NATIVE_WIN */
901
902 return retval;
903}
904
905static void retrogui_free_BUTTON( union RETROGUI_CTL* ctl ) {
906 if( NULL != ctl->BUTTON.label_h ) {
907 maug_mfree( ctl->BUTTON.label_h );
908 }
909}
910
911static MERROR_RETVAL retrogui_init_BUTTON( union RETROGUI_CTL* ctl ) {
912 MERROR_RETVAL retval = MERROR_OK;
913
914 debug_printf( RETROGUI_TRACE_LVL,
915 "initializing button " SIZE_T_FMT "...", ctl->base.idc );
916
917 ctl->base.fg_color = RETROFLAT_COLOR_BLACK;
918 if( 2 < retroflat_screen_colors() ) {
919 ctl->base.bg_color = RETROFLAT_COLOR_GRAY;
920 ctl->base.sel_fg = RETROFLAT_COLOR_BLUE;
921 ctl->base.sel_bg = RETROFLAT_COLOR_GRAY;
922 } else {
923 ctl->base.bg_color = RETROFLAT_COLOR_WHITE;
924 ctl->base.sel_fg = RETROFLAT_COLOR_WHITE;
925 ctl->base.sel_bg = RETROFLAT_COLOR_BLACK;
926 }
927
928 return retval;
929}
930
931#ifndef RETROGUI_NO_TEXTBOX
932
933/* === Control: TEXTBOX === */
934
935static retrogui_idc_t retrogui_click_TEXTBOX(
936 struct RETROGUI* gui,
937 union RETROGUI_CTL* ctl, RETROFLAT_IN_KEY* p_input,
938 struct RETROFLAT_INPUT* input_evt
939) {
940 retrogui_idc_t idc_out = RETROGUI_IDC_NONE;
941
942 return idc_out;
943}
944
945static retrogui_idc_t retrogui_key_TEXTBOX(
946 union RETROGUI_CTL* ctl, RETROFLAT_IN_KEY* p_input,
947 struct RETROFLAT_INPUT* input_evt
948) {
949 retrogui_idc_t idc_out = RETROGUI_IDC_NONE;
950 char c = '\0';
951
952# if defined( RETROGUI_NATIVE_WIN )
953 /* Do nothing. */
954# else
955
956 c = retroflat_vk_to_ascii( *p_input, input_evt->key_flags );
957
958 /* Ignore non-printable characters. */
959 if(
960 0 == c &&
961 RETROFLAT_KEY_RIGHT != *p_input &&
962 RETROFLAT_KEY_LEFT != *p_input
963 ) {
964 goto cleanup;
965 }
966
967 /* Lock text field. */
968 assert( NULL == ctl->TEXTBOX.text );
969 assert( (MAUG_MHANDLE)NULL != ctl->TEXTBOX.text_h );
970 maug_mlock( ctl->TEXTBOX.text_h, ctl->TEXTBOX.text );
971 if( NULL == ctl->TEXTBOX.text ) {
972 error_printf( "could not lock TEXTBOX text handle!" );
973 goto cleanup;
974 }
975
976 switch( *p_input ) {
977 case RETROFLAT_KEY_BKSP:
979 ctl->TEXTBOX.text, ctl->TEXTBOX.text_cur, ctl->TEXTBOX.text_sz )
980 break;
981
982 case RETROFLAT_KEY_ENTER:
983 idc_out = ctl->base.idc;
984 break;
985
986 case RETROFLAT_KEY_LEFT:
987 if( 0 < ctl->TEXTBOX.text_cur ) {
988 ctl->TEXTBOX.text_cur--;
989 }
990 break;
991
992 case RETROFLAT_KEY_RIGHT:
993 if( ctl->TEXTBOX.text_sz > ctl->TEXTBOX.text_cur ) {
994 ctl->TEXTBOX.text_cur++;
995 }
996 break;
997
998 default:
999 assert( ctl->TEXTBOX.text_sz < ctl->TEXTBOX.text_sz_max );
1001 ctl->TEXTBOX.text,
1002 ctl->TEXTBOX.text_cur,
1003 ctl->TEXTBOX.text_sz,
1004 ctl->TEXTBOX.text_sz_max );
1005 break;
1006 }
1007
1008 /* TODO: Remove input from queue? */
1009
1010cleanup:
1011
1012 if( NULL != ctl->TEXTBOX.text ) {
1013 maug_munlock( ctl->TEXTBOX.text_h, ctl->TEXTBOX.text );
1014 }
1015
1016# endif
1017
1018 return idc_out;
1019}
1020
1021static void retrogui_redraw_TEXTBOX(
1022 struct RETROGUI* gui, union RETROGUI_CTL* ctl
1023) {
1024 RETROFLAT_COLOR shadow_color = RETROFLAT_COLOR_DARKGRAY;
1025
1026 /* Adjust shadow colors for monochrome. */
1027 if( 2 >= retroflat_screen_colors() ) {
1028 shadow_color = RETROFLAT_COLOR_BLACK;
1029 }
1030
1031# if defined( RETROGUI_NATIVE_WIN )
1032 /* Do nothing. */
1033# else
1034
1035 retroflat_2d_rect( gui->draw_bmp, ctl->base.bg_color,
1036 gui->x + ctl->base.x, gui->y + ctl->base.y,
1037 ctl->base.w, ctl->base.h, RETROFLAT_FLAGS_FILL );
1038
1039 /* Draw chiselled inset border. */
1040
1041 retroflat_2d_rect( gui->draw_bmp, RETROFLAT_COLOR_BLACK,
1042 gui->x + ctl->base.x,
1043 gui->y + ctl->base.y, ctl->base.w, 2,
1045
1046 retroflat_2d_rect( gui->draw_bmp, RETROFLAT_COLOR_BLACK,
1047 gui->x + ctl->base.x,
1048 gui->y + ctl->base.y, 2, ctl->base.h,
1050
1051 retroflat_2d_rect( gui->draw_bmp, shadow_color,
1052 gui->x + ctl->base.x,
1053 gui->y + ctl->base.y + ctl->base.h - 1,
1054 ctl->base.w, 2,
1056
1057 retroflat_2d_rect( gui->draw_bmp, shadow_color,
1058 gui->x + ctl->base.x + ctl->base.w - 1,
1059 gui->y + ctl->base.y, 2, ctl->base.h,
1061
1062 /* Draw text. */
1063
1064 assert( NULL == ctl->TEXTBOX.text );
1065 maug_mlock( ctl->TEXTBOX.text_h, ctl->TEXTBOX.text );
1066 if( NULL == ctl->TEXTBOX.text ) {
1067 goto cleanup;
1068 }
1069
1070#ifdef RETROGXC_PRESENT
1071 retrogxc_string(
1072 gui->draw_bmp, ctl->base.fg_color, ctl->TEXTBOX.text, 0, gui->font_idx,
1073 gui->x + ctl->base.x + RETROGUI_PADDING,
1074 gui->y + ctl->base.y + RETROGUI_PADDING, ctl->base.w, ctl->base.h, 0 );
1075#else
1076 retrofont_string(
1077 gui->draw_bmp, ctl->base.fg_color, ctl->TEXTBOX.text, 0, gui->font_h,
1078 gui->x + ctl->base.x + RETROGUI_PADDING,
1079 gui->y + ctl->base.y + RETROGUI_PADDING, ctl->base.w, ctl->base.h, 0 );
1080#endif /* RETROGXC_PRESENT */
1081
1082cleanup:
1083
1084 if( NULL != ctl->TEXTBOX.text ) {
1085 maug_munlock( ctl->TEXTBOX.text_h, ctl->TEXTBOX.text );
1086 }
1087
1088 /* TODO: Get cursor color from GUI. */
1089 retroflat_2d_rect( gui->draw_bmp,
1090 ctl->base.sel_fg,
1091 gui->x + ctl->base.x + RETROGUI_PADDING + (8 * ctl->TEXTBOX.text_cur),
1092 gui->y + ctl->base.y + RETROGUI_PADDING,
1093 8, 8,
1094 /* Draw blinking cursor. */
1095 /* TODO: Use a global timer to mark this field dirty. */
1096 gui->focus == ctl->base.idc &&
1097 0 < ctl->TEXTBOX.blink_frames ? RETROFLAT_FLAGS_FILL : 0 );
1098
1099 if( (-1 * RETROGUI_CTL_TEXT_BLINK_FRAMES) > --(ctl->TEXTBOX.blink_frames) ) {
1100 ctl->TEXTBOX.blink_frames = RETROGUI_CTL_TEXT_BLINK_FRAMES;
1101 }
1102
1103 gui->flags |= RETROGUI_FLAGS_DIRTY; /* Mark dirty for blink animation. */
1104
1105# endif
1106
1107 return;
1108}
1109
1110static MERROR_RETVAL retrogui_push_TEXTBOX( union RETROGUI_CTL* ctl ) {
1111 MERROR_RETVAL retval = MERROR_OK;
1112
1113# if defined( RETROGUI_NATIVE_WIN )
1114
1115 ctl->base.hwnd = CreateWindow(
1116 "EDIT", 0, WS_CHILD | WS_VISIBLE | WS_BORDER,
1117 gui->x + ctl->base.x, gui->y + ctl->base.y, ctl->base.w, ctl->base.h,
1118 g_retroflat_state->window, (HMENU)(ctl->base.idc),
1119 g_retroflat_instance, NULL );
1120 if( (HWND)NULL == ctl->base.hwnd ) {
1122 "Could not create textbox: " SIZE_T_FMT, ctl->base.idc );
1123 retval = MERROR_GUI;
1124 goto cleanup;
1125 }
1126
1127# else
1128
1129 debug_printf( RETROGUI_TRACE_LVL,
1130 "clearing textbox " SIZE_T_FMT " buffer...", ctl->base.idc );
1131 assert( NULL == ctl->TEXTBOX.text_h );
1132 ctl->TEXTBOX.text_h = maug_malloc( RETROGUI_CTL_TEXT_SZ_MAX + 1, 1 );
1133 maug_cleanup_if_null_alloc( MAUG_MHANDLE, ctl->TEXTBOX.text_h );
1134 ctl->TEXTBOX.text_sz_max = RETROGUI_CTL_TEXT_SZ_MAX;
1135
1136 maug_mlock( ctl->TEXTBOX.text_h, ctl->TEXTBOX.text );
1137 maug_cleanup_if_null_alloc( char*, ctl->TEXTBOX.text );
1138 debug_printf( RETROGUI_TRACE_LVL,
1139 "clearing textbox " SIZE_T_FMT " buffer...", ctl->base.idc );
1140 maug_mzero( ctl->TEXTBOX.text, RETROGUI_CTL_TEXT_SZ_MAX + 1 );
1141 maug_munlock( ctl->TEXTBOX.text_h, ctl->TEXTBOX.text );
1142
1143# endif
1144
1145cleanup:
1146
1147 return retval;
1148}
1149
1150static MERROR_RETVAL retrogui_sz_TEXTBOX(
1151 struct RETROGUI* gui, union RETROGUI_CTL* ctl,
1154) {
1155 MERROR_RETVAL retval = MERROR_GUI;
1156 /* TODO */
1157 return retval;
1158}
1159
1160static MERROR_RETVAL retrogui_pos_TEXTBOX(
1161 struct RETROGUI* gui, union RETROGUI_CTL* ctl,
1164) {
1165 MERROR_RETVAL retval = MERROR_GUI;
1166 /* TODO */
1167 return retval;
1168}
1169
1170static void retrogui_free_TEXTBOX( union RETROGUI_CTL* ctl ) {
1171 if( NULL != ctl->TEXTBOX.text_h ) {
1172 maug_mfree( ctl->TEXTBOX.text_h );
1173 }
1174}
1175
1176static MERROR_RETVAL retrogui_init_TEXTBOX( union RETROGUI_CTL* ctl ) {
1177 MERROR_RETVAL retval = MERROR_OK;
1178
1179 debug_printf( RETROGUI_TRACE_LVL,
1180 "initializing textbox " SIZE_T_FMT "...", ctl->base.idc );
1181
1182 ctl->base.fg_color = RETROFLAT_COLOR_BLACK;
1183 ctl->base.bg_color = RETROFLAT_COLOR_WHITE;
1184 ctl->base.sel_bg = RETROFLAT_COLOR_WHITE;
1185 if( 2 < retroflat_screen_colors() ) {
1186 ctl->base.sel_fg = RETROFLAT_COLOR_BLUE;
1187 } else {
1188 ctl->base.sel_fg = RETROFLAT_COLOR_BLACK;
1189 }
1190
1191 return retval;
1192}
1193
1194#endif /* RETROGUI_NO_TEXTBOX */
1195
1196/* === Control: LABEL === */
1197
1198static retrogui_idc_t retrogui_click_LABEL(
1199 struct RETROGUI* gui,
1200 union RETROGUI_CTL* ctl, RETROFLAT_IN_KEY* p_input,
1201 struct RETROFLAT_INPUT* input_evt
1202) {
1203 return RETROGUI_IDC_NONE;
1204}
1205
1206static retrogui_idc_t retrogui_key_LABEL(
1207 union RETROGUI_CTL* ctl, RETROFLAT_IN_KEY* p_input,
1208 struct RETROFLAT_INPUT* input_evt
1209) {
1210 return RETROGUI_IDC_NONE;
1211}
1212
1213static void retrogui_redraw_LABEL(
1214 struct RETROGUI* gui, union RETROGUI_CTL* ctl
1215) {
1216
1217# if defined( RETROGUI_NATIVE_WIN )
1218 /* Do nothing. */
1219# else
1220
1221 /* Draw text. */
1222
1223#ifdef RETROGXC_PRESENT
1224 assert( 0 <= gui->font_idx );
1225#else
1226 assert( (MAUG_MHANDLE)NULL != gui->font_h );
1227#endif /* RETROGXC_PRESENT */
1228
1229 assert( NULL == ctl->LABEL.label );
1230 maug_mlock( ctl->LABEL.label_h, ctl->LABEL.label );
1231 if( NULL == ctl->LABEL.label ) {
1232 error_printf( "could not lock LABEL text!" );
1233 goto cleanup;
1234 }
1235
1236#ifdef RETROGXC_PRESENT
1237 retrogxc_string(
1238#else
1239 retrofont_string(
1240#endif /* RETROGXC_PRESENT */
1241 gui->draw_bmp, ctl->base.fg_color, ctl->LABEL.label,
1242 ctl->LABEL.label_sz,
1243#ifdef RETROGXC_PRESENT
1244 gui->font_idx,
1245#else
1246 gui->font_h,
1247#endif /* RETROGXC_PRESENT */
1248 gui->x + ctl->base.x + RETROGUI_PADDING,
1249 gui->y + ctl->base.y + RETROGUI_PADDING, ctl->base.w, ctl->base.h,
1250 ctl->LABEL.font_flags );
1251
1252cleanup:
1253
1254 if( NULL != ctl->LABEL.label ) {
1255 maug_munlock( ctl->LABEL.label_h, ctl->LABEL.label );
1256 }
1257
1258# endif
1259
1260 return;
1261}
1262
1263static MERROR_RETVAL retrogui_push_LABEL( union RETROGUI_CTL* ctl ) {
1264 MERROR_RETVAL retval = MERROR_OK;
1265
1266# if defined( RETROGUI_NATIVE_WIN )
1267
1268 /* TODO */
1269
1270# else
1271 size_t label_sz = 0;
1272 char* label_tmp = NULL;
1273
1274 debug_printf( RETROGUI_TRACE_LVL, "pushing LABEL control..." );
1275
1276 _retrogui_copy_str(
1277 label, ctl->LABEL.label, ctl->LABEL, label_tmp, label_sz );
1278 ctl->LABEL.label = NULL;
1279# endif
1280
1281cleanup:
1282
1283 return retval;
1284}
1285
1286static MERROR_RETVAL retrogui_sz_LABEL(
1287 struct RETROGUI* gui, union RETROGUI_CTL* ctl,
1290) {
1291 MERROR_RETVAL retval = MERROR_GUI;
1292 /* TODO */
1293 return retval;
1294}
1295
1296static MERROR_RETVAL retrogui_pos_LABEL(
1297 struct RETROGUI* gui, union RETROGUI_CTL* ctl,
1300) {
1301 MERROR_RETVAL retval = MERROR_GUI;
1302 /* TODO */
1303 return retval;
1304}
1305
1306static void retrogui_free_LABEL( union RETROGUI_CTL* ctl ) {
1307 if( NULL != ctl->LABEL.label_h ) {
1308 maug_mfree( ctl->LABEL.label_h );
1309 }
1310}
1311
1312static MERROR_RETVAL retrogui_init_LABEL( union RETROGUI_CTL* ctl ) {
1313 MERROR_RETVAL retval = MERROR_OK;
1314
1315 debug_printf( RETROGUI_TRACE_LVL,
1316 "initializing label " SIZE_T_FMT "...", ctl->base.idc );
1317
1318 ctl->base.fg_color = RETROFLAT_COLOR_BLACK;
1319 ctl->base.bg_color = RETROFLAT_COLOR_WHITE;
1320
1321 return retval;
1322}
1323
1324/* === Control: IMAGE === */
1325
1326static retrogui_idc_t retrogui_click_IMAGE(
1327 struct RETROGUI* gui,
1328 union RETROGUI_CTL* ctl, RETROFLAT_IN_KEY* p_input,
1329 struct RETROFLAT_INPUT* input_evt
1330) {
1331 return RETROGUI_IDC_NONE;
1332}
1333
1334static retrogui_idc_t retrogui_key_IMAGE(
1335 union RETROGUI_CTL* ctl, RETROFLAT_IN_KEY* p_input,
1336 struct RETROFLAT_INPUT* input_evt
1337) {
1338 return RETROGUI_IDC_NONE;
1339}
1340
1341static void retrogui_redraw_IMAGE(
1342 struct RETROGUI* gui, union RETROGUI_CTL* ctl
1343) {
1344# if defined( RETROGUI_NATIVE_WIN )
1345 /* Do nothing. */
1346# else
1347
1348# if defined( RETROGXC_PRESENT )
1349 if( 0 > ctl->IMAGE.image_cache_id ) {
1350 return;
1351 }
1352 debug_printf( RETROGUI_TRACE_LVL,
1353 "redrawing image ctl " SIZE_T_FMT ", cache ID " SSIZE_T_FMT "...",
1354 ctl->base.idc, ctl->IMAGE.image_cache_id );
1355 retrogxc_blit_bitmap(
1356 gui->draw_bmp,
1357 ctl->IMAGE.image_cache_id,
1358# else
1359 if( !retroflat_2d_bitmap_ok( gui->draw_bmp ) ) {
1360 return;
1361 }
1362 retroflat_2d_blit_bitmap(
1363 gui->draw_bmp,
1364 &(ctl->IMAGE.image),
1365# endif /* RETROGXC_PRESENT */
1366 ctl->IMAGE.src_x, ctl->IMAGE.src_y,
1367 gui->x + ctl->base.x, gui->y + ctl->base.y, ctl->base.w, ctl->base.h,
1368 ctl->IMAGE.instance );
1369# endif
1370
1371 return;
1372}
1373
1374static MERROR_RETVAL retrogui_push_IMAGE( union RETROGUI_CTL* ctl ) {
1375 MERROR_RETVAL retval = MERROR_OK;
1376
1377# if defined( RETROGUI_NATIVE_WIN )
1378
1379 /* TODO */
1380
1381# else
1382
1383 debug_printf( RETROGUI_TRACE_LVL, "pushing IMAGE control..." );
1384
1385 /* TODO: Copy non-cached image. */
1386
1387 /* ctl->IMAGE.cache_idx = NULL; */
1388# endif
1389
1390 return retval;
1391}
1392
1393static MERROR_RETVAL retrogui_sz_IMAGE(
1394 struct RETROGUI* gui, union RETROGUI_CTL* ctl,
1397) {
1398 MERROR_RETVAL retval = MERROR_GUI;
1399# ifdef RETROGXC_PRESENT
1400 retval = retrogxc_bitmap_wh( ctl->IMAGE.image_cache_id, p_w, p_h );
1401 maug_cleanup_if_not_ok();
1402# else
1403 if( !retroflat_2d_bitmap_ok( &(ctl->IMAGE.image) ) ) {
1404 error_printf( "image not assigned!" );
1405 retval = MERROR_GUI;
1406 goto cleanup;
1407 }
1408
1409 *p_w = retroflat_2d_bitmap_w( &(ctl->IMAGE.image) );
1410 *p_h = retroflat_2d_bitmap_h( &(ctl->IMAGE.image) );
1411# endif /* RETROGXC_PRESENT */
1412
1413cleanup:
1414
1415 return retval;
1416}
1417
1418static MERROR_RETVAL retrogui_pos_IMAGE(
1419 struct RETROGUI* gui, union RETROGUI_CTL* ctl,
1422) {
1423 MERROR_RETVAL retval = MERROR_GUI;
1424 /* TODO */
1425 return retval;
1426}
1427
1428static void retrogui_free_IMAGE( union RETROGUI_CTL* ctl ) {
1429# ifndef RETROGXC_PRESENT
1430 retroflat_2d_destroy_bitmap( &(ctl->IMAGE.image) );
1431# endif /* RETROGXC_PRESENT */
1432}
1433
1434static MERROR_RETVAL retrogui_init_IMAGE( union RETROGUI_CTL* ctl ) {
1435 MERROR_RETVAL retval = MERROR_OK;
1436
1437 debug_printf( RETROGUI_TRACE_LVL,
1438 "initializing IMAGE " SIZE_T_FMT "...", ctl->base.idc );
1439
1440 return retval;
1441}
1442
1443/* === Control: FILLBAR === */
1444
1445static retrogui_idc_t retrogui_click_FILLBAR(
1446 struct RETROGUI* gui,
1447 union RETROGUI_CTL* ctl, RETROFLAT_IN_KEY* p_input,
1448 struct RETROFLAT_INPUT* input_evt
1449) {
1450 retrogui_idc_t idc_out = RETROGUI_IDC_NONE;
1451
1452 return idc_out;
1453}
1454
1455static retrogui_idc_t retrogui_key_FILLBAR(
1456 union RETROGUI_CTL* ctl, RETROFLAT_IN_KEY* p_input,
1457 struct RETROFLAT_INPUT* input_evt
1458) {
1459 retrogui_idc_t idc_out = RETROGUI_IDC_NONE;
1460
1461 return idc_out;
1462}
1463
1464static void retrogui_redraw_FILLBAR(
1465 struct RETROGUI* gui, union RETROGUI_CTL* ctl
1466) {
1467 retroflat_pxxy_t fill_w = 0;
1468
1469 if( 0 == ctl->FILLBAR.cur ) {
1470 fill_w = 0;
1471 } else {
1472 fill_w = ctl->base.w * ctl->FILLBAR.cur / ctl->FILLBAR.max;
1473 }
1474
1475 retroflat_2d_rect(
1476 gui->draw_bmp, ctl->base.bg_color, ctl->base.x + fill_w, ctl->base.y,
1477 ctl->base.w - fill_w, ctl->base.h, RETROFLAT_FLAGS_FILL );
1478
1479 retroflat_2d_rect(
1480 gui->draw_bmp, ctl->base.fg_color, ctl->base.x, ctl->base.y,
1481 fill_w, ctl->base.h, RETROFLAT_FLAGS_FILL );
1482
1483 return;
1484}
1485
1486static MERROR_RETVAL retrogui_push_FILLBAR( union RETROGUI_CTL* ctl ) {
1487 MERROR_RETVAL retval = MERROR_OK;
1488
1489# if defined( RETROGUI_NATIVE_WIN )
1490
1491 /* TODO: Native fillbar implementation. */
1492
1493# endif
1494
1495 return retval;
1496}
1497
1498static MERROR_RETVAL retrogui_sz_FILLBAR(
1499 struct RETROGUI* gui, union RETROGUI_CTL* ctl,
1502) {
1503 MERROR_RETVAL retval = MERROR_OK;
1504
1505 assert( NULL != ctl );
1506
1507 /* TODO? */
1508
1509 return retval;
1510}
1511
1512static MERROR_RETVAL retrogui_pos_FILLBAR(
1513 struct RETROGUI* gui, union RETROGUI_CTL* ctl,
1516) {
1517 MERROR_RETVAL retval = MERROR_OK;
1518
1519# if defined( RETROGUI_NATIVE_WIN )
1520 /* TODO */
1521# else
1522 assert( NULL != ctl );
1523
1524 ctl->base.x = x;
1525 ctl->base.y = y;
1526 if( 0 < w ) {
1527 ctl->base.w = w;
1528 }
1529 if( 0 < h ) {
1530 ctl->base.h = h;
1531 }
1532# endif /* RETROGUI_NATIVE_WIN */
1533
1534 return retval;
1535}
1536
1537static void retrogui_free_FILLBAR( union RETROGUI_CTL* ctl ) {
1538}
1539
1540static MERROR_RETVAL retrogui_init_FILLBAR( union RETROGUI_CTL* ctl ) {
1541 MERROR_RETVAL retval = MERROR_OK;
1542
1543 debug_printf( RETROGUI_TRACE_LVL,
1544 "initializing fillbar " SIZE_T_FMT "...", ctl->base.idc );
1545
1546 ctl->base.fg_color = RETROFLAT_COLOR_BLACK;
1547 if( 2 < retroflat_screen_colors() ) {
1548 ctl->base.bg_color = RETROFLAT_COLOR_GRAY;
1549 } else {
1550 ctl->base.bg_color = RETROFLAT_COLOR_WHITE;
1551 }
1552
1553 return retval;
1554}
1555
1556/* === Static Internal Functions === */
1557
1558static union RETROGUI_CTL* _retrogui_get_ctl_by_idc(
1559 struct RETROGUI* gui, size_t idc
1560) {
1561 size_t i = 0;
1562 union RETROGUI_CTL* ctl = NULL;
1563
1564 assert( retrogui_is_locked( gui ) );
1565
1566 for( i = 0 ; mdata_vector_ct( &(gui->ctls) ) > i ; i++ ) {
1567 ctl = mdata_vector_get( &(gui->ctls), i, union RETROGUI_CTL );
1568 if( idc == ctl->base.idc ) {
1569 break;
1570 }
1571 ctl = NULL;
1572 }
1573
1574 if( NULL == ctl ) {
1575 debug_printf( RETROGUI_TRACE_LVL,
1576 "could not find GUI item IDC " SIZE_T_FMT, idc );
1577 }
1578
1579 return ctl;
1580}
1581
1582/* === */
1583
1584static MERROR_RETVAL _retrogui_sz_ctl(
1585 struct RETROGUI* gui, retrogui_idc_t idc,
1588) {
1589 MERROR_RETVAL retval = MERROR_OK;
1590 union RETROGUI_CTL* ctl = NULL;
1591
1592 assert( retrogui_is_locked( gui ) );
1593
1594 debug_printf( RETROGUI_TRACE_LVL,
1595 "sizing control " SIZE_T_FMT " to: " SIZE_T_FMT "x" SIZE_T_FMT,
1596 idc, max_w, max_h );
1597
1598 ctl = _retrogui_get_ctl_by_idc( gui, idc );
1599 if( NULL == ctl ) {
1600 error_printf( "could not find control to size!" );
1601 retval = MERROR_GUI;
1602 goto cleanup;
1603 }
1604
1605 #define RETROGUI_CTL_TABLE_SZ( idx, c_name, c_fields ) \
1606 } else if( RETROGUI_CTL_TYPE_ ## c_name == ctl->base.type ) { \
1607 /* Mark dirty first so redraw can unmark it for animation! */ \
1608 retval = retrogui_sz_ ## c_name( gui, ctl, p_w, p_h, max_w, max_h ); \
1609 maug_cleanup_if_not_ok();
1610
1611 if( 0 ) {
1612 RETROGUI_CTL_TABLE( RETROGUI_CTL_TABLE_SZ )
1613 }
1614
1615 debug_printf( RETROGUI_TRACE_LVL,
1616 "sized control " SIZE_T_FMT " at " SIZE_T_FMT "x" SIZE_T_FMT "...",
1617 ctl->base.idc, ctl->base.w, ctl->base.h );
1618
1619cleanup:
1620
1621 return retval;
1622}
1623
1624/* === Generic Functions === */
1625
1627 struct RETROGUI* gui, RETROFLAT_IN_KEY* p_input,
1628 struct RETROFLAT_INPUT* input_evt
1629) {
1630 size_t i = 0;
1631 retroflat_pxxy_t mouse_x = 0,
1632 mouse_y = 0;
1633 retrogui_idc_t idc_out = RETROGUI_IDC_NONE;
1634 union RETROGUI_CTL* ctl = NULL;
1635 MERROR_RETVAL retval = MERROR_OK;
1636
1637 if( 0 == mdata_vector_ct( &(gui->ctls) ) ) {
1638 return RETROGUI_IDC_NONE;
1639 }
1640
1641 assert( !retrogui_is_locked( gui ) );
1642 mdata_vector_lock( &(gui->ctls) );
1643
1644# if defined( RETROGUI_NATIVE_WIN )
1645
1646 if( 0 == g_retroflat_state->last_idc ) {
1647 /* No WM_COMMAND to process. */
1648 goto cleanup;
1649 }
1650
1651 ctl = retrogui_get_ctl_by_idc( gui, g_retroflat_state->last_idc );
1652 g_retroflat_state->last_idc = 0;
1653 if( NULL == ctl ) {
1654 debug_printf( RETROGUI_TRACE_LVL,
1655 "invalid IDC: " SIZE_T_FMT, gui->focus );
1656 }
1657
1658# ifndef RETROGUI_NO_TEXTBOX
1659 if( RETROGUI_CTL_TYPE_TEXTBOX == ctl->base.type ) {
1660 if( SendMessage( ctl->base.hwnd, EM_GETMODIFY, 0, 0 ) ) {
1661 SendMessage( ctl->base.hwnd, EM_SETMODIFY, 0, 0 );
1662 debug_printf( RETROGUI_TRACE_LVL, "mod: %d",
1663 SendMessage( ctl->base.hwnd, EM_GETMODIFY, 0, 0 ) );
1664 }
1665 }
1666# endif /* !RETROGUI_NO_TEXTBOX */
1667
1668# else
1669
1670 /* Use our cross-platform controls. */
1671
1672 #define RETROGUI_CTL_TABLE_CLICK( idx, c_name, c_fields ) \
1673 } else if( RETROGUI_CTL_TYPE_ ## c_name == ctl->base.type ) { \
1674 gui->flags |= RETROGUI_FLAGS_DIRTY; \
1675 idc_out = retrogui_click_ ## c_name( gui, ctl, p_input, input_evt );
1676
1677 #define RETROGUI_CTL_TABLE_KEY( idx, c_name, c_fields ) \
1678 } else if( RETROGUI_CTL_TYPE_ ## c_name == ctl->base.type ) { \
1679 gui->flags |= RETROGUI_FLAGS_DIRTY; \
1680 idc_out = retrogui_key_ ## c_name( ctl, p_input, input_evt );
1681
1682 if( 0 == *p_input ) {
1683 goto reset_debounce;
1684
1685 } else if( RETROGUI_KEY_ACTIVATE == *p_input ) {
1686
1687 if( 0 <= gui->focus ) {
1688 idc_out = gui->focus;
1689 gui->focus = -1;
1690 gui->flags |= RETROGUI_FLAGS_DIRTY;
1691 }
1692
1693
1694 } else if( RETROGUI_KEY_NEXT == *p_input ) {
1695 retrogui_focus_next( gui );
1696
1697 debug_printf( RETROGUI_TRACE_LVL, "next: " SSIZE_T_FMT, gui->focus );
1698
1699 /* Cleanup after the menu. */
1700 *p_input = 0;
1701
1702 } else if( RETROGUI_KEY_PREV == *p_input ) {
1703 retrogui_focus_prev( gui );
1704
1705 debug_printf( RETROGUI_TRACE_LVL, "prev: " SSIZE_T_FMT, gui->focus );
1706
1707 /* Cleanup after the menu. */
1708 *p_input = 0;
1709
1710# ifndef RETROGUI_NO_MOUSE
1711 } else if(
1712 RETROFLAT_MOUSE_B_LEFT == *p_input ||
1713 RETROFLAT_MOUSE_B_RIGHT == *p_input
1714 ) {
1715 /* Handle mouse input. */
1716
1717 /* Remove all focus before testing if a new control has focus. */
1718 gui->focus = RETROGUI_IDC_NONE;
1719
1720 mouse_x = input_evt->mouse_x - gui->x;
1721 mouse_y = input_evt->mouse_y - gui->y;
1722
1723 for( i = 0 ; mdata_vector_ct( &(gui->ctls) ) > i ; i++ ) {
1724 ctl = mdata_vector_get( &(gui->ctls), i, union RETROGUI_CTL );
1725 if(
1726 mouse_x < ctl->base.x ||
1727 mouse_y < ctl->base.y ||
1728 mouse_x > ctl->base.x + ctl->base.w ||
1729 mouse_y > ctl->base.y + ctl->base.h
1730 ) {
1731 continue;
1732 }
1733
1734 if( gui->idc_prev == ctl->base.idc ) {
1735 /* No repeated clicks! */
1736 /* TODO: Allow exceptions for e.g. scrollbars. */
1737 idc_out = RETROGUI_IDC_NONE;
1738 goto cleanup;
1739 }
1740
1741 gui->idc_prev = ctl->base.idc;
1742
1743 gui->focus = ctl->base.idc;
1744
1745 if( 0 ) {
1746 RETROGUI_CTL_TABLE( RETROGUI_CTL_TABLE_CLICK )
1747 }
1748 break;
1749 }
1750# endif /* !RETROGUI_NO_MOUSE */
1751
1752 } else {
1753
1754 if( RETROGUI_IDC_NONE == gui->focus ) {
1755 goto reset_debounce;
1756 }
1757
1758 /* Send keystrokes to control that has focus. */
1759
1760 ctl = _retrogui_get_ctl_by_idc( gui, gui->focus );
1761 if( NULL == ctl ) {
1762 debug_printf( RETROGUI_TRACE_LVL,
1763 "invalid IDC: " SIZE_T_FMT, gui->focus );
1764 goto reset_debounce;
1765 }
1766
1767 if( 0 ) {
1768 RETROGUI_CTL_TABLE( RETROGUI_CTL_TABLE_KEY )
1769 }
1770 }
1771
1772reset_debounce:
1773
1774 /* Reset repeat detector. */
1775 gui->idc_prev = RETROGUI_IDC_NONE;
1776
1777# endif
1778
1779cleanup:
1780
1781 if( MERROR_OK != retval ) {
1782 idc_out = RETROGUI_IDC_NONE;
1783 }
1784
1785 mdata_vector_unlock( &(gui->ctls) );
1786
1787 return idc_out;
1788}
1789
1790/* === */
1791
1792MERROR_RETVAL retrogui_redraw_ctls( struct RETROGUI* gui ) {
1793 size_t i = 0;
1794 union RETROGUI_CTL* ctl = NULL;
1795 MERROR_RETVAL retval = MERROR_OK;
1796 int autolock = 0;
1797
1798 /* OpenGL tends to call glClear on every frame, so always redraw! */
1799 if( RETROGUI_FLAGS_DIRTY != (RETROGUI_FLAGS_DIRTY & gui->flags) ) {
1800 /* Shortcut! */
1801 return MERROR_OK;
1802 }
1803
1804 if( 0 == mdata_vector_ct( &(gui->ctls) ) ) {
1805 return MERROR_OK;
1806 }
1807
1808 if( !retrogui_is_locked( gui ) ) {
1809 mdata_vector_lock( &(gui->ctls) );
1810 autolock = 1;
1811 }
1812
1813 if(
1814 RETROFLAT_COLOR_BLACK != gui->bg_color &&
1815 0 < gui->w && 0 < gui->h
1816 ) {
1817 retroflat_2d_rect( gui->draw_bmp,
1818 gui->bg_color, gui->x, gui->y, gui->w, gui->h, RETROFLAT_FLAGS_FILL );
1819 }
1820
1821 #define RETROGUI_CTL_TABLE_REDRAW( idx, c_name, c_fields ) \
1822 } else if( RETROGUI_CTL_TYPE_ ## c_name == ctl->base.type ) { \
1823 /* Mark dirty first so redraw can unmark it for animation! */ \
1824 gui->flags &= ~RETROGUI_FLAGS_DIRTY; \
1825 retrogui_redraw_ ## c_name( gui, ctl );
1826
1827 for( i = 0 ; mdata_vector_ct( &(gui->ctls) ) > i ; i++ ) {
1828 ctl = mdata_vector_get( &(gui->ctls), i, union RETROGUI_CTL );
1829 if( 0 ) {
1830 RETROGUI_CTL_TABLE( RETROGUI_CTL_TABLE_REDRAW )
1831 }
1832 }
1833
1834cleanup:
1835
1836 if( autolock ) {
1837 mdata_vector_unlock( &(gui->ctls) );
1838 }
1839
1840 return retval;
1841}
1842
1843/* === */
1844
1845MERROR_RETVAL retrogui_pos_ctl(
1846 struct RETROGUI* gui, retrogui_idc_t idc,
1847 size_t x, size_t y, size_t w, size_t h
1848) {
1849 MERROR_RETVAL retval = MERROR_OK;
1850 union RETROGUI_CTL* ctl = NULL;
1851 int autolock = 0;
1852
1853 if( !retrogui_is_locked( gui ) ) {
1854 mdata_vector_lock( &(gui->ctls) );
1855 autolock = 1;
1856 }
1857
1858 debug_printf( RETROGUI_TRACE_LVL,
1859 "moving control " SIZE_T_FMT " to: " SIZE_T_FMT ", " SIZE_T_FMT,
1860 idc, x, y );
1861
1862 ctl = _retrogui_get_ctl_by_idc( gui, idc );
1863 if( NULL == ctl ) {
1864 error_printf( "could not position control!" );
1865 retval = MERROR_GUI;
1866 goto cleanup;
1867 }
1868
1869 #define RETROGUI_CTL_TABLE_POS( idx, c_name, c_fields ) \
1870 } else if( RETROGUI_CTL_TYPE_ ## c_name == ctl->base.type ) { \
1871 /* Mark dirty first so redraw can unmark it for animation! */ \
1872 retval = retrogui_pos_ ## c_name( gui, ctl, x, y, w, h ); \
1873 maug_cleanup_if_not_ok();
1874
1875 if( 0 ) {
1876 RETROGUI_CTL_TABLE( RETROGUI_CTL_TABLE_POS )
1877 }
1878
1879 debug_printf( RETROGUI_TRACE_LVL,
1880 "moved control " SIZE_T_FMT " to " SIZE_T_FMT ", " SIZE_T_FMT
1881 " and sized to " SIZE_T_FMT "x" SIZE_T_FMT "...",
1882 ctl->base.idc, gui->x + ctl->base.x, gui->y + ctl->base.y,
1883 ctl->base.w, ctl->base.h );
1884
1885 /* New position! Redraw! */
1886 gui->flags |= RETROGUI_FLAGS_DIRTY;
1887
1888cleanup:
1889
1890 if( autolock ) {
1891 mdata_vector_unlock( &(gui->ctls) );
1892 }
1893
1894 return retval;
1895
1896}
1897
1898/* === */
1899
1900MERROR_RETVAL retrogui_push_ctl(
1901 struct RETROGUI* gui, union RETROGUI_CTL* ctl
1902) {
1903 MERROR_RETVAL retval = MERROR_OK;
1904 int autolock = 0;
1905
1906 assert( 0 < ctl->base.idc );
1907
1908#ifdef RETROGXC_PRESENT
1909 if( 0 > gui->font_idx ) {
1910#else
1911 if( (MAUG_MHANDLE)NULL == gui->font_h ) {
1912#endif /* RETROGXC_PRESENT */
1914 RETROFLAT_MSG_FLAG_ERROR, "Error", "GUI font not loaded!" );
1915 retval = MERROR_GUI;
1916 goto cleanup;
1917 }
1918
1919 /* TODO: Hunt for control IDC and fail if duplicate found! */
1920
1921 debug_printf( RETROGUI_TRACE_LVL,
1922 "gui->ctls_ct: " SIZE_T_FMT, mdata_vector_ct( &(gui->ctls) ) );
1923
1924 if(
1925 RETROGUI_CTL_TYPE_IMAGE != ctl->base.type &&
1926 RETROFLAT_COLOR_NULL == ctl->base.bg_color
1927 ) {
1929 "invalid background color specified for control " SIZE_T_FMT "!",
1930 ctl->base.idc );
1931 retval = MERROR_GUI;
1932 goto cleanup;
1933
1934 }
1935
1936 if(
1937 RETROGUI_CTL_TYPE_IMAGE != ctl->base.type &&
1938 RETROFLAT_COLOR_NULL == ctl->base.fg_color
1939 ) {
1941 "invalid foreground color specified for control " SIZE_T_FMT "!",
1942 ctl->base.idc );
1943 retval = MERROR_GUI;
1944 goto cleanup;
1945 }
1946
1947 /* Perform the actual push. */
1948 debug_printf( RETROGUI_TRACE_LVL,
1949 "pushing %s " SIZE_T_FMT " to slot " SIZE_T_FMT "...",
1950 gc_retrogui_ctl_names[ctl->base.type], ctl->base.idc,
1951 mdata_vector_ct( &(gui->ctls) ) );
1952
1953 mdata_vector_append( &(gui->ctls), ctl, sizeof( union RETROGUI_CTL ) );
1954
1955 gui->flags |= RETROGUI_FLAGS_DIRTY;
1956
1957 /* Now that append is done, lock the vector and grab a pointer to our
1958 * newly-pushed control to run some fixups on.
1959 */
1960 if( !retrogui_is_locked( gui ) ) {
1961 mdata_vector_lock( &(gui->ctls) );
1962 autolock = 1;
1963 }
1964
1965 /* TODO: More elegant way to grab index. */
1966 ctl = mdata_vector_get_last( &(gui->ctls),
1967 union RETROGUI_CTL );
1968 assert( NULL != ctl );
1969
1970 #define RETROGUI_CTL_TABLE_PUSH( idx, c_name, c_fields ) \
1971 } else if( RETROGUI_CTL_TYPE_ ## c_name == ctl->base.type ) { \
1972 debug_printf( RETROGUI_TRACE_LVL, \
1973 "running " #c_name " push hook..." ); \
1974 retval = retrogui_push_ ## c_name( ctl ); \
1975 maug_cleanup_if_not_ok();
1976
1977 if( 0 ) {
1978 RETROGUI_CTL_TABLE( RETROGUI_CTL_TABLE_PUSH )
1979 }
1980
1981 /* Try to auto-size the control now that the push-hook as set its text
1982 * or whatever else might be needed to determine an automatic size.
1983 */
1984 if( 0 == ctl->base.w || 0 == ctl->base.h ) {
1985 debug_printf( RETROGUI_TRACE_LVL,
1986 "determining size for new %s control " SIZE_T_FMT "...",
1987 gc_retrogui_ctl_names[ctl->base.type], ctl->base.idc );
1988 retval = _retrogui_sz_ctl(
1989 gui, ctl->base.idc, &(ctl->base.w), &(ctl->base.h), 0, 0 );
1990 maug_cleanup_if_not_ok();
1991 }
1992
1993 if( RETROGUI_IDC_NONE == gui->focus ) {
1994 gui->focus = ctl->base.idc;
1995 }
1996
1997cleanup:
1998
1999 if( autolock ) {
2000 mdata_vector_unlock( &(gui->ctls) );
2001 }
2002
2003 return retval;
2004}
2005
2006/* === */
2007
2008MERROR_RETVAL retrogui_remove_ctl( struct RETROGUI* gui, retrogui_idc_t idc ) {
2009 size_t i = 0;
2010 union RETROGUI_CTL* ctl = NULL;
2011 MERROR_RETVAL retval = MERROR_OK;
2012
2013 if( retrogui_is_locked( gui ) ) {
2014 error_printf( "GUI is locked!" );
2015 goto cleanup;
2016 }
2017
2018 assert( !retrogui_is_locked( gui ) );
2019 mdata_vector_lock( &(gui->ctls) );
2020
2021 #define RETROGUI_CTL_TABLE_FREE_CTL( idx, c_name, c_fields ) \
2022 } else if( RETROGUI_CTL_TYPE_ ## c_name == ctl->base.type ) { \
2023 retrogui_free_ ## c_name( ctl );
2024
2025 for( i = 0 ; mdata_vector_ct( &(gui->ctls) ) > i ; i++ ) {
2026 ctl = mdata_vector_get( &(gui->ctls), i, union RETROGUI_CTL );
2027 if( idc != ctl->base.idc ) {
2028 continue;
2029 }
2030
2031 /* Free the control data. */
2032 if( 0 ) {
2033 RETROGUI_CTL_TABLE( RETROGUI_CTL_TABLE_FREE_CTL )
2034 }
2035
2036 /* Remove the control. */
2037 mdata_vector_unlock( &(gui->ctls) );
2038 mdata_vector_remove( &(gui->ctls), i );
2039 mdata_vector_lock( &(gui->ctls) );
2040 break;
2041 }
2042
2043 mdata_vector_unlock( &(gui->ctls) );
2044
2045cleanup:
2046
2047 return retval;
2048}
2049
2050/* === */
2051
2052#ifndef RETROGUI_NO_TEXTBOX
2053
2054MERROR_RETVAL retrogui_get_ctl_text(
2055 struct RETROGUI* gui, retrogui_idc_t idc, char* buffer, size_t buffer_sz
2056) {
2057 MERROR_RETVAL retval = MERROR_OK;
2058 union RETROGUI_CTL* ctl = NULL;
2059 int autolock = 0;
2060
2061 if( !retrogui_is_locked( gui ) ) {
2062 mdata_vector_lock( &(gui->ctls) );
2063 autolock = 1;
2064 }
2065
2066 ctl = _retrogui_get_ctl_by_idc( gui, idc );
2067 if( NULL == ctl ) {
2068 goto cleanup;
2069 }
2070
2071 if( RETROGUI_CTL_TYPE_TEXTBOX == ctl->base.type ) {
2072# if defined( RETROGUI_NATIVE_WIN )
2073 /* TODO */
2074#else
2075 maug_mlock( ctl->TEXTBOX.text_h, ctl->TEXTBOX.text );
2076 maug_cleanup_if_null_lock( char*, ctl->TEXTBOX.text );
2077
2078 maug_strncpy( buffer, ctl->TEXTBOX.text, buffer_sz );
2079# endif
2080 } else if( RETROGUI_CTL_TYPE_LABEL == ctl->base.type ) {
2081# if defined( RETROGUI_NATIVE_WIN )
2082 /* TODO */
2083#else
2084 maug_mlock( ctl->LABEL.label_h, ctl->LABEL.label );
2085 maug_cleanup_if_null_lock( char*, ctl->LABEL.label );
2086
2087 maug_strncpy( buffer, ctl->LABEL.label, buffer_sz );
2088# endif
2089
2090 }
2091
2092cleanup:
2093
2094 if( RETROGUI_CTL_TYPE_TEXTBOX == ctl->base.type ) {
2095 if( NULL != ctl->TEXTBOX.text ) {
2096 maug_munlock( ctl->TEXTBOX.text_h, ctl->TEXTBOX.text );
2097 }
2098
2099 } else if( RETROGUI_CTL_TYPE_LABEL == ctl->base.type ) {
2100 if( NULL != ctl->LABEL.label ) {
2101 maug_munlock( ctl->LABEL.label_h, ctl->LABEL.label );
2102 }
2103 }
2104
2105 if( autolock ) {
2106 mdata_vector_unlock( &(gui->ctls) );
2107 }
2108
2109 return retval;
2110}
2111
2112#endif /* !RETROGUI_NO_TEXTBOX */
2113
2114/* === */
2115
2116ssize_t retrogui_get_ctl_sel_idx( struct RETROGUI* gui, retrogui_idc_t idc ) {
2117 ssize_t idx = -1;
2118 union RETROGUI_CTL* ctl = NULL;
2119 MERROR_RETVAL retval = MERROR_OK;
2120 int autolock = 0;
2121
2122 if( !retrogui_is_locked( gui ) ) {
2123 mdata_vector_lock( &(gui->ctls) );
2124 }
2125
2126 ctl = _retrogui_get_ctl_by_idc( gui, idc );
2127 if( NULL == ctl ) {
2128 goto cleanup;
2129 }
2130
2131 assert( RETROGUI_CTL_TYPE_LISTBOX == ctl->base.type );
2132
2133# if defined( RETROGUI_NATIVE_WIN )
2134 idx = SendMessage( ctl->base.hwnd, LB_GETCARETINDEX, 0, 0 );
2135# else
2136 idx = ctl->LISTBOX.sel_idx;
2137# endif
2138
2139cleanup:
2140
2141 if( autolock ) {
2142 mdata_vector_unlock( &(gui->ctls) );
2143 }
2144
2145 if( MERROR_OK != retval ) {
2146 idx = -1 * retval;
2147 }
2148
2149 return idx;
2150}
2151
2152/* === */
2153
2154MERROR_RETVAL retrogui_set_ctl_text(
2155 struct RETROGUI* gui, retrogui_idc_t idc, size_t buffer_sz,
2156 const char* fmt, ...
2157) {
2158 MERROR_RETVAL retval = MERROR_OK;
2159 size_t label_sz = 0;
2160 char* label_tmp = NULL;
2161 char* buffer = NULL;
2162 union RETROGUI_CTL* ctl = NULL;
2163 MAUG_MHANDLE buffer_h = (MAUG_MHANDLE)NULL;
2164 va_list args;
2165
2166 assert( !retrogui_is_locked( gui ) );
2167 mdata_vector_lock( &(gui->ctls) );
2168
2169 debug_printf( RETROGUI_TRACE_LVL,
2170 "setting control " SIZE_T_FMT " text to: %s", idc, fmt );
2171
2172 /* Figure out the control to update. */
2173 ctl = _retrogui_get_ctl_by_idc( gui, idc );
2174 if( NULL == ctl ) {
2175 retval = MERROR_GUI;
2176 goto cleanup;
2177 }
2178
2179 /* Perform the buffer substitutions. */
2180 buffer_h = maug_malloc( 1, buffer_sz + 1 );
2181 maug_cleanup_if_null_alloc( MAUG_MHANDLE, buffer_h );
2182
2183 assert( 0 < buffer_sz );
2184
2185 maug_mlock( buffer_h, buffer );
2186 maug_cleanup_if_null_lock( char*, buffer );
2187 maug_mzero( buffer, buffer_sz + 1 );
2188
2189 assert( NULL != buffer );
2190
2191 if( NULL == fmt ) {
2192 /* Zero the buffer. */
2193 maug_mzero( buffer, buffer_sz + 1);
2194
2195 } else {
2196 /* Format the buffer. */
2197 va_start( args, fmt );
2198 maug_vsnprintf( buffer, buffer_sz, fmt, args );
2199 va_end( args );
2200 }
2201
2202 /* Perform the actual update. */
2203 if( RETROGUI_CTL_TYPE_BUTTON == ctl->base.type ) {
2204 assert( NULL == ctl->BUTTON.label );
2205 _retrogui_copy_str( label, buffer, ctl->BUTTON, label_tmp, buffer_sz );
2206 } else if( RETROGUI_CTL_TYPE_LABEL == ctl->base.type ) {
2207 assert( NULL == ctl->LABEL.label );
2208 _retrogui_copy_str( label, buffer, ctl->LABEL, label_tmp, label_sz );
2209#ifndef RETROGUI_NO_TEXTBOX
2210 } else if( RETROGUI_CTL_TYPE_TEXTBOX == ctl->base.type ) {
2211 assert( NULL == ctl->TEXTBOX.text );
2212 /* This must always be the same and an lvalue! */
2213 label_sz = RETROGUI_CTL_TEXT_SZ_MAX;
2214 _retrogui_copy_str(
2215 text, buffer, ctl->TEXTBOX, label_tmp, label_sz );
2216 ctl->TEXTBOX.text_cur = 0;
2217#endif /* !RETROGUI_NO_TEXTBOX */
2218 } else {
2219 error_printf( "invalid control type! no label!" );
2220 goto cleanup;
2221 }
2222
2223 /* New text! Redraw! */
2224 gui->flags |= RETROGUI_FLAGS_DIRTY;
2225
2226cleanup:
2227
2228 if( NULL != buffer ) {
2229 maug_munlock( buffer_h, buffer );
2230 }
2231
2232 if( NULL != buffer_h ) {
2233 maug_mfree( buffer_h );
2234 }
2235
2236 mdata_vector_unlock( &(gui->ctls) );
2237
2238 return retval;
2239}
2240
2241/* === */
2242
2243MERROR_RETVAL retrogui_set_ctl_image(
2244 struct RETROGUI* gui, retrogui_idc_t idc, const char* path, uint8_t flags
2245) {
2246 MERROR_RETVAL retval = MERROR_OK;
2247 union RETROGUI_CTL* ctl = NULL;
2248 int autolock = 0;
2249
2250 if( !retrogui_is_locked( gui ) ) {
2251 mdata_vector_lock( &(gui->ctls) );
2252 autolock = 1;
2253 }
2254
2255 debug_printf( RETROGUI_TRACE_LVL,
2256 "setting control " SIZE_T_FMT " image to: %s", idc, path );
2257
2258 /* Figure out the control to update. */
2259 ctl = _retrogui_get_ctl_by_idc( gui, idc );
2260 if( NULL == ctl ) {
2261 retval = MERROR_GUI;
2262 goto cleanup;
2263 }
2264
2265 /* Perform the actual update. */
2266 if( RETROGUI_CTL_TYPE_IMAGE == ctl->base.type ) {
2267 if( NULL != path ) {
2268# if defined( RETROGXC_PRESENT )
2269 ctl->IMAGE.image_cache_id = retrogxc_load_bitmap( path, 0 );
2270# else
2271 retroflat_2d_load_bitmap( path, &(ctl->IMAGE.image), 0 );
2272# endif /* RETROGXC_PRESENT */
2273 } else {
2274# ifdef RETROGXC_PRESENT
2275 ctl->IMAGE.image_cache_id = -1;
2276# else
2277 retroflat_2d_destroy_bitmap( &(ctl->IMAGE.image) );
2278# endif /* RETROGXC_PRESENT */
2279 }
2280 } else {
2281 error_printf( "invalid control type! no image!" );
2282 goto cleanup;
2283 }
2284
2285 /* New text! Redraw! */
2286 gui->flags |= RETROGUI_FLAGS_DIRTY;
2287
2288cleanup:
2289
2290 if( autolock ) {
2291 mdata_vector_unlock( &(gui->ctls) );
2292 }
2293
2294 return retval;
2295}
2296
2297/* === */
2298
2299MERROR_RETVAL retrogui_set_ctl_level(
2300 struct RETROGUI* gui, retrogui_idc_t idc, uint16_t level, uint16_t max,
2301 uint8_t flags
2302) {
2303 MERROR_RETVAL retval = MERROR_OK;
2304 union RETROGUI_CTL* ctl = NULL;
2305 int autolock = 0;
2306
2307 if( !retrogui_is_locked( gui ) ) {
2308 mdata_vector_lock( &(gui->ctls) );
2309 autolock = 1;
2310 }
2311
2312 debug_printf( RETROGUI_TRACE_LVL,
2313 "setting control " SIZE_T_FMT " level to: %u", idc, level );
2314
2315 /* Figure out the control to update. */
2316 ctl = _retrogui_get_ctl_by_idc( gui, idc );
2317 if( NULL == ctl ) {
2318 retval = MERROR_GUI;
2319 goto cleanup;
2320 }
2321
2322 /* Perform the actual update. */
2323 if( RETROGUI_CTL_TYPE_FILLBAR == ctl->base.type ) {
2324 ctl->FILLBAR.cur = level;
2325 if( 0 < max ) {
2326 ctl->FILLBAR.max = max;
2327 }
2328 } else {
2329 error_printf( "invalid control type! no level!" );
2330 goto cleanup;
2331 }
2332
2333 /* New level! Redraw! */
2334 gui->flags |= RETROGUI_FLAGS_DIRTY;
2335
2336cleanup:
2337
2338 if( autolock ) {
2339 mdata_vector_unlock( &(gui->ctls) );
2340 }
2341
2342 return retval;
2343}
2344
2345/* === */
2346
2347MERROR_RETVAL retrogui_init_ctl(
2348 union RETROGUI_CTL* ctl, uint8_t type, size_t idc
2349) {
2350 MERROR_RETVAL retval = MERROR_OK;
2351
2352 debug_printf( RETROGUI_TRACE_LVL,
2353 "initializing control base " SIZE_T_FMT "...", idc );
2354
2355 maug_mzero( ctl, sizeof( union RETROGUI_CTL ) );
2356
2357 ctl->base.type = type;
2358 ctl->base.idc = idc;
2359 ctl->base.fg_color = RETROFLAT_COLOR_NULL;
2360 ctl->base.bg_color = RETROFLAT_COLOR_NULL;
2361 ctl->base.sel_fg = RETROFLAT_COLOR_NULL;
2362 ctl->base.sel_bg = RETROFLAT_COLOR_NULL;
2363
2364 #define RETROGUI_CTL_TABLE_INITS( idx, c_name, c_fields ) \
2365 } else if( RETROGUI_CTL_TYPE_ ## c_name == ctl->base.type ) { \
2366 retrogui_init_ ## c_name( ctl );
2367
2368 if( 0 ) {
2369 RETROGUI_CTL_TABLE( RETROGUI_CTL_TABLE_INITS )
2370 }
2371
2372# ifdef RETROGXC_PRESENT
2373 if( RETROGUI_CTL_TYPE_IMAGE == type ) {
2374 ctl->IMAGE.image_cache_id = -1;
2375 }
2376# endif /* !RETROGXC_PRESENT */
2377
2378 return retval;
2379}
2380
2381/* === */
2382
2383MERROR_RETVAL retrogui_free( struct RETROGUI* gui ) {
2384 size_t i = 0;
2385 union RETROGUI_CTL* ctl = NULL;
2386 MERROR_RETVAL retval = MERROR_OK;
2387
2388 if( retrogui_is_locked( gui ) ) {
2389 error_printf( "GUI is locked!" );
2390 goto cleanup;
2391 }
2392
2393 if( 0 == mdata_vector_ct( &(gui->ctls) ) ) {
2394 goto cleanup;
2395 }
2396
2397 assert( !retrogui_is_locked( gui ) );
2398 mdata_vector_lock( &(gui->ctls) );
2399
2400 #define RETROGUI_CTL_TABLE_FREE( idx, c_name, c_fields ) \
2401 } else if( RETROGUI_CTL_TYPE_ ## c_name == ctl->base.type ) { \
2402 retrogui_free_ ## c_name( ctl );
2403
2404 for( i = 0 ; mdata_vector_ct( &(gui->ctls) ) > i ; i++ ) {
2405 ctl = mdata_vector_get( &(gui->ctls), i, union RETROGUI_CTL );
2406 if( 0 ) {
2407 RETROGUI_CTL_TABLE( RETROGUI_CTL_TABLE_FREE )
2408 }
2409 }
2410
2411 mdata_vector_unlock( &(gui->ctls) );
2412
2413cleanup:
2414
2415 mdata_vector_free( &(gui->ctls) );
2416
2417 return retval;
2418}
2419
2420/* === */
2421
2422retrogui_idc_t retrogui_focus_iter(
2423 struct RETROGUI* gui, size_t start, ssize_t incr
2424) {
2425 retrogui_idc_t idc_out = RETROGUI_IDC_NONE;
2426 union RETROGUI_CTL* ctl = NULL;
2427 MERROR_RETVAL retval = MERROR_OK;
2428 ssize_t i = 0;
2429 ssize_t i_before = -1;
2430 int autolock = 0;
2431
2432 if( 0 == mdata_vector_ct( &(gui->ctls) ) ) {
2433 goto cleanup;
2434 }
2435
2436 if( !retrogui_is_locked( gui ) ) {
2437 mdata_vector_lock( &(gui->ctls) );
2438 autolock = 1;
2439 }
2440
2441 /* Find the currently selected IDC. */
2442 for(
2443 i = start ; mdata_vector_ct( &(gui->ctls) ) > i && 0 <= i ; i += incr
2444 ) {
2445 ctl = mdata_vector_get( &(gui->ctls), i, union RETROGUI_CTL );
2446 if( RETROGUI_CTL_TYPE_BUTTON != ctl->base.type ) {
2447 continue;
2448 } else if( RETROGUI_IDC_NONE == gui->focus || 0 <= i_before ) {
2449 /* We're primed to set the new focus, so do that and finish. */
2450 idc_out = ctl->base.idc;
2451 gui->focus = idc_out;
2452 goto cleanup;
2453
2454 } else if( ctl->base.idc == gui->focus ) {
2455 /* We've found the current focus, so prime to select the new focus. */
2456 i_before = i;
2457 }
2458 }
2459
2460 /* We didn't select a focus in the loop above, so we must be wrapping around!
2461 */
2462
2463 /* Select the next IDC. */
2464 if( 0 > i ) {
2465 /* Wrap around to last item. */
2466 idc_out = mdata_vector_get( &(gui->ctls),
2467 mdata_vector_ct( &(gui->ctls) ) - 1, union RETROGUI_CTL )->base.idc;
2468 gui->focus = idc_out;
2469
2470 } else if( mdata_vector_ct( &(gui->ctls) ) <= i ) {
2471 /* Wrap around to first item. */
2472 idc_out =
2473 mdata_vector_get( &(gui->ctls), 0, union RETROGUI_CTL )->base.idc;
2474 gui->focus = idc_out;
2475
2476 } else {
2477 error_printf( "invalid focus: " SSIZE_T_FMT, i );
2478
2479 }
2480
2481cleanup:
2482
2483 /* New focus! Dirty! */
2484 gui->flags |= RETROGUI_FLAGS_DIRTY;
2485
2486 if( MERROR_OK != retval ) {
2487 idc_out = merror_retval_to_sz( retval );
2488 }
2489
2490 if( autolock ) {
2491 mdata_vector_unlock( &(gui->ctls) );
2492 }
2493
2494 debug_printf( RETROGUI_TRACE_LVL, "selected IDC: " SIZE_T_FMT, idc_out );
2495
2496 return idc_out;
2497}
2498
2499/* === */
2500
2501MERROR_RETVAL retrogui_init( struct RETROGUI* gui ) {
2502 MERROR_RETVAL retval = MERROR_OK;
2503
2504 maug_mzero( gui, sizeof( struct RETROGUI ) );
2505
2506 gui->bg_color = RETROFLAT_COLOR_BLACK;
2507 gui->focus = RETROGUI_IDC_NONE;
2508
2509 debug_printf( RETROGUI_TRACE_LVL, "initialized GUI" );
2510
2511 return retval;
2512}
2513
2514#else
2515
2516#define RETROGUI_CTL_TABLE_CONSTS( idx, c_name, c_fields ) \
2517 extern MAUG_CONST uint8_t RETROGUI_CTL_TYPE_ ## c_name;
2518
2519RETROGUI_CTL_TABLE( RETROGUI_CTL_TABLE_CONSTS )
2520
2521extern MAUG_CONST char* gc_retrogui_ctl_names[];
2522
2523#endif /* RETROGUI_C */
2524 /* maug_retrogui */
2526
2527#endif /* !RETROGUI_H */
2528
int MERROR_RETVAL
Return type indicating function returns a value from this list.
Definition merror.h:19
#define maug_mzero(ptr, sz)
Zero the block of memory pointed to by ptr.
Definition mmem.h:65
void retroflat_message(uint8_t flags, const char *title, const char *format,...)
Display a message in a dialog box and/or on stderr.
int8_t RETROFLAT_COLOR
Defines an index in the platform-specific color-table.
Definition retroflt.h:325
#define RETROFLAT_FLAGS_FILL
Flag for retroflat_rect() or retroflat_ellipse(), indicating drawn shape should be filled.
Definition retroflt.h:373
#define retroflat_buffer_insert(c, buffer, buffer_cur, buffer_sz, buffer_mx)
Insert a character into a text buffer at cursor position.
Definition retroflt.h:819
#define retroflat_buffer_bksp(buffer, buffer_cur, buffer_sz)
Remove a character from a text buffer before cursor position.
Definition retroflt.h:803
#define RETROFLAT_MSG_FLAG_ERROR
This icon/type flag indicates an error. It will try to display messages in an urgent way with a red i...
Definition retroflt.h:456
int mouse_y
Y-coordinate of the mouse pointer in pixels if the returned event is a mouse click.
Definition retroflt.h:852
int mouse_x
X-coordinate of the mouse pointer in pixels if the returned event is a mouse click.
Definition retroflt.h:847
size_t retroflat_pxxy_t
Type used for surface pixel coordinates.
Definition retroflt.h:895
#define RETROGUI_CTL_TABLE_FIELDS(idx, c_name, c_fields)
Creates the corresponding RETROGUI_* structs from RETROGUI_CTL_TABLE that populate union RETROGUI_CTL...
Definition retrogui.h:161
#define RETROGUI_CTL_TABLE_TYPES(idx, c_name, c_fields)
Adds the structs created by RETROGUI_CTL_TABLE_FIELDS to union RETROGUI_CTL.
Definition retrogui.h:173
#define RETROGUI_FLAGS_DIRTY
RETROGUI::flags indicating controls should be redrawn.
Definition retrogui.h:28
ssize_t retrogui_idc_t
Unique identifying constant number for controls.
Definition retrogui.h:103
retrogui_idc_t retrogui_poll_ctls(struct RETROGUI *gui, RETROFLAT_IN_KEY *p_input, struct RETROFLAT_INPUT *input_evt)
Poll for the last clicked control and maintain listboxes and menus.
A vector of uniformly-sized objects, stored contiguously.
Definition mdata.h:89
size_t item_sz
Size, in bytes, of each item.
Definition mdata.h:105
Struct passed to retroflat_poll_input() to hold return data.
Definition retroflt.h:842
Fields common to ALL RETROGUI_CTL types.
Definition retrogui.h:141
Definition retrogui.h:186
Definition retrogui.h:176