Work around text extent differences resulting in clipped text

Under at least some versions of Windows 10 with wxDVC themed text can be
clipped horizontally because of discrepancies between the text extent
as drawn by DrawThemeTextEx() and calculated with GetTextExtent()
earlier.

Work around the issue by always trying to use GetThemeTextExtent() in
DrawItemText(), not just for alignment of multi-line strings, and adjust
for any width differences similar to the existing adjustment for height.

See #18487.
This commit is contained in:
Dimitri Schoolwerth 2021-07-26 21:39:07 +02:00
parent ebf1141db2
commit 90ba137f20

View File

@ -1104,13 +1104,16 @@ void wxRendererXP::DrawItemText(wxWindow* win,
such alignment use DT_TOP (0), which does work for multi-lines,
and deal with the actual desired vertical alignment ourselves with
the help of GetThemeTextExtent().
*/
bool useTopDrawing =
s_GetThemeTextExtent
&& ( align & (wxALIGN_BOTTOM | wxALIGN_CENTRE_VERTICAL) ) != 0
&& text.Contains(wxS('\n'));
if ( useTopDrawing )
[TODO] Ideally text measurement should only be needed for the above
mentioned situations but because there can be a difference between
the extent from GetThemeTextExtent() and the rect received by this
function could have involved other text measurements (e.g. with wxDVC,
see #18487), use it in all cases for now.
*/
bool useTopDrawing = false;
if ( s_GetThemeTextExtent != NULL )
{
/*
Get the actual text extent using GetThemeTextExtent() and adjust
@ -1151,6 +1154,30 @@ void wxRendererXP::DrawItemText(wxWindow* win,
defTextFlags, NULL, &rcExtent);
if ( SUCCEEDED(hr) )
{
/*
Compensate for rare cases where the horizontal extents differ
slightly. Don't use the width of the passed rect here to deal
with horizontal alignment as it results in the text always
fitting and ellipsization then can't occur. Instead check for
width differences by comparing with the extent as calculated
by wxDC.
*/
const int textWidthDc = dc.GetMultiLineTextExtent(text).x;
const int widthDiff = textWidthDc - rcExtent.right;
if ( widthDiff )
{
if ( align & wxALIGN_CENTRE_HORIZONTAL )
{
const int widthOffset = widthDiff / 2;
rc.left += widthOffset;
rc.right -= widthOffset;
}
else if ( align & wxALIGN_RIGHT )
rc.left += widthDiff;
else // left aligned
rc.right -= widthDiff;
}
/*
For height compare with the height of the passed rect and use
the difference for handling vertical alignment. This has
@ -1163,8 +1190,12 @@ void wxRendererXP::DrawItemText(wxWindow* win,
necessity) confines rendering to a cell's bounds.
*/
const int heightDiff = rect.GetHeight() - rcExtent.bottom;
if ( heightDiff )
if ( heightDiff
&& (align & (wxALIGN_BOTTOM | wxALIGN_CENTRE_VERTICAL))
&& text.Contains(wxS('\n')) )
{
useTopDrawing = true;
if ( align & wxALIGN_CENTRE_VERTICAL )
{
const int heightOffset = heightDiff / 2;
@ -1177,10 +1208,6 @@ void wxRendererXP::DrawItemText(wxWindow* win,
rc.bottom -= heightDiff;
}
}
else
{
useTopDrawing = false;
}
}
if ( !useTopDrawing )