diff --git a/src/deferred_actions.jai b/src/deferred_actions.jai index d5df1601..a46f41c4 100644 --- a/src/deferred_actions.jai +++ b/src/deferred_actions.jai @@ -10,8 +10,9 @@ execute_deferred_actions :: () { } } -defer_action_switch_to_project :: (path: string) { +defer_action_switch_to_project :: (path: string, open_project_file := false) { clear_action_queue(); + defer_action_open_file(path); push_action(.reload_workspace, .{ reload_workspace = .{ automatic = false } }); push_action(.load_project_config, .{ load_project_config = .{ path = copy_string(path) } }); push_action(.abort_workspace_scanning); @@ -112,6 +113,9 @@ defer_action_save_buffers :: (buffer_ids: [] s64) { push_action(.save_buffers, .{ save_buffers = .{ buffer_ids = array_copy(buffer_ids) } }); } +defer_action_open_file :: (path: string, placement: Editor_Placement = .in_place ) { + push_action(.open_file, .{ open_file = .{ path = copy_string(path), placement = placement } }); +} Deferred_Action_Id :: #type,distinct s64; @@ -150,6 +154,7 @@ execute_top_action :: () -> Action_Result { case .close_all_editors; return execute_close_all_editors(action); case .close_pane; return execute_close_pane(action); case .close_other_panes; return execute_close_other_panes(action); + case .open_file; return execute_open_file(action); } } @@ -173,6 +178,10 @@ remove_top_action :: () { using action.details.save_buffers; array_free(buffer_ids); + case .open_file; + using action.details.open_file; + if path { free(path); path = ""; } + // Nothing to free case .quit; case .save_as; @@ -216,6 +225,7 @@ Deferred_Action :: struct { close_editor: struct { editor_id: s64; } close_editors_for_pane: struct { pane: *Editor_Pane; except: s64; notify: bool; } close_pane: struct { pane: *Editor_Pane; } + open_file: struct { path: string; placement: Editor_Placement; } } Kind :: enum { @@ -238,6 +248,7 @@ Deferred_Action :: struct { close_all_editors; close_pane; close_other_panes; + open_file; } } @@ -469,7 +480,7 @@ execute_refresh_config_or_theme :: (action: Deferred_Action) -> Action_Result { execute_reload_workspace :: (action: Deferred_Action) -> Action_Result { reload_workspace(action.details.reload_workspace.automatic); - return .CANCEL; // final command + return .DONE; } execute_build_command :: (action: Deferred_Action) -> Action_Result { @@ -543,3 +554,10 @@ execute_close_other_panes :: (action: Deferred_Action) -> Action_Result { return .DONE; } +execute_open_file :: (action: Deferred_Action) -> Action_Result { + print("Before opening file.\n"); + success := editors_open_file(action.details.open_file.path, action.details.open_file.placement); + print("OPENING FILE % -- %\n", action.details.open_file.path, success); + return .DONE; +} + diff --git a/src/draw.jai b/src/draw.jai index 3bf0af75..19a2f47e 100644 --- a/src/draw.jai +++ b/src/draw.jai @@ -182,6 +182,7 @@ draw_welcome_screen :: (main_area: Rect) { margin := logo_rect.x; shrink_step := logo_rect.w / 6.5; + left_y_cursor : float; // Draw the left part { draw_rect(left_area, .BACKGROUND_3, extra_draw_info = .{is_background = true}); @@ -204,25 +205,25 @@ draw_welcome_screen :: (main_area: Rect) { } if version_width < info_area.w { x := (info_area.w - version_width) / 2; - y := info_area.y + info_area.h - shrink_step - font_ui_line_height; - Simp.draw_prepared_text(font, xx x, xx y, color = xx Color.UI_DIM); + left_y_cursor = info_area.y + info_area.h - shrink_step - font_ui_line_height; + Simp.draw_prepared_text(font, xx x, xx left_y_cursor, color = xx Color.UI_DIM); // Copy version when clicking on it { - version_rect := Rect.{ x, y, version_width, font_ui_line_height}; + version_rect := Rect.{ x, left_y_cursor, version_width, font_ui_line_height}; version_ui_id := get_ui_id_from_loc(); clicked := maybe_set_hot_or_active(version_ui_id, version_rect, .PRESSABLE); if clicked { os_clipboard_set_text(version_text); add_success_message("Version copied to clipboard", dismiss_in_seconds = 3); } - if is_hovering_over(version_ui_id) then draw_tooltip_bottom_left("Click to copy to clipboard", Vector2.{ mouse.pointer.x, y }); + if is_hovering_over(version_ui_id) then draw_tooltip_bottom_left("Click to copy to clipboard", Vector2.{ mouse.pointer.x, left_y_cursor }); } date_width := Simp.prepare_text(font_ui_medium, RELEASE_DATE); x = (info_area.w - date_width) / 2; - y -= 1.5 * font_ui_big_line_height; - Simp.draw_prepared_text(font_ui_medium, xx x, xx y, color = xx Color.UI_DIM); + left_y_cursor -= 1.5 * font_ui_big_line_height; + Simp.draw_prepared_text(font_ui_medium, xx x, xx left_y_cursor, color = xx Color.UI_DIM); } } @@ -234,6 +235,7 @@ draw_welcome_screen :: (main_area: Rect) { SHORTCUTS_TO_DISPLAY :: Shortcut.[ .{ .show_commands, "Show All Commands" }, + .{ .switch_to_project, "Open or Create a Project" }, .{ .open_file_by_name, "Open File By Name" }, .{ .navigate_to_file, "Navigate To File" }, .{ .switch_between_open_files, "Switch Between Open Files" }, @@ -253,10 +255,10 @@ draw_welcome_screen :: (main_area: Rect) { line_height = min(line_height, key_height * 3); total_height := line_height * SHORTCUTS_TO_DISPLAY.count - key_height; - - x := right_area.x; - y := logo_rect.y + logo_rect.h - key_height - (logo_rect.h - total_height) / 2; - + + logo_and_info_center := (left_y_cursor + logo_rect.y + logo_rect.h) * 0.5; + y := logo_and_info_center + total_height * 0.5 - key_height; + for shortcut : SHORTCUTS_TO_DISPLAY { key_sequence_strings := get_first_matching_key_sequence_from_action(shortcut.action); @@ -278,7 +280,7 @@ draw_welcome_screen :: (main_area: Rect) { } } - x = right_area.x + align_x - key_sequence_width; + x := right_area.x + align_x - key_sequence_width; text_y := y + padding_v * 1.5; for combo_strings: key_sequence_strings { @@ -2952,6 +2954,15 @@ draw_generic_choice_dialog :: (using dialog: *Generic_Choice_Dialog, ui_id: Ui_I entry_rect.y + (entry_rect.h - font_ui.character_height) / 2 + 2 * dpi_scale, }; + if entry.icon { + icon_char := convert_utf32_to_utf8(xx entry.icon); + icon_width := Simp.prepare_text(font_icons, to_string(*icon_char)); + icon_x := pen.x - (icon_width - font_icons.em_width) / 2.0; + Simp.draw_prepared_text(font_icons, xx icon_x, xx pen.y, color = xx Color.UI_DEFAULT); + + pen.x += xx font_icons.em_width + padding * 1.5; + } + // Draw name width := Simp.draw_text_with_highlights(font_ui, xx pen.x, xx pen.y, entry.name, entry.highlights, color = xx Color.UI_DEFAULT, highlight_color = xx Color.LETTER_HIGHLIGHT); @@ -4334,6 +4345,8 @@ start_scrollbar_fade_out_animation :: (ui_id: Ui_Id, initial_value := -1.0) { #scope_export Icon :: enum u16 { + none :: 0x0; + // File types file_unknown :: 0xf15b; text :: 0xf15c; diff --git a/src/widgets/generic_choice_dialog.jai b/src/widgets/generic_choice_dialog.jai index e7c15a3e..5f7333fe 100644 --- a/src/widgets/generic_choice_dialog.jai +++ b/src/widgets/generic_choice_dialog.jai @@ -126,6 +126,7 @@ Generic_Choice_Dialog :: struct(Entry_Details: Type) { memory_pool: Flat_Pool; Entry :: struct { + icon: Icon; highlights: [] bool; sort_key: u64; using details: Entry_Details; diff --git a/src/widgets/open_file_dialog.jai b/src/widgets/open_file_dialog.jai index 7b8a3fba..e22c9f5e 100644 --- a/src/widgets/open_file_dialog.jai +++ b/src/widgets/open_file_dialog.jai @@ -388,7 +388,8 @@ refresh_entries :: (clear_input := true) { if buffer.modified_on_disk then { entry.flags |= .MODIFIED_ON_DISK; entry.sort_key |= top_priority_bit; } } - filter := construct_fuzzy_filter(to_string(input.text), multi_chunk_search = true); + filter := construct_fuzzy_filter(to_string(input.text), multi_chunk_search = true); + full_path_exists := false; if #complete mode == { case .save; #through; @@ -484,6 +485,8 @@ refresh_entries :: (clear_input := true) { is_dir_part: u64 = (cast,trunc(u64) (entry.type == .folder)) << 56; // directories come first score_part: u64 = (cast,trunc(u64) score) << 16; entry.sort_key = is_dir_part | score_part; + + if it.name == to_string(input.text) then full_path_exists = true; } } @@ -500,7 +503,7 @@ refresh_entries :: (clear_input := true) { } } - if (mode == .save || mode == .move) && !is_empty(input.text) && path_chunks { + if (mode == .save || mode == .move) && !is_empty(input.text) && path_chunks && !full_path_exists { entry_name: string; if mode == .save { entry_name = sprint("Save as '%/%'", get_current_folder_path(), to_string(input.text)); diff --git a/src/widgets/switch_to_project.jai b/src/widgets/switch_to_project.jai index 321b54d7..cf186c0e 100644 --- a/src/widgets/switch_to_project.jai +++ b/src/widgets/switch_to_project.jai @@ -9,6 +9,9 @@ Switch_To_Project_Dialog :: struct { generic_dialog.global_widget_id = .switch_to_project_dialog; generic_dialog.refresh_entries = switch_to_project_refresh_entries; generic_dialog.open_entry = open_selected_project; + generic_dialog.after_refresh = switch_to_project_add_special_entries; + + new_project_name : string; }; @@ -22,12 +25,16 @@ open_selected_project :: (_: Editor_Placement) { entry := filtered[selected]; - defer_action_switch_to_project(entry.path); + if entry.type == .new { + write_entire_file(entry.path, DEFAULT_CONFIG_FILE_DATA); + } + + defer_action_switch_to_project(entry.path, open_project_file = (entry.type == .new)); } switch_to_project_refresh_entries :: (filter: Fuzzy_Filter) { using switch_to_project_dialog; - + assert(context.allocator.proc == flat_pool_allocator_proc, "Non-pool allocator is used in switch_to_project dialog. This is a bug."); project_configs: [..] Project_Config; @@ -66,15 +73,40 @@ switch_to_project_refresh_entries :: (filter: Fuzzy_Filter) { case .alphabetical_no_case; quick_sort(project_configs, (a, b) => compare_alphabetically(a.name, b.name, true)); } - + + full_path_exists := false; + for project : project_configs { - score, highlights := fuzzy_match(project.name, filter); + score, highlights, exact_match := fuzzy_match(project.name, filter); if score <= 0 && filter.full_string continue; entry := array_add(*filtered); entry.details = project; entry.highlights = highlights; entry.sort_key = cast(u64) (score + project_configs.count - it_index); // sort by the list order originally + + if project.name == filter.full_string then full_path_exists = true; + } + + if !full_path_exists { + new_project_name = filter.full_string; + } else { + new_project_name = ""; + } +} + +switch_to_project_add_special_entries :: () +{ + using switch_to_project_dialog; + + if new_project_name { + project_path := sprint("%/%.focus-config", projects_dir, new_project_name); + entry_name := sprint("New project '%'", project_path); + + fake_project_config := Project_Config.{ type = .new, name = entry_name, path = project_path, config_parent_dir = projects_dir }; + no_highlights := NewArray(entry_name.count, bool, true); + + entry := array_insert_at(*filtered, .{ details = fake_project_config, highlights = no_highlights, icon = .save }, 0); } } @@ -127,6 +159,7 @@ compare_alphabetically :: (a : string, b : string, $no_case : bool) -> s64 { } Project_Config :: struct { + type: enum { open; new; }; name: string; path: string; config_parent_dir: string;