Files
MontaukOS/programs/src/desktop/apps/filemanager/filemanager_internal.hpp
T

311 lines
12 KiB
C++

/*
* filemanager_internal.hpp
* Shared declarations for the embedded desktop file manager
* Copyright (c) 2026 Daniel Hammer
*/
#pragma once
#include "../apps_common.hpp"
#include <gui/mtk/widgets.hpp>
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