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