diff --git a/wintablemetrics b/wintablemetrics new file mode 100644 index 00000000..5c00e252 --- /dev/null +++ b/wintablemetrics @@ -0,0 +1,153 @@ +diff --git a/windows/table.cpp b/windows/table.cpp +index 32c60244..d33cb22f 100644 +--- a/windows/table.cpp ++++ b/windows/table.cpp +@@ -137,11 +137,71 @@ static COLORREF blend(COLORREF base, double r, double g, double b, double a) + (BYTE) (bb * 255)); + } + ++static HRESULT fillSubitemDrawParams(HWND hwnd, NMLVCUSTOMDRAW *nm, uiprivSubitemDrawParams *dp) ++{ ++ RECT r; ++ HRESULT hr; ++ ++ // note that we can't just copy nm->nmcd.rc into p->bounds because that is only defined during prepaint stages ++ ++ if (nm->iSubItem == 0) {return S_OK; ++ ZeroMemory(&r, sizeof (RECT)); ++ r.left = LVIR_BOUNDS; ++ if (SendMessageW(hwnd, LVM_GETITEMRECT, nm->nmcd.dwItemSpec, (LPARAM) (&r)) == FALSE) { ++ logLastError(L"LVM_GETITEMRECT LVIR_BOUNDS"); ++ return E_FAIL; ++ } ++ dp->bounds = r; ++ ZeroMemory(&r, sizeof (RECT)); ++ r.left = LVIR_ICON; ++ if (SendMessageW(hwnd, LVM_GETITEMRECT, nm->nmcd.dwItemSpec, (LPARAM) (&r)) == FALSE) { ++ logLastError(L"LVM_GETITEMRECT LVIR_ICON"); ++ return E_FAIL; ++ } ++ dp->icon = r; ++ ZeroMemory(&r, sizeof (RECT)); ++ r.left = LVIR_LABEL; ++ if (SendMessageW(hwnd, LVM_GETITEMRECT, nm->nmcd.dwItemSpec, (LPARAM) (&r)) == FALSE) { ++ logLastError(L"LVM_GETITEMRECT LVIR_LABEL"); ++ return E_FAIL; ++ } ++ dp->label = r; ++ return S_OK; ++ } ++ ++ ZeroMemory(&r, sizeof (RECT)); ++ r.left = LVIR_BOUNDS; ++ r.top = nm->iSubItem; ++ if (SendMessageW(hwnd, LVM_GETSUBITEMRECT, nm->nmcd.dwItemSpec, (LPARAM) (&r)) == 0) { ++ logLastError(L"LVM_GETSUBITEMRECT LVIR_BOUNDS"); ++ return E_FAIL; ++ } ++ dp->bounds = r; ++ ZeroMemory(&r, sizeof (RECT)); ++ r.left = LVIR_ICON; ++ r.top = nm->iSubItem; ++ if (SendMessageW(hwnd, LVM_GETSUBITEMRECT, nm->nmcd.dwItemSpec, (LPARAM) (&r)) == 0) { ++ logLastError(L"LVM_GETSUBITEMRECT LVIR_ICON"); ++ return E_FAIL; ++ } ++ dp->icon = r; ++ // LVIR_LABEL is treated as LVIR_BOUNDS for LVM_GETSUBITEMRECT, but it doesn't matter because the label rect is uses isn't what we want anyway ++ // there's a hardocded 2-logical unit gap between the icon and text for subitems, AND the text starts being drawn (in the background) one bitmap margin to the right of that ++ // with normal items, there's no gap, and only the 2-logical unit gap after the background starts (TODO confirm this part) ++ // let's copy that to look nicer, even if it's not "accurate" ++ // TODO check against accessibility ++ dp->label = dp->bounds; ++ // because we want the 2 extra logical units to be included with the background, we don't include them here ++ dp->label.left = dp->icon.right; ++ return S_OK; ++} ++ + static LRESULT onNM_CUSTOMDRAW(uiTable *t, NMLVCUSTOMDRAW *nm) + { + uiprivTableColumnParams *p; + uiTableData *data; + double r, g, b, a; ++ uiprivSubitemDrawParams dp; + LRESULT ret; + HRESULT hr; + +@@ -193,7 +253,12 @@ DrawTextW(nm->nmcd.hdc, L"Part", -1, + ret = CDRF_DODEFAULT; + } + +- hr = uiprivNM_CUSTOMDRAWImagesCheckboxes(t, nm, &ret); ++ ZeroMemory(&dp, sizeof (uiprivSubitemDrawParams)); ++ hr = fillSubitemDrawParams(t->hwnd, nm, &dp); ++ if (hr != S_OK) { ++ // TODO ++ } ++ hr = uiprivNM_CUSTOMDRAWImagesCheckboxes(t, nm, &dp, &ret); + if (hr != S_OK) { + // TODO + } +diff --git a/windows/table.hpp b/windows/table.hpp +index 0be01d8f..2f4f6936 100644 +--- a/windows/table.hpp ++++ b/windows/table.hpp +@@ -43,8 +43,14 @@ struct uiTable { + // custom draw state + COLORREF clrItemText; + }; ++typedef struct uiprivSubitemDrawParams uiprivSubitemDrawParams; ++struct uiprivSubitemDrawParams { ++ RECT bounds; ++ RECT icon; ++ RECT label; ++}; + + // tableimages.cpp + extern HRESULT uiprivLVN_GETDISPINFOImagesCheckboxes(uiTable *t, NMLVDISPINFOW *nm, uiprivTableColumnParams *p); +-extern HRESULT uiprivNM_CUSTOMDRAWImagesCheckboxes(uiTable *t, NMLVCUSTOMDRAW *nm, LRESULT *lResult); ++extern HRESULT uiprivNM_CUSTOMDRAWImagesCheckboxes(uiTable *t, NMLVCUSTOMDRAW *nm, uiprivSubitemDrawParams *dp, LRESULT *lResult); + extern HRESULT uiprivTableSetupImagesCheckboxes(uiTable *t); +diff --git a/windows/tableimages.cpp b/windows/tableimages.cpp +index a42307b1..14bae8c8 100644 +--- a/windows/tableimages.cpp ++++ b/windows/tableimages.cpp +@@ -139,12 +139,11 @@ HRESULT uiprivLVN_GETDISPINFOImagesCheckboxes(uiTable *t, NMLVDISPINFOW *nm, uip + // however, there seems to be no way to do this natively, so we have to draw over ourselves (TODO?) + // hopefully the performance won't be too bad + // see also https://www.codeproject.com/Articles/79/Neat-Stuff-to-Do-in-List-Controls-Using-Custom-Dra +-HRESULT uiprivNM_CUSTOMDRAWImagesCheckboxes(uiTable *t, NMLVCUSTOMDRAW *nm, LRESULT *lResult) ++HRESULT uiprivNM_CUSTOMDRAWImagesCheckboxes(uiTable *t, NMLVCUSTOMDRAW *nm, uiprivSubitemDrawParams *dp, LRESULT *lResult) + { + uiprivTableColumnParams *p; + int index; + RECT r; +- RECT cellRect; + LONG yoff; + + if (nm->nmcd.dwDrawStage == (CDDS_SUBITEM | CDDS_ITEMPREPAINT)) { +@@ -161,22 +160,9 @@ HRESULT uiprivNM_CUSTOMDRAWImagesCheckboxes(uiTable *t, NMLVCUSTOMDRAW *nm, LRES + + index = checkboxIndex(t->model, nm->nmcd.dwItemSpec, + p->checkboxModelColumn, p->checkboxEditableColumn); +- ZeroMemory(&r, sizeof (RECT)); +- r.left = LVIR_ICON; +- r.top = nm->iSubItem; +- if (SendMessageW(t->hwnd, LVM_GETSUBITEMRECT, nm->nmcd.dwItemSpec, (LPARAM) (&r)) == 0) { +- logLastError(L"LVM_GETSUBITEMRECT"); +- return E_FAIL; +- } ++ r = dp->icon; + // the real listview also does this :| +- ZeroMemory(&cellRect, sizeof (RECT)); +- r.left = LVIR_BOUNDS; +- r.top = nm->iSubItem; +- if (SendMessageW(t->hwnd, LVM_GETSUBITEMRECT, nm->nmcd.dwItemSpec, (LPARAM) (&cellRect)) == 0) { +- logLastError(L"LVM_GETSUBITEMRECT cell"); +- return E_FAIL; +- } +- yoff = ((cellRect.bottom - cellRect.top) - (r.bottom - r.top)) / 2; ++ yoff = ((dp->bounds.bottom - dp->bounds.top) - (r.bottom - r.top)) / 2; + r.top += yoff; + r.bottom += yoff; + if ((nm->nmcd.dwItemSpec%2)==0)