From 708517a6680ed8f8891ff3b3aa4bf7da2945fba0 Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Fri, 2 Feb 2024 15:35:44 -0800 Subject: [PATCH] move fuzzy range match visualization into formal ui rendering path; write dedicated truncated fuzzy match rendering path; fixes some visual bugs & makes all fuzzy range match visualization consistent and not ad-hoc --- src/base/base_string.c | 17 ++++++++++++ src/base/base_string.h | 1 + src/df/gfx/df_gfx.c | 46 +++++++------------------------ src/df/gfx/df_gfx.h | 5 ---- src/df/gfx/df_views.c | 16 +++++------ src/draw/draw.c | 61 +++++++++++++++++++++++++++++++++++++----- src/draw/draw.h | 1 + src/ui/ui_core.c | 7 +++++ src/ui/ui_core.h | 6 +++-- 9 files changed, 102 insertions(+), 58 deletions(-) diff --git a/src/base/base_string.c b/src/base/base_string.c index 44a90279..cc9dddf7 100644 --- a/src/base/base_string.c +++ b/src/base/base_string.c @@ -1699,6 +1699,23 @@ fuzzy_match_find(Arena *arena, String8 needle, String8 haystack) scratch_end(scratch); return result; } + +internal FuzzyMatchRangeList +fuzzy_match_range_list_copy(Arena *arena, FuzzyMatchRangeList *src) +{ + FuzzyMatchRangeList dst = {0}; + for(FuzzyMatchRangeNode *src_n = src->first; src_n != 0; src_n = src_n->next) + { + FuzzyMatchRangeNode *dst_n = push_array(arena, FuzzyMatchRangeNode, 1); + SLLQueuePush(dst.first, dst.last, dst_n); + dst_n->range = src_n->range; + } + dst.count = src->count; + dst.needle_part_count = src->needle_part_count; + dst.total_dim = src->total_dim; + return dst; +} + //////////////////////////////// //~ NOTE(allen): Serialization Helpers diff --git a/src/base/base_string.h b/src/base/base_string.h index 0f41849a..21384967 100644 --- a/src/base/base_string.h +++ b/src/base/base_string.h @@ -342,6 +342,7 @@ internal Vec4F32 rgba_from_hex_string_4f32(String8 hex_string); //~ rjf: String Fuzzy Matching internal FuzzyMatchRangeList fuzzy_match_find(Arena *arena, String8 needle, String8 haystack); +internal FuzzyMatchRangeList fuzzy_match_range_list_copy(Arena *arena, FuzzyMatchRangeList *src); //////////////////////////////// //~ NOTE(allen): Serialization Helpers diff --git a/src/df/gfx/df_gfx.c b/src/df/gfx/df_gfx.c index 4f2d50c1..3c76984c 100644 --- a/src/df/gfx/df_gfx.c +++ b/src/df/gfx/df_gfx.c @@ -6472,6 +6472,12 @@ df_window_update_and_render(Arena *arena, OS_EventList *events, DF_Window *ws, D ellipses_run = f_push_run_from_string(scratch.arena, box->font, box->font_size, 0, str8_lit("...")); } d_truncated_fancy_run_list(text_position, &box->display_string_runs, max_x, ellipses_run); + if(box->flags & UI_BoxFlag_HasFuzzyMatchRanges) + { + Vec4F32 match_color = df_rgba_from_theme_color(DF_ThemeColor_Cursor); + match_color.w *= 0.25f; + d_truncated_fancy_run_fuzzy_matches(text_position, &box->display_string_runs, max_x, &box->fuzzy_match_ranges, match_color); + } } // rjf: draw focus viz @@ -8390,38 +8396,6 @@ df_cfg_strings_from_gfx(Arena *arena, String8 root_path, DF_CfgSrc source) return strs; } -//////////////////////////////// -//~ rjf: UI Helpers - -internal void -df_box_equip_fuzzy_match_range_list_vis(UI_Box *box, FuzzyMatchRangeList range_list) -{ - UI_Parent(box) - { - String8 display_string = ui_box_display_string(box); - F_Metrics metrics = f_metrics_from_tag_size(box->font, box->font_size); - F32 line_height = f_line_height_from_metrics(&metrics); - for(FuzzyMatchRangeNode *match_n = range_list.first; match_n != 0; match_n = match_n->next) - { - Rng1F32 match_pixel_range = - { - f_dim_from_tag_size_string(box->font, box->font_size, str8_prefix(display_string, match_n->range.min)).x, - f_dim_from_tag_size_string(box->font, box->font_size, str8_prefix(display_string, match_n->range.max)).x, - }; - ui_set_next_fixed_x(match_pixel_range.min + box->text_padding + 4.f); - ui_set_next_fixed_y(box->font_size/8.f); - ui_set_next_fixed_width(match_pixel_range.max-match_pixel_range.min); - ui_set_next_pref_height(ui_pct(1, 0)); - ui_set_next_corner_radius_00(box->font_size/3.f); - ui_set_next_corner_radius_01(box->font_size/3.f); - ui_set_next_corner_radius_10(box->font_size/3.f); - ui_set_next_corner_radius_11(box->font_size/3.f); - ui_set_next_background_color(df_rgba_from_theme_color(DF_ThemeColor_PlainOverlay)); - ui_build_box_from_key(UI_BoxFlag_FloatingX|UI_BoxFlag_FloatingY|UI_BoxFlag_DrawBackground, ui_key_zero()); - } - } -} - //////////////////////////////// //~ rjf: UI Widgets: Fancy Buttons @@ -10935,7 +10909,7 @@ df_line_edit(DF_LineEditFlags flags, S32 depth, FuzzyMatchRangeList *matches, Tx UI_Box *box = df_code_label(1.f, 1, ui_top_text_color(), display_string); if(matches != 0) { - df_box_equip_fuzzy_match_range_list_vis(box, *matches); + ui_box_equip_fuzzy_match_ranges(box, matches); } } else if(flags & DF_LineEditFlag_DisplayStringIsCode) @@ -10943,7 +10917,7 @@ df_line_edit(DF_LineEditFlags flags, S32 depth, FuzzyMatchRangeList *matches, Tx UI_Box *box = df_code_label(1.f, 1, ui_top_text_color(), display_string); if(matches != 0) { - df_box_equip_fuzzy_match_range_list_vis(box, *matches); + ui_box_equip_fuzzy_match_ranges(box, matches); } } else @@ -10952,7 +10926,7 @@ df_line_edit(DF_LineEditFlags flags, S32 depth, FuzzyMatchRangeList *matches, Tx UI_Box *box = ui_label(display_string).box; if(matches != 0) { - df_box_equip_fuzzy_match_range_list_vis(box, *matches); + ui_box_equip_fuzzy_match_ranges(box, matches); } } } @@ -10970,7 +10944,7 @@ df_line_edit(DF_LineEditFlags flags, S32 depth, FuzzyMatchRangeList *matches, Tx UI_Box *box = ui_label(display_string).box; if(matches != 0) { - df_box_equip_fuzzy_match_range_list_vis(box, *matches); + ui_box_equip_fuzzy_match_ranges(box, matches); } } else if(is_focus_active && flags & DF_LineEditFlag_CodeContents) diff --git a/src/df/gfx/df_gfx.h b/src/df/gfx/df_gfx.h index 75bd2b4b..09a5abb1 100644 --- a/src/df/gfx/df_gfx.h +++ b/src/df/gfx/df_gfx.h @@ -1018,11 +1018,6 @@ internal F32 df_font_size_from_slot(DF_Window *ws, DF_FontSlot slot); //- rjf: config serialization internal String8List df_cfg_strings_from_gfx(Arena *arena, String8 root_path, DF_CfgSrc source); -//////////////////////////////// -//~ rjf: UI Helpers - -internal void df_box_equip_fuzzy_match_range_list_vis(UI_Box *box, FuzzyMatchRangeList range_list); - //////////////////////////////// //~ rjf: UI Widgets: Fancy Buttons diff --git a/src/df/gfx/df_views.c b/src/df/gfx/df_views.c index c55613db..db9ef6c0 100644 --- a/src/df/gfx/df_views.c +++ b/src/df/gfx/df_views.c @@ -1965,8 +1965,8 @@ DF_VIEW_UI_FUNCTION_DEF(Commands) { desc_box = ui_build_box_from_stringf(UI_BoxFlag_DrawText, "%S##desc_%p", cmd_desc, item->cmd_spec); } - df_box_equip_fuzzy_match_range_list_vis(name_box, item->name_match_ranges); - df_box_equip_fuzzy_match_range_list_vis(desc_box, item->desc_match_ranges); + ui_box_equip_fuzzy_match_ranges(name_box, &item->name_match_ranges); + ui_box_equip_fuzzy_match_ranges(desc_box, &item->desc_match_ranges); } //- rjf: binding @@ -2405,7 +2405,7 @@ DF_VIEW_UI_FUNCTION_DEF(FileSystem) UI_PrefWidth(ui_pct(1, 0)) { UI_Box *box = ui_build_box_from_stringf(UI_BoxFlag_DrawText, "%S##%p", file->filename, view); - df_box_equip_fuzzy_match_range_list_vis(box, file->match_ranges); + ui_box_equip_fuzzy_match_ranges(box, &file->match_ranges); } } @@ -2579,14 +2579,14 @@ DF_VIEW_UI_FUNCTION_DEF(SystemProcesses) if(is_attached) UI_TextColor(df_rgba_from_theme_color(DF_ThemeColor_Highlight1)) UI_PrefWidth(ui_text_dim(10, 1)) { UI_Box *attached_label = ui_build_box_from_stringf(UI_BoxFlag_DrawText, "[attached]##attached_label_%i", (int)info->info.pid); - df_box_equip_fuzzy_match_range_list_vis(attached_label, info->attached_match_ranges); + ui_box_equip_fuzzy_match_ranges(attached_label, &info->attached_match_ranges); } // rjf: process name UI_PrefWidth(ui_text_dim(10, 1)) { UI_Box *name_label = ui_build_box_from_stringf(UI_BoxFlag_DrawText, "%S##name_label_%i", info->info.name, (int)info->info.pid); - df_box_equip_fuzzy_match_range_list_vis(name_label, info->name_match_ranges); + ui_box_equip_fuzzy_match_ranges(name_label, &info->name_match_ranges); } // rjf: process number @@ -2594,7 +2594,7 @@ DF_VIEW_UI_FUNCTION_DEF(SystemProcesses) { ui_labelf("[PID: "); UI_Box *pid_label = ui_build_box_from_stringf(UI_BoxFlag_DrawText, "%i##pid_label", info->info.pid); - df_box_equip_fuzzy_match_range_list_vis(pid_label, info->pid_match_ranges); + ui_box_equip_fuzzy_match_ranges(pid_label, &info->pid_match_ranges); ui_labelf("]"); } } @@ -2748,7 +2748,7 @@ DF_VIEW_UI_FUNCTION_DEF(EntityLister) ui_set_next_text_color(color); } UI_Box *name_label = ui_build_box_from_stringf(UI_BoxFlag_DrawText, "%S##label_%p", display_string, ent); - df_box_equip_fuzzy_match_range_list_vis(name_label, item.name_match_ranges); + ui_box_equip_fuzzy_match_ranges(name_label, &item.name_match_ranges); } if(ui_signal_from_box(box).clicked) { @@ -2880,7 +2880,7 @@ DF_VIEW_UI_FUNCTION_DEF(SymbolLister) UI_Parent(box) UI_PrefWidth(ui_text_dim(10, 1)) { UI_Box *box = df_code_label(1.f, 0, df_rgba_from_theme_color(DF_ThemeColor_CodeFunction), name); - df_box_equip_fuzzy_match_range_list_vis(box, item->match_ranges); + ui_box_equip_fuzzy_match_ranges(box, &item->match_ranges); if(!tg_key_match(tg_key_zero(), type_key)) { String8 type_string = tg_string_from_key(scratch.arena, graph, rdbg, type_key); diff --git a/src/draw/draw.c b/src/draw/draw.c index 7b610fc7..c0174c43 100644 --- a/src/draw/draw.c +++ b/src/draw/draw.c @@ -439,16 +439,14 @@ d_truncated_fancy_run_list(Vec2F32 p, D_FancyRunList *list, F32 max_x, F_Run tra { ProfBeginFunction(); - // rjf: grab total advance - F32 run_list_total_advance = list->dim.x; + //- rjf: total advance > max? -> enable trailer + B32 trailer_enabled = (list->dim.x >= max_x && trailer_run.dim.x < max_x); - // rjf: total advance > max? -> enable trailer - B32 trailer_enabled = (run_list_total_advance >= max_x && trailer_run.dim.x < max_x); - - // rjf: draw runs + //- rjf: draw runs F32 advance = 0; B32 trailer_found = 0; Vec4F32 last_color = {0}; + U64 byte_off = 0; for(D_FancyRunNode *n = list->first; n != 0; n = n->next) { D_FancyRun *fr = &n->v; @@ -479,6 +477,7 @@ d_truncated_fancy_run_list(Vec2F32 p, D_FancyRunList *list, F32 max_x, F_Run tra if(!r_handle_match(texture, r_handle_zero())) { d_img(dst, src, texture, fr->color, 0, 0, 0); + //d_rect(dst, v4f32(1, 0, 0, 1), 0, 1.f, 0.f); } advance += piece->advance; } @@ -501,7 +500,7 @@ d_truncated_fancy_run_list(Vec2F32 p, D_FancyRunList *list, F32 max_x, F_Run tra } end_draw:; - // rjf: draw trailer + //- rjf: draw trailer if(trailer_found) { F_Piece *piece_first = trailer_run.pieces.v; @@ -531,6 +530,54 @@ d_truncated_fancy_run_list(Vec2F32 p, D_FancyRunList *list, F32 max_x, F_Run tra ProfEnd(); } +internal void +d_truncated_fancy_run_fuzzy_matches(Vec2F32 p, D_FancyRunList *list, F32 max_x, FuzzyMatchRangeList *ranges, Vec4F32 color) +{ + for(FuzzyMatchRangeNode *match_n = ranges->first; match_n != 0; match_n = match_n->next) + { + Rng1U64 byte_range = match_n->range; + Rng1F32 pixel_range = {0}; + { + pixel_range.min = 100000; + pixel_range.max = 0; + } + F32 last_piece_end_pad = 0; + U64 byte_off = 0; + F32 advance = 0; + F32 ascent = 0; + F32 descent = 0; + for(D_FancyRunNode *fr_n = list->first; fr_n != 0; fr_n = fr_n->next) + { + D_FancyRun *fr = &fr_n->v; + F_Run *run = &fr->run; + ascent = run->ascent; + descent = run->descent; + for(U64 piece_idx = 0; piece_idx < run->pieces.count; piece_idx += 1) + { + F_Piece *piece = &run->pieces.v[piece_idx]; + if(contains_1u64(byte_range, byte_off)) + { + F32 pre_advance = advance+piece->offset.x; + F32 post_advance = advance+piece->advance; + last_piece_end_pad = ((F32)piece->offset.x+(F32)dim_2s16(piece->subrect).x) - piece->advance; + pixel_range.min = Min(pre_advance, pixel_range.min); + pixel_range.max = Max(post_advance, pixel_range.max); + } + byte_off += piece->decode_size; + advance += piece->advance; + } + } + if(pixel_range.min < pixel_range.max) + { + Rng2F32 rect = r2f32p(p.x + pixel_range.min, p.y - descent - ascent, + p.x + pixel_range.max + last_piece_end_pad/2, p.y - descent - ascent + list->dim.y); + rect.x0 = Min(rect.x0, p.x+max_x); + rect.x1 = Min(rect.x1, p.x+max_x); + d_rect(rect, color, (descent+ascent)/4.f, 0, 1.f); + } + } +} + internal void d_text_run(Vec2F32 p, Vec4F32 color, F_Run run) { diff --git a/src/draw/draw.h b/src/draw/draw.h index 72719163..7f94af9e 100644 --- a/src/draw/draw.h +++ b/src/draw/draw.h @@ -183,6 +183,7 @@ internal void d_sub_bucket(D_Bucket *bucket); //- rjf: text internal void d_truncated_fancy_run_list(Vec2F32 p, D_FancyRunList *list, F32 max_x, F_Run trailer_run); +internal void d_truncated_fancy_run_fuzzy_matches(Vec2F32 p, D_FancyRunList *list, F32 max_x, FuzzyMatchRangeList *ranges, Vec4F32 color); internal void d_text_run(Vec2F32 p, Vec4F32 color, F_Run run); internal void d_truncated_text_run(Vec2F32 p, Vec4F32 color, F32 max_x, F_Run text_run, F_Run trailer_run); internal void d_text(F_Tag font, F32 size, Vec2F32 p, Vec4F32 color, String8 string); diff --git a/src/ui/ui_core.c b/src/ui/ui_core.c index 8bef651a..5f866bdb 100644 --- a/src/ui/ui_core.c +++ b/src/ui/ui_core.c @@ -2195,6 +2195,13 @@ ui_box_equip_display_string_fancy_runs(UI_Box *box, String8 string, D_FancyRunLi box->display_string_runs = d_fancy_run_list_copy(ui_build_arena(), runs); } +internal inline void +ui_box_equip_fuzzy_match_ranges(UI_Box *box, FuzzyMatchRangeList *matches) +{ + box->flags |= UI_BoxFlag_HasFuzzyMatchRanges; + box->fuzzy_match_ranges = fuzzy_match_range_list_copy(ui_build_arena(), matches); +} + internal void ui_box_equip_draw_bucket(UI_Box *box, D_Bucket *bucket) { diff --git a/src/ui/ui_core.h b/src/ui/ui_core.h index 4f15e72e..ffe1c33c 100644 --- a/src/ui/ui_core.h +++ b/src/ui/ui_core.h @@ -235,7 +235,8 @@ typedef U64 UI_BoxFlags; # define UI_BoxFlag_DisableFocusViz (UI_BoxFlags)(1ull<<44) # define UI_BoxFlag_RequireFocusBackground (UI_BoxFlags)(1ull<<45) # define UI_BoxFlag_HasDisplayString (UI_BoxFlags)(1ull<<46) -# define UI_BoxFlag_RoundChildrenByParent (UI_BoxFlags)(1ull<<47) +# define UI_BoxFlag_HasFuzzyMatchRanges (UI_BoxFlags)(1ull<<47) +# define UI_BoxFlag_RoundChildrenByParent (UI_BoxFlags)(1ull<<48) //- rjf: bundles # define UI_BoxFlag_Clickable (UI_BoxFlag_MouseClickable|UI_BoxFlag_KeyboardClickable) @@ -294,7 +295,7 @@ struct UI_Box Rng2F32 rect; Vec2F32 fixed_position_animated; Vec2F32 position_delta; - U64 num_focus_children; + FuzzyMatchRangeList fuzzy_match_ranges; //- rjf: persistent data U64 first_touched_build_index; @@ -605,6 +606,7 @@ internal UI_Box * ui_build_box_from_stringf(UI_BoxFlags flags, char *fm internal inline void ui_box_equip_display_string(UI_Box *box, String8 string); internal inline void ui_box_equip_display_fancy_strings(UI_Box *box, D_FancyStringList *strings); internal inline void ui_box_equip_display_string_fancy_runs(UI_Box *box, String8 string, D_FancyRunList *runs); +internal inline void ui_box_equip_fuzzy_match_ranges(UI_Box *box, FuzzyMatchRangeList *matches); internal inline void ui_box_equip_draw_bucket(UI_Box *box, D_Bucket *bucket); internal inline void ui_box_equip_custom_draw(UI_Box *box, UI_BoxCustomDrawFunctionType *custom_draw, void *user_data);