diff options
| -rw-r--r-- | src/base/system.c | 51 | ||||
| -rw-r--r-- | src/base/system.h | 18 | ||||
| -rw-r--r-- | src/game/client/components/menus.h | 13 | ||||
| -rw-r--r-- | src/game/client/components/menus_demo.cpp | 117 |
4 files changed, 131 insertions, 68 deletions
diff --git a/src/base/system.c b/src/base/system.c index 6c74fb23..bf473650 100644 --- a/src/base/system.c +++ b/src/base/system.c @@ -869,6 +869,7 @@ int fs_listdir(const char *dir, FS_LISTDIR_CALLBACK cb, int type, void *user) WIN32_FIND_DATA finddata; HANDLE handle; char buffer[1024*2]; + int length; str_format(buffer, sizeof(buffer), "%s/*", dir); 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) return 0; + str_format(buffer, sizeof(buffer), "%s/", dir); + length = str_length(buffer); + /* add all the entries */ do { - cb(finddata.cFileName, 0, type, user); - } while (FindNextFileA(handle, &finddata)); + str_copy(buffer+length, finddata.cFileName, (int)sizeof(buffer)-length); + cb(finddata.cFileName, fs_is_dir(buffer), type, user); + } + while (FindNextFileA(handle, &finddata)); FindClose(handle); return 0; #else struct dirent *entry; + char buffer[1024*2]; + int length; DIR *d = opendir(dir); if(!d) return 0; + str_format(buffer, sizeof(buffer), "%s/", dir); + length = str_length(buffer); + 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 */ closedir(d); @@ -1155,6 +1169,37 @@ int str_comp_num(const char *a, const char *b, const int 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) { while(*haystack) /* native implementation */ diff --git a/src/base/system.h b/src/base/system.h index 2ef7a9f3..f71a03ec 100644 --- a/src/base/system.h +++ b/src/base/system.h @@ -830,6 +830,24 @@ int str_comp(const char *a, const char *b); 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 Finds a string inside another string case insensitive. diff --git a/src/game/client/components/menus.h b/src/game/client/components/menus.h index 2fb53d13..a1e75f61 100644 --- a/src/game/client/components/menus.h +++ b/src/game/client/components/menus.h @@ -156,16 +156,23 @@ class CMenus : public CComponent // demo struct CDemoItem { - char m_aFilename[512]; - char m_aName[256]; + char m_aFilename[128]; + 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; char m_aCurrentDemoFolder[256]; bool m_DemolistDelEntry; + int m_DemolistSelectedIndex; + bool m_DemolistSelectedIsDir; + void DemolistOnUpdate(bool Reset); void DemolistPopulate(); static void DemolistFetchCallback(const char *pName, int IsDir, int DirType, void *pUser); diff --git a/src/game/client/components/menus_demo.cpp b/src/game/client/components/menus_demo.cpp index abe59094..470a2529 100644 --- a/src/game/client/components/menus_demo.cpp +++ b/src/game/client/components/menus_demo.cpp @@ -410,61 +410,59 @@ int CMenus::UiDoListboxEnd(float *pScrollValue, bool *pItemActivated) void CMenus::DemolistFetchCallback(const char *pName, int IsDir, int DirType, void *pUser) { - if(pName[0] == '.') - return; - 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; CDemoItem Item; - str_format(Item.m_aFilename, sizeof(Item.m_aFilename), "%s%s%s/%s", pSelf->Storage()->GetDirectory(DirType), - pSelf->Storage()->GetDirectory(DirType)[0] ? "/" : "", pSelf->m_aCurrentDemoFolder, pName); - str_copy(Item.m_aName, pName, sizeof(Item.m_aName)); + str_copy(Item.m_aFilename, pName, sizeof(Item.m_aFilename)); + if(IsDir) + 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); } void CMenus::DemolistPopulate() { 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); } +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) { - static int s_SelectedItem = -1; static int s_Inited = 0; if(!s_Inited) { DemolistPopulate(); + DemolistOnUpdate(true); 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 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(); - s_SelectedItem = s_SelectedItem-1 < 0 ? m_lDemos.size() > 0 ? 0 : -1 : s_SelectedItem-1; + DemolistOnUpdate(false); } m_DemolistDelEntry = false; } @@ -473,15 +471,17 @@ void CMenus::RenderDemoList(CUIRect MainView) RenderTools()->DrawUIRect(&MainView, ms_ColorTabbarActive, CUI::CORNER_ALL, 10.0f); MainView.Margin(10.0f, &MainView); - CUIRect ButtonBar; + CUIRect ButtonBar, RefreshRect, PlayRect, DeleteRect; MainView.HSplitBottom(ms_ButtonHeight+5.0f, &MainView, &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 float s_ScrollValue = 0; - - UiDoListboxStart(&s_DemoListId, &MainView, 17.0f, Localize("Demos"), "", m_lDemos.size(), 1, s_SelectedItem, s_ScrollValue); - //for(int i = 0; i < num_demos; i++) + UiDoListboxStart(&s_DemoListId, &MainView, 17.0f, Localize("Demos"), "", m_lDemos.size(), 1, m_DemolistSelectedIndex, s_ScrollValue); for(sorted_array<CDemoItem>::range r = m_lDemos.all(); !r.empty(); r.pop_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); } bool Activated = false; - s_SelectedItem = UiDoListboxEnd(&s_ScrollValue, &Activated); - - 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); + m_DemolistSelectedIndex = UiDoListboxEnd(&s_ScrollValue, &Activated); + DemolistOnUpdate(false); static int s_RefreshButton = 0; if(DoButton_Menu(&s_RefreshButton, Localize("Refresh"), 0, &RefreshRect)) { DemolistPopulate(); + DemolistOnUpdate(false); } static int s_PlayButton = 0; - char aTitleButton[10]; - 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(DoButton_Menu(&s_PlayButton, m_DemolistSelectedIsDir?Localize("Open"):Localize("Play"), 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 - { - fs_parent_dir(m_aCurrentDemoFolder); - DemolistPopulate(); - s_SelectedItem = m_lDemos.size() > 0 ? 0 : -1; - } - else if(IsDir) //folder + if(m_DemolistSelectedIsDir) // folder { - char aTemp[256]; - str_copy(aTemp, m_aCurrentDemoFolder, sizeof(aTemp)); - str_format(m_aCurrentDemoFolder, sizeof(m_aCurrentDemoFolder), "%s/%s", aTemp, m_lDemos[s_SelectedItem].m_aName); + if(str_comp(m_lDemos[m_DemolistSelectedIndex].m_aFilename, "..") == 0) // parent folder + fs_parent_dir(m_aCurrentDemoFolder); + else // sub folder + { + char aTemp[256]; + str_copy(aTemp, m_aCurrentDemoFolder, sizeof(aTemp)); + str_format(m_aCurrentDemoFolder, sizeof(m_aCurrentDemoFolder), "%s/%s", aTemp, m_lDemos[m_DemolistSelectedIndex].m_aFilename); + } 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) PopupMessage(Localize("Error"), str_comp(pError, "error loading demo") ? pError : Localize("error loading demo"), Localize("Ok")); else @@ -542,12 +535,12 @@ void CMenus::RenderDemoList(CUIRect MainView) } } - if(!IsDir) + if(!m_DemolistSelectedIsDir) { static int s_DeleteButton = 0; 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); m_Popup = POPUP_DELETE_DEMO; |