37.2.4 Example: Selecting a Line of Text

The example in this section is taken from a simple word processing application. It includes code that allows the user to set the position of the caret by clicking anywhere on a line of text, and to select (highlight) a line of text by double-clicking anywhere on the line.

LONG APIENTRY MainWndProc(hwndMain, uMsg, wParam, lParam)

HWND hwndMain;

UINT uMsg;

UINT wParam;

LONG lParam;

{

HDC hdc; /* handle of device context */

TEXTMETRIC tm; /* font size data */

int i, j; /* loop counters */

int cCR = 0; /* count of carriage returns */

char ch; /* character from input buffer */

static int nBegLine; /* beginning of selected line */

static int nCurrentLine = 0; /* currently selected line */

static int nLastLine = 0; /* last text line */

static int nCaretPosX = 0; /* x-coordinate of caret */

static int cch = 0; /* number of characters entered */

static int nCharWidth = 0; /* exact width of a character */

static char szHilite[128]; /* text string to hilite */

static DWORD dwCharX; /* average width of characters */

static DWORD dwLineHeight; /* line height */

static POINTS ptsCursor; /* coordinates of mouse cursor */

static COLORREF crPrevText; /* previous text color */

static COLORREF crPrevBk; /* previous background color */

static PTCHAR pchInputBuf; /* address of input buffer */

static BOOL fTextSelected = FALSE; /* text-selection flag */

switch (uMsg) {

case WM_CREATE:

/* Get metrics of current font. */

hdc = GetDC(hwndMain);

GetTextMetrics(hdc, &tm);

ReleaseDC(hwndMain, hdc);

/* Save the average character width and height. */

dwCharX = tm.tmAveCharWidth;

dwLineHeight = tm.tmHeight;

/* Allocate a buffer to store keyboard input. */

pchInputBuf = (LPSTR) GlobalAlloc(GPTR,

BUFSIZE * sizeof(TCHAR));

return 0;

.

. /* Process other messages. */

.

case WM_LBUTTONDOWN:

/*

* If a line of text is currently highlighted, redraw

* redraw the text to remove the highlighting.

*/

if (fTextSelected) {

hdc = GetDC(hwndMain);

SetTextColor(hdc, crPrevText);

SetBkColor(hdc, crPrevBk);

TextOut(hdc, 0, nCurrentLine * dwLineHeight,

szHilite, lstrlen(szHilite));

ReleaseDC(hwndMain, hdc);

ShowCaret(hwndMain);

fTextSelected = FALSE;

}

/* Save the current mouse-cursor coordinates. */

ptsCursor = MAKEPOINTS(lParam);

/*

* Determine which line the mouse cursor is on and save

* the line number. Don't allow line numers greater

* than the number of the last line of text. Later, the

* line number will be multiplied by the average height

* of the current font. The result will be used to set

* y-coordinate of the caret.

*/

for (i = 1; (i * dwLineHeight) <= ptsCursor.y; i++);

nCurrentLine = min(i - 1, nLastLine);

/*

* Parse the text input buffer to find the first

* character in the selected line of text. Each

* line ends with a carriage return, so it's possible

* to count the carriage returns to find the selected

* line.

*/

cCR = 0;

nBegLine = 0;

if (nCurrentLine != 0) {

for (i = 0; (i < cch) && (cCR < nCurrentLine); i++)

if (pchInputBuf[i] == 0x0D)

++cCR;

nBegLine = i;

}

/*

* Starting at the beginning of the selected line,

* measure the width of each character, summing the

* width with each character measured. Stop when the

* sum is greater than the x-coordinate of the mouse

* cursor. The sum will be used to set the x-coordinate

* of the caret.

*/

hdc = GetDC(hwndMain);

nCaretPosX = 0;

for (i = nBegLine;

(pchInputBuf[i] != 0x0D) && (i < cch); i++) {

ch = pchInputBuf[i];

GetCharWidth(hdc, (int) ch, (int) ch, &nCharWidth);

if ((nCaretPosX + nCharWidth) > ptsCursor.x)

break;

else

nCaretPosX += nCharWidth;

}

ReleaseDC(hwndMain, hdc);

/* Set the caret to the user-selected position. */

SetCaretPos(nCaretPosX, nCurrentLine * dwLineHeight);

break;

case WM_LBUTTONDBLCLK:

/* Copy the selected line of text to a buffer. */

for (i = nBegLine, j = 0; (pchInputBuf[i] != 0x0D) &&

(i < cch); i++)

szHilite[j++] = pchInputBuf[i];

szHilite[j] = '\0';

/*

* Hide the caret, invert the background an foreground

* colors, then redraw the selected line.

*/

HideCaret(hwndMain);

hdc = GetDC(hwndMain);

crPrevText = SetTextColor(hdc, RGB(255, 255, 255));

crPrevBk = SetBkColor(hdc, RGB(0,0,0));

TextOut(hdc, 0, nCurrentLine * dwLineHeight, szHilite,

lstrlen(szHilite));

SetTextColor(hdc, crPrevText);

SetBkColor(hdc, crPrevBk);

ReleaseDC(hwndMain, hdc);

fTextSelected = TRUE;

break;

.

. /* Process other messages. */

.

default:

return (DefWindowProc(hwndMain, uMsg, wParam, lParam));

}

return NULL;

}