mirror of https://github.com/OpenRCT2/OpenRCT2.git
Merge pull request #3009 from OpenRCT2/improve-native-file-dialog
Improve native file dialog
This commit is contained in:
commit
966aaf1adc
60
src/game.c
60
src/game.c
|
@ -611,40 +611,6 @@ static void game_load_or_quit(int *eax, int *ebx, int *ecx, int *edx, int *esi,
|
|||
*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
|
||||
|
@ -1025,32 +991,6 @@ void reset_all_sprite_quadrant_placements()
|
|||
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()
|
||||
{
|
||||
if (!gFirstTimeSave) {
|
||||
|
|
|
@ -487,8 +487,6 @@ enum {
|
|||
LOADSAVETYPE_LANDSCAPE = 1 << 1,
|
||||
LOADSAVETYPE_SCENARIO = 2 << 1,
|
||||
LOADSAVETYPE_TRACK = 3 << 1,
|
||||
|
||||
LOADSAVETYPE_NETWORK = 1 << 4,
|
||||
};
|
||||
|
||||
enum {
|
||||
|
|
|
@ -280,18 +280,22 @@ enum {
|
|||
STR_CAN_ONLY_BUILD_THIS_ABOVE_GROUND = 1033,
|
||||
STR_CAN_ONLY_BUILD_THIS_ON_LAND = 1034,
|
||||
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_LANDSCAPE_SAVE_FAILED = 1049,
|
||||
STR_FAILED_TO_LOAD_FILE_CONTAINS_INVALID_DATA = 1050,
|
||||
|
||||
STR_INVISIBLE_SUPPORTS = 1051,
|
||||
STR_INVISIBLE_PEOPLE = 1052,
|
||||
|
|
|
@ -163,13 +163,18 @@ void execute_cmd(char *command, int *exit_value, char *buf, size_t *buf_size) {
|
|||
if (buf && buf_size) {
|
||||
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
|
||||
if (n_chars == *buf_size) {
|
||||
n_chars--;
|
||||
}
|
||||
buf[n_chars] = '\0';
|
||||
|
||||
*buf_size = n_chars;
|
||||
// account for null terminator
|
||||
*buf_size = n_chars + 1;
|
||||
} else {
|
||||
fflush(f);
|
||||
}
|
||||
|
@ -212,7 +217,7 @@ dialog_type get_dialog_app(char *cmd, size_t *cmd_size) {
|
|||
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;
|
||||
char executable[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;
|
||||
char *action;
|
||||
char *flags;
|
||||
char *filter = NULL;
|
||||
char filter[MAX_PATH] = { 0 };
|
||||
char filterPatternRegex[64];
|
||||
char *allFilesPatternDescription;
|
||||
int allFilesPatternLength = 0;
|
||||
|
||||
size = MAX_PATH;
|
||||
dtype = get_dialog_app(executable, &size);
|
||||
|
||||
switch (dtype) {
|
||||
case DT_KDIALOG:
|
||||
switch (type) {
|
||||
switch (desc->type) {
|
||||
case FD_OPEN:
|
||||
action = "--getopenfilename";
|
||||
break;
|
||||
|
@ -239,16 +245,44 @@ int platform_open_common_file_dialog(filedialog_type type, utf8 *title, utf8 *fi
|
|||
break;
|
||||
}
|
||||
|
||||
if (filterPattern && filterName) {
|
||||
filter = (char*) malloc(1 + strlen(filterPattern) + 3 + strlen(filterName) + 1);
|
||||
sprintf(filter, "\"%s | %s\"", filterPattern, filterName);
|
||||
{
|
||||
bool first = true;
|
||||
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;
|
||||
case DT_ZENITY:
|
||||
action = "--file-selection";
|
||||
switch (type) {
|
||||
switch (desc->type) {
|
||||
case FD_SAVE:
|
||||
flags = "--confirm-overwrite --save";
|
||||
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.
|
||||
if (filterPattern && filterName) {
|
||||
int regexIterator = 0;
|
||||
for(int i = 0; i <= sizeof(filterPattern); i++) {
|
||||
if (isalpha(filterPattern[i])) {
|
||||
filterPatternRegex[regexIterator+0] = '[';
|
||||
filterPatternRegex[regexIterator+1] = (char)toupper(filterPattern[i]);
|
||||
filterPatternRegex[regexIterator+2] = (char)tolower(filterPattern[i]);
|
||||
filterPatternRegex[regexIterator+3] = ']';
|
||||
regexIterator += 3;
|
||||
for (int j = 0; j < countof(desc->filters); j++) {
|
||||
if (desc->filters[j].pattern && desc->filters[j].name) {
|
||||
int regexIterator = 0;
|
||||
for(int i = 0; i <= strlen(desc->filters[j].pattern); i++) {
|
||||
if (isalpha(desc->filters[j].pattern[i])) {
|
||||
filterPatternRegex[regexIterator+0] = '[';
|
||||
filterPatternRegex[regexIterator+1] = (char)toupper(desc->filters[j].pattern[i]);
|
||||
filterPatternRegex[regexIterator+2] = (char)tolower(desc->filters[j].pattern[i]);
|
||||
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] = (char)filterPattern[i];
|
||||
}
|
||||
regexIterator++;
|
||||
filterPatternRegex[regexIterator+1] = 0;
|
||||
|
||||
char filterTemp[100] = { 0 };
|
||||
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;
|
||||
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);
|
||||
|
||||
if (exit_value != 0) {
|
||||
free(filter);
|
||||
return 0;
|
||||
}
|
||||
|
||||
result[size-1] = '\0';
|
||||
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];
|
||||
|
||||
snprintf(msg, MAX_PATH, "\"%s\" not found: %s, please choose another file\n", result, strerror(errno));
|
||||
platform_show_messagebox(msg);
|
||||
|
||||
if (filter != NULL)
|
||||
free(filter);
|
||||
return platform_open_common_file_dialog(type, title, filename, filterPattern, filterName);
|
||||
return platform_open_common_file_dialog(outFilename, desc);
|
||||
} 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);
|
||||
|
||||
size = MAX_PATH;
|
||||
execute_cmd(cmd, &exit_value, 0, 0);
|
||||
|
||||
if (exit_value != 0) {
|
||||
if (filter != NULL)
|
||||
free(filter);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
strncpy(filename, result, MAX_PATH);
|
||||
|
||||
if (filter != NULL)
|
||||
free(filter);
|
||||
strncpy(outFilename, result, MAX_PATH);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
{
|
||||
NSString *fillPatternNS = [NSString stringWithUTF8String:filterPattern];
|
||||
fillPatternNS = [fillPatternNS stringByReplacingOccurrencesOfString:@"*." withString:@""];
|
||||
NSArray *extensions = [fillPatternNS componentsSeparatedByString:@";"];
|
||||
NSMutableArray *extensions = [NSMutableArray new];
|
||||
for (int i=0; i < countof(desc->filters); ++i) {
|
||||
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 *basename = filePath.lastPathComponent;
|
||||
|
||||
NSSavePanel *panel;
|
||||
if (type == FD_SAVE)
|
||||
if (desc->type == FD_SAVE)
|
||||
{
|
||||
panel = [NSSavePanel savePanel];
|
||||
panel.nameFieldStringValue = [NSString stringWithFormat:@"%@.%@", basename, extensions.firstObject];
|
||||
}
|
||||
else if (type == FD_OPEN)
|
||||
else if (desc->type == FD_OPEN)
|
||||
{
|
||||
NSOpenPanel *open = [NSOpenPanel openPanel];
|
||||
open.canChooseDirectories = false;
|
||||
|
@ -157,19 +161,19 @@ int platform_open_common_file_dialog(filedialog_type type, utf8 *title, utf8 *fi
|
|||
open.allowsMultipleSelection = false;
|
||||
panel = open;
|
||||
} else {
|
||||
return 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
panel.title = [NSString stringWithUTF8String:title];
|
||||
panel.title = [NSString stringWithUTF8String:desc->title];
|
||||
panel.allowedFileTypes = extensions;
|
||||
panel.directoryURL = [NSURL fileURLWithPath:directory];
|
||||
if ([panel runModal] == NSFileHandlingPanelCancelButton){
|
||||
SDL_RaiseWindow(gWindow);
|
||||
return 0;
|
||||
return false;
|
||||
} else {
|
||||
strcpy(filename, panel.URL.path.UTF8String);
|
||||
strcpy(outFilename, panel.URL.path.UTF8String);
|
||||
SDL_RaiseWindow(gWindow);
|
||||
return 1;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -88,6 +88,16 @@ enum {
|
|||
|
||||
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 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);
|
||||
utf8* platform_get_username();
|
||||
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);
|
||||
uint8 platform_get_locale_currency();
|
||||
uint8 platform_get_currency_value(const char *currencyCode);
|
||||
|
|
|
@ -580,76 +580,95 @@ void platform_show_messagebox(char *message)
|
|||
*
|
||||
* 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;
|
||||
BOOL result;
|
||||
int tmp;
|
||||
DWORD commonFlags;
|
||||
wchar_t wcFilename[MAX_PATH];
|
||||
|
||||
MultiByteToWideChar(CP_UTF8, 0, title, -1, wctitle, countof(wctitle));
|
||||
MultiByteToWideChar(CP_UTF8, 0, filename, -1, wcfilename, countof(wcfilename));
|
||||
MultiByteToWideChar(CP_UTF8, 0, filterPattern, -1, wcfilterPattern, countof(wcfilterPattern));
|
||||
MultiByteToWideChar(CP_UTF8, 0, filterName, -1, wcfilterName, countof(wcfilterName));
|
||||
|
||||
// Get directory path from given filename
|
||||
lstrcpyW(initialDirectory, wcfilename);
|
||||
dotAddress = wcsrchr(initialDirectory, '.');
|
||||
if (dotAddress != NULL) {
|
||||
slashAddress = wcsrchr(initialDirectory, '\\');
|
||||
if (slashAddress < dotAddress)
|
||||
*(slashAddress + 1) = 0;
|
||||
// Copy default filename to result filename buffer
|
||||
if (desc->default_filename == NULL) {
|
||||
wcFilename[0] = 0;
|
||||
} else {
|
||||
wchar_t *wcDefaultFilename = utf8_to_widechar(desc->default_filename);
|
||||
lstrcpyW(wcFilename, wcDefaultFilename);
|
||||
free(wcDefaultFilename);
|
||||
}
|
||||
|
||||
// Clear filename
|
||||
if (type != FD_SAVE)
|
||||
wcfilename[0] = 0;
|
||||
|
||||
// Set open file name options
|
||||
memset(&openFileName, 0, sizeof(OPENFILENAMEW));
|
||||
openFileName.lStructSize = sizeof(OPENFILENAMEW);
|
||||
openFileName.hwndOwner = windows_get_window_handle();
|
||||
openFileName.lpstrFile = wcfilename;
|
||||
openFileName.nMaxFile = MAX_PATH;
|
||||
openFileName.lpstrInitialDir = initialDirectory;
|
||||
openFileName.lpstrTitle = wctitle;
|
||||
openFileName.lpstrTitle = utf8_to_widechar(desc->title);
|
||||
openFileName.lpstrInitialDir = utf8_to_widechar(desc->initial_directory);
|
||||
openFileName.lpstrFile = wcFilename;
|
||||
|
||||
// Copy filter name
|
||||
lstrcpyW((wchar_t*)0x01423800, wcfilterName);
|
||||
|
||||
// Copy filter pattern
|
||||
int wcfilterNameLength = lstrlenW(wcfilterName);
|
||||
int wcfilterPatternLength = lstrlenW(wcfilterPattern);
|
||||
|
||||
lstrcpyW((wchar_t*)0x01423800 + wcfilterNameLength + 1, wcfilterPattern);
|
||||
*((wchar_t*)((wchar_t*)0x01423800 + wcfilterNameLength + 1 + wcfilterPatternLength + 1)) = 0;
|
||||
openFileName.lpstrFilter = (wchar_t*)0x01423800;
|
||||
|
||||
//
|
||||
tmp = RCT2_GLOBAL(0x009E2C74, uint32);
|
||||
if (RCT2_GLOBAL(0x009E2BB8, uint32) == 2 && RCT2_GLOBAL(0x009E1AF8, uint32) == 1)
|
||||
RCT2_GLOBAL(0x009E2C74, uint32) = 1;
|
||||
|
||||
// Open dialog
|
||||
commonFlags = OFN_EXPLORER | OFN_PATHMUSTEXIST | OFN_HIDEREADONLY | OFN_NOCHANGEDIR;
|
||||
if (type == FD_SAVE) {
|
||||
wchar_t *defaultExtension = wcsrchr(wcfilterPattern, '.');
|
||||
if (defaultExtension != NULL) {
|
||||
openFileName.lpstrDefExt = defaultExtension + 1;
|
||||
utf8 filters[256];
|
||||
utf8 *ch = filters;
|
||||
for (int i = 0; i < countof(desc->filters); i++) {
|
||||
if (desc->filters[i].name != NULL) {
|
||||
strcpy(ch, desc->filters[i].name);
|
||||
ch = strchr(ch, 0) + 1;
|
||||
strcpy(ch, desc->filters[i].pattern);
|
||||
ch = strchr(ch, 0) + 1;
|
||||
}
|
||||
}
|
||||
assert(ch != filters);
|
||||
*ch = 0;
|
||||
|
||||
// HACK: Replace all null terminators with 0x01 so that we convert the entire string
|
||||
size_t fullLength = (size_t)(ch - filters);
|
||||
for (size_t i = 0; i < fullLength; i++) {
|
||||
if (filters[i] == '\0') {
|
||||
filters[i] = 1;
|
||||
}
|
||||
}
|
||||
wchar_t *wcFilter = utf8_to_widechar(filters);
|
||||
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);
|
||||
}
|
||||
|
||||
//
|
||||
RCT2_GLOBAL(0x009E2C74, uint32) = tmp;
|
||||
openFileName.lpstrFilter = wcFilter;
|
||||
|
||||
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;
|
||||
}
|
||||
|
|
|
@ -3073,25 +3073,37 @@ int save_track_design(uint8 rideIndex){
|
|||
// Track design files
|
||||
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();
|
||||
|
||||
int result = platform_open_common_file_dialog(
|
||||
FD_SAVE,
|
||||
RCT2_ADDRESS(RCT2_ADDRESS_COMMON_STRING_FORMAT_BUFFER, char),
|
||||
path,
|
||||
"*.TD?",
|
||||
RCT2_ADDRESS(0x141EE68, char));
|
||||
|
||||
bool result = platform_open_common_file_dialog(path, &desc);
|
||||
audio_unpause_sounds();
|
||||
|
||||
if (result == 0){
|
||||
if (!result) {
|
||||
ride_list_item item = { .type = 0xFD, .entry_index = 0 };
|
||||
track_load_list(item);
|
||||
return 1;
|
||||
}
|
||||
|
||||
path_append_extension(path, "TD6");
|
||||
|
||||
save_track_to_file(RCT2_ADDRESS(0x009D8178, rct_track_td6), path);
|
||||
|
||||
ride_list_item item = { .type = 0xFC, .entry_index = 0 };
|
||||
|
|
|
@ -318,34 +318,6 @@ void window_editor_bottom_toolbar_jump_forward_to_objective_selection() {
|
|||
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
|
||||
|
@ -353,8 +325,6 @@ static int show_save_scenario_dialog(char *resultPath)
|
|||
void window_editor_bottom_toolbar_jump_forward_to_save_scenario()
|
||||
{
|
||||
rct_s6_info *s6Info = (rct_s6_info*)0x0141F570;
|
||||
int parkFlagsBackup, success;
|
||||
char path[256];
|
||||
|
||||
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));
|
||||
|
@ -363,37 +333,7 @@ void window_editor_bottom_toolbar_jump_forward_to_save_scenario()
|
|||
}
|
||||
|
||||
window_close_all();
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -71,7 +71,6 @@ static rct_widget window_loadsave_widgets[] = {
|
|||
|
||||
static void window_loadsave_close(rct_window *w);
|
||||
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_scrollmousedown(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;
|
||||
switch (type & 0x0F) {
|
||||
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;
|
||||
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;
|
||||
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;
|
||||
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;
|
||||
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;
|
||||
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;
|
||||
default:
|
||||
log_error("Unsupported load / save type: %d", type & 0x0F);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
w->no_list_items = 0;
|
||||
|
@ -302,27 +304,53 @@ static void window_loadsave_mouseup(rct_window *w, int widgetIndex)
|
|||
safe_strcpy(filter, "*", MAX_PATH);
|
||||
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) {
|
||||
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;
|
||||
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;
|
||||
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;
|
||||
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;
|
||||
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;
|
||||
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;
|
||||
}
|
||||
|
||||
result = platform_open_common_file_dialog(path, &desc);
|
||||
if (result) {
|
||||
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);
|
||||
} else if (game_load_save(path)) {
|
||||
if (_loadsaveType & LOADSAVETYPE_NETWORK) {
|
||||
network_begin_server(gConfigNetwork.default_port);
|
||||
}
|
||||
|
||||
safe_strcpy(gScenarioSavePath, path, MAX_PATH);
|
||||
gFirstTimeSave = 0;
|
||||
|
||||
|
@ -789,7 +813,7 @@ static void window_loadsave_select(rct_window *w, const char *path)
|
|||
window_loadsave_invoke_callback(MODAL_RESULT_OK);
|
||||
title_load();
|
||||
} 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;
|
||||
window_loadsave_invoke_callback(MODAL_RESULT_FAIL);
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
switch (widgetIndex) {
|
||||
|
@ -199,7 +206,8 @@ static void window_server_start_mouseup(rct_window *w, int widgetIndex)
|
|||
break;
|
||||
case WIDX_LOAD_SERVER:
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue