about summary refs log tree commit diff
diff options
context:
space:
mode:
authoroy <Tom_Adams@web.de>2010-09-29 00:53:53 +0200
committeroy <Tom_Adams@web.de>2010-09-29 00:53:53 +0200
commitaaf8e2bc8e02d37fb132c8acd7c2a8fe82c15117 (patch)
treed8898339563b2dbbc4bc55f579c3b180cd1c435f
parentc172c24fd1fbf6a430e1852e62e72f6e0cfeeb63 (diff)
downloadzcatch-aaf8e2bc8e02d37fb132c8acd7c2a8fe82c15117.tar.gz
zcatch-aaf8e2bc8e02d37fb132c8acd7c2a8fe82c15117.zip
cleaned up demo listing and fixed its sorting. Closes #73
-rw-r--r--src/base/system.c51
-rw-r--r--src/base/system.h18
-rw-r--r--src/game/client/components/menus.h13
-rw-r--r--src/game/client/components/menus_demo.cpp117
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;