55#include " highlightutils.h"
66
77#include < QPainter>
8- #include < QFontMetrics >
8+ #include < QFontMetricsF >
99#include < QRegularExpression>
1010#include < QPalette>
11+ #include < QFont>
1112#include < algorithm>
1213
1314namespace HighlightUtils {
1415
15- static int charWidth (const QFontMetrics &fm, QChar ch)
16+ static double charWidth (const QFontMetricsF &fm, QChar ch)
1617{
17- #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
18- return fm.width (ch);
19- #else
2018 return fm.horizontalAdvance (ch);
21- #endif
2219}
2320
24- static int textWidth (const QFontMetrics &fm, const QString &text)
21+ static double textWidth (const QFontMetricsF &fm, const QString &text)
2522{
26- #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
27- return fm.width (text);
28- #else
2923 return fm.horizontalAdvance (text);
30- #endif
3124}
3225
3326QVector<MatchRange> findMatchRanges (const QString &text, const QStringList &keywords)
@@ -58,16 +51,16 @@ QVector<MatchRange> findMatchRanges(const QString &text, const QStringList &keyw
5851}
5952
6053static ElideResult buildWindowElide (const QString &text, int keepStart, int keepEnd,
61- int maxWidth, const QFontMetrics &fm)
54+ int maxWidth, const QFontMetricsF &fm)
6255{
6356 ElideResult result;
6457 const QString ellipsis = QStringLiteral (" …" );
65- int ellipsisWidth = charWidth (fm, QChar (0x2026 ));
58+ double ellipsisWidth = charWidth (fm, QChar (0x2026 ));
6659
6760 bool needLeft = (keepStart > 0 );
6861 bool needRight = (keepEnd < text.length ());
6962 int numEllipsis = (needLeft ? 1 : 0 ) + (needRight ? 1 : 0 );
70- int budget = maxWidth - numEllipsis * ellipsisWidth;
63+ double budget = maxWidth - numEllipsis * ellipsisWidth;
7164 if (budget <= 0 ) {
7265 result.text = ellipsis;
7366 result.origPositions = { -1 };
@@ -76,10 +69,10 @@ static ElideResult buildWindowElide(const QString &text, int keepStart, int keep
7669
7770 int keepLen = keepEnd - keepStart;
7871 int trimLeft = 0 , trimRight = 0 ;
79- int w = textWidth (fm, text.mid (keepStart, keepLen));
72+ double w = textWidth (fm, text.mid (keepStart, keepLen));
8073 while (w > budget && keepLen > 0 ) {
81- int lNext = charWidth (fm, text[keepStart + trimLeft]);
82- int rNext = charWidth (fm, text[keepEnd - 1 - trimRight]);
74+ double lNext = charWidth (fm, text[keepStart + trimLeft]);
75+ double rNext = charWidth (fm, text[keepEnd - 1 - trimRight]);
8376 if (trimRight >= keepLen - trimLeft - 1 ) {
8477 w -= lNext;
8578 ++trimLeft;
@@ -116,11 +109,11 @@ static ElideResult buildWindowElide(const QString &text, int keepStart, int keep
116109}
117110
118111ElideResult smartElideWithTracking (const QString &text, int maxWidth,
119- const QFontMetrics &fm,
112+ const QFontMetricsF &fm,
120113 const QVector<MatchRange> &matchRanges)
121114{
122115 const QString ellipsis = QStringLiteral (" …" );
123- int ellipsisWidth = charWidth (fm, QChar (0x2026 ));
116+ double ellipsisWidth = charWidth (fm, QChar (0x2026 ));
124117
125118 if (textWidth (fm, text) <= maxWidth) {
126119 ElideResult result;
@@ -152,9 +145,9 @@ ElideResult smartElideWithTracking(const QString &text, int maxWidth,
152145 bool needLeft = (keepStart > 0 );
153146 bool needRight = (keepEnd < text.length ());
154147 int numEllipsis = (needLeft ? 1 : 0 ) + (needRight ? 1 : 0 );
155- int budget = maxWidth - numEllipsis * ellipsisWidth;
148+ double budget = maxWidth - numEllipsis * ellipsisWidth;
156149
157- int keptWidth = textWidth (fm, text.mid (keepStart, keepEnd - keepStart));
150+ double keptWidth = textWidth (fm, text.mid (keepStart, keepEnd - keepStart));
158151 if (keptWidth > budget)
159152 break ;
160153
@@ -163,20 +156,20 @@ ElideResult smartElideWithTracking(const QString &text, int maxWidth,
163156
164157 bool expanded = false ;
165158 if (keepStart > 0 ) {
166- int cw = charWidth (fm, text[keepStart - 1 ]);
159+ double cw = charWidth (fm, text[keepStart - 1 ]);
167160 int newNeedLeft = (keepStart - 1 > 0 );
168161 int newNumEllipsis = (newNeedLeft ? 1 : 0 ) + (needRight ? 1 : 0 );
169- int newBudget = maxWidth - newNumEllipsis * ellipsisWidth;
162+ double newBudget = maxWidth - newNumEllipsis * ellipsisWidth;
170163 if (keptWidth + cw <= newBudget) {
171164 --keepStart;
172165 expanded = true ;
173166 }
174167 }
175168 if (!expanded && keepEnd < text.length ()) {
176- int cw = charWidth (fm, text[keepEnd]);
169+ double cw = charWidth (fm, text[keepEnd]);
177170 int newNeedRight = (keepEnd + 1 < text.length ());
178171 int newNumEllipsis = (needLeft ? 1 : 0 ) + (newNeedRight ? 1 : 0 );
179- int newBudget = maxWidth - newNumEllipsis * ellipsisWidth;
172+ double newBudget = maxWidth - newNumEllipsis * ellipsisWidth;
180173 if (keptWidth + cw <= newBudget) {
181174 ++keepEnd;
182175 expanded = true ;
@@ -190,14 +183,14 @@ ElideResult smartElideWithTracking(const QString &text, int maxWidth,
190183}
191184
192185ElideResult elideWithTracking (const QString &text, Qt::TextElideMode mode,
193- int maxWidth, const QFontMetrics &fm)
186+ int maxWidth, const QFontMetricsF &fm)
194187{
195188 ElideResult result;
196189 if (text.isEmpty ())
197190 return result;
198191
199192 const QString ellipsis = QStringLiteral (" …" );
200- int ellipsisWidth = charWidth (fm, QChar (0x2026 ));
193+ double ellipsisWidth = charWidth (fm, QChar (0x2026 ));
201194
202195 if (textWidth (fm, text) <= maxWidth) {
203196 result.text = text;
@@ -213,14 +206,14 @@ ElideResult elideWithTracking(const QString &text, Qt::TextElideMode mode,
213206 return result;
214207 }
215208
216- int availWidth = maxWidth - ellipsisWidth;
209+ double availWidth = maxWidth - ellipsisWidth;
217210
218211 switch (mode) {
219212 case Qt::ElideRight: {
220- int w = 0 ;
213+ double w = 0 ;
221214 int keep = 0 ;
222215 for (int i = 0 ; i < text.length (); ++i) {
223- int cw = charWidth (fm, text[i]);
216+ double cw = charWidth (fm, text[i]);
224217 if (w + cw > availWidth)
225218 break ;
226219 w += cw;
@@ -241,7 +234,7 @@ ElideResult elideWithTracking(const QString &text, Qt::TextElideMode mode,
241234 int tail = tryChars - head;
242235 if (head < 0 || tail < 0 || head + tail > total)
243236 continue ;
244- int w = textWidth (fm, text.left (head)) + textWidth (fm, text.right (tail));
237+ double w = textWidth (fm, text.left (head)) + textWidth (fm, text.right (tail));
245238 if (w <= availWidth) {
246239 bestKeep = tryChars;
247240 break ;
@@ -264,10 +257,10 @@ ElideResult elideWithTracking(const QString &text, Qt::TextElideMode mode,
264257 break ;
265258 }
266259 case Qt::ElideLeft: {
267- int w = 0 ;
260+ double w = 0 ;
268261 int keep = 0 ;
269262 for (int i = text.length () - 1 ; i >= 0 ; --i) {
270- int cw = charWidth (fm, text[i]);
263+ double cw = charWidth (fm, text[i]);
271264 if (w + cw > availWidth)
272265 break ;
273266 w += cw;
@@ -293,11 +286,11 @@ ElideResult elideWithTracking(const QString &text, Qt::TextElideMode mode,
293286}
294287
295288QVector<QTextLayout::FormatRange> buildFormatRanges (
296- const QString &displayText,
297- const QVector<int > &origPosMapping,
298- const QString &originalText,
299- const QStringList &keywords,
300- const QTextCharFormat &format)
289+ const QString &displayText,
290+ const QVector<int > &origPosMapping,
291+ const QString &originalText,
292+ const QStringList &keywords,
293+ const QTextCharFormat &format)
301294{
302295 QVector<QTextLayout::FormatRange> ranges;
303296
@@ -373,72 +366,4 @@ QTextCharFormat defaultHighlightFormat(const QFont &baseFont, const QPalette &pa
373366 return fmt;
374367}
375368
376- void drawHighlightedText (QPainter *painter, const QString &text,
377- const QStringList &keywords,
378- const QFont &font, const QColor &textColor,
379- const QColor &highlightColor,
380- const QRect &rect, Qt::Alignment alignment)
381- {
382- if (text.isEmpty ())
383- return ;
384-
385- QFontMetrics fm (font);
386- int maxWidth = rect.width ();
387-
388- // Elide
389- QVector<MatchRange> matchRanges = findMatchRanges (text, keywords);
390- ElideResult elideResult;
391-
392- if (!matchRanges.isEmpty ()) {
393- elideResult = smartElideWithTracking (text, maxWidth, fm, matchRanges);
394- }
395- if (elideResult.text .isEmpty ()) {
396- elideResult = elideWithTracking (text, Qt::ElideRight, maxWidth, fm);
397- }
398-
399- const QString &displayText = elideResult.text ;
400- const QVector<int > &origPosMapping = elideResult.origPositions ;
401-
402- // Build format ranges for keywords
403- QVector<QTextLayout::FormatRange> formats;
404- if (!keywords.isEmpty ()) {
405- QTextCharFormat fmt;
406- fmt.setFont (font);
407- fmt.setFontWeight (QFont::DemiBold);
408- fmt.setForeground (highlightColor);
409-
410- // Create a temporary palette with our desired highlight color
411- QPalette tempPalette;
412- tempPalette.setColor (QPalette::BrightText, highlightColor);
413-
414- formats = buildFormatRanges (displayText, origPosMapping, text, keywords, fmt);
415- }
416-
417- // Setup QTextLayout
418- QTextLayout layout;
419- layout.setText (displayText);
420- layout.setFont (font);
421- layout.setFormats (formats);
422-
423- layout.beginLayout ();
424- QTextLine line = layout.createLine ();
425- if (line.isValid ())
426- line.setLineWidth (maxWidth);
427- layout.endLayout ();
428-
429- // Vertical alignment
430- int textHeight = fm.height ();
431- int y = rect.y ();
432- if (alignment & Qt::AlignVCenter)
433- y += (rect.height () - textHeight) / 2 ;
434- else if (alignment & Qt::AlignBottom)
435- y += rect.height () - textHeight;
436-
437- painter->save ();
438- painter->setPen (textColor);
439- painter->translate (rect.x (), y);
440- layout.draw (painter, QPointF (0 , 0 ));
441- painter->restore ();
442- }
443-
444369} // namespace HighlightUtils
0 commit comments