Started drawing uiTable text. We're drawing fully manually from here on out. Also fixed LVIF_INDENT settings and a few other things.
This commit is contained in:
parent
15bc55dd5e
commit
caa0688687
|
@ -52,6 +52,7 @@ list(APPEND _LIBUI_SOURCES
|
|||
windows/tab.cpp
|
||||
windows/table.cpp
|
||||
windows/tableimages.cpp
|
||||
windows/tabletext.cpp
|
||||
windows/tabpage.cpp
|
||||
windows/text.cpp
|
||||
windows/utf16.cpp
|
||||
|
|
|
@ -79,24 +79,13 @@ void uiTableModelRowDeleted(uiTableModel *m, int oldIndex)
|
|||
static LRESULT onLVN_GETDISPINFO(uiTable *t, NMLVDISPINFOW *nm)
|
||||
{
|
||||
static uiprivTableColumnParams *p;
|
||||
uiTableData *data;
|
||||
WCHAR *wstr;
|
||||
HRESULT hr;
|
||||
|
||||
p = (*(t->columns))[nm->item.iSubItem];
|
||||
if ((nm->item.mask & LVIF_TEXT) != 0)
|
||||
if (p->textModelColumn != -1) {
|
||||
data = (*(t->model->mh->CellValue))(t->model->mh, t->model, nm->item.iItem, p->textModelColumn);
|
||||
wstr = toUTF16(uiTableDataString(data));
|
||||
uiFreeTableData(data);
|
||||
// we could just make pszText into a freshly allocated conversion and avoid the limitation of cchTextMax
|
||||
// but then we would have to keep things around for some amount of time (some pages on MSDN say 2 additional LVN_GETDISPINFO messages)
|
||||
// and in practice, anything that results in extra LVN_GETDISPINFO messages (such as fillSubitemDrawParams() below) will break this counting
|
||||
// TODO make it so we don't have to make a copy; instead we can convert directly into pszText (this will also avoid the risk of having a dangling surrogate pair at the end)
|
||||
wcscpy_s(nm->item.pszText, nm->item.cchTextMax, wstr);
|
||||
uiprivFree(wstr);
|
||||
}
|
||||
|
||||
hr = uiprivLVN_GETDISPINFOText(t, nm, p);
|
||||
if (hr != S_OK) {
|
||||
// TODO
|
||||
}
|
||||
hr = uiprivLVN_GETDISPINFOImagesCheckboxes(t, nm, p);
|
||||
if (hr != S_OK) {
|
||||
// TODO
|
||||
|
@ -126,31 +115,47 @@ 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)
|
||||
COLORREF uiprivTableBlendedColorFromModel(uiTable *t, NMLVCUSTOMDRAW *nm, int modelColumn, int fallbackSysColorID)
|
||||
{
|
||||
uiTableData *data;
|
||||
double r, g, b, a;
|
||||
|
||||
data = (*(t->model->mh->CellValue))(t->model->mh, t->model, nm->nmcd.dwItemSpec, modelColumn);
|
||||
if (data == NULL)
|
||||
return GetSysColor(fallbackSysColorID);
|
||||
uiTableDataColor(data, &r, &g, &b, &a);
|
||||
uiFreeTableData(data);
|
||||
return blend(nm->clrTextBk, r, g, b, a);
|
||||
}
|
||||
|
||||
static HRESULT fillSubitemDrawParams(uiTable *t, NMLVCUSTOMDRAW *nm, uiprivSubitemDrawParams *dp)
|
||||
{
|
||||
LRESULT state;
|
||||
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
|
||||
// note: nm->nmcd.uItemState CDIS_SELECTED is unreliable for the listview configuration we have
|
||||
state = SendMessageW(t->hwnd, LVM_GETITEMSTATE, nm->nmcd.dwItemSpec, LVIS_SELECTED);
|
||||
dp->selected = (state & LVIS_SELECTED) != 0;
|
||||
|
||||
if (nm->iSubItem == 0) {
|
||||
ZeroMemory(&r, sizeof (RECT));
|
||||
r.left = LVIR_BOUNDS;
|
||||
if (SendMessageW(hwnd, LVM_GETITEMRECT, nm->nmcd.dwItemSpec, (LPARAM) (&r)) == FALSE) {
|
||||
if (SendMessageW(t->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) {
|
||||
if (SendMessageW(t->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) {
|
||||
if (SendMessageW(t->hwnd, LVM_GETITEMRECT, nm->nmcd.dwItemSpec, (LPARAM) (&r)) == FALSE) {
|
||||
logLastError(L"LVM_GETITEMRECT LVIR_LABEL");
|
||||
return E_FAIL;
|
||||
}
|
||||
|
@ -161,7 +166,7 @@ static HRESULT fillSubitemDrawParams(HWND hwnd, NMLVCUSTOMDRAW *nm, uiprivSubite
|
|||
ZeroMemory(&r, sizeof (RECT));
|
||||
r.left = LVIR_BOUNDS;
|
||||
r.top = nm->iSubItem;
|
||||
if (SendMessageW(hwnd, LVM_GETSUBITEMRECT, nm->nmcd.dwItemSpec, (LPARAM) (&r)) == 0) {
|
||||
if (SendMessageW(t->hwnd, LVM_GETSUBITEMRECT, nm->nmcd.dwItemSpec, (LPARAM) (&r)) == 0) {
|
||||
logLastError(L"LVM_GETSUBITEMRECT LVIR_BOUNDS");
|
||||
return E_FAIL;
|
||||
}
|
||||
|
@ -169,7 +174,7 @@ static HRESULT fillSubitemDrawParams(HWND hwnd, NMLVCUSTOMDRAW *nm, uiprivSubite
|
|||
ZeroMemory(&r, sizeof (RECT));
|
||||
r.left = LVIR_ICON;
|
||||
r.top = nm->iSubItem;
|
||||
if (SendMessageW(hwnd, LVM_GETSUBITEMRECT, nm->nmcd.dwItemSpec, (LPARAM) (&r)) == 0) {
|
||||
if (SendMessageW(t->hwnd, LVM_GETSUBITEMRECT, nm->nmcd.dwItemSpec, (LPARAM) (&r)) == 0) {
|
||||
logLastError(L"LVM_GETSUBITEMRECT LVIR_ICON");
|
||||
return E_FAIL;
|
||||
}
|
||||
|
@ -229,8 +234,7 @@ static LRESULT onNM_CUSTOMDRAW(uiTable *t, NMLVCUSTOMDRAW *nm)
|
|||
logLastError(L"DeleteObject()");
|
||||
}
|
||||
t->clrItemText = nm->clrText;
|
||||
ret = CDRF_NEWFONT | CDRF_NOTIFYSUBITEMDRAW;
|
||||
break;
|
||||
return CDRF_NEWFONT | CDRF_NOTIFYSUBITEMDRAW;
|
||||
case CDDS_SUBITEM | CDDS_ITEMPREPAINT:
|
||||
p = (*(t->columns))[nm->iSubItem];
|
||||
// TODO none of this runs on the first item
|
||||
|
@ -245,26 +249,14 @@ static LRESULT onNM_CUSTOMDRAW(uiTable *t, NMLVCUSTOMDRAW *nm)
|
|||
}
|
||||
}
|
||||
// TODO draw background on image columns if needed
|
||||
ret = /*CDRF_SKIPDEFAULT | */CDRF_NEWFONT;
|
||||
ret = CDRF_SKIPDEFAULT | CDRF_NEWFONT;
|
||||
break;
|
||||
//case CDDS_SUBITEM | CDDS_ITEMPOSTPAINT:
|
||||
if(0){//nm->iSubItem == 1) {
|
||||
RECT r, r2;
|
||||
r.left = LVIR_LABEL;
|
||||
r.top = 1;
|
||||
SendMessageW(t->hwnd, LVM_GETSUBITEMRECT, nm->nmcd.dwItemSpec, (LPARAM)(&r));
|
||||
r2.left = LVIR_ICON;
|
||||
r2.top = 1;
|
||||
SendMessageW(t->hwnd, LVM_GETSUBITEMRECT, nm->nmcd.dwItemSpec, (LPARAM)(&r2));
|
||||
r.left = r2.right + 2;
|
||||
DrawTextW(nm->nmcd.hdc, L"Part", -1,
|
||||
&r, DT_LEFT | DT_VCENTER | DT_END_ELLIPSIS | DT_SINGLELINE | DT_NOPREFIX | DT_EDITCONTROL);}
|
||||
default:
|
||||
return CDRF_DODEFAULT;
|
||||
}
|
||||
|
||||
ZeroMemory(&dp, sizeof (uiprivSubitemDrawParams));
|
||||
hr = fillSubitemDrawParams(t->hwnd, nm, &dp);
|
||||
hr = fillSubitemDrawParams(t, nm, &dp);
|
||||
if (hr != S_OK) {
|
||||
// TODO
|
||||
}
|
||||
|
@ -272,6 +264,10 @@ DrawTextW(nm->nmcd.hdc, L"Part", -1,
|
|||
if (hr != S_OK) {
|
||||
// TODO
|
||||
}
|
||||
hr = uiprivNM_CUSTOMDRAWText(t, nm, p, &dp);
|
||||
if (hr != S_OK) {
|
||||
// TODO
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
|
@ -40,11 +40,17 @@ struct uiTable {
|
|||
};
|
||||
typedef struct uiprivSubitemDrawParams uiprivSubitemDrawParams;
|
||||
struct uiprivSubitemDrawParams {
|
||||
bool selected;
|
||||
RECT bounds;
|
||||
RECT icon;
|
||||
RECT label;
|
||||
};
|
||||
|
||||
extern COLORREF uiprivTableBlendedColorFromModel(uiTable *t, NMLVCUSTOMDRAW *nm, int modelColumn, int fallbackSysColorID);
|
||||
|
||||
// tabletext.cpp
|
||||
extern HRESULT uiprivLVN_GETDISPINFOText(uiTable *t, NMLVDISPINFOW *nm, uiprivTableColumnParams *p);
|
||||
extern HRESULT uiprivNM_CUSTOMDRAWText(uiTable *t, NMLVCUSTOMDRAW *nm, uiprivTableColumnParams *p, uiprivSubitemDrawParams *dp);
|
||||
|
||||
// tableimages.cpp
|
||||
extern HRESULT uiprivLVN_GETDISPINFOImagesCheckboxes(uiTable *t, NMLVDISPINFOW *nm, uiprivTableColumnParams *p);
|
||||
extern HRESULT uiprivNM_CUSTOMDRAWImagesCheckboxes(uiTable *t, NMLVCUSTOMDRAW *nm, uiprivSubitemDrawParams *dp);
|
||||
|
|
|
@ -95,8 +95,14 @@ HRESULT uiprivLVN_GETDISPINFOImagesCheckboxes(uiTable *t, NMLVDISPINFOW *nm, uip
|
|||
uiTableData *data;
|
||||
HRESULT hr;
|
||||
|
||||
if (nm->item.iSubItem == 0 && p->imageModelColumn == -1 && p->checkboxModelColumn == -1) {
|
||||
// having an image list always leaves space for an image on the main item :|
|
||||
// other places on the internet imply that you should be able to do this but that it shouldn't work
|
||||
// but it works perfectly (and pixel-perfectly too) for me, so...
|
||||
nm->item.mask |= LVIF_INDENT;
|
||||
nm->item.iIndent = -1;
|
||||
}
|
||||
if ((nm->item.mask & LVIF_IMAGE) == 0)
|
||||
// TODO we actually need to do the first column fix here too...
|
||||
return S_OK; // nothing to do here
|
||||
|
||||
if (p->imageModelColumn != -1) {
|
||||
|
@ -122,16 +128,8 @@ HRESULT uiprivLVN_GETDISPINFOImagesCheckboxes(uiTable *t, NMLVDISPINFOW *nm, uip
|
|||
return S_OK;
|
||||
}
|
||||
|
||||
// if we got here, there's no image in this cell
|
||||
nm->item.mask &= ~LVIF_IMAGE;
|
||||
// having an image list always leaves space for an image on the main item :|
|
||||
// other places on the internet imply that you should be able to do this but that it shouldn't work
|
||||
// but it works perfectly (and pixel-perfectly too) for me, so...
|
||||
// TODO it doesn't work anymore...
|
||||
if (nm->item.iSubItem == 0) {
|
||||
nm->item.mask |= LVIF_INDENT;
|
||||
nm->item.iIndent = -1;
|
||||
}
|
||||
// TODO see if this is correct
|
||||
nm->item.iImage = -1;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,88 @@
|
|||
// 13 june 2018
|
||||
#include "uipriv_windows.hpp"
|
||||
#include "table.hpp"
|
||||
|
||||
// This file handles text in tables.
|
||||
|
||||
HRESULT uiprivLVN_GETDISPINFOText(uiTable *t, NMLVDISPINFOW *nm, uiprivTableColumnParams *p)
|
||||
{
|
||||
uiTableData *data;
|
||||
WCHAR *wstr;
|
||||
HRESULT hr;
|
||||
|
||||
if ((nm->item.mask & LVIF_TEXT) == 0)
|
||||
return S_OK;
|
||||
if (p->textModelColumn != -1)
|
||||
return S_OK;
|
||||
|
||||
data = (*(t->model->mh->CellValue))(t->model->mh, t->model, nm->item.iItem, p->textModelColumn);
|
||||
wstr = toUTF16(uiTableDataString(data));
|
||||
uiFreeTableData(data);
|
||||
// we could just make pszText into a freshly allocated conversion and avoid the limitation of cchTextMax
|
||||
// but then we would have to keep things around for some amount of time (some pages on MSDN say 2 additional LVN_GETDISPINFO messages)
|
||||
// and in practice, anything that results in extra LVN_GETDISPINFO messages (such as fillSubitemDrawParams() below) will break this counting
|
||||
// TODO make it so we don't have to make a copy; instead we can convert directly into pszText (this will also avoid the risk of having a dangling surrogate pair at the end)
|
||||
wcsncpy(nm->item.pszText, wstr, nm->item.cchTextMax);
|
||||
nm->item.pszText[nm->item.cchTextMax - 1] = L'\0';
|
||||
uiprivFree(wstr);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT uiprivNM_CUSTOMDRAWText(uiTable *t, NMLVCUSTOMDRAW *nm, uiprivTableColumnParams *p, uiprivSubitemDrawParams *dp)
|
||||
{
|
||||
COLORREF color;
|
||||
COLORREF prev;
|
||||
int prevMode;
|
||||
RECT r;
|
||||
uiTableData *data;
|
||||
WCHAR *wstr;
|
||||
|
||||
if (p->textModelColumn == -1)
|
||||
return S_OK;
|
||||
|
||||
if (dp->selected)
|
||||
color = GetSysColor(COLOR_HIGHLIGHTTEXT);
|
||||
else if (p->textParams.ColorModelColumn != -1)
|
||||
color = uiprivTableBlendedColorFromModel(t, nm, p->textParams.ColorModelColumn, COLOR_WINDOWTEXT);
|
||||
else
|
||||
color = GetSysColor(COLOR_WINDOWTEXT);
|
||||
prev = SetTextColor(nm->nmcd.hdc, color);
|
||||
if (prev == CLR_INVALID) {
|
||||
logLastError(L"SetTextColor()");
|
||||
return E_FAIL;
|
||||
}
|
||||
prevMode = SetBkMode(nm->nmcd.hdc, TRANSPARENT);
|
||||
if (prevMode == 0) {
|
||||
logLastError(L"SetBkMode()");
|
||||
return E_FAIL;
|
||||
}
|
||||
|
||||
// text is actually drawn two logical units to the right of the beginning of the text rect
|
||||
// TODO confirm this for the first column on both image and imageless cases
|
||||
// TODO actually this whole thing is wrong for imageless columns
|
||||
r = dp->label;
|
||||
r.left += 2;
|
||||
|
||||
data = (*(t->model->mh->CellValue))(t->model->mh, t->model, nm->nmcd.dwItemSpec, p->textModelColumn);
|
||||
wstr = toUTF16(uiTableDataString(data));
|
||||
uiFreeTableData(data);
|
||||
// these flags are a menagerie of flags from various sources: guessing, the Windows 2000 source leak, various custom draw examples on the web, etc.
|
||||
// TODO find the real correct flags
|
||||
if (DrawTextW(nm->nmcd.hdc, wstr, -1, &r, DT_LEFT | DT_VCENTER | DT_END_ELLIPSIS | DT_SINGLELINE | DT_NOPREFIX | DT_EDITCONTROL) == 0) {
|
||||
uiprivFree(wstr);
|
||||
logLastError(L"DrawTextW()");
|
||||
return E_FAIL;
|
||||
}
|
||||
uiprivFree(wstr);
|
||||
|
||||
// TODO decide once and for all what to compare to here and with SelectObject()
|
||||
if (SetBkMode(nm->nmcd.hdc, prevMode) != TRANSPARENT) {
|
||||
logLastError(L"SetBkMode() prev");
|
||||
return E_FAIL;
|
||||
}
|
||||
if (SetTextColor(nm->nmcd.hdc, prev) != color) {
|
||||
logLastError(L"SetTextColor() prev");
|
||||
return E_FAIL;
|
||||
}
|
||||
return S_OK;
|
||||
}
|
Loading…
Reference in New Issue