2016-06-29 17:16:08 +00:00
/*
2016-09-03 01:15:53 +00:00
* Mr . 4 th Dimention - Allen Webster
*
* 12.12 .2014
*
* Application layer for project codename " 4ed "
*
*/
2016-06-29 17:16:08 +00:00
// TOP
2017-07-11 21:53:27 +00:00
// Messages
global_const char messages [ ] =
" ---------------------------------------------------------------- \n "
" Welcome to " VERSION " \n "
" If you're new to 4coder there are some tutorials at http://4coder.net/tutorials.html \n "
2017-11-22 21:02:56 +00:00
" Direct bug reports to editor@4coder.net for maximum reply speed \n "
" Questions or requests can go to editor@4coder.net or to 4coder.handmade.network \n "
" \n "
2018-05-07 02:58:17 +00:00
" In alpha 4.0.26: \n "
" Routine bug fixing... \n "
" -Fixed various text input crash bugs \n "
" -Fixed load large file crash bug \n "
" -Fixed crash in 'list_all_locations_of_type_definition_of_identifier' \n "
" -Fixed sticky jump crash \n "
" -Fixed line move/delete bugs on last line of file \n "
" -Fixed <end> to work on indefinitely long lines \n "
" -Fixed jump behavior quirks with parsing and cursor movement \n "
" -Fixed rare bug causing copy from other applications to fail on Windows \n "
" -Fixed auto indent commands to do a better job picking an anchor for parsing \n "
" Testing system now in place: \n "
" Flag -R <file-name> creates an 'input recording' file of the 4coder session \n "
" Flag -T <file-name> overrides user input and drives input by the input recorded in the specified file \n "
" \n "
" \n "
2017-12-01 19:13:36 +00:00
" New in alpha 4.0.25: \n "
" -Support for unbounded paste sizes \n "
" -Window title now reflects the open project file \n "
" -Buffer names resolve with more path information instead of just a counter \n "
" -Support for Rust error format and improved autoindenting for Rust \n "
" -Work around for bug in make on Windows \n "
" -New commands: \n "
" <ctrl 1> show the current buffer in the other panel (side by side) \n "
" <ctrl 2> show the current buffer in the other panel (swap with other buffer) \n "
" <alt D> list all type definition locations of a particular string ~ if only one jump to it instead \n "
" <alt T> list all type definition locations of the token under the cursor ~ if only one jump to it instead \n "
" -The indenter no longer does anything to multi-line strings such as raw strings. \n "
" -The customization API now has the ability to set the window's title. \n "
" -The customization API has a hook for resolving buffer name conflicts. \n "
" \n "
2017-11-22 21:02:56 +00:00
" New in alpha 4.0.24: \n "
" -Fonts can now be loaded from the system API or from the fonts folder \n "
" -Fonts can now be resized at run time, hinting can be toggled at run time \n "
" -Fonts can now be rendered with any combination of the styles: bold, italic, underline \n "
" (That is provided the font supports the style.) \n "
" -Now font faces can have different sizes simultaneously, or have the different hinting or styling configurations. \n "
" -Lots of new built in commands including: \n "
" <ctrl D> delete the line under the cursor \n "
" <ctrl L> duplicate the line under the cursor \n "
" <alt up> move the line under the cursor up \n "
" <alt down> move the line under the cursor down \n "
" <alt [> select surrounding scope in code file \n "
" <alt ]> select the next scope up in code file \n "
" <alt '> select the next scope down in code file \n "
" <alt -> if a scope is selected, delete it's braces \n "
" <alt j> if a scope is selected, absorb the statement below it into the scope \n "
" <alt x> + 'delete file' close the current buffer and delete it's physical file \n "
" <alt x> + 'rename file' rename the current buffer's physical file and reopen the buffer with the new file name \n "
" <alt x> + 'mkdir' create a new directory \n "
" -The customization API is extended for more explicit font face control. \n "
" -The customization API comes with a parser and generator for generating metadata on built in and custom commands. \n "
2017-07-11 21:53:27 +00:00
" \n "
2017-11-16 23:03:36 +00:00
" New in alpha 4.0.22 and 4.0.23: \n "
2017-11-11 17:23:09 +00:00
" -The rendering layer is cleaned up and faster \n "
" -4coder can now ship with multiple built in command bindings \n "
" New built in binding \" mac-default \" : For the mac version of 4coder - similar to most Mac applications \n "
" -Fullscreen now works on Windows without the '-S' flag \n "
" -Set up a single 4coder project for Windows/Linux/Mac in one command: <alt x> -> \" new project \" \n "
" \n "
" New in alpha 4.0.21: \n "
2017-07-11 21:53:27 +00:00
" -Color schemes are now loaded in theme files from the \" themes \" folder \n "
" -After loading a project <alt h> sets the hot directory to the project directory \n "
" -The flag -L enables a logging system that will collect information in case more information is needed while debugging a problem \n "
" -All command line flags after the special flag --custom are now passed to the custom API start hook \n "
" -The start hook now gets the list of file names that were specified on the command line \n "
" All of the files specified on the command line are loaded before the start hook runs \n "
" -It is now possible to set the hot directory from the custom API \n "
" -On windows the buildsuper scripts are improved to look for vcvarsall.bat in lots of common locations \n "
" \n "
" New in alpha 4.0.20: \n "
" -Option for LAlt + LCtrl = AltGr on Windows is now in config.4coder \n "
" -The 4cpp lexer now has a customizable keyword table, *experimental* expansion of language support to: \n "
" Rust, C#, Java \n "
" Arbitrary keyword customization available in custom code (super users) \n "
" \n "
" New in alpha 4.0.19: \n "
" -Lexer now handles string literal prefixes and is more optimized \n "
" -Fixes for lingering unicode bugs \n "
2017-11-11 17:23:09 +00:00
" -Power users have an experimental new jump to error that keeps correct positions through edits (coming to all tiers soon) \n "
2017-07-11 21:53:27 +00:00
" \n "
" New in alpha 4.0.18: \n "
" -Support for rendering unicode characters \n "
" -<ctrl t> isearch alpha-numeric word under cursor \n "
" -<ctrl Q> query replace alpha-numeric word under cursor \n "
" -<alt b> toggle file bar \n "
" \n "
" New in alpha 4.0.17: \n "
" -New support for extended ascii input. \n "
" -Extended ascii encoded in buffers as utf8. \n "
" -The custom layer now has a 'markers' API for tracking buffer positions across changes. \n "
" \n "
" New in alpha 4.0.16: \n "
" -<alt 2> If the current file is a C++ code file, this opens the matching header. \n " " If the current file is a C++ header, this opens the matching code file. \n "
" -Option to automatically save changes on build in the config file. \n "
" This works for builds triggered by <alt m>. \n "
" -Option in project files to have certain fkey commands save changes. \n "
" \n "
" New in alpha 4.0.15: \n "
" -<ctrl I> find all functions in the current buffer and list them in a jump buffer \n "
" -option to set user name in config.4coder \n "
" The user name is used in <alt t> and <alt y> comment writing commands \n "
" \n "
" New in alpha 4.0.14: \n "
" -Option to have wrap widths automatically adjust based on average view width \n "
" -The 'config.4coder' file can now be placed with the 4ed executable file \n "
" -New options in 'config.4coder' to specify the font and color theme \n "
" -New built in project configuration system \n "
" -New on-save hooks allows custom behavior in the custom layer whenever a file is saved \n "
" -When using code wrapping, any saved file is automatically indented in the text format, this option can be turned off in config.4coder \n "
" \n "
" New in alpha 4.0.12 and 4.0.13: \n "
" -Text files wrap lines at whitespace when possible \n "
" -New code wrapping feature is on by default \n "
" -Introduced a 'config.4coder' for setting several wrapping options: \n "
" enable_code_wrapping: set to false if you want the text like behavior \n "
" default_wrap_width: the wrap width to set in new files \n "
" -<ctrl 2> decrease the current buffer's wrap width \n "
" -<ctrl 3> increase the current buffer's wrap width \n "
" -In the customization layer new settings for the buffer are exposed dealing with wrapping \n "
" -In the customization layer there is a call for setting what keys the GUI should use \n "
" \n "
" New in alpha 4.0.11: \n "
" -The commands for going to next error, previous error, etc now work \n "
" on any buffer with jump locations including *search* \n "
" -4coder now supports proper, borderless, fullscreen with the flag -F \n "
" and fullscreen can be toggled with <control pageup>. \n "
" (This sometimes causes artifacts on the Windows task bar) \n "
" -<alt E> to exit \n "
" -hook on exit for the customization system \n "
" -tokens now exposed in customization system \n "
" -mouse release events in customization system \n "
" \n "
" New in alpha 4.0.10: \n "
" -<ctrl F> list all locations of a string across all open buffers \n "
" -Build now finds build.sh and Makefile on Linux \n "
" -<alt n> goes to the next error if the *compilation* buffer is open \n "
" -<alt N> goes to the previous error \n "
" -<alt M> goes to the first error \n "
" -<alt .> switch to the compilation buffer \n "
" -<alt ,> close the panel viewing the compilation buffer \n "
" -New documentation for the 4coder string library included in 4coder_API.html \n "
" -Low level allocation calls available in custom API \n "
" -Each panel can change font independently. \n "
" Per-buffer fonts are exposed in the custom API. \n "
" \n "
" New in alpha 4.0.9: \n "
" -A scratch buffer is now opened with 4coder automatically \n "
" -A new mouse suppression mode toggled by <F2> \n "
" -Hinting is disabled by default, a -h flag on the command line enables it \n "
" -New 4coder_API.html documentation file provided for the custom layer API \n "
" -Experimental new work-flow for building and jumping to errors \n "
" This system is only for MSVC in the 'power' version as of 4.0.9 \n "
" \n "
" New in alpha 4.0.8: \n "
" -Eliminated the parameter stack \n "
" \n "
" New in alpha 4.0.7: \n "
" -Right click sets the mark \n "
" -Clicks now have key codes so they can have events bound in customizations \n "
" -<alt d> opens a debug view, see more in README.txt \n "
" \n "
" New in alpha 4.0.6: \n "
" -Tied the view scrolling and the list arrow navigation together \n "
" -Scroll bars are now toggleable with <alt s> for show and <alt w> for hide \n "
" \n "
" New in alpha 4.0.5: \n "
" -New indent rule \n "
" -app->buffer_compute_cursor in the customization API \n "
" -f keys are available in the customization system now \n "
" \n "
" New in alpha 4.0.3 and 4.0.4: \n "
" -Scroll bar on files and file lists \n "
" -Arrow navigation in lists \n "
" -A new minimal theme editor \n "
" \n "
" New in alpha 4.0.2: \n "
" -The file count limit is over 8 million now \n "
" -File equality is handled better so renamings (such as 'subst') are safe now \n "
" -This buffer will report events including errors that happen in 4coder \n "
" -Super users can post their own messages here with app->print_message \n "
" -<ctrl e> centers view on cursor; cmdid_center_view in customization API \n "
" -Set font size on command line with -f N, N = 16 by default \n \n " ;
2016-06-29 17:16:08 +00:00
// App Structs
2016-09-22 00:01:12 +00:00
# define DEFAULT_DISPLAY_WIDTH 672
2016-10-25 00:26:52 +00:00
# define DEFAULT_MINIMUM_BASE_DISPLAY_WIDTH 550
2016-09-22 00:01:12 +00:00
2016-09-01 03:06:46 +00:00
internal Available_Input
2017-01-29 00:03:23 +00:00
init_available_input ( Key_Input_Data * keys , Mouse_State * mouse ) {
2016-06-29 17:16:08 +00:00
Available_Input result = { 0 } ;
result . keys = keys ;
result . mouse = mouse ;
return ( result ) ;
}
2017-01-29 00:03:23 +00:00
internal Key_Input_Data
2016-06-29 17:16:08 +00:00
direct_get_key_data ( Available_Input * available ) {
2017-01-29 00:03:23 +00:00
Key_Input_Data result = * available - > keys ;
2016-06-29 17:16:08 +00:00
return ( result ) ;
}
2016-09-01 03:06:46 +00:00
internal Mouse_State
2016-06-29 17:16:08 +00:00
direct_get_mouse_state ( Available_Input * available ) {
Mouse_State result = * available - > mouse ;
return ( result ) ;
}
2017-01-29 00:03:23 +00:00
internal Key_Input_Data
2016-06-29 17:16:08 +00:00
get_key_data ( Available_Input * available ) {
2017-01-29 00:03:23 +00:00
Key_Input_Data result = { 0 } ;
2016-06-29 17:16:08 +00:00
if ( ! available - > records [ Input_AnyKey ] . consumed ) {
result = * available - > keys ;
}
else if ( ! available - > records [ Input_Esc ] . consumed ) {
i32 count = available - > keys - > count ;
2018-03-10 02:06:55 +00:00
for ( i32 i = 0 ; i < count ; + + i ) {
Key_Event_Data key = available - > keys - > keys [ i ] ;
2016-06-29 17:16:08 +00:00
if ( key . keycode = = key_esc ) {
result . count = 1 ;
result . keys [ 0 ] = key ;
break ;
}
}
}
return ( result ) ;
}
2016-09-01 03:06:46 +00:00
internal Mouse_State
2016-06-29 17:16:08 +00:00
get_mouse_state ( Available_Input * available ) {
Mouse_State mouse = * available - > mouse ;
if ( available - > records [ Input_MouseLeftButton ] . consumed ) {
mouse . l = 0 ;
mouse . press_l = 0 ;
mouse . release_l = 0 ;
}
if ( available - > records [ Input_MouseRightButton ] . consumed ) {
mouse . r = 0 ;
mouse . press_r = 0 ;
mouse . release_r = 0 ;
}
if ( available - > records [ Input_MouseWheel ] . consumed ) {
mouse . wheel = 0 ;
}
return ( mouse ) ;
}
2016-09-01 03:06:46 +00:00
internal void
2016-06-29 17:16:08 +00:00
consume_input ( Available_Input * available , i32 input_type , char * consumer ) {
Consumption_Record * record = & available - > records [ input_type ] ;
record - > consumed = 1 ;
if ( consumer ) {
String str = make_fixed_width_string ( record - > consumer ) ;
2016-08-28 04:31:06 +00:00
copy_sc ( & str , consumer ) ;
2016-06-29 17:16:08 +00:00
terminate_with_null ( & str ) ;
}
else {
record - > consumer [ 0 ] = 0 ;
}
}
inline App_Coroutine_State
get_state ( Application_Links * app ) {
App_Coroutine_State state = { 0 } ;
state . co = app - > current_coroutine ;
state . type = app - > type_coroutine ;
return ( state ) ;
}
inline void
restore_state ( Application_Links * app , App_Coroutine_State state ) {
app - > current_coroutine = state . co ;
app - > type_coroutine = state . type ;
}
2017-07-19 20:07:50 +00:00
inline Coroutine_Head *
app_launch_coroutine ( System_Functions * system , Application_Links * app , Coroutine_Type type , Coroutine_Head * co , void * in , void * out ) {
Coroutine_Head * result = 0 ;
2016-06-29 17:16:08 +00:00
App_Coroutine_State prev_state = get_state ( app ) ;
app - > current_coroutine = co ;
app - > type_coroutine = type ;
result = system - > launch_coroutine ( co , in , out ) ;
restore_state ( app , prev_state ) ;
return ( result ) ;
}
2017-07-19 20:07:50 +00:00
inline Coroutine_Head *
app_resume_coroutine ( System_Functions * system , Application_Links * app , Coroutine_Type type , Coroutine_Head * co , void * in , void * out ) {
Coroutine_Head * result = 0 ;
2016-06-29 17:16:08 +00:00
App_Coroutine_State prev_state = get_state ( app ) ;
app - > current_coroutine = co ;
app - > type_coroutine = type ;
result = system - > resume_coroutine ( co , in , out ) ;
restore_state ( app , prev_state ) ;
return ( result ) ;
}
inline void
2018-03-24 21:43:57 +00:00
output_file_append ( System_Functions * system , Models * models , Editing_File * file , String value ) {
2017-11-22 20:05:58 +00:00
if ( ! file - > is_dummy ) {
i32 end = buffer_size ( & file - > state . buffer ) ;
2018-03-24 21:43:57 +00:00
edit_single ( system , models , file ,
end , end , value . str , value . size ) ;
2017-11-22 20:05:58 +00:00
}
2016-06-29 17:16:08 +00:00
}
inline void
2016-07-14 21:44:34 +00:00
do_feedback_message ( System_Functions * system , Models * models , String value , b32 set_to_start = 0 ) {
2016-06-29 17:16:08 +00:00
Editing_File * file = models - > message_buffer ;
2018-03-26 05:19:08 +00:00
if ( file ! = 0 ) {
2018-03-24 21:43:57 +00:00
output_file_append ( system , models , file , value ) ;
2016-07-14 21:44:34 +00:00
i32 pos = 0 ;
if ( ! set_to_start ) {
pos = buffer_size ( & file - > state . buffer ) ;
}
2018-03-24 10:06:45 +00:00
for ( Panel * panel = models - > layout . used_sentinel . next ;
panel ! = & models - > layout . used_sentinel ;
panel = panel - > next ) {
View * view = panel - > view ;
if ( view - > transient . file_data . file ! = file ) {
continue ;
}
view_cursor_move ( system , view , pos ) ;
2016-06-29 17:16:08 +00:00
}
}
}
// Commands
# define USE_MODELS(n) Models *n = command->models
# define USE_VARS(n) App_Vars *n = command->vars
# define USE_FILE(n,v) Editing_File *n = (v)->file_data.file
2017-03-17 17:45:41 +00:00
# define USE_PANEL(n) Panel *n = 0; do{ \
2016-09-21 22:34:19 +00:00
i32 panel_index = command - > models - > layout . active_panel ; \
n = command - > models - > layout . panels + panel_index ; \
2017-03-17 17:45:41 +00:00
} while ( false )
2016-09-21 22:34:19 +00:00
2017-03-17 17:45:41 +00:00
# define USE_VIEW(n) View *n = 0; do{ \
i32 panel_index = command - > models - > layout . active_panel ; \
Panel * __panel__ = command - > models - > layout . panels + panel_index ; \
n = __panel__ - > view ; \
} while ( false )
2016-09-21 22:34:19 +00:00
2018-03-24 10:06:45 +00:00
# define REQ_OPEN_VIEW(n) USE_VIEW(n); if (view_lock_flags(n) != 0) return
2016-06-29 17:16:08 +00:00
2018-03-24 10:06:45 +00:00
# define REQ_FILE(n,v) Editing_File *n = (v)->transient.file_data.file; if (n == 0) return
# define REQ_FILE_HISTORY(n,v) Editing_File *n = (v)->transient.file_data.file; if (n == 0 || n->state.undo.undo.edits == 0) return
2016-06-29 17:16:08 +00:00
# define COMMAND_DECL(n) internal void command_##n(System_Functions *system, Command_Data *command, Command_Binding binding)
internal View *
2017-07-17 23:35:13 +00:00
panel_make_empty ( System_Functions * system , Models * models , Panel * panel ) {
2016-06-29 17:16:08 +00:00
Assert ( panel - > view = = 0 ) ;
2018-03-26 05:19:08 +00:00
View_And_ID new_view = live_set_alloc_view ( & models - > mem . general , & models - > live_set , panel ) ;
2018-03-25 06:43:56 +00:00
view_set_file ( system , models , new_view . view , models - > scratch_buffer ) ;
2018-03-24 10:06:45 +00:00
new_view . view - > transient . map = models - > scratch_buffer - > settings . base_map_id ;
2016-06-29 17:16:08 +00:00
return ( new_view . view ) ;
}
COMMAND_DECL ( null ) {
AllowLocal ( command ) ;
}
2018-03-24 21:43:57 +00:00
internal void
view_undo_redo ( System_Functions * system , Models * models , View * view , Edit_Stack * stack , Edit_Type expected_type ) {
Editing_File * file = view - > transient . file_data . file ;
Assert ( file ! = 0 ) ;
Assert ( view - > transient . edit_pos ! = 0 ) ;
if ( stack - > edit_count > 0 ) {
Edit_Step step = stack - > edits [ stack - > edit_count - 1 ] ;
Assert ( step . type = = expected_type ) ;
edit_historical ( system , models , file , view , stack ,
step , hist_normal ) ;
}
}
2016-06-29 17:16:08 +00:00
COMMAND_DECL ( undo ) {
USE_MODELS ( models ) ;
REQ_OPEN_VIEW ( view ) ;
REQ_FILE_HISTORY ( file , view ) ;
2017-02-26 20:13:06 +00:00
view_undo_redo ( system , models , view , & file - > state . undo . undo , ED_UNDO ) ;
2016-06-29 17:16:08 +00:00
Assert ( file - > state . undo . undo . size > = 0 ) ;
}
COMMAND_DECL ( redo ) {
USE_MODELS ( models ) ;
REQ_OPEN_VIEW ( view ) ;
REQ_FILE_HISTORY ( file , view ) ;
2017-02-26 20:13:06 +00:00
view_undo_redo ( system , models , view , & file - > state . undo . redo , ED_REDO ) ;
2016-06-29 17:16:08 +00:00
Assert ( file - > state . undo . undo . size > = 0 ) ;
}
COMMAND_DECL ( interactive_new ) {
2017-07-17 23:35:13 +00:00
USE_MODELS ( models ) ;
2016-06-29 17:16:08 +00:00
USE_VIEW ( view ) ;
2017-07-17 23:35:13 +00:00
view_show_interactive ( system , view , models , IAct_New , IInt_Sys_File_List , make_lit_string ( " New: " ) ) ;
2016-06-29 17:16:08 +00:00
}
COMMAND_DECL ( interactive_open ) {
2017-07-17 23:35:13 +00:00
USE_MODELS ( models ) ;
2016-06-29 17:16:08 +00:00
USE_VIEW ( view ) ;
2017-07-17 23:35:13 +00:00
view_show_interactive ( system , view , models , IAct_Open , IInt_Sys_File_List , make_lit_string ( " Open: " ) ) ;
2016-06-29 17:16:08 +00:00
}
2017-03-27 22:36:42 +00:00
COMMAND_DECL ( interactive_open_or_new ) {
2017-07-17 23:35:13 +00:00
USE_MODELS ( models ) ;
2017-03-27 22:36:42 +00:00
USE_VIEW ( view ) ;
2017-07-17 23:35:13 +00:00
view_show_interactive ( system , view , models , IAct_OpenOrNew , IInt_Sys_File_List , make_lit_string ( " Open: " ) ) ;
2017-03-27 22:36:42 +00:00
}
2016-06-29 17:16:08 +00:00
// TODO(allen): Improvements to reopen
2017-02-12 06:01:01 +00:00
// - Perform a diff
// - If the diff is not tremendously big, apply the edits.
2016-06-29 17:16:08 +00:00
COMMAND_DECL ( reopen ) {
USE_MODELS ( models ) ;
USE_VIEW ( view ) ;
REQ_FILE ( file , view ) ;
2017-02-12 06:01:01 +00:00
if ( file - > canon . name . str = = 0 ) return ;
2016-06-29 17:16:08 +00:00
2016-08-26 17:52:35 +00:00
if ( file - > canon . name . size ! = 0 ) {
Plat_Handle handle ;
if ( system - > load_handle ( file - > canon . name . str , & handle ) ) {
i32 size = system - > load_size ( handle ) ;
Partition * part = & models - > mem . part ;
Temp_Memory temp = begin_temp_memory ( part ) ;
char * buffer = push_array ( part , char , size ) ;
2018-03-24 10:06:45 +00:00
if ( buffer ! = 0 ) {
2016-08-26 17:52:35 +00:00
if ( system - > load_file ( handle , buffer , size ) ) {
2016-11-05 02:59:35 +00:00
system - > load_close ( handle ) ;
2016-08-26 17:52:35 +00:00
General_Memory * general = & models - > mem . general ;
File_Edit_Positions edit_poss [ 16 ] ;
2017-03-23 19:15:33 +00:00
int32_t line_number [ 16 ] ;
int32_t column_number [ 16 ] ;
2016-08-26 17:52:35 +00:00
View * vptrs [ 16 ] ;
i32 vptr_count = 0 ;
2018-03-24 10:06:45 +00:00
for ( Panel * panel = models - > layout . used_sentinel . next ;
panel ! = & models - > layout . used_sentinel ;
panel = panel - > next ) {
View * view = panel - > view ;
if ( view - > transient . file_data . file ! = file ) {
continue ;
}
vptrs [ vptr_count ] = view ;
edit_poss [ vptr_count ] = view - > transient . edit_pos [ 0 ] ;
line_number [ vptr_count ] = view - > transient . edit_pos [ 0 ] . cursor . line ;
column_number [ vptr_count ] = view - > transient . edit_pos [ 0 ] . cursor . character ;
view - > transient . edit_pos = 0 ;
2016-08-26 17:52:35 +00:00
+ + vptr_count ;
}
2018-05-07 02:47:22 +00:00
file_free ( system , & models - > app_links , general , file ) ;
2018-03-25 06:43:56 +00:00
init_normal_file ( system , models , buffer , size , file ) ;
2016-08-26 17:52:35 +00:00
2016-09-13 19:56:14 +00:00
for ( i32 i = 0 ; i < vptr_count ; + + i ) {
2018-03-25 06:43:56 +00:00
view_set_file ( system , models , vptrs [ i ] , file ) ;
2016-09-13 19:56:14 +00:00
2017-03-23 19:15:33 +00:00
int32_t line = line_number [ i ] ;
int32_t character = column_number [ i ] ;
2016-09-13 19:56:14 +00:00
2018-03-24 10:06:45 +00:00
* vptrs [ i ] - > transient . edit_pos = edit_poss [ i ] ;
Full_Cursor cursor = file_compute_cursor ( system , file , seek_line_char ( line , character ) , 0 ) ;
2016-09-13 19:56:14 +00:00
2017-03-12 01:20:24 +00:00
view_set_cursor ( vptrs [ i ] , cursor , true , file - > settings . unwrapped_lines ) ;
2016-08-26 17:52:35 +00:00
}
2016-08-24 23:01:33 +00:00
}
2016-11-05 02:59:35 +00:00
else {
system - > load_close ( handle ) ;
}
}
else {
system - > load_close ( handle ) ;
2016-07-06 22:04:31 +00:00
}
2016-08-26 17:52:35 +00:00
end_temp_memory ( temp ) ;
2016-06-29 17:16:08 +00:00
}
}
}
COMMAND_DECL ( save ) {
USE_MODELS ( models ) ;
USE_VIEW ( view ) ;
REQ_FILE ( file , view ) ;
2016-08-26 21:30:08 +00:00
if ( ! file - > is_dummy & & file_is_ready ( file ) & & buffer_can_save ( file ) ) {
2016-12-26 22:49:01 +00:00
save_file ( system , models , file ) ;
2016-06-29 17:16:08 +00:00
}
}
COMMAND_DECL ( interactive_switch_buffer ) {
2017-07-17 23:35:13 +00:00
USE_MODELS ( models ) ;
2016-06-29 17:16:08 +00:00
USE_VIEW ( view ) ;
2017-07-17 23:35:13 +00:00
view_show_interactive ( system , view , models , IAct_Switch , IInt_Live_File_List , make_lit_string ( " Switch Buffer: " ) ) ;
2016-06-29 17:16:08 +00:00
}
COMMAND_DECL ( interactive_kill_buffer ) {
2017-07-17 23:35:13 +00:00
USE_MODELS ( models ) ;
2016-06-29 17:16:08 +00:00
USE_VIEW ( view ) ;
2017-07-17 23:35:13 +00:00
view_show_interactive ( system , view , models , IAct_Kill , IInt_Live_File_List , make_lit_string ( " Kill Buffer: " ) ) ;
2016-06-29 17:16:08 +00:00
}
COMMAND_DECL ( kill_buffer ) {
USE_MODELS ( models ) ;
USE_VIEW ( view ) ;
REQ_FILE ( file , view ) ;
2018-03-25 06:43:56 +00:00
if ( interactive_try_kill_file ( system , models , file ) = = TryKill_NeedDialogue ) {
interactive_begin_sure_to_kill ( system , view , models , file ) ;
}
2016-06-29 17:16:08 +00:00
}
internal void
2017-05-19 23:55:50 +00:00
case_change_range ( System_Functions * system , Models * models , View * view , Editing_File * file , u8 a , u8 z , u8 char_delta ) {
2017-01-23 06:19:43 +00:00
Range range = { 0 } ;
2018-03-24 10:06:45 +00:00
range . min = Min ( view - > transient . edit_pos - > cursor . pos , view - > transient . edit_pos - > mark ) ;
range . max = Max ( view - > transient . edit_pos - > cursor . pos , view - > transient . edit_pos - > mark ) ;
2016-06-29 17:16:08 +00:00
if ( range . start < range . end ) {
Edit_Step step = { } ;
step . type = ED_NORMAL ;
step . edit . start = range . start ;
step . edit . end = range . end ;
step . edit . len = range . end - range . start ;
2016-10-22 15:30:25 +00:00
if ( file - > state . still_lexing ) {
2016-06-29 17:16:08 +00:00
system - > cancel_job ( BACKGROUND_THREADS , file - > state . lex_job ) ;
2016-10-22 15:30:25 +00:00
}
2016-06-29 17:16:08 +00:00
2017-05-19 23:55:50 +00:00
file_update_history_before_edit ( & models - > mem , file , step , 0 , hist_normal ) ;
2016-06-29 17:16:08 +00:00
u8 * data = ( u8 * ) file - > state . buffer . data ;
2017-03-23 19:15:33 +00:00
for ( i32 i = range . start ; i < range . end ; + + i ) {
2016-06-29 17:16:08 +00:00
if ( data [ i ] > = a & & data [ i ] < = z ) {
data [ i ] + = char_delta ;
}
}
2017-01-14 03:01:35 +00:00
if ( file - > state . token_array . tokens ) {
2017-05-19 23:55:50 +00:00
file_relex_parallel ( system , models , file , range . start , range . end , 0 ) ;
2017-01-14 03:01:35 +00:00
}
2016-06-29 17:16:08 +00:00
}
}
COMMAND_DECL ( open_color_tweaker ) {
USE_VIEW ( view ) ;
2018-03-25 06:43:56 +00:00
view - > transient . map = mapid_ui ;
view - > transient . showing_ui = VUI_Theme ;
view - > transient . color_mode = CV_Mode_Library ;
view - > transient . color = super_color_create ( 0xFF000000 ) ;
view - > transient . current_color_editing = 0 ;
view - > transient . changed_context_in_step = true ;
2016-06-29 17:16:08 +00:00
}
COMMAND_DECL ( user_callback ) {
USE_MODELS ( models ) ;
2018-03-25 06:43:56 +00:00
if ( binding . custom ! = 0 ) {
binding . custom ( & models - > app_links ) ;
}
2016-06-29 17:16:08 +00:00
}
2017-11-08 18:24:30 +00:00
global Command_Function * command_table [ cmdid_count ] ;
SCROLL_RULE_SIG ( fallback_scroll_rule ) {
b32 result = false ;
if ( target_x ! = * scroll_x ) {
* scroll_x = target_x ;
result = true ;
}
if ( target_y ! = * scroll_y ) {
* scroll_y = target_y ;
result = true ;
}
return ( result ) ;
}
2017-11-08 21:28:44 +00:00
# define DEFAULT_MAP_SIZE 10
# define DEFAULT_UI_MAP_SIZE 32
2017-11-08 18:24:30 +00:00
internal void
setup_ui_commands ( Command_Map * commands , Partition * part , i32 parent ) {
2017-11-08 21:28:44 +00:00
map_init ( commands , part , DEFAULT_UI_MAP_SIZE , parent ) ;
2017-11-08 18:24:30 +00:00
// TODO(allen): This is hacky, when the new UI stuff happens, let's fix it,
// and by that I mean actually fix it, don't just say you fixed it with
// something stupid again.
u8 mdfr_array [ ] = { MDFR_NONE , MDFR_SHIFT , MDFR_CTRL , MDFR_SHIFT | MDFR_CTRL } ;
for ( i32 i = 0 ; i < 4 ; + + i ) {
u8 mdfr = mdfr_array [ i ] ;
map_add ( commands , key_left , mdfr , command_null ) ;
map_add ( commands , key_right , mdfr , command_null ) ;
map_add ( commands , key_up , mdfr , command_null ) ;
map_add ( commands , key_down , mdfr , command_null ) ;
map_add ( commands , key_back , mdfr , command_null ) ;
}
}
internal void
setup_file_commands ( Command_Map * commands , Partition * part , i32 parent ) {
2017-11-08 21:28:44 +00:00
map_init ( commands , part , DEFAULT_MAP_SIZE , parent ) ;
2017-11-08 18:24:30 +00:00
}
internal void
setup_top_commands ( Command_Map * commands , Partition * part , i32 parent ) {
2017-11-08 21:28:44 +00:00
map_init ( commands , part , DEFAULT_MAP_SIZE , parent ) ;
2017-11-08 18:24:30 +00:00
}
internal b32
interpret_binding_buffer ( Models * models , void * buffer , i32 size ) {
b32 result = true ;
2017-11-08 21:28:44 +00:00
General_Memory * gen = & models - > mem . general ;
2017-11-08 18:24:30 +00:00
Partition * part = & models - > mem . part ;
2017-11-08 21:28:44 +00:00
Temp_Memory temp = begin_temp_memory ( part ) ;
Partition local_part = { 0 } ;
2017-11-08 18:24:30 +00:00
Mapping new_mapping = { 0 } ;
models - > scroll_rule = fallback_scroll_rule ;
models - > hook_open_file = 0 ;
models - > hook_new_file = 0 ;
models - > hook_save_file = 0 ;
models - > hook_end_file = 0 ;
models - > command_caller = 0 ;
models - > input_filter = 0 ;
b32 did_top = false ;
b32 did_file = false ;
Command_Map * map_ptr = 0 ;
2017-11-08 21:28:44 +00:00
Binding_Unit * unit = ( Binding_Unit * ) buffer ;
2017-11-08 18:24:30 +00:00
if ( unit - > type = = unit_header & & unit - > header . error = = 0 ) {
Binding_Unit * end = unit + unit - > header . total_size ;
i32 user_map_count = unit - > header . user_map_count ;
2017-11-08 21:28:44 +00:00
new_mapping . user_map_count = user_map_count ;
2017-11-08 18:24:30 +00:00
2017-11-08 21:28:44 +00:00
// Initialize Table and User Maps in Temp Buffer
2017-11-08 18:24:30 +00:00
new_mapping . map_id_table = push_array ( part , i32 , user_map_count ) ;
memset ( new_mapping . map_id_table , - 1 , user_map_count * sizeof ( i32 ) ) ;
new_mapping . user_maps = push_array ( part , Command_Map , user_map_count ) ;
2017-11-09 00:12:14 +00:00
memset ( new_mapping . user_maps , 0 , user_map_count * sizeof ( Command_Map ) ) ;
2017-11-08 18:24:30 +00:00
2017-11-08 21:28:44 +00:00
// Find the Size of Each Map
2017-11-08 18:24:30 +00:00
for ( + + unit ; unit < end ; + + unit ) {
switch ( unit - > type ) {
case unit_map_begin :
{
i32 mapid = unit - > map_begin . mapid ;
2017-11-08 21:28:44 +00:00
if ( mapid = = mapid_ui | | mapid = = mapid_nomap ) {
break ;
}
else if ( mapid = = mapid_global ) {
did_top = true ;
}
else if ( mapid = = mapid_file ) {
did_file = true ;
}
Command_Map * map = get_or_add_map ( & new_mapping , mapid ) ;
i32 count = map - > count ;
i32 new_count = 0 ;
2017-11-08 18:24:30 +00:00
if ( unit - > map_begin . replace ) {
2017-11-08 21:28:44 +00:00
map - > real_beginning = unit ;
new_count = unit - > map_begin . bind_count ;
2017-11-08 18:24:30 +00:00
}
else {
2017-11-08 21:28:44 +00:00
if ( map - > real_beginning = = 0 ) {
map - > real_beginning = unit ;
}
new_count = unit - > map_begin . bind_count + count ;
}
map - > count = new_count ;
if ( map - > max < new_count ) {
map - > max = new_count ;
2017-11-08 18:24:30 +00:00
}
} break ;
}
}
2017-11-08 21:28:44 +00:00
// Add up the Map Counts
i32 count_global = DEFAULT_MAP_SIZE ;
if ( did_top ) {
count_global = clamp_bottom ( 6 , new_mapping . map_top . count * 3 / 2 ) ;
}
i32 count_file = DEFAULT_MAP_SIZE ;
if ( did_file ) {
count_file = clamp_bottom ( 6 , new_mapping . map_file . count * 3 / 2 ) ;
}
i32 count_ui = DEFAULT_UI_MAP_SIZE ;
i32 count_user = 0 ;
for ( i32 i = 0 ; i < user_map_count ; + + i ) {
Command_Map * map = & new_mapping . user_maps [ i ] ;
count_user + = clamp_bottom ( 6 , map - > max * 3 / 2 ) ;
}
i32 binding_memsize = ( count_global + count_file + count_ui + count_user ) * sizeof ( Command_Binding ) ;
// Allocate Needed Memory
i32 map_id_table_memsize = user_map_count * sizeof ( i32 ) ;
i32 user_maps_memsize = user_map_count * sizeof ( Command_Map ) ;
i32 map_id_table_rounded_memsize = l_round_up_i32 ( map_id_table_memsize , 8 ) ;
i32 user_maps_rounded_memsize = l_round_up_i32 ( user_maps_memsize , 8 ) ;
i32 binding_rounded_memsize = l_round_up_i32 ( binding_memsize , 8 ) ;
i32 needed_memsize = map_id_table_rounded_memsize + user_maps_rounded_memsize + binding_rounded_memsize ;
new_mapping . memory = general_memory_allocate ( gen , needed_memsize ) ;
local_part = make_part ( new_mapping . memory , needed_memsize ) ;
// Move ID Table Memory and Pointer
i32 * old_table = new_mapping . map_id_table ;
new_mapping . map_id_table = push_array ( & local_part , i32 , user_map_count ) ;
memmove ( new_mapping . map_id_table , old_table , map_id_table_memsize ) ;
// Move User Maps Memory and Pointer
Command_Map * old_maps = new_mapping . user_maps ;
new_mapping . user_maps = push_array ( & local_part , Command_Map , user_map_count ) ;
memmove ( new_mapping . user_maps , old_maps , user_maps_memsize ) ;
// Fill in Command Maps
unit = ( Binding_Unit * ) buffer ;
2017-11-08 18:24:30 +00:00
for ( + + unit ; unit < end ; + + unit ) {
switch ( unit - > type ) {
case unit_map_begin :
{
i32 mapid = unit - > map_begin . mapid ;
2017-11-08 21:28:44 +00:00
if ( mapid = = mapid_ui | | mapid = = mapid_nomap ) {
2017-11-08 18:24:30 +00:00
map_ptr = 0 ;
2017-11-08 21:28:44 +00:00
break ;
2017-11-08 18:24:30 +00:00
}
2017-11-08 21:28:44 +00:00
Command_Map * map = get_or_add_map ( & new_mapping , mapid ) ;
if ( unit > = map - > real_beginning ) {
if ( mapid = = mapid_global ) {
map_ptr = & new_mapping . map_top ;
}
else if ( mapid = = mapid_file ) {
map_ptr = & new_mapping . map_file ;
}
else if ( mapid < mapid_global ) {
i32 index = get_or_add_map_index ( & new_mapping , mapid ) ;
Assert ( index < user_map_count ) ;
map_ptr = & new_mapping . user_maps [ index ] ;
}
else {
map_ptr = 0 ;
break ;
}
Assert ( map_ptr ! = 0 ) ;
// NOTE(allen): Map can begin multiple times, only alloc and clear when we first see it.
if ( map_ptr - > commands = = 0 ) {
i32 count = map - > max ;
i32 table_max = clamp_bottom ( 6 , count * 3 / 2 ) ;
map_init ( map_ptr , & local_part , table_max , mapid_global ) ;
}
2017-11-08 18:24:30 +00:00
}
} break ;
case unit_inherit :
2017-11-08 21:28:44 +00:00
{
if ( map_ptr ! = 0 ) {
map_ptr - > parent = unit - > map_inherit . mapid ;
2017-11-08 18:24:30 +00:00
}
} break ;
case unit_binding :
2017-11-08 21:28:44 +00:00
{
if ( map_ptr ! = 0 ) {
Command_Function * func = 0 ;
2017-11-09 01:19:55 +00:00
if ( unit - > binding . command_id < cmdid_count ) {
2017-11-08 21:28:44 +00:00
func = command_table [ unit - > binding . command_id ] ;
2017-11-09 00:12:14 +00:00
}
if ( func ! = 0 ) {
2017-11-08 21:28:44 +00:00
if ( unit - > binding . code = = 0 ) {
u32 index = 0 ;
if ( map_get_modifiers_hash ( unit - > binding . modifiers , & index ) ) {
map_ptr - > vanilla_keyboard_default [ index ] . function = func ;
map_ptr - > vanilla_keyboard_default [ index ] . custom_id = unit - > binding . command_id ;
}
}
else {
map_add ( map_ptr , unit - > binding . code , unit - > binding . modifiers , func , unit - > binding . command_id ) ;
2017-11-08 18:24:30 +00:00
}
}
}
} break ;
case unit_callback :
2017-11-08 21:28:44 +00:00
{
if ( map_ptr ! = 0 ) {
Command_Function * func = command_user_callback ;
Custom_Command_Function * custom = unit - > callback . func ;
2017-11-09 00:12:14 +00:00
if ( func ! = 0 ) {
2017-11-08 21:28:44 +00:00
if ( unit - > callback . code = = 0 ) {
u32 index = 0 ;
if ( map_get_modifiers_hash ( unit - > binding . modifiers , & index ) ) {
map_ptr - > vanilla_keyboard_default [ index ] . function = func ;
map_ptr - > vanilla_keyboard_default [ index ] . custom = custom ;
}
}
else {
map_add ( map_ptr , unit - > callback . code , unit - > callback . modifiers , func , custom ) ;
2017-11-08 18:24:30 +00:00
}
}
}
} break ;
case unit_hook :
{
i32 hook_id = unit - > hook . hook_id ;
if ( hook_id > = 0 ) {
if ( hook_id < hook_type_count ) {
models - > hooks [ hook_id ] = ( Hook_Function * ) unit - > hook . func ;
}
else {
switch ( hook_id ) {
case special_hook_open_file :
{
models - > hook_open_file = ( Open_File_Hook_Function * ) unit - > hook . func ;
} break ;
case special_hook_new_file :
{
models - > hook_new_file = ( Open_File_Hook_Function * ) unit - > hook . func ;
} break ;
case special_hook_save_file :
{
models - > hook_save_file = ( Open_File_Hook_Function * ) unit - > hook . func ;
} break ;
case special_hook_end_file :
{
models - > hook_end_file = ( Open_File_Hook_Function * ) unit - > hook . func ;
} break ;
case special_hook_command_caller :
{
models - > command_caller = ( Command_Caller_Hook_Function * ) unit - > hook . func ;
} break ;
case special_hook_scroll_rule :
{
models - > scroll_rule = ( Scroll_Rule_Function * ) unit - > hook . func ;
} break ;
2017-11-30 23:25:49 +00:00
case special_hook_buffer_name_resolver :
{
models - > buffer_name_resolver = ( Buffer_Name_Resolver_Function * ) unit - > hook . func ;
} break ;
2017-11-08 18:24:30 +00:00
case special_hook_input_filter :
{
models - > input_filter = ( Input_Filter_Function * ) unit - > hook . func ;
} break ;
case special_hook_start :
{
models - > hook_start = ( Start_Hook_Function * ) unit - > hook . func ;
} break ;
}
}
}
} break ;
}
}
2017-11-08 21:28:44 +00:00
if ( ! did_top ) {
setup_top_commands ( & new_mapping . map_top , & local_part , mapid_global ) ;
}
if ( ! did_file ) {
setup_file_commands ( & new_mapping . map_file , & local_part , mapid_global ) ;
}
setup_ui_commands ( & new_mapping . map_ui , & local_part , mapid_global ) ;
2017-11-08 18:24:30 +00:00
}
2017-11-08 21:28:44 +00:00
else {
// TODO(allen): Probably should have some recovery plan here.
InvalidCodePath ;
2017-11-08 18:24:30 +00:00
}
2017-11-08 21:28:44 +00:00
Mapping old_mapping = models - > mapping ;
if ( old_mapping . memory ! = 0 ) {
// TODO(allen): Do I need to explicity work on recovering the old ids of buffers?
general_memory_free ( gen , old_mapping . memory ) ;
2017-11-08 18:24:30 +00:00
}
models - > mapping = new_mapping ;
2017-11-08 21:28:44 +00:00
end_temp_memory ( temp ) ;
2017-11-08 18:24:30 +00:00
return ( result ) ;
}
2016-06-29 17:16:08 +00:00
# include "4ed_api_implementation.cpp"
internal void
2017-07-19 20:07:50 +00:00
command_caller ( Coroutine_Head * coroutine ) {
2016-06-29 17:16:08 +00:00
Command_In * cmd_in = ( Command_In * ) coroutine - > in ;
2016-09-21 22:34:19 +00:00
Command_Data * command = cmd_in - > cmd ;
Models * models = command - > models ;
USE_VIEW ( view ) ;
2016-06-29 17:16:08 +00:00
2016-06-29 18:23:14 +00:00
if ( models - > command_caller ) {
Generic_Command generic ;
if ( cmd_in - > bind . function = = command_user_callback ) {
generic . command = cmd_in - > bind . custom ;
}
else {
generic . cmdid = ( Command_ID ) cmd_in - > bind . custom_id ;
}
2017-03-29 20:50:29 +00:00
models - > command_caller ( & models - > app_links , generic ) ;
2016-06-29 18:23:14 +00:00
}
else {
2016-09-21 22:34:19 +00:00
cmd_in - > bind . function ( command - > system , command , cmd_in - > bind ) ;
2016-06-29 18:23:14 +00:00
}
2016-06-29 17:16:08 +00:00
}
internal void
2016-08-29 01:03:26 +00:00
app_links_init ( System_Functions * system , Application_Links * app_links , void * data , i32 size ) {
2016-06-29 17:16:08 +00:00
app_links - > memory = data ;
app_links - > memory_size = size ;
FillAppLinksAPI ( app_links ) ;
app_links - > current_coroutine = 0 ;
app_links - > system_links = system ;
}
internal void
setup_command_table ( ) {
# define SET(n) command_table[cmdid_##n] = command_##n
SET ( null ) ;
SET ( undo ) ;
SET ( redo ) ;
SET ( interactive_new ) ;
SET ( interactive_open ) ;
2017-03-27 22:36:42 +00:00
SET ( interactive_open_or_new ) ;
2016-06-29 17:16:08 +00:00
SET ( interactive_switch_buffer ) ;
SET ( interactive_kill_buffer ) ;
2016-07-05 13:11:26 +00:00
SET ( reopen ) ;
SET ( save ) ;
2016-06-29 17:16:08 +00:00
SET ( kill_buffer ) ;
SET ( open_color_tweaker ) ;
# undef SET
}
// App Functions
2018-03-10 02:06:55 +00:00
internal void
app_recording_emit_events ( System_Functions * system , Models * models , Simulation_Event * new_events , i32 new_event_count ) {
if ( models - > recorded_event_count + new_event_count > models - > recorded_event_max ) {
i32 new_max = 2 * ( models - > recorded_event_count + new_event_count ) ;
void * new_ptr = system - > memory_allocate ( sizeof ( Simulation_Event ) * new_max ) ;
memmove ( new_ptr , models - > recorded_events , sizeof ( * models - > recorded_events ) * models - > recorded_event_count ) ;
system - > memory_free ( models - > recorded_events , sizeof ( * models - > recorded_events ) * models - > recorded_event_max ) ;
models - > recorded_events = ( Simulation_Event * ) new_ptr ;
models - > recorded_event_max = new_max ;
}
memcpy ( models - > recorded_events + models - > recorded_event_count , new_events , sizeof ( * new_events ) * new_event_count ) ;
models - > recorded_event_count + = new_event_count ;
}
2016-06-29 17:16:08 +00:00
internal void
2017-06-16 23:10:50 +00:00
app_hardcode_default_style ( Models * models ) {
2016-07-01 05:42:19 +00:00
Interactive_Style file_info_style = { 0 } ;
Style * styles = models - > styles . styles ;
Style * style = styles + 1 ;
2016-06-29 17:16:08 +00:00
/////////////////
style_set_name ( style , make_lit_string ( " 4coder " ) ) ;
style - > main . back_color = 0xFF0C0C0C ;
style - > main . margin_color = 0xFF181818 ;
style - > main . margin_hover_color = 0xFF252525 ;
style - > main . margin_active_color = 0xFF323232 ;
2017-04-23 02:11:03 +00:00
style - > main . list_item_color = style - > main . margin_color ;
style - > main . list_item_hover_color = style - > main . margin_hover_color ;
style - > main . list_item_active_color = style - > main . margin_active_color ;
2016-06-29 17:16:08 +00:00
style - > main . cursor_color = 0xFF00EE00 ;
style - > main . highlight_color = 0xFFDDEE00 ;
style - > main . mark_color = 0xFF494949 ;
style - > main . default_color = 0xFF90B080 ;
style - > main . at_cursor_color = style - > main . back_color ;
style - > main . at_highlight_color = 0xFFFF44DD ;
style - > main . comment_color = 0xFF2090F0 ;
style - > main . keyword_color = 0xFFD08F20 ;
style - > main . str_constant_color = 0xFF50FF30 ;
style - > main . char_constant_color = style - > main . str_constant_color ;
style - > main . int_constant_color = style - > main . str_constant_color ;
style - > main . float_constant_color = style - > main . str_constant_color ;
style - > main . bool_constant_color = style - > main . str_constant_color ;
style - > main . include_color = style - > main . str_constant_color ;
style - > main . preproc_color = style - > main . default_color ;
style - > main . special_character_color = 0xFFFF0000 ;
2016-10-14 21:21:17 +00:00
style - > main . ghost_character_color = color_blend ( style - > main . default_color , 0.5f , style - > main . back_color ) ;
2016-06-29 17:16:08 +00:00
style - > main . paste_color = 0xFFDDEE00 ;
style - > main . undo_color = 0xFF00DDEE ;
style - > main . highlight_junk_color = 0xff3a0000 ;
style - > main . highlight_white_color = 0xff003a3a ;
file_info_style . bar_color = 0xFF888888 ;
file_info_style . bar_active_color = 0xFF666666 ;
file_info_style . base_color = 0xFF000000 ;
2016-07-02 22:59:16 +00:00
file_info_style . pop1_color = 0xFF3C57DC ;
2016-06-29 17:16:08 +00:00
file_info_style . pop2_color = 0xFFFF0000 ;
style - > main . file_info_style = file_info_style ;
+ + style ;
2016-09-13 01:58:32 +00:00
/////////////////
2016-06-29 17:16:08 +00:00
models - > styles . count = ( i32 ) ( style - styles ) ;
models - > styles . max = ArrayCount ( models - > styles . styles ) ;
2018-03-24 21:43:57 +00:00
style_copy ( & models - > styles . styles [ 0 ] , models - > styles . styles + 1 ) ;
2016-06-29 17:16:08 +00:00
}
2017-06-23 23:07:18 +00:00
internal void
2017-07-19 20:07:50 +00:00
init_command_line_settings ( App_Settings * settings , Plat_Settings * plat_settings , i32 argc , char * * argv ) {
2016-09-19 02:49:25 +00:00
char * arg = 0 ;
Command_Line_Mode mode = CLMode_App ;
2016-06-29 17:16:08 +00:00
Command_Line_Action action = CLAct_Nothing ;
2017-06-12 17:40:54 +00:00
b32 strict = false ;
2016-06-29 17:16:08 +00:00
settings - > init_files_max = ArrayCount ( settings - > init_files ) ;
2017-07-19 20:07:50 +00:00
for ( i32 i = 1 ; i < = argc ; + + i ) {
if ( i = = argc ) {
2016-09-19 02:49:25 +00:00
arg = " " ;
}
else {
2017-07-19 20:07:50 +00:00
arg = argv [ i ] ;
2016-09-19 02:49:25 +00:00
}
if ( arg [ 0 ] = = ' - ' & & arg [ 1 ] = = ' - ' ) {
char * long_arg_name = arg + 2 ;
if ( match_cc ( long_arg_name , " custom " ) ) {
mode = CLMode_Custom ;
continue ;
}
}
switch ( mode ) {
case CLMode_App :
2016-06-29 17:16:08 +00:00
{
2016-09-19 02:49:25 +00:00
switch ( action ) {
case CLAct_Nothing :
{
if ( arg [ 0 ] = = ' - ' ) {
action = CLAct_Ignore ;
switch ( arg [ 1 ] ) {
2017-06-12 17:40:54 +00:00
case ' d ' : action = CLAct_CustomDLL ; strict = false ; break ;
case ' D ' : action = CLAct_CustomDLL ; strict = true ; break ;
2016-09-19 02:49:25 +00:00
case ' i ' : action = CLAct_InitialFilePosition ; break ;
case ' w ' : action = CLAct_WindowSize ; break ;
case ' W ' : action = CLAct_WindowMaximize ; break ;
case ' p ' : action = CLAct_WindowPosition ; break ;
case ' F ' : action = CLAct_WindowFullscreen ; break ;
case ' f ' : action = CLAct_FontSize ; break ;
2017-06-12 17:40:54 +00:00
case ' h ' : action = CLAct_FontUseHinting ; - - i ; break ;
2017-07-03 15:43:51 +00:00
case ' l ' : action = CLAct_LogStdout ; - - i ; break ;
case ' L ' : action = CLAct_LogFile ; - - i ; break ;
2018-03-03 07:46:44 +00:00
2018-03-03 20:22:24 +00:00
case ' T ' : action = CLAct_TestInput ; break ;
2018-03-10 02:06:55 +00:00
case ' R ' : action = CLAct_RecordInput ; break ;
2016-09-19 02:49:25 +00:00
}
}
else if ( arg [ 0 ] ! = 0 ) {
if ( settings - > init_files_count < settings - > init_files_max ) {
2017-06-12 17:40:54 +00:00
i32 index = settings - > init_files_count + + ;
2016-09-19 02:49:25 +00:00
settings - > init_files [ index ] = arg ;
}
}
} break ;
2016-06-29 17:16:08 +00:00
2016-09-19 02:49:25 +00:00
case CLAct_CustomDLL :
{
2017-03-29 16:32:06 +00:00
plat_settings - > custom_dll_is_strict = ( b8 ) strict ;
2017-07-19 20:07:50 +00:00
if ( i < argc ) {
plat_settings - > custom_dll = argv [ i ] ;
2016-09-19 02:49:25 +00:00
}
action = CLAct_Nothing ;
} break ;
case CLAct_InitialFilePosition :
{
2017-07-19 20:07:50 +00:00
if ( i < argc ) {
settings - > initial_line = str_to_int_c ( argv [ i ] ) ;
2016-09-19 02:49:25 +00:00
}
action = CLAct_Nothing ;
} break ;
case CLAct_WindowSize :
{
2017-07-19 20:07:50 +00:00
if ( i + 1 < argc ) {
2017-03-29 16:32:06 +00:00
plat_settings - > set_window_size = true ;
2017-06-17 23:41:27 +00:00
2017-07-19 20:07:50 +00:00
i32 w = str_to_int_c ( argv [ i ] ) ;
i32 h = str_to_int_c ( argv [ i + 1 ] ) ;
2017-06-17 23:41:27 +00:00
if ( w > 0 ) {
plat_settings - > window_w = w ;
}
if ( h > 0 ) {
plat_settings - > window_h = h ;
}
2016-09-19 02:49:25 +00:00
+ + i ;
}
action = CLAct_Nothing ;
} break ;
case CLAct_WindowMaximize :
{
- - i ;
2017-03-29 16:32:06 +00:00
plat_settings - > maximize_window = true ;
2016-09-19 02:49:25 +00:00
action = CLAct_Nothing ;
} break ;
case CLAct_WindowPosition :
{
2017-07-19 20:07:50 +00:00
if ( i + 1 < argc ) {
2017-03-29 16:32:06 +00:00
plat_settings - > set_window_pos = true ;
2017-06-17 23:41:27 +00:00
2017-07-19 20:07:50 +00:00
i32 x = str_to_int_c ( argv [ i ] ) ;
i32 y = str_to_int_c ( argv [ i + 1 ] ) ;
2017-06-17 23:41:27 +00:00
if ( x > 0 ) {
plat_settings - > window_x = x ;
}
if ( y > 0 ) {
plat_settings - > window_y = y ;
}
2016-09-19 02:49:25 +00:00
+ + i ;
}
action = CLAct_Nothing ;
} break ;
case CLAct_WindowFullscreen :
{
- - i ;
2017-03-29 16:32:06 +00:00
plat_settings - > fullscreen_window = true ;
2016-09-19 02:49:25 +00:00
action = CLAct_Nothing ;
} break ;
case CLAct_FontSize :
{
2017-07-19 20:07:50 +00:00
if ( i < argc ) {
plat_settings - > font_size = str_to_int_c ( argv [ i ] ) ;
2017-11-20 23:31:57 +00:00
settings - > font_size = plat_settings - > font_size ;
2016-09-19 02:49:25 +00:00
}
action = CLAct_Nothing ;
} break ;
2017-03-29 16:32:06 +00:00
case CLAct_FontUseHinting :
2016-09-19 02:49:25 +00:00
{
2017-03-29 16:32:06 +00:00
plat_settings - > use_hinting = true ;
2017-11-20 23:31:57 +00:00
settings - > use_hinting = plat_settings - > use_hinting ;
2016-09-19 02:49:25 +00:00
action = CLAct_Nothing ;
} break ;
2017-06-12 17:40:54 +00:00
2017-07-03 15:43:51 +00:00
case CLAct_LogStdout :
2017-06-12 17:40:54 +00:00
{
2017-07-03 15:43:51 +00:00
plat_settings - > use_log = LogTo_Stdout ;
action = CLAct_Nothing ;
} break ;
case CLAct_LogFile :
{
plat_settings - > use_log = LogTo_LogFile ;
2017-06-12 17:40:54 +00:00
action = CLAct_Nothing ;
} break ;
2018-03-03 07:46:44 +00:00
case CLAct_TestInput :
{
2018-03-03 20:22:24 +00:00
if ( i < argc ) {
plat_settings - > use_test_input = true ;
plat_settings - > test_input = argv [ i ] ;
}
2018-03-03 07:46:44 +00:00
action = CLAct_Nothing ;
} break ;
2018-03-10 02:06:55 +00:00
case CLAct_RecordInput :
{
if ( i < argc ) {
settings - > make_input_recording = true ;
settings - > input_recording_output_file = argv [ i ] ;
}
action = CLAct_Nothing ;
} break ;
2016-06-29 17:16:08 +00:00
}
} break ;
2016-07-03 22:29:07 +00:00
2016-09-19 02:49:25 +00:00
case CLMode_Custom :
2016-07-03 22:29:07 +00:00
{
2017-07-19 20:07:50 +00:00
settings - > custom_flags = argv + i ;
settings - > custom_flags_count = argc - i ;
i = argc ;
2017-06-23 23:07:18 +00:00
mode = CLMode_App ;
2016-07-03 22:29:07 +00:00
} break ;
2016-06-29 17:16:08 +00:00
}
}
}
internal App_Vars *
2016-10-22 15:30:25 +00:00
app_setup_memory ( System_Functions * system , Application_Memory * memory ) {
2016-06-29 17:16:08 +00:00
Partition _partition = make_part ( memory - > vars_memory , memory - > vars_memory_size ) ;
App_Vars * vars = push_struct ( & _partition , App_Vars ) ;
2017-02-17 22:03:19 +00:00
Assert ( vars ! = 0 ) ;
2018-03-10 02:06:55 +00:00
memset ( vars , 0 , sizeof ( * vars ) ) ;
2016-06-29 17:16:08 +00:00
vars - > models . mem . part = _partition ;
2017-01-14 03:01:35 +00:00
# if defined(USE_DEBUG_MEMORY)
2016-10-22 15:30:25 +00:00
general_memory_open ( system , & vars - > models . mem . general , memory - > target_memory , memory - > target_memory_size ) ;
2017-01-14 03:01:35 +00:00
# else
general_memory_open ( & vars - > models . mem . general , memory - > target_memory , memory - > target_memory_size ) ;
# endif
2016-06-29 17:16:08 +00:00
return ( vars ) ;
}
App_Read_Command_Line_Sig ( app_read_command_line ) {
i32 out_size = 0 ;
2016-10-22 15:30:25 +00:00
App_Vars * vars = app_setup_memory ( system , memory ) ;
2016-07-03 22:29:07 +00:00
App_Settings * settings = & vars - > models . settings ;
2016-06-29 17:16:08 +00:00
2017-01-30 18:41:08 +00:00
* settings = null_app_settings ;
2017-03-29 16:32:06 +00:00
plat_settings - > font_size = 16 ;
2016-07-03 22:29:07 +00:00
2017-07-19 20:07:50 +00:00
if ( argc > 1 ) {
init_command_line_settings ( & vars - > models . settings , plat_settings , argc , argv ) ;
2016-06-29 17:16:08 +00:00
}
2016-07-03 22:29:07 +00:00
* files = vars - > models . settings . init_files ;
* file_count = & vars - > models . settings . init_files_count ;
2016-06-29 17:16:08 +00:00
return ( out_size ) ;
}
App_Init_Sig ( app_init ) {
2016-09-20 19:48:02 +00:00
App_Vars * vars = ( App_Vars * ) memory - > vars_memory ;
Models * models = & vars - > models ;
2017-03-29 20:50:29 +00:00
models - > keep_playing = true ;
2016-06-29 17:16:08 +00:00
app_links_init ( system , & models - > app_links , memory - > user_memory , memory - > user_memory_size ) ;
models - > config_api = api ;
models - > app_links . cmd_context = & vars - > command_data ;
2017-03-29 20:50:29 +00:00
Partition * partition = & models - > mem . part ;
2016-06-29 17:16:08 +00:00
2017-03-29 20:50:29 +00:00
i32 panel_max_count = models - > layout . panel_max_count = MAX_VIEWS ;
i32 divider_max_count = panel_max_count - 1 ;
models - > layout . panel_count = 0 ;
Panel * panels = push_array ( partition , Panel , panel_max_count ) ;
models - > layout . panels = panels ;
dll_init_sentinel ( & models - > layout . free_sentinel ) ;
dll_init_sentinel ( & models - > layout . used_sentinel ) ;
Panel * panel = panels ;
for ( i32 i = 0 ; i < panel_max_count ; + + i , + + panel ) {
dll_insert ( & models - > layout . free_sentinel , panel ) ;
}
Panel_Divider * dividers = push_array ( partition , Panel_Divider , divider_max_count ) ;
models - > layout . dividers = dividers ;
Panel_Divider * div = dividers ;
for ( i32 i = 0 ; i < divider_max_count - 1 ; + + i , + + div ) {
div - > next = ( div + 1 ) ;
2016-06-29 17:16:08 +00:00
}
2017-03-29 20:50:29 +00:00
div - > next = 0 ;
models - > layout . free_divider = dividers ;
2016-06-29 17:16:08 +00:00
{
2017-07-17 23:35:13 +00:00
models - > live_set . count = 0 ;
models - > live_set . max = panel_max_count ;
2016-06-29 17:16:08 +00:00
2017-07-17 23:35:13 +00:00
models - > live_set . views = push_array ( partition , View , models - > live_set . max ) ;
2016-06-29 17:16:08 +00:00
2018-03-24 10:06:45 +00:00
//dll_init_sentinel
models - > live_set . free_sentinel . transient . next = & models - > live_set . free_sentinel ;
models - > live_set . free_sentinel . transient . prev = & models - > live_set . free_sentinel ;
2016-06-29 17:16:08 +00:00
2017-07-17 23:35:13 +00:00
i32 max = models - > live_set . max ;
View * view = models - > live_set . views ;
2017-03-29 20:50:29 +00:00
for ( i32 i = 0 ; i < max ; + + i , + + view ) {
2018-03-24 10:06:45 +00:00
//dll_insert(&models->live_set.free_sentinel, view);
view - > transient . next = models - > live_set . free_sentinel . transient . next ;
view - > transient . prev = & models - > live_set . free_sentinel ;
models - > live_set . free_sentinel . transient . next = view ;
view - > transient . next - > transient . prev = view ;
2016-06-29 17:16:08 +00:00
2017-03-29 20:50:29 +00:00
View_Persistent * persistent = & view - > persistent ;
2016-06-29 17:16:08 +00:00
persistent - > id = i ;
}
}
2017-05-19 23:55:50 +00:00
{
umem memsize = KB ( 8 ) ;
void * mem = push_block ( partition , ( i32 ) memsize ) ;
parse_context_init_memory ( & models - > parse_context_memory , mem , memsize ) ;
parse_context_add_default ( & models - > parse_context_memory , & models - > mem . general ) ;
}
2016-06-29 17:16:08 +00:00
{
setup_command_table ( ) ;
Assert ( models - > config_api . get_bindings ! = 0 ) ;
2017-01-23 06:19:43 +00:00
i32 wanted_size = models - > config_api . get_bindings ( models - > app_links . memory , models - > app_links . memory_size ) ;
2017-11-08 18:24:30 +00:00
Assert ( wanted_size < = models - > app_links . memory_size ) ;
interpret_binding_buffer ( models , models - > app_links . memory , wanted_size ) ;
2016-06-29 17:16:08 +00:00
memset ( models - > app_links . memory , 0 , wanted_size ) ;
}
// NOTE(allen): file setup
2017-01-14 03:01:35 +00:00
working_set_init ( & models - > working_set , partition , & vars - > models . mem . general ) ;
2016-09-22 00:01:12 +00:00
models - > working_set . default_display_width = DEFAULT_DISPLAY_WIDTH ;
2016-10-24 23:02:10 +00:00
models - > working_set . default_minimum_base_display_width = DEFAULT_MINIMUM_BASE_DISPLAY_WIDTH ;
2016-06-29 17:16:08 +00:00
// NOTE(allen): clipboard setup
models - > working_set . clipboard_max_size = ArrayCount ( models - > working_set . clipboards ) ;
models - > working_set . clipboard_size = 0 ;
models - > working_set . clipboard_current = 0 ;
models - > working_set . clipboard_rolling = 0 ;
// TODO(allen): more robust allocation solution for the clipboard
if ( clipboard . str ) {
2017-01-14 03:01:35 +00:00
String * dest = working_set_next_clipboard_string ( & models - > mem . general , & models - > working_set , clipboard . size ) ;
2016-08-28 04:31:06 +00:00
copy_ss ( dest , make_string ( ( char * ) clipboard . str , clipboard . size ) ) ;
2016-06-29 17:16:08 +00:00
}
// NOTE(allen): style setup
2017-03-11 18:53:48 +00:00
models - > global_font_id = 1 ;
2017-06-16 23:10:50 +00:00
app_hardcode_default_style ( models ) ;
2016-06-29 17:16:08 +00:00
2017-11-30 19:02:37 +00:00
// NOTE(allen): title space
models - > has_new_title = true ;
models - > title_capacity = KB ( 4 ) ;
models - > title_space = push_array ( partition , char , models - > title_capacity ) ;
{
String builder = make_string_cap ( models - > title_space , 0 , models - > title_capacity ) ;
append ( & builder , WINDOW_NAME ) ;
terminate_with_null ( & builder ) ;
}
2016-06-29 17:16:08 +00:00
// NOTE(allen): init first panel
2016-09-21 22:34:19 +00:00
Command_Data * cmd = & vars - > command_data ;
cmd - > models = models ;
cmd - > vars = vars ;
cmd - > system = system ;
2017-07-17 23:35:13 +00:00
cmd - > live_set = & models - > live_set ;
2016-09-21 22:34:19 +00:00
cmd - > screen_width = target - > width ;
cmd - > screen_height = target - > height ;
cmd - > key = null_key_event_data ;
2016-09-22 21:25:52 +00:00
File_Init init_files [ ] = {
2017-03-10 20:44:42 +00:00
{ make_lit_string ( " *messages* " ) , & models - > message_buffer , true , } ,
2018-03-25 06:43:56 +00:00
{ make_lit_string ( " *scratch* " ) , & models - > scratch_buffer , false , } ,
2016-09-21 22:34:19 +00:00
} ;
2018-03-25 06:43:56 +00:00
General_Memory * general = & models - > mem . general ;
2016-09-21 22:34:19 +00:00
for ( i32 i = 0 ; i < ArrayCount ( init_files ) ; + + i ) {
2017-01-14 03:01:35 +00:00
Editing_File * file = working_set_alloc_always ( & models - > working_set , general ) ;
2017-12-01 18:04:07 +00:00
buffer_bind_name ( models , general , partition , & models - > working_set , file , init_files [ i ] . name ) ;
2016-09-22 21:25:52 +00:00
2017-03-29 16:32:06 +00:00
if ( init_files [ i ] . read_only ) {
init_read_only_file ( system , models , file ) ;
}
else {
2018-03-25 06:43:56 +00:00
init_normal_file ( system , models , 0 , 0 , file ) ;
2016-09-22 21:25:52 +00:00
}
2017-02-12 06:01:01 +00:00
file - > settings . never_kill = true ;
2018-05-07 02:47:22 +00:00
file_set_unimportant ( file , true ) ;
2017-02-12 06:01:01 +00:00
file - > settings . unwrapped_lines = true ;
2016-09-21 22:34:19 +00:00
2016-09-22 21:25:52 +00:00
if ( init_files [ i ] . ptr ) {
* init_files [ i ] . ptr = file ;
}
2016-09-21 22:34:19 +00:00
}
2016-06-29 17:16:08 +00:00
Panel_And_ID p = layout_alloc_panel ( & models - > layout ) ;
2017-07-17 23:35:13 +00:00
panel_make_empty ( system , models , p . panel ) ;
2016-06-29 17:16:08 +00:00
models - > layout . active_panel = p . id ;
2017-02-12 06:01:01 +00:00
hot_directory_init ( & models - > hot_directory , current_directory ) ;
2016-06-29 17:16:08 +00:00
// NOTE(allen): child proc list setup
2017-07-17 22:46:56 +00:00
vars - > cli_processes = make_cli_list ( partition , 16 ) ;
2016-10-27 23:45:41 +00:00
// NOTE(allen): init GUI keys
models - > user_up_key = key_up ;
models - > user_down_key = key_down ;
2018-03-10 02:06:55 +00:00
// NOTE(allen): init recording
if ( models - > settings . make_input_recording ) {
i32 max = KB ( 4 ) / sizeof ( Simulation_Event ) ;
void * ptr = system - > memory_allocate ( max * sizeof ( Simulation_Event ) ) ;
models - > recorded_events = ( Simulation_Event * ) ptr ;
models - > recorded_event_count = 0 ;
models - > recorded_event_max = max ;
}
2016-06-29 17:16:08 +00:00
}
App_Step_Sig ( app_step ) {
App_Vars * vars = ( App_Vars * ) memory - > vars_memory ;
Models * models = & vars - > models ;
2018-03-03 07:46:44 +00:00
Application_Step_Result app_result = { 0 } ;
app_result . mouse_cursor_type = APP_MOUSE_CURSOR_DEFAULT ;
app_result . lctrl_lalt_is_altgr = models - > settings . lctrl_lalt_is_altgr ;
2018-03-10 02:06:55 +00:00
// NOTE(allen): Emit recorded events
if ( models - > settings . make_input_recording ) {
local_const i32 max_possible_events = KEY_INPUT_BUFFER_SIZE + KEY_EXTRA_SIZE + 5 ;
Simulation_Event new_events [ max_possible_events ] ;
i32 new_event_count = 0 ;
i32 counter_index = models - > frame_counter ;
for ( i32 i = 0 ; i < input - > keys . count ; + + i ) {
Assert ( new_event_count < max_possible_events ) ;
Key_Event_Data key = input - > keys . keys [ i ] ;
Simulation_Event * new_event = new_events + ( new_event_count + + ) ;
new_event - > counter_index = counter_index ;
new_event - > type = SimulationEvent_Key ;
new_event - > key . code = key . keycode ;
u8 modifier_flags = 0 ;
# define MDFR_FLAG_READ(I,F) if (key.modifiers[I]) { modifier_flags |= F; }
MDFR_FLAG_READ ( MDFR_CONTROL_INDEX , MDFR_CTRL ) ;
MDFR_FLAG_READ ( MDFR_ALT_INDEX , MDFR_ALT ) ;
MDFR_FLAG_READ ( MDFR_COMMAND_INDEX , MDFR_CMND ) ;
MDFR_FLAG_READ ( MDFR_SHIFT_INDEX , MDFR_SHIFT ) ;
new_event - > key . modifiers = modifier_flags ;
}
if ( input - > mouse . press_l ) {
Assert ( new_event_count < max_possible_events ) ;
Simulation_Event * new_event = new_events + ( new_event_count + + ) ;
new_event - > counter_index = counter_index ;
new_event - > type = SimulationEvent_MouseLeftPress ;
}
if ( input - > mouse . release_l ) {
Assert ( new_event_count < max_possible_events ) ;
Simulation_Event * new_event = new_events + ( new_event_count + + ) ;
new_event - > counter_index = counter_index ;
new_event - > type = SimulationEvent_MouseLeftRelease ;
}
if ( input - > mouse . press_r ) {
Assert ( new_event_count < max_possible_events ) ;
Simulation_Event * new_event = new_events + ( new_event_count + + ) ;
new_event - > counter_index = counter_index ;
new_event - > type = SimulationEvent_MouseRightPress ;
}
if ( input - > mouse . release_r ) {
Assert ( new_event_count < max_possible_events ) ;
Simulation_Event * new_event = new_events + ( new_event_count + + ) ;
new_event - > counter_index = counter_index ;
new_event - > type = SimulationEvent_MouseRightRelease ;
}
if ( input - > mouse . wheel ! = 0 ) {
Assert ( new_event_count < max_possible_events ) ;
Simulation_Event * new_event = new_events + ( new_event_count + + ) ;
new_event - > counter_index = counter_index ;
new_event - > type = SimulationEvent_MouseWheel ;
new_event - > wheel = input - > mouse . wheel ;
}
if ( input - > mouse . x ! = models - > previous_mouse_x | |
input - > mouse . y ! = models - > previous_mouse_y ) {
Assert ( new_event_count < max_possible_events ) ;
Simulation_Event * new_event = new_events + ( new_event_count + + ) ;
new_event - > counter_index = counter_index ;
new_event - > type = SimulationEvent_MouseXY ;
new_event - > mouse_xy . x = input - > mouse . x ;
new_event - > mouse_xy . y = input - > mouse . y ;
models - > previous_mouse_x = input - > mouse . x ;
models - > previous_mouse_y = input - > mouse . y ;
}
if ( input - > trying_to_kill ) {
Assert ( new_event_count < max_possible_events ) ;
Simulation_Event * new_event = new_events + ( new_event_count + + ) ;
new_event - > counter_index = counter_index ;
new_event - > type = SimulationEvent_Exit ;
}
if ( new_event_count > 0 ) {
app_recording_emit_events ( system , models , new_events , new_event_count ) ;
Partition * scratch = & models - > mem . part ;
Temp_Memory temp = begin_temp_memory ( scratch ) ;
i32 event_count = models - > recorded_event_count ;
u32 data_size = 4 + sizeof ( Simulation_Event ) * event_count ;
char * data = push_array ( scratch , char , 0 ) ;
i32 * count = push_array ( scratch , i32 , 1 ) ;
* count = event_count ;
Simulation_Event * events = push_array ( scratch , Simulation_Event , event_count ) ;
memcpy ( events , models - > recorded_events , sizeof ( * models - > recorded_events ) * event_count ) ;
system - > save_file ( models - > settings . input_recording_output_file , data , data_size ) ;
end_temp_memory ( temp ) ;
}
}
2016-06-29 17:16:08 +00:00
// NOTE(allen): OS clipboard event handling
String clipboard = input - > clipboard ;
if ( clipboard . str ) {
2017-01-14 03:01:35 +00:00
String * dest = working_set_next_clipboard_string ( & models - > mem . general , & models - > working_set , clipboard . size ) ;
2017-03-23 19:15:33 +00:00
dest - > size = eol_convert_in ( dest - > str , clipboard . str , clipboard . size ) ;
2016-06-29 17:16:08 +00:00
}
2016-08-26 21:30:08 +00:00
// NOTE(allen): check files are up to date
{
b32 mem_too_small = 0 ;
2017-03-23 19:14:39 +00:00
i32 size = 0 ;
i32 buffer_size = KB ( 32 ) ;
2016-08-26 21:30:08 +00:00
Partition * part = & models - > mem . part ;
Temp_Memory temp = begin_temp_memory ( part ) ;
char * buffer = push_array ( part , char , buffer_size ) ;
2017-02-12 06:01:01 +00:00
u32 unmark_top = 0 ;
u32 unmark_max = ( 8 < < 10 ) ;
2016-08-27 00:42:16 +00:00
Editing_File * * unmark = ( Editing_File * * ) push_array ( part , Editing_File * , unmark_max ) ;
2016-08-26 21:30:08 +00:00
Working_Set * working_set = & models - > working_set ;
for ( ; system - > get_file_change ( buffer , buffer_size , & mem_too_small , & size ) ; ) {
Assert ( ! mem_too_small ) ;
2017-11-30 23:25:49 +00:00
Editing_File_Name canon = { 0 } ;
2018-03-25 06:43:56 +00:00
if ( get_canon_name ( system , make_string ( buffer , size ) ,
& canon ) ) {
2017-11-30 23:25:49 +00:00
Editing_File * file = working_set_contains_canon ( working_set , canon . name ) ;
2017-11-21 21:30:40 +00:00
if ( file ! = 0 ) {
2016-08-26 21:30:08 +00:00
if ( file - > state . ignore_behind_os = = 0 ) {
2018-05-07 02:47:22 +00:00
file_set_dirty_flag ( file , DirtyState_UnloadedChanges ) ;
2016-08-26 21:30:08 +00:00
}
2016-08-27 00:42:16 +00:00
else if ( file - > state . ignore_behind_os = = 1 ) {
2017-02-12 06:01:01 +00:00
file - > state . ignore_behind_os = 2 ;
unmark [ unmark_top + + ] = file ;
2016-08-27 00:42:16 +00:00
if ( unmark_top = = unmark_max ) {
break ;
}
2016-08-26 21:30:08 +00:00
}
}
}
}
2017-02-12 06:01:01 +00:00
for ( u32 i = 0 ; i < unmark_top ; + + i ) {
2016-08-27 00:42:16 +00:00
unmark [ i ] - > state . ignore_behind_os = 0 ;
}
2016-08-26 21:30:08 +00:00
end_temp_memory ( temp ) ;
}
2016-06-29 17:16:08 +00:00
// NOTE(allen): reorganizing panels on screen
{
i32 prev_width = models - > layout . full_width ;
i32 prev_height = models - > layout . full_height ;
i32 current_width = target - > width ;
i32 current_height = target - > height ;
models - > layout . full_width = current_width ;
models - > layout . full_height = current_height ;
if ( prev_width ! = current_width | | prev_height ! = current_height ) {
layout_refit ( & models - > layout , prev_width , prev_height ) ;
}
}
// NOTE(allen): prepare input information
{
2016-06-29 19:11:37 +00:00
if ( models - > input_filter ) {
models - > input_filter ( & input - > mouse ) ;
}
2016-06-29 17:16:08 +00:00
Key_Event_Data mouse_event = { 0 } ;
if ( input - > mouse . press_l ) {
mouse_event . keycode = key_mouse_left ;
2017-01-29 00:03:23 +00:00
input - > keys . keys [ input - > keys . count + + ] = mouse_event ;
}
else if ( input - > mouse . release_l ) {
mouse_event . keycode = key_mouse_left_release ;
input - > keys . keys [ input - > keys . count + + ] = mouse_event ;
2016-06-29 17:16:08 +00:00
}
if ( input - > mouse . press_r ) {
mouse_event . keycode = key_mouse_right ;
2017-01-29 00:03:23 +00:00
input - > keys . keys [ input - > keys . count + + ] = mouse_event ;
2016-09-09 17:14:38 +00:00
}
2017-01-29 00:03:23 +00:00
else if ( input - > mouse . release_r ) {
2016-09-09 17:14:38 +00:00
mouse_event . keycode = key_mouse_right_release ;
2017-01-29 00:03:23 +00:00
input - > keys . keys [ input - > keys . count + + ] = mouse_event ;
2016-09-09 17:14:38 +00:00
}
2016-06-29 17:16:08 +00:00
}
// NOTE(allen): detect mouse hover status
i32 mx = input - > mouse . x ;
i32 my = input - > mouse . y ;
2017-03-17 17:45:41 +00:00
b32 mouse_in_edit_area = false ;
b32 mouse_in_margin_area = false ;
2016-06-29 17:16:08 +00:00
2017-03-17 17:45:41 +00:00
Panel * mouse_panel = 0 ;
2018-03-24 10:06:45 +00:00
for ( Panel * panel = models - > layout . used_sentinel . next ;
panel ! = & models - > layout . used_sentinel ;
panel = panel - > next ) {
if ( hit_check ( mx , my , panel - > inner ) ) {
mouse_panel = panel ;
mouse_in_edit_area = true ;
break ;
}
else if ( hit_check ( mx , my , panel - > full ) ) {
mouse_panel = panel ;
mouse_in_margin_area = true ;
break ;
2017-03-17 17:45:41 +00:00
}
2016-06-29 17:16:08 +00:00
}
2017-04-15 21:47:23 +00:00
b32 mouse_on_divider = false ;
b32 mouse_divider_vertical = false ;
2016-06-29 17:16:08 +00:00
i32 mouse_divider_id = 0 ;
i32 mouse_divider_side = 0 ;
if ( mouse_in_margin_area ) {
Panel * panel = mouse_panel ;
if ( mx > = panel - > inner . x0 & & mx < panel - > inner . x1 ) {
2017-04-15 21:47:23 +00:00
mouse_divider_vertical = false ;
2016-06-29 17:16:08 +00:00
if ( my > panel - > inner . y0 ) {
mouse_divider_side = - 1 ;
}
else {
mouse_divider_side = 1 ;
}
}
else {
2017-04-15 21:47:23 +00:00
mouse_divider_vertical = true ;
2016-06-29 17:16:08 +00:00
if ( mx > panel - > inner . x0 ) {
mouse_divider_side = - 1 ;
}
else {
mouse_divider_side = 1 ;
}
}
if ( models - > layout . panel_count > 1 ) {
mouse_divider_id = panel - > parent ;
2017-04-15 21:47:23 +00:00
i32 which_child = panel - > which_child ;
2016-06-29 17:16:08 +00:00
for ( ; ; ) {
Divider_And_ID div = layout_get_divider ( & models - > layout , mouse_divider_id ) ;
if ( which_child = = mouse_divider_side & &
div . divider - > v_divider = = mouse_divider_vertical ) {
2017-04-15 21:47:23 +00:00
mouse_on_divider = true ;
2016-06-29 17:16:08 +00:00
break ;
}
if ( mouse_divider_id = = models - > layout . root ) {
break ;
}
else {
mouse_divider_id = div . divider - > parent ;
which_child = div . divider - > which_child ;
}
}
}
else {
mouse_on_divider = 0 ;
mouse_divider_id = 0 ;
}
}
// NOTE(allen): update child processes
if ( input - > dt > 0 ) {
2017-07-17 22:46:56 +00:00
Partition * scratch = & models - > mem . part ;
CLI_List * list = & vars - > cli_processes ;
2016-06-29 17:16:08 +00:00
Temp_Memory temp = begin_temp_memory ( & models - > mem . part ) ;
2017-07-17 22:46:56 +00:00
CLI_Process * * procs_to_free = push_array ( scratch , CLI_Process * , list - > count ) ;
u32 proc_free_count = 0 ;
2017-01-23 06:19:43 +00:00
u32 max = KB ( 128 ) ;
2017-07-17 22:46:56 +00:00
char * dest = push_array ( scratch , char , max ) ;
2016-06-29 17:16:08 +00:00
2017-07-17 22:46:56 +00:00
CLI_Process * proc_ptr = list - > procs ;
for ( u32 i = 0 ; i < list - > count ; + + i , + + proc_ptr ) {
Editing_File * file = proc_ptr - > out_file ;
CLI_Handles * cli = & proc_ptr - > cli ;
2016-06-29 17:16:08 +00:00
2017-07-17 22:46:56 +00:00
u32 amount = 0 ;
system - > cli_begin_update ( cli ) ;
if ( system - > cli_update_step ( cli , dest , max , & amount ) ) {
if ( file ! = 0 ) {
amount = eol_in_place_convert_in ( dest , amount ) ;
2018-03-24 21:43:57 +00:00
output_file_append ( system , models , file , make_string ( dest , amount ) ) ;
2016-06-29 17:16:08 +00:00
}
}
2017-07-17 22:46:56 +00:00
if ( system - > cli_end_update ( cli ) ) {
if ( file ! = 0 ) {
char str_space [ 256 ] ;
String str = make_fixed_width_string ( str_space ) ;
append ( & str , make_lit_string ( " exited with code " ) ) ;
append_int_to_str ( & str , cli - > exit ) ;
2018-03-24 21:43:57 +00:00
output_file_append ( system , models , file , str ) ;
2017-07-17 22:46:56 +00:00
}
procs_to_free [ proc_free_count + + ] = proc_ptr ;
2016-08-28 19:25:24 +00:00
}
2016-06-29 17:16:08 +00:00
}
2018-03-24 21:43:57 +00:00
// TODO(allen): proc_ptr->cursor_at_end
2017-07-17 23:35:13 +00:00
for ( i32 i = proc_free_count - 1 ; i > = 0 ; - - i ) {
2017-07-17 22:46:56 +00:00
cli_list_free_proc ( list , procs_to_free [ i ] ) ;
}
2016-06-29 17:16:08 +00:00
end_temp_memory ( temp ) ;
}
// NOTE(allen): prepare to start executing commands
Command_Data * cmd = & vars - > command_data ;
cmd - > models = models ;
cmd - > vars = vars ;
cmd - > system = system ;
2017-07-17 23:35:13 +00:00
cmd - > live_set = & models - > live_set ;
2016-06-29 17:16:08 +00:00
cmd - > screen_width = target - > width ;
cmd - > screen_height = target - > height ;
2016-09-01 19:40:25 +00:00
cmd - > key = null_key_event_data ;
2016-06-29 17:16:08 +00:00
2017-11-30 16:50:39 +00:00
// NOTE(allen): First frame initialization
2016-06-29 17:16:08 +00:00
if ( input - > first_step ) {
2017-06-23 23:07:18 +00:00
// Open command line files.
2016-09-09 22:56:43 +00:00
char space [ 512 ] ;
String cl_filename = make_fixed_width_string ( space ) ;
copy_ss ( & cl_filename , models - > hot_directory . string ) ;
i32 cl_filename_len = cl_filename . size ;
2017-06-23 23:07:18 +00:00
for ( i32 i = 0 ; i < models - > settings . init_files_count ; + + i ) {
2016-09-09 22:56:43 +00:00
cl_filename . size = cl_filename_len ;
2016-09-17 01:11:22 +00:00
String filename = { 0 } ;
2017-11-30 23:25:49 +00:00
Editing_File_Name canon_name = { 0 } ;
2018-03-25 06:43:56 +00:00
if ( get_canon_name ( system , make_string_slowly ( models - > settings . init_files [ i ] ) ,
& canon_name ) ) {
2016-09-17 01:11:22 +00:00
filename = canon_name . name ;
}
else {
append_sc ( & cl_filename , models - > settings . init_files [ i ] ) ;
filename = cl_filename ;
}
2016-06-29 17:16:08 +00:00
2017-06-23 23:07:18 +00:00
open_file ( system , models , filename ) ;
2016-06-29 17:16:08 +00:00
}
2017-06-23 23:07:18 +00:00
if ( models - > hook_start ! = 0 ) {
char * * files = models - > settings . init_files ;
i32 files_count = models - > settings . init_files_count ;
char * * flags = models - > settings . custom_flags ;
i32 flags_count = models - > settings . custom_flags_count ;
models - > hook_start ( & models - > app_links , files , files_count , flags , flags_count ) ;
2016-06-29 17:45:26 +00:00
}
2016-06-29 17:16:08 +00:00
}
// NOTE(allen): respond if the user is trying to kill the application
2018-03-03 07:46:44 +00:00
if ( input - > trying_to_kill ) {
2018-03-24 10:06:45 +00:00
b32 there_is_unsaved = false ;
app_result . animating = true ;
2016-06-29 17:16:08 +00:00
2018-03-24 10:06:45 +00:00
for ( File_Node * node = models - > working_set . used_sentinel . next ;
node ! = & models - > working_set . used_sentinel ;
node = node - > next ) {
2016-06-29 17:16:08 +00:00
Editing_File * file = ( Editing_File * ) node ;
if ( buffer_needs_save ( file ) ) {
2018-03-24 10:06:45 +00:00
there_is_unsaved = true ;
2016-06-29 17:16:08 +00:00
break ;
}
}
if ( there_is_unsaved ) {
2017-07-19 20:07:50 +00:00
Coroutine_Head * command_coroutine = models - > command_coroutine ;
2016-09-21 22:34:19 +00:00
Command_Data * command = cmd ;
USE_VIEW ( view ) ;
2016-06-29 17:16:08 +00:00
2017-07-19 20:07:50 +00:00
for ( i32 i = 0 ; i < 128 & & command_coroutine ! = 0 ; + + i ) {
2016-06-29 17:16:08 +00:00
User_Input user_in = { 0 } ;
2017-04-15 21:47:23 +00:00
user_in . abort = true ;
2016-06-29 17:16:08 +00:00
2017-04-15 21:47:23 +00:00
command_coroutine = app_resume_coroutine ( system , & models - > app_links , Co_Command , command_coroutine , & user_in , models - > command_coroutine_flags ) ;
2016-06-29 17:16:08 +00:00
}
if ( command_coroutine ! = 0 ) {
// TODO(allen): post grave warning
command_coroutine = 0 ;
}
if ( view ! = 0 ) {
2018-03-24 10:06:45 +00:00
init_query_set ( & view - > transient . query_set ) ;
2016-06-29 17:16:08 +00:00
}
if ( view = = 0 ) {
Panel * panel = models - > layout . used_sentinel . next ;
view = panel - > view ;
}
2017-07-17 23:35:13 +00:00
view_show_interactive ( system , view , models , IAct_Sure_To_Close , IInt_Sure_To_Close , make_lit_string ( " Are you sure? " ) ) ;
2016-06-29 17:16:08 +00:00
models - > command_coroutine = command_coroutine ;
}
else {
models - > keep_playing = 0 ;
}
}
// NOTE(allen): pass events to debug
2017-01-29 00:03:23 +00:00
vars - > available_input = init_available_input ( & input - > keys , & input - > mouse ) ;
2016-06-29 17:16:08 +00:00
{
Debug_Data * debug = & models - > debug ;
2017-01-29 00:03:23 +00:00
Key_Input_Data key_data = get_key_data ( & vars - > available_input ) ;
2016-06-29 17:16:08 +00:00
Debug_Input_Event * events = debug - > input_events ;
i32 count = key_data . count ;
i32 preserved_inputs = ArrayCount ( debug - > input_events ) - count ;
debug - > this_frame_count = count ;
2017-11-27 23:26:56 +00:00
memmove ( events + count , events , sizeof ( Debug_Input_Event ) * preserved_inputs ) ;
2016-06-29 17:16:08 +00:00
for ( i32 i = 0 ; i < key_data . count ; + + i ) {
2018-03-10 02:06:55 +00:00
Key_Event_Data key = key_data . keys [ i ] ;
2016-06-29 17:16:08 +00:00
events [ i ] . key = key . keycode ;
events [ i ] . consumer [ 0 ] = 0 ;
events [ i ] . is_hold = key . modifiers [ MDFR_HOLD_INDEX ] ;
events [ i ] . is_ctrl = key . modifiers [ MDFR_CONTROL_INDEX ] ;
events [ i ] . is_alt = key . modifiers [ MDFR_ALT_INDEX ] ;
events [ i ] . is_shift = key . modifiers [ MDFR_SHIFT_INDEX ] ;
}
}
2017-07-18 00:00:07 +00:00
// NOTE(allen): Keyboard and Mouse input to command coroutine.
2016-06-29 17:16:08 +00:00
if ( models - > command_coroutine ! = 0 ) {
2017-07-19 20:07:50 +00:00
Coroutine_Head * command_coroutine = models - > command_coroutine ;
2016-06-29 17:16:08 +00:00
u32 get_flags = models - > command_coroutine_flags [ 0 ] ;
u32 abort_flags = models - > command_coroutine_flags [ 1 ] ;
get_flags | = abort_flags ;
2017-07-18 00:00:07 +00:00
Command_Data * command = cmd ;
USE_VIEW ( view ) ;
Partition * part = & models - > mem . part ;
Temp_Memory temp = begin_temp_memory ( part ) ;
// HACK(allen): This can be simplified a lot more.
Coroutine_Event * events = push_array ( part , Coroutine_Event , 32 ) ;
u32 event_count = 0 ;
Key_Input_Data key_data = get_key_data ( & vars - > available_input ) ;
2016-06-29 17:16:08 +00:00
if ( ( get_flags & EventOnAnyKey ) | | ( get_flags & EventOnEsc ) ) {
for ( i32 key_i = 0 ; key_i < key_data . count ; + + key_i ) {
2017-07-18 00:00:07 +00:00
Coroutine_Event * new_event = & events [ event_count + + ] ;
new_event - > type = Event_Keyboard ;
new_event - > key_i = key_i ;
2016-06-29 17:16:08 +00:00
}
}
if ( models - > command_coroutine ! = 0 & & ( get_flags & EventOnMouse ) ) {
2017-07-18 00:00:07 +00:00
Coroutine_Event * new_event = & events [ event_count + + ] ;
new_event - > type = Event_Mouse ;
}
Coroutine_Event * event = events ;
for ( u32 event_i = 0 ; event_i < event_count ; + + event_i , + + event ) {
b32 pass_in = false ;
2017-04-15 21:47:23 +00:00
User_Input user_in = { 0 } ;
2016-06-29 17:16:08 +00:00
2017-07-18 00:00:07 +00:00
switch ( event - > type ) {
case Event_Keyboard :
{
2018-03-10 02:06:55 +00:00
Key_Event_Data key = key_data . keys [ event - > key_i ] ;
2017-07-18 00:00:07 +00:00
cmd - > key = key ;
2017-11-08 18:24:30 +00:00
i32 map = mapid_global ;
if ( view ! = 0 ) {
2018-03-24 10:06:45 +00:00
map = view - > transient . map ;
2017-07-18 00:00:07 +00:00
}
2017-11-08 18:24:30 +00:00
Command_Binding cmd_bind = map_extract_recursive ( & models - > mapping , map , key ) ;
2017-07-18 00:00:07 +00:00
user_in . type = UserInputKey ;
user_in . key = key ;
user_in . command . command = cmd_bind . custom ;
if ( ( abort_flags & EventOnEsc ) & & key . keycode = = key_esc ) {
user_in . abort = true ;
}
else if ( abort_flags & EventOnAnyKey ) {
user_in . abort = true ;
}
if ( get_flags & EventOnAnyKey ) {
pass_in = true ;
consume_input ( & vars - > available_input , Input_AnyKey , " command coroutine " ) ;
}
if ( key . keycode = = key_esc ) {
if ( get_flags & EventOnEsc ) {
pass_in = true ;
}
consume_input ( & vars - > available_input , Input_Esc , " command coroutine " ) ;
}
} break ;
case Event_Mouse :
{
user_in . type = UserInputMouse ;
user_in . mouse = input - > mouse ;
if ( abort_flags & EventOnMouseMove ) {
user_in . abort = true ;
}
if ( get_flags & EventOnMouseMove ) {
pass_in = true ;
consume_input ( & vars - > available_input , Input_MouseMove , " command coroutine " ) ;
}
if ( input - > mouse . press_l | | input - > mouse . release_l | | input - > mouse . l ) {
if ( abort_flags & EventOnLeftButton ) {
user_in . abort = true ;
}
if ( get_flags & EventOnLeftButton ) {
pass_in = true ;
consume_input ( & vars - > available_input , Input_MouseLeftButton , " command coroutine " ) ;
}
}
if ( input - > mouse . press_r | | input - > mouse . release_r | | input - > mouse . r ) {
if ( abort_flags & EventOnRightButton ) {
user_in . abort = true ;
}
if ( get_flags & EventOnRightButton ) {
pass_in = true ;
consume_input ( & vars - > available_input , Input_MouseRightButton , " command coroutine " ) ;
}
}
if ( input - > mouse . wheel ! = 0 ) {
if ( abort_flags & EventOnWheel ) {
user_in . abort = true ;
}
if ( get_flags & EventOnWheel ) {
pass_in = true ;
consume_input ( & vars - > available_input , Input_MouseWheel , " command coroutine " ) ;
}
}
} break ;
2016-06-29 17:16:08 +00:00
}
if ( pass_in ) {
2017-04-15 21:47:23 +00:00
models - > command_coroutine = app_resume_coroutine ( system , & models - > app_links , Co_Command , command_coroutine , & user_in , models - > command_coroutine_flags ) ;
2016-06-29 17:16:08 +00:00
2017-04-15 21:47:23 +00:00
app_result . animating = true ;
2016-06-29 17:16:08 +00:00
// TODO(allen): Should I somehow allow a view to clean up however it wants after a
// command finishes, or after transfering to another view mid command?
if ( view ! = 0 & & models - > command_coroutine = = 0 ) {
2018-03-24 10:06:45 +00:00
init_query_set ( & view - > transient . query_set ) ;
2016-06-29 17:16:08 +00:00
}
2017-07-18 00:00:07 +00:00
if ( models - > command_coroutine = = 0 ) break ;
2016-06-29 17:16:08 +00:00
}
}
2017-07-18 00:00:07 +00:00
end_temp_memory ( temp ) ;
2016-06-29 17:16:08 +00:00
}
// NOTE(allen): pass raw input to the panels
Input_Summary dead_input = { } ;
dead_input . mouse . x = input - > mouse . x ;
dead_input . mouse . y = input - > mouse . y ;
dead_input . dt = input - > dt ;
Input_Summary active_input = { } ;
active_input . mouse . x = input - > mouse . x ;
active_input . mouse . y = input - > mouse . y ;
active_input . dt = input - > dt ;
active_input . keys = get_key_data ( & vars - > available_input ) ;
Mouse_State mouse_state = get_mouse_state ( & vars - > available_input ) ;
{
2016-09-21 22:34:19 +00:00
Command_Data * command = cmd ;
USE_VIEW ( active_view ) ;
USE_PANEL ( active_panel ) ;
2018-03-24 10:06:45 +00:00
for ( Panel * panel = models - > layout . used_sentinel . next ;
panel ! = & models - > layout . used_sentinel ;
panel = panel - > next ) {
View * view = panel - > view ;
b32 active = ( panel = = active_panel ) ;
Input_Summary summary = ( active ) ? ( active_input ) : ( dead_input ) ;
2016-06-29 17:16:08 +00:00
2018-03-24 10:06:45 +00:00
view - > transient . changed_context_in_step = 0 ;
2016-06-29 17:16:08 +00:00
2018-03-26 05:19:08 +00:00
View_Step_Result result = step_view ( system , view , models , active_view , summary ) ;
2016-07-20 16:16:02 +00:00
2016-06-29 17:16:08 +00:00
if ( result . animating ) {
app_result . animating = 1 ;
}
if ( result . consume_keys ) {
2016-12-18 20:42:11 +00:00
consume_input ( & vars - > available_input , Input_AnyKey , " file view step " ) ;
2016-06-29 17:16:08 +00:00
}
if ( result . consume_keys | | result . consume_esc ) {
2016-12-18 20:42:11 +00:00
consume_input ( & vars - > available_input , Input_Esc , " file view step " ) ;
2016-06-29 17:16:08 +00:00
}
2018-03-24 10:06:45 +00:00
if ( view - > transient . changed_context_in_step = = 0 ) {
2016-09-21 22:34:19 +00:00
active = ( panel = = active_panel ) ;
2016-06-29 17:16:08 +00:00
summary = ( active ) ? ( active_input ) : ( dead_input ) ;
if ( panel = = mouse_panel & & ! input - > mouse . out_of_window ) {
summary . mouse = mouse_state ;
}
2016-07-02 22:59:16 +00:00
b32 file_scroll = false ;
2018-03-24 10:06:45 +00:00
GUI_Scroll_Vars * scroll_vars = & view - > transient . gui_scroll ;
if ( view - > transient . showing_ui = = VUI_None ) {
Assert ( view - > transient . file_data . file ! = 0 ) ;
scroll_vars = & view - > transient . edit_pos - > scroll ;
2018-03-03 07:46:44 +00:00
file_scroll = true ;
2016-07-02 17:54:56 +00:00
}
2016-07-06 22:04:31 +00:00
i32 max_y = 0 ;
2018-03-24 10:06:45 +00:00
if ( view - > transient . showing_ui = = VUI_None ) {
2016-07-06 22:04:31 +00:00
max_y = view_compute_max_target_y ( view ) ;
}
else {
2018-03-24 10:06:45 +00:00
max_y = view - > transient . gui_max_y ;
2016-07-06 22:04:31 +00:00
}
2018-03-24 10:06:45 +00:00
Input_Process_Result ip_result = do_step_file_view ( system , view , models , panel - > inner , active , & summary , * scroll_vars , view - > transient . scroll_region , max_y ) ;
2016-07-06 22:04:31 +00:00
2016-06-29 17:16:08 +00:00
if ( ip_result . is_animating ) {
app_result . animating = 1 ;
}
if ( ip_result . consumed_l ) {
2016-12-18 20:42:11 +00:00
consume_input ( & vars - > available_input , Input_MouseLeftButton , " file view step " ) ;
2016-06-29 17:16:08 +00:00
}
if ( ip_result . consumed_r ) {
2016-12-18 20:42:11 +00:00
consume_input ( & vars - > available_input , Input_MouseRightButton , " file view step " ) ;
2016-06-29 17:16:08 +00:00
}
2016-07-02 17:54:56 +00:00
2016-07-06 22:04:31 +00:00
if ( ip_result . has_max_y_suggestion ) {
2018-03-24 10:06:45 +00:00
view - > transient . gui_max_y = ip_result . max_y ;
2016-07-06 22:04:31 +00:00
}
2016-07-02 17:54:56 +00:00
if ( ! gui_scroll_eq ( scroll_vars , & ip_result . vars ) ) {
2016-07-02 22:59:16 +00:00
if ( file_scroll ) {
2017-03-12 01:20:24 +00:00
view_set_scroll ( system , view , ip_result . vars ) ;
2016-07-02 17:54:56 +00:00
}
else {
* scroll_vars = ip_result . vars ;
}
}
2018-03-24 10:06:45 +00:00
view - > transient . scroll_region = ip_result . region ;
2016-06-29 17:16:08 +00:00
}
}
}
// NOTE(allen): command execution
{
2017-01-29 00:03:23 +00:00
Key_Input_Data key_data = get_key_data ( & vars - > available_input ) ;
2016-06-29 17:16:08 +00:00
b32 hit_something = 0 ;
b32 hit_esc = 0 ;
for ( i32 key_i = 0 ; key_i < key_data . count ; + + key_i ) {
2017-11-08 21:28:44 +00:00
if ( models - > command_coroutine ! = 0 ) {
break ;
}
2016-06-29 17:16:08 +00:00
switch ( vars - > state ) {
case APP_STATE_EDIT :
{
2018-03-10 02:06:55 +00:00
Key_Event_Data key = key_data . keys [ key_i ] ;
2016-06-29 17:16:08 +00:00
cmd - > key = key ;
2016-09-21 22:34:19 +00:00
Command_Data * command = cmd ;
USE_VIEW ( view ) ;
2017-11-08 18:24:30 +00:00
Assert ( view ! = 0 ) ;
2016-06-29 17:16:08 +00:00
2018-03-24 10:06:45 +00:00
Command_Binding cmd_bind = map_extract_recursive ( & models - > mapping , view - > transient . map , key ) ;
2016-06-29 17:16:08 +00:00
if ( cmd_bind . function ) {
if ( key . keycode = = key_esc ) {
2017-11-08 21:28:44 +00:00
hit_esc = true ;
2016-06-29 17:16:08 +00:00
}
else {
2017-11-08 21:28:44 +00:00
hit_something = true ;
2016-06-29 17:16:08 +00:00
}
Assert ( models - > command_coroutine = = 0 ) ;
2017-07-19 20:07:50 +00:00
Coroutine_Head * command_coroutine = system - > create_coroutine ( command_caller ) ;
2016-06-29 17:16:08 +00:00
models - > command_coroutine = command_coroutine ;
Command_In cmd_in ;
cmd_in . cmd = cmd ;
cmd_in . bind = cmd_bind ;
2016-12-18 20:42:11 +00:00
models - > command_coroutine = app_launch_coroutine ( system , & models - > app_links , Co_Command , models - > command_coroutine , & cmd_in , models - > command_coroutine_flags ) ;
2016-06-29 17:16:08 +00:00
models - > prev_command = cmd_bind ;
2017-11-08 21:28:44 +00:00
app_result . animating = true ;
2016-06-29 17:16:08 +00:00
}
} break ;
case APP_STATE_RESIZING :
{
if ( key_data . count > 0 ) {
vars - > state = APP_STATE_EDIT ;
}
} break ;
}
}
if ( hit_something ) {
2016-12-18 20:42:11 +00:00
consume_input ( & vars - > available_input , Input_AnyKey , " command dispatcher " ) ;
2016-06-29 17:16:08 +00:00
}
if ( hit_esc ) {
2016-12-18 20:42:11 +00:00
consume_input ( & vars - > available_input , Input_Esc , " command dispatcher " ) ;
2016-06-29 17:16:08 +00:00
}
}
// NOTE(allen): pass consumption data to debug
{
Debug_Data * debug = & models - > debug ;
i32 count = debug - > this_frame_count ;
Consumption_Record * record = 0 ;
record = & vars - > available_input . records [ Input_MouseLeftButton ] ;
if ( record - > consumed & & record - > consumer [ 0 ] ! = 0 ) {
Debug_Input_Event * event = debug - > input_events ;
for ( i32 i = 0 ; i < count ; + + i , + + event ) {
2016-09-09 17:14:38 +00:00
if ( event - > key = = key_mouse_left & & event - > consumer [ 0 ] = = 0 ) {
2016-06-29 17:16:08 +00:00
memcpy ( event - > consumer , record - > consumer , sizeof ( record - > consumer ) ) ;
}
}
}
record = & vars - > available_input . records [ Input_MouseRightButton ] ;
if ( record - > consumed & & record - > consumer [ 0 ] ! = 0 ) {
Debug_Input_Event * event = debug - > input_events ;
for ( i32 i = 0 ; i < count ; + + i , + + event ) {
2016-09-09 17:14:38 +00:00
if ( event - > key = = key_mouse_right & & event - > consumer [ 0 ] = = 0 ) {
2016-06-29 17:16:08 +00:00
memcpy ( event - > consumer , record - > consumer , sizeof ( record - > consumer ) ) ;
}
}
}
record = & vars - > available_input . records [ Input_Esc ] ;
if ( record - > consumed & & record - > consumer [ 0 ] ! = 0 ) {
Debug_Input_Event * event = debug - > input_events ;
for ( i32 i = 0 ; i < count ; + + i , + + event ) {
2016-09-09 17:14:38 +00:00
if ( event - > key = = key_esc & & event - > consumer [ 0 ] = = 0 ) {
2016-06-29 17:16:08 +00:00
memcpy ( event - > consumer , record - > consumer , sizeof ( record - > consumer ) ) ;
}
}
}
record = & vars - > available_input . records [ Input_AnyKey ] ;
if ( record - > consumed ) {
Debug_Input_Event * event = debug - > input_events ;
for ( i32 i = 0 ; i < count ; + + i , + + event ) {
if ( event - > consumer [ 0 ] = = 0 ) {
memcpy ( event - > consumer , record - > consumer , sizeof ( record - > consumer ) ) ;
}
}
}
}
// NOTE(allen): initialize message
if ( input - > first_step ) {
2017-07-11 21:53:27 +00:00
String welcome = make_lit_string ( messages ) ;
2016-07-14 21:44:34 +00:00
do_feedback_message ( system , models , welcome , true ) ;
2016-06-29 17:16:08 +00:00
}
// NOTE(allen): panel resizing
switch ( vars - > state ) {
case APP_STATE_EDIT :
{
if ( input - > mouse . press_l & & mouse_on_divider ) {
vars - > state = APP_STATE_RESIZING ;
Divider_And_ID div = layout_get_divider ( & models - > layout , mouse_divider_id ) ;
vars - > resizing . divider = div . divider ;
f32 min = 0 ;
f32 max = 0 ;
{
f32 mid = layout_get_position ( & models - > layout , mouse_divider_id ) ;
if ( mouse_divider_vertical ) {
max = ( f32 ) models - > layout . full_width ;
}
else {
max = ( f32 ) models - > layout . full_height ;
}
i32 divider_id = div . id ;
do {
Divider_And_ID other_div = layout_get_divider ( & models - > layout , divider_id ) ;
b32 divider_match = ( other_div . divider - > v_divider = = mouse_divider_vertical ) ;
f32 pos = layout_get_position ( & models - > layout , divider_id ) ;
if ( divider_match & & pos > mid & & pos < max ) {
max = pos ;
}
else if ( divider_match & & pos < mid & & pos > min ) {
min = pos ;
}
divider_id = other_div . divider - > parent ;
} while ( divider_id ! = - 1 ) ;
Temp_Memory temp = begin_temp_memory ( & models - > mem . part ) ;
i32 * divider_stack = push_array ( & models - > mem . part , i32 , models - > layout . panel_count ) ;
i32 top = 0 ;
divider_stack [ top + + ] = div . id ;
while ( top > 0 ) {
- - top ;
Divider_And_ID other_div = layout_get_divider ( & models - > layout , divider_stack [ top ] ) ;
b32 divider_match = ( other_div . divider - > v_divider = = mouse_divider_vertical ) ;
f32 pos = layout_get_position ( & models - > layout , divider_stack [ top ] ) ;
if ( divider_match & & pos > mid & & pos < max ) {
max = pos ;
}
else if ( divider_match & & pos < mid & & pos > min ) {
min = pos ;
}
if ( other_div . divider - > child1 ! = - 1 ) {
divider_stack [ top + + ] = other_div . divider - > child1 ;
}
if ( other_div . divider - > child2 ! = - 1 ) {
divider_stack [ top + + ] = other_div . divider - > child2 ;
}
}
end_temp_memory ( temp ) ;
}
}
} break ;
case APP_STATE_RESIZING :
{
if ( input - > mouse . l ) {
Panel_Divider * divider = vars - > resizing . divider ;
2016-09-09 15:04:38 +00:00
i32 mouse_position = 0 ;
2016-06-29 17:16:08 +00:00
2016-09-09 17:02:57 +00:00
b32 do_absolute_positions = 1 ;
2016-09-09 15:04:38 +00:00
if ( do_absolute_positions ) {
i32 absolute_positions [ MAX_VIEWS ] ;
i32 min = 0 , max = 0 ;
i32 div_id = ( i32 ) ( divider - models - > layout . dividers ) ;
layout_compute_absolute_positions ( & models - > layout , absolute_positions ) ;
mouse_position = ( divider - > v_divider ) ? ( mx ) : ( my ) ;
layout_get_min_max ( & models - > layout , divider , absolute_positions , & min , & max ) ;
2017-03-23 19:15:33 +00:00
absolute_positions [ div_id ] = clamp ( min , mouse_position , max ) ;
2016-09-09 15:04:38 +00:00
layout_update_all_positions ( & models - > layout , absolute_positions ) ;
2016-06-29 17:16:08 +00:00
}
2016-09-09 15:04:38 +00:00
else {
if ( divider - > v_divider ) {
2017-03-23 19:15:33 +00:00
mouse_position = clamp ( 0 , mx , models - > layout . full_width ) ;
2016-09-09 15:04:38 +00:00
}
else {
2017-03-23 19:15:33 +00:00
mouse_position = clamp ( 0 , my , models - > layout . full_height ) ;
2016-09-09 15:04:38 +00:00
}
2016-09-09 16:47:07 +00:00
divider - > pos = layout_compute_position ( & models - > layout , divider , mouse_position ) ;
2016-06-29 17:16:08 +00:00
}
layout_fix_all_panels ( & models - > layout ) ;
}
else {
vars - > state = APP_STATE_EDIT ;
}
} break ;
}
2016-12-18 20:42:11 +00:00
if ( models - > layout . panel_state_dirty & & models - > hooks [ hook_view_size_change ] ! = 0 ) {
models - > layout . panel_state_dirty = 0 ;
models - > hooks [ hook_view_size_change ] ( & models - > app_links ) ;
}
2016-06-29 17:16:08 +00:00
if ( mouse_in_edit_area & & mouse_panel ! = 0 & & input - > mouse . press_l ) {
2017-04-15 21:47:23 +00:00
i32 new_panel_id = ( i32 ) ( mouse_panel - models - > layout . panels ) ;
if ( models - > layout . active_panel ! = new_panel_id ) {
if ( models - > command_coroutine ! = 0 ) {
User_Input user_in = { 0 } ;
user_in . abort = true ;
for ( u32 j = 0 ; j < 10 & & models - > command_coroutine ! = 0 ; + + j ) {
models - > command_coroutine = app_resume_coroutine ( system , & models - > app_links , Co_Command , models - > command_coroutine , & user_in , models - > command_coroutine_flags ) ;
}
if ( models - > command_coroutine ! = 0 ) {
// TODO(allen): post grave warning
models - > command_coroutine = 0 ;
}
Panel * active_panel = & models - > layout . panels [ models - > layout . active_panel ] ;
View * view = active_panel - > view ;
2018-03-24 10:06:45 +00:00
init_query_set ( & view - > transient . query_set ) ;
2017-04-15 21:47:23 +00:00
}
models - > layout . active_panel = new_panel_id ;
app_result . animating = true ;
}
2016-06-29 17:16:08 +00:00
}
2016-07-06 22:28:39 +00:00
// NOTE(allen): on the first frame there should be no scrolling
if ( input - > first_step ) {
2018-03-24 10:06:45 +00:00
for ( Panel * panel = models - > layout . used_sentinel . next ;
panel ! = & models - > layout . used_sentinel ;
panel = panel - > next ) {
2016-07-06 22:28:39 +00:00
View * view = panel - > view ;
2018-03-24 10:06:45 +00:00
GUI_Scroll_Vars * scroll_vars = & view - > transient . gui_scroll ;
if ( view - > transient . edit_pos ! = 0 ) {
scroll_vars = & view - > transient . edit_pos - > scroll ;
2016-07-06 22:28:39 +00:00
}
scroll_vars - > scroll_x = ( f32 ) scroll_vars - > target_x ;
scroll_vars - > scroll_y = ( f32 ) scroll_vars - > target_y ;
}
}
2016-09-09 13:04:51 +00:00
// NOTE(allen): if this is the last frame, run the exit hook
2018-03-24 10:06:45 +00:00
if ( ! models - > keep_playing & & models - > hooks [ hook_exit ] ! = 0 ) {
2016-09-09 13:04:51 +00:00
if ( ! models - > hooks [ hook_exit ] ( & models - > app_links ) ) {
2018-03-24 10:06:45 +00:00
models - > keep_playing = true ;
2016-09-09 13:04:51 +00:00
}
}
2016-06-29 17:16:08 +00:00
// NOTE(allen): rendering
{
begin_render_section ( target , system ) ;
2016-09-21 22:34:19 +00:00
Command_Data * command = cmd ;
USE_PANEL ( active_panel ) ;
USE_VIEW ( active_view ) ;
2016-06-29 17:16:08 +00:00
// NOTE(allen): render the panels
2018-03-24 10:06:45 +00:00
for ( Panel * panel = models - > layout . used_sentinel . next ;
panel ! = & models - > layout . used_sentinel ;
panel = panel - > next ) {
2016-06-29 17:16:08 +00:00
i32_Rect full = panel - > full ;
i32_Rect inner = panel - > inner ;
View * view = panel - > view ;
2018-03-24 21:43:57 +00:00
Style * style = & models - > styles . styles [ 0 ] ;
2016-06-29 17:16:08 +00:00
2016-09-21 22:34:19 +00:00
b32 active = ( panel = = active_panel ) ;
2016-06-29 17:16:08 +00:00
u32 back_color = style - > main . back_color ;
draw_rectangle ( target , full , back_color ) ;
2016-07-02 22:59:16 +00:00
b32 file_scroll = false ;
2018-03-24 10:06:45 +00:00
GUI_Scroll_Vars * scroll_vars = & view - > transient . gui_scroll ;
if ( view - > transient . showing_ui = = VUI_None ) {
Assert ( view - > transient . file_data . file ! = 0 ) ;
scroll_vars = & view - > transient . edit_pos - > scroll ;
2018-03-03 07:46:44 +00:00
file_scroll = true ;
2016-07-02 17:54:56 +00:00
}
2017-11-11 00:58:47 +00:00
do_render_file_view ( system , view , models , scroll_vars , active_view , panel - > inner , active , target , & dead_input ) ;
2016-06-29 17:16:08 +00:00
u32 margin_color ;
if ( active ) {
margin_color = style - > main . margin_active_color ;
}
else if ( panel = = mouse_panel ) {
margin_color = style - > main . margin_hover_color ;
}
else {
margin_color = style - > main . margin_color ;
}
draw_rectangle ( target , i32R ( full . x0 , full . y0 , full . x1 , inner . y0 ) , margin_color ) ;
draw_rectangle ( target , i32R ( full . x0 , inner . y1 , full . x1 , full . y1 ) , margin_color ) ;
draw_rectangle ( target , i32R ( full . x0 , inner . y0 , inner . x0 , inner . y1 ) , margin_color ) ;
draw_rectangle ( target , i32R ( inner . x1 , inner . y0 , full . x1 , inner . y1 ) , margin_color ) ;
}
end_render_section ( target , system ) ;
}
2017-11-30 19:02:37 +00:00
// NOTE(allen): get new window title
if ( models - > has_new_title ) {
models - > has_new_title = false ;
app_result . has_new_title = true ;
app_result . title_string = models - > title_space ;
}
2016-06-29 17:16:08 +00:00
// NOTE(allen): get cursor type
if ( mouse_in_edit_area ) {
app_result . mouse_cursor_type = APP_MOUSE_CURSOR_ARROW ;
}
else if ( mouse_in_margin_area ) {
if ( mouse_on_divider ) {
if ( mouse_divider_vertical ) {
app_result . mouse_cursor_type = APP_MOUSE_CURSOR_LEFTRIGHT ;
}
else {
app_result . mouse_cursor_type = APP_MOUSE_CURSOR_UPDOWN ;
}
}
else {
app_result . mouse_cursor_type = APP_MOUSE_CURSOR_ARROW ;
}
}
models - > prev_mouse_panel = mouse_panel ;
app_result . lctrl_lalt_is_altgr = models - > settings . lctrl_lalt_is_altgr ;
app_result . perform_kill = ! models - > keep_playing ;
2018-03-10 02:06:55 +00:00
models - > frame_counter + = 1 ;
2016-06-29 17:16:08 +00:00
// end-of-app_step
2018-03-03 07:46:44 +00:00
return ( app_result ) ;
2016-06-29 17:16:08 +00:00
}
2017-01-03 20:05:35 +00:00
extern " C " App_Get_Functions_Sig ( app_get_functions ) {
2016-06-29 17:16:08 +00:00
App_Functions result = { } ;
result . read_command_line = app_read_command_line ;
result . init = app_init ;
result . step = app_step ;
return ( result ) ;
}
// BOTTOM