AlbumArtListView.cpp 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848
  1. #include "AlbumArtListView.h"
  2. #include "api__ml_pmp.h"
  3. #include "resource1.h"
  4. #include "../tataki/export.h"
  5. #include <api/service/waServiceFactory.h>
  6. #include <api/service/svcs/svc_imgload.h>
  7. #include "./local_menu.h"
  8. extern winampMediaLibraryPlugin plugin;
  9. #define WM_EX_GETREALLIST (WM_USER + 0x01)
  10. #define HORZ_SPACING 4
  11. #define VERT_SPACING 4
  12. AlbumArtListView::AlbumArtListView(ListContents * lc, int dlgitem, HWND libraryParent, HWND parent, bool enableHeaderMenu)
  13. : SkinnedListView(lc,dlgitem,libraryParent,parent,enableHeaderMenu), hbmpNames(NULL),
  14. classicnotfoundW(0), classicnotfoundH(0), ratingrow(-1), itemHeight(0), textHeight(0), ratingTop(0),
  15. notfound(L"winamp.cover.notfound"), notfound60(L"winamp.cover.notfound.60"), notfound90(L"winamp.cover.notfound.90")
  16. {
  17. this->hwndDlg = parent;
  18. this->dlgitem = dlgitem;
  19. mode = lc->config->ReadInt(L"albumartviewmode",0);
  20. lc->SetMode(mode);
  21. ZeroMemory(classicnotfound, sizeof(classicnotfound));
  22. }
  23. AlbumArtListView::~AlbumArtListView() {
  24. if (hbmpNames) DeleteObject(hbmpNames);
  25. }
  26. int AlbumArtListView::GetFindItemColumn() {
  27. if(mode > 1) return 1;
  28. return contents->GetSortColumn();
  29. }
  30. static COLORREF GetWAColor(INT index)
  31. {
  32. static int (*wad_getColor)(int idx) = NULL;
  33. if (!wad_getColor) *(void **)&wad_getColor=(void*)SendMessage(plugin.hwndLibraryParent,WM_ML_IPC,1,ML_IPC_SKIN_WADLG_GETFUNC);
  34. return (wad_getColor) ? wad_getColor(index) : 0xFF00FF;
  35. }
  36. static void getImgSize(int mode, int &w, int &h) {
  37. switch(mode) {
  38. case 0: w=h=60; break;
  39. case 1: w=h=90; break;
  40. case 2: w=h=120; break;
  41. case 3: w=h=60; break;
  42. case 4: w=h=90; break;
  43. case 5: w=h=120; break;
  44. }
  45. }
  46. static bool isDetailsMode(int mode) {
  47. return mode == 0 || mode == 1 || mode == 2;
  48. }
  49. void DrawRect(HDC dc, int x, int y, int w, int h) {
  50. w-=1;
  51. h-=1;
  52. MoveToEx(dc,x,y,NULL);
  53. LineTo(dc,x,y+h);
  54. MoveToEx(dc,x,y+h,NULL);
  55. LineTo(dc,x+w,y+h);
  56. MoveToEx(dc,x+w,y+h,NULL);
  57. LineTo(dc,x+w,y);
  58. MoveToEx(dc,x+w,y,NULL);
  59. LineTo(dc,x,y);
  60. }
  61. static int getStrExtent(HDC dc, const wchar_t * s) {
  62. int ret=0;
  63. while(s && *s) {
  64. int f=0;
  65. GetCharWidth32(dc,*s,*s,&f);
  66. s++;
  67. ret+=f;
  68. }
  69. return int(ret);
  70. }
  71. ARGB32 * loadImg(const void * data, int len, int *w, int *h, bool ldata=false) {
  72. FOURCC imgload = svc_imageLoader::getServiceType();
  73. int n = plugin.service->service_getNumServices(imgload);
  74. for(int i=0; i<n; i++) {
  75. waServiceFactory *sf = plugin.service->service_enumService(imgload,i);
  76. if(sf) {
  77. svc_imageLoader * l = (svc_imageLoader*)sf->getInterface();
  78. if(l) {
  79. if(l->testData(data,len)) {
  80. ARGB32* ret;
  81. if(ldata) ret = l->loadImageData(data,len,w,h);
  82. else ret = l->loadImage(data,len,w,h);
  83. sf->releaseInterface(l);
  84. return ret;
  85. }
  86. sf->releaseInterface(l);
  87. }
  88. }
  89. }
  90. return NULL;
  91. }
  92. ARGB32 * loadRrc(int id, char * sec, int *w, int *h, bool data=false)
  93. {
  94. DWORD size = 0;
  95. // as a nice little treat, allow lang packs to contain a custom IDR_IMAGE_NOTFOUND file
  96. HGLOBAL resourceHandle = WASABI_API_LOADRESFROMFILEA((LPCSTR)sec, (LPCSTR)MAKEINTRESOURCEA(id), &size);
  97. if(resourceHandle)
  98. {
  99. ARGB32* ret = loadImg(resourceHandle,size,w,h,data);
  100. UnlockResource(resourceHandle);
  101. return ret;
  102. }
  103. return NULL;
  104. }
  105. void adjustbmp(ARGB32 * p, int len, COLORREF fg)
  106. {
  107. ARGB32 * end = p+len;
  108. while (p < end)
  109. {
  110. int a = (*p>>24)&0xff ;
  111. int b = a*((*p&0xff) * (fg&0xff)) / (0xff*0xff);
  112. int g = a*(((*p>>8)&0xff) * ((fg>>8)&0xff)) / (0xff*0xff);
  113. int r = a*(((*p>>16)&0xff) * ((fg>>16)&0xff)) / (0xff*0xff);
  114. *p = (a<<24) | (r&0xff) | ((g&0xff)<<8) | ((b&0xff)<<16);
  115. p++;
  116. }
  117. }
  118. void AlbumArtListView::drawArt(pmpart_t art, DCCanvas *pCanvas, RECT *prcDst, int itemid, int imageIndex)
  119. {
  120. int x = prcDst->left;
  121. int y = prcDst->top;
  122. int w = prcDst->right - prcDst->left;
  123. int h = prcDst->bottom - prcDst->top;
  124. HDC dc = pCanvas->getHDC();
  125. if(art) contents->dev->setArtNaturalSize(art,w,h);
  126. // draw image 4,4,w,h
  127. if(art && contents->dev->drawArt(art,pCanvas->getHDC(),x,y,w,h)) {
  128. // drawn by plugin!
  129. }
  130. else
  131. {
  132. SkinBitmap *noart;
  133. int h = prcDst->right - prcDst->left;
  134. if (h == 60)
  135. noart = notfound60.getBitmap();
  136. else if (h == 90)
  137. noart = notfound90.getBitmap();
  138. else
  139. noart = notfound.getBitmap();
  140. if (!noart || noart->isInvalid())
  141. {
  142. if(classicnotfound[imageIndex])
  143. SkinBitmap(classicnotfound[imageIndex],classicnotfoundW,classicnotfoundH).stretchToRectAlpha(pCanvas, prcDst);
  144. else
  145. {
  146. DrawRect(dc,x,y,w,h);
  147. wchar_t str1[32] = {0}, str2[32] = {0};
  148. WASABI_API_LNGSTRINGW_BUF(IDS_NO_IMAGE,str1,32);
  149. WASABI_API_LNGSTRINGW_BUF(IDS_AVAILABLE,str2,32);
  150. ExtTextOutW(dc, w/2 - 22 + x, w/2 - 14 + y, 0,NULL,str1,wcslen(str1),0);
  151. ExtTextOutW(dc, w/2 - 22 + x, w/2 + 1 + y, 0,NULL,str2,wcslen(str2),0);
  152. }
  153. }
  154. else
  155. noart->stretch(pCanvas,x,y,w,h);
  156. }
  157. }
  158. // icon view
  159. BOOL AlbumArtListView::DrawItemIcon(NMLVCUSTOMDRAW *plvcd, DCCanvas *pCanvas, UINT itemState, RECT *prcClip, BOOL bWndActive)
  160. {
  161. HDC hdc = plvcd->nmcd.hdc;
  162. RECT ri, re, rcText;
  163. int w=0,h=0, imageIndex;
  164. getImgSize(mode,w,h);
  165. SetBkColor(hdc, plvcd->clrTextBk);
  166. SetTextColor(hdc, plvcd->clrText);
  167. SetRect(&rcText, plvcd->nmcd.rc.left, plvcd->nmcd.rc.bottom - (textHeight + 2), plvcd->nmcd.rc.right, plvcd->nmcd.rc.bottom);
  168. imageIndex = 0;
  169. if ((LVIS_SELECTED | LVIS_FOCUSED) & itemState)
  170. {
  171. SetRect(&re, plvcd->nmcd.rc.left, plvcd->nmcd.rc.top, plvcd->nmcd.rc.right, rcText.top - 4);
  172. if (IntersectRect(&ri, &re, prcClip)) ExtTextOutW(hdc,0, 0, ETO_OPAQUE, &ri, L"", 0, 0);
  173. if (LVIS_SELECTED & itemState) imageIndex = (bWndActive) ? 1 : 2;
  174. }
  175. SetRect(&re, plvcd->nmcd.rc.left + 2, plvcd->nmcd.rc.top + 2, plvcd->nmcd.rc.left + 2 + w, plvcd->nmcd.rc.top + 2 + h);
  176. if (IntersectRect(&ri, &re, prcClip))
  177. {
  178. pmpart_t art = contents->GetArt(plvcd->nmcd.dwItemSpec);
  179. drawArt(art, pCanvas, &re, plvcd->nmcd.dwItemSpec, imageIndex);
  180. }
  181. if (IntersectRect(&ri, &rcText, prcClip))
  182. {
  183. if ((LVIS_SELECTED | LVIS_FOCUSED) & itemState) ExtTextOutW(hdc,0, 0, ETO_OPAQUE, &ri, L"", 0, 0);
  184. wchar_t buf[104] = {0};
  185. contents->GetCellText(plvcd->nmcd.dwItemSpec,1,buf,100);
  186. const wchar_t *p = buf;
  187. if (p && *p)
  188. {
  189. SetRect(&ri, rcText.left + 2, rcText.top + 1, rcText.right - 2, rcText.bottom -1);
  190. DrawTextW(hdc, p, -1, &ri, DT_CENTER | DT_SINGLELINE | DT_WORD_ELLIPSIS | DT_NOPREFIX);
  191. }
  192. if ((LVIS_FOCUSED & itemState) && bWndActive)
  193. {
  194. HWND hwndRealList;
  195. hwndRealList = (HWND)SendMessageW(plvcd->nmcd.hdr.hwndFrom, WM_EX_GETREALLIST, 0, 0L);
  196. if (hwndRealList && 0 == (0x01/*UISF_HIDEFOCUS*/ & SendMessageW(hwndRealList, 0x0129/*WM_QUERYUISTATE*/, 0, 0L)))
  197. {
  198. SetTextColor(hdc, GetSysColor(COLOR_WINDOWTEXT));
  199. SetBkColor(hdc, GetSysColor(COLOR_WINDOW));
  200. DrawFocusRect(hdc, &rcText);
  201. }
  202. }
  203. }
  204. return TRUE;
  205. }
  206. //detail view
  207. BOOL AlbumArtListView::PrepareDetails(HDC hdc)
  208. {
  209. INT width(0), height, len;
  210. HFONT hFont,hFontBold, hOldFont;
  211. HDC hdcTmp;
  212. HBITMAP hbmpOld;
  213. LOGFONT l={0};
  214. RECT ri = {0};
  215. wchar_t ratingstr[100] = {0}, buf[100] = {0};
  216. hdcTmp = CreateCompatibleDC(hdc);
  217. if (!hdcTmp) return FALSE;
  218. hFont = (HFONT)GetCurrentObject(hdc, OBJ_FONT);
  219. GetObject(hFont, sizeof(LOGFONT), &l);
  220. l.lfWeight = FW_BOLD;
  221. hFontBold = CreateFontIndirect(&l);
  222. hOldFont = (HFONT)SelectObject(hdcTmp, hFontBold);
  223. for (int i=0; i < contents->GetNumColumns(); i++)
  224. {
  225. int of = getStrExtent(hdcTmp, contents->GetColumnTitle(i));
  226. if (of > width) width = of;
  227. }
  228. if(width) width += 20;
  229. height = contents->GetNumColumns() * textHeight;
  230. hbmpNames = CreateCompatibleBitmap(hdc, width * 3, height);
  231. hbmpOld = (HBITMAP)SelectObject(hdcTmp, hbmpNames);
  232. SetRect(&ri, 0, 0, width, height);
  233. WASABI_API_LNGSTRINGW_BUF(IDS_RATING,ratingstr,100);
  234. INT clrText[3] = { WADLG_ITEMFG, WADLG_SELBAR_FGCOLOR, WADLG_INACT_SELBAR_FGCOLOR, };
  235. INT clrBk[3] = { WADLG_ITEMBG, WADLG_SELBAR_BGCOLOR, WADLG_INACT_SELBAR_BGCOLOR, };
  236. for (int j = 0; j < 3; j++)
  237. {
  238. SetTextColor(hdcTmp, GetWAColor(clrText[j]));
  239. SetBkColor(hdcTmp, GetWAColor(clrBk[j]));
  240. ExtTextOutW(hdcTmp,0, 0, ETO_OPAQUE, &ri, L"", 0, 0);
  241. for (int i=0, top = 0; i < contents->GetNumColumns(); i++, top += textHeight)
  242. {
  243. if (-1 == ratingrow && 0 == lstrcmpW(contents->GetColumnTitle(i), ratingstr)) ratingrow = i;
  244. StringCchCopyW(buf, 100, contents->GetColumnTitle(i));
  245. len = wcslen(buf);
  246. if (len > 0 && len < 99) { buf[len] = L':'; len ++; }
  247. ExtTextOutW(hdcTmp, ri.left + 1, top, ETO_CLIPPED, &ri, buf, len, NULL);
  248. }
  249. OffsetRect(&ri, width, 0);
  250. }
  251. SelectObject(hdcTmp, hbmpOld);
  252. SelectObject(hdcTmp, hOldFont);
  253. DeleteObject(hFontBold);
  254. DeleteDC(hdcTmp);
  255. return TRUE;
  256. }
  257. BOOL AlbumArtListView::DrawItemDetail(NMLVCUSTOMDRAW *plvcd, DCCanvas *pCanvas, UINT itemState, RECT *prcClip, BOOL bWndActive, HDC hdcNames, INT namesWidth)
  258. {
  259. RECT ri, re;
  260. HDC hdc;
  261. INT imageIndex;
  262. hdc = plvcd->nmcd.hdc;
  263. SetTextColor(hdc, plvcd->clrText);
  264. SetBkColor(hdc, plvcd->clrTextBk);
  265. if (LVIS_SELECTED & itemState)
  266. {
  267. // background
  268. SetRect(&re, plvcd->nmcd.rc.left + 4, plvcd->nmcd.rc.top, plvcd->nmcd.rc.right, plvcd->nmcd.rc.bottom - 5);
  269. if (IntersectRect(&ri, &re, prcClip)) ExtTextOutW(hdc,0, 0, ETO_OPAQUE, &ri, L"", 0, 0);
  270. imageIndex = (bWndActive) ? 1 : 2;
  271. }
  272. else imageIndex = 0;
  273. int w, h;
  274. getImgSize(mode, w, h);
  275. SetRect(&re, 6+plvcd->nmcd.rc.left, 3+plvcd->nmcd.rc.top, 6+ plvcd->nmcd.rc.left + w, 3+ plvcd->nmcd.rc.top + h);
  276. if (IntersectRect(&ri, &re, prcClip))
  277. {
  278. pmpart_t art = contents->GetArt(plvcd->nmcd.dwItemSpec);
  279. drawArt(art, pCanvas, &re, plvcd->nmcd.dwItemSpec, imageIndex);
  280. }
  281. // text
  282. int limCY, limCX;
  283. wchar_t buf[100] = {0};
  284. limCY = plvcd->nmcd.rc.bottom;
  285. if (prcClip->bottom < plvcd->nmcd.rc.bottom) limCY = prcClip->bottom;
  286. limCX = plvcd->nmcd.rc.right -1;
  287. if (prcClip->right < plvcd->nmcd.rc.right) limCX = prcClip->right;
  288. SetRect(&ri, w+16+plvcd->nmcd.rc.left, 3+plvcd->nmcd.rc.top, limCX, limCY);
  289. if (hdcNames && ri.left < ri.right)
  290. {
  291. BitBlt(hdc, ri.left, ri.top, min(ri.right - ri.left, namesWidth), ri.bottom - ri.top, hdcNames, namesWidth*imageIndex, 0, SRCCOPY);
  292. ri.left += namesWidth;
  293. }
  294. ri.bottom = ri.top;
  295. if (ri.left < ri.right)
  296. {
  297. for (int i=0; i < contents->GetNumColumns() && ri.top < limCY; i++, ri.top += textHeight)
  298. {
  299. contents->GetCellText(plvcd->nmcd.dwItemSpec,i,buf,100);
  300. const wchar_t *p = buf;
  301. ri.bottom += textHeight;
  302. if (ri.bottom > limCY) ri.bottom = limCY;
  303. if ((INT)i == ratingrow) // this is the ratings column, so draw graphical stars
  304. {
  305. int rating = wcslen(buf);
  306. RATINGDRAWPARAMS p = {sizeof(RATINGDRAWPARAMS),hdc,
  307. {ri.left, ri.top + ratingTop, ri.right,ri.bottom},
  308. rating,5,0,RDS_SHOWEMPTY,NULL,0};
  309. MLRating_Draw(plugin.hwndLibraryParent,&p);
  310. }
  311. else ExtTextOutW(hdc, ri.left, ri.top, ETO_CLIPPED ,&ri,p,wcslen(p),NULL);
  312. }
  313. }
  314. // bottom line
  315. MoveToEx(hdc,plvcd->nmcd.rc.left + 4,plvcd->nmcd.rc.bottom - 3,NULL);
  316. LineTo(hdc,plvcd->nmcd.rc.right, plvcd->nmcd.rc.bottom - 3);
  317. // focus rect
  318. SetRect(&ri, plvcd->nmcd.rc.left + 4, plvcd->nmcd.rc.top, plvcd->nmcd.rc.right, plvcd->nmcd.rc.bottom - 5);
  319. if ((LVIS_FOCUSED & itemState) && bWndActive)
  320. {
  321. HWND hwndRealList;
  322. hwndRealList = (HWND)SendMessageW(plvcd->nmcd.hdr.hwndFrom, WM_EX_GETREALLIST, 0, 0L);
  323. if (hwndRealList && 0 == (0x01/*UISF_HIDEFOCUS*/ & SendMessageW(hwndRealList, 0x0129/*WM_QUERYUISTATE*/, 0, 0L)))
  324. {
  325. SetTextColor(hdc, GetSysColor(COLOR_WINDOWTEXT));
  326. SetBkColor(hdc, GetSysColor(COLOR_WINDOW));
  327. DrawFocusRect(hdc, &ri);
  328. }
  329. }
  330. return TRUE;
  331. }
  332. static HWND CreateSmoothScrollList(HWND parent, int x, int y, int cx, int cy, int dlgid) {
  333. DWORD flags = WS_CHILD | WS_VSCROLL | DS_CONTROL | WS_CLIPSIBLINGS | WS_CLIPCHILDREN;
  334. HWND h = CreateWindowExW(WS_EX_CONTROLPARENT, L"SmoothScrollList", L"",flags, x, y, cx, cy, parent,(HMENU)dlgid, NULL, (LPVOID)0);
  335. SendMessage(h,WM_INITDIALOG,0,0);
  336. return h;
  337. }
  338. static HWND CreateHeaderIconList(HWND parent, int x, int y, int cx, int cy, int dlgid) {
  339. DWORD flags = WS_CHILD | WS_VSCROLL | DS_CONTROL | WS_CLIPSIBLINGS | WS_CLIPCHILDREN;
  340. HWND h = CreateWindowExW(WS_EX_CONTROLPARENT, L"HeaderIconList", L"",flags, x, y, cx, cy, parent,(HMENU)dlgid, NULL, (LPVOID)0);
  341. SendMessage(h,WM_INITDIALOG,0,0);
  342. return h;
  343. }
  344. BOOL AlbumArtListView::OnKeyDown(NMLVKEYDOWN *plvkd)
  345. {
  346. switch (plvkd->wVKey)
  347. {
  348. case 'A':
  349. if (GetAsyncKeyState(VK_CONTROL) && !GetAsyncKeyState(VK_SHIFT))
  350. {
  351. LVITEM item;
  352. item.state = LVIS_SELECTED;
  353. item.stateMask = LVIS_SELECTED;
  354. SendMessageW(plvkd->hdr.hwndFrom, LVM_SETITEMSTATE, (WPARAM)-1, (LPARAM)&item);
  355. return TRUE;
  356. }
  357. break;
  358. }
  359. return FALSE;
  360. }
  361. BOOL AlbumArtListView::OnCustomDrawIcon(NMLVCUSTOMDRAW *plvcd, LRESULT *pResult)
  362. {
  363. static RECT rcClip;
  364. static BOOL bActive;
  365. static DCCanvas activeCanvas;
  366. *pResult = CDRF_DODEFAULT;
  367. switch(plvcd->nmcd.dwDrawStage)
  368. {
  369. case CDDS_PREPAINT:
  370. if (0 == plvcd->nmcd.rc.bottom && 0 == plvcd->nmcd.rc.right)
  371. {
  372. *pResult = CDRF_SKIPDEFAULT;
  373. return TRUE;
  374. }
  375. CopyRect(&rcClip, &plvcd->nmcd.rc);
  376. bActive = (GetFocus() == (HWND)SendMessageW(plvcd->nmcd.hdr.hwndFrom, WM_EX_GETREALLIST, 0, 0L));
  377. activeCanvas.cloneDC(plvcd->nmcd.hdc, NULL);
  378. *pResult = CDRF_NOTIFYITEMDRAW | CDRF_NOTIFYPOSTPAINT;
  379. return TRUE;
  380. case CDDS_ITEMPREPAINT:
  381. {
  382. UINT itemState;
  383. itemState = SendMessageW(plvcd->nmcd.hdr.hwndFrom, LVM_GETITEMSTATE, plvcd->nmcd.dwItemSpec,
  384. LVIS_FOCUSED | LVIS_SELECTED | LVIS_DROPHILITED | LVIS_CUT);
  385. plvcd->nmcd.rc.left = LVIR_BOUNDS;
  386. SendMessageW(plvcd->nmcd.hdr.hwndFrom, LVM_GETITEMRECT, plvcd->nmcd.dwItemSpec, (LPARAM)&plvcd->nmcd.rc);
  387. plvcd->nmcd.rc.right -= HORZ_SPACING;
  388. if (rcClip.left < plvcd->nmcd.rc.right)
  389. {
  390. DrawItemIcon(plvcd, &activeCanvas, itemState, &rcClip, bActive);
  391. *pResult = CDRF_SKIPDEFAULT;
  392. }
  393. }
  394. return TRUE;
  395. case CDDS_POSTPAINT:
  396. return TRUE;
  397. }
  398. return FALSE;
  399. }
  400. BOOL AlbumArtListView::OnCustomDrawDetails(NMLVCUSTOMDRAW *plvcd, LRESULT *pResult)
  401. {
  402. static RECT rcClip;
  403. static BOOL bActive;
  404. static HDC hdcNames;
  405. static INT namesWidth;
  406. static HBITMAP hbmpOld;
  407. static HPEN penOld;
  408. static DCCanvas activeCanvas;
  409. *pResult = CDRF_DODEFAULT;
  410. switch(plvcd->nmcd.dwDrawStage)
  411. {
  412. case CDDS_PREPAINT:
  413. if (0 == plvcd->nmcd.rc.bottom && 0 == plvcd->nmcd.rc.right)
  414. {
  415. *pResult = CDRF_SKIPDEFAULT;
  416. return TRUE;
  417. }
  418. CopyRect(&rcClip, &plvcd->nmcd.rc);
  419. if (!hbmpNames) PrepareDetails(plvcd->nmcd.hdc);
  420. if (hbmpNames)
  421. {
  422. BITMAP bi;
  423. GetObject(hbmpNames, sizeof(BITMAP), &bi);
  424. namesWidth = bi.bmWidth/3;
  425. hdcNames = CreateCompatibleDC(plvcd->nmcd.hdc);
  426. hbmpOld = (hdcNames) ? (HBITMAP)SelectObject(hdcNames, hbmpNames) : NULL;
  427. }
  428. else
  429. {
  430. hdcNames = NULL;
  431. namesWidth = 0;
  432. }
  433. bActive = (GetFocus() == (HWND)SendMessageW(plvcd->nmcd.hdr.hwndFrom, WM_EX_GETREALLIST, 0, 0L));
  434. penOld = (HPEN)SelectObject(plvcd->nmcd.hdc, CreatePen(PS_SOLID,1, GetWAColor(WADLG_HILITE)));
  435. activeCanvas.cloneDC(plvcd->nmcd.hdc, NULL);
  436. *pResult = CDRF_NOTIFYITEMDRAW | CDRF_NOTIFYPOSTPAINT;
  437. return TRUE;
  438. case CDDS_ITEMPREPAINT:
  439. {
  440. UINT itemState;
  441. itemState = SendMessageW(plvcd->nmcd.hdr.hwndFrom, LVM_GETITEMSTATE, plvcd->nmcd.dwItemSpec,
  442. LVIS_FOCUSED | LVIS_SELECTED | LVIS_DROPHILITED | LVIS_CUT);
  443. plvcd->nmcd.rc.left = LVIR_BOUNDS;
  444. SendMessageW(plvcd->nmcd.hdr.hwndFrom, LVM_GETITEMRECT, plvcd->nmcd.dwItemSpec, (LPARAM)&plvcd->nmcd.rc);
  445. if (rcClip.left < plvcd->nmcd.rc.right)
  446. {
  447. DrawItemDetail(plvcd, &activeCanvas, itemState, &rcClip, bActive, hdcNames, namesWidth);
  448. *pResult = CDRF_SKIPDEFAULT;
  449. }
  450. }
  451. return TRUE;
  452. case CDDS_POSTPAINT:
  453. if (hdcNames)
  454. {
  455. SelectObject(hdcNames, hbmpOld);
  456. DeleteDC(hdcNames);
  457. }
  458. if (penOld)
  459. {
  460. HPEN pen;
  461. pen = (HPEN)SelectObject(plvcd->nmcd.hdc, penOld);
  462. if (pen) DeleteObject(pen);
  463. penOld = NULL;
  464. }
  465. return TRUE;
  466. }
  467. return FALSE;
  468. }
  469. BOOL AlbumArtListView::CalcuateItemHeight(void)
  470. {
  471. int w, h;
  472. HWND hwndList = GetDlgItem(hwndDlg, dlgitem);
  473. TEXTMETRIC tm = {0};
  474. getImgSize(mode, w, h);
  475. textHeight = 0;
  476. HDC hdc = GetDC(hwndDlg);
  477. if (hdc)
  478. {
  479. HFONT hFont = (HFONT)SendMessageW(hwndList, WM_GETFONT, 0, 0L);
  480. if (!hFont) hFont = (HFONT)GetStockObject(DEFAULT_GUI_FONT);
  481. HFONT hFontOld = (HFONT)SelectObject(hdc, hFont);
  482. GetTextMetrics(hdc, &tm);
  483. textHeight = tm.tmHeight;
  484. SelectObject(hdc, hFontOld);
  485. ReleaseDC(hwndDlg, hdc);
  486. }
  487. if (isDetailsMode(mode))
  488. {
  489. if (textHeight < 14) textHeight = 14;
  490. RECT r;
  491. MLRating_CalcRect(plugin.hwndLibraryParent, NULL, 5, &r);
  492. r.bottom -= r.top;
  493. if ( r.bottom >= textHeight ) ratingTop = 0;
  494. else
  495. {
  496. if (tm.tmAscent > (r.bottom + (r.bottom/2))) ratingTop = tm.tmAscent - r.bottom;
  497. else ratingTop = (textHeight - r.bottom)/2 + 1;
  498. }
  499. int newHeight = max(h, textHeight * (INT)contents->GetNumColumns()) + 12;
  500. if (newHeight != itemHeight)
  501. {
  502. itemHeight = newHeight;
  503. RECT rw;
  504. GetWindowRect(hwndList, &rw);
  505. SetWindowPos(hwndList, NULL, 0, 0, rw.right - rw.left - 1, rw.bottom - rw.top, SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOZORDER | SWP_NOREDRAW);
  506. SetWindowPos(hwndList, NULL, 0, 0, rw.right - rw.left, rw.bottom - rw.top, SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOZORDER);
  507. }
  508. }
  509. else
  510. {
  511. HIMAGELIST hIL = (HIMAGELIST)SendMessageW(hwndList, LVM_GETIMAGELIST, 0, 0L);
  512. if (!hIL || !ImageList_GetIconSize(hIL, &w, &h))
  513. { h += 4; w+= 4; }
  514. SendMessageW(hwndList, LVM_SETICONSPACING, 0, MAKELPARAM(w + HORZ_SPACING, h + textHeight + 6 + VERT_SPACING));
  515. if (!tm.tmAveCharWidth) tm.tmAveCharWidth = 2;
  516. itemHeight = w / tm.tmAveCharWidth;
  517. }
  518. return TRUE;
  519. }
  520. BOOL AlbumArtListView::DialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam,LPARAM lParam) {
  521. switch(uMsg) {
  522. case WM_INITDIALOG:
  523. {
  524. HWND hwnd = GetDlgItem(hwndDlg,dlgitem);
  525. RECT r;
  526. if (hwnd)
  527. {
  528. GetWindowRect(hwnd,&r);
  529. MapWindowPoints(HWND_DESKTOP, hwndDlg, (POINT*)&r, 2);
  530. }
  531. else SetRect(&r, 0, 0, 1, 1);
  532. if (isDetailsMode(mode))
  533. {
  534. if (hwnd) DestroyWindow(hwnd);
  535. hwnd = CreateSmoothScrollList(hwndDlg, r.left, r.top, r.right - r.left, r.bottom - r.top, dlgitem);
  536. SendMessage(hwnd,WM_USER+6,0,0);
  537. ShowWindow(hwnd, SW_SHOWNORMAL);
  538. }
  539. else
  540. {
  541. if (hwnd) DestroyWindow(hwnd);
  542. hwnd = CreateHeaderIconList(hwndDlg, r.left, r.top, r.right - r.left, r.bottom - r.top, dlgitem);
  543. ShowWindow(hwnd,SW_SHOWNORMAL);
  544. int w=0,h=0;
  545. getImgSize(mode,w,h);
  546. HIMAGELIST il = ImageList_Create(w + 4,h + 4,ILC_COLOR24,0,1); // add borders
  547. ListView_SetImageList(hwnd,il,LVSIL_NORMAL);
  548. }
  549. }
  550. break;
  551. case WM_DISPLAYCHANGE:
  552. {
  553. if (hbmpNames) DeleteObject(hbmpNames);
  554. hbmpNames = NULL;
  555. ratingrow = -1;
  556. CalcuateItemHeight();
  557. int rw,rh;
  558. ARGB32 * bmp = loadRrc(IDR_IMAGE_NOTFOUND,"PNG",&rw,&rh,true);
  559. classicnotfoundW = rw;
  560. classicnotfoundH = rh;
  561. INT color[] = { WADLG_ITEMFG, WADLG_SELBAR_FGCOLOR, WADLG_INACT_SELBAR_FGCOLOR, };
  562. for (int i = sizeof(classicnotfound)/sizeof(classicnotfound[0]) -1; i > -1; i--)
  563. {
  564. if(classicnotfound[i]) WASABI_API_MEMMGR->sysFree(classicnotfound[i]);
  565. classicnotfound[i] = NULL;
  566. if(bmp)
  567. {
  568. if (0 != i)
  569. {
  570. classicnotfound[i] = (ARGB32*)WASABI_API_MEMMGR->sysMalloc(sizeof(ARGB32)*rw*rh);
  571. CopyMemory(classicnotfound[i], bmp, sizeof(ARGB32)*rw*rh);
  572. }
  573. else classicnotfound[i] = bmp;
  574. adjustbmp(classicnotfound[i],rw*rh, GetWAColor(color[i]));
  575. }
  576. }
  577. if(uMsg == WM_DISPLAYCHANGE) PostMessageW(GetDlgItem(hwndDlg,dlgitem),uMsg,wParam,lParam);
  578. }
  579. break;
  580. case WM_DESTROY:
  581. for (int i = sizeof(classicnotfound)/sizeof(classicnotfound[0]) -1; i > -1; i--)
  582. {
  583. if(classicnotfound[i]) WASABI_API_MEMMGR->sysFree(classicnotfound[i]);
  584. classicnotfound[i] = NULL;
  585. }
  586. break;
  587. case WM_MEASUREITEM:
  588. if (wParam == (WPARAM)dlgitem)
  589. {
  590. ((MEASUREITEMSTRUCT*)lParam)->itemHeight = itemHeight;
  591. return TRUE;
  592. }
  593. break;
  594. case WM_NOTIFY:
  595. if (wParam == (WPARAM)dlgitem)
  596. {
  597. BOOL bProcessed(FALSE);
  598. LRESULT result(0);
  599. switch (((NMHDR*)lParam)->code)
  600. {
  601. case LVN_KEYDOWN: bProcessed = OnKeyDown((NMLVKEYDOWN*)lParam); break;
  602. case NM_CUSTOMDRAW:
  603. bProcessed = (isDetailsMode(mode)) ? OnCustomDrawDetails((NMLVCUSTOMDRAW*)lParam, &result) : OnCustomDrawIcon((NMLVCUSTOMDRAW*)lParam, &result);
  604. break;
  605. case LVN_GETDISPINFOW:
  606. return TRUE;
  607. case LVN_GETINFOTIPW:
  608. {
  609. wchar_t buf[256]=L"";
  610. contents->GetCellText(((NMLVGETINFOTIPW*)lParam)->iItem,1,buf,256);
  611. const wchar_t *p = buf;
  612. if (p && *p && lstrlenW(p) > itemHeight) // we use itemHeight to write number of average characters that fits label in icon mode
  613. {
  614. StringCchCopyW(((NMLVGETINFOTIPW*)lParam)->pszText, ((NMLVGETINFOTIPW*)lParam)->cchTextMax, p);
  615. }
  616. }
  617. return TRUE;
  618. }
  619. if (bProcessed) SetWindowLongPtrW(hwndDlg, DWLP_MSGRESULT, (LONG_PTR)result);
  620. return bProcessed;
  621. }
  622. {
  623. LPNMHDR l=(LPNMHDR)lParam;
  624. if(l->code == NM_RCLICK && l->hwndFrom == ListView_GetHeader(listview.getwnd())) {
  625. extern HMENU m_context_menus;
  626. HMENU menu = GetSubMenu(m_context_menus, 10);
  627. POINT p;
  628. GetCursorPos(&p);
  629. int checked=0;
  630. switch(mode) {
  631. case 0: checked=ID_ARTHEADERMENU_SMALLDETAILS; break;
  632. case 1: checked=ID_ARTHEADERMENU_MEDIUMDETAILS; break;
  633. case 2: checked=ID_ARTHEADERMENU_LARGEDETAILS; break;
  634. case 3: checked=ID_ARTHEADERMENU_SMALLICON; break;
  635. case 4: checked=ID_ARTHEADERMENU_MEDIUMICON; break;
  636. case 5: checked=ID_ARTHEADERMENU_LARGEICON; break;
  637. }
  638. CheckMenuItem(menu,checked,MF_CHECKED | MF_BYCOMMAND);
  639. int r = Menu_TrackSkinnedPopup(menu, TPM_RETURNCMD | TPM_RIGHTBUTTON | TPM_LEFTBUTTON, p.x, p.y, l->hwndFrom, NULL);
  640. CheckMenuItem(menu,checked,MF_UNCHECKED | MF_BYCOMMAND);
  641. if(!r) return TRUE;
  642. ProcessMenuResult(r,false,0,NULL,hwndDlg);
  643. return TRUE;
  644. } else if(l->code == LVN_GETINFOTIP && l->idFrom == dlgitem) {
  645. NMLVGETINFOTIP *n = (NMLVGETINFOTIP*)l;
  646. wchar_t artist[100] = {0}, album[100] = {0}, tracks[10] = {0}, year[10] = {0};
  647. contents->GetCellText(n->iItem,0,artist,100);
  648. contents->GetCellText(n->iItem,1,album,100);
  649. contents->GetCellText(n->iItem,2,tracks,10);
  650. contents->GetCellText(n->iItem,3,year,10);
  651. wchar_t trackstr[100] = {0};
  652. WASABI_API_LNGSTRINGW_BUF(IDS_TRACKS,trackstr,100);
  653. CharLower(trackstr);
  654. if(year[0]) StringCchPrintf(n->pszText,n->cchTextMax,L"%s - %s (%s): %s %s",artist,album,year,tracks,trackstr);
  655. else StringCchPrintf(n->pszText,n->cchTextMax,L"%s - %s: %s %s",artist,album,tracks,trackstr);
  656. }
  657. }
  658. break;
  659. case LVM_REDRAWITEMS:
  660. {
  661. RECT ri;
  662. HWND hwndList = GetDlgItem(hwndDlg, dlgitem);
  663. if (hwndList)
  664. {
  665. HWND hwndRealList = (HWND)SendMessageW(hwndList, WM_EX_GETREALLIST, 0, 0L);
  666. if (hwndRealList)
  667. {
  668. int w, h;
  669. getImgSize(mode, w, h);
  670. if (isDetailsMode(mode))
  671. {
  672. for(int i = (INT)wParam; i <= (INT)lParam; i++)
  673. {
  674. ri.left = LVIR_BOUNDS;
  675. if (SendMessageW(hwndRealList, LVM_GETITEMRECT, i, (LPARAM)&ri))
  676. {
  677. ri.left += 6;
  678. ri.top += 3;
  679. ri.right = ri.left + w;
  680. ri.bottom = ri.top + h;
  681. InvalidateRect(hwndRealList, &ri, FALSE);
  682. }
  683. }
  684. }
  685. else
  686. {
  687. for(int i = (INT)wParam; i <= (INT)lParam; i++)
  688. {
  689. ri.left = LVIR_ICON;
  690. if (SendMessageW(hwndRealList, LVM_GETITEMRECT, i, (LPARAM)&ri))
  691. {
  692. ri.left += 2;
  693. ri.top += 2;
  694. ri.right = ri.left + w;
  695. ri.bottom = ri.top + h;
  696. InvalidateRect(hwndRealList, &ri, FALSE);
  697. }
  698. }
  699. }
  700. }
  701. else SendMessageW(hwndList, LVM_REDRAWITEMS, wParam, lParam);
  702. }
  703. }
  704. return TRUE;
  705. }
  706. return SkinnedListView::DialogProc(hwndDlg,uMsg,wParam,lParam);
  707. }
  708. HMENU AlbumArtListView::GetMenu(bool isFilter, int filterNum, C_Config *c, HMENU themenu) {
  709. HMENU menu = GetSubMenu(themenu, 10);
  710. int checked=0;
  711. switch(mode) {
  712. case 0: checked=ID_ARTHEADERMENU_SMALLDETAILS; break;
  713. case 1: checked=ID_ARTHEADERMENU_MEDIUMDETAILS; break;
  714. case 2: checked=ID_ARTHEADERMENU_LARGEDETAILS; break;
  715. case 3: checked=ID_ARTHEADERMENU_SMALLICON; break;
  716. case 4: checked=ID_ARTHEADERMENU_MEDIUMICON; break;
  717. case 5: checked=ID_ARTHEADERMENU_LARGEICON; break;
  718. }
  719. CheckMenuItem(menu,checked,MF_CHECKED | MF_BYCOMMAND);
  720. if(isFilter) {
  721. MENUITEMINFO m={sizeof(m),MIIM_ID,0};
  722. int i=0;
  723. while(GetMenuItemInfo(menu,i,TRUE,&m)) {
  724. m.wID |= (1+filterNum) << 16;
  725. SetMenuItemInfo(menu,i,TRUE,&m);
  726. i++;
  727. }
  728. }
  729. return menu;
  730. }
  731. void AlbumArtListView::ProcessMenuResult(int r, bool isFilter, int filterNum, C_Config *c, HWND parent) {
  732. int mid = (r >> 16);
  733. if(!isFilter && mid) return;
  734. if(isFilter && mid-1 != filterNum) return;
  735. r &= 0xFFFF;
  736. switch(r) {
  737. case ID_ARTHEADERMENU_SMALLDETAILS: mode=0; break;
  738. case ID_ARTHEADERMENU_MEDIUMDETAILS: mode=1; break;
  739. case ID_ARTHEADERMENU_LARGEDETAILS: mode=2; break;
  740. case ID_ARTHEADERMENU_SMALLICON: mode=3; break;
  741. case ID_ARTHEADERMENU_MEDIUMICON: mode=4; break;
  742. case ID_ARTHEADERMENU_LARGEICON: mode=5; break;
  743. default: return;
  744. }
  745. contents->config->WriteInt(L"albumartviewmode",mode);
  746. contents->SetMode(mode);
  747. while (ListView_DeleteColumn(listview.getwnd(), 0));
  748. DialogProc(parent,WM_INITDIALOG,0,0);
  749. HWND hwndList = GetDlgItem(parent,dlgitem);
  750. if (hwndList)
  751. {
  752. MLSkinnedWnd_SkinChanged(hwndList, TRUE, TRUE);
  753. ListView_SetItemCount(hwndList, contents->GetNumRows());
  754. CalcuateItemHeight();
  755. }
  756. }