| 435 | } |
| 436 | |
| 437 | uint32_t DoDrawString(const Surface &out, string_view text, Rectangle rect, Point &characterPosition, |
| 438 | int lineWidth, int charactersInLine, int rightMargin, int bottomMargin, GameFontTables size, text_color color, bool outline, |
| 439 | TextRenderOptions &opts) |
| 440 | { |
| 441 | CurrentFont currentFont; |
| 442 | int curSpacing = opts.spacing; |
| 443 | if (HasAnyOf(opts.flags, UiFlags::KerningFitSpacing)) { |
| 444 | curSpacing = AdjustSpacingToFitHorizontally(lineWidth, opts.spacing, charactersInLine, rect.size.width); |
| 445 | if (curSpacing != opts.spacing && HasAnyOf(opts.flags, UiFlags::AlignCenter | UiFlags::AlignRight)) { |
| 446 | const int adjustedLineWidth = GetLineWidth(text, size, curSpacing, &charactersInLine); |
| 447 | characterPosition.x = GetLineStartX(opts.flags, rect, adjustedLineWidth); |
| 448 | } |
| 449 | } |
| 450 | |
| 451 | char32_t next; |
| 452 | string_view remaining = text; |
| 453 | size_t cpLen; |
| 454 | |
| 455 | const auto maybeDrawCursor = [&]() { |
| 456 | if (opts.cursorPosition == static_cast<int>(text.size() - remaining.size())) { |
| 457 | Point position = characterPosition; |
| 458 | MaybeWrap(position, 2, rightMargin, position.x, opts.lineHeight); |
| 459 | if (GetAnimationFrame(2, 500) != 0) { |
| 460 | FontStack baseFont = LoadFont(size, color, 0); |
| 461 | if (baseFont.has_value()) { |
| 462 | DrawFont(out, position, baseFont.glyph('|'), color, outline); |
| 463 | } |
| 464 | } |
| 465 | if (opts.renderedCursorPositionOut != nullptr) { |
| 466 | *opts.renderedCursorPositionOut = position; |
| 467 | } |
| 468 | } |
| 469 | }; |
| 470 | |
| 471 | for (; !remaining.empty() && remaining[0] != '\0' |
| 472 | && (next = DecodeFirstUtf8CodePoint(remaining, &cpLen)) != Utf8DecodeError; |
| 473 | remaining.remove_prefix(cpLen)) { |
| 474 | if (next == ZWSP) |
| 475 | continue; |
| 476 | |
| 477 | if (!currentFont.load(size, color, next)) { |
| 478 | next = U'?'; |
| 479 | if (!currentFont.load(size, color, next)) { |
| 480 | app_fatal("Missing fonts"); |
| 481 | } |
| 482 | } |
| 483 | |
| 484 | const uint8_t frame = next & 0xFF; |
| 485 | const uint16_t width = currentFont.glyph(frame).width(); |
| 486 | if (next == U'\n' || characterPosition.x + width > rightMargin) { |
| 487 | if (next == '\n') |
| 488 | maybeDrawCursor(); |
| 489 | const int nextLineY = characterPosition.y + opts.lineHeight; |
| 490 | if (nextLineY >= bottomMargin) |
| 491 | break; |
| 492 | characterPosition.y = nextLineY; |
| 493 | |
| 494 | if (HasAnyOf(opts.flags, UiFlags::KerningFitSpacing)) { |
no test coverage detected