setupGroup.cpp 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929
  1. #include "./setupGroup.h"
  2. #include "./setupGroupFilter.h"
  3. #include "./setupListboxLabel.h"
  4. #include "./setupDetails.h"
  5. #include "./setupPage.h"
  6. #include "../common.h"
  7. #include "../api__ml_online.h"
  8. #include "../resource.h"
  9. #include "../serviceHost.h"
  10. #include "../serviceHelper.h"
  11. #include "../../nu/menuHelpers.h"
  12. #include <vector>
  13. #include <ifc_omservice.h>
  14. #include <ifc_omstorage.h>
  15. #include <ifc_omstorageasync.h>
  16. #include <ifc_omserviceenum.h>
  17. #include <ifc_omfilestorage.h>
  18. #include <shlwapi.h>
  19. #include <strsafe.h>
  20. #include <algorithm>
  21. typedef std::vector<ifc_omservice*> ServiceList;
  22. #define GROUP_MARGINCX 0
  23. #define GROUP_MARGINCY 1
  24. #define TEXT_OFFSET_LEFT 2
  25. #define TEXT_OFFSET_BOTTOM 2
  26. #define TEXT_ALIGN (TA_LEFT | TA_BOTTOM)
  27. SetupGroup::SetupGroup(INT groupId, LPCWSTR pszName, LPCWSTR pszAddress, const GUID *storageId, const GUID *filterId, UINT fStyle)
  28. : ref(1), id(groupId), name(NULL), flags(0), emptyLabel(NULL), errorCode(S_OK), hPage(NULL),
  29. longName(NULL), description(NULL), address(NULL), loadResult(NULL), style(fStyle), loadComplete(NULL)
  30. {
  31. name = Plugin_DuplicateResString(pszName);
  32. address = Plugin_DuplicateResString(pszAddress);
  33. this->storageId = (NULL != storageId) ? *storageId : GUID_NULL;
  34. this->filterId = (NULL != filterId) ? *filterId : GUID_NULL;
  35. InitializeCriticalSection(&lock);
  36. }
  37. SetupGroup::~SetupGroup()
  38. {
  39. Plugin_FreeResString(name);
  40. Plugin_FreeResString(address);
  41. SetLongName(NULL);
  42. SetDescription(NULL);
  43. EnterCriticalSection(&lock);
  44. size_t index = list.size();
  45. while(index--)
  46. {
  47. list[index]->Release();
  48. }
  49. if (NULL != emptyLabel)
  50. emptyLabel->Release();
  51. if (NULL != loadResult)
  52. {
  53. ifc_omstorage *storage;
  54. HRESULT hr = OMSERVICEMNGR->QueryStorage(&storageId, &storage);
  55. if (SUCCEEDED(hr))
  56. {
  57. storage->RequestAbort(loadResult, TRUE);
  58. }
  59. loadResult->Release();
  60. loadResult = NULL;
  61. }
  62. if (NULL != loadComplete)
  63. CloseHandle(loadComplete);
  64. LeaveCriticalSection(&lock);
  65. DeleteCriticalSection(&lock);
  66. }
  67. SetupGroup *SetupGroup::CreateInstance(INT groupId, LPCWSTR pszName, LPCWSTR pszAddress, const GUID *storageId, const GUID *filterId, UINT fStyle)
  68. {
  69. return new SetupGroup(groupId, pszName, pszAddress, storageId, filterId, fStyle);
  70. }
  71. ULONG SetupGroup::AddRef()
  72. {
  73. return InterlockedIncrement((LONG*)&ref);
  74. }
  75. ULONG SetupGroup::Release()
  76. {
  77. if (0 == ref)
  78. return ref;
  79. LONG r = InterlockedDecrement((LONG*)&ref);
  80. if (0 == r)
  81. delete(this);
  82. return r;
  83. }
  84. HRESULT SetupGroup::GetName(LPWSTR pszBuffer, INT cchBufferMax)
  85. {
  86. if (NULL == pszBuffer)
  87. return E_POINTER;
  88. HRESULT hr;
  89. if (NULL != name)
  90. {
  91. if (IS_INTRESOURCE(name))
  92. {
  93. WASABI_API_LNGSTRINGW_BUF((INT)(INT_PTR)name, pszBuffer, cchBufferMax);
  94. hr = (L'\0' != *pszBuffer) ? S_OK : E_FAIL;
  95. }
  96. else
  97. {
  98. hr = StringCchCopyW(pszBuffer, cchBufferMax, name);
  99. }
  100. }
  101. else
  102. {
  103. hr = StringCchCopyW(pszBuffer, cchBufferMax, L"Unknown");
  104. }
  105. return hr;
  106. }
  107. HRESULT SetupGroup::GetLongName(LPWSTR pszBuffer, INT cchBufferMax)
  108. {
  109. if (NULL == pszBuffer)
  110. return E_POINTER;
  111. HRESULT hr;
  112. if (NULL == longName)
  113. return GetName(pszBuffer, cchBufferMax);
  114. if (IS_INTRESOURCE(longName))
  115. {
  116. WASABI_API_LNGSTRINGW_BUF((INT)(INT_PTR)longName, pszBuffer, cchBufferMax);
  117. hr = (L'\0' != *pszBuffer) ? S_OK : E_FAIL;
  118. }
  119. else
  120. {
  121. hr = StringCchCopyW(pszBuffer, cchBufferMax, longName);
  122. }
  123. return hr;
  124. }
  125. HRESULT SetupGroup::GetDescription(LPWSTR pszBuffer, INT cchBufferMax)
  126. {
  127. if (NULL == pszBuffer)
  128. return E_POINTER;
  129. HRESULT hr;
  130. if (NULL != description && IS_INTRESOURCE(description))
  131. {
  132. WASABI_API_LNGSTRINGW_BUF((INT)(INT_PTR)description, pszBuffer, cchBufferMax);
  133. hr = (L'\0' != *pszBuffer) ? S_OK : E_FAIL;
  134. }
  135. else
  136. {
  137. hr = StringCchCopyEx(pszBuffer, cchBufferMax, description, NULL, NULL, STRSAFE_IGNORE_NULLS);
  138. }
  139. return hr;
  140. }
  141. size_t SetupGroup::GetRecordCount()
  142. {
  143. return list.size();
  144. }
  145. size_t SetupGroup::GetListboxCount()
  146. {
  147. if (0 != (flagCollapsed & flags)) return 0;
  148. size_t listSize = list.size();
  149. if (0 == listSize)
  150. {
  151. return (NULL != emptyLabel && FALSE == emptyLabel->IsNameNull()) ? 1 : 0;
  152. }
  153. return listSize;
  154. }
  155. SetupListboxItem *SetupGroup::GetListboxItem(size_t index)
  156. {
  157. if (0 != (flagCollapsed & flags)) return NULL;
  158. size_t listSize = list.size();
  159. if (0 == listSize)
  160. {
  161. return (NULL != emptyLabel && FALSE == emptyLabel->IsNameNull()) ? emptyLabel : NULL;
  162. }
  163. return list[index];
  164. }
  165. BOOL SetupGroup::IsModified()
  166. {
  167. size_t index = list.size();
  168. while(index--)
  169. {
  170. if (list[index]->IsModified())
  171. return TRUE;
  172. }
  173. return FALSE;
  174. }
  175. BOOL SetupGroup::IsExpanded()
  176. {
  177. return (0 == (flagCollapsed & flags));
  178. }
  179. void SetupGroup::SetExpanded(BOOL fExpanded)
  180. {
  181. if ((FALSE == fExpanded) == (FALSE == IsExpanded()))
  182. return;
  183. if (FALSE == fExpanded)
  184. flags |= flagCollapsed;
  185. else
  186. flags &= ~flagCollapsed;
  187. }
  188. void SetupGroup::Clear(BOOL fInvalidate)
  189. {
  190. size_t index = list.size();
  191. if (0 == index) return;
  192. EnterCriticalSection(&lock);
  193. while(index--)
  194. {
  195. SetupRecord *record = list[index];
  196. if (NULL != record)
  197. {
  198. record->Release();
  199. }
  200. }
  201. list.clear();
  202. LeaveCriticalSection(&lock);
  203. SetEmptyText(MAKEINTRESOURCE(IDS_SETUP_EMPTYGROUP), FALSE);
  204. if (FALSE != fInvalidate && NULL != hPage)
  205. PostMessage(hPage, SPM_UPDATELIST, (WPARAM)id, NULL);
  206. }
  207. static void CALLBACK SetupGroup_LoadCallback(ifc_omstorageasync *result)
  208. {
  209. if (NULL == result) return;
  210. SetupGroup *group;
  211. if (SUCCEEDED(result->GetData((void**)&group)) && NULL != group)
  212. {
  213. group->OnLoadCompleted();
  214. }
  215. }
  216. __inline static int __cdecl SetupGroup_AlphabeticalSorter(const void *elem1, const void *elem2)
  217. {
  218. SetupRecord *record1 = (SetupRecord*)elem1;
  219. SetupRecord *record2 = (SetupRecord*)elem2;
  220. if (NULL == record1 || NULL == record2)
  221. return (INT)(INT_PTR)(record1 - record2);
  222. ifc_omservice *svc1 = record1->GetService();
  223. ifc_omservice *svc2 = record2->GetService();
  224. if (NULL == svc1 || NULL == svc2)
  225. return (INT)(INT_PTR)(svc1 - svc2);
  226. WCHAR szBuffer1[256] = {0}, szBuffer2[256] = {0};
  227. if (FAILED(svc1->GetName(szBuffer1, ARRAYSIZE(szBuffer1))))
  228. szBuffer1[0] = L'\0';
  229. if (FAILED(svc2->GetName(szBuffer2, ARRAYSIZE(szBuffer2))))
  230. szBuffer2[0] = L'\0';
  231. return CompareString(LOCALE_USER_DEFAULT, NORM_IGNORECASE, szBuffer1, -1, szBuffer2, -1) - 2;
  232. }
  233. __inline static bool __cdecl SetupGroup_AlphabeticalSorter_V2(const void* elem1, const void* elem2)
  234. {
  235. return SetupGroup_AlphabeticalSorter(elem1, elem2) < 0;
  236. }
  237. void SetupGroup::OnLoadCompleted()
  238. {
  239. ifc_omstorage *storage;
  240. HRESULT hr = OMSERVICEMNGR->QueryStorage(&storageId, &storage);
  241. if (SUCCEEDED(hr))
  242. {
  243. ifc_omserviceenum *serviceEnum;
  244. hr = storage->EndLoad(loadResult, &serviceEnum);
  245. if (SUCCEEDED(hr))
  246. {
  247. SetupGroupFilter *filter;
  248. if (FAILED(SetupGroupFilter::CreateInstance(&filterId, &filter)))
  249. {
  250. filter = NULL;
  251. }
  252. else if (FAILED(filter->Initialize()))
  253. {
  254. filter->Release();
  255. filter = NULL;
  256. }
  257. EnterCriticalSection(&lock);
  258. ifc_omservice *service;
  259. UINT filterResult, defaultFilter;
  260. defaultFilter = SetupGroupFilter::serviceInclude;
  261. if (0 != (styleDefaultUnsubscribed & style))
  262. defaultFilter |= SetupGroupFilter::serviceForceUnsubscribe;
  263. else if (0 != (styleDefaultSubscribed & style))
  264. defaultFilter |= SetupGroupFilter::serviceForceSubscribe;
  265. while(S_OK == serviceEnum->Next(1, &service, NULL))
  266. {
  267. filterResult = defaultFilter;
  268. if (NULL != filter && FAILED(filter->ProcessService(service, &filterResult)))
  269. filterResult = defaultFilter;
  270. if (0 == (SetupGroupFilter::serviceInclude & filterResult))
  271. {
  272. service->Release();
  273. service = NULL;
  274. continue;
  275. }
  276. if (0 != (SetupGroupFilter::serviceForceUnsubscribe & filterResult))
  277. ServiceHelper_Subscribe(service, TRUE, 0);
  278. else if (0 != (SetupGroupFilter::serviceForceSubscribe & filterResult))
  279. ServiceHelper_Subscribe(service, FALSE, 0);
  280. if (0 != (styleSaveAll & style))
  281. ServiceHelper_MarkModified(service, (UINT)-1, (UINT)-1);
  282. SetupRecord *record = SetupRecord::CreateInstance(service);
  283. if (NULL != record)
  284. {
  285. if (0 != (SetupGroupFilter::serviceForceUnsubscribe & filterResult))
  286. record->SetSelected(FALSE);
  287. else if (0 != (SetupGroupFilter::serviceForceSubscribe & filterResult))
  288. record->SetSelected(TRUE);
  289. list.push_back(record);
  290. }
  291. service->Release();
  292. }
  293. if (0 != (styleSortAlphabetically & style))
  294. {
  295. //qsort(list.first(), list.size(), sizeof(SetupRecord*), SetupGroup_AlphabeticalSorter);
  296. std::sort(list.begin(), list.end(), SetupGroup_AlphabeticalSorter_V2);
  297. }
  298. LeaveCriticalSection(&lock);
  299. serviceEnum->Release();
  300. if (NULL != filter)
  301. filter->Release();
  302. }
  303. storage->Release();
  304. }
  305. EnterCriticalSection(&lock);
  306. loadResult->Release();
  307. loadResult = NULL;
  308. if (NULL != loadComplete)
  309. {
  310. SetEvent(loadComplete);
  311. CloseHandle(loadComplete);
  312. loadComplete = NULL;
  313. }
  314. LeaveCriticalSection(&lock);
  315. LPCWSTR pszText = MAKEINTRESOURCE(((FAILED(hr)) ? IDS_SETUP_GROUPLOADFAILED : IDS_SETUP_EMPTYGROUP));
  316. SetEmptyText( pszText, TRUE);
  317. }
  318. HRESULT SetupGroup::RequestReload()
  319. {
  320. if (NULL == OMSERVICEMNGR)
  321. return E_UNEXPECTED;
  322. HRESULT hr;
  323. EnterCriticalSection(&lock);
  324. if (NULL != loadResult)
  325. hr = E_PENDING;
  326. else
  327. {
  328. if (NULL != loadComplete)
  329. {
  330. CloseHandle(loadComplete);
  331. loadComplete = NULL;
  332. }
  333. Clear(FALSE);
  334. SetEmptyText(MAKEINTRESOURCE(IDS_SETUP_LOADINGGROUP), TRUE);
  335. ifc_omstorage *storage;
  336. hr = OMSERVICEMNGR->QueryStorage(&storageId, &storage);
  337. if (SUCCEEDED(hr))
  338. {
  339. ServiceHost *serviceHost;
  340. if (FAILED(ServiceHost::GetCachedInstance(&serviceHost)))
  341. serviceHost = NULL;
  342. hr = storage->BeginLoad(address, serviceHost, SetupGroup_LoadCallback, this, &loadResult);
  343. storage->Release();
  344. if (NULL != serviceHost)
  345. serviceHost->Release();
  346. }
  347. if (FAILED(hr))
  348. {
  349. SetEmptyText(MAKEINTRESOURCE(IDS_SETUP_GROUPLOADFAILED), TRUE);
  350. }
  351. }
  352. LeaveCriticalSection(&lock);
  353. return hr;
  354. }
  355. void SetupGroup::SetPageWnd(HWND hPage)
  356. {
  357. this->hPage = hPage;
  358. }
  359. HRESULT SetupGroup::SignalLoadCompleted(HANDLE event)
  360. {
  361. HRESULT hr;
  362. if (NULL == event) return E_INVALIDARG;
  363. EnterCriticalSection(&lock);
  364. if (NULL == loadResult)
  365. {
  366. SetEvent(event);
  367. hr = S_OK;
  368. }
  369. else
  370. {
  371. if (NULL != loadComplete)
  372. CloseHandle(loadComplete);
  373. if (FALSE == DuplicateHandle(GetCurrentProcess(), event, GetCurrentProcess(), &loadComplete, 0, FALSE, DUPLICATE_SAME_ACCESS))
  374. {
  375. DWORD error = GetLastError();
  376. hr = HRESULT_FROM_WIN32(error);
  377. }
  378. hr = S_OK;
  379. }
  380. LeaveCriticalSection(&lock);
  381. return hr;
  382. }
  383. HRESULT SetupGroup::Save(SetupLog *log)
  384. {
  385. HRESULT hr(S_OK);
  386. size_t index = list.size();
  387. while(index--)
  388. {
  389. if (FAILED(list[index]->Save(log)))
  390. hr = E_FAIL;
  391. }
  392. return hr;
  393. }
  394. void SetupGroup::GetColors(HDC hdc, UINT state, COLORREF *rgbBkOut, COLORREF *rgbTextOut)
  395. {
  396. COLORREF rgbBk, rgbText;
  397. if (0 != (ODS_DISABLED & state))
  398. {
  399. rgbBk = GetBkColor(hdc);
  400. rgbText = GetSysColor(COLOR_GRAYTEXT);
  401. }
  402. else
  403. {
  404. if (0 != (ODS_SELECTED & state))
  405. {
  406. if (0 == (ODS_INACTIVE & state))
  407. {
  408. rgbBk = GetSysColor(COLOR_HIGHLIGHT);
  409. rgbText = GetSysColor(COLOR_HIGHLIGHTTEXT);
  410. }
  411. else
  412. {
  413. rgbBk = GetSysColor(COLOR_3DFACE);
  414. rgbText = GetSysColor(COLOR_WINDOWTEXT);
  415. }
  416. }
  417. else
  418. {
  419. rgbBk = GetSysColor(COLOR_WINDOW);
  420. rgbText = GetSysColor(COLOR_WINDOWTEXT);
  421. }
  422. }
  423. if (NULL != rgbBkOut) *rgbBkOut = rgbBk;
  424. if (NULL != rgbTextOut) *rgbTextOut = rgbText;
  425. }
  426. HBRUSH SetupGroup::GetBrush(HDC hdc, UINT state)
  427. {
  428. if (0 != (ODS_DISABLED & state))
  429. {
  430. return GetSysColorBrush(COLOR_WINDOW);
  431. }
  432. if (0 != (ODS_COMBOBOXEDIT & state))
  433. {
  434. return GetSysColorBrush(COLOR_WINDOWTEXT);
  435. }
  436. if (0 != (ODS_SELECTED & state))
  437. {
  438. return GetSysColorBrush( (0 == (ODS_INACTIVE & state)) ? COLOR_HIGHLIGHT : COLOR_3DFACE);
  439. }
  440. return GetSysColorBrush(COLOR_WINDOW);
  441. }
  442. BOOL SetupGroup::MeasureItem(SetupListbox *instance, UINT *cx, UINT *cy)
  443. {
  444. HDC hdc = GetDCEx(instance->GetHwnd(), NULL, DCX_CACHE | DCX_NORESETATTRS);
  445. if (NULL == hdc) return FALSE;
  446. HFONT originalFont = (HFONT)SelectObject(hdc, instance->GetFont());
  447. SIZE imageSize;
  448. if (!instance->GetExpandboxMetrics(hdc, IsExpanded(), &imageSize))
  449. ZeroMemory(&imageSize, sizeof(SIZE));
  450. if (NULL != cy)
  451. {
  452. *cy = 0;
  453. TEXTMETRIC tm;
  454. if (GetTextMetrics(hdc, &tm))
  455. {
  456. *cy = tm.tmHeight + tm.tmExternalLeading;
  457. if (imageSize.cy > (INT)*cy) *cy = imageSize.cy;
  458. *cy += GROUP_MARGINCY*2;
  459. }
  460. }
  461. if (NULL != cx)
  462. {
  463. *cx = imageSize.cx;
  464. WCHAR szBuffer[128] = {0};
  465. if (SUCCEEDED(GetName(szBuffer, ARRAYSIZE(szBuffer))))
  466. {
  467. INT cchBuffer = lstrlenW(szBuffer);
  468. SIZE textSize;
  469. if (0 != cchBuffer && GetTextExtentPoint32(hdc, szBuffer, cchBuffer, &textSize))
  470. {
  471. *cx += textSize.cx;
  472. }
  473. }
  474. if (0 != *cx) *cx += GROUP_MARGINCX*2;
  475. }
  476. SelectObject(hdc, originalFont);
  477. ReleaseDC(instance->GetHwnd(), hdc);
  478. return TRUE;
  479. }
  480. static void SetupGroup_DrawFrame(HDC hdc, const RECT *prc, INT width, COLORREF rgbFrame)
  481. {
  482. if (width > 0)
  483. {
  484. COLORREF rgbOld = SetBkColor(hdc, rgbFrame);
  485. RECT rcPart;
  486. SetRect(&rcPart, prc->left, prc->top, prc->right, prc->top + width);
  487. ExtTextOut(hdc, 0, 0, ETO_OPAQUE, &rcPart, NULL, 0, NULL);
  488. SetRect(&rcPart, prc->left, prc->bottom - width, prc->right, prc->bottom);
  489. ExtTextOut(hdc, 0, 0, ETO_OPAQUE, &rcPart, NULL, 0, NULL);
  490. SetRect(&rcPart, prc->left, prc->top + width, prc->left + width, prc->bottom - width);
  491. ExtTextOut(hdc, 0, 0, ETO_OPAQUE, &rcPart, NULL, 0, NULL);
  492. SetRect(&rcPart, prc->right - width, prc->top + width, prc->right, prc->bottom - width);
  493. ExtTextOut(hdc, 0, 0, ETO_OPAQUE, &rcPart, NULL, 0, NULL);
  494. if (rgbOld != rgbFrame)
  495. SetBkColor(hdc, rgbOld);
  496. }
  497. }
  498. BOOL SetupGroup::DrawItem(SetupListbox *instance, HDC hdc, const RECT *prc, UINT state)
  499. {
  500. LONG paintLeft = prc->left + GROUP_MARGINCX;
  501. RECT partRect;
  502. SetRectEmpty(&partRect);
  503. COLORREF rgbBk, rgbText;
  504. GetColors(hdc, state, &rgbBk, &rgbText);
  505. COLORREF origBk = SetBkColor(hdc, rgbBk);
  506. COLORREF origText = SetTextColor(hdc, rgbText);
  507. UINT textAlign = SetTextAlign(hdc, TEXT_ALIGN);
  508. HRGN backRgn, rgn;
  509. backRgn = CreateRectRgnIndirect(prc);
  510. rgn = CreateRectRgn(0,0,0,0);
  511. SetRectEmpty(&partRect);
  512. if (instance->GetExpandboxMetrics(hdc, IsExpanded(), (((SIZE*)&partRect) + 1)))
  513. {
  514. INT space = (prc->bottom - prc->top) - (partRect.bottom- partRect.top);
  515. INT offsetY = space / 2 + space%2;
  516. if (offsetY < 0) offsetY = 0;
  517. OffsetRect(&partRect, paintLeft, prc->top + offsetY);
  518. if (instance->DrawExpandbox(hdc, IsExpanded(), &partRect, rgbBk, rgbText))
  519. {
  520. paintLeft = partRect.right;
  521. if (SetRectRgn(rgn, partRect.left, partRect.top, partRect.right, partRect.bottom))
  522. CombineRgn(backRgn, backRgn, rgn, RGN_DIFF);
  523. }
  524. }
  525. WCHAR szBuffer[128] = {0};
  526. INT cchBuffer = 0;
  527. if (SUCCEEDED(GetName(szBuffer, ARRAYSIZE(szBuffer))))
  528. cchBuffer = lstrlenW(szBuffer);
  529. SetRect(&partRect, paintLeft, prc->top, prc->right, prc->bottom);
  530. if (ExtTextOut(hdc, partRect.left + TEXT_OFFSET_LEFT, partRect.bottom - TEXT_OFFSET_BOTTOM,
  531. ETO_OPAQUE | ETO_CLIPPED, &partRect, szBuffer, cchBuffer, NULL))
  532. {
  533. if (SetRectRgn(rgn, partRect.left, partRect.top, partRect.right, partRect.bottom))
  534. CombineRgn(backRgn, backRgn, rgn, RGN_DIFF);
  535. }
  536. COLORREF rgbLine = ColorAdjustLuma(rgbBk, -150, TRUE);
  537. if (rgbLine != rgbBk)
  538. {
  539. RECT lineRect;
  540. SetRect(&lineRect, prc->left, prc->bottom - 1, prc->right, prc->bottom);
  541. SetBkColor(hdc, rgbLine);
  542. if (ExtTextOut(hdc, 0, 0, ETO_OPAQUE, &lineRect, NULL, 0, NULL))
  543. {
  544. if (SetRectRgn(rgn, lineRect.left, lineRect.top, lineRect.right, lineRect.bottom))
  545. CombineRgn(backRgn, backRgn, rgn, RGN_DIFF);
  546. }
  547. SetBkColor(hdc, rgbBk);
  548. }
  549. if (0 != (flagMenuActive & flags))
  550. {
  551. COLORREF rgbFrame = rgbLine; //ColorAdjustLuma(GetSysColor(COLOR_HIGHLIGHT), 100, TRUE);
  552. SetupGroup_DrawFrame(hdc, prc, 1, rgbFrame);
  553. if (SetRectRgn(rgn, prc->left + 1, prc->top + 1, prc->right - 1, prc->bottom - 1))
  554. CombineRgn(backRgn, backRgn, rgn, RGN_AND);
  555. }
  556. if (NULL != backRgn)
  557. {
  558. FillRgn(hdc, backRgn, GetBrush(hdc, state));
  559. DeleteObject(backRgn);
  560. }
  561. if (NULL != rgn)
  562. DeleteObject(rgn);
  563. if (ODS_FOCUS == ((ODS_FOCUS | 0x0200/*ODS_NOFOCUSRECT*/) & state))
  564. DrawFocusRect(hdc, prc);
  565. if (TEXT_ALIGN != textAlign) SetTextAlign(hdc, textAlign);
  566. if (origBk != rgbBk) SetBkColor(hdc, origBk);
  567. if (origText != rgbText) SetTextColor(hdc, origText);
  568. return TRUE;
  569. }
  570. INT_PTR SetupGroup::KeyToItem(SetupListbox *instance, const RECT *prcItem, INT vKey)
  571. {
  572. switch(vKey)
  573. {
  574. case VK_SPACE:
  575. InvertExpanded(instance);
  576. return -2;
  577. }
  578. return -1;
  579. }
  580. BOOL SetupGroup::MouseMove(SetupListbox *instance, const RECT *prcItem, UINT mouseFlags, POINT pt)
  581. {
  582. return FALSE;
  583. }
  584. BOOL SetupGroup::MouseLeave(SetupListbox *instance, const RECT *prcItem)
  585. {
  586. return FALSE;
  587. }
  588. BOOL SetupGroup::LButtonDown(SetupListbox *instance, const RECT *prcItem, UINT mouseFlags, POINT pt)
  589. {
  590. return FALSE;
  591. }
  592. BOOL SetupGroup::LButtonUp(SetupListbox *instance, const RECT *prcItem, UINT mouseFlags, POINT pt)
  593. {
  594. return FALSE;
  595. }
  596. BOOL SetupGroup::LButtonDblClk(SetupListbox *instance, const RECT *prcItem, UINT mouseFlags, POINT pt)
  597. {
  598. InvertExpanded(instance);
  599. return TRUE;
  600. }
  601. BOOL SetupGroup::RButtonDown(SetupListbox *instance, const RECT *prcItem, UINT mouseFlags, POINT pt)
  602. {
  603. return TRUE;
  604. }
  605. BOOL SetupGroup::RButtonUp(SetupListbox *instance, const RECT *prcItem, UINT mouseFlags, POINT pt)
  606. {
  607. HMENU hMenu = instance->GetContextMenu(SetupListbox::menuGroupContext);
  608. if (NULL == hMenu)
  609. return FALSE;
  610. hMenu = MenuHelper_DuplcateMenu(hMenu);
  611. if (NULL == hMenu) return FALSE;
  612. MENUITEMINFO mi;
  613. mi.cbSize = sizeof(MENUITEMINFO);
  614. mi.fMask = MIIM_STATE;
  615. GetMenuItemInfo(hMenu, ID_GROUP_TOGGLE, FALSE, &mi);
  616. mi.fMask = 0;
  617. if (0 == (MFS_DEFAULT & mi.fState))
  618. {
  619. mi.fMask |= MIIM_STATE;
  620. mi.fState |= MFS_DEFAULT;
  621. }
  622. WCHAR szBuffer[128] = {0};
  623. WASABI_API_LNGSTRINGW_BUF(((IsExpanded()) ? IDS_COLLAPSE : IDS_EXPAND), szBuffer, ARRAYSIZE(szBuffer));
  624. mi.fMask |= MIIM_STRING;
  625. mi.dwTypeData = szBuffer;
  626. if (0 != mi.fMask)
  627. SetMenuItemInfo(hMenu, ID_GROUP_TOGGLE, FALSE, &mi);
  628. if (0 == list.size())
  629. {
  630. EnableMenuItem(hMenu, ID_GROUP_SELECTALL, MF_BYCOMMAND | MF_DISABLED | MF_GRAYED);
  631. EnableMenuItem(hMenu, ID_GROUP_UNSELECTALL, MF_BYCOMMAND | MF_DISABLED | MF_GRAYED);
  632. }
  633. if (0 != (flagLoading & flags))
  634. {
  635. EnableMenuItem(hMenu, ID_GROUP_RELOAD, MF_BYCOMMAND | MF_DISABLED | MF_GRAYED);
  636. }
  637. MapWindowPoints(instance->GetHwnd(), HWND_DESKTOP, &pt, 1);
  638. flags |= flagMenuActive;
  639. instance->InvalidateRect(prcItem, TRUE);
  640. INT cmd = TrackPopupMenuEx(hMenu, TPM_LEFTALIGN | TPM_TOPALIGN | TPM_RETURNCMD, pt.x, pt.y, instance->GetHwnd(), NULL);
  641. if (0 != cmd)
  642. {
  643. Command(instance, cmd, 0);
  644. }
  645. DestroyMenu(hMenu);
  646. flags &= ~flagMenuActive;
  647. instance->InvalidateRect(prcItem, TRUE);
  648. return TRUE;
  649. }
  650. void SetupGroup::CaptureChanged(SetupListbox *instance, const RECT *prcItem, SetupListboxItem *captured)
  651. {
  652. }
  653. void SetupGroup::InvertExpanded(SetupListbox *instance)
  654. {
  655. if (FALSE != IsExpanded())
  656. ValidateSelection(instance);
  657. SetExpanded(!IsExpanded());
  658. if (NULL != instance)
  659. {
  660. instance->UpdateCount();
  661. UpdateWindow(instance->GetHwnd());
  662. }
  663. }
  664. void SetupGroup::SelectAll(SetupListbox *instance, BOOL fSelect)
  665. {
  666. size_t index = list.size();
  667. INT baseIndex;
  668. if (NULL == instance || FALSE == instance->GetIndex(this, &baseIndex))
  669. baseIndex = -1;
  670. else
  671. baseIndex++;
  672. while(index--)
  673. {
  674. SetupRecord *record = list[index];
  675. if (NULL != record && !record->IsDisabled())
  676. {
  677. if ((FALSE == fSelect) != (FALSE == record->IsSelected()))
  678. {
  679. record->SetSelected(fSelect);
  680. if (0 == (flagCollapsed & flags) && NULL != instance && -1 != baseIndex)
  681. {
  682. instance->InvalidateItem((INT)(baseIndex + index), TRUE);
  683. }
  684. }
  685. }
  686. }
  687. }
  688. void SetupGroup::SetEmptyText(LPCWSTR pszText, BOOL fInvalidate)
  689. {
  690. if (NULL == emptyLabel)
  691. emptyLabel = SetupListboxLabel::CreateInstance(pszText);
  692. else
  693. emptyLabel->SetName(pszText);
  694. if (FALSE != fInvalidate && NULL != hPage)
  695. PostMessage(hPage, SPM_UPDATELIST, (WPARAM)id, NULL);
  696. }
  697. HWND SetupGroup::CreateDetailsView(HWND hParent)
  698. {
  699. WCHAR szName[64] = {0};
  700. if (FALSE == GetUniqueName(szName, ARRAYSIZE(szName)))
  701. szName[0] = L'\0';
  702. return SetupDetails_CreateGroupView(hParent, szName, this);
  703. }
  704. BOOL SetupGroup::GetUniqueName(LPWSTR pszBuffer, UINT cchBufferMax)
  705. {
  706. if (NULL == pszBuffer ||
  707. FAILED(StringCchPrintf(pszBuffer, cchBufferMax, L"grp_id_%d", id)))
  708. {
  709. return FALSE;
  710. }
  711. return TRUE;
  712. }
  713. void SetupGroup::SetLongName(LPCWSTR pszText)
  714. {
  715. if (NULL != longName && !IS_INTRESOURCE(longName))
  716. Plugin_FreeString(longName);
  717. longName = NULL;
  718. if (NULL != pszText)
  719. longName = (IS_INTRESOURCE(pszText)) ? (LPWSTR)pszText : Plugin_CopyString(pszText);
  720. }
  721. void SetupGroup::SetDescription(LPCWSTR pszText)
  722. {
  723. if (NULL != description && !IS_INTRESOURCE(description))
  724. Plugin_FreeString(description);
  725. description = NULL;
  726. if (NULL != pszText)
  727. description = (IS_INTRESOURCE(pszText)) ? (LPWSTR)pszText : Plugin_CopyString(pszText);
  728. }
  729. void SetupGroup::ValidateSelection(SetupListbox *instance)
  730. {
  731. if (NULL == instance)
  732. return;
  733. SetupListboxItem *selection = instance->GetSelection();
  734. if (NULL != selection)
  735. {
  736. EnterCriticalSection(&lock);
  737. size_t index = list.size();
  738. while(index--)
  739. {
  740. if (list[index] == selection)
  741. {
  742. instance->SetSelection(this);
  743. break;
  744. }
  745. }
  746. LeaveCriticalSection(&lock);
  747. }
  748. }
  749. void SetupGroup::Command(SetupListbox *instance, INT commandId, INT eventId)
  750. {
  751. switch(commandId)
  752. {
  753. case ID_GROUP_TOGGLE:
  754. InvertExpanded(instance);
  755. break;
  756. case ID_GROUP_SELECTALL:
  757. SelectAll(instance, TRUE);
  758. break;
  759. case ID_GROUP_UNSELECTALL:
  760. SelectAll(instance, FALSE);
  761. break;
  762. case ID_GROUP_RELOAD:
  763. ValidateSelection(instance);
  764. RequestReload();
  765. break;
  766. }
  767. }