mirror of
https://github.com/joel16/VitaShell.git
synced 2025-02-24 22:31:05 +00:00

Created a better fix, that makes unassisted mode to not mess with dialogs at all, which is much metter Also checks the result of the thread to notify ftp client properly about the result
1455 lines
38 KiB
C
1455 lines
38 KiB
C
/*
|
|
VitaShell
|
|
Copyright (C) 2015-2016, 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 <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
/*
|
|
TODO:
|
|
- Hide mount points
|
|
- Network update
|
|
- Context menu: 'More' entry
|
|
- Inverse sort, sort by date, size
|
|
- vita2dlib: Handle big images > 4096
|
|
- Page skip for text viewer
|
|
- Hex editor byte group size
|
|
- Moving destination folder to subfolder of source folder prevention
|
|
- Moving a folder to a location where the folder does already exit causes error, so move its content.
|
|
- Duplicate when same location or same name. /lol to /lol - Backup. or overwrite question.
|
|
- Shortcuts
|
|
- CPU changement
|
|
- Media player
|
|
*/
|
|
|
|
#include "main.h"
|
|
#include "init.h"
|
|
#include "io_process.h"
|
|
#include "package_installer.h"
|
|
#include "network_update.h"
|
|
#include "archive.h"
|
|
#include "photo.h"
|
|
#include "file.h"
|
|
#include "text.h"
|
|
#include "hex.h"
|
|
#include "message_dialog.h"
|
|
#include "ime_dialog.h"
|
|
#include "theme.h"
|
|
#include "language.h"
|
|
#include "utils.h"
|
|
#include "audioplayer.h"
|
|
#include "sfo.h"
|
|
|
|
int _newlib_heap_size_user = 64 * 1024 * 1024;
|
|
|
|
#define MAX_DIR_LEVELS 1024
|
|
|
|
// File lists
|
|
static FileList file_list, mark_list, copy_list, install_list;
|
|
|
|
// Paths
|
|
static char cur_file[MAX_PATH_LENGTH], archive_path[MAX_PATH_LENGTH], install_path[MAX_PATH_LENGTH];
|
|
|
|
// Position
|
|
static 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;
|
|
|
|
// Copy mode
|
|
static int copy_mode = COPY_MODE_NORMAL;
|
|
|
|
// Archive
|
|
static int is_in_archive = 0;
|
|
static int dir_level_archive = -1;
|
|
|
|
// Context menu
|
|
static int ctx_menu_mode = CONTEXT_MENU_CLOSED;
|
|
static int ctx_menu_pos = -1;
|
|
static float ctx_menu_width = 0;
|
|
static float ctx_menu_max_width = 0;
|
|
|
|
// Net info
|
|
static SceNetEtherAddr mac;
|
|
static char ip[16];
|
|
|
|
// FTP
|
|
static char vita_ip[16];
|
|
static unsigned short int vita_port;
|
|
|
|
// Enter and cancel buttons
|
|
int SCE_CTRL_ENTER = SCE_CTRL_CROSS, SCE_CTRL_CANCEL = SCE_CTRL_CIRCLE;
|
|
|
|
// Dialog step
|
|
int dialog_step = DIALOG_STEP_NONE;
|
|
|
|
// Use custom config
|
|
int use_custom_config = 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;
|
|
}
|
|
}
|
|
|
|
void dirUp() {
|
|
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 = base_pos_list[dir_level];
|
|
rel_pos = rel_pos_list[dir_level];
|
|
dirUpCloseArchive();
|
|
}
|
|
|
|
void focusOnFilename(char *name) {
|
|
int name_pos = fileListGetNumberByName(&file_list, name);
|
|
if (name_pos < file_list.length) {
|
|
while (1) {
|
|
int index = base_pos + rel_pos;
|
|
if (index == name_pos)
|
|
break;
|
|
|
|
if (index > name_pos) {
|
|
if (rel_pos > 0) {
|
|
rel_pos--;
|
|
} else {
|
|
if (base_pos > 0) {
|
|
base_pos--;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (index < name_pos) {
|
|
if ((rel_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++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
int refreshFileList() {
|
|
int ret = 0, res = 0;
|
|
|
|
do {
|
|
fileListEmpty(&file_list);
|
|
|
|
res = fileListGetEntries(&file_list, file_list.path);
|
|
|
|
if (res < 0) {
|
|
ret = res;
|
|
dirUp();
|
|
}
|
|
} while (res < 0);
|
|
|
|
// Correct position after deleting the latest entry of the file list
|
|
while ((base_pos + rel_pos) >= file_list.length) {
|
|
if (base_pos > 0) {
|
|
base_pos--;
|
|
} else {
|
|
if (rel_pos > 0) {
|
|
rel_pos--;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Correct position after deleting an entry while the scrollbar is on the bottom
|
|
if (file_list.length >= MAX_POSITION) {
|
|
while ((base_pos + MAX_POSITION - 1) >= file_list.length) {
|
|
if (base_pos > 0) {
|
|
base_pos--;
|
|
rel_pos++;
|
|
}
|
|
}
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
void refreshMarkList() {
|
|
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;
|
|
if (sceIoGetstat(path, &stat) < 0)
|
|
fileListRemoveEntry(&mark_list, entry);
|
|
|
|
// Next
|
|
entry = next;
|
|
}
|
|
}
|
|
|
|
void refreshCopyList() {
|
|
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;
|
|
int res = sceIoGetstat(path, &stat);
|
|
if (res < 0 && res != 0x80010014)
|
|
fileListRemoveEntry(©_list, entry);
|
|
|
|
// Next
|
|
entry = next;
|
|
}
|
|
}
|
|
|
|
void resetFileLists() {
|
|
memset(&file_list, 0, sizeof(FileList));
|
|
memset(&mark_list, 0, sizeof(FileList));
|
|
memset(©_list, 0, sizeof(FileList));
|
|
|
|
// Home
|
|
strcpy(file_list.path, HOME_PATH);
|
|
|
|
refreshFileList();
|
|
}
|
|
|
|
int handleFile(char *file, FileListEntry *entry) {
|
|
int res = 0;
|
|
|
|
int type = getFileType(file);
|
|
switch (type) {
|
|
case FILE_TYPE_VPK:
|
|
case FILE_TYPE_ZIP:
|
|
if (isInArchive())
|
|
type = FILE_TYPE_UNKNOWN;
|
|
|
|
break;
|
|
}
|
|
|
|
switch (type) {
|
|
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:
|
|
res = audioPlayer(file, &file_list, entry, &base_pos, &rel_pos, SCE_AUDIODEC_TYPE_MP3, 1);
|
|
break;
|
|
|
|
case FILE_TYPE_VPK:
|
|
initMessageDialog(SCE_MSG_DIALOG_BUTTON_TYPE_YESNO, language_container[INSTALL_QUESTION]);
|
|
dialog_step = DIALOG_STEP_INSTALL_QUESTION;
|
|
break;
|
|
|
|
case FILE_TYPE_ZIP:
|
|
res = archiveOpen(file);
|
|
break;
|
|
|
|
case FILE_TYPE_SFO:
|
|
res = SFOReader(file);
|
|
break;
|
|
|
|
default:
|
|
errorDialog(type);
|
|
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);
|
|
|
|
float y = START_Y + ((pos * FONT_Y_SPACE) / (n * FONT_Y_SPACE)) * (MAX_ENTRIES * FONT_Y_SPACE);
|
|
float height = ((MAX_POSITION * FONT_Y_SPACE) / (n * FONT_Y_SPACE)) * (MAX_ENTRIES * FONT_Y_SPACE);
|
|
|
|
vita2d_draw_rectangle(SCROLL_BAR_X, MIN(y, (START_Y + MAX_ENTRIES * FONT_Y_SPACE - height)), SCROLL_BAR_WIDTH, MAX(height, SCROLL_BAR_MIN_HEIGHT), SCROLL_BAR_COLOR);
|
|
}
|
|
}
|
|
|
|
void drawShellInfo(char *path) {
|
|
// Title
|
|
char version[8];
|
|
sprintf(version, "%X.%X", VITASHELL_VERSION_MAJOR, VITASHELL_VERSION_MINOR);
|
|
if (version[3] == '0')
|
|
version[3] = '\0';
|
|
|
|
pgf_draw_textf(SHELL_MARGIN_X, SHELL_MARGIN_Y, TITLE_COLOR, FONT_SIZE, "VitaShell %s", version);
|
|
|
|
// Battery
|
|
float battery_x = ALIGN_LEFT(SCREEN_WIDTH - SHELL_MARGIN_X, vita2d_texture_get_width(battery_image));
|
|
vita2d_draw_texture(battery_image, battery_x, SHELL_MARGIN_Y + 3.0f);
|
|
|
|
vita2d_texture *battery_bar_image = battery_bar_green_image;
|
|
|
|
if (scePowerIsBatteryCharging()) {
|
|
battery_bar_image = battery_bar_charge_image;
|
|
} else if (scePowerIsLowBattery()) {
|
|
battery_bar_image = battery_bar_red_image;
|
|
}
|
|
|
|
float percent = scePowerGetBatteryLifePercent() / 100.0f;
|
|
|
|
float width = vita2d_texture_get_width(battery_bar_image);
|
|
vita2d_draw_texture_part(battery_bar_image, battery_x + 3.0f + (1.0f - percent) * width, SHELL_MARGIN_Y + 5.0f, (1.0f - percent) * width, 0.0f, percent * width, vita2d_texture_get_height(battery_bar_image));
|
|
|
|
// Date & time
|
|
SceDateTime time;
|
|
sceRtcGetCurrentClock(&time, 0);
|
|
|
|
char date_string[16];
|
|
getDateString(date_string, date_format, &time);
|
|
|
|
char time_string[24];
|
|
getTimeString(time_string, time_format, &time);
|
|
|
|
char string[64];
|
|
sprintf(string, "%s %s", date_string, time_string);
|
|
float date_time_x = ALIGN_LEFT(battery_x - 12.0f, vita2d_pgf_text_width(font, FONT_SIZE, string));
|
|
pgf_draw_text(date_time_x, SHELL_MARGIN_Y, DATE_TIME_COLOR, FONT_SIZE, string);
|
|
|
|
// FTP
|
|
if (ftpvita_is_initialized())
|
|
vita2d_draw_texture(ftp_image, date_time_x - 30.0f, SHELL_MARGIN_Y + 3.0f);
|
|
|
|
// TODO: make this more elegant
|
|
// Path
|
|
int line_width = 0;
|
|
|
|
int i;
|
|
for (i = 0; i < strlen(path); i++) {
|
|
char ch_width = font_size_cache[(int)path[i]];
|
|
|
|
// Too long
|
|
if ((line_width + ch_width) >= MAX_WIDTH)
|
|
break;
|
|
|
|
// Increase line width
|
|
line_width += ch_width;
|
|
}
|
|
|
|
char path_first_line[256], path_second_line[256];
|
|
|
|
strncpy(path_first_line, path, i);
|
|
path_first_line[i] = '\0';
|
|
|
|
strcpy(path_second_line, path + i);
|
|
|
|
pgf_draw_text(SHELL_MARGIN_X, PATH_Y, PATH_COLOR, FONT_SIZE, path_first_line);
|
|
pgf_draw_text(SHELL_MARGIN_X, PATH_Y + FONT_Y_SPACE, PATH_COLOR, FONT_SIZE, path_second_line);
|
|
|
|
char str[128];
|
|
|
|
// Show numbers of files and folders
|
|
// sprintf(str, "%d files and %d folders", file_list.files, file_list.folders);
|
|
|
|
// Show memory card
|
|
/*
|
|
uint64_t free_size = 0, max_size = 0;
|
|
sceAppMgrGetDevInfo("ux0:", &max_size, &free_size);
|
|
|
|
char free_size_string[16], max_size_string[16];
|
|
getSizeString(free_size_string, free_size);
|
|
getSizeString(max_size_string, max_size);
|
|
|
|
sprintf(str, "%s/%s", free_size_string, max_size_string);
|
|
*/
|
|
|
|
// Draw on bottom left
|
|
// pgf_draw_textf(ALIGN_LEFT(SCREEN_WIDTH - SHELL_MARGIN_X, vita2d_pgf_text_width(font, FONT_SIZE, str)), SCREEN_HEIGHT - SHELL_MARGIN_Y - FONT_Y_SPACE - 2.0f, LITEGRAY, FONT_SIZE, str);
|
|
}
|
|
|
|
enum MenuEntrys {
|
|
MENU_ENTRY_INSTALL_ALL,
|
|
MENU_ENTRY_MARK_UNMARK_ALL,
|
|
MENU_ENTRY_EMPTY_1,
|
|
MENU_ENTRY_MOVE,
|
|
MENU_ENTRY_COPY,
|
|
MENU_ENTRY_PASTE,
|
|
MENU_ENTRY_EMPTY_3,
|
|
MENU_ENTRY_DELETE,
|
|
MENU_ENTRY_RENAME,
|
|
MENU_ENTRY_EMPTY_4,
|
|
MENU_ENTRY_NEW_FOLDER,
|
|
};
|
|
|
|
enum MenuVisibilities {
|
|
VISIBILITY_UNUSED,
|
|
VISIBILITY_INVISIBLE,
|
|
VISIBILITY_VISIBLE,
|
|
};
|
|
|
|
typedef struct {
|
|
int name;
|
|
int visibility;
|
|
} MenuEntry;
|
|
|
|
MenuEntry menu_entries[] = {
|
|
{ INSTALL_ALL, VISIBILITY_INVISIBLE },
|
|
{ MARK_ALL, VISIBILITY_INVISIBLE },
|
|
{ -1, VISIBILITY_UNUSED },
|
|
{ MOVE, VISIBILITY_INVISIBLE },
|
|
{ COPY, VISIBILITY_INVISIBLE },
|
|
{ PASTE, VISIBILITY_INVISIBLE },
|
|
{ -1, VISIBILITY_UNUSED },
|
|
{ DELETE, VISIBILITY_INVISIBLE },
|
|
{ RENAME, VISIBILITY_INVISIBLE },
|
|
{ -1, VISIBILITY_UNUSED },
|
|
{ NEW_FOLDER, VISIBILITY_INVISIBLE },
|
|
};
|
|
|
|
#define N_MENU_ENTRIES (sizeof(menu_entries) / sizeof(MenuEntry))
|
|
|
|
void initContextMenu() {
|
|
int i;
|
|
|
|
// All visible
|
|
for (i = 0; i < N_MENU_ENTRIES; i++) {
|
|
if (menu_entries[i].visibility == VISIBILITY_INVISIBLE)
|
|
menu_entries[i].visibility = VISIBILITY_VISIBLE;
|
|
}
|
|
|
|
FileListEntry *file_entry = fileListGetNthEntry(&file_list, base_pos + rel_pos);
|
|
|
|
// Invisble entries when on '..'
|
|
if (strcmp(file_entry->name, DIR_UP) == 0) {
|
|
menu_entries[MENU_ENTRY_MARK_UNMARK_ALL].visibility = VISIBILITY_INVISIBLE;
|
|
menu_entries[MENU_ENTRY_MOVE].visibility = VISIBILITY_INVISIBLE;
|
|
menu_entries[MENU_ENTRY_COPY].visibility = VISIBILITY_INVISIBLE;
|
|
menu_entries[MENU_ENTRY_DELETE].visibility = VISIBILITY_INVISIBLE;
|
|
menu_entries[MENU_ENTRY_RENAME].visibility = VISIBILITY_INVISIBLE;
|
|
}
|
|
|
|
// Invisible 'Paste' if nothing is copied yet
|
|
if (copy_list.length == 0)
|
|
menu_entries[MENU_ENTRY_PASTE].visibility = VISIBILITY_INVISIBLE;
|
|
|
|
// Invisble write operations in archives
|
|
if (isInArchive()) { // TODO: read-only mount points
|
|
menu_entries[MENU_ENTRY_MOVE].visibility = VISIBILITY_INVISIBLE;
|
|
menu_entries[MENU_ENTRY_PASTE].visibility = VISIBILITY_INVISIBLE;
|
|
menu_entries[MENU_ENTRY_DELETE].visibility = VISIBILITY_INVISIBLE;
|
|
menu_entries[MENU_ENTRY_RENAME].visibility = VISIBILITY_INVISIBLE;
|
|
menu_entries[MENU_ENTRY_NEW_FOLDER].visibility = VISIBILITY_INVISIBLE;
|
|
}
|
|
|
|
if(file_entry->type != FILE_TYPE_VPK) {
|
|
menu_entries[MENU_ENTRY_INSTALL_ALL].visibility = VISIBILITY_INVISIBLE;
|
|
}
|
|
|
|
// TODO: Moving from one mount point to another is not possible
|
|
|
|
// Mark/Unmark all text
|
|
if (mark_list.length == (file_list.length - 1)) { // All marked
|
|
menu_entries[MENU_ENTRY_MARK_UNMARK_ALL].name = UNMARK_ALL;
|
|
} else { // Not all marked yet
|
|
// On marked entry
|
|
if (fileListFindEntry(&mark_list, file_entry->name)) {
|
|
menu_entries[MENU_ENTRY_MARK_UNMARK_ALL].name = UNMARK_ALL;
|
|
} else {
|
|
menu_entries[MENU_ENTRY_MARK_UNMARK_ALL].name = MARK_ALL;
|
|
}
|
|
}
|
|
|
|
// Go to first entry
|
|
for (i = 0; i < N_MENU_ENTRIES; i++) {
|
|
if (menu_entries[i].visibility == VISIBILITY_VISIBLE) {
|
|
ctx_menu_pos = i;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (i == N_MENU_ENTRIES)
|
|
ctx_menu_pos = -1;
|
|
}
|
|
|
|
float easeOut(float x0, float x1, float a) {
|
|
float dx = (x1 - x0);
|
|
return ((dx * a) > 0.5f) ? (dx * a) : dx;
|
|
}
|
|
|
|
void drawContextMenu() {
|
|
// Easing out
|
|
if (ctx_menu_mode == CONTEXT_MENU_CLOSING) {
|
|
if (ctx_menu_width > 0.0f) {
|
|
ctx_menu_width -= easeOut(0.0f, ctx_menu_width, 0.375f);
|
|
} else {
|
|
ctx_menu_mode = CONTEXT_MENU_CLOSED;
|
|
}
|
|
}
|
|
|
|
if (ctx_menu_mode == CONTEXT_MENU_OPENING) {
|
|
if (ctx_menu_width < ctx_menu_max_width) {
|
|
ctx_menu_width += easeOut(ctx_menu_width, ctx_menu_max_width, 0.375f);
|
|
} else {
|
|
ctx_menu_mode = CONTEXT_MENU_OPENED;
|
|
}
|
|
}
|
|
|
|
// Draw context menu
|
|
if (ctx_menu_mode != CONTEXT_MENU_CLOSED) {
|
|
vita2d_draw_texture_part(context_image, SCREEN_WIDTH - ctx_menu_width, 0.0f, 0.0f, 0.0f, ctx_menu_width, SCREEN_HEIGHT);
|
|
|
|
int i;
|
|
for (i = 0; i < N_MENU_ENTRIES; i++) {
|
|
if (menu_entries[i].visibility == VISIBILITY_UNUSED)
|
|
continue;
|
|
|
|
float y = START_Y + (i * FONT_Y_SPACE);
|
|
|
|
uint32_t color = GENERAL_COLOR;
|
|
|
|
if (i == ctx_menu_pos)
|
|
color = FOCUS_COLOR;
|
|
|
|
if (menu_entries[i].visibility == VISIBILITY_INVISIBLE)
|
|
color = INVISIBLE_COLOR;
|
|
|
|
pgf_draw_text(SCREEN_WIDTH - ctx_menu_width + CONTEXT_MENU_MARGIN, y, color, FONT_SIZE, language_container[menu_entries[i].name]);
|
|
}
|
|
}
|
|
}
|
|
|
|
void contextMenuCtrl() {
|
|
if (hold_buttons & SCE_CTRL_UP || hold2_buttons & SCE_CTRL_LEFT_ANALOG_UP) {
|
|
int i;
|
|
for (i = N_MENU_ENTRIES - 1; i >= 0; i--) {
|
|
if (menu_entries[i].visibility == VISIBILITY_VISIBLE) {
|
|
if (i < ctx_menu_pos) {
|
|
ctx_menu_pos = i;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
} else if (hold_buttons & SCE_CTRL_DOWN || hold2_buttons & SCE_CTRL_LEFT_ANALOG_DOWN) {
|
|
int i;
|
|
for (i = 0; i < N_MENU_ENTRIES; i++) {
|
|
if (menu_entries[i].visibility == VISIBILITY_VISIBLE) {
|
|
if (i > ctx_menu_pos) {
|
|
ctx_menu_pos = i;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Back
|
|
if (pressed_buttons & SCE_CTRL_TRIANGLE || pressed_buttons & SCE_CTRL_CANCEL) {
|
|
ctx_menu_mode = CONTEXT_MENU_CLOSING;
|
|
}
|
|
|
|
// Handle
|
|
if (pressed_buttons & SCE_CTRL_ENTER) {
|
|
switch (ctx_menu_pos) {
|
|
case MENU_ENTRY_MARK_UNMARK_ALL:
|
|
{
|
|
int on_marked_entry = 0;
|
|
int length = mark_list.length;
|
|
|
|
FileListEntry *file_entry = fileListGetNthEntry(&file_list, base_pos + rel_pos);
|
|
if (fileListFindEntry(&mark_list, file_entry->name))
|
|
on_marked_entry = 1;
|
|
|
|
// Empty mark list
|
|
fileListEmpty(&mark_list);
|
|
|
|
// Mark all if not all entries are marked yet and we are not focusing on a marked entry
|
|
if (length != (file_list.length - 1) && !on_marked_entry) {
|
|
FileListEntry *file_entry = file_list.head->next; // Ignore '..'
|
|
|
|
int i;
|
|
for (i = 0; i < file_list.length - 1; i++) {
|
|
FileListEntry *mark_entry = malloc(sizeof(FileListEntry));
|
|
memcpy(mark_entry, file_entry, sizeof(FileListEntry));
|
|
fileListAddEntry(&mark_list, mark_entry, SORT_NONE);
|
|
|
|
// Next
|
|
file_entry = file_entry->next;
|
|
}
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
case MENU_ENTRY_MOVE:
|
|
case MENU_ENTRY_COPY:
|
|
{
|
|
// Mode
|
|
if (ctx_menu_pos == MENU_ENTRY_MOVE) {
|
|
copy_mode = COPY_MODE_MOVE;
|
|
} else {
|
|
copy_mode = isInArchive() ? COPY_MODE_EXTRACT : COPY_MODE_NORMAL;
|
|
}
|
|
|
|
// Empty copy list at first
|
|
if (copy_list.length > 0)
|
|
fileListEmpty(©_list);
|
|
|
|
FileListEntry *file_entry = fileListGetNthEntry(&file_list, base_pos + rel_pos);
|
|
|
|
// Paths
|
|
if (fileListFindEntry(&mark_list, file_entry->name)) { // On marked entry
|
|
// Copy mark list to copy list
|
|
FileListEntry *mark_entry = mark_list.head;
|
|
|
|
int i;
|
|
for (i = 0; i < mark_list.length; i++) {
|
|
FileListEntry *copy_entry = malloc(sizeof(FileListEntry));
|
|
memcpy(copy_entry, mark_entry, sizeof(FileListEntry));
|
|
fileListAddEntry(©_list, copy_entry, SORT_NONE);
|
|
|
|
// Next
|
|
mark_entry = mark_entry->next;
|
|
}
|
|
} else {
|
|
FileListEntry *copy_entry = malloc(sizeof(FileListEntry));
|
|
memcpy(copy_entry, file_entry, sizeof(FileListEntry));
|
|
fileListAddEntry(©_list, copy_entry, SORT_NONE);
|
|
}
|
|
|
|
strcpy(copy_list.path, file_list.path);
|
|
|
|
char *message;
|
|
|
|
// On marked entry
|
|
if (fileListFindEntry(©_list, file_entry->name)) {
|
|
if (copy_list.length == 1) {
|
|
message = language_container[file_entry->is_folder ? COPIED_FOLDER : COPIED_FILE];
|
|
} else {
|
|
message = language_container[COPIED_FILES_FOLDERS];
|
|
}
|
|
} else {
|
|
message = language_container[file_entry->is_folder ? COPIED_FOLDER : COPIED_FILE];
|
|
}
|
|
|
|
// Copy message
|
|
infoDialog(message, copy_list.length);
|
|
|
|
break;
|
|
}
|
|
|
|
case MENU_ENTRY_PASTE:
|
|
initMessageDialog(MESSAGE_DIALOG_PROGRESS_BAR, language_container[copy_mode == COPY_MODE_MOVE ? MOVING : COPYING]);
|
|
dialog_step = DIALOG_STEP_PASTE;
|
|
break;
|
|
|
|
case MENU_ENTRY_DELETE:
|
|
{
|
|
char *message;
|
|
|
|
FileListEntry *file_entry = fileListGetNthEntry(&file_list, base_pos + rel_pos);
|
|
|
|
// On marked entry
|
|
if (fileListFindEntry(&mark_list, file_entry->name)) {
|
|
if (mark_list.length == 1) {
|
|
message = language_container[file_entry->is_folder ? DELETE_FOLDER_QUESTION : DELETE_FILE_QUESTION];
|
|
} else {
|
|
message = language_container[DELETE_FILES_FOLDERS_QUESTION];
|
|
}
|
|
} else {
|
|
message = language_container[file_entry->is_folder ? DELETE_FOLDER_QUESTION : DELETE_FILE_QUESTION];
|
|
}
|
|
|
|
initMessageDialog(SCE_MSG_DIALOG_BUTTON_TYPE_YESNO, message);
|
|
dialog_step = DIALOG_STEP_DELETE_QUESTION;
|
|
break;
|
|
}
|
|
|
|
case MENU_ENTRY_RENAME:
|
|
{
|
|
FileListEntry *file_entry = fileListGetNthEntry(&file_list, base_pos + rel_pos);
|
|
|
|
char name[MAX_NAME_LENGTH];
|
|
strcpy(name, file_entry->name);
|
|
removeEndSlash(name);
|
|
|
|
initImeDialog(language_container[RENAME], name, MAX_NAME_LENGTH);
|
|
|
|
dialog_step = DIALOG_STEP_RENAME;
|
|
break;
|
|
}
|
|
|
|
case MENU_ENTRY_NEW_FOLDER:
|
|
{
|
|
// Find a new folder name
|
|
char path[MAX_PATH_LENGTH];
|
|
|
|
int count = 1;
|
|
while (1) {
|
|
if (count == 1) {
|
|
snprintf(path, MAX_PATH_LENGTH, "%s%s", file_list.path, language_container[NEW_FOLDER]);
|
|
} else {
|
|
snprintf(path, MAX_PATH_LENGTH, "%s%s (%d)", file_list.path, language_container[NEW_FOLDER], count);
|
|
}
|
|
|
|
SceIoStat stat;
|
|
if (sceIoGetstat(path, &stat) < 0)
|
|
break;
|
|
|
|
count++;
|
|
}
|
|
|
|
initImeDialog(language_container[NEW_FOLDER], path + strlen(file_list.path), MAX_NAME_LENGTH);
|
|
dialog_step = DIALOG_STEP_NEW_FOLDER;
|
|
break;
|
|
}
|
|
|
|
case MENU_ENTRY_INSTALL_ALL:
|
|
{
|
|
// Empty install list
|
|
fileListEmpty(&install_list);
|
|
|
|
FileListEntry *file_entry = file_list.head->next; // Ignore '..'
|
|
|
|
int i;
|
|
for (i = 0; i < file_list.length - 1; i++) {
|
|
char path[MAX_PATH_LENGTH];
|
|
snprintf(path, MAX_PATH_LENGTH, "%s%s", file_list.path, file_entry->name);
|
|
|
|
int type = getFileType(path);
|
|
if (type == FILE_TYPE_VPK) {
|
|
FileListEntry *install_entry = malloc(sizeof(FileListEntry));
|
|
memcpy(install_entry, file_entry, sizeof(FileListEntry));
|
|
fileListAddEntry(&install_list, install_entry, SORT_NONE);
|
|
}
|
|
|
|
// Next
|
|
file_entry = file_entry->next;
|
|
}
|
|
|
|
strcpy(install_list.path, file_list.path);
|
|
|
|
initMessageDialog(SCE_MSG_DIALOG_BUTTON_TYPE_YESNO, language_container[INSTALL_ALL_QUESTION]);
|
|
dialog_step = DIALOG_STEP_INSTALL_QUESTION;
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
ctx_menu_mode = CONTEXT_MENU_CLOSING;
|
|
}
|
|
}
|
|
|
|
int dialogSteps() {
|
|
int refresh = 0;
|
|
|
|
int msg_result = updateMessageDialog();
|
|
int ime_result = updateImeDialog();
|
|
|
|
switch (dialog_step) {
|
|
// Without refresh
|
|
case DIALOG_STEP_ERROR:
|
|
case DIALOG_STEP_INFO:
|
|
case DIALOG_STEP_SYSTEM:
|
|
if (msg_result == MESSAGE_DIALOG_RESULT_NONE || msg_result == MESSAGE_DIALOG_RESULT_FINISHED) {
|
|
dialog_step = DIALOG_STEP_NONE;
|
|
}
|
|
|
|
break;
|
|
|
|
// With refresh
|
|
case DIALOG_STEP_COPIED:
|
|
case DIALOG_STEP_DELETED:
|
|
if (msg_result == MESSAGE_DIALOG_RESULT_NONE || msg_result == MESSAGE_DIALOG_RESULT_FINISHED) {
|
|
refresh = 1;
|
|
dialog_step = DIALOG_STEP_NONE;
|
|
}
|
|
|
|
break;
|
|
|
|
case DIALOG_STEP_CANCELLED:
|
|
refresh = 1;
|
|
dialog_step = DIALOG_STEP_NONE;
|
|
break;
|
|
|
|
case DIALOG_STEP_MOVED:
|
|
if (msg_result == MESSAGE_DIALOG_RESULT_NONE || msg_result == MESSAGE_DIALOG_RESULT_FINISHED) {
|
|
fileListEmpty(©_list);
|
|
refresh = 1;
|
|
dialog_step = DIALOG_STEP_NONE;
|
|
}
|
|
|
|
break;
|
|
|
|
case DIALOG_STEP_FTP:
|
|
if (msg_result == MESSAGE_DIALOG_RESULT_YES) {
|
|
dialog_step = DIALOG_STEP_NONE;
|
|
} else if (msg_result == MESSAGE_DIALOG_RESULT_NO) {
|
|
powerUnlock();
|
|
ftpvita_fini();
|
|
refresh = 1;
|
|
dialog_step = DIALOG_STEP_NONE;
|
|
}
|
|
|
|
break;
|
|
|
|
case DIALOG_STEP_PASTE:
|
|
if (msg_result == MESSAGE_DIALOG_RESULT_RUNNING) {
|
|
CopyArguments args;
|
|
args.file_list = &file_list;
|
|
args.copy_list = ©_list;
|
|
args.archive_path = archive_path;
|
|
args.copy_mode = copy_mode;
|
|
|
|
SceUID thid = sceKernelCreateThread("copy_thread", (SceKernelThreadEntry)copy_thread, 0x40, 0x10000, 0, 0, NULL);
|
|
if (thid >= 0)
|
|
sceKernelStartThread(thid, sizeof(CopyArguments), &args);
|
|
|
|
dialog_step = DIALOG_STEP_COPYING;
|
|
}
|
|
|
|
break;
|
|
|
|
case DIALOG_STEP_DELETE_QUESTION:
|
|
if (msg_result == MESSAGE_DIALOG_RESULT_YES) {
|
|
initMessageDialog(MESSAGE_DIALOG_PROGRESS_BAR, language_container[DELETING]);
|
|
dialog_step = DIALOG_STEP_DELETE_CONFIRMED;
|
|
} else if (msg_result == MESSAGE_DIALOG_RESULT_NO) {
|
|
dialog_step = DIALOG_STEP_NONE;
|
|
}
|
|
|
|
break;
|
|
|
|
case DIALOG_STEP_DELETE_CONFIRMED:
|
|
if (msg_result == MESSAGE_DIALOG_RESULT_RUNNING) {
|
|
DeleteArguments args;
|
|
args.file_list = &file_list;
|
|
args.mark_list = &mark_list;
|
|
args.index = base_pos + rel_pos;
|
|
|
|
SceUID thid = sceKernelCreateThread("delete_thread", (SceKernelThreadEntry)delete_thread, 0x40, 0x10000, 0, 0, NULL);
|
|
if (thid >= 0)
|
|
sceKernelStartThread(thid, sizeof(DeleteArguments), &args);
|
|
|
|
dialog_step = DIALOG_STEP_DELETING;
|
|
}
|
|
|
|
break;
|
|
|
|
case DIALOG_STEP_RENAME:
|
|
if (ime_result == IME_DIALOG_RESULT_FINISHED) {
|
|
char *name = (char *)getImeDialogInputTextUTF8();
|
|
if (name[0] == '\0') {
|
|
dialog_step = DIALOG_STEP_NONE;
|
|
} else {
|
|
FileListEntry *file_entry = fileListGetNthEntry(&file_list, base_pos + rel_pos);
|
|
|
|
char old_name[MAX_NAME_LENGTH];
|
|
strcpy(old_name, file_entry->name);
|
|
removeEndSlash(old_name);
|
|
|
|
if (strcmp(old_name, name) == 0) { // No change
|
|
dialog_step = DIALOG_STEP_NONE;
|
|
} else {
|
|
char old_path[MAX_PATH_LENGTH];
|
|
char new_path[MAX_PATH_LENGTH];
|
|
|
|
snprintf(old_path, MAX_PATH_LENGTH, "%s%s", file_list.path, old_name);
|
|
snprintf(new_path, MAX_PATH_LENGTH, "%s%s", file_list.path, name);
|
|
|
|
int res = sceIoRename(old_path, new_path);
|
|
if (res < 0) {
|
|
errorDialog(res);
|
|
} else {
|
|
refresh = 1;
|
|
dialog_step = DIALOG_STEP_NONE;
|
|
}
|
|
}
|
|
}
|
|
} else if (ime_result == IME_DIALOG_RESULT_CANCELED) {
|
|
dialog_step = DIALOG_STEP_NONE;
|
|
}
|
|
|
|
break;
|
|
|
|
case DIALOG_STEP_NEW_FOLDER:
|
|
if (ime_result == IME_DIALOG_RESULT_FINISHED) {
|
|
char *name = (char *)getImeDialogInputTextUTF8();
|
|
if (name[0] == '\0') {
|
|
dialog_step = DIALOG_STEP_NONE;
|
|
} else {
|
|
char path[MAX_PATH_LENGTH];
|
|
snprintf(path, MAX_PATH_LENGTH, "%s%s", file_list.path, name);
|
|
|
|
int res = sceIoMkdir(path, 0777);
|
|
if (res < 0) {
|
|
errorDialog(res);
|
|
} else {
|
|
refresh = 1;
|
|
dialog_step = DIALOG_STEP_NONE;
|
|
}
|
|
}
|
|
} else if (ime_result == IME_DIALOG_RESULT_CANCELED) {
|
|
dialog_step = DIALOG_STEP_NONE;
|
|
}
|
|
|
|
break;
|
|
|
|
case DIALOG_STEP_INSTALL_QUESTION:
|
|
if (msg_result == MESSAGE_DIALOG_RESULT_YES) {
|
|
initMessageDialog(MESSAGE_DIALOG_PROGRESS_BAR, language_container[INSTALLING]);
|
|
dialog_step = DIALOG_STEP_INSTALL_CONFIRMED;
|
|
} else if (msg_result == MESSAGE_DIALOG_RESULT_NO) {
|
|
dialog_step = DIALOG_STEP_NONE;
|
|
}
|
|
|
|
break;
|
|
|
|
case DIALOG_STEP_INSTALL_CONFIRMED:
|
|
if (msg_result == MESSAGE_DIALOG_RESULT_RUNNING) {
|
|
InstallArguments args = {0};
|
|
args.assisted = 1;
|
|
if(install_list.length > 0) {
|
|
FileListEntry *entry = install_list.head;
|
|
snprintf(install_path, MAX_PATH_LENGTH, "%s%s", install_list.path, entry->name);
|
|
args.file = install_path;
|
|
|
|
// Focus
|
|
focusOnFilename(entry->name);
|
|
|
|
// Remove entry
|
|
fileListRemoveEntry(&install_list, entry);
|
|
} else {
|
|
args.file = cur_file;
|
|
}
|
|
|
|
SceUID thid = sceKernelCreateThread("install_thread", (SceKernelThreadEntry)install_thread, 0x40, 0x10000, 0, 0, NULL);
|
|
if (thid >= 0)
|
|
sceKernelStartThread(thid, sizeof(InstallArguments), &args);
|
|
|
|
dialog_step = DIALOG_STEP_INSTALLING;
|
|
}
|
|
|
|
break;
|
|
|
|
case DIALOG_STEP_INSTALL_WARNING:
|
|
if (msg_result == MESSAGE_DIALOG_RESULT_YES) {
|
|
dialog_step = DIALOG_STEP_INSTALL_WARNING_AGREED;
|
|
} else if (msg_result == MESSAGE_DIALOG_RESULT_NO) {
|
|
dialog_step = DIALOG_STEP_CANCELLED;
|
|
}
|
|
|
|
break;
|
|
|
|
case DIALOG_STEP_INSTALLED:
|
|
if (msg_result == MESSAGE_DIALOG_RESULT_NONE || msg_result == MESSAGE_DIALOG_RESULT_FINISHED) {
|
|
if(install_list.length > 0) {
|
|
initMessageDialog(MESSAGE_DIALOG_PROGRESS_BAR, language_container[INSTALLING]);
|
|
dialog_step = DIALOG_STEP_INSTALL_CONFIRMED;
|
|
break;
|
|
}
|
|
|
|
dialog_step = DIALOG_STEP_NONE;
|
|
}
|
|
|
|
break;
|
|
|
|
case DIALOG_STEP_UPDATE_QUESTION:
|
|
if (msg_result == MESSAGE_DIALOG_RESULT_YES) {
|
|
initMessageDialog(MESSAGE_DIALOG_PROGRESS_BAR, language_container[DOWNLOADING]);
|
|
dialog_step = DIALOG_STEP_DOWNLOADING;
|
|
} else if (msg_result == MESSAGE_DIALOG_RESULT_NO) {
|
|
dialog_step = DIALOG_STEP_NONE;
|
|
}
|
|
|
|
case DIALOG_STEP_DOWNLOADED:
|
|
if (msg_result == MESSAGE_DIALOG_RESULT_FINISHED) {
|
|
initMessageDialog(MESSAGE_DIALOG_PROGRESS_BAR, language_container[INSTALLING]);
|
|
|
|
SceUID thid = sceKernelCreateThread("update_extract_thread", (SceKernelThreadEntry)update_extract_thread, 0x40, 0x10000, 0, 0, NULL);
|
|
if (thid >= 0)
|
|
sceKernelStartThread(thid, 0, NULL);
|
|
|
|
dialog_step = DIALOG_STEP_EXTRACTING;
|
|
}
|
|
|
|
break;
|
|
|
|
case DIALOG_STEP_EXTRACTED:
|
|
launchAppByUriExit("VSUPDATER");
|
|
dialog_step = DIALOG_STEP_NONE;
|
|
break;
|
|
}
|
|
|
|
return refresh;
|
|
}
|
|
|
|
void fileBrowserMenuCtrl() {
|
|
// System information
|
|
if (current_buttons & SCE_CTRL_START) {
|
|
SceSystemSwVersionParam sw_ver_param;
|
|
sw_ver_param.size = sizeof(SceSystemSwVersionParam);
|
|
sceKernelGetSystemSwVersion(&sw_ver_param);
|
|
|
|
char mac_string[32];
|
|
sprintf(mac_string, "%02X:%02X:%02X:%02X:%02X:%02X", mac.data[0], mac.data[1], mac.data[2], mac.data[3], mac.data[4], mac.data[5]);
|
|
|
|
uint64_t free_size = 0, max_size = 0;
|
|
sceAppMgrGetDevInfo("ux0:", &max_size, &free_size);
|
|
|
|
char free_size_string[16], max_size_string[16];
|
|
getSizeString(free_size_string, free_size);
|
|
getSizeString(max_size_string, max_size);
|
|
|
|
initMessageDialog(SCE_MSG_DIALOG_BUTTON_TYPE_OK, language_container[SYS_INFO], sw_ver_param.version_string, sceKernelGetModelForCDialog(), mac_string, ip, free_size_string, max_size_string);
|
|
dialog_step = DIALOG_STEP_SYSTEM;
|
|
}
|
|
|
|
// FTP
|
|
if (pressed_buttons & SCE_CTRL_SELECT) {
|
|
// Init FTP
|
|
if (!ftpvita_is_initialized()) {
|
|
int res = ftpvita_init(vita_ip, &vita_port);
|
|
if (res < 0) {
|
|
infoDialog(language_container[WIFI_ERROR]);
|
|
} else {
|
|
// Add all the current mountpoints to ftpvita
|
|
int i;
|
|
for (i = 0; i < getNumberMountPoints(); i++) {
|
|
char **mount_points = getMountPoints();
|
|
if (mount_points[i]) {
|
|
ftpvita_add_device(mount_points[i]);
|
|
}
|
|
}
|
|
ftpvita_ext_add_custom_command("PROM", ftpvita_PROM);
|
|
}
|
|
|
|
// 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);
|
|
dialog_step = DIALOG_STEP_FTP;
|
|
}
|
|
}
|
|
|
|
// Move
|
|
if (hold_buttons & SCE_CTRL_UP || hold2_buttons & SCE_CTRL_LEFT_ANALOG_UP) {
|
|
if (rel_pos > 0) {
|
|
rel_pos--;
|
|
} else {
|
|
if (base_pos > 0) {
|
|
base_pos--;
|
|
}
|
|
}
|
|
} else if (hold_buttons & SCE_CTRL_DOWN || hold2_buttons & SCE_CTRL_LEFT_ANALOG_DOWN) {
|
|
if ((rel_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++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Not at 'home'
|
|
if (dir_level > 0) {
|
|
// Context menu trigger
|
|
if (pressed_buttons & SCE_CTRL_TRIANGLE) {
|
|
if (ctx_menu_mode == CONTEXT_MENU_CLOSED) {
|
|
initContextMenu();
|
|
ctx_menu_mode = CONTEXT_MENU_OPENING;
|
|
}
|
|
}
|
|
|
|
// Mark entry
|
|
if (pressed_buttons & SCE_CTRL_SQUARE) {
|
|
FileListEntry *file_entry = fileListGetNthEntry(&file_list, base_pos + rel_pos);
|
|
if (strcmp(file_entry->name, DIR_UP) != 0) {
|
|
if (!fileListFindEntry(&mark_list, file_entry->name)) {
|
|
FileListEntry *mark_entry = malloc(sizeof(FileListEntry));
|
|
memcpy(mark_entry, file_entry, sizeof(FileListEntry));
|
|
fileListAddEntry(&mark_list, mark_entry, SORT_NONE);
|
|
} else {
|
|
fileListRemoveEntryByName(&mark_list, file_entry->name);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Back
|
|
if (pressed_buttons & SCE_CTRL_CANCEL) {
|
|
fileListEmpty(&mark_list);
|
|
dirUp();
|
|
refreshFileList();
|
|
}
|
|
}
|
|
|
|
// Handle
|
|
if (pressed_buttons & SCE_CTRL_ENTER) {
|
|
fileListEmpty(&mark_list);
|
|
|
|
// Handle file or folder
|
|
FileListEntry *file_entry = fileListGetNthEntry(&file_list, base_pos + rel_pos);
|
|
if (file_entry->is_folder) {
|
|
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();
|
|
}
|
|
|
|
// Open folder
|
|
int res = refreshFileList();
|
|
if (res < 0)
|
|
errorDialog(res);
|
|
} else {
|
|
snprintf(cur_file, MAX_PATH_LENGTH, "%s%s", file_list.path, file_entry->name);
|
|
int type = handleFile(cur_file, file_entry);
|
|
|
|
// Archive mode
|
|
if (type == FILE_TYPE_ZIP) {
|
|
is_in_archive = 1;
|
|
dir_level_archive = dir_level;
|
|
|
|
snprintf(archive_path, MAX_PATH_LENGTH, "%s%s", file_list.path, file_entry->name);
|
|
|
|
strcat(file_list.path, file_entry->name);
|
|
addEndSlash(file_list.path);
|
|
|
|
dirLevelUp();
|
|
refreshFileList();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
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));
|
|
|
|
// Reset file lists
|
|
resetFileLists();
|
|
|
|
while (1) {
|
|
readPad();
|
|
|
|
int refresh = 0;
|
|
|
|
// Control
|
|
if (dialog_step == DIALOG_STEP_NONE) {
|
|
if (ctx_menu_mode != CONTEXT_MENU_CLOSED) {
|
|
contextMenuCtrl();
|
|
} else {
|
|
fileBrowserMenuCtrl();
|
|
}
|
|
} else {
|
|
refresh = dialogSteps();
|
|
}
|
|
|
|
// Receive system event
|
|
SceAppMgrSystemEvent event;
|
|
sceAppMgrReceiveSystemEvent(&event);
|
|
|
|
// Refresh on app resume
|
|
if (event.systemEvent == SCE_APPMGR_SYSTEMEVENT_ON_RESUME) {
|
|
refresh = 1;
|
|
}
|
|
|
|
if (refresh) {
|
|
// Refresh lists
|
|
refreshFileList();
|
|
refreshMarkList();
|
|
refreshCopyList();
|
|
}
|
|
|
|
// Start drawing
|
|
startDrawing(bg_browser_image);
|
|
|
|
// Draw shell info
|
|
drawShellInfo(file_list.path);
|
|
|
|
// Draw scroll bar
|
|
drawScrollBar(base_pos, file_list.length);
|
|
|
|
// Draw
|
|
FileListEntry *file_entry = fileListGetNthEntry(&file_list, base_pos);
|
|
|
|
int i;
|
|
for (i = 0; i < MAX_ENTRIES && (base_pos + i) < file_list.length; i++) {
|
|
uint32_t color = GENERAL_COLOR;
|
|
float y = START_Y + (i * FONT_Y_SPACE);
|
|
|
|
// Folder
|
|
if (file_entry->is_folder) {
|
|
color = FOLDER_COLOR;
|
|
vita2d_draw_texture(folder_icon, SHELL_MARGIN_X, y + 3.0f);
|
|
} else {
|
|
if (file_entry->type == FILE_TYPE_BMP || file_entry->type == FILE_TYPE_PNG || file_entry->type == FILE_TYPE_JPEG) { // Images
|
|
color = IMAGE_COLOR;
|
|
vita2d_draw_texture(image_icon, SHELL_MARGIN_X, y + 3.0f);
|
|
} else if (file_entry->type == FILE_TYPE_VPK || file_entry->type == FILE_TYPE_ZIP) { // Archive
|
|
color = ARCHIVE_COLOR;
|
|
vita2d_draw_texture(archive_icon, SHELL_MARGIN_X, y + 3.0f);
|
|
} else if (file_entry->type == FILE_TYPE_MP3) { // Audio
|
|
color = IMAGE_COLOR;
|
|
vita2d_draw_texture(audio_icon, SHELL_MARGIN_X, y + 3.0f);
|
|
} else if (file_entry->type == FILE_TYPE_SFO) { // SFO
|
|
// note: specific color to be determined
|
|
vita2d_draw_texture(sfo_icon, SHELL_MARGIN_X, y + 3.0f);
|
|
} else if (file_entry->type == FILE_TYPE_INI || file_entry->type == FILE_TYPE_TXT || file_entry->type == FILE_TYPE_XML) { // TXT
|
|
// note: specific color to be determined
|
|
vita2d_draw_texture(text_icon, SHELL_MARGIN_X, y + 3.0f);
|
|
} else { // Other files
|
|
vita2d_draw_texture(file_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);
|
|
|
|
// File name
|
|
int length = strlen(file_entry->name);
|
|
int line_width = 0;
|
|
|
|
int j;
|
|
for (j = 0; j < length; j++) {
|
|
char ch_width = font_size_cache[(int)file_entry->name[j]];
|
|
|
|
// Too long
|
|
if ((line_width + ch_width) >= MAX_NAME_WIDTH)
|
|
break;
|
|
|
|
// Increase line width
|
|
line_width += ch_width;
|
|
}
|
|
|
|
char ch = 0;
|
|
|
|
if (j != length) {
|
|
ch = file_entry->name[j];
|
|
file_entry->name[j] = '\0';
|
|
}
|
|
|
|
// Draw shortened file name
|
|
pgf_draw_text(SHELL_MARGIN_X + 26.0f, y, color, FONT_SIZE, file_entry->name);
|
|
|
|
if (j != length)
|
|
file_entry->name[j] = ch;
|
|
|
|
// File information
|
|
if (strcmp(file_entry->name, DIR_UP) != 0) {
|
|
// Folder/size
|
|
char size_string[16];
|
|
getSizeString(size_string, file_entry->size);
|
|
|
|
char *str = file_entry->is_folder ? language_container[FOLDER] : size_string;
|
|
|
|
pgf_draw_text(ALIGN_LEFT(INFORMATION_X, vita2d_pgf_text_width(font, FONT_SIZE, str)), y, color, FONT_SIZE, str);
|
|
|
|
// Date
|
|
char date_string[16];
|
|
getDateString(date_string, date_format, &file_entry->time);
|
|
|
|
char time_string[24];
|
|
getTimeString(time_string, time_format, &file_entry->time);
|
|
|
|
char string[64];
|
|
sprintf(string, "%s %s", date_string, time_string);
|
|
|
|
pgf_draw_text(ALIGN_LEFT(SCREEN_WIDTH - SHELL_MARGIN_X, vita2d_pgf_text_width(font, FONT_SIZE, string)), y, color, FONT_SIZE, string);
|
|
}
|
|
|
|
// Next
|
|
file_entry = file_entry->next;
|
|
}
|
|
|
|
// Draw context menu
|
|
drawContextMenu();
|
|
|
|
// End drawing
|
|
endDrawing();
|
|
}
|
|
|
|
// Empty lists
|
|
fileListEmpty(©_list);
|
|
fileListEmpty(&mark_list);
|
|
fileListEmpty(&file_list);
|
|
|
|
return 0;
|
|
}
|
|
|
|
void initShell() {
|
|
int i;
|
|
for (i = 0; i < N_MENU_ENTRIES; i++) {
|
|
if (menu_entries[i].visibility != VISIBILITY_UNUSED)
|
|
ctx_menu_max_width = MAX(ctx_menu_max_width, vita2d_pgf_text_width(font, FONT_SIZE, language_container[menu_entries[i].name]));
|
|
|
|
if (menu_entries[i].name == MARK_ALL) {
|
|
menu_entries[i].name = UNMARK_ALL;
|
|
i--;
|
|
}
|
|
}
|
|
|
|
ctx_menu_max_width += 2.0f * CONTEXT_MENU_MARGIN;
|
|
ctx_menu_max_width = MAX(ctx_menu_max_width, CONTEXT_MENU_MIN_WIDTH);
|
|
}
|
|
|
|
void getNetInfo() {
|
|
// Get mac address
|
|
sceNetGetMacAddress(&mac, 0);
|
|
|
|
// Get IP
|
|
SceNetCtlInfo info;
|
|
if (sceNetCtlInetGetInfo(SCE_NETCTL_INFO_GET_IP_ADDRESS, &info) < 0) {
|
|
strcpy(ip, "-");
|
|
} else {
|
|
strcpy(ip, info.ip_address);
|
|
}
|
|
}
|
|
|
|
void ftpvita_PROM(ftpvita_client_info_t *client) {
|
|
char cmd[64];
|
|
char path[MAX_PATH_LENGTH];
|
|
sscanf(client->recv_buffer, "%s %s", cmd, path);
|
|
|
|
InstallArguments args = {0};
|
|
args.file = path;
|
|
args.assisted = 0;
|
|
|
|
SceUID thid = sceKernelCreateThread("install_thread", (SceKernelThreadEntry)install_thread, 0x40, 0x10000, 0, 0, NULL);
|
|
if (thid >= 0) {
|
|
int exitStatus = 0;
|
|
sceKernelStartThread(thid, sizeof(InstallArguments), &args);
|
|
sceKernelWaitThreadEnd(thid, &exitStatus, NULL);
|
|
|
|
if (exitStatus == 0) {
|
|
ftpvita_ext_client_send_ctrl_msg(client, "200 OK PROMOTING\r\n");
|
|
} else {
|
|
ftpvita_ext_client_send_ctrl_msg(client, "500 ERROR PROMOTING\r\n");
|
|
}
|
|
}
|
|
}
|
|
|
|
int main(int argc, const char *argv[]) {
|
|
// Init VitaShell
|
|
initVitaShell();
|
|
|
|
// Get net info
|
|
getNetInfo();
|
|
|
|
// No custom config, in case they are damaged or unuseable
|
|
readPad();
|
|
if (current_buttons & SCE_CTRL_LTRIGGER)
|
|
use_custom_config = 0;
|
|
|
|
// Load theme
|
|
loadTheme();
|
|
|
|
// Load language
|
|
loadLanguage(language);
|
|
|
|
// Automatic network update
|
|
SceUID thid = sceKernelCreateThread("network_update_thread", (SceKernelThreadEntry)network_update_thread, 0x40, 0x10000, 0, 0, NULL);
|
|
if (thid >= 0)
|
|
sceKernelStartThread(thid, 0, NULL);
|
|
|
|
// Main
|
|
initShell();
|
|
shellMain();
|
|
|
|
// Finish VitaShell
|
|
finishVitaShell();
|
|
|
|
return 0;
|
|
}
|