summaryrefslogtreecommitdiff
path: root/table_windows.c
diff options
context:
space:
mode:
authorPietro Gagliardi <[email protected]>2014-08-30 23:02:02 -0400
committerPietro Gagliardi <[email protected]>2014-08-30 23:02:02 -0400
commit77bf566ebbcb62acd4d08d905d9542d6ff9b6b80 (patch)
treeeeb8e72bc3bf57f5be7f0c0af4319189ac6de838 /table_windows.c
parent155899c65ed32245e2ccad4197a10c77017d835b (diff)
...in with the new.
Diffstat (limited to 'table_windows.c')
-rw-r--r--table_windows.c195
1 files changed, 195 insertions, 0 deletions
diff --git a/table_windows.c b/table_windows.c
new file mode 100644
index 0000000..2c956f5
--- /dev/null
+++ b/table_windows.c
@@ -0,0 +1,195 @@
+// 28 july 2014
+
+#include "winapi_windows.h"
+#include "_cgo_export.h"
+
+// provided for cgo's benefit
+LPWSTR xWC_LISTVIEW = WC_LISTVIEW;
+
+static void handle(HWND hwnd, LPARAM lParam, void (*handler)(void *, int, int), void *data)
+{
+ LVHITTESTINFO ht;
+
+ ZeroMemory(&ht, sizeof (LVHITTESTINFO));
+ ht.pt.x = GET_X_LPARAM(lParam);
+ ht.pt.y = GET_Y_LPARAM(lParam);
+ if (SendMessageW(hwnd, LVM_SUBITEMHITTEST, 0, (LPARAM) (&ht)) == (LRESULT) -1) {
+ (*handler)(data, -1, -1);
+ return; // no item
+ }
+ if (ht.flags != LVHT_ONITEMSTATEICON) {
+ (*handler)(data, -1, -1);
+ return; // not on a checkbox
+ }
+ (*handler)(data, ht.iItem, ht.iSubItem);
+}
+
+struct tableData {
+ void *gotable;
+ HIMAGELIST imagelist;
+ HTHEME theme;
+ HIMAGELIST checkboxImageList;
+};
+
+static void tableLoadImageList(HWND hwnd, struct tableData *t, HIMAGELIST new)
+{
+ HIMAGELIST old;
+
+ old = t->imagelist;
+ t->imagelist = new;
+ applyImageList(hwnd, LVM_SETIMAGELIST, LVSIL_SMALL, t->imagelist, old);
+}
+
+static void tableSetCheckboxImageList(HWND hwnd, struct tableData *t)
+{
+ HIMAGELIST old;
+
+ old = t->checkboxImageList;
+ t->checkboxImageList = makeCheckboxImageList(hwnd, &t->theme);
+ applyImageList(hwnd, LVM_SETIMAGELIST, LVSIL_STATE, t->checkboxImageList, old);
+ // thanks to Jonathan Potter (http://stackoverflow.com/questions/25354448/why-do-my-owner-data-list-view-state-images-come-up-as-blank-on-windows-xp)
+ if (SendMessageW(hwnd, LVM_SETCALLBACKMASK, LVIS_STATEIMAGEMASK, 0) == FALSE)
+ xpanic("error marking state image list as application-managed", GetLastError());
+}
+
+static LRESULT CALLBACK tableSubProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR id, DWORD_PTR data)
+{
+ NMHDR *nmhdr = (NMHDR *) lParam;
+ NMLVDISPINFOW *fill = (NMLVDISPINFO *) lParam;
+ NMLISTVIEW *nlv = (NMLISTVIEW *) lParam;
+ struct tableData *t = (struct tableData *) data;
+
+ switch (uMsg) {
+ case msgNOTIFY:
+ switch (nmhdr->code) {
+ case LVN_GETDISPINFO:
+ tableGetCell(t->gotable, &(fill->item));
+ return 0;
+ case LVN_ITEMCHANGED:
+ if ((nlv->uChanged & LVIF_STATE) == 0)
+ break;
+ // if both old and new states have the same value for the selected bit, then the selection state did not change, regardless of selected or deselected
+ if ((nlv->uOldState & LVIS_SELECTED) == (nlv->uNewState & LVIS_SELECTED))
+ break;
+ tableSelectionChanged(t->gotable);
+ return 0;
+ }
+ return (*fv_DefSubclassProc)(hwnd, uMsg, wParam, lParam);
+ case WM_MOUSEMOVE:
+ handle(hwnd, lParam, tableSetHot, t->gotable);
+ // and let the list view do its thing
+ return (*fv_DefSubclassProc)(hwnd, uMsg, wParam, lParam);
+ case WM_LBUTTONDOWN:
+ case WM_LBUTTONDBLCLK: // listviews have CS_DBLCICKS; check this to better mimic the behavior of a real checkbox
+ handle(hwnd, lParam, tablePushed, t->gotable);
+ // and let the list view do its thing
+ return (*fv_DefSubclassProc)(hwnd, uMsg, wParam, lParam);
+ case WM_LBUTTONUP:
+ handle(hwnd, lParam, tableToggled, t->gotable);
+ // and let the list view do its thing
+ return (*fv_DefSubclassProc)(hwnd, uMsg, wParam, lParam);
+ case msgLoadImageList:
+ tableLoadImageList(hwnd, t, (HIMAGELIST) lParam);
+ return 0;
+ case msgTableMakeInitialCheckboxImageList:
+ tableSetCheckboxImageList(hwnd, t);
+ return 0;
+ case WM_THEMECHANGED:
+ tableSetCheckboxImageList(hwnd, t);
+ return (*fv_DefSubclassProc)(hwnd, uMsg, wParam, lParam);
+ // see table.autoresize() in table_windows.go for the column autosize policy
+ case WM_NOTIFY: // from the contained header control
+ if (nmhdr->code == HDN_BEGINTRACK)
+ tableStopColumnAutosize(t->gotable);
+ return (*fv_DefSubclassProc)(hwnd, uMsg, wParam, lParam);
+ case WM_NCDESTROY:
+ free(t);
+ if ((*fv_RemoveWindowSubclass)(hwnd, tableSubProc, id) == FALSE)
+ xpanic("error removing Table subclass (which was for its own event handler)", GetLastError());
+ return (*fv_DefSubclassProc)(hwnd, uMsg, wParam, lParam);
+ default:
+ return (*fv_DefSubclassProc)(hwnd, uMsg, wParam, lParam);
+ }
+ xmissedmsg("Button", "tableSubProc()", uMsg);
+ return 0; // unreached
+}
+
+void setTableSubclass(HWND hwnd, void *data)
+{
+ struct tableData *t;
+
+ t = (struct tableData *) malloc(sizeof (struct tableData));
+ if (t == NULL)
+ xpanic("error allocating structure for Table extra data", GetLastError());
+ ZeroMemory(t, sizeof (struct tableData));
+ t->gotable = data;
+ if ((*fv_SetWindowSubclass)(hwnd, tableSubProc, 0, (DWORD_PTR) t) == FALSE)
+ xpanic("error subclassing Table to give it its own event handler", GetLastError());
+}
+
+void tableAppendColumn(HWND hwnd, int index, LPWSTR name)
+{
+ LVCOLUMNW col;
+
+ ZeroMemory(&col, sizeof (LVCOLUMNW));
+ col.mask = LVCF_FMT | LVCF_TEXT | LVCF_SUBITEM | LVCF_ORDER;
+ col.fmt = LVCFMT_LEFT;
+ col.pszText = name;
+ col.iSubItem = index;
+ col.iOrder = index;
+ if (SendMessageW(hwnd, LVM_INSERTCOLUMN, (WPARAM) index, (LPARAM) (&col)) == (LRESULT) -1)
+ xpanic("error adding column to Table", GetLastError());
+}
+
+void tableUpdate(HWND hwnd, int nItems)
+{
+ if (SendMessageW(hwnd, LVM_SETITEMCOUNT, (WPARAM) nItems, 0) == 0)
+ xpanic("error setting number of items in Table", GetLastError());
+}
+
+void tableAddExtendedStyles(HWND hwnd, LPARAM styles)
+{
+ // the bits of WPARAM specify which bits of LPARAM to look for; having WPARAM == LPARAM ensures that only the bits we want to add are affected
+ SendMessageW(hwnd, LVM_SETEXTENDEDLISTVIEWSTYLE, (WPARAM) styles, styles);
+}
+
+void tableAutosizeColumns(HWND hwnd, int nColumns)
+{
+ int i;
+
+ for (i = 0; i < nColumns; i++)
+ if (SendMessageW(hwnd, LVM_SETCOLUMNWIDTH, (WPARAM) i, (LPARAM) LVSCW_AUTOSIZE_USEHEADER) == FALSE)
+ xpanic("error resizing columns of results list view", GetLastError());
+}
+
+// because Go won't let me do C.WPARAM(-1)
+intptr_t tableSelectedItem(HWND hwnd)
+{
+ return (intptr_t) SendMessageW(hwnd, LVM_GETNEXTITEM, (WPARAM) -1, LVNI_SELECTED);
+}
+
+void tableSelectItem(HWND hwnd, intptr_t index)
+{
+ LVITEMW item;
+ LRESULT current;
+
+ // via http://support.microsoft.com/kb/131284
+ // we don't need to clear the other bits; Tables don't support cutting or drag/drop
+ current = SendMessageW(hwnd, LVM_GETNEXTITEM, (WPARAM) -1, LVNI_SELECTED);
+ if (current != (LRESULT) -1) {
+ ZeroMemory(&item, sizeof (LVITEMW));
+ item.mask = LVIF_STATE;
+ item.state = 0;
+ item.stateMask = LVIS_FOCUSED | LVIS_SELECTED;
+ if (SendMessageW(hwnd, LVM_SETITEMSTATE, (WPARAM) current, (LPARAM) (&item)) == FALSE)
+ xpanic("error deselecting current Table item", GetLastError());
+ }
+ if (index == -1) // select nothing
+ return;
+ ZeroMemory(&item, sizeof (LVITEMW));
+ item.mask = LVIF_STATE;
+ item.state = LVIS_FOCUSED | LVIS_SELECTED;
+ item.stateMask = LVIS_FOCUSED | LVIS_SELECTED;
+ if (SendMessageW(hwnd, LVM_SETITEMSTATE, (WPARAM) index, (LPARAM) (&item)) == FALSE)
+ xpanic("error selecting new Table item", GetLastError());
+}