diff --git a/4ed_font_provider_freetype.cpp b/4ed_font_provider_freetype.cpp index 36aa4b63..1800935f 100644 --- a/4ed_font_provider_freetype.cpp +++ b/4ed_font_provider_freetype.cpp @@ -201,7 +201,7 @@ ft__font_make_face(Arena *arena, Face_Description *description, f32 scale_factor met->ascent = f32_ceil32(ft_face->size->metrics.ascender/64.f); met->descent = f32_floor32(ft_face->size->metrics.descender/64.f); met->text_height = f32_ceil32(ft_face->size->metrics.height/64.f); - met->line_skip = met->text_height - met->ascent + met->descent; + met->line_skip = met->text_height - (met->ascent - met->descent); met->line_skip = clamp_bot(1.f, met->line_skip); met->line_height = met->text_height + met->line_skip; diff --git a/custom/4coder_default_framework.cpp b/custom/4coder_default_framework.cpp index 23674a7f..ebcb6872 100644 --- a/custom/4coder_default_framework.cpp +++ b/custom/4coder_default_framework.cpp @@ -96,7 +96,7 @@ open_footer_panel(Application_Links *app, View_ID view){ Buffer_ID buffer = view_get_buffer(app, special_view, Access_Always); Face_ID face_id = get_face_id(app, buffer); Face_Metrics metrics = get_face_metrics(app, face_id); - view_set_split_pixel_size(app, special_view, (i32)(metrics.line_height*20.f)); + view_set_split_pixel_size(app, special_view, (i32)(metrics.line_height*14.f)); view_set_passive(app, special_view, true); return(special_view); } diff --git a/custom/4coder_draw.cpp b/custom/4coder_draw.cpp index 1c675f44..f37de6a5 100644 --- a/custom/4coder_draw.cpp +++ b/custom/4coder_draw.cpp @@ -740,5 +740,26 @@ draw_drop_down(Application_Links *app, Face_ID face, Fancy_Block *block, return(box); } +function b32 +draw_button(Application_Links *app, Rect_f32 rect, Vec2_f32 mouse_p, Face_ID face, String_Const_u8 text){ + b32 hovered = false; + if (rect_contains_point(rect, mouse_p)){ + hovered = true; + } + + FColor margin_color = get_margin_color(hovered?UIHighlight_Active:UIHighlight_None); + draw_rectangle(app, rect, 3.f, margin_color); + rect = rect_inner(rect, 3.f); + draw_rectangle(app, rect, 3.f, fcolor_id(Stag_Back)); + + Scratch_Block scratch(app); + Fancy_String *fancy = push_fancy_string(scratch, 0, face, fcolor_id(Stag_Default), text); + Vec2_f32 dim = get_fancy_string_dim(app, 0, fancy); + Vec2_f32 p = (rect.p0 + rect.p1 - dim)*0.5f; + draw_fancy_string(app, fancy, p); + + return(hovered); +} + // BOTTOM diff --git a/custom/4coder_fancy.cpp b/custom/4coder_fancy.cpp index 1b43efc6..ce368bb4 100644 --- a/custom/4coder_fancy.cpp +++ b/custom/4coder_fancy.cpp @@ -548,8 +548,7 @@ get_fancy_string_width__inner(Application_Links *app, Face_ID face, } function f32 -get_fancy_string_height__inner(Application_Links *app, Face_ID face, - Fancy_String *string){ +get_fancy_string_height__inner(Application_Links *app, Face_ID face, Fancy_String *string){ f32 result = 0.f; if (face != 0){ Face_Metrics metrics = get_face_metrics(app, face); @@ -566,11 +565,44 @@ get_fancy_string_height__inner(Application_Links *app, Face_ID face, return(result); } -function Vec2_f32 -draw_fancy_string__inner(Application_Links *app, Face_ID face, FColor fore, - Fancy_String *string, Vec2_f32 p, u32 flags, Vec2_f32 delta){ +function f32 +get_fancy_string_text_height__inner(Application_Links *app, Face_ID face, Fancy_String *string){ + f32 result = 0.f; + if (face != 0){ + Face_Metrics metrics = get_face_metrics(app, face); + result = metrics.text_height; + } for (;string != 0; string = string->next){ + if (string->face != 0){ + Face_ID use_face = string->face; + Face_Metrics metrics = get_face_metrics(app, use_face); + result = max(result, metrics.text_height); + } + } + return(result); +} + +function Vec2_f32 +draw_fancy_string__inner(Application_Links *app, Face_ID face, FColor fore, Fancy_String *first_string, Vec2_f32 p, u32 flags, Vec2_f32 delta){ + f32 base_line = 0.f; + for (Fancy_String *string = first_string; + string != 0; + string = string->next){ + Face_ID use_face = face; + if (string->face != 0){ + use_face = string->face; + } + if (use_face != 0){ + Face_Metrics metrics = get_face_metrics(app, use_face); + base_line = max(base_line, metrics.ascent); + } + } + + Vec2_f32 down_delta = V2f32(-delta.y, delta.x); + for (Fancy_String *string = first_string; + string != 0; + string = string->next){ Face_ID use_face = face; if (string->face != 0){ use_face = string->face; @@ -581,19 +613,25 @@ draw_fancy_string__inner(Application_Links *app, Face_ID face, FColor fore, } if (use_face != 0){ Face_Metrics metrics = get_face_metrics(app, use_face); + f32 down_shift = (base_line - metrics.ascent); + down_shift = clamp_bot(0.f, down_shift); + Vec2_f32 p_shift = down_shift*down_delta; + Vec2_f32 p_shifted = p + p_shift; + if (fcolor_is_valid(use_fore)){ Vec2_f32 margin_delta = delta*metrics.normal_advance; - p += margin_delta*string->pre_margin; - p = draw_string_oriented(app, use_face, use_fore, - string->value, p, flags, delta); - p += margin_delta*string->post_margin; + p_shifted += margin_delta*string->pre_margin; + p_shifted = draw_string_oriented(app, use_face, use_fore, string->value, p_shifted, flags, delta); + p_shifted += margin_delta*string->post_margin; } else{ f32 adv = (string->pre_margin + string->post_margin)*metrics.normal_advance; adv += get_string_advance(app, use_face, string->value); - p += adv*delta; + p_shifted += adv*delta; } + + p = p_shifted - p_shift; } } return(p); @@ -619,13 +657,32 @@ get_fancy_string_height(Application_Links *app, Face_ID face, return(result); } +function f32 +get_fancy_string_text_height(Application_Links *app, Face_ID face, + Fancy_String *string){ + Fancy_String *next = string->next; + string->next = 0; + f32 result = get_fancy_string_text_height__inner(app, face, string); + string->next = next; + return(result); +} + +function Vec2_f32 +get_fancy_string_dim(Application_Links *app, Face_ID face, Fancy_String *string){ + Fancy_String *next = string->next; + string->next = 0; + Vec2_f32 result = V2f32(get_fancy_string_width__inner(app, face, string), + get_fancy_string_height__inner(app, face, string)); + string->next = next; + return(result); +} + function Vec2_f32 draw_fancy_string(Application_Links *app, Face_ID face, FColor fore, Fancy_String *string, Vec2_f32 p, u32 flags, Vec2_f32 delta){ Fancy_String *next = string->next; string->next = 0; - Vec2_f32 result = draw_fancy_string__inner(app, face, fore, - string, p, flags, delta); + Vec2_f32 result = draw_fancy_string__inner(app, face, fore, string, p, flags, delta); string->next = next; return(result); } @@ -646,6 +703,14 @@ get_fancy_line_height(Application_Links *app, Face_ID face, Fancy_Line *line){ return(get_fancy_string_height__inner(app, face, line->first)); } +function f32 +get_fancy_line_text_height(Application_Links *app, Face_ID face, Fancy_Line *line){ + if (line->face != 0){ + face = line->face; + } + return(get_fancy_string_text_height__inner(app, face, line->first)); +} + function Vec2_f32 get_fancy_line_dim(Application_Links *app, Face_ID face, Fancy_Line *line){ if (line->face != 0){ @@ -663,8 +728,7 @@ draw_fancy_line(Application_Links *app, Face_ID face, FColor fore, if (fcolor_is_valid(line->fore)){ fore = line->fore; } - return(draw_fancy_string__inner(app, face, fore, - line->first, p, flags, delta)); + return(draw_fancy_string__inner(app, face, fore, line->first, p, flags, delta)); } function f32 @@ -715,6 +779,11 @@ draw_fancy_string(Application_Links *app, Face_ID face, FColor fore, return(draw_fancy_string(app, face, fore, string, p, 0, V2f32(1.f, 0.f))); } +function Vec2_f32 +draw_fancy_string(Application_Links *app, Fancy_String *string, Vec2_f32 p){ + return(draw_fancy_string(app, 0, fcolor_zero(), string, p, 0, V2f32(1.f, 0.f))); +} + function Vec2_f32 draw_fancy_line(Application_Links *app, Face_ID face, FColor fore, Fancy_Line *line, Vec2_f32 p){ diff --git a/custom/4coder_tutorial.cpp b/custom/4coder_tutorial.cpp index 39e6acfd..d4cb627e 100644 --- a/custom/4coder_tutorial.cpp +++ b/custom/4coder_tutorial.cpp @@ -4,13 +4,23 @@ // TOP +typedef i32 Tutorial_Action; +enum{ + TutorialAction_None, + TutorialAction_Prev, + TutorialAction_Next, +}; + global b32 in_tutorial = false; global View_ID tutorial_view = 0; global Face_ID tutorial_face = 0; global b32 tutorial_is_active = false; +global Tutorial_Action tutorial_hover_action = TutorialAction_None; +global Tutorial_Action tutorial_depressed_action = TutorialAction_None; -function void -kill_tutorial(Application_Links *app){ +CUSTOM_COMMAND_SIG(kill_tutorial) +CUSTOM_DOC("If in the tutorial state - kill it.") +{ if (!in_tutorial){ return; } @@ -49,6 +59,11 @@ tutorial_deactivate(Application_Links *app){ tutorial_is_active = false; } +function void +tutorial_action(Application_Links *app, Tutorial_Action action){ + +} + function void tutorial_default_4coder_render(Application_Links *app, Frame_Info frame_info, View_ID view_id){ View_ID active_view = get_active_view(app, Access_Always); @@ -58,11 +73,15 @@ tutorial_default_4coder_render(Application_Links *app, Frame_Info frame_info, Vi Rect_f32 region = draw_background_and_margin(app, view_id, margin_color, margin_color); Rect_f32 prev_clip = draw_set_clip(app, region); + f32 panel_y0 = region.y0 - 3.f; + region = rect_inner(region, 3.f); draw_rectangle(app, region, 20.f, fcolor_id(Stag_Back)); + region = rect_inner(region, 10.f); + + Face_ID face = get_face_id(app, 0); if (tutorial_face == 0){ - Face_ID face = get_face_id(app, 0); Face_Description face_description = get_face_description(app, face); face_description.parameters.pt_size *= 2; tutorial_face = try_create_new_face(app, &face_description); @@ -71,6 +90,11 @@ tutorial_default_4coder_render(Application_Links *app, Frame_Info frame_info, Vi } } + Face_Metrics metrics = get_face_metrics(app, face); + Face_Metrics tut_metrics = get_face_metrics(app, tutorial_face); + + Vec2_f32 title_p = V2f32(region.x0, panel_y0 + (metrics.line_height*2.f) - tut_metrics.line_height*0.5f); + if (is_active_view){ if (!tutorial_is_active){ view_enqueue_command_function(app, view_id, tutorial_activate); @@ -84,12 +108,126 @@ tutorial_default_4coder_render(Application_Links *app, Frame_Info frame_info, Vi Scratch_Block scratch(app); - Fancy_Line line = {}; - push_fancy_string(scratch, &line, tutorial_face, fcolor_id(Stag_Default), string_u8_litexpr("Tutorial")); + String_Const_u8 title = string_u8_litexpr("Handmade Seattle Demo"); - Vec2_f32 line_dim = get_fancy_line_dim(app, 0, &line); - Vec2_f32 p = (region.p0 + region.p1 - line_dim)*0.5f; - draw_fancy_line(app, 0, fcolor_zero(), &line, p); + Fancy_Block long_details = {}; + push_fancy_line(scratch, &long_details, tutorial_face, fcolor_id(Stag_Pop1), title); + + // + Fancy_Line *line = push_fancy_line(scratch, &long_details, face, fcolor_id(Stag_Default)); +#define M "If there are any features you'd like to know about or try out, " + push_fancy_string(scratch, line, string_u8_litexpr(M)); + #undef M + push_fancy_string(scratch, line, fcolor_id(Stag_Keyword), string_u8_litexpr("ask!")); + + + // + push_fancy_line(scratch, &long_details, face, fcolor_id(Stag_Pop1), string_u8_litexpr("")); + + // + push_fancy_line(scratch, &long_details, face, fcolor_id(Stag_Keyword), string_u8_litexpr("Let's start with a few navigation commands:")); + + // + line = push_fancy_line(scratch, &long_details, face, fcolor_id(Stag_Default)); + push_fancy_stringf(scratch, line, fcolor_id(Stag_Pop2), + "%40s ", ""); + push_fancy_stringf(scratch, line, "change active panel"); + + // + line = push_fancy_line(scratch, &long_details, face, fcolor_id(Stag_Default)); + push_fancy_stringf(scratch, line, fcolor_id(Stag_Pop2), + "%40s ", "<*AnyArrow*>"); + push_fancy_stringf(scratch, line, "move cursor one character or line"); + + // + line = push_fancy_line(scratch, &long_details, face, fcolor_id(Stag_Default)); + push_fancy_stringf(scratch, line, fcolor_id(Stag_Pop2), + "%40s ", ""); + push_fancy_stringf(scratch, line, "move cursor by 'chunks'"); + + // + line = push_fancy_line(scratch, &long_details, face, fcolor_id(Stag_Default)); + push_fancy_stringf(scratch, line, fcolor_id(Stag_Pop2), + "%40s ", ", "); + push_fancy_stringf(scratch, line, "move cursor to the first/last character of the line"); + + // + line = push_fancy_line(scratch, &long_details, face, fcolor_id(Stag_Default)); + push_fancy_stringf(scratch, line, fcolor_id(Stag_Pop2), + "%40s ", ", "); + push_fancy_stringf(scratch, line, "move cursor by full pages up/down"); + + // + push_fancy_line(scratch, &long_details, face, fcolor_id(Stag_Keyword), string_u8_litexpr("Available in code files:")); + + // + line = push_fancy_line(scratch, &long_details, face, fcolor_id(Stag_Default)); + push_fancy_stringf(scratch, line, fcolor_id(Stag_Pop2), + "%40s ", ""); + push_fancy_stringf(scratch, line, "move cursor and mark to surrounding scope"); + + // + line = push_fancy_line(scratch, &long_details, face, fcolor_id(Stag_Default)); + push_fancy_stringf(scratch, line, fcolor_id(Stag_Pop2), + "%40s ", ""); + push_fancy_stringf(scratch, line, "move cursor and mark to previous scope"); + + // + line = push_fancy_line(scratch, &long_details, face, fcolor_id(Stag_Default)); + push_fancy_stringf(scratch, line, fcolor_id(Stag_Pop2), + "%40s ", ""); + push_fancy_stringf(scratch, line, "move cursor and mark to next scope"); + + // + line = push_fancy_line(scratch, &long_details, face, fcolor_id(Stag_Default)); + push_fancy_stringf(scratch, line, fcolor_id(Stag_Pop2), + "%40s ", ""); + push_fancy_stringf(scratch, line, "move cursor and mark to previous top-level scope"); + + // + line = push_fancy_line(scratch, &long_details, face, fcolor_id(Stag_Default)); + push_fancy_stringf(scratch, line, fcolor_id(Stag_Pop2), + "%40s ", ""); + push_fancy_stringf(scratch, line, "move cursor and mark to next top-level scope"); + + + //// + Fancy_Line short_details = {}; + push_fancy_string(scratch, &short_details, tutorial_face, fcolor_id(Stag_Pop1), title); + push_fancy_string(scratch, &short_details, face, fcolor_id(Stag_Default), 8.f, 8.f, string_u8_litexpr("Welcome to Handmade Seattle and to this 4coder demo!")); + push_fancy_string(scratch, &short_details, face, fcolor_id(Stag_Pop2), string_u8_litexpr("Click here to see more.")); + + tutorial_hover_action = TutorialAction_None; + + if (tutorial_is_active){ + draw_fancy_block(app, 0, fcolor_zero(), &long_details, title_p); + + // NOTE(allen): buttons + Rect_f32_Pair pair = rect_split_top_bottom_neg(region, metrics.line_height*2.f); + Rect_f32 footer = pair.max; + footer.x0 += 10.f; + footer.y0 -= 10.f; + footer.y1 -= 10.f; + + f32 b_width = metrics.normal_advance*10.f; + Rect_f32_Pair b1_pair = rect_split_left_right(footer, b_width); + footer = b1_pair.max; + footer.x0 += 10.f; + Rect_f32_Pair b2_pair = rect_split_left_right(footer, b_width); + + Mouse_State mouse = get_mouse_state(app); + Vec2_f32 m_p = V2f32(mouse.p); + + if (draw_button(app, b1_pair.min, m_p, face, string_u8_litexpr("prev"))){ + tutorial_hover_action = TutorialAction_Prev; + } + if (draw_button(app, b2_pair.min, m_p, face, string_u8_litexpr("next"))){ + tutorial_hover_action = TutorialAction_Next; + } + } + else{ + draw_fancy_line(app, 0, fcolor_zero(), &short_details, title_p); + } draw_set_clip(app, prev_clip); } @@ -114,6 +252,22 @@ tutorial_default_4coder_run(Application_Links *app) b32 handled = true; switch (in.event.kind){ + case InputEventKind_MouseButton: + { + if (in.event.mouse.code == MouseCode_Left){ + tutorial_depressed_action = tutorial_hover_action; + } + }break; + + case InputEventKind_MouseButtonRelease: + { + if (in.event.mouse.code == MouseCode_Left){ + if (tutorial_depressed_action == tutorial_hover_action){ + tutorial_action(app, tutorial_depressed_action); + } + } + }break; + case InputEventKind_Core: { switch (in.event.core.code){ @@ -159,7 +313,7 @@ tutorial_default_4coder_run(Application_Links *app) in_tutorial = false; } -CUSTOM_COMMAND_SIG(tutorial_default_4coder) +CUSTOM_COMMAND_SIG(default_4coder_tutorial) CUSTOM_DOC("Tutorial for built in 4coder bindings and features.") { kill_tutorial(app); diff --git a/custom/generated/command_metadata.h b/custom/generated/command_metadata.h index 9b9ce585..e71946d3 100644 --- a/custom/generated/command_metadata.h +++ b/custom/generated/command_metadata.h @@ -2,7 +2,7 @@ #define command_id(c) (fcoder_metacmd_ID_##c) #define command_metadata(c) (&fcoder_metacmd_table[command_id(c)]) #define command_metadata_by_id(id) (&fcoder_metacmd_table[id]) -#define command_one_past_last_id 215 +#define command_one_past_last_id 216 #if defined(CUSTOM_COMMAND_SIG) #define PROC_LINKS(x,y) x #else @@ -221,7 +221,8 @@ CUSTOM_COMMAND_SIG(miblo_decrement_time_stamp); CUSTOM_COMMAND_SIG(miblo_increment_time_stamp_minute); CUSTOM_COMMAND_SIG(miblo_decrement_time_stamp_minute); CUSTOM_COMMAND_SIG(profile_inspect); -CUSTOM_COMMAND_SIG(tutorial_default_4coder); +CUSTOM_COMMAND_SIG(kill_tutorial); +CUSTOM_COMMAND_SIG(default_4coder_tutorial); CUSTOM_COMMAND_SIG(default_startup); CUSTOM_COMMAND_SIG(default_try_exit); #endif @@ -236,7 +237,7 @@ char *source_name; i32 source_name_len; i32 line_number; }; -static Command_Metadata fcoder_metacmd_table[215] = { +static Command_Metadata fcoder_metacmd_table[216] = { { PROC_LINKS(default_view_input_handler, 0), false, "default_view_input_handler", 26, "Input consumption loop for default view behavior", 48, "w:\\4ed\\code\\custom\\4coder_default_hooks.cpp", 43, 56 }, { PROC_LINKS(profile_enable, 0), false, "profile_enable", 14, "Allow 4coder's self profiler to gather new profiling information.", 65, "w:\\4ed\\code\\custom\\4coder_profile.cpp", 37, 207 }, { PROC_LINKS(profile_disable, 0), false, "profile_disable", 15, "Prevent 4coder's self profiler from gathering new profiling information.", 72, "w:\\4ed\\code\\custom\\4coder_profile.cpp", 37, 214 }, @@ -449,7 +450,8 @@ static Command_Metadata fcoder_metacmd_table[215] = { { PROC_LINKS(miblo_increment_time_stamp_minute, 0), false, "miblo_increment_time_stamp_minute", 33, "Increment a time stamp under the cursor by one minute. (format [m]m:ss or h:mm:ss", 81, "w:\\4ed\\code\\custom\\4coder_miblo_numbers.cpp", 43, 243 }, { PROC_LINKS(miblo_decrement_time_stamp_minute, 0), false, "miblo_decrement_time_stamp_minute", 33, "Decrement a time stamp under the cursor by one minute. (format [m]m:ss or h:mm:ss", 81, "w:\\4ed\\code\\custom\\4coder_miblo_numbers.cpp", 43, 249 }, { PROC_LINKS(profile_inspect, 0), true, "profile_inspect", 15, "Inspect all currently collected profiling information in 4coder's self profiler.", 80, "w:\\4ed\\code\\custom\\4coder_profile_inspect.cpp", 45, 779 }, -{ PROC_LINKS(tutorial_default_4coder, 0), false, "tutorial_default_4coder", 23, "Tutorial for built in 4coder bindings and features.", 51, "w:\\4ed\\code\\custom\\4coder_tutorial.cpp", 38, 162 }, +{ PROC_LINKS(kill_tutorial, 0), false, "kill_tutorial", 13, "If in the tutorial state - kill it.", 35, "w:\\4ed\\code\\custom\\4coder_tutorial.cpp", 38, 21 }, +{ PROC_LINKS(default_4coder_tutorial, 0), false, "default_4coder_tutorial", 23, "Tutorial for built in 4coder bindings and features.", 51, "w:\\4ed\\code\\custom\\4coder_tutorial.cpp", 38, 316 }, { PROC_LINKS(default_startup, 0), false, "default_startup", 15, "Default command for responding to a startup event", 49, "w:\\4ed\\code\\custom\\4coder_default_hooks.cpp", 43, 7 }, { PROC_LINKS(default_try_exit, 0), false, "default_try_exit", 16, "Default command for responding to a try-exit event", 50, "w:\\4ed\\code\\custom\\4coder_default_hooks.cpp", 43, 22 }, }; @@ -665,7 +667,8 @@ static i32 fcoder_metacmd_ID_miblo_decrement_time_stamp = 208; static i32 fcoder_metacmd_ID_miblo_increment_time_stamp_minute = 209; static i32 fcoder_metacmd_ID_miblo_decrement_time_stamp_minute = 210; static i32 fcoder_metacmd_ID_profile_inspect = 211; -static i32 fcoder_metacmd_ID_tutorial_default_4coder = 212; -static i32 fcoder_metacmd_ID_default_startup = 213; -static i32 fcoder_metacmd_ID_default_try_exit = 214; +static i32 fcoder_metacmd_ID_kill_tutorial = 212; +static i32 fcoder_metacmd_ID_default_4coder_tutorial = 213; +static i32 fcoder_metacmd_ID_default_startup = 214; +static i32 fcoder_metacmd_ID_default_try_exit = 215; #endif