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
78
79#ifndef RETROFONT_PRESENT
80# error "retrofont not present!"
81#endif /* !RETROFONT_PRESENT */
82
83/* TODO: Maug log unified API to reference. */
84
85#ifndef RETROGUI_TRACE_LVL
86# define RETROGUI_TRACE_LVL 0
87#endif /* !RETROGUI_TRACE_LVL */
88
89#ifndef RETROGUI_COLOR_BORDER
95# define RETROGUI_COLOR_BORDER RETROFLAT_COLOR_DARKBLUE
96#endif /* !RETROGUI_COLOR_BORDER */
97
98#ifndef RETROGUI_CTL_TEXT_SZ_MAX
104
105#ifndef RETROGUI_KEY_ACTIVATE
111# define RETROGUI_KEY_ACTIVATE RETROFLAT_KEY_SPACE
112#endif /* !RETROGUI_KEY_ACTIVATE */
113
114#ifndef RETROGUI_KEY_NEXT
120# define RETROGUI_KEY_NEXT RETROFLAT_KEY_DOWN
121#endif /* !RETROGUI_KEY_NEXT */
122
123#ifndef RETROGUI_KEY_PREV
129# define RETROGUI_KEY_PREV RETROFLAT_KEY_UP
130#endif /* !RETROGUI_KEY_PREV */
131
132#ifndef RETROGUI_KEY_SEL_NEXT
138# define RETROGUI_KEY_SEL_NEXT RETROFLAT_KEY_RIGHT
139#endif /* !RETROGUI_KEY_SEL_NEXT */
140
141#ifndef RETROGUI_KEY_SEL_PREV
147# define RETROGUI_KEY_SEL_PREV RETROFLAT_KEY_LEFT
148#endif /* !RETROGUI_KEY_SEL_PREV */
149
150#ifndef RETROGUI_PAD_ACTIVATE
156# define RETROGUI_PAD_ACTIVATE RETROFLAT_PAD_A
157#endif /* !RETROGUI_PAD_ACTIVATE */
158
159#ifndef RETROGUI_PAD_NEXT
165# define RETROGUI_PAD_NEXT RETROFLAT_PAD_DOWN
166#endif /* !RETROGUI_PAD_NEXT */
167
168#ifndef RETROGUI_PAD_PREV
174# define RETROGUI_PAD_PREV RETROFLAT_PAD_UP
175#endif /* !RETROGUI_PAD_PREV */
176
177#ifndef RETROGUI_PAD_SEL_NEXT
183# define RETROGUI_PAD_SEL_NEXT RETROFLAT_PAD_RIGHT
184#endif /* !RETROGUI_PAD_SEL_NEXT */
185
186#ifndef RETROGUI_PAD_SEL_PREV
192# define RETROGUI_PAD_SEL_PREV RETROFLAT_PAD_LEFT
193#endif /* !RETROGUI_PAD_SEL_PREV */
194
195# define RETROGUI_CTL_TEXT_SZ_MAX 128
196#endif /* !RETROGUI_CTL_TEXT_SZ_MAX */
197
198#ifndef RETROGUI_CTL_SZ_MAX_INIT
199# define RETROGUI_CTL_SZ_MAX_INIT 20
200#endif /* !RETROGUI_CTL_SZ_MAX_INIT */
201
202#ifndef RETROGUI_PADDING
207# define RETROGUI_PADDING 5
208#endif /* !RETROGUI_PADDING */
209
210#ifndef RETROGUI_BTN_LBL_SZ_MAX
211# define RETROGUI_BTN_LBL_SZ_MAX 64
212#endif /* !RETROGUI_BTN_LBL_SZ_MAX */
213
214#ifndef RETROGUI_BTN_LBL_PADDED_X
215# define RETROGUI_BTN_LBL_PADDED_X 8
216#endif /* !RETROGUI_BTN_LBL_PADDED_X */
217
218#ifndef RETROGUI_BTN_LBL_PADDED_Y
219# define RETROGUI_BTN_LBL_PADDED_Y 8
220#endif /* !RETROGUI_BTN_LBL_PADDED_Y */
221
222#ifndef RETROGUI_CTL_TEXT_BLINK_FRAMES
223# define RETROGUI_CTL_TEXT_BLINK_FRAMES 15
224#endif /* !RETROGUI_CTL_TEXT_BLINK_FRAMES */
225
226#ifndef RETROGUI_CTL_LISTBOX_CURSOR_RADIUS
227# define RETROGUI_CTL_LISTBOX_CURSOR_RADIUS 8
228#endif /* !RETROGUI_CTL_LISTBOX_CURSOR_RADIUS */
229
230#ifndef RETROGUI_CTL_LISTBOX_STR_SZ_MAX
231# define RETROGUI_CTL_LISTBOX_STR_SZ_MAX 255
232#endif /* !RETROGUI_CTL_LISTBOX_STR_SZ_MAX */
233
234#ifndef RETROGUI_CTL_TEXT_CUR_WH
235# define RETROGUI_CTL_TEXT_CUR_WH 8
236#endif /* !RETROGUI_CTL_LISTBOX_STR_SZ_MAX */
237
238#ifndef RETROGUI_DEBOUNCE_MAX_DEFAULT
239# define RETROGUI_DEBOUNCE_MAX_DEFAULT 100
240#endif /* !RETROGUI_DEBOUNCE_MAX_DEFAULT */
241 /* maug_retrogui_cfg */
243
248#define RETROGUI_FLAGS_DIRTY 0x01
249
255#define RETROGUI_FLAGS_FONT_OWNED 0x02
256
257#define RETROGUI_FILLBAR_FLAG_SHOWNUM 0x02
258
259#define _retrogui_copy_str( field, src_str, dest_ctl, str_tmp, str_sz ) \
260 /* Sanity checking. */ \
261 assert( NULL != src_str ); \
262 debug_printf( RETROGUI_TRACE_LVL, \
263 "copying string \"%s\" to " #dest_ctl, src_str ); \
264 if( 0 == str_sz ) { \
265 str_sz = maug_strlen( src_str ); \
266 debug_printf( RETROGUI_TRACE_LVL, \
267 "determined str sz of \"%s\": " SIZE_T_FMT, src_str, str_sz ); \
268 } \
269 if( (MAUG_MHANDLE)NULL != dest_ctl. field ## _h ) { \
270 /* Free the existing string. */ \
271 maug_mfree( dest_ctl. field ## _h ); \
272 } \
273 \
274 /* Allocate new string space. */ \
275 dest_ctl. field ## _h = maug_malloc( str_sz + 1, 1 ); \
276 debug_printf( RETROGUI_TRACE_LVL, \
277 "allocated str sz for \"%s\": " SIZE_T_FMT, src_str, str_sz + 1 ); \
278 maug_cleanup_if_null_alloc( MAUG_MHANDLE, dest_ctl. field ## _h ); \
279 maug_mlock( dest_ctl. field ## _h, str_tmp ); \
280 maug_cleanup_if_null_lock( char*, str_tmp ); \
281 \
282 /* Copy the string over. */ \
283 assert( NULL != str_tmp ); \
284 maug_mzero( str_tmp, str_sz + 1 ); \
285 debug_printf( RETROGUI_TRACE_LVL, \
286 "zeroed str sz for \"%s\": " SIZE_T_FMT, src_str, str_sz + 1 ); \
287 maug_strncpy( str_tmp, src_str, str_sz ); \
288 debug_printf( RETROGUI_TRACE_LVL, "copied str as: \"%s\"", str_tmp ); \
289 maug_munlock( dest_ctl. field ## _h, str_tmp );
290
292typedef int16_t retrogui_idc_t;
293
294#define RETROGUI_IDC_FMT "%d"
295
296#define RETROGUI_IDC_NONE -1
297
301#define RETROGUI_COLOR_BG 1
302
306#define RETROGUI_COLOR_FG 2
307
312#define RETROGUI_COLOR_SEL_BG 3
313
318#define RETROGUI_COLOR_SEL_FG 4
319
324
342/* TODO: USe MDATA_VECTOR for LISTBOX items. */
343#define RETROGUI_CTL_TABLE_BASE( f ) \
344 f( 0, NONE, void* none; ) \
345 f( 1, LISTBOX, struct MDATA_VECTOR list; size_t sel_idx; ) \
346 f( 2, BUTTON, MAUG_MHANDLE label_h; char* label; size_t label_sz; int16_t push_frames; uint8_t font_flags; ) \
347 f( 3, LABEL, MAUG_MHANDLE label_h; char* label; size_t label_sz; uint8_t font_flags; ) \
348 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; ) \
349 f( 5, FILLBAR, uint8_t flags; uint16_t cur; uint16_t max; )
350
351#ifdef RETROGUI_NO_TEXTBOX
352# define RETROGUI_CTL_TABLE( f ) RETROGUI_CTL_TABLE_BASE( f )
353#else
354# define RETROGUI_CTL_TABLE( f ) RETROGUI_CTL_TABLE_BASE( f ) \
355 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; )
356#endif /* RETROGUI_NO_TEXTBOX */
357
358#if 0
359 f( 6, SCROLLBAR, size_t min; size_t max; size_t value; )
360#endif
361
362#ifdef RETROGUI_NO_TEXTBOX
363# define retrogui_can_focus_ctl( ctl ) \
364 (RETROGUI_CTL_TYPE_BUTTON == (ctl)->base.type || \
365 RETROGUI_CTL_TYPE_LISTBOX == (ctl)->base.type)
366#else
370# define retrogui_can_focus_ctl( ctl ) \
371 (RETROGUI_CTL_TYPE_BUTTON == (ctl)->base.type || \
372 RETROGUI_CTL_TYPE_TEXTBOX == (ctl)->base.type || \
373 RETROGUI_CTL_TYPE_LISTBOX == (ctl)->base.type)
374#endif /* RETROGUI_NO_TEXTBOX */
375
378 uint8_t type;
379 retrogui_idc_t idc;
384 RETROFLAT_COLOR bg_color;
385 RETROFLAT_COLOR fg_color;
386 RETROFLAT_COLOR sel_fg;
387 RETROFLAT_COLOR sel_bg;
388#if defined( RETROGUI_NATIVE_WIN )
389 HWND hwnd;
390#endif
391};
392
397#define RETROGUI_CTL_TABLE_FIELDS( idx, c_name, c_fields ) \
398 struct RETROGUI_CTL_ ## c_name { \
399 struct RETROGUI_CTL_BASE base; \
400 c_fields \
401 };
402
403RETROGUI_CTL_TABLE( RETROGUI_CTL_TABLE_FIELDS )
404
405
409#define RETROGUI_CTL_TABLE_TYPES( idx, c_name, c_fields ) \
410 struct RETROGUI_CTL_ ## c_name c_name;
411
413 struct RETROGUI_CTL_BASE base;
414 RETROGUI_CTL_TABLE( RETROGUI_CTL_TABLE_TYPES )
415};
416 /* maug_retrogui_ctl */
418
419typedef void (*retrogui_xy_cb)(
420 retroflat_pxxy_t* x, retroflat_pxxy_t* y, void* data );
421
422typedef char retrogui_list_t[RETROGUI_CTL_LISTBOX_STR_SZ_MAX + 1];
423
424/*
425 * \note It is possible to have multiple GUI controllers in a program. For
426 * example, a web browser might have a controller for its address bar and
427 * a controller for form elements on pages.
428 *
429 */
430struct RETROGUI {
431 uint8_t flags;
436 RETROFLAT_COLOR bg_color;
437 retrogui_idc_t idc_prev;
438 struct MDATA_VECTOR ctls;
441 retroflat_blit_t* draw_bmp;
442 retroflat_ms_t debounce_next;
443 retroflat_ms_t debounce_max;
444#ifdef RETROGXC_PRESENT
445 ssize_t font_idx;
446#else
456 MAUG_MHANDLE font_h;
457#endif /* RETROGXC_PRESENT */
458};
459
460MERROR_RETVAL retrogui_push_listbox_item(
461 struct RETROGUI* gui, retrogui_idc_t idc, const char* item, size_t item_sz );
462
472 struct RETROGUI* gui, RETROFLAT_IN_KEY* p_input,
473 struct RETROFLAT_INPUT* input_evt );
474
475MERROR_RETVAL retrogui_redraw_ctls( struct RETROGUI* gui );
476
477MERROR_RETVAL retrogui_sz_ctl(
478 struct RETROGUI* gui, retrogui_idc_t idc,
480 retroflat_pxxy_t max_w, retroflat_pxxy_t max_h );
481
482MERROR_RETVAL retrogui_pos_ctl(
483 struct RETROGUI* gui, retrogui_idc_t idc,
486
487MERROR_RETVAL retrogui_push_ctl(
488 struct RETROGUI* gui, union RETROGUI_CTL* ctl );
489
498 struct RETROGUI* gui, const char* font_path );
499
500#ifndef RETROGUI_NO_TEXTBOX
501
502MERROR_RETVAL retrogui_get_ctl_text(
503 struct RETROGUI* gui, retrogui_idc_t idc, char* buffer, size_t buffer_sz );
504
505#endif /* !RETROGUI_NO_TEXTBOX */
506
507ssize_t retrogui_get_ctl_sel_idx( struct RETROGUI* gui, retrogui_idc_t idc );
508
509MERROR_RETVAL retrogui_set_ctl_color(
510 struct RETROGUI* gui, retrogui_idc_t idc, uint8_t color_key,
511 RETROFLAT_COLOR color_val );
512
513MERROR_RETVAL retrogui_set_ctl_text(
514 struct RETROGUI* gui, retrogui_idc_t idc, size_t buffer_sz,
515 const char* fmt, ... );
516
526 struct RETROGUI* gui, retrogui_idc_t idc, const char* path, uint8_t flags );
527
538 struct RETROGUI* gui, retrogui_idc_t idc, uint16_t level, uint16_t max,
539 uint8_t flags );
540
541MERROR_RETVAL retrogui_init_ctl(
542 union RETROGUI_CTL* ctl, uint8_t type, size_t idc );
543
556 struct RETROGUI* gui, size_t start, ssize_t incr );
557
571
581
593
594#define retrogui_focus_next( gui ) \
595 retrogui_focus_iter( gui, 0, 1 )
596
597#define retrogui_focus_prev( gui ) \
598 retrogui_focus_iter( gui, mdata_vector_ct( &((gui)->ctls) ) - 1, -1 )
599
600#ifdef RETROGUI_C
601
602#define RETROGUI_CTL_TABLE_CONSTS( idx, c_name, c_fields ) \
603 MAUG_CONST uint8_t SEG_MCONST RETROGUI_CTL_TYPE_ ## c_name = idx;
604
605RETROGUI_CTL_TABLE( RETROGUI_CTL_TABLE_CONSTS )
606
607#ifdef RETROGUI_TRACE_TOKENS
608
609#define RETROGUI_CTL_TABLE_NAMES( idx, c_name, f_fields ) \
610 #c_name,
611
612MAUG_CONST char* SEG_MCONST gc_retrogui_ctl_names[] = {
613 RETROGUI_CTL_TABLE( RETROGUI_CTL_TABLE_NAMES )
614 ""
615};
616
617#endif /* RETROGUI_TRACE_TOKENS */
618
619static union RETROGUI_CTL* _retrogui_get_ctl_by_idc(
620 struct RETROGUI* gui, size_t idc );
621
622/* === Control: NONE === */
623
624static retrogui_idc_t retrogui_click_NONE(
625 struct RETROGUI* gui,
626 union RETROGUI_CTL* ctl, RETROFLAT_IN_KEY* p_input,
627 struct RETROFLAT_INPUT* input_evt
628) {
629 retrogui_idc_t idc_out = RETROGUI_IDC_NONE;
630
631 return idc_out;
632}
633
634static retrogui_idc_t retrogui_key_NONE(
635 struct RETROGUI* gui, union RETROGUI_CTL* ctl, RETROFLAT_IN_KEY* p_input,
636 struct RETROFLAT_INPUT* input_evt
637) {
638 retrogui_idc_t idc_out = RETROGUI_IDC_NONE;
639
640 return idc_out;
641}
642
643void retrogui_redraw_NONE( struct RETROGUI* gui, union RETROGUI_CTL* ctl ) {
644}
645
646static MERROR_RETVAL retrogui_push_NONE( union RETROGUI_CTL* ctl ) {
647 MERROR_RETVAL retval = MERROR_GUI;
648
649 return retval;
650}
651
652static MERROR_RETVAL retrogui_sz_NONE(
653 struct RETROGUI* gui, union RETROGUI_CTL* ctl,
656) {
657 return MERROR_OK;
658}
659
660static MERROR_RETVAL retrogui_pos_NONE(
661 struct RETROGUI* gui, union RETROGUI_CTL* ctl,
664) {
665 return MERROR_OK;
666}
667
668static void retrogui_destroy_NONE( union RETROGUI_CTL* ctl ) {
669}
670
671static MERROR_RETVAL retrogui_init_NONE( union RETROGUI_CTL* ctl ) {
672 MERROR_RETVAL retval = MERROR_GUI;
673
674 return retval;
675}
676
677/* === Control: LISTBOX === */
678
679static retrogui_idc_t retrogui_click_LISTBOX(
680 struct RETROGUI* gui,
681 union RETROGUI_CTL* ctl, RETROFLAT_IN_KEY* p_input,
682 struct RETROFLAT_INPUT* input_evt
683) {
684 retrogui_idc_t idc_out = RETROGUI_IDC_NONE;
685 MERROR_RETVAL retval = MERROR_OK;
686 size_t i = 0;
687 retroflat_pxxy_t w = 0,
688 h = 0;
689 int autolock = 0;
690 char* list_i = NULL;
691
692# if defined( RETROGUI_NATIVE_WIN )
693 /* Do nothing. */
694# else
695
696 if( !mdata_vector_is_locked( &(ctl->LISTBOX.list) ) ) {
697 mdata_vector_lock( &(ctl->LISTBOX.list) );
698 autolock = 1;
699 }
700
701 /* Figure out the item clicked. */
702 while( i < mdata_vector_ct( &(ctl->LISTBOX.list) ) ) {
703 list_i =
704 (char*)mdata_vector_get( &(ctl->LISTBOX.list), i, retrogui_list_t );
705
706 /* TODO: Use retrogui_sz_LISTBOX() instead? */
707#ifdef RETROGXC_PRESENT
708 retrogxc_string_sz(
709 gui->draw_bmp, list_i, 0, gui->font_idx,
710 ctl->base.w, ctl->base.h, &w, &h, 0 );
711#else
712 retrofont_string_sz(
713 gui->draw_bmp, list_i, 0, gui->font_h,
714 ctl->base.w, ctl->base.h, &w, &h, 0 );
715#endif /* RETROGXC_PRESENT */
716
717 if(
718 (retroflat_pxxy_t)(input_evt->mouse_y) <
719 ctl->base.y + ((i + 1) * (h + RETROGUI_PADDING))
720 ) {
721 ctl->LISTBOX.sel_idx = i;
722 break;
723 }
724
725 i++;
726 }
727
728cleanup:
729
730 if( autolock ) {
731 mdata_vector_unlock( &(ctl->LISTBOX.list) );
732 }
733
734 if( MERROR_OK != retval ) {
735 idc_out = RETROGUI_IDC_NONE;
736 }
737
738#endif
739
740 return idc_out;
741}
742
743static retrogui_idc_t retrogui_key_LISTBOX(
744 struct RETROGUI* gui, union RETROGUI_CTL* ctl, RETROFLAT_IN_KEY* p_input,
745 struct RETROFLAT_INPUT* input_evt
746) {
747 retrogui_idc_t idc_out = RETROGUI_IDC_NONE;
748
749 switch( *p_input ) {
751 ctl->LISTBOX.sel_idx++;
752 if( ctl->LISTBOX.sel_idx >= mdata_vector_ct( &(ctl->LISTBOX.list) ) ) {
753 ctl->LISTBOX.sel_idx = 0;
754 }
755
756 /* Redraw and preempt further processing of input. */
757 gui->flags |= RETROGUI_FLAGS_DIRTY;
758 *p_input = 0;
759 break;
760
762 ctl->LISTBOX.sel_idx--;
763 /* sel_idx is unsigned, so overflow is always positive! */
764 if( ctl->LISTBOX.sel_idx >= mdata_vector_ct( &(ctl->LISTBOX.list) ) ) {
765 ctl->LISTBOX.sel_idx = mdata_vector_ct( &(ctl->LISTBOX.list) ) - 1;
766 }
767
768 /* Redraw and preempt further processing of input. */
769 gui->flags |= RETROGUI_FLAGS_DIRTY;
770 *p_input = 0;
771 break;
772 }
773
774 return idc_out;
775}
776
777static void retrogui_redraw_LISTBOX(
778 struct RETROGUI* gui, union RETROGUI_CTL* ctl
779) {
780 size_t i = 0;
781 retroflat_pxxy_t w = 0,
782 h = 0,
783 item_y = 0;
784 RETROFLAT_COLOR fg_color;
785 int autolock = 0;
786 char* list_i = NULL;
787 MERROR_RETVAL retval = MERROR_OK;
788
789# if defined( RETROGUI_NATIVE_WIN )
790 /* TODO: InvalidateRect()? */
791# else
792
793 if( !mdata_vector_is_locked( &(ctl->LISTBOX.list) ) ) {
794 mdata_vector_lock( &(ctl->LISTBOX.list) );
795 autolock = 1;
796 }
797
798 if( RETROFLAT_COLOR_BLACK != ctl->base.bg_color ) {
799 retroflat_2d_rect( gui->draw_bmp, ctl->base.bg_color,
800 gui->x + ctl->base.x, gui->y + ctl->base.y,
801 ctl->base.w, ctl->base.h, RETROFLAT_FLAGS_FILL );
802 }
803
804 while( i < mdata_vector_ct( &(ctl->LISTBOX.list) ) ) {
805 list_i =
806 (char*)mdata_vector_get( &(ctl->LISTBOX.list), i, retrogui_list_t );
807#ifdef RETROGXC_PRESENT
808 retrogxc_string_sz(
809 gui->draw_bmp, list_i, 0, gui->font_idx,
810 ctl->base.w, ctl->base.h, &w, &h, 0 );
811#else
812 retrofont_string_sz(
813 gui->draw_bmp, list_i, 0, gui->font_h,
814 ctl->base.w, ctl->base.h, &w, &h, 0 );
815#endif /* RETROGXC_PRESENT */
816#if RETROGUI_TRACE_LVL > 0
817 debug_printf( RETROGUI_TRACE_LVL,
818 "str height for \"%s\": " SIZE_T_FMT, list_i, h );
819#endif /* RETROGUI_TRACE_LVL */
820 if( i == ctl->LISTBOX.sel_idx ) {
821 /* Draw selection colors. */
822 retroflat_2d_rect( gui->draw_bmp, ctl->base.sel_bg,
823 gui->x + ctl->base.x,
824 gui->y + ctl->base.y + item_y,
825 ctl->base.w, h, RETROFLAT_FLAGS_FILL );
826 fg_color = ctl->base.sel_fg;
827
829 gui->draw_bmp, ctl->base.sel_fg,
830 gui->x + ctl->base.x,
831 gui->y + ctl->base.y + item_y,
832 RETROGUI_CTL_LISTBOX_CURSOR_RADIUS,
833 RETROGUI_CTL_LISTBOX_CURSOR_RADIUS, 0 );
834
835 } else {
836 fg_color = ctl->base.fg_color;
837 }
838
839#ifdef RETROGXC_PRESENT
840 retrogxc_string(
841 gui->draw_bmp, fg_color, list_i, 0, gui->font_idx,
842 gui->x + ctl->base.x +
843 RETROGUI_CTL_LISTBOX_CURSOR_RADIUS + RETROGUI_PADDING,
844 gui->y + ctl->base.y + item_y,
845 0, 0, 0 );
846#else
848 gui->draw_bmp, fg_color, list_i, 0, gui->font_h,
849 gui->x + ctl->base.x +
850 RETROGUI_CTL_LISTBOX_CURSOR_RADIUS + RETROGUI_PADDING,
851 gui->y + ctl->base.y + item_y,
852 0, 0, 0 );
853#endif /* RETROGXC_PRESENT */
854
855 i++;
856 /* Track the item height separately in case the item is multi-line. */
857 item_y += h + RETROGUI_PADDING;
858 }
859
860cleanup:
861
862 if( autolock ) {
863 mdata_vector_unlock( &(ctl->LISTBOX.list) );
864 }
865
866 assert( MERROR_OK == retval );
867
868# endif
869
870}
871
872MERROR_RETVAL retrogui_select_listbox_item(
873 union RETROGUI_CTL* ctl, size_t item_idx
874) {
875 MERROR_RETVAL retval = MERROR_OK;
876
877# if defined( RETROGUI_NATIVE_WIN )
878
879 /* Select sel_idx. */
880 SendMessage( ctl->base.hwnd, LB_SETCURSEL, item_idx, 0 );
881
882# else
883
884 ctl->LISTBOX.sel_idx = item_idx;
885
886# endif
887
888 return retval;
889}
890
891MERROR_RETVAL retrogui_push_listbox_item(
892 struct RETROGUI* gui, retrogui_idc_t idc, const char* item, size_t item_sz
893) {
894 MERROR_RETVAL retval = MERROR_OK;
895 union RETROGUI_CTL* ctl = NULL;
896 int autolock = 0;
897 retrogui_list_t item_stage;
898 ssize_t i = 0;
899
900 if( !mdata_vector_is_locked( &((gui)->ctls) ) ) {
901 mdata_vector_lock( &(gui->ctls) );
902 autolock = 1;
903 }
904
905#if RETROGUI_TRACE_LVL > 0
906 debug_printf( RETROGUI_TRACE_LVL,
907 "pushing item \"%s\" to listbox " RETROGUI_IDC_FMT "...", item, idc );
908#endif /* RETROGUI_TRACE_LVL */
909
910 ctl = _retrogui_get_ctl_by_idc( gui, idc );
911 if( NULL == ctl ) {
912 /* Elaborate on error from _retrogui_get_ctl_by_idc(). */
913 error_printf( "could not add item: %s", item );
914 retval = MERROR_GUI;
915 goto cleanup;
916 }
917
918# if defined( RETROGUI_NATIVE_WIN )
919
920 SendMessage( ctl->LISTBOX.base.hwnd, LB_ADDSTRING, 0, (LPARAM)item );
921
922# else
923
924 maug_mzero( item_stage, RETROGUI_CTL_LISTBOX_STR_SZ_MAX + 1 );
925 maug_strncpy( item_stage, item, RETROGUI_CTL_LISTBOX_STR_SZ_MAX );
926 i = mdata_vector_append(
927 &(ctl->LISTBOX.list), item_stage, RETROGUI_CTL_LISTBOX_STR_SZ_MAX + 1 );
928 if( 0 > i ) {
929 retval = merror_sz_to_retval( i );
930 }
931
932#endif
933
934 gui->flags |= RETROGUI_FLAGS_DIRTY;
935
936cleanup:
937
938 if( autolock ) {
939 mdata_vector_unlock( &(gui->ctls) );
940 }
941
942 return retval;
943}
944
945static MERROR_RETVAL retrogui_push_LISTBOX( union RETROGUI_CTL* ctl ) {
946 MERROR_RETVAL retval = MERROR_OK;
947
948# if defined( RETROGUI_NATIVE_WIN )
949
950 ctl->base.hwnd = CreateWindow(
951 "LISTBOX", NULL, WS_CHILD | WS_VISIBLE | LBS_STANDARD,
952 gui->x + ctl->base.x, gui->y + ctl->base.y, ctl->base.w, ctl->base.h,
953 g_retroflat_state->window, (HMENU)(ctl->base.idc),
954 g_retroflat_instance, NULL );
955#if RETROGUI_TRACE_LVL > 0
956 debug_printf( RETROGUI_TRACE_LVL,
957 "listbox hwnd: %p", ctl->LISTBOX.base.hwnd );
958#endif /* RETROGUI_TRACE_LVL */
959 if( (HWND)NULL == ctl->base.hwnd ) {
960 error_printf( "could not create listbox" );
961 retval = MERROR_GUI;
962 goto cleanup;
963 }
964
965 gui->flags |= RETROGUI_FLAGS_DIRTY;
966
967cleanup:
968
969# else
970
971 /* TODO? */
972
973# endif
974
975 return retval;
976}
977
978static MERROR_RETVAL retrogui_sz_LISTBOX(
979 struct RETROGUI* gui, union RETROGUI_CTL* ctl,
982) {
983 MERROR_RETVAL retval = MERROR_GUI;
984 /* TODO */
985 return retval;
986}
987
988static MERROR_RETVAL retrogui_pos_LISTBOX(
989 struct RETROGUI* gui, union RETROGUI_CTL* ctl,
992) {
993 MERROR_RETVAL retval = MERROR_GUI;
994 /* TODO */
995 return retval;
996}
997
998static void retrogui_destroy_LISTBOX( union RETROGUI_CTL* ctl ) {
999 mdata_vector_free( &(ctl->LISTBOX.list) );
1000}
1001
1002static MERROR_RETVAL retrogui_init_LISTBOX( union RETROGUI_CTL* ctl ) {
1003 MERROR_RETVAL retval = MERROR_OK;
1004
1005#if RETROGUI_TRACE_LVL > 0
1006 debug_printf( RETROGUI_TRACE_LVL,
1007 "initializing listbox " RETROGUI_IDC_FMT "...", ctl->base.idc );
1008#endif /* RETROGUI_IDC_FMT */
1009
1010 ctl->base.bg_color = RETROFLAT_COLOR_WHITE;
1011 ctl->base.sel_fg = RETROFLAT_COLOR_WHITE;
1012 if( 2 < retroflat_screen_colors() ) {
1013 ctl->base.sel_bg = RETROFLAT_COLOR_BLUE;
1014 ctl->base.fg_color = RETROGUI_COLOR_BORDER;
1015 } else {
1016 ctl->base.sel_bg = RETROFLAT_COLOR_BLACK;
1017 ctl->base.fg_color = RETROFLAT_COLOR_BLACK;
1018 }
1019
1020 return retval;
1021}
1022
1023/* === Control: BUTTON === */
1024
1025static retrogui_idc_t retrogui_click_BUTTON(
1026 struct RETROGUI* gui,
1027 union RETROGUI_CTL* ctl, RETROFLAT_IN_KEY* p_input,
1028 struct RETROFLAT_INPUT* input_evt
1029) {
1030 retrogui_idc_t idc_out = RETROGUI_IDC_NONE;
1031
1032 if( 0 < ctl->BUTTON.push_frames ) {
1033 goto cleanup;
1034 }
1035
1036 /* Set the last button clicked. */
1037 idc_out = ctl->base.idc;
1038
1039 /* Set the frames to show the pushed-in view. */
1040 /* TODO: Use a constant, here. */
1041 ctl->BUTTON.push_frames = 3;
1042
1043cleanup:
1044
1045 return idc_out;
1046}
1047
1048static retrogui_idc_t retrogui_key_BUTTON(
1049 struct RETROGUI* gui, union RETROGUI_CTL* ctl, RETROFLAT_IN_KEY* p_input,
1050 struct RETROFLAT_INPUT* input_evt
1051) {
1052 retrogui_idc_t idc_out = RETROGUI_IDC_NONE;
1053
1054 /* Set the last button clicked. */
1055 /* TODO: Only set out on ENTER/SPACE. */
1056 /* idc_out = ctl->base.idc; */
1057
1058 return idc_out;
1059}
1060
1061static void retrogui_redraw_BUTTON(
1062 struct RETROGUI* gui, union RETROGUI_CTL* ctl
1063) {
1064 retroflat_pxxy_t w = 0,
1065 h = 0,
1066 text_offset = 0;
1067 RETROFLAT_COLOR fg_color = ctl->base.fg_color;
1068 RETROFLAT_COLOR bg_color = ctl->base.bg_color;
1069 RETROFLAT_COLOR push_shadow_color = RETROFLAT_COLOR_DARKGRAY;
1071
1072 if( ctl->base.idc == gui->focus ) {
1073 /* Assign selected color if focused. */
1074 fg_color = ctl->base.sel_fg;
1075 }
1076
1077 if( ctl->base.idc == gui->focus ) {
1078 /* Assign selected color if focused. */
1079 bg_color = ctl->base.sel_bg;
1080 }
1081
1082 /* Figure out push shadow color for current color depth. */
1083 if( 2 >= retroflat_screen_colors() ) {
1084 push_shadow_color = RETROFLAT_COLOR_BLACK;
1085 border_color = RETROFLAT_COLOR_BLACK;
1086 }
1087
1088 retroflat_2d_rect(
1089 gui->draw_bmp, bg_color, ctl->base.x, ctl->base.y,
1090 ctl->base.w, ctl->base.h, RETROFLAT_FLAGS_FILL );
1091
1092 retroflat_2d_rect( gui->draw_bmp, border_color,
1093 gui->x + ctl->base.x, gui->y + ctl->base.y,
1094 ctl->base.w, ctl->base.h, 0 );
1095
1096 /* Draw the push shadows on top/left or bottom/right, depending on pushed
1097 * status.
1098 */
1099 if( 0 < ctl->BUTTON.push_frames ) {
1100 retroflat_2d_line(
1101 gui->draw_bmp, push_shadow_color,
1102 gui->x + ctl->base.x + 1, gui->y + ctl->base.y + 1,
1103 gui->x + ctl->base.x + ctl->base.w - 2, gui->y + ctl->base.y + 1, 0 );
1104 retroflat_2d_line(
1105 gui->draw_bmp, push_shadow_color,
1106 gui->x + ctl->base.x + 1, gui->y + ctl->base.y + 2,
1107 gui->x + ctl->base.x + 1, gui->y + ctl->base.y + ctl->base.h - 3, 0 );
1108
1109 gui->flags |= RETROGUI_FLAGS_DIRTY; /* Mark dirty for push animation. */
1110 ctl->BUTTON.push_frames--;
1111 text_offset = 1;
1112 } else {
1113 /* Button is not pushed. */
1114 retroflat_2d_line(
1115 gui->draw_bmp, RETROFLAT_COLOR_WHITE,
1116 gui->x + ctl->base.x + 1, gui->y + ctl->base.y + 1,
1117 gui->x + ctl->base.x + ctl->base.w - 2, gui->y + ctl->base.y + 1, 0 );
1118 retroflat_2d_line(
1119 gui->draw_bmp, RETROFLAT_COLOR_WHITE,
1120 gui->x + ctl->base.x + 1, gui->y + ctl->base.y + 2,
1121 gui->x + ctl->base.x + 1, gui->y + ctl->base.y + ctl->base.h - 3, 0 );
1122 }
1123
1124 maug_mlock( ctl->BUTTON.label_h, ctl->BUTTON.label );
1125 if( NULL == ctl->BUTTON.label ) {
1126 error_printf( "could not lock BUTTON label!" );
1127 goto cleanup;
1128 }
1129
1130 /* Grab the string size and use it to center the text in the control. */
1131#ifdef RETROGXC_PRESENT
1132 retrogxc_string_sz(
1133#else
1134 retrofont_string_sz(
1135#endif /* RETROGXC_PRESENT */
1136 gui->draw_bmp, ctl->BUTTON.label, 0,
1137#ifdef RETROGXC_PRESENT
1138 gui->font_idx,
1139#else
1140 gui->font_h,
1141#endif /* RETROGXC_PRESENT */
1142 /* TODO: Pad max client area. */
1143 ctl->base.w, ctl->base.h, &w, &h, ctl->BUTTON.font_flags );
1144
1145#ifdef RETROGXC_PRESENT
1146 retrogxc_string(
1147#else
1149#endif /* RETROGXC_PRESENT */
1150 gui->draw_bmp, fg_color, ctl->BUTTON.label, 0,
1151#ifdef RETROGXC_PRESENT
1152 gui->font_idx,
1153#else
1154 gui->font_h,
1155#endif /* RETROGXC_PRESENT */
1156 gui->x + ctl->base.x + ((ctl->base.w >> 1) - (w >> 1)) + text_offset,
1157 gui->y + ctl->base.y + ((ctl->base.h >> 1) - (h >> 1)) + text_offset,
1158 /* TODO: Pad max client area. */
1159 ctl->base.w, ctl->base.h, ctl->BUTTON.font_flags );
1160
1161 maug_munlock( ctl->BUTTON.label_h, ctl->BUTTON.label );
1162
1163cleanup:
1164
1165 return;
1166}
1167
1168static MERROR_RETVAL retrogui_push_BUTTON( union RETROGUI_CTL* ctl ) {
1169 MERROR_RETVAL retval = MERROR_OK;
1170
1171# if defined( RETROGUI_NATIVE_WIN )
1172
1173 ctl->base.hwnd = CreateWindow(
1174 "BUTTON", ctl->BUTTON.label, WS_CHILD | WS_VISIBLE | BS_DEFPUSHBUTTON,
1175 gui->x + ctl->base.x, gui->y + ctl->base.y, ctl->base.w, ctl->base.h,
1176 g_retroflat_state->window, (HMENU)(ctl->base.idc),
1177 g_retroflat_instance, NULL );
1178 if( (HWND)NULL == ctl->base.hwnd ) {
1180 "Could not create button " RETROGUI_IDC_FMT ": %s",
1181 ctl->base.idc, ctl->BUTTON.label );
1182 retval = MERROR_GUI;
1183 goto cleanup;
1184 }
1185
1186# else
1187 size_t label_sz = 0;
1188 char* label_tmp = NULL;
1189
1190#if RETROGUI_TRACE_LVL > 0
1191 debug_printf( RETROGUI_TRACE_LVL, "pushing BUTTON control..." );
1192#endif /* RETROGUI_TRACE_LVL */
1193
1194 _retrogui_copy_str(
1195 label, ctl->BUTTON.label, ctl->BUTTON, label_tmp, label_sz );
1196 ctl->BUTTON.label = NULL;
1197# endif
1198
1199cleanup:
1200
1201 return retval;
1202}
1203
1204static MERROR_RETVAL retrogui_sz_BUTTON(
1205 struct RETROGUI* gui, union RETROGUI_CTL* ctl,
1208) {
1209 MERROR_RETVAL retval = MERROR_OK;
1210
1211 assert( NULL != ctl );
1212 assert( NULL == ctl->BUTTON.label );
1213 assert( (MAUG_MHANDLE)NULL != ctl->BUTTON.label_h );
1214
1215 maug_mlock( ctl->BUTTON.label_h, ctl->BUTTON.label );
1216 maug_cleanup_if_null_lock( char*, ctl->BUTTON.label );
1217
1218 /* Get the size of the text-based GUI item. */
1219#ifdef RETROGXC_PRESENT
1220 retrogxc_string_sz(
1221#else
1222 retrofont_string_sz(
1223#endif /* RETROGXC_PRESENT */
1224 NULL,
1225 ctl->BUTTON.label,
1226 0,
1227#ifdef RETROGXC_PRESENT
1228 gui->font_idx,
1229#else
1230 gui->font_h,
1231#endif /* RETROGXC_PRESENT */
1232 max_w - 8,
1233 max_h - 8,
1234 p_w,
1235 p_h, ctl->BUTTON.font_flags );
1236
1237 /* Add space for borders and stuff. */
1238 *p_w += RETROGUI_BTN_LBL_PADDED_X;
1239 *p_h += RETROGUI_BTN_LBL_PADDED_Y;
1240
1241cleanup:
1242
1243 maug_munlock( ctl->BUTTON.label_h, ctl->BUTTON.label );
1244
1245 return retval;
1246}
1247
1248static MERROR_RETVAL retrogui_pos_BUTTON(
1249 struct RETROGUI* gui, union RETROGUI_CTL* ctl,
1252) {
1253 MERROR_RETVAL retval = MERROR_OK;
1254
1255# if defined( RETROGUI_NATIVE_WIN )
1256 /* TODO */
1257# else
1258 assert( NULL != ctl );
1259
1260 ctl->base.x = x;
1261 ctl->base.y = y;
1262 if( 0 < w ) {
1263 ctl->base.w = w;
1264 }
1265 if( 0 < h ) {
1266 ctl->base.h = h;
1267 }
1268# endif /* RETROGUI_NATIVE_WIN */
1269
1270 return retval;
1271}
1272
1273static void retrogui_destroy_BUTTON( union RETROGUI_CTL* ctl ) {
1274 if( (MAUG_MHANDLE)NULL != ctl->BUTTON.label_h ) {
1275 maug_mfree( ctl->BUTTON.label_h );
1276 }
1277}
1278
1279static MERROR_RETVAL retrogui_init_BUTTON( union RETROGUI_CTL* ctl ) {
1280 MERROR_RETVAL retval = MERROR_OK;
1281
1282#if RETROGUI_TRACE_LVL > 0
1283 debug_printf( RETROGUI_TRACE_LVL,
1284 "initializing button " RETROGUI_IDC_FMT "...", ctl->base.idc );
1285#endif /* RETROGUI_TRACE_LVL */
1286
1287 if( 2 < retroflat_screen_colors() ) {
1288 ctl->base.fg_color = RETROGUI_COLOR_BORDER;
1289 ctl->base.bg_color = RETROFLAT_COLOR_GRAY;
1290 ctl->base.sel_fg = RETROFLAT_COLOR_BLUE;
1291 ctl->base.sel_bg = RETROFLAT_COLOR_GRAY;
1292 } else {
1293 ctl->base.fg_color = RETROFLAT_COLOR_BLACK;
1294 ctl->base.bg_color = RETROFLAT_COLOR_WHITE;
1295 ctl->base.sel_fg = RETROFLAT_COLOR_WHITE;
1296 ctl->base.sel_bg = RETROFLAT_COLOR_BLACK;
1297 }
1298
1299 return retval;
1300}
1301
1302#ifndef RETROGUI_NO_TEXTBOX
1303
1304/* === Control: TEXTBOX === */
1305
1306static retrogui_idc_t retrogui_click_TEXTBOX(
1307 struct RETROGUI* gui,
1308 union RETROGUI_CTL* ctl, RETROFLAT_IN_KEY* p_input,
1309 struct RETROFLAT_INPUT* input_evt
1310) {
1311 retrogui_idc_t idc_out = RETROGUI_IDC_NONE;
1312
1313 return idc_out;
1314}
1315
1316static retrogui_idc_t retrogui_key_TEXTBOX(
1317 struct RETROGUI* gui, union RETROGUI_CTL* ctl, RETROFLAT_IN_KEY* p_input,
1318 struct RETROFLAT_INPUT* input_evt
1319) {
1320 retrogui_idc_t idc_out = RETROGUI_IDC_NONE;
1321 char c = '\0';
1322
1323# if defined( RETROGUI_NATIVE_WIN )
1324 /* Do nothing. */
1325# else
1326
1327 c = retroflat_vk_to_ascii( *p_input, input_evt->key_flags );
1328
1329 /* Ignore non-printable characters. */
1330 if(
1331 0 == c &&
1332 RETROFLAT_KEY_RIGHT != *p_input &&
1333 RETROFLAT_KEY_LEFT != *p_input
1334 ) {
1335 goto cleanup;
1336 }
1337
1338 /* Lock text field. */
1339 assert( NULL == ctl->TEXTBOX.text );
1340 assert( (MAUG_MHANDLE)NULL != ctl->TEXTBOX.text_h );
1341 maug_mlock( ctl->TEXTBOX.text_h, ctl->TEXTBOX.text );
1342 if( NULL == ctl->TEXTBOX.text ) {
1343 error_printf( "could not lock TEXTBOX text handle!" );
1344 goto cleanup;
1345 }
1346
1347 switch( *p_input ) {
1348 case RETROFLAT_KEY_BKSP:
1350 ctl->TEXTBOX.text, ctl->TEXTBOX.text_cur, ctl->TEXTBOX.text_sz )
1351 break;
1352
1353 case RETROFLAT_KEY_ENTER:
1354 idc_out = ctl->base.idc;
1355 break;
1356
1357 case RETROFLAT_KEY_LEFT:
1358 if( 0 < ctl->TEXTBOX.text_cur ) {
1359 ctl->TEXTBOX.text_cur--;
1360 }
1361 break;
1362
1363 case RETROFLAT_KEY_RIGHT:
1364 if( ctl->TEXTBOX.text_sz > ctl->TEXTBOX.text_cur ) {
1365 ctl->TEXTBOX.text_cur++;
1366 }
1367 break;
1368
1369 default:
1370 assert( ctl->TEXTBOX.text_sz < ctl->TEXTBOX.text_sz_max );
1372 ctl->TEXTBOX.text,
1373 ctl->TEXTBOX.text_cur,
1374 ctl->TEXTBOX.text_sz,
1375 ctl->TEXTBOX.text_sz_max );
1376 break;
1377 }
1378
1379 /* TODO: Remove input from queue? */
1380
1381cleanup:
1382
1383 if( NULL != ctl->TEXTBOX.text ) {
1384 maug_munlock( ctl->TEXTBOX.text_h, ctl->TEXTBOX.text );
1385 }
1386
1387# endif
1388
1389 return idc_out;
1390}
1391
1392static void retrogui_redraw_TEXTBOX(
1393 struct RETROGUI* gui, union RETROGUI_CTL* ctl
1394) {
1395 RETROFLAT_COLOR shadow_color = RETROFLAT_COLOR_DARKGRAY;
1397 retroflat_pxxy_t cursor_x = 0,
1398 cursor_y = 0;
1399
1400 /* Adjust shadow colors for monochrome. */
1401 if( 2 >= retroflat_screen_colors() ) {
1402 shadow_color = RETROFLAT_COLOR_BLACK;
1403 border_color = RETROFLAT_COLOR_BLACK;
1404 }
1405
1406# if defined( RETROGUI_NATIVE_WIN )
1407 /* Do nothing. */
1408# else
1409
1410 retroflat_2d_rect( gui->draw_bmp, ctl->base.bg_color,
1411 gui->x + ctl->base.x, gui->y + ctl->base.y,
1412 ctl->base.w, ctl->base.h, RETROFLAT_FLAGS_FILL );
1413
1414 /* Draw chiselled inset border. */
1415
1416 retroflat_2d_rect( gui->draw_bmp, border_color,
1417 gui->x + ctl->base.x,
1418 gui->y + ctl->base.y, ctl->base.w, 2,
1420
1421 retroflat_2d_rect( gui->draw_bmp, border_color,
1422 gui->x + ctl->base.x,
1423 gui->y + ctl->base.y, 2, ctl->base.h,
1425
1426 retroflat_2d_rect( gui->draw_bmp, shadow_color,
1427 gui->x + ctl->base.x,
1428 gui->y + ctl->base.y + ctl->base.h - 1,
1429 ctl->base.w, 2,
1431
1432 retroflat_2d_rect( gui->draw_bmp, shadow_color,
1433 gui->x + ctl->base.x + ctl->base.w - 1,
1434 gui->y + ctl->base.y, 2, ctl->base.h,
1436
1437 /* Draw text. */
1438
1439 assert( NULL == ctl->TEXTBOX.text );
1440 maug_mlock( ctl->TEXTBOX.text_h, ctl->TEXTBOX.text );
1441 if( NULL == ctl->TEXTBOX.text ) {
1442 goto cleanup;
1443 }
1444
1445#ifdef RETROGXC_PRESENT
1446 retrogxc_string(
1447 gui->draw_bmp, ctl->base.fg_color,
1448 ctl->TEXTBOX.text, ctl->TEXTBOX.text_cur, gui->font_idx,
1449 gui->x + ctl->base.x + RETROGUI_PADDING,
1450 gui->y + ctl->base.y + RETROGUI_PADDING, ctl->base.w, ctl->base.h, 0 );
1451
1452 /* Get the line size for cursor placement below. */
1453 retrogxc_string_sz(
1454 gui->draw_bmp, ctl->TEXTBOX.text, ctl->TEXTBOX.text_cur, gui->font_idx,
1455 ctl->base.w, ctl->base.h, &cursor_x, &cursor_y, RETROFONT_FLAG_SZ_MIN );
1456#else
1458 gui->draw_bmp, ctl->base.fg_color,
1459 ctl->TEXTBOX.text, ctl->TEXTBOX.text_cur, gui->font_h,
1460 gui->x + ctl->base.x + RETROGUI_PADDING,
1461 gui->y + ctl->base.y + RETROGUI_PADDING, ctl->base.w, ctl->base.h, 0 );
1462
1463 /* Get the line size for cursor placement below. */
1464 retrofont_string_sz(
1465 gui->draw_bmp, ctl->TEXTBOX.text, ctl->TEXTBOX.text_cur, gui->font_h,
1466 ctl->base.w, ctl->base.h, &cursor_x, &cursor_y, RETROFONT_FLAG_SZ_MIN );
1467#endif /* RETROGXC_PRESENT */
1468
1469cleanup:
1470
1471 if( cursor_x + RETROGUI_CTL_TEXT_CUR_WH >= ctl->base.w ) {
1472 cursor_x = 0;
1473 /* TODO: Use font height. */
1474 cursor_y += RETROGUI_CTL_TEXT_CUR_WH;
1475 }
1476
1477 /* Use same padding as font for cursor. */
1478 retroflat_2d_rect( gui->draw_bmp,
1479 ctl->base.sel_fg,
1480 gui->x + ctl->base.x + RETROGUI_PADDING + cursor_x,
1481 gui->y + ctl->base.y + RETROGUI_PADDING + cursor_y,
1482 RETROGUI_CTL_TEXT_CUR_WH, RETROGUI_CTL_TEXT_CUR_WH,
1483 /* Draw blinking cursor. */
1484 /* TODO: Use a global timer to mark this field dirty. */
1485 gui->focus == ctl->base.idc &&
1486 0 < ctl->TEXTBOX.blink_frames ? RETROFLAT_FLAGS_FILL : 0 );
1487
1488 if( (-1 * RETROGUI_CTL_TEXT_BLINK_FRAMES) > --(ctl->TEXTBOX.blink_frames) ) {
1489 ctl->TEXTBOX.blink_frames = RETROGUI_CTL_TEXT_BLINK_FRAMES;
1490 }
1491
1492 if( NULL != ctl->TEXTBOX.text ) {
1493 /* Draw the text that comes after the cursor. */
1494 #ifdef RETROGXC_PRESENT
1495 retrogxc_string_indent(
1496 gui->draw_bmp, ctl->base.fg_color,
1497 &(ctl->TEXTBOX.text[ctl->TEXTBOX.text_cur]),
1498 /* Chop off chars from first half. */
1499 strlen( ctl->TEXTBOX.text ) - ctl->TEXTBOX.text_cur,
1500 gui->font_idx,
1501 gui->x + ctl->base.x + RETROGUI_PADDING,
1502 /* Post-cursor line beings on cursor line. */
1503 gui->y + ctl->base.y + RETROGUI_PADDING + cursor_y,
1504 ctl->base.w, ctl->base.h,
1505 cursor_x + RETROGUI_CTL_TEXT_CUR_WH, 0 );
1506#else
1507 retrofont_string_indent(
1508 gui->draw_bmp, ctl->base.fg_color,
1509 &(ctl->TEXTBOX.text[ctl->TEXTBOX.text_cur]),
1510 /* Chop off chars from first half. */
1511 strlen( ctl->TEXTBOX.text ) - ctl->TEXTBOX.text_cur,
1512 gui->font_h,
1513 gui->x + ctl->base.x + RETROGUI_PADDING,
1514 /* Post-cursor line beings on cursor line. */
1515 gui->y + ctl->base.y + RETROGUI_PADDING + cursor_y,
1516 ctl->base.w, ctl->base.h,
1517 cursor_x + RETROGUI_CTL_TEXT_CUR_WH, 0 );
1518#endif /* RETROGXC_PRESENT */
1519
1520 maug_munlock( ctl->TEXTBOX.text_h, ctl->TEXTBOX.text );
1521 }
1522
1523 gui->flags |= RETROGUI_FLAGS_DIRTY; /* Mark dirty for blink animation. */
1524
1525# endif
1526
1527 return;
1528}
1529
1530static MERROR_RETVAL retrogui_push_TEXTBOX( union RETROGUI_CTL* ctl ) {
1531 MERROR_RETVAL retval = MERROR_OK;
1532
1533# if defined( RETROGUI_NATIVE_WIN )
1534
1535 ctl->base.hwnd = CreateWindow(
1536 "EDIT", 0, WS_CHILD | WS_VISIBLE | WS_BORDER,
1537 gui->x + ctl->base.x, gui->y + ctl->base.y, ctl->base.w, ctl->base.h,
1538 g_retroflat_state->window, (HMENU)(ctl->base.idc),
1539 g_retroflat_instance, NULL );
1540 if( (HWND)NULL == ctl->base.hwnd ) {
1542 "Could not create textbox: " RETROGUI_IDC_FMT, ctl->base.idc );
1543 retval = MERROR_GUI;
1544 goto cleanup;
1545 }
1546
1547# else
1548
1549#if RETROGUI_TRACE_LVL > 0
1550 debug_printf( RETROGUI_TRACE_LVL,
1551 "clearing textbox " RETROGUI_IDC_FMT " buffer...", ctl->base.idc );
1552#endif /* RETROGUI_TRACE_LVL */
1553 assert( (MAUG_MHANDLE)NULL == ctl->TEXTBOX.text_h );
1554 ctl->TEXTBOX.text_h = maug_malloc( RETROGUI_CTL_TEXT_SZ_MAX + 1, 1 );
1555 maug_cleanup_if_null_alloc( MAUG_MHANDLE, ctl->TEXTBOX.text_h );
1556 ctl->TEXTBOX.text_sz_max = RETROGUI_CTL_TEXT_SZ_MAX;
1557
1558 maug_mlock( ctl->TEXTBOX.text_h, ctl->TEXTBOX.text );
1559 maug_cleanup_if_null_alloc( char*, ctl->TEXTBOX.text );
1560#if RETROGUI_TRACE_LVL > 0
1561 debug_printf( RETROGUI_TRACE_LVL,
1562 "clearing textbox " RETROGUI_IDC_FMT " buffer...", ctl->base.idc );
1563#endif /* RETROGUI_TRACE_LVL */
1564 maug_mzero( ctl->TEXTBOX.text, RETROGUI_CTL_TEXT_SZ_MAX + 1 );
1565 maug_munlock( ctl->TEXTBOX.text_h, ctl->TEXTBOX.text );
1566
1567# endif
1568
1569cleanup:
1570
1571 return retval;
1572}
1573
1574static MERROR_RETVAL retrogui_sz_TEXTBOX(
1575 struct RETROGUI* gui, union RETROGUI_CTL* ctl,
1578) {
1579 MERROR_RETVAL retval = MERROR_GUI;
1580 /* TODO */
1581 return retval;
1582}
1583
1584static MERROR_RETVAL retrogui_pos_TEXTBOX(
1585 struct RETROGUI* gui, union RETROGUI_CTL* ctl,
1588) {
1589 MERROR_RETVAL retval = MERROR_GUI;
1590 /* TODO */
1591 return retval;
1592}
1593
1594static void retrogui_destroy_TEXTBOX( union RETROGUI_CTL* ctl ) {
1595 if( (MAUG_MHANDLE)NULL != ctl->TEXTBOX.text_h ) {
1596 maug_mfree( ctl->TEXTBOX.text_h );
1597 }
1598}
1599
1600static MERROR_RETVAL retrogui_init_TEXTBOX( union RETROGUI_CTL* ctl ) {
1601 MERROR_RETVAL retval = MERROR_OK;
1602
1603#if RETROGUI_TRACE_LVL > 0
1604 debug_printf( RETROGUI_TRACE_LVL,
1605 "initializing textbox " RETROGUI_IDC_FMT "...", ctl->base.idc );
1606#endif /* RETROGUI_TRACE_LVL */
1607
1608 ctl->base.bg_color = RETROFLAT_COLOR_WHITE;
1609 ctl->base.sel_bg = RETROFLAT_COLOR_WHITE;
1610 if( 2 < retroflat_screen_colors() ) {
1611 ctl->base.sel_fg = RETROFLAT_COLOR_BLUE;
1612 ctl->base.fg_color = RETROGUI_COLOR_BORDER;
1613 } else {
1614 ctl->base.sel_fg = RETROFLAT_COLOR_BLACK;
1615 ctl->base.fg_color = RETROFLAT_COLOR_BLACK;
1616 }
1617
1618 return retval;
1619}
1620
1621#endif /* RETROGUI_NO_TEXTBOX */
1622
1623/* === Control: LABEL === */
1624
1625static retrogui_idc_t retrogui_click_LABEL(
1626 struct RETROGUI* gui,
1627 union RETROGUI_CTL* ctl, RETROFLAT_IN_KEY* p_input,
1628 struct RETROFLAT_INPUT* input_evt
1629) {
1630 return RETROGUI_IDC_NONE;
1631}
1632
1633static retrogui_idc_t retrogui_key_LABEL(
1634 struct RETROGUI* gui, union RETROGUI_CTL* ctl, RETROFLAT_IN_KEY* p_input,
1635 struct RETROFLAT_INPUT* input_evt
1636) {
1637 return RETROGUI_IDC_NONE;
1638}
1639
1640static void retrogui_redraw_LABEL(
1641 struct RETROGUI* gui, union RETROGUI_CTL* ctl
1642) {
1643
1644# if defined( RETROGUI_NATIVE_WIN )
1645 /* Do nothing. */
1646# else
1647
1648 /* Draw text. */
1649
1650#ifdef RETROGXC_PRESENT
1651 assert( 0 <= gui->font_idx );
1652#else
1653 assert( (MAUG_MHANDLE)NULL != gui->font_h );
1654#endif /* RETROGXC_PRESENT */
1655
1656 assert( NULL == ctl->LABEL.label );
1657 maug_mlock( ctl->LABEL.label_h, ctl->LABEL.label );
1658 if( NULL == ctl->LABEL.label ) {
1659 error_printf( "could not lock LABEL text!" );
1660 goto cleanup;
1661 }
1662
1663#ifdef RETROGXC_PRESENT
1664 retrogxc_string(
1665#else
1667#endif /* RETROGXC_PRESENT */
1668 gui->draw_bmp, ctl->base.fg_color, ctl->LABEL.label,
1669 ctl->LABEL.label_sz,
1670#ifdef RETROGXC_PRESENT
1671 gui->font_idx,
1672#else
1673 gui->font_h,
1674#endif /* RETROGXC_PRESENT */
1675 gui->x + ctl->base.x + RETROGUI_PADDING,
1676 gui->y + ctl->base.y + RETROGUI_PADDING, ctl->base.w, ctl->base.h,
1677 ctl->LABEL.font_flags );
1678
1679cleanup:
1680
1681 if( NULL != ctl->LABEL.label ) {
1682 maug_munlock( ctl->LABEL.label_h, ctl->LABEL.label );
1683 }
1684
1685# endif
1686
1687 return;
1688}
1689
1690static MERROR_RETVAL retrogui_push_LABEL( union RETROGUI_CTL* ctl ) {
1691 MERROR_RETVAL retval = MERROR_OK;
1692
1693# if defined( RETROGUI_NATIVE_WIN )
1694
1695 /* TODO */
1696
1697# else
1698 size_t label_sz = 0;
1699 char* label_tmp = NULL;
1700
1701#if RETROGUI_TRACE_LVL > 0
1702 debug_printf( RETROGUI_TRACE_LVL, "pushing LABEL control..." );
1703#endif /* RETROGUI_TRACE_LVL */
1704
1705 _retrogui_copy_str(
1706 label, ctl->LABEL.label, ctl->LABEL, label_tmp, label_sz );
1707 ctl->LABEL.label = NULL;
1708# endif
1709
1710cleanup:
1711
1712 return retval;
1713}
1714
1715static MERROR_RETVAL retrogui_sz_LABEL(
1716 struct RETROGUI* gui, union RETROGUI_CTL* ctl,
1719) {
1720 MERROR_RETVAL retval = MERROR_GUI;
1721 /* TODO */
1722 return retval;
1723}
1724
1725static MERROR_RETVAL retrogui_pos_LABEL(
1726 struct RETROGUI* gui, union RETROGUI_CTL* ctl,
1729) {
1730 MERROR_RETVAL retval = MERROR_GUI;
1731 /* TODO */
1732 return retval;
1733}
1734
1735static void retrogui_destroy_LABEL( union RETROGUI_CTL* ctl ) {
1736 if( (MAUG_MHANDLE)NULL != ctl->LABEL.label_h ) {
1737 maug_mfree( ctl->LABEL.label_h );
1738 }
1739}
1740
1741static MERROR_RETVAL retrogui_init_LABEL( union RETROGUI_CTL* ctl ) {
1742 MERROR_RETVAL retval = MERROR_OK;
1743
1744#if RETROGUI_TRACE_LVL > 0
1745 debug_printf( RETROGUI_TRACE_LVL,
1746 "initializing label " RETROGUI_IDC_FMT "...", ctl->base.idc );
1747#endif /* RETROGUI_TRACE_LVL */
1748
1749 if( 2 < retroflat_screen_colors() ) {
1750 ctl->base.fg_color = RETROGUI_COLOR_BORDER;
1751 } else {
1752 ctl->base.fg_color = RETROFLAT_COLOR_BLACK;
1753 }
1754 ctl->base.bg_color = RETROFLAT_COLOR_WHITE;
1755
1756 return retval;
1757}
1758
1759/* === Control: IMAGE === */
1760
1761static retrogui_idc_t retrogui_click_IMAGE(
1762 struct RETROGUI* gui,
1763 union RETROGUI_CTL* ctl, RETROFLAT_IN_KEY* p_input,
1764 struct RETROFLAT_INPUT* input_evt
1765) {
1766 return RETROGUI_IDC_NONE;
1767}
1768
1769static retrogui_idc_t retrogui_key_IMAGE(
1770 struct RETROGUI* gui, union RETROGUI_CTL* ctl, RETROFLAT_IN_KEY* p_input,
1771 struct RETROFLAT_INPUT* input_evt
1772) {
1773 return RETROGUI_IDC_NONE;
1774}
1775
1776static void retrogui_redraw_IMAGE(
1777 struct RETROGUI* gui, union RETROGUI_CTL* ctl
1778) {
1779# if defined( RETROGUI_NATIVE_WIN )
1780 /* Do nothing. */
1781# else
1782
1783# if defined( RETROGXC_PRESENT )
1784 if( 0 > ctl->IMAGE.image_cache_id ) {
1785 return;
1786 }
1787#if RETROGUI_TRACE_LVL > 0
1788 debug_printf( RETROGUI_TRACE_LVL,
1789 "redrawing image ctl " RETROGUI_IDC_FMT ", cache ID " SSIZE_T_FMT "...",
1790 ctl->base.idc, ctl->IMAGE.image_cache_id );
1791#endif /* RETROGUI_TRACE_LVL */
1792 retrogxc_blit_bitmap(
1793 gui->draw_bmp,
1794 ctl->IMAGE.image_cache_id,
1795# else
1796 if( !retroflat_2d_bitmap_ok( gui->draw_bmp ) ) {
1797 return;
1798 }
1799 retroflat_2d_blit_bitmap(
1800 gui->draw_bmp,
1801 &(ctl->IMAGE.image),
1802# endif /* RETROGXC_PRESENT */
1803 ctl->IMAGE.src_x, ctl->IMAGE.src_y,
1804 gui->x + ctl->base.x, gui->y + ctl->base.y, ctl->base.w, ctl->base.h,
1805 ctl->IMAGE.instance );
1806# endif
1807
1808 return;
1809}
1810
1811static MERROR_RETVAL retrogui_push_IMAGE( union RETROGUI_CTL* ctl ) {
1812 MERROR_RETVAL retval = MERROR_OK;
1813
1814# if defined( RETROGUI_NATIVE_WIN )
1815
1816 /* TODO */
1817
1818# else
1819
1820#if RETROGUI_TRACE_LVL > 0
1821 debug_printf( RETROGUI_TRACE_LVL, "pushing IMAGE control..." );
1822#endif /* RETROGUI_TRACE_LVL */
1823
1824 /* TODO: Copy non-cached image. */
1825
1826 /* ctl->IMAGE.cache_idx = NULL; */
1827# endif
1828
1829 return retval;
1830}
1831
1832static MERROR_RETVAL retrogui_sz_IMAGE(
1833 struct RETROGUI* gui, union RETROGUI_CTL* ctl,
1836) {
1837 MERROR_RETVAL retval = MERROR_GUI;
1838# ifdef RETROGXC_PRESENT
1839 retval = retrogxc_bitmap_wh( ctl->IMAGE.image_cache_id, p_w, p_h );
1840 maug_cleanup_if_not_ok();
1841# else
1842 if( !retroflat_2d_bitmap_ok( &(ctl->IMAGE.image) ) ) {
1843 error_printf( "image not assigned!" );
1844 retval = MERROR_GUI;
1845 goto cleanup;
1846 }
1847
1848 *p_w = retroflat_2d_bitmap_w( &(ctl->IMAGE.image) );
1849 *p_h = retroflat_2d_bitmap_h( &(ctl->IMAGE.image) );
1850# endif /* RETROGXC_PRESENT */
1851
1852cleanup:
1853
1854 return retval;
1855}
1856
1857static MERROR_RETVAL retrogui_pos_IMAGE(
1858 struct RETROGUI* gui, union RETROGUI_CTL* ctl,
1861) {
1862 MERROR_RETVAL retval = MERROR_GUI;
1863 /* TODO */
1864 return retval;
1865}
1866
1867static void retrogui_destroy_IMAGE( union RETROGUI_CTL* ctl ) {
1868# ifndef RETROGXC_PRESENT
1869 retroflat_2d_destroy_bitmap( &(ctl->IMAGE.image) );
1870# endif /* RETROGXC_PRESENT */
1871}
1872
1873static MERROR_RETVAL retrogui_init_IMAGE( union RETROGUI_CTL* ctl ) {
1874 MERROR_RETVAL retval = MERROR_OK;
1875
1876#if RETROGUI_TRACE_LVL > 0
1877 debug_printf( RETROGUI_TRACE_LVL,
1878 "initializing IMAGE " RETROGUI_IDC_FMT "...", ctl->base.idc );
1879#endif /* RETROGUI_TRACE_LVL */
1880
1881 return retval;
1882}
1883
1884/* === Control: FILLBAR === */
1885
1886static retrogui_idc_t retrogui_click_FILLBAR(
1887 struct RETROGUI* gui,
1888 union RETROGUI_CTL* ctl, RETROFLAT_IN_KEY* p_input,
1889 struct RETROFLAT_INPUT* input_evt
1890) {
1891 retrogui_idc_t idc_out = RETROGUI_IDC_NONE;
1892
1893 return idc_out;
1894}
1895
1896static retrogui_idc_t retrogui_key_FILLBAR(
1897 struct RETROGUI* gui, union RETROGUI_CTL* ctl, RETROFLAT_IN_KEY* p_input,
1898 struct RETROFLAT_INPUT* input_evt
1899) {
1900 retrogui_idc_t idc_out = RETROGUI_IDC_NONE;
1901
1902 return idc_out;
1903}
1904
1905static void retrogui_redraw_FILLBAR(
1906 struct RETROGUI* gui, union RETROGUI_CTL* ctl
1907) {
1908 retroflat_pxxy_t fill_w = 0;
1909
1910 if( 0 == ctl->FILLBAR.cur ) {
1911 fill_w = 0;
1912 } else {
1913 fill_w = ctl->base.w * ctl->FILLBAR.cur / ctl->FILLBAR.max;
1914 }
1915
1916 retroflat_2d_rect(
1917 gui->draw_bmp, ctl->base.bg_color, ctl->base.x + fill_w, ctl->base.y,
1918 ctl->base.w - fill_w, ctl->base.h, RETROFLAT_FLAGS_FILL );
1919
1920 retroflat_2d_rect(
1921 gui->draw_bmp, ctl->base.fg_color, ctl->base.x, ctl->base.y,
1922 fill_w, ctl->base.h, RETROFLAT_FLAGS_FILL );
1923
1924 return;
1925}
1926
1927static MERROR_RETVAL retrogui_push_FILLBAR( union RETROGUI_CTL* ctl ) {
1928 MERROR_RETVAL retval = MERROR_OK;
1929
1930# if defined( RETROGUI_NATIVE_WIN )
1931
1932 /* TODO: Native fillbar implementation. */
1933
1934# endif
1935
1936 return retval;
1937}
1938
1939static MERROR_RETVAL retrogui_sz_FILLBAR(
1940 struct RETROGUI* gui, union RETROGUI_CTL* ctl,
1943) {
1944 MERROR_RETVAL retval = MERROR_OK;
1945
1946 assert( NULL != ctl );
1947
1948 /* TODO? */
1949
1950 return retval;
1951}
1952
1953static MERROR_RETVAL retrogui_pos_FILLBAR(
1954 struct RETROGUI* gui, union RETROGUI_CTL* ctl,
1957) {
1958 MERROR_RETVAL retval = MERROR_OK;
1959
1960# if defined( RETROGUI_NATIVE_WIN )
1961 /* TODO */
1962# else
1963 assert( NULL != ctl );
1964
1965 ctl->base.x = x;
1966 ctl->base.y = y;
1967 if( 0 < w ) {
1968 ctl->base.w = w;
1969 }
1970 if( 0 < h ) {
1971 ctl->base.h = h;
1972 }
1973# endif /* RETROGUI_NATIVE_WIN */
1974
1975 return retval;
1976}
1977
1978static void retrogui_destroy_FILLBAR( union RETROGUI_CTL* ctl ) {
1979}
1980
1981static MERROR_RETVAL retrogui_init_FILLBAR( union RETROGUI_CTL* ctl ) {
1982 MERROR_RETVAL retval = MERROR_OK;
1983
1984#if RETROGUI_TRACE_LVL > 0
1985 debug_printf( RETROGUI_TRACE_LVL,
1986 "initializing fillbar " RETROGUI_IDC_FMT "...", ctl->base.idc );
1987#endif /* RETROGUI_TRACE_LVL */
1988
1989 if( 2 < retroflat_screen_colors() ) {
1990 ctl->base.fg_color = RETROGUI_COLOR_BORDER;
1991 ctl->base.bg_color = RETROFLAT_COLOR_GRAY;
1992 } else {
1993 ctl->base.fg_color = RETROFLAT_COLOR_BLACK;
1994 ctl->base.bg_color = RETROFLAT_COLOR_WHITE;
1995 }
1996
1997 return retval;
1998}
1999
2000/* === Static Internal Functions === */
2001
2002static union RETROGUI_CTL* _retrogui_get_ctl_by_idc(
2003 struct RETROGUI* gui, size_t idc
2004) {
2005 size_t i = 0;
2006 union RETROGUI_CTL* ctl = NULL;
2007
2008 assert( mdata_vector_is_locked( &((gui)->ctls) ) );
2009
2010 for( i = 0 ; mdata_vector_ct( &(gui->ctls) ) > i ; i++ ) {
2011 ctl = mdata_vector_get( &(gui->ctls), i, union RETROGUI_CTL );
2012 if( idc == ctl->base.idc ) {
2013 break;
2014 }
2015 ctl = NULL;
2016 }
2017
2018 if( NULL == ctl ) {
2019 error_printf( "could not find GUI item IDC " RETROGUI_IDC_FMT, idc );
2020 }
2021
2022 return ctl;
2023}
2024
2025/* === */
2026
2027static MERROR_RETVAL _retrogui_sz_ctl(
2028 struct RETROGUI* gui, retrogui_idc_t idc,
2031) {
2032 MERROR_RETVAL retval = MERROR_OK;
2033 union RETROGUI_CTL* ctl = NULL;
2034
2035 assert( mdata_vector_is_locked( &((gui)->ctls) ) );
2036
2037#if RETROGUI_TRACE_LVL > 0
2038 debug_printf( RETROGUI_TRACE_LVL,
2039 "sizing control " RETROGUI_IDC_FMT " to: " SIZE_T_FMT "x" SIZE_T_FMT,
2040 idc, max_w, max_h );
2041#endif /* RETROGUI_TRACE_LVL */
2042
2043 ctl = _retrogui_get_ctl_by_idc( gui, idc );
2044 if( NULL == ctl ) {
2045 /* Elaborate on error from _retrogui_get_ctl_by_idc(). */
2046 error_printf( "could not size item!" );
2047 retval = MERROR_GUI;
2048 goto cleanup;
2049 }
2050
2051 #define RETROGUI_CTL_TABLE_SZ( idx, c_name, c_fields ) \
2052 } else if( RETROGUI_CTL_TYPE_ ## c_name == ctl->base.type ) { \
2053 /* Mark dirty first so redraw can unmark it for animation! */ \
2054 retval = retrogui_sz_ ## c_name( gui, ctl, p_w, p_h, max_w, max_h ); \
2055 maug_cleanup_if_not_ok();
2056
2057 if( 0 ) {
2058 RETROGUI_CTL_TABLE( RETROGUI_CTL_TABLE_SZ )
2059 }
2060
2061#if RETROGUI_TRACE_LVL > 0
2062 debug_printf( RETROGUI_TRACE_LVL,
2063 "sized control " RETROGUI_IDC_FMT " at " SIZE_T_FMT "x" SIZE_T_FMT "...",
2064 ctl->base.idc, ctl->base.w, ctl->base.h );
2065#endif /* RETROGUI_TRACE_LVL */
2066
2067cleanup:
2068
2069 return retval;
2070}
2071
2072/* === Generic Functions === */
2073
2075 struct RETROGUI* gui, RETROFLAT_IN_KEY* p_input,
2076 struct RETROFLAT_INPUT* input_evt
2077) {
2078 size_t i = 0;
2079 retroflat_pxxy_t mouse_x = 0,
2080 mouse_y = 0;
2081 retrogui_idc_t idc_out = RETROGUI_IDC_NONE;
2082 union RETROGUI_CTL* ctl = NULL;
2083 MERROR_RETVAL retval = MERROR_OK;
2084
2085 if( 0 == mdata_vector_ct( &(gui->ctls) ) ) {
2086 return RETROGUI_IDC_NONE;
2087 }
2088
2089 assert( !mdata_vector_is_locked( &((gui)->ctls) ) );
2090 mdata_vector_lock( &(gui->ctls) );
2091
2092# if defined( RETROGUI_NATIVE_WIN )
2093
2094 if( 0 == g_retroflat_state->last_idc ) {
2095 /* No WM_COMMAND to process. */
2096 goto cleanup;
2097 }
2098
2099 ctl = retrogui_get_ctl_by_idc( gui, g_retroflat_state->last_idc );
2100 g_retroflat_state->last_idc = 0;
2101 if( NULL == ctl ) {
2102#if RETROGUI_TRACE_LVL > 0
2103 debug_printf( RETROGUI_TRACE_LVL,
2104 "invalid IDC: " RETROGUI_IDC_FMT, gui->focus );
2105#endif /* RETROGUI_TRACE_LVL */
2106 goto cleanup;
2107 }
2108
2109# ifndef RETROGUI_NO_TEXTBOX
2110 if( RETROGUI_CTL_TYPE_TEXTBOX == ctl->base.type ) {
2111 if( SendMessage( ctl->base.hwnd, EM_GETMODIFY, 0, 0 ) ) {
2112 SendMessage( ctl->base.hwnd, EM_SETMODIFY, 0, 0 );
2113#if RETROGUI_TRACE_LVL > 0
2114 debug_printf( RETROGUI_TRACE_LVL, "mod: %d",
2115 SendMessage( ctl->base.hwnd, EM_GETMODIFY, 0, 0 ) );
2116#endif /* RETROGUI_TRACE_LVL */
2117 }
2118 }
2119# endif /* !RETROGUI_NO_TEXTBOX */
2120
2121# else
2122
2123 /* Use our cross-platform controls. */
2124
2125# define RETROGUI_CTL_TABLE_CLICK( idx, c_name, c_fields ) \
2126 } else if( RETROGUI_CTL_TYPE_ ## c_name == ctl->base.type ) { \
2127 gui->flags |= RETROGUI_FLAGS_DIRTY; \
2128 idc_out = retrogui_click_ ## c_name( gui, ctl, p_input, input_evt );
2129
2130# define RETROGUI_CTL_TABLE_KEY( idx, c_name, c_fields ) \
2131 } else if( RETROGUI_CTL_TYPE_ ## c_name == ctl->base.type ) { \
2132 gui->flags |= RETROGUI_FLAGS_DIRTY; \
2133 idc_out = retrogui_key_ ## c_name( gui, ctl, p_input, input_evt );
2134
2135 if( 0 != *p_input ) {
2136#if RETROGUI_TRACE_LVL > 0
2137 debug_printf( RETROGUI_TRACE_LVL,
2138 "focus " RETROGUI_IDC_FMT " input: %d", gui->focus, *p_input );
2139#endif /* RETROGUI_TRACE_LVL */
2140 }
2141
2142 /* Don't accept any input until debounce period has expired. */
2143 if( retroflat_get_ms() < gui->debounce_next ) {
2144#if RETROGUI_TRACE_LVL > 0
2145 debug_printf( RETROGUI_TRACE_LVL,
2146 "debo! %d vs %d", retroflat_get_ms(), gui->debounce_next );
2147#endif /* RETROGUI_TRACE_LVL */
2148 goto cleanup;
2149 }
2150
2151 if( 0 == *p_input ) {
2152 /* No input to debounce! */
2153 goto cleanup;
2154
2155 } else if(
2156 retroflat_or_key( *p_input, RETROGUI_KEY_ACTIVATE, RETROGUI_PAD_ACTIVATE )
2157 ) {
2158
2159 if( 0 <= gui->focus ) {
2160 idc_out = gui->focus;
2161 /* gui->focus = -1; */
2162 gui->flags |= RETROGUI_FLAGS_DIRTY;
2163 }
2164
2165 } else if(
2166 retroflat_or_key( *p_input, RETROGUI_KEY_NEXT, RETROGUI_PAD_NEXT )
2167 ) {
2168 retrogui_focus_next( gui );
2169
2170#if RETROGUI_TRACE_LVL > 0
2171 debug_printf( RETROGUI_TRACE_LVL, "next: " RETROGUI_IDC_FMT, gui->focus );
2172#endif /* RETROGUI_TRACE_LVL */
2173
2174 /* Cleanup after the menu. */
2175 *p_input = 0;
2176
2177 } else if(
2178 retroflat_or_key( *p_input, RETROGUI_KEY_PREV, RETROGUI_PAD_PREV )
2179 ) {
2180 retrogui_focus_prev( gui );
2181
2182#if RETROGUI_TRACE_LVL > 0
2183 debug_printf( RETROGUI_TRACE_LVL, "prev: " RETROGUI_IDC_FMT, gui->focus );
2184#endif /* RETROGUI_TRACE_LVL */
2185
2186 /* Cleanup after the menu. */
2187 *p_input = 0;
2188
2189# ifndef RETROGUI_NO_MOUSE
2190 } else if(
2191 RETROFLAT_MOUSE_B_LEFT == *p_input ||
2192 RETROFLAT_MOUSE_B_RIGHT == *p_input
2193 ) {
2194 /* Handle mouse input. */
2195
2196 /* Remove all focus before testing if a new control has focus. */
2197#if RETROGUI_TRACE_LVL > 0
2198 debug_printf( RETROGUI_TRACE_LVL, "resetting focus for mouse click..." );
2199#endif /* RETROGUI_TRACE_LVL */
2200 gui->focus = RETROGUI_IDC_NONE;
2201
2202 mouse_x = input_evt->mouse_x - gui->x;
2203 mouse_y = input_evt->mouse_y - gui->y;
2204
2205 for( i = 0 ; mdata_vector_ct( &(gui->ctls) ) > i ; i++ ) {
2206 ctl = mdata_vector_get( &(gui->ctls), i, union RETROGUI_CTL );
2207 if(
2208 mouse_x < ctl->base.x ||
2209 mouse_y < ctl->base.y ||
2210 mouse_x > ctl->base.x + ctl->base.w ||
2211 mouse_y > ctl->base.y + ctl->base.h
2212 ) {
2213 continue;
2214 }
2215
2216 if( gui->idc_prev == ctl->base.idc ) {
2217 /* No repeated clicks! */
2218 /* TODO: Allow exceptions for e.g. scrollbars. */
2219 idc_out = RETROGUI_IDC_NONE;
2220 goto cleanup;
2221 }
2222
2223 gui->idc_prev = ctl->base.idc;
2224
2225#if RETROGUI_TRACE_LVL > 0
2226 debug_printf( RETROGUI_TRACE_LVL,
2227 "setting focus to clicked control: " RETROGUI_IDC_FMT,
2228 ctl->base.idc );
2229#endif /* RETROGUI_TRACE_LVL */
2230 gui->focus = ctl->base.idc;
2231
2232 if( 0 ) {
2233 RETROGUI_CTL_TABLE( RETROGUI_CTL_TABLE_CLICK )
2234 }
2235 break;
2236 }
2237# endif /* !RETROGUI_NO_MOUSE */
2238
2239 } else {
2240
2241 if( RETROGUI_IDC_NONE == gui->focus ) {
2242 goto cleanup;
2243 }
2244
2245 /* Send keystrokes to control that has focus. */
2246
2247 ctl = _retrogui_get_ctl_by_idc( gui, gui->focus );
2248 if( NULL == ctl ) {
2249 /* This is a debug message because an invalid focus isn't necessarily
2250 * a game-over situation...
2251 */
2252#if RETROGUI_TRACE_LVL > 0
2253 debug_printf( RETROGUI_TRACE_LVL,
2254 "invalid focus IDC: " RETROGUI_IDC_FMT, gui->focus );
2255#endif /* RETROGUI_TRACE_LVL */
2256 goto cleanup;
2257 }
2258
2259 if( 0 ) {
2260 RETROGUI_CTL_TABLE( RETROGUI_CTL_TABLE_KEY )
2261 }
2262 }
2263
2264 /* Input must have been valid, so set a debounce backoff time. */
2265 gui->debounce_next = retroflat_get_ms() + gui->debounce_max;
2266
2267# endif
2268
2269cleanup:
2270
2271 if( MERROR_OK != retval ) {
2272 idc_out = RETROGUI_IDC_NONE;
2273 }
2274
2275 mdata_vector_unlock( &(gui->ctls) );
2276
2277 return idc_out;
2278}
2279
2280/* === */
2281
2282MERROR_RETVAL retrogui_redraw_ctls( struct RETROGUI* gui ) {
2283 size_t i = 0;
2284 union RETROGUI_CTL* ctl = NULL;
2285 MERROR_RETVAL retval = MERROR_OK;
2286 int autolock = 0;
2287
2288 /* OpenGL tends to call glClear on every frame, so always redraw! */
2289 if( RETROGUI_FLAGS_DIRTY != (RETROGUI_FLAGS_DIRTY & gui->flags) ) {
2290 /* Shortcut! */
2291 return MERROR_OK;
2292 }
2293
2294 if( 0 == mdata_vector_ct( &(gui->ctls) ) ) {
2295 return MERROR_OK;
2296 }
2297
2298 if( !mdata_vector_is_locked( &((gui)->ctls) ) ) {
2299 mdata_vector_lock( &(gui->ctls) );
2300 autolock = 1;
2301 }
2302
2303 if(
2304 RETROFLAT_COLOR_BLACK != gui->bg_color &&
2305 0 < gui->w && 0 < gui->h
2306 ) {
2307 retroflat_2d_rect( gui->draw_bmp,
2308 gui->bg_color, gui->x, gui->y, gui->w, gui->h, RETROFLAT_FLAGS_FILL );
2309 }
2310
2311 #define RETROGUI_CTL_TABLE_REDRAW( idx, c_name, c_fields ) \
2312 } else if( RETROGUI_CTL_TYPE_ ## c_name == ctl->base.type ) { \
2313 /* Mark dirty first so redraw can unmark it for animation! */ \
2314 gui->flags &= ~RETROGUI_FLAGS_DIRTY; \
2315 retrogui_redraw_ ## c_name( gui, ctl );
2316
2317 for( i = 0 ; mdata_vector_ct( &(gui->ctls) ) > i ; i++ ) {
2318 ctl = mdata_vector_get( &(gui->ctls), i, union RETROGUI_CTL );
2319 if( 0 ) {
2320 RETROGUI_CTL_TABLE( RETROGUI_CTL_TABLE_REDRAW )
2321 }
2322 }
2323
2324cleanup:
2325
2326 if( autolock ) {
2327 mdata_vector_unlock( &(gui->ctls) );
2328 }
2329
2330 return retval;
2331}
2332
2333/* === */
2334
2335MERROR_RETVAL retrogui_pos_ctl(
2336 struct RETROGUI* gui, retrogui_idc_t idc,
2337 size_t x, size_t y, size_t w, size_t h
2338) {
2339 MERROR_RETVAL retval = MERROR_OK;
2340 union RETROGUI_CTL* ctl = NULL;
2341 int autolock = 0;
2342
2343 if( !mdata_vector_is_locked( &((gui)->ctls) ) ) {
2344 mdata_vector_lock( &(gui->ctls) );
2345 autolock = 1;
2346 }
2347
2348#if RETROGUI_TRACE_LVL > 0
2349 debug_printf( RETROGUI_TRACE_LVL,
2350 "moving control " RETROGUI_IDC_FMT " to: " SIZE_T_FMT ", " SIZE_T_FMT,
2351 idc, x, y );
2352#endif /* RETROGUI_TRACE_LVL */
2353
2354 ctl = _retrogui_get_ctl_by_idc( gui, idc );
2355 if( NULL == ctl ) {
2356 /* Elaborate on error from _retrogui_get_ctl_by_idc(). */
2357 error_printf( "could not position control!" );
2358 retval = MERROR_GUI;
2359 goto cleanup;
2360 }
2361
2362 #define RETROGUI_CTL_TABLE_POS( idx, c_name, c_fields ) \
2363 } else if( RETROGUI_CTL_TYPE_ ## c_name == ctl->base.type ) { \
2364 /* Mark dirty first so redraw can unmark it for animation! */ \
2365 retval = retrogui_pos_ ## c_name( gui, ctl, x, y, w, h ); \
2366 maug_cleanup_if_not_ok();
2367
2368 if( 0 ) {
2369 RETROGUI_CTL_TABLE( RETROGUI_CTL_TABLE_POS )
2370 }
2371
2372#if RETROGUI_TRACE_LVL > 0
2373 debug_printf( RETROGUI_TRACE_LVL,
2374 "moved control " RETROGUI_IDC_FMT " to " SIZE_T_FMT ", " SIZE_T_FMT
2375 " and sized to " SIZE_T_FMT "x" SIZE_T_FMT "...",
2376 ctl->base.idc, gui->x + ctl->base.x, gui->y + ctl->base.y,
2377 ctl->base.w, ctl->base.h );
2378#endif /* RETROGUI_TRACE_LVL */
2379
2380 /* New position! Redraw! */
2381 gui->flags |= RETROGUI_FLAGS_DIRTY;
2382
2383cleanup:
2384
2385 if( autolock ) {
2386 mdata_vector_unlock( &(gui->ctls) );
2387 }
2388
2389 return retval;
2390
2391}
2392
2393/* === */
2394
2395MERROR_RETVAL retrogui_push_ctl(
2396 struct RETROGUI* gui, union RETROGUI_CTL* ctl
2397) {
2398 MERROR_RETVAL retval = MERROR_OK;
2399 int autolock = 0;
2400
2401 assert( 0 < ctl->base.idc );
2402
2403#ifdef RETROGXC_PRESENT
2404 if( 0 > gui->font_idx ) {
2405#else
2406 if( (MAUG_MHANDLE)NULL == gui->font_h ) {
2407#endif /* RETROGXC_PRESENT */
2409 RETROFLAT_MSG_FLAG_ERROR, "Error", "GUI font not loaded!" );
2410 retval = MERROR_GUI;
2411 goto cleanup;
2412 }
2413
2414 /* TODO: Hunt for control IDC and fail if duplicate found! */
2415
2416#if RETROGUI_TRACE_LVL > 0
2417 debug_printf( RETROGUI_TRACE_LVL,
2418 "gui->ctls_ct: " SIZE_T_FMT, mdata_vector_ct( &(gui->ctls) ) );
2419#endif /* RETROGUI_TRACE_LVL */
2420
2421 if(
2422 RETROGUI_CTL_TYPE_IMAGE != ctl->base.type &&
2423 RETROFLAT_COLOR_NULL == ctl->base.bg_color
2424 ) {
2426 "invalid background color specified for control " RETROGUI_IDC_FMT "!",
2427 ctl->base.idc );
2428 retval = MERROR_GUI;
2429 goto cleanup;
2430
2431 }
2432
2433 if(
2434 RETROGUI_CTL_TYPE_IMAGE != ctl->base.type &&
2435 RETROFLAT_COLOR_NULL == ctl->base.fg_color
2436 ) {
2438 "invalid foreground color specified for control " RETROGUI_IDC_FMT "!",
2439 ctl->base.idc );
2440 retval = MERROR_GUI;
2441 goto cleanup;
2442 }
2443
2444 /* Perform the actual push. */
2445
2446#ifdef RETROGUI_TRACE_TOKENS
2447 debug_printf( RETROGUI_TRACE_LVL,
2448 "pushing %s " RETROGUI_IDC_FMT " to slot " SIZE_T_FMT "...",
2449 gc_retrogui_ctl_names[ctl->base.type], ctl->base.idc,
2450 mdata_vector_ct( &(gui->ctls) ) );
2451#elif RETROGUI_TRACE_LVL > 0
2452 debug_printf( RETROGUI_TRACE_LVL,
2453 "pushing control type %d, " RETROGUI_IDC_FMT " to slot " SIZE_T_FMT "...",
2454 ctl->base.type, ctl->base.idc, mdata_vector_ct( &(gui->ctls) ) );
2455#endif /* RETROGUI_TRACE_TOKENS */
2456
2457 mdata_vector_append( &(gui->ctls), ctl, sizeof( union RETROGUI_CTL ) );
2458
2459 gui->flags |= RETROGUI_FLAGS_DIRTY;
2460
2461 /* Now that append is done, lock the vector and grab a pointer to our
2462 * newly-pushed control to run some fixups on.
2463 */
2464 if( !mdata_vector_is_locked( &((gui)->ctls) ) ) {
2465 mdata_vector_lock( &(gui->ctls) );
2466 autolock = 1;
2467 }
2468
2469 /* TODO: More elegant way to grab index. */
2470 ctl = mdata_vector_get_last( &(gui->ctls),
2471 union RETROGUI_CTL );
2472 assert( NULL != ctl );
2473
2474#if RETROGUI_TRACE_LVL > 0
2475# define RETROGUI_CTL_TABLE_PUSH( idx, c_name, c_fields ) \
2476 } else if( RETROGUI_CTL_TYPE_ ## c_name == ctl->base.type ) { \
2477 debug_printf( RETROGUI_TRACE_LVL, \
2478 "running " #c_name " push hook..." ); \
2479 retval = retrogui_push_ ## c_name( ctl ); \
2480 maug_cleanup_if_not_ok();
2481#else
2482# define RETROGUI_CTL_TABLE_PUSH( idx, c_name, c_fields ) \
2483 } else if( RETROGUI_CTL_TYPE_ ## c_name == ctl->base.type ) { \
2484 retval = retrogui_push_ ## c_name( ctl ); \
2485 maug_cleanup_if_not_ok();
2486#endif /* RETROGUI_TRACE_LVL */
2487
2488 if( 0 ) {
2489 RETROGUI_CTL_TABLE( RETROGUI_CTL_TABLE_PUSH )
2490 }
2491
2492 /* Try to auto-size the control now that the push-hook as set its text
2493 * or whatever else might be needed to determine an automatic size.
2494 */
2495 if( 0 == ctl->base.w || 0 == ctl->base.h ) {
2496#ifdef RETROGUI_TRACE_TOKENS
2497 debug_printf( RETROGUI_TRACE_LVL,
2498 "determining size for new %s control " RETROGUI_IDC_FMT "...",
2499 gc_retrogui_ctl_names[ctl->base.type], ctl->base.idc );
2500#elif RETROGUI_TRACE_LVL > 0
2501 debug_printf( RETROGUI_TRACE_LVL,
2502 "determining size for new control type %d, " RETROGUI_IDC_FMT "...",
2503 ctl->base.type, ctl->base.idc );
2504#endif /* RETROGUI_TRACE_TOKENS */
2505 retval = _retrogui_sz_ctl(
2506 gui, ctl->base.idc, &(ctl->base.w), &(ctl->base.h), 0, 0 );
2507 maug_cleanup_if_not_ok();
2508 }
2509
2510 if( 0 > gui->focus && retrogui_can_focus_ctl( ctl ) ) {
2511#if RETROGUI_TRACE_LVL > 0
2512 debug_printf( RETROGUI_TRACE_LVL,
2513 "setting focus to control: " RETROGUI_IDC_FMT, ctl->base.idc );
2514#endif /* RETROGUI_TRACE_LVL */
2515 gui->focus = ctl->base.idc;
2516 }
2517
2518cleanup:
2519
2520 if( autolock ) {
2521 mdata_vector_unlock( &(gui->ctls) );
2522 }
2523
2524 return retval;
2525}
2526
2527/* === */
2528
2529MERROR_RETVAL retrogui_remove_ctl( struct RETROGUI* gui, retrogui_idc_t idc ) {
2530 size_t i = 0;
2531 union RETROGUI_CTL* ctl = NULL;
2532 MERROR_RETVAL retval = MERROR_OK;
2533
2534 if( mdata_vector_is_locked( &((gui)->ctls) ) ) {
2535 error_printf( "GUI is locked!" );
2536 goto cleanup;
2537 }
2538
2539 assert( !mdata_vector_is_locked( &((gui)->ctls) ) );
2540 mdata_vector_lock( &(gui->ctls) );
2541
2542 #define RETROGUI_CTL_TABLE_FREE_CTL( idx, c_name, c_fields ) \
2543 } else if( RETROGUI_CTL_TYPE_ ## c_name == ctl->base.type ) { \
2544 retrogui_destroy_ ## c_name( ctl );
2545
2546 for( i = 0 ; mdata_vector_ct( &(gui->ctls) ) > i ; i++ ) {
2547 ctl = mdata_vector_get( &(gui->ctls), i, union RETROGUI_CTL );
2548 if( idc != ctl->base.idc ) {
2549 continue;
2550 }
2551
2552 /* Free the control data. */
2553 if( 0 ) {
2554 RETROGUI_CTL_TABLE( RETROGUI_CTL_TABLE_FREE_CTL )
2555 }
2556
2557 /* Remove the control. */
2558 mdata_vector_unlock( &(gui->ctls) );
2559 mdata_vector_remove( &(gui->ctls), i );
2560 mdata_vector_lock( &(gui->ctls) );
2561 break;
2562 }
2563
2564 mdata_vector_unlock( &(gui->ctls) );
2565
2566cleanup:
2567
2568 return retval;
2569}
2570
2571/* === */
2572
2574 struct RETROGUI* gui, const char* font_path
2575) {
2576 MERROR_RETVAL retval = MERROR_OK;
2577
2578#ifdef RETROGXC_PRESENT
2579 gui->font_idx = retrogxc_load_font( font_path, 0, 33, 93 );
2580 maug_cleanup_if_lt(
2581 gui->font_idx, (ssize_t)0, SSIZE_T_FMT, MERROR_GUI );
2582#else
2583 retval = retrofont_load( font_path, &(gui->font_h), 0, 33, 93 );
2584 maug_cleanup_if_not_ok();
2585#endif /* RETROGXC_PRESENT */
2586
2587 gui->flags |= RETROGUI_FLAGS_FONT_OWNED;
2588
2589cleanup:
2590
2591 return retval;
2592}
2593
2594#ifndef RETROGUI_NO_TEXTBOX
2595
2596MERROR_RETVAL retrogui_get_ctl_text(
2597 struct RETROGUI* gui, retrogui_idc_t idc, char* buffer, size_t buffer_sz
2598) {
2599 MERROR_RETVAL retval = MERROR_OK;
2600 union RETROGUI_CTL* ctl = NULL;
2601 int autolock = 0;
2602
2603 if( !mdata_vector_is_locked( &((gui)->ctls) ) ) {
2604 mdata_vector_lock( &(gui->ctls) );
2605 autolock = 1;
2606 }
2607
2608 ctl = _retrogui_get_ctl_by_idc( gui, idc );
2609 if( NULL == ctl ) {
2610 /* Elaborate on error from _retrogui_get_ctl_by_idc(). */
2611 error_printf( "could not get control text!" );
2612 retval = MERROR_GUI;
2613 goto cleanup;
2614 }
2615
2616 if( RETROGUI_CTL_TYPE_TEXTBOX == ctl->base.type ) {
2617# if defined( RETROGUI_NATIVE_WIN )
2618 /* TODO */
2619#else
2620 maug_mlock( ctl->TEXTBOX.text_h, ctl->TEXTBOX.text );
2621 maug_cleanup_if_null_lock( char*, ctl->TEXTBOX.text );
2622
2623 maug_strncpy( buffer, ctl->TEXTBOX.text, buffer_sz );
2624# endif
2625 } else if( RETROGUI_CTL_TYPE_LABEL == ctl->base.type ) {
2626# if defined( RETROGUI_NATIVE_WIN )
2627 /* TODO */
2628#else
2629 maug_mlock( ctl->LABEL.label_h, ctl->LABEL.label );
2630 maug_cleanup_if_null_lock( char*, ctl->LABEL.label );
2631
2632 maug_strncpy( buffer, ctl->LABEL.label, buffer_sz );
2633# endif
2634
2635 }
2636
2637cleanup:
2638
2639 if( RETROGUI_CTL_TYPE_TEXTBOX == ctl->base.type ) {
2640 if( NULL != ctl->TEXTBOX.text ) {
2641 maug_munlock( ctl->TEXTBOX.text_h, ctl->TEXTBOX.text );
2642 }
2643
2644 } else if( RETROGUI_CTL_TYPE_LABEL == ctl->base.type ) {
2645 if( NULL != ctl->LABEL.label ) {
2646 maug_munlock( ctl->LABEL.label_h, ctl->LABEL.label );
2647 }
2648 }
2649
2650 if( autolock ) {
2651 mdata_vector_unlock( &(gui->ctls) );
2652 }
2653
2654 return retval;
2655}
2656
2657#endif /* !RETROGUI_NO_TEXTBOX */
2658
2659/* === */
2660
2661ssize_t retrogui_get_ctl_sel_idx( struct RETROGUI* gui, retrogui_idc_t idc ) {
2662 ssize_t idx = -1;
2663 union RETROGUI_CTL* ctl = NULL;
2664 MERROR_RETVAL retval = MERROR_OK;
2665 int autolock = 0;
2666
2667 if( !mdata_vector_is_locked( &((gui)->ctls) ) ) {
2668 mdata_vector_lock( &(gui->ctls) );
2669 autolock = 1;
2670 }
2671
2672 ctl = _retrogui_get_ctl_by_idc( gui, idc );
2673 if( NULL == ctl ) {
2674 /* Elaborate on error from _retrogui_get_ctl_by_idc(). */
2675 error_printf( "could not get control selection!" );
2676 retval = MERROR_GUI;
2677 goto cleanup;
2678 }
2679
2680 assert( RETROGUI_CTL_TYPE_LISTBOX == ctl->base.type );
2681
2682# if defined( RETROGUI_NATIVE_WIN )
2683 idx = SendMessage( ctl->base.hwnd, LB_GETCARETINDEX, 0, 0 );
2684# else
2685 idx = ctl->LISTBOX.sel_idx;
2686# endif
2687
2688cleanup:
2689
2690 if( autolock ) {
2691 mdata_vector_unlock( &(gui->ctls) );
2692 }
2693
2694 if( MERROR_OK != retval ) {
2695 idx = -1 * retval;
2696 }
2697
2698 return idx;
2699}
2700
2701/* === */
2702
2703MERROR_RETVAL retrogui_set_ctl_color(
2704 struct RETROGUI* gui, retrogui_idc_t idc, uint8_t color_key,
2705 RETROFLAT_COLOR color_val
2706) {
2707 MERROR_RETVAL retval = MERROR_OK;
2708 union RETROGUI_CTL* ctl = NULL;
2709
2710 assert( !mdata_vector_is_locked( &((gui)->ctls) ) );
2711 mdata_vector_lock( &(gui->ctls) );
2712
2713#if RETROGUI_TRACE_LVL > 0
2714 debug_printf( RETROGUI_TRACE_LVL,
2715 "setting control " RETROGUI_IDC_FMT " color %u to: %d",
2716 idc, color_key, color_val );
2717#endif /* RETROGUI_TRACE_LVL */
2718
2719 /* Figure out the control to update. */
2720 ctl = _retrogui_get_ctl_by_idc( gui, idc );
2721 if( NULL == ctl ) {
2722 /* Elaborate on error from _retrogui_get_ctl_by_idc(). */
2723 error_printf( "could not set control color!" );
2724 retval = MERROR_GUI;
2725 goto cleanup;
2726 }
2727
2728 switch( color_key ) {
2729 case RETROGUI_COLOR_BG: ctl->base.bg_color = color_val; break;
2730 case RETROGUI_COLOR_FG: ctl->base.fg_color = color_val; break;
2731 case RETROGUI_COLOR_SEL_BG: ctl->base.sel_bg = color_val; break;
2732 case RETROGUI_COLOR_SEL_FG: ctl->base.sel_fg = color_val; break;
2733
2734 default:
2735 error_printf( "invalid color key specified: %u", color_key );
2736 break;
2737 }
2738
2739cleanup:
2740
2741 mdata_vector_unlock( &(gui->ctls) );
2742
2743 return retval;
2744}
2745
2746/* === */
2747
2748MERROR_RETVAL retrogui_set_ctl_text(
2749 struct RETROGUI* gui, retrogui_idc_t idc, size_t buffer_sz,
2750 const char* fmt, ...
2751) {
2752 MERROR_RETVAL retval = MERROR_OK;
2753 size_t label_sz = 0;
2754 char* label_tmp = NULL;
2755 char* buffer = NULL;
2756 union RETROGUI_CTL* ctl = NULL;
2757 MAUG_MHANDLE buffer_h = (MAUG_MHANDLE)NULL;
2758 va_list args;
2759
2760 assert( !mdata_vector_is_locked( &((gui)->ctls) ) );
2761 mdata_vector_lock( &(gui->ctls) );
2762
2763#if RETROGUI_TRACE_LVL > 0
2764 debug_printf( RETROGUI_TRACE_LVL,
2765 "setting control " RETROGUI_IDC_FMT " text to: %s", idc, fmt );
2766#endif /* RETROGUI_TRACE_LVL */
2767
2768 /* Figure out the control to update. */
2769 ctl = _retrogui_get_ctl_by_idc( gui, idc );
2770 if( NULL == ctl ) {
2771 /* Elaborate on error from _retrogui_get_ctl_by_idc(). */
2772 error_printf( "could not set control text!" );
2773 retval = MERROR_GUI;
2774 goto cleanup;
2775 }
2776
2777 /* Perform the buffer substitutions. */
2778 buffer_h = maug_malloc( 1, buffer_sz + 1 );
2779 maug_cleanup_if_null_alloc( MAUG_MHANDLE, buffer_h );
2780
2781 assert( 0 < buffer_sz );
2782
2783 maug_mlock( buffer_h, buffer );
2784 maug_cleanup_if_null_lock( char*, buffer );
2785 maug_mzero( buffer, buffer_sz + 1 );
2786
2787 assert( NULL != buffer );
2788
2789 if( NULL == fmt ) {
2790 /* Zero the buffer. */
2791 maug_mzero( buffer, buffer_sz + 1);
2792
2793 } else {
2794 /* Format the buffer. */
2795 va_start( args, fmt );
2796 maug_vsnprintf( buffer, buffer_sz, fmt, args );
2797 va_end( args );
2798 }
2799
2800 /* Perform the actual update. */
2801 if( RETROGUI_CTL_TYPE_BUTTON == ctl->base.type ) {
2802 assert( NULL == ctl->BUTTON.label );
2803 _retrogui_copy_str( label, buffer, ctl->BUTTON, label_tmp, buffer_sz );
2804 } else if( RETROGUI_CTL_TYPE_LABEL == ctl->base.type ) {
2805 assert( NULL == ctl->LABEL.label );
2806 _retrogui_copy_str( label, buffer, ctl->LABEL, label_tmp, label_sz );
2807#ifndef RETROGUI_NO_TEXTBOX
2808 } else if( RETROGUI_CTL_TYPE_TEXTBOX == ctl->base.type ) {
2809 assert( NULL == ctl->TEXTBOX.text );
2810 /* This must always be the same and an lvalue! */
2811 label_sz = RETROGUI_CTL_TEXT_SZ_MAX;
2812 _retrogui_copy_str(
2813 text, buffer, ctl->TEXTBOX, label_tmp, label_sz );
2814 ctl->TEXTBOX.text_cur = 0;
2815#endif /* !RETROGUI_NO_TEXTBOX */
2816 } else {
2817 error_printf( "invalid control type! no label!" );
2818 goto cleanup;
2819 }
2820
2821 /* New text! Redraw! */
2822 gui->flags |= RETROGUI_FLAGS_DIRTY;
2823
2824cleanup:
2825
2826 if( NULL != buffer ) {
2827 maug_munlock( buffer_h, buffer );
2828 }
2829
2830 if( (MAUG_MHANDLE)NULL != buffer_h ) {
2831 maug_mfree( buffer_h );
2832 }
2833
2834 mdata_vector_unlock( &(gui->ctls) );
2835
2836 return retval;
2837}
2838
2839/* === */
2840
2842 struct RETROGUI* gui, retrogui_idc_t idc, const char* path, uint8_t flags
2843) {
2844 MERROR_RETVAL retval = MERROR_OK;
2845 union RETROGUI_CTL* ctl = NULL;
2846 int autolock = 0;
2847
2848 if( !mdata_vector_is_locked( &((gui)->ctls) ) ) {
2849 mdata_vector_lock( &(gui->ctls) );
2850 autolock = 1;
2851 }
2852
2853#if RETROGUI_TRACE_LVL > 0
2854 debug_printf( RETROGUI_TRACE_LVL,
2855 "setting control " RETROGUI_IDC_FMT " image to: %s", idc, path );
2856#endif /* RETROGUI_TRACE_LVL */
2857
2858 /* Figure out the control to update. */
2859 ctl = _retrogui_get_ctl_by_idc( gui, idc );
2860 if( NULL == ctl ) {
2861 /* Elaborate on error from _retrogui_get_ctl_by_idc(). */
2862 error_printf( "could not set control image!" );
2863 retval = MERROR_GUI;
2864 goto cleanup;
2865 }
2866
2867 /* Perform the actual update. */
2868 if( RETROGUI_CTL_TYPE_IMAGE == ctl->base.type ) {
2869 if( NULL != path ) {
2870# if defined( RETROGXC_PRESENT )
2871 ctl->IMAGE.image_cache_id = retrogxc_load_bitmap( path, flags );
2872# else
2873 retroflat_2d_load_bitmap( path, &(ctl->IMAGE.image), flags );
2874# endif /* RETROGXC_PRESENT */
2875 } else {
2876# ifdef RETROGXC_PRESENT
2877 ctl->IMAGE.image_cache_id = -1;
2878# else
2879 retroflat_2d_destroy_bitmap( &(ctl->IMAGE.image) );
2880# endif /* RETROGXC_PRESENT */
2881 }
2882 } else {
2883 error_printf( "invalid control type! no image!" );
2884 goto cleanup;
2885 }
2886
2887 /* New text! Redraw! */
2888 gui->flags |= RETROGUI_FLAGS_DIRTY;
2889
2890cleanup:
2891
2892 if( autolock ) {
2893 mdata_vector_unlock( &(gui->ctls) );
2894 }
2895
2896 return retval;
2897}
2898
2899/* === */
2900
2902 struct RETROGUI* gui, retrogui_idc_t idc, uint16_t level, uint16_t max,
2903 uint8_t flags
2904) {
2905 MERROR_RETVAL retval = MERROR_OK;
2906 union RETROGUI_CTL* ctl = NULL;
2907 int autolock = 0;
2908
2909 if( !mdata_vector_is_locked( &((gui)->ctls) ) ) {
2910 mdata_vector_lock( &(gui->ctls) );
2911 autolock = 1;
2912 }
2913
2914#if RETROGUI_TRACE_LVL > 0
2915 debug_printf( RETROGUI_TRACE_LVL,
2916 "setting control " RETROGUI_IDC_FMT " level to: %u", idc, level );
2917#endif /* RETROGUI_TRACE_LVL */
2918
2919 /* Figure out the control to update. */
2920 ctl = _retrogui_get_ctl_by_idc( gui, idc );
2921 if( NULL == ctl ) {
2922 /* Elaborate on error from _retrogui_get_ctl_by_idc(). */
2923 error_printf( "could not set control level!" );
2924 retval = MERROR_GUI;
2925 goto cleanup;
2926 }
2927
2928 /* Perform the actual update. */
2929 if( RETROGUI_CTL_TYPE_FILLBAR == ctl->base.type ) {
2930 ctl->FILLBAR.cur = level;
2931 if( 0 < max ) {
2932 ctl->FILLBAR.max = max;
2933 }
2934 } else {
2935 error_printf( "invalid control type! no level!" );
2936 goto cleanup;
2937 }
2938
2939 /* New level! Redraw! */
2940 gui->flags |= RETROGUI_FLAGS_DIRTY;
2941
2942cleanup:
2943
2944 if( autolock ) {
2945 mdata_vector_unlock( &(gui->ctls) );
2946 }
2947
2948 return retval;
2949}
2950
2951/* === */
2952
2953MERROR_RETVAL retrogui_init_ctl(
2954 union RETROGUI_CTL* ctl, uint8_t type, size_t idc
2955) {
2956 MERROR_RETVAL retval = MERROR_OK;
2957
2958#if RETROGUI_TRACE_LVL > 0
2959 debug_printf( RETROGUI_TRACE_LVL,
2960 "initializing control base " RETROGUI_IDC_FMT "...", idc );
2961#endif /* RETROGUI_TRACE_LVL */
2962
2963 maug_mzero( ctl, sizeof( union RETROGUI_CTL ) );
2964
2965 ctl->base.type = type;
2966 ctl->base.idc = idc;
2967 ctl->base.fg_color = RETROFLAT_COLOR_NULL;
2968 ctl->base.bg_color = RETROFLAT_COLOR_NULL;
2969 ctl->base.sel_fg = RETROFLAT_COLOR_NULL;
2970 ctl->base.sel_bg = RETROFLAT_COLOR_NULL;
2971
2972 #define RETROGUI_CTL_TABLE_INITS( idx, c_name, c_fields ) \
2973 } else if( RETROGUI_CTL_TYPE_ ## c_name == ctl->base.type ) { \
2974 retrogui_init_ ## c_name( ctl );
2975
2976 if( 0 ) {
2977 RETROGUI_CTL_TABLE( RETROGUI_CTL_TABLE_INITS )
2978 }
2979
2980# ifdef RETROGXC_PRESENT
2981 if( RETROGUI_CTL_TYPE_IMAGE == type ) {
2982 ctl->IMAGE.image_cache_id = -1;
2983 }
2984# endif /* !RETROGXC_PRESENT */
2985
2986 return retval;
2987}
2988
2989/* === */
2990
2991MERROR_RETVAL retrogui_destroy( struct RETROGUI* gui ) {
2992 size_t i = 0;
2993 union RETROGUI_CTL* ctl = NULL;
2994 MERROR_RETVAL retval = MERROR_OK;
2995
2996 if( mdata_vector_is_locked( &((gui)->ctls) ) ) {
2997 error_printf( "GUI is locked!" );
2998 goto cleanup;
2999 }
3000
3001 if( 0 == mdata_vector_ct( &(gui->ctls) ) ) {
3002 goto cleanup;
3003 }
3004
3005 assert( !mdata_vector_is_locked( &((gui)->ctls) ) );
3006 mdata_vector_lock( &(gui->ctls) );
3007
3008 #define RETROGUI_CTL_TABLE_FREE( idx, c_name, c_fields ) \
3009 } else if( RETROGUI_CTL_TYPE_ ## c_name == ctl->base.type ) { \
3010 retrogui_destroy_ ## c_name( ctl );
3011
3012 for( i = 0 ; mdata_vector_ct( &(gui->ctls) ) > i ; i++ ) {
3013 ctl = mdata_vector_get( &(gui->ctls), i, union RETROGUI_CTL );
3014 if( 0 ) {
3015 RETROGUI_CTL_TABLE( RETROGUI_CTL_TABLE_FREE )
3016 }
3017 }
3018
3019 mdata_vector_unlock( &(gui->ctls) );
3020
3021# ifndef RETROGXC_PRESENT
3022 if( RETROGUI_FLAGS_FONT_OWNED == (RETROGUI_FLAGS_FONT_OWNED & gui->flags) ) {
3023 maug_mfree( gui->font_h );
3024 }
3025# endif /* !RETROGXC_PRESENT */
3026
3027cleanup:
3028
3029 mdata_vector_free( &(gui->ctls) );
3030
3031 return retval;
3032}
3033
3034/* === */
3035
3036retrogui_idc_t retrogui_focus_iter(
3037 struct RETROGUI* gui, size_t start, ssize_t incr
3038) {
3039 retrogui_idc_t idc_out = RETROGUI_IDC_NONE;
3040 union RETROGUI_CTL* ctl = NULL;
3041 MERROR_RETVAL retval = MERROR_OK;
3042 retrogui_idc_t i = 0;
3043 ssize_t i_before = -1; /* Index of the current selected IDC. */
3044 int autolock = 0;
3045
3046 if( 0 == mdata_vector_ct( &(gui->ctls) ) ) {
3047 goto cleanup;
3048 }
3049
3050 if( !mdata_vector_is_locked( &((gui)->ctls) ) ) {
3051 mdata_vector_lock( &(gui->ctls) );
3052 autolock = 1;
3053 }
3054
3055 /* Find the currently selected IDC. */
3056 for(
3057 i = start ; mdata_vector_ct( &(gui->ctls) ) > i && 0 <= i ; i += incr
3058 ) {
3059 ctl = mdata_vector_get( &(gui->ctls), i, union RETROGUI_CTL );
3060 if( !retrogui_can_focus_ctl( ctl ) ) {
3061 continue;
3062 } else if( RETROGUI_IDC_NONE == gui->focus || 0 <= i_before ) {
3063 /* We're primed to set the new focus, so do that and finish. */
3064 idc_out = ctl->base.idc;
3065#if RETROGUI_TRACE_LVL > 0
3066 debug_printf( RETROGUI_TRACE_LVL,
3067 "moving focus to control: " RETROGUI_IDC_FMT, idc_out );
3068#endif /* RETROGUI_TRACE_LVL */
3069 gui->focus = idc_out;
3070 goto cleanup;
3071
3072 } else if( ctl->base.idc == gui->focus ) {
3073 /* We've found the current focus, so prime to select the new focus. */
3074 i_before = i;
3075 }
3076 }
3077
3078 /* We didn't select a focus in the loop above, so we must be wrapping around!
3079 */
3080
3081 /* Select the next IDC. */
3082 if( 0 > i ) {
3083 /* Wrap around to last SELECTABLE item. */
3084 for( i = mdata_vector_ct( &(gui->ctls) ) - 1 ; 0 <= i ; i-- ) {
3085 ctl = mdata_vector_get( &(gui->ctls), i, union RETROGUI_CTL );
3086 if( !retrogui_can_focus_ctl( ctl ) ) {
3087 /* Skip NON-SELECTABLE items! */
3088#if RETROGUI_TRACE_LVL > 0
3089 debug_printf(
3090 RETROGUI_TRACE_LVL, "skipping: " RETROGUI_IDC_FMT, i );
3091#endif /* RETROGUI_TRACE_LVL */
3092 continue;
3093 } else {
3094 idc_out = ctl->base.idc;
3095#if RETROGUI_TRACE_LVL > 0
3096 debug_printf( RETROGUI_TRACE_LVL,
3097 "moving focus to control: " RETROGUI_IDC_FMT, idc_out );
3098#endif /* RETROGUI_TRACE_LVL */
3099 gui->focus = idc_out;
3100 break;
3101 }
3102 }
3103
3104 } else if( mdata_vector_ct( &(gui->ctls) ) <= i ) {
3105 /* Wrap around to first SELECTABLE item. */
3106 for( i = 0 ; mdata_vector_ct( &(gui->ctls) ) > i ; i++ ) {
3107 ctl = mdata_vector_get( &(gui->ctls), i, union RETROGUI_CTL );
3108 if( !retrogui_can_focus_ctl( ctl ) ) {
3109 /* Skip NON-SELECTABLE items! */
3110#if RETROGUI_TRACE_LVL > 0
3111 debug_printf(
3112 RETROGUI_TRACE_LVL, "skipping: " RETROGUI_IDC_FMT, i );
3113#endif /* RETROGUI_TRACE_LVL */
3114 continue;
3115 } else {
3116 idc_out = ctl->base.idc;
3117#if RETROGUI_TRACE_LVL > 0
3118 debug_printf( RETROGUI_TRACE_LVL,
3119 "moving focus to control: " RETROGUI_IDC_FMT, idc_out );
3120#endif /* RETROGUI_TRACE_LVL */
3121 gui->focus = idc_out;
3122 break;
3123 }
3124 }
3125
3126 } else {
3127 error_printf( "invalid focus: " RETROGUI_IDC_FMT, i );
3128
3129 }
3130
3131cleanup:
3132
3133 /* New focus! Dirty! */
3134 gui->flags |= RETROGUI_FLAGS_DIRTY;
3135
3136 if( MERROR_OK != retval ) {
3137 idc_out = merror_retval_to_sz( retval );
3138 }
3139
3140 if( autolock ) {
3141 mdata_vector_unlock( &(gui->ctls) );
3142 }
3143
3144#if RETROGUI_TRACE_LVL > 0
3145 debug_printf(
3146 RETROGUI_TRACE_LVL, "selected IDC: " RETROGUI_IDC_FMT, idc_out );
3147#endif /* RETROGUI_TRACE_LVL */
3148
3149 return idc_out;
3150}
3151
3152/* === */
3153
3154MERROR_RETVAL retrogui_init( struct RETROGUI* gui ) {
3155 MERROR_RETVAL retval = MERROR_OK;
3156
3157 maug_mzero( gui, sizeof( struct RETROGUI ) );
3158
3159 gui->bg_color = RETROFLAT_COLOR_BLACK;
3160 gui->focus = RETROGUI_IDC_NONE;
3161 gui->debounce_max = RETROGUI_DEBOUNCE_MAX_DEFAULT;
3162
3163#if RETROGUI_TRACE_LVL > 0
3164 debug_printf( RETROGUI_TRACE_LVL, "initialized GUI" );
3165#endif /* RETROGUI_TRACE_LVL */
3166
3167 return retval;
3168}
3169
3170#else
3171
3172#define RETROGUI_CTL_TABLE_CONSTS( idx, c_name, c_fields ) \
3173 extern MAUG_CONST uint8_t SEG_MCONST RETROGUI_CTL_TYPE_ ## c_name;
3174
3175RETROGUI_CTL_TABLE( RETROGUI_CTL_TABLE_CONSTS )
3176
3177#ifdef RETROGUI_TRACE_TOKENS
3178extern MAUG_CONST char* gc_retrogui_ctl_names[];
3179#endif /* RETROGUI_TRACE_TOKENS */
3180
3181#endif /* RETROGUI_C */
3182 /* maug_retrogui */
3184 /* maug_retroflt */
3186
3187#endif /* !RETROGUI_H */
3188
int MERROR_RETVAL
Return type indicating function returns a value from this list.
Definition merror.h:19
int8_t RETROFLAT_COLOR
Defines an index in the platform-specific color-table.
Definition retroflt.h:325
void retroflat_ellipse(struct RETROFLAT_BITMAP *target, const RETROFLAT_COLOR color, int16_t x, int16_t y, int16_t w, int16_t h, uint8_t flags)
Draw an ellipse 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: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:791
#define retroflat_buffer_bksp(buffer, buffer_cur, buffer_sz)
Remove a character from a text buffer before cursor position.
Definition retroflt.h:775
#define retroflat_case_key(key, pad)
Specify cases for a select() on the result of retroflat_poll_input() for keyboard or game pad as avai...
Definition retroflt.h:1016
void retroflat_message(uint8_t flags, const char *title, const char *format,...)
Display a message in a dialog box and/or on stderr.
#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:461
size_t retroflat_pxxy_t
Type used for surface pixel coordinates.
Definition retroflt.h:870
#define RETROGUI_KEY_SEL_PREV
Overrideable constant defining the keyboard key (RETROFLAT_KEY_*) that will select the previous sub-i...
Definition retrogui.h:147
#define RETROGUI_PAD_SEL_NEXT
Overrideable constant defining the gamepad button (RETROGUI_PAD_*) that will select the next sub-item...
Definition retrogui.h:183
#define RETROGUI_KEY_NEXT
Overrideable constant defining the keyboard key (RETROFLAT_KEY_*) that will select the next activatea...
Definition retrogui.h:120
#define RETROGUI_KEY_ACTIVATE
Overrideable constant defining the keyboard key (RETROFLAT_KEY_*) that will activate the RETROGUI_CTL...
Definition retrogui.h:111
#define RETROGUI_PAD_ACTIVATE
Overrideable constant defining the gamepad button (RETROFLAT_PAD_*) that will activate the RETROGUI_C...
Definition retrogui.h:156
#define RETROGUI_PAD_SEL_PREV
Overrideable constant defining the gamepad button (RETROGUI_PAD_*) that will select the previous sub-...
Definition retrogui.h:192
#define RETROGUI_PAD_NEXT
Overrideable constant defining the gamepad button (RETROFLAT_PAD_*) that will select the next activat...
Definition retrogui.h:165
#define RETROGUI_KEY_PREV
Overrideable constant defining the keyboard key (RETROFLAT_KEY_*) that will select the previous activ...
Definition retrogui.h:129
#define RETROGUI_KEY_SEL_NEXT
Overrideable constant defining the keyboard key (RETROFLAT_KEY_*) that will select the next sub-item ...
Definition retrogui.h:138
#define RETROGUI_PAD_PREV
Overrideable constant defining the gamepad button (RETROFLAT_PAD_*) that will select the previous act...
Definition retrogui.h:174
#define RETROGUI_PADDING
Overrideable constant defining the padding for text inside of controls in pixels.
Definition retrogui.h:207
#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:397
#define retrogui_can_focus_ctl(ctl)
Determine if a RETROGUI_CTL can hold RETROGUI::focus.
Definition retrogui.h:370
#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:409
MERROR_RETVAL retrogui_set_ctl_level(struct RETROGUI *gui, retrogui_idc_t idc, uint16_t level, uint16_t max, uint8_t flags)
Set the current progress level displayed by a FILLBAR-type RETROGUI_CTL.
#define RETROGUI_COLOR_SEL_BG
Value for retrogui_set_ctl_color() color_key indicating selection background.
Definition retrogui.h:312
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.
MERROR_RETVAL retrogui_remove_ctl(struct RETROGUI *gui, retrogui_idc_t idc)
Remove a control with the given unique identifier index from the given RETROGUI controller.
#define RETROGUI_COLOR_SEL_FG
Value for retrogui_set_ctl_color() color_key indicating selection foreground.
Definition retrogui.h:318
#define RETROGUI_COLOR_BG
Value for retrogui_set_ctl_color() color_key indicating background.
Definition retrogui.h:301
MERROR_RETVAL retrogui_destroy(struct RETROGUI *gui)
Free memory held by a RETROGUI controller internally and clean up any subordinate controls.
retrogui_idc_t retrogui_focus_iter(struct RETROGUI *gui, size_t start, ssize_t incr)
Increment RETROGUI::focus, skipping elements that cannot hold focus.
MERROR_RETVAL retrogui_init(struct RETROGUI *gui)
Prepare a RETROGUI controller for use.
MERROR_RETVAL retrogui_set_font(struct RETROGUI *gui, const char *font_path)
Load the RetroFont API for the given RETROGUI to draw its controls with. Use RetroGXCache API if avai...
int16_t retrogui_idc_t
Unique identifying constant number for controls.
Definition retrogui.h:292
#define RETROGUI_COLOR_BORDER
RetroGUI will try to use this color on non-monochrome systems instead of black to draw things like bo...
Definition retrogui.h:95
MERROR_RETVAL retrogui_set_ctl_image(struct RETROGUI *gui, retrogui_idc_t idc, const char *path, uint8_t flags)
Set the image displayed by an IMAGE-type RETROGUI_CTL.
#define RETROGUI_COLOR_FG
Value for retrogui_set_ctl_color() color_key indicating foreground.
Definition retrogui.h:306
void retrofont_string(retroflat_blit_t *target, RETROFLAT_COLOR color, const char *str, size_t str_sz, MAUG_MHANDLE font_h, size_t x, size_t y, size_t max_w, size_t max_h, uint8_t flags)
Draw a string with the given font.
#define RETROFONT_FLAG_SZ_MIN
Flag for retroflat_string_sz() to return the size of the shortest line in a multi-line string.
Definition retrofnt.h:39
MERROR_RETVAL retrofont_load(const char *font_name, MAUG_MHANDLE *p_font_h, uint8_t glyph_h, uint16_t first_glyph, uint16_t glyphs_count)
Load a font for drawing.
A vector of uniformly-sized objects, stored contiguously.
Definition mdata.h:93
size_t item_sz
Size, in bytes, of each item.
Definition mdata.h:111
Struct passed to retroflat_poll_input() to hold return data.
Definition retroflt.h:814
int mouse_y
Y-coordinate of the mouse pointer in pixels if the returned event is a mouse click.
Definition retroflt.h:824
int mouse_x
X-coordinate of the mouse pointer in pixels if the returned event is a mouse click.
Definition retroflt.h:819
Fields common to ALL RETROGUI_CTL types.
Definition retrogui.h:377
Definition retrogui.h:430
MAUG_MHANDLE font_h
Font used to draw any attached RETROGUI_CTL.
Definition retrogui.h:456
retrogui_idc_t focus
Unique identifying index for current highlighted RETROGUI_CTL.
Definition retrogui.h:440
Definition retrogui.h:412