* Wrap the text in buffer to width, returns width of longest line. * * Inserts NULL where line should break (as \n is used for something else), * so the number of lines is returned in num_lines. font_height seems to be * a control character for line height. * * rct2: 0x006C21E2 * buffer (esi) * width (edi) - in * num_lines (edi) - out * font_heigh
| 148 | * font_height (ebx) - out |
| 149 | */ |
| 150 | int32_t wrapString(u8string_view text, int32_t width, FontStyle fontStyle, u8string* outWrappedText, int32_t* outNumLines) |
| 151 | { |
| 152 | constexpr size_t kNullIndex = std::numeric_limits<size_t>::max(); |
| 153 | u8string buffer; |
| 154 | |
| 155 | size_t currentLineIndex = 0; |
| 156 | size_t splitIndex = kNullIndex; |
| 157 | size_t bestSplitIndex = kNullIndex; |
| 158 | size_t numLines = 0; |
| 159 | int32_t maxWidth = 0; |
| 160 | |
| 161 | FmtString fmt(text); |
| 162 | for (const auto& token : fmt) |
| 163 | { |
| 164 | if (token.IsLiteral()) |
| 165 | { |
| 166 | CodepointView codepoints(token.text); |
| 167 | for (auto codepoint : codepoints) |
| 168 | { |
| 169 | char cb[8]{}; |
| 170 | UTF8WriteCodepoint(cb, codepoint); |
| 171 | buffer.append(cb); |
| 172 | |
| 173 | auto lineWidth = getStringWidth(&buffer[currentLineIndex], fontStyle); |
| 174 | if (lineWidth <= width || (splitIndex == kNullIndex && bestSplitIndex == kNullIndex)) |
| 175 | { |
| 176 | if (codepoint == ' ') |
| 177 | { |
| 178 | // Mark line split here |
| 179 | splitIndex = buffer.size() - 1; |
| 180 | } |
| 181 | else if (splitIndex == kNullIndex) |
| 182 | { |
| 183 | // Mark line split here (this is after first character of line) |
| 184 | bestSplitIndex = buffer.size(); |
| 185 | } |
| 186 | } |
| 187 | else |
| 188 | { |
| 189 | // Insert new line before current word |
| 190 | if (splitIndex == kNullIndex) |
| 191 | { |
| 192 | splitIndex = bestSplitIndex; |
| 193 | } |
| 194 | buffer.insert(buffer.begin() + splitIndex, '\0'); |
| 195 | |
| 196 | // Recalculate the line length after splitting |
| 197 | lineWidth = getStringWidth(&buffer[currentLineIndex], fontStyle); |
| 198 | maxWidth = std::max(maxWidth, lineWidth); |
| 199 | numLines++; |
| 200 | |
| 201 | currentLineIndex = splitIndex + 1; |
| 202 | splitIndex = kNullIndex; |
| 203 | bestSplitIndex = kNullIndex; |
| 204 | |
| 205 | // Trim the beginning of the new line |
| 206 | while (buffer[currentLineIndex] == ' ') |
| 207 | { |
no test coverage detected