aboutsummaryrefslogtreecommitdiff
path: root/source
diff options
context:
space:
mode:
authorNebuleon Fumika2013-06-15 23:40:29 -0400
committerNebuleon Fumika2013-06-15 23:40:29 -0400
commita1d1e01e11185d389f9448be0be0a567f1430600 (patch)
tree324e45c5680fbd14ed7cafe91910d6fc137d6425 /source
parent4252250fe77d6bd874ed626314a819340c29b4db (diff)
downloadsnes9x2005-a1d1e01e11185d389f9448be0be0a567f1430600.tar.gz
snes9x2005-a1d1e01e11185d389f9448be0be0a567f1430600.tar.bz2
snes9x2005-a1d1e01e11185d389f9448be0be0a567f1430600.zip
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 <https://github.com/Nebuleon/GameYob/commit/afbeeba>. * 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.
Diffstat (limited to 'source')
-rw-r--r--source/nds/gui.c1315
-rw-r--r--source/nds/message.h4
2 files changed, 606 insertions, 713 deletions
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,