/* 4coder_default_framework.cpp - Sets up the basics of the framework that is used for default 4coder behaviour. */ // TOP static Partition global_part; static General_Memory global_general; #if !defined(AUTO_CENTER_AFTER_JUMPS) #define AUTO_CENTER_AFTER_JUMPS true #endif static bool32 auto_center_after_jumps = AUTO_CENTER_AFTER_JUMPS; static char locked_buffer_space[256]; static String locked_buffer = make_fixed_width_string(locked_buffer_space); static View_ID special_note_view_id = 0; static bool32 default_use_scrollbars = false; static bool32 default_use_file_bars = true; View_Paste_Index view_paste_index_[16]; View_Paste_Index *view_paste_index = view_paste_index_ - 1; static char out_buffer_space[1024]; static char command_space[1024]; static char hot_directory_space[1024]; static bool32 suppressing_mouse = false; static ID_Based_Jump_Location prev_location = {0}; static Config_Data global_config = {0}; //////////////////////////////// static void unlock_jump_buffer(void){ locked_buffer.size = 0; } static void lock_jump_buffer(char *name, int32_t size){ if (size <= locked_buffer.memory_size){ copy(&locked_buffer, make_string(name, size)); } } static void lock_jump_buffer(Buffer_Summary buffer){ lock_jump_buffer(buffer.buffer_name, buffer.buffer_name_len); } static View_Summary get_view_for_locked_jump_buffer(Application_Links *app){ View_Summary view = {0}; if (locked_buffer.size > 0){ Buffer_Summary buffer = get_buffer_by_name(app, locked_buffer.str, locked_buffer.size, AccessAll); if (buffer.exists){ view = get_first_view_with_buffer(app, buffer.buffer_id); } else{ unlock_jump_buffer(); } } return(view); } //////////////////////////////// static void new_view_settings(Application_Links *app, View_Summary *view){ if (!default_use_scrollbars){ view_set_setting(app, view, ViewSetting_ShowScrollbar, false); } if (!default_use_file_bars){ view_set_setting(app, view, ViewSetting_ShowFileBar, false); } } static void close_special_note_view(Application_Links *app){ View_Summary special_view = get_view(app, special_note_view_id, AccessAll); if (special_view.exists){ close_view(app, &special_view); } special_note_view_id = 0; } static View_Summary open_special_note_view(Application_Links *app, bool32 create_if_not_exist = true){ View_Summary special_view = get_view(app, special_note_view_id, AccessAll); if (create_if_not_exist && !special_view.exists){ View_Summary view = get_active_view(app, AccessAll); special_view = open_view(app, &view, ViewSplit_Bottom); new_view_settings(app, &special_view); view_set_split_proportion(app, &special_view, .2f); set_active_view(app, &view); special_note_view_id = special_view.view_id; } return(special_view); } static View_Summary get_next_active_panel(Application_Links *app, View_Summary *view_start){ View_ID original_view_id = view_start->view_id; View_Summary view = *view_start; do{ get_view_next_looped(app, &view, AccessAll); if (view.view_id != special_note_view_id){ break; } }while(view.view_id != original_view_id); if (!view.exists){ memset(&view, 0, sizeof(view)); } return(view); } static View_Summary get_prev_active_panel(Application_Links *app, View_Summary *view_start){ View_ID original_view_id = view_start->view_id; View_Summary view = *view_start; do{ get_view_prev_looped(app, &view, AccessAll); if (view.view_id != special_note_view_id){ break; } }while(view.view_id != original_view_id); if (!view.exists){ memset(&view, 0, sizeof(view)); } return(view); } CUSTOM_COMMAND_SIG(change_active_panel) CUSTOM_DOC("Change the currently active panel, moving to the panel with the next highest view_id.") { View_Summary view = get_active_view(app, AccessAll); view = get_next_active_panel(app, &view); if (view.exists){ set_active_view(app, &view); } } CUSTOM_COMMAND_SIG(change_active_panel_backwards) CUSTOM_DOC("Change the currently active panel, moving to the panel with the next lowest view_id.") { View_Summary view = get_active_view(app, AccessAll); view = get_prev_active_panel(app, &view); if (view.exists){ set_active_view(app, &view); } } CUSTOM_COMMAND_SIG(open_panel_vsplit) CUSTOM_DOC("Create a new panel by vertically splitting the active panel.") { View_Summary view = get_active_view(app, AccessAll); View_Summary new_view = open_view(app, &view, ViewSplit_Right); new_view_settings(app, &new_view); view_set_buffer(app, &new_view, view.buffer_id, 0); } CUSTOM_COMMAND_SIG(open_panel_hsplit) CUSTOM_DOC("Create a new panel by horizontally splitting the active panel.") { View_Summary view = get_active_view(app, AccessAll); View_Summary new_view = open_view(app, &view, ViewSplit_Bottom); new_view_settings(app, &new_view); view_set_buffer(app, &new_view, view.buffer_id, 0); } //////////////////////////////// static void set_mouse_suppression(Application_Links *app, int32_t suppress){ if (suppress){ suppressing_mouse = 1; show_mouse_cursor(app, MouseCursorShow_Never); } else{ suppressing_mouse = 0; show_mouse_cursor(app, MouseCursorShow_Always); } } CUSTOM_COMMAND_SIG(suppress_mouse) CUSTOM_DOC("Hides the mouse and causes all mosue input (clicks, position, wheel) to be ignored.") { set_mouse_suppression(app, true); } CUSTOM_COMMAND_SIG(allow_mouse) CUSTOM_DOC("Shows the mouse and causes all mouse input to be processed normally.") { set_mouse_suppression(app, false); } CUSTOM_COMMAND_SIG(toggle_mouse) CUSTOM_DOC("Toggles the mouse suppression mode, see suppress_mouse and allow_mouse.") { set_mouse_suppression(app, !suppressing_mouse); } CUSTOM_COMMAND_SIG(toggle_fullscreen) CUSTOM_DOC("Toggle fullscreen mode on or off. The change(s) do not take effect until the next frame.") { set_fullscreen(app, !is_fullscreen(app)); } //////////////////////////////// CUSTOM_COMMAND_SIG(remap_interactive) CUSTOM_DOC("Switch to a named key binding map.") { Query_Bar bar = {0}; char space[1024]; bar.prompt = make_lit_string("Map Name: "); bar.string = make_fixed_width_string(space); if (!query_user_string(app, &bar)) return; change_mapping(app, bar.string); } //////////////////////////////// #if 0 static bool32 get_current_name(char **name_out, int32_t *len_out){ bool32 result = false; *name_out = 0; if (user_name.str[0] != 0){ *name_out = user_name.str; *len_out = user_name.size; result = true; } return(result); } static String get_default_theme_name(void){ String str = default_theme_name; if (str.size == 0){ str = make_lit_string("4coder"); } return(str); } static String get_default_font_name(void){ String str = default_font_name; if (str.size == 0){ str = make_lit_string("Liberation Mono"); } return(str); } #endif //////////////////////////////// static bool32 descriptions_match(Face_Description *a, Face_Description *b){ bool32 result = false; if (match(a->font.name, b->font.name) && a->font.in_local_font_folder == b->font.in_local_font_folder){ if (memcmp((&a->pt_size), (&b->pt_size), sizeof(*a) - sizeof(a->font)) == 0){ result = true; } } return(result); } static Face_ID get_existing_face_id_matching_name(Application_Links *app, char *name, int32_t len){ String name_str = make_string(name, len); Face_ID largest_id = get_largest_face_id(app); Face_ID result = 0; for (Face_ID id = 1; id <= largest_id; ++id){ Face_Description compare = get_face_description(app, id); if (match(compare.font.name, name_str)){ result = id; break; } } return(result); } static Face_ID get_existing_face_id_matching_description(Application_Links *app, Face_Description *description){ Face_ID largest_id = get_largest_face_id(app); Face_ID result = 0; for (Face_ID id = 1; id <= largest_id; ++id){ Face_Description compare = get_face_description(app, id); if (descriptions_match(&compare, description)){ result = id; break; } } return(result); } static Face_ID get_face_id_by_name(Application_Links *app, char *name, int32_t len, Face_Description *base_description){ Face_ID new_id = 0; String str = make_string(name, len); if (!match(str, base_description->font.name)){ new_id = get_existing_face_id_matching_name(app, name, len); if (new_id == 0){ Face_Description description = *base_description; copy_fast_unsafe_cs(description.font.name, str); description.font.name[str.size] = 0; description.font.in_local_font_folder = false; new_id = try_create_new_face(app, &description); if (new_id == 0){ description.font.in_local_font_folder = true; new_id = try_create_new_face(app, &description); } } } return(new_id); } static void change_font(Application_Links *app, char *name, int32_t len, bool32 apply_to_all_buffers){ Face_ID global_face_id = get_face_id(app, 0); Face_Description description = get_face_description(app, global_face_id); Face_ID new_id = get_face_id_by_name(app, name, len, &description); if (new_id != 0){ set_global_face(app, new_id, apply_to_all_buffers); } } static void buffer_set_font(Application_Links *app, Buffer_Summary *buffer, char *name, int32_t len){ Face_ID current_id = get_face_id(app, buffer); if (current_id != 0){ Face_Description description = get_face_description(app, current_id); Face_ID new_id = get_face_id_by_name(app, name, len, &description); if (new_id != 0){ buffer_set_face(app, buffer, new_id); } } } static Face_ID get_face_id_by_description(Application_Links *app, Face_Description *description, Face_Description *base_description){ Face_ID new_id = 0; if (!descriptions_match(description, base_description)){ new_id = get_existing_face_id_matching_description(app, description); if (new_id == 0){ new_id = try_create_new_face(app, description); } } return(new_id); } static void change_face_description(Application_Links *app, Face_Description *new_description, bool32 apply_to_all_buffers){ Face_ID global_face_id = get_face_id(app, 0); Face_Description old_description = get_face_description(app, global_face_id); Face_ID new_id = get_face_id_by_description(app, new_description, &old_description); if (new_id != 0){ set_global_face(app, new_id, apply_to_all_buffers); } } static void buffer_set_face_description(Application_Links *app, Buffer_Summary *buffer, Face_Description *new_description){ Face_ID current_id = get_face_id(app, buffer); if (current_id != 0){ Face_Description old_description = get_face_description(app, current_id); Face_ID new_id = get_face_id_by_description(app, new_description, &old_description); if (new_id != 0){ buffer_set_face(app, buffer, new_id); } } } static Face_Description get_buffer_face_description(Application_Links *app, Buffer_Summary *buffer){ Face_ID current_id = get_face_id(app, buffer); Face_Description description = {0}; if (current_id != 0){ description = get_face_description(app, current_id); } return(description); } static Face_Description get_global_face_description(Application_Links *app){ Face_ID current_id = get_face_id(app, 0); Face_Description description = get_face_description(app, current_id); return(description); } //////////////////////////////// static void init_memory(Application_Links *app){ int32_t part_size = (32 << 20); int32_t general_size = (4 << 20); void *part_mem = memory_allocate(app, part_size); global_part = make_part(part_mem, part_size); void *general_mem = memory_allocate(app, general_size); general_memory_open(&global_general, general_mem, general_size); } static void default_4coder_initialize(Application_Links *app, bool32 use_scrollbars, bool32 use_file_bars){ init_memory(app); static const char message[] = "" "Welcome to " VERSION "\n" "If you're new to 4coder there are some tutorials at http://4coder.net/tutorials.html\n" "Direct bug reports to editor@4coder.net for maximum reply speed\n" "Questions or requests can go to editor@4coder.net or to 4coder.handmade.network\n" "\n"; String msg = make_lit_string(message); print_message(app, msg.str, msg.size); load_config_and_apply(app, &global_part, &global_config); load_folder_of_themes_into_live_set(app, &global_part, "themes"); String theme = global_config.default_theme_name; String font = global_config.default_font_name; change_theme(app, theme.str, theme.size); change_font(app, font.str, font.size, true); default_use_scrollbars = use_scrollbars; default_use_file_bars = use_file_bars; } static void default_4coder_initialize(Application_Links *app){ default_4coder_initialize(app, false, true); } static void default_4coder_side_by_side_panels(Application_Links *app, Buffer_Identifier left_buffer, Buffer_Identifier right_buffer){ Buffer_ID left_id = buffer_identifier_to_id(app, left_buffer); Buffer_ID right_id = buffer_identifier_to_id(app, right_buffer); // Left Panel View_Summary view = get_active_view(app, AccessAll); new_view_settings(app, &view); view_set_buffer(app, &view, left_id, 0); // Right Panel open_panel_vsplit(app); View_Summary right_view = get_active_view(app, AccessAll); view_set_buffer(app, &right_view, right_id, 0); // Restore Active to Left set_active_view(app, &view); } static void default_4coder_side_by_side_panels(Application_Links *app, char **command_line_files, int32_t file_count){ Buffer_Identifier left = buffer_identifier(literal("*scratch*")); Buffer_Identifier right = buffer_identifier(literal("*messages*")); if (file_count > 0){ char *left_name = command_line_files[0]; int32_t left_len = str_size(left_name); left = buffer_identifier(left_name, left_len); if (file_count > 1){ char *right_name = command_line_files[1]; int32_t right_len = str_size(right_name); right = buffer_identifier(right_name, right_len); } } default_4coder_side_by_side_panels(app, left, right); } static void default_4coder_side_by_side_panels(Application_Links *app){ default_4coder_side_by_side_panels(app, 0, 0); } static void default_4coder_one_panel(Application_Links *app, Buffer_Identifier buffer){ Buffer_ID id = buffer_identifier_to_id(app, buffer); View_Summary view = get_active_view(app, AccessAll); new_view_settings(app, &view); view_set_buffer(app, &view, id, 0); } static void default_4coder_one_panel(Application_Links *app, char **command_line_files, int32_t file_count){ Buffer_Identifier buffer = buffer_identifier(literal("*messages*")); if (file_count > 0){ char *name = command_line_files[0]; int32_t len = str_size(name); buffer = buffer_identifier(name, len); } default_4coder_one_panel(app, buffer); } static void default_4coder_one_panel(Application_Links *app){ default_4coder_one_panel(app, 0, 0); } // BOTTOM