From 1dcdcd522cf1e63fd61f4ca376d4108a775a1565 Mon Sep 17 00:00:00 2001 From: Pietro Gagliardi Date: Thu, 8 Jan 2015 01:45:06 -0500 Subject: [PATCH] Collected all of the metric updating stuff into a single update() function. Far from optimal, but much better. --- wintable/api.h | 13 ++++++++----- wintable/header.h | 41 +++++------------------------------------ wintable/main.h | 4 ++++ wintable/resize.h | 23 ++--------------------- wintable/test.c | 3 ++- wintable/update.h | 44 ++++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 65 insertions(+), 63 deletions(-) create mode 100644 wintable/update.h diff --git a/wintable/api.h b/wintable/api.h index bf259ad..260202e 100644 --- a/wintable/api.h +++ b/wintable/api.h @@ -9,7 +9,7 @@ static void addColumn(struct table *t, WPARAM wParam, LPARAM lParam) if (t->columnTypes[t->nColumns - 1] >= nTableColumnTypes) panic("invalid column type passed to tableAddColumn"); headerAddColumn(t, (WCHAR *) lParam); - updateTableWidth(t); + update(t, TRUE); } HANDLER(apiHandlers) @@ -21,8 +21,11 @@ HANDLER(apiHandlers) // don't free the old font; see http://blogs.msdn.com/b/oldnewthing/archive/2008/09/12/8945692.aspx t->font = (HFONT) wParam; SendMessageW(t->header, WM_SETFONT, wParam, lParam); - // TODO how to properly handle LOWORD(lParam) != FALSE? - // TODO depending on the result of the above, update table width to refresh t->headerHeight? + update(t, LOWORD(lParam) != FALSE); + // TODO is this needed? + if (LOWORD(lParam) != FALSE) + // TODO check error + InvalidateRect(t->hwnd, NULL, TRUE); *lResult = 0; return TRUE; case WM_GETFONT: @@ -35,8 +38,8 @@ HANDLER(apiHandlers) case tableSetRowCount: rcp = (intptr_t *) lParam; t->count = *rcp; - // TODO refresh table in this way? - updateTableWidth(t); + // TODO shouldn't we just redraw everything? + update(t, TRUE); *lResult = 0; return TRUE; } diff --git a/wintable/header.h b/wintable/header.h index 5652029..863d3d0 100644 --- a/wintable/header.h +++ b/wintable/header.h @@ -22,6 +22,9 @@ static void destroyHeader(struct table *t) panic("error destroying Table header"); } +// to avoid weird bugs, the only functions allowed to call this one are the horizontal scroll functions +// when we need to reposition the header in a situation other than a user-initiated scroll, we use a dummy scroll (hscrollby(t, 0)) +// see update() in update.h static void repositionHeader(struct table *t) { RECT r; @@ -58,40 +61,6 @@ static void headerAddColumn(struct table *t, WCHAR *name) panic("error adding column to Table header"); } -// TODO make a better name for this? -// TODO move to hscroll.h? -// TODO organize this in general... -// TODO because of this function's new extended functionality only hscrollto() is allowed to call repositionHeader() -static void updateTableWidth(struct table *t) -{ - HDITEMW item; - intptr_t i; - RECT client; - - t->width = 0; - // TODO count dividers? - // TODO use columnWidth() - 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) - panic("error getting Table column width for updateTableWidth()"); - t->width += item.cxy; - } - - if (GetClientRect(t->hwnd, &client) == 0) - panic("error getting Table client rect in updateTableWidth()"); - t->hpagesize = client.right - client.left; - - // this part is critical: if we resize the columns to less than the client area width, then the following hscrollby() will make t->hscrollpos negative, which does very bad things - // note to self: do this regardless of whether the table width or the client area width was changed - if (t->hpagesize > t->width) - t->hpagesize = t->width; - - // do a dummy scroll to update the horizontal scrollbar to use the new width - hscrollby(t, 0); -} - HANDLER(headerNotifyHandler) { NMHDR *nmhdr = (NMHDR *) lParam; @@ -100,10 +69,10 @@ HANDLER(headerNotifyHandler) return FALSE; if (nmhdr->code != HDN_ITEMCHANGED) return FALSE; - updateTableWidth(t); + update(t, TRUE); // TODO make more intelligent + // (TODO is it actually needed?) InvalidateRect(t->hwnd, NULL, TRUE); - // TODO UpdateWindow()? *lResult = 0; return TRUE; } diff --git a/wintable/main.h b/wintable/main.h index c8ba30c..ba85e7a 100644 --- a/wintable/main.h +++ b/wintable/main.h @@ -103,6 +103,9 @@ struct table { // forward declaration (TODO needed?) static LRESULT notify(struct table *, UINT, intptr_t, intptr_t, uintptr_t); +// necessary forward declaration +static void update(struct table *, BOOL); + #include "util.h" #include "coord.h" #include "scroll.h" @@ -117,6 +120,7 @@ static LRESULT notify(struct table *, UINT, intptr_t, intptr_t, uintptr_t); #include "draw.h" #include "api.h" #include "accessibility.h" +#include "update.h" static const handlerfunc handlers[] = { eventHandlers, diff --git a/wintable/resize.h b/wintable/resize.h index 2ffaad7..ae669e3 100644 --- a/wintable/resize.h +++ b/wintable/resize.h @@ -3,37 +3,18 @@ // TODO why doesn't this trigger on first show? // TODO see if there's anything not metaphor related in the last bits of the scrollbar series // TODO rename this to boot +// TODO merge with update.h? HANDLER(resizeHandler) { WINDOWPOS *wp; - RECT client; - intptr_t height; if (uMsg != WM_WINDOWPOSCHANGED) return FALSE; wp = (WINDOWPOS *) lParam; if ((wp->flags & SWP_NOSIZE) != 0) return FALSE; - - // TODO does wp store the window rect or the client rect? - if (GetClientRect(t->hwnd, &client) == 0) - panic("error getting Table client rect in resizeHandler()"); - // TODO do this after calling updateTableWidth() (which calls repositionHeader()?)? - client.top += t->headerHeight; - - // update the width... - // this will call repositionHeader(); there's a good reason... (see comments) - // TODO when I clean that mess up, remove this comment - updateTableWidth(t); - - // ...and the height - // TODO find out if order matters - height = client.bottom - client.top; - t->vpagesize = height / rowht(t); - // do a dummy scroll to reflect those changes - vscrollby(t, 0); - + update(t, TRUE); *lResult = 0; return TRUE; } diff --git a/wintable/test.c b/wintable/test.c index 6d38bd1..d3f75ab 100644 --- a/wintable/test.c +++ b/wintable/test.c @@ -117,7 +117,8 @@ int main(int argc, char *argv[]) INITCOMMONCONTROLSEX icc; WNDCLASSW wc; - mkbitmap(); + if (argc != 1) + msgfont = TRUE; ZeroMemory(&icc, sizeof (INITCOMMONCONTROLSEX)); icc.dwSize = sizeof (INITCOMMONCONTROLSEX); icc.dwICC = ICC_LISTVIEW_CLASSES; diff --git a/wintable/update.h b/wintable/update.h new file mode 100644 index 0000000..c4beea7 --- /dev/null +++ b/wintable/update.h @@ -0,0 +1,44 @@ +// 8 january 2015 + +// Whenever a number of things in the Table changes, the update() function needs to be called to update any metrics and scrolling positions. +// The control font changing is the big one, as that comes with a flag that decides whether or not to redraw everything. We'll need to respect that here. + +// TODO actually use redraw here +static void update(struct table *t, int redraw) +{ + RECT client; + intptr_t i; + intptr_t height; + + // before we do anything we need the client rect + if (GetClientRect(t->hwnd, &client) == 0) + panic("error getting Table client rect in update()"); + + // the first step is to figure out how wide the whole table is + // TODO count dividers? + t->width = 0; + for (i = 0; i < t->nColumns; i++) + t->width += columnWidth(t, i); + + // now we need to figure out how much of the width of the table can be seen at once + t->hpagesize = client.right - client.left; + // this part is critical: if we resize the columns to less than the client area width, then the following hscrollby() will make t->hscrollpos negative, which does very bad things + // we do this regardless of which of the two has changed, just to be safe + if (t->hpagesize > t->width) + t->hpagesize = t->width; + + // now we do a dummy horizontal scroll to apply the new width and horizontal page size + // this will also reposition and resize the header (the latter in case the font changed), which will be important for the next step + hscrollby(t, 0); + + // now that we have the new height of the header, we can fix up vertical scrolling + // so let's take the header height away from the client area + client.top += t->headerHeight; + // and update our page size appropriately + height = client.bottom - client.top; + t->vpagesize = height / rowht(t); + // and do a dummy vertical scroll to apply that + vscrollby(t, 0); + + // TODO invalidate /everything/? +}