winamp/Src/Plugins/General/gen_ml/HeaderIconList.cpp

1115 lines
28 KiB
C++
Raw Permalink Normal View History

2024-09-24 13:54:57 +01:00
#include "main.h"
#include "../gen_ml/ml.h"
#include "../gen_ml/ml_ipc_0313.h"
#include "../Winamp/gen.h"
#define WM_EX_GETREALLIST (WM_USER + 0x01)
#define WM_EX_UNLOCKREDRAW (WM_USER + 0x02)
#define WM_EX_UPDATESCROLLINFO (WM_USER + 0x03)
#define WM_EX_GETCOUNTPERPAGE (WM_USER + 0x04)
#define LVN_EX_SIZECHANGED (LVN_LAST)
#define IWF_NO 0x0000
#define IWF_ALL 0x00FF
#define IWF_CONTAINER 0x0001
#define IWF_LISTVIEW 0x0002
#define IWF_HEADER 0x0004
#define IWF_UPDATENOW 0x1000
BOOL
CopyListColumnToHeaderItem(const LVCOLUMNW *column, HDITEMW *item)
{
if (NULL == column || NULL == item)
return FALSE;
item->mask = 0;
if (0 != (LVCF_FMT & column->mask))
{
item->mask |= HDI_FORMAT;
item->fmt = 0;
switch((LVCFMT_JUSTIFYMASK & column->fmt))
{
case LVCFMT_RIGHT:
item->fmt |= HDF_RIGHT;
break;
case LVCFMT_CENTER:
item->fmt |= HDF_CENTER;
break;
default:
item->fmt |= HDF_LEFT;
break;
}
if (0 != (LVCFMT_IMAGE & column->fmt))
item->fmt |= HDF_IMAGE;
if (0 != (LVCFMT_BITMAP_ON_RIGHT & column->fmt))
item->fmt |= HDF_BITMAP_ON_RIGHT;
}
if (0 != (LVCF_WIDTH & column->mask))
{
item->mask |= HDI_WIDTH;
item->cxy = column->cx;
}
if (0 != (LVCF_TEXT & column->mask))
{
item->mask |= HDI_TEXT;
item->pszText = column->pszText;
item->cchTextMax = column->cchTextMax;
}
if (0 != (LVCF_IMAGE & column->mask))
{
item->mask |= HDI_IMAGE;
item->iImage = column->iImage;
}
if (0 != (LVCF_ORDER & column->mask))
{
item->mask |= HDI_ORDER;
item->iOrder = column->iOrder;
}
return TRUE;
}
BOOL
CopyHeaderItemToListColumn(const HDITEMW *item, LVCOLUMNW *column)
{
if (NULL == column || NULL == item)
return FALSE;
column->mask = 0;
if (0 != (HDI_FORMAT& item->mask))
{
column->mask |= LVCF_FMT ;
column->fmt = 0;
switch((HDF_JUSTIFYMASK & item->fmt))
{
case HDF_RIGHT:
column->fmt |= LVCFMT_RIGHT;
break;
case HDF_CENTER:
column->fmt |= LVCFMT_CENTER;
break;
default:
column->fmt |= LVCFMT_LEFT;
break;
}
if (0 != (HDF_IMAGE & item->fmt))
column->fmt |= LVCFMT_IMAGE;
if (0 != (HDF_BITMAP_ON_RIGHT & item->fmt))
column->fmt |= LVCFMT_BITMAP_ON_RIGHT;
}
if (0 != (HDI_WIDTH & item->mask))
{
column->mask |= LVCF_WIDTH;
column->cx = item->cxy;
}
if (0 != (HDI_TEXT & item->mask))
{
column->mask |= LVCF_TEXT;
column->pszText = item->pszText;
column->cchTextMax = item->cchTextMax;
}
if (0 != (HDI_IMAGE & item->mask))
{
column->mask |= LVCF_IMAGE;
column->iImage = item->iImage;
}
if (0 != (HDI_ORDER & item->mask))
{
column->mask |= LVCF_ORDER;
column->iOrder = item->iOrder;
}
return TRUE;
}
static BOOL UpdateScrollInfo(HWND hwnd, UINT fMask, BOOL bRedraw)
{
HWND hwndList;
SCROLLINFO si;
BOOL bUpdateBars(FALSE);
hwndList = GetDlgItem(hwnd,2);
si.cbSize= sizeof(SCROLLINFO);
si.fMask = SIF_RANGE | SIF_PAGE | SIF_POS;
if (!hwndList || !GetScrollInfo(hwnd, SB_VERT, &si))
return FALSE;
if (SIF_RANGE & fMask)
{
RECT rc, rv;
UINT nPage;
INT nMax;
BOOL bScrollVisible;
HDLAYOUT headerLayout;
WINDOWPOS headerPos;
HWND hwndHeader = GetDlgItem(hwnd, 3);
if (!hwndHeader)
return FALSE;
GetClientRect(hwnd, &rc);
ListView_GetViewRect(hwndList,&rv);
headerLayout.prc = &rc;
headerLayout.pwpos = &headerPos;
SendMessageW(hwndHeader, HDM_LAYOUT, 0, (LPARAM)&headerLayout);
bScrollVisible = (si.nMax > 0 && si.nPage > 0 && (INT)si.nPage < si.nMax);
nMax = rv.bottom - rv.top;
nPage = (rc.bottom - rc.top);
if (si.nMax != nMax || si.nPage != nPage)
{
si.nMin = 0;
si.nMax = nMax;
si.nPage = nPage;
SetScrollInfo(hwnd, SB_VERT, &si, FALSE);
bUpdateBars = TRUE;
if (bScrollVisible != (si.nMax > 0 && si.nPage > 0 && (INT)si.nPage < si.nMax))
{
MLSkinnedScrollWnd_UpdateBars(hwnd, bRedraw);
GetClientRect(hwnd, &rc);
headerLayout.prc = &rc;
headerLayout.pwpos = &headerPos;
SendMessageW(hwndHeader, HDM_LAYOUT, 0, (LPARAM)&headerLayout);
headerPos.flags |= SWP_NOREDRAW;
SetWindowPos(hwndHeader, headerPos.hwndInsertAfter, headerPos.x, headerPos.y,
headerPos.cx, headerPos.cy, headerPos.flags);
SetWindowPos(hwndList, NULL, rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top,
SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOMOVE | SWP_NOREDRAW);
if (FALSE != bRedraw)
RedrawWindow(hwnd, NULL, NULL, RDW_INVALIDATE | RDW_ALLCHILDREN);
bUpdateBars = FALSE;
}
}
}
if (SIF_POS & fMask)
{
POINT p;
if (FALSE != SendMessageW(hwndList, LVM_GETORIGIN, (WPARAM)0, (LPARAM)&p))
{
if (p.y < si.nMin)
p.y = si.nMin;
if (p.y > (si.nMax - (int)si.nPage))
p.y = si.nMax - si.nPage;
if (p.y != si.nPos)
{
si.nPos = p.y;
si.fMask = SIF_POS;
SetScrollInfo(hwnd, SB_VERT, &si, TRUE);
bUpdateBars = TRUE;
}
}
}
if (bUpdateBars)
MLSkinnedScrollWnd_UpdateBars(hwnd, bRedraw);
return TRUE;
}
static void
UpdateFontMetrics(HWND hwnd, BOOL redraw)
{
HWND controlWindow;
RECT headerRect;
unsigned int windowStyle;
windowStyle = GetWindowLongPtr(hwnd, GWL_STYLE);
if(0 != (WS_VISIBLE & windowStyle))
SetWindowLongPtrW(hwnd, GWL_STYLE, windowStyle & ~WS_VISIBLE);
controlWindow = GetDlgItem(hwnd, 3);
if (NULL != controlWindow)
{
MLSkinnedHeader_SetHeight(controlWindow, -1);
if (FALSE == GetWindowRect(controlWindow, &headerRect))
SetRectEmpty(&headerRect);
}
else
SetRectEmpty(&headerRect);
controlWindow = GetDlgItem(hwnd, 2);
if (NULL != controlWindow)
{
RECT rect;
if (FALSE != GetClientRect(hwnd, &rect))
{
SetWindowPos(controlWindow, NULL,
rect.left, rect.top + headerRect.bottom - headerRect.top,
rect.right - rect.left, (rect.bottom - rect.top) - (headerRect.bottom - headerRect.top),
SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOREDRAW | SWP_NOCOPYBITS);
}
}
if (0 != (WS_VISIBLE & windowStyle))
{
windowStyle = GetWindowLongPtr(hwnd, GWL_STYLE);
if (0 == (WS_VISIBLE & windowStyle))
{
windowStyle |= WS_VISIBLE;
SetWindowLongPtrW(hwnd, GWL_STYLE, windowStyle);
}
if (FALSE != redraw)
RedrawWindow(hwnd, NULL, NULL, RDW_INVALIDATE | RDW_ERASE | RDW_ALLCHILDREN);
}
}
static HHOOK hook = NULL;
static HWND hwndToMonitor = NULL;
typedef struct UpdateSelection
{
BOOL active;
int iFrom;
int iTo;
}UpdateSelection;
typedef struct ListViewData
{
WNDPROC prevWindowProc;
UpdateSelection updateSelection;
} ListViewData;
#define LVCWP_NORMAL 0
#define LVCWP_UPDATESCROLLINFO (1 << 0)
static LRESULT CALLBACK HookProc(int nCode, WPARAM wParam, LPARAM lParam)
{
MSG *pMsg = (MSG*)lParam;
if (pMsg->hwnd == hwndToMonitor)
{
switch(pMsg->message)
{
case WM_LBUTTONUP:
case WM_RBUTTONUP:
{
LRESULT result = CallNextHookEx(hook, nCode, wParam, lParam);
UnhookWindowsHookEx(hook);
hwndToMonitor = NULL;
hook = NULL;
return result;
}
case WM_MOUSEMOVE:
if ((MK_LBUTTON | MK_RBUTTON) & pMsg->wParam)
{
RECT rw;
POINTS pts(MAKEPOINTS(pMsg->lParam));
POINT pt;
POINTSTOPOINT(pt, pts);
MapWindowPoints(pMsg->hwnd, HWND_DESKTOP, &pt, 1);
GetWindowRect(pMsg->hwnd, &rw);
if (pt.y < rw.top || pt.y > rw.bottom)
{
HWND hwndParent = GetParent(pMsg->hwnd);
if (hwndParent)
{
SCROLLINFO si;
si.cbSize = sizeof(SCROLLINFO);
si.fMask = SIF_RANGE | SIF_POS | SIF_PAGE;
if (GetScrollInfo(hwndParent, SB_VERT, &si))
{
if ((si.nPos > si.nMin && pt.y < rw.top) || (si.nPos < (si.nMax - (INT)si.nPage) && pt.y > rw.bottom))
{
SendMessageW(hwndParent, WM_SETREDRAW, FALSE, 0L);
LRESULT result = CallNextHookEx(hook, nCode, wParam, lParam);
PostMessageW(hwndParent, WM_EX_UPDATESCROLLINFO, SIF_POS, FALSE);
PostMessageW(hwndParent, WM_EX_UNLOCKREDRAW, IWF_CONTAINER | IWF_LISTVIEW | IWF_UPDATENOW, 0L);
return result;
}
}
}
}
SleepEx(1, TRUE);
}
break;
}
}
return CallNextHookEx(hook, nCode, wParam, lParam);
}
static void
ListView_ScheduleSelectionUpdate(HWND hwnd, int iFrom, int iTo)
{
ListViewData *listView;
listView = (ListViewData*)(LONG_PTR)GetWindowLongPtrW(hwnd, GWLP_USERDATA);
if (NULL == listView)
return;
listView->updateSelection.iFrom = iFrom;
listView->updateSelection.iTo = iTo;
listView->updateSelection.active = TRUE;
}
static void
ListView_UpdateSelection(HWND hwnd, int iFrom, int iTo)
{
HWND parentWindow;
LVITEM item;
int start, stop, i, lim;
start = (int)SendMessageW(hwnd, LVM_GETSELECTIONMARK, 0, 0L);
stop = (int)SendMessageW(hwnd, LVM_GETNEXTITEM, iFrom - 1, LVNI_FOCUSED);
if (stop < start)
{
int tmp = start;
start = stop;
stop = tmp;
}
item.state = 0;
item.stateMask = LVIS_SELECTED;
if (start != iFrom)
{
if (start < iFrom)
{
i = start;
lim = iFrom;
}
else
{
i = iFrom;
lim = start;
}
i--;
for(;;)
{
i = (int)SendMessageW(hwnd, LVM_GETNEXTITEM, (WPARAM)i,
(LPARAM)(LVNI_ALL | LVNI_SELECTED));
if (-1 == i || i >= lim)
break;
SendMessageW(hwnd, LVM_SETITEMSTATE, i, (LPARAM)&item);
}
}
if (stop < iTo)
{
i = stop + 1;
lim = iTo;
i--;
for(;;)
{
i = (int)SendMessageW(hwnd, LVM_GETNEXTITEM, (WPARAM)i,
(LPARAM)(LVNI_ALL | LVNI_SELECTED));
if (-1 == i || i > lim)
break;
SendMessageW(hwnd, LVM_SETITEMSTATE, i, (LPARAM)&item);
}
}
parentWindow = GetAncestor(hwnd, GA_PARENT);
if (NULL != parentWindow)
{
HWND notifyWindow;
SendMessageW(parentWindow, WM_SETREDRAW, TRUE, 0L);
RedrawWindow(parentWindow, NULL, NULL, RDW_INVALIDATE | RDW_ALLCHILDREN);
notifyWindow = GetAncestor(parentWindow, GA_PARENT);
if (NULL != notifyWindow)
{
NMLVODSTATECHANGE stateChange;
stateChange.hdr.idFrom = GetWindowLongPtrW(parentWindow, GWLP_ID);
stateChange.hdr.hwndFrom = parentWindow;
stateChange.hdr.code = LVN_ODSTATECHANGED;
stateChange.iFrom = start;
stateChange.iTo = stop;
stateChange.uNewState = LVIS_SELECTED;
stateChange.uOldState = 0;
SendMessageW(notifyWindow, WM_NOTIFY, stateChange.hdr.idFrom, (LPARAM)&stateChange);
}
}
}
static LRESULT
ListView_CallWindowProc(ListViewData *listView, HWND hwnd, unsigned int uMsg, WPARAM wParam, LPARAM lParam,
unsigned int flags)
{
LRESULT result;
result = CallWindowProcW(listView->prevWindowProc, hwnd, uMsg, wParam, lParam);
if (FALSE != listView->updateSelection.active)
{
listView->updateSelection.active = FALSE;
ListView_UpdateSelection(hwnd, listView->updateSelection.iFrom, listView->updateSelection.iTo);
}
if (0 != (LVCWP_UPDATESCROLLINFO & flags))
{
HWND hwndParent;
hwndParent = GetAncestor(hwnd, GA_PARENT);
if (NULL != hwndParent)
UpdateScrollInfo(hwndParent, SIF_POS, TRUE);
}
return result;
}
static LRESULT WINAPI
ListView_WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
ListViewData *listView;
listView = (ListViewData*)(LONG_PTR)GetWindowLongPtrW(hwnd, GWLP_USERDATA);
if (NULL == listView ||
NULL == listView->prevWindowProc)
{
return DefWindowProcW(hwnd, uMsg, wParam, lParam);
}
switch(uMsg)
{
case WM_DESTROY:
SetWindowLongPtrW(hwnd, GWLP_USERDATA, NULL);
CallWindowProcW(listView->prevWindowProc, hwnd, uMsg, wParam, lParam);
free(listView);
return 0;
case WM_KEYDOWN:
switch(wParam)
{
case VK_PRIOR:
case VK_UP:
case VK_HOME:
case VK_NEXT:
case VK_END:
case VK_DOWN:
case VK_LEFT:
case VK_RIGHT:
return ListView_CallWindowProc(listView, hwnd, uMsg, wParam, lParam, LVCWP_UPDATESCROLLINFO);
}
break;
case WM_TIMER:
if (43 == wParam)
return ListView_CallWindowProc(listView, hwnd, uMsg, wParam, lParam, LVCWP_UPDATESCROLLINFO);
break;
case WM_HSCROLL:
case WM_VSCROLL:
case WM_MOUSEWHEEL:
case LVM_ENSUREVISIBLE:
return ListView_CallWindowProc(listView, hwnd, uMsg, wParam, lParam, LVCWP_UPDATESCROLLINFO);
case WM_LBUTTONDOWN:
case WM_RBUTTONDOWN:
{
LVHITTESTINFO ht;
ht.pt.x = GET_X_LPARAM(lParam);
ht.pt.y = GET_Y_LPARAM(lParam);
if (-1 == SendMessageW(hwnd, LVM_HITTEST, 0, (LPARAM)&ht) || 0 == (LVHT_ONITEM & ht.flags))
{
hwndToMonitor = hwnd;
hook = SetWindowsHookEx(WH_MSGFILTER, HookProc, NULL, GetCurrentThreadId());
}
}
break;
}
return ListView_CallWindowProc(listView, hwnd, uMsg, wParam, lParam, LVCWP_NORMAL);
}
static LRESULT
HeaderIconList_OnCreate(HWND hwnd, CREATESTRUCT *createStruct)
{
HWND hwndList, hwndHeader;
MLSKINWINDOW m;
RECT rc;
DWORD style;
m.skinType = SKINNEDWND_TYPE_SCROLLWND;
m.style = SWS_USESKINFONT | SWS_USESKINCOLORS | SWS_USESKINCURSORS;
m.hwndToSkin = hwnd;
MLSkinWindow(g_hwnd, &m);
SetScrollRange(hwnd, SB_VERT, 0, 0, FALSE);
MLSkinnedScrollWnd_UpdateBars(hwnd, FALSE);
GetClientRect(hwnd, &rc);
style = WS_CLIPSIBLINGS | WS_CHILD | WS_VISIBLE | HDS_BUTTONS | HDS_FULLDRAG;
hwndHeader = CreateWindowExW(WS_EX_NOPARENTNOTIFY, WC_HEADERW, L"", style, 0, 0, rc.right - rc.left, 20, hwnd, (HMENU)3,0,0);
if (NULL != hwndHeader)
{
m.hwndToSkin = hwndHeader;
m.skinType = SKINNEDWND_TYPE_HEADER;
m.style = SWS_USESKINFONT | SWS_USESKINCOLORS | SWS_USESKINCURSORS;
MLSkinWindow(g_hwnd, &m);
}
style = WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_CHILD | WS_TABSTOP | WS_VISIBLE |
LVS_ICON | LVS_SHOWSELALWAYS | LVS_OWNERDATA | LVS_NOLABELWRAP;
hwndList = CreateWindowExW(WS_EX_NOPARENTNOTIFY, WC_LISTVIEWW,L"",style,0, 20, rc.right - rc.left, rc.bottom - rc.top - 20, hwnd,(HMENU)2,0,0);
if (NULL != hwndList)
{
ListViewData *listView;
listView = (ListViewData*)calloc(1, sizeof(ListViewData));
if (NULL != listView)
{
listView->prevWindowProc = (WNDPROC)(LONG_PTR)SetWindowLongPtrW(hwndList, GWLP_WNDPROC, (LONGX86)(LONG_PTR)ListView_WindowProc);
SetWindowLongPtrW(hwndList,GWLP_USERDATA, (LONGX86)(LONG_PTR)listView);
}
SendMessageW(hwndList, LVM_SETEXTENDEDLISTVIEWSTYLE, LVS_EX_INFOTIP, LVS_EX_INFOTIP);
if (NULL != hwndHeader)
SetWindowPos(hwndHeader, hwndList, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
m.skinType = SKINNEDWND_TYPE_LISTVIEW;
m.hwndToSkin = hwndList;
m.style = SWS_USESKINFONT | SWS_USESKINCOLORS | SWS_USESKINCURSORS | SWLVS_FULLROWSELECT | SWLVS_DOUBLEBUFFER;
MLSkinWindow(g_hwnd, &m);
MLSkinnedScrollWnd_SetMode(hwndList, SCROLLMODE_STANDARD);
MLSkinnedScrollWnd_ShowHorzBar(hwndList, FALSE);
MLSkinnedScrollWnd_ShowVertBar(hwndList, FALSE);
}
UpdateFontMetrics(hwnd, FALSE);
return 0;
}
static void
HeaderIconList_OnDestroy(HWND hwnd)
{
}
// TODO need to finish off the butting up to edge handling
static void
HeaderIconList_OnWindowPosChanged(HWND hwnd, WINDOWPOS *windowPos)
{
RECT rc;
HWND hwndHeader, hwndList;
hwndHeader = GetDlgItem(hwnd, 3);
hwndList = GetDlgItem(hwnd, 2);
BOOL bRedraw;
bRedraw = (0 == (SWP_NOREDRAW & windowPos->flags));
if ((SWP_NOSIZE | SWP_NOMOVE) == ((SWP_NOSIZE | SWP_NOMOVE | SWP_FRAMECHANGED) & windowPos->flags))
return;
hwndHeader = GetDlgItem(hwnd, 3);
hwndList = GetDlgItem(hwnd, 2);
if (hwndHeader && hwndList)
{
HDLAYOUT headerLayout;
WINDOWPOS headerPos;
GetClientRect(hwnd, &rc);
/*SCROLLINFO si;
si.cbSize= sizeof(SCROLLINFO);
si.fMask = SIF_RANGE | SIF_PAGE | SIF_POS;
BOOL got = GetScrollInfo(hwnd, SB_VERT, &si);
BOOL bScrollVisible = (si.nMax > 0 && si.nPage > 0 && (INT)si.nPage <= si.nMax);*/
headerLayout.prc = &rc;
headerLayout.pwpos = &headerPos;
if (FALSE != SendMessageW(hwndHeader, HDM_LAYOUT, 0, (LPARAM)&headerLayout))
{
headerPos.flags |= ((SWP_NOREDRAW | SWP_NOCOPYBITS) & windowPos->flags);
SetWindowPos(hwndHeader, headerPos.hwndInsertAfter, headerPos.x, headerPos.y,
headerPos.cx, headerPos.cy, headerPos.flags);
}
SetWindowPos(hwndList, NULL, rc.left, rc.top, rc.right - rc.left/* + (bScrollVisible ? 16 : 0)*/, rc.bottom - rc.top,
SWP_NOMOVE | SWP_NOOWNERZORDER | SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOREDRAW | SWP_NOCOPYBITS);
UpdateScrollInfo(hwnd, SIF_RANGE | SIF_POS, bRedraw);
}
NMHDR hdr;
hdr.code = LVN_EX_SIZECHANGED;
hdr.hwndFrom = hwnd;
hdr.idFrom = GetWindowLongPtrW(hwnd,GWLP_ID);
SendMessageW(GetParent(hwnd), WM_NOTIFY, hdr.idFrom, (LPARAM)&hdr);
}
static void
HeaderIconList_OnVertScroll(HWND hwnd, INT actionLayout, INT trackPosition, HWND scrollBar)
{
SCROLLINFO si={sizeof(si),SIF_TRACKPOS | SIF_POS | SIF_RANGE | SIF_PAGE,0};
if (GetScrollInfo(hwnd,SB_VERT,&si))
{
int pos(0), itemHeight;
BOOL bRedraw(TRUE);
HWND hwndList;
hwndList = GetDlgItem(hwnd, 2);
if (!hwndList)
return;
itemHeight = HIWORD(SendMessageW(hwndList, LVM_GETITEMSPACING, 0, 0L));
if (si.nPos > (si.nMax - (INT)si.nPage))
si.nPos = si.nMax - si.nPage;
switch(actionLayout)
{
case SB_TOP: pos = si.nMin; break;
case SB_BOTTOM: pos = si.nMax; break;
case SB_LINEDOWN: pos = si.nPos + itemHeight/2; break;
case SB_LINEUP: pos = si.nPos - itemHeight/2; break;
case SB_PAGEDOWN: pos = si.nPos + si.nPage - (((INT)si.nPage > itemHeight && 0 == ((INT)si.nPage%itemHeight)) ? itemHeight : 0);break;
case SB_PAGEUP: pos = si.nPos - si.nPage - (((INT)si.nPage > itemHeight && 0 == ((INT)si.nPage%itemHeight)) ? itemHeight : 0);break;
case SB_THUMBPOSITION:
case SB_THUMBTRACK:
{
POINT pt;
if (!SendMessageW(hwndList, LVM_GETORIGIN, 0, (LPARAM)&pt))
return;
si.nPos = pt.y;
pos = si.nTrackPos;
bRedraw = FALSE;
}
break;
case SB_ENDSCROLL: MLSkinnedScrollWnd_UpdateBars(hwnd, TRUE); return;
default: pos = si.nPos;
}
if (pos < si.nMin) pos = si.nMin;
if (pos > (si.nMax - (INT)si.nPage)) pos = si.nMax - si.nPage;
if (pos != si.nPos)
{
BOOL br;
if (!bRedraw)
{
UpdateWindow(GetDlgItem(hwnd, 3));
UpdateWindow(hwnd);
SendMessageW(hwnd, WM_SETREDRAW, FALSE, 0L);
}
br = (BOOL)SendMessageW(hwndList, LVM_SCROLL, 0, pos - si.nPos);
if (!bRedraw) SendMessageW(hwnd, WM_SETREDRAW, TRUE, 0L);
if (br)
{
si.fMask = SIF_POS;
si.nPos = pos;
SetScrollInfo(hwnd, SB_VERT, &si, FALSE);
if (!bRedraw)
InvalidateRect(hwndList, NULL, TRUE);
}
}
}
}
static void
HeaderIconList_OnSetFont(HWND hwnd, HFONT font, BOOL redraw)
{
if (0 == (SWS_USESKINFONT & MLSkinnedWnd_GetStyle(hwnd)))
{
HWND controlWindow;
controlWindow = GetDlgItem(hwnd,3);
if (NULL != controlWindow)
SendMessageW(controlWindow, WM_SETFONT, (WPARAM)font, MAKELPARAM(0, 0L));
controlWindow = GetDlgItem(hwnd,2);
if (NULL != controlWindow)
SendMessageW(controlWindow, WM_SETFONT, (WPARAM)font, MAKELPARAM(0, 0L));
UpdateFontMetrics(hwnd, redraw);
}
}
static LRESULT
HeaderIconList_OnGetFont(HWND hwnd)
{
HWND listWindow;
listWindow = GetDlgItem(hwnd, 2);
if (NULL != listWindow)
return SendMessageW(listWindow, WM_GETFONT, 0, 0L);
return DefWindowProcW(hwnd, WM_GETFONT, 0, 0L);
}
static void
HeaderIconList_OnSetRedraw(HWND hwnd, BOOL enableRedraw)
{
HWND childWindow;
DefWindowProcW(hwnd, WM_SETREDRAW, enableRedraw, 0L);
childWindow = GetDlgItem(hwnd, 3);
if (NULL != childWindow)
{
SendMessage(childWindow, WM_SETREDRAW, enableRedraw, 0L);
if (FALSE != enableRedraw)
InvalidateRect(childWindow, NULL, TRUE);
}
childWindow = GetDlgItem(hwnd, 2);
if (NULL != childWindow)
{
SendMessage(childWindow, WM_SETREDRAW, enableRedraw, 0L);
if (FALSE != enableRedraw)
InvalidateRect(childWindow, NULL, TRUE);
}
}
static void
HeaderIconList_OnSkinUpdated(HWND hwnd, BOOL notifyChildren, BOOL redraw)
{
UpdateFontMetrics(hwnd, redraw);
}
static LRESULT
HeaderIconList_OnDisplaySort(HWND hwnd, int sortIndex, BOOL ascendingOrder)
{
HWND headerWindow;
headerWindow = GetDlgItem(hwnd, 3);
if (NULL == headerWindow)
return 0;
return SENDMLIPC(headerWindow, ML_IPC_SKINNEDHEADER_DISPLAYSORT, MAKEWPARAM(sortIndex, ascendingOrder));
}
static LRESULT
HeaderIconList_OnGetSort(HWND hwnd)
{
HWND headerWindow;
headerWindow = GetDlgItem(hwnd, 3);
if (NULL == headerWindow)
return 0;
return SENDMLIPC(headerWindow, ML_IPC_SKINNEDHEADER_GETSORT, 0);
}
static LRESULT
HeaderIconList_OnMediaLibraryIPC(HWND hwnd, INT msg, INT_PTR param)
{
switch(msg)
{
case ML_IPC_SKINNEDWND_SKINUPDATED: HeaderIconList_OnSkinUpdated(hwnd, LOWORD(param), HIWORD(param)); break;
case ML_IPC_SKINNEDLISTVIEW_DISPLAYSORT: return HeaderIconList_OnDisplaySort(hwnd, LOWORD(param), HIWORD(param));
case ML_IPC_SKINNEDLISTVIEW_GETSORT: return HeaderIconList_OnGetSort(hwnd);
}
return 0;
}
static LRESULT CALLBACK HeaderIconList(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
switch(uMsg)
{
case WM_CREATE: return HeaderIconList_OnCreate(hwnd, (CREATESTRUCT*)lParam);
case WM_DESTROY: HeaderIconList_OnDestroy(hwnd); return 0;
case WM_WINDOWPOSCHANGED: HeaderIconList_OnWindowPosChanged(hwnd, (WINDOWPOS*)lParam); return 0;
case WM_VSCROLL: HeaderIconList_OnVertScroll(hwnd, LOWORD(wParam), (short)HIWORD(wParam), (HWND)lParam); return 0;
case WM_ERASEBKGND: return 1;
case WM_SETFONT: HeaderIconList_OnSetFont(hwnd, (HFONT)wParam, LOWORD(lParam)); return 0;
case WM_GETFONT: return HeaderIconList_OnGetFont(hwnd);
case WM_SETREDRAW: HeaderIconList_OnSetRedraw(hwnd, (BOOL)wParam); return 0;
case WM_TIMER:
if (43 == wParam)
{
KillTimer(hwnd, 43);
PostMessageW(hwnd, WM_EX_UPDATESCROLLINFO, SIF_POS, FALSE);
PostMessageW(hwnd, WM_EX_UNLOCKREDRAW, IWF_CONTAINER | IWF_LISTVIEW | IWF_UPDATENOW, 0L);
}
break;
case WM_EX_UPDATESCROLLINFO:
return UpdateScrollInfo(hwnd, (UINT)wParam, (BOOL)lParam);
case WM_EX_UNLOCKREDRAW:
SendMessageW(hwnd, WM_SETREDRAW, TRUE, 0L);
if (IWF_CONTAINER & wParam) { InvalidateRect(hwnd, NULL, FALSE); if (IWF_UPDATENOW & wParam) UpdateWindow(hwnd); }
if (IWF_LISTVIEW & wParam)
{
HWND hwndList = GetDlgItem(hwnd, 2);
if(hwndList) { InvalidateRect(hwndList, NULL, TRUE); if (IWF_UPDATENOW & wParam) UpdateWindow(hwndList); }
}
if (IWF_HEADER & wParam)
{
HWND hwndHeader = GetDlgItem(hwnd, 3);
if(hwndHeader) { InvalidateRect(hwndHeader, NULL, TRUE); if (IWF_UPDATENOW & wParam) UpdateWindow(hwndHeader); }
}
break;
case LVM_GETHEADER:
return (LRESULT)GetDlgItem(hwnd,3);
case LVM_DELETECOLUMN:
{
HWND headerWindow;
headerWindow = GetDlgItem(hwnd,3);
if (NULL != headerWindow)
return SendMessageW(headerWindow, HDM_DELETEITEM, wParam, 0L);
}
return FALSE;
case LVM_GETCOLUMNWIDTH:
{
HWND headerWindow;
headerWindow = GetDlgItem(hwnd,3);
if (NULL != headerWindow)
{
HDITEMW headerItem;
headerItem.mask = HDI_WIDTH;
if (FALSE != SendMessageW(headerWindow, HDM_GETITEM, wParam, (LPARAM)&headerItem))
return headerItem.cxy;
}
}
return 0;
case LVM_INSERTCOLUMNA:
case LVM_INSERTCOLUMNW:
{
LVCOLUMNW *listColumn = (LVCOLUMNW*)lParam;
HDITEMW headerItem;
HWND headerWindow;
headerWindow = GetDlgItem(hwnd,3);
if (NULL == headerWindow)
return -1;
if (FALSE == CopyListColumnToHeaderItem(listColumn, &headerItem))
return -1;
if (0 == (HDI_FORMAT & headerItem.mask))
{
headerItem.mask |= HDI_FORMAT;
headerItem.fmt = HDF_LEFT;
}
return SendMessageW(headerWindow,
(LVM_INSERTCOLUMNW == uMsg) ? HDM_INSERTITEMW : HDM_INSERTITEMA,
wParam, (LPARAM)&headerItem);
}
break;
case LVM_SETITEMCOUNT:
{
HWND hwndList = GetDlgItem(hwnd, 2);
if (hwndList)
{
LRESULT lr = ListView_WindowProc(hwndList, uMsg, wParam, lParam);
UpdateScrollInfo(hwnd, SIF_RANGE | SIF_POS, TRUE);
return lr;
}
}
break;
case LVM_GETCOLUMNW:
case LVM_GETCOLUMNA:
{
LVCOLUMNW *l = (LVCOLUMNW *)lParam;
HDITEMW h;
HWND headerWindow;
headerWindow = GetDlgItem(hwnd, 3);
if (NULL == headerWindow)
return FALSE;
if (FALSE == CopyListColumnToHeaderItem(l, &h))
return FALSE;
if(!SendMessageW(headerWindow,
(LVM_GETCOLUMNW == uMsg) ? HDM_GETITEMW : HDM_GETITEMA,
wParam,
(LPARAM)&h))
{
return FALSE;
}
if (FALSE == CopyHeaderItemToListColumn(&h, l))
return FALSE;
}
return TRUE;
case LVM_SETCOLUMNW:
case LVM_SETCOLUMNA:
{
LVCOLUMNW *l = (LVCOLUMNW *)lParam;
HDITEMW h;
HWND headerWindow;
headerWindow = GetDlgItem(hwnd, 3);
if (NULL == headerWindow)
return FALSE;
if (FALSE == CopyListColumnToHeaderItem(l, &h))
return FALSE;
if(!SendMessageW(headerWindow,
(LVM_SETCOLUMNW == uMsg) ? HDM_SETITEMW : HDM_SETITEMA,
wParam, (LPARAM)&h))
{
return FALSE;
}
if (FALSE == CopyHeaderItemToListColumn(&h, l))
return FALSE;
}
return TRUE;
case LVM_SETCOLUMNWIDTH:
{
HWND headerWindow;
HDITEMW headerItem;
headerWindow = GetDlgItem(hwnd, 3);
if (NULL == headerWindow)
return FALSE;
if (LVSCW_AUTOSIZE == lParam)
return FALSE;
if (LVSCW_AUTOSIZE_USEHEADER == lParam)
return FALSE;
headerItem.mask = HDI_WIDTH;
headerItem.cxy = (int)lParam;
return SendMessageW(headerWindow, HDM_SETITEMW, (WPARAM)wParam, (LPARAM)&headerItem);
}
break;
case WM_NOTIFY:
{
BOOL bPost(FALSE);
LPNMHDR l=(LPNMHDR)lParam;
if(l->idFrom == 2)
{
switch(l->code)
{
case LVN_ODFINDITEMA:
case LVN_ODFINDITEMW:
bPost = TRUE;
break;
case LVN_ODSTATECHANGED:
{
NMLVODSTATECHANGE *stateChange;
stateChange = (NMLVODSTATECHANGE*)lParam;
if (0 != (LVIS_SELECTED & (stateChange->uNewState ^ stateChange->uOldState)))
{
SendMessageW(hwnd, WM_SETREDRAW, FALSE, 0L);
ListView_ScheduleSelectionUpdate(l->hwndFrom, stateChange->iFrom,stateChange->iTo);
}
return 0;
}
break;
}
l->idFrom = GetWindowLong(hwnd,GWL_ID);
l->hwndFrom = hwnd;
LRESULT lr = SendMessageW(GetParent(hwnd),uMsg,l->idFrom,lParam);
if (bPost)
{
UpdateWindow(GetDlgItem(hwnd, 3));
SendMessageW(hwnd, WM_SETREDRAW, FALSE, 0L);
PostMessageW(hwnd, WM_EX_UPDATESCROLLINFO, SIF_POS, TRUE);
PostMessageW(hwnd, WM_EX_UNLOCKREDRAW, IWF_CONTAINER | IWF_LISTVIEW, 0L);
}
return lr;
}
else if(l->idFrom == 3) {
switch(l->code) {
case HDN_ITEMCLICKA:
case HDN_ITEMCLICKW:
{
NMHEADER *nm = (NMHEADER*)lParam;
HWND hwndParent;
hwndParent = GetParent(hwnd);
if (hwndParent)
{
wParam = GetWindowLongPtrW(hwnd,GWLP_ID);
if(nm->iButton == 0) { // left click
NMLISTVIEW p = {{hwnd, wParam, LVN_COLUMNCLICK},-1,nm->iItem,0};
return SendMessageW(hwndParent,WM_NOTIFY,wParam,(LPARAM)&p);
} else if(nm->iButton == 1) { // right click
NMHDR p = {nm->hdr.hwndFrom,wParam,NM_RCLICK};
return SendMessageW(hwndParent,WM_NOTIFY,wParam,(LPARAM)&p);
}
}
}
break;
}
return SendMessageW(GetParent(hwnd),uMsg, wParam,lParam);
}
}
break;
case WM_EX_GETREALLIST:
return (LRESULT)GetDlgItem(hwnd, 2);
case WM_EX_GETCOUNTPERPAGE:
{
HWND hwndList;
RECT rc;
hwndList = GetDlgItem(hwnd, 2);
if (hwndList)
{
GetClientRect(hwndList, &rc);
OffsetRect(&rc, -rc.left, -rc.top);
DWORD spacing = (DWORD)SendMessageW(hwndList, LVM_GETITEMSPACING, 0, 0L);
if (LOWORD(spacing) && HIWORD(spacing))
{
return (rc.right/LOWORD(spacing)) * (rc.bottom /HIWORD(spacing) + ((rc.bottom%HIWORD(spacing)) ? 1 : 0));
}
}
}
return 0;
case WM_ML_IPC:
return HeaderIconList_OnMediaLibraryIPC(hwnd, (INT)lParam, (INT_PTR)wParam);
default:
if(uMsg >= LVM_FIRST && uMsg < LVM_FIRST + 0x100)
{
HWND hwndList = GetDlgItem(hwnd,2);
if (hwndList) return ListView_WindowProc(hwndList, uMsg, wParam, lParam);
}
break;
}
return DefWindowProcW(hwnd,uMsg,wParam,lParam);
}
void InitHeaderIconList() {
WNDCLASSW wc = {0, };
if (GetClassInfoW(plugin.hDllInstance, L"HeaderIconList", &wc)) return;
wc.style = CS_DBLCLKS;
wc.lpfnWndProc = HeaderIconList;
wc.hInstance = plugin.hDllInstance;
wc.lpszClassName = L"HeaderIconList";
RegisterClassW(&wc);
}