🔧 Reversible file alpha sorting (#26130)

Co-authored-by: Scott Lahteine <thinkyhead@users.noreply.github.com>
This commit is contained in:
Vovodroid 2023-08-18 02:13:10 +03:00 committed by GitHub
parent 7e7dcb8692
commit 49ead19d00
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 65 additions and 44 deletions

View file

@ -1746,9 +1746,10 @@
// SD Card Sorting options // SD Card Sorting options
#if ENABLED(SDCARD_SORT_ALPHA) #if ENABLED(SDCARD_SORT_ALPHA)
#define SDSORT_REVERSE false // Default to sorting file names in reverse order.
#define SDSORT_LIMIT 40 // Maximum number of sorted items (10-256). Costs 27 bytes each. #define SDSORT_LIMIT 40 // Maximum number of sorted items (10-256). Costs 27 bytes each.
#define FOLDER_SORTING -1 // -1=above 0=none 1=below #define SDSORT_FOLDERS -1 // -1=above 0=none 1=below
#define SDSORT_GCODE false // Allow turning sorting on/off with LCD and M34 G-code. #define SDSORT_GCODE false // Enable G-code M34 to set sorting behaviors: M34 S<-1|0|1> F<-1|0|1>
#define SDSORT_USES_RAM false // Pre-allocate a static array for faster pre-sorting. #define SDSORT_USES_RAM false // Pre-allocate a static array for faster pre-sorting.
#define SDSORT_USES_STACK false // Prefer the stack for pre-sorting to give back some SRAM. (Negated by next 2 options.) #define SDSORT_USES_STACK false // Prefer the stack for pre-sorting to give back some SRAM. (Negated by next 2 options.)
#define SDSORT_CACHE_NAMES false // Keep sorted items in RAM longer for speedy performance. Most expensive option. #define SDSORT_CACHE_NAMES false // Keep sorted items in RAM longer for speedy performance. Most expensive option.

View file

@ -29,9 +29,19 @@
/** /**
* M34: Set SD Card Sorting Options * M34: Set SD Card Sorting Options
*
* S - Default sorting (i.e., SDSORT_REVERSE)
* S-1 - Reverse alpha sorting
* S0 - FID Order (not always newest)
* S1 - Forward alpha sorting
* S2 - Alias for S-1 [deprecated]
*
* F-1 - Folders above files
* F0 - Sort According to 'S'
* F1 - Folders after files
*/ */
void GcodeSuite::M34() { void GcodeSuite::M34() {
if (parser.seen('S')) card.setSortOn(parser.value_bool()); if (parser.seen('S')) card.setSortOn(SortFlag(parser.ushortval('S', TERN(SDSORT_REVERSE, AS_REV, AS_FWD))));
if (parser.seenval('F')) { if (parser.seenval('F')) {
const int v = parser.value_long(); const int v = parser.value_long();
card.setSortFolders(v < 0 ? -1 : v > 0 ? 1 : 0); card.setSortFolders(v < 0 ? -1 : v > 0 ? 1 : 0);

View file

@ -661,6 +661,8 @@
#error "Z4_USE_ENDSTOP is obsolete. Instead set Z4_STOP_PIN directly. (e.g., 'Z4_USE_ENDSTOP _ZMAX_' becomes 'Z4_STOP_PIN Z_MAX_PIN')" #error "Z4_USE_ENDSTOP is obsolete. Instead set Z4_STOP_PIN directly. (e.g., 'Z4_USE_ENDSTOP _ZMAX_' becomes 'Z4_STOP_PIN Z_MAX_PIN')"
#elif defined(INTEGRATED_BABYSTEPPING) #elif defined(INTEGRATED_BABYSTEPPING)
#error "INTEGRATED_BABYSTEPPING is no longer needed and should be removed." #error "INTEGRATED_BABYSTEPPING is no longer needed and should be removed."
#elif defined(FOLDER_SORTING)
#error "FOLDER_SORTING is now SDSORT_FOLDERS."
#endif #endif
// L64xx stepper drivers have been removed // L64xx stepper drivers have been removed

View file

@ -3337,8 +3337,8 @@
#define SDSORT_CACHE_NAMES true #define SDSORT_CACHE_NAMES true
#define SDSORT_CACHE_LPC1768_WARNING 1 #define SDSORT_CACHE_LPC1768_WARNING 1
#endif #endif
#ifndef FOLDER_SORTING #ifndef SDSORT_FOLDERS
#define FOLDER_SORTING -1 #define SDSORT_FOLDERS -1
#endif #endif
#ifndef SDSORT_GCODE #ifndef SDSORT_GCODE
#define SDSORT_GCODE false #define SDSORT_GCODE false

View file

@ -850,7 +850,7 @@ bool DWIN_lcd_sd_status = false;
#if ENABLED(MEDIASORT_MENU_ITEM) #if ENABLED(MEDIASORT_MENU_ITEM)
void setMediaSort() { void setMediaSort() {
toggleCheckboxLine(hmiData.mediaSort); toggleCheckboxLine(hmiData.mediaSort);
card.setSortOn(hmiData.mediaSort); card.setSortOn(hmiData.mediaSort ? TERN(SDSORT_REVERSE, AS_REV, AS_FWD) : AS_OFF);
} }
#endif #endif
@ -1754,7 +1754,7 @@ void dwinSetDataDefaults() {
#endif #endif
#if ENABLED(MEDIASORT_MENU_ITEM) #if ENABLED(MEDIASORT_MENU_ITEM)
hmiData.mediaSort = true; hmiData.mediaSort = true;
card.setSortOn(true); card.setSortOn(TERN(SDSORT_REVERSE, AS_REV, AS_FWD));
#endif #endif
hmiData.mediaAutoMount = ENABLED(HAS_SD_EXTENDER); hmiData.mediaAutoMount = ENABLED(HAS_SD_EXTENDER);
#if ALL(INDIVIDUAL_AXIS_HOMING_SUBMENU, MESH_BED_LEVELING) #if ALL(INDIVIDUAL_AXIS_HOMING_SUBMENU, MESH_BED_LEVELING)

View file

@ -1422,11 +1422,13 @@ int16_t SdBaseFile::read(void * const buf, uint16_t nbyte) {
* *
* \param[out] dir The dir_t struct that will receive the data. * \param[out] dir The dir_t struct that will receive the data.
* *
* \return For success readDir() returns the number of bytes read. * \return For success return a non-zero value (number of bytes read).
* A value of zero will be returned if end of file is reached. * A value of zero will be returned if end of dir is reached.
* If an error occurs, readDir() returns -1. Possible errors include * If an error occurs, readDir() returns -1. Possible errors:
* readDir() called before a directory has been opened, this is not * - readDir() called on unopened dir
* a directory file or an I/O error occurred. * - not a directory file
* - bad dir entry
* - I/O error
*/ */
int8_t SdBaseFile::readDir(dir_t * const dir, char * const longFilename) { int8_t SdBaseFile::readDir(dir_t * const dir, char * const longFilename) {
int16_t n; int16_t n;
@ -1488,7 +1490,7 @@ int8_t SdBaseFile::readDir(dir_t * const dir, char * const longFilename) {
longFilename[idx] = utf16_ch & 0xFF; longFilename[idx] = utf16_ch & 0xFF;
longFilename[idx + 1] = (utf16_ch >> 8) & 0xFF; longFilename[idx + 1] = (utf16_ch >> 8) & 0xFF;
#else #else
// Replace all multibyte characters to '_' // Replace multibyte character with '_'
longFilename[n + i] = (utf16_ch > 0xFF) ? '_' : (utf16_ch & 0xFF); longFilename[n + i] = (utf16_ch > 0xFF) ? '_' : (utf16_ch & 0xFF);
#endif #endif
} }

View file

@ -91,8 +91,8 @@ int16_t CardReader::nrItems = -1;
int16_t CardReader::sort_count; int16_t CardReader::sort_count;
#if ENABLED(SDSORT_GCODE) #if ENABLED(SDSORT_GCODE)
bool CardReader::sort_alpha; SortFlag CardReader::sort_alpha;
int CardReader::sort_folders; int8_t CardReader::sort_folders;
//bool CardReader::sort_reverse; //bool CardReader::sort_reverse;
#endif #endif
@ -160,8 +160,8 @@ CardReader::CardReader() {
#if ENABLED(SDCARD_SORT_ALPHA) #if ENABLED(SDCARD_SORT_ALPHA)
sort_count = 0; sort_count = 0;
#if ENABLED(SDSORT_GCODE) #if ENABLED(SDSORT_GCODE)
sort_alpha = true; sort_alpha = TERN(SDSORT_REVERSE, AS_REV, AS_FWD);
sort_folders = FOLDER_SORTING; sort_folders = SDSORT_FOLDERS;
//sort_reverse = false; //sort_reverse = false;
#endif #endif
#endif #endif
@ -993,7 +993,7 @@ void CardReader::selectFileByIndex(const int16_t nr) {
if (nr < sort_count) { if (nr < sort_count) {
strcpy(filename, sortshort[nr]); strcpy(filename, sortshort[nr]);
strcpy(longFilename, sortnames[nr]); strcpy(longFilename, sortnames[nr]);
flag.filenameIsDir = IS_DIR(nr); TERN_(HAS_FOLDER_SORTING, flag.filenameIsDir = IS_DIR(nr));
setBinFlag(strcmp_P(strrchr(filename, '.'), PSTR(".BIN")) == 0); setBinFlag(strcmp_P(strrchr(filename, '.'), PSTR(".BIN")) == 0);
return; return;
} }
@ -1011,7 +1011,7 @@ void CardReader::selectFileByName(const char * const match) {
if (strcasecmp(match, sortshort[nr]) == 0) { if (strcasecmp(match, sortshort[nr]) == 0) {
strcpy(filename, sortshort[nr]); strcpy(filename, sortshort[nr]);
strcpy(longFilename, sortnames[nr]); strcpy(longFilename, sortnames[nr]);
flag.filenameIsDir = IS_DIR(nr); TERN_(HAS_FOLDER_SORTING, flag.filenameIsDir = IS_DIR(nr));
setBinFlag(strcmp_P(strrchr(filename, '.'), PSTR(".BIN")) == 0); setBinFlag(strcmp_P(strrchr(filename, '.'), PSTR(".BIN")) == 0);
return; return;
} }
@ -1163,7 +1163,7 @@ void CardReader::cdroot() {
* Get the name of a file in the working directory by sort-index * Get the name of a file in the working directory by sort-index
*/ */
void CardReader::selectFileByIndexSorted(const int16_t nr) { void CardReader::selectFileByIndexSorted(const int16_t nr) {
selectFileByIndex(TERN1(SDSORT_GCODE, sort_alpha) && (nr < sort_count) ? sort_order[nr] : nr); selectFileByIndex(SortFlag(TERN1(SDSORT_GCODE, sort_alpha != AS_OFF)) && (nr < sort_count) ? sort_order[nr] : nr);
} }
#if ENABLED(SDSORT_USES_RAM) #if ENABLED(SDSORT_USES_RAM)
@ -1210,7 +1210,7 @@ void CardReader::cdroot() {
int16_t fileCnt = get_num_items(); int16_t fileCnt = get_num_items();
// Sorting may be turned off // Sorting may be turned off
if (TERN0(SDSORT_GCODE, !sort_alpha)) return; if (TERN0(SDSORT_GCODE, sort_alpha == AS_OFF)) return;
// If there are files, sort up to the limit // If there are files, sort up to the limit
if (fileCnt > 0) { if (fileCnt > 0) {
@ -1239,9 +1239,9 @@ void CardReader::cdroot() {
// Folder sorting needs 1 bit per entry for flags. // Folder sorting needs 1 bit per entry for flags.
#if HAS_FOLDER_SORTING #if HAS_FOLDER_SORTING
#if ENABLED(SDSORT_DYNAMIC_RAM) #if ENABLED(SDSORT_DYNAMIC_RAM)
isDir = new uint8_t[(fileCnt + 7) >> 3]; isDir = new uint8_t[(fileCnt + 7) >> 3]; // Allocate space with 'new'
#elif ENABLED(SDSORT_USES_STACK) #elif ENABLED(SDSORT_USES_STACK)
uint8_t isDir[(fileCnt + 7) >> 3]; uint8_t isDir[(fileCnt + 7) >> 3]; // Use stack in this scope
#endif #endif
#endif #endif
@ -1291,18 +1291,18 @@ void CardReader::cdroot() {
const int16_t o2 = sort_order[j + 1]; const int16_t o2 = sort_order[j + 1];
// Compare names from the array or just the two buffered names // Compare names from the array or just the two buffered names
#if ENABLED(SDSORT_USES_RAM) auto _sort_cmp_file = [](char * const n1, char * const n2) -> bool {
#define _SORT_CMP_NODIR() (strcasecmp(sortnames[o1], sortnames[o2]) > 0) const bool sort = strcasecmp(n1, n2) > 0;
#else return (TERN(SDSORT_GCODE, card.sort_alpha == AS_REV, ENABLED(SDSORT_REVERSE))) ? !sort : sort;
#define _SORT_CMP_NODIR() (strcasecmp(name1, name2) > 0) };
#endif #define _SORT_CMP_FILE() _sort_cmp_file(TERN(SDSORT_USES_RAM, sortnames[o1], name1), TERN(SDSORT_USES_RAM, sortnames[o2], name2))
#if HAS_FOLDER_SORTING #if HAS_FOLDER_SORTING
#if ENABLED(SDSORT_USES_RAM) #if ENABLED(SDSORT_USES_RAM)
// Folder sorting needs an index and bit to test for folder-ness. // Folder sorting needs an index and bit to test for folder-ness.
#define _SORT_CMP_DIR(fs) (IS_DIR(o1) == IS_DIR(o2) ? _SORT_CMP_NODIR() : IS_DIR(fs > 0 ? o1 : o2)) #define _SORT_CMP_DIR(fs) (IS_DIR(o1) == IS_DIR(o2) ? _SORT_CMP_FILE() : IS_DIR(fs > 0 ? o1 : o2))
#else #else
#define _SORT_CMP_DIR(fs) ((dir1 == flag.filenameIsDir) ? _SORT_CMP_NODIR() : (fs > 0 ? dir1 : !dir1)) #define _SORT_CMP_DIR(fs) ((dir1 == flag.filenameIsDir) ? _SORT_CMP_FILE() : (fs > 0 ? dir1 : !dir1))
#endif #endif
#endif #endif
@ -1318,12 +1318,12 @@ void CardReader::cdroot() {
if ( if (
#if HAS_FOLDER_SORTING #if HAS_FOLDER_SORTING
#if ENABLED(SDSORT_GCODE) #if ENABLED(SDSORT_GCODE)
sort_folders ? _SORT_CMP_DIR(sort_folders) : _SORT_CMP_NODIR() sort_folders ? _SORT_CMP_DIR(sort_folders) : _SORT_CMP_FILE()
#else #else
_SORT_CMP_DIR(FOLDER_SORTING) _SORT_CMP_DIR(SDSORT_FOLDERS)
#endif #endif
#else #else
_SORT_CMP_NODIR() _SORT_CMP_FILE()
#endif #endif
) { ) {
// Reorder the index, indicate that sorting happened // Reorder the index, indicate that sorting happened
@ -1357,13 +1357,15 @@ void CardReader::cdroot() {
#if ENABLED(SDSORT_DYNAMIC_RAM) #if ENABLED(SDSORT_DYNAMIC_RAM)
sortnames = new char*[1]; sortnames = new char*[1];
sortshort = new char*[1]; sortshort = new char*[1];
isDir = new uint8_t[1];
#endif #endif
selectFileByIndex(0); selectFileByIndex(0);
SET_SORTNAME(0); SET_SORTNAME(0);
SET_SORTSHORT(0); SET_SORTSHORT(0);
#if ALL(HAS_FOLDER_SORTING, SDSORT_DYNAMIC_RAM)
isDir = new uint8_t[1];
isDir[0] = flag.filenameIsDir; isDir[0] = flag.filenameIsDir;
#endif #endif
#endif
} }
sort_count = fileCnt; sort_count = fileCnt;

View file

@ -31,7 +31,10 @@ extern const char M23_STR[], M24_STR[];
#if ENABLED(SDSORT_DYNAMIC_RAM) #if ENABLED(SDSORT_DYNAMIC_RAM)
#define SD_RESORT 1 #define SD_RESORT 1
#endif #endif
#if FOLDER_SORTING || ENABLED(SDSORT_GCODE) #ifndef SDSORT_FOLDERS
#define SDSORT_FOLDERS 0
#endif
#if SDSORT_FOLDERS || ENABLED(SDSORT_GCODE)
#define HAS_FOLDER_SORTING 1 #define HAS_FOLDER_SORTING 1
#endif #endif
#endif #endif
@ -84,6 +87,7 @@ typedef struct {
} card_flags_t; } card_flags_t;
enum ListingFlags : uint8_t { LS_LONG_FILENAME, LS_ONLY_BIN, LS_TIMESTAMP }; enum ListingFlags : uint8_t { LS_LONG_FILENAME, LS_ONLY_BIN, LS_TIMESTAMP };
enum SortFlag : int8_t { AS_REV = -1, AS_OFF, AS_FWD, AS_ALSO_REV };
#if ENABLED(AUTO_REPORT_SD_STATUS) #if ENABLED(AUTO_REPORT_SD_STATUS)
#include "../libs/autoreport.h" #include "../libs/autoreport.h"
@ -199,8 +203,8 @@ public:
static void presort(); static void presort();
static void selectFileByIndexSorted(const int16_t nr); static void selectFileByIndexSorted(const int16_t nr);
#if ENABLED(SDSORT_GCODE) #if ENABLED(SDSORT_GCODE)
FORCE_INLINE static void setSortOn(bool b) { sort_alpha = b; presort(); } FORCE_INLINE static void setSortOn(const SortFlag f) { sort_alpha = (f == AS_ALSO_REV) ? AS_REV : f; presort(); }
FORCE_INLINE static void setSortFolders(int i) { sort_folders = i; presort(); } FORCE_INLINE static void setSortFolders(const int8_t i) { sort_folders = i; presort(); }
//FORCE_INLINE static void setSortReverse(bool b) { sort_reverse = b; } //FORCE_INLINE static void setSortReverse(bool b) { sort_reverse = b; }
#endif #endif
#else #else
@ -272,12 +276,12 @@ private:
#if ENABLED(SDCARD_SORT_ALPHA) #if ENABLED(SDCARD_SORT_ALPHA)
static int16_t sort_count; // Count of sorted items in the current directory static int16_t sort_count; // Count of sorted items in the current directory
#if ENABLED(SDSORT_GCODE) #if ENABLED(SDSORT_GCODE)
static bool sort_alpha; // Flag to enable / disable the feature static SortFlag sort_alpha; // Sorting: REV, OFF, FWD
static int sort_folders; // Folder sorting before/none/after static int8_t sort_folders; // Folder sorting before/none/after
//static bool sort_reverse; // Flag to enable / disable reverse sorting //static bool sort_reverse; // Flag to enable / disable reverse sorting
#endif #endif
// By default the sort index is static // By default the sort index is statically allocated
#if ENABLED(SDSORT_DYNAMIC_RAM) #if ENABLED(SDSORT_DYNAMIC_RAM)
static uint8_t *sort_order; static uint8_t *sort_order;
#else #else

View file

@ -8,16 +8,16 @@ set -e
use_example_configs Alfawise/U20 use_example_configs Alfawise/U20
opt_enable BAUD_RATE_GCODE opt_enable BAUD_RATE_GCODE
exec_test $1 $2 "maple CLASSIC_UI U20 config" "$3" exec_test $1 $2 "Maple - Alfawise U20 - CLASSIC_UI" "$3"
use_example_configs Alfawise/U20 use_example_configs Alfawise/U20
opt_enable BAUD_RATE_GCODE TFT_COLOR_UI opt_enable BAUD_RATE_GCODE TFT_COLOR_UI
opt_disable TFT_CLASSIC_UI CUSTOM_STATUS_SCREEN_IMAGE opt_disable TFT_CLASSIC_UI CUSTOM_STATUS_SCREEN_IMAGE
exec_test $1 $2 "maple COLOR_UI U20 config" "$3" exec_test $1 $2 "Maple - Alfawise U20 - COLOR_UI" "$3"
use_example_configs Alfawise/U20-bltouch use_example_configs Alfawise/U20-bltouch
opt_enable BAUD_RATE_GCODE opt_enable BAUD_RATE_GCODE
exec_test $1 $2 "maple BLTouch U20 config" exec_test $1 $2 "Maple - Alfawise U20 - BLTouch"
# cleanup # cleanup
restore_configs restore_configs