maug
Quick and dirty C mini-augmentation library.
Loading...
Searching...
No Matches
retrocon.h
1
2#ifndef RETROCON_H
3#define RETROCON_H
4
5#define RETROCON_DEBOUNCE_WAIT 3
6
7#define RETROCON_FLAG_ACTIVE 0x01
8
9#define RETROCON_IDC_TEXTBOX 1
10
11#define RETROCON_IDC_CON_BASE 10
12
13#define RETROCON_IDC_CLOSE 65535
14
15#ifndef RETROCON_TRACE_LVL
16# define RETROCON_TRACE_LVL 0
17#endif /* !RETROCON_TRACE_LVL */
18
19#ifdef RETROCON_DISABLE
20
21struct RETROCON {
22 uint8_t flags;
23 RETROFLAT_COLOR lbuffer_color;
24 RETROFLAT_COLOR sbuffer_color;
25 RETROFLAT_COLOR bg_color;
26};
27
28# define retrocon_init( con, fn, x, y, w, h ) (MERROR_OK)
29
30# define retrocon_add_command( con, cmd, cb, cb_data ) (MERROR_OK)
31
32# define retrocon_display( con, display )
33
34# define retrocon_print_line( con, line )
35
36# define retrocon_exec_line( con, line, line_sz )
37
38# define retrocon_debounce( con, c )
39
40# define retrocon_input( con, p_c, input_evt, p_idc, win_stack )
41
42# define retrocon_shutdown( con )
43
44#else
45
51#ifndef RETROCON_TRACE_LVL
52# define RETROCON_TRACE_LVL 0
53#endif /* !RETROCON_TRACE_LVL */
54
55#ifndef RETROCON_SBUFFER_SZ_MAX
56# define RETROCON_SBUFFER_SZ_MAX 4096
57#endif /* !RETROCON_SBUFFER_SZ_MAX */
58
59#ifndef RETROCON_SBUFFER_LINES_MAX
60# define RETROCON_SBUFFER_LINES_MAX 30
61#endif /* !RETROCON_SBUFFER_LINES_MAX */
62
63#ifndef RETROCON_LBUFFER_SZ_MAX
64# define RETROCON_LBUFFER_SZ_MAX 256
65#endif /* !RETROCON_LBUFFER_SZ_MAX */
66
67#ifndef RETROCON_ACTIVE_KEY
68# define RETROCON_ACTIVE_KEY RETROFLAT_KEY_GRAVE
69#endif /* !RETROCON_ACTIVE_KEY */
70
71#ifndef RETROCON_CB_NAME_SZ_MAX
72# define RETROCON_CB_NAME_SZ_MAX 32
73#endif /* !RETROCON_CB_NAME_SZ_MAX */
74
75#ifndef RETROCON_CB_SZ_MAX
76# define RETROCON_CB_SZ_MAX 128
77#endif /* !RETROCON_CB_SZ_MAX */
78
79#ifndef RETROCON_WIN_H
80# define RETROCON_WIN_H 110
81#endif /* !RETROCON_WIN_H */
82
83struct RETROCON;
84
85typedef MERROR_RETVAL (*retrocon_cb)(
86 struct RETROCON* con, const char* line, size_t line_sz, void* data );
87
88struct RETROCON {
89 uint8_t flags;
90 struct RETROGUI gui;
91 int input_prev;
92 int debounce_wait;
93 void* callback_data[RETROCON_CB_SZ_MAX];
94 char callback_names[RETROCON_CB_SZ_MAX][RETROCON_CB_NAME_SZ_MAX + 1];
95 retrocon_cb callbacks[RETROCON_CB_SZ_MAX];
96 size_t callbacks_sz;
97 RETROFLAT_COLOR lbuffer_color;
98 RETROFLAT_COLOR sbuffer_color;
99 RETROFLAT_COLOR bg_color;
100 size_t sbuffer_lines;
101};
102
103MERROR_RETVAL retrocon_init(
104 struct RETROCON* con, const char* font_name,
105 size_t x, size_t y, size_t w, size_t h );
106
107MERROR_RETVAL retrocon_add_command(
108 struct RETROCON* con, const char* cmd, retrocon_cb cb, void* cb_data );
109
110MERROR_RETVAL retrocon_print_line( struct RETROCON* con, const char* line );
111
112MERROR_RETVAL retrocon_exec_line(
113 struct RETROCON* con, char* line, size_t line_sz );
114
115int retrocon_debounce( struct RETROCON* con, int c );
116
126 struct RETROCON* con, RETROFLAT_IN_KEY* p_c,
127 struct RETROFLAT_INPUT* input_evt,
128 retrogui_idc_t* p_idc_out, struct MDATA_VECTOR* win_stack );
129
130MERROR_RETVAL retrocon_display(
131 struct RETROCON* con, struct RETROFLAT_BITMAP* gui_bmp );
132
133void retrocon_shutdown( struct RETROCON* con );
134
135#ifdef RETROCON_C
136
137static MERROR_RETVAL retrocon_cmd_print(
138 struct RETROCON* con, const char* line, size_t line_sz, void* data
139) {
140 MERROR_RETVAL retval = MERROR_OK;
141 char* print_line = NULL;
142
143 print_line = maug_strchr( line, ' ' );
144 if( NULL == print_line ) {
145 /* Not technically an error. */
146 goto cleanup;
147 }
148
149 /* Skip space. */
150 print_line++;
151
152 retrocon_print_line( con, print_line );
153
154cleanup:
155
156 return retval;
157}
158
159static MERROR_RETVAL retrocon_cmd_quit(
160 struct RETROCON* con, const char* line, size_t line_sz, void* data
161) {
162 MERROR_RETVAL retval = MERROR_OK;
163
164 retroflat_quit( 0 );
165
166 return retval;
167}
168
169MERROR_RETVAL retrocon_init(
170 struct RETROCON* con, const char* font_name,
171 size_t x, size_t y, size_t w, size_t h
172) {
173 MERROR_RETVAL retval = MERROR_OK;
174 union RETROGUI_CTL ctl;
175 size_t ctl_y_iter = 0;
176
177 debug_printf( RETROCON_TRACE_LVL, "initializing console..." );
178
179 retval = retrogui_init( &(con->gui) );
180 maug_cleanup_if_not_ok();
181
182 /* TODO: Parse font height from filename and only load printable glyphs. */
183#ifdef RETROGXC_PRESENT
184 con->gui.font_idx = retrogxc_load_font( font_name, 0, 33, 93 );
185#else
186 retval = retrofont_load( font_name, &(con->gui.font_h), 0, 33, 93 );
187#endif /* RETROGXC_PRESENT */
188 maug_cleanup_if_not_ok();
189
190 con->sbuffer_color = RETROFLAT_COLOR_DARKBLUE;
191 con->lbuffer_color = RETROFLAT_COLOR_BLACK;
192 con->gui.bg_color = RETROFLAT_COLOR_WHITE;
193 con->gui.x = x;
194 con->gui.y = y;
195 con->gui.w = w;
196 con->gui.h = h;
197
198 retrogui_lock( &(con->gui) );
199
200 retrogui_init_ctl(
201 &ctl, RETROGUI_CTL_TYPE_TEXTBOX, RETROCON_IDC_TEXTBOX );
202
203 ctl.base.x = 5;
204 ctl.base.y = 5;
205 ctl.base.w = con->gui.w - 10;
206 ctl.base.h = 20; /* TODO: Dynamic height based on font. */
207 ctl.base.fg_color = RETROFLAT_COLOR_BLACK;
208
209 retval = retrogui_push_ctl( &(con->gui), &ctl );
210 maug_cleanup_if_not_ok();
211
212 ctl_y_iter = ctl.base.y + ctl.base.h + 1;
213 while( h - 5 > ctl_y_iter + 8 + 1 ) {
214 retrogui_init_ctl(
215 &ctl, RETROGUI_CTL_TYPE_LABEL,
216 RETROCON_IDC_CON_BASE + con->sbuffer_lines );
217
218 ctl.base.x = 5;
219 ctl.base.y = ctl_y_iter;
220 ctl.base.w = con->gui.w - 10;
221 ctl.base.h = 8; /* TODO: Dynamic height based on font. */
222 ctl.base.fg_color = RETROFLAT_COLOR_DARKGRAY;
223 ctl.LABEL.label = "xxxxxx";
224
225 retval = retrogui_push_ctl( &(con->gui), &ctl );
226 maug_cleanup_if_not_ok();
227
228 ctl_y_iter += ctl.base.h + 1;
229 con->sbuffer_lines++;
230 }
231
232 retrogui_unlock( &(con->gui) );
233
234 con->gui.focus = RETROCON_IDC_TEXTBOX;
235
236 retval = retrocon_add_command( con, "PRINT", retrocon_cmd_print, NULL );
237 maug_cleanup_if_not_ok();
238 retval = retrocon_add_command( con, "QUIT", retrocon_cmd_quit, NULL );
239 maug_cleanup_if_not_ok();
240
241cleanup:
242
243 return retval;
244}
245
246MERROR_RETVAL retrocon_add_command(
247 struct RETROCON* con, const char* cmd, retrocon_cb cb, void* cb_data
248) {
249 MERROR_RETVAL retval = MERROR_OK;
250
251 debug_printf( RETROCON_TRACE_LVL, "adding console command: %s", cmd );
252
253 maug_cleanup_if_ge_overflow( con->callbacks_sz + 1, RETROCON_CB_SZ_MAX );
254
255 maug_strncpy(
256 con->callback_names[con->callbacks_sz], cmd, RETROCON_CB_NAME_SZ_MAX );
257
258 con->callbacks[con->callbacks_sz] = cb;
259
260 con->callback_data[con->callbacks_sz] = cb_data;
261
262 con->callbacks_sz++;
263
264cleanup:
265
266 return retval;
267}
268
269#if 0
270MERROR_RETVAL retrocon_display(
271 struct RETROCON* con, struct RETROFLAT_BITMAP* display
272) {
273 MERROR_RETVAL retval = MERROR_OK;
274 size_t i = 0,
275 line_sz = 0;
276
277 if( RETROCON_FLAG_ACTIVE != (RETROCON_FLAG_ACTIVE & con->flags) ) {
278 goto cleanup;
279 }
280
281 if( (RETROFLAT_COLOR)0 == con->bg_color ) {
282 error_printf( "colors not set!" );
283 goto cleanup;
284 }
285
287 NULL, con->bg_color, 10, 10,
288 300, RETROCON_WIN_H, RETROFLAT_FLAGS_FILL );
289
291 NULL, con->lbuffer_color, con->lbuffer, -1, NULL,
292 15, 15, 0 );
293
294 /* Draw each line, one by one. */
295 for( i = 0 ; con->sbuffer_lines_sz > i ; i++ ) {
296 if( i + 1 < con->sbuffer_lines_sz ) {
297 line_sz = con->sbuffer_lines[i + 1] - con->sbuffer_lines[i];
298 } else {
299 line_sz = -1;
300 }
301
303 NULL, con->sbuffer_color,
304 &(con->sbuffer[con->sbuffer_lines[i]]), line_sz, NULL,
305 15, 25 + (i * 10), 0 );
306 }
307
308cleanup:
309
310 return retval;
311}
312#endif
313
314MERROR_RETVAL retrocon_print_line( struct RETROCON* con, const char* line ) {
315 char sbuffer_shift[RETROCON_LBUFFER_SZ_MAX + 1] = { 0 };
316 size_t i = 0;
317 MERROR_RETVAL retval = MERROR_OK;
318
319 /* TODO: Escape newlines in line. */
320
321 /* Shift existing screen buffer lines all down by one. */
322 for( i = con->sbuffer_lines - 1 ; 0 < i ; i-- ) {
323 debug_printf( RETROCON_TRACE_LVL,
324 "copying sbuffer line " SIZE_T_FMT " to " SIZE_T_FMT "...",
325 i - 1, i );
326 maug_mzero( sbuffer_shift, RETROCON_LBUFFER_SZ_MAX + 1 );
327 retrogui_lock( &(con->gui) );
328 retval = retrogui_get_ctl_text(
329 &(con->gui), RETROCON_IDC_CON_BASE + i - 1,
330 sbuffer_shift, RETROCON_LBUFFER_SZ_MAX );
331 retval = retrogui_set_ctl_text(
332 &(con->gui), RETROCON_IDC_CON_BASE + i,
333 RETROCON_LBUFFER_SZ_MAX, sbuffer_shift );
334 retrogui_unlock( &(con->gui) );
335 maug_cleanup_if_not_ok();
336 }
337
338 /* Put line in first sbuffer line. */
339 retrogui_lock( &(con->gui) );
340 retval = retrogui_set_ctl_text(
341 &(con->gui), RETROCON_IDC_CON_BASE,
342 RETROCON_LBUFFER_SZ_MAX, line );
343 retrogui_unlock( &(con->gui) );
344 maug_cleanup_if_not_ok();
345
346cleanup:
347
348 return retval;
349}
350
351MERROR_RETVAL retrocon_exec_line(
352 struct RETROCON* con, char* line, size_t line_sz
353) {
354 MERROR_RETVAL retval = MERROR_OK;
355 size_t i = 0;
356 char line_cap[RETROCON_LBUFFER_SZ_MAX + 1];
357
358 /* Create an uppercase for comparison. */
359 maug_mzero( line_cap, RETROCON_LBUFFER_SZ_MAX + 1 );
360 strncpy( line_cap, line, RETROCON_LBUFFER_SZ_MAX );
361 maug_str_upper( line_cap, line_sz );
362
363 /* Find callback with name starting line. */
364 for( i = 0 ; con->callbacks_sz > i ; i++ ) {
365 if(
366 0 == strncmp(
367 /* TODO: Compare up to first space in line. */
368 con->callback_names[i], line_cap,
369 maug_strlen( con->callback_names[i] ) )
370 ) {
371 retval = con->callbacks[i](
372 con, line, line_sz, con->callback_data[i] );
373 goto cleanup;
374 }
375 }
376
377 retrocon_print_line( con, "COMMAND NOT FOUND!" );
378
379cleanup:
380
381 return retval;
382}
383
385 struct RETROCON* con, RETROFLAT_IN_KEY* p_c,
386 struct RETROFLAT_INPUT* input_evt,
387 /* TODO: Right now only 3D win stack exists, but update this for 2D
388 * when that's developed, as well.
389 */
390 retrogui_idc_t* p_idc_out, struct MDATA_VECTOR* win_stack
391) {
392 MERROR_RETVAL retval = MERROR_OK;
393 char lbuffer[RETROCON_LBUFFER_SZ_MAX + 1] = { 0 };
394
395 *p_idc_out = RETROGUI_IDC_NONE;
396
397 if( *p_c == RETROCON_ACTIVE_KEY ) {
398 debug_printf( RETROCON_TRACE_LVL, "active key pressed" );
399 if( RETROCON_FLAG_ACTIVE != (RETROCON_FLAG_ACTIVE & (con)->flags) ) {
400 debug_printf( RETROCON_TRACE_LVL, "opening console..." );
401 (con)->flags |= RETROCON_FLAG_ACTIVE;
402 (con)->gui.flags |= RETROGUI_FLAGS_DIRTY;
403
404# ifdef RETROFLAT_OPENGL
405 retval = retro3dw_push_win(
406 &((con)->gui), win_stack,
407 *p_idc_out, NULL, (con)->gui.x, (con)->gui.y,
408 (con)->gui.w, (con)->gui.h, 0 );
409 maug_cleanup_if_not_ok();
410# endif /* RETROFLAT_OPENGL */
411
412 debug_printf( RETROCON_TRACE_LVL, "console open!" );
413 } else {
414 debug_printf( RETROCON_TRACE_LVL, "closing console..." );
415 con->flags &= ~RETROCON_FLAG_ACTIVE;
416
417# ifdef RETROFLAT_OPENGL
418
419 retro3dw_destroy_win( win_stack, *p_idc_out );
420# endif /* RETROFLAT_OPENGL */
421 debug_printf( RETROCON_TRACE_LVL, "console closed!" );
422
423 /* Return, in case the caller needs to do something with this. */
424 *p_idc_out = RETROCON_IDC_CLOSE;
425 }
426 *p_c = 0;
427 goto cleanup;
428 } else if( RETROCON_FLAG_ACTIVE != (RETROCON_FLAG_ACTIVE & (con)->flags) ) {
429 goto cleanup;
430 }
431
432 /* debug_printf( RETROCON_TRACE_LVL, "processing console input..." ); */
433
434 retrogui_lock( &(con->gui) );
435
436 *p_idc_out = retrogui_poll_ctls( &(con->gui), p_c, input_evt );
437
438 retrogui_unlock( &(con->gui) );
439
440 *p_c = 0; /* If we got this far then don't pass keystroke back. */
441
442 if( RETROCON_IDC_TEXTBOX == *p_idc_out ) {
443 retrogui_lock( &(con->gui) );
444 retval = retrogui_get_ctl_text(
445 &(con->gui), RETROCON_IDC_TEXTBOX, lbuffer, RETROCON_LBUFFER_SZ_MAX );
446 retval = retrogui_set_ctl_text(
447 &(con->gui), RETROCON_IDC_TEXTBOX, 1, "" );
448 retrogui_unlock( &(con->gui) );
449 maug_cleanup_if_not_ok();
450
451 if( 0 == maug_strlen( lbuffer ) ) {
452 /* Do nothing if line is empty. */
453 goto cleanup;
454 }
455
456 /* Execute/reset line. */
457 retval = retrocon_exec_line( con, lbuffer, maug_strlen( lbuffer ) );
458 }
459
460#if 0
461 /* Debounce retrocon track only! */
462 if( !retrocon_debounce( con, c ) ) {
463 goto cleanup;
464 }
465
466 /* Process input. */
467 switch( c ) {
468 case RETROCON_ACTIVE_KEY:
469 if( RETROCON_FLAG_ACTIVE == (RETROCON_FLAG_ACTIVE & con->flags) ) {
470 con->flags &= ~RETROCON_FLAG_ACTIVE;
471 } else {
472 con->flags |= RETROCON_FLAG_ACTIVE;
473 }
474 break;
475
476 case 0:
477 break;
478
479 case 0x08:
480 /* Backspace. */
481 if( 0 < con->lbuffer_sz ) {
482 con->lbuffer_sz--;
483 con->lbuffer[con->lbuffer_sz] = '\0';
484 }
485 break;
486
487 case '\r':
488 case '\n':
489 if( 0 == con->lbuffer_sz ) {
490 /* Do nothing if line is empty. */
491 break;
492 }
493
494 /* Execute/reset line. */
495 retval = retrocon_exec_line( con, con->lbuffer, con->lbuffer_sz );
496 con->lbuffer_sz = 0;
497 con->lbuffer[con->lbuffer_sz] = '\0';
498 break;
499
500 default:
501 c = retroflat_vk_to_ascii(
502 c, input_evt->key_flags | RETROFLAT_INPUT_FORCE_UPPER );
503 if(
504 /* Active and printable chars get added to line buffer. */
505 RETROCON_FLAG_ACTIVE == (RETROCON_FLAG_ACTIVE & con->flags) &&
506 0 < c
507 ) {
508 con->lbuffer[con->lbuffer_sz++] = c;
509 con->lbuffer[con->lbuffer_sz] = '\0';
510 }
511 break;
512 }
513#endif
514
515cleanup:
516
517 return retval;
518}
519
520MERROR_RETVAL retrocon_display(
521 struct RETROCON* con, struct RETROFLAT_BITMAP* gui_bmp
522) {
523 MERROR_RETVAL retval = MERROR_OK;
524
525 if( RETROCON_FLAG_ACTIVE != (RETROCON_FLAG_ACTIVE & (con)->flags) ) {
526 goto cleanup;
527 }
528
529 (con)->gui.draw_bmp = (gui_bmp);
530 (con)->gui.flags |= RETROGUI_FLAGS_DIRTY;
531
532 retrogui_lock( &((con)->gui) );
533 retrogui_redraw_ctls( &((con)->gui) );
534 retrogui_unlock( &((con)->gui) );
535
536cleanup:
537
538 return retval;
539}
540
541void retrocon_shutdown( struct RETROCON* con ) {
542#ifndef RETROGXC_PRESENT
543 maug_mfree( con->gui.font_h );
544#endif /* !RETROGXC_PRESENT */
545 retrogui_free( &(con->gui) );
546}
547
548#endif /* RETROCON_C */
549
550 /* maug_console */
551
552#endif /* RETROCON_DISABLE */
553
554#endif /* !RETROCON_H */
555
MERROR_RETVAL retrocon_input(struct RETROCON *con, RETROFLAT_IN_KEY *p_c, struct RETROFLAT_INPUT *input_evt, retrogui_idc_t *p_idc_out, struct MDATA_VECTOR *win_stack)
Process input from retroflat_poll_input() and apply it to the console, if open.
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_string(struct RETROFLAT_BITMAP *target, const RETROFLAT_COLOR color, const char *str, int str_sz, const char *font_str, int16_t x_orig, int16_t y_orig, uint8_t flags)
Draw a text string at the specified location in the specified font and color on the target RETROFLAT_...
#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
#define retroflat_quit(retval_in)
This should be called in order to quit a program using RetroFlat.
Definition retpltd.h:47
Definition retrocon.h:88
Platform-specific bitmap structure. retroflat_bitmap_ok() can be used on a pointer to it to determine...
Definition retpltd.h:21
Struct passed to retroflat_poll_input() to hold return data.
Definition retroflt.h:836
Definition retrogui.h:167
Definition retrogui.h:158