feat: system settings stored as applets in virtual folder

This commit is contained in:
2026-04-23 15:36:03 +02:00
parent 348ff6981b
commit d912a636e9
21 changed files with 747 additions and 359 deletions
@@ -9,33 +9,92 @@
namespace filemanager {
void filemanager_read_drives(FileManagerState* fm) {
static int filemanager_find_external_app(DesktopState* ds, const char* bin_path) {
if (!ds || !bin_path) return -1;
for (int x = 0; x < ds->external_app_count; x++) {
if (montauk::streq(ds->external_apps[x].binary_path, bin_path)) return x;
}
return -1;
}
static void filemanager_reset_list_state(FileManagerState* fm) {
fm->selected = -1;
fm->scroll_offset = 0;
fm->scrollbar.scroll_offset = 0;
fm->last_click_item = -1;
fm->last_click_time = 0;
}
static void filemanager_reset_virtual_entry(FileManagerVirtualEntry* entry) {
if (!entry) return;
entry->external_app_index = -1;
entry->builtin_id = DESKTOP_BUILTIN_NONE;
entry->icon_lg = {};
entry->icon_sm = {};
}
static void filemanager_add_root_entry(FileManagerState* fm,
const char* name,
FileManagerEntryType type,
int drive_index) {
if (!fm || fm->entry_count >= 64) return;
int idx = fm->entry_count++;
montauk::strncpy(fm->entry_names[idx], name, 63);
fm->entry_types[idx] = type;
fm->entry_sizes[idx] = 0;
fm->is_dir[idx] = true;
fm->drive_indices[idx] = drive_index;
}
static void filemanager_add_virtual_entry(FileManagerState* fm,
const char* name,
const char* icon_path,
int external_index,
DesktopBuiltinId builtin_id) {
if (!fm || fm->entry_count >= 64) return;
int idx = fm->entry_count;
montauk::strncpy(fm->entry_names[idx], name, 63);
fm->entry_types[idx] = FM_ENTRY_VIRTUAL_APP;
fm->entry_sizes[idx] = 0;
fm->is_dir[idx] = false;
fm->drive_indices[idx] = -1;
filemanager_reset_virtual_entry(&fm->virtual_entries[idx]);
fm->virtual_entries[idx].external_app_index = external_index;
fm->virtual_entries[idx].builtin_id = builtin_id;
if (icon_path && icon_path[0]) {
Color defColor = colors::ICON_COLOR;
fm->virtual_entries[idx].icon_lg = svg_load(icon_path, 48, 48, defColor);
fm->virtual_entries[idx].icon_sm = svg_load(icon_path, 16, 16, defColor);
}
fm->entry_count++;
fm->virtual_entry_count = fm->entry_count;
}
static void filemanager_begin_virtual_view(FileManagerState* fm, FileManagerVirtualViewKind view) {
filemanager_free_app_icons(fm);
fm->current_path[0] = '\0';
fm->virtual_view = view;
fm->entry_count = 0;
fm->at_drives_root = true;
}
void filemanager_read_drives(FileManagerState* fm) {
filemanager_free_app_icons(fm);
fm->entry_count = 0;
fm->virtual_view = FM_VIRTUAL_VIEW_NONE;
fm->current_path[0] = '\0';
// Home folder entry (if we have a valid home directory)
DesktopState* ds = fm->desktop;
if (ds && ds->home_dir[0] != '\0') {
int i = fm->entry_count;
montauk::strncpy(fm->entry_names[i], "Home", 63);
fm->entry_types[i] = 4; // home
fm->entry_sizes[i] = 0;
fm->is_dir[i] = true;
fm->drive_indices[i] = -1;
fm->entry_count++;
filemanager_add_root_entry(fm, "Home", FM_ENTRY_HOME, -1);
}
// Apps entry
{
int i = fm->entry_count;
montauk::strncpy(fm->entry_names[i], "Apps", 63);
fm->entry_types[i] = 5; // apps
fm->entry_sizes[i] = 0;
fm->is_dir[i] = true;
fm->drive_indices[i] = -1;
fm->entry_count++;
}
filemanager_add_root_entry(fm, "Apps", FM_ENTRY_APPS_ROOT, -1);
// Special user folders (Documents, Desktop, Music, etc.) - only if they exist
if (ds && ds->home_dir[0] != '\0') {
@@ -51,24 +110,20 @@ void filemanager_read_drives(FileManagerState* fm) {
int probe_fd = montauk::open(probe_path);
if (probe_fd >= 0) {
montauk::close(probe_fd);
int i = fm->entry_count;
montauk::strncpy(fm->entry_names[i], sf_names[sf], 63);
fm->entry_types[i] = 7; // special_dir
fm->entry_sizes[i] = 0;
fm->is_dir[i] = true;
fm->drive_indices[i] = sf; // special folder index
fm->entry_count++;
filemanager_add_root_entry(fm, sf_names[sf], FM_ENTRY_SPECIAL_DIR, sf);
}
}
}
// System configuration entry
filemanager_add_root_entry(fm, "System Configuration", FM_ENTRY_SYSTEM_TOOLS_ROOT, -1);
// Drive entries
int drives[FM_MAX_DRIVES];
int driveCount = montauk::drivelist(drives, FM_MAX_DRIVES);
for (int di = 0; di < driveCount; di++) {
int d = drives[di];
int i = fm->entry_count;
char probe[8];
if (d < 10) {
probe[0] = '0' + d;
@@ -91,28 +146,22 @@ void filemanager_read_drives(FileManagerState* fm) {
str_append(label, volume_label, 64);
str_append(label, "]", 64);
}
montauk::strncpy(fm->entry_names[i], label, 63);
fm->entry_types[i] = 3; // drive
fm->entry_sizes[i] = 0;
fm->is_dir[i] = true;
fm->drive_indices[i] = d;
fm->entry_count++;
filemanager_add_root_entry(fm, label, FM_ENTRY_DRIVE, d);
if (fm->entry_count >= 64) break;
}
fm->selected = -1;
fm->scroll_offset = 0;
fm->scrollbar.scroll_offset = 0;
fm->last_click_item = -1;
fm->last_click_time = 0;
filemanager_reset_list_state(fm);
}
void filemanager_read_dir(FileManagerState* fm) {
fm->at_drives_root = false;
if (fm->at_apps_view) {
fm->at_apps_view = false;
filemanager_free_app_icons(fm);
if (fm->current_path[0] == '\0') {
filemanager_read_drives(fm);
return;
}
filemanager_free_app_icons(fm);
fm->virtual_view = FM_VIRTUAL_VIEW_NONE;
const char* names[64];
fm->entry_count = montauk::readdir(fm->current_path, names, 64);
if (fm->entry_count < 0) fm->entry_count = 0;
@@ -210,33 +259,36 @@ void filemanager_read_dir(FileManagerState* fm) {
fm->is_dir[j + 1] = tmp_isdir;
}
fm->selected = -1;
fm->scroll_offset = 0;
fm->scrollbar.scroll_offset = 0;
fm->last_click_item = -1;
fm->last_click_time = 0;
filemanager_reset_list_state(fm);
}
void filemanager_free_app_icons(FileManagerState* fm) {
for (int i = 0; i < fm->app_icon_count; i++) {
if (fm->app_icons_lg[i].pixels) {
montauk::mfree(fm->app_icons_lg[i].pixels);
fm->app_icons_lg[i].pixels = nullptr;
if (!fm) return;
for (int i = 0; i < fm->virtual_entry_count; i++) {
if (fm->virtual_entries[i].icon_lg.pixels) {
montauk::mfree(fm->virtual_entries[i].icon_lg.pixels);
fm->virtual_entries[i].icon_lg.pixels = nullptr;
}
if (fm->app_icons_sm[i].pixels) {
montauk::mfree(fm->app_icons_sm[i].pixels);
fm->app_icons_sm[i].pixels = nullptr;
if (fm->virtual_entries[i].icon_sm.pixels) {
montauk::mfree(fm->virtual_entries[i].icon_sm.pixels);
fm->virtual_entries[i].icon_sm.pixels = nullptr;
}
filemanager_reset_virtual_entry(&fm->virtual_entries[i]);
}
fm->virtual_entry_count = 0;
}
void filemanager_read_virtual_view(FileManagerState* fm, FileManagerVirtualViewKind view) {
switch (view) {
case FM_VIRTUAL_VIEW_APPS: filemanager_read_apps(fm); break;
case FM_VIRTUAL_VIEW_SYSTEM_TOOLS: filemanager_read_system_tools(fm); break;
default: filemanager_read_drives(fm); break;
}
fm->app_icon_count = 0;
}
void filemanager_read_apps(FileManagerState* fm) {
filemanager_free_app_icons(fm);
fm->at_drives_root = false;
fm->at_apps_view = true;
fm->entry_count = 0;
filemanager_begin_virtual_view(fm, FM_VIRTUAL_VIEW_APPS);
DesktopState* ds = fm->desktop;
if (!ds) return;
@@ -283,45 +335,36 @@ void filemanager_read_apps(FileManagerState* fm) {
const char* binary = doc.get_string("app.binary", "");
const char* icon_file = doc.get_string("app.icon", "");
int idx = fm->entry_count;
montauk::strncpy(fm->entry_names[idx], name, 63);
fm->entry_types[idx] = 6; // app entry
fm->entry_sizes[idx] = 0;
fm->is_dir[idx] = false;
// Store binary path in drive_indices as an app_map index
fm->app_map[idx] = -1;
// Find matching external_app by binary path
char bin_path[128];
snprintf(bin_path, 128, "0:/apps/%s/%s", dirname, binary);
for (int x = 0; x < ds->external_app_count; x++) {
if (montauk::streq(ds->external_apps[x].binary_path, bin_path)) {
fm->app_map[idx] = x;
break;
}
char icon_path[128];
icon_path[0] = '\0';
if (icon_file[0]) {
snprintf(icon_path, 128, "0:/apps/%s/%s", dirname, icon_file);
}
// Load icons at file manager sizes
fm->app_icons_lg[idx] = {};
fm->app_icons_sm[idx] = {};
if (icon_file[0]) {
char icon_path[128];
snprintf(icon_path, 128, "0:/apps/%s/%s", dirname, icon_file);
Color defColor = colors::ICON_COLOR;
fm->app_icons_lg[idx] = svg_load(icon_path, 48, 48, defColor);
fm->app_icons_sm[idx] = svg_load(icon_path, 16, 16, defColor);
}
filemanager_add_virtual_entry(fm, name, icon_path,
filemanager_find_external_app(ds, bin_path),
DESKTOP_BUILTIN_NONE);
doc.destroy();
fm->entry_count++;
fm->app_icon_count = fm->entry_count;
}
fm->selected = -1;
fm->scroll_offset = 0;
fm->scrollbar.scroll_offset = 0;
fm->last_click_item = -1;
fm->last_click_time = 0;
filemanager_reset_list_state(fm);
}
void filemanager_read_system_tools(FileManagerState* fm) {
filemanager_begin_virtual_view(fm, FM_VIRTUAL_VIEW_SYSTEM_TOOLS);
int builtin_count = 0;
const DesktopBuiltinEntry* builtins = desktop_builtin_registry(&builtin_count);
for (int i = 0; i < builtin_count; i++) {
if (!builtins[i].system_tools_applet) continue;
filemanager_add_virtual_entry(fm, builtins[i].label, builtins[i].icon_path,
-1, builtins[i].id);
}
filemanager_reset_list_state(fm);
}
bool filemanager_delete_recursive(const char* path) {