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); }