diff --git a/implementations/Crafter.Graphics-TextElement.cpp b/implementations/Crafter.Graphics-TextElement.cpp index 11e81d3..556146d 100644 --- a/implementations/Crafter.Graphics-TextElement.cpp +++ b/implementations/Crafter.Graphics-TextElement.cpp @@ -34,7 +34,7 @@ TextElement::TextElement(std::int_fast32_t anchorX, std::int_fast32_t anchorY, s } -void TextElement::RenderText(const std::string_view text, float size, Pixel_BU8_GU8_RU8_AU8 color, Font& font, TextAlignment alignment, TextOverflowMode overflowMode) { +void TextElement::RenderText(const std::string_view text, float size, Pixel_BU8_GU8_RU8_AU8 color, Font& font, TextAlignment alignment, VerticalTextAlignment verticalAlignment, TextOverflowMode overflowMode) { // Calculate the actual size needed for the text float scale = stbtt_ScaleForPixelHeight(&font.font, size); int baseline = (int)(font.ascent * scale); @@ -70,6 +70,22 @@ void TextElement::RenderText(const std::string_view text, float size, Pixel_BU8_ // Now process each line std::uint_fast32_t lineHeight = (font.ascent - font.descent) * scale; std::uint_fast32_t maxLineWidth = scaled.width; + std::uint_fast32_t totalTextHeight = lines.size() * lineHeight; + + // Calculate vertical offset based on vertical alignment + std::int_fast32_t verticalOffset = 0; + switch (verticalAlignment) { + case VerticalTextAlignment::Top: + verticalOffset = 0; + break; + case VerticalTextAlignment::Middle: + verticalOffset = (scaled.height - totalTextHeight) / 2; + break; + case VerticalTextAlignment::Bottom: + verticalOffset = scaled.height - totalTextHeight; + break; + } + std::uint_fast32_t currentLineStartY = 0; for (std::size_t lineIndex = 0; lineIndex < lines.size(); ++lineIndex) { @@ -101,7 +117,7 @@ void TextElement::RenderText(const std::string_view text, float size, Pixel_BU8_ // Render the line int x = startX; - int startY = currentLineStartY + baseline + (lineIndex * lineHeight); + int startY = verticalOffset + currentLineStartY + baseline + (lineIndex * lineHeight); for (std::size_t i = 0; i < line.size(); ++i) { int codepoint = line[i]; @@ -248,6 +264,39 @@ void TextElement::RenderText(const std::string_view text, float size, Pixel_BU8_ if (!currentLine.empty()) { RenderWrappedLine(currentLine, scale, baseline, currentLineStartY, color, font, alignment); } + + // Apply vertical alignment to the entire wrapped text + std::uint_fast32_t totalTextHeight = (currentLineStartY + lineHeight); // Total height including last line + + // Calculate vertical offset based on vertical alignment + std::int_fast32_t verticalOffset = 0; + switch (verticalAlignment) { + case VerticalTextAlignment::Top: + verticalOffset = 0; + break; + case VerticalTextAlignment::Middle: + verticalOffset = (scaled.height - totalTextHeight) / 2; + break; + case VerticalTextAlignment::Bottom: + verticalOffset = scaled.height - totalTextHeight; + break; + } + + // Shift all rendered content vertically + if (verticalOffset != 0) { + for (std::uint_fast32_t y = 0; y < scaled.height; ++y) { + for (std::uint_fast32_t x = 0; x < scaled.width; ++x) { + std::uint_fast32_t index = y * scaled.width + x; + if (index < bufferScaled.size()) { + // Move the pixel vertically + std::uint_fast32_t newIndex = (y + verticalOffset) * scaled.width + x; + if (newIndex < bufferScaled.size()) { + bufferScaled[newIndex] = bufferScaled[index]; + } + } + } + } + } } } diff --git a/interfaces/Crafter.Graphics-TextElement.cppm b/interfaces/Crafter.Graphics-TextElement.cppm index 2962a3d..391dad4 100644 --- a/interfaces/Crafter.Graphics-TextElement.cppm +++ b/interfaces/Crafter.Graphics-TextElement.cppm @@ -30,6 +30,12 @@ export namespace Crafter { Right }; + enum class VerticalTextAlignment { + Top, + Middle, + Bottom + }; + enum class TextOverflowMode { Clip, // Clip text that overflows Wrap // Wrap text to multiple lines @@ -40,6 +46,6 @@ export namespace Crafter { void RenderWrappedLine(const std::string_view line, float scale, int baseline, std::uint_fast32_t startY, Pixel_BU8_GU8_RU8_AU8 color, Font& font, TextAlignment alignment); public: TextElement(std::int_fast32_t anchorX = FractionalToMapped(0.5), std::int_fast32_t anchorY = FractionalToMapped(0.5), std::uint_fast32_t relativeWidth = FractionalToMapped(1), std::uint_fast32_t relativeHeight = FractionalToMapped(1), std::int_fast32_t anchorOffsetX = FractionalToMapped(0.5), std::int_fast32_t anchorOffsetY = FractionalToMapped(0.5), std::int_fast32_t z = 0, bool ignoreScaling = false); - void RenderText(const std::string_view text, float size, Pixel_BU8_GU8_RU8_AU8 pixel, Font& font, TextAlignment alignment = TextAlignment::Left, TextOverflowMode overflowMode = TextOverflowMode::Clip); + void RenderText(const std::string_view text, float size, Pixel_BU8_GU8_RU8_AU8 pixel, Font& font, TextAlignment alignment = TextAlignment::Left, VerticalTextAlignment verticalAlignment = VerticalTextAlignment::Top, TextOverflowMode overflowMode = TextOverflowMode::Clip); }; } \ No newline at end of file