From d2d5e9bdd278022f0d6bcd4e2816a0ded92c0527 Mon Sep 17 00:00:00 2001 From: attila Date: Tue, 22 Apr 2025 15:39:58 +0200 Subject: [PATCH] TextEditor: Fix setLineSpacing Applies the previously missed line spacing value of the TextEditor. The changes in JustifiedText fix calculating the vertical position of the first line for the case where ShapedTextOptions has the following settings: isBaselineAtZero() == false, getHeight().has_value() == false getLeading() > 1.0f This case however is only triggered by the TextEditor, as with all functions in GlyphArrangement at least one setting is different. --- .../detail/juce_JustifiedText.cpp | 23 ++++++++----------- .../widgets/juce_TextEditor.cpp | 9 +++++++- .../juce_gui_basics/widgets/juce_TextEditor.h | 2 +- 3 files changed, 19 insertions(+), 15 deletions(-) diff --git a/modules/juce_graphics/detail/juce_JustifiedText.cpp b/modules/juce_graphics/detail/juce_JustifiedText.cpp index d996577fe5..124c28716c 100644 --- a/modules/juce_graphics/detail/juce_JustifiedText.cpp +++ b/modules/juce_graphics/detail/juce_JustifiedText.cpp @@ -200,12 +200,12 @@ struct LineInfo static float getCrossAxisStartingAnchor (Justification justification, Span lineInfos, std::optional height, - float leadingInHeight) + float leading) { if (lineInfos.empty()) return 0.0f; - const auto minimumTop = lineInfos.front().maxAscent + lineInfos.front().lineHeight * leadingInHeight; + const auto minimumTop = lineInfos.front().maxAscent * leading; if (! height.has_value()) return minimumTop; @@ -213,15 +213,14 @@ static float getCrossAxisStartingAnchor (Justification justification, const auto textHeight = std::accumulate (lineInfos.begin(), lineInfos.end(), 0.0f, - [] (auto acc, const auto info) { return acc + info.lineHeight; }); + [leading] (auto acc, const auto info) { return acc + info.lineHeight * leading; }); if (justification.testFlags (Justification::verticallyCentred)) return (*height - textHeight) / 2.0f + lineInfos.front().maxAscent; if (justification.testFlags (Justification::bottom)) { - const auto bottomLeading = 0.5f * lineInfos.back().lineHeight * leadingInHeight; - return *height - textHeight - bottomLeading + lineInfos.front().maxAscent; + return *height - textHeight + lineInfos.front().maxAscent * leading; } return minimumTop; @@ -230,8 +229,6 @@ static float getCrossAxisStartingAnchor (Justification justification, JustifiedText::JustifiedText (const SimpleShapedText* t, const ShapedTextOptions& options) : shapedText (*t) { - const auto leading = options.getLeading() - 1.0f; - std::vector lineInfos; for (const auto [range, lineNumber] : shapedText.getLineNumbersForGlyphRanges()) @@ -285,7 +282,7 @@ JustifiedText::JustifiedText (const SimpleShapedText* t, const ShapedTextOptions : getCrossAxisStartingAnchor (options.getJustification(), lineInfos, options.getHeight(), - leading); + options.getLeading()); detail::Ranges::Operations ops; @@ -297,16 +294,16 @@ JustifiedText::JustifiedText (const SimpleShapedText* t, const ShapedTextOptions const auto range = lineNumber.range; const auto maxDescent = lineInfo.lineHeight - lineInfo.maxAscent; - const auto nextLineTop = baseline + (1.0f + leading) * maxDescent + options.getAdditiveLineSpacing(); + const auto nextLineTop = baseline + options.getLeading() * maxDescent + options.getAdditiveLineSpacing(); if (! top.has_value()) - top = baseline - (1.0f + leading) * lineInfo.maxAscent; + top = baseline - options.getLeading() * lineInfo.maxAscent; lineMetricsForGlyphRange.set (range, { lineNumber.value, { lineInfo.mainAxisLineAlignment.anchor, baseline }, - lineInfo.maxAscent, - lineInfo.lineHeight - lineInfo.maxAscent, + lineInfo.maxAscent * options.getLeading(), + (lineInfo.lineHeight - lineInfo.maxAscent) * options.getLeading(), lineInfo.mainAxisLineAlignment.effectiveLineLength + lineInfo.mainAxisLineAlignment.extraWhitespaceAdvance, *top, @@ -324,7 +321,7 @@ JustifiedText::JustifiedText (const SimpleShapedText* t, const ShapedTextOptions ops.clear(); const auto nextLineMaxAscent = lineIndex < (int) lineInfos.size() - 1 ? lineInfos[(size_t) lineIndex + 1].maxAscent : 0.0f; - baseline = nextLineTop + (1.0f + leading) * nextLineMaxAscent; + baseline = nextLineTop + options.getLeading() * nextLineMaxAscent; top = nextLineTop; } diff --git a/modules/juce_gui_basics/widgets/juce_TextEditor.cpp b/modules/juce_gui_basics/widgets/juce_TextEditor.cpp index a9188964cf..c2842adc0d 100644 --- a/modules/juce_gui_basics/widgets/juce_TextEditor.cpp +++ b/modules/juce_gui_basics/widgets/juce_TextEditor.cpp @@ -377,6 +377,12 @@ void TextEditor::setJustification (Justification j) } } +void TextEditor::setLineSpacing (float newLineSpacing) noexcept +{ + lineSpacing = jmax (1.0f, newLineSpacing); + updateBaseShapedTextOptions(); +} + //============================================================================== void TextEditor::setFont (const Font& newFont) { @@ -924,7 +930,8 @@ TextEditor::CaretEdge TextEditor::getTextSelectionEdge (int index, Edge edge) co void TextEditor::updateBaseShapedTextOptions() { auto options = detail::ShapedText::Options{}.withTrailingWhitespacesShouldFit (true) - .withJustification (getJustificationType().getOnlyHorizontalFlags()); + .withJustification (getJustificationType().getOnlyHorizontalFlags()) + .withLeading (lineSpacing); if (wordWrap) options = options.withMaxWidth ((float) getMaximumTextWidth()); diff --git a/modules/juce_gui_basics/widgets/juce_TextEditor.h b/modules/juce_gui_basics/widgets/juce_TextEditor.h index 4840f9852e..5f9f7c1ce0 100644 --- a/modules/juce_gui_basics/widgets/juce_TextEditor.h +++ b/modules/juce_gui_basics/widgets/juce_TextEditor.h @@ -551,7 +551,7 @@ public: The default (and minimum) value is 1.0 and values > 1.0 will increase the line spacing as a multiple of the line height e.g. for double-spacing call this method with an argument of 2.0. */ - void setLineSpacing (float newLineSpacing) noexcept { lineSpacing = jmax (1.0f, newLineSpacing); } + void setLineSpacing (float newLineSpacing) noexcept; /** Returns the current line spacing of the TextEditor. */ float getLineSpacing() const noexcept { return lineSpacing; }