Integrated tablemetrics.cpp with tabledraw.cpp.

This commit is contained in:
Pietro Gagliardi 2018-06-20 18:03:56 -04:00
parent ec07b12295
commit 5ae45a1fcb
4 changed files with 78 additions and 169 deletions

View File

@ -54,6 +54,7 @@ list(APPEND _LIBUI_SOURCES
windows/tabledispinfo.cpp windows/tabledispinfo.cpp
windows/tabledraw.cpp windows/tabledraw.cpp
windows/tableediting.cpp windows/tableediting.cpp
windows/tablemetrics.cpp
windows/tabpage.cpp windows/tabpage.cpp
windows/text.cpp windows/text.cpp
windows/utf16.cpp windows/utf16.cpp

View File

@ -34,6 +34,7 @@ struct uiTable {
// TODO document all this // TODO document all this
std::map<std::pair<int, int>, LONG> *indeterminatePositions; std::map<std::pair<int, int>, LONG> *indeterminatePositions;
BOOL inLButtonDown; BOOL inLButtonDown;
// TODO is this even necessary? it seems NM_CLICK is not sent if NM_DBLCLICK or LVN_ITEMACTIVATE (one of the two) happens...
BOOL inDoubleClickTimer; BOOL inDoubleClickTimer;
HWND edit; HWND edit;
int editedItem; int editedItem;
@ -52,3 +53,27 @@ extern HRESULT uiprivUpdateImageListSize(uiTable *t);
extern HRESULT uiprivTableHandleNM_CLICK(uiTable *t, NMITEMACTIVATE *nm, LRESULT *lResult); extern HRESULT uiprivTableHandleNM_CLICK(uiTable *t, NMITEMACTIVATE *nm, LRESULT *lResult);
extern HRESULT uiprivTableFinishEditingText(uiTable *t); extern HRESULT uiprivTableFinishEditingText(uiTable *t);
extern HRESULT uiprivTableAbortEditingText(uiTable *t); extern HRESULT uiprivTableAbortEditingText(uiTable *t);
// tablemetrics.cpp
typedef struct uiprivTableMetrics uiprivTableMetrics;
struct uiprivTableMetrics {
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;
};
extern HRESULT uiprivTableGetMetrics(uiTable *t, int iItem, int iSubItem, uiprivTableMetrics **mout);

View File

@ -2,25 +2,19 @@
#include "uipriv_windows.hpp" #include "uipriv_windows.hpp"
#include "table.hpp" #include "table.hpp"
// TODO
#define cellValue(model, row, column) ((*((model)->mh->CellValue))((model)->mh, (model), (row), (column)))
struct drawState { struct drawState {
uiTable *t; uiTable *t;
uiTableModel *m; uiTableModel *model;
uiprivTableColumnParams *p; uiprivTableColumnParams *p;
HDC dc; HDC dc;
int iItem; int iItem;
int iSubItem; int iSubItem;
BOOL hasText;
BOOL hasImage;
BOOL selected;
BOOL focused;
RECT itemBounds; uiprivTableMetrics *m;
RECT itemIcon;
RECT itemLabel;
RECT subitemBounds;
RECT subitemIcon;
RECT subitemLabel;
COLORREF bgColor; COLORREF bgColor;
HBRUSH bgBrush; HBRUSH bgBrush;
@ -28,52 +22,19 @@ struct drawState {
COLORREF textColor; COLORREF textColor;
HBRUSH textBrush; HBRUSH textBrush;
BOOL freeTextBrush; BOOL freeTextBrush;
LRESULT bitmapMargin;
int cxIcon;
int cyIcon;
RECT realTextRect;
RECT focusRect;
}; };
static HRESULT computeOtherRectsAndDrawBackgrounds(struct drawState *s) static HRESULT drawBackgrounds(struct drawState *s)
{ {
RECT r; if (s->m->hasImage)
if (FillRect(s->dc, &(s->m->subitemIcon), GetSysColorBrush(COLOR_WINDOW)) == 0) {
r = s->subitemLabel;
if (!s->hasText && !s->hasImage)
r = s->subitemBounds;
else if (!s->hasImage && s->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 = s->subitemBounds.left;
if (s->hasImage)
if (FillRect(s->dc, &(s->subitemIcon), GetSysColorBrush(COLOR_WINDOW)) == 0) {
logLastError(L"FillRect() icon"); logLastError(L"FillRect() icon");
return E_FAIL; return E_FAIL;
} }
if (FillRect(s->dc, &r, s->bgBrush) == 0) { if (FillRect(s->dc, &(s->m->realTextBackground), s->bgBrush) == 0) {
logLastError(L"FillRect()"); logLastError(L"FillRect()");
return E_FAIL; return E_FAIL;
} }
UnionRect(&(s->focusRect), &(s->focusRect), &r);
s->realTextRect = r;
// TODO confirm whether this really happens on column 0 as well
if (s->hasImage && s->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.
s->realTextRect.left += 2;
else if (s->iSubItem != 0)
// In the case of subitem text without an image, we draw
// text one bitmap margin away from the left edge.
s->realTextRect.left += s->bitmapMargin;
return S_OK; return S_OK;
} }
@ -110,11 +71,11 @@ static HRESULT drawImagePart(struct drawState *s)
if (s->p->imageModelColumn == -1) if (s->p->imageModelColumn == -1)
return S_OK; return S_OK;
data = (*(s->m->mh->CellValue))(s->m->mh, s->m, s->iItem, s->p->imageModelColumn); data = cellValue(s->model, s->iItem, s->p->imageModelColumn);
wb = uiprivImageAppropriateForDC(uiTableDataImage(data), s->dc); wb = uiprivImageAppropriateForDC(uiTableDataImage(data), s->dc);
uiFreeTableData(data); uiFreeTableData(data);
hr = uiprivWICToGDI(wb, s->dc, s->cxIcon, s->cyIcon, &b); hr = uiprivWICToGDI(wb, s->dc, s->m->cxIcon, s->m->cyIcon, &b);
if (hr != S_OK) if (hr != S_OK)
return hr; return hr;
// TODO rewrite this condition to make more sense; possibly swap the if and else blocks too // TODO rewrite this condition to make more sense; possibly swap the if and else blocks too
@ -132,12 +93,12 @@ static HRESULT drawImagePart(struct drawState *s)
// TODO error check // TODO error check
DeleteObject(b); DeleteObject(b);
r = s->subitemIcon; r = s->m->subitemIcon;
r.right = r.left + s->cxIcon; r.right = r.left + s->m->cxIcon;
r.bottom = r.top + s->cyIcon; r.bottom = r.top + s->m->cyIcon;
centerImageRect(&r, &(s->subitemIcon)); centerImageRect(&r, &(s->m->subitemIcon));
fStyle = ILD_NORMAL; fStyle = ILD_NORMAL;
if (s->selected) if (s->m->selected)
fStyle = ILD_SELECTED; fStyle = ILD_SELECTED;
if (ImageList_Draw(s->t->imagelist, 0, if (ImageList_Draw(s->t->imagelist, 0,
s->dc, r.left, r.top, fStyle) == 0) { s->dc, r.left, r.top, fStyle) == 0) {
@ -156,7 +117,7 @@ static HRESULT drawUnthemedCheckbox(struct drawState *s, int checked, int enable
RECT r; RECT r;
UINT state; UINT state;
r = s->subitemIcon; r = s->m->subitemIcon;
// this is what the actual list view LVS_EX_CHECKBOXES code does to size the checkboxes // this is what the actual list view LVS_EX_CHECKBOXES code does to size the checkboxes
// TODO reverify the initial size // TODO reverify the initial size
r.right = r.left + GetSystemMetrics(SM_CXSMICON); r.right = r.left + GetSystemMetrics(SM_CXSMICON);
@ -168,7 +129,7 @@ static HRESULT drawUnthemedCheckbox(struct drawState *s, int checked, int enable
r.right++; r.right++;
r.bottom++; r.bottom++;
centerImageRect(&r, &(s->subitemIcon)); centerImageRect(&r, &(s->m->subitemIcon));
state = DFCS_BUTTONCHECK | DFCS_FLAT; state = DFCS_BUTTONCHECK | DFCS_FLAT;
if (checked) if (checked)
state |= DFCS_CHECKED; state |= DFCS_CHECKED;
@ -195,11 +156,11 @@ static HRESULT drawThemedCheckbox(struct drawState *s, HTHEME theme, int checked
logHRESULT(L"GetThemePartSize()", hr); logHRESULT(L"GetThemePartSize()", hr);
return hr; // TODO fall back? return hr; // TODO fall back?
} }
r = s->subitemIcon; r = s->m->subitemIcon;
r.right = r.left + size.cx; r.right = r.left + size.cx;
r.bottom = r.top + size.cy; r.bottom = r.top + size.cy;
centerImageRect(&r, &(s->subitemIcon)); centerImageRect(&r, &(s->m->subitemIcon));
if (!checked && enabled) if (!checked && enabled)
state = CBS_UNCHECKEDNORMAL; state = CBS_UNCHECKEDNORMAL;
else if (checked && enabled) else if (checked && enabled)
@ -228,7 +189,7 @@ static HRESULT drawCheckboxPart(struct drawState *s)
if (s->p->checkboxModelColumn == -1) if (s->p->checkboxModelColumn == -1)
return S_OK; return S_OK;
data = (*(s->m->mh->CellValue))(s->m->mh, s->m, s->iItem, s->p->checkboxModelColumn); data = cellValue(s->model, s->iItem, s->p->checkboxModelColumn);
checked = uiTableDataInt(data); checked = uiTableDataInt(data);
uiFreeTableData(data); uiFreeTableData(data);
switch (s->p->checkboxEditableColumn) { switch (s->p->checkboxEditableColumn) {
@ -239,7 +200,7 @@ static HRESULT drawCheckboxPart(struct drawState *s)
enabled = 1; enabled = 1;
break; break;
default: default:
data = (*(s->m->mh->CellValue))(s->m->mh, s->m, s->iItem, s->p->checkboxEditableColumn); data = cellValue(s->model, s->iItem, s->p->checkboxEditableColumn);
enabled = uiTableDataInt(data); enabled = uiTableDataInt(data);
uiFreeTableData(data); uiFreeTableData(data);
} }
@ -270,7 +231,7 @@ static HRESULT drawTextPart(struct drawState *s)
uiTableData *data; uiTableData *data;
WCHAR *wstr; WCHAR *wstr;
if (!s->hasText) if (!s->m->hasText)
return S_OK; return S_OK;
prevText = SetTextColor(s->dc, s->textColor); prevText = SetTextColor(s->dc, s->textColor);
@ -284,14 +245,14 @@ static HRESULT drawTextPart(struct drawState *s)
return E_FAIL; return E_FAIL;
} }
data = (*(s->m->mh->CellValue))(s->m->mh, s->m, s->iItem, s->p->textModelColumn); data = cellValue(s->model, s->iItem, s->p->textModelColumn);
wstr = toUTF16(uiTableDataString(data)); wstr = toUTF16(uiTableDataString(data));
uiFreeTableData(data); uiFreeTableData(data);
// These flags are a menagerie of flags from various sources: // These flags are a menagerie of flags from various sources:
// guessing, the Windows 2000 source leak, various custom // guessing, the Windows 2000 source leak, various custom
// draw examples on the web, etc. // draw examples on the web, etc.
// TODO find the real correct flags // TODO find the real correct flags
if (DrawTextW(s->dc, wstr, -1, &(s->realTextRect), DT_LEFT | DT_VCENTER | DT_END_ELLIPSIS | DT_SINGLELINE | DT_NOPREFIX | DT_EDITCONTROL) == 0) { if (DrawTextW(s->dc, wstr, -1, &(s->m->realTextRect), DT_LEFT | DT_VCENTER | DT_END_ELLIPSIS | DT_SINGLELINE | DT_NOPREFIX | DT_EDITCONTROL) == 0) {
uiprivFree(wstr); uiprivFree(wstr);
logLastError(L"DrawTextW()"); logLastError(L"DrawTextW()");
return E_FAIL; return E_FAIL;
@ -337,7 +298,7 @@ static HRESULT drawProgressBarPart(struct drawState *s)
hr = E_FAIL; hr = E_FAIL;
goto fail; goto fail;
} }
r = s->subitemBounds; r = s->m->subitemBounds;
// this sets the height of the progressbar and vertically centers it in one fell swoop // this sets the height of the progressbar and vertically centers it in one fell swoop
r.top += (r.bottom - tm.tmHeight - r.top) / 2; r.top += (r.bottom - tm.tmHeight - r.top) / 2;
r.bottom = r.top + tm.tmHeight; r.bottom = r.top + tm.tmHeight;
@ -367,7 +328,7 @@ static HRESULT drawProgressBarPart(struct drawState *s)
HBRUSH brush, prevBrush; HBRUSH brush, prevBrush;
sysColor = COLOR_HIGHLIGHT; sysColor = COLOR_HIGHLIGHT;
if (s->selected) if (s->m->selected)
sysColor = COLOR_HIGHLIGHTTEXT; sysColor = COLOR_HIGHLIGHTTEXT;
// TODO check errors everywhere // TODO check errors everywhere
@ -438,7 +399,7 @@ static HRESULT drawButtonPart(struct drawState *s)
if (s->p->buttonModelColumn == -1) if (s->p->buttonModelColumn == -1)
return S_OK; return S_OK;
data = (*(s->m->mh->CellValue))(s->m->mh, s->m, s->iItem, s->p->buttonModelColumn); data = cellValue(s->model, s->iItem, s->p->buttonModelColumn);
wstr = toUTF16(uiTableDataString(data)); wstr = toUTF16(uiTableDataString(data));
uiFreeTableData(data); uiFreeTableData(data);
switch (s->p->buttonClickableModelColumn) { switch (s->p->buttonClickableModelColumn) {
@ -449,7 +410,7 @@ static HRESULT drawButtonPart(struct drawState *s)
enabled = 1; enabled = 1;
break; break;
default: default:
data = (*(s->m->mh->CellValue))(s->m->mh, s->m, s->iItem, s->p->checkboxEditableColumn); data = cellValue(s->model, s->iItem, s->p->checkboxEditableColumn);
enabled = uiTableDataInt(data); enabled = uiTableDataInt(data);
uiFreeTableData(data); uiFreeTableData(data);
} }
@ -461,7 +422,7 @@ static HRESULT drawButtonPart(struct drawState *s)
hr = E_FAIL; hr = E_FAIL;
goto fail; goto fail;
} }
r = s->subitemBounds; r = s->m->subitemBounds;
if (theme != NULL) { if (theme != NULL) {
int state; int state;
@ -534,6 +495,10 @@ static HRESULT freeDrawState(struct drawState *s)
HRESULT hr, hrret; HRESULT hr, hrret;
hrret = S_OK; hrret = S_OK;
if (s->m != NULL) {
uiprivFree(s->m);
s->m = NULL;
}
if (s->freeTextBrush) { if (s->freeTextBrush) {
if (DeleteObject(s->textBrush) == 0) { if (DeleteObject(s->textBrush) == 0) {
logLastError(L"DeleteObject()"); logLastError(L"DeleteObject()");
@ -553,20 +518,6 @@ static HRESULT freeDrawState(struct drawState *s)
return hrret; return hrret;
} }
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;
}
static COLORREF blend(COLORREF base, double r, double g, double b, double a) static COLORREF blend(COLORREF base, double r, double g, double b, double a)
{ {
double br, bg, bb; double br, bg, bb;
@ -591,48 +542,18 @@ static HRESULT fillDrawState(struct drawState *s, uiTable *t, NMLVCUSTOMDRAW *nm
ZeroMemory(s, sizeof (struct drawState)); ZeroMemory(s, sizeof (struct drawState));
s->t = t; s->t = t;
s->m = t->model; s->model = t->model;
s->p = p; s->p = p;
s->dc = nm->nmcd.hdc; s->dc = nm->nmcd.hdc;
s->iItem = nm->nmcd.dwItemSpec; s->iItem = nm->nmcd.dwItemSpec;
s->iSubItem = nm->iSubItem; s->iSubItem = nm->iSubItem;
s->hasText = p->textModelColumn != -1;
s->hasImage = (p->imageModelColumn != -1) || (p->checkboxModelColumn != -1);
// nm->nmcd.uItemState CDIS_SELECTED is unreliable for the
// listview configuration we have, so we must do this.
state = SendMessageW(t->hwnd, LVM_GETITEMSTATE, nm->nmcd.dwItemSpec, LVIS_SELECTED);
s->selected = (state & LVIS_SELECTED) != 0;
s->focused = (nm->nmcd.uItemState & CDIS_FOCUS) != 0;
// TODO check LRESULT bad parameters here hr = uiprivTableGetMetrics(t, s->iItem, s->iSubItem, &(s->m));
hr = itemRect(S_OK, t, LVM_GETITEMRECT, s->iItem,
LVIR_BOUNDS, 0, FALSE, &(s->itemBounds));
hr = itemRect(hr, t, LVM_GETITEMRECT, s->iItem,
LVIR_ICON, 0, FALSE, &(s->itemIcon));
hr = itemRect(hr, t, LVM_GETITEMRECT, s->iItem,
LVIR_LABEL, 0, FALSE, &(s->itemLabel));
hr = itemRect(hr, t, LVM_GETSUBITEMRECT, s->iItem,
LVIR_BOUNDS, s->iSubItem, 0, &(s->subitemBounds));
hr = itemRect(hr, t, LVM_GETSUBITEMRECT, s->iItem,
LVIR_ICON, s->iSubItem, 0, &(s->subitemIcon));
if (hr != S_OK) if (hr != S_OK)
goto fail; 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.
s->subitemLabel = s->subitemBounds;
s->subitemLabel.left = s->subitemIcon.right;
// And on iSubItem == 0, LVIF_GETSUBITEMRECT still includes
// all the subitems, which we don't want.
if (s->iSubItem == 0) {
s->subitemBounds.right = s->itemLabel.right;
s->subitemLabel.right = s->itemLabel.right;
}
if (s->selected) { if (s->m->selected) {
s->bgColor = GetSysColor(COLOR_HIGHLIGHT); s->bgColor = GetSysColor(COLOR_HIGHLIGHT);
s->bgBrush = GetSysColorBrush(COLOR_HIGHLIGHT); s->bgBrush = GetSysColorBrush(COLOR_HIGHLIGHT);
s->textColor = GetSysColor(COLOR_HIGHLIGHTTEXT); s->textColor = GetSysColor(COLOR_HIGHLIGHTTEXT);
@ -644,7 +565,7 @@ static HRESULT fillDrawState(struct drawState *s, uiTable *t, NMLVCUSTOMDRAW *nm
s->bgColor = GetSysColor(COLOR_WINDOW); s->bgColor = GetSysColor(COLOR_WINDOW);
s->bgBrush = GetSysColorBrush(COLOR_WINDOW); s->bgBrush = GetSysColorBrush(COLOR_WINDOW);
if (t->backgroundColumn != -1) { if (t->backgroundColumn != -1) {
data = (*(s->m->mh->CellValue))(s->m->mh, s->m, s->iItem, t->backgroundColumn); data = cellValue(s->model, s->iItem, t->backgroundColumn);
if (data != NULL) { if (data != NULL) {
uiTableDataColor(data, &r, &g, &b, &a); uiTableDataColor(data, &r, &g, &b, &a);
uiFreeTableData(data); uiFreeTableData(data);
@ -661,7 +582,7 @@ static HRESULT fillDrawState(struct drawState *s, uiTable *t, NMLVCUSTOMDRAW *nm
s->textColor = GetSysColor(COLOR_WINDOWTEXT); s->textColor = GetSysColor(COLOR_WINDOWTEXT);
s->textBrush = GetSysColorBrush(COLOR_WINDOWTEXT); s->textBrush = GetSysColorBrush(COLOR_WINDOWTEXT);
if (p->textParams.ColorModelColumn != -1) { if (p->textParams.ColorModelColumn != -1) {
data = (*(s->m->mh->CellValue))(s->m->mh, s->m, s->iItem, p->textParams.ColorModelColumn); data = cellValue(s->model, s->iItem, p->textParams.ColorModelColumn);
if (data != NULL) { if (data != NULL) {
uiTableDataColor(data, &r, &g, &b, &a); uiTableDataColor(data, &r, &g, &b, &a);
uiFreeTableData(data); uiFreeTableData(data);
@ -677,14 +598,6 @@ static HRESULT fillDrawState(struct drawState *s, uiTable *t, NMLVCUSTOMDRAW *nm
} }
} }
header = (HWND) SendMessageW(t->hwnd, LVM_GETHEADER, 0, 0);
s->bitmapMargin = SendMessageW(header, HDM_GETBITMAPMARGIN, 0, 0);
if (ImageList_GetIconSize(t->imagelist, &(s->cxIcon), &(s->cyIcon)) == 0) {
logLastError(L"ImageList_GetIconSize()");
hr = E_FAIL;
goto fail;
}
return S_OK; return S_OK;
fail: fail:
// ignore the error; we need to return the one we got above // ignore the error; we need to return the one we got above
@ -716,7 +629,7 @@ HRESULT uiprivTableHandleNM_CUSTOMDRAW(uiTable *t, NMLVCUSTOMDRAW *nm, LRESULT *
hr = fillDrawState(&s, t, nm, p); hr = fillDrawState(&s, t, nm, p);
if (hr != S_OK) if (hr != S_OK)
return hr; return hr;
hr = computeOtherRectsAndDrawBackgrounds(&s); hr = drawBackgrounds(&s);
if (hr != S_OK) if (hr != S_OK)
goto fail; goto fail;
hr = drawImagePart(&s); hr = drawImagePart(&s);

View File

@ -2,33 +2,6 @@
#include "uipriv_windows.hpp" #include "uipriv_windows.hpp"
#include "table.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) static HRESULT itemRect(HRESULT hr, uiTable *t, UINT uMsg, WPARAM wParam, LONG left, LONG top, LRESULT bad, RECT *r)
{ {
if (hr != S_OK) if (hr != S_OK)
@ -46,6 +19,7 @@ static HRESULT itemRect(HRESULT hr, uiTable *t, UINT uMsg, WPARAM wParam, LONG l
HRESULT uiprivTableGetMetrics(uiTable *t, int iItem, int iSubItem, uiprivTableMetrics **mout) HRESULT uiprivTableGetMetrics(uiTable *t, int iItem, int iSubItem, uiprivTableMetrics **mout)
{ {
uiprivTableMetrics *m; uiprivTableMetrics *m;
uiprivTableColumnParams *p;
LRESULT state; LRESULT state;
HWND header; HWND header;
RECT r; RECT r;
@ -55,29 +29,25 @@ HRESULT uiprivTableGetMetrics(uiTable *t, int iItem, int iSubItem, uiprivTableMe
return E_POINTER; return E_POINTER;
m = uiprivNew(uiprivTableMetrics); m = uiprivNew(uiprivTableMetrics);
m->t = t;
m->m = t->model;
m->p = (*(t->columns))[iSubItem];
m->iItem = iItem; p = (*(t->columns))[iSubItem];
m->iSubItem = iSubItem; m->hasText = p->textModelColumn != -1;
m->hasText = m->p->textModelColumn != -1; m->hasImage = (p->imageModelColumn != -1) || (p->checkboxModelColumn != -1);
m->hasImage = (m->p->imageModelColumn != -1) || (m->p->checkboxModelColumn != -1);
state = SendMessageW(t->hwnd, LVM_GETITEMSTATE, iItem, LVIS_FOCUSED | LVIS_SELECTED); state = SendMessageW(t->hwnd, LVM_GETITEMSTATE, iItem, LVIS_FOCUSED | LVIS_SELECTED);
m->focused = (state & LVIS_FOCUSED) != 0; m->focused = (state & LVIS_FOCUSED) != 0;
m->selected = (state & LVIS_SELECTED) != 0; m->selected = (state & LVIS_SELECTED) != 0;
// TODO check LRESULT bad parameters here // TODO check LRESULT bad parameters here
hr = itemRect(S_OK, t, LVM_GETITEMRECT, s->iItem, hr = itemRect(S_OK, t, LVM_GETITEMRECT, iItem,
LVIR_BOUNDS, 0, FALSE, &(m->itemBounds)); LVIR_BOUNDS, 0, FALSE, &(m->itemBounds));
hr = itemRect(hr, t, LVM_GETITEMRECT, s->iItem, hr = itemRect(hr, t, LVM_GETITEMRECT, iItem,
LVIR_ICON, 0, FALSE, &(m->itemIcon)); LVIR_ICON, 0, FALSE, &(m->itemIcon));
hr = itemRect(hr, t, LVM_GETITEMRECT, s->iItem, hr = itemRect(hr, t, LVM_GETITEMRECT, iItem,
LVIR_LABEL, 0, FALSE, &(m->itemLabel)); LVIR_LABEL, 0, FALSE, &(m->itemLabel));
hr = itemRect(hr, t, LVM_GETSUBITEMRECT, s->iItem, hr = itemRect(hr, t, LVM_GETSUBITEMRECT, iItem,
LVIR_BOUNDS, s->iSubItem, 0, &(m->subitemBounds)); LVIR_BOUNDS, iSubItem, 0, &(m->subitemBounds));
hr = itemRect(hr, t, LVM_GETSUBITEMRECT, s->iItem, hr = itemRect(hr, t, LVM_GETSUBITEMRECT, iItem,
LVIR_ICON, s->iSubItem, 0, &(m->subitemIcon)); LVIR_ICON, iSubItem, 0, &(m->subitemIcon));
if (hr != S_OK) if (hr != S_OK)
goto fail; goto fail;
// LVM_GETSUBITEMRECT treats LVIR_LABEL as the same as // LVM_GETSUBITEMRECT treats LVIR_LABEL as the same as
@ -104,7 +74,7 @@ HRESULT uiprivTableGetMetrics(uiTable *t, int iItem, int iSubItem, uiprivTableMe
r = m->subitemLabel; r = m->subitemLabel;
if (!m->hasText && !m->hasImage) if (!m->hasText && !m->hasImage)
r = s->subitemBounds; r = m->subitemBounds;
else if (!m->hasImage && iSubItem != 0) else if (!m->hasImage && iSubItem != 0)
// By default, this will include images; we're not drawing // By default, this will include images; we're not drawing
// images, so we will manually draw over the image area. // images, so we will manually draw over the image area.