From fc2ea17bb8ccc5f3d1a9375d5584d273aea3b449 Mon Sep 17 00:00:00 2001 From: Ben Campbell Date: Sat, 5 May 2018 22:45:01 +1200 Subject: [PATCH 1/5] Add minimal uiTable implementation for windows This uses the win32 common controls listview to implement uiTable. There are limitations: - It supports only a single TextPart per column. - ImagePart, CheckboxPart and ProgessBarPart are not implemented. - There is no support for cell coloring. - Cell editing is not implemented. Some of these will be very hard to support using the standard common control listview, and probably require an entire custom listview. --- test/page16.c | 2 + windows/CMakeLists.txt | 2 + windows/image.cpp | 31 +++++ windows/table.cpp | 277 +++++++++++++++++++++++++++++++++++++++++ 4 files changed, 312 insertions(+) create mode 100644 windows/image.cpp create mode 100644 windows/table.cpp diff --git a/test/page16.c b/test/page16.c index 80ac01397..3a5ac639b 100644 --- a/test/page16.c +++ b/test/page16.c @@ -132,6 +132,8 @@ uiBox *makePage16(void) uiTableSetRowBackgroundColorModelColumn(t, 3); + uiTableAppendTextColumn(t, "Numbers", 8); + tc = uiTableAppendColumn(t, "Buttons"); uiTableColumnAppendCheckboxPart(tc, 7, 0); uiTableColumnAppendButtonPart(tc, 6, 1); diff --git a/windows/CMakeLists.txt b/windows/CMakeLists.txt index 16beefa7a..b871b5290 100644 --- a/windows/CMakeLists.txt +++ b/windows/CMakeLists.txt @@ -34,6 +34,7 @@ list(APPEND _LIBUI_SOURCES windows/graphemes.cpp windows/grid.cpp windows/group.cpp + windows/image.cpp windows/init.cpp windows/label.cpp windows/main.cpp @@ -49,6 +50,7 @@ list(APPEND _LIBUI_SOURCES windows/spinbox.cpp windows/stddialogs.cpp windows/tab.cpp + windows/table.cpp windows/tabpage.cpp windows/text.cpp windows/utf16.cpp diff --git a/windows/image.cpp b/windows/image.cpp new file mode 100644 index 000000000..bba013b1f --- /dev/null +++ b/windows/image.cpp @@ -0,0 +1,31 @@ +#include "uipriv_windows.hpp" +// stubbed out windows image list implementation. +// Required for uiTable control, but windows implemenation +// doesn't currently have image support. + +struct uiImage { + double width; + double height; + // HIMAGELIST images; +}; + +uiImage *uiNewImage(double width, double height) +{ + uiImage *i; + + i = uiprivNew(uiImage); + i->width = width; + i->height = height; + return i; +} + +void uiFreeImage(uiImage *i) +{ + uiprivFree(i); +} + +void uiImageAppend(uiImage *i, void *pixels, int pixelWidth, int pixelHeight, int pixelStride) +{ + // not implemented +} + diff --git a/windows/table.cpp b/windows/table.cpp new file mode 100644 index 000000000..5d2273af8 --- /dev/null +++ b/windows/table.cpp @@ -0,0 +1,277 @@ +#include "uipriv_windows.hpp" + +#include + +static void uiTableDestroy(uiControl *c); +static void uiTableMinimumSize(uiWindowsControl *c, int *width, int *height); +static BOOL onWM_NOTIFY(uiControl *c, HWND hwnd, NMHDR *nm, LRESULT *lResult); + +struct uiTable; + +struct uiTableModel { + uiTableModelHandler *mh; + std::vector tables; +}; + +struct uiTableColumn { + uiTable *t; + WCHAR *name; + // don't really support parts (but this would part=>column mappings if we did) + int modelColumn; // -1 = none +}; + +struct uiTable { + uiWindowsControl c; + uiTableModel *model; + HWND hwnd; + std::vector columns; +}; + +void *uiTableModelStrdup(const char *str) +{ + return strdup(str); +} + +void *uiTableModelGiveColor(double r, double g, double b, double a) +{ + return 0; // not implemented +} + +uiTableModel *uiNewTableModel(uiTableModelHandler *mh) +{ + uiTableModel *m; + + m = new uiTableModel(); + m->mh = mh; + return m; +} + + +void uiFreeTableModel(uiTableModel *m) +{ + delete m; +} + +void uiTableModelRowInserted(uiTableModel *m, int newIndex) +{ + LVITEM item; + + item.mask = 0; + item.iItem = newIndex; + item.iSubItem = 0; //? + for (auto t : m->tables) { + ListView_InsertItem( t->hwnd, &item ); + } +} + +void uiTableModelRowChanged(uiTableModel *m, int index) +{ + for (auto t : m->tables) { + ListView_Update( t->hwnd, index ); + } +} + +void uiTableModelRowDeleted(uiTableModel *m, int oldIndex) +{ + for (auto t : m->tables) { + ListView_DeleteItem( t->hwnd, oldIndex ); + } +} + +void uiTableColumnAppendTextPart(uiTableColumn *c, int modelColumn, int expand) +{ + uiTable *t = c->t; + int lvIndex = 0; + + if (c->modelColumn >=0) { + return; // multiple parts not implemented + } + c->modelColumn = modelColumn; + + // work out appropriate listview index for the column + for (auto candidate : t->columns) { + if (candidate == c) { + break; + } + if (candidate->modelColumn >= 0) { + ++lvIndex; + } + } + + LV_COLUMN lvc; + lvc.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT; /* | LVCF_SUBITEM; */ + lvc.fmt = LVCFMT_LEFT; + lvc.cx = 120; // TODO + lvc.pszText = c->name; + ListView_InsertColumn(c->t->hwnd, lvIndex, &lvc); +} + +void uiTableColumnAppendImagePart(uiTableColumn *c, int modelColumn, int expand) +{ + // not implemented +} + +void uiTableColumnAppendButtonPart(uiTableColumn *c, int modelColumn, int expand) +{ + // not implemented +} + +void uiTableColumnAppendCheckboxPart(uiTableColumn *c, int modelColumn, int expand) +{ + // not implemented +} + +void uiTableColumnAppendProgressBarPart(uiTableColumn *c, int modelColumn, int expand) +{ + // not implemented +} + +void uiTableColumnPartSetEditable(uiTableColumn *c, int part, int editable) +{ + // TODO +} + +void uiTableColumnPartSetTextColor(uiTableColumn *c, int part, int modelColumn) +{ + // not implemented +} + +// uiTable implementation + +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(); // (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 *c = uiprivNew(uiTableColumn); + c->name = toUTF16(name); + c->t = t; + c->modelColumn = -1; // -1 = unassigned + // we defer the actual ListView_InsertColumn call until a part is added... + t->columns.push_back(c); + return c; +} + +void uiTableSetRowBackgroundColorModelColumn(uiTable *t, int modelColumn) +{ + // not implemented +} + +static void uiTableDestroy(uiControl *c) +{ + uiTable *t = uiTable(c); + uiTableModel *model = t->model; + std::vector::iterator it; + + uiWindowsUnregisterWM_NOTIFYHandler(t->hwnd); + uiWindowsEnsureDestroyWindow(t->hwnd); + // detach table from model + for (it = model->tables.begin(); it != model->tables.end(); ++it) { + if (*it == t) { + model->tables.erase(it); + break; + } + } + // free the columns + for (auto col: t->columns) { + uiprivFree(col->name); + uiprivFree(col); + } + t->columns.~vector(); // (created with placement new, so just call dtor directly) + uiFreeControl(uiControl(t)); +} + +static void uiTableMinimumSize(uiWindowsControl *c, int *width, int *height) +{ + uiTable *t = uiTable(c); + uiWindowsSizing sizing; + int x, y; + + // 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: + + x = 107; // in line with other controls + y = 14*3; // header + 2 lines (roughly) + uiWindowsGetSizing(t->hwnd, &sizing); + uiWindowsSizingDlgUnitsToPixels(&sizing, &x, &y); + *width = x; + *height = y; +} + +static BOOL onWM_NOTIFY(uiControl *c, HWND hwnd, NMHDR *nm, LRESULT *lResult) +{ + uiTable *t = uiTable(c); + uiTableModelHandler *mh = t->model->mh; + BOOL ret = FALSE; + + switch (nm->code) { + case LVN_GETDISPINFO: + { + NMLVDISPINFO* di = (NMLVDISPINFO*)nm; + LVITEM* item = &di->item; + if (!(item->mask & LVIF_TEXT)) { + break; + } + int row = item->iItem; + int col = item->iSubItem; + if (col<0 || col>=(int)t->columns.size()) { + break; + } + + uiTableColumn *tc = (uiTableColumn*)t->columns[col]; + + int mcol = tc->modelColumn; + uiTableModelColumnType typ = (*mh->ColumnType)(mh,t->model,mcol); + if (typ == uiTableModelColumnString) { + void* data = (*(mh->CellValue))(mh, t->model, row, mcol); + int n = MultiByteToWideChar(CP_UTF8, 0, (const char*)data, -1, item->pszText, item->cchTextMax); + // make sure clipped strings are nul-terminated + if (n>=item->cchTextMax) { + item->pszText[item->cchTextMax-1] = L'\0'; + } + } else if (typ == uiTableModelColumnInt) { + char buf[32]; + intptr_t data = (intptr_t)(*(mh->CellValue))(mh, t->model, row, mcol); + sprintf(buf, "%d", (int)data); + int n = MultiByteToWideChar(CP_UTF8, 0, buf, -1, item->pszText, item->cchTextMax); + // make sure clipped strings are nul-terminated + if (n>=item->cchTextMax) { + item->pszText[item->cchTextMax-1] = L'\0'; + } + } else { + item->pszText[0] = L'\0'; + } + break; + } + default: + break; + } + *lResult = 0; + return ret; +} + From 7402dec26610b6317d40758986a54feaa34140e2 Mon Sep 17 00:00:00 2001 From: Ben Campbell Date: Sun, 6 May 2018 01:29:59 +1200 Subject: [PATCH 2/5] remove superfluous #include --- windows/table.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/windows/table.cpp b/windows/table.cpp index 5d2273af8..4d2ebd123 100644 --- a/windows/table.cpp +++ b/windows/table.cpp @@ -1,7 +1,5 @@ #include "uipriv_windows.hpp" -#include - static void uiTableDestroy(uiControl *c); static void uiTableMinimumSize(uiWindowsControl *c, int *width, int *height); static BOOL onWM_NOTIFY(uiControl *c, HWND hwnd, NMHDR *nm, LRESULT *lResult); From 4246ae5549c43cbd48c0bea726ec16b8d1f38282 Mon Sep 17 00:00:00 2001 From: Ben Campbell Date: Tue, 22 May 2018 22:53:25 +1200 Subject: [PATCH 3/5] assorted consistancy cleanup --- windows/table.cpp | 158 ++++++++++++++++++++++++++-------------------- 1 file changed, 89 insertions(+), 69 deletions(-) diff --git a/windows/table.cpp b/windows/table.cpp index 4d2ebd123..2f7737eec 100644 --- a/windows/table.cpp +++ b/windows/table.cpp @@ -1,14 +1,12 @@ #include "uipriv_windows.hpp" -static void uiTableDestroy(uiControl *c); -static void uiTableMinimumSize(uiWindowsControl *c, int *width, int *height); -static BOOL onWM_NOTIFY(uiControl *c, HWND hwnd, NMHDR *nm, LRESULT *lResult); +//static void uiTableMinimumSize(uiWindowsControl *c, int *width, int *height); struct uiTable; struct uiTableModel { uiTableModelHandler *mh; - std::vector tables; + std::vector tables; }; struct uiTableColumn { @@ -22,7 +20,7 @@ struct uiTable { uiWindowsControl c; uiTableModel *model; HWND hwnd; - std::vector columns; + std::vector columns; }; void *uiTableModelStrdup(const char *str) @@ -52,27 +50,31 @@ void uiFreeTableModel(uiTableModel *m) void uiTableModelRowInserted(uiTableModel *m, int newIndex) { - LVITEM item; + LVITEMW item; + ZeroMemory(&item, sizeof (LVITEMW)); item.mask = 0; item.iItem = newIndex; item.iSubItem = 0; //? 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) { 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) { 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; int lvIndex = 0; + LVCOLUMNW lvc; if (c->modelColumn >=0) { return; // multiple parts not implemented @@ -92,16 +95,17 @@ void uiTableColumnAppendTextPart(uiTableColumn *c, int modelColumn, int expand) break; } if (candidate->modelColumn >= 0) { - ++lvIndex; + lvIndex++; } } - - LV_COLUMN lvc; + + ZeroMemory(&lvc, sizeof (LVCOLUMNW)); lvc.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT; /* | LVCF_SUBITEM; */ lvc.fmt = LVCFMT_LEFT; lvc.cx = 120; // TODO 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) @@ -138,33 +142,11 @@ void uiTableColumnPartSetTextColor(uiTableColumn *c, int part, int modelColumn) 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(); // (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 *c = uiprivNew(uiTableColumn); + uiTableColumn *c; + + c = uiprivNew(uiTableColumn); c->name = toUTF16(name); c->t = t; c->modelColumn = -1; // -1 = unassigned @@ -182,81 +164,93 @@ static void uiTableDestroy(uiControl *c) { uiTable *t = uiTable(c); uiTableModel *model = t->model; - std::vector::iterator it; + std::vector::iterator it; uiWindowsUnregisterWM_NOTIFYHandler(t->hwnd); uiWindowsEnsureDestroyWindow(t->hwnd); // 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) { model->tables.erase(it); break; } } // free the columns - for (auto col: t->columns) { + for (auto col : t->columns) { uiprivFree(col->name); uiprivFree(col); } - t->columns.~vector(); // (created with placement new, so just call dtor directly) + t->columns.~vector(); // (created with placement new, so just call dtor directly) 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) { uiTable *t = uiTable(c); uiWindowsSizing sizing; int x, y; - // 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: - - x = 107; // in line with other controls - y = 14*3; // header + 2 lines (roughly) + x = tableMinWidth; + y = tableMinHeight; uiWindowsGetSizing(t->hwnd, &sizing); uiWindowsSizingDlgUnitsToPixels(&sizing, &x, &y); *width = x; *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); uiTableModelHandler *mh = t->model->mh; BOOL ret = FALSE; - switch (nm->code) { + switch (nmhdr->code) { case LVN_GETDISPINFO: { - NMLVDISPINFO* di = (NMLVDISPINFO*)nm; - LVITEM* item = &di->item; - if (!(item->mask & LVIF_TEXT)) { + NMLVDISPINFOW *di; + LVITEMW *item; + int row, col; + uiTableColumn *tc; + int mcol; + uiTableModelColumnType typ; + + di = (NMLVDISPINFOW *)nmhdr; + item = &(di->item); + if (!(item->mask & LVIF_TEXT)) break; - } - int row = item->iItem; - int col = item->iSubItem; - if (col<0 || col>=(int)t->columns.size()) { + 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); - uiTableColumn *tc = (uiTableColumn*)t->columns[col]; - - int mcol = tc->modelColumn; - uiTableModelColumnType typ = (*mh->ColumnType)(mh,t->model,mcol); if (typ == uiTableModelColumnString) { - void* data = (*(mh->CellValue))(mh, t->model, row, mcol); - int n = MultiByteToWideChar(CP_UTF8, 0, (const char*)data, -1, item->pszText, item->cchTextMax); + void* data; + 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 - if (n>=item->cchTextMax) { + if (n>=item->cchTextMax) item->pszText[item->cchTextMax-1] = L'\0'; - } } else if (typ == uiTableModelColumnInt) { 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); - 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 if (n>=item->cchTextMax) { 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; } +uiTable *uiNewTable(uiTableModel *model) +{ + uiTable *t; + int n; + + uiWindowsNewControl(uiTable, t); + new(&t->columns) std::vector(); // (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; +} + From ba13227bed454ac8f76455feb4a6d409fd497b95 Mon Sep 17 00:00:00 2001 From: Ben Campbell Date: Mon, 28 May 2018 20:26:07 +1200 Subject: [PATCH 4/5] further style consistency tweaks --- windows/table.cpp | 43 +++++++++++++++---------------------------- 1 file changed, 15 insertions(+), 28 deletions(-) diff --git a/windows/table.cpp b/windows/table.cpp index 2f7737eec..ad05c62c4 100644 --- a/windows/table.cpp +++ b/windows/table.cpp @@ -1,9 +1,5 @@ #include "uipriv_windows.hpp" -//static void uiTableMinimumSize(uiWindowsControl *c, int *width, int *height); - -struct uiTable; - struct uiTableModel { uiTableModelHandler *mh; std::vector tables; @@ -42,7 +38,6 @@ uiTableModel *uiNewTableModel(uiTableModelHandler *mh) return m; } - void uiFreeTableModel(uiTableModel *m) { delete m; @@ -55,27 +50,24 @@ void uiTableModelRowInserted(uiTableModel *m, int newIndex) ZeroMemory(&item, sizeof (LVITEMW)); item.mask = 0; item.iItem = newIndex; - item.iSubItem = 0; //? - for (auto t : m->tables) { + item.iSubItem = 0; + for (auto t : m->tables) 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) { - for (auto t : m->tables) { + for (auto t : m->tables) 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) { - for (auto t : m->tables) { + for (auto t : m->tables) if (SendMessageW(t->hwnd, LVM_DELETEITEM, (WPARAM) oldIndex, 0) == (LRESULT) (-1)) logLastError(L"error calling LVM_DELETEITEM in uiTableModelRowDeleted()"); - } } void uiTableColumnAppendTextPart(uiTableColumn *c, int modelColumn, int expand) @@ -84,19 +76,16 @@ void uiTableColumnAppendTextPart(uiTableColumn *c, int modelColumn, int expand) int lvIndex = 0; LVCOLUMNW lvc; - if (c->modelColumn >=0) { + if (c->modelColumn >= 0) return; // multiple parts not implemented - } c->modelColumn = modelColumn; // work out appropriate listview index for the column for (auto candidate : t->columns) { - if (candidate == c) { + if (candidate == c) break; - } - if (candidate->modelColumn >= 0) { + if (candidate->modelColumn >= 0) lvIndex++; - } } ZeroMemory(&lvc, sizeof (LVCOLUMNW)); @@ -130,7 +119,7 @@ void uiTableColumnAppendProgressBarPart(uiTableColumn *c, int modelColumn, int e void uiTableColumnPartSetEditable(uiTableColumn *c, int part, int editable) { - // TODO + // not implemented } void uiTableColumnPartSetTextColor(uiTableColumn *c, int part, int modelColumn) @@ -187,7 +176,8 @@ static void uiTableDestroy(uiControl *c) // 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: +// stupidly long URLs). So for now, just hardcode a minimum. +// TODO: Investigate using LVM_GETHEADER/HDM_LAYOUT here... #define tableMinWidth 107 /* in line with other controls */ #define tableMinHeight (14*3) /* header + 2 lines (roughly) */ @@ -205,7 +195,6 @@ static void uiTableMinimumSize(uiWindowsControl *c, int *width, int *height) *height = y; } - static BOOL onWM_NOTIFY(uiControl *c, HWND hwnd, NMHDR *nmhdr, LRESULT *lResult) { uiTable *t = uiTable(c); @@ -228,7 +217,7 @@ static BOOL onWM_NOTIFY(uiControl *c, HWND hwnd, NMHDR *nmhdr, LRESULT *lResult) break; row = item->iItem; col = item->iSubItem; - if (col<0 || col>=(int)t->columns.size()) + if (col < 0 || col >= (int)t->columns.size()) break; tc = (uiTableColumn *)t->columns[col]; mcol = tc->modelColumn; @@ -241,7 +230,7 @@ static BOOL onWM_NOTIFY(uiControl *c, HWND hwnd, NMHDR *nmhdr, LRESULT *lResult) 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 - if (n>=item->cchTextMax) + if (n >= item->cchTextMax) item->pszText[item->cchTextMax-1] = L'\0'; } else if (typ == uiTableModelColumnInt) { char buf[32]; @@ -252,12 +241,10 @@ static BOOL onWM_NOTIFY(uiControl *c, HWND hwnd, NMHDR *nmhdr, LRESULT *lResult) sprintf(buf, "%d", (int)data); n = MultiByteToWideChar(CP_UTF8, 0, buf, -1, item->pszText, item->cchTextMax); // make sure clipped strings are nul-terminated - if (n>=item->cchTextMax) { + if (n >= item->cchTextMax) item->pszText[item->cchTextMax-1] = L'\0'; - } - } else { + } else item->pszText[0] = L'\0'; - } break; } default: @@ -283,10 +270,10 @@ uiTable *uiNewTable(uiTableModel *model) model->tables.push_back(t); uiWindowsRegisterWM_NOTIFYHandler(t->hwnd, onWM_NOTIFY, uiControl(t)); + // TODO: try LVS_EX_AUTOSIZECOLUMNS 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()"); From b3b21196a157f91dd2b1cd569f8586fbeadfa64b Mon Sep 17 00:00:00 2001 From: Ben Campbell Date: Tue, 29 May 2018 18:17:10 +1200 Subject: [PATCH 5/5] minor windows table tweaks --- windows/table.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/windows/table.cpp b/windows/table.cpp index ad05c62c4..120bc8308 100644 --- a/windows/table.cpp +++ b/windows/table.cpp @@ -119,7 +119,7 @@ void uiTableColumnAppendProgressBarPart(uiTableColumn *c, int modelColumn, int e void uiTableColumnPartSetEditable(uiTableColumn *c, int part, int editable) { - // not implemented + // TODO } void uiTableColumnPartSetTextColor(uiTableColumn *c, int part, int modelColumn) @@ -247,8 +247,6 @@ static BOOL onWM_NOTIFY(uiControl *c, HWND hwnd, NMHDR *nmhdr, LRESULT *lResult) item->pszText[0] = L'\0'; break; } - default: - break; } *lResult = 0; return ret;