Nilorea Library
C utilities for networking, threading, graphics
Loading...
Searching...
No Matches
ex_gui_dictionary.c

Nilorea Library gui dictionary search using n_gui widgets.

Nilorea Library gui dictionary search using n_gui widgets

Author
Castagnier Mickael
Version
2.0
Date
10/02/2020
/*
* Nilorea Library
* Copyright (C) 2005-2026 Castagnier Mickael
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#define WIDTH 800
#define HEIGHT 800
#define ALLEGRO_UNSTABLE 1
#include "nilorea/n_list.h"
#include "nilorea/n_hash.h"
#include "nilorea/n_pcre.h"
#include "nilorea/n_str.h"
#include "nilorea/n_gui.h"
#include <allegro5/allegro_ttf.h>
/* dictionnaries are from https://www.bragitoff.com/2016/03/english-dictionary-in-csv-format/ */
ALLEGRO_DISPLAY* display = NULL;
int DONE = 0, /* Flag to check if we are always running */
getoptret = 0, /* launch parameter check */
log_level = LOG_INFO; /* default LOG_LEVEL */
ALLEGRO_TIMER* fps_timer = NULL;
ALLEGRO_TIMER* logic_timer = NULL;
typedef struct DICTIONARY_DEFINITION {
char* type;
char* definition;
typedef struct DICTIONARY_ENTRY {
char* key;
/* application state */
static HASH_TABLE* dictionary = NULL;
static LIST* completion = NULL;
static size_t max_results = 100;
static char last_search[4096] = "";
/* GUI widget ids */
static int search_textarea_id = -1;
static int completion_listbox_id = -1;
static int definition_label_id = -1;
static int definition_win_id = -1;
static int status_win_id = -1;
static int status_label_id = -1;
/* forward declarations */
static void update_completion(N_GUI_CTX* gui, const char* text);
static void update_definitions(N_GUI_CTX* gui, const char* word);
void free_entry_def(void* entry_def) {
FreeNoLog(def->type);
FreeNoLog(def);
}
void free_entry(void* entry_ptr) {
DICTIONARY_ENTRY* entry = (DICTIONARY_ENTRY*)entry_ptr;
FreeNoLog(entry->key);
FreeNoLog(entry);
}
/* callback: search text changed */
void on_search_change(int widget_id, const char* text, void* user_data) {
(void)widget_id;
N_GUI_CTX* gui = (N_GUI_CTX*)user_data;
}
/* callback: completion list selection */
void on_completion_select(int widget_id, int index, int selected, void* user_data) {
(void)widget_id;
if (!selected) return;
N_GUI_CTX* gui = (N_GUI_CTX*)user_data;
const char* item_text = n_gui_listbox_get_item_text(gui, completion_listbox_id, index);
if (item_text) {
update_completion(gui, item_text);
update_definitions(gui, item_text);
}
}
/* callback: clear button */
void on_clear_click(int widget_id, void* user_data) {
(void)widget_id;
N_GUI_CTX* gui = (N_GUI_CTX*)user_data;
}
static void update_completion(N_GUI_CTX* gui, const char* text) {
if (strcmp(text, last_search) == 0) return;
strncpy(last_search, text, sizeof(last_search) - 1);
last_search[sizeof(last_search) - 1] = '\0';
if (completion) {
}
if (completion) {
char* entry_key = (char*)node->ptr;
}
}
}
static void update_definitions(N_GUI_CTX* gui, const char* word) {
DICTIONARY_ENTRY* entry = NULL;
if (ht_get_ptr(dictionary, word, (void**)&entry) == TRUE) {
char buf[16384] = "";
size_t offset = 0;
list_foreach(node, entry->definitions) {
int written = snprintf(buf + offset, sizeof(buf) - offset, "%s : %s\n", def->type, def->definition);
if (written > 0) offset += (size_t)written;
if (offset >= sizeof(buf) - 1) break;
}
} else {
}
}
int main(int argc, char* argv[]) {
n_log(LOG_NOTICE, "%s is starting ...", argv[0]);
/* allegro 5 + addons loading */
if (!al_init()) {
n_abort("Could not init Allegro.\n");
}
if (!al_init_image_addon()) {
n_abort("Unable to initialize image addon\n");
}
if (!al_init_primitives_addon()) {
n_abort("Unable to initialize primitives addon\n");
}
if (!al_init_font_addon()) {
n_abort("Unable to initialize font addon\n");
}
if (!al_init_ttf_addon()) {
n_abort("Unable to initialize ttf_font addon\n");
}
if (!al_install_keyboard()) {
n_abort("Unable to initialize keyboard handler\n");
}
if (!al_install_mouse()) {
n_abort("Unable to initialize mouse handler\n");
}
ALLEGRO_EVENT_QUEUE* event_queue = NULL;
event_queue = al_create_event_queue();
if (!event_queue) {
fprintf(stderr, "failed to create event_queue!\n");
al_destroy_display(display);
return -1;
}
char ver_str[128] = "";
while ((getoptret = getopt(argc, argv, "hvV:L:")) != EOF) {
switch (getoptret) {
case 'h':
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]);
exit(TRUE);
case 'v':
sprintf(ver_str, "%s %s", __DATE__, __TIME__);
exit(TRUE);
break;
case 'V':
if (!strncmp("INFO", optarg, 6)) {
} else {
if (!strncmp("NOTICE", optarg, 7)) {
} else {
if (!strncmp("ERR", optarg, 5)) {
} else {
if (!strncmp("DEBUG", optarg, 5)) {
} else {
n_log(LOG_ERR, "%s is not a valid log level\n", optarg);
exit(FALSE);
}
}
}
}
n_log(LOG_NOTICE, "LOG LEVEL UP TO: %d\n", log_level);
break;
case 'L':
n_log(LOG_NOTICE, "LOG FILE: %s\n", optarg);
set_log_file(optarg);
break;
case '?': {
switch (optopt) {
case 'V':
n_log(LOG_ERR, "\nPlease specify a log level after -V. \nAvailable values: NOLOG,VERBOSE,NOTICE,ERROR,DEBUG\n\n");
break;
case 'L':
n_log(LOG_ERR, "\nPlease specify a log file after -L\n");
default:
break;
}
}
__attribute__((fallthrough));
default:
n_log(LOG_ERR, "\n %s -h help -v version -V DEBUGLEVEL (NOLOG,VERBOSE,NOTICE,ERROR,DEBUG) -L logfile\n", argv[0]);
exit(FALSE);
}
}
double fps = 60.0;
double fps_delta_time = 1.0 / fps;
fps_timer = al_create_timer(fps_delta_time);
al_set_new_display_flags(ALLEGRO_OPENGL | ALLEGRO_WINDOWED);
display = al_create_display(WIDTH, HEIGHT);
if (!display) {
n_abort("Unable to create display\n");
}
al_set_window_title(display, argv[0]);
al_set_new_bitmap_flags(ALLEGRO_VIDEO_BITMAP);
DONE = 0;
enum APP_KEYS {
KEY_ESC
};
int key[1] = {false};
al_register_event_source(event_queue, al_get_display_event_source(display));
al_start_timer(fps_timer);
al_register_event_source(event_queue, al_get_timer_event_source(fps_timer));
al_register_event_source(event_queue, al_get_keyboard_event_source());
al_register_event_source(event_queue, al_get_mouse_event_source());
ALLEGRO_FONT* font = NULL;
font = al_load_font("DATAS/2Dumb.ttf", 18, 0);
if (!font) {
n_log(LOG_ERR, "Unable to load DATAS/2Dumb.ttf, using builtin font");
font = al_create_builtin_font();
}
int do_draw = 0;
/* Load dictionaries */
dictionary = new_ht_trie(256, 32);
FILE* dict_file = fopen("DATAS/dictionary.csv", "r");
if (!dict_file) {
n_abort("Unable to open DATAS/dictionary.csv\n");
}
char read_buf[16384] = "";
char* entry_key = NULL;
char* type = NULL;
char* definition = NULL;
N_PCRE* dico_regexp = npcre_new("\"(.*)\",\"(.*)\",\"(.*)\"", 0);
while (fgets(read_buf, 16384, dict_file)) {
if (npcre_match_capture(read_buf, dico_regexp)) {
entry_key = strdup(_str((char*)dico_regexp->match_list[1]));
type = strdup(_str((char*)dico_regexp->match_list[2]));
definition = strdup(_str((char*)dico_regexp->match_list[3]));
// n_log(LOG_DEBUG, "matched %s , %s , %s", entry_key, type, definition);
DICTIONARY_ENTRY* entry = NULL;
DICTIONARY_DEFINITION* entry_def = NULL;
if (ht_get_ptr(dictionary, entry_key, (void**)&entry) == TRUE) {
Malloc(entry_def, DICTIONARY_DEFINITION, 1);
entry_def->type = strdup(type);
entry_def->definition = strdup(definition);
list_push(entry->definitions, entry_def, &free_entry_def);
} else {
entry->definitions = new_generic_list(MAX_LIST_ITEMS);
entry->key = strdup(entry_key);
Malloc(entry_def, DICTIONARY_DEFINITION, 1);
entry_def->type = strdup(type);
entry_def->definition = strdup(definition);
list_push(entry->definitions, entry_def, &free_entry_def);
ht_put_ptr(dictionary, entry_key, entry, &free_entry, NULL);
}
FreeNoLog(entry_key);
FreeNoLog(type);
FreeNoLog(definition);
npcre_clean_match(dico_regexp);
}
}
fclose(dict_file);
npcre_delete(&dico_regexp);
n_log(LOG_NOTICE, "Dictionary loaded, starting GUI");
/* ---- Create GUI ---- */
/* set display size for global scrollbars (shown when GUI exceeds display) */
/* enable virtual canvas for resolution-independent scaling */
/* --- Search Window --- */
int search_win = n_gui_add_window(gui, "Search", 20, 20, 400, 85);
n_gui_add_label(gui, search_win, "Type to search:", 10, 5, 280, 20, N_GUI_ALIGN_LEFT);
search_textarea_id = n_gui_add_textarea(gui, search_win, 10, 28, 300, 24, 0, 256, on_search_change, gui);
n_gui_add_button(gui, search_win, "Clear", 320, 28, 70, 24, N_GUI_SHAPE_ROUNDED, on_clear_click, gui);
/* --- Completion Window --- */
int completion_win = n_gui_add_window(gui, "Completions", 440, 20, 350, 690);
/* --- Definition Window --- */
definition_win_id = n_gui_add_window(gui, "Definition", 20, 120, 400, 590);
/* --- Status Bar Window --- */
status_win_id = n_gui_add_window(gui, "Help", 20, 720, 770, 60);
status_label_id = n_gui_add_label(gui, status_win_id, "Type in Search box | Click completions to select | ESC to quit", 5, 2, 760, 20, N_GUI_ALIGN_LEFT);
/* initial completion */
strncpy(last_search, "a", sizeof(last_search) - 1);
al_clear_keyboard_state(NULL);
al_flush_event_queue(event_queue);
do {
ALLEGRO_EVENT ev;
al_wait_for_event(event_queue, &ev);
/* pass events to the GUI.
* Use gui_handled to prevent mouse events from reaching game logic
* when the cursor is over a GUI window or widget. */
int gui_handled = n_gui_process_event(gui, ev);
(void)gui_handled;
if (ev.type == ALLEGRO_EVENT_KEY_DOWN) {
switch (ev.keyboard.keycode) {
case ALLEGRO_KEY_ESCAPE:
key[KEY_ESC] = 1;
break;
default:
break;
}
} else if (ev.type == ALLEGRO_EVENT_DISPLAY_CLOSE) {
DONE = 1;
} else if (ev.type == ALLEGRO_EVENT_DISPLAY_RESIZE) {
al_acknowledge_resize(display);
n_gui_set_display_size(gui, (float)al_get_display_width(display),
(float)al_get_display_height(display));
} else if (ev.type == ALLEGRO_EVENT_DISPLAY_SWITCH_IN || ev.type == ALLEGRO_EVENT_DISPLAY_SWITCH_OUT) {
al_clear_keyboard_state(display);
al_flush_event_queue(event_queue);
}
if (ev.type == ALLEGRO_EVENT_TIMER) {
do_draw = 1;
}
if (do_draw && al_is_event_queue_empty(event_queue)) {
al_set_target_bitmap(al_get_backbuffer(display));
al_clear_to_color(al_map_rgba(20, 20, 25, 255));
/* draw all GUI windows and widgets */
al_flip_display();
do_draw = 0;
}
} while (!key[KEY_ESC] && !DONE);
al_destroy_event_queue(event_queue);
al_destroy_font(font);
al_destroy_timer(fps_timer);
al_uninstall_system();
return 0;
}
int main(void)
ALLEGRO_TIMER * fps_timer
Definition ex_fluid.c:66
int getoptret
Definition ex_fluid.c:60
int DONE
Definition ex_fluid.c:59
int log_level
Definition ex_fluid.c:61
ALLEGRO_TIMER * logic_timer
Definition ex_fluid.c:67
ALLEGRO_DISPLAY * display
Definition ex_fluid.c:53
#define WIDTH
Definition ex_gui.c:36
#define HEIGHT
Definition ex_gui.c:37
char * definition
content of definition
static int search_textarea_id
void free_entry(void *entry_ptr)
static int status_win_id
LIST * definitions
list of DICTIONARY_DEFINITION for that entry
void on_search_change(int widget_id, const char *text, void *user_data)
static int definition_win_id
void on_clear_click(int widget_id, void *user_data)
void on_completion_select(int widget_id, int index, int selected, void *user_data)
static int status_label_id
static int definition_label_id
char * key
key of the entry
static LIST * completion
char * type
type of definition (verb, noun,...)
static void update_completion(N_GUI_CTX *gui, const char *text)
static int completion_listbox_id
void free_entry_def(void *entry_def)
static size_t max_results
static void update_definitions(N_GUI_CTX *gui, const char *word)
static HASH_TABLE * dictionary
static char last_search[4096]
dictionary definition for DICTIONARY_ENTRY
dictionary entry
static N_GUI_CTX * gui
char * key
#define FreeNoLog(__ptr)
Free Handler without log.
Definition n_common.h:271
#define Malloc(__ptr, __struct, __size)
Malloc Handler to get errors and set to 0.
Definition n_common.h:203
#define _str(__PTR)
define true
Definition n_common.h:192
void n_abort(char const *format,...)
abort program with a text
Definition n_common.c:52
void n_gui_set_display_size(N_GUI_CTX *ctx, float w, float h)
Set the display (viewport) size for global scrollbar computation.
Definition n_gui.c:5176
#define N_GUI_ALIGN_LEFT
left aligned text
Definition n_gui.h:156
void n_gui_textarea_set_text(N_GUI_CTX *ctx, int widget_id, const char *text)
set the text content of a textarea widget
Definition n_gui.c:1752
void n_gui_label_set_text(N_GUI_CTX *ctx, int widget_id, const char *text)
set the text of a label widget
Definition n_gui.c:2178
int n_gui_add_listbox(N_GUI_CTX *ctx, int window_id, float x, float y, float w, float h, int selection_mode, void(*on_select)(int, int, int, void *), void *user_data)
Add a listbox widget.
Definition n_gui.c:1336
int n_gui_process_event(N_GUI_CTX *ctx, ALLEGRO_EVENT event)
Process an allegro event through the GUI system.
Definition n_gui.c:5767
int n_gui_add_label(N_GUI_CTX *ctx, int window_id, const char *text, float x, float y, float w, float h, int align)
Add a static text label.
Definition n_gui.c:1497
#define N_GUI_WIN_FIXED_POSITION
disable window dragging (default:enable)
Definition n_gui.h:196
int n_gui_listbox_add_item(N_GUI_CTX *ctx, int widget_id, const char *text)
add an item to a listbox widget
Definition n_gui.c:1860
void n_gui_set_virtual_size(N_GUI_CTX *ctx, float w, float h)
Set the virtual canvas size for resolution-independent scaling.
Definition n_gui.c:4974
#define N_GUI_SELECT_SINGLE
single item selection
Definition n_gui.h:142
void n_gui_draw(N_GUI_CTX *ctx)
Draw all visible windows and their widgets.
Definition n_gui.c:4800
int n_gui_add_window(N_GUI_CTX *ctx, const char *title, float x, float y, float w, float h)
Add a new pseudo-window to the context.
Definition n_gui.c:581
N_GUI_CTX * n_gui_new_ctx(ALLEGRO_FONT *default_font)
Create a new GUI context.
Definition n_gui.c:466
const char * n_gui_listbox_get_item_text(N_GUI_CTX *ctx, int widget_id, int index)
get the text of a listbox item
Definition n_gui.c:1937
void n_gui_listbox_clear(N_GUI_CTX *ctx, int widget_id)
remove all items from a listbox widget
Definition n_gui.c:1907
void n_gui_destroy_ctx(N_GUI_CTX **ctx)
Destroy a GUI context and all its windows/widgets.
Definition n_gui.c:523
#define N_GUI_SHAPE_ROUNDED
rounded rectangle shape
Definition n_gui.h:116
void n_gui_window_set_flags(N_GUI_CTX *ctx, int window_id, int flags)
Set feature flags on a window.
Definition n_gui.c:843
#define N_GUI_ALIGN_JUSTIFIED
justified text (spread words to fill width)
Definition n_gui.h:162
int n_gui_add_textarea(N_GUI_CTX *ctx, int window_id, float x, float y, float w, float h, int multiline, size_t char_limit, void(*on_change)(int, const char *, void *), void *user_data)
Add a text area widget.
Definition n_gui.c:1214
int n_gui_add_button(N_GUI_CTX *ctx, int window_id, const char *label, float x, float y, float w, float h, int shape, void(*on_click)(int, void *), void *user_data)
Add a button widget to a window.
Definition n_gui.c:1001
The top-level GUI context that holds all windows.
Definition n_gui.h:882
int ht_get_ptr(HASH_TABLE *table, const char *key, void **val)
get pointer at 'key' from 'table'
Definition n_hash.c:2100
int destroy_ht(HASH_TABLE **table)
empty a table and destroy it
Definition n_hash.c:2234
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:2391
int ht_put_ptr(HASH_TABLE *table, const char *key, void *ptr, void(*destructor)(void *ptr), void *(*duplicator)(void *ptr))
put an arbitrary pointer value with given key in the targeted hash table
Definition n_hash.c:2154
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:1955
structure of a hash table
Definition n_hash.h:137
int list_push(LIST *list, void *ptr, void(*destructor)(void *ptr))
Add a pointer to the end of the list.
Definition n_list.c:227
#define list_foreach(__ITEM_, __LIST_)
ForEach macro helper, safe for node removal during iteration.
Definition n_list.h:88
int list_destroy(LIST **list)
Empty and Free a list container.
Definition n_list.c:547
LIST * new_generic_list(size_t max_items)
Initialiaze a generic list container to max_items pointers.
Definition n_list.c:36
#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:74
Structure of a generic LIST container.
Definition n_list.h:58
#define n_log(__LEVEL__,...)
Logging function wrapper to get line and func.
Definition n_log.h:88
#define LOG_DEBUG
debug-level messages
Definition n_log.h:83
#define LOG_ERR
error conditions
Definition n_log.h:75
int set_log_file(char *file)
Set the logging to a file instead of stderr.
Definition n_log.c:167
void set_log_level(const int log_level)
Set the global log level value ( static int LOG_LEVEL )
Definition n_log.c:120
#define LOG_NOTICE
normal but significant condition
Definition n_log.h:79
#define LOG_INFO
informational
Definition n_log.h:81
PCRE2_UCHAR8 ** match_list
populated match list (NULL-terminated) after npcre_match_capture() Allocated by PCRE2 via pcre2_subst...
Definition n_pcre.h:104
N_PCRE * npcre_new(char *str, int flags)
From pcre doc, the flag bits are: PCRE_ANCHORED Force pattern anchoring PCRE_AUTO_CALLOUT Compile aut...
Definition n_pcre.c:80
int npcre_match_capture(char *str, N_PCRE *pcre)
Return TRUE if str matches regexp, and make captures.
Definition n_pcre.c:261
int npcre_clean_match(N_PCRE *pcre)
clean the match list of the last capture, if any
Definition n_pcre.c:164
int npcre_delete(N_PCRE **pcre)
Free a N_PCRE pointer.
Definition n_pcre.c:134
N_PCRE structure.
Definition n_pcre.h:93
Common headers and low-level functions & define.
GUI system: buttons, sliders, text areas, checkboxes, scrollbars, dropdown menus, windows.
Hash functions and table.
List structures and definitions.
__attribute__((unused))
Definition n_network.c:1233
PCRE helpers for regex matching.
N_STR and string function declaration.