From 418308bc7ce4e9924d6280f784222ba45172eea4 Mon Sep 17 00:00:00 2001 From: Kitty Barnett Date: Wed, 6 Nov 2019 12:34:26 +0100 Subject: Characters can have more than one representation in LLFontFreetype * By default all viewer text will use B/W glyphs * Added temporary use_color attribute to LLTextBase for testing --- indra/llui/lltextbase.cpp | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) (limited to 'indra/llui/lltextbase.cpp') diff --git a/indra/llui/lltextbase.cpp b/indra/llui/lltextbase.cpp index a23741b6dd..64b3a0ddcc 100644 --- a/indra/llui/lltextbase.cpp +++ b/indra/llui/lltextbase.cpp @@ -163,6 +163,7 @@ LLTextBase::Params::Params() wrap("wrap"), trusted_content("trusted_content", true), use_ellipses("use_ellipses", false), + use_color("use_color", false), parse_urls("parse_urls", false), force_urls_external("force_urls_external", false), parse_highlights("parse_highlights", false) @@ -217,6 +218,7 @@ LLTextBase::LLTextBase(const LLTextBase::Params &p) mPlainText ( p.plain_text ), mWordWrap(p.wrap), mUseEllipses( p.use_ellipses ), + mUseColor(p.use_color), mParseHTML(p.parse_urls), mForceUrlsExternal(p.force_urls_external), mParseHighlights(p.parse_highlights), @@ -3198,7 +3200,8 @@ F32 LLNormalTextSegment::drawClippedSegment(S32 seg_start, S32 seg_end, S32 sele mStyle->getShadowType(), length, &right_x, - mEditor.getUseEllipses()); + mEditor.getUseEllipses(), + mEditor.getUseColor()); } rect.mLeft = right_x; @@ -3217,7 +3220,8 @@ F32 LLNormalTextSegment::drawClippedSegment(S32 seg_start, S32 seg_end, S32 sele LLFontGL::NO_SHADOW, length, &right_x, - mEditor.getUseEllipses()); + mEditor.getUseEllipses(), + mEditor.getUseColor()); } rect.mLeft = right_x; if( selection_end < seg_end ) @@ -3234,7 +3238,8 @@ F32 LLNormalTextSegment::drawClippedSegment(S32 seg_start, S32 seg_end, S32 sele mStyle->getShadowType(), length, &right_x, - mEditor.getUseEllipses()); + mEditor.getUseEllipses(), + mEditor.getUseColor()); } return right_x; } -- cgit v1.2.3 From b44ade68e6eea656dc0e31738f9603caffe4d659 Mon Sep 17 00:00:00 2001 From: Kitty Barnett Date: Thu, 7 Nov 2019 20:33:53 +0100 Subject: FIXED Calling LLTextBase::insertStringNoUndo() with more than one segment results in overlapping segment ranges Text is only inserted into the view model *after* the segments are added so if seg1_pos_start is the current EOF: -> 1st segment: getSegIterContaining(seg1_pos_start) returns the last segment and insertSegment() ends up properly adjusting its start/end position -> 2nd segment: getSegIterContaining(seg2_pos_start) returns mSegments.end() since its position is beyond the available and insertSegment() leaves the last 2 segments with overlapping ranges After the fix: -> if index runs past the end of all segments then mSegments.end() is returned (no change) -> if index is a position past the length of text but claimed by a segment then that segment is returned (change) -> if index specifies a position in the middle of the document unclaimed by any segment then the first segment after that position is returned (no change) (this does break the assertion that segment->mStart <= index <= segment->mEnd?) --- indra/llui/lltextbase.cpp | 4 ---- 1 file changed, 4 deletions(-) (limited to 'indra/llui/lltextbase.cpp') diff --git a/indra/llui/lltextbase.cpp b/indra/llui/lltextbase.cpp index 64b3a0ddcc..ecceb289f0 100644 --- a/indra/llui/lltextbase.cpp +++ b/indra/llui/lltextbase.cpp @@ -1889,8 +1889,6 @@ LLTextBase::segment_set_t::iterator LLTextBase::getSegIterContaining(S32 index) text_len = mLabel.getWString().length(); } - if (index > text_len) { return mSegments.end(); } - // when there are no segments, we return the end iterator, which must be checked by caller if (mSegments.size() <= 1) { return mSegments.begin(); } @@ -1914,8 +1912,6 @@ LLTextBase::segment_set_t::const_iterator LLTextBase::getSegIterContaining(S32 i text_len = mLabel.getWString().length(); } - if (index > text_len) { return mSegments.end(); } - // when there are no segments, we return the end iterator, which must be checked by caller if (mSegments.size() <= 1) { return mSegments.begin(); } -- cgit v1.2.3 From d58b530e805e2b3c943b1ff446ac84a10c500b32 Mon Sep 17 00:00:00 2001 From: Kitty Barnett Date: Thu, 7 Nov 2019 20:48:20 +0100 Subject: Add text_valign to LLTextBase to specify the vertical alignment within a single document line The existing font_valign property is used as to position the entire document so it's impossible to top align a text editor with each line's text centered within that line's extents --- indra/llui/lltextbase.cpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'indra/llui/lltextbase.cpp') diff --git a/indra/llui/lltextbase.cpp b/indra/llui/lltextbase.cpp index ecceb289f0..cc44f46706 100644 --- a/indra/llui/lltextbase.cpp +++ b/indra/llui/lltextbase.cpp @@ -160,6 +160,7 @@ LLTextBase::Params::Params() line_spacing("line_spacing"), max_text_length("max_length", 255), font_shadow("font_shadow"), + text_valign("text_valign"), wrap("wrap"), trusted_content("trusted_content", true), use_ellipses("use_ellipses", false), @@ -205,6 +206,7 @@ LLTextBase::LLTextBase(const LLTextBase::Params &p) mVPad(p.v_pad), mHAlign(p.font_halign), mVAlign(p.font_valign), + mTextVAlign(p.text_valign.isProvided() ? p.text_valign : p.font_valign), mLineSpacingMult(p.line_spacing.multiple), mLineSpacingPixels(p.line_spacing.pixels), mClip(p.clip), @@ -515,7 +517,7 @@ void LLTextBase::drawCursor() fontp = segmentp->getStyle()->getFont(); fontp->render(text, mCursorPos, cursor_rect, LLColor4(1.f - text_color.mV[VRED], 1.f - text_color.mV[VGREEN], 1.f - text_color.mV[VBLUE], alpha), - LLFontGL::LEFT, mVAlign, + LLFontGL::LEFT, mTextVAlign, LLFontGL::NORMAL, LLFontGL::NO_SHADOW, 1); @@ -3191,7 +3193,7 @@ F32 LLNormalTextSegment::drawClippedSegment(S32 seg_start, S32 seg_end, S32 sele font->render(text, start, rect, color, - LLFontGL::LEFT, mEditor.mVAlign, + LLFontGL::LEFT, mEditor.mTextVAlign, LLFontGL::NORMAL, mStyle->getShadowType(), length, @@ -3211,7 +3213,7 @@ F32 LLNormalTextSegment::drawClippedSegment(S32 seg_start, S32 seg_end, S32 sele font->render(text, start, rect, mStyle->getSelectedColor().get(), - LLFontGL::LEFT, mEditor.mVAlign, + LLFontGL::LEFT, mEditor.mTextVAlign, LLFontGL::NORMAL, LLFontGL::NO_SHADOW, length, @@ -3229,7 +3231,7 @@ F32 LLNormalTextSegment::drawClippedSegment(S32 seg_start, S32 seg_end, S32 sele font->render(text, start, rect, color, - LLFontGL::LEFT, mEditor.mVAlign, + LLFontGL::LEFT, mEditor.mTextVAlign, LLFontGL::NORMAL, mStyle->getShadowType(), length, -- cgit v1.2.3 From bab70f6f152952ce755188d29bea1cfd8821a4be Mon Sep 17 00:00:00 2001 From: Kitty Barnett Date: Mon, 29 Aug 2022 00:00:31 +0200 Subject: Review + resolve minor issues --- indra/llui/lltextbase.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'indra/llui/lltextbase.cpp') diff --git a/indra/llui/lltextbase.cpp b/indra/llui/lltextbase.cpp index 9005d70b2e..0447e7070c 100644 --- a/indra/llui/lltextbase.cpp +++ b/indra/llui/lltextbase.cpp @@ -208,7 +208,7 @@ LLTextBase::LLTextBase(const LLTextBase::Params &p) mVPad(p.v_pad), mHAlign(p.font_halign), mVAlign(p.font_valign), - mTextVAlign(p.text_valign.isProvided() ? p.text_valign : p.font_valign), + mTextVAlign(p.text_valign.isProvided() ? p.text_valign.getValue() : p.font_valign.getValue()), mLineSpacingMult(p.line_spacing.multiple), mLineSpacingPixels(p.line_spacing.pixels), mClip(p.clip), -- cgit v1.2.3 From 063fe5953ada75177c1668f8b805cd9b79724581 Mon Sep 17 00:00:00 2001 From: Kitty Barnett Date: Wed, 2 Nov 2022 14:25:27 +0100 Subject: Create a separate segment for emoji characters so that we can display them in a slightly larger font size than the surrounding text --- indra/llui/lltextbase.cpp | 49 ++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 46 insertions(+), 3 deletions(-) (limited to 'indra/llui/lltextbase.cpp') diff --git a/indra/llui/lltextbase.cpp b/indra/llui/lltextbase.cpp index 0447e7070c..2a6e6901e4 100644 --- a/indra/llui/lltextbase.cpp +++ b/indra/llui/lltextbase.cpp @@ -2302,6 +2302,36 @@ void LLTextBase::appendWidget(const LLInlineViewSegment::Params& params, const s insertStringNoUndo(getLength(), widget_wide_text, &segments); } +void LLTextBase::createTextWithEmojiSegment(const LLWString& text, S32 segment_start, LLStyleConstSP style, segment_vec_t& segments) +{ + LLStyleSP emoji_style; + + S32 text_start = 0, text_kitty = 0, text_len = text.size(); + for (; text_kitty < text_len; text_kitty++) + { + if (LLStringOps::isEmoji(text[text_kitty])) + { + if (text_kitty > text_start) + { + segments.push_back(new LLNormalTextSegment(style, segment_start + text_start, segment_start + text_kitty, *this)); + } + + if (!emoji_style) + { + emoji_style = new LLStyle(*style); + emoji_style->setFont(LLFontGL::getFontEmoji()); + } + segments.push_back(new LLEmojiTextSegment(emoji_style, segment_start + text_kitty, segment_start + text_kitty + 1, *this)); + text_start = text_kitty + 1; + } + } + + if (text_start < text_len) + { + segments.push_back(new LLNormalTextSegment(style, segment_start + text_start, segment_start + text_len, *this)); + } +} + void LLTextBase::appendAndHighlightTextImpl(const std::string &new_text, S32 highlight_part, const LLStyle::Params& style_params, bool underline_on_hover_only) { // Save old state @@ -2334,6 +2364,7 @@ void LLTextBase::appendAndHighlightTextImpl(const std::string &new_text, S32 hig S32 cur_length = getLength(); LLStyleConstSP sp(new LLStyle(highlight_params)); LLTextSegmentPtr segmentp; + segment_vec_t segments; if (underline_on_hover_only || mSkipLinkUnderline) { highlight_params.font.style("NORMAL"); @@ -2342,9 +2373,8 @@ void LLTextBase::appendAndHighlightTextImpl(const std::string &new_text, S32 hig } else { - segmentp = new LLNormalTextSegment(sp, cur_length, cur_length + wide_text.size(), *this); + createTextWithEmojiSegment(wide_text, cur_length, sp, segments); } - segment_vec_t segments; segments.push_back(segmentp); insertStringNoUndo(cur_length, wide_text, &segments); } @@ -2367,7 +2397,7 @@ void LLTextBase::appendAndHighlightTextImpl(const std::string &new_text, S32 hig } else { - segments.push_back(new LLNormalTextSegment(sp, segment_start, segment_end, *this )); + createTextWithEmojiSegment(wide_text, segment_start, sp, segments); } insertStringNoUndo(getLength(), wide_text, &segments); @@ -3514,6 +3544,19 @@ const S32 LLLabelTextSegment::getLength() const return mEditor.getWlabel().length(); } +// +// LLEmojiTextSegment +// +LLEmojiTextSegment::LLEmojiTextSegment(LLStyleConstSP style, S32 start, S32 end, LLTextBase& editor) + : LLNormalTextSegment(style, start, end, editor) +{ +} + +LLEmojiTextSegment::LLEmojiTextSegment(const LLColor4& color, S32 start, S32 end, LLTextBase& editor, BOOL is_visible) + : LLNormalTextSegment(color, start, end, editor, is_visible) +{ +} + // // LLOnHoverChangeableTextSegment // -- cgit v1.2.3 From 8d08f417dc1f5b2681774f000951993e0f0cf79f Mon Sep 17 00:00:00 2001 From: Kitty Barnett Date: Sun, 23 Oct 2022 16:37:10 +0200 Subject: Show tooltip when hovering over an emoji text segment (currently will show its shortcode) --- indra/llui/lltextbase.cpp | 14 ++++++++++++++ 1 file changed, 14 insertions(+) (limited to 'indra/llui/lltextbase.cpp') diff --git a/indra/llui/lltextbase.cpp b/indra/llui/lltextbase.cpp index 2a6e6901e4..693dcb7b8d 100644 --- a/indra/llui/lltextbase.cpp +++ b/indra/llui/lltextbase.cpp @@ -3557,6 +3557,20 @@ LLEmojiTextSegment::LLEmojiTextSegment(const LLColor4& color, S32 start, S32 end { } +BOOL LLEmojiTextSegment::handleToolTip(S32 x, S32 y, MASK mask) +{ + if (mTooltip.empty()) + { + LLWString emoji = getWText().substr(getStart(), getEnd() - getStart()); + if (!emoji.empty()) + { + mTooltip = LLEmojiHelper::instance().getToolTip(emoji[0]); + } + } + + return LLNormalTextSegment::handleToolTip(x, y, mask); +} + // // LLOnHoverChangeableTextSegment // -- cgit v1.2.3 From c40d3351d511b19f4468f7467be38499bf16588f Mon Sep 17 00:00:00 2001 From: Kitty Barnett Date: Wed, 2 Nov 2022 19:05:24 +0100 Subject: Commit immediately if the user already typed a full shortcode --- indra/llui/lltextbase.cpp | 1 + 1 file changed, 1 insertion(+) (limited to 'indra/llui/lltextbase.cpp') diff --git a/indra/llui/lltextbase.cpp b/indra/llui/lltextbase.cpp index 693dcb7b8d..b88c7ced40 100644 --- a/indra/llui/lltextbase.cpp +++ b/indra/llui/lltextbase.cpp @@ -29,6 +29,7 @@ #include "lltextbase.h" +#include "llemojihelper.h" #include "lllocalcliprect.h" #include "llmenugl.h" #include "llscrollcontainer.h" -- cgit v1.2.3 From 62d62abe9c35066bb7bb29155046311245854563 Mon Sep 17 00:00:00 2001 From: Kitty Barnett Date: Wed, 9 Nov 2022 00:08:43 +0100 Subject: [FIXED] Using the Windows emoji picker or pasting text containing emojis doesn't create emoji segments (=emoji size is same size as the text size) -> Partial revert of 063fe59 --- indra/llui/lltextbase.cpp | 55 +++++++++++++++++++---------------------------- 1 file changed, 22 insertions(+), 33 deletions(-) (limited to 'indra/llui/lltextbase.cpp') diff --git a/indra/llui/lltextbase.cpp b/indra/llui/lltextbase.cpp index b88c7ced40..28165aa1ef 100644 --- a/indra/llui/lltextbase.cpp +++ b/indra/llui/lltextbase.cpp @@ -834,6 +834,25 @@ S32 LLTextBase::insertStringNoUndo(S32 pos, const LLWString &wstr, LLTextBase::s } } + // Insert special segments where necessary (insertSegment takes care of splitting normal text segments around them for us) + { + LLStyleSP emoji_style; + for (S32 text_kitty = 0, text_len = wstr.size(); text_kitty < text_len; text_kitty++) + { + if (LLStringOps::isEmoji(wstr[text_kitty])) + { + if (!emoji_style) + { + emoji_style = new LLStyle(getStyleParams()); + emoji_style->setFont(LLFontGL::getFontEmoji()); + } + + S32 new_seg_start = pos + text_kitty; + insertSegment(new LLEmojiTextSegment(emoji_style, new_seg_start, new_seg_start + 1, *this)); + } + } + } + getViewModel()->getEditableDisplay().insert(pos, wstr); if ( truncate() ) @@ -2303,36 +2322,6 @@ void LLTextBase::appendWidget(const LLInlineViewSegment::Params& params, const s insertStringNoUndo(getLength(), widget_wide_text, &segments); } -void LLTextBase::createTextWithEmojiSegment(const LLWString& text, S32 segment_start, LLStyleConstSP style, segment_vec_t& segments) -{ - LLStyleSP emoji_style; - - S32 text_start = 0, text_kitty = 0, text_len = text.size(); - for (; text_kitty < text_len; text_kitty++) - { - if (LLStringOps::isEmoji(text[text_kitty])) - { - if (text_kitty > text_start) - { - segments.push_back(new LLNormalTextSegment(style, segment_start + text_start, segment_start + text_kitty, *this)); - } - - if (!emoji_style) - { - emoji_style = new LLStyle(*style); - emoji_style->setFont(LLFontGL::getFontEmoji()); - } - segments.push_back(new LLEmojiTextSegment(emoji_style, segment_start + text_kitty, segment_start + text_kitty + 1, *this)); - text_start = text_kitty + 1; - } - } - - if (text_start < text_len) - { - segments.push_back(new LLNormalTextSegment(style, segment_start + text_start, segment_start + text_len, *this)); - } -} - void LLTextBase::appendAndHighlightTextImpl(const std::string &new_text, S32 highlight_part, const LLStyle::Params& style_params, bool underline_on_hover_only) { // Save old state @@ -2365,7 +2354,6 @@ void LLTextBase::appendAndHighlightTextImpl(const std::string &new_text, S32 hig S32 cur_length = getLength(); LLStyleConstSP sp(new LLStyle(highlight_params)); LLTextSegmentPtr segmentp; - segment_vec_t segments; if (underline_on_hover_only || mSkipLinkUnderline) { highlight_params.font.style("NORMAL"); @@ -2374,8 +2362,9 @@ void LLTextBase::appendAndHighlightTextImpl(const std::string &new_text, S32 hig } else { - createTextWithEmojiSegment(wide_text, cur_length, sp, segments); + segmentp = new LLNormalTextSegment(sp, cur_length, cur_length + wide_text.size(), *this); } + segment_vec_t segments; segments.push_back(segmentp); insertStringNoUndo(cur_length, wide_text, &segments); } @@ -2398,7 +2387,7 @@ void LLTextBase::appendAndHighlightTextImpl(const std::string &new_text, S32 hig } else { - createTextWithEmojiSegment(wide_text, segment_start, sp, segments); + segments.push_back(new LLNormalTextSegment(sp, segment_start, segment_end, *this )); } insertStringNoUndo(getLength(), wide_text, &segments); -- cgit v1.2.3