848 lines
25 KiB
C++
848 lines
25 KiB
C++
|
#include "AlbumArtListView.h"
|
||
|
#include "api__ml_pmp.h"
|
||
|
#include "resource1.h"
|
||
|
#include "../tataki/export.h"
|
||
|
#include <api/service/waServiceFactory.h>
|
||
|
#include <api/service/svcs/svc_imgload.h>
|
||
|
#include "./local_menu.h"
|
||
|
|
||
|
extern winampMediaLibraryPlugin plugin;
|
||
|
|
||
|
#define WM_EX_GETREALLIST (WM_USER + 0x01)
|
||
|
|
||
|
#define HORZ_SPACING 4
|
||
|
#define VERT_SPACING 4
|
||
|
|
||
|
AlbumArtListView::AlbumArtListView(ListContents * lc, int dlgitem, HWND libraryParent, HWND parent, bool enableHeaderMenu)
|
||
|
: SkinnedListView(lc,dlgitem,libraryParent,parent,enableHeaderMenu), hbmpNames(NULL),
|
||
|
classicnotfoundW(0), classicnotfoundH(0), ratingrow(-1), itemHeight(0), textHeight(0), ratingTop(0),
|
||
|
notfound(L"winamp.cover.notfound"), notfound60(L"winamp.cover.notfound.60"), notfound90(L"winamp.cover.notfound.90")
|
||
|
{
|
||
|
this->hwndDlg = parent;
|
||
|
this->dlgitem = dlgitem;
|
||
|
mode = lc->config->ReadInt(L"albumartviewmode",0);
|
||
|
lc->SetMode(mode);
|
||
|
|
||
|
ZeroMemory(classicnotfound, sizeof(classicnotfound));
|
||
|
}
|
||
|
|
||
|
AlbumArtListView::~AlbumArtListView() {
|
||
|
if (hbmpNames) DeleteObject(hbmpNames);
|
||
|
}
|
||
|
|
||
|
int AlbumArtListView::GetFindItemColumn() {
|
||
|
if(mode > 1) return 1;
|
||
|
return contents->GetSortColumn();
|
||
|
}
|
||
|
|
||
|
static COLORREF GetWAColor(INT index)
|
||
|
{
|
||
|
static int (*wad_getColor)(int idx) = NULL;
|
||
|
if (!wad_getColor) *(void **)&wad_getColor=(void*)SendMessage(plugin.hwndLibraryParent,WM_ML_IPC,1,ML_IPC_SKIN_WADLG_GETFUNC);
|
||
|
return (wad_getColor) ? wad_getColor(index) : 0xFF00FF;
|
||
|
}
|
||
|
|
||
|
static void getImgSize(int mode, int &w, int &h) {
|
||
|
switch(mode) {
|
||
|
case 0: w=h=60; break;
|
||
|
case 1: w=h=90; break;
|
||
|
case 2: w=h=120; break;
|
||
|
case 3: w=h=60; break;
|
||
|
case 4: w=h=90; break;
|
||
|
case 5: w=h=120; break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static bool isDetailsMode(int mode) {
|
||
|
return mode == 0 || mode == 1 || mode == 2;
|
||
|
}
|
||
|
|
||
|
void DrawRect(HDC dc, int x, int y, int w, int h) {
|
||
|
w-=1;
|
||
|
h-=1;
|
||
|
MoveToEx(dc,x,y,NULL);
|
||
|
LineTo(dc,x,y+h);
|
||
|
MoveToEx(dc,x,y+h,NULL);
|
||
|
LineTo(dc,x+w,y+h);
|
||
|
MoveToEx(dc,x+w,y+h,NULL);
|
||
|
LineTo(dc,x+w,y);
|
||
|
MoveToEx(dc,x+w,y,NULL);
|
||
|
LineTo(dc,x,y);
|
||
|
}
|
||
|
|
||
|
static int getStrExtent(HDC dc, const wchar_t * s) {
|
||
|
int ret=0;
|
||
|
while(s && *s) {
|
||
|
int f=0;
|
||
|
GetCharWidth32(dc,*s,*s,&f);
|
||
|
s++;
|
||
|
ret+=f;
|
||
|
}
|
||
|
return int(ret);
|
||
|
}
|
||
|
|
||
|
ARGB32 * loadImg(const void * data, int len, int *w, int *h, bool ldata=false) {
|
||
|
FOURCC imgload = svc_imageLoader::getServiceType();
|
||
|
int n = plugin.service->service_getNumServices(imgload);
|
||
|
for(int i=0; i<n; i++) {
|
||
|
waServiceFactory *sf = plugin.service->service_enumService(imgload,i);
|
||
|
if(sf) {
|
||
|
svc_imageLoader * l = (svc_imageLoader*)sf->getInterface();
|
||
|
if(l) {
|
||
|
if(l->testData(data,len)) {
|
||
|
ARGB32* ret;
|
||
|
if(ldata) ret = l->loadImageData(data,len,w,h);
|
||
|
else ret = l->loadImage(data,len,w,h);
|
||
|
sf->releaseInterface(l);
|
||
|
return ret;
|
||
|
}
|
||
|
sf->releaseInterface(l);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
ARGB32 * loadRrc(int id, char * sec, int *w, int *h, bool data=false)
|
||
|
{
|
||
|
DWORD size = 0;
|
||
|
// as a nice little treat, allow lang packs to contain a custom IDR_IMAGE_NOTFOUND file
|
||
|
HGLOBAL resourceHandle = WASABI_API_LOADRESFROMFILEA((LPCSTR)sec, (LPCSTR)MAKEINTRESOURCEA(id), &size);
|
||
|
if(resourceHandle)
|
||
|
{
|
||
|
ARGB32* ret = loadImg(resourceHandle,size,w,h,data);
|
||
|
UnlockResource(resourceHandle);
|
||
|
return ret;
|
||
|
}
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
void adjustbmp(ARGB32 * p, int len, COLORREF fg)
|
||
|
{
|
||
|
ARGB32 * end = p+len;
|
||
|
while (p < end)
|
||
|
{
|
||
|
int a = (*p>>24)&0xff ;
|
||
|
int b = a*((*p&0xff) * (fg&0xff)) / (0xff*0xff);
|
||
|
int g = a*(((*p>>8)&0xff) * ((fg>>8)&0xff)) / (0xff*0xff);
|
||
|
int r = a*(((*p>>16)&0xff) * ((fg>>16)&0xff)) / (0xff*0xff);
|
||
|
*p = (a<<24) | (r&0xff) | ((g&0xff)<<8) | ((b&0xff)<<16);
|
||
|
p++;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void AlbumArtListView::drawArt(pmpart_t art, DCCanvas *pCanvas, RECT *prcDst, int itemid, int imageIndex)
|
||
|
{
|
||
|
int x = prcDst->left;
|
||
|
int y = prcDst->top;
|
||
|
int w = prcDst->right - prcDst->left;
|
||
|
int h = prcDst->bottom - prcDst->top;
|
||
|
HDC dc = pCanvas->getHDC();
|
||
|
if(art) contents->dev->setArtNaturalSize(art,w,h);
|
||
|
// draw image 4,4,w,h
|
||
|
if(art && contents->dev->drawArt(art,pCanvas->getHDC(),x,y,w,h)) {
|
||
|
// drawn by plugin!
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
SkinBitmap *noart;
|
||
|
|
||
|
int h = prcDst->right - prcDst->left;
|
||
|
if (h == 60)
|
||
|
noart = notfound60.getBitmap();
|
||
|
else if (h == 90)
|
||
|
noart = notfound90.getBitmap();
|
||
|
else
|
||
|
noart = notfound.getBitmap();
|
||
|
|
||
|
if (!noart || noart->isInvalid())
|
||
|
{
|
||
|
if(classicnotfound[imageIndex])
|
||
|
SkinBitmap(classicnotfound[imageIndex],classicnotfoundW,classicnotfoundH).stretchToRectAlpha(pCanvas, prcDst);
|
||
|
else
|
||
|
{
|
||
|
DrawRect(dc,x,y,w,h);
|
||
|
wchar_t str1[32] = {0}, str2[32] = {0};
|
||
|
WASABI_API_LNGSTRINGW_BUF(IDS_NO_IMAGE,str1,32);
|
||
|
WASABI_API_LNGSTRINGW_BUF(IDS_AVAILABLE,str2,32);
|
||
|
ExtTextOutW(dc, w/2 - 22 + x, w/2 - 14 + y, 0,NULL,str1,wcslen(str1),0);
|
||
|
ExtTextOutW(dc, w/2 - 22 + x, w/2 + 1 + y, 0,NULL,str2,wcslen(str2),0);
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
noart->stretch(pCanvas,x,y,w,h);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// icon view
|
||
|
BOOL AlbumArtListView::DrawItemIcon(NMLVCUSTOMDRAW *plvcd, DCCanvas *pCanvas, UINT itemState, RECT *prcClip, BOOL bWndActive)
|
||
|
{
|
||
|
HDC hdc = plvcd->nmcd.hdc;
|
||
|
RECT ri, re, rcText;
|
||
|
int w=0,h=0, imageIndex;
|
||
|
getImgSize(mode,w,h);
|
||
|
|
||
|
SetBkColor(hdc, plvcd->clrTextBk);
|
||
|
SetTextColor(hdc, plvcd->clrText);
|
||
|
SetRect(&rcText, plvcd->nmcd.rc.left, plvcd->nmcd.rc.bottom - (textHeight + 2), plvcd->nmcd.rc.right, plvcd->nmcd.rc.bottom);
|
||
|
imageIndex = 0;
|
||
|
if ((LVIS_SELECTED | LVIS_FOCUSED) & itemState)
|
||
|
{
|
||
|
SetRect(&re, plvcd->nmcd.rc.left, plvcd->nmcd.rc.top, plvcd->nmcd.rc.right, rcText.top - 4);
|
||
|
if (IntersectRect(&ri, &re, prcClip)) ExtTextOutW(hdc,0, 0, ETO_OPAQUE, &ri, L"", 0, 0);
|
||
|
if (LVIS_SELECTED & itemState) imageIndex = (bWndActive) ? 1 : 2;
|
||
|
}
|
||
|
|
||
|
SetRect(&re, plvcd->nmcd.rc.left + 2, plvcd->nmcd.rc.top + 2, plvcd->nmcd.rc.left + 2 + w, plvcd->nmcd.rc.top + 2 + h);
|
||
|
if (IntersectRect(&ri, &re, prcClip))
|
||
|
{
|
||
|
pmpart_t art = contents->GetArt(plvcd->nmcd.dwItemSpec);
|
||
|
drawArt(art, pCanvas, &re, plvcd->nmcd.dwItemSpec, imageIndex);
|
||
|
}
|
||
|
|
||
|
if (IntersectRect(&ri, &rcText, prcClip))
|
||
|
{
|
||
|
if ((LVIS_SELECTED | LVIS_FOCUSED) & itemState) ExtTextOutW(hdc,0, 0, ETO_OPAQUE, &ri, L"", 0, 0);
|
||
|
|
||
|
wchar_t buf[104] = {0};
|
||
|
contents->GetCellText(plvcd->nmcd.dwItemSpec,1,buf,100);
|
||
|
const wchar_t *p = buf;
|
||
|
if (p && *p)
|
||
|
{
|
||
|
SetRect(&ri, rcText.left + 2, rcText.top + 1, rcText.right - 2, rcText.bottom -1);
|
||
|
DrawTextW(hdc, p, -1, &ri, DT_CENTER | DT_SINGLELINE | DT_WORD_ELLIPSIS | DT_NOPREFIX);
|
||
|
}
|
||
|
|
||
|
if ((LVIS_FOCUSED & itemState) && bWndActive)
|
||
|
{
|
||
|
HWND hwndRealList;
|
||
|
hwndRealList = (HWND)SendMessageW(plvcd->nmcd.hdr.hwndFrom, WM_EX_GETREALLIST, 0, 0L);
|
||
|
if (hwndRealList && 0 == (0x01/*UISF_HIDEFOCUS*/ & SendMessageW(hwndRealList, 0x0129/*WM_QUERYUISTATE*/, 0, 0L)))
|
||
|
{
|
||
|
SetTextColor(hdc, GetSysColor(COLOR_WINDOWTEXT));
|
||
|
SetBkColor(hdc, GetSysColor(COLOR_WINDOW));
|
||
|
DrawFocusRect(hdc, &rcText);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
//detail view
|
||
|
BOOL AlbumArtListView::PrepareDetails(HDC hdc)
|
||
|
{
|
||
|
INT width(0), height, len;
|
||
|
HFONT hFont,hFontBold, hOldFont;
|
||
|
HDC hdcTmp;
|
||
|
HBITMAP hbmpOld;
|
||
|
LOGFONT l={0};
|
||
|
RECT ri = {0};
|
||
|
wchar_t ratingstr[100] = {0}, buf[100] = {0};
|
||
|
|
||
|
hdcTmp = CreateCompatibleDC(hdc);
|
||
|
if (!hdcTmp) return FALSE;
|
||
|
|
||
|
hFont = (HFONT)GetCurrentObject(hdc, OBJ_FONT);
|
||
|
GetObject(hFont, sizeof(LOGFONT), &l);
|
||
|
l.lfWeight = FW_BOLD;
|
||
|
hFontBold = CreateFontIndirect(&l);
|
||
|
|
||
|
hOldFont = (HFONT)SelectObject(hdcTmp, hFontBold);
|
||
|
|
||
|
for (int i=0; i < contents->GetNumColumns(); i++)
|
||
|
{
|
||
|
int of = getStrExtent(hdcTmp, contents->GetColumnTitle(i));
|
||
|
if (of > width) width = of;
|
||
|
}
|
||
|
if(width) width += 20;
|
||
|
height = contents->GetNumColumns() * textHeight;
|
||
|
hbmpNames = CreateCompatibleBitmap(hdc, width * 3, height);
|
||
|
hbmpOld = (HBITMAP)SelectObject(hdcTmp, hbmpNames);
|
||
|
|
||
|
SetRect(&ri, 0, 0, width, height);
|
||
|
|
||
|
WASABI_API_LNGSTRINGW_BUF(IDS_RATING,ratingstr,100);
|
||
|
INT clrText[3] = { WADLG_ITEMFG, WADLG_SELBAR_FGCOLOR, WADLG_INACT_SELBAR_FGCOLOR, };
|
||
|
INT clrBk[3] = { WADLG_ITEMBG, WADLG_SELBAR_BGCOLOR, WADLG_INACT_SELBAR_BGCOLOR, };
|
||
|
for (int j = 0; j < 3; j++)
|
||
|
{
|
||
|
SetTextColor(hdcTmp, GetWAColor(clrText[j]));
|
||
|
SetBkColor(hdcTmp, GetWAColor(clrBk[j]));
|
||
|
|
||
|
ExtTextOutW(hdcTmp,0, 0, ETO_OPAQUE, &ri, L"", 0, 0);
|
||
|
|
||
|
for (int i=0, top = 0; i < contents->GetNumColumns(); i++, top += textHeight)
|
||
|
{
|
||
|
if (-1 == ratingrow && 0 == lstrcmpW(contents->GetColumnTitle(i), ratingstr)) ratingrow = i;
|
||
|
StringCchCopyW(buf, 100, contents->GetColumnTitle(i));
|
||
|
len = wcslen(buf);
|
||
|
if (len > 0 && len < 99) { buf[len] = L':'; len ++; }
|
||
|
ExtTextOutW(hdcTmp, ri.left + 1, top, ETO_CLIPPED, &ri, buf, len, NULL);
|
||
|
}
|
||
|
OffsetRect(&ri, width, 0);
|
||
|
}
|
||
|
|
||
|
SelectObject(hdcTmp, hbmpOld);
|
||
|
SelectObject(hdcTmp, hOldFont);
|
||
|
DeleteObject(hFontBold);
|
||
|
DeleteDC(hdcTmp);
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
BOOL AlbumArtListView::DrawItemDetail(NMLVCUSTOMDRAW *plvcd, DCCanvas *pCanvas, UINT itemState, RECT *prcClip, BOOL bWndActive, HDC hdcNames, INT namesWidth)
|
||
|
{
|
||
|
RECT ri, re;
|
||
|
HDC hdc;
|
||
|
|
||
|
INT imageIndex;
|
||
|
|
||
|
hdc = plvcd->nmcd.hdc;
|
||
|
|
||
|
SetTextColor(hdc, plvcd->clrText);
|
||
|
SetBkColor(hdc, plvcd->clrTextBk);
|
||
|
|
||
|
if (LVIS_SELECTED & itemState)
|
||
|
{
|
||
|
// background
|
||
|
SetRect(&re, plvcd->nmcd.rc.left + 4, plvcd->nmcd.rc.top, plvcd->nmcd.rc.right, plvcd->nmcd.rc.bottom - 5);
|
||
|
if (IntersectRect(&ri, &re, prcClip)) ExtTextOutW(hdc,0, 0, ETO_OPAQUE, &ri, L"", 0, 0);
|
||
|
imageIndex = (bWndActive) ? 1 : 2;
|
||
|
}
|
||
|
else imageIndex = 0;
|
||
|
|
||
|
int w, h;
|
||
|
getImgSize(mode, w, h);
|
||
|
SetRect(&re, 6+plvcd->nmcd.rc.left, 3+plvcd->nmcd.rc.top, 6+ plvcd->nmcd.rc.left + w, 3+ plvcd->nmcd.rc.top + h);
|
||
|
if (IntersectRect(&ri, &re, prcClip))
|
||
|
{
|
||
|
pmpart_t art = contents->GetArt(plvcd->nmcd.dwItemSpec);
|
||
|
drawArt(art, pCanvas, &re, plvcd->nmcd.dwItemSpec, imageIndex);
|
||
|
}
|
||
|
|
||
|
// text
|
||
|
int limCY, limCX;
|
||
|
wchar_t buf[100] = {0};
|
||
|
|
||
|
limCY = plvcd->nmcd.rc.bottom;
|
||
|
if (prcClip->bottom < plvcd->nmcd.rc.bottom) limCY = prcClip->bottom;
|
||
|
limCX = plvcd->nmcd.rc.right -1;
|
||
|
if (prcClip->right < plvcd->nmcd.rc.right) limCX = prcClip->right;
|
||
|
|
||
|
SetRect(&ri, w+16+plvcd->nmcd.rc.left, 3+plvcd->nmcd.rc.top, limCX, limCY);
|
||
|
|
||
|
if (hdcNames && ri.left < ri.right)
|
||
|
{
|
||
|
BitBlt(hdc, ri.left, ri.top, min(ri.right - ri.left, namesWidth), ri.bottom - ri.top, hdcNames, namesWidth*imageIndex, 0, SRCCOPY);
|
||
|
ri.left += namesWidth;
|
||
|
}
|
||
|
|
||
|
ri.bottom = ri.top;
|
||
|
|
||
|
if (ri.left < ri.right)
|
||
|
{
|
||
|
for (int i=0; i < contents->GetNumColumns() && ri.top < limCY; i++, ri.top += textHeight)
|
||
|
{
|
||
|
contents->GetCellText(plvcd->nmcd.dwItemSpec,i,buf,100);
|
||
|
const wchar_t *p = buf;
|
||
|
|
||
|
ri.bottom += textHeight;
|
||
|
if (ri.bottom > limCY) ri.bottom = limCY;
|
||
|
|
||
|
if ((INT)i == ratingrow) // this is the ratings column, so draw graphical stars
|
||
|
{
|
||
|
int rating = wcslen(buf);
|
||
|
RATINGDRAWPARAMS p = {sizeof(RATINGDRAWPARAMS),hdc,
|
||
|
{ri.left, ri.top + ratingTop, ri.right,ri.bottom},
|
||
|
rating,5,0,RDS_SHOWEMPTY,NULL,0};
|
||
|
MLRating_Draw(plugin.hwndLibraryParent,&p);
|
||
|
}
|
||
|
else ExtTextOutW(hdc, ri.left, ri.top, ETO_CLIPPED ,&ri,p,wcslen(p),NULL);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// bottom line
|
||
|
MoveToEx(hdc,plvcd->nmcd.rc.left + 4,plvcd->nmcd.rc.bottom - 3,NULL);
|
||
|
LineTo(hdc,plvcd->nmcd.rc.right, plvcd->nmcd.rc.bottom - 3);
|
||
|
|
||
|
// focus rect
|
||
|
SetRect(&ri, plvcd->nmcd.rc.left + 4, plvcd->nmcd.rc.top, plvcd->nmcd.rc.right, plvcd->nmcd.rc.bottom - 5);
|
||
|
if ((LVIS_FOCUSED & itemState) && bWndActive)
|
||
|
{
|
||
|
HWND hwndRealList;
|
||
|
hwndRealList = (HWND)SendMessageW(plvcd->nmcd.hdr.hwndFrom, WM_EX_GETREALLIST, 0, 0L);
|
||
|
if (hwndRealList && 0 == (0x01/*UISF_HIDEFOCUS*/ & SendMessageW(hwndRealList, 0x0129/*WM_QUERYUISTATE*/, 0, 0L)))
|
||
|
{
|
||
|
SetTextColor(hdc, GetSysColor(COLOR_WINDOWTEXT));
|
||
|
SetBkColor(hdc, GetSysColor(COLOR_WINDOW));
|
||
|
DrawFocusRect(hdc, &ri);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
static HWND CreateSmoothScrollList(HWND parent, int x, int y, int cx, int cy, int dlgid) {
|
||
|
DWORD flags = WS_CHILD | WS_VSCROLL | DS_CONTROL | WS_CLIPSIBLINGS | WS_CLIPCHILDREN;
|
||
|
HWND h = CreateWindowExW(WS_EX_CONTROLPARENT, L"SmoothScrollList", L"",flags, x, y, cx, cy, parent,(HMENU)dlgid, NULL, (LPVOID)0);
|
||
|
SendMessage(h,WM_INITDIALOG,0,0);
|
||
|
return h;
|
||
|
}
|
||
|
|
||
|
static HWND CreateHeaderIconList(HWND parent, int x, int y, int cx, int cy, int dlgid) {
|
||
|
DWORD flags = WS_CHILD | WS_VSCROLL | DS_CONTROL | WS_CLIPSIBLINGS | WS_CLIPCHILDREN;
|
||
|
HWND h = CreateWindowExW(WS_EX_CONTROLPARENT, L"HeaderIconList", L"",flags, x, y, cx, cy, parent,(HMENU)dlgid, NULL, (LPVOID)0);
|
||
|
SendMessage(h,WM_INITDIALOG,0,0);
|
||
|
return h;
|
||
|
}
|
||
|
|
||
|
BOOL AlbumArtListView::OnKeyDown(NMLVKEYDOWN *plvkd)
|
||
|
{
|
||
|
switch (plvkd->wVKey)
|
||
|
{
|
||
|
case 'A':
|
||
|
if (GetAsyncKeyState(VK_CONTROL) && !GetAsyncKeyState(VK_SHIFT))
|
||
|
{
|
||
|
LVITEM item;
|
||
|
item.state = LVIS_SELECTED;
|
||
|
item.stateMask = LVIS_SELECTED;
|
||
|
SendMessageW(plvkd->hdr.hwndFrom, LVM_SETITEMSTATE, (WPARAM)-1, (LPARAM)&item);
|
||
|
return TRUE;
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
BOOL AlbumArtListView::OnCustomDrawIcon(NMLVCUSTOMDRAW *plvcd, LRESULT *pResult)
|
||
|
{
|
||
|
static RECT rcClip;
|
||
|
static BOOL bActive;
|
||
|
static DCCanvas activeCanvas;
|
||
|
|
||
|
*pResult = CDRF_DODEFAULT;
|
||
|
switch(plvcd->nmcd.dwDrawStage)
|
||
|
{
|
||
|
case CDDS_PREPAINT:
|
||
|
if (0 == plvcd->nmcd.rc.bottom && 0 == plvcd->nmcd.rc.right)
|
||
|
{
|
||
|
*pResult = CDRF_SKIPDEFAULT;
|
||
|
return TRUE;
|
||
|
}
|
||
|
CopyRect(&rcClip, &plvcd->nmcd.rc);
|
||
|
bActive = (GetFocus() == (HWND)SendMessageW(plvcd->nmcd.hdr.hwndFrom, WM_EX_GETREALLIST, 0, 0L));
|
||
|
activeCanvas.cloneDC(plvcd->nmcd.hdc, NULL);
|
||
|
*pResult = CDRF_NOTIFYITEMDRAW | CDRF_NOTIFYPOSTPAINT;
|
||
|
return TRUE;
|
||
|
|
||
|
case CDDS_ITEMPREPAINT:
|
||
|
{
|
||
|
UINT itemState;
|
||
|
itemState = SendMessageW(plvcd->nmcd.hdr.hwndFrom, LVM_GETITEMSTATE, plvcd->nmcd.dwItemSpec,
|
||
|
LVIS_FOCUSED | LVIS_SELECTED | LVIS_DROPHILITED | LVIS_CUT);
|
||
|
|
||
|
plvcd->nmcd.rc.left = LVIR_BOUNDS;
|
||
|
SendMessageW(plvcd->nmcd.hdr.hwndFrom, LVM_GETITEMRECT, plvcd->nmcd.dwItemSpec, (LPARAM)&plvcd->nmcd.rc);
|
||
|
plvcd->nmcd.rc.right -= HORZ_SPACING;
|
||
|
if (rcClip.left < plvcd->nmcd.rc.right)
|
||
|
{
|
||
|
DrawItemIcon(plvcd, &activeCanvas, itemState, &rcClip, bActive);
|
||
|
*pResult = CDRF_SKIPDEFAULT;
|
||
|
}
|
||
|
}
|
||
|
return TRUE;
|
||
|
|
||
|
case CDDS_POSTPAINT:
|
||
|
return TRUE;
|
||
|
}
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
BOOL AlbumArtListView::OnCustomDrawDetails(NMLVCUSTOMDRAW *plvcd, LRESULT *pResult)
|
||
|
{
|
||
|
static RECT rcClip;
|
||
|
static BOOL bActive;
|
||
|
static HDC hdcNames;
|
||
|
static INT namesWidth;
|
||
|
static HBITMAP hbmpOld;
|
||
|
static HPEN penOld;
|
||
|
static DCCanvas activeCanvas;
|
||
|
|
||
|
*pResult = CDRF_DODEFAULT;
|
||
|
switch(plvcd->nmcd.dwDrawStage)
|
||
|
{
|
||
|
case CDDS_PREPAINT:
|
||
|
if (0 == plvcd->nmcd.rc.bottom && 0 == plvcd->nmcd.rc.right)
|
||
|
{
|
||
|
*pResult = CDRF_SKIPDEFAULT;
|
||
|
return TRUE;
|
||
|
}
|
||
|
CopyRect(&rcClip, &plvcd->nmcd.rc);
|
||
|
if (!hbmpNames) PrepareDetails(plvcd->nmcd.hdc);
|
||
|
if (hbmpNames)
|
||
|
{
|
||
|
BITMAP bi;
|
||
|
GetObject(hbmpNames, sizeof(BITMAP), &bi);
|
||
|
namesWidth = bi.bmWidth/3;
|
||
|
hdcNames = CreateCompatibleDC(plvcd->nmcd.hdc);
|
||
|
hbmpOld = (hdcNames) ? (HBITMAP)SelectObject(hdcNames, hbmpNames) : NULL;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
hdcNames = NULL;
|
||
|
namesWidth = 0;
|
||
|
}
|
||
|
bActive = (GetFocus() == (HWND)SendMessageW(plvcd->nmcd.hdr.hwndFrom, WM_EX_GETREALLIST, 0, 0L));
|
||
|
|
||
|
penOld = (HPEN)SelectObject(plvcd->nmcd.hdc, CreatePen(PS_SOLID,1, GetWAColor(WADLG_HILITE)));
|
||
|
activeCanvas.cloneDC(plvcd->nmcd.hdc, NULL);
|
||
|
*pResult = CDRF_NOTIFYITEMDRAW | CDRF_NOTIFYPOSTPAINT;
|
||
|
return TRUE;
|
||
|
|
||
|
case CDDS_ITEMPREPAINT:
|
||
|
{
|
||
|
UINT itemState;
|
||
|
itemState = SendMessageW(plvcd->nmcd.hdr.hwndFrom, LVM_GETITEMSTATE, plvcd->nmcd.dwItemSpec,
|
||
|
LVIS_FOCUSED | LVIS_SELECTED | LVIS_DROPHILITED | LVIS_CUT);
|
||
|
|
||
|
plvcd->nmcd.rc.left = LVIR_BOUNDS;
|
||
|
SendMessageW(plvcd->nmcd.hdr.hwndFrom, LVM_GETITEMRECT, plvcd->nmcd.dwItemSpec, (LPARAM)&plvcd->nmcd.rc);
|
||
|
|
||
|
if (rcClip.left < plvcd->nmcd.rc.right)
|
||
|
{
|
||
|
DrawItemDetail(plvcd, &activeCanvas, itemState, &rcClip, bActive, hdcNames, namesWidth);
|
||
|
*pResult = CDRF_SKIPDEFAULT;
|
||
|
}
|
||
|
}
|
||
|
return TRUE;
|
||
|
|
||
|
case CDDS_POSTPAINT:
|
||
|
if (hdcNames)
|
||
|
{
|
||
|
SelectObject(hdcNames, hbmpOld);
|
||
|
DeleteDC(hdcNames);
|
||
|
}
|
||
|
if (penOld)
|
||
|
{
|
||
|
HPEN pen;
|
||
|
pen = (HPEN)SelectObject(plvcd->nmcd.hdc, penOld);
|
||
|
if (pen) DeleteObject(pen);
|
||
|
penOld = NULL;
|
||
|
}
|
||
|
return TRUE;
|
||
|
}
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
BOOL AlbumArtListView::CalcuateItemHeight(void)
|
||
|
{
|
||
|
int w, h;
|
||
|
HWND hwndList = GetDlgItem(hwndDlg, dlgitem);
|
||
|
TEXTMETRIC tm = {0};
|
||
|
|
||
|
getImgSize(mode, w, h);
|
||
|
|
||
|
textHeight = 0;
|
||
|
|
||
|
HDC hdc = GetDC(hwndDlg);
|
||
|
if (hdc)
|
||
|
{
|
||
|
HFONT hFont = (HFONT)SendMessageW(hwndList, WM_GETFONT, 0, 0L);
|
||
|
if (!hFont) hFont = (HFONT)GetStockObject(DEFAULT_GUI_FONT);
|
||
|
HFONT hFontOld = (HFONT)SelectObject(hdc, hFont);
|
||
|
|
||
|
GetTextMetrics(hdc, &tm);
|
||
|
textHeight = tm.tmHeight;
|
||
|
SelectObject(hdc, hFontOld);
|
||
|
ReleaseDC(hwndDlg, hdc);
|
||
|
}
|
||
|
|
||
|
if (isDetailsMode(mode))
|
||
|
{
|
||
|
if (textHeight < 14) textHeight = 14;
|
||
|
RECT r;
|
||
|
MLRating_CalcRect(plugin.hwndLibraryParent, NULL, 5, &r);
|
||
|
r.bottom -= r.top;
|
||
|
|
||
|
if ( r.bottom >= textHeight ) ratingTop = 0;
|
||
|
else
|
||
|
{
|
||
|
if (tm.tmAscent > (r.bottom + (r.bottom/2))) ratingTop = tm.tmAscent - r.bottom;
|
||
|
else ratingTop = (textHeight - r.bottom)/2 + 1;
|
||
|
}
|
||
|
|
||
|
int newHeight = max(h, textHeight * (INT)contents->GetNumColumns()) + 12;
|
||
|
if (newHeight != itemHeight)
|
||
|
{
|
||
|
itemHeight = newHeight;
|
||
|
RECT rw;
|
||
|
GetWindowRect(hwndList, &rw);
|
||
|
SetWindowPos(hwndList, NULL, 0, 0, rw.right - rw.left - 1, rw.bottom - rw.top, SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOZORDER | SWP_NOREDRAW);
|
||
|
SetWindowPos(hwndList, NULL, 0, 0, rw.right - rw.left, rw.bottom - rw.top, SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOZORDER);
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
HIMAGELIST hIL = (HIMAGELIST)SendMessageW(hwndList, LVM_GETIMAGELIST, 0, 0L);
|
||
|
if (!hIL || !ImageList_GetIconSize(hIL, &w, &h))
|
||
|
{ h += 4; w+= 4; }
|
||
|
SendMessageW(hwndList, LVM_SETICONSPACING, 0, MAKELPARAM(w + HORZ_SPACING, h + textHeight + 6 + VERT_SPACING));
|
||
|
if (!tm.tmAveCharWidth) tm.tmAveCharWidth = 2;
|
||
|
itemHeight = w / tm.tmAveCharWidth;
|
||
|
}
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
BOOL AlbumArtListView::DialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam,LPARAM lParam) {
|
||
|
switch(uMsg) {
|
||
|
case WM_INITDIALOG:
|
||
|
{
|
||
|
HWND hwnd = GetDlgItem(hwndDlg,dlgitem);
|
||
|
|
||
|
RECT r;
|
||
|
if (hwnd)
|
||
|
{
|
||
|
GetWindowRect(hwnd,&r);
|
||
|
MapWindowPoints(HWND_DESKTOP, hwndDlg, (POINT*)&r, 2);
|
||
|
}
|
||
|
else SetRect(&r, 0, 0, 1, 1);
|
||
|
|
||
|
if (isDetailsMode(mode))
|
||
|
{
|
||
|
if (hwnd) DestroyWindow(hwnd);
|
||
|
hwnd = CreateSmoothScrollList(hwndDlg, r.left, r.top, r.right - r.left, r.bottom - r.top, dlgitem);
|
||
|
SendMessage(hwnd,WM_USER+6,0,0);
|
||
|
ShowWindow(hwnd, SW_SHOWNORMAL);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if (hwnd) DestroyWindow(hwnd);
|
||
|
hwnd = CreateHeaderIconList(hwndDlg, r.left, r.top, r.right - r.left, r.bottom - r.top, dlgitem);
|
||
|
ShowWindow(hwnd,SW_SHOWNORMAL);
|
||
|
int w=0,h=0;
|
||
|
getImgSize(mode,w,h);
|
||
|
HIMAGELIST il = ImageList_Create(w + 4,h + 4,ILC_COLOR24,0,1); // add borders
|
||
|
ListView_SetImageList(hwnd,il,LVSIL_NORMAL);
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case WM_DISPLAYCHANGE:
|
||
|
{
|
||
|
if (hbmpNames) DeleteObject(hbmpNames);
|
||
|
hbmpNames = NULL;
|
||
|
ratingrow = -1;
|
||
|
CalcuateItemHeight();
|
||
|
|
||
|
int rw,rh;
|
||
|
ARGB32 * bmp = loadRrc(IDR_IMAGE_NOTFOUND,"PNG",&rw,&rh,true);
|
||
|
classicnotfoundW = rw;
|
||
|
classicnotfoundH = rh;
|
||
|
INT color[] = { WADLG_ITEMFG, WADLG_SELBAR_FGCOLOR, WADLG_INACT_SELBAR_FGCOLOR, };
|
||
|
|
||
|
for (int i = sizeof(classicnotfound)/sizeof(classicnotfound[0]) -1; i > -1; i--)
|
||
|
{
|
||
|
if(classicnotfound[i]) WASABI_API_MEMMGR->sysFree(classicnotfound[i]);
|
||
|
classicnotfound[i] = NULL;
|
||
|
|
||
|
if(bmp)
|
||
|
{
|
||
|
if (0 != i)
|
||
|
{
|
||
|
classicnotfound[i] = (ARGB32*)WASABI_API_MEMMGR->sysMalloc(sizeof(ARGB32)*rw*rh);
|
||
|
CopyMemory(classicnotfound[i], bmp, sizeof(ARGB32)*rw*rh);
|
||
|
}
|
||
|
else classicnotfound[i] = bmp;
|
||
|
adjustbmp(classicnotfound[i],rw*rh, GetWAColor(color[i]));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if(uMsg == WM_DISPLAYCHANGE) PostMessageW(GetDlgItem(hwndDlg,dlgitem),uMsg,wParam,lParam);
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case WM_DESTROY:
|
||
|
for (int i = sizeof(classicnotfound)/sizeof(classicnotfound[0]) -1; i > -1; i--)
|
||
|
{
|
||
|
if(classicnotfound[i]) WASABI_API_MEMMGR->sysFree(classicnotfound[i]);
|
||
|
classicnotfound[i] = NULL;
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case WM_MEASUREITEM:
|
||
|
if (wParam == (WPARAM)dlgitem)
|
||
|
{
|
||
|
((MEASUREITEMSTRUCT*)lParam)->itemHeight = itemHeight;
|
||
|
return TRUE;
|
||
|
}
|
||
|
break;
|
||
|
case WM_NOTIFY:
|
||
|
if (wParam == (WPARAM)dlgitem)
|
||
|
{
|
||
|
BOOL bProcessed(FALSE);
|
||
|
LRESULT result(0);
|
||
|
switch (((NMHDR*)lParam)->code)
|
||
|
{
|
||
|
case LVN_KEYDOWN: bProcessed = OnKeyDown((NMLVKEYDOWN*)lParam); break;
|
||
|
case NM_CUSTOMDRAW:
|
||
|
bProcessed = (isDetailsMode(mode)) ? OnCustomDrawDetails((NMLVCUSTOMDRAW*)lParam, &result) : OnCustomDrawIcon((NMLVCUSTOMDRAW*)lParam, &result);
|
||
|
break;
|
||
|
case LVN_GETDISPINFOW:
|
||
|
return TRUE;
|
||
|
case LVN_GETINFOTIPW:
|
||
|
{
|
||
|
wchar_t buf[256]=L"";
|
||
|
contents->GetCellText(((NMLVGETINFOTIPW*)lParam)->iItem,1,buf,256);
|
||
|
const wchar_t *p = buf;
|
||
|
if (p && *p && lstrlenW(p) > itemHeight) // we use itemHeight to write number of average characters that fits label in icon mode
|
||
|
{
|
||
|
StringCchCopyW(((NMLVGETINFOTIPW*)lParam)->pszText, ((NMLVGETINFOTIPW*)lParam)->cchTextMax, p);
|
||
|
}
|
||
|
}
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
if (bProcessed) SetWindowLongPtrW(hwndDlg, DWLP_MSGRESULT, (LONG_PTR)result);
|
||
|
return bProcessed;
|
||
|
}
|
||
|
{
|
||
|
LPNMHDR l=(LPNMHDR)lParam;
|
||
|
if(l->code == NM_RCLICK && l->hwndFrom == ListView_GetHeader(listview.getwnd())) {
|
||
|
extern HMENU m_context_menus;
|
||
|
HMENU menu = GetSubMenu(m_context_menus, 10);
|
||
|
POINT p;
|
||
|
GetCursorPos(&p);
|
||
|
int checked=0;
|
||
|
switch(mode) {
|
||
|
case 0: checked=ID_ARTHEADERMENU_SMALLDETAILS; break;
|
||
|
case 1: checked=ID_ARTHEADERMENU_MEDIUMDETAILS; break;
|
||
|
case 2: checked=ID_ARTHEADERMENU_LARGEDETAILS; break;
|
||
|
case 3: checked=ID_ARTHEADERMENU_SMALLICON; break;
|
||
|
case 4: checked=ID_ARTHEADERMENU_MEDIUMICON; break;
|
||
|
case 5: checked=ID_ARTHEADERMENU_LARGEICON; break;
|
||
|
}
|
||
|
CheckMenuItem(menu,checked,MF_CHECKED | MF_BYCOMMAND);
|
||
|
int r = Menu_TrackSkinnedPopup(menu, TPM_RETURNCMD | TPM_RIGHTBUTTON | TPM_LEFTBUTTON, p.x, p.y, l->hwndFrom, NULL);
|
||
|
CheckMenuItem(menu,checked,MF_UNCHECKED | MF_BYCOMMAND);
|
||
|
if(!r) return TRUE;
|
||
|
ProcessMenuResult(r,false,0,NULL,hwndDlg);
|
||
|
return TRUE;
|
||
|
} else if(l->code == LVN_GETINFOTIP && l->idFrom == dlgitem) {
|
||
|
NMLVGETINFOTIP *n = (NMLVGETINFOTIP*)l;
|
||
|
wchar_t artist[100] = {0}, album[100] = {0}, tracks[10] = {0}, year[10] = {0};
|
||
|
contents->GetCellText(n->iItem,0,artist,100);
|
||
|
contents->GetCellText(n->iItem,1,album,100);
|
||
|
contents->GetCellText(n->iItem,2,tracks,10);
|
||
|
contents->GetCellText(n->iItem,3,year,10);
|
||
|
wchar_t trackstr[100] = {0};
|
||
|
WASABI_API_LNGSTRINGW_BUF(IDS_TRACKS,trackstr,100);
|
||
|
CharLower(trackstr);
|
||
|
if(year[0]) StringCchPrintf(n->pszText,n->cchTextMax,L"%s - %s (%s): %s %s",artist,album,year,tracks,trackstr);
|
||
|
else StringCchPrintf(n->pszText,n->cchTextMax,L"%s - %s: %s %s",artist,album,tracks,trackstr);
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case LVM_REDRAWITEMS:
|
||
|
{
|
||
|
RECT ri;
|
||
|
HWND hwndList = GetDlgItem(hwndDlg, dlgitem);
|
||
|
if (hwndList)
|
||
|
{
|
||
|
HWND hwndRealList = (HWND)SendMessageW(hwndList, WM_EX_GETREALLIST, 0, 0L);
|
||
|
if (hwndRealList)
|
||
|
{
|
||
|
int w, h;
|
||
|
getImgSize(mode, w, h);
|
||
|
if (isDetailsMode(mode))
|
||
|
{
|
||
|
for(int i = (INT)wParam; i <= (INT)lParam; i++)
|
||
|
{
|
||
|
ri.left = LVIR_BOUNDS;
|
||
|
if (SendMessageW(hwndRealList, LVM_GETITEMRECT, i, (LPARAM)&ri))
|
||
|
{
|
||
|
ri.left += 6;
|
||
|
ri.top += 3;
|
||
|
ri.right = ri.left + w;
|
||
|
ri.bottom = ri.top + h;
|
||
|
InvalidateRect(hwndRealList, &ri, FALSE);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
for(int i = (INT)wParam; i <= (INT)lParam; i++)
|
||
|
{
|
||
|
ri.left = LVIR_ICON;
|
||
|
if (SendMessageW(hwndRealList, LVM_GETITEMRECT, i, (LPARAM)&ri))
|
||
|
{
|
||
|
ri.left += 2;
|
||
|
ri.top += 2;
|
||
|
ri.right = ri.left + w;
|
||
|
ri.bottom = ri.top + h;
|
||
|
InvalidateRect(hwndRealList, &ri, FALSE);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
else SendMessageW(hwndList, LVM_REDRAWITEMS, wParam, lParam);
|
||
|
}
|
||
|
}
|
||
|
return TRUE;
|
||
|
}
|
||
|
return SkinnedListView::DialogProc(hwndDlg,uMsg,wParam,lParam);
|
||
|
}
|
||
|
|
||
|
HMENU AlbumArtListView::GetMenu(bool isFilter, int filterNum, C_Config *c, HMENU themenu) {
|
||
|
HMENU menu = GetSubMenu(themenu, 10);
|
||
|
|
||
|
int checked=0;
|
||
|
switch(mode) {
|
||
|
case 0: checked=ID_ARTHEADERMENU_SMALLDETAILS; break;
|
||
|
case 1: checked=ID_ARTHEADERMENU_MEDIUMDETAILS; break;
|
||
|
case 2: checked=ID_ARTHEADERMENU_LARGEDETAILS; break;
|
||
|
case 3: checked=ID_ARTHEADERMENU_SMALLICON; break;
|
||
|
case 4: checked=ID_ARTHEADERMENU_MEDIUMICON; break;
|
||
|
case 5: checked=ID_ARTHEADERMENU_LARGEICON; break;
|
||
|
}
|
||
|
CheckMenuItem(menu,checked,MF_CHECKED | MF_BYCOMMAND);
|
||
|
|
||
|
if(isFilter) {
|
||
|
MENUITEMINFO m={sizeof(m),MIIM_ID,0};
|
||
|
int i=0;
|
||
|
while(GetMenuItemInfo(menu,i,TRUE,&m)) {
|
||
|
m.wID |= (1+filterNum) << 16;
|
||
|
SetMenuItemInfo(menu,i,TRUE,&m);
|
||
|
i++;
|
||
|
}
|
||
|
}
|
||
|
return menu;
|
||
|
}
|
||
|
|
||
|
void AlbumArtListView::ProcessMenuResult(int r, bool isFilter, int filterNum, C_Config *c, HWND parent) {
|
||
|
int mid = (r >> 16);
|
||
|
if(!isFilter && mid) return;
|
||
|
if(isFilter && mid-1 != filterNum) return;
|
||
|
r &= 0xFFFF;
|
||
|
|
||
|
switch(r) {
|
||
|
case ID_ARTHEADERMENU_SMALLDETAILS: mode=0; break;
|
||
|
case ID_ARTHEADERMENU_MEDIUMDETAILS: mode=1; break;
|
||
|
case ID_ARTHEADERMENU_LARGEDETAILS: mode=2; break;
|
||
|
case ID_ARTHEADERMENU_SMALLICON: mode=3; break;
|
||
|
case ID_ARTHEADERMENU_MEDIUMICON: mode=4; break;
|
||
|
case ID_ARTHEADERMENU_LARGEICON: mode=5; break;
|
||
|
default: return;
|
||
|
}
|
||
|
|
||
|
contents->config->WriteInt(L"albumartviewmode",mode);
|
||
|
contents->SetMode(mode);
|
||
|
while (ListView_DeleteColumn(listview.getwnd(), 0));
|
||
|
DialogProc(parent,WM_INITDIALOG,0,0);
|
||
|
HWND hwndList = GetDlgItem(parent,dlgitem);
|
||
|
if (hwndList)
|
||
|
{
|
||
|
MLSkinnedWnd_SkinChanged(hwndList, TRUE, TRUE);
|
||
|
ListView_SetItemCount(hwndList, contents->GetNumRows());
|
||
|
CalcuateItemHeight();
|
||
|
}
|
||
|
}
|