And consolidated the LVN_DISPINFO handlers. Everything's a lot cleaner now too, woo!

This commit is contained in:
Pietro Gagliardi 2018-06-16 12:33:16 -04:00
parent b9289c93a6
commit bcab521311
6 changed files with 81 additions and 133 deletions

View File

@ -51,9 +51,8 @@ list(APPEND _LIBUI_SOURCES
windows/stddialogs.cpp
windows/tab.cpp
windows/table.cpp
windows/tabledispinfo.cpp
windows/tabledraw.cpp
windows/tableimages.cpp
windows/tabletext.cpp
windows/tabpage.cpp
windows/text.cpp
windows/utf16.cpp

View File

@ -76,25 +76,6 @@ void uiTableModelRowDeleted(uiTableModel *m, int oldIndex)
}
}
static LRESULT onLVN_GETDISPINFO(uiTable *t, NMLVDISPINFOW *nm)
{
// TODO remove static
static uiprivTableColumnParams *p;
HRESULT hr;
p = (*(t->columns))[nm->item.iSubItem];
hr = uiprivLVN_GETDISPINFOText(t, nm, p);
if (hr != S_OK) {
// TODO
}
hr = uiprivLVN_GETDISPINFOImagesCheckboxes(t, nm, p);
if (hr != S_OK) {
// TODO
}
return 0;
}
static BOOL onWM_NOTIFY(uiControl *c, HWND hwnd, NMHDR *nmhdr, LRESULT *lResult)
{
uiTable *t = uiTable(c);
@ -102,7 +83,11 @@ static BOOL onWM_NOTIFY(uiControl *c, HWND hwnd, NMHDR *nmhdr, LRESULT *lResult)
switch (nmhdr->code) {
case LVN_GETDISPINFO:
*lResult = onLVN_GETDISPINFO(t, (NMLVDISPINFOW *) nmhdr);
hr = uiprivTableHandleLVN_GETDISPINFO(t, (NMLVDISPINFOW *) nmhdr, lResult);
if (hr != S_OK) {
// TODO
return FALSE;
}
return TRUE;
case NM_CUSTOMDRAW:
hr = uiprivTableHandleNM_CUSTOMDRAW(t, (NMLVCUSTOMDRAW *) nmhdr, lResult);

View File

@ -32,21 +32,9 @@ struct uiTable {
// TODO make sure replacing images while selected in the listview is even allowed
HIMAGELIST imagelist;
};
typedef struct uiprivSubitemDrawParams uiprivSubitemDrawParams;
struct uiprivSubitemDrawParams {
bool selected;
LRESULT bitmapMargin;
RECT bounds;
RECT icon;
RECT label;
};
// tabletext.cpp
extern HRESULT uiprivLVN_GETDISPINFOText(uiTable *t, NMLVDISPINFOW *nm, uiprivTableColumnParams *p);
// tableimages.cpp
extern HRESULT uiprivLVN_GETDISPINFOImagesCheckboxes(uiTable *t, NMLVDISPINFOW *nm, uiprivTableColumnParams *p);
extern HRESULT uiprivNM_CUSTOMDRAWImagesCheckboxes(uiTable *t, NMLVCUSTOMDRAW *nm, uiprivSubitemDrawParams *dp);
// tabledispinfo.cpp
extern HRESULT uiprivTableHandleLVN_GETDISPINFO(uiTable *t, NMLVDISPINFOW *nm, LRESULT *lResult);
// tabledraw.cpp
extern HRESULT uiprivTableHandleNM_CUSTOMDRAW(uiTable *t, NMLVCUSTOMDRAW *nm, LRESULT *lResult);

73
windows/tabledispinfo.cpp Normal file
View File

@ -0,0 +1,73 @@
// 13 june 2018
#include "uipriv_windows.hpp"
#include "table.hpp"
static HRESULT handleLVIF_TEXT(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
// LVN_GETITEMRECT with LVIR_LABEL) 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;
}
static HRESULT handleLVIF_IMAGE(uiTable *t, NMLVDISPINFOW *nm, uiprivTableColumnParams *p)
{
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)
return S_OK; // nothing to do here
// TODO see if the -1 part is correct
// TODO see if we should use state instead of images for checkbox data
nm->item.iImage = -1;
if (p->imageModelColumn != -1 || p->checkboxModelColumn != -1)
nm->item.iImage = 0;
return S_OK;
}
HRESULT uiprivTableHandleLVN_GETDISPINFO(uiTable *t, NMLVDISPINFOW *nm, LRESULT *lResult)
{
uiprivTableColumnParams *p;
HRESULT hr;
p = (*(t->columns))[nm->item.iSubItem];
hr = handleLVIF_TEXT(t, nm, p);
if (hr != S_OK)
return hr;
hr = handleLVIF_IMAGE(t, nm, p);
if (hr != S_OK)
return hr;
*lResult = 0;
return S_OK;
}

View File

@ -1,68 +0,0 @@
// 10 june 2018
#include "uipriv_windows.hpp"
#include "table.hpp"
/*
This file handles both images and checkboxes in tables.
For images, we'll do a similar thing to what text columns do: cycle out images from the small image list every few LVN_GETDISPINFO notifications.
For checkboxes, the native list view checkbox functionality uses state images, but those are only supported on the main item, not on subitems. So instead, we'll do them on normal images instead.
TODO will this affect accessibility?
We'll use the small image list. For this, the first few items will be reserved for checkboxes, and the last few for cell images.
*/
// checkboxes TODOs:
// - see if we need to get rid of the extra margin in subitems
// - get rid of the extra bitmap margin space before text
// - get rid of extra whitespace before text on subitems (this might not be necessary if we can fill the background of images AND this amount is the same as on the first column; it is a hardcoded 2 logical units in the real list view code)
#define nCheckboxImages 4
HRESULT uiprivLVN_GETDISPINFOImagesCheckboxes(uiTable *t, NMLVDISPINFOW *nm, uiprivTableColumnParams *p)
{
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)
return S_OK; // nothing to do here
// TODO
nm->item.iImage = -1;
if (p->imageModelColumn != -1 || p->checkboxModelColumn != -1)
nm->item.iImage = 0;
return S_OK;
if (p->imageModelColumn != -1) {
nm->item.iImage = 0;
return S_OK;
}
if (p->checkboxModelColumn != -1) {
#if 0
// TODO handle enabled
data = (*(t->model->mh->CellValue))(t->model->mh, t->model, nm->item.iItem, p->textModelColumn);
checked = uiTableDataInt(data) != 0;
uiFreeTableData(data);
nm->item.iImage = 0;
if (checked)
nm->item.iImage = 1;
nm->item.mask |= LVIF_IMAGE;
#endif
nm->item.mask |= LVIF_IMAGE;
nm->item.iImage = nm->item.iItem % 4;
return S_OK;
}
// TODO see if this is correct
nm->item.iImage = -1;
return S_OK;
}

View File

@ -1,29 +0,0 @@
// 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;
}