summaryrefslogtreecommitdiff
path: root/wintable/scroll.h
blob: ba5a9f892e0c93b0868ecb20113a5c971d70711c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
// 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);
}