Nilorea Library
C utilities for networking, threading, graphics
ex_gui_dictionary.c

Nilorea Library gui particle api test.

Nilorea Library gui particle api test

Author
Castagnier Mickael
Version
1.0
Date
10/02/2020
#define WIDTH 1280
#define HEIGHT 800
#include "nilorea/n_list.h"
#include "nilorea/n_hash.h"
#include "nilorea/n_pcre.h"
#include "nilorea/n_str.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_BITMAP *scr_buf = NULL ;
ALLEGRO_TIMER *fps_timer = NULL ;
ALLEGRO_TIMER *logic_timer = NULL ;
int main( int argc, char *argv[] )
{
set_log_level( log_level );
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 ) )
{
log_level = LOG_INFO ;
}
else
{
if( !strncmp( "NOTICE", optarg, 7 ) )
{
log_level = LOG_NOTICE ;
}
else
{
if( !strncmp( "ERR", optarg, 5 ) )
{
log_level = LOG_ERR ;
}
else
{
if( !strncmp( "DEBUG", optarg, 5 ) )
{
log_level = LOG_DEBUG ;
}
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 );
set_log_level( 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 ;
double logic_delta_time = 1.0 / (5.0 * fps);
fps_timer = al_create_timer( fps_delta_time );
logic_timer = al_create_timer( logic_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_start_timer( logic_timer );
al_register_event_source(event_queue, al_get_timer_event_source(fps_timer));
al_register_event_source(event_queue, al_get_timer_event_source(logic_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", 24 , 0 );
if (! font )
{
n_log( LOG_ERR, "Unable to load DATAS/2Dumb.ttf" );
exit( 1 );
}
ALLEGRO_BITMAP *scrbuf = al_create_bitmap( WIDTH, HEIGHT );
al_hide_mouse_cursor(display);
int mx = 0, my = 0, mz = 0 ;
int mouse_b1 = 0, mouse_b2 = 0 ;
int do_draw = 0, do_logic = 0 ;
typedef struct DICTIONARY_DEFINITION
{
char *type ;
char *definition ;
} DICTIONARY_DEFINITION;
typedef struct DICTIONARY_ENTRY
{
char *key ;
LIST *definitions ;
} DICTIONARY_ENTRY ;
void free_entry_def( void *entry_def )
{
DICTIONARY_DEFINITION *def = (DICTIONARY_DEFINITION *)entry_def;
FreeNoLog( def -> type );
FreeNoLog( def -> definition );
FreeNoLog( def );
}
void free_entry( void *entry_ptr )
{
DICTIONARY_ENTRY *entry = (DICTIONARY_ENTRY *)entry_ptr;
list_destroy( &entry -> definitions );
FreeNoLog( entry -> key );
FreeNoLog( entry );
}
/* Load dictionaries */
HASH_TABLE *dictionary = new_ht_trie( 256 , 32 );
FILE *dict_file = fopen( "DATAS/dictionary.csv" , "r" );
char read_buf[ 16384 ] = "" ;
char *entry_key = NULL ;
char *type = NULL ;
char *definition = NULL ;
N_PCRE *dico_regexp = npcre_new ( "\"(.*)\",\"(.*)\",\"(.*)\"" , 99 , 0 );
while( fgets( read_buf , 16384 , dict_file ) )
{
if( npcre_match( read_buf , dico_regexp ) )
{
entry_key = strdup( _str( dico_regexp -> match_list[ 1 ] ) );
type = strdup( _str( dico_regexp -> match_list[ 2 ] ) );
definition = strdup( _str( 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
{
Malloc( entry , DICTIONARY_ENTRY , 1 );
entry -> definitions = new_generic_list( 0 );
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 );
}
FreeNoLog( entry_key );
FreeNoLog( type );
FreeNoLog( definition );
npcre_clean_match( dico_regexp );
}
}
fclose( dict_file );
ALLEGRO_USTR *keyboard_buffer = al_ustr_new( "" );
LIST *completion = NULL ;
int key_pressed = 0 ;
n_log( LOG_NOTICE , "Starting main loop" );
al_clear_keyboard_state( NULL );
al_flush_event_queue( event_queue );
int max_results = 100 ;
completion = ht_get_completion_list( dictionary , al_cstr( keyboard_buffer ) , max_results );
do
{
do
{
ALLEGRO_EVENT ev ;
al_wait_for_event(event_queue, &ev);
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_KEY_UP)
{
switch(ev.keyboard.keycode)
{
case ALLEGRO_KEY_ESCAPE:
key[KEY_ESC] = 0 ;
break;
default:
break;
}
}
else if( ev.type == ALLEGRO_EVENT_TIMER )
{
if( al_get_timer_event_source( fps_timer ) == ev.any.source )
{
do_draw = 1 ;
}
else if( al_get_timer_event_source( logic_timer ) == ev.any.source )
{
do_logic = 1;
}
}
else if( ev.type == ALLEGRO_EVENT_MOUSE_AXES )
{
mx = ev.mouse.x;
my = ev.mouse.y;
mz -= ev.mouse.dz;
if( mz < 0 ) mz = 0 ;
}
else if( ev.type == ALLEGRO_EVENT_MOUSE_BUTTON_DOWN )
{
if( ev.mouse.button == 1 )
mouse_b1 = 1 ;
if( ev.mouse.button == 2 )
mouse_b2 = 1 ;
}
else if( ev.type == ALLEGRO_EVENT_MOUSE_BUTTON_UP )
{
if( ev.mouse.button == 1 )
mouse_b1 = 0 ;
if( ev.mouse.button == 2 )
mouse_b2 = 0 ;
}
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 );
}
else
{
/* Processing inputs */
if( get_keyboard( keyboard_buffer , ev ) == TRUE )
key_pressed = 1 ;
}
}while( !al_is_event_queue_empty( event_queue) );
if( do_logic == 1 )
{
if( key_pressed == 1 )
{
key_pressed = 0 ;
mz = 0 ;
if( completion )
{
list_destroy( &completion );
}
completion = ht_get_completion_list( dictionary , al_cstr( keyboard_buffer ) , max_results );
}
if( mouse_b1==1 )
{
if( completion )
{
int skip_entry = mz ;
if( skip_entry >= completion -> nb_items )
{
skip_entry = completion -> nb_items - 1 ;
mz = skip_entry ;
}
char *key = NULL ;
list_foreach( node , completion )
{
skip_entry -- ;
key = (char *)node -> ptr ;
if( skip_entry < 0 )
{
break ;
}
}
al_ustr_free( keyboard_buffer );
keyboard_buffer = al_ustr_new( key );
}
completion = ht_get_completion_list( dictionary , al_cstr( keyboard_buffer ) , max_results );
mz = 0 ;
mouse_b1 = 0 ;
}
if( mouse_b2==1 )
{
int pos = (int)al_ustr_size( keyboard_buffer );
if( al_ustr_prev( keyboard_buffer , &pos ) )
{
al_ustr_truncate( keyboard_buffer , pos );
}
completion = ht_get_completion_list( dictionary , al_cstr( keyboard_buffer ) , max_results );
mouse_b2 = 0 ;
}
do_logic = 0 ;
}
if( do_draw == 1 )
{
static int last_time = 0 ;
al_acknowledge_resize( display );
//int w = al_get_display_width( display );
//int h = al_get_display_height( display );
al_set_target_bitmap( scrbuf );
al_clear_to_color( al_map_rgba( 0, 0, 0, 255 ) );
last_time -= 1000000/30.0 ;
static int length = 0 ;
if( last_time < 0 )
{
last_time = 250000 ;
}
else
{
length = al_get_text_width( font , al_cstr( keyboard_buffer ) );
al_draw_filled_rectangle( WIDTH / 2 + ( length + 6 ) / 2 , 50 ,
WIDTH / 2 + ( length + 6 ) / 2 + 15 , 70 ,
al_map_rgb( 0 , 128 , 0 ) );
}
int input_size = al_get_text_width( font , al_cstr( keyboard_buffer ) );
al_draw_text( font , al_map_rgb( 0 , 255 , 0 ) , (WIDTH / 2) - (input_size / 2), 50 , ALLEGRO_ALIGN_LEFT , al_cstr( keyboard_buffer ) );
DICTIONARY_ENTRY *entry = NULL ;
if( completion )
{
int pos_x = (WIDTH / 2) + (input_size / 2) + 50 ;
int pos_y = 50 ;
int skip_entry = mz ;
if( skip_entry >= completion -> nb_items )
{
skip_entry = completion -> nb_items - 1 ;
mz = skip_entry ;
}
list_foreach( node , completion )
{
if( skip_entry > 0 )
{
skip_entry -- ;
continue ;
}
char *key = (char *)node -> ptr ;
al_draw_text( font , al_map_rgb( 230 , 230 , 0 ) , pos_x , pos_y , ALLEGRO_ALIGN_LEFT , key );
pos_y += 35 ;
}
}
if( ht_get_ptr( dictionary , al_cstr( keyboard_buffer ) , (void **)&entry ) == TRUE )
{
int vertical_it = 0 ;
list_foreach( node , entry -> definitions )
{
DICTIONARY_DEFINITION *definition = (DICTIONARY_DEFINITION *)node -> ptr ;
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 );
vertical_it += 50 ;
}
}
al_set_target_bitmap( al_get_backbuffer( display ) );
al_draw_bitmap( scrbuf, 0, 0, 0 );
/* mouse pointer */
al_draw_line( mx - 5, my, mx + 5, my, al_map_rgb( 255, 0, 0 ), 1 );
al_draw_line( mx, my + 5, mx, my - 5, al_map_rgb( 255, 0, 0 ), 1 );
al_flip_display();
do_draw = 0 ;
}
}
while( !key[KEY_ESC] && !DONE );
destroy_ht( &dictionary );
return 0;
}
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:268
#define Malloc(__ptr, __struct, __size)
Malloc Handler to get errors and set to 0.
Definition: n_common.h:183
#define _str(__PTR)
define true
Definition: n_common.h:172
void n_abort(char const *format,...)
abort program with a text
Definition: n_common.c:38
int ht_get_ptr(HASH_TABLE *table, const char *key, void **val)
get pointer at 'key' from 'table'
Definition: n_hash.c:2282
int destroy_ht(HASH_TABLE **table)
empty a table and destroy it
Definition: n_hash.c:2448
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:2630
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:2123
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:2347
structure of a hash table
Definition: n_hash.h:109
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:603
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.