mirror of
https://github.com/joel16/VitaShell.git
synced 2024-11-26 21:30:45 +00:00
481 lines
14 KiB
C
481 lines
14 KiB
C
/*
|
|
VitaShell
|
|
Copyright (C) 2015-2017, 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/>.
|
|
*/
|
|
|
|
#include "main.h"
|
|
#include "archive.h"
|
|
#include "archiveRAR.h"
|
|
#include "init.h"
|
|
#include "theme.h"
|
|
#include "language.h"
|
|
#include "utils.h"
|
|
#include "property_dialog.h"
|
|
|
|
typedef struct {
|
|
int status;
|
|
int reset;
|
|
float info_x;
|
|
float x;
|
|
float y;
|
|
float width;
|
|
float height;
|
|
float scale;
|
|
} PropertyDialog;
|
|
|
|
static PropertyDialog property_dialog;
|
|
|
|
static char property_name[256], property_type[32], property_fself_mode[16];
|
|
static char property_size[16], property_size_new[16];
|
|
static char property_compressed_size[16];
|
|
static char property_contains[64], property_contains_new[64];
|
|
static char property_creation_date[64], property_modification_date[64];
|
|
|
|
static int scroll_count = 0;
|
|
static float scroll_x = 0;
|
|
|
|
typedef struct {
|
|
int name;
|
|
int visibility;
|
|
char *entry;
|
|
int entry_size;
|
|
} PropertyEntry;
|
|
|
|
/*
|
|
TODO:
|
|
- Audio information
|
|
- Image information
|
|
*/
|
|
|
|
PropertyEntry property_entries[] = {
|
|
{ PROPERTY_NAME, PROPERTY_ENTRY_VISIBLE, property_name, sizeof(property_name) },
|
|
{ PROPERTY_TYPE, PROPERTY_ENTRY_VISIBLE, property_type, sizeof(property_type) },
|
|
{ PROPERTY_FSELF_MODE, PROPERTY_ENTRY_VISIBLE, property_fself_mode, sizeof(property_fself_mode) },
|
|
{ PROPERTY_SIZE, PROPERTY_ENTRY_VISIBLE, property_size, sizeof(property_size) },
|
|
{ PROPERTY_COMPRESSED_SIZE, PROPERTY_ENTRY_VISIBLE, property_compressed_size, sizeof(property_compressed_size) },
|
|
{ PROPERTY_CONTAINS, PROPERTY_ENTRY_VISIBLE, property_contains, sizeof(property_contains) },
|
|
{ -1, PROPERTY_ENTRY_UNUSED, NULL },
|
|
{ PROPERTY_CREATION_DATE, PROPERTY_ENTRY_VISIBLE, property_creation_date, sizeof(property_creation_date) },
|
|
{ PROPERTY_MODFICATION_DATE, PROPERTY_ENTRY_VISIBLE, property_modification_date, sizeof(property_modification_date) },
|
|
};
|
|
|
|
enum PropertyEntries {
|
|
PROPERTY_ENTRY_NAME,
|
|
PROPERTY_ENTRY_TYPE,
|
|
PROPERTY_ENTRY_FSELF_MODE,
|
|
PROPERTY_ENTRY_SIZE,
|
|
PROPERTY_ENTRY_COMPRESSED_SIZE,
|
|
PROPERTY_ENTRY_CONTAINS,
|
|
PROPERTY_ENTRY_EMPTY_1,
|
|
PROPERTY_ENTRY_CREATION_DATE,
|
|
PROPERTY_ENTRY_MODIFICATION_DATE,
|
|
};
|
|
|
|
#define N_PROPERTIES_ENTRIES (sizeof(property_entries) / sizeof(PropertyEntry))
|
|
|
|
int getPropertyDialogStatus() {
|
|
return property_dialog.status;
|
|
}
|
|
|
|
static float copyStringGetWidth(char *out, char *in) {
|
|
strcpy(out, in);
|
|
return vita2d_pgf_text_width(font, FONT_SIZE, out);
|
|
}
|
|
|
|
typedef struct {
|
|
char *path;
|
|
} InfoArguments;
|
|
|
|
SceUID info_thid = -1;
|
|
int info_done = 0;
|
|
|
|
static int propertyCancelHandler() {
|
|
return info_done;
|
|
}
|
|
|
|
static int info_thread(SceSize args_size, InfoArguments *args) {
|
|
uint64_t size = 0;
|
|
uint32_t folders = 0, files = 0;
|
|
|
|
info_done = 0;
|
|
getPathInfo(args->path, &size, &folders, &files, propertyCancelHandler);
|
|
info_done = 1;
|
|
|
|
if (folders > 0)
|
|
folders--;
|
|
|
|
getSizeString(property_size_new, size);
|
|
|
|
snprintf(property_contains_new, sizeof(property_contains_new), language_container[PROPERTY_CONTAINS_FILES_FOLDERS], files, folders);
|
|
|
|
property_dialog.reset = 1;
|
|
|
|
return sceKernelExitDeleteThread(0);
|
|
}
|
|
|
|
static void resetWidth() {
|
|
float width = 0.0f, max_width = 0.0f;
|
|
|
|
width = copyStringGetWidth(property_size, property_size_new);
|
|
if (width > max_width)
|
|
max_width = width;
|
|
|
|
width = copyStringGetWidth(property_contains, property_contains_new);
|
|
if (width > max_width)
|
|
max_width = width;
|
|
|
|
if (property_dialog.width < property_dialog.info_x + max_width + 2.0f * SHELL_MARGIN_X) {
|
|
property_dialog.width = property_dialog.info_x + max_width + 2.0f * SHELL_MARGIN_X;
|
|
property_dialog.x = ALIGN_CENTER(SCREEN_WIDTH, property_dialog.width);
|
|
}
|
|
}
|
|
|
|
int initPropertyDialog(char *path, FileListEntry *entry) {
|
|
int i;
|
|
|
|
scroll_count = 0;
|
|
scroll_x = 0;
|
|
|
|
memset(&property_dialog, 0, sizeof(PropertyDialog));
|
|
|
|
// Opening status
|
|
property_dialog.status = PROPERTY_DIALOG_OPENING;
|
|
|
|
// Get info x
|
|
property_dialog.info_x = 0.0f;
|
|
|
|
for (i = 0; i < N_PROPERTIES_ENTRIES; i++) {
|
|
if (property_entries[i].name != -1) {
|
|
float width = vita2d_pgf_text_width(font, FONT_SIZE, language_container[property_entries[i].name]);
|
|
if (width > property_dialog.info_x)
|
|
property_dialog.info_x = width;
|
|
|
|
property_entries[i].visibility = PROPERTY_ENTRY_VISIBLE;
|
|
} else {
|
|
property_entries[i].visibility = PROPERTY_ENTRY_UNUSED;
|
|
}
|
|
}
|
|
|
|
// Extend
|
|
property_dialog.info_x += 2.0f * SHELL_MARGIN_X;
|
|
|
|
// Entries
|
|
float width = 0.0f, max_width = 0.0f;
|
|
|
|
// Name
|
|
strcpy(property_name, entry->name);
|
|
if (entry->is_folder)
|
|
removeEndSlash(property_name);
|
|
|
|
// Type
|
|
int type = entry->is_folder ? FOLDER : FILE_;
|
|
|
|
int size = 0;
|
|
uint32_t buffer[0x88/4];
|
|
|
|
if (isInArchive()) {
|
|
enum FileTypes archiveType = getArchiveType();
|
|
switch(archiveType){
|
|
case FILE_TYPE_ZIP:
|
|
size = ReadArchiveFile(path, buffer, sizeof(buffer));
|
|
break;
|
|
case FILE_TYPE_RAR:
|
|
size = ReadArchiveRARFile(path,buffer,sizeof(buffer));
|
|
break;
|
|
default:
|
|
size = -1;
|
|
break;
|
|
}
|
|
} else {
|
|
size = ReadFile(path, buffer, sizeof(buffer));
|
|
}
|
|
|
|
// FSELF mode
|
|
if (*(uint32_t *)buffer == 0x00454353) {
|
|
type = PROPERTY_TYPE_FSELF;
|
|
|
|
// Check authid flag
|
|
uint64_t authid = *(uint64_t *)((uint32_t)buffer + 0x80);
|
|
if (authid == 0x2F00000000000001 || authid == 0x2F00000000000003) {
|
|
width = copyStringGetWidth(property_fself_mode, language_container[PROPERTY_FSELF_MODE_UNSAFE]);
|
|
} else if (authid == 0x2F00000000000002) {
|
|
width = copyStringGetWidth(property_fself_mode, language_container[PROPERTY_FSELF_MODE_SAFE]);
|
|
} else {
|
|
width = copyStringGetWidth(property_fself_mode, language_container[PROPERTY_FSELF_MODE_SCE]);
|
|
}
|
|
|
|
if (width > max_width)
|
|
max_width = width;
|
|
|
|
property_entries[PROPERTY_ENTRY_FSELF_MODE].visibility = PROPERTY_ENTRY_VISIBLE;
|
|
} else {
|
|
property_entries[PROPERTY_ENTRY_FSELF_MODE].visibility = PROPERTY_ENTRY_INVISIBLE;
|
|
}
|
|
|
|
switch (entry->type) {
|
|
case FILE_TYPE_BMP:
|
|
type = PROPERTY_TYPE_BMP;
|
|
break;
|
|
|
|
case FILE_TYPE_INI:
|
|
type = PROPERTY_TYPE_INI;
|
|
break;
|
|
|
|
case FILE_TYPE_JPEG:
|
|
type = PROPERTY_TYPE_JPEG;
|
|
break;
|
|
|
|
case FILE_TYPE_MP3:
|
|
type = PROPERTY_TYPE_MP3;
|
|
break;
|
|
|
|
case FILE_TYPE_OGG:
|
|
type = PROPERTY_TYPE_OGG;
|
|
break;
|
|
|
|
case FILE_TYPE_PNG:
|
|
type = PROPERTY_TYPE_PNG;
|
|
break;
|
|
|
|
case FILE_TYPE_SFO:
|
|
type = PROPERTY_TYPE_SFO;
|
|
break;
|
|
|
|
case FILE_TYPE_TXT:
|
|
type = PROPERTY_TYPE_TXT;
|
|
break;
|
|
|
|
case FILE_TYPE_VPK:
|
|
type = PROPERTY_TYPE_VPK;
|
|
break;
|
|
|
|
case FILE_TYPE_XML:
|
|
type = PROPERTY_TYPE_XML;
|
|
break;
|
|
|
|
case FILE_TYPE_ZIP:
|
|
type = PROPERTY_TYPE_ZIP;
|
|
break;
|
|
|
|
case FILE_TYPE_RAR:
|
|
type = PROPERTY_TYPE_RAR;
|
|
break;
|
|
}
|
|
|
|
width = copyStringGetWidth(property_type, language_container[type]);
|
|
if (width > max_width)
|
|
max_width = width;
|
|
|
|
// Size & contains
|
|
if (entry->is_folder) {
|
|
if (isInArchive()) {
|
|
property_entries[PROPERTY_ENTRY_SIZE].visibility = PROPERTY_ENTRY_INVISIBLE;
|
|
property_entries[PROPERTY_ENTRY_CONTAINS].visibility = PROPERTY_ENTRY_INVISIBLE;
|
|
} else {
|
|
strcpy(property_size, "...");
|
|
strcpy(property_contains, "...");
|
|
|
|
// Info thread
|
|
InfoArguments info_args;
|
|
info_args.path = path;
|
|
|
|
info_thid = sceKernelCreateThread("info_thread", (SceKernelThreadEntry)info_thread, 0x10000100, 0x100000, 0, 0, NULL);
|
|
if (info_thid >= 0)
|
|
sceKernelStartThread(info_thid, sizeof(InfoArguments), &info_args);
|
|
|
|
property_entries[PROPERTY_ENTRY_CONTAINS].visibility = PROPERTY_ENTRY_VISIBLE;
|
|
}
|
|
|
|
property_entries[PROPERTY_ENTRY_COMPRESSED_SIZE].visibility = PROPERTY_ENTRY_INVISIBLE;
|
|
} else {
|
|
getSizeString(property_size, entry->size);
|
|
property_entries[PROPERTY_ENTRY_CONTAINS].visibility = PROPERTY_ENTRY_INVISIBLE;
|
|
|
|
// Compressed size
|
|
if (isInArchive()) {
|
|
getSizeString(property_compressed_size, entry->size2);
|
|
property_entries[PROPERTY_ENTRY_COMPRESSED_SIZE].visibility = PROPERTY_ENTRY_VISIBLE;
|
|
} else {
|
|
property_entries[PROPERTY_ENTRY_COMPRESSED_SIZE].visibility = PROPERTY_ENTRY_INVISIBLE;
|
|
}
|
|
}
|
|
|
|
// Dates
|
|
char date_string[16];
|
|
char time_string[24];
|
|
char string[64];
|
|
|
|
// Modification date
|
|
getDateString(date_string, date_format, &entry->mtime);
|
|
getTimeString(time_string, time_format, &entry->mtime);
|
|
snprintf(string, sizeof(string), "%s %s", date_string, time_string);
|
|
width = copyStringGetWidth(property_modification_date, string);
|
|
if (width > max_width)
|
|
max_width = width;
|
|
|
|
// Creation date
|
|
getDateString(date_string, date_format, &entry->ctime);
|
|
getTimeString(time_string, time_format, &entry->ctime);
|
|
snprintf(string, sizeof(string), "%s %s", date_string, time_string);
|
|
width = copyStringGetWidth(property_creation_date, string);
|
|
if (width > max_width)
|
|
max_width = width;
|
|
|
|
// Number of entries
|
|
int j = 0;
|
|
|
|
for (i = 0; i < N_PROPERTIES_ENTRIES; i++) {
|
|
if (property_entries[i].visibility != PROPERTY_ENTRY_INVISIBLE)
|
|
j++;
|
|
}
|
|
|
|
// Width and height
|
|
property_dialog.width = property_dialog.info_x + max_width;
|
|
property_dialog.height = FONT_Y_SPACE * j;
|
|
|
|
// For buttons
|
|
property_dialog.height += 2.0f * FONT_Y_SPACE;
|
|
|
|
// Margin
|
|
property_dialog.width += 2.0f * SHELL_MARGIN_X;
|
|
property_dialog.height += 2.0f * SHELL_MARGIN_Y;
|
|
|
|
// Position
|
|
property_dialog.x = ALIGN_CENTER(SCREEN_WIDTH, property_dialog.width);
|
|
property_dialog.y = ALIGN_CENTER(SCREEN_HEIGHT, property_dialog.height);
|
|
|
|
// Align
|
|
int y_n = (int)((float)(property_dialog.y - 2.0f) / FONT_Y_SPACE);
|
|
property_dialog.y = (float)y_n * FONT_Y_SPACE + 2.0f;
|
|
|
|
// Scale
|
|
property_dialog.scale = 0.0f;
|
|
|
|
return 0;
|
|
}
|
|
|
|
void propertyDialogCtrl() {
|
|
if (pressed_buttons & SCE_CTRL_ENTER) {
|
|
info_done = 1;
|
|
sceKernelWaitThreadEnd(info_thid, NULL, NULL);
|
|
property_dialog.status = PROPERTY_DIALOG_CLOSING;
|
|
}
|
|
}
|
|
|
|
void drawPropertyDialog() {
|
|
if (property_dialog.status == PROPERTY_DIALOG_CLOSED)
|
|
return;
|
|
|
|
// Dialog background
|
|
float dialog_width = vita2d_texture_get_width(dialog_image);
|
|
float dialog_height = vita2d_texture_get_height(dialog_image);
|
|
vita2d_draw_texture_scale_rotate_hotspot(dialog_image, property_dialog.x + property_dialog.width / 2.0f,
|
|
property_dialog.y + property_dialog.height / 2.0f,
|
|
property_dialog.scale * (property_dialog.width/dialog_width),
|
|
property_dialog.scale * (property_dialog.height/dialog_height),
|
|
0.0f, dialog_width / 2.0f, dialog_height / 2.0f);
|
|
|
|
// Easing out
|
|
if (property_dialog.status == PROPERTY_DIALOG_CLOSING) {
|
|
if (property_dialog.scale > 0.0f) {
|
|
property_dialog.scale -= easeOut(0.0f, property_dialog.scale, 0.25f, 0.01f);
|
|
} else {
|
|
property_dialog.status = PROPERTY_DIALOG_CLOSED;
|
|
}
|
|
}
|
|
|
|
if (property_dialog.status == PROPERTY_DIALOG_OPENING) {
|
|
if (property_dialog.scale < 1.0f) {
|
|
property_dialog.scale += easeOut(property_dialog.scale, 1.0f, 0.25f, 0.01f);
|
|
} else {
|
|
property_dialog.status = PROPERTY_DIALOG_OPENED;
|
|
}
|
|
}
|
|
|
|
if (property_dialog.reset > 0) {
|
|
if (property_dialog.reset == 1) {
|
|
if (property_dialog.status == PROPERTY_DIALOG_OPENED) {
|
|
property_dialog.status = PROPERTY_DIALOG_CLOSING;
|
|
property_dialog.reset++;
|
|
} else {
|
|
resetWidth();
|
|
property_dialog.reset = 0;
|
|
}
|
|
} else if (property_dialog.reset == 2) {
|
|
if (property_dialog.status == PROPERTY_DIALOG_CLOSED) {
|
|
resetWidth();
|
|
property_dialog.status = PROPERTY_DIALOG_OPENING;
|
|
property_dialog.reset++;
|
|
}
|
|
} else if (property_dialog.reset == 3) {
|
|
if (property_dialog.status == PROPERTY_DIALOG_OPENED) {
|
|
property_dialog.reset = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (property_dialog.status == PROPERTY_DIALOG_OPENED) {
|
|
float string_y = property_dialog.y + SHELL_MARGIN_Y - 2.0f;
|
|
|
|
int i;
|
|
for (i = 0; i < N_PROPERTIES_ENTRIES; i++) {
|
|
if (property_entries[i].visibility == PROPERTY_ENTRY_VISIBLE) {
|
|
pgf_draw_text(property_dialog.x + SHELL_MARGIN_X, string_y, DIALOG_COLOR, FONT_SIZE, language_container[property_entries[i].name]);
|
|
|
|
if (property_entries[i].entry != NULL) {
|
|
uint32_t color = DIALOG_COLOR;
|
|
|
|
float x = property_dialog.x + SHELL_MARGIN_X + property_dialog.info_x;
|
|
float max_width = property_dialog.width-property_dialog.info_x - 2 * SHELL_MARGIN_X;
|
|
|
|
vita2d_enable_clipping();
|
|
vita2d_set_clip_rectangle(x + 1.0f, string_y, x + 1.0f + max_width, string_y + FONT_Y_SPACE);
|
|
|
|
if (property_entries[i].name == PROPERTY_NAME) {
|
|
int width = (int)vita2d_pgf_text_width(font, FONT_SIZE, property_entries[i].entry);
|
|
if (width >= max_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, string_y, color, FONT_SIZE, property_entries[i].entry);
|
|
|
|
vita2d_disable_clipping();
|
|
}
|
|
}
|
|
|
|
if (property_entries[i].visibility != PROPERTY_ENTRY_INVISIBLE)
|
|
string_y += FONT_Y_SPACE;
|
|
}
|
|
|
|
char button_string[32];
|
|
sprintf(button_string, "%s %s", enter_button == SCE_SYSTEM_PARAM_ENTER_BUTTON_CIRCLE ? CIRCLE : CROSS, language_container[OK]);
|
|
pgf_draw_text(ALIGN_CENTER(SCREEN_WIDTH, vita2d_pgf_text_width(font, FONT_SIZE, button_string)), string_y + FONT_Y_SPACE, DIALOG_COLOR, FONT_SIZE, button_string);
|
|
}
|
|
} |