andlabs-ui/wintable/util.h

137 lines
3.1 KiB
C
Raw Normal View History

// 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);
}