From ce26812caa9f7dd5bb53ecb6d548e0ffc70c3f43 Mon Sep 17 00:00:00 2001 From: Thomas Date: Mon, 22 Jun 2015 13:49:35 +0200 Subject: [PATCH 1/4] Add sorting based on date --- data/language/english_uk.txt | 6 ++- src/config.c | 1 + src/config.h | 8 ++++ src/localisation/string_ids.h | 5 ++ src/platform/platform.h | 1 + src/platform/windows.c | 7 +++ src/windows/loadsave.c | 88 ++++++++++++++++++++++++++++++----- 7 files changed, 104 insertions(+), 12 deletions(-) diff --git a/data/language/english_uk.txt b/data/language/english_uk.txt index 8401ebc0ac..09ac4112be 100644 --- a/data/language/english_uk.txt +++ b/data/language/english_uk.txt @@ -3705,4 +3705,8 @@ STR_5368 :Reset crash status STR_5369 :Park parameters... STR_5370 :{SMALLFONT}{BLACK}Click this button to modify park{NEWLINE}parameters like restrictions,{NEWLINE}guest generation and money. STR_5371 :Object Selection -STR_5372 :Invert right mouse dragging \ No newline at end of file +STR_5372 :Invert right mouse dragging +STR_5373 :Name {STRINGID} +STR_5374 :Date {STRINGID} +STR_5375 :{UP} +STR_5376 :{DOWN} \ No newline at end of file diff --git a/src/config.c b/src/config.c index a5521c2cf1..37f32c9b60 100644 --- a/src/config.c +++ b/src/config.c @@ -181,6 +181,7 @@ config_property_definition _generalDefinitions[] = { { offsetof(general_configuration, last_run_version), "last_run_version", CONFIG_VALUE_TYPE_STRING, { .value_string = NULL }, NULL }, { offsetof(general_configuration, title_sequence), "title_sequence", CONFIG_VALUE_TYPE_UINT8, TITLE_SEQUENCE_OPENRCT2, NULL }, { offsetof(general_configuration, invert_viewport_drag), "invert_viewport_drag", CONFIG_VALUE_TYPE_BOOLEAN, false, NULL }, + { offsetof(general_configuration, load_save_sort), "load_save_sort", CONFIG_VALUE_TYPE_UINT8, SORT_NAME_ASCENDING, NULL }, }; config_property_definition _interfaceDefinitions[] = { diff --git a/src/config.h b/src/config.h index 9c161c965d..0ad455ff07 100644 --- a/src/config.h +++ b/src/config.h @@ -112,6 +112,13 @@ enum { TITLE_SEQUENCE_RANDOM }; +enum { + SORT_NAME_ASCENDING, + SORT_NAME_DESCENDING, + SORT_DATE_ASCENDING, + SORT_DATE_DESCENDING, +}; + typedef struct { uint8 play_intro; uint8 confirmation_prompt; @@ -145,6 +152,7 @@ typedef struct { utf8string last_run_version; uint8 title_sequence; uint8 invert_viewport_drag; + uint8 load_save_sort; } general_configuration; typedef struct { diff --git a/src/localisation/string_ids.h b/src/localisation/string_ids.h index 2e040cf311..a1029e0da5 100644 --- a/src/localisation/string_ids.h +++ b/src/localisation/string_ids.h @@ -1545,6 +1545,11 @@ enum { STR_INVERT_RIGHT_MOUSE_DRAG = 5372, + STR_NAME = 5373, + STR_DATE = 5374, + STR_UP = 5375, + STR_DOWN = 5376, + // Have to include resource strings (from scenarios and objects) for the time being now that language is partially working STR_COUNT = 32768 }; diff --git a/src/platform/platform.h b/src/platform/platform.h index ee3a146cd1..c0264e66dd 100644 --- a/src/platform/platform.h +++ b/src/platform/platform.h @@ -87,6 +87,7 @@ void platform_stop_text_input(); char platform_get_path_separator(); int platform_file_exists(const char *path); int platform_directory_exists(const char *path); +time_t platform_file_get_modified_time(char* path); int platform_ensure_directory_exists(const char *path); int platform_lock_single_instance(); int platform_enumerate_files_begin(const char *pattern); diff --git a/src/platform/windows.c b/src/platform/windows.c index 52fb1000df..2c5f9402e9 100644 --- a/src/platform/windows.c +++ b/src/platform/windows.c @@ -23,6 +23,7 @@ #include #include #include +#include #include "../addresses.h" #include "../cmdline.h" #include "../openrct2.h" @@ -641,6 +642,12 @@ uint16 platform_get_locale_language(){ return LANGUAGE_UNDEFINED; } +time_t platform_file_get_modified_time(char* path){ + struct _stat stat; + _stat(path, &stat); + return stat.st_mtime; +} + uint8 platform_get_locale_currency(){ CHAR currCode[4]; diff --git a/src/windows/loadsave.c b/src/windows/loadsave.c index 88e4662520..9cde2098bd 100644 --- a/src/windows/loadsave.c +++ b/src/windows/loadsave.c @@ -18,6 +18,7 @@ * along with this program. If not, see . *****************************************************************************/ +#include #include "../addresses.h" #include "../config.h" #include "../game.h" @@ -40,17 +41,21 @@ enum { WIDX_BACKGROUND, WIDX_TITLE, WIDX_CLOSE, + WIDX_SORT_NAME, + WIDX_SORT_DATE, WIDX_SCROLL, WIDX_BROWSE, }; // 0x9DE48C static rct_widget window_loadsave_widgets[] = { - { 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 }, - { WWT_SCROLL, 0, 4, WW - 5, 36, WH - 40, 2, STR_NONE }, - { WWT_CLOSEBOX, 0, 4, 200, WH - 36, WH - 18, 2707, STR_NONE }, // Use native browser + { 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 }, + { WWT_CLOSEBOX, 0, 4, (WW - 5) / 2, 36, 47, STR_NONE, STR_NONE }, + { WWT_CLOSEBOX, 0, (WW - 5) / 2 + 1, WW - 5 - 1, 36, 47, STR_NONE, STR_NONE }, + { WWT_SCROLL, 0, 4, WW - 5, 47, WH - 40, 2, STR_NONE }, + { WWT_CLOSEBOX, 0, 4, 200, WH - 36, WH - 18, 2707, STR_NONE }, // Use native browser { WIDGETS_END } }; @@ -104,9 +109,18 @@ static void* window_loadsave_events[] = { #pragma endregion +enum { + TYPE_UP, + TYPE_NEW_FILE, + TYPE_DIRECTORY, + TYPE_FILE, +}; + typedef struct { char name[256]; char path[MAX_PATH]; + time_t date_modified; + uint8 type; } loadsave_list_item; int _listItemsCount = 0; @@ -120,6 +134,7 @@ int _type; static void window_loadsave_populate_list(int includeNewItem, bool browsable, const char *directory, const char *extension); static void window_loadsave_select(rct_window *w, const char *path); +static void window_loadsave_sort_list(int index, int endIndex); static int has_extension(char *path, char *extension); @@ -139,7 +154,7 @@ rct_window *window_loadsave_open(int type, char *defaultName) if (w == NULL) { w = window_create_centred(WW, WH, (uint32*)window_loadsave_events, WC_LOADSAVE, WF_STICK_TO_FRONT); w->widgets = window_loadsave_widgets; - w->enabled_widgets = (1 << WIDX_CLOSE) | (1 << WIDX_BROWSE); + w->enabled_widgets = (1 << WIDX_CLOSE) | (1 << WIDX_SORT_NAME) | (1 << WIDX_SORT_DATE) | (1 << WIDX_BROWSE); w->colours[0] = 7; w->colours[1] = 7; w->colours[2] = 7; @@ -296,6 +311,26 @@ static void window_loadsave_mouseup() window_loadsave_select(w, filename); } break; + 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; } } @@ -448,7 +483,19 @@ static void window_loadsave_paint() sprintf(buffer, "%c%c%s", FORMAT_MEDIUMFONT, FORMAT_BLACK, _shortenedDirectory); // Draw shadow gfx_draw_string(dpi, buffer, 0, w->x + 4, w->y + 20); - + rct_string_id id = STR_NONE; + 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 + 36, (w->width - 8) / 2); + 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 + 36, (w->width - 8) / 2); } static void shorten_path(char* path, char* buffer, int available_width){ @@ -523,7 +570,21 @@ 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; - return strcmp(itemA->name, itemB->name); + if (itemA->type != itemB->type) + return itemA->type - itemB->type; + + switch (gConfigGeneral.load_save_sort){ + case SORT_NAME_ASCENDING: + return strcmp(itemA->name, itemB->name); + case SORT_NAME_DESCENDING: + return -strcmp(itemA->name, itemB->name); + 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 strcmp(itemA->name, itemB->name); + } } static void window_loadsave_sort_list(int index, int endIndex) @@ -580,6 +641,7 @@ static void window_loadsave_populate_list(int includeNewItem, bool browsable, co strncpy(listItem->name, language_get_string(2718), sizeof(listItem->name)); memset(listItem->path, '\0', MAX_PATH); strncpy(listItem->path, directory, lastSlash + 1); + listItem->type = TYPE_UP; _listItemsCount++; } } @@ -587,7 +649,8 @@ static void window_loadsave_populate_list(int includeNewItem, bool browsable, co if (includeNewItem) { listItem = &_listItems[_listItemsCount]; strncpy(listItem->name, language_get_string(2719), sizeof(listItem->name)); - listItem->path[0] = 0; + listItem->path[0] = '\0'; + listItem->type = TYPE_NEW_FILE; _listItemsCount++; } @@ -604,7 +667,7 @@ static void window_loadsave_populate_list(int includeNewItem, bool browsable, co strncpy(listItem->path, directory, MAX_PATH); strncat(listItem->path, subDir, MAX_PATH); strncpy(listItem->name, subDir, sizeof(listItem->name)); - + listItem->type = TYPE_DIRECTORY; _listItemsCount++; } platform_enumerate_files_end(fileEnumHandle); @@ -621,7 +684,9 @@ static void window_loadsave_populate_list(int includeNewItem, bool browsable, co listItem = &_listItems[_listItemsCount]; strncpy(listItem->path, directory, sizeof(listItem->path)); strncat(listItem->path, fileInfo.path, sizeof(listItem->path)); - + listItem->type = TYPE_FILE; + listItem->date_modified = platform_file_get_modified_time(listItem->path); + src = fileInfo.path; dst = listItem->name; i = 0; @@ -634,6 +699,7 @@ static void window_loadsave_populate_list(int includeNewItem, bool browsable, co _listItemsCount++; } platform_enumerate_files_end(fileEnumHandle); + window_loadsave_sort_list(sortStartIndex, _listItemsCount - 1); } From c7781e272c951e087a41f4c50e40ceb8565e27d1 Mon Sep 17 00:00:00 2001 From: Thomas Date: Mon, 22 Jun 2015 13:54:09 +0200 Subject: [PATCH 2/4] Make sorting case insensitive --- src/windows/loadsave.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/windows/loadsave.c b/src/windows/loadsave.c index 9cde2098bd..6764d27145 100644 --- a/src/windows/loadsave.c +++ b/src/windows/loadsave.c @@ -565,6 +565,15 @@ static void window_loadsave_scrollpaint() } } +static int strcicmp(char const *a, char const *b) +{ + for (;; a++, b++) { + int d = tolower(*a) - tolower(*b); + if (d != 0 || !*a) + return d; + } +} + static int list_item_sort(const void *a, const void *b) { const loadsave_list_item *itemA = (loadsave_list_item*)a; @@ -575,9 +584,9 @@ static int list_item_sort(const void *a, const void *b) switch (gConfigGeneral.load_save_sort){ case SORT_NAME_ASCENDING: - return strcmp(itemA->name, itemB->name); + return strcicmp(itemA->name, itemB->name); case SORT_NAME_DESCENDING: - return -strcmp(itemA->name, itemB->name); + return -strcicmp(itemA->name, itemB->name); case SORT_DATE_DESCENDING: return (int) -difftime(itemA->date_modified, itemB->date_modified); case SORT_DATE_ASCENDING: From 21ecd52af1dd42a78dc3bd1bdba0dded25432785 Mon Sep 17 00:00:00 2001 From: Thomas Date: Mon, 22 Jun 2015 14:17:45 +0200 Subject: [PATCH 3/4] Fix for travis --- src/windows/loadsave.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/windows/loadsave.c b/src/windows/loadsave.c index 6764d27145..2bcd719b15 100644 --- a/src/windows/loadsave.c +++ b/src/windows/loadsave.c @@ -565,7 +565,7 @@ static void window_loadsave_scrollpaint() } } -static int strcicmp(char const *a, char const *b) +static int compare_string_case_insensitive(char const *a, char const *b) { for (;; a++, b++) { int d = tolower(*a) - tolower(*b); @@ -584,15 +584,15 @@ static int list_item_sort(const void *a, const void *b) switch (gConfigGeneral.load_save_sort){ case SORT_NAME_ASCENDING: - return strcicmp(itemA->name, itemB->name); + return compare_string_case_insensitive(itemA->name, itemB->name); case SORT_NAME_DESCENDING: - return -strcicmp(itemA->name, itemB->name); + return -compare_string_case_insensitive(itemA->name, itemB->name); 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 strcmp(itemA->name, itemB->name); + return compare_string_case_insensitive(itemA->name, itemB->name); } } From 2fc23b008480ccca777c59c622950cc61548fac4 Mon Sep 17 00:00:00 2001 From: Thomas Date: Mon, 22 Jun 2015 15:55:57 +0200 Subject: [PATCH 4/4] Add browsing drives on windows --- src/platform/platform.h | 4 ++ src/platform/windows.c | 4 ++ src/windows/loadsave.c | 121 +++++++++++++++++++++++++--------------- 3 files changed, 84 insertions(+), 45 deletions(-) diff --git a/src/platform/platform.h b/src/platform/platform.h index c0264e66dd..ca7ad50dfd 100644 --- a/src/platform/platform.h +++ b/src/platform/platform.h @@ -96,6 +96,10 @@ void platform_enumerate_files_end(int handle); int platform_enumerate_directories_begin(const char *directory); int platform_enumerate_directories_next(int handle, char *path); void platform_enumerate_directories_end(int handle); + +// Returns the bitmask of the GetLogicalDrives function for windows, 0 for other systems +int platform_get_drives(); + int platform_file_copy(const char *srcPath, const char *dstPath); int platform_file_move(const char *srcPath, const char *dstPath); int platform_file_delete(const char *path); diff --git a/src/platform/windows.c b/src/platform/windows.c index 2c5f9402e9..db17d1ffbc 100644 --- a/src/platform/windows.c +++ b/src/platform/windows.c @@ -266,6 +266,10 @@ void platform_enumerate_directories_end(int handle) enumFileInfo->active = 0; } +int platform_get_drives(){ + return GetLogicalDrives(); +} + int platform_file_copy(const char *srcPath, const char *dstPath) { return CopyFileA(srcPath, dstPath, TRUE); diff --git a/src/windows/loadsave.c b/src/windows/loadsave.c index 2bcd719b15..976bcf1e88 100644 --- a/src/windows/loadsave.c +++ b/src/windows/loadsave.c @@ -370,8 +370,7 @@ static void window_loadsave_scrollmousedown() if (selectedItem >= w->no_list_items) return; - // Load or overwrite - if (_listItems[selectedItem].path[0] == 0) { + if (_listItems[selectedItem].type == TYPE_NEW_FILE) { rct_string_id templateStringId = 3165; char *templateString; @@ -380,7 +379,7 @@ static void window_loadsave_scrollmousedown() window_text_input_open(w, WIDX_SCROLL, STR_NONE, 2710, templateStringId, 0, 64); } else { - if (_listItems[selectedItem].path[strlen(_listItems[selectedItem].path) - 1] == platform_get_path_separator()){ + if (_listItems[selectedItem].type == TYPE_DIRECTORY || _listItems[selectedItem].type == TYPE_UP){ // The selected item is a folder int includeNewItem; @@ -397,6 +396,8 @@ static void window_loadsave_scrollmousedown() w->no_list_items = _listItemsCount; } else { + // TYPE_FILE + // Load or overwrite if ((_loadsaveType & 1) == LOADSAVETYPE_SAVE) window_overwrite_prompt_open(_listItems[selectedItem].name, _listItems[selectedItem].path); else @@ -628,6 +629,8 @@ static void window_loadsave_populate_list(int includeNewItem, bool browsable, co _listItems = (loadsave_list_item*)malloc(listItemCapacity * sizeof(loadsave_list_item)); _listItemsCount = 0; + bool drivesList = false; + if (browsable) { int directoryLength = strlen(directory); int topLevel = 1; @@ -652,6 +655,13 @@ static void window_loadsave_populate_list(int includeNewItem, bool browsable, co strncpy(listItem->path, directory, lastSlash + 1); listItem->type = TYPE_UP; _listItemsCount++; + } else if (platform_get_drives() != 0 && directory[0] != '\0'){ + includeNewItem = false; + listItem = &_listItems[_listItemsCount]; + strncpy(listItem->name, language_get_string(2718), sizeof(listItem->name)); + memset(listItem->path, '\0', MAX_PATH); + listItem->type = TYPE_UP; + _listItemsCount++; } } @@ -664,50 +674,71 @@ static void window_loadsave_populate_list(int includeNewItem, bool browsable, co } int sortStartIndex = _listItemsCount; - 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)); - } - listItem = &_listItems[_listItemsCount]; - memset(listItem->path, '\0', MAX_PATH); - strncpy(listItem->path, directory, MAX_PATH); - strncat(listItem->path, subDir, MAX_PATH); - strncpy(listItem->name, subDir, sizeof(listItem->name)); - listItem->type = TYPE_DIRECTORY; - _listItemsCount++; + if (directory[0] != '\0'){ + 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)); + } + + listItem = &_listItems[_listItemsCount]; + memset(listItem->path, '\0', MAX_PATH); + strncpy(listItem->path, directory, MAX_PATH); + strncat(listItem->path, subDir, MAX_PATH); + strncpy(listItem->name, subDir, sizeof(listItem->name)); + listItem->type = TYPE_DIRECTORY; + _listItemsCount++; + } + platform_enumerate_files_end(fileEnumHandle); + window_loadsave_sort_list(sortStartIndex, _listItemsCount - 1); + + sortStartIndex = _listItemsCount; + 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)); + } + + listItem = &_listItems[_listItemsCount]; + strncpy(listItem->path, directory, sizeof(listItem->path)); + strncat(listItem->path, fileInfo.path, sizeof(listItem->path)); + listItem->type = TYPE_FILE; + listItem->date_modified = platform_file_get_modified_time(listItem->path); + + src = fileInfo.path; + dst = listItem->name; + i = 0; + while (*src != 0 && *src != '.' && i < sizeof(listItem->name) - 1) { + *dst++ = *src++; + i++; + } + *dst = 0; + + _listItemsCount++; + } + platform_enumerate_files_end(fileEnumHandle); + } else { + 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++; + } + } } - platform_enumerate_files_end(fileEnumHandle); - window_loadsave_sort_list(sortStartIndex, _listItemsCount - 1); - - sortStartIndex = _listItemsCount; - 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)); - } - - listItem = &_listItems[_listItemsCount]; - strncpy(listItem->path, directory, sizeof(listItem->path)); - strncat(listItem->path, fileInfo.path, sizeof(listItem->path)); - listItem->type = TYPE_FILE; - listItem->date_modified = platform_file_get_modified_time(listItem->path); - - src = fileInfo.path; - dst = listItem->name; - i = 0; - while (*src != 0 && *src != '.' && i < sizeof(listItem->name) - 1) { - *dst++ = *src++; - i++; - } - *dst = 0; - - _listItemsCount++; - } - platform_enumerate_files_end(fileEnumHandle); window_loadsave_sort_list(sortStartIndex, _listItemsCount - 1); }