/* * filemanager_internal.hpp * Shared declarations for the embedded desktop file manager * Copyright (c) 2026 Daniel Hammer */ #pragma once #include "../apps_common.hpp" #include namespace filemanager { inline constexpr int FM_MAX_DRIVES = 16; enum FileManagerEntryType : int { FM_ENTRY_FILE = 0, FM_ENTRY_DIR = 1, FM_ENTRY_EXEC = 2, FM_ENTRY_DRIVE = 3, FM_ENTRY_HOME = 4, FM_ENTRY_APPS_ROOT = 5, FM_ENTRY_VIRTUAL_APP = 6, FM_ENTRY_SPECIAL_DIR = 7, FM_ENTRY_SYSTEM_CONFIGURATION_ROOT = 8, }; enum FileManagerVirtualViewKind : uint8_t { FM_VIRTUAL_VIEW_NONE = 0, FM_VIRTUAL_VIEW_APPS, FM_VIRTUAL_VIEW_SYSTEM_CONFIGURATION, }; enum FileManagerVirtualEntryKind : uint8_t { FM_VIRTUAL_ENTRY_NONE = 0, FM_VIRTUAL_ENTRY_EXTERNAL_APP, FM_VIRTUAL_ENTRY_SYSTEM_CONFIGURATION_APPLET, }; struct FileManagerLocation { char path[256]; FileManagerVirtualViewKind virtual_view; }; struct FileManagerVirtualEntry { FileManagerVirtualEntryKind kind; int external_app_index; DesktopAppletEntry applet; SvgIcon icon_lg; SvgIcon icon_sm; }; // Hard backstop on entries per directory: protects the pagination loop from a // misbehaving driver and bounds memory. Far above any realistic directory. inline constexpr int FM_ENTRY_HARD_CAP = 8192; // Single-file deletes at or below this size are freed inline; larger files go // to the background worker + progress dialog. Freeing a big file rewrites the // filesystem allocation bitmaps and can take seconds on real disks, which would // otherwise stall the desktop (Files runs inside desktop.elf). inline constexpr uint64_t FILEMANAGER_DELETE_INLINE_MAX_BYTES = 4ull * 1024 * 1024; struct FileManagerState { char current_path[256]; FileManagerLocation history[16]; int history_pos; int history_count; // Parallel per-entry arrays, dynamically grown together to entry_cap. // Allocated lazily via filemanager_ensure_entry_capacity(). char (*entry_names)[128]; int* entry_types; uint64_t* entry_sizes; // 64-bit: avoids overflow on files >= 2 GiB int64_t* entry_mtimes; // last-modified time, UTC unix seconds (0 = unknown) int entry_count; int entry_cap; // allocated capacity of the per-entry arrays int selected; int scroll_offset; bool* is_dir; int last_click_item; uint64_t last_click_time; Scrollbar scrollbar; DesktopState* desktop; bool grid_view; int* drive_indices; // drive number or special-folder index for Computer view entries int* drive_kinds; // kernel BlockDeviceKind for FM_ENTRY_DRIVE entries (4 = USB MSC) // Clipboard (supports multiple paths from a selection), grown to clipboard_cap. char (*clipboard_paths)[256]; int clipboard_cap; int clipboard_count; bool clipboard_is_cut; // Multi-selection (marquee selection), sized with the entry arrays. bool* multi_selected; int multi_count; // Marquee drag state. Coordinates are stored in content space: // x is local_x (window content relative) // y is rel_y (local_y - list_y + scroll_offset), so anchor follows scroll bool marquee_active; int marquee_start_x, marquee_start_y; int marquee_cur_x, marquee_cur_y; // Context menu bool ctx_open; int ctx_x, ctx_y; int ctx_target_idx; // -1 = background int ctx_items[8]; int ctx_item_count; int ctx_hover; // Rename bool rename_active; int rename_idx; char rename_buf[128]; int rename_cursor; int rename_len; // Path bar editing bool pathbar_editing; char pathbar_buf[256]; int pathbar_cursor; int pathbar_len; // Virtual views (sized with the entry arrays) FileManagerVirtualViewKind virtual_view; FileManagerVirtualEntry* virtual_entries; int virtual_entry_count; // Background file operation (copy/move/delete) + its progress dialog. void* active_fileop; // FileOpJob*, non-null while an operation runs // File Manager-owned dialogs void* delete_confirm_dialog; }; inline constexpr int FM_TOOLBAR_H = 32; inline constexpr int FM_PATHBAR_H = 24; inline constexpr int FM_HEADER_H = 20; inline constexpr int FM_ITEM_H = 24; inline constexpr int FM_SCROLLBAR_W = 12; inline constexpr int FM_GRID_CELL_W = 80; inline constexpr int FM_GRID_CELL_H = 80; inline constexpr int FM_GRID_CELL_H_WRAPPED = 92; inline constexpr int FM_GRID_ICON = 48; inline constexpr int FM_GRID_PAD = 4; // Special user folders: name, icon filename, index into DesktopState arrays inline constexpr int SF_COUNT = DesktopState::SPECIAL_FOLDER_COUNT; inline constexpr const char* sf_names[SF_COUNT] = { "Documents", "Desktop", "Music", "Videos", "Pictures", "Downloads" }; inline constexpr const char* sf_icons[SF_COUNT] = { "folder-blue-documents.svg", "folder-blue-desktop.svg", "folder-blue-music.svg", "folder-blue-videos.svg", "folder-blue-pictures.svg", "folder-blue-downloads.svg" }; // Context menu action codes inline constexpr int CTX_OPEN = 0; inline constexpr int CTX_COPY = 1; inline constexpr int CTX_CUT = 2; inline constexpr int CTX_PASTE = 3; inline constexpr int CTX_RENAME = 4; inline constexpr int CTX_DELETE = 5; inline constexpr int CTX_NEW_FOLDER = 6; inline constexpr int CTX_PROPERTIES = 7; inline constexpr int CTX_REFRESH = 8; inline bool filemanager_is_virtual_view(const FileManagerState* fm) { return fm && fm->virtual_view != FM_VIRTUAL_VIEW_NONE; } inline bool filemanager_is_computer_view(const FileManagerState* fm) { return fm && !filemanager_is_virtual_view(fm) && fm->current_path[0] == '\0'; } inline const char* filemanager_virtual_view_label(FileManagerVirtualViewKind view) { switch (view) { case FM_VIRTUAL_VIEW_APPS: return "Apps"; case FM_VIRTUAL_VIEW_SYSTEM_CONFIGURATION: return "Settings"; default: return "Computer"; } } int special_folder_index(const char* name); const char* ctx_label(int action); inline mtk::ContextMenuState filemanager_context_state(const FileManagerState* fm) { if (!fm) return {}; return {fm->ctx_open, fm->ctx_x, fm->ctx_y, fm->ctx_hover}; } inline void filemanager_store_context_state(FileManagerState* fm, const mtk::ContextMenuState& state) { if (!fm) return; fm->ctx_open = state.open; fm->ctx_x = state.x; fm->ctx_y = state.y; fm->ctx_hover = state.hover; } inline void filemanager_build_context_items(const FileManagerState* fm, mtk::ContextMenuItem* items, int max_items) { if (!fm || !items || max_items <= 0) return; int count = fm->ctx_item_count < max_items ? fm->ctx_item_count : max_items; for (int i = 0; i < count; i++) items[i] = {ctx_label(fm->ctx_items[i]), fm->ctx_items[i], true}; } bool str_ends_with(const char* s, const char* suffix); bool is_image_file(const char* name); bool is_font_file(const char* name); bool is_pdf_file(const char* name); bool is_spreadsheet_file(const char* name); bool is_wordprocessor_file(const char* name); bool is_audio_file(const char* name); bool is_video_file(const char* name); int detect_file_type(const char* name, bool is_dir); void filemanager_build_fullpath(char* out, int out_max, const char* dir, const char* name); const char* path_basename(const char* path); // Grow the per-entry parallel arrays to hold at least `needed` entries. // Returns false if allocation fails (callers should stop adding entries). bool filemanager_ensure_entry_capacity(FileManagerState* fm, int needed); // Grow the clipboard path array to hold at least `needed` paths. bool filemanager_ensure_clipboard_capacity(FileManagerState* fm, int needed); // Free all dynamically-allocated arrays (called on window close). void filemanager_free_arrays(FileManagerState* fm); void filemanager_read_drives(FileManagerState* fm); void filemanager_read_dir(FileManagerState* fm); void filemanager_free_app_icons(FileManagerState* fm); void filemanager_read_virtual_view(FileManagerState* fm, FileManagerVirtualViewKind view); void filemanager_read_apps(FileManagerState* fm); void filemanager_read_system_configuration(FileManagerState* fm); bool filemanager_delete_recursive(const char* path); bool filemanager_copy_file(const char* src, const char* dst); bool filemanager_copy_dir_recursive(const char* src, const char* dst); void filemanager_do_copy(FileManagerState* fm); void filemanager_do_cut(FileManagerState* fm); void filemanager_do_paste(FileManagerState* fm); void filemanager_start_rename(FileManagerState* fm); void filemanager_finish_rename(FileManagerState* fm); void filemanager_cancel_rename(FileManagerState* fm); void filemanager_new_folder(FileManagerState* fm); void filemanager_delete_selected(FileManagerState* fm); void filemanager_open_ctx_menu(FileManagerState* fm, int local_x, int local_y, int target_idx); void filemanager_close_ctx_menu(FileManagerState* fm); void props_center_dialog(DesktopState* ds, const void* owner_app_data, int w, int h, int* out_x, int* out_y); void filemanager_show_properties(FileManagerState* fm, int target_idx); void filemanager_show_multi_properties(FileManagerState* fm, const int* indices, int count); void filemanager_show_directory_delete_confirmation(FileManagerState* fm, int target_idx); void filemanager_show_bulk_delete_confirmation(FileManagerState* fm, const int* indices, int count); void filemanager_push_history(FileManagerState* fm); void filemanager_navigate(FileManagerState* fm, const char* name); void filemanager_go_up(FileManagerState* fm); void filemanager_navigate_to_history(FileManagerState* fm); void filemanager_go_back(FileManagerState* fm); void filemanager_go_forward(FileManagerState* fm); void filemanager_go_home(FileManagerState* fm); void filemanager_refresh(FileManagerState* fm); void filemanager_start_pathbar(FileManagerState* fm); void filemanager_cancel_pathbar(FileManagerState* fm); void filemanager_commit_pathbar(FileManagerState* fm); void filemanager_open_entry(FileManagerState* fm, int idx); // ---- Async file operations (copy/move/delete on a worker thread) ---- enum FileOpKind : int { FILE_OP_COPY = 0, FILE_OP_MOVE = 1, FILE_OP_DELETE = 2, }; // Start a background copy/move of clipboard contents into the current dir, // or a background delete of the given paths, showing a progress dialog. // Returns true if a job was started (caller should not also do it inline). bool filemanager_start_paste_job(FileManagerState* fm); bool filemanager_start_delete_job(FileManagerState* fm, const char* const* paths, int count); int filemanager_grid_row_height(FileManagerState* fm, int row, int cols); int filemanager_grid_row_y(FileManagerState* fm, int row, int cols); int filemanager_grid_content_height(FileManagerState* fm, int cols); int filemanager_grid_index_at(FileManagerState* fm, int cols, int x, int rel_y); // Selection helpers void filemanager_clear_multi_selection(FileManagerState* fm); // Fill out with selected entry indices. Returns count. Uses multi_selected if // non-empty, otherwise falls back to fm->selected (0 or 1 results). int filemanager_collect_selection(const FileManagerState* fm, int* out, int max); void filemanager_draw_header(Canvas& c, FileManagerState* fm, Color toolbar_color, Color btn_bg); void filemanager_on_draw(Window* win, Framebuffer& fb); void filemanager_on_mouse(Window* win, MouseEvent& ev); void filemanager_on_key(Window* win, const montauk::abi::KeyEvent& key); void filemanager_on_close(Window* win); } // namespace filemanager