andlabs-ui/wintable/new/coord.h

138 lines
3.9 KiB
C
Raw Normal View History

// 4 december 2014
2014-12-13 12:56:31 -06:00
// 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;
};
2014-12-13 11:17:18 -06:00
static struct rowcol clientCoordToRowColumn(struct table *t, POINT pt)
{
2014-12-13 11:17:18 -06:00
RECT r;
struct rowcol rc;
intptr_t i;
RECT colrect;
// initial values for the PtInRect() check
rc.row = -1;
rc.column = -1;
if (GetClientRect(t->hwnd, &r) == 0)
panic("error getting Table client rect in clientCoordToRowColumn()");
r.top += t->headerHeight;
2014-12-13 12:56:31 -06:00
if (PtInRect(&r, pt) == 0)
2014-12-13 11:17:18 -06:00
return rc;
// the row is easy
2014-12-13 12:56:31 -06:00
pt.y -= t->headerHeight;
rc.row = (pt.y / rowht(t)) + t->vscrollpos;
2014-12-13 11:17:18 -06:00
// the column... not so much
// we scroll p.x, then subtract column widths until we cross the left edge of the control
2014-12-13 12:56:31 -06:00
pt.x += t->hscrollpos;
2014-12-13 11:17:18 -06:00
rc.column = 0;
for (i = 0; i < t->nColumns; i++) {
// TODO error check
SendMessage(t->header, HDM_GETITEMRECT, (WPARAM) i, (LPARAM) (&colrect));
2014-12-13 12:56:31 -06:00
pt.x -= colrect.right - colrect.left;
2014-12-13 11:17:18 -06:00
// use <, not <=, here:
// assume r.left and t->hscrollpos == 0;
// given the first column is 100 wide,
2014-12-13 12:56:31 -06:00
// 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)
2014-12-13 11:17:18 -06:00
break;
rc.column++;
}
// TODO what happens if the break was never taken?
return rc;
}
// same as client coordinates, but stored in a lParam (like the various mouse messages provide)
2014-12-13 11:17:18 -06:00
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
RECT colrect;
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++) {
// TODO error check
SendMessage(t->header, HDM_GETITEMRECT, (WPARAM) i, (LPARAM) (&colrect));
xpos += colrect.right - colrect.left;
}
// 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;
// TODO error check
SendMessage(t->header, HDM_GETITEMRECT, (WPARAM) (rc.column), (LPARAM) (&colrect));
out.right = xpos + (colrect.right - colrect.left);
// 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?