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
11#ifndef RETROFONT_PRESENT
12# error "retrofont not present!"
13#endif /* !RETROFONT_PRESENT */
14
16#define RETROGUI_FLAGS_DIRTY 0x01
17
18#ifndef RETROGUI_TRACE_LVL
19# define RETROGUI_TRACE_LVL 0
20#endif /* !RETROGUI_TRACE_LVL */
21
22#ifndef RETROGUI_CTL_TEXT_SZ_MAX
23# define RETROGUI_CTL_TEXT_SZ_MAX 128
24#endif /* !RETROGUI_CTL_TEXT_SZ_MAX */
25
26#ifndef RETROGUI_CTL_SZ_MAX_INIT
27# define RETROGUI_CTL_SZ_MAX_INIT 20
28#endif /* !RETROGUI_CTL_SZ_MAX_INIT */
29
30#ifndef RETROGUI_PADDING
31# define RETROGUI_PADDING 5
32#endif /* !RETROGUI_PADDING */
33
34#ifndef RETROGUI_BTN_LBL_SZ_MAX
35# define RETROGUI_BTN_LBL_SZ_MAX 64
36#endif /* !RETROGUI_BTN_LBL_SZ_MAX */
37
38#ifndef RETROGUI_BTN_LBL_PADDED_X
39# define RETROGUI_BTN_LBL_PADDED_X 8
40#endif /* !RETROGUI_BTN_LBL_PADDED_X */
41
42#ifndef RETROGUI_BTN_LBL_PADDED_Y
43# define RETROGUI_BTN_LBL_PADDED_Y 8
44#endif /* !RETROGUI_BTN_LBL_PADDED_Y */
45
46#ifndef RETROGUI_CTL_TEXT_BLINK_FRAMES
47# define RETROGUI_CTL_TEXT_BLINK_FRAMES 15
48#endif /* !RETROGUI_CTL_TEXT_BLINK_FRAMES */
49
50#define retrogui_lock( gui )
51
52#define retrogui_unlock( gui )
53
54#define retrogui_is_locked( gui ) (mdata_vector_is_locked( &((gui)->ctls) ))
55
56#define _retrogui_copy_str( field, src_str, dest_ctl, str_tmp, str_sz ) \
57 /* Sanity checking. */ \
58 assert( NULL != src_str ); \
59 debug_printf( RETROGUI_TRACE_LVL, \
60 "copying string \"%s\" to " #dest_ctl, src_str ); \
61 if( 0 == str_sz ) { \
62 str_sz = maug_strlen( src_str ); \
63 debug_printf( RETROGUI_TRACE_LVL, \
64 "determined str sz of \"%s\": " SIZE_T_FMT, src_str, str_sz ); \
65 } \
66 if( (MAUG_MHANDLE)NULL != dest_ctl. field ## _h ) { \
67 /* Free the existing string. */ \
68 maug_mfree( dest_ctl. field ## _h ); \
69 } \
70 \
71 /* Allocate new string space. */ \
72 dest_ctl. field ## _h = maug_malloc( str_sz + 1, 1 ); \
73 debug_printf( RETROGUI_TRACE_LVL, \
74 "allocated str sz for \"%s\": " SIZE_T_FMT, src_str, str_sz + 1 ); \
75 maug_cleanup_if_null_alloc( MAUG_MHANDLE, dest_ctl. field ## _h ); \
76 maug_mlock( dest_ctl. field ## _h, str_tmp ); \
77 maug_cleanup_if_null_lock( char*, str_tmp ); \
78 \
79 /* Copy the string over. */ \
80 assert( NULL != str_tmp ); \
81 maug_mzero( str_tmp, str_sz + 1 ); \
82 debug_printf( RETROGUI_TRACE_LVL, \
83 "zeroed str sz for \"%s\": " SIZE_T_FMT, src_str, str_sz + 1 ); \
84 maug_strncpy( str_tmp, src_str, str_sz ); \
85 debug_printf( RETROGUI_TRACE_LVL, "copied str as: \"%s\"", str_tmp ); \
86 maug_munlock( dest_ctl. field ## _h, str_tmp );
87
89typedef size_t retrogui_idc_t;
90
91#define RETROGUI_IDC_NONE 0
92
107#define RETROGUI_CTL_TABLE_BASE( f ) \
108 f( 0, NONE, void* none; ) \
109 f( 1, LISTBOX, MAUG_MHANDLE list_h; char* list; size_t list_sz; size_t list_sz_max; size_t sel_idx; ) \
110 f( 2, BUTTON, MAUG_MHANDLE label_h; char* label; size_t label_sz; int16_t push_frames; uint8_t font_flags; ) \
111 f( 3, LABEL, MAUG_MHANDLE label_h; char* label; size_t label_sz; uint8_t font_flags; )
112
113#ifdef RETROGUI_NO_TEXTBOX
114# define RETROGUI_CTL_TABLE( f ) RETROGUI_CTL_TABLE_BASE( f )
115#else
116# define RETROGUI_CTL_TABLE( f ) RETROGUI_CTL_TABLE_BASE( f ) \
117 f( 4, TEXTBOX, MAUG_MHANDLE text_h; char* text; size_t text_sz; size_t text_sz_max; size_t text_cur; int16_t blink_frames; )
118#endif /* RETROGUI_NO_TEXTBOX */
119
120#if 0
121 f( 5, SCROLLBAR, size_t min; size_t max; size_t value; )
122#endif
123
126 uint8_t type;
127 retrogui_idc_t idc;
128 size_t x;
129 size_t y;
130 size_t w;
131 size_t h;
132 RETROFLAT_COLOR bg_color;
133 RETROFLAT_COLOR fg_color;
134#if defined( RETROGUI_NATIVE_WIN )
135 HWND hwnd;
136#endif
137};
138
143#define RETROGUI_CTL_TABLE_FIELDS( idx, c_name, c_fields ) \
144 struct RETROGUI_CTL_ ## c_name { \
145 struct RETROGUI_CTL_BASE base; \
146 c_fields \
147 };
148
149RETROGUI_CTL_TABLE( RETROGUI_CTL_TABLE_FIELDS )
150
151
155#define RETROGUI_CTL_TABLE_TYPES( idx, c_name, c_fields ) \
156 struct RETROGUI_CTL_ ## c_name c_name;
157
159 struct RETROGUI_CTL_BASE base;
160 RETROGUI_CTL_TABLE( RETROGUI_CTL_TABLE_TYPES )
161};
162
163 /* maug_retrogui_ctl */
164
165typedef void (*retrogui_xy_cb)( size_t* x, size_t* y, void* data );
166
167struct RETROGUI {
168 uint8_t flags;
169 size_t x;
170 size_t y;
171 size_t w;
172 size_t h;
173 RETROFLAT_COLOR bg_color;
174 retrogui_idc_t idc_prev;
175 struct MDATA_VECTOR ctls;
176 retrogui_idc_t focus;
177 struct RETROFLAT_BITMAP* draw_bmp;
178#ifdef RETROGXC_PRESENT
179 ssize_t font_idx;
180#else
181 MAUG_MHANDLE font_h;
182#endif /* RETROGXC_PRESENT */
183};
184
185MERROR_RETVAL retrogui_push_listbox_item(
186 struct RETROGUI* gui, retrogui_idc_t idc, const char* item, size_t item_sz );
187
197 struct RETROGUI* gui, RETROFLAT_IN_KEY* p_input,
198 struct RETROFLAT_INPUT* input_evt );
199
200MERROR_RETVAL retrogui_redraw_ctls( struct RETROGUI* gui );
201
202MERROR_RETVAL retrogui_sz_ctl(
203 struct RETROGUI* gui, retrogui_idc_t idc,
204 size_t* p_w, size_t* p_h, size_t max_w, size_t max_h );
205
206MERROR_RETVAL retrogui_pos_ctl(
207 struct RETROGUI* gui, retrogui_idc_t idc,
208 size_t x, size_t y, size_t w, size_t h );
209
210MERROR_RETVAL retrogui_push_ctl(
211 struct RETROGUI* gui, union RETROGUI_CTL* ctl );
212
213MERROR_RETVAL retrogui_get_ctl_text(
214 struct RETROGUI* gui, retrogui_idc_t idc, char* buffer, size_t buffer_sz );
215
216ssize_t retrogui_get_ctl_sel_idx( struct RETROGUI* gui, size_t idc );
217
218#ifndef RETROGUI_NO_TEXTBOX
219
220/*
221MERROR_RETVAL retrogui_set_ctl_text(
222 struct RETROGUI* gui, retrogui_idc_t idc,
223 const char* buffer, size_t buffer_sz );
224*/
225
226#endif /* !RETROGUI_NO_TEXTBOX */
227
228MERROR_RETVAL retrogui_set_ctl_text(
229 struct RETROGUI* gui, retrogui_idc_t idc, size_t buffer_sz,
230 const char* fmt, ... );
231
232MERROR_RETVAL retrogui_init_ctl(
233 union RETROGUI_CTL* ctl, uint8_t type, size_t idc );
234
235MERROR_RETVAL retrogui_init( struct RETROGUI* gui );
236
237MERROR_RETVAL retrogui_remove_ctl( struct RETROGUI* gui, retrogui_idc_t idc );
238
239MERROR_RETVAL retrogui_free( struct RETROGUI* gui );
240
241#ifdef RETROGUI_C
242
243#define RETROGUI_CTL_TABLE_CONSTS( idx, c_name, c_fields ) \
244 MAUG_CONST uint8_t RETROGUI_CTL_TYPE_ ## c_name = idx;
245
246RETROGUI_CTL_TABLE( RETROGUI_CTL_TABLE_CONSTS )
247
248#define RETROGUI_CTL_TABLE_NAMES( idx, c_name, f_fields ) \
249 #c_name,
250
251MAUG_CONST char* gc_retrogui_ctl_names[] = {
252 RETROGUI_CTL_TABLE( RETROGUI_CTL_TABLE_NAMES )
253 ""
254};
255
256static union RETROGUI_CTL* _retrogui_get_ctl_by_idc(
257 struct RETROGUI* gui, size_t idc );
258
259/* === Control: NONE === */
260
261static retrogui_idc_t retrogui_click_NONE(
262 struct RETROGUI* gui,
263 union RETROGUI_CTL* ctl, RETROFLAT_IN_KEY* p_input,
264 struct RETROFLAT_INPUT* input_evt
265) {
266 retrogui_idc_t idc_out = RETROGUI_IDC_NONE;
267
268 return idc_out;
269}
270
271static retrogui_idc_t retrogui_key_NONE(
272 union RETROGUI_CTL* ctl, RETROFLAT_IN_KEY* p_input,
273 struct RETROFLAT_INPUT* input_evt
274) {
275 retrogui_idc_t idc_out = RETROGUI_IDC_NONE;
276
277 return idc_out;
278}
279
280void retrogui_redraw_NONE( struct RETROGUI* gui, union RETROGUI_CTL* ctl ) {
281}
282
283static MERROR_RETVAL retrogui_push_NONE( union RETROGUI_CTL* ctl ) {
284 MERROR_RETVAL retval = MERROR_GUI;
285
286 return retval;
287}
288
289static MERROR_RETVAL retrogui_sz_NONE(
290 struct RETROGUI* gui, union RETROGUI_CTL* ctl,
291 size_t* p_w, size_t* p_h, size_t max_w, size_t max_h
292) {
293 return MERROR_OK;
294}
295
296static MERROR_RETVAL retrogui_pos_NONE(
297 struct RETROGUI* gui, union RETROGUI_CTL* ctl,
298 size_t x, size_t y, size_t w, size_t h
299) {
300 return MERROR_OK;
301}
302
303static void retrogui_free_NONE( union RETROGUI_CTL* ctl ) {
304}
305
306static MERROR_RETVAL retrogui_init_NONE( union RETROGUI_CTL* ctl ) {
307 MERROR_RETVAL retval = MERROR_GUI;
308
309 return retval;
310}
311
312/* === Control: LISTBOX === */
313
314static retrogui_idc_t retrogui_click_LISTBOX(
315 struct RETROGUI* gui,
316 union RETROGUI_CTL* ctl, RETROFLAT_IN_KEY* p_input,
317 struct RETROFLAT_INPUT* input_evt
318) {
319 retrogui_idc_t idc_out = RETROGUI_IDC_NONE;
320 MERROR_RETVAL retval = MERROR_OK;
321 size_t i = 0,
322 j = 0,
323 w = 0,
324 h = 0;
325
326# if defined( RETROGUI_NATIVE_WIN )
327 /* Do nothing. */
328# else
329
330 assert( NULL == ctl->LISTBOX.list );
331 assert( NULL != ctl->LISTBOX.list_h );
332 maug_mlock( ctl->LISTBOX.list_h, ctl->LISTBOX.list );
333 maug_cleanup_if_null_lock( char*, ctl->LISTBOX.list );
334
335 /* Figure out the item clicked. */
336 while( i < ctl->LISTBOX.list_sz ) {
337#ifdef RETROGXC_PRESENT
338 retrogxc_string_sz(
339 gui->draw_bmp, &(ctl->LISTBOX.list[i]), 0, gui->font_idx,
340 ctl->base.w, ctl->base.h, &w, &h, 0 );
341#else
342 retrofont_string_sz(
343 gui->draw_bmp, &(ctl->LISTBOX.list[i]), 0, gui->font_h,
344 ctl->base.w, ctl->base.h, &w, &h, 0 );
345#endif /* RETROGXC_PRESENT */
346
347 if(
348 (size_t)(input_evt->mouse_y) <
349 ctl->base.y + ((j + 1) * (h + RETROGUI_PADDING))
350 ) {
351 ctl->LISTBOX.sel_idx = j;
352 break;
353 }
354
355 /* Try next variable-length string. */
356 i += maug_strlen( &(ctl->LISTBOX.list[i]) ) + 1;
357 assert( i <= ctl->LISTBOX.list_sz );
358 j++;
359 }
360
361cleanup:
362
363 if( NULL != ctl->LISTBOX.list ) {
364 maug_munlock( ctl->LISTBOX.list_h, ctl->LISTBOX.list );
365 }
366
367 if( MERROR_OK != retval ) {
368 idc_out = RETROGUI_IDC_NONE;
369 }
370
371#endif
372
373 return idc_out;
374}
375
376static retrogui_idc_t retrogui_key_LISTBOX(
377 union RETROGUI_CTL* ctl, RETROFLAT_IN_KEY* p_input,
378 struct RETROFLAT_INPUT* input_evt
379) {
380 retrogui_idc_t idc_out = RETROGUI_IDC_NONE;
381
382 /* TODO: Move up or down to next/prev item. */
383
384 return idc_out;
385}
386
387static void retrogui_redraw_LISTBOX(
388 struct RETROGUI* gui, union RETROGUI_CTL* ctl
389) {
390 size_t i = 0,
391 j = 0,
392 w = 0,
393 h = 0;
394
395 assert( NULL == ctl->LISTBOX.list );
396
397# if defined( RETROGUI_NATIVE_WIN )
398 /* TODO: InvalidateRect()? */
399# else
400
401 maug_mlock( ctl->LISTBOX.list_h, ctl->LISTBOX.list );
402 if( NULL == ctl->LISTBOX.list ) {
403 goto cleanup;
404 }
405
406 retroflat_rect( gui->draw_bmp, ctl->base.bg_color,
407 gui->x + ctl->base.x, gui->y + ctl->base.y,
408 ctl->base.w, ctl->base.h, RETROFLAT_FLAGS_FILL );
409
410 /* Parse out variable-length strings. */
411 while( i < ctl->LISTBOX.list_sz ) {
412#ifdef RETROGXC_PRESENT
413 retrogxc_string_sz(
414 gui->draw_bmp, &(ctl->LISTBOX.list[i]), 0, gui->font_idx,
415 ctl->base.w, ctl->base.h, &w, &h, 0 );
416#else
417 retrofont_string_sz(
418 gui->draw_bmp, &(ctl->LISTBOX.list[i]), 0, gui->font_h,
419 ctl->base.w, ctl->base.h, &w, &h, 0 );
420#endif /* RETROGXC_PRESENT */
421 if( j == ctl->LISTBOX.sel_idx ) {
422 /* TODO: Configurable selection colors. */
423 retroflat_rect( gui->draw_bmp, RETROFLAT_COLOR_BLUE,
424 gui->x + ctl->base.x,
425 gui->y + ctl->base.y + (j * (h + RETROGUI_PADDING)),
426 ctl->base.w, h, RETROFLAT_FLAGS_FILL );
427
428 }
429#ifdef RETROGXC_PRESENT
430 retrogxc_string(
431 gui->draw_bmp, ctl->base.fg_color, &(ctl->LISTBOX.list[i]), 0,
432 gui->font_idx,
433 gui->x + ctl->base.x,
434 gui->y + ctl->base.y + (j * (h + RETROGUI_PADDING)),
435 0, 0, 0 );
436#else
437 retrofont_string(
438 gui->draw_bmp, ctl->base.fg_color, &(ctl->LISTBOX.list[i]), 0,
439 gui->font_h,
440 gui->x + ctl->base.x,
441 gui->y + ctl->base.y + (j * (h + RETROGUI_PADDING)),
442 0, 0, 0 );
443#endif /* RETROGXC_PRESENT */
444
445 /* Move to next variable-length string. */
446 i += maug_strlen( &(ctl->LISTBOX.list[i]) ) + 1;
447 assert( i <= ctl->LISTBOX.list_sz );
448 j++;
449 }
450
451cleanup:
452
453 if( NULL != ctl->LISTBOX.list ) {
454 maug_munlock( ctl->LISTBOX.list_h, ctl->LISTBOX.list );
455 }
456
457# endif
458
459}
460
461MERROR_RETVAL retrogui_select_listbox_item(
462 union RETROGUI_CTL* ctl, size_t item_idx
463) {
464 MERROR_RETVAL retval = MERROR_OK;
465
466# if defined( RETROGUI_NATIVE_WIN )
467
468 /* Select sel_idx. */
469 SendMessage( ctl->base.hwnd, LB_SETCURSEL, item_idx, 0 );
470
471# else
472
473 ctl->LISTBOX.sel_idx = item_idx;
474
475# endif
476
477 return retval;
478}
479
480MERROR_RETVAL retrogui_push_listbox_item(
481 struct RETROGUI* gui, retrogui_idc_t idc, const char* item, size_t item_sz
482) {
483 MERROR_RETVAL retval = MERROR_OK;
484 union RETROGUI_CTL* ctl = NULL;
485 MAUG_MHANDLE listbox_h_new = (MAUG_MHANDLE)NULL;
486
487 retrogui_lock( gui );
488
489 debug_printf( RETROGUI_TRACE_LVL,
490 "pushing item \"%s\" to listbox " SIZE_T_FMT "...", item, idc );
491
492 ctl = _retrogui_get_ctl_by_idc( gui, idc );
493 if( NULL == ctl ) {
495 "Adding item \"%s\" failed: Control missing!", item );
496 retval = MERROR_GUI;
497 goto cleanup;
498 }
499
500# if defined( RETROGUI_NATIVE_WIN )
501
502 SendMessage( ctl->LISTBOX.base.hwnd, LB_ADDSTRING, 0, (LPARAM)item );
503
504# else
505
506 if( 0 == ctl->LISTBOX.list_sz ) {
507 ctl->LISTBOX.list_h = maug_malloc( 255, sizeof( char ) );
508 maug_cleanup_if_null_alloc( MAUG_MHANDLE, ctl->LISTBOX.list_h );
509 ctl->LISTBOX.list_sz_max = 255;
510 }
511
512 if( NULL != ctl->LISTBOX.list ) {
513 maug_munlock( ctl->LISTBOX.list_h, ctl->LISTBOX.list );
514 }
515
516 while( ctl->LISTBOX.list_sz + item_sz + 1 >= ctl->LISTBOX.list_sz_max ) {
517 debug_printf( RETROGUI_TRACE_LVL,
518 "resizing listbox items to " SIZE_T_FMT "...",
519 ctl->LISTBOX.list_sz );
520 maug_mrealloc_test(
521 listbox_h_new, ctl->LISTBOX.list_h,
522 ctl->LISTBOX.list_sz_max * 2, sizeof( char ) );
523 ctl->LISTBOX.list_sz_max *= 2;
524 }
525
526 maug_mlock( ctl->LISTBOX.list_h, ctl->LISTBOX.list );
527 maug_cleanup_if_null_alloc( char*, ctl->LISTBOX.list );
528
529 maug_strncpy( &(ctl->LISTBOX.list[ctl->LISTBOX.list_sz]), item, item_sz );
530 ctl->LISTBOX.list[ctl->LISTBOX.list_sz + item_sz] = '\0';
531 ctl->LISTBOX.list_sz += item_sz + 1;
532
533#endif
534
535cleanup:
536
537 if( NULL != ctl->LISTBOX.list ) {
538 maug_munlock( ctl->LISTBOX.list_h, ctl->LISTBOX.list );
539 }
540
541 return retval;
542}
543
544static MERROR_RETVAL retrogui_push_LISTBOX( union RETROGUI_CTL* ctl ) {
545 MERROR_RETVAL retval = MERROR_OK;
546
547# if defined( RETROGUI_NATIVE_WIN )
548
549 ctl->base.hwnd = CreateWindow(
550 "LISTBOX", NULL, WS_CHILD | WS_VISIBLE | LBS_STANDARD,
551 gui->x + ctl->base.x, gui->y + ctl->base.y, ctl->base.w, ctl->base.h,
552 g_retroflat_state->window, (HMENU)(ctl->base.idc),
553 g_retroflat_instance, NULL );
554 debug_printf( RETROGUI_TRACE_LVL,
555 "listbox hwnd: %p", ctl->LISTBOX.base.hwnd );
556 if( (HWND)NULL == ctl->base.hwnd ) {
557 error_printf( "could not create listbox" );
558 retval = MERROR_GUI;
559 goto cleanup;
560 }
561
562cleanup:
563
564# else
565
566 /* TODO? */
567
568# endif
569
570 return retval;
571}
572
573static MERROR_RETVAL retrogui_sz_LISTBOX(
574 struct RETROGUI* gui, union RETROGUI_CTL* ctl,
575 size_t* p_w, size_t* p_h, size_t max_w, size_t max_h
576) {
577 MERROR_RETVAL retval = MERROR_GUI;
578 /* TODO */
579 return retval;
580}
581
582static MERROR_RETVAL retrogui_pos_LISTBOX(
583 struct RETROGUI* gui, union RETROGUI_CTL* ctl,
584 size_t x, size_t y, size_t w, size_t h
585) {
586 MERROR_RETVAL retval = MERROR_GUI;
587 /* TODO */
588 return retval;
589}
590
591static void retrogui_free_LISTBOX( union RETROGUI_CTL* ctl ) {
592 assert( NULL == ctl->LISTBOX.list );
593 maug_mfree( ctl->LISTBOX.list_h );
594}
595
596static MERROR_RETVAL retrogui_init_LISTBOX( union RETROGUI_CTL* ctl ) {
597 MERROR_RETVAL retval = MERROR_OK;
598
599 debug_printf( RETROGUI_TRACE_LVL,
600 "initializing listbox " SIZE_T_FMT "...", ctl->base.idc );
601
602 ctl->base.fg_color = RETROFLAT_COLOR_BLACK;
603 ctl->base.bg_color = RETROFLAT_COLOR_WHITE;
604
605 return retval;
606}
607
608/* === Control: BUTTON === */
609
610static retrogui_idc_t retrogui_click_BUTTON(
611 struct RETROGUI* gui,
612 union RETROGUI_CTL* ctl, RETROFLAT_IN_KEY* p_input,
613 struct RETROFLAT_INPUT* input_evt
614) {
615 retrogui_idc_t idc_out = RETROGUI_IDC_NONE;
616
617 if( 0 < ctl->BUTTON.push_frames ) {
618 goto cleanup;
619 }
620
621 /* Set the last button clicked. */
622 idc_out = ctl->base.idc;
623
624 /* Set the frames to show the pushed-in view. */
625 /* TODO: Use a constant, here. */
626 ctl->BUTTON.push_frames = 3;
627
628cleanup:
629
630 return idc_out;
631}
632
633static retrogui_idc_t retrogui_key_BUTTON(
634 union RETROGUI_CTL* ctl, RETROFLAT_IN_KEY* p_input,
635 struct RETROFLAT_INPUT* input_evt
636) {
637 retrogui_idc_t idc_out = RETROGUI_IDC_NONE;
638
639 /* Set the last button clicked. */
640 /* TODO: Only set out on ENTER/SPACE. */
641 /* idc_out = ctl->base.idc; */
642
643 return idc_out;
644}
645
646static void retrogui_redraw_BUTTON(
647 struct RETROGUI* gui, union RETROGUI_CTL* ctl
648) {
649 size_t w = 0,
650 h = 0,
651 text_offset = 0;
652
653 retroflat_rect( gui->draw_bmp, ctl->base.bg_color, ctl->base.x, ctl->base.y,
654 ctl->base.w, ctl->base.h, RETROFLAT_FLAGS_FILL );
655
656 retroflat_rect( gui->draw_bmp, RETROFLAT_COLOR_BLACK,
657 gui->x + ctl->base.x, gui->y + ctl->base.y,
658 ctl->base.w, ctl->base.h, 0 );
659
660 if( 0 < ctl->BUTTON.push_frames ) {
662 gui->draw_bmp, RETROFLAT_COLOR_DARKGRAY,
663 gui->x + ctl->base.x + 1, gui->y + ctl->base.y + 1,
664 gui->x + ctl->base.x + ctl->base.w - 2, gui->y + ctl->base.y + 1, 0 );
666 gui->draw_bmp, RETROFLAT_COLOR_DARKGRAY,
667 gui->x + ctl->base.x + 1, gui->y + ctl->base.y + 2,
668 gui->x + ctl->base.x + 1, gui->y + ctl->base.y + ctl->base.h - 3, 0 );
669
670 gui->flags |= RETROGUI_FLAGS_DIRTY; /* Mark dirty for push animation. */
671 ctl->BUTTON.push_frames--;
672 text_offset = 1;
673 } else {
674 /* Button is not pushed. */
676 gui->draw_bmp, RETROFLAT_COLOR_WHITE,
677 gui->x + ctl->base.x + 1, gui->y + ctl->base.y + 1,
678 gui->x + ctl->base.x + ctl->base.w - 2, gui->y + ctl->base.y + 1, 0 );
680 gui->draw_bmp, RETROFLAT_COLOR_WHITE,
681 gui->x + ctl->base.x + 1, gui->y + ctl->base.y + 2,
682 gui->x + ctl->base.x + 1, gui->y + ctl->base.y + ctl->base.h - 3, 0 );
683 }
684
685 maug_mlock( ctl->BUTTON.label_h, ctl->BUTTON.label );
686 if( NULL == ctl->BUTTON.label ) {
687 error_printf( "could not lock BUTTON label!" );
688 goto cleanup;
689 }
690
691 /* Grab the string size and use it to center the text in the control. */
692#ifdef RETROGXC_PRESENT
693 retrogxc_string_sz(
694#else
695 retrofont_string_sz(
696#endif /* RETROGXC_PRESENT */
697 gui->draw_bmp, ctl->BUTTON.label, 0,
698#ifdef RETROGXC_PRESENT
699 gui->font_idx,
700#else
701 gui->font_h,
702#endif /* RETROGXC_PRESENT */
703 /* TODO: Pad max client area. */
704 ctl->base.w, ctl->base.h, &w, &h, ctl->BUTTON.font_flags );
705
706#ifdef RETROGXC_PRESENT
707 retrogxc_string(
708#else
709 retrofont_string(
710#endif /* RETROGXC_PRESENT */
711 gui->draw_bmp, ctl->base.fg_color, ctl->BUTTON.label, 0,
712#ifdef RETROGXC_PRESENT
713 gui->font_idx,
714#else
715 gui->font_h,
716#endif /* RETROGXC_PRESENT */
717 gui->x + ctl->base.x + ((ctl->base.w >> 1) - (w >> 1)) + text_offset,
718 gui->y + ctl->base.y + ((ctl->base.h >> 1) - (h >> 1)) + text_offset,
719 /* TODO: Pad max client area. */
720 ctl->base.w, ctl->base.h, ctl->BUTTON.font_flags );
721
722 maug_munlock( ctl->BUTTON.label_h, ctl->BUTTON.label );
723
724cleanup:
725
726 return;
727}
728
729static MERROR_RETVAL retrogui_push_BUTTON( union RETROGUI_CTL* ctl ) {
730 MERROR_RETVAL retval = MERROR_OK;
731
732# if defined( RETROGUI_NATIVE_WIN )
733
734 ctl->base.hwnd = CreateWindow(
735 "BUTTON", ctl->BUTTON.label, WS_CHILD | WS_VISIBLE | BS_DEFPUSHBUTTON,
736 gui->x + ctl->base.x, gui->y + ctl->base.y, ctl->base.w, ctl->base.h,
737 g_retroflat_state->window, (HMENU)(ctl->base.idc),
738 g_retroflat_instance, NULL );
739 if( (HWND)NULL == ctl->base.hwnd ) {
741 "Could not create button " SIZE_T_FMT ": %s",
742 ctl->base.idc, ctl->BUTTON.label );
743 retval = MERROR_GUI;
744 goto cleanup;
745 }
746
747# else
748 size_t label_sz = 0;
749 char* label_tmp = NULL;
750
751 debug_printf( RETROGUI_TRACE_LVL, "pushing BUTTON control..." );
752
753 _retrogui_copy_str(
754 label, ctl->BUTTON.label, ctl->BUTTON, label_tmp, label_sz );
755 ctl->BUTTON.label = NULL;
756# endif
757
758cleanup:
759
760 return retval;
761}
762
763static MERROR_RETVAL retrogui_sz_BUTTON(
764 struct RETROGUI* gui, union RETROGUI_CTL* ctl,
765 size_t* p_w, size_t* p_h, size_t max_w, size_t max_h
766) {
767 MERROR_RETVAL retval = MERROR_OK;
768
769 assert( NULL != ctl );
770 assert( NULL == ctl->BUTTON.label );
771 assert( NULL != ctl->BUTTON.label_h );
772
773 maug_mlock( ctl->BUTTON.label_h, ctl->BUTTON.label );
774 maug_cleanup_if_null_lock( char*, ctl->BUTTON.label );
775
776 /* Get the size of the text-based GUI item. */
777#ifdef RETROGXC_PRESENT
778 retrogxc_string_sz(
779#else
780 retrofont_string_sz(
781#endif /* RETROGXC_PRESENT */
782 NULL,
783 ctl->BUTTON.label,
784 0,
785#ifdef RETROGXC_PRESENT
786 gui->font_idx,
787#else
788 gui->font_h,
789#endif /* RETROGXC_PRESENT */
790 max_w - 8,
791 max_h - 8,
792 p_w,
793 p_h, ctl->BUTTON.font_flags );
794
795 /* Add space for borders and stuff. */
796 *p_w += RETROGUI_BTN_LBL_PADDED_X;
797 *p_h += RETROGUI_BTN_LBL_PADDED_Y;
798
799cleanup:
800
801 maug_munlock( ctl->BUTTON.label_h, ctl->BUTTON.label );
802
803 return retval;
804}
805
806static MERROR_RETVAL retrogui_pos_BUTTON(
807 struct RETROGUI* gui, union RETROGUI_CTL* ctl,
808 size_t x, size_t y, size_t w, size_t h
809) {
810 MERROR_RETVAL retval = MERROR_OK;
811
812# if defined( RETROGUI_NATIVE_WIN )
813 /* TODO */
814# else
815 assert( NULL != ctl );
816
817 ctl->base.x = x;
818 ctl->base.y = y;
819 if( 0 < w ) {
820 ctl->base.w = w;
821 }
822 if( 0 < h ) {
823 ctl->base.h = h;
824 }
825# endif /* RETROGUI_NATIVE_WIN */
826
827 return retval;
828}
829
830static void retrogui_free_BUTTON( union RETROGUI_CTL* ctl ) {
831 if( NULL != ctl->BUTTON.label_h ) {
832 maug_mfree( ctl->BUTTON.label_h );
833 }
834}
835
836static MERROR_RETVAL retrogui_init_BUTTON( union RETROGUI_CTL* ctl ) {
837 MERROR_RETVAL retval = MERROR_OK;
838
839 debug_printf( RETROGUI_TRACE_LVL,
840 "initializing button " SIZE_T_FMT "...", ctl->base.idc );
841
842 ctl->base.fg_color = RETROFLAT_COLOR_BLACK;
843 ctl->base.bg_color = RETROFLAT_COLOR_GRAY;
844
845 return retval;
846}
847
848#ifndef RETROGUI_NO_TEXTBOX
849
850/* === Control: TEXTBOX === */
851
852static retrogui_idc_t retrogui_click_TEXTBOX(
853 struct RETROGUI* gui,
854 union RETROGUI_CTL* ctl, RETROFLAT_IN_KEY* p_input,
855 struct RETROFLAT_INPUT* input_evt
856) {
857 retrogui_idc_t idc_out = RETROGUI_IDC_NONE;
858
859 return idc_out;
860}
861
862static retrogui_idc_t retrogui_key_TEXTBOX(
863 union RETROGUI_CTL* ctl, RETROFLAT_IN_KEY* p_input,
864 struct RETROFLAT_INPUT* input_evt
865) {
866 retrogui_idc_t idc_out = RETROGUI_IDC_NONE;
867 char c = '\0';
868
869# if defined( RETROGUI_NATIVE_WIN )
870 /* Do nothing. */
871# else
872
873 c = retroflat_vk_to_ascii( *p_input, input_evt->key_flags );
874
875 /* Ignore non-printable characters. */
876 if(
877 0 == c &&
878 RETROFLAT_KEY_RIGHT != *p_input &&
879 RETROFLAT_KEY_LEFT != *p_input
880 ) {
881 goto cleanup;
882 }
883
884 /* Lock text field. */
885 assert( NULL == ctl->TEXTBOX.text );
886 assert( (MAUG_MHANDLE)NULL != ctl->TEXTBOX.text_h );
887 maug_mlock( ctl->TEXTBOX.text_h, ctl->TEXTBOX.text );
888 if( NULL == ctl->TEXTBOX.text ) {
889 error_printf( "could not lock TEXTBOX text handle!" );
890 goto cleanup;
891 }
892
893 switch( *p_input ) {
894 case RETROFLAT_KEY_BKSP:
896 ctl->TEXTBOX.text, ctl->TEXTBOX.text_cur, ctl->TEXTBOX.text_sz )
897 break;
898
899 case RETROFLAT_KEY_ENTER:
900 idc_out = ctl->base.idc;
901 break;
902
903 case RETROFLAT_KEY_LEFT:
904 if( 0 < ctl->TEXTBOX.text_cur ) {
905 ctl->TEXTBOX.text_cur--;
906 }
907 break;
908
909 case RETROFLAT_KEY_RIGHT:
910 if( ctl->TEXTBOX.text_sz > ctl->TEXTBOX.text_cur ) {
911 ctl->TEXTBOX.text_cur++;
912 }
913 break;
914
915 default:
916 assert( ctl->TEXTBOX.text_sz < ctl->TEXTBOX.text_sz_max );
918 ctl->TEXTBOX.text,
919 ctl->TEXTBOX.text_cur,
920 ctl->TEXTBOX.text_sz,
921 ctl->TEXTBOX.text_sz_max );
922 break;
923 }
924
925 /* TODO: Remove input from queue? */
926
927cleanup:
928
929 if( NULL != ctl->TEXTBOX.text ) {
930 maug_munlock( ctl->TEXTBOX.text_h, ctl->TEXTBOX.text );
931 }
932
933# endif
934
935 return idc_out;
936}
937
938static void retrogui_redraw_TEXTBOX(
939 struct RETROGUI* gui, union RETROGUI_CTL* ctl
940) {
941
942# if defined( RETROGUI_NATIVE_WIN )
943 /* Do nothing. */
944# else
945
946 retroflat_rect( gui->draw_bmp, ctl->base.bg_color,
947 gui->x + ctl->base.x, gui->y + ctl->base.y,
948 ctl->base.w, ctl->base.h, RETROFLAT_FLAGS_FILL );
949
950 /* Draw chiselled inset border. */
951
952 retroflat_rect( gui->draw_bmp, RETROFLAT_COLOR_BLACK,
953 gui->x + ctl->base.x,
954 gui->y + ctl->base.y, ctl->base.w, 2,
956
957 retroflat_rect( gui->draw_bmp, RETROFLAT_COLOR_BLACK,
958 gui->x + ctl->base.x,
959 gui->y + ctl->base.y, 2, ctl->base.h,
961
962 retroflat_rect( gui->draw_bmp, RETROFLAT_COLOR_DARKGRAY,
963 gui->x + ctl->base.x,
964 gui->y + ctl->base.y + ctl->base.h - 1,
965 ctl->base.w, 2,
967
968 retroflat_rect( gui->draw_bmp, RETROFLAT_COLOR_DARKGRAY,
969 gui->x + ctl->base.x + ctl->base.w - 1,
970 gui->y + ctl->base.y, 2, ctl->base.h,
972
973 /* Draw text. */
974
975 assert( NULL == ctl->TEXTBOX.text );
976 maug_mlock( ctl->TEXTBOX.text_h, ctl->TEXTBOX.text );
977 if( NULL == ctl->TEXTBOX.text ) {
978 goto cleanup;
979 }
980
981#ifdef RETROGXC_PRESENT
982 retrogxc_string(
983 gui->draw_bmp, ctl->base.fg_color, ctl->TEXTBOX.text, 0, gui->font_idx,
984 gui->x + ctl->base.x + RETROGUI_PADDING,
985 gui->y + ctl->base.y + RETROGUI_PADDING, ctl->base.w, ctl->base.h, 0 );
986#else
987 retrofont_string(
988 gui->draw_bmp, ctl->base.fg_color, ctl->TEXTBOX.text, 0, gui->font_h,
989 gui->x + ctl->base.x + RETROGUI_PADDING,
990 gui->y + ctl->base.y + RETROGUI_PADDING, ctl->base.w, ctl->base.h, 0 );
991#endif /* RETROGXC_PRESENT */
992
993cleanup:
994
995 if( NULL != ctl->TEXTBOX.text ) {
996 maug_munlock( ctl->TEXTBOX.text_h, ctl->TEXTBOX.text );
997 }
998
999 /* TODO: Get cursor color from GUI. */
1000 retroflat_rect( gui->draw_bmp, RETROFLAT_COLOR_BLUE,
1001 gui->x + ctl->base.x + RETROGUI_PADDING + (8 * ctl->TEXTBOX.text_cur),
1002 gui->y + ctl->base.y + RETROGUI_PADDING,
1003 8, 8,
1004 /* Draw blinking cursor. */
1005 /* TODO: Use a global timer to mark this field dirty. */
1006 gui->focus == ctl->base.idc &&
1007 0 < ctl->TEXTBOX.blink_frames ? RETROFLAT_FLAGS_FILL : 0 );
1008
1009 if( (-1 * RETROGUI_CTL_TEXT_BLINK_FRAMES) > --(ctl->TEXTBOX.blink_frames) ) {
1010 ctl->TEXTBOX.blink_frames = RETROGUI_CTL_TEXT_BLINK_FRAMES;
1011 }
1012
1013 gui->flags |= RETROGUI_FLAGS_DIRTY; /* Mark dirty for blink animation. */
1014
1015# endif
1016
1017 return;
1018}
1019
1020static MERROR_RETVAL retrogui_push_TEXTBOX( union RETROGUI_CTL* ctl ) {
1021 MERROR_RETVAL retval = MERROR_OK;
1022
1023# if defined( RETROGUI_NATIVE_WIN )
1024
1025 ctl->base.hwnd = CreateWindow(
1026 "EDIT", 0, WS_CHILD | WS_VISIBLE | WS_BORDER,
1027 gui->x + ctl->base.x, gui->y + ctl->base.y, ctl->base.w, ctl->base.h,
1028 g_retroflat_state->window, (HMENU)(ctl->base.idc),
1029 g_retroflat_instance, NULL );
1030 if( (HWND)NULL == ctl->base.hwnd ) {
1032 "Could not create textbox: " SIZE_T_FMT, ctl->base.idc );
1033 retval = MERROR_GUI;
1034 goto cleanup;
1035 }
1036
1037# else
1038
1039 debug_printf( RETROGUI_TRACE_LVL,
1040 "clearing textbox " SIZE_T_FMT " buffer...", ctl->base.idc );
1041 assert( NULL == ctl->TEXTBOX.text_h );
1042 ctl->TEXTBOX.text_h = maug_malloc( RETROGUI_CTL_TEXT_SZ_MAX + 1, 1 );
1043 maug_cleanup_if_null_alloc( MAUG_MHANDLE, ctl->TEXTBOX.text_h );
1044 ctl->TEXTBOX.text_sz_max = RETROGUI_CTL_TEXT_SZ_MAX;
1045
1046 maug_mlock( ctl->TEXTBOX.text_h, ctl->TEXTBOX.text );
1047 maug_cleanup_if_null_alloc( char*, ctl->TEXTBOX.text );
1048 debug_printf( RETROGUI_TRACE_LVL,
1049 "clearing textbox " SIZE_T_FMT " buffer...", ctl->base.idc );
1050 maug_mzero( ctl->TEXTBOX.text, RETROGUI_CTL_TEXT_SZ_MAX + 1 );
1051 maug_munlock( ctl->TEXTBOX.text_h, ctl->TEXTBOX.text );
1052
1053# endif
1054
1055cleanup:
1056
1057 return retval;
1058}
1059
1060static MERROR_RETVAL retrogui_sz_TEXTBOX(
1061 struct RETROGUI* gui, union RETROGUI_CTL* ctl,
1062 size_t* p_w, size_t* p_h, size_t max_w, size_t max_h
1063) {
1064 MERROR_RETVAL retval = MERROR_GUI;
1065 /* TODO */
1066 return retval;
1067}
1068
1069static MERROR_RETVAL retrogui_pos_TEXTBOX(
1070 struct RETROGUI* gui, union RETROGUI_CTL* ctl,
1071 size_t x, size_t y, size_t w, size_t h
1072) {
1073 MERROR_RETVAL retval = MERROR_GUI;
1074 /* TODO */
1075 return retval;
1076}
1077
1078static void retrogui_free_TEXTBOX( union RETROGUI_CTL* ctl ) {
1079 if( NULL != ctl->TEXTBOX.text_h ) {
1080 maug_mfree( ctl->TEXTBOX.text_h );
1081 }
1082}
1083
1084static MERROR_RETVAL retrogui_init_TEXTBOX( union RETROGUI_CTL* ctl ) {
1085 MERROR_RETVAL retval = MERROR_OK;
1086
1087 debug_printf( RETROGUI_TRACE_LVL,
1088 "initializing textbox " SIZE_T_FMT "...", ctl->base.idc );
1089
1090 ctl->base.fg_color = RETROFLAT_COLOR_BLACK;
1091 ctl->base.bg_color = RETROFLAT_COLOR_WHITE;
1092
1093 return retval;
1094}
1095
1096#endif /* RETROGUI_NO_TEXTBOX */
1097
1098/* === Control: LABEL === */
1099
1100static retrogui_idc_t retrogui_click_LABEL(
1101 struct RETROGUI* gui,
1102 union RETROGUI_CTL* ctl, RETROFLAT_IN_KEY* p_input,
1103 struct RETROFLAT_INPUT* input_evt
1104) {
1105 return RETROGUI_IDC_NONE;
1106}
1107
1108static retrogui_idc_t retrogui_key_LABEL(
1109 union RETROGUI_CTL* ctl, RETROFLAT_IN_KEY* p_input,
1110 struct RETROFLAT_INPUT* input_evt
1111) {
1112 return RETROGUI_IDC_NONE;
1113}
1114
1115static void retrogui_redraw_LABEL(
1116 struct RETROGUI* gui, union RETROGUI_CTL* ctl
1117) {
1118
1119# if defined( RETROGUI_NATIVE_WIN )
1120 /* Do nothing. */
1121# else
1122
1123 /* Draw text. */
1124
1125#ifdef RETROGXC_PRESENT
1126 assert( 0 <= gui->font_idx );
1127#else
1128 assert( (MAUG_MHANDLE)NULL != gui->font_h );
1129#endif /* RETROGXC_PRESENT */
1130
1131 assert( NULL == ctl->LABEL.label );
1132 maug_mlock( ctl->LABEL.label_h, ctl->LABEL.label );
1133 if( NULL == ctl->LABEL.label ) {
1134 error_printf( "could not lock LABEL text!" );
1135 goto cleanup;
1136 }
1137
1138#ifdef RETROGXC_PRESENT
1139 retrogxc_string(
1140#else
1141 retrofont_string(
1142#endif /* RETROGXC_PRESENT */
1143 gui->draw_bmp, ctl->base.fg_color, ctl->LABEL.label,
1144 ctl->LABEL.label_sz,
1145#ifdef RETROGXC_PRESENT
1146 gui->font_idx,
1147#else
1148 gui->font_h,
1149#endif /* RETROGXC_PRESENT */
1150 gui->x + ctl->base.x + RETROGUI_PADDING,
1151 gui->y + ctl->base.y + RETROGUI_PADDING, ctl->base.w, ctl->base.h,
1152 ctl->LABEL.font_flags );
1153
1154cleanup:
1155
1156 if( NULL != ctl->LABEL.label ) {
1157 maug_munlock( ctl->LABEL.label_h, ctl->LABEL.label );
1158 }
1159
1160# endif
1161
1162 return;
1163}
1164
1165static MERROR_RETVAL retrogui_push_LABEL( union RETROGUI_CTL* ctl ) {
1166 MERROR_RETVAL retval = MERROR_OK;
1167
1168# if defined( RETROGUI_NATIVE_WIN )
1169
1170 /* TODO */
1171
1172# else
1173 size_t label_sz = 0;
1174 char* label_tmp = NULL;
1175
1176 debug_printf( RETROGUI_TRACE_LVL, "pushing LABEL control..." );
1177
1178 _retrogui_copy_str(
1179 label, ctl->LABEL.label, ctl->LABEL, label_tmp, label_sz );
1180 ctl->LABEL.label = NULL;
1181# endif
1182
1183cleanup:
1184
1185 return retval;
1186}
1187
1188static MERROR_RETVAL retrogui_sz_LABEL(
1189 struct RETROGUI* gui, union RETROGUI_CTL* ctl,
1190 size_t* p_w, size_t* p_h, size_t max_w, size_t max_h
1191) {
1192 MERROR_RETVAL retval = MERROR_GUI;
1193 /* TODO */
1194 return retval;
1195}
1196
1197static MERROR_RETVAL retrogui_pos_LABEL(
1198 struct RETROGUI* gui, union RETROGUI_CTL* ctl,
1199 size_t x, size_t y, size_t w, size_t h
1200) {
1201 MERROR_RETVAL retval = MERROR_GUI;
1202 /* TODO */
1203 return retval;
1204}
1205
1206static void retrogui_free_LABEL( union RETROGUI_CTL* ctl ) {
1207 if( NULL != ctl->LABEL.label_h ) {
1208 maug_mfree( ctl->LABEL.label_h );
1209 }
1210}
1211
1212static MERROR_RETVAL retrogui_init_LABEL( union RETROGUI_CTL* ctl ) {
1213 MERROR_RETVAL retval = MERROR_OK;
1214
1215 debug_printf( RETROGUI_TRACE_LVL,
1216 "initializing label " SIZE_T_FMT "...", ctl->base.idc );
1217
1218 ctl->base.fg_color = RETROFLAT_COLOR_BLACK;
1219 ctl->base.bg_color = RETROFLAT_COLOR_WHITE;
1220
1221 return retval;
1222}
1223
1224/* === Static Internal Functions === */
1225
1226static union RETROGUI_CTL* _retrogui_get_ctl_by_idc(
1227 struct RETROGUI* gui, size_t idc
1228) {
1229 size_t i = 0;
1230 union RETROGUI_CTL* ctl = NULL;
1231
1232 assert( retrogui_is_locked( gui ) );
1233
1234 for( i = 0 ; mdata_vector_ct( &(gui->ctls) ) > i ; i++ ) {
1235 ctl = mdata_vector_get( &(gui->ctls), i, union RETROGUI_CTL );
1236 if( idc == ctl->base.idc ) {
1237 break;
1238 }
1239 ctl = NULL;
1240 }
1241
1242 if( NULL == ctl ) {
1244 "Could not find GUI item: " SIZE_T_FMT, idc );
1245 }
1246
1247 return ctl;
1248}
1249
1250static MERROR_RETVAL _retrogui_sz_ctl(
1251 struct RETROGUI* gui, retrogui_idc_t idc,
1252 size_t* p_w, size_t* p_h, size_t max_w, size_t max_h
1253) {
1254 MERROR_RETVAL retval = MERROR_OK;
1255 union RETROGUI_CTL* ctl = NULL;
1256
1257 assert( retrogui_is_locked( gui ) );
1258
1259 debug_printf( RETROGUI_TRACE_LVL,
1260 "sizing control " SIZE_T_FMT " to: " SIZE_T_FMT "x" SIZE_T_FMT,
1261 idc, max_w, max_h );
1262
1263 ctl = _retrogui_get_ctl_by_idc( gui, idc );
1264 if( NULL == ctl ) {
1265 error_printf( "could not find control to size!" );
1266 retval = MERROR_GUI;
1267 goto cleanup;
1268 }
1269
1270 #define RETROGUI_CTL_TABLE_SZ( idx, c_name, c_fields ) \
1271 } else if( RETROGUI_CTL_TYPE_ ## c_name == ctl->base.type ) { \
1272 /* Mark dirty first so redraw can unmark it for animation! */ \
1273 retval = retrogui_sz_ ## c_name( gui, ctl, p_w, p_h, max_w, max_h ); \
1274 maug_cleanup_if_not_ok();
1275
1276 if( 0 ) {
1277 RETROGUI_CTL_TABLE( RETROGUI_CTL_TABLE_SZ )
1278 }
1279
1280 debug_printf( RETROGUI_TRACE_LVL,
1281 "sized control " SIZE_T_FMT " at " SIZE_T_FMT "x" SIZE_T_FMT "...",
1282 ctl->base.idc, ctl->base.w, ctl->base.h );
1283
1284cleanup:
1285
1286 return retval;
1287}
1288
1289/* === Generic Functions === */
1290
1292 struct RETROGUI* gui, RETROFLAT_IN_KEY* p_input,
1293 struct RETROFLAT_INPUT* input_evt
1294) {
1295 size_t i = 0,
1296 mouse_x = 0,
1297 mouse_y = 0;
1298 retrogui_idc_t idc_out = RETROGUI_IDC_NONE;
1299 union RETROGUI_CTL* ctl = NULL;
1300 MERROR_RETVAL retval = MERROR_OK;
1301
1302 assert( !retrogui_is_locked( gui ) );
1303 mdata_vector_lock( &(gui->ctls) );
1304
1305# if defined( RETROGUI_NATIVE_WIN )
1306
1307 if( 0 == g_retroflat_state->last_idc ) {
1308 /* No WM_COMMAND to process. */
1309 goto cleanup;
1310 }
1311
1312 ctl = retrogui_get_ctl_by_idc( gui, g_retroflat_state->last_idc );
1313 g_retroflat_state->last_idc = 0;
1314 if( NULL == ctl ) {
1315 debug_printf( RETROGUI_TRACE_LVL,
1316 "invalid IDC: " SIZE_T_FMT, gui->focus );
1317 }
1318
1319# ifndef RETROGUI_NO_TEXTBOX
1320 if( RETROGUI_CTL_TYPE_TEXTBOX == ctl->base.type ) {
1321 if( SendMessage( ctl->base.hwnd, EM_GETMODIFY, 0, 0 ) ) {
1322 SendMessage( ctl->base.hwnd, EM_SETMODIFY, 0, 0 );
1323 debug_printf( RETROGUI_TRACE_LVL, "mod: %d",
1324 SendMessage( ctl->base.hwnd, EM_GETMODIFY, 0, 0 ) );
1325 }
1326 }
1327# endif /* !RETROGUI_NO_TEXTBOX */
1328
1329# else
1330
1331 /* Use our cross-platform controls. */
1332
1333 #define RETROGUI_CTL_TABLE_CLICK( idx, c_name, c_fields ) \
1334 } else if( RETROGUI_CTL_TYPE_ ## c_name == ctl->base.type ) { \
1335 gui->flags |= RETROGUI_FLAGS_DIRTY; \
1336 idc_out = retrogui_click_ ## c_name( gui, ctl, p_input, input_evt );
1337
1338 #define RETROGUI_CTL_TABLE_KEY( idx, c_name, c_fields ) \
1339 } else if( RETROGUI_CTL_TYPE_ ## c_name == ctl->base.type ) { \
1340 gui->flags |= RETROGUI_FLAGS_DIRTY; \
1341 idc_out = retrogui_key_ ## c_name( ctl, p_input, input_evt );
1342
1343 if( 0 == *p_input ) {
1344 goto reset_debounce;
1345
1346# ifndef RETROGUI_NO_MOUSE
1347 } else if(
1348 RETROFLAT_MOUSE_B_LEFT == *p_input ||
1349 RETROFLAT_MOUSE_B_RIGHT == *p_input
1350 ) {
1351 /* Remove all focus before testing if a new control has focus. */
1352 gui->focus = RETROGUI_IDC_NONE;
1353
1354 mouse_x = input_evt->mouse_x - gui->x;
1355 mouse_y = input_evt->mouse_y - gui->y;
1356
1357 for( i = 0 ; mdata_vector_ct( &(gui->ctls) ) > i ; i++ ) {
1358 ctl = mdata_vector_get( &(gui->ctls), i, union RETROGUI_CTL );
1359 if(
1360 mouse_x < ctl->base.x ||
1361 mouse_y < ctl->base.y ||
1362 mouse_x > ctl->base.x + ctl->base.w ||
1363 mouse_y > ctl->base.y + ctl->base.h
1364 ) {
1365 continue;
1366 }
1367
1368 if( gui->idc_prev == ctl->base.idc ) {
1369 /* No repeated clicks! */
1370 /* TODO: Allow exceptions for e.g. scrollbars. */
1371 idc_out = RETROGUI_IDC_NONE;
1372 goto cleanup;
1373 }
1374
1375 gui->idc_prev = ctl->base.idc;
1376
1377 gui->focus = ctl->base.idc;
1378
1379 if( 0 ) {
1380 RETROGUI_CTL_TABLE( RETROGUI_CTL_TABLE_CLICK )
1381 }
1382 break;
1383 }
1384# endif /* !RETROGUI_NO_MOUSE */
1385
1386 } else {
1387
1388 if( RETROGUI_IDC_NONE == gui->focus ) {
1389 goto reset_debounce;
1390 }
1391
1392 /* Send keystrokes to control that has focus. */
1393
1394 ctl = _retrogui_get_ctl_by_idc( gui, gui->focus );
1395 if( NULL == ctl ) {
1396 debug_printf( RETROGUI_TRACE_LVL,
1397 "invalid IDC: " SIZE_T_FMT, gui->focus );
1398 goto reset_debounce;
1399 }
1400
1401 if( 0 ) {
1402 RETROGUI_CTL_TABLE( RETROGUI_CTL_TABLE_KEY )
1403 }
1404 }
1405
1406reset_debounce:
1407
1408 /* Reset repeat detector. */
1409 gui->idc_prev = RETROGUI_IDC_NONE;
1410
1411# endif
1412
1413cleanup:
1414
1415 if( MERROR_OK != retval ) {
1416 idc_out = RETROGUI_IDC_NONE;
1417 }
1418
1419 mdata_vector_unlock( &(gui->ctls) );
1420
1421 return idc_out;
1422}
1423
1424MERROR_RETVAL retrogui_redraw_ctls( struct RETROGUI* gui ) {
1425 size_t i = 0;
1426 union RETROGUI_CTL* ctl = NULL;
1427 MERROR_RETVAL retval = MERROR_OK;
1428
1429 if( RETROGUI_FLAGS_DIRTY != (RETROGUI_FLAGS_DIRTY & gui->flags) ) {
1430 /* Shortcut! */
1431 return MERROR_OK;
1432 }
1433
1434 assert( !retrogui_is_locked( gui ) );
1435 mdata_vector_lock( &(gui->ctls) );
1436
1437 if(
1438 RETROFLAT_COLOR_BLACK != gui->bg_color &&
1439 0 < gui->w && 0 < gui->h
1440 ) {
1441 retroflat_rect( gui->draw_bmp,
1442 gui->bg_color, gui->x, gui->y, gui->w, gui->h, RETROFLAT_FLAGS_FILL );
1443 }
1444
1445 #define RETROGUI_CTL_TABLE_REDRAW( idx, c_name, c_fields ) \
1446 } else if( RETROGUI_CTL_TYPE_ ## c_name == ctl->base.type ) { \
1447 /* Mark dirty first so redraw can unmark it for animation! */ \
1448 gui->flags &= ~RETROGUI_FLAGS_DIRTY; \
1449 retrogui_redraw_ ## c_name( gui, ctl );
1450
1451 for( i = 0 ; mdata_vector_ct( &(gui->ctls) ) > i ; i++ ) {
1452 ctl = mdata_vector_get( &(gui->ctls), i, union RETROGUI_CTL );
1453 if( 0 ) {
1454 RETROGUI_CTL_TABLE( RETROGUI_CTL_TABLE_REDRAW )
1455 }
1456 }
1457
1458cleanup:
1459
1460 mdata_vector_unlock( &(gui->ctls) );
1461
1462 return retval;
1463}
1464
1465MERROR_RETVAL retrogui_pos_ctl(
1466 struct RETROGUI* gui, retrogui_idc_t idc,
1467 size_t x, size_t y, size_t w, size_t h
1468) {
1469 MERROR_RETVAL retval = MERROR_OK;
1470 union RETROGUI_CTL* ctl = NULL;
1471
1472 assert( !retrogui_is_locked( gui ) );
1473 mdata_vector_lock( &(gui->ctls) );
1474
1475 debug_printf( RETROGUI_TRACE_LVL,
1476 "moving control " SIZE_T_FMT " to: " SIZE_T_FMT ", " SIZE_T_FMT,
1477 idc, x, y );
1478
1479 ctl = _retrogui_get_ctl_by_idc( gui, idc );
1480 if( NULL == ctl ) {
1481 error_printf( "could not position control!" );
1482 retval = MERROR_GUI;
1483 goto cleanup;
1484 }
1485
1486 #define RETROGUI_CTL_TABLE_POS( idx, c_name, c_fields ) \
1487 } else if( RETROGUI_CTL_TYPE_ ## c_name == ctl->base.type ) { \
1488 /* Mark dirty first so redraw can unmark it for animation! */ \
1489 retval = retrogui_pos_ ## c_name( gui, ctl, x, y, w, h ); \
1490 maug_cleanup_if_not_ok();
1491
1492 if( 0 ) {
1493 RETROGUI_CTL_TABLE( RETROGUI_CTL_TABLE_POS )
1494 }
1495
1496 debug_printf( RETROGUI_TRACE_LVL,
1497 "moved control " SIZE_T_FMT " to " SIZE_T_FMT ", " SIZE_T_FMT
1498 " and sized to " SIZE_T_FMT "x" SIZE_T_FMT "...",
1499 ctl->base.idc, gui->x + ctl->base.x, gui->y + ctl->base.y,
1500 ctl->base.w, ctl->base.h );
1501
1502 /* New position! Redraw! */
1503 gui->flags |= RETROGUI_FLAGS_DIRTY;
1504
1505cleanup:
1506
1507 mdata_vector_unlock( &(gui->ctls) );
1508
1509 return retval;
1510
1511}
1512
1513MERROR_RETVAL retrogui_push_ctl(
1514 struct RETROGUI* gui, union RETROGUI_CTL* ctl
1515) {
1516 MERROR_RETVAL retval = MERROR_OK;
1517
1518 assert( 0 < ctl->base.idc );
1519
1520#ifdef RETROGXC_PRESENT
1521 if( 0 > gui->font_idx ) {
1522#else
1523 if( (MAUG_MHANDLE)NULL == gui->font_h ) {
1524#endif /* RETROGXC_PRESENT */
1526 RETROFLAT_MSG_FLAG_ERROR, "Error", "GUI font not loaded!" );
1527 retval = MERROR_GUI;
1528 goto cleanup;
1529 }
1530
1531 assert( !retrogui_is_locked( gui ) );
1532 /*
1533 if( retrogui_is_locked( gui ) ) {
1534 error_printf( "GUI is locked!" );
1535 goto cleanup;
1536 }
1537 */
1538
1539 /* TODO: Hunt for control IDC and fail if duplicate found! */
1540
1541 debug_printf( RETROGUI_TRACE_LVL,
1542 "gui->ctls_ct: " SIZE_T_FMT, mdata_vector_ct( &(gui->ctls) ) );
1543
1544 if( RETROFLAT_COLOR_NULL == ctl->base.bg_color ) {
1546 "invalid background color specified for control " SIZE_T_FMT "!",
1547 ctl->base.idc );
1548 retval = MERROR_GUI;
1549 goto cleanup;
1550
1551 }
1552
1553 if( RETROFLAT_COLOR_NULL == ctl->base.fg_color ) {
1555 "invalid foreground color specified for control " SIZE_T_FMT "!",
1556 ctl->base.idc );
1557 retval = MERROR_GUI;
1558 goto cleanup;
1559 }
1560
1561 /* Perform the actual push. */
1562 debug_printf( RETROGUI_TRACE_LVL,
1563 "pushing %s " SIZE_T_FMT " to slot " SIZE_T_FMT "...",
1564 gc_retrogui_ctl_names[ctl->base.type], ctl->base.idc,
1565 mdata_vector_ct( &(gui->ctls) ) );
1566
1567 mdata_vector_append( &(gui->ctls), ctl, sizeof( union RETROGUI_CTL ) );
1568
1569 gui->flags |= RETROGUI_FLAGS_DIRTY;
1570
1571 /* Now that append is done, lock the vector and grab a pointer to our
1572 * newly-pushed control to run some fixups on.
1573 */
1574 mdata_vector_lock( &(gui->ctls) );
1575
1576 /* TODO: More elegant way to grab index. */
1577 ctl = mdata_vector_get_last( &(gui->ctls),
1578 union RETROGUI_CTL );
1579 assert( NULL != ctl );
1580
1581 #define RETROGUI_CTL_TABLE_PUSH( idx, c_name, c_fields ) \
1582 } else if( RETROGUI_CTL_TYPE_ ## c_name == ctl->base.type ) { \
1583 debug_printf( RETROGUI_TRACE_LVL, \
1584 "running " #c_name " push hook..." ); \
1585 retval = retrogui_push_ ## c_name( ctl ); \
1586 maug_cleanup_if_not_ok();
1587
1588 if( 0 ) {
1589 RETROGUI_CTL_TABLE( RETROGUI_CTL_TABLE_PUSH )
1590 }
1591
1592 /* Try to auto-size the control now that the push-hook as set its text
1593 * or whatever else might be needed to determine an automatic size.
1594 */
1595 if( 0 == ctl->base.w || 0 == ctl->base.h ) {
1596 debug_printf( RETROGUI_TRACE_LVL,
1597 "determining size for new %s control " SIZE_T_FMT "...",
1598 gc_retrogui_ctl_names[ctl->base.type], ctl->base.idc );
1599 retval = _retrogui_sz_ctl(
1600 gui, ctl->base.idc, &(ctl->base.w), &(ctl->base.h), 0, 0 );
1601 maug_cleanup_if_not_ok();
1602 }
1603
1604cleanup:
1605
1606 mdata_vector_unlock( &(gui->ctls) );
1607
1608 return retval;
1609}
1610
1611MERROR_RETVAL retrogui_remove_ctl( struct RETROGUI* gui, retrogui_idc_t idc ) {
1612 size_t i = 0;
1613 union RETROGUI_CTL* ctl = NULL;
1614 MERROR_RETVAL retval = MERROR_OK;
1615
1616 if( retrogui_is_locked( gui ) ) {
1617 error_printf( "GUI is locked!" );
1618 goto cleanup;
1619 }
1620
1621 assert( !retrogui_is_locked( gui ) );
1622 mdata_vector_lock( &(gui->ctls) );
1623
1624 #define RETROGUI_CTL_TABLE_FREE_CTL( idx, c_name, c_fields ) \
1625 } else if( RETROGUI_CTL_TYPE_ ## c_name == ctl->base.type ) { \
1626 retrogui_free_ ## c_name( ctl );
1627
1628 for( i = 0 ; mdata_vector_ct( &(gui->ctls) ) > i ; i++ ) {
1629 ctl = mdata_vector_get( &(gui->ctls), i, union RETROGUI_CTL );
1630 if( idc != ctl->base.idc ) {
1631 continue;
1632 }
1633
1634 /* Free the control data. */
1635 if( 0 ) {
1636 RETROGUI_CTL_TABLE( RETROGUI_CTL_TABLE_FREE_CTL )
1637 }
1638
1639 /* Remove the control. */
1640 mdata_vector_unlock( &(gui->ctls) );
1641 mdata_vector_remove( &(gui->ctls), i );
1642 mdata_vector_lock( &(gui->ctls) );
1643 break;
1644 }
1645
1646 mdata_vector_unlock( &(gui->ctls) );
1647
1648cleanup:
1649
1650 return retval;
1651}
1652
1653#ifndef RETROGUI_NO_TEXTBOX
1654
1655MERROR_RETVAL retrogui_get_ctl_text(
1656 struct RETROGUI* gui, retrogui_idc_t idc, char* buffer, size_t buffer_sz
1657) {
1658 MERROR_RETVAL retval = MERROR_OK;
1659 union RETROGUI_CTL* ctl = NULL;
1660
1661 assert( !retrogui_is_locked( gui ) );
1662 mdata_vector_lock( &(gui->ctls) );
1663
1664 ctl = _retrogui_get_ctl_by_idc( gui, idc );
1665 if( NULL == ctl ) {
1666 goto cleanup;
1667 }
1668
1669 if( RETROGUI_CTL_TYPE_TEXTBOX == ctl->base.type ) {
1670# if defined( RETROGUI_NATIVE_WIN )
1671 /* TODO */
1672#else
1673 maug_mlock( ctl->TEXTBOX.text_h, ctl->TEXTBOX.text );
1674 maug_cleanup_if_null_lock( char*, ctl->TEXTBOX.text );
1675
1676 maug_strncpy( buffer, ctl->TEXTBOX.text, buffer_sz );
1677# endif
1678 } else if( RETROGUI_CTL_TYPE_LABEL == ctl->base.type ) {
1679# if defined( RETROGUI_NATIVE_WIN )
1680 /* TODO */
1681#else
1682 maug_mlock( ctl->LABEL.label_h, ctl->LABEL.label );
1683 maug_cleanup_if_null_lock( char*, ctl->LABEL.label );
1684
1685 maug_strncpy( buffer, ctl->LABEL.label, buffer_sz );
1686# endif
1687
1688 }
1689
1690cleanup:
1691
1692 if( RETROGUI_CTL_TYPE_TEXTBOX == ctl->base.type ) {
1693 if( NULL != ctl->TEXTBOX.text ) {
1694 maug_munlock( ctl->TEXTBOX.text_h, ctl->TEXTBOX.text );
1695 }
1696
1697 } else if( RETROGUI_CTL_TYPE_LABEL == ctl->base.type ) {
1698 if( NULL != ctl->LABEL.label ) {
1699 maug_munlock( ctl->LABEL.label_h, ctl->LABEL.label );
1700 }
1701 }
1702
1703 mdata_vector_unlock( &(gui->ctls) );
1704
1705 return retval;
1706}
1707
1708#endif /* !RETROGUI_NO_TEXTBOX */
1709
1710ssize_t retrogui_get_ctl_sel_idx( struct RETROGUI* gui, retrogui_idc_t idc ) {
1711 ssize_t idx = -1;
1712 union RETROGUI_CTL* ctl = NULL;
1713 MERROR_RETVAL retval = MERROR_OK;
1714
1715 assert( !retrogui_is_locked( gui ) );
1716 mdata_vector_lock( &(gui->ctls) );
1717
1718 ctl = _retrogui_get_ctl_by_idc( gui, idc );
1719 if( NULL == ctl ) {
1720 goto cleanup;
1721 }
1722
1723 assert( RETROGUI_CTL_TYPE_LISTBOX == ctl->base.type );
1724
1725# if defined( RETROGUI_NATIVE_WIN )
1726 idx = SendMessage( ctl->base.hwnd, LB_GETCARETINDEX, 0, 0 );
1727# else
1728 idx = ctl->LISTBOX.sel_idx;
1729# endif
1730
1731cleanup:
1732
1733 mdata_vector_unlock( &(gui->ctls) );
1734
1735 if( MERROR_OK != retval ) {
1736 idx = -1 * retval;
1737 }
1738
1739 return idx;
1740}
1741
1742MERROR_RETVAL retrogui_set_ctl_text(
1743 struct RETROGUI* gui, retrogui_idc_t idc, size_t buffer_sz,
1744 const char* fmt, ...
1745) {
1746 MERROR_RETVAL retval = MERROR_OK;
1747 size_t label_sz = 0;
1748 char* label_tmp = NULL;
1749 char* buffer = NULL;
1750 union RETROGUI_CTL* ctl = NULL;
1751 MAUG_MHANDLE buffer_h = (MAUG_MHANDLE)NULL;
1752 va_list args;
1753
1754 assert( !retrogui_is_locked( gui ) );
1755 mdata_vector_lock( &(gui->ctls) );
1756
1757 debug_printf( RETROGUI_TRACE_LVL,
1758 "setting control " SIZE_T_FMT " text to: %s", idc, fmt );
1759
1760 /* Figure out the control to update. */
1761 ctl = _retrogui_get_ctl_by_idc( gui, idc );
1762 if( NULL == ctl ) {
1763 retval = MERROR_GUI;
1764 goto cleanup;
1765 }
1766
1767 /* Perform the buffer substitutions. */
1768 buffer_h = maug_malloc( 1, buffer_sz + 1 );
1769 maug_cleanup_if_null_alloc( MAUG_MHANDLE, buffer_h );
1770
1771 maug_mlock( buffer_h, buffer );
1772 maug_cleanup_if_null_lock( char*, buffer );
1773 maug_mzero( buffer, buffer_sz + 1 );
1774
1775 assert( NULL != fmt );
1776 assert( NULL != buffer );
1777 assert( 0 < buffer_sz );
1778
1779 va_start( args, fmt );
1780 maug_vsnprintf( buffer, buffer_sz, fmt, args );
1781 va_end( args );
1782
1783 /* Perform the actual update. */
1784 if( RETROGUI_CTL_TYPE_BUTTON == ctl->base.type ) {
1785 assert( NULL == ctl->BUTTON.label );
1786 _retrogui_copy_str( label, buffer, ctl->BUTTON, label_tmp, buffer_sz );
1787 } else if( RETROGUI_CTL_TYPE_LABEL == ctl->base.type ) {
1788 assert( NULL == ctl->LABEL.label );
1789 _retrogui_copy_str( label, buffer, ctl->LABEL, label_tmp, label_sz );
1790#ifndef RETROGUI_NO_TEXTBOX
1791 } else if( RETROGUI_CTL_TYPE_TEXTBOX == ctl->base.type ) {
1792 assert( NULL == ctl->TEXTBOX.text );
1793 /* This must always be the same and an lvalue! */
1794 label_sz = RETROGUI_CTL_TEXT_SZ_MAX;
1795 _retrogui_copy_str(
1796 text, buffer, ctl->TEXTBOX, label_tmp, label_sz );
1797 ctl->TEXTBOX.text_cur = 0;
1798#endif /* !RETROGUI_NO_TEXTBOX */
1799 } else {
1800 error_printf( "invalid control type! no label!" );
1801 goto cleanup;
1802 }
1803
1804 /* New text! Redraw! */
1805 gui->flags |= RETROGUI_FLAGS_DIRTY;
1806
1807cleanup:
1808
1809 if( NULL != buffer ) {
1810 maug_munlock( buffer_h, buffer );
1811 }
1812
1813 if( NULL != buffer_h ) {
1814 maug_mfree( buffer_h );
1815 }
1816
1817 mdata_vector_unlock( &(gui->ctls) );
1818
1819 return retval;
1820}
1821
1822MERROR_RETVAL retrogui_init_ctl(
1823 union RETROGUI_CTL* ctl, uint8_t type, size_t idc
1824) {
1825 MERROR_RETVAL retval = MERROR_OK;
1826
1827 debug_printf( RETROGUI_TRACE_LVL,
1828 "initializing control base " SIZE_T_FMT "...", idc );
1829
1830 maug_mzero( ctl, sizeof( union RETROGUI_CTL ) );
1831
1832 ctl->base.type = type;
1833 ctl->base.idc = idc;
1834 ctl->base.fg_color = RETROFLAT_COLOR_NULL;
1835 ctl->base.bg_color = RETROFLAT_COLOR_NULL;
1836
1837 #define RETROGUI_CTL_TABLE_INITS( idx, c_name, c_fields ) \
1838 } else if( RETROGUI_CTL_TYPE_ ## c_name == ctl->base.type ) { \
1839 retrogui_init_ ## c_name( ctl );
1840
1841 if( 0 ) {
1842 RETROGUI_CTL_TABLE( RETROGUI_CTL_TABLE_INITS )
1843 }
1844
1845 return retval;
1846}
1847
1848MERROR_RETVAL retrogui_free( struct RETROGUI* gui ) {
1849 size_t i = 0;
1850 union RETROGUI_CTL* ctl = NULL;
1851 MERROR_RETVAL retval = MERROR_OK;
1852
1853 if( retrogui_is_locked( gui ) ) {
1854 error_printf( "GUI is locked!" );
1855 goto cleanup;
1856 }
1857
1858 assert( !retrogui_is_locked( gui ) );
1859 mdata_vector_lock( &(gui->ctls) );
1860
1861 #define RETROGUI_CTL_TABLE_FREE( idx, c_name, c_fields ) \
1862 } else if( RETROGUI_CTL_TYPE_ ## c_name == ctl->base.type ) { \
1863 retrogui_free_ ## c_name( ctl );
1864
1865 for( i = 0 ; mdata_vector_ct( &(gui->ctls) ) > i ; i++ ) {
1866 ctl = mdata_vector_get( &(gui->ctls), i, union RETROGUI_CTL );
1867 if( 0 ) {
1868 RETROGUI_CTL_TABLE( RETROGUI_CTL_TABLE_FREE )
1869 }
1870 }
1871
1872 mdata_vector_unlock( &(gui->ctls) );
1873
1874cleanup:
1875
1876 mdata_vector_free( &(gui->ctls) );
1877
1878 return retval;
1879}
1880
1881MERROR_RETVAL retrogui_init( struct RETROGUI* gui ) {
1882 MERROR_RETVAL retval = MERROR_OK;
1883
1884 maug_mzero( gui, sizeof( struct RETROGUI ) );
1885
1886 gui->bg_color = RETROFLAT_COLOR_BLACK;
1887
1888 debug_printf( RETROGUI_TRACE_LVL, "initialized GUI" );
1889
1890 return retval;
1891}
1892
1893#else
1894
1895#define RETROGUI_CTL_TABLE_CONSTS( idx, c_name, c_fields ) \
1896 extern MAUG_CONST uint8_t RETROGUI_CTL_TYPE_ ## c_name;
1897
1898RETROGUI_CTL_TABLE( RETROGUI_CTL_TABLE_CONSTS )
1899
1900extern MAUG_CONST char* gc_retrogui_ctl_names[];
1901
1902#endif /* RETROGUI_C */
1903
1904 /* maug_retrogui */
1905
1906#endif /* !RETROGUI_H */
1907
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:62
int8_t RETROFLAT_COLOR
Defines an index in the platform-specific color-table.
Definition retroflt.h:307
void retroflat_rect(struct RETROFLAT_BITMAP *target, const RETROFLAT_COLOR color, int16_t x, int16_t y, int16_t w, int16_t h, uint8_t flags)
Draw a rectangle onto the target RETROFLAT_BITMAP.
#define RETROFLAT_FLAGS_FILL
Flag for retroflat_rect() or retroflat_ellipse(), indicating drawn shape should be filled.
Definition retroflt.h:355
void retroflat_line(struct RETROFLAT_BITMAP *target, const RETROFLAT_COLOR color, int16_t x1, int16_t y1, int16_t x2, int16_t y2, uint8_t flags)
Draw a straight line onto the target RETROFLAT_BITMAP.
#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:813
#define retroflat_buffer_bksp(buffer, buffer_cur, buffer_sz)
Remove a character from a text buffer before cursor position.
Definition retroflt.h:797
#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:459
void retroflat_message(uint8_t flags, const char *title, const char *format,...)
Display a message in a dialog box and/or on stderr.
#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:143
#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:155
#define RETROGUI_FLAGS_DIRTY
RETROGUI::flags indicating controls should be redrawn.
Definition retrogui.h:16
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.
size_t retrogui_idc_t
Unique identifying constant number for controls.
Definition retrogui.h:89
Platform-specific bitmap structure. retroflat_bitmap_ok() can be used on a pointer to it to determine...
Definition retpltd.h:21
Struct passed to retroflat_poll_input() to hold return data.
Definition retroflt.h:836
int mouse_y
Y-coordinate of the mouse pointer in pixels if the returned event is a mouse click.
Definition retroflt.h:846
int mouse_x
X-coordinate of the mouse pointer in pixels if the returned event is a mouse click.
Definition retroflt.h:841
Fields common to ALL RETROGUI_CTL types.
Definition retrogui.h:125
Definition retrogui.h:167
Definition retrogui.h:158