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)