@@ -1,103 +1,8 @@
fn void transcript_browser_update ( app_frame_t * frame , mt_tweak_t * tweak_table , i32 tweak_count ) {
ui_begin_frame ( frame ) ;
rn_begin_frame ( frame ) ;
s8_t cmds [ ] = {
s8 ( " show data tab " ) ,
s8 ( " show log tab " ) ,
s8 ( " show menus tab " ) ,
s8 ( " show menus tab2 " ) ,
s8 ( " show menus tab3 " ) ,
s8 ( " show menus tab4 " ) ,
s8 ( " show menus tab5 " ) ,
s8 ( " show menus tab6 " ) ,
s8 ( " show menus tab8 " ) ,
s8 ( " show menus tab7 " ) ,
s8 ( " show menus tab9 " ) ,
s8 ( " show menus tab0 " ) ,
s8 ( " show menus tab11 " ) ,
s8 ( " show menus tab22 " ) ,
s8 ( " show menus tab33 " ) ,
s8 ( " show menus tab44 " ) ,
s8 ( " show menus tab55 " ) ,
s8 ( " show menus tab66 " ) ,
} ;
for ( app_event_t * ev = frame - > first_event ; ev ; ev = ev - > next ) {
ui_begin_build ( UILOC , ev , window_rect_from_frame ( frame ) ) ;
locl b8 set_focus ;
locl char buff [ 128 ] ;
locl ui_text_input_t text_input ;
ui_signal_t text_input_sig ;
text_input . str = buff ;
text_input . cap = lengthof ( buff ) ;
ui_box_t * top_box = ui_box ( . null_id = true , . rect = r2f32_cut_top ( ui_top_rectp ( ) , ui_em ( 1.0f ) ) , . flags = { . draw_rect = true , . clip_rect = true } ) ;
ui_set_text_align ( ui_text_align_left )
ui_set_lop ( ui_lop_cut_top )
ui_set_top ( top_box ) {
text_input_sig = ui_text_input ( & text_input , . sim_even_if_no_focus = true , . keyboard_nav = false ) ;
}
ma_temp_t scratch = ma_begin_scratch ( ) ;
s8_t needle = s8_make ( text_input . str , text_input . len ) ;
fuzzy_pair_t * pairs = s8_fuzzy_rate_array ( scratch . arena , needle , cmds , lengthof ( cmds ) ) ;
if ( text_input_sig . text_changed ) {
set_focus = true ;
}
ui_box_t * lister = ui_box ( . null_id = true , . rect = r2f32_cut_top ( ui_top_rectp ( ) , ui_max ) , . flags = { . draw_rect = true , . clip_rect = true } ) ;
locl f32 verti_scroller_value ;
ui_scroller_t scroller = ui_begin_scroller ( UILOC , ( ui_scroller_params_t ) {
. parent = lister ,
. verti = {
. enabled = true ,
. value = & verti_scroller_value ,
. item_pixels = ui_em ( 1 ) ,
. item_count = ( i32 ) lengthof ( cmds ) ,
} ,
} ) ;
ui_set_top ( lister )
ui_set_string_pos_offset ( ui_dm ( 1 ) ) {
ui_cut_top_scroller_offset ( scroller ) ;
for ( i32 i = scroller . verti . istart ; i < scroller . verti . iend ; i + = 1 ) {
s8_t text = cmds [ pairs [ i ] . index ] ;
ui_box_t * box = ui_box ( . string = text , . flags = { . draw_rect = true , . draw_text = true , . keyboard_nav = true } ) ;
ui_signal_from_box ( box ) ;
if ( set_focus ) {
ui - > focus = box - > id ;
set_focus = false ;
}
}
}
if ( text_input_sig . text_commit ) {
fuzzy_pair_t * pair = & pairs [ 0 ] ;
// ui_g_panel = (i32)pair->index + 1;
ui_text_clear ( & text_input ) ;
set_focus = true ;
}
ui_end_scroller ( scroller ) ;
ui_end_build ( ) ;
ma_end_scratch ( scratch ) ;
}
rn_begin ( white_color ) ;
ui_draw ( ) ;
rn_end ( ) ;
ui_end_frame ( ) ;
}
///////////////////////////////
///////////////////////////////
// work queue
// work queue
# define WORK_FUNCTION (name) void name(void *data)
# define FN_ WORK(name) void name(void *data)
typedef WORK_FUNCTION ( work_queue_callback_t ) ;
typedef FN_ WORK( work_queue_callback_t ) ;
typedef struct {
typedef struct {
work_queue_callback_t * callback ;
work_queue_callback_t * callback ;
@@ -106,32 +11,32 @@ typedef struct {
typedef struct work_queue_t work_queue_t ;
typedef struct work_queue_t work_queue_t ;
struct work_queue_t {
struct work_queue_t {
int32_t thread_count ;
i32 thread_count ;
work_queue_entry_t entries [ 256 ] ;
work_queue_entry_t entries [ 1024 ] ;
int64_t volatile index_to_write ;
i64 volatile index_to_write ;
int64_t volatile index_to_read ;
i64 volatile index_to_read ;
int64_t volatile completion_index ;
i64 volatile completion_index ;
int64_t volatile completion_goal ;
i64 volatile completion_goal ;
void * semaphore ;
void * semaphore ;
} ;
} ;
typedef struct thread_startup_info_t thread_startup_info_t ;
typedef struct thread_startup_info_t thread_startup_info_t ;
struct thread_startup_info_t {
struct thread_startup_info_t {
uint32_t thread_id ;
u32 thread_id ;
int32_t thread_index ;
i32 thread_index ;
work_queue_t * queue ;
work_queue_t * queue ;
} ;
} ;
fn int64_t atomic_increment ( volatile int64_t * i ) {
fn i64 atomic_increment ( volatile i64 * i ) {
return InterlockedIncrement64 ( i ) ;
return InterlockedIncrement64 ( i ) ;
}
}
fn int64_t atomic_compare_and_swap ( volatile int64_t * dst , int64_t exchange , int64_t comperand ) {
fn i64 atomic_compare_and_swap ( volatile i64 * dst , i64 exchange , i64 comperand ) {
return InterlockedCompareExchange64 ( dst , exchange , comperand ) ;
return InterlockedCompareExchange64 ( dst , exchange , comperand ) ;
}
}
fn void work_queue_push ( work_queue_t * wq , void * data , work_queue_callback_t * callback ) {
fn void work_queue_push ( work_queue_t * wq , void * data , work_queue_callback_t * callback ) {
uint32_t new_index = ( wq - > index_to_write + 1 ) % lengthof ( wq - > entries ) ;
u32 new_index = ( wq - > index_to_write + 1 ) % lengthof ( wq - > entries ) ;
assert ( new_index ! = wq - > index_to_read ) ;
assert ( new_index ! = wq - > index_to_read ) ;
work_queue_entry_t * entry = wq - > entries + wq - > index_to_write ;
work_queue_entry_t * entry = wq - > entries + wq - > index_to_write ;
@@ -146,10 +51,10 @@ fn void work_queue_push(work_queue_t *wq, void *data, work_queue_callback_t *cal
fn b8 work_queue_try_doing_work ( work_queue_t * wq ) {
fn b8 work_queue_try_doing_work ( work_queue_t * wq ) {
b8 should_sleep = false ;
b8 should_sleep = false ;
int64_t original_index_to_read = wq - > index_to_read ;
i64 original_index_to_read = wq - > index_to_read ;
int64_t new_index_to_read = ( original_index_to_read + 1 ) % lengthof ( wq - > entries ) ;
i64 new_index_to_read = ( original_index_to_read + 1 ) % lengthof ( wq - > entries ) ;
if ( original_index_to_read ! = wq - > index_to_write ) {
if ( original_index_to_read ! = wq - > index_to_write ) {
int64_t index = atomic_compare_and_swap ( & wq - > index_to_read , new_index_to_read , original_index_to_read ) ;
i64 index = atomic_compare_and_swap ( & wq - > index_to_read , new_index_to_read , original_index_to_read ) ;
if ( index = = original_index_to_read ) {
if ( index = = original_index_to_read ) {
work_queue_entry_t * entry = wq - > entries + index ;
work_queue_entry_t * entry = wq - > entries + index ;
entry - > callback ( entry - > data ) ;
entry - > callback ( entry - > data ) ;
@@ -164,7 +69,8 @@ fn b8 work_queue_try_doing_work(work_queue_t *wq) {
fn DWORD WINAPI work_queue_thread_entry ( LPVOID param ) {
fn DWORD WINAPI work_queue_thread_entry ( LPVOID param ) {
thread_startup_info_t * ti = ( thread_startup_info_t * ) param ;
thread_startup_info_t * ti = ( thread_startup_info_t * ) param ;
os_core_init ( ) ;
tcx = & global_thread_context ;
os_win32_register_crash_handler ( ) ;
tcx - > thread_index = ti - > thread_index ;
tcx - > thread_index = ti - > thread_index ;
for ( ; ; ) {
for ( ; ; ) {
if ( work_queue_try_doing_work ( ti - > queue ) ) {
if ( work_queue_try_doing_work ( ti - > queue ) ) {
@@ -173,7 +79,7 @@ fn DWORD WINAPI work_queue_thread_entry(LPVOID param) {
}
}
}
}
fn void work_queue_init ( work_queue_t * queue , uint32_t thread_count , thread_startup_info_t * info ) {
fn void work_queue_init ( work_queue_t * queue , thread_startup_info_t * info , u32 thread_count ) {
queue - > thread_count = thread_count ;
queue - > thread_count = thread_count ;
queue - > index_to_read = 0 ;
queue - > index_to_read = 0 ;
queue - > index_to_write = 0 ;
queue - > index_to_write = 0 ;
@@ -182,7 +88,7 @@ fn void work_queue_init(work_queue_t *queue, uint32_t thread_count, thread_start
queue - > semaphore = CreateSemaphoreExA ( 0 , 0 , thread_count , 0 , 0 , SEMAPHORE_ALL_ACCESS ) ;
queue - > semaphore = CreateSemaphoreExA ( 0 , 0 , thread_count , 0 , 0 , SEMAPHORE_ALL_ACCESS ) ;
assert ( queue - > semaphore ! = INVALID_HANDLE_VALUE ) ;
assert ( queue - > semaphore ! = INVALID_HANDLE_VALUE ) ;
for ( uint32_t i = 0 ; i < thread_count ; i + + ) {
for ( u32 i = 0 ; i < thread_count ; i + + ) {
thread_startup_info_t * ti = info + i ;
thread_startup_info_t * ti = info + i ;
ti - > thread_index = i ;
ti - > thread_index = i ;
ti - > queue = queue ;
ti - > queue = queue ;
@@ -206,6 +112,52 @@ fn void work_queue_wait(work_queue_t *wq) {
}
}
}
}
///////////////////////////////
// process
typedef struct process_t process_t ;
struct process_t {
b8 is_valid ;
char platform [ 32 ] ;
} ;
fn process_t process_run ( s8_t args ) {
ma_temp_t scratch = ma_begin_scratch ( ) ;
wchar_t * application_name = NULL ;
wchar_t * cmd = s16_from_s8 ( scratch . arena , args ) . str ;
BOOL inherit_handles = FALSE ;
DWORD creation_flags = 0 ;
void * enviroment = NULL ;
wchar_t * working_dir = NULL ;
STARTUPINFOW startup_info = { } ;
startup_info . cb = sizeof ( STARTUPINFOW ) ;
process_t result = { } ;
assert ( sizeof ( result . platform ) > = sizeof ( PROCESS_INFORMATION ) ) ;
PROCESS_INFORMATION * process_info = ( PROCESS_INFORMATION * ) result . platform ;
BOOL success = CreateProcessW ( application_name , cmd , NULL , NULL , inherit_handles , creation_flags , enviroment , working_dir , & startup_info , process_info ) ;
result . is_valid = true ;
if ( ! success ) {
result . is_valid = false ;
LPVOID lpMsgBuf ;
DWORD dw = GetLastError ( ) ;
FormatMessage ( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS ,
NULL , dw , MAKELANGID ( LANG_NEUTRAL , SUBLANG_DEFAULT ) , ( LPTSTR ) & lpMsgBuf , 0 , NULL ) ;
char * buff = ( char * ) lpMsgBuf ;
size_t buffLen = strlen ( ( const char * ) buff ) ;
if ( buffLen > 0 & & buff [ buffLen - 1 ] = = ' \n ' ) {
buff [ buffLen - 1 ] = 0 ;
}
debugf ( " failed to create process | message: %s | cmd: %s " , ( char * ) lpMsgBuf , args ) ;
LocalFree ( lpMsgBuf ) ;
}
ma_end_scratch ( scratch ) ;
return result ;
}
///////////////////////////////
///////////////////////////////
// mutex
// mutex
@@ -244,18 +196,13 @@ fn void mutex_unlock(mutex_t mutex) {
typedef struct srt_entry_t srt_entry_t ;
typedef struct srt_entry_t srt_entry_t ;
struct srt_entry_t {
struct srt_entry_t {
srt_entry_t * next ;
u16 hour , minute , second ;
u16 hour , minute , second ;
s8_t string ;
s8_t string ;
s8_t filepath ;
} ;
} ;
typedef array ( srt_entry_t ) array_srt_entry_t ;
typedef struc t srt_result_t srt_result_t ;
fn array_srt_entry_ t srt_parse ( ma_arena_t * arena , s8_t filename ) {
struct srt_result_t {
srt_entry_t * first ;
srt_entry_t * last ;
} ;
srt_result_t srt_parse ( ma_arena_t * arena , s8_t filename ) {
s8_t content = os_read ( arena , filename ) ;
s8_t content = os_read ( arena , filename ) ;
sb8_t lines = s8_split ( arena , content , s8 ( " \n " ) , s8_split_cleanup ) ;
sb8_t lines = s8_split ( arena , content , s8 ( " \n " ) , s8_split_cleanup ) ;
@@ -269,7 +216,8 @@ srt_result_t srt_parse(ma_arena_t *arena, s8_t filename) {
// time interval
// time interval
// text
// text
int section_number = 1 ;
int section_number = 1 ;
srt_result _t result = { 0 } ;
array_srt_entry _t result = { 0 } ;
result . alo = malo ( arena ) ;
for ( sb8_node_t * it = lines . first ; it ; ) {
for ( sb8_node_t * it = lines . first ; it ; ) {
// parse section number
// parse section number
long num = strtol ( it - > str , NULL , 10 ) ;
long num = strtol ( it - > str , NULL , 10 ) ;
@@ -282,17 +230,16 @@ srt_result_t srt_parse(ma_arena_t *arena, s8_t filename) {
entry . hour = ( u16 ) strtol ( it - > str , NULL , 10 ) ;
entry . hour = ( u16 ) strtol ( it - > str , NULL , 10 ) ;
entry . minute = ( u16 ) strtol ( it - > str + 3 , NULL , 10 ) ;
entry . minute = ( u16 ) strtol ( it - > str + 3 , NULL , 10 ) ;
entry . second = ( u16 ) strtol ( it - > str + 6 , NULL , 10 ) ;
entry . second = ( u16 ) strtol ( it - > str + 6 , NULL , 10 ) ;
entry . filepath = filename ;
it = it - > next ;
it = it - > next ;
// parse text
// parse text
s8_t next_section_number = s8_printf ( arena , " %d " , section_number ) ;
s8_t next_section_number = s8_printf ( arena , " %d " , section_number ) ;
while ( it & & ! s8_are_equal ( next_section_number , it - > string ) ) {
while ( it & & ! s8_are_equal ( next_section_number , it - > string ) ) {
b8 duplicate = result . last & & s8_are_equal ( it - > string , result . last - > string ) ;
b8 duplicate = result . len & & s8_are_equal ( it - > string , array_last ( & result ) . string ) ;
if ( ! duplicate ) {
if ( ! duplicate ) {
srt_entry_t * entry_copy = ma_push_type ( arena , srt_entry_t ) ;
entry . string = it - > string ;
entry_copy [ 0 ] = entry ;
array_add ( & result , entry ) ;
entry_copy - > string = it - > string ;
SLLQ_APPEND ( result . first , result . last , entry_copy ) ;
}
}
it = it - > next ;
it = it - > next ;
}
}
@@ -301,14 +248,301 @@ srt_result_t srt_parse(ma_arena_t *arena, s8_t filename) {
return result ;
return result ;
}
}
fn_test void testing_out_things ( void ) {
///////////////////////////////
mutex_t mutex = mutex_create ( ) ;
// multithreaded resource loading
mutex_lock ( mutex ) ;
mutex_unlock ( mutex ) ;
mutex_destroy ( mutex ) ;
typedef array ( s8_t ) array_s8_t ;
typedef struct res_parse_work_t res_parse_work_t ;
typedef struct res_t res_t ;
struct res_parse_work_t {
s8_t srt ;
res_t * res ;
} ;
struct res_t {
ma_arena_t misc_arena ;
array_s8_t error_messages ;
mutex_t mutex ;
ma_arena_t text_arena ;
ma_arena_t node_arena ;
array_srt_entry_t mapping_entries ;
thread_startup_info_t thread_info [ 16 ] ;
work_queue_t work_queue ;
mutex_t log_mutex ;
i64 search_stop_counter ;
mutex_t search_mutex ;
array_s8_t search_matches ;
ui_text_input_t search_text_input ;
char search_prompt [ 256 ] ;
} ;
# define res_report(res, ...) (mutex_lock((res)->log_mutex), array_add(&(res)->error_messages, s8_printf(&(res)->misc_arena, __VA_ARGS__)), mutex_unlock((res)->log_mutex))
fn void res_init ( res_t * res ) {
work_queue_init ( & res - > work_queue , res - > thread_info , lengthof ( res - > thread_info ) ) ;
ma_init ( & res - > text_arena , ma_default_reserve_size ) ;
ma_init ( & res - > node_arena , ma_default_reserve_size ) ;
ma_init ( & res - > misc_arena , ma_default_reserve_size ) ;
res - > log_mutex = mutex_create ( ) ;
res - > mutex = mutex_create ( ) ;
res - > search_mutex = mutex_create ( ) ;
array_init ( malo ( & res - > misc_arena ) , & res - > search_matches , 10000000 ) ;
array_init ( malo ( & res - > misc_arena ) , & res - > error_messages , 10000 ) ;
res - > text_arena . align = 0 ;
}
fn s8_t srt_find_matching_video ( s8_t filename ) {
s8_t no_srt = s8_chop_last_period ( filename ) ;
if ( s8_ends_with ( no_srt , s8 ( " .en " ) ) ) {
no_srt = s8_chop_last_period ( no_srt ) ;
}
char * ext [ ] = { " mp4 " , " webm " , " mkv " } ;
for ( i32 i = 0 ; i < lengthof ( ext ) ; i + = 1 ) {
s8_t video = s8_printf ( tcx - > temp , " %S.%s " , no_srt , ext [ i ] ) ;
if ( os_exists ( video ) ) {
return video ;
}
}
return s8_null ;
}
FN_WORK ( res_parse_thread ) {
res_parse_work_t * pair = ( res_parse_work_t * ) data ;
ma_temp_t scratch = ma_begin_scratch ( ) ;
ma_temp_t scratch = ma_begin_scratch ( ) ;
srt_result_t resul t = srt_parse ( scratch . arena , s8 ( " D: \\ videos \\ zizek \\ ‘ Hegel and the Spirit of Distrust’ Sven-Olov Wallenstein & Slavoj Žižek in Conversation [a7gEN-Rxr4c].en.srt" ) ) ;
array_srt_entry_t sr t = srt_parse ( scratch . arena , pair - > srt ) ;
unused ( result ) ;
mutex_lock ( pair - > res - > mutex ) ;
pair - > res - > mapping_entries . alo = malo ( & pair - > res - > node_arena ) ;
for ( i64 i = 0 ; i < srt . len ; i + = 1 ) {
srt_entry_t it = srt . data [ i ] ;
it . filepath = s8_copy ( & pair - > res - > misc_arena , it . filepath ) ;
it . string = s8_copy ( & pair - > res - > text_arena , it . string ) ;
it . string . str [ it . string . len ] = ' ' ;
array_add ( & pair - > res - > mapping_entries , it ) ;
}
mutex_unlock ( pair - > res - > mutex ) ;
ma_end_scratch ( scratch ) ;
ma_end_scratch ( scratch ) ;
if ( srt . len ) {
res_report ( pair - > res , " %S " , pair - > srt ) ;
} else {
res_report ( pair - > res , " failed to load: %S " , pair - > srt ) ;
}
}
fn void res_add_folder ( res_t * res , s8_t folder ) {
ma_temp_t scratch = ma_begin_scratch ( ) ;
if ( ! os_is_dir ( folder ) ) {
res_report ( res , " failed to find folder: %S " , folder ) ;
}
for ( os_iter_t * iter = os_iter ( scratch . arena , folder ) ; iter - > is_valid ; os_advance ( iter ) ) {
if ( iter - > is_directory ) {
continue ;
}
if ( ! s8_ends_with ( iter - > abs , s8 ( " .srt " ) ) ) {
continue ;
}
// @leak
res_parse_work_t * work = ma_push_type ( & res - > misc_arena , res_parse_work_t ) ;
work - > srt = iter - > abs ;
work - > res = res ;
work_queue_push ( & res - > work_queue , work , res_parse_thread ) ;
}
ma_end_scratch ( scratch ) ;
}
fn srt_entry_t * res_find_entry ( res_t * res , s8_t res_string ) {
srt_entry_t * result = NULL ;
mutex_lock ( res - > mutex ) ;
for ( srt_entry_t * it = res - > mapping_entries . data ; it ! = res - > mapping_entries . data + res - > mapping_entries . len ; it + = 1 ) {
u64 begin = ( u64 ) ( it - > string . str ) ;
u64 end = ( u64 ) ( it - > string . str + it - > string . len ) ;
u64 needle = ( u64 ) ( res_string . str ) ;
if ( needle > = begin & & needle < end ) {
result = it ;
break ;
}
}
mutex_unlock ( res - > mutex ) ;
return result ;
}
fn s8_t res_get_string ( res_t * res ) {
mutex_lock ( res - > mutex ) ;
s8_t result = ( s8_t ) { res - > text_arena . data , res - > text_arena . len } ;
mutex_unlock ( res - > mutex ) ;
return result ;
}
///////////////////////////////
// search thread
FN_WORK ( res_search_thread ) {
res_t * res = ( res_t * ) data ;
if ( res - > search_text_input . len = = 0 ) {
return ;
}
i64 search_stop_counter = res - > search_stop_counter ;
mutex_lock ( res - > search_mutex ) ;
res - > search_matches . len = 0 ;
mutex_unlock ( res - > search_mutex ) ;
s8_t buffer = res_get_string ( res ) ;
s8_t find = res - > search_text_input . string ;
i64 index = 0 ;
while ( s8_seek ( buffer , find , s8_seek_ignore_case , & index ) ) {
if ( search_stop_counter ! = res - > search_stop_counter ) {
break ;
}
assert ( res - > search_matches . cap = = 10000000 ) ;
s8_t found = s8_make ( buffer . str + index , find . len ) ;
array_add ( & res - > search_matches , found ) ;
buffer = s8_skip ( buffer , index + find . len ) ;
}
}
fn void res_search_start ( res_t * res ) {
res - > search_stop_counter + = 1 ;
work_queue_push ( & res - > work_queue , res , res_search_thread ) ;
}
fn array_s8_t res_search_get ( ma_arena_t * arena , res_t * res ) {
mutex_lock ( res - > search_mutex ) ;
array_s8_t copy = res - > search_matches ;
copy . data = ma_push_array_copy ( arena , copy . data , copy . len ) ;
mutex_unlock ( res - > search_mutex ) ;
return copy ;
}
res_t * global_res = NULL ;
// @todo @core make temp arena normal pointer in ctx, dont init on win32 etc.
// @todo @core make it sure that not too much arenas are initialized for threads
// @todo @ui scrolling when focused button goes out of screen
fn_test void testing_out_things ( void ) {
}
///////////////////////////////
// update
fn void transcript_browser_update ( app_frame_t * frame , mt_tweak_t * tweak_table , i32 tweak_count ) {
ui_begin_frame ( frame ) ;
rn_begin_frame ( frame ) ;
res_t * res = global_res ;
for ( app_event_t * ev = frame - > first_event ; ev ; ev = ev - > next ) {
ui_begin_build ( UILOC , ev , window_rect_from_frame ( frame ) ) ;
locl b8 set_focus ;
ui_signal_t text_input_sig ;
res - > search_text_input . str = res - > search_prompt ;
res - > search_text_input . cap = lengthof ( res - > search_prompt ) ;
ui_box_t * top_box = ui_box ( . null_id = true , . rect = r2f32_cut_top ( ui_top_rectp ( ) , ui_em ( 1.0f ) ) , . flags = { . draw_rect = true , . clip_rect = true } ) ;
ui_set_text_align ( ui_text_align_left )
ui_set_lop ( ui_lop_cut_top )
ui_set_top ( top_box ) {
text_input_sig = ui_text_input ( & res - > search_text_input , . sim_even_if_no_focus = true , . keyboard_nav = false ) ;
}
ma_temp_t scratch = ma_begin_scratch ( ) ;
array_s8_t matches = res_search_get ( scratch . arena , res ) ;
if ( matches . len = = 0 | | res - > search_text_input . len = = 0 ) {
// @concurrency not sure if this is ok
matches = res - > error_messages ;
}
ui_box_t * lister = ui_box ( . null_id = true , . rect = r2f32_cut_top ( ui_top_rectp ( ) , ui_max ) , . flags = { . draw_rect = true , . clip_rect = true } ) ;
locl f32 verti_scroller_value ;
ui_scroller_t scroller = ui_begin_scroller ( UILOC , ( ui_scroller_params_t ) {
. parent = lister ,
. verti = {
. enabled = true ,
. value = & verti_scroller_value ,
. item_pixels = ui_em ( 1 ) ,
. item_count = ( i32 ) matches . len ,
} ,
} ) ;
ui_set_top ( lister )
ui_set_string_pos_offset ( ui_dm ( 1 ) ) {
ui_cut_top_scroller_offset ( scroller ) ;
for ( i32 i = scroller . verti . istart ; i < scroller . verti . iend ; i + = 1 ) {
if ( i > = matches . len ) {
break ;
}
ui_push_id ( ( ui_id_t ) { i } ) ;
s8_t it = matches . data [ i ] ;
uintptr_t begin_region = ( uintptr_t ) res - > text_arena . data ;
uintptr_t end_region = ( uintptr_t ) res - > text_arena . data + res - > text_arena . len ;
u64 chars_per_line = ( i64 ) ( frame - > window_size . x ) / ( i64 ) ui_dm ( 1 ) - strlen ( res - > search_prompt ) * 2 ;
u64 begin = ( uintptr_t ) ( it . str - chars_per_line / 2 ) ;
u64 end = ( uintptr_t ) ( it . str + it . len + chars_per_line / 2 ) ;
u64 a = CLAMP ( begin , begin_region , end_region ) ;
u64 b = CLAMP ( ( uintptr_t ) it . str , begin_region , end_region ) ;
s8_t left = { ( char * ) a , ( i64 ) ( b - a ) } ;
u64 c = CLAMP ( ( uintptr_t ) ( it . str + it . len ) , begin_region , end_region ) ;
u64 d = CLAMP ( end , begin_region , end_region ) ;
s8_t right = { ( char * ) c , ( i64 ) ( d - c ) } ;
s8_t middle = it ;
s8_t string = s8_printf ( scratch . arena , " %S**%S**%S " , left , middle , right ) ;
ui_box_t * box = ui_box ( . string = string , . flags = { . draw_rect = true , . draw_text = true , . keyboard_nav = true } ) ;
ui_signal_t sig = ui_signal_from_box ( box ) ;
if ( sig . clicked & & matches . data ! = res - > error_messages . data ) {
srt_entry_t * entry = res_find_entry ( res , middle ) ;
s8_t video = srt_find_matching_video ( entry - > filepath ) ;
if ( video . len = = 0 ) {
res_report ( res , " failed to find video for: %S " , entry - > filepath ) ;
} else {
int seconds = entry - > hour * 60 * 60 + entry - > minute * 60 + entry - > second ;
for ( i64 i = 0 ; i < video . len ; i + = 1 ) {
if ( video . str [ i ] = = ' / ' ) video . str [ i ] = ' \\ ' ;
}
s8_t cmd = s8_printf ( scratch . arena , " \" C:/Program Files/VideoLAN/VLC/vlc.exe \" --start-time %d \" %S \" " , seconds , video ) ;
debugf ( " %S \n " , cmd ) ;
process_run ( cmd ) ;
}
}
if ( set_focus ) {
ui - > focus = box - > id ;
set_focus = false ;
}
ui_pop_id ( ) ;
}
}
if ( text_input_sig . text_changed ) {
res_search_start ( res ) ;
set_focus = true ;
}
assert ( res - > error_messages . cap = = 10000 ) ;
assert ( res - > search_matches . cap = = 10000000 ) ;
ui_end_scroller ( scroller ) ;
ui_end_build ( ) ;
ma_end_scratch ( scratch ) ;
}
rn_begin ( white_color ) ;
ui_draw ( ) ;
rn_end ( ) ;
ui_end_frame ( ) ;
}
}