/* * actions.cpp * Clipboard, rename, delete, and context-menu actions for the embedded desktop file manager * Copyright (c) 2026 Daniel Hammer */ #include "filemanager_internal.hpp" namespace filemanager { static void filemanager_load_clipboard(FileManagerState* fm, bool is_cut) { if (filemanager_is_computer_view(fm) || filemanager_is_virtual_view(fm)) return; if (fm->entry_count <= 0) return; int* sel = (int*)montauk::malloc((uint64_t)fm->entry_count * sizeof(int)); if (!sel) return; int n = filemanager_collect_selection(fm, sel, fm->entry_count); if (n <= 0) { montauk::mfree(sel); return; } if (!filemanager_ensure_clipboard_capacity(fm, n)) { montauk::mfree(sel); return; } int out = 0; for (int i = 0; i < n && out < fm->clipboard_cap; i++) { int idx = sel[i]; if (fm->entry_types[idx] == FM_ENTRY_DRIVE) continue; filemanager_build_fullpath(fm->clipboard_paths[out], 256, fm->current_path, fm->entry_names[idx]); out++; } montauk::mfree(sel); if (out == 0) return; fm->clipboard_count = out; fm->clipboard_is_cut = is_cut; } void filemanager_do_copy(FileManagerState* fm) { filemanager_load_clipboard(fm, false); } void filemanager_do_cut(FileManagerState* fm) { filemanager_load_clipboard(fm, true); } void filemanager_do_paste(FileManagerState* fm) { // Copy/move runs on a worker thread with a progress dialog (a small single // file pastes inline). Same-volume moves use rename (instant, no copy). filemanager_start_paste_job(fm); } void filemanager_start_rename(FileManagerState* fm) { if (fm->selected < 0 || fm->selected >= fm->entry_count) return; if (filemanager_is_computer_view(fm) || filemanager_is_virtual_view(fm) || fm->entry_types[fm->selected] == FM_ENTRY_DRIVE) return; fm->rename_active = true; fm->rename_idx = fm->selected; montauk::strcpy(fm->rename_buf, fm->entry_names[fm->selected]); fm->rename_len = montauk::slen(fm->rename_buf); fm->rename_cursor = fm->rename_len; } void filemanager_finish_rename(FileManagerState* fm) { if (!fm->rename_active) return; fm->rename_active = false; // If name unchanged, skip if (montauk::streq(fm->rename_buf, fm->entry_names[fm->rename_idx])) return; if (fm->rename_len == 0) return; char old_path[512], new_path[512]; filemanager_build_fullpath(old_path, 512, fm->current_path, fm->entry_names[fm->rename_idx]); filemanager_build_fullpath(new_path, 512, fm->current_path, fm->rename_buf); if (montauk::frename(old_path, new_path) != 0) { // Fall back to copy + delete for drivers that don't support rename if (fm->is_dir[fm->rename_idx]) { if (filemanager_copy_dir_recursive(old_path, new_path)) filemanager_delete_recursive(old_path); } else { if (filemanager_copy_file(old_path, new_path)) montauk::fdelete(old_path); } } filemanager_read_dir(fm); } void filemanager_cancel_rename(FileManagerState* fm) { fm->rename_active = false; } void filemanager_new_folder(FileManagerState* fm) { if (filemanager_is_computer_view(fm) || filemanager_is_virtual_view(fm)) return; // Find a unique name char name[64] = "New Folder"; char path[512]; filemanager_build_fullpath(path, 512, fm->current_path, name); int attempt = 1; // Try creating; if it fails, append a number if (montauk::fmkdir(path) != 0) { for (attempt = 2; attempt <= 99; attempt++) { snprintf(name, 64, "New Folder %d", attempt); filemanager_build_fullpath(path, 512, fm->current_path, name); if (montauk::fmkdir(path) == 0) break; } } filemanager_read_dir(fm); // Select the new folder and start rename for (int i = 0; i < fm->entry_count; i++) { if (montauk::streq(fm->entry_names[i], name)) { fm->selected = i; filemanager_start_rename(fm); break; } } } void filemanager_delete_selected(FileManagerState* fm) { if (filemanager_is_computer_view(fm) || filemanager_is_virtual_view(fm)) return; if (fm->entry_count <= 0) return; int* sel = (int*)montauk::malloc((uint64_t)fm->entry_count * sizeof(int)); if (!sel) return; int n = filemanager_collect_selection(fm, sel, fm->entry_count); if (n <= 0) { montauk::mfree(sel); return; } // Filter out drives. int* filtered = (int*)montauk::malloc((uint64_t)n * sizeof(int)); if (!filtered) { montauk::mfree(sel); return; } int fn = 0; bool any_dir = false; for (int i = 0; i < n; i++) { int idx = sel[i]; if (fm->entry_types[idx] == FM_ENTRY_DRIVE) continue; filtered[fn++] = idx; if (fm->is_dir[idx]) any_dir = true; } montauk::mfree(sel); if (fn == 0) { montauk::mfree(filtered); return; } // Anything with a directory or multi-item selection: confirm first. if (any_dir || fn > 1) { if (fn == 1 && any_dir) { filemanager_show_directory_delete_confirmation(fm, filtered[0]); } else { filemanager_show_bulk_delete_confirmation(fm, filtered, fn); } montauk::mfree(filtered); return; } // Single plain file: delete immediately. char fullpath[512]; filemanager_build_fullpath(fullpath, 512, fm->current_path, fm->entry_names[filtered[0]]); montauk::mfree(filtered); montauk::fdelete(fullpath); filemanager_clear_multi_selection(fm); filemanager_read_dir(fm); } void filemanager_open_ctx_menu(FileManagerState* fm, int local_x, int local_y, int target_idx) { fm->ctx_open = true; fm->ctx_x = local_x; fm->ctx_y = local_y; fm->ctx_target_idx = target_idx; fm->ctx_hover = -1; fm->ctx_item_count = 0; if (target_idx >= 0 && target_idx < fm->entry_count) { int tt = fm->entry_types[target_idx]; if ((filemanager_is_computer_view(fm) && (tt == FM_ENTRY_DRIVE || tt == FM_ENTRY_HOME || tt == FM_ENTRY_APPS_ROOT || tt == FM_ENTRY_SPECIAL_DIR || tt == FM_ENTRY_SYSTEM_CONFIGURATION_ROOT)) || (filemanager_is_virtual_view(fm) && tt == FM_ENTRY_VIRTUAL_APP)) { // Drive, Home, Apps shortcut, or app entry: only Open fm->ctx_items[fm->ctx_item_count++] = CTX_OPEN; fm->ctx_items[fm->ctx_item_count++] = CTX_PROPERTIES; } else { fm->ctx_items[fm->ctx_item_count++] = CTX_OPEN; fm->ctx_items[fm->ctx_item_count++] = CTX_COPY; fm->ctx_items[fm->ctx_item_count++] = CTX_CUT; fm->ctx_items[fm->ctx_item_count++] = CTX_RENAME; fm->ctx_items[fm->ctx_item_count++] = CTX_DELETE; fm->ctx_items[fm->ctx_item_count++] = CTX_PROPERTIES; } } else { // Background click if (filemanager_is_virtual_view(fm)) { fm->ctx_open = false; return; } if (filemanager_is_computer_view(fm)) { fm->ctx_items[fm->ctx_item_count++] = CTX_REFRESH; } else { if (fm->clipboard_count > 0) fm->ctx_items[fm->ctx_item_count++] = CTX_PASTE; fm->ctx_items[fm->ctx_item_count++] = CTX_NEW_FOLDER; } } } void filemanager_close_ctx_menu(FileManagerState* fm) { fm->ctx_open = false; fm->ctx_hover = -1; } } // namespace filemanager