OpenRCT2/src/windows/loadsave.c

946 lines
28 KiB
C
Raw Normal View History

#pragma region Copyright (c) 2014-2016 OpenRCT2 Developers
/*****************************************************************************
* OpenRCT2, an open source clone of Roller Coaster Tycoon 2.
*
* OpenRCT2 is the work of many authors, a full list can be found in contributors.md
* For more information, visit https://github.com/OpenRCT2/OpenRCT2
*
* OpenRCT2 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.
*
* A full copy of the GNU General Public License can be found in licence.txt
*****************************************************************************/
#pragma endregion
2015-10-20 20:16:30 +02:00
#include <time.h>
#include "../addresses.h"
#include "../config.h"
#include "../game.h"
#include "../editor.h"
#include "../interface/widget.h"
#include "../interface/window.h"
#include "../localisation/localisation.h"
#include "../network/network.h"
#include "../scenario.h"
#include "../title.h"
#include "../windows/error.h"
#include "../interface/themes.h"
2015-06-24 18:22:12 +02:00
#include "../interface/title_sequences.h"
#include "../util/util.h"
#pragma region Widgets
#define WW 340
#define WH 400
enum {
WIDX_BACKGROUND,
WIDX_TITLE,
WIDX_CLOSE,
WIDX_UP,
WIDX_NEW,
2015-06-22 13:49:35 +02:00
WIDX_SORT_NAME,
WIDX_SORT_DATE,
WIDX_SCROLL,
2015-02-15 19:48:25 +01:00
WIDX_BROWSE,
};
// 0x9DE48C
static rct_widget window_loadsave_widgets[] = {
2015-06-22 13:49:35 +02:00
{ WWT_FRAME, 0, 0, WW - 1, 0, WH - 1, STR_NONE, STR_NONE },
{ WWT_CAPTION, 0, 1, WW - 2, 1, 14, STR_NONE, STR_WINDOW_TITLE_TIP },
{ WWT_CLOSEBOX, 0, WW - 13, WW - 3, 2, 13, STR_CLOSE_X, STR_CLOSE_WINDOW_TIP }, //Window close button
{ WWT_CLOSEBOX, 0, 4, 104, 36, 47, 2718, STR_NONE}, // Up
{ WWT_CLOSEBOX, 0, 105, 205, 36, 47, 2719, STR_NONE}, // New
{ WWT_CLOSEBOX, 0, 4, (WW - 5) / 2, 50, 61, STR_NONE, STR_NONE }, // Name
{ WWT_CLOSEBOX, 0, (WW - 5) / 2 + 1, WW - 5 - 1, 50, 61, STR_NONE, STR_NONE }, // Date
{ WWT_SCROLL, 0, 4, WW - 5, 61, WH - 40, 2, STR_NONE }, // File list
2015-06-22 13:49:35 +02:00
{ WWT_CLOSEBOX, 0, 4, 200, WH - 36, WH - 18, 2707, STR_NONE }, // Use native browser
{ WIDGETS_END }
};
#pragma endregion
#pragma region Events
static void window_loadsave_close(rct_window *w);
static void window_loadsave_mouseup(rct_window *w, int widgetIndex);
static void window_loadsave_scrollgetsize(rct_window *w, int scrollIndex, int *width, int *height);
static void window_loadsave_scrollmousedown(rct_window *w, int scrollIndex, int x, int y);
static void window_loadsave_scrollmouseover(rct_window *w, int scrollIndex, int x, int y);
static void window_loadsave_textinput(rct_window *w, int widgetIndex, char *text);
static void window_loadsave_tooltip(rct_window* w, int widgetIndex, rct_string_id *stringId);
static void window_loadsave_invalidate(rct_window *w);
static void window_loadsave_paint(rct_window *w, rct_drawpixelinfo *dpi);
static void window_loadsave_scrollpaint(rct_window *w, rct_drawpixelinfo *dpi, int scrollIndex);
static rct_window_event_list window_loadsave_events = {
window_loadsave_close,
window_loadsave_mouseup,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
window_loadsave_scrollgetsize,
window_loadsave_scrollmousedown,
NULL,
window_loadsave_scrollmouseover,
window_loadsave_textinput,
NULL,
NULL,
window_loadsave_tooltip,
NULL,
NULL,
window_loadsave_invalidate,
window_loadsave_paint,
window_loadsave_scrollpaint
};
#pragma endregion
2015-06-22 13:49:35 +02:00
enum {
TYPE_DIRECTORY,
TYPE_FILE,
};
2016-05-12 23:57:40 +02:00
typedef struct loadsave_list_item {
char name[256];
char path[MAX_PATH];
2015-06-22 13:49:35 +02:00
time_t date_modified;
uint8 type;
} loadsave_list_item;
2015-11-02 21:43:55 +01:00
modal_callback gLoadSaveCallback;
int _listItemsCount = 0;
loadsave_list_item *_listItems = NULL;
char _directory[MAX_PATH];
char _shortenedDirectory[MAX_PATH];
static char _parentDirectory[MAX_PATH];
char _extension[32];
char _defaultName[MAX_PATH];
int _loadsaveType;
int _type;
static void window_loadsave_populate_list(rct_window *w, int includeNewItem, const char *directory, const char *extension);
static void window_loadsave_select(rct_window *w, const char *path);
2015-06-22 13:49:35 +02:00
static void window_loadsave_sort_list(int index, int endIndex);
static int has_extension(char *path, char *extension);
2015-02-15 19:48:25 +01:00
static rct_window *window_overwrite_prompt_open(const char *name, const char *path);
rct_window *window_loadsave_open(int type, char *defaultName)
{
2015-11-02 21:43:55 +01:00
gLoadSaveCallback = NULL;
2015-06-24 18:22:12 +02:00
gLoadSaveTitleSequenceSave = false;
char path[MAX_PATH], *ch;
int includeNewItem;
rct_window* w;
_type = type;
_defaultName[0] = '\0';
if (!str_is_null_or_empty(defaultName)) {
2016-01-18 20:49:52 +01:00
safe_strcpy(_defaultName, defaultName, sizeof(_defaultName));
}
w = window_bring_to_front_by_class(WC_LOADSAVE);
if (w == NULL) {
w = window_create_centred(WW, WH, &window_loadsave_events, WC_LOADSAVE, WF_STICK_TO_FRONT);
w->widgets = window_loadsave_widgets;
w->enabled_widgets = (1 << WIDX_CLOSE) | (1 << WIDX_UP) | (1 << WIDX_NEW) | (1 << WIDX_SORT_NAME) | (1 << WIDX_SORT_DATE) | (1 << WIDX_BROWSE);
w->colours[0] = 7;
w->colours[1] = 7;
w->colours[2] = 7;
}
_loadsaveType = type;
switch (type & 0x0F) {
case (LOADSAVETYPE_LOAD | LOADSAVETYPE_GAME):
w->widgets[WIDX_TITLE].image = STR_FILE_DIALOG_TITLE_LOAD_GAME;
break;
case (LOADSAVETYPE_SAVE | LOADSAVETYPE_GAME) :
w->widgets[WIDX_TITLE].image = STR_FILE_DIALOG_TITLE_SAVE_GAME;
break;
case (LOADSAVETYPE_LOAD | LOADSAVETYPE_LANDSCAPE) :
w->widgets[WIDX_TITLE].image = STR_FILE_DIALOG_TITLE_LOAD_LANDSCAPE;
break;
case (LOADSAVETYPE_SAVE | LOADSAVETYPE_LANDSCAPE) :
w->widgets[WIDX_TITLE].image = STR_FILE_DIALOG_TITLE_SAVE_LANDSCAPE;
break;
case (LOADSAVETYPE_SAVE | LOADSAVETYPE_SCENARIO) :
w->widgets[WIDX_TITLE].image = STR_FILE_DIALOG_TITLE_SAVE_SCENARIO;
break;
2015-04-02 23:00:59 +02:00
case (LOADSAVETYPE_LOAD | LOADSAVETYPE_TRACK) :
w->widgets[WIDX_TITLE].image = STR_FILE_DIALOG_TITLE_INSTALL_NEW_TRACK_DESIGN;
2015-04-02 23:00:59 +02:00
break;
default:
log_error("Unsupported load / save type: %d", type & 0x0F);
return NULL;
}
w->no_list_items = 0;
w->selected_list_item = -1;
includeNewItem = (type & 0x01) == LOADSAVETYPE_SAVE;
switch (type & 0x0E) {
case LOADSAVETYPE_GAME:
platform_get_user_directory(path, "save");
if (!platform_ensure_directory_exists(path)) {
log_error("Unable to create save directory.");
window_close(w);
return NULL;
}
window_loadsave_populate_list(w, includeNewItem, path, ".sv6");
break;
case LOADSAVETYPE_LANDSCAPE:
platform_get_user_directory(path, "landscape");
if (!platform_ensure_directory_exists(path)) {
log_error("Unable to create landscapes directory.");
window_close(w);
return NULL;
}
window_loadsave_populate_list(w, includeNewItem, path, ".sc6");
break;
case LOADSAVETYPE_SCENARIO:
platform_get_user_directory(path, "scenario");
if (!platform_ensure_directory_exists(path)) {
log_error("Unable to create scenarios directory.");
window_close(w);
return NULL;
}
window_loadsave_populate_list(w, includeNewItem, path, ".sc6");
break;
2015-04-02 23:00:59 +02:00
case LOADSAVETYPE_TRACK:
/*
Uncomment when user tracks are separated
platform_get_user_directory(path, "tracks");
if (!platform_ensure_directory_exists(path)) {
log_error("Unable to create tracks directory.");
2015-04-02 23:00:59 +02:00
window_close(w);
return NULL;
}
*/
2016-06-19 23:47:06 +02:00
safe_strcpy(path, gRCT2AddressTracksPath, MAX_PATH);
2015-04-02 23:00:59 +02:00
ch = strchr(path, '*');
if (ch != NULL)
*ch = 0;
window_loadsave_populate_list(w, includeNewItem, path, ".td?");
2015-04-02 23:00:59 +02:00
break;
}
w->no_list_items = _listItemsCount;
window_init_scroll_widgets(w);
return w;
}
static void window_loadsave_close(rct_window *w)
{
if (_listItems != NULL) {
free(_listItems);
_listItems = NULL;
}
window_close_by_class(WC_LOADSAVE_OVERWRITE_PROMPT);
}
static void window_loadsave_mouseup(rct_window *w, int widgetIndex)
{
int result = 0;
char path[MAX_PATH], filter[MAX_PATH];
switch (widgetIndex){
case WIDX_CLOSE:
window_close(w);
break;
case WIDX_UP:
{
char directory[MAX_PATH];
int includeNewItem = (_type & 1) == LOADSAVETYPE_SAVE;
2016-01-18 20:49:52 +01:00
safe_strcpy(directory, _parentDirectory, sizeof(directory));
window_loadsave_populate_list(w, includeNewItem, directory, _extension);
window_init_scroll_widgets(w);
w->no_list_items = _listItemsCount;
break;
}
case WIDX_NEW:
{
rct_string_id templateStringId = STR_PLACEHOLDER;
char *templateString;
templateString = (char *)language_get_string(templateStringId);
strcpy(templateString, _defaultName);
window_text_input_open(w, WIDX_NEW, STR_NONE, 2710, templateStringId, 0, 64);
break;
}
2015-02-15 19:48:25 +01:00
case WIDX_BROWSE:
2016-01-18 20:49:52 +01:00
safe_strcpy(path, _directory, MAX_PATH);
2016-01-02 23:41:35 +01:00
if (_type & LOADSAVETYPE_SAVE) {
strcat(path, _defaultName);
}
2015-02-15 19:48:25 +01:00
memset(filter, '\0', MAX_PATH);
2016-01-18 20:49:52 +01:00
safe_strcpy(filter, "*", MAX_PATH);
strncat(filter, _extension, MAX_PATH - strnlen(filter, MAX_PATH) - 1);
2015-02-15 19:48:25 +01:00
file_dialog_desc desc;
memset(&desc, 0, sizeof(desc));
desc.initial_directory = _directory;
if (_type & LOADSAVETYPE_SAVE) {
desc.default_filename = path;
}
2015-02-15 19:48:25 +01:00
switch (_type) {
case (LOADSAVETYPE_LOAD | LOADSAVETYPE_GAME) :
desc.type = FD_OPEN;
desc.title = language_get_string(STR_FILE_DIALOG_TITLE_LOAD_GAME);
desc.filters[0].name = language_get_string(STR_OPENRCT2_SAVED_GAME);
desc.filters[0].pattern = "*.sv4;*.sv6";
2015-02-15 19:48:25 +01:00
break;
case (LOADSAVETYPE_SAVE | LOADSAVETYPE_GAME) :
desc.type = FD_SAVE;
desc.title = language_get_string(STR_FILE_DIALOG_TITLE_SAVE_GAME);
desc.filters[0].name = language_get_string(STR_OPENRCT2_SAVED_GAME);
desc.filters[0].pattern = "*.sv6";
2015-02-15 19:48:25 +01:00
break;
case (LOADSAVETYPE_LOAD | LOADSAVETYPE_LANDSCAPE) :
desc.type = FD_OPEN;
desc.title = language_get_string(STR_FILE_DIALOG_TITLE_LOAD_LANDSCAPE);
desc.filters[0].name = language_get_string(STR_OPENRCT2_LANDSCAPE_FILE);
desc.filters[0].pattern = "*.sc4;*.sv4;*.sc6;*.sv6";
2015-02-15 19:48:25 +01:00
break;
case (LOADSAVETYPE_SAVE | LOADSAVETYPE_LANDSCAPE) :
desc.type = FD_SAVE;
desc.title = language_get_string(STR_FILE_DIALOG_TITLE_SAVE_LANDSCAPE);
desc.filters[0].name = language_get_string(STR_OPENRCT2_LANDSCAPE_FILE);
desc.filters[0].pattern = "*.sc6";
2015-02-15 19:48:25 +01:00
break;
case (LOADSAVETYPE_SAVE | LOADSAVETYPE_SCENARIO) :
desc.type = FD_SAVE;
desc.title = language_get_string(STR_FILE_DIALOG_TITLE_SAVE_SCENARIO);
desc.filters[0].name = language_get_string(STR_OPENRCT2_SCENARIO_FILE);
desc.filters[0].pattern = "*.sc6";
2015-02-15 19:48:25 +01:00
break;
2015-04-02 23:00:59 +02:00
case (LOADSAVETYPE_LOAD | LOADSAVETYPE_TRACK) :
desc.type = FD_OPEN;
desc.title = language_get_string(STR_FILE_DIALOG_TITLE_INSTALL_NEW_TRACK_DESIGN);
desc.filters[0].name = language_get_string(STR_OPENRCT2_TRACK_DESIGN_FILE);
desc.filters[0].pattern = "*.td4;*.td6";
2015-04-02 23:00:59 +02:00
break;
2015-02-15 19:48:25 +01:00
}
result = platform_open_common_file_dialog(path, &desc);
if (result) {
window_loadsave_select(w, path);
2015-02-15 19:48:25 +01:00
}
break;
2015-06-22 13:49:35 +02:00
case WIDX_SORT_NAME:
if (gConfigGeneral.load_save_sort == SORT_NAME_ASCENDING){
gConfigGeneral.load_save_sort = SORT_NAME_DESCENDING;
} else {
gConfigGeneral.load_save_sort = SORT_NAME_ASCENDING;
}
config_save_default();
window_loadsave_sort_list(0, _listItemsCount - 1);
window_invalidate(w);
break;
case WIDX_SORT_DATE:
if (gConfigGeneral.load_save_sort == SORT_DATE_DESCENDING){
gConfigGeneral.load_save_sort = SORT_DATE_ASCENDING;
} else {
gConfigGeneral.load_save_sort = SORT_DATE_DESCENDING;
}
config_save_default();
window_loadsave_sort_list(0, _listItemsCount - 1);
window_invalidate(w);
break;
2015-02-15 19:48:25 +01:00
}
}
static int has_extension(char *path, char *extension)
2015-02-15 19:48:25 +01:00
{
int extensionLength = strlen(extension);
int pathLength = strlen(path);
for (int u = 0; u < extensionLength; u++) {
2015-02-15 19:48:25 +01:00
if (tolower(path[pathLength - extensionLength + u]) != tolower(extension[u]))
return 0;
}
2015-02-15 19:48:25 +01:00
return 1;
}
static void window_loadsave_scrollgetsize(rct_window *w, int scrollIndex, int *width, int *height)
{
*height = w->no_list_items * 10;
}
static void window_loadsave_scrollmousedown(rct_window *w, int scrollIndex, int x, int y)
{
int selectedItem;
selectedItem = y / 10;
if (selectedItem >= w->no_list_items)
return;
if (_listItems[selectedItem].type == TYPE_DIRECTORY){
// The selected item is a folder
int includeNewItem;
w->no_list_items = 0;
w->selected_list_item = -1;
includeNewItem = (_type & 1) == LOADSAVETYPE_SAVE;
char directory[MAX_PATH];
2016-01-18 20:49:52 +01:00
safe_strcpy(directory, _listItems[selectedItem].path, sizeof(directory));
window_loadsave_populate_list(w, includeNewItem, directory, _extension);
window_init_scroll_widgets(w);
w->no_list_items = _listItemsCount;
} else {
// TYPE_FILE
// Load or overwrite
if ((_loadsaveType & 0x01) == LOADSAVETYPE_SAVE)
window_overwrite_prompt_open(_listItems[selectedItem].name, _listItems[selectedItem].path);
else
window_loadsave_select(w, _listItems[selectedItem].path);
}
}
static void window_loadsave_scrollmouseover(rct_window *w, int scrollIndex, int x, int y)
{
int selectedItem;
selectedItem = y / 10;
if (selectedItem >= w->no_list_items)
return;
2015-10-20 20:16:30 +02:00
w->selected_list_item = selectedItem;
window_invalidate(w);
}
static void window_loadsave_textinput(rct_window *w, int widgetIndex, char *text)
{
char path[MAX_PATH];
int i, overwrite;
if (text == NULL || text[0] == 0)
return;
2015-06-24 18:22:12 +02:00
if (gLoadSaveTitleSequenceSave) {
if (filename_valid_characters(text)) {
if (!title_sequence_save_exists(gCurrentTitleSequence, text)) {
title_sequence_add_save(gCurrentTitleSequence, path, text);
}
else {
window_error_open(5404, STR_NONE);
}
}
else {
window_error_open(5243, STR_NONE);
}
return;
}
2016-01-18 20:49:52 +01:00
safe_strcpy(path, _directory, sizeof(path));
2015-09-07 00:46:54 +02:00
strncat(path, text, sizeof(path) - strnlen(path, MAX_PATH) - 1);
strncat(path, _extension, sizeof(path) - strnlen(path, MAX_PATH) - 1);
overwrite = 0;
for (i = 0; i < _listItemsCount; i++) {
if (_stricmp(_listItems[i].path, path) == 0) {
overwrite = 1;
break;
}
}
if (overwrite)
window_overwrite_prompt_open(text, path);
else
window_loadsave_select(w, path);
}
static void window_loadsave_tooltip(rct_window* w, int widgetIndex, rct_string_id *stringId)
{
2016-05-15 23:03:53 +02:00
set_format_arg(0, uint16, STR_LIST);
}
static void window_loadsave_invalidate(rct_window *w)
{
colour_scheme_update(w);
}
static void window_loadsave_paint(rct_window *w, rct_drawpixelinfo *dpi)
{
window_draw_widgets(w, dpi);
2015-02-15 15:20:19 +01:00
2016-01-02 23:41:35 +01:00
if (_shortenedDirectory[0] == '\0') {
shorten_path(_shortenedDirectory, sizeof(_shortenedDirectory), _directory, w->width - 8);
}
utf8 buffer[256];
2015-02-15 15:20:19 +01:00
// Format text
utf8 *ch = buffer;
ch = utf8_write_codepoint(ch, FORMAT_MEDIUMFONT);
ch = utf8_write_codepoint(ch, FORMAT_BLACK);
2016-01-18 20:49:52 +01:00
safe_strcpy(ch, _shortenedDirectory, sizeof(buffer) - (ch - buffer));
2015-02-15 15:20:19 +01:00
// Draw shadow
gfx_draw_string(dpi, buffer, 0, w->x + 4, w->y + 20);
2015-06-22 13:49:35 +02:00
rct_string_id id = STR_NONE;
// Name button text
2015-06-22 13:49:35 +02:00
if (gConfigGeneral.load_save_sort == SORT_NAME_ASCENDING)
id = STR_UP;
else if (gConfigGeneral.load_save_sort == SORT_NAME_DESCENDING)
id = STR_DOWN;
gfx_draw_string_centred_clipped(dpi, STR_NAME, &id, 1, w->x + 4 + (w->width - 8) / 4, w->y + 50, (w->width - 8) / 2);
// Date button text
2015-06-22 13:49:35 +02:00
if (gConfigGeneral.load_save_sort == SORT_DATE_ASCENDING)
id = STR_UP;
else if (gConfigGeneral.load_save_sort == SORT_DATE_DESCENDING)
id = STR_DOWN;
else
id = STR_NONE;
gfx_draw_string_centred_clipped(dpi, STR_DATE, &id, 1, w->x + 4 + (w->width - 8) * 3 / 4, w->y + 50, (w->width - 8) / 2);
}
static void window_loadsave_scrollpaint(rct_window *w, rct_drawpixelinfo *dpi, int scrollIndex)
{
int i, y;
rct_string_id stringId, templateStringId = STR_PLACEHOLDER;
char *templateString;
2015-11-08 19:55:32 +01:00
gfx_fill_rect(dpi, dpi->x, dpi->y, dpi->x + dpi->width - 1, dpi->y + dpi->height - 1, ColourMapA[w->colours[1]].mid_light);
2015-10-20 20:16:30 +02:00
templateString = (char*)language_get_string(templateStringId);
for (i = 0; i < w->no_list_items; i++) {
y = i * 10;
if (y > dpi->y + dpi->height)
break;
2015-10-20 20:16:30 +02:00
if (y + 10 < dpi->y)
continue;
stringId = STR_BLACK_STRING;
if (i == w->selected_list_item) {
stringId = STR_WINDOW_COLOUR_2_STRING;
gfx_fill_rect(dpi, 0, y, 800, y + 9, 0x2000031);
}
strcpy(templateString, _listItems[i].name);
gfx_draw_string_left(dpi, stringId, &templateStringId, 0, 0, y - 1);
}
}
static int list_item_sort(const void *a, const void *b)
{
const loadsave_list_item *itemA = (loadsave_list_item*)a;
const loadsave_list_item *itemB = (loadsave_list_item*)b;
2015-06-22 13:49:35 +02:00
if (itemA->type != itemB->type)
return itemA->type - itemB->type;
switch (gConfigGeneral.load_save_sort){
case SORT_NAME_ASCENDING:
return strcicmp(itemA->name, itemB->name);
2015-06-22 13:49:35 +02:00
case SORT_NAME_DESCENDING:
return -strcicmp(itemA->name, itemB->name);
2015-06-22 13:49:35 +02:00
case SORT_DATE_DESCENDING:
return (int) -difftime(itemA->date_modified, itemB->date_modified);
case SORT_DATE_ASCENDING:
return (int) difftime(itemA->date_modified, itemB->date_modified);
default:
return strcicmp(itemA->name, itemB->name);
2015-06-22 13:49:35 +02:00
}
}
static void window_loadsave_sort_list(int index, int endIndex)
{
int count = endIndex - index + 1;
if (count < 0)
return;
qsort(_listItems + index, count, sizeof(loadsave_list_item), list_item_sort);
}
static void window_loadsave_populate_list(rct_window *w, int includeNewItem, const char *directory, const char *extension)
{
int i;
int sortStartIndex = 0;
int listItemCapacity = 8;
loadsave_list_item *listItem;
char filter[MAX_PATH];
2016-01-18 20:49:52 +01:00
safe_strcpy(_directory, directory, sizeof(_directory));
if (_extension != extension) {
2016-01-18 20:49:52 +01:00
safe_strcpy(_extension, extension, sizeof(_extension));
2015-10-24 23:52:12 +02:00
_extension[sizeof(_extension) - 1] = '\0';
}
_shortenedDirectory[0] = '\0';
2016-01-18 20:49:52 +01:00
safe_strcpy(filter, directory, sizeof(filter));
2015-09-07 00:46:54 +02:00
strncat(filter, "*", sizeof(filter) - strnlen(filter, MAX_PATH) - 1);
strncat(filter, extension, sizeof(filter) - strnlen(filter, MAX_PATH) - 1);
if (_listItems != NULL)
free(_listItems);
_listItems = (loadsave_list_item*)malloc(listItemCapacity * sizeof(loadsave_list_item));
_listItemsCount = 0;
window_loadsave_widgets[WIDX_NEW].type = includeNewItem?WWT_CLOSEBOX:WWT_EMPTY; // Hide/Show "new" button
if(directory[0]=='\0' && platform_get_drives()!=0) // List Windows drives
{
w->disabled_widgets |= (1<<WIDX_NEW) | (1<<WIDX_UP);
for (int x = 0; x < 32; x++){
if (listItemCapacity <= _listItemsCount) {
listItemCapacity *= 2;
_listItems = realloc(_listItems, listItemCapacity * sizeof(loadsave_list_item));
}
if (platform_get_drives() & (1 << (x))){
listItem = &_listItems[_listItemsCount];
memset(listItem->path, '\0', MAX_PATH);
listItem->path[0] = 'A' + x;
listItem->path[1] = ':';
listItem->path[2] = platform_get_path_separator();
strcpy(listItem->name, listItem->path);
listItem->type = TYPE_DIRECTORY;
_listItemsCount++;
}
}
}
else
{
//Get parent directory
int directoryLength = strlen(directory);
char separator = platform_get_path_separator();
for(i = directoryLength-2; i>=0; i--)
{
if(directory[i]==separator)
break;
}
2016-01-18 20:49:52 +01:00
safe_strcpy(_parentDirectory, directory, sizeof(_parentDirectory));
_parentDirectory[i+1] = '\0';
if(_parentDirectory[0]=='\0' && platform_get_drives()==0)
w->disabled_widgets |= (1<<WIDX_UP);
else
w->disabled_widgets &= ~(1<<WIDX_UP);
w->disabled_widgets &= ~(1<<WIDX_NEW);
file_info fileInfo;
int fileEnumHandle;
const char *src;
char *dst;
char *last_dot_in_filename;
char subDir[MAX_PATH];
2015-06-22 15:55:57 +02:00
fileEnumHandle = platform_enumerate_directories_begin(directory);
while (platform_enumerate_directories_next(fileEnumHandle, subDir)){
if (listItemCapacity <= _listItemsCount) {
listItemCapacity *= 2;
_listItems = realloc(_listItems, listItemCapacity * sizeof(loadsave_list_item));
}
2015-06-22 15:55:57 +02:00
listItem = &_listItems[_listItemsCount];
memset(listItem->path, '\0', MAX_PATH);
2016-01-18 20:49:52 +01:00
safe_strcpy(listItem->path, directory, MAX_PATH);
strncat(listItem->path, subDir, MAX_PATH - strnlen(listItem->path, MAX_PATH) - 1);
2016-01-18 20:49:52 +01:00
safe_strcpy(listItem->name, subDir, sizeof(listItem->name));
2015-06-22 15:55:57 +02:00
listItem->type = TYPE_DIRECTORY;
_listItemsCount++;
}
2015-06-22 15:55:57 +02:00
platform_enumerate_files_end(fileEnumHandle);
fileEnumHandle = platform_enumerate_files_begin(filter);
while (platform_enumerate_files_next(fileEnumHandle, &fileInfo)) {
if (listItemCapacity <= _listItemsCount) {
listItemCapacity *= 2;
_listItems = realloc(_listItems, listItemCapacity * sizeof(loadsave_list_item));
}
2015-06-22 15:55:57 +02:00
listItem = &_listItems[_listItemsCount];
2016-01-18 20:49:52 +01:00
safe_strcpy(listItem->path, directory, sizeof(listItem->path));
strncat(listItem->path, fileInfo.path, sizeof(listItem->path) - strnlen(listItem->path, MAX_PATH) - 1);
2015-06-22 15:55:57 +02:00
listItem->type = TYPE_FILE;
listItem->date_modified = platform_file_get_modified_time(listItem->path);
src = fileInfo.path;
dst = listItem->name;
last_dot_in_filename = strrchr(fileInfo.path, '.');
assert(last_dot_in_filename != NULL);
2015-06-22 15:55:57 +02:00
i = 0;
while (src < last_dot_in_filename && i < sizeof(listItem->name) - 1) {
2015-06-22 15:55:57 +02:00
*dst++ = *src++;
i++;
}
*dst = '\0';
2015-06-22 15:55:57 +02:00
_listItemsCount++;
}
2015-06-22 15:55:57 +02:00
platform_enumerate_files_end(fileEnumHandle);
window_loadsave_sort_list(sortStartIndex, _listItemsCount - 1);
}
}
2015-11-02 21:43:55 +01:00
static void window_loadsave_invoke_callback(int result)
{
if (gLoadSaveCallback != NULL) {
gLoadSaveCallback(result);
}
}
static void window_loadsave_select(rct_window *w, const char *path)
{
2015-07-05 06:36:25 +02:00
SDL_RWops* rw;
2015-08-16 19:42:30 +02:00
switch (_loadsaveType & 0x0F) {
case (LOADSAVETYPE_LOAD | LOADSAVETYPE_GAME) :
if (gLoadSaveTitleSequenceSave) {
utf8 newName[MAX_PATH];
char *extension = (char*)path_get_extension(path);
2016-01-18 20:49:52 +01:00
safe_strcpy(newName, path_get_filename(path), MAX_PATH);
if (_stricmp(extension, ".sv6") != 0 && _stricmp(extension, ".sc6") != 0)
strcat(newName, ".sv6");
if (title_sequence_save_exists(gCurrentTitleSequence, newName)) {
2016-05-15 23:03:53 +02:00
set_format_arg(0, uint32, (uint32)&_listItems[w->selected_list_item].name);
window_text_input_open(w, WIDX_SCROLL, 5435, 5404, 1170, (uint32)_listItems[w->selected_list_item].name, TITLE_SEQUENCE_MAX_SAVE_LENGTH - 1);
}
else {
title_sequence_add_save(gCurrentTitleSequence, path, newName);
window_close(w);
}
2015-11-02 21:43:55 +01:00
window_loadsave_invoke_callback(MODAL_RESULT_OK);
2016-01-09 01:25:09 +01:00
} else if (game_load_save(path)) {
2016-01-18 20:49:52 +01:00
safe_strcpy(gScenarioSavePath, path, MAX_PATH);
gFirstTimeSave = 0;
window_close(w);
gfx_invalidate_screen();
2015-11-02 21:43:55 +01:00
window_loadsave_invoke_callback(MODAL_RESULT_OK);
2016-01-09 01:25:09 +01:00
} else {
// 1050, not the best message...
window_error_open(STR_LOAD_GAME, 1050);
2015-11-02 21:43:55 +01:00
window_loadsave_invoke_callback(MODAL_RESULT_FAIL);
}
break;
case (LOADSAVETYPE_SAVE | LOADSAVETYPE_GAME) :
rw = SDL_RWFromFile(path, "wb+");
if (rw != NULL) {
int success = scenario_save(rw, gConfigGeneral.save_plugin_data ? 1 : 0);
SDL_RWclose(rw);
if (success) {
2016-01-18 20:49:52 +01:00
safe_strcpy(gScenarioSavePath, path, MAX_PATH);
gFirstTimeSave = 0;
window_close_by_class(WC_LOADSAVE);
gfx_invalidate_screen();
2015-11-02 21:43:55 +01:00
window_loadsave_invoke_callback(MODAL_RESULT_OK);
2015-07-05 06:36:25 +02:00
} else {
window_error_open(STR_SAVE_GAME, 1047);
2015-11-02 21:43:55 +01:00
window_loadsave_invoke_callback(MODAL_RESULT_FAIL);
2015-07-05 06:36:25 +02:00
}
} else {
window_error_open(STR_SAVE_GAME, 1047);
2015-11-02 21:43:55 +01:00
window_loadsave_invoke_callback(MODAL_RESULT_FAIL);
}
break;
case (LOADSAVETYPE_LOAD | LOADSAVETYPE_LANDSCAPE) :
2016-01-09 01:25:09 +01:00
if (editor_load_landscape(path)) {
gfx_invalidate_screen();
2015-11-02 21:43:55 +01:00
window_loadsave_invoke_callback(MODAL_RESULT_OK);
2016-01-09 01:25:09 +01:00
} else {
// 1050, not the best message...
window_error_open(STR_LOAD_LANDSCAPE, 1050);
2015-11-02 21:43:55 +01:00
window_loadsave_invoke_callback(MODAL_RESULT_FAIL);
}
break;
case (LOADSAVETYPE_SAVE | LOADSAVETYPE_LANDSCAPE) :
rw = SDL_RWFromFile(path, "wb+");
if (rw != NULL) {
2015-09-05 21:06:58 +02:00
scenario_set_filename(path);
int success = scenario_save(rw, gConfigGeneral.save_plugin_data ? 3 : 2);
SDL_RWclose(rw);
if (success) {
window_close_by_class(WC_LOADSAVE);
gfx_invalidate_screen();
2015-11-02 21:43:55 +01:00
window_loadsave_invoke_callback(MODAL_RESULT_OK);
2015-07-05 06:36:25 +02:00
} else {
window_error_open(STR_SAVE_LANDSCAPE, 1049);
2015-11-02 21:43:55 +01:00
window_loadsave_invoke_callback(MODAL_RESULT_FAIL);
}
} else {
window_error_open(STR_SAVE_LANDSCAPE, 1049);
2015-11-02 21:43:55 +01:00
window_loadsave_invoke_callback(MODAL_RESULT_FAIL);
}
break;
case (LOADSAVETYPE_SAVE | LOADSAVETYPE_SCENARIO) :
{
2016-04-23 01:51:22 +02:00
int parkFlagsBackup = gParkFlags;
gParkFlags &= ~PARK_FLAGS_18;
2016-05-21 00:26:19 +02:00
gS6Info->editor_step = 255;
rw = SDL_RWFromFile(path, "wb+");
int success = 0;
if (rw != NULL) {
2015-09-05 21:06:58 +02:00
scenario_set_filename(path);
success = scenario_save(rw, gConfigGeneral.save_plugin_data ? 3 : 2);
SDL_RWclose(rw);
}
2016-04-23 01:51:22 +02:00
gParkFlags = parkFlagsBackup;
if (success) {
2015-04-02 23:00:59 +02:00
window_close_by_class(WC_LOADSAVE);
2015-11-02 21:43:55 +01:00
window_loadsave_invoke_callback(MODAL_RESULT_OK);
title_load();
} else {
window_error_open(STR_FILE_DIALOG_TITLE_SAVE_SCENARIO, STR_SCENARIO_SAVE_FAILED);
2016-05-21 00:26:19 +02:00
gS6Info->editor_step = EDITOR_STEP_OBJECTIVE_SELECTION;
2015-11-02 21:43:55 +01:00
window_loadsave_invoke_callback(MODAL_RESULT_FAIL);
}
break;
}
case (LOADSAVETYPE_LOAD | LOADSAVETYPE_TRACK) :
window_install_track_open(path);
window_close_by_class(WC_LOADSAVE);
2015-11-02 21:43:55 +01:00
window_loadsave_invoke_callback(MODAL_RESULT_OK);
break;
}
}
#pragma region Overwrite prompt
#define OVERWRITE_WW 200
#define OVERWRITE_WH 100
enum {
WIDX_OVERWRITE_BACKGROUND,
WIDX_OVERWRITE_TITLE,
WIDX_OVERWRITE_CLOSE,
WIDX_OVERWRITE_OVERWRITE,
WIDX_OVERWRITE_CANCEL
};
static rct_widget window_overwrite_prompt_widgets[] = {
{ WWT_FRAME, 0, 0, OVERWRITE_WW - 1, 0, OVERWRITE_WH - 1, STR_NONE, STR_NONE },
{ WWT_CAPTION, 0, 1, OVERWRITE_WW - 2, 1, 14, 2709, STR_WINDOW_TITLE_TIP },
{ WWT_CLOSEBOX, 0, OVERWRITE_WW - 13, OVERWRITE_WW - 3, 2, 13, STR_CLOSE_X, STR_CLOSE_WINDOW_TIP },
{ WWT_DROPDOWN_BUTTON, 0, 10, 94, OVERWRITE_WH - 20, OVERWRITE_WH - 9, 2709, STR_NONE },
{ WWT_DROPDOWN_BUTTON, 0, OVERWRITE_WW - 95, OVERWRITE_WW - 11, OVERWRITE_WH - 20, OVERWRITE_WH - 9, STR_SAVE_PROMPT_CANCEL, STR_NONE },
{ WIDGETS_END }
};
static void window_overwrite_prompt_mouseup(rct_window *w, int widgetIndex);
static void window_overwrite_prompt_invalidate(rct_window *w);
static void window_overwrite_prompt_paint(rct_window *w, rct_drawpixelinfo *dpi);
static rct_window_event_list window_overwrite_prompt_events = {
NULL,
window_overwrite_prompt_mouseup,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
window_overwrite_prompt_invalidate,
window_overwrite_prompt_paint,
NULL
};
static char _window_overwrite_prompt_name[256];
static char _window_overwrite_prompt_path[MAX_PATH];
static rct_window *window_overwrite_prompt_open(const char *name, const char *path)
{
rct_window *w;
window_close_by_class(WC_LOADSAVE_OVERWRITE_PROMPT);
w = window_create_centred(OVERWRITE_WW, OVERWRITE_WH, &window_overwrite_prompt_events, WC_LOADSAVE_OVERWRITE_PROMPT, WF_STICK_TO_FRONT);
w->widgets = window_overwrite_prompt_widgets;
w->enabled_widgets = (1 << WIDX_CLOSE) | (1 << WIDX_OVERWRITE_CANCEL) | (1 << WIDX_OVERWRITE_OVERWRITE);
window_init_scroll_widgets(w);
w->flags |= WF_TRANSPARENT;
w->colours[0] = 154;
2016-01-18 20:49:52 +01:00
safe_strcpy(_window_overwrite_prompt_name, name, sizeof(_window_overwrite_prompt_name));
safe_strcpy(_window_overwrite_prompt_path, path, sizeof(_window_overwrite_prompt_path));
return w;
}
static void window_overwrite_prompt_mouseup(rct_window *w, int widgetIndex)
{
rct_window *loadsaveWindow;
switch (widgetIndex) {
case WIDX_OVERWRITE_OVERWRITE:
loadsaveWindow = window_find_by_class(WC_LOADSAVE);
if (loadsaveWindow != NULL)
window_loadsave_select(loadsaveWindow, _window_overwrite_prompt_path);
// As the window_loadsave_select function can change the order of the
// windows we can't use window_close(w).
window_close_by_class(WC_LOADSAVE_OVERWRITE_PROMPT);
break;
case WIDX_OVERWRITE_CANCEL:
case WIDX_OVERWRITE_CLOSE:
window_close(w);
break;
}
}
static void window_overwrite_prompt_invalidate(rct_window *w)
{
colour_scheme_update(w);
}
static void window_overwrite_prompt_paint(rct_window *w, rct_drawpixelinfo *dpi)
{
window_draw_widgets(w, dpi);
rct_string_id templateStringId = STR_PLACEHOLDER;
char *templateString;
templateString = (char*)language_get_string(templateStringId);
strcpy(templateString, _window_overwrite_prompt_name);
int x = w->x + w->width / 2;
int y = w->y + (w->height / 2) - 3;
gfx_draw_string_centred_wrapped(dpi, &templateStringId, x, y, w->width - 4, 2708, 0);
}
#pragma endregion