1
0

ml_ratingcolumn.cpp 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874
  1. #include "main.h"
  2. #include "./ml_ratingcolumn.h"
  3. #include "./ml_rating.h"
  4. #include "api__gen_ml.h"
  5. #include "./ml.h"
  6. #include "./ml_IPC_0313.h"
  7. #include "./resource.h"
  8. #include "../winamp/gen.h"
  9. #include "./stockobjects.h"
  10. #include <commctrl.h>
  11. #include <strsafe.h>
  12. extern HMLIMGLST hmlilRating;
  13. extern UINT ratingGlobalStyle;
  14. #define RATING_IMAGELIST hmlilRating
  15. #define RATING_IMAGEINDEX 0
  16. #define RATING_MAXVALUE 5
  17. #define RATING_LEFTPADDING 5
  18. #define RATING_RIGHTPADDING 2
  19. #define RATING_AUTOUNHOVERDELAY 80
  20. #define RATING_ANIMATIONINTERVAL 200
  21. #define RAITNG_ANIMATIONMAX 1000
  22. #define RATING_DRAGFORGIVENESS_LEFT 0xFFFF
  23. #define RATING_DRAGFORGIVENESS_RIGHT 0xFFFF
  24. #define RATING_DRAGFORGIVENESS_TOP 12
  25. #define RATING_DRAGFORGIVENESS_BOTTOM 12
  26. #define RATING_FILLCHAR L'x'
  27. typedef struct _RATINGTRACKING
  28. {
  29. HWND hwndList;
  30. UINT iItem;
  31. UINT iSubItem;
  32. RECT rc; // trackin cell
  33. INT value;
  34. UINT_PTR timerId;
  35. } RATINGTRACKING;
  36. typedef struct _RATINGANIMATION
  37. {
  38. HWND hwndList;
  39. UINT iItem;
  40. UINT_PTR timerId;
  41. UINT durationMs;
  42. UINT startedMs;
  43. WORD stage;
  44. } RATINGANIMATION;
  45. typedef struct _RATINGDRAG
  46. {
  47. HWND hwndList;
  48. UINT iItem;
  49. UINT iSubItem;
  50. RECT rc;
  51. INT value;
  52. BOOL update;
  53. BOOL outside;
  54. UINT fStyle;
  55. } RATINGDRAG;
  56. typedef struct _TWEAKPARAM
  57. {
  58. ONRATINGTWEAKAPLLY fnApply;
  59. UINT fStyle;
  60. } TWEAKPARAM;
  61. static INT ratingMinWidth = 65;
  62. static INT ratingCharWidth = 8;
  63. static RATINGTRACKING ratingTracking;
  64. static RATINGANIMATION ratingAnimation;
  65. static RATINGDRAG ratingDrag;
  66. static void CALLBACK Timer_AutoUnhover(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime);
  67. static void CALLBACK Timer_Animation(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime);
  68. static void CorrectDragPoint(CONST RECT *prc, POINT *ppt);
  69. static BOOL IsTrakingAllowed(HWND hwndList, UINT fStyle);
  70. static BOOL IsItemTrackable(HWND hwndList, UINT iItem, UINT fStyle);
  71. static INT_PTR WINAPI TweakDialogProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
  72. BOOL MLRatingColumnI_Initialize(void)
  73. {
  74. RECT rc;
  75. ZeroMemory(&ratingTracking, sizeof(RATINGTRACKING));
  76. ratingTracking.iItem = (UINT)-1;
  77. ZeroMemory(&ratingAnimation, sizeof(RATINGANIMATION));
  78. ratingAnimation.iItem = (UINT)-1;
  79. ratingMinWidth = ((MLRatingI_CalcMinRect(RATING_MAXVALUE, RATING_IMAGELIST, &rc)) ? (rc.right - rc.left) : 0);
  80. return TRUE;
  81. }
  82. BOOL MLRatingColumnI_Update(void)
  83. {
  84. HDC hdc;
  85. HFONT hFontOld, hFont;
  86. INT length;
  87. WCHAR test[6], *p;
  88. hdc = (HDC)MlStockObjects_Get(CACHED_DC);
  89. if (!hdc) return FALSE;
  90. hFont = (HFONT)MlStockObjects_Get(SKIN_FONT);
  91. length = sizeof(test)/sizeof(WCHAR);
  92. p = test + length;
  93. while (p-- != test) *p = RATING_FILLCHAR;
  94. hFontOld = (HFONT)SelectObject(hdc, hFont);
  95. SIZE sz;
  96. if (GetTextExtentPoint32W(hdc, test, length, &sz)) ratingCharWidth = sz.cx/length;
  97. else ratingCharWidth = 8;
  98. SelectObject(hdc, hFontOld);
  99. return TRUE;
  100. }
  101. INT MLRatingColumnI_GetMinWidth(void)
  102. {
  103. return ratingMinWidth + RATING_LEFTPADDING + RATING_RIGHTPADDING;
  104. }
  105. LPCWSTR MLRatingColumnI_FillBackString(LPWSTR pszText, INT cchTextMax, INT nColumnWidth, UINT fStyle)
  106. {
  107. INT width, count;
  108. LPWSTR p;
  109. if (!pszText) return NULL;
  110. pszText[0] = 0x00;
  111. fStyle = (RCS_DEFAULT == fStyle) ? ratingGlobalStyle : fStyle;
  112. width = MLRatingColumnI_GetMinWidth();
  113. if (nColumnWidth < width) return pszText;
  114. if (RCS_ALLIGN_RIGHT_I & fStyle) width = nColumnWidth;
  115. else if (RCS_ALLIGN_CENTER_I & fStyle) width += (nColumnWidth - width)/2;
  116. if (width <= 0) return pszText;
  117. count = (width - 4)/ratingCharWidth;
  118. if (count >= cchTextMax) count = cchTextMax -1;
  119. for (p = pszText; count--; p++) *p = RATING_FILLCHAR;
  120. *p = 0x00;
  121. return pszText;
  122. }
  123. BOOL MLRatingColumnI_Paint(RATINGCOLUMNPAINT_I *pRCPaint)
  124. {
  125. RECT rc;
  126. UINT fStyle, fRCStyle;
  127. fRCStyle = (RCS_DEFAULT == pRCPaint->fStyle) ? ratingGlobalStyle : pRCPaint->fStyle;
  128. rc.left = LVIR_BOUNDS;
  129. rc.top = pRCPaint->iSubItem;
  130. if (SendMessageW(pRCPaint->hwndList, LVM_GETSUBITEMRECT, pRCPaint->iItem, (LPARAM)&rc))
  131. {
  132. if ((rc.right - rc.left - RATING_LEFTPADDING - RATING_RIGHTPADDING) >= ratingMinWidth &&
  133. (rc.left + RATING_LEFTPADDING) < (rc.right - RATING_RIGHTPADDING) && rc.top < rc.bottom)
  134. {
  135. INT left;
  136. COLORREF rgbBkOld;
  137. BOOL tracking;
  138. if (rc.right <= pRCPaint->prcView->left || rc.left >= pRCPaint->prcView->right) return TRUE;
  139. tracking = (pRCPaint->hwndList == ratingTracking.hwndList && pRCPaint->iItem == ratingTracking.iItem);
  140. rgbBkOld = SetBkColor(pRCPaint->hdc, pRCPaint->rgbBk);
  141. left = rc.left;
  142. if (0 == rc.left) rc.left = 3;
  143. ExtTextOutW(pRCPaint->hdc, 0, 0, ETO_OPAQUE, &rc, L"", 0, 0);
  144. fStyle = RDS_VCENTER_I;
  145. if (RCS_ALLIGN_RIGHT_I & fRCStyle) fStyle |= RDS_RIGHT_I;
  146. else if (RCS_ALLIGN_CENTER_I & fRCStyle) fStyle |= RDS_HCENTER_I;
  147. INT value = pRCPaint->value, trackingValue;
  148. if (tracking)
  149. {
  150. fStyle |= RDS_HOT_I;
  151. if(RCS_SHOWEMPTY_HOT_I & fRCStyle) fStyle |= RDS_SHOWEMPTY_I;
  152. trackingValue = ratingTracking.value;
  153. }
  154. else if (pRCPaint->hwndList == ratingDrag.hwndList && pRCPaint->iItem == ratingDrag.iItem && !ratingDrag.outside)
  155. {
  156. value = 0;
  157. trackingValue = 0;
  158. fStyle |= (RDS_SHOWEMPTY_I | RDS_HOT_I);
  159. }
  160. else
  161. {
  162. if(RCS_SHOWEMPTY_NORMAL_I & fRCStyle) fStyle |= RDS_SHOWEMPTY_I;
  163. trackingValue = 0;
  164. }
  165. if(RCS_SHOWINACTIVE_HOT_I & fRCStyle) fStyle |= RDS_INACTIVE_HOT_I;
  166. if (pRCPaint->hwndList == ratingAnimation.hwndList && pRCPaint->iItem == ratingAnimation.iItem)
  167. {
  168. if (RCS_SHOWEMPTY_ANIMATION_I & fRCStyle) fStyle |= RDS_SHOWEMPTY_I;
  169. switch(ratingAnimation.stage)
  170. {
  171. case 1:
  172. rc.top -= 1;
  173. rc.bottom -= 1;
  174. break;
  175. }
  176. }
  177. if (value || (RDS_SHOWEMPTY_I & fStyle))
  178. {
  179. COLORREF rgbFgOld = SetTextColor(pRCPaint->hdc, pRCPaint->rgbFg);
  180. rc.left = left + RATING_LEFTPADDING;
  181. rc.right -= RATING_RIGHTPADDING;
  182. MLRatingI_Draw(pRCPaint->hdc, RATING_MAXVALUE, value, trackingValue, RATING_IMAGELIST, RATING_IMAGEINDEX, &rc, fStyle);
  183. if (pRCPaint->rgbFg != rgbFgOld) SetTextColor(pRCPaint->hdc, rgbFgOld);
  184. }
  185. if (pRCPaint->rgbBk != rgbBkOld) SetBkColor(pRCPaint->hdc, rgbBkOld);
  186. return TRUE;
  187. }
  188. }
  189. return FALSE;
  190. }
  191. BOOL MLRatingColumnI_Click(RATINGCOLUMN_I *pRating)
  192. {
  193. UINT fRCStyle;
  194. LVHITTESTINFO lvhit;
  195. fRCStyle = (RCS_DEFAULT == pRating->fStyle) ? ratingGlobalStyle : pRating->fStyle;
  196. lvhit.pt = pRating->ptAction;
  197. SendMessageW(pRating->hwndList, LVM_SUBITEMHITTEST, 0, (LPARAM)&lvhit);
  198. pRating->iItem = lvhit.iItem;
  199. if (ratingTracking.hwndList && ratingTracking.hwndList != pRating->hwndList ||
  200. !IsTrakingAllowed(pRating->hwndList, fRCStyle)) MLRatingColumnI_CancelTracking(TRUE);
  201. if (-1 != ratingTracking.iItem && ratingTracking.iItem != (UINT)lvhit.iItem)
  202. {
  203. if (-1 == lvhit.iItem) MLRatingColumnI_CancelTracking(TRUE);
  204. else
  205. {
  206. ratingTracking.iItem = (UINT)lvhit.iItem;
  207. ratingTracking.iSubItem = lvhit.iSubItem;
  208. }
  209. }
  210. if (-1 != lvhit.iItem && (0 == (RCS_BLOCKCLICK_I & fRCStyle)))
  211. {
  212. RECT rc;
  213. UINT fStyle;
  214. rc.left = LVIR_BOUNDS;
  215. rc.top = lvhit.iSubItem;
  216. fStyle = RDS_VCENTER_I;
  217. if (RCS_ALLIGN_RIGHT_I & fRCStyle) fStyle |= RDS_RIGHT_I;
  218. if (RCS_ALLIGN_CENTER_I & fRCStyle) fStyle |= RDS_HCENTER_I;
  219. if (SendMessageW(pRating->hwndList, LVM_GETSUBITEMRECT, lvhit.iItem, (LPARAM)&rc))
  220. {
  221. if (0 == lvhit.iSubItem)
  222. {
  223. HWND hwndHeader;
  224. RECT rh;
  225. hwndHeader = (HWND)SendMessageW(pRating->hwndList, LVM_GETHEADER, 0, 0L);
  226. if (hwndHeader && SendMessageW(hwndHeader, HDM_GETITEMRECT, lvhit.iSubItem, (LPARAM)&rh))
  227. {
  228. rc.left = rh.left;
  229. rc.right = rh.right;
  230. }
  231. else SetRect(&rc, 0, 0, 0, 0);
  232. }
  233. rc.left += RATING_LEFTPADDING;
  234. rc.right -= RATING_RIGHTPADDING;
  235. if ((rc.right - rc.left) >= ratingMinWidth)
  236. {
  237. pRating->value = MLRatingI_HitTest(pRating->ptAction, RATING_MAXVALUE, RATING_IMAGELIST, &rc, fStyle);
  238. pRating->value = LOWORD(pRating->value);
  239. if (0 == pRating->value && (RCS_BLOCKUNRATECLICK_I & fRCStyle)) return FALSE;
  240. if (ratingTracking.iItem == (UINT)lvhit.iItem && ratingTracking.value != pRating->value)
  241. {
  242. ratingTracking.value = pRating->value;
  243. SendMessageW(pRating->hwndList, LVM_REDRAWITEMS, lvhit.iItem, lvhit.iItem);
  244. if (pRating->bRedrawNow) UpdateWindow(pRating->hwndList);
  245. }
  246. return TRUE;
  247. }
  248. }
  249. }
  250. return FALSE;
  251. }
  252. void MLRatingColumnI_Track(RATINGCOLUMN_I *pRating)
  253. {
  254. UINT fRCStyle;
  255. BOOL trackingOk;
  256. fRCStyle = (RCS_DEFAULT == pRating->fStyle) ? ratingGlobalStyle : pRating->fStyle;
  257. if (ratingTracking.hwndList != pRating->hwndList) MLRatingColumnI_CancelTracking(pRating->bRedrawNow);
  258. trackingOk = (IsTrakingAllowed(pRating->hwndList, fRCStyle) && IsItemTrackable(pRating->hwndList, pRating->iItem, fRCStyle));
  259. if (ratingTracking.iItem != pRating->iItem || ratingTracking.iSubItem != pRating->iSubItem || (-1 != ratingTracking.iItem && !trackingOk))
  260. {
  261. if (-1 != ratingTracking.iItem) MLRatingColumnI_CancelTracking(FALSE);
  262. if (trackingOk)
  263. {
  264. ratingTracking.rc.left = LVIR_BOUNDS;
  265. ratingTracking.rc.top = pRating->iSubItem;
  266. if (SendMessageW(pRating->hwndList, LVM_GETSUBITEMRECT, pRating->iItem, (LPARAM)&ratingTracking.rc))
  267. {
  268. if (0 == pRating->iSubItem)
  269. {
  270. HWND hwndHeader;
  271. RECT rh;
  272. hwndHeader = (HWND)SendMessageW(pRating->hwndList, LVM_GETHEADER, 0, 0L);
  273. if (hwndHeader && SendMessageW(hwndHeader, HDM_GETITEMRECT, pRating->iSubItem, (LPARAM)&rh))
  274. {
  275. ratingTracking.rc.left = rh.left;
  276. ratingTracking.rc.right = rh.right;
  277. }
  278. else SetRect(&ratingTracking.rc, 0, 0, 0, 0);
  279. }
  280. ratingTracking.rc.left += RATING_LEFTPADDING;
  281. ratingTracking.rc.right -= RATING_RIGHTPADDING;
  282. if ((ratingTracking.rc.right - ratingTracking.rc.left) < ratingMinWidth)
  283. {
  284. SetRect(&ratingTracking.rc, 0, 0, 0, 0);
  285. }
  286. }
  287. else SetRect(&ratingTracking.rc, 0, 0, 0, 0);
  288. if (ratingTracking.rc.left != ratingTracking.rc.right)
  289. {
  290. ratingTracking.hwndList = pRating->hwndList;
  291. ratingTracking.iItem = pRating->iItem;
  292. ratingTracking.iSubItem = pRating->iSubItem;
  293. ratingTracking.timerId = SetTimer(NULL, NULL, RATING_AUTOUNHOVERDELAY, Timer_AutoUnhover);
  294. }
  295. else
  296. {
  297. ratingTracking.hwndList = NULL;
  298. ratingTracking.iItem = -1;
  299. ratingTracking.iSubItem = 0;
  300. }
  301. }
  302. }
  303. if (-1 != ratingTracking.iItem)
  304. {
  305. UINT fStyle;
  306. INT value;
  307. fStyle = RDS_VCENTER_I;
  308. if (RCS_ALLIGN_RIGHT_I & fRCStyle) fStyle |= RDS_RIGHT_I;
  309. if (RCS_ALLIGN_CENTER_I & fRCStyle) fStyle |= RDS_HCENTER_I;
  310. value = LOWORD(MLRatingI_HitTest(pRating->ptAction, RATING_MAXVALUE, RATING_IMAGELIST, &ratingTracking.rc, fStyle));
  311. if (ratingTracking.value != value)
  312. {
  313. ratingTracking.value = value;
  314. SendMessageW(pRating->hwndList, LVM_REDRAWITEMS, ratingTracking.iItem, ratingTracking.iItem);
  315. if (pRating->bRedrawNow) UpdateWindow(pRating->hwndList);
  316. }
  317. }
  318. }
  319. BOOL MLRatingColumnI_BeginDrag(RATINGCOLUMN_I *pRating)
  320. {
  321. POINT pt;
  322. if (ratingDrag.hwndList)
  323. {
  324. RATINGCOLUMN_I rcol;
  325. rcol.bCanceled = TRUE;
  326. rcol.bRedrawNow = TRUE;
  327. MLRatingColumnI_EndDrag(&rcol);
  328. }
  329. ratingDrag.fStyle = (RCS_DEFAULT == pRating->fStyle) ? ratingGlobalStyle : pRating->fStyle;
  330. ratingDrag.rc.left = LVIR_BOUNDS;
  331. ratingDrag.rc.top = pRating->iSubItem;
  332. ratingDrag.fStyle = ratingDrag.fStyle &
  333. ~(RCS_TRACKITEM_SELECTED_I | RCS_TRACKITEM_FOCUSED_I | RCS_BLOCKCLICK_I | RCS_BLOCKUNRATECLICK_I) |
  334. (RCS_TRACKITEM_ALL_I | RCS_TRACK_ALWAYS_I);
  335. if ((RCS_BLOCKDRAG_I & ratingDrag.fStyle ) || !pRating->hwndList || !IsWindow(pRating->hwndList) ||
  336. (UINT)-1 == pRating->iItem || (UINT)-1 == pRating->iSubItem ||
  337. !SendMessageW(pRating->hwndList, LVM_GETSUBITEMRECT, pRating->iItem, (LPARAM)&ratingDrag.rc)) return FALSE;
  338. if (0 == pRating->iSubItem)
  339. {
  340. HWND hwndHeader;
  341. RECT rh;
  342. hwndHeader = (HWND)SendMessageW(pRating->hwndList, LVM_GETHEADER, 0, 0L);
  343. if (!hwndHeader || !SendMessageW(hwndHeader, HDM_GETITEMRECT, pRating->iSubItem, (LPARAM)&rh)) return FALSE;
  344. ratingDrag.rc.left = rh.left;
  345. ratingDrag.rc.right = rh.right;
  346. }
  347. ratingDrag.rc.left += RATING_LEFTPADDING;
  348. ratingDrag.rc.right -= RATING_RIGHTPADDING;
  349. if ((ratingDrag.rc.right - ratingDrag.rc.left) < ratingMinWidth)
  350. {
  351. SetRect(&ratingDrag.rc, 0, 0, 0, 0);
  352. return FALSE;
  353. }
  354. if (RCS_ALLIGN_RIGHT_I & ratingDrag.fStyle) ratingDrag.rc.left = ratingDrag.rc.right - ratingMinWidth;
  355. else
  356. {
  357. if (RCS_ALLIGN_CENTER_I & ratingDrag.fStyle) ratingDrag.rc.left += ((ratingDrag.rc.right - ratingDrag.rc.left) - ratingMinWidth)/2;
  358. ratingDrag.rc.right = ratingDrag.rc.left + ratingMinWidth;
  359. }
  360. GetCursorPos(&pt);
  361. MapWindowPoints(HWND_DESKTOP, pRating->hwndList, &pt, 1);
  362. if (ratingDrag.rc.left <= pt.x && pt.x <= ratingDrag.rc.right)
  363. {
  364. ratingDrag.hwndList = pRating->hwndList;
  365. ratingDrag.iItem = pRating->iItem;
  366. ratingDrag.iSubItem = pRating->iSubItem;
  367. ratingDrag.value = pRating->value;
  368. ratingDrag.update = TRUE;
  369. ratingDrag.outside = TRUE;
  370. return TRUE;
  371. }
  372. return FALSE;
  373. }
  374. BOOL MLRatingColumnI_Drag(POINT pt)
  375. {
  376. if (ratingDrag.hwndList && ratingDrag.hwndList == WindowFromPoint(pt))
  377. {
  378. SendMessageW(ratingDrag.hwndList, WM_SETCURSOR, (WPARAM)ratingDrag.hwndList, MAKELPARAM(HTCLIENT, WM_MOUSEMOVE));
  379. ratingDrag.outside = FALSE;
  380. MapWindowPoints(HWND_DESKTOP, ratingDrag.hwndList, &pt, 1);
  381. CorrectDragPoint(&ratingDrag.rc, &pt);
  382. if (PtInRect(&ratingDrag.rc, pt))
  383. {
  384. RATINGCOLUMN_I rcol;
  385. ratingDrag.update = TRUE;
  386. rcol.hwndList = ratingDrag.hwndList;
  387. rcol.iItem = ratingDrag.iItem;
  388. rcol.iSubItem = ratingDrag.iSubItem;
  389. rcol.value = ratingDrag.value;
  390. rcol.ptAction = pt;
  391. rcol.bRedrawNow = FALSE;
  392. rcol.fStyle = ratingDrag.fStyle;
  393. MLRatingColumnI_Track(&rcol);
  394. KillTimer(NULL, ratingTracking.timerId);
  395. if (-1 != ratingTracking.iItem && ratingTracking.value)
  396. {
  397. UpdateWindow(ratingDrag.hwndList);
  398. return TRUE;
  399. }
  400. }
  401. if (ratingDrag.update)
  402. {
  403. MLRatingColumnI_CancelTracking(FALSE);
  404. SendMessageW(ratingDrag.hwndList, LVM_REDRAWITEMS, ratingDrag.iItem, ratingDrag.iItem);
  405. UpdateWindow(ratingDrag.hwndList);
  406. ratingDrag.update = FALSE;
  407. }
  408. return TRUE;
  409. }
  410. if (ratingTracking.hwndList)
  411. {
  412. MLRatingColumnI_CancelTracking(FALSE);
  413. ratingDrag.update = FALSE;
  414. }
  415. if (!ratingDrag.update)
  416. {
  417. ratingDrag.outside = TRUE;
  418. if (NULL != ratingDrag.hwndList)
  419. {
  420. SendMessageW(ratingDrag.hwndList, LVM_REDRAWITEMS, ratingDrag.iItem, ratingDrag.iItem);
  421. UpdateWindow(ratingDrag.hwndList);
  422. }
  423. ratingDrag.update = TRUE;
  424. }
  425. return FALSE;
  426. }
  427. BOOL MLRatingColumnI_EndDrag(RATINGCOLUMN_I *pRating)
  428. {
  429. BOOL result;
  430. RATINGCOLUMN_I rcol;
  431. RECT rc;
  432. rcol.hwndList = ratingDrag.hwndList;
  433. rcol.iItem = ratingDrag.iItem;
  434. rcol.iSubItem = ratingDrag.iSubItem;
  435. rcol.fStyle = ratingDrag.fStyle;
  436. rcol.bRedrawNow = FALSE;
  437. CopyRect(&rc, &ratingDrag.rc);
  438. ZeroMemory(&ratingDrag, sizeof(RATINGDRAG));
  439. ratingDrag.iItem = (UINT)-1;
  440. result = FALSE;
  441. if (rcol.hwndList) SendMessageW(rcol.hwndList, LVM_REDRAWITEMS, rcol.iItem, rcol.iItem);
  442. if (rcol.hwndList && rcol.hwndList == WindowFromPoint(pRating->ptAction))
  443. {
  444. if (!pRating->bCanceled)
  445. {
  446. rcol.ptAction = pRating->ptAction;
  447. MapWindowPoints(HWND_DESKTOP, rcol.hwndList, &rcol.ptAction, 1);
  448. CorrectDragPoint(&rc, &rcol.ptAction);
  449. pRating->value = (PtInRect(&rc, rcol.ptAction) && MLRatingColumnI_Click(&rcol)) ? rcol.value : 0;
  450. pRating->hwndList = rcol.hwndList;
  451. pRating->iItem = rcol.iItem;
  452. pRating->iSubItem = rcol.iSubItem;
  453. result = TRUE;
  454. }
  455. }
  456. if (pRating->bRedrawNow && NULL != rcol.hwndList)
  457. UpdateWindow(rcol.hwndList);
  458. return result;
  459. }
  460. void MLRatingColumnI_Animate(HWND hwndList, UINT iItem, UINT durationMs)
  461. {
  462. if (ratingAnimation.timerId)
  463. {
  464. HWND ratingList;
  465. KillTimer(NULL, ratingAnimation.timerId);
  466. ratingList = ratingAnimation.hwndList;
  467. ratingAnimation.hwndList = NULL;
  468. if (ratingList && IsWindow(ratingList))
  469. {
  470. SendMessageW(ratingList, LVM_REDRAWITEMS, ratingAnimation.iItem, ratingAnimation.iItem);
  471. UpdateWindow(ratingList);
  472. }
  473. }
  474. if ((UINT)-1 != iItem && IsWindow(hwndList))
  475. {
  476. ratingAnimation.hwndList = hwndList;
  477. ratingAnimation.durationMs = (durationMs > RAITNG_ANIMATIONMAX) ? RAITNG_ANIMATIONMAX : durationMs;
  478. ratingAnimation.stage = 1;
  479. ratingAnimation.iItem = iItem;
  480. ratingAnimation.startedMs = GetTickCount();
  481. ratingAnimation.timerId = SetTimer(NULL, NULL, RATING_ANIMATIONINTERVAL, Timer_Animation);
  482. }
  483. else ratingAnimation.timerId = 0;
  484. if (ratingAnimation.timerId)
  485. {
  486. SendMessageW(ratingAnimation.hwndList, LVM_REDRAWITEMS, ratingAnimation.iItem, ratingAnimation.iItem);
  487. UpdateWindow(ratingAnimation.hwndList);
  488. }
  489. else
  490. {
  491. ZeroMemory(&ratingAnimation, sizeof(RATINGANIMATION));
  492. ratingAnimation.iItem = (UINT)-1;
  493. }
  494. }
  495. void MLRatingColumnI_CancelTracking(BOOL bRedrawNow)
  496. {
  497. HWND hwndList;
  498. UINT iItem;
  499. if (ratingTracking.timerId)
  500. {
  501. KillTimer(NULL, ratingTracking.timerId);
  502. ratingTracking.timerId = 0;
  503. }
  504. if (ratingTracking.hwndList && IsWindow(ratingTracking.hwndList) && -1 != ratingTracking.iItem)
  505. {
  506. hwndList = ratingTracking.hwndList;
  507. iItem = ratingTracking.iItem;
  508. }
  509. else
  510. {
  511. hwndList = NULL;
  512. iItem = (UINT)-1;
  513. }
  514. ratingTracking.hwndList = NULL;
  515. ratingTracking.iItem = (UINT)-1;
  516. ratingTracking.iSubItem = (UINT)-1;
  517. ratingTracking.value = -1;
  518. if(hwndList)
  519. {
  520. SendMessageW(hwndList, LVM_REDRAWITEMS, (WPARAM)iItem, (LPARAM)iItem);
  521. if(bRedrawNow) UpdateWindow(hwndList);
  522. }
  523. }
  524. INT MLRatingColumnI_GetWidth(INT width, UINT fStyle)
  525. {
  526. INT minWidth;
  527. if (RCS_DEFAULT == fStyle) fStyle = ratingGlobalStyle;
  528. minWidth = MLRatingColumnI_GetMinWidth();
  529. if (width < minWidth && 0 == (RCS_SIZE_ALLOWDECREASE_I & fStyle)) width = minWidth;
  530. if (width > minWidth && 0 == (RCS_SIZE_ALLOWINCREASE_I & fStyle)) width = minWidth;
  531. return width;
  532. }
  533. HWND MLRatingColumnI_TweakDialog(HWND hwndParent, UINT fStyle, ONRATINGTWEAKAPLLY fnApply, BOOL bVisible)
  534. {
  535. HWND hwndDlg;
  536. TWEAKPARAM param;
  537. if (!hwndParent || !IsWindow(hwndParent) || !fnApply) return NULL;
  538. param.fnApply = fnApply;
  539. param.fStyle = fStyle;
  540. hwndDlg = WASABI_API_CREATEDIALOGPARAMW(IDD_RATINGTWEAK, hwndParent, TweakDialogProc, (LPARAM)&param);
  541. if (IsWindow(hwndDlg))
  542. {
  543. RECT rw, rc;
  544. GetWindowRect((IsWindowVisible(hwndParent)?hwndParent:prefsWnd), &rc);
  545. GetWindowRect(hwndDlg, &rw);
  546. rc.left += ((rc.right - rc.left) - (rw.right - rw.left))/2;
  547. rc.top += ((rc.bottom - rc.top) - (rw.bottom - rw.top))/2;
  548. SetWindowPos(hwndDlg, NULL, rc.left, rc.top, 0, 0, SWP_NOSIZE | SWP_NOZORDER | ((bVisible) ? SWP_SHOWWINDOW : SWP_NOACTIVATE));
  549. }
  550. return hwndDlg;
  551. }
  552. static void CorrectDragPoint(CONST RECT *prc, POINT *ppt)
  553. {
  554. if (ppt->x <= prc->left && (prc->left - ppt->x) < RATING_DRAGFORGIVENESS_LEFT) ppt->x = prc->left + 1;
  555. if (ppt->x >= prc->right && (ppt->x - prc->right) < RATING_DRAGFORGIVENESS_RIGHT) ppt->x = prc->right - 1;
  556. if (ppt->y <= prc->top && (prc->top - ppt->y) < RATING_DRAGFORGIVENESS_TOP) ppt->y = prc->top + 1;
  557. if (ppt->y >= prc->bottom && (ppt->y - prc->bottom) < RATING_DRAGFORGIVENESS_BOTTOM) ppt->y = prc->bottom -1;
  558. }
  559. static BOOL IsTrakingAllowed(HWND hwndList, UINT fStyle)
  560. {
  561. if (RCS_TRACK_ALWAYS_I & fStyle) return TRUE;
  562. if (RCS_TRACK_WNDFOCUSED_I & fStyle)
  563. {
  564. return (hwndList == GetFocus());
  565. }
  566. if (RCS_TRACK_ANCESTORACITVE_I & fStyle)
  567. {
  568. HWND hwndActive;
  569. hwndActive = GetActiveWindow();
  570. return (hwndList == hwndActive || IsChild(hwndActive, hwndList));
  571. }
  572. if (RCS_TRACK_PROCESSACTIVE_I & fStyle)
  573. {
  574. GUITHREADINFO gui;
  575. gui.cbSize = sizeof(GUITHREADINFO);
  576. return (!GetGUIThreadInfo(GetWindowThreadProcessId(hwndList, NULL), &gui) || gui.hwndActive);
  577. }
  578. return FALSE;
  579. }
  580. static BOOL IsItemTrackable(HWND hwndList, UINT iItem, UINT fStyle)
  581. {
  582. if (RCS_TRACKITEM_SELECTED_I & fStyle) return (LVIS_SELECTED == (LVIS_SELECTED & SendMessageW(hwndList, LVM_GETITEMSTATE, (WPARAM)iItem, (LPARAM)LVIS_SELECTED)));
  583. if (RCS_TRACKITEM_FOCUSED_I & fStyle) return (LVIS_FOCUSED == (LVIS_FOCUSED & SendMessageW(hwndList, LVM_GETITEMSTATE, (WPARAM)iItem, (LPARAM)LVIS_FOCUSED)));
  584. return TRUE;
  585. }
  586. static void CALLBACK Timer_AutoUnhover(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime)
  587. {
  588. if (-1 == ratingTracking.iItem || NULL == ratingTracking.hwndList) KillTimer(NULL, idEvent);
  589. else
  590. {
  591. POINT pt;
  592. GetCursorPos(&pt);
  593. MapWindowPoints(HWND_DESKTOP, ratingTracking.hwndList, &pt, 1);
  594. if (pt.x > (ratingTracking.rc.right + RATING_RIGHTPADDING) || pt.x < (ratingTracking.rc.left - RATING_LEFTPADDING) ||
  595. pt.y > ratingTracking.rc.bottom || pt.y < ratingTracking.rc.top)
  596. {
  597. MLRatingColumnI_CancelTracking(FALSE);
  598. }
  599. }
  600. }
  601. static void CALLBACK Timer_Animation(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime)
  602. {
  603. if (-1 == ratingAnimation.iItem || !ratingAnimation.hwndList) KillTimer(NULL, idEvent);
  604. else
  605. {
  606. UINT iItem;
  607. HWND hwndList;
  608. iItem = ratingAnimation.iItem;
  609. hwndList = ratingAnimation.hwndList;
  610. if ((GetTickCount() - ratingAnimation.startedMs) > ratingAnimation.durationMs)
  611. {
  612. KillTimer(NULL, idEvent);
  613. ZeroMemory(&ratingAnimation, sizeof(RATINGANIMATION));
  614. ratingAnimation.iItem = (UINT)-1;
  615. }
  616. else if (++ratingAnimation.stage > 1) ratingAnimation.stage = 0;
  617. SendMessageW(hwndList, LVM_REDRAWITEMS, iItem, iItem);
  618. UpdateWindow(hwndList);
  619. }
  620. }
  621. static void TweakDialog_ApplyStyle(HWND hwndDlg, TWEAKPARAM *pTweak, UINT newStyle, BOOL bClosing)
  622. {
  623. if (!pTweak->fnApply(newStyle, bClosing))
  624. {
  625. wchar_t title[32] = {0};
  626. MessageBoxW(hwndDlg, WASABI_API_LNGSTRINGW(IDS_UNABLE_TO_APPLY_NEW_STYLE),
  627. WASABI_API_LNGSTRINGW_BUF(IDS_TWEAK_ERROR,title,32), MB_OK);
  628. newStyle = pTweak->fStyle;
  629. }
  630. else pTweak->fStyle = newStyle;
  631. }
  632. static void TweakDialog_InitializeControls(HWND hwndDlg, UINT fStyle)
  633. {
  634. INT i;
  635. HWND hwndCtrl;
  636. if (NULL != (hwndCtrl = GetDlgItem(hwndDlg, IDC_CMB_TRACKWHEN)))
  637. {
  638. int pszTrackWhen[] = { IDS_ALWAYS, IDS_PROCESS_ACTIVE, IDS_ANCESTOR_ACTIVE, IDS_WINDOW_FOCUSED, IDS_NEVER};
  639. for (i = 0; i < sizeof(pszTrackWhen)/sizeof(char*); i++) SendMessageW(hwndCtrl, CB_ADDSTRING, 0, (LPARAM)WASABI_API_LNGSTRINGW(pszTrackWhen[i]));
  640. if (RCS_TRACK_ALWAYS_I & fStyle) i = 0;
  641. else if (RCS_TRACK_PROCESSACTIVE_I & fStyle) i = 1;
  642. else if (RCS_TRACK_ANCESTORACITVE_I & fStyle) i = 2;
  643. else if (RCS_TRACK_WNDFOCUSED_I & fStyle) i = 3;
  644. else i = 4;
  645. SendMessage(hwndCtrl, CB_SETCURSEL, (WPARAM)i, 0L);
  646. }
  647. if (NULL != (hwndCtrl = GetDlgItem(hwndDlg, IDC_CMB_TRACKWHAT)))
  648. {
  649. int pszTrackWhat[] = { IDS_ALL, IDS_SELECTED, IDS_FOCUSED,};
  650. for (i = 0; i < sizeof(pszTrackWhat)/sizeof(char*); i++) SendMessageW(hwndCtrl, CB_ADDSTRING, 0, (LPARAM)WASABI_API_LNGSTRINGW(pszTrackWhat[i]));
  651. if (RCS_TRACKITEM_SELECTED_I & fStyle) i = 1;
  652. else if (RCS_TRACKITEM_FOCUSED_I & fStyle) i = 2;
  653. else i = 0;
  654. SendMessage(hwndCtrl, CB_SETCURSEL, (WPARAM)i, 0L);
  655. }
  656. if (NULL != (hwndCtrl = GetDlgItem(hwndDlg, IDC_CMB_ALIGNMENT)))
  657. {
  658. int pszAlignment[] = { IDS_LEFT, IDS_CENTER, IDS_RIGHT,};
  659. for (i = 0; i < sizeof(pszAlignment)/sizeof(char*); i++) SendMessageW(hwndCtrl, CB_ADDSTRING, 0, (LPARAM)WASABI_API_LNGSTRINGW(pszAlignment[i]));
  660. if (RCS_ALLIGN_CENTER_I & fStyle) i = 1;
  661. else if (RCS_ALLIGN_RIGHT_I & fStyle) i = 2;
  662. else i = 0;
  663. SendMessage(hwndCtrl, CB_SETCURSEL, (WPARAM)i, 0L);
  664. }
  665. CheckDlgButton(hwndDlg, IDC_CHK_SHOWEMPTY_NORMAL, (RCS_SHOWEMPTY_NORMAL_I & fStyle) ? BST_CHECKED : BST_UNCHECKED);
  666. CheckDlgButton(hwndDlg, IDC_CHK_SHOWEMPTY_HOT, (RCS_SHOWEMPTY_HOT_I & fStyle) ? BST_CHECKED : BST_UNCHECKED);
  667. CheckDlgButton(hwndDlg, IDC_CHK_SHOWEMPTY_ANIMATION, (RCS_SHOWEMPTY_ANIMATION_I & fStyle) ? BST_CHECKED : BST_UNCHECKED);
  668. CheckDlgButton(hwndDlg, IDC_CHK_SHOWINACTIVE_HOT, (RCS_SHOWINACTIVE_HOT_I & fStyle) ? BST_CHECKED : BST_UNCHECKED);
  669. CheckDlgButton(hwndDlg, IDC_CHK_BLOCKUNRATE, (RCS_BLOCKUNRATECLICK_I & fStyle) ? BST_CHECKED : BST_UNCHECKED);
  670. CheckDlgButton(hwndDlg, IDC_CHK_BLOCKCLICK, (RCS_BLOCKCLICK_I & fStyle) ? BST_CHECKED : BST_UNCHECKED);
  671. CheckDlgButton(hwndDlg, IDC_CHK_BLOCKDRAG, (RCS_BLOCKDRAG_I & fStyle) ? BST_CHECKED : BST_UNCHECKED);
  672. CheckDlgButton(hwndDlg, IDC_CHK_SIZEDECREASE, (RCS_SIZE_ALLOWDECREASE_I & fStyle) ? BST_CHECKED : BST_UNCHECKED);
  673. CheckDlgButton(hwndDlg, IDC_CHK_SIZEINCREASE, (RCS_SIZE_ALLOWINCREASE_I & fStyle) ? BST_CHECKED : BST_UNCHECKED);
  674. }
  675. static UINT TweakDialog_GetStyle(HWND hwndDlg)
  676. {
  677. INT i;
  678. HWND hwndCtrl;
  679. UINT fStyle;
  680. fStyle = 0;
  681. if (BST_CHECKED == IsDlgButtonChecked(hwndDlg, IDC_CHK_SHOWEMPTY_NORMAL)) fStyle |= RCS_SHOWEMPTY_NORMAL_I;
  682. if (BST_CHECKED == IsDlgButtonChecked(hwndDlg, IDC_CHK_SHOWEMPTY_HOT)) fStyle |= RCS_SHOWEMPTY_HOT_I;
  683. if (BST_CHECKED == IsDlgButtonChecked(hwndDlg, IDC_CHK_SHOWEMPTY_ANIMATION)) fStyle |= RCS_SHOWEMPTY_ANIMATION_I;
  684. if (BST_CHECKED == IsDlgButtonChecked(hwndDlg, IDC_CHK_SHOWINACTIVE_HOT)) fStyle |= RCS_SHOWINACTIVE_HOT_I;
  685. if (BST_CHECKED == IsDlgButtonChecked(hwndDlg, IDC_CHK_BLOCKUNRATE)) fStyle |= RCS_BLOCKUNRATECLICK_I;
  686. if (BST_CHECKED == IsDlgButtonChecked(hwndDlg, IDC_CHK_BLOCKCLICK)) fStyle |= RCS_BLOCKCLICK_I;
  687. if (BST_CHECKED == IsDlgButtonChecked(hwndDlg, IDC_CHK_BLOCKDRAG)) fStyle |= RCS_BLOCKDRAG_I;
  688. if (BST_CHECKED == IsDlgButtonChecked(hwndDlg, IDC_CHK_SIZEDECREASE)) fStyle |= RCS_SIZE_ALLOWDECREASE_I;
  689. if (BST_CHECKED == IsDlgButtonChecked(hwndDlg, IDC_CHK_SIZEINCREASE)) fStyle |= RCS_SIZE_ALLOWINCREASE_I;
  690. i = (NULL != (hwndCtrl = GetDlgItem(hwndDlg, IDC_CMB_TRACKWHEN))) ? (INT)SendMessage(hwndCtrl, CB_GETCURSEL, 0, 0L) : CB_ERR;
  691. switch(i)
  692. {
  693. case 0: fStyle |= RCS_TRACK_ALWAYS_I; break;
  694. case 1: fStyle |= RCS_TRACK_PROCESSACTIVE_I; break;
  695. case 2: fStyle |= RCS_TRACK_ANCESTORACITVE_I; break;
  696. case 3: fStyle |= RCS_TRACK_WNDFOCUSED_I; break;
  697. }
  698. i = (NULL != (hwndCtrl = GetDlgItem(hwndDlg, IDC_CMB_TRACKWHAT))) ? (INT)SendMessage(hwndCtrl, CB_GETCURSEL, 0,0L) : CB_ERR;
  699. switch(i)
  700. {
  701. case 1: fStyle |= RCS_TRACKITEM_SELECTED_I; break;
  702. case 2: fStyle |= RCS_TRACKITEM_FOCUSED_I; break;
  703. }
  704. i = (NULL != (hwndCtrl = GetDlgItem(hwndDlg, IDC_CMB_ALIGNMENT))) ? (INT)SendMessage(hwndCtrl, CB_GETCURSEL, 0,0L) : CB_ERR;
  705. switch(i)
  706. {
  707. case 1: fStyle |= RCS_ALLIGN_CENTER_I; break;
  708. case 2: fStyle |= RCS_ALLIGN_RIGHT_I; break;
  709. }
  710. return fStyle;
  711. }
  712. static INT_PTR WINAPI TweakDialogProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  713. {
  714. static TWEAKPARAM tweak;
  715. static UINT fStyle;
  716. switch(uMsg)
  717. {
  718. case WM_INITDIALOG:
  719. tweak.fnApply = (lParam) ? ((TWEAKPARAM*)lParam)->fnApply : NULL;
  720. tweak.fStyle = (lParam) ? ((TWEAKPARAM*)lParam)->fStyle : 0x000;
  721. if (RCS_DEFAULT == tweak.fStyle) tweak.fStyle = ratingGlobalStyle;
  722. fStyle = tweak.fStyle;
  723. TweakDialog_InitializeControls(hwnd, fStyle);
  724. break;
  725. case WM_COMMAND:
  726. switch(LOWORD(wParam))
  727. {
  728. case IDCANCEL:
  729. {
  730. wchar_t title[32] = {0};
  731. fStyle = TweakDialog_GetStyle(hwnd);
  732. TweakDialog_ApplyStyle(hwnd, &tweak,
  733. (tweak.fStyle != fStyle &&
  734. IDYES == MessageBoxW(hwnd, WASABI_API_LNGSTRINGW(IDS_DO_YOU_WANT_TO_SAVE_CHANGES_FIRST),
  735. WASABI_API_LNGSTRINGW_BUF(IDS_CONFIRM_CLOSE,title,32), MB_YESNO)) ?
  736. fStyle :tweak.fStyle, TRUE);
  737. DestroyWindow(hwnd);
  738. break;
  739. }
  740. case IDOK:
  741. if (BN_CLICKED == HIWORD(wParam))
  742. {
  743. fStyle = TweakDialog_GetStyle(hwnd);
  744. TweakDialog_ApplyStyle(hwnd, &tweak, fStyle, FALSE);
  745. }
  746. DestroyWindow(hwnd);
  747. break;
  748. }
  749. }
  750. return 0;
  751. }