cleaned up demo listing and fixed its sorting. Closes #73

This commit is contained in:
oy 2010-09-29 00:53:53 +02:00
parent c172c24fd1
commit aaf8e2bc8e
4 changed files with 131 additions and 68 deletions

View file

@ -869,6 +869,7 @@ int fs_listdir(const char *dir, FS_LISTDIR_CALLBACK cb, int type, void *user)
WIN32_FIND_DATA finddata; WIN32_FIND_DATA finddata;
HANDLE handle; HANDLE handle;
char buffer[1024*2]; char buffer[1024*2];
int length;
str_format(buffer, sizeof(buffer), "%s/*", dir); str_format(buffer, sizeof(buffer), "%s/*", dir);
handle = FindFirstFileA(buffer, &finddata); handle = FindFirstFileA(buffer, &finddata);
@ -876,23 +877,36 @@ int fs_listdir(const char *dir, FS_LISTDIR_CALLBACK cb, int type, void *user)
if (handle == INVALID_HANDLE_VALUE) if (handle == INVALID_HANDLE_VALUE)
return 0; return 0;
str_format(buffer, sizeof(buffer), "%s/", dir);
length = str_length(buffer);
/* add all the entries */ /* add all the entries */
do do
{ {
cb(finddata.cFileName, 0, type, user); str_copy(buffer+length, finddata.cFileName, (int)sizeof(buffer)-length);
} while (FindNextFileA(handle, &finddata)); cb(finddata.cFileName, fs_is_dir(buffer), type, user);
}
while (FindNextFileA(handle, &finddata));
FindClose(handle); FindClose(handle);
return 0; return 0;
#else #else
struct dirent *entry; struct dirent *entry;
char buffer[1024*2];
int length;
DIR *d = opendir(dir); DIR *d = opendir(dir);
if(!d) if(!d)
return 0; return 0;
str_format(buffer, sizeof(buffer), "%s/", dir);
length = str_length(buffer);
while((entry = readdir(d)) != NULL) while((entry = readdir(d)) != NULL)
cb(entry->d_name, 0, type, user); {
str_copy(buffer+length, entry->d_name, (int)sizeof(buffer)-length);
cb(entry->d_name, fs_is_dir(buffer), type, user);
}
/* close the directory and return */ /* close the directory and return */
closedir(d); closedir(d);
@ -1155,6 +1169,37 @@ int str_comp_num(const char *a, const char *b, const int num)
return strncmp(a, b, num); return strncmp(a, b, num);
} }
int str_comp_filenames(const char *a, const char *b)
{
int result;
for(; *a && *b; ++a, ++b)
{
if(*a >= '0' && *a <= '9' && *b >= '0' && *b <= '9')
{
result = 0;
do
{
if(!result)
result = *a - *b;
++a; ++b;
}
while(*a >= '0' && *a <= '9' && *b >= '0' && *b <= '9');
if(*a >= '0' && *a <= '9')
return 1;
else if(*b >= '0' && *b <= '9')
return -1;
else if(result)
return result;
}
if(*a != *b)
break;
}
return *a - *b;
}
const char *str_find_nocase(const char *haystack, const char *needle) const char *str_find_nocase(const char *haystack, const char *needle)
{ {
while(*haystack) /* native implementation */ while(*haystack) /* native implementation */

View file

@ -829,6 +829,24 @@ int str_comp(const char *a, const char *b);
*/ */
int str_comp_num(const char *a, const char *b, const int num); int str_comp_num(const char *a, const char *b, const int num);
/*
Function: str_comp_filenames
Compares two strings case sensitive, digit chars will be compared as numbers.
Parameters:
a - String to compare.
b - String to compare.
Returns:
<0 - String a is lesser then string b
0 - String a is equal to string b
>0 - String a is greater then string b
Remarks:
- The strings are treated as zero-termineted strings.
*/
int str_comp_filenames(const char *a, const char *b);
/* /*
Function: str_find_nocase Function: str_find_nocase
Finds a string inside another string case insensitive. Finds a string inside another string case insensitive.

View file

@ -156,16 +156,23 @@ class CMenus : public CComponent
// demo // demo
struct CDemoItem struct CDemoItem
{ {
char m_aFilename[512]; char m_aFilename[128];
char m_aName[256]; char m_aName[128];
bool m_IsDir;
int m_DirType;
bool operator<(const CDemoItem &Other) { return str_comp(m_aName, Other.m_aName) < 0; } bool operator<(const CDemoItem &Other) { return !str_comp(m_aFilename, "..") ? true : !str_comp(Other.m_aFilename, "..") ? false :
m_IsDir && !Other.m_IsDir ? true : !m_IsDir && Other.m_IsDir ? false :
str_comp_filenames(m_aFilename, Other.m_aFilename) < 0; }
}; };
sorted_array<CDemoItem> m_lDemos; sorted_array<CDemoItem> m_lDemos;
char m_aCurrentDemoFolder[256]; char m_aCurrentDemoFolder[256];
bool m_DemolistDelEntry; bool m_DemolistDelEntry;
int m_DemolistSelectedIndex;
bool m_DemolistSelectedIsDir;
void DemolistOnUpdate(bool Reset);
void DemolistPopulate(); void DemolistPopulate();
static void DemolistFetchCallback(const char *pName, int IsDir, int DirType, void *pUser); static void DemolistFetchCallback(const char *pName, int IsDir, int DirType, void *pUser);

View file

@ -410,61 +410,59 @@ int CMenus::UiDoListboxEnd(float *pScrollValue, bool *pItemActivated)
void CMenus::DemolistFetchCallback(const char *pName, int IsDir, int DirType, void *pUser) void CMenus::DemolistFetchCallback(const char *pName, int IsDir, int DirType, void *pUser)
{ {
if(pName[0] == '.') CMenus *pSelf = (CMenus *)pUser;
int Length = str_length(pName);
if((pName[0] == '.' && (pName[1] == 0 ||
(pName[1] == '.' && pName[2] == 0 && !str_comp(pSelf->m_aCurrentDemoFolder, "demos")))) ||
(!IsDir && (Length < 5 || str_comp(pName+Length-5, ".demo"))))
return; return;
CMenus *pSelf = (CMenus *)pUser;
CDemoItem Item; CDemoItem Item;
str_format(Item.m_aFilename, sizeof(Item.m_aFilename), "%s%s%s/%s", pSelf->Storage()->GetDirectory(DirType), str_copy(Item.m_aFilename, pName, sizeof(Item.m_aFilename));
pSelf->Storage()->GetDirectory(DirType)[0] ? "/" : "", pSelf->m_aCurrentDemoFolder, pName); if(IsDir)
str_copy(Item.m_aName, pName, sizeof(Item.m_aName)); str_format(Item.m_aName, sizeof(Item.m_aName), "%s/", pName);
else
str_format(Item.m_aName, min(static_cast<int>(sizeof(Item.m_aName)), Length), " %s", pName);
Item.m_IsDir = IsDir != 0;
Item.m_DirType = DirType;
pSelf->m_lDemos.add(Item); pSelf->m_lDemos.add(Item);
} }
void CMenus::DemolistPopulate() void CMenus::DemolistPopulate()
{ {
m_lDemos.clear(); m_lDemos.clear();
if(str_comp(m_aCurrentDemoFolder, "demos") != 0) //add parent folder
{
CDemoItem Item;
str_copy(Item.m_aName, "..", sizeof(Item.m_aName));
str_copy(Item.m_aFilename, "..", sizeof(Item.m_aFilename));
m_lDemos.add(Item);
}
Storage()->ListDirectory(IStorage::TYPE_SAVE|IStorage::TYPE_CURRENT, m_aCurrentDemoFolder, DemolistFetchCallback, this); Storage()->ListDirectory(IStorage::TYPE_SAVE|IStorage::TYPE_CURRENT, m_aCurrentDemoFolder, DemolistFetchCallback, this);
} }
void CMenus::DemolistOnUpdate(bool Reset)
{
m_DemolistSelectedIndex = Reset ? m_lDemos.size() > 0 ? 0 : -1 :
m_DemolistSelectedIndex >= m_lDemos.size() ? m_lDemos.size()-1 : m_DemolistSelectedIndex;
m_DemolistSelectedIsDir = m_DemolistSelectedIndex < 0 ? false : m_lDemos[m_DemolistSelectedIndex].m_IsDir;
}
void CMenus::RenderDemoList(CUIRect MainView) void CMenus::RenderDemoList(CUIRect MainView)
{ {
static int s_SelectedItem = -1;
static int s_Inited = 0; static int s_Inited = 0;
if(!s_Inited) if(!s_Inited)
{ {
DemolistPopulate(); DemolistPopulate();
DemolistOnUpdate(true);
s_Inited = 1; s_Inited = 1;
if(m_lDemos.size() > 0)
s_SelectedItem = 0;
}
bool IsDir = false;
if(s_SelectedItem >= 0 && s_SelectedItem < m_lDemos.size())
{
if(str_comp(m_lDemos[s_SelectedItem].m_aName, "..") == 0 || fs_is_dir(m_lDemos[s_SelectedItem].m_aFilename))
IsDir = true;
} }
// delete demo // delete demo
if(m_DemolistDelEntry) if(m_DemolistDelEntry)
{ {
if(s_SelectedItem >= 0 && s_SelectedItem < m_lDemos.size() && !IsDir) if(m_DemolistSelectedIndex >= 0 && !m_DemolistSelectedIsDir)
{ {
Storage()->RemoveFile(m_lDemos[s_SelectedItem].m_aFilename); char aBuf[512];
str_format(aBuf, sizeof(aBuf), "%s%s%s/%s", Storage()->GetDirectory(m_lDemos[m_DemolistSelectedIndex].m_DirType),
Storage()->GetDirectory(m_lDemos[m_DemolistSelectedIndex].m_DirType)[0] ? "/" : "",
m_aCurrentDemoFolder, m_lDemos[m_DemolistSelectedIndex].m_aFilename);
Storage()->RemoveFile(aBuf);
DemolistPopulate(); DemolistPopulate();
s_SelectedItem = s_SelectedItem-1 < 0 ? m_lDemos.size() > 0 ? 0 : -1 : s_SelectedItem-1; DemolistOnUpdate(false);
} }
m_DemolistDelEntry = false; m_DemolistDelEntry = false;
} }
@ -473,15 +471,17 @@ void CMenus::RenderDemoList(CUIRect MainView)
RenderTools()->DrawUIRect(&MainView, ms_ColorTabbarActive, CUI::CORNER_ALL, 10.0f); RenderTools()->DrawUIRect(&MainView, ms_ColorTabbarActive, CUI::CORNER_ALL, 10.0f);
MainView.Margin(10.0f, &MainView); MainView.Margin(10.0f, &MainView);
CUIRect ButtonBar; CUIRect ButtonBar, RefreshRect, PlayRect, DeleteRect;
MainView.HSplitBottom(ms_ButtonHeight+5.0f, &MainView, &ButtonBar); MainView.HSplitBottom(ms_ButtonHeight+5.0f, &MainView, &ButtonBar);
ButtonBar.HSplitTop(5.0f, 0, &ButtonBar); ButtonBar.HSplitTop(5.0f, 0, &ButtonBar);
ButtonBar.VSplitRight(130.0f, &ButtonBar, &PlayRect);
ButtonBar.VSplitLeft(130.0f, &RefreshRect, &ButtonBar);
ButtonBar.VSplitLeft(10.0f, &DeleteRect, &ButtonBar);
ButtonBar.VSplitLeft(120.0f, &DeleteRect, &ButtonBar);
static int s_DemoListId = 0; static int s_DemoListId = 0;
static float s_ScrollValue = 0; static float s_ScrollValue = 0;
UiDoListboxStart(&s_DemoListId, &MainView, 17.0f, Localize("Demos"), "", m_lDemos.size(), 1, m_DemolistSelectedIndex, s_ScrollValue);
UiDoListboxStart(&s_DemoListId, &MainView, 17.0f, Localize("Demos"), "", m_lDemos.size(), 1, s_SelectedItem, s_ScrollValue);
//for(int i = 0; i < num_demos; i++)
for(sorted_array<CDemoItem>::range r = m_lDemos.all(); !r.empty(); r.pop_front()) for(sorted_array<CDemoItem>::range r = m_lDemos.all(); !r.empty(); r.pop_front())
{ {
CListboxItem Item = UiDoListboxNextItem((void*)(&r.front())); CListboxItem Item = UiDoListboxNextItem((void*)(&r.front()));
@ -489,48 +489,41 @@ void CMenus::RenderDemoList(CUIRect MainView)
UI()->DoLabel(&Item.m_Rect, r.front().m_aName, Item.m_Rect.h*ms_FontmodHeight, -1); UI()->DoLabel(&Item.m_Rect, r.front().m_aName, Item.m_Rect.h*ms_FontmodHeight, -1);
} }
bool Activated = false; bool Activated = false;
s_SelectedItem = UiDoListboxEnd(&s_ScrollValue, &Activated); m_DemolistSelectedIndex = UiDoListboxEnd(&s_ScrollValue, &Activated);
DemolistOnUpdate(false);
CUIRect RefreshRect, PlayRect, DeleteRect;
ButtonBar.VSplitRight(130.0f, &ButtonBar, &PlayRect);
ButtonBar.VSplitLeft(130.0f, &RefreshRect, &ButtonBar);
ButtonBar.VSplitLeft(10.0f, &DeleteRect, &ButtonBar);
ButtonBar.VSplitLeft(120.0f, &DeleteRect, &ButtonBar);
static int s_RefreshButton = 0; static int s_RefreshButton = 0;
if(DoButton_Menu(&s_RefreshButton, Localize("Refresh"), 0, &RefreshRect)) if(DoButton_Menu(&s_RefreshButton, Localize("Refresh"), 0, &RefreshRect))
{ {
DemolistPopulate(); DemolistPopulate();
DemolistOnUpdate(false);
} }
static int s_PlayButton = 0; static int s_PlayButton = 0;
char aTitleButton[10]; if(DoButton_Menu(&s_PlayButton, m_DemolistSelectedIsDir?Localize("Open"):Localize("Play"), 0, &PlayRect) || Activated)
if(IsDir)
str_copy(aTitleButton, Localize("Open"), sizeof(aTitleButton));
else
str_copy(aTitleButton, Localize("Play"), sizeof(aTitleButton));
if(DoButton_Menu(&s_PlayButton, aTitleButton, 0, &PlayRect) || Activated)
{ {
if(s_SelectedItem >= 0 && s_SelectedItem < m_lDemos.size()) if(m_DemolistSelectedIndex >= 0)
{ {
if(str_comp(m_lDemos[s_SelectedItem].m_aName, "..") == 0) //parent folder if(m_DemolistSelectedIsDir) // folder
{ {
if(str_comp(m_lDemos[m_DemolistSelectedIndex].m_aFilename, "..") == 0) // parent folder
fs_parent_dir(m_aCurrentDemoFolder); fs_parent_dir(m_aCurrentDemoFolder);
DemolistPopulate(); else // sub folder
s_SelectedItem = m_lDemos.size() > 0 ? 0 : -1;
}
else if(IsDir) //folder
{ {
char aTemp[256]; char aTemp[256];
str_copy(aTemp, m_aCurrentDemoFolder, sizeof(aTemp)); str_copy(aTemp, m_aCurrentDemoFolder, sizeof(aTemp));
str_format(m_aCurrentDemoFolder, sizeof(m_aCurrentDemoFolder), "%s/%s", aTemp, m_lDemos[s_SelectedItem].m_aName); str_format(m_aCurrentDemoFolder, sizeof(m_aCurrentDemoFolder), "%s/%s", aTemp, m_lDemos[m_DemolistSelectedIndex].m_aFilename);
}
DemolistPopulate(); DemolistPopulate();
s_SelectedItem = m_lDemos.size() > 0 ? 0 : -1; DemolistOnUpdate(true);
} }
else // file else // file
{ {
const char *pError = Client()->DemoPlayer_Play(m_lDemos[s_SelectedItem].m_aFilename); char aBuf[512];
str_format(aBuf, sizeof(aBuf), "%s%s%s/%s", Storage()->GetDirectory(m_lDemos[m_DemolistSelectedIndex].m_DirType),
Storage()->GetDirectory(m_lDemos[m_DemolistSelectedIndex].m_DirType)[0] ? "/" : "",
m_aCurrentDemoFolder, m_lDemos[m_DemolistSelectedIndex].m_aFilename);
const char *pError = Client()->DemoPlayer_Play(aBuf);
if(pError) if(pError)
PopupMessage(Localize("Error"), str_comp(pError, "error loading demo") ? pError : Localize("error loading demo"), Localize("Ok")); PopupMessage(Localize("Error"), str_comp(pError, "error loading demo") ? pError : Localize("error loading demo"), Localize("Ok"));
else else
@ -542,12 +535,12 @@ void CMenus::RenderDemoList(CUIRect MainView)
} }
} }
if(!IsDir) if(!m_DemolistSelectedIsDir)
{ {
static int s_DeleteButton = 0; static int s_DeleteButton = 0;
if(DoButton_Menu(&s_DeleteButton, Localize("Delete"), 0, &DeleteRect) || m_DeletePressed) if(DoButton_Menu(&s_DeleteButton, Localize("Delete"), 0, &DeleteRect) || m_DeletePressed)
{ {
if(s_SelectedItem >= 0 && s_SelectedItem < m_lDemos.size()) if(m_DemolistSelectedIndex >= 0)
{ {
UI()->SetActiveItem(0); UI()->SetActiveItem(0);
m_Popup = POPUP_DELETE_DEMO; m_Popup = POPUP_DELETE_DEMO;