138 lines
3.9 KiB
C
138 lines
3.9 KiB
C
|
// 9 december 2014
|
||
|
|
||
|
struct scrollParams {
|
||
|
intptr_t *pos;
|
||
|
intptr_t pagesize;
|
||
|
intptr_t length;
|
||
|
intptr_t scale;
|
||
|
void (*post)(struct table *);
|
||
|
int *wheelCarry;
|
||
|
};
|
||
|
|
||
|
static void scrollto(struct table *t, int which, struct scrollParams *p, intptr_t pos)
|
||
|
{
|
||
|
RECT scrollArea;
|
||
|
SCROLLINFO si;
|
||
|
intptr_t xamount, yamount;
|
||
|
|
||
|
if (pos < 0)
|
||
|
pos = 0;
|
||
|
if (pos > p->length - p->pagesize)
|
||
|
pos = p->length - p->pagesize;
|
||
|
// TODO this shouldn't have been necessary but alas
|
||
|
// TODO the logic is really intended for the whole y origin thing in the scrollbar series; fix that
|
||
|
if (pos < 0)
|
||
|
pos = 0;
|
||
|
|
||
|
// we don't want to scroll the header
|
||
|
if (GetClientRect(t->hwnd, &scrollArea) == 0)
|
||
|
panic("error getting Table client rect for scrollto()");
|
||
|
scrollArea.top += t->headerHeight;
|
||
|
|
||
|
// negative because ScrollWindowEx() is "backwards"
|
||
|
xamount = -(pos - *(p->pos)) * p->scale;
|
||
|
yamount = 0;
|
||
|
if (which == SB_VERT) {
|
||
|
yamount = xamount;
|
||
|
xamount = 0;
|
||
|
}
|
||
|
|
||
|
if (ScrollWindowEx(t->hwnd, xamount, yamount,
|
||
|
&scrollArea, &scrollArea, NULL, NULL,
|
||
|
SW_ERASE | SW_INVALIDATE) == ERROR)
|
||
|
;// TODO failure case ignored for now; see https://bugs.winehq.org/show_bug.cgi?id=37706
|
||
|
// panic("error scrolling Table");
|
||
|
// TODO call UpdateWindow()?
|
||
|
|
||
|
*(p->pos) = pos;
|
||
|
|
||
|
// now commit our new scrollbar setup...
|
||
|
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; // endpoint inclusive
|
||
|
si.nPos = *(p->pos);
|
||
|
SetScrollInfo(t->hwnd, which, &si, TRUE);
|
||
|
|
||
|
if (p->post != NULL)
|
||
|
(*(p->post))(t);
|
||
|
|
||
|
// EVENT_OBJECT_CONTENTSCROLLED is Vista and up only
|
||
|
// TODO send state changes for all affected rows/cells?
|
||
|
}
|
||
|
|
||
|
static void scrollby(struct table *t, int which, struct scrollParams *p, intptr_t delta)
|
||
|
{
|
||
|
scrollto(t, which, p, *(p->pos) + delta);
|
||
|
}
|
||
|
|
||
|
static void scroll(struct table *t, int which, struct scrollParams *p, WPARAM wParam, LPARAM lParam)
|
||
|
{
|
||
|
intptr_t pos;
|
||
|
SCROLLINFO si;
|
||
|
|
||
|
pos = *(p->pos);
|
||
|
switch (LOWORD(wParam)) {
|
||
|
case SB_LEFT: // also SB_TOP
|
||
|
pos = 0;
|
||
|
break;
|
||
|
case SB_RIGHT: // also SB_BOTTOM
|
||
|
pos = p->length - p->pagesize;
|
||
|
break;
|
||
|
case SB_LINELEFT: // also SB_LINEUP
|
||
|
pos--;
|
||
|
break;
|
||
|
case SB_LINERIGHT: // also SB_LINEDOWN
|
||
|
pos++;
|
||
|
break;
|
||
|
case SB_PAGELEFT: // also SB_PAGEUP
|
||
|
pos -= p->pagesize;
|
||
|
break;
|
||
|
case SB_PAGERIGHT: // also SB_PAGEDOWN
|
||
|
pos += p->pagesize;
|
||
|
break;
|
||
|
case SB_THUMBPOSITION:
|
||
|
ZeroMemory(&si, sizeof (SCROLLINFO));
|
||
|
si.cbSize = sizeof (SCROLLINFO);
|
||
|
si.fMask = SIF_POS;
|
||
|
if (GetScrollInfo(t->hwnd, which, &si) == 0)
|
||
|
panic("error getting thumb position for scroll() in Table");
|
||
|
pos = si.nPos;
|
||
|
break;
|
||
|
case SB_THUMBTRACK:
|
||
|
ZeroMemory(&si, sizeof (SCROLLINFO));
|
||
|
si.cbSize = sizeof (SCROLLINFO);
|
||
|
si.fMask = SIF_TRACKPOS;
|
||
|
if (GetScrollInfo(t->hwnd, which, &si) == 0)
|
||
|
panic("error getting thumb track position for scroll() in Table");
|
||
|
pos = si.nTrackPos;
|
||
|
break;
|
||
|
}
|
||
|
scrollto(t, which, p, pos);
|
||
|
}
|
||
|
|
||
|
static void wheelscroll(struct table *t, int which, struct scrollParams *p, WPARAM wParam, LPARAM lParam)
|
||
|
{
|
||
|
int delta;
|
||
|
int lines;
|
||
|
UINT scrollAmount;
|
||
|
|
||
|
delta = GET_WHEEL_DELTA_WPARAM(wParam);
|
||
|
// TODO make a note of what the appropriate hscroll constant is
|
||
|
if (SystemParametersInfoW(SPI_GETWHEELSCROLLLINES, 0, &scrollAmount, 0) == 0)
|
||
|
// TODO use scrollAmount == 3 instead?
|
||
|
panic("error getting wheel scroll amount in wheelscroll()");
|
||
|
if (scrollAmount == WHEEL_PAGESCROLL)
|
||
|
scrollAmount = p->pagesize;
|
||
|
if (scrollAmount == 0) // no mouse wheel scrolling (or t->pagesize == 0)
|
||
|
return;
|
||
|
// the rest of this is basically http://blogs.msdn.com/b/oldnewthing/archive/2003/08/07/54615.aspx and http://blogs.msdn.com/b/oldnewthing/archive/2003/08/11/54624.aspx
|
||
|
// see those pages for information on subtleties
|
||
|
delta += *(p->wheelCarry);
|
||
|
lines = delta * ((int) scrollAmount) / WHEEL_DELTA;
|
||
|
*(p->wheelCarry) = delta - lines * WHEEL_DELTA / ((int) scrollAmount);
|
||
|
scrollby(t, which, p, -lines);
|
||
|
}
|