Wrote new (incomplete) image drawing code. Now to build and test.
This commit is contained in:
parent
d6cebf4ca0
commit
43bb983f5b
|
@ -290,7 +290,7 @@ uiTable *uiNewTable(uiTableModel *model)
|
||||||
|
|
||||||
t->backgroundColumn = -1;
|
t->backgroundColumn = -1;
|
||||||
|
|
||||||
hr = uiprivTableSetupImagesCheckboxes(t);
|
hr = uiprivUpdateImageListSize(t);
|
||||||
if (hr != S_OK) {
|
if (hr != S_OK) {
|
||||||
// TODO
|
// TODO
|
||||||
}
|
}
|
||||||
|
|
|
@ -53,7 +53,7 @@ extern HRESULT uiprivLVN_GETDISPINFOText(uiTable *t, NMLVDISPINFOW *nm, uiprivTa
|
||||||
// tableimages.cpp
|
// tableimages.cpp
|
||||||
extern HRESULT uiprivLVN_GETDISPINFOImagesCheckboxes(uiTable *t, NMLVDISPINFOW *nm, uiprivTableColumnParams *p);
|
extern HRESULT uiprivLVN_GETDISPINFOImagesCheckboxes(uiTable *t, NMLVDISPINFOW *nm, uiprivTableColumnParams *p);
|
||||||
extern HRESULT uiprivNM_CUSTOMDRAWImagesCheckboxes(uiTable *t, NMLVCUSTOMDRAW *nm, uiprivSubitemDrawParams *dp);
|
extern HRESULT uiprivNM_CUSTOMDRAWImagesCheckboxes(uiTable *t, NMLVCUSTOMDRAW *nm, uiprivSubitemDrawParams *dp);
|
||||||
extern HRESULT uiprivTableSetupImagesCheckboxes(uiTable *t);
|
|
||||||
|
|
||||||
// tabledraw.cpp
|
// tabledraw.cpp
|
||||||
extern HRESULT uiprivTableHandleNM_CUSTOMDRAW(uiTable *t, NMLVCUSTOMDRAW *nm, LRESULT *lResult);
|
extern HRESULT uiprivTableHandleNM_CUSTOMDRAW(uiTable *t, NMLVCUSTOMDRAW *nm, LRESULT *lResult);
|
||||||
|
extern HRESULT uiprivUpdateImageListSize(uiTable *t);
|
||||||
|
|
|
@ -37,7 +37,7 @@ struct drawState {
|
||||||
RECT focusRect;
|
RECT focusRect;
|
||||||
};
|
};
|
||||||
|
|
||||||
static HRESULT computeAndDrawTextRect(struct drawState *s)
|
static HRESULT computeOtherRectsAndDrawBackgrounds(struct drawState *s)
|
||||||
{
|
{
|
||||||
RECT r;
|
RECT r;
|
||||||
|
|
||||||
|
@ -50,6 +50,11 @@ static HRESULT computeAndDrawTextRect(struct drawState *s)
|
||||||
// There's a second part to this; see below.
|
// There's a second part to this; see below.
|
||||||
r.left = s->subitemBounds.left;
|
r.left = s->subitemBounds.left;
|
||||||
|
|
||||||
|
if (s->hasImage)
|
||||||
|
if (FillRect(s->dc, &(s->subitemIcon), GetSysColorBrush(COLOR_WINDOW)) == 0) {
|
||||||
|
logLastError(L"FillRect() icon");
|
||||||
|
return E_FAIL;
|
||||||
|
}
|
||||||
if (FillRect(s->dc, &r, s->bgBrush) == 0) {
|
if (FillRect(s->dc, &r, s->bgBrush) == 0) {
|
||||||
logLastError(L"FillRect()");
|
logLastError(L"FillRect()");
|
||||||
return E_FAIL;
|
return E_FAIL;
|
||||||
|
@ -72,6 +77,52 @@ static HRESULT computeAndDrawTextRect(struct drawState *s)
|
||||||
return S_OK;
|
return S_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static HRESULT drawImagePart(struct drawState *s)
|
||||||
|
{
|
||||||
|
uiTableData *data;
|
||||||
|
IWICBitmap *wb;
|
||||||
|
HBITMAP b;
|
||||||
|
UINT fStyle;
|
||||||
|
HRESULT hr;
|
||||||
|
|
||||||
|
if (s->p->imageModelColumn == -1)
|
||||||
|
return S_OK;
|
||||||
|
|
||||||
|
data = (*(t->model->mh->CellValue))(t->model->mh, t->model, nm->item.iItem, p->imageModelColumn);
|
||||||
|
wb = uiprivImageAppropriateForDC(uiTableDataImage(data), s->dc);
|
||||||
|
uiFreeTableData(data);
|
||||||
|
|
||||||
|
hr = uiprivWICToGDI(wb, s->cxIcon, s->cyIcon, &b);
|
||||||
|
if (hr != S_OK)
|
||||||
|
return hr;
|
||||||
|
// TODO rewrite this condition to make more sense; possibly swap the if and else blocks too
|
||||||
|
// TODO proper cleanup
|
||||||
|
if (ImageList_GetImageCount(t->imagelist) > 1) {
|
||||||
|
if (ImageList_Replace(t->imagelist, 0, b, NULL) == 0) {
|
||||||
|
logLastError(L"ImageList_Replace()");
|
||||||
|
return E_FAIL;
|
||||||
|
}
|
||||||
|
} else
|
||||||
|
if (ImageList_Add(t->imagelist, b, NULL) == -1) {
|
||||||
|
logLastError(L"ImageList_Add()");
|
||||||
|
return E_FAIL;
|
||||||
|
}
|
||||||
|
// TODO error check
|
||||||
|
DeleteObject(b);
|
||||||
|
|
||||||
|
fStyle = ILD_NORMAL;
|
||||||
|
if (s->selected)
|
||||||
|
fStyle = ILD_SELECTED;
|
||||||
|
// TODO copy the centering code from tableimage.cpp
|
||||||
|
if (ImageList_Draw(t->imagelist, 0,
|
||||||
|
s->dc, s->subitemIcon.left, s->subitemIcon.top,
|
||||||
|
fStyle) == 0) {
|
||||||
|
logLastError(L"ImageList_Draw()");
|
||||||
|
return E_FAIL;
|
||||||
|
}
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
|
||||||
static HRESULT drawTextPart(struct drawState *s)
|
static HRESULT drawTextPart(struct drawState *s)
|
||||||
{
|
{
|
||||||
COLORREF prevText;
|
COLORREF prevText;
|
||||||
|
@ -212,8 +263,8 @@ static HRESULT fillDrawState(struct drawState *s, uiTable *t, NMLVCUSTOMDRAW *nm
|
||||||
// LVM_GETSUBITEMRECT treats LVIR_LABEL as the same as
|
// LVM_GETSUBITEMRECT treats LVIR_LABEL as the same as
|
||||||
// LVIR_BOUNDS, so we can't use that directly. Instead, let's
|
// LVIR_BOUNDS, so we can't use that directly. Instead, let's
|
||||||
// assume the text is immediately after the icon. The correct
|
// assume the text is immediately after the icon. The correct
|
||||||
// rect will be determined by computeAndDrawTextRect()
|
// rect will be determined by
|
||||||
// above.
|
// computeOtherRectsAndDrawBackgrounds() above.
|
||||||
s->subitemLabel = s->subitemBounds;
|
s->subitemLabel = s->subitemBounds;
|
||||||
s->subitemLabel.left = s->subitemIcon.right;
|
s->subitemLabel.left = s->subitemIcon.right;
|
||||||
// And on iSubItem == 0, LVIF_GETSUBITEMRECT still includes
|
// And on iSubItem == 0, LVIF_GETSUBITEMRECT still includes
|
||||||
|
@ -270,7 +321,11 @@ static HRESULT fillDrawState(struct drawState *s, uiTable *t, NMLVCUSTOMDRAW *nm
|
||||||
|
|
||||||
header = (HWND) SendMessageW(t->hwnd, LVM_GETHEADER, 0, 0);
|
header = (HWND) SendMessageW(t->hwnd, LVM_GETHEADER, 0, 0);
|
||||||
s->bitmapMargin = SendMessageW(header, HDM_GETBITMAPMARGIN, 0, 0);
|
s->bitmapMargin = SendMessageW(header, HDM_GETBITMAPMARGIN, 0, 0);
|
||||||
// TODO
|
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:
|
||||||
|
@ -303,7 +358,10 @@ 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 = computeAndDrawTextRect(&s);
|
hr = computeOtherRectsAndDrawBackgrounds(&s);
|
||||||
|
if (hr != S_OK)
|
||||||
|
goto fail;
|
||||||
|
hr = drawImagePart(&s);
|
||||||
if (hr != S_OK)
|
if (hr != S_OK)
|
||||||
goto fail;
|
goto fail;
|
||||||
hr = drawTextPart(&s);
|
hr = drawTextPart(&s);
|
||||||
|
@ -319,3 +377,64 @@ fail:
|
||||||
freeDrawState(&s);
|
freeDrawState(&s);
|
||||||
return hr;
|
return hr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO run again when the DPI or the theme changes
|
||||||
|
// TODO properly clean things up here
|
||||||
|
// TODO properly destroy the old lists here too
|
||||||
|
HRESULT uiprivUpdateImageListSize(uiTable *t)
|
||||||
|
{
|
||||||
|
HDC dc;
|
||||||
|
int cxList, cyList;
|
||||||
|
HTHEME theme;
|
||||||
|
SIZE sizeCheck;
|
||||||
|
HRESULT hr;
|
||||||
|
|
||||||
|
dc = GetDC(t->hwnd);
|
||||||
|
if (dc == NULL) {
|
||||||
|
logLastError(L"GetDC()");
|
||||||
|
return E_FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
cxList = GetSystemMetrics(SM_CXSMICON);
|
||||||
|
cyList = GetSystemMetrics(SM_CYSMICON);
|
||||||
|
sizeCheck.cx = cxList;
|
||||||
|
sizeCheck.cy = cyList;
|
||||||
|
theme = OpenThemeData(t->hwnd, L"button");
|
||||||
|
if (theme != NULL) {
|
||||||
|
hr = GetThemePartSize(theme, dc,
|
||||||
|
BP_CHECKBOX, CBS_UNCHECKEDNORMAL,
|
||||||
|
NULL, TS_DRAW, &sizeCheck);
|
||||||
|
if (hr != S_OK) {
|
||||||
|
logHRESULT(L"GetThemePartSize()", hr);
|
||||||
|
return hr; // TODO fall back?
|
||||||
|
}
|
||||||
|
// make sure these checkmarks fit
|
||||||
|
// unthemed checkmarks will by the code above be smaller than cxList/cyList here
|
||||||
|
if (cxList < sizeCheck.cx)
|
||||||
|
cxList = sizeCheck.cx;
|
||||||
|
if (cyList < sizeCheck.cy)
|
||||||
|
cyList = sizeCheck.cy;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO handle errors
|
||||||
|
t->imagelist = ImageList_Create(cxList, cyList,
|
||||||
|
ILC_COLOR32,
|
||||||
|
1, 1);
|
||||||
|
if (t->smallImages == NULL) {
|
||||||
|
logLastError(L"ImageList_Create()");
|
||||||
|
return E_FAIL;
|
||||||
|
}
|
||||||
|
// TODO will this return NULL here because it's an initial state?
|
||||||
|
SendMessageW(t->hwnd, LVM_SETIMAGELIST, LVSIL_SMALL, (LPARAM) (t->smallImages));
|
||||||
|
|
||||||
|
hr = CloseThemeData(theme);
|
||||||
|
if (hr != S_OK) {
|
||||||
|
logHRESULT(L"CloseThemeData()", hr);
|
||||||
|
return hr;
|
||||||
|
}
|
||||||
|
if (ReleaseDC(t->hwnd, dc) == 0) {
|
||||||
|
logLastError(L"ReleaseDC()");
|
||||||
|
return E_FAIL;
|
||||||
|
}
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
|
|
@ -21,44 +21,7 @@ We'll use the small image list. For this, the first few items will be reserved f
|
||||||
#define nCheckboxImages 4
|
#define nCheckboxImages 4
|
||||||
|
|
||||||
static HRESULT setCellImage(uiTable *t, NMLVDISPINFOW *nm, uiprivTableColumnParams *p, uiTableData *data)
|
static HRESULT setCellImage(uiTable *t, NMLVDISPINFOW *nm, uiprivTableColumnParams *p, uiTableData *data)
|
||||||
{
|
{return E_NOTIMPL;/*TODO*/}
|
||||||
int index;
|
|
||||||
HDC dc;
|
|
||||||
IWICBitmap *wb;
|
|
||||||
HBITMAP b;
|
|
||||||
|
|
||||||
index = t->smallIndex + nCheckboxImages;
|
|
||||||
t->smallIndex++;
|
|
||||||
t->smallIndex %= uiprivNumLVN_GETDISPINFOSkip;
|
|
||||||
nm->item.iImage = index;
|
|
||||||
|
|
||||||
dc = GetDC(t->hwnd);
|
|
||||||
if (dc == NULL) {
|
|
||||||
logLastError(L"GetDC()");
|
|
||||||
return E_FAIL;
|
|
||||||
}
|
|
||||||
|
|
||||||
wb = uiprivImageAppropriateForDC(uiTableDataImage(data), dc);
|
|
||||||
b = uiprivWICToGDI(wb, dc);
|
|
||||||
// TODO rewrite this condition to make more sense; possibly swap the if and else blocks too
|
|
||||||
if (ImageList_GetImageCount(t->smallImages) > index) {
|
|
||||||
if (ImageList_Replace(t->smallImages, index, b, NULL) == 0) {
|
|
||||||
logLastError(L"ImageList_Replace()");
|
|
||||||
return E_FAIL;
|
|
||||||
}
|
|
||||||
} else
|
|
||||||
if (ImageList_Add(t->smallImages, b, NULL) == -1) {
|
|
||||||
logLastError(L"ImageList_Add()");
|
|
||||||
return E_FAIL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ReleaseDC(t->hwnd, dc) == 0) {
|
|
||||||
logLastError(L"ReleaseDC()");
|
|
||||||
return E_FAIL;
|
|
||||||
}
|
|
||||||
|
|
||||||
return S_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
#define stateUnchecked 0
|
#define stateUnchecked 0
|
||||||
#define stateChecked 1
|
#define stateChecked 1
|
||||||
|
@ -105,6 +68,10 @@ HRESULT uiprivLVN_GETDISPINFOImagesCheckboxes(uiTable *t, NMLVDISPINFOW *nm, uip
|
||||||
if ((nm->item.mask & LVIF_IMAGE) == 0)
|
if ((nm->item.mask & LVIF_IMAGE) == 0)
|
||||||
return S_OK; // nothing to do here
|
return S_OK; // nothing to do here
|
||||||
|
|
||||||
|
// TODO
|
||||||
|
nm->item.iImage = 0;
|
||||||
|
return S_OK;
|
||||||
|
|
||||||
if (p->imageModelColumn != -1) {
|
if (p->imageModelColumn != -1) {
|
||||||
data = (*(t->model->mh->CellValue))(t->model->mh, t->model, nm->item.iItem, p->imageModelColumn);
|
data = (*(t->model->mh->CellValue))(t->model->mh, t->model, nm->item.iItem, p->imageModelColumn);
|
||||||
hr = setCellImage(t, nm, p, data);
|
hr = setCellImage(t, nm, p, data);
|
||||||
|
@ -297,65 +264,3 @@ static HRESULT mkCheckboxes(uiTable *t, HTHEME theme, HDC dc, int cxList, int cy
|
||||||
DeleteObject(b);
|
DeleteObject(b);
|
||||||
return S_OK;
|
return S_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO run again when the DPI changes
|
|
||||||
HRESULT uiprivTableSetupImagesCheckboxes(uiTable *t)
|
|
||||||
{
|
|
||||||
HDC dc;
|
|
||||||
int cxList, cyList;
|
|
||||||
HTHEME theme;
|
|
||||||
SIZE sizeCheck;
|
|
||||||
HRESULT hr;
|
|
||||||
|
|
||||||
dc = GetDC(t->hwnd);
|
|
||||||
if (dc == NULL) {
|
|
||||||
logLastError(L"GetDC()");
|
|
||||||
return E_FAIL;
|
|
||||||
}
|
|
||||||
|
|
||||||
cxList = GetSystemMetrics(SM_CXSMICON);
|
|
||||||
cyList = GetSystemMetrics(SM_CYSMICON);
|
|
||||||
sizeCheck.cx = cxList;
|
|
||||||
sizeCheck.cy = cyList;
|
|
||||||
theme = OpenThemeData(t->hwnd, L"button");
|
|
||||||
if (theme != NULL) {
|
|
||||||
hr = GetThemePartSize(theme, dc,
|
|
||||||
BP_CHECKBOX, CBS_UNCHECKEDNORMAL,
|
|
||||||
NULL, TS_DRAW, &sizeCheck);
|
|
||||||
if (hr != S_OK) {
|
|
||||||
logHRESULT(L"GetThemePartSize()", hr);
|
|
||||||
return hr; // TODO fall back?
|
|
||||||
}
|
|
||||||
// make sure these checkmarks fit
|
|
||||||
// unthemed checkmarks will by the code above be smaller than cxList/cyList here
|
|
||||||
if (cxList < sizeCheck.cx)
|
|
||||||
cxList = sizeCheck.cx;
|
|
||||||
if (cyList < sizeCheck.cy)
|
|
||||||
cyList = sizeCheck.cy;
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO handle errors
|
|
||||||
t->smallImages = ImageList_Create(cxList, cyList,
|
|
||||||
ILC_COLOR32,
|
|
||||||
nCheckboxImages + uiprivNumLVN_GETDISPINFOSkip, nCheckboxImages + uiprivNumLVN_GETDISPINFOSkip);
|
|
||||||
if (t->smallImages == NULL) {
|
|
||||||
logLastError(L"ImageList_Create()");
|
|
||||||
return E_FAIL;
|
|
||||||
}
|
|
||||||
// TODO will this return NULL here because it's an initial state?
|
|
||||||
SendMessageW(t->hwnd, LVM_SETIMAGELIST, LVSIL_SMALL, (LPARAM) (t->smallImages));
|
|
||||||
hr = mkCheckboxes(t, theme, dc, cxList, cyList, sizeCheck.cx, sizeCheck.cy);
|
|
||||||
if (hr != S_OK)
|
|
||||||
return hr;
|
|
||||||
|
|
||||||
hr = CloseThemeData(theme);
|
|
||||||
if (hr != S_OK) {
|
|
||||||
logHRESULT(L"CloseThemeData()", hr);
|
|
||||||
return hr;
|
|
||||||
}
|
|
||||||
if (ReleaseDC(t->hwnd, dc) == 0) {
|
|
||||||
logLastError(L"ReleaseDC()");
|
|
||||||
return E_FAIL;
|
|
||||||
}
|
|
||||||
return S_OK;
|
|
||||||
}
|
|
||||||
|
|
Loading…
Reference in New Issue