11#ifndef RETROFONT_PRESENT
12# error "retrofont not present!"
16#define RETROGUI_FLAGS_DIRTY 0x01
18#ifndef RETROGUI_TRACE_LVL
19# define RETROGUI_TRACE_LVL 0
22#ifndef RETROGUI_CTL_TEXT_SZ_MAX
23# define RETROGUI_CTL_TEXT_SZ_MAX 128
26#ifndef RETROGUI_CTL_SZ_MAX_INIT
27# define RETROGUI_CTL_SZ_MAX_INIT 20
30#ifndef RETROGUI_PADDING
31# define RETROGUI_PADDING 5
34#ifndef RETROGUI_BTN_LBL_SZ_MAX
35# define RETROGUI_BTN_LBL_SZ_MAX 64
38#ifndef RETROGUI_BTN_LBL_PADDED_X
39# define RETROGUI_BTN_LBL_PADDED_X 8
42#ifndef RETROGUI_BTN_LBL_PADDED_Y
43# define RETROGUI_BTN_LBL_PADDED_Y 8
46#ifndef RETROGUI_CTL_TEXT_BLINK_FRAMES
47# define RETROGUI_CTL_TEXT_BLINK_FRAMES 15
50#define retrogui_lock( gui )
52#define retrogui_unlock( gui )
54#define retrogui_is_locked( gui ) (mdata_vector_is_locked( &((gui)->ctls) ))
56#define _retrogui_copy_str( field, src_str, dest_ctl, str_tmp, str_sz ) \
58 assert( NULL != src_str ); \
59 debug_printf( RETROGUI_TRACE_LVL, \
60 "copying string \"%s\" to " #dest_ctl, src_str ); \
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 ); \
66 if( (MAUG_MHANDLE)NULL != dest_ctl. field ## _h ) { \
68 maug_mfree( dest_ctl. field ## _h ); \
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 ); \
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 );
91#define RETROGUI_IDC_NONE 0
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; )
113#ifdef RETROGUI_NO_TEXTBOX
114# define RETROGUI_CTL_TABLE( f ) RETROGUI_CTL_TABLE_BASE( f )
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; )
121 f( 5, SCROLLBAR,
size_t min;
size_t max;
size_t value; )
134#if defined( RETROGUI_NATIVE_WIN )
143#define RETROGUI_CTL_TABLE_FIELDS( idx, c_name, c_fields ) \
144 struct RETROGUI_CTL_ ## c_name { \
145 struct RETROGUI_CTL_BASE base; \
155#define RETROGUI_CTL_TABLE_TYPES( idx, c_name, c_fields ) \
156 struct RETROGUI_CTL_ ## c_name c_name;
165typedef void (*retrogui_xy_cb)(
size_t* x,
size_t* y,
void* data );
175 struct MDATA_VECTOR ctls;
178#ifdef RETROGXC_PRESENT
197 struct RETROGUI* gui, RETROFLAT_IN_KEY* p_input,
204 size_t* p_w,
size_t* p_h,
size_t max_w,
size_t max_h );
208 size_t x,
size_t y,
size_t w,
size_t h );
216ssize_t retrogui_get_ctl_sel_idx(
struct RETROGUI* gui,
size_t idc );
218#ifndef RETROGUI_NO_TEXTBOX
230 const char* fmt, ... );
243#define RETROGUI_CTL_TABLE_CONSTS( idx, c_name, c_fields ) \
244 MAUG_CONST uint8_t RETROGUI_CTL_TYPE_ ## c_name = idx;
246RETROGUI_CTL_TABLE( RETROGUI_CTL_TABLE_CONSTS )
248#define RETROGUI_CTL_TABLE_NAMES( idx, c_name, f_fields ) \
251MAUG_CONST
char* gc_retrogui_ctl_names[] = {
252 RETROGUI_CTL_TABLE( RETROGUI_CTL_TABLE_NAMES )
291 size_t* p_w,
size_t* p_h,
size_t max_w,
size_t max_h
298 size_t x,
size_t y,
size_t w,
size_t h
303static void retrogui_free_NONE(
union RETROGUI_CTL* ctl ) {
326# if defined( RETROGUI_NATIVE_WIN )
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 );
336 while( i < ctl->LISTBOX.list_sz ) {
337#ifdef RETROGXC_PRESENT
339 gui->draw_bmp, &(ctl->LISTBOX.list[i]), 0, gui->font_idx,
340 ctl->base.w, ctl->base.h, &w, &h, 0 );
343 gui->draw_bmp, &(ctl->LISTBOX.list[i]), 0, gui->font_h,
344 ctl->base.w, ctl->base.h, &w, &h, 0 );
349 ctl->base.y + ((j + 1) * (h + RETROGUI_PADDING))
351 ctl->LISTBOX.sel_idx = j;
356 i += maug_strlen( &(ctl->LISTBOX.list[i]) ) + 1;
357 assert( i <= ctl->LISTBOX.list_sz );
363 if( NULL != ctl->LISTBOX.list ) {
364 maug_munlock( ctl->LISTBOX.list_h, ctl->LISTBOX.list );
367 if( MERROR_OK != retval ) {
368 idc_out = RETROGUI_IDC_NONE;
387static void retrogui_redraw_LISTBOX(
395 assert( NULL == ctl->LISTBOX.list );
397# if defined( RETROGUI_NATIVE_WIN )
401 maug_mlock( ctl->LISTBOX.list_h, ctl->LISTBOX.list );
402 if( NULL == ctl->LISTBOX.list ) {
407 gui->x + ctl->base.x, gui->y + ctl->base.y,
411 while( i < ctl->LISTBOX.list_sz ) {
412#ifdef RETROGXC_PRESENT
414 gui->draw_bmp, &(ctl->LISTBOX.list[i]), 0, gui->font_idx,
415 ctl->base.w, ctl->base.h, &w, &h, 0 );
418 gui->draw_bmp, &(ctl->LISTBOX.list[i]), 0, gui->font_h,
419 ctl->base.w, ctl->base.h, &w, &h, 0 );
421 if( j == ctl->LISTBOX.sel_idx ) {
424 gui->x + ctl->base.x,
425 gui->y + ctl->base.y + (j * (h + RETROGUI_PADDING)),
429#ifdef RETROGXC_PRESENT
431 gui->draw_bmp, ctl->base.fg_color, &(ctl->LISTBOX.list[i]), 0,
433 gui->x + ctl->base.x,
434 gui->y + ctl->base.y + (j * (h + RETROGUI_PADDING)),
438 gui->draw_bmp, ctl->base.fg_color, &(ctl->LISTBOX.list[i]), 0,
440 gui->x + ctl->base.x,
441 gui->y + ctl->base.y + (j * (h + RETROGUI_PADDING)),
446 i += maug_strlen( &(ctl->LISTBOX.list[i]) ) + 1;
447 assert( i <= ctl->LISTBOX.list_sz );
453 if( NULL != ctl->LISTBOX.list ) {
454 maug_munlock( ctl->LISTBOX.list_h, ctl->LISTBOX.list );
466# if defined( RETROGUI_NATIVE_WIN )
469 SendMessage( ctl->base.hwnd, LB_SETCURSEL, item_idx, 0 );
473 ctl->LISTBOX.sel_idx = item_idx;
485 MAUG_MHANDLE listbox_h_new = (MAUG_MHANDLE)NULL;
487 retrogui_lock( gui );
489 debug_printf( RETROGUI_TRACE_LVL,
490 "pushing item \"%s\" to listbox " SIZE_T_FMT
"...", item, idc );
492 ctl = _retrogui_get_ctl_by_idc( gui, idc );
495 "Adding item \"%s\" failed: Control missing!", item );
500# if defined( RETROGUI_NATIVE_WIN )
502 SendMessage( ctl->LISTBOX.base.hwnd, LB_ADDSTRING, 0, (LPARAM)item );
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;
512 if( NULL != ctl->LISTBOX.list ) {
513 maug_munlock( ctl->LISTBOX.list_h, ctl->LISTBOX.list );
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 );
521 listbox_h_new, ctl->LISTBOX.list_h,
522 ctl->LISTBOX.list_sz_max * 2,
sizeof(
char ) );
523 ctl->LISTBOX.list_sz_max *= 2;
526 maug_mlock( ctl->LISTBOX.list_h, ctl->LISTBOX.list );
527 maug_cleanup_if_null_alloc(
char*, ctl->LISTBOX.list );
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;
537 if( NULL != ctl->LISTBOX.list ) {
538 maug_munlock( ctl->LISTBOX.list_h, ctl->LISTBOX.list );
547# if defined( RETROGUI_NATIVE_WIN )
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" );
575 size_t* p_w,
size_t* p_h,
size_t max_w,
size_t max_h
584 size_t x,
size_t y,
size_t w,
size_t h
591static void retrogui_free_LISTBOX(
union RETROGUI_CTL* ctl ) {
592 assert( NULL == ctl->LISTBOX.list );
593 maug_mfree( ctl->LISTBOX.list_h );
599 debug_printf( RETROGUI_TRACE_LVL,
600 "initializing listbox " SIZE_T_FMT
"...", ctl->base.idc );
602 ctl->base.fg_color = RETROFLAT_COLOR_BLACK;
603 ctl->base.bg_color = RETROFLAT_COLOR_WHITE;
617 if( 0 < ctl->BUTTON.push_frames ) {
622 idc_out = ctl->base.idc;
626 ctl->BUTTON.push_frames = 3;
646static void retrogui_redraw_BUTTON(
653 retroflat_rect( gui->draw_bmp, ctl->base.bg_color, ctl->base.x, ctl->base.y,
657 gui->x + ctl->base.x, gui->y + ctl->base.y,
658 ctl->base.w, ctl->base.h, 0 );
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 );
671 ctl->BUTTON.push_frames--;
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 );
685 maug_mlock( ctl->BUTTON.label_h, ctl->BUTTON.label );
686 if( NULL == ctl->BUTTON.label ) {
687 error_printf(
"could not lock BUTTON label!" );
692#ifdef RETROGXC_PRESENT
697 gui->draw_bmp, ctl->BUTTON.label, 0,
698#ifdef RETROGXC_PRESENT
704 ctl->base.w, ctl->base.h, &w, &h, ctl->BUTTON.font_flags );
706#ifdef RETROGXC_PRESENT
711 gui->draw_bmp, ctl->base.fg_color, ctl->BUTTON.label, 0,
712#ifdef 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,
720 ctl->base.w, ctl->base.h, ctl->BUTTON.font_flags );
722 maug_munlock( ctl->BUTTON.label_h, ctl->BUTTON.label );
732# if defined( RETROGUI_NATIVE_WIN )
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 );
749 char* label_tmp = NULL;
751 debug_printf( RETROGUI_TRACE_LVL,
"pushing BUTTON control..." );
754 label, ctl->BUTTON.label, ctl->BUTTON, label_tmp, label_sz );
755 ctl->BUTTON.label = NULL;
765 size_t* p_w,
size_t* p_h,
size_t max_w,
size_t max_h
769 assert( NULL != ctl );
770 assert( NULL == ctl->BUTTON.label );
771 assert( NULL != ctl->BUTTON.label_h );
773 maug_mlock( ctl->BUTTON.label_h, ctl->BUTTON.label );
774 maug_cleanup_if_null_lock(
char*, ctl->BUTTON.label );
777#ifdef RETROGXC_PRESENT
785#ifdef RETROGXC_PRESENT
793 p_h, ctl->BUTTON.font_flags );
796 *p_w += RETROGUI_BTN_LBL_PADDED_X;
797 *p_h += RETROGUI_BTN_LBL_PADDED_Y;
801 maug_munlock( ctl->BUTTON.label_h, ctl->BUTTON.label );
808 size_t x,
size_t y,
size_t w,
size_t h
812# if defined( RETROGUI_NATIVE_WIN )
815 assert( NULL != ctl );
830static void retrogui_free_BUTTON(
union RETROGUI_CTL* ctl ) {
831 if( NULL != ctl->BUTTON.label_h ) {
832 maug_mfree( ctl->BUTTON.label_h );
839 debug_printf( RETROGUI_TRACE_LVL,
840 "initializing button " SIZE_T_FMT
"...", ctl->base.idc );
842 ctl->base.fg_color = RETROFLAT_COLOR_BLACK;
843 ctl->base.bg_color = RETROFLAT_COLOR_GRAY;
848#ifndef RETROGUI_NO_TEXTBOX
869# if defined( RETROGUI_NATIVE_WIN )
873 c = retroflat_vk_to_ascii( *p_input, input_evt->key_flags );
878 RETROFLAT_KEY_RIGHT != *p_input &&
879 RETROFLAT_KEY_LEFT != *p_input
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!" );
894 case RETROFLAT_KEY_BKSP:
896 ctl->TEXTBOX.text, ctl->TEXTBOX.text_cur, ctl->TEXTBOX.text_sz )
899 case RETROFLAT_KEY_ENTER:
900 idc_out = ctl->base.idc;
903 case RETROFLAT_KEY_LEFT:
904 if( 0 < ctl->TEXTBOX.text_cur ) {
905 ctl->TEXTBOX.text_cur--;
909 case RETROFLAT_KEY_RIGHT:
910 if( ctl->TEXTBOX.text_sz > ctl->TEXTBOX.text_cur ) {
911 ctl->TEXTBOX.text_cur++;
916 assert( ctl->TEXTBOX.text_sz < ctl->TEXTBOX.text_sz_max );
919 ctl->TEXTBOX.text_cur,
920 ctl->TEXTBOX.text_sz,
921 ctl->TEXTBOX.text_sz_max );
929 if( NULL != ctl->TEXTBOX.text ) {
930 maug_munlock( ctl->TEXTBOX.text_h, ctl->TEXTBOX.text );
938static void retrogui_redraw_TEXTBOX(
942# if defined( RETROGUI_NATIVE_WIN )
947 gui->x + ctl->base.x, gui->y + ctl->base.y,
953 gui->x + ctl->base.x,
954 gui->y + ctl->base.y, ctl->base.w, 2,
958 gui->x + ctl->base.x,
959 gui->y + ctl->base.y, 2, ctl->base.h,
963 gui->x + ctl->base.x,
964 gui->y + ctl->base.y + ctl->base.h - 1,
969 gui->x + ctl->base.x + ctl->base.w - 1,
970 gui->y + ctl->base.y, 2, ctl->base.h,
975 assert( NULL == ctl->TEXTBOX.text );
976 maug_mlock( ctl->TEXTBOX.text_h, ctl->TEXTBOX.text );
977 if( NULL == ctl->TEXTBOX.text ) {
981#ifdef RETROGXC_PRESENT
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 );
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 );
995 if( NULL != ctl->TEXTBOX.text ) {
996 maug_munlock( ctl->TEXTBOX.text_h, ctl->TEXTBOX.text );
1001 gui->x + ctl->base.x + RETROGUI_PADDING + (8 * ctl->TEXTBOX.text_cur),
1002 gui->y + ctl->base.y + RETROGUI_PADDING,
1006 gui->focus == ctl->base.idc &&
1009 if( (-1 * RETROGUI_CTL_TEXT_BLINK_FRAMES) > --(ctl->TEXTBOX.blink_frames) ) {
1010 ctl->TEXTBOX.blink_frames = RETROGUI_CTL_TEXT_BLINK_FRAMES;
1023# if defined( RETROGUI_NATIVE_WIN )
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;
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;
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 );
1062 size_t* p_w,
size_t* p_h,
size_t max_w,
size_t max_h
1071 size_t x,
size_t y,
size_t w,
size_t h
1078static void retrogui_free_TEXTBOX(
union RETROGUI_CTL* ctl ) {
1079 if( NULL != ctl->TEXTBOX.text_h ) {
1080 maug_mfree( ctl->TEXTBOX.text_h );
1087 debug_printf( RETROGUI_TRACE_LVL,
1088 "initializing textbox " SIZE_T_FMT
"...", ctl->base.idc );
1090 ctl->base.fg_color = RETROFLAT_COLOR_BLACK;
1091 ctl->base.bg_color = RETROFLAT_COLOR_WHITE;
1105 return RETROGUI_IDC_NONE;
1112 return RETROGUI_IDC_NONE;
1115static void retrogui_redraw_LABEL(
1119# if defined( RETROGUI_NATIVE_WIN )
1125#ifdef RETROGXC_PRESENT
1126 assert( 0 <= gui->font_idx );
1128 assert( (MAUG_MHANDLE)NULL != gui->font_h );
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!" );
1138#ifdef RETROGXC_PRESENT
1143 gui->draw_bmp, ctl->base.fg_color, ctl->LABEL.label,
1144 ctl->LABEL.label_sz,
1145#ifdef 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 );
1156 if( NULL != ctl->LABEL.label ) {
1157 maug_munlock( ctl->LABEL.label_h, ctl->LABEL.label );
1168# if defined( RETROGUI_NATIVE_WIN )
1173 size_t label_sz = 0;
1174 char* label_tmp = NULL;
1176 debug_printf( RETROGUI_TRACE_LVL,
"pushing LABEL control..." );
1179 label, ctl->LABEL.label, ctl->LABEL, label_tmp, label_sz );
1180 ctl->LABEL.label = NULL;
1190 size_t* p_w,
size_t* p_h,
size_t max_w,
size_t max_h
1199 size_t x,
size_t y,
size_t w,
size_t h
1206static void retrogui_free_LABEL(
union RETROGUI_CTL* ctl ) {
1207 if( NULL != ctl->LABEL.label_h ) {
1208 maug_mfree( ctl->LABEL.label_h );
1215 debug_printf( RETROGUI_TRACE_LVL,
1216 "initializing label " SIZE_T_FMT
"...", ctl->base.idc );
1218 ctl->base.fg_color = RETROFLAT_COLOR_BLACK;
1219 ctl->base.bg_color = RETROFLAT_COLOR_WHITE;
1232 assert( retrogui_is_locked( gui ) );
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 ) {
1244 "Could not find GUI item: " SIZE_T_FMT, idc );
1252 size_t* p_w,
size_t* p_h,
size_t max_w,
size_t max_h
1257 assert( retrogui_is_locked( gui ) );
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 );
1263 ctl = _retrogui_get_ctl_by_idc( gui, idc );
1265 error_printf(
"could not find control to size!" );
1266 retval = MERROR_GUI;
1270 #define RETROGUI_CTL_TABLE_SZ( idx, c_name, c_fields ) \
1271 } else if( RETROGUI_CTL_TYPE_ ## c_name == ctl->base.type ) { \
1273 retval = retrogui_sz_ ## c_name( gui, ctl, p_w, p_h, max_w, max_h ); \
1274 maug_cleanup_if_not_ok();
1277 RETROGUI_CTL_TABLE( RETROGUI_CTL_TABLE_SZ )
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 );
1292 struct RETROGUI* gui, RETROFLAT_IN_KEY* p_input,
1302 assert( !retrogui_is_locked( gui ) );
1303 mdata_vector_lock( &(gui->ctls) );
1305# if defined( RETROGUI_NATIVE_WIN )
1307 if( 0 == g_retroflat_state->last_idc ) {
1312 ctl = retrogui_get_ctl_by_idc( gui, g_retroflat_state->last_idc );
1313 g_retroflat_state->last_idc = 0;
1315 debug_printf( RETROGUI_TRACE_LVL,
1316 "invalid IDC: " SIZE_T_FMT, gui->focus );
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 ) );
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 );
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 );
1343 if( 0 == *p_input ) {
1344 goto reset_debounce;
1346# ifndef RETROGUI_NO_MOUSE
1348 RETROFLAT_MOUSE_B_LEFT == *p_input ||
1349 RETROFLAT_MOUSE_B_RIGHT == *p_input
1352 gui->focus = RETROGUI_IDC_NONE;
1354 mouse_x = input_evt->
mouse_x - gui->x;
1355 mouse_y = input_evt->
mouse_y - gui->y;
1357 for( i = 0 ; mdata_vector_ct( &(gui->ctls) ) > i ; i++ ) {
1358 ctl = mdata_vector_get( &(gui->ctls), i,
union RETROGUI_CTL );
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
1368 if( gui->idc_prev == ctl->base.idc ) {
1371 idc_out = RETROGUI_IDC_NONE;
1375 gui->idc_prev = ctl->base.idc;
1377 gui->focus = ctl->base.idc;
1380 RETROGUI_CTL_TABLE( RETROGUI_CTL_TABLE_CLICK )
1388 if( RETROGUI_IDC_NONE == gui->focus ) {
1389 goto reset_debounce;
1394 ctl = _retrogui_get_ctl_by_idc( gui, gui->focus );
1396 debug_printf( RETROGUI_TRACE_LVL,
1397 "invalid IDC: " SIZE_T_FMT, gui->focus );
1398 goto reset_debounce;
1402 RETROGUI_CTL_TABLE( RETROGUI_CTL_TABLE_KEY )
1409 gui->idc_prev = RETROGUI_IDC_NONE;
1415 if( MERROR_OK != retval ) {
1416 idc_out = RETROGUI_IDC_NONE;
1419 mdata_vector_unlock( &(gui->ctls) );
1434 assert( !retrogui_is_locked( gui ) );
1435 mdata_vector_lock( &(gui->ctls) );
1438 RETROFLAT_COLOR_BLACK != gui->bg_color &&
1439 0 < gui->w && 0 < gui->h
1445 #define RETROGUI_CTL_TABLE_REDRAW( idx, c_name, c_fields ) \
1446 } else if( RETROGUI_CTL_TYPE_ ## c_name == ctl->base.type ) { \
1448 gui->flags &= ~RETROGUI_FLAGS_DIRTY; \
1449 retrogui_redraw_ ## c_name( gui, ctl );
1451 for( i = 0 ; mdata_vector_ct( &(gui->ctls) ) > i ; i++ ) {
1452 ctl = mdata_vector_get( &(gui->ctls), i,
union RETROGUI_CTL );
1454 RETROGUI_CTL_TABLE( RETROGUI_CTL_TABLE_REDRAW )
1460 mdata_vector_unlock( &(gui->ctls) );
1467 size_t x,
size_t y,
size_t w,
size_t h
1472 assert( !retrogui_is_locked( gui ) );
1473 mdata_vector_lock( &(gui->ctls) );
1475 debug_printf( RETROGUI_TRACE_LVL,
1476 "moving control " SIZE_T_FMT
" to: " SIZE_T_FMT
", " SIZE_T_FMT,
1479 ctl = _retrogui_get_ctl_by_idc( gui, idc );
1481 error_printf(
"could not position control!" );
1482 retval = MERROR_GUI;
1486 #define RETROGUI_CTL_TABLE_POS( idx, c_name, c_fields ) \
1487 } else if( RETROGUI_CTL_TYPE_ ## c_name == ctl->base.type ) { \
1489 retval = retrogui_pos_ ## c_name( gui, ctl, x, y, w, h ); \
1490 maug_cleanup_if_not_ok();
1493 RETROGUI_CTL_TABLE( RETROGUI_CTL_TABLE_POS )
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 );
1507 mdata_vector_unlock( &(gui->ctls) );
1518 assert( 0 < ctl->base.idc );
1520#ifdef RETROGXC_PRESENT
1521 if( 0 > gui->font_idx ) {
1523 if( (MAUG_MHANDLE)NULL == gui->font_h ) {
1527 retval = MERROR_GUI;
1531 assert( !retrogui_is_locked( gui ) );
1541 debug_printf( RETROGUI_TRACE_LVL,
1542 "gui->ctls_ct: " SIZE_T_FMT, mdata_vector_ct( &(gui->ctls) ) );
1544 if( RETROFLAT_COLOR_NULL == ctl->base.bg_color ) {
1546 "invalid background color specified for control " SIZE_T_FMT
"!",
1548 retval = MERROR_GUI;
1553 if( RETROFLAT_COLOR_NULL == ctl->base.fg_color ) {
1555 "invalid foreground color specified for control " SIZE_T_FMT
"!",
1557 retval = MERROR_GUI;
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) ) );
1567 mdata_vector_append( &(gui->ctls), ctl,
sizeof(
union RETROGUI_CTL ) );
1574 mdata_vector_lock( &(gui->ctls) );
1577 ctl = mdata_vector_get_last( &(gui->ctls),
1579 assert( NULL != ctl );
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();
1589 RETROGUI_CTL_TABLE( RETROGUI_CTL_TABLE_PUSH )
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();
1606 mdata_vector_unlock( &(gui->ctls) );
1616 if( retrogui_is_locked( gui ) ) {
1617 error_printf(
"GUI is locked!" );
1621 assert( !retrogui_is_locked( gui ) );
1622 mdata_vector_lock( &(gui->ctls) );
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 );
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 ) {
1636 RETROGUI_CTL_TABLE( RETROGUI_CTL_TABLE_FREE_CTL )
1640 mdata_vector_unlock( &(gui->ctls) );
1641 mdata_vector_remove( &(gui->ctls), i );
1642 mdata_vector_lock( &(gui->ctls) );
1646 mdata_vector_unlock( &(gui->ctls) );
1653#ifndef RETROGUI_NO_TEXTBOX
1661 assert( !retrogui_is_locked( gui ) );
1662 mdata_vector_lock( &(gui->ctls) );
1664 ctl = _retrogui_get_ctl_by_idc( gui, idc );
1669 if( RETROGUI_CTL_TYPE_TEXTBOX == ctl->base.type ) {
1670# if defined( RETROGUI_NATIVE_WIN )
1673 maug_mlock( ctl->TEXTBOX.text_h, ctl->TEXTBOX.text );
1674 maug_cleanup_if_null_lock(
char*, ctl->TEXTBOX.text );
1676 maug_strncpy( buffer, ctl->TEXTBOX.text, buffer_sz );
1678 }
else if( RETROGUI_CTL_TYPE_LABEL == ctl->base.type ) {
1679# if defined( RETROGUI_NATIVE_WIN )
1682 maug_mlock( ctl->LABEL.label_h, ctl->LABEL.label );
1683 maug_cleanup_if_null_lock(
char*, ctl->LABEL.label );
1685 maug_strncpy( buffer, ctl->LABEL.label, buffer_sz );
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 );
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 );
1703 mdata_vector_unlock( &(gui->ctls) );
1715 assert( !retrogui_is_locked( gui ) );
1716 mdata_vector_lock( &(gui->ctls) );
1718 ctl = _retrogui_get_ctl_by_idc( gui, idc );
1723 assert( RETROGUI_CTL_TYPE_LISTBOX == ctl->base.type );
1725# if defined( RETROGUI_NATIVE_WIN )
1726 idx = SendMessage( ctl->base.hwnd, LB_GETCARETINDEX, 0, 0 );
1728 idx = ctl->LISTBOX.sel_idx;
1733 mdata_vector_unlock( &(gui->ctls) );
1735 if( MERROR_OK != retval ) {
1744 const char* fmt, ...
1747 size_t label_sz = 0;
1748 char* label_tmp = NULL;
1749 char* buffer = NULL;
1751 MAUG_MHANDLE buffer_h = (MAUG_MHANDLE)NULL;
1754 assert( !retrogui_is_locked( gui ) );
1755 mdata_vector_lock( &(gui->ctls) );
1757 debug_printf( RETROGUI_TRACE_LVL,
1758 "setting control " SIZE_T_FMT
" text to: %s", idc, fmt );
1761 ctl = _retrogui_get_ctl_by_idc( gui, idc );
1763 retval = MERROR_GUI;
1768 buffer_h = maug_malloc( 1, buffer_sz + 1 );
1769 maug_cleanup_if_null_alloc( MAUG_MHANDLE, buffer_h );
1771 maug_mlock( buffer_h, buffer );
1772 maug_cleanup_if_null_lock(
char*, buffer );
1775 assert( NULL != fmt );
1776 assert( NULL != buffer );
1777 assert( 0 < buffer_sz );
1779 va_start( args, fmt );
1780 maug_vsnprintf( buffer, buffer_sz, fmt, args );
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 );
1794 label_sz = RETROGUI_CTL_TEXT_SZ_MAX;
1796 text, buffer, ctl->TEXTBOX, label_tmp, label_sz );
1797 ctl->TEXTBOX.text_cur = 0;
1800 error_printf(
"invalid control type! no label!" );
1809 if( NULL != buffer ) {
1810 maug_munlock( buffer_h, buffer );
1813 if( NULL != buffer_h ) {
1814 maug_mfree( buffer_h );
1817 mdata_vector_unlock( &(gui->ctls) );
1827 debug_printf( RETROGUI_TRACE_LVL,
1828 "initializing control base " SIZE_T_FMT
"...", idc );
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;
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 );
1842 RETROGUI_CTL_TABLE( RETROGUI_CTL_TABLE_INITS )
1853 if( retrogui_is_locked( gui ) ) {
1854 error_printf(
"GUI is locked!" );
1858 assert( !retrogui_is_locked( gui ) );
1859 mdata_vector_lock( &(gui->ctls) );
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 );
1865 for( i = 0 ; mdata_vector_ct( &(gui->ctls) ) > i ; i++ ) {
1866 ctl = mdata_vector_get( &(gui->ctls), i,
union RETROGUI_CTL );
1868 RETROGUI_CTL_TABLE( RETROGUI_CTL_TABLE_FREE )
1872 mdata_vector_unlock( &(gui->ctls) );
1876 mdata_vector_free( &(gui->ctls) );
1886 gui->bg_color = RETROFLAT_COLOR_BLACK;
1888 debug_printf( RETROGUI_TRACE_LVL,
"initialized GUI" );
1895#define RETROGUI_CTL_TABLE_CONSTS( idx, c_name, c_fields ) \
1896 extern MAUG_CONST uint8_t RETROGUI_CTL_TYPE_ ## c_name;
1898RETROGUI_CTL_TABLE( RETROGUI_CTL_TABLE_CONSTS )
1900extern MAUG_CONST
char* gc_retrogui_ctl_names[];
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_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
Fields common to ALL RETROGUI_CTL types.
Definition retrogui.h:125
Definition retrogui.h:167
Definition retrogui.h:158