@@ -32,6 +32,93 @@ namespace
3232 });
3333 return maxWidthStringSize;
3434 }
35+
36+
37+ // Returns a vector of pairs <indexes where the wraps should occur> and <if a truncation occurred>.
38+ // Wraps occur at the last available space before the text width is exceeded.
39+ std::vector<std::pair<size_t , bool >> wrapIndexesBreakOnSpace (const std::string& text, const NAS2D ::Font& font, int textWidth)
40+ {
41+ std::vector<std::pair<size_t , bool >> wrapIndexes;
42+ size_t wrapIndexOffset = 0 ;
43+ size_t lastSpaceIndex = 0 ;
44+ const int truncationSize = font.size (" ..." ).x ;
45+
46+ for (size_t index = 0 ; index < text.size (); ++index)
47+ {
48+ if (text[index] == ' \n ' )
49+ {
50+ wrapIndexOffset = index + 1 ;
51+ }
52+
53+ if (text[index] == ' ' )
54+ {
55+ lastSpaceIndex = index;
56+ }
57+
58+ if (font.size (text.substr (wrapIndexOffset, index - wrapIndexOffset + 1 )).x + truncationSize > textWidth && lastSpaceIndex <= wrapIndexOffset)
59+ {
60+ wrapIndexes.push_back ({index - 1 , true });
61+
62+ // Fast forward the index to the next space
63+ while (index < text.size () && text[index] != ' ' )
64+ {
65+ ++index;
66+ }
67+
68+ if (index < text.size ())
69+ {
70+ wrapIndexOffset = index + 1 ;
71+ lastSpaceIndex = index;
72+ }
73+ }
74+
75+ if (font.size (text.substr (wrapIndexOffset, index - wrapIndexOffset + 1 )).x > textWidth && lastSpaceIndex > wrapIndexOffset)
76+ {
77+ // Rewind index to the last space
78+ index = lastSpaceIndex;
79+ wrapIndexOffset = index + 1 ;
80+ wrapIndexes.push_back ({lastSpaceIndex, false });
81+ }
82+ }
83+
84+ return wrapIndexes;
85+ };
86+
87+
88+ // Returns a constructed string with line breaks at the last available space before the text width is exceeded.
89+ // Lines truncated will attempt to fit and end in "..." but may spill beyond the designated width
90+ std::string wrapTextBreakOnSpace (const std::string& text, const NAS2D ::Font& font, int textWidth)
91+ {
92+ auto wrapIndexes = wrapIndexesBreakOnSpace (text, font, textWidth);
93+ std::string wrappedText;
94+ size_t wrapIndexOffset = 0 ;
95+ for (const auto & [wrapIndex, truncated] : wrapIndexes)
96+ {
97+ wrappedText += text.substr (wrapIndexOffset, wrapIndex - wrapIndexOffset);
98+ if (truncated)
99+ {
100+ wrappedText += " ..." ;
101+ wrapIndexOffset = wrapIndex;
102+ while (wrapIndexOffset < text.size () && text[wrapIndexOffset] != ' ' )
103+ {
104+ ++wrapIndexOffset;
105+ }
106+
107+ if (wrapIndexOffset < text.size ())
108+ {
109+ wrappedText += ' \n ' ;
110+ wrapIndexOffset++;
111+ }
112+ }
113+ else
114+ {
115+ wrappedText += ' \n ' ;
116+ wrapIndexOffset = wrapIndex + 1 ;
117+ }
118+ }
119+ wrappedText += text.substr (wrapIndexOffset);
120+ return wrappedText;
121+ };
35122}
36123
37124
@@ -133,8 +220,8 @@ void ToolTip::draw() const
133220 auto linePosition = position () + PaddingSize;
134221
135222 forEachLine (mFocusedControl ->second , [this , &renderer, &linePosition](const std::string& lineStr) {
136- renderer.drawText (mFont , lineStr, linePosition);
137- linePosition.y += mFont .height ();
223+ renderer.drawText (mFont , lineStr, linePosition);
224+ linePosition.y += mFont .height ();
138225 });
139226 }
140227}
0 commit comments