From 6575a1cccdc4ba6d89d4a5cbf426ad19325e179d Mon Sep 17 00:00:00 2001 From: Allen Webster Date: Tue, 1 Mar 2016 16:25:56 -0500 Subject: [PATCH] eliminated all view types except File_View --- 4coder_custom.cpp | 36 +- 4ed.cpp | 8988 +++++++++++++++++++------------------- 4ed.h | 9 - 4ed_app_target.cpp | 17 +- 4ed_color_view.cpp | 1909 -------- 4ed_config_view.cpp | 89 - 4ed_delay.cpp | 6 - 4ed_file.cpp | 62 +- 4ed_file_view.cpp | 994 ++++- 4ed_gui.cpp | 1322 +++++- 4ed_interactive_view.cpp | 233 - 4ed_layout.cpp | 61 +- 4ed_menu_view.cpp | 91 - 4ed_metagen.cpp | 4 - 4ed_version.h | 19 + win32_4ed.cpp | 3 +- 16 files changed, 6779 insertions(+), 7064 deletions(-) delete mode 100644 4ed_color_view.cpp delete mode 100644 4ed_config_view.cpp delete mode 100644 4ed_interactive_view.cpp delete mode 100644 4ed_menu_view.cpp create mode 100644 4ed_version.h diff --git a/4coder_custom.cpp b/4coder_custom.cpp index 6d26a92a..634f06df 100644 --- a/4coder_custom.cpp +++ b/4coder_custom.cpp @@ -72,11 +72,10 @@ CUSTOM_COMMAND_SIG(write_decrement){ app->buffer_replace_range(app, &buffer, buffer.buffer_cursor_pos, buffer.buffer_cursor_pos, text, size); } -CUSTOM_COMMAND_SIG(open_long_braces){ +static void +long_braces(Application_Links *app, char *text, int size){ File_View_Summary view; Buffer_Summary buffer; - char text[] = "{\n\n}"; - int size = sizeof(text) - 1; int pos; view = app->get_active_file_view(app); @@ -92,24 +91,22 @@ CUSTOM_COMMAND_SIG(open_long_braces){ exec_command(app, cmdid_auto_tab_range); } +CUSTOM_COMMAND_SIG(open_long_braces){ + char text[] = "{\n\n}"; + int size = sizeof(text) - 1; + long_braces(app, text, size); +} + CUSTOM_COMMAND_SIG(open_long_braces_semicolon){ - File_View_Summary view; - Buffer_Summary buffer; char text[] = "{\n\n};"; int size = sizeof(text) - 1; - int pos; - - view = app->get_active_file_view(app); - buffer = app->get_buffer(app, view.buffer_id); - - pos = view.cursor.pos; - app->buffer_replace_range(app, &buffer, pos, pos, text, size); - app->view_set_cursor(app, &view, seek_pos(pos + 2), 1); - - push_parameter(app, par_range_start, pos); - push_parameter(app, par_range_end, pos + size); - push_parameter(app, par_clear_blank_lines, 0); - exec_command(app, cmdid_auto_tab_range); + long_braces(app, text, size); +} + +CUSTOM_COMMAND_SIG(open_long_braces_break){ + char text[] = "{\n\n}break;"; + int size = sizeof(text) - 1; + long_braces(app, text, size); } CUSTOM_COMMAND_SIG(paren_wrap){ @@ -768,7 +765,8 @@ extern "C" GET_BINDING_DATA(get_bindings){ bind(context, '=', MDFR_CTRL, write_increment); bind(context, '-', MDFR_CTRL, write_decrement); bind(context, '[', MDFR_CTRL, open_long_braces); - bind(context, '{', MDFR_CTRL, open_long_braces); + bind(context, '{', MDFR_CTRL, open_long_braces_semicolon); + bind(context, '}', MDFR_CTRL, open_long_braces_break); bind(context, '9', MDFR_CTRL, paren_wrap); bind(context, 'i', MDFR_ALT, if0_off); diff --git a/4ed.cpp b/4ed.cpp index 0d6f9e2a..fa861119 100644 --- a/4ed.cpp +++ b/4ed.cpp @@ -1,4528 +1,4460 @@ -/* - * Mr. 4th Dimention - Allen Webster - * - * 12.12.2014 - * - * Application layer for project codename "4ed" - * - */ - -// TOP - -// App Structs - -enum App_State{ - APP_STATE_EDIT, - APP_STATE_RESIZING, - // never below this - APP_STATE_COUNT -}; - -struct App_State_Resizing{ - Panel_Divider *divider; - i32 min, max; -}; - -struct CLI_Process{ - CLI_Handles cli; - Editing_File *out_file; -}; - -struct CLI_List{ - CLI_Process *procs; - i32 count, max; -}; - -#define SysAppCreateView 0x1 -#define SysAppCreateNewBuffer 0x2 - -struct Sys_App_Binding{ - i32 sys_id; - i32 app_id; - - u32 success; - u32 fail; - Panel *panel; -}; - -struct Complete_State{ - Search_Set set; - Search_Iter iter; - Table hits; - String_Space str; - i32 word_start, word_end; - b32 initialized; -}; - -struct Command_Data{ - Mem_Options *mem; - Panel *panel; - View *view; - Working_Set *working_set; - Editing_Layout *layout; - Live_Views *live_set; - Style *style; - Delay *delay; - struct App_Vars *vars; - Exchange *exchange; - System_Functions *system; - Coroutine *current_coroutine; - - i32 screen_width, screen_height; - Key_Event_Data key; - - Partition part; -}; - -struct App_Vars{ - Mem_Options mem; - - App_Settings settings; - - Command_Map map_top; - Command_Map map_file; - Command_Map map_ui; -#if FRED_INTERNAL - Command_Map map_debug; -#endif - Command_Map *user_maps; - i32 *map_id_table; - i32 user_map_count; - Command_Binding prev_command; - - Coroutine *command_coroutine; - u32 command_coroutine_flags[2]; - - Sys_App_Binding *sys_app_bindings; - i32 sys_app_count, sys_app_max; - - Custom_Command_Function *hooks[hook_type_count]; - - Font_Set *font_set; - - Style style; - Style_Library styles; - u32 *palette; - i32 palette_size; - - Editing_Layout layout; - Live_Views live_set; - Working_Set working_set; - - char hot_dir_base_[256]; - Hot_Directory hot_directory; - - CLI_List cli_processes; - - Delay delay1, delay2; - - String mini_str; - u8 mini_buffer[512]; - - App_State state; - App_State_Resizing resizing; - Complete_State complete_state; - Panel *prev_mouse_panel; - - Command_Data command_data; - - Custom_API config_api; -}; - -internal i32 -app_get_or_add_map_index(App_Vars *vars, i32 mapid){ - i32 result; - i32 user_map_count = vars->user_map_count; - i32 *map_id_table = vars->map_id_table; - for (result = 0; result < user_map_count; ++result){ - if (map_id_table[result] == mapid) break; - if (map_id_table[result] == 0){ - map_id_table[result] = mapid; - break; - } - } - return result; -} - -internal i32 -app_get_map_index(App_Vars *vars, i32 mapid){ - i32 result; - i32 user_map_count = vars->user_map_count; - i32 *map_id_table = vars->map_id_table; - for (result = 0; result < user_map_count; ++result){ - if (map_id_table[result] == mapid) break; - if (map_id_table[result] == 0){ - result = user_map_count; - break; - } - } - return result; -} - -internal Command_Map* -app_get_map(App_Vars *vars, i32 mapid){ - Command_Map *map = 0; - if (mapid < mapid_global) map = vars->user_maps + mapid; - else if (mapid == mapid_global) map = &vars->map_top; - else if (mapid == mapid_file) map = &vars->map_file; - return map; -} - -// Commands - -globalvar Application_Links app_links; - -#define USE_MEM(n) Mem_Options *n = command->mem -#define USE_PANEL(n) Panel *n = command->panel -#define USE_VIEW(n) View *n = command->view -#define USE_FILE_VIEW(n) File_View *n = view_to_file_view(command->view) -#define USE_FILE(n,v) Editing_File *n = 0; if (v) { (n) = (v)->file; } -#define USE_WORKING_SET(n) Working_Set *n = command->working_set -#define USE_LAYOUT(n) Editing_Layout *n = command->layout -#define USE_LIVE_SET(n) Live_Views *live_set = command->live_set -#define USE_STYLE(n) Style *n = command->style -#define USE_DELAY(n) Delay *n = command->delay -#define USE_VARS(n) App_Vars *n = command->vars -#define USE_EXCHANGE(n) Exchange *n = command->exchange -#define USE_FONT_SET(n) Font_Set *n = command->vars->font_set; - -#define REQ_VIEW(n) View *n = command->view; if (!n) return -#define REQ_FILE_VIEW(n) File_View *n = view_to_file_view(command->view); if (!n) return -#define REQ_OPEN_FILE_VIEW(n) File_View *n = view_to_file_view(command->view); if (!n || n->locked) return -#define REQ_FILE_HISTORY(n,v) Editing_File *n = (v)->file; if (!n || !buffer_good(&n->state.buffer) || n->state.is_dummy || !n->state.undo.undo.edits) return -#define REQ_FILE_LOADING(n,v) Editing_File *n = (v)->file; if (!n || n->state.is_dummy) return -#define REQ_FILE(n,v) Editing_File *n = (v)->file; if (!n || !buffer_good(&n->state.buffer) || n->state.is_dummy) return -#define REQ_COLOR_VIEW(n) Color_View *n = view_to_color_view(command->view); if (!n) return -#define REQ_DBG_VIEW(n) Debug_View *n = view_to_debug_view(command->view); if (!n) return - -#define COMMAND_DECL(n) internal void command_##n(System_Functions *system, Command_Data *command, Command_Binding binding) -#define COMPOSE_DECL(n) internal void n(System_Functions *system, Command_Data *command, Command_Binding binding) - -struct Command_Parameter{ - i32 type; - union{ - struct{ - Dynamic param; - Dynamic value; - } param; - struct{ - i32 len; - char *str; - } inline_string; - }; -}; - -inline Command_Parameter* -param_next(Command_Parameter *param, Command_Parameter *end){ - Command_Parameter *result = param; - if (result->type == 0){ - ++result; - } - while (result->type != 0 && result < end){ - i32 len = result->inline_string.len; - len += sizeof(*result) - 1; - len -= (len % sizeof(*result)); - result = (Command_Parameter*)((char*)result + len + sizeof(*result)); - } - return result; -} - -inline Command_Parameter* -param_stack_first(Partition *part, Command_Parameter *end){ - Command_Parameter *result = (Command_Parameter*)part->base; - if (result->type != 0) result = param_next(result, end); - return result; -} - -inline Command_Parameter* -param_stack_end(Partition *part){ - return (Command_Parameter*)((char*)part->base + part->pos); -} - -COMMAND_DECL(null){ - AllowLocal(command); -} - -COMMAND_DECL(write_character){ - ProfileMomentFunction(); - REQ_OPEN_FILE_VIEW(view); - REQ_FILE(file, view); - USE_LAYOUT(layout); - USE_MEM(mem); - - char character; - i32 pos, next_cursor_pos; - - character = command->key.character; - if (character != 0){ - pos = view->cursor.pos; - next_cursor_pos = view->cursor.pos + 1; - view_replace_range(system, mem, view, layout, pos, pos, &character, 1, next_cursor_pos); - view_cursor_move(view, next_cursor_pos); - file->state.cursor_pos = view->cursor.pos; - } -} - -COMMAND_DECL(seek_whitespace_right){ - ProfileMomentFunction(); - REQ_FILE_VIEW(view); - REQ_FILE(file, view); - - i32 pos = buffer_seek_whitespace_right(&file->state.buffer, view->cursor.pos); - view_cursor_move(view, pos); -} - -COMMAND_DECL(seek_whitespace_left){ - ProfileMomentFunction(); - REQ_FILE_VIEW(view); - REQ_FILE(file, view); - - i32 pos = buffer_seek_whitespace_left(&file->state.buffer, view->cursor.pos); - view_cursor_move(view, pos); -} - -COMMAND_DECL(seek_whitespace_up){ - ProfileMomentFunction(); - REQ_FILE_VIEW(view); - REQ_FILE(file, view); - - i32 pos = buffer_seek_whitespace_up(&file->state.buffer, view->cursor.pos); - view_cursor_move(view, pos); -} - -COMMAND_DECL(seek_whitespace_down){ - ProfileMomentFunction(); - REQ_FILE_VIEW(view); - REQ_FILE(file, view); - - i32 pos = buffer_seek_whitespace_down(&file->state.buffer, view->cursor.pos); - view_cursor_move(view, pos); -} - -internal i32 -seek_token_left(Cpp_Token_Stack *tokens, i32 pos){ - Cpp_Get_Token_Result get = cpp_get_token(tokens, pos); - if (get.token_index == -1){ - get.token_index = 0; - } - - Cpp_Token *token = tokens->tokens + get.token_index; - if (token->start == pos && get.token_index > 0){ - --token; - } - - return token->start; -} - -internal i32 -seek_token_right(Cpp_Token_Stack *tokens, i32 pos){ - Cpp_Get_Token_Result get = cpp_get_token(tokens, pos); - if (get.in_whitespace){ - ++get.token_index; - } - if (get.token_index >= tokens->count){ - get.token_index = tokens->count-1; - } - - Cpp_Token *token = tokens->tokens + get.token_index; - return token->start + token->size; -} - -COMMAND_DECL(seek_token_left){ - ProfileMomentFunction(); - REQ_FILE_VIEW(view); - REQ_FILE(file, view); - - if (file->state.tokens_complete){ - i32 pos = seek_token_left(&file->state.token_stack, view->cursor.pos); - view_cursor_move(view, pos); - } -} - -COMMAND_DECL(seek_token_right){ - ProfileMomentFunction(); - REQ_FILE_VIEW(view); - REQ_FILE(file, view); - - if (file->state.tokens_complete){ - i32 pos = seek_token_right(&file->state.token_stack, view->cursor.pos); - view_cursor_move(view, pos); - } -} - -COMMAND_DECL(seek_white_or_token_right){ - ProfileMomentFunction(); - REQ_FILE_VIEW(view); - REQ_FILE(file, view); - - i32 token_pos, white_pos; - if (file->state.tokens_complete){ - token_pos = seek_token_right(&file->state.token_stack, view->cursor.pos); - } - else{ - token_pos = buffer_size(&file->state.buffer); - } - white_pos = buffer_seek_whitespace_right(&file->state.buffer, view->cursor.pos); - view_cursor_move(view, Min(token_pos, white_pos)); -} - -COMMAND_DECL(seek_white_or_token_left){ - ProfileMomentFunction(); - REQ_FILE_VIEW(view); - REQ_FILE(file, view); - - i32 token_pos, white_pos; - if (file->state.tokens_complete){ - token_pos = seek_token_left(&file->state.token_stack, view->cursor.pos); - } - else{ - token_pos = 0; - } - white_pos = buffer_seek_whitespace_left(&file->state.buffer, view->cursor.pos); - view_cursor_move(view, Max(token_pos, white_pos)); -} - -COMMAND_DECL(seek_alphanumeric_right){ - ProfileMomentFunction(); - REQ_FILE_VIEW(view); - REQ_FILE(file, view); - - i32 pos = buffer_seek_alphanumeric_right(&file->state.buffer, view->cursor.pos); - view_cursor_move(view, pos); -} - -COMMAND_DECL(seek_alphanumeric_left){ - ProfileMomentFunction(); - REQ_FILE_VIEW(view); - REQ_FILE(file, view); - - i32 pos = buffer_seek_alphanumeric_left(&file->state.buffer, view->cursor.pos); - view_cursor_move(view, pos); -} - -COMMAND_DECL(seek_alphanumeric_or_camel_right){ - ProfileMomentFunction(); - REQ_FILE_VIEW(view); - REQ_FILE(file, view); - - i32 pos = buffer_seek_alphanumeric_or_camel_right(&file->state.buffer, view->cursor.pos); - view_cursor_move(view, pos); -} - -COMMAND_DECL(seek_alphanumeric_or_camel_left){ - ProfileMomentFunction(); - REQ_FILE_VIEW(view); - REQ_FILE(file, view); - - i32 pos = buffer_seek_alphanumeric_or_camel_left(&file->state.buffer, view->cursor.pos); - view_cursor_move(view, pos); -} - -COMMAND_DECL(word_complete){ - ProfileMomentFunction(); - REQ_FILE_VIEW(view); - REQ_FILE(file, view); - USE_LAYOUT(layout); - USE_MEM(mem); - USE_VARS(vars); - USE_WORKING_SET(working_set); - - Partition *part = &mem->part; - General_Memory *general = &mem->general; - Complete_State *complete_state = &vars->complete_state; - Search_Range *ranges; - Search_Match match; - - Temp_Memory temp; - - Buffer_Type *buffer; - Buffer_Backify_Type loop; - char *data; - i32 end; - i32 size_of_buffer; - - i32 cursor_pos, word_start, word_end; - char c; - - char *spare; - i32 size; - - i32 buffer_count, i, j; - Editing_File *file_ptr; - - i32 match_size; - b32 do_init = 0; - - buffer = &file->state.buffer; - size_of_buffer = buffer_size(buffer); - - if (view->mode.rewrite != 2){ - do_init = 1; - } - view->next_mode.rewrite = 2; - - if (complete_state->initialized == 0){ - do_init = 1; - } - - if (do_init){ - word_end = view->cursor.pos; - word_start = word_end; - cursor_pos = word_end - 1; - - // TODO(allen): macros for these buffer loops and some method of breaking out of them. - for (loop = buffer_backify_loop(buffer, cursor_pos, 0); - buffer_backify_good(&loop); - buffer_backify_next(&loop)){ - end = loop.absolute_pos; - data = loop.data - loop.absolute_pos; - for (; cursor_pos >= end; --cursor_pos){ - c = data[cursor_pos]; - if (char_is_alpha(c)){ - word_start = cursor_pos; - } - else if (!char_is_numeric(c)){ - goto double_break; - } - } - } - double_break:; - - size = word_end - word_start; - - if (size == 0){ - complete_state->initialized = 0; - return; - } - - complete_state->initialized = 1; - search_iter_init(general, &complete_state->iter, size); - buffer_stringify(buffer, word_start, word_end, complete_state->iter.word.str); - complete_state->iter.word.size = size; - - buffer_count = working_set->file_index_count; - search_set_init(general, &complete_state->set, buffer_count + 1); - ranges = complete_state->set.ranges; - ranges[0].buffer = buffer; - ranges[0].start = 0; - ranges[0].size = word_start; - - ranges[1].buffer = buffer; - ranges[1].start = word_end; - ranges[1].size = size_of_buffer - word_end; - - file_ptr = working_set->files; - for (i = 0, j = 2; i < buffer_count; ++i, ++file_ptr){ - if (file_ptr != file && !file_ptr->state.is_dummy){ - ranges[j].buffer = &file_ptr->state.buffer; - ranges[j].start = 0; - ranges[j].size = buffer_size(ranges[j].buffer); - ++j; - } - } - complete_state->set.count = j; - - search_hits_init(general, &complete_state->hits, &complete_state->str, 100, Kbytes(4)); - search_hit_add(general, &complete_state->hits, &complete_state->str, - complete_state->iter.word.str, complete_state->iter.word.size); - - complete_state->word_start = word_start; - complete_state->word_end = word_end; - } - else{ - word_start = complete_state->word_start; - word_end = complete_state->word_end; - size = complete_state->iter.word.size; - } - - if (size > 0){ - for (;;){ - match = search_next_match(part, &complete_state->set, &complete_state->iter); - - if (match.found_match){ - temp = begin_temp_memory(part); - match_size = match.end - match.start; - spare = (char*)push_array(part, char, match_size); - buffer_stringify(match.buffer, match.start, match.end, spare); - - if (search_hit_add(general, &complete_state->hits, &complete_state->str, spare, match_size)){ - view_replace_range(system, mem, view, layout, word_start, word_end, spare, match_size, word_end); - - complete_state->word_end = word_start + match_size; - complete_state->set.ranges[1].start = word_start + match_size; - break; - } - end_temp_memory(temp); - } - else{ - complete_state->iter.pos = 0; - complete_state->iter.i = 0; - - search_hits_init(general, &complete_state->hits, &complete_state->str, 100, Kbytes(4)); - search_hit_add(general, &complete_state->hits, &complete_state->str, - complete_state->iter.word.str, complete_state->iter.word.size); - - match_size = complete_state->iter.word.size; - view_replace_range(system, mem, view, layout, word_start, word_end, - complete_state->iter.word.str, match_size, word_end); - - complete_state->word_end = word_start + match_size; - complete_state->set.ranges[1].start = word_start + match_size; - break; - } - } - } -} - -COMMAND_DECL(set_mark){ - ProfileMomentFunction(); - REQ_FILE_VIEW(view); - REQ_FILE(file, view); - - view->mark = (i32)view->cursor.pos; -} - -COMMAND_DECL(copy){ - ProfileMomentFunction(); - REQ_FILE_VIEW(view); - REQ_FILE(file, view); - USE_WORKING_SET(working_set); - USE_MEM(mem); - - // TODO(allen): deduplicate - int r_start = 0, r_end = 0; - int start_set = 0, end_set = 0; - - Command_Parameter *end = param_stack_end(&command->part); - Command_Parameter *param = param_stack_first(&command->part, end); - for (; param < end; param = param_next(param, end)){ - int p = dynamic_to_int(¶m->param.param); - switch (p){ - case par_range_start: - start_set = 1; - r_start = dynamic_to_int(¶m->param.value); - break; - - case par_range_end: - end_set = 1; - r_end = dynamic_to_int(¶m->param.value); - break; - } - } - - Range range = make_range(view->cursor.pos, view->mark); - if (start_set) range.start = r_start; - if (end_set) range.end = r_end; - if (range.start < range.end){ - clipboard_copy(system, &mem->general, working_set, range, file); - } -} - -COMMAND_DECL(cut){ - ProfileMomentFunction(); - REQ_OPEN_FILE_VIEW(view); - REQ_FILE(file, view); - USE_WORKING_SET(working_set); - USE_LAYOUT(layout); - USE_MEM(mem); - - // TODO(allen): deduplicate - int r_start = 0, r_end = 0; - int start_set = 0, end_set = 0; - - Command_Parameter *end = param_stack_end(&command->part); - Command_Parameter *param = param_stack_first(&command->part, end); - for (; param < end; param = param_next(param, end)){ - int p = dynamic_to_int(¶m->param.param); - switch (p){ - case par_range_start: - start_set = 1; - r_start = dynamic_to_int(¶m->param.value); - break; - - case par_range_end: - end_set = 1; - r_end = dynamic_to_int(¶m->param.value); - break; - } - } - - Range range = make_range(view->cursor.pos, view->mark); - if (start_set) range.start = r_start; - if (end_set) range.end = r_end; - if (range.start < range.end){ - i32 next_cursor_pos = range.start; - - clipboard_copy(system, &mem->general, working_set, range, file); - view_replace_range(system, mem, view, layout, range.start, range.end, 0, 0, next_cursor_pos); - - view->mark = range.start; - view_cursor_move(view, next_cursor_pos); - } -} - -COMMAND_DECL(paste){ - ProfileMomentFunction(); - REQ_OPEN_FILE_VIEW(view); - REQ_FILE(file, view); - USE_WORKING_SET(working_set); - USE_LAYOUT(layout); - USE_MEM(mem); - - Panel *current_panel; - String *src; - File_View *current_view; - i32 pos_left, next_cursor_pos; - i32 panel_count; - i32 i; - - if (working_set->clipboard_size > 0){ - view->next_mode.rewrite = 1; - - src = working_set_clipboard_head(working_set); - pos_left = view->cursor.pos; - - next_cursor_pos = pos_left+src->size; - view_replace_range(system, mem, view, layout, pos_left, pos_left, src->str, src->size, next_cursor_pos); - - view_cursor_move(view, next_cursor_pos); - view->mark = pos_left; - - current_panel = layout->panels; - panel_count = layout->panel_count; - for (i = 0; i < panel_count; ++i, ++current_panel){ - current_view = view_to_file_view(current_panel->view); - - if (current_view && current_view->file == file){ - view_post_paste_effect(current_view, 20, pos_left, src->size, - current_view->style->main.paste_color); - } - } - } -} - -COMMAND_DECL(paste_next){ - ProfileMomentFunction(); - REQ_OPEN_FILE_VIEW(view); - REQ_FILE(file, view); - USE_WORKING_SET(working_set); - USE_LAYOUT(layout); - USE_MEM(mem); - - if (working_set->clipboard_size > 0 && view->mode.rewrite == 1){ - view->next_mode.rewrite = 1; - - Range range = make_range(view->mark, view->cursor.pos); - String *src = working_set_clipboard_roll_down(working_set); - i32 next_cursor_pos = range.start+src->size; - view_replace_range(system, - mem, view, layout, range.start, range.end, - src->str, src->size, next_cursor_pos); - - view_cursor_move(view, next_cursor_pos); - view->mark = range.start; - - Editing_Layout *layout = command->layout; - Panel *panels = layout->panels; - i32 panel_count = layout->panel_count; - for (i32 i = 0; i < panel_count; ++i){ - Panel *current_panel = panels + i; - File_View *current_view = view_to_file_view(current_panel->view); - - if (current_view && current_view->file == file){ - view_post_paste_effect(current_view, 20, range.start, src->size, - current_view->style->main.paste_color); - } - } - } - else{ - command_paste(system, command, binding); - } -} - -COMMAND_DECL(delete_range){ - ProfileMomentFunction(); - REQ_OPEN_FILE_VIEW(view); - REQ_FILE(file, view); - USE_LAYOUT(layout); - USE_MEM(mem); - - Range range = make_range(view->cursor.pos, view->mark); - if (range.start < range.end){ - i32 next_cursor_pos = range.start; - view_replace_range(system, mem, view, layout, range.start, range.end, - 0, 0, next_cursor_pos); - view_cursor_move(view, next_cursor_pos); - view->mark = range.start; - } -} - -COMMAND_DECL(timeline_scrub){ - ProfileMomentFunction(); - REQ_FILE_VIEW(view); - REQ_FILE_HISTORY(file, view); - - view_set_widget(view, FWIDG_TIMELINES); - view->widget.timeline.undo_line = 1; - view->widget.timeline.history_line = 1; -} - -COMMAND_DECL(undo){ - ProfileMomentFunction(); - REQ_FILE_VIEW(view); - REQ_FILE_HISTORY(file, view); - USE_LAYOUT(layout); - USE_MEM(mem); - - view_undo(system, mem, layout, view); -} - -COMMAND_DECL(redo){ - ProfileMomentFunction(); - REQ_FILE_VIEW(view); - REQ_FILE_HISTORY(file, view); - USE_LAYOUT(layout); - USE_MEM(mem); - - view_redo(system, mem, layout, view); -} - -COMMAND_DECL(history_backward){ - ProfileMomentFunction(); - REQ_FILE_VIEW(view); - REQ_FILE_HISTORY(file, view); - USE_LAYOUT(layout); - USE_MEM(mem); - - view_history_step(system, mem, layout, view, hist_backward); -} - -COMMAND_DECL(history_forward){ - ProfileMomentFunction(); - REQ_FILE_VIEW(view); - REQ_FILE_HISTORY(file, view); - USE_LAYOUT(layout); - USE_MEM(mem); - - view_history_step(system, mem, layout, view, hist_forward); -} - -#if UseFileHistoryDump -COMMAND_DECL(save_history){ - ProfileMomentFunction(); - REQ_FILE_VIEW(view); - REQ_FILE(file, view); - USE_MEM(mem); - - file_dump_history(system, mem, file, "history_data.hst"); -} -#endif - -COMMAND_DECL(interactive_new){ - ProfileMomentFunction(); - USE_VARS(vars); - USE_LIVE_SET(live_set); - USE_PANEL(panel); - USE_MEM(mem); - USE_WORKING_SET(working_set); - USE_STYLE(style); - USE_DELAY(delay); - USE_EXCHANGE(exchange); - USE_FONT_SET(font_set); - - View *new_view = live_set_alloc_view(live_set, mem); - view_replace_minor(system, exchange, new_view, panel, live_set); - - new_view->map = &vars->map_ui; - Interactive_View *int_view = - interactive_view_init(system, new_view, &vars->hot_directory, - style, working_set, - font_set, delay); - int_view->interaction = INTV_SYS_FILE_LIST; - int_view->action = INTV_NEW; - copy(&int_view->query, "New: "); -} - -internal Sys_App_Binding* -app_push_file_binding(App_Vars *vars, int sys_id, int app_id){ - Sys_App_Binding *binding; - Assert(vars->sys_app_count < vars->sys_app_max); - binding = vars->sys_app_bindings + vars->sys_app_count++; - binding->sys_id = sys_id; - binding->app_id = app_id; - return(binding); -} - -struct App_Open_File_Result{ - Editing_File *file; - i32 sys_id; - i32 file_index; - b32 is_new; -}; - -internal App_Open_File_Result -app_open_file_background(App_Vars *vars, Exchange *exchange, Working_Set *working_set, String filename){ - Get_File_Result file; - i32 file_id; - App_Open_File_Result result = {}; - - result.file = working_set_contains(working_set, filename); - if (result.file == 0){ - result.is_new = 1; - file = working_set_get_available_file(working_set); - if (file.file){ - result.file = file.file; - file_id = exchange_request_file(exchange, filename.str, filename.size); - if (file_id){ - file_init_strings(result.file); - file_set_name(working_set, result.file, filename.str); - file_set_to_loading(result.file); - table_add(&working_set->table, result.file->name.source_path, file.index); - - result.sys_id = file_id; - result.file_index = file.index; - } - else{ - file_get_dummy(file.file); - } - } - } - - return(result); -} - -COMMAND_DECL(interactive_open){ - ProfileMomentFunction(); - USE_VARS(vars); - USE_LIVE_SET(live_set); - USE_PANEL(panel); - USE_MEM(mem); - USE_WORKING_SET(working_set); - USE_STYLE(style); - USE_DELAY(delay); - USE_EXCHANGE(exchange); - USE_FONT_SET(font_set); - - char *filename = 0; - int filename_len = 0; - int do_in_background = 0; - - Command_Parameter *end = param_stack_end(&command->part); - Command_Parameter *param = param_stack_first(&command->part, end); - for (; param < end; param = param_next(param, end)){ - if (param->param.param.type == dynamic_type_int){ - if (param->param.param.int_value == par_name && - param->param.value.type == dynamic_type_string){ - filename = param->param.value.str_value; - filename_len = param->param.value.str_len; - } - else if (param->param.param.int_value == par_do_in_background){ - do_in_background = dynamic_to_int(¶m->param.value); - } - } - } - - if (filename){ - String string = make_string(filename, filename_len); - if (do_in_background){ - delayed_open_background(delay, string); - } - else{ - delayed_open(delay, string, panel); - } - } - else{ - View *new_view = live_set_alloc_view(live_set, mem); - view_replace_minor(system, exchange, new_view, panel, live_set); - - new_view->map = &vars->map_ui; - Interactive_View *int_view = - interactive_view_init(system, new_view, &vars->hot_directory, - style, working_set, font_set, delay); - int_view->interaction = INTV_SYS_FILE_LIST; - int_view->action = INTV_OPEN; - copy(&int_view->query, "Open: "); - } -} - -internal void -panel_make_empty(System_Functions *system, Exchange *exchange, - App_Vars *vars, Style *style, Panel *panel){ - - Mem_Options *mem = &vars->mem; - Live_Views *live_set = &vars->live_set; - Editing_Layout *layout = &vars->layout; - - View *new_view; - File_View *file_view; - - new_view = live_set_alloc_view(live_set, mem); - if (panel->view){ - view_replace_major(system, exchange, new_view, panel, live_set); - } - else{ - view_set_first(new_view, panel); - } - file_view = file_view_init(new_view, layout); - view_set_file(file_view, 0, vars->font_set, style, 0, 0, 0); - new_view->map = app_get_map(vars, mapid_global); -} - -internal void -view_file_in_panel(Command_Data *cmd, Panel *panel, Editing_File *file){ - Live_Views *live_set = cmd->live_set; - Mem_Options *mem = cmd->mem; - Exchange *exchange = cmd->exchange; - System_Functions *system = cmd->system; - Editing_Layout *layout = cmd->layout; - App_Vars *vars = cmd->vars; - Style *style = cmd->style; - - Partition old_part; - Temp_Memory temp; - View *new_view, *old_view; - File_View *file_view; - - new_view = live_set_alloc_view(live_set, mem); - view_replace_major(system, exchange, new_view, panel, live_set); - - file_view = file_view_init(new_view, layout); - - old_view = cmd->view; - cmd->view = new_view; - - old_part = cmd->part; - temp = begin_temp_memory(&mem->part); - cmd->part = partition_sub_part(&mem->part, Kbytes(16)); - - view_set_file(file_view, file, vars->font_set, style, - system, vars->hooks[hook_open_file], &app_links); - - cmd->part = old_part; - end_temp_memory(temp); - cmd->view = old_view; - - new_view->map = app_get_map(vars, file->settings.base_map_id); -} - -// TODO(allen): Improvements to reopen -// - Preserve existing token stack -// - Keep current version open and do some sort of diff to keep -// the cursor position correct -COMMAND_DECL(reopen){ - ProfileMomentFunction(); - REQ_FILE_VIEW(view); - REQ_FILE(file, view); - USE_EXCHANGE(exchange); - USE_WORKING_SET(working_set); - USE_VARS(vars); - USE_STYLE(style); - - i32 file_id = exchange_request_file(exchange, expand_str(file->name.source_path)); - i32 index = 0; - if (file_id){ - file_set_to_loading(file); - index = working_set_get_index(working_set, file); - app_push_file_binding(vars, file_id, index); - - view_set_file(view, file, vars->font_set, style, - system, vars->hooks[hook_open_file], &app_links); - } - else{ - // TODO(allen): feedback message - } -} - -COMMAND_DECL(save){ - ProfileMomentFunction(); - USE_FILE_VIEW(view); - USE_FILE(file, view); - USE_DELAY(delay); - USE_WORKING_SET(working_set); - - char *filename = 0; - int filename_len = 0; - int buffer_id = -1; - - Command_Parameter *end = param_stack_end(&command->part); - Command_Parameter *param = param_stack_first(&command->part, end); - for (; param < end; param = param_next(param, end)){ - int v = dynamic_to_int(¶m->param.param); - if (v == par_name && param->param.value.type == dynamic_type_string){ - filename = param->param.value.str_value; - filename_len = param->param.value.str_len; - } - else if (v == par_buffer_id && param->param.value.type == dynamic_type_int){ - buffer_id = dynamic_to_int(¶m->param.value); - } - } - - String name = {}; - if (filename){ - name = make_string(filename, filename_len); - } - else if (file){ - name = file->name.source_path; - } - - if (name.size != 0){ - if (buffer_id == -1){ - if (file){ - delayed_save(delay, name, file); - } - } - else{ - file = working_set->files + buffer_id; - - if (!file->state.is_dummy && file_is_ready(file)){ - delayed_save(delay, name, file); - } - else{ - delayed_save(delay, name); - } - } - } -} - -COMMAND_DECL(interactive_save_as){ - ProfileMomentFunction(); - USE_VARS(vars); - USE_LIVE_SET(live_set); - USE_PANEL(panel); - USE_MEM(mem); - USE_WORKING_SET(working_set); - USE_STYLE(style); - USE_DELAY(delay); - USE_EXCHANGE(exchange); - USE_FONT_SET(font_set); - - View *new_view = live_set_alloc_view(live_set, mem); - view_replace_minor(system, exchange, new_view, panel, live_set); - - new_view->map = &vars->map_ui; - Interactive_View *int_view = - interactive_view_init(system, new_view, &vars->hot_directory, style, - working_set, font_set, delay); - int_view->interaction = INTV_SYS_FILE_LIST; - int_view->action = INTV_SAVE_AS; - copy(&int_view->query, "Save As: "); -} - -COMMAND_DECL(change_active_panel){ - ProfileMomentFunction(); - USE_LAYOUT(layout); - if (layout->panel_count > 1){ - ++layout->active_panel; - if (layout->active_panel >= layout->panel_count){ - layout->active_panel = 0; - } - } -} - -COMMAND_DECL(interactive_switch_buffer){ - ProfileMomentFunction(); - USE_VARS(vars); - USE_LIVE_SET(live_set); - USE_PANEL(panel); - USE_MEM(mem); - USE_WORKING_SET(working_set); - USE_STYLE(style); - USE_DELAY(delay); - USE_EXCHANGE(exchange); - USE_FONT_SET(font_set); - - View *new_view = live_set_alloc_view(live_set, mem); - view_replace_minor(system, exchange, new_view, panel, live_set); - - new_view->map = &vars->map_ui; - Interactive_View *int_view = - interactive_view_init(system, new_view, &vars->hot_directory, style, - working_set, font_set, delay); - int_view->interaction = INTV_LIVE_FILE_LIST; - int_view->action = INTV_SWITCH; - copy(&int_view->query, "Switch File: "); -} - -COMMAND_DECL(interactive_kill_buffer){ - ProfileMomentFunction(); - USE_VARS(vars); - USE_LIVE_SET(live_set); - USE_PANEL(panel); - USE_MEM(mem); - USE_WORKING_SET(working_set); - USE_STYLE(style); - USE_DELAY(delay); - USE_EXCHANGE(exchange); - USE_FONT_SET(font_set); - - View *new_view = live_set_alloc_view(live_set, mem); - view_replace_minor(system, exchange, new_view, panel, live_set); - - new_view->map = &vars->map_ui; - Interactive_View *int_view = - interactive_view_init(system, new_view, &vars->hot_directory, style, - working_set, font_set, delay); - int_view->interaction = INTV_LIVE_FILE_LIST; - int_view->action = INTV_KILL; - copy(&int_view->query, "Kill File: "); -} - -COMMAND_DECL(kill_buffer){ - ProfileMomentFunction(); - REQ_FILE_VIEW(view); - REQ_FILE(file, view); - USE_DELAY(delay); - - delayed_try_kill(delay, file->name.live_name, view->view_base.panel); -} - -COMMAND_DECL(toggle_line_wrap){ - ProfileMomentFunction(); - REQ_FILE_VIEW(view); - REQ_FILE(file, view); - - Relative_Scrolling scrolling = view_get_relative_scrolling(view); - if (view->unwrapped_lines){ - view->unwrapped_lines = 0; - file->settings.unwrapped_lines = 0; - view->target_x = 0; - view->cursor = - view_compute_cursor_from_pos(view, view->cursor.pos); - view->preferred_x = view->cursor.wrapped_x; - } - else{ - view->unwrapped_lines = 1; - file->settings.unwrapped_lines = 1; - view->cursor = - view_compute_cursor_from_pos(view, view->cursor.pos); - view->preferred_x = view->cursor.unwrapped_x; - } - view_set_relative_scrolling(view, scrolling); -} - -COMMAND_DECL(toggle_show_whitespace){ - ProfileMomentFunction(); - REQ_FILE_VIEW(view); - view->show_whitespace = !view->show_whitespace; -} - -COMMAND_DECL(toggle_tokens){ -#if BUFFER_EXPERIMENT_SCALPEL <= 0 - ProfileMomentFunction(); - REQ_FILE_VIEW(view); - REQ_FILE(file, view); - USE_MEM(mem); - - if (file->settings.tokens_exist){ - file_kill_tokens(system, &mem->general, file); - } - else{ - file_first_lex_parallel(system, &mem->general, file); - } -#endif -} - -internal void -case_change_range(System_Functions *system, - Mem_Options *mem, File_View *view, Editing_File *file, - u8 a, u8 z, u8 char_delta){ -#if BUFFER_EXPERIMENT_SCALPEL <= 0 - Range range = make_range(view->cursor.pos, view->mark); - 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; - - if (file->state.still_lexing) - system->cancel_job(BACKGROUND_THREADS, file->state.lex_job); - - file_update_history_before_edit(mem, file, step, 0, hist_normal); - - u8 *data = (u8*)file->state.buffer.data; - for (i32 i = range.start; i < range.end; ++i){ - if (data[i] >= a && data[i] <= z){ - data[i] += char_delta; - } - } - - if (file->state.token_stack.tokens) - file_relex_parallel(system, mem, file, range.start, range.end, 0); - } -#endif -} - -COMMAND_DECL(to_uppercase){ - ProfileMomentFunction(); - REQ_FILE_VIEW(view); - REQ_FILE(file, view); - USE_MEM(mem); - case_change_range(system, mem, view, file, 'a', 'z', (u8)('A' - 'a')); -} - -COMMAND_DECL(to_lowercase){ - ProfileMomentFunction(); - REQ_FILE_VIEW(view); - REQ_FILE(file, view); - USE_MEM(mem); - case_change_range(system, mem, view, file, 'A', 'Z', (u8)('a' - 'A')); -} - -COMMAND_DECL(clean_all_lines){ - ProfileMomentFunction(); - REQ_FILE_VIEW(view); - REQ_FILE(file, view); - USE_LAYOUT(layout); - USE_MEM(mem); - - view_clean_whitespace(system, mem, view, layout); -} - -COMMAND_DECL(eol_dosify){ - ProfileMomentFunction(); - REQ_FILE_VIEW(view); - REQ_FILE(file, view); - - file->settings.dos_write_mode = 1; - file->state.last_4ed_edit_time = system->time(); -} - -COMMAND_DECL(eol_nixify){ - ProfileMomentFunction(); - REQ_FILE_VIEW(view); - REQ_FILE(file, view); - - file->settings.dos_write_mode = 0; - file->state.last_4ed_edit_time = system->time(); -} - -COMMAND_DECL(auto_tab_range){ - ProfileMomentFunction(); - REQ_FILE_VIEW(view); - REQ_FILE(file, view); - USE_LAYOUT(layout); - USE_MEM(mem); - - int r_start = 0, r_end = 0; - int start_set = 0, end_set = 0; - int clear_blank_lines = 1; - - // TODO(allen): deduplicate - Command_Parameter *end = param_stack_end(&command->part); - Command_Parameter *param = param_stack_first(&command->part, end); - for (; param < end; param = param_next(param, end)){ - int p = dynamic_to_int(¶m->param.param); - switch (p){ - case par_range_start: - start_set = 1; - r_start = dynamic_to_int(¶m->param.value); - break; - - case par_range_end: - end_set = 1; - r_end = dynamic_to_int(¶m->param.value); - break; - - case par_clear_blank_lines: - clear_blank_lines = dynamic_to_bool(¶m->param.value); - break; - } - } - - if (file->state.token_stack.tokens && file->state.tokens_complete){ - Range range = make_range(view->cursor.pos, view->mark); - if (start_set) range.start = r_start; - if (end_set) range.end = r_end; - view_auto_tab_tokens(system, mem, view, layout, range.start, range.end, clear_blank_lines); - } -} - -COMMAND_DECL(auto_tab_line_at_cursor){ - ProfileMomentFunction(); - REQ_FILE_VIEW(view); - REQ_FILE(file, view); - USE_LAYOUT(layout); - USE_MEM(mem); - - int clear_blank_lines = 0; - - Command_Parameter *end = param_stack_end(&command->part); - Command_Parameter *param = param_stack_first(&command->part, end); - for (; param < end; param = param_next(param, end)){ - int p = dynamic_to_int(¶m->param.param); - switch (p){ - case par_clear_blank_lines: - clear_blank_lines = dynamic_to_bool(¶m->param.value); - break; - } - } - - if (file->state.token_stack.tokens && file->state.tokens_complete){ - i32 pos = view->cursor.pos; - view_auto_tab_tokens(system, mem, view, layout, pos, pos, clear_blank_lines); - } -} - -COMMAND_DECL(auto_tab_whole_file){ - ProfileMomentFunction(); - REQ_FILE_VIEW(view); - REQ_FILE(file, view); - USE_LAYOUT(layout); - USE_MEM(mem); - - if (file->state.token_stack.tokens && file->state.tokens_complete){ - view_auto_tab_tokens(system, mem, view, layout, 0, buffer_size(&file->state.buffer), 1); - } -} - -COMMAND_DECL(open_panel_vsplit){ - ProfileMomentFunction(); - USE_LAYOUT(layout); - USE_PANEL(panel); - USE_EXCHANGE(exchange); - USE_VARS(vars); - USE_STYLE(style); - - if (layout->panel_count < layout->panel_max_count){ - Split_Result split = layout_split_panel(layout, panel, 1); - - Panel *panel1 = panel; - Panel *panel2 = split.panel; - - panel2->screen_region = panel1->screen_region; - - panel2->full.x0 = split.divider->pos; - panel2->full.x1 = panel1->full.x1; - panel1->full.x1 = split.divider->pos; - - panel_fix_internal_area(panel1); - panel_fix_internal_area(panel2); - panel2->prev_inner = panel2->inner; - - layout->active_panel = (i32)(panel2 - layout->panels); - panel_make_empty(system, exchange, vars, style, panel2); - } -} - -COMMAND_DECL(open_panel_hsplit){ - ProfileMomentFunction(); - USE_LAYOUT(layout); - USE_PANEL(panel); - USE_EXCHANGE(exchange); - USE_VARS(vars); - USE_STYLE(style); - - if (layout->panel_count < layout->panel_max_count){ - Split_Result split = layout_split_panel(layout, panel, 0); - - Panel *panel1 = panel; - Panel *panel2 = split.panel; - - panel2->screen_region = panel1->screen_region; - - panel2->full.y0 = split.divider->pos; - panel2->full.y1 = panel1->full.y1; - panel1->full.y1 = split.divider->pos; - - panel_fix_internal_area(panel1); - panel_fix_internal_area(panel2); - panel2->prev_inner = panel2->inner; - - layout->active_panel = (i32)(panel2 - layout->panels); - panel_make_empty(system, exchange, vars, style, panel2); - } -} - -COMMAND_DECL(close_panel){ - ProfileMomentFunction(); - USE_LAYOUT(layout); - USE_PANEL(panel); - USE_VIEW(view); - USE_EXCHANGE(exchange); - - if (layout->panel_count > 1){ - if (view){ - live_set_free_view(system, exchange, command->live_set, view); - panel->view = 0; - } - - Divider_And_ID div = layout_get_divider(layout, panel->parent); - Assert(div.divider->child1 == -1 || div.divider->child2 == -1); - - i32 child; - if (div.divider->child1 == -1){ - child = div.divider->child2; - } - else{ - child = div.divider->child1; - } - - i32 parent = div.divider->parent; - i32 which_child = div.divider->which_child; - if (parent != -1){ - Divider_And_ID par = layout_get_divider(layout, parent); - if (which_child == -1){ - par.divider->child1 = child; - } - else{ - par.divider->child2 = child; - } - } - else{ - Assert(layout->root == div.id); - layout->root = child; - } - - if (child != -1){ - Divider_And_ID chi = layout_get_divider(layout, child); - chi.divider->parent = parent; - chi.divider->which_child = div.divider->which_child; - } - - layout_free_divider(layout, div.divider); - layout_free_panel(layout, panel); - - if (child == -1){ - panel = layout->panels; - layout->active_panel = -1; - for (i32 i = 0; i < layout->panel_count; ++i){ - if (panel->parent == div.id){ - panel->parent = parent; - panel->which_child = which_child; - layout->active_panel = i; - break; - } - ++panel; - } - Assert(layout->active_panel != -1); - } - else{ - layout->active_panel = layout->active_panel % layout->panel_count; - } - - layout_fix_all_panels(layout); - } -} - -COMMAND_DECL(move_left){ - ProfileMomentFunction(); - REQ_FILE_VIEW(view); - REQ_FILE(file, view); - - i32 pos = view->cursor.pos; - if (pos > 0) --pos; - view_cursor_move(view, pos); -} - -COMMAND_DECL(move_right){ - ProfileMomentFunction(); - REQ_FILE_VIEW(view); - REQ_FILE(file, view); - - i32 size = buffer_size(&file->state.buffer); - i32 pos = view->cursor.pos; - if (pos < size) ++pos; - view_cursor_move(view, pos); -} - -COMMAND_DECL(delete){ - ProfileMomentFunction(); - REQ_OPEN_FILE_VIEW(view); - REQ_FILE(file, view); - USE_LAYOUT(layout); - USE_MEM(mem); - - i32 size = buffer_size(&file->state.buffer); - i32 cursor_pos = view->cursor.pos; - if (0 < size && cursor_pos < size){ - i32 start, end; - start = cursor_pos; - end = cursor_pos+1; - - Assert(end - start > 0); - - i32 next_cursor_pos = start; - view_replace_range(system, mem, view, layout, start, end, 0, 0, next_cursor_pos); - view_cursor_move(view, next_cursor_pos); - } -} - -COMMAND_DECL(backspace){ - ProfileMomentFunction(); - REQ_OPEN_FILE_VIEW(view); - REQ_FILE(file, view); - USE_LAYOUT(layout); - USE_MEM(mem); - - i32 size = buffer_size(&file->state.buffer); - i32 cursor_pos = view->cursor.pos; - if (cursor_pos > 0 && cursor_pos <= size){ - i32 start, end; - end = cursor_pos; - start = cursor_pos-1; - - i32 shift = (end - start); - Assert(shift > 0); - - i32 next_cursor_pos = view->cursor.pos - shift; - view_replace_range(system, mem, view, layout, start, end, 0, 0, next_cursor_pos); - view_cursor_move(view, next_cursor_pos); - } -} - -COMMAND_DECL(move_up){ - ProfileMomentFunction(); - REQ_FILE_VIEW(view); - REQ_FILE(file, view); - USE_FONT_SET(font_set); - - f32 font_height = (f32)get_font_info(font_set, view->style->font_id)->height; - f32 cy = view_get_cursor_y(view)-font_height; - f32 px = view->preferred_x; - if (cy >= 0){ - view->cursor = view_compute_cursor_from_xy(view, px, cy); - file->state.cursor_pos = view->cursor.pos; - } -} - -COMMAND_DECL(move_down){ - ProfileMomentFunction(); - REQ_FILE_VIEW(view); - REQ_FILE(file, view); - USE_FONT_SET(font_set); - - f32 font_height = (f32)get_font_info(font_set, view->style->font_id)->height; - f32 cy = view_get_cursor_y(view)+font_height; - f32 px = view->preferred_x; - view->cursor = view_compute_cursor_from_xy(view, px, cy); - file->state.cursor_pos = view->cursor.pos; -} - -COMMAND_DECL(seek_end_of_line){ - ProfileMomentFunction(); - REQ_FILE_VIEW(view); - REQ_FILE(file, view); - - i32 pos = view_find_end_of_line(view, view->cursor.pos); - view_cursor_move(view, pos); -} - -COMMAND_DECL(seek_beginning_of_line){ - ProfileMomentFunction(); - REQ_FILE_VIEW(view); - REQ_FILE(file, view); - - i32 pos = view_find_beginning_of_line(view, view->cursor.pos); - view_cursor_move(view, pos); -} - -COMMAND_DECL(page_down){ - ProfileMomentFunction(); - REQ_FILE_VIEW(view); - - f32 height = view_compute_height(view); - f32 max_target_y = view_compute_max_target_y(view); - - view->target_y += height; - if (view->target_y > max_target_y) view->target_y = max_target_y; - - view->cursor = view_compute_cursor_from_xy( - view, 0, view->target_y + (height - view->font_height)*.5f); -} - -COMMAND_DECL(page_up){ - ProfileMomentFunction(); - REQ_FILE_VIEW(view); - - f32 height = view_compute_height(view); - - view->target_y -= height; - if (view->target_y < 0) view->target_y = 0; - - view->cursor = view_compute_cursor_from_xy( - view, 0, view->target_y + (height - view->font_height)*.5f); -} - -inline void -open_theme_options(System_Functions *system, Exchange *exchange, - App_Vars *vars, Live_Views *live_set, Mem_Options *mem, Panel *panel){ - View *new_view = live_set_alloc_view(live_set, mem); - view_replace_minor(system, exchange, new_view, panel, live_set); - - new_view->map = &vars->map_ui; - Color_View *color_view = color_view_init(new_view, &vars->working_set); - color_view->hot_directory = &vars->hot_directory; - color_view->main_style = &vars->style; - color_view->styles = &vars->styles; - color_view->palette = vars->palette; - color_view->palette_size = vars->palette_size; - color_view->font_set = vars->font_set; -} - -COMMAND_DECL(open_color_tweaker){ - ProfileMomentFunction(); - USE_VARS(vars); - USE_LIVE_SET(live_set); - USE_MEM(mem); - USE_PANEL(panel); - USE_EXCHANGE(exchange); - - open_theme_options(system, exchange, vars, live_set, mem, panel); -} - -inline void -open_config_options(System_Functions *system, Exchange *exchange, - App_Vars *vars, Live_Views *live_set, Mem_Options *mem, Panel *panel){ - View *new_view = live_set_alloc_view(live_set, mem); - view_replace_minor(system, exchange, new_view, panel, live_set); - - new_view->map = &vars->map_ui; - config_view_init(new_view, &vars->style, - &vars->working_set, vars->font_set, - &vars->settings); -} - -COMMAND_DECL(open_config){ - ProfileMomentFunction(); - USE_VARS(vars); - USE_LIVE_SET(live_set); - USE_MEM(mem); - USE_PANEL(panel); - USE_EXCHANGE(exchange); - - open_config_options(system, exchange, vars, live_set, mem, panel); -} - -COMMAND_DECL(open_menu){ - ProfileMomentFunction(); - USE_VARS(vars); - USE_LIVE_SET(live_set); - USE_PANEL(panel); - USE_MEM(mem); - USE_WORKING_SET(working_set); - USE_STYLE(style); - USE_EXCHANGE(exchange); - - View *new_view = live_set_alloc_view(live_set, mem); - view_replace_minor(system, exchange, new_view, panel, live_set); - - new_view->map = &vars->map_ui; - Menu_View *menu_view = menu_view_init(new_view, style, working_set, - &vars->delay1, vars->font_set); - AllowLocal(menu_view); -} - -COMMAND_DECL(close_minor_view){ - ProfileMomentFunction(); - REQ_VIEW(view); - USE_PANEL(panel); - USE_LIVE_SET(live_set); - USE_EXCHANGE(exchange); - - view_remove_minor(system, exchange, panel, live_set); -} - -COMMAND_DECL(cursor_mark_swap){ - ProfileMomentFunction(); - REQ_FILE_VIEW(view); - - i32 pos = view->cursor.pos; - view_cursor_move(view, view->mark); - view->mark = pos; -} - -COMMAND_DECL(user_callback){ - ProfileMomentFunction(); - if (binding.custom) binding.custom(&app_links); -} - -COMMAND_DECL(set_settings){ - ProfileMomentFunction(); - REQ_FILE_VIEW(view); - REQ_FILE_LOADING(file, view); - USE_VARS(vars); - USE_MEM(mem); - - Command_Parameter *end = param_stack_end(&command->part); - Command_Parameter *param = param_stack_first(&command->part, end); - for (; param < end; param = param_next(param, end)){ - int p = dynamic_to_int(¶m->param.param); - switch (p){ - case par_lex_as_cpp_file: - { -#if BUFFER_EXPERIMENT_SCALPEL <= 0 - int v = dynamic_to_bool(¶m->param.value); - if (file->settings.tokens_exist){ - if (!v) file_kill_tokens(system, &mem->general, file); - } - else{ - if (v) file_first_lex_parallel(system, &mem->general, file); - } -#endif - }break; - - case par_wrap_lines: - { - int v = dynamic_to_bool(¶m->param.value); - if (view->unwrapped_lines){ - if (v){ - view->unwrapped_lines = 0; - file->settings.unwrapped_lines = 0; - - if (!file->state.is_loading){ - Relative_Scrolling scrolling = view_get_relative_scrolling(view); - view->target_x = 0; - view->cursor = - view_compute_cursor_from_pos(view, view->cursor.pos); - view_set_relative_scrolling(view, scrolling); - } - } - } - else{ - if (!v){ - view->unwrapped_lines = 1; - file->settings.unwrapped_lines = 1; - - if (!file->state.is_loading){ - Relative_Scrolling scrolling = view_get_relative_scrolling(view); - view->cursor = - view_compute_cursor_from_pos(view, view->cursor.pos); - view_set_relative_scrolling(view, scrolling); - } - } - } - }break; - - case par_key_mapid: - { - int v = dynamic_to_int(¶m->param.value); - if (v == mapid_global) file->settings.base_map_id = mapid_global; - else if (v == mapid_file) file->settings.base_map_id = mapid_file; - else if (v < mapid_global){ - int index = app_get_map_index(vars, v); - if (index < vars->user_map_count) file->settings.base_map_id = v; - else file->settings.base_map_id = mapid_file; - } - }break; - } - } -} - -#define CLI_OverlapWithConflict (1<<0) -#define CLI_AlwaysBindToView (2<<0) - -internal void -build(System_Functions *system, Mem_Options *mem, - App_Vars *vars, Working_Set *working_set, - Font_Set *font_set, Style *style, - Live_Views *live_set, Exchange *exchange, - Panel *panel, Command_Data *command, - String hot_directory, - char *buffer_name, i32 buffer_name_len, - char *path, i32 path_len, - char *script, i32 script_len, - u32 flags){ - if (buffer_name == 0 || path == 0 || script == 0){ - return; - } - - if (vars->cli_processes.count < vars->cli_processes.max){ - Editing_Layout *layout = &vars->layout; - Editing_File *file = working_set_contains(working_set, make_string_slowly(buffer_name)); - i32 index; - b32 bind_to_new_view = 1; - - if (!file){ - Get_File_Result get_file = working_set_get_available_file(working_set); - file = get_file.file; - index = get_file.index; - } - else{ - i32 proc_count = vars->cli_processes.count; - for (i32 i = 0; i < proc_count; ++i){ - if (vars->cli_processes.procs[i].out_file == file){ - if (flags & CLI_OverlapWithConflict) - vars->cli_processes.procs[i].out_file = 0; - else file = 0; - break; - } - } - index = (i32)(file - vars->working_set.files); - if (file){ - if (!(flags & CLI_AlwaysBindToView)){ - Panel *panel = layout->panels; - for (i32 i = 0; i < layout->panel_count; ++i, ++panel){ - File_View *fview = view_to_file_view(panel->view); - if (fview && fview->file == file){ - bind_to_new_view = 0; - break; - } - } - } - } - } - - if (file){ - file_create_super_locked(system, mem, working_set, file, buffer_name, font_set, style->font_id); - file->settings.unimportant = 1; - table_add(&working_set->table, file->name.source_path, index); - - if (bind_to_new_view){ - view_file_in_panel(command, panel, file); - } - - i32 i = vars->cli_processes.count++; - CLI_Process *proc = vars->cli_processes.procs + i; - if (!system->cli_call(path, script, &proc->cli)){ - --vars->cli_processes.count; - } - proc->out_file = file; - } - else{ - // TODO(allen): feedback message - no available file - } - } - else{ - // TODO(allen): feedback message - no available process slot - } -} - -COMMAND_DECL(command_line){ - ProfileMomentFunction(); - USE_VARS(vars); - USE_MEM(mem); - USE_WORKING_SET(working_set); - USE_STYLE(style); - USE_LIVE_SET(live_set); - USE_PANEL(panel); - USE_EXCHANGE(exchange); - USE_FONT_SET(font_set); - - char *buffer_name = 0; - char *path = 0; - char *script = 0; - - int buffer_name_len = 0; - int path_len = 0; - int script_len = 0; - u32 flags = CLI_OverlapWithConflict; - - Command_Parameter *end = param_stack_end(&command->part); - Command_Parameter *param = param_stack_first(&command->part, end); - for (; param < end; param = param_next(param, end)){ - int p = dynamic_to_int(¶m->param.param); - switch (p){ - case par_name: - { - if (buffer_name == 0){ - char *new_buffer_name = dynamic_to_string(¶m->param.value, &buffer_name_len); - if (new_buffer_name){ - buffer_name = new_buffer_name; - } - } - }break; - - case par_cli_path: - { - if (path == 0){ - char *new_cli_path = dynamic_to_string(¶m->param.value, &path_len); - if (new_cli_path){ - path = new_cli_path; - } - } - }break; - - case par_cli_command: - { - if (script == 0){ - char *new_command = dynamic_to_string(¶m->param.value, &script_len); - if (new_command){ - script = new_command; - } - } - }break; - - case par_cli_overlap_with_conflict: - { - if (dynamic_to_int(¶m->param.value)) - flags |= CLI_OverlapWithConflict; - else - flags &= (~CLI_OverlapWithConflict); - }break; - - case par_cli_always_bind_to_view: - { - if (dynamic_to_int(¶m->param.value)) - flags |= CLI_OverlapWithConflict; - else - flags &= (~CLI_OverlapWithConflict); - }break; - } - } - - build(system, mem, vars, working_set, - font_set, style, live_set, exchange, - panel, command, - vars->hot_directory.string, - buffer_name, buffer_name_len, - path, path_len, - script, script_len, - flags); -} - -internal void -update_command_data(App_Vars *vars, Command_Data *cmd){ - cmd->panel = cmd->layout->panels + cmd->layout->active_panel; - cmd->view = cmd->panel->view; - cmd->style = &vars->style; -} - -globalvar Command_Function command_table[cmdid_count]; - -internal void -fill_buffer_summary(Buffer_Summary *buffer, Editing_File *file, Working_Set *working_set){ - buffer->exists = 1; - buffer->ready = file_is_ready(file); - buffer->is_lexed = file->settings.tokens_exist; - buffer->buffer_id = (int)(file - working_set->files); - buffer->size = file->state.buffer.size; - buffer->buffer_cursor_pos = file->state.cursor_pos; - - buffer->file_name_len = file->name.source_path.size; - buffer->buffer_name_len = file->name.live_name.size; - buffer->file_name = file->name.source_path.str; - buffer->buffer_name = file->name.live_name.str; - - buffer->map_id = file->settings.base_map_id; -} - -internal void -fill_view_summary(File_View_Summary *view, File_View *file_view, Live_Views *live_set, Working_Set *working_set){ - view->exists = 1; - view->view_id = (int)((char*)file_view - (char*)live_set->views) / live_set->stride; - if (file_view->file){ - view->buffer_id = (int)(file_view->file - working_set->files); - view->mark = view_compute_cursor_from_pos(file_view, file_view->mark); - view->cursor = file_view->cursor; - view->preferred_x = file_view->preferred_x; - view->line_height = file_view->font_height; - view->unwrapped_lines = file_view->unwrapped_lines; - } -} - -extern "C"{ - EXECUTE_COMMAND_SIG(external_exec_command_keep_stack){ - Command_Data *cmd = (Command_Data*)context->cmd_context; - Command_Function function = command_table[command_id]; - Command_Binding binding; - binding.function = function; - if (function) function(cmd->system, cmd, binding); - - update_command_data(cmd->vars, cmd); - } - - PUSH_PARAMETER_SIG(external_push_parameter){ - Command_Data *cmd = (Command_Data*)context->cmd_context; - Partition *part = &cmd->part; - Command_Parameter *cmd_param = push_struct(part, Command_Parameter); - cmd_param->type = 0; - cmd_param->param.param = param; - cmd_param->param.value = value; - } - - PUSH_MEMORY_SIG(external_push_memory){ - Command_Data *cmd = (Command_Data*)context->cmd_context; - Partition *part = &cmd->part; - Command_Parameter *base = push_struct(part, Command_Parameter); - char *result = push_array(part, char, len); - int full_len = len + sizeof(Command_Parameter) - 1; - full_len -= (full_len % sizeof(Command_Parameter)); - part->pos += full_len - len; - base->type = 1; - base->inline_string.str = result; - base->inline_string.len = len; - return(result); - } - - CLEAR_PARAMETERS_SIG(external_clear_parameters){ - Command_Data *cmd = (Command_Data*)context->cmd_context; - cmd->part.pos = 0; - } - - DIRECTORY_GET_HOT_SIG(external_directory_get_hot){ - Command_Data *cmd = (Command_Data*)context->cmd_context; - Hot_Directory *hot = &cmd->vars->hot_directory; - i32 copy_max = capacity - 1; - hot_directory_clean_end(hot); - if (copy_max > hot->string.size) - copy_max = hot->string.size; - memcpy(out, hot->string.str, copy_max); - out[copy_max] = 0; - return(hot->string.size); - } - - GET_FILE_LIST_SIG(external_get_file_list){ - Command_Data *cmd = (Command_Data*)context->cmd_context; - System_Functions *system = cmd->system; - File_List result = {}; - system->set_file_list(&result, make_string(dir, len)); - return(result); - } - - FREE_FILE_LIST_SIG(external_free_file_list){ - Command_Data *cmd = (Command_Data*)context->cmd_context; - System_Functions *system = cmd->system; - system->set_file_list(&list, make_string(0, 0)); - } - - GET_BUFFER_MAX_INDEX_SIG(external_get_buffer_max_index){ - Command_Data *cmd = (Command_Data*)context->cmd_context; - Working_Set *working_set = cmd->working_set; - int max = working_set->file_index_count; - return(max); - } - - GET_BUFFER_SIG(external_get_buffer){ - Command_Data *cmd = (Command_Data*)context->cmd_context; - Editing_File *file; - Working_Set *working_set = cmd->working_set; - int max = working_set->file_index_count; - Buffer_Summary buffer = {}; - - if (index >= 0 && index < max){ - file = working_set->files + index; - if (!file->state.is_dummy){ - fill_buffer_summary(&buffer, file, working_set); - } - } - - return(buffer); - } - - GET_ACTIVE_BUFFER_SIG(external_get_active_buffer){ - Command_Data *cmd = (Command_Data*)context->cmd_context; - File_View *view; - Editing_File *file; - Working_Set *working_set; - Buffer_Summary buffer = {}; - - view = view_to_file_view(cmd->view); - if (view){ - file = view->file; - working_set = cmd->working_set; - - if (file && !file->state.is_dummy){ - fill_buffer_summary(&buffer, file, working_set); - } - } - - return(buffer); - } - - GET_BUFFER_BY_NAME(external_get_buffer_by_name){ - Command_Data *cmd = (Command_Data*)context->cmd_context; - Editing_File *file; - Working_Set *working_set; - i32 index; - Buffer_Summary buffer = {}; - - working_set = cmd->working_set; - if (table_find(&working_set->table, make_string(filename, len), &index)){ - file = working_set->files + index; - if (!file->state.is_dummy && file_is_ready(file)){ - fill_buffer_summary(&buffer, file, working_set); - } - } - - return(buffer); - } - - REFRESH_BUFFER_SIG(external_refresh_buffer){ - int result; - *buffer = external_get_buffer(context, buffer->buffer_id); - result = buffer->exists; - return(result); - } - - BUFFER_SEEK_DELIMITER_SIG(external_buffer_seek_delimiter){ - Command_Data *cmd = (Command_Data*)context->cmd_context; - Editing_File *file; - Working_Set *working_set; - int result = 0; - int size; - - if (buffer->exists){ - working_set = cmd->working_set; - file = working_set->files + buffer->buffer_id; - if (!file->state.is_dummy && file_is_ready(file)){ - size = buffer_size(&file->state.buffer); - result = 1; - - if (start < 0 && !seek_forward) *out = start; - else if (start >= size && seek_forward) *out = start; - else{ - if (seek_forward){ - *out = buffer_seek_delimiter(&file->state.buffer, start, delim); - } - else{ - *out = buffer_reverse_seek_delimiter(&file->state.buffer, start, delim); - } - } - - fill_buffer_summary(buffer, file, working_set); - } - } - - return(result); - } - - BUFFER_SEEK_STRING_SIG(external_buffer_seek_string){ - Command_Data *cmd = (Command_Data*)context->cmd_context; - Editing_File *file; - Working_Set *working_set; - Temp_Memory temp; - Partition *part; - char *spare; - int result = 0; - int size; - - if (buffer->exists){ - working_set = cmd->working_set; - file = working_set->files + buffer->buffer_id; - if (!file->state.is_dummy && file_is_ready(file)){ - size = buffer_size(&file->state.buffer); - - if (start < 0 && !seek_forward) *out = start; - else if (start >= size && seek_forward) *out = start; - else{ - part = &cmd->mem->part; - temp = begin_temp_memory(part); - spare = push_array(part, char, len); - result = 1; - if (seek_forward){ - *out = buffer_find_string(&file->state.buffer, start, size, str, len, spare); - } - else{ - *out = buffer_rfind_string(&file->state.buffer, start, str, len, spare); - } - end_temp_memory(temp); - } - fill_buffer_summary(buffer, file, working_set); - } - } - - return(result); - } - - BUFFER_READ_RANGE_SIG(external_buffer_read_range){ - Command_Data *cmd = (Command_Data*)context->cmd_context; - Editing_File *file; - Working_Set *working_set; - int result = 0; - int size; - - if (buffer->exists){ - working_set = cmd->working_set; - file = working_set->files + buffer->buffer_id; - if (!file->state.is_dummy && file_is_ready(file)){ - size = buffer_size(&file->state.buffer); - if (0 <= start && start <= end && end <= size){ - result = 1; - buffer_stringify(&file->state.buffer, start, end, out); - } - fill_buffer_summary(buffer, file, working_set); - } - } - - return(result); - } - - BUFFER_REPLACE_RANGE_SIG(external_buffer_replace_range){ - Command_Data *cmd = (Command_Data*)context->cmd_context; - Editing_File *file; - Working_Set *working_set; - - System_Functions *system; - Mem_Options *mem; - Editing_Layout *layout; - - int result = 0; - int size; - int next_cursor, pos; - - if (buffer->exists){ - working_set = cmd->working_set; - file = working_set->files + buffer->buffer_id; - if (!file->state.is_dummy && file_is_ready(file)){ - size = buffer_size(&file->state.buffer); - if (0 <= start && start <= end && end <= size){ - result = 1; - - system = cmd->system; - mem = cmd->mem; - layout = cmd->layout; - - pos = file->state.cursor_pos; - if (pos < start) next_cursor = pos; - else if (pos < end) next_cursor = start + len; - else next_cursor = pos + end - start + len; - - file_replace_range(system, mem, file, layout, - start, end, str, len, next_cursor); - } - fill_buffer_summary(buffer, file, working_set); - } - } - - return(result); - } - - GET_VIEW_MAX_INDEX_SIG(external_get_view_max_index){ - Command_Data *cmd = (Command_Data*)context->cmd_context; - Live_Views *live_set = cmd->live_set; - int max = live_set->max; - return(max); - } - - GET_FILE_VIEW_SIG(external_get_file_view){ - Command_Data *cmd = (Command_Data*)context->cmd_context; - Live_Views *live_set = cmd->live_set; - int max = live_set->max; - View *vptr; - File_View *file_view; - File_View_Summary view = {}; - - if (index >= 0 && index < max){ - vptr = (View*)((char*)live_set->views + live_set->stride*index); - file_view = view_to_file_view(vptr); - if (file_view){ - fill_view_summary(&view, file_view, cmd->live_set, cmd->working_set); - } - } - - return(view); - } - - GET_ACTIVE_FILE_VIEW_SIG(external_get_active_file_view){ - Command_Data *cmd = (Command_Data*)context->cmd_context; - File_View_Summary view = {}; - File_View *file_view; - - file_view = view_to_file_view(cmd->view); - if (file_view){ - fill_view_summary(&view, file_view, cmd->live_set, cmd->working_set); - } - - return(view); - } - - REFRESH_FILE_VIEW_SIG(external_refresh_file_view){ - int result; - *view = external_get_file_view(context, view->view_id); - result = view->exists; - return(result); - } - - VIEW_SET_CURSOR_SIG(external_view_set_cursor){ - Command_Data *cmd = (Command_Data*)context->cmd_context; - Live_Views *live_set; - View *vptr; - File_View *file_view; - int result = 0; - - if (view->exists){ - live_set = cmd->live_set; - vptr = (View*)((char*)live_set->views + live_set->stride * view->view_id); - file_view = view_to_file_view(vptr); - if (file_view){ - result = 1; - file_view->cursor = view_compute_cursor(file_view, seek); - if (set_preferred_x){ - file_view->preferred_x = view_get_cursor_x(file_view); - } - fill_view_summary(view, file_view, cmd->live_set, cmd->working_set); - } - } - - return(result); - } - - VIEW_SET_MARK_SIG(external_view_set_mark){ - Command_Data *cmd = (Command_Data*)context->cmd_context; - Live_Views *live_set; - View *vptr; - File_View *file_view; - Full_Cursor cursor; - int result = 0; - - if (view->exists){ - live_set = cmd->live_set; - vptr = (View*)((char*)live_set->views + live_set->stride * view->view_id); - file_view = view_to_file_view(vptr); - if (file_view){ - result = 1; - if (seek.type != buffer_seek_pos){ - cursor = view_compute_cursor(file_view, seek); - file_view->mark = cursor.pos; - } - else{ - file_view->mark = seek.pos; - } - fill_view_summary(view, file_view, cmd->live_set, cmd->working_set); - } - } - - return(result); - } - - VIEW_SET_HIGHLIGHT_SIG(external_view_set_highlight){ - Command_Data *cmd = (Command_Data*)context->cmd_context; - Live_Views *live_set; - View *vptr; - File_View *file_view; - int result = 0; - - if (view->exists){ - live_set = cmd->live_set; - vptr = (View*)((char*)live_set->views + live_set->stride * view->view_id); - file_view = view_to_file_view(vptr); - if (file_view){ - result = 1; - if (turn_on){ - view_set_temp_highlight(file_view, start, end); - } - else{ - file_view->show_temp_highlight = 0; - } - fill_view_summary(view, file_view, cmd->live_set, cmd->working_set); - } - } - - return(result); - } - - VIEW_SET_BUFFER_SIG(external_view_set_buffer){ - Command_Data *cmd = (Command_Data*)context->cmd_context; - Live_Views *live_set; - View *vptr; - File_View *file_view; - Editing_File *file; - Working_Set *working_set; - int max, result = 0; - - if (view->exists){ - live_set = cmd->live_set; - vptr = (View*)((char*)live_set->views + live_set->stride * view->view_id); - file_view = view_to_file_view(vptr); - if (file_view){ - working_set = cmd->working_set; - max = working_set->file_index_count; - if (buffer_id >= 0 && buffer_id < max){ - file = working_set->files + buffer_id; - if (!file->state.is_dummy){ - view_set_file(file_view, file, cmd->vars->font_set, cmd->style, - cmd->system, cmd->vars->hooks[hook_open_file], &app_links); - } - } - - fill_view_summary(view, file_view, cmd->live_set, cmd->working_set); - } - } - - return(result); - } - - GET_USER_INPUT_SIG(external_get_user_input){ - Command_Data *cmd = (Command_Data*)context->cmd_context; - System_Functions *system = cmd->system; - Coroutine *coroutine = cmd->current_coroutine; - User_Input result; - - Assert(coroutine); - *((u32*)coroutine->out+0) = get_type; - *((u32*)coroutine->out+1) = abort_type; - system->yield_coroutine(coroutine); - result = *(User_Input*)coroutine->in; - - return(result); - } - - START_QUERY_BAR_SIG(external_start_query_bar){ - Command_Data *cmd = (Command_Data*)context->cmd_context; - Query_Slot *slot = 0; - View *vptr; - File_View *file_view; - - vptr = cmd->view; - file_view = view_to_file_view(vptr); - - if (file_view){ - slot = alloc_query_slot(&file_view->query_set); - slot->query_bar = bar; - } - - return(slot != 0); - } - - END_QUERY_BAR_SIG(external_end_query_bar){ - Command_Data *cmd = (Command_Data*)context->cmd_context; - View *vptr; - File_View *file_view; - - vptr = cmd->view; - file_view = view_to_file_view(vptr); - - if (file_view){ - free_query_slot(&file_view->query_set, bar); - } - } -} - -struct Command_In{ - Command_Data *cmd; - Command_Binding bind; -}; - -internal void -command_caller(Coroutine *coroutine){ - Command_In *cmd_in = (Command_In*)coroutine->in; - Command_Data *cmd = cmd_in->cmd; - View *view = cmd->view; - // TODO(allen): this isn't really super awesome, could have issues if - // the file view get's change out under us. - File_View *fview = view_to_file_view(view); - if (fview) fview->next_mode = {}; - cmd_in->bind.function(cmd->system, cmd, cmd_in->bind); - fview = view_to_file_view(view); - if (fview) fview->mode = fview->next_mode; -} - -internal void -app_links_init(System_Functions *system, void *data, int size){ - app_links.memory = data; - app_links.memory_size = size; - - app_links.exec_command_keep_stack = external_exec_command_keep_stack; - app_links.push_parameter = external_push_parameter; - app_links.push_memory = external_push_memory; - app_links.clear_parameters = external_clear_parameters; - - app_links.directory_get_hot = external_directory_get_hot; - app_links.file_exists = system->file_exists; - app_links.directory_cd = system->directory_cd; - app_links.get_file_list = external_get_file_list; - app_links.free_file_list = external_free_file_list; - - app_links.get_buffer_max_index = external_get_buffer_max_index; - app_links.get_buffer = external_get_buffer; - app_links.get_active_buffer = external_get_active_buffer; - app_links.get_buffer_by_name = external_get_buffer_by_name; - - app_links.refresh_buffer = external_refresh_buffer; - app_links.buffer_seek_delimiter = external_buffer_seek_delimiter; - app_links.buffer_seek_string = external_buffer_seek_string; - app_links.buffer_read_range = external_buffer_read_range; - app_links.buffer_replace_range = external_buffer_replace_range; - - app_links.get_view_max_index = external_get_view_max_index; - app_links.get_file_view = external_get_file_view; - app_links.get_active_file_view = external_get_active_file_view; - - app_links.refresh_file_view = external_refresh_file_view; - app_links.view_set_cursor = external_view_set_cursor; - app_links.view_set_mark = external_view_set_mark; - app_links.view_set_highlight = external_view_set_highlight; - app_links.view_set_buffer = external_view_set_buffer; - - app_links.get_user_input = external_get_user_input; - - app_links.start_query_bar = external_start_query_bar; - app_links.end_query_bar = external_end_query_bar; -} - -internal void -setup_ui_commands(Command_Map *commands, Partition *part, Command_Map *parent){ - map_init(commands, part, 32, parent); - - commands->vanilla_keyboard_default.function = command_null; - - // 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; - u8 mdfr_array[] = {MDFR_NONE, MDFR_SHIFT, MDFR_CTRL, MDFR_SHIFT | MDFR_CTRL}; - for (i32 i = 0; i < 4; ++i){ - 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); - map_add(commands, key_esc, mdfr, command_close_minor_view); - } -} - -internal void -setup_file_commands(Command_Map *commands, Partition *part, Command_Map *parent){ - map_init(commands, part, 10, parent); -} - -internal void -setup_top_commands(Command_Map *commands, Partition *part, Command_Map *parent){ - map_init(commands, part, 5, parent); -} - -internal void -setup_command_table(){ -#define SET(n) command_table[cmdid_##n] = command_##n - - SET(null); - SET(write_character); - SET(seek_whitespace_right); - SET(seek_whitespace_left); - SET(seek_whitespace_up); - SET(seek_whitespace_down); - SET(seek_token_left); - SET(seek_token_right); - SET(seek_white_or_token_right); - SET(seek_white_or_token_left); - SET(seek_alphanumeric_right); - SET(seek_alphanumeric_left); - SET(seek_alphanumeric_or_camel_right); - SET(seek_alphanumeric_or_camel_left); - SET(word_complete); - SET(set_mark); - SET(copy); - SET(cut); - SET(paste); - SET(paste_next); - SET(delete_range); - SET(timeline_scrub); - SET(undo); - SET(redo); - SET(history_backward); - SET(history_forward); - SET(interactive_new); - SET(interactive_open); - SET(reopen); - SET(save); - SET(interactive_save_as); - SET(change_active_panel); - SET(interactive_switch_buffer); - SET(interactive_kill_buffer); - SET(kill_buffer); - SET(toggle_line_wrap); - SET(to_uppercase); - SET(to_lowercase); - SET(toggle_show_whitespace); - SET(clean_all_lines); - SET(eol_dosify); - SET(eol_nixify); - SET(auto_tab_range); - SET(auto_tab_line_at_cursor); - SET(auto_tab_whole_file); - SET(open_panel_vsplit); - SET(open_panel_hsplit); - SET(close_panel); - SET(move_left); - SET(move_right); - SET(delete); - SET(backspace); - SET(move_up); - SET(move_down); - SET(seek_end_of_line); - SET(seek_beginning_of_line); - SET(page_up); - SET(page_down); - SET(open_color_tweaker); - SET(close_minor_view); - SET(cursor_mark_swap); - SET(open_menu); - SET(set_settings); - SET(command_line); - -#undef SET -} - -// App Functions - -internal void -app_hardcode_styles(App_Vars *vars){ - Interactive_Style file_info_style; - Style *styles, *style; - styles = vars->styles.styles; - style = styles; - - i16 fonts = 1; - - ///////////////// - style_set_name(style, make_lit_string("4coder")); - style->font_id = fonts + 0; - - style->main.back_color = 0xFF0C0C0C; - style->main.margin_color = 0xFF181818; - style->main.margin_hover_color = 0xFF252525; - style->main.margin_active_color = 0xFF323232; - 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; - - 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; - file_info_style.pop1_color = 0xFF4444AA; - file_info_style.pop2_color = 0xFFFF0000; - style->main.file_info_style = file_info_style; - style->font_changed = 1; - ++style; - - ///////////////// - *style = *(style-1); - style_set_name(style, make_lit_string("4coder-mono")); - style->font_id = fonts + 1; - ++style; - - ///////////////// - style_set_name(style, make_lit_string("Handmade Hero")); - style->font_id = fonts + 1; - - style->main.back_color = 0xFF161616; - style->main.margin_color = 0xFF262626; - style->main.margin_hover_color = 0xFF333333; - style->main.margin_active_color = 0xFF404040; - style->main.cursor_color = 0xFF40FF40; - style->main.at_cursor_color = style->main.back_color; - style->main.mark_color = 0xFF808080; - style->main.highlight_color = 0xFF703419; - style->main.at_highlight_color = 0xFFCDAA7D; - style->main.default_color = 0xFFCDAA7D; - style->main.comment_color = 0xFF7F7F7F; - style->main.keyword_color = 0xFFCD950C; - style->main.str_constant_color = 0xFF6B8E23; - 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; - - style->main.paste_color = 0xFFFFBB00; - style->main.undo_color = 0xFFFF00BB; - style->main.undo_color = 0xFF80005D; - - style->main.highlight_junk_color = 0xFF3A0000; - style->main.highlight_white_color = 0xFF003A3A; - - file_info_style.bar_color = 0xFFCACACA; - file_info_style.bar_active_color = 0xFFA8A8A8; - file_info_style.base_color = 0xFF000000; - file_info_style.pop1_color = 0xFF03CF0C; - file_info_style.pop2_color = 0xFFFF0000; - style->main.file_info_style = file_info_style; - style->font_changed = 1; - ++style; - - ///////////////// - style_set_name(style, make_lit_string("Twilight")); - style->font_id = fonts + 2; - - style->main.back_color = 0xFF090D12; - style->main.margin_color = 0xFF1A2634; - style->main.margin_hover_color = 0xFF2D415B; - style->main.margin_active_color = 0xFF405D82; - style->main.cursor_color = 0xFFEEE800; - style->main.at_cursor_color = style->main.back_color; - style->main.mark_color = 0xFF8BA8CC; - style->main.highlight_color = 0xFF037A7B; - style->main.at_highlight_color = 0xFFFEB56C; - style->main.default_color = 0xFFB7C19E; - style->main.comment_color = 0xFF20ECF0; - style->main.keyword_color = 0xFFD86909; - style->main.str_constant_color = 0xFFC4EA5D; - 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; - - style->main.paste_color = 0xFFDDEE00; - style->main.undo_color = 0xFF00DDEE; - - style->main.highlight_junk_color = 0xff3a0000; - style->main.highlight_white_color = 0xFF151F2A; - - file_info_style.bar_color = 0xFF315E68; - file_info_style.bar_active_color = 0xFF0F3C46; - file_info_style.base_color = 0xFF000000; - file_info_style.pop1_color = 0xFF1BFF0C; - file_info_style.pop2_color = 0xFFFF200D; - style->main.file_info_style = file_info_style; - style->font_changed = 1; - ++style; - - ///////////////// - style_set_name(style, make_lit_string("Wolverine")); - style->font_id = fonts + 3; - - style->main.back_color = 0xFF070711; - style->main.margin_color = 0xFF111168; - style->main.margin_hover_color = 0xFF191996; - style->main.margin_active_color = 0xFF2121C3; - style->main.cursor_color = 0xFF7082F9; - style->main.at_cursor_color = 0xFF000014; - style->main.mark_color = 0xFF4b5028; - style->main.highlight_color = 0xFFDDEE00; - style->main.at_highlight_color = 0xFF000019; - style->main.default_color = 0xFF8C9740; - style->main.comment_color = 0xFF3A8B29; - style->main.keyword_color = 0xFFD6B109; - style->main.str_constant_color = 0xFFAF5FA7; - 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; - - style->main.paste_color = 0xFF900090; - style->main.undo_color = 0xFF606090; - - style->main.highlight_junk_color = 0xff3a0000; - style->main.highlight_white_color = 0xff003a3a; - - file_info_style.bar_color = 0xFF7082F9; - file_info_style.bar_active_color = 0xFF4E60D7; - file_info_style.base_color = 0xFF000000; - file_info_style.pop1_color = 0xFFFAFA15; - file_info_style.pop2_color = 0xFFD20000; - style->main.file_info_style = file_info_style; - style->font_changed = 1; - ++style; - - ///////////////// - style_set_name(style, make_lit_string("stb")); - style->font_id = fonts + 4; - - style->main.back_color = 0xFFD6D6D6; - style->main.margin_color = 0xFF9E9E9E; - style->main.margin_hover_color = 0xFF7E7E7E; - style->main.margin_active_color = 0xFF5C5C5C; - style->main.cursor_color = 0xFF000000; - style->main.at_cursor_color = 0xFFD6D6D6; - style->main.mark_color = 0xFF525252; - style->main.highlight_color = 0xFF0044FF; - style->main.at_highlight_color = 0xFFD6D6D6; - style->main.default_color = 0xFF000000; - style->main.comment_color = 0xFF000000; - style->main.keyword_color = 0xFF000000; - style->main.str_constant_color = 0xFF000000; - 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 = 0xFF9A0000; - - style->main.paste_color = 0xFF00B8B8; - style->main.undo_color = 0xFFB800B8; - - style->main.highlight_junk_color = 0xFFFF7878; - style->main.highlight_white_color = 0xFFBCBCBC; - - file_info_style.bar_color = 0xFF606060; - file_info_style.bar_active_color = 0xFF3E3E3E; - file_info_style.base_color = 0xFF000000; - file_info_style.pop1_color = 0xFF1111DC; - file_info_style.pop2_color = 0xFFE80505; - style->main.file_info_style = file_info_style; - style->font_changed = 1; - ++style; - - vars->styles.count = (i32)(style - styles); - vars->styles.max = ArrayCount(vars->styles.styles); - style_copy(&vars->style, vars->styles.styles); - vars->style.font_changed = 0; -} - -char *_4coder_get_extension(const char *filename, int len, int *extension_len){ - char *c = (char*)(filename + len - 1); - char *end = c; - while (*c != '.' && c > filename) --c; - *extension_len = (int)(end - c); - return c+1; -} - -bool _4coder_str_match(const char *a, int len_a, const char *b, int len_b){ - bool result = 0; - if (len_a == len_b){ - char *end = (char*)(a + len_a); - while (a < end && *a == *b){ - ++a; ++b; - } - if (a == end) result = 1; - } - return result; -} - -enum Command_Line_Action{ - CLAct_Nothing, - CLAct_Ignore, - CLAct_UserFile, - CLAct_CustomDLL, - CLAct_InitialFilePosition, - CLAct_WindowSize, - CLAct_WindowMaximize, - CLAct_WindowPosition, - CLAct_Count -}; - -void -init_command_line_settings(App_Settings *settings, Plat_Settings *plat_settings, - Command_Line_Parameters clparams){ - char *arg; - Command_Line_Action action = CLAct_Nothing; - i32 i,index; - b32 strict = 0; - - settings->init_files_max = ArrayCount(settings->init_files); - for (i = 1; i <= clparams.argc; ++i){ - if (i == clparams.argc) arg = ""; - else arg = clparams.argv[i]; - switch (action){ - case CLAct_Nothing: - { - if (arg[0] == '-'){ - action = CLAct_Ignore; - switch (arg[1]){ - case 'u': action = CLAct_UserFile; strict = 0; break; - case 'U': action = CLAct_UserFile; strict = 1; break; - - case 'd': action = CLAct_CustomDLL; strict = 0; break; - case 'D': action = CLAct_CustomDLL; strict = 1; break; - - case 'i': action = CLAct_InitialFilePosition; break; - - case 'w': action = CLAct_WindowSize; break; - case 'W': action = CLAct_WindowMaximize; break; - case 'p': action = CLAct_WindowPosition; break; - } - } - else if (arg[0] != 0){ - if (settings->init_files_count < settings->init_files_max){ - index = settings->init_files_count++; - settings->init_files[index] = arg; - } - } - }break; - - case CLAct_UserFile: - { - settings->user_file_is_strict = strict; - if (i < clparams.argc){ - settings->user_file = clparams.argv[i]; - } - action = CLAct_Nothing; - }break; - - case CLAct_CustomDLL: - { - plat_settings->custom_dll_is_strict = strict; - if (i < clparams.argc){ - plat_settings->custom_dll = clparams.argv[i]; - } - action = CLAct_Nothing; - }break; - - case CLAct_InitialFilePosition: - { - if (i < clparams.argc){ - settings->initial_line = str_to_int(clparams.argv[i]); - } - action = CLAct_Nothing; - }break; - - case CLAct_WindowSize: - { - if (i + 1 < clparams.argc){ - plat_settings->set_window_size = 1; - plat_settings->window_w = str_to_int(clparams.argv[i]); - plat_settings->window_h = str_to_int(clparams.argv[i+1]); - - ++i; - } - action = CLAct_Nothing; - }break; - - case CLAct_WindowMaximize: - { - --i; - plat_settings->maximize_window = 1; - action = CLAct_Nothing; - }break; - - case CLAct_WindowPosition: - { - if (i + 1 < clparams.argc){ - plat_settings->set_window_pos = 1; - plat_settings->window_x = str_to_int(clparams.argv[i]); - plat_settings->window_y = str_to_int(clparams.argv[i+1]); - - ++i; - } - action = CLAct_Nothing; - }break; - } - } -} - -internal App_Vars* -app_setup_memory(Application_Memory *memory){ - Partition _partition = partition_open(memory->vars_memory, memory->vars_memory_size); - App_Vars *vars = push_struct(&_partition, App_Vars); - Assert(vars); - *vars = {}; - vars->mem.part = _partition; - - general_memory_open(&vars->mem.general, memory->target_memory, memory->target_memory_size); - - return(vars); -} - -internal i32 -execute_special_tool(void *memory, i32 size, Command_Line_Parameters clparams){ - i32 result; - char message[] = "tool was not specified or is invalid"; - result = sizeof(message) - 1; - memcpy(memory, message, result); - if (clparams.argc > 2){ - if (match(clparams.argv[2], "version")){ - result = sizeof(VERSION) - 1; - memcpy(memory, VERSION, result); - } - } - return(result); -} - -App_Read_Command_Line_Sig(app_read_command_line){ - App_Vars *vars; - i32 out_size = 0; - - if (clparams.argc > 1 && match(clparams.argv[1], "-T")){ - out_size = execute_special_tool(memory->target_memory, memory->target_memory_size, clparams); - } - else{ - vars = app_setup_memory(memory); - if (clparams.argc > 1){ - init_command_line_settings(&vars->settings, plat_settings, clparams); - } - else{ - vars->settings = {}; - } - *files = vars->settings.init_files; - *file_count = &vars->settings.init_files_count; - } - - return(out_size); -} - -App_Init_Sig(app_init){ - app_links_init(system, memory->user_memory, memory->user_memory_size); - - App_Vars *vars = (App_Vars*)memory->vars_memory; - vars->config_api = api; - app_links.cmd_context = &vars->command_data; - - Partition *partition = &vars->mem.part; - target->partition = partition; - - Panel *panels; - Panel_Divider *dividers, *div; - i32 panel_max_count; - i32 divider_max_count; - - panel_max_count = vars->layout.panel_max_count = 16; - divider_max_count = panel_max_count - 1; - vars->layout.panel_count = 1; - - panels = push_array(partition, Panel, panel_max_count); - vars->layout.panels = panels; - - dividers = push_array(partition, Panel_Divider, divider_max_count); - vars->layout.dividers = dividers; - - div = dividers; - for (i32 i = 0; i < divider_max_count-1; ++i, ++div){ - div->next = (div + 1); - } - div->next = 0; - vars->layout.free_divider = dividers; - - i32 view_chunk_size = 0; - i32 view_sizes[] = { - sizeof(File_View), - sizeof(Color_View), - sizeof(Interactive_View), - sizeof(Menu_View), - sizeof(Config_View), - }; - - { - char *vptr = 0; - View *v = 0, *n = 0; - i32 i = 0, max = 0; - - vars->live_set.count = 0; - vars->live_set.max = 1 + 2*panel_max_count; - - for (i = 0; i < ArrayCount(view_sizes); ++i){ - view_chunk_size = Max(view_chunk_size, view_sizes[i]); - } - vars->live_set.stride = view_chunk_size; - vars->live_set.views = push_block(partition, view_chunk_size*vars->live_set.max); - - max = vars->live_set.max; - vptr = (char*)vars->live_set.views; - vars->live_set.free_view = (View*)vptr; - for (i = 0; i < max; ++i){ - v = (View*)(vptr); - n = (View*)(vptr + view_chunk_size); - v->next_free = n; - vptr = (char*)n; - } - v->next_free = 0; - } - - - - setup_command_table(); - - Command_Map *global = &vars->map_top; - Assert(vars->config_api.get_bindings != 0); - - i32 wanted_size = vars->config_api.get_bindings(app_links.memory, app_links.memory_size); - - b32 did_top = 0; - b32 did_file = 0; - if (wanted_size <= app_links.memory_size){ - Binding_Unit *unit = (Binding_Unit*)app_links.memory; - 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; - - vars->map_id_table = push_array( - &vars->mem.part, i32, user_map_count); - - vars->user_maps = push_array( - &vars->mem.part, Command_Map, user_map_count); - - vars->user_map_count = user_map_count; - - Command_Map *mapptr = 0; - for (++unit; unit < end; ++unit){ - switch (unit->type){ - case unit_map_begin: - { - int table_max = unit->map_begin.bind_count * 3 / 2; - int mapid = unit->map_begin.mapid; - if (mapid == mapid_global){ - mapptr = &vars->map_top; - map_init(mapptr, &vars->mem.part, table_max, global); - did_top = 1; - } - else if (mapid == mapid_file){ - mapptr = &vars->map_file; - map_init(mapptr, &vars->mem.part, table_max, global); - did_file = 1; - } - else if (mapid < mapid_global){ - i32 index = app_get_or_add_map_index(vars, mapid); - Assert(index < user_map_count); - mapptr = vars->user_maps + index; - map_init(mapptr, &vars->mem.part, table_max, global); - } - else mapptr = 0; - }break; - - case unit_inherit: - if (mapptr){ - Command_Map *parent = 0; - int mapid = unit->map_inherit.mapid; - if (mapid == mapid_global) parent = &vars->map_top; - else if (mapid == mapid_file) parent = &vars->map_file; - else if (mapid < mapid_global){ - i32 index = app_get_or_add_map_index(vars, mapid); - if (index < user_map_count) parent = vars->user_maps + index; - else parent = 0; - } - mapptr->parent = parent; - }break; - - case unit_binding: - if (mapptr){ - Command_Function func = 0; - if (unit->binding.command_id >= 0 && unit->binding.command_id < cmdid_count) - func = command_table[unit->binding.command_id]; - if (func){ - if (unit->binding.code == 0 && unit->binding.modifiers == 0){ - mapptr->vanilla_keyboard_default.function = func; - mapptr->vanilla_keyboard_default.custom_id = unit->binding.command_id; - } - else{ - map_add(mapptr, unit->binding.code, unit->binding.modifiers, func, unit->binding.command_id); - } - } - } - break; - - case unit_callback: - if (mapptr){ - Command_Function func = command_user_callback; - Custom_Command_Function *custom = unit->callback.func; - if (func){ - if (unit->callback.code == 0 && unit->callback.modifiers == 0){ - mapptr->vanilla_keyboard_default.function = func; - mapptr->vanilla_keyboard_default.custom = custom; - } - else{ - map_add(mapptr, unit->callback.code, unit->callback.modifiers, func, custom); - } - } - } - break; - - case unit_hook: - { - int hook_id = unit->hook.hook_id; - if (hook_id >= 0 && hook_id < hook_type_count){ - vars->hooks[hook_id] = unit->hook.func; - } - }break; - } - } - } - } - - memset(app_links.memory, 0, wanted_size); - if (!did_top) setup_top_commands(&vars->map_top, &vars->mem.part, global); - if (!did_file) setup_file_commands(&vars->map_file, &vars->mem.part, global); - -#if 1 || !defined(FRED_SUPER) - vars->hooks[hook_start] = 0; -#endif - - setup_ui_commands(&vars->map_ui, &vars->mem.part, global); - - vars->font_set = &target->font_set; - - font_set_init(vars->font_set, partition, 16, 5); - - { - struct Font_Setup{ - char *c_file_name; - i32 file_name_len; - char *c_name; - i32 name_len; - i32 pt_size; - }; - -#define LitStr(n) n, sizeof(n)-1 - - Font_Setup font_setup[] = { - {LitStr("LiberationSans-Regular.ttf"), - LitStr("liberation sans"), - 16}, - - {LitStr("liberation-mono.ttf"), - LitStr("liberation mono"), - 16}, - - {LitStr("Hack-Regular.ttf"), - LitStr("hack"), - 16}, - - {LitStr("CutiveMono-Regular.ttf"), - LitStr("cutive mono"), - 16}, - - {LitStr("Inconsolata-Regular.ttf"), - LitStr("inconsolata"), - 16}, - - }; - i32 font_count = ArrayCount(font_setup); - - for (i32 i = 0; i < font_count; ++i){ - String file_name = make_string(font_setup[i].c_file_name, - font_setup[i].file_name_len); - String name = make_string(font_setup[i].c_name, - font_setup[i].name_len); - i32 pt_size = font_setup[i].pt_size; - - font_set_add(partition, vars->font_set, file_name, name, pt_size); - } - } - - // NOTE(allen): file setup - vars->working_set.file_index_count = 1; - vars->working_set.file_max_count = 120; - vars->working_set.files = - push_array(partition, Editing_File, vars->working_set.file_max_count); - - file_get_dummy(&vars->working_set.files[0]); - - vars->working_set.table.max = vars->working_set.file_max_count * 3 / 2; - vars->working_set.table.count = 0; - vars->working_set.table.table = - push_array(partition, File_Table_Entry, vars->working_set.table.max); - memset(vars->working_set.table.table, 0, sizeof(File_Table_Entry) * vars->working_set.table.max); - - // NOTE(allen): clipboard setup - vars->working_set.clipboard_max_size = ArrayCount(vars->working_set.clipboards); - vars->working_set.clipboard_size = 0; - vars->working_set.clipboard_current = 0; - vars->working_set.clipboard_rolling = 0; - - // TODO(allen): more robust allocation solution for the clipboard - if (clipboard.str){ - String *dest = working_set_next_clipboard_string(&vars->mem.general, &vars->working_set, clipboard.size); - copy(dest, make_string((char*)clipboard.str, clipboard.size)); - } - - // NOTE(allen): delay setup - vars->delay1.general = &vars->mem.general; - vars->delay1.max = 16; - vars->delay1.acts = (Delayed_Action*)general_memory_allocate( - &vars->mem.general, vars->delay1.max*sizeof(Delayed_Action), 0); - - vars->delay2.general = &vars->mem.general; - vars->delay2.max = 16; - vars->delay2.acts = (Delayed_Action*)general_memory_allocate( - &vars->mem.general, vars->delay2.max*sizeof(Delayed_Action), 0); - - // NOTE(allen): style setup - app_hardcode_styles(vars); - - vars->palette_size = 40; - vars->palette = push_array(partition, u32, vars->palette_size); - - // NOTE(allen): init first panel - panel_init(&panels[0]); - panel_make_empty(system, exchange, vars, &vars->style, &panels[0]); - - String hdbase = make_fixed_width_string(vars->hot_dir_base_); - hot_directory_init(&vars->hot_directory, hdbase, current_directory, system->slash); - - vars->mini_str = make_string((char*)vars->mini_buffer, 0, 512); - - // NOTE(allen): child proc list setup - i32 max_children = 16; - partition_align(partition, 8); - vars->cli_processes.procs = push_array(partition, CLI_Process, max_children); - vars->cli_processes.max = max_children; - vars->cli_processes.count = 0; - - // NOTE(allen): sys app binding setup - vars->sys_app_max = exchange->file.max; - vars->sys_app_count = 0; - vars->sys_app_bindings = (Sys_App_Binding*)push_array(partition, Sys_App_Binding, vars->sys_app_max); -} - -App_Step_Sig(app_step){ - ProfileStart(OS_syncing); - Application_Step_Result app_result = *result; - app_result.redraw = force_redraw; - - App_Vars *vars = (App_Vars*)memory->vars_memory; - target->partition = &vars->mem.part; - - if (first_step || !time_step){ - app_result.redraw = 1; - } - - // NOTE(allen): OS clipboard event handling - if (clipboard.str){ - String *dest = working_set_next_clipboard_string(&vars->mem.general, &vars->working_set, clipboard.size); - dest->size = eol_convert_in(dest->str, clipboard.str, clipboard.size); - } - - // TODO(allen): profile this make sure it's not costing me too much power. - // NOTE(allen): check files are up to date - for (i32 i = 0; i < vars->working_set.file_index_count; ++i){ - Editing_File *file = vars->working_set.files + i; - - if (!file->state.is_dummy){ - u64 time_stamp = system->file_time_stamp(make_c_str(file->name.source_path)); - - if (time_stamp > 0){ - file->state.last_sys_write_time = time_stamp; - if (file->state.last_sys_write_time != file->state.last_4ed_write_time){ - app_result.redraw = 1; - } - } - } - } - - // NOTE(allen): update child processes - Panel *panels = vars->layout.panels; - if (time_step){ - Temp_Memory temp = begin_temp_memory(&vars->mem.part); - u32 max = Kbytes(32); - char *dest = push_array(&vars->mem.part, char, max); - u32 amount; - - i32 count = vars->cli_processes.count; - for (i32 i = 0; i < count; ++i){ - CLI_Process *proc = vars->cli_processes.procs + i; - Editing_File *out_file = proc->out_file; - - if (out_file != 0){ - i32 new_cursor = out_file->state.cursor_pos; - - for (system->cli_begin_update(&proc->cli); - system->cli_update_step(&proc->cli, dest, max, &amount);){ - amount = eol_in_place_convert_in(dest, amount); - Edit_Spec spec = {}; - spec.step.type = ED_NORMAL; - spec.step.edit.start = buffer_size(&out_file->state.buffer); - spec.step.edit.end = spec.step.edit.start; - spec.step.edit.len = amount; - spec.step.pre_pos = new_cursor; - spec.step.post_pos = spec.step.edit.start + amount; - spec.str = (u8*)dest; - file_do_single_edit(system, &vars->mem, out_file, - &vars->layout, spec, hist_normal); - app_result.redraw = 1; - new_cursor = spec.step.post_pos; - } - - if (system->cli_end_update(&proc->cli)){ - *proc = vars->cli_processes.procs[--count]; - --i; - - char str_space[256]; - String str = make_fixed_width_string(str_space); - append(&str, "exited with code "); - append_int_to_str(proc->cli.exit, &str); - - Edit_Spec spec = {}; - spec.step.type = ED_NORMAL; - spec.step.edit.start = buffer_size(&out_file->state.buffer); - spec.step.edit.end = spec.step.edit.start; - spec.step.edit.len = str.size; - spec.step.pre_pos = new_cursor; - spec.step.post_pos = spec.step.edit.start + str.size; - spec.str = (u8*)str.str; - file_do_single_edit(system, &vars->mem, out_file, - &vars->layout, spec, hist_normal); - app_result.redraw = 1; - new_cursor = spec.step.post_pos; - } - - Panel *panel = panels; - i32 panel_count = vars->layout.panel_count; - for (i32 i = 0; i < panel_count; ++i, ++panel){ - View *view = panel->view; - if (view && view->is_minor) view = view->major; - File_View *fview = view_to_file_view(view); - if (fview && fview->file == out_file){ - view_cursor_move(fview, new_cursor); - } - } - } - } - - vars->cli_processes.count = count; - end_temp_memory(temp); - } - - // NOTE(allen): reorganizing panels on screen - { - i32 prev_width = vars->layout.full_width; - i32 prev_height = vars->layout.full_height; - i32 current_width = target->width; - i32 current_height = target->height; - - View *view; - File_View *fview; - i32 i, view_count; - - vars->layout.full_width = current_width; - vars->layout.full_height = current_height; - - view_count = vars->layout.panel_max_count; - - if (prev_width != current_width || prev_height != current_height){ - layout_refit(&vars->layout, prev_width, prev_height); - for (i = 0; i < view_count; ++i){ - view = live_set_get_view(&vars->live_set, i); - if (!view->is_active) continue; - fview = view_to_file_view(view); - if (!fview) continue; - // TODO(allen): All responses to a panel changing size should - // be handled in the same place. - view_change_size(system, &vars->mem.general, fview); - } - app_result.redraw = 1; - } - } - - // NOTE(allen): prepare input information - Key_Summary key_data = {}; - for (i32 i = 0; i < input->press_count; ++i){ - key_data.keys[key_data.count++] = input->press[i]; - } - for (i32 i = 0; i < input->hold_count; ++i){ - key_data.keys[key_data.count++] = input->hold[i]; - } - - mouse->wheel = -mouse->wheel; - - ProfileEnd(OS_syncing); - - // NOTE(allen): while I transition away from this view system to something that has - // more unified behavior, I will use this to add checks to the program's state so that I - // can make sure it behaving well. - ProfileStart(correctness_checks); - { - Panel *panel = panels; - i32 panel_count = vars->layout.panel_count; - for (i32 i = 0; i < panel_count; ++i, ++panel){ - Assert(panel->view); - } - } - ProfileEnd(correctness_checks); - - ProfileStart(hover_status); - // NOTE(allen): detect mouse hover status - i32 mx = mouse->x; - i32 my = mouse->y; - b32 mouse_in_edit_area = 0; - b32 mouse_in_margin_area = 0; - Panel *mouse_panel = 0; - i32 mouse_panel_i = 0; - i32 panel_count = vars->layout.panel_count; - - mouse_panel = panels; - for (mouse_panel_i = 0; mouse_panel_i < panel_count; ++mouse_panel_i, ++mouse_panel){ - if (hit_check(mx, my, mouse_panel->inner)){ - mouse_in_edit_area = 1; - break; - } - else if (hit_check(mx, my, mouse_panel->full)){ - mouse_in_margin_area = 1; - break; - } - } - - if (!(mouse_in_edit_area || mouse_in_margin_area)){ - mouse_panel = 0; - mouse_panel_i = 0; - } - - b32 mouse_on_divider = 0; - b32 mouse_divider_vertical = 0; - 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){ - mouse_divider_vertical = 0; - if (my > panel->inner.y0){ - mouse_divider_side = -1; - } - else{ - mouse_divider_side = 1; - } - } - else{ - mouse_divider_vertical = 1; - if (mx > panel->inner.x0){ - mouse_divider_side = -1; - } - else{ - mouse_divider_side = 1; - } - } - - if (vars->layout.panel_count > 1){ - i32 which_child; - mouse_divider_id = panel->parent; - which_child = panel->which_child; - for (;;){ - Divider_And_ID div = layout_get_divider(&vars->layout, mouse_divider_id); - - if (which_child == mouse_divider_side && - div.divider->v_divider == mouse_divider_vertical){ - mouse_on_divider = 1; - break; - } - - if (mouse_divider_id == vars->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; - } - } - ProfileEnd(hover_status); - - // NOTE(allen): prepare to start executing commands - ProfileStart(command_coroutine); - - Command_Data *cmd = &vars->command_data; - - cmd->mem = &vars->mem; - cmd->panel = panels + vars->layout.active_panel; - cmd->view = cmd->panel->view; - cmd->working_set = &vars->working_set; - cmd->layout = &vars->layout; - cmd->live_set = &vars->live_set; - cmd->style = &vars->style; - cmd->delay = &vars->delay1; - cmd->vars = vars; - cmd->exchange = exchange; - cmd->screen_width = target->width; - cmd->screen_height = target->height; - cmd->system = system; - - Temp_Memory param_stack_temp = begin_temp_memory(&vars->mem.part); - cmd->part = partition_sub_part(&vars->mem.part, 16 << 10); - - if (first_step){ - if (vars->hooks[hook_start]){ - vars->hooks[hook_start](&app_links); - cmd->part.pos = 0; - } - - i32 i; - String file_name; - Panel *panel = vars->layout.panels; - for (i = 0; i < vars->settings.init_files_count; ++i, ++panel){ - file_name = make_string_slowly(vars->settings.init_files[i]); - - if (i < vars->layout.panel_count){ - delayed_open(&vars->delay1, file_name, panel); - if (i == 0){ - delayed_set_line(&vars->delay1, panel, vars->settings.initial_line); - } - } - else{ - delayed_open_background(&vars->delay1, file_name); - } - } - } - ProfileEnd(hover_status); - - // NOTE(allen): process the command_coroutine if it is unfinished - ProfileStart(command_coroutine); - b8 consumed_input[6] = {0}; - - if (vars->command_coroutine != 0){ - Coroutine *command_coroutine = vars->command_coroutine; - u32 get_flags = vars->command_coroutine_flags[0]; - u32 abort_flags = vars->command_coroutine_flags[1]; - - get_flags |= abort_flags; - - if ((get_flags & EventOnAnyKey) || (get_flags & EventOnEsc)){ - for (i32 key_i = 0; key_i < key_data.count; ++key_i){ - Key_Event_Data key = get_single_key(&key_data, key_i); - View *view = cmd->view; - b32 pass_in = 0; - cmd->key = key; - - Command_Map *map = 0; - if (view) map = view->map; - if (map == 0) map = &vars->map_top; - Command_Binding cmd_bind = map_extract_recursive(map, key); - - User_Input user_in; - user_in.type = UserInputKey; - user_in.key = key; - user_in.command = (unsigned long long)cmd_bind.custom; - user_in.abort = 0; - - if ((EventOnEsc & abort_flags) && key.keycode == key_esc){ - user_in.abort = 1; - } - else if (EventOnAnyKey & abort_flags){ - user_in.abort = 1; - } - - if (EventOnAnyKey & get_flags){ - pass_in = 1; - consumed_input[0] = 1; - } - if (key.keycode == key_esc){ - if (EventOnEsc & get_flags){ - pass_in = 1; - } - consumed_input[1] = 1; - } - - if (pass_in){ - cmd->current_coroutine = vars->command_coroutine; - vars->command_coroutine = system->resume_coroutine(command_coroutine, - &user_in, vars->command_coroutine_flags); - app_result.redraw = 1; - - // TOOD(allen): Deduplicate - // TODO(allen): Allow a view to clean up however it wants after a command - // finishes, or after transfering to another view mid command. - File_View *fview = view_to_file_view(view); - if (fview != 0 && vars->command_coroutine == 0){ - init_query_set(&fview->query_set); - } - if (vars->command_coroutine == 0) break; - } - } - } - - if (vars->command_coroutine != 0 && (get_flags & EventOnMouse)){ - View *view = cmd->view; - b32 pass_in = 0; - - User_Input user_in; - user_in.type = UserInputMouse; - user_in.mouse = *mouse; - user_in.command = 0; - user_in.abort = 0; - - if (abort_flags & EventOnMouseMove){ - user_in.abort = 1; - } - if (get_flags & EventOnMouseMove){ - pass_in = 1; - consumed_input[2] = 1; - } - - if (mouse->press_l || mouse->release_l || mouse->l){ - if (abort_flags & EventOnLeftButton){ - user_in.abort = 1; - } - if (get_flags & EventOnLeftButton){ - pass_in = 1; - consumed_input[3] = 1; - } - } - - if (mouse->press_r || mouse->release_r || mouse->r){ - if (abort_flags & EventOnRightButton){ - user_in.abort = 1; - } - if (get_flags & EventOnRightButton){ - pass_in = 1; - consumed_input[4] = 1; - } - } - - if (mouse->wheel != 0){ - if (abort_flags & EventOnWheel){ - user_in.abort = 1; - } - if (get_flags & EventOnWheel){ - pass_in = 1; - consumed_input[5] = 1; - } - } - - if (pass_in){ - cmd->current_coroutine = vars->command_coroutine; - vars->command_coroutine = system->resume_coroutine(command_coroutine, &user_in, - vars->command_coroutine_flags); - app_result.redraw = 1; - - // TOOD(allen): Deduplicate - // TODO(allen): Allow a view to clean up however it wants after a command finishes, - // or after transfering to another view mid command. - File_View *fview = view_to_file_view(view); - if (fview != 0 && vars->command_coroutine == 0){ - init_query_set(&fview->query_set); - } - } - } - } - - update_command_data(vars, cmd); - - ProfileEnd(command_coroutine); - - // NOTE(allen): pass raw input to the panels - ProfileStart(step); - - Input_Summary dead_input = {}; - dead_input.mouse.x = mouse->x; - dead_input.mouse.y = mouse->y; - - Input_Summary active_input = {}; - active_input.mouse.x = mouse->x; - active_input.mouse.y = mouse->y; - if (!consumed_input[0]){ - active_input.keys = key_data; - } - else if (!consumed_input[1]){ - for (i32 i = 0; i < key_data.count; ++i){ - Key_Event_Data key = get_single_key(&key_data, i); - if (key.keycode == key_esc){ - active_input.keys.count = 1; - active_input.keys.keys[0] = key; - break; - } - } - } - - Mouse_State mouse_state = *mouse; - - if (consumed_input[3]){ - mouse_state.l = 0; - mouse_state.press_l = 0; - mouse_state.release_l = 0; - } - - if (consumed_input[4]){ - mouse_state.r = 0; - mouse_state.press_r = 0; - mouse_state.release_r = 0; - } - - if (consumed_input[5]){ - mouse_state.wheel = 0; - } - - { - Panel *panel = panels; - for (i32 panel_i = vars->layout.panel_count; panel_i > 0; --panel_i, ++panel){ - View *view_ = panel->view; - if (view_){ - Assert(view_->do_view); - b32 active = (panel == cmd->panel); - Input_Summary input = (active)?(active_input):(dead_input); - if (panel == mouse_panel && !mouse->out_of_window){ - input.mouse = mouse_state; - } - if (view_->do_view(system, exchange, view_, panel->inner, cmd->view, - VMSG_STEP, 0, &input, &active_input)){ - app_result.redraw = 1; - } - } - } - } - - update_command_data(vars, cmd); - ProfileEnd(step); - - // NOTE(allen): command execution - ProfileStart(command); - if (!consumed_input[0] || !consumed_input[1]){ - b32 consumed_input2[2] = {0}; - - for (i32 key_i = 0; key_i < key_data.count; ++key_i){ - switch (vars->state){ - case APP_STATE_EDIT: - { - Key_Event_Data key = get_single_key(&key_data, key_i); - b32 hit_esc = (key.keycode == key_esc); - cmd->key = key; - - if (hit_esc || !consumed_input[0]){ - View *view = cmd->view; - - Command_Map *map = 0; - if (view) map = view->map; - if (map == 0) map = &vars->map_top; - Command_Binding cmd_bind = map_extract_recursive(map, key); - - if (cmd_bind.function){ - if (hit_esc){ - consumed_input2[1] = 1; - } - else{ - consumed_input2[0] = 1; - } - - Coroutine *command_coroutine = system->create_coroutine(command_caller); - vars->command_coroutine = command_coroutine; - - Command_In cmd_in; - cmd_in.cmd = cmd; - cmd_in.bind = cmd_bind; - - cmd->current_coroutine = vars->command_coroutine; - vars->command_coroutine = system->launch_coroutine(vars->command_coroutine, - &cmd_in, vars->command_coroutine_flags); - vars->prev_command = cmd_bind; - app_result.redraw = 1; - } - } - }break; - - case APP_STATE_RESIZING: - { - if (key_data.count > 0){ - vars->state = APP_STATE_EDIT; - } - }break; - } - } - - consumed_input[0] |= consumed_input2[0]; - consumed_input[1] |= consumed_input2[1]; - } - - update_command_data(vars, cmd); - ProfileEnd(command); - - ProfileStart(resizing); - // NOTE(allen): panel resizing - switch (vars->state){ - case APP_STATE_EDIT: - { - if (mouse->press_l && mouse_on_divider){ - vars->state = APP_STATE_RESIZING; - Divider_And_ID div = layout_get_divider(&vars->layout, mouse_divider_id); - vars->resizing.divider = div.divider; - - i32 min, max; - { - i32 mid, MIN, MAX; - mid = div.divider->pos; - if (mouse_divider_vertical){ - MIN = 0; - MAX = MIN + vars->layout.full_width; - } - else{ - MIN = 0; - MAX = MIN + vars->layout.full_height; - } - min = MIN; - max = MAX; - - i32 divider_id = div.id; - do{ - Divider_And_ID other_div = layout_get_divider(&vars->layout, divider_id); - b32 divider_match = (other_div.divider->v_divider == mouse_divider_vertical); - i32 pos = other_div.divider->pos; - 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(&vars->mem.part); - i32 *divider_stack = push_array(&vars->mem.part, i32, vars->layout.panel_count); - i32 top = 0; - divider_stack[top++] = div.id; - - while (top > 0){ - Divider_And_ID other_div = layout_get_divider(&vars->layout, divider_stack[--top]); - b32 divider_match = (other_div.divider->v_divider == mouse_divider_vertical); - i32 pos = other_div.divider->pos; - 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); - } - - vars->resizing.min = min; - vars->resizing.max = max; - } - }break; - - case APP_STATE_RESIZING: - { - app_result.redraw = 1; - if (mouse->l){ - Panel_Divider *divider = vars->resizing.divider; - if (divider->v_divider){ - divider->pos = mx; - } - else{ - divider->pos = my; - } - - if (divider->pos < vars->resizing.min){ - divider->pos = vars->resizing.min; - } - else if (divider->pos > vars->resizing.max){ - divider->pos = vars->resizing.max - 1; - } - - layout_fix_all_panels(&vars->layout); - } - else{ - vars->state = APP_STATE_EDIT; - } - }break; - } - - if (mouse_in_edit_area && mouse_panel != 0 && mouse->press_l){ - vars->layout.active_panel = mouse_panel_i; - app_result.redraw = 1; - } - - update_command_data(vars, cmd); - ProfileEnd(resizing); - - // NOTE(allen): processing sys app bindings - ProfileStart(sys_app_bind_processing); - { - Mem_Options *mem = &vars->mem; - General_Memory *general = &mem->general; - - for (i32 i = 0; i < vars->sys_app_count; ++i){ - Sys_App_Binding *binding; - b32 remove = 0; - b32 failed = 0; - binding = vars->sys_app_bindings + i; - - byte *data; - i32 size, max; - Editing_File *ed_file; - Editing_File_Preload preload_settings; - char *filename; - - Working_Set *working_set = &vars->working_set; - - if (exchange_file_ready(exchange, binding->sys_id, &data, &size, &max)){ - ed_file = working_set->files + binding->app_id; - filename = exchange_file_filename(exchange, binding->sys_id); - preload_settings = ed_file->preload; - if (data){ - String val = make_string((char*)data, size); - file_create_from_string(system, mem, working_set, ed_file, filename, - vars->font_set, vars->style.font_id, val); - - if (ed_file->settings.tokens_exist){ - file_first_lex_parallel(system, general, ed_file); - } - - if ((binding->success & SysAppCreateView) && binding->panel != 0){ - view_file_in_panel(cmd, binding->panel, ed_file); - } - - app_result.redraw = 1; - } - else{ - if (binding->fail & SysAppCreateNewBuffer){ - file_create_empty(system, mem, working_set, ed_file, filename, - vars->font_set, vars->style.font_id); - if (binding->fail & SysAppCreateView){ - view_file_in_panel(cmd, binding->panel, ed_file); - } - } - else{ - table_remove(&vars->working_set.table, ed_file->name.source_path); - file_get_dummy(ed_file); - } - - app_result.redraw = 1; - } - - if (!ed_file->state.is_dummy){ - for (File_View_Iter iter = file_view_iter_init(&vars->layout, ed_file, 0); - file_view_iter_good(iter); - iter = file_view_iter_next(iter)){ - view_measure_wraps(system, general, iter.view); - view_cursor_move(iter.view, preload_settings.start_line, 0); - } - } - - exchange_free_file(exchange, binding->sys_id); - remove = 1; - } - - if (exchange_file_save_complete(exchange, binding->sys_id, &data, &size, &max, &failed)){ - Assert(remove == 0); - - if (data){ - general_memory_free(general, data); - exchange_clear_file(exchange, binding->sys_id); - } - - Editing_File *file = get_file(working_set, binding->app_id); - if (file){ - file_synchronize_times(system, file, file->name.source_path.str); - } - - exchange_free_file(exchange, binding->sys_id); - remove = 1; - - // if (failed) { TODO(allen): saving error, now what? } - } - - if (remove){ - *binding = vars->sys_app_bindings[--vars->sys_app_count]; - --i; - } - } - } - ProfileEnd(sys_app_bind_processing); - - // NOTE(allen): process as many delayed actions as possible - ProfileStart(delayed_actions); - if (vars->delay1.count > 0){ - Style *style = &vars->style; - Working_Set *working_set = &vars->working_set; - Live_Views *live_set = &vars->live_set; - Mem_Options *mem = &vars->mem; - General_Memory *general = &vars->mem.general; - - i32 count = vars->delay1.count; - vars->delay1.count = 0; - vars->delay2.count = 0; - - Delayed_Action *act = vars->delay1.acts; - for (i32 i = 0; i < count; ++i, ++act){ - String string = act->string; - Panel *panel = act->panel; - Editing_File *file = act->file; - i32 integer = act->integer; - - // TODO(allen): Paramter checking in each DACT case. - switch (act->type){ - case DACT_OPEN: - { - App_Open_File_Result result; - - result = app_open_file_background(vars, exchange, working_set, string); - - if (result.is_new){ - if (result.file){ - if (result.sys_id){ - Sys_App_Binding *binding = app_push_file_binding(vars, result.sys_id, result.file_index); - binding->success = SysAppCreateView; - binding->fail = 0; - binding->panel = panel; - } - else{ - delayed_action_repush(&vars->delay2, act); - } - } - } - else{ - if (result.file->state.is_dummy || result.file->state.is_loading){ - // do nothing - } - else{ - view_file_in_panel(cmd, panel, result.file); - } - } - }break; - - case DACT_OPEN_BACKGROUND: - { - App_Open_File_Result result; - result = app_open_file_background(vars, exchange, working_set, string); - if (result.is_new){ - if (result.file){ - if (result.sys_id){ - Sys_App_Binding *binding = app_push_file_binding(vars, result.sys_id, result.file_index); - binding->success = 0; - binding->fail = 0; - binding->panel = panel; - } - else{ - delayed_action_repush(&vars->delay2, act); - } - } - } - }break; - - case DACT_SET_LINE: - { - // TODO(allen): deduplicate - View *view = panel->view; - File_View *fview = view_to_file_view(view); - if (!fview && view->is_minor) fview = view_to_file_view(view->major); - if (!file){ - if (fview){ - file = working_set_lookup_file(working_set, string); - } - } - if (file && !file->state.is_dummy){ - if (file->state.is_loading){ - file->preload.start_line = integer; - } - else{ - view_cursor_move(fview, integer, 0); - } - } - }break; - - case DACT_SAVE_AS: - { - // TODO(allen): deduplicate - View *view = panel->view; - File_View *fview = view_to_file_view(view); - if (!fview && view->is_minor) fview = view_to_file_view(view->major); - if (!file){ - if (fview){ - file = working_set_lookup_file(working_set, string); - } - } - if (file && !file->state.is_dummy){ - i32 sys_id = file_save_and_set_names(system, exchange, mem, working_set, file, string.str); - if (sys_id){ - app_push_file_binding(vars, sys_id, get_file_id(working_set, file)); - } - else{ - delayed_action_repush(&vars->delay2, act); - } - } - }break; - - case DACT_SAVE: - { - if (!file){ - if (panel){ - View *view; - File_View *fview; - view = panel->view; - Assert(view); - if (view->is_minor) view = view->major; - fview = view_to_file_view(view); - if (fview){ - file = fview->file; - } - } - else{ - file = working_set_lookup_file(working_set, string); - } - } - // TODO(allen): We could handle the case where someone tries to save the same thing - // twice... that would be nice to have under control. - if (file && !file->state.is_dummy && buffer_needs_save(file)){ - i32 sys_id = file_save(system, exchange, mem, file, file->name.source_path.str); - if (sys_id){ - // TODO(allen): This is fishy! Shouldn't we bind it to a file name instead? This file - // might be killed before we get notified that the saving is done! - app_push_file_binding(vars, sys_id, get_file_id(working_set, file)); - } - else{ - delayed_action_repush(&vars->delay2, act); - } - } - }break; - - case DACT_NEW: - { - Get_File_Result file = working_set_get_available_file(working_set); - file_create_empty(system, mem, working_set, file.file, string.str, - vars->font_set, style->font_id); - table_add(&working_set->table, file.file->name.source_path, file.index); - - View *new_view = live_set_alloc_view(live_set, mem); - view_replace_major(system, exchange, new_view, panel, live_set); - - File_View *file_view = file_view_init(new_view, &vars->layout); - cmd->view = (View*)file_view; - view_set_file(file_view, file.file, vars->font_set, style, - system, vars->hooks[hook_open_file], &app_links); - new_view->map = app_get_map(vars, file.file->settings.base_map_id); -#if BUFFER_EXPERIMENT_SCALPEL <= 0 - if (file.file->settings.tokens_exist) - file_first_lex_parallel(system, general, file.file); -#endif - }break; - - case DACT_SWITCH: - { - Editing_File *file = working_set_lookup_file(working_set, string); - if (file){ - View *new_view = live_set_alloc_view(live_set, mem); - view_replace_major(system, exchange, new_view, panel, live_set); - - File_View *file_view = file_view_init(new_view, &vars->layout); - cmd->view = (View*)file_view; - - view_set_file(file_view, file, vars->font_set, style, - system, vars->hooks[hook_open_file], &app_links); - - new_view->map = app_get_map(vars, file->settings.base_map_id); - } - }break; - - case DACT_KILL: - { - Editing_File *file = working_set_lookup_file(working_set, string); - if (file){ - table_remove(&working_set->table, file->name.source_path); - kill_file(system, exchange, general, file, live_set, &vars->layout); - } - }break; - - case DACT_TRY_KILL: - { - Editing_File *file = working_set_lookup_file(working_set, string); - if (file){ - if (buffer_needs_save(file)){ - View *new_view = live_set_alloc_view(live_set, mem); - view_replace_minor(system, exchange, new_view, panel, live_set); - - new_view->map = &vars->map_ui; - Interactive_View *int_view = - interactive_view_init(system, new_view, &vars->hot_directory, style, - working_set, vars->font_set, &vars->delay1); - int_view->interaction = INTV_SURE_TO_KILL_INTER; - int_view->action = INTV_SURE_TO_KILL; - copy(&int_view->query, "Are you sure?"); - copy(&int_view->dest, file->name.live_name); - } - else{ - table_remove(&working_set->table, file->name.source_path); - kill_file(system, exchange, general, file, live_set, &vars->layout); - view_remove_minor(system, exchange, panel, live_set); - } - } - }break; - - case DACT_CLOSE_MINOR: - { - view_remove_minor(system, exchange, panel, live_set); - }break; - - case DACT_THEME_OPTIONS: - { - open_theme_options(system, exchange, vars, live_set, mem, panel); - }break; - - case DACT_KEYBOARD_OPTIONS: - { - open_config_options(system, exchange, vars, live_set, mem, panel); - }break; - } - - if (string.str){ - general_memory_free(&mem->general, string.str); - } - } - Swap(vars->delay1, vars->delay2); - } - ProfileEnd(delayed_actions); - - end_temp_memory(param_stack_temp); - - ProfileStart(resize); - // NOTE(allen): send resize messages to panels that have changed size - { - Panel *panel = panels; - for (i32 panel_i = vars->layout.panel_count; panel_i > 0; --panel_i, ++panel){ - i32_Rect prev = panel->prev_inner; - i32_Rect inner = panel->inner; - if (prev.x0 != inner.x0 || prev.y0 != inner.y0 || - prev.x1 != inner.x1 || prev.y1 != inner.y1){ - View *view = panel->view; - if (view){ - view->do_view(system, exchange, - view, inner, cmd->view, - VMSG_RESIZE, 0, &dead_input, &active_input); - view = (view->is_minor)?view->major:0; - if (view){ - view->do_view(system, exchange, - view, inner, cmd->view, - VMSG_RESIZE, 0, &dead_input, &active_input); - } - } - } - panel->prev_inner = inner; - } - } - ProfileEnd(resize); - - ProfileStart(style_change); - // NOTE(allen): send style change messages if the style has changed - if (vars->style.font_changed){ - vars->style.font_changed = 0; - - Editing_File *file = vars->working_set.files; - for (i32 i = vars->working_set.file_index_count; i > 0; --i, ++file){ - if (buffer_good(&file->state.buffer) && !file->state.is_dummy){ - Render_Font *font = get_font_info(vars->font_set, vars->style.font_id)->font; - float *advance_data = 0; - if (font) advance_data = font->advance_data; - - file_measure_starts_widths(system, &vars->mem.general, - &file->state.buffer, advance_data); - } - } - - Panel *panel = panels; - for (i32 panel_i = vars->layout.panel_count; panel_i > 0; --panel_i, ++panel){ - View *view = panel->view; - if (view){ - view->do_view(system, exchange, - view, panel->inner, cmd->view, - VMSG_STYLE_CHANGE, 0, &dead_input, &active_input); - view = (view->is_minor)?view->major:0; - if (view){ - view->do_view(system, exchange, - view, panel->inner, cmd->view, - VMSG_STYLE_CHANGE, 0, &dead_input, &active_input); - } - } - } - } - ProfileEnd(style_change); - - ProfileStart(redraw); - if (mouse_panel != vars->prev_mouse_panel) app_result.redraw = 1; - if (app_result.redraw){ - begin_render_section(target, system); - - target->clip_top = -1; - draw_push_clip(target, rect_from_target(target)); - - // NOTE(allen): render the panels - Panel *panel = panels; - for (i32 panel_i = vars->layout.panel_count; panel_i > 0; --panel_i, ++panel){ - i32_Rect full = panel->full; - i32_Rect inner = panel->inner; - - View *view = panel->view; - Style *style = &vars->style; - - b32 active = (panel == cmd->panel); - u32 back_color = style->main.back_color; - draw_rectangle(target, full, back_color); - - if (view){ - Assert(view->do_view); - draw_push_clip(target, panel->inner); - view->do_view(system, exchange, - view, panel->inner, cmd->view, - VMSG_DRAW, target, &dead_input, &active_input); - draw_pop_clip(target); - } - - 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); - } - ProfileEnd(redraw); - - ProfileStart(get_cursor); - // NOTE(allen): get cursor type - if (mouse_in_edit_area){ - View *view = mouse_panel->view; - if (view){ - app_result.mouse_cursor_type = view->mouse_cursor_type; - } - else{ - 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; - } - } - vars->prev_mouse_panel = mouse_panel; - ProfileEnd(get_cursor); - - *result = app_result; - result->lctrl_lalt_is_altgr = vars->settings.lctrl_lalt_is_altgr; - - // end-of-app_step -} - -#if 0 -internal -App_Alloc_Sig(app_alloc){ - Mem_Options *mem = (Mem_Options*)(handle); - void *result = general_memory_allocate(&mem->general, size, 0); - return(result); -} - -internal -App_Free_Sig(app_free){ - Mem_Options *mem = (Mem_Options*)(handle); - general_memory_free(&mem->general, block); -} -#endif - -external App_Get_Functions_Sig(app_get_functions){ - App_Functions result = {}; - - result.read_command_line = app_read_command_line; - result.init = app_init; - result.step = app_step; - -#if 0 - result.alloc = app_alloc; - result.free = app_free; -#endif - - return(result); -} - -// BOTTOM - +/* + * Mr. 4th Dimention - Allen Webster + * + * 12.12.2014 + * + * Application layer for project codename "4ed" + * + */ + +// TOP + +// App Structs + +enum App_State{ + APP_STATE_EDIT, + APP_STATE_RESIZING, + // never below this + APP_STATE_COUNT +}; + +struct App_State_Resizing{ + Panel_Divider *divider; + i32 min, max; +}; + +struct CLI_Process{ + CLI_Handles cli; + Editing_File *out_file; +}; + +struct CLI_List{ + CLI_Process *procs; + i32 count, max; +}; + +#define SysAppCreateView 0x1 +#define SysAppCreateNewBuffer 0x2 + +struct Sys_App_Binding{ + i32 sys_id; + i32 app_id; + + u32 success; + u32 fail; + Panel *panel; +}; + +struct Complete_State{ + Search_Set set; + Search_Iter iter; + Table hits; + String_Space str; + i32 word_start, word_end; + b32 initialized; +}; + +struct Command_Data{ + Mem_Options *mem; + Panel *panel; + View *view; + Working_Set *working_set; + Editing_Layout *layout; + Live_Views *live_set; + Style *style; + Delay *delay; + struct App_Vars *vars; + Exchange *exchange; + System_Functions *system; + Coroutine *current_coroutine; + + i32 screen_width, screen_height; + Key_Event_Data key; + + Partition part; +}; + +struct App_Vars{ + Mem_Options mem; + + App_Settings settings; + + Command_Map map_top; + Command_Map map_file; + Command_Map map_ui; +#if FRED_INTERNAL + Command_Map map_debug; +#endif + Command_Map *user_maps; + i32 *map_id_table; + i32 user_map_count; + Command_Binding prev_command; + + Coroutine *command_coroutine; + u32 command_coroutine_flags[2]; + + Sys_App_Binding *sys_app_bindings; + i32 sys_app_count, sys_app_max; + + Custom_Command_Function *hooks[hook_type_count]; + + Font_Set *font_set; + + Style style; + Style_Library styles; + u32 *palette; + i32 palette_size; + + Editing_Layout layout; + Live_Views live_set; + Working_Set working_set; + + char hot_dir_base_[256]; + Hot_Directory hot_directory; + + CLI_List cli_processes; + + Delay delay1, delay2; + + String mini_str; + u8 mini_buffer[512]; + + App_State state; + App_State_Resizing resizing; + Complete_State complete_state; + Panel *prev_mouse_panel; + + Command_Data command_data; + + Custom_API config_api; +}; + +internal i32 +app_get_or_add_map_index(App_Vars *vars, i32 mapid){ + i32 result; + i32 user_map_count = vars->user_map_count; + i32 *map_id_table = vars->map_id_table; + for (result = 0; result < user_map_count; ++result){ + if (map_id_table[result] == mapid) break; + if (map_id_table[result] == 0){ + map_id_table[result] = mapid; + break; + } + } + return result; +} + +internal i32 +app_get_map_index(App_Vars *vars, i32 mapid){ + i32 result; + i32 user_map_count = vars->user_map_count; + i32 *map_id_table = vars->map_id_table; + for (result = 0; result < user_map_count; ++result){ + if (map_id_table[result] == mapid) break; + if (map_id_table[result] == 0){ + result = user_map_count; + break; + } + } + return result; +} + +internal Command_Map* +app_get_map(App_Vars *vars, i32 mapid){ + Command_Map *map = 0; + if (mapid < mapid_global) map = vars->user_maps + mapid; + else if (mapid == mapid_global) map = &vars->map_top; + else if (mapid == mapid_file) map = &vars->map_file; + return map; +} + +// Commands + +globalvar Application_Links app_links; + +#define USE_MEM(n) Mem_Options *n = command->mem +#define USE_PANEL(n) Panel *n = command->panel +#define USE_VIEW(n) View *n = command->view +#define USE_FILE_VIEW(n) File_View *n = view_to_file_view(command->view) +#define USE_FILE(n,v) Editing_File *n = 0; if (v) { (n) = (v)->file; } +#define USE_WORKING_SET(n) Working_Set *n = command->working_set +#define USE_LAYOUT(n) Editing_Layout *n = command->layout +#define USE_LIVE_SET(n) Live_Views *live_set = command->live_set +#define USE_STYLE(n) Style *n = command->style +#define USE_DELAY(n) Delay *n = command->delay +#define USE_VARS(n) App_Vars *n = command->vars +#define USE_EXCHANGE(n) Exchange *n = command->exchange +#define USE_FONT_SET(n) Font_Set *n = command->vars->font_set; + +#define REQ_VIEW(n) View *n = command->view; if (!n) return +#define REQ_FILE_VIEW(n) File_View *n = view_to_file_view(command->view); if (!n) return +#define REQ_OPEN_FILE_VIEW(n) File_View *n = view_to_file_view(command->view); if (!n || n->locked) return +#define REQ_FILE_HISTORY(n,v) Editing_File *n = (v)->file; if (!n || !buffer_good(&n->state.buffer) || n->state.is_dummy || !n->state.undo.undo.edits) return +#define REQ_FILE_LOADING(n,v) Editing_File *n = (v)->file; if (!n || n->state.is_dummy) return +#define REQ_FILE(n,v) Editing_File *n = (v)->file; if (!n || !buffer_good(&n->state.buffer) || n->state.is_dummy) return +#define REQ_COLOR_VIEW(n) Color_View *n = view_to_color_view(command->view); if (!n) return +#define REQ_DBG_VIEW(n) Debug_View *n = view_to_debug_view(command->view); if (!n) return + +#define COMMAND_DECL(n) internal void command_##n(System_Functions *system, Command_Data *command, Command_Binding binding) +#define COMPOSE_DECL(n) internal void n(System_Functions *system, Command_Data *command, Command_Binding binding) + +struct Command_Parameter{ + i32 type; + union{ + struct{ + Dynamic param; + Dynamic value; + } param; + struct{ + i32 len; + char *str; + } inline_string; + }; +}; + +inline Command_Parameter* +param_next(Command_Parameter *param, Command_Parameter *end){ + Command_Parameter *result = param; + if (result->type == 0){ + ++result; + } + while (result->type != 0 && result < end){ + i32 len = result->inline_string.len; + len += sizeof(*result) - 1; + len -= (len % sizeof(*result)); + result = (Command_Parameter*)((char*)result + len + sizeof(*result)); + } + return result; +} + +inline Command_Parameter* +param_stack_first(Partition *part, Command_Parameter *end){ + Command_Parameter *result = (Command_Parameter*)part->base; + if (result->type != 0) result = param_next(result, end); + return result; +} + +inline Command_Parameter* +param_stack_end(Partition *part){ + return (Command_Parameter*)((char*)part->base + part->pos); +} + +internal File_View* +panel_make_empty(System_Functions *system, Exchange *exchange, + App_Vars *vars, Style *style, Panel *panel){ + + Mem_Options *mem = &vars->mem; + Live_Views *live_set = &vars->live_set; + Editing_Layout *layout = &vars->layout; + Working_Set *working_set = &vars->working_set; + + // TODO(allen): vars->delay pointer for directing all delayed actions to appropriate place + Delay *delay = &vars->delay1; + + View *new_view; + File_View *file_view; + + new_view = live_set_alloc_view(live_set, mem); + if (panel->view){ + view_replace_major(system, exchange, new_view, panel, live_set); + } + else{ + view_set_first(new_view, panel); + } + file_view = file_view_init(new_view, layout, working_set, delay, + &vars->settings, &vars->hot_directory, mem, &vars->styles); + view_set_file(file_view, 0, vars->font_set, style, 0, 0, 0); + new_view->map = app_get_map(vars, mapid_global); + + return(file_view); +} + +COMMAND_DECL(null){ + AllowLocal(command); +} + +COMMAND_DECL(write_character){ + ProfileMomentFunction(); + REQ_OPEN_FILE_VIEW(view); + REQ_FILE(file, view); + USE_LAYOUT(layout); + USE_MEM(mem); + + char character; + i32 pos, next_cursor_pos; + + character = command->key.character; + if (character != 0){ + pos = view->cursor.pos; + next_cursor_pos = view->cursor.pos + 1; + view_replace_range(system, mem, view, layout, pos, pos, &character, 1, next_cursor_pos); + view_cursor_move(view, next_cursor_pos); + file->state.cursor_pos = view->cursor.pos; + } +} + +COMMAND_DECL(seek_whitespace_right){ + ProfileMomentFunction(); + REQ_FILE_VIEW(view); + REQ_FILE(file, view); + + i32 pos = buffer_seek_whitespace_right(&file->state.buffer, view->cursor.pos); + view_cursor_move(view, pos); +} + +COMMAND_DECL(seek_whitespace_left){ + ProfileMomentFunction(); + REQ_FILE_VIEW(view); + REQ_FILE(file, view); + + i32 pos = buffer_seek_whitespace_left(&file->state.buffer, view->cursor.pos); + view_cursor_move(view, pos); +} + +COMMAND_DECL(seek_whitespace_up){ + ProfileMomentFunction(); + REQ_FILE_VIEW(view); + REQ_FILE(file, view); + + i32 pos = buffer_seek_whitespace_up(&file->state.buffer, view->cursor.pos); + view_cursor_move(view, pos); +} + +COMMAND_DECL(seek_whitespace_down){ + ProfileMomentFunction(); + REQ_FILE_VIEW(view); + REQ_FILE(file, view); + + i32 pos = buffer_seek_whitespace_down(&file->state.buffer, view->cursor.pos); + view_cursor_move(view, pos); +} + +internal i32 +seek_token_left(Cpp_Token_Stack *tokens, i32 pos){ + Cpp_Get_Token_Result get = cpp_get_token(tokens, pos); + if (get.token_index == -1){ + get.token_index = 0; + } + + Cpp_Token *token = tokens->tokens + get.token_index; + if (token->start == pos && get.token_index > 0){ + --token; + } + + return token->start; +} + +internal i32 +seek_token_right(Cpp_Token_Stack *tokens, i32 pos){ + Cpp_Get_Token_Result get = cpp_get_token(tokens, pos); + if (get.in_whitespace){ + ++get.token_index; + } + if (get.token_index >= tokens->count){ + get.token_index = tokens->count-1; + } + + Cpp_Token *token = tokens->tokens + get.token_index; + return token->start + token->size; +} + +COMMAND_DECL(seek_token_left){ + ProfileMomentFunction(); + REQ_FILE_VIEW(view); + REQ_FILE(file, view); + + if (file->state.tokens_complete){ + i32 pos = seek_token_left(&file->state.token_stack, view->cursor.pos); + view_cursor_move(view, pos); + } +} + +COMMAND_DECL(seek_token_right){ + ProfileMomentFunction(); + REQ_FILE_VIEW(view); + REQ_FILE(file, view); + + if (file->state.tokens_complete){ + i32 pos = seek_token_right(&file->state.token_stack, view->cursor.pos); + view_cursor_move(view, pos); + } +} + +COMMAND_DECL(seek_white_or_token_right){ + ProfileMomentFunction(); + REQ_FILE_VIEW(view); + REQ_FILE(file, view); + + i32 token_pos, white_pos; + if (file->state.tokens_complete){ + token_pos = seek_token_right(&file->state.token_stack, view->cursor.pos); + } + else{ + token_pos = buffer_size(&file->state.buffer); + } + white_pos = buffer_seek_whitespace_right(&file->state.buffer, view->cursor.pos); + view_cursor_move(view, Min(token_pos, white_pos)); +} + +COMMAND_DECL(seek_white_or_token_left){ + ProfileMomentFunction(); + REQ_FILE_VIEW(view); + REQ_FILE(file, view); + + i32 token_pos, white_pos; + if (file->state.tokens_complete){ + token_pos = seek_token_left(&file->state.token_stack, view->cursor.pos); + } + else{ + token_pos = 0; + } + white_pos = buffer_seek_whitespace_left(&file->state.buffer, view->cursor.pos); + view_cursor_move(view, Max(token_pos, white_pos)); +} + +COMMAND_DECL(seek_alphanumeric_right){ + ProfileMomentFunction(); + REQ_FILE_VIEW(view); + REQ_FILE(file, view); + + i32 pos = buffer_seek_alphanumeric_right(&file->state.buffer, view->cursor.pos); + view_cursor_move(view, pos); +} + +COMMAND_DECL(seek_alphanumeric_left){ + ProfileMomentFunction(); + REQ_FILE_VIEW(view); + REQ_FILE(file, view); + + i32 pos = buffer_seek_alphanumeric_left(&file->state.buffer, view->cursor.pos); + view_cursor_move(view, pos); +} + +COMMAND_DECL(seek_alphanumeric_or_camel_right){ + ProfileMomentFunction(); + REQ_FILE_VIEW(view); + REQ_FILE(file, view); + + i32 pos = buffer_seek_alphanumeric_or_camel_right(&file->state.buffer, view->cursor.pos); + view_cursor_move(view, pos); +} + +COMMAND_DECL(seek_alphanumeric_or_camel_left){ + ProfileMomentFunction(); + REQ_FILE_VIEW(view); + REQ_FILE(file, view); + + i32 pos = buffer_seek_alphanumeric_or_camel_left(&file->state.buffer, view->cursor.pos); + view_cursor_move(view, pos); +} + +COMMAND_DECL(word_complete){ + ProfileMomentFunction(); + REQ_FILE_VIEW(view); + REQ_FILE(file, view); + USE_LAYOUT(layout); + USE_MEM(mem); + USE_VARS(vars); + USE_WORKING_SET(working_set); + + Partition *part = &mem->part; + General_Memory *general = &mem->general; + Complete_State *complete_state = &vars->complete_state; + Search_Range *ranges; + Search_Match match; + + Temp_Memory temp; + + Buffer_Type *buffer; + Buffer_Backify_Type loop; + char *data; + i32 end; + i32 size_of_buffer; + + i32 cursor_pos, word_start, word_end; + char c; + + char *spare; + i32 size; + + i32 buffer_count, i, j; + Editing_File *file_ptr; + + i32 match_size; + b32 do_init = 0; + + buffer = &file->state.buffer; + size_of_buffer = buffer_size(buffer); + + if (view->mode.rewrite != 2){ + do_init = 1; + } + view->next_mode.rewrite = 2; + + if (complete_state->initialized == 0){ + do_init = 1; + } + + if (do_init){ + word_end = view->cursor.pos; + word_start = word_end; + cursor_pos = word_end - 1; + + // TODO(allen): macros for these buffer loops and some method of breaking out of them. + for (loop = buffer_backify_loop(buffer, cursor_pos, 0); + buffer_backify_good(&loop); + buffer_backify_next(&loop)){ + end = loop.absolute_pos; + data = loop.data - loop.absolute_pos; + for (; cursor_pos >= end; --cursor_pos){ + c = data[cursor_pos]; + if (char_is_alpha(c)){ + word_start = cursor_pos; + } + else if (!char_is_numeric(c)){ + goto double_break; + } + } + } + double_break:; + + size = word_end - word_start; + + if (size == 0){ + complete_state->initialized = 0; + return; + } + + complete_state->initialized = 1; + search_iter_init(general, &complete_state->iter, size); + buffer_stringify(buffer, word_start, word_end, complete_state->iter.word.str); + complete_state->iter.word.size = size; + + buffer_count = working_set->file_index_count; + search_set_init(general, &complete_state->set, buffer_count + 1); + ranges = complete_state->set.ranges; + ranges[0].buffer = buffer; + ranges[0].start = 0; + ranges[0].size = word_start; + + ranges[1].buffer = buffer; + ranges[1].start = word_end; + ranges[1].size = size_of_buffer - word_end; + + file_ptr = working_set->files; + for (i = 0, j = 2; i < buffer_count; ++i, ++file_ptr){ + if (file_ptr != file && !file_ptr->state.is_dummy){ + ranges[j].buffer = &file_ptr->state.buffer; + ranges[j].start = 0; + ranges[j].size = buffer_size(ranges[j].buffer); + ++j; + } + } + complete_state->set.count = j; + + search_hits_init(general, &complete_state->hits, &complete_state->str, 100, Kbytes(4)); + search_hit_add(general, &complete_state->hits, &complete_state->str, + complete_state->iter.word.str, complete_state->iter.word.size); + + complete_state->word_start = word_start; + complete_state->word_end = word_end; + } + else{ + word_start = complete_state->word_start; + word_end = complete_state->word_end; + size = complete_state->iter.word.size; + } + + if (size > 0){ + for (;;){ + match = search_next_match(part, &complete_state->set, &complete_state->iter); + + if (match.found_match){ + temp = begin_temp_memory(part); + match_size = match.end - match.start; + spare = (char*)push_array(part, char, match_size); + buffer_stringify(match.buffer, match.start, match.end, spare); + + if (search_hit_add(general, &complete_state->hits, &complete_state->str, spare, match_size)){ + view_replace_range(system, mem, view, layout, word_start, word_end, spare, match_size, word_end); + + complete_state->word_end = word_start + match_size; + complete_state->set.ranges[1].start = word_start + match_size; + break; + } + end_temp_memory(temp); + } + else{ + complete_state->iter.pos = 0; + complete_state->iter.i = 0; + + search_hits_init(general, &complete_state->hits, &complete_state->str, 100, Kbytes(4)); + search_hit_add(general, &complete_state->hits, &complete_state->str, + complete_state->iter.word.str, complete_state->iter.word.size); + + match_size = complete_state->iter.word.size; + view_replace_range(system, mem, view, layout, word_start, word_end, + complete_state->iter.word.str, match_size, word_end); + + complete_state->word_end = word_start + match_size; + complete_state->set.ranges[1].start = word_start + match_size; + break; + } + } + } +} + +COMMAND_DECL(set_mark){ + ProfileMomentFunction(); + REQ_FILE_VIEW(view); + REQ_FILE(file, view); + + view->mark = (i32)view->cursor.pos; +} + +COMMAND_DECL(copy){ + ProfileMomentFunction(); + REQ_FILE_VIEW(view); + REQ_FILE(file, view); + USE_WORKING_SET(working_set); + USE_MEM(mem); + + // TODO(allen): deduplicate + int r_start = 0, r_end = 0; + int start_set = 0, end_set = 0; + + Command_Parameter *end = param_stack_end(&command->part); + Command_Parameter *param = param_stack_first(&command->part, end); + for (; param < end; param = param_next(param, end)){ + int p = dynamic_to_int(¶m->param.param); + switch (p){ + case par_range_start: + start_set = 1; + r_start = dynamic_to_int(¶m->param.value); + break; + + case par_range_end: + end_set = 1; + r_end = dynamic_to_int(¶m->param.value); + break; + } + } + + Range range = make_range(view->cursor.pos, view->mark); + if (start_set) range.start = r_start; + if (end_set) range.end = r_end; + if (range.start < range.end){ + clipboard_copy(system, &mem->general, working_set, range, file); + } +} + +COMMAND_DECL(cut){ + ProfileMomentFunction(); + REQ_OPEN_FILE_VIEW(view); + REQ_FILE(file, view); + USE_WORKING_SET(working_set); + USE_LAYOUT(layout); + USE_MEM(mem); + + // TODO(allen): deduplicate + int r_start = 0, r_end = 0; + int start_set = 0, end_set = 0; + + Command_Parameter *end = param_stack_end(&command->part); + Command_Parameter *param = param_stack_first(&command->part, end); + for (; param < end; param = param_next(param, end)){ + int p = dynamic_to_int(¶m->param.param); + switch (p){ + case par_range_start: + start_set = 1; + r_start = dynamic_to_int(¶m->param.value); + break; + + case par_range_end: + end_set = 1; + r_end = dynamic_to_int(¶m->param.value); + break; + } + } + + Range range = make_range(view->cursor.pos, view->mark); + if (start_set) range.start = r_start; + if (end_set) range.end = r_end; + if (range.start < range.end){ + i32 next_cursor_pos = range.start; + + clipboard_copy(system, &mem->general, working_set, range, file); + view_replace_range(system, mem, view, layout, range.start, range.end, 0, 0, next_cursor_pos); + + view->mark = range.start; + view_cursor_move(view, next_cursor_pos); + } +} + +COMMAND_DECL(paste){ + ProfileMomentFunction(); + REQ_OPEN_FILE_VIEW(view); + REQ_FILE(file, view); + USE_WORKING_SET(working_set); + USE_LAYOUT(layout); + USE_MEM(mem); + + Panel *current_panel; + String *src; + File_View *current_view; + i32 pos_left, next_cursor_pos; + i32 panel_count; + i32 i; + + if (working_set->clipboard_size > 0){ + view->next_mode.rewrite = 1; + + src = working_set_clipboard_head(working_set); + pos_left = view->cursor.pos; + + next_cursor_pos = pos_left+src->size; + view_replace_range(system, mem, view, layout, pos_left, pos_left, src->str, src->size, next_cursor_pos); + + view_cursor_move(view, next_cursor_pos); + view->mark = pos_left; + + current_panel = layout->panels; + panel_count = layout->panel_count; + for (i = 0; i < panel_count; ++i, ++current_panel){ + current_view = view_to_file_view(current_panel->view); + + if (current_view && current_view->file == file){ + view_post_paste_effect(current_view, 20, pos_left, src->size, + current_view->style->main.paste_color); + } + } + } +} + +COMMAND_DECL(paste_next){ + ProfileMomentFunction(); + REQ_OPEN_FILE_VIEW(view); + REQ_FILE(file, view); + USE_WORKING_SET(working_set); + USE_LAYOUT(layout); + USE_MEM(mem); + + if (working_set->clipboard_size > 0 && view->mode.rewrite == 1){ + view->next_mode.rewrite = 1; + + Range range = make_range(view->mark, view->cursor.pos); + String *src = working_set_clipboard_roll_down(working_set); + i32 next_cursor_pos = range.start+src->size; + view_replace_range(system, + mem, view, layout, range.start, range.end, + src->str, src->size, next_cursor_pos); + + view_cursor_move(view, next_cursor_pos); + view->mark = range.start; + + Editing_Layout *layout = command->layout; + Panel *panels = layout->panels; + i32 panel_count = layout->panel_count; + for (i32 i = 0; i < panel_count; ++i){ + Panel *current_panel = panels + i; + File_View *current_view = view_to_file_view(current_panel->view); + + if (current_view && current_view->file == file){ + view_post_paste_effect(current_view, 20, range.start, src->size, + current_view->style->main.paste_color); + } + } + } + else{ + command_paste(system, command, binding); + } +} + +COMMAND_DECL(delete_range){ + ProfileMomentFunction(); + REQ_OPEN_FILE_VIEW(view); + REQ_FILE(file, view); + USE_LAYOUT(layout); + USE_MEM(mem); + + Range range = make_range(view->cursor.pos, view->mark); + if (range.start < range.end){ + i32 next_cursor_pos = range.start; + view_replace_range(system, mem, view, layout, range.start, range.end, + 0, 0, next_cursor_pos); + view_cursor_move(view, next_cursor_pos); + view->mark = range.start; + } +} + +COMMAND_DECL(timeline_scrub){ + ProfileMomentFunction(); + REQ_FILE_VIEW(view); + REQ_FILE_HISTORY(file, view); + + view_set_widget(view, FWIDG_TIMELINES); + view->widget.timeline.undo_line = 1; + view->widget.timeline.history_line = 1; +} + +COMMAND_DECL(undo){ + ProfileMomentFunction(); + REQ_FILE_VIEW(view); + REQ_FILE_HISTORY(file, view); + USE_LAYOUT(layout); + USE_MEM(mem); + + view_undo(system, mem, layout, view); +} + +COMMAND_DECL(redo){ + ProfileMomentFunction(); + REQ_FILE_VIEW(view); + REQ_FILE_HISTORY(file, view); + USE_LAYOUT(layout); + USE_MEM(mem); + + view_redo(system, mem, layout, view); +} + +COMMAND_DECL(history_backward){ + ProfileMomentFunction(); + REQ_FILE_VIEW(view); + REQ_FILE_HISTORY(file, view); + USE_LAYOUT(layout); + USE_MEM(mem); + + view_history_step(system, mem, layout, view, hist_backward); +} + +COMMAND_DECL(history_forward){ + ProfileMomentFunction(); + REQ_FILE_VIEW(view); + REQ_FILE_HISTORY(file, view); + USE_LAYOUT(layout); + USE_MEM(mem); + + view_history_step(system, mem, layout, view, hist_forward); +} + +#if UseFileHistoryDump +COMMAND_DECL(save_history){ + ProfileMomentFunction(); + REQ_FILE_VIEW(view); + REQ_FILE(file, view); + USE_MEM(mem); + + file_dump_history(system, mem, file, "history_data.hst"); +} +#endif + +COMMAND_DECL(interactive_new){ + ProfileMomentFunction(); + USE_FILE_VIEW(fview); + USE_VARS(vars); + USE_PANEL(panel); + USE_STYLE(style); + USE_EXCHANGE(exchange); + + if (!fview){ + fview = panel_make_empty(system, exchange, vars, style, panel); + } + + view_show_interactive(system, fview, &vars->map_ui, + IAct_New, IInt_Sys_File_List, make_lit_string("New: ")); +} + +internal Sys_App_Binding* +app_push_file_binding(App_Vars *vars, int sys_id, int app_id){ + Sys_App_Binding *binding; + Assert(vars->sys_app_count < vars->sys_app_max); + binding = vars->sys_app_bindings + vars->sys_app_count++; + binding->sys_id = sys_id; + binding->app_id = app_id; + return(binding); +} + +struct App_Open_File_Result{ + Editing_File *file; + i32 sys_id; + i32 file_index; + b32 is_new; +}; + +internal App_Open_File_Result +app_open_file_background(App_Vars *vars, Exchange *exchange, Working_Set *working_set, String filename){ + Get_File_Result file; + i32 file_id; + App_Open_File_Result result = {}; + + result.file = working_set_contains(working_set, filename); + if (result.file == 0){ + result.is_new = 1; + file = working_set_get_available_file(working_set); + if (file.file){ + result.file = file.file; + file_id = exchange_request_file(exchange, filename.str, filename.size); + if (file_id){ + file_init_strings(result.file); + file_set_name(working_set, result.file, filename.str); + file_set_to_loading(result.file); + table_add(&working_set->table, result.file->name.source_path, file.index); + + result.sys_id = file_id; + result.file_index = file.index; + } + else{ + file_get_dummy(file.file); + } + } + } + + return(result); +} + +COMMAND_DECL(interactive_open){ + ProfileMomentFunction(); + USE_VARS(vars); + USE_PANEL(panel); + USE_STYLE(style); + USE_DELAY(delay); + USE_EXCHANGE(exchange); + + char *filename = 0; + int filename_len = 0; + int do_in_background = 0; + + Command_Parameter *end = param_stack_end(&command->part); + Command_Parameter *param = param_stack_first(&command->part, end); + for (; param < end; param = param_next(param, end)){ + if (param->param.param.type == dynamic_type_int){ + if (param->param.param.int_value == par_name && + param->param.value.type == dynamic_type_string){ + filename = param->param.value.str_value; + filename_len = param->param.value.str_len; + } + else if (param->param.param.int_value == par_do_in_background){ + do_in_background = dynamic_to_int(¶m->param.value); + } + } + } + + if (filename){ + String string = make_string(filename, filename_len); + if (do_in_background){ + delayed_open_background(delay, string); + } + else{ + delayed_open(delay, string, panel); + } + } + else{ + View *view = panel->view; + Assert(view); + + File_View *fview = view_to_file_view(view); + + if (!fview){ + fview = panel_make_empty(system, exchange, vars, style, panel); + } + + view_show_interactive(system, fview, &vars->map_ui, + IAct_Open, IInt_Sys_File_List, make_lit_string("Open: ")); + } +} + +internal void +view_file_in_panel(Command_Data *cmd, Panel *panel, Editing_File *file){ + Live_Views *live_set = cmd->live_set; + Mem_Options *mem = cmd->mem; + Exchange *exchange = cmd->exchange; + System_Functions *system = cmd->system; + Editing_Layout *layout = cmd->layout; + App_Vars *vars = cmd->vars; + Style *style = cmd->style; + Working_Set *working_set = &vars->working_set; + Delay *delay = &vars->delay1; + + Partition old_part; + Temp_Memory temp; + View *new_view, *old_view; + File_View *file_view; + + new_view = live_set_alloc_view(live_set, mem); + view_replace_major(system, exchange, new_view, panel, live_set); + + file_view = file_view_init(new_view, layout, working_set, delay, + &vars->settings, &vars->hot_directory, mem, &vars->styles); + + old_view = cmd->view; + cmd->view = new_view; + + old_part = cmd->part; + temp = begin_temp_memory(&mem->part); + cmd->part = partition_sub_part(&mem->part, Kbytes(16)); + + view_set_file(file_view, file, vars->font_set, style, + system, vars->hooks[hook_open_file], &app_links); + + cmd->part = old_part; + end_temp_memory(temp); + cmd->view = old_view; + + new_view->map = app_get_map(vars, file->settings.base_map_id); +} + +// TODO(allen): Improvements to reopen +// - Preserve existing token stack +// - Keep current version open and do some sort of diff to keep +// the cursor position correct +COMMAND_DECL(reopen){ + ProfileMomentFunction(); + REQ_FILE_VIEW(view); + REQ_FILE(file, view); + USE_EXCHANGE(exchange); + USE_WORKING_SET(working_set); + USE_VARS(vars); + USE_STYLE(style); + + i32 file_id = exchange_request_file(exchange, expand_str(file->name.source_path)); + i32 index = 0; + if (file_id){ + file_set_to_loading(file); + index = working_set_get_index(working_set, file); + app_push_file_binding(vars, file_id, index); + + view_set_file(view, file, vars->font_set, style, + system, vars->hooks[hook_open_file], &app_links); + } + else{ + // TODO(allen): feedback message + } +} + +COMMAND_DECL(save){ + ProfileMomentFunction(); + USE_FILE_VIEW(view); + USE_FILE(file, view); + USE_DELAY(delay); + USE_WORKING_SET(working_set); + + char *filename = 0; + int filename_len = 0; + int buffer_id = -1; + + Command_Parameter *end = param_stack_end(&command->part); + Command_Parameter *param = param_stack_first(&command->part, end); + for (; param < end; param = param_next(param, end)){ + int v = dynamic_to_int(¶m->param.param); + if (v == par_name && param->param.value.type == dynamic_type_string){ + filename = param->param.value.str_value; + filename_len = param->param.value.str_len; + } + else if (v == par_buffer_id && param->param.value.type == dynamic_type_int){ + buffer_id = dynamic_to_int(¶m->param.value); + } + } + + String name = {}; + if (filename){ + name = make_string(filename, filename_len); + } + else if (file){ + name = file->name.source_path; + } + + if (name.size != 0){ + if (buffer_id == -1){ + if (file){ + delayed_save(delay, name, file); + } + } + else{ + file = working_set->files + buffer_id; + + if (!file->state.is_dummy && file_is_ready(file)){ + delayed_save(delay, name, file); + } + else{ + delayed_save(delay, name); + } + } + } +} + +COMMAND_DECL(interactive_save_as){ + ProfileMomentFunction(); + USE_FILE_VIEW(fview); + USE_VARS(vars); + USE_PANEL(panel); + USE_STYLE(style); + USE_EXCHANGE(exchange); + + if (!fview){ + fview = panel_make_empty(system, exchange, vars, style, panel); + } + + view_show_interactive(system, fview, &vars->map_ui, + IAct_Save_As, IInt_Sys_File_List, make_lit_string("Save As: ")); +} + +COMMAND_DECL(change_active_panel){ + ProfileMomentFunction(); + USE_LAYOUT(layout); + if (layout->panel_count > 1){ + ++layout->active_panel; + if (layout->active_panel >= layout->panel_count){ + layout->active_panel = 0; + } + } +} + +COMMAND_DECL(interactive_switch_buffer){ + ProfileMomentFunction(); + USE_FILE_VIEW(fview); + USE_VARS(vars); + USE_PANEL(panel); + USE_STYLE(style); + USE_EXCHANGE(exchange); + + if (!fview){ + fview = panel_make_empty(system, exchange, vars, style, panel); + } + + view_show_interactive(system, fview, &vars->map_ui, + IAct_Switch, IInt_Live_File_List, make_lit_string("Switch Buffer: ")); +} + +COMMAND_DECL(interactive_kill_buffer){ + ProfileMomentFunction(); + USE_FILE_VIEW(fview); + USE_VARS(vars); + USE_PANEL(panel); + USE_STYLE(style); + USE_EXCHANGE(exchange); + + if (!fview){ + fview = panel_make_empty(system, exchange, vars, style, panel); + } + + view_show_interactive(system, fview, &vars->map_ui, + IAct_Kill, IInt_Live_File_List, make_lit_string("Kill Buffer: ")); +} + +COMMAND_DECL(kill_buffer){ + ProfileMomentFunction(); + REQ_FILE_VIEW(view); + REQ_FILE(file, view); + USE_DELAY(delay); + + delayed_try_kill(delay, file->name.live_name, view->view_base.panel); +} + +COMMAND_DECL(toggle_line_wrap){ + ProfileMomentFunction(); + REQ_FILE_VIEW(view); + REQ_FILE(file, view); + + Relative_Scrolling scrolling = view_get_relative_scrolling(view); + if (view->unwrapped_lines){ + view->unwrapped_lines = 0; + file->settings.unwrapped_lines = 0; + view->target_x = 0; + view->cursor = + view_compute_cursor_from_pos(view, view->cursor.pos); + view->preferred_x = view->cursor.wrapped_x; + } + else{ + view->unwrapped_lines = 1; + file->settings.unwrapped_lines = 1; + view->cursor = + view_compute_cursor_from_pos(view, view->cursor.pos); + view->preferred_x = view->cursor.unwrapped_x; + } + view_set_relative_scrolling(view, scrolling); +} + +COMMAND_DECL(toggle_show_whitespace){ + ProfileMomentFunction(); + REQ_FILE_VIEW(view); + view->show_whitespace = !view->show_whitespace; +} + +COMMAND_DECL(toggle_tokens){ +#if BUFFER_EXPERIMENT_SCALPEL <= 0 + ProfileMomentFunction(); + REQ_FILE_VIEW(view); + REQ_FILE(file, view); + USE_MEM(mem); + + if (file->settings.tokens_exist){ + file_kill_tokens(system, &mem->general, file); + } + else{ + file_first_lex_parallel(system, &mem->general, file); + } +#endif +} + +internal void +case_change_range(System_Functions *system, + Mem_Options *mem, File_View *view, Editing_File *file, + u8 a, u8 z, u8 char_delta){ +#if BUFFER_EXPERIMENT_SCALPEL <= 0 + Range range = make_range(view->cursor.pos, view->mark); + 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; + + if (file->state.still_lexing) + system->cancel_job(BACKGROUND_THREADS, file->state.lex_job); + + file_update_history_before_edit(mem, file, step, 0, hist_normal); + + u8 *data = (u8*)file->state.buffer.data; + for (i32 i = range.start; i < range.end; ++i){ + if (data[i] >= a && data[i] <= z){ + data[i] += char_delta; + } + } + + if (file->state.token_stack.tokens) + file_relex_parallel(system, mem, file, range.start, range.end, 0); + } +#endif +} + +COMMAND_DECL(to_uppercase){ + ProfileMomentFunction(); + REQ_FILE_VIEW(view); + REQ_FILE(file, view); + USE_MEM(mem); + case_change_range(system, mem, view, file, 'a', 'z', (u8)('A' - 'a')); +} + +COMMAND_DECL(to_lowercase){ + ProfileMomentFunction(); + REQ_FILE_VIEW(view); + REQ_FILE(file, view); + USE_MEM(mem); + case_change_range(system, mem, view, file, 'A', 'Z', (u8)('a' - 'A')); +} + +COMMAND_DECL(clean_all_lines){ + ProfileMomentFunction(); + REQ_FILE_VIEW(view); + REQ_FILE(file, view); + USE_LAYOUT(layout); + USE_MEM(mem); + + view_clean_whitespace(system, mem, view, layout); +} + +COMMAND_DECL(eol_dosify){ + ProfileMomentFunction(); + REQ_FILE_VIEW(view); + REQ_FILE(file, view); + + file->settings.dos_write_mode = 1; + file->state.last_4ed_edit_time = system->time(); +} + +COMMAND_DECL(eol_nixify){ + ProfileMomentFunction(); + REQ_FILE_VIEW(view); + REQ_FILE(file, view); + + file->settings.dos_write_mode = 0; + file->state.last_4ed_edit_time = system->time(); +} + +COMMAND_DECL(auto_tab_range){ + ProfileMomentFunction(); + REQ_FILE_VIEW(view); + REQ_FILE(file, view); + USE_LAYOUT(layout); + USE_MEM(mem); + + int r_start = 0, r_end = 0; + int start_set = 0, end_set = 0; + int clear_blank_lines = 1; + + // TODO(allen): deduplicate + Command_Parameter *end = param_stack_end(&command->part); + Command_Parameter *param = param_stack_first(&command->part, end); + for (; param < end; param = param_next(param, end)){ + int p = dynamic_to_int(¶m->param.param); + switch (p){ + case par_range_start: + start_set = 1; + r_start = dynamic_to_int(¶m->param.value); + break; + + case par_range_end: + end_set = 1; + r_end = dynamic_to_int(¶m->param.value); + break; + + case par_clear_blank_lines: + clear_blank_lines = dynamic_to_bool(¶m->param.value); + break; + } + } + + if (file->state.token_stack.tokens && file->state.tokens_complete){ + Range range = make_range(view->cursor.pos, view->mark); + if (start_set) range.start = r_start; + if (end_set) range.end = r_end; + view_auto_tab_tokens(system, mem, view, layout, range.start, range.end, clear_blank_lines); + } +} + +COMMAND_DECL(auto_tab_line_at_cursor){ + ProfileMomentFunction(); + REQ_FILE_VIEW(view); + REQ_FILE(file, view); + USE_LAYOUT(layout); + USE_MEM(mem); + + int clear_blank_lines = 0; + + Command_Parameter *end = param_stack_end(&command->part); + Command_Parameter *param = param_stack_first(&command->part, end); + for (; param < end; param = param_next(param, end)){ + int p = dynamic_to_int(¶m->param.param); + switch (p){ + case par_clear_blank_lines: + clear_blank_lines = dynamic_to_bool(¶m->param.value); + break; + } + } + + if (file->state.token_stack.tokens && file->state.tokens_complete){ + i32 pos = view->cursor.pos; + view_auto_tab_tokens(system, mem, view, layout, pos, pos, clear_blank_lines); + } +} + +COMMAND_DECL(auto_tab_whole_file){ + ProfileMomentFunction(); + REQ_FILE_VIEW(view); + REQ_FILE(file, view); + USE_LAYOUT(layout); + USE_MEM(mem); + + if (file->state.token_stack.tokens && file->state.tokens_complete){ + view_auto_tab_tokens(system, mem, view, layout, 0, buffer_size(&file->state.buffer), 1); + } +} + +COMMAND_DECL(open_panel_vsplit){ + ProfileMomentFunction(); + USE_LAYOUT(layout); + USE_PANEL(panel); + USE_EXCHANGE(exchange); + USE_VARS(vars); + USE_STYLE(style); + + if (layout->panel_count < layout->panel_max_count){ + Split_Result split = layout_split_panel(layout, panel, 1); + + Panel *panel1 = panel; + Panel *panel2 = split.panel; + + panel2->screen_region = panel1->screen_region; + + panel2->full.x0 = split.divider->pos; + panel2->full.x1 = panel1->full.x1; + panel1->full.x1 = split.divider->pos; + + panel_fix_internal_area(panel1); + panel_fix_internal_area(panel2); + panel2->prev_inner = panel2->inner; + + layout->active_panel = (i32)(panel2 - layout->panels); + panel_make_empty(system, exchange, vars, style, panel2); + } +} + +COMMAND_DECL(open_panel_hsplit){ + ProfileMomentFunction(); + USE_LAYOUT(layout); + USE_PANEL(panel); + USE_EXCHANGE(exchange); + USE_VARS(vars); + USE_STYLE(style); + + if (layout->panel_count < layout->panel_max_count){ + Split_Result split = layout_split_panel(layout, panel, 0); + + Panel *panel1 = panel; + Panel *panel2 = split.panel; + + panel2->screen_region = panel1->screen_region; + + panel2->full.y0 = split.divider->pos; + panel2->full.y1 = panel1->full.y1; + panel1->full.y1 = split.divider->pos; + + panel_fix_internal_area(panel1); + panel_fix_internal_area(panel2); + panel2->prev_inner = panel2->inner; + + layout->active_panel = (i32)(panel2 - layout->panels); + panel_make_empty(system, exchange, vars, style, panel2); + } +} + +COMMAND_DECL(close_panel){ + ProfileMomentFunction(); + USE_LAYOUT(layout); + USE_PANEL(panel); + USE_VIEW(view); + USE_EXCHANGE(exchange); + + if (layout->panel_count > 1){ + if (view){ + live_set_free_view(system, exchange, command->live_set, view); + panel->view = 0; + } + + Divider_And_ID div = layout_get_divider(layout, panel->parent); + Assert(div.divider->child1 == -1 || div.divider->child2 == -1); + + i32 child; + if (div.divider->child1 == -1){ + child = div.divider->child2; + } + else{ + child = div.divider->child1; + } + + i32 parent = div.divider->parent; + i32 which_child = div.divider->which_child; + if (parent != -1){ + Divider_And_ID par = layout_get_divider(layout, parent); + if (which_child == -1){ + par.divider->child1 = child; + } + else{ + par.divider->child2 = child; + } + } + else{ + Assert(layout->root == div.id); + layout->root = child; + } + + if (child != -1){ + Divider_And_ID chi = layout_get_divider(layout, child); + chi.divider->parent = parent; + chi.divider->which_child = div.divider->which_child; + } + + layout_free_divider(layout, div.divider); + layout_free_panel(layout, panel); + + if (child == -1){ + panel = layout->panels; + layout->active_panel = -1; + for (i32 i = 0; i < layout->panel_count; ++i){ + if (panel->parent == div.id){ + panel->parent = parent; + panel->which_child = which_child; + layout->active_panel = i; + break; + } + ++panel; + } + Assert(layout->active_panel != -1); + } + else{ + layout->active_panel = layout->active_panel % layout->panel_count; + } + + layout_fix_all_panels(layout); + } +} + +COMMAND_DECL(move_left){ + ProfileMomentFunction(); + REQ_FILE_VIEW(view); + REQ_FILE(file, view); + + i32 pos = view->cursor.pos; + if (pos > 0) --pos; + view_cursor_move(view, pos); +} + +COMMAND_DECL(move_right){ + ProfileMomentFunction(); + REQ_FILE_VIEW(view); + REQ_FILE(file, view); + + i32 size = buffer_size(&file->state.buffer); + i32 pos = view->cursor.pos; + if (pos < size) ++pos; + view_cursor_move(view, pos); +} + +COMMAND_DECL(delete){ + ProfileMomentFunction(); + REQ_OPEN_FILE_VIEW(view); + REQ_FILE(file, view); + USE_LAYOUT(layout); + USE_MEM(mem); + + i32 size = buffer_size(&file->state.buffer); + i32 cursor_pos = view->cursor.pos; + if (0 < size && cursor_pos < size){ + i32 start, end; + start = cursor_pos; + end = cursor_pos+1; + + Assert(end - start > 0); + + i32 next_cursor_pos = start; + view_replace_range(system, mem, view, layout, start, end, 0, 0, next_cursor_pos); + view_cursor_move(view, next_cursor_pos); + } +} + +COMMAND_DECL(backspace){ + ProfileMomentFunction(); + REQ_OPEN_FILE_VIEW(view); + REQ_FILE(file, view); + USE_LAYOUT(layout); + USE_MEM(mem); + + i32 size = buffer_size(&file->state.buffer); + i32 cursor_pos = view->cursor.pos; + if (cursor_pos > 0 && cursor_pos <= size){ + i32 start, end; + end = cursor_pos; + start = cursor_pos-1; + + i32 shift = (end - start); + Assert(shift > 0); + + i32 next_cursor_pos = view->cursor.pos - shift; + view_replace_range(system, mem, view, layout, start, end, 0, 0, next_cursor_pos); + view_cursor_move(view, next_cursor_pos); + } +} + +COMMAND_DECL(move_up){ + ProfileMomentFunction(); + REQ_FILE_VIEW(view); + REQ_FILE(file, view); + USE_FONT_SET(font_set); + + f32 font_height = (f32)get_font_info(font_set, view->style->font_id)->height; + f32 cy = view_get_cursor_y(view)-font_height; + f32 px = view->preferred_x; + if (cy >= 0){ + view->cursor = view_compute_cursor_from_xy(view, px, cy); + file->state.cursor_pos = view->cursor.pos; + } +} + +COMMAND_DECL(move_down){ + ProfileMomentFunction(); + REQ_FILE_VIEW(view); + REQ_FILE(file, view); + USE_FONT_SET(font_set); + + f32 font_height = (f32)get_font_info(font_set, view->style->font_id)->height; + f32 cy = view_get_cursor_y(view)+font_height; + f32 px = view->preferred_x; + view->cursor = view_compute_cursor_from_xy(view, px, cy); + file->state.cursor_pos = view->cursor.pos; +} + +COMMAND_DECL(seek_end_of_line){ + ProfileMomentFunction(); + REQ_FILE_VIEW(view); + REQ_FILE(file, view); + + i32 pos = view_find_end_of_line(view, view->cursor.pos); + view_cursor_move(view, pos); +} + +COMMAND_DECL(seek_beginning_of_line){ + ProfileMomentFunction(); + REQ_FILE_VIEW(view); + REQ_FILE(file, view); + + i32 pos = view_find_beginning_of_line(view, view->cursor.pos); + view_cursor_move(view, pos); +} + +COMMAND_DECL(page_down){ + ProfileMomentFunction(); + REQ_FILE_VIEW(view); + + f32 height = view_compute_height(view); + f32 max_target_y = view_compute_max_target_y(view); + + view->target_y += height; + if (view->target_y > max_target_y) view->target_y = max_target_y; + + view->cursor = view_compute_cursor_from_xy( + view, 0, view->target_y + (height - view->font_height)*.5f); +} + +COMMAND_DECL(page_up){ + ProfileMomentFunction(); + REQ_FILE_VIEW(view); + + f32 height = view_compute_height(view); + + view->target_y -= height; + if (view->target_y < 0) view->target_y = 0; + + view->cursor = view_compute_cursor_from_xy( + view, 0, view->target_y + (height - view->font_height)*.5f); +} + +COMMAND_DECL(open_color_tweaker){ +#if 0 + ProfileMomentFunction(); + USE_VARS(vars); + USE_LIVE_SET(live_set); + USE_MEM(mem); + USE_PANEL(panel); + USE_EXCHANGE(exchange); + + { + View *new_view = live_set_alloc_view(live_set, mem); + view_replace_minor(system, exchange, new_view, panel, live_set); + + new_view->map = &vars->map_ui; + + Color_View *color_view = color_view_init(new_view, &vars->working_set); + color_view->hot_directory = &vars->hot_directory; + color_view->main_style = &vars->style; + color_view->styles = &vars->styles; + color_view->palette = vars->palette; + color_view->palette_size = vars->palette_size; + color_view->font_set = vars->font_set; + } +#endif + + ProfileMomentFunction(); + USE_FILE_VIEW(fview); + USE_VARS(vars); + USE_PANEL(panel); + USE_STYLE(style); + USE_EXCHANGE(exchange); + + if (!fview){ + fview = panel_make_empty(system, exchange, vars, style, panel); + } + + view_show_theme(fview, &vars->map_ui); +} + +COMMAND_DECL(open_config){ + ProfileMomentFunction(); + USE_FILE_VIEW(fview); + USE_VARS(vars); + USE_PANEL(panel); + USE_STYLE(style); + USE_EXCHANGE(exchange); + + if (!fview){ + fview = panel_make_empty(system, exchange, vars, style, panel); + } + + view_show_config(fview, &vars->map_ui); +} + +COMMAND_DECL(open_menu){ + ProfileMomentFunction(); + USE_FILE_VIEW(fview); + USE_VARS(vars); + USE_PANEL(panel); + USE_STYLE(style); + USE_EXCHANGE(exchange); + + if (!fview){ + fview = panel_make_empty(system, exchange, vars, style, panel); + } + + view_show_menu(fview, &vars->map_ui); +} + +COMMAND_DECL(close_minor_view){ + ProfileMomentFunction(); + REQ_VIEW(view); + USE_FILE_VIEW(fview); + USE_VARS(vars); + + Command_Map *map = &vars->map_top; + if (fview->file){ + map = app_get_map(vars, fview->file->settings.base_map_id); + } + view_show_file(fview, map); +} + +COMMAND_DECL(cursor_mark_swap){ + ProfileMomentFunction(); + REQ_FILE_VIEW(view); + + i32 pos = view->cursor.pos; + view_cursor_move(view, view->mark); + view->mark = pos; +} + +COMMAND_DECL(user_callback){ + ProfileMomentFunction(); + if (binding.custom) binding.custom(&app_links); +} + +COMMAND_DECL(set_settings){ + ProfileMomentFunction(); + REQ_FILE_VIEW(view); + REQ_FILE_LOADING(file, view); + USE_VARS(vars); + USE_MEM(mem); + + Command_Parameter *end = param_stack_end(&command->part); + Command_Parameter *param = param_stack_first(&command->part, end); + for (; param < end; param = param_next(param, end)){ + int p = dynamic_to_int(¶m->param.param); + switch (p){ + case par_lex_as_cpp_file: + { +#if BUFFER_EXPERIMENT_SCALPEL <= 0 + int v = dynamic_to_bool(¶m->param.value); + if (file->settings.tokens_exist){ + if (!v) file_kill_tokens(system, &mem->general, file); + } + else{ + if (v) file_first_lex_parallel(system, &mem->general, file); + } +#endif + }break; + + case par_wrap_lines: + { + int v = dynamic_to_bool(¶m->param.value); + if (view->unwrapped_lines){ + if (v){ + view->unwrapped_lines = 0; + file->settings.unwrapped_lines = 0; + + if (!file->state.is_loading){ + Relative_Scrolling scrolling = view_get_relative_scrolling(view); + view->target_x = 0; + view->cursor = + view_compute_cursor_from_pos(view, view->cursor.pos); + view_set_relative_scrolling(view, scrolling); + } + } + } + else{ + if (!v){ + view->unwrapped_lines = 1; + file->settings.unwrapped_lines = 1; + + if (!file->state.is_loading){ + Relative_Scrolling scrolling = view_get_relative_scrolling(view); + view->cursor = + view_compute_cursor_from_pos(view, view->cursor.pos); + view_set_relative_scrolling(view, scrolling); + } + } + } + }break; + + case par_key_mapid: + { + int v = dynamic_to_int(¶m->param.value); + if (v == mapid_global) file->settings.base_map_id = mapid_global; + else if (v == mapid_file) file->settings.base_map_id = mapid_file; + else if (v < mapid_global){ + int index = app_get_map_index(vars, v); + if (index < vars->user_map_count) file->settings.base_map_id = v; + else file->settings.base_map_id = mapid_file; + } + }break; + } + } +} + +#define CLI_OverlapWithConflict (1<<0) +#define CLI_AlwaysBindToView (2<<0) + +internal void +build(System_Functions *system, Mem_Options *mem, + App_Vars *vars, Working_Set *working_set, + Font_Set *font_set, Style *style, + Live_Views *live_set, Exchange *exchange, + Panel *panel, Command_Data *command, + String hot_directory, + char *buffer_name, i32 buffer_name_len, + char *path, i32 path_len, + char *script, i32 script_len, + u32 flags){ + if (buffer_name == 0 || path == 0 || script == 0){ + return; + } + + if (vars->cli_processes.count < vars->cli_processes.max){ + Editing_Layout *layout = &vars->layout; + Editing_File *file = working_set_contains(working_set, make_string_slowly(buffer_name)); + i32 index; + b32 bind_to_new_view = 1; + + if (!file){ + Get_File_Result get_file = working_set_get_available_file(working_set); + file = get_file.file; + index = get_file.index; + } + else{ + i32 proc_count = vars->cli_processes.count; + for (i32 i = 0; i < proc_count; ++i){ + if (vars->cli_processes.procs[i].out_file == file){ + if (flags & CLI_OverlapWithConflict) + vars->cli_processes.procs[i].out_file = 0; + else file = 0; + break; + } + } + index = (i32)(file - vars->working_set.files); + if (file){ + if (!(flags & CLI_AlwaysBindToView)){ + Panel *panel = layout->panels; + for (i32 i = 0; i < layout->panel_count; ++i, ++panel){ + File_View *fview = view_to_file_view(panel->view); + if (fview && fview->file == file){ + bind_to_new_view = 0; + break; + } + } + } + } + } + + if (file){ + file_create_super_locked(system, mem, working_set, file, buffer_name, font_set, style->font_id); + file->settings.unimportant = 1; + table_add(&working_set->table, file->name.source_path, index); + + if (bind_to_new_view){ + view_file_in_panel(command, panel, file); + } + + i32 i = vars->cli_processes.count++; + CLI_Process *proc = vars->cli_processes.procs + i; + if (!system->cli_call(path, script, &proc->cli)){ + --vars->cli_processes.count; + } + proc->out_file = file; + } + else{ + // TODO(allen): feedback message - no available file + } + } + else{ + // TODO(allen): feedback message - no available process slot + } +} + +COMMAND_DECL(command_line){ + ProfileMomentFunction(); + USE_VARS(vars); + USE_MEM(mem); + USE_WORKING_SET(working_set); + USE_STYLE(style); + USE_LIVE_SET(live_set); + USE_PANEL(panel); + USE_EXCHANGE(exchange); + USE_FONT_SET(font_set); + + char *buffer_name = 0; + char *path = 0; + char *script = 0; + + int buffer_name_len = 0; + int path_len = 0; + int script_len = 0; + u32 flags = CLI_OverlapWithConflict; + + Command_Parameter *end = param_stack_end(&command->part); + Command_Parameter *param = param_stack_first(&command->part, end); + for (; param < end; param = param_next(param, end)){ + int p = dynamic_to_int(¶m->param.param); + switch (p){ + case par_name: + { + if (buffer_name == 0){ + char *new_buffer_name = dynamic_to_string(¶m->param.value, &buffer_name_len); + if (new_buffer_name){ + buffer_name = new_buffer_name; + } + } + }break; + + case par_cli_path: + { + if (path == 0){ + char *new_cli_path = dynamic_to_string(¶m->param.value, &path_len); + if (new_cli_path){ + path = new_cli_path; + } + } + }break; + + case par_cli_command: + { + if (script == 0){ + char *new_command = dynamic_to_string(¶m->param.value, &script_len); + if (new_command){ + script = new_command; + } + } + }break; + + case par_cli_overlap_with_conflict: + { + if (dynamic_to_int(¶m->param.value)) + flags |= CLI_OverlapWithConflict; + else + flags &= (~CLI_OverlapWithConflict); + }break; + + case par_cli_always_bind_to_view: + { + if (dynamic_to_int(¶m->param.value)) + flags |= CLI_OverlapWithConflict; + else + flags &= (~CLI_OverlapWithConflict); + }break; + } + } + + build(system, mem, vars, working_set, + font_set, style, live_set, exchange, + panel, command, + vars->hot_directory.string, + buffer_name, buffer_name_len, + path, path_len, + script, script_len, + flags); +} + +internal void +update_command_data(App_Vars *vars, Command_Data *cmd){ + cmd->panel = cmd->layout->panels + cmd->layout->active_panel; + cmd->view = cmd->panel->view; + cmd->style = &vars->style; +} + +globalvar Command_Function command_table[cmdid_count]; + +internal void +fill_buffer_summary(Buffer_Summary *buffer, Editing_File *file, Working_Set *working_set){ + buffer->exists = 1; + buffer->ready = file_is_ready(file); + buffer->is_lexed = file->settings.tokens_exist; + buffer->buffer_id = (int)(file - working_set->files); + buffer->size = file->state.buffer.size; + buffer->buffer_cursor_pos = file->state.cursor_pos; + + buffer->file_name_len = file->name.source_path.size; + buffer->buffer_name_len = file->name.live_name.size; + buffer->file_name = file->name.source_path.str; + buffer->buffer_name = file->name.live_name.str; + + buffer->map_id = file->settings.base_map_id; +} + +internal void +fill_view_summary(File_View_Summary *view, File_View *file_view, Live_Views *live_set, Working_Set *working_set){ + view->exists = 1; + view->view_id = (int)((char*)file_view - (char*)live_set->views) / live_set->stride; + if (file_view->file){ + view->buffer_id = (int)(file_view->file - working_set->files); + view->mark = view_compute_cursor_from_pos(file_view, file_view->mark); + view->cursor = file_view->cursor; + view->preferred_x = file_view->preferred_x; + view->line_height = file_view->font_height; + view->unwrapped_lines = file_view->unwrapped_lines; + } +} + +extern "C"{ + EXECUTE_COMMAND_SIG(external_exec_command_keep_stack){ + Command_Data *cmd = (Command_Data*)context->cmd_context; + Command_Function function = command_table[command_id]; + Command_Binding binding; + binding.function = function; + if (function) function(cmd->system, cmd, binding); + + update_command_data(cmd->vars, cmd); + } + + PUSH_PARAMETER_SIG(external_push_parameter){ + Command_Data *cmd = (Command_Data*)context->cmd_context; + Partition *part = &cmd->part; + Command_Parameter *cmd_param = push_struct(part, Command_Parameter); + cmd_param->type = 0; + cmd_param->param.param = param; + cmd_param->param.value = value; + } + + PUSH_MEMORY_SIG(external_push_memory){ + Command_Data *cmd = (Command_Data*)context->cmd_context; + Partition *part = &cmd->part; + Command_Parameter *base = push_struct(part, Command_Parameter); + char *result = push_array(part, char, len); + int full_len = len + sizeof(Command_Parameter) - 1; + full_len -= (full_len % sizeof(Command_Parameter)); + part->pos += full_len - len; + base->type = 1; + base->inline_string.str = result; + base->inline_string.len = len; + return(result); + } + + CLEAR_PARAMETERS_SIG(external_clear_parameters){ + Command_Data *cmd = (Command_Data*)context->cmd_context; + cmd->part.pos = 0; + } + + DIRECTORY_GET_HOT_SIG(external_directory_get_hot){ + Command_Data *cmd = (Command_Data*)context->cmd_context; + Hot_Directory *hot = &cmd->vars->hot_directory; + i32 copy_max = capacity - 1; + hot_directory_clean_end(hot); + if (copy_max > hot->string.size) + copy_max = hot->string.size; + memcpy(out, hot->string.str, copy_max); + out[copy_max] = 0; + return(hot->string.size); + } + + GET_FILE_LIST_SIG(external_get_file_list){ + Command_Data *cmd = (Command_Data*)context->cmd_context; + System_Functions *system = cmd->system; + File_List result = {}; + system->set_file_list(&result, make_string(dir, len)); + return(result); + } + + FREE_FILE_LIST_SIG(external_free_file_list){ + Command_Data *cmd = (Command_Data*)context->cmd_context; + System_Functions *system = cmd->system; + system->set_file_list(&list, make_string(0, 0)); + } + + GET_BUFFER_MAX_INDEX_SIG(external_get_buffer_max_index){ + Command_Data *cmd = (Command_Data*)context->cmd_context; + Working_Set *working_set = cmd->working_set; + int max = working_set->file_index_count; + return(max); + } + + GET_BUFFER_SIG(external_get_buffer){ + Command_Data *cmd = (Command_Data*)context->cmd_context; + Editing_File *file; + Working_Set *working_set = cmd->working_set; + int max = working_set->file_index_count; + Buffer_Summary buffer = {}; + + if (index >= 0 && index < max){ + file = working_set->files + index; + if (!file->state.is_dummy){ + fill_buffer_summary(&buffer, file, working_set); + } + } + + return(buffer); + } + + GET_ACTIVE_BUFFER_SIG(external_get_active_buffer){ + Command_Data *cmd = (Command_Data*)context->cmd_context; + File_View *view; + Editing_File *file; + Working_Set *working_set; + Buffer_Summary buffer = {}; + + view = view_to_file_view(cmd->view); + if (view){ + file = view->file; + working_set = cmd->working_set; + + if (file && !file->state.is_dummy){ + fill_buffer_summary(&buffer, file, working_set); + } + } + + return(buffer); + } + + GET_BUFFER_BY_NAME(external_get_buffer_by_name){ + Command_Data *cmd = (Command_Data*)context->cmd_context; + Editing_File *file; + Working_Set *working_set; + i32 index; + Buffer_Summary buffer = {}; + + working_set = cmd->working_set; + if (table_find(&working_set->table, make_string(filename, len), &index)){ + file = working_set->files + index; + if (!file->state.is_dummy && file_is_ready(file)){ + fill_buffer_summary(&buffer, file, working_set); + } + } + + return(buffer); + } + + REFRESH_BUFFER_SIG(external_refresh_buffer){ + int result; + *buffer = external_get_buffer(context, buffer->buffer_id); + result = buffer->exists; + return(result); + } + + BUFFER_SEEK_DELIMITER_SIG(external_buffer_seek_delimiter){ + Command_Data *cmd = (Command_Data*)context->cmd_context; + Editing_File *file; + Working_Set *working_set; + int result = 0; + int size; + + if (buffer->exists){ + working_set = cmd->working_set; + file = working_set->files + buffer->buffer_id; + if (!file->state.is_dummy && file_is_ready(file)){ + size = buffer_size(&file->state.buffer); + result = 1; + + if (start < 0 && !seek_forward) *out = start; + else if (start >= size && seek_forward) *out = start; + else{ + if (seek_forward){ + *out = buffer_seek_delimiter(&file->state.buffer, start, delim); + } + else{ + *out = buffer_reverse_seek_delimiter(&file->state.buffer, start, delim); + } + } + + fill_buffer_summary(buffer, file, working_set); + } + } + + return(result); + } + + BUFFER_SEEK_STRING_SIG(external_buffer_seek_string){ + Command_Data *cmd = (Command_Data*)context->cmd_context; + Editing_File *file; + Working_Set *working_set; + Temp_Memory temp; + Partition *part; + char *spare; + int result = 0; + int size; + + if (buffer->exists){ + working_set = cmd->working_set; + file = working_set->files + buffer->buffer_id; + if (!file->state.is_dummy && file_is_ready(file)){ + size = buffer_size(&file->state.buffer); + + if (start < 0 && !seek_forward) *out = start; + else if (start >= size && seek_forward) *out = start; + else{ + part = &cmd->mem->part; + temp = begin_temp_memory(part); + spare = push_array(part, char, len); + result = 1; + if (seek_forward){ + *out = buffer_find_string(&file->state.buffer, start, size, str, len, spare); + } + else{ + *out = buffer_rfind_string(&file->state.buffer, start, str, len, spare); + } + end_temp_memory(temp); + } + fill_buffer_summary(buffer, file, working_set); + } + } + + return(result); + } + + BUFFER_READ_RANGE_SIG(external_buffer_read_range){ + Command_Data *cmd = (Command_Data*)context->cmd_context; + Editing_File *file; + Working_Set *working_set; + int result = 0; + int size; + + if (buffer->exists){ + working_set = cmd->working_set; + file = working_set->files + buffer->buffer_id; + if (!file->state.is_dummy && file_is_ready(file)){ + size = buffer_size(&file->state.buffer); + if (0 <= start && start <= end && end <= size){ + result = 1; + buffer_stringify(&file->state.buffer, start, end, out); + } + fill_buffer_summary(buffer, file, working_set); + } + } + + return(result); + } + + BUFFER_REPLACE_RANGE_SIG(external_buffer_replace_range){ + Command_Data *cmd = (Command_Data*)context->cmd_context; + Editing_File *file; + Working_Set *working_set; + + System_Functions *system; + Mem_Options *mem; + Editing_Layout *layout; + + int result = 0; + int size; + int next_cursor, pos; + + if (buffer->exists){ + working_set = cmd->working_set; + file = working_set->files + buffer->buffer_id; + if (!file->state.is_dummy && file_is_ready(file)){ + size = buffer_size(&file->state.buffer); + if (0 <= start && start <= end && end <= size){ + result = 1; + + system = cmd->system; + mem = cmd->mem; + layout = cmd->layout; + + pos = file->state.cursor_pos; + if (pos < start) next_cursor = pos; + else if (pos < end) next_cursor = start + len; + else next_cursor = pos + end - start + len; + + file_replace_range(system, mem, file, layout, + start, end, str, len, next_cursor); + } + fill_buffer_summary(buffer, file, working_set); + } + } + + return(result); + } + + GET_VIEW_MAX_INDEX_SIG(external_get_view_max_index){ + Command_Data *cmd = (Command_Data*)context->cmd_context; + Live_Views *live_set = cmd->live_set; + int max = live_set->max; + return(max); + } + + GET_FILE_VIEW_SIG(external_get_file_view){ + Command_Data *cmd = (Command_Data*)context->cmd_context; + Live_Views *live_set = cmd->live_set; + int max = live_set->max; + View *vptr; + File_View *file_view; + File_View_Summary view = {}; + + if (index >= 0 && index < max){ + vptr = (View*)((char*)live_set->views + live_set->stride*index); + file_view = view_to_file_view(vptr); + if (file_view){ + fill_view_summary(&view, file_view, cmd->live_set, cmd->working_set); + } + } + + return(view); + } + + GET_ACTIVE_FILE_VIEW_SIG(external_get_active_file_view){ + Command_Data *cmd = (Command_Data*)context->cmd_context; + File_View_Summary view = {}; + File_View *file_view; + + file_view = view_to_file_view(cmd->view); + if (file_view){ + fill_view_summary(&view, file_view, cmd->live_set, cmd->working_set); + } + + return(view); + } + + REFRESH_FILE_VIEW_SIG(external_refresh_file_view){ + int result; + *view = external_get_file_view(context, view->view_id); + result = view->exists; + return(result); + } + + VIEW_SET_CURSOR_SIG(external_view_set_cursor){ + Command_Data *cmd = (Command_Data*)context->cmd_context; + Live_Views *live_set; + View *vptr; + File_View *file_view; + int result = 0; + + if (view->exists){ + live_set = cmd->live_set; + vptr = (View*)((char*)live_set->views + live_set->stride * view->view_id); + file_view = view_to_file_view(vptr); + if (file_view){ + result = 1; + file_view->cursor = view_compute_cursor(file_view, seek); + if (set_preferred_x){ + file_view->preferred_x = view_get_cursor_x(file_view); + } + fill_view_summary(view, file_view, cmd->live_set, cmd->working_set); + } + } + + return(result); + } + + VIEW_SET_MARK_SIG(external_view_set_mark){ + Command_Data *cmd = (Command_Data*)context->cmd_context; + Live_Views *live_set; + View *vptr; + File_View *file_view; + Full_Cursor cursor; + int result = 0; + + if (view->exists){ + live_set = cmd->live_set; + vptr = (View*)((char*)live_set->views + live_set->stride * view->view_id); + file_view = view_to_file_view(vptr); + if (file_view){ + result = 1; + if (seek.type != buffer_seek_pos){ + cursor = view_compute_cursor(file_view, seek); + file_view->mark = cursor.pos; + } + else{ + file_view->mark = seek.pos; + } + fill_view_summary(view, file_view, cmd->live_set, cmd->working_set); + } + } + + return(result); + } + + VIEW_SET_HIGHLIGHT_SIG(external_view_set_highlight){ + Command_Data *cmd = (Command_Data*)context->cmd_context; + Live_Views *live_set; + View *vptr; + File_View *file_view; + int result = 0; + + if (view->exists){ + live_set = cmd->live_set; + vptr = (View*)((char*)live_set->views + live_set->stride * view->view_id); + file_view = view_to_file_view(vptr); + if (file_view){ + result = 1; + if (turn_on){ + view_set_temp_highlight(file_view, start, end); + } + else{ + file_view->show_temp_highlight = 0; + } + fill_view_summary(view, file_view, cmd->live_set, cmd->working_set); + } + } + + return(result); + } + + VIEW_SET_BUFFER_SIG(external_view_set_buffer){ + Command_Data *cmd = (Command_Data*)context->cmd_context; + Live_Views *live_set; + View *vptr; + File_View *file_view; + Editing_File *file; + Working_Set *working_set; + int max, result = 0; + + if (view->exists){ + live_set = cmd->live_set; + vptr = (View*)((char*)live_set->views + live_set->stride * view->view_id); + file_view = view_to_file_view(vptr); + if (file_view){ + working_set = cmd->working_set; + max = working_set->file_index_count; + if (buffer_id >= 0 && buffer_id < max){ + file = working_set->files + buffer_id; + if (!file->state.is_dummy){ + view_set_file(file_view, file, cmd->vars->font_set, cmd->style, + cmd->system, cmd->vars->hooks[hook_open_file], &app_links); + } + } + + fill_view_summary(view, file_view, cmd->live_set, cmd->working_set); + } + } + + return(result); + } + + GET_USER_INPUT_SIG(external_get_user_input){ + Command_Data *cmd = (Command_Data*)context->cmd_context; + System_Functions *system = cmd->system; + Coroutine *coroutine = cmd->current_coroutine; + User_Input result; + + Assert(coroutine); + *((u32*)coroutine->out+0) = get_type; + *((u32*)coroutine->out+1) = abort_type; + system->yield_coroutine(coroutine); + result = *(User_Input*)coroutine->in; + + return(result); + } + + START_QUERY_BAR_SIG(external_start_query_bar){ + Command_Data *cmd = (Command_Data*)context->cmd_context; + Query_Slot *slot = 0; + View *vptr; + File_View *file_view; + + vptr = cmd->view; + file_view = view_to_file_view(vptr); + + if (file_view){ + slot = alloc_query_slot(&file_view->query_set); + slot->query_bar = bar; + } + + return(slot != 0); + } + + END_QUERY_BAR_SIG(external_end_query_bar){ + Command_Data *cmd = (Command_Data*)context->cmd_context; + View *vptr; + File_View *file_view; + + vptr = cmd->view; + file_view = view_to_file_view(vptr); + + if (file_view){ + free_query_slot(&file_view->query_set, bar); + } + } +} + +struct Command_In{ + Command_Data *cmd; + Command_Binding bind; +}; + +internal void +command_caller(Coroutine *coroutine){ + Command_In *cmd_in = (Command_In*)coroutine->in; + Command_Data *cmd = cmd_in->cmd; + View *view = cmd->view; + // TODO(allen): this isn't really super awesome, could have issues if + // the file view get's change out under us. + File_View *fview = view_to_file_view(view); + if (fview) fview->next_mode = {}; + cmd_in->bind.function(cmd->system, cmd, cmd_in->bind); + fview = view_to_file_view(view); + if (fview) fview->mode = fview->next_mode; +} + +internal void +app_links_init(System_Functions *system, void *data, int size){ + app_links.memory = data; + app_links.memory_size = size; + + app_links.exec_command_keep_stack = external_exec_command_keep_stack; + app_links.push_parameter = external_push_parameter; + app_links.push_memory = external_push_memory; + app_links.clear_parameters = external_clear_parameters; + + app_links.directory_get_hot = external_directory_get_hot; + app_links.file_exists = system->file_exists; + app_links.directory_cd = system->directory_cd; + app_links.get_file_list = external_get_file_list; + app_links.free_file_list = external_free_file_list; + + app_links.get_buffer_max_index = external_get_buffer_max_index; + app_links.get_buffer = external_get_buffer; + app_links.get_active_buffer = external_get_active_buffer; + app_links.get_buffer_by_name = external_get_buffer_by_name; + + app_links.refresh_buffer = external_refresh_buffer; + app_links.buffer_seek_delimiter = external_buffer_seek_delimiter; + app_links.buffer_seek_string = external_buffer_seek_string; + app_links.buffer_read_range = external_buffer_read_range; + app_links.buffer_replace_range = external_buffer_replace_range; + + app_links.get_view_max_index = external_get_view_max_index; + app_links.get_file_view = external_get_file_view; + app_links.get_active_file_view = external_get_active_file_view; + + app_links.refresh_file_view = external_refresh_file_view; + app_links.view_set_cursor = external_view_set_cursor; + app_links.view_set_mark = external_view_set_mark; + app_links.view_set_highlight = external_view_set_highlight; + app_links.view_set_buffer = external_view_set_buffer; + + app_links.get_user_input = external_get_user_input; + + app_links.start_query_bar = external_start_query_bar; + app_links.end_query_bar = external_end_query_bar; +} + +internal void +setup_ui_commands(Command_Map *commands, Partition *part, Command_Map *parent){ + map_init(commands, part, 32, parent); + + commands->vanilla_keyboard_default.function = command_null; + + // 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; + u8 mdfr_array[] = {MDFR_NONE, MDFR_SHIFT, MDFR_CTRL, MDFR_SHIFT | MDFR_CTRL}; + for (i32 i = 0; i < 4; ++i){ + 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); + map_add(commands, key_esc, mdfr, command_close_minor_view); + } +} + +internal void +setup_file_commands(Command_Map *commands, Partition *part, Command_Map *parent){ + map_init(commands, part, 10, parent); +} + +internal void +setup_top_commands(Command_Map *commands, Partition *part, Command_Map *parent){ + map_init(commands, part, 5, parent); +} + +internal void +setup_command_table(){ +#define SET(n) command_table[cmdid_##n] = command_##n + + SET(null); + SET(write_character); + SET(seek_whitespace_right); + SET(seek_whitespace_left); + SET(seek_whitespace_up); + SET(seek_whitespace_down); + SET(seek_token_left); + SET(seek_token_right); + SET(seek_white_or_token_right); + SET(seek_white_or_token_left); + SET(seek_alphanumeric_right); + SET(seek_alphanumeric_left); + SET(seek_alphanumeric_or_camel_right); + SET(seek_alphanumeric_or_camel_left); + SET(word_complete); + SET(set_mark); + SET(copy); + SET(cut); + SET(paste); + SET(paste_next); + SET(delete_range); + SET(timeline_scrub); + SET(undo); + SET(redo); + SET(history_backward); + SET(history_forward); + SET(interactive_new); + SET(interactive_open); + SET(reopen); + SET(save); + SET(interactive_save_as); + SET(change_active_panel); + SET(interactive_switch_buffer); + SET(interactive_kill_buffer); + SET(kill_buffer); + SET(toggle_line_wrap); + SET(to_uppercase); + SET(to_lowercase); + SET(toggle_show_whitespace); + SET(clean_all_lines); + SET(eol_dosify); + SET(eol_nixify); + SET(auto_tab_range); + SET(auto_tab_line_at_cursor); + SET(auto_tab_whole_file); + SET(open_panel_vsplit); + SET(open_panel_hsplit); + SET(close_panel); + SET(move_left); + SET(move_right); + SET(delete); + SET(backspace); + SET(move_up); + SET(move_down); + SET(seek_end_of_line); + SET(seek_beginning_of_line); + SET(page_up); + SET(page_down); + SET(open_color_tweaker); + SET(close_minor_view); + SET(cursor_mark_swap); + SET(open_menu); + SET(set_settings); + SET(command_line); + +#undef SET +} + +// App Functions + +internal void +app_hardcode_styles(App_Vars *vars){ + Interactive_Style file_info_style; + Style *styles, *style; + styles = vars->styles.styles; + style = styles; + + i16 fonts = 1; + + ///////////////// + style_set_name(style, make_lit_string("4coder")); + style->font_id = fonts + 0; + + style->main.back_color = 0xFF0C0C0C; + style->main.margin_color = 0xFF181818; + style->main.margin_hover_color = 0xFF252525; + style->main.margin_active_color = 0xFF323232; + 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; + + 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; + file_info_style.pop1_color = 0xFF4444AA; + file_info_style.pop2_color = 0xFFFF0000; + style->main.file_info_style = file_info_style; + style->font_changed = 1; + ++style; + + ///////////////// + *style = *(style-1); + style_set_name(style, make_lit_string("4coder-mono")); + style->font_id = fonts + 1; + ++style; + + ///////////////// + style_set_name(style, make_lit_string("Handmade Hero")); + style->font_id = fonts + 1; + + style->main.back_color = 0xFF161616; + style->main.margin_color = 0xFF262626; + style->main.margin_hover_color = 0xFF333333; + style->main.margin_active_color = 0xFF404040; + style->main.cursor_color = 0xFF40FF40; + style->main.at_cursor_color = style->main.back_color; + style->main.mark_color = 0xFF808080; + style->main.highlight_color = 0xFF703419; + style->main.at_highlight_color = 0xFFCDAA7D; + style->main.default_color = 0xFFCDAA7D; + style->main.comment_color = 0xFF7F7F7F; + style->main.keyword_color = 0xFFCD950C; + style->main.str_constant_color = 0xFF6B8E23; + 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; + + style->main.paste_color = 0xFFFFBB00; + style->main.undo_color = 0xFFFF00BB; + style->main.undo_color = 0xFF80005D; + + style->main.highlight_junk_color = 0xFF3A0000; + style->main.highlight_white_color = 0xFF003A3A; + + file_info_style.bar_color = 0xFFCACACA; + file_info_style.bar_active_color = 0xFFA8A8A8; + file_info_style.base_color = 0xFF000000; + file_info_style.pop1_color = 0xFF03CF0C; + file_info_style.pop2_color = 0xFFFF0000; + style->main.file_info_style = file_info_style; + style->font_changed = 1; + ++style; + + ///////////////// + style_set_name(style, make_lit_string("Twilight")); + style->font_id = fonts + 2; + + style->main.back_color = 0xFF090D12; + style->main.margin_color = 0xFF1A2634; + style->main.margin_hover_color = 0xFF2D415B; + style->main.margin_active_color = 0xFF405D82; + style->main.cursor_color = 0xFFEEE800; + style->main.at_cursor_color = style->main.back_color; + style->main.mark_color = 0xFF8BA8CC; + style->main.highlight_color = 0xFF037A7B; + style->main.at_highlight_color = 0xFFFEB56C; + style->main.default_color = 0xFFB7C19E; + style->main.comment_color = 0xFF20ECF0; + style->main.keyword_color = 0xFFD86909; + style->main.str_constant_color = 0xFFC4EA5D; + 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; + + style->main.paste_color = 0xFFDDEE00; + style->main.undo_color = 0xFF00DDEE; + + style->main.highlight_junk_color = 0xff3a0000; + style->main.highlight_white_color = 0xFF151F2A; + + file_info_style.bar_color = 0xFF315E68; + file_info_style.bar_active_color = 0xFF0F3C46; + file_info_style.base_color = 0xFF000000; + file_info_style.pop1_color = 0xFF1BFF0C; + file_info_style.pop2_color = 0xFFFF200D; + style->main.file_info_style = file_info_style; + style->font_changed = 1; + ++style; + + ///////////////// + style_set_name(style, make_lit_string("Wolverine")); + style->font_id = fonts + 3; + + style->main.back_color = 0xFF070711; + style->main.margin_color = 0xFF111168; + style->main.margin_hover_color = 0xFF191996; + style->main.margin_active_color = 0xFF2121C3; + style->main.cursor_color = 0xFF7082F9; + style->main.at_cursor_color = 0xFF000014; + style->main.mark_color = 0xFF4b5028; + style->main.highlight_color = 0xFFDDEE00; + style->main.at_highlight_color = 0xFF000019; + style->main.default_color = 0xFF8C9740; + style->main.comment_color = 0xFF3A8B29; + style->main.keyword_color = 0xFFD6B109; + style->main.str_constant_color = 0xFFAF5FA7; + 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; + + style->main.paste_color = 0xFF900090; + style->main.undo_color = 0xFF606090; + + style->main.highlight_junk_color = 0xff3a0000; + style->main.highlight_white_color = 0xff003a3a; + + file_info_style.bar_color = 0xFF7082F9; + file_info_style.bar_active_color = 0xFF4E60D7; + file_info_style.base_color = 0xFF000000; + file_info_style.pop1_color = 0xFFFAFA15; + file_info_style.pop2_color = 0xFFD20000; + style->main.file_info_style = file_info_style; + style->font_changed = 1; + ++style; + + ///////////////// + style_set_name(style, make_lit_string("stb")); + style->font_id = fonts + 4; + + style->main.back_color = 0xFFD6D6D6; + style->main.margin_color = 0xFF9E9E9E; + style->main.margin_hover_color = 0xFF7E7E7E; + style->main.margin_active_color = 0xFF5C5C5C; + style->main.cursor_color = 0xFF000000; + style->main.at_cursor_color = 0xFFD6D6D6; + style->main.mark_color = 0xFF525252; + style->main.highlight_color = 0xFF0044FF; + style->main.at_highlight_color = 0xFFD6D6D6; + style->main.default_color = 0xFF000000; + style->main.comment_color = 0xFF000000; + style->main.keyword_color = 0xFF000000; + style->main.str_constant_color = 0xFF000000; + 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 = 0xFF9A0000; + + style->main.paste_color = 0xFF00B8B8; + style->main.undo_color = 0xFFB800B8; + + style->main.highlight_junk_color = 0xFFFF7878; + style->main.highlight_white_color = 0xFFBCBCBC; + + file_info_style.bar_color = 0xFF606060; + file_info_style.bar_active_color = 0xFF3E3E3E; + file_info_style.base_color = 0xFF000000; + file_info_style.pop1_color = 0xFF1111DC; + file_info_style.pop2_color = 0xFFE80505; + style->main.file_info_style = file_info_style; + style->font_changed = 1; + ++style; + + vars->styles.count = (i32)(style - styles); + vars->styles.max = ArrayCount(vars->styles.styles); + style_copy(&vars->style, vars->styles.styles); + vars->style.font_changed = 0; +} + +char *_4coder_get_extension(const char *filename, int len, int *extension_len){ + char *c = (char*)(filename + len - 1); + char *end = c; + while (*c != '.' && c > filename) --c; + *extension_len = (int)(end - c); + return c+1; +} + +bool _4coder_str_match(const char *a, int len_a, const char *b, int len_b){ + bool result = 0; + if (len_a == len_b){ + char *end = (char*)(a + len_a); + while (a < end && *a == *b){ + ++a; ++b; + } + if (a == end) result = 1; + } + return result; +} + +enum Command_Line_Action{ + CLAct_Nothing, + CLAct_Ignore, + CLAct_UserFile, + CLAct_CustomDLL, + CLAct_InitialFilePosition, + CLAct_WindowSize, + CLAct_WindowMaximize, + CLAct_WindowPosition, + CLAct_Count +}; + +void +init_command_line_settings(App_Settings *settings, Plat_Settings *plat_settings, + Command_Line_Parameters clparams){ + char *arg; + Command_Line_Action action = CLAct_Nothing; + i32 i,index; + b32 strict = 0; + + settings->init_files_max = ArrayCount(settings->init_files); + for (i = 1; i <= clparams.argc; ++i){ + if (i == clparams.argc) arg = ""; + else arg = clparams.argv[i]; + switch (action){ + case CLAct_Nothing: + { + if (arg[0] == '-'){ + action = CLAct_Ignore; + switch (arg[1]){ + case 'u': action = CLAct_UserFile; strict = 0; break; + case 'U': action = CLAct_UserFile; strict = 1; break; + + case 'd': action = CLAct_CustomDLL; strict = 0; break; + case 'D': action = CLAct_CustomDLL; strict = 1; break; + + case 'i': action = CLAct_InitialFilePosition; break; + + case 'w': action = CLAct_WindowSize; break; + case 'W': action = CLAct_WindowMaximize; break; + case 'p': action = CLAct_WindowPosition; break; + } + } + else if (arg[0] != 0){ + if (settings->init_files_count < settings->init_files_max){ + index = settings->init_files_count++; + settings->init_files[index] = arg; + } + } + }break; + + case CLAct_UserFile: + { + settings->user_file_is_strict = strict; + if (i < clparams.argc){ + settings->user_file = clparams.argv[i]; + } + action = CLAct_Nothing; + }break; + + case CLAct_CustomDLL: + { + plat_settings->custom_dll_is_strict = strict; + if (i < clparams.argc){ + plat_settings->custom_dll = clparams.argv[i]; + } + action = CLAct_Nothing; + }break; + + case CLAct_InitialFilePosition: + { + if (i < clparams.argc){ + settings->initial_line = str_to_int(clparams.argv[i]); + } + action = CLAct_Nothing; + }break; + + case CLAct_WindowSize: + { + if (i + 1 < clparams.argc){ + plat_settings->set_window_size = 1; + plat_settings->window_w = str_to_int(clparams.argv[i]); + plat_settings->window_h = str_to_int(clparams.argv[i+1]); + + ++i; + } + action = CLAct_Nothing; + }break; + + case CLAct_WindowMaximize: + { + --i; + plat_settings->maximize_window = 1; + action = CLAct_Nothing; + }break; + + case CLAct_WindowPosition: + { + if (i + 1 < clparams.argc){ + plat_settings->set_window_pos = 1; + plat_settings->window_x = str_to_int(clparams.argv[i]); + plat_settings->window_y = str_to_int(clparams.argv[i+1]); + + ++i; + } + action = CLAct_Nothing; + }break; + } + } +} + +internal App_Vars* +app_setup_memory(Application_Memory *memory){ + Partition _partition = partition_open(memory->vars_memory, memory->vars_memory_size); + App_Vars *vars = push_struct(&_partition, App_Vars); + Assert(vars); + *vars = {}; + vars->mem.part = _partition; + + general_memory_open(&vars->mem.general, memory->target_memory, memory->target_memory_size); + + return(vars); +} + +internal i32 +execute_special_tool(void *memory, i32 size, Command_Line_Parameters clparams){ + i32 result; + char message[] = "tool was not specified or is invalid"; + result = sizeof(message) - 1; + memcpy(memory, message, result); + if (clparams.argc > 2){ + if (match(clparams.argv[2], "version")){ + result = sizeof(VERSION) - 1; + memcpy(memory, VERSION, result); + } + } + return(result); +} + +App_Read_Command_Line_Sig(app_read_command_line){ + App_Vars *vars; + i32 out_size = 0; + + if (clparams.argc > 1 && match(clparams.argv[1], "-T")){ + out_size = execute_special_tool(memory->target_memory, memory->target_memory_size, clparams); + } + else{ + vars = app_setup_memory(memory); + if (clparams.argc > 1){ + init_command_line_settings(&vars->settings, plat_settings, clparams); + } + else{ + vars->settings = {}; + } + *files = vars->settings.init_files; + *file_count = &vars->settings.init_files_count; + } + + return(out_size); +} + +App_Init_Sig(app_init){ + app_links_init(system, memory->user_memory, memory->user_memory_size); + + App_Vars *vars = (App_Vars*)memory->vars_memory; + vars->config_api = api; + app_links.cmd_context = &vars->command_data; + + Partition *partition = &vars->mem.part; + target->partition = partition; + + Panel *panels; + Panel_Divider *dividers, *div; + i32 panel_max_count; + i32 divider_max_count; + + panel_max_count = vars->layout.panel_max_count = 16; + divider_max_count = panel_max_count - 1; + vars->layout.panel_count = 1; + + panels = push_array(partition, Panel, panel_max_count); + vars->layout.panels = panels; + + dividers = push_array(partition, Panel_Divider, divider_max_count); + vars->layout.dividers = dividers; + + div = dividers; + for (i32 i = 0; i < divider_max_count-1; ++i, ++div){ + div->next = (div + 1); + } + div->next = 0; + vars->layout.free_divider = dividers; + + i32 view_chunk_size = 0; + i32 view_sizes[] = { + sizeof(File_View) + }; + + { + char *vptr = 0; + View *v = 0, *n = 0; + i32 i = 0, max = 0; + + vars->live_set.count = 0; + vars->live_set.max = panel_max_count; + + for (i = 0; i < ArrayCount(view_sizes); ++i){ + view_chunk_size = Max(view_chunk_size, view_sizes[i]); + } + vars->live_set.stride = view_chunk_size; + vars->live_set.views = push_block(partition, view_chunk_size*vars->live_set.max); + + max = vars->live_set.max; + vptr = (char*)vars->live_set.views; + vars->live_set.free_view = (View*)vptr; + for (i = 0; i < max; ++i){ + v = (View*)(vptr); + n = (View*)(vptr + view_chunk_size); + v->next_free = n; + vptr = (char*)n; + } + v->next_free = 0; + } + + + + setup_command_table(); + + Command_Map *global = &vars->map_top; + Assert(vars->config_api.get_bindings != 0); + + i32 wanted_size = vars->config_api.get_bindings(app_links.memory, app_links.memory_size); + + b32 did_top = 0; + b32 did_file = 0; + if (wanted_size <= app_links.memory_size){ + Binding_Unit *unit = (Binding_Unit*)app_links.memory; + 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; + + vars->map_id_table = push_array( + &vars->mem.part, i32, user_map_count); + + vars->user_maps = push_array( + &vars->mem.part, Command_Map, user_map_count); + + vars->user_map_count = user_map_count; + + Command_Map *mapptr = 0; + for (++unit; unit < end; ++unit){ + switch (unit->type){ + case unit_map_begin: + { + int table_max = unit->map_begin.bind_count * 3 / 2; + int mapid = unit->map_begin.mapid; + if (mapid == mapid_global){ + mapptr = &vars->map_top; + map_init(mapptr, &vars->mem.part, table_max, global); + did_top = 1; + } + else if (mapid == mapid_file){ + mapptr = &vars->map_file; + map_init(mapptr, &vars->mem.part, table_max, global); + did_file = 1; + } + else if (mapid < mapid_global){ + i32 index = app_get_or_add_map_index(vars, mapid); + Assert(index < user_map_count); + mapptr = vars->user_maps + index; + map_init(mapptr, &vars->mem.part, table_max, global); + } + else mapptr = 0; + }break; + + case unit_inherit: + if (mapptr){ + Command_Map *parent = 0; + int mapid = unit->map_inherit.mapid; + if (mapid == mapid_global) parent = &vars->map_top; + else if (mapid == mapid_file) parent = &vars->map_file; + else if (mapid < mapid_global){ + i32 index = app_get_or_add_map_index(vars, mapid); + if (index < user_map_count) parent = vars->user_maps + index; + else parent = 0; + } + mapptr->parent = parent; + }break; + + case unit_binding: + if (mapptr){ + Command_Function func = 0; + if (unit->binding.command_id >= 0 && unit->binding.command_id < cmdid_count) + func = command_table[unit->binding.command_id]; + if (func){ + if (unit->binding.code == 0 && unit->binding.modifiers == 0){ + mapptr->vanilla_keyboard_default.function = func; + mapptr->vanilla_keyboard_default.custom_id = unit->binding.command_id; + } + else{ + map_add(mapptr, unit->binding.code, unit->binding.modifiers, func, unit->binding.command_id); + } + } + } + break; + + case unit_callback: + if (mapptr){ + Command_Function func = command_user_callback; + Custom_Command_Function *custom = unit->callback.func; + if (func){ + if (unit->callback.code == 0 && unit->callback.modifiers == 0){ + mapptr->vanilla_keyboard_default.function = func; + mapptr->vanilla_keyboard_default.custom = custom; + } + else{ + map_add(mapptr, unit->callback.code, unit->callback.modifiers, func, custom); + } + } + } + break; + + case unit_hook: + { + int hook_id = unit->hook.hook_id; + if (hook_id >= 0 && hook_id < hook_type_count){ + vars->hooks[hook_id] = unit->hook.func; + } + }break; + } + } + } + } + + memset(app_links.memory, 0, wanted_size); + if (!did_top) setup_top_commands(&vars->map_top, &vars->mem.part, global); + if (!did_file) setup_file_commands(&vars->map_file, &vars->mem.part, global); + +#if 1 || !defined(FRED_SUPER) + vars->hooks[hook_start] = 0; +#endif + + setup_ui_commands(&vars->map_ui, &vars->mem.part, global); + + vars->font_set = &target->font_set; + + font_set_init(vars->font_set, partition, 16, 5); + + { + struct Font_Setup{ + char *c_file_name; + i32 file_name_len; + char *c_name; + i32 name_len; + i32 pt_size; + }; + +#define LitStr(n) n, sizeof(n)-1 + + Font_Setup font_setup[] = { + {LitStr("LiberationSans-Regular.ttf"), + LitStr("liberation sans"), + 16}, + + {LitStr("liberation-mono.ttf"), + LitStr("liberation mono"), + 16}, + + {LitStr("Hack-Regular.ttf"), + LitStr("hack"), + 16}, + + {LitStr("CutiveMono-Regular.ttf"), + LitStr("cutive mono"), + 16}, + + {LitStr("Inconsolata-Regular.ttf"), + LitStr("inconsolata"), + 16}, + + }; + i32 font_count = ArrayCount(font_setup); + + for (i32 i = 0; i < font_count; ++i){ + String file_name = make_string(font_setup[i].c_file_name, + font_setup[i].file_name_len); + String name = make_string(font_setup[i].c_name, + font_setup[i].name_len); + i32 pt_size = font_setup[i].pt_size; + + font_set_add(partition, vars->font_set, file_name, name, pt_size); + } + } + + // NOTE(allen): file setup + vars->working_set.file_index_count = 1; + vars->working_set.file_max_count = 120; + vars->working_set.files = + push_array(partition, Editing_File, vars->working_set.file_max_count); + + file_get_dummy(&vars->working_set.files[0]); + + vars->working_set.table.max = vars->working_set.file_max_count * 3 / 2; + vars->working_set.table.count = 0; + vars->working_set.table.table = + push_array(partition, File_Table_Entry, vars->working_set.table.max); + memset(vars->working_set.table.table, 0, sizeof(File_Table_Entry) * vars->working_set.table.max); + + // NOTE(allen): clipboard setup + vars->working_set.clipboard_max_size = ArrayCount(vars->working_set.clipboards); + vars->working_set.clipboard_size = 0; + vars->working_set.clipboard_current = 0; + vars->working_set.clipboard_rolling = 0; + + // TODO(allen): more robust allocation solution for the clipboard + if (clipboard.str){ + String *dest = working_set_next_clipboard_string(&vars->mem.general, &vars->working_set, clipboard.size); + copy(dest, make_string((char*)clipboard.str, clipboard.size)); + } + + // NOTE(allen): delay setup + vars->delay1.general = &vars->mem.general; + vars->delay1.max = 16; + vars->delay1.acts = (Delayed_Action*)general_memory_allocate( + &vars->mem.general, vars->delay1.max*sizeof(Delayed_Action), 0); + + vars->delay2.general = &vars->mem.general; + vars->delay2.max = 16; + vars->delay2.acts = (Delayed_Action*)general_memory_allocate( + &vars->mem.general, vars->delay2.max*sizeof(Delayed_Action), 0); + + // NOTE(allen): style setup + app_hardcode_styles(vars); + + vars->palette_size = 40; + vars->palette = push_array(partition, u32, vars->palette_size); + + // NOTE(allen): init first panel + panel_init(&panels[0]); + panel_make_empty(system, exchange, vars, &vars->style, &panels[0]); + + String hdbase = make_fixed_width_string(vars->hot_dir_base_); + hot_directory_init(&vars->hot_directory, hdbase, current_directory, system->slash); + + vars->mini_str = make_string((char*)vars->mini_buffer, 0, 512); + + // NOTE(allen): child proc list setup + i32 max_children = 16; + partition_align(partition, 8); + vars->cli_processes.procs = push_array(partition, CLI_Process, max_children); + vars->cli_processes.max = max_children; + vars->cli_processes.count = 0; + + // NOTE(allen): sys app binding setup + vars->sys_app_max = exchange->file.max; + vars->sys_app_count = 0; + vars->sys_app_bindings = (Sys_App_Binding*)push_array(partition, Sys_App_Binding, vars->sys_app_max); +} + +App_Step_Sig(app_step){ + ProfileStart(OS_syncing); + Application_Step_Result app_result = *result; + app_result.redraw = force_redraw; + + App_Vars *vars = (App_Vars*)memory->vars_memory; + target->partition = &vars->mem.part; + + if (first_step || !time_step){ + app_result.redraw = 1; + } + + // NOTE(allen): OS clipboard event handling + if (clipboard.str){ + String *dest = working_set_next_clipboard_string(&vars->mem.general, &vars->working_set, clipboard.size); + dest->size = eol_convert_in(dest->str, clipboard.str, clipboard.size); + } + + // TODO(allen): profile this make sure it's not costing me too much power. + // NOTE(allen): check files are up to date + for (i32 i = 0; i < vars->working_set.file_index_count; ++i){ + Editing_File *file = vars->working_set.files + i; + + if (!file->state.is_dummy){ + u64 time_stamp = system->file_time_stamp(make_c_str(file->name.source_path)); + + if (time_stamp > 0){ + file->state.last_sys_write_time = time_stamp; + if (file->state.last_sys_write_time != file->state.last_4ed_write_time){ + app_result.redraw = 1; + } + } + } + } + + // NOTE(allen): update child processes + Panel *panels = vars->layout.panels; + if (time_step){ + Temp_Memory temp = begin_temp_memory(&vars->mem.part); + u32 max = Kbytes(32); + char *dest = push_array(&vars->mem.part, char, max); + u32 amount; + + i32 count = vars->cli_processes.count; + for (i32 i = 0; i < count; ++i){ + CLI_Process *proc = vars->cli_processes.procs + i; + Editing_File *out_file = proc->out_file; + + if (out_file != 0){ + i32 new_cursor = out_file->state.cursor_pos; + + for (system->cli_begin_update(&proc->cli); + system->cli_update_step(&proc->cli, dest, max, &amount);){ + amount = eol_in_place_convert_in(dest, amount); + Edit_Spec spec = {}; + spec.step.type = ED_NORMAL; + spec.step.edit.start = buffer_size(&out_file->state.buffer); + spec.step.edit.end = spec.step.edit.start; + spec.step.edit.len = amount; + spec.step.pre_pos = new_cursor; + spec.step.post_pos = spec.step.edit.start + amount; + spec.str = (u8*)dest; + file_do_single_edit(system, &vars->mem, out_file, + &vars->layout, spec, hist_normal); + app_result.redraw = 1; + new_cursor = spec.step.post_pos; + } + + if (system->cli_end_update(&proc->cli)){ + *proc = vars->cli_processes.procs[--count]; + --i; + + char str_space[256]; + String str = make_fixed_width_string(str_space); + append(&str, "exited with code "); + append_int_to_str(proc->cli.exit, &str); + + Edit_Spec spec = {}; + spec.step.type = ED_NORMAL; + spec.step.edit.start = buffer_size(&out_file->state.buffer); + spec.step.edit.end = spec.step.edit.start; + spec.step.edit.len = str.size; + spec.step.pre_pos = new_cursor; + spec.step.post_pos = spec.step.edit.start + str.size; + spec.str = (u8*)str.str; + file_do_single_edit(system, &vars->mem, out_file, + &vars->layout, spec, hist_normal); + app_result.redraw = 1; + new_cursor = spec.step.post_pos; + } + + Panel *panel = panels; + i32 panel_count = vars->layout.panel_count; + for (i32 i = 0; i < panel_count; ++i, ++panel){ + View *view = panel->view; + File_View *fview = view_to_file_view(view); + Assert(fview); + if (fview->file == out_file){ + view_cursor_move(fview, new_cursor); + } + } + } + } + + vars->cli_processes.count = count; + end_temp_memory(temp); + } + + // NOTE(allen): reorganizing panels on screen + { + i32 prev_width = vars->layout.full_width; + i32 prev_height = vars->layout.full_height; + i32 current_width = target->width; + i32 current_height = target->height; + + Panel *panel; + File_View *fview; + i32 i, count; + + vars->layout.full_width = current_width; + vars->layout.full_height = current_height; + + if (prev_width != current_width || prev_height != current_height){ + layout_refit(&vars->layout, prev_width, prev_height); + + count = vars->layout.panel_count; + panel = panels; + for (i = 0; i < count; ++i, ++panel){ + fview = view_to_file_view(panel->view); + Assert(fview); + // TODO(allen): All responses to a panel changing size should + // be handled in the same place. + view_change_size(system, &vars->mem.general, fview); + } + + app_result.redraw = 1; + } + } + + // NOTE(allen): prepare input information + Key_Summary key_data = {}; + for (i32 i = 0; i < input->press_count; ++i){ + key_data.keys[key_data.count++] = input->press[i]; + } + for (i32 i = 0; i < input->hold_count; ++i){ + key_data.keys[key_data.count++] = input->hold[i]; + } + + mouse->wheel = -mouse->wheel; + + ProfileEnd(OS_syncing); + + // NOTE(allen): while I transition away from this view system to something that has + // more unified behavior, I will use this to add checks to the program's state so that I + // can make sure it behaving well. + ProfileStart(correctness_checks); + { + Panel *panel = panels; + i32 panel_count = vars->layout.panel_count; + for (i32 i = 0; i < panel_count; ++i, ++panel){ + Assert(panel->view); + } + } + ProfileEnd(correctness_checks); + + ProfileStart(hover_status); + // NOTE(allen): detect mouse hover status + i32 mx = mouse->x; + i32 my = mouse->y; + b32 mouse_in_edit_area = 0; + b32 mouse_in_margin_area = 0; + Panel *mouse_panel = 0; + i32 mouse_panel_i = 0; + i32 panel_count = vars->layout.panel_count; + + mouse_panel = panels; + for (mouse_panel_i = 0; mouse_panel_i < panel_count; ++mouse_panel_i, ++mouse_panel){ + if (hit_check(mx, my, mouse_panel->inner)){ + mouse_in_edit_area = 1; + break; + } + else if (hit_check(mx, my, mouse_panel->full)){ + mouse_in_margin_area = 1; + break; + } + } + + if (!(mouse_in_edit_area || mouse_in_margin_area)){ + mouse_panel = 0; + mouse_panel_i = 0; + } + + b32 mouse_on_divider = 0; + b32 mouse_divider_vertical = 0; + 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){ + mouse_divider_vertical = 0; + if (my > panel->inner.y0){ + mouse_divider_side = -1; + } + else{ + mouse_divider_side = 1; + } + } + else{ + mouse_divider_vertical = 1; + if (mx > panel->inner.x0){ + mouse_divider_side = -1; + } + else{ + mouse_divider_side = 1; + } + } + + if (vars->layout.panel_count > 1){ + i32 which_child; + mouse_divider_id = panel->parent; + which_child = panel->which_child; + for (;;){ + Divider_And_ID div = layout_get_divider(&vars->layout, mouse_divider_id); + + if (which_child == mouse_divider_side && + div.divider->v_divider == mouse_divider_vertical){ + mouse_on_divider = 1; + break; + } + + if (mouse_divider_id == vars->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; + } + } + ProfileEnd(hover_status); + + // NOTE(allen): prepare to start executing commands + ProfileStart(command_coroutine); + + Command_Data *cmd = &vars->command_data; + + cmd->mem = &vars->mem; + cmd->panel = panels + vars->layout.active_panel; + cmd->view = cmd->panel->view; + cmd->working_set = &vars->working_set; + cmd->layout = &vars->layout; + cmd->live_set = &vars->live_set; + cmd->style = &vars->style; + cmd->delay = &vars->delay1; + cmd->vars = vars; + cmd->exchange = exchange; + cmd->screen_width = target->width; + cmd->screen_height = target->height; + cmd->system = system; + + Temp_Memory param_stack_temp = begin_temp_memory(&vars->mem.part); + cmd->part = partition_sub_part(&vars->mem.part, 16 << 10); + + if (first_step){ + if (vars->hooks[hook_start]){ + vars->hooks[hook_start](&app_links); + cmd->part.pos = 0; + } + + i32 i; + String file_name; + Panel *panel = vars->layout.panels; + for (i = 0; i < vars->settings.init_files_count; ++i, ++panel){ + file_name = make_string_slowly(vars->settings.init_files[i]); + + if (i < vars->layout.panel_count){ + delayed_open(&vars->delay1, file_name, panel); + if (i == 0){ + delayed_set_line(&vars->delay1, panel, vars->settings.initial_line); + } + } + else{ + delayed_open_background(&vars->delay1, file_name); + } + } + } + ProfileEnd(hover_status); + + // NOTE(allen): process the command_coroutine if it is unfinished + ProfileStart(command_coroutine); + b8 consumed_input[6] = {0}; + + if (vars->command_coroutine != 0){ + Coroutine *command_coroutine = vars->command_coroutine; + u32 get_flags = vars->command_coroutine_flags[0]; + u32 abort_flags = vars->command_coroutine_flags[1]; + + get_flags |= abort_flags; + + if ((get_flags & EventOnAnyKey) || (get_flags & EventOnEsc)){ + for (i32 key_i = 0; key_i < key_data.count; ++key_i){ + Key_Event_Data key = get_single_key(&key_data, key_i); + View *view = cmd->view; + b32 pass_in = 0; + cmd->key = key; + + Command_Map *map = 0; + if (view) map = view->map; + if (map == 0) map = &vars->map_top; + Command_Binding cmd_bind = map_extract_recursive(map, key); + + User_Input user_in; + user_in.type = UserInputKey; + user_in.key = key; + user_in.command = (unsigned long long)cmd_bind.custom; + user_in.abort = 0; + + if ((EventOnEsc & abort_flags) && key.keycode == key_esc){ + user_in.abort = 1; + } + else if (EventOnAnyKey & abort_flags){ + user_in.abort = 1; + } + + if (EventOnAnyKey & get_flags){ + pass_in = 1; + consumed_input[0] = 1; + } + if (key.keycode == key_esc){ + if (EventOnEsc & get_flags){ + pass_in = 1; + } + consumed_input[1] = 1; + } + + if (pass_in){ + cmd->current_coroutine = vars->command_coroutine; + vars->command_coroutine = system->resume_coroutine(command_coroutine, + &user_in, vars->command_coroutine_flags); + app_result.redraw = 1; + + // TOOD(allen): Deduplicate + // TODO(allen): Allow a view to clean up however it wants after a command + // finishes, or after transfering to another view mid command. + File_View *fview = view_to_file_view(view); + if (fview != 0 && vars->command_coroutine == 0){ + init_query_set(&fview->query_set); + } + if (vars->command_coroutine == 0) break; + } + } + } + + if (vars->command_coroutine != 0 && (get_flags & EventOnMouse)){ + View *view = cmd->view; + b32 pass_in = 0; + + User_Input user_in; + user_in.type = UserInputMouse; + user_in.mouse = *mouse; + user_in.command = 0; + user_in.abort = 0; + + if (abort_flags & EventOnMouseMove){ + user_in.abort = 1; + } + if (get_flags & EventOnMouseMove){ + pass_in = 1; + consumed_input[2] = 1; + } + + if (mouse->press_l || mouse->release_l || mouse->l){ + if (abort_flags & EventOnLeftButton){ + user_in.abort = 1; + } + if (get_flags & EventOnLeftButton){ + pass_in = 1; + consumed_input[3] = 1; + } + } + + if (mouse->press_r || mouse->release_r || mouse->r){ + if (abort_flags & EventOnRightButton){ + user_in.abort = 1; + } + if (get_flags & EventOnRightButton){ + pass_in = 1; + consumed_input[4] = 1; + } + } + + if (mouse->wheel != 0){ + if (abort_flags & EventOnWheel){ + user_in.abort = 1; + } + if (get_flags & EventOnWheel){ + pass_in = 1; + consumed_input[5] = 1; + } + } + + if (pass_in){ + cmd->current_coroutine = vars->command_coroutine; + vars->command_coroutine = system->resume_coroutine(command_coroutine, &user_in, + vars->command_coroutine_flags); + app_result.redraw = 1; + + // TOOD(allen): Deduplicate + // TODO(allen): Allow a view to clean up however it wants after a command finishes, + // or after transfering to another view mid command. + File_View *fview = view_to_file_view(view); + if (fview != 0 && vars->command_coroutine == 0){ + init_query_set(&fview->query_set); + } + } + } + } + + update_command_data(vars, cmd); + + ProfileEnd(command_coroutine); + + // NOTE(allen): pass raw input to the panels + ProfileStart(step); + + Input_Summary dead_input = {}; + dead_input.mouse.x = mouse->x; + dead_input.mouse.y = mouse->y; + + Input_Summary active_input = {}; + active_input.mouse.x = mouse->x; + active_input.mouse.y = mouse->y; + if (!consumed_input[0]){ + active_input.keys = key_data; + } + else if (!consumed_input[1]){ + for (i32 i = 0; i < key_data.count; ++i){ + Key_Event_Data key = get_single_key(&key_data, i); + if (key.keycode == key_esc){ + active_input.keys.count = 1; + active_input.keys.keys[0] = key; + break; + } + } + } + + Mouse_State mouse_state = *mouse; + + if (consumed_input[3]){ + mouse_state.l = 0; + mouse_state.press_l = 0; + mouse_state.release_l = 0; + } + + if (consumed_input[4]){ + mouse_state.r = 0; + mouse_state.press_r = 0; + mouse_state.release_r = 0; + } + + if (consumed_input[5]){ + mouse_state.wheel = 0; + } + + { + Panel *panel = panels; + for (i32 panel_i = vars->layout.panel_count; panel_i > 0; --panel_i, ++panel){ + View *view_ = panel->view; + if (view_){ + Assert(view_->do_view); + b32 active = (panel == cmd->panel); + Input_Summary input = (active)?(active_input):(dead_input); + if (panel == mouse_panel && !mouse->out_of_window){ + input.mouse = mouse_state; + } + if (view_->do_view(system, exchange, view_, panel->inner, cmd->view, + VMSG_STEP, 0, &input, &active_input)){ + app_result.redraw = 1; + } + } + } + } + + update_command_data(vars, cmd); + ProfileEnd(step); + + // NOTE(allen): command execution + ProfileStart(command); + if (!consumed_input[0] || !consumed_input[1]){ + b32 consumed_input2[2] = {0}; + + for (i32 key_i = 0; key_i < key_data.count; ++key_i){ + switch (vars->state){ + case APP_STATE_EDIT: + { + Key_Event_Data key = get_single_key(&key_data, key_i); + b32 hit_esc = (key.keycode == key_esc); + cmd->key = key; + + if (hit_esc || !consumed_input[0]){ + View *view = cmd->view; + + Command_Map *map = 0; + if (view) map = view->map; + if (map == 0) map = &vars->map_top; + Command_Binding cmd_bind = map_extract_recursive(map, key); + + if (cmd_bind.function){ + if (hit_esc){ + consumed_input2[1] = 1; + } + else{ + consumed_input2[0] = 1; + } + + Coroutine *command_coroutine = system->create_coroutine(command_caller); + vars->command_coroutine = command_coroutine; + + Command_In cmd_in; + cmd_in.cmd = cmd; + cmd_in.bind = cmd_bind; + + cmd->current_coroutine = vars->command_coroutine; + vars->command_coroutine = system->launch_coroutine(vars->command_coroutine, + &cmd_in, vars->command_coroutine_flags); + vars->prev_command = cmd_bind; + app_result.redraw = 1; + } + } + }break; + + case APP_STATE_RESIZING: + { + if (key_data.count > 0){ + vars->state = APP_STATE_EDIT; + } + }break; + } + } + + consumed_input[0] |= consumed_input2[0]; + consumed_input[1] |= consumed_input2[1]; + } + + update_command_data(vars, cmd); + ProfileEnd(command); + + ProfileStart(resizing); + // NOTE(allen): panel resizing + switch (vars->state){ + case APP_STATE_EDIT: + { + if (mouse->press_l && mouse_on_divider){ + vars->state = APP_STATE_RESIZING; + Divider_And_ID div = layout_get_divider(&vars->layout, mouse_divider_id); + vars->resizing.divider = div.divider; + + i32 min, max; + { + i32 mid, MIN, MAX; + mid = div.divider->pos; + if (mouse_divider_vertical){ + MIN = 0; + MAX = MIN + vars->layout.full_width; + } + else{ + MIN = 0; + MAX = MIN + vars->layout.full_height; + } + min = MIN; + max = MAX; + + i32 divider_id = div.id; + do{ + Divider_And_ID other_div = layout_get_divider(&vars->layout, divider_id); + b32 divider_match = (other_div.divider->v_divider == mouse_divider_vertical); + i32 pos = other_div.divider->pos; + 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(&vars->mem.part); + i32 *divider_stack = push_array(&vars->mem.part, i32, vars->layout.panel_count); + i32 top = 0; + divider_stack[top++] = div.id; + + while (top > 0){ + Divider_And_ID other_div = layout_get_divider(&vars->layout, divider_stack[--top]); + b32 divider_match = (other_div.divider->v_divider == mouse_divider_vertical); + i32 pos = other_div.divider->pos; + 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); + } + + vars->resizing.min = min; + vars->resizing.max = max; + } + }break; + + case APP_STATE_RESIZING: + { + app_result.redraw = 1; + if (mouse->l){ + Panel_Divider *divider = vars->resizing.divider; + if (divider->v_divider){ + divider->pos = mx; + } + else{ + divider->pos = my; + } + + if (divider->pos < vars->resizing.min){ + divider->pos = vars->resizing.min; + } + else if (divider->pos > vars->resizing.max){ + divider->pos = vars->resizing.max - 1; + } + + layout_fix_all_panels(&vars->layout); + } + else{ + vars->state = APP_STATE_EDIT; + } + }break; + } + + if (mouse_in_edit_area && mouse_panel != 0 && mouse->press_l){ + vars->layout.active_panel = mouse_panel_i; + app_result.redraw = 1; + } + + update_command_data(vars, cmd); + ProfileEnd(resizing); + + // NOTE(allen): processing sys app bindings + ProfileStart(sys_app_bind_processing); + { + Mem_Options *mem = &vars->mem; + General_Memory *general = &mem->general; + + for (i32 i = 0; i < vars->sys_app_count; ++i){ + Sys_App_Binding *binding; + b32 remove = 0; + b32 failed = 0; + binding = vars->sys_app_bindings + i; + + byte *data; + i32 size, max; + Editing_File *ed_file; + Editing_File_Preload preload_settings; + char *filename; + + Working_Set *working_set = &vars->working_set; + + if (exchange_file_ready(exchange, binding->sys_id, &data, &size, &max)){ + ed_file = working_set->files + binding->app_id; + filename = exchange_file_filename(exchange, binding->sys_id); + preload_settings = ed_file->preload; + if (data){ + String val = make_string((char*)data, size); + file_create_from_string(system, mem, working_set, ed_file, filename, + vars->font_set, vars->style.font_id, val); + + if (ed_file->settings.tokens_exist){ + file_first_lex_parallel(system, general, ed_file); + } + + if ((binding->success & SysAppCreateView) && binding->panel != 0){ + view_file_in_panel(cmd, binding->panel, ed_file); + } + + app_result.redraw = 1; + } + else{ + if (binding->fail & SysAppCreateNewBuffer){ + file_create_empty(system, mem, working_set, ed_file, filename, + vars->font_set, vars->style.font_id); + if (binding->fail & SysAppCreateView){ + view_file_in_panel(cmd, binding->panel, ed_file); + } + } + else{ + table_remove(&vars->working_set.table, ed_file->name.source_path); + file_get_dummy(ed_file); + } + + app_result.redraw = 1; + } + + if (!ed_file->state.is_dummy){ + for (File_View_Iter iter = file_view_iter_init(&vars->layout, ed_file, 0); + file_view_iter_good(iter); + iter = file_view_iter_next(iter)){ + view_measure_wraps(system, general, iter.view); + view_cursor_move(iter.view, preload_settings.start_line, 0); + } + } + + exchange_free_file(exchange, binding->sys_id); + remove = 1; + } + + if (exchange_file_save_complete(exchange, binding->sys_id, &data, &size, &max, &failed)){ + Assert(remove == 0); + + if (data){ + general_memory_free(general, data); + exchange_clear_file(exchange, binding->sys_id); + } + + Editing_File *file = get_file(working_set, binding->app_id); + if (file){ + file_synchronize_times(system, file, file->name.source_path.str); + } + + exchange_free_file(exchange, binding->sys_id); + remove = 1; + + // if (failed) { TODO(allen): saving error, now what? } + } + + if (remove){ + *binding = vars->sys_app_bindings[--vars->sys_app_count]; + --i; + } + } + } + ProfileEnd(sys_app_bind_processing); + + // NOTE(allen): process as many delayed actions as possible + ProfileStart(delayed_actions); + if (vars->delay1.count > 0){ + Style *style = &vars->style; + Working_Set *working_set = &vars->working_set; + Live_Views *live_set = &vars->live_set; + Mem_Options *mem = &vars->mem; + General_Memory *general = &vars->mem.general; + + i32 count = vars->delay1.count; + vars->delay1.count = 0; + vars->delay2.count = 0; + + Delayed_Action *act = vars->delay1.acts; + for (i32 i = 0; i < count; ++i, ++act){ + String string = act->string; + Panel *panel = act->panel; + Editing_File *file = act->file; + i32 integer = act->integer; + + // TODO(allen): Paramter checking in each DACT case. + switch (act->type){ + case DACT_OPEN: + { + App_Open_File_Result result; + + result = app_open_file_background(vars, exchange, working_set, string); + + if (result.is_new){ + if (result.file){ + if (result.sys_id){ + Sys_App_Binding *binding = app_push_file_binding(vars, result.sys_id, result.file_index); + binding->success = SysAppCreateView; + binding->fail = 0; + binding->panel = panel; + } + else{ + delayed_action_repush(&vars->delay2, act); + } + } + } + else{ + if (result.file->state.is_dummy || result.file->state.is_loading){ + // do nothing + } + else{ + view_file_in_panel(cmd, panel, result.file); + } + } + }break; + + case DACT_OPEN_BACKGROUND: + { + App_Open_File_Result result; + result = app_open_file_background(vars, exchange, working_set, string); + if (result.is_new){ + if (result.file){ + if (result.sys_id){ + Sys_App_Binding *binding = app_push_file_binding(vars, result.sys_id, result.file_index); + binding->success = 0; + binding->fail = 0; + binding->panel = panel; + } + else{ + delayed_action_repush(&vars->delay2, act); + } + } + } + }break; + + case DACT_SET_LINE: + { + // TODO(allen): deduplicate + Editing_File *file = 0; + if (panel){ + File_View *fview = view_to_file_view(panel->view); + file = fview->file; + } + else if (string.str && string.size > 0){ + file = working_set_lookup_file(working_set, string); + } + if (file){ + if (file->state.is_loading){ + file->preload.start_line = integer; + } + else{ + // TODO(allen): write this case + } + } + }break; + + case DACT_SAVE_AS: + { + // TODO(allen): deduplicate + Editing_File *file = 0; + if (panel){ + File_View *fview = view_to_file_view(panel->view); + file = fview->file; + } + else if (string.str && string.size > 0){ + file = working_set_lookup_file(working_set, string); + } + if (file && !file->state.is_dummy){ + i32 sys_id = file_save_and_set_names(system, exchange, mem, working_set, file, string.str); + if (sys_id){ + app_push_file_binding(vars, sys_id, get_file_id(working_set, file)); + } + else{ + delayed_action_repush(&vars->delay2, act); + } + } + }break; + + case DACT_SAVE: + { + if (!file){ + if (panel){ + View *view; + File_View *fview; + view = panel->view; + fview = view_to_file_view(view); + Assert(fview); + file = fview->file; + } + else{ + file = working_set_lookup_file(working_set, string); + } + } + // TODO(allen): We could handle the case where someone tries to save the same thing + // twice... that would be nice to have under control. + if (file && !file->state.is_dummy && buffer_needs_save(file)){ + i32 sys_id = file_save(system, exchange, mem, file, file->name.source_path.str); + if (sys_id){ + // TODO(allen): This is fishy! Shouldn't we bind it to a file name instead? This file + // might be killed before we get notified that the saving is done! + app_push_file_binding(vars, sys_id, get_file_id(working_set, file)); + } + else{ + delayed_action_repush(&vars->delay2, act); + } + } + }break; + + case DACT_NEW: + { + Get_File_Result file = working_set_get_available_file(working_set); + file_create_empty(system, mem, working_set, file.file, string.str, + vars->font_set, style->font_id); + table_add(&working_set->table, file.file->name.source_path, file.index); + + View *new_view = live_set_alloc_view(live_set, mem); + view_replace_major(system, exchange, new_view, panel, live_set); + + File_View *file_view = file_view_init( + new_view, &vars->layout, working_set, &vars->delay2, + &vars->settings, &vars->hot_directory, mem, &vars->styles); + cmd->view = (View*)file_view; + view_set_file(file_view, file.file, vars->font_set, style, + system, vars->hooks[hook_open_file], &app_links); + new_view->map = app_get_map(vars, file.file->settings.base_map_id); +#if BUFFER_EXPERIMENT_SCALPEL <= 0 + if (file.file->settings.tokens_exist) + file_first_lex_parallel(system, general, file.file); +#endif + }break; + + case DACT_SWITCH: + { + Editing_File *file = working_set_lookup_file(working_set, string); + if (file){ + View *new_view = live_set_alloc_view(live_set, mem); + view_replace_major(system, exchange, new_view, panel, live_set); + + File_View *file_view = file_view_init( + new_view, &vars->layout, working_set, &vars->delay2, + &vars->settings, &vars->hot_directory, mem, &vars->styles); + cmd->view = (View*)file_view; + + view_set_file(file_view, file, vars->font_set, style, + system, vars->hooks[hook_open_file], &app_links); + + new_view->map = app_get_map(vars, file->settings.base_map_id); + } + }break; + + case DACT_KILL: + { + Editing_File *file = working_set_lookup_file(working_set, string); + if (file){ + table_remove(&working_set->table, file->name.source_path); + kill_file(system, exchange, general, file, live_set, &vars->layout); + } + }break; + + case DACT_TRY_KILL: + { + Editing_File *file = 0; + file = working_set_lookup_file(working_set, string); + + View *view = 0; + if (panel){ + view = panel->view; + } + else{ + view = (vars->layout.panels + vars->layout.active_panel)->view; + } + + File_View *fview = view_to_file_view(view); + Assert(fview); + + if (file){ + if (buffer_needs_save(file)){ + view_show_interactive(system, fview, &vars->map_ui, + IAct_Sure_To_Kill, IInt_Sure_To_Kill, make_lit_string("Are you sure?")); + copy(&fview->dest, file->name.live_name); + } + else{ + table_remove(&working_set->table, file->name.source_path); + kill_file(system, exchange, general, file, live_set, &vars->layout); + } + } + }break; + } + + if (string.str){ + general_memory_free(&mem->general, string.str); + } + } + Swap(vars->delay1, vars->delay2); + } + ProfileEnd(delayed_actions); + + end_temp_memory(param_stack_temp); + + ProfileStart(resize); + // NOTE(allen): send resize messages to panels that have changed size + { + Panel *panel = panels; + for (i32 panel_i = vars->layout.panel_count; panel_i > 0; --panel_i, ++panel){ + i32_Rect prev = panel->prev_inner; + i32_Rect inner = panel->inner; + if (prev.x0 != inner.x0 || prev.y0 != inner.y0 || + prev.x1 != inner.x1 || prev.y1 != inner.y1){ + View *view = panel->view; + if (view){ + view->do_view(system, exchange, + view, inner, cmd->view, + VMSG_RESIZE, 0, &dead_input, &active_input); + } + } + panel->prev_inner = inner; + } + } + ProfileEnd(resize); + + ProfileStart(style_change); + // NOTE(allen): send style change messages if the style has changed + if (vars->style.font_changed){ + vars->style.font_changed = 0; + + Editing_File *file = vars->working_set.files; + for (i32 i = vars->working_set.file_index_count; i > 0; --i, ++file){ + if (buffer_good(&file->state.buffer) && !file->state.is_dummy){ + Render_Font *font = get_font_info(vars->font_set, vars->style.font_id)->font; + float *advance_data = 0; + if (font) advance_data = font->advance_data; + + file_measure_starts_widths(system, &vars->mem.general, + &file->state.buffer, advance_data); + } + } + + Panel *panel = panels; + i32 count = vars->layout.panel_count; + for (i32 i = 0; i < count; ++i, ++panel){ + View *view = panel->view; + if (view){ + view->do_view(system, exchange, + view, panel->inner, cmd->view, + VMSG_STYLE_CHANGE, 0, &dead_input, &active_input); + } + } + } + ProfileEnd(style_change); + + ProfileStart(redraw); + if (mouse_panel != vars->prev_mouse_panel) app_result.redraw = 1; + if (app_result.redraw){ + begin_render_section(target, system); + + target->clip_top = -1; + draw_push_clip(target, rect_from_target(target)); + + // NOTE(allen): render the panels + Panel *panel = panels; + for (i32 panel_i = vars->layout.panel_count; panel_i > 0; --panel_i, ++panel){ + i32_Rect full = panel->full; + i32_Rect inner = panel->inner; + + View *view = panel->view; + Style *style = &vars->style; + + b32 active = (panel == cmd->panel); + u32 back_color = style->main.back_color; + draw_rectangle(target, full, back_color); + + if (view){ + Assert(view->do_view); + draw_push_clip(target, panel->inner); + view->do_view(system, exchange, + view, panel->inner, cmd->view, + VMSG_DRAW, target, &dead_input, &active_input); + draw_pop_clip(target); + } + + 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); + } + ProfileEnd(redraw); + + ProfileStart(get_cursor); + // NOTE(allen): get cursor type + if (mouse_in_edit_area){ + View *view = mouse_panel->view; + if (view){ + app_result.mouse_cursor_type = view->mouse_cursor_type; + } + else{ + 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; + } + } + vars->prev_mouse_panel = mouse_panel; + ProfileEnd(get_cursor); + + *result = app_result; + result->lctrl_lalt_is_altgr = vars->settings.lctrl_lalt_is_altgr; + + // end-of-app_step +} + +external App_Get_Functions_Sig(app_get_functions){ + App_Functions result = {}; + + result.read_command_line = app_read_command_line; + result.init = app_init; + result.step = app_step; + + return(result); +} + +// BOTTOM + diff --git a/4ed.h b/4ed.h index ab05756e..c27572fe 100644 --- a/4ed.h +++ b/4ed.h @@ -115,19 +115,10 @@ struct Application_Step_Result{ typedef App_Step_Sig(App_Step); -#define App_Alloc_Sig(name) void *name(void *handle, i32 size) -typedef App_Alloc_Sig(App_Alloc); - -#define App_Free_Sig(name) void name(void *handle, void *block) -typedef App_Free_Sig(App_Free); - struct App_Functions{ App_Read_Command_Line *read_command_line; App_Init *init; App_Step *step; - - App_Alloc *alloc; - App_Free *free; }; #define App_Get_Functions_Sig(name) App_Functions name() diff --git a/4ed_app_target.cpp b/4ed_app_target.cpp index 03bdf872..7fe48439 100644 --- a/4ed_app_target.cpp +++ b/4ed_app_target.cpp @@ -9,16 +9,7 @@ // TOP -#define VERSION_NUMBER "alpha 3.4.4" - -#ifdef FRED_SUPER -#define VERSION_TYPE " super!" -#else -#define VERSION_TYPE "" -#endif - -#define VERSION VERSION_NUMBER VERSION_TYPE - +#include "4ed_version.h" #include "4ed_config.h" #define BUFFER_EXPERIMENT_SCALPEL 0 @@ -53,12 +44,8 @@ #include "4ed_file.cpp" #include "4ed_gui.cpp" #include "4ed_delay.cpp" -#include "4ed_file_view.cpp" -#include "4ed_color_view.cpp" -#include "4ed_interactive_view.cpp" -#include "4ed_menu_view.cpp" #include "4ed_app_settings.h" -#include "4ed_config_view.cpp" +#include "4ed_file_view.cpp" #include "4ed.cpp" // BOTTOM diff --git a/4ed_color_view.cpp b/4ed_color_view.cpp deleted file mode 100644 index c60442e1..00000000 --- a/4ed_color_view.cpp +++ /dev/null @@ -1,1909 +0,0 @@ -/* - * Mr. 4th Dimention - Allen Webster - * - * 20.08.2015 - * - * Color customizing view for 4coder - * - */ - -// TOP - -enum Color_View_Mode{ - CV_MODE_LIBRARY, - CV_MODE_IMPORT_FILE, - CV_MODE_EXPORT_FILE, - CV_MODE_IMPORT, - CV_MODE_EXPORT, - CV_MODE_IMPORT_WAIT, - CV_MODE_ADJUSTING -}; - -struct Super_Color{ - Vec4 hsla; - Vec4 rgba; - u32 *out; -}; - -internal Super_Color -super_color_create(u32 packed){ - Super_Color result = {}; - result.rgba = unpack_color4(packed); - result.hsla = rgba_to_hsla(result.rgba); - return result; -} - -internal void -super_color_post_hsla(Super_Color *color, Vec4 hsla){ - color->hsla = hsla; - if (hsla.h == 1.f) - hsla.h = 0.f; - color->rgba = hsla_to_rgba(hsla); - *color->out = pack_color4(color->rgba); -} - -internal void -super_color_post_rgba(Super_Color *color, Vec4 rgba){ - color->rgba = rgba; - color->hsla = rgba_to_hsla(rgba); - *color->out = pack_color4(rgba); -} - -internal void -super_color_post_packed(Super_Color *color, u32 packed){ - color->rgba = unpack_color4(packed); - color->hsla = rgba_to_hsla(color->rgba); - *color->out = packed; -} - -u32 super_color_clear_masks[] = {0xFF00FFFF, 0xFFFF00FF, 0xFFFFFF00}; -u32 super_color_shifts[] = {16, 8, 0}; - -internal u32 -super_color_post_byte(Super_Color *color, i32 channel, u8 byte){ - u32 packed = *color->out; - packed &= super_color_clear_masks[channel]; - packed |= (byte << super_color_shifts[channel]); - super_color_post_packed(color, packed); - return packed; -} - -struct Color_Highlight{ - i32 ids[4]; -}; - -struct Library_UI{ - UI_State state; - UI_Layout layout; - - Font_Set *fonts; - - Style_Library *styles; - Hot_Directory *hot_directory; -}; - -struct Color_UI{ - UI_State state; - UI_Layout layout; - - Font_Set *fonts; - - real32 hex_advance; - u32 *palette; - i32 palette_size; - - Color_Highlight highlight; - Super_Color color; - - bool32 has_hover_color; - Super_Color hover_color; -}; - -struct Color_View{ - View view_base; - Hot_Directory *hot_directory; - Style *main_style; - Style_Library *styles; - File_View *hot_file_view; - Font_Set *font_set; - u32 *palette; - Working_Set *working_set; - i32 palette_size; - Color_View_Mode mode; - UI_State state; - Super_Color color; - Color_Highlight highlight; - b32 p4c_only; - Style_Library inspecting_styles; - b8 import_export_check[64]; - i32 import_file_id; -}; - -inline Color_View* -view_to_color_view(View *view){ - Assert(!view || view->type == VIEW_TYPE_COLOR); - return (Color_View*)view; -} - -internal void -draw_gradient_slider(Render_Target *target, Vec4 base, i32 channel, - i32 steps, f32 top, f32_Rect slider, b32 hsla){ - Vec4 low, high; - f32 *lowv, *highv; - f32 x; - f32 next_x; - f32 x_step; - f32 v_step; - f32 m; - - x = (real32)slider.x0; - x_step = (real32)(slider.x1 - slider.x0) / steps; - v_step = top / steps; - m = 1.f / top; - lowv = &low.v[channel]; - highv = &high.v[channel]; - - if (hsla){ - for (i32 i = 0; i < steps; ++i){ - low = high = base; - *lowv = (i * v_step); - *highv = *lowv + v_step; - *lowv *= m; - *highv *= m; - low = hsla_to_rgba(low); - high = hsla_to_rgba(high); - - next_x = x + x_step; - draw_gradient_2corner_clipped( - target, x, slider.y0, next_x, slider.y1, - low, high); - x = next_x; - } - } - else{ - for (i32 i = 0; i < steps; ++i){ - low = high = base; - *lowv = (i * v_step); - *highv = *lowv + v_step; - *lowv *= m; - *highv *= m; - - next_x = x + x_step; - draw_gradient_2corner_clipped( - target, x, slider.y0, next_x, slider.y1, - low, high); - x = next_x; - } - } -} - -inline void -draw_hsl_slider(Render_Target *target, Vec4 base, i32 channel, - i32 steps, real32 top, f32_Rect slider){ - draw_gradient_slider(target, base, channel, steps, top, slider, 1); -} - -inline void -draw_rgb_slider(Render_Target *target, Vec4 base, i32 channel, - i32 steps, f32 top, f32_Rect slider){ - draw_gradient_slider(target, base, channel, steps, top, slider, 0); -} - -internal void -do_label(UI_State *state, UI_Layout *layout, char *text, int text_size, f32 height = 2.f){ - Style *style = state->style; - i16 font_id = style->font_id; - i32 line_height = get_font_info(state->font_set, font_id)->height; - i32_Rect label = layout_rect(layout, FLOOR32(line_height * height)); - - if (!state->input_stage){ - Render_Target *target = state->target; - u32 back = style->main.margin_color; - u32 fore = style->main.default_color; - draw_rectangle(target, label, back); - i32 height = label.y1 - label.y0; - - String textstr = make_string(text, text_size); - draw_string(target, font_id, textstr, label.x0, - label.y0 + (height - line_height)/2, fore); - } -} - -inline void -do_label(UI_State *state, UI_Layout *layout, String text, f32 height = 2.f){ - do_label(state, layout, text.str, text.size, height); -} - -internal void -do_scroll_bar(UI_State *state, i32_Rect rect){ - i32 id = 1; - i32 w = (rect.x1 - rect.x0); - i32 h = (rect.y1 - rect.y0); - - i32_Rect top_arrow, bottom_arrow; - top_arrow.x0 = rect.x0; - top_arrow.x1 = rect.x1; - top_arrow.y0 = rect.y0; - top_arrow.y1 = top_arrow.y0 + w; - - bottom_arrow.x0 = rect.x0; - bottom_arrow.x1 = rect.x1; - bottom_arrow.y1 = rect.y1; - bottom_arrow.y0 = bottom_arrow.y1 - w; - - f32 space_h = (f32)(bottom_arrow.y0 - top_arrow.y1); - if (space_h <= w) return; - - i32 slider_h = w; - - f32 view_hmin = 0; - f32 view_hmax = state->height - h; - f32 L = unlerp(view_hmin, state->view_y, view_hmax); - - f32 slider_hmin = (f32)top_arrow.y1; - f32 slider_hmax = (f32)bottom_arrow.y0 - slider_h; - f32 S = lerp(slider_hmin, L, slider_hmax); - - i32_Rect slider; - slider.x0 = rect.x0; - slider.x1 = rect.x1; - slider.y0 = FLOOR32(S); - slider.y1 = slider.y0 + slider_h; - - Widget_ID wid = make_id(state, id); - - if (state->input_stage){ - state->view_y = - ui_do_vscroll_input(state, top_arrow, bottom_arrow, slider, wid, state->view_y, - (f32)(get_font_info(state->font_set, state->font_id)->height), - slider_hmin, slider_hmax, view_hmin, view_hmax); - } - else{ - Render_Target *target = state->target; - - f32 x0, y0, x1, y1, x2, y2; - f32 w_1_2 = w*.5f; - f32 w_1_3 = w*.333333f; - f32 w_2_3 = w*.666667f; - - - UI_Style ui_style = get_ui_style(state->style); - u32 outline, back, fore; - - outline = ui_style.bright; - - wid.sub_id2 = 0; - - x0 = (w_1_2 + top_arrow.x0); - x1 = (w_1_3 + top_arrow.x0); - x2 = (w_2_3 + top_arrow.x0); - - ++wid.sub_id2; - y0 = (w_1_3 + top_arrow.y0); - y1 = (w_2_3 + top_arrow.y0); - y2 = (w_2_3 + top_arrow.y0); - get_colors(state, &back, &fore, wid, ui_style); - draw_rectangle(target, top_arrow, back); - draw_rectangle_outline(target, top_arrow, outline); - - ++wid.sub_id2; - y0 = (w_2_3 + bottom_arrow.y0); - y1 = (w_1_3 + bottom_arrow.y0); - y2 = (w_1_3 + bottom_arrow.y0); - get_colors(state, &back, &fore, wid, ui_style); - draw_rectangle(target, bottom_arrow, back); - draw_rectangle_outline(target, bottom_arrow, outline); - - ++wid.sub_id2; - get_colors(state, &back, &fore, wid, ui_style); - draw_rectangle(target, slider, back); - draw_rectangle_outline(target, slider, outline); - - draw_rectangle_outline(target, rect, outline); - } -} - -internal void -do_single_slider(i32 sub_id, Color_UI *ui, i32 channel, b32 is_rgba, - i32 grad_steps, f32 top, f32_Rect slider, f32 v_handle, - i32_Rect rect){ - f32_Rect click_box = slider; - click_box.y0 -= v_handle; - - if (ui->state.input_stage){ - real32 v; - if (ui_do_slider_input(&ui->state, i32R(click_box), make_sub1(&ui->state, sub_id), - slider.x0, slider.x1, &v)){ - Vec4 new_color; - if (is_rgba) new_color = ui->color.rgba; - else new_color = ui->color.hsla; - new_color.v[channel] = clamp(0.f, v, 1.f); - if (is_rgba) super_color_post_rgba(&ui->color, new_color); - else super_color_post_hsla(&ui->color, new_color); - } - } - else{ - Render_Target *target = ui->state.target; - Vec4 color; - real32 x; - if (is_rgba){ - color = ui->color.rgba; - draw_rgb_slider(target, V4(0,0,0,1.f), channel, 10, 100.f, slider); - } - else{ - i32 steps; - real32 top; - if (channel == 0){ - steps = 45; - top = 360.f; - } - else{ - steps = 10; - top = 100.f; - } - color = ui->color.hsla; - draw_hsl_slider(target, color, channel, steps, top, slider); - } - - x = lerp(slider.x0, color.v[channel], slider.x1); - draw_rectangle( - target, f32R(x, slider.y0, x + 1, slider.y1), 0xff000000); - - draw_rectangle( - target, f32R(x-2, click_box.y0, x+3, slider.y0-4), 0xff777777); - } -} - -internal void -do_hsl_sliders(Color_UI *ui, i32_Rect rect){ - real32 bar_width = (real32)(rect.x1 - rect.x0 - 20); - if (bar_width > 45){ - f32_Rect slider; - real32 y; - i32 sub_id; - - real32 v_full_space = 30.f; - real32 v_half_space = 15.f; - real32 v_quarter_space = 12.f; - real32 v_handle = 9.f; - - slider.x0 = rect.x0 + 10.f; - slider.x1 = slider.x0 + bar_width; - - sub_id = 0; - - i32 step_count[] = {45, 10, 10}; - real32 tops[] = {360.f, 100.f, 100.f}; - - y = rect.y0 + v_quarter_space; - for (i32 i = 0; i < 3; ++i){ - ++sub_id; - slider.y0 = y; - slider.y1 = slider.y0 + v_half_space; - do_single_slider(sub_id, ui, i, 0, step_count[i], tops[i], slider, v_handle, rect); - y += v_full_space; - } - } -} - -enum Channel_Field_Type{ - CF_DEC, - CF_HEX -}; - -internal void -fill_buffer_color_channel(char *buffer, u8 x, Channel_Field_Type ftype){ - if (ftype == CF_DEC){ - u8 x0; - x0 = x / 10; - buffer[2] = (x - (10*x0)) + '0'; - x = x0; - x0 = x / 10; - buffer[1] = (x - (10*x0)) + '0'; - x = x0; - x0 = x / 10; - buffer[0] = (x - (10*x0)) + '0'; - } - else{ - u8 n; - n = x & 0xF; - buffer[1] = int_to_hexchar(n); - x >>= 4; - n = x & 0xF; - buffer[0] = int_to_hexchar(n); - } -} - -internal b32 -do_channel_field(i32 sub_id, Color_UI *ui, u8 *channel, Channel_Field_Type ftype, - i32 y, u32 color, u32 back, i32 x0, i32 x1){ - b32 result = 0; - - i16 font_id = ui->state.font_id; - i32 line_height = get_font_info(ui->state.font_set, font_id)->height; - i32_Rect hit_region; - hit_region.x0 = x0; - hit_region.x1 = x1; - hit_region.y0 = y; - hit_region.y1 = y + line_height; - - i32 digit_count; - if (ftype == CF_DEC) digit_count = 3; - else digit_count = 2; - - Render_Target *target = ui->state.target; - - if (ui->state.input_stage){ - i32 indx; - ui_do_subdivided_button_input(&ui->state, hit_region, digit_count, - make_sub1(&ui->state, sub_id), 1, &indx); - } - else{ - if (ui->state.hover.sub_id1 == sub_id && ui->state.selected.sub_id1 != sub_id){ - draw_rectangle(target, hit_region, back); - } - } - - char string_buffer[4]; - string_buffer[digit_count] = 0; - fill_buffer_color_channel(string_buffer, *channel, ftype); - - if (ui->state.selected.sub_id1 == sub_id){ - i32 indx = ui->state.selected.sub_id2; - if (ui->state.input_stage){ - Key_Summary *keys = ui->state.keys; - for (i32 key_i = 0; key_i < keys->count; ++key_i){ - Key_Event_Data key = get_single_key(keys, key_i); - - if (key.keycode == key_right){ - ++indx; - if (indx > digit_count-1) indx = 0; - } - if (key.keycode == key_left){ - --indx; - if (indx < 0) indx = digit_count-1; - } - - i32 new_value = *channel; - if (key.keycode == key_up || key.keycode == key_down){ - i32 place = digit_count-1-indx; - i32 base = (ftype == CF_DEC)?10:0x10; - i32 step_amount = 1; - while (place > 0){ - step_amount *= base; - --place; - } - if (key.keycode == key_down){ - step_amount = 0 - step_amount; - } - new_value += step_amount; - } - - u8 c = (u8)key.character; - bool32 is_good = (ftype == CF_DEC)?char_is_numeric(c):char_is_hex(c); - if (is_good){ - string_buffer[indx] = c; - if (ftype == CF_DEC) - new_value = str_to_int(make_string(string_buffer, 3)); - else - new_value = hexstr_to_int(make_string(string_buffer, 2)); - ++indx; - if (indx > digit_count-1) indx = 0; - } - - if (c == '\n'){ - switch (sub_id){ - case 1: case 2: - case 4: case 5: - ui->state.sub_id1_change = sub_id + 3; break; - - case 7: case 8: - ui->state.sub_id1_change = sub_id - 6; break; - } - } - - if (new_value != *channel){ - if (new_value > 255){ - *channel = 255; - } - else if (new_value < 0){ - *channel = 0; - } - else{ - *channel = (u8)new_value; - } - fill_buffer_color_channel(string_buffer, *channel, ftype); - result = 1; - } - ui->state.selected.sub_id2 = indx; - } - } - else{ - f32_Rect r = f32R(hit_region); - r.x0 += indx*ui->hex_advance+1; - r.x1 = r.x0+ui->hex_advance+1; - draw_rectangle(target, r, back); - } - } - - if (!ui->state.input_stage) - draw_string_mono(target, font_id, string_buffer, - (real32)x0 + 1, (real32)y, ui->hex_advance, - color); - - return result; -} - -internal void -do_rgb_sliders(Color_UI *ui, i32_Rect rect){ - i32 dec_x0, dec_x1; - dec_x0 = rect.x0 + 10; - dec_x1 = TRUNC32(dec_x0 + ui->hex_advance*3 + 2); - - i32 hex_x0, hex_x1; - hex_x0 = dec_x1 + 10; - hex_x1 = TRUNC32(hex_x0 + ui->hex_advance*2 + 2); - - rect.x0 = hex_x1; - real32 bar_width = (real32)(rect.x1 - rect.x0 - 20); - - f32_Rect slider; - f32 y; - i32 sub_id; - u8 channel; - - real32 v_full_space = 30.f; - real32 v_half_space = 15.f; - real32 v_quarter_space = 12.f; - real32 v_handle = 9.f; - - u32 packed_color = *ui->color.out; - - y = rect.y0 + v_quarter_space; - slider.x0 = rect.x0 + 10.f; - slider.x1 = slider.x0 + bar_width; - - sub_id = 0; - - persist i32 shifts[3] = { 16, 8, 0 }; - persist u32 fore_colors[3] = { 0xFFFF0000, 0xFF00FF00, 0xFF1919FF }; - persist u32 back_colors[3] = { 0xFF222222, 0xFF222222, 0xFF131313 }; - - for (i32 i = 0; i < 3; ++i){ - i32 shift = shifts[i]; - u32 fore = fore_colors[i]; - u32 back = back_colors[i]; - - ++sub_id; - channel = (packed_color >> shift) & 0xFF; - if (do_channel_field(sub_id, ui, &channel, CF_DEC, - (i32)y, fore, back, dec_x0, dec_x1)) - super_color_post_byte(&ui->color, i, channel); - - ++sub_id; - channel = (packed_color >> shift) & 0xFF; - if (do_channel_field(sub_id, ui, &channel, CF_HEX, - (i32)y, fore, back, hex_x0, hex_x1)) - super_color_post_byte(&ui->color, i, channel); - - ++sub_id; - slider.y0 = y; - slider.y1 = slider.y0 + v_half_space; - if (bar_width > 45.f) - do_single_slider(sub_id, ui, i, 1, 10, 100.f, slider, v_handle, rect); - y += v_full_space; - } -} - -struct Blob_Layout{ - i32_Rect rect; - i32 x, y; - i32 size, space; -}; - -internal void -begin_layout(Blob_Layout *layout, i32_Rect rect){ - layout->rect = rect; - layout->x = rect.x0 + 10; - layout->y = rect.y0; - layout->size = 20; - layout->space = 5; -} - -internal void -do_blob(Color_UI *ui, Blob_Layout *layout, u32 color, bool32 *set_me, i32 sub_id){ - i32_Rect rect = layout->rect; - f32_Rect blob; - blob.x0 = (real32)layout->x; - blob.y0 = (real32)layout->y; - blob.x1 = blob.x0 + layout->size; - blob.y1 = blob.y0 + layout->size; - - layout->y += layout->size + layout->space; - if (layout->y + layout->size + layout->space*2 > rect.y1){ - layout->y = rect.y0; - layout->x += layout->size + layout->space; - } - - if (ui->state.input_stage){ - bool32 right = 0; - if (ui_do_button_input(&ui->state, i32R(blob), make_sub1(&ui->state, sub_id), 0, &right)){ - super_color_post_packed(&ui->color, color); - } - else if (right) *set_me = 1; - } - else{ - Render_Target *target = ui->state.target; - draw_rectangle(target, blob, color); - persist u32 silver = 0xFFa0a0a0; - draw_rectangle_outline(target, blob, silver); - } -} - -inline void -do_blob(Color_UI *ui, Blob_Layout *layout, u32 *color, bool32 *set_me){ - i32 sub_id = (i32)((char*)color - (char*)ui->state.style); - do_blob(ui, layout, *color, set_me, sub_id); -} - -internal void -do_v_divide(Color_UI *ui, Blob_Layout *layout, i32 width){ - i32_Rect rect = layout->rect; - if (layout->y > rect.y0){ - layout->x += layout->size + layout->space; - } - layout->x += width; - layout->y = rect.y0; -} - -internal void -do_palette(Color_UI *ui, i32_Rect rect){ - Style *style = ui->state.style; - Blob_Layout layout; - begin_layout(&layout, rect); - bool32 set_me; - - do_blob(ui, &layout, &style->main.back_color, &set_me); - do_blob(ui, &layout, &style->main.margin_color, &set_me); - do_blob(ui, &layout, &style->main.margin_active_color, &set_me); - - do_blob(ui, &layout, &style->main.cursor_color, &set_me); - do_blob(ui, &layout, &style->main.at_cursor_color, &set_me); - do_blob(ui, &layout, &style->main.mark_color, &set_me); - - do_blob(ui, &layout, &style->main.highlight_color, &set_me); - do_blob(ui, &layout, &style->main.at_highlight_color, &set_me); - - do_blob(ui, &layout, &style->main.default_color, &set_me); - do_blob(ui, &layout, &style->main.comment_color, &set_me); - do_blob(ui, &layout, &style->main.keyword_color, &set_me); - do_blob(ui, &layout, &style->main.str_constant_color, &set_me); - do_blob(ui, &layout, &style->main.char_constant_color, &set_me); - do_blob(ui, &layout, &style->main.int_constant_color, &set_me); - do_blob(ui, &layout, &style->main.float_constant_color, &set_me); - do_blob(ui, &layout, &style->main.bool_constant_color, &set_me); - do_blob(ui, &layout, &style->main.include_color, &set_me); - do_blob(ui, &layout, &style->main.preproc_color, &set_me); - do_blob(ui, &layout, &style->main.special_character_color, &set_me); - - do_blob(ui, &layout, &style->main.highlight_junk_color, &set_me); - do_blob(ui, &layout, &style->main.highlight_white_color, &set_me); - - do_blob(ui, &layout, &style->main.paste_color, &set_me); - - do_blob(ui, &layout, &style->main.file_info_style.bar_color, &set_me); - do_blob(ui, &layout, &style->main.file_info_style.base_color, &set_me); - do_blob(ui, &layout, &style->main.file_info_style.pop1_color, &set_me); - do_blob(ui, &layout, &style->main.file_info_style.pop2_color, &set_me); - - do_v_divide(ui, &layout, 20); - - if (!ui->state.input_stage){ - Render_Target *target = ui->state.target; - draw_string(target, style->font_id, "Global Palette: right click to save color", - layout.x, layout.rect.y0, style->main.default_color); - } - - layout.rect.y0 += layout.size + layout.space; - layout.y = layout.rect.y0; - i32 palette_size = ui->palette_size + 1000; - u32 *color = ui->palette; - for (i32 i = 1000; i < palette_size; ++i, ++color){ - set_me = 0; - do_blob(ui, &layout, *color, &set_me, i); - if (set_me){ - *color = *ui->color.out; - ui->state.redraw = 1; - } - } -} - -internal void -do_sub_button(i32 id, Color_UI *ui, char *text){ - i16 font_id = ui->state.font_id; - i32 line_height = get_font_info(ui->state.font_set, font_id)->height; - i32_Rect rect = layout_rect(&ui->layout, line_height + 2); - - if (ui->state.input_stage){ - ui_do_button_input(&ui->state, rect, make_sub0(&ui->state, id), 1); - } - else{ - Render_Target *target = ui->state.target; - - u32 back_color, text_color; - text_color = 0xFFDDDDDD; - if (ui->state.selected.sub_id0 == id){ - back_color = 0xFF444444; - } - else if (ui->state.hover.sub_id0 == id){ - back_color = 0xFF222222; - } - else{ - back_color = 0xFF111111; - } - - draw_rectangle(target, rect, back_color); - draw_string(target, font_id, text, rect.x0, rect.y0 + 1, - text_color); - } -} - -internal void -do_color_adjuster(Color_UI *ui, u32 *color, - u32 text_color, u32 back_color, char *name){ - i32 id = raw_ptr_dif(color, ui->state.style); - i16 font_id = ui->state.font_id; - i32 character_h = get_font_info(ui->state.font_set, font_id)->height; - u32 text = 0, back = 0; - - i32_Rect bar = layout_rect(&ui->layout, character_h); - - if (ui->state.input_stage){ - if (ui_do_button_input(&ui->state, bar, make_id(&ui->state, id), 1)){ - ui->has_hover_color = 1; - ui->hover_color = super_color_create(*color); - } - } - - else{ - Render_Target *target = ui->state.target; - u32 text_hover = 0xFF101010; - u32 back_hover = 0xFF999999; - if (ui->state.selected.id != id && ui->state.hover.id == id){ - text = text_hover; - back = back_hover; - } - else{ - text = text_color; - back = back_color; - } - - draw_rectangle(target, bar, back); - i32 end_pos = draw_string(target, font_id, name, bar.x0, bar.y0, text); - - real32 x_spacing = ui->hex_advance; - i32_Rect temp_rect = bar; - temp_rect.x0 = temp_rect.x1 - CEIL32(x_spacing * 9.f); - if (temp_rect.x0 >= end_pos + x_spacing){ - u32 n = *color; - char full_hex_string[] = "0x000000"; - for (i32 i = 7; i >= 2; --i){ - i32 m = (n & 0xF); - n >>= 4; - full_hex_string[i] = int_to_hexchar(m); - } - draw_string_mono(target, font_id, full_hex_string, - (f32)temp_rect.x0, (f32)bar.y0, - x_spacing, text); - } - - for (i32 i = 0; i < ArrayCount(ui->highlight.ids); ++i){ - if (ui->highlight.ids[i] == id){ - draw_rectangle_outline(target, f32R(bar), text_color); - break; - } - } - } - - if (ui->state.selected.id == id){ - Render_Target *target = ui->state.target; - i32_Rect expanded = layout_rect(&ui->layout, 115 + (character_h + 2)); - UI_Layout_Restore restore = begin_sub_layout(&ui->layout, expanded); - - ui->color.out = color; - - if (ui->state.input_stage){ - if (ui->state.selected.sub_id0 == 0){ - ui->state.selected.sub_id0 = 1; - } - } - else{ - draw_rectangle(target, expanded, 0xff000000); - } - - begin_row(&ui->layout, 3); - do_sub_button(1, ui, "HSL"); - do_sub_button(2, ui, "RGB"); - do_sub_button(3, ui, "Palette"); - - i32_Rect sub_rect; - sub_rect = expanded; - sub_rect.y0 += 10 + character_h; - - switch (ui->state.selected.sub_id0){ - case 1: do_hsl_sliders(ui, sub_rect); break; - case 2: do_rgb_sliders(ui, sub_rect); break; - case 3: do_palette(ui, sub_rect); break; - } - - end_sub_layout(restore); - } -} - -internal void -do_style_name(Color_UI *ui){ - i32 id = -3; - - i16 font_id = ui->state.font_id; - i32 line_height = get_font_info(ui->state.font_set, font_id)->height; - - i32_Rect srect = layout_rect(&ui->layout, line_height); - - Widget_ID wid = make_id(&ui->state, id); - b32 selected = is_selected(&ui->state, wid); - - if (ui->state.input_stage){ - if (!selected){ - ui_do_button_input(&ui->state, srect, wid, 1); - } - else{ - Style *style = ui->state.style; - if (ui_do_text_field_input(&ui->state, &style->name)){ - ui->state.selected = {}; - } - } - } - else{ - Render_Target *target = ui->state.target; - Style *style = ui->state.style; - u32 back, fore_text, fore_label; - if (selected){ - back = 0xFF000000; - fore_label = 0xFF808080; - fore_text = 0xFFFFFFFF; - } - else if (is_hover(&ui->state, wid)){ - back = 0xFF999999; - fore_text = fore_label = 0xFF101010; - } - else{ - back = style->main.back_color; - fore_text = fore_label = style->main.default_color; - } - - draw_rectangle(target, srect, back); - i32 x = srect.x0; - x = draw_string(target, font_id, "NAME: ", - x, srect.y0, fore_label); - x = draw_string(target, font_id, style->name.str, - x, srect.y0, fore_text); - } -} - -internal b32 -do_font_option(Color_UI *ui, i16 font_id){ - b32 result = 0; - Font_Info *info = get_font_info(ui->state.font_set, font_id); - - i32 sub_id = (i32)(i64)(info); - i32_Rect orect = layout_rect(&ui->layout, info->height); - - Widget_ID wid = make_sub0(&ui->state, sub_id); - if (ui->state.input_stage){ - if (ui_do_button_input(&ui->state, orect, wid, 0)){ - result = 1; - } - } - else{ - Render_Target *target = ui->state.target; - u32 back, fore; - if (is_hover(&ui->state, wid)){ - back = 0xFF999999; - fore = 0xFF101010; - } - else{ - back = 0xFF000000; - fore = 0xFFFFFFFF; - } - draw_rectangle(target, orect, back); - i32 x = orect.x0; - x = draw_string(target, font_id, "->", x, orect.y0, fore); - draw_string(target, font_id, info->name.str, x, orect.y0, fore); - } - - return result; -} - -internal void -do_font_switch(Color_UI *ui){ - i32 id = -2; - Render_Target *target = ui->state.target; - Font_Set *font_set = ui->state.font_set; - - i16 font_id = ui->state.font_id; - Font_Info *info = get_font_info(font_set, font_id); - i32 character_h = info->height; - - i32_Rect srect = layout_rect(&ui->layout, character_h); - Widget_ID wid = make_id(&ui->state, id); - - if (ui->state.input_stage){ - ui_do_button_input(&ui->state, srect, wid, 1); - } - else{ - Style *style = ui->state.style; - u32 back, fore; - if (is_hover(&ui->state, wid) && !is_selected(&ui->state, wid)){ - back = 0xFF999999; - fore = 0xFF101010; - } - else{ - back = style->main.back_color; - fore = style->main.default_color; - } - draw_rectangle(target, srect, back); - i32 x = srect.x0; - x = draw_string(target, font_id, "FONT: ", - x, srect.y0, fore); - x = draw_string(target, font_id, info->name.str, - x, srect.y0, fore); - } - - if (is_selected(&ui->state, wid)){ - srect = layout_rect(&ui->layout, character_h/2); - if (!ui->state.input_stage) - draw_rectangle(target, srect, 0xFF000000); - - i32 count = font_set->count + 1; - - for (i16 i = 1; i < count; ++i){ - if (i == font_id) continue; - if (do_font_option(ui, i)){ - ui->state.style->font_id = i; - ui->state.style->font_changed = 1; - } - } - - srect = layout_rect(&ui->layout, character_h/2); - if (!ui->state.input_stage) - draw_rectangle(target, srect, 0xFF000000); - } -} - -internal i32 -step_draw_adjusting(Color_View *color_view, i32_Rect rect, View_Message message, - Render_Target *target, Input_Summary *user_input){ - Style *style = color_view->main_style; - i32 result = 0; - - if (message != VMSG_DRAW && message != VMSG_STEP) return result; - - Color_UI ui; - ui.state = ui_state_init(&color_view->state, target, user_input, - style, color_view->font_set, color_view->working_set, - (message == VMSG_STEP)); - - begin_layout(&ui.layout, rect); - - ui.fonts = color_view->font_set; - ui.highlight = color_view->highlight; - ui.color = color_view->color; - ui.has_hover_color = 0; - ui.state.sub_id1_change = 0; - ui.hex_advance = font_get_max_width(ui.fonts, ui.state.font_id, "0123456789abcdefx"); - ui.palette = color_view->palette; - ui.palette_size = color_view->palette_size; - - i32_Rect bar_rect = ui.layout.rect; - bar_rect.x0 = bar_rect.x1 - 20; - do_scroll_bar(&ui.state, bar_rect); - - ui.layout.y -= FLOOR32(color_view->state.view_y); - ui.layout.rect.x1 -= 20; - - if (!ui.state.input_stage) draw_push_clip(target, ui.layout.rect); - if (do_button(-1, &ui.state, &ui.layout, "Back to Library", 2)){ - color_view->mode = CV_MODE_LIBRARY; - ui.state.view_y = 0; - } - - do_style_name(&ui); - do_font_switch(&ui); - - do_color_adjuster(&ui, &style->main.back_color, - style->main.default_color, style->main.back_color, - "Background"); - do_color_adjuster(&ui, &style->main.margin_color, - style->main.default_color, style->main.margin_color, - "Margin"); - do_color_adjuster(&ui, &style->main.margin_hover_color, - style->main.default_color, style->main.margin_hover_color, - "Margin Hover"); - do_color_adjuster(&ui, &style->main.margin_active_color, - style->main.default_color, style->main.margin_active_color, - "Margin Active"); - - do_color_adjuster(&ui, &style->main.cursor_color, - style->main.at_cursor_color, style->main.cursor_color, - "Cursor"); - do_color_adjuster(&ui, &style->main.at_cursor_color, - style->main.at_cursor_color, style->main.cursor_color, - "Text At Cursor"); - do_color_adjuster(&ui, &style->main.mark_color, - style->main.mark_color, style->main.back_color, - "Mark"); - - do_color_adjuster(&ui, &style->main.highlight_color, - style->main.at_highlight_color, style->main.highlight_color, - "Highlight"); - do_color_adjuster(&ui, &style->main.at_highlight_color, - style->main.at_highlight_color, style->main.highlight_color, - "Text At Highlight"); - - do_color_adjuster(&ui, &style->main.default_color, - style->main.default_color, style->main.back_color, - "Text Default"); - do_color_adjuster(&ui, &style->main.comment_color, - style->main.comment_color, style->main.back_color, - "Comment"); - do_color_adjuster(&ui, &style->main.keyword_color, - style->main.keyword_color, style->main.back_color, - "Keyword"); - do_color_adjuster(&ui, &style->main.str_constant_color, - style->main.str_constant_color, style->main.back_color, - "String Constant"); - do_color_adjuster(&ui, &style->main.char_constant_color, - style->main.char_constant_color, style->main.back_color, - "Character Constant"); - do_color_adjuster(&ui, &style->main.int_constant_color, - style->main.int_constant_color, style->main.back_color, - "Integer Constant"); - do_color_adjuster(&ui, &style->main.float_constant_color, - style->main.float_constant_color, style->main.back_color, - "Float Constant"); - do_color_adjuster(&ui, &style->main.bool_constant_color, - style->main.bool_constant_color, style->main.back_color, - "Boolean Constant"); - do_color_adjuster(&ui, &style->main.preproc_color, - style->main.preproc_color, style->main.back_color, - "Preprocessor"); - do_color_adjuster(&ui, &style->main.include_color, - style->main.include_color, style->main.back_color, - "Include Constant"); - do_color_adjuster(&ui, &style->main.special_character_color, - style->main.special_character_color, style->main.back_color, - "Special Character"); - - do_color_adjuster(&ui, &style->main.highlight_junk_color, - style->main.default_color, style->main.highlight_junk_color, - "Junk Highlight"); - do_color_adjuster(&ui, &style->main.highlight_white_color, - style->main.default_color, style->main.highlight_white_color, - "Whitespace Highlight"); - - do_color_adjuster(&ui, &style->main.paste_color, - style->main.paste_color, style->main.back_color, - "Paste Color"); - - Interactive_Style *bar_style = &style->main.file_info_style; - do_color_adjuster(&ui, &bar_style->bar_color, - bar_style->base_color, bar_style->bar_color, - "Bar"); - do_color_adjuster(&ui, &bar_style->base_color, - bar_style->base_color, bar_style->bar_color, - "Bar Text"); - do_color_adjuster(&ui, &bar_style->pop1_color, - bar_style->pop1_color, bar_style->bar_color, - "Bar Pop 1"); - do_color_adjuster(&ui, &bar_style->pop2_color, - bar_style->pop2_color, bar_style->bar_color, - "Bar Pop 2"); - - i32 did_activation = 0; - if (ui_finish_frame(&color_view->state, &ui.state, &ui.layout, rect, 1, &did_activation)){ - result = 1; - } - if (did_activation){ - if (ui.has_hover_color){ - ui.color = ui.hover_color; - } - } - if (!ui.state.input_stage) draw_pop_clip(target); - color_view->color = ui.color; - - return result; -} - -internal void -update_highlighting(Color_View *color_view){ - File_View *file_view = color_view->hot_file_view; - if (!file_view){ - color_view->highlight = {}; - return; - } - -#if BUFFER_EXPERIMENT_SCALPEL <= 0 - Style *style = color_view->main_style; - Editing_File *file = file_view->file; - i32 pos = view_get_cursor_pos(file_view); - char c = file->state.buffer.data[pos]; - - if (c == '\r'){ - color_view->highlight.ids[0] = - raw_ptr_dif(&style->main.special_character_color, style); - } - - else if (file->state.tokens_complete){ - Cpp_Token_Stack *tokens = &file->state.token_stack; - Cpp_Get_Token_Result result = cpp_get_token(tokens, pos); - Cpp_Token token = tokens->tokens[result.token_index]; - if (!result.in_whitespace){ - u32 *color = style_get_color(style, token); - color_view->highlight.ids[0] = raw_ptr_dif(color, style); - if (token.type == CPP_TOKEN_JUNK){ - color_view->highlight.ids[1] = - raw_ptr_dif(&style->main.highlight_junk_color, style); - } - else if (char_is_whitespace(c)){ - color_view->highlight.ids[1] = - raw_ptr_dif(&style->main.highlight_white_color, style); - } - else{ - color_view->highlight.ids[1] = 0; - } - } - else{ - color_view->highlight.ids[0] = 0; - color_view->highlight.ids[1] = - raw_ptr_dif(&style->main.highlight_white_color, style); - } - } - - else{ - if (char_is_whitespace(c)){ - color_view->highlight.ids[0] = 0; - color_view->highlight.ids[1] = - raw_ptr_dif(&style->main.highlight_white_color, style); - } - else{ - color_view->highlight.ids[0] = - raw_ptr_dif(&style->main.default_color, style); - color_view->highlight.ids[1] = 0; - } - } - - if (file_view->show_temp_highlight){ - color_view->highlight.ids[2] = - raw_ptr_dif(&style->main.highlight_color, style); - color_view->highlight.ids[3] = - raw_ptr_dif(&style->main.at_highlight_color, style); - } - else if (file->state.paste_effect.tick_down > 0){ - color_view->highlight.ids[2] = - raw_ptr_dif(&style->main.paste_color, style); - color_view->highlight.ids[3] = 0; - } - else{ - color_view->highlight.ids[2] = 0; - color_view->highlight.ids[3] = 0; - } -#endif -} - -internal b32 -do_style_preview(Library_UI *ui, Style *style, i32 toggle = -1){ - b32 result = 0; - i32 id; - if (style == ui->state.style) id = 2; - else id = raw_ptr_dif(style, ui->styles->styles) + 100; - - i16 font_id = style->font_id; - Font_Info *info = get_font_info(ui->state.font_set, font_id); - - i32_Rect prect = layout_rect(&ui->layout, info->height*3 + 6); - - Widget_ID wid = make_id(&ui->state, id); - - if (ui->state.input_stage){ - if (ui_do_button_input(&ui->state, prect, wid, 0)){ - result = 1; - } - } - else{ - Render_Target *target = ui->state.target; - u32 margin_color = style->main.margin_color; - if (is_hover(&ui->state, wid)){ - margin_color = style->main.margin_active_color; - } - - i32_Rect inner; - if (toggle != -1){ - i32_Rect toggle_box = prect; - toggle_box.x1 = toggle_box.x0 + info->height*2 + 6; - prect.x0 = toggle_box.x1; - - inner = get_inner_rect(toggle_box, 3); - draw_margin(target, toggle_box, inner, margin_color); - draw_rectangle(target, inner, style->main.back_color); - - i32 d; - d = info->height/2; - i32_Rect b; - b.x0 = (inner.x1 + inner.x0)/2 - d; - b.y0 = (inner.y1 + inner.y0)/2 - d; - b.x1 = b.x0 + info->height; - b.y1 = b.y0 + info->height; - if (toggle) draw_rectangle(target, b, margin_color); - else draw_rectangle_outline(target, b, margin_color); - } - - inner = get_inner_rect(prect, 3); - draw_margin(target, prect, inner, margin_color); - draw_rectangle(target, inner, style->main.back_color); - - i32 text_y = inner.y0; - i32 text_x = inner.x0; - text_x = draw_string(target, font_id, style->name.str, - text_x, text_y, style->main.default_color); - i32 font_x = (i32)(inner.x1 - font_string_width(target, font_id, info->name.str)); - if (font_x > text_x + 10) - draw_string(target, font_id, info->name.str, - font_x, text_y, style->main.default_color); - - text_x = inner.x0; - text_y += info->height; - text_x = draw_string(target, font_id, "if ", text_x, text_y, - style->main.keyword_color); - text_x = draw_string(target, font_id, "(x < ", text_x, text_y, - style->main.default_color); - text_x = draw_string(target, font_id, "0", text_x, text_y, - style->main.int_constant_color); - text_x = draw_string(target, font_id, ") { x = ", text_x, text_y, - style->main.default_color); - text_x = draw_string(target, font_id, "0", text_x, text_y, - style->main.int_constant_color); - text_x = draw_string(target, font_id, "; } ", text_x, text_y, - style->main.default_color); - text_x = draw_string(target, font_id, "// comment", text_x, text_y, - style->main.comment_color); - - text_x = inner.x0; - text_y += info->height; - text_x = draw_string(target, font_id, "[] () {}; * -> +-/ <>= ! && || % ^", - text_x, text_y, style->main.default_color); - } - - ui->layout.y = prect.y1; - return result; -} - -internal b32 -do_main_file_box(System_Functions *system, UI_State *state, UI_Layout *layout, - Hot_Directory *hot_directory, b32 try_to_match, b32 case_sensitive, char *end){ - b32 result = 0; - Style *style = state->style; - String *string = &hot_directory->string; - - i16 font_id = style->font_id; - i32 line_height = get_font_info(state->font_set, font_id)->height; - i32_Rect box = layout_rect(layout, line_height + 2); - - if (state->input_stage){ - if (ui_do_file_field_input(system, state, hot_directory, try_to_match, case_sensitive)){ - result = 1; - } - } - else{ - Render_Target *target = state->target; - u32 back = style->main.margin_color; - u32 fore = style->main.default_color; - u32 special = style->main.special_character_color; - draw_rectangle(target, box, back); - i32 x = box.x0; - x = draw_string(target, font_id, string->str, x, box.y0, fore); - if (end) draw_string(target, font_id, end, x, box.y0, special); - } - - layout->y = box.y1; - return result; -} - -internal b32 -do_main_string_box(System_Functions *system, UI_State *state, UI_Layout *layout, String *string){ - b32 result = 0; - Style *style = state->style; - - i16 font_id = style->font_id; - i32 line_height = get_font_info(state->font_set, font_id)->height; - i32_Rect box = layout_rect(layout, line_height + 2); - - if (state->input_stage){ - if (ui_do_line_field_input(system, state, string)){ - result = 1; - } - } - else{ - Render_Target *target = state->target; - u32 back = style->main.margin_color; - u32 fore = style->main.default_color; - draw_rectangle(target, box, back); - i32 x = box.x0; - x = draw_string(target, font_id, string->str, x, box.y0, fore); - } - - layout->y = box.y1; - return result; -} - -internal b32 -do_list_option(i32 id, UI_State *state, UI_Layout *layout, String text){ - b32 result = 0; - Style *style = state->style; - - i16 font_id = style->font_id; - i32 character_h = get_font_info(state->font_set, font_id)->height; - - i32_Rect box = layout_rect(layout, character_h*2); - Widget_ID wid = make_id(state, id); - - if (state->input_stage){ - if (ui_do_button_input(state, box, wid, 0)){ - result = 1; - } - } - else{ - Render_Target *target = state->target; - i32_Rect inner = get_inner_rect(box, 3); - u32 back, outline, fore, pop; - back = style->main.back_color; - fore = style->main.default_color; - pop = style->main.file_info_style.pop2_color; - if (is_hover(state, wid)) outline = style->main.margin_active_color; - else outline = style->main.margin_color; - - draw_rectangle(target, inner, back); - i32 x = inner.x0, y = box.y0 + character_h/2; - x = draw_string(target, font_id, text, x, y, fore); - draw_margin(target, box, inner, outline); - } - - layout->y = box.y1; - return result; -} - -internal b32 -do_checkbox_list_option(i32 id, UI_State *state, UI_Layout *layout, String text, b32 is_on){ - b32 result = 0; - Style *style = state->style; - - i16 font_id = style->font_id; - i32 character_h = get_font_info(state->font_set, font_id)->height; - - i32_Rect box = layout_rect(layout, character_h*2); - Widget_ID wid = make_id(state, id); - - if (state->input_stage){ - if (ui_do_button_input(state, box, wid, 0)){ - result = 1; - } - } - else{ - Render_Target *target = state->target; - i32_Rect inner = get_inner_rect(box, 3); - u32 back, outline, fore, pop, box_color; - back = style->main.back_color; - fore = style->main.default_color; - pop = style->main.file_info_style.pop2_color; - if (is_hover(state, wid)) outline = style->main.margin_active_color; - else outline = style->main.margin_color; - box_color = style->main.margin_active_color; - - draw_rectangle(target, inner, back); - - i32_Rect square; - square = get_inner_rect(inner, character_h/3); - square.x1 = square.x0 + (square.y1 - square.y0); - if (is_on) draw_rectangle(target, square, box_color); - else draw_margin(target, square, 1, box_color); - - i32 x = square.x1 + 3; - i32 y = box.y0 + character_h/2; - x = draw_string(target, font_id, text, x, y, fore); - draw_margin(target, box, inner, outline); - } - - layout->y = box.y1; - return result; -} - - -internal b32 -do_file_option(i32 id, UI_State *state, UI_Layout *layout, String filename, b32 is_folder, String extra, char slash){ - b32 result = 0; - Style *style = state->style; - i16 font_id = style->font_id; - i32 character_h = get_font_info(state->font_set, font_id)->height; - char slash_buf[2] = { slash, 0 }; - - i32_Rect box = layout_rect(layout, character_h*2); - Widget_ID wid = make_id(state, id); - - if (state->input_stage){ - if (ui_do_button_input(state, box, wid, 0)){ - result = 1; - } - } - else{ - Render_Target *target = state->target; - i32_Rect inner = get_inner_rect(box, 3); - u32 back, outline, fore, pop; - back = style->main.back_color; - fore = style->main.default_color; - pop = style->main.file_info_style.pop2_color; - if (is_hover(state, wid)) outline = style->main.margin_active_color; - else outline = style->main.margin_color; - - draw_rectangle(target, inner, back); - i32 x = inner.x0, y = box.y0 + character_h/2; - x = draw_string(target, font_id, filename, x, y, fore); - if (is_folder) x = draw_string(target, font_id, slash_buf, x, y, fore); - draw_string(target, font_id, extra, x, y, pop); - draw_margin(target, box, inner, outline); - } - - layout->y = box.y1; - return result; -} - -internal b32 -do_file_list_box(System_Functions *system, UI_State *state, UI_Layout *layout, - Hot_Directory *hot_dir, b32 has_filter, b32 try_to_match, b32 case_sensitive, - b32 *new_dir, b32 *selected, char *end){ - b32 result = 0; - File_List *files = &hot_dir->file_list; - - if (do_main_file_box(system, state, layout, hot_dir, try_to_match, case_sensitive, end)){ - *selected = 1; - terminate_with_null(&hot_dir->string); - } - else{ - persist String p4c_extension = make_lit_string("p4c"); - persist String message_loaded = make_lit_string(" LOADED"); - persist String message_unsaved = make_lit_string(" LOADED *"); - persist String message_unsynced = make_lit_string(" LOADED !"); - persist String message_nothing = {}; - - char front_name_space[256]; - String front_name = make_fixed_width_string(front_name_space); - get_front_of_directory(&front_name, hot_dir->string); - - Absolutes absolutes; - get_absolutes(front_name, &absolutes, 1, 1); - - char full_path_[256]; - String full_path = make_fixed_width_string(full_path_); - get_path_of_directory(&full_path, hot_dir->string); - i32 restore_size = full_path.size; - - i32 i; - File_Info *info, *end; - end = files->infos + files->count; - for (info = files->infos, i = 0; info != end; ++info, ++i){ - String filename = info->filename; - - append(&full_path, filename); - terminate_with_null(&full_path); - - Editing_File *file = working_set_contains(state->working_set, full_path); - full_path.size = restore_size; - - b8 is_folder = (info->folder != 0); - b8 ext_match = (match(file_extension(filename), p4c_extension) != 0); - b8 name_match = (filename_match(front_name, &absolutes, filename, case_sensitive) != 0); - b8 is_loaded = (file != 0 && file_is_ready(file)); - - String message = message_nothing; - if (is_loaded){ - switch (buffer_get_sync(file)){ - case SYNC_GOOD: message = message_loaded; break; - case SYNC_BEHIND_OS: message = message_unsynced; break; - case SYNC_UNSAVED: message = message_unsaved; break; - } - } - - if ((is_folder || !has_filter || ext_match) && name_match){ - if (do_file_option(100+i, state, layout, filename, is_folder, message, system->slash)){ - result = 1; - hot_directory_clean_end(hot_dir); - append(&hot_dir->string, filename); - if (is_folder){ - *new_dir = 1; - append(&hot_dir->string, system->slash); - } - else{ - *selected = 1; - } - terminate_with_null(&hot_dir->string); - } - } - } - } - - return result; -} - -internal b32 -do_live_file_list_box(System_Functions *system, UI_State *state, UI_Layout *layout, - Working_Set *working_set, String *string, b32 *selected){ - b32 result = 0; - - if (do_main_string_box(system, state, layout, string)){ - *selected = 1; - terminate_with_null(string); - } - else{ - persist String message_unsaved = make_lit_string(" *"); - persist String message_unsynced = make_lit_string(" !"); - persist String message_nothing = {}; - - Absolutes absolutes; - get_absolutes(*string, &absolutes, 1, 1); - - i32 count = working_set->file_index_count; - Editing_File *files = working_set->files; - for (i32 i = 0; i < count; ++i){ - Editing_File *file = files + i; - - if (!file->state.is_dummy){ - String message = message_nothing; - switch (buffer_get_sync(file)){ - case SYNC_BEHIND_OS: message = message_unsynced; break; - case SYNC_UNSAVED: message = message_unsaved; break; - } - - if (filename_match(*string, &absolutes, file->name.live_name, 1)){ - if (do_file_option(100+i, state, layout, file->name.live_name, 0, message, system->slash)){ - result = 1; - *selected = 1; - copy(string, file->name.source_path); - terminate_with_null(string); - } - } - } - } - } - - return result; -} - -internal i32 -step_draw_library(System_Functions *system, Exchange *exchange, Mem_Options *mem, - Color_View *color_view, i32_Rect rect, View_Message message, - Render_Target *target, Input_Summary *user_input){ - i32 result = 0; - - Library_UI ui; - ui.state = ui_state_init(&color_view->state, target, user_input, - color_view->main_style, color_view->font_set, - color_view->working_set, (message == VMSG_STEP)); - - ui.fonts = color_view->font_set; - ui.hot_directory = color_view->hot_directory; - ui.styles = color_view->styles; - - begin_layout(&ui.layout, rect); - - Color_View_Mode mode = color_view->mode; - - i32_Rect bar_rect = ui.layout.rect; - bar_rect.x0 = bar_rect.x1 - 20; - do_scroll_bar(&ui.state, bar_rect); - - ui.layout.y -= FLOOR32(color_view->state.view_y); - ui.layout.rect.x1 -= 20; - - b32 case_sensitive = 0; - - if (!ui.state.input_stage) draw_push_clip(ui.state.target, ui.layout.rect); - switch (mode){ - case CV_MODE_LIBRARY: - { - do_label(&ui.state, &ui.layout, literal("Current Theme - Click to Edit")); - if (do_style_preview(&ui, color_view->main_style)){ - color_view->mode = CV_MODE_ADJUSTING; - color_view->state.selected = {}; - ui.state.view_y = 0; - result = 1; - } - - begin_row(&ui.layout, 3); - if (ui.state.style->name.size >= 1){ - if (do_button(-2, &ui.state, &ui.layout, "Save", 2)){ - style_library_add(ui.styles, ui.state.style); - } - } - else{ - do_button(-2, &ui.state, &ui.layout, "~Need's Name~", 2); - } - if (do_button(-3, &ui.state, &ui.layout, "Import", 2)){ - color_view->mode = CV_MODE_IMPORT_FILE; - hot_directory_clean_end(color_view->hot_directory); - hot_directory_reload(system, color_view->hot_directory, color_view->working_set); - } - if (do_button(-4, &ui.state, &ui.layout, "Export", 2)){ - color_view->mode = CV_MODE_EXPORT; - hot_directory_clean_end(color_view->hot_directory); - hot_directory_reload(system, color_view->hot_directory, color_view->working_set); - memset(color_view->import_export_check, 0, sizeof(color_view->import_export_check)); - } - - do_label(&ui.state, &ui.layout, literal("Theme Library - Click to Select")); - - i32 style_count = color_view->styles->count; - Style *style = color_view->styles->styles; - for (i32 i = 0; i < style_count; ++i, ++style){ - if (do_style_preview(&ui, style)){ - style_copy(color_view->main_style, style); - result = 1; - } - } - }break; - - case CV_MODE_IMPORT_FILE: - { - do_label(&ui.state, &ui.layout, literal("Current Theme")); - do_style_preview(&ui, color_view->main_style); - - b32 file_selected = 0; - - do_label(&ui.state, &ui.layout, literal("Import Which File?")); - begin_row(&ui.layout, 2); - if (do_button(-2, &ui.state, &ui.layout, "*.p4c only", 2, 1, color_view->p4c_only)){ - color_view->p4c_only = !color_view->p4c_only; - } - if (do_button(-3, &ui.state, &ui.layout, "Cancel", 2)){ - color_view->mode = CV_MODE_LIBRARY; - } - - b32 new_dir = 0; - if (do_file_list_box(system, &ui.state, &ui.layout, - ui.hot_directory, color_view->p4c_only, 1, case_sensitive, - &new_dir, &file_selected, 0)){ - result = 1; - } - - if (new_dir){ - hot_directory_reload(system, ui.hot_directory, ui.state.working_set); - } - if (file_selected){ - memset(&color_view->inspecting_styles, 0, sizeof(Style_Library)); - memset(color_view->import_export_check, 1, - sizeof(color_view->import_export_check)); - - color_view->import_file_id = - exchange_request_file(exchange, - color_view->hot_directory->string.str, - color_view->hot_directory->string.size); - color_view->mode = CV_MODE_IMPORT_WAIT; - - } - }break; - - case CV_MODE_IMPORT_WAIT: - { - Style *styles = color_view->inspecting_styles.styles; - Data file = {}; - i32 file_max = 0; - - i32 count = 0; - i32 max = ArrayCount(color_view->inspecting_styles.styles); - - AllowLocal(styles); - AllowLocal(max); - - if (exchange_file_ready(exchange, color_view->import_file_id, - &file.data, &file.size, &file_max)){ - if (file.data){ - if (0 /* && style_library_import(file, ui.fonts, styles, max, &count) */){ - color_view->mode = CV_MODE_IMPORT; - } - else{ - color_view->mode = CV_MODE_LIBRARY; - } - color_view->inspecting_styles.count = count; - } - else{ - Assert(!"this shouldn't happen!"); - } - - exchange_free_file(exchange, color_view->import_file_id); - } - }break; - - case CV_MODE_EXPORT_FILE: - { - do_label(&ui.state, &ui.layout, literal("Current Theme")); - do_style_preview(&ui, color_view->main_style); - - b32 file_selected = 0; - - do_label(&ui.state, &ui.layout, literal("Export File Name?")); - begin_row(&ui.layout, 2); - if (do_button(-2, &ui.state, &ui.layout, "Finish Export", 2)){ - file_selected = 1; - } - if (do_button(-3, &ui.state, &ui.layout, "Cancel", 2)){ - color_view->mode = CV_MODE_LIBRARY; - } - - b32 new_dir = 0; - if (do_file_list_box(system, &ui.state, &ui.layout, - ui.hot_directory, 1, 1, case_sensitive, - &new_dir, &file_selected, ".p4c")){ - result = 1; - } - - if (new_dir){ - hot_directory_reload(system, - ui.hot_directory, ui.state.working_set); - } - if (file_selected){ - i32 count = ui.styles->count; - Temp_Memory temp = begin_temp_memory(&mem->part); - Style **styles = push_array(&mem->part, Style*, sizeof(Style*)*count); - - Style *style = ui.styles->styles; - bool8 *export_check = color_view->import_export_check; - i32 export_count = 0; - for (i32 i = 0; i < count; ++i, ++style){ - if (export_check[i]){ - styles[export_count++] = style; - } - } - char *data = push_array(&mem->part, char, ui.hot_directory->string.size + 5); - String str = make_string(data, 0, ui.hot_directory->string.size + 5); - copy(&str, ui.hot_directory->string); - append(&str, make_lit_string(".p4c")); - /*style_library_export(system, exchange, mem, &target->font_set, str.str, styles, export_count);*/ - - end_temp_memory(temp); - color_view->mode = CV_MODE_LIBRARY; - } - }break; - - case CV_MODE_IMPORT: - { - do_label(&ui.state, &ui.layout, literal("Current Theme")); - do_style_preview(&ui, color_view->main_style); - - i32 style_count = color_view->inspecting_styles.count; - Style *styles = color_view->inspecting_styles.styles; - bool8 *import_check = color_view->import_export_check; - - do_label(&ui.state, &ui.layout, literal("Pack")); - begin_row(&ui.layout, 2); - if (do_button(-2, &ui.state, &ui.layout, "Finish Import", 2)){ - Style *style = styles; - for (i32 i = 0; i < style_count; ++i, ++style){ - if (import_check[i]) style_library_add(ui.styles, style); - } - color_view->mode = CV_MODE_LIBRARY; - } - if (do_button(-3, &ui.state, &ui.layout, "Cancel", 2)){ - color_view->mode = CV_MODE_LIBRARY; - } - - Style *style = styles; - for (i32 i = 0; i < style_count; ++i, ++style){ - if (do_style_preview(&ui, style, import_check[i])){ - import_check[i] = !import_check[i]; - result = 1; - } - } - }break; - - case CV_MODE_EXPORT: - { - do_label(&ui.state, &ui.layout, literal("Current Theme")); - do_style_preview(&ui, color_view->main_style); - - do_label(&ui.state, &ui.layout, literal("Export Which Themes?")); - begin_row(&ui.layout, 2); - if (do_button(-2, &ui.state, &ui.layout, "Export", 2)){ - color_view->mode = CV_MODE_EXPORT_FILE; - } - if (do_button(-3, &ui.state, &ui.layout, "Cancel", 2)){ - color_view->mode = CV_MODE_LIBRARY; - } - - i32 style_count = color_view->styles->count; - Style *style = color_view->styles->styles; - bool8 *export_check = color_view->import_export_check; - for (i32 i = 0; i < style_count; ++i, ++style){ - if (do_style_preview(&ui, style, export_check[i])){ - export_check[i] = !export_check[i]; - result = 1; - } - } - }break; - } - if (!ui.state.input_stage) draw_pop_clip(ui.state.target); - - if (ui_finish_frame(&color_view->state, &ui.state, &ui.layout, rect, 1, 0)){ - result = 1; - } - - return result; -} - -internal -Do_View_Sig(do_color_view){ - view->mouse_cursor_type = APP_MOUSE_CURSOR_ARROW; - Color_View *color_view = (Color_View*)view; - i32 result = 0; - - switch (color_view->mode){ - case CV_MODE_LIBRARY: - case CV_MODE_IMPORT_FILE: - case CV_MODE_EXPORT_FILE: - case CV_MODE_IMPORT: - case CV_MODE_EXPORT: - case CV_MODE_IMPORT_WAIT: - switch (message){ - case VMSG_STEP: - { - result = step_draw_library(system, exchange, view->mem, - color_view, rect, message, target, user_input); - }break; - case VMSG_DRAW: - { - step_draw_library(system, exchange, view->mem, - color_view, rect, message, target, user_input); - }break; - }break; - - case CV_MODE_ADJUSTING: - switch (message){ - case VMSG_STEP: - { - result = step_draw_adjusting(color_view, rect, message, target, user_input); - }break; - case VMSG_DRAW: - { - if (view != active){ - File_View *file_view = view_to_file_view(active); - color_view->hot_file_view = file_view; - } - if (color_view->hot_file_view && !color_view->hot_file_view->view_base.is_active){ - color_view->hot_file_view = 0; - } - update_highlighting(color_view); - step_draw_adjusting(color_view, rect, message, target, user_input); - }break; - }break; - } - - return result; -} - -internal Color_View* -color_view_init(View *view, Working_Set *working_set){ - Color_View* result = (Color_View*)view; - view->type = VIEW_TYPE_COLOR; - view->do_view = do_color_view; - result->working_set = working_set; - return result; -} - -// BOTTOM - diff --git a/4ed_config_view.cpp b/4ed_config_view.cpp deleted file mode 100644 index f01d83c4..00000000 --- a/4ed_config_view.cpp +++ /dev/null @@ -1,89 +0,0 @@ -/* - * Mr. 4th Dimention - Allen Webster - * - * 27.01.2016 - * - * Configuration customizing view for 4coder - * - */ - -// TOP - -struct Config_View{ - View view_base; - UI_State state; - Style *style; - Font_Set *font_set; - Working_Set *working_set; - - App_Settings *settings; -}; - -inline Config_View* -view_to_config_view(View *view){ - Config_View *result = 0; - if (view->type == VIEW_TYPE_CONFIG){ - result = (Config_View*)view; - } - return result; -} - -internal i32 -step_draw_config_view(Config_View *view, Render_Target *target, i32_Rect rect, - Input_Summary *user_input, b32 input_stage){ - i32 result = 0; - - UI_State state = - ui_state_init(&view->state, target, user_input, - view->style, view->font_set, view->working_set, input_stage); - - UI_Layout layout; - begin_layout(&layout, rect); - - i32 id = 0; - - do_label(&state, &layout, literal("Config"), 2.f); - - if (do_checkbox_list_option(++id, &state, &layout, make_lit_string("Left Ctrl + Left Alt = AltGr"), - view->settings->lctrl_lalt_is_altgr)){ - view->settings->lctrl_lalt_is_altgr = !view->settings->lctrl_lalt_is_altgr; - } - - if (ui_finish_frame(&view->state, &state, &layout, rect, 0, 0)){ - result = 1; - } - - return result; -} - -Do_View_Sig(do_config_view){ - i32 result = 0; - - Config_View *config_view = (Config_View*)view; - switch (message){ - case VMSG_STEP: case VMSG_DRAW: - result = step_draw_config_view(config_view, target, rect, user_input, - (message == VMSG_STEP)); - break; - } - - return result; -} - -internal Config_View* -config_view_init(View *view, Style *style, Working_Set *working_set, - Font_Set *font_set, App_Settings *settings){ - view->type = VIEW_TYPE_CONFIG; - view->do_view = do_config_view; - - Config_View *result; - result = (Config_View*)view; - result->style = style; - result->working_set = working_set; - result->font_set = font_set; - result->settings = settings; - return result; -} - -// BOTTOM - diff --git a/4ed_delay.cpp b/4ed_delay.cpp index f36e99e4..d8fb83d7 100644 --- a/4ed_delay.cpp +++ b/4ed_delay.cpp @@ -8,9 +8,6 @@ enum Action_Type{ DACT_SWITCH, DACT_TRY_KILL, DACT_KILL, - DACT_CLOSE_MINOR, - DACT_THEME_OPTIONS, - DACT_KEYBOARD_OPTIONS, }; struct Delayed_Action{ @@ -113,6 +110,3 @@ delayed_action_repush(Delay *delay, Delayed_Action *act){ #define delayed_switch(delay, ...) delayed_action_(delay, DACT_SWITCH, __VA_ARGS__) #define delayed_try_kill(delay, ...) delayed_action_(delay, DACT_TRY_KILL, __VA_ARGS__) #define delayed_kill(delay, ...) delayed_action_(delay, DACT_KILL, __VA_ARGS__) -#define delayed_close_minor(delay, ...) delayed_action_(delay, DACT_CLOSE_MINOR, __VA_ARGS__) -#define delayed_theme_options(delay, ...) delayed_action_(delay, DACT_THEME_OPTIONS, __VA_ARGS__) -#define delayed_keyboard_options(delay, ...) delayed_action_(delay, DACT_KEYBOARD_OPTIONS, __VA_ARGS__) diff --git a/4ed_file.cpp b/4ed_file.cpp index 7a909297..a10307d2 100644 --- a/4ed_file.cpp +++ b/4ed_file.cpp @@ -254,16 +254,6 @@ struct Hot_Directory{ char slash; }; -internal void -hot_directory_init(Hot_Directory *hot_directory, String base, String dir, char slash){ - hot_directory->string = base; - hot_directory->string.str[255] = 0; - hot_directory->string.size = 0; - copy(&hot_directory->string, dir); - append(&hot_directory->string, slash); - hot_directory->slash = slash; -} - internal void hot_directory_clean_end(Hot_Directory *hot_directory){ String *str = &hot_directory->string; @@ -326,6 +316,16 @@ hot_directory_reload(System_Functions *system, Hot_Directory *hot_directory, Wor hot_directory_fixup(hot_directory, working_set); } +internal void +hot_directory_init(Hot_Directory *hot_directory, String base, String dir, char slash){ + hot_directory->string = base; + hot_directory->string.str[255] = 0; + hot_directory->string.size = 0; + copy(&hot_directory->string, dir); + append(&hot_directory->string, slash); + hot_directory->slash = slash; +} + struct Hot_Directory_Match{ String filename; b32 is_folder; @@ -404,5 +404,47 @@ buffer_needs_save(Editing_File *file){ return(result); } +inline b32 +file_is_ready(Editing_File *file){ + b32 result = 0; + if (file && file->state.is_loading == 0){ + result = 1; + } + return(result); +} + +inline Editing_File* +working_set_contains(Working_Set *working, String filename){ + Editing_File *result = 0; + i32 id; + if (table_find(&working->table, filename, &id)){ + if (id < working->file_max_count){ + result = working->files + id; + } + } + return result; +} + +// TODO(allen): Find a way to choose an ordering for these so it picks better first options. +internal Editing_File* +working_set_lookup_file(Working_Set *working_set, String string){ + Editing_File *file = working_set_contains(working_set, string); + + if (!file){ + i32 file_i; + i32 end = working_set->file_index_count; + file = working_set->files; + for (file_i = 0; file_i < end; ++file_i, ++file){ + if (file->name.live_name.str && + (string.size == 0 || has_substr(file->name.live_name, string))){ + break; + } + } + if (file_i == end) file = 0; + } + + return file; +} + // BOTTOM diff --git a/4ed_file_view.cpp b/4ed_file_view.cpp index cd436c68..e7226152 100644 --- a/4ed_file_view.cpp +++ b/4ed_file_view.cpp @@ -9,6 +9,21 @@ // TOP +enum Interactive_Action{ + IAct_Open, + IAct_Save_As, + IAct_New, + IAct_Switch, + IAct_Kill, + IAct_Sure_To_Kill +}; + +enum Interactive_Interaction{ + IInt_Sys_File_List, + IInt_Live_File_List, + IInt_Sure_To_Kill +}; + struct File_View_Mode{ i8 rewrite; }; @@ -36,17 +51,68 @@ struct File_View_Widget{ } timeline; }; +enum View_UI{ + VUI_None, + VUI_Theme, + VUI_Interactive, + VUI_Menu, + VUI_Config, +}; + +enum Color_View_Mode{ + CV_Mode_Library, + CV_Mode_Import_File, + CV_Mode_Export_File, + CV_Mode_Import, + CV_Mode_Export, + CV_Mode_Import_Wait, + CV_Mode_Adjusting +}; + struct File_View{ View view_base; - - Font_Set *font_set; + Editing_File *file; - Style *style; + Editing_Layout *layout; + Style *style; + Working_Set *working_set; + Delay *delay; + Font_Set *font_set; + App_Settings *settings; + Hot_Directory *hot_directory; + Mem_Options *mem; + Style_Library *styles; + + UI_State ui_state; + View_UI showing_ui; + + // interactive stuff + Interactive_Interaction interaction; + Interactive_Action action; + b32 finished; + char query_[256]; + String query; + char dest_[256]; + String dest; + i32 user_action; + + // theme stuff + File_View *hot_file_view; + u32 *palette; + i32 palette_size; + Color_View_Mode color_mode; + Super_Color color; + Color_Highlight highlight; + b32 p4c_only; + Style_Library inspecting_styles; + b8 import_export_check[64]; + i32 import_file_id; + i32 font_advance; i32 font_height; - + Full_Cursor cursor; i32 mark; f32 scroll_y, target_y, vel_y; @@ -78,14 +144,13 @@ struct File_View{ i32 line_count, line_max; f32 *line_wrap_y; + + Command_Map *map_for_file; }; inline File_View* view_to_file_view(View *view){ - File_View* result = 0; - if (view && view->type == VIEW_TYPE_FILE){ - result = (File_View*)view; - } + File_View* result = (File_View*)view; return result; } @@ -116,15 +181,6 @@ file_init_strings(Editing_File *file){ file->name.extension = make_fixed_width_string(file->name.extension_); } -inline b32 -file_is_ready(Editing_File *file){ - b32 result = 0; - if (file && file->state.is_loading == 0){ - result = 1; - } - return(result); -} - inline void file_set_name(Working_Set *working_set, Editing_File *file, char *filename){ String f, ext; @@ -309,10 +365,9 @@ file_measure_starts_widths(System_Functions *system, General_Memory *general, max = ((max + 1) << 1); { - i32 *new_lines = (i32*) - general_memory_reallocate(general, buffer->line_starts, - sizeof(i32)*count, sizeof(i32)*max, BUBBLE_STARTS); - + i32 *new_lines = (i32*)general_memory_reallocate( + general, buffer->line_starts, sizeof(i32)*count, sizeof(i32)*max, BUBBLE_STARTS); + // TODO(allen): when unable to grow? TentativeAssert(new_lines); buffer->line_starts = new_lines; @@ -1340,7 +1395,7 @@ view_set_file( view->unwrapped_lines = file->settings.unwrapped_lines; if (file_is_ready(file)){ - view_measure_wraps(system, &view->view_base.mem->general, view); + view_measure_wraps(system, &view->mem->general, view); view->cursor = view_compute_cursor_from_pos(view, file->state.cursor_pos); cursor_x = view_get_cursor_x(view); @@ -2255,39 +2310,6 @@ working_set_clipboard_roll_down(Working_Set *working){ return result; } -inline Editing_File* -working_set_contains(Working_Set *working, String filename){ - Editing_File *result = 0; - i32 id; - if (table_find(&working->table, filename, &id)){ - if (id < working->file_max_count){ - result = working->files + id; - } - } - return result; -} - -// TODO(allen): Find a way to choose an ordering for these so it picks better first options. -internal Editing_File* -working_set_lookup_file(Working_Set *working_set, String string){ - Editing_File *file = working_set_contains(working_set, string); - - if (!file){ - i32 file_i; - i32 end = working_set->file_index_count; - file = working_set->files; - for (file_i = 0; file_i < end; ++file_i, ++file){ - if (file->name.live_name.str && - (string.size == 0 || has_substr(file->name.live_name, string))){ - break; - } - } - if (file_i == end) file = 0; - } - - return file; -} - internal void clipboard_copy(System_Functions *system, General_Memory *general, Working_Set *working, Range range, Editing_File *file){ i32 size = range.end - range.start; @@ -2698,7 +2720,7 @@ remeasure_file_view(System_Functions *system, View *view_, i32_Rect rect){ File_View *view = (File_View*)view_; if (file_is_ready(view->file)){ Relative_Scrolling relative = view_get_relative_scrolling(view); - view_measure_wraps(system, &view->view_base.mem->general, view); + view_measure_wraps(system, &view->mem->general, view); view_cursor_move(view, view->cursor.pos); view->preferred_x = view_get_cursor_x(view); view_set_relative_scrolling(view, relative); @@ -2709,7 +2731,6 @@ internal void undo_shit(System_Functions *system, File_View *view, UI_State *state, UI_Layout *layout, i32 total_count, i32 undo_count, i32 scrub_max){ - View *view_ = (View*)view; Editing_File *file = view->file; if (view->widget.timeline.undo_line){ @@ -2722,11 +2743,11 @@ undo_shit(System_Functions *system, File_View *view, UI_State *state, UI_Layout i32 new_count; if (do_undo_slider(wid, state, layout, total_count, undo_count, 0, &new_count)){ for (i32 i = 0; i < scrub_max && new_count < undo_count; ++i){ - view_undo(system, view_->mem, view->layout, view); + view_undo(system, view->mem, view->layout, view); --undo_count; } for (i32 i = 0; i < scrub_max && new_count > undo_count; ++i){ - view_redo(system, view_->mem, view->layout, view); + view_redo(system, view->mem, view->layout, view); ++undo_count; } } @@ -2750,10 +2771,10 @@ undo_shit(System_Functions *system, File_View *view, UI_State *state, UI_Layout i32 count = file->state.undo.edit_history_cursor; if (do_undo_slider(wid, state, layout, mid, count, &file->state.undo, &new_count)){ for (i32 i = 0; i < scrub_max && new_count < count; ++i){ - view_history_step(system, view_->mem, view->layout, view, hist_backward); + view_history_step(system, view->mem, view->layout, view, hist_backward); } for (i32 i = 0; i < scrub_max && new_count > count; ++i){ - view_history_step(system, view_->mem, view->layout, view, hist_forward); + view_history_step(system, view->mem, view->layout, view, hist_forward); } } } @@ -2779,8 +2800,718 @@ draw_file_view_queries(File_View *view, UI_State *state, UI_Layout *layout){ } } +inline void +view_show_menu(File_View *fview, Command_Map *gui_map){ + fview->ui_state = {}; + fview->map_for_file = fview->view_base.map; + fview->view_base.map = gui_map; + fview->locked = 1; + fview->showing_ui = VUI_Menu; +} + +inline void +view_show_config(File_View *fview, Command_Map *gui_map){ + fview->ui_state = {}; + fview->map_for_file = fview->view_base.map; + fview->view_base.map = gui_map; + fview->locked = 1; + fview->showing_ui = VUI_Config; +} + +inline void +view_show_interactive(System_Functions *system, File_View *fview, Command_Map *gui_map, + Interactive_Action action, Interactive_Interaction interaction, String query){ + fview->ui_state = {}; + fview->map_for_file = fview->view_base.map; + fview->view_base.map = gui_map; + fview->locked = 1; + fview->showing_ui = VUI_Interactive; + fview->action = action; + fview->interaction = interaction; + fview->finished = 0; + + copy(&fview->query, query); + + hot_directory_clean_end(fview->hot_directory); + hot_directory_reload(system, fview->hot_directory, fview->working_set); +} + +inline void +view_show_theme(File_View *fview, Command_Map *gui_map){ + fview->ui_state = {}; + fview->map_for_file = fview->view_base.map; + fview->view_base.map = gui_map; + fview->locked = 1; + fview->showing_ui = VUI_Theme; + fview->color_mode = CV_Mode_Library; +} + +inline void +view_show_file(File_View *fview, Command_Map *file_map){ + fview->ui_state = {}; + if (file_map){ + fview->view_base.map = file_map; + } + else{ + fview->view_base.map = fview->map_for_file; + } + fview->locked = 0; + fview->showing_ui = VUI_None; +} + +internal void +interactive_view_complete(File_View *view){ + Panel *panel = view->view_base.panel; + switch (view->action){ + case IAct_Open: + delayed_open(view->delay, view->hot_directory->string, panel); + break; + + case IAct_Save_As: + delayed_save_as(view->delay, view->hot_directory->string, panel); + view_show_file(view, 0); + break; + + case IAct_New: + delayed_new(view->delay, view->hot_directory->string, panel); + break; + + case IAct_Switch: + delayed_switch(view->delay, view->dest, panel); + break; + + case IAct_Kill: + delayed_try_kill(view->delay, view->dest, panel); + break; + + case IAct_Sure_To_Kill: + switch (view->user_action){ + case 0: + delayed_kill(view->delay, view->dest, panel); + break; + + case 1:break; + + case 2: + // TODO(allen): This is fishy! What if the save doesn't happen this time around? + // We need to ensure delayed acts happen in order I think. + delayed_save(view->delay, view->dest, panel); + delayed_kill(view->delay, view->dest, panel); + break; + } + view_show_file(view, 0); + break; + } +} + +internal void +update_highlighting(File_View *view){ + File_View *file_view = view->hot_file_view; + if (!file_view){ + view->highlight = {}; + return; + } + + Editing_File *file = file_view->file; + if (!file || !file_is_ready(file)){ + view->highlight = {}; + return; + } + + Style *style = view->style; + i32 pos = view_get_cursor_pos(file_view); + char c = buffer_get_char(&file->state.buffer, pos); + + if (c == '\r'){ + view->highlight.ids[0] = + raw_ptr_dif(&style->main.special_character_color, style); + } + + else if (file->state.tokens_complete){ + Cpp_Token_Stack *tokens = &file->state.token_stack; + Cpp_Get_Token_Result result = cpp_get_token(tokens, pos); + Cpp_Token token = tokens->tokens[result.token_index]; + if (!result.in_whitespace){ + u32 *color = style_get_color(style, token); + view->highlight.ids[0] = raw_ptr_dif(color, style); + if (token.type == CPP_TOKEN_JUNK){ + view->highlight.ids[1] = + raw_ptr_dif(&style->main.highlight_junk_color, style); + } + else if (char_is_whitespace(c)){ + view->highlight.ids[1] = + raw_ptr_dif(&style->main.highlight_white_color, style); + } + else{ + view->highlight.ids[1] = 0; + } + } + else{ + view->highlight.ids[0] = 0; + view->highlight.ids[1] = + raw_ptr_dif(&style->main.highlight_white_color, style); + } + } + + else{ + if (char_is_whitespace(c)){ + view->highlight.ids[0] = 0; + view->highlight.ids[1] = + raw_ptr_dif(&style->main.highlight_white_color, style); + } + else{ + view->highlight.ids[0] = + raw_ptr_dif(&style->main.default_color, style); + view->highlight.ids[1] = 0; + } + } + + if (file_view->show_temp_highlight){ + view->highlight.ids[2] = + raw_ptr_dif(&style->main.highlight_color, style); + view->highlight.ids[3] = + raw_ptr_dif(&style->main.at_highlight_color, style); + } + else if (file->state.paste_effect.tick_down > 0){ + view->highlight.ids[2] = + raw_ptr_dif(&style->main.paste_color, style); + view->highlight.ids[3] = 0; + } + else{ + view->highlight.ids[2] = 0; + view->highlight.ids[3] = 0; + } +} + +internal b32 +theme_library_shit(System_Functions *system, Exchange *exchange, + File_View *view, UI_State *state, UI_Layout *layout){ + + Mem_Options *mem = view->mem; + + i32 result = 0; + + Library_UI ui; + ui.state = state; + ui.layout = layout; + + ui.fonts = view->font_set; + ui.hot_directory = view->hot_directory; + ui.styles = view->styles; + + Color_View_Mode mode = view->color_mode; + + i32_Rect bar_rect = ui.layout->rect; + bar_rect.x0 = bar_rect.x1 - 20; + do_scroll_bar(ui.state, bar_rect); + + ui.layout->y -= FLOOR32(view->ui_state.view_y); + ui.layout->rect.x1 -= 20; + + b32 case_sensitive = 0; + + switch (mode){ + case CV_Mode_Library: + { + do_label(ui.state, ui.layout, literal("Current Theme - Click to Edit")); + if (do_style_preview(&ui, view->style)){ + view->color_mode = CV_Mode_Adjusting; + view->ui_state.selected = {}; + ui.state->view_y = 0; + result = 1; + } + + begin_row(ui.layout, 3); + if (ui.state->style->name.size >= 1){ + if (do_button(-2, ui.state, ui.layout, "Save", 2)){ + style_library_add(ui.styles, ui.state->style); + } + } + else{ + do_button(-2, ui.state, ui.layout, "~Need's Name~", 2); + } + if (do_button(-3, ui.state, ui.layout, "Import", 2)){ + view->color_mode = CV_Mode_Import_File; + hot_directory_clean_end(view->hot_directory); + hot_directory_reload(system, view->hot_directory, view->working_set); + } + if (do_button(-4, ui.state, ui.layout, "Export", 2)){ + view->color_mode = CV_Mode_Export; + hot_directory_clean_end(view->hot_directory); + hot_directory_reload(system, view->hot_directory, view->working_set); + memset(view->import_export_check, 0, sizeof(view->import_export_check)); + } + + do_label(ui.state, ui.layout, literal("Theme Library - Click to Select")); + + i32 style_count = view->styles->count; + Style *style = view->styles->styles; + for (i32 i = 0; i < style_count; ++i, ++style){ + if (do_style_preview(&ui, style)){ + style_copy(view->style, style); + result = 1; + } + } + }break; + + case CV_Mode_Import_File: + { + do_label(ui.state, ui.layout, literal("Current Theme")); + do_style_preview(&ui, view->style); + + b32 file_selected = 0; + + do_label(ui.state, ui.layout, literal("Import Which File?")); + begin_row(ui.layout, 2); + if (do_button(-2, ui.state, ui.layout, "*.p4c only", 2, 1, view->p4c_only)){ + view->p4c_only = !view->p4c_only; + } + if (do_button(-3, ui.state, ui.layout, "Cancel", 2)){ + view->color_mode = CV_Mode_Library; + } + + b32 new_dir = 0; + if (do_file_list_box(system, ui.state, ui.layout, + ui.hot_directory, view->p4c_only, 1, case_sensitive, + &new_dir, &file_selected, 0)){ + result = 1; + } + + if (new_dir){ + hot_directory_reload(system, ui.hot_directory, ui.state->working_set); + } + if (file_selected){ + memset(&view->inspecting_styles, 0, sizeof(Style_Library)); + memset(view->import_export_check, 1, + sizeof(view->import_export_check)); + + view->import_file_id = exchange_request_file(exchange, + view->hot_directory->string.str, + view->hot_directory->string.size); + view->color_mode = CV_Mode_Import_Wait; + + } + }break; + + case CV_Mode_Import_Wait: + { + Style *styles = view->inspecting_styles.styles; + Data file = {}; + i32 file_max = 0; + + i32 count = 0; + i32 max = ArrayCount(view->inspecting_styles.styles); + + AllowLocal(styles); + AllowLocal(max); + + if (exchange_file_ready(exchange, view->import_file_id, + &file.data, &file.size, &file_max)){ + if (file.data){ + if (0 /* && style_library_import(file, ui.fonts, styles, max, &count) */){ + view->color_mode = CV_Mode_Import; + } + else{ + view->color_mode = CV_Mode_Library; + } + view->inspecting_styles.count = count; + } + else{ + Assert(!"this shouldn't happen!"); + } + + exchange_free_file(exchange, view->import_file_id); + } + }break; + + case CV_Mode_Export_File: + { + do_label(ui.state, ui.layout, literal("Current Theme")); + do_style_preview(&ui, view->style); + + b32 file_selected = 0; + + do_label(ui.state, ui.layout, literal("Export File Name?")); + begin_row(ui.layout, 2); + if (do_button(-2, ui.state, ui.layout, "Finish Export", 2)){ + file_selected = 1; + } + if (do_button(-3, ui.state, ui.layout, "Cancel", 2)){ + view->color_mode = CV_Mode_Library; + } + + b32 new_dir = 0; + if (do_file_list_box(system, ui.state, ui.layout, + ui.hot_directory, 1, 1, case_sensitive, + &new_dir, &file_selected, ".p4c")){ + result = 1; + } + + if (new_dir){ + hot_directory_reload(system, + ui.hot_directory, ui.state->working_set); + } + if (file_selected){ + i32 count = ui.styles->count; + Temp_Memory temp = begin_temp_memory(&mem->part); + Style **styles = push_array(&mem->part, Style*, sizeof(Style*)*count); + + Style *style = ui.styles->styles; + b8 *export_check = view->import_export_check; + i32 export_count = 0; + for (i32 i = 0; i < count; ++i, ++style){ + if (export_check[i]){ + styles[export_count++] = style; + } + } + char *data = push_array(&mem->part, char, ui.hot_directory->string.size + 5); + String str = make_string(data, 0, ui.hot_directory->string.size + 5); + copy(&str, ui.hot_directory->string); + append(&str, make_lit_string(".p4c")); + /*style_library_export(system, exchange, mem, &target->font_set, str.str, styles, export_count);*/ + + end_temp_memory(temp); + view->color_mode = CV_Mode_Library; + } + }break; + + case CV_Mode_Import: + { + do_label(ui.state, ui.layout, literal("Current Theme")); + do_style_preview(&ui, view->style); + + i32 style_count = view->inspecting_styles.count; + Style *styles = view->inspecting_styles.styles; + b8 *import_check = view->import_export_check; + + do_label(ui.state, ui.layout, literal("Pack")); + begin_row(ui.layout, 2); + if (do_button(-2, ui.state, ui.layout, "Finish Import", 2)){ + Style *style = styles; + for (i32 i = 0; i < style_count; ++i, ++style){ + if (import_check[i]) style_library_add(ui.styles, style); + } + view->color_mode = CV_Mode_Library; + } + if (do_button(-3, ui.state, ui.layout, "Cancel", 2)){ + view->color_mode = CV_Mode_Library; + } + + Style *style = styles; + for (i32 i = 0; i < style_count; ++i, ++style){ + if (do_style_preview(&ui, style, import_check[i])){ + import_check[i] = !import_check[i]; + result = 1; + } + } + }break; + + case CV_Mode_Export: + { + do_label(ui.state, ui.layout, literal("Current Theme")); + do_style_preview(&ui, view->style); + + do_label(ui.state, ui.layout, literal("Export Which Themes?")); + begin_row(ui.layout, 2); + if (do_button(-2, ui.state, ui.layout, "Export", 2)){ + view->color_mode = CV_Mode_Export_File; + } + if (do_button(-3, ui.state, ui.layout, "Cancel", 2)){ + view->color_mode = CV_Mode_Library; + } + + i32 style_count = view->styles->count; + Style *style = view->styles->styles; + b8 *export_check = view->import_export_check; + for (i32 i = 0; i < style_count; ++i, ++style){ + if (do_style_preview(&ui, style, export_check[i])){ + export_check[i] = !export_check[i]; + result = 1; + } + } + }break; + } + + return result; +} + +internal b32 +theme_adjusting_shit(File_View *view, UI_State *state, UI_Layout *layout){ + update_highlighting(view); + + Style *style = view->style; + i32 result = 0; + + Color_UI ui; + ui.state = state; + ui.layout = layout; + + ui.fonts = view->font_set; + ui.highlight = view->highlight; + ui.color = view->color; + ui.has_hover_color = 0; + ui.state->sub_id1_change = 0; + ui.hex_advance = font_get_max_width(ui.fonts, ui.state->font_id, "0123456789abcdefx"); + ui.palette = view->palette; + ui.palette_size = view->palette_size; + + i32_Rect bar_rect = ui.layout->rect; + bar_rect.x0 = bar_rect.x1 - 20; + do_scroll_bar(ui.state, bar_rect); + + ui.layout->y -= FLOOR32(view->ui_state.view_y); + ui.layout->rect.x1 -= 20; + + if (do_button(-1, ui.state, ui.layout, "Back to Library", 2)){ + view->color_mode = CV_Mode_Library; + ui.state->view_y = 0; + } + + do_style_name(&ui); + do_font_switch(&ui); + + do_color_adjuster(&ui, &style->main.back_color, + style->main.default_color, style->main.back_color, + "Background"); + do_color_adjuster(&ui, &style->main.margin_color, + style->main.default_color, style->main.margin_color, + "Margin"); + do_color_adjuster(&ui, &style->main.margin_hover_color, + style->main.default_color, style->main.margin_hover_color, + "Margin Hover"); + do_color_adjuster(&ui, &style->main.margin_active_color, + style->main.default_color, style->main.margin_active_color, + "Margin Active"); + + do_color_adjuster(&ui, &style->main.cursor_color, + style->main.at_cursor_color, style->main.cursor_color, + "Cursor"); + do_color_adjuster(&ui, &style->main.at_cursor_color, + style->main.at_cursor_color, style->main.cursor_color, + "Text At Cursor"); + do_color_adjuster(&ui, &style->main.mark_color, + style->main.mark_color, style->main.back_color, + "Mark"); + + do_color_adjuster(&ui, &style->main.highlight_color, + style->main.at_highlight_color, style->main.highlight_color, + "Highlight"); + do_color_adjuster(&ui, &style->main.at_highlight_color, + style->main.at_highlight_color, style->main.highlight_color, + "Text At Highlight"); + + do_color_adjuster(&ui, &style->main.default_color, + style->main.default_color, style->main.back_color, + "Text Default"); + do_color_adjuster(&ui, &style->main.comment_color, + style->main.comment_color, style->main.back_color, + "Comment"); + do_color_adjuster(&ui, &style->main.keyword_color, + style->main.keyword_color, style->main.back_color, + "Keyword"); + do_color_adjuster(&ui, &style->main.str_constant_color, + style->main.str_constant_color, style->main.back_color, + "String Constant"); + do_color_adjuster(&ui, &style->main.char_constant_color, + style->main.char_constant_color, style->main.back_color, + "Character Constant"); + do_color_adjuster(&ui, &style->main.int_constant_color, + style->main.int_constant_color, style->main.back_color, + "Integer Constant"); + do_color_adjuster(&ui, &style->main.float_constant_color, + style->main.float_constant_color, style->main.back_color, + "Float Constant"); + do_color_adjuster(&ui, &style->main.bool_constant_color, + style->main.bool_constant_color, style->main.back_color, + "Boolean Constant"); + do_color_adjuster(&ui, &style->main.preproc_color, + style->main.preproc_color, style->main.back_color, + "Preprocessor"); + do_color_adjuster(&ui, &style->main.include_color, + style->main.include_color, style->main.back_color, + "Include Constant"); + do_color_adjuster(&ui, &style->main.special_character_color, + style->main.special_character_color, style->main.back_color, + "Special Character"); + + do_color_adjuster(&ui, &style->main.highlight_junk_color, + style->main.default_color, style->main.highlight_junk_color, + "Junk Highlight"); + do_color_adjuster(&ui, &style->main.highlight_white_color, + style->main.default_color, style->main.highlight_white_color, + "Whitespace Highlight"); + + do_color_adjuster(&ui, &style->main.paste_color, + style->main.paste_color, style->main.back_color, + "Paste Color"); + + Interactive_Style *bar_style = &style->main.file_info_style; + do_color_adjuster(&ui, &bar_style->bar_color, + bar_style->base_color, bar_style->bar_color, + "Bar"); + do_color_adjuster(&ui, &bar_style->base_color, + bar_style->base_color, bar_style->bar_color, + "Bar Text"); + do_color_adjuster(&ui, &bar_style->pop1_color, + bar_style->pop1_color, bar_style->bar_color, + "Bar Pop 1"); + do_color_adjuster(&ui, &bar_style->pop2_color, + bar_style->pop2_color, bar_style->bar_color, + "Bar Pop 2"); + + view->color = ui.color; + + return result; +} + +internal b32 +theme_shit(System_Functions *system, Exchange *exchange, + File_View *view, View *active, UI_State *state, UI_Layout *layout){ + b32 result = 0; + + File_View *factive = view_to_file_view(active); + if (view != factive){ + view->hot_file_view = factive; + } + + switch (view->color_mode){ + case CV_Mode_Library: + case CV_Mode_Import_File: + case CV_Mode_Export_File: + case CV_Mode_Import: + case CV_Mode_Export: + case CV_Mode_Import_Wait: + if (theme_library_shit(system, exchange, view, state, layout)){ + result = 1; + } + break; + + case CV_Mode_Adjusting: + if (theme_adjusting_shit(view, state, layout)){ + result = 1; + } + break; + } + + return(result); +} + +internal b32 +interactive_shit(System_Functions *system, File_View *view, UI_State *state, UI_Layout *layout){ + b32 result = 0; + b32 new_dir = 0; + b32 complete = 0; + + do_label(state, layout, view->query, 1.f); + + b32 case_sensitive = 0; + + b32 input_stage = state->input_stage; + Key_Summary *keys = state->keys; + + switch (view->interaction){ + case IInt_Sys_File_List: + { + b32 is_new = (view->action == IAct_New); + + if (do_file_list_box(system, state, + layout, view->hot_directory, 0, !is_new, case_sensitive, + &new_dir, &complete, 0)){ + result = 1; + } + if (new_dir){ + hot_directory_reload(system, + view->hot_directory, view->working_set); + } + }break; + + case IInt_Live_File_List: + { + if (do_live_file_list_box(system, state, layout, view->working_set, &view->dest, &complete)){ + result = 1; + } + }break; + + case IInt_Sure_To_Kill: + { + i32 action = -1; + char s_[256]; + String s = make_fixed_width_string(s_); + append(&s, view->dest); + append(&s, " has unsaved changes, kill it?"); + do_label(state, layout, s, 1.f); + + i32 id = 0; + if (do_list_option(++id, state, layout, make_lit_string("(Y)es"))){ + action = 0; + } + + if (do_list_option(++id, state, layout, make_lit_string("(N)o"))){ + action = 1; + } + + if (do_list_option(++id, state, layout, make_lit_string("(S)ave and kill"))){ + action = 2; + } + + if (action == -1 && input_stage){ + i32 key_count = keys->count; + for (i32 i = 0; i < key_count; ++i){ + Key_Event_Data key = keys->keys[i]; + switch (key.character){ + case 'y': case 'Y': action = 0; break; + case 'n': case 'N': action = 1; break; + case 's': case 'S': action = 2; break; + } + if (action == -1 && key.keycode == key_esc) action = 1; + if (action != -1) break; + } + } + + if (action != -1){ + complete = 1; + view->user_action = action; + } + }break; + } + + if (complete){ + view->finished = 1; + interactive_view_complete(view); + } + + return(result); +} + +internal void +menu_shit(File_View *view, UI_State *state, UI_Layout *layout){ + i32 id = 0; + + do_label(state, layout, literal("Menu"), 2.f); + + if (do_list_option(++id, state, layout, make_lit_string("Theme Options"))){ + view_show_theme(view, view->view_base.map); + } + + if (do_list_option(++id, state, layout, make_lit_string("Keyboard Layout Options"))){ + view_show_config(view, view->view_base.map); + } +} + +internal void +config_shit(File_View *view, UI_State *state, UI_Layout *layout){ + i32 id = 0; + + do_label(state, layout, literal("Config"), 2.f); + + if (do_checkbox_list_option(++id, state, layout, make_lit_string("Left Ctrl + Left Alt = AltGr"), + view->settings->lctrl_lalt_is_altgr)){ + view->settings->lctrl_lalt_is_altgr = !view->settings->lctrl_lalt_is_altgr; + } +} + internal i32 -step_file_view(System_Functions *system, View *view_, i32_Rect rect, +step_file_view(System_Functions *system, Exchange *exchange, View *view_, i32_Rect rect, b32 is_active, Input_Summary *user_input){ view_->mouse_cursor_type = APP_MOUSE_CURSOR_IBEAM; @@ -2822,6 +3553,7 @@ step_file_view(System_Functions *system, View *view_, i32_Rect rect, } } + // TODO(allen): Split this into passive step and step that depends on input if (file && !file->state.is_loading){ f32 line_height = (f32)view->font_height; f32 cursor_y = view_get_cursor_y(view); @@ -2914,6 +3646,41 @@ step_file_view(System_Functions *system, View *view_, i32_Rect rect, if (!is_active) view_set_widget(view, FWIDG_NONE); } + { + UI_State state = + ui_state_init(&view->ui_state, 0, user_input, + view->style, view->font_set, view->working_set, 1); + + UI_Layout layout; + begin_layout(&layout, rect); + + switch (view->showing_ui){ + case VUI_None: break; + case VUI_Theme: + { + theme_shit(system, exchange, view, 0, &state, &layout); + }break; + case VUI_Interactive: + { + if (interactive_shit(system, view, &state, &layout)){ + result = 1; + } + }break; + case VUI_Menu: + { + menu_shit(view, &state, &layout); + }break; + case VUI_Config: + { + config_shit(view, &state, &layout); + }break; + } + + if (ui_finish_frame(&view->ui_state, &state, &layout, rect, 0, 0)){ + result = 1; + } + } + return(result); } @@ -2989,7 +3756,7 @@ draw_file_loaded(File_View *view, i32_Rect rect, b32 is_active, Render_Target *t token_stack = file->state.token_stack; } - Partition *part = &view->view_base.mem->part; + Partition *part = &view->mem->part; Temp_Memory temp = begin_temp_memory(part); @@ -3139,19 +3906,15 @@ draw_file_loaded(File_View *view, i32_Rect rect, b32 is_active, Render_Target *t } internal i32 -draw_file_view(View *view_, i32_Rect rect, b32 is_active, Render_Target *target){ +draw_file_view(System_Functions *system, Exchange *exchange, + View *view_, View *active, i32_Rect rect, b32 is_active, Render_Target *target, Input_Summary *user_input){ File_View *view = (File_View*)view_; i32 result = 0; i32 widget_height = 0; { - //UI_Style ui_style = get_ui_style_upper(view->style); - i32_Rect widg_rect = view_widget_rect(view, view->font_height); - //draw_rectangle(target, widg_rect, ui_style.dark); - //draw_rectangle_outline(target, widg_rect, ui_style.dim); - UI_State state = ui_state_init(&view->widget.state, target, 0, view->style, view->font_set, 0, 0); @@ -3184,21 +3947,59 @@ draw_file_view(View *view_, i32_Rect rect, b32 is_active, Render_Target *target) ui_finish_frame(&view->widget.state, &state, &layout, widg_rect, 0, 0); } - if (view->file){ - Interactive_Bar bar; - draw_file_setup_bar(view->style, view->font_height, &bar, &rect); + { + rect.y0 += widget_height; + target->push_clip(target, rect); + + UI_State state = + ui_state_init(&view->ui_state, target, user_input, + view->style, view->font_set, view->working_set, 0); + + UI_Layout layout; + begin_layout(&layout, rect); + + rect.y0 -= widget_height; + + switch (view->showing_ui){ + case VUI_None: + { + if (view->file){ + Interactive_Bar bar; + draw_file_setup_bar(view->style, view->font_height, &bar, &rect); - if (file_is_ready(view->file)){ - rect.y0 += widget_height; - target->push_clip(target, rect); - rect.y0 -= widget_height; - result = draw_file_loaded(view, rect, is_active, target); - target->pop_clip(target); + if (file_is_ready(view->file)){ + result = draw_file_loaded(view, rect, is_active, target); + } + + draw_file_bar(view, &bar, target); + } + }break; + + case VUI_Theme: + { + theme_shit(system, exchange, view, active, &state, &layout); + }break; + + case VUI_Interactive: + { + interactive_shit(system, view, &state, &layout); + }break; + case VUI_Menu: + { + menu_shit(view, &state, &layout); + }break; + case VUI_Config: + { + config_shit(view, &state, &layout); + }break; } - draw_file_bar(view, &bar, target); + ui_finish_frame(&view->ui_state, &state, &layout, rect, 0, 0); + + target->pop_clip(target); } + return (result); } @@ -3208,7 +4009,7 @@ kill_file( General_Memory *general, Editing_File *file, Live_Views *live_set, Editing_Layout *layout){ - View *view, *to_kill; + View *view; File_View *fview; Panel *panel; i32 panel_count, i; @@ -3217,10 +4018,10 @@ kill_file( panel = layout->panels; for (i = 0; i < panel_count; ++i, ++panel){ view = panel->view; - to_kill = view; - if (view->is_minor) to_kill = view->major; - fview = view_to_file_view(to_kill); - if (fview && fview->file == file){ + fview = view_to_file_view(view); + Assert(fview); + + if (fview->file == file){ fview->file = 0; } } @@ -3232,7 +4033,7 @@ inline void free_file_view(View *view){ File_View *fview = (File_View*)view; if (fview->line_wrap_y) - general_memory_free(&view->mem->general, fview->line_wrap_y); + general_memory_free(&fview->mem->general, fview->line_wrap_y); } internal @@ -3246,11 +4047,11 @@ Do_View_Sig(do_file_view){ }break; case VMSG_DRAW: { - result = draw_file_view(view, rect, (view == active), target); + result = draw_file_view(system, exchange, view, active, rect, (view == active), target, user_input); }break; case VMSG_STEP: { - result = step_file_view(system, view, rect, (view == active), user_input); + result = step_file_view(system, exchange, view, rect, (view == active), user_input); }break; case VMSG_FREE: { @@ -3261,13 +4062,28 @@ Do_View_Sig(do_file_view){ } internal File_View* -file_view_init(View *view, Editing_Layout *layout){ - view->type = VIEW_TYPE_FILE; +file_view_init(View *view, Editing_Layout *layout, + Working_Set *working_set, Delay *delay, + App_Settings *settings, Hot_Directory *hot_directory, + Mem_Options *mem, Style_Library *styles){ + view->do_view = do_file_view; File_View *result = (File_View*)view; result->layout = layout; + result->working_set = working_set; + result->delay = delay; + result->settings = settings; + result->hot_directory = hot_directory; + result->mem = mem; + result->styles = styles; + result->scrub_max = 1; + + // TODO(allen): Make "interactive" mode customizable just like the query bars! + result->query = make_fixed_width_string(result->query_); + result->dest = make_fixed_width_string(result->dest_); + init_query_set(&result->query_set); return(result); diff --git a/4ed_gui.cpp b/4ed_gui.cpp index 4fbae7a0..955c4064 100644 --- a/4ed_gui.cpp +++ b/4ed_gui.cpp @@ -368,7 +368,7 @@ struct UI_State{ b32 input_stage; i32 sub_id1_change; - real32 height, view_y; + f32 height, view_y; }; inline Widget_ID @@ -1010,6 +1010,1326 @@ do_undo_slider(Widget_ID wid, UI_State *state, UI_Layout *layout, i32 max, i32 v return result; } +internal void +do_label(UI_State *state, UI_Layout *layout, char *text, int text_size, f32 height = 2.f){ + Style *style = state->style; + i16 font_id = style->font_id; + i32 line_height = get_font_info(state->font_set, font_id)->height; + i32_Rect label = layout_rect(layout, FLOOR32(line_height * height)); + + if (!state->input_stage){ + Render_Target *target = state->target; + u32 back = style->main.margin_color; + u32 fore = style->main.default_color; + draw_rectangle(target, label, back); + i32 height = label.y1 - label.y0; + + String textstr = make_string(text, text_size); + draw_string(target, font_id, textstr, label.x0, + label.y0 + (height - line_height)/2, fore); + } +} + +inline void +do_label(UI_State *state, UI_Layout *layout, String text, f32 height = 2.f){ + do_label(state, layout, text.str, text.size, height); +} + +internal void +do_scroll_bar(UI_State *state, i32_Rect rect){ + i32 id = 1; + i32 w = (rect.x1 - rect.x0); + i32 h = (rect.y1 - rect.y0); + + i32_Rect top_arrow, bottom_arrow; + top_arrow.x0 = rect.x0; + top_arrow.x1 = rect.x1; + top_arrow.y0 = rect.y0; + top_arrow.y1 = top_arrow.y0 + w; + + bottom_arrow.x0 = rect.x0; + bottom_arrow.x1 = rect.x1; + bottom_arrow.y1 = rect.y1; + bottom_arrow.y0 = bottom_arrow.y1 - w; + + f32 space_h = (f32)(bottom_arrow.y0 - top_arrow.y1); + if (space_h <= w) return; + + i32 slider_h = w; + + f32 view_hmin = 0; + f32 view_hmax = state->height - h; + f32 L = unlerp(view_hmin, state->view_y, view_hmax); + + f32 slider_hmin = (f32)top_arrow.y1; + f32 slider_hmax = (f32)bottom_arrow.y0 - slider_h; + f32 S = lerp(slider_hmin, L, slider_hmax); + + i32_Rect slider; + slider.x0 = rect.x0; + slider.x1 = rect.x1; + slider.y0 = FLOOR32(S); + slider.y1 = slider.y0 + slider_h; + + Widget_ID wid = make_id(state, id); + + if (state->input_stage){ + state->view_y = + ui_do_vscroll_input(state, top_arrow, bottom_arrow, slider, wid, state->view_y, + (f32)(get_font_info(state->font_set, state->font_id)->height), + slider_hmin, slider_hmax, view_hmin, view_hmax); + } + else{ + Render_Target *target = state->target; + + f32 x0, y0, x1, y1, x2, y2; + f32 w_1_2 = w*.5f; + f32 w_1_3 = w*.333333f; + f32 w_2_3 = w*.666667f; + + + UI_Style ui_style = get_ui_style(state->style); + u32 outline, back, fore; + + outline = ui_style.bright; + + wid.sub_id2 = 0; + + x0 = (w_1_2 + top_arrow.x0); + x1 = (w_1_3 + top_arrow.x0); + x2 = (w_2_3 + top_arrow.x0); + + ++wid.sub_id2; + y0 = (w_1_3 + top_arrow.y0); + y1 = (w_2_3 + top_arrow.y0); + y2 = (w_2_3 + top_arrow.y0); + get_colors(state, &back, &fore, wid, ui_style); + draw_rectangle(target, top_arrow, back); + draw_rectangle_outline(target, top_arrow, outline); + + ++wid.sub_id2; + y0 = (w_2_3 + bottom_arrow.y0); + y1 = (w_1_3 + bottom_arrow.y0); + y2 = (w_1_3 + bottom_arrow.y0); + get_colors(state, &back, &fore, wid, ui_style); + draw_rectangle(target, bottom_arrow, back); + draw_rectangle_outline(target, bottom_arrow, outline); + + ++wid.sub_id2; + get_colors(state, &back, &fore, wid, ui_style); + draw_rectangle(target, slider, back); + draw_rectangle_outline(target, slider, outline); + + draw_rectangle_outline(target, rect, outline); + } +} + +internal void +draw_gradient_slider(Render_Target *target, Vec4 base, i32 channel, + i32 steps, f32 top, f32_Rect slider, b32 hsla){ + Vec4 low, high; + f32 *lowv, *highv; + f32 x; + f32 next_x; + f32 x_step; + f32 v_step; + f32 m; + + x = (real32)slider.x0; + x_step = (real32)(slider.x1 - slider.x0) / steps; + v_step = top / steps; + m = 1.f / top; + lowv = &low.v[channel]; + highv = &high.v[channel]; + + if (hsla){ + for (i32 i = 0; i < steps; ++i){ + low = high = base; + *lowv = (i * v_step); + *highv = *lowv + v_step; + *lowv *= m; + *highv *= m; + low = hsla_to_rgba(low); + high = hsla_to_rgba(high); + + next_x = x + x_step; + draw_gradient_2corner_clipped( + target, x, slider.y0, next_x, slider.y1, + low, high); + x = next_x; + } + } + else{ + for (i32 i = 0; i < steps; ++i){ + low = high = base; + *lowv = (i * v_step); + *highv = *lowv + v_step; + *lowv *= m; + *highv *= m; + + next_x = x + x_step; + draw_gradient_2corner_clipped( + target, x, slider.y0, next_x, slider.y1, + low, high); + x = next_x; + } + } +} + +inline void +draw_hsl_slider(Render_Target *target, Vec4 base, i32 channel, + i32 steps, real32 top, f32_Rect slider){ + draw_gradient_slider(target, base, channel, steps, top, slider, 1); +} + +inline void +draw_rgb_slider(Render_Target *target, Vec4 base, i32 channel, + i32 steps, f32 top, f32_Rect slider){ + draw_gradient_slider(target, base, channel, steps, top, slider, 0); +} + +internal b32 +do_main_file_box(System_Functions *system, UI_State *state, UI_Layout *layout, + Hot_Directory *hot_directory, b32 try_to_match, b32 case_sensitive, char *end){ + b32 result = 0; + Style *style = state->style; + String *string = &hot_directory->string; + + i16 font_id = style->font_id; + i32 line_height = get_font_info(state->font_set, font_id)->height; + i32_Rect box = layout_rect(layout, line_height + 2); + + if (state->input_stage){ + if (ui_do_file_field_input(system, state, hot_directory, try_to_match, case_sensitive)){ + result = 1; + } + } + else{ + Render_Target *target = state->target; + u32 back = style->main.margin_color; + u32 fore = style->main.default_color; + u32 special = style->main.special_character_color; + draw_rectangle(target, box, back); + i32 x = box.x0; + x = draw_string(target, font_id, string->str, x, box.y0, fore); + if (end) draw_string(target, font_id, end, x, box.y0, special); + } + + layout->y = box.y1; + return result; +} + +internal b32 +do_main_string_box(System_Functions *system, UI_State *state, UI_Layout *layout, String *string){ + b32 result = 0; + Style *style = state->style; + + i16 font_id = style->font_id; + i32 line_height = get_font_info(state->font_set, font_id)->height; + i32_Rect box = layout_rect(layout, line_height + 2); + + if (state->input_stage){ + if (ui_do_line_field_input(system, state, string)){ + result = 1; + } + } + else{ + Render_Target *target = state->target; + u32 back = style->main.margin_color; + u32 fore = style->main.default_color; + draw_rectangle(target, box, back); + i32 x = box.x0; + x = draw_string(target, font_id, string->str, x, box.y0, fore); + } + + layout->y = box.y1; + return result; +} + +internal b32 +do_list_option(i32 id, UI_State *state, UI_Layout *layout, String text){ + b32 result = 0; + Style *style = state->style; + + i16 font_id = style->font_id; + i32 character_h = get_font_info(state->font_set, font_id)->height; + + i32_Rect box = layout_rect(layout, character_h*2); + Widget_ID wid = make_id(state, id); + + if (state->input_stage){ + if (ui_do_button_input(state, box, wid, 0)){ + result = 1; + } + } + else{ + Render_Target *target = state->target; + i32_Rect inner = get_inner_rect(box, 3); + u32 back, outline, fore, pop; + back = style->main.back_color; + fore = style->main.default_color; + pop = style->main.file_info_style.pop2_color; + if (is_hover(state, wid)) outline = style->main.margin_active_color; + else outline = style->main.margin_color; + + draw_rectangle(target, inner, back); + i32 x = inner.x0, y = box.y0 + character_h/2; + x = draw_string(target, font_id, text, x, y, fore); + draw_margin(target, box, inner, outline); + } + + layout->y = box.y1; + return result; +} + +internal b32 +do_checkbox_list_option(i32 id, UI_State *state, UI_Layout *layout, String text, b32 is_on){ + b32 result = 0; + Style *style = state->style; + + i16 font_id = style->font_id; + i32 character_h = get_font_info(state->font_set, font_id)->height; + + i32_Rect box = layout_rect(layout, character_h*2); + Widget_ID wid = make_id(state, id); + + if (state->input_stage){ + if (ui_do_button_input(state, box, wid, 0)){ + result = 1; + } + } + else{ + Render_Target *target = state->target; + i32_Rect inner = get_inner_rect(box, 3); + u32 back, outline, fore, pop, box_color; + back = style->main.back_color; + fore = style->main.default_color; + pop = style->main.file_info_style.pop2_color; + if (is_hover(state, wid)) outline = style->main.margin_active_color; + else outline = style->main.margin_color; + box_color = style->main.margin_active_color; + + draw_rectangle(target, inner, back); + + i32_Rect square; + square = get_inner_rect(inner, character_h/3); + square.x1 = square.x0 + (square.y1 - square.y0); + if (is_on) draw_rectangle(target, square, box_color); + else draw_margin(target, square, 1, box_color); + + i32 x = square.x1 + 3; + i32 y = box.y0 + character_h/2; + x = draw_string(target, font_id, text, x, y, fore); + draw_margin(target, box, inner, outline); + } + + layout->y = box.y1; + return result; +} + + +internal b32 +do_file_option(i32 id, UI_State *state, UI_Layout *layout, String filename, b32 is_folder, String extra, char slash){ + b32 result = 0; + Style *style = state->style; + i16 font_id = style->font_id; + i32 character_h = get_font_info(state->font_set, font_id)->height; + char slash_buf[2] = { slash, 0 }; + + i32_Rect box = layout_rect(layout, character_h*2); + Widget_ID wid = make_id(state, id); + + if (state->input_stage){ + if (ui_do_button_input(state, box, wid, 0)){ + result = 1; + } + } + else{ + Render_Target *target = state->target; + i32_Rect inner = get_inner_rect(box, 3); + u32 back, outline, fore, pop; + back = style->main.back_color; + fore = style->main.default_color; + pop = style->main.file_info_style.pop2_color; + if (is_hover(state, wid)) outline = style->main.margin_active_color; + else outline = style->main.margin_color; + + draw_rectangle(target, inner, back); + i32 x = inner.x0, y = box.y0 + character_h/2; + x = draw_string(target, font_id, filename, x, y, fore); + if (is_folder) x = draw_string(target, font_id, slash_buf, x, y, fore); + draw_string(target, font_id, extra, x, y, pop); + draw_margin(target, box, inner, outline); + } + + layout->y = box.y1; + return result; +} + +internal b32 +do_file_list_box(System_Functions *system, UI_State *state, UI_Layout *layout, + Hot_Directory *hot_dir, b32 has_filter, b32 try_to_match, b32 case_sensitive, + b32 *new_dir, b32 *selected, char *end){ + b32 result = 0; + File_List *files = &hot_dir->file_list; + + if (do_main_file_box(system, state, layout, hot_dir, try_to_match, case_sensitive, end)){ + *selected = 1; + terminate_with_null(&hot_dir->string); + } + else{ + persist String p4c_extension = make_lit_string("p4c"); + persist String message_loaded = make_lit_string(" LOADED"); + persist String message_unsaved = make_lit_string(" LOADED *"); + persist String message_unsynced = make_lit_string(" LOADED !"); + persist String message_nothing = {}; + + char front_name_space[256]; + String front_name = make_fixed_width_string(front_name_space); + get_front_of_directory(&front_name, hot_dir->string); + + Absolutes absolutes; + get_absolutes(front_name, &absolutes, 1, 1); + + char full_path_[256]; + String full_path = make_fixed_width_string(full_path_); + get_path_of_directory(&full_path, hot_dir->string); + i32 restore_size = full_path.size; + + i32 i; + File_Info *info, *end; + end = files->infos + files->count; + for (info = files->infos, i = 0; info != end; ++info, ++i){ + String filename = info->filename; + + append(&full_path, filename); + terminate_with_null(&full_path); + + Editing_File *file = working_set_contains(state->working_set, full_path); + full_path.size = restore_size; + + b8 is_folder = (info->folder != 0); + b8 ext_match = (match(file_extension(filename), p4c_extension) != 0); + b8 name_match = (filename_match(front_name, &absolutes, filename, case_sensitive) != 0); + b8 is_loaded = (file != 0 && file_is_ready(file)); + + String message = message_nothing; + if (is_loaded){ + switch (buffer_get_sync(file)){ + case SYNC_GOOD: message = message_loaded; break; + case SYNC_BEHIND_OS: message = message_unsynced; break; + case SYNC_UNSAVED: message = message_unsaved; break; + } + } + + if ((is_folder || !has_filter || ext_match) && name_match){ + if (do_file_option(100+i, state, layout, filename, is_folder, message, system->slash)){ + result = 1; + hot_directory_clean_end(hot_dir); + append(&hot_dir->string, filename); + if (is_folder){ + *new_dir = 1; + append(&hot_dir->string, system->slash); + } + else{ + *selected = 1; + } + terminate_with_null(&hot_dir->string); + } + } + } + } + + return result; +} + +internal b32 +do_live_file_list_box(System_Functions *system, UI_State *state, UI_Layout *layout, + Working_Set *working_set, String *string, b32 *selected){ + b32 result = 0; + + if (do_main_string_box(system, state, layout, string)){ + *selected = 1; + terminate_with_null(string); + } + else{ + persist String message_unsaved = make_lit_string(" *"); + persist String message_unsynced = make_lit_string(" !"); + persist String message_nothing = {}; + + Absolutes absolutes; + get_absolutes(*string, &absolutes, 1, 1); + + i32 count = working_set->file_index_count; + Editing_File *files = working_set->files; + for (i32 i = 0; i < count; ++i){ + Editing_File *file = files + i; + + if (!file->state.is_dummy){ + String message = message_nothing; + switch (buffer_get_sync(file)){ + case SYNC_BEHIND_OS: message = message_unsynced; break; + case SYNC_UNSAVED: message = message_unsaved; break; + } + + if (filename_match(*string, &absolutes, file->name.live_name, 1)){ + if (do_file_option(100+i, state, layout, file->name.live_name, 0, message, system->slash)){ + result = 1; + *selected = 1; + copy(string, file->name.source_path); + terminate_with_null(string); + } + } + } + } + } + + return result; +} + + +struct Super_Color{ + Vec4 hsla; + Vec4 rgba; + u32 *out; +}; + +internal Super_Color +super_color_create(u32 packed){ + Super_Color result = {}; + result.rgba = unpack_color4(packed); + result.hsla = rgba_to_hsla(result.rgba); + return result; +} + +internal void +super_color_post_hsla(Super_Color *color, Vec4 hsla){ + color->hsla = hsla; + if (hsla.h == 1.f) + hsla.h = 0.f; + color->rgba = hsla_to_rgba(hsla); + *color->out = pack_color4(color->rgba); +} + +internal void +super_color_post_rgba(Super_Color *color, Vec4 rgba){ + color->rgba = rgba; + color->hsla = rgba_to_hsla(rgba); + *color->out = pack_color4(rgba); +} + +internal void +super_color_post_packed(Super_Color *color, u32 packed){ + color->rgba = unpack_color4(packed); + color->hsla = rgba_to_hsla(color->rgba); + *color->out = packed; +} + +u32 super_color_clear_masks[] = {0xFF00FFFF, 0xFFFF00FF, 0xFFFFFF00}; +u32 super_color_shifts[] = {16, 8, 0}; + +internal u32 +super_color_post_byte(Super_Color *color, i32 channel, u8 byte){ + u32 packed = *color->out; + packed &= super_color_clear_masks[channel]; + packed |= (byte << super_color_shifts[channel]); + super_color_post_packed(color, packed); + return packed; +} + +struct Color_Highlight{ + i32 ids[4]; +}; + +struct Library_UI{ + UI_State *state; + UI_Layout *layout; + + Font_Set *fonts; + + Style_Library *styles; + Hot_Directory *hot_directory; +}; + +struct Color_UI{ + UI_State *state; + UI_Layout *layout; + + Font_Set *fonts; + + f32 hex_advance; + u32 *palette; + i32 palette_size; + + Color_Highlight highlight; + Super_Color color; + + b32 has_hover_color; + Super_Color hover_color; +}; + +enum Channel_Field_Type{ + CF_DEC, + CF_HEX +}; + +internal void +do_single_slider(i32 sub_id, Color_UI *ui, i32 channel, b32 is_rgba, + i32 grad_steps, f32 top, f32_Rect slider, f32 v_handle, + i32_Rect rect){ + f32_Rect click_box = slider; + click_box.y0 -= v_handle; + + if (ui->state->input_stage){ + real32 v; + if (ui_do_slider_input(ui->state, i32R(click_box), make_sub1(ui->state, sub_id), slider.x0, slider.x1, &v)){ + Vec4 new_color; + if (is_rgba) new_color = ui->color.rgba; + else new_color = ui->color.hsla; + new_color.v[channel] = clamp(0.f, v, 1.f); + if (is_rgba) super_color_post_rgba(&ui->color, new_color); + else super_color_post_hsla(&ui->color, new_color); + } + } + else{ + Render_Target *target = ui->state->target; + Vec4 color; + real32 x; + if (is_rgba){ + color = ui->color.rgba; + draw_rgb_slider(target, V4(0,0,0,1.f), channel, 10, 100.f, slider); + } + else{ + i32 steps; + real32 top; + if (channel == 0){ + steps = 45; + top = 360.f; + } + else{ + steps = 10; + top = 100.f; + } + color = ui->color.hsla; + draw_hsl_slider(target, color, channel, steps, top, slider); + } + + x = lerp(slider.x0, color.v[channel], slider.x1); + draw_rectangle( + target, f32R(x, slider.y0, x + 1, slider.y1), 0xff000000); + + draw_rectangle( + target, f32R(x-2, click_box.y0, x+3, slider.y0-4), 0xff777777); + } +} + +internal void +do_hsl_sliders(Color_UI *ui, i32_Rect rect){ + real32 bar_width = (real32)(rect.x1 - rect.x0 - 20); + if (bar_width > 45){ + f32_Rect slider; + real32 y; + i32 sub_id; + + real32 v_full_space = 30.f; + real32 v_half_space = 15.f; + real32 v_quarter_space = 12.f; + real32 v_handle = 9.f; + + slider.x0 = rect.x0 + 10.f; + slider.x1 = slider.x0 + bar_width; + + sub_id = 0; + + i32 step_count[] = {45, 10, 10}; + real32 tops[] = {360.f, 100.f, 100.f}; + + y = rect.y0 + v_quarter_space; + for (i32 i = 0; i < 3; ++i){ + ++sub_id; + slider.y0 = y; + slider.y1 = slider.y0 + v_half_space; + do_single_slider(sub_id, ui, i, 0, step_count[i], tops[i], slider, v_handle, rect); + y += v_full_space; + } + } +} + +internal void +fill_buffer_color_channel(char *buffer, u8 x, Channel_Field_Type ftype){ + if (ftype == CF_DEC){ + u8 x0; + x0 = x / 10; + buffer[2] = (x - (10*x0)) + '0'; + x = x0; + x0 = x / 10; + buffer[1] = (x - (10*x0)) + '0'; + x = x0; + x0 = x / 10; + buffer[0] = (x - (10*x0)) + '0'; + } + else{ + u8 n; + n = x & 0xF; + buffer[1] = int_to_hexchar(n); + x >>= 4; + n = x & 0xF; + buffer[0] = int_to_hexchar(n); + } +} + +internal b32 +do_channel_field(i32 sub_id, Color_UI *ui, u8 *channel, Channel_Field_Type ftype, + i32 y, u32 color, u32 back, i32 x0, i32 x1){ + b32 result = 0; + + i16 font_id = ui->state->font_id; + i32 line_height = get_font_info(ui->state->font_set, font_id)->height; + i32_Rect hit_region; + hit_region.x0 = x0; + hit_region.x1 = x1; + hit_region.y0 = y; + hit_region.y1 = y + line_height; + + i32 digit_count; + if (ftype == CF_DEC) digit_count = 3; + else digit_count = 2; + + Render_Target *target = ui->state->target; + + if (ui->state->input_stage){ + i32 indx; + ui_do_subdivided_button_input(ui->state, hit_region, digit_count, + make_sub1(ui->state, sub_id), 1, &indx); + } + else{ + if (ui->state->hover.sub_id1 == sub_id && ui->state->selected.sub_id1 != sub_id){ + draw_rectangle(target, hit_region, back); + } + } + + char string_buffer[4]; + string_buffer[digit_count] = 0; + fill_buffer_color_channel(string_buffer, *channel, ftype); + + if (ui->state->selected.sub_id1 == sub_id){ + i32 indx = ui->state->selected.sub_id2; + if (ui->state->input_stage){ + Key_Summary *keys = ui->state->keys; + for (i32 key_i = 0; key_i < keys->count; ++key_i){ + Key_Event_Data key = get_single_key(keys, key_i); + + if (key.keycode == key_right){ + ++indx; + if (indx > digit_count-1) indx = 0; + } + if (key.keycode == key_left){ + --indx; + if (indx < 0) indx = digit_count-1; + } + + i32 new_value = *channel; + if (key.keycode == key_up || key.keycode == key_down){ + i32 place = digit_count-1-indx; + i32 base = (ftype == CF_DEC)?10:0x10; + i32 step_amount = 1; + while (place > 0){ + step_amount *= base; + --place; + } + if (key.keycode == key_down){ + step_amount = 0 - step_amount; + } + new_value += step_amount; + } + + u8 c = (u8)key.character; + bool32 is_good = (ftype == CF_DEC)?char_is_numeric(c):char_is_hex(c); + if (is_good){ + string_buffer[indx] = c; + if (ftype == CF_DEC) + new_value = str_to_int(make_string(string_buffer, 3)); + else + new_value = hexstr_to_int(make_string(string_buffer, 2)); + ++indx; + if (indx > digit_count-1) indx = 0; + } + + if (c == '\n'){ + switch (sub_id){ + case 1: case 2: + case 4: case 5: + ui->state->sub_id1_change = sub_id + 3; break; + + case 7: case 8: + ui->state->sub_id1_change = sub_id - 6; break; + } + } + + if (new_value != *channel){ + if (new_value > 255){ + *channel = 255; + } + else if (new_value < 0){ + *channel = 0; + } + else{ + *channel = (u8)new_value; + } + fill_buffer_color_channel(string_buffer, *channel, ftype); + result = 1; + } + ui->state->selected.sub_id2 = indx; + } + } + else{ + f32_Rect r = f32R(hit_region); + r.x0 += indx*ui->hex_advance+1; + r.x1 = r.x0+ui->hex_advance+1; + draw_rectangle(target, r, back); + } + } + + if (!ui->state->input_stage) + draw_string_mono(target, font_id, string_buffer, + (real32)x0 + 1, (real32)y, ui->hex_advance, + color); + + return result; +} + +internal void +do_rgb_sliders(Color_UI *ui, i32_Rect rect){ + i32 dec_x0, dec_x1; + dec_x0 = rect.x0 + 10; + dec_x1 = TRUNC32(dec_x0 + ui->hex_advance*3 + 2); + + i32 hex_x0, hex_x1; + hex_x0 = dec_x1 + 10; + hex_x1 = TRUNC32(hex_x0 + ui->hex_advance*2 + 2); + + rect.x0 = hex_x1; + real32 bar_width = (real32)(rect.x1 - rect.x0 - 20); + + f32_Rect slider; + f32 y; + i32 sub_id; + u8 channel; + + real32 v_full_space = 30.f; + real32 v_half_space = 15.f; + real32 v_quarter_space = 12.f; + real32 v_handle = 9.f; + + u32 packed_color = *ui->color.out; + + y = rect.y0 + v_quarter_space; + slider.x0 = rect.x0 + 10.f; + slider.x1 = slider.x0 + bar_width; + + sub_id = 0; + + persist i32 shifts[3] = { 16, 8, 0 }; + persist u32 fore_colors[3] = { 0xFFFF0000, 0xFF00FF00, 0xFF1919FF }; + persist u32 back_colors[3] = { 0xFF222222, 0xFF222222, 0xFF131313 }; + + for (i32 i = 0; i < 3; ++i){ + i32 shift = shifts[i]; + u32 fore = fore_colors[i]; + u32 back = back_colors[i]; + + ++sub_id; + channel = (packed_color >> shift) & 0xFF; + if (do_channel_field(sub_id, ui, &channel, CF_DEC, + (i32)y, fore, back, dec_x0, dec_x1)) + super_color_post_byte(&ui->color, i, channel); + + ++sub_id; + channel = (packed_color >> shift) & 0xFF; + if (do_channel_field(sub_id, ui, &channel, CF_HEX, + (i32)y, fore, back, hex_x0, hex_x1)) + super_color_post_byte(&ui->color, i, channel); + + ++sub_id; + slider.y0 = y; + slider.y1 = slider.y0 + v_half_space; + if (bar_width > 45.f) + do_single_slider(sub_id, ui, i, 1, 10, 100.f, slider, v_handle, rect); + y += v_full_space; + } +} + +struct Blob_Layout{ + i32_Rect rect; + i32 x, y; + i32 size, space; +}; + +internal void +begin_layout(Blob_Layout *layout, i32_Rect rect){ + layout->rect = rect; + layout->x = rect.x0 + 10; + layout->y = rect.y0; + layout->size = 20; + layout->space = 5; +} + +internal void +do_blob(Color_UI *ui, Blob_Layout *layout, u32 color, bool32 *set_me, i32 sub_id){ + i32_Rect rect = layout->rect; + f32_Rect blob; + blob.x0 = (real32)layout->x; + blob.y0 = (real32)layout->y; + blob.x1 = blob.x0 + layout->size; + blob.y1 = blob.y0 + layout->size; + + layout->y += layout->size + layout->space; + if (layout->y + layout->size + layout->space*2 > rect.y1){ + layout->y = rect.y0; + layout->x += layout->size + layout->space; + } + + if (ui->state->input_stage){ + bool32 right = 0; + if (ui_do_button_input(ui->state, i32R(blob), make_sub1(ui->state, sub_id), 0, &right)){ + super_color_post_packed(&ui->color, color); + } + else if (right) *set_me = 1; + } + else{ + Render_Target *target = ui->state->target; + draw_rectangle(target, blob, color); + persist u32 silver = 0xFFa0a0a0; + draw_rectangle_outline(target, blob, silver); + } +} + +inline void +do_blob(Color_UI *ui, Blob_Layout *layout, u32 *color, bool32 *set_me){ + i32 sub_id = (i32)((char*)color - (char*)ui->state->style); + do_blob(ui, layout, *color, set_me, sub_id); +} + +internal void +do_v_divide(Color_UI *ui, Blob_Layout *layout, i32 width){ + i32_Rect rect = layout->rect; + if (layout->y > rect.y0){ + layout->x += layout->size + layout->space; + } + layout->x += width; + layout->y = rect.y0; +} + +internal void +do_palette(Color_UI *ui, i32_Rect rect){ + Style *style = ui->state->style; + Blob_Layout layout; + begin_layout(&layout, rect); + bool32 set_me; + + do_blob(ui, &layout, &style->main.back_color, &set_me); + do_blob(ui, &layout, &style->main.margin_color, &set_me); + do_blob(ui, &layout, &style->main.margin_active_color, &set_me); + + do_blob(ui, &layout, &style->main.cursor_color, &set_me); + do_blob(ui, &layout, &style->main.at_cursor_color, &set_me); + do_blob(ui, &layout, &style->main.mark_color, &set_me); + + do_blob(ui, &layout, &style->main.highlight_color, &set_me); + do_blob(ui, &layout, &style->main.at_highlight_color, &set_me); + + do_blob(ui, &layout, &style->main.default_color, &set_me); + do_blob(ui, &layout, &style->main.comment_color, &set_me); + do_blob(ui, &layout, &style->main.keyword_color, &set_me); + do_blob(ui, &layout, &style->main.str_constant_color, &set_me); + do_blob(ui, &layout, &style->main.char_constant_color, &set_me); + do_blob(ui, &layout, &style->main.int_constant_color, &set_me); + do_blob(ui, &layout, &style->main.float_constant_color, &set_me); + do_blob(ui, &layout, &style->main.bool_constant_color, &set_me); + do_blob(ui, &layout, &style->main.include_color, &set_me); + do_blob(ui, &layout, &style->main.preproc_color, &set_me); + do_blob(ui, &layout, &style->main.special_character_color, &set_me); + + do_blob(ui, &layout, &style->main.highlight_junk_color, &set_me); + do_blob(ui, &layout, &style->main.highlight_white_color, &set_me); + + do_blob(ui, &layout, &style->main.paste_color, &set_me); + + do_blob(ui, &layout, &style->main.file_info_style.bar_color, &set_me); + do_blob(ui, &layout, &style->main.file_info_style.base_color, &set_me); + do_blob(ui, &layout, &style->main.file_info_style.pop1_color, &set_me); + do_blob(ui, &layout, &style->main.file_info_style.pop2_color, &set_me); + + do_v_divide(ui, &layout, 20); + + if (!ui->state->input_stage){ + Render_Target *target = ui->state->target; + draw_string(target, style->font_id, "Global Palette: right click to save color", + layout.x, layout.rect.y0, style->main.default_color); + } + + layout.rect.y0 += layout.size + layout.space; + layout.y = layout.rect.y0; + i32 palette_size = ui->palette_size + 1000; + u32 *color = ui->palette; + for (i32 i = 1000; i < palette_size; ++i, ++color){ + set_me = 0; + do_blob(ui, &layout, *color, &set_me, i); + if (set_me){ + *color = *ui->color.out; + ui->state->redraw = 1; + } + } +} + +internal void +do_sub_button(i32 id, Color_UI *ui, char *text){ + i16 font_id = ui->state->font_id; + i32 line_height = get_font_info(ui->state->font_set, font_id)->height; + i32_Rect rect = layout_rect(ui->layout, line_height + 2); + + if (ui->state->input_stage){ + ui_do_button_input(ui->state, rect, make_sub0(ui->state, id), 1); + } + else{ + Render_Target *target = ui->state->target; + + u32 back_color, text_color; + text_color = 0xFFDDDDDD; + if (ui->state->selected.sub_id0 == id){ + back_color = 0xFF444444; + } + else if (ui->state->hover.sub_id0 == id){ + back_color = 0xFF222222; + } + else{ + back_color = 0xFF111111; + } + + draw_rectangle(target, rect, back_color); + draw_string(target, font_id, text, rect.x0, rect.y0 + 1, + text_color); + } +} + +internal void +do_color_adjuster(Color_UI *ui, u32 *color, + u32 text_color, u32 back_color, char *name){ + i32 id = raw_ptr_dif(color, ui->state->style); + i16 font_id = ui->state->font_id; + i32 character_h = get_font_info(ui->state->font_set, font_id)->height; + u32 text = 0, back = 0; + + i32_Rect bar = layout_rect(ui->layout, character_h); + + if (ui->state->input_stage){ + if (ui_do_button_input(ui->state, bar, make_id(ui->state, id), 1)){ + ui->has_hover_color = 1; + ui->hover_color = super_color_create(*color); + } + } + + else{ + Render_Target *target = ui->state->target; + u32 text_hover = 0xFF101010; + u32 back_hover = 0xFF999999; + if (ui->state->selected.id != id && ui->state->hover.id == id){ + text = text_hover; + back = back_hover; + } + else{ + text = text_color; + back = back_color; + } + + draw_rectangle(target, bar, back); + i32 end_pos = draw_string(target, font_id, name, bar.x0, bar.y0, text); + + real32 x_spacing = ui->hex_advance; + i32_Rect temp_rect = bar; + temp_rect.x0 = temp_rect.x1 - CEIL32(x_spacing * 9.f); + if (temp_rect.x0 >= end_pos + x_spacing){ + u32 n = *color; + char full_hex_string[] = "0x000000"; + for (i32 i = 7; i >= 2; --i){ + i32 m = (n & 0xF); + n >>= 4; + full_hex_string[i] = int_to_hexchar(m); + } + draw_string_mono(target, font_id, full_hex_string, + (f32)temp_rect.x0, (f32)bar.y0, + x_spacing, text); + } + + for (i32 i = 0; i < ArrayCount(ui->highlight.ids); ++i){ + if (ui->highlight.ids[i] == id){ + draw_rectangle_outline(target, f32R(bar), text_color); + break; + } + } + } + + if (ui->state->selected.id == id){ + Render_Target *target = ui->state->target; + i32_Rect expanded = layout_rect(ui->layout, 115 + (character_h + 2)); + UI_Layout_Restore restore = begin_sub_layout(ui->layout, expanded); + + ui->color.out = color; + + if (ui->state->input_stage){ + if (ui->state->selected.sub_id0 == 0){ + ui->state->selected.sub_id0 = 1; + } + } + else{ + draw_rectangle(target, expanded, 0xff000000); + } + + begin_row(ui->layout, 3); + do_sub_button(1, ui, "HSL"); + do_sub_button(2, ui, "RGB"); + do_sub_button(3, ui, "Palette"); + + i32_Rect sub_rect; + sub_rect = expanded; + sub_rect.y0 += 10 + character_h; + + switch (ui->state->selected.sub_id0){ + case 1: do_hsl_sliders(ui, sub_rect); break; + case 2: do_rgb_sliders(ui, sub_rect); break; + case 3: do_palette(ui, sub_rect); break; + } + + end_sub_layout(restore); + } +} + +internal void +do_style_name(Color_UI *ui){ + i32 id = -3; + + i16 font_id = ui->state->font_id; + i32 line_height = get_font_info(ui->state->font_set, font_id)->height; + + i32_Rect srect = layout_rect(ui->layout, line_height); + + Widget_ID wid = make_id(ui->state, id); + b32 selected = is_selected(ui->state, wid); + + if (ui->state->input_stage){ + if (!selected){ + ui_do_button_input(ui->state, srect, wid, 1); + } + else{ + Style *style = ui->state->style; + if (ui_do_text_field_input(ui->state, &style->name)){ + ui->state->selected = {}; + } + } + } + else{ + Render_Target *target = ui->state->target; + Style *style = ui->state->style; + u32 back, fore_text, fore_label; + if (selected){ + back = 0xFF000000; + fore_label = 0xFF808080; + fore_text = 0xFFFFFFFF; + } + else if (is_hover(ui->state, wid)){ + back = 0xFF999999; + fore_text = fore_label = 0xFF101010; + } + else{ + back = style->main.back_color; + fore_text = fore_label = style->main.default_color; + } + + draw_rectangle(target, srect, back); + i32 x = srect.x0; + x = draw_string(target, font_id, "NAME: ", + x, srect.y0, fore_label); + x = draw_string(target, font_id, style->name.str, + x, srect.y0, fore_text); + } +} + +internal b32 +do_font_option(Color_UI *ui, i16 font_id){ + b32 result = 0; + Font_Info *info = get_font_info(ui->state->font_set, font_id); + + i32 sub_id = (i32)(i64)(info); + i32_Rect orect = layout_rect(ui->layout, info->height); + + Widget_ID wid = make_sub0(ui->state, sub_id); + if (ui->state->input_stage){ + if (ui_do_button_input(ui->state, orect, wid, 0)){ + result = 1; + } + } + else{ + Render_Target *target = ui->state->target; + u32 back, fore; + if (is_hover(ui->state, wid)){ + back = 0xFF999999; + fore = 0xFF101010; + } + else{ + back = 0xFF000000; + fore = 0xFFFFFFFF; + } + draw_rectangle(target, orect, back); + i32 x = orect.x0; + x = draw_string(target, font_id, "->", x, orect.y0, fore); + draw_string(target, font_id, info->name.str, x, orect.y0, fore); + } + + return result; +} + +internal void +do_font_switch(Color_UI *ui){ + i32 id = -2; + Render_Target *target = ui->state->target; + Font_Set *font_set = ui->state->font_set; + + i16 font_id = ui->state->font_id; + Font_Info *info = get_font_info(font_set, font_id); + i32 character_h = info->height; + + i32_Rect srect = layout_rect(ui->layout, character_h); + Widget_ID wid = make_id(ui->state, id); + + if (ui->state->input_stage){ + ui_do_button_input(ui->state, srect, wid, 1); + } + else{ + Style *style = ui->state->style; + u32 back, fore; + if (is_hover(ui->state, wid) && !is_selected(ui->state, wid)){ + back = 0xFF999999; + fore = 0xFF101010; + } + else{ + back = style->main.back_color; + fore = style->main.default_color; + } + draw_rectangle(target, srect, back); + i32 x = srect.x0; + x = draw_string(target, font_id, "FONT: ", + x, srect.y0, fore); + x = draw_string(target, font_id, info->name.str, + x, srect.y0, fore); + } + + if (is_selected(ui->state, wid)){ + srect = layout_rect(ui->layout, character_h/2); + if (!ui->state->input_stage) + draw_rectangle(target, srect, 0xFF000000); + + i32 count = font_set->count + 1; + + for (i16 i = 1; i < count; ++i){ + if (i == font_id) continue; + if (do_font_option(ui, i)){ + ui->state->style->font_id = i; + ui->state->style->font_changed = 1; + } + } + + srect = layout_rect(ui->layout, character_h/2); + if (!ui->state->input_stage) + draw_rectangle(target, srect, 0xFF000000); + } +} + +internal b32 +do_style_preview(Library_UI *ui, Style *style, i32 toggle = -1){ + b32 result = 0; + i32 id; + if (style == ui->state->style) id = 2; + else id = raw_ptr_dif(style, ui->styles->styles) + 100; + + i16 font_id = style->font_id; + Font_Info *info = get_font_info(ui->state->font_set, font_id); + + i32_Rect prect = layout_rect(ui->layout, info->height*3 + 6); + + Widget_ID wid = make_id(ui->state, id); + + if (ui->state->input_stage){ + if (ui_do_button_input(ui->state, prect, wid, 0)){ + result = 1; + } + } + else{ + Render_Target *target = ui->state->target; + u32 margin_color = style->main.margin_color; + if (is_hover(ui->state, wid)){ + margin_color = style->main.margin_active_color; + } + + i32_Rect inner; + if (toggle != -1){ + i32_Rect toggle_box = prect; + toggle_box.x1 = toggle_box.x0 + info->height*2 + 6; + prect.x0 = toggle_box.x1; + + inner = get_inner_rect(toggle_box, 3); + draw_margin(target, toggle_box, inner, margin_color); + draw_rectangle(target, inner, style->main.back_color); + + i32 d; + d = info->height/2; + i32_Rect b; + b.x0 = (inner.x1 + inner.x0)/2 - d; + b.y0 = (inner.y1 + inner.y0)/2 - d; + b.x1 = b.x0 + info->height; + b.y1 = b.y0 + info->height; + if (toggle) draw_rectangle(target, b, margin_color); + else draw_rectangle_outline(target, b, margin_color); + } + + inner = get_inner_rect(prect, 3); + draw_margin(target, prect, inner, margin_color); + draw_rectangle(target, inner, style->main.back_color); + + i32 text_y = inner.y0; + i32 text_x = inner.x0; + text_x = draw_string(target, font_id, style->name.str, + text_x, text_y, style->main.default_color); + i32 font_x = (i32)(inner.x1 - font_string_width(target, font_id, info->name.str)); + if (font_x > text_x + 10) + draw_string(target, font_id, info->name.str, + font_x, text_y, style->main.default_color); + + text_x = inner.x0; + text_y += info->height; + text_x = draw_string(target, font_id, "if ", text_x, text_y, + style->main.keyword_color); + text_x = draw_string(target, font_id, "(x < ", text_x, text_y, + style->main.default_color); + text_x = draw_string(target, font_id, "0", text_x, text_y, + style->main.int_constant_color); + text_x = draw_string(target, font_id, ") { x = ", text_x, text_y, + style->main.default_color); + text_x = draw_string(target, font_id, "0", text_x, text_y, + style->main.int_constant_color); + text_x = draw_string(target, font_id, "; } ", text_x, text_y, + style->main.default_color); + text_x = draw_string(target, font_id, "// comment", text_x, text_y, + style->main.comment_color); + + text_x = inner.x0; + text_y += info->height; + text_x = draw_string(target, font_id, "[] () {}; * -> +-/ <>= ! && || % ^", + text_x, text_y, style->main.default_color); + } + + ui->layout->y = prect.y1; + return result; +} // BOTTOM diff --git a/4ed_interactive_view.cpp b/4ed_interactive_view.cpp deleted file mode 100644 index 6ef77bad..00000000 --- a/4ed_interactive_view.cpp +++ /dev/null @@ -1,233 +0,0 @@ -/* - * Mr. 4th Dimention - Allen Webster - * - * 19.09.2015 - * - * File editing view for 4coder - * - */ - -// TOP - -enum Interactive_View_Action{ - INTV_OPEN, - INTV_SAVE_AS, - INTV_NEW, - INTV_SWITCH, - INTV_KILL, - INTV_SURE_TO_KILL -}; - -enum Interactive_View_Interaction{ - INTV_SYS_FILE_LIST, - INTV_LIVE_FILE_LIST, - INTV_SURE_TO_KILL_INTER -}; - -struct Interactive_View{ - View view_base; - Hot_Directory *hot_directory; - Style *style; - Working_Set *working_set; - Delay *delay; - Font_Set *font_set; - UI_State state; - Interactive_View_Interaction interaction; - Interactive_View_Action action; - int finished; - - char query_[256]; - String query; - char dest_[256]; - String dest; - i32 user_action; -}; - -inline Interactive_View* -view_to_interactive_view(View *view){ - Interactive_View *result = 0; - if (view->type == VIEW_TYPE_INTERACTIVE) - result = (Interactive_View*)view; - return result; -} - -internal void -interactive_view_complete(Interactive_View *view){ - Panel *panel = view->view_base.panel; - switch (view->action){ - case INTV_OPEN: - delayed_open(view->delay, view->hot_directory->string, panel); - break; - - case INTV_SAVE_AS: - delayed_save_as(view->delay, view->hot_directory->string, panel); - delayed_close_minor(view->delay, panel); - break; - - case INTV_NEW: - delayed_new(view->delay, view->hot_directory->string, panel); - break; - - case INTV_SWITCH: - delayed_switch(view->delay, view->dest, panel); - break; - - case INTV_KILL: - delayed_try_kill(view->delay, view->dest, panel); - break; - - case INTV_SURE_TO_KILL: - switch (view->user_action){ - case 0: - delayed_kill(view->delay, view->dest, panel); - delayed_close_minor(view->delay, {}, panel); - break; - - case 1: - delayed_close_minor(view->delay, {}, panel); - break; - - case 2: - delayed_save(view->delay, view->dest, panel); - delayed_kill(view->delay, view->dest, panel); - delayed_close_minor(view->delay, {}, panel); - break; - } - break; -} -} - -internal i32 -step_draw_int_view(System_Functions *system, Interactive_View *view, - Render_Target *target, i32_Rect rect, - Input_Summary *user_input, b32 input_stage){ - if (view->finished) return 0; - i32 result = 0; - - UI_State state = - ui_state_init(&view->state, target, user_input, - view->style, view->font_set, view->working_set, input_stage); - - UI_Layout layout; - begin_layout(&layout, rect); - - b32 new_dir = 0; - b32 complete = 0; - - do_label(&state, &layout, view->query, 1.f); - - b32 case_sensitive = 0; - - switch (view->interaction){ - case INTV_SYS_FILE_LIST: - { - b32 is_new = (view->action == INTV_NEW); - - if (do_file_list_box(system, &state, - &layout, view->hot_directory, 0, !is_new, case_sensitive, - &new_dir, &complete, 0)){ - result = 1; - } - if (new_dir){ - hot_directory_reload(system, - view->hot_directory, view->working_set); - } - }break; - - case INTV_LIVE_FILE_LIST: - if (do_live_file_list_box(system, &state, &layout, view->working_set, &view->dest, &complete)){ - result = 1; - } - break; - - case INTV_SURE_TO_KILL_INTER: - { - i32 action = -1; - char s_[256]; - String s = make_fixed_width_string(s_); - append(&s, view->dest); - append(&s, " has unsaved changes, kill it?"); - do_label(&state, &layout, s, 1.f); - - i32 id = 0; - if (do_list_option(++id, &state, &layout, make_lit_string("(Y)es"))){ - action = 0; - } - - if (do_list_option(++id, &state, &layout, make_lit_string("(N)o"))){ - action = 1; - } - - if (do_list_option(++id, &state, &layout, make_lit_string("(S)ave and kill"))){ - action = 2; - } - - if (action == -1 && input_stage){ - i32 key_count = user_input->keys.count; - for (i32 i = 0; i < key_count; ++i){ - Key_Event_Data key = user_input->keys.keys[i]; - switch (key.character){ - case 'y': case 'Y': action = 0; break; - case 'n': case 'N': action = 1; break; - case 's': case 'S': action = 2; break; - } - if (action == -1 && key.keycode == key_esc) action = 1; - if (action != -1) break; - } - } - - if (action != -1){ - complete = 1; - view->user_action = action; - } - }break; - } - - if (complete){ - view->finished = 1; - interactive_view_complete(view); - } - - if (ui_finish_frame(&view->state, &state, &layout, rect, 0, 0)){ - result = 1; - } - - return result; -} - -Do_View_Sig(do_interactive_view){ - i32 result = 0; - - view->mouse_cursor_type = APP_MOUSE_CURSOR_ARROW; - Interactive_View *int_view = (Interactive_View*)view; - switch (message){ - case VMSG_STEP: case VMSG_DRAW: - result = step_draw_int_view(system, int_view, target, rect, user_input, (message == VMSG_STEP)); - break; - } - - return result; -} - -internal Interactive_View* -interactive_view_init(System_Functions *system, View *view, - Hot_Directory *hot_dir, Style *style, - Working_Set *working_set, Font_Set *font_set, Delay *delay){ - Interactive_View *result = (Interactive_View*)view; - view->type = VIEW_TYPE_INTERACTIVE; - view->do_view = do_interactive_view; - result->hot_directory = hot_dir; - hot_directory_clean_end(hot_dir); - hot_directory_reload(system, hot_dir, working_set); - result->query = make_fixed_width_string(result->query_); - result->dest = make_fixed_width_string(result->dest_); - result->style = style; - result->working_set = working_set; - result->font_set = font_set; - result->delay = delay; - result->finished = 0; - return result; -} - -// BOTTOM - diff --git a/4ed_layout.cpp b/4ed_layout.cpp index e9d60591..05becd9d 100644 --- a/4ed_layout.cpp +++ b/4ed_layout.cpp @@ -42,32 +42,13 @@ struct View; typedef Do_View_Sig(Do_View_Function); -// TODO(allen): this shouldn't exist -enum View_Type{ - VIEW_TYPE_NONE, - VIEW_TYPE_FILE, - VIEW_TYPE_COLOR, - VIEW_TYPE_INTERACTIVE, - VIEW_TYPE_MENU, - VIEW_TYPE_CONFIG -}; - struct Panel; struct View{ - union{ - View *next_free; - View *major; - View *minor; - }; + View *next_free; Panel *panel; Command_Map *map; Do_View_Function *do_view; - Mem_Options *mem; - i32 type; - i32 block_size; Application_Mouse_Cursor mouse_cursor_type; - b32 is_active; - b32 is_minor; }; struct Live_Views{ @@ -168,8 +149,6 @@ live_set_alloc_view(Live_Views *live_set, Mem_Options *mem){ live_set->free_view = result->next_free; memset(result, 0, live_set->stride); ++live_set->count; - result->is_active = 1; - result->mem = mem; return result; } @@ -180,13 +159,11 @@ live_set_free_view(System_Functions *system, Exchange *exchange, Live_Views *liv view->next_free = live_set->free_view; live_set->free_view = view; --live_set->count; - view->is_active = 0; } inline void view_set_first(View *new_view, Panel *panel){ new_view->panel = panel; - new_view->minor = 0; panel->view = new_view; } @@ -194,47 +171,11 @@ inline void view_replace_major(System_Functions *system, Exchange *exchange, View *new_view, Panel *panel, Live_Views *live_set){ View *view = panel->view; - if (view->is_minor && view->major){ - live_set_free_view(system, exchange, live_set, view->major); - } live_set_free_view(system, exchange, live_set, view); new_view->panel = panel; - new_view->minor = 0; panel->view = new_view; } -inline void -view_replace_minor(System_Functions *system, Exchange *exchange, - View *new_view, Panel *panel, Live_Views *live_set){ - View *view = panel->view; - - new_view->is_minor = 1; - if (view->is_minor){ - new_view->major = view->major; - live_set_free_view(system, exchange, live_set, view); - } - else{ - new_view->major = view; - view->is_active = 0; - } - new_view->panel = panel; - panel->view = new_view; -} - -inline void -view_remove_minor(System_Functions *system, Exchange *exchange, - Panel *panel, Live_Views *live_set){ - View *view = panel->view; - View *major = view; - if (view->is_minor){ - major = view->major; - live_set_free_view(system, exchange, live_set, view); - } - Assert(major); - panel->view = major; - major->is_active = 1; -} - struct Divider_And_ID{ Panel_Divider* divider; i32 id; diff --git a/4ed_menu_view.cpp b/4ed_menu_view.cpp deleted file mode 100644 index 7f6fe2a5..00000000 --- a/4ed_menu_view.cpp +++ /dev/null @@ -1,91 +0,0 @@ -/* - * Mr. 4th Dimention - Allen Webster - * - * 26.09.2015 - * - * File editing view for 4coder - * - */ - -// TOP - -struct Menu_View{ - View view_base; - Style *style; - Working_Set *working_set; - Delay *delay; - Font_Set *font_set; - UI_State state; -}; - -inline Menu_View* -view_to_menu_view(View *view){ - Menu_View *result = 0; - if (view->type == VIEW_TYPE_MENU){ - result = (Menu_View*)view; - } - return result; -} - -internal i32 -step_draw_menu_view(Menu_View *view, Render_Target *target, i32_Rect rect, - Input_Summary *user_input, b32 input_stage){ - i32 result = 0; - - UI_State state = - ui_state_init(&view->state, target, user_input, - view->style, view->font_set, view->working_set, input_stage); - - UI_Layout layout; - begin_layout(&layout, rect); - - i32 id = 0; - - do_label(&state, &layout, literal("Menu"), 2.f); - - if (do_list_option(++id, &state, &layout, make_lit_string("Theme Options"))){ - delayed_theme_options(view->delay, {}, view->view_base.panel); - } - - if (do_list_option(++id, &state, &layout, make_lit_string("Keyboard Layout Options"))){ - delayed_keyboard_options(view->delay, {}, view->view_base.panel); - } - - if (ui_finish_frame(&view->state, &state, &layout, rect, 0, 0)){ - result = 1; - } - - return result; -} - -Do_View_Sig(do_menu_view){ - i32 result = 0; - - Menu_View *menu_view = (Menu_View*)view; - switch (message){ - case VMSG_STEP: case VMSG_DRAW: - result = step_draw_menu_view(menu_view, target, rect, user_input, (message == VMSG_STEP)); - break; - } - - return result; -} - -internal Menu_View* -menu_view_init(View *view, Style *style, Working_Set *working_set, - Delay *delay, Font_Set *font_set){ - view->type = VIEW_TYPE_INTERACTIVE; - view->do_view = do_menu_view; - - Menu_View *result; - result = (Menu_View*)view; - result->style = style; - result->working_set = working_set; - result->delay = delay; - result->font_set = font_set; - return result; -} - -// BOTTOM - - diff --git a/4ed_metagen.cpp b/4ed_metagen.cpp index 5f0479ae..c3cbb926 100644 --- a/4ed_metagen.cpp +++ b/4ed_metagen.cpp @@ -108,7 +108,6 @@ char* generate_keycode_enum(){ return(filename); } - char daction_enum_name[] = "Action_Type"; char *daction_enum[] = { "OPEN", @@ -120,9 +119,6 @@ char *daction_enum[] = { "SWITCH", "TRY_KILL", "KILL", - "CLOSE_MINOR", - "THEME_OPTIONS", - "KEYBOARD_OPTIONS" }; char str_alloc_copy[] = diff --git a/4ed_version.h b/4ed_version.h new file mode 100644 index 00000000..264558e3 --- /dev/null +++ b/4ed_version.h @@ -0,0 +1,19 @@ +/* + * Mr. 4th Dimention - Allen Webster + * + * 01.03.2016 + * + * Shared header for version stuff + * + */ + +#define VERSION_NUMBER "alpha 3.4.4" + +#ifdef FRED_SUPER +#define VERSION_TYPE " super!" +#else +#define VERSION_TYPE "" +#endif + +#define VERSION VERSION_NUMBER VERSION_TYPE + diff --git a/win32_4ed.cpp b/win32_4ed.cpp index 295354e4..80e4c4ae 100644 --- a/win32_4ed.cpp +++ b/win32_4ed.cpp @@ -9,6 +9,7 @@ // TOP +#include "4ed_version.h" #include "4ed_config.h" #include "4ed_meta.h" @@ -1827,7 +1828,7 @@ main(int argc, char **argv){ // TODO(allen): non-fatal diagnostics } -#define WINDOW_NAME "4coder-window" +#define WINDOW_NAME "4coder-window: " VERSION i32 window_x; i32 window_y;