Suppose I write a line of text in a variable-width font to a window with TextOut, and allow the user to click on any letter. Then how do I find out which part of the text he has clicked on? In other words, how do I convert the cursor-coordinates of his click to a string-offset?
I guess it could be done by calling GetTextExtentPoint32 on various string-truncations until I hit the right one, but surely there is a more efficient way. Microsoft's Notepad program knows exactly how many pixels to move when I right-arrow across a line - but how?
This answer was compiled by trial and error after wading through Microsoft's cryptic documentation.
The MSDN C library provides the following functions to display text:
If kerning is required (and on reflection I think that it is desirable) then it is a choice between ExtTextOut and DrawText.
DrawText provides a solution along the lines suggested by Groo. It requires a box to be drawn around the text-area, as in:
When the fontsize is set or changed, then a character-width lookup-table "CharW" must be built:
When the font is changed, the kerning-table must be built:
To play safe, the kerning table "Kern" should be sorted by (wFirst, wSecond), but it appears to be clustered by wFirst and therefore my code works without a qsort.
We can therefore calculate the pixel-width of any substring as follows:
This has been tested and agrees with the x-coordinate returned by DrawText when the maintain-current-coordinates flag is set:
It is therefore straightfoward to find the substring-length that matches a given pixel-width.
However, a simpler solution is provided by ExtTextOut:
The MSDN function GetCharacterPlacement() returns an array with the actual pixel-width for each character in the string s. It replaces my lookup-tables CharW, Kern, CharK above. According to Microsoft, it has been superseded by Uniscribe functions, though it still works fine for a European language like English.