From a1d1e01e11185d389f9448be0be0a567f1430600 Mon Sep 17 00:00:00 2001 From: Nebuleon Fumika Date: Sat, 15 Jun 2013 23:40:29 -0400 Subject: Dynamically allocate memory for the file selector to store the name pointers into. Also dramatically simplify the file selector's name management code. This has many effects: * It allows the file selector to handle directories of more than 511 files and a parent directory entry. (Fixes GitHub issue #37). * It allows the file selector to sort directories along with files, which is a more common use case (game folders that contain ROM hacks, plus single game files, are sorted by name as the user expects). * The file selector now reports progress while loading a large directory. * The screenshot slideshow function now shows an existing dedicated message, "No screenshots found", instead of crashing when the screenshot directory contains no screenshots. Add Quicksort code from GameYob. See . * Faster sorting in the common case where a directory's natural order is already sorted, using the isSorted function. * Use the median-of-three algorithm first described by Robert Sedgewick to select the pivot. Causes less recursion in many cases. * Associates file names with their is-directory flag, keeping both in sync. --- source/nds/gui.c | 1315 +++++++++++++++++++++++--------------------------- source/nds/message.h | 4 + 2 files changed, 606 insertions(+), 713 deletions(-) (limited to 'source') diff --git a/source/nds/gui.c b/source/nds/gui.c index c75564f..ea76c08 100644 --- a/source/nds/gui.c +++ b/source/nds/gui.c @@ -69,6 +69,7 @@ char *language_options[] = { (char *) &lang[0], (char *) &lang[1], (char *) &lan * Macro definition ******************************************************************************/ #define SUBMENU_ROW_NUM 8 +#define FILE_LIST_ROWS SUBMENU_ROW_NUM #define NDSSFC_VERSION "1.35" @@ -313,7 +314,6 @@ static uint8 SavedStateSquareX (u32 slot); static bool8 SavedStateFileExists (u32 slot); static void SavedStateCacheInvalidate (void); void get_newest_savestate(char *name_buffer); -static int sort_function(const void *dest_str_ptr, const void *src_str_ptr); static u32 parse_line(char *current_line, char *current_str); static void get_timestamp_string(char *buffer, u16 msg_id, u16 year, u16 mon, u16 day, u16 wday, u16 hour, u16 min, u16 sec, u32 msec); static void get_time_string(char *buff, struct rtc *rtcp); @@ -511,61 +511,155 @@ void change_ext(char *src, char *buffer, char *extension) /*-------------------------------------------------------- Sort function --------------------------------------------------------*/ -static int sort_function(const void *dest_str_ptr, const void *src_str_ptr) +static int nameSortFunction(char* a, char* b) { - char *dest_str = ((char *)dest_str_ptr); - char *src_str = ((char *)src_str_ptr); + // ".." sorts before everything except itself. + bool aIsParent = strcmp(a, "..") == 0; + bool bIsParent = strcmp(b, "..") == 0; - // For files and directories, . and .. sort first. - if(src_str[0] == '.' && dest_str[0] != '.') - return 1; - - if(dest_str[0] == '.' && src_str[0] != '.') - return -1; - - return strcasecmp(dest_str, src_str); + if (aIsParent && bIsParent) + return 0; + else if (aIsParent) // Sorts before + return -1; + else if (bIsParent) // Sorts after + return 1; + else + return strcasecmp(a, b); } -static int my_array_partion(void **array, int left, int right) +/* + * Determines whether a portion of a vector is sorted. + * Input assertions: 'from' and 'to' are valid indices into data. 'to' can be + * the maximum value for the type 'unsigned int'. + * Input: 'data', data vector, possibly sorted. + * 'sortFunction', function determining the sort order of two elements. + * 'from', index of the first element in the range to test. + * 'to', index of the last element in the range to test. + * Output: true if, for any valid index 'i' such as from <= i < to, + * data[i] < data[i + 1]. + * true if the range is one or no elements, or if from > to. + * false otherwise. + */ +static bool isSorted(char** data, int (*sortFunction) (char*, char*), unsigned int from, unsigned int to) { - // Choose a pivot, left <= pivot <= right - unsigned int pivotIndex = left + (right - left) / 2; - - // Move pivot value to the end - void *temp = array[pivotIndex]; - array[pivotIndex] = array[right]; - array[right] = temp; - - // Move values that sort before the pivot value to before the new - // pivot's location - unsigned int storeIndex = left, i; - for (i = left; i <= right - 1; i++) - { - if (sort_function(array[i], array[right]) < 0) - { - temp = array[i]; - array[i] = array[storeIndex]; - array[storeIndex] = temp; - storeIndex++; - } - } + if (from >= to) + return true; - // Move the pivot value to its correct location - temp = array[storeIndex]; - array[storeIndex] = array[right]; - array[right] = temp; + char** prev = &data[from]; + unsigned int i; + for (i = from + 1; i < to; i++) + { + if ((*sortFunction)(*prev, data[i]) > 0) + return false; + prev = &data[i]; + } + if ((*sortFunction)(*prev, data[to]) > 0) + return false; - return storeIndex; + return true; } -static void my_qsort(void **array, int left, int right) +/* + * Chooses a pivot for Quicksort. Uses the median-of-three search algorithm + * first proposed by Robert Sedgewick. + * Input assertions: 'from' and 'to' are valid indices into data. 'to' can be + * the maximum value for the type 'unsigned int'. + * Input: 'data', data vector. + * 'sortFunction', function determining the sort order of two elements. + * 'from', index of the first element in the range to be sorted. + * 'to', index of the last element in the range to be sorted. + * Output: a valid index into data, between 'from' and 'to' inclusive. + */ +static unsigned int choosePivot(char** data, int (*sortFunction) (char*, char*), unsigned int from, unsigned int to) { - if(left < right) + // The highest of the two extremities is calculated first. + unsigned int highest = ((*sortFunction)(data[from], data[to]) > 0) + ? from + : to; + // Then the lowest of that highest extremity and the middle + // becomes the pivot. + return ((*sortFunction)(data[from + (to - from) / 2], data[highest]) < 0) + ? (from + (to - from) / 2) + : highest; +} + +/* + * Partition function for Quicksort. Moves elements such that those that are + * less than the pivot end up before it in the data vector. + * Input assertions: 'from', 'to' and 'pivotIndex' are valid indices into data. + * 'to' can be the maximum value for the type 'unsigned int'. + * Input: 'data', data vector. + * 'metadata', data describing the values in 'data'. + * 'sortFunction', function determining the sort order of two elements. + * 'from', index of the first element in the range to sort. + * 'to', index of the last element in the range to sort. + * 'pivotIndex', index of the value chosen as the pivot. + * Output: the index of the value chosen as the pivot after it has been moved + * after all the values that are less than it. + */ +static unsigned int partition(char** data, u8* metadata, int (*sortFunction) (char*, char*), unsigned int from, unsigned int to, unsigned int pivotIndex) +{ + char* pivotValue = data[pivotIndex]; + data[pivotIndex] = data[to]; + data[to] = pivotValue; + { + u8 tM = metadata[pivotIndex]; + metadata[pivotIndex] = metadata[to]; + metadata[to] = tM; + } + + unsigned int storeIndex = from; + unsigned int i; + for (i = from; i < to; i++) + { + if ((*sortFunction)(data[i], pivotValue) < 0) + { + char* tD = data[storeIndex]; + data[storeIndex] = data[i]; + data[i] = tD; + u8 tM = metadata[storeIndex]; + metadata[storeIndex] = metadata[i]; + metadata[i] = tM; + ++storeIndex; + } + } + { - int mid= my_array_partion(array, left, right); - my_qsort(array, left, mid-1); - my_qsort(array, mid+1, right); + char* tD = data[to]; + data[to] = data[storeIndex]; + data[storeIndex] = tD; + u8 tM = metadata[to]; + metadata[to] = metadata[storeIndex]; + metadata[storeIndex] = tM; } + return storeIndex; +} + +/* + * Sorts an array while keeping metadata in sync. + * This sort is unstable and its average performance is + * O(data.size() * log2(data.size()). + * Input assertions: for any valid index 'i' in data, index 'i' is valid in + * metadata. 'from' and 'to' are valid indices into data. 'to' can be + * the maximum value for the type 'unsigned int'. + * Invariant: index 'i' in metadata describes index 'i' in data. + * Input: 'data', data to sort. + * 'metadata', data describing the values in 'data'. + * 'sortFunction', function determining the sort order of two elements. + * 'from', index of the first element in the range to sort. + * 'to', index of the last element in the range to sort. + */ +static void quickSort(char** data, u8* metadata, int (*sortFunction) (char*, char*), unsigned int from, unsigned int to) +{ + if (isSorted(data, sortFunction, from, to)) + return; + + unsigned int pivotIndex = choosePivot(data, sortFunction, from, to); + unsigned int newPivotIndex = partition(data, metadata, sortFunction, from, to, pivotIndex); + if (newPivotIndex > 0) + quickSort(data, metadata, sortFunction, from, newPivotIndex - 1); + if (newPivotIndex < to) + quickSort(data, metadata, sortFunction, newPivotIndex + 1, to); } static void strupr(char *str) @@ -580,739 +674,545 @@ static void strupr(char *str) // ****************************************************************************** // get file list // ****************************************************************************** -#define FILE_LIST_MAX 512 -#define DIR_LIST_MAX 64 -#define NAME_MEM_SIZE (320*64) - -struct FILE_LIST_INFO -{ - char current_path[MAX_PATH]; - char **wildcards; - unsigned int file_num; - unsigned int dir_num; - unsigned int mem_size; - unsigned int file_size; - unsigned int dir_size; - char **file_list; - char **dir_list; - char *filename_mem; -}; -/* -* Function: internal function to manage FILE_LIST_INFO structure -* filelist_infop: a pointer to a predefined FILE_LIST_INFO structure -* flag: 0 initialize the structure -* 1 increase filename memory size -* 2 increase file name buffer size -* 4 increase directory name buffer size -* -1 free all allocated memroy -* other value are invalide -* return: -1 on failure -*/ -static int manage_filelist_info(struct FILE_LIST_INFO *filelist_infop, int flag) +s32 load_file(char **wildcards, char *result, char *default_dir_name) { - //Initialize - if(0 == flag) - { - filelist_infop->file_list = (char**)malloc(FILE_LIST_MAX*4); - if(NULL == filelist_infop->file_list) - return -1; - - filelist_infop->dir_list = (char**)malloc(DIR_LIST_MAX*4); - if(NULL == filelist_infop->dir_list) - { - free((void*)filelist_infop->file_list); - return -1; - } - - filelist_infop->filename_mem = (char*)malloc(NAME_MEM_SIZE); - if(NULL == filelist_infop->filename_mem) - { - free((void*)filelist_infop->file_list); - free((void*)filelist_infop->dir_list); - return -1; - } - - filelist_infop->mem_size = NAME_MEM_SIZE; - filelist_infop->file_size = FILE_LIST_MAX; - filelist_infop->dir_size = DIR_LIST_MAX; - return 0; - } - //free all memroy - if(-1 == flag) - { - free((void*)filelist_infop->file_list); - free((void*)filelist_infop->dir_list); - free((void*)filelist_infop->filename_mem); - return 0; - } - - int i; - void *pt; - - //Increase all - if(flag & 0x1) - { - i = NAME_MEM_SIZE; - - do - { - pt = (void*)realloc(filelist_infop->filename_mem, filelist_infop->mem_size+i); - if(NULL == pt) i /= 2; - } while(i > 256); - - if(NULL == pt) return -1; - - filelist_infop->mem_size += i; - filelist_infop->filename_mem = (char*)pt; - i = (int)pt - (int)filelist_infop->file_list; + if (default_dir_name == NULL || *default_dir_name == '\0') + return -4; - int k; - char **m; + char CurrentDirectory[MAX_PATH]; + u32 ContinueDirectoryRead = 1; + u32 ReturnValue; + u32 i; - k = 0; - m = filelist_infop->file_list; - for(k= 0; k < filelist_infop->file_num; k++) - m[k] += i; + strcpy(CurrentDirectory, default_dir_name); - k = 0; - m = filelist_infop->dir_list; - for(k = 0; k < filelist_infop->dir_num; k++) - m[k] += i; - } - //Increase file name buffer - if(flag & 0x2) + while (ContinueDirectoryRead) { - i = filelist_infop->file_size + FILE_LIST_MAX; + // Read the current directory. This loop is continued every time the + // current directory changes. + HighFrequencyCPU(); - pt = (void*)realloc(filelist_infop->file_list, i*4); - if(NULL == pt) return -1; + show_icon(down_screen_addr, &ICON_SUBBG, 0, 0); + show_icon(down_screen_addr, &ICON_TITLE, 0, 0); + show_icon(down_screen_addr, &ICON_TITLEICON, TITLE_ICON_X, TITLE_ICON_Y); + PRINT_STRING_BG(down_screen_addr, msg[MSG_FILE_MENU_LOADING_LIST], COLOR_WHITE, COLOR_TRANS, 49, 10); + ds2_flipScreen(DOWN_SCREEN, DOWN_SCREEN_UPDATE_METHOD); - filelist_infop->file_list = (char**)pt; - filelist_infop->file_size = i; - } - //Increase directory name buffer - if(flag & 0x4) - { - i = filelist_infop->dir_size + DIR_LIST_MAX; + u32 LastCountDisplayTime = getSysTime(); - pt = (void*)realloc(filelist_infop->dir_list, i*4); - if(NULL == pt) return -1; + char** EntryNames = NULL; + u8* EntryDirectoryFlags = NULL; + DIR* CurrentDirHandle = NULL; + u32 EntryCount = 1, EntryCapacity = 4 /* initial */; - filelist_infop->dir_list = (char**)pt; - filelist_infop->dir_size = i; - } + EntryNames = (char**) malloc(EntryCapacity * sizeof(char*)); + if (EntryNames == NULL) + { + ReturnValue = -2; + ContinueDirectoryRead = 0; + goto cleanup; + } - return 0; -} + EntryDirectoryFlags = (u8*) malloc(EntryCapacity * sizeof(u8)); + if (EntryDirectoryFlags == NULL) + { + ReturnValue = -2; + ContinueDirectoryRead = 0; + goto cleanup; + } -static int load_file_list(struct FILE_LIST_INFO *filelist_infop) -{ - DIR* current_dir; - char current_dir_name[MAX_PATH]; - dirent *current_file; - struct stat st; - char *file_name; - unsigned int len; - unsigned int file_name_length; - char* name_mem_base; - char **file_list; - char **dir_list; - unsigned int mem_size; - unsigned int file_size; - unsigned int dir_size; - unsigned int num_files; - unsigned int num_dirs; - char **wildcards; - - if(filelist_infop -> current_path == NULL) - return -1; + CurrentDirHandle = opendir(CurrentDirectory); + if(CurrentDirHandle == NULL) { + ReturnValue = -1; + ContinueDirectoryRead = 0; + goto cleanup; + } - name_mem_base = &(filelist_infop -> filename_mem[0]); - mem_size = filelist_infop -> mem_size; - file_size = filelist_infop -> file_size; - dir_size = filelist_infop -> dir_size; - file_list = filelist_infop -> file_list; - dir_list = filelist_infop -> dir_list; - num_files = 0; - num_dirs = 0; - wildcards = filelist_infop -> wildcards; - - strcpy(current_dir_name, filelist_infop -> current_path); - - // path formate should be: "fat:/" or "fat:/dir0" or "fat:", not "fat:/dir0/" - current_dir = opendir(current_dir_name); - //Open directory faiure - if(current_dir == NULL) { - return -1; - } + EntryNames[0] = ".."; + EntryDirectoryFlags[0] = 1; - file_name_length = 0; - //while((current_file = readdir(current_dir)) != NULL) - while((current_file = readdir_ex(current_dir, &st)) != NULL) - { - //lstat(current_file->d_name, &st); - file_name = current_file->d_name; + dirent* CurrentEntryHandle; + struct stat Stat; - len = strlen(file_name) +1; - if((file_name_length+len) > mem_size) + while((CurrentEntryHandle = readdir_ex(CurrentDirHandle, &Stat)) != NULL) { - //get more memory - if(manage_filelist_info(filelist_infop, 1) == -1) - break; + u32 Now = getSysTime(); + u32 AddEntry = 0; + char* Name = CurrentEntryHandle->d_name; - name_mem_base = &(filelist_infop -> filename_mem[0]); - mem_size = filelist_infop -> mem_size; - } - //Increase file_list - if(num_files >= file_size) { - if(manage_filelist_info(filelist_infop, 2) == -1) - break; - file_size = filelist_infop -> file_size; - } - //Increase dir_list - if(num_dirs >= dir_size) { - if(manage_filelist_info(filelist_infop, 4) == -1) - break; - dir_size = filelist_infop -> dir_size; - } - - //If dirctory - if(S_ISDIR(st.st_mode)) - { - if(file_name[0] != '.') + if (Now >= LastCountDisplayTime + 5859 /* 250 ms */) { - dir_list[num_dirs] = name_mem_base + file_name_length; - strcpy(dir_list[num_dirs], file_name); - num_dirs++; - file_name_length += len; + LastCountDisplayTime = Now; + + show_icon(down_screen_addr, &ICON_TITLE, 0, 0); + show_icon(down_screen_addr, &ICON_TITLEICON, TITLE_ICON_X, TITLE_ICON_Y); + char Line[384], Element[128]; + strcpy(Line, msg[MSG_FILE_MENU_LOADING_LIST]); + sprintf(Element, " (%u)", EntryCount); + strcat(Line, Element); + PRINT_STRING_BG(down_screen_addr, Line, COLOR_WHITE, COLOR_TRANS, 49, 10); + ds2_flipScreen(DOWN_SCREEN, DOWN_SCREEN_UPDATE_METHOD); } - //take ".." directory as file - else if(file_name[1] == '.') + + if(S_ISDIR(Stat.st_mode)) { - file_list[num_files] = name_mem_base + file_name_length; - strcpy(file_list[num_files], file_name); - num_files++; - file_name_length += len; + // Add directories no matter what, except for the special + // ones, "." and "..". + if (!(Name[0] == '.' && + (Name[1] == '\0' || (Name[1] == '.' && Name[2] == '\0')) + )) + { + AddEntry = 1; + } } - } - else - { - char *ext_pos; - unsigned int i; - - ext_pos = (char*)strrchr((const char*)file_name, '.'); - if(NULL != ext_pos) - for(i = 0; wildcards[i] != NULL; i++) + else { - if(!strcasecmp(ext_pos, wildcards[i])) + if (wildcards[0] == NULL) // Show every file + AddEntry = 1; + else { - file_list[num_files] = name_mem_base + file_name_length; - strcpy(file_list[num_files], file_name); - num_files++; - file_name_length += len; - break; + // Add files only if their extension is in the list. + char* Extension = strrchr(Name, '.'); + if (Extension != NULL) + { + for(i = 0; wildcards[i] != NULL; i++) + { + if(strcasecmp(Extension, wildcards[i]) == 0) + { + AddEntry = 1; + break; + } + } + } } } - } - } - - closedir(current_dir); - - filelist_infop -> file_num = num_files; - filelist_infop -> dir_num = num_dirs; - //printf("%s: num_files %d; num_dirs %d\n", filelist_infop ->current_path, num_files, num_dirs); -#if 0 - my_qsort((void *)file_list, 0, num_files-1); -#else //to support ".." directory, but take it as file - my_qsort((void **)file_list, 1, num_files-1); -#endif - my_qsort((void **)dir_list, 0, num_dirs-1); - return 0; -} + if (AddEntry) + { + // Ensure we have enough capacity in the char* array first. + if (EntryCount == EntryCapacity) + { + void* NewEntryNames = realloc(EntryNames, EntryCapacity * 2 * sizeof(char*)); + if (NewEntryNames == NULL) + { + ReturnValue = -2; + ContinueDirectoryRead = 0; + goto cleanup; + } + else + EntryNames = NewEntryNames; -/*-------------------------------------------------------- - 读取文件 ---------------------------------------------------------*/ -#define FILE_LIST_ROWS 8 -#define FILE_LIST_ROWS_CENTER ((FILE_LIST_ROWS+1)/2-1) -#define FILE_LIST_POSITION 42 //Started displaying x position + void* NewEntryDirectoryFlags = realloc(EntryDirectoryFlags, EntryCapacity * 2 * sizeof(char*)); + if (NewEntryDirectoryFlags == NULL) + { + ReturnValue = -2; + ContinueDirectoryRead = 0; + goto cleanup; + } + else + EntryDirectoryFlags = NewEntryDirectoryFlags; -s32 load_file(char **wildcards, char *result, char *default_dir_name) -{ - struct FILE_LIST_INFO filelist_info; - u32 repeat; - int return_value; - gui_action_type gui_action; - u32 selected_item_on_list; - u32 selected_item_on_screen; - u32 to_update_filelist; - u32 total_items_num; - int redraw; - u32 path_scroll; - u32 num_files; //File numbers on the directory - u32 num_dirs; //Directory numbers on the dirctory - char **file_list; - char **dir_list; - int flag; - - //Have no path - if(NULL == default_dir_name) - return -1; + EntryCapacity *= 2; + } - //construct filelist_info struct - if(-1 == manage_filelist_info(&filelist_info, 0)) - return -1; + // Then add the entry. + EntryNames[EntryCount] = malloc(strlen(Name) + 1); + if (EntryNames[EntryCount] == NULL) + { + ReturnValue = -2; + ContinueDirectoryRead = 0; + goto cleanup; + } - result[0] = '\0'; - strcpy(filelist_info.current_path, default_dir_name); + strcpy(EntryNames[EntryCount], Name); + if (S_ISDIR(Stat.st_mode)) + EntryDirectoryFlags[EntryCount] = 1; + else + EntryDirectoryFlags[EntryCount] = 0; - filelist_info.wildcards = wildcards; - filelist_info.file_num = 0; - filelist_info.dir_num = 0; + EntryCount++; + } + } - flag = load_file_list(&filelist_info); - if(-1 == flag) - { - //deconstruct filelist_info struct - manage_filelist_info(&filelist_info, -1); - return -1; - } + show_icon(down_screen_addr, &ICON_TITLE, 0, 0); + show_icon(down_screen_addr, &ICON_TITLEICON, TITLE_ICON_X, TITLE_ICON_Y); + PRINT_STRING_BG(down_screen_addr, msg[MSG_FILE_MENU_SORTING_LIST], COLOR_WHITE, COLOR_TRANS, 49, 10); + ds2_flipScreen(DOWN_SCREEN, DOWN_SCREEN_UPDATE_METHOD); - num_files = filelist_info.file_num; - num_dirs = filelist_info.dir_num; - file_list = filelist_info.file_list; - dir_list = filelist_info.dir_list; + quickSort(EntryNames, EntryDirectoryFlags, nameSortFunction, 1, EntryCount - 1); + LowFrequencyCPU(); - selected_item_on_list = 0; //Selected item on list - selected_item_on_screen = 0; //Selected item on screen's position - redraw = -1; //redraw all - total_items_num = num_files + num_dirs; - to_update_filelist = 0; //to load new file list - path_scroll = 0x8000; //path scroll method, first scroll left + u32 ContinueInput = 1; + s32 SelectedIndex = 0; + u32 DirectoryScrollDirection = 0x8000; // First scroll to the left + s32 EntryScrollValue = 0; + u32 ModifyScrollers = 1; + u32 ScrollerCount = 0; - repeat= 1; - return_value = -1; - while(repeat) - { - struct key_buf inputdata; - gui_action = get_gui_input(); - int mod; + draw_hscroll_init(down_screen_addr, 49, 10, 199, COLOR_TRANS, + COLOR_WHITE, CurrentDirectory); + ScrollerCount++; - // Get KEY_RIGHT and KEY_LEFT separately to allow scrolling - // the selected file name faster. - ds2_getrawInput(&inputdata); - if (inputdata.key & KEY_RIGHT) - redraw = -3; - else if (inputdata.key & KEY_LEFT) - redraw = 3; + // Show the current directory and get input. This loop is continued + // every frame, because the current directory scrolls atop the screen. - switch(gui_action) + while (ContinueDirectoryRead && ContinueInput) { - case CURSOR_TOUCH: - ds2_getrawInput(&inputdata); - wait_Allkey_release(0); - // ___ 33 This screen has 6 possible rows. Touches - // ___ 60 above or below these are ignored. - // . . . (+27) - // ___ 192 - if(inputdata.y < GUI_ROW1_Y || inputdata.y > NDS_SCREEN_HEIGHT) - break; - else - mod = (inputdata.y - GUI_ROW1_Y) / GUI_ROW_SY; - - if(selected_item_on_list - selected_item_on_screen + mod >= total_items_num) - break; + // Try to use a row set such that the selected entry is in the + // middle of the screen. + s32 LastEntry = SelectedIndex + FILE_LIST_ROWS / 2; + + // If the last row is out of bounds, put it back in bounds. + // (In this case, the user has selected an entry in the last + // FILE_LIST_ROWS / 2.) + if (LastEntry >= EntryCount) + LastEntry = EntryCount - 1; + + s32 FirstEntry = LastEntry - (FILE_LIST_ROWS - 1); + + // If the first row is out of bounds, put it back in bounds. + // (In this case, the user has selected an entry in the first + // FILE_LIST_ROWS / 2, or there are fewer than FILE_LIST_ROWS + // entries.) + if (FirstEntry < 0) + { + FirstEntry = 0; - selected_item_on_list = selected_item_on_list - selected_item_on_screen + mod; + // If there are more than FILE_LIST_ROWS / 2 files, + // we need to enlarge the first page. + LastEntry = FILE_LIST_ROWS - 1; + if (LastEntry >= EntryCount) // No... + LastEntry = EntryCount - 1; + } - if(selected_item_on_list + 1 <= num_files) + // Update scrollers. + // a) If a different item has been selected, remake entry + // scrollers, resetting the formerly selected entry to the + // start and updating the selection color. + if (ModifyScrollers) + { + // Preserve the directory scroller. + for (; ScrollerCount > 1; ScrollerCount--) + draw_hscroll_over(ScrollerCount - 1); + for (i = FirstEntry; i <= LastEntry; i++) { - //The ".." directory is the parent - if(!strcasecmp(file_list[selected_item_on_list], "..")) + u16 color = (SelectedIndex == i) + ? COLOR_ACTIVE_ITEM + : COLOR_INACTIVE_ITEM; + if (hscroll_init(down_screen_addr, FILE_SELECTOR_NAME_X, GUI_ROW1_Y + (i - FirstEntry) * GUI_ROW_SY + TEXT_OFFSET_Y, FILE_SELECTOR_NAME_SX, + COLOR_TRANS, color, EntryNames[i]) < 0) { - char *ext_pos; - - strcpy(filelist_info.current_path, default_dir_name); - ext_pos = strrchr(filelist_info.current_path, '/'); - if(NULL != ext_pos) //Not root directory - { - *ext_pos = '\0'; - to_update_filelist= 1; - } + ReturnValue = -2; + ContinueDirectoryRead = 0; + goto cleanupScrollers; } else { - repeat = 0; - return_value = 0; - strcpy(default_dir_name, filelist_info.current_path); - strcpy(result, file_list[selected_item_on_list]); + ScrollerCount++; } } - //directory selected - else if(num_dirs > 0) - { - unsigned int m; - m = selected_item_on_list - num_files; - strcpy(filelist_info.current_path, default_dir_name); - strcat(filelist_info.current_path, "/"); - strcat(filelist_info.current_path, dir_list[m]); - to_update_filelist= 1; - } - break; - case CURSOR_UP: - redraw = 1; - if(selected_item_on_screen > 0) + ModifyScrollers = 0; + } + + // b) Must we update the directory scroller? + if ((DirectoryScrollDirection & 0xFF) >= 0x20) + { + if(DirectoryScrollDirection & 0x8000) //scroll left { - //Not the first item on list - selected_item_on_list -= 1; - //Selected item on screen center - if(FILE_LIST_ROWS_CENTER == selected_item_on_screen) { - if(selected_item_on_screen > selected_item_on_list) - selected_item_on_screen -= 1; - } - //Selected item on down half screen - else if(FILE_LIST_ROWS_CENTER < selected_item_on_screen) { - selected_item_on_screen -= 1; - } - //Selected item on up half screen - else { - if(selected_item_on_screen < selected_item_on_list) - selected_item_on_screen += 1; - else if(selected_item_on_screen > selected_item_on_list) - selected_item_on_screen -= 1; - } - } - else if(selected_item_on_screen > selected_item_on_list) { - selected_item_on_screen -= 1; + if(draw_hscroll(0, -1) == 0) DirectoryScrollDirection = 0; //scroll right } else - redraw = 0; - - break; + { + if(draw_hscroll(0, 1) == 0) DirectoryScrollDirection = 0x8000; //scroll left + } + } + else + { + // Wait one less frame before scrolling the directory again. + DirectoryScrollDirection++; + } - case CURSOR_DOWN: + // c) Must we scroll the current file as a result of user input? + if (EntryScrollValue != 0) { - unsigned int m, n; - m = total_items_num - (selected_item_on_list + 1); - n = FILE_LIST_ROWS - (FILE_LIST_ROWS_CENTER + 1); - //Selected item on screen center - if(FILE_LIST_ROWS_CENTER == selected_item_on_screen) { - if(m > 0 && m < n) - selected_item_on_screen += 1; - redraw = 1; - } - //Selected item on down half screen - else if(FILE_LIST_ROWS_CENTER < selected_item_on_screen) { - if(m > 0) { - redraw = 1; - if(m <= n) selected_item_on_screen += 1; - else if(m > n) selected_item_on_screen -= 1; - else redraw = 0; //cancel - } - } - //Selected item on up half screen - else { - if(m > 0) { - selected_item_on_screen += 1; - redraw = 1; - } - } + draw_hscroll(SelectedIndex - FirstEntry + 1, EntryScrollValue); + EntryScrollValue = 0; + } - //Not reach the last item - if((selected_item_on_list + 1) < total_items_num) - selected_item_on_list += 1; + // Draw. + // a) The background. + show_icon(down_screen_addr, &ICON_SUBBG, 0, 0); + show_icon(down_screen_addr, &ICON_TITLE, 0, 0); + show_icon(down_screen_addr, &ICON_TITLEICON, TITLE_ICON_X, TITLE_ICON_Y); - break; - } - //scroll page down - case CURSOR_RTRIGGER: + // b) The selection background. + show_icon(down_screen_addr, &ICON_SUBSELA, SUBSELA_X, GUI_ROW1_Y + (SelectedIndex - FirstEntry) * GUI_ROW_SY + SUBSELA_OFFSET_Y); + + // c) The scrollers. + for (i = 0; i < ScrollerCount; i++) + draw_hscroll(i, 0); + + // d) The icons. + for (i = FirstEntry; i <= LastEntry; i++) { - unsigned int m, n; - //first item on screen in item list's position - m = selected_item_on_list - selected_item_on_screen; - n = total_items_num - (m+1); - //there are more than 1 page after the m item - if(n >= FILE_LIST_ROWS) { - m += FILE_LIST_ROWS -1; - selected_item_on_list = m; - - m = total_items_num - (selected_item_on_list +1); - if(m >= (FILE_LIST_ROWS_CENTER +1)) - selected_item_on_screen = FILE_LIST_ROWS_CENTER; + struct gui_iconlist* icon; + if (i == 0) + icon = &ICON_DOTDIR; + else if (EntryDirectoryFlags[i]) + icon = &ICON_DIRECTORY; + else + { + char* Extension = strrchr(EntryNames[i], '.'); + if (strcasecmp(Extension, ".smc") == 0 || strcasecmp(Extension, ".sfc") == 0) + icon = &ICON_SFCFILE; + else if (strcasecmp(Extension, ".zip") == 0) + icon = &ICON_ZIPFILE; + else if (strcasecmp(Extension, ".cht") == 0) + icon = &ICON_CHTFILE; else - selected_item_on_screen = 0; - - selected_item_on_list += selected_item_on_screen; - redraw = 1; + icon = &ICON_UNKNOW; } - break; + show_icon(down_screen_addr, icon, FILE_SELECTOR_ICON_X, GUI_ROW1_Y + (i - FirstEntry) * GUI_ROW_SY + FILE_SELECTOR_ICON_Y); } - //scroll page up - case CURSOR_LTRIGGER: + + ds2_flipScreen(DOWN_SCREEN, DOWN_SCREEN_UPDATE_METHOD); + + // Delay before getting the input. + mdelay(20); + + struct key_buf inputdata; + gui_action_type gui_action = get_gui_input(); + ds2_getrawInput(&inputdata); + + // Get KEY_RIGHT and KEY_LEFT separately to allow scrolling + // the selected file name faster. + if (inputdata.key & KEY_RIGHT) + EntryScrollValue = -3; + else if (inputdata.key & KEY_LEFT) + EntryScrollValue = 3; + + switch(gui_action) { - unsigned int m; - //first item on screen in item list's position - m = selected_item_on_list - selected_item_on_screen; - //there are more than 1 page befroe the m item - if((m+1) >= FILE_LIST_ROWS) + case CURSOR_TOUCH: { - m -= FILE_LIST_ROWS -1; - selected_item_on_list = m; + wait_Allkey_release(0); + // ___ 33 This screen has 6 possible rows. Touches + // ___ 60 above or below these are ignored. + // . . . (+27) + // ___ 192 + if(inputdata.y <= GUI_ROW1_Y || inputdata.y > NDS_SCREEN_HEIGHT) + break; - selected_item_on_screen = FILE_LIST_ROWS_CENTER; - selected_item_on_list += selected_item_on_screen; - redraw = 1; - } + u32 mod = (inputdata.y - GUI_ROW1_Y) / GUI_ROW_SY; - break; - } - //scroll string (see above the switch) - case CURSOR_RIGHT: - /* fall through */ - //scroll string (see above the switch) - case CURSOR_LEFT: - break; + if(mod >= LastEntry - FirstEntry + 1) + break; - case CURSOR_SELECT: - wait_Allkey_release(0); - //file selected - if(selected_item_on_list + 1 <= num_files) - { - //The ".." directory - if(!strcasecmp(file_list[selected_item_on_list], "..")) - { - char *ext_pos; + SelectedIndex = FirstEntry + mod; + /* fall through */ + } - strcpy(filelist_info.current_path, default_dir_name); - ext_pos = strrchr(filelist_info.current_path, '/'); - if(NULL != ext_pos) //Not root directory + case CURSOR_SELECT: + wait_Allkey_release(0); + if (SelectedIndex == 0) // The parent directory + { + char* SlashPos = strrchr(CurrentDirectory, '/'); + if (SlashPos != NULL) // There's a parent + { + *SlashPos = '\0'; + ContinueInput = 0; + } + else // We're at the root { - *ext_pos = '\0'; - to_update_filelist= 1; + ReturnValue = -1; + ContinueDirectoryRead = 0; } } + else if (EntryDirectoryFlags[SelectedIndex]) + { + strcat(CurrentDirectory, "/"); + strcat(CurrentDirectory, EntryNames[SelectedIndex]); + ContinueInput = 0; + } else { - repeat = 0; - return_value = 0; - strcpy(default_dir_name, filelist_info.current_path); - strcpy(result, file_list[selected_item_on_list]); + strcpy(default_dir_name, CurrentDirectory); + strcpy(result, EntryNames[SelectedIndex]); + ReturnValue = 0; + ContinueDirectoryRead = 0; } - } - //directory selected - else if(num_dirs > 0) - { - unsigned int m; + break; - m = selected_item_on_list - num_files; - strcpy(filelist_info.current_path, default_dir_name); - strcat(filelist_info.current_path, "/"); - strcat(filelist_info.current_path, dir_list[m]); - to_update_filelist= 1; - } - break; + case CURSOR_UP: + SelectedIndex--; + if (SelectedIndex < 0) + SelectedIndex++; + else + ModifyScrollers = 1; + break; - case CURSOR_BACK: - { - wait_Allkey_release(0); - char *ext_pos; + case CURSOR_DOWN: + SelectedIndex++; + if (SelectedIndex >= EntryCount) + SelectedIndex--; + else + ModifyScrollers = 1; + break; - strcpy(filelist_info.current_path, default_dir_name); - ext_pos = strrchr(filelist_info.current_path, '/'); - if(NULL != ext_pos) //Not root directory + //scroll page down + case CURSOR_RTRIGGER: { - *ext_pos = '\0'; - to_update_filelist= 1; + u32 OldIndex = SelectedIndex; + SelectedIndex += FILE_LIST_ROWS; + if (SelectedIndex >= EntryCount) + SelectedIndex = EntryCount - 1; + if (SelectedIndex != OldIndex) + ModifyScrollers = 1; + break; } - else { //is root directory - return_value = -1; - repeat = 0; + + //scroll page up + case CURSOR_LTRIGGER: + { + u32 OldIndex = SelectedIndex; + SelectedIndex -= FILE_LIST_ROWS; + if (SelectedIndex < 0) + SelectedIndex = 0; + if (SelectedIndex != OldIndex) + ModifyScrollers = 1; + break; } - break; - } - case CURSOR_EXIT: - wait_Allkey_release(0); - return_value = -1; - repeat = 0; - break; + case CURSOR_BACK: + { + wait_Allkey_release(0); + char* SlashPos = strrchr(CurrentDirectory, '/'); + if (SlashPos != NULL) // There's a parent + { + *SlashPos = '\0'; + ContinueInput = 0; + } + else // We're at the root + { + ReturnValue = -1; + ContinueDirectoryRead = 0; + } + break; + } - default: - break; - } //end switch + case CURSOR_EXIT: + wait_Allkey_release(0); + ReturnValue = -1; + ContinueDirectoryRead = 0; + break; - if(to_update_filelist) - { - flag = load_file_list(&filelist_info); - if(-1 != flag) { - strcpy(default_dir_name, filelist_info.current_path); - num_files = filelist_info.file_num; - num_dirs = filelist_info.dir_num; - total_items_num = num_files + num_dirs;; + default: + break; + } // end switch + } // end while - selected_item_on_list = 0; //Selected item on list - selected_item_on_screen = 0; //Selected item on screen's position +cleanupScrollers: + for (; ScrollerCount > 0; ScrollerCount--) + draw_hscroll_over(ScrollerCount - 1); - redraw = -1; //redraw all - } - to_update_filelist = 0; - } +cleanup: + if (CurrentDirHandle != NULL) + closedir(CurrentDirHandle); - //redraw, code reuse - if(-1 == redraw || 1 == redraw) + if (EntryDirectoryFlags != NULL) + free(EntryDirectoryFlags); + if (EntryNames != NULL) { - unsigned int m, n, k; - char *pt; - unsigned short color; - - //draw background - show_icon(down_screen_addr, &ICON_SUBBG, 0, 0); - show_icon(down_screen_addr, &ICON_TITLE, 0, 0); - show_icon(down_screen_addr, &ICON_TITLEICON, TITLE_ICON_X, TITLE_ICON_Y); - - //release data struct to draw scrolling string - //Path - if(-1 == redraw) { - draw_hscroll_over(0); - draw_hscroll_init(down_screen_addr, 49, 10, 199, COLOR_TRANS, - COLOR_WHITE, default_dir_name); - path_scroll = 0x8000; //first scroll left - } + // EntryNames[0] is "..", a literal. Don't free it. + for (; EntryCount > 1; EntryCount--) + free(EntryNames[EntryCount - 1]); + free(EntryNames); + } + } // end while - for(m = 0; m < MAX_SCROLL_STRING; m++) - draw_hscroll_over(m+1); + return ReturnValue; +} - //file and directory list - //the first displayed item - m = selected_item_on_list - selected_item_on_screen; - //nubers of item to displayed - n = total_items_num - m; - if(n > FILE_LIST_ROWS) n = FILE_LIST_ROWS; +/*-------------------------------------------------------- + 放映幻灯片 +--------------------------------------------------------*/ - for(k= 0; k < n; k++, m++) - { - if(k == selected_item_on_screen) { - color = COLOR_ACTIVE_ITEM; - show_icon(down_screen_addr, &ICON_SUBSELA, SUBSELA_X, GUI_ROW1_Y + k * GUI_ROW_SY + SUBSELA_OFFSET_Y); - } - else - color = COLOR_INACTIVE_ITEM; +u32 play_screen_snapshot(void) +{ + s32 flag; + u32 repeat, i; + u16 *screenp; + u32 color_bg; - //directorys - if((m+1) > num_files) { - show_icon(down_screen_addr, &ICON_DIRECTORY, FILE_SELECTOR_ICON_X, GUI_ROW1_Y + k * GUI_ROW_SY + FILE_SELECTOR_ICON_Y); - pt = dir_list[m - num_files]; - } - //files - else { - pt= strrchr(file_list[m], '.'); - - if(!strcasecmp(pt, ".smc") || !strcasecmp(pt, ".sfc")) - show_icon(down_screen_addr, &ICON_SFCFILE, FILE_SELECTOR_ICON_X, GUI_ROW1_Y + k * GUI_ROW_SY + FILE_SELECTOR_ICON_Y); - else if(!strcasecmp(pt, ".zip")) - show_icon(down_screen_addr, &ICON_ZIPFILE, FILE_SELECTOR_ICON_X, GUI_ROW1_Y + k * GUI_ROW_SY + FILE_SELECTOR_ICON_Y); - else if(!strcasecmp(pt, ".cht")) - show_icon(down_screen_addr, &ICON_CHTFILE, FILE_SELECTOR_ICON_X, GUI_ROW1_Y + k * GUI_ROW_SY + FILE_SELECTOR_ICON_Y); - else if(!strcasecmp(file_list[m], "..")) - show_icon(down_screen_addr, &ICON_DOTDIR, FILE_SELECTOR_ICON_X, GUI_ROW1_Y + k * GUI_ROW_SY + FILE_SELECTOR_ICON_Y); - else //Not recoganized file - show_icon(down_screen_addr, &ICON_UNKNOW, FILE_SELECTOR_ICON_X, GUI_ROW1_Y + k * GUI_ROW_SY + FILE_SELECTOR_ICON_Y); - - pt = file_list[m]; - } + char** EntryNames = NULL; + DIR* CurrentDirHandle = NULL; + u32 EntryCount = 0, EntryCapacity = 4 /* initial */; + u32 Failed = 0; - draw_hscroll_init(down_screen_addr, FILE_SELECTOR_NAME_X, GUI_ROW1_Y + k * GUI_ROW_SY + TEXT_OFFSET_Y, FILE_SELECTOR_NAME_SX, - COLOR_TRANS, color, pt); - } + EntryNames = (char**) malloc(EntryCapacity * sizeof(char*)); + if (EntryNames == NULL) + { + Failed = 1; + goto cleanup; + } - redraw = 0; - } //end if(0 != redraw) - else if(0 != redraw) { - unsigned int m, n; - char *pt; - - m = selected_item_on_screen; - show_icon(down_screen_addr, &ICON_SUBSELA, SUBSELA_X, GUI_ROW1_Y + m * GUI_ROW_SY + SUBSELA_OFFSET_Y); - - n = selected_item_on_list; - if((n+1) > num_files) - show_icon(down_screen_addr, &ICON_DIRECTORY, FILE_SELECTOR_ICON_X, GUI_ROW1_Y + m * GUI_ROW_SY + FILE_SELECTOR_ICON_Y); - else { - pt= strrchr(file_list[n], '.'); - - if(!strcasecmp(pt, ".smc")) - show_icon(down_screen_addr, &ICON_SFCFILE, FILE_SELECTOR_ICON_X, GUI_ROW1_Y + m * GUI_ROW_SY + FILE_SELECTOR_ICON_Y); - else if(!strcasecmp(pt, ".zip")) - show_icon(down_screen_addr, &ICON_ZIPFILE, FILE_SELECTOR_ICON_X, GUI_ROW1_Y + m * GUI_ROW_SY + FILE_SELECTOR_ICON_Y); - else if(!strcasecmp(pt, ".cht")) - show_icon(down_screen_addr, &ICON_CHTFILE, FILE_SELECTOR_ICON_X, GUI_ROW1_Y + m * GUI_ROW_SY + FILE_SELECTOR_ICON_Y); - else if(!strcasecmp(file_list[m], "..")) - show_icon(down_screen_addr, &ICON_DOTDIR, FILE_SELECTOR_ICON_X, GUI_ROW1_Y + m * GUI_ROW_SY + FILE_SELECTOR_ICON_Y); - else //Not recoganized file - show_icon(down_screen_addr, &ICON_UNKNOW, FILE_SELECTOR_ICON_X, GUI_ROW1_Y + m * GUI_ROW_SY + FILE_SELECTOR_ICON_Y); - } + CurrentDirHandle = opendir(DEFAULT_SS_DIR); + if(CurrentDirHandle == NULL) { + Failed = 1; + goto cleanup; + } - draw_hscroll(m+1, redraw); - redraw = 0; - } + dirent* CurrentEntryHandle; + struct stat Stat; - //Path auto scroll - unsigned int m = path_scroll & 0xFF; - if(m < 20) //pause 0.5sec + while((CurrentEntryHandle = readdir_ex(CurrentDirHandle, &Stat)) != NULL) + { + char* Name = CurrentEntryHandle->d_name; + if(!S_ISDIR(Stat.st_mode)) { - draw_hscroll(0, 0); - // ^ but prevent flashing with non-scrolling paths - path_scroll += 1; - } - else { - show_icon(down_screen_addr, &ICON_TITLE, 0, 0); - show_icon(down_screen_addr, &ICON_TITLEICON, TITLE_ICON_X, TITLE_ICON_Y); - - if(path_scroll & 0x8000) //scroll left - { - if(draw_hscroll(0, -1) <= 1) path_scroll = 0; //scroll right - } - else + // Add files only if their extension is in the list. + char* Extension = strrchr(Name, '.'); + if (Extension != NULL) { - if(draw_hscroll(0, 1) <= 1) path_scroll = 0x8000; //scroll left - } - } - - ds2_flipScreen(DOWN_SCREEN, DOWN_SCREEN_UPDATE_METHOD); - - mdelay(20); //about 50ms - } //end while(repeat) + if(strcasecmp(Extension, ".bmp") == 0) + { + // Ensure we have enough capacity in the char* array first. + if (EntryCount == EntryCapacity) + { + void* NewEntryNames = realloc(EntryNames, EntryCapacity * 2 * sizeof(char*)); + if (NewEntryNames == NULL) + { + Failed = 1; + goto cleanup; + } + else + EntryNames = NewEntryNames; - unsigned int i; - for(i= 0; i < (FILE_LIST_ROWS +1); i++) - draw_hscroll_over(i); + EntryCapacity *= 2; + } - //deconstruct filelist_info struct - manage_filelist_info(&filelist_info, -1); + // Then add the entry. + EntryNames[EntryCount] = malloc(strlen(Name) + 1); + if (EntryNames[EntryCount] == NULL) + { + Failed = 1; + goto cleanup; + } - // ds2_clearScreen(DOWN_SCREEN, COLOR_BLACK); - // ds2_flipScreen(DOWN_SCREEN, DOWN_SCREEN_UPDATE_METHOD); + strcpy(EntryNames[EntryCount], Name); - return return_value; -} + EntryCount++; + } + } + } + } -/*-------------------------------------------------------- - 放映幻灯片 ---------------------------------------------------------*/ -u32 play_screen_snapshot(void) -{ - struct FILE_LIST_INFO filelist_info; - char *file_ext[] = { ".bmp", NULL }; - u32 file_num; - char **file_list; - s32 flag; - u32 repeat, i; - u16 *screenp; - u32 color_bg; +cleanup: + if (CurrentDirHandle != NULL) + closedir(CurrentDirHandle); screenp= (u16*)malloc(256*192*2); if(screenp == NULL) @@ -1326,42 +1226,25 @@ u32 play_screen_snapshot(void) color_bg = COLOR16(43, 11, 11); } - //construct filelist_info struct - if(-1 == manage_filelist_info(&filelist_info, 0)) - return -1; - - strcpy(filelist_info.current_path, DEFAULT_SS_DIR); - - filelist_info.wildcards = file_ext; - filelist_info.file_num = 0; - filelist_info.dir_num = 0; - - flag = load_file_list(&filelist_info); - if(-1 == flag) - { - //construct filelist_info struct - manage_filelist_info(&filelist_info, -1); - return -1; - } - - flag = load_file_list(&filelist_info); - file_num = filelist_info.file_num; - file_list = filelist_info.file_list; - - if(flag < 0 || file_num== 0) + if(Failed || EntryCount == 0) { draw_message(down_screen_addr, screenp, 28, 31, 227, 165, color_bg); draw_string_vcenter(down_screen_addr, MESSAGE_BOX_TEXT_X, MESSAGE_BOX_TEXT_Y, MESSAGE_BOX_TEXT_SX, COLOR_MSSG, msg[MSG_NO_SLIDE]); ds2_flipScreen(DOWN_SCREEN, DOWN_SCREEN_UPDATE_METHOD); if(screenp) free((void*)screenp); - //construct filelist_info struct - manage_filelist_info(&filelist_info, -1); - if(draw_yesno_dialog(DOWN_SCREEN, 115, msg[MSG_GENERAL_CONFIRM_WITH_A], msg[MSG_GENERAL_CANCEL_WITH_B])) - return 1; - else - return 0; + if (EntryNames != NULL) + { + for (; EntryCount > 0; EntryCount--) + free(EntryNames[EntryCount - 1]); + free(EntryNames); + } + + wait_Anykey_press(0); + wait_Allkey_release(0); + + return 0; } char bmp_path[MAX_PATH]; @@ -1380,7 +1263,7 @@ u32 play_screen_snapshot(void) i= 0; while(repeat) { - sprintf(bmp_path, "%s/%s", filelist_info.current_path, file_list[i]); + sprintf(bmp_path, "%s/%s", DEFAULT_SS_DIR, EntryNames[i]); flag = openBMP(&SbmpInfo, (const char*)bmp_path); if(flag == BMP_OK) @@ -1439,7 +1322,7 @@ u32 play_screen_snapshot(void) closeBMP(&SbmpInfo); } - if(i+1 < file_num) i++; + if(i+1 < EntryCount) i++; else i= 0; gui_action_type gui_action; @@ -1472,8 +1355,8 @@ u32 play_screen_snapshot(void) case CURSOR_LEFT: time1 = ticks; if(i > 1) i -= 2; - else if(i == 1) i= file_num -1; - else i= file_num -2; + else if(i == 1) i= EntryCount -1; + else i= EntryCount -2; break; case CURSOR_RIGHT: @@ -1494,9 +1377,6 @@ u32 play_screen_snapshot(void) break; case CURSOR_BACK: - if(screenp) free((void*)screenp); - //deconstruct filelist_info struct - manage_filelist_info(&filelist_info, -1); repeat = 0; break; @@ -1511,6 +1391,15 @@ u32 play_screen_snapshot(void) } } + if(screenp) free((void*)screenp); + + if (EntryNames != NULL) + { + for (; EntryCount > 0; EntryCount--) + free(EntryNames[EntryCount - 1]); + free(EntryNames); + } + return 0; } diff --git a/source/nds/message.h b/source/nds/message.h index 98f64ab..f2977e4 100644 --- a/source/nds/message.h +++ b/source/nds/message.h @@ -31,6 +31,10 @@ enum MSG MSG_MAIN_MENU_TOOLS, MSG_MAIN_MENU_OPTIONS, MSG_MAIN_MENU_EXIT, + + MSG_FILE_MENU_LOADING_LIST, + MSG_FILE_MENU_SORTING_LIST, + FMT_VIDEO_AUDIO_FLUIDITY_PREFERENCE, MSG_VIDEO_AUDIO_FLUIDITY_PREFER_VIDEO, MSG_VIDEO_AUDIO_FLUIDITY_PREFER_AUDIO, -- cgit v1.2.3