Demo browser column listbox added

This commit is contained in:
east 2015-08-27 14:57:56 +02:00
parent da17b795c5
commit 675c6eb1e0
8 changed files with 221 additions and 65 deletions

View file

@ -1569,6 +1569,59 @@ int net_init()
return 0;
}
int fs_listdir_info(const char *dir, FS_LISTDIR_INFO_CALLBACK cb, int type, void *user)
{
#if defined(CONF_FAMILY_WINDOWS)
WIN32_FIND_DATA finddata;
HANDLE handle;
char buffer[1024*2];
int length;
str_format(buffer, sizeof(buffer), "%s/*", dir);
handle = FindFirstFileA(buffer, &finddata);
if (handle == INVALID_HANDLE_VALUE)
return 0;
str_format(buffer, sizeof(buffer), "%s/", dir);
length = str_length(buffer);
/* add all the entries */
do
{
str_copy(buffer+length, finddata.cFileName, (int)sizeof(buffer)-length);
if(cb(finddata.cFileName, fs_getmtime(buffer), fs_is_dir(buffer), type, user))
break;
}
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)
{
str_copy(buffer+length, entry->d_name, (int)sizeof(buffer)-length);
if(cb(entry->d_name, fs_getmtime(buffer), fs_is_dir(buffer), type, user))
break;
}
/* close the directory and return */
closedir(d);
return 0;
#endif
}
int fs_listdir(const char *dir, FS_LISTDIR_CALLBACK cb, int type, void *user)
{
#if defined(CONF_FAMILY_WINDOWS)
@ -2060,15 +2113,20 @@ void str_hex(char *dst, int dst_size, const void *data, int data_size)
}
}
void str_timestamp_ex(time_t time_data, char *buffer, int buffer_size, const char *format)
{
struct tm *time_info;
time_info = localtime(&time_data);
strftime(buffer, buffer_size, format, time_info);
buffer[buffer_size-1] = 0; /* assure null termination */
}
void str_timestamp(char *buffer, int buffer_size)
{
time_t time_data;
struct tm *time_info;
time(&time_data);
time_info = localtime(&time_data);
strftime(buffer, buffer_size, "%Y-%m-%d_%H-%M-%S", time_info);
buffer[buffer_size-1] = 0; /* assure null termination */
str_timestamp_ex(time_data, buffer, buffer_size, "%Y-%m-%d_%H-%M-%S");
}
int mem_comp(const void *a, const void *b, int size)

View file

@ -1027,6 +1027,7 @@ void str_hex(char *dst, int dst_size, const void *data, int data_size);
- Guarantees that buffer string will contain zero-termination.
*/
void str_timestamp(char *buffer, int buffer_size);
void str_timestamp_ex(time_t time, char *buffer, int buffer_size, const char *format);
/* Group: Filesystem */
@ -1044,7 +1045,9 @@ void str_timestamp(char *buffer, int buffer_size);
Always returns 0.
*/
typedef int (*FS_LISTDIR_CALLBACK)(const char *name, int is_dir, int dir_type, void *user);
typedef int (*FS_LISTDIR_INFO_CALLBACK)(const char *name, time_t date, int is_dir, int dir_type, void *user);
int fs_listdir(const char *dir, FS_LISTDIR_CALLBACK cb, int type, void *user);
int fs_listdir_info(const char *dir, FS_LISTDIR_INFO_CALLBACK cb, int type, void *user);
/*
Function: fs_makedir

View file

@ -62,6 +62,9 @@ MACRO_CONFIG_INT(BrSort, br_sort, 4, 0, 256, CFGFLAG_SAVE|CFGFLAG_CLIENT, "")
MACRO_CONFIG_INT(BrSortOrder, br_sort_order, 1, 0, 1, CFGFLAG_SAVE|CFGFLAG_CLIENT, "")
MACRO_CONFIG_INT(BrMaxRequests, br_max_requests, 25, 0, 1000, CFGFLAG_SAVE|CFGFLAG_CLIENT, "Number of requests to use when refreshing server browser")
MACRO_CONFIG_INT(BrDemoSort, br_demo_sort, 0, 0, 1, CFGFLAG_SAVE|CFGFLAG_CLIENT, "")
MACRO_CONFIG_INT(BrDemoSortOrder, br_demo_sort_order, 0, 0, 1, CFGFLAG_SAVE|CFGFLAG_CLIENT, "")
MACRO_CONFIG_INT(SndBufferSize, snd_buffer_size, 512, 128, 32768, CFGFLAG_SAVE|CFGFLAG_CLIENT, "Sound buffer size")
#if defined(__ANDROID__)
MACRO_CONFIG_INT(SndRate, snd_rate, 44100, 0, 0, CFGFLAG_SAVE|CFGFLAG_CLIENT, "Sound mixing rate")

View file

@ -230,6 +230,23 @@ public:
dbg_msg("storage", "warning no data directory found");
}
virtual void ListDirectoryInfo(int Type, const char *pPath, FS_LISTDIR_INFO_CALLBACK pfnCallback, void *pUser)
{
char aBuffer[MAX_PATH_LENGTH];
if(Type == TYPE_ALL)
{
// list all available directories
for(int i = 0; i < m_NumPaths; ++i)
fs_listdir_info(GetPath(i, pPath, aBuffer, sizeof(aBuffer)), pfnCallback, i, pUser);
}
else if(Type >= 0 && Type < m_NumPaths)
{
// list wanted directory
fs_listdir_info(GetPath(Type, pPath, aBuffer, sizeof(aBuffer)), pfnCallback, Type, pUser);
}
}
virtual void ListDirectory(int Type, const char *pPath, FS_LISTDIR_CALLBACK pfnCallback, void *pUser)
{
char aBuffer[MAX_PATH_LENGTH];

View file

@ -27,6 +27,7 @@ public:
int FindDatadir(const char *pArgv0);
virtual void ListDirectory(int Types, const char *pPath, FS_LISTDIR_CALLBACK pfnCallback, void *pUser);
virtual void ListDirectoryInfo(int Type, const char *pPath, FS_LISTDIR_INFO_CALLBACK pfnCallback, void *pUser) = 0;
virtual IOHANDLE OpenFile(const char *pFilename, int Flags, char *pBuffer = 0, int BufferSize = 0);

View file

@ -20,6 +20,7 @@ public:
};
virtual void ListDirectory(int Type, const char *pPath, FS_LISTDIR_CALLBACK pfnCallback, void *pUser) = 0;
virtual void ListDirectoryInfo(int Type, const char *pPath, FS_LISTDIR_INFO_CALLBACK pfnCallback, void *pUser) = 0;
virtual IOHANDLE OpenFile(const char *pFilename, int Flags, int Type, char *pBuffer = 0, int BufferSize = 0) = 0;
virtual bool FindFile(const char *pFilename, const char *pPath, int Type, char *pBuffer, int BufferSize) = 0;
virtual bool RemoveFile(const char *pFilename, int Type) = 0;

View file

@ -155,14 +155,45 @@ class CMenus : public CComponent
char m_aName[128];
bool m_IsDir;
int m_StorageType;
time_t m_Date;
bool m_InfosLoaded;
bool m_Valid;
CDemoHeader m_Info;
bool operator<(const CDemoItem &Other) { return !str_comp(m_aFilename, "..") ? true : !str_comp(Other.m_aFilename, "..") ? false :
bool operator<(const CDemoItem &Other)
{
if (g_Config.m_BrDemoSort)
{
if (g_Config.m_BrDemoSortOrder)
{
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; }
m_Date < Other.m_Date;
}
else
{
return !str_comp(m_aFilename, "..") ? true : !str_comp(Other.m_aFilename, "..") ? false :
m_IsDir && !Other.m_IsDir ? true : !m_IsDir && Other.m_IsDir ? false :
m_Date > Other.m_Date;
}
}
else
{
if (g_Config.m_BrDemoSortOrder)
{
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;
}
else
{
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;
@ -174,7 +205,7 @@ class CMenus : public CComponent
void DemolistOnUpdate(bool Reset);
//void DemolistPopulate();
static int DemolistFetchCallback(const char *pName, int IsDir, int StorageType, void *pUser);
static int DemolistFetchCallback(const char *pName, time_t Date, int IsDir, int StorageType, void *pUser);
// friends
struct CFriendItem

View file

@ -644,7 +644,7 @@ int CMenus::UiDoListboxEnd(float *pScrollValue, bool *pItemActivated)
return gs_ListBoxNewSelected;
}
int CMenus::DemolistFetchCallback(const char *pName, int IsDir, int StorageType, void *pUser)
int CMenus::DemolistFetchCallback(const char *pName, time_t Date, int IsDir, int StorageType, void *pUser)
{
CMenus *pSelf = (CMenus *)pUser;
int Length = str_length(pName);
@ -664,6 +664,7 @@ int CMenus::DemolistFetchCallback(const char *pName, int IsDir, int StorageType,
{
str_copy(Item.m_aName, pName, min(static_cast<int>(sizeof(Item.m_aName)), Length-4));
Item.m_InfosLoaded = false;
Item.m_Date = Date;
}
Item.m_IsDir = IsDir != 0;
Item.m_StorageType = StorageType;
@ -677,12 +678,34 @@ void CMenus::DemolistPopulate()
m_lDemos.clear();
if(!str_comp(m_aCurrentDemoFolder, "demos"))
m_DemolistStorageType = IStorage::TYPE_ALL;
Storage()->ListDirectory(m_DemolistStorageType, m_aCurrentDemoFolder, DemolistFetchCallback, this);
Storage()->ListDirectoryInfo(m_DemolistStorageType, m_aCurrentDemoFolder, DemolistFetchCallback, this);
m_lDemos.sort_range();
}
void CMenus::DemolistOnUpdate(bool Reset)
{
if (Reset)
g_Config.m_UiDemoSelected[0] = '\0';
else
{
bool Found = false;
int SelectedIndex = -1;
// search for selected index
for(sorted_array<CDemoItem>::range r = m_lDemos.all(); !r.empty(); r.pop_front())
{
SelectedIndex++;
if (str_comp(g_Config.m_UiDemoSelected, r.front().m_aName) == 0)
{
Found = true;
break;
}
}
if (Found)
m_DemolistSelectedIndex = SelectedIndex;
}
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;
@ -807,6 +830,7 @@ void CMenus::RenderDemoList(CUIRect MainView)
UI()->DoLabelScaled(&Right, m_lDemos[m_DemolistSelectedIndex].m_Info.m_aNetversion, 14.0f, -1);
}
// demo list
CUIRect Headers;
@ -827,19 +851,20 @@ void CMenus::RenderDemoList(CUIRect MainView)
enum
{
COL_DEMONAME=0,
COL_ICON=0,
COL_DEMONAME,
COL_DATE,
SORT_DEMONAME,
SORT_DEMONAME=0,
SORT_DATE,
};
static CColumn s_aCols[] = {
{COL_ICON, -1, " ", -1, 14.0f, 0, {0}, {0}},
{COL_DEMONAME, SORT_DEMONAME, "Demo", 0, 0.0f, 0, {0}, {0}},
{COL_DATE, SORT_DATE, "Date", 1, 300.0f, 0, {0}, {0}}
{COL_DATE, SORT_DATE, "Date", 1, 150.0f, 0, {0}, {0}},
};
RenderTools()->DrawUIRect(&Headers, vec4(0.0f,0,0,0.15f), 0, 0);
int NumCols = sizeof(s_aCols)/sizeof(CColumn);
@ -877,34 +902,66 @@ void CMenus::RenderDemoList(CUIRect MainView)
// do headers
for(int i = 0; i < NumCols; i++)
{
if(DoButton_GridHeader(s_aCols[i].m_Caption, s_aCols[i].m_Caption, g_Config.m_BrSort == s_aCols[i].m_Sort, &s_aCols[i].m_Rect))
if(DoButton_GridHeader(s_aCols[i].m_Caption, s_aCols[i].m_Caption, g_Config.m_BrDemoSort == s_aCols[i].m_Sort, &s_aCols[i].m_Rect))
{
if(s_aCols[i].m_Sort != -1)
{
if(g_Config.m_BrSort == s_aCols[i].m_Sort)
g_Config.m_BrSortOrder ^= 1;
if(g_Config.m_BrDemoSort == s_aCols[i].m_Sort)
g_Config.m_BrDemoSortOrder ^= 1;
else
g_Config.m_BrSortOrder = 0;
g_Config.m_BrSort = s_aCols[i].m_Sort;
g_Config.m_BrDemoSortOrder = 0;
g_Config.m_BrDemoSort = s_aCols[i].m_Sort;
}
DemolistPopulate();
DemolistOnUpdate(false);
}
}
// scrollbar
CUIRect Scroll;
#if defined(__ANDROID__)
ListBox.VSplitRight(50, &ListBox, &Scroll);
#else
ListBox.VSplitRight(15, &ListBox, &Scroll);
#endif
int Num = (int)(ListBox.h/s_aCols[0].m_Rect.h) + 1;
static int s_ScrollBar = 0;
static float s_ScrollValue = 0;
Scroll.HMargin(5.0f, &Scroll);
s_ScrollValue = DoScrollbarV(&s_ScrollBar, &Scroll, s_ScrollValue);
int ScrollNum = m_lDemos.size()-Num+1;
if(ScrollNum > 0)
{
if(m_ScrollOffset)
{
s_ScrollValue = (float)(m_ScrollOffset)/ScrollNum;
m_ScrollOffset = 0;
}
if(Input()->KeyPresses(KEY_MOUSE_WHEEL_UP) && UI()->MouseInside(&ListBox))
s_ScrollValue -= 3.0f/ScrollNum;
if(Input()->KeyPresses(KEY_MOUSE_WHEEL_DOWN) && UI()->MouseInside(&ListBox))
s_ScrollValue += 3.0f/ScrollNum;
}
else
ScrollNum = 0;
if(s_ScrollValue < 0) s_ScrollValue = 0;
if(s_ScrollValue > 1) s_ScrollValue = 1;
// set clipping
UI()->ClipEnable(&ListBox);
CUIRect OriginalView = ListBox;
ListBox.y -= s_ScrollValue*ScrollNum*s_aCols[0].m_Rect.h;
int NewSelected = -1;
int ItemIndex = -1;
for(sorted_array<CDemoItem>::range r = m_lDemos.all(); !r.empty(); r.pop_front())
/*{
CListboxItem Item = UiDoListboxNextItem((void*)(&r.front()));
if(Item.m_Visible)
{
Item.m_Rect.VSplitLeft(Item.m_Rect.h, &FileIcon, &Item.m_Rect);
Item.m_Rect.VSplitLeft(5.0f, 0, &Item.m_Rect);
DoButton_Icon(IMAGE_FILEICONS, r.front().m_IsDir?SPRITE_FILE_FOLDER:SPRITE_FILE_DEMO1, &FileIcon);
UI()->DoLabel(&Item.m_Rect, r.front().m_aName, Item.m_Rect.h*ms_FontmodHeight, -1);
}
}*/
{
ItemIndex++;
@ -914,7 +971,7 @@ void CMenus::RenderDemoList(CUIRect MainView)
ListBox.HSplitTop(ms_ListheaderHeight, &Row, &ListBox);
SelectHitBox = Row;
int Selected = str_comp(g_Config.m_UiDemoSelected, r.front().m_aName) == 0;
int Selected = ItemIndex == m_DemolistSelectedIndex;
// make sure that only those in view can be selected
if(Row.y+Row.h > OriginalView.y && Row.y < OriginalView.y+OriginalView.h)
@ -939,19 +996,17 @@ void CMenus::RenderDemoList(CUIRect MainView)
{
NewSelected = ItemIndex;
str_copy(g_Config.m_UiDemoSelected, r.front().m_aName, sizeof(g_Config.m_UiDemoSelected));
DemolistOnUpdate(false);
#if defined(__ANDROID__)
if(NewSelected == m_DoubleClickIndex)
DoubleClicked = 1;
#endif
m_DoubleClickIndex = NewSelected;
}
}
else
{
// reset active item, if not visible
//if(UI()->ActiveItem() == pItem)
// UI()->SetActiveItem(0);
// don't render invisible items
continue;
}
@ -967,7 +1022,11 @@ void CMenus::RenderDemoList(CUIRect MainView)
int ID = s_aCols[c].m_ID;
if(ID == COL_DEMONAME)
if (ID == COL_ICON)
{
DoButton_Icon(IMAGE_FILEICONS, r.front().m_IsDir?SPRITE_FILE_FOLDER:SPRITE_FILE_DEMO1, &Button);
}
else if(ID == COL_DEMONAME)
{
CTextCursor Cursor;
TextRender()->SetCursor(&Cursor, Button.x, Button.y, 12.0f * UI()->Scale(), TEXTFLAG_RENDER|TEXTFLAG_STOP_AT_END);
@ -976,46 +1035,29 @@ void CMenus::RenderDemoList(CUIRect MainView)
TextRender()->TextEx(&Cursor, r.front().m_aName, -1);
}
else if (ID == COL_DATE)
else if (ID == COL_DATE && !r.front().m_IsDir)
{
CTextCursor Cursor;
TextRender()->SetCursor(&Cursor, Button.x, Button.y, 12.0f * UI()->Scale(), TEXTFLAG_RENDER|TEXTFLAG_STOP_AT_END);
Cursor.m_LineWidth = Button.w;
TextRender()->TextEx(&Cursor, "somedate", -1);
char aBuf[256];
str_timestamp_ex(r.front().m_Date, aBuf, sizeof(aBuf), "%Y-%m-%d %H:%M:%S");
TextRender()->TextEx(&Cursor, aBuf, -1);
}
}
}
/* CUIRect Scroll;
#if defined(__ANDROID__)
View.VSplitRight(50, &View, &Scroll);
#else
View.VSplitRight(15, &View, &Scroll);
#endif*/
UI()->ClipDisable();
/*static int s_DemoListId = 0;
static float s_ScrollValue = 0;
#if defined(__ANDROID__)
UiDoListboxStart(&s_DemoListId, &ListBox, 50.0f, Localize("Demos"), aFooterLabel, m_lDemos.size(), 1, m_DemolistSelectedIndex, s_ScrollValue);
#else
UiDoListboxStart(&s_DemoListId, &ListBox, 17.0f, Localize("Demos"), aFooterLabel, m_lDemos.size(), 1, m_DemolistSelectedIndex, s_ScrollValue);
#endif
for(sorted_array<CDemoItem>::range r = m_lDemos.all(); !r.empty(); r.pop_front())
{
CListboxItem Item = UiDoListboxNextItem((void*)(&r.front()));
if(Item.m_Visible)
{
Item.m_Rect.VSplitLeft(Item.m_Rect.h, &FileIcon, &Item.m_Rect);
Item.m_Rect.VSplitLeft(5.0f, 0, &Item.m_Rect);
DoButton_Icon(IMAGE_FILEICONS, r.front().m_IsDir?SPRITE_FILE_FOLDER:SPRITE_FILE_DEMO1, &FileIcon);
UI()->DoLabel(&Item.m_Rect, r.front().m_aName, Item.m_Rect.h*ms_FontmodHeight, -1);
}
}*/
bool Activated = false;
/*m_DemolistSelectedIndex = UiDoListboxEnd(&s_ScrollValue, &Activated);
DemolistOnUpdate(false);*/
if (m_EnterPressed || (Input()->MouseDoubleClick() && UI()->ActiveItem() == m_lDemos[m_DemolistSelectedIndex].m_aName))
{
UI()->SetActiveItem(0);
Activated = true;
}
static int s_RefreshButton = 0;
if(DoButton_Menu(&s_RefreshButton, Localize("Refresh"), 0, &RefreshRect))