setupListbox.cpp 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878
  1. #include "./setupPage.h"
  2. #include "./setupListbox.h"
  3. #include "./setupGroupList.h"
  4. #include "./setupImage.h"
  5. #include "../common.h"
  6. #include "../resource.h"
  7. #include "../api__ml_online.h"
  8. #include "../../nu/windowsTheme.h"
  9. #include <vssym32.h>
  10. //#include <tmschema.h>
  11. static ATOM SERVICELIST_PROP = 0;
  12. #define SLF_UNICODE 0x0001
  13. #define SLF_DRAGMOVE 0x0002
  14. typedef BOOL (SetupListboxItem::*ITEMMOUSEPROC)(SetupListbox*, const RECT*, UINT, POINT);
  15. class Listbox : public SetupListbox
  16. {
  17. protected:
  18. Listbox(HWND hListbox, SetupGroupList *groupList);
  19. ~Listbox();
  20. public:
  21. static HRESULT AttachToWindow(HWND hwndListbox, SetupGroupList *groupList, SetupListbox **pInstance);
  22. public:
  23. HWND GetHwnd() { return hwnd; }
  24. HFONT GetFont() { return (HFONT)::SendMessage(hwnd, WM_GETFONT, 0, 0L); }
  25. LRESULT CallDefaultProc(UINT uMsg, WPARAM wParam, LPARAM lParam);
  26. LRESULT CallPrevProc(UINT uMsg, WPARAM wParam, LPARAM lParam);
  27. BOOL MeasureItem(INT itemId, UINT *cx, UINT *cy);
  28. BOOL DrawItem(HDC hdc, const RECT *itemRect, INT itemId, UINT itemState, UINT itemAction);
  29. INT_PTR KeyToItem(INT vKey, INT caretPos);
  30. INT_PTR CharToItem(INT vKey, INT caretPos);
  31. BOOL DrawCheckbox(HDC hdc, BOOL checked, UINT state, const RECT *pRect, const RECT *pClipRect);
  32. BOOL GetCheckboxMetrics(HDC hdc, BOOL checked, UINT state, SIZE *pSize);
  33. INT GetCheckboxThemeState(BOOL checked, UINT state);
  34. INT HitTest(POINT pt, RECT *prcItem);
  35. void SetCapture(SetupListboxItem *item);
  36. SetupListboxItem *GetCapture();
  37. void ReleaseCapture();
  38. BOOL InvalidateRect(const RECT *prcInvalidate, BOOL fErase);
  39. BOOL InvalidateItem(INT itemId, BOOL fErase);
  40. void UpdateCount();
  41. BOOL DrawExpandbox(HDC hdc, BOOL fExpanded, const RECT *pRect, COLORREF rgbBk, COLORREF rgbFg);
  42. BOOL GetExpandboxMetrics(HDC hdc, BOOL fExpanded, SIZE *pSize);
  43. INT GetPageCount();
  44. INT GetNextEnabledItem(INT iItem, SetupListboxItem **itemOut);
  45. INT GetPrevEnabledItem(INT iItem, SetupListboxItem **itemOut);
  46. SetupListboxItem *GetSelection();
  47. BOOL SetSelection(SetupListboxItem *item);
  48. BOOL GetIndex(SetupListboxItem *item, INT *iItem);
  49. BOOL DoDragAndDrop(UINT mouseEvent, UINT mouseFlags, POINT pt);
  50. HMENU GetContextMenu(UINT menuId);
  51. protected:
  52. friend static LRESULT WINAPI Listbox_WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
  53. LRESULT WindowProc(UINT uMsg, WPARAM wParam, LPARAM lParam);
  54. void OnDestroy();
  55. void GetItemRect(INT itemId, RECT *prcItem);
  56. SetupImage *GetExpandboxImage(HDC hdc, BOOL fExpanded);
  57. void OnMouseEvent(UINT mouseEvent, UINT mouseFlags, POINTS pts, BOOL fDefaultHandler, ITEMMOUSEPROC proc);
  58. void OnMouseLeave();
  59. void OnEraseBkGround(HDC hdc);
  60. void OnCaptureChanged(HWND hwndGained);
  61. void NotifyReleaseCapture(INT itemId, SetupListboxItem *itemGain);
  62. void OnCommand(INT commandId, INT eventId, HWND hControl);
  63. protected:
  64. HWND hwnd;
  65. UINT flags;
  66. WNDPROC originalProc;
  67. UXTHEME buttonTheme;
  68. SetupGroupList *groups;
  69. INT mouseoverId;
  70. INT capturedId;
  71. SetupImage *expandedImage;
  72. SetupImage *collapsedImage;
  73. };
  74. #define GetList(__hwnd) ((Listbox*)GetPropW((__hwnd), MAKEINTATOM(SERVICELIST_PROP)))
  75. HRESULT SetupListbox::CreateInstance(HWND hListbox, SetupGroupList *groupList, SetupListbox **pInstance)
  76. {
  77. return Listbox::AttachToWindow(hListbox, groupList, pInstance);
  78. }
  79. SetupListbox *SetupListbox::GetInstance(HWND hListbox)
  80. {
  81. return GetList(hListbox);
  82. }
  83. Listbox::Listbox(HWND hListbox, SetupGroupList *groupList)
  84. : hwnd(hListbox), flags(0), originalProc(NULL), buttonTheme(NULL), groups(groupList),
  85. mouseoverId(LB_ERR), capturedId(LB_ERR), expandedImage(NULL), collapsedImage(NULL)
  86. {
  87. if (IsWindowUnicode(hwnd))
  88. flags |= SLF_UNICODE;
  89. buttonTheme = (UxIsAppThemed()) ? UxOpenThemeData(hwnd, L"Button") : NULL;
  90. groups->AddRef();
  91. UpdateCount();
  92. }
  93. Listbox::~Listbox()
  94. {
  95. if (NULL != hwnd)
  96. {
  97. RemoveProp(hwnd, MAKEINTATOM(SERVICELIST_PROP));
  98. if (NULL != originalProc)
  99. {
  100. SetWindowLongPtr(hwnd, GWLP_WNDPROC, (LONGX86)(LONG_PTR)originalProc);
  101. CallPrevProc(WM_DESTROY, 0, 0L);
  102. }
  103. }
  104. if (NULL != groups)
  105. groups->Release();
  106. if (NULL != buttonTheme)
  107. UxCloseThemeData(buttonTheme);
  108. if (NULL != expandedImage)
  109. expandedImage->Release();
  110. if (NULL != collapsedImage)
  111. collapsedImage->Release();
  112. }
  113. HRESULT Listbox::AttachToWindow(HWND hListbox, SetupGroupList *groupList, SetupListbox **pInstance)
  114. {
  115. if (0 == SERVICELIST_PROP)
  116. {
  117. SERVICELIST_PROP = GlobalAddAtom(TEXT("omSetupListbox"));
  118. if (0 == SERVICELIST_PROP) return E_UNEXPECTED;
  119. }
  120. if(NULL == hListbox || !IsWindow(hListbox) || NULL == groupList)
  121. return E_INVALIDARG;
  122. Listbox *list = new Listbox(hListbox, groupList);
  123. if (NULL == list)
  124. return E_OUTOFMEMORY;
  125. list->originalProc = (WNDPROC)(LONG_PTR)SetWindowLongPtr(hListbox, GWLP_WNDPROC,
  126. (LONGX86)(LONG_PTR)Listbox_WindowProc);
  127. if (NULL == list->originalProc || !SetProp(hListbox, MAKEINTATOM(SERVICELIST_PROP), list))
  128. {
  129. if (NULL != list->originalProc)
  130. SetWindowLongPtr(hListbox, GWLP_WNDPROC, (LONGX86)(LONG_PTR)list->originalProc);
  131. delete(list);
  132. return E_FAIL;
  133. }
  134. if (NULL != pInstance)
  135. *pInstance = list;
  136. return S_OK;
  137. }
  138. LRESULT Listbox::CallDefaultProc(UINT uMsg, WPARAM wParam, LPARAM lParam)
  139. {
  140. return (0 != (SLF_UNICODE & flags)) ?
  141. DefWindowProcW(hwnd, uMsg, wParam, lParam) :
  142. DefWindowProcA(hwnd, uMsg, wParam, lParam);
  143. }
  144. LRESULT Listbox::CallPrevProc(UINT uMsg, WPARAM wParam, LPARAM lParam)
  145. {
  146. return (0 != (SLF_UNICODE & flags)) ?
  147. CallWindowProcW(originalProc, hwnd, uMsg, wParam, lParam) :
  148. CallWindowProcA(originalProc, hwnd, uMsg, wParam, lParam);
  149. }
  150. void Listbox::UpdateCount()
  151. {
  152. SendMessage(hwnd, WM_SETREDRAW, FALSE, 0L);
  153. INT iSelected = (INT)SendMessage(hwnd, LB_GETCURSEL, 0, 0L);
  154. size_t recordCount = (NULL != groups) ? groups->GetListboxCount() : 0;
  155. SendMessage(hwnd, LB_SETCOUNT, (WPARAM)recordCount, 0L);
  156. SetupListboxItem *item;
  157. UINT cy, maxCY = 0;
  158. for (size_t i = 0; i < recordCount; i++)
  159. {
  160. if (SUCCEEDED(groups->FindListboxItem(i, &item)) &&
  161. item->MeasureItem(this, NULL, &cy) && cy > maxCY)
  162. {
  163. maxCY = cy;
  164. }
  165. }
  166. SendMessage(hwnd, LB_SETITEMHEIGHT, (WPARAM)0, (LPARAM)maxCY);
  167. if (recordCount > 0)
  168. {
  169. if (iSelected < 0)
  170. iSelected = 0;
  171. if ((size_t)iSelected >= recordCount)
  172. iSelected = (INT)(recordCount - 1);
  173. SendMessage(hwnd, LB_SETCARETINDEX, (WPARAM)iSelected, TRUE);
  174. SendMessage(hwnd, LB_SETANCHORINDEX, (WPARAM)iSelected, 0L);
  175. SendMessage(hwnd, LB_SETCURSEL, (WPARAM)iSelected, 0L);
  176. }
  177. SendMessage(hwnd, WM_SETREDRAW, TRUE, 0L);
  178. }
  179. BOOL Listbox::MeasureItem(INT itemId, UINT *cx, UINT *cy)
  180. {
  181. SetupListboxItem *item;
  182. HRESULT hr = groups->FindListboxItem(itemId, &item);
  183. return (SUCCEEDED(hr)) ? item->MeasureItem(this, cx, cy) : FALSE;
  184. }
  185. BOOL Listbox::DrawItem(HDC hdc, const RECT *prcItem, INT itemId, UINT itemState, UINT itemAction)
  186. {
  187. SetupListboxItem *item;
  188. HRESULT hr = groups->FindListboxItem(itemId, &item);
  189. if (FAILED(hr)) return FALSE;
  190. if (0 != (ODS_SELECTED & itemState) && GetFocus() != hwnd)
  191. itemState |= ODS_INACTIVE;
  192. if (item->IsDisabled())
  193. itemState |= ODS_DISABLED;
  194. return item->DrawItem(this, hdc, prcItem, itemState);
  195. }
  196. INT Listbox::GetPageCount()
  197. {
  198. RECT clientRect;
  199. if (NULL == hwnd || !GetClientRect(hwnd, &clientRect))
  200. return 0;
  201. INT itemHeight = (INT)SendMessage(hwnd, LB_GETITEMHEIGHT, 0, 0L);
  202. return (clientRect.bottom - clientRect.top) / itemHeight;
  203. }
  204. INT Listbox::GetNextEnabledItem(INT iItem, SetupListboxItem **itemOut)
  205. {
  206. INT iLast = (INT)SendMessage(hwnd, LB_GETCOUNT, 0, 0L);
  207. if (iLast >= 0) iLast--;
  208. SetupListboxItem *testItem;
  209. while(iItem++ < iLast)
  210. {
  211. if (SUCCEEDED(groups->FindListboxItem(iItem, &testItem)))
  212. {
  213. if (FALSE == testItem->IsDisabled()) break;
  214. }
  215. }
  216. if (NULL != itemOut)
  217. {
  218. *itemOut = (iItem <= iLast) ? testItem : NULL;
  219. }
  220. return (iItem <= iLast) ? iItem : LB_ERR;
  221. }
  222. INT Listbox::GetPrevEnabledItem(INT iItem, SetupListboxItem **itemOut)
  223. {
  224. SetupListboxItem *testItem;
  225. while(iItem-- > 0)
  226. {
  227. if (SUCCEEDED(groups->FindListboxItem(iItem, &testItem)))
  228. {
  229. if (FALSE == testItem->IsDisabled()) break;
  230. }
  231. }
  232. if (NULL != itemOut)
  233. {
  234. *itemOut = (iItem >= 0) ? testItem : NULL;
  235. }
  236. return (iItem >= 0) ? iItem : LB_ERR;
  237. }
  238. SetupListboxItem *Listbox::GetSelection()
  239. {
  240. INT iSelected = (INT)SendMessage(hwnd, LB_GETCURSEL, 0, 0L);
  241. if (LB_ERR == iSelected)
  242. return NULL;
  243. SetupListboxItem *item;
  244. return (SUCCEEDED(groups->FindListboxItem(iSelected, &item))) ? item : NULL;
  245. }
  246. BOOL Listbox::SetSelection(SetupListboxItem *item)
  247. {
  248. INT iItem = LB_ERR;
  249. if (NULL != item)
  250. {
  251. iItem = groups->GetListboxItem(item);
  252. if (LB_ERR == iItem)
  253. return FALSE;
  254. }
  255. BOOL resultOk = (LB_ERR != SendMessage(hwnd, LB_SETCURSEL, (WPARAM)iItem, 0L));
  256. if (LB_ERR == iItem) resultOk = TRUE;
  257. if (LB_ERR != iItem)
  258. {
  259. HWND hParent = GetParent(hwnd);
  260. if (NULL != hParent)
  261. SendMessage(hParent, WM_COMMAND, MAKEWPARAM(GetDlgCtrlID(hwnd), LBN_SELCHANGE), (LPARAM)hwnd);
  262. }
  263. return resultOk;
  264. }
  265. BOOL Listbox::GetIndex(SetupListboxItem *item, INT *iItem)
  266. {
  267. if (NULL == iItem)
  268. return FALSE;
  269. *iItem = (NULL != item && NULL != groups) ? groups->GetListboxItem(item) : LB_ERR;
  270. return (LB_ERR != *iItem);
  271. }
  272. INT_PTR Listbox::KeyToItem(INT vKey, INT iCaret)
  273. {
  274. SetupListboxItem *item;
  275. HRESULT hr = groups->FindListboxItem(iCaret, &item);
  276. if (FAILED(hr)) return -1;
  277. RECT itemRect;
  278. GetItemRect(iCaret, &itemRect);
  279. INT_PTR result = item->KeyToItem(this, &itemRect, vKey);
  280. if (-1 != result) return result;
  281. INT iTarget, iCount;
  282. switch(vKey)
  283. {
  284. case VK_UP:
  285. case VK_LEFT:
  286. iTarget = GetPrevEnabledItem(iCaret, NULL);
  287. if (LB_ERR != iTarget) return iTarget;
  288. SendMessage(hwnd, LB_SETTOPINDEX, (WPARAM)0, 0L);
  289. SendMessage(hwnd, LB_SETCARETINDEX, (WPARAM)iCaret, FALSE);
  290. return -2;
  291. case VK_DOWN:
  292. case VK_RIGHT:
  293. iTarget = GetNextEnabledItem(iCaret, NULL);
  294. if (LB_ERR != iTarget) return iTarget;
  295. SendMessage(hwnd, LB_SETTOPINDEX, (WPARAM)iCaret, 0L);
  296. return -2;
  297. case VK_HOME:
  298. if (iCaret > 0)
  299. {
  300. SendMessage(hwnd, LB_SETTOPINDEX, (WPARAM)0, 0L);
  301. iTarget = GetNextEnabledItem(-1, NULL);
  302. if (iTarget >= iCaret) iTarget = LB_ERR;
  303. if (LB_ERR != iTarget) return iTarget;
  304. SendMessage(hwnd, LB_SETCARETINDEX, (WPARAM)iCaret, FALSE);
  305. }
  306. return -2;
  307. case VK_PRIOR:
  308. if (iCaret > 0)
  309. {
  310. INT iTop = (INT)SendMessage(hwnd, LB_GETTOPINDEX, 0, 0L);
  311. if (iTop == iCaret)
  312. {
  313. INT iPage = iCaret - GetPageCount() + 1;
  314. iTop = (iPage <= 0) ? 0 : (iPage - 1);
  315. }
  316. iTarget = GetPrevEnabledItem(iTop + 1, NULL);
  317. if (LB_ERR == iTarget)
  318. {
  319. SendMessage(hwnd, LB_SETTOPINDEX, (WPARAM)0, 0L);
  320. iTarget = GetNextEnabledItem(iTop, NULL);
  321. if (iTarget > iCaret) iTarget = LB_ERR;
  322. }
  323. if (LB_ERR != iTarget) return iTarget;
  324. SendMessage(hwnd, LB_SETCARETINDEX, (WPARAM)iCaret, FALSE);
  325. }
  326. return -2;
  327. case VK_END:
  328. iCount = (INT)SendMessage(hwnd, LB_GETCOUNT, 0, 0L);
  329. if (iCount > 0 && iCaret != (iCount - 1))
  330. {
  331. SendMessage(hwnd, LB_SETTOPINDEX, (WPARAM)(iCount - 1), 0L);
  332. iTarget = GetPrevEnabledItem(iCount, NULL);
  333. if (iTarget <= iCaret) iTarget = LB_ERR;
  334. if (LB_ERR != iTarget) return iTarget;
  335. SendMessage(hwnd, LB_SETCARETINDEX, (WPARAM)iCaret, FALSE);
  336. }
  337. return -2;
  338. case VK_NEXT:
  339. iCount = (INT)SendMessage(hwnd, LB_GETCOUNT, 0, 0L);
  340. if (iCount > 0 && iCaret != (iCount - 1))
  341. {
  342. INT iPage = GetPageCount();
  343. INT iBottom = (INT)SendMessage(hwnd, LB_GETTOPINDEX, 0, 0L) + iPage - 1;
  344. if (iBottom == iCaret)
  345. {
  346. iBottom += iPage;
  347. if (iBottom >= iCount) iBottom = iCount -1;
  348. }
  349. iTarget = GetNextEnabledItem(iBottom - 1, NULL);
  350. if (LB_ERR == iTarget)
  351. {
  352. SendMessage(hwnd, LB_SETTOPINDEX, (WPARAM)(iCount - 1), 0L);
  353. iTarget = GetPrevEnabledItem(iBottom, NULL);
  354. if (iTarget < iCaret) iTarget = LB_ERR;
  355. }
  356. if (LB_ERR != iTarget) return iTarget;
  357. SendMessage(hwnd, LB_SETCARETINDEX, (WPARAM)iCaret, FALSE);
  358. }
  359. return -2;
  360. }
  361. return result;
  362. }
  363. INT_PTR Listbox::CharToItem(INT vKey, INT caretPos)
  364. {
  365. return -2;
  366. //SetupListboxItem *item;
  367. //HRESULT hr = groups->FindListboxItem(caretPos, &item);
  368. //return (SUCCEEDED(hr)) ? item->CharToItem(this, vKey) : -1;
  369. }
  370. INT Listbox::GetCheckboxThemeState(BOOL checked, UINT state)
  371. {
  372. if (FALSE != checked)
  373. {
  374. if (0 != (ODS_DISABLED & state)) return CBS_CHECKEDDISABLED;
  375. if (0 != (ODS_HOTLIGHT & state)) return CBS_CHECKEDHOT;
  376. if (0 != (ODS_SELECTED & state)) return CBS_CHECKEDPRESSED;
  377. return CBS_CHECKEDNORMAL;
  378. }
  379. if (0 != (ODS_DISABLED & state)) return CBS_UNCHECKEDDISABLED;
  380. if (0 != (ODS_HOTLIGHT & state)) return CBS_UNCHECKEDHOT;
  381. if (0 != (ODS_SELECTED & state)) return CBS_UNCHECKEDPRESSED;
  382. return CBS_UNCHECKEDNORMAL;
  383. }
  384. BOOL Listbox::DrawCheckbox(HDC hdc, BOOL checked, UINT state, const RECT *pRect, const RECT *pClipRect)
  385. {
  386. if (NULL != buttonTheme)
  387. {
  388. INT stateId = GetCheckboxThemeState(checked, state);
  389. if (SUCCEEDED(UxDrawThemeBackground(buttonTheme, hdc, BP_CHECKBOX, stateId, pRect, pClipRect)))
  390. return TRUE;
  391. }
  392. UINT stateId = DFCS_BUTTONCHECK;
  393. if (FALSE != checked) stateId |= DFCS_CHECKED;
  394. if (0 != (ODS_DISABLED & state)) stateId |= DFCS_INACTIVE;
  395. if (0 != (ODS_HOTLIGHT & state)) stateId |= DFCS_HOT;
  396. if (0 != (ODS_SELECTED & state)) stateId |= DFCS_PUSHED;
  397. return DrawFrameControl(hdc, (LPRECT)pRect,DFC_BUTTON, stateId);
  398. }
  399. BOOL Listbox::GetCheckboxMetrics(HDC hdc, BOOL checked, UINT state, SIZE *pSize)
  400. {
  401. if (NULL != buttonTheme)
  402. {
  403. HDC hdcMine = NULL;
  404. if (NULL == hdc)
  405. {
  406. hdcMine = GetDCEx(hwnd, NULL, DCX_CACHE | DCX_NORESETATTRS);
  407. hdc = hdcMine;
  408. }
  409. INT stateId = GetCheckboxThemeState(checked, state);
  410. HRESULT hr = UxGetThemePartSize(buttonTheme, hdc, BP_CHECKBOX,
  411. stateId, NULL, TS_DRAW, pSize);
  412. if (NULL != hdcMine)
  413. ReleaseDC(hwnd, hdcMine);
  414. if (SUCCEEDED(hr)) return TRUE;
  415. }
  416. pSize->cx = 13;
  417. pSize->cy = 13;
  418. return TRUE;
  419. }
  420. void Listbox::OnDestroy()
  421. {
  422. delete(this);
  423. }
  424. INT Listbox::HitTest(POINT pt, RECT *prcItem)
  425. {
  426. RECT itemRect;
  427. INT itemId = (INT)SendMessage(hwnd, LB_ITEMFROMPOINT, 0, MAKELONG(pt.x, pt.y));
  428. if (LB_ERR == itemId ||
  429. LB_ERR == SendMessage(hwnd, LB_GETITEMRECT, (WPARAM)itemId, (LPARAM)&itemRect) ||
  430. FALSE == PtInRect(&itemRect, pt))
  431. {
  432. return LB_ERR;
  433. }
  434. if (NULL != prcItem)
  435. CopyRect(prcItem, &itemRect);
  436. return itemId;
  437. }
  438. void Listbox::GetItemRect(INT itemId, RECT *prcItem)
  439. {
  440. if (LB_ERR == ::SendMessage(hwnd, LB_GETITEMRECT, (WPARAM)itemId, (LPARAM)prcItem))
  441. SetRectEmpty(prcItem);
  442. }
  443. BOOL Listbox::DoDragAndDrop(UINT mouseEvent, UINT mouseFlags, POINT pt)
  444. {
  445. if (WM_MOUSEMOVE == mouseEvent &&
  446. 0 != ((MK_LBUTTON | MK_MBUTTON | MK_RBUTTON) & mouseFlags))
  447. {
  448. flags |= SLF_DRAGMOVE;
  449. }
  450. else
  451. {
  452. flags &= ~SLF_DRAGMOVE;
  453. }
  454. return (0 != (SLF_DRAGMOVE & flags));
  455. }
  456. void Listbox::OnMouseEvent(UINT mouseEvent, UINT mouseFlags, POINTS pts, BOOL fDefaultHandler, ITEMMOUSEPROC proc)
  457. {
  458. POINT pt;
  459. POINTSTOPOINT(pt, pts);
  460. SetupListboxItem *item;
  461. RECT itemRect;
  462. if (LB_ERR != capturedId)
  463. {
  464. if (SUCCEEDED(groups->FindListboxItem(capturedId, &item)))
  465. {
  466. GetItemRect(capturedId, &itemRect);
  467. if (FALSE == ((item->*proc)(this, &itemRect, mouseFlags, pt)))
  468. {
  469. CallPrevProc(mouseEvent, (WPARAM)mouseFlags, *((LPARAM*)&pts));
  470. }
  471. return;
  472. }
  473. capturedId = LB_ERR;
  474. }
  475. if (DoDragAndDrop(mouseEvent, mouseFlags, pt))
  476. return;
  477. INT itemId = HitTest(pt, &itemRect);
  478. if (mouseoverId != itemId)
  479. {
  480. if (SUCCEEDED(groups->FindListboxItem(mouseoverId, &item)))
  481. {
  482. RECT leaveRect;
  483. GetItemRect(mouseoverId, &leaveRect);
  484. item->MouseLeave(this, &leaveRect);
  485. }
  486. mouseoverId = itemId;
  487. TRACKMOUSEEVENT tm;
  488. tm.cbSize = sizeof(TRACKMOUSEEVENT);
  489. tm.hwndTrack = hwnd;
  490. tm.dwFlags = TME_LEAVE;
  491. if (LB_ERR == mouseoverId)
  492. tm.dwFlags |= TME_CANCEL;
  493. TrackMouseEvent(&tm);
  494. }
  495. if (LB_ERR != mouseoverId)
  496. {
  497. if (SUCCEEDED(groups->FindListboxItem(mouseoverId, &item)))
  498. {
  499. BOOL callListbox = FALSE;
  500. if (FALSE != item->IsDisabled())
  501. {
  502. switch(mouseEvent)
  503. {
  504. case WM_LBUTTONUP:
  505. case WM_RBUTTONUP:
  506. case WM_MBUTTONUP:
  507. case 0x020C /*WM_XBUTTONUP*/:
  508. callListbox = TRUE;
  509. break;
  510. }
  511. }
  512. else
  513. {
  514. if (FALSE == ((item->*proc)(this, &itemRect, mouseFlags, pt)))
  515. {
  516. callListbox = TRUE;
  517. }
  518. }
  519. if (FALSE != callListbox)
  520. {
  521. CallPrevProc(mouseEvent, (WPARAM)mouseFlags, *((LPARAM*)&pts));
  522. }
  523. return;
  524. }
  525. }
  526. if (FALSE != fDefaultHandler)
  527. {
  528. CallPrevProc(mouseEvent, (WPARAM)mouseFlags, *((LPARAM*)&pts));
  529. }
  530. }
  531. void Listbox::OnMouseLeave()
  532. {
  533. if (LB_ERR != mouseoverId)
  534. {
  535. SetupListboxItem *item;
  536. INT itemId = mouseoverId;
  537. mouseoverId = LB_ERR;
  538. if (SUCCEEDED(groups->FindListboxItem(itemId, &item)))
  539. {
  540. RECT itemRect;
  541. GetItemRect(itemId, &itemRect);
  542. if (item->MouseLeave(this, &itemRect))
  543. return;
  544. }
  545. }
  546. CallPrevProc(WM_MOUSELEAVE, 0, 0L);
  547. }
  548. void Listbox::SetCapture(SetupListboxItem *item)
  549. {
  550. INT prevCapturedId = capturedId;
  551. capturedId = (NULL != item) ? groups->GetListboxItem(item) : LB_ERR;
  552. NotifyReleaseCapture(prevCapturedId, item);
  553. if (LB_ERR != capturedId && ::GetCapture() != hwnd)
  554. ::SetCapture(hwnd);
  555. }
  556. SetupListboxItem *Listbox::GetCapture()
  557. {
  558. SetupListboxItem *capturedItem;
  559. if (LB_ERR == capturedId || FAILED(groups->FindListboxItem(capturedId, &capturedItem)))
  560. capturedItem = NULL;
  561. return capturedItem;
  562. }
  563. void Listbox::ReleaseCapture()
  564. {
  565. if (LB_ERR != capturedId)
  566. {
  567. INT prevCapturedId = capturedId;
  568. capturedId = LB_ERR;
  569. NotifyReleaseCapture(prevCapturedId, NULL);
  570. if (::GetCapture() == hwnd)
  571. ::ReleaseCapture();
  572. }
  573. }
  574. void Listbox::NotifyReleaseCapture(INT itemId, SetupListboxItem *itemGain)
  575. {
  576. if (LB_ERR == itemId)
  577. return;
  578. SetupListboxItem *item;
  579. if (SUCCEEDED(groups->FindListboxItem(itemId, &item)))
  580. {
  581. RECT itemRect;
  582. GetItemRect(itemId, &itemRect);
  583. item->CaptureChanged(this, &itemRect, itemGain);
  584. }
  585. }
  586. void Listbox::OnCaptureChanged(HWND hwndGained)
  587. {
  588. if (hwnd != hwndGained && LB_ERR != capturedId)
  589. {
  590. INT prevCapturedId = capturedId;
  591. capturedId = LB_ERR;
  592. NotifyReleaseCapture(prevCapturedId, NULL);
  593. }
  594. }
  595. BOOL Listbox::InvalidateRect(const RECT *prcInvalidate, BOOL fErase)
  596. {
  597. return ::InvalidateRect(hwnd, prcInvalidate, fErase);
  598. }
  599. BOOL Listbox::InvalidateItem(INT itemId, BOOL fErase)
  600. {
  601. if (itemId < 0) return FALSE;
  602. RECT itemRect;
  603. if (LB_ERR == SendMessage(hwnd, LB_GETITEMRECT, (WPARAM)itemId, (LPARAM)&itemRect))
  604. return FALSE;
  605. return ::InvalidateRect(hwnd, &itemRect, fErase);
  606. }
  607. void Listbox::OnEraseBkGround(HDC hdc)
  608. {
  609. INT iCount = (INT)SendMessage(hwnd, LB_GETCOUNT, 0, 0L);
  610. RECT clientRect, itemRect;
  611. GetClientRect(hwnd, &clientRect);
  612. if (iCount > 0 &&
  613. LB_ERR != SendMessage(hwnd, LB_GETITEMRECT, (WPARAM)(iCount - 1), (LPARAM)&itemRect))
  614. {
  615. clientRect.top = itemRect.top;
  616. }
  617. if (clientRect.top < clientRect.bottom)
  618. {
  619. HBRUSH hb = NULL;
  620. HWND hParent = GetParent(hwnd);
  621. if (NULL != hParent)
  622. {
  623. hb = (HBRUSH)SendMessage(hParent, WM_CTLCOLORLISTBOX, (WPARAM)hdc, (LPARAM)hwnd);
  624. }
  625. if (NULL == hb)
  626. {
  627. hb = GetSysColorBrush(COLOR_WINDOW);
  628. }
  629. FillRect(hdc, &clientRect, hb);
  630. }
  631. }
  632. void Listbox::OnCommand(INT commandId, INT eventId, HWND hControl)
  633. {
  634. if (NULL == hControl)
  635. {
  636. SetupListboxItem *item = GetSelection();
  637. if (NULL != item)
  638. {
  639. item->Command(this, commandId, eventId);
  640. }
  641. }
  642. }
  643. SetupImage *Listbox::GetExpandboxImage(HDC hdc, BOOL fExpanded)
  644. {
  645. if (fExpanded)
  646. {
  647. if (NULL == expandedImage)
  648. expandedImage = SetupImage::CreateFromPluginBitmap(hdc, L"gen_ml.dll", MAKEINTRESOURCE(137), 3);
  649. return expandedImage;
  650. }
  651. if (NULL == collapsedImage)
  652. collapsedImage = SetupImage::CreateFromPluginBitmap(hdc, L"gen_ml.dll", MAKEINTRESOURCE(135), 3);
  653. return collapsedImage;
  654. }
  655. BOOL Listbox::DrawExpandbox(HDC hdc, BOOL fExpanded, const RECT *pRect, COLORREF rgbBk, COLORREF rgbFg)
  656. {
  657. SetupImage *image = GetExpandboxImage(hdc, fExpanded);
  658. return (NULL != image) ?
  659. image->DrawImage(hdc, pRect->left, pRect->top,
  660. pRect->right - pRect->left, pRect->bottom- pRect->top,
  661. 0, 0, rgbBk, rgbFg)
  662. : FALSE;
  663. }
  664. BOOL Listbox::GetExpandboxMetrics(HDC hdc, BOOL fExpanded, SIZE *pSize)
  665. {
  666. SetupImage *image = GetExpandboxImage(hdc, fExpanded);
  667. return (NULL != image) ? image->GetSize(pSize) : FALSE;
  668. }
  669. HMENU Listbox::GetContextMenu(UINT menuId)
  670. {
  671. HMENU baseMenu = WASABI_API_LOADMENUW(IDR_SETUPMENU);
  672. if (NULL == baseMenu)
  673. return NULL;
  674. switch(menuId)
  675. {
  676. case menuGroupContext:
  677. return GetSubMenu(baseMenu, 0);
  678. }
  679. return NULL;
  680. }
  681. LRESULT Listbox::WindowProc(UINT uMsg, WPARAM wParam, LPARAM lParam)
  682. {
  683. switch(uMsg)
  684. {
  685. case WM_DESTROY:
  686. OnDestroy();
  687. return 0;
  688. case WM_MOUSEMOVE:
  689. OnMouseEvent(uMsg, (UINT)wParam, MAKEPOINTS(lParam), TRUE, &SetupListboxItem::MouseMove);
  690. return 0;
  691. case WM_LBUTTONDOWN:
  692. OnMouseEvent(uMsg, (UINT)wParam, MAKEPOINTS(lParam), FALSE, &SetupListboxItem::LButtonDown);
  693. return 0;
  694. case WM_LBUTTONUP:
  695. OnMouseEvent(uMsg, (UINT)wParam, MAKEPOINTS(lParam), TRUE, &SetupListboxItem::LButtonUp);
  696. return 0;
  697. case WM_LBUTTONDBLCLK:
  698. OnMouseEvent(uMsg, (UINT)wParam, MAKEPOINTS(lParam), FALSE, &SetupListboxItem::LButtonDblClk);
  699. return 0;
  700. case WM_RBUTTONDOWN:
  701. OnMouseEvent(uMsg, (UINT)wParam, MAKEPOINTS(lParam), FALSE, &SetupListboxItem::RButtonDown);
  702. return 0;
  703. case WM_RBUTTONUP:
  704. OnMouseEvent(uMsg, (UINT)wParam, MAKEPOINTS(lParam), TRUE, &SetupListboxItem::RButtonUp);
  705. return 0;
  706. case WM_MOUSELEAVE:
  707. OnMouseLeave();
  708. return 0;
  709. case WM_CAPTURECHANGED:
  710. OnCaptureChanged((HWND)lParam);
  711. break;
  712. case WM_ERASEBKGND:
  713. OnEraseBkGround((HDC)wParam);
  714. return TRUE;
  715. case WM_COMMAND:
  716. OnCommand(LOWORD(wParam), HIWORD(wParam), (HWND)lParam);
  717. return 0;
  718. }
  719. return CallPrevProc(uMsg, wParam, lParam);
  720. }
  721. static LRESULT WINAPI Listbox_WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  722. {
  723. Listbox *list = GetList(hwnd);
  724. if (NULL != list)
  725. return list->WindowProc(uMsg, wParam, lParam);
  726. return (IsWindowUnicode(hwnd)) ?
  727. DefWindowProcW(hwnd, uMsg, wParam, lParam) :
  728. DefWindowProcA(hwnd, uMsg, wParam, lParam);
  729. }