summaryrefslogtreecommitdiff
path: root/wintable/new/coord.h
blob: be0dbd7c58fe7068c191803ead63ad30924c44fa (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
// 4 december 2014

// TODO find a better place for this
static LONG rowHeight(struct table *t, HDC dc, BOOL select)
{
	BOOL release;
	HFONT prevfont, newfont;
	TEXTMETRICW tm;

	release = FALSE;
	if (dc == NULL) {
		dc = GetDC(t->hwnd);
		if (dc == NULL)
			panic("error getting Table DC for rowHeight()");
		release = TRUE;
	}
	if (select)
		prevfont = selectFont(t, dc, &newfont);
	if (GetTextMetricsW(dc, &tm) == 0)
		panic("error getting text metrics for rowHeight()");
	if (select)
		deselectFont(dc, prevfont, newfont);
	if (release)
		if (ReleaseDC(t->hwnd, dc) == 0)
			panic("error releasing Table DC for rowHeight()");
	return tm.tmHeight;
}

#define rowht(t) rowHeight(t, NULL, TRUE)

struct rowcol {
	intptr_t row;
	intptr_t column;
};

static struct rowcol clientCoordToRowColumn(struct table *t, POINT pt)
{
	RECT r;
	struct rowcol rc;
	intptr_t i;

	if (GetClientRect(t->hwnd, &r) == 0)
		panic("error getting Table client rect in clientCoordToRowColumn()");
	r.top += t->headerHeight;
	if (PtInRect(&r, pt) == 0)
		goto outside;

	// the row is easy
	pt.y -= t->headerHeight;
	rc.row = (pt.y / rowht(t)) + t->vscrollpos;
	if (rc.row >= t->count)
		goto outside;

	// the column... not so much
	// we scroll p.x, then subtract column widths until we cross the left edge of the control
	pt.x += t->hscrollpos;
	rc.column = 0;
	for (i = 0; i < t->nColumns; i++) {
		pt.x -= columnWidth(t, i);
		// use <, not <=, here:
		// assume r.left and t->hscrollpos == 0;
		// given the first column is 100 wide,
		// pt.x == 0 (first pixel of col 0) -> p.x - 100 == -100 < 0 -> break
		// pt.x == 99 (last pixel of col 0) -> p.x - 100 == -1 < 0 -> break
		// pt.x == 100 (first pixel of col 1) -> p.x - 100 == 0 >= 0 -> next column
		if (pt.x < r.left)
			break;
		rc.column++;
	}
	if (rc.column >= t->nColumns)
		goto outside;

	return rc;

outside:
	rc.row = -1;
	rc.column = -1;
	return rc;
}

// same as client coordinates, but stored in a lParam (like the various mouse messages provide)
static struct rowcol lParamToRowColumn(struct table *t, LPARAM lParam)
{
	POINT pt;

	pt.x = GET_X_LPARAM(lParam);
	pt.y = GET_Y_LPARAM(lParam);
	return clientCoordToRowColumn(t, pt);
}

// returns TRUE if the row is visible (even partially visible) and thus has a rectangle in the client area; FALSE otherwise
static BOOL rowColumnToClientRect(struct table *t, struct rowcol rc, RECT *r)
{
	RECT client;
	RECT out;			// don't change r if we return FALSE
	LONG height;
	intptr_t xpos;
	intptr_t i;

	if (rc.row < t->vscrollpos)
		return FALSE;
	rc.row -= t->vscrollpos;		// align with client.top

	if (GetClientRect(t->hwnd, &client) == 0)
		panic("error getting Table client rect in rowColumnToClientRect()");
	client.top += t->headerHeight;

	height = rowht(t);
	out.top = client.top + (rc.row * height);
	if (out.top >= client.bottom)		// >= because RECT.bottom is the first pixel outside the rectangle
		return FALSE;
	out.bottom = out.top + height;

	// and again the columns are the hard part
	// so we start with client.left - t->hscrollpos, then keep adding widths until we get to the column we want
	xpos = client.left - t->hscrollpos;
	for (i = 0; i < rc.column; i++)
		xpos += columnWidth(t, i);
	// did we stray too far to the right? if so it's not visible
	if (xpos >= client.right)		// >= because RECT.right is the first pixel outside the rectangle
		return FALSE;
	out.left = xpos;
	out.right = xpos + columnWidth(t, rc.column);
	// and is this too far to the left?
	if (out.right < client.left)		// < because RECT.left is the first pixel inside the rect
		return FALSE;

	*r = out;
	return TRUE;
}

// TODO idealCoordToRowColumn/rowColumnToIdealCoord?