summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--wintable/api.h25
-rw-r--r--wintable/hscroll.h114
-rw-r--r--wintable/main.c371
-rw-r--r--wintable/util.h136
-rw-r--r--wintable/vscroll.h97
5 files changed, 376 insertions, 367 deletions
diff --git a/wintable/api.h b/wintable/api.h
new file mode 100644
index 0000000..a933df7
--- /dev/null
+++ b/wintable/api.h
@@ -0,0 +1,25 @@
+// 29 november 2014
+
+static void addColumn(struct table *t, WPARAM wParam, LPARAM lParam)
+{
+ HDITEMW item;
+
+ if (((int) wParam) >= nTableColumnTypes)
+ abort();
+
+ t->nColumns++;
+ t->columnTypes = (int *) realloc(t->columnTypes, t->nColumns * sizeof (int));
+ if (t->columnTypes == NULL)
+ abort();
+ t->columnTypes[t->nColumns - 1] = (int) wParam;
+
+ ZeroMemory(&item, sizeof (HDITEMW));
+ item.mask = HDI_WIDTH | HDI_TEXT | HDI_FORMAT;
+ item.cxy = 200; // TODO
+ item.pszText = (WCHAR *) lParam;
+ item.fmt = HDF_LEFT | HDF_STRING;
+ if (SendMessage(t->header, HDM_INSERTITEM, (WPARAM) (t->nColumns - 1), (LPARAM) (&item)) == (LRESULT) (-1))
+ abort();
+ // TODO resize(t)?
+ redrawAll(t);
+}
diff --git a/wintable/hscroll.h b/wintable/hscroll.h
new file mode 100644
index 0000000..6c700a7
--- /dev/null
+++ b/wintable/hscroll.h
@@ -0,0 +1,114 @@
+// 29 november 2014
+
+static void hscrollto(struct table *t, intptr_t newpos)
+{
+ SCROLLINFO si;
+ RECT scrollArea;
+
+ if (newpos < 0)
+ newpos = 0;
+ if (newpos > (t->width - t->hpagesize))
+ newpos = (t->width - t->hpagesize);
+
+ scrollArea = realClientRect(t);
+
+ // negative because ScrollWindowEx() is "backwards"
+ if (ScrollWindowEx(t->hwnd, -(newpos - t->hpos), 0,
+ &scrollArea, &scrollArea, NULL, NULL,
+ SW_ERASE | SW_INVALIDATE) == ERROR)
+ abort();
+ t->hpos = newpos;
+ // TODO text in header controls doesn't redraw?
+
+ // TODO put this in a separate function? same for vscroll?
+ ZeroMemory(&si, sizeof (SCROLLINFO));
+ si.cbSize = sizeof (SCROLLINFO);
+ si.fMask = SIF_PAGE | SIF_POS | SIF_RANGE;
+ si.nPage = t->hpagesize;
+ si.nMin = 0;
+ si.nMax = t->width - 1; // nMax is inclusive
+ si.nPos = t->hpos;
+ SetScrollInfo(t->hwnd, SB_HORZ, &si, TRUE);
+
+ // and finally reposition the header
+ repositionHeader(t);
+}
+
+static void hscrollby(struct table *t, intptr_t n)
+{
+ hscrollto(t, t->hpos + n);
+}
+
+// unfortunately horizontal wheel scrolling was only added in Vista
+
+static void hscroll(struct table *t, WPARAM wParam)
+{
+ SCROLLINFO si;
+ intptr_t newpos;
+
+ ZeroMemory(&si, sizeof (SCROLLINFO));
+ si.cbSize = sizeof (SCROLLINFO);
+ si.fMask = SIF_POS | SIF_TRACKPOS;
+ if (GetScrollInfo(t->hwnd, SB_HORZ, &si) == 0)
+ abort();
+
+ newpos = t->hpos;
+ switch (LOWORD(wParam)) {
+ case SB_LEFT:
+ newpos = 0;
+ break;
+ case SB_RIGHT:
+ newpos = t->width - t->hpagesize;
+ break;
+ case SB_LINELEFT:
+ newpos--;
+ break;
+ case SB_LINERIGHT:
+ newpos++;
+ break;
+ case SB_PAGELEFT:
+ newpos -= t->hpagesize;
+ break;
+ case SB_PAGERIGHT:
+ newpos += t->hpagesize;
+ break;
+ case SB_THUMBPOSITION:
+ newpos = (intptr_t) (si.nPos);
+ break;
+ case SB_THUMBTRACK:
+ newpos = (intptr_t) (si.nTrackPos);
+ }
+
+ hscrollto(t, newpos);
+}
+
+static void recomputeHScroll(struct table *t)
+{
+ HDITEMW item;
+ intptr_t i;
+ int width = 0;
+ RECT r;
+ SCROLLINFO si;
+
+ // TODO count dividers
+ for (i = 0; i < t->nColumns; i++) {
+ ZeroMemory(&item, sizeof (HDITEMW));
+ item.mask = HDI_WIDTH;
+ if (SendMessageW(t->header, HDM_GETITEM, (WPARAM) i, (LPARAM) (&item)) == FALSE)
+ abort();
+ width += item.cxy;
+ }
+ t->width = (intptr_t) width;
+
+ if (GetClientRect(t->hwnd, &r) == 0)
+ abort();
+ t->hpagesize = r.right - r.left;
+
+ ZeroMemory(&si, sizeof (SCROLLINFO));
+ si.cbSize = sizeof (SCROLLINFO);
+ si.fMask = SIF_PAGE | SIF_RANGE;
+ si.nPage = t->hpagesize;
+ si.nMin = 0;
+ si.nMax = t->width - 1; // - 1 because endpoints inclusive
+ SetScrollInfo(t->hwnd, SB_HORZ, &si, TRUE);
+}
diff --git a/wintable/main.c b/wintable/main.c
index 6618f50..1349889 100644
--- a/wintable/main.c
+++ b/wintable/main.c
@@ -93,373 +93,10 @@ struct table {
int checkboxHeight;
};
-static LONG rowHeight(struct table *t)
-{
- HFONT thisfont, prevfont;
- TEXTMETRICW tm;
- HDC dc;
- LONG ret;
-
- dc = GetDC(t->hwnd);
- if (dc == NULL)
- abort();
- thisfont = t->font; // in case WM_SETFONT happens before we return
- prevfont = (HFONT) SelectObject(dc, thisfont);
- if (prevfont == NULL)
- abort();
- if (GetTextMetricsW(dc, &tm) == 0)
- abort();
- if (SelectObject(dc, prevfont) != (HGDIOBJ) (thisfont))
- abort();
- if (ReleaseDC(t->hwnd, dc) == 0)
- abort();
- ret = tm.tmHeight;
- if (ret < t->imagelistHeight)
- ret = t->imagelistHeight;
- if (ret < t->checkboxHeight)
- ret = t->checkboxHeight;
- return ret;
-}
-
-static void redrawAll(struct table *t)
-{
- if (InvalidateRect(t->hwnd, NULL, TRUE) == 0)
- abort();
- if (UpdateWindow(t->hwnd) == 0)
- abort();
-}
-
-static RECT realClientRect(struct table *t)
-{
- RECT r;
-
- if (GetClientRect(t->hwnd, &r) == 0)
- abort();
- r.top += t->headerHeight;
- return r;
-}
-
-static void repositionHeader(struct table *t)
-{
- RECT r;
- HDLAYOUT headerlayout;
- WINDOWPOS headerpos;
-
- if (GetClientRect(t->hwnd, &r) == 0) // use the whole client rect
- abort();
- // grow the rectangle to the left to fake scrolling
- r.left -= t->hpos;
- headerlayout.prc = &r;
- headerlayout.pwpos = &headerpos;
- if (SendMessageW(t->header, HDM_LAYOUT, 0, (LPARAM) (&headerlayout)) == FALSE)
- abort();
- if (SetWindowPos(t->header, headerpos.hwndInsertAfter, headerpos.x, headerpos.y, headerpos.cx, headerpos.cy, headerpos.flags | SWP_SHOWWINDOW) == 0)
- abort();
- t->headerHeight = headerpos.cy;
-}
-
-// this counts partially visible rows
-// for all fully visible rows use t->pagesize
-// cliprect and rowHeight must be specified here to avoid recomputing things multiple times
-static intptr_t lastVisible(struct table *t, RECT cliprect, LONG rowHeight)
-{
- intptr_t last;
-
- last = ((cliprect.bottom + rowHeight - 1) / rowHeight) + t->firstVisible;
- if (last >= t->count)
- last = t->count;
- return last;
-}
-
-static void redrawRow(struct table *t, intptr_t row)
-{
- RECT r;
- intptr_t height;
-
- r = realClientRect(t);
- height = rowHeight(t);
- if (row < t->firstVisible || row > lastVisible(t, r, height)) // not visible; don't bother
- return;
- r.top = (row - t->firstVisible) * height + t->headerHeight;
- r.bottom = r.top + height;
- // keep the width and height the same; it spans the client area anyway
- if (InvalidateRect(t->hwnd, &r, TRUE) == 0)
- abort();
- if (UpdateWindow(t->hwnd) == 0)
- abort();
-}
-
-static intptr_t hitTestColumn(struct table *t, int x)
-{
- HDITEMW item;
- intptr_t i;
-
- // TODO count dividers
- for (i = 0; i < t->nColumns; i++) {
- ZeroMemory(&item, sizeof (HDITEMW));
- item.mask = HDI_WIDTH;
- if (SendMessageW(t->header, HDM_GETITEM, (WPARAM) i, (LPARAM) (&item)) == FALSE)
- abort();
- if (x < item.cxy)
- return i;
- x -= item.cxy; // not yet
- }
- // no column
- return -1;
-}
-
-static void lParamToRowColumn(struct table *t, LPARAM lParam, intptr_t *row, intptr_t *column)
-{
- int x, y;
- LONG h;
-
- x = GET_X_LPARAM(lParam);
- y = GET_Y_LPARAM(lParam);
- h = rowHeight(t);
- y += t->firstVisible * h;
- y -= t->headerHeight;
- y /= h;
- if (row != NULL) {
- *row = y;
- if (*row >= t->count)
- *row = -1;
- }
- if (column != NULL)
- *column = hitTestColumn(t, x);
-}
-
-static void addColumn(struct table *t, WPARAM wParam, LPARAM lParam)
-{
- HDITEMW item;
-
- if (((int) wParam) >= nTableColumnTypes)
- abort();
-
- t->nColumns++;
- t->columnTypes = (int *) realloc(t->columnTypes, t->nColumns * sizeof (int));
- if (t->columnTypes == NULL)
- abort();
- t->columnTypes[t->nColumns - 1] = (int) wParam;
-
- ZeroMemory(&item, sizeof (HDITEMW));
- item.mask = HDI_WIDTH | HDI_TEXT | HDI_FORMAT;
- item.cxy = 200; // TODO
- item.pszText = (WCHAR *) lParam;
- item.fmt = HDF_LEFT | HDF_STRING;
- if (SendMessage(t->header, HDM_INSERTITEM, (WPARAM) (t->nColumns - 1), (LPARAM) (&item)) == (LRESULT) (-1))
- abort();
- // TODO resize(t)?
- redrawAll(t);
-}
-
-static void hscrollto(struct table *t, intptr_t newpos)
-{
- SCROLLINFO si;
- RECT scrollArea;
-
- if (newpos < 0)
- newpos = 0;
- if (newpos > (t->width - t->hpagesize))
- newpos = (t->width - t->hpagesize);
-
- scrollArea = realClientRect(t);
-
- // negative because ScrollWindowEx() is "backwards"
- if (ScrollWindowEx(t->hwnd, -(newpos - t->hpos), 0,
- &scrollArea, &scrollArea, NULL, NULL,
- SW_ERASE | SW_INVALIDATE) == ERROR)
- abort();
- t->hpos = newpos;
- // TODO text in header controls doesn't redraw?
-
- // TODO put this in a separate function? same for vscroll?
- ZeroMemory(&si, sizeof (SCROLLINFO));
- si.cbSize = sizeof (SCROLLINFO);
- si.fMask = SIF_PAGE | SIF_POS | SIF_RANGE;
- si.nPage = t->hpagesize;
- si.nMin = 0;
- si.nMax = t->width - 1; // nMax is inclusive
- si.nPos = t->hpos;
- SetScrollInfo(t->hwnd, SB_HORZ, &si, TRUE);
-
- // and finally reposition the header
- repositionHeader(t);
-}
-
-static void hscrollby(struct table *t, intptr_t n)
-{
- hscrollto(t, t->hpos + n);
-}
-
-// unfortunately horizontal wheel scrolling was only added in Vista
-
-static void hscroll(struct table *t, WPARAM wParam)
-{
- SCROLLINFO si;
- intptr_t newpos;
-
- ZeroMemory(&si, sizeof (SCROLLINFO));
- si.cbSize = sizeof (SCROLLINFO);
- si.fMask = SIF_POS | SIF_TRACKPOS;
- if (GetScrollInfo(t->hwnd, SB_HORZ, &si) == 0)
- abort();
-
- newpos = t->hpos;
- switch (LOWORD(wParam)) {
- case SB_LEFT:
- newpos = 0;
- break;
- case SB_RIGHT:
- newpos = t->width - t->hpagesize;
- break;
- case SB_LINELEFT:
- newpos--;
- break;
- case SB_LINERIGHT:
- newpos++;
- break;
- case SB_PAGELEFT:
- newpos -= t->hpagesize;
- break;
- case SB_PAGERIGHT:
- newpos += t->hpagesize;
- break;
- case SB_THUMBPOSITION:
- newpos = (intptr_t) (si.nPos);
- break;
- case SB_THUMBTRACK:
- newpos = (intptr_t) (si.nTrackPos);
- }
-
- hscrollto(t, newpos);
-}
-
-static void recomputeHScroll(struct table *t)
-{
- HDITEMW item;
- intptr_t i;
- int width = 0;
- RECT r;
- SCROLLINFO si;
-
- // TODO count dividers
- for (i = 0; i < t->nColumns; i++) {
- ZeroMemory(&item, sizeof (HDITEMW));
- item.mask = HDI_WIDTH;
- if (SendMessageW(t->header, HDM_GETITEM, (WPARAM) i, (LPARAM) (&item)) == FALSE)
- abort();
- width += item.cxy;
- }
- t->width = (intptr_t) width;
-
- if (GetClientRect(t->hwnd, &r) == 0)
- abort();
- t->hpagesize = r.right - r.left;
-
- ZeroMemory(&si, sizeof (SCROLLINFO));
- si.cbSize = sizeof (SCROLLINFO);
- si.fMask = SIF_PAGE | SIF_RANGE;
- si.nPage = t->hpagesize;
- si.nMin = 0;
- si.nMax = t->width - 1; // - 1 because endpoints inclusive
- SetScrollInfo(t->hwnd, SB_HORZ, &si, TRUE);
-}
-
-static void vscrollto(struct table *t, intptr_t newpos)
-{
- SCROLLINFO si;
- RECT scrollArea;
-
- if (newpos < 0)
- newpos = 0;
- if (newpos > (t->count - t->pagesize))
- newpos = (t->count - t->pagesize);
-
- scrollArea = realClientRect(t);
-
- // negative because ScrollWindowEx() is "backwards"
- if (ScrollWindowEx(t->hwnd, 0, (-(newpos - t->firstVisible)) * rowHeight(t),
- &scrollArea, &scrollArea, NULL, NULL,
- SW_ERASE | SW_INVALIDATE) == ERROR)
- abort();
- t->firstVisible = newpos;
-
- ZeroMemory(&si, sizeof (SCROLLINFO));
- si.cbSize = sizeof (SCROLLINFO);
- si.fMask = SIF_PAGE | SIF_POS | SIF_RANGE;
- si.nPage = t->pagesize;
- si.nMin = 0;
- si.nMax = t->count - 1; // nMax is inclusive
- si.nPos = t->firstVisible;
- SetScrollInfo(t->hwnd, SB_VERT, &si, TRUE);
-}
-
-static void vscrollby(struct table *t, intptr_t n)
-{
- vscrollto(t, t->firstVisible + n);
-}
-
-static void wheelscroll(struct table *t, WPARAM wParam)
-{
- int delta;
- int lines;
- UINT scrollAmount;
-
- delta = GET_WHEEL_DELTA_WPARAM(wParam);
- if (SystemParametersInfoW(SPI_GETWHEELSCROLLLINES, 0, &scrollAmount, 0) == 0)
- abort();
- if (scrollAmount == WHEEL_PAGESCROLL)
- scrollAmount = t->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 += t->wheelCarry;
- lines = delta * ((int) scrollAmount) / WHEEL_DELTA;
- t->wheelCarry = delta - lines * WHEEL_DELTA / ((int) scrollAmount);
- vscrollby(t, -lines);
-}
-
-static void vscroll(struct table *t, WPARAM wParam)
-{
- SCROLLINFO si;
- intptr_t newpos;
-
- ZeroMemory(&si, sizeof (SCROLLINFO));
- si.cbSize = sizeof (SCROLLINFO);
- si.fMask = SIF_POS | SIF_TRACKPOS;
- if (GetScrollInfo(t->hwnd, SB_VERT, &si) == 0)
- abort();
-
- newpos = t->firstVisible;
- switch (LOWORD(wParam)) {
- case SB_TOP:
- newpos = 0;
- break;
- case SB_BOTTOM:
- newpos = t->count - t->pagesize;
- break;
- case SB_LINEUP:
- newpos--;
- break;
- case SB_LINEDOWN:
- newpos++;
- break;
- case SB_PAGEUP:
- newpos -= t->pagesize;
- break;
- case SB_PAGEDOWN:
- newpos += t->pagesize;
- break;
- case SB_THUMBPOSITION:
- newpos = (intptr_t) (si.nPos);
- break;
- case SB_THUMBTRACK:
- newpos = (intptr_t) (si.nTrackPos);
- }
-
- vscrollto(t, newpos);
-}
+#include "util.h"
+#include "api.h"
+#include "hscroll.h"
+#include "vscroll.h"
static void finishSelect(struct table *t, intptr_t prev)
{
diff --git a/wintable/util.h b/wintable/util.h
new file mode 100644
index 0000000..c12435f
--- /dev/null
+++ b/wintable/util.h
@@ -0,0 +1,136 @@
+// 29 november 2014
+
+static LONG rowHeight(struct table *t)
+{
+ HFONT thisfont, prevfont;
+ TEXTMETRICW tm;
+ HDC dc;
+ LONG ret;
+
+ dc = GetDC(t->hwnd);
+ if (dc == NULL)
+ abort();
+ thisfont = t->font; // in case WM_SETFONT happens before we return
+ prevfont = (HFONT) SelectObject(dc, thisfont);
+ if (prevfont == NULL)
+ abort();
+ if (GetTextMetricsW(dc, &tm) == 0)
+ abort();
+ if (SelectObject(dc, prevfont) != (HGDIOBJ) (thisfont))
+ abort();
+ if (ReleaseDC(t->hwnd, dc) == 0)
+ abort();
+ ret = tm.tmHeight;
+ if (ret < t->imagelistHeight)
+ ret = t->imagelistHeight;
+ if (ret < t->checkboxHeight)
+ ret = t->checkboxHeight;
+ return ret;
+}
+
+static void redrawAll(struct table *t)
+{
+ if (InvalidateRect(t->hwnd, NULL, TRUE) == 0)
+ abort();
+ if (UpdateWindow(t->hwnd) == 0)
+ abort();
+}
+
+static RECT realClientRect(struct table *t)
+{
+ RECT r;
+
+ if (GetClientRect(t->hwnd, &r) == 0)
+ abort();
+ r.top += t->headerHeight;
+ return r;
+}
+
+static void repositionHeader(struct table *t)
+{
+ RECT r;
+ HDLAYOUT headerlayout;
+ WINDOWPOS headerpos;
+
+ if (GetClientRect(t->hwnd, &r) == 0) // use the whole client rect
+ abort();
+ // grow the rectangle to the left to fake scrolling
+ r.left -= t->hpos;
+ headerlayout.prc = &r;
+ headerlayout.pwpos = &headerpos;
+ if (SendMessageW(t->header, HDM_LAYOUT, 0, (LPARAM) (&headerlayout)) == FALSE)
+ abort();
+ if (SetWindowPos(t->header, headerpos.hwndInsertAfter, headerpos.x, headerpos.y, headerpos.cx, headerpos.cy, headerpos.flags | SWP_SHOWWINDOW) == 0)
+ abort();
+ t->headerHeight = headerpos.cy;
+}
+
+// this counts partially visible rows
+// for all fully visible rows use t->pagesize
+// cliprect and rowHeight must be specified here to avoid recomputing things multiple times
+static intptr_t lastVisible(struct table *t, RECT cliprect, LONG rowHeight)
+{
+ intptr_t last;
+
+ last = ((cliprect.bottom + rowHeight - 1) / rowHeight) + t->firstVisible;
+ if (last >= t->count)
+ last = t->count;
+ return last;
+}
+
+static void redrawRow(struct table *t, intptr_t row)
+{
+ RECT r;
+ intptr_t height;
+
+ r = realClientRect(t);
+ height = rowHeight(t);
+ if (row < t->firstVisible || row > lastVisible(t, r, height)) // not visible; don't bother
+ return;
+ r.top = (row - t->firstVisible) * height + t->headerHeight;
+ r.bottom = r.top + height;
+ // keep the width and height the same; it spans the client area anyway
+ if (InvalidateRect(t->hwnd, &r, TRUE) == 0)
+ abort();
+ if (UpdateWindow(t->hwnd) == 0)
+ abort();
+}
+
+static intptr_t hitTestColumn(struct table *t, int x)
+{
+ HDITEMW item;
+ intptr_t i;
+
+ // TODO count dividers
+ for (i = 0; i < t->nColumns; i++) {
+ ZeroMemory(&item, sizeof (HDITEMW));
+ item.mask = HDI_WIDTH;
+ if (SendMessageW(t->header, HDM_GETITEM, (WPARAM) i, (LPARAM) (&item)) == FALSE)
+ abort();
+ if (x < item.cxy)
+ return i;
+ x -= item.cxy; // not yet
+ }
+ // no column
+ return -1;
+}
+
+static void lParamToRowColumn(struct table *t, LPARAM lParam, intptr_t *row, intptr_t *column)
+{
+ int x, y;
+ LONG h;
+
+ x = GET_X_LPARAM(lParam);
+ y = GET_Y_LPARAM(lParam);
+ h = rowHeight(t);
+ y += t->firstVisible * h;
+ y -= t->headerHeight;
+ y /= h;
+ if (row != NULL) {
+ *row = y;
+ if (*row >= t->count)
+ *row = -1;
+ }
+ if (column != NULL)
+ *column = hitTestColumn(t, x);
+}
diff --git a/wintable/vscroll.h b/wintable/vscroll.h
new file mode 100644
index 0000000..7f2d912
--- /dev/null
+++ b/wintable/vscroll.h
@@ -0,0 +1,97 @@
+// 29 november 2014
+
+static void vscrollto(struct table *t, intptr_t newpos)
+{
+ SCROLLINFO si;
+ RECT scrollArea;
+
+ if (newpos < 0)
+ newpos = 0;
+ if (newpos > (t->count - t->pagesize))
+ newpos = (t->count - t->pagesize);
+
+ scrollArea = realClientRect(t);
+
+ // negative because ScrollWindowEx() is "backwards"
+ if (ScrollWindowEx(t->hwnd, 0, (-(newpos - t->firstVisible)) * rowHeight(t),
+ &scrollArea, &scrollArea, NULL, NULL,
+ SW_ERASE | SW_INVALIDATE) == ERROR)
+ abort();
+ t->firstVisible = newpos;
+
+ ZeroMemory(&si, sizeof (SCROLLINFO));
+ si.cbSize = sizeof (SCROLLINFO);
+ si.fMask = SIF_PAGE | SIF_POS | SIF_RANGE;
+ si.nPage = t->pagesize;
+ si.nMin = 0;
+ si.nMax = t->count - 1; // nMax is inclusive
+ si.nPos = t->firstVisible;
+ SetScrollInfo(t->hwnd, SB_VERT, &si, TRUE);
+}
+
+static void vscrollby(struct table *t, intptr_t n)
+{
+ vscrollto(t, t->firstVisible + n);
+}
+
+static void wheelscroll(struct table *t, WPARAM wParam)
+{
+ int delta;
+ int lines;
+ UINT scrollAmount;
+
+ delta = GET_WHEEL_DELTA_WPARAM(wParam);
+ if (SystemParametersInfoW(SPI_GETWHEELSCROLLLINES, 0, &scrollAmount, 0) == 0)
+ abort();
+ if (scrollAmount == WHEEL_PAGESCROLL)
+ scrollAmount = t->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 += t->wheelCarry;
+ lines = delta * ((int) scrollAmount) / WHEEL_DELTA;
+ t->wheelCarry = delta - lines * WHEEL_DELTA / ((int) scrollAmount);
+ vscrollby(t, -lines);
+}
+
+static void vscroll(struct table *t, WPARAM wParam)
+{
+ SCROLLINFO si;
+ intptr_t newpos;
+
+ ZeroMemory(&si, sizeof (SCROLLINFO));
+ si.cbSize = sizeof (SCROLLINFO);
+ si.fMask = SIF_POS | SIF_TRACKPOS;
+ if (GetScrollInfo(t->hwnd, SB_VERT, &si) == 0)
+ abort();
+
+ newpos = t->firstVisible;
+ switch (LOWORD(wParam)) {
+ case SB_TOP:
+ newpos = 0;
+ break;
+ case SB_BOTTOM:
+ newpos = t->count - t->pagesize;
+ break;
+ case SB_LINEUP:
+ newpos--;
+ break;
+ case SB_LINEDOWN:
+ newpos++;
+ break;
+ case SB_PAGEUP:
+ newpos -= t->pagesize;
+ break;
+ case SB_PAGEDOWN:
+ newpos += t->pagesize;
+ break;
+ case SB_THUMBPOSITION:
+ newpos = (intptr_t) (si.nPos);
+ break;
+ case SB_THUMBTRACK:
+ newpos = (intptr_t) (si.nTrackPos);
+ }
+
+ vscrollto(t, newpos);
+}