diff --git a/custom/4coder_default_include.cpp b/custom/4coder_default_include.cpp index acb77ab6..a2158c74 100644 --- a/custom/4coder_default_include.cpp +++ b/custom/4coder_default_include.cpp @@ -51,6 +51,7 @@ #include "4coder_combined_write_commands.h" #include "4coder_log_parser.h" #include "4coder_profile_inspect.h" +#include "4coder_tutorial.h" //////////////////////////////// diff --git a/custom/4coder_fancy.cpp b/custom/4coder_fancy.cpp index ce368bb4..b1750d11 100644 --- a/custom/4coder_fancy.cpp +++ b/custom/4coder_fancy.cpp @@ -689,46 +689,66 @@ draw_fancy_string(Application_Links *app, Face_ID face, FColor fore, function f32 get_fancy_line_width(Application_Links *app, Face_ID face, Fancy_Line *line){ + f32 result = 0.f; + if (line != 0){ if (line->face != 0){ face = line->face; } - return(get_fancy_string_width__inner(app, face, line->first)); + result = get_fancy_string_width__inner(app, face, line->first); + } + return(result); } function f32 get_fancy_line_height(Application_Links *app, Face_ID face, Fancy_Line *line){ - if (line->face != 0){ - face = line->face; + f32 result = 0.f; + if (line != 0){ + if (line->face != 0){ + face = line->face; + } + result = get_fancy_string_height__inner(app, face, line->first); } - return(get_fancy_string_height__inner(app, face, line->first)); + return(result); } function f32 get_fancy_line_text_height(Application_Links *app, Face_ID face, Fancy_Line *line){ - if (line->face != 0){ - face = line->face; + f32 result = 0.f; + if (line != 0){ + if (line->face != 0){ + face = line->face; + } + result = get_fancy_string_text_height__inner(app, face, line->first); } - return(get_fancy_string_text_height__inner(app, face, line->first)); + return(result); } function Vec2_f32 get_fancy_line_dim(Application_Links *app, Face_ID face, Fancy_Line *line){ - if (line->face != 0){ - face = line->face; + Vec2_f32 result = {}; + if (line != 0){ + if (line->face != 0){ + face = line->face; + } + result = V2f32(get_fancy_string_width__inner(app, face, line->first), get_fancy_string_height__inner(app, face, line->first)); } - return(V2f32(get_fancy_string_width__inner(app, face, line->first), get_fancy_string_height__inner(app, face, line->first))); + return(result); } function Vec2_f32 draw_fancy_line(Application_Links *app, Face_ID face, FColor fore, Fancy_Line *line, Vec2_f32 p, u32 flags, Vec2_f32 delta){ + Vec2_f32 result = {}; + if (line != 0){ if (line->face != 0){ face = line->face; } if (fcolor_is_valid(line->fore)){ fore = line->fore; } - return(draw_fancy_string__inner(app, face, fore, line->first, p, flags, delta)); + result = draw_fancy_string__inner(app, face, fore, line->first, p, flags, delta); + } + return(result); } function f32 diff --git a/custom/4coder_tutorial.cpp b/custom/4coder_tutorial.cpp index d4cb627e..a0b83f2c 100644 --- a/custom/4coder_tutorial.cpp +++ b/custom/4coder_tutorial.cpp @@ -4,47 +4,35 @@ // 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; +global Tutorial_State tutorial = {}; CUSTOM_COMMAND_SIG(kill_tutorial) -CUSTOM_DOC("If in the tutorial state - kill it.") +CUSTOM_DOC("If there is an active tutorial, kill it.") { - if (!in_tutorial){ + if (!tutorial.in_tutorial){ return; } - in_tutorial = false; - view_close(app, tutorial_view); + tutorial.in_tutorial = false; + view_close(app, tutorial.view); } function void tutorial_activate(Application_Links *app){ - if (!in_tutorial){ + if (!tutorial.in_tutorial){ return; } - Panel_ID panel = view_get_panel(app, tutorial_view); + Panel_ID panel = view_get_panel(app, tutorial.view); Panel_ID parent = panel_get_parent(app, panel); panel_set_split(app, parent, PanelSplitKind_Ratio_Min, 0.5f); - tutorial_is_active = true; + tutorial.is_active = true; } function void tutorial_deactivate(Application_Links *app){ - if (!in_tutorial){ + if (!tutorial.in_tutorial){ return; } @@ -52,20 +40,73 @@ tutorial_deactivate(Application_Links *app){ Face_Metrics metrics = get_face_metrics(app, face); f32 line_height = metrics.line_height; - Panel_ID panel = view_get_panel(app, tutorial_view); + Panel_ID panel = view_get_panel(app, tutorial.view); Panel_ID parent = panel_get_parent(app, panel); panel_set_split(app, parent, PanelSplitKind_FixedPixels_Min, line_height*4.f); - tutorial_is_active = false; + tutorial.is_active = false; } function void tutorial_action(Application_Links *app, Tutorial_Action action){ - + switch (action){ + case TutorialAction_Prev: + { + tutorial.slide_index -= 1; + }break; + + case TutorialAction_Next: + { + tutorial.slide_index += 1; + }break; + + case TutorialAction_Exit: + { + kill_tutorial(app); + }break; + + case TutorialAction_Restart: + { + tutorial.slide_index = 0; + }break; + } } function void -tutorial_default_4coder_render(Application_Links *app, Frame_Info frame_info, View_ID view_id){ +tutorial_init_title_face(Application_Links *app){ + 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); + if (tutorial.face == 0){ + tutorial.face = face; + } + } +} + +function void +default_4coder_tutorial_render(Application_Links *app, Frame_Info frame_info, View_ID view_id){ + Face_ID face = get_face_id(app, 0); + tutorial_init_title_face(app); + Face_Metrics metrics = get_face_metrics(app, face); + Face_Metrics tut_metrics = get_face_metrics(app, tutorial.face); + + //////// + + Scratch_Block scratch(app); + tutorial.slide_index = clamp(0, tutorial.slide_index, tutorial.slide_count - 1); + Tutorial_Slide_Function *slide_func = tutorial.slide_func_ptrs[tutorial.slide_index]; + Tutorial_Slide slide = slide_func(app, scratch); + + //////// + + f32 h0 = get_fancy_line_height(app, 0, &slide.short_details); + f32 h1 = get_fancy_line_height(app, 0, slide.long_details.first); + f32 title_height = max(h0, h1); + + //////// + View_ID active_view = get_active_view(app, Access_Always); b32 is_active_view = (active_view == view_id); @@ -79,170 +120,93 @@ tutorial_default_4coder_render(Application_Links *app, Frame_Info frame_info, Vi 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_Description face_description = get_face_description(app, face); - face_description.parameters.pt_size *= 2; - tutorial_face = try_create_new_face(app, &face_description); - if (tutorial_face == 0){ - tutorial_face = face; - } - } - - 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); + Vec2_f32 title_p = V2f32(region.x0, panel_y0 + (metrics.line_height*2.f) - title_height*0.5f); if (is_active_view){ - if (!tutorial_is_active){ + if (!tutorial.is_active){ view_enqueue_command_function(app, view_id, tutorial_activate); } } else{ - if (tutorial_is_active){ + if (tutorial.is_active){ view_enqueue_command_function(app, view_id, tutorial_deactivate); } } - Scratch_Block scratch(app); - - String_Const_u8 title = string_u8_litexpr("Handmade Seattle Demo"); - - 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); + tutorial.hover_action = TutorialAction_None; + if (tutorial.is_active){ + draw_fancy_block(app, 0, fcolor_zero(), &slide.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; + Rect_f32_Pair footer_pair = rect_split_top_bottom_neg(region, metrics.line_height*2.f); + Rect_f32 footer = 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; + { + Rect_f32_Pair pair = rect_split_left_right(footer, b_width); + footer = pair.max; + footer.x0 += 10.f; + if (tutorial.slide_index > 0){ + if (draw_button(app, 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; +} + +{ + Rect_f32_Pair pair = rect_split_left_right(footer, b_width); + footer = pair.max; + footer.x0 += 10.f; + if (tutorial.slide_index < tutorial.slide_count - 1){ + if (draw_button(app, pair.min, m_p, face, string_u8_litexpr("next"))){ + tutorial.hover_action = TutorialAction_Next; + } } + } + +{ + Rect_f32_Pair pair = rect_split_left_right(footer, b_width); + footer = pair.max; + footer.x0 += 10.f; + Rect_f32 exit_box = pair.min; + pair = rect_split_left_right(footer, b_width); + Rect_f32 restart_box = pair.min; + + if (tutorial.slide_index == tutorial.slide_count - 1){ + if (draw_button(app, exit_box, m_p, face, string_u8_litexpr("exit"))){ + tutorial.hover_action = TutorialAction_Exit; + } + + if (draw_button(app, restart_box, m_p, face, string_u8_litexpr("restart"))){ + tutorial.hover_action = TutorialAction_Restart; + } + } +} } else{ - draw_fancy_line(app, 0, fcolor_zero(), &short_details, title_p); + draw_fancy_line(app, 0, fcolor_zero(), &slide.short_details, title_p); } draw_set_clip(app, prev_clip); } function void -tutorial_default_4coder_run(Application_Links *app) +default_4coder_tutorial_run(Application_Links *app) { View_ID view = get_this_ctx_view(app, Access_Always); View_Context ctx = view_current_context(app, view); - ctx.render_caller = tutorial_default_4coder_render; + ctx.render_caller = default_4coder_tutorial_render; ctx.hides_buffer = true; View_Context_Block ctx_block(app, view, &ctx); - in_tutorial = true; - tutorial_view = view; + tutorial.in_tutorial = true; + tutorial.view = view; for (;;){ User_Input in = get_next_input(app, EventPropertyGroup_Any, 0); @@ -255,15 +219,15 @@ tutorial_default_4coder_run(Application_Links *app) case InputEventKind_MouseButton: { if (in.event.mouse.code == MouseCode_Left){ - tutorial_depressed_action = tutorial_hover_action; + 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); + if (tutorial.depressed_action == tutorial.hover_action){ + tutorial_action(app, tutorial.depressed_action); } } }break; @@ -310,7 +274,197 @@ tutorial_default_4coder_run(Application_Links *app) } } - in_tutorial = false; + tutorial.in_tutorial = false; +} + +global String_Const_u8 hms_title = string_u8_litexpr("Handmade Seattle Demo"); + +function void +default_4coder_tutorial_short_details(Application_Links *app, Arena *arena, Fancy_Line *short_details){ + Face_ID face = get_face_id(app, 0); + push_fancy_string(arena, short_details, tutorial.face, fcolor_id(Stag_Pop1), hms_title); + push_fancy_string(arena, 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(arena, short_details, face, fcolor_id(Stag_Pop2), string_u8_litexpr("Click here to see more.")); +} + +function void +default_4coder_tutorial_long_start(Application_Links *app, Arena *arena, Fancy_Block *long_details){ + Fancy_Line *line = push_fancy_line(arena, long_details, tutorial.face, fcolor_id(Stag_Pop1), hms_title); + + Face_ID face = get_face_id(app, 0); + // + line = push_fancy_line(arena, 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(arena, line, string_u8_litexpr(M)); +#undef M + push_fancy_string(arena, line, fcolor_id(Stag_Keyword), string_u8_litexpr("ask!")); + + // + push_fancy_line(arena, long_details, face, fcolor_id(Stag_Pop1), string_u8_litexpr("")); +} + +function Tutorial_Slide +default_4coder_tutorial_slide_1(Application_Links *app, Arena *arena){ + Tutorial_Slide result = {}; + + Face_ID face = get_face_id(app, 0); + tutorial_init_title_face(app); + + default_4coder_tutorial_short_details(app, arena, &result.short_details); + + Fancy_Block *long_details = &result.long_details; + default_4coder_tutorial_long_start(app, arena, long_details); + + Fancy_Line *line = 0; + + // + push_fancy_line(arena, long_details, face, fcolor_id(Stag_Keyword), string_u8_litexpr("Let's start with a few navigation commands:")); + + // + line = push_fancy_line(arena, long_details, face, fcolor_id(Stag_Default)); + push_fancy_stringf(arena, line, fcolor_id(Stag_Pop2), + "%40s ", ""); + push_fancy_stringf(arena, line, "change active panel"); + + // + line = push_fancy_line(arena, long_details, face, fcolor_id(Stag_Default)); + push_fancy_stringf(arena, line, fcolor_id(Stag_Pop2), + "%40s ", "<*AnyArrow*>"); + push_fancy_stringf(arena, line, "move cursor one character or line"); + + // + line = push_fancy_line(arena, long_details, face, fcolor_id(Stag_Default)); + push_fancy_stringf(arena, line, fcolor_id(Stag_Pop2), + "%40s ", ""); + push_fancy_stringf(arena, line, "move cursor by 'chunks'"); + + // + line = push_fancy_line(arena, long_details, face, fcolor_id(Stag_Default)); + push_fancy_stringf(arena, line, fcolor_id(Stag_Pop2), + "%40s ", ", "); + push_fancy_stringf(arena, line, "move cursor to the first/last character of the line"); + + // + line = push_fancy_line(arena, long_details, face, fcolor_id(Stag_Default)); + push_fancy_stringf(arena, line, fcolor_id(Stag_Pop2), + "%40s ", ", "); + push_fancy_stringf(arena, line, "move cursor by full pages up/down"); + + // + push_fancy_line(arena, long_details, face, fcolor_id(Stag_Keyword), string_u8_litexpr("Available in code files:")); + + // + line = push_fancy_line(arena, long_details, face, fcolor_id(Stag_Default)); + push_fancy_stringf(arena, line, fcolor_id(Stag_Pop2), + "%40s ", ""); + push_fancy_stringf(arena, line, "move cursor and mark to surrounding scope"); + + // + line = push_fancy_line(arena, long_details, face, fcolor_id(Stag_Default)); + push_fancy_stringf(arena, line, fcolor_id(Stag_Pop2), + "%40s ", ""); + push_fancy_stringf(arena, line, "move cursor and mark to previous scope"); + + // + line = push_fancy_line(arena, long_details, face, fcolor_id(Stag_Default)); + push_fancy_stringf(arena, line, fcolor_id(Stag_Pop2), + "%40s ", ""); + push_fancy_stringf(arena, line, "move cursor and mark to next scope"); + + // + line = push_fancy_line(arena, long_details, face, fcolor_id(Stag_Default)); + push_fancy_stringf(arena, line, fcolor_id(Stag_Pop2), + "%40s ", ""); + push_fancy_stringf(arena, line, "move cursor and mark to previous top-level scope"); + + // + line = push_fancy_line(arena, long_details, face, fcolor_id(Stag_Default)); + push_fancy_stringf(arena, line, fcolor_id(Stag_Pop2), + "%40s ", ""); + push_fancy_stringf(arena, line, "move cursor and mark to next top-level scope"); + + return(result); +} + +function Tutorial_Slide +default_4coder_tutorial_slide_2(Application_Links *app, Arena *arena){ + Tutorial_Slide result = {}; + + Face_ID face = get_face_id(app, 0); + tutorial_init_title_face(app); + + default_4coder_tutorial_short_details(app, arena, &result.short_details); + + Fancy_Block *long_details = &result.long_details; + default_4coder_tutorial_long_start(app, arena, long_details); + + Fancy_Line *line = 0; + + // + push_fancy_line(arena, long_details, face, fcolor_id(Stag_Keyword), string_u8_litexpr("4coder's default editing paradigm is emacs-like but with some differences:")); + + // + line = push_fancy_line(arena, long_details, face, fcolor_id(Stag_Default)); + push_fancy_stringf(arena, line, fcolor_id(Stag_Pop2), + "%40s ", ""); + push_fancy_stringf(arena, line, "non-modal text insertion works in any user-writable buffers at the cursor"); + + // + line = push_fancy_line(arena, long_details, face, fcolor_id(Stag_Default)); + push_fancy_stringf(arena, line, fcolor_id(Stag_Pop2), + "%40s ", "/"); + push_fancy_stringf(arena, line, "delete the previous/next character from the cursor"); + + // + line = push_fancy_line(arena, long_details, face, fcolor_id(Stag_Default)); + push_fancy_stringf(arena, line, fcolor_id(Stag_Pop2), + "%40s ", ""); + push_fancy_stringf(arena, line, "moves the mark to the cursor cursor"); + + // + line = push_fancy_line(arena, long_details, face, fcolor_id(Stag_Default)); + push_fancy_stringf(arena, line, fcolor_id(Stag_Pop2), + "%40s ", ""); + push_fancy_stringf(arena, line, "delete the cursor to mark range"); + + // + line = push_fancy_line(arena, long_details, face, fcolor_id(Stag_Default)); + push_fancy_stringf(arena, line, fcolor_id(Stag_Pop2), + "%40s ", ""); + push_fancy_stringf(arena, line, "copy the cursor to mark range to the clipboard"); + + // + line = push_fancy_line(arena, long_details, face, fcolor_id(Stag_Default)); + push_fancy_stringf(arena, line, fcolor_id(Stag_Pop2), + "%40s ", ""); + push_fancy_stringf(arena, line, "cut the cursor to mark range to the clipboard"); + + // + line = push_fancy_line(arena, long_details, face, fcolor_id(Stag_Default)); + push_fancy_stringf(arena, line, fcolor_id(Stag_Pop2), + "%40s ", ""); + push_fancy_stringf(arena, line, "paste the clipboard to the buffer"); + + // + line = push_fancy_line(arena, long_details, face, fcolor_id(Stag_Default)); + push_fancy_stringf(arena, line, fcolor_id(Stag_Pop2), + "%40s ", ""); + push_fancy_stringf(arena, line, "paste the clipboard to the buffer cycling through the clipboard's 'clips'"); + + // + line = push_fancy_line(arena, long_details, face, fcolor_id(Stag_Default)); + push_fancy_stringf(arena, line, fcolor_id(Stag_Pop2), + "%40s ", ""); + push_fancy_stringf(arena, line, "undo the last edit"); + + // + line = push_fancy_line(arena, long_details, face, fcolor_id(Stag_Default)); + push_fancy_stringf(arena, line, fcolor_id(Stag_Pop2), + "%40s ", ""); + push_fancy_stringf(arena, line, "redo the last undone edit"); + + + return(result); } CUSTOM_COMMAND_SIG(default_4coder_tutorial) @@ -322,10 +476,19 @@ CUSTOM_DOC("Tutorial for built in 4coder bindings and features.") if (panel_split(app, root_panel, Dimension_Y)){ panel_swap_children(app, root_panel); Panel_ID tutorial_panel = panel_get_child(app, root_panel, Side_Min); - tutorial_view = panel_get_view(app, tutorial_panel, Access_Always); - view_set_passive(app, tutorial_view, true); + tutorial.view = panel_get_view(app, tutorial_panel, Access_Always); + view_set_passive(app, tutorial.view, true); tutorial_activate(app); - view_enqueue_command_function(app, tutorial_view, tutorial_default_4coder_run); + + local_persist Tutorial_Slide_Function *slides[] = { + default_4coder_tutorial_slide_1, + default_4coder_tutorial_slide_2, + }; + tutorial.slide_index = 0; + tutorial.slide_func_ptrs = slides; + tutorial.slide_count = ArrayCount(slides); + + view_enqueue_command_function(app, tutorial.view, default_4coder_tutorial_run); } } diff --git a/custom/4coder_tutorial.h b/custom/4coder_tutorial.h new file mode 100644 index 00000000..3c58272f --- /dev/null +++ b/custom/4coder_tutorial.h @@ -0,0 +1,41 @@ +/* +4coder_tutorial.h - Guided graphical tutorial system. +*/ + +// TOP + +#if !defined(FCODER_TUTORIAL_H) +#define FCODER_TUTORIAL_H + +typedef i32 Tutorial_Action; +enum{ + TutorialAction_None, + TutorialAction_Prev, + TutorialAction_Next, + TutorialAction_Exit, + TutorialAction_Restart, +}; + +struct Tutorial_Slide{ + Fancy_Block long_details; + Fancy_Line short_details; +}; + +typedef Tutorial_Slide Tutorial_Slide_Function(Application_Links *app, Arena *arena); + +struct Tutorial_State{ + b32 in_tutorial; + View_ID view; + Face_ID face; + b32 is_active; + Tutorial_Action hover_action; + Tutorial_Action depressed_action; + + i32 slide_index; + Tutorial_Slide_Function **slide_func_ptrs; + i32 slide_count; +}; + +#endif + +// BOTTOM diff --git a/custom/generated/command_metadata.h b/custom/generated/command_metadata.h index e71946d3..75ce21b1 100644 --- a/custom/generated/command_metadata.h +++ b/custom/generated/command_metadata.h @@ -450,8 +450,8 @@ static Command_Metadata fcoder_metacmd_table[216] = { { 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(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(kill_tutorial, 0), false, "kill_tutorial", 13, "If there is an active tutorial, kill it.", 40, "w:\\4ed\\code\\custom\\4coder_tutorial.cpp", 38, 9 }, +{ 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, 470 }, { 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 }, };