diff --git a/windows/tablemetrics.cpp b/windows/tablemetrics.cpp new file mode 100644 index 00000000..76c879c7 --- /dev/null +++ b/windows/tablemetrics.cpp @@ -0,0 +1,135 @@ +// 14 june 2018 +#include "uipriv_windows.hpp" +#include "table.hpp" + +struct uiprivTableMetrics { + uiTable *t; + uiTableModel *m; + uiprivTableColumnParams *p; + + int iItem; + int iSubItem; + BOOL hasText; + BOOL hasImage; + BOOL focused; + BOOL selected; + + RECT itemBounds; + RECT itemIcon; + RECT itemLabel; + RECT subitemBounds; + RECT subitemIcon; + RECT subitemLabel; + + LRESULT bitmapMargin; + int cxIcon; + int cyIcon; + + RECT realTextBackground; + RECT realTextRect; +}; + +static HRESULT itemRect(HRESULT hr, uiTable *t, UINT uMsg, WPARAM wParam, LONG left, LONG top, LRESULT bad, RECT *r) +{ + if (hr != S_OK) + return hr; + ZeroMemory(r, sizeof (RECT)); + r->left = left; + r->top = top; + if (SendMessageW(t->hwnd, uMsg, wParam, (LPARAM) r) == bad) { + logLastError(L"itemRect() message"); + return E_FAIL; + } + return S_OK; +} + +HRESULT uiprivTableGetMetrics(uiTable *t, int iItem, int iSubItem, uiprivTableMetrics **mout) +{ + uiprivTableMetrics *m; + LRESULT state; + HWND header; + RECT r; + HRESULT hr; + + if (mout == NULL) + return E_POINTER; + + m = uiprivNew(uiprivTableMetrics); + m->t = t; + m->m = t->model; + m->p = (*(t->columns))[iSubItem]; + + m->iItem = iItem; + m->iSubItem = iSubItem; + m->hasText = m->p->textModelColumn != -1; + m->hasImage = (m->p->imageModelColumn != -1) || (m->p->checkboxModelColumn != -1); + state = SendMessageW(t->hwnd, LVM_GETITEMSTATE, iItem, LVIS_FOCUSED | LVIS_SELECTED); + m->focused = (state & LVIS_FOCUSED) != 0; + m->selected = (state & LVIS_SELECTED) != 0; + + // TODO check LRESULT bad parameters here + hr = itemRect(S_OK, t, LVM_GETITEMRECT, s->iItem, + LVIR_BOUNDS, 0, FALSE, &(m->itemBounds)); + hr = itemRect(hr, t, LVM_GETITEMRECT, s->iItem, + LVIR_ICON, 0, FALSE, &(m->itemIcon)); + hr = itemRect(hr, t, LVM_GETITEMRECT, s->iItem, + LVIR_LABEL, 0, FALSE, &(m->itemLabel)); + hr = itemRect(hr, t, LVM_GETSUBITEMRECT, s->iItem, + LVIR_BOUNDS, s->iSubItem, 0, &(m->subitemBounds)); + hr = itemRect(hr, t, LVM_GETSUBITEMRECT, s->iItem, + LVIR_ICON, s->iSubItem, 0, &(m->subitemIcon)); + if (hr != S_OK) + goto fail; + // LVM_GETSUBITEMRECT treats LVIR_LABEL as the same as + // LVIR_BOUNDS, so we can't use that directly. Instead, let's + // assume the text is immediately after the icon. The correct + // rect will be determined by + // computeOtherRectsAndDrawBackgrounds() above. + m->subitemLabel = m->subitemBounds; + m->subitemLabel.left = m->subitemIcon.right; + // And on iSubItem == 0, LVIF_GETSUBITEMRECT still includes + // all the subitems, which we don't want. + if (iSubItem == 0) { + m->subitemBounds.right = m->itemLabel.right; + m->subitemLabel.right = m->itemLabel.right; + } + + header = (HWND) SendMessageW(t->hwnd, LVM_GETHEADER, 0, 0); + m->bitmapMargin = SendMessageW(header, HDM_GETBITMAPMARGIN, 0, 0); + if (ImageList_GetIconSize(t->imagelist, &(m->cxIcon), &(m->cyIcon)) == 0) { + logLastError(L"ImageList_GetIconSize()"); + hr = E_FAIL; + goto fail; + } + + r = m->subitemLabel; + if (!m->hasText && !m->hasImage) + r = s->subitemBounds; + else if (!m->hasImage && iSubItem != 0) + // By default, this will include images; we're not drawing + // images, so we will manually draw over the image area. + // There's a second part to this; see below. + r.left = m->subitemBounds.left; + m->realTextBackground = r; + + m->realTextRect = r; + // TODO confirm whether this really happens on column 0 as well + if (m->hasImage && iSubItem != 0) + // Normally there's this many hard-coded logical units + // of blank space, followed by the background, followed + // by a bitmap margin's worth of space. This looks bad, + // so we overrule that to start the background immediately + // and the text after the hard-coded amount. + m->realTextRect.left += 2; + else if (iSubItem != 0) + // In the case of subitem text without an image, we draw + // text one bitmap margin away from the left edge. + m->realTextRect.left += m->bitmapMargin; + + *mout = m; + return S_OK; +fail: + uiprivFree(m); + *mout = NULL; + return hr; +}