|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Announcements
Chapters
Services
Feature Zones
|
IntroductionThe This article shows how to customize the folder list. Here, on a whim, I made it show only those folders that have an "L" in their names, and hides the "All Folder" and "Add/Remove Folder" options. More seriously, for an app that always saves documents on SD card, you could limit it to showing SD-card folders. Or remove the silly 'Templates' and 'Annotations' folders from the list. BackgroundThe Second, if there is a folder of the same name in more than one location (e.g. \My Documents\Lu as well as Storage Card\Lu) then the drop-down folder list will merge the two together. But if one happens to be written with different capitalization, then they two are merged for selection purposes but are left unmerged for display purposes. PreliminariesThis code uses the Standard Template Library (STL). Everyone should use the STL. Download the STL, ported to eVC++ by Giuseppe Govi. Unzip it into a subdirectory called stl_eVC of your project. Next, under Project > Settings > Compiler > Preprocessor, add the directory stl_eVC to the list of search paths. The following shows which libraries to include. I have disabled warning 4018 within the STL, because it is spurious. Also, under Project > Settings > Linker > Input, link with doclist.lib and note_prj.lib. The first is for the #include <windows.h> #include <doclist.h> #include <projects.h> #pragma warning( push ) #pragma warning( disable: 4018 ) #include <string> #include <list> #pragma warning( pop ) using namespace std; HINSTANCE hInstance; HWND hdlc=0; The global variable Building a fake folder-listThe first problem is, although we can manipulate the // BuildProjectsList -- the goal here is to to build exactly // the same list as the DocList will build. (We also // annotate it to say whether each entry is valid, according // to our criteria). struct TProjectInfo { wstring fn; bool valid; int id; bool operator<(const TProjectInfo &b) const { return _wcsicmp(fn.c_str(),b.fn.c_str())<0; } }; list<TProjectInfo> dlcprojects; The global variable The following function populates the list. (It also returns the name of a valid entry in the list.) wstring BuildProjectsList()
{ wstring validfn;
dlcprojects.clear();
EnumProjectsEx(EnumCallback,0,PRJ_ENUM_ALL_DEVICES,0);
dlcprojects.sort();
// The DocList's drop-down has some extra items:
TProjectInfo pi; pi.valid=false;
pi.fn=L"All Folders"; dlcprojects.push_front(pi);
pi.fn=L"---"; dlcprojects.push_back(pi);
pi.fn=L"Add/Delete..."; dlcprojects.push_back(pi);
// Now we "unique" the list: if a folder exists in My Doc-
// uments and also in a flash card, we only show it once.
// This is in accordance with the behaviour of DocList.
for (list<TProjectInfo>::iterator i=dlcprojects.begin();
i!=dlcprojects.end(); i++)
{ list<TProjectInfo>::iterator j=i; j++;
while (j!=dlcprojects.end() && (*i).fn==(*j).fn)
{ if ((*j).valid && !(*i).valid) *i=*j;
j=dlcprojects.erase(j);
}
if (validfn==L"" && (*i).valid) validfn=(*i).fn;
}
return validfn;
}
Note the function BOOL CALLBACK EnumCallback(PAstruct *pa, LPARAM lp)
{ wchar_t *fn;
if (pa->m_IDtype!=FILE_ID_TYPE_OID) fn=pa->m_szPathname;
else
{ CEOIDINFO cinf; CeOidGetInfo(pa->m_fileOID,&cinf);
fn = cinf.infDirectory.szDirName;
}
TProjectInfo pi;
// Get the "display-name" (ie. without the path)
wchar_t *c=fn, *lastslash=c;
while (*c!=0) {if (*c=='\\') lastslash=c+1; c++;}
pi.fn = lastslash;
// and our arbitrary 'validity' criterion:
pi.valid = (wcschr(lastslash,'l')!=0);
pi.valid |= (wcschr(lastslash,'L')!=0);
dlcprojects.push_back(pi);
return TRUE;
}
Subclassing the DocListNext, we will subclass the WNDPROC OldDLCProc=0;
LRESULT CALLBACK NewDLCProc(HWND hs,UINT msg,
WPARAM wParam,LPARAM lParam)
{ if (msg==WM_INITMENUPOPUP)
{ BuildProjectsList(); // just to be sure we're fresh
// We will correlate menu-item IDs with 'dlcprojects'
LRESULT ret = CallWindowProc(OldDLCProc,hs,msg,
wParam,lParam);
HMENU hm = (HMENU)wParam; wstring ws;
list<TProjectInfo>::iterator it=dlcprojects.begin();
for (unsigned int pos=0; ; pos++,it++)
{ MENUITEMINFO minf; ZeroMemory(&minf,sizeof(minf));
minf.cbSize=sizeof(minf); minf.fMask=MIIM_ID;
BOOL res=GetMenuItemInfo(hm,pos,TRUE,&minf);
if (!res) break;
(*it).id=minf.wID;
}
return ret;
}
else if (msg==WM_MEASUREITEM)
{ MEASUREITEMSTRUCT *ms=(MEASUREITEMSTRUCT*)lParam;
bool valid=false;
for (list<TProjectInfo>::const_iterator i=
dlcprojects.begin(); i!=dlcprojects.end(); i++)
{ if ((*i).id==(int)ms->itemID) valid=(*i).valid;
}
LONG ret = CallWindowProc(OldDLCProc,hs,msg,
wParam,lParam);
if (!valid) {ms->itemWidth=1; ms->itemHeight=0;}
return ret;
}
return CallWindowProc(OldDLCProc,hs,msg,wParam,lParam);
}
And the following is how to install the subclass, in response to case WM_CREATE: { wstring initf=BuildProjectsList(); DOCLISTCREATE dlc; ZeroMemory(&dlc,sizeof(dlc)); dlc.dwStructSize=sizeof(dlc); dlc.hwndParent=hwnd; dlc.pszFolder = initf.c_str(); dlc.pstrFilter = L"All files\0*.*\0Text\0*.pwd;*.txt\0"; dlc.wId=102; hdlc = DocList_Create(&dlc); OldDLCProc=(WNDPROC)SetWindowLong(hdlc,GWL_WNDPROC, (LONG)NewDLCProc); RECT rc; GetClientRect(hwnd,&rc); MoveWindow(hdlc,0,0,rc.right,rc.bottom,false); DocList_Refresh(hdlc);
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||