folderbrowser.cpp 65 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271
  1. #include "./folderbrowser.h"
  2. #include "./folderbrowser_internal.h"
  3. #include "./stringvector.h"
  4. #include <vector>
  5. #include "../Winamp/wa_dlg.h"
  6. #include "./skinnedlistbox.h"
  7. #include "./colors.h"
  8. #include <windowsx.h>
  9. #include <strsafe.h>
  10. static LRESULT CALLBACK FolderBrowser_WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
  11. typedef struct _FBITEM
  12. {
  13. INT index;
  14. DWORD styles;
  15. } FBITEM;
  16. typedef struct _FBCOLUMN
  17. {
  18. INT bufferOffset;
  19. INT count;
  20. INT firstVisible;
  21. INT firstSelected;
  22. INT width;
  23. BOOL autoAdjust;
  24. FBITEM *pItems;
  25. } FBCOLUMN;
  26. typedef struct _FBDATA
  27. {
  28. COLORREF rgbBk;
  29. COLORREF rgbText;
  30. std::vector<FBCOLUMN> *pColumns;
  31. StringVector *pBuffer;
  32. HWND hwndDraw;
  33. HWND hwndActive;
  34. LPWSTR pszRoot;
  35. int focusedColumn;
  36. // filesystem
  37. FILESYSTEMINFO filesystem;
  38. } FBDATA;
  39. static int clickoffs = 0;
  40. static size_t hiddenActive = -1;
  41. static size_t sizerActive = -1;
  42. static size_t sizerHover = -1;
  43. #define GetFolderBrowser(__hwnd) ((FBDATA*)(LONG_PTR)(LONGX86)GetWindowLongPtrW((__hwnd), 0))
  44. BOOL RegisterFolderBrowserControl(HINSTANCE hInstance)
  45. {
  46. WNDCLASSW wc;
  47. if (GetClassInfoW(hInstance, FOLDERBROWSER_NAME, &wc)) return TRUE;
  48. ZeroMemory(&wc, sizeof(WNDCLASSW));
  49. wc.hInstance = hInstance;
  50. wc.lpszClassName = FOLDERBROWSER_NAME;
  51. wc.lpfnWndProc = FolderBrowser_WindowProc;
  52. wc.style = CS_DBLCLKS | CS_GLOBALCLASS;
  53. wc.hCursor = LoadCursor(NULL, IDC_ARROW);
  54. wc.hbrBackground = NULL;
  55. wc.cbWndExtra = sizeof(FBDATA*);
  56. return ( 0 != RegisterClassW(&wc));
  57. }
  58. BOOL FolderBrowser_CustomizeListBox(HWND hwndListbox);
  59. __inline size_t FolderBrowser_GetListBoxColumn(HWND hwndList)
  60. {
  61. SetLastError(0);
  62. size_t c = (size_t)GetWindowLongPtrW(hwndList, GWLP_USERDATA);
  63. return (ERROR_SUCCESS == GetLastError()) ? c : ((size_t)-1);
  64. }
  65. static BOOL FolderBrowser_GetAdjustedClientRect(HWND hwnd, RECT *prc)
  66. {
  67. if (!GetClientRect(hwnd, prc))
  68. return FALSE;
  69. SCROLLINFO si;
  70. si.cbSize = sizeof(SCROLLINFO);
  71. si.fMask = SIF_POS;
  72. if (!GetScrollInfo(hwnd, SB_HORZ, &si)) ZeroMemory(&si, sizeof(SCROLLINFO));
  73. prc->left -= si.nPos;
  74. return TRUE;
  75. }
  76. static BOOL PrepareDrawingListBox(HWND hwndList, FBCOLUMN *pc, LONG height, size_t columnId)
  77. {
  78. if (-1 != columnId && columnId == (size_t)GetWindowLongPtrW(hwndList, GWLP_USERDATA))
  79. return TRUE;
  80. SetWindowLongPtrW(hwndList, GWLP_USERDATA, (LONGX86)columnId);
  81. SetWindowPos(hwndList, NULL, 0, 0, pc->width, height,
  82. SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOMOVE | SWP_NOREDRAW | SWP_NOSENDCHANGING);
  83. if (pc->count)
  84. {
  85. SendMessageW(hwndList, LB_SETCOUNT, pc->count, 0L);
  86. SendMessageW(hwndList, LB_SETTOPINDEX, pc->firstVisible, 0L);
  87. }
  88. else
  89. {
  90. SendMessageW(hwndList, LB_SETCOUNT, 1, 0L); // ** Keep this two messages
  91. SendMessageW(hwndList, LB_SETTOPINDEX, 0, 0L); // ** for skinned scrollbars
  92. }
  93. MLSkinnedScrollWnd_UpdateBars(hwndList, FALSE);
  94. return TRUE;
  95. }
  96. static void RefreshListBoxNC(HWND hHost, HWND hList, POINT ptViewport)
  97. {
  98. UINT flags = DCX_PARENTCLIP | DCX_CACHE | DCX_WINDOW | DCX_CLIPSIBLINGS |
  99. DCX_INTERSECTUPDATE | DCX_VALIDATE;
  100. HDC hdc = GetDCEx(hHost, NULL, flags);
  101. if (NULL != hdc)
  102. {
  103. POINT ptOrig;
  104. SetViewportOrgEx(hdc, ptViewport.x, ptViewport.y, &ptOrig);
  105. SendMessageW(hList, WM_PRINT, (WPARAM)hdc, (LPARAM)PRF_NONCLIENT);
  106. SetViewportOrgEx(hdc, ptOrig.x, ptOrig.y, NULL);
  107. ReleaseDC(hHost, hdc);
  108. }
  109. }
  110. static void FolderBrowser_UpdateScrollInfo(HWND hwnd)
  111. {
  112. RECT rc;
  113. FBDATA *pfb = GetFolderBrowser(hwnd);
  114. if (!pfb) return;
  115. GetClientRect(hwnd, &rc);
  116. LONG totalWidth = 0;
  117. for(size_t i = 0; i < pfb->pColumns->size(); i++)
  118. {
  119. totalWidth += (pfb->pColumns->at(i).width + SIZER_WIDTH);
  120. }
  121. SCROLLINFO si;
  122. si.cbSize = sizeof(SCROLLINFO);
  123. si.fMask = SIF_RANGE | SIF_PAGE | SIF_POS;
  124. if (GetScrollInfo(hwnd, SB_HORZ, &si) && si.nMax != totalWidth)
  125. {
  126. INT dx = 0;
  127. si.fMask = SIF_RANGE | SIF_DISABLENOSCROLL;
  128. si.nMin = 0;
  129. si.nMax = totalWidth;
  130. if (si.nPage != rc.right - rc.left)
  131. {
  132. si.nPage = rc.right - rc.left;
  133. si.fMask |= SIF_PAGE;
  134. }
  135. if ((si.nPos + si.nPage) > (UINT)si.nMax && si.nPos > si.nMin) si.nMax = si.nPos + si.nPage;
  136. SetScrollInfo(hwnd, SB_HORZ, &si, FALSE);
  137. RECT rw;
  138. if (dx && pfb->hwndActive &&
  139. (WS_VISIBLE & GetWindowLongPtrW(pfb->hwndActive, GWL_STYLE))
  140. && GetWindowRect(pfb->hwndActive, &rw))
  141. {
  142. MapWindowPoints(HWND_DESKTOP, hwnd, (POINT*)&rw, 2);
  143. SetWindowPos(pfb->hwndActive, NULL, rw.left + dx, rw.top, 0, 0,
  144. SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOSENDCHANGING | SWP_NOSIZE);
  145. }
  146. }
  147. }
  148. static INT FolderBrowser_GetPreferredColumnWidth(HWND hwnd, size_t columnIndex)
  149. {
  150. FBCOLUMN *pc;
  151. INT nameWidth = 0, prevMaxLen = 0;
  152. HDC hdc;
  153. HFONT hf, hfo = NULL;
  154. SIZE size;
  155. size_t count;
  156. FBDATA *pfb = GetFolderBrowser(hwnd);
  157. if (!pfb) return -1;
  158. if (columnIndex >= pfb->pColumns->size()) return -1;
  159. pc = &pfb->pColumns->at(columnIndex);
  160. count = pc->bufferOffset + pc->count;
  161. if (count > pfb->pBuffer->Count()) count = pfb->pBuffer->Count();
  162. hdc = GetDCEx(hwnd, NULL, DCX_CACHE);
  163. if (!hdc) return -1;
  164. hf = (HFONT)SendMessageW((pfb->hwndDraw) ? pfb->hwndDraw : hwnd, WM_GETFONT, 0, 0L);
  165. if (NULL == hf) hf = (HFONT)MlStockObjects_Get(DEFAULT_FONT);
  166. if (NULL != hf) hfo = (HFONT)SelectObject(hdc, hf);
  167. for (size_t i = pc->bufferOffset; i < count; i++)
  168. {
  169. LPCWSTR pszText = pfb->pBuffer->GetString(i);
  170. INT len = (pszText) ? lstrlenW(pszText) : 0;
  171. if (len > 0 && len > (prevMaxLen - 3) &&
  172. hdc && GetTextExtentPoint32W(hdc, pszText, len, &size) &&
  173. size.cx > nameWidth)
  174. {
  175. nameWidth = size.cx;
  176. prevMaxLen = len;
  177. }
  178. }
  179. if (NULL != hfo) SelectObject(hdc, hfo);
  180. ReleaseDC(hwnd, hdc);
  181. nameWidth += 20;
  182. if (nameWidth < COLUMN_MIN_WIDTH) nameWidth = COLUMN_MIN_WIDTH;
  183. if (nameWidth > COLUMN_MAX_WIDTH) nameWidth = COLUMN_MAX_WIDTH;
  184. return nameWidth;
  185. }
  186. static StringVector *g_pCompareBuffer = NULL;
  187. static INT g_szCompareOffset = 0;
  188. static INT __cdecl FolderBrowser_CompareFolderNames(const void *elem1, const void *elem2)
  189. {
  190. return (CompareStringW(LOCALE_USER_DEFAULT, NORM_IGNORECASE,
  191. g_pCompareBuffer->GetString(g_szCompareOffset + ((FBITEM*)elem1)->index), -1,
  192. g_pCompareBuffer->GetString(g_szCompareOffset + ((FBITEM*)elem2)->index), -1) - 2);
  193. }
  194. static void FolderBrowser_SortColumn(HWND hwnd, size_t columnIndex)
  195. {
  196. FBDATA *pfb = GetFolderBrowser(hwnd);
  197. if (!pfb || columnIndex >= pfb->pColumns->size()) return;
  198. FBCOLUMN *pc = &pfb->pColumns->at(columnIndex);
  199. if (pc->count == 0 || !pc->pItems) return;
  200. g_pCompareBuffer = pfb->pBuffer;
  201. g_szCompareOffset = pc->bufferOffset;
  202. qsort(pc->pItems, pc->count, sizeof(FBITEM), FolderBrowser_CompareFolderNames);
  203. g_pCompareBuffer = NULL;
  204. }
  205. typedef struct _FINDKEY
  206. {
  207. LPCWSTR pszKey;
  208. INT cchKey;
  209. FBCOLUMN *pCol;
  210. INT foundIndex;
  211. StringVector *pBuffer;
  212. } FINDKEY;
  213. static INT __cdecl FolderBrowser_FindKey(const void *key, const void *elem)
  214. {
  215. FINDKEY *pfk = (FINDKEY*)key;
  216. LPCWSTR pszTest = pfk->pBuffer->GetString(pfk->pCol->bufferOffset + ((FBITEM*)elem)->index);
  217. return (CompareStringW(LOCALE_USER_DEFAULT, NORM_IGNORECASE, pfk->pszKey, pfk->cchKey,
  218. pfk->pBuffer->GetString(pfk->pCol->bufferOffset + ((FBITEM*)elem)->index), -1) - 2);
  219. }
  220. static INT FoderBrowser_FindFolder(StringVector *pBuffer, FBCOLUMN *pColumn, LPCWSTR pszFolder, INT cchFolder)
  221. {
  222. FINDKEY fk;
  223. fk.pCol = pColumn;
  224. fk.pszKey = pszFolder;
  225. fk.cchKey = cchFolder;
  226. fk.pBuffer = pBuffer;
  227. if (!pBuffer || !pszFolder) return -1;
  228. FBITEM *pi = (FBITEM*)bsearch(&fk, pColumn->pItems, pColumn->count, sizeof(FBITEM), FolderBrowser_FindKey);
  229. if (!pi) return -1;
  230. return (INT)(pi - pColumn->pItems);
  231. }
  232. static INT FolderBrowser_AddColumn(HWND hwnd, LPCWSTR pszPath, INT cchPath, INT width, BOOL bAutoAdjust)
  233. {
  234. HANDLE hFile;
  235. WIN32_FIND_DATAW fd = {0};
  236. wchar_t szSearch[2 * MAX_PATH + 4] = {0};
  237. FBDATA *pfb = GetFolderBrowser(hwnd);
  238. if (!pfb || !pszPath) return -1;
  239. if (cchPath < 0) cchPath = lstrlenW(pszPath);
  240. if (S_OK != StringCchCopyNW(szSearch, sizeof(szSearch)/sizeof(szSearch[0]), pszPath, cchPath) ||
  241. S_OK != StringCchCatW(szSearch, sizeof(szSearch)/sizeof(szSearch[0]), L"\\*")) return -1;
  242. FBCOLUMN col;
  243. ZeroMemory(&col, sizeof(FBCOLUMN));
  244. col.bufferOffset = (INT)pfb->pBuffer->Count();
  245. col.firstSelected = -1;
  246. col.width = width;
  247. col.autoAdjust = bAutoAdjust;
  248. DWORD ws = GetWindowLongPtrW(hwnd, GWL_STYLE);
  249. hFile = pfb->filesystem.fnFindFirstFile(szSearch, &fd);
  250. if (INVALID_HANDLE_VALUE != hFile)
  251. {
  252. do
  253. {
  254. if (0 != (FILE_ATTRIBUTE_DIRECTORY & fd.dwFileAttributes) &&
  255. (0 == (FBS_IGNOREHIDDEN & ws) || 0 == (FILE_ATTRIBUTE_HIDDEN & fd.dwFileAttributes)) &&
  256. (0 == (FBS_IGNORESYSTEM & ws) || 0 == (FILE_ATTRIBUTE_SYSTEM & fd.dwFileAttributes)) &&
  257. !(L'.' == fd.cFileName[0] && (L'\0' == fd.cFileName[1] || (L'.' == fd.cFileName[1] && L'\0' == fd.cFileName[2]))))
  258. {
  259. pfb->pBuffer->Add(fd.cFileName);
  260. col.count++;
  261. }
  262. } while (pfb->filesystem.fnFindNextFile(hFile, &fd));
  263. pfb->filesystem.fnFindClose(hFile);
  264. }
  265. pfb->pColumns->push_back(col);
  266. if (pfb->pColumns->size() > 0)
  267. {
  268. FBCOLUMN *pc = &pfb->pColumns->back();
  269. if (pc->autoAdjust)
  270. {
  271. width = FolderBrowser_GetPreferredColumnWidth(hwnd, pfb->pColumns->size() - 1);
  272. if (width < COLUMN_DEFAULT_WIDTH) width = COLUMN_DEFAULT_WIDTH;
  273. }
  274. else if (-1 == width) width = COLUMN_DEFAULT_WIDTH;
  275. pc->width = width;
  276. if (pc->count)
  277. {
  278. FBITEM *pi = (FBITEM*)calloc(pc->count, sizeof(FBITEM));
  279. if (pi)
  280. {
  281. for (INT i = 0; i < pc->count; i++)
  282. {
  283. pi[i].index = i;
  284. pi[i].styles = 0;
  285. }
  286. pc->pItems = pi;
  287. }
  288. }
  289. FolderBrowser_SortColumn(hwnd, pfb->pColumns->size() - 1);
  290. }
  291. return col.count;
  292. }
  293. static INT FolderBrowser_CalculateListItemHeight(HWND hwndList)
  294. {
  295. HFONT hf, hfo;
  296. TEXTMETRIC tm;
  297. HDC hdc = GetDCEx(hwndList, NULL, DCX_CACHE);
  298. if (!hdc) return 20;
  299. hf = (HFONT)SendMessageW(hwndList, WM_GETFONT, 0, 0L);
  300. if (NULL == hf) hf = (HFONT)MlStockObjects_Get(DEFAULT_FONT);
  301. hfo = (NULL != hf) ? (HFONT)SelectObject(hdc, hf) : NULL;
  302. if (!GetTextMetrics(hdc, &tm)) tm.tmHeight = 20;
  303. if (hfo) SelectObject(hdc, hfo);
  304. ReleaseDC(hwndList, hdc);
  305. return tm.tmHeight + 2;
  306. }
  307. static INT FolderBrowser_OnGetCurrentPath(HWND hwnd, LPWSTR pszPath, INT cchMax)
  308. {
  309. HRESULT hr;
  310. FBCOLUMN *pc;
  311. if (!pszPath || cchMax < 1) return 0;
  312. pszPath[0] = L'\0';
  313. FBDATA *pfb = GetFolderBrowser(hwnd);
  314. if (!pfb || !pfb->pszRoot) return 0;
  315. size_t r = cchMax;
  316. for(size_t i = 0; i < pfb->pColumns->size(); i++)
  317. {
  318. pc = &pfb->pColumns->at(i);
  319. if (-1 == pc->firstSelected) break;
  320. size_t textIndex = pc->firstSelected;
  321. if (pc->pItems && textIndex < (size_t)pc->count) textIndex = pc->pItems[textIndex].index;
  322. textIndex += pc->bufferOffset;
  323. LPCWSTR pszText = (textIndex < pfb->pBuffer->Count()) ? pfb->pBuffer->GetString(textIndex) : NULL;
  324. if (!pszText) return 0;
  325. if (r < 2) hr= STRSAFE_E_INSUFFICIENT_BUFFER;
  326. else
  327. {
  328. if (0 != i) { *pszPath = L'\\'; r--; pszPath++; }
  329. hr = StringCchCopyExW(pszPath, r, pszText, &pszPath, &r, STRSAFE_IGNORE_NULLS);
  330. }
  331. if (S_OK != hr) return 0;
  332. }
  333. return (cchMax - (INT)r);
  334. }
  335. static BOOL FolderBrowser_HideActive(HWND hwnd)
  336. {
  337. FBDATA *pfb = GetFolderBrowser(hwnd);
  338. if (!pfb || -1 != hiddenActive ||
  339. 0 == (WS_VISIBLE & GetWindowLongPtrW(pfb->hwndActive, GWL_STYLE))) return FALSE;
  340. hiddenActive = FolderBrowser_GetListBoxColumn(pfb->hwndActive);
  341. if (hiddenActive < pfb->pColumns->size())
  342. {
  343. FBCOLUMN *pc = &pfb->pColumns->at(hiddenActive);
  344. if (pc) pc->firstVisible = (INT)SendMessageW(pfb->hwndActive, LB_GETTOPINDEX, 0, 0L);
  345. if (pfb->focusedColumn == hiddenActive) SetFocus(hwnd);
  346. SetWindowLongPtrW(pfb->hwndActive, GWLP_USERDATA, (LONGX86)-1);
  347. ShowWindow(pfb->hwndActive, SW_HIDE);
  348. }
  349. return TRUE;
  350. }
  351. static BOOL FolderBrowser_RestoreActive(HWND hwnd)
  352. {
  353. FBDATA *pfb = GetFolderBrowser(hwnd);
  354. if (!pfb || -1 == hiddenActive) return FALSE;
  355. if (hiddenActive >= pfb->pColumns->size())
  356. {
  357. hiddenActive = -1;
  358. return FALSE;
  359. }
  360. RECT rw;
  361. GetWindowRect(pfb->hwndActive, &rw);
  362. MapWindowPoints(HWND_DESKTOP, hwnd, (POINT*)&rw, 2);
  363. SetWindowLongPtrW(pfb->hwndActive, GWLP_USERDATA, (LONGX86)hiddenActive);
  364. SCROLLINFO si;
  365. si.cbSize = sizeof(SCROLLINFO);
  366. si.fMask = SIF_POS;
  367. if(!GetScrollInfo(hwnd, SB_HORZ, &si)) si.nPos = 0;
  368. LONG left = -si.nPos;
  369. for (size_t i=0; i < hiddenActive; i++) left += (pfb->pColumns->at(i).width + SIZER_WIDTH);
  370. LONG width = pfb->pColumns->at(hiddenActive).width;
  371. if (left != rw.left || width != (rw.right - rw.left))
  372. {
  373. SetWindowPos(pfb->hwndActive, NULL, left, rw.top, width, rw.bottom - rw.top,
  374. SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOSENDCHANGING |
  375. ((left == rw.left) ? SWP_NOMOVE : 0) |
  376. ((width == (rw.right - rw.left)) ? SWP_NOSIZE : 0));
  377. }
  378. ShowWindow(pfb->hwndActive, SW_SHOWNA);
  379. if (pfb->focusedColumn == hiddenActive) SetFocus(pfb->hwndActive);
  380. hiddenActive = -1;
  381. return TRUE;
  382. }
  383. static INT FolderBrowser_ScrollWindow(HWND hwnd, INT dx, UINT smoothTime, BOOL bRedraw)
  384. {
  385. SCROLLINFO si;
  386. size_t hiddenActive = -1;
  387. FBDATA *pfb = GetFolderBrowser(hwnd);
  388. if (!pfb) return 0;
  389. si.cbSize = sizeof(SCROLLINFO);
  390. si.fMask = SIF_PAGE | SIF_RANGE | SIF_POS;
  391. if (!GetScrollInfo(hwnd, SB_HORZ, &si)) return 0;
  392. if ((si.nPos + dx) < si.nMin) dx = si.nMin - si.nPos;
  393. else if ((si.nPos + dx) > (si.nMax - (INT)si.nPage))
  394. {
  395. dx = si.nMax - si.nPos - si.nPage;
  396. if (dx < 0) dx = 0;
  397. }
  398. if (dx == 0) return 0;
  399. SendMessageW(hwnd, WM_SETREDRAW, FALSE, 0L);
  400. if (pfb && (WS_VISIBLE & GetWindowLongPtrW(pfb->hwndActive, GWL_STYLE)))
  401. {
  402. hiddenActive = FolderBrowser_GetListBoxColumn(pfb->hwndActive);
  403. if (-1 != hiddenActive)
  404. {
  405. pfb->pColumns->at(hiddenActive).firstVisible = (INT)SendMessageW(pfb->hwndActive, LB_GETTOPINDEX, 0, 0L);
  406. if (pfb->focusedColumn == hiddenActive) SetFocus(hwnd);
  407. SetWindowLongPtrW(pfb->hwndActive, GWLP_USERDATA, (LONGX86)-1);
  408. ShowWindow(pfb->hwndActive, SW_HIDE);
  409. }
  410. }
  411. si.fMask = SIF_POS;
  412. si.nPos += dx;
  413. SetScrollInfo(hwnd, SB_HORZ, &si, FALSE);
  414. if (bRedraw || smoothTime) SendMessageW(hwnd, WM_SETREDRAW, TRUE, 0L);
  415. if (smoothTime) ScrollWindowEx(hwnd, -dx, 0, NULL, NULL, NULL, NULL, MAKELPARAM(SW_SMOOTHSCROLL, 150));
  416. else ScrollWindowEx(hwnd, -dx, 0, NULL, NULL, NULL, NULL, ((bRedraw) ? (SW_INVALIDATE | SW_ERASE) : 0));
  417. if (-1 != hiddenActive)
  418. {
  419. RECT rw;
  420. GetWindowRect(pfb->hwndActive, &rw);
  421. MapWindowPoints(HWND_DESKTOP, hwnd, (POINT*)&rw, 1);
  422. SetWindowLongPtrW(pfb->hwndActive, GWLP_USERDATA, (LONGX86)hiddenActive);
  423. SetWindowPos(pfb->hwndActive, NULL, rw.left - dx, rw.top, 0, 0,
  424. SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOSIZE | SWP_NOSENDCHANGING |
  425. ((bRedraw) ? 0 : SWP_NOREDRAW));
  426. ShowWindow(pfb->hwndActive, SW_SHOWNA);
  427. if (pfb->focusedColumn == hiddenActive) SetFocus(pfb->hwndActive);
  428. }
  429. if (!bRedraw && !smoothTime) SendMessageW(hwnd, WM_SETREDRAW, TRUE, 0L);
  430. return dx;
  431. }
  432. static INT FolderBrowser_OnEnsureVisible(HWND hwnd, size_t column, UINT uFlags)
  433. {
  434. RECT rc;
  435. SCROLLINFO si;
  436. FBDATA *pfb = GetFolderBrowser(hwnd);
  437. if (!pfb) return 0;
  438. LONG left;
  439. FBCOLUMN *pc;
  440. size_t count = pfb->pColumns->size();
  441. if (column >= count) return 0;
  442. si.cbSize = sizeof(SCROLLINFO);
  443. si.fMask = SIF_POS | SIF_RANGE | SIF_PAGE;
  444. if (!GetScrollInfo(hwnd, SB_HORZ, &si) || !GetClientRect(hwnd, &rc)) return 0;
  445. pc = NULL;
  446. left = -si.nPos;
  447. for (size_t i = 0; i < column; i++)
  448. {
  449. pc = &pfb->pColumns->at(i);
  450. left += (pc->width + SIZER_WIDTH);
  451. }
  452. INT dx = 0;
  453. if (left < rc.left)
  454. {
  455. dx = left - rc.left;
  456. if (0 == (EVF_NOEXTRALSPACE & uFlags) && column != 0) dx -= COLUMN_EXTRALSPACE;
  457. }
  458. else
  459. {
  460. LONG ol = left;
  461. if (0 == (EVF_NOEXTRALSPACE & uFlags) && column != 0) ol -= COLUMN_EXTRALSPACE;
  462. left += (pfb->pColumns->at(column).width + SIZER_WIDTH);
  463. if (0 == (EVF_NOEXTRARSPACE & uFlags) && column < (count - 1))
  464. left += (pfb->pColumns->at(column + 1).width + SIZER_WIDTH);
  465. if (left > rc.right) dx = left - rc.right;
  466. if (ol - dx < rc.left)
  467. {
  468. dx = ol - rc.left;
  469. }
  470. if ((INT)si.nPage > si.nMax) si.nPage = si.nMax;
  471. if ((si.nPos + dx) > (si.nMax - (INT)si.nPage))
  472. {
  473. si.nMax = si.nPos + dx + si.nPage;
  474. si.fMask = SIF_RANGE;
  475. SetScrollInfo(hwnd, SB_HORZ, &si, FALSE);
  476. }
  477. }
  478. if (dx == 0) return 0;
  479. return FolderBrowser_ScrollWindow(hwnd, dx, 250, 0 == (EVF_NOREDRAW & uFlags));
  480. }
  481. static INT FolderBrowser_SaveActiveSelection(HWND hwnd)
  482. {
  483. FBCOLUMN *pc;
  484. FBDATA *pfb = GetFolderBrowser(hwnd);
  485. if (!pfb) return -1;
  486. size_t activeColumn = FolderBrowser_GetListBoxColumn(pfb->hwndActive);
  487. if (activeColumn >= pfb->pColumns->size()) return -1;
  488. pc = &pfb->pColumns->at(activeColumn);
  489. if (!pc) return -1;
  490. for (INT i = 0; i < pc->count; i++)
  491. pc->pItems[i].styles &= ~FBIS_SELECTED;
  492. INT count = (INT)SendMessageW(pfb->hwndActive, LB_GETSELCOUNT, 0, 0L);
  493. INT *pSelection = NULL;
  494. if (count > 0)
  495. {
  496. pSelection = (INT*)calloc((count + 1), sizeof(INT));
  497. if (LB_ERR == SendMessageW(pfb->hwndActive, LB_GETSELITEMS, count, (LPARAM)pSelection))
  498. count = 0;
  499. }
  500. for (INT i = 0; i < count; i++)
  501. {
  502. INT k = pSelection[i];
  503. if (k < pc->count && k >= 0)
  504. {
  505. pc->pItems[k].styles |= FBIS_SELECTED;
  506. }
  507. }
  508. INT selectedItem = (1 == count && pSelection) ? pSelection[0] : -1;
  509. if (pSelection) free(pSelection);
  510. return selectedItem;
  511. }
  512. static void FolderBrowser_OnSelectionChanged(HWND hwnd, BOOL bForceUpdate, BOOL bUpdateUI)
  513. {
  514. FBCOLUMN *pc;
  515. INT columnWidth = -1;
  516. BOOL bAutoAdjust = TRUE;
  517. size_t activeColumn, selectedItem;
  518. FBDATA *pfb = GetFolderBrowser(hwnd);
  519. if (!pfb) return;
  520. activeColumn = FolderBrowser_GetListBoxColumn(pfb->hwndActive);
  521. if (activeColumn >= pfb->pColumns->size()) return;
  522. pc = &pfb->pColumns->at(activeColumn);
  523. selectedItem = FolderBrowser_SaveActiveSelection(hwnd);
  524. if (activeColumn < (pfb->pColumns->size() -1))
  525. {
  526. columnWidth = pfb->pColumns->at(activeColumn + 1).width;
  527. bAutoAdjust = pfb->pColumns->at(activeColumn + 1).autoAdjust;
  528. }
  529. pfb->pBuffer->TrimCount(pc->bufferOffset + pc->count);
  530. while (pfb->pColumns->size() > (activeColumn + 1))
  531. {
  532. FBCOLUMN *pctmp = &pfb->pColumns->back();
  533. if (pctmp->pItems)
  534. {
  535. free(pctmp->pItems);
  536. pctmp->pItems = NULL;
  537. }
  538. pfb->pColumns->pop_back();
  539. }
  540. //if (((size_t)-1) != selectedItem)
  541. {
  542. /* if (!bForceUpdate && (size_t)pc->firstSelected == selectedItem)
  543. {
  544. FolderBrowser_OnEnsureVisible(hwnd, activeColumn, 0);
  545. return;
  546. }*/
  547. pc->firstSelected = (INT)selectedItem;
  548. wchar_t szPath[2*MAX_PATH] = {0};
  549. INT cchPath = FolderBrowser_OnGetCurrentPath(hwnd, szPath, sizeof(szPath)/sizeof(szPath[0]));
  550. if (0 != cchPath && ((size_t)-1) != selectedItem) FolderBrowser_AddColumn(hwnd, szPath, cchPath, columnWidth, bAutoAdjust);
  551. }
  552. if (bUpdateUI)
  553. {
  554. RECT rc;
  555. FolderBrowser_GetAdjustedClientRect(hwnd, &rc);
  556. for(size_t i = 0; i <= activeColumn; i++) rc.left += (pfb->pColumns->at(i).width + SIZER_WIDTH);
  557. FolderBrowser_OnEnsureVisible(hwnd, activeColumn, EVF_NOREDRAW);
  558. FolderBrowser_UpdateScrollInfo(hwnd);
  559. InvalidateRect(hwnd, &rc, TRUE);
  560. UpdateWindow(hwnd);
  561. if (pfb->hwndActive) UpdateWindow(pfb->hwndActive);
  562. }
  563. HWND hwndParent = GetParent(hwnd);
  564. if (NULL != hwndParent)
  565. {
  566. NMHDR hdr;
  567. hdr.code = FBN_SELCHANGED;
  568. hdr.hwndFrom = hwnd;
  569. hdr.idFrom = GetDlgCtrlID(hwnd);
  570. SendMessageW(hwndParent, WM_NOTIFY, hdr.idFrom, (LPARAM)&hdr);
  571. }
  572. }
  573. // returns new active column index
  574. static size_t FolderBrowser_UpdateActiveColumn(HWND hwnd, size_t newActiveColumn)
  575. {
  576. FBDATA *pfb = GetFolderBrowser(hwnd);
  577. if (!pfb) return ((size_t)-1);
  578. HRGN rgnInvalid = NULL;
  579. FBCOLUMN *pc;
  580. RECT rc, ri;
  581. size_t activeColumn = FolderBrowser_GetListBoxColumn(pfb->hwndActive);
  582. GetClientRect(hwnd, &rc);
  583. if (newActiveColumn >= pfb->pColumns->size()) newActiveColumn = ((size_t)-1);
  584. if (newActiveColumn == -1 && pfb->focusedColumn != -1)
  585. {
  586. CopyRect(&ri, &rc);
  587. for (size_t i = 0; i <= (size_t)pfb->focusedColumn; i++)
  588. {
  589. pc = &pfb->pColumns->at(i);
  590. if (i < (size_t)pfb->focusedColumn) ri.left += (pc->width + SIZER_WIDTH);
  591. else ri.right = ri.left + (pc->width + SIZER_WIDTH);
  592. }
  593. if (NULL == rgnInvalid) rgnInvalid = CreateRectRgnIndirect(&ri);
  594. }
  595. if (activeColumn == newActiveColumn)
  596. {
  597. if (rgnInvalid)
  598. {
  599. InvalidateRgn(hwnd, rgnInvalid, FALSE);
  600. DeleteObject(rgnInvalid);
  601. UpdateWindow(hwnd);
  602. }
  603. return activeColumn;
  604. }
  605. SetRect(&ri, 0, 0, 0, 0);
  606. if (activeColumn < pfb->pColumns->size())
  607. {
  608. pc = &pfb->pColumns->at(activeColumn);
  609. pc->firstVisible = (INT)SendMessageW(pfb->hwndActive, LB_GETTOPINDEX, 0, 0L);
  610. pc->firstSelected = FolderBrowser_SaveActiveSelection(hwnd);
  611. INT selectedCount = (INT)SendMessageW(pfb->hwndActive, LB_GETSELCOUNT, 0, 0L);
  612. if (-1 == pc->firstSelected && selectedCount > 0)
  613. {
  614. pc->firstSelected = (INT)SendMessageW(pfb->hwndActive, LB_GETANCHORINDEX, 0, 0L);
  615. }
  616. if (selectedCount > 0 || LB_ERR == SendMessageW(pfb->hwndActive, LB_GETITEMRECT, pc->firstSelected, (LPARAM)&ri))
  617. GetClientRect(pfb->hwndActive, &ri);
  618. MapWindowPoints(pfb->hwndActive, hwnd, (POINT*)&ri, 2);
  619. }
  620. if (ri.left != ri.right)
  621. {
  622. if (NULL == rgnInvalid) rgnInvalid = CreateRectRgnIndirect(&ri);
  623. else
  624. {
  625. HRGN rgnTmp = CreateRectRgnIndirect(&ri);
  626. CombineRgn(rgnInvalid, rgnInvalid, rgnTmp, RGN_OR);
  627. DeleteObject(rgnTmp);
  628. }
  629. }
  630. SetWindowLongPtrW(pfb->hwndActive, GWLP_USERDATA, (LONGX86)newActiveColumn);
  631. if ((size_t)-1 == newActiveColumn)
  632. {
  633. pfb->focusedColumn = -1;
  634. if ((WS_VISIBLE & GetWindowLongPtrW(pfb->hwndActive, GWL_STYLE)))
  635. {
  636. SendMessageW(pfb->hwndActive, WM_SETREDRAW, FALSE, 0L);
  637. UpdateWindow(hwnd);
  638. SendMessage(hwnd, WM_SETREDRAW, FALSE, 0L);
  639. ShowWindow(pfb->hwndActive, SW_HIDE);
  640. SendMessage(hwnd, WM_SETREDRAW, TRUE, 0L);
  641. }
  642. }
  643. else
  644. {
  645. SendMessageW(pfb->hwndActive, WM_SETREDRAW, FALSE, 0L);
  646. UpdateWindow(hwnd);
  647. SendMessage(hwnd, WM_SETREDRAW, FALSE, 0L);
  648. for (size_t i = 0; i < pfb->pColumns->size(); i++)
  649. {
  650. pc = &pfb->pColumns->at(i);
  651. if (i == newActiveColumn)
  652. {
  653. rc.right = rc.left + pc->width;
  654. SendMessageW(pfb->hwndActive, LB_SETCOUNT, pc->count, 0L);
  655. for (int k = 0; k < pc->count; k++)
  656. {
  657. if (FBIS_SELECTED & pc->pItems[k].styles)
  658. SendMessageW(pfb->hwndActive, LB_SETSEL, TRUE, k);
  659. }
  660. if ((UINT)pc->firstSelected < (UINT)pc->count)
  661. {
  662. SendMessageW(pfb->hwndActive, LB_SETSEL, TRUE, pc->firstSelected);
  663. }
  664. SendMessageW(pfb->hwndActive, LB_SETTOPINDEX, pc->firstVisible, 0L);
  665. break;
  666. }
  667. else rc.left += (pc->width + SIZER_WIDTH);
  668. }
  669. SCROLLINFO si;
  670. si.cbSize = sizeof(SCROLLINFO);
  671. si.fMask = SIF_POS;
  672. if (!GetScrollInfo(hwnd, SB_HORZ, &si)) ZeroMemory(&si, sizeof(SCROLLINFO));
  673. SetWindowPos(pfb->hwndActive, NULL, rc.left - si.nPos, rc.top, rc.right - rc.left, rc.bottom - rc.top,
  674. SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOSENDCHANGING | SWP_NOREDRAW);
  675. MLSkinnedScrollWnd_UpdateBars(pfb->hwndActive, FALSE);
  676. if (0 == (WS_VISIBLE & GetWindowLongPtrW(pfb->hwndActive, GWL_STYLE)))
  677. ShowWindow(pfb->hwndActive, SW_SHOWNA);
  678. SendMessage(hwnd, WM_SETREDRAW, TRUE, 0L);
  679. SendMessageW(pfb->hwndActive, WM_CHANGEUISTATE, MAKEWPARAM(UIS_INITIALIZE, UISF_HIDEACCEL | UISF_HIDEFOCUS), 0L);
  680. SendMessageW(pfb->hwndActive, WM_SETREDRAW, TRUE, 0L);
  681. UpdateWindow(pfb->hwndActive);
  682. }
  683. if (rgnInvalid)
  684. {
  685. InvalidateRgn(hwnd, rgnInvalid, FALSE);
  686. DeleteObject(rgnInvalid);
  687. UpdateWindow(hwnd);
  688. }
  689. return newActiveColumn;
  690. }
  691. static BOOL FolderBrowser_OnSetRootFolder(HWND hwnd, LPCWSTR pszRoot)
  692. {
  693. FBDATA *pfb = GetFolderBrowser(hwnd);
  694. if (!pfb) return FALSE;
  695. FolderBrowser_UpdateActiveColumn(hwnd, ((size_t)-1));
  696. pfb->pColumns->clear();
  697. pfb->pBuffer->Clear();
  698. pfb->pszRoot = NULL;
  699. if (pszRoot) pfb->pszRoot = _wcsdup(pszRoot);
  700. FBCOLUMN col;
  701. ZeroMemory(&col, sizeof(FBCOLUMN));
  702. col.width = COLUMN_DEFAULT_WIDTH;
  703. col.count = 1;
  704. col.pItems = (FBITEM*)calloc(1, sizeof(FBITEM));
  705. col.pItems[0].index = 0;
  706. pfb->pBuffer->Add(pszRoot);
  707. pfb->pColumns->push_back(col);
  708. LRESULT result = FolderBrowser_AddColumn(hwnd, pszRoot, -1, -1, TRUE);
  709. FolderBrowser_UpdateScrollInfo(hwnd);
  710. return ( -1 != result);
  711. }
  712. static INT FolderBrowser_OnGetRootFolder(HWND hwnd, LPWSTR pszBuffer, INT cchMax)
  713. {
  714. FBDATA *pfb = GetFolderBrowser(hwnd);
  715. if (!pfb || !pszBuffer) return -1;
  716. HRESULT hr = StringCchCopyExW(pszBuffer, cchMax, pfb->pszRoot, NULL, (size_t*)&cchMax, STRSAFE_IGNORE_NULLS);
  717. return (S_OK == hr) ? cchMax : -1;
  718. }
  719. static BOOL FolderBrowser_OnSetCurrentPath(HWND hwnd, LPCWSTR pszPath, BOOL bRedraw)
  720. {
  721. FBDATA *pfb = GetFolderBrowser(hwnd);
  722. if (!pfb || !pfb->pszRoot) return FALSE;
  723. BOOL updateLast = FALSE;
  724. DWORD lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
  725. size_t column = 0;
  726. INT cchPart;
  727. LPCWSTR pszCursor, pszPart;
  728. pszCursor = pszPath;
  729. pszPart = pszCursor;
  730. if (pszCursor)
  731. {
  732. for (; column < pfb->pColumns->size() && !updateLast; column++, pszCursor++)
  733. {
  734. pszPart = pszCursor;
  735. FBCOLUMN *pc = &pfb->pColumns->at(column);
  736. if (pc->pItems)
  737. {
  738. for (int i = 0; i < pc->count; i++)
  739. pc->pItems[i].styles = 0;
  740. }
  741. while (L'\0' != *pszCursor && L'\\' != *pszCursor) pszCursor++;
  742. cchPart = (int)(pszCursor - pszPart);
  743. if (0 == cchPart)
  744. {
  745. pc->firstSelected = -1;
  746. pc->firstVisible = 0;
  747. break;
  748. }
  749. if (-1 == pc->firstSelected || CSTR_EQUAL != CompareStringW(lcid, NORM_IGNORECASE, pszPart, cchPart,
  750. pfb->pBuffer->GetString(pc->bufferOffset + pc->pItems[pc->firstSelected].index), -1))
  751. {
  752. pc->firstSelected = FoderBrowser_FindFolder(pfb->pBuffer, pc, pszPart, cchPart);
  753. if (-1 != pc->firstSelected)
  754. {
  755. pc->firstVisible = pc->firstSelected;
  756. updateLast = TRUE;
  757. }
  758. else break;
  759. }
  760. if (-1 != pc->firstSelected)
  761. {
  762. if (pc->pItems && pc->firstSelected < pc->count) pc->pItems[pc->firstSelected].styles |= FBIS_SELECTED;
  763. }
  764. if (L'\0' == *pszCursor) break;
  765. }
  766. }
  767. if (0 == column)
  768. {
  769. FBCOLUMN *pc = &pfb->pColumns->at(0);
  770. if (pc && pc->count > 0 && pc->pItems)
  771. {
  772. pc->firstSelected = 0;
  773. pc->pItems[pc->firstSelected].styles |= FBIS_SELECTED;
  774. }
  775. if(CSTR_EQUAL == CompareStringW(lcid, NORM_IGNORECASE, pszPart, cchPart, pfb->pszRoot, cchPart))
  776. {
  777. pszPath = pfb->pszRoot;
  778. pszCursor = pfb->pszRoot + lstrlenW(pszPath);
  779. updateLast = TRUE;
  780. }
  781. }
  782. if (column == pfb->pColumns->size()) updateLast = TRUE;
  783. if (column < pfb->pColumns->size())
  784. {
  785. pfb->pBuffer->TrimCount(pfb->pColumns->at(column).bufferOffset + pfb->pColumns->at(column).count);
  786. while (pfb->pColumns->size() > (column + 1))
  787. {
  788. FBCOLUMN *pc = &pfb->pColumns->back();
  789. if (pc->pItems) free(pc->pItems);
  790. pfb->pColumns->pop_back();
  791. }
  792. }
  793. while (updateLast)
  794. {
  795. updateLast = FALSE;
  796. INT cchPath = (INT)(pszCursor - pszPath);
  797. if (0 != cchPath && FolderBrowser_AddColumn(hwnd, pszPath, cchPath, -1, TRUE) >= 0)
  798. {
  799. FBCOLUMN *pc = &pfb->pColumns->back();
  800. pszPart = pszCursor;
  801. while (L'\0' != *pszCursor && L'\\' != *pszCursor) pszCursor++;
  802. cchPart = (int)(pszCursor - pszPart);
  803. if (0 != cchPart)
  804. {
  805. pc->firstSelected = FoderBrowser_FindFolder(pfb->pBuffer, pc, pszPart, cchPart);
  806. if (-1 != pc->firstSelected)
  807. {
  808. pc->firstVisible = pc->firstSelected;
  809. if (pc->pItems && pc->firstSelected < pc->count) pc->pItems[pc->firstSelected].styles |= FBIS_SELECTED;
  810. updateLast = TRUE;
  811. }
  812. if (0x00 != *pszCursor) pszCursor++;
  813. }
  814. column++;
  815. }
  816. }
  817. FolderBrowser_HideActive(hwnd);
  818. if (bRedraw)
  819. {
  820. size_t active = column;
  821. if (active >= pfb->pColumns->size()) active = pfb->pColumns->size() - 1;
  822. while(0 != active && -1 == pfb->pColumns->at(active).firstSelected) active--;
  823. FolderBrowser_OnEnsureVisible(hwnd, active, EVF_NOREDRAW);
  824. FolderBrowser_UpdateScrollInfo(hwnd);
  825. }
  826. FolderBrowser_RestoreActive(hwnd);
  827. if (bRedraw) InvalidateRect(hwnd, NULL, TRUE);
  828. return TRUE;
  829. }
  830. static LRESULT FolderBrowser_OnCreateWindow(HWND hwnd, CREATESTRUCT *pcs)
  831. {
  832. FBDATA *pfb;
  833. pfb = (FBDATA*)calloc(1, sizeof(FBDATA));
  834. if (!pfb) return -1;
  835. SetLastError(ERROR_SUCCESS);
  836. if (!SetWindowLongPtrW(hwnd, 0, (LONGX86)(LONG_PTR)pfb) && ERROR_SUCCESS != GetLastError())
  837. {
  838. free(pfb);
  839. return -1;
  840. }
  841. SetWindowLongPtrW(hwnd, GWL_STYLE, GetWindowLongPtrW(hwnd, GWL_STYLE) | WS_CLIPCHILDREN);
  842. pfb->rgbBk = GetSysColor(COLOR_WINDOW);
  843. pfb->rgbText = GetSysColor(COLOR_WINDOWTEXT);
  844. pfb->pColumns = new std::vector<FBCOLUMN>();
  845. pfb->pBuffer = new StringVector(8192, 4096);
  846. pfb->focusedColumn = -1;
  847. pfb->hwndActive = CreateWindowExW(WS_EX_NOACTIVATE /*| WS_EX_NOPARENTNOTIFY*/, L"ListBox", L"FolderView active listbox",
  848. WS_CHILD | WS_VSCROLL |
  849. LBS_NODATA | LBS_OWNERDRAWFIXED | LBS_DISABLENOSCROLL | LBS_NOREDRAW | LBS_NOTIFY |
  850. LBS_EXTENDEDSEL | LBS_NOINTEGRALHEIGHT | LBS_WANTKEYBOARDINPUT,
  851. 0, 0, 1, 1, hwnd, NULL, NULL, 0L);
  852. pfb->hwndDraw = CreateWindowExW(WS_EX_NOACTIVATE | WS_EX_NOPARENTNOTIFY, L"ListBox", L"FolderView drawing listbox",
  853. WS_CHILD | WS_VSCROLL |
  854. LBS_NODATA | LBS_OWNERDRAWFIXED | LBS_DISABLENOSCROLL | LBS_NOREDRAW |
  855. LBS_EXTENDEDSEL | LBS_NOINTEGRALHEIGHT,
  856. 0, 0, 1, 1, hwnd, NULL, NULL, 0L);
  857. HFONT hFont = (HFONT)SendMessageW(hwnd, WM_GETFONT, 0, 0L);
  858. if (pfb->hwndActive)
  859. {
  860. SetWindowLongPtrW(pfb->hwndActive, GWLP_USERDATA, (LONGX86)-1);
  861. SendMessageW(pfb->hwndActive, WM_SETFONT, (WPARAM)hFont, FALSE);
  862. SendMessageW(pfb->hwndActive, LB_SETITEMHEIGHT, 0, (LPARAM)FolderBrowser_CalculateListItemHeight(pfb->hwndActive));
  863. FolderBrowser_CustomizeListBox(pfb->hwndActive);
  864. }
  865. if (pfb->hwndDraw)
  866. {
  867. SetWindowLongPtrW(pfb->hwndDraw, GWLP_USERDATA, (LONGX86)-1);
  868. SendMessageW(pfb->hwndDraw, WM_SETFONT, (WPARAM)hFont, FALSE);
  869. SendMessageW(pfb->hwndDraw, LB_SETITEMHEIGHT, 0, (LPARAM)FolderBrowser_CalculateListItemHeight(pfb->hwndDraw));
  870. }
  871. // this weird call need to be done to disable vertical scrollbar in skinned mode
  872. SCROLLINFO si;
  873. ZeroMemory(&si, sizeof(SCROLLINFO));
  874. si.cbSize = sizeof(SCROLLINFO);
  875. si.fMask = SIF_RANGE | SIF_PAGE;
  876. si.nMin = 0;
  877. si.nMax = 0;
  878. si.nPage = 100;
  879. SetScrollInfo(hwnd, SB_VERT, &si, TRUE);
  880. SendMessageW(hwnd, FBM_SETFILESYSTEMINFO, 0, 0L);
  881. return 0;
  882. }
  883. static void FolderBrowser_OnDestroyWindow(HWND hwnd)
  884. {
  885. FBDATA *pfb = GetFolderBrowser(hwnd);
  886. SetWindowLongPtrW(hwnd, 0, 0L);
  887. if (!pfb) return;
  888. if (pfb->pBuffer) delete(pfb->pBuffer);
  889. if (pfb->pColumns)
  890. {
  891. while (pfb->pColumns->size() > 1)
  892. {
  893. FBCOLUMN *pc = &pfb->pColumns->back();
  894. if (pc->pItems) free(pc->pItems);
  895. pfb->pColumns->pop_back();
  896. }
  897. delete(pfb->pColumns);
  898. }
  899. if (pfb->hwndDraw) DestroyWindow(pfb->hwndDraw);
  900. if (pfb->hwndActive) DestroyWindow(pfb->hwndActive);
  901. free(pfb);
  902. }
  903. static void FolderBrowser_Draw(HWND hwnd, PAINTSTRUCT *pps)
  904. {
  905. FBDATA *pfb = GetFolderBrowser(hwnd);
  906. HDC hdc;
  907. RECT rc, rp, rs;
  908. hdc = pps->hdc;
  909. CopyRect(&rp, &pps->rcPaint);
  910. FolderBrowser_GetAdjustedClientRect(hwnd, &rc);
  911. size_t activeColumn = FolderBrowser_GetListBoxColumn(pfb->hwndActive);
  912. int height = rc.bottom - rc.top;
  913. for (size_t i = 0; i < pfb->pColumns->size(); i++)
  914. {
  915. FBCOLUMN *pc = &pfb->pColumns->at(i);
  916. if (rc.left < rp.right && (rc.left + pc->width + SIZER_WIDTH) > rp.left)
  917. {
  918. SetViewportOrgEx(hdc, rc.left, rc.top, NULL);
  919. if (i != activeColumn && rp.left < (rc.left + pc->width))
  920. {
  921. PrepareDrawingListBox(pfb->hwndDraw, pc, height, i);
  922. SendMessageW(pfb->hwndDraw, WM_PRINT, (WPARAM)hdc, (LPARAM)(PRF_CLIENT | PRF_NONCLIENT | ((pps->fErase) ? PRF_ERASEBKGND : 0)));
  923. }
  924. if (rp.right > (rc.left + pc->width) && (SIZER_WIDTH > 0))
  925. {
  926. SetBkColor(hdc, pfb->rgbBk);
  927. SetRect(&rs, pc->width, rp.top - rc.top, pc->width + SIZER_WIDTH, rp.bottom - rc.top);
  928. ExtTextOutW(hdc, 0, 0, ETO_OPAQUE, &rs, NULL, 0, NULL);
  929. if ((i == sizerActive || i == sizerHover) && 1 == (rs.right - rs.left)%2)
  930. {
  931. COLORREF clr;
  932. HPEN hp, hpo;
  933. clr = BlendColors(pfb->rgbText, pfb->rgbBk, (i != sizerActive) ? 76 : 127);
  934. hp = (HPEN)GetStockObject(DC_PEN);
  935. hpo = (hp) ? (HPEN)SelectObject(hdc, hp) : NULL;
  936. SetDCPenColor(hdc, clr);
  937. LONG l = rs.left + (rs.right - rs.left)/2;
  938. MoveToEx(hdc, l, rs.top, NULL);
  939. LineTo(hdc, l, rs.bottom);
  940. if (hpo) SelectObject(hdc, hpo);
  941. }
  942. }
  943. }
  944. rc.left += (pc->width + SIZER_WIDTH);
  945. if (rc.left > rc.right) break;
  946. }
  947. if (pps->fErase && rc.left < rp.right)
  948. {
  949. if (rc.left < rp.left) rc.left = rp.left;
  950. SetViewportOrgEx(hdc, 0, 0, NULL);
  951. SetBkColor(hdc, pfb->rgbBk);
  952. ExtTextOutW(hdc, 0, 0, ETO_OPAQUE, &rc, L"", 0, 0);
  953. }
  954. SetWindowLongPtrW(pfb->hwndDraw, GWLP_USERDATA, (LONGX86)-1);
  955. }
  956. static void FolderBrowser_OnPaint(HWND hwnd)
  957. {
  958. PAINTSTRUCT ps;
  959. if (BeginPaint(hwnd, &ps))
  960. {
  961. if (ps.rcPaint.left != ps.rcPaint.right) FolderBrowser_Draw(hwnd, &ps);
  962. EndPaint(hwnd, &ps);
  963. }
  964. }
  965. static COLORREF FolderBrowser_OnGetBkColor(HWND hwnd)
  966. {
  967. FBDATA *pfb = GetFolderBrowser(hwnd);
  968. return (pfb) ? pfb->rgbBk : 0;
  969. }
  970. static BOOL FolderBrowser_OnSetBkColor(HWND hwnd, COLORREF rgbBk)
  971. {
  972. FBDATA *pfb = GetFolderBrowser(hwnd);
  973. if (!pfb) return FALSE;
  974. pfb->rgbBk = rgbBk;
  975. return TRUE;
  976. }
  977. static COLORREF FolderBrowser_OnGetTextColor(HWND hwnd)
  978. {
  979. FBDATA *pfb = GetFolderBrowser(hwnd);
  980. return (pfb) ? pfb->rgbText : 0;
  981. }
  982. static BOOL FolderBrowser_OnSetTextColor(HWND hwnd, COLORREF rgbText)
  983. {
  984. FBDATA *pfb = GetFolderBrowser(hwnd);
  985. if (!pfb) return FALSE;
  986. pfb->rgbText = rgbText;
  987. return TRUE;
  988. }
  989. static BOOL FolderBrowser_OnGetFolderBrowserInfo(HWND hwnd, FOLDERBROWSERINFO *pInfo)
  990. {
  991. FBDATA *pfb = GetFolderBrowser(hwnd);
  992. if (!pfb || !pInfo || pInfo->cbSize < sizeof(FOLDERBROWSERINFO)) return FALSE;
  993. pInfo->activeColumn = FolderBrowser_GetListBoxColumn(pfb->hwndActive);
  994. pInfo->hwndActive = pfb->hwndActive;
  995. pInfo->hwndDraw = pfb->hwndDraw;
  996. return TRUE;
  997. }
  998. static BOOL FolderBrowser_OnMeasureItem(HWND hwnd, INT ctrlId, MEASUREITEMSTRUCT *pmis)
  999. {
  1000. LPCWSTR pszText(NULL);
  1001. HWND hItem = GetDlgItem(hwnd, pmis->CtlID);
  1002. FBDATA *pfb = GetFolderBrowser(hwnd);
  1003. if (!pfb || NULL == hItem) return FALSE;
  1004. size_t c = FolderBrowser_GetListBoxColumn(hItem);
  1005. if (c < pfb->pColumns->size())
  1006. {
  1007. if (c == 0) // special case
  1008. {
  1009. pszText = pfb->pszRoot;
  1010. }
  1011. else
  1012. {
  1013. FBCOLUMN *pc = &pfb->pColumns->at(c);
  1014. size_t i = pmis->itemID;
  1015. if (pc->pItems && i < (UINT)pc->count) i = pc->pItems[i].index;
  1016. i += pc->bufferOffset;
  1017. if (i < pfb->pBuffer->Count()) pszText = pfb->pBuffer->GetString(i);
  1018. }
  1019. INT cchText(0);
  1020. if (NULL != pszText) cchText = lstrlenW(pszText);
  1021. SkinnedListbox::MeasureItem(hItem, pszText, cchText, &pmis->itemWidth, &pmis->itemHeight);
  1022. }
  1023. return TRUE;
  1024. }
  1025. static BOOL FolderBrowser_OnDrawItem(HWND hwnd, INT ctrlId, DRAWITEMSTRUCT *pdis)
  1026. {
  1027. LPCWSTR pszText(NULL);
  1028. FBDATA *pfb = GetFolderBrowser(hwnd);
  1029. if (!pfb) return FALSE;
  1030. size_t c = FolderBrowser_GetListBoxColumn(pdis->hwndItem);
  1031. if (c < pfb->pColumns->size())
  1032. {
  1033. if (c == 0) // special case
  1034. {
  1035. pszText = pfb->pszRoot;
  1036. if (pdis->hwndItem != pfb->hwndActive &&
  1037. pfb->pColumns->at(0).pItems &&
  1038. (FBIS_SELECTED & pfb->pColumns->at(0).pItems[0].styles))
  1039. {
  1040. pdis->itemState |= ODS_SELECTED;
  1041. }
  1042. }
  1043. else
  1044. {
  1045. FBCOLUMN *pc = &pfb->pColumns->at(c);
  1046. size_t i = pdis->itemID;
  1047. if (pc->pItems && i < (UINT)pc->count) i = pc->pItems[i].index;
  1048. i += pc->bufferOffset;
  1049. if (i < pfb->pBuffer->Count()) pszText = pfb->pBuffer->GetString(i);
  1050. if (pdis->hwndItem != pfb->hwndActive && pc->pItems &&
  1051. (FBIS_SELECTED & pc->pItems[pdis->itemID].styles))
  1052. {
  1053. pdis->itemState |= ODS_SELECTED;
  1054. }
  1055. }
  1056. INT cchText(0);
  1057. if (NULL != pszText) cchText = lstrlenW(pszText);
  1058. if (c == pfb->focusedColumn && pdis->hwndItem != pfb->hwndActive)
  1059. {
  1060. pdis->hwndItem = hwnd;
  1061. if(pdis->itemState & ODS_SELECTED)
  1062. {
  1063. SkinnedListbox::DrawItem(pdis, pszText, cchText);
  1064. pdis->itemAction = ODA_FOCUS;
  1065. pdis->itemState &= ~0x0200/*ODS_NOFOCUSRECT*/;
  1066. if (UISF_HIDEFOCUS & SendMessageW(hwnd, WM_QUERYUISTATE, 0, 0L)) pdis->itemState |= 0x0200/*ODS_NOFOCUSRECT*/;
  1067. }
  1068. }
  1069. SkinnedListbox::DrawItem(pdis, pszText, cchText);
  1070. }
  1071. return TRUE;
  1072. }
  1073. static void FolderBrowser_OnSetFont(HWND hwnd, HFONT hFont, BOOL bRedraw)
  1074. {
  1075. FBDATA *pfb = GetFolderBrowser(hwnd);
  1076. if (!pfb) return;
  1077. if (pfb->hwndActive)
  1078. {
  1079. SendMessageW(pfb->hwndActive, WM_SETFONT, (WPARAM)hFont, FALSE);
  1080. SendMessageW(pfb->hwndActive, LB_SETITEMHEIGHT, 0, (LPARAM)FolderBrowser_CalculateListItemHeight(pfb->hwndActive));
  1081. }
  1082. if (pfb->hwndDraw)
  1083. {
  1084. SendMessageW(pfb->hwndDraw, WM_SETFONT, (WPARAM)hFont, FALSE);
  1085. SendMessageW(pfb->hwndDraw, LB_SETITEMHEIGHT, 0, (LPARAM)FolderBrowser_CalculateListItemHeight(pfb->hwndDraw));
  1086. }
  1087. }
  1088. static void FolderBrowser_OnSetFocus(HWND hwnd, HWND hwndLost)
  1089. {
  1090. FBDATA *pfb = GetFolderBrowser(hwnd);
  1091. if (NULL == pfb) return;
  1092. if (pfb && hwndLost != pfb->hwndActive && FolderBrowser_GetListBoxColumn(pfb->hwndActive) > pfb->pColumns->size())
  1093. {
  1094. size_t last = 0;
  1095. for (size_t i= 0; i < pfb->pColumns->size(); i++)
  1096. {
  1097. if (-1 != pfb->pColumns->at(i).firstSelected) last = i;
  1098. else break;
  1099. }
  1100. last = FolderBrowser_UpdateActiveColumn(hwnd, last);
  1101. if (-1 != last)
  1102. {
  1103. //INT selCount = (INT)SendMessageW(pfb->hwndActive, LB_GETSELCOUNT, 0, 0L);
  1104. //if (selCount < 1)
  1105. //{
  1106. // SendMessageW(pfb->hwndActive, LB_SETSEL, TRUE, 0L);
  1107. // FolderBrowser_OnSelectionChanged(hwnd, TRUE, TRUE);
  1108. //}
  1109. //else SendMessageW(pfb->hwndActive, LB_SETCARETINDEX, pfb->pColumns->at(last).firstSelected, FALSE);
  1110. //FolderBrowser_OnEnsureVisible(hwnd, last, 0);
  1111. }
  1112. if (IsWindowVisible(pfb->hwndActive) && IsWindowEnabled(pfb->hwndActive)) SetFocus(pfb->hwndActive);
  1113. }
  1114. }
  1115. static void FolderBrowser_OnKillFocus(HWND hwnd, HWND hwndRecieve)
  1116. {
  1117. FBDATA *pfb = GetFolderBrowser(hwnd);
  1118. if (pfb && hwndRecieve != pfb->hwndActive)
  1119. {
  1120. FolderBrowser_UpdateActiveColumn(hwnd, ((size_t)-1));
  1121. }
  1122. }
  1123. static LRESULT FolderBrowser_OnGetDlgCode(HWND hwnd, INT vKey, MSG *pMsg)
  1124. {
  1125. return DLGC_WANTARROWS;
  1126. }
  1127. static UINT FolderBrowser_HitTest(HWND hwnd, POINT pt, size_t *pColumn, size_t *pItem)
  1128. {
  1129. RECT rc;
  1130. size_t column = -1, item = -1;
  1131. UINT hitTest = HTERROR;
  1132. FBDATA *pfb = GetFolderBrowser(hwnd);
  1133. if (!pfb || !FolderBrowser_GetAdjustedClientRect(hwnd, &rc))
  1134. return hitTest;
  1135. hitTest = HTCLIENT;
  1136. size_t activeColumn = FolderBrowser_GetListBoxColumn(pfb->hwndActive);
  1137. for(size_t i = 0; i < pfb->pColumns->size(); i++)
  1138. {
  1139. FBCOLUMN *pc = &pfb->pColumns->at(i);
  1140. rc.right = rc.left + pc->width;
  1141. if (PtInRect(&rc, pt))
  1142. {
  1143. column = i;
  1144. if (pc->count > 0)
  1145. {
  1146. HWND hwndTest = NULL;
  1147. if (i != activeColumn)
  1148. {
  1149. hwndTest = pfb->hwndDraw;
  1150. SetWindowPos(hwndTest, NULL, 0, 0, pc->width, rc.bottom - rc.top,
  1151. SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOMOVE | SWP_NOREDRAW | SWP_NOSENDCHANGING);
  1152. SendMessageW(hwndTest, LB_SETCOUNT, pc->count, 0L);
  1153. if (-1 != pc->firstSelected) SendMessageW(pfb->hwndDraw, LB_SETSEL, TRUE, pc->firstSelected);
  1154. SendMessageW(hwndTest, LB_SETTOPINDEX, pc->firstVisible, 0L);
  1155. }
  1156. else
  1157. hwndTest = pfb->hwndActive;
  1158. if (NULL != hwndTest)
  1159. {
  1160. RECT rw;
  1161. GetClientRect(hwndTest, &rw);
  1162. MapWindowPoints(hwndTest, hwnd, (POINT*)&rw, 2);
  1163. if (hwndTest != pfb->hwndActive)
  1164. OffsetRect(&rw, rc.left, rc.top);
  1165. if (PtInRect(&rw, pt))
  1166. {
  1167. INT itemIndex = (INT)SendMessageW(hwndTest, LB_ITEMFROMPOINT, 0, MAKELPARAM(pt.x - rc.left, pt.y - rc.top));
  1168. if (HIWORD(itemIndex)) itemIndex = -1;
  1169. if (itemIndex != -1) item = (size_t)itemIndex;
  1170. }
  1171. }
  1172. }
  1173. break;
  1174. }
  1175. rc.right += SIZER_WIDTH;
  1176. rc.left = rc.right;
  1177. if (rc.left > pt.x) break;
  1178. }
  1179. if (pColumn) *pColumn = column;
  1180. if (pItem) *pItem = item;
  1181. return hitTest;
  1182. }
  1183. static void FolderBrowser_UpdateScrollHovering(HWND hwnd, UINT uFlags, POINTS pts)
  1184. {
  1185. RECT rc;
  1186. FBCOLUMN *pc;
  1187. POINT pt;
  1188. LONG left;
  1189. static size_t hoveredColumn = -1;
  1190. static INT nHoveredPart = -1;
  1191. FBDATA *pfb = GetFolderBrowser(hwnd);
  1192. if (!pfb || !FolderBrowser_GetAdjustedClientRect(hwnd, &rc))
  1193. return;
  1194. left = rc.left;
  1195. POINTSTOPOINT(pt, pts);
  1196. size_t activeColumn = FolderBrowser_GetListBoxColumn(pfb->hwndActive);
  1197. size_t nHovered = -1;
  1198. for(size_t i = 0; i < pfb->pColumns->size() && pt.x >= rc.left; i++)
  1199. {
  1200. pc = &pfb->pColumns->at(i);
  1201. rc.right = rc.left + pc->width;
  1202. if (i != activeColumn && PtInRect(&rc, pt))
  1203. {
  1204. PrepareDrawingListBox(pfb->hwndDraw, pc, rc.bottom - rc.top, -1);
  1205. SCROLLINFO si;
  1206. si.cbSize = sizeof(SCROLLINFO);
  1207. si.fMask = SIF_PAGE | SIF_RANGE;
  1208. if (GetScrollInfo(pfb->hwndDraw, SB_VERT, &si) && (INT)si.nPage <= si.nMax)
  1209. {
  1210. pt.x -= rc.left;
  1211. pt.y -= rc.top;
  1212. MapWindowPoints(hwnd, HWND_DESKTOP, &pt, 1);
  1213. INT ht = (INT) SendMessageW(pfb->hwndDraw, WM_NCHITTEST, 0, MAKELPARAM(pt.x, pt.y));
  1214. if (HTVSCROLL == ht || HTHSCROLL == ht)
  1215. {
  1216. nHovered = i;
  1217. SBADJUSTHOVER hoverTest;
  1218. hoverTest.hitTest = ht;
  1219. hoverTest.ptMouse.x = (SHORT)pt.x;
  1220. hoverTest.ptMouse.y = (SHORT)pt.y;
  1221. if (SENDMLIPC(pfb->hwndDraw, IPC_ML_SKINNEDSCROLLWND_ADJUSTHOVER, (WPARAM)&hoverTest))
  1222. {
  1223. if (nHoveredPart != hoverTest.nResult)
  1224. {
  1225. nHoveredPart = hoverTest.nResult;
  1226. RefreshListBoxNC(hwnd, pfb->hwndDraw, *(POINT*)&rc);
  1227. }
  1228. }
  1229. }
  1230. else
  1231. nHoveredPart = -1;
  1232. }
  1233. break;
  1234. }
  1235. rc.right += SIZER_WIDTH;
  1236. rc.left = rc.right;
  1237. }
  1238. if (hoveredColumn != nHovered && -1 != hoveredColumn)
  1239. {
  1240. rc.left = left;
  1241. for(size_t i = 0; i < hoveredColumn; i++)
  1242. rc.left += pfb->pColumns->at(i).width + SIZER_WIDTH;
  1243. pc = &pfb->pColumns->at(hoveredColumn);
  1244. if (PrepareDrawingListBox(pfb->hwndDraw, pc, rc.bottom - rc.top, -1))
  1245. {
  1246. SendMessageW(pfb->hwndDraw, WM_NCMOUSELEAVE, HTNOWHERE, 0L);
  1247. RefreshListBoxNC(hwnd, pfb->hwndDraw, *(POINT*)&rc);
  1248. }
  1249. nHoveredPart = -1;
  1250. }
  1251. hoveredColumn = nHovered;
  1252. if (-1 != hoveredColumn && -1 != nHoveredPart)
  1253. {
  1254. TRACKMOUSEEVENT tracker;
  1255. tracker.cbSize = sizeof(tracker);
  1256. tracker.hwndTrack = hwnd;
  1257. tracker.dwHoverTime = 0;
  1258. tracker.dwFlags = TME_LEAVE;
  1259. TrackMouseEvent(&tracker);
  1260. }
  1261. }
  1262. static void FolderBrowser_OnMouseMove(HWND hwnd, UINT uFlags, POINTS pts)
  1263. {
  1264. FBDATA *pfb = GetFolderBrowser(hwnd);
  1265. if (!pfb) return;
  1266. if (GetCapture() == hwnd && sizerActive < pfb->pColumns->size())
  1267. {
  1268. RECT rc, ri;
  1269. SCROLLINFO si;
  1270. FBCOLUMN *pc;
  1271. GetClientRect(hwnd, &rc);
  1272. CopyRect(&ri, &rc);
  1273. si.cbSize = sizeof(SCROLLINFO);
  1274. si.fMask = SIF_POS;
  1275. if (!GetScrollInfo(hwnd, SB_HORZ, &si))
  1276. ZeroMemory(&si, sizeof(SCROLLINFO));
  1277. rc.right = rc.left - si.nPos;
  1278. for (size_t i = 0; i <= sizerActive; i++)
  1279. {
  1280. pc = &pfb->pColumns->at(i);
  1281. rc.right += (pc->width + SIZER_WIDTH);
  1282. }
  1283. rc.left = rc.right - SIZER_WIDTH;
  1284. GetCursorPos(((LPPOINT)&rc) + 1);
  1285. MapWindowPoints(HWND_DESKTOP, hwnd, ((LPPOINT)&rc) + 1, 1);
  1286. rc.right -= clickoffs;
  1287. if (rc.left != rc.right)
  1288. {
  1289. if (pc)
  1290. {
  1291. ri.left = rc.left - pc->width;
  1292. INT w = pc->width + (rc.right - rc.left);
  1293. pc->autoAdjust = FALSE;
  1294. if (w < COLUMN_MIN_WIDTH) w = COLUMN_MIN_WIDTH;
  1295. if (w > COLUMN_MAX_WIDTH) w = COLUMN_MAX_WIDTH;
  1296. if (pc->width != w)
  1297. {
  1298. pc->width = w;
  1299. FolderBrowser_UpdateScrollInfo(hwnd);
  1300. InvalidateRect(hwnd, &ri, TRUE);
  1301. UpdateWindow(hwnd);
  1302. }
  1303. }
  1304. }
  1305. }
  1306. else FolderBrowser_UpdateScrollHovering(hwnd, uFlags, pts);
  1307. }
  1308. static void FolderBrowser_OnLButtonUp(HWND hwnd, UINT uFlags, POINTS pts)
  1309. {
  1310. FBDATA *pfb = GetFolderBrowser(hwnd);
  1311. if (!pfb || pfb->pColumns->size() == 0) return;
  1312. if (-1 != sizerActive)
  1313. {
  1314. RECT rc;
  1315. SCROLLINFO si;
  1316. GetClientRect(hwnd, &rc);
  1317. si.cbSize = sizeof(SCROLLINFO);
  1318. si.fMask = SIF_POS;
  1319. if (!GetScrollInfo(hwnd, SB_HORZ, &si)) ZeroMemory(&si, sizeof(SCROLLINFO));
  1320. rc.right = rc.left - si.nPos;
  1321. for (size_t i = 0; i <= sizerActive; i++)
  1322. {
  1323. rc.right += (pfb->pColumns->at(i).width + SIZER_WIDTH);
  1324. }
  1325. rc.left = rc.right - SIZER_WIDTH;
  1326. sizerActive = -1;
  1327. clickoffs = 0;
  1328. ReleaseCapture();
  1329. FolderBrowser_RestoreActive(hwnd);
  1330. InvalidateRect(hwnd, &rc, FALSE);
  1331. }
  1332. }
  1333. static void FolderBrowser_OnButtonDown(HWND hwnd, UINT uButtonMsg, UINT uFlags, POINTS pts)
  1334. {
  1335. RECT rc;
  1336. POINT pt;
  1337. UINT ht;
  1338. size_t column, item;
  1339. FBDATA *pfb = GetFolderBrowser(hwnd);
  1340. if (!pfb || pfb->pColumns->size() == 0) return;
  1341. ht = HTERROR;
  1342. FolderBrowser_GetAdjustedClientRect(hwnd, &rc);
  1343. POINTSTOPOINT(pt, pts);
  1344. // check if sizer clicked
  1345. LONG cPoint = rc.left;
  1346. for(size_t i = 0; i < pfb->pColumns->size() && rc.left <= pt.x; i++)
  1347. {
  1348. FBCOLUMN *pc = &pfb->pColumns->at(i);
  1349. cPoint += pc->width;
  1350. rc.left = cPoint - SIZER_OVERLAP_LEFT;
  1351. cPoint += SIZER_WIDTH;
  1352. rc.right = cPoint + SIZER_OVERLAP_RIGHT;
  1353. if (WM_LBUTTONDOWN == uButtonMsg)
  1354. {
  1355. if (PtInRect(&rc, pt))
  1356. {
  1357. sizerActive = i;
  1358. clickoffs = pts.x - (rc.left + SIZER_OVERLAP_LEFT);
  1359. UpdateWindow(hwnd);
  1360. FolderBrowser_HideActive(hwnd);
  1361. SetCapture(hwnd);
  1362. InvalidateRect(hwnd, &rc, FALSE);
  1363. return;
  1364. }
  1365. }
  1366. }
  1367. ht = FolderBrowser_HitTest(hwnd, pt, &column, &item);
  1368. if (-1 != column && -1 == item)
  1369. {
  1370. while (-1 != column && 0 == pfb->pColumns->at(column).count)
  1371. {
  1372. column--;
  1373. /*item = */pfb->pColumns->at(column).firstSelected;
  1374. }
  1375. }
  1376. if (-1 != column)
  1377. {
  1378. //if (WM_LBUTTONDOWN != uButtonMsg || (HTCLIENT == ht && -1 == item))
  1379. //{
  1380. // FolderBrowser_OnEnsureVisible(hwnd, column, 0);
  1381. // return; // prevent activation
  1382. //}
  1383. if (pfb->hwndActive == GetFocus())
  1384. {
  1385. UpdateWindow(pfb->hwndActive);
  1386. SendMessageW(pfb->hwndActive, WM_SETREDRAW, FALSE, 0L);
  1387. SetFocus(hwnd);
  1388. SendMessageW(pfb->hwndActive, WM_SETREDRAW, TRUE, 0L);
  1389. }
  1390. /*if (-1 != item) */pfb->focusedColumn = -1;
  1391. FolderBrowser_UpdateActiveColumn(hwnd, column);
  1392. if ((WS_VISIBLE & GetWindowLongPtrW(pfb->hwndActive, GWL_STYLE)))
  1393. {
  1394. MapWindowPoints(hwnd, HWND_DESKTOP, &pt, 1);
  1395. ht = (UINT)SendMessageW(pfb->hwndActive, WM_NCHITTEST, 0, MAKELPARAM(pt.x, pt.y));
  1396. switch(ht)
  1397. {
  1398. case HTERROR: break;
  1399. case HTCLIENT:
  1400. MapWindowPoints(HWND_DESKTOP, pfb->hwndActive, &pt, 1);
  1401. if (0 == (WS_EX_NOPARENTNOTIFY & (DWORD)GetWindowLongPtrW(pfb->hwndActive, GWL_EXSTYLE)))
  1402. {
  1403. HWND hParent = GetParent(pfb->hwndActive);
  1404. if (NULL != hParent)
  1405. {
  1406. POINT ptParent = pt;
  1407. MapWindowPoints(pfb->hwndActive, hParent, &ptParent, 1);
  1408. SendMessageW(hParent, WM_PARENTNOTIFY, MAKEWPARAM(uButtonMsg, 0), MAKELPARAM(ptParent.x, ptParent.y));
  1409. }
  1410. }
  1411. SendMessageW(pfb->hwndActive, uButtonMsg, uFlags, MAKELPARAM(pt.x, pt.y));
  1412. // maxRight = (LONG)SendMessageW(pfb->hwndActive, LB_ITEMFROMPOINT, uFlags, MAKELPARAM(pt.x, pt.y));
  1413. // if (0 == HIWORD(maxRight))
  1414. // {
  1415. // size_t a = FolderBrowser_GetListBoxColumn(pfb->hwndActive);
  1416. //// if (a < pfb->pColumns->size() && LOWORD(maxRight) == pfb->pColumns->at(a).firstSelected)
  1417. //// pfb->pColumns->at(a).firstSelected = -1;
  1418. // }
  1419. break;
  1420. default:
  1421. SendMessageW(pfb->hwndActive, (uButtonMsg - WM_MOUSEMOVE) + WM_NCMOUSEMOVE, ht, MAKELPARAM(pt.x, pt.y));
  1422. break;
  1423. }
  1424. }
  1425. }
  1426. else
  1427. {
  1428. HWND hFocus = GetFocus();
  1429. if (hFocus != hwnd && hFocus != pfb->hwndActive)
  1430. SetFocus(hwnd);
  1431. }
  1432. }
  1433. static void FolderBrowser_OnLButtonDown(HWND hwnd, UINT uFlags, POINTS pts)
  1434. {
  1435. FolderBrowser_OnButtonDown(hwnd, WM_LBUTTONDOWN, uFlags, pts);
  1436. }
  1437. static void FolderBrowser_OnLButtonDblClick(HWND hwnd, UINT uFlags, POINTS pts)
  1438. {
  1439. RECT rc;
  1440. LONG maxRight;
  1441. POINT pt;
  1442. FBDATA *pfb = GetFolderBrowser(hwnd);
  1443. if (!pfb || pfb->pColumns->size() == 0) return;
  1444. GetClientRect(hwnd, &rc);
  1445. FolderBrowser_GetAdjustedClientRect(hwnd, &rc);
  1446. maxRight = rc.right;
  1447. POINTSTOPOINT(pt, pts);
  1448. LONG cPoint = rc.left;
  1449. for(size_t i = 0; i < pfb->pColumns->size() && rc.left <= pt.x; i++)
  1450. {
  1451. FBCOLUMN *pc = &pfb->pColumns->at(i);
  1452. cPoint += pc->width;
  1453. rc.left = cPoint - SIZER_OVERLAP_LEFT;
  1454. cPoint += SIZER_WIDTH;
  1455. rc.right = cPoint + SIZER_OVERLAP_RIGHT;
  1456. if (PtInRect(&rc, pt))
  1457. {
  1458. pc->autoAdjust = TRUE;
  1459. INT width = FolderBrowser_GetPreferredColumnWidth(hwnd, i);
  1460. if ( -1 != width && pc->width != width)
  1461. {
  1462. rc.left = (rc.left + SIZER_OVERLAP_LEFT) - pc->width;
  1463. rc.right = maxRight;
  1464. pc->width = width;
  1465. UpdateWindow(hwnd);
  1466. SendMessageW(hwnd, WM_SETREDRAW, FALSE, 0L);
  1467. FolderBrowser_HideActive(hwnd);
  1468. FolderBrowser_UpdateScrollInfo(hwnd);
  1469. FolderBrowser_RestoreActive(hwnd);
  1470. SendMessageW(hwnd, WM_SETREDRAW, TRUE, 0L);
  1471. RedrawWindow(hwnd, &rc, NULL, RDW_INVALIDATE | RDW_ERASE | RDW_ALLCHILDREN | RDW_ERASENOW | RDW_UPDATENOW);
  1472. return;
  1473. }
  1474. }
  1475. }
  1476. }
  1477. static void FolderBrowser_OnRButtonDown(HWND hwnd, UINT uFlags, POINTS pts)
  1478. {
  1479. POINT pt;
  1480. size_t col, item;
  1481. POINTSTOPOINT(pt, pts);
  1482. UINT ht = FolderBrowser_HitTest(hwnd, pt, &col, &item);
  1483. if (HTCLIENT == ht && -1 != col)
  1484. {
  1485. INT ox = FolderBrowser_OnEnsureVisible(hwnd, col, EVF_NOEXTRALSPACE | EVF_NOEXTRARSPACE);
  1486. if (0 != ox) pts.x -= ox;
  1487. }
  1488. TRACE_FMT(TEXT("RDown at (%d,%d) [ht=%d, col=%d, raw=%d]\n"), pt.x, pt.y, ht, col, item);
  1489. }
  1490. static void FolderBrowser_OnRButtonUp(HWND hwnd, UINT uFlags, POINTS pts)
  1491. {
  1492. POINT pt;
  1493. size_t col, item;
  1494. POINTSTOPOINT(pt, pts);
  1495. UINT ht = FolderBrowser_HitTest(hwnd, pt, &col, &item);
  1496. TRACE_FMT(TEXT("RUp at (%d,%d) [ht=%d, col=%d, raw=%d]\n"), pt.x, pt.y, ht, col, item);
  1497. FolderBrowser_RestoreActive(hwnd);
  1498. }
  1499. static void FolderBrowser_OnKeyDown(HWND hwnd, UINT vkCode, UINT flags)
  1500. {
  1501. FBDATA *pfb = GetFolderBrowser(hwnd);
  1502. if (pfb)
  1503. {
  1504. switch(vkCode)
  1505. {
  1506. case VK_PRIOR:
  1507. case VK_NEXT:
  1508. case VK_END:
  1509. case VK_HOME:
  1510. case VK_DOWN:
  1511. case VK_UP:
  1512. case VK_RIGHT:
  1513. case VK_LEFT:
  1514. if (pfb->focusedColumn != -1)
  1515. {
  1516. FolderBrowser_UpdateActiveColumn(hwnd, pfb->focusedColumn);
  1517. if (IsWindowVisible(pfb->hwndActive) && IsWindowEnabled(pfb->hwndActive)) SetFocus(pfb->hwndActive);
  1518. }
  1519. if ((WS_VISIBLE & GetWindowLongPtrW(pfb->hwndActive, GWL_STYLE)))
  1520. {
  1521. SendMessageW(pfb->hwndActive, WM_KEYDOWN, (WPARAM)vkCode, (LPARAM)flags);
  1522. return;
  1523. }
  1524. break;
  1525. }
  1526. }
  1527. DefWindowProcW(hwnd, WM_KEYDOWN, (WPARAM)vkCode, (LPARAM)flags);
  1528. }
  1529. static void FolderBorwser_OnCommand(HWND hwnd, UINT ctrlId, UINT eventId, HWND hwndCtrl)
  1530. {
  1531. FBDATA *pfb = GetFolderBrowser(hwnd);
  1532. if (!pfb) return;
  1533. if (pfb->hwndActive == hwndCtrl)
  1534. {
  1535. switch(eventId)
  1536. {
  1537. //case LBN_SELCANCEL:
  1538. // break;
  1539. case LBN_SELCHANGE:
  1540. FolderBrowser_OnSelectionChanged(hwnd, FALSE, TRUE);
  1541. break;
  1542. case LBN_SETFOCUS:
  1543. pfb->focusedColumn = (int)FolderBrowser_GetListBoxColumn(hwndCtrl);
  1544. break;
  1545. case LBN_KILLFOCUS:
  1546. if (hwnd != GetFocus())
  1547. {
  1548. FolderBrowser_UpdateActiveColumn(hwnd, ((size_t)-1));
  1549. }
  1550. break;
  1551. }
  1552. }
  1553. }
  1554. static LRESULT FolderBrowser_OnVKeyToItem(HWND hwnd, UINT vkCode, UINT caretPos, HWND hwndCtrl)
  1555. {
  1556. FBDATA *pfb = GetFolderBrowser(hwnd);
  1557. if (!pfb) return -1;
  1558. if (pfb->hwndActive == hwndCtrl)
  1559. {
  1560. size_t activeColumn = FolderBrowser_GetListBoxColumn(pfb->hwndActive);
  1561. switch(vkCode)
  1562. {
  1563. case VK_LEFT:
  1564. if (0 != (0x80000000 & GetAsyncKeyState(VK_CONTROL)) ||
  1565. 0 != (0x80000000 & GetAsyncKeyState(VK_SHIFT))) break;
  1566. if (activeColumn > 0)
  1567. {
  1568. pfb->focusedColumn = -1;
  1569. FolderBrowser_UpdateActiveColumn(hwnd, activeColumn - 1);
  1570. pfb->focusedColumn = (int)FolderBrowser_GetListBoxColumn(pfb->hwndActive);
  1571. FolderBrowser_OnSelectionChanged(hwnd, TRUE, TRUE);
  1572. }
  1573. return -2;
  1574. case VK_RIGHT:
  1575. if (0 != (0x80000000 & GetAsyncKeyState(VK_CONTROL)) ||
  1576. 0 != (0x80000000 & GetAsyncKeyState(VK_SHIFT))) break;
  1577. if (activeColumn < (pfb->pColumns->size() -1))
  1578. {
  1579. FBCOLUMN *pc = &pfb->pColumns->at(activeColumn + 1);
  1580. if (pc->count > 0)
  1581. {
  1582. pc->firstSelected = 0;
  1583. pfb->focusedColumn = -1;
  1584. FolderBrowser_UpdateActiveColumn(hwnd, activeColumn + 1);
  1585. pfb->focusedColumn = (int)FolderBrowser_GetListBoxColumn(pfb->hwndActive);
  1586. FolderBrowser_OnSelectionChanged(hwnd, TRUE, TRUE);
  1587. }
  1588. }
  1589. return -2;
  1590. }
  1591. }
  1592. return -1;
  1593. }
  1594. static void FolderBrowser_OnWindowPosChanged(HWND hwnd, WINDOWPOS *pwp)
  1595. {
  1596. FBDATA *pfb = GetFolderBrowser(hwnd);
  1597. if (!pfb) return;
  1598. if (0 == (SWP_NOSIZE & pwp->flags) || (SWP_FRAMECHANGED & pwp->flags))
  1599. {
  1600. RECT rc, rw;
  1601. GetClientRect(hwnd, &rc);
  1602. SCROLLINFO si;
  1603. INT dx = 0;
  1604. LONG totalWidth = 0;
  1605. for(size_t i = 0; i < pfb->pColumns->size(); i++) totalWidth += (pfb->pColumns->at(i).width + SIZER_WIDTH);
  1606. si.cbSize = sizeof(SCROLLINFO);
  1607. si.fMask = SIF_PAGE | SIF_RANGE | SIF_POS;
  1608. if (!GetScrollInfo(hwnd, SB_HORZ, &si))
  1609. {
  1610. ZeroMemory(&si, sizeof(SCROLLINFO));
  1611. si.cbSize = sizeof(SCROLLINFO);
  1612. si.fMask = SIF_PAGE | SIF_RANGE | SIF_POS;
  1613. si.nMax = 100;
  1614. si.nPage = 10;
  1615. SetScrollInfo(hwnd, SB_HORZ, &si, FALSE);
  1616. }
  1617. if ( (si.nPage != (rc.right - rc.left) || si.nMax < totalWidth))
  1618. {
  1619. si.fMask = SIF_PAGE;
  1620. if (si.nMax != totalWidth)
  1621. {
  1622. si.nMax = totalWidth;
  1623. si.fMask |= SIF_RANGE;
  1624. }
  1625. si.nPage = rc.right - rc.left;
  1626. if ((si.nPos + si.nPage) > (UINT)si.nMax && si.nPos > si.nMin)
  1627. {
  1628. dx = si.nPos;
  1629. si.nPos = si.nMax - si.nPage;
  1630. if (si.nPos < si.nMin) si.nPos = si.nMin;
  1631. dx -= si.nPos;
  1632. si.fMask |= SIF_POS;
  1633. InvalidateRect(hwnd, NULL, FALSE);
  1634. }
  1635. if (0 == si.nMax)
  1636. {
  1637. si.nMax = 100;
  1638. si.nPage = si.nMax;
  1639. }
  1640. SetScrollInfo(hwnd, SB_HORZ, &si, FALSE);
  1641. }
  1642. if (pfb->hwndActive &&
  1643. (WS_VISIBLE & GetWindowLongPtrW(pfb->hwndActive, GWL_STYLE))
  1644. && GetWindowRect(pfb->hwndActive, &rw))
  1645. {
  1646. if (rw.bottom - rw.top != rc.bottom - rc.top || dx != 0)
  1647. {
  1648. if (dx) MapWindowPoints(HWND_DESKTOP, hwnd, (POINT*)&rw, 2);
  1649. SetWindowPos(pfb->hwndActive, NULL, rw.left + dx, rw.top, rw.right - rw.left, rc.bottom - rc.top,
  1650. SWP_NOACTIVATE | SWP_NOZORDER |
  1651. ((0 == dx) ? SWP_NOMOVE : 0) |
  1652. ((rw.bottom - rw.top == rc.bottom - rc.top) ? SWP_NOSIZE : 0));
  1653. if (0 == (SWP_NOREDRAW & pwp->flags)) InvalidateRect(pfb->hwndActive, NULL, TRUE);
  1654. }
  1655. }
  1656. if (0 == (SWP_NOREDRAW & pwp->flags))
  1657. {
  1658. GetWindowRect(pfb->hwndDraw, &rw);
  1659. if (rw.bottom - rw.top != rc.bottom - rc.top) InvalidateRect(hwnd, NULL, FALSE);
  1660. }
  1661. }
  1662. }
  1663. static void UpdateAfterScroll(HWND hwnd, INT scrollPos, BOOL fRedraw)
  1664. {
  1665. FBDATA *pfb = GetFolderBrowser(hwnd);
  1666. if (pfb && (WS_VISIBLE & GetWindowLongPtrW(pfb->hwndActive, GWL_STYLE)))
  1667. {
  1668. RECT rc;
  1669. size_t a = FolderBrowser_GetListBoxColumn(pfb->hwndActive);
  1670. GetClientRect(hwnd, &rc);
  1671. rc.left -= scrollPos;
  1672. for (size_t i = 0; i < a; i++) rc.left += (pfb->pColumns->at(i).width + SIZER_WIDTH);
  1673. SetWindowPos(pfb->hwndActive, NULL, rc.left, rc.top, 0, 0,
  1674. SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOSENDCHANGING | SWP_NOSIZE |
  1675. ((fRedraw) ? 0 : SWP_NOREDRAW));
  1676. }
  1677. if (fRedraw)
  1678. {
  1679. InvalidateRect(hwnd, NULL, TRUE);
  1680. UpdateWindow(hwnd);
  1681. }
  1682. }
  1683. static void FolderBrowser_OnHScroll(HWND hwnd, UINT uCode, UINT uPos)
  1684. {
  1685. SCROLLINFO si;
  1686. FBDATA *pfb = GetFolderBrowser(hwnd);
  1687. if (!pfb) return;
  1688. si.cbSize = sizeof(SCROLLINFO);
  1689. si.fMask = SIF_PAGE | SIF_RANGE | SIF_POS;
  1690. if (!GetScrollInfo(hwnd, SB_HORZ, &si)) return;
  1691. INT line = si.nPage / 10;
  1692. if (line < 1) line = 1;
  1693. INT dx = 0;
  1694. static INT startPos = 0;
  1695. static INT scrollCount = 0;
  1696. switch(uCode)
  1697. {
  1698. case SB_LINELEFT: dx = -line; break;
  1699. case SB_LINERIGHT: dx = line; break;
  1700. case SB_PAGELEFT: dx = -((int)si.nPage); break;
  1701. case SB_PAGERIGHT: dx = ((int)si.nPage); break;
  1702. case SB_THUMBTRACK:
  1703. UpdateAfterScroll(hwnd, si.nPos, TRUE);
  1704. return;
  1705. case SB_LEFT:
  1706. si.fMask = SIF_POS;
  1707. si.nPos = 0;
  1708. SetScrollInfo(hwnd, SB_HORZ, &si, FALSE);
  1709. UpdateAfterScroll(hwnd, si.nPos, TRUE);
  1710. return;
  1711. case SB_RIGHT:
  1712. si.fMask = SIF_POS;
  1713. si.nPos = si.nMax - si.nPage;
  1714. SetScrollInfo(hwnd, SB_HORZ, &si, FALSE);
  1715. UpdateAfterScroll(hwnd, si.nPos, TRUE);
  1716. return;
  1717. case SB_ENDSCROLL:
  1718. if (-1 != hiddenActive)
  1719. {
  1720. RECT rw;
  1721. GetWindowRect(pfb->hwndActive, &rw);
  1722. MapWindowPoints(HWND_DESKTOP, hwnd, (POINT*)&rw, 1);
  1723. SetWindowLongPtrW(pfb->hwndActive, GWLP_USERDATA, (LONGX86)hiddenActive);
  1724. dx = startPos - si.nPos;
  1725. SetWindowPos(pfb->hwndActive, NULL, rw.left + dx, rw.top, 0, 0,
  1726. SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOSIZE | SWP_NOSENDCHANGING);
  1727. ShowWindow(pfb->hwndActive, SW_SHOWNA);
  1728. if (pfb->focusedColumn == hiddenActive) SetFocus(pfb->hwndActive);
  1729. hiddenActive = -1;
  1730. startPos = si.nPos;
  1731. }
  1732. scrollCount = 0;
  1733. return;
  1734. default:
  1735. return;
  1736. }
  1737. if (dx != 0)
  1738. {
  1739. if ((si.nPos + dx) < si.nMin) dx = si.nMin - si.nPos;
  1740. else if ((si.nPos + dx) > (si.nMax - (INT)si.nPage))
  1741. {
  1742. dx = si.nMax - si.nPos - si.nPage;
  1743. if (dx < 0) dx = 0;
  1744. }
  1745. if (dx != 0)
  1746. {
  1747. SendMessageW(hwnd, WM_SETREDRAW, FALSE, 0L);
  1748. if (pfb && -1 == hiddenActive && (WS_VISIBLE & GetWindowLongPtrW(pfb->hwndActive, GWL_STYLE)))
  1749. {
  1750. hiddenActive = FolderBrowser_GetListBoxColumn(pfb->hwndActive);
  1751. if (hiddenActive < pfb->pColumns->size())
  1752. {
  1753. FBCOLUMN *pc = &pfb->pColumns->at(hiddenActive);
  1754. if (pc) pc->firstVisible = (INT)SendMessageW(pfb->hwndActive, LB_GETTOPINDEX, 0, 0L);
  1755. if (pfb->focusedColumn == hiddenActive) SetFocus(hwnd);
  1756. SetWindowLongPtrW(pfb->hwndActive, GWLP_USERDATA, (LONGX86)-1);
  1757. ShowWindow(pfb->hwndActive, SW_HIDE);
  1758. startPos = si.nPos;
  1759. }
  1760. }
  1761. si.fMask = SIF_POS;
  1762. si.nPos += dx;
  1763. SetScrollInfo(hwnd, SB_HORZ, &si, FALSE);
  1764. SendMessageW(hwnd, WM_SETREDRAW, TRUE, 0L);
  1765. if (scrollCount)
  1766. {
  1767. ScrollWindowEx(hwnd, -dx, 0, NULL, NULL, NULL, NULL, SW_INVALIDATE | SW_ERASE);
  1768. // InvalidateRect(hwnd, NULL, TRUE);
  1769. }
  1770. else
  1771. {
  1772. ScrollWindowEx(hwnd, -dx, 0, NULL, NULL, NULL, NULL, MAKELPARAM(SW_SMOOTHSCROLL, 150));
  1773. }
  1774. UpdateWindow(hwnd);
  1775. }
  1776. scrollCount++;
  1777. }
  1778. }
  1779. static void FolderBroser_OnPrintClient(HWND hwnd, HDC hdc, UINT options)
  1780. {
  1781. PAINTSTRUCT ps;
  1782. ZeroMemory(&ps, sizeof(PAINTSTRUCT));
  1783. ps.hdc = hdc;
  1784. GetClientRect(hwnd, &ps.rcPaint);
  1785. ps.fErase = (0 != (PRF_ERASEBKGND & options));
  1786. FolderBrowser_Draw(hwnd, &ps);
  1787. }
  1788. static void FolderBrowser_OnMouseWheel(HWND hwnd, UINT vkCode, INT delta, POINTS pts)
  1789. {
  1790. if (MK_CONTROL == vkCode)
  1791. {
  1792. SendMessageW(hwnd, WM_HSCROLL, MAKEWPARAM(((delta > 0) ? SB_LINELEFT : SB_LINERIGHT), 0), NULL);
  1793. SendMessageW(hwnd, WM_HSCROLL, MAKEWPARAM(SB_ENDSCROLL, 0), NULL);
  1794. }
  1795. }
  1796. static BOOL FolderBrowser_OnSetCursor(HWND hwnd, HWND hwndCursor, UINT hitTest, UINT uMsg)
  1797. {
  1798. FBDATA *pfb = GetFolderBrowser(hwnd);
  1799. SCROLLINFO si;
  1800. si.cbSize = sizeof(SCROLLINFO);
  1801. si.fMask = SIF_POS;
  1802. if(!GetScrollInfo(hwnd, SB_HORZ, &si)) si.nPos = 0;
  1803. if(pfb && HTCLIENT == hitTest)
  1804. {
  1805. POINT pt;
  1806. GetCursorPos(&pt);
  1807. MapWindowPoints(HWND_DESKTOP, hwnd, &pt, 1);
  1808. LONG left = -si.nPos;
  1809. for (size_t i=0, count = pfb->pColumns->size(); i < count; i++)
  1810. {
  1811. left += pfb->pColumns->at(i).width;
  1812. if (pt.x >= (left - SIZER_OVERLAP_LEFT) && pt.x < (left + SIZER_WIDTH + SIZER_OVERLAP_RIGHT))
  1813. {
  1814. if (sizerHover != i)
  1815. {
  1816. SetCursor(LoadCursor(NULL, IDC_SIZEWE));
  1817. if (IsChild(GetActiveWindow(), hwnd))
  1818. {
  1819. RECT rc;
  1820. GetClientRect(hwnd, &rc);
  1821. rc.left = left;
  1822. rc.right = left + SIZER_WIDTH;
  1823. sizerHover = i;
  1824. InvalidateRect(hwnd, &rc, FALSE);
  1825. TRACKMOUSEEVENT tm;
  1826. tm.cbSize = sizeof(TRACKMOUSEEVENT);
  1827. tm.dwFlags = TME_LEAVE;
  1828. tm.hwndTrack = hwnd;
  1829. _TrackMouseEvent(&tm);
  1830. }
  1831. }
  1832. return TRUE;
  1833. }
  1834. left += SIZER_WIDTH;
  1835. if (left > pt.x) break;
  1836. }
  1837. }
  1838. if (sizerHover < pfb->pColumns->size())
  1839. {
  1840. RECT rc;
  1841. GetClientRect(hwnd, &rc);
  1842. rc.right = rc.left - si.nPos;
  1843. for (size_t i = 0; i <= sizerHover; i++) rc.right += (pfb->pColumns->at(i).width + SIZER_WIDTH);
  1844. rc.left = rc.right - SIZER_WIDTH;
  1845. sizerHover = -1;
  1846. InvalidateRect(hwnd, &rc, FALSE);
  1847. }
  1848. DefWindowProcW(hwnd, WM_SETCURSOR, (WPARAM)hwndCursor, MAKELPARAM(hitTest, uMsg));
  1849. return TRUE;
  1850. }
  1851. static BOOL FolderBrowser_OnSetFileSystemInfo(HWND hwnd, FILESYSTEMINFO *pfs)
  1852. {
  1853. FBDATA *pfb = GetFolderBrowser(hwnd);
  1854. if (!pfb) return FALSE;
  1855. if (!pfs)
  1856. {
  1857. pfb->filesystem.fnFindFirstFile = FindFirstFileW;
  1858. pfb->filesystem.fnFindNextFile = FindNextFileW;
  1859. pfb->filesystem.fnFindClose = FindClose;
  1860. }
  1861. else
  1862. {
  1863. if (pfs->cbSize != sizeof(FILESYSTEMINFO) ||
  1864. !pfs->fnFindFirstFile || !pfs->fnFindNextFile || !pfs->fnFindClose) return FALSE;
  1865. CopyMemory(&pfb->filesystem, pfs, sizeof(FILESYSTEMINFO));
  1866. }
  1867. return TRUE;
  1868. }
  1869. static BOOL FolderBrowser_OnGetFileSystemInfo(HWND hwnd, FILESYSTEMINFO *pfs)
  1870. {
  1871. FBDATA *pfb = GetFolderBrowser(hwnd);
  1872. if (!pfb || !pfs || pfs->cbSize != sizeof(FILESYSTEMINFO)) return FALSE;
  1873. CopyMemory(pfs, &pfb->filesystem, sizeof(FILESYSTEMINFO));
  1874. return TRUE;
  1875. }
  1876. static void FolderBrowser_OnMouseLeave(HWND hwnd)
  1877. {
  1878. FBDATA *pfb = GetFolderBrowser(hwnd);
  1879. if (pfb && sizerHover < pfb->pColumns->size())
  1880. {
  1881. RECT rc;
  1882. GetClientRect(hwnd, &rc);
  1883. SCROLLINFO si;
  1884. si.cbSize = sizeof(SCROLLINFO);
  1885. si.fMask = SIF_POS;
  1886. if(!GetScrollInfo(hwnd, SB_HORZ, &si)) si.nPos = 0;
  1887. rc.right = rc.left - si.nPos;
  1888. for (size_t i = 0; i <= sizerHover; i++) rc.right += (pfb->pColumns->at(i).width + SIZER_WIDTH);
  1889. rc.left = rc.right - SIZER_WIDTH;
  1890. sizerHover = -1;
  1891. InvalidateRect(hwnd, &rc, FALSE);
  1892. }
  1893. POINTS pts = { -1, -1};
  1894. FolderBrowser_UpdateScrollHovering(hwnd, 0, pts);
  1895. }
  1896. static void FolderBrowser_OnParentNotify(HWND hwnd, UINT message, LPARAM lParam)
  1897. {
  1898. switch(LOWORD(message))
  1899. {
  1900. case WM_RBUTTONDOWN:
  1901. {
  1902. FolderBrowser_HideActive(hwnd);
  1903. DWORD flags = 0;
  1904. if (0 != (0x80000000 & GetAsyncKeyState(VK_CONTROL))) flags |= MK_CONTROL;
  1905. if (0 != (0x80000000 & GetAsyncKeyState(VK_SHIFT))) flags |= MK_SHIFT;
  1906. if (0 != (0x80000000 & GetAsyncKeyState(VK_LBUTTON))) flags |= MK_LBUTTON;
  1907. if (0 != (0x80000000 & GetAsyncKeyState(VK_RBUTTON))) flags |= MK_RBUTTON;
  1908. if (0 != (0x80000000 & GetAsyncKeyState(VK_MBUTTON))) flags |= MK_MBUTTON;
  1909. if (0 != (0x80000000 & GetAsyncKeyState(VK_XBUTTON1))) flags |= MK_XBUTTON1;
  1910. if (0 != (0x80000000 & GetAsyncKeyState(VK_XBUTTON2))) flags |= MK_XBUTTON1;
  1911. SendMessageW(hwnd, LOWORD(message), flags, lParam);
  1912. }
  1913. break;
  1914. }
  1915. }
  1916. LRESULT CALLBACK FolderBrowser_WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  1917. {
  1918. switch(uMsg)
  1919. {
  1920. case WM_CREATE: return FolderBrowser_OnCreateWindow(hwnd, (CREATESTRUCT*)lParam);
  1921. case WM_DESTROY: FolderBrowser_OnDestroyWindow(hwnd); return 0;
  1922. case WM_PAINT: FolderBrowser_OnPaint(hwnd); return 0;
  1923. case WM_DRAWITEM: return (LRESULT)FolderBrowser_OnDrawItem(hwnd, (INT)wParam, (DRAWITEMSTRUCT*)lParam);
  1924. case WM_SETFONT: FolderBrowser_OnSetFont(hwnd, (HFONT)wParam, (BOOL)LOWORD(lParam)); break;
  1925. case WM_SETFOCUS: FolderBrowser_OnSetFocus(hwnd, (HWND)wParam); break;
  1926. case WM_KILLFOCUS: FolderBrowser_OnKillFocus(hwnd, (HWND)wParam); return 0;
  1927. case WM_GETDLGCODE: return FolderBrowser_OnGetDlgCode(hwnd, (INT)wParam, (MSG*)lParam);
  1928. case WM_LBUTTONDOWN: FolderBrowser_OnLButtonDown(hwnd, (UINT)wParam, MAKEPOINTS(lParam)); return 0;
  1929. case WM_LBUTTONUP: FolderBrowser_OnLButtonUp(hwnd, (UINT)wParam, MAKEPOINTS(lParam)); return 0;
  1930. case WM_LBUTTONDBLCLK: FolderBrowser_OnLButtonDblClick(hwnd, (UINT)wParam, MAKEPOINTS(lParam)); return 0;
  1931. case WM_RBUTTONDOWN: FolderBrowser_OnRButtonDown(hwnd, (UINT)wParam, MAKEPOINTS(lParam)); return 0;
  1932. case WM_RBUTTONUP: FolderBrowser_OnRButtonUp(hwnd, (UINT)wParam, MAKEPOINTS(lParam)); return 0;
  1933. case WM_MOUSEMOVE: FolderBrowser_OnMouseMove(hwnd, (UINT)wParam, MAKEPOINTS(lParam)); return 0;
  1934. case WM_WINDOWPOSCHANGED: FolderBrowser_OnWindowPosChanged(hwnd, (WINDOWPOS*)lParam); return 0;
  1935. case WM_KEYDOWN: FolderBrowser_OnKeyDown(hwnd, (UINT)wParam, (UINT)lParam); return 0;
  1936. case WM_COMMAND: FolderBorwser_OnCommand(hwnd, LOWORD(wParam), HIWORD(wParam), (HWND)lParam); return 0;
  1937. case WM_VKEYTOITEM: return FolderBrowser_OnVKeyToItem(hwnd, LOWORD(wParam), HIWORD(wParam), (HWND)lParam);
  1938. case WM_HSCROLL: FolderBrowser_OnHScroll(hwnd, LOWORD(wParam), HIWORD(wParam)); return 0;
  1939. case WM_PRINTCLIENT: FolderBroser_OnPrintClient(hwnd, (HDC)wParam, (UINT)lParam); return 0;
  1940. case WM_SETCURSOR: return (LRESULT)FolderBrowser_OnSetCursor(hwnd, (HWND)wParam, LOWORD(lParam), HIWORD(lParam));
  1941. case WM_MOUSEWHEEL: FolderBrowser_OnMouseWheel(hwnd, GET_KEYSTATE_WPARAM(wParam), GET_WHEEL_DELTA_WPARAM(wParam), MAKEPOINTS(lParam)); return 0;
  1942. case WM_MOUSELEAVE: FolderBrowser_OnMouseLeave(hwnd); return 0;
  1943. case WM_MOUSEACTIVATE:
  1944. if (HIWORD(lParam) == WM_MBUTTONDOWN)
  1945. {
  1946. return MA_NOACTIVATEANDEAT;
  1947. }
  1948. break;
  1949. case WM_MEASUREITEM: return (LRESULT)FolderBrowser_OnMeasureItem(hwnd, (INT)wParam, (MEASUREITEMSTRUCT*)lParam);
  1950. case WM_PARENTNOTIFY: FolderBrowser_OnParentNotify(hwnd, (UINT)wParam, lParam); return 0;
  1951. case FBM_GETBKCOLOR: return (LRESULT)FolderBrowser_OnGetBkColor(hwnd);
  1952. case FBM_SETBKCOLOR: return (LRESULT)FolderBrowser_OnSetBkColor(hwnd, (COLORREF)lParam);
  1953. case FBM_GETTEXTCOLOR: return (LRESULT)FolderBrowser_OnGetTextColor(hwnd);
  1954. case FBM_SETTEXTCOLOR: return (LRESULT)FolderBrowser_OnSetTextColor(hwnd, (COLORREF)lParam);
  1955. case FBM_GETFOLDERBROWSERINFO: return (LRESULT)FolderBrowser_OnGetFolderBrowserInfo(hwnd, (FOLDERBROWSERINFO*)lParam);
  1956. case FBM_SETROOT: return (LRESULT)FolderBrowser_OnSetRootFolder(hwnd, (LPCWSTR)lParam);
  1957. case FBM_GETROOT: return (LRESULT)FolderBrowser_OnGetRootFolder(hwnd, (LPWSTR)lParam, (INT)wParam);
  1958. case FBM_SETFILESYSTEMINFO: return (LRESULT)FolderBrowser_OnSetFileSystemInfo(hwnd, (FILESYSTEMINFO*)lParam);
  1959. case FBM_GETFILESYSTEMINFO: return (LRESULT)FolderBrowser_OnGetFileSystemInfo(hwnd, (FILESYSTEMINFO*)lParam);
  1960. case FBM_GETCURRENTPATH: return (LRESULT)FolderBrowser_OnGetCurrentPath(hwnd, (LPWSTR)lParam, (INT)wParam);
  1961. case FBM_SETCURRENTPATH: return (LRESULT)FolderBrowser_OnSetCurrentPath(hwnd, (LPWSTR)lParam, (BOOL)wParam);
  1962. case FBM_ENSUREVISIBLE: return (LRESULT)FolderBrowser_OnEnsureVisible(hwnd, LOWORD(wParam), HIWORD(wParam));
  1963. }
  1964. return DefWindowProcW(hwnd, uMsg, wParam, lParam);
  1965. }