From 515657be19e4e228ad2221b092fae312d3eb4a9e Mon Sep 17 00:00:00 2001 From: pajlada Date: Sat, 11 Jul 2020 09:12:17 -0400 Subject: [PATCH] Add proper IRC text/word wrapping (#1802) Fixes #1781 --- src/messages/MessageElement.cpp | 50 +++++++++++++++++++++++++++++---- 1 file changed, 45 insertions(+), 5 deletions(-) diff --git a/src/messages/MessageElement.cpp b/src/messages/MessageElement.cpp index c1b887693..85e85b306 100644 --- a/src/messages/MessageElement.cpp +++ b/src/messages/MessageElement.cpp @@ -596,6 +596,7 @@ void IrcTextElement::addToContainer(MessageLayoutContainer &container, // we done goofed, we need to wrap the text QString text = word.text; + std::vector segments = word.segments; int textLength = text.length(); int wordStart = 0; int width = 0; @@ -611,10 +612,47 @@ void IrcTextElement::addToContainer(MessageLayoutContainer &container, auto charWidth = isSurrogate ? metrics.width(text.mid(i, 2)) : metrics.width(text[i]); - if (!container.fitsInLine(width + charWidth)) // + if (!container.fitsInLine(width + charWidth)) { - container.addElementNoLineBreak(getTextLayoutElement( - text.mid(wordStart, i - wordStart), {}, width, false)); + std::vector pieceSegments; + int charactersLeft = i - wordStart; + assert(charactersLeft > 0); + for (auto segmentIt = segments.begin(); + segmentIt != segments.end();) + { + assert(charactersLeft > 0); + auto &segment = *segmentIt; + if (charactersLeft >= segment.text.length()) + { + // Entire segment fits in this piece + pieceSegments.push_back(segment); + charactersLeft -= segment.text.length(); + segmentIt = segments.erase(segmentIt); + + assert(charactersLeft >= 0); + + if (charactersLeft == 0) + { + break; + } + } + else + { + // Only part of the segment fits in this piece + // We create a new segment with the characters that fit, and modify the segment we checked to only contain the characters we didn't consume + Segment segmentThatFitsInPiece{ + segment.text.left(charactersLeft), segment.fg, + segment.bg}; + pieceSegments.emplace_back(segmentThatFitsInPiece); + segment.text = segment.text.mid(charactersLeft); + + break; + } + } + + container.addElementNoLineBreak( + getTextLayoutElement(text.mid(wordStart, i - wordStart), + pieceSegments, width, false)); container.breakLine(); wordStart = i; @@ -631,8 +669,10 @@ void IrcTextElement::addToContainer(MessageLayoutContainer &container, i++; } - container.addElement(getTextLayoutElement( - text.mid(wordStart), {}, width, this->hasTrailingSpace())); + // Add last remaining text & segments + container.addElement( + getTextLayoutElement(text.mid(wordStart), segments, width, + this->hasTrailingSpace())); container.breakLine(); } }