From 6ac870dac0c66d6be52596348376adda955e4c6a Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Sat, 22 Jun 2024 15:58:40 -0700 Subject: [PATCH] improvements in text layout, focus visualization, smooth text rasterization for icons; checkpoint in ui visuals pass --- src/df/gfx/df_gfx.c | 129 ++++++++++-------- src/df/gfx/df_gfx.h | 3 + src/df/gfx/df_views.c | 5 +- src/font_cache/font_cache.c | 13 +- src/font_cache/font_cache.h | 3 +- .../dwrite/font_provider_dwrite.c | 74 +++++++--- .../dwrite/font_provider_dwrite.h | 15 +- src/font_provider/font_provider.h | 2 +- src/ui/ui_basic_widgets.c | 2 +- src/ui/ui_core.c | 11 +- src/ui/ui_core.h | 21 +-- 11 files changed, 179 insertions(+), 99 deletions(-) diff --git a/src/df/gfx/df_gfx.c b/src/df/gfx/df_gfx.c index 31ef599a..b5ca9379 100644 --- a/src/df/gfx/df_gfx.c +++ b/src/df/gfx/df_gfx.c @@ -4339,14 +4339,21 @@ df_window_update_and_render(Arena *arena, DF_Window *ws, DF_CmdList *cmds) UI_BlurSize(10*df_gfx_state->confirm_t) UI_Palette(palette) { - bg_box = ui_build_box_from_stringf(UI_BoxFlag_FixedSize|UI_BoxFlag_Floating|UI_BoxFlag_Clickable|UI_BoxFlag_Scroll|UI_BoxFlag_DefaultFocusNav|UI_BoxFlag_DrawBackgroundBlur|UI_BoxFlag_DrawBackground, "###confirm_popup_%p", ws); + bg_box = ui_build_box_from_stringf(UI_BoxFlag_FixedSize| + UI_BoxFlag_Floating| + UI_BoxFlag_Clickable| + UI_BoxFlag_Scroll| + UI_BoxFlag_DefaultFocusNav| + UI_BoxFlag_DisableFocusOverlay| + UI_BoxFlag_DrawBackgroundBlur| + UI_BoxFlag_DrawBackground, "###confirm_popup_%p", ws); } if(df_gfx_state->confirm_active) UI_Parent(bg_box) UI_Transparency(1-df_gfx_state->confirm_t) { ui_ctx_menu_close(); UI_WidthFill UI_PrefHeight(ui_children_sum(1.f)) UI_Column UI_Padding(ui_pct(1, 0)) { - UI_FontSize(ui_top_font_size()*2.f) UI_PrefHeight(ui_em(3.f, 1.f)) ui_label(df_gfx_state->confirm_title); + UI_RunFlags(F_RunFlag_Smooth) UI_FontSize(ui_top_font_size()*2.f) UI_PrefHeight(ui_em(3.f, 1.f)) ui_label(df_gfx_state->confirm_title); UI_PrefHeight(ui_em(3.f, 1.f)) UI_FlagsAdd(UI_BoxFlag_DrawTextWeak) ui_label(df_gfx_state->confirm_msg); ui_spacer(ui_em(1.5f, 1.f)); UI_Row UI_Padding(ui_pct(1.f, 0.f)) UI_WidthFill UI_PrefHeight(ui_em(5.f, 1.f)) @@ -4597,8 +4604,8 @@ df_window_update_and_render(Arena *arena, DF_Window *ws, DF_CmdList *cmds) F32 row_height_px = floor_f32(ui_top_font_size()*2.5f); ui_set_next_fixed_x(autocomp_root_box->rect.x0); ui_set_next_fixed_y(autocomp_root_box->rect.y1); - ui_set_next_pref_width(ui_em(25.f, 1.f)); - ui_set_next_pref_height(ui_px(row_height_px*ws->autocomp_num_visible_rows_t, 1.f)); + ui_set_next_pref_width(ui_em(30.f, 1.f)); + ui_set_next_pref_height(ui_px(row_height_px*ws->autocomp_num_visible_rows_t + ui_top_font_size()*2.f, 1.f)); ui_set_next_child_layout_axis(Axis2_Y); ui_set_next_corner_radius_01(ui_top_font_size()*0.25f); ui_set_next_corner_radius_11(ui_top_font_size()*0.25f); @@ -4607,15 +4614,30 @@ df_window_update_and_render(Arena *arena, DF_Window *ws, DF_CmdList *cmds) UI_Squish(0.25f-0.25f*ws->autocomp_open_t) UI_Transparency(1.f-ws->autocomp_open_t) { - autocomp_box = ui_build_box_from_stringf(UI_BoxFlag_DefaultFocusNavY|UI_BoxFlag_Clickable|UI_BoxFlag_Clip|UI_BoxFlag_RoundChildrenByParent|UI_BoxFlag_DrawBorder|UI_BoxFlag_DrawBackgroundBlur|UI_BoxFlag_DrawDropShadow|UI_BoxFlag_DrawBackground, "autocomp_box"); + autocomp_box = ui_build_box_from_stringf(UI_BoxFlag_DefaultFocusNavY| + UI_BoxFlag_Clickable| + UI_BoxFlag_Clip| + UI_BoxFlag_RoundChildrenByParent| + UI_BoxFlag_DisableFocusOverlay| + UI_BoxFlag_DrawBorder| + UI_BoxFlag_DrawBackgroundBlur| + UI_BoxFlag_DrawDropShadow| + UI_BoxFlag_DrawBackground, + "autocomp_box"); if(ws->autocomp_query_dirty) { ws->autocomp_query_dirty = 0; autocomp_box->default_nav_focus_hot_key = autocomp_box->default_nav_focus_active_key = autocomp_box->default_nav_focus_next_hot_key = autocomp_box->default_nav_focus_next_active_key = ui_key_zero(); } } - UI_Parent(autocomp_box) UI_WidthFill UI_PrefHeight(ui_px(row_height_px, 1.f)) UI_Font(df_font_from_slot(DF_FontSlot_Code)) UI_HoverCursor(OS_Cursor_HandPoint) + UI_Parent(autocomp_box) + UI_WidthFill + UI_PrefHeight(ui_px(row_height_px, 1.f)) + UI_Font(df_font_from_slot(DF_FontSlot_Code)) + UI_HoverCursor(OS_Cursor_HandPoint) UI_Focus(UI_FocusKind_Null) + DF_Palette(DF_PaletteCode_ImplicitContents) + UI_Padding(ui_em(1.f, 1.f)) { for(U64 idx = 0; idx < item_array.count; idx += 1) { @@ -4684,11 +4706,17 @@ df_window_update_and_render(Arena *arena, DF_Window *ws, DF_CmdList *cmds) UI_WidthFill UI_NamedRow(str8_lit("###menu_bar")) { //- rjf: icon - UI_Padding(ui_em(0.5f, 1.f)) UI_PrefWidth(ui_px(dim_2f32(top_bar_rect).y, 1.f)) + UI_Padding(ui_em(0.5f, 1.f)) { - R_Handle texture = df_gfx_state->icon_texture; - Vec2S32 texture_dim = r_size_from_tex2d(texture); - ui_image(texture, R_Tex2DSampleKind_Linear, r2f32p(0, 0, texture_dim.x, texture_dim.y), v4f32(1, 1, 1, 1), 0, str8_lit("")); + UI_PrefWidth(ui_px(dim_2f32(top_bar_rect).y - ui_top_font_size()*0.8f, 1.f)) + UI_Column + UI_Padding(ui_em(0.4f, 1.f)) + UI_HeightFill + { + R_Handle texture = df_gfx_state->icon_texture; + Vec2S32 texture_dim = r_size_from_tex2d(texture); + ui_image(texture, R_Tex2DSampleKind_Linear, r2f32p(0, 0, texture_dim.x, texture_dim.y), v4f32(1, 1, 1, 1), 0, str8_lit("")); + } } //- rjf: menu items @@ -5127,7 +5155,7 @@ df_window_update_and_render(Arena *arena, DF_Window *ws, DF_CmdList *cmds) if(can_play || !have_targets || processes.count == 0) UI_TextAlignment(UI_TextAlign_Center) UI_Flags((can_play ? 0 : UI_BoxFlag_Disabled)) - DF_Palette(DF_PaletteCode_DefaultPositive) + DF_Palette(DF_PaletteCode_MenuBarPositive) { UI_Signal sig = ui_button(df_g_icon_kind_text_table[DF_IconKind_Play]); os_window_push_custom_title_bar_client_area(ws->os, sig.box->rect); @@ -5168,7 +5196,7 @@ df_window_update_and_render(Arena *arena, DF_Window *ws, DF_CmdList *cmds) //- rjf: restart button if(!can_play && processes.count != 0) UI_TextAlignment(UI_TextAlign_Center) - DF_Palette(DF_PaletteCode_DefaultPositive) + DF_Palette(DF_PaletteCode_MenuBarPositive) { UI_Signal sig = ui_button(df_g_icon_kind_text_table[DF_IconKind_Redo]); os_window_push_custom_title_bar_client_area(ws->os, sig.box->rect); @@ -5203,7 +5231,7 @@ df_window_update_and_render(Arena *arena, DF_Window *ws, DF_CmdList *cmds) //- rjf: pause button UI_TextAlignment(UI_TextAlign_Center) UI_Flags(can_pause ? 0 : UI_BoxFlag_Disabled) - DF_Palette(DF_PaletteCode_DefaultNeutral) + DF_Palette(DF_PaletteCode_MenuBarNeutral) { UI_Signal sig = ui_button(df_g_icon_kind_text_table[DF_IconKind_Pause]); os_window_push_custom_title_bar_client_area(ws->os, sig.box->rect); @@ -5230,7 +5258,7 @@ df_window_update_and_render(Arena *arena, DF_Window *ws, DF_CmdList *cmds) //- rjf: stop button UI_TextAlignment(UI_TextAlign_Center) UI_Flags(can_stop ? 0 : UI_BoxFlag_Disabled) - DF_Palette(DF_PaletteCode_DefaultNegative) + DF_Palette(DF_PaletteCode_MenuBarNegative) { UI_Signal sig = {0}; { @@ -5736,6 +5764,7 @@ df_window_update_and_render(Arena *arena, DF_Window *ws, DF_CmdList *cmds) UI_BoxFlag_AllowOverflow| UI_BoxFlag_Clickable| UI_BoxFlag_Clip| + UI_BoxFlag_DisableFocusOverlay| UI_BoxFlag_DrawBorder| UI_BoxFlag_DrawBackground| UI_BoxFlag_DrawBackgroundBlur| @@ -5984,6 +6013,7 @@ df_window_update_and_render(Arena *arena, DF_Window *ws, DF_CmdList *cmds) UI_BoxFlag_DrawBackground| UI_BoxFlag_DrawBackgroundBlur| UI_BoxFlag_DrawDropShadow| + UI_BoxFlag_DisableFocusOverlay| UI_BoxFlag_Clip| UI_BoxFlag_AllowOverflowY| UI_BoxFlag_ViewScroll| @@ -6808,7 +6838,8 @@ df_window_update_and_render(Arena *arena, DF_Window *ws, DF_CmdList *cmds) panel_box = ui_build_box_from_key(UI_BoxFlag_MouseClickable| UI_BoxFlag_Clip| UI_BoxFlag_DrawBorder| - ((ws->focused_panel != panel)*UI_BoxFlag_DisableFocusViz)| + UI_BoxFlag_DisableFocusOverlay| + ((ws->focused_panel != panel)*UI_BoxFlag_DisableFocusBorder)| ((ws->focused_panel != panel)*UI_BoxFlag_DrawOverlay), panel_key); } @@ -7076,7 +7107,7 @@ df_window_update_and_render(Arena *arena, DF_Window *ws, DF_CmdList *cmds) if((!view_is_selected && panel->tab_side == Side_Min) || (view_is_selected && panel->tab_side == Side_Max)) { - ui_spacer(ui_px(tab_bar_rv_diff, 1.f)); + ui_spacer(ui_px(1.f, 1.f)); } else { @@ -7157,6 +7188,7 @@ df_window_update_and_render(Arena *arena, DF_Window *ws, DF_CmdList *cmds) UI_Font(df_font_from_slot(DF_FontSlot_Icons)) UI_FontSize(df_font_size_from_slot(ws, DF_FontSlot_Icons)*0.75f) UI_RunFlags(F_RunFlag_Smooth) + UI_Flags(UI_BoxFlag_DrawTextWeak) UI_CornerRadius00(0) UI_CornerRadius01(0) { @@ -7228,10 +7260,11 @@ df_window_update_and_render(Arena *arena, DF_Window *ws, DF_CmdList *cmds) ui_spacer(ui_px(tab_bar_rv_diff/2.f, 1.f)); UI_CornerRadius(tab_bar_vheight/2.f) UI_Font(df_font_from_slot(DF_FontSlot_Icons)) - UI_FontSize(ui_top_font_size()*0.75f) + UI_FontSize(ui_top_font_size()) UI_RunFlags(F_RunFlag_Smooth) UI_FlagsAdd(UI_BoxFlag_DrawTextWeak) UI_HoverCursor(OS_Cursor_HandPoint) + DF_Palette(DF_PaletteCode_ImplicitContents) { UI_Box *add_new_box = ui_build_box_from_stringf(UI_BoxFlag_DrawBackground| UI_BoxFlag_DrawText| @@ -7906,30 +7939,17 @@ df_window_update_and_render(Arena *arena, DF_Window *ws, DF_CmdList *cmds) } } - // rjf: draw focus hot vis - if(b->flags & UI_BoxFlag_Clickable && !(b->flags & UI_BoxFlag_DisableFocusViz) && b->focus_hot_t > 0.01f) + // rjf: draw focus overlay + if(b->flags & UI_BoxFlag_Clickable && !(b->flags & UI_BoxFlag_DisableFocusOverlay) && b->focus_hot_t > 0.01f) { - Vec4F32 color = df_rgba_from_theme_color(DF_ThemeColor_Highlight0); - F32 size_factor = 1 - Clamp(0, dim_2f32(b->rect).y / 100.f, 1); - if(b->flags & UI_BoxFlag_RequireFocusBackground) - { - color.w *= 0.2f + b->focus_hot_t * 0.3f * size_factor; - } - else - { - color.w *= b->focus_hot_t * 0.5f * size_factor; - } - R_Rect2DInst *inst = d_rect(pad_2f32(r2f32p(b->rect.x0, - b->rect.y0, - b->rect.x0 + (b->rect.x1 - b->rect.x0) * 1.f, - b->rect.y1), - 1.f), - color, 4.f, 0, 1.f); + Vec4F32 color = df_rgba_from_theme_color(DF_ThemeColor_FocusActive); + color.w *= 0.2f*b->focus_hot_t; + R_Rect2DInst *inst = d_rect(b->rect, color, 0, 0, 1.f); MemoryCopyArray(inst->corner_radii, b->corner_radii); } - // rjf: draw focus active vis - if(b->flags & UI_BoxFlag_Clickable && !(b->flags & UI_BoxFlag_DisableFocusViz) && b->focus_active_t > 0.01f) + // rjf: draw focus border + if(b->flags & UI_BoxFlag_Clickable && !(b->flags & UI_BoxFlag_DisableFocusBorder) && b->focus_active_t > 0.01f) { Vec4F32 color = df_rgba_from_theme_color(DF_ThemeColor_FocusActive); color.w *= b->focus_active_t; @@ -7937,15 +7957,6 @@ df_window_update_and_render(Arena *arena, DF_Window *ws, DF_CmdList *cmds) MemoryCopyArray(inst->corner_radii, b->corner_radii); } - // rjf: draw focus active disabled vis - if(b->flags & UI_BoxFlag_Clickable && !(b->flags & UI_BoxFlag_DisableFocusViz) && b->focus_active_disabled_t > 0.01f) - { - Vec4F32 color = df_rgba_from_theme_color(DF_ThemeColor_FocusInactive); - color.w *= b->focus_active_disabled_t; - R_Rect2DInst *inst = d_rect(pad_2f32(b->rect, 1.f), color, 0, 1.f, 1.f); - MemoryCopyArray(inst->corner_radii, b->corner_radii); - } - // rjf: disabled overlay if(b->disabled_t >= 0.005f) { @@ -9827,19 +9838,15 @@ df_cmd_binding_button(DF_CmdSpec *spec) ui_set_next_palette(palette); UI_Box *box = ui_build_box_from_stringf(UI_BoxFlag_DrawText| UI_BoxFlag_Clickable| - UI_BoxFlag_DrawActiveEffects, + UI_BoxFlag_DrawActiveEffects| + UI_BoxFlag_DrawHotEffects| + UI_BoxFlag_DrawBorder| + UI_BoxFlag_DrawBackground, "%S###bind_btn_%p", keybinding_str, spec); //- rjf: interaction UI_Signal sig = ui_signal_from_box(box); { - // rjf: hover => visualize clickability - if(ui_hovering(sig)) - { - box->flags |= UI_BoxFlag_DrawBorder; - box->flags |= UI_BoxFlag_DrawBackground; - } - // rjf: click => toggle activity if(!df_gfx_state->bind_change_active && ui_clicked(sig)) { @@ -10577,7 +10584,7 @@ df_code_slice(DF_Window *ws, DF_CtrlCtx *ctrl_ctx, EVAL_ParseCtx *parse_ctx, DF_ ui_set_next_child_layout_axis(Axis2_X); ui_set_next_pref_width(ui_px(params->line_text_max_width_px, 1)); ui_set_next_pref_height(ui_children_sum(1)); - top_container_box = ui_build_box_from_string(UI_BoxFlag_DisableFocusViz|UI_BoxFlag_DrawBorder, string); + top_container_box = ui_build_box_from_string(UI_BoxFlag_DisableFocusEffects|UI_BoxFlag_DrawBorder, string); clipped_top_container_rect = top_container_box->rect; for(UI_Box *b = top_container_box; !ui_box_is_nil(b); b = b->parent) { @@ -14173,6 +14180,18 @@ df_gfx_begin_frame(Arena *arena, DF_CmdList *cmds) df_gfx_state->cfg_palettes[DF_PaletteCode_MenuBar].text = current->colors[DF_ThemeColor_MenuBarText]; df_gfx_state->cfg_palettes[DF_PaletteCode_MenuBar].text_weak = current->colors[DF_ThemeColor_MenuBarTextWeak]; df_gfx_state->cfg_palettes[DF_PaletteCode_MenuBar].border = current->colors[DF_ThemeColor_MenuBarBorder]; + df_gfx_state->cfg_palettes[DF_PaletteCode_MenuBarPositive].background = current->colors[DF_ThemeColor_MenuBarBackground]; + df_gfx_state->cfg_palettes[DF_PaletteCode_MenuBarPositive].text = current->colors[DF_ThemeColor_MenuBarTextPositive]; + df_gfx_state->cfg_palettes[DF_PaletteCode_MenuBarPositive].text_weak = current->colors[DF_ThemeColor_MenuBarTextWeak]; + df_gfx_state->cfg_palettes[DF_PaletteCode_MenuBarPositive].border = current->colors[DF_ThemeColor_MenuBarBorder]; + df_gfx_state->cfg_palettes[DF_PaletteCode_MenuBarNegative].background = current->colors[DF_ThemeColor_MenuBarBackground]; + df_gfx_state->cfg_palettes[DF_PaletteCode_MenuBarNegative].text = current->colors[DF_ThemeColor_MenuBarTextNegative]; + df_gfx_state->cfg_palettes[DF_PaletteCode_MenuBarNegative].text_weak = current->colors[DF_ThemeColor_MenuBarTextWeak]; + df_gfx_state->cfg_palettes[DF_PaletteCode_MenuBarNegative].border = current->colors[DF_ThemeColor_MenuBarBorder]; + df_gfx_state->cfg_palettes[DF_PaletteCode_MenuBarNeutral].background = current->colors[DF_ThemeColor_MenuBarBackground]; + df_gfx_state->cfg_palettes[DF_PaletteCode_MenuBarNeutral].text = current->colors[DF_ThemeColor_DefaultTextNeutral]; + df_gfx_state->cfg_palettes[DF_PaletteCode_MenuBarNeutral].text_weak = current->colors[DF_ThemeColor_MenuBarTextWeak]; + df_gfx_state->cfg_palettes[DF_PaletteCode_MenuBarNeutral].border = current->colors[DF_ThemeColor_MenuBarBorder]; df_gfx_state->cfg_palettes[DF_PaletteCode_TabActive].background = current->colors[DF_ThemeColor_TabActiveBackground]; df_gfx_state->cfg_palettes[DF_PaletteCode_TabActive].text = current->colors[DF_ThemeColor_TabActiveText]; df_gfx_state->cfg_palettes[DF_PaletteCode_TabActive].text_weak = current->colors[DF_ThemeColor_TabActiveTextWeak]; diff --git a/src/df/gfx/df_gfx.h b/src/df/gfx/df_gfx.h index 8f08ee50..379dc1e4 100644 --- a/src/df/gfx/df_gfx.h +++ b/src/df/gfx/df_gfx.h @@ -386,6 +386,9 @@ typedef enum DF_PaletteCode DF_PaletteCode_SpecialNegative, DF_PaletteCode_SpecialNeutral, DF_PaletteCode_MenuBar, + DF_PaletteCode_MenuBarPositive, + DF_PaletteCode_MenuBarNegative, + DF_PaletteCode_MenuBarNeutral, DF_PaletteCode_TabActive, DF_PaletteCode_TabInactive, DF_PaletteCode_Code, diff --git a/src/df/gfx/df_views.c b/src/df/gfx/df_views.c index 310df2ba..ffd95093 100644 --- a/src/df/gfx/df_views.c +++ b/src/df/gfx/df_views.c @@ -1658,7 +1658,10 @@ df_watch_view_build(DF_Window *ws, DF_Panel *panel, DF_View *view, DF_WatchViewS ui_set_next_flags(disabled_flags); ui_set_next_pref_width(ui_pct(1, 0)); ui_set_next_pref_height(ui_px(scroll_list_params.row_height_px*row->size_in_rows, 1.f)); - UI_Box *row_box = ui_build_box_from_stringf(UI_BoxFlag_DrawSideBottom|UI_BoxFlag_RequireFocusBackground|UI_BoxFlag_Clickable, "row_%I64x", row_hash); + ui_set_next_focus_hot(row_selected ? UI_FocusKind_On : UI_FocusKind_Off); + UI_Box *row_box = ui_build_box_from_stringf(UI_BoxFlag_DrawSideBottom|UI_BoxFlag_Clickable, "row_%I64x", row_hash); + ui_ts_vector_idx += 1; + ui_ts_cell_idx = 0; //////////////////////// //- rjf: canvas row -> fill with canvas ui build diff --git a/src/font_cache/font_cache.c b/src/font_cache/font_cache.c index 96d1a467..5832e05e 100644 --- a/src/font_cache/font_cache.c +++ b/src/font_cache/font_cache.c @@ -516,7 +516,7 @@ f_piece_array_copy(Arena *arena, F_PieceArray *src) //~ rjf: Rasterization Cache internal F_Hash2StyleRasterCacheNode * -f_hash2style_from_tag_size(F_Tag tag, F32 size) +f_hash2style_from_tag_size_flags(F_Tag tag, F32 size, F_RunFlags flags) { //- rjf: tag * size -> style hash U64 style_hash = {0}; @@ -527,6 +527,7 @@ f_hash2style_from_tag_size(F_Tag tag, F32 size) tag.u64[0], tag.u64[1], *(U64 *)(&size_f64), + (U64)flags, }; style_hash = f_little_hash_from_string(str8((U8 *)buffer, sizeof(buffer))); } @@ -571,11 +572,12 @@ f_push_run_from_string(Arena *arena, F_Tag tag, F32 size, F32 base_align_px, F32 ProfBeginFunction(); //- rjf: map tag/size to style node - F_Hash2StyleRasterCacheNode *hash2style_node = f_hash2style_from_tag_size(tag, size); + F_Hash2StyleRasterCacheNode *hash2style_node = f_hash2style_from_tag_size_flags(tag, size, flags); //- rjf: decode string & produce run pieces F_PieceChunkList piece_chunks = {0}; Vec2F32 dim = {0}; + F32 last_piece_end_pad = 0; B32 font_handle_mapped_on_miss = 0; FP_Handle font_handle = {0}; U64 piece_substring_start_idx = 0; @@ -683,7 +685,7 @@ f_push_run_from_string(Arena *arena, F_Tag tag, F32 size, F32 base_align_px, F32 } // rjf: call into font provider to rasterize this substring - FP_RasterResult raster = fp_raster(scratch.arena, font_handle, floor_f32(size), FP_RasterMode_Sharp, piece_substring); + FP_RasterResult raster = fp_raster(scratch.arena, font_handle, floor_f32(size), (flags & F_RunFlag_Smooth) ? FP_RasterMode_Smooth : FP_RasterMode_Sharp, piece_substring); // rjf: allocate portion of an atlas to upload the rasterization S16 chosen_atlas_num = 0; @@ -759,6 +761,7 @@ f_push_run_from_string(Arena *arena, F_Tag tag, F32 size, F32 base_align_px, F32 if(info != 0) { info->subrect = chosen_atlas_region; + info->bounding_box = raster.bounding_box; info->atlas_num = chosen_atlas_num; info->raster_dim = raster.atlas_dim; info->advance = raster.advance; @@ -811,7 +814,8 @@ f_push_run_from_string(Arena *arena, F_Tag tag, F32 size, F32 base_align_px, F32 } base_align_px += advance; dim.x += piece->advance; - dim.y = Max(dim.y, dim_2s16(piece->subrect).y); + dim.y = Max(dim.y, info->raster_dim.y); + last_piece_end_pad = ((F32)piece->offset.x+(F32)dim_2s16(info->bounding_box).x) - piece->advance; } } } @@ -829,6 +833,7 @@ f_push_run_from_string(Arena *arena, F_Tag tag, F32 size, F32 base_align_px, F32 run.pieces = f_piece_array_from_chunk_list(arena, &piece_chunks); } run.dim = dim; + run.dim.x += last_piece_end_pad; run.ascent = hash2style_node->ascent; run.descent = hash2style_node->descent; } diff --git a/src/font_cache/font_cache.h b/src/font_cache/font_cache.h index 0e4ab173..8cb72523 100644 --- a/src/font_cache/font_cache.h +++ b/src/font_cache/font_cache.h @@ -102,6 +102,7 @@ typedef struct F_RasterCacheInfo F_RasterCacheInfo; struct F_RasterCacheInfo { Rng2S16 subrect; + Rng2S16 bounding_box; Vec2S16 raster_dim; S16 atlas_num; F32 advance; @@ -247,7 +248,7 @@ internal F_PieceArray f_piece_array_copy(Arena *arena, F_PieceArray *src); //////////////////////////////// //~ rjf: Rasterization Cache -internal F_Hash2StyleRasterCacheNode *f_hash2style_from_tag_size(F_Tag tag, F32 size); +internal F_Hash2StyleRasterCacheNode *f_hash2style_from_tag_size_flags(F_Tag tag, F32 size, F_RunFlags flags); internal F_Run f_push_run_from_string(Arena *arena, F_Tag tag, F32 size, F32 base_align_px, F32 tab_size_px, F_RunFlags flags, String8 string); internal String8List f_wrapped_string_lines_from_font_size_string_max(Arena *arena, F_Tag font, F32 size, F32 base_align_px, F32 tab_size_px, String8 string, F32 max); internal Vec2F32 f_dim_from_tag_size_string(F_Tag tag, F32 size, F32 base_align_px, F32 tab_size_px, String8 string); diff --git a/src/font_provider/dwrite/font_provider_dwrite.c b/src/font_provider/dwrite/font_provider_dwrite.c index a108fe49..79ead99b 100644 --- a/src/font_provider/dwrite/font_provider_dwrite.c +++ b/src/font_provider/dwrite/font_provider_dwrite.c @@ -172,7 +172,15 @@ fp_init(void) } //- rjf: make dwrite factory - error = DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED, &IID_IDWriteFactory, (void **)&fp_dwrite_state->factory); + error = DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED, &IID_IDWriteFactory2, (void **)&fp_dwrite_state->factory); + if(error == S_OK) + { + fp_dwrite_state->dwrite2_is_supported = 1; + } + else + { + error = DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED, &IID_IDWriteFactory, (void **)&fp_dwrite_state->factory); + } //- rjf: register static data font "loader" interface error = IDWriteFactory_RegisterFontFileLoader(fp_dwrite_state->factory, (IDWriteFontFileLoader *)&fp_dwrite_static_data_font_file_loader); @@ -182,28 +190,58 @@ fp_init(void) //- rjf: make sharp rendering params { - FLOAT gamma = 1.f; + FLOAT gamma = IDWriteRenderingParams_GetGamma(fp_dwrite_state->base_rendering_params); FLOAT enhanced_contrast = IDWriteRenderingParams_GetEnhancedContrast(fp_dwrite_state->base_rendering_params); - // FLOAT clear_type_level = fp_dwrite_state->base_rendering_params->GetClearTypeLevel(); - error = IDWriteFactory_CreateCustomRenderingParams(fp_dwrite_state->factory, gamma, - enhanced_contrast, - 2.f, - DWRITE_PIXEL_GEOMETRY_FLAT, - DWRITE_RENDERING_MODE_GDI_NATURAL, - &fp_dwrite_state->rendering_params[FP_RasterMode_Sharp]); + if(fp_dwrite_state->dwrite2_is_supported) + { + error = IDWriteFactory2_CreateCustomRenderingParams2((IDWriteFactory2 *)fp_dwrite_state->factory, + gamma, + enhanced_contrast, + enhanced_contrast, + 1.f, + DWRITE_PIXEL_GEOMETRY_FLAT, + DWRITE_RENDERING_MODE_GDI_NATURAL, + DWRITE_GRID_FIT_MODE_ENABLED, + (IDWriteRenderingParams2 **)&fp_dwrite_state->rendering_params[FP_RasterMode_Sharp]); + } + else + { + error = IDWriteFactory_CreateCustomRenderingParams(fp_dwrite_state->factory, + gamma, + enhanced_contrast, + 1.f, + DWRITE_PIXEL_GEOMETRY_FLAT, + DWRITE_RENDERING_MODE_GDI_NATURAL, + &fp_dwrite_state->rendering_params[FP_RasterMode_Sharp]); + } } //- rjf: make smooth rendering params { FLOAT gamma = 1.f; - FLOAT enhanced_contrast = IDWriteRenderingParams_GetEnhancedContrast(fp_dwrite_state->base_rendering_params); - // FLOAT clear_type_level = fp_dwrite_state->base_rendering_params->GetClearTypeLevel(); - error = IDWriteFactory_CreateCustomRenderingParams(fp_dwrite_state->factory, gamma, - enhanced_contrast, - 2.f, - DWRITE_PIXEL_GEOMETRY_FLAT, - DWRITE_RENDERING_MODE_NATURAL_SYMMETRIC, - &fp_dwrite_state->rendering_params[FP_RasterMode_Smooth]); + FLOAT enhanced_contrast = 0.f; + if(fp_dwrite_state->dwrite2_is_supported) + { + error = IDWriteFactory2_CreateCustomRenderingParams2((IDWriteFactory2 *)fp_dwrite_state->factory, + gamma, + enhanced_contrast, + enhanced_contrast, + 1.f, + DWRITE_PIXEL_GEOMETRY_FLAT, + DWRITE_RENDERING_MODE_CLEARTYPE_NATURAL_SYMMETRIC, + DWRITE_GRID_FIT_MODE_DISABLED, + (IDWriteRenderingParams2 **)&fp_dwrite_state->rendering_params[FP_RasterMode_Smooth]); + } + else + { + error = IDWriteFactory_CreateCustomRenderingParams(fp_dwrite_state->factory, + gamma, + enhanced_contrast, + 0.f, + DWRITE_PIXEL_GEOMETRY_FLAT, + DWRITE_RENDERING_MODE_NATURAL_SYMMETRIC, + &fp_dwrite_state->rendering_params[FP_RasterMode_Smooth]); + } } //- rjf: make dwrite gdi interop @@ -415,7 +453,7 @@ fp_raster(Arena *arena, FP_Handle font_handle, F32 size, FP_RasterMode mode, Str result.atlas_dim = atlas_dim; result.atlas = push_array_no_zero(arena, U8, atlas_dim.x*atlas_dim.y*4); result.advance = floor_f32(advance); - result.height = bounding_box.bottom + 1.f; + result.bounding_box = r2s16p(bounding_box.left, bounding_box.top, bounding_box.right, bounding_box.bottom); // rjf: fill atlas { diff --git a/src/font_provider/dwrite/font_provider_dwrite.h b/src/font_provider/dwrite/font_provider_dwrite.h index c0b599b6..cd4a75f2 100644 --- a/src/font_provider/dwrite/font_provider_dwrite.h +++ b/src/font_provider/dwrite/font_provider_dwrite.h @@ -88,6 +88,12 @@ typedef enum DWRITE_FONT_FACE_TYPE { DWRITE_FONT_FACE_TYPE_TRUETYPE_COLLECTION = 2, } DWRITE_FONT_FACE_TYPE; +typedef enum DWRITE_GRID_FIT_MODE { + DWRITE_GRID_FIT_MODE_DEFAULT = 0, + DWRITE_GRID_FIT_MODE_DISABLED = 1, + DWRITE_GRID_FIT_MODE_ENABLED = 2, +} DWRITE_GRID_FIT_MODE; + //- rjf: interfaces typedef struct IDWriteFactory { struct { void* tbl[]; }* v; } IDWriteFactory; @@ -173,13 +179,15 @@ static inline HRESULT IDWriteFactory_CreateRenderingPa static inline HRESULT IDWriteFactory_CreateCustomRenderingParams (IDWriteFactory* this_, FLOAT gamma, FLOAT enhancedContrast, FLOAT clearTypeLevel, DWRITE_PIXEL_GEOMETRY pixelGeometry, DWRITE_RENDERING_MODE renderingMode, IDWriteRenderingParams** renderingParams) { return ((HRESULT (WINAPI*)(IDWriteFactory*, FLOAT, FLOAT, FLOAT, DWRITE_PIXEL_GEOMETRY, DWRITE_RENDERING_MODE, IDWriteRenderingParams**))this_->v->tbl[12])(this_, gamma, enhancedContrast, clearTypeLevel, pixelGeometry, renderingMode, renderingParams); } static inline HRESULT IDWriteFactory_GetGdiInterop (IDWriteFactory* this_, IDWriteGdiInterop** gdiInterop) { return ((HRESULT (WINAPI*)(IDWriteFactory*, IDWriteGdiInterop**))this_->v->tbl[17])(this_, gdiInterop); } static inline HRESULT IDWriteFactory_CreateCustomFontFileReference (IDWriteFactory* this_, const void* fontFileReferenceKey, UINT32 fontFileReferenceKeySize, IDWriteFontFileLoader* fontFileLoader, IDWriteFontFile** fontFile) { return ((HRESULT (WINAPI*)(IDWriteFactory*, const void*, UINT32, IDWriteFontFileLoader*, IDWriteFontFile**))this_->v->tbl[8])(this_, fontFileReferenceKey, fontFileReferenceKeySize, fontFileLoader, fontFile); } -static inline FLOAT IDWriteRenderingParams_GetEnhancedContrast (IDWriteRenderingParams* this__) { return ((FLOAT (WINAPI*)(IDWriteRenderingParams*))this__->v->tbl[4])(this__); } +static inline HRESULT IDWriteFactory_CreateFontFileReference (IDWriteFactory* this_, const WCHAR* filePath, const FILETIME* lastWriteTime, IDWriteFontFile** fontFile) { return ((HRESULT (WINAPI*)(IDWriteFactory*, const WCHAR*, const FILETIME*, IDWriteFontFile**))this_->v->tbl[7])(this_, filePath, lastWriteTime, fontFile); } +static inline HRESULT IDWriteFactory_CreateFontFace (IDWriteFactory* this_, DWRITE_FONT_FACE_TYPE fontFaceType, UINT32 numberOfFiles, IDWriteFontFile** fontFiles, UINT32 faceIndex, DWRITE_FONT_SIMULATIONS fontFaceSimulationFlags, IDWriteFontFace** fontFace) { return ((HRESULT (WINAPI*)(IDWriteFactory*, DWRITE_FONT_FACE_TYPE, UINT32, IDWriteFontFile**, UINT32, DWRITE_FONT_SIMULATIONS, IDWriteFontFace**))this_->v->tbl[9])(this_, fontFaceType, numberOfFiles, fontFiles, faceIndex, fontFaceSimulationFlags, fontFace); } +static inline HRESULT IDWriteFactory2_CreateCustomRenderingParams2 (IDWriteFactory2* this, FLOAT gamma, FLOAT enhancedContrast, FLOAT grayscaleEnhancedContrast, FLOAT clearTypeLevel, DWRITE_PIXEL_GEOMETRY pixelGeometry, DWRITE_RENDERING_MODE renderingMode, DWRITE_GRID_FIT_MODE gridFitMode, IDWriteRenderingParams2** renderingParams) { return ((HRESULT (WINAPI*)(IDWriteFactory2*, FLOAT, FLOAT, FLOAT, FLOAT, DWRITE_PIXEL_GEOMETRY, DWRITE_RENDERING_MODE, DWRITE_GRID_FIT_MODE, IDWriteRenderingParams2**))this->v->tbl[29])(this, gamma, enhancedContrast, grayscaleEnhancedContrast, clearTypeLevel, pixelGeometry, renderingMode, gridFitMode, renderingParams); } +static inline FLOAT IDWriteRenderingParams_GetEnhancedContrast (IDWriteRenderingParams* this_) { return ((FLOAT (WINAPI*)(IDWriteRenderingParams*))this_->v->tbl[4])(this_); } +static inline FLOAT IDWriteRenderingParams_GetGamma (IDWriteRenderingParams* this_) { return ((FLOAT (WINAPI*)(IDWriteRenderingParams*))this_->v->tbl[3])(this_); } static inline HRESULT IDWriteGdiInterop_CreateBitmapRenderTarget (IDWriteGdiInterop* this_, HDC hdc, UINT32 width, UINT32 height, IDWriteBitmapRenderTarget** renderTarget) { return ((HRESULT (WINAPI*)(IDWriteGdiInterop*, HDC, UINT32, UINT32, IDWriteBitmapRenderTarget**))this_->v->tbl[7])(this_, hdc, width, height, renderTarget); } static inline HRESULT IDWriteBitmapRenderTarget_SetPixelsPerDip (IDWriteBitmapRenderTarget* this_, FLOAT pixelsPerDip) { return ((HRESULT (WINAPI*)(IDWriteBitmapRenderTarget*, FLOAT))this_->v->tbl[6])(this_, pixelsPerDip); } static inline HDC IDWriteBitmapRenderTarget_GetMemoryDC (IDWriteBitmapRenderTarget* this_) { return ((HDC (WINAPI*)(IDWriteBitmapRenderTarget*))this_->v->tbl[4])(this_); } static inline HRESULT IDWriteBitmapRenderTarget_DrawGlyphRun (IDWriteBitmapRenderTarget* this_, FLOAT baselineOriginX, FLOAT baselineOriginY, DWRITE_MEASURING_MODE measuringMode, const DWRITE_GLYPH_RUN* glyphRun, IDWriteRenderingParams* renderingParams, COLORREF textColor, RECT* blackBoxRect) { return ((HRESULT (WINAPI*)(IDWriteBitmapRenderTarget*, FLOAT, FLOAT, DWRITE_MEASURING_MODE, const DWRITE_GLYPH_RUN*, IDWriteRenderingParams*, COLORREF, RECT*))this_->v->tbl[3])(this_, baselineOriginX, baselineOriginY, measuringMode, glyphRun, renderingParams, textColor, blackBoxRect); } -static inline HRESULT IDWriteFactory_CreateFontFileReference (IDWriteFactory* this_, const WCHAR* filePath, const FILETIME* lastWriteTime, IDWriteFontFile** fontFile) { return ((HRESULT (WINAPI*)(IDWriteFactory*, const WCHAR*, const FILETIME*, IDWriteFontFile**))this_->v->tbl[7])(this_, filePath, lastWriteTime, fontFile); } -static inline HRESULT IDWriteFactory_CreateFontFace (IDWriteFactory* this_, DWRITE_FONT_FACE_TYPE fontFaceType, UINT32 numberOfFiles, IDWriteFontFile** fontFiles, UINT32 faceIndex, DWRITE_FONT_SIMULATIONS fontFaceSimulationFlags, IDWriteFontFace** fontFace) { return ((HRESULT (WINAPI*)(IDWriteFactory*, DWRITE_FONT_FACE_TYPE, UINT32, IDWriteFontFile**, UINT32, DWRITE_FONT_SIMULATIONS, IDWriteFontFace**))this_->v->tbl[9])(this_, fontFaceType, numberOfFiles, fontFiles, faceIndex, fontFaceSimulationFlags, fontFace); } static inline UINT32 IDWriteFontFace_Release (IDWriteFontFace* this_) { return ((UINT32 (WINAPI*)(IDWriteFontFace*))this_->v->tbl[2])(this_); } static inline void IDWriteFontFace_GetMetrics (IDWriteFontFace* this_, DWRITE_FONT_METRICS* fontFaceMetrics) { ((void (WINAPI*)(IDWriteFontFace*, DWRITE_FONT_METRICS*))this_->v->tbl[8])(this_, fontFaceMetrics); } static inline UINT32 IDWriteFontFile_Release (IDWriteFontFile* this_) { return ((UINT32 (WINAPI*)(IDWriteFontFile*))this_->v->tbl[2])(this_); } @@ -244,6 +252,7 @@ typedef struct FP_DWrite_State FP_DWrite_State; struct FP_DWrite_State { Arena *arena; + B32 dwrite2_is_supported; IDWriteFactory *factory; IDWriteRenderingParams *base_rendering_params; IDWriteRenderingParams *rendering_params[FP_RasterMode_COUNT]; diff --git a/src/font_provider/font_provider.h b/src/font_provider/font_provider.h index 9abf14c1..5377b453 100644 --- a/src/font_provider/font_provider.h +++ b/src/font_provider/font_provider.h @@ -39,7 +39,7 @@ struct FP_RasterResult Vec2S16 atlas_dim; void *atlas; F32 advance; - S16 height; + Rng2S16 bounding_box; }; //////////////////////////////// diff --git a/src/ui/ui_basic_widgets.c b/src/ui/ui_basic_widgets.c index 4d9fec5d..e2b72ba6 100644 --- a/src/ui/ui_basic_widgets.c +++ b/src/ui/ui_basic_widgets.c @@ -31,7 +31,7 @@ ui_divider(UI_Size size) internal UI_Signal ui_label(String8 string) { - UI_Box *box = ui_build_box_from_string(UI_BoxFlag_DrawText, str8_lit("")); + UI_Box *box = ui_build_box_from_string(UI_BoxFlag_DrawText, str8_zero()); ui_box_equip_display_string(box, string); UI_Signal interact = ui_signal_from_box(box); return interact; diff --git a/src/ui/ui_core.c b/src/ui/ui_core.c index c65f1f2b..d4a90085 100644 --- a/src/ui/ui_core.c +++ b/src/ui/ui_core.c @@ -1870,6 +1870,7 @@ ui_begin_ctx_menu(UI_Key key) ui_state->ctx_menu_root->flags |= UI_BoxFlag_RoundChildrenByParent; ui_state->ctx_menu_root->flags |= UI_BoxFlag_DrawBackgroundBlur; ui_state->ctx_menu_root->flags |= UI_BoxFlag_DrawBackground; + ui_state->ctx_menu_root->flags |= UI_BoxFlag_DisableFocusOverlay; ui_state->ctx_menu_root->flags |= UI_BoxFlag_DrawBorder; ui_state->ctx_menu_root->flags |= UI_BoxFlag_Clip; ui_state->ctx_menu_root->flags |= UI_BoxFlag_Clickable; @@ -2376,7 +2377,7 @@ ui_box_text_position(UI_Box *box) F_Tag font = box->font; F32 font_size = box->font_size; F_Metrics font_metrics = f_metrics_from_tag_size(font, font_size); - result.y = ceil_f32((box->rect.p0.y + box->rect.p1.y)/2.f + (font_metrics.capital_height/2) - font_metrics.line_gap/2); + result.y = floor_f32((box->rect.p0.y + box->rect.p1.y)/2.f + (font_metrics.capital_height/2) - font_metrics.line_gap/2); switch(box->text_align) { default: @@ -2386,14 +2387,14 @@ ui_box_text_position(UI_Box *box) }break; case UI_TextAlign_Center: { - Vec2F32 advance = box->display_string_runs.dim; - result.x = floor_f32((box->rect.p0.x + box->rect.p1.x)/2 - advance.x/2 - 1.f); + Vec2F32 text_dim = box->display_string_runs.dim; + result.x = round_f32((box->rect.p0.x + box->rect.p1.x)/2 - text_dim.x/2) - 1.f; result.x = ClampBot(result.x, box->rect.x0); }break; case UI_TextAlign_Right: { - Vec2F32 advance = box->display_string_runs.dim; - result.x = (box->rect.p1.x) - 1.f - advance.x; + Vec2F32 text_dim = box->display_string_runs.dim; + result.x = round_f32((box->rect.p1.x) - text_dim.x); result.x = ClampBot(result.x, box->rect.x0); }break; } diff --git a/src/ui/ui_core.h b/src/ui/ui_core.h index 2df508bd..cdf4f246 100644 --- a/src/ui/ui_core.h +++ b/src/ui/ui_core.h @@ -323,21 +323,22 @@ typedef U64 UI_BoxFlags; # define UI_BoxFlag_AnimatePosY (UI_BoxFlags)(1ull<<44) # define UI_BoxFlag_DisableTextTrunc (UI_BoxFlags)(1ull<<45) # define UI_BoxFlag_DisableIDString (UI_BoxFlags)(1ull<<46) -# define UI_BoxFlag_DisableFocusViz (UI_BoxFlags)(1ull<<47) -# define UI_BoxFlag_RequireFocusBackground (UI_BoxFlags)(1ull<<48) +# define UI_BoxFlag_DisableFocusBorder (UI_BoxFlags)(1ull<<47) +# define UI_BoxFlag_DisableFocusOverlay (UI_BoxFlags)(1ull<<48) # define UI_BoxFlag_HasDisplayString (UI_BoxFlags)(1ull<<49) # define UI_BoxFlag_HasFuzzyMatchRanges (UI_BoxFlags)(1ull<<50) # define UI_BoxFlag_RoundChildrenByParent (UI_BoxFlags)(1ull<<51) //- rjf: bundles -# define UI_BoxFlag_Clickable (UI_BoxFlag_MouseClickable|UI_BoxFlag_KeyboardClickable) -# define UI_BoxFlag_DefaultFocusNav (UI_BoxFlag_DefaultFocusNavX|UI_BoxFlag_DefaultFocusNavY|UI_BoxFlag_DefaultFocusEdit) -# define UI_BoxFlag_Floating (UI_BoxFlag_FloatingX|UI_BoxFlag_FloatingY) -# define UI_BoxFlag_FixedSize (UI_BoxFlag_FixedWidth|UI_BoxFlag_FixedHeight) -# define UI_BoxFlag_AllowOverflow (UI_BoxFlag_AllowOverflowX|UI_BoxFlag_AllowOverflowY) -# define UI_BoxFlag_AnimatePos (UI_BoxFlag_AnimatePosX|UI_BoxFlag_AnimatePosY) -# define UI_BoxFlag_ViewScroll (UI_BoxFlag_ViewScrollX|UI_BoxFlag_ViewScrollY) -# define UI_BoxFlag_ViewClamp (UI_BoxFlag_ViewClampX|UI_BoxFlag_ViewClampY) +# define UI_BoxFlag_Clickable (UI_BoxFlag_MouseClickable|UI_BoxFlag_KeyboardClickable) +# define UI_BoxFlag_DefaultFocusNav (UI_BoxFlag_DefaultFocusNavX|UI_BoxFlag_DefaultFocusNavY|UI_BoxFlag_DefaultFocusEdit) +# define UI_BoxFlag_Floating (UI_BoxFlag_FloatingX|UI_BoxFlag_FloatingY) +# define UI_BoxFlag_FixedSize (UI_BoxFlag_FixedWidth|UI_BoxFlag_FixedHeight) +# define UI_BoxFlag_AllowOverflow (UI_BoxFlag_AllowOverflowX|UI_BoxFlag_AllowOverflowY) +# define UI_BoxFlag_AnimatePos (UI_BoxFlag_AnimatePosX|UI_BoxFlag_AnimatePosY) +# define UI_BoxFlag_ViewScroll (UI_BoxFlag_ViewScrollX|UI_BoxFlag_ViewScrollY) +# define UI_BoxFlag_ViewClamp (UI_BoxFlag_ViewClampX|UI_BoxFlag_ViewClampY) +# define UI_BoxFlag_DisableFocusEffects (UI_BoxFlag_DisableFocusBorder|UI_BoxFlag_DisableFocusOverlay) //} typedef struct UI_Box UI_Box;