2019-11-08 04:58:13 +00:00
/*
4 coder_tutorial . cpp - Guided graphical tutorial system .
*/
// TOP
2019-11-09 19:55:05 +00:00
global Tutorial_State tutorial = { } ;
2019-11-08 04:58:13 +00:00
2019-11-09 01:33:35 +00:00
CUSTOM_COMMAND_SIG ( kill_tutorial )
2019-11-09 19:55:05 +00:00
CUSTOM_DOC ( " If there is an active tutorial, kill it. " )
2019-11-09 01:33:35 +00:00
{
2019-11-09 19:55:05 +00:00
if ( ! tutorial . in_tutorial ) {
2019-11-08 06:38:51 +00:00
return ;
}
2019-11-09 19:55:05 +00:00
tutorial . in_tutorial = false ;
view_close ( app , tutorial . view ) ;
2019-11-08 06:38:51 +00:00
}
2019-11-15 02:36:31 +00:00
CUSTOM_COMMAND_SIG ( tutorial_maximize )
CUSTOM_DOC ( " Expand the tutorial window " )
{
2019-11-09 19:55:05 +00:00
if ( ! tutorial . in_tutorial ) {
2019-11-08 06:38:51 +00:00
return ;
}
2019-11-09 19:55:05 +00:00
Panel_ID panel = view_get_panel ( app , tutorial . view ) ;
2019-11-08 06:38:51 +00:00
Panel_ID parent = panel_get_parent ( app , panel ) ;
panel_set_split ( app , parent , PanelSplitKind_Ratio_Min , 0.5f ) ;
2019-11-09 19:55:05 +00:00
tutorial . is_active = true ;
2019-11-08 06:38:51 +00:00
}
2019-11-15 02:36:31 +00:00
CUSTOM_COMMAND_SIG ( tutorial_minimize )
CUSTOM_DOC ( " Shrink the tutorial window " )
{
2019-11-09 19:55:05 +00:00
if ( ! tutorial . in_tutorial ) {
2019-11-08 06:38:51 +00:00
return ;
2019-11-08 04:58:13 +00:00
}
2019-11-08 06:38:51 +00:00
Face_ID face = get_face_id ( app , 0 ) ;
Face_Metrics metrics = get_face_metrics ( app , face ) ;
f32 line_height = metrics . line_height ;
2019-11-09 19:55:05 +00:00
Panel_ID panel = view_get_panel ( app , tutorial . view ) ;
2019-11-08 06:38:51 +00:00
Panel_ID parent = panel_get_parent ( app , panel ) ;
panel_set_split ( app , parent , PanelSplitKind_FixedPixels_Min , line_height * 4.f ) ;
2019-11-09 19:55:05 +00:00
tutorial . is_active = false ;
2019-11-08 04:58:13 +00:00
}
2019-11-09 01:33:35 +00:00
function void
tutorial_action ( Application_Links * app , Tutorial_Action action ) {
2019-11-09 19:55:05 +00:00
switch ( action ) {
2019-11-15 02:36:31 +00:00
case TutorialAction_Minimize :
{
tutorial_minimize ( app ) ;
} break ;
case TutorialAction_Maximize :
{
tutorial_maximize ( app ) ;
} break ;
2019-11-09 19:55:05 +00:00
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 ;
}
2019-11-09 01:33:35 +00:00
}
2019-11-08 04:58:13 +00:00
function void
2019-11-09 19:55:05 +00:00
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
2019-11-09 22:41:18 +00:00
tutorial_render ( Application_Links * app , Frame_Info frame_info , View_ID view_id ) {
2019-11-09 19:55:05 +00:00
Face_ID face = get_face_id ( app , 0 ) ;
tutorial_init_title_face ( app ) ;
Face_Metrics metrics = get_face_metrics ( app , 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 ) ;
////////
2019-11-08 04:58:13 +00:00
View_ID active_view = get_active_view ( app , Access_Always ) ;
b32 is_active_view = ( active_view = = view_id ) ;
2019-11-08 06:38:51 +00:00
FColor margin_color = get_margin_color ( is_active_view ? UIHighlight_Active : UIHighlight_None ) ;
Rect_f32 region = draw_background_and_margin ( app , view_id , margin_color , margin_color ) ;
2019-11-08 04:58:13 +00:00
Rect_f32 prev_clip = draw_set_clip ( app , region ) ;
2019-11-09 01:33:35 +00:00
f32 panel_y0 = region . y0 - 3.f ;
2019-11-08 06:38:51 +00:00
region = rect_inner ( region , 3.f ) ;
draw_rectangle ( app , region , 20.f , fcolor_id ( Stag_Back ) ) ;
2019-11-09 01:33:35 +00:00
region = rect_inner ( region , 10.f ) ;
2019-11-09 19:55:05 +00:00
Vec2_f32 title_p = V2f32 ( region . x0 , panel_y0 + ( metrics . line_height * 2.f ) - title_height * 0.5f ) ;
2019-11-09 01:33:35 +00:00
2019-11-09 19:55:05 +00:00
tutorial . hover_action = TutorialAction_None ;
if ( tutorial . is_active ) {
draw_fancy_block ( app , 0 , fcolor_zero ( ) , & slide . long_details , title_p ) ;
2019-11-09 01:33:35 +00:00
// NOTE(allen): buttons
2019-11-09 19:55:05 +00:00
Rect_f32_Pair footer_pair = rect_split_top_bottom_neg ( region , metrics . line_height * 2.f ) ;
Rect_f32 footer = footer_pair . max ;
2019-11-09 01:33:35 +00:00
footer . x0 + = 10.f ;
footer . y0 - = 10.f ;
footer . y1 - = 10.f ;
f32 b_width = metrics . normal_advance * 10.f ;
Mouse_State mouse = get_mouse_state ( app ) ;
Vec2_f32 m_p = V2f32 ( mouse . p ) ;
2019-11-15 02:36:31 +00:00
{
Rect_f32_Pair pair = rect_split_left_right ( footer , b_width ) ;
footer = pair . max ;
footer . x0 + = 10.f ;
if ( draw_button ( app , pair . min , m_p , face , string_u8_litexpr ( " minimize " ) ) ) {
tutorial . hover_action = TutorialAction_Minimize ;
}
}
2019-11-09 19:55:05 +00:00
{
Rect_f32_Pair pair = rect_split_left_right ( footer , b_width ) ;
footer = pair . max ;
footer . x0 + = 10.f ;
2019-11-11 02:51:37 +00:00
if ( tutorial . slide_index > 0 ) {
if ( draw_button ( app , pair . min , m_p , face , string_u8_litexpr ( " prev " ) ) ) {
tutorial . hover_action = TutorialAction_Prev ;
}
2019-11-09 19:55:05 +00:00
}
}
2019-11-11 02:51:37 +00:00
{
2019-11-09 19:55:05 +00:00
Rect_f32_Pair pair = rect_split_left_right ( footer , b_width ) ;
footer = pair . max ;
footer . x0 + = 10.f ;
2019-11-11 02:51:37 +00:00
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 ;
}
2019-11-09 19:55:05 +00:00
}
2019-11-09 01:33:35 +00:00
}
2019-11-11 02:51:37 +00:00
{
2019-11-09 19:55:05 +00:00
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 ;
2019-11-11 02:51:37 +00:00
if ( tutorial . slide_index = = tutorial . slide_count - 1 ) {
if ( draw_button ( app , exit_box , m_p , face , string_u8_litexpr ( " end " ) ) ) {
tutorial . hover_action = TutorialAction_Exit ;
}
2019-11-09 19:55:05 +00:00
if ( draw_button ( app , restart_box , m_p , face , string_u8_litexpr ( " restart " ) ) ) {
2019-11-11 02:51:37 +00:00
tutorial . hover_action = TutorialAction_Restart ;
}
2019-11-09 19:55:05 +00:00
}
}
2019-11-09 01:33:35 +00:00
}
else {
2019-11-09 19:55:05 +00:00
draw_fancy_line ( app , 0 , fcolor_zero ( ) , & slide . short_details , title_p ) ;
2019-11-09 01:33:35 +00:00
}
2019-11-08 04:58:13 +00:00
draw_set_clip ( app , prev_clip ) ;
}
function void
2019-11-15 02:36:31 +00:00
tutorial_run_loop ( Application_Links * app ) {
2019-11-08 04:58:13 +00:00
View_ID view = get_this_ctx_view ( app , Access_Always ) ;
View_Context ctx = view_current_context ( app , view ) ;
2019-11-09 22:41:18 +00:00
ctx . render_caller = tutorial_render ;
2019-11-08 04:58:13 +00:00
ctx . hides_buffer = true ;
View_Context_Block ctx_block ( app , view , & ctx ) ;
2019-11-09 19:55:05 +00:00
tutorial . in_tutorial = true ;
tutorial . view = view ;
2019-11-15 02:36:31 +00:00
tutorial_maximize ( app ) ;
2019-11-08 06:38:51 +00:00
2019-11-15 23:33:14 +00:00
change_active_panel ( app ) ;
2019-11-08 04:58:13 +00:00
for ( ; ; ) {
2019-11-08 06:38:51 +00:00
User_Input in = get_next_input ( app , EventPropertyGroup_Any , 0 ) ;
if ( in . abort ) {
2019-11-08 04:58:13 +00:00
break ;
}
2019-11-08 06:38:51 +00:00
2019-11-11 02:51:37 +00:00
b32 handled = true ;
2019-11-08 06:38:51 +00:00
switch ( in . event . kind ) {
2019-11-09 01:33:35 +00:00
case InputEventKind_MouseButton :
{
2019-11-15 02:36:31 +00:00
tutorial_maximize ( app ) ;
2019-11-09 01:33:35 +00:00
if ( in . event . mouse . code = = MouseCode_Left ) {
2019-11-15 23:33:14 +00:00
tutorial_action ( app , tutorial . hover_action ) ;
2019-11-09 01:33:35 +00:00
}
} break ;
2019-11-08 06:38:51 +00:00
case InputEventKind_Core :
{
switch ( in . event . core . code ) {
case CoreCode_ClickActivateView :
{
2019-11-15 02:36:31 +00:00
tutorial_maximize ( app ) ;
2019-11-15 23:33:14 +00:00
tutorial_action ( app , tutorial . hover_action ) ;
change_active_panel ( app ) ;
2019-11-08 06:38:51 +00:00
} break ;
default :
{
handled = false ;
} break ;
}
} break ;
default :
{
handled = false ;
} break ;
}
2019-11-11 02:51:37 +00:00
2019-11-08 06:38:51 +00:00
if ( ! handled ) {
Mapping * mapping = ctx . mapping ;
Command_Map * map = mapping_get_map ( mapping , ctx . map_id ) ;
Fallback_Dispatch_Result disp_result =
fallback_command_dispatch ( app , mapping , map , & in ) ;
if ( disp_result . code = = FallbackDispatch_DelayedUICall ) {
call_after_ctx_shutdown ( app , view , disp_result . func ) ;
break ;
}
if ( disp_result . code = = FallbackDispatch_Unhandled ) {
leave_current_input_unhandled ( app ) ;
}
}
2019-11-08 04:58:13 +00:00
}
2019-11-08 06:38:51 +00:00
2019-11-09 19:55:05 +00:00
tutorial . in_tutorial = false ;
}
2019-11-09 22:41:18 +00:00
function void
run_tutorial ( Application_Links * app , Tutorial_Slide_Function * * slides , i32 slide_count ) {
if ( slide_count > 0 ) {
kill_tutorial ( app ) ;
Panel_ID root_panel = panel_get_root ( app ) ;
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 . slide_index = 0 ;
tutorial . slide_func_ptrs = slides ;
tutorial . slide_count = slide_count ;
view_enqueue_command_function ( app , tutorial . view , tutorial_run_loop ) ;
}
}
}
////////////////////////////////
2019-11-09 19:55:05 +00:00
global String_Const_u8 hms_title = string_u8_litexpr ( " Handmade Seattle Demo " ) ;
function void
2019-11-09 22:41:18 +00:00
hms_demo_tutorial_short_details ( Application_Links * app , Arena * arena , Fancy_Line * short_details ) {
2019-11-09 19:55:05 +00:00
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
2019-11-09 22:41:18 +00:00
hms_demo_tutorial_long_start ( Application_Links * app , Arena * arena , Fancy_Block * long_details ) {
2019-11-09 19:55:05 +00:00
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 ) ) ;
2019-11-10 22:56:03 +00:00
# define M "If you want more information than what you can find here, please "
2019-11-09 19:55:05 +00:00
push_fancy_string ( arena , line , string_u8_litexpr ( M ) ) ;
# undef M
2019-11-09 22:41:18 +00:00
push_fancy_string ( arena , line , fcolor_id ( Stag_Pop2 ) , string_u8_litexpr ( " ask! " ) ) ;
2019-11-09 19:55:05 +00:00
//
push_fancy_line ( arena , long_details , face , fcolor_id ( Stag_Pop1 ) , string_u8_litexpr ( " " ) ) ;
}
2019-11-09 22:41:18 +00:00
function void
hms_demo_tutorial_binding_line ( Application_Links * app , Arena * arena , Fancy_Block * long_details , Face_ID face , char * modifiers , char * key , char * description ) {
String_Const_u8 m = SCu8 ( modifiers ) ;
String_Const_u8 k = SCu8 ( key ) ;
f32 fill_size = ( f32 ) k . size ;
if ( m . size > 0 ) {
fill_size + = ( f32 ) m . size + 0.5f ;
}
f32 pad_size = 0.f ;
if ( fill_size < 40.f ) {
2019-11-11 02:51:37 +00:00
pad_size = 40.f - fill_size ;
2019-11-09 22:41:18 +00:00
}
Fancy_Line * line = line = push_fancy_line ( arena , long_details , face , fcolor_id ( Stag_Default ) ) ;
push_fancy_stringf ( arena , line , pad_size , 0.5f , " < " ) ;
if ( m . size > 0 ) {
push_fancy_stringf ( arena , line , fcolor_id ( Stag_Keyword ) , 0.f , 0.5f , " %s " , modifiers ) ;
}
push_fancy_stringf ( arena , line , fcolor_id ( Stag_Pop2 ) , " %s " , key ) ;
push_fancy_stringf ( arena , line , 0.5f , 1.f , " > " ) ;
push_fancy_stringf ( arena , line , " %s " , description ) ;
}
2019-11-09 19:55:05 +00:00
function Tutorial_Slide
2019-11-09 22:41:18 +00:00
hms_demo_tutorial_slide_1 ( Application_Links * app , Arena * arena ) {
2019-11-09 19:55:05 +00:00
Tutorial_Slide result = { } ;
Face_ID face = get_face_id ( app , 0 ) ;
tutorial_init_title_face ( app ) ;
2019-11-09 22:41:18 +00:00
hms_demo_tutorial_short_details ( app , arena , & result . short_details ) ;
2019-11-09 19:55:05 +00:00
Fancy_Block * long_details = & result . long_details ;
2019-11-09 22:41:18 +00:00
hms_demo_tutorial_long_start ( app , arena , long_details ) ;
2019-11-09 19:55:05 +00:00
2019-11-09 22:41:18 +00:00
push_fancy_line ( arena , long_details , face , fcolor_id ( Stag_Pop1 ) , string_u8_litexpr ( " Let's start with a few navigation commands: " ) ) ;
2019-11-09 19:55:05 +00:00
2019-11-09 22:41:18 +00:00
hms_demo_tutorial_binding_line ( app , arena , long_details , face ,
" Control " , " Comma " , " change active panel " ) ;
2019-11-09 19:55:05 +00:00
2019-11-09 22:41:18 +00:00
hms_demo_tutorial_binding_line ( app , arena , long_details , face ,
" " , " *AnyArrow* " , " move cursor one character or line " ) ;
2019-11-09 19:55:05 +00:00
2019-11-09 22:41:18 +00:00
hms_demo_tutorial_binding_line ( app , arena , long_details , face ,
" Control " , " *AnyArrow* " , " move cursor by 'chunks' " ) ;
2019-11-09 19:55:05 +00:00
2019-11-09 22:41:18 +00:00
hms_demo_tutorial_binding_line ( app , arena , long_details , face ,
" " , " Home/End " , " move cursor to the first/last character of the line " ) ;
2019-11-09 19:55:05 +00:00
2019-11-09 22:41:18 +00:00
hms_demo_tutorial_binding_line ( app , arena , long_details , face ,
" " , " PageUp/PageDown " , " move cursor by full pages up/down " ) ;
2019-11-09 19:55:05 +00:00
2019-11-09 22:41:18 +00:00
push_fancy_line ( arena , long_details , face , fcolor_id ( Stag_Pop1 ) , string_u8_litexpr ( " Available in code files: " ) ) ;
2019-11-09 19:55:05 +00:00
2019-11-09 22:41:18 +00:00
hms_demo_tutorial_binding_line ( app , arena , long_details , face ,
" Alt " , " LeftBracket " , " move cursor and mark to surrounding scope " ) ;
2019-11-09 19:55:05 +00:00
2019-11-09 22:41:18 +00:00
hms_demo_tutorial_binding_line ( app , arena , long_details , face ,
" Alt " , " RightBracket " , " move cursor and mark to previous scope " ) ;
2019-11-09 19:55:05 +00:00
2019-11-09 22:41:18 +00:00
hms_demo_tutorial_binding_line ( app , arena , long_details , face ,
" Alt " , " Quote " , " move cursor and mark to next scope " ) ;
2019-11-09 19:55:05 +00:00
2019-11-09 22:41:18 +00:00
hms_demo_tutorial_binding_line ( app , arena , long_details , face ,
" Alt Shift " , " RightBracket " , " move cursor and mark to previous top-level scope " ) ;
2019-11-09 19:55:05 +00:00
2019-11-09 22:41:18 +00:00
hms_demo_tutorial_binding_line ( app , arena , long_details , face ,
" Alt Shift " , " Quote " , " move cursor and mark to next scope at the same level as the current scope " ) ;
2019-11-09 19:55:05 +00:00
return ( result ) ;
}
function Tutorial_Slide
2019-11-09 22:41:18 +00:00
hms_demo_tutorial_slide_2 ( Application_Links * app , Arena * arena ) {
2019-11-09 19:55:05 +00:00
Tutorial_Slide result = { } ;
Face_ID face = get_face_id ( app , 0 ) ;
tutorial_init_title_face ( app ) ;
2019-11-09 22:41:18 +00:00
hms_demo_tutorial_short_details ( app , arena , & result . short_details ) ;
2019-11-09 19:55:05 +00:00
Fancy_Block * long_details = & result . long_details ;
2019-11-09 22:41:18 +00:00
hms_demo_tutorial_long_start ( app , arena , long_details ) ;
2019-11-09 19:55:05 +00:00
2019-11-09 22:41:18 +00:00
push_fancy_line ( arena , long_details , face , fcolor_id ( Stag_Pop1 ) , string_u8_litexpr ( " Now a look at basic editing: " ) ) ;
2019-11-09 19:55:05 +00:00
2019-11-09 22:41:18 +00:00
hms_demo_tutorial_binding_line ( app , arena , long_details , face ,
" " , " TextInsert " , " non-modal text insertion works in any user-writable buffers at the cursor " ) ;
2019-11-09 19:55:05 +00:00
2019-11-09 22:41:18 +00:00
hms_demo_tutorial_binding_line ( app , arena , long_details , face ,
" " , " Backspace/Delete " , " delete the previous/next character from the cursor " ) ;
2019-11-09 19:55:05 +00:00
2019-11-09 22:41:18 +00:00
hms_demo_tutorial_binding_line ( app , arena , long_details , face ,
" Control " , " Z " , " undo the last edit " ) ;
2019-11-09 19:55:05 +00:00
2019-11-09 22:41:18 +00:00
hms_demo_tutorial_binding_line ( app , arena , long_details , face ,
" Control " , " Y " , " redo the last undone edit " ) ;
2019-11-09 19:55:05 +00:00
2019-11-09 22:41:18 +00:00
hms_demo_tutorial_binding_line ( app , arena , long_details , face ,
" Control " , " L " , " duplicate the current line " ) ;
2019-11-09 19:55:05 +00:00
2019-11-09 22:41:18 +00:00
hms_demo_tutorial_binding_line ( app , arena , long_details , face ,
" Alt " , " Up/Down " , " move the current line " ) ;
2019-11-09 19:55:05 +00:00
2019-11-09 22:41:18 +00:00
push_fancy_line ( arena , long_details , face , fcolor_id ( Stag_Pop1 ) , string_u8_litexpr ( " Range commands based on a cursor and mark (emacs style): " ) ) ;
2019-11-09 19:55:05 +00:00
2019-11-09 22:41:18 +00:00
hms_demo_tutorial_binding_line ( app , arena , long_details , face ,
2019-11-15 23:33:14 +00:00
" Control " , " Space " , " moves the mark to the cursor " ) ;
2019-11-09 19:55:05 +00:00
2019-11-09 22:41:18 +00:00
hms_demo_tutorial_binding_line ( app , arena , long_details , face ,
" Control " , " D " , " delete the range " ) ;
2019-11-09 19:55:05 +00:00
2019-11-09 22:41:18 +00:00
hms_demo_tutorial_binding_line ( app , arena , long_details , face ,
" Control " , " C " , " copy the range " ) ;
2019-11-09 19:55:05 +00:00
2019-11-09 22:41:18 +00:00
hms_demo_tutorial_binding_line ( app , arena , long_details , face ,
" Control " , " X " , " cut the range " ) ;
2019-11-09 19:55:05 +00:00
2019-11-09 22:41:18 +00:00
push_fancy_line ( arena , long_details , face , fcolor_id ( Stag_Pop1 ) , string_u8_litexpr ( " Paste options with a multi-stage clipboard: " ) ) ;
hms_demo_tutorial_binding_line ( app , arena , long_details , face ,
" Control " , " V " , " paste the clipboard to the buffer " ) ;
hms_demo_tutorial_binding_line ( app , arena , long_details , face ,
" Control Shift " , " V " , " paste the clipboard to the buffer cycling through the clipboard's 'clips' " ) ;
2019-11-09 19:55:05 +00:00
return ( result ) ;
2019-11-08 04:58:13 +00:00
}
2019-11-09 22:41:18 +00:00
function Tutorial_Slide
hms_demo_tutorial_slide_3 ( Application_Links * app , Arena * arena ) {
Tutorial_Slide result = { } ;
Face_ID face = get_face_id ( app , 0 ) ;
tutorial_init_title_face ( app ) ;
hms_demo_tutorial_short_details ( app , arena , & result . short_details ) ;
Fancy_Block * long_details = & result . long_details ;
hms_demo_tutorial_long_start ( app , arena , long_details ) ;
push_fancy_line ( arena , long_details , face , fcolor_id ( Stag_Pop1 ) , string_u8_litexpr ( " Now try beginning a file lister: " ) ) ;
hms_demo_tutorial_binding_line ( app , arena , long_details , face ,
" Control " , " N " , " begin a file lister for exploring the file system - always creating a new file " ) ;
hms_demo_tutorial_binding_line ( app , arena , long_details , face ,
" Control " , " O " , " begin a file lister for exploring the file system - ultimiately opening or creating a file " ) ;
hms_demo_tutorial_binding_line ( app , arena , long_details , face ,
" Alt " , " O " , " same as previous option but opens in the other panel " ) ;
push_fancy_line ( arena , long_details , face , fcolor_id ( Stag_Pop1 ) , string_u8_litexpr ( " Inside a file lister: " ) ) ;
hms_demo_tutorial_binding_line ( app , arena , long_details , face ,
" " , " TextInsert " , " narrows the lister down to options with substrings matching the text field " ) ;
hms_demo_tutorial_binding_line ( app , arena , long_details , face ,
" " , " Backspace " , " backspace the end of the text field " ) ;
hms_demo_tutorial_binding_line ( app , arena , long_details , face ,
" " , " Up/Down " , " move the highlighted option up/down " ) ;
hms_demo_tutorial_binding_line ( app , arena , long_details , face ,
" " , " PageUp/PageDown " , " move the highlighted option up/down by a 'large chunk' " ) ;
hms_demo_tutorial_binding_line ( app , arena , long_details , face ,
" " , " Return/Tab " , " select the highlighted option; when a folder is highlighted it is opened in the lister " ) ;
hms_demo_tutorial_binding_line ( app , arena , long_details , face ,
" " , " Escape " , " cancel the operation " ) ;
push_fancy_line ( arena , long_details , face , fcolor_id ( Stag_Pop1 ) , string_u8_litexpr ( " There are also buffer listers for operations on buffers that are already open: " ) ) ;
hms_demo_tutorial_binding_line ( app , arena , long_details , face ,
" Control " , " I " , " begin a buffer lister and switch to the selected buffer " ) ;
hms_demo_tutorial_binding_line ( app , arena , long_details , face ,
" Control " , " K " , " begin a buffer lister and try to kill the selected buffer " ) ;
return ( result ) ;
}
function Tutorial_Slide
hms_demo_tutorial_slide_4 ( Application_Links * app , Arena * arena ) {
Tutorial_Slide result = { } ;
Face_ID face = get_face_id ( app , 0 ) ;
tutorial_init_title_face ( app ) ;
hms_demo_tutorial_short_details ( app , arena , & result . short_details ) ;
Fancy_Block * long_details = & result . long_details ;
hms_demo_tutorial_long_start ( app , arena , long_details ) ;
push_fancy_line ( arena , long_details , face , fcolor_id ( Stag_Pop1 ) , string_u8_litexpr ( " The command lister makes all commands available in one place: " ) ) ;
hms_demo_tutorial_binding_line ( app , arena , long_details , face ,
" Alt " , " X " , " a lister of all commands " ) ;
push_fancy_line ( arena , long_details , face , fcolor_id ( Stag_Pop1 ) , string_u8_litexpr ( " Try some of these commands from the command lister: " ) ) ;
hms_demo_tutorial_binding_line ( app , arena , long_details , face ,
" " , " toggle_filebar " , " toggle the panel's filebar " ) ;
hms_demo_tutorial_binding_line ( app , arena , long_details , face ,
" " , " toggle_line_numbers " , " toggle the panel's line number " ) ;
hms_demo_tutorial_binding_line ( app , arena , long_details , face ,
" " , " set_eol_mode_* " , " change how a buffer prefers to fixup it's line endings " ) ;
hms_demo_tutorial_binding_line ( app , arena , long_details , face ,
" " , " close_panel " , " close the current panel " ) ;
hms_demo_tutorial_binding_line ( app , arena , long_details , face ,
" " , " open_panel_vsplit " , " create a vertical split in the current panel " ) ;
hms_demo_tutorial_binding_line ( app , arena , long_details , face ,
" " , " open_panel_hsplit " , " create a horizontal split in the current panel " ) ;
return ( result ) ;
}
function Tutorial_Slide
hms_demo_tutorial_slide_5 ( Application_Links * app , Arena * arena ) {
Tutorial_Slide result = { } ;
Face_ID face = get_face_id ( app , 0 ) ;
tutorial_init_title_face ( app ) ;
hms_demo_tutorial_short_details ( app , arena , & result . short_details ) ;
Fancy_Block * long_details = & result . long_details ;
hms_demo_tutorial_long_start ( app , arena , long_details ) ;
push_fancy_line ( arena , long_details , face , fcolor_id ( Stag_Pop1 ) , string_u8_litexpr ( " Fast navigation by jump lists: " ) ) ;
hms_demo_tutorial_binding_line ( app , arena , long_details , face ,
" Alt " , " F " , " after the user answers a query for a string generate a jump list of matches " ) ;
hms_demo_tutorial_binding_line ( app , arena , long_details , face ,
" Control Shift " , " T " , " extract an identifier from the text under cursor and generate a jump list of matches " ) ;
hms_demo_tutorial_binding_line ( app , arena , long_details , face ,
" Control Shift " , " I " , " parse the current buffer as a C/C++ source and generate a jump list of functions " ) ;
push_fancy_line ( arena , long_details , face , fcolor_id ( Stag_Pop1 ) , string_u8_litexpr ( " After generating a jump list it is bound as the active jump list enabling these commands: " ) ) ;
hms_demo_tutorial_binding_line ( app , arena , long_details , face ,
" Alt " , " N " , " jump to the next jump location " ) ;
hms_demo_tutorial_binding_line ( app , arena , long_details , face ,
" Alt Shift " , " N " , " jump to the previous jump location " ) ;
hms_demo_tutorial_binding_line ( app , arena , long_details , face ,
" Alt Shift " , " M " , " jump to the first jump " ) ;
return ( result ) ;
}
function Tutorial_Slide
hms_demo_tutorial_slide_6 ( Application_Links * app , Arena * arena ) {
Tutorial_Slide result = { } ;
Face_ID face = get_face_id ( app , 0 ) ;
tutorial_init_title_face ( app ) ;
hms_demo_tutorial_short_details ( app , arena , & result . short_details ) ;
Fancy_Block * long_details = & result . long_details ;
hms_demo_tutorial_long_start ( app , arena , long_details ) ;
push_fancy_line ( arena , long_details , face , fcolor_id ( Stag_Pop1 ) , string_u8_litexpr ( " Virtual whitespace: " ) ) ;
push_fancy_line ( arena , long_details , face , fcolor_id ( Stag_Default ) ,
string_u8_litexpr ( " \t Buffers that are indexed with information about nest structures can be equiped with the virtual whitespace layout algorithm. " ) ) ;
push_fancy_line ( arena , long_details , face , fcolor_id ( Stag_Default ) ,
2019-11-15 02:36:31 +00:00
string_u8_litexpr ( " \t The on screen layout of text is independent of the actual whitespace contents of the underlying text. " ) ) ;
push_fancy_line ( arena , long_details , face , fcolor_id ( Stag_Default ) , string_u8_litexpr ( " " ) ) ;
push_fancy_line ( arena , long_details , face , fcolor_id ( Stag_Keyword ) ,
2019-11-09 22:41:18 +00:00
string_u8_litexpr ( " \t Try inserting new scopes and parenthetical sections in a code file. " ) ) ;
push_fancy_line ( arena , long_details , face , fcolor_id ( Stag_Default ) ,
2019-11-15 02:36:31 +00:00
string_u8_litexpr ( " \t \t Observe that indentation is updated automatically. " ) ) ;
2019-11-09 22:41:18 +00:00
2019-11-15 02:36:31 +00:00
push_fancy_line ( arena , long_details , face , fcolor_id ( Stag_Keyword ) ,
2019-11-09 22:41:18 +00:00
string_u8_litexpr ( " \t Try creating a line that is long enough to wrap around the edge. " ) ) ;
push_fancy_line ( arena , long_details , face , fcolor_id ( Stag_Default ) ,
2019-11-15 02:36:31 +00:00
string_u8_litexpr ( " \t \t Observe that wrapped lines obey the same indentation rules as literal lines. " ) ) ;
2019-11-09 22:41:18 +00:00
{
Fancy_Line * line = push_fancy_line ( arena , long_details , face , fcolor_id ( Stag_Default ) ) ;
push_fancy_stringf ( arena , line , " \t Use the command " ) ;
push_fancy_stringf ( arena , line , fcolor_id ( Stag_Pop2 ) , " toggle_virtual_whitespace " ) ;
push_fancy_stringf ( arena , line , " to turn this feature on and off " ) ;
}
2019-11-15 02:36:31 +00:00
{
Fancy_Line * line = push_fancy_line ( arena , long_details , face , fcolor_id ( Stag_Default ) ) ;
push_fancy_stringf ( arena , line , " \t Use the command " ) ;
push_fancy_stringf ( arena , line , fcolor_id ( Stag_Pop2 ) , " toggle_line_wrap " ) ;
push_fancy_stringf ( arena , line , " to see how layout changes with line wrapping on and off " ) ;
}
2019-11-09 22:41:18 +00:00
push_fancy_line ( arena , long_details , face , fcolor_id ( Stag_Pop1 ) , string_u8_litexpr ( " Auto Indentation: " ) ) ;
hms_demo_tutorial_binding_line ( app , arena , long_details , face ,
2019-11-10 22:56:03 +00:00
" Control " , " Tab " , " auto indent the lines marked by the range; the effect is only visible with virtual whitespace off. " ) ;
return ( result ) ;
}
function Tutorial_Slide
hms_demo_tutorial_slide_7 ( Application_Links * app , Arena * arena ) {
Tutorial_Slide result = { } ;
Face_ID face = get_face_id ( app , 0 ) ;
tutorial_init_title_face ( app ) ;
hms_demo_tutorial_short_details ( app , arena , & result . short_details ) ;
Fancy_Block * long_details = & result . long_details ;
hms_demo_tutorial_long_start ( app , arena , long_details ) ;
push_fancy_line ( arena , long_details , face , fcolor_id ( Stag_Pop1 ) , string_u8_litexpr ( " Builds, scripts, and projects: " ) ) ;
hms_demo_tutorial_binding_line ( app , arena , long_details , face ,
" Alt " , " M " , " searches for and runs a build script (windows -> 'build.bat'; unix -> 'build.sh') " ) ;
hms_demo_tutorial_binding_line ( app , arena , long_details , face ,
" " , " execute_any_cli " , " queries the user for a buffer name and a system command then runs the command and pipes output to the buffer " ) ;
hms_demo_tutorial_binding_line ( app , arena , long_details , face ,
" " , " execute_previous_cli " , " repeats an execute_any_cli command with the same command and ouptut buffer " ) ;
push_fancy_line ( arena , long_details , face , fcolor_id ( Stag_Pop1 ) , string_u8_litexpr ( " If a script/command generates output that can be parsed as jumps (e.g. compilation errors) then it becomes the active jump buffer: " ) ) ;
hms_demo_tutorial_binding_line ( app , arena , long_details , face ,
" Alt " , " N " , " jump to the next jump location " ) ;
hms_demo_tutorial_binding_line ( app , arena , long_details , face ,
" Alt Shift " , " N " , " jump to the previous jump location " ) ;
hms_demo_tutorial_binding_line ( app , arena , long_details , face ,
" Alt Shift " , " M " , " jump to the first jump " ) ;
push_fancy_line ( arena , long_details , face , fcolor_id ( Stag_Pop1 ) , string_u8_litexpr ( " The project system enables rich bindings of arbitrary system scripts (when a project is loaded): " ) ) ;
hms_demo_tutorial_binding_line ( app , arena , long_details , face ,
" " , " F# " , " run a script bound to the corresponding index in the loaded project " ) ;
hms_demo_tutorial_binding_line ( app , arena , long_details , face ,
" " , " project_command_lister " , " use a lister to examine all system commands encoded in the loaded project " ) ;
hms_demo_tutorial_binding_line ( app , arena , long_details , face ,
" " , " load_project " , " searches for and loads a 'project.4coder' file " ) ;
hms_demo_tutorial_binding_line ( app , arena , long_details , face ,
" " , " setup_new_project " , " command to generate a new 'project.4coder' file and build scripts " ) ;
push_fancy_line ( arena , long_details , face , fcolor_id ( Stag_Default ) ,
string_u8_litexpr ( " \t Checkout 'project.4coder' to see more about what is in a project. " ) ) ;
return ( result ) ;
}
function Tutorial_Slide
hms_demo_tutorial_slide_8 ( Application_Links * app , Arena * arena ) {
Tutorial_Slide result = { } ;
Face_ID face = get_face_id ( app , 0 ) ;
tutorial_init_title_face ( app ) ;
hms_demo_tutorial_short_details ( app , arena , & result . short_details ) ;
Fancy_Block * long_details = & result . long_details ;
hms_demo_tutorial_long_start ( app , arena , long_details ) ;
push_fancy_line ( arena , long_details , face , fcolor_id ( Stag_Default ) ,
string_u8_litexpr ( " Probably the biggest feature in 4coder is that so many things about it can be customized. " ) ) ;
push_fancy_line ( arena , long_details , face , fcolor_id ( Stag_Default ) ,
2019-11-15 02:36:31 +00:00
string_u8_litexpr ( " The project loaded for this demo is the 'default custom layer' everything here could be done differently, as you see fit. " ) ) ;
push_fancy_line ( arena , long_details , face , fcolor_id ( Stag_Default ) ,
string_u8_litexpr ( " " ) ) ;
2019-11-10 22:56:03 +00:00
push_fancy_line ( arena , long_details , face , fcolor_id ( Stag_Pop1 ) ,
string_u8_litexpr ( " Search for these commands to see some of the features available to customization: " ) ) ;
hms_demo_tutorial_binding_line ( app , arena , long_details , face ,
" Alt " , " F " , " (hint!) this is the default binding for search, use it to find these functions " ) ;
hms_demo_tutorial_binding_line ( app , arena , long_details , face ,
" " , " write_text_input " , " the default implementation for text insertion " ) ;
hms_demo_tutorial_binding_line ( app , arena , long_details , face ,
" " , " copy " , " the default implementation copying to clipboard " ) ;
hms_demo_tutorial_binding_line ( app , arena , long_details , face ,
" " , " goto_line " , " jump to a line specified by the user (which you should try by the way!) " ) ;
hms_demo_tutorial_binding_line ( app , arena , long_details , face ,
" " , " interactive_switch_buffer " , " see how this command encodes it's use of a lister with the call 'get_buffer_from_user' " ) ;
hms_demo_tutorial_binding_line ( app , arena , long_details , face ,
" " , " project_command_lister " , " again see how this command encodes a lister with a call, this time 'get_project_command_from_user' " ) ;
hms_demo_tutorial_binding_line ( app , arena , long_details , face ,
" " , " setup_default_mapping " , " defines the mapping of commands to bindings " ) ;
push_fancy_line ( arena , long_details , face , fcolor_id ( Stag_Default ) , string_u8_litexpr ( " " ) ) ;
push_fancy_line ( arena , long_details , face , fcolor_id ( Stag_Default ) , string_u8_litexpr ( " \t The macros CUSTOM_COMMAND_SIG and CUSTOM_DOC markup the commands to create the list of all available commands. " ) ) ;
push_fancy_line ( arena , long_details , face , fcolor_id ( Stag_Default ) , string_u8_litexpr ( " \t This means that user written commands that use the same markup automatically appear in the command_lister along side built in commands! " ) ) ;
return ( result ) ;
}
function Tutorial_Slide
hms_demo_tutorial_slide_9 ( Application_Links * app , Arena * arena ) {
Tutorial_Slide result = { } ;
Face_ID face = get_face_id ( app , 0 ) ;
tutorial_init_title_face ( app ) ;
hms_demo_tutorial_short_details ( app , arena , & result . short_details ) ;
Fancy_Block * long_details = & result . long_details ;
hms_demo_tutorial_long_start ( app , arena , long_details ) ;
push_fancy_line ( arena , long_details , face , fcolor_id ( Stag_Default ) ,
string_u8_litexpr ( " The customization system exposes much more than just commands to be customized... " ) ) ;
hms_demo_tutorial_binding_line ( app , arena , long_details , face ,
" Alt " , " F " , " (hint!) this is the default binding for search, use it to find these functions " ) ;
push_fancy_line ( arena , long_details , face , fcolor_id ( Stag_Pop1 ) ,
string_u8_litexpr ( " Write completely custom GUIs: " ) ) ;
hms_demo_tutorial_binding_line ( app , arena , long_details , face ,
" " , " run_lister/lister_render " , " the input handling loop for listers; and the render handler for listers " ) ;
hms_demo_tutorial_binding_line ( app , arena , long_details , face ,
" " , " tutorial_run_loop/tutorial_render " , " underlying implementation for the tutorial system powering this demo! " ) ;
push_fancy_line ( arena , long_details , face , fcolor_id ( Stag_Pop1 ) ,
string_u8_litexpr ( " Write custom text coloring and highlighting in buffers: " ) ) ;
hms_demo_tutorial_binding_line ( app , arena , long_details , face ,
" " , " draw_cpp_token_colors " , " syntax highlighting for C++ tokens. " ) ;
hms_demo_tutorial_binding_line ( app , arena , long_details , face ,
" " , " draw_line_number_margin " , " draws a line number margin " ) ;
hms_demo_tutorial_binding_line ( app , arena , long_details , face ,
" " , " default_render_buffer " , " puts together all the default markup in buffer rendering " ) ;
push_fancy_line ( arena , long_details , face , fcolor_id ( Stag_Pop1 ) ,
string_u8_litexpr ( " Write custom line layout rules: " ) ) ;
hms_demo_tutorial_binding_line ( app , arena , long_details , face ,
" " , " layout_unwrapped_small_blank_lines " , " a funky layout that makes blank lines half height " ) ;
hms_demo_tutorial_binding_line ( app , arena , long_details , face ,
" " , " layout_index_unwrapped__inner " , " the unwrapped version of the virtual whitespace layout logic " ) ;
push_fancy_line ( arena , long_details , face , fcolor_id ( Stag_Pop1 ) ,
string_u8_litexpr ( " Write custom smoothing rules that interact with buffer and UI scrolling: " ) ) ;
hms_demo_tutorial_binding_line ( app , arena , long_details , face ,
" " , " snap_delta " , " a delta rule that snaps to the destination point instantly " ) ;
hms_demo_tutorial_binding_line ( app , arena , long_details , face ,
" " , " fixed_time_cubic_delta " , " the smooth scrolling enabled in this build " ) ;
return ( result ) ;
}
function Tutorial_Slide
hms_demo_tutorial_slide_10 ( Application_Links * app , Arena * arena ) {
Tutorial_Slide result = { } ;
Face_ID face = get_face_id ( app , 0 ) ;
tutorial_init_title_face ( app ) ;
hms_demo_tutorial_short_details ( app , arena , & result . short_details ) ;
Fancy_Block * long_details = & result . long_details ;
hms_demo_tutorial_long_start ( app , arena , long_details ) ;
push_fancy_line ( arena , long_details , face , fcolor_id ( Stag_Pop1 ) ,
string_u8_litexpr ( " Some miscellaneous things to try: " ) ) ;
hms_demo_tutorial_binding_line ( app , arena , long_details , face ,
" " , " Tab " , " in a code file this triggers the cyclic word complete, often a handy command " ) ;
2019-11-09 22:41:18 +00:00
2019-11-15 02:36:31 +00:00
hms_demo_tutorial_binding_line ( app , arena , long_details , face ,
" Control " , " F/R " , " forward/reverse iterative search " ) ;
hms_demo_tutorial_binding_line ( app , arena , long_details , face ,
" Control " , " A " , " replace all instances of a string in the range " ) ;
hms_demo_tutorial_binding_line ( app , arena , long_details , face ,
" Control " , " 0 " , " insert an assignment to an empty struct or array " ) ;
hms_demo_tutorial_binding_line ( app , arena , long_details , face ,
" Alt " , " 0 " , " insert a #if 0 / #endif pair at the cursor and mark " ) ;
hms_demo_tutorial_binding_line ( app , arena , long_details , face ,
" Alt " , " 2 " , " open the corresponding .h/.cpp file to the current buffer in the second panel " ) ;
return ( result ) ;
}
function Tutorial_Slide
hms_demo_tutorial_slide_11 ( Application_Links * app , Arena * arena ) {
Tutorial_Slide result = { } ;
Face_ID face = get_face_id ( app , 0 ) ;
tutorial_init_title_face ( app ) ;
hms_demo_tutorial_short_details ( app , arena , & result . short_details ) ;
Fancy_Block * long_details = & result . long_details ;
hms_demo_tutorial_long_start ( app , arena , long_details ) ;
push_fancy_line ( arena , long_details , face , fcolor_id ( Stag_Pop1 ) , string_u8_litexpr ( " " ) ) ;
push_fancy_line ( arena , long_details , face , fcolor_id ( Stag_Pop1 ) , string_u8_litexpr ( " " ) ) ;
push_fancy_line ( arena , long_details , face , fcolor_id ( Stag_Pop1 ) , string_u8_litexpr ( " \t \t Thanks for checking out the demo! " ) ) ;
2019-11-09 22:41:18 +00:00
return ( result ) ;
}
CUSTOM_COMMAND_SIG ( hms_demo_tutorial )
2019-11-08 04:58:13 +00:00
CUSTOM_DOC ( " Tutorial for built in 4coder bindings and features. " )
{
2019-11-09 22:41:18 +00:00
local_persist Tutorial_Slide_Function * slides [ ] = {
// basic navigation
hms_demo_tutorial_slide_1 ,
// basic editing
hms_demo_tutorial_slide_2 ,
// file and buffer lister
hms_demo_tutorial_slide_3 ,
// command lister
hms_demo_tutorial_slide_4 ,
// advanced navigation
hms_demo_tutorial_slide_5 ,
// virtual whitespace
hms_demo_tutorial_slide_6 ,
2019-11-10 22:56:03 +00:00
// system commands
hms_demo_tutorial_slide_7 ,
// customizable commands
hms_demo_tutorial_slide_8 ,
// customizable ui
hms_demo_tutorial_slide_9 ,
// miscellanea
hms_demo_tutorial_slide_10 ,
2019-11-15 02:36:31 +00:00
// end
hms_demo_tutorial_slide_11 ,
2019-11-09 22:41:18 +00:00
} ;
run_tutorial ( app , slides , ArrayCount ( slides ) ) ;
2019-11-08 04:58:13 +00:00
}
// BOTTOM