assorted consistancy cleanup

This commit is contained in:
Ben Campbell 2018-05-22 22:53:25 +12:00
parent 7402dec266
commit 4246ae5549
1 changed files with 90 additions and 70 deletions

View File

@ -1,14 +1,12 @@
#include "uipriv_windows.hpp" #include "uipriv_windows.hpp"
static void uiTableDestroy(uiControl *c); //static void uiTableMinimumSize(uiWindowsControl *c, int *width, int *height);
static void uiTableMinimumSize(uiWindowsControl *c, int *width, int *height);
static BOOL onWM_NOTIFY(uiControl *c, HWND hwnd, NMHDR *nm, LRESULT *lResult);
struct uiTable; struct uiTable;
struct uiTableModel { struct uiTableModel {
uiTableModelHandler *mh; uiTableModelHandler *mh;
std::vector<uiTable*> tables; std::vector<uiTable *> tables;
}; };
struct uiTableColumn { struct uiTableColumn {
@ -22,7 +20,7 @@ struct uiTable {
uiWindowsControl c; uiWindowsControl c;
uiTableModel *model; uiTableModel *model;
HWND hwnd; HWND hwnd;
std::vector<uiTableColumn*> columns; std::vector<uiTableColumn *> columns;
}; };
void *uiTableModelStrdup(const char *str) void *uiTableModelStrdup(const char *str)
@ -52,27 +50,31 @@ void uiFreeTableModel(uiTableModel *m)
void uiTableModelRowInserted(uiTableModel *m, int newIndex) void uiTableModelRowInserted(uiTableModel *m, int newIndex)
{ {
LVITEM item; LVITEMW item;
ZeroMemory(&item, sizeof (LVITEMW));
item.mask = 0; item.mask = 0;
item.iItem = newIndex; item.iItem = newIndex;
item.iSubItem = 0; //? item.iSubItem = 0; //?
for (auto t : m->tables) { for (auto t : m->tables) {
ListView_InsertItem( t->hwnd, &item ); if (SendMessageW(t->hwnd, LVM_INSERTITEM, 0, (LPARAM) (&item)) == (LRESULT) (-1))
logLastError(L"error calling LVM_INSERTITEM in uiTableModelRowInserted()");
} }
} }
void uiTableModelRowChanged(uiTableModel *m, int index) void uiTableModelRowChanged(uiTableModel *m, int index)
{ {
for (auto t : m->tables) { for (auto t : m->tables) {
ListView_Update( t->hwnd, index ); if (SendMessageW(t->hwnd, LVM_UPDATE, (WPARAM) index, 0) == (LRESULT) (-1))
logLastError(L"error calling LVM_UPDATE in uiTableModelRowChanged()");
} }
} }
void uiTableModelRowDeleted(uiTableModel *m, int oldIndex) void uiTableModelRowDeleted(uiTableModel *m, int oldIndex)
{ {
for (auto t : m->tables) { for (auto t : m->tables) {
ListView_DeleteItem( t->hwnd, oldIndex ); if (SendMessageW(t->hwnd, LVM_DELETEITEM, (WPARAM) oldIndex, 0) == (LRESULT) (-1))
logLastError(L"error calling LVM_DELETEITEM in uiTableModelRowDeleted()");
} }
} }
@ -80,6 +82,7 @@ void uiTableColumnAppendTextPart(uiTableColumn *c, int modelColumn, int expand)
{ {
uiTable *t = c->t; uiTable *t = c->t;
int lvIndex = 0; int lvIndex = 0;
LVCOLUMNW lvc;
if (c->modelColumn >=0) { if (c->modelColumn >=0) {
return; // multiple parts not implemented return; // multiple parts not implemented
@ -92,16 +95,17 @@ void uiTableColumnAppendTextPart(uiTableColumn *c, int modelColumn, int expand)
break; break;
} }
if (candidate->modelColumn >= 0) { if (candidate->modelColumn >= 0) {
++lvIndex; lvIndex++;
} }
} }
LV_COLUMN lvc; ZeroMemory(&lvc, sizeof (LVCOLUMNW));
lvc.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT; /* | LVCF_SUBITEM; */ lvc.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT; /* | LVCF_SUBITEM; */
lvc.fmt = LVCFMT_LEFT; lvc.fmt = LVCFMT_LEFT;
lvc.cx = 120; // TODO lvc.cx = 120; // TODO
lvc.pszText = c->name; lvc.pszText = c->name;
ListView_InsertColumn(c->t->hwnd, lvIndex, &lvc); if (SendMessageW(c->t->hwnd, LVM_INSERTCOLUMN, (WPARAM) lvIndex, (LPARAM) (&lvc)) == (LRESULT) (-1))
logLastError(L"error calling LVM_INSERTCOLUMN in uiTableColumnPartSetTextPart()");
} }
void uiTableColumnAppendImagePart(uiTableColumn *c, int modelColumn, int expand) void uiTableColumnAppendImagePart(uiTableColumn *c, int modelColumn, int expand)
@ -138,33 +142,11 @@ void uiTableColumnPartSetTextColor(uiTableColumn *c, int part, int modelColumn)
uiWindowsControlAllDefaultsExceptDestroy(uiTable) uiWindowsControlAllDefaultsExceptDestroy(uiTable)
uiTable *uiNewTable(uiTableModel *model)
{
uiTable *t;
int winStyle = WS_CHILD | LVS_AUTOARRANGE | LVS_REPORT | LVS_OWNERDATA | LVS_SINGLESEL;
uiWindowsNewControl(uiTable, t);
new(&t->columns) std::vector<uiTableColumn*>(); // (initialising in place)
t->model = model;
t->hwnd = uiWindowsEnsureCreateControlHWND(WS_EX_CLIENTEDGE,
WC_LISTVIEW,
L"",
winStyle,
hInstance,
NULL,
TRUE);
model->tables.push_back(t);
uiWindowsRegisterWM_NOTIFYHandler(t->hwnd, onWM_NOTIFY, uiControl(t));
ListView_SetExtendedListViewStyle(t->hwnd, LVS_EX_FULLROWSELECT | LVS_EX_LABELTIP);
// TODO: try LVS_EX_AUTOSIZECOLUMNS
int n = (*(model->mh->NumRows))(model->mh, model);
ListView_SetItemCountEx(t->hwnd, n, 0);
return t;
}
uiTableColumn *uiTableAppendColumn(uiTable *t, const char *name) uiTableColumn *uiTableAppendColumn(uiTable *t, const char *name)
{ {
uiTableColumn *c = uiprivNew(uiTableColumn); uiTableColumn *c;
c = uiprivNew(uiTableColumn);
c->name = toUTF16(name); c->name = toUTF16(name);
c->t = t; c->t = t;
c->modelColumn = -1; // -1 = unassigned c->modelColumn = -1; // -1 = unassigned
@ -182,81 +164,93 @@ static void uiTableDestroy(uiControl *c)
{ {
uiTable *t = uiTable(c); uiTable *t = uiTable(c);
uiTableModel *model = t->model; uiTableModel *model = t->model;
std::vector<uiTable*>::iterator it; std::vector<uiTable *>::iterator it;
uiWindowsUnregisterWM_NOTIFYHandler(t->hwnd); uiWindowsUnregisterWM_NOTIFYHandler(t->hwnd);
uiWindowsEnsureDestroyWindow(t->hwnd); uiWindowsEnsureDestroyWindow(t->hwnd);
// detach table from model // detach table from model
for (it = model->tables.begin(); it != model->tables.end(); ++it) { for (it = model->tables.begin(); it != model->tables.end(); it++) {
if (*it == t) { if (*it == t) {
model->tables.erase(it); model->tables.erase(it);
break; break;
} }
} }
// free the columns // free the columns
for (auto col: t->columns) { for (auto col : t->columns) {
uiprivFree(col->name); uiprivFree(col->name);
uiprivFree(col); uiprivFree(col);
} }
t->columns.~vector<uiTableColumn*>(); // (created with placement new, so just call dtor directly) t->columns.~vector<uiTableColumn *>(); // (created with placement new, so just call dtor directly)
uiFreeControl(uiControl(t)); uiFreeControl(uiControl(t));
} }
// suggested listview sizing from http://msdn.microsoft.com/en-us/library/windows/desktop/dn742486.aspx#sizingandspacing:
// "columns widths that avoid truncated data x an integral number of items"
// Don't think that'll cut it when some cells have overlong data (eg
// stupidly long URLs). So for now, just hardcode a minimum:
#define tableMinWidth 107 /* in line with other controls */
#define tableMinHeight (14*3) /* header + 2 lines (roughly) */
static void uiTableMinimumSize(uiWindowsControl *c, int *width, int *height) static void uiTableMinimumSize(uiWindowsControl *c, int *width, int *height)
{ {
uiTable *t = uiTable(c); uiTable *t = uiTable(c);
uiWindowsSizing sizing; uiWindowsSizing sizing;
int x, y; int x, y;
// suggested listview sizing from http://msdn.microsoft.com/en-us/library/windows/desktop/dn742486.aspx#sizingandspacing: x = tableMinWidth;
// "columns widths that avoid truncated data x an integral number of items" y = tableMinHeight;
// Don't think that'll cut it when some cells have overlong data (eg
// stupidly long URLs). So for now, just hardcode a minimum:
x = 107; // in line with other controls
y = 14*3; // header + 2 lines (roughly)
uiWindowsGetSizing(t->hwnd, &sizing); uiWindowsGetSizing(t->hwnd, &sizing);
uiWindowsSizingDlgUnitsToPixels(&sizing, &x, &y); uiWindowsSizingDlgUnitsToPixels(&sizing, &x, &y);
*width = x; *width = x;
*height = y; *height = y;
} }
static BOOL onWM_NOTIFY(uiControl *c, HWND hwnd, NMHDR *nm, LRESULT *lResult)
static BOOL onWM_NOTIFY(uiControl *c, HWND hwnd, NMHDR *nmhdr, LRESULT *lResult)
{ {
uiTable *t = uiTable(c); uiTable *t = uiTable(c);
uiTableModelHandler *mh = t->model->mh; uiTableModelHandler *mh = t->model->mh;
BOOL ret = FALSE; BOOL ret = FALSE;
switch (nm->code) { switch (nmhdr->code) {
case LVN_GETDISPINFO: case LVN_GETDISPINFO:
{ {
NMLVDISPINFO* di = (NMLVDISPINFO*)nm; NMLVDISPINFOW *di;
LVITEM* item = &di->item; LVITEMW *item;
if (!(item->mask & LVIF_TEXT)) { int row, col;
break; uiTableColumn *tc;
} int mcol;
int row = item->iItem; uiTableModelColumnType typ;
int col = item->iSubItem;
if (col<0 || col>=(int)t->columns.size()) {
break;
}
uiTableColumn *tc = (uiTableColumn*)t->columns[col]; di = (NMLVDISPINFOW *)nmhdr;
item = &(di->item);
if (!(item->mask & LVIF_TEXT))
break;
row = item->iItem;
col = item->iSubItem;
if (col<0 || col>=(int)t->columns.size())
break;
tc = (uiTableColumn *)t->columns[col];
mcol = tc->modelColumn;
typ = (*mh->ColumnType)(mh, t->model, mcol);
int mcol = tc->modelColumn;
uiTableModelColumnType typ = (*mh->ColumnType)(mh,t->model,mcol);
if (typ == uiTableModelColumnString) { if (typ == uiTableModelColumnString) {
void* data = (*(mh->CellValue))(mh, t->model, row, mcol); void* data;
int n = MultiByteToWideChar(CP_UTF8, 0, (const char*)data, -1, item->pszText, item->cchTextMax); int n;
data = (*(mh->CellValue))(mh, t->model, row, mcol);
n = MultiByteToWideChar(CP_UTF8, 0, (const char *)data, -1, item->pszText, item->cchTextMax);
// make sure clipped strings are nul-terminated // make sure clipped strings are nul-terminated
if (n>=item->cchTextMax) { if (n>=item->cchTextMax)
item->pszText[item->cchTextMax-1] = L'\0'; item->pszText[item->cchTextMax-1] = L'\0';
}
} else if (typ == uiTableModelColumnInt) { } else if (typ == uiTableModelColumnInt) {
char buf[32]; char buf[32];
intptr_t data = (intptr_t)(*(mh->CellValue))(mh, t->model, row, mcol); intptr_t data;
int n;
data = (intptr_t)(*(mh->CellValue))(mh, t->model, row, mcol);
sprintf(buf, "%d", (int)data); sprintf(buf, "%d", (int)data);
int n = MultiByteToWideChar(CP_UTF8, 0, buf, -1, item->pszText, item->cchTextMax); n = MultiByteToWideChar(CP_UTF8, 0, buf, -1, item->pszText, item->cchTextMax);
// make sure clipped strings are nul-terminated // make sure clipped strings are nul-terminated
if (n>=item->cchTextMax) { if (n>=item->cchTextMax) {
item->pszText[item->cchTextMax-1] = L'\0'; item->pszText[item->cchTextMax-1] = L'\0';
@ -273,3 +267,29 @@ static BOOL onWM_NOTIFY(uiControl *c, HWND hwnd, NMHDR *nm, LRESULT *lResult)
return ret; return ret;
} }
uiTable *uiNewTable(uiTableModel *model)
{
uiTable *t;
int n;
uiWindowsNewControl(uiTable, t);
new(&t->columns) std::vector<uiTableColumn *>(); // (initialising in place)
t->model = model;
t->hwnd = uiWindowsEnsureCreateControlHWND(WS_EX_CLIENTEDGE,
WC_LISTVIEW, L"",
LVS_REPORT | LVS_OWNERDATA | LVS_SINGLESEL | WS_TABSTOP | WS_HSCROLL | WS_VSCROLL,
hInstance, NULL,
TRUE);
model->tables.push_back(t);
uiWindowsRegisterWM_NOTIFYHandler(t->hwnd, onWM_NOTIFY, uiControl(t));
SendMessageW(t->hwnd, LVM_SETEXTENDEDLISTVIEWSTYLE,
(WPARAM) (LVS_EX_FULLROWSELECT | LVS_EX_LABELTIP),
(LPARAM) (LVS_EX_FULLROWSELECT | LVS_EX_LABELTIP));
// TODO: try LVS_EX_AUTOSIZECOLUMNS
n = (*(model->mh->NumRows))(model->mh, model);
if (SendMessageW(t->hwnd, LVM_SETITEMCOUNT, (WPARAM) n, 0) == 0)
logLastError(L"error calling LVM_SETITEMCOUNT in uiNewTable()");
return t;
}