From e9eb2cfe302b2f07eea88a183e02294d3d41baad Mon Sep 17 00:00:00 2001 From: Filippo Crocchini Date: Tue, 16 Sep 2025 01:10:03 +0200 Subject: [PATCH 1/5] Don't show save as if file exists --- src/widgets/open_file_dialog.jai | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/widgets/open_file_dialog.jai b/src/widgets/open_file_dialog.jai index 7b8a3fba3..e22c9f5ef 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)); From c185283eb36edd01fbf5526c844a0deef4b3bf67 Mon Sep 17 00:00:00 2001 From: Filippo Crocchini Date: Tue, 16 Sep 2025 01:10:15 +0200 Subject: [PATCH 2/5] Added new project option --- src/draw.jai | 9 ++++++++ src/widgets/generic_choice_dialog.jai | 2 ++ src/widgets/switch_to_project.jai | 32 +++++++++++++++++++++++++-- 3 files changed, 41 insertions(+), 2 deletions(-) diff --git a/src/draw.jai b/src/draw.jai index 3bf0af75d..ada15cc27 100644 --- a/src/draw.jai +++ b/src/draw.jai @@ -2952,6 +2952,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.show_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); diff --git a/src/widgets/generic_choice_dialog.jai b/src/widgets/generic_choice_dialog.jai index e7c15a3ed..4aaf0116e 100644 --- a/src/widgets/generic_choice_dialog.jai +++ b/src/widgets/generic_choice_dialog.jai @@ -126,6 +126,8 @@ Generic_Choice_Dialog :: struct(Entry_Details: Type) { memory_pool: Flat_Pool; Entry :: struct { + show_icon: bool; + icon: Icon; highlights: [] bool; sort_key: u64; using details: Entry_Details; diff --git a/src/widgets/switch_to_project.jai b/src/widgets/switch_to_project.jai index 321b54d78..124fc923a 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; }; @@ -66,15 +69,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("%/%", projects_dir, new_project_name); + entry_name := sprint("New project '%.focus-config'", project_path); + + fake_project_config := Project_Config.{ 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, show_icon = true, icon = .save }, 0); } } From ae6b2c68b41a5963ce27ca593d9a798c5ef19634 Mon Sep 17 00:00:00 2001 From: Filippo Crocchini Date: Tue, 16 Sep 2025 21:44:01 +0200 Subject: [PATCH 3/5] Actually create the new project and switch to it --- src/deferred_actions.jai | 22 ++++++++++++++++++++-- src/draw.jai | 4 +++- src/widgets/generic_choice_dialog.jai | 1 - src/widgets/switch_to_project.jai | 17 +++++++++++------ 4 files changed, 34 insertions(+), 10 deletions(-) diff --git a/src/deferred_actions.jai b/src/deferred_actions.jai index d5df16013..a46f41c46 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 ada15cc27..10b4210ec 100644 --- a/src/draw.jai +++ b/src/draw.jai @@ -2952,7 +2952,7 @@ 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.show_icon { + 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; @@ -4343,6 +4343,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 4aaf0116e..5f7333fe2 100644 --- a/src/widgets/generic_choice_dialog.jai +++ b/src/widgets/generic_choice_dialog.jai @@ -126,7 +126,6 @@ Generic_Choice_Dialog :: struct(Entry_Details: Type) { memory_pool: Flat_Pool; Entry :: struct { - show_icon: bool; icon: Icon; highlights: [] bool; sort_key: u64; diff --git a/src/widgets/switch_to_project.jai b/src/widgets/switch_to_project.jai index 124fc923a..cf186c0e3 100644 --- a/src/widgets/switch_to_project.jai +++ b/src/widgets/switch_to_project.jai @@ -25,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; @@ -96,13 +100,13 @@ switch_to_project_add_special_entries :: () using switch_to_project_dialog; if new_project_name { - project_path := sprint("%/%", projects_dir, new_project_name); - entry_name := sprint("New project '%.focus-config'", project_path); + project_path := sprint("%/%.focus-config", projects_dir, new_project_name); + entry_name := sprint("New project '%'", project_path); - fake_project_config := Project_Config.{ name = entry_name, path = project_path, config_parent_dir = projects_dir }; + 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, show_icon = true, icon = .save }, 0); + entry := array_insert_at(*filtered, .{ details = fake_project_config, highlights = no_highlights, icon = .save }, 0); } } @@ -155,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; From 6b97f89b489a470108b314d09dc6df08785d057b Mon Sep 17 00:00:00 2001 From: Filippo Crocchini Date: Tue, 16 Sep 2025 22:42:34 +0200 Subject: [PATCH 4/5] Added create or add project to welcome, tweaked alignment --- src/draw.jai | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/src/draw.jai b/src/draw.jai index 10b4210ec..57954390d 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" }, @@ -242,8 +244,6 @@ draw_welcome_screen :: (main_area: Rect) { .{ .search_in_project, "Search In Workspace" }, ]; - right_area = shrink(right_area, margin); - padding_v := floor(4 * dpi_scale); padding_h := floor(6 * dpi_scale); align_x := right_area.w - (right_area.w / GOLDEN_RATIO); @@ -253,10 +253,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 +278,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 { From f7148b012623d40f78ebc21821136293e7611d1e Mon Sep 17 00:00:00 2001 From: Filippo Crocchini Date: Tue, 16 Sep 2025 23:43:16 +0200 Subject: [PATCH 5/5] Restored line I accidentally deleted --- src/draw.jai | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/draw.jai b/src/draw.jai index 57954390d..19a2f47e9 100644 --- a/src/draw.jai +++ b/src/draw.jai @@ -244,6 +244,8 @@ draw_welcome_screen :: (main_area: Rect) { .{ .search_in_project, "Search In Workspace" }, ]; + right_area = shrink(right_area, margin); + padding_v := floor(4 * dpi_scale); padding_h := floor(6 * dpi_scale); align_x := right_area.w - (right_area.w / GOLDEN_RATIO);