1838 lines
44 KiB
C++
1838 lines
44 KiB
C++
|
#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);
|
||
|
}
|