summaryrefslogtreecommitdiff
path: root/wintable/util.h
diff options
context:
space:
mode:
Diffstat (limited to 'wintable/util.h')
-rw-r--r--wintable/util.h136
1 files changed, 136 insertions, 0 deletions
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);
+}