Nilorea Library
C utilities for networking, threading, graphics
Loading...
Searching...
No Matches
ex_gui_dictionary.c
1
7#define WIDTH 1280
8#define HEIGHT 800
9
10#define ALLEGRO_UNSTABLE 1
11
12#include "nilorea/n_common.h"
13#include "nilorea/n_list.h"
14#include "nilorea/n_hash.h"
15#include "nilorea/n_pcre.h"
16#include "nilorea/n_str.h"
17#include "nilorea/n_allegro5.h"
18#include <allegro5/allegro_ttf.h>
19
20/* dictionnaries are from https://www.bragitoff.com/2016/03/english-dictionary-in-csv-format/ */
21
22ALLEGRO_DISPLAY *display = NULL ;
23
24int DONE = 0, /* Flag to check if we are always running */
25 getoptret = 0, /* launch parameter check */
26 log_level = LOG_INFO ; /* default LOG_LEVEL */
27
28ALLEGRO_BITMAP *scr_buf = NULL ;
29
30ALLEGRO_TIMER *fps_timer = NULL ;
31ALLEGRO_TIMER *logic_timer = NULL ;
32
33
34int main( int argc, char *argv[] )
35{
36 set_log_level( log_level );
37
38 n_log( LOG_NOTICE, "%s is starting ...", argv[ 0 ] );
39
40
41 /* allegro 5 + addons loading */
42 if (!al_init())
43 {
44 n_abort("Could not init Allegro.\n");
45 }
46 if (!al_init_image_addon())
47 {
48 n_abort("Unable to initialize image addon\n");
49 }
50 if (!al_init_primitives_addon() )
51 {
52 n_abort("Unable to initialize primitives addon\n");
53 }
54 if( !al_init_font_addon() )
55 {
56 n_abort("Unable to initialize font addon\n");
57 }
58 if( !al_init_ttf_addon() )
59 {
60 n_abort("Unable to initialize ttf_font addon\n");
61 }
62 if( !al_install_keyboard() )
63 {
64 n_abort("Unable to initialize keyboard handler\n");
65 }
66 if( !al_install_mouse())
67 {
68 n_abort("Unable to initialize mouse handler\n");
69 }
70 ALLEGRO_EVENT_QUEUE *event_queue = NULL;
71
72 event_queue = al_create_event_queue();
73 if(!event_queue)
74 {
75 fprintf(stderr, "failed to create event_queue!\n");
76 al_destroy_display(display);
77 return -1;
78 }
79
80 char ver_str[ 128 ] = "" ;
81 while( ( getoptret = getopt( argc, argv, "hvV:L:" ) ) != EOF )
82 {
83 switch( getoptret )
84 {
85 case 'h':
86 n_log( LOG_NOTICE, "\n %s -h help -v version -V LOG_LEVEL (NOLOG,INFO,NOTICE,ERR,DEBUG) -L OPT_LOG_FILE\n", argv[ 0 ] );
87 exit( TRUE );
88 case 'v':
89 sprintf( ver_str, "%s %s", __DATE__, __TIME__ );
90 exit( TRUE );
91 break ;
92 case 'V':
93 if( !strncmp( "INFO", optarg, 6 ) )
94 {
95 log_level = LOG_INFO ;
96 }
97 else
98 {
99 if( !strncmp( "NOTICE", optarg, 7 ) )
100 {
101 log_level = LOG_NOTICE ;
102 }
103 else
104 {
105 if( !strncmp( "ERR", optarg, 5 ) )
106 {
107 log_level = LOG_ERR ;
108 }
109 else
110 {
111 if( !strncmp( "DEBUG", optarg, 5 ) )
112 {
113 log_level = LOG_DEBUG ;
114 }
115 else
116 {
117 n_log( LOG_ERR, "%s is not a valid log level\n", optarg );
118 exit( FALSE );
119 }
120 }
121 }
122 }
123 n_log( LOG_NOTICE, "LOG LEVEL UP TO: %d\n", log_level );
124 set_log_level( log_level );
125 break;
126 case 'L' :
127 n_log( LOG_NOTICE, "LOG FILE: %s\n", optarg );
128 set_log_file( optarg );
129 break ;
130 case '?' :
131 {
132 switch( optopt )
133 {
134 case 'V' :
135 n_log( LOG_ERR, "\nPlease specify a log level after -V. \nAvailable values: NOLOG,VERBOSE,NOTICE,ERROR,DEBUG\n\n" );
136 break;
137 case 'L' :
138 n_log( LOG_ERR, "\nPlease specify a log file after -L\n" );
139 default:
140 break;
141 }
142 }
143 __attribute__ ((fallthrough));
144 default:
145 n_log( LOG_ERR, "\n %s -h help -v version -V DEBUGLEVEL (NOLOG,VERBOSE,NOTICE,ERROR,DEBUG) -L logfile\n", argv[ 0 ] );
146 exit( FALSE );
147 }
148 }
149
150 double fps = 60.0 ;
151 double fps_delta_time = 1.0 / fps ;
152 double logic_delta_time = 1.0 / (5.0 * fps);
153
154 fps_timer = al_create_timer( fps_delta_time );
155 logic_timer = al_create_timer( logic_delta_time );
156
157 al_set_new_display_flags( ALLEGRO_OPENGL|ALLEGRO_WINDOWED );
158 display = al_create_display( WIDTH, HEIGHT );
159 if( !display )
160 {
161 n_abort("Unable to create display\n");
162 }
163 al_set_window_title( display, argv[ 0 ] );
164
165 al_set_new_bitmap_flags( ALLEGRO_VIDEO_BITMAP );
166
167 DONE = 0 ;
168
169 enum APP_KEYS
170 {
171 KEY_ESC
172 };
173 int key[ 1 ] = {false};
174
175 al_register_event_source(event_queue, al_get_display_event_source(display));
176 al_start_timer( fps_timer );
177 al_start_timer( logic_timer );
178 al_register_event_source(event_queue, al_get_timer_event_source(fps_timer));
179 al_register_event_source(event_queue, al_get_timer_event_source(logic_timer));
180
181 al_register_event_source(event_queue, al_get_keyboard_event_source());
182 al_register_event_source(event_queue, al_get_mouse_event_source());
183
184 ALLEGRO_FONT *font = NULL ;
185 font = al_load_font( "DATAS/2Dumb.ttf", 24 , 0 );
186 if (! font )
187 {
188 n_log( LOG_ERR, "Unable to load DATAS/2Dumb.ttf" );
189 exit( 1 );
190 }
191
192 ALLEGRO_BITMAP *scrbuf = al_create_bitmap( WIDTH, HEIGHT );
193
194 al_hide_mouse_cursor(display);
195
196 int mx = 0, my = 0, mz = 0 ;
197 int mouse_b1 = 0, mouse_b2 = 0 ;
198 int do_draw = 0, do_logic = 0 ;
199
201 typedef struct DICTIONARY_DEFINITION
202 {
204 char *type ;
206 char *definition ;
207 } DICTIONARY_DEFINITION;
208
210 typedef struct DICTIONARY_ENTRY
211 {
213 char *key ;
215 LIST *definitions ;
216 } DICTIONARY_ENTRY ;
217
218 void free_entry_def( void *entry_def )
219 {
220 DICTIONARY_DEFINITION *def = (DICTIONARY_DEFINITION *)entry_def;
221 FreeNoLog( def -> type );
222 FreeNoLog( def -> definition );
223 FreeNoLog( def );
224 }
225 void free_entry( void *entry_ptr )
226 {
227 DICTIONARY_ENTRY *entry = (DICTIONARY_ENTRY *)entry_ptr;
228 list_destroy( &entry -> definitions );
229 FreeNoLog( entry -> key );
230 FreeNoLog( entry );
231 }
232
233 /* Load dictionaries */
234 HASH_TABLE *dictionary = new_ht_trie( 256 , 32 );
235 FILE *dict_file = fopen( "DATAS/dictionary.csv" , "r" );
236 char read_buf[ 16384 ] = "" ;
237 char *entry_key = NULL ;
238 char *type = NULL ;
239 char *definition = NULL ;
240 N_PCRE *dico_regexp = npcre_new ( "\"(.*)\",\"(.*)\",\"(.*)\"" , 99 , 0 );
241
242 while( fgets( read_buf , 16384 , dict_file ) )
243 {
244 if( npcre_match( read_buf , dico_regexp ) )
245 {
246 entry_key = strdup( _str( dico_regexp -> match_list[ 1 ] ) );
247 type = strdup( _str( dico_regexp -> match_list[ 2 ] ) );
248 definition = strdup( _str( dico_regexp -> match_list[ 3 ] ) );
249
250 n_log( LOG_DEBUG , "matched %s , %s , %s" , entry_key , type , definition );
251
252 DICTIONARY_ENTRY *entry = NULL ;
253 DICTIONARY_DEFINITION *entry_def = NULL ;
254
255 if( ht_get_ptr( dictionary , entry_key , (void **)&entry ) == TRUE )
256 {
257 Malloc( entry_def , DICTIONARY_DEFINITION , 1 );
258 entry_def -> type = strdup( type );
259 entry_def -> definition = strdup( definition );
260 list_push( entry -> definitions , entry_def , &free_entry_def );
261 }
262 else
263 {
264 Malloc( entry , DICTIONARY_ENTRY , 1 );
265
266 entry -> definitions = new_generic_list( 0 );
267 entry -> key = strdup( entry_key );
268
269 Malloc( entry_def , DICTIONARY_DEFINITION , 1 );
270
271 entry_def -> type = strdup( type );
272 entry_def -> definition = strdup( definition );
273
274 list_push( entry -> definitions , entry_def , &free_entry_def );
275
276 ht_put_ptr( dictionary , entry_key , entry , &free_entry );
277 }
278 FreeNoLog( entry_key );
279 FreeNoLog( type );
280 FreeNoLog( definition );
281
282 npcre_clean_match( dico_regexp );
283 }
284 }
285 fclose( dict_file );
286
287 ALLEGRO_USTR *keyboard_buffer = al_ustr_new( "" );
288 LIST *completion = NULL ;
289 int key_pressed = 0 ;
290 n_log( LOG_NOTICE , "Starting main loop" );
291
292 al_clear_keyboard_state( NULL );
293 al_flush_event_queue( event_queue );
294
295 int max_results = 100 ;
296 completion = ht_get_completion_list( dictionary , al_cstr( keyboard_buffer ) , max_results );
297
298 do
299 {
300 do
301 {
302 ALLEGRO_EVENT ev ;
303
304 al_wait_for_event(event_queue, &ev);
305
306 if(ev.type == ALLEGRO_EVENT_KEY_DOWN)
307 {
308 switch(ev.keyboard.keycode)
309 {
310 case ALLEGRO_KEY_ESCAPE:
311 key[KEY_ESC] = 1 ;
312 break;
313 default:
314 break;
315 }
316 }
317 else if(ev.type == ALLEGRO_EVENT_KEY_UP)
318 {
319 switch(ev.keyboard.keycode)
320 {
321 case ALLEGRO_KEY_ESCAPE:
322 key[KEY_ESC] = 0 ;
323 break;
324 default:
325 break;
326 }
327 }
328 else if( ev.type == ALLEGRO_EVENT_TIMER )
329 {
330 if( al_get_timer_event_source( fps_timer ) == ev.any.source )
331 {
332 do_draw = 1 ;
333 }
334 else if( al_get_timer_event_source( logic_timer ) == ev.any.source )
335 {
336 do_logic = 1;
337 }
338 }
339 else if( ev.type == ALLEGRO_EVENT_MOUSE_AXES )
340 {
341 mx = ev.mouse.x;
342 my = ev.mouse.y;
343 mz -= ev.mouse.dz;
344 if( mz < 0 ) mz = 0 ;
345 }
346 else if( ev.type == ALLEGRO_EVENT_MOUSE_BUTTON_DOWN )
347 {
348 if( ev.mouse.button == 1 )
349 mouse_b1 = 1 ;
350 if( ev.mouse.button == 2 )
351 mouse_b2 = 1 ;
352 }
353 else if( ev.type == ALLEGRO_EVENT_MOUSE_BUTTON_UP )
354 {
355 if( ev.mouse.button == 1 )
356 mouse_b1 = 0 ;
357 if( ev.mouse.button == 2 )
358 mouse_b2 = 0 ;
359 }
360 else if( ev.type == ALLEGRO_EVENT_DISPLAY_SWITCH_IN || ev.type == ALLEGRO_EVENT_DISPLAY_SWITCH_OUT )
361 {
362 al_clear_keyboard_state( display );
363 al_flush_event_queue( event_queue );
364 }
365 else
366 {
367 /* Processing inputs */
368 if( get_keyboard( keyboard_buffer , ev ) == TRUE )
369 key_pressed = 1 ;
370 }
371 }while( !al_is_event_queue_empty( event_queue) );
372
373 if( do_logic == 1 )
374 {
375 if( key_pressed == 1 )
376 {
377 key_pressed = 0 ;
378 mz = 0 ;
379 if( completion )
380 {
381 list_destroy( &completion );
382 }
383 completion = ht_get_completion_list( dictionary , al_cstr( keyboard_buffer ) , max_results );
384 }
385
386 if( mouse_b1==1 )
387 {
388 if( completion )
389 {
390 int skip_entry = mz ;
391 if( skip_entry >= completion -> nb_items )
392 {
393 skip_entry = completion -> nb_items - 1 ;
394 mz = skip_entry ;
395 }
396 char *key = NULL ;
397 list_foreach( node , completion )
398 {
399 skip_entry -- ;
400 key = (char *)node -> ptr ;
401
402 if( skip_entry < 0 )
403 {
404 break ;
405 }
406 }
407 al_ustr_free( keyboard_buffer );
408 keyboard_buffer = al_ustr_new( key );
409 }
410 completion = ht_get_completion_list( dictionary , al_cstr( keyboard_buffer ) , max_results );
411 mz = 0 ;
412 mouse_b1 = 0 ;
413 }
414 if( mouse_b2==1 )
415 {
416 int pos = (int)al_ustr_size( keyboard_buffer );
417 if( al_ustr_prev( keyboard_buffer , &pos ) )
418 {
419 al_ustr_truncate( keyboard_buffer , pos );
420 }
421 completion = ht_get_completion_list( dictionary , al_cstr( keyboard_buffer ) , max_results );
422 mouse_b2 = 0 ;
423 }
424
425 do_logic = 0 ;
426 }
427
428 if( do_draw == 1 )
429 {
430 static int last_time = 0 ;
431
432 al_acknowledge_resize( display );
433 //int w = al_get_display_width( display );
434 //int h = al_get_display_height( display );
435
436 al_set_target_bitmap( scrbuf );
437 al_clear_to_color( al_map_rgba( 0, 0, 0, 255 ) );
438
439 last_time -= 1000000/30.0 ;
440 static int length = 0 ;
441 if( last_time < 0 )
442 {
443 last_time = 250000 ;
444 }
445 else
446 {
447 length = al_get_text_width( font , al_cstr( keyboard_buffer ) );
448 al_draw_filled_rectangle( WIDTH / 2 + ( length + 6 ) / 2 , 50 ,
449 WIDTH / 2 + ( length + 6 ) / 2 + 15 , 70 ,
450 al_map_rgb( 0 , 128 , 0 ) );
451 }
452 int input_size = al_get_text_width( font , al_cstr( keyboard_buffer ) );
453 al_draw_text( font , al_map_rgb( 0 , 255 , 0 ) , (WIDTH / 2) - (input_size / 2), 50 , ALLEGRO_ALIGN_LEFT , al_cstr( keyboard_buffer ) );
454
455 DICTIONARY_ENTRY *entry = NULL ;
456
457 if( completion )
458 {
459 int pos_x = (WIDTH / 2) + (input_size / 2) + 50 ;
460 int pos_y = 50 ;
461 int skip_entry = mz ;
462 if( skip_entry >= completion -> nb_items )
463 {
464 skip_entry = completion -> nb_items - 1 ;
465 mz = skip_entry ;
466 }
467
468 list_foreach( node , completion )
469 {
470 if( skip_entry > 0 )
471 {
472 skip_entry -- ;
473 continue ;
474 }
475 char *key = (char *)node -> ptr ;
476 al_draw_text( font , al_map_rgb( 230 , 230 , 0 ) , pos_x , pos_y , ALLEGRO_ALIGN_LEFT , key );
477 pos_y += 35 ;
478 }
479 }
480
481 if( ht_get_ptr( dictionary , al_cstr( keyboard_buffer ) , (void **)&entry ) == TRUE )
482 {
483 int vertical_it = 0 ;
484 list_foreach( node , entry -> definitions )
485 {
486 DICTIONARY_DEFINITION *definition = (DICTIONARY_DEFINITION *)node -> ptr ;
487 al_draw_multiline_textf( font , al_map_rgb( 0 , 255 , 0 ) , 10 , 100 + vertical_it , WIDTH - 10 , 20 , ALLEGRO_ALIGN_LEFT , "%s : %s" , definition -> type , definition -> definition );
488 vertical_it += 50 ;
489 }
490 }
491
492 al_set_target_bitmap( al_get_backbuffer( display ) );
493 al_draw_bitmap( scrbuf, 0, 0, 0 );
494
495 /* mouse pointer */
496 al_draw_line( mx - 5, my, mx + 5, my, al_map_rgb( 255, 0, 0 ), 1 );
497 al_draw_line( mx, my + 5, mx, my - 5, al_map_rgb( 255, 0, 0 ), 1 );
498
499 al_flip_display();
500 do_draw = 0 ;
501 }
502
503 }
504 while( !key[KEY_ESC] && !DONE );
505
506 destroy_ht( &dictionary );
507
508 return 0;
509}
int get_keyboard(ALLEGRO_USTR *str, ALLEGRO_EVENT event)
update a keyboard buffer from an event
Definition n_allegro5.c:19
#define FreeNoLog(__ptr)
Free Handler without log.
Definition n_common.h:276
#define Malloc(__ptr, __struct, __size)
Malloc Handler to get errors and set to 0.
Definition n_common.h:191
#define _str(__PTR)
define true
Definition n_common.h:180
void n_abort(char const *format,...)
abort program with a text
Definition n_common.c:40
int ht_get_ptr(HASH_TABLE *table, const char *key, void **val)
get pointer at 'key' from 'table'
Definition n_hash.c:2283
int destroy_ht(HASH_TABLE **table)
empty a table and destroy it
Definition n_hash.c:2449
LIST * ht_get_completion_list(HASH_TABLE *table, const char *keybud, size_t max_results)
get next matching keys in table tree
Definition n_hash.c:2631
HASH_TABLE * new_ht_trie(size_t alphabet_length, size_t alphabet_offset)
create a TRIE hash table with the alphabet_size, each key value beeing decreased by alphabet_offset
Definition n_hash.c:2124
int ht_put_ptr(HASH_TABLE *table, const char *key, void *ptr, void(*destructor)(void *ptr))
put a pointer to the string value with given key in the targeted hash table
Definition n_hash.c:2348
structure of a hash table
Definition n_hash.h:108
int list_push(LIST *list, void *ptr, void(*destructor)(void *ptr))
Add a pointer to the end of the list.
Definition n_list.c:244
#define list_foreach(__ITEM_, __LIST_)
ForEach macro helper.
Definition n_list.h:70
int list_destroy(LIST **list)
Empty and Free a list container.
Definition n_list.c:605
LIST * new_generic_list(int max_items)
Initialiaze a generic list container to max_items pointers.
Definition n_list.c:20
Structure of a generic LIST container.
Definition n_list.h:45
#define n_log(__LEVEL__,...)
Logging function wrapper to get line and func.
Definition n_log.h:74
#define LOG_DEBUG
debug-level messages
Definition n_log.h:66
#define LOG_ERR
error conditions
Definition n_log.h:58
int set_log_file(char *file)
Set the logging to a file instead of stderr.
Definition n_log.c:135
void set_log_level(const int log_level)
Set the global log level value ( static int LOG_LEVEL )
Definition n_log.c:97
#define LOG_NOTICE
normal but significant condition
Definition n_log.h:62
#define LOG_INFO
informational
Definition n_log.h:64
N_PCRE * npcre_new(char *str, int max_cap, int flags)
From pcre doc, the flag bits are: PCRE_ANCHORED Force pattern anchoring PCRE_AUTO_CALLOUT Compile aut...
Definition n_pcre.c:59
int npcre_match(char *str, N_PCRE *pcre)
Return TRUE if str matches regexp, and make captures up to max_cap.
Definition n_pcre.c:165
int npcre_clean_match(N_PCRE *pcre)
clean the match list of the last capture, if any
Definition n_pcre.c:144
N_PCRE structure.
Definition n_pcre.h:29
Allegro5 helpers.
Common headers and low-level hugly functions & define.
Hash functions and table.
List structures and definitions.
PCRE helpers for regex matching.
N_STR and string function declaration.