From d23cdd76827728a4f7eb6b0afa9b6e572aab964c Mon Sep 17 00:00:00 2001 From: Pietro Gagliardi Date: Sat, 29 Nov 2014 18:29:50 -0500 Subject: [PATCH] Started splitting the new Windows Table code into more manageable chunks. --- wintable/api.h | 25 +++ wintable/hscroll.h | 114 ++++++++++++++ wintable/main.c | 371 +-------------------------------------------- wintable/util.h | 136 +++++++++++++++++ wintable/vscroll.h | 97 ++++++++++++ 5 files changed, 376 insertions(+), 367 deletions(-) create mode 100644 wintable/api.h create mode 100644 wintable/hscroll.h create mode 100644 wintable/util.h create mode 100644 wintable/vscroll.h 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); +}