Merge pull request #3009 from OpenRCT2/improve-native-file-dialog

Improve native file dialog
This commit is contained in:
Ted John 2016-03-31 21:30:53 +01:00
commit 966aaf1adc
11 changed files with 264 additions and 271 deletions

View File

@ -611,40 +611,6 @@ static void game_load_or_quit(int *eax, int *ebx, int *ecx, int *edx, int *esi,
*ebx = 0; *ebx = 0;
} }
/**
*
* rct2: 0x00674F40
*/
static int open_landscape_file_dialog()
{
int result;
format_string((char*)RCT2_ADDRESS_COMMON_STRING_FORMAT_BUFFER, STR_LOAD_LANDSCAPE_DIALOG_TITLE, 0);
safe_strcpy((char*)0x0141EF68, (char*)RCT2_ADDRESS_LANDSCAPES_PATH, MAX_PATH);
format_string((char*)0x0141EE68, STR_RCT2_LANDSCAPE_FILE, 0);
audio_pause_sounds();
result = platform_open_common_file_dialog(FD_OPEN, (char*)RCT2_ADDRESS_COMMON_STRING_FORMAT_BUFFER, (char*)0x0141EF68, "*.SV6;*.SV4;*.SC6", (char*)0x0141EE68);
audio_unpause_sounds();
// window_proc
return result;
}
/**
*
* rct2: 0x00674EB6
*/
static int open_load_game_dialog()
{
int result;
format_string((char*)RCT2_ADDRESS_COMMON_STRING_FORMAT_BUFFER, STR_LOAD_GAME_DIALOG_TITLE, 0);
safe_strcpy((char*)0x0141EF68, (char*)RCT2_ADDRESS_SAVED_GAMES_PATH, MAX_PATH);
format_string((char*)0x0141EE68, STR_RCT2_SAVED_GAME, 0);
audio_pause_sounds();
result = platform_open_common_file_dialog(FD_OPEN, (char*)RCT2_ADDRESS_COMMON_STRING_FORMAT_BUFFER, (char*)0x0141EF68, "*.SV6", (char*)0x0141EE68);
audio_unpause_sounds();
// window_proc
return result;
}
/** /**
* *
* rct2: 0x0066DC0F * rct2: 0x0066DC0F
@ -1025,32 +991,6 @@ void reset_all_sprite_quadrant_placements()
sprite_move(spr->unknown.x, spr->unknown.y, spr->unknown.z, spr); sprite_move(spr->unknown.x, spr->unknown.y, spr->unknown.z, spr);
} }
/**
*
* rct2: 0x006750E9
*/
static int show_save_game_dialog(char *resultPath)
{
rct_s6_info *s6Info = (rct_s6_info*)0x0141F570;
int result;
char title[256];
char filename[MAX_PATH];
char filterName[256];
format_string(title, STR_SAVE_GAME_1040, NULL);
safe_strcpy(filename, RCT2_ADDRESS(RCT2_ADDRESS_SAVED_GAMES_PATH_2, char), MAX_PATH);
format_string(filterName, STR_RCT2_SAVED_GAME, NULL);
audio_pause_sounds();
result = platform_open_common_file_dialog(FD_SAVE, title, filename, "*.SV6", filterName);
audio_unpause_sounds();
if (result)
safe_strcpy(resultPath, filename, MAX_PATH);
return result;
}
void save_game() void save_game()
{ {
if (!gFirstTimeSave) { if (!gFirstTimeSave) {

View File

@ -487,8 +487,6 @@ enum {
LOADSAVETYPE_LANDSCAPE = 1 << 1, LOADSAVETYPE_LANDSCAPE = 1 << 1,
LOADSAVETYPE_SCENARIO = 2 << 1, LOADSAVETYPE_SCENARIO = 2 << 1,
LOADSAVETYPE_TRACK = 3 << 1, LOADSAVETYPE_TRACK = 3 << 1,
LOADSAVETYPE_NETWORK = 1 << 4,
}; };
enum { enum {

View File

@ -280,18 +280,22 @@ enum {
STR_CAN_ONLY_BUILD_THIS_ABOVE_GROUND = 1033, STR_CAN_ONLY_BUILD_THIS_ABOVE_GROUND = 1033,
STR_CAN_ONLY_BUILD_THIS_ON_LAND = 1034, STR_CAN_ONLY_BUILD_THIS_ON_LAND = 1034,
STR_LOCAL_AUTHORITY_WONT_ALLOW_CONSTRUCTION_ABOVE_TREE_HEIGHT = 1035, STR_LOCAL_AUTHORITY_WONT_ALLOW_CONSTRUCTION_ABOVE_TREE_HEIGHT = 1035,
STR_LOAD_GAME_DIALOG_TITLE = 1036,
STR_LOAD_LANDSCAPE_DIALOG_TITLE = 1037,
STR_CONVERT_SAVED_GAME_TO_SCENARIO_1038 = 1038,
STR_SAVE_GAME_1040 = 1040,
STR_SAVE_SCENARIO = 1041,
STR_RCT2_SAVED_GAME = 1043,
STR_RCT2_SCENARIO_FILE = 1044,
STR_RCT2_LANDSCAPE_FILE = 1045,
STR_FILE_DIALOG_TITLE_LOAD_GAME = 1036,
STR_FILE_DIALOG_TITLE_LOAD_LANDSCAPE = 1037,
STR_FILE_DIALOG_TITLE_CONVERT_SAVED_GAME_TO_SCENARIO = 1038,
STR_FILE_DIALOG_TITLE_INSTALL_NEW_TRACK_DESIGN = 1039,
STR_FILE_DIALOG_TITLE_SAVE_GAME = 1040,
STR_FILE_DIALOG_TITLE_SAVE_SCENARIO = 1041,
STR_FILE_DIALOG_TITLE_SAVE_LANDSCAPE = 1042,
STR_OPENRCT2_SAVED_GAME = 1043,
STR_OPENRCT2_SCENARIO_FILE = 1044,
STR_OPENRCT2_LANDSCAPE_FILE = 1045,
STR_OPENRCT2_TRACK_DESIGN_FILE = 1046,
STR_GAME_SAVE_FAILED = 1047,
STR_SCENARIO_SAVE_FAILED = 1048, STR_SCENARIO_SAVE_FAILED = 1048,
STR_LANDSCAPE_SAVE_FAILED = 1049,
STR_FAILED_TO_LOAD_FILE_CONTAINS_INVALID_DATA = 1050,
STR_INVISIBLE_SUPPORTS = 1051, STR_INVISIBLE_SUPPORTS = 1051,
STR_INVISIBLE_PEOPLE = 1052, STR_INVISIBLE_PEOPLE = 1052,

View File

@ -163,13 +163,18 @@ void execute_cmd(char *command, int *exit_value, char *buf, size_t *buf_size) {
if (buf && buf_size) { if (buf && buf_size) {
n_chars = fread(buf, 1, *buf_size, f); n_chars = fread(buf, 1, *buf_size, f);
// some commands may return a new-line terminated result, trim that…
if (n_chars > 0 && buf[n_chars - 1] == '\n') {
buf[n_chars - 1] = '\0';
}
// make sure string is null-terminated // make sure string is null-terminated
if (n_chars == *buf_size) { if (n_chars == *buf_size) {
n_chars--; n_chars--;
} }
buf[n_chars] = '\0'; buf[n_chars] = '\0';
*buf_size = n_chars; // account for null terminator
*buf_size = n_chars + 1;
} else { } else {
fflush(f); fflush(f);
} }
@ -212,7 +217,7 @@ dialog_type get_dialog_app(char *cmd, size_t *cmd_size) {
return dtype; return dtype;
} }
int platform_open_common_file_dialog(filedialog_type type, utf8 *title, utf8 *filename, utf8 *filterPattern, utf8 *filterName) { bool platform_open_common_file_dialog(utf8 *outFilename, file_dialog_desc *desc) {
int exit_value; int exit_value;
char executable[MAX_PATH]; char executable[MAX_PATH];
char cmd[MAX_PATH]; char cmd[MAX_PATH];
@ -221,16 +226,17 @@ int platform_open_common_file_dialog(filedialog_type type, utf8 *title, utf8 *fi
dialog_type dtype; dialog_type dtype;
char *action; char *action;
char *flags; char *flags;
char *filter = NULL; char filter[MAX_PATH] = { 0 };
char filterPatternRegex[64]; char filterPatternRegex[64];
char *allFilesPatternDescription; char *allFilesPatternDescription;
int allFilesPatternLength = 0;
size = MAX_PATH; size = MAX_PATH;
dtype = get_dialog_app(executable, &size); dtype = get_dialog_app(executable, &size);
switch (dtype) { switch (dtype) {
case DT_KDIALOG: case DT_KDIALOG:
switch (type) { switch (desc->type) {
case FD_OPEN: case FD_OPEN:
action = "--getopenfilename"; action = "--getopenfilename";
break; break;
@ -239,16 +245,44 @@ int platform_open_common_file_dialog(filedialog_type type, utf8 *title, utf8 *fi
break; break;
} }
if (filterPattern && filterName) { {
filter = (char*) malloc(1 + strlen(filterPattern) + 3 + strlen(filterName) + 1); bool first = true;
sprintf(filter, "\"%s | %s\"", filterPattern, filterName); for (int j = 0; j < countof(desc->filters); j++) {
if (desc->filters[j].pattern && desc->filters[j].name) {
char filterTemp[100] = { 0 };
if (first) {
snprintf(filterTemp, countof(filterTemp), "%s | %s", desc->filters[j].pattern, desc->filters[j].name);
first = false;
} else {
snprintf(filterTemp, countof(filterTemp), "\\n%s | %s", desc->filters[j].pattern, desc->filters[j].name);
}
safe_strcat(filter, filterTemp, countof(filter));
}
}
char filterTemp[100] = { 0 };
if (first) {
snprintf(filterTemp, countof(filterTemp), "*|%s", (char *)language_get_string(STR_ALL_FILES));
} else {
snprintf(filterTemp, countof(filterTemp), "\\n*|%s", (char *)language_get_string(STR_ALL_FILES));
}
safe_strcat(filter, filterTemp, countof(filter));
// kdialog wants filters space-delimited and we don't expect ';' anywhere else,
// this is much easier and quicker to do than being overly careful about replacing
// it only where truly needed.
int filterSize = strlen(filter);
for (int i = 0; i < filterSize + 3; i++) {
if (filter[i] == ';') {
filter[i] = ' ';
}
}
} }
snprintf(cmd, MAX_PATH, "%s --title \"%s\" %s ~ %s", executable, title, action, filter?filter:""); snprintf(cmd, MAX_PATH, "%s --title \"%s\" %s ~ \"%s\"", executable, desc->title, action, filter);
break; break;
case DT_ZENITY: case DT_ZENITY:
action = "--file-selection"; action = "--file-selection";
switch (type) { switch (desc->type) {
case FD_SAVE: case FD_SAVE:
flags = "--confirm-overwrite --save"; flags = "--confirm-overwrite --save";
break; break;
@ -258,29 +292,37 @@ int platform_open_common_file_dialog(filedialog_type type, utf8 *title, utf8 *fi
} }
// Zenity seems to be case sensitive, while Kdialog isn't. // Zenity seems to be case sensitive, while Kdialog isn't.
if (filterPattern && filterName) { for (int j = 0; j < countof(desc->filters); j++) {
int regexIterator = 0; if (desc->filters[j].pattern && desc->filters[j].name) {
for(int i = 0; i <= sizeof(filterPattern); i++) { int regexIterator = 0;
if (isalpha(filterPattern[i])) { for(int i = 0; i <= strlen(desc->filters[j].pattern); i++) {
filterPatternRegex[regexIterator+0] = '['; if (isalpha(desc->filters[j].pattern[i])) {
filterPatternRegex[regexIterator+1] = (char)toupper(filterPattern[i]); filterPatternRegex[regexIterator+0] = '[';
filterPatternRegex[regexIterator+2] = (char)tolower(filterPattern[i]); filterPatternRegex[regexIterator+1] = (char)toupper(desc->filters[j].pattern[i]);
filterPatternRegex[regexIterator+3] = ']'; filterPatternRegex[regexIterator+2] = (char)tolower(desc->filters[j].pattern[i]);
regexIterator += 3; filterPatternRegex[regexIterator+3] = ']';
regexIterator += 3;
}
else if(desc->filters[j].pattern[i] == ';') {
filterPatternRegex[regexIterator] = ' ';
}
else {
filterPatternRegex[regexIterator] = (char)desc->filters[j].pattern[i];
}
regexIterator++;
} }
else { filterPatternRegex[regexIterator+1] = 0;
filterPatternRegex[regexIterator] = (char)filterPattern[i];
} char filterTemp[100] = { 0 };
regexIterator++; snprintf(filterTemp, countof(filterTemp), " --file-filter=\"%s | %s\"", desc->filters[j].name, filterPatternRegex);
safe_strcat(filter, filterTemp, countof(filter));
} }
filterPatternRegex[regexIterator+1] = 0;
allFilesPatternDescription = (char *)language_get_string(STR_ALL_FILES);
filter = (char*) malloc(strlen("--file-filter=\"") + strlen(filterPatternRegex) + 3 + strlen(filterName) + 2 + strlen(" --file-filter=\"") + strlen(allFilesPatternDescription) + strlen(" | *\""));
sprintf(filter, "--file-filter=\"%s | %s\" --file-filter=\"%s | *\"", filterName, filterPatternRegex, allFilesPatternDescription);
} }
char filterTemp[100] = { 0 };
snprintf(filterTemp, countof(filterTemp), " --file-filter=\"%s | *\"", (char *)language_get_string(STR_ALL_FILES));
safe_strcat(filter, filterTemp, countof(filter));
snprintf(cmd, MAX_PATH, "%s %s %s --title=\"%s\" / %s", executable, action, flags, title, filter?filter:""); snprintf(cmd, MAX_PATH, "%s %s %s --title=\"%s\" / %s", executable, action, flags, desc->title, filter);
break; break;
default: return 0; default: return 0;
} }
@ -289,40 +331,32 @@ int platform_open_common_file_dialog(filedialog_type type, utf8 *title, utf8 *fi
execute_cmd(cmd, &exit_value, result, &size); execute_cmd(cmd, &exit_value, result, &size);
if (exit_value != 0) { if (exit_value != 0) {
free(filter);
return 0; return 0;
} }
result[size-1] = '\0'; result[size-1] = '\0';
log_verbose("filename = %s", result); log_verbose("filename = %s", result);
if (type == FD_OPEN && access(result, F_OK) == -1) { if (desc->type == FD_OPEN && access(result, F_OK) == -1) {
char msg[MAX_PATH]; char msg[MAX_PATH];
snprintf(msg, MAX_PATH, "\"%s\" not found: %s, please choose another file\n", result, strerror(errno)); snprintf(msg, MAX_PATH, "\"%s\" not found: %s, please choose another file\n", result, strerror(errno));
platform_show_messagebox(msg); platform_show_messagebox(msg);
if (filter != NULL) return platform_open_common_file_dialog(outFilename, desc);
free(filter);
return platform_open_common_file_dialog(type, title, filename, filterPattern, filterName);
} else } else
if (type == FD_SAVE && access(result, F_OK) != -1 && dtype == DT_KDIALOG) { if (desc->type == FD_SAVE && access(result, F_OK) != -1 && dtype == DT_KDIALOG) {
snprintf(cmd, MAX_PATH, "%s --yesno \"Overwrite %s?\"", executable, result); snprintf(cmd, MAX_PATH, "%s --yesno \"Overwrite %s?\"", executable, result);
size = MAX_PATH; size = MAX_PATH;
execute_cmd(cmd, &exit_value, 0, 0); execute_cmd(cmd, &exit_value, 0, 0);
if (exit_value != 0) { if (exit_value != 0) {
if (filter != NULL)
free(filter);
return 0; return 0;
} }
} }
strncpy(filename, result, MAX_PATH); strncpy(outFilename, result, MAX_PATH);
if (filter != NULL)
free(filter);
return 1; return 1;
} }

View File

@ -131,25 +131,29 @@ utf8 *platform_open_directory_browser(utf8 *title)
} }
} }
int platform_open_common_file_dialog(filedialog_type type, utf8 *title, utf8 *filename, utf8 *filterPattern, utf8 *filterName) bool platform_open_common_file_dialog(utf8 *outFilename, file_dialog_desc *desc) {
{
@autoreleasepool @autoreleasepool
{ {
NSString *fillPatternNS = [NSString stringWithUTF8String:filterPattern]; NSMutableArray *extensions = [NSMutableArray new];
fillPatternNS = [fillPatternNS stringByReplacingOccurrencesOfString:@"*." withString:@""]; for (int i=0; i < countof(desc->filters); ++i) {
NSArray *extensions = [fillPatternNS componentsSeparatedByString:@";"]; if (desc->filters[i].pattern != NULL) {
NSString *fp = [NSString stringWithUTF8String:desc->filters[i].pattern];
fp = [fp stringByReplacingOccurrencesOfString:@"*." withString:@""];
[extensions addObjectsFromArray:[fp componentsSeparatedByString:@";"]];
}
}
NSString *filePath = [NSString stringWithUTF8String:filename]; NSString *filePath = [NSString stringWithUTF8String:desc->default_filename];
NSString *directory = filePath.stringByDeletingLastPathComponent; NSString *directory = filePath.stringByDeletingLastPathComponent;
NSString *basename = filePath.lastPathComponent; NSString *basename = filePath.lastPathComponent;
NSSavePanel *panel; NSSavePanel *panel;
if (type == FD_SAVE) if (desc->type == FD_SAVE)
{ {
panel = [NSSavePanel savePanel]; panel = [NSSavePanel savePanel];
panel.nameFieldStringValue = [NSString stringWithFormat:@"%@.%@", basename, extensions.firstObject]; panel.nameFieldStringValue = [NSString stringWithFormat:@"%@.%@", basename, extensions.firstObject];
} }
else if (type == FD_OPEN) else if (desc->type == FD_OPEN)
{ {
NSOpenPanel *open = [NSOpenPanel openPanel]; NSOpenPanel *open = [NSOpenPanel openPanel];
open.canChooseDirectories = false; open.canChooseDirectories = false;
@ -157,19 +161,19 @@ int platform_open_common_file_dialog(filedialog_type type, utf8 *title, utf8 *fi
open.allowsMultipleSelection = false; open.allowsMultipleSelection = false;
panel = open; panel = open;
} else { } else {
return 0; return false;
} }
panel.title = [NSString stringWithUTF8String:title]; panel.title = [NSString stringWithUTF8String:desc->title];
panel.allowedFileTypes = extensions; panel.allowedFileTypes = extensions;
panel.directoryURL = [NSURL fileURLWithPath:directory]; panel.directoryURL = [NSURL fileURLWithPath:directory];
if ([panel runModal] == NSFileHandlingPanelCancelButton){ if ([panel runModal] == NSFileHandlingPanelCancelButton){
SDL_RaiseWindow(gWindow); SDL_RaiseWindow(gWindow);
return 0; return false;
} else { } else {
strcpy(filename, panel.URL.path.UTF8String); strcpy(outFilename, panel.URL.path.UTF8String);
SDL_RaiseWindow(gWindow); SDL_RaiseWindow(gWindow);
return 1; return true;
} }
} }
} }

View File

@ -88,6 +88,16 @@ enum {
typedef enum {FD_OPEN, FD_SAVE} filedialog_type; typedef enum {FD_OPEN, FD_SAVE} filedialog_type;
typedef struct {
uint8 type;
const utf8 *title;
const utf8 *initial_directory;
const utf8 *default_filename;
struct {
const utf8 *name; // E.g. "Image Files"
const utf8 *pattern; // E.g. "*.png;*.jpg;*.gif"
} filters[8];
} file_dialog_desc;
extern openrct2_cursor gCursorState; extern openrct2_cursor gCursorState;
extern const unsigned char *gKeysState; extern const unsigned char *gKeysState;
@ -164,7 +174,7 @@ void platform_get_openrct_data_path(utf8 *outPath);
void platform_get_user_directory(utf8 *outPath, const utf8 *subDirectory); void platform_get_user_directory(utf8 *outPath, const utf8 *subDirectory);
utf8* platform_get_username(); utf8* platform_get_username();
void platform_show_messagebox(utf8 *message); void platform_show_messagebox(utf8 *message);
int platform_open_common_file_dialog(filedialog_type type, utf8 *title, utf8 *filename, utf8 *filterPattern, utf8 *filterName); bool platform_open_common_file_dialog(utf8 *outFilename, file_dialog_desc *desc);
utf8 *platform_open_directory_browser(utf8 *title); utf8 *platform_open_directory_browser(utf8 *title);
uint8 platform_get_locale_currency(); uint8 platform_get_locale_currency();
uint8 platform_get_currency_value(const char *currencyCode); uint8 platform_get_currency_value(const char *currencyCode);

View File

@ -580,76 +580,95 @@ void platform_show_messagebox(char *message)
* *
* rct2: 0x004080EA * rct2: 0x004080EA
*/ */
int platform_open_common_file_dialog(filedialog_type type, utf8 *title, utf8 *filename, utf8 *filterPattern, utf8 *filterName) bool platform_open_common_file_dialog(utf8 *outFilename, file_dialog_desc *desc)
{ {
wchar_t wctitle[256], wcfilename[MAX_PATH], wcfilterPattern[256], wcfilterName[256];
wchar_t initialDirectory[MAX_PATH], *dotAddress, *slashAddress;
OPENFILENAMEW openFileName; OPENFILENAMEW openFileName;
BOOL result; wchar_t wcFilename[MAX_PATH];
int tmp;
DWORD commonFlags;
MultiByteToWideChar(CP_UTF8, 0, title, -1, wctitle, countof(wctitle)); // Copy default filename to result filename buffer
MultiByteToWideChar(CP_UTF8, 0, filename, -1, wcfilename, countof(wcfilename)); if (desc->default_filename == NULL) {
MultiByteToWideChar(CP_UTF8, 0, filterPattern, -1, wcfilterPattern, countof(wcfilterPattern)); wcFilename[0] = 0;
MultiByteToWideChar(CP_UTF8, 0, filterName, -1, wcfilterName, countof(wcfilterName)); } else {
wchar_t *wcDefaultFilename = utf8_to_widechar(desc->default_filename);
// Get directory path from given filename lstrcpyW(wcFilename, wcDefaultFilename);
lstrcpyW(initialDirectory, wcfilename); free(wcDefaultFilename);
dotAddress = wcsrchr(initialDirectory, '.');
if (dotAddress != NULL) {
slashAddress = wcsrchr(initialDirectory, '\\');
if (slashAddress < dotAddress)
*(slashAddress + 1) = 0;
} }
// Clear filename
if (type != FD_SAVE)
wcfilename[0] = 0;
// Set open file name options // Set open file name options
memset(&openFileName, 0, sizeof(OPENFILENAMEW)); memset(&openFileName, 0, sizeof(OPENFILENAMEW));
openFileName.lStructSize = sizeof(OPENFILENAMEW); openFileName.lStructSize = sizeof(OPENFILENAMEW);
openFileName.hwndOwner = windows_get_window_handle(); openFileName.hwndOwner = windows_get_window_handle();
openFileName.lpstrFile = wcfilename;
openFileName.nMaxFile = MAX_PATH; openFileName.nMaxFile = MAX_PATH;
openFileName.lpstrInitialDir = initialDirectory; openFileName.lpstrTitle = utf8_to_widechar(desc->title);
openFileName.lpstrTitle = wctitle; openFileName.lpstrInitialDir = utf8_to_widechar(desc->initial_directory);
openFileName.lpstrFile = wcFilename;
// Copy filter name utf8 filters[256];
lstrcpyW((wchar_t*)0x01423800, wcfilterName); utf8 *ch = filters;
for (int i = 0; i < countof(desc->filters); i++) {
// Copy filter pattern if (desc->filters[i].name != NULL) {
int wcfilterNameLength = lstrlenW(wcfilterName); strcpy(ch, desc->filters[i].name);
int wcfilterPatternLength = lstrlenW(wcfilterPattern); ch = strchr(ch, 0) + 1;
strcpy(ch, desc->filters[i].pattern);
lstrcpyW((wchar_t*)0x01423800 + wcfilterNameLength + 1, wcfilterPattern); ch = strchr(ch, 0) + 1;
*((wchar_t*)((wchar_t*)0x01423800 + wcfilterNameLength + 1 + wcfilterPatternLength + 1)) = 0; }
openFileName.lpstrFilter = (wchar_t*)0x01423800; }
assert(ch != filters);
// *ch = 0;
tmp = RCT2_GLOBAL(0x009E2C74, uint32);
if (RCT2_GLOBAL(0x009E2BB8, uint32) == 2 && RCT2_GLOBAL(0x009E1AF8, uint32) == 1) // HACK: Replace all null terminators with 0x01 so that we convert the entire string
RCT2_GLOBAL(0x009E2C74, uint32) = 1; size_t fullLength = (size_t)(ch - filters);
for (size_t i = 0; i < fullLength; i++) {
// Open dialog if (filters[i] == '\0') {
commonFlags = OFN_EXPLORER | OFN_PATHMUSTEXIST | OFN_HIDEREADONLY | OFN_NOCHANGEDIR; filters[i] = 1;
if (type == FD_SAVE) { }
wchar_t *defaultExtension = wcsrchr(wcfilterPattern, '.'); }
if (defaultExtension != NULL) { wchar_t *wcFilter = utf8_to_widechar(filters);
openFileName.lpstrDefExt = defaultExtension + 1; fullLength = lstrlenW(wcFilter);
for (size_t i = 0; i < fullLength; i++) {
if (wcFilter[i] == 1) {
wcFilter[i] = '\0';
} }
openFileName.Flags = commonFlags | OFN_CREATEPROMPT | OFN_OVERWRITEPROMPT;
result = GetSaveFileNameW(&openFileName);
} else if (type == FD_OPEN) {
openFileName.Flags = commonFlags | OFN_NONETWORKBUTTON | OFN_FILEMUSTEXIST;
result = GetOpenFileNameW(&openFileName);
} }
// openFileName.lpstrFilter = wcFilter;
RCT2_GLOBAL(0x009E2C74, uint32) = tmp;
WideCharToMultiByte(CP_UTF8, 0, wcfilename, countof(wcfilename), filename, MAX_PATH, NULL, NULL); // Open dialog
BOOL result;
DWORD commonFlags = OFN_EXPLORER | OFN_PATHMUSTEXIST | OFN_HIDEREADONLY | OFN_NOCHANGEDIR;
if (desc->type == FD_OPEN) {
openFileName.Flags = commonFlags | OFN_NONETWORKBUTTON | OFN_FILEMUSTEXIST;
result = GetOpenFileNameW(&openFileName);
} else if (desc->type == FD_SAVE) {
openFileName.Flags = commonFlags | OFN_CREATEPROMPT | OFN_OVERWRITEPROMPT;
result = GetSaveFileNameW(&openFileName);
}
// Clean up
free((void*)openFileName.lpstrTitle);
free((void*)openFileName.lpstrInitialDir);
free((void*)openFileName.lpstrFilter);
if (result) {
utf8 *resultFilename = widechar_to_utf8(openFileName.lpstrFile);
strcpy(outFilename, resultFilename);
free(resultFilename);
// If there is no extension, append the pattern
const utf8 *outFilenameExtension = path_get_extension(outFilename);
if (str_is_null_or_empty(outFilenameExtension)) {
int filterIndex = openFileName.nFilterIndex - 1;
assert(filterIndex >= 0);
assert(filterIndex < countof(desc->filters));
const utf8 *pattern = desc->filters[filterIndex].pattern;
const utf8 *patternExtension = path_get_extension(pattern);
if (!str_is_null_or_empty(patternExtension)) {
strcat(outFilename, patternExtension);
}
}
}
return result; return result;
} }

View File

@ -3073,25 +3073,37 @@ int save_track_design(uint8 rideIndex){
// Track design files // Track design files
format_string(RCT2_ADDRESS(0x141EE68, char), 2305, NULL); format_string(RCT2_ADDRESS(0x141EE68, char), 2305, NULL);
// Show save dialog
utf8 initialDirectory[MAX_PATH];
{
strcpy(initialDirectory, path);
utf8 *a = strrchr(initialDirectory, '/');
utf8 *b = strrchr(initialDirectory, '\\');
utf8 *c = max(a, b);
if (c != NULL) {
*c = '\0';
}
}
file_dialog_desc desc;
memset(&desc, 0, sizeof(desc));
desc.type = FD_SAVE;
desc.title = RCT2_ADDRESS(RCT2_ADDRESS_COMMON_STRING_FORMAT_BUFFER, utf8);
desc.initial_directory = initialDirectory;
desc.default_filename = path;
desc.filters[0].name = language_get_string(STR_OPENRCT2_TRACK_DESIGN_FILE);
desc.filters[0].pattern = "*.td6";
audio_pause_sounds(); audio_pause_sounds();
bool result = platform_open_common_file_dialog(path, &desc);
int result = platform_open_common_file_dialog(
FD_SAVE,
RCT2_ADDRESS(RCT2_ADDRESS_COMMON_STRING_FORMAT_BUFFER, char),
path,
"*.TD?",
RCT2_ADDRESS(0x141EE68, char));
audio_unpause_sounds(); audio_unpause_sounds();
if (result == 0){ if (!result) {
ride_list_item item = { .type = 0xFD, .entry_index = 0 }; ride_list_item item = { .type = 0xFD, .entry_index = 0 };
track_load_list(item); track_load_list(item);
return 1; return 1;
} }
path_append_extension(path, "TD6");
save_track_to_file(RCT2_ADDRESS(0x009D8178, rct_track_td6), path); save_track_to_file(RCT2_ADDRESS(0x009D8178, rct_track_td6), path);
ride_list_item item = { .type = 0xFC, .entry_index = 0 }; ride_list_item item = { .type = 0xFC, .entry_index = 0 };

View File

@ -318,34 +318,6 @@ void window_editor_bottom_toolbar_jump_forward_to_objective_selection() {
gfx_invalidate_screen(); gfx_invalidate_screen();
} }
/**
*
* rct2: 0x00675181
*/
static int show_save_scenario_dialog(char *resultPath)
{
rct_s6_info *s6Info = (rct_s6_info*)0x0141F570;
int result;
char title[256];
char filename[MAX_PATH];
char filterName[256];
format_string(title, STR_SAVE_SCENARIO, NULL);
substitute_path(filename, RCT2_ADDRESS(RCT2_ADDRESS_SCENARIOS_PATH, char), s6Info->name);
strcat(filename, ".SC6");
format_string(filterName, STR_RCT2_SCENARIO_FILE, NULL);
audio_pause_sounds();
result = platform_open_common_file_dialog(FD_SAVE, title, filename, "*.SC6", filterName);
audio_unpause_sounds();
if (result)
safe_strcpy(resultPath, filename, MAX_PATH);
return result;
}
/** /**
* *
* rct2: 0x0066F7C0 * rct2: 0x0066F7C0
@ -353,8 +325,6 @@ static int show_save_scenario_dialog(char *resultPath)
void window_editor_bottom_toolbar_jump_forward_to_save_scenario() void window_editor_bottom_toolbar_jump_forward_to_save_scenario()
{ {
rct_s6_info *s6Info = (rct_s6_info*)0x0141F570; rct_s6_info *s6Info = (rct_s6_info*)0x0141F570;
int parkFlagsBackup, success;
char path[256];
if (!scenario_prepare_for_save()) { if (!scenario_prepare_for_save()) {
window_error_open(STR_UNABLE_TO_SAVE_SCENARIO_FILE, RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, rct_string_id)); window_error_open(STR_UNABLE_TO_SAVE_SCENARIO_FILE, RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, rct_string_id));
@ -363,37 +333,7 @@ void window_editor_bottom_toolbar_jump_forward_to_save_scenario()
} }
window_close_all(); window_close_all();
window_loadsave_open(LOADSAVETYPE_SAVE | LOADSAVETYPE_SCENARIO, s6Info->name); window_loadsave_open(LOADSAVETYPE_SAVE | LOADSAVETYPE_SCENARIO, s6Info->name);
return;
if (!show_save_scenario_dialog(path)) {
gfx_invalidate_screen();
return;
}
//
s6Info->editor_step = 255;
// Ensure path has .SC6 extension
path_append_extension(path, ".SC6");
// Save the scenario
parkFlagsBackup = RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32);
RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) &= ~PARK_FLAGS_18;
SDL_RWops* rw = SDL_RWFromFile(path, "wb+");
if (rw != NULL) {
success = scenario_save(rw, gConfigGeneral.save_plugin_data ? 3 : 2);
SDL_RWclose(rw);
}
RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) = parkFlagsBackup;
if (success) {
title_load();
} else {
window_error_open(STR_SCENARIO_SAVE_FAILED, -1);
s6Info->editor_step = EDITOR_STEP_OBJECTIVE_SELECTION;
}
} }
/** /**

View File

@ -71,7 +71,6 @@ static rct_widget window_loadsave_widgets[] = {
static void window_loadsave_close(rct_window *w); static void window_loadsave_close(rct_window *w);
static void window_loadsave_mouseup(rct_window *w, int widgetIndex); static void window_loadsave_mouseup(rct_window *w, int widgetIndex);
static void window_loadsave_update(rct_window *w);
static void window_loadsave_scrollgetsize(rct_window *w, int scrollIndex, int *width, int *height); 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_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_scrollmouseover(rct_window *w, int scrollIndex, int x, int y);
@ -173,23 +172,26 @@ rct_window *window_loadsave_open(int type, char *defaultName)
_loadsaveType = type; _loadsaveType = type;
switch (type & 0x0F) { switch (type & 0x0F) {
case (LOADSAVETYPE_LOAD | LOADSAVETYPE_GAME): case (LOADSAVETYPE_LOAD | LOADSAVETYPE_GAME):
w->widgets[WIDX_TITLE].image = STR_LOAD_GAME; w->widgets[WIDX_TITLE].image = STR_FILE_DIALOG_TITLE_LOAD_GAME;
break; break;
case (LOADSAVETYPE_SAVE | LOADSAVETYPE_GAME) : case (LOADSAVETYPE_SAVE | LOADSAVETYPE_GAME) :
w->widgets[WIDX_TITLE].image = STR_SAVE_GAME; w->widgets[WIDX_TITLE].image = STR_FILE_DIALOG_TITLE_SAVE_GAME;
break; break;
case (LOADSAVETYPE_LOAD | LOADSAVETYPE_LANDSCAPE) : case (LOADSAVETYPE_LOAD | LOADSAVETYPE_LANDSCAPE) :
w->widgets[WIDX_TITLE].image = STR_LOAD_LANDSCAPE; w->widgets[WIDX_TITLE].image = STR_FILE_DIALOG_TITLE_LOAD_LANDSCAPE;
break; break;
case (LOADSAVETYPE_SAVE | LOADSAVETYPE_LANDSCAPE) : case (LOADSAVETYPE_SAVE | LOADSAVETYPE_LANDSCAPE) :
w->widgets[WIDX_TITLE].image = STR_SAVE_LANDSCAPE; w->widgets[WIDX_TITLE].image = STR_FILE_DIALOG_TITLE_SAVE_LANDSCAPE;
break; break;
case (LOADSAVETYPE_SAVE | LOADSAVETYPE_SCENARIO) : case (LOADSAVETYPE_SAVE | LOADSAVETYPE_SCENARIO) :
w->widgets[WIDX_TITLE].image = STR_SAVE_SCENARIO; w->widgets[WIDX_TITLE].image = STR_FILE_DIALOG_TITLE_SAVE_SCENARIO;
break; break;
case (LOADSAVETYPE_LOAD | LOADSAVETYPE_TRACK) : case (LOADSAVETYPE_LOAD | LOADSAVETYPE_TRACK) :
w->widgets[WIDX_TITLE].image = 1039; w->widgets[WIDX_TITLE].image = STR_FILE_DIALOG_TITLE_INSTALL_NEW_TRACK_DESIGN;
break; break;
default:
log_error("Unsupported load / save type: %d", type & 0x0F);
return NULL;
} }
w->no_list_items = 0; w->no_list_items = 0;
@ -302,27 +304,53 @@ static void window_loadsave_mouseup(rct_window *w, int widgetIndex)
safe_strcpy(filter, "*", MAX_PATH); safe_strcpy(filter, "*", MAX_PATH);
strncat(filter, _extension, MAX_PATH - strnlen(filter, MAX_PATH) - 1); strncat(filter, _extension, MAX_PATH - strnlen(filter, MAX_PATH) - 1);
file_dialog_desc desc;
memset(&desc, 0, sizeof(desc));
desc.initial_directory = _directory;
if (_type & LOADSAVETYPE_SAVE) {
desc.default_filename = path;
}
switch (_type) { switch (_type) {
case (LOADSAVETYPE_LOAD | LOADSAVETYPE_GAME) : case (LOADSAVETYPE_LOAD | LOADSAVETYPE_GAME) :
result = platform_open_common_file_dialog(FD_OPEN, (char*)language_get_string(STR_LOAD_GAME), path, filter, _extension); 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";
break; break;
case (LOADSAVETYPE_SAVE | LOADSAVETYPE_GAME) : case (LOADSAVETYPE_SAVE | LOADSAVETYPE_GAME) :
result = platform_open_common_file_dialog(FD_SAVE, (char*)language_get_string(STR_SAVE_GAME), path, filter, _extension); 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";
break; break;
case (LOADSAVETYPE_LOAD | LOADSAVETYPE_LANDSCAPE) : case (LOADSAVETYPE_LOAD | LOADSAVETYPE_LANDSCAPE) :
result = platform_open_common_file_dialog(FD_OPEN, (char*)language_get_string(STR_LOAD_LANDSCAPE), path, filter, _extension); 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";
break; break;
case (LOADSAVETYPE_SAVE | LOADSAVETYPE_LANDSCAPE) : case (LOADSAVETYPE_SAVE | LOADSAVETYPE_LANDSCAPE) :
result = platform_open_common_file_dialog(FD_SAVE, (char*)language_get_string(STR_SAVE_LANDSCAPE), path, filter, _extension); 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";
break; break;
case (LOADSAVETYPE_SAVE | LOADSAVETYPE_SCENARIO) : case (LOADSAVETYPE_SAVE | LOADSAVETYPE_SCENARIO) :
result = platform_open_common_file_dialog(FD_SAVE, (char*)language_get_string(STR_SAVE_SCENARIO), path, filter, _extension); 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";
break; break;
case (LOADSAVETYPE_LOAD | LOADSAVETYPE_TRACK) : case (LOADSAVETYPE_LOAD | LOADSAVETYPE_TRACK) :
result = platform_open_common_file_dialog(FD_OPEN, (char*)language_get_string(1039), path, filter, _extension); 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";
break; break;
} }
result = platform_open_common_file_dialog(path, &desc);
if (result) { if (result) {
window_loadsave_select(w, path); window_loadsave_select(w, path);
} }
@ -702,10 +730,6 @@ static void window_loadsave_select(rct_window *w, const char *path)
} }
window_loadsave_invoke_callback(MODAL_RESULT_OK); window_loadsave_invoke_callback(MODAL_RESULT_OK);
} else if (game_load_save(path)) { } else if (game_load_save(path)) {
if (_loadsaveType & LOADSAVETYPE_NETWORK) {
network_begin_server(gConfigNetwork.default_port);
}
safe_strcpy(gScenarioSavePath, path, MAX_PATH); safe_strcpy(gScenarioSavePath, path, MAX_PATH);
gFirstTimeSave = 0; gFirstTimeSave = 0;
@ -789,7 +813,7 @@ static void window_loadsave_select(rct_window *w, const char *path)
window_loadsave_invoke_callback(MODAL_RESULT_OK); window_loadsave_invoke_callback(MODAL_RESULT_OK);
title_load(); title_load();
} else { } else {
window_error_open(STR_SAVE_SCENARIO, STR_SCENARIO_SAVE_FAILED); window_error_open(STR_FILE_DIALOG_TITLE_SAVE_SCENARIO, STR_SCENARIO_SAVE_FAILED);
s6Info->editor_step = EDITOR_STEP_OBJECTIVE_SELECTION; s6Info->editor_step = EDITOR_STEP_OBJECTIVE_SELECTION;
window_loadsave_invoke_callback(MODAL_RESULT_FAIL); window_loadsave_invoke_callback(MODAL_RESULT_FAIL);
} }

View File

@ -160,6 +160,13 @@ static void window_server_start_scenarioselect_callback(const utf8 *path)
} }
} }
static void window_server_start_loadsave_callback(int result)
{
if (result == MODAL_RESULT_OK) {
network_begin_server(gConfigNetwork.default_port);
}
}
static void window_server_start_mouseup(rct_window *w, int widgetIndex) static void window_server_start_mouseup(rct_window *w, int widgetIndex)
{ {
switch (widgetIndex) { switch (widgetIndex) {
@ -199,7 +206,8 @@ static void window_server_start_mouseup(rct_window *w, int widgetIndex)
break; break;
case WIDX_LOAD_SERVER: case WIDX_LOAD_SERVER:
network_set_password(_password); network_set_password(_password);
window_loadsave_open(LOADSAVETYPE_LOAD | LOADSAVETYPE_GAME | LOADSAVETYPE_NETWORK, NULL); window_loadsave_open(LOADSAVETYPE_LOAD | LOADSAVETYPE_GAME, NULL);
gLoadSaveCallback = window_server_start_loadsave_callback;
break; break;
} }
} }