HeaderIconList.cpp 28 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115
  1. #include "main.h"
  2. #include "../gen_ml/ml.h"
  3. #include "../gen_ml/ml_ipc_0313.h"
  4. #include "../Winamp/gen.h"
  5. #define WM_EX_GETREALLIST (WM_USER + 0x01)
  6. #define WM_EX_UNLOCKREDRAW (WM_USER + 0x02)
  7. #define WM_EX_UPDATESCROLLINFO (WM_USER + 0x03)
  8. #define WM_EX_GETCOUNTPERPAGE (WM_USER + 0x04)
  9. #define LVN_EX_SIZECHANGED (LVN_LAST)
  10. #define IWF_NO 0x0000
  11. #define IWF_ALL 0x00FF
  12. #define IWF_CONTAINER 0x0001
  13. #define IWF_LISTVIEW 0x0002
  14. #define IWF_HEADER 0x0004
  15. #define IWF_UPDATENOW 0x1000
  16. BOOL
  17. CopyListColumnToHeaderItem(const LVCOLUMNW *column, HDITEMW *item)
  18. {
  19. if (NULL == column || NULL == item)
  20. return FALSE;
  21. item->mask = 0;
  22. if (0 != (LVCF_FMT & column->mask))
  23. {
  24. item->mask |= HDI_FORMAT;
  25. item->fmt = 0;
  26. switch((LVCFMT_JUSTIFYMASK & column->fmt))
  27. {
  28. case LVCFMT_RIGHT:
  29. item->fmt |= HDF_RIGHT;
  30. break;
  31. case LVCFMT_CENTER:
  32. item->fmt |= HDF_CENTER;
  33. break;
  34. default:
  35. item->fmt |= HDF_LEFT;
  36. break;
  37. }
  38. if (0 != (LVCFMT_IMAGE & column->fmt))
  39. item->fmt |= HDF_IMAGE;
  40. if (0 != (LVCFMT_BITMAP_ON_RIGHT & column->fmt))
  41. item->fmt |= HDF_BITMAP_ON_RIGHT;
  42. }
  43. if (0 != (LVCF_WIDTH & column->mask))
  44. {
  45. item->mask |= HDI_WIDTH;
  46. item->cxy = column->cx;
  47. }
  48. if (0 != (LVCF_TEXT & column->mask))
  49. {
  50. item->mask |= HDI_TEXT;
  51. item->pszText = column->pszText;
  52. item->cchTextMax = column->cchTextMax;
  53. }
  54. if (0 != (LVCF_IMAGE & column->mask))
  55. {
  56. item->mask |= HDI_IMAGE;
  57. item->iImage = column->iImage;
  58. }
  59. if (0 != (LVCF_ORDER & column->mask))
  60. {
  61. item->mask |= HDI_ORDER;
  62. item->iOrder = column->iOrder;
  63. }
  64. return TRUE;
  65. }
  66. BOOL
  67. CopyHeaderItemToListColumn(const HDITEMW *item, LVCOLUMNW *column)
  68. {
  69. if (NULL == column || NULL == item)
  70. return FALSE;
  71. column->mask = 0;
  72. if (0 != (HDI_FORMAT& item->mask))
  73. {
  74. column->mask |= LVCF_FMT ;
  75. column->fmt = 0;
  76. switch((HDF_JUSTIFYMASK & item->fmt))
  77. {
  78. case HDF_RIGHT:
  79. column->fmt |= LVCFMT_RIGHT;
  80. break;
  81. case HDF_CENTER:
  82. column->fmt |= LVCFMT_CENTER;
  83. break;
  84. default:
  85. column->fmt |= LVCFMT_LEFT;
  86. break;
  87. }
  88. if (0 != (HDF_IMAGE & item->fmt))
  89. column->fmt |= LVCFMT_IMAGE;
  90. if (0 != (HDF_BITMAP_ON_RIGHT & item->fmt))
  91. column->fmt |= LVCFMT_BITMAP_ON_RIGHT;
  92. }
  93. if (0 != (HDI_WIDTH & item->mask))
  94. {
  95. column->mask |= LVCF_WIDTH;
  96. column->cx = item->cxy;
  97. }
  98. if (0 != (HDI_TEXT & item->mask))
  99. {
  100. column->mask |= LVCF_TEXT;
  101. column->pszText = item->pszText;
  102. column->cchTextMax = item->cchTextMax;
  103. }
  104. if (0 != (HDI_IMAGE & item->mask))
  105. {
  106. column->mask |= LVCF_IMAGE;
  107. column->iImage = item->iImage;
  108. }
  109. if (0 != (HDI_ORDER & item->mask))
  110. {
  111. column->mask |= LVCF_ORDER;
  112. column->iOrder = item->iOrder;
  113. }
  114. return TRUE;
  115. }
  116. static BOOL UpdateScrollInfo(HWND hwnd, UINT fMask, BOOL bRedraw)
  117. {
  118. HWND hwndList;
  119. SCROLLINFO si;
  120. BOOL bUpdateBars(FALSE);
  121. hwndList = GetDlgItem(hwnd,2);
  122. si.cbSize= sizeof(SCROLLINFO);
  123. si.fMask = SIF_RANGE | SIF_PAGE | SIF_POS;
  124. if (!hwndList || !GetScrollInfo(hwnd, SB_VERT, &si))
  125. return FALSE;
  126. if (SIF_RANGE & fMask)
  127. {
  128. RECT rc, rv;
  129. UINT nPage;
  130. INT nMax;
  131. BOOL bScrollVisible;
  132. HDLAYOUT headerLayout;
  133. WINDOWPOS headerPos;
  134. HWND hwndHeader = GetDlgItem(hwnd, 3);
  135. if (!hwndHeader)
  136. return FALSE;
  137. GetClientRect(hwnd, &rc);
  138. ListView_GetViewRect(hwndList,&rv);
  139. headerLayout.prc = &rc;
  140. headerLayout.pwpos = &headerPos;
  141. SendMessageW(hwndHeader, HDM_LAYOUT, 0, (LPARAM)&headerLayout);
  142. bScrollVisible = (si.nMax > 0 && si.nPage > 0 && (INT)si.nPage < si.nMax);
  143. nMax = rv.bottom - rv.top;
  144. nPage = (rc.bottom - rc.top);
  145. if (si.nMax != nMax || si.nPage != nPage)
  146. {
  147. si.nMin = 0;
  148. si.nMax = nMax;
  149. si.nPage = nPage;
  150. SetScrollInfo(hwnd, SB_VERT, &si, FALSE);
  151. bUpdateBars = TRUE;
  152. if (bScrollVisible != (si.nMax > 0 && si.nPage > 0 && (INT)si.nPage < si.nMax))
  153. {
  154. MLSkinnedScrollWnd_UpdateBars(hwnd, bRedraw);
  155. GetClientRect(hwnd, &rc);
  156. headerLayout.prc = &rc;
  157. headerLayout.pwpos = &headerPos;
  158. SendMessageW(hwndHeader, HDM_LAYOUT, 0, (LPARAM)&headerLayout);
  159. headerPos.flags |= SWP_NOREDRAW;
  160. SetWindowPos(hwndHeader, headerPos.hwndInsertAfter, headerPos.x, headerPos.y,
  161. headerPos.cx, headerPos.cy, headerPos.flags);
  162. SetWindowPos(hwndList, NULL, rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top,
  163. SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOMOVE | SWP_NOREDRAW);
  164. if (FALSE != bRedraw)
  165. RedrawWindow(hwnd, NULL, NULL, RDW_INVALIDATE | RDW_ALLCHILDREN);
  166. bUpdateBars = FALSE;
  167. }
  168. }
  169. }
  170. if (SIF_POS & fMask)
  171. {
  172. POINT p;
  173. if (FALSE != SendMessageW(hwndList, LVM_GETORIGIN, (WPARAM)0, (LPARAM)&p))
  174. {
  175. if (p.y < si.nMin)
  176. p.y = si.nMin;
  177. if (p.y > (si.nMax - (int)si.nPage))
  178. p.y = si.nMax - si.nPage;
  179. if (p.y != si.nPos)
  180. {
  181. si.nPos = p.y;
  182. si.fMask = SIF_POS;
  183. SetScrollInfo(hwnd, SB_VERT, &si, TRUE);
  184. bUpdateBars = TRUE;
  185. }
  186. }
  187. }
  188. if (bUpdateBars)
  189. MLSkinnedScrollWnd_UpdateBars(hwnd, bRedraw);
  190. return TRUE;
  191. }
  192. static void
  193. UpdateFontMetrics(HWND hwnd, BOOL redraw)
  194. {
  195. HWND controlWindow;
  196. RECT headerRect;
  197. unsigned int windowStyle;
  198. windowStyle = GetWindowLongPtr(hwnd, GWL_STYLE);
  199. if(0 != (WS_VISIBLE & windowStyle))
  200. SetWindowLongPtrW(hwnd, GWL_STYLE, windowStyle & ~WS_VISIBLE);
  201. controlWindow = GetDlgItem(hwnd, 3);
  202. if (NULL != controlWindow)
  203. {
  204. MLSkinnedHeader_SetHeight(controlWindow, -1);
  205. if (FALSE == GetWindowRect(controlWindow, &headerRect))
  206. SetRectEmpty(&headerRect);
  207. }
  208. else
  209. SetRectEmpty(&headerRect);
  210. controlWindow = GetDlgItem(hwnd, 2);
  211. if (NULL != controlWindow)
  212. {
  213. RECT rect;
  214. if (FALSE != GetClientRect(hwnd, &rect))
  215. {
  216. SetWindowPos(controlWindow, NULL,
  217. rect.left, rect.top + headerRect.bottom - headerRect.top,
  218. rect.right - rect.left, (rect.bottom - rect.top) - (headerRect.bottom - headerRect.top),
  219. SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOREDRAW | SWP_NOCOPYBITS);
  220. }
  221. }
  222. if (0 != (WS_VISIBLE & windowStyle))
  223. {
  224. windowStyle = GetWindowLongPtr(hwnd, GWL_STYLE);
  225. if (0 == (WS_VISIBLE & windowStyle))
  226. {
  227. windowStyle |= WS_VISIBLE;
  228. SetWindowLongPtrW(hwnd, GWL_STYLE, windowStyle);
  229. }
  230. if (FALSE != redraw)
  231. RedrawWindow(hwnd, NULL, NULL, RDW_INVALIDATE | RDW_ERASE | RDW_ALLCHILDREN);
  232. }
  233. }
  234. static HHOOK hook = NULL;
  235. static HWND hwndToMonitor = NULL;
  236. typedef struct UpdateSelection
  237. {
  238. BOOL active;
  239. int iFrom;
  240. int iTo;
  241. }UpdateSelection;
  242. typedef struct ListViewData
  243. {
  244. WNDPROC prevWindowProc;
  245. UpdateSelection updateSelection;
  246. } ListViewData;
  247. #define LVCWP_NORMAL 0
  248. #define LVCWP_UPDATESCROLLINFO (1 << 0)
  249. static LRESULT CALLBACK HookProc(int nCode, WPARAM wParam, LPARAM lParam)
  250. {
  251. MSG *pMsg = (MSG*)lParam;
  252. if (pMsg->hwnd == hwndToMonitor)
  253. {
  254. switch(pMsg->message)
  255. {
  256. case WM_LBUTTONUP:
  257. case WM_RBUTTONUP:
  258. {
  259. LRESULT result = CallNextHookEx(hook, nCode, wParam, lParam);
  260. UnhookWindowsHookEx(hook);
  261. hwndToMonitor = NULL;
  262. hook = NULL;
  263. return result;
  264. }
  265. case WM_MOUSEMOVE:
  266. if ((MK_LBUTTON | MK_RBUTTON) & pMsg->wParam)
  267. {
  268. RECT rw;
  269. POINTS pts(MAKEPOINTS(pMsg->lParam));
  270. POINT pt;
  271. POINTSTOPOINT(pt, pts);
  272. MapWindowPoints(pMsg->hwnd, HWND_DESKTOP, &pt, 1);
  273. GetWindowRect(pMsg->hwnd, &rw);
  274. if (pt.y < rw.top || pt.y > rw.bottom)
  275. {
  276. HWND hwndParent = GetParent(pMsg->hwnd);
  277. if (hwndParent)
  278. {
  279. SCROLLINFO si;
  280. si.cbSize = sizeof(SCROLLINFO);
  281. si.fMask = SIF_RANGE | SIF_POS | SIF_PAGE;
  282. if (GetScrollInfo(hwndParent, SB_VERT, &si))
  283. {
  284. if ((si.nPos > si.nMin && pt.y < rw.top) || (si.nPos < (si.nMax - (INT)si.nPage) && pt.y > rw.bottom))
  285. {
  286. SendMessageW(hwndParent, WM_SETREDRAW, FALSE, 0L);
  287. LRESULT result = CallNextHookEx(hook, nCode, wParam, lParam);
  288. PostMessageW(hwndParent, WM_EX_UPDATESCROLLINFO, SIF_POS, FALSE);
  289. PostMessageW(hwndParent, WM_EX_UNLOCKREDRAW, IWF_CONTAINER | IWF_LISTVIEW | IWF_UPDATENOW, 0L);
  290. return result;
  291. }
  292. }
  293. }
  294. }
  295. SleepEx(1, TRUE);
  296. }
  297. break;
  298. }
  299. }
  300. return CallNextHookEx(hook, nCode, wParam, lParam);
  301. }
  302. static void
  303. ListView_ScheduleSelectionUpdate(HWND hwnd, int iFrom, int iTo)
  304. {
  305. ListViewData *listView;
  306. listView = (ListViewData*)(LONG_PTR)GetWindowLongPtrW(hwnd, GWLP_USERDATA);
  307. if (NULL == listView)
  308. return;
  309. listView->updateSelection.iFrom = iFrom;
  310. listView->updateSelection.iTo = iTo;
  311. listView->updateSelection.active = TRUE;
  312. }
  313. static void
  314. ListView_UpdateSelection(HWND hwnd, int iFrom, int iTo)
  315. {
  316. HWND parentWindow;
  317. LVITEM item;
  318. int start, stop, i, lim;
  319. start = (int)SendMessageW(hwnd, LVM_GETSELECTIONMARK, 0, 0L);
  320. stop = (int)SendMessageW(hwnd, LVM_GETNEXTITEM, iFrom - 1, LVNI_FOCUSED);
  321. if (stop < start)
  322. {
  323. int tmp = start;
  324. start = stop;
  325. stop = tmp;
  326. }
  327. item.state = 0;
  328. item.stateMask = LVIS_SELECTED;
  329. if (start != iFrom)
  330. {
  331. if (start < iFrom)
  332. {
  333. i = start;
  334. lim = iFrom;
  335. }
  336. else
  337. {
  338. i = iFrom;
  339. lim = start;
  340. }
  341. i--;
  342. for(;;)
  343. {
  344. i = (int)SendMessageW(hwnd, LVM_GETNEXTITEM, (WPARAM)i,
  345. (LPARAM)(LVNI_ALL | LVNI_SELECTED));
  346. if (-1 == i || i >= lim)
  347. break;
  348. SendMessageW(hwnd, LVM_SETITEMSTATE, i, (LPARAM)&item);
  349. }
  350. }
  351. if (stop < iTo)
  352. {
  353. i = stop + 1;
  354. lim = iTo;
  355. i--;
  356. for(;;)
  357. {
  358. i = (int)SendMessageW(hwnd, LVM_GETNEXTITEM, (WPARAM)i,
  359. (LPARAM)(LVNI_ALL | LVNI_SELECTED));
  360. if (-1 == i || i > lim)
  361. break;
  362. SendMessageW(hwnd, LVM_SETITEMSTATE, i, (LPARAM)&item);
  363. }
  364. }
  365. parentWindow = GetAncestor(hwnd, GA_PARENT);
  366. if (NULL != parentWindow)
  367. {
  368. HWND notifyWindow;
  369. SendMessageW(parentWindow, WM_SETREDRAW, TRUE, 0L);
  370. RedrawWindow(parentWindow, NULL, NULL, RDW_INVALIDATE | RDW_ALLCHILDREN);
  371. notifyWindow = GetAncestor(parentWindow, GA_PARENT);
  372. if (NULL != notifyWindow)
  373. {
  374. NMLVODSTATECHANGE stateChange;
  375. stateChange.hdr.idFrom = GetWindowLongPtrW(parentWindow, GWLP_ID);
  376. stateChange.hdr.hwndFrom = parentWindow;
  377. stateChange.hdr.code = LVN_ODSTATECHANGED;
  378. stateChange.iFrom = start;
  379. stateChange.iTo = stop;
  380. stateChange.uNewState = LVIS_SELECTED;
  381. stateChange.uOldState = 0;
  382. SendMessageW(notifyWindow, WM_NOTIFY, stateChange.hdr.idFrom, (LPARAM)&stateChange);
  383. }
  384. }
  385. }
  386. static LRESULT
  387. ListView_CallWindowProc(ListViewData *listView, HWND hwnd, unsigned int uMsg, WPARAM wParam, LPARAM lParam,
  388. unsigned int flags)
  389. {
  390. LRESULT result;
  391. result = CallWindowProcW(listView->prevWindowProc, hwnd, uMsg, wParam, lParam);
  392. if (FALSE != listView->updateSelection.active)
  393. {
  394. listView->updateSelection.active = FALSE;
  395. ListView_UpdateSelection(hwnd, listView->updateSelection.iFrom, listView->updateSelection.iTo);
  396. }
  397. if (0 != (LVCWP_UPDATESCROLLINFO & flags))
  398. {
  399. HWND hwndParent;
  400. hwndParent = GetAncestor(hwnd, GA_PARENT);
  401. if (NULL != hwndParent)
  402. UpdateScrollInfo(hwndParent, SIF_POS, TRUE);
  403. }
  404. return result;
  405. }
  406. static LRESULT WINAPI
  407. ListView_WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  408. {
  409. ListViewData *listView;
  410. listView = (ListViewData*)(LONG_PTR)GetWindowLongPtrW(hwnd, GWLP_USERDATA);
  411. if (NULL == listView ||
  412. NULL == listView->prevWindowProc)
  413. {
  414. return DefWindowProcW(hwnd, uMsg, wParam, lParam);
  415. }
  416. switch(uMsg)
  417. {
  418. case WM_DESTROY:
  419. SetWindowLongPtrW(hwnd, GWLP_USERDATA, NULL);
  420. CallWindowProcW(listView->prevWindowProc, hwnd, uMsg, wParam, lParam);
  421. free(listView);
  422. return 0;
  423. case WM_KEYDOWN:
  424. switch(wParam)
  425. {
  426. case VK_PRIOR:
  427. case VK_UP:
  428. case VK_HOME:
  429. case VK_NEXT:
  430. case VK_END:
  431. case VK_DOWN:
  432. case VK_LEFT:
  433. case VK_RIGHT:
  434. return ListView_CallWindowProc(listView, hwnd, uMsg, wParam, lParam, LVCWP_UPDATESCROLLINFO);
  435. }
  436. break;
  437. case WM_TIMER:
  438. if (43 == wParam)
  439. return ListView_CallWindowProc(listView, hwnd, uMsg, wParam, lParam, LVCWP_UPDATESCROLLINFO);
  440. break;
  441. case WM_HSCROLL:
  442. case WM_VSCROLL:
  443. case WM_MOUSEWHEEL:
  444. case LVM_ENSUREVISIBLE:
  445. return ListView_CallWindowProc(listView, hwnd, uMsg, wParam, lParam, LVCWP_UPDATESCROLLINFO);
  446. case WM_LBUTTONDOWN:
  447. case WM_RBUTTONDOWN:
  448. {
  449. LVHITTESTINFO ht;
  450. ht.pt.x = GET_X_LPARAM(lParam);
  451. ht.pt.y = GET_Y_LPARAM(lParam);
  452. if (-1 == SendMessageW(hwnd, LVM_HITTEST, 0, (LPARAM)&ht) || 0 == (LVHT_ONITEM & ht.flags))
  453. {
  454. hwndToMonitor = hwnd;
  455. hook = SetWindowsHookEx(WH_MSGFILTER, HookProc, NULL, GetCurrentThreadId());
  456. }
  457. }
  458. break;
  459. }
  460. return ListView_CallWindowProc(listView, hwnd, uMsg, wParam, lParam, LVCWP_NORMAL);
  461. }
  462. static LRESULT
  463. HeaderIconList_OnCreate(HWND hwnd, CREATESTRUCT *createStruct)
  464. {
  465. HWND hwndList, hwndHeader;
  466. MLSKINWINDOW m;
  467. RECT rc;
  468. DWORD style;
  469. m.skinType = SKINNEDWND_TYPE_SCROLLWND;
  470. m.style = SWS_USESKINFONT | SWS_USESKINCOLORS | SWS_USESKINCURSORS;
  471. m.hwndToSkin = hwnd;
  472. MLSkinWindow(g_hwnd, &m);
  473. SetScrollRange(hwnd, SB_VERT, 0, 0, FALSE);
  474. MLSkinnedScrollWnd_UpdateBars(hwnd, FALSE);
  475. GetClientRect(hwnd, &rc);
  476. style = WS_CLIPSIBLINGS | WS_CHILD | WS_VISIBLE | HDS_BUTTONS | HDS_FULLDRAG;
  477. hwndHeader = CreateWindowExW(WS_EX_NOPARENTNOTIFY, WC_HEADERW, L"", style, 0, 0, rc.right - rc.left, 20, hwnd, (HMENU)3,0,0);
  478. if (NULL != hwndHeader)
  479. {
  480. m.hwndToSkin = hwndHeader;
  481. m.skinType = SKINNEDWND_TYPE_HEADER;
  482. m.style = SWS_USESKINFONT | SWS_USESKINCOLORS | SWS_USESKINCURSORS;
  483. MLSkinWindow(g_hwnd, &m);
  484. }
  485. style = WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_CHILD | WS_TABSTOP | WS_VISIBLE |
  486. LVS_ICON | LVS_SHOWSELALWAYS | LVS_OWNERDATA | LVS_NOLABELWRAP;
  487. hwndList = CreateWindowExW(WS_EX_NOPARENTNOTIFY, WC_LISTVIEWW,L"",style,0, 20, rc.right - rc.left, rc.bottom - rc.top - 20, hwnd,(HMENU)2,0,0);
  488. if (NULL != hwndList)
  489. {
  490. ListViewData *listView;
  491. listView = (ListViewData*)calloc(1, sizeof(ListViewData));
  492. if (NULL != listView)
  493. {
  494. listView->prevWindowProc = (WNDPROC)(LONG_PTR)SetWindowLongPtrW(hwndList, GWLP_WNDPROC, (LONGX86)(LONG_PTR)ListView_WindowProc);
  495. SetWindowLongPtrW(hwndList,GWLP_USERDATA, (LONGX86)(LONG_PTR)listView);
  496. }
  497. SendMessageW(hwndList, LVM_SETEXTENDEDLISTVIEWSTYLE, LVS_EX_INFOTIP, LVS_EX_INFOTIP);
  498. if (NULL != hwndHeader)
  499. SetWindowPos(hwndHeader, hwndList, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
  500. m.skinType = SKINNEDWND_TYPE_LISTVIEW;
  501. m.hwndToSkin = hwndList;
  502. m.style = SWS_USESKINFONT | SWS_USESKINCOLORS | SWS_USESKINCURSORS | SWLVS_FULLROWSELECT | SWLVS_DOUBLEBUFFER;
  503. MLSkinWindow(g_hwnd, &m);
  504. MLSkinnedScrollWnd_SetMode(hwndList, SCROLLMODE_STANDARD);
  505. MLSkinnedScrollWnd_ShowHorzBar(hwndList, FALSE);
  506. MLSkinnedScrollWnd_ShowVertBar(hwndList, FALSE);
  507. }
  508. UpdateFontMetrics(hwnd, FALSE);
  509. return 0;
  510. }
  511. static void
  512. HeaderIconList_OnDestroy(HWND hwnd)
  513. {
  514. }
  515. // TODO need to finish off the butting up to edge handling
  516. static void
  517. HeaderIconList_OnWindowPosChanged(HWND hwnd, WINDOWPOS *windowPos)
  518. {
  519. RECT rc;
  520. HWND hwndHeader, hwndList;
  521. hwndHeader = GetDlgItem(hwnd, 3);
  522. hwndList = GetDlgItem(hwnd, 2);
  523. BOOL bRedraw;
  524. bRedraw = (0 == (SWP_NOREDRAW & windowPos->flags));
  525. if ((SWP_NOSIZE | SWP_NOMOVE) == ((SWP_NOSIZE | SWP_NOMOVE | SWP_FRAMECHANGED) & windowPos->flags))
  526. return;
  527. hwndHeader = GetDlgItem(hwnd, 3);
  528. hwndList = GetDlgItem(hwnd, 2);
  529. if (hwndHeader && hwndList)
  530. {
  531. HDLAYOUT headerLayout;
  532. WINDOWPOS headerPos;
  533. GetClientRect(hwnd, &rc);
  534. /*SCROLLINFO si;
  535. si.cbSize= sizeof(SCROLLINFO);
  536. si.fMask = SIF_RANGE | SIF_PAGE | SIF_POS;
  537. BOOL got = GetScrollInfo(hwnd, SB_VERT, &si);
  538. BOOL bScrollVisible = (si.nMax > 0 && si.nPage > 0 && (INT)si.nPage <= si.nMax);*/
  539. headerLayout.prc = &rc;
  540. headerLayout.pwpos = &headerPos;
  541. if (FALSE != SendMessageW(hwndHeader, HDM_LAYOUT, 0, (LPARAM)&headerLayout))
  542. {
  543. headerPos.flags |= ((SWP_NOREDRAW | SWP_NOCOPYBITS) & windowPos->flags);
  544. SetWindowPos(hwndHeader, headerPos.hwndInsertAfter, headerPos.x, headerPos.y,
  545. headerPos.cx, headerPos.cy, headerPos.flags);
  546. }
  547. SetWindowPos(hwndList, NULL, rc.left, rc.top, rc.right - rc.left/* + (bScrollVisible ? 16 : 0)*/, rc.bottom - rc.top,
  548. SWP_NOMOVE | SWP_NOOWNERZORDER | SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOREDRAW | SWP_NOCOPYBITS);
  549. UpdateScrollInfo(hwnd, SIF_RANGE | SIF_POS, bRedraw);
  550. }
  551. NMHDR hdr;
  552. hdr.code = LVN_EX_SIZECHANGED;
  553. hdr.hwndFrom = hwnd;
  554. hdr.idFrom = GetWindowLongPtrW(hwnd,GWLP_ID);
  555. SendMessageW(GetParent(hwnd), WM_NOTIFY, hdr.idFrom, (LPARAM)&hdr);
  556. }
  557. static void
  558. HeaderIconList_OnVertScroll(HWND hwnd, INT actionLayout, INT trackPosition, HWND scrollBar)
  559. {
  560. SCROLLINFO si={sizeof(si),SIF_TRACKPOS | SIF_POS | SIF_RANGE | SIF_PAGE,0};
  561. if (GetScrollInfo(hwnd,SB_VERT,&si))
  562. {
  563. int pos(0), itemHeight;
  564. BOOL bRedraw(TRUE);
  565. HWND hwndList;
  566. hwndList = GetDlgItem(hwnd, 2);
  567. if (!hwndList)
  568. return;
  569. itemHeight = HIWORD(SendMessageW(hwndList, LVM_GETITEMSPACING, 0, 0L));
  570. if (si.nPos > (si.nMax - (INT)si.nPage))
  571. si.nPos = si.nMax - si.nPage;
  572. switch(actionLayout)
  573. {
  574. case SB_TOP: pos = si.nMin; break;
  575. case SB_BOTTOM: pos = si.nMax; break;
  576. case SB_LINEDOWN: pos = si.nPos + itemHeight/2; break;
  577. case SB_LINEUP: pos = si.nPos - itemHeight/2; break;
  578. case SB_PAGEDOWN: pos = si.nPos + si.nPage - (((INT)si.nPage > itemHeight && 0 == ((INT)si.nPage%itemHeight)) ? itemHeight : 0);break;
  579. case SB_PAGEUP: pos = si.nPos - si.nPage - (((INT)si.nPage > itemHeight && 0 == ((INT)si.nPage%itemHeight)) ? itemHeight : 0);break;
  580. case SB_THUMBPOSITION:
  581. case SB_THUMBTRACK:
  582. {
  583. POINT pt;
  584. if (!SendMessageW(hwndList, LVM_GETORIGIN, 0, (LPARAM)&pt))
  585. return;
  586. si.nPos = pt.y;
  587. pos = si.nTrackPos;
  588. bRedraw = FALSE;
  589. }
  590. break;
  591. case SB_ENDSCROLL: MLSkinnedScrollWnd_UpdateBars(hwnd, TRUE); return;
  592. default: pos = si.nPos;
  593. }
  594. if (pos < si.nMin) pos = si.nMin;
  595. if (pos > (si.nMax - (INT)si.nPage)) pos = si.nMax - si.nPage;
  596. if (pos != si.nPos)
  597. {
  598. BOOL br;
  599. if (!bRedraw)
  600. {
  601. UpdateWindow(GetDlgItem(hwnd, 3));
  602. UpdateWindow(hwnd);
  603. SendMessageW(hwnd, WM_SETREDRAW, FALSE, 0L);
  604. }
  605. br = (BOOL)SendMessageW(hwndList, LVM_SCROLL, 0, pos - si.nPos);
  606. if (!bRedraw) SendMessageW(hwnd, WM_SETREDRAW, TRUE, 0L);
  607. if (br)
  608. {
  609. si.fMask = SIF_POS;
  610. si.nPos = pos;
  611. SetScrollInfo(hwnd, SB_VERT, &si, FALSE);
  612. if (!bRedraw)
  613. InvalidateRect(hwndList, NULL, TRUE);
  614. }
  615. }
  616. }
  617. }
  618. static void
  619. HeaderIconList_OnSetFont(HWND hwnd, HFONT font, BOOL redraw)
  620. {
  621. if (0 == (SWS_USESKINFONT & MLSkinnedWnd_GetStyle(hwnd)))
  622. {
  623. HWND controlWindow;
  624. controlWindow = GetDlgItem(hwnd,3);
  625. if (NULL != controlWindow)
  626. SendMessageW(controlWindow, WM_SETFONT, (WPARAM)font, MAKELPARAM(0, 0L));
  627. controlWindow = GetDlgItem(hwnd,2);
  628. if (NULL != controlWindow)
  629. SendMessageW(controlWindow, WM_SETFONT, (WPARAM)font, MAKELPARAM(0, 0L));
  630. UpdateFontMetrics(hwnd, redraw);
  631. }
  632. }
  633. static LRESULT
  634. HeaderIconList_OnGetFont(HWND hwnd)
  635. {
  636. HWND listWindow;
  637. listWindow = GetDlgItem(hwnd, 2);
  638. if (NULL != listWindow)
  639. return SendMessageW(listWindow, WM_GETFONT, 0, 0L);
  640. return DefWindowProcW(hwnd, WM_GETFONT, 0, 0L);
  641. }
  642. static void
  643. HeaderIconList_OnSetRedraw(HWND hwnd, BOOL enableRedraw)
  644. {
  645. HWND childWindow;
  646. DefWindowProcW(hwnd, WM_SETREDRAW, enableRedraw, 0L);
  647. childWindow = GetDlgItem(hwnd, 3);
  648. if (NULL != childWindow)
  649. {
  650. SendMessage(childWindow, WM_SETREDRAW, enableRedraw, 0L);
  651. if (FALSE != enableRedraw)
  652. InvalidateRect(childWindow, NULL, TRUE);
  653. }
  654. childWindow = GetDlgItem(hwnd, 2);
  655. if (NULL != childWindow)
  656. {
  657. SendMessage(childWindow, WM_SETREDRAW, enableRedraw, 0L);
  658. if (FALSE != enableRedraw)
  659. InvalidateRect(childWindow, NULL, TRUE);
  660. }
  661. }
  662. static void
  663. HeaderIconList_OnSkinUpdated(HWND hwnd, BOOL notifyChildren, BOOL redraw)
  664. {
  665. UpdateFontMetrics(hwnd, redraw);
  666. }
  667. static LRESULT
  668. HeaderIconList_OnDisplaySort(HWND hwnd, int sortIndex, BOOL ascendingOrder)
  669. {
  670. HWND headerWindow;
  671. headerWindow = GetDlgItem(hwnd, 3);
  672. if (NULL == headerWindow)
  673. return 0;
  674. return SENDMLIPC(headerWindow, ML_IPC_SKINNEDHEADER_DISPLAYSORT, MAKEWPARAM(sortIndex, ascendingOrder));
  675. }
  676. static LRESULT
  677. HeaderIconList_OnGetSort(HWND hwnd)
  678. {
  679. HWND headerWindow;
  680. headerWindow = GetDlgItem(hwnd, 3);
  681. if (NULL == headerWindow)
  682. return 0;
  683. return SENDMLIPC(headerWindow, ML_IPC_SKINNEDHEADER_GETSORT, 0);
  684. }
  685. static LRESULT
  686. HeaderIconList_OnMediaLibraryIPC(HWND hwnd, INT msg, INT_PTR param)
  687. {
  688. switch(msg)
  689. {
  690. case ML_IPC_SKINNEDWND_SKINUPDATED: HeaderIconList_OnSkinUpdated(hwnd, LOWORD(param), HIWORD(param)); break;
  691. case ML_IPC_SKINNEDLISTVIEW_DISPLAYSORT: return HeaderIconList_OnDisplaySort(hwnd, LOWORD(param), HIWORD(param));
  692. case ML_IPC_SKINNEDLISTVIEW_GETSORT: return HeaderIconList_OnGetSort(hwnd);
  693. }
  694. return 0;
  695. }
  696. static LRESULT CALLBACK HeaderIconList(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
  697. switch(uMsg)
  698. {
  699. case WM_CREATE: return HeaderIconList_OnCreate(hwnd, (CREATESTRUCT*)lParam);
  700. case WM_DESTROY: HeaderIconList_OnDestroy(hwnd); return 0;
  701. case WM_WINDOWPOSCHANGED: HeaderIconList_OnWindowPosChanged(hwnd, (WINDOWPOS*)lParam); return 0;
  702. case WM_VSCROLL: HeaderIconList_OnVertScroll(hwnd, LOWORD(wParam), (short)HIWORD(wParam), (HWND)lParam); return 0;
  703. case WM_ERASEBKGND: return 1;
  704. case WM_SETFONT: HeaderIconList_OnSetFont(hwnd, (HFONT)wParam, LOWORD(lParam)); return 0;
  705. case WM_GETFONT: return HeaderIconList_OnGetFont(hwnd);
  706. case WM_SETREDRAW: HeaderIconList_OnSetRedraw(hwnd, (BOOL)wParam); return 0;
  707. case WM_TIMER:
  708. if (43 == wParam)
  709. {
  710. KillTimer(hwnd, 43);
  711. PostMessageW(hwnd, WM_EX_UPDATESCROLLINFO, SIF_POS, FALSE);
  712. PostMessageW(hwnd, WM_EX_UNLOCKREDRAW, IWF_CONTAINER | IWF_LISTVIEW | IWF_UPDATENOW, 0L);
  713. }
  714. break;
  715. case WM_EX_UPDATESCROLLINFO:
  716. return UpdateScrollInfo(hwnd, (UINT)wParam, (BOOL)lParam);
  717. case WM_EX_UNLOCKREDRAW:
  718. SendMessageW(hwnd, WM_SETREDRAW, TRUE, 0L);
  719. if (IWF_CONTAINER & wParam) { InvalidateRect(hwnd, NULL, FALSE); if (IWF_UPDATENOW & wParam) UpdateWindow(hwnd); }
  720. if (IWF_LISTVIEW & wParam)
  721. {
  722. HWND hwndList = GetDlgItem(hwnd, 2);
  723. if(hwndList) { InvalidateRect(hwndList, NULL, TRUE); if (IWF_UPDATENOW & wParam) UpdateWindow(hwndList); }
  724. }
  725. if (IWF_HEADER & wParam)
  726. {
  727. HWND hwndHeader = GetDlgItem(hwnd, 3);
  728. if(hwndHeader) { InvalidateRect(hwndHeader, NULL, TRUE); if (IWF_UPDATENOW & wParam) UpdateWindow(hwndHeader); }
  729. }
  730. break;
  731. case LVM_GETHEADER:
  732. return (LRESULT)GetDlgItem(hwnd,3);
  733. case LVM_DELETECOLUMN:
  734. {
  735. HWND headerWindow;
  736. headerWindow = GetDlgItem(hwnd,3);
  737. if (NULL != headerWindow)
  738. return SendMessageW(headerWindow, HDM_DELETEITEM, wParam, 0L);
  739. }
  740. return FALSE;
  741. case LVM_GETCOLUMNWIDTH:
  742. {
  743. HWND headerWindow;
  744. headerWindow = GetDlgItem(hwnd,3);
  745. if (NULL != headerWindow)
  746. {
  747. HDITEMW headerItem;
  748. headerItem.mask = HDI_WIDTH;
  749. if (FALSE != SendMessageW(headerWindow, HDM_GETITEM, wParam, (LPARAM)&headerItem))
  750. return headerItem.cxy;
  751. }
  752. }
  753. return 0;
  754. case LVM_INSERTCOLUMNA:
  755. case LVM_INSERTCOLUMNW:
  756. {
  757. LVCOLUMNW *listColumn = (LVCOLUMNW*)lParam;
  758. HDITEMW headerItem;
  759. HWND headerWindow;
  760. headerWindow = GetDlgItem(hwnd,3);
  761. if (NULL == headerWindow)
  762. return -1;
  763. if (FALSE == CopyListColumnToHeaderItem(listColumn, &headerItem))
  764. return -1;
  765. if (0 == (HDI_FORMAT & headerItem.mask))
  766. {
  767. headerItem.mask |= HDI_FORMAT;
  768. headerItem.fmt = HDF_LEFT;
  769. }
  770. return SendMessageW(headerWindow,
  771. (LVM_INSERTCOLUMNW == uMsg) ? HDM_INSERTITEMW : HDM_INSERTITEMA,
  772. wParam, (LPARAM)&headerItem);
  773. }
  774. break;
  775. case LVM_SETITEMCOUNT:
  776. {
  777. HWND hwndList = GetDlgItem(hwnd, 2);
  778. if (hwndList)
  779. {
  780. LRESULT lr = ListView_WindowProc(hwndList, uMsg, wParam, lParam);
  781. UpdateScrollInfo(hwnd, SIF_RANGE | SIF_POS, TRUE);
  782. return lr;
  783. }
  784. }
  785. break;
  786. case LVM_GETCOLUMNW:
  787. case LVM_GETCOLUMNA:
  788. {
  789. LVCOLUMNW *l = (LVCOLUMNW *)lParam;
  790. HDITEMW h;
  791. HWND headerWindow;
  792. headerWindow = GetDlgItem(hwnd, 3);
  793. if (NULL == headerWindow)
  794. return FALSE;
  795. if (FALSE == CopyListColumnToHeaderItem(l, &h))
  796. return FALSE;
  797. if(!SendMessageW(headerWindow,
  798. (LVM_GETCOLUMNW == uMsg) ? HDM_GETITEMW : HDM_GETITEMA,
  799. wParam,
  800. (LPARAM)&h))
  801. {
  802. return FALSE;
  803. }
  804. if (FALSE == CopyHeaderItemToListColumn(&h, l))
  805. return FALSE;
  806. }
  807. return TRUE;
  808. case LVM_SETCOLUMNW:
  809. case LVM_SETCOLUMNA:
  810. {
  811. LVCOLUMNW *l = (LVCOLUMNW *)lParam;
  812. HDITEMW h;
  813. HWND headerWindow;
  814. headerWindow = GetDlgItem(hwnd, 3);
  815. if (NULL == headerWindow)
  816. return FALSE;
  817. if (FALSE == CopyListColumnToHeaderItem(l, &h))
  818. return FALSE;
  819. if(!SendMessageW(headerWindow,
  820. (LVM_SETCOLUMNW == uMsg) ? HDM_SETITEMW : HDM_SETITEMA,
  821. wParam, (LPARAM)&h))
  822. {
  823. return FALSE;
  824. }
  825. if (FALSE == CopyHeaderItemToListColumn(&h, l))
  826. return FALSE;
  827. }
  828. return TRUE;
  829. case LVM_SETCOLUMNWIDTH:
  830. {
  831. HWND headerWindow;
  832. HDITEMW headerItem;
  833. headerWindow = GetDlgItem(hwnd, 3);
  834. if (NULL == headerWindow)
  835. return FALSE;
  836. if (LVSCW_AUTOSIZE == lParam)
  837. return FALSE;
  838. if (LVSCW_AUTOSIZE_USEHEADER == lParam)
  839. return FALSE;
  840. headerItem.mask = HDI_WIDTH;
  841. headerItem.cxy = (int)lParam;
  842. return SendMessageW(headerWindow, HDM_SETITEMW, (WPARAM)wParam, (LPARAM)&headerItem);
  843. }
  844. break;
  845. case WM_NOTIFY:
  846. {
  847. BOOL bPost(FALSE);
  848. LPNMHDR l=(LPNMHDR)lParam;
  849. if(l->idFrom == 2)
  850. {
  851. switch(l->code)
  852. {
  853. case LVN_ODFINDITEMA:
  854. case LVN_ODFINDITEMW:
  855. bPost = TRUE;
  856. break;
  857. case LVN_ODSTATECHANGED:
  858. {
  859. NMLVODSTATECHANGE *stateChange;
  860. stateChange = (NMLVODSTATECHANGE*)lParam;
  861. if (0 != (LVIS_SELECTED & (stateChange->uNewState ^ stateChange->uOldState)))
  862. {
  863. SendMessageW(hwnd, WM_SETREDRAW, FALSE, 0L);
  864. ListView_ScheduleSelectionUpdate(l->hwndFrom, stateChange->iFrom,stateChange->iTo);
  865. }
  866. return 0;
  867. }
  868. break;
  869. }
  870. l->idFrom = GetWindowLong(hwnd,GWL_ID);
  871. l->hwndFrom = hwnd;
  872. LRESULT lr = SendMessageW(GetParent(hwnd),uMsg,l->idFrom,lParam);
  873. if (bPost)
  874. {
  875. UpdateWindow(GetDlgItem(hwnd, 3));
  876. SendMessageW(hwnd, WM_SETREDRAW, FALSE, 0L);
  877. PostMessageW(hwnd, WM_EX_UPDATESCROLLINFO, SIF_POS, TRUE);
  878. PostMessageW(hwnd, WM_EX_UNLOCKREDRAW, IWF_CONTAINER | IWF_LISTVIEW, 0L);
  879. }
  880. return lr;
  881. }
  882. else if(l->idFrom == 3) {
  883. switch(l->code) {
  884. case HDN_ITEMCLICKA:
  885. case HDN_ITEMCLICKW:
  886. {
  887. NMHEADER *nm = (NMHEADER*)lParam;
  888. HWND hwndParent;
  889. hwndParent = GetParent(hwnd);
  890. if (hwndParent)
  891. {
  892. wParam = GetWindowLongPtrW(hwnd,GWLP_ID);
  893. if(nm->iButton == 0) { // left click
  894. NMLISTVIEW p = {{hwnd, wParam, LVN_COLUMNCLICK},-1,nm->iItem,0};
  895. return SendMessageW(hwndParent,WM_NOTIFY,wParam,(LPARAM)&p);
  896. } else if(nm->iButton == 1) { // right click
  897. NMHDR p = {nm->hdr.hwndFrom,wParam,NM_RCLICK};
  898. return SendMessageW(hwndParent,WM_NOTIFY,wParam,(LPARAM)&p);
  899. }
  900. }
  901. }
  902. break;
  903. }
  904. return SendMessageW(GetParent(hwnd),uMsg, wParam,lParam);
  905. }
  906. }
  907. break;
  908. case WM_EX_GETREALLIST:
  909. return (LRESULT)GetDlgItem(hwnd, 2);
  910. case WM_EX_GETCOUNTPERPAGE:
  911. {
  912. HWND hwndList;
  913. RECT rc;
  914. hwndList = GetDlgItem(hwnd, 2);
  915. if (hwndList)
  916. {
  917. GetClientRect(hwndList, &rc);
  918. OffsetRect(&rc, -rc.left, -rc.top);
  919. DWORD spacing = (DWORD)SendMessageW(hwndList, LVM_GETITEMSPACING, 0, 0L);
  920. if (LOWORD(spacing) && HIWORD(spacing))
  921. {
  922. return (rc.right/LOWORD(spacing)) * (rc.bottom /HIWORD(spacing) + ((rc.bottom%HIWORD(spacing)) ? 1 : 0));
  923. }
  924. }
  925. }
  926. return 0;
  927. case WM_ML_IPC:
  928. return HeaderIconList_OnMediaLibraryIPC(hwnd, (INT)lParam, (INT_PTR)wParam);
  929. default:
  930. if(uMsg >= LVM_FIRST && uMsg < LVM_FIRST + 0x100)
  931. {
  932. HWND hwndList = GetDlgItem(hwnd,2);
  933. if (hwndList) return ListView_WindowProc(hwndList, uMsg, wParam, lParam);
  934. }
  935. break;
  936. }
  937. return DefWindowProcW(hwnd,uMsg,wParam,lParam);
  938. }
  939. void InitHeaderIconList() {
  940. WNDCLASSW wc = {0, };
  941. if (GetClassInfoW(plugin.hDllInstance, L"HeaderIconList", &wc)) return;
  942. wc.style = CS_DBLCLKS;
  943. wc.lpfnWndProc = HeaderIconList;
  944. wc.hInstance = plugin.hDllInstance;
  945. wc.lpszClassName = L"HeaderIconList";
  946. RegisterClassW(&wc);
  947. }