skinnedcombo.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444
  1. #include "./skinnedcombo.h"
  2. #include "./skinnedheader.h"
  3. #include "../winamp/wa_dlg.h"
  4. #include "./skinning.h"
  5. #include "../nu/trace.h"
  6. #include <windowsx.h>
  7. #include <strsafe.h>
  8. #define COMBO_TEXT_MAX 512
  9. SkinnedCombobox::SkinnedCombobox(void) : SkinnedWnd(FALSE), activeBorder(TRUE)
  10. {
  11. }
  12. SkinnedCombobox::~SkinnedCombobox(void)
  13. {
  14. }
  15. BOOL SkinnedCombobox::Attach(HWND hwndCombo)
  16. {
  17. if(!SkinnedWnd::Attach(hwndCombo)) return FALSE;
  18. SetType(SKINNEDWND_TYPE_COMBOBOX);
  19. activeBorder = TRUE;
  20. COMBOBOXINFO cbi;
  21. ZeroMemory(&cbi, sizeof(COMBOBOXINFO));
  22. cbi.cbSize = sizeof(COMBOBOXINFO);
  23. if (GetComboBoxInfo(hwnd, &cbi))
  24. {
  25. if (NULL != cbi.hwndItem) SkinWindowEx(cbi.hwndItem, SKINNEDWND_TYPE_EDIT, style);
  26. if (NULL != cbi.hwndList)
  27. {
  28. SkinWindowEx(cbi.hwndList, SKINNEDWND_TYPE_LISTBOX, style);
  29. }
  30. }
  31. SetWindowPos(hwnd, NULL, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE | SWP_FRAMECHANGED);
  32. return TRUE;
  33. }
  34. BOOL SkinnedCombobox::SetStyle(UINT newStyle, BOOL bRedraw)
  35. {
  36. BOOL result = __super::SetStyle(newStyle, bRedraw);
  37. if (hwnd)
  38. {
  39. COMBOBOXINFO cbi;
  40. ZeroMemory(&cbi, sizeof(COMBOBOXINFO));
  41. cbi.cbSize = sizeof(COMBOBOXINFO);
  42. activeBorder = (0 == (SWCBS_TOOLBAR & style));
  43. if (GetComboBoxInfo(hwnd, &cbi))
  44. {
  45. if (NULL != cbi.hwndItem) MLSkinnedWnd_SetStyle(cbi.hwndItem, style);
  46. if (NULL != cbi.hwndList) MLSkinnedWnd_SetStyle(cbi.hwndList, style);
  47. }
  48. }
  49. return result;
  50. }
  51. BOOL SkinnedCombobox::IsButtonDown(DWORD windowStyle)
  52. {
  53. if(GetAsyncKeyState((GetSystemMetrics(SM_SWAPBUTTON)) ? VK_RBUTTON : VK_LBUTTON) & 0x8000)
  54. {
  55. if (CBS_DROPDOWNLIST == (0x0F & windowStyle))
  56. {
  57. POINT pt;
  58. RECT rc;
  59. if (hwnd == GetFocus() && GetClientRect(hwnd, &rc))
  60. {
  61. GetCursorPos(&pt);
  62. MapWindowPoints(HWND_DESKTOP, hwnd, &pt, 1);
  63. return PtInRect(&rc, pt);
  64. }
  65. return FALSE;
  66. }
  67. COMBOBOXINFO cbi;
  68. ZeroMemory(&cbi, sizeof(COMBOBOXINFO));
  69. cbi.cbSize = sizeof(COMBOBOXINFO);
  70. if (GetComboBoxInfo(hwnd, &cbi))
  71. {
  72. //check if in arrow down area
  73. POINT pt;
  74. GetCursorPos(&pt);
  75. MapWindowPoints(HWND_DESKTOP, hwnd, &pt, 1);
  76. return PtInRect(&cbi.rcButton, pt);
  77. }
  78. }
  79. return FALSE;
  80. }
  81. void SkinnedCombobox::DrawButton(HDC hdc, RECT *prcButton, BOOL bPressed, BOOL bActive)
  82. {
  83. COLORREF rgbBkOld, rgbBk;
  84. rgbBk = WADlg_getColor(WADLG_LISTHEADER_BGCOLOR);
  85. rgbBkOld = SetBkColor(hdc, rgbBk);
  86. ExtTextOutW(hdc, 0, 0, ETO_OPAQUE, prcButton, NULL, 0, 0);
  87. if (bActive)
  88. {
  89. HPEN pen, penOld;
  90. pen = (HPEN)MlStockObjects_Get((bPressed) ? HEADERBOTTOM_PEN : HEADERTOP_PEN);
  91. penOld = (HPEN)SelectObject(hdc, pen);
  92. MoveToEx(hdc, prcButton->left, prcButton->top, NULL);
  93. LineTo(hdc, prcButton->right, prcButton->top);
  94. MoveToEx(hdc, prcButton->left, prcButton->top, NULL);
  95. LineTo(hdc, prcButton->left, prcButton->bottom);
  96. if (!bPressed)
  97. {
  98. SelectObject(hdc, penOld);
  99. pen = (HPEN)MlStockObjects_Get(HEADERBOTTOM_PEN);
  100. penOld = (HPEN)SelectObject(hdc, pen);
  101. }
  102. MoveToEx(hdc, prcButton->right - 1, prcButton->top, NULL);
  103. LineTo(hdc, prcButton->right - 1, prcButton->bottom);
  104. MoveToEx(hdc, prcButton->right - 1, prcButton->bottom - 1, NULL);
  105. LineTo(hdc, prcButton->left - 1, prcButton->bottom - 1);
  106. if (!bPressed)
  107. {
  108. SelectObject(hdc, penOld);
  109. pen = (HPEN)MlStockObjects_Get(HEADERMIDDLE_PEN);
  110. penOld = (HPEN)SelectObject(hdc, pen);
  111. MoveToEx(hdc, prcButton->right - 2, prcButton->top + 1, NULL);
  112. LineTo(hdc, prcButton->right - 2, prcButton->bottom - 2);
  113. MoveToEx(hdc, prcButton->right - 2, prcButton->bottom - 2, NULL);
  114. LineTo(hdc, prcButton->left, prcButton->bottom - 2);
  115. }
  116. SelectObject(hdc, penOld);
  117. }
  118. RECT r;
  119. DWORD arrowSize = SkinnedHeader::GetSortArrowSize();
  120. SetRect(&r, 0, 0, GET_X_LPARAM(arrowSize), GET_Y_LPARAM(arrowSize));
  121. OffsetRect(&r,
  122. prcButton->left + (prcButton->right - prcButton->left - r.right)/2 + (prcButton->right - prcButton->left - r.right)%2,
  123. prcButton->top + (prcButton->bottom - prcButton->top - r.bottom)/2);
  124. if (bPressed) OffsetRect(&r, 1, 1);
  125. if (r.left > (prcButton->left + 1) && r.top > (prcButton->top + 1))
  126. {
  127. SkinnedHeader::DrawSortArrow(hdc, &r, rgbBk, WADlg_getColor(WADLG_LISTHEADER_FONTCOLOR), FALSE);
  128. }
  129. SetBkColor(hdc, rgbBkOld);
  130. }
  131. void SkinnedCombobox::OnPaint()
  132. {
  133. HDC hdc;
  134. PAINTSTRUCT ps;
  135. RECT rc;
  136. COMBOBOXINFO cbi;
  137. BOOL ctrlActive;
  138. if (!GetClientRect(hwnd, &rc) || rc.bottom <= rc.top || rc.right <= rc.left) return;
  139. hdc= BeginPaint(hwnd, &ps);
  140. if (NULL == hdc) return;
  141. ctrlActive = (activeBorder /*|| hwnd == GetFocus()*/);
  142. if (SWCBS_TOOLBAR & style)
  143. {
  144. DrawBorder(hdc, &rc, BORDER_FLAT, (HPEN)MlStockObjects_Get(WNDBCK_PEN));
  145. if (ctrlActive)
  146. {
  147. InflateRect(&rc, -1, -1);
  148. DrawBorder(hdc, &rc, BORDER_FLAT, __super::GetBorderPen());
  149. }
  150. }
  151. else DrawBorder(hdc, &rc, BORDER_FLAT, GetBorderPen());
  152. InflateRect(&rc, -1, -1);
  153. ZeroMemory(&cbi, sizeof(COMBOBOXINFO));
  154. cbi.cbSize = sizeof(COMBOBOXINFO);
  155. if (GetComboBoxInfo(hwnd, &cbi))
  156. {
  157. RECT r;
  158. DWORD ws = GetWindowLongPtrW(hwnd, GWL_STYLE);
  159. SetBkMode(hdc, OPAQUE);
  160. SetBkColor(hdc, WADlg_getColor(WADLG_ITEMBG));
  161. SetRect(&r, rc.left, rc.top, cbi.rcItem.left, rc.bottom);
  162. if (r.left < r.right) ExtTextOutW(hdc, 0, 0, ETO_OPAQUE, &r, L"", 0, NULL);
  163. SetRect(&r, cbi.rcItem.left, rc.top, cbi.rcItem.right, cbi.rcItem.top);
  164. if (r.top < r.bottom) ExtTextOutW(hdc, 0, 0, ETO_OPAQUE, &r, L"", 0, NULL);
  165. SetRect(&r, cbi.rcItem.left, cbi.rcItem.bottom, cbi.rcItem.right, rc.bottom);
  166. if (r.top < r.bottom) ExtTextOutW(hdc, 0, 0, ETO_OPAQUE, &r, L"", 0, NULL);
  167. if (cbi.rcButton.left != cbi.rcButton.right)
  168. {
  169. SetRect(&r, cbi.rcItem.right, rc.top, cbi.rcButton.left, rc.bottom);
  170. if (r.left < r.right) ExtTextOutW(hdc, 0, 0, ETO_OPAQUE, &r, L"", 0, NULL);
  171. SetRect(&r, cbi.rcButton.right, rc.top, rc.right, rc.bottom);
  172. if (r.left < r.right) ExtTextOutW(hdc, 0, 0, ETO_OPAQUE, &r, L"", 0, NULL);
  173. SetRect(&r, cbi.rcButton.left, rc.top, cbi.rcButton.right, cbi.rcButton.top);
  174. if (r.top < r.bottom) ExtTextOutW(hdc, 0, 0, ETO_OPAQUE, &r, L"", 0, NULL);
  175. SetRect(&r, cbi.rcButton.left, cbi.rcButton.bottom, cbi.rcButton.right, rc.bottom);
  176. if (r.top < r.bottom) ExtTextOutW(hdc, 0, 0, ETO_OPAQUE, &r, L"", 0, NULL);
  177. DrawButton(hdc, &cbi.rcButton, IsButtonDown(ws), ctrlActive);
  178. }
  179. else
  180. {
  181. SetRect(&r, cbi.rcItem.right, rc.top, rc.right, rc.bottom);
  182. if (r.left < r.right) ExtTextOutW(hdc, 0, 0, ETO_OPAQUE, &r, L"", 0, NULL);
  183. }
  184. if (CBS_DROPDOWNLIST == (0x0F & ws))
  185. {
  186. INT cchText = (INT)SendMessageW(hwnd, WM_GETTEXTLENGTH, 0, 0);
  187. if (cchText)
  188. {
  189. HFONT hFont, hFontOld;
  190. wchar_t szText[COMBO_TEXT_MAX] = {0};
  191. SendMessageW(hwnd, WM_GETTEXT, (WPARAM)COMBO_TEXT_MAX, (LPARAM)szText);
  192. hFont = (HFONT)SendMessage(hwnd, WM_GETFONT, 0, 0L);
  193. if (!hFont) hFont = (HFONT)MlStockObjects_Get(DEFAULT_FONT);
  194. hFontOld = (hFont) ? (HFONT)SelectObject(hdc, hFont) : NULL;
  195. COLORREF rgbText;
  196. BOOL bFocused = (hwnd == GetFocus() && !SendMessageW(hwnd, CB_GETDROPPEDSTATE, 0, 0L));
  197. if (bFocused && 0 == (SWCBS_TOOLBAR & style))
  198. {
  199. rgbText = WADlg_getColor(WADLG_SELBAR_FGCOLOR);
  200. SetBkColor(hdc, WADlg_getColor(WADLG_SELBAR_BGCOLOR));
  201. }
  202. else rgbText = WADlg_getColor(WADLG_ITEMFG);
  203. if(!IsWindowEnabled(hwnd))
  204. {
  205. COLORREF rgbBack = GetBkColor(hdc);
  206. rgbText = RGB((GetRValue(rgbText)+GetRValue(rgbBack))/2,
  207. (GetGValue(rgbText)+GetGValue(rgbBack))/2,
  208. (GetBValue(rgbText)+GetBValue(rgbBack))/2);
  209. }
  210. SetTextColor(hdc, rgbText);
  211. ExtTextOutW(hdc, 0, 0, ETO_OPAQUE, &cbi.rcItem, L"", 0, NULL);
  212. if (bFocused &&
  213. 0 == (0x01/*UISF_HIDEFOCUS*/ & uiState) &&
  214. 0 == (SWCBS_TOOLBAR & style))
  215. {
  216. COLORREF fg, bk;
  217. fg = SetTextColor(hdc, GetSysColor(COLOR_WINDOWTEXT));
  218. bk = SetBkColor(hdc, GetSysColor(COLOR_WINDOW));
  219. DrawFocusRect(hdc, &cbi.rcItem);
  220. SetTextColor(hdc, fg);
  221. SetBkColor(hdc, bk);
  222. }
  223. InflateRect(&cbi.rcItem, -1, -1);
  224. DrawTextW(hdc, szText, min(cchText,COMBO_TEXT_MAX), &cbi.rcItem, DT_NOPREFIX | DT_SINGLELINE | DT_VCENTER);
  225. if (hFontOld) SelectObject(hdc, hFontOld);
  226. }
  227. else
  228. {
  229. ExtTextOutW(hdc, 0, 0, ETO_OPAQUE, &cbi.rcItem, L"", 0, NULL);
  230. }
  231. }
  232. }
  233. EndPaint(hwnd, &ps);
  234. }
  235. void SkinnedCombobox::OnSkinUpdated(BOOL bNotifyChildren, BOOL bRedraw)
  236. {
  237. __super::OnSkinUpdated(bNotifyChildren, bRedraw);
  238. if (SWS_USESKINFONT & style)
  239. {
  240. if (0 == (CBS_OWNERDRAWVARIABLE & GetWindowLongPtrW(hwnd, GWL_STYLE)))
  241. {
  242. HDC hdc = GetDCEx(hwnd, NULL, DCX_CACHE | DCX_NORESETATTRS);
  243. HFONT hf, hfo;
  244. TEXTMETRIC tm;
  245. hf = (HFONT)SendMessageW(hwnd, WM_GETFONT, 0, 0L);
  246. if (NULL == hf) hf = (HFONT)MlStockObjects_Get(DEFAULT_FONT);
  247. hfo = (HFONT)SelectObject(hdc, hf);
  248. GetTextMetrics(hdc, &tm);
  249. SendMessageW(hwnd, CB_SETITEMHEIGHT, -1, tm.tmHeight + 2);
  250. SendMessageW(hwnd, CB_SETITEMHEIGHT, 0, tm.tmHeight + 2);
  251. SelectObject(hdc, hfo);
  252. ReleaseDC(hwnd, hdc);
  253. }
  254. }
  255. }
  256. INT SkinnedCombobox::OnNcHitTest(POINTS pts)
  257. {
  258. INT ht = __super::OnNcHitTest(pts);
  259. if (ht > 0 && !activeBorder && (SWCBS_TOOLBAR & style) && IsChild(GetActiveWindow(), hwnd))
  260. {
  261. TRACKMOUSEEVENT track;
  262. track.cbSize = sizeof(TRACKMOUSEEVENT);
  263. track.dwFlags = TME_LEAVE;
  264. track.hwndTrack = hwnd;
  265. TrackMouseEvent(&track);
  266. activeBorder = TRUE;
  267. InvalidateRect(hwnd, NULL, TRUE);
  268. UpdateWindow(hwnd);
  269. }
  270. return ht;
  271. }
  272. void SkinnedCombobox::OnMouseLeave(void)
  273. {
  274. if (!activeBorder) return;
  275. COMBOBOXINFO cbi;
  276. ZeroMemory(&cbi, sizeof(COMBOBOXINFO));
  277. cbi.cbSize = sizeof(COMBOBOXINFO);
  278. if (GetComboBoxInfo(hwnd, &cbi) && IsWindowVisible(cbi.hwndList))
  279. return;
  280. activeBorder = FALSE;
  281. if (SWCBS_TOOLBAR & style)
  282. {
  283. InvalidateRect(hwnd, NULL, TRUE);
  284. UpdateWindow(hwnd);
  285. }
  286. }
  287. LRESULT SkinnedCombobox::SilenceMessage(UINT uMsg, WPARAM wParam, LPARAM lParam)
  288. {
  289. LRESULT result;
  290. UpdateWindow(hwnd);
  291. CallDefWndProc(WM_SETREDRAW, FALSE, 0L);
  292. result = __super::WindowProc(uMsg, wParam, lParam);
  293. CallDefWndProc(WM_SETREDRAW, TRUE, 0L);
  294. InvalidateRect(hwnd, NULL, TRUE);
  295. return result;
  296. }
  297. static HWND hwndPreviousFocus = NULL;
  298. LRESULT SkinnedCombobox::WindowProc(UINT uMsg, WPARAM wParam, LPARAM lParam)
  299. {
  300. if (SWCBS_TOOLBAR & style)
  301. {
  302. switch(uMsg)
  303. {
  304. case WM_SETFOCUS:
  305. hwndPreviousFocus = (HWND)wParam;
  306. break;
  307. case REFLECTED_COMMAND:
  308. switch(HIWORD(wParam))
  309. {
  310. case CBN_CLOSEUP:
  311. {
  312. if (NULL != hwndPreviousFocus && hwnd == GetFocus())
  313. {
  314. do
  315. {
  316. if (IsWindowVisible(hwndPreviousFocus) && IsWindowEnabled(hwndPreviousFocus))
  317. {
  318. SetFocus(hwndPreviousFocus);
  319. break;
  320. }
  321. } while (NULL != (hwndPreviousFocus = GetAncestor(hwndPreviousFocus, GA_PARENT)));
  322. }
  323. hwndPreviousFocus = NULL;
  324. }
  325. break;
  326. }
  327. break;
  328. }
  329. }
  330. if (SWS_USESKINCOLORS & style)
  331. {
  332. switch(uMsg)
  333. {
  334. case WM_PAINT: OnPaint(); return 0;
  335. case WM_ERASEBKGND: return 0;
  336. case WM_MOUSELEAVE: OnMouseLeave(); break;
  337. case WM_KILLFOCUS:
  338. case WM_SETFOCUS:
  339. case WM_COMMAND:
  340. case WM_CAPTURECHANGED:
  341. case 0x0128/*WM_UPDATEUISTATE*/:
  342. SilenceMessage(uMsg, wParam, lParam);
  343. return 0;
  344. case WM_LBUTTONUP:
  345. if (activeBorder && (SWCBS_TOOLBAR & style))
  346. {
  347. TRACKMOUSEEVENT track;
  348. track.cbSize = sizeof(TRACKMOUSEEVENT);
  349. track.dwFlags = TME_LEAVE;
  350. track.hwndTrack = hwnd;
  351. TrackMouseEvent(&track);
  352. POINT pt;
  353. pt.x = GET_X_LPARAM(lParam);
  354. pt.y = GET_Y_LPARAM(lParam);
  355. RECT rw;
  356. if (GetWindowRect(hwnd, &rw))
  357. {
  358. MapWindowPoints(hwnd, HWND_DESKTOP, &pt, 1);
  359. if (!PtInRect(&rw, pt))
  360. {
  361. INPUT pi[2];
  362. ZeroMemory(&pi[0], sizeof(INPUT));
  363. pi[0].type = INPUT_MOUSE;
  364. pi[0].mi.dx = pt.x;
  365. pi[0].mi.dy = pt.y;
  366. pi[0].mi.dwFlags = MOUSEEVENTF_ABSOLUTE | MOUSEEVENTF_LEFTDOWN;
  367. CopyMemory(&pi[1], &pi[0], sizeof(INPUT));
  368. pi[1].mi.dwFlags = MOUSEEVENTF_ABSOLUTE | MOUSEEVENTF_LEFTUP;
  369. SendInput(2, pi, sizeof(INPUT));
  370. }
  371. }
  372. }
  373. break;
  374. case WM_LBUTTONDOWN:
  375. if (!activeBorder && (SWCBS_TOOLBAR & style))
  376. {
  377. TRACKMOUSEEVENT track;
  378. track.cbSize = sizeof(TRACKMOUSEEVENT);
  379. track.dwFlags = TME_LEAVE;
  380. track.hwndTrack = hwnd;
  381. TrackMouseEvent(&track);
  382. activeBorder = TRUE;
  383. }
  384. break;
  385. }
  386. }
  387. return __super::WindowProc(uMsg, wParam, lParam);
  388. }