summaryrefslogtreecommitdiff
path: root/redo/table_windows.c
blob: 6f0faae56cba889998e6f15067dcf893189b1920 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
// 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, WPARAM wParam, LPARAM lParam, void (*handler)(void *, int, int), void *data)
{
	LVHITTESTINFO ht;

	// TODO use wParam
	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);
}

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;

	switch (uMsg) {
	case msgNOTIFY:
		switch (nmhdr->code) {
		case LVN_GETDISPINFO:
			tableGetCell((void *) data, &(fill->item));
			return 0;
		}
		return (*fv_DefSubclassProc)(hwnd, uMsg, wParam, lParam);
	case WM_MOUSEMOVE:
		handle(hwnd, wParam, lParam, tableSetHot, (void *) data);
		// 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, wParam, lParam, tablePushed, (void *) data);
		// and let the list view do its thing
		return (*fv_DefSubclassProc)(hwnd, uMsg, wParam, lParam);
	case WM_LBUTTONUP:
		handle(hwnd, wParam, lParam, tableToggled, (void *) data);
		// and let the list view do its thing
		return (*fv_DefSubclassProc)(hwnd, uMsg, wParam, lParam);
	case WM_MOUSELEAVE:
		// TODO doesn't work
		tablePushed((void *) data, -1, -1);			// in case button held as drag out
		// and let the list view do its thing
		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((void *) data);
		return (*fv_DefSubclassProc)(hwnd, uMsg, wParam, lParam);
	case WM_NCDESTROY:
		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)
{
	if ((*fv_SetWindowSubclass)(hwnd, tableSubProc, 0, (DWORD_PTR) data) == 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());
}

void tableSetCheckboxImageList(HWND hwnd)
{
	if (SendMessageW(hwnd, LVM_SETIMAGELIST, LVSIL_STATE, (LPARAM) checkboxImageList) == (LRESULT) NULL)
;//TODO		xpanic("error setting image list", GetLastError());
	// TODO free old one here if any/different
	// 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());
}

// 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());
}