#include "main.h" #include "../Winamp/gen.h" #include "../gen_ml/ml.h" #include "../gen_ml/ml_ipc_0313.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_NORMAL 0x0000 #define IWF_ERASE 0x0001 #define IWF_UPDATENOW 0x0002 #define IWF_FRAME 0x0004 typedef enum ScrollPosFlags { SPF_NORMAL = 0, SPF_NOREDRAW = (1 << 0), SPF_FORCE = (1 << 1), SPF_RELATIVE = (1 << 2), } ScrollPosFlags; DEFINE_ENUM_FLAG_OPERATORS(ScrollPosFlags); BOOL CopyListColumnToHeaderItem(const LVCOLUMNW *column, HDITEMW *item); BOOL CopyHeaderItemToListColumn(const HDITEMW *item, LVCOLUMNW *column); typedef enum PostProcessKeyCommands { PostProcessKeyCmd_Nothing = 0, PostProcessKeyCmd_UpdateScrollPos = (1 << 0), PostProcessKeyCmd_EnsureFocusVisible = (1 << 1), } PostProcessKeyCommands; DEFINE_ENUM_FLAG_OPERATORS(PostProcessKeyCommands); typedef struct SmoothScrollList { unsigned int itemHeight; unsigned int textHeight; long viewHeight; unsigned int listFontHeight; unsigned int headerFontHeight; int wheelCarryover; } SmoothScrollList; #define GetUserData(hwnd) ((SmoothScrollList*)(LONG_PTR)GetWindowLongPtrW(hwnd, GWLP_USERDATA)) static LRESULT SubclassedListView_CallPrevWndProc(HWND hwnd, unsigned int message, WPARAM wParam, LPARAM lParam) { WNDPROC windowProc; windowProc = (WNDPROC)(LONG_PTR)GetWindowLongPtrW(hwnd,GWLP_USERDATA); if (NULL == windowProc) return DefWindowProcW(hwnd, message, wParam, lParam); return CallWindowProcW(windowProc, hwnd, message,wParam,lParam); } static BOOL GetViewRect(HWND hwnd, RECT *prc) { HWND headerWindow; GetClientRect(hwnd, prc); headerWindow = GetDlgItem(hwnd, 3); if (NULL != headerWindow) { RECT rh; GetWindowRect(headerWindow, &rh); MapWindowPoints(HWND_DESKTOP, headerWindow, ((POINT*)&rh) + 1, 1); prc->top = rh.bottom; } if (prc->right < prc->left) prc->right = prc->left; if (prc->bottom < prc->top) prc->bottom = prc->top; return TRUE; } static int SmoothScrollList_GetScrollPosFromItem(HWND hwnd, int iItem) { HWND listWindow; RECT listRect, viewRect; int pos; int count; pos = 0; if (FALSE == GetViewRect(hwnd, &viewRect)) return 0; listWindow = GetDlgItem(hwnd, 2); if (NULL == listWindow || FALSE == GetWindowRect(listWindow, &listRect)) { return 0; } MapWindowPoints(HWND_DESKTOP, hwnd, (POINT*)&listRect, 2); count = (int)SendMessageW(listWindow, LVM_GETITEMCOUNT, 0, 0L); if (0 != count) { SmoothScrollList *self; if (iItem < 0) iItem = 0; if (iItem >= count) iItem = count - 1; self = GetUserData(hwnd); if (NULL != self) pos = iItem * self->itemHeight; } pos += (viewRect.top - listRect.top); return pos; } static BOOL UpdateScrollInfo(HWND hwndView, UINT fFlags, BOOL bRedraw) { RECT rv; HWND hwndList; SCROLLINFO si; BOOL needUpdate; BOOL needRedraw; HRGN regionUpdate, regionTemp; SmoothScrollList* s = GetUserData(hwndView); hwndList = GetDlgItem(hwndView, 2); if (!s || !hwndList ) return FALSE; if (FALSE!= bRedraw) { GetWindowRect(hwndView, &rv); MapWindowPoints(HWND_DESKTOP, hwndView, (POINT*)&rv, 2); regionUpdate = CreateRectRgnIndirect(&rv); GetClientRect(hwndView, &rv); regionTemp = CreateRectRgnIndirect(&rv); CombineRgn(regionUpdate, regionUpdate, regionTemp, RGN_DIFF); } else { regionUpdate = NULL; regionTemp = NULL; } si.cbSize = sizeof(SCROLLINFO); si.fMask = SIF_RANGE | SIF_PAGE | SIF_POS; if (!GetScrollInfo(hwndView, SB_VERT, &si)) return FALSE; if (FALSE == GetViewRect(hwndView, &rv)) SetRectEmpty(&rv); needUpdate = FALSE; needRedraw = FALSE; if (SIF_RANGE & fFlags) { unsigned int count, nPage, nMax; nPage = rv.bottom - rv.top; count = (INT)SendMessageW(hwndList, LVM_GETITEMCOUNT, 0, 0L); nMax = count * s->itemHeight; if (si.nPage != nPage || si.nMax != nMax) { BOOL forcePos; unsigned int windowStyle; si.fMask = SIF_PAGE | SIF_RANGE; si.nPage = nPage; si.nMax = nMax; windowStyle = GetWindowLongPtrW(hwndView, GWL_STYLE); SetScrollInfo(hwndView, SB_VERT, &si, FALSE); needUpdate = TRUE; needRedraw = FALSE; forcePos = FALSE; if (nPage >= nMax && 0 != (WS_VSCROLL & windowStyle)) { SetWindowLongPtrW(hwndView, GWL_STYLE, windowStyle & ~WS_VSCROLL); RECT rc; HWND hwndHeader; // MLSkinnedScrollWnd_UpdateBars(hwndView, bRedraw); GetClientRect(hwndView, &rc); hwndHeader = GetDlgItem(hwndView, 3); if (hwndHeader) { HDLAYOUT headerLayout; WINDOWPOS headerPos; headerLayout.prc = &rc; headerLayout.pwpos = &headerPos; if (FALSE != SendMessageW(hwndHeader, HDM_LAYOUT, 0, (LPARAM)&headerLayout)) { headerPos.flags |= SWP_NOREDRAW | SWP_NOCOPYBITS; headerPos.flags &= ~SWP_NOZORDER; headerPos.hwndInsertAfter = HWND_TOP; SetWindowPos(hwndHeader, headerPos.hwndInsertAfter, headerPos.x, headerPos.y, headerPos.cx, headerPos.cy, headerPos.flags); InvalidateRect(hwndHeader, NULL, FALSE); } } rv.right = rc.right; forcePos = TRUE; needUpdate = FALSE; needRedraw = TRUE; } if (nPage >= nMax || forcePos) { RECT rl; GetWindowRect(hwndList, &rl); MapWindowPoints(HWND_DESKTOP, hwndView, (POINT*)&rl, 2); if (rv.top != rl.top || forcePos) { SetWindowPos(hwndList, NULL, rv.left, rv.top, rv.right - rv.left, rv.bottom - rv.top, SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOREDRAW | SWP_NOCOPYBITS); needRedraw = TRUE; } } } } if (SIF_POS & fFlags) { INT nTop; nTop = (INT)SendMessageW(hwndList, LVM_GETTOPINDEX, 0, 0L); nTop = SmoothScrollList_GetScrollPosFromItem(hwndView, nTop); if(si.nMax > 0) { if (nTop >= (si.nMax - (int)si.nPage)) nTop = (si.nMax - si.nPage) + 1; } else nTop = 0; if (nTop < si.nMin) nTop = si.nMin; if (si.nPos != nTop) { si.fMask = SIF_POS; si.nPos = nTop; SetScrollInfo(hwndView, SB_VERT, &si, (FALSE == needRedraw && FALSE != bRedraw)); needUpdate = TRUE; } } if (FALSE != needUpdate) MLSkinnedScrollWnd_UpdateBars(hwndView, (FALSE == needRedraw && FALSE != bRedraw)); if (FALSE != bRedraw && FALSE != needRedraw) { HRGN regionTemp2; GetWindowRect(hwndView, &rv); MapWindowPoints(HWND_DESKTOP, hwndView, (POINT*)&rv, 2); SetRectRgn(regionTemp, rv.left, rv.top, rv.right, rv.bottom); GetClientRect(hwndView, &rv); regionTemp2 = CreateRectRgnIndirect(&rv); CombineRgn(regionTemp, regionTemp, regionTemp2, RGN_DIFF); CombineRgn(regionUpdate, regionUpdate, regionTemp, RGN_OR); DeleteObject(regionTemp2); RedrawWindow(hwndView, NULL, regionUpdate, RDW_INVALIDATE | RDW_ALLCHILDREN | RDW_FRAME); } if (NULL != regionUpdate) DeleteObject(regionUpdate); if (NULL != regionTemp) DeleteObject(regionTemp); return TRUE; } static BOOL SmoothScrollList_SetScrollPos(HWND hwnd, int position, ScrollPosFlags flags) { SmoothScrollList *self; HWND listWindow; BOOL invalidate, failed; unsigned long viewStyle; int y, scrollPos; RECT rv, rl; SCROLLINFO si; listWindow = GetDlgItem(hwnd, 2); if (NULL == listWindow) return FALSE; self = GetUserData(hwnd); if (NULL == self) return FALSE; si.cbSize = sizeof(si); si.fMask = SIF_POS | SIF_RANGE | SIF_PAGE; if (FALSE == GetScrollInfo(hwnd, SB_VERT, &si)) return FALSE; scrollPos = si.nPos; viewStyle = GetWindowLongPtrW(hwnd, GWL_STYLE); invalidate = FALSE; failed = FALSE; y = 0; if (0 != (SPF_RELATIVE & flags)) { position = si.nPos + position; if (si.nPos > (si.nMax - (int)si.nPage)) position -= (si.nPos - (si.nMax - (int)si.nPage)); } if (position < si.nMin) position = si.nMin; if (position > (si.nMax - (INT)si.nPage + 1)) position = si.nMax - si.nPage + 1; if (position == si.nPos && 0 == (SPF_FORCE & flags)) return TRUE; if (FALSE == GetViewRect(hwnd, &rv)) SetRectEmpty(&rv); if (FALSE == GetWindowRect(listWindow, &rl)) SetRectEmpty(&rl); MapWindowPoints(HWND_DESKTOP, hwnd, (POINT*)&rl, 2); if (0 != (WS_VISIBLE & viewStyle)) SetWindowLongPtrW(hwnd, GWL_STYLE, viewStyle & ~WS_VISIBLE); if (si.nMin == position) { if (rl.top != rv.top || rl.bottom != rv.bottom || rl.left != rv.left || rl.right != rv.right) { SetWindowPos(listWindow, NULL, rv.left, rv.top, rv.right - rv.left, rv.bottom - rv.top, SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOREDRAW | SWP_NOCOPYBITS); invalidate = TRUE; } if (0 != (int)SendMessageW(listWindow, LVM_GETITEMCOUNT, 0, 0L)) { RECT rect; rect.left = LVIR_BOUNDS; if (FALSE != SendMessageW(listWindow, LVM_GETITEMRECT, 0, (LPARAM)&rect) && 0 != rect.top) { int scrollY; scrollY = rect.top; failed = !SendMessageW(listWindow, LVM_SCROLL, 0, scrollY); invalidate = TRUE; } } } else { int iTop, iPos; iTop = (int)SendMessageW(listWindow, LVM_GETTOPINDEX, 0, 0L); if (position > (si.nMax - (int)si.nPage)) position = (si.nMax - si.nPage); iPos = position/self->itemHeight; y = (position - iPos*self->itemHeight); if (iTop > iPos) { failed = !SendMessageW(listWindow, LVM_SCROLL, 0, (iPos - iTop) * self->itemHeight); invalidate = TRUE; } if (rl.top != rv.top + y || rl.bottom != rv.bottom || rl.left != rv.left || rl.right != rv.right) { SetWindowPos(listWindow, NULL, rv.left, rv.top - y, rv.right - rv.left, rv.bottom - rv.top + y, SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOREDRAW | SWP_NOCOPYBITS); invalidate = TRUE; } if (iTop < iPos) { failed = !SendMessageW(listWindow, LVM_SCROLL, 0, (iPos - iTop)*self->itemHeight); invalidate = TRUE; } } if (FALSE == failed) { if (position == si.nMax - si.nPage && 0 != si.nMax) position++; if (scrollPos != position) { si.nPos = position; si.fMask = SIF_POS; SetScrollInfo(hwnd, SB_VERT, &si, (0 == (SPF_NOREDRAW & flags))); } } if (0 != (WS_VISIBLE & viewStyle)) { viewStyle = GetWindowLongPtrW(hwnd, GWL_STYLE); if (0 == (WS_VISIBLE & viewStyle)) { viewStyle |= WS_VISIBLE; SetWindowLongPtrW(hwnd, GWL_STYLE, viewStyle); } if (0 == (SPF_NOREDRAW & flags) && FALSE != invalidate) { InvalidateRect(listWindow, NULL, TRUE); } } return TRUE; } static BOOL SmoothScrollList_EnsureVisible(HWND hwnd, int iItem, BOOL partialOk) { int itemTop, itemBottom; int pageTop, pageBottom, delta; SCROLLINFO scrollInfo; SmoothScrollList *self; if (NULL == hwnd || iItem < 0) return FALSE; self = GetUserData(hwnd); if (NULL == self) return FALSE; scrollInfo.cbSize = sizeof(scrollInfo); scrollInfo.fMask = SIF_POS | SIF_PAGE; if (FALSE == GetScrollInfo(hwnd, SB_VERT, &scrollInfo)) return FALSE; itemTop = iItem * self->itemHeight; itemBottom = itemTop + self->itemHeight; pageTop = scrollInfo.nPos; pageBottom = pageTop + scrollInfo.nPage; if (FALSE != partialOk) { if (itemTop < pageBottom && itemBottom > pageTop) { return TRUE; } } else { if (itemTop >= pageTop && itemBottom <= pageBottom) { return TRUE; } } if (itemTop < pageTop) delta = itemTop - pageTop; else { delta = itemBottom - pageBottom; if ((itemTop - delta) < pageTop) delta = itemTop - pageTop; } if (FALSE == SmoothScrollList_SetScrollPos(hwnd, delta, SPF_RELATIVE | SPF_FORCE)) return FALSE; MLSkinnedScrollWnd_UpdateBars(hwnd, TRUE); return TRUE; } static BOOL SmoothScrollList_PreProcessKey(HWND hwnd, unsigned int vKey, unsigned int keyFlags, PostProcessKeyCommands *postProcessCommands) { HWND listWindow; RECT viewRect; SmoothScrollList *self; int iItem, iNextItem, count; BOOL shortView; if (NULL != postProcessCommands) *postProcessCommands = PostProcessKeyCmd_Nothing; switch(vKey) { case VK_UP: case VK_DOWN: case VK_HOME: case VK_END: case VK_PRIOR: case VK_NEXT: break; default: return TRUE; } if (NULL == hwnd || FALSE == GetViewRect(hwnd, &viewRect)) return FALSE; self = GetUserData(hwnd); if (NULL == self) return FALSE; listWindow = GetDlgItem(hwnd, 2); if (NULL == listWindow) return FALSE; iItem = (int)SendMessageW(listWindow, LVM_GETNEXTITEM, (WPARAM)-1, (LPARAM)(LVNI_ALL | LVNI_FOCUSED)); if (-1 == iItem) return FALSE; count = (int)SendMessageW(listWindow, LVM_GETITEMCOUNT, 0, 0L); iNextItem = iItem; shortView = ((viewRect.bottom - viewRect.top) < (long)self->itemHeight); switch(vKey) { case VK_UP: if (iNextItem > 0) iNextItem--; if (FALSE != shortView) { if (NULL != postProcessCommands) *postProcessCommands |= PostProcessKeyCmd_EnsureFocusVisible; } break; case VK_DOWN: if (FALSE == shortView) { if ((iNextItem + 1) < count) iNextItem++; } else { if (NULL != postProcessCommands) *postProcessCommands |= PostProcessKeyCmd_EnsureFocusVisible; } break; case VK_HOME: if (FALSE == shortView) { iNextItem = 0; } else { iNextItem = 1; if (NULL != postProcessCommands) *postProcessCommands |= PostProcessKeyCmd_UpdateScrollPos; } break; case VK_END: if (FALSE == shortView) { iNextItem = count - 1; } else { iNextItem = -1; if (NULL != postProcessCommands) *postProcessCommands |= PostProcessKeyCmd_EnsureFocusVisible; } break; case VK_PRIOR: { RECT listRect; GetWindowRect(listWindow, &listRect); MapWindowPoints(HWND_DESKTOP, hwnd, (POINT*)&listRect, 2); if (listRect.top != viewRect.top) SmoothScrollList_SetScrollPos(hwnd, listRect.top - viewRect.top, SPF_RELATIVE); if (FALSE == shortView) { iNextItem = (viewRect.bottom - viewRect.top)/self->itemHeight; iNextItem = iItem - iNextItem; if (iNextItem < 0) iNextItem = 0; } else { if (0 == iItem) iNextItem = 1; if (NULL != postProcessCommands) *postProcessCommands |= PostProcessKeyCmd_UpdateScrollPos; } } break; case VK_NEXT: { RECT listRect; int reminder; GetWindowRect(listWindow, &listRect); MapWindowPoints(HWND_DESKTOP, hwnd, (POINT*)&listRect, 2); reminder = (listRect.bottom - listRect.top)%self->itemHeight; if (0 != reminder) SmoothScrollList_SetScrollPos(hwnd, self->itemHeight - reminder, SPF_RELATIVE); if (FALSE == shortView) { iNextItem = (viewRect.bottom - viewRect.top)/self->itemHeight; iNextItem = iItem + iNextItem; if (iNextItem >= count) iNextItem = count - 1; } else { if (NULL != postProcessCommands) *postProcessCommands |= (PostProcessKeyCmd_UpdateScrollPos | PostProcessKeyCmd_EnsureFocusVisible); } } break; } if (iNextItem >= 0 && iNextItem < count) SmoothScrollList_EnsureVisible(hwnd, iNextItem, FALSE); return TRUE; } static void SmoothScrollList_PostProcessKey(HWND hwnd, unsigned int vKey, unsigned int keyFlags, PostProcessKeyCommands processCommands) { if (0 != (PostProcessKeyCmd_UpdateScrollPos & processCommands)) UpdateScrollInfo(hwnd, SIF_POS, TRUE); if (0 != (PostProcessKeyCmd_EnsureFocusVisible & processCommands)) { HWND listWindow = GetDlgItem(hwnd, 2); if (NULL != listWindow) { int iItem = (int)SendMessageW(listWindow, LVM_GETNEXTITEM, (WPARAM)-1, (LPARAM)(LVNI_ALL | LVNI_FOCUSED)); if (-1 != iItem) { SmoothScrollList_EnsureVisible(hwnd, iItem, FALSE); } } } } static void SmoothScrollList_UpdateFontMetrics(HWND hwnd, BOOL redraw) { SmoothScrollList *self; HWND controlWindow; unsigned int windowStyle; HFONT font, prevFont; HDC hdc; TEXTMETRICW textMetrics; unsigned int fontHeight; self = GetUserData(hwnd); if (NULL == self) return; windowStyle = GetWindowLongPtr(hwnd, GWL_STYLE); if(0 != (WS_VISIBLE & windowStyle)) SetWindowLongPtrW(hwnd, GWL_STYLE, windowStyle & ~WS_VISIBLE); hdc = GetDCEx(hwnd, NULL, DCX_CACHE | DCX_NORESETATTRS); if (NULL != hdc) prevFont = (HFONT)GetCurrentObject(hdc, OBJ_FONT); else prevFont = NULL; controlWindow = GetDlgItem(hwnd, 3); if (NULL != controlWindow) { font = (HFONT)SendMessageW(controlWindow, WM_GETFONT, 0, 0L); fontHeight = 0; if (NULL != hdc) { SelectObject(hdc, font); if (FALSE != GetTextMetricsW(hdc, &textMetrics)) fontHeight = textMetrics.tmHeight; } if (self->headerFontHeight != fontHeight) { self->headerFontHeight = fontHeight; MLSkinnedHeader_SetHeight(controlWindow, -1); } } controlWindow = GetDlgItem(hwnd, 2); if (NULL != controlWindow) { font = (HFONT)SendMessageW(controlWindow, WM_GETFONT, 0, 0L); fontHeight = 0; if (NULL != hdc) { SelectObject(hdc, font); if (FALSE != GetTextMetricsW(hdc, &textMetrics)) fontHeight = textMetrics.tmHeight; } if (self->listFontHeight != fontHeight) { self->listFontHeight = fontHeight; SmoothScrollList_SetScrollPos(hwnd, 0, SPF_NOREDRAW | SPF_FORCE); MLSkinnedScrollWnd_UpdateBars(hwnd, FALSE); } } if (NULL != hdc) { SelectObject(hdc, prevFont); ReleaseDC(hwnd, hdc); } 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_FRAME | RDW_ALLCHILDREN); } } static HHOOK hook = NULL; static HWND hwndToMonitor = NULL; static LRESULT CALLBACK HookProc(int nCode, WPARAM wParam, LPARAM lParam) { MSG *pMsg = (MSG*)lParam; if (pMsg->hwnd == hwndToMonitor) { static INT lastScrollPos = -1; switch(pMsg->message) { case WM_LBUTTONUP: case WM_RBUTTONUP: { LRESULT result = CallNextHookEx(hook, nCode, wParam, lParam); UnhookWindowsHookEx(hook); hwndToMonitor = NULL; hook = NULL; lastScrollPos = -1; 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)) { LRESULT result; if (lastScrollPos == si.nPos) { result = CallNextHookEx(hook, nCode, wParam, lParam); SmoothScrollList_SetScrollPos(hwndParent, (pt.y < rw.top) ? --si.nPos : ++si.nPos, SPF_NORMAL); } else { unsigned long windowStyle; windowStyle = GetWindowLongPtrW(hwndParent, GWL_STYLE); if (0 != (WS_VISIBLE & windowStyle)) SetWindowLongPtrW(hwndParent, GWL_STYLE, windowStyle & ~WS_VISIBLE); result = CallNextHookEx(hook, nCode, wParam, lParam); PostMessageW(hwndParent, WM_EX_UPDATESCROLLINFO, SIF_POS, TRUE); if (0 != (WS_VISIBLE & windowStyle)) PostMessageW(hwndParent, WM_EX_UNLOCKREDRAW, IWF_UPDATENOW | IWF_FRAME, 0L); } lastScrollPos = si.nPos; return result; } } } } SleepEx(1, TRUE); } break; } } return CallNextHookEx(hook, nCode, wParam, lParam); } static LRESULT CALLBACK ListViewSubclass(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { if(uMsg == WM_MOUSEMOVE || uMsg == WM_LBUTTONDOWN) { LVHITTESTINFO ht = {{LOWORD(lParam),HIWORD(lParam)},LVHT_ONITEM,-1,0}; int item = ListView_SubItemHitTest(hwnd, &ht); { RECT r={0}; ListView_GetItemRect(hwnd,item,&r,LVIR_BOUNDS); ht.pt.x -= r.left; ht.pt.y -= r.top; typedef struct { int x,y,item; HWND hwnd; UINT msg; } hitinfo; hitinfo info = { ht.pt.x, ht.pt.y, item, hwnd, uMsg, }; SendMessage(GetParent(GetParent(hwnd)),WM_USER+700,(WPARAM)&info,0); } } switch(uMsg) { case WM_HSCROLL: case WM_VSCROLL: case WM_MOUSEWHEEL: { HWND parentWindow; KillTimer(hwnd, 43); parentWindow = GetAncestor(hwnd, GA_PARENT); if (NULL != parentWindow) return SendMessageW(parentWindow, uMsg, wParam, lParam); } break; case WM_TIMER: if (43 == wParam) { HWND parentWindow; KillTimer(hwnd, wParam); parentWindow = GetAncestor(hwnd, GA_PARENT); if (NULL != parentWindow) { int iFocused = (int)SendMessageW(hwnd, LVM_GETNEXTITEM, (WPARAM)-1, (LPARAM)(LVNI_ALL | LVNI_FOCUSED)); if (-1 != iFocused) SmoothScrollList_EnsureVisible(parentWindow, iFocused, FALSE); return 0; } } break; case WM_LBUTTONDOWN: case WM_RBUTTONDOWN: case WM_MBUTTONDOWN: case WM_XBUTTONDOWN: hwndToMonitor = hwnd; hook = SetWindowsHookEx(WH_MSGFILTER, HookProc, NULL, GetCurrentThreadId()); { unsigned int windowStyle; windowStyle = GetWindowLongPtrW(hwnd, GWL_STYLE); if (0 != (LVS_OWNERDRAWFIXED & windowStyle)) { LRESULT result; SetWindowLongPtrW(hwnd, GWL_STYLE, windowStyle & ~LVS_OWNERDRAWFIXED); result = SubclassedListView_CallPrevWndProc(hwnd, uMsg, wParam, lParam); windowStyle = GetWindowLongPtrW(hwnd, GWL_STYLE); if (0 == (LVS_OWNERDRAWFIXED & windowStyle)) { windowStyle |= LVS_OWNERDRAWFIXED; SetWindowLongPtrW(hwnd, GWL_STYLE, windowStyle); } return result; } } break; case WM_KEYDOWN: { HWND parentWindow; parentWindow = GetAncestor(hwnd, GA_PARENT); if (NULL != parentWindow) { PostProcessKeyCommands postProcessKeyCommands; if (FALSE == SmoothScrollList_PreProcessKey(parentWindow, (unsigned int)wParam, (unsigned int)lParam, &postProcessKeyCommands)) { postProcessKeyCommands = PostProcessKeyCmd_UpdateScrollPos; } SubclassedListView_CallPrevWndProc(hwnd, uMsg, wParam, lParam); SmoothScrollList_PostProcessKey(parentWindow, (unsigned int)wParam, (unsigned int)lParam, postProcessKeyCommands); return 0; } } break; case WM_CHAR: case WM_UNICHAR: { HWND parentWindow; parentWindow = GetAncestor(hwnd, GA_PARENT); if (NULL != parentWindow) { int iFocused; unsigned int windowStyle; windowStyle = GetWindowLongPtrW(hwnd, GWL_STYLE); if (0 != (WS_VISIBLE & windowStyle)) SetWindowLongPtr(hwnd, GWL_STYLE, windowStyle & ~WS_VISIBLE); SubclassedListView_CallPrevWndProc(hwnd, uMsg, wParam, lParam); iFocused = (int)SendMessageW(hwnd, LVM_GETNEXTITEM, (WPARAM)-1, (LPARAM)(LVNI_ALL | LVNI_FOCUSED)); if (-1 != iFocused) SmoothScrollList_EnsureVisible(parentWindow, iFocused, FALSE); if (0 != (WS_VISIBLE & windowStyle)) { windowStyle = GetWindowLongPtrW(hwnd, GWL_STYLE); windowStyle |= WS_VISIBLE; SetWindowLongPtr(hwnd, GWL_STYLE, windowStyle); } InvalidateRect(hwnd, NULL, FALSE); return 0; } } break; case LVM_ENSUREVISIBLE: { HWND parentWindow = GetAncestor(hwnd, GA_PARENT); if (NULL != parentWindow) return SmoothScrollList_EnsureVisible(parentWindow, (int)wParam, (BOOL)lParam); } break; } return SubclassedListView_CallPrevWndProc(hwnd, uMsg, wParam, lParam); } static LRESULT SmoothScrollList_OnCreate(HWND hwnd, CREATESTRUCT *createStruct) { HWND hwndList, hwndHeader; MLSKINWINDOW m = {0}; RECT rc; DWORD style; SmoothScrollList *self = (SmoothScrollList *)calloc(1, sizeof(SmoothScrollList)); if (NULL == self) return -1; self->itemHeight = 1; self->textHeight = 1; SetWindowLongPtrW(hwnd, GWLP_USERDATA, (LONGX86)(LONG_PTR)self); 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); if (FALSE == GetClientRect(hwnd, &rc)) SetRectEmpty(&rc); style = WS_CLIPSIBLINGS | WS_CHILD | WS_VISIBLE | HDS_BUTTONS | HDS_FULLDRAG; hwndHeader = CreateWindowExW(WS_EX_NOPARENTNOTIFY, WC_HEADERW, NULL, style, 0, 0, rc.right - rc.left, 0, 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_REPORT | LVS_SHOWSELALWAYS | LVS_OWNERDRAWFIXED | LVS_OWNERDATA | LVS_NOCOLUMNHEADER; hwndList = CreateWindowExW(WS_EX_NOPARENTNOTIFY, WC_LISTVIEWW, NULL, style, 0, 0, rc.right - rc.left, rc.bottom - rc.top, hwnd,(HMENU)2,0,0); if (NULL != hwndList) { WNDPROC oldp = (WNDPROC)(LONG_PTR)SetWindowLongPtrW(hwndList, GWLP_WNDPROC, (LONGX86)(LONG_PTR)ListViewSubclass); SetWindowLongPtrW(hwndList,GWLP_USERDATA, (LONGX86)(LONG_PTR)oldp); 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 | SWLVS_ALTERNATEITEMS; MLSkinWindow(g_hwnd, &m); MLSkinnedScrollWnd_SetMode(hwndList, SCROLLMODE_STANDARD); MLSkinnedScrollWnd_ShowHorzBar(hwndList, FALSE); MLSkinnedScrollWnd_ShowVertBar(hwndList, FALSE); } SmoothScrollList_UpdateFontMetrics(hwnd, FALSE); return 0; } static void SmoothScrollList_OnDestroy(HWND hwnd) { SmoothScrollList *self; self = (SmoothScrollList*)(LONG_PTR)SetWindowLongPtrW(hwnd, GWLP_USERDATA, 0); if (NULL == self) return; free(self); } static void SmoothScrollList_OnWindowPosChanged(HWND hwnd, WINDOWPOS *windowPos) { HWND controlWindow; RECT rect; long clientWidth; HWND parentWindow; SmoothScrollList *self; if ((SWP_NOSIZE | SWP_NOMOVE) == ((SWP_NOSIZE | SWP_NOMOVE | SWP_FRAMECHANGED) & windowPos->flags)) return; self = GetUserData(hwnd); if (NULL == self) return; if (FALSE == GetClientRect(hwnd, &rect)) return; clientWidth = rect.right - rect.left; controlWindow = GetDlgItem(hwnd, 3); if (NULL != controlWindow) { HDLAYOUT headerLayout; WINDOWPOS headerPos; headerLayout.prc = ▭ headerLayout.pwpos = &headerPos; if (FALSE != SendMessageW(controlWindow, HDM_LAYOUT, 0, (LPARAM)&headerLayout)) { headerPos.flags |= ((SWP_NOREDRAW | SWP_NOCOPYBITS) & windowPos->flags); headerPos.flags &= ~SWP_NOZORDER; headerPos.hwndInsertAfter = HWND_TOP; SetWindowPos(controlWindow, headerPos.hwndInsertAfter, headerPos.x, headerPos.y, headerPos.cx, headerPos.cy, headerPos.flags); } } if (self->viewHeight != windowPos->cy || 0 != (SWP_FRAMECHANGED & windowPos->flags)) { ScrollPosFlags scrollFlags; scrollFlags = SPF_FORCE | SPF_RELATIVE; if (0 != (SWP_NOREDRAW & windowPos->flags)) scrollFlags |= SPF_NOREDRAW; self->viewHeight = windowPos->cy; UpdateScrollInfo(hwnd, SIF_RANGE | SIF_POS, TRUE); SmoothScrollList_SetScrollPos(hwnd, 0, scrollFlags); } else { controlWindow = GetDlgItem(hwnd, 2); if (NULL != controlWindow) { if (FALSE != GetWindowRect(controlWindow, &rect) && (rect.right - rect.left) != clientWidth) { SetWindowPos(controlWindow, NULL, 0, 0, clientWidth, rect.bottom - rect.top, SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE | ((SWP_NOREDRAW | SWP_NOCOPYBITS) & windowPos->flags)); } } } parentWindow = GetAncestor(hwnd, GA_PARENT); if (NULL != parentWindow) { NMHDR hdr; hdr.code = LVN_EX_SIZECHANGED; hdr.hwndFrom = hwnd; hdr.idFrom = GetWindowLongPtrW(hwnd, GWLP_ID); SendMessageW(parentWindow, WM_NOTIFY, hdr.idFrom, (LPARAM)&hdr); } } static void SmoothScrollList_OnMouseWheel(HWND hwnd, INT virtualKeys, INT distance, LONG pointer_s) { SmoothScrollList *self; int pos; unsigned int wheelScroll; int scrollLines; KillTimer(hwnd, 43); self = GetUserData(hwnd); if (NULL == self) return; if (FALSE == SystemParametersInfo(SPI_GETWHEELSCROLLLINES, 0, &wheelScroll, 0)) wheelScroll = 3; if (0 == wheelScroll) return; if (WHEEL_PAGESCROLL == wheelScroll) { SendMessageW(hwnd, WM_VSCROLL, MAKEWPARAM(((distance > 0) ? SB_PAGEUP : SB_PAGEDOWN), 0), 0L); SendMessageW(hwnd, WM_VSCROLL, MAKEWPARAM(SB_ENDSCROLL, 0), 0L); return; } distance += self->wheelCarryover; scrollLines = distance * (int)wheelScroll / WHEEL_DELTA; self->wheelCarryover = distance - scrollLines * WHEEL_DELTA / (int)wheelScroll; pos = scrollLines * (int)self->textHeight; SmoothScrollList_SetScrollPos(hwnd, -pos, SPF_RELATIVE | SPF_NORMAL); MLSkinnedScrollWnd_UpdateBars(hwnd, TRUE); } static void SmoothScrollList_OnVertScroll(HWND hwnd, INT actionLayout, INT trackPosition, HWND scrollBar) { SmoothScrollList *s; SCROLLINFO si; int pos; ScrollPosFlags scrollFlags; unsigned int lineHeight; KillTimer(hwnd, 43); s = GetUserData(hwnd); if (NULL == s) return; si.cbSize =sizeof(si); si.fMask = SIF_PAGE | SIF_POS | SIF_TRACKPOS | SIF_RANGE; if (FALSE == GetScrollInfo(hwnd, SB_VERT, &si)) return; scrollFlags = SPF_NORMAL; if (si.nPos > (si.nMax - (INT)si.nPage)) si.nPos = si.nMax - si.nPage; lineHeight = s->textHeight * 3; if (lineHeight > s->itemHeight) lineHeight = s->itemHeight; if (lineHeight > si.nPage) lineHeight = si.nPage; switch(actionLayout) { case SB_TOP: pos = si.nMin; break; case SB_BOTTOM: pos = si.nMax; break; case SB_LINEDOWN: pos = si.nPos + lineHeight; break; case SB_LINEUP: pos = si.nPos - lineHeight; break; case SB_PAGEDOWN: pos = si.nPos + (si.nPage / s->itemHeight) * s->itemHeight; break; case SB_PAGEUP: pos = si.nPos - (si.nPage / s->itemHeight) * s->itemHeight; break; case SB_THUMBPOSITION: case SB_THUMBTRACK: pos = si.nTrackPos; scrollFlags |= SPF_FORCE; break; case SB_ENDSCROLL: MLSkinnedScrollWnd_UpdateBars(hwnd, TRUE); return; default: pos = si.nPos; } SmoothScrollList_SetScrollPos(hwnd, pos, scrollFlags); } static LRESULT SmoothScrollList_OnMeasureItem(HWND hwnd, MEASUREITEMSTRUCT *measureItem) { LRESULT result; HWND parentWindow; SmoothScrollList *self; unsigned int itemHeight, textHeight; BOOL updateScroll; if(2 != measureItem->CtlID) return FALSE; self = GetUserData(hwnd); updateScroll = FALSE; itemHeight = measureItem->itemHeight; parentWindow = GetAncestor(hwnd, GA_PARENT); if (NULL != parentWindow) { measureItem->CtlID = GetWindowLongPtrW(hwnd, GWLP_ID); result = SendMessageW(parentWindow, WM_MEASUREITEM, measureItem->CtlID, (LPARAM)measureItem); itemHeight = measureItem->itemHeight; } else result = 0; textHeight = 12; HDC hdc = GetDCEx(hwnd, NULL, DCX_CACHE | DCX_NORESETATTRS); if (NULL != hdc) { HFONT font, fontPrev; TEXTMETRIC textMetrics; font = (HFONT)SendMessageW(hwnd, WM_GETFONT, 0, 0L); fontPrev = (HFONT)SelectObject(hdc, font); if (FALSE != GetTextMetrics(hdc, &textMetrics)) textHeight = textMetrics.tmHeight; SelectObject(hdc, fontPrev); ReleaseDC(hwnd, hdc); } if (NULL != self) { if (self->itemHeight != itemHeight) { SmoothScrollList_SetScrollPos(hwnd, 0, SPF_NOREDRAW); self->itemHeight = itemHeight; updateScroll = TRUE; } if (self->textHeight != textHeight) { self->textHeight = textHeight; updateScroll = TRUE; } } if (FALSE != updateScroll) { UpdateScrollInfo(hwnd, SIF_RANGE | SIF_POS, TRUE); } return result; } static void SmoothScrollList_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)); SmoothScrollList_UpdateFontMetrics(hwnd, redraw); } } static LRESULT SmoothScrollList_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 SmoothScrollList_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 SmoothScrollList_OnSkinUpdated(HWND hwnd, BOOL notifyChildren, BOOL redraw) { SmoothScrollList_UpdateFontMetrics(hwnd, redraw); } static LRESULT SmoothScrollList_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 SmoothScrollList_OnGetSort(HWND hwnd) { HWND headerWindow; headerWindow = GetDlgItem(hwnd, 3); if (NULL == headerWindow) return 0; return SENDMLIPC(headerWindow, ML_IPC_SKINNEDHEADER_GETSORT, 0); } static void SmoothScrollList_OnKeyDown(HWND hwnd, unsigned int vKey, unsigned int keyFlags) { HWND listWindow; listWindow = GetDlgItem(hwnd, 2); if (NULL != listWindow && WS_VISIBLE == ((WS_VISIBLE | WS_DISABLED) & GetWindowLongPtrW(listWindow, GWL_STYLE))) { SendMessageW(listWindow, WM_KEYDOWN, vKey, (LPARAM)keyFlags); } DefWindowProcW(hwnd, WM_KEYDOWN, vKey, (LPARAM)keyFlags); } static LRESULT SmoothScrollList_OnMediaLibraryIPC(HWND hwnd, INT msg, INT_PTR param) { switch(msg) { case ML_IPC_SKINNEDWND_SKINUPDATED: SmoothScrollList_OnSkinUpdated(hwnd, LOWORD(param), HIWORD(param)); break; case ML_IPC_SKINNEDLISTVIEW_DISPLAYSORT: return SmoothScrollList_OnDisplaySort(hwnd, LOWORD(param), HIWORD(param)); case ML_IPC_SKINNEDLISTVIEW_GETSORT: return SmoothScrollList_OnGetSort(hwnd); } return 0; } static LRESULT CALLBACK SmoothScrollMsgProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { switch(uMsg) { case WM_CREATE: return SmoothScrollList_OnCreate(hwnd, (CREATESTRUCT*)lParam); case WM_DESTROY: SmoothScrollList_OnDestroy(hwnd); return 0; case WM_WINDOWPOSCHANGED: SmoothScrollList_OnWindowPosChanged(hwnd, (WINDOWPOS*)lParam); return 0; case WM_MOUSEWHEEL: SmoothScrollList_OnMouseWheel(hwnd, LOWORD(wParam), (short)HIWORD(wParam), (LONG)lParam); return 0; case WM_VSCROLL: SmoothScrollList_OnVertScroll(hwnd, LOWORD(wParam), (short)HIWORD(wParam), (HWND)lParam); return 0; case WM_ERASEBKGND: return 1; case WM_MEASUREITEM: return SmoothScrollList_OnMeasureItem(hwnd, (MEASUREITEMSTRUCT*)lParam); case WM_SETFONT: SmoothScrollList_OnSetFont(hwnd, (HFONT)wParam, LOWORD(lParam)); return 0; case WM_GETFONT: return SmoothScrollList_OnGetFont(hwnd); case WM_SETREDRAW: SmoothScrollList_OnSetRedraw(hwnd, (BOOL)wParam); return 0; case LVM_GETHEADER: return (LRESULT)GetDlgItem(hwnd,3); case LVM_INSERTCOLUMNA: case LVM_INSERTCOLUMNW: { LVCOLUMNW *listColumn = (LVCOLUMNW*)lParam; HWND controlWindow; LRESULT result; result = -1; controlWindow = GetDlgItem(hwnd,3); if (NULL != controlWindow) { HDITEMW headerItem; if (FALSE == CopyListColumnToHeaderItem(listColumn, &headerItem)) return -1; if (0 == (HDI_FORMAT & headerItem.mask)) { headerItem.mask |= HDI_FORMAT; headerItem.fmt = HDF_LEFT; } result = SendMessageW(controlWindow, (LVM_INSERTCOLUMNW == uMsg) ? HDM_INSERTITEMW : HDM_INSERTITEMA, wParam, (LPARAM)&headerItem); if (-1 == result) return result; } controlWindow = GetDlgItem(hwnd, 2); if (NULL != controlWindow) result = SendMessageW(controlWindow, uMsg, wParam, lParam); return result; } break; case LVM_DELETECOLUMN: { HWND controlWindow; controlWindow = GetDlgItem(hwnd,3); if (NULL != controlWindow && FALSE ==SendMessageW(controlWindow, HDM_DELETEITEM, wParam, 0L)) { return FALSE; } controlWindow = GetDlgItem(hwnd,2); if (NULL != controlWindow) return SendMessageW(controlWindow ,uMsg,wParam,lParam); } return FALSE; 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_GETCOLUMNWIDTH: { HWND controlWindow; controlWindow = GetDlgItem(hwnd,3); if (NULL != controlWindow) { HDITEMW h; h.mask = HDI_WIDTH; if (FALSE == SendMessageW(controlWindow, HDM_GETITEM, wParam, (LPARAM)&h)) return 0; return h.cxy; } controlWindow = GetDlgItem(hwnd, 2); if (NULL != controlWindow) return SendMessageW(controlWindow, uMsg, wParam, lParam); } break; case LVM_SETCOLUMNW: case LVM_SETCOLUMNA: { LVCOLUMNW *l = (LVCOLUMNW *)lParam; HWND controlWindow; LRESULT result; controlWindow = GetDlgItem(hwnd, 3); if (NULL != controlWindow) { HDITEMW h; if (FALSE == CopyListColumnToHeaderItem(l, &h)) return FALSE; if(!SendMessageW(controlWindow, (LVM_SETCOLUMNW == uMsg) ? HDM_SETITEMW : HDM_SETITEMA, wParam, (LPARAM)&h)) { return FALSE; } if (FALSE == CopyHeaderItemToListColumn(&h, l)) return FALSE; result = TRUE; } else result = FALSE; controlWindow = GetDlgItem(hwnd,2); if (NULL != controlWindow) result = SendMessageW(controlWindow, uMsg, wParam, lParam); return result; } break; case LVM_SETCOLUMNWIDTH: { HWND controlWindow; LRESULT result; controlWindow = GetDlgItem(hwnd, 3); if (NULL != controlWindow) { HDITEMW headerItem; if (LVSCW_AUTOSIZE == lParam) return FALSE; if (LVSCW_AUTOSIZE_USEHEADER == lParam) return FALSE; headerItem.mask = HDI_WIDTH; headerItem.cxy = (int)lParam; result = SendMessageW(controlWindow, HDM_SETITEMW, (WPARAM)wParam, (LPARAM)&headerItem); if (FALSE == result) return FALSE; } else result = FALSE; controlWindow = GetDlgItem(hwnd,2); if (NULL != controlWindow) result = SendMessageW(controlWindow, uMsg, wParam, lParam); return result; } break; case LVM_SETITEMCOUNT: { LRESULT result; HWND controlWindow = GetDlgItem(hwnd,2); result = (NULL != controlWindow) ? SendMessageW(controlWindow, uMsg, wParam,lParam) : 0; UpdateScrollInfo(hwnd, SIF_RANGE | SIF_POS, TRUE); return result; } break; case LVM_ENSUREVISIBLE: return SmoothScrollList_EnsureVisible(hwnd, (int)wParam, (BOOL)lParam); case WM_EX_UPDATESCROLLINFO: return UpdateScrollInfo(hwnd, (UINT)wParam, (BOOL)lParam); case WM_EX_UNLOCKREDRAW: { unsigned long windowStyle; unsigned int redrawFlags; HRGN regionInvalid; RECT rect; windowStyle = GetWindowLongPtrW(hwnd, GWL_STYLE); if (0 == (WS_VISIBLE & windowStyle)) SetWindowLongPtrW(hwnd, GWL_STYLE, windowStyle | WS_VISIBLE); redrawFlags = RDW_INVALIDATE | RDW_ALLCHILDREN; if (0 != (IWF_FRAME & wParam)) { redrawFlags |= RDW_FRAME; GetWindowRect(hwnd, &rect); MapWindowPoints(HWND_DESKTOP, hwnd, (POINT*)&rect, 2); } else GetClientRect(hwnd, &rect); if (0 != (IWF_ERASE & wParam)) redrawFlags |= RDW_ERASE; if (0 != (IWF_UPDATENOW & wParam)) { redrawFlags |= RDW_UPDATENOW; if (0 != (IWF_ERASE & wParam)) redrawFlags |= RDW_ERASENOW; } regionInvalid = CreateRectRgnIndirect(&rect); if (NULL != regionInvalid) { HWND headerWindow; headerWindow = GetDlgItem(hwnd, 3); if (NULL != headerWindow && 0 != (WS_VISIBLE & GetWindowLongPtrW(headerWindow, GWL_STYLE))) { HRGN regionHeader; GetWindowRect(headerWindow, &rect); MapWindowPoints(HWND_DESKTOP, hwnd, (POINT*)&rect, 2); regionHeader = CreateRectRgnIndirect(&rect); if (NULL != regionHeader) { CombineRgn(regionInvalid, regionInvalid, regionHeader, RGN_DIFF); DeleteObject(regionHeader); } } } RedrawWindow(hwnd, NULL, regionInvalid, redrawFlags); if (NULL != regionInvalid) DeleteObject(regionInvalid); } break; case WM_NOTIFY: { LPNMHDR l=(LPNMHDR)lParam; if(l->idFrom == 2) { l->idFrom = GetWindowLongPtrW(hwnd,GWLP_ID); l->hwndFrom = hwnd; // this is prevents double reflecting return SendMessageW(GetParent(hwnd),uMsg,l->idFrom,lParam); } 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; case HDN_ITEMCHANGINGA: case HDN_ITEMCHANGINGW: case HDN_ITEMCHANGEDA: case HDN_ITEMCHANGEDW: { LRESULT result; NMHEADER *nm = (NMHEADER*)lParam; result = SendMessageW(GetParent(hwnd),uMsg, wParam,lParam); if (FALSE != result && (HDN_ITEMCHANGINGW == l->code || HDN_ITEMCHANGINGA == l->code)) { return result; } if (NULL != nm->pitem && 0 != (HDI_WIDTH & nm->pitem->mask)) { HWND hwndList; hwndList = GetDlgItem(hwnd,2); if (hwndList) { unsigned long windowStyle; windowStyle = GetWindowLongPtrW(hwnd, GWL_STYLE); if (0 != (WS_VISIBLE & windowStyle)) SetWindowLongPtrW(hwnd, GWL_STYLE, windowStyle & ~WS_VISIBLE); ListView_SetColumnWidth(hwndList, nm->iItem,nm->pitem->cxy); if (0 != (WS_VISIBLE & windowStyle)) { windowStyle = GetWindowLongPtrW(hwnd, GWL_STYLE); if (0 == (WS_VISIBLE & windowStyle)) { windowStyle |= WS_VISIBLE; SetWindowLongPtrW(hwnd, GWL_STYLE, windowStyle); } InvalidateRect(hwndList, NULL, FALSE); } } } return result; } break; } return SendMessageW(GetParent(hwnd),uMsg, wParam,lParam); } } break; case WM_EX_GETREALLIST: return (LRESULT)GetDlgItem(hwnd, 2); case WM_EX_GETCOUNTPERPAGE: return SendMessageW(GetDlgItem(hwnd, 2), LVM_GETCOUNTPERPAGE, 0, 0L) + 1; case WM_KEYDOWN: SmoothScrollList_OnKeyDown(hwnd, (unsigned int)wParam, (unsigned int)lParam); return 0; case WM_ML_IPC: return SmoothScrollList_OnMediaLibraryIPC(hwnd, (INT)lParam, (INT_PTR)wParam); default: if(uMsg >= LVM_FIRST && uMsg < LVM_FIRST + 0x100) { HWND hwndList = GetDlgItem(hwnd,2); if (hwndList) return ListViewSubclass(hwndList, uMsg, wParam, lParam); } break; } return DefWindowProcW(hwnd,uMsg,wParam,lParam); } void InitSmoothScrollList() { WNDCLASSW wc = {0, }; if (GetClassInfoW(plugin.hDllInstance, L"SmoothScrollList", &wc)) return; wc.style = CS_DBLCLKS; wc.lpfnWndProc = SmoothScrollMsgProc; wc.hInstance = plugin.hDllInstance; wc.lpszClassName = L"SmoothScrollList"; RegisterClassW(&wc); }