From acf89564044ad6ecc72a48b6d32de9f2495b4ddc Mon Sep 17 00:00:00 2001 From: TheFloW Date: Thu, 13 Sep 2018 14:46:10 +0200 Subject: [PATCH] Moved browser related stuff to browser.c --- CMakeLists.txt | 1 + browser.c | 1025 +++++++++++++++++++++++++++++++++++++++++++++ browser.h | 53 +++ file.c | 1 + hex.c | 1 + init.c | 7 +- init.h | 1 + io_process.h | 1 - main.c | 1002 +------------------------------------------- main.h | 30 +- main_context.c | 1 + photo.c | 1 + property_dialog.c | 1 + sfo.c | 1 + text.c | 3 +- 15 files changed, 1120 insertions(+), 1009 deletions(-) create mode 100644 browser.c create mode 100644 browser.h diff --git a/CMakeLists.txt b/CMakeLists.txt index bf32486..cfc38c6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -80,6 +80,7 @@ add_executable(VitaShell ${vitashell_res} main.c main_context.c + browser.c init.c usb.c qr.c diff --git a/browser.c b/browser.c new file mode 100644 index 0000000..ad39729 --- /dev/null +++ b/browser.c @@ -0,0 +1,1025 @@ +/* + VitaShell + Copyright (C) 2015-2018, TheFloW + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#include "main.h" +#include "main_context.h" +#include "browser.h" +#include "init.h" +#include "io_process.h" +#include "refresh.h" +#include "makezip.h" +#include "package_installer.h" +#include "context_menu.h" +#include "archive.h" +#include "photo.h" +#include "audioplayer.h" +#include "file.h" +#include "text.h" +#include "hex.h" +#include "settings.h" +#include "adhoc_dialog.h" +#include "property_dialog.h" +#include "message_dialog.h" +#include "netcheck_dialog.h" +#include "ime_dialog.h" +#include "theme.h" +#include "language.h" +#include "utils.h" +#include "sfo.h" +#include "coredump.h" +#include "usb.h" +#include "qr.h" + +// File lists +FileList file_list, mark_list, copy_list, install_list; + +// Paths +char cur_file[MAX_PATH_LENGTH]; +char archive_copy_path[MAX_PATH_LENGTH]; +char archive_path[MAX_PATH_LENGTH]; + +static char focus_name[MAX_NAME_LENGTH]; + +// Position +int base_pos = 0, rel_pos = 0; +static int base_pos_list[MAX_DIR_LEVELS]; +static int rel_pos_list[MAX_DIR_LEVELS]; +static int dir_level = 0; + +// Modes +int sort_mode = SORT_BY_NAME; +int last_set_sort_mode = SORT_BY_NAME; +int copy_mode = COPY_MODE_NORMAL; +int file_type = FILE_TYPE_UNKNOWN; + +// Archive +static int is_in_archive = 0; +static char dir_level_archive = -1; + +// Scrolling filename +static int scroll_count = 0; +static float scroll_x = FILE_X; + +SceInt64 time_last_recent_files, time_last_bookmarks; + +static void fileBrowserHandleSymlink(FileListEntry* file_entry); +static void fileBrowserHandleFolder(FileListEntry* file_entry); +static void fileBrowserHandleFile(FileListEntry* file_entry); + +static void create_recent_symlink(FileListEntry *file_entry); + +// escape from dir hierarchy with a symlink +typedef struct SymlinkDirectoryPath { + struct SymlinkDirectoryPath* previous; + // contains / at the end, is directory where jumped from + char last_path[MAX_PATH_LENGTH]; + // contains / at the end, is directory where jumped to + char last_hook[MAX_PATH_LENGTH]; +} SymlinkDirectoryPath; + +static SymlinkDirectoryPath* symlink_directory_path = NULL; +static SymlinkDirectoryPath* symlink_directory_path_head = NULL; + +static void storeSymlinkPath(SymlinkDirectoryPath * path) { + if (!symlink_directory_path) { + symlink_directory_path = path; + symlink_directory_path_head = path; + symlink_directory_path->previous = 0; + } else { + SymlinkDirectoryPath *prev = symlink_directory_path; + symlink_directory_path = path; + symlink_directory_path->previous = prev; + } +} + +void dirLevelUp() { + base_pos_list[dir_level] = base_pos; + rel_pos_list[dir_level] = rel_pos; + dir_level++; + base_pos_list[dir_level] = 0; + rel_pos_list[dir_level] = 0; + base_pos = 0; + rel_pos = 0; +} + +void setDirArchiveLevel() { + dir_level_archive = dir_level; +} + +void setInArchive() { + is_in_archive = 1; +} + +int isInArchive() { + return is_in_archive; +} + +void dirUpCloseArchive() { + if (isInArchive() && dir_level_archive >= dir_level) { + is_in_archive = 0; + archiveClose(); + dir_level_archive = -1; + } +} + +int change_to_directory(char *lastdir) { + if (!checkFolderExist(lastdir)) { + return VITASHELL_ERROR_NAVIGATION; + } else { + if (isInArchive()) { + dirUpCloseArchive(); + } + int i; + for (i = 0; i < strlen(lastdir) + 1; i++) { + if (lastdir[i] == ':' || lastdir[i] == '/') { + char ch = lastdir[i + 1]; + lastdir[i + 1] = '\0'; + + char ch2 = lastdir[i]; + lastdir[i] = '\0'; + + char *p = strrchr(lastdir, '/'); + if (!p) + p = strrchr(lastdir, ':'); + if (!p) + p = lastdir - 1; + + lastdir[i] = ch2; + + refreshFileList(); + setFocusOnFilename(p + 1); + + strcpy(file_list.path, lastdir); + + lastdir[i + 1] = ch; + + dirLevelUp(); + } + } + } + refreshFileList(); + return 0; +} + +static void dirUp() { + if (pfs_mounted_path[0] && + strcmp(file_list.path, pfs_mounted_path) == 0 && // we're about to leave the pfs path + !strstr(copy_list.path, pfs_mounted_path)) { // nothing has been copied from pfs path + // Then umount + pfsUmount(); + } + + // skip all symlink hierarchies when pressing O in bookmarks/ recent files + if (symlink_directory_path_head && + ((strncmp(file_list.path, VITASHELL_BOOKMARKS_PATH, MAX_PATH_LENGTH) == 0) + || strncmp(file_list.path, VITASHELL_RECENT_PATH, MAX_PATH_LENGTH) == 0)) { + strcpy(file_list.path, symlink_directory_path_head->last_path); + SymlinkDirectoryPath *e = symlink_directory_path; + while(e != NULL) { + SymlinkDirectoryPath *prev = e->previous; + free(e); + dir_level--; + e = prev; + } + symlink_directory_path_head = 0; + symlink_directory_path = 0; + goto DIR_UP_RETURN; + } + + if (symlink_directory_path + && strncmp(file_list.path, symlink_directory_path->last_hook, MAX_PATH_LENGTH) == 0) { + strcpy(file_list.path, symlink_directory_path->last_path); + SymlinkDirectoryPath* prev = symlink_directory_path->previous; + free(symlink_directory_path); + symlink_directory_path = prev; + dir_level--; + goto DIR_UP_RETURN; + } + + removeEndSlash(file_list.path); + + char *p; + p = strrchr(file_list.path, '/'); + if (p) { + p[1] = '\0'; + dir_level--; + goto DIR_UP_RETURN; + } + + p = strrchr(file_list.path, ':'); + if (p) { + if (strlen(file_list.path) - ((p + 1) - file_list.path) > 0) { + p[1] = '\0'; + dir_level--; + goto DIR_UP_RETURN; + } + } + + strcpy(file_list.path, HOME_PATH); + dir_level = 0; + +DIR_UP_RETURN: + base_pos = (int)base_pos_list[dir_level]; + rel_pos = (int)rel_pos_list[dir_level]; + dirUpCloseArchive(); +} + +void setFocusName(const char *name) { + strncpy(focus_name, name, MAX_NAME_LENGTH-1); + focus_name[MAX_NAME_LENGTH-1] = '\0'; +} + +void setFocusOnFilename(const char *name) { + int name_pos = fileListGetNumberByName(&file_list, name); + if (name_pos < 0 || name_pos >= file_list.length) + return; + + if (name_pos >= base_pos && name_pos < (base_pos + MAX_POSITION)) { + rel_pos = name_pos - base_pos; + } else if (name_pos < base_pos) { + base_pos = name_pos; + rel_pos = 0; + } else if (name_pos >= (base_pos + MAX_POSITION)) { + rel_pos = MAX_POSITION - 1; + base_pos = name_pos - rel_pos; + } +} + +int refreshFileList() { + int ret = 0, res = 0; + + // always sort recent files by date + char *contains = strstr(file_list.path, VITASHELL_RECENT_PATH); + if (contains) { + sort_mode = SORT_BY_DATE; + } else { + sort_mode = last_set_sort_mode; + } + + do { + fileListEmpty(&file_list); + + res = fileListGetEntries(&file_list, file_list.path, sort_mode); + + if (res < 0) { + ret = res; + dirUp(); + } + } while (res < 0); + + // Position correction + if (file_list.length >= MAX_POSITION) { + if ((base_pos + rel_pos) >= file_list.length) { + rel_pos = MAX_POSITION - 1; + } + + if ((base_pos + MAX_POSITION - 1) >= file_list.length) { + base_pos = file_list.length - MAX_POSITION; + } + } else { + if ((base_pos + rel_pos) >= file_list.length) { + rel_pos = file_list.length - 1; + } + + base_pos = 0; + } + + return ret; +} + +static void refreshMarkList() { + if (isInArchive()) + return; + + FileListEntry *entry = mark_list.head; + + int length = mark_list.length; + + int i; + for (i = 0; i < length; i++) { + // Get next entry already now to prevent crash after entry is removed + FileListEntry *next = entry->next; + + char path[MAX_PATH_LENGTH]; + snprintf(path, MAX_PATH_LENGTH, "%s%s", file_list.path, entry->name); + + // Check if the entry still exits. If not, remove it from list + SceIoStat stat; + memset(&stat, 0, sizeof(SceIoStat)); + if (sceIoGetstat(path, &stat) < 0) + fileListRemoveEntry(&mark_list, entry); + + // Next + entry = next; + } +} + +static void refreshCopyList() { + if (copy_list.is_in_archive) + return; + + FileListEntry *entry = copy_list.head; + + int length = copy_list.length; + + int i; + for (i = 0; i < length; i++) { + // Get next entry already now to prevent crash after entry is removed + FileListEntry *next = entry->next; + + char path[MAX_PATH_LENGTH]; + snprintf(path, MAX_PATH_LENGTH, "%s%s", copy_list.path, entry->name); + + // Check if the entry still exits. If not, remove it from list + SceIoStat stat; + memset(&stat, 0, sizeof(SceIoStat)); + if (sceIoGetstat(path, &stat) < 0) + fileListRemoveEntry(©_list, entry); + + // Next + entry = next; + } +} + +static int handleFile(const char *file, FileListEntry *entry) { + int res = 0; + + // try to fix GPU freeze + vita2d_wait_rendering_done(); + + int type = getFileType(file); + + switch (type) { + case FILE_TYPE_PSP2DMP: + case FILE_TYPE_MP3: + case FILE_TYPE_OGG: + case FILE_TYPE_VPK: + case FILE_TYPE_ARCHIVE: + if (isInArchive()) + type = FILE_TYPE_UNKNOWN; + + break; + } + + switch (type) { + case FILE_TYPE_PSP2DMP: + res = coredumpViewer(file); + break; + + case FILE_TYPE_INI: + case FILE_TYPE_TXT: + case FILE_TYPE_XML: + case FILE_TYPE_UNKNOWN: + res = textViewer(file); + break; + + case FILE_TYPE_BMP: + case FILE_TYPE_PNG: + case FILE_TYPE_JPEG: + res = photoViewer(file, type, &file_list, entry, &base_pos, &rel_pos); + break; + + case FILE_TYPE_MP3: + case FILE_TYPE_OGG: + res = audioPlayer(file, type, &file_list, entry, &base_pos, &rel_pos); + break; + + case FILE_TYPE_SFO: + res = SFOReader(file); + break; + + case FILE_TYPE_VPK: + initMessageDialog(SCE_MSG_DIALOG_BUTTON_TYPE_YESNO, language_container[INSTALL_QUESTION]); + setDialogStep(DIALOG_STEP_INSTALL_QUESTION); + break; + + case FILE_TYPE_ARCHIVE: + archiveClearPassword(); + res = archiveOpen(file); + if (res >= 0 && archiveNeedPassword()) { + initImeDialog(language_container[ENTER_PASSWORD], "", 128, SCE_IME_TYPE_BASIC_LATIN, 0, 1); + setDialogStep(DIALOG_STEP_ENTER_PASSWORD); + } + break; + + default: + res = textViewer(file); + break; + } + + if (res < 0) { + errorDialog(res); + return res; + } + + return type; +} + +static int fileBrowserMenuCtrl() { + int refresh = 0; + + // Settings menu + if (pressed_pad[PAD_START]) { + openSettingsMenu(); + } + + // SELECT button + if (pressed_pad[PAD_SELECT]) { + if (vitashell_config.select_button == SELECT_BUTTON_MODE_USB && + sceKernelGetModel() == SCE_KERNEL_MODEL_VITA) { + if (isSafeMode()) { + infoDialog(language_container[EXTENDED_PERMISSIONS_REQUIRED]); + } else { + SceUdcdDeviceState state; + sceUdcdGetDeviceState(&state); + + if (state.cable & SCE_UDCD_STATUS_CABLE_CONNECTED) { + initUsb(); + } else { + initMessageDialog(SCE_MSG_DIALOG_BUTTON_TYPE_CANCEL, + language_container[USB_NOT_CONNECTED]); + setDialogStep(DIALOG_STEP_USB_WAIT); + } + } + } else if (vitashell_config.select_button == SELECT_BUTTON_MODE_FTP || + sceKernelGetModel() == SCE_KERNEL_MODEL_VITATV) { + // Init FTP + if (!ftpvita_is_initialized()) { + int res = ftpvita_init(vita_ip, &vita_port); + if (res < 0) { + initMessageDialog(SCE_MSG_DIALOG_BUTTON_TYPE_CANCEL, language_container[PLEASE_WAIT]); + setDialogStep(DIALOG_STEP_FTP_WAIT); + } else { + initFtp(); + } + + // Lock power timers + powerLock(); + } + + // Dialog + if (ftpvita_is_initialized()) { + initMessageDialog(SCE_MSG_DIALOG_BUTTON_TYPE_OK_CANCEL, language_container[FTP_SERVER], + vita_ip, vita_port); + setDialogStep(DIALOG_STEP_FTP); + } + } + } + +/* + // QR + if (hold_pad[PAD_LTRIGGER] && hold_pad[PAD_RTRIGGER] && enabledQR()) { + startQR(); + initMessageDialog(MESSAGE_DIALOG_QR_CODE, language_container[QR_SCANNING]); + setDialogStep(DIALOG_STEP_QR); + } +*/ + + // bookmarks shortcut + if (current_pad[PAD_LEFT] && current_pad[PAD_SQUARE]) { + SceInt64 now = sceKernelGetSystemTimeWide(); + + // switching too quickly back and forth between recent and bookmarks + // causes VS to crash + if (now - time_last_bookmarks > THRESHOLD_LAST_PAD_BOOKMARKS_WAIT) { + if (strncmp(file_list.path, VITASHELL_BOOKMARKS_PATH, MAX_PATH_LENGTH) != 0) { + char path[MAX_PATH_LENGTH] = VITASHELL_BOOKMARKS_PATH; + sort_mode = last_set_sort_mode; + jump_to_directory_track_current_path(path); + time_last_bookmarks = now; + return 0; + + } + } + } + // recent files shortcut + if (current_pad[PAD_LEFT] && current_pad[PAD_TRIANGLE]) { + SceInt64 now = sceKernelGetSystemTimeWide(); + if (now - time_last_recent_files > THRESHOLD_LAST_PAD_RECENT_FILES_WAIT) { + if (strncmp(file_list.path, VITASHELL_RECENT_PATH, MAX_PATH_LENGTH) != 0) { + char path[MAX_PATH_LENGTH] = VITASHELL_RECENT_PATH; + sort_mode = SORT_BY_DATE; + jump_to_directory_track_current_path(path); + time_last_recent_files = now; + return 0; + + } + } + } + + // Move + if (hold_pad[PAD_UP] || hold2_pad[PAD_LEFT_ANALOG_UP]) { + int old_pos = base_pos + rel_pos; + + if (rel_pos > 0) { + rel_pos--; + } else if (base_pos > 0) { + base_pos--; + } + + if (old_pos != base_pos + rel_pos) { + scroll_count = 0; + } + } else if (hold_pad[PAD_DOWN] || hold2_pad[PAD_LEFT_ANALOG_DOWN]) { + int old_pos = base_pos + rel_pos; + + if ((old_pos + 1) < file_list.length) { + if ((rel_pos + 1) < MAX_POSITION) { + rel_pos++; + } else if ((base_pos + rel_pos + 1) < file_list.length) { + base_pos++; + } + } + + if (old_pos != base_pos + rel_pos) { + scroll_count = 0; + } + } + + // Page skip + if (hold_pad[PAD_LTRIGGER] || hold_pad[PAD_RTRIGGER]) { + int old_pos = base_pos + rel_pos; + + if (hold_pad[PAD_LTRIGGER]) { // Skip page up + base_pos = base_pos - MAX_ENTRIES; + if (base_pos < 0) { + base_pos = 0; + rel_pos = 0; + } + } else { // Skip page down + base_pos = base_pos + MAX_ENTRIES; + if (base_pos >= file_list.length - MAX_POSITION) { + base_pos = MAX(file_list.length - MAX_POSITION, 0); + rel_pos = MIN(MAX_POSITION - 1, file_list.length - 1); + } + } + + if (old_pos != base_pos + rel_pos) { + scroll_count = 0; + } + } + + // Context menu trigger + if (pressed_pad[PAD_TRIANGLE]) { + if (getContextMenuMode() == CONTEXT_MENU_CLOSED) { + if (dir_level > 0) { + setContextMenu(&context_menu_main); + setContextMenuMainVisibilities(); + setContextMenuMode(CONTEXT_MENU_OPENING); + } else { + setContextMenu(&context_menu_home); + setContextMenuHomeVisibilities(); + setContextMenuMode(CONTEXT_MENU_OPENING); + } + } + } + + // Not at 'home' + if (dir_level > 0) { + // Mark entry + if (pressed_pad[PAD_SQUARE]) { + FileListEntry *file_entry = fileListGetNthEntry(&file_list, base_pos + rel_pos); + if (file_entry && strcmp(file_entry->name, DIR_UP) != 0) { + if (!fileListFindEntry(&mark_list, file_entry->name)) { + fileListAddEntry(&mark_list, fileListCopyEntry(file_entry), SORT_NONE); + } else { + fileListRemoveEntryByName(&mark_list, file_entry->name); + } + } + } + + // Back + if (pressed_pad[PAD_CANCEL]) { + scroll_count = 0; + fileListEmpty(&mark_list); + dirUp(); + WriteFile(VITASHELL_LASTDIR, file_list.path, strlen(file_list.path) + 1); + refreshFileList(); + } + } + + // Handle + if (pressed_pad[PAD_ENTER]) { + scroll_count = 0; + + fileListEmpty(&mark_list); + + // Handle file, symlink or folder + FileListEntry *file_entry = fileListGetNthEntry(&file_list, base_pos + rel_pos); + if (file_entry) { + if (file_entry->is_symlink) { + fileBrowserHandleSymlink(file_entry); + } else if (file_entry->is_folder) { + fileBrowserHandleFolder(file_entry); + } else { + fileBrowserHandleFile(file_entry); + create_recent_symlink(file_entry); + } + } + } + return refresh; +} + +static void create_recent_symlink(FileListEntry *file_entry) { + if (isInArchive()) return; + + char target[MAX_PATH_LENGTH]; + snprintf(target, MAX_PATH_LENGTH, "%s%s."SYMLINK_EXT, VITASHELL_RECENT_PATH, + file_entry->name); + snprintf(cur_file, MAX_PATH_LENGTH, "%s%s", file_list.path, file_entry->name); + + // create file recent symlink + createSymLink(target, cur_file); +} + +static void fileBrowserHandleFile(FileListEntry *file_entry) { + snprintf(cur_file, MAX_PATH_LENGTH - 1, "%s%s", file_list.path, file_entry->name); + int type = handleFile(cur_file, file_entry); + + // Archive mode + if (type == FILE_TYPE_ARCHIVE && getDialogStep() != DIALOG_STEP_ENTER_PASSWORD) { + is_in_archive = 1; + dir_level_archive = dir_level; + + snprintf(archive_path, MAX_PATH_LENGTH - 1, "%s%s", file_list.path, file_entry->name); + + strcat(file_list.path, file_entry->name); + addEndSlash(file_list.path); + + dirLevelUp(); + refreshFileList(); + } +} + +static void fileBrowserHandleFolder(FileListEntry *file_entry) { + if (strcmp(file_entry->name, DIR_UP) == 0) { + dirUp(); + } else { + if (dir_level == 0) { + strcpy(file_list.path, file_entry->name); + } else { + if (dir_level > 1) + addEndSlash(file_list.path); + strcat(file_list.path, file_entry->name); + } + dirLevelUp(); + } + + // Save last dir + WriteFile(VITASHELL_LASTDIR, file_list.path, strlen(file_list.path) + 1); + + // Open folder + int res = refreshFileList(); + if (res < 0) + errorDialog(res); +} + +// escape from dir level structure so that parent directory is browsed +// where this jump came from and not the hierarchically higher folder +int jump_to_directory_track_current_path(char *path) { + SymlinkDirectoryPath *symlink_path = malloc(sizeof(SymlinkDirectoryPath)); + + int archive = 0; + while(isInArchive()) { + archive = 1; + dirUp(); + } + if (archive) { + dirUpCloseArchive(); + } + + if (symlink_path) { + strncpy(symlink_path->last_path, file_list.path, MAX_PATH_LENGTH); + strncpy(symlink_path->last_hook, path, MAX_PATH_LENGTH); + dirLevelUp(); + int _dir_level = dir_level; // we escape from hierarchical dir level structure + if (change_to_directory(path) < 0) { + free(symlink_path); + return VITASHELL_ERROR_NAVIGATION; + } + WriteFile(VITASHELL_LASTDIR, file_list.path, strlen(file_list.path) + 1); + storeSymlinkPath(symlink_path); + dir_level = _dir_level; + refreshFileList(); + } + return 0; +} + +static void fileBrowserHandleSymlink(FileListEntry *file_entry) { + if ((file_entry->symlink->to_file == 1 && !checkFileExist(file_entry->symlink->target_path)) + || (file_entry->symlink->to_file == 0 && !checkFolderExist(file_entry->symlink->target_path))) { + // TODO: What if in archive? + snprintf(cur_file, MAX_PATH_LENGTH - 1, "%s%s", file_list.path, file_entry->name); + textViewer(cur_file); + return; + } + if (file_entry->symlink->to_file == 0) { + if (jump_to_directory_track_current_path(file_entry->symlink->target_path) < 0) { + errorDialog(VITASHELL_ERROR_SYMLINK_INVALID_PATH); + } + } else { + char *target_base_directory = getBaseDirectory(file_entry->symlink->target_path); + if (!target_base_directory) { + errorDialog(VITASHELL_ERROR_SYMLINK_CANT_RESOLVE_BASEDIR); + return; + } + char *target_file_name = getFilename(file_entry->symlink->target_path); + if (!target_file_name) { + errorDialog(VITASHELL_ERROR_SYMLINK_CANT_RESOLVE_FILENAME); + return; + } + if (jump_to_directory_track_current_path(target_base_directory) < 0) { + errorDialog(VITASHELL_ERROR_SYMLINK_INVALID_PATH); + return; + } + FileListEntry *resolved_file_entry = fileListFindEntry(&file_list, target_file_name); + if (!resolved_file_entry) { + errorDialog(VITASHELL_ERROR_SYMLINK_INVALID_PATH); + return; + } + fileBrowserHandleFile(resolved_file_entry); + dirUp(); + } + int res = refreshFileList(); + if (res < 0) + errorDialog(res); +} + +int browserMain() { + // Position + memset(base_pos_list, 0, sizeof(base_pos_list)); + memset(rel_pos_list, 0, sizeof(rel_pos_list)); + + // Paths + memset(cur_file, 0, sizeof(cur_file)); + memset(archive_path, 0, sizeof(archive_path)); + + // File lists + memset(&file_list, 0, sizeof(FileList)); + memset(&mark_list, 0, sizeof(FileList)); + memset(©_list, 0, sizeof(FileList)); + memset(&install_list, 0, sizeof(FileList)); + + // Current path is 'home' + strcpy(file_list.path, HOME_PATH); + + if (use_custom_config) { + // Last dir + char lastdir[MAX_PATH_LENGTH]; + ReadFile(VITASHELL_LASTDIR, lastdir, sizeof(lastdir)); + change_to_directory(lastdir); + } + + // Refresh file list + refreshFileList(); + + // Init settings menu + initSettingsMenu(); + + while (1) { + readPad(); + + int refresh = REFRESH_MODE_NONE; + + // Control + if (getDialogStep() != DIALOG_STEP_NONE) { + refresh = dialogSteps(); + // scroll_count = 0; + } else if (getAdhocDialogStatus() != ADHOC_DIALOG_CLOSED) { + adhocDialogCtrl(); + } else if (getPropertyDialogStatus() != PROPERTY_DIALOG_CLOSED) { + propertyDialogCtrl(); + scroll_count = 0; + } else if (getSettingsMenuStatus() != SETTINGS_MENU_CLOSED) { + settingsMenuCtrl(); + } else if (getContextMenuMode() != CONTEXT_MENU_CLOSED) { + contextMenuCtrl(); + } else { + refresh = fileBrowserMenuCtrl(); + } + + // Receive system event + SceAppMgrSystemEvent event; + sceAppMgrReceiveSystemEvent(&event); + + // Refresh on app resume + if (event.systemEvent == SCE_APPMGR_SYSTEMEVENT_ON_RESUME) { + sceShellUtilLock(SCE_SHELL_UTIL_LOCK_TYPE_USB_CONNECTION); + pfsUmount(); // umount game data at resume + refresh = REFRESH_MODE_NORMAL; + } + if (refresh != REFRESH_MODE_NONE) { + // Refresh lists + refreshFileList(); + refreshMarkList(); + refreshCopyList(); + + // Focus + if (refresh == REFRESH_MODE_SETFOCUS) + setFocusOnFilename(focus_name); + } + + // Start drawing + startDrawing(bg_browser_image); + + // Draw + drawShellInfo(file_list.path); + drawScrollBar(base_pos, file_list.length); + + // Draw + FileListEntry *file_entry = fileListGetNthEntry(&file_list, base_pos); + if (file_entry) { + int i; + for (i = 0; i < MAX_ENTRIES && (base_pos + i) < file_list.length; i++) { + uint32_t color = FILE_COLOR; + float y = START_Y + (i * FONT_Y_SPACE); + + vita2d_texture *icon = NULL; + if (file_entry->is_symlink) { + if (file_entry->symlink->to_file) { + color = FILE_SYMLINK_COLOR; + icon = file_symlink_icon; + } else { + color = FOLDER_SYMLINK_COLOR; + icon = folder_symlink_icon; + } + } + // Folder + else if (file_entry->is_folder) { + color = FOLDER_COLOR; + icon = folder_icon; + } else { + switch (file_entry->type) { + case FILE_TYPE_BMP: + case FILE_TYPE_PNG: + case FILE_TYPE_JPEG: + color = IMAGE_COLOR; + icon = image_icon; + break; + + case FILE_TYPE_VPK: + case FILE_TYPE_ARCHIVE: + color = ARCHIVE_COLOR; + icon = archive_icon; + break; + + case FILE_TYPE_MP3: + case FILE_TYPE_OGG: + color = IMAGE_COLOR; + icon = audio_icon; + break; + + case FILE_TYPE_SFO: + color = SFO_COLOR; + icon = sfo_icon; + break; + + case FILE_TYPE_INI: + case FILE_TYPE_TXT: + case FILE_TYPE_XML: + color = TXT_COLOR; + icon = text_icon; + break; + + default: + color = FILE_COLOR; + icon = file_icon; + break; + } + } + + // Draw icon + if (icon) + vita2d_draw_texture(icon, SHELL_MARGIN_X, y + 3.0f); + + // Current position + if (i == rel_pos) + color = FOCUS_COLOR; + + // Marked + if (fileListFindEntry(&mark_list, file_entry->name)) + vita2d_draw_rectangle(SHELL_MARGIN_X, y + 3.0f, MARK_WIDTH, FONT_Y_SPACE, MARKED_COLOR); + + // Draw file name + vita2d_enable_clipping(); + vita2d_set_clip_rectangle(FILE_X + 1.0f, y, FILE_X + 1.0f + MAX_NAME_WIDTH, y + FONT_Y_SPACE); + + float x = FILE_X; + + char file_name[MAX_PATH_LENGTH]; + memset(file_name, 0, sizeof(MAX_PATH_LENGTH)); + + if (file_entry->is_symlink) { + snprintf(file_name, MAX_PATH_LENGTH, "%s → %s", + file_entry->name, file_entry->symlink->target_path); + } else { + strncpy(file_name, file_entry->name, file_entry->name_length + 1); + file_name[file_entry->name_length] = '\0'; + } + if (i == rel_pos) { + int width = (int)pgf_text_width(file_name); + if (width >= MAX_NAME_WIDTH) { + if (scroll_count < 60) { + scroll_x = x; + } else if (scroll_count < width + 90) { + scroll_x--; + } else if (scroll_count < width + 120) { + color = (color & 0x00FFFFFF) | ((((color >> 24) * (scroll_count - width - 90)) / 30) << 24); // fade-in in 0.5s + scroll_x = x; + } else { + scroll_count = 0; + } + + scroll_count++; + + x = scroll_x; + } + } + + pgf_draw_text(x, y, color, file_name); + + vita2d_disable_clipping(); + + // File information + if (strcmp(file_entry->name, DIR_UP) != 0) { + if (dir_level == 0) { + char used_size_string[16], max_size_string[16]; + int max_size_x = ALIGN_RIGHT(INFORMATION_X, pgf_text_width("0000.00 MB")); + int separator_x = ALIGN_RIGHT(max_size_x, pgf_text_width(" / ")); + if (file_entry->size != 0 && file_entry->size2 != 0) { + getSizeString(used_size_string, file_entry->size2 - file_entry->size); + getSizeString(max_size_string, file_entry->size2); + } else { + strcpy(used_size_string, "-"); + strcpy(max_size_string, "-"); + } + + float x = ALIGN_RIGHT(INFORMATION_X, pgf_text_width(max_size_string)); + pgf_draw_text(x, y, color, max_size_string); + pgf_draw_text(separator_x, y, color, " /"); + x = ALIGN_RIGHT(separator_x, pgf_text_width(used_size_string)); + pgf_draw_text(x, y, color, used_size_string); + } else { + char *str = NULL; + if (!file_entry->is_folder) { + // Folder/size + char string[16]; + getSizeString(string, file_entry->size); + str = string; + } else { + str = language_container[FOLDER]; + } + pgf_draw_text(ALIGN_RIGHT(INFORMATION_X, pgf_text_width(str)), y, color, str); + } + + // Date + char date_string[16]; + getDateString(date_string, date_format, &file_entry->mtime); + + char time_string[24]; + getTimeString(time_string, time_format, &file_entry->mtime); + + char string[64]; + sprintf(string, "%s %s", date_string, time_string); + + float x = ALIGN_RIGHT(SCREEN_WIDTH - SHELL_MARGIN_X, pgf_text_width(string)); + pgf_draw_text(x, y, color, string); + } + + // Next + file_entry = file_entry->next; + } + } + + // Draw + drawSettingsMenu(); + drawContextMenu(); + drawAdhocDialog(); + drawPropertyDialog(); + + // End drawing + endDrawing(); + } + + // Empty lists + fileListEmpty(©_list); + fileListEmpty(&mark_list); + fileListEmpty(&file_list); + + return 0; +} diff --git a/browser.h b/browser.h new file mode 100644 index 0000000..d1bfb3b --- /dev/null +++ b/browser.h @@ -0,0 +1,53 @@ +/* + VitaShell + Copyright (C) 2015-2018, TheFloW + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#ifndef __BROWSER_H__ +#define __BROWSER_H__ + +extern FileList file_list, mark_list, copy_list, install_list; + +extern char cur_file[MAX_PATH_LENGTH]; +extern char archive_copy_path[MAX_PATH_LENGTH]; +extern char archive_path[MAX_PATH_LENGTH]; + +extern int base_pos, rel_pos; +extern int sort_mode, copy_mode; + +extern int last_set_sort_mode; + +// minimum time to pass before shortcutting to recent files/ bookmarks via L/R keys +extern SceInt64 time_last_recent_files, time_last_bookmarks; +#define THRESHOLD_LAST_PAD_RECENT_FILES_WAIT 1000000 +#define THRESHOLD_LAST_PAD_BOOKMARKS_WAIT 1000000 + +void dirLevelUp(); + +void setDirArchiveLevel(); +void setInArchive(); +int isInArchive(); + +void setFocusName(const char *name); +void setFocusOnFilename(const char *name); + +int refreshFileList(); + +int jump_to_directory_track_current_path(char *path); + +int browserMain(); + +#endif diff --git a/file.c b/file.c index 61671aa..5042253 100644 --- a/file.c +++ b/file.c @@ -17,6 +17,7 @@ */ #include "main.h" +#include "browser.h" #include "init.h" #include "archive.h" #include "file.h" diff --git a/hex.c b/hex.c index 3143177..18531b8 100644 --- a/hex.c +++ b/hex.c @@ -17,6 +17,7 @@ */ #include "main.h" +#include "browser.h" #include "archive.h" #include "file.h" #include "text.h" diff --git a/init.c b/init.c index 422cd37..36ab836 100644 --- a/init.c +++ b/init.c @@ -17,6 +17,7 @@ */ #include "main.h" +#include "browser.h" #include "init.h" #include "file.h" #include "package_installer.h" @@ -167,6 +168,10 @@ SceUID patch_modid = -1, kernel_modid = -1, user_modid = -1; // System params int language = 0, enter_button = 0, date_format = 0, time_format = 0; +int isSafeMode() { + return is_safe_mode; +} + static void initSceAppUtil() { // Init SceAppUtil SceAppUtilInitParam init_param; @@ -415,7 +420,7 @@ void initVitaShell() { sceIoMkdir(VITASHELL_RECENT_PATH, 0777); } time_last_recent_files = 0; - time_last_bookmars = 0; + time_last_bookmarks = 0; } void finishVitaShell() { diff --git a/init.h b/init.h index 1158d49..6d24857 100644 --- a/init.h +++ b/init.h @@ -40,6 +40,7 @@ typedef struct { vita2d_pgf *loadSystemFonts(); +int isSafeMode(); void initVitaShell(); void finishVitaShell(); diff --git a/io_process.h b/io_process.h index 993b6ba..31d064c 100644 --- a/io_process.h +++ b/io_process.h @@ -46,7 +46,6 @@ typedef struct { FileList *copy_list; const char *archive_path; int copy_mode; - int file_type; } CopyArguments; typedef struct { diff --git a/main.c b/main.c index 5a924c3..786262a 100644 --- a/main.c +++ b/main.c @@ -18,6 +18,7 @@ #include "main.h" #include "main_context.h" +#include "browser.h" #include "init.h" #include "io_process.h" #include "refresh.h" @@ -48,87 +49,23 @@ int _newlib_heap_size_user = 128 * 1024 * 1024; -// Dialog step static volatile int dialog_step = DIALOG_STEP_NONE; -// File lists -FileList file_list, mark_list, copy_list, install_list; - -// Paths -char cur_file[MAX_PATH_LENGTH]; -char archive_copy_path[MAX_PATH_LENGTH]; -char archive_path[MAX_PATH_LENGTH]; - static char install_path[MAX_PATH_LENGTH]; -static char focus_name[MAX_NAME_LENGTH], compress_name[MAX_NAME_LENGTH]; - -// Position -int base_pos = 0, rel_pos = 0; -static int base_pos_list[MAX_DIR_LEVELS]; -static int rel_pos_list[MAX_DIR_LEVELS]; -static int dir_level = 0; - -// Modes -int sort_mode = SORT_BY_NAME; -int last_set_sort_mode = SORT_BY_NAME; -int copy_mode = COPY_MODE_NORMAL; -int file_type = FILE_TYPE_UNKNOWN; - -// Archive -static int is_in_archive = 0; -static char dir_level_archive = -1; - -// FTP -static char vita_ip[16]; -static unsigned short int vita_port; +static char compress_name[MAX_NAME_LENGTH]; static SceUID usbdevice_modid = -1; static SceKernelLwMutexWork dialog_mutex; -// Scrolling filename -static int scroll_count = 0; -static float scroll_x = FILE_X; +char vita_ip[16]; +unsigned short int vita_port; VitaShellConfig vitashell_config; -// Enter and cancel buttons int SCE_CTRL_ENTER = SCE_CTRL_CROSS, SCE_CTRL_CANCEL = SCE_CTRL_CIRCLE; -// Use custom config int use_custom_config = 1; -SceInt64 time_last_recent_files, time_last_bookmars; - -static void setFocusOnFilename(const char *name); -static void fileBrowserHandleSymlink(FileListEntry* file_entry); -static void fileBrowserHandleFolder(FileListEntry* file_entry); -static void fileBrowserHandleFile(FileListEntry* file_entry); - -static void create_recent_symlink(FileListEntry *file_entry); - -// escape from dir hierarchy with a symlink -typedef struct SymlinkDirectoryPath { - struct SymlinkDirectoryPath* previous; - // contains / at the end, is directory where jumped from - char last_path[MAX_PATH_LENGTH]; - // contains / at the end, is directory where jumped to - char last_hook[MAX_PATH_LENGTH]; -} SymlinkDirectoryPath; - -static SymlinkDirectoryPath* symlink_directory_path = NULL; -static SymlinkDirectoryPath* symlink_directory_path_head = NULL; - -static void storeSymlinkPath(SymlinkDirectoryPath * path) { - if (!symlink_directory_path) { - symlink_directory_path = path; - symlink_directory_path_head = path; - symlink_directory_path->previous = 0; - } else { - SymlinkDirectoryPath *prev = symlink_directory_path; - symlink_directory_path = path; - symlink_directory_path->previous = prev; - } -} int getDialogStep() { sceKernelLockLwMutex(&dialog_mutex, 1, NULL); @@ -143,316 +80,6 @@ void setDialogStep(int step) { sceKernelUnlockLwMutex(&dialog_mutex, 1); } -void dirLevelUp() { - base_pos_list[dir_level] = base_pos; - rel_pos_list[dir_level] = rel_pos; - dir_level++; - base_pos_list[dir_level] = 0; - rel_pos_list[dir_level] = 0; - base_pos = 0; - rel_pos = 0; -} - -int isInArchive() { - return is_in_archive; -} - -void dirUpCloseArchive() { - if (isInArchive() && dir_level_archive >= dir_level) { - is_in_archive = 0; - archiveClose(); - dir_level_archive = -1; - } -} - -int change_to_directory(char *lastdir) { - if (!checkFolderExist(lastdir)) { - return VITASHELL_ERROR_NAVIGATION; - } else { - if (isInArchive()) { - dirUpCloseArchive(); - } - int i; - for (i = 0; i < strlen(lastdir) + 1; i++) { - if (lastdir[i] == ':' || lastdir[i] == '/') { - char ch = lastdir[i + 1]; - lastdir[i + 1] = '\0'; - - char ch2 = lastdir[i]; - lastdir[i] = '\0'; - - char *p = strrchr(lastdir, '/'); - if (!p) - p = strrchr(lastdir, ':'); - if (!p) - p = lastdir - 1; - - lastdir[i] = ch2; - - refreshFileList(); - setFocusOnFilename(p + 1); - - strcpy(file_list.path, lastdir); - - lastdir[i + 1] = ch; - - dirLevelUp(); - } - } - } - refreshFileList(); - return 0; -} - -static void dirUp() { - if (pfs_mounted_path[0] && - strcmp(file_list.path, pfs_mounted_path) == 0 && // we're about to leave the pfs path - !strstr(copy_list.path, pfs_mounted_path)) { // nothing has been copied from pfs path - // Then umount - pfsUmount(); - } - - // skip all symlink hierarchies when pressing O in bookmarks/ recent files - if (symlink_directory_path_head && - ((strncmp(file_list.path, VITASHELL_BOOKMARKS_PATH, MAX_PATH_LENGTH) == 0) - || strncmp(file_list.path, VITASHELL_RECENT_PATH, MAX_PATH_LENGTH) == 0)) { - strcpy(file_list.path, symlink_directory_path_head->last_path); - SymlinkDirectoryPath *e = symlink_directory_path; - while(e != NULL) { - SymlinkDirectoryPath *prev = e->previous; - free(e); - dir_level--; - e = prev; - } - symlink_directory_path_head = 0; - symlink_directory_path = 0; - goto DIR_UP_RETURN; - } - - if (symlink_directory_path - && strncmp(file_list.path, symlink_directory_path->last_hook, MAX_PATH_LENGTH) == 0) { - strcpy(file_list.path, symlink_directory_path->last_path); - SymlinkDirectoryPath* prev = symlink_directory_path->previous; - free(symlink_directory_path); - symlink_directory_path = prev; - dir_level--; - goto DIR_UP_RETURN; - } - - removeEndSlash(file_list.path); - - char *p; - p = strrchr(file_list.path, '/'); - if (p) { - p[1] = '\0'; - dir_level--; - goto DIR_UP_RETURN; - } - - p = strrchr(file_list.path, ':'); - if (p) { - if (strlen(file_list.path) - ((p + 1) - file_list.path) > 0) { - p[1] = '\0'; - dir_level--; - goto DIR_UP_RETURN; - } - } - - strcpy(file_list.path, HOME_PATH); - dir_level = 0; - -DIR_UP_RETURN: - base_pos = (int)base_pos_list[dir_level]; - rel_pos = (int)rel_pos_list[dir_level]; - dirUpCloseArchive(); -} - -static void setFocusOnFilename(const char *name) { - int name_pos = fileListGetNumberByName(&file_list, name); - if (name_pos < 0 || name_pos >= file_list.length) - return; - - if (name_pos >= base_pos && name_pos < (base_pos + MAX_POSITION)) { - rel_pos = name_pos - base_pos; - } else if (name_pos < base_pos) { - base_pos = name_pos; - rel_pos = 0; - } else if (name_pos >= (base_pos + MAX_POSITION)) { - rel_pos = MAX_POSITION - 1; - base_pos = name_pos - rel_pos; - } -} - -int refreshFileList() { - int ret = 0, res = 0; - - // always sort recent files by date - char *contains = strstr(file_list.path, VITASHELL_RECENT_PATH); - if (contains) { - sort_mode = SORT_BY_DATE; - } else { - sort_mode = last_set_sort_mode; - } - - do { - fileListEmpty(&file_list); - - res = fileListGetEntries(&file_list, file_list.path, sort_mode); - - if (res < 0) { - ret = res; - dirUp(); - } - } while (res < 0); - - // Position correction - if (file_list.length >= MAX_POSITION) { - if ((base_pos + rel_pos) >= file_list.length) { - rel_pos = MAX_POSITION - 1; - } - - if ((base_pos + MAX_POSITION - 1) >= file_list.length) { - base_pos = file_list.length - MAX_POSITION; - } - } else { - if ((base_pos + rel_pos) >= file_list.length) { - rel_pos = file_list.length - 1; - } - - base_pos = 0; - } - - return ret; -} - -static void refreshMarkList() { - if (isInArchive()) - return; - - FileListEntry *entry = mark_list.head; - - int length = mark_list.length; - - int i; - for (i = 0; i < length; i++) { - // Get next entry already now to prevent crash after entry is removed - FileListEntry *next = entry->next; - - char path[MAX_PATH_LENGTH]; - snprintf(path, MAX_PATH_LENGTH, "%s%s", file_list.path, entry->name); - - // Check if the entry still exits. If not, remove it from list - SceIoStat stat; - memset(&stat, 0, sizeof(SceIoStat)); - if (sceIoGetstat(path, &stat) < 0) - fileListRemoveEntry(&mark_list, entry); - - // Next - entry = next; - } -} - -static void refreshCopyList() { - if (copy_list.is_in_archive) - return; - - FileListEntry *entry = copy_list.head; - - int length = copy_list.length; - - int i; - for (i = 0; i < length; i++) { - // Get next entry already now to prevent crash after entry is removed - FileListEntry *next = entry->next; - - char path[MAX_PATH_LENGTH]; - snprintf(path, MAX_PATH_LENGTH, "%s%s", copy_list.path, entry->name); - - // Check if the entry still exits. If not, remove it from list - SceIoStat stat; - memset(&stat, 0, sizeof(SceIoStat)); - if (sceIoGetstat(path, &stat) < 0) - fileListRemoveEntry(©_list, entry); - - // Next - entry = next; - } -} - -static int handleFile(const char *file, FileListEntry *entry) { - int res = 0; - - // try to fix GPU freeze - vita2d_wait_rendering_done(); - - int type = getFileType(file); - - switch (type) { - case FILE_TYPE_PSP2DMP: - case FILE_TYPE_MP3: - case FILE_TYPE_OGG: - case FILE_TYPE_VPK: - case FILE_TYPE_ARCHIVE: - if (isInArchive()) - type = FILE_TYPE_UNKNOWN; - - break; - } - - switch (type) { - case FILE_TYPE_PSP2DMP: - res = coredumpViewer(file); - break; - - case FILE_TYPE_INI: - case FILE_TYPE_TXT: - case FILE_TYPE_XML: - case FILE_TYPE_UNKNOWN: - res = textViewer(file); - break; - - case FILE_TYPE_BMP: - case FILE_TYPE_PNG: - case FILE_TYPE_JPEG: - res = photoViewer(file, type, &file_list, entry, &base_pos, &rel_pos); - break; - - case FILE_TYPE_MP3: - case FILE_TYPE_OGG: - res = audioPlayer(file, type, &file_list, entry, &base_pos, &rel_pos); - break; - - case FILE_TYPE_SFO: - res = SFOReader(file); - break; - - case FILE_TYPE_VPK: - initMessageDialog(SCE_MSG_DIALOG_BUTTON_TYPE_YESNO, language_container[INSTALL_QUESTION]); - setDialogStep(DIALOG_STEP_INSTALL_QUESTION); - break; - - case FILE_TYPE_ARCHIVE: - archiveClearPassword(); - res = archiveOpen(file); - if (res >= 0 && archiveNeedPassword()) { - initImeDialog(language_container[ENTER_PASSWORD], "", 128, SCE_IME_TYPE_BASIC_LATIN, 0, 1); - setDialogStep(DIALOG_STEP_ENTER_PASSWORD); - } - break; - - default: - res = textViewer(file); - break; - } - - if (res < 0) { - errorDialog(res); - return res; - } - - return type; -} - void drawScrollBar(int pos, int n) { if (n > MAX_POSITION) { vita2d_draw_rectangle(SCROLL_BAR_X, START_Y, SCROLL_BAR_WIDTH, MAX_ENTRIES * FONT_Y_SPACE, SCROLL_BAR_BG_COLOR); @@ -553,7 +180,7 @@ void drawShellInfo(const char *path) { // home (SAFE/UNSAFE MODE) if (strcmp(path_first_line, HOME_PATH) == 0) { pgf_draw_textf(SHELL_MARGIN_X, PATH_Y, PATH_COLOR, "%s (%s)", HOME_PATH, - is_safe_mode ? language_container[SAFE_MODE] : language_container[UNSAFE_MODE]); + isSafeMode() ? language_container[SAFE_MODE] : language_container[UNSAFE_MODE]); } else { // Path pgf_draw_text(SHELL_MARGIN_X, PATH_Y, PATH_COLOR, path_first_line); @@ -561,13 +188,13 @@ void drawShellInfo(const char *path) { } } -static void initFtp() { +void initFtp() { // Add all the current mountpoints to ftpvita int i; for (i = 0; i < getNumberOfDevices(); i++) { char **devices = getDevices(); if (devices[i]) { - if (is_safe_mode && strcmp(devices[i], "ux0:") != 0) + if (isSafeMode() && strcmp(devices[i], "ux0:") != 0) continue; ftpvita_add_device(devices[i]); @@ -577,7 +204,7 @@ static void initFtp() { ftpvita_ext_add_custom_command("PROM", ftpvita_PROM); } -static void initUsb() { +void initUsb() { char *path = NULL; if (vitashell_config.usbdevice == USBDEVICE_MODE_MEMORY_CARD) { @@ -621,7 +248,7 @@ static void initUsb() { } } -static int dialogSteps() { +int dialogSteps() { int refresh = REFRESH_MODE_NONE; int msg_result = updateMessageDialog(); @@ -679,7 +306,7 @@ static int dialogSteps() { } // Focus - strcpy(focus_name, compress_name); + setFocusName(compress_name); refresh = REFRESH_MODE_SETFOCUS; } @@ -710,7 +337,7 @@ static int dialogSteps() { } // Focus - strcpy(focus_name, copy_list.head->name); + setFocusName(copy_list.head->name); // Empty copy list when moved if (getDialogStep() == DIALOG_STEP_MOVED) @@ -886,7 +513,6 @@ static int dialogSteps() { args.copy_list = ©_list; args.archive_path = archive_copy_path; args.copy_mode = copy_mode; - args.file_type = file_type; setDialogStep(DIALOG_STEP_COPYING); @@ -1015,8 +641,10 @@ static int dialogSteps() { errorDialog(res); } else { // Focus + char focus_name[MAX_NAME_LENGTH]; strcpy(focus_name, name); addEndSlash(focus_name); + setFocusName(focus_name); refresh = REFRESH_MODE_SETFOCUS; setDialogStep(DIALOG_STEP_NONE); @@ -1046,8 +674,10 @@ static int dialogSteps() { sceIoClose(fd); // Focus + char focus_name[MAX_NAME_LENGTH]; strcpy(focus_name, name); addEndSlash(focus_name); + setFocusName(focus_name); refresh = REFRESH_MODE_SETFOCUS; setDialogStep(DIALOG_STEP_NONE); @@ -1404,8 +1034,8 @@ static int dialogSteps() { break; } - is_in_archive = 1; - dir_level_archive = dir_level; + setInArchive(); + setDirArchiveLevel(); snprintf(archive_path, MAX_PATH_LENGTH, "%s%s", file_list.path, file_entry->name); @@ -1587,600 +1217,6 @@ static int dialogSteps() { return refresh; } -static int fileBrowserMenuCtrl() { - int refresh = 0; - - // Settings menu - if (pressed_pad[PAD_START]) { - openSettingsMenu(); - } - - // SELECT button - if (pressed_pad[PAD_SELECT]) { - if (vitashell_config.select_button == SELECT_BUTTON_MODE_USB && - sceKernelGetModel() == SCE_KERNEL_MODEL_VITA) { - if (is_safe_mode) { - infoDialog(language_container[EXTENDED_PERMISSIONS_REQUIRED]); - } else { - SceUdcdDeviceState state; - sceUdcdGetDeviceState(&state); - - if (state.cable & SCE_UDCD_STATUS_CABLE_CONNECTED) { - initUsb(); - } else { - initMessageDialog(SCE_MSG_DIALOG_BUTTON_TYPE_CANCEL, - language_container[USB_NOT_CONNECTED]); - setDialogStep(DIALOG_STEP_USB_WAIT); - } - } - } else if (vitashell_config.select_button == SELECT_BUTTON_MODE_FTP || - sceKernelGetModel() == SCE_KERNEL_MODEL_VITATV) { - // Init FTP - if (!ftpvita_is_initialized()) { - int res = ftpvita_init(vita_ip, &vita_port); - if (res < 0) { - initMessageDialog(SCE_MSG_DIALOG_BUTTON_TYPE_CANCEL, language_container[PLEASE_WAIT]); - setDialogStep(DIALOG_STEP_FTP_WAIT); - } else { - initFtp(); - } - - // Lock power timers - powerLock(); - } - - // Dialog - if (ftpvita_is_initialized()) { - initMessageDialog(SCE_MSG_DIALOG_BUTTON_TYPE_OK_CANCEL, language_container[FTP_SERVER], - vita_ip, vita_port); - setDialogStep(DIALOG_STEP_FTP); - } - } - } - -/* - // QR - if (hold_pad[PAD_LTRIGGER] && hold_pad[PAD_RTRIGGER] && enabledQR()) { - startQR(); - initMessageDialog(MESSAGE_DIALOG_QR_CODE, language_container[QR_SCANNING]); - setDialogStep(DIALOG_STEP_QR); - } -*/ - - // bookmarks shortcut - if (current_pad[PAD_LEFT] && current_pad[PAD_SQUARE]) { - SceInt64 now = sceKernelGetSystemTimeWide(); - - // switching too quickly back and forth between recent and bookmarks - // causes VS to crash - if (now - time_last_bookmars > THRESHOLD_LAST_PAD_BOOKMARKS_WAIT) { - if (strncmp(file_list.path, VITASHELL_BOOKMARKS_PATH, MAX_PATH_LENGTH) != 0) { - char path[MAX_PATH_LENGTH] = VITASHELL_BOOKMARKS_PATH; - sort_mode = last_set_sort_mode; - jump_to_directory_track_current_path(path); - time_last_bookmars = now; - return 0; - - } - } - } - // recent files shortcut - if (current_pad[PAD_LEFT] && current_pad[PAD_TRIANGLE]) { - SceInt64 now = sceKernelGetSystemTimeWide(); - if (now - time_last_recent_files > THRESHOLD_LAST_PAD_RECENT_FILES_WAIT) { - if (strncmp(file_list.path, VITASHELL_RECENT_PATH, MAX_PATH_LENGTH) != 0) { - char path[MAX_PATH_LENGTH] = VITASHELL_RECENT_PATH; - sort_mode = SORT_BY_DATE; - jump_to_directory_track_current_path(path); - time_last_recent_files = now; - return 0; - - } - } - } - - // Move - if (hold_pad[PAD_UP] || hold2_pad[PAD_LEFT_ANALOG_UP]) { - int old_pos = base_pos + rel_pos; - - if (rel_pos > 0) { - rel_pos--; - } else if (base_pos > 0) { - base_pos--; - } - - if (old_pos != base_pos + rel_pos) { - scroll_count = 0; - } - } else if (hold_pad[PAD_DOWN] || hold2_pad[PAD_LEFT_ANALOG_DOWN]) { - int old_pos = base_pos + rel_pos; - - if ((old_pos + 1) < file_list.length) { - if ((rel_pos + 1) < MAX_POSITION) { - rel_pos++; - } else if ((base_pos + rel_pos + 1) < file_list.length) { - base_pos++; - } - } - - if (old_pos != base_pos + rel_pos) { - scroll_count = 0; - } - } - - // Page skip - if (hold_pad[PAD_LTRIGGER] || hold_pad[PAD_RTRIGGER]) { - int old_pos = base_pos + rel_pos; - - if (hold_pad[PAD_LTRIGGER]) { // Skip page up - base_pos = base_pos - MAX_ENTRIES; - if (base_pos < 0) { - base_pos = 0; - rel_pos = 0; - } - } else { // Skip page down - base_pos = base_pos + MAX_ENTRIES; - if (base_pos >= file_list.length - MAX_POSITION) { - base_pos = MAX(file_list.length - MAX_POSITION, 0); - rel_pos = MIN(MAX_POSITION - 1, file_list.length - 1); - } - } - - if (old_pos != base_pos + rel_pos) { - scroll_count = 0; - } - } - - // Context menu trigger - if (pressed_pad[PAD_TRIANGLE]) { - if (getContextMenuMode() == CONTEXT_MENU_CLOSED) { - if (dir_level > 0) { - setContextMenu(&context_menu_main); - setContextMenuMainVisibilities(); - setContextMenuMode(CONTEXT_MENU_OPENING); - } else { - setContextMenu(&context_menu_home); - setContextMenuHomeVisibilities(); - setContextMenuMode(CONTEXT_MENU_OPENING); - } - } - } - - // Not at 'home' - if (dir_level > 0) { - // Mark entry - if (pressed_pad[PAD_SQUARE]) { - FileListEntry *file_entry = fileListGetNthEntry(&file_list, base_pos + rel_pos); - if (file_entry && strcmp(file_entry->name, DIR_UP) != 0) { - if (!fileListFindEntry(&mark_list, file_entry->name)) { - fileListAddEntry(&mark_list, fileListCopyEntry(file_entry), SORT_NONE); - } else { - fileListRemoveEntryByName(&mark_list, file_entry->name); - } - } - } - - // Back - if (pressed_pad[PAD_CANCEL]) { - scroll_count = 0; - fileListEmpty(&mark_list); - dirUp(); - WriteFile(VITASHELL_LASTDIR, file_list.path, strlen(file_list.path) + 1); - refreshFileList(); - } - } - - // Handle - if (pressed_pad[PAD_ENTER]) { - scroll_count = 0; - - fileListEmpty(&mark_list); - - // Handle file, symlink or folder - FileListEntry *file_entry = fileListGetNthEntry(&file_list, base_pos + rel_pos); - if (file_entry) { - if (file_entry->is_symlink) { - fileBrowserHandleSymlink(file_entry); - } else if (file_entry->is_folder) { - fileBrowserHandleFolder(file_entry); - } else { - fileBrowserHandleFile(file_entry); - create_recent_symlink(file_entry); - } - } - } - return refresh; -} - -static void create_recent_symlink(FileListEntry *file_entry) { - if (isInArchive()) return; - - char target[MAX_PATH_LENGTH]; - snprintf(target, MAX_PATH_LENGTH, "%s%s."SYMLINK_EXT, VITASHELL_RECENT_PATH, - file_entry->name); - snprintf(cur_file, MAX_PATH_LENGTH, "%s%s", file_list.path, file_entry->name); - - // create file recent symlink - createSymLink(target, cur_file); -} - -static void fileBrowserHandleFile(FileListEntry *file_entry) { - snprintf(cur_file, MAX_PATH_LENGTH - 1, "%s%s", file_list.path, file_entry->name); - int type = handleFile(cur_file, file_entry); - - // Archive mode - if (type == FILE_TYPE_ARCHIVE && getDialogStep() != DIALOG_STEP_ENTER_PASSWORD) { - is_in_archive = 1; - dir_level_archive = dir_level; - - snprintf(archive_path, MAX_PATH_LENGTH - 1, "%s%s", file_list.path, file_entry->name); - - strcat(file_list.path, file_entry->name); - addEndSlash(file_list.path); - - dirLevelUp(); - refreshFileList(); - } -} - -static void fileBrowserHandleFolder(FileListEntry *file_entry) { - if (strcmp(file_entry->name, DIR_UP) == 0) { - dirUp(); - } else { - if (dir_level == 0) { - strcpy(file_list.path, file_entry->name); - } else { - if (dir_level > 1) - addEndSlash(file_list.path); - strcat(file_list.path, file_entry->name); - } - dirLevelUp(); - } - - // Save last dir - WriteFile(VITASHELL_LASTDIR, file_list.path, strlen(file_list.path) + 1); - - // Open folder - int res = refreshFileList(); - if (res < 0) - errorDialog(res); -} - -// escape from dir level structure so that parent directory is browsed -// where this jump came from and not the hierarchically higher folder -int jump_to_directory_track_current_path(char *path) { - SymlinkDirectoryPath *symlink_path = malloc(sizeof(SymlinkDirectoryPath)); - - int archive = 0; - while(isInArchive()) { - archive = 1; - dirUp(); - } - if (archive) { - dirUpCloseArchive(); - } - - if (symlink_path) { - strncpy(symlink_path->last_path, file_list.path, MAX_PATH_LENGTH); - strncpy(symlink_path->last_hook, path, MAX_PATH_LENGTH); - dirLevelUp(); - int _dir_level = dir_level; // we escape from hierarchical dir level structure - if (change_to_directory(path) < 0) { - free(symlink_path); - return VITASHELL_ERROR_NAVIGATION; - } - WriteFile(VITASHELL_LASTDIR, file_list.path, strlen(file_list.path) + 1); - storeSymlinkPath(symlink_path); - dir_level = _dir_level; - refreshFileList(); - } - return 0; -} - -static void fileBrowserHandleSymlink(FileListEntry *file_entry) { - if ((file_entry->symlink->to_file == 1 && !checkFileExist(file_entry->symlink->target_path)) - || (file_entry->symlink->to_file == 0 && !checkFolderExist(file_entry->symlink->target_path))) { - // TODO: What if in archive? - snprintf(cur_file, MAX_PATH_LENGTH - 1, "%s%s", file_list.path, file_entry->name); - textViewer(cur_file); - return; - } - if (file_entry->symlink->to_file == 0) { - if (jump_to_directory_track_current_path(file_entry->symlink->target_path) < 0) { - errorDialog(VITASHELL_ERROR_SYMLINK_INVALID_PATH); - } - } else { - char *target_base_directory = getBaseDirectory(file_entry->symlink->target_path); - if (!target_base_directory) { - errorDialog(VITASHELL_ERROR_SYMLINK_CANT_RESOLVE_BASEDIR); - return; - } - char *target_file_name = getFilename(file_entry->symlink->target_path); - if (!target_file_name) { - errorDialog(VITASHELL_ERROR_SYMLINK_CANT_RESOLVE_FILENAME); - return; - } - if (jump_to_directory_track_current_path(target_base_directory) < 0) { - errorDialog(VITASHELL_ERROR_SYMLINK_INVALID_PATH); - return; - } - FileListEntry *resolved_file_entry = fileListFindEntry(&file_list, target_file_name); - if (!resolved_file_entry) { - errorDialog(VITASHELL_ERROR_SYMLINK_INVALID_PATH); - return; - } - fileBrowserHandleFile(resolved_file_entry); - dirUp(); - } - int res = refreshFileList(); - if (res < 0) - errorDialog(res); -} - -static int shellMain() { - // Position - memset(base_pos_list, 0, sizeof(base_pos_list)); - memset(rel_pos_list, 0, sizeof(rel_pos_list)); - - // Paths - memset(cur_file, 0, sizeof(cur_file)); - memset(archive_path, 0, sizeof(archive_path)); - - // File lists - memset(&file_list, 0, sizeof(FileList)); - memset(&mark_list, 0, sizeof(FileList)); - memset(©_list, 0, sizeof(FileList)); - memset(&install_list, 0, sizeof(FileList)); - - // Current path is 'home' - strcpy(file_list.path, HOME_PATH); - - if (use_custom_config) { - // Last dir - char lastdir[MAX_PATH_LENGTH]; - ReadFile(VITASHELL_LASTDIR, lastdir, sizeof(lastdir)); - change_to_directory(lastdir); - } - - // Refresh file list - refreshFileList(); - - // Init settings menu - initSettingsMenu(); - - while (1) { - readPad(); - - int refresh = REFRESH_MODE_NONE; - - // Control - if (getDialogStep() != DIALOG_STEP_NONE) { - refresh = dialogSteps(); - // scroll_count = 0; - } else if (getAdhocDialogStatus() != ADHOC_DIALOG_CLOSED) { - adhocDialogCtrl(); - } else if (getPropertyDialogStatus() != PROPERTY_DIALOG_CLOSED) { - propertyDialogCtrl(); - scroll_count = 0; - } else if (getSettingsMenuStatus() != SETTINGS_MENU_CLOSED) { - settingsMenuCtrl(); - } else if (getContextMenuMode() != CONTEXT_MENU_CLOSED) { - contextMenuCtrl(); - } else { - refresh = fileBrowserMenuCtrl(); - } - - // Receive system event - SceAppMgrSystemEvent event; - sceAppMgrReceiveSystemEvent(&event); - - // Refresh on app resume - if (event.systemEvent == SCE_APPMGR_SYSTEMEVENT_ON_RESUME) { - sceShellUtilLock(SCE_SHELL_UTIL_LOCK_TYPE_USB_CONNECTION); - pfsUmount(); // umount game data at resume - refresh = REFRESH_MODE_NORMAL; - } - if (refresh != REFRESH_MODE_NONE) { - // Refresh lists - refreshFileList(); - refreshMarkList(); - refreshCopyList(); - - // Focus - if (refresh == REFRESH_MODE_SETFOCUS) - setFocusOnFilename(focus_name); - } - - // Start drawing - startDrawing(bg_browser_image); - - // Draw - drawShellInfo(file_list.path); - drawScrollBar(base_pos, file_list.length); - - // Draw - FileListEntry *file_entry = fileListGetNthEntry(&file_list, base_pos); - if (file_entry) { - int i; - for (i = 0; i < MAX_ENTRIES && (base_pos + i) < file_list.length; i++) { - uint32_t color = FILE_COLOR; - float y = START_Y + (i * FONT_Y_SPACE); - - vita2d_texture *icon = NULL; - if (file_entry->is_symlink) { - if (file_entry->symlink->to_file) { - color = FILE_SYMLINK_COLOR; - icon = file_symlink_icon; - } else { - color = FOLDER_SYMLINK_COLOR; - icon = folder_symlink_icon; - } - } - // Folder - else if (file_entry->is_folder) { - color = FOLDER_COLOR; - icon = folder_icon; - } else { - switch (file_entry->type) { - case FILE_TYPE_BMP: - case FILE_TYPE_PNG: - case FILE_TYPE_JPEG: - color = IMAGE_COLOR; - icon = image_icon; - break; - - case FILE_TYPE_VPK: - case FILE_TYPE_ARCHIVE: - color = ARCHIVE_COLOR; - icon = archive_icon; - break; - - case FILE_TYPE_MP3: - case FILE_TYPE_OGG: - color = IMAGE_COLOR; - icon = audio_icon; - break; - - case FILE_TYPE_SFO: - color = SFO_COLOR; - icon = sfo_icon; - break; - - case FILE_TYPE_INI: - case FILE_TYPE_TXT: - case FILE_TYPE_XML: - color = TXT_COLOR; - icon = text_icon; - break; - - default: - color = FILE_COLOR; - icon = file_icon; - break; - } - } - - // Draw icon - if (icon) - vita2d_draw_texture(icon, SHELL_MARGIN_X, y + 3.0f); - - // Current position - if (i == rel_pos) - color = FOCUS_COLOR; - - // Marked - if (fileListFindEntry(&mark_list, file_entry->name)) - vita2d_draw_rectangle(SHELL_MARGIN_X, y + 3.0f, MARK_WIDTH, FONT_Y_SPACE, MARKED_COLOR); - - // Draw file name - vita2d_enable_clipping(); - vita2d_set_clip_rectangle(FILE_X + 1.0f, y, FILE_X + 1.0f + MAX_NAME_WIDTH, y + FONT_Y_SPACE); - - float x = FILE_X; - - char file_name[MAX_PATH_LENGTH]; - memset(file_name, 0, sizeof(MAX_PATH_LENGTH)); - - if (file_entry->is_symlink) { - snprintf(file_name, MAX_PATH_LENGTH, "%s → %s", - file_entry->name, file_entry->symlink->target_path); - } else { - strncpy(file_name, file_entry->name, file_entry->name_length + 1); - file_name[file_entry->name_length] = '\0'; - } - if (i == rel_pos) { - int width = (int)pgf_text_width(file_name); - if (width >= MAX_NAME_WIDTH) { - if (scroll_count < 60) { - scroll_x = x; - } else if (scroll_count < width + 90) { - scroll_x--; - } else if (scroll_count < width + 120) { - color = (color & 0x00FFFFFF) | ((((color >> 24) * (scroll_count - width - 90)) / 30) << 24); // fade-in in 0.5s - scroll_x = x; - } else { - scroll_count = 0; - } - - scroll_count++; - - x = scroll_x; - } - } - - pgf_draw_text(x, y, color, file_name); - - vita2d_disable_clipping(); - - // File information - if (strcmp(file_entry->name, DIR_UP) != 0) { - if (dir_level == 0) { - char used_size_string[16], max_size_string[16]; - int max_size_x = ALIGN_RIGHT(INFORMATION_X, pgf_text_width("0000.00 MB")); - int separator_x = ALIGN_RIGHT(max_size_x, pgf_text_width(" / ")); - if (file_entry->size != 0 && file_entry->size2 != 0) { - getSizeString(used_size_string, file_entry->size2 - file_entry->size); - getSizeString(max_size_string, file_entry->size2); - } else { - strcpy(used_size_string, "-"); - strcpy(max_size_string, "-"); - } - - float x = ALIGN_RIGHT(INFORMATION_X, pgf_text_width(max_size_string)); - pgf_draw_text(x, y, color, max_size_string); - pgf_draw_text(separator_x, y, color, " /"); - x = ALIGN_RIGHT(separator_x, pgf_text_width(used_size_string)); - pgf_draw_text(x, y, color, used_size_string); - } else { - char *str = NULL; - if (!file_entry->is_folder) { - // Folder/size - char string[16]; - getSizeString(string, file_entry->size); - str = string; - } else { - str = language_container[FOLDER]; - } - pgf_draw_text(ALIGN_RIGHT(INFORMATION_X, pgf_text_width(str)), y, color, str); - } - - // Date - char date_string[16]; - getDateString(date_string, date_format, &file_entry->mtime); - - char time_string[24]; - getTimeString(time_string, time_format, &file_entry->mtime); - - char string[64]; - sprintf(string, "%s %s", date_string, time_string); - - float x = ALIGN_RIGHT(SCREEN_WIDTH - SHELL_MARGIN_X, pgf_text_width(string)); - pgf_draw_text(x, y, color, string); - } - - // Next - file_entry = file_entry->next; - } - } - - // Draw - drawSettingsMenu(); - drawContextMenu(); - drawAdhocDialog(); - drawPropertyDialog(); - - // End drawing - endDrawing(); - } - - // Empty lists - fileListEmpty(©_list); - fileListEmpty(&mark_list); - fileListEmpty(&file_list); - - return 0; -} - void ftpvita_PROM(ftpvita_client_info_t *client) { char cmd[64]; char path[MAX_PATH_LENGTH]; @@ -2221,8 +1257,8 @@ int main(int argc, const char *argv[]) { sceKernelStartThread(thid, 0, NULL); } - // Main - shellMain(); + // File browser + browserMain(); // Finish VitaShell finishVitaShell(); diff --git a/main.h b/main.h index ba8a31a..9e7619e 100644 --- a/main.h +++ b/main.h @@ -250,44 +250,28 @@ enum DialogSteps { DIALOG_STEP_ADHOC_RECEIVED, }; -extern FileList file_list, mark_list, copy_list, install_list; - -extern char cur_file[MAX_PATH_LENGTH]; -extern char archive_copy_path[MAX_PATH_LENGTH]; -extern char archive_path[MAX_PATH_LENGTH]; - -extern int base_pos, rel_pos; -extern int sort_mode, copy_mode; - -extern int last_set_sort_mode; - -// minimum time to pass before shortcutting to recent files/ bookmarks via L/R keys -extern SceInt64 time_last_recent_files, time_last_bookmars; -#define THRESHOLD_LAST_PAD_RECENT_FILES_WAIT 1000000 -#define THRESHOLD_LAST_PAD_BOOKMARKS_WAIT 1000000 - extern vita2d_pgf *font; extern char font_size_cache[256]; +extern char vita_ip[16]; +extern unsigned short int vita_port; + extern VitaShellConfig vitashell_config; extern int SCE_CTRL_ENTER, SCE_CTRL_CANCEL; extern int use_custom_config; -void dirLevelUp(); - int getDialogStep(); void setDialogStep(int step); +int dialogSteps(); + +void initFtp(); +void initUsb(); void drawScrollBar(int pos, int n); void drawShellInfo(const char *path); -int isInArchive(); - -int refreshFileList(); - void ftpvita_PROM(ftpvita_client_info_t *client); -int jump_to_directory_track_current_path(char *path); #endif diff --git a/main_context.c b/main_context.c index 0852e02..15c569d 100644 --- a/main_context.c +++ b/main_context.c @@ -17,6 +17,7 @@ */ #include "main.h" +#include "browser.h" #include "init.h" #include "io_process.h" #include "context_menu.h" diff --git a/photo.c b/photo.c index 771daf2..d780a2e 100644 --- a/photo.c +++ b/photo.c @@ -17,6 +17,7 @@ */ #include "main.h" +#include "browser.h" #include "archive.h" #include "photo.h" #include "file.h" diff --git a/property_dialog.c b/property_dialog.c index d7d19b9..52d4b02 100644 --- a/property_dialog.c +++ b/property_dialog.c @@ -17,6 +17,7 @@ */ #include "main.h" +#include "browser.h" #include "archive.h" #include "init.h" #include "theme.h" diff --git a/sfo.c b/sfo.c index 13e81de..d5ddde3 100644 --- a/sfo.c +++ b/sfo.c @@ -17,6 +17,7 @@ */ #include "main.h" +#include "browser.h" #include "archive.h" #include "file.h" #include "text.h" diff --git a/text.c b/text.c index 99b8f0d..6b52041 100644 --- a/text.c +++ b/text.c @@ -16,7 +16,8 @@ along with this program. If not, see . */ -#include "main.h" +#include "main.h" +#include "browser.h" #include "context_menu.h" #include "archive.h" #include "file.h"