#include "uipriv_windows.hpp"
#include "area.hpp"
struct scrollParams {
int *pos;
int pagesize;
int length;
int *wheelCarry;
UINT wheelSPIAction;
};
static void scrollto(uiArea *a, int which, struct scrollParams *p, int pos)
{
SCROLLINFO si;
if (pos > p->length - p->pagesize)
pos = p->length - p->pagesize;
if (pos < 0)
pos = 0;
invalidateRect(a->hwnd, NULL, FALSE);
*(p->pos) = pos;
ZeroMemory(&si, sizeof (SCROLLINFO));
si.cbSize = sizeof (SCROLLINFO);
si.fMask = SIF_PAGE | SIF_POS | SIF_RANGE;
si.nPage = p->pagesize;
si.nMin = 0;
si.nMax = p->length - 1; si.nPos = *(p->pos);
SetScrollInfo(a->hwnd, which, &si, TRUE);
}
static void scrollby(uiArea *a, int which, struct scrollParams *p, int delta)
{
scrollto(a, which, p, *(p->pos) + delta);
}
static void scroll(uiArea *a, int which, struct scrollParams *p, WPARAM wParam, LPARAM lParam)
{
int pos;
SCROLLINFO si;
pos = *(p->pos);
switch (LOWORD(wParam)) {
case SB_LEFT: pos = 0;
break;
case SB_RIGHT: pos = p->length - p->pagesize;
break;
case SB_LINELEFT: pos--;
break;
case SB_LINERIGHT: pos++;
break;
case SB_PAGELEFT: pos -= p->pagesize;
break;
case SB_PAGERIGHT: pos += p->pagesize;
break;
case SB_THUMBPOSITION:
ZeroMemory(&si, sizeof (SCROLLINFO));
si.cbSize = sizeof (SCROLLINFO);
si.fMask = SIF_POS;
if (GetScrollInfo(a->hwnd, which, &si) == 0)
logLastError(L"error getting thumb position for area");
pos = si.nPos;
break;
case SB_THUMBTRACK:
ZeroMemory(&si, sizeof (SCROLLINFO));
si.cbSize = sizeof (SCROLLINFO);
si.fMask = SIF_TRACKPOS;
if (GetScrollInfo(a->hwnd, which, &si) == 0)
logLastError(L"error getting thumb track position for area");
pos = si.nTrackPos;
break;
}
scrollto(a, which, p, pos);
}
static void wheelscroll(uiArea *a, int which, struct scrollParams *p, WPARAM wParam, LPARAM lParam)
{
int delta;
int lines;
UINT scrollAmount;
delta = GET_WHEEL_DELTA_WPARAM(wParam);
if (SystemParametersInfoW(p->wheelSPIAction, 0, &scrollAmount, 0) == 0)
logLastError(L"error getting area wheel scroll amount");
if (scrollAmount == WHEEL_PAGESCROLL)
scrollAmount = p->pagesize;
if (scrollAmount == 0) return;
delta += *(p->wheelCarry);
lines = delta * ((int) scrollAmount) / WHEEL_DELTA;
*(p->wheelCarry) = delta - lines * WHEEL_DELTA / ((int) scrollAmount);
scrollby(a, which, p, -lines);
}
static void hscrollParams(uiArea *a, struct scrollParams *p)
{
RECT r;
ZeroMemory(p, sizeof (struct scrollParams));
p->pos = &(a->hscrollpos);
uiWindowsEnsureGetClientRect(a->hwnd, &r);
p->pagesize = r.right - r.left;
p->length = a->scrollWidth;
p->wheelCarry = &(a->hwheelCarry);
p->wheelSPIAction = SPI_GETWHEELSCROLLCHARS;
}
static void hscrollto(uiArea *a, int pos)
{
struct scrollParams p;
hscrollParams(a, &p);
scrollto(a, SB_HORZ, &p, pos);
}
static void hscrollby(uiArea *a, int delta)
{
struct scrollParams p;
hscrollParams(a, &p);
scrollby(a, SB_HORZ, &p, delta);
}
static void hscroll(uiArea *a, WPARAM wParam, LPARAM lParam)
{
struct scrollParams p;
hscrollParams(a, &p);
scroll(a, SB_HORZ, &p, wParam, lParam);
}
static void hwheelscroll(uiArea *a, WPARAM wParam, LPARAM lParam)
{
struct scrollParams p;
hscrollParams(a, &p);
wheelscroll(a, SB_HORZ, &p, wParam, lParam);
}
static void vscrollParams(uiArea *a, struct scrollParams *p)
{
RECT r;
ZeroMemory(p, sizeof (struct scrollParams));
p->pos = &(a->vscrollpos);
uiWindowsEnsureGetClientRect(a->hwnd, &r);
p->pagesize = r.bottom - r.top;
p->length = a->scrollHeight;
p->wheelCarry = &(a->vwheelCarry);
p->wheelSPIAction = SPI_GETWHEELSCROLLLINES;
}
static void vscrollto(uiArea *a, int pos)
{
struct scrollParams p;
vscrollParams(a, &p);
scrollto(a, SB_VERT, &p, pos);
}
static void vscrollby(uiArea *a, int delta)
{
struct scrollParams p;
vscrollParams(a, &p);
scrollby(a, SB_VERT, &p, delta);
}
static void vscroll(uiArea *a, WPARAM wParam, LPARAM lParam)
{
struct scrollParams p;
vscrollParams(a, &p);
scroll(a, SB_VERT, &p, wParam, lParam);
}
static void vwheelscroll(uiArea *a, WPARAM wParam, LPARAM lParam)
{
struct scrollParams p;
vscrollParams(a, &p);
wheelscroll(a, SB_VERT, &p, wParam, lParam);
}
BOOL areaDoScroll(uiArea *a, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT *lResult)
{
switch (uMsg) {
case WM_HSCROLL:
hscroll(a, wParam, lParam);
*lResult = 0;
return TRUE;
case WM_MOUSEHWHEEL:
hwheelscroll(a, wParam, lParam);
*lResult = 0;
return TRUE;
case WM_VSCROLL:
vscroll(a, wParam, lParam);
*lResult = 0;
return TRUE;
case WM_MOUSEWHEEL:
vwheelscroll(a, wParam, lParam);
*lResult = 0;
return TRUE;
}
return FALSE;
}
void areaScrollOnResize(uiArea *a, RECT *client)
{
areaUpdateScroll(a);
}
void areaUpdateScroll(uiArea *a)
{
hscrollby(a, 0);
vscrollby(a, 0);
}