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/llfolderviewitem.cpp | 6 +++--- indra/llui/lltextbase.cpp | 11 ++++++++--- indra/llui/lltextbase.h | 3 +++ indra/llui/llview.cpp | 2 +- 4 files changed, 15 insertions(+), 7 deletions(-) (limited to 'indra/llui') diff --git a/indra/llui/llfolderviewitem.cpp b/indra/llui/llfolderviewitem.cpp index 0510e472c5..0c1c3c40ec 100644 --- a/indra/llui/llfolderviewitem.cpp +++ b/indra/llui/llfolderviewitem.cpp @@ -826,7 +826,7 @@ void LLFolderViewItem::drawLabel(const LLFontGL * font, const F32 x, const F32 y // font->renderUTF8(mLabel, 0, x, y, color, LLFontGL::LEFT, LLFontGL::BOTTOM, LLFontGL::NORMAL, LLFontGL::NO_SHADOW, - S32_MAX, getRect().getWidth() - (S32) x - mLabelPaddingRight, &right_x, TRUE); + S32_MAX, getRect().getWidth() - (S32) x - mLabelPaddingRight, &right_x, /*use_ellipses*/TRUE, /*use_color*/FALSE); } void LLFolderViewItem::draw() @@ -905,7 +905,7 @@ void LLFolderViewItem::draw() { font->renderUTF8( mLabelSuffix, 0, right_x, y, isFadeItem() ? color : (LLColor4)sSuffixColor, LLFontGL::LEFT, LLFontGL::BOTTOM, LLFontGL::NORMAL, LLFontGL::NO_SHADOW, - S32_MAX, S32_MAX, &right_x, FALSE ); + S32_MAX, S32_MAX, &right_x, /*use_ellipses*/FALSE, /*use_color*/FALSE ); } //--------------------------------------------------------------------------------// @@ -917,7 +917,7 @@ void LLFolderViewItem::draw() F32 yy = (F32)getRect().getHeight() - font->getLineHeight() - (F32)mTextPad - (F32)TOP_PAD; font->renderUTF8( combined_string, mViewModelItem->getFilterStringOffset(), match_string_left, yy, sFilterTextColor, LLFontGL::LEFT, LLFontGL::BOTTOM, LLFontGL::NORMAL, LLFontGL::NO_SHADOW, - filter_string_length, S32_MAX, &right_x, FALSE ); + filter_string_length, S32_MAX, &right_x, /*use_ellipses*/FALSE, /*use_color*/FALSE ); } //Gilbert Linden 9-20-2012: Although this should be legal, removing it because it causes the mLabelSuffix rendering to 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; } diff --git a/indra/llui/lltextbase.h b/indra/llui/lltextbase.h index 9831c35858..6f1e178e36 100644 --- a/indra/llui/lltextbase.h +++ b/indra/llui/lltextbase.h @@ -314,6 +314,7 @@ public: plain_text, wrap, use_ellipses, + use_color, parse_urls, force_urls_external, parse_highlights, @@ -389,6 +390,7 @@ public: // used by LLTextSegment layout code bool getWordWrap() { return mWordWrap; } bool getUseEllipses() { return mUseEllipses; } + bool getUseColor() { return mUseColor; } bool truncate(); // returns true of truncation occurred bool isContentTrusted() {return mTrustedContent;} @@ -681,6 +683,7 @@ protected: bool mParseHighlights; // highlight user-defined keywords bool mWordWrap; bool mUseEllipses; + bool mUseColor; bool mTrackEnd; // if true, keeps scroll position at end of document during resize bool mReadOnly; bool mBGVisible; // render background? diff --git a/indra/llui/llview.cpp b/indra/llui/llview.cpp index 89ad8138d8..40537e6c4a 100644 --- a/indra/llui/llview.cpp +++ b/indra/llui/llview.cpp @@ -1282,7 +1282,7 @@ void LLView::drawDebugRect() debug_rect.getWidth(), debug_rect.getHeight()); LLFontGL::getFontSansSerifSmall()->renderUTF8(debug_text, 0, (F32)x, (F32)y, border_color, LLFontGL::HCENTER, LLFontGL::BASELINE, LLFontGL::NORMAL, LLFontGL::NO_SHADOW, - S32_MAX, S32_MAX, NULL, FALSE); + S32_MAX, S32_MAX, NULL, /*use_ellipses*/FALSE, /*use_color*/FALSE); } } LLUI::popMatrix(); -- 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') 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 ++++++---- indra/llui/lltextbase.h | 7 +++++-- 2 files changed, 11 insertions(+), 6 deletions(-) (limited to 'indra/llui') 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, diff --git a/indra/llui/lltextbase.h b/indra/llui/lltextbase.h index 6f1e178e36..99c243a346 100644 --- a/indra/llui/lltextbase.h +++ b/indra/llui/lltextbase.h @@ -333,6 +333,8 @@ public: Optional font_shadow; + Optional text_valign; + Params(); }; @@ -673,8 +675,9 @@ protected: // configuration S32 mHPad; // padding on left of text S32 mVPad; // padding above text - LLFontGL::HAlign mHAlign; - LLFontGL::VAlign mVAlign; + LLFontGL::HAlign mHAlign; // horizontal alignment of the document in its entirety + LLFontGL::VAlign mVAlign; // vertical alignment of the document in its entirety + LLFontGL::VAlign mTextVAlign; // vertical alignment of a text segment within a single line of text F32 mLineSpacingMult; // multiple of line height used as space for a single line of text (e.g. 1.5 to get 50% padding) S32 mLineSpacingPixels; // padding between lines bool mBorderVisible; -- 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') 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 ++++++++++++++++++++++++++++++++++++++++++++--- indra/llui/lltextbase.h | 12 ++++++++++++ 2 files changed, 58 insertions(+), 3 deletions(-) (limited to 'indra/llui') 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 // diff --git a/indra/llui/lltextbase.h b/indra/llui/lltextbase.h index 590e7c9dbb..fc999c4cca 100644 --- a/indra/llui/lltextbase.h +++ b/indra/llui/lltextbase.h @@ -178,6 +178,17 @@ protected: /*virtual*/ const S32 getLength() const; }; +// Text segment that represents a single emoji character that has a different style (=font size) than the rest of +// the document it belongs to +class LLEmojiTextSegment : public LLNormalTextSegment +{ +public: + LLEmojiTextSegment(LLStyleConstSP style, S32 start, S32 end, LLTextBase& editor); + LLEmojiTextSegment(const LLColor4& color, S32 start, S32 end, LLTextBase& editor, BOOL is_visible = TRUE); + + bool canEdit() const override { return false; } +}; + // Text segment that changes it's style depending of mouse pointer position ( is it inside or outside segment) class LLOnHoverChangeableTextSegment : public LLNormalTextSegment { @@ -629,6 +640,7 @@ protected: void appendTextImpl(const std::string &new_text, const LLStyle::Params& input_params = LLStyle::Params()); void appendAndHighlightTextImpl(const std::string &new_text, S32 highlight_part, const LLStyle::Params& style_params, bool underline_on_hover_only = false); + void createTextWithEmojiSegment(const LLWString& wide_text, S32 segment_start, LLStyleConstSP style, segment_vec_t& segments); S32 normalizeUri(std::string& uri); protected: -- cgit v1.2.3 From 8694f055b64eb7ce13897e49afe73c4d3295a29a Mon Sep 17 00:00:00 2001 From: Kitty Barnett Date: Sun, 23 Oct 2022 16:09:30 +0200 Subject: Add emoji helper support to LLTextEditor --- indra/llui/lltexteditor.cpp | 40 ++++++++++++++++++++++++++++++++++++++++ indra/llui/lltexteditor.h | 5 +++++ 2 files changed, 45 insertions(+) (limited to 'indra/llui') diff --git a/indra/llui/lltexteditor.cpp b/indra/llui/lltexteditor.cpp index b1f8b00cab..889940cf9a 100644 --- a/indra/llui/lltexteditor.cpp +++ b/indra/llui/lltexteditor.cpp @@ -43,6 +43,7 @@ #include "llmath.h" #include "llclipboard.h" +#include "llemojihelper.h" #include "llscrollbar.h" #include "llstl.h" #include "llstring.h" @@ -238,6 +239,7 @@ LLTextEditor::Params::Params() default_color("default_color"), commit_on_focus_lost("commit_on_focus_lost", false), show_context_menu("show_context_menu"), + show_emoji_helper("show_emoji_helper"), enable_tooltip_paste("enable_tooltip_paste") { addSynonym(prevalidate_callback, "text_type"); @@ -259,6 +261,7 @@ LLTextEditor::LLTextEditor(const LLTextEditor::Params& p) : mPrevalidateFunc(p.prevalidate_callback()), mContextMenu(NULL), mShowContextMenu(p.show_context_menu), + mShowEmojiHelper(p.show_emoji_helper), mEnableTooltipPaste(p.enable_tooltip_paste), mPassDelete(FALSE), mKeepSelectionOnReturn(false) @@ -501,6 +504,15 @@ void LLTextEditor::getSegmentsInRange(LLTextEditor::segment_vec_t& segments_out, } } +void LLTextEditor::setShowEmojiHelper(bool show) { + if (!mShowEmojiHelper) + { + LLEmojiHelper::instance().hideHelper(this); + } + + mShowEmojiHelper = show; +} + BOOL LLTextEditor::selectionContainsLineBreaks() { if (hasSelection()) @@ -930,6 +942,12 @@ BOOL LLTextEditor::handleDoubleClick(S32 x, S32 y, MASK mask) S32 LLTextEditor::execute( TextCmd* cmd ) { + if (!mReadOnly && mShowEmojiHelper) + { + // Any change to our contents should always hide the helper + LLEmojiHelper::instance().hideHelper(this); + } + S32 delta = 0; if( cmd->execute(this, &delta) ) { @@ -1124,6 +1142,17 @@ void LLTextEditor::addChar(llwchar wc) setCursorPos(mCursorPos + addChar( mCursorPos, wc )); + if (!mReadOnly && mShowEmojiHelper) + { + LLWString wtext(getWText()); S32 shortCodePos; + if (LLEmojiHelper::isCursorInEmojiCode(wtext, mCursorPos, &shortCodePos)) + { + const LLRect cursorRect = getLocalRectFromDocIndex(mCursorPos); + const LLWString shortCode = wtext.substr(shortCodePos, mCursorPos); + LLEmojiHelper::instance().showHelper(this, cursorRect.mLeft, cursorRect.mTop, wstring_to_utf8str(shortCode)); + } + } + if (!mReadOnly && mAutoreplaceCallback != NULL) { // autoreplace the text, if necessary @@ -1774,6 +1803,11 @@ BOOL LLTextEditor::handleKeyHere(KEY key, MASK mask ) } else { + if (!mReadOnly && mShowEmojiHelper && LLEmojiHelper::instance().handleKey(this, key, mask)) + { + return TRUE; + } + if (mEnableTooltipPaste && LLToolTipMgr::instance().toolTipVisible() && KEY_TAB == key) @@ -1815,6 +1849,12 @@ BOOL LLTextEditor::handleKeyHere(KEY key, MASK mask ) { resetCursorBlink(); needsScroll(); + + if (mShowEmojiHelper) + { + // Dismiss the helper whenever we handled a key that it didn't + LLEmojiHelper::instance().hideHelper(this); + } } return handled; diff --git a/indra/llui/lltexteditor.h b/indra/llui/lltexteditor.h index 26702b2412..04910b6f68 100644 --- a/indra/llui/lltexteditor.h +++ b/indra/llui/lltexteditor.h @@ -60,6 +60,7 @@ public: ignore_tab, commit_on_focus_lost, show_context_menu, + show_emoji_helper, enable_tooltip_paste, auto_indent; @@ -201,6 +202,9 @@ public: void setShowContextMenu(bool show) { mShowContextMenu = show; } bool getShowContextMenu() const { return mShowContextMenu; } + void setShowEmojiHelper(bool show); + bool getShowEmojiHelper() const { return mShowEmojiHelper; } + void setPassDelete(BOOL b) { mPassDelete = b; } protected: @@ -317,6 +321,7 @@ private: BOOL mAllowEmbeddedItems; bool mShowContextMenu; + bool mShowEmojiHelper; bool mEnableTooltipPaste; bool mPassDelete; bool mKeepSelectionOnReturn; // disabling of removing selected text after pressing of Enter -- cgit v1.2.3 From ec23b4bc633b853223d8442f60e769d44a25fe2d Mon Sep 17 00:00:00 2001 From: Kitty Barnett Date: Sun, 23 Oct 2022 16:06:41 +0200 Subject: Add the basic emoji dictionary class (responsible for loading them from disk and providing helpful lookup functions) --- indra/llui/CMakeLists.txt | 2 + indra/llui/llemojidictionary.cpp | 177 +++++++++++++++++++++++++++++++++++++++ indra/llui/llemojidictionary.h | 71 ++++++++++++++++ 3 files changed, 250 insertions(+) create mode 100644 indra/llui/llemojidictionary.cpp create mode 100644 indra/llui/llemojidictionary.h (limited to 'indra/llui') diff --git a/indra/llui/CMakeLists.txt b/indra/llui/CMakeLists.txt index f781ff4110..4e007e429a 100644 --- a/indra/llui/CMakeLists.txt +++ b/indra/llui/CMakeLists.txt @@ -53,6 +53,7 @@ set(llui_SOURCE_FILES lldockcontrol.cpp lldraghandle.cpp lleditmenuhandler.cpp + llemojidictionary.cpp llf32uictrl.cpp llfiltereditor.cpp llflashtimer.cpp @@ -163,6 +164,7 @@ set(llui_HEADER_FILES lldockablefloater.h lldockcontrol.h lleditmenuhandler.h + llemojidictionary.h llf32uictrl.h llfiltereditor.h llflashtimer.h diff --git a/indra/llui/llemojidictionary.cpp b/indra/llui/llemojidictionary.cpp new file mode 100644 index 0000000000..e149832a8b --- /dev/null +++ b/indra/llui/llemojidictionary.cpp @@ -0,0 +1,177 @@ +/** +* @file llemojidictionary.cpp +* @brief Implementation of LLEmojiDictionary +* +* $LicenseInfo:firstyear=2014&license=viewerlgpl$ +* Second Life Viewer Source Code +* Copyright (C) 2014, Linden Research, Inc. +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public +* License as published by the Free Software Foundation; +* version 2.1 of the License only. +* +* This library is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public +* License along with this library; if not, write to the Free Software +* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +* +* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA +* $/LicenseInfo$ +*/ + +#include "linden_common.h" + +#include "lldir.h" +#include "llemojidictionary.h" +#include "llsdserialize.h" + +#include + +// ============================================================================ +// Constants +// + +constexpr char SKINNED_EMOJI_FILENAME[] = "emoji_characters.xml"; + +// ============================================================================ +// Helper functions +// + +template +std::list llsd_array_to_list(const LLSD& sd, std::function mutator = {}); + +template<> +std::list llsd_array_to_list(const LLSD& sd, std::function mutator) +{ + std::list result; + for (LLSD::array_const_iterator it = sd.beginArray(), end = sd.endArray(); it != end; ++it) + { + const LLSD& entry = *it; + if (!entry.isString()) + continue; + + result.push_back(entry.asStringRef()); + if (mutator) + { + mutator(result.back()); + } + } + return result; +} + +LLEmojiDescriptor::LLEmojiDescriptor(const LLSD& descriptor_sd) +{ + Name = descriptor_sd["Name"].asStringRef(); + + const LLWString emoji_string = utf8str_to_wstring(descriptor_sd["Character"].asString()); + Character = (1 == emoji_string.size()) ? emoji_string[0] : L'\0'; // We don't currently support character composition + + auto toLower = [](std::string& str) { LLStringUtil::toLower(str); }; + ShortCodes = llsd_array_to_list(descriptor_sd["ShortCodes"], toLower); + Categories = llsd_array_to_list(descriptor_sd["Categories"], toLower); + + if (Name.empty()) + { + Name = ShortCodes.front(); + } +} + +bool LLEmojiDescriptor::isValid() const +{ + return + Character && + !ShortCodes.empty() && + !Categories.empty(); +} + +// ============================================================================ +// LLEmojiDictionary class +// + +LLEmojiDictionary::LLEmojiDictionary() +{ +} + +// static +void LLEmojiDictionary::initClass() +{ + LLEmojiDictionary* pThis = &LLEmojiDictionary::initParamSingleton(); + + LLSD data; + + const std::string filename = gDirUtilp->findSkinnedFilenames(LLDir::XUI, SKINNED_EMOJI_FILENAME, LLDir::CURRENT_SKIN).front(); + llifstream file(filename.c_str()); + if (file.is_open()) + { + LL_DEBUGS() << "Loading emoji characters file at " << filename << LL_ENDL; + LLSDSerialize::fromXML(data, file); + } + + if (data.isUndefined()) + { + LL_WARNS() << "Emoji file characters missing or ill-formed" << LL_ENDL; + return; + } + + for (LLSD::array_const_iterator descriptor_it = data.beginArray(), descriptor_end = data.endArray(); descriptor_it != descriptor_end; ++descriptor_it) + { + LLEmojiDescriptor descriptor(*descriptor_it); + if (!descriptor.isValid()) + { + LL_WARNS() << "Skipping invalid emoji descriptor " << descriptor.Character << LL_ENDL; + continue; + } + pThis->addEmoji(std::move(descriptor)); + } +} + +LLWString LLEmojiDictionary::findMatchingEmojis(std::string needle) +{ + // Search without the colon (if present) so the user can type ':food' and see all emojis in the 'Food' category + LLStringUtil::toLower(needle); + const auto kitty_needle = boost::make_iterator_range((boost::starts_with(needle, ":")) ? needle.begin() + 1 : needle.begin(), needle.end()); + + LLWString wstr; + for (const auto& descr : mEmojis) + { + for (const auto& short_code : descr.ShortCodes) + { + if (boost::icontains(short_code, kitty_needle)) + { + wstr.push_back(descr.Character); + continue; + } + } + + for (const auto& category : descr.Categories) + { + if (boost::icontains(category, kitty_needle)) + { + wstr.push_back(descr.Character); + continue; + } + } + } + + return wstr; +} + +std::string LLEmojiDictionary::getNameFromEmoji(llwchar ch) +{ + const auto it = mEmoji2Descr.find(ch); + return (mEmoji2Descr.end() != it) ? it->second->Name : LLStringUtil::null; +} + +void LLEmojiDictionary::addEmoji(LLEmojiDescriptor&& descr) +{ + mEmojis.push_back(descr); + const LLEmojiDescriptor& back = mEmojis.back(); + mEmoji2Descr.insert(std::make_pair(descr.Character, &back)); +} + +// ============================================================================ diff --git a/indra/llui/llemojidictionary.h b/indra/llui/llemojidictionary.h new file mode 100644 index 0000000000..87ea4a5aef --- /dev/null +++ b/indra/llui/llemojidictionary.h @@ -0,0 +1,71 @@ +/** +* @file llemojidictionary.h +* @brief Header file for LLEmojiDictionary +* +* $LicenseInfo:firstyear=2014&license=viewerlgpl$ +* Second Life Viewer Source Code +* Copyright (C) 2014, Linden Research, Inc. +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public +* License as published by the Free Software Foundation; +* version 2.1 of the License only. +* +* This library is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public +* License along with this library; if not, write to the Free Software +* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +* +* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA +* $/LicenseInfo$ +*/ + +#pragma once + +#include "lldictionary.h" +#include "llinitdestroyclass.h" +#include "llsingleton.h" + +// ============================================================================ +// LLEmojiDescriptor class +// + +struct LLEmojiDescriptor +{ + LLEmojiDescriptor(const LLSD& descriptor_sd); + + bool isValid() const; + + std::string Name; + llwchar Character; + std::list ShortCodes; + std::list Categories; +}; + +// ============================================================================ +// LLEmojiDictionary class +// + +class LLEmojiDictionary : public LLParamSingleton, public LLInitClass +{ + LLSINGLETON(LLEmojiDictionary); + ~LLEmojiDictionary() override {}; + +public: + static void initClass(); + LLWString findMatchingEmojis(std::string needle); + std::string getNameFromEmoji(llwchar ch); + +private: + void addEmoji(LLEmojiDescriptor&& descr); + +private: + std::list mEmojis; + std::map mEmoji2Descr; +}; + +// ============================================================================ -- cgit v1.2.3 From dad25bcb1e17e3dc384a9fb35d21b669bc3bbacd Mon Sep 17 00:00:00 2001 From: Kitty Barnett Date: Sun, 23 Oct 2022 16:17:02 +0200 Subject: Add the emoji helper class which can be used by text-input controls to provide emoji picker support --- indra/llui/CMakeLists.txt | 2 + indra/llui/llemojihelper.cpp | 142 +++++++++++++++++++++++++++++++++++++++++++ indra/llui/llemojihelper.h | 64 +++++++++++++++++++ 3 files changed, 208 insertions(+) create mode 100644 indra/llui/llemojihelper.cpp create mode 100644 indra/llui/llemojihelper.h (limited to 'indra/llui') diff --git a/indra/llui/CMakeLists.txt b/indra/llui/CMakeLists.txt index 4e007e429a..68019734ab 100644 --- a/indra/llui/CMakeLists.txt +++ b/indra/llui/CMakeLists.txt @@ -54,6 +54,7 @@ set(llui_SOURCE_FILES lldraghandle.cpp lleditmenuhandler.cpp llemojidictionary.cpp + llemojihelper.cpp llf32uictrl.cpp llfiltereditor.cpp llflashtimer.cpp @@ -165,6 +166,7 @@ set(llui_HEADER_FILES lldockcontrol.h lleditmenuhandler.h llemojidictionary.h + llemojihelper.h llf32uictrl.h llfiltereditor.h llflashtimer.h diff --git a/indra/llui/llemojihelper.cpp b/indra/llui/llemojihelper.cpp new file mode 100644 index 0000000000..d4c31ee986 --- /dev/null +++ b/indra/llui/llemojihelper.cpp @@ -0,0 +1,142 @@ +/** +* @file llemojihelper.h +* @brief Header file for LLEmojiHelper +* +* $LicenseInfo:firstyear=2014&license=viewerlgpl$ +* Second Life Viewer Source Code +* Copyright (C) 2014, Linden Research, Inc. +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public +* License as published by the Free Software Foundation; +* version 2.1 of the License only. +* +* This library is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public +* License along with this library; if not, write to the Free Software +* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +* +* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA +* $/LicenseInfo$ +*/ + +#include "linden_common.h" + +#include "llemojidictionary.h" +#include "llemojihelper.h" +#include "llfloater.h" +#include "llfloaterreg.h" +#include "lluictrl.h" + +// ============================================================================ +// Constants +// + +constexpr char DEFAULT_EMOJI_HELPER_FLOATER[] = "emoji_complete"; +constexpr S32 HELPER_FLOATER_OFFSET_X = 20; +constexpr S32 HELPER_FLOATER_OFFSET_Y = 0; + +// ============================================================================ +// LLEmojiHelper +// + +std::string LLEmojiHelper::getToolTip(llwchar ch) const +{ + return LLEmojiDictionary::instance().getNameFromEmoji(ch); +} + +bool LLEmojiHelper::isActive(const LLUICtrl* ctrl_p) const +{ + return mHostHandle.get() == ctrl_p; +} + +// static +bool LLEmojiHelper::isCursorInEmojiCode(const LLWString& wtext, S32 cursorPos, S32* pShortCodePos) +{ + S32 shortCodePos = cursorPos; + + while (shortCodePos > 1 && + (LLStringOps::isAlnum(wtext[shortCodePos - 1]) || wtext[shortCodePos - 1] == L'-' || wtext[shortCodePos - 1] == L'_') ) + { + shortCodePos--; + } + + bool isShortCode = (L':' == wtext[shortCodePos - 1]) && (cursorPos - shortCodePos >= 2); + if (pShortCodePos) + *pShortCodePos = (isShortCode) ? shortCodePos - 1 : -1; + return isShortCode; +} + +void LLEmojiHelper::showHelper(LLUICtrl* hostctrl_p, S32 local_x, S32 local_y, const std::string& short_code, std::function cb) +{ + if (mHelperHandle.isDead()) + { + LLFloater* pHelperFloater = LLFloaterReg::getInstance(DEFAULT_EMOJI_HELPER_FLOATER); + mHelperHandle = pHelperFloater->getHandle(); + mHelperCommitConn = pHelperFloater->setCommitCallback(std::bind([&](const LLSD& sdValue) { onCommitEmoji(utf8str_to_wstring(sdValue.asStringRef())); }, std::placeholders::_2)); + } + setHostCtrl(hostctrl_p); + mEmojiCommitCb = cb; + + S32 floater_x, floater_y; + if (!hostctrl_p->localPointToOtherView(local_x, local_y, &floater_x, &floater_y, gFloaterView)) + { + LL_ERRS() << "Cannot show emoji helper for non-floater controls." << LL_ENDL; + return; + } + + LLFloater* pHelperFloater = mHelperHandle.get(); + LLRect rct = pHelperFloater->getRect(); + rct.setLeftTopAndSize(floater_x - HELPER_FLOATER_OFFSET_X, floater_y - HELPER_FLOATER_OFFSET_Y + rct.getHeight(), rct.getWidth(), rct.getHeight()); + pHelperFloater->setRect(rct); + pHelperFloater->openFloater(LLSD().with("hint", short_code)); +} + +void LLEmojiHelper::hideHelper(const LLUICtrl* ctrl_p) +{ + setHostCtrl(nullptr); +} + +bool LLEmojiHelper::handleKey(const LLUICtrl* ctrl_p, KEY key, MASK mask) +{ + if (mHelperHandle.isDead() || !isActive(ctrl_p)) + { + return false; + } + + return mHelperHandle.get()->handleKey(key, mask, true); +} + +void LLEmojiHelper::onCommitEmoji(const LLWString& wstr) +{ + if (!mHostHandle.isDead() && mEmojiCommitCb) + { + mEmojiCommitCb(wstr); + } +} + +void LLEmojiHelper::setHostCtrl(LLUICtrl* hostctrl_p) +{ + const LLUICtrl* pCurHostCtrl = mHostHandle.get(); + if (pCurHostCtrl != hostctrl_p) + { + mHostCtrlFocusLostConn.disconnect(); + mHostHandle.markDead(); + mEmojiCommitCb = {}; + + if (!mHelperHandle.isDead()) + { + mHelperHandle.get()->closeFloater(); + } + + if (hostctrl_p) + { + mHostHandle = hostctrl_p->getHandle(); + mHostCtrlFocusLostConn = hostctrl_p->setFocusLostCallback(std::bind([&]() { hideHelper(getHostCtrl()); })); + } + } +} diff --git a/indra/llui/llemojihelper.h b/indra/llui/llemojihelper.h new file mode 100644 index 0000000000..7ed042fc5f --- /dev/null +++ b/indra/llui/llemojihelper.h @@ -0,0 +1,64 @@ +/** +* @file llemojihelper.h +* @brief Header file for LLEmojiHelper +* +* $LicenseInfo:firstyear=2014&license=viewerlgpl$ +* Second Life Viewer Source Code +* Copyright (C) 2014, Linden Research, Inc. +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public +* License as published by the Free Software Foundation; +* version 2.1 of the License only. +* +* This library is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public +* License along with this library; if not, write to the Free Software +* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +* +* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA +* $/LicenseInfo$ +*/ + +#pragma once + +#include "llhandle.h" +#include "llsingleton.h" + +#include + +class LLFloater; +class LLUICtrl; + +class LLEmojiHelper : public LLSingleton +{ + LLSINGLETON(LLEmojiHelper) {} + ~LLEmojiHelper() override {} + +public: + // General + std::string getToolTip(llwchar ch) const; + bool isActive(const LLUICtrl* ctrl_p) const; + static bool isCursorInEmojiCode(const LLWString& wtext, S32 cursor_pos, S32* short_code_pos_p = nullptr); + void showHelper(LLUICtrl* hostctrl_p, S32 local_x, S32 local_y, const std::string& short_code, std::function commit_cb); + void hideHelper(const LLUICtrl* ctrl_p); + + // Eventing + bool handleKey(const LLUICtrl* ctrl_p, KEY key, MASK mask); + void onCommitEmoji(const LLWString& wstr); + +protected: + LLUICtrl* getHostCtrl() const { return mHostHandle.get(); } + void setHostCtrl(LLUICtrl* hostctrl_p); + +private: + LLHandle mHostHandle; + LLHandle mHelperHandle; + boost::signals2::connection mHostCtrlFocusLostConn; + boost::signals2::connection mHelperCommitConn; + std::function mEmojiCommitCb; +}; -- cgit v1.2.3 From 3acb4caa0fb9d381be6cfbe1693ace389d90a16c Mon Sep 17 00:00:00 2001 From: Kitty Barnett Date: Sun, 23 Oct 2022 16:18:22 +0200 Subject: Add emoji helper support to LLTextEditor --- indra/llui/lltexteditor.cpp | 21 ++++++++++++++++++--- indra/llui/lltexteditor.h | 2 ++ 2 files changed, 20 insertions(+), 3 deletions(-) (limited to 'indra/llui') diff --git a/indra/llui/lltexteditor.cpp b/indra/llui/lltexteditor.cpp index 889940cf9a..168c260c7d 100644 --- a/indra/llui/lltexteditor.cpp +++ b/indra/llui/lltexteditor.cpp @@ -676,6 +676,21 @@ void LLTextEditor::selectByCursorPosition(S32 prev_cursor_pos, S32 next_cursor_p endSelection(); } +void LLTextEditor::handleEmojiCommit(const LLWString& wstr) +{ + LLWString wtext(getWText()); S32 shortCodePos; + if (LLEmojiHelper::isCursorInEmojiCode(wtext, mCursorPos, &shortCodePos)) + { + remove(shortCodePos, mCursorPos - shortCodePos, true); + + auto styleParams = LLStyle::Params(); + styleParams.font = LLFontGL::getFontEmoji(); + insert(shortCodePos, wstr, false, new LLEmojiTextSegment(new LLStyle(styleParams), shortCodePos, shortCodePos + wstr.size(), *this)); + + setCursorPos(shortCodePos + 1); + } +} + BOOL LLTextEditor::handleMouseDown(S32 x, S32 y, MASK mask) { BOOL handled = FALSE; @@ -1147,9 +1162,9 @@ void LLTextEditor::addChar(llwchar wc) LLWString wtext(getWText()); S32 shortCodePos; if (LLEmojiHelper::isCursorInEmojiCode(wtext, mCursorPos, &shortCodePos)) { - const LLRect cursorRect = getLocalRectFromDocIndex(mCursorPos); - const LLWString shortCode = wtext.substr(shortCodePos, mCursorPos); - LLEmojiHelper::instance().showHelper(this, cursorRect.mLeft, cursorRect.mTop, wstring_to_utf8str(shortCode)); + const LLRect cursorRect = getLocalRectFromDocIndex(mCursorPos - 1); + const LLWString shortCode = wtext.substr(shortCodePos, mCursorPos - shortCodePos); + LLEmojiHelper::instance().showHelper(this, cursorRect.mLeft, cursorRect.mTop, wstring_to_utf8str(shortCode), std::bind(&LLTextEditor::handleEmojiCommit, this, std::placeholders::_1)); } } diff --git a/indra/llui/lltexteditor.h b/indra/llui/lltexteditor.h index 04910b6f68..4c8175a286 100644 --- a/indra/llui/lltexteditor.h +++ b/indra/llui/lltexteditor.h @@ -92,6 +92,8 @@ public: static S32 spacesPerTab(); + void handleEmojiCommit(const LLWString& wstr); + // mousehandler overrides virtual BOOL handleMouseDown(S32 x, S32 y, MASK mask); virtual BOOL handleMouseUp(S32 x, S32 y, MASK mask); -- cgit v1.2.3 From f6f52d327be5f03265d66a95df6fc0716f91ca07 Mon Sep 17 00:00:00 2001 From: Kitty Barnett Date: Sun, 23 Oct 2022 16:35:44 +0200 Subject: Provide a way for a floater to remain the topmost floater, even when focus is given to a different floater --- indra/llui/llfloater.cpp | 24 +++++++++++++++++++++++- indra/llui/llfloater.h | 4 ++++ 2 files changed, 27 insertions(+), 1 deletion(-) (limited to 'indra/llui') diff --git a/indra/llui/llfloater.cpp b/indra/llui/llfloater.cpp index 0e42922543..04f6b11b7c 100644 --- a/indra/llui/llfloater.cpp +++ b/indra/llui/llfloater.cpp @@ -3039,7 +3039,29 @@ void LLFloaterView::syncFloaterTabOrder() LLFloater* floaterp = dynamic_cast(*child_it); if (gFocusMgr.childHasKeyboardFocus(floaterp)) { - bringToFront(floaterp, FALSE); + if (mFrontChild != floaterp) + { + // Grab a list of the top floaters that want to stay on top of the focused floater + std::list listTop; + if (mFrontChild && !mFrontChild->canFocusStealFrontmost()) + { + for (LLView* childfloaterp : *getChildList()) + { + if (static_cast(childfloaterp)->canFocusStealFrontmost()) + break; + listTop.push_back(childfloaterp); + } + } + + bringToFront(floaterp, FALSE); + + // Restore top floaters + for (LLView* childp :listTop) + { + sendChildToFront(childp); + } + } + break; } } diff --git a/indra/llui/llfloater.h b/indra/llui/llfloater.h index 2672d600c6..1d4aff31eb 100644 --- a/indra/llui/llfloater.h +++ b/indra/llui/llfloater.h @@ -313,6 +313,9 @@ public: /*virtual*/ void setVisible(BOOL visible); // do not override /*virtual*/ void onVisibilityChange ( BOOL new_visibility ); // do not override + bool canFocusStealFrontmost() const { return mFocusStealsFrontmost; } + void setFocusStealsFrontmost(bool wants_frontmost) { mFocusStealsFrontmost = wants_frontmost; } + void setFrontmost(BOOL take_focus = TRUE, BOOL restore = TRUE); virtual void setVisibleAndFrontmost(BOOL take_focus=TRUE, const LLSD& key = LLSD()); @@ -478,6 +481,7 @@ private: BOOL mCanTearOff; BOOL mCanMinimize; BOOL mCanClose; + bool mFocusStealsFrontmost = true; // FALSE if we don't want the currently focused floater to cover this floater without user interaction BOOL mDragOnLeft; BOOL mResizable; -- 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 ++++++++++++++ indra/llui/lltextbase.h | 1 + 2 files changed, 15 insertions(+) (limited to 'indra/llui') 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 // diff --git a/indra/llui/lltextbase.h b/indra/llui/lltextbase.h index fc999c4cca..31e9f16110 100644 --- a/indra/llui/lltextbase.h +++ b/indra/llui/lltextbase.h @@ -187,6 +187,7 @@ public: LLEmojiTextSegment(const LLColor4& color, S32 start, S32 end, LLTextBase& editor, BOOL is_visible = TRUE); bool canEdit() const override { return false; } + BOOL handleToolTip(S32 x, S32 y, MASK mask); }; // Text segment that changes it's style depending of mouse pointer position ( is it inside or outside segment) -- cgit v1.2.3 From 58cdcd5dd23778c6fad9fa0da31b670ceff8eeeb Mon Sep 17 00:00:00 2001 From: Kitty Barnett Date: Sun, 23 Oct 2022 17:47:51 +0200 Subject: Handle return and escape in the mini emoji helper --- indra/llui/llemojihelper.cpp | 5 +++++ indra/llui/llemojihelper.h | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) (limited to 'indra/llui') diff --git a/indra/llui/llemojihelper.cpp b/indra/llui/llemojihelper.cpp index d4c31ee986..54c801ab7b 100644 --- a/indra/llui/llemojihelper.cpp +++ b/indra/llui/llemojihelper.cpp @@ -98,6 +98,11 @@ void LLEmojiHelper::showHelper(LLUICtrl* hostctrl_p, S32 local_x, S32 local_y, c void LLEmojiHelper::hideHelper(const LLUICtrl* ctrl_p) { + if (ctrl_p && !isActive(ctrl_p)) + { + return; + } + setHostCtrl(nullptr); } diff --git a/indra/llui/llemojihelper.h b/indra/llui/llemojihelper.h index 7ed042fc5f..63f5c640c9 100644 --- a/indra/llui/llemojihelper.h +++ b/indra/llui/llemojihelper.h @@ -45,7 +45,7 @@ public: bool isActive(const LLUICtrl* ctrl_p) const; static bool isCursorInEmojiCode(const LLWString& wtext, S32 cursor_pos, S32* short_code_pos_p = nullptr); void showHelper(LLUICtrl* hostctrl_p, S32 local_x, S32 local_y, const std::string& short_code, std::function commit_cb); - void hideHelper(const LLUICtrl* ctrl_p); + void hideHelper(const LLUICtrl* ctrl_p = nullptr); // Eventing bool handleKey(const LLUICtrl* ctrl_p, KEY key, MASK mask); -- cgit v1.2.3 From fb1553d8cf704eeb222de7ebd520a81fa242b317 Mon Sep 17 00:00:00 2001 From: Kitty Barnett Date: Sun, 23 Oct 2022 17:55:13 +0200 Subject: Cannot use the :+1 emoji shortcode --- indra/llui/llemojihelper.cpp | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) (limited to 'indra/llui') diff --git a/indra/llui/llemojihelper.cpp b/indra/llui/llemojihelper.cpp index 54c801ab7b..551f0331e7 100644 --- a/indra/llui/llemojihelper.cpp +++ b/indra/llui/llemojihelper.cpp @@ -59,8 +59,18 @@ bool LLEmojiHelper::isCursorInEmojiCode(const LLWString& wtext, S32 cursorPos, S { S32 shortCodePos = cursorPos; - while (shortCodePos > 1 && - (LLStringOps::isAlnum(wtext[shortCodePos - 1]) || wtext[shortCodePos - 1] == L'-' || wtext[shortCodePos - 1] == L'_') ) + auto isPartOfShortcode = [](llwchar ch) { + switch (ch) + { + case L'-': + case L'_': + case L'+': + return true; + default: + return LLStringOps::isAlnum(ch); + } + }; + while (shortCodePos > 1 && isPartOfShortcode(wtext[shortCodePos - 1])) { shortCodePos--; } -- cgit v1.2.3 From d1dbefc09b77990563d22aaf08d0c5708cc6cbbe Mon Sep 17 00:00:00 2001 From: Kitty Barnett Date: Sun, 23 Oct 2022 19:05:19 +0200 Subject: Refactor emoji matching --- indra/llui/llemojidictionary.cpp | 70 ++++++++++++++++++++++++---------------- indra/llui/llemojidictionary.h | 2 +- 2 files changed, 43 insertions(+), 29 deletions(-) (limited to 'indra/llui') diff --git a/indra/llui/llemojidictionary.cpp b/indra/llui/llemojidictionary.cpp index e149832a8b..eefa4047a2 100644 --- a/indra/llui/llemojidictionary.cpp +++ b/indra/llui/llemojidictionary.cpp @@ -31,6 +31,8 @@ #include "llsdserialize.h" #include +#include +#include // ============================================================================ // Constants @@ -89,6 +91,41 @@ bool LLEmojiDescriptor::isValid() const !Categories.empty(); } +struct emoji_filter_base +{ + emoji_filter_base(const std::string& needle) + { + // Search without the colon (if present) so the user can type ':food' and see all emojis in the 'Food' category + mNeedle = (boost::starts_with(needle, ":")) ? needle.substr(1) : needle; + LLStringUtil::toLower(mNeedle); + } + +protected: + std::string mNeedle; +}; + +struct emoji_filter_shortcode_or_category_contains : public emoji_filter_base +{ + emoji_filter_shortcode_or_category_contains(const std::string& needle) : emoji_filter_base(needle) {} + + bool operator()(const LLEmojiDescriptor& descr) const + { + for (const auto& short_code : descr.ShortCodes) + { + if (boost::icontains(short_code, mNeedle)) + return true; + } + + for (const auto& category : descr.Categories) + { + if (boost::icontains(category, mNeedle)) + return true; + } + + return false; + } +}; + // ============================================================================ // LLEmojiDictionary class // @@ -130,35 +167,12 @@ void LLEmojiDictionary::initClass() } } -LLWString LLEmojiDictionary::findMatchingEmojis(std::string needle) +LLWString LLEmojiDictionary::findMatchingEmojis(const std::string& needle) const { - // Search without the colon (if present) so the user can type ':food' and see all emojis in the 'Food' category - LLStringUtil::toLower(needle); - const auto kitty_needle = boost::make_iterator_range((boost::starts_with(needle, ":")) ? needle.begin() + 1 : needle.begin(), needle.end()); - - LLWString wstr; - for (const auto& descr : mEmojis) - { - for (const auto& short_code : descr.ShortCodes) - { - if (boost::icontains(short_code, kitty_needle)) - { - wstr.push_back(descr.Character); - continue; - } - } - - for (const auto& category : descr.Categories) - { - if (boost::icontains(category, kitty_needle)) - { - wstr.push_back(descr.Character); - continue; - } - } - } - - return wstr; + LLWString result; + boost::transform(mEmojis | boost::adaptors::filtered(emoji_filter_shortcode_or_category_contains(needle)), + std::back_inserter(result), [](const auto& descr) { return descr.Character; }); + return result; } std::string LLEmojiDictionary::getNameFromEmoji(llwchar ch) diff --git a/indra/llui/llemojidictionary.h b/indra/llui/llemojidictionary.h index 87ea4a5aef..3fa55cd417 100644 --- a/indra/llui/llemojidictionary.h +++ b/indra/llui/llemojidictionary.h @@ -57,7 +57,7 @@ class LLEmojiDictionary : public LLParamSingleton, public LLI public: static void initClass(); - LLWString findMatchingEmojis(std::string needle); + LLWString findMatchingEmojis(const std::string& needle) const; std::string getNameFromEmoji(llwchar ch); private: -- 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/llemojidictionary.cpp | 17 +++++++++++++---- indra/llui/llemojidictionary.h | 6 ++++-- indra/llui/llemojihelper.cpp | 8 ++++++++ indra/llui/lltextbase.cpp | 1 + 4 files changed, 26 insertions(+), 6 deletions(-) (limited to 'indra/llui') diff --git a/indra/llui/llemojidictionary.cpp b/indra/llui/llemojidictionary.cpp index eefa4047a2..c31638b0bf 100644 --- a/indra/llui/llemojidictionary.cpp +++ b/indra/llui/llemojidictionary.cpp @@ -175,17 +175,26 @@ LLWString LLEmojiDictionary::findMatchingEmojis(const std::string& needle) const return result; } -std::string LLEmojiDictionary::getNameFromEmoji(llwchar ch) +const LLEmojiDescriptor* LLEmojiDictionary::getDescriptorFromShortCode(const std::string& short_code) const +{ + const auto it = mShortCode2Descr.find(short_code); + return (mShortCode2Descr.end() != it) ? &it->second : nullptr; +} + +std::string LLEmojiDictionary::getNameFromEmoji(llwchar ch) const { const auto it = mEmoji2Descr.find(ch); - return (mEmoji2Descr.end() != it) ? it->second->Name : LLStringUtil::null; + return (mEmoji2Descr.end() != it) ? it->second.Name : LLStringUtil::null; } void LLEmojiDictionary::addEmoji(LLEmojiDescriptor&& descr) { mEmojis.push_back(descr); - const LLEmojiDescriptor& back = mEmojis.back(); - mEmoji2Descr.insert(std::make_pair(descr.Character, &back)); + mEmoji2Descr.insert(std::make_pair(descr.Character, mEmojis.back())); + for (const std::string& shortCode : descr.ShortCodes) + { + mShortCode2Descr.insert(std::make_pair(shortCode, mEmojis.back())); + } } // ============================================================================ diff --git a/indra/llui/llemojidictionary.h b/indra/llui/llemojidictionary.h index 3fa55cd417..0cde663719 100644 --- a/indra/llui/llemojidictionary.h +++ b/indra/llui/llemojidictionary.h @@ -58,14 +58,16 @@ class LLEmojiDictionary : public LLParamSingleton, public LLI public: static void initClass(); LLWString findMatchingEmojis(const std::string& needle) const; - std::string getNameFromEmoji(llwchar ch); + const LLEmojiDescriptor* getDescriptorFromShortCode(const std::string& short_code) const; + std::string getNameFromEmoji(llwchar ch) const; private: void addEmoji(LLEmojiDescriptor&& descr); private: std::list mEmojis; - std::map mEmoji2Descr; + std::map mEmoji2Descr; + std::map mShortCode2Descr; }; // ============================================================================ diff --git a/indra/llui/llemojihelper.cpp b/indra/llui/llemojihelper.cpp index 551f0331e7..32471e59a8 100644 --- a/indra/llui/llemojihelper.cpp +++ b/indra/llui/llemojihelper.cpp @@ -83,6 +83,14 @@ bool LLEmojiHelper::isCursorInEmojiCode(const LLWString& wtext, S32 cursorPos, S void LLEmojiHelper::showHelper(LLUICtrl* hostctrl_p, S32 local_x, S32 local_y, const std::string& short_code, std::function cb) { + // Commit immediately if the user already typed a full shortcode + if (const auto* emojiDescrp = LLEmojiDictionary::instance().getDescriptorFromShortCode(short_code)) + { + cb(LLWString(1, emojiDescrp->Character)); + hideHelper(); + return; + } + if (mHelperHandle.isDead()) { LLFloater* pHelperFloater = LLFloaterReg::getInstance(DEFAULT_EMOJI_HELPER_FLOATER); 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 81dd143d0d901e8e5234cff01fbda246e4621628 Mon Sep 17 00:00:00 2001 From: Kitty Barnett Date: Tue, 8 Nov 2022 00:16:58 +0100 Subject: [FIXED] Various minor issues - Typing :+1: doesn't replace the short code with the thumbs-up emoji - Moving the mouse over the emoji complete panel highlights the wrong emoji when mScrollPos > 0 - Emoji complete panel is missing attributes - Crash when attempting to show the tooltip for an emoji text segment - Emoji autocomplete panel can sometimes show empty (type ':cat', select the heart eyed one, Ctrl-Z and then type 2 which should show the emoji for :cat2 but shows an empty square instead) --- indra/llui/llemojidictionary.cpp | 8 ++++---- indra/llui/llemojidictionary.h | 4 ++-- indra/llui/llemojihelper.cpp | 3 ++- 3 files changed, 8 insertions(+), 7 deletions(-) (limited to 'indra/llui') diff --git a/indra/llui/llemojidictionary.cpp b/indra/llui/llemojidictionary.cpp index c31638b0bf..b70a9b2e7a 100644 --- a/indra/llui/llemojidictionary.cpp +++ b/indra/llui/llemojidictionary.cpp @@ -178,22 +178,22 @@ LLWString LLEmojiDictionary::findMatchingEmojis(const std::string& needle) const const LLEmojiDescriptor* LLEmojiDictionary::getDescriptorFromShortCode(const std::string& short_code) const { const auto it = mShortCode2Descr.find(short_code); - return (mShortCode2Descr.end() != it) ? &it->second : nullptr; + return (mShortCode2Descr.end() != it) ? it->second : nullptr; } std::string LLEmojiDictionary::getNameFromEmoji(llwchar ch) const { const auto it = mEmoji2Descr.find(ch); - return (mEmoji2Descr.end() != it) ? it->second.Name : LLStringUtil::null; + return (mEmoji2Descr.end() != it) ? it->second->Name : LLStringUtil::null; } void LLEmojiDictionary::addEmoji(LLEmojiDescriptor&& descr) { mEmojis.push_back(descr); - mEmoji2Descr.insert(std::make_pair(descr.Character, mEmojis.back())); + mEmoji2Descr.insert(std::make_pair(descr.Character, &mEmojis.back())); for (const std::string& shortCode : descr.ShortCodes) { - mShortCode2Descr.insert(std::make_pair(shortCode, mEmojis.back())); + mShortCode2Descr.insert(std::make_pair(shortCode, &mEmojis.back())); } } diff --git a/indra/llui/llemojidictionary.h b/indra/llui/llemojidictionary.h index 0cde663719..46a61f1cd7 100644 --- a/indra/llui/llemojidictionary.h +++ b/indra/llui/llemojidictionary.h @@ -66,8 +66,8 @@ private: private: std::list mEmojis; - std::map mEmoji2Descr; - std::map mShortCode2Descr; + std::map mEmoji2Descr; + std::map mShortCode2Descr; }; // ============================================================================ diff --git a/indra/llui/llemojihelper.cpp b/indra/llui/llemojihelper.cpp index 32471e59a8..1e4c19a183 100644 --- a/indra/llui/llemojihelper.cpp +++ b/indra/llui/llemojihelper.cpp @@ -57,7 +57,8 @@ bool LLEmojiHelper::isActive(const LLUICtrl* ctrl_p) const // static bool LLEmojiHelper::isCursorInEmojiCode(const LLWString& wtext, S32 cursorPos, S32* pShortCodePos) { - S32 shortCodePos = cursorPos; + // If the cursor is currently on a colon start the check one character further back + S32 shortCodePos = (cursorPos == 0 || L':' != wtext[cursorPos - 1]) ? cursorPos : cursorPos - 1; auto isPartOfShortcode = [](llwchar ch) { switch (ch) -- cgit v1.2.3 From 17a3924a28770e6910022ad8f627bb8e2b667730 Mon Sep 17 00:00:00 2001 From: Kitty Barnett Date: Tue, 8 Nov 2022 01:10:09 +0100 Subject: Add proper mouse down handler to the emoji complete panel -> the previous commit didn't properly set mFrontChild after restoring the topmost floaters -> additionally we don't want mouse clicks in "can't steal focus from frontmost" floaters to set focus to them --- indra/llui/llfloater.cpp | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) (limited to 'indra/llui') diff --git a/indra/llui/llfloater.cpp b/indra/llui/llfloater.cpp index 04f6b11b7c..6f341bc0cd 100644 --- a/indra/llui/llfloater.cpp +++ b/indra/llui/llfloater.cpp @@ -2486,7 +2486,7 @@ void LLFloaterView::bringToFront(LLFloater* child, BOOL give_focus, BOOL restore if (mFrontChild == child) { - if (give_focus && !gFocusMgr.childHasKeyboardFocus(child)) + if (give_focus && child->canFocusStealFrontmost() && !gFocusMgr.childHasKeyboardFocus(child)) { child->setFocus(TRUE); } @@ -3042,24 +3042,29 @@ void LLFloaterView::syncFloaterTabOrder() if (mFrontChild != floaterp) { // Grab a list of the top floaters that want to stay on top of the focused floater - std::list listTop; + std::list listTop; if (mFrontChild && !mFrontChild->canFocusStealFrontmost()) { - for (LLView* childfloaterp : *getChildList()) + for (LLView* childp : *getChildList()) { - if (static_cast(childfloaterp)->canFocusStealFrontmost()) + LLFloater* child_floaterp = static_cast(childp); + if (child_floaterp->canFocusStealFrontmost()) break; - listTop.push_back(childfloaterp); + listTop.push_back(child_floaterp); } } bringToFront(floaterp, FALSE); // Restore top floaters - for (LLView* childp :listTop) - { - sendChildToFront(childp); - } + if (!listTop.empty()) + { + for (LLView* childp : listTop) + { + sendChildToFront(childp); + } + mFrontChild = listTop.back(); + } } break; -- 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 +++++++++++++++++++---------------------------- indra/llui/lltextbase.h | 1 - 2 files changed, 22 insertions(+), 34 deletions(-) (limited to 'indra/llui') 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); diff --git a/indra/llui/lltextbase.h b/indra/llui/lltextbase.h index 31e9f16110..a047db25b2 100644 --- a/indra/llui/lltextbase.h +++ b/indra/llui/lltextbase.h @@ -641,7 +641,6 @@ protected: void appendTextImpl(const std::string &new_text, const LLStyle::Params& input_params = LLStyle::Params()); void appendAndHighlightTextImpl(const std::string &new_text, S32 highlight_part, const LLStyle::Params& style_params, bool underline_on_hover_only = false); - void createTextWithEmojiSegment(const LLWString& wide_text, S32 segment_start, LLStyleConstSP style, segment_vec_t& segments); S32 normalizeUri(std::string& uri); protected: -- cgit v1.2.3 From 3185bdea27b19e155c2ccc03c80624e113d312a6 Mon Sep 17 00:00:00 2001 From: Callum Prentice Date: Thu, 26 Jan 2023 14:45:45 -0800 Subject: DRTVWR-489-emoji: As part of the work to get macOS version of the Viewer working, the flag was introduced to warn (and therefore error out) when a virtual override was not marked with the 'override' keyword. Fixing this up involved a large number of changes and this commit represents just those changes - nothing specially from the DRTVWR-489 viewer --- indra/llui/llnotifications.h | 6 +++--- indra/llui/llspellcheck.h | 2 +- indra/llui/lltextbase.cpp | 21 --------------------- indra/llui/lltextbase.h | 2 +- indra/llui/lluictrl.h | 2 +- indra/llui/llview.cpp | 4 ++-- indra/llui/llviewquery.h | 12 ++++++------ 7 files changed, 14 insertions(+), 35 deletions(-) (limited to 'indra/llui') diff --git a/indra/llui/llnotifications.h b/indra/llui/llnotifications.h index 921398a693..4d9a33f1d7 100644 --- a/indra/llui/llnotifications.h +++ b/indra/llui/llnotifications.h @@ -913,7 +913,7 @@ public: /* virtual */ LLNotificationPtr add(const std::string& name, const LLSD& substitutions, const LLSD& payload, - LLNotificationFunctorRegistry::ResponseFunctor functor); + LLNotificationFunctorRegistry::ResponseFunctor functor) override; LLNotificationPtr add(const LLNotification::Params& p); void add(const LLNotificationPtr pNotif); @@ -964,8 +964,8 @@ public: bool isVisibleByRules(LLNotificationPtr pNotification); private: - /*virtual*/ void initSingleton(); - /*virtual*/ void cleanupSingleton(); + /*virtual*/ void initSingleton() override; + /*virtual*/ void cleanupSingleton() override; void loadPersistentNotifications(); diff --git a/indra/llui/llspellcheck.h b/indra/llui/llspellcheck.h index 3da5e30955..14f9b44fe4 100644 --- a/indra/llui/llspellcheck.h +++ b/indra/llui/llspellcheck.h @@ -47,7 +47,7 @@ public: protected: void addToDictFile(const std::string& dict_path, const std::string& word); void initHunspell(const std::string& dict_language); - void initSingleton(); + void initSingleton() override; public: typedef std::list dict_list_t; diff --git a/indra/llui/lltextbase.cpp b/indra/llui/lltextbase.cpp index b2c0577604..dff4bf9617 100644 --- a/indra/llui/lltextbase.cpp +++ b/indra/llui/lltextbase.cpp @@ -1997,19 +1997,8 @@ LLTextBase::segment_set_t::const_iterator LLTextBase::getEditableSegIterContaini LLTextBase::segment_set_t::iterator LLTextBase::getSegIterContaining(S32 index) { - static LLPointer index_segment = new LLIndexSegment(); - S32 text_len = 0; - if (!useLabel()) - { - text_len = getLength(); - } - else - { - text_len = mLabel.getWString().length(); - } - // when there are no segments, we return the end iterator, which must be checked by caller if (mSegments.size() <= 1) { return mSegments.begin(); } @@ -2023,16 +2012,6 @@ LLTextBase::segment_set_t::const_iterator LLTextBase::getSegIterContaining(S32 i { static LLPointer index_segment = new LLIndexSegment(); - S32 text_len = 0; - if (!useLabel()) - { - text_len = getLength(); - } - else - { - text_len = mLabel.getWString().length(); - } - // when there are no segments, we return the end iterator, which must be checked by caller if (mSegments.size() <= 1) { return mSegments.begin(); } diff --git a/indra/llui/lltextbase.h b/indra/llui/lltextbase.h index 7e1f727607..9b3691e404 100644 --- a/indra/llui/lltextbase.h +++ b/indra/llui/lltextbase.h @@ -187,7 +187,7 @@ public: LLEmojiTextSegment(const LLColor4& color, S32 start, S32 end, LLTextBase& editor, BOOL is_visible = TRUE); bool canEdit() const override { return false; } - BOOL handleToolTip(S32 x, S32 y, MASK mask); + BOOL handleToolTip(S32 x, S32 y, MASK mask) override; }; // Text segment that changes it's style depending of mouse pointer position ( is it inside or outside segment) diff --git a/indra/llui/lluictrl.h b/indra/llui/lluictrl.h index 67dd24341c..d71dc8d859 100644 --- a/indra/llui/lluictrl.h +++ b/indra/llui/lluictrl.h @@ -263,7 +263,7 @@ public: class LLTextInputFilter : public LLQueryFilter, public LLSingleton { LLSINGLETON_EMPTY_CTOR(LLTextInputFilter); - /*virtual*/ filterResult_t operator() (const LLView* const view, const viewList_t & children) const + /*virtual*/ filterResult_t operator() (const LLView* const view, const viewList_t & children) const override { return filterResult_t(view->isCtrl() && static_cast(view)->acceptsTextInput(), TRUE); } diff --git a/indra/llui/llview.cpp b/indra/llui/llview.cpp index 74abe54690..2b7f05dcda 100644 --- a/indra/llui/llview.cpp +++ b/indra/llui/llview.cpp @@ -1953,7 +1953,7 @@ private: class SortByTabOrder : public LLQuerySorter, public LLSingleton { LLSINGLETON_EMPTY_CTOR(SortByTabOrder); - /*virtual*/ void sort(LLView * parent, LLView::child_list_t &children) const + /*virtual*/ void sort(LLView * parent, LLView::child_list_t &children) const override { children.sort(CompareByTabOrder(parent->getTabOrder(), parent->getDefaultTabGroup())); } @@ -1977,7 +1977,7 @@ const LLViewQuery & LLView::getTabOrderQuery() class LLFocusRootsFilter : public LLQueryFilter, public LLSingleton { LLSINGLETON_EMPTY_CTOR(LLFocusRootsFilter); - /*virtual*/ filterResult_t operator() (const LLView* const view, const viewList_t & children) const + /*virtual*/ filterResult_t operator() (const LLView* const view, const viewList_t & children) const override { return filterResult_t(view->isCtrl() && view->isFocusRoot(), !view->isFocusRoot()); } diff --git a/indra/llui/llviewquery.h b/indra/llui/llviewquery.h index 21bb1be26f..4bc9c4a08e 100644 --- a/indra/llui/llviewquery.h +++ b/indra/llui/llviewquery.h @@ -55,37 +55,37 @@ public: class LLLeavesFilter : public LLQueryFilter, public LLSingleton { LLSINGLETON_EMPTY_CTOR(LLLeavesFilter); - /*virtual*/ filterResult_t operator() (const LLView* const view, const viewList_t & children) const; + /*virtual*/ filterResult_t operator() (const LLView* const view, const viewList_t & children) const override; }; class LLRootsFilter : public LLQueryFilter, public LLSingleton { LLSINGLETON_EMPTY_CTOR(LLRootsFilter); - /*virtual*/ filterResult_t operator() (const LLView* const view, const viewList_t & children) const; + /*virtual*/ filterResult_t operator() (const LLView* const view, const viewList_t & children) const override; }; class LLVisibleFilter : public LLQueryFilter, public LLSingleton { LLSINGLETON_EMPTY_CTOR(LLVisibleFilter); - /*virtual*/ filterResult_t operator() (const LLView* const view, const viewList_t & children) const; + /*virtual*/ filterResult_t operator() (const LLView* const view, const viewList_t & children) const override; }; class LLEnabledFilter : public LLQueryFilter, public LLSingleton { LLSINGLETON_EMPTY_CTOR(LLEnabledFilter); - /*virtual*/ filterResult_t operator() (const LLView* const view, const viewList_t & children) const; + /*virtual*/ filterResult_t operator() (const LLView* const view, const viewList_t & children) const override; }; class LLTabStopFilter : public LLQueryFilter, public LLSingleton { LLSINGLETON_EMPTY_CTOR(LLTabStopFilter); - /*virtual*/ filterResult_t operator() (const LLView* const view, const viewList_t & children) const; + /*virtual*/ filterResult_t operator() (const LLView* const view, const viewList_t & children) const override; }; class LLCtrlFilter : public LLQueryFilter, public LLSingleton { LLSINGLETON_EMPTY_CTOR(LLCtrlFilter); - /*virtual*/ filterResult_t operator() (const LLView* const view, const viewList_t & children) const; + /*virtual*/ filterResult_t operator() (const LLView* const view, const viewList_t & children) const override; }; template -- cgit v1.2.3 From a804b98e4ed127ce1a11f639babb82574f2e5204 Mon Sep 17 00:00:00 2001 From: Callum Prentice Date: Thu, 26 Jan 2023 17:03:58 -0800 Subject: DRTVWR-489-emoji: A couple of tabs slipped into this file and our new no-tabs coding policy caught it and failed the build --- indra/llui/CMakeLists.txt | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'indra/llui') diff --git a/indra/llui/CMakeLists.txt b/indra/llui/CMakeLists.txt index 44c61dcdbc..4fc3836248 100644 --- a/indra/llui/CMakeLists.txt +++ b/indra/llui/CMakeLists.txt @@ -53,8 +53,8 @@ set(llui_SOURCE_FILES lldockcontrol.cpp lldraghandle.cpp lleditmenuhandler.cpp - llemojidictionary.cpp - llemojihelper.cpp + llemojidictionary.cpp + llemojihelper.cpp llf32uictrl.cpp llfiltereditor.cpp llflashtimer.cpp @@ -165,8 +165,8 @@ set(llui_HEADER_FILES lldockablefloater.h lldockcontrol.h lleditmenuhandler.h - llemojidictionary.h - llemojihelper.h + llemojidictionary.h + llemojihelper.h llf32uictrl.h llfiltereditor.h llflashtimer.h -- cgit v1.2.3 From ff7ebf08922293c1623b7bdb8c9923c14fc9db48 Mon Sep 17 00:00:00 2001 From: Alexander Gavriliuk Date: Fri, 14 Apr 2023 07:44:56 +0200 Subject: SL-19575 Create emoji gallery access icon --- indra/llui/llemojidictionary.h | 2 ++ indra/llui/llemojihelper.cpp | 10 +++++----- indra/llui/llemojihelper.h | 6 +++--- indra/llui/llscrolllistctrl.cpp | 2 +- indra/llui/lltexteditor.cpp | 22 ++++++++++++++-------- indra/llui/lltexteditor.h | 3 ++- 6 files changed, 27 insertions(+), 18 deletions(-) (limited to 'indra/llui') diff --git a/indra/llui/llemojidictionary.h b/indra/llui/llemojidictionary.h index 46a61f1cd7..adc22ced58 100644 --- a/indra/llui/llemojidictionary.h +++ b/indra/llui/llemojidictionary.h @@ -61,6 +61,8 @@ public: const LLEmojiDescriptor* getDescriptorFromShortCode(const std::string& short_code) const; std::string getNameFromEmoji(llwchar ch) const; + const std::map& getEmoji2Descr() const { return mEmoji2Descr; } + private: void addEmoji(LLEmojiDescriptor&& descr); diff --git a/indra/llui/llemojihelper.cpp b/indra/llui/llemojihelper.cpp index 1e4c19a183..fb660a9e5b 100644 --- a/indra/llui/llemojihelper.cpp +++ b/indra/llui/llemojihelper.cpp @@ -82,12 +82,12 @@ bool LLEmojiHelper::isCursorInEmojiCode(const LLWString& wtext, S32 cursorPos, S return isShortCode; } -void LLEmojiHelper::showHelper(LLUICtrl* hostctrl_p, S32 local_x, S32 local_y, const std::string& short_code, std::function cb) +void LLEmojiHelper::showHelper(LLUICtrl* hostctrl_p, S32 local_x, S32 local_y, const std::string& short_code, std::function cb) { // Commit immediately if the user already typed a full shortcode if (const auto* emojiDescrp = LLEmojiDictionary::instance().getDescriptorFromShortCode(short_code)) { - cb(LLWString(1, emojiDescrp->Character)); + cb(emojiDescrp->Character); hideHelper(); return; } @@ -96,7 +96,7 @@ void LLEmojiHelper::showHelper(LLUICtrl* hostctrl_p, S32 local_x, S32 local_y, c { LLFloater* pHelperFloater = LLFloaterReg::getInstance(DEFAULT_EMOJI_HELPER_FLOATER); mHelperHandle = pHelperFloater->getHandle(); - mHelperCommitConn = pHelperFloater->setCommitCallback(std::bind([&](const LLSD& sdValue) { onCommitEmoji(utf8str_to_wstring(sdValue.asStringRef())); }, std::placeholders::_2)); + mHelperCommitConn = pHelperFloater->setCommitCallback(std::bind([&](const LLSD& sdValue) { onCommitEmoji(utf8str_to_wstring(sdValue.asStringRef())[0]); }, std::placeholders::_2)); } setHostCtrl(hostctrl_p); mEmojiCommitCb = cb; @@ -135,11 +135,11 @@ bool LLEmojiHelper::handleKey(const LLUICtrl* ctrl_p, KEY key, MASK mask) return mHelperHandle.get()->handleKey(key, mask, true); } -void LLEmojiHelper::onCommitEmoji(const LLWString& wstr) +void LLEmojiHelper::onCommitEmoji(llwchar emoji) { if (!mHostHandle.isDead() && mEmojiCommitCb) { - mEmojiCommitCb(wstr); + mEmojiCommitCb(emoji); } } diff --git a/indra/llui/llemojihelper.h b/indra/llui/llemojihelper.h index 63f5c640c9..58f68d12a4 100644 --- a/indra/llui/llemojihelper.h +++ b/indra/llui/llemojihelper.h @@ -44,12 +44,12 @@ public: std::string getToolTip(llwchar ch) const; bool isActive(const LLUICtrl* ctrl_p) const; static bool isCursorInEmojiCode(const LLWString& wtext, S32 cursor_pos, S32* short_code_pos_p = nullptr); - void showHelper(LLUICtrl* hostctrl_p, S32 local_x, S32 local_y, const std::string& short_code, std::function commit_cb); + void showHelper(LLUICtrl* hostctrl_p, S32 local_x, S32 local_y, const std::string& short_code, std::function commit_cb); void hideHelper(const LLUICtrl* ctrl_p = nullptr); // Eventing bool handleKey(const LLUICtrl* ctrl_p, KEY key, MASK mask); - void onCommitEmoji(const LLWString& wstr); + void onCommitEmoji(llwchar emoji); protected: LLUICtrl* getHostCtrl() const { return mHostHandle.get(); } @@ -60,5 +60,5 @@ private: LLHandle mHelperHandle; boost::signals2::connection mHostCtrlFocusLostConn; boost::signals2::connection mHelperCommitConn; - std::function mEmojiCommitCb; + std::function mEmojiCommitCb; }; diff --git a/indra/llui/llscrolllistctrl.cpp b/indra/llui/llscrolllistctrl.cpp index 219667f766..2a6e8a6b76 100644 --- a/indra/llui/llscrolllistctrl.cpp +++ b/indra/llui/llscrolllistctrl.cpp @@ -411,7 +411,7 @@ void LLScrollListCtrl::clearRows() LLScrollListItem* LLScrollListCtrl::getFirstSelected() const { item_list::const_iterator iter; - for(iter = mItemList.begin(); iter != mItemList.end(); iter++) + for (iter = mItemList.begin(); iter != mItemList.end(); iter++) { LLScrollListItem* item = *iter; if (item->getSelected()) diff --git a/indra/llui/lltexteditor.cpp b/indra/llui/lltexteditor.cpp index a85ac2a5a3..95d8b666ab 100644 --- a/indra/llui/lltexteditor.cpp +++ b/indra/llui/lltexteditor.cpp @@ -680,18 +680,24 @@ void LLTextEditor::selectByCursorPosition(S32 prev_cursor_pos, S32 next_cursor_p endSelection(); } -void LLTextEditor::handleEmojiCommit(const LLWString& wstr) +void LLTextEditor::insertEmoji(llwchar emoji) { - LLWString wtext(getWText()); S32 shortCodePos; - if (LLEmojiHelper::isCursorInEmojiCode(wtext, mCursorPos, &shortCodePos)) + auto styleParams = LLStyle::Params(); + styleParams.font = LLFontGL::getFontEmoji(); + auto segment = new LLEmojiTextSegment(new LLStyle(styleParams), mCursorPos, mCursorPos + 1, *this); + insert(mCursorPos, LLWString(1, emoji), false, segment); + setCursorPos(mCursorPos + 1); +} + +void LLTextEditor::handleEmojiCommit(llwchar emoji) +{ + S32 shortCodePos; + if (LLEmojiHelper::isCursorInEmojiCode(getWText(), mCursorPos, &shortCodePos)) { remove(shortCodePos, mCursorPos - shortCodePos, true); + setCursorPos(shortCodePos); - auto styleParams = LLStyle::Params(); - styleParams.font = LLFontGL::getFontEmoji(); - insert(shortCodePos, wstr, false, new LLEmojiTextSegment(new LLStyle(styleParams), shortCodePos, shortCodePos + wstr.size(), *this)); - - setCursorPos(shortCodePos + 1); + insertEmoji(emoji); } } diff --git a/indra/llui/lltexteditor.h b/indra/llui/lltexteditor.h index dabd0460c6..f830732cb8 100644 --- a/indra/llui/lltexteditor.h +++ b/indra/llui/lltexteditor.h @@ -92,7 +92,8 @@ public: static S32 spacesPerTab(); - void handleEmojiCommit(const LLWString& wstr); + void insertEmoji(llwchar emoji); + void handleEmojiCommit(llwchar emoji); // mousehandler overrides virtual BOOL handleMouseDown(S32 x, S32 y, MASK mask); -- cgit v1.2.3 From 97b0ba2a6d2596da867043077e32065653d44f6e Mon Sep 17 00:00:00 2001 From: Alexander Gavriliuk Date: Wed, 19 Apr 2023 01:39:42 +0200 Subject: SL-19575 LLFloaterEmojiPicker - Add filter by category --- indra/llui/llbutton.cpp | 23 ++++++++++++++--------- indra/llui/llbutton.h | 5 +++++ indra/llui/llemojidictionary.cpp | 10 ++++++++++ indra/llui/llemojidictionary.h | 14 +++++++++++--- indra/llui/llfloater.cpp | 18 ++++++++++++++---- indra/llui/llfloater.h | 4 ++-- indra/llui/llscrolllistctrl.cpp | 4 ++-- indra/llui/llscrolllistctrl.h | 30 +++++++++++++++--------------- 8 files changed, 73 insertions(+), 35 deletions(-) (limited to 'indra/llui') diff --git a/indra/llui/llbutton.cpp b/indra/llui/llbutton.cpp index 3354cb2db3..aeeff0b36f 100644 --- a/indra/llui/llbutton.cpp +++ b/indra/llui/llbutton.cpp @@ -68,6 +68,7 @@ LLButton::Params::Params() label_shadow("label_shadow", true), auto_resize("auto_resize", false), use_ellipses("use_ellipses", false), + use_font_color("use_font_color", false), image_unselected("image_unselected"), image_selected("image_selected"), image_hover_selected("image_hover_selected"), @@ -160,6 +161,7 @@ LLButton::LLButton(const LLButton::Params& p) mDropShadowedText(p.label_shadow), mAutoResize(p.auto_resize), mUseEllipses( p.use_ellipses ), + mUseFontColor( p.use_font_color), mHAlign(p.font_halign), mLeftHPad(p.pad_left), mRightHPad(p.pad_right), @@ -960,7 +962,7 @@ void LLButton::draw() LLFontGL::NORMAL, mDropShadowedText ? LLFontGL::DROP_SHADOW_SOFT : LLFontGL::NO_SHADOW, S32_MAX, text_width, - NULL, mUseEllipses); + NULL, mUseEllipses, mUseFontColor); } LLUICtrl::draw(); @@ -1020,6 +1022,16 @@ BOOL LLButton::toggleState() return flipped; } +void LLButton::setLabel( const std::string& label ) +{ + mUnselectedLabel = mSelectedLabel = label; +} + +void LLButton::setLabel( const LLUIString& label ) +{ + mUnselectedLabel = mSelectedLabel = label; +} + void LLButton::setLabel( const LLStringExplicit& label ) { setLabelUnselected(label); @@ -1051,14 +1063,7 @@ bool LLButton::labelIsTruncated() const const LLUIString& LLButton::getCurrentLabel() const { - if( getToggleState() ) - { - return mSelectedLabel; - } - else - { - return mUnselectedLabel; - } + return getToggleState() ? mSelectedLabel : mUnselectedLabel; } void LLButton::setImageUnselected(LLPointer image) diff --git a/indra/llui/llbutton.h b/indra/llui/llbutton.h index ccd31e90c0..257159f64f 100644 --- a/indra/llui/llbutton.h +++ b/indra/llui/llbutton.h @@ -73,6 +73,7 @@ public: Optional label_shadow; Optional auto_resize; Optional use_ellipses; + Optional use_font_color; // images Optional image_unselected, @@ -174,6 +175,7 @@ public: void setUnselectedLabelColor( const LLColor4& c ) { mUnselectedLabelColor = c; } void setSelectedLabelColor( const LLColor4& c ) { mSelectedLabelColor = c; } void setUseEllipses( BOOL use_ellipses ) { mUseEllipses = use_ellipses; } + void setUseFontColor( BOOL use_font_color) { mUseFontColor = use_font_color; } boost::signals2::connection setClickedCallback(const CommitCallbackParam& cb); @@ -238,6 +240,8 @@ public: void autoResize(); // resize with label of current btn state void resize(LLUIString label); // resize with label input + void setLabel(const std::string& label); + void setLabel(const LLUIString& label); void setLabel( const LLStringExplicit& label); virtual BOOL setLabelArg( const std::string& key, const LLStringExplicit& text ); void setLabelUnselected(const LLStringExplicit& label); @@ -353,6 +357,7 @@ protected: bool mDropShadowedText; bool mAutoResize; bool mUseEllipses; + bool mUseFontColor; bool mBorderEnabled; bool mFlashing; diff --git a/indra/llui/llemojidictionary.cpp b/indra/llui/llemojidictionary.cpp index b70a9b2e7a..d306407484 100644 --- a/indra/llui/llemojidictionary.cpp +++ b/indra/llui/llemojidictionary.cpp @@ -175,6 +175,12 @@ LLWString LLEmojiDictionary::findMatchingEmojis(const std::string& needle) const return result; } +const LLEmojiDescriptor* LLEmojiDictionary::getDescriptorFromEmoji(llwchar emoji) const +{ + const auto it = mEmoji2Descr.find(emoji); + return (mEmoji2Descr.end() != it) ? it->second : nullptr; +} + const LLEmojiDescriptor* LLEmojiDictionary::getDescriptorFromShortCode(const std::string& short_code) const { const auto it = mShortCode2Descr.find(short_code); @@ -195,6 +201,10 @@ void LLEmojiDictionary::addEmoji(LLEmojiDescriptor&& descr) { mShortCode2Descr.insert(std::make_pair(shortCode, &mEmojis.back())); } + for (const std::string& category : descr.Categories) + { + mCategory2Descrs[category].push_back(&mEmojis.back()); + } } // ============================================================================ diff --git a/indra/llui/llemojidictionary.h b/indra/llui/llemojidictionary.h index adc22ced58..cbb0ac577d 100644 --- a/indra/llui/llemojidictionary.h +++ b/indra/llui/llemojidictionary.h @@ -56,20 +56,28 @@ class LLEmojiDictionary : public LLParamSingleton, public LLI ~LLEmojiDictionary() override {}; public: + typedef std::map emoji2descr_map_t; + typedef std::map code2descr_map_t; + typedef std::map> cat2descrs_map_t; + static void initClass(); LLWString findMatchingEmojis(const std::string& needle) const; + const LLEmojiDescriptor* getDescriptorFromEmoji(llwchar emoji) const; const LLEmojiDescriptor* getDescriptorFromShortCode(const std::string& short_code) const; std::string getNameFromEmoji(llwchar ch) const; - const std::map& getEmoji2Descr() const { return mEmoji2Descr; } + const emoji2descr_map_t& getEmoji2Descr() const { return mEmoji2Descr; } + const code2descr_map_t& getShortCode2Descr() const { return mShortCode2Descr; } + const cat2descrs_map_t& getCategory2Descrs() const { return mCategory2Descrs; } private: void addEmoji(LLEmojiDescriptor&& descr); private: std::list mEmojis; - std::map mEmoji2Descr; - std::map mShortCode2Descr; + emoji2descr_map_t mEmoji2Descr; + code2descr_map_t mShortCode2Descr; + cat2descrs_map_t mCategory2Descrs; }; // ============================================================================ diff --git a/indra/llui/llfloater.cpp b/indra/llui/llfloater.cpp index 346e89a101..98895d56dd 100644 --- a/indra/llui/llfloater.cpp +++ b/indra/llui/llfloater.cpp @@ -1509,14 +1509,24 @@ BOOL LLFloater::isFrontmost() && floater_view->getFrontmost() == this); } -void LLFloater::addDependentFloater(LLFloater* floaterp, BOOL reposition) +void LLFloater::addDependentFloater(LLFloater* floaterp, BOOL reposition, BOOL resize) { mDependents.insert(floaterp->getHandle()); floaterp->mDependeeHandle = getHandle(); if (reposition) { - floaterp->setRect(gFloaterView->findNeighboringPosition(this, floaterp)); + LLRect rect = gFloaterView->findNeighboringPosition(this, floaterp); + if (resize) + { + const LLRect& base = getRect(); + if (rect.mTop == base.mTop) + rect.mBottom = base.mBottom; + else if (rect.mLeft == base.mLeft) + rect.mRight = base.mRight; + floaterp->reshape(rect.getWidth(), rect.getHeight(), FALSE); + } + floaterp->setRect(rect); floaterp->setSnapTarget(getHandle()); } gFloaterView->adjustToFitScreen(floaterp, FALSE, TRUE); @@ -1527,12 +1537,12 @@ void LLFloater::addDependentFloater(LLFloater* floaterp, BOOL reposition) } } -void LLFloater::addDependentFloater(LLHandle dependent, BOOL reposition) +void LLFloater::addDependentFloater(LLHandle dependent, BOOL reposition, BOOL resize) { LLFloater* dependent_floaterp = dependent.get(); if(dependent_floaterp) { - addDependentFloater(dependent_floaterp, reposition); + addDependentFloater(dependent_floaterp, reposition, resize); } } diff --git a/indra/llui/llfloater.h b/indra/llui/llfloater.h index 282f7a80ac..3699629ef8 100644 --- a/indra/llui/llfloater.h +++ b/indra/llui/llfloater.h @@ -255,8 +255,8 @@ public: std::string getShortTitle() const; virtual void setMinimized(BOOL b); void moveResizeHandlesToFront(); - void addDependentFloater(LLFloater* dependent, BOOL reposition = TRUE); - void addDependentFloater(LLHandle dependent_handle, BOOL reposition = TRUE); + void addDependentFloater(LLFloater* dependent, BOOL reposition = TRUE, BOOL resize = FALSE); + void addDependentFloater(LLHandle dependent_handle, BOOL reposition = TRUE, BOOL resize = FALSE); LLFloater* getDependee() { return (LLFloater*)mDependeeHandle.get(); } void removeDependentFloater(LLFloater* dependent); BOOL isMinimized() const { return mMinimized; } diff --git a/indra/llui/llscrolllistctrl.cpp b/indra/llui/llscrolllistctrl.cpp index 2a6e8a6b76..f982dc99e8 100644 --- a/indra/llui/llscrolllistctrl.cpp +++ b/indra/llui/llscrolllistctrl.cpp @@ -1269,7 +1269,7 @@ BOOL LLScrollListCtrl::selectItemByLabel(const std::string& label, BOOL case_sen LLScrollListItem* item = getItemByLabel(label, case_sensitive, column); bool found = NULL != item; - if(found) + if (found) { selectItem(item, -1); } @@ -2747,7 +2747,7 @@ BOOL LLScrollListCtrl::setSort(S32 column_idx, BOOL ascending) S32 LLScrollListCtrl::getLinesPerPage() { //if mPageLines is NOT provided display all item - if(mPageLines) + if (mPageLines) { return mPageLines; } diff --git a/indra/llui/llscrolllistctrl.h b/indra/llui/llscrolllistctrl.h index 73b4fb036a..326589a329 100644 --- a/indra/llui/llscrolllistctrl.h +++ b/indra/llui/llscrolllistctrl.h @@ -253,7 +253,7 @@ public: S32 getItemIndex( LLScrollListItem* item ) const; S32 getItemIndex( const LLUUID& item_id ) const; - void setCommentText( const std::string& comment_text); + void setCommentText( const std::string& comment_text); LLScrollListItem* addSeparator(EAddPosition pos); // "Simple" interface: use this when you're creating a list that contains only unique strings, only @@ -263,7 +263,7 @@ public: BOOL selectItemByLabel( const std::string& item, BOOL case_sensitive = TRUE, S32 column = 0 ); // FALSE if item not found BOOL selectItemByPrefix(const std::string& target, BOOL case_sensitive = TRUE, S32 column = -1); BOOL selectItemByPrefix(const LLWString& target, BOOL case_sensitive = TRUE, S32 column = -1); - LLScrollListItem* getItemByLabel( const std::string& item, BOOL case_sensitive = TRUE, S32 column = 0 ); + LLScrollListItem* getItemByLabel(const std::string& item, BOOL case_sensitive = TRUE, S32 column = 0); const std::string getSelectedItemLabel(S32 column = 0) const; LLSD getSelectedValue(); @@ -322,7 +322,7 @@ public: virtual S32 getScrollPos() const; virtual void setScrollPos( S32 pos ); - S32 getSearchColumn(); + S32 getSearchColumn(); void setSearchColumn(S32 column) { mSearchColumn = column; } S32 getColumnIndexFromOffset(S32 x); S32 getColumnOffsetFromIndex(S32 index); @@ -371,13 +371,13 @@ public: // Used "internally" by the scroll bar. void onScrollChange( S32 new_pos, LLScrollbar* src ); - static void onClickColumn(void *userdata); + static void onClickColumn(void *userdata); - virtual void updateColumns(bool force_update = false); - S32 calcMaxContentWidth(); - bool updateColumnWidths(); + virtual void updateColumns(bool force_update = false); + S32 calcMaxContentWidth(); + bool updateColumnWidths(); - void setHeadingHeight(S32 heading_height); + void setHeadingHeight(S32 heading_height); /** * Sets max visible lines without scroolbar, if this value equals to 0, * then display all items. @@ -398,18 +398,20 @@ public: virtual void deselect(); virtual BOOL canDeselect() const; - void setNumDynamicColumns(S32 num) { mNumDynamicWidthColumns = num; } - void updateStaticColumnWidth(LLScrollListColumn* col, S32 new_width); - S32 getTotalStaticColumnWidth() { return mTotalStaticColumnWidth; } + void setNumDynamicColumns(S32 num) { mNumDynamicWidthColumns = num; } + void updateStaticColumnWidth(LLScrollListColumn* col, S32 new_width); + S32 getTotalStaticColumnWidth() { return mTotalStaticColumnWidth; } std::string getSortColumnName(); BOOL getSortAscending() { return mSortColumns.empty() ? TRUE : mSortColumns.back().second; } BOOL hasSortOrder() const; void clearSortOrder(); - void setAlternateSort() { mAlternateSort = true; } + void setAlternateSort() { mAlternateSort = TRUE; } - S32 selectMultiple( uuid_vec_t ids ); + void selectPrevItem(BOOL extend_selection = FALSE); + void selectNextItem(BOOL extend_selection = FALSE); + S32 selectMultiple(uuid_vec_t ids); // conceptually const, but mutates mItemList void updateSort() const; // sorts a list without affecting the permanent sort order (so further list insertions can be unsorted, for example) @@ -454,8 +456,6 @@ protected: void updateLineHeight(); private: - void selectPrevItem(BOOL extend_selection); - void selectNextItem(BOOL extend_selection); void drawItems(); void updateLineHeightInsert(LLScrollListItem* item); -- cgit v1.2.3 From 8fcf691623c21dedd0e478fb8d013a28a2959811 Mon Sep 17 00:00:00 2001 From: Ansariel Date: Sat, 22 Apr 2023 14:19:42 +0200 Subject: Load correct localized version of emoji dictionary and guard against access violation exception --- indra/llui/llemojidictionary.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'indra/llui') diff --git a/indra/llui/llemojidictionary.cpp b/indra/llui/llemojidictionary.cpp index d306407484..bb5c94689a 100644 --- a/indra/llui/llemojidictionary.cpp +++ b/indra/llui/llemojidictionary.cpp @@ -141,7 +141,13 @@ void LLEmojiDictionary::initClass() LLSD data; - const std::string filename = gDirUtilp->findSkinnedFilenames(LLDir::XUI, SKINNED_EMOJI_FILENAME, LLDir::CURRENT_SKIN).front(); + auto filenames = gDirUtilp->findSkinnedFilenames(LLDir::XUI, SKINNED_EMOJI_FILENAME, LLDir::CURRENT_SKIN); + if (filenames.empty()) + { + LL_WARNS() << "Emoji file characters not found" << LL_ENDL; + return; + } + const std::string filename = filenames.back(); llifstream file(filename.c_str()); if (file.is_open()) { -- cgit v1.2.3 From fbf5b199f3bd9775bc992609baf6c093177a70d8 Mon Sep 17 00:00:00 2001 From: Alexander Gavriliuk Date: Tue, 25 Apr 2023 00:44:25 +0200 Subject: SL-19575 LLFloaterEmojiPicker - code cleanup and layout fixup --- indra/llui/llemojidictionary.h | 3 +++ indra/llui/llview.h | 24 ++++++++++-------------- 2 files changed, 13 insertions(+), 14 deletions(-) (limited to 'indra/llui') diff --git a/indra/llui/llemojidictionary.h b/indra/llui/llemojidictionary.h index cbb0ac577d..88ff5b8300 100644 --- a/indra/llui/llemojidictionary.h +++ b/indra/llui/llemojidictionary.h @@ -57,8 +57,11 @@ class LLEmojiDictionary : public LLParamSingleton, public LLI public: typedef std::map emoji2descr_map_t; + typedef std::pair emoji2descr_item_t; typedef std::map code2descr_map_t; + typedef std::pair code2descr_item_t; typedef std::map> cat2descrs_map_t; + typedef std::pair> cat2descrs_item_t; static void initClass(); LLWString findMatchingEmojis(const std::string& needle) const; diff --git a/indra/llui/llview.h b/indra/llui/llview.h index bec45df78a..0add3839bb 100644 --- a/indra/llui/llview.h +++ b/indra/llui/llview.h @@ -111,7 +111,7 @@ public: Alternative string; Alternative flags; - Follows(); + Follows(); }; struct Params : public LLInitParam::Block @@ -656,8 +656,8 @@ public: // Draw debug rectangles around widgets to help with alignment and spacing static bool sDebugRects; - static bool sIsRectDirty; - static LLRect sDirtyRect; + static bool sIsRectDirty; + static LLRect sDirtyRect; // Draw widget names and sizes when drawing debug rectangles, turning this // off is useful to make the rectangles themselves easier to see. @@ -700,20 +700,16 @@ template T* LLView::getChild(const std::string& name, BOOL recurse) co if (!result) { result = LLUICtrlFactory::getDefaultWidget(name); - - if (result) - { - // *NOTE: You cannot call mFoo = getChild("bar") - // in a floater or panel constructor. The widgets will not - // be ready. Instead, put it in postBuild(). - LL_WARNS() << "Making dummy " << typeid(T).name() << " named \"" << name << "\" in " << getName() << LL_ENDL; - } - else + if (!result) { - LL_WARNS() << "Failed to create dummy " << typeid(T).name() << LL_ENDL; - return NULL; + LL_ERRS() << "Failed to create dummy " << typeid(T).name() << LL_ENDL; } + // *NOTE: You cannot call mFoo = getChild("bar") + // in a floater or panel constructor. The widgets will not + // be ready. Instead, put it in postBuild(). + LL_WARNS() << "Making dummy " << typeid(T).name() << " named \"" << name << "\" in " << getName() << LL_ENDL; + getDefaultWidgetContainer().addChild(result); } } -- cgit v1.2.3 From 671978e3927bc3ba9fc34008bbb7efd6f07b6c81 Mon Sep 17 00:00:00 2001 From: Alexander Gavriliuk Date: Wed, 17 May 2023 14:28:36 +0200 Subject: SL-19575 Create emoji gallery (fix bug with drawing emojis in chat history) --- indra/llui/llemojidictionary.cpp | 11 +++++++++++ indra/llui/llemojidictionary.h | 1 + indra/llui/lltextbase.cpp | 41 +++++++++++++++++++++++----------------- indra/llui/lltextbase.h | 2 +- 4 files changed, 37 insertions(+), 18 deletions(-) (limited to 'indra/llui') diff --git a/indra/llui/llemojidictionary.cpp b/indra/llui/llemojidictionary.cpp index bb5c94689a..179c5d25bf 100644 --- a/indra/llui/llemojidictionary.cpp +++ b/indra/llui/llemojidictionary.cpp @@ -199,6 +199,17 @@ std::string LLEmojiDictionary::getNameFromEmoji(llwchar ch) const return (mEmoji2Descr.end() != it) ? it->second->Name : LLStringUtil::null; } +bool LLEmojiDictionary::isEmoji(llwchar ch) const +{ + // Currently used codes: A9,AE,203C,2049,2122,...,2B55,3030,303D,3297,3299,1F004,...,1FAF6 + if (ch == 0xA9 || ch == 0xAE || (ch >= 0x2000 && ch < 0x3300) || (ch >= 0x1F000 && ch < 0x20000)) + { + return mEmoji2Descr.find(ch) != mEmoji2Descr.end(); + } + + return false; +} + void LLEmojiDictionary::addEmoji(LLEmojiDescriptor&& descr) { mEmojis.push_back(descr); diff --git a/indra/llui/llemojidictionary.h b/indra/llui/llemojidictionary.h index 88ff5b8300..cc26f75ea3 100644 --- a/indra/llui/llemojidictionary.h +++ b/indra/llui/llemojidictionary.h @@ -68,6 +68,7 @@ public: const LLEmojiDescriptor* getDescriptorFromEmoji(llwchar emoji) const; const LLEmojiDescriptor* getDescriptorFromShortCode(const std::string& short_code) const; std::string getNameFromEmoji(llwchar ch) const; + bool isEmoji(llwchar ch) const; const emoji2descr_map_t& getEmoji2Descr() const { return mEmoji2Descr; } const code2descr_map_t& getShortCode2Descr() const { return mShortCode2Descr; } diff --git a/indra/llui/lltextbase.cpp b/indra/llui/lltextbase.cpp index 0066e09cfc..e7273c96c1 100644 --- a/indra/llui/lltextbase.cpp +++ b/indra/llui/lltextbase.cpp @@ -29,6 +29,7 @@ #include "lltextbase.h" +#include "llemojidictionary.h" #include "llemojihelper.h" #include "lllocalcliprect.h" #include "llmenugl.h" @@ -366,7 +367,7 @@ void LLTextBase::onValueChange(S32 start, S32 end) { } -std::vector LLTextBase::getSelctionRects() +std::vector LLTextBase::getSelectionRects() { // Nor supposed to be called without selection llassert(hasSelection()); @@ -463,7 +464,7 @@ void LLTextBase::drawSelectionBackground() // Draw selection even if we don't have keyboard focus for search/replace if (hasSelection() && !mLineInfoList.empty()) { - std::vector selection_rects = getSelctionRects(); + std::vector selection_rects = getSelectionRects(); // Draw the selection box (we're using a box instead of reversing the colors on the selected text). gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); @@ -904,9 +905,12 @@ 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; + LLEmojiDictionary* ed = LLEmojiDictionary::instanceExists() ? LLEmojiDictionary::getInstance() : NULL; for (S32 text_kitty = 0, text_len = wstr.size(); text_kitty < text_len; text_kitty++) { - if (LLStringOps::isEmoji(wstr[text_kitty])) + llwchar code = wstr[text_kitty]; + bool isEmoji = ed ? ed->isEmoji(code) : LLStringOps::isEmoji(code); + if (isEmoji) { if (!emoji_style) { @@ -2181,8 +2185,8 @@ void LLTextBase::appendTextImpl(const std::string &new_text, const LLStyle::Para S32 start=0,end=0; LLUrlMatch match; std::string text = new_text; - while ( LLUrlRegistry::instance().findUrl(text, match, - boost::bind(&LLTextBase::replaceUrl, this, _1, _2, _3),isContentTrusted() || mAlwaysShowIcons)) + while (LLUrlRegistry::instance().findUrl(text, match, + boost::bind(&LLTextBase::replaceUrl, this, _1, _2, _3), isContentTrusted() || mAlwaysShowIcons)) { start = match.getStart(); end = match.getEnd()+1; @@ -2430,18 +2434,18 @@ void LLTextBase::appendAndHighlightTextImpl(const std::string &new_text, S32 hig LLStyle::Params normal_style_params(style_params); normal_style_params.font.style("NORMAL"); LLStyleConstSP normal_sp(new LLStyle(normal_style_params)); - segments.push_back(new LLOnHoverChangeableTextSegment(sp, normal_sp, segment_start, segment_end, *this )); + segments.push_back(new LLOnHoverChangeableTextSegment(sp, normal_sp, segment_start, segment_end, *this)); } else { - segments.push_back(new LLNormalTextSegment(sp, segment_start, segment_end, *this )); + segments.push_back(new LLNormalTextSegment(sp, segment_start, segment_end, *this)); } insertStringNoUndo(getLength(), wide_text, &segments); } // Set the cursor and scroll position - if( selection_start != selection_end ) + if (selection_start != selection_end) { mSelectionStart = selection_start; mSelectionEnd = selection_end; @@ -2449,7 +2453,7 @@ void LLTextBase::appendAndHighlightTextImpl(const std::string &new_text, S32 hig mIsSelecting = was_selecting; setCursorPos(cursor_pos); } - else if( cursor_was_at_end ) + else if (cursor_was_at_end) { setCursorPos(getLength()); } @@ -2461,25 +2465,28 @@ void LLTextBase::appendAndHighlightTextImpl(const std::string &new_text, S32 hig void LLTextBase::appendAndHighlightText(const std::string &new_text, S32 highlight_part, const LLStyle::Params& style_params, bool underline_on_hover_only) { - if (new_text.empty()) return; + if (new_text.empty()) + { + return; + } std::string::size_type start = 0; - std::string::size_type pos = new_text.find("\n",start); + std::string::size_type pos = new_text.find("\n", start); - while(pos!=-1) + while (pos != std::string::npos) { - if(pos!=start) + if (pos != start) { std::string str = std::string(new_text,start,pos-start); - appendAndHighlightTextImpl(str,highlight_part, style_params, underline_on_hover_only); + appendAndHighlightTextImpl(str, highlight_part, style_params, underline_on_hover_only); } appendLineBreakSegment(style_params); start = pos+1; - pos = new_text.find("\n",start); + pos = new_text.find("\n", start); } - std::string str = std::string(new_text,start,new_text.length()-start); - appendAndHighlightTextImpl(str,highlight_part, style_params, underline_on_hover_only); + std::string str = std::string(new_text, start, new_text.length() - start); + appendAndHighlightTextImpl(str, highlight_part, style_params, underline_on_hover_only); } diff --git a/indra/llui/lltextbase.h b/indra/llui/lltextbase.h index 9b3691e404..37ab798a1d 100644 --- a/indra/llui/lltextbase.h +++ b/indra/llui/lltextbase.h @@ -654,7 +654,7 @@ protected: return mLabel.getString() + getToolTip(); } - std::vector getSelctionRects(); + std::vector getSelectionRects(); protected: // text segmentation and flow -- cgit v1.2.3 From bb97f3bf03cfa776b09dc2c0929fbb100a11c775 Mon Sep 17 00:00:00 2001 From: Alexander Gavriliuk Date: Thu, 18 May 2023 07:47:54 +0200 Subject: SL-19575 Create emoji gallery (use ::value_type in LLEmojiDictionary typedefs) --- indra/llui/llemojidictionary.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'indra/llui') diff --git a/indra/llui/llemojidictionary.h b/indra/llui/llemojidictionary.h index cc26f75ea3..1507ebfad3 100644 --- a/indra/llui/llemojidictionary.h +++ b/indra/llui/llemojidictionary.h @@ -57,11 +57,11 @@ class LLEmojiDictionary : public LLParamSingleton, public LLI public: typedef std::map emoji2descr_map_t; - typedef std::pair emoji2descr_item_t; + typedef emoji2descr_map_t::value_type emoji2descr_item_t; typedef std::map code2descr_map_t; - typedef std::pair code2descr_item_t; + typedef code2descr_map_t::value_type code2descr_item_t; typedef std::map> cat2descrs_map_t; - typedef std::pair> cat2descrs_item_t; + typedef cat2descrs_map_t::value_type cat2descrs_item_t; static void initClass(); LLWString findMatchingEmojis(const std::string& needle) const; -- cgit v1.2.3 From 8bbbce015b6dae1bdafe0bba329463322642ca85 Mon Sep 17 00:00:00 2001 From: Alexander Gavriliuk Date: Tue, 4 Jul 2023 07:38:05 +0200 Subject: SL-19575 Rework emoji picker layout similar to Slack --- indra/llui/llscrollingpanellist.cpp | 184 +++++++++++++++++++++--------------- indra/llui/llscrollingpanellist.h | 37 ++++++-- 2 files changed, 136 insertions(+), 85 deletions(-) (limited to 'indra/llui') diff --git a/indra/llui/llscrollingpanellist.cpp b/indra/llui/llscrollingpanellist.cpp index b6f2eb8ba2..3a819e7d06 100644 --- a/indra/llui/llscrollingpanellist.cpp +++ b/indra/llui/llscrollingpanellist.cpp @@ -37,53 +37,44 @@ static LLDefaultChildRegistry::Register r("scrolling_panel // This could probably be integrated with LLScrollContainer -SJB +LLScrollingPanelList::Params::Params() + : is_horizontal("is_horizontal") + , padding("padding") + , spacing("spacing") +{ +} + +LLScrollingPanelList::LLScrollingPanelList(const Params& p) + : LLUICtrl(p) + , mIsHorizontal(p.is_horizontal) + , mPadding(p.padding.isProvided() ? p.padding : DEFAULT_PADDING) + , mSpacing(p.spacing.isProvided() ? p.spacing : DEFAULT_SPACING) +{ +} + void LLScrollingPanelList::clearPanels() { deleteAllChildren(); mPanelList.clear(); - - LLRect rc = getRect(); - rc.setLeftTopAndSize(rc.mLeft, rc.mTop, 1, 1); - setRect(rc); - - notifySizeChanged(rc.getHeight()); + rearrange(); } -S32 LLScrollingPanelList::addPanel( LLScrollingPanel* panel ) +S32 LLScrollingPanelList::addPanel(LLScrollingPanel* panel, bool back) { - addChildInBack( panel ); - mPanelList.push_front( panel ); - - // Resize this view - S32 total_height = 0; - S32 max_width = 0; - S32 cur_gap = 0; - for (std::deque::iterator iter = mPanelList.begin(); - iter != mPanelList.end(); ++iter) + if (back) { - LLScrollingPanel *childp = *iter; - total_height += childp->getRect().getHeight() + cur_gap; - max_width = llmax( max_width, childp->getRect().getWidth() ); - cur_gap = GAP_BETWEEN_PANELS; + addChild(panel); + mPanelList.push_back(panel); } - LLRect rc = getRect(); - rc.setLeftTopAndSize(rc.mLeft, rc.mTop, max_width, total_height); - setRect(rc); - - notifySizeChanged(rc.getHeight()); - - // Reposition each of the child views - S32 cur_y = total_height; - for (std::deque::iterator iter = mPanelList.begin(); - iter != mPanelList.end(); ++iter) + else { - LLScrollingPanel *childp = *iter; - cur_y -= childp->getRect().getHeight(); - childp->translate( -childp->getRect().mLeft, cur_y - childp->getRect().mBottom); - cur_y -= GAP_BETWEEN_PANELS; + addChildInBack(panel); + mPanelList.push_front(panel); } - return total_height; + rearrange(); + + return mIsHorizontal ? getRect().getWidth() : getRect().getHeight(); } void LLScrollingPanelList::removePanel(LLScrollingPanel* panel) @@ -100,7 +91,7 @@ void LLScrollingPanelList::removePanel(LLScrollingPanel* panel) break; } } - if(iter != mPanelList.end()) + if (iter != mPanelList.end()) { removePanel(index); } @@ -120,62 +111,104 @@ void LLScrollingPanelList::removePanel( U32 panel_index ) mPanelList.erase( mPanelList.begin() + panel_index ); } - const S32 GAP_BETWEEN_PANELS = 6; + rearrange(); +} - // Resize this view - S32 total_height = 0; - S32 max_width = 0; - S32 cur_gap = 0; - for (std::deque::iterator iter = mPanelList.begin(); +void LLScrollingPanelList::updatePanels(BOOL allow_modify) +{ + for (std::deque::iterator iter = mPanelList.begin(); iter != mPanelList.end(); ++iter) - { + { LLScrollingPanel *childp = *iter; - total_height += childp->getRect().getHeight() + cur_gap; - max_width = llmax( max_width, childp->getRect().getWidth() ); - cur_gap = GAP_BETWEEN_PANELS; + childp->updatePanel(allow_modify); + } +} + +void LLScrollingPanelList::rearrange() +{ + // Resize this view + S32 new_width, new_height; + if (!mPanelList.empty()) + { + new_width = new_height = mPadding * 2; + for (std::deque::iterator iter = mPanelList.begin(); + iter != mPanelList.end(); ++iter) + { + LLScrollingPanel* childp = *iter; + const LLRect& rect = childp->getRect(); + if (mIsHorizontal) + { + new_width += rect.getWidth() + mSpacing; + new_height = llmax(new_height, rect.getHeight()); + } + else + { + new_height += rect.getHeight() + mSpacing; + new_width = llmax(new_width, rect.getWidth()); + } + } + + if (mIsHorizontal) + { + new_width -= mSpacing; + } + else + { + new_height -= mSpacing; + } } + else + { + new_width = new_height = 1; + } + LLRect rc = getRect(); - rc.setLeftTopAndSize(rc.mLeft, rc.mTop, max_width, total_height); - setRect(rc); + if (mIsHorizontal || !followsRight()) + { + rc.mRight = rc.mLeft + new_width; + } + if (!mIsHorizontal || !followsBottom()) + { + rc.mBottom = rc.mTop - new_height; + } - notifySizeChanged(rc.getHeight()); + if (rc.mRight != getRect().mRight || rc.mBottom != getRect().mBottom) + { + setRect(rc); + notifySizeChanged(); + } // Reposition each of the child views - S32 cur_y = total_height; + S32 pos = mIsHorizontal ? mPadding : rc.getHeight() - mPadding; for (std::deque::iterator iter = mPanelList.begin(); - iter != mPanelList.end(); ++iter) + iter != mPanelList.end(); ++iter) { - LLScrollingPanel *childp = *iter; - cur_y -= childp->getRect().getHeight(); - childp->translate( -childp->getRect().mLeft, cur_y - childp->getRect().mBottom); - cur_y -= GAP_BETWEEN_PANELS; + LLScrollingPanel* childp = *iter; + const LLRect& rect = childp->getRect(); + if (mIsHorizontal) + { + childp->translate(pos - rect.mLeft, rc.getHeight() - mPadding - rect.mTop); + pos += rect.getWidth() + mSpacing; + } + else + { + childp->translate(mPadding - rect.mLeft, pos - rect.mTop); + pos -= rect.getHeight() + mSpacing; + } } } -void LLScrollingPanelList::updatePanels(BOOL allow_modify) -{ - for (std::deque::iterator iter = mPanelList.begin(); - iter != mPanelList.end(); ++iter) - { - LLScrollingPanel *childp = *iter; - childp->updatePanel(allow_modify); - } -} - void LLScrollingPanelList::updatePanelVisiblilty() { // Determine visibility of children. - S32 BORDER_WIDTH = 2; // HACK - LLRect parent_local_rect = getParent()->getRect(); - parent_local_rect.stretch( -BORDER_WIDTH ); - LLRect parent_screen_rect; - getParent()->localPointToScreen( - BORDER_WIDTH, 0, + getParent()->localPointToScreen( + mPadding, mPadding, &parent_screen_rect.mLeft, &parent_screen_rect.mBottom ); - getParent()->localPointToScreen( - parent_local_rect.getWidth() - BORDER_WIDTH, parent_local_rect.getHeight() - BORDER_WIDTH, + getParent()->localPointToScreen( + getParent()->getRect().getWidth() - mPadding, + getParent()->getRect().getHeight() - mPadding, &parent_screen_rect.mRight, &parent_screen_rect.mTop ); for (std::deque::iterator iter = mPanelList.begin(); @@ -207,11 +240,12 @@ void LLScrollingPanelList::draw() LLUICtrl::draw(); } -void LLScrollingPanelList::notifySizeChanged(S32 height) +void LLScrollingPanelList::notifySizeChanged() { LLSD info; info["action"] = "size_changes"; - info["height"] = height; + info["height"] = getRect().getHeight(); + info["width"] = getRect().getWidth(); notifyParent(info); } diff --git a/indra/llui/llscrollingpanellist.h b/indra/llui/llscrollingpanellist.h index e8df176ec3..9dc65dabb5 100644 --- a/indra/llui/llscrollingpanellist.h +++ b/indra/llui/llscrollingpanellist.h @@ -51,12 +51,18 @@ class LLScrollingPanelList : public LLUICtrl { public: struct Params : public LLInitParam::Block - {}; - LLScrollingPanelList(const Params& p) - : LLUICtrl(p) - {} + { + Optional is_horizontal; + Optional padding; + Optional spacing; + + Params(); + }; + + LLScrollingPanelList(const Params& p); - static const S32 GAP_BETWEEN_PANELS = 6; + static const S32 DEFAULT_SPACING = 6; + static const S32 DEFAULT_PADDING = 2; typedef std::deque panel_list_t; @@ -65,11 +71,18 @@ public: virtual void draw(); void clearPanels(); - S32 addPanel( LLScrollingPanel* panel ); - void removePanel( LLScrollingPanel* panel ); - void removePanel( U32 panel_index ); + S32 addPanel(LLScrollingPanel* panel, bool back = false); + void removePanel(LLScrollingPanel* panel); + void removePanel(U32 panel_index); void updatePanels(BOOL allow_modify); - const panel_list_t& getPanelList() { return mPanelList; } + void rearrange(); + + const panel_list_t& getPanelList() const { return mPanelList; } + bool getIsHorizontal() const { return mIsHorizontal; } + void setPadding(S32 padding) { mPadding = padding; rearrange(); } + void setSpacing(S32 spacing) { mSpacing = spacing; rearrange(); } + S32 getPadding() const { return mPadding; } + S32 getSpacing() const { return mSpacing; } private: void updatePanelVisiblilty(); @@ -77,7 +90,11 @@ private: /** * Notify parent about size change, makes sense when used inside accordion */ - void notifySizeChanged(S32 height); + void notifySizeChanged(); + + bool mIsHorizontal; + S32 mPadding; + S32 mSpacing; panel_list_t mPanelList; }; -- cgit v1.2.3 From 9793308a600c1e1ce35ec727ed6341e7668848ea Mon Sep 17 00:00:00 2001 From: Alexander Gavriliuk Date: Thu, 6 Jul 2023 23:48:06 +0200 Subject: SL-19951 Organize emoji categories in groups --- indra/llui/llemojidictionary.cpp | 424 +++++++++++++++++++++++++++------------ indra/llui/llemojidictionary.h | 78 ++++--- 2 files changed, 349 insertions(+), 153 deletions(-) (limited to 'indra/llui') diff --git a/indra/llui/llemojidictionary.cpp b/indra/llui/llemojidictionary.cpp index 179c5d25bf..cdcf5a93d6 100644 --- a/indra/llui/llemojidictionary.cpp +++ b/indra/llui/llemojidictionary.cpp @@ -38,7 +38,12 @@ // Constants // -constexpr char SKINNED_EMOJI_FILENAME[] = "emoji_characters.xml"; +static const std::string SKINNED_EMOJI_FILENAME("emoji_characters.xml"); +static const std::string SKINNED_CATEGORY_FILENAME("emoji_categories.xml"); +static const std::string COMMON_GROUP_FILENAME("emoji_groups.xml"); +static const std::string GROUP_NAME_ALL("all"); +static const std::string GROUP_NAME_OTHERS("others"); +static const std::string GROUP_NAME_SKIP("skip"); // ============================================================================ // Helper functions @@ -50,82 +55,68 @@ std::list llsd_array_to_list(const LLSD& sd, std::function mutator template<> std::list llsd_array_to_list(const LLSD& sd, std::function mutator) { - std::list result; - for (LLSD::array_const_iterator it = sd.beginArray(), end = sd.endArray(); it != end; ++it) - { - const LLSD& entry = *it; - if (!entry.isString()) - continue; - - result.push_back(entry.asStringRef()); - if (mutator) - { - mutator(result.back()); - } - } - return result; -} - -LLEmojiDescriptor::LLEmojiDescriptor(const LLSD& descriptor_sd) -{ - Name = descriptor_sd["Name"].asStringRef(); - - const LLWString emoji_string = utf8str_to_wstring(descriptor_sd["Character"].asString()); - Character = (1 == emoji_string.size()) ? emoji_string[0] : L'\0'; // We don't currently support character composition - - auto toLower = [](std::string& str) { LLStringUtil::toLower(str); }; - ShortCodes = llsd_array_to_list(descriptor_sd["ShortCodes"], toLower); - Categories = llsd_array_to_list(descriptor_sd["Categories"], toLower); - - if (Name.empty()) - { - Name = ShortCodes.front(); - } -} - -bool LLEmojiDescriptor::isValid() const -{ - return - Character && - !ShortCodes.empty() && - !Categories.empty(); + std::list result; + for (LLSD::array_const_iterator it = sd.beginArray(), end = sd.endArray(); it != end; ++it) + { + const LLSD& entry = *it; + if (!entry.isString()) + continue; + + result.push_back(entry.asStringRef()); + if (mutator) + { + mutator(result.back()); + } + } + return result; } struct emoji_filter_base { - emoji_filter_base(const std::string& needle) - { - // Search without the colon (if present) so the user can type ':food' and see all emojis in the 'Food' category - mNeedle = (boost::starts_with(needle, ":")) ? needle.substr(1) : needle; - LLStringUtil::toLower(mNeedle); - } + emoji_filter_base(const std::string& needle) + { + // Search without the colon (if present) so the user can type ':food' and see all emojis in the 'Food' category + mNeedle = (boost::starts_with(needle, ":")) ? needle.substr(1) : needle; + LLStringUtil::toLower(mNeedle); + } protected: - std::string mNeedle; + std::string mNeedle; }; struct emoji_filter_shortcode_or_category_contains : public emoji_filter_base { - emoji_filter_shortcode_or_category_contains(const std::string& needle) : emoji_filter_base(needle) {} + emoji_filter_shortcode_or_category_contains(const std::string& needle) : emoji_filter_base(needle) {} - bool operator()(const LLEmojiDescriptor& descr) const - { - for (const auto& short_code : descr.ShortCodes) - { - if (boost::icontains(short_code, mNeedle)) - return true; - } + bool operator()(const LLEmojiDescriptor& descr) const + { + for (const auto& short_code : descr.ShortCodes) + { + if (boost::icontains(short_code, mNeedle)) + return true; + } - for (const auto& category : descr.Categories) - { - if (boost::icontains(category, mNeedle)) - return true; - } + if (boost::icontains(descr.Category, mNeedle)) + return true; - return false; - } + return false; + } }; +std::string LLEmojiDescriptor::getShortCodes() const +{ + std::string result; + for (const std::string& shortCode : ShortCodes) + { + if (!result.empty()) + { + result += ", "; + } + result += shortCode; + } + return result; +} + // ============================================================================ // LLEmojiDictionary class // @@ -137,91 +128,278 @@ LLEmojiDictionary::LLEmojiDictionary() // static void LLEmojiDictionary::initClass() { - LLEmojiDictionary* pThis = &LLEmojiDictionary::initParamSingleton(); - - LLSD data; - - auto filenames = gDirUtilp->findSkinnedFilenames(LLDir::XUI, SKINNED_EMOJI_FILENAME, LLDir::CURRENT_SKIN); - if (filenames.empty()) - { - LL_WARNS() << "Emoji file characters not found" << LL_ENDL; - return; - } - const std::string filename = filenames.back(); - llifstream file(filename.c_str()); - if (file.is_open()) - { - LL_DEBUGS() << "Loading emoji characters file at " << filename << LL_ENDL; - LLSDSerialize::fromXML(data, file); - } - - if (data.isUndefined()) - { - LL_WARNS() << "Emoji file characters missing or ill-formed" << LL_ENDL; - return; - } - - for (LLSD::array_const_iterator descriptor_it = data.beginArray(), descriptor_end = data.endArray(); descriptor_it != descriptor_end; ++descriptor_it) - { - LLEmojiDescriptor descriptor(*descriptor_it); - if (!descriptor.isValid()) - { - LL_WARNS() << "Skipping invalid emoji descriptor " << descriptor.Character << LL_ENDL; - continue; - } - pThis->addEmoji(std::move(descriptor)); - } + LLEmojiDictionary* pThis = &LLEmojiDictionary::initParamSingleton(); + + pThis->loadTranslations(); + pThis->loadGroups(); + pThis->loadEmojis(); } LLWString LLEmojiDictionary::findMatchingEmojis(const std::string& needle) const { - LLWString result; - boost::transform(mEmojis | boost::adaptors::filtered(emoji_filter_shortcode_or_category_contains(needle)), - std::back_inserter(result), [](const auto& descr) { return descr.Character; }); - return result; + LLWString result; + boost::transform(mEmojis | boost::adaptors::filtered(emoji_filter_shortcode_or_category_contains(needle)), + std::back_inserter(result), [](const auto& descr) { return descr.Character; }); + return result; } const LLEmojiDescriptor* LLEmojiDictionary::getDescriptorFromEmoji(llwchar emoji) const { - const auto it = mEmoji2Descr.find(emoji); - return (mEmoji2Descr.end() != it) ? it->second : nullptr; + const auto it = mEmoji2Descr.find(emoji); + return (mEmoji2Descr.end() != it) ? it->second : nullptr; } const LLEmojiDescriptor* LLEmojiDictionary::getDescriptorFromShortCode(const std::string& short_code) const { - const auto it = mShortCode2Descr.find(short_code); - return (mShortCode2Descr.end() != it) ? it->second : nullptr; + const auto it = mShortCode2Descr.find(short_code); + return (mShortCode2Descr.end() != it) ? it->second : nullptr; } std::string LLEmojiDictionary::getNameFromEmoji(llwchar ch) const { - const auto it = mEmoji2Descr.find(ch); - return (mEmoji2Descr.end() != it) ? it->second->Name : LLStringUtil::null; + const auto it = mEmoji2Descr.find(ch); + return (mEmoji2Descr.end() != it) ? it->second->ShortCodes.front() : LLStringUtil::null; } bool LLEmojiDictionary::isEmoji(llwchar ch) const { - // Currently used codes: A9,AE,203C,2049,2122,...,2B55,3030,303D,3297,3299,1F004,...,1FAF6 - if (ch == 0xA9 || ch == 0xAE || (ch >= 0x2000 && ch < 0x3300) || (ch >= 0x1F000 && ch < 0x20000)) - { - return mEmoji2Descr.find(ch) != mEmoji2Descr.end(); - } + // Currently used codes: A9,AE,203C,2049,2122,...,2B55,3030,303D,3297,3299,1F004,...,1FAF6 + if (ch == 0xA9 || ch == 0xAE || (ch >= 0x2000 && ch < 0x3300) || (ch >= 0x1F000 && ch < 0x20000)) + { + return mEmoji2Descr.find(ch) != mEmoji2Descr.end(); + } - return false; + return false; +} + +void LLEmojiDictionary::loadTranslations() +{ + std::vector filenames = gDirUtilp->findSkinnedFilenames(LLDir::XUI, SKINNED_CATEGORY_FILENAME, LLDir::CURRENT_SKIN); + if (filenames.empty()) + { + LL_WARNS() << "Emoji file categories not found" << LL_ENDL; + return; + } + + const std::string filename = filenames.back(); + llifstream file(filename.c_str()); + if (!file.is_open()) + { + LL_WARNS() << "Emoji file categories failed to open" << LL_ENDL; + return; + } + + LL_DEBUGS() << "Loading emoji categories file at " << filename << LL_ENDL; + + LLSD data; + LLSDSerialize::fromXML(data, file); + if (data.isUndefined()) + { + LL_WARNS() << "Emoji file categories missing or ill-formed" << LL_ENDL; + return; + } + + // Register translations for all categories + for (LLSD::array_const_iterator it = data.beginArray(), end = data.endArray(); it != end; ++it) + { + const LLSD& sd = *it; + const std::string& name = sd["Name"].asStringRef(); + const std::string& category = sd["Category"].asStringRef(); + if (!name.empty() && !category.empty()) + { + mTranslations[name] = category; + } + else + { + LL_WARNS() << "Skipping invalid emoji category '" << name << "' => '" << category << "'" << LL_ENDL; + } + } +} + +void LLEmojiDictionary::loadGroups() +{ + const std::string filename = gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, COMMON_GROUP_FILENAME); + llifstream file(filename.c_str()); + if (!file.is_open()) + { + LL_WARNS() << "Emoji file groups failed to open" << LL_ENDL; + return; + } + + LL_DEBUGS() << "Loading emoji groups file at " << filename << LL_ENDL; + + LLSD data; + LLSDSerialize::fromXML(data, file); + if (data.isUndefined()) + { + LL_WARNS() << "Emoji file groups missing or ill-formed" << LL_ENDL; + return; + } + + mGroups.clear(); + // Add group "all" + mGroups.emplace_back(); + // https://www.compart.com/en/unicode/U+1F50D + mGroups.front().Character = 0x1F50D; + // https://www.compart.com/en/unicode/U+1F302 + llwchar iconOthers = 0x1F302; + + // Register all groups + for (LLSD::array_const_iterator it = data.beginArray(), end = data.endArray(); it != end; ++it) + { + const LLSD& sd = *it; + const std::string& name = sd["Name"].asStringRef(); + if (name == GROUP_NAME_ALL) + { + mGroups.front().Character = loadIcon(sd); + } + else if (name == GROUP_NAME_OTHERS) + { + iconOthers = loadIcon(sd); + } + else if (name == GROUP_NAME_SKIP) + { + mSkipCategories = loadCategories(sd); + translateCategories(mSkipCategories); + } + else + { + // Add new group + mGroups.emplace_back(); + LLEmojiGroup& group = mGroups.back(); + group.Character = loadIcon(sd); + group.Categories = loadCategories(sd); + translateCategories(group.Categories); + + for (const std::string& category : group.Categories) + { + mCategory2Group.insert(std::make_pair(category, &group)); + } + } + } + + // Add group "others" + mGroups.emplace_back(); + mGroups.back().Character = iconOthers; +} + +void LLEmojiDictionary::loadEmojis() +{ + std::vector filenames = gDirUtilp->findSkinnedFilenames(LLDir::XUI, SKINNED_EMOJI_FILENAME, LLDir::CURRENT_SKIN); + if (filenames.empty()) + { + LL_WARNS() << "Emoji file characters not found" << LL_ENDL; + return; + } + + const std::string filename = filenames.back(); + llifstream file(filename.c_str()); + if (!file.is_open()) + { + LL_WARNS() << "Emoji file characters failed to open" << LL_ENDL; + return; + } + + LL_DEBUGS() << "Loading emoji characters file at " << filename << LL_ENDL; + + LLSD data; + LLSDSerialize::fromXML(data, file); + if (data.isUndefined()) + { + LL_WARNS() << "Emoji file characters missing or ill-formed" << LL_ENDL; + return; + } + + for (LLSD::array_const_iterator it = data.beginArray(), end = data.endArray(); it != end; ++it) + { + const LLSD& sd = *it; + + llwchar icon = loadIcon(sd); + if (!icon) + { + LL_WARNS() << "Skipping invalid emoji descriptor (no icon)" << LL_ENDL; + continue; + } + + std::list categories = loadCategories(sd); + if (categories.empty()) + { + LL_WARNS() << "Skipping invalid emoji descriptor (no categories)" << LL_ENDL; + continue; + } + + std::string category = categories.front(); + + if (std::find(mSkipCategories.begin(), mSkipCategories.end(), category) != mSkipCategories.end()) + { + // This category is listed for skip + continue; + } + + std::list shortCodes = loadShortCodes(sd); + if (shortCodes.empty()) + { + LL_WARNS() << "Skipping invalid emoji descriptor (no shortCodes)" << LL_ENDL; + continue; + } + + if (mCategory2Group.find(category) == mCategory2Group.end()) + { + // Add unknown category to "others" group + mGroups.back().Categories.push_back(category); + mCategory2Group.insert(std::make_pair(category, &mGroups.back())); + } + + mEmojis.emplace_back(); + LLEmojiDescriptor& emoji = mEmojis.back(); + emoji.Character = icon; + emoji.Category = category; + emoji.ShortCodes = std::move(shortCodes); + + mEmoji2Descr.insert(std::make_pair(icon, &emoji)); + mCategory2Descrs[category].push_back(&emoji); + for (const std::string& shortCode : emoji.ShortCodes) + { + mShortCode2Descr.insert(std::make_pair(shortCode, &emoji)); + } + } +} + +llwchar LLEmojiDictionary::loadIcon(const LLSD& sd) +{ + // We don't currently support character composition + const LLWString icon = utf8str_to_wstring(sd["Character"].asString()); + return (1 == icon.size()) ? icon[0] : L'\0'; +} + +static inline std::list loadStrings(const LLSD& sd, const std::string key) +{ + auto toLower = [](std::string& str) { LLStringUtil::toLower(str); }; + return llsd_array_to_list(sd[key], toLower); +} + +std::list LLEmojiDictionary::loadCategories(const LLSD& sd) +{ + static const std::string categoriesKey("Categories"); + return loadStrings(sd, categoriesKey); +} + +std::list LLEmojiDictionary::loadShortCodes(const LLSD& sd) +{ + static const std::string shortCodesKey("ShortCodes"); + return loadStrings(sd, shortCodesKey); } -void LLEmojiDictionary::addEmoji(LLEmojiDescriptor&& descr) +void LLEmojiDictionary::translateCategories(std::list& categories) { - mEmojis.push_back(descr); - mEmoji2Descr.insert(std::make_pair(descr.Character, &mEmojis.back())); - for (const std::string& shortCode : descr.ShortCodes) - { - mShortCode2Descr.insert(std::make_pair(shortCode, &mEmojis.back())); - } - for (const std::string& category : descr.Categories) - { - mCategory2Descrs[category].push_back(&mEmojis.back()); - } + for (std::string& category : categories) + { + auto it = mTranslations.find(category); + if (it != mTranslations.end()) + { + category = it->second; + } + } } // ============================================================================ diff --git a/indra/llui/llemojidictionary.h b/indra/llui/llemojidictionary.h index 1507ebfad3..f6442684a7 100644 --- a/indra/llui/llemojidictionary.h +++ b/indra/llui/llemojidictionary.h @@ -36,14 +36,20 @@ struct LLEmojiDescriptor { - LLEmojiDescriptor(const LLSD& descriptor_sd); + llwchar Character; + std::string Category; + std::list ShortCodes; + std::string getShortCodes() const; +}; - bool isValid() const; +// ============================================================================ +// LLEmojiGroup class +// - std::string Name; - llwchar Character; - std::list ShortCodes; - std::list Categories; +struct LLEmojiGroup +{ + llwchar Character; + std::list Categories; }; // ============================================================================ @@ -52,36 +58,48 @@ struct LLEmojiDescriptor class LLEmojiDictionary : public LLParamSingleton, public LLInitClass { - LLSINGLETON(LLEmojiDictionary); - ~LLEmojiDictionary() override {}; + LLSINGLETON(LLEmojiDictionary); + ~LLEmojiDictionary() override {}; public: - typedef std::map emoji2descr_map_t; - typedef emoji2descr_map_t::value_type emoji2descr_item_t; - typedef std::map code2descr_map_t; - typedef code2descr_map_t::value_type code2descr_item_t; - typedef std::map> cat2descrs_map_t; - typedef cat2descrs_map_t::value_type cat2descrs_item_t; - - static void initClass(); - LLWString findMatchingEmojis(const std::string& needle) const; - const LLEmojiDescriptor* getDescriptorFromEmoji(llwchar emoji) const; - const LLEmojiDescriptor* getDescriptorFromShortCode(const std::string& short_code) const; - std::string getNameFromEmoji(llwchar ch) const; - bool isEmoji(llwchar ch) const; - - const emoji2descr_map_t& getEmoji2Descr() const { return mEmoji2Descr; } - const code2descr_map_t& getShortCode2Descr() const { return mShortCode2Descr; } - const cat2descrs_map_t& getCategory2Descrs() const { return mCategory2Descrs; } + typedef std::map cat2cat_map_t; + typedef std::map cat2group_map_t; + typedef std::map emoji2descr_map_t; + typedef std::map code2descr_map_t; + typedef std::map> cat2descrs_map_t; + + static void initClass(); + LLWString findMatchingEmojis(const std::string& needle) const; + const LLEmojiDescriptor* getDescriptorFromEmoji(llwchar emoji) const; + const LLEmojiDescriptor* getDescriptorFromShortCode(const std::string& short_code) const; + std::string getNameFromEmoji(llwchar ch) const; + bool isEmoji(llwchar ch) const; + + const std::vector& getGroups() const { return mGroups; } + const emoji2descr_map_t& getEmoji2Descr() const { return mEmoji2Descr; } + const cat2descrs_map_t& getCategory2Descrs() const { return mCategory2Descrs; } + const code2descr_map_t& getShortCode2Descr() const { return mShortCode2Descr; } private: - void addEmoji(LLEmojiDescriptor&& descr); + void loadTranslations(); + void loadGroups(); + void loadEmojis(); + + static llwchar loadIcon(const LLSD& sd); + static std::list loadCategories(const LLSD& sd); + static std::list loadShortCodes(const LLSD& sd); + void translateCategories(std::list& categories); private: - std::list mEmojis; - emoji2descr_map_t mEmoji2Descr; - code2descr_map_t mShortCode2Descr; - cat2descrs_map_t mCategory2Descrs; + std::vector mGroups; + std::list mEmojis; + std::list mSkipCategories; + + cat2cat_map_t mTranslations; + cat2group_map_t mCategory2Group; + emoji2descr_map_t mEmoji2Descr; + cat2descrs_map_t mCategory2Descrs; + code2descr_map_t mShortCode2Descr; }; // ============================================================================ -- cgit v1.2.3 From 1fe007abef6eeceefb0dc720b4a5ecb4505ede88 Mon Sep 17 00:00:00 2001 From: Alexander Gavriliuk Date: Thu, 13 Jul 2023 21:18:22 +0200 Subject: SL-20001 EmojiPicker - make the preview to be a panel instead of a button --- indra/llui/lllineeditor.cpp | 4 +++- indra/llui/lllineeditor.h | 2 ++ 2 files changed, 5 insertions(+), 1 deletion(-) (limited to 'indra/llui') diff --git a/indra/llui/lllineeditor.cpp b/indra/llui/lllineeditor.cpp index 940cf398c0..7d13d731e2 100644 --- a/indra/llui/lllineeditor.cpp +++ b/indra/llui/lllineeditor.cpp @@ -89,6 +89,7 @@ LLLineEditor::Params::Params() background_image_disabled("background_image_disabled"), background_image_focused("background_image_focused"), bg_image_always_focused("bg_image_always_focused", false), + show_label_focused("show_label_focused", false), select_on_focus("select_on_focus", false), revert_on_esc("revert_on_esc", true), spellcheck("spellcheck", false), @@ -152,6 +153,7 @@ LLLineEditor::LLLineEditor(const LLLineEditor::Params& p) mBgImageDisabled( p.background_image_disabled ), mBgImageFocused( p.background_image_focused ), mShowImageFocused( p.bg_image_always_focused ), + mShowLabelFocused( p.show_label_focused ), mUseBgColor(p.use_bg_color), mHaveHistory(FALSE), mReplaceNewlinesWithSpaces( TRUE ), @@ -2068,7 +2070,7 @@ void LLLineEditor::draw() //draw label if no text is provided //but we should draw it in a different color //to give indication that it is not text you typed in - if (0 == mText.length() && mReadOnly) + if (0 == mText.length() && (mReadOnly || mShowLabelFocused)) { mGLFont->render(mLabel.getWString(), 0, mTextLeftEdge, (F32)text_bottom, diff --git a/indra/llui/lllineeditor.h b/indra/llui/lllineeditor.h index ae4e05c065..624371ebda 100644 --- a/indra/llui/lllineeditor.h +++ b/indra/llui/lllineeditor.h @@ -91,6 +91,7 @@ public: commit_on_focus_lost, ignore_tab, bg_image_always_focused, + show_label_focused, is_password, use_bg_color; @@ -395,6 +396,7 @@ protected: BOOL mReadOnly; BOOL mShowImageFocused; + BOOL mShowLabelFocused; bool mUseBgColor; -- cgit v1.2.3 From 264d9c32d9e04df0ceeaf2a63f6872aad29dd46a Mon Sep 17 00:00:00 2001 From: Alexander Gavriliuk Date: Fri, 28 Jul 2023 18:42:57 +0200 Subject: SL-20088 EmojiPicker - replace the image on the activation button with an emoji --- indra/llui/lluistring.h | 1 + 1 file changed, 1 insertion(+) (limited to 'indra/llui') diff --git a/indra/llui/lluistring.h b/indra/llui/lluistring.h index 07e02de6d8..b1089a3903 100644 --- a/indra/llui/lluistring.h +++ b/indra/llui/lluistring.h @@ -61,6 +61,7 @@ public: LLUIString() : mArgs(NULL), mNeedsResult(false), mNeedsWResult(false) {} LLUIString(const std::string& instring, const LLStringUtil::format_map_t& args); LLUIString(const std::string& instring) : mArgs(NULL) { assign(instring); } + LLUIString(const LLWString& instring) : mArgs(NULL) { insert(0, instring); } ~LLUIString() { delete mArgs; } void assign(const std::string& instring); -- cgit v1.2.3 From 031032fb892560a0f5fa1a996aea77f593f54704 Mon Sep 17 00:00:00 2001 From: Alexander Gavriliuk Date: Tue, 29 Aug 2023 13:12:09 +0200 Subject: SL-20211 EmojiPicker - The search field should be the same as other floaters --- indra/llui/llsearcheditor.cpp | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'indra/llui') diff --git a/indra/llui/llsearcheditor.cpp b/indra/llui/llsearcheditor.cpp index bafeef41fb..cfaf08ec0a 100644 --- a/indra/llui/llsearcheditor.cpp +++ b/indra/llui/llsearcheditor.cpp @@ -178,6 +178,10 @@ void LLSearchEditor::setFocus( BOOL b ) void LLSearchEditor::onClearButtonClick(const LLSD& data) { setText(LLStringUtil::null); + if (mTextChangedCallback) + { + mTextChangedCallback(this, getValue()); + } mSearchEditor->onCommit(); // force keystroke callback } -- cgit v1.2.3 From c30208d598d43779cea7b5de50c44d4b21b16487 Mon Sep 17 00:00:00 2001 From: Alexander Gavriliuk Date: Fri, 8 Sep 2023 01:02:06 +0200 Subject: SL-19951 Organize emoji categories in groups (fix for German) --- indra/llui/llemojidictionary.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'indra/llui') diff --git a/indra/llui/llemojidictionary.cpp b/indra/llui/llemojidictionary.cpp index cdcf5a93d6..89758f538b 100644 --- a/indra/llui/llemojidictionary.cpp +++ b/indra/llui/llemojidictionary.cpp @@ -204,7 +204,8 @@ void LLEmojiDictionary::loadTranslations() { const LLSD& sd = *it; const std::string& name = sd["Name"].asStringRef(); - const std::string& category = sd["Category"].asStringRef(); + std::string category = sd["Category"].asString(); + LLStringUtil::toLower(category); if (!name.empty() && !category.empty()) { mTranslations[name] = category; -- cgit v1.2.3 From 29a3295c82fb65143f8eea7e27c61436a19b4272 Mon Sep 17 00:00:00 2001 From: Alexander Gavriliuk Date: Fri, 8 Sep 2023 12:19:21 +0200 Subject: SL-19951 EmojiPicker - preserve original character case for German categories --- indra/llui/llemojidictionary.cpp | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) (limited to 'indra/llui') diff --git a/indra/llui/llemojidictionary.cpp b/indra/llui/llemojidictionary.cpp index 89758f538b..1ee97ea2d2 100644 --- a/indra/llui/llemojidictionary.cpp +++ b/indra/llui/llemojidictionary.cpp @@ -204,8 +204,7 @@ void LLEmojiDictionary::loadTranslations() { const LLSD& sd = *it; const std::string& name = sd["Name"].asStringRef(); - std::string category = sd["Category"].asString(); - LLStringUtil::toLower(category); + const std::string& category = sd["Category"].asStringRef(); if (!name.empty() && !category.empty()) { mTranslations[name] = category; @@ -373,22 +372,17 @@ llwchar LLEmojiDictionary::loadIcon(const LLSD& sd) return (1 == icon.size()) ? icon[0] : L'\0'; } -static inline std::list loadStrings(const LLSD& sd, const std::string key) -{ - auto toLower = [](std::string& str) { LLStringUtil::toLower(str); }; - return llsd_array_to_list(sd[key], toLower); -} - std::list LLEmojiDictionary::loadCategories(const LLSD& sd) { - static const std::string categoriesKey("Categories"); - return loadStrings(sd, categoriesKey); + static const std::string key("Categories"); + return llsd_array_to_list(sd[key]); } std::list LLEmojiDictionary::loadShortCodes(const LLSD& sd) { - static const std::string shortCodesKey("ShortCodes"); - return loadStrings(sd, shortCodesKey); + static const std::string key("ShortCodes"); + auto toLower = [](std::string& str) { LLStringUtil::toLower(str); }; + return llsd_array_to_list(sd[key], toLower); } void LLEmojiDictionary::translateCategories(std::list& categories) -- cgit v1.2.3 From 317041be0dca02cf0667abad472db51fd7e69ded Mon Sep 17 00:00:00 2001 From: Alexander Gavriliuk Date: Mon, 2 Oct 2023 09:35:50 +0200 Subject: SL-20356 Allow menu navigation by tabbing around emoji menu --- indra/llui/llview.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'indra/llui') diff --git a/indra/llui/llview.cpp b/indra/llui/llview.cpp index 8716e6b338..a8eada59b2 100644 --- a/indra/llui/llview.cpp +++ b/indra/llui/llview.cpp @@ -514,7 +514,7 @@ BOOL LLView::focusNext(LLView::child_list_t & result) { next = result.rbegin(); } - if((*next)->isCtrl()) + if ((*next)->isCtrl() && ((LLUICtrl*)*next)->hasTabStop()) { LLUICtrl * ctrl = static_cast(*next); ctrl->setFocus(TRUE); -- cgit v1.2.3 From f36f50462e226308424d57298aa29c4dccfef6e2 Mon Sep 17 00:00:00 2001 From: Alexander Gavriliuk Date: Mon, 2 Oct 2023 14:08:31 +0200 Subject: SL-20387 Show Emoji Completion floater at the beginning of the shortcode --- indra/llui/llemojihelper.cpp | 3 ++- indra/llui/lltexteditor.cpp | 11 +++++++---- 2 files changed, 9 insertions(+), 5 deletions(-) (limited to 'indra/llui') diff --git a/indra/llui/llemojihelper.cpp b/indra/llui/llemojihelper.cpp index fb660a9e5b..1d7744cb55 100644 --- a/indra/llui/llemojihelper.cpp +++ b/indra/llui/llemojihelper.cpp @@ -37,7 +37,7 @@ // constexpr char DEFAULT_EMOJI_HELPER_FLOATER[] = "emoji_complete"; -constexpr S32 HELPER_FLOATER_OFFSET_X = 20; +constexpr S32 HELPER_FLOATER_OFFSET_X = 0; constexpr S32 HELPER_FLOATER_OFFSET_Y = 0; // ============================================================================ @@ -113,6 +113,7 @@ void LLEmojiHelper::showHelper(LLUICtrl* hostctrl_p, S32 local_x, S32 local_y, c rct.setLeftTopAndSize(floater_x - HELPER_FLOATER_OFFSET_X, floater_y - HELPER_FLOATER_OFFSET_Y + rct.getHeight(), rct.getWidth(), rct.getHeight()); pHelperFloater->setRect(rct); pHelperFloater->openFloater(LLSD().with("hint", short_code)); + gFloaterView->adjustToFitScreen(pHelperFloater, FALSE); } void LLEmojiHelper::hideHelper(const LLUICtrl* ctrl_p) diff --git a/indra/llui/lltexteditor.cpp b/indra/llui/lltexteditor.cpp index 95d8b666ab..4467496146 100644 --- a/indra/llui/lltexteditor.cpp +++ b/indra/llui/lltexteditor.cpp @@ -1169,12 +1169,15 @@ void LLTextEditor::addChar(llwchar wc) if (!mReadOnly && mShowEmojiHelper) { - LLWString wtext(getWText()); S32 shortCodePos; + S32 shortCodePos; + LLWString wtext(getWText()); if (LLEmojiHelper::isCursorInEmojiCode(wtext, mCursorPos, &shortCodePos)) { - const LLRect cursorRect = getLocalRectFromDocIndex(mCursorPos - 1); - const LLWString shortCode = wtext.substr(shortCodePos, mCursorPos - shortCodePos); - LLEmojiHelper::instance().showHelper(this, cursorRect.mLeft, cursorRect.mTop, wstring_to_utf8str(shortCode), std::bind(&LLTextEditor::handleEmojiCommit, this, std::placeholders::_1)); + const LLRect cursorRect(getLocalRectFromDocIndex(shortCodePos)); + const LLWString wpart(wtext.substr(shortCodePos, mCursorPos - shortCodePos)); + const std::string part(wstring_to_utf8str(wpart)); + auto cb = [this](llwchar emoji) { handleEmojiCommit(emoji); }; + LLEmojiHelper::instance().showHelper(this, cursorRect.mLeft, cursorRect.mTop, part, cb); } } -- cgit v1.2.3 From c3adae2a5ff3912ffb741b84a5d098d078da062b Mon Sep 17 00:00:00 2001 From: Alexander Gavriliuk Date: Mon, 2 Oct 2023 15:09:39 +0200 Subject: SL-20391 Show Emoji Completion floater after backspacing a character --- indra/llui/lltexteditor.cpp | 53 ++++++++++++++++++++++++++------------------- indra/llui/lltexteditor.h | 1 + 2 files changed, 32 insertions(+), 22 deletions(-) (limited to 'indra/llui') diff --git a/indra/llui/lltexteditor.cpp b/indra/llui/lltexteditor.cpp index 4467496146..7aef056e5a 100644 --- a/indra/llui/lltexteditor.cpp +++ b/indra/llui/lltexteditor.cpp @@ -1022,7 +1022,7 @@ S32 LLTextEditor::remove(S32 pos, S32 length, bool group_with_next_op) // store text segments getSegmentsInRange(segments_to_remove, pos, pos + length, false); - if(pos <= end_pos) + if (pos <= end_pos) { removedChar = execute( new TextCmdRemove( pos, group_with_next_op, end_pos - pos, segments_to_remove ) ); } @@ -1046,11 +1046,12 @@ S32 LLTextEditor::overwriteChar(S32 pos, llwchar wc) // a pseudo-tab (up to for spaces in a row) void LLTextEditor::removeCharOrTab() { - if( !getEnabled() ) + if (!getEnabled()) { return; } - if( mCursorPos > 0 ) + + if (mCursorPos > 0) { S32 chars_to_remove = 1; @@ -1062,14 +1063,14 @@ void LLTextEditor::removeCharOrTab() if (offset > 0) { chars_to_remove = offset % SPACES_PER_TAB; - if( chars_to_remove == 0 ) + if (chars_to_remove == 0) { chars_to_remove = SPACES_PER_TAB; } - for( S32 i = 0; i < chars_to_remove; i++ ) + for (S32 i = 0; i < chars_to_remove; i++) { - if (text[ mCursorPos - i - 1] != ' ') + if (text[mCursorPos - i - 1] != ' ') { // Fewer than a full tab's worth of spaces, so // just delete a single character. @@ -1083,8 +1084,10 @@ void LLTextEditor::removeCharOrTab() for (S32 i = 0; i < chars_to_remove; i++) { setCursorPos(mCursorPos - 1); - remove( mCursorPos, 1, FALSE ); + remove(mCursorPos, 1, false); } + + tryToShowEmojiHelper(); } else { @@ -1095,7 +1098,7 @@ void LLTextEditor::removeCharOrTab() // Remove a single character from the text S32 LLTextEditor::removeChar(S32 pos) { - return remove( pos, 1, FALSE ); + return remove(pos, 1, false); } void LLTextEditor::removeChar() @@ -1104,10 +1107,12 @@ void LLTextEditor::removeChar() { return; } + if (mCursorPos > 0) { setCursorPos(mCursorPos - 1); removeChar(mCursorPos); + tryToShowEmojiHelper(); } else { @@ -1166,20 +1171,7 @@ void LLTextEditor::addChar(llwchar wc) } setCursorPos(mCursorPos + addChar( mCursorPos, wc )); - - if (!mReadOnly && mShowEmojiHelper) - { - S32 shortCodePos; - LLWString wtext(getWText()); - if (LLEmojiHelper::isCursorInEmojiCode(wtext, mCursorPos, &shortCodePos)) - { - const LLRect cursorRect(getLocalRectFromDocIndex(shortCodePos)); - const LLWString wpart(wtext.substr(shortCodePos, mCursorPos - shortCodePos)); - const std::string part(wstring_to_utf8str(wpart)); - auto cb = [this](llwchar emoji) { handleEmojiCommit(emoji); }; - LLEmojiHelper::instance().showHelper(this, cursorRect.mLeft, cursorRect.mTop, part, cb); - } - } + tryToShowEmojiHelper(); if (!mReadOnly && mAutoreplaceCallback != NULL) { @@ -1199,6 +1191,23 @@ void LLTextEditor::addChar(llwchar wc) } } +void LLTextEditor::tryToShowEmojiHelper() +{ + if (mReadOnly || !mShowEmojiHelper) + return; + + S32 shortCodePos; + LLWString wtext(getWText()); + if (LLEmojiHelper::isCursorInEmojiCode(wtext, mCursorPos, &shortCodePos)) + { + const LLRect cursorRect(getLocalRectFromDocIndex(shortCodePos)); + const LLWString wpart(wtext.substr(shortCodePos, mCursorPos - shortCodePos)); + const std::string part(wstring_to_utf8str(wpart)); + auto cb = [this](llwchar emoji) { handleEmojiCommit(emoji); }; + LLEmojiHelper::instance().showHelper(this, cursorRect.mLeft, cursorRect.mTop, part, cb); + } +} + void LLTextEditor::addLineBreakChar(BOOL group_together) { if( !getEnabled() ) diff --git a/indra/llui/lltexteditor.h b/indra/llui/lltexteditor.h index f830732cb8..7a96e17899 100644 --- a/indra/llui/lltexteditor.h +++ b/indra/llui/lltexteditor.h @@ -255,6 +255,7 @@ protected: S32 insert(S32 pos, const LLWString &wstr, bool group_with_next_op, LLTextSegmentPtr segment); S32 remove(S32 pos, S32 length, bool group_with_next_op); + void tryToShowEmojiHelper(); void focusLostHelper(); void updateAllowingLanguageInput(); BOOL hasPreeditString() const; -- cgit v1.2.3 From be655fef7f1f5717df73dedf84e84b73d246a0ec Mon Sep 17 00:00:00 2001 From: Alexander Gavriliuk Date: Tue, 3 Oct 2023 13:54:07 +0200 Subject: :x --- indra/llui/llemojihelper.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'indra/llui') diff --git a/indra/llui/llemojihelper.cpp b/indra/llui/llemojihelper.cpp index 1d7744cb55..9411f7cac5 100644 --- a/indra/llui/llemojihelper.cpp +++ b/indra/llui/llemojihelper.cpp @@ -109,11 +109,12 @@ void LLEmojiHelper::showHelper(LLUICtrl* hostctrl_p, S32 local_x, S32 local_y, c } LLFloater* pHelperFloater = mHelperHandle.get(); - LLRect rct = pHelperFloater->getRect(); - rct.setLeftTopAndSize(floater_x - HELPER_FLOATER_OFFSET_X, floater_y - HELPER_FLOATER_OFFSET_Y + rct.getHeight(), rct.getWidth(), rct.getHeight()); - pHelperFloater->setRect(rct); + LLRect rect = pHelperFloater->getRect(); + S32 left = floater_x - HELPER_FLOATER_OFFSET_X; + S32 top = floater_y - HELPER_FLOATER_OFFSET_Y + rect.getHeight(); + rect.setLeftTopAndSize(left, top, rect.getWidth(), rect.getHeight()); + pHelperFloater->setRect(rect); pHelperFloater->openFloater(LLSD().with("hint", short_code)); - gFloaterView->adjustToFitScreen(pHelperFloater, FALSE); } void LLEmojiHelper::hideHelper(const LLUICtrl* ctrl_p) -- cgit v1.2.3 From 9f8763cae1ccb3577a2cd148ffc5cee564a2df65 Mon Sep 17 00:00:00 2001 From: Alexander Gavriliuk Date: Wed, 4 Oct 2023 22:30:48 +0200 Subject: SL-20402 Emoji Completion floater - use vertical scrollbar when needed --- indra/llui/llscrollbar.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'indra/llui') diff --git a/indra/llui/llscrollbar.cpp b/indra/llui/llscrollbar.cpp index fde6de4921..d5d0d97b55 100644 --- a/indra/llui/llscrollbar.cpp +++ b/indra/llui/llscrollbar.cpp @@ -475,13 +475,15 @@ void LLScrollbar::reshape(S32 width, S32 height, BOOL called_from_parent) { up_button->reshape(up_button->getRect().getWidth(), llmin(getRect().getHeight() / 2, mThickness)); down_button->reshape(down_button->getRect().getWidth(), llmin(getRect().getHeight() / 2, mThickness)); - up_button->setOrigin(up_button->getRect().mLeft, getRect().getHeight() - up_button->getRect().getHeight()); + up_button->setOrigin(0, getRect().getHeight() - up_button->getRect().getHeight()); + down_button->setOrigin(0, 0); } else { up_button->reshape(llmin(getRect().getWidth() / 2, mThickness), up_button->getRect().getHeight()); down_button->reshape(llmin(getRect().getWidth() / 2, mThickness), down_button->getRect().getHeight()); - down_button->setOrigin(getRect().getWidth() - down_button->getRect().getWidth(), down_button->getRect().mBottom); + up_button->setOrigin(0, 0); + down_button->setOrigin(getRect().getWidth() - down_button->getRect().getWidth(), 0); } updateThumbRect(); } -- cgit v1.2.3 From 98214577c36d9c8dd0e13c7b678a399b35450bd3 Mon Sep 17 00:00:00 2001 From: Alexander Gavriliuk Date: Thu, 5 Oct 2023 11:28:54 +0200 Subject: SL-20390 Emoji Completion floater - ignore symbols in shortcodes when searching by pattern --- indra/llui/llemojidictionary.cpp | 64 ++++++++++++++++++++++++++++++++++++++++ indra/llui/llemojidictionary.h | 20 +++++++++++++ 2 files changed, 84 insertions(+) (limited to 'indra/llui') diff --git a/indra/llui/llemojidictionary.cpp b/indra/llui/llemojidictionary.cpp index 1ee97ea2d2..bf7e53701d 100644 --- a/indra/llui/llemojidictionary.cpp +++ b/indra/llui/llemojidictionary.cpp @@ -143,6 +143,70 @@ LLWString LLEmojiDictionary::findMatchingEmojis(const std::string& needle) const return result; } +void LLEmojiDictionary::findByShortCode(std::vector& result, const std::string& needle) const +{ + result.clear(); + + if (needle.empty() || needle.front() != ':') + return; + + auto search = [needle](std::size_t& begin, std::size_t& end, const std::string& shortCode) -> bool + { + begin = 0; + end = 1; + std::size_t index = 1; + // Search for begin + char d = tolower(needle[index++]); + while (end < shortCode.size()) + { + char s = tolower(shortCode[end++]); + if (s == d) + { + begin = end - 1; + break; + } + } + if (!begin) + return false; + // Search for end + d = tolower(needle[index++]); + while (end < shortCode.size() && index <= needle.size()) + { + char s = tolower(shortCode[end++]); + if (s == d) + { + if (index == needle.size()) + return true; + d = tolower(needle[index++]); + continue; + } + switch (s) + { + case L'-': + case L'_': + case L'+': + continue; + } + break; + } + return false; + }; + + for (const LLEmojiDescriptor& d : mEmojis) + { + if (d.ShortCodes.empty()) + continue; + const std::string& shortCode = d.ShortCodes.front(); + if (shortCode.size() < needle.size() || shortCode.front() != needle.front()) + continue; + std::size_t begin, end; + if (search(begin, end, shortCode)) + { + result.emplace_back(d.Character, shortCode, begin, end); + } + } +} + const LLEmojiDescriptor* LLEmojiDictionary::getDescriptorFromEmoji(llwchar emoji) const { const auto it = mEmoji2Descr.find(emoji); diff --git a/indra/llui/llemojidictionary.h b/indra/llui/llemojidictionary.h index f6442684a7..66b564b70a 100644 --- a/indra/llui/llemojidictionary.h +++ b/indra/llui/llemojidictionary.h @@ -52,6 +52,25 @@ struct LLEmojiGroup std::list Categories; }; +// ============================================================================ +// LLEmojiSearchResult class +// + +struct LLEmojiSearchResult +{ + llwchar Character; + std::string String; + std::size_t Begin, End; + + LLEmojiSearchResult(llwchar character, const std::string& string, std::size_t begin, std::size_t end) + : Character(character) + , String(string) + , Begin(begin) + , End(end) + { + } +}; + // ============================================================================ // LLEmojiDictionary class // @@ -70,6 +89,7 @@ public: static void initClass(); LLWString findMatchingEmojis(const std::string& needle) const; + void findByShortCode(std::vector& result, const std::string& needle) const; const LLEmojiDescriptor* getDescriptorFromEmoji(llwchar emoji) const; const LLEmojiDescriptor* getDescriptorFromShortCode(const std::string& short_code) const; std::string getNameFromEmoji(llwchar ch) const; -- cgit v1.2.3 From f9a4266e2ffd49e38d2d9bb536cd6af5009c4868 Mon Sep 17 00:00:00 2001 From: Alexander Gavriliuk Date: Thu, 5 Oct 2023 18:30:34 +0200 Subject: SL-20355 Sort completion suggestions by position of the search pattern --- indra/llui/llemojidictionary.cpp | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) (limited to 'indra/llui') diff --git a/indra/llui/llemojidictionary.cpp b/indra/llui/llemojidictionary.cpp index bf7e53701d..e29f3436cf 100644 --- a/indra/llui/llemojidictionary.cpp +++ b/indra/llui/llemojidictionary.cpp @@ -192,6 +192,8 @@ void LLEmojiDictionary::findByShortCode(std::vector& result return false; }; + std::map> results; + for (const LLEmojiDescriptor& d : mEmojis) { if (d.ShortCodes.empty()) @@ -202,9 +204,18 @@ void LLEmojiDictionary::findByShortCode(std::vector& result std::size_t begin, end; if (search(begin, end, shortCode)) { - result.emplace_back(d.Character, shortCode, begin, end); + results[begin].emplace_back(d.Character, shortCode, begin, end); } } + + for (const auto& it : results) + { +#ifdef __cpp_lib_containers_ranges + result.append_range(it.second); +#else + result.insert(result.end(), it.second.cbegin(), it.second.cend()); +#endif + } } const LLEmojiDescriptor* LLEmojiDictionary::getDescriptorFromEmoji(llwchar emoji) const -- cgit v1.2.3 From 80bdfe3b5eec180e563bb0887bdc986f76dfd6f9 Mon Sep 17 00:00:00 2001 From: Alexander Gavriliuk Date: Tue, 10 Oct 2023 23:18:41 +0200 Subject: SL-20288 Lags in Appearance floater (code format in LLAccordionCtrl) --- indra/llui/llaccordionctrl.cpp | 330 ++++++++++++++++----------------- indra/llui/llaccordionctrl.h | 2 +- indra/llui/llaccordionctrltab.cpp | 371 ++++++++++++++++++++------------------ indra/llui/llaccordionctrltab.h | 2 +- indra/llui/llflatlistview.cpp | 52 +++--- 5 files changed, 387 insertions(+), 370 deletions(-) (limited to 'indra/llui') diff --git a/indra/llui/llaccordionctrl.cpp b/indra/llui/llaccordionctrl.cpp index 809d72208f..0a82bed896 100644 --- a/indra/llui/llaccordionctrl.cpp +++ b/indra/llui/llaccordionctrl.cpp @@ -60,7 +60,7 @@ LLAccordionCtrl::LLAccordionCtrl(const Params& params):LLPanel(params) initNoTabsWidget(params.no_matched_tabs_text); mSingleExpansion = params.single_expansion; - if(mFitParent && !mSingleExpansion) + if (mFitParent && !mSingleExpansion) { LL_INFOS() << "fit_parent works best when combined with single_expansion" << LL_ENDL; } @@ -102,14 +102,13 @@ void LLAccordionCtrl::draw() LLPanel::draw(); } - //--------------------------------------------------------------------------------- BOOL LLAccordionCtrl::postBuild() { - static LLUICachedControl scrollbar_size ("UIScrollbarSize", 0); + static LLUICachedControl scrollbar_size("UIScrollbarSize", 0); LLRect scroll_rect; - scroll_rect.setOriginAndSize( + scroll_rect.setOriginAndSize( getRect().getWidth() - scrollbar_size, 1, scrollbar_size, @@ -126,39 +125,42 @@ BOOL LLAccordionCtrl::postBuild() sbparams.follows.flags(FOLLOWS_RIGHT | FOLLOWS_TOP | FOLLOWS_BOTTOM); sbparams.change_callback(boost::bind(&LLAccordionCtrl::onScrollPosChangeCallback, this, _1, _2)); - mScrollbar = LLUICtrlFactory::create (sbparams); - LLView::addChild( mScrollbar ); - mScrollbar->setVisible( false ); + mScrollbar = LLUICtrlFactory::create(sbparams); + LLView::addChild(mScrollbar); + mScrollbar->setVisible(FALSE); mScrollbar->setFollowsRight(); mScrollbar->setFollowsTop(); mScrollbar->setFollowsBottom(); //if it was created from xml... std::vector accordion_tabs; - for(child_list_const_iter_t it = getChildList()->begin(); + for (child_list_const_iter_t it = getChildList()->begin(); getChildList()->end() != it; ++it) { LLAccordionCtrlTab* accordion_tab = dynamic_cast(*it); - if(accordion_tab == NULL) + if (accordion_tab == NULL) continue; - if(std::find(mAccordionTabs.begin(),mAccordionTabs.end(),accordion_tab) == mAccordionTabs.end()) + if (std::find(mAccordionTabs.begin(), mAccordionTabs.end(), accordion_tab) == mAccordionTabs.end()) { accordion_tabs.push_back(accordion_tab); } } - for(std::vector::reverse_iterator it = accordion_tabs.rbegin();it!=accordion_tabs.rend();++it) + for (std::vector::reverse_iterator it = accordion_tabs.rbegin(); + it < accordion_tabs.rend(); ++it) + { addCollapsibleCtrl(*it); + } - arrange (); + arrange(); - if(mSingleExpansion) + if (mSingleExpansion) { - if(!mAccordionTabs[0]->getDisplayChildren()) + if (!mAccordionTabs[0]->getDisplayChildren()) mAccordionTabs[0]->setDisplayChildren(true); - for(size_t i=1;igetDisplayChildren()) + if (mAccordionTabs[i]->getDisplayChildren()) mAccordionTabs[i]->setDisplayChildren(false); } } @@ -205,23 +207,22 @@ BOOL LLAccordionCtrl::handleRightMouseDown(S32 x, S32 y, MASK mask) //--------------------------------------------------------------------------------- void LLAccordionCtrl::shiftAccordionTabs(S16 panel_num, S32 delta) { - for(size_t i = panel_num; i < mAccordionTabs.size(); i++ ) + for (size_t i = panel_num; i < mAccordionTabs.size(); ++i) { ctrlShiftVertical(mAccordionTabs[i],delta); } } - //--------------------------------------------------------------------------------- void LLAccordionCtrl::onCollapseCtrlCloseOpen(S16 panel_num) { - if(mSingleExpansion) + if (mSingleExpansion) { - for(size_t i=0;igetDisplayChildren()) + if (mAccordionTabs[i]->getDisplayChildren()) mAccordionTabs[i]->setDisplayChildren(false); } @@ -232,64 +233,63 @@ void LLAccordionCtrl::onCollapseCtrlCloseOpen(S16 panel_num) void LLAccordionCtrl::show_hide_scrollbar(S32 width, S32 height) { calcRecuiredHeight(); - if(getRecuiredHeight() > height ) - showScrollbar(width,height); + if (getRecuiredHeight() > height) + showScrollbar(width, height); else - hideScrollbar(width,height); + hideScrollbar(width, height); } -void LLAccordionCtrl::showScrollbar(S32 width, S32 height) +void LLAccordionCtrl::showScrollbar(S32 width, S32 height) { bool was_visible = mScrollbar->getVisible(); - mScrollbar->setVisible(true); + mScrollbar->setVisible(TRUE); static LLUICachedControl scrollbar_size ("UIScrollbarSize", 0); ctrlSetLeftTopAndSize(mScrollbar - ,width-scrollbar_size - PARENT_BORDER_MARGIN/2 - ,height-PARENT_BORDER_MARGIN - ,scrollbar_size - ,height-2*PARENT_BORDER_MARGIN); + , width - scrollbar_size - PARENT_BORDER_MARGIN / 2 + , height - PARENT_BORDER_MARGIN + , scrollbar_size + , height - PARENT_BORDER_MARGIN * 2); mScrollbar->setPageSize(height); - mScrollbar->setDocParams(mInnerRect.getHeight(),mScrollbar->getDocPos()); + mScrollbar->setDocParams(mInnerRect.getHeight(), mScrollbar->getDocPos()); - if(was_visible) + if (was_visible) { S32 scroll_pos = llmin(mScrollbar->getDocPos(), getRecuiredHeight() - height - 1); mScrollbar->setDocPos(scroll_pos); } } -void LLAccordionCtrl::hideScrollbar( S32 width, S32 height ) +void LLAccordionCtrl::hideScrollbar(S32 width, S32 height) { - if(mScrollbar->getVisible() == false) + if (mScrollbar->getVisible() == FALSE) return; - mScrollbar->setVisible(false); + mScrollbar->setVisible(FALSE); static LLUICachedControl scrollbar_size ("UIScrollbarSize", 0); S32 panel_width = width - 2*BORDER_MARGIN; - //reshape all accordeons and shift all draggers - for(size_t i=0;igetRect(); - ctrlSetLeftTopAndSize(mAccordionTabs[i],panel_rect.mLeft,panel_rect.mTop,panel_width,panel_rect.getHeight()); + ctrlSetLeftTopAndSize(mAccordionTabs[i], panel_rect.mLeft, panel_rect.mTop, panel_width, panel_rect.getHeight()); } mScrollbar->setDocPos(0); - if(mAccordionTabs.size()>0) + if (!mAccordionTabs.empty()) { - S32 panel_top = height - BORDER_MARGIN; // Top coordinate of the first panel + S32 panel_top = height - BORDER_MARGIN; // Top coordinate of the first panel S32 diff = panel_top - mAccordionTabs[0]->getRect().mTop; - shiftAccordionTabs(0,diff); + shiftAccordionTabs(0, diff); } } - //--------------------------------------------------------------------------------- S32 LLAccordionCtrl::calcRecuiredHeight() { @@ -305,7 +305,7 @@ S32 LLAccordionCtrl::calcRecuiredHeight() } } - mInnerRect.setLeftTopAndSize(0,rec_height + BORDER_MARGIN*2,getRect().getWidth(),rec_height + BORDER_MARGIN); + mInnerRect.setLeftTopAndSize(0, rec_height + BORDER_MARGIN * 2, getRect().getWidth(), rec_height + BORDER_MARGIN); return mInnerRect.getHeight(); } @@ -313,7 +313,7 @@ S32 LLAccordionCtrl::calcRecuiredHeight() //--------------------------------------------------------------------------------- void LLAccordionCtrl::ctrlSetLeftTopAndSize(LLView* panel, S32 left, S32 top, S32 width, S32 height) { - if(!panel) + if (!panel) return; LLRect panel_rect = panel->getRect(); panel_rect.setLeftTopAndSize( left, top, width, height); @@ -321,9 +321,9 @@ void LLAccordionCtrl::ctrlSetLeftTopAndSize(LLView* panel, S32 left, S32 top, S3 panel->setRect(panel_rect); } -void LLAccordionCtrl::ctrlShiftVertical(LLView* panel,S32 delta) +void LLAccordionCtrl::ctrlShiftVertical(LLView* panel, S32 delta) { - if(!panel) + if (!panel) return; panel->translate(0,delta); } @@ -333,9 +333,9 @@ void LLAccordionCtrl::ctrlShiftVertical(LLView* panel,S32 delta) void LLAccordionCtrl::addCollapsibleCtrl(LLView* view) { LLAccordionCtrlTab* accordion_tab = dynamic_cast(view); - if(!accordion_tab) + if (!accordion_tab) return; - if(std::find(beginChild(), endChild(), accordion_tab) == endChild()) + if (std::find(beginChild(), endChild(), accordion_tab) == endChild()) addChild(accordion_tab); mAccordionTabs.push_back(accordion_tab); @@ -369,7 +369,7 @@ void LLAccordionCtrl::removeCollapsibleCtrl(LLView* view) } } -void LLAccordionCtrl::initNoTabsWidget(const LLTextBox::Params& tb_params) +void LLAccordionCtrl::initNoTabsWidget(const LLTextBox::Params& tb_params) { LLTextBox::Params tp = tb_params; tp.rect(getLocalRect()); @@ -377,39 +377,39 @@ void LLAccordionCtrl::initNoTabsWidget(const LLTextBox::Params& tb_params) mNoVisibleTabsHelpText = LLUICtrlFactory::create(tp, this); } -void LLAccordionCtrl::updateNoTabsHelpTextVisibility() +void LLAccordionCtrl::updateNoTabsHelpTextVisibility() { bool visible_exists = false; std::vector::const_iterator it = mAccordionTabs.begin(); const std::vector::const_iterator it_end = mAccordionTabs.end(); - for (; it != it_end; ++it) + while (it < it_end) { - if ((*it)->getVisible()) + if ((*(it++))->getVisible()) { visible_exists = true; break; } } - mNoVisibleTabsHelpText->setVisible(!visible_exists); + mNoVisibleTabsHelpText->setVisible(visible_exists ? FALSE : TRUE); } -void LLAccordionCtrl::arrangeSinge() +void LLAccordionCtrl::arrangeSingle() { - S32 panel_left = BORDER_MARGIN; // Margin from left side of Splitter - S32 panel_top = getRect().getHeight() - BORDER_MARGIN; // Top coordinate of the first panel - S32 panel_width = getRect().getWidth() - 4; // Top coordinate of the first panel + S32 panel_left = BORDER_MARGIN; // Margin from left side of Splitter + S32 panel_top = getRect().getHeight() - BORDER_MARGIN; // Top coordinate of the first panel + S32 panel_width = getRect().getWidth() - 4; S32 panel_height; S32 collapsed_height = 0; - for(size_t i=0;i(mAccordionTabs[i]); - if(accordion_tab->getVisible() == false) //skip hidden accordion tabs + if (accordion_tab->getVisible() == FALSE) // Skip hidden accordion tabs continue; - if(!accordion_tab->isExpanded() ) + if (!accordion_tab->isExpanded() ) { collapsed_height+=mAccordionTabs[i]->getRect().getHeight(); } @@ -417,28 +417,28 @@ void LLAccordionCtrl::arrangeSinge() S32 expanded_height = getRect().getHeight() - BORDER_MARGIN - collapsed_height; - for(size_t i=0;i(mAccordionTabs[i]); - if(accordion_tab->getVisible() == false) //skip hidden accordion tabs + if (accordion_tab->getVisible() == FALSE) // Skip hidden accordion tabs continue; - if(!accordion_tab->isExpanded() ) + if (!accordion_tab->isExpanded() ) { panel_height = accordion_tab->getRect().getHeight(); } else { - if(mFitParent) + if (mFitParent) { panel_height = expanded_height; } else { - if(accordion_tab->getAccordionView()) + if (accordion_tab->getAccordionView()) { panel_height = accordion_tab->getAccordionView()->getRect().getHeight() + - accordion_tab->getHeaderHeight() + 2*BORDER_MARGIN; + accordion_tab->getHeaderHeight() + BORDER_MARGIN * 2; } else { @@ -451,67 +451,67 @@ void LLAccordionCtrl::arrangeSinge() panel_height = llmax(panel_height, accordion_tab->getHeaderHeight()); ctrlSetLeftTopAndSize(mAccordionTabs[i], panel_left, panel_top, panel_width, panel_height); - panel_top-=mAccordionTabs[i]->getRect().getHeight(); + panel_top -= mAccordionTabs[i]->getRect().getHeight(); } show_hide_scrollbar(getRect().getWidth(), getRect().getHeight()); updateLayout(getRect().getWidth(), getRect().getHeight()); } -void LLAccordionCtrl::arrangeMultiple() +void LLAccordionCtrl::arrangeMultiple() { - S32 panel_left = BORDER_MARGIN; // Margin from left side of Splitter - S32 panel_top = getRect().getHeight() - BORDER_MARGIN; // Top coordinate of the first panel - S32 panel_width = getRect().getWidth() - 4; // Top coordinate of the first panel + S32 panel_left = BORDER_MARGIN; // Margin from left side of Splitter + S32 panel_top = getRect().getHeight() - BORDER_MARGIN; // Top coordinate of the first panel + S32 panel_width = getRect().getWidth() - 4; //Calculate params - for(size_t i = 0; i < mAccordionTabs.size(); i++ ) + for (size_t i = 0; i < mAccordionTabs.size(); i++ ) { LLAccordionCtrlTab* accordion_tab = dynamic_cast(mAccordionTabs[i]); - if(accordion_tab->getVisible() == false) //skip hidden accordion tabs + if (accordion_tab->getVisible() == FALSE) // Skip hidden accordion tabs continue; - if(!accordion_tab->isExpanded() ) + if (!accordion_tab->isExpanded() ) { ctrlSetLeftTopAndSize(mAccordionTabs[i], panel_left, panel_top, panel_width, accordion_tab->getRect().getHeight()); - panel_top-=mAccordionTabs[i]->getRect().getHeight(); + panel_top -= mAccordionTabs[i]->getRect().getHeight(); } else { S32 panel_height = accordion_tab->getRect().getHeight(); - if(mFitParent) + if (mFitParent) { - // all expanded tabs will have equal height + // All expanded tabs will have equal height panel_height = calcExpandedTabHeight(i, panel_top); ctrlSetLeftTopAndSize(accordion_tab, panel_left, panel_top, panel_width, panel_height); - // try to make accordion tab fit accordion view height. + // Try to make accordion tab fit accordion view height. // Accordion View should implement getRequiredRect() and provide valid height S32 optimal_height = accordion_tab->getAccordionView()->getRequiredRect().getHeight(); optimal_height += accordion_tab->getHeaderHeight() + 2 * BORDER_MARGIN; - if(optimal_height < panel_height) + if (optimal_height < panel_height) { panel_height = optimal_height; } // minimum tab height is equal to header height - if(mAccordionTabs[i]->getHeaderHeight() > panel_height) + if (mAccordionTabs[i]->getHeaderHeight() > panel_height) { panel_height = mAccordionTabs[i]->getHeaderHeight(); } } ctrlSetLeftTopAndSize(mAccordionTabs[i], panel_left, panel_top, panel_width, panel_height); - panel_top-=panel_height; + panel_top -= panel_height; } } - show_hide_scrollbar(getRect().getWidth(),getRect().getHeight()); + show_hide_scrollbar(getRect().getWidth(), getRect().getHeight()); - updateLayout(getRect().getWidth(),getRect().getHeight()); + updateLayout(getRect().getWidth(), getRect().getHeight()); } @@ -519,70 +519,67 @@ void LLAccordionCtrl::arrange() { updateNoTabsHelpTextVisibility(); - if( mAccordionTabs.size() == 0) + if (mAccordionTabs.empty()) { - //We do not arrange if we do not have what should be arranged + // Nothing to arrange return; } - - if(mAccordionTabs.size() == 1) + if (mAccordionTabs.size() == 1) { - S32 panel_top = getRect().getHeight() - BORDER_MARGIN; // Top coordinate of the first panel - S32 panel_width = getRect().getWidth() - 4; // Top coordinate of the first panel + S32 panel_top = getRect().getHeight() - BORDER_MARGIN; // Top coordinate of the first panel + S32 panel_width = getRect().getWidth() - 4; LLAccordionCtrlTab* accordion_tab = dynamic_cast(mAccordionTabs[0]); LLRect panel_rect = accordion_tab->getRect(); - S32 panel_height = getRect().getHeight() - 2*BORDER_MARGIN; - + S32 panel_height = getRect().getHeight() - BORDER_MARGIN * 2; if (accordion_tab->getFitParent()) panel_height = accordion_tab->getRect().getHeight(); - ctrlSetLeftTopAndSize(accordion_tab,panel_rect.mLeft,panel_top,panel_width,panel_height); + + ctrlSetLeftTopAndSize(accordion_tab, panel_rect.mLeft, panel_top, panel_width, panel_height); - show_hide_scrollbar(getRect().getWidth(),getRect().getHeight()); + show_hide_scrollbar(getRect().getWidth(), getRect().getHeight()); return; - } - if(mSingleExpansion) - arrangeSinge (); + if (mSingleExpansion) + arrangeSingle(); else - arrangeMultiple (); + arrangeMultiple(); } //--------------------------------------------------------------------------------- -BOOL LLAccordionCtrl::handleScrollWheel ( S32 x, S32 y, S32 clicks ) +BOOL LLAccordionCtrl::handleScrollWheel(S32 x, S32 y, S32 clicks) { - if(LLPanel::handleScrollWheel(x,y,clicks)) + if (LLPanel::handleScrollWheel(x, y, clicks)) return TRUE; - if( mScrollbar->getVisible() && mScrollbar->handleScrollWheel( 0, 0, clicks ) ) + if (mScrollbar->getVisible() && mScrollbar->handleScrollWheel(0, 0, clicks)) return TRUE; - return false; - + return FALSE; } -BOOL LLAccordionCtrl::handleKeyHere (KEY key, MASK mask) +BOOL LLAccordionCtrl::handleKeyHere(KEY key, MASK mask) { - if( mScrollbar->getVisible() && mScrollbar->handleKeyHere( key,mask ) ) + if (mScrollbar->getVisible() && mScrollbar->handleKeyHere(key, mask)) return TRUE; - return LLPanel::handleKeyHere(key,mask); + return LLPanel::handleKeyHere(key, mask); } -BOOL LLAccordionCtrl::handleDragAndDrop (S32 x, S32 y, MASK mask, - BOOL drop, - EDragAndDropType cargo_type, - void* cargo_data, - EAcceptance* accept, - std::string& tooltip_msg) +BOOL LLAccordionCtrl::handleDragAndDrop(S32 x, S32 y, MASK mask, + BOOL drop, + EDragAndDropType cargo_type, + void* cargo_data, + EAcceptance* accept, + std::string& tooltip_msg) { // Scroll folder view if needed. Never accepts a drag or drop. *accept = ACCEPT_NO; BOOL handled = autoScroll(x, y); - if( !handled ) + if (!handled) { handled = childrenHandleDragAndDrop(x, y, mask, drop, cargo_type, cargo_data, accept, tooltip_msg) != NULL; @@ -590,14 +587,14 @@ BOOL LLAccordionCtrl::handleDragAndDrop (S32 x, S32 y, MASK mask, return TRUE; } -BOOL LLAccordionCtrl::autoScroll (S32 x, S32 y) +BOOL LLAccordionCtrl::autoScroll(S32 x, S32 y) { static LLUICachedControl scrollbar_size ("UIScrollbarSize", 0); bool scrolling = false; - if( mScrollbar->getVisible() ) + if (mScrollbar->getVisible()) { - LLRect rect_local( 0, getRect().getHeight(), getRect().getWidth() - scrollbar_size, 0 ); + LLRect rect_local(0, getRect().getHeight(), getRect().getWidth() - scrollbar_size, 0); LLRect screen_local_extents; // clip rect against root view @@ -610,51 +607,52 @@ BOOL LLAccordionCtrl::autoScroll (S32 x, S32 y) LLRect bottom_scroll_rect = screen_local_extents; bottom_scroll_rect.mTop = rect_local.mBottom + auto_scroll_region_height; - if( bottom_scroll_rect.pointInRect( x, y ) && (mScrollbar->getDocPos() < mScrollbar->getDocPosMax()) ) + if (bottom_scroll_rect.pointInRect( x, y ) && (mScrollbar->getDocPos() < mScrollbar->getDocPosMax())) { - mScrollbar->setDocPos( mScrollbar->getDocPos() + auto_scroll_speed ); + mScrollbar->setDocPos(mScrollbar->getDocPos() + auto_scroll_speed); mAutoScrolling = true; scrolling = true; } LLRect top_scroll_rect = screen_local_extents; top_scroll_rect.mBottom = rect_local.mTop - auto_scroll_region_height; - if( top_scroll_rect.pointInRect( x, y ) && (mScrollbar->getDocPos() > 0) ) + if (top_scroll_rect.pointInRect(x, y) && (mScrollbar->getDocPos() > 0)) { - mScrollbar->setDocPos( mScrollbar->getDocPos() - auto_scroll_speed ); + mScrollbar->setDocPos(mScrollbar->getDocPos() - auto_scroll_speed); mAutoScrolling = true; scrolling = true; } } - return scrolling; + + return scrolling ? TRUE : FALSE; } -void LLAccordionCtrl::updateLayout (S32 width, S32 height) +void LLAccordionCtrl::updateLayout(S32 width, S32 height) { S32 panel_top = height - BORDER_MARGIN ; - if(mScrollbar->getVisible()) - panel_top+=mScrollbar->getDocPos(); + if (mScrollbar->getVisible()) + panel_top += mScrollbar->getDocPos(); - S32 panel_width = width - 2*BORDER_MARGIN; + S32 panel_width = width - BORDER_MARGIN * 2; static LLUICachedControl scrollbar_size ("UIScrollbarSize", 0); - if(mScrollbar->getVisible()) - panel_width-=scrollbar_size; + if (mScrollbar->getVisible()) + panel_width -= scrollbar_size; - //set sizes for first panels and dragbars - for(size_t i=0;igetVisible()) + if (!mAccordionTabs[i]->getVisible()) continue; LLRect panel_rect = mAccordionTabs[i]->getRect(); - ctrlSetLeftTopAndSize(mAccordionTabs[i],panel_rect.mLeft,panel_top,panel_width,panel_rect.getHeight()); - panel_top-=panel_rect.getHeight(); + ctrlSetLeftTopAndSize(mAccordionTabs[i], panel_rect.mLeft, panel_top, panel_width, panel_rect.getHeight()); + panel_top -= panel_rect.getHeight(); } } -void LLAccordionCtrl::onScrollPosChangeCallback(S32, LLScrollbar*) +void LLAccordionCtrl::onScrollPosChangeCallback(S32, LLScrollbar*) { - updateLayout(getRect().getWidth(),getRect().getHeight()); + updateLayout(getRect().getWidth(), getRect().getHeight()); } // virtual @@ -687,42 +685,43 @@ void LLAccordionCtrl::onUpdateScrollToChild(const LLUICtrl *cntrl) LLUICtrl::onUpdateScrollToChild(cntrl); } -void LLAccordionCtrl::onOpen (const LLSD& key) +void LLAccordionCtrl::onOpen(const LLSD& key) { - for(size_t i=0;i(mAccordionTabs[i]); LLPanel* panel = dynamic_cast(accordion_tab->getAccordionView()); - if(panel!=NULL) + if (panel != NULL) { panel->onOpen(key); } } } + S32 LLAccordionCtrl::notifyParent(const LLSD& info) { - if(info.has("action")) + if (info.has("action")) { std::string str_action = info["action"]; - if(str_action == "size_changes") + if (str_action == "size_changes") { // arrange(); return 1; } - else if(str_action == "select_next") + if (str_action == "select_next") { - for(size_t i=0;i(mAccordionTabs[i]); - if(accordion_tab->hasFocus()) + if (accordion_tab->hasFocus()) { - while(++igetVisible()) + if (mAccordionTabs[i]->getVisible()) break; } - if(i(mAccordionTabs[i]); accordion_tab->notify(LLSD().with("action","select_first")); @@ -733,17 +732,17 @@ S32 LLAccordionCtrl::notifyParent(const LLSD& info) } return 0; } - else if(str_action == "select_prev") + if (str_action == "select_prev") { - for(size_t i=0;i(mAccordionTabs[i]); - if(accordion_tab->hasFocus() && i>0) + if (accordion_tab->hasFocus() && i > 0) { bool prev_visible_tab_found = false; - while(i>0) + while (i > 0) { - if(mAccordionTabs[--i]->getVisible()) + if (mAccordionTabs[--i]->getVisible()) { prev_visible_tab_found = true; break; @@ -761,12 +760,12 @@ S32 LLAccordionCtrl::notifyParent(const LLSD& info) } return 0; } - else if(str_action == "select_current") + if (str_action == "select_current") { - for(size_t i=0;ihasFocus()) + if (mAccordionTabs[i]->hasFocus()) { if (mAccordionTabs[i] != mSelectedTab) { @@ -783,7 +782,7 @@ S32 LLAccordionCtrl::notifyParent(const LLSD& info) } return 0; } - else if(str_action == "deselect_current") + if (str_action == "deselect_current") { // Reset selection to the currently selected tab. if (mSelectedTab) @@ -802,9 +801,9 @@ S32 LLAccordionCtrl::notifyParent(const LLSD& info) screenRectToLocal(screen_rc, &local_rc); // Translate to parent coordinatess to check if we are in visible rectangle - local_rc.translate( getRect().mLeft, getRect().mBottom ); + local_rc.translate(getRect().mLeft, getRect().mBottom); - if ( !getRect().contains (local_rc) ) + if (!getRect().contains (local_rc)) { // Back to local coords and calculate position for scroller S32 bottom = mScrollbar->getDocPos() - local_rc.mBottom + getRect().mBottom; @@ -814,7 +813,7 @@ S32 LLAccordionCtrl::notifyParent(const LLSD& info) bottom, // min vertical scroll top); // max vertical scroll - mScrollbar->setDocPos( scroll_pos ); + mScrollbar->setDocPos(scroll_pos); } return 1; } @@ -834,15 +833,16 @@ S32 LLAccordionCtrl::notifyParent(const LLSD& info) } return LLPanel::notifyParent(info); } -void LLAccordionCtrl::reset () + +void LLAccordionCtrl::reset() { - if(mScrollbar) + if (mScrollbar) mScrollbar->setDocPos(0); } void LLAccordionCtrl::expandDefaultTab() { - if (mAccordionTabs.size() > 0) + if (!mAccordionTabs.empty()) { LLAccordionCtrlTab* tab = mAccordionTabs.front(); @@ -877,7 +877,7 @@ void LLAccordionCtrl::sort() arrange(); } -void LLAccordionCtrl::setFilterSubString(const std::string& filter_string) +void LLAccordionCtrl::setFilterSubString(const std::string& filter_string) { LLStringUtil::format_map_t args; args["[SEARCH_TERM]"] = LLURI::escape(filter_string); @@ -907,7 +907,7 @@ const LLAccordionCtrlTab* LLAccordionCtrl::getExpandedTab() const S32 LLAccordionCtrl::calcExpandedTabHeight(S32 tab_index /* = 0 */, S32 available_height /* = 0 */) { - if(tab_index < 0) + if (tab_index < 0) { return available_height; } @@ -915,9 +915,9 @@ S32 LLAccordionCtrl::calcExpandedTabHeight(S32 tab_index /* = 0 */, S32 availabl S32 collapsed_tabs_height = 0; S32 num_expanded = 0; - for(size_t n = tab_index; n < mAccordionTabs.size(); ++n) + for (size_t n = tab_index; n < mAccordionTabs.size(); ++n) { - if(!mAccordionTabs[n]->isExpanded()) + if (!mAccordionTabs[n]->isExpanded()) { collapsed_tabs_height += mAccordionTabs[n]->getHeaderHeight(); } @@ -927,7 +927,7 @@ S32 LLAccordionCtrl::calcExpandedTabHeight(S32 tab_index /* = 0 */, S32 availabl } } - if(0 == num_expanded) + if (0 == num_expanded) { return available_height; } diff --git a/indra/llui/llaccordionctrl.h b/indra/llui/llaccordionctrl.h index 2828254472..6a1989afba 100644 --- a/indra/llui/llaccordionctrl.h +++ b/indra/llui/llaccordionctrl.h @@ -144,7 +144,7 @@ private: void initNoTabsWidget(const LLTextBox::Params& tb_params); void updateNoTabsHelpTextVisibility(); - void arrangeSinge(); + void arrangeSingle(); void arrangeMultiple(); // Calc Splitter's height that is necessary to display all child content diff --git a/indra/llui/llaccordionctrltab.cpp b/indra/llui/llaccordionctrltab.cpp index 04485c6262..20da568746 100644 --- a/indra/llui/llaccordionctrltab.cpp +++ b/indra/llui/llaccordionctrltab.cpp @@ -69,13 +69,13 @@ public: virtual BOOL postBuild(); std::string getTitle(); - void setTitle(const std::string& title, const std::string& hl); + void setTitle(const std::string& title, const std::string& hl); - void setTitleFontStyle(std::string style); + void setTitleFontStyle(std::string style); - void setTitleColor(LLUIColor); + void setTitleColor(LLUIColor); - void setSelected(bool is_selected) { mIsSelected = is_selected; } + void setSelected(bool is_selected) { mIsSelected = is_selected; } virtual void onMouseEnter(S32 x, S32 y, MASK mask); virtual void onMouseLeave(S32 x, S32 y, MASK mask); @@ -85,8 +85,8 @@ public: void* cargo_data, EAcceptance* accept, std::string& tooltip_msg); -private: +private: LLTextBox* mHeaderTextbox; // Overlay images (arrows) @@ -102,7 +102,7 @@ private: LLPointer mImageHeaderFocused; // style saved when applying it in setTitleFontStyle - LLStyle::Params mStyleParams; + LLStyle::Params mStyleParams; LLUIColor mHeaderBGColor; @@ -157,19 +157,17 @@ BOOL LLAccordionCtrlTab::LLAccordionCtrlTabHeader::postBuild() std::string LLAccordionCtrlTab::LLAccordionCtrlTabHeader::getTitle() { - if(mHeaderTextbox) + if (mHeaderTextbox) { return mHeaderTextbox->getText(); } - else - { - return LLStringUtil::null; - } + + return LLStringUtil::null; } void LLAccordionCtrlTab::LLAccordionCtrlTabHeader::setTitle(const std::string& title, const std::string& hl) { - if(mHeaderTextbox) + if (mHeaderTextbox) { LLTextUtil::textboxSetHighlightedVal( mHeaderTextbox, @@ -192,7 +190,7 @@ void LLAccordionCtrlTab::LLAccordionCtrlTabHeader::setTitleFontStyle(std::string void LLAccordionCtrlTab::LLAccordionCtrlTabHeader::setTitleColor(LLUIColor color) { - if(mHeaderTextbox) + if (mHeaderTextbox) { mHeaderTextbox->setColor(color); } @@ -204,11 +202,11 @@ void LLAccordionCtrlTab::LLAccordionCtrlTabHeader::draw() S32 height = getRect().getHeight(); F32 alpha = getCurrentTransparency(); - gl_rect_2d(0,0,width - 1 ,height - 1,mHeaderBGColor.get() % alpha,true); + gl_rect_2d(0, 0, width - 1, height - 1, mHeaderBGColor.get() % alpha, TRUE); LLAccordionCtrlTab* parent = dynamic_cast(getParent()); - bool collapsible = (parent && parent->getCollapsible()); - bool expanded = (parent && parent->getDisplayChildren()); + bool collapsible = parent && parent->getCollapsible(); + bool expanded = parent && parent->getDisplayChildren(); // Handle overlay images, if needed // Only show green "focus" background image if the accordion is open, @@ -218,23 +216,22 @@ void LLAccordionCtrlTab::LLAccordionCtrlTabHeader::draw() /*&& !(collapsible && !expanded)*/ // WHY?? ) { - mImageHeaderFocused->draw(0,0,width,height); + mImageHeaderFocused->draw(0, 0, width, height); } else { - mImageHeader->draw(0,0,width,height); + mImageHeader->draw(0, 0, width, height); } - if(mNeedsHighlight) + if (mNeedsHighlight) { - mImageHeaderOver->draw(0,0,width,height); + mImageHeaderOver->draw(0, 0, width, height); } - - if(collapsible) + if (collapsible) { LLPointer overlay_image; - if(expanded) + if (expanded) { overlay_image = mImageExpanded; } @@ -242,8 +239,7 @@ void LLAccordionCtrlTab::LLAccordionCtrlTabHeader::draw() { overlay_image = mImageCollapsed; } - overlay_image->draw(HEADER_IMAGE_LEFT_OFFSET, - (height - overlay_image->getHeight()) / 2); + overlay_image->draw(HEADER_IMAGE_LEFT_OFFSET, (height - overlay_image->getHeight()) / 2); } LLUICtrl::draw(); @@ -253,7 +249,7 @@ void LLAccordionCtrlTab::LLAccordionCtrlTabHeader::reshape(S32 width, S32 height { S32 header_height = mHeaderTextbox->getTextPixelHeight(); - LLRect textboxRect(HEADER_TEXT_LEFT_OFFSET,(height+header_height)/2 ,width,(height-header_height)/2); + LLRect textboxRect(HEADER_TEXT_LEFT_OFFSET, (height + header_height) / 2, width, (height - header_height) / 2); mHeaderTextbox->reshape(textboxRect.getWidth(), textboxRect.getHeight()); mHeaderTextbox->setRect(textboxRect); @@ -272,20 +268,24 @@ void LLAccordionCtrlTab::LLAccordionCtrlTabHeader::onMouseEnter(S32 x, S32 y, MA LLUICtrl::onMouseEnter(x, y, mask); mNeedsHighlight = true; } + void LLAccordionCtrlTab::LLAccordionCtrlTabHeader::onMouseLeave(S32 x, S32 y, MASK mask) { LLUICtrl::onMouseLeave(x, y, mask); mNeedsHighlight = false; mAutoOpenTimer.stop(); } + BOOL LLAccordionCtrlTab::LLAccordionCtrlTabHeader::handleKey(KEY key, MASK mask, BOOL called_from_parent) { - if ( ( key == KEY_LEFT || key == KEY_RIGHT) && mask == MASK_NONE) + if ((key == KEY_LEFT || key == KEY_RIGHT) && mask == MASK_NONE) { return getParent()->handleKey(key, mask, called_from_parent); } + return LLUICtrl::handleKey(key, mask, called_from_parent); } + BOOL LLAccordionCtrlTab::LLAccordionCtrlTabHeader::handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop, EDragAndDropType cargo_type, @@ -295,7 +295,7 @@ BOOL LLAccordionCtrlTab::LLAccordionCtrlTabHeader::handleDragAndDrop(S32 x, S32 { LLAccordionCtrlTab* parent = dynamic_cast(getParent()); - if ( parent && !parent->getDisplayChildren() && parent->getCollapsible() && parent->canOpenClose() ) + if (parent && !parent->getDisplayChildren() && parent->getCollapsible() && parent->canOpenClose()) { if (mAutoOpenTimer.getStarted()) { @@ -307,12 +307,15 @@ BOOL LLAccordionCtrlTab::LLAccordionCtrlTabHeader::handleDragAndDrop(S32 x, S32 } } else + { mAutoOpenTimer.start(); + } } return LLUICtrl::handleDragAndDrop(x, y, mask, drop, cargo_type, cargo_data, accept, tooltip_msg); } + LLAccordionCtrlTab::Params::Params() : title("title") ,display_children("expanded", true) @@ -384,41 +387,39 @@ LLAccordionCtrlTab::~LLAccordionCtrlTab() { } - void LLAccordionCtrlTab::setDisplayChildren(bool display) { mDisplayChildren = display; LLRect rect = getRect(); - rect.mBottom = rect.mTop - (getDisplayChildren() ? - mExpandedHeight : HEADER_HEIGHT); + rect.mBottom = rect.mTop - (getDisplayChildren() ? mExpandedHeight : HEADER_HEIGHT); setRect(rect); - if(mContainerPanel) + if (mContainerPanel) + { mContainerPanel->setVisible(getDisplayChildren()); + } - if(mDisplayChildren) + if (mDisplayChildren) { adjustContainerPanel(); } else { - if(mScrollbar) - mScrollbar->setVisible(false); + if (mScrollbar) + mScrollbar->setVisible(FALSE); } - } void LLAccordionCtrlTab::reshape(S32 width, S32 height, BOOL called_from_parent /* = TRUE */) { LLRect headerRect; - headerRect.setLeftTopAndSize( - 0,height,width,HEADER_HEIGHT); + headerRect.setLeftTopAndSize(0, height, width, HEADER_HEIGHT); mHeader->setRect(headerRect); mHeader->reshape(headerRect.getWidth(), headerRect.getHeight()); - if(!mDisplayChildren) + if (!mDisplayChildren) return; LLRect childRect; @@ -426,7 +427,7 @@ void LLAccordionCtrlTab::reshape(S32 width, S32 height, BOOL called_from_parent childRect.setLeftTopAndSize( getPaddingLeft(), height - getHeaderHeight() - getPaddingTop(), - width - getPaddingLeft() - getPaddingRight(), + width - getPaddingLeft() - getPaddingRight(), height - getHeaderHeight() - getPaddingTop() - getPaddingBottom() ); adjustContainerPanel(childRect); @@ -434,7 +435,7 @@ void LLAccordionCtrlTab::reshape(S32 width, S32 height, BOOL called_from_parent void LLAccordionCtrlTab::changeOpenClose(bool is_open) { - if(is_open) + if (is_open) mExpandedHeight = getRect().getHeight(); setDisplayChildren(!is_open); @@ -483,14 +484,14 @@ void LLAccordionCtrlTab::onUpdateScrollToChild(const LLUICtrl *cntrl) BOOL LLAccordionCtrlTab::handleMouseDown(S32 x, S32 y, MASK mask) { - if(mCollapsible && mHeaderVisible && mCanOpenClose) + if (mCollapsible && mHeaderVisible && mCanOpenClose) { - if(y >= (getRect().getHeight() - HEADER_HEIGHT) ) + if (y >= (getRect().getHeight() - HEADER_HEIGHT)) { mHeader->setFocus(true); changeOpenClose(getDisplayChildren()); - //reset stored state + // Reset stored state mWasStateStored = false; return TRUE; } @@ -510,7 +511,7 @@ boost::signals2::connection LLAccordionCtrlTab::setDropDownStateChangedCallback( bool LLAccordionCtrlTab::addChild(LLView* child, S32 tab_group) { - if(DD_HEADER_NAME != child->getName()) + if (DD_HEADER_NAME != child->getName()) { reshape(child->getRect().getWidth() , child->getRect().getHeight() + HEADER_HEIGHT ); mExpandedHeight = getRect().getHeight(); @@ -518,12 +519,12 @@ bool LLAccordionCtrlTab::addChild(LLView* child, S32 tab_group) bool res = LLUICtrl::addChild(child, tab_group); - if(DD_HEADER_NAME != child->getName()) + if (DD_HEADER_NAME != child->getName()) { - if(!mCollapsible) + if (!mCollapsible) setDisplayChildren(true); else - setDisplayChildren(getDisplayChildren()); + setDisplayChildren(getDisplayChildren()); } if (!mContainerPanel) @@ -534,7 +535,7 @@ bool LLAccordionCtrlTab::addChild(LLView* child, S32 tab_group) void LLAccordionCtrlTab::setAccordionView(LLView* panel) { - addChild(panel,0); + addChild(panel, 0); } std::string LLAccordionCtrlTab::getTitle() const @@ -543,10 +544,8 @@ std::string LLAccordionCtrlTab::getTitle() const { return mHeader->getTitle(); } - else - { - return LLStringUtil::null; - } + + return LLStringUtil::null; } void LLAccordionCtrlTab::setTitle(const std::string& title, const std::string& hl) @@ -579,6 +578,7 @@ boost::signals2::connection LLAccordionCtrlTab::setFocusReceivedCallback(const f { return mHeader->setFocusReceivedCallback(cb); } + return boost::signals2::connection(); } @@ -588,6 +588,7 @@ boost::signals2::connection LLAccordionCtrlTab::setFocusLostCallback(const focus { return mHeader->setFocusLostCallback(cb); } + return boost::signals2::connection(); } @@ -601,59 +602,65 @@ void LLAccordionCtrlTab::setSelected(bool is_selected) LLView* LLAccordionCtrlTab::findContainerView() { - for(child_list_const_iter_t it = getChildList()->begin(); - getChildList()->end() != it; ++it) + child_list_const_iter_t it = getChildList()->begin(), it_end = getChildList()->end(); + while (it != it_end) { - LLView* child = *it; - if(DD_HEADER_NAME == child->getName()) - continue; - if(!child->getVisible()) - continue; - return child; + LLView* child = *(it++); + if (DD_HEADER_NAME != child->getName() && child->getVisible()) + return child; } + return NULL; } void LLAccordionCtrlTab::selectOnFocusReceived() { if (getParent()) // A parent may not be set if tabs are added dynamically. + { getParent()->notifyParent(LLSD().with("action", "select_current")); + } } void LLAccordionCtrlTab::deselectOnFocusLost() { - if(getParent()) // A parent may not be set if tabs are added dynamically. + if (getParent()) // A parent may not be set if tabs are added dynamically. { getParent()->notifyParent(LLSD().with("action", "deselect_current")); } - } S32 LLAccordionCtrlTab::getHeaderHeight() { - return mHeaderVisible?HEADER_HEIGHT:0; + return mHeaderVisible ? HEADER_HEIGHT : 0; } -void LLAccordionCtrlTab::setHeaderVisible(bool value) +void LLAccordionCtrlTab::setHeaderVisible(bool value) { - if(mHeaderVisible == value) + if (mHeaderVisible == value) return; + mHeaderVisible = value; - if(mHeader) - mHeader->setVisible(value); + + if (mHeader) + { + mHeader->setVisible(value ? TRUE : FALSE); + } + reshape(getRect().getWidth(), getRect().getHeight(), FALSE); }; //virtual BOOL LLAccordionCtrlTab::postBuild() { - if(mHeader) + if (mHeader) + { mHeader->setVisible(mHeaderVisible); - - static LLUICachedControl scrollbar_size ("UIScrollbarSize", 0); + } + + static LLUICachedControl scrollbar_size("UIScrollbarSize", 0); LLRect scroll_rect; - scroll_rect.setOriginAndSize( + scroll_rect.setOriginAndSize( getRect().getWidth() - scrollbar_size, 1, scrollbar_size, @@ -661,7 +668,7 @@ BOOL LLAccordionCtrlTab::postBuild() mContainerPanel = findContainerView(); - if(!mFitPanel) + if (!mFitPanel) { LLScrollbar::Params sbparams; sbparams.name("scrollable vertical"); @@ -674,9 +681,8 @@ BOOL LLAccordionCtrlTab::postBuild() sbparams.follows.flags(FOLLOWS_RIGHT | FOLLOWS_TOP | FOLLOWS_BOTTOM); sbparams.change_callback(boost::bind(&LLAccordionCtrlTab::onScrollPosChangeCallback, this, _1, _2)); - - mScrollbar = LLUICtrlFactory::create (sbparams); - LLView::addChild( mScrollbar ); + mScrollbar = LLUICtrlFactory::create(sbparams); + LLView::addChild(mScrollbar); mScrollbar->setFollowsRight(); mScrollbar->setFollowsTop(); mScrollbar->setFollowsBottom(); @@ -684,44 +690,48 @@ BOOL LLAccordionCtrlTab::postBuild() mScrollbar->setVisible(false); } - if(mContainerPanel) + if (mContainerPanel) + { mContainerPanel->setVisible(mDisplayChildren); + } return LLUICtrl::postBuild(); } -bool LLAccordionCtrlTab::notifyChildren (const LLSD& info) + +bool LLAccordionCtrlTab::notifyChildren (const LLSD& info) { - if(info.has("action")) + if (info.has("action")) { std::string str_action = info["action"]; - if(str_action == "store_state") + if (str_action == "store_state") { storeOpenCloseState(); return true; } - if(str_action == "restore_state") + + if (str_action == "restore_state") { restoreOpenCloseState(); return true; } } + return LLUICtrl::notifyChildren(info); } S32 LLAccordionCtrlTab::notifyParent(const LLSD& info) { - if(info.has("action")) + if (info.has("action")) { std::string str_action = info["action"]; - if(str_action == "size_changes") + if (str_action == "size_changes") { - // S32 height = info["height"]; - height = llmax(height,10) + HEADER_HEIGHT + getPaddingTop() + getPaddingBottom(); + height = llmax(height, 10) + HEADER_HEIGHT + getPaddingTop() + getPaddingBottom(); mExpandedHeight = height; - if(isExpanded() && !mSkipChangesOnNotifyParent) + if (isExpanded() && !mSkipChangesOnNotifyParent) { LLRect panel_rect = getRect(); panel_rect.setLeftTopAndSize( panel_rect.mLeft, panel_rect.mTop, panel_rect.getWidth(), height); @@ -729,12 +739,13 @@ S32 LLAccordionCtrlTab::notifyParent(const LLSD& info) setRect(panel_rect); } - //LLAccordionCtrl should rearrange accordion tab if one of accordion change its size + // LLAccordionCtrl should rearrange accordion tab if one of accordions changed its size if (getParent()) // A parent may not be set if tabs are added dynamically. getParent()->notifyParent(info); return 1; } - else if(str_action == "select_prev") + + if (str_action == "select_prev") { showAndFocusHeader(); return 1; @@ -772,78 +783,85 @@ S32 LLAccordionCtrlTab::notifyParent(const LLSD& info) S32 LLAccordionCtrlTab::notify(const LLSD& info) { - if(info.has("action")) + if (info.has("action")) { std::string str_action = info["action"]; - if(str_action == "select_first") + if (str_action == "select_first") { showAndFocusHeader(); return 1; } - else if( str_action == "select_last" ) + + if (str_action == "select_last") { - if(getDisplayChildren() == false) + if (!getDisplayChildren()) { showAndFocusHeader(); } else { LLView* view = getAccordionView(); - if(view) - view->notify(LLSD().with("action","select_last")); + if (view) + { + view->notify(LLSD().with("action", "select_last")); + } } } } + return 0; } BOOL LLAccordionCtrlTab::handleKey(KEY key, MASK mask, BOOL called_from_parent) { - if( !mHeader->hasFocus() ) + if (!mHeader->hasFocus()) return LLUICtrl::handleKey(key, mask, called_from_parent); - if ( (key == KEY_RETURN )&& mask == MASK_NONE) + if ((key == KEY_RETURN) && mask == MASK_NONE) { changeOpenClose(getDisplayChildren()); return TRUE; } - if ( (key == KEY_ADD || key == KEY_RIGHT)&& mask == MASK_NONE) + if ((key == KEY_ADD || key == KEY_RIGHT) && mask == MASK_NONE) { - if(getDisplayChildren() == false) + if (!getDisplayChildren()) { changeOpenClose(getDisplayChildren()); return TRUE; } } - if ( (key == KEY_SUBTRACT || key == KEY_LEFT)&& mask == MASK_NONE) + + if ((key == KEY_SUBTRACT || key == KEY_LEFT) && mask == MASK_NONE) { - if(getDisplayChildren() == true) + if (getDisplayChildren()) { changeOpenClose(getDisplayChildren()); return TRUE; } } - if ( key == KEY_DOWN && mask == MASK_NONE) + if (key == KEY_DOWN && mask == MASK_NONE) { - //if collapsed go to the next accordion - if(getDisplayChildren() == false) - //we processing notifyParent so let call parent directly - getParent()->notifyParent(LLSD().with("action","select_next")); + // if collapsed go to the next accordion + if (!getDisplayChildren()) + { + // we're processing notifyParent so let call parent directly + getParent()->notifyParent(LLSD().with("action", "select_next")); + } else { - getAccordionView()->notify(LLSD().with("action","select_first")); + getAccordionView()->notify(LLSD().with("action", "select_first")); } return TRUE; } - if ( key == KEY_UP && mask == MASK_NONE) + if (key == KEY_UP && mask == MASK_NONE) { - //go to the previous accordion + // go to the previous accordion - //we processing notifyParent so let call parent directly - getParent()->notifyParent(LLSD().with("action","select_prev")); + // we're processing notifyParent so let call parent directly + getParent()->notifyParent(LLSD().with("action", "select_prev")); return TRUE; } @@ -869,28 +887,29 @@ void LLAccordionCtrlTab::showAndFocusHeader() // accordion tab (assuming that the parent is an LLAccordionCtrl) the calls chain // is shortened and messages from inside the collapsed tabs are avoided. // See STORM-536. - getParent()->notifyParent(LLSD().with("scrollToShowRect",screen_rc.getValue())); + getParent()->notifyParent(LLSD().with("scrollToShowRect", screen_rc.getValue())); } -void LLAccordionCtrlTab::storeOpenCloseState() + +void LLAccordionCtrlTab::storeOpenCloseState() { - if(mWasStateStored) + if (mWasStateStored) return; mStoredOpenCloseState = getDisplayChildren(); mWasStateStored = true; } -void LLAccordionCtrlTab::restoreOpenCloseState() +void LLAccordionCtrlTab::restoreOpenCloseState() { - if(!mWasStateStored) + if (!mWasStateStored) return; - if(getDisplayChildren() != mStoredOpenCloseState) + if (getDisplayChildren() != mStoredOpenCloseState) { changeOpenClose(getDisplayChildren()); } mWasStateStored = false; } -void LLAccordionCtrlTab::adjustContainerPanel () +void LLAccordionCtrlTab::adjustContainerPanel() { S32 width = getRect().getWidth(); S32 height = getRect().getHeight(); @@ -907,83 +926,83 @@ void LLAccordionCtrlTab::adjustContainerPanel () void LLAccordionCtrlTab::adjustContainerPanel(const LLRect& child_rect) { - if(!mContainerPanel) + if (!mContainerPanel) return; - if(!mFitPanel) + if (!mFitPanel) { show_hide_scrollbar(child_rect); updateLayout(child_rect); } else { - mContainerPanel->reshape(child_rect.getWidth(),child_rect.getHeight()); + mContainerPanel->reshape(child_rect.getWidth(), child_rect.getHeight()); mContainerPanel->setRect(child_rect); } } S32 LLAccordionCtrlTab::getChildViewHeight() { - if(!mContainerPanel) + if (!mContainerPanel) return 0; return mContainerPanel->getRect().getHeight(); } void LLAccordionCtrlTab::show_hide_scrollbar(const LLRect& child_rect) { - if(getChildViewHeight() > child_rect.getHeight() ) + if (getChildViewHeight() > child_rect.getHeight()) showScrollbar(child_rect); else hideScrollbar(child_rect); } + void LLAccordionCtrlTab::showScrollbar(const LLRect& child_rect) { - if(!mContainerPanel || !mScrollbar) + if (!mContainerPanel || !mScrollbar) return; bool was_visible = mScrollbar->getVisible(); mScrollbar->setVisible(true); static LLUICachedControl scrollbar_size ("UIScrollbarSize", 0); - { - ctrlSetLeftTopAndSize(mScrollbar,child_rect.getWidth()-scrollbar_size, - child_rect.getHeight()-PARENT_BORDER_MARGIN, - scrollbar_size, - child_rect.getHeight()-2*PARENT_BORDER_MARGIN); - } + ctrlSetLeftTopAndSize(mScrollbar, + child_rect.getWidth() - scrollbar_size, + child_rect.getHeight() - PARENT_BORDER_MARGIN, + scrollbar_size, + child_rect.getHeight() - PARENT_BORDER_MARGIN * 2); LLRect orig_rect = mContainerPanel->getRect(); mScrollbar->setPageSize(child_rect.getHeight()); - mScrollbar->setDocParams(orig_rect.getHeight(),mScrollbar->getDocPos()); + mScrollbar->setDocParams(orig_rect.getHeight(), mScrollbar->getDocPos()); - if(was_visible) + if (was_visible) { S32 scroll_pos = llmin(mScrollbar->getDocPos(), orig_rect.getHeight() - child_rect.getHeight() - 1); mScrollbar->setDocPos(scroll_pos); } - else//shrink child panel + else // Shrink child panel { updateLayout(child_rect); } - } -void LLAccordionCtrlTab::hideScrollbar( const LLRect& child_rect ) +void LLAccordionCtrlTab::hideScrollbar(const LLRect& child_rect) { - if(!mContainerPanel || !mScrollbar) + if (!mContainerPanel || !mScrollbar) return; - if(mScrollbar->getVisible() == false) + if (mScrollbar->getVisible() == FALSE) return; - mScrollbar->setVisible(false); + + mScrollbar->setVisible(FALSE); mScrollbar->setDocPos(0); //shrink child panel updateLayout(child_rect); } -void LLAccordionCtrlTab::onScrollPosChangeCallback(S32, LLScrollbar*) +void LLAccordionCtrlTab::onScrollPosChangeCallback(S32, LLScrollbar*) { LLRect child_rect; @@ -999,21 +1018,20 @@ void LLAccordionCtrlTab::onScrollPosChangeCallback(S32, LLScrollbar*) updateLayout(child_rect); } -void LLAccordionCtrlTab::drawChild(const LLRect& root_rect,LLView* child) +void LLAccordionCtrlTab::drawChild(const LLRect& root_rect, LLView* child) { if (child && child->getVisible() && child->getRect().isValid()) { LLRect screen_rect; - localRectToScreen(child->getRect(),&screen_rect); - - if ( root_rect.overlaps(screen_rect) && sDirtyRect.overlaps(screen_rect)) + localRectToScreen(child->getRect(), &screen_rect); + + if (root_rect.overlaps(screen_rect) && sDirtyRect.overlaps(screen_rect)) { gGL.matrixMode(LLRender::MM_MODELVIEW); LLUI::pushMatrix(); { LLUI::translate((F32)child->getRect().mLeft, (F32)child->getRect().mBottom); child->draw(); - } LLUI::popMatrix(); } @@ -1022,64 +1040,67 @@ void LLAccordionCtrlTab::drawChild(const LLRect& root_rect,LLView* child) void LLAccordionCtrlTab::draw() { - if(mFitPanel) + if (mFitPanel) + { LLUICtrl::draw(); + } else { - LLRect root_rect = getRootView()->getRect(); - drawChild(root_rect,mHeader); - drawChild(root_rect,mScrollbar ); - { - LLRect child_rect; + LLRect root_rect(getRootView()->getRect()); + drawChild(root_rect, mHeader); + drawChild(root_rect, mScrollbar); - S32 width = getRect().getWidth(); - S32 height = getRect().getHeight(); + LLRect child_rect; - child_rect.setLeftTopAndSize( - getPaddingLeft(), - height - getHeaderHeight() - getPaddingTop(), - width - getPaddingLeft() - getPaddingRight(), - height - getHeaderHeight() - getPaddingTop() - getPaddingBottom() ); + S32 width = getRect().getWidth(); + S32 height = getRect().getHeight(); - LLLocalClipRect clip(child_rect); - drawChild(root_rect,mContainerPanel); - } + child_rect.setLeftTopAndSize( + getPaddingLeft(), + height - getHeaderHeight() - getPaddingTop(), + width - getPaddingLeft() - getPaddingRight(), + height - getHeaderHeight() - getPaddingTop() - getPaddingBottom()); + + LLLocalClipRect clip(child_rect); + drawChild(root_rect,mContainerPanel); } } -void LLAccordionCtrlTab::updateLayout ( const LLRect& child_rect ) +void LLAccordionCtrlTab::updateLayout(const LLRect& child_rect) { LLView* child = getAccordionView(); - if(!mContainerPanel) + if (!mContainerPanel) return; S32 panel_top = child_rect.getHeight(); S32 panel_width = child_rect.getWidth(); - static LLUICachedControl scrollbar_size ("UIScrollbarSize", 0); - if(mScrollbar && mScrollbar->getVisible() != false) + static LLUICachedControl scrollbar_size("UIScrollbarSize", 0); + if (mScrollbar && mScrollbar->getVisible()) { - panel_top+=mScrollbar->getDocPos(); - panel_width-=scrollbar_size; + panel_top += mScrollbar->getDocPos(); + panel_width -= scrollbar_size; } - //set sizes for first panels and dragbars + // Set sizes for first panels and dragbars LLRect panel_rect = child->getRect(); - ctrlSetLeftTopAndSize(mContainerPanel,child_rect.mLeft,panel_top,panel_width,panel_rect.getHeight()); + ctrlSetLeftTopAndSize(mContainerPanel, child_rect.mLeft, panel_top, panel_width, panel_rect.getHeight()); } + void LLAccordionCtrlTab::ctrlSetLeftTopAndSize(LLView* panel, S32 left, S32 top, S32 width, S32 height) { - if(!panel) + if (!panel) return; LLRect panel_rect = panel->getRect(); - panel_rect.setLeftTopAndSize( left, top, width, height); + panel_rect.setLeftTopAndSize(left, top, width, height); panel->reshape( width, height, 1); panel->setRect(panel_rect); } + BOOL LLAccordionCtrlTab::handleToolTip(S32 x, S32 y, MASK mask) { //header may be not the first child but we need to process it first - if(y >= (getRect().getHeight() - HEADER_HEIGHT - HEADER_HEIGHT/2) ) + if (y >= (getRect().getHeight() - HEADER_HEIGHT - HEADER_HEIGHT / 2)) { //inside tab header //fix for EXT-6619 @@ -1088,16 +1109,18 @@ BOOL LLAccordionCtrlTab::handleToolTip(S32 x, S32 y, MASK mask) } return LLUICtrl::handleToolTip(x, y, mask); } -BOOL LLAccordionCtrlTab::handleScrollWheel ( S32 x, S32 y, S32 clicks ) + +BOOL LLAccordionCtrlTab::handleScrollWheel(S32 x, S32 y, S32 clicks) { - if( LLUICtrl::handleScrollWheel(x,y,clicks)) + if (LLUICtrl::handleScrollWheel(x, y, clicks)) { return TRUE; } - if( mScrollbar && mScrollbar->getVisible() && mScrollbar->handleScrollWheel( 0, 0, clicks ) ) + + if (mScrollbar && mScrollbar->getVisible() && mScrollbar->handleScrollWheel(0, 0, clicks)) { return TRUE; } + return FALSE; } - diff --git a/indra/llui/llaccordionctrltab.h b/indra/llui/llaccordionctrltab.h index 2c72e8c036..896a34cac4 100644 --- a/indra/llui/llaccordionctrltab.h +++ b/indra/llui/llaccordionctrltab.h @@ -104,7 +104,7 @@ public: virtual void setDisplayChildren(bool display); // Returns expand/collapse state - virtual bool getDisplayChildren() const {return mDisplayChildren;}; + virtual bool getDisplayChildren() const { return mDisplayChildren; }; //set LLAccordionCtrlTab panel void setAccordionView(LLView* panel); diff --git a/indra/llui/llflatlistview.cpp b/indra/llui/llflatlistview.cpp index b13e7389cc..460bd0945b 100644 --- a/indra/llui/llflatlistview.cpp +++ b/indra/llui/llflatlistview.cpp @@ -1198,7 +1198,7 @@ void LLFlatListView::onFocusReceived() { if (size()) { - mSelectedItemsBorder->setVisible(TRUE); + mSelectedItemsBorder->setVisible(TRUE); } gEditMenuHandler = this; } @@ -1207,7 +1207,7 @@ void LLFlatListView::onFocusLost() { mSelectedItemsBorder->setVisible(FALSE); // Route menu back to the default - if( gEditMenuHandler == this ) + if (gEditMenuHandler == this) { gEditMenuHandler = NULL; } @@ -1216,16 +1216,16 @@ void LLFlatListView::onFocusLost() //virtual S32 LLFlatListView::notify(const LLSD& info) { - if(info.has("action")) + if (info.has("action")) { std::string str_action = info["action"]; - if(str_action == "select_first") + if (str_action == "select_first") { setFocus(true); selectFirstItem(); return 1; } - else if(str_action == "select_last") + else if (str_action == "select_last") { setFocus(true); selectLastItem(); @@ -1238,6 +1238,7 @@ S32 LLFlatListView::notify(const LLSD& info) notifyParentItemsRectChanged(); return 1; } + return 0; } @@ -1249,10 +1250,8 @@ void LLFlatListView::detachItems(std::vector& detached_items) detached_items.clear(); // Go through items and detach valid items, remove them from items panel // and add to detached_items. - for (pairs_iterator_t - iter = mItemPairs.begin(), - iter_end = mItemPairs.end(); - iter != iter_end; ++iter) + pairs_iterator_t iter = mItemPairs.begin(), iter_end = mItemPairs.end(); + while (iter != iter_end) { LLPanel* pItem = (*iter)->first; if (1 == pItem->notify(action)) @@ -1261,6 +1260,7 @@ void LLFlatListView::detachItems(std::vector& detached_items) mItemsPanel->removeChild(pItem); detached_items.push_back(pItem); } + iter++; } if (!detached_items.empty()) { @@ -1268,13 +1268,12 @@ void LLFlatListView::detachItems(std::vector& detached_items) if (detached_items.size() == mItemPairs.size()) { // This way will be faster if all items were disconnected - for (pairs_iterator_t - iter = mItemPairs.begin(), - iter_end = mItemPairs.end(); - iter != iter_end; ++iter) + pairs_iterator_t iter = mItemPairs.begin(), iter_end = mItemPairs.end(); + while (iter != iter_end) { (*iter)->first = NULL; delete *iter; + iter++; } mItemPairs.clear(); // Also set items panel height to zero. @@ -1287,16 +1286,14 @@ void LLFlatListView::detachItems(std::vector& detached_items) } else { - for (std::vector::const_iterator - detached_iter = detached_items.begin(), - detached_iter_end = detached_items.end(); - detached_iter != detached_iter_end; ++detached_iter) + std::vector::const_iterator + detached_iter = detached_items.begin(), + detached_iter_end = detached_items.end(); + while (detached_iter < detached_iter_end) { LLPanel* pDetachedItem = *detached_iter; - for (pairs_iterator_t - iter = mItemPairs.begin(), - iter_end = mItemPairs.end(); - iter != iter_end; ++iter) + pairs_iterator_t iter = mItemPairs.begin(), iter_end = mItemPairs.end(); + while (iter != iter_end) { item_pair_t* item_pair = *iter; if (item_pair->first == pDetachedItem) @@ -1306,7 +1303,9 @@ void LLFlatListView::detachItems(std::vector& detached_items) delete item_pair; break; } + iter++; } + detached_iter++; } rearrangeItems(); } @@ -1322,7 +1321,6 @@ LLFlatListViewEx::Params::Params() : no_items_msg("no_items_msg") , no_filtered_items_msg("no_filtered_items_msg") { - } LLFlatListViewEx::LLFlatListViewEx(const Params& p) @@ -1332,7 +1330,6 @@ LLFlatListViewEx::LLFlatListViewEx(const Params& p) , mForceShowingUnmatchedItems(false) , mHasMatchedItems(false) { - } void LLFlatListViewEx::updateNoItemsMessage(const std::string& filter_string) @@ -1352,7 +1349,6 @@ void LLFlatListViewEx::updateNoItemsMessage(const std::string& filter_string) // list does not contain any items at all setNoItemsCommentText(mNoItemsMsg); } - } bool LLFlatListViewEx::getForceShowingUnmatchedItems() @@ -1411,12 +1407,10 @@ void LLFlatListViewEx::filterItems() getItems(items); mHasMatchedItems = false; - for (item_panel_list_t::iterator - iter = items.begin(), - iter_end = items.end(); - iter != iter_end; ++iter) + item_panel_list_t::iterator iter = items.begin(), iter_end = items.end(); + while (iter < iter_end) { - LLPanel* pItem = (*iter); + LLPanel* pItem = *(iter++); updateItemVisibility(pItem, action); } -- cgit v1.2.3 From 716b9af35d0dbc3ba8048a1bcca2c8c8f703bed0 Mon Sep 17 00:00:00 2001 From: Alexander Gavriliuk Date: Tue, 7 Nov 2023 23:13:00 +0100 Subject: SL-20356 EmojiPicker - Implement arrow keys navigation --- indra/llui/llscrollcontainer.cpp | 23 ++++++++++++++++++++++- indra/llui/llscrollcontainer.h | 4 +++- indra/llui/llscrollingpanellist.h | 2 +- 3 files changed, 26 insertions(+), 3 deletions(-) (limited to 'indra/llui') diff --git a/indra/llui/llscrollcontainer.cpp b/indra/llui/llscrollcontainer.cpp index ad32f7186c..22d27b1f2a 100644 --- a/indra/llui/llscrollcontainer.cpp +++ b/indra/llui/llscrollcontainer.cpp @@ -70,6 +70,7 @@ LLScrollContainer::Params::Params() bg_color("color"), border_visible("border_visible"), hide_scrollbar("hide_scrollbar"), + ignore_arrow_keys("ignore_arrow_keys"), min_auto_scroll_rate("min_auto_scroll_rate", 100), max_auto_scroll_rate("max_auto_scroll_rate", 1000), max_auto_scroll_zone("max_auto_scroll_zone", 16), @@ -86,6 +87,7 @@ LLScrollContainer::LLScrollContainer(const LLScrollContainer::Params& p) mBackgroundColor(p.bg_color()), mIsOpaque(p.is_opaque), mHideScrollbar(p.hide_scrollbar), + mIgnoreArrowKeys(p.ignore_arrow_keys), mReserveScrollCorner(p.reserve_scroll_corner), mMinAutoScrollRate(p.min_auto_scroll_rate), mMaxAutoScrollRate(p.max_auto_scroll_rate), @@ -204,10 +206,29 @@ void LLScrollContainer::reshape(S32 width, S32 height, } } +// virtual BOOL LLScrollContainer::handleKeyHere(KEY key, MASK mask) { + if (mIgnoreArrowKeys) + { + switch(key) + { + case KEY_LEFT: + case KEY_RIGHT: + case KEY_UP: + case KEY_DOWN: + case KEY_PAGE_UP: + case KEY_PAGE_DOWN: + case KEY_HOME: + case KEY_END: + return FALSE; + default: + break; + } + } + // allow scrolled view to handle keystrokes in case it delegated keyboard focus - // to the scroll container. + // to the scroll container. // NOTE: this should not recurse indefinitely as handleKeyHere // should not propagate to parent controls, so mScrolledView should *not* // call LLScrollContainer::handleKeyHere in turn diff --git a/indra/llui/llscrollcontainer.h b/indra/llui/llscrollcontainer.h index dacea2a987..79dc70cac9 100644 --- a/indra/llui/llscrollcontainer.h +++ b/indra/llui/llscrollcontainer.h @@ -63,7 +63,8 @@ public: Optional is_opaque, reserve_scroll_corner, border_visible, - hide_scrollbar; + hide_scrollbar, + ignore_arrow_keys; Optional min_auto_scroll_rate, max_auto_scroll_rate; Optional max_auto_scroll_zone; @@ -149,6 +150,7 @@ private: F32 mMaxAutoScrollRate; U32 mMaxAutoScrollZone; bool mHideScrollbar; + bool mIgnoreArrowKeys; }; diff --git a/indra/llui/llscrollingpanellist.h b/indra/llui/llscrollingpanellist.h index 9dc65dabb5..d625039427 100644 --- a/indra/llui/llscrollingpanellist.h +++ b/indra/llui/llscrollingpanellist.h @@ -45,7 +45,7 @@ public: /* - * A set of panels that are displayed in a vertical sequence inside a scroll container. + * A set of panels that are displayed in a sequence inside a scroll container. */ class LLScrollingPanelList : public LLUICtrl { -- cgit v1.2.3 From 1e7643eea5883db5b773db99b37440eb06b63e3e Mon Sep 17 00:00:00 2001 From: Alexander Gavriliuk Date: Thu, 9 Nov 2023 17:51:32 +0100 Subject: SL-20438 Emoji picker will dock with edge of screen if the Conversations floater is dragged there --- indra/llui/llfloater.cpp | 96 +++++++++++++++++++++++++++++++++++------------- indra/llui/llfloater.h | 7 ++-- indra/llui/llview.cpp | 41 +++++++++++++-------- indra/llui/llview.h | 1 + 4 files changed, 100 insertions(+), 45 deletions(-) (limited to 'indra/llui') diff --git a/indra/llui/llfloater.cpp b/indra/llui/llfloater.cpp index 98895d56dd..23d3a66631 100644 --- a/indra/llui/llfloater.cpp +++ b/indra/llui/llfloater.cpp @@ -829,6 +829,24 @@ void LLFloater::reshape(S32 width, S32 height, BOOL called_from_parent) LLPanel::reshape(width, height, called_from_parent); } +// virtual +void LLFloater::translate(S32 x, S32 y) +{ + LLView::translate(x, y); + + if (!mTranslateWithDependents || mDependents.empty()) + return; + + for (const LLHandle& handle : mDependents) + { + LLFloater* floater = handle.get(); + if (floater && floater->getSnapTarget() == getHandle()) + { + floater->LLView::translate(x, y); + } + } +} + void LLFloater::releaseFocus() { LLUI::getInstance()->removePopup(this); @@ -1117,9 +1135,9 @@ BOOL LLFloater::canSnapTo(const LLView* other_view) if (other_view != getParent()) { - const LLFloater* other_floaterp = dynamic_cast(other_view); - if (other_floaterp - && other_floaterp->getSnapTarget() == getHandle() + const LLFloater* other_floaterp = dynamic_cast(other_view); + if (other_floaterp + && other_floaterp->getSnapTarget() == getHandle() && mDependents.find(other_floaterp->getHandle()) != mDependents.end()) { // this is a dependent that is already snapped to us, so don't snap back to it @@ -1552,6 +1570,44 @@ void LLFloater::removeDependentFloater(LLFloater* floaterp) floaterp->mDependeeHandle = LLHandle(); } +void LLFloater::fitWithDependentsOnScreen(const LLRect& left, const LLRect& bottom, const LLRect& right, const LLRect& constraint, S32 min_overlap_pixels) +{ + LLRect total_rect = getRect(); + + for (const LLHandle& handle : mDependents) + { + LLFloater* floater = handle.get(); + if (floater && floater->getSnapTarget() == getHandle()) + { + total_rect.unionWith(floater->getRect()); + } + } + + S32 delta_left = left.notEmpty() ? left.mRight - total_rect.mRight : 0; + S32 delta_bottom = bottom.notEmpty() ? bottom.mTop - total_rect.mTop : 0; + S32 delta_right = right.notEmpty() ? right.mLeft - total_rect.mLeft : 0; + + // move floater with dependings fully onscreen + mTranslateWithDependents = true; + if (translateRectIntoRect(total_rect, constraint, min_overlap_pixels)) + { + clearSnapTarget(); + } + else if (delta_left > 0 && total_rect.mTop < left.mTop && total_rect.mBottom > left.mBottom) + { + translate(delta_left, 0); + } + else if (delta_bottom > 0 && total_rect.mLeft > bottom.mLeft && total_rect.mRight < bottom.mRight) + { + translate(0, delta_bottom); + } + else if (delta_right < 0 && total_rect.mTop < right.mTop && total_rect.mBottom > right.mBottom) + { + translate(delta_right, 0); + } + mTranslateWithDependents = false; +} + BOOL LLFloater::offerClickToButton(S32 x, S32 y, MASK mask, EFloaterButton index) { if( mButtonsEnabled[index] ) @@ -2862,10 +2918,17 @@ void LLFloaterView::adjustToFitScreen(LLFloater* floater, BOOL allow_partial_out // floater is hosted elsewhere, so ignore return; } + + if (floater->getDependee() && + floater->getDependee() == floater->getSnapTarget().get()) + { + // floater depends on other and snaps to it, so ignore + return; + } + LLRect::tCoordType screen_width = getSnapRect().getWidth(); LLRect::tCoordType screen_height = getSnapRect().getHeight(); - // only automatically resize non-minimized, resizable floaters if( floater->isResizable() && !floater->isMinimized() ) { @@ -2907,29 +2970,10 @@ void LLFloaterView::adjustToFitScreen(LLFloater* floater, BOOL allow_partial_out } } - const LLRect& floater_rect = floater->getRect(); - - S32 delta_left = mToolbarLeftRect.notEmpty() ? mToolbarLeftRect.mRight - floater_rect.mRight : 0; - S32 delta_bottom = mToolbarBottomRect.notEmpty() ? mToolbarBottomRect.mTop - floater_rect.mTop : 0; - S32 delta_right = mToolbarRightRect.notEmpty() ? mToolbarRightRect.mLeft - floater_rect.mLeft : 0; + const LLRect& constraint = snap_in_toolbars ? getSnapRect() : gFloaterView->getRect(); + S32 min_overlap_pixels = allow_partial_outside ? FLOATER_MIN_VISIBLE_PIXELS : S32_MAX; - // move window fully onscreen - if (floater->translateIntoRect( snap_in_toolbars ? getSnapRect() : gFloaterView->getRect(), allow_partial_outside ? FLOATER_MIN_VISIBLE_PIXELS : S32_MAX )) - { - floater->clearSnapTarget(); - } - else if (delta_left > 0 && floater_rect.mTop < mToolbarLeftRect.mTop && floater_rect.mBottom > mToolbarLeftRect.mBottom) - { - floater->translate(delta_left, 0); - } - else if (delta_bottom > 0 && floater_rect.mLeft > mToolbarBottomRect.mLeft && floater_rect.mRight < mToolbarBottomRect.mRight) - { - floater->translate(0, delta_bottom); - } - else if (delta_right < 0 && floater_rect.mTop < mToolbarRightRect.mTop && floater_rect.mBottom > mToolbarRightRect.mBottom) - { - floater->translate(delta_right, 0); - } + floater->fitWithDependentsOnScreen(mToolbarLeftRect, mToolbarBottomRect, mToolbarRightRect, constraint, min_overlap_pixels); } void LLFloaterView::draw() diff --git a/indra/llui/llfloater.h b/indra/llui/llfloater.h index 3699629ef8..08fc5f425f 100644 --- a/indra/llui/llfloater.h +++ b/indra/llui/llfloater.h @@ -113,8 +113,6 @@ struct LLCoordFloater : LLCoord bool operator!=(const LLCoordFloater& other) const { return !(*this == other); } void setFloater(LLFloater& floater); - - }; class LLFloater : public LLPanel, public LLInstanceTracker @@ -237,6 +235,7 @@ public: virtual void closeHostedFloater(); /*virtual*/ void reshape(S32 width, S32 height, BOOL called_from_parent = TRUE); + /*virtual*/ void translate(S32 x, S32 y); // Release keyboard and mouse focus void releaseFocus(); @@ -258,7 +257,8 @@ public: void addDependentFloater(LLFloater* dependent, BOOL reposition = TRUE, BOOL resize = FALSE); void addDependentFloater(LLHandle dependent_handle, BOOL reposition = TRUE, BOOL resize = FALSE); LLFloater* getDependee() { return (LLFloater*)mDependeeHandle.get(); } - void removeDependentFloater(LLFloater* dependent); + void removeDependentFloater(LLFloater* dependent); + void fitWithDependentsOnScreen(const LLRect& left, const LLRect& bottom, const LLRect& right, const LLRect& constraint, S32 min_overlap_pixels); BOOL isMinimized() const { return mMinimized; } /// isShown() differs from getVisible() in that isShown() also considers /// isMinimized(). isShown() is true only if visible and not minimized. @@ -506,6 +506,7 @@ private: typedef std::set > handle_set_t; typedef std::set >::iterator handle_set_iter_t; handle_set_t mDependents; + bool mTranslateWithDependents { false }; bool mButtonsEnabled[BUTTON_COUNT]; F32 mButtonScale; diff --git a/indra/llui/llview.cpp b/indra/llui/llview.cpp index d8d605871f..0046105870 100644 --- a/indra/llui/llview.cpp +++ b/indra/llui/llview.cpp @@ -1753,23 +1753,26 @@ LLCoordGL getNeededTranslation(const LLRect& input, const LLRect& constraint, S3 const S32 KEEP_ONSCREEN_PIXELS_WIDTH = llmin(min_overlap_pixels, input.getWidth()); const S32 KEEP_ONSCREEN_PIXELS_HEIGHT = llmin(min_overlap_pixels, input.getHeight()); - if( input.mRight - KEEP_ONSCREEN_PIXELS_WIDTH < constraint.mLeft ) + if (KEEP_ONSCREEN_PIXELS_WIDTH <= constraint.getWidth() && + KEEP_ONSCREEN_PIXELS_HEIGHT <= constraint.getHeight()) { - delta.mX = constraint.mLeft - (input.mRight - KEEP_ONSCREEN_PIXELS_WIDTH); - } - else if( input.mLeft + KEEP_ONSCREEN_PIXELS_WIDTH > constraint.mRight ) - { - delta.mX = constraint.mRight - (input.mLeft + KEEP_ONSCREEN_PIXELS_WIDTH); - } + if (input.mRight - KEEP_ONSCREEN_PIXELS_WIDTH < constraint.mLeft) + { + delta.mX = constraint.mLeft - (input.mRight - KEEP_ONSCREEN_PIXELS_WIDTH); + } + else if (input.mLeft + KEEP_ONSCREEN_PIXELS_WIDTH > constraint.mRight) + { + delta.mX = constraint.mRight - (input.mLeft + KEEP_ONSCREEN_PIXELS_WIDTH); + } - if( input.mTop > constraint.mTop ) - { - delta.mY = constraint.mTop - input.mTop; - } - else - if( input.mTop - KEEP_ONSCREEN_PIXELS_HEIGHT < constraint.mBottom ) - { - delta.mY = constraint.mBottom - (input.mTop - KEEP_ONSCREEN_PIXELS_HEIGHT); + if (input.mTop > constraint.mTop) + { + delta.mY = constraint.mTop - input.mTop; + } + else if (input.mTop - KEEP_ONSCREEN_PIXELS_HEIGHT < constraint.mBottom) + { + delta.mY = constraint.mBottom - (input.mTop - KEEP_ONSCREEN_PIXELS_HEIGHT); + } } return delta; @@ -1780,13 +1783,19 @@ LLCoordGL getNeededTranslation(const LLRect& input, const LLRect& constraint, S3 // (Why top and left? That's where the drag bars are for floaters.) BOOL LLView::translateIntoRect(const LLRect& constraint, S32 min_overlap_pixels) { - LLCoordGL translation = getNeededTranslation(getRect(), constraint, min_overlap_pixels); + return translateRectIntoRect(getRect(), constraint, min_overlap_pixels); +} + +BOOL LLView::translateRectIntoRect(const LLRect& rect, const LLRect& constraint, S32 min_overlap_pixels) +{ + LLCoordGL translation = getNeededTranslation(rect, constraint, min_overlap_pixels); if (translation.mX != 0 || translation.mY != 0) { translate(translation.mX, translation.mY); return TRUE; } + return FALSE; } diff --git a/indra/llui/llview.h b/indra/llui/llview.h index 3d52d3048f..b498451dce 100644 --- a/indra/llui/llview.h +++ b/indra/llui/llview.h @@ -369,6 +369,7 @@ public: virtual void translate( S32 x, S32 y ); void setOrigin( S32 x, S32 y ) { mRect.translate( x - mRect.mLeft, y - mRect.mBottom ); } BOOL translateIntoRect( const LLRect& constraint, S32 min_overlap_pixels = S32_MAX); + BOOL translateRectIntoRect( const LLRect& rect, const LLRect& constraint, S32 min_overlap_pixels = S32_MAX); BOOL translateIntoRectWithExclusion( const LLRect& inside, const LLRect& exclude, S32 min_overlap_pixels = S32_MAX); void centerWithin(const LLRect& bounds); -- cgit v1.2.3 From 2fad5a770b3583e576992d075c24bc0e25443053 Mon Sep 17 00:00:00 2001 From: Alexander Gavriliuk Date: Thu, 30 Nov 2023 13:59:14 +0100 Subject: SL-19801 Log unicode characters for debug --- indra/llui/lltexteditor.cpp | 1 + indra/llui/llview.cpp | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) (limited to 'indra/llui') diff --git a/indra/llui/lltexteditor.cpp b/indra/llui/lltexteditor.cpp index 7aef056e5a..3910be1443 100644 --- a/indra/llui/lltexteditor.cpp +++ b/indra/llui/lltexteditor.cpp @@ -682,6 +682,7 @@ void LLTextEditor::selectByCursorPosition(S32 prev_cursor_pos, S32 next_cursor_p void LLTextEditor::insertEmoji(llwchar emoji) { + LL_INFOS() << "LLTextEditor::insertEmoji(" << wchar_utf8_preview(emoji) << ")" << LL_ENDL; auto styleParams = LLStyle::Params(); styleParams.font = LLFontGL::getFontEmoji(); auto segment = new LLEmojiTextSegment(new LLStyle(styleParams), mCursorPos, mCursorPos + 1, *this); diff --git a/indra/llui/llview.cpp b/indra/llui/llview.cpp index 0046105870..7b6661a519 100644 --- a/indra/llui/llview.cpp +++ b/indra/llui/llview.cpp @@ -1024,7 +1024,7 @@ BOOL LLView::handleUnicodeChar(llwchar uni_char, BOOL called_from_parent) handled = handleUnicodeCharHere(uni_char); if (handled && LLView::sDebugKeys) { - LL_INFOS() << "Unicode key handled by " << getName() << LL_ENDL; + LL_INFOS() << "Unicode key " << wchar_utf8_preview(uni_char) << " is handled by " << getName() << LL_ENDL; } } } -- cgit v1.2.3 From 03870e0cf3733d244269f8c9ce7c982309d4f9fd Mon Sep 17 00:00:00 2001 From: Alexander Gavriliuk Date: Thu, 11 Jan 2024 20:29:06 +0100 Subject: SL-20756 The emoji in the profile floater is displayed schematically --- indra/llui/lltextbase.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'indra/llui') diff --git a/indra/llui/lltextbase.cpp b/indra/llui/lltextbase.cpp index 1b83ee401c..8f628b4818 100644 --- a/indra/llui/lltextbase.cpp +++ b/indra/llui/lltextbase.cpp @@ -168,7 +168,7 @@ LLTextBase::Params::Params() trusted_content("trusted_content", true), always_show_icons("always_show_icons", false), use_ellipses("use_ellipses", false), - use_color("use_color", false), + use_color("use_color", true), parse_urls("parse_urls", false), force_urls_external("force_urls_external", false), parse_highlights("parse_highlights", false) -- cgit v1.2.3 From ae91ae43a51c58cc496f3947921fbf886c6be86e Mon Sep 17 00:00:00 2001 From: Alexander Gavriliuk Date: Mon, 15 Jan 2024 23:20:24 +0100 Subject: SL-20795 Part of previously typed emojis disappear in the 'Save settings as a preset...' option of the 'Preferences' floater --- indra/llui/llbutton.cpp | 2 +- indra/llui/llfolderviewitem.cpp | 10 +++++----- indra/llui/lllineeditor.cpp | 2 +- indra/llui/llview.cpp | 3 +-- 4 files changed, 8 insertions(+), 9 deletions(-) (limited to 'indra/llui') diff --git a/indra/llui/llbutton.cpp b/indra/llui/llbutton.cpp index 5ce1cbd63c..9ef019840a 100644 --- a/indra/llui/llbutton.cpp +++ b/indra/llui/llbutton.cpp @@ -68,7 +68,7 @@ LLButton::Params::Params() label_shadow("label_shadow", true), auto_resize("auto_resize", false), use_ellipses("use_ellipses", false), - use_font_color("use_font_color", false), + use_font_color("use_font_color", true), image_unselected("image_unselected"), image_selected("image_selected"), image_hover_selected("image_hover_selected"), diff --git a/indra/llui/llfolderviewitem.cpp b/indra/llui/llfolderviewitem.cpp index c47f4c60e3..bc9469cfad 100644 --- a/indra/llui/llfolderviewitem.cpp +++ b/indra/llui/llfolderviewitem.cpp @@ -890,7 +890,7 @@ void LLFolderViewItem::drawLabel(const LLFontGL * font, const F32 x, const F32 y // font->renderUTF8(mLabel, 0, x, y, color, LLFontGL::LEFT, LLFontGL::BOTTOM, LLFontGL::NORMAL, LLFontGL::NO_SHADOW, - S32_MAX, getRect().getWidth() - (S32) x - mLabelPaddingRight, &right_x, /*use_ellipses*/TRUE, /*use_color*/FALSE); + S32_MAX, getRect().getWidth() - (S32) x - mLabelPaddingRight, &right_x, /*use_ellipses*/TRUE); } void LLFolderViewItem::draw() @@ -999,7 +999,7 @@ void LLFolderViewItem::draw() { suffix_font->renderUTF8( mLabelSuffix, 0, right_x, y, isFadeItem() ? color : (LLColor4)sSuffixColor, LLFontGL::LEFT, LLFontGL::BOTTOM, LLFontGL::NORMAL, LLFontGL::NO_SHADOW, - S32_MAX, S32_MAX, &right_x, /*use_ellipses*/FALSE, /*use_color*/FALSE ); + S32_MAX, S32_MAX, &right_x); } //--------------------------------------------------------------------------------// @@ -1013,7 +1013,7 @@ void LLFolderViewItem::draw() F32 yy = (F32)getRect().getHeight() - font->getLineHeight() - (F32)mTextPad - (F32)TOP_PAD; font->renderUTF8(combined_string, filter_offset, match_string_left, yy, sFilterTextColor, LLFontGL::LEFT, LLFontGL::BOTTOM, LLFontGL::NORMAL, LLFontGL::NO_SHADOW, - filter_string_length, S32_MAX, &right_x, FALSE, FALSE); + filter_string_length, S32_MAX, &right_x); } else { @@ -1024,7 +1024,7 @@ void LLFolderViewItem::draw() F32 yy = (F32)getRect().getHeight() - font->getLineHeight() - (F32)mTextPad - (F32)TOP_PAD; font->renderUTF8(mLabel, filter_offset, match_string_left, yy, sFilterTextColor, LLFontGL::LEFT, LLFontGL::BOTTOM, LLFontGL::NORMAL, LLFontGL::NO_SHADOW, - label_filter_length, S32_MAX, &right_x, FALSE, FALSE); + label_filter_length, S32_MAX, &right_x); } S32 suffix_filter_length = label_filter_length > 0 ? filter_string_length - label_filter_length : filter_string_length; @@ -1035,7 +1035,7 @@ void LLFolderViewItem::draw() F32 yy = (F32)getRect().getHeight() - suffix_font->getLineHeight() - (F32)mTextPad - (F32)TOP_PAD; suffix_font->renderUTF8(mLabelSuffix, suffix_offset, match_string_left, yy, sFilterTextColor, LLFontGL::LEFT, LLFontGL::BOTTOM, LLFontGL::NORMAL, LLFontGL::NO_SHADOW, - suffix_filter_length, S32_MAX, &right_x, FALSE, FALSE); + suffix_filter_length, S32_MAX, &right_x); } } diff --git a/indra/llui/lllineeditor.cpp b/indra/llui/lllineeditor.cpp index bd6fd5b79e..e032b4b8c2 100644 --- a/indra/llui/lllineeditor.cpp +++ b/indra/llui/lllineeditor.cpp @@ -2107,7 +2107,7 @@ void LLLineEditor::draw() LLFontGL::NO_SHADOW, S32_MAX, mTextRightEdge - ll_round(rendered_pixels_right), - &rendered_pixels_right, FALSE); + &rendered_pixels_right); } // Draw children (border) LLView::draw(); diff --git a/indra/llui/llview.cpp b/indra/llui/llview.cpp index 7b6661a519..0afccef735 100644 --- a/indra/llui/llview.cpp +++ b/indra/llui/llview.cpp @@ -1336,8 +1336,7 @@ void LLView::drawDebugRect() std::string debug_text = llformat("%s (%d x %d)", getName().c_str(), debug_rect.getWidth(), debug_rect.getHeight()); LLFontGL::getFontSansSerifSmall()->renderUTF8(debug_text, 0, (F32)x, (F32)y, border_color, - LLFontGL::HCENTER, LLFontGL::BASELINE, LLFontGL::NORMAL, LLFontGL::NO_SHADOW, - S32_MAX, S32_MAX, NULL, /*use_ellipses*/FALSE, /*use_color*/FALSE); + LLFontGL::HCENTER, LLFontGL::BASELINE, LLFontGL::NORMAL, LLFontGL::NO_SHADOW); } } LLUI::popMatrix(); -- cgit v1.2.3 From f6ceafee5bb26cf86d64959cabf68deefaf791a8 Mon Sep 17 00:00:00 2001 From: Alexander Gavriliuk Date: Mon, 22 Jan 2024 06:40:41 +0100 Subject: SL-20416 Avoid of taking focus by EmojiPicker --- indra/llui/llemojidictionary.cpp | 132 +++++++++++++++++++-------------------- indra/llui/llemojidictionary.h | 1 + indra/llui/llemojihelper.cpp | 7 ++- indra/llui/llemojihelper.h | 4 +- indra/llui/llfloater.cpp | 28 +++++++-- indra/llui/llfloater.h | 5 +- indra/llui/lltexteditor.cpp | 24 ++++++- indra/llui/lltexteditor.h | 1 + indra/llui/lluictrl.cpp | 25 +++----- 9 files changed, 132 insertions(+), 95 deletions(-) (limited to 'indra/llui') diff --git a/indra/llui/llemojidictionary.cpp b/indra/llui/llemojidictionary.cpp index e29f3436cf..f16c38a11a 100644 --- a/indra/llui/llemojidictionary.cpp +++ b/indra/llui/llemojidictionary.cpp @@ -41,9 +41,9 @@ static const std::string SKINNED_EMOJI_FILENAME("emoji_characters.xml"); static const std::string SKINNED_CATEGORY_FILENAME("emoji_categories.xml"); static const std::string COMMON_GROUP_FILENAME("emoji_groups.xml"); -static const std::string GROUP_NAME_ALL("all"); -static const std::string GROUP_NAME_OTHERS("others"); static const std::string GROUP_NAME_SKIP("skip"); +// https://www.compart.com/en/unicode/U+1F302 +static const S32 GROUP_OTHERS_IMAGE_INDEX = 0x1F302; // ============================================================================ // Helper functions @@ -143,68 +143,76 @@ LLWString LLEmojiDictionary::findMatchingEmojis(const std::string& needle) const return result; } -void LLEmojiDictionary::findByShortCode(std::vector& result, const std::string& needle) const +// static +bool LLEmojiDictionary::searchInShortCode(std::size_t& begin, std::size_t& end, const std::string& shortCode, const std::string& needle) +{ + begin = 0; + end = 1; + std::size_t index = 1; + // Search for begin + char d = tolower(needle[index++]); + while (end < shortCode.size()) + { + char s = tolower(shortCode[end++]); + if (s == d) + { + begin = end - 1; + break; + } + } + if (!begin) + return false; + // Search for end + d = tolower(needle[index++]); + if (!d) + return true; + while (end < shortCode.size() && index <= needle.size()) + { + char s = tolower(shortCode[end++]); + if (s == d) + { + if (index == needle.size()) + return true; + d = tolower(needle[index++]); + continue; + } + switch (s) + { + case L'-': + case L'_': + case L'+': + continue; + } + break; + } + return false; +} + +void LLEmojiDictionary::findByShortCode( + std::vector& result, + const std::string& needle +) const { result.clear(); if (needle.empty() || needle.front() != ':') return; - auto search = [needle](std::size_t& begin, std::size_t& end, const std::string& shortCode) -> bool + std::map> results; + + for (const LLEmojiDescriptor& d : mEmojis) + { + if (!d.ShortCodes.empty()) { - begin = 0; - end = 1; - std::size_t index = 1; - // Search for begin - char d = tolower(needle[index++]); - while (end < shortCode.size()) + const std::string& shortCode = d.ShortCodes.front(); + if (shortCode.size() >= needle.size() && shortCode.front() == needle.front()) { - char s = tolower(shortCode[end++]); - if (s == d) + std::size_t begin, end; + if (searchInShortCode(begin, end, shortCode, needle)) { - begin = end - 1; - break; + results[begin].emplace_back(d.Character, shortCode, begin, end); } } - if (!begin) - return false; - // Search for end - d = tolower(needle[index++]); - while (end < shortCode.size() && index <= needle.size()) - { - char s = tolower(shortCode[end++]); - if (s == d) - { - if (index == needle.size()) - return true; - d = tolower(needle[index++]); - continue; - } - switch (s) - { - case L'-': - case L'_': - case L'+': - continue; - } - break; - } - return false; - }; - - std::map> results; - - for (const LLEmojiDescriptor& d : mEmojis) - { - if (d.ShortCodes.empty()) - continue; - const std::string& shortCode = d.ShortCodes.front(); - if (shortCode.size() < needle.size() || shortCode.front() != needle.front()) - continue; - std::size_t begin, end; - if (search(begin, end, shortCode)) - { - results[begin].emplace_back(d.Character, shortCode, begin, end); } } @@ -312,27 +320,13 @@ void LLEmojiDictionary::loadGroups() } mGroups.clear(); - // Add group "all" - mGroups.emplace_back(); - // https://www.compart.com/en/unicode/U+1F50D - mGroups.front().Character = 0x1F50D; - // https://www.compart.com/en/unicode/U+1F302 - llwchar iconOthers = 0x1F302; // Register all groups for (LLSD::array_const_iterator it = data.beginArray(), end = data.endArray(); it != end; ++it) { const LLSD& sd = *it; const std::string& name = sd["Name"].asStringRef(); - if (name == GROUP_NAME_ALL) - { - mGroups.front().Character = loadIcon(sd); - } - else if (name == GROUP_NAME_OTHERS) - { - iconOthers = loadIcon(sd); - } - else if (name == GROUP_NAME_SKIP) + if (name == GROUP_NAME_SKIP) { mSkipCategories = loadCategories(sd); translateCategories(mSkipCategories); @@ -355,7 +349,7 @@ void LLEmojiDictionary::loadGroups() // Add group "others" mGroups.emplace_back(); - mGroups.back().Character = iconOthers; + mGroups.back().Character = GROUP_OTHERS_IMAGE_INDEX; } void LLEmojiDictionary::loadEmojis() diff --git a/indra/llui/llemojidictionary.h b/indra/llui/llemojidictionary.h index 66b564b70a..4af376df64 100644 --- a/indra/llui/llemojidictionary.h +++ b/indra/llui/llemojidictionary.h @@ -89,6 +89,7 @@ public: static void initClass(); LLWString findMatchingEmojis(const std::string& needle) const; + static bool searchInShortCode(std::size_t& begin, std::size_t& end, const std::string& shortCode, const std::string& needle); void findByShortCode(std::vector& result, const std::string& needle) const; const LLEmojiDescriptor* getDescriptorFromEmoji(llwchar emoji) const; const LLEmojiDescriptor* getDescriptorFromShortCode(const std::string& short_code) const; diff --git a/indra/llui/llemojihelper.cpp b/indra/llui/llemojihelper.cpp index 9411f7cac5..89e6ddf987 100644 --- a/indra/llui/llemojihelper.cpp +++ b/indra/llui/llemojihelper.cpp @@ -36,7 +36,7 @@ // Constants // -constexpr char DEFAULT_EMOJI_HELPER_FLOATER[] = "emoji_complete"; +constexpr char DEFAULT_EMOJI_HELPER_FLOATER[] = "emoji_picker"; constexpr S32 HELPER_FLOATER_OFFSET_X = 0; constexpr S32 HELPER_FLOATER_OFFSET_Y = 0; @@ -117,9 +117,10 @@ void LLEmojiHelper::showHelper(LLUICtrl* hostctrl_p, S32 local_x, S32 local_y, c pHelperFloater->openFloater(LLSD().with("hint", short_code)); } -void LLEmojiHelper::hideHelper(const LLUICtrl* ctrl_p) +void LLEmojiHelper::hideHelper(const LLUICtrl* ctrl_p, bool strict) { - if (ctrl_p && !isActive(ctrl_p)) + mIsHideDisabled &= !strict; + if (mIsHideDisabled || (ctrl_p && !isActive(ctrl_p))) { return; } diff --git a/indra/llui/llemojihelper.h b/indra/llui/llemojihelper.h index 58f68d12a4..e826ff93e6 100644 --- a/indra/llui/llemojihelper.h +++ b/indra/llui/llemojihelper.h @@ -45,7 +45,8 @@ public: bool isActive(const LLUICtrl* ctrl_p) const; static bool isCursorInEmojiCode(const LLWString& wtext, S32 cursor_pos, S32* short_code_pos_p = nullptr); void showHelper(LLUICtrl* hostctrl_p, S32 local_x, S32 local_y, const std::string& short_code, std::function commit_cb); - void hideHelper(const LLUICtrl* ctrl_p = nullptr); + void hideHelper(const LLUICtrl* ctrl_p = nullptr, bool strict = false); + void setIsHideDisabled(bool disabled) { mIsHideDisabled = disabled; }; // Eventing bool handleKey(const LLUICtrl* ctrl_p, KEY key, MASK mask); @@ -61,4 +62,5 @@ private: boost::signals2::connection mHostCtrlFocusLostConn; boost::signals2::connection mHelperCommitConn; std::function mEmojiCommitCb; + bool mIsHideDisabled; }; diff --git a/indra/llui/llfloater.cpp b/indra/llui/llfloater.cpp index 23d3a66631..31019f6c33 100644 --- a/indra/llui/llfloater.cpp +++ b/indra/llui/llfloater.cpp @@ -182,6 +182,7 @@ LLFloater::Params::Params() save_visibility("save_visibility", false), can_dock("can_dock", false), show_title("show_title", true), + auto_close("auto_close", false), positioning("positioning", LLFloaterEnums::POSITIONING_RELATIVE), header_height("header_height", 0), legacy_header_height("legacy_header_height", 0), @@ -254,6 +255,7 @@ LLFloater::LLFloater(const LLSD& key, const LLFloater::Params& p) mCanClose(p.can_close), mDragOnLeft(p.can_drag_on_left), mResizable(p.can_resize), + mAutoClose(p.auto_close), mPositioning(p.positioning), mMinWidth(p.min_width), mMinHeight(p.min_height), @@ -681,7 +683,7 @@ void LLFloater::openFloater(const LLSD& key) if (getHost() != NULL) { getHost()->setMinimized(FALSE); - getHost()->setVisibleAndFrontmost(mAutoFocus); + getHost()->setVisibleAndFrontmost(mAutoFocus && !getIsChrome()); getHost()->showFloater(this); } else @@ -693,7 +695,7 @@ void LLFloater::openFloater(const LLSD& key) } applyControlsAndPosition(floater_to_stack); setMinimized(FALSE); - setVisibleAndFrontmost(mAutoFocus); + setVisibleAndFrontmost(mAutoFocus && !getIsChrome()); } mOpenSignal(this, key); @@ -1551,7 +1553,7 @@ void LLFloater::addDependentFloater(LLFloater* floaterp, BOOL reposition, BOOL r if (floaterp->isFrontmost()) { // make sure to bring self and sibling floaters to front - gFloaterView->bringToFront(floaterp); + gFloaterView->bringToFront(floaterp, floaterp->getAutoFocus() && !getIsChrome()); } } @@ -1696,6 +1698,7 @@ BOOL LLFloater::handleDoubleClick(S32 x, S32 y, MASK mask) return was_minimized || LLPanel::handleDoubleClick(x, y, mask); } +// virtual void LLFloater::bringToFront( S32 x, S32 y ) { if (getVisible() && pointInView(x, y)) @@ -1710,12 +1713,20 @@ void LLFloater::bringToFront( S32 x, S32 y ) LLFloaterView* parent = dynamic_cast( getParent() ); if (parent) { - parent->bringToFront( this ); + parent->bringToFront(this, !getIsChrome()); } } } } +// virtual +void LLFloater::goneFromFront() +{ + if (mAutoClose) + { + closeFloater(); + } +} // virtual void LLFloater::setVisibleAndFrontmost(BOOL take_focus,const LLSD& key) @@ -2561,6 +2572,11 @@ void LLFloaterView::bringToFront(LLFloater* child, BOOL give_focus, BOOL restore return; } + if (mFrontChild && !mFrontChild->isDead()) + { + mFrontChild->goneFromFront(); + } + mFrontChild = child; // *TODO: make this respect floater's mAutoFocus value, instead of @@ -3060,6 +3076,9 @@ LLFloater *LLFloaterView::getBackmost() const void LLFloaterView::syncFloaterTabOrder() { + if (mFrontChild && !mFrontChild->isDead() && mFrontChild->getIsChrome()) + return; + // look for a visible modal dialog, starting from first LLModalDialog* modal_dialog = NULL; for ( child_list_const_iter_t child_it = getChildList()->begin(); child_it != getChildList()->end(); ++child_it) @@ -3307,6 +3326,7 @@ void LLFloater::initFromParams(const LLFloater::Params& p) mDefaultRelativeY = p.rel_y; mPositioning = p.positioning; + mAutoClose = p.auto_close; mSaveRect = p.save_rect; if (p.save_visibility) diff --git a/indra/llui/llfloater.h b/indra/llui/llfloater.h index 860a6f9e2a..5f4e1a2cad 100644 --- a/indra/llui/llfloater.h +++ b/indra/llui/llfloater.h @@ -163,7 +163,8 @@ public: save_visibility, save_dock_state, can_dock, - show_title; + show_title, + auto_close; Optional positioning; @@ -390,6 +391,7 @@ protected: void setInstanceName(const std::string& name); virtual void bringToFront(S32 x, S32 y); + virtual void goneFromFront(); void setExpandedRect(const LLRect& rect) { mExpandedRect = rect; } // size when not minimized const LLRect& getExpandedRect() const { return mExpandedRect; } @@ -488,6 +490,7 @@ private: bool mFocusStealsFrontmost = true; // FALSE if we don't want the currently focused floater to cover this floater without user interaction BOOL mDragOnLeft; BOOL mResizable; + BOOL mAutoClose; LLFloaterEnums::EOpenPositioning mPositioning; LLCoordFloater mPosition; diff --git a/indra/llui/lltexteditor.cpp b/indra/llui/lltexteditor.cpp index 3910be1443..092739a538 100644 --- a/indra/llui/lltexteditor.cpp +++ b/indra/llui/lltexteditor.cpp @@ -508,7 +508,8 @@ void LLTextEditor::getSegmentsInRange(LLTextEditor::segment_vec_t& segments_out, } } -void LLTextEditor::setShowEmojiHelper(bool show) { +void LLTextEditor::setShowEmojiHelper(bool show) +{ if (!mShowEmojiHelper) { LLEmojiHelper::instance().hideHelper(this); @@ -1192,6 +1193,16 @@ void LLTextEditor::addChar(llwchar wc) } } +void LLTextEditor::showEmojiHelper() +{ + if (mReadOnly || !mShowEmojiHelper) + return; + + const LLRect cursorRect(getLocalRectFromDocIndex(mCursorPos)); + auto cb = [this](llwchar emoji) { insertEmoji(emoji); }; + LLEmojiHelper::instance().showHelper(this, cursorRect.mLeft, cursorRect.mTop, LLStringUtil::null, cb); +} + void LLTextEditor::tryToShowEmojiHelper() { if (mReadOnly || !mShowEmojiHelper) @@ -1207,6 +1218,10 @@ void LLTextEditor::tryToShowEmojiHelper() auto cb = [this](llwchar emoji) { handleEmojiCommit(emoji); }; LLEmojiHelper::instance().showHelper(this, cursorRect.mLeft, cursorRect.mTop, part, cb); } + else + { + LLEmojiHelper::instance().hideHelper(); + } } void LLTextEditor::addLineBreakChar(BOOL group_together) @@ -1911,7 +1926,12 @@ BOOL LLTextEditor::handleUnicodeCharHere(llwchar uni_char) // Handle most keys only if the text editor is writeable. if( !mReadOnly ) { - if( mAutoIndent && '}' == uni_char ) + if (mShowEmojiHelper && uni_char < 0x80 && LLEmojiHelper::instance().handleKey(this, (KEY)uni_char, MASK_NONE)) + { + return TRUE; + } + + if( mAutoIndent && '}' == uni_char ) { unindentLineBeforeCloseBrace(); } diff --git a/indra/llui/lltexteditor.h b/indra/llui/lltexteditor.h index 7a96e17899..521405ec25 100644 --- a/indra/llui/lltexteditor.h +++ b/indra/llui/lltexteditor.h @@ -206,6 +206,7 @@ public: void setShowContextMenu(bool show) { mShowContextMenu = show; } bool getShowContextMenu() const { return mShowContextMenu; } + void showEmojiHelper(); void setShowEmojiHelper(bool show); bool getShowEmojiHelper() const { return mShowEmojiHelper; } diff --git a/indra/llui/lluictrl.cpp b/indra/llui/lluictrl.cpp index 21afcae7c3..7eb9ae69fb 100644 --- a/indra/llui/lluictrl.cpp +++ b/indra/llui/lluictrl.cpp @@ -768,25 +768,20 @@ void LLUICtrl::setIsChrome(BOOL is_chrome) // virtual BOOL LLUICtrl::getIsChrome() const -{ +{ + if (mIsChrome) + return TRUE; + LLView* parent_ctrl = getParent(); - while(parent_ctrl) + while (parent_ctrl) { - if(parent_ctrl->isCtrl()) - { - break; - } + if (parent_ctrl->isCtrl()) + return ((LLUICtrl*)parent_ctrl)->getIsChrome(); + parent_ctrl = parent_ctrl->getParent(); } - - if(parent_ctrl) - { - return mIsChrome || ((LLUICtrl*)parent_ctrl)->getIsChrome(); - } - else - { - return mIsChrome ; - } + + return FALSE; } -- cgit v1.2.3 From fea01389c94002ffce639cab164280b3e558147c Mon Sep 17 00:00:00 2001 From: Alexander Gavriliuk Date: Tue, 23 Jan 2024 23:13:00 +0100 Subject: SL-20416 Fix Crash Report 1409376 --- indra/llui/llfloater.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'indra/llui') diff --git a/indra/llui/llfloater.cpp b/indra/llui/llfloater.cpp index 31019f6c33..fb90cebd39 100644 --- a/indra/llui/llfloater.cpp +++ b/indra/llui/llfloater.cpp @@ -2572,7 +2572,7 @@ void LLFloaterView::bringToFront(LLFloater* child, BOOL give_focus, BOOL restore return; } - if (mFrontChild && !mFrontChild->isDead()) + if (mFrontChild && !mFrontChild->isDead() && mFrontChild->getVisible()) { mFrontChild->goneFromFront(); } -- cgit v1.2.3 From cc43f42e6b7401c2cdd3204a16f757f5169bd95b Mon Sep 17 00:00:00 2001 From: Alexander Gavriliuk Date: Wed, 24 Jan 2024 18:24:41 +0100 Subject: SL-20416 Fix Crash Report 1409376 (update) --- indra/llui/llfloater.cpp | 11 ++++++++++- indra/llui/llfloater.h | 1 + 2 files changed, 11 insertions(+), 1 deletion(-) (limited to 'indra/llui') diff --git a/indra/llui/llfloater.cpp b/indra/llui/llfloater.cpp index fb90cebd39..de3de53569 100644 --- a/indra/llui/llfloater.cpp +++ b/indra/llui/llfloater.cpp @@ -506,6 +506,7 @@ void LLFloater::enableResizeCtrls(bool enable, bool width, bool height) void LLFloater::destroy() { + gFloaterView->onDestroyFloater(this); // LLFloaterReg should be synchronized with "dead" floater to avoid returning dead instance before // it was deleted via LLMortician::updateClass(). See EXT-8458. LLFloaterReg::removeInstance(mInstanceName, mKey); @@ -2572,7 +2573,7 @@ void LLFloaterView::bringToFront(LLFloater* child, BOOL give_focus, BOOL restore return; } - if (mFrontChild && !mFrontChild->isDead() && mFrontChild->getVisible()) + if (mFrontChild) { mFrontChild->goneFromFront(); } @@ -3234,6 +3235,14 @@ void LLFloaterView::setToolbarRect(LLToolBarEnums::EToolBarLocation tb, const LL } } +void LLFloaterView::onDestroyFloater(LLFloater* floater) +{ + if (mFrontChild == floater) + { + mFrontChild = nullptr; + } +} + void LLFloater::setInstanceName(const std::string& name) { if (name != mInstanceName) diff --git a/indra/llui/llfloater.h b/indra/llui/llfloater.h index 5f4e1a2cad..88f9e77777 100644 --- a/indra/llui/llfloater.h +++ b/indra/llui/llfloater.h @@ -607,6 +607,7 @@ public: LLFloater* getFrontmostClosableFloater(); void setToolbarRect(LLToolBarEnums::EToolBarLocation tb, const LLRect& toolbar_rect); + void onDestroyFloater(LLFloater* floater); private: void hiddenFloaterClosed(LLFloater* floater); -- cgit v1.2.3 From 7075717b7c4a57d6bef60697ee506096a7c1b1ab Mon Sep 17 00:00:00 2001 From: Alexander Gavriliuk Date: Wed, 7 Feb 2024 21:26:57 +0100 Subject: SL-20363 Add Advanced option 'Debug Unicode' --- indra/llui/lllineeditor.cpp | 14 ++++++ indra/llui/lllineeditor.h | 112 ++++++++++++++++++++++---------------------- indra/llui/lltextbase.cpp | 24 ++++++++++ indra/llui/lltextbase.h | 66 +++++++++++++------------- indra/llui/llview.cpp | 1 + indra/llui/llview.h | 3 ++ 6 files changed, 133 insertions(+), 87 deletions(-) (limited to 'indra/llui') diff --git a/indra/llui/lllineeditor.cpp b/indra/llui/lllineeditor.cpp index e032b4b8c2..453fa29e7c 100644 --- a/indra/llui/lllineeditor.cpp +++ b/indra/llui/lllineeditor.cpp @@ -1739,6 +1739,20 @@ void LLLineEditor::drawBackground() } } +//virtual +const std::string LLLineEditor::getToolTip() const +{ + if (sDebugUnicode) + { + std::string text = getText(); + std::string tooltip = utf8str_showBytesUTF8(text); + return tooltip; + } + + return LLUICtrl::getToolTip(); +} + +//virtual void LLLineEditor::draw() { F32 alpha = getDrawContext().mAlpha; diff --git a/indra/llui/lllineeditor.h b/indra/llui/lllineeditor.h index 69eb0792e1..5794b3c35a 100644 --- a/indra/llui/lllineeditor.h +++ b/indra/llui/lllineeditor.h @@ -119,54 +119,55 @@ protected: friend class LLUICtrlFactory; friend class LLFloaterEditUI; void showContextMenu(S32 x, S32 y); + public: virtual ~LLLineEditor(); // mousehandler overrides - /*virtual*/ BOOL handleMouseDown(S32 x, S32 y, MASK mask); - /*virtual*/ BOOL handleMouseUp(S32 x, S32 y, MASK mask); - /*virtual*/ BOOL handleHover(S32 x, S32 y, MASK mask); - /*virtual*/ BOOL handleDoubleClick(S32 x,S32 y,MASK mask); - /*virtual*/ BOOL handleMiddleMouseDown(S32 x,S32 y,MASK mask); - /*virtual*/ BOOL handleRightMouseDown(S32 x, S32 y, MASK mask); - /*virtual*/ BOOL handleKeyHere(KEY key, MASK mask ); - /*virtual*/ BOOL handleUnicodeCharHere(llwchar uni_char); - /*virtual*/ void onMouseCaptureLost(); + /*virtual*/ BOOL handleMouseDown(S32 x, S32 y, MASK mask) override; + /*virtual*/ BOOL handleMouseUp(S32 x, S32 y, MASK mask) override; + /*virtual*/ BOOL handleHover(S32 x, S32 y, MASK mask) override; + /*virtual*/ BOOL handleDoubleClick(S32 x,S32 y,MASK mask) override; + /*virtual*/ BOOL handleMiddleMouseDown(S32 x,S32 y,MASK mask) override; + /*virtual*/ BOOL handleRightMouseDown(S32 x, S32 y, MASK mask) override; + /*virtual*/ BOOL handleKeyHere(KEY key, MASK mask) override; + /*virtual*/ BOOL handleUnicodeCharHere(llwchar uni_char) override; + /*virtual*/ void onMouseCaptureLost() override; // LLEditMenuHandler overrides - virtual void cut(); - virtual BOOL canCut() const; - virtual void copy(); - virtual BOOL canCopy() const; - virtual void paste(); - virtual BOOL canPaste() const; + /*virtual*/ void cut() override; + /*virtual*/ BOOL canCut() const override; + /*virtual*/ void copy() override; + /*virtual*/ BOOL canCopy() const override; + /*virtual*/ void paste() override; + /*virtual*/ BOOL canPaste() const override; virtual void updatePrimary(); virtual void copyPrimary(); virtual void pastePrimary(); virtual BOOL canPastePrimary() const; - virtual void doDelete(); - virtual BOOL canDoDelete() const; + /*virtual*/ void doDelete() override; + /*virtual*/ BOOL canDoDelete() const override; - virtual void selectAll(); - virtual BOOL canSelectAll() const; + /*virtual*/ void selectAll() override; + /*virtual*/ BOOL canSelectAll() const override; - virtual void deselect(); - virtual BOOL canDeselect() const; + /*virtual*/ void deselect() override; + /*virtual*/ BOOL canDeselect() const override; // LLSpellCheckMenuHandler overrides - /*virtual*/ bool getSpellCheck() const; + /*virtual*/ bool getSpellCheck() const override; - /*virtual*/ const std::string& getSuggestion(U32 index) const; - /*virtual*/ U32 getSuggestionCount() const; - /*virtual*/ void replaceWithSuggestion(U32 index); + /*virtual*/ const std::string& getSuggestion(U32 index) const override; + /*virtual*/ U32 getSuggestionCount() const override; + /*virtual*/ void replaceWithSuggestion(U32 index) override; - /*virtual*/ void addToDictionary(); - /*virtual*/ bool canAddToDictionary() const; + /*virtual*/ void addToDictionary() override; + /*virtual*/ bool canAddToDictionary() const override; - /*virtual*/ void addToIgnore(); - /*virtual*/ bool canAddToIgnore() const; + /*virtual*/ void addToIgnore() override; + /*virtual*/ bool canAddToIgnore() const override; // Spell checking helper functions std::string getMisspelledWord(U32 pos) const; @@ -174,27 +175,28 @@ public: void onSpellCheckSettingsChange(); // view overrides - virtual void draw(); - virtual void reshape(S32 width,S32 height,BOOL called_from_parent=TRUE); - virtual void onFocusReceived(); - virtual void onFocusLost(); - virtual void setEnabled(BOOL enabled); + /*virtual*/ const std::string getToolTip() const override; + /*virtual*/ void draw() override; + /*virtual*/ void reshape(S32 width, S32 height, BOOL called_from_parent = TRUE) override; + /*virtual*/ void onFocusReceived() override; + /*virtual*/ void onFocusLost() override; + /*virtual*/ void setEnabled(BOOL enabled) override; // UI control overrides - virtual void clear(); - virtual void onTabInto(); - virtual void setFocus( BOOL b ); - virtual void setRect(const LLRect& rect); - virtual BOOL acceptsTextInput() const; - virtual void onCommit(); - virtual BOOL isDirty() const; // Returns TRUE if user changed value at all - virtual void resetDirty(); // Clear dirty state + /*virtual*/ void clear() override; + /*virtual*/ void onTabInto() override; + /*virtual*/ void setFocus(BOOL b) override; + /*virtual*/ void setRect(const LLRect& rect) override; + /*virtual*/ BOOL acceptsTextInput() const override; + /*virtual*/ void onCommit() override; + /*virtual*/ BOOL isDirty() const override; // Returns TRUE if user changed value at all + /*virtual*/ void resetDirty() override; // Clear dirty state // assumes UTF8 text - virtual void setValue(const LLSD& value ); - virtual LLSD getValue() const; - virtual BOOL setTextArg( const std::string& key, const LLStringExplicit& text ); - virtual BOOL setLabelArg( const std::string& key, const LLStringExplicit& text ); + /*virtual*/ void setValue(const LLSD& value) override; + /*virtual*/ LLSD getValue() const override; + /*virtual*/ BOOL setTextArg(const std::string& key, const LLStringExplicit& text) override; + /*virtual*/ BOOL setLabelArg(const std::string& key, const LLStringExplicit& text) override; void setLabel(const LLStringExplicit &new_label) { mLabel = new_label; } const std::string& getLabel() { return mLabel.getString(); } @@ -216,7 +218,7 @@ public: // Selects characters 'start' to 'end'. void setSelection(S32 start, S32 end); - virtual void getSelectionRange(S32 *position, S32 *length) const; + /*virtual*/ void getSelectionRange(S32 *position, S32 *length) const override; void setCommitOnFocusLost( BOOL b ) { mCommitOnFocusLost = b; } void setRevertOnEsc( BOOL b ) { mRevertOnEsc = b; } @@ -315,14 +317,14 @@ public: void updateAllowingLanguageInput(); BOOL hasPreeditString() const; // Implementation (overrides) of LLPreeditor - virtual void resetPreedit(); - virtual void updatePreedit(const LLWString &preedit_string, - const segment_lengths_t &preedit_segment_lengths, const standouts_t &preedit_standouts, S32 caret_position); - virtual void markAsPreedit(S32 position, S32 length); - virtual void getPreeditRange(S32 *position, S32 *length) const; - virtual BOOL getPreeditLocation(S32 query_position, LLCoordGL *coord, LLRect *bounds, LLRect *control) const; - virtual S32 getPreeditFontSize() const; - virtual LLWString getPreeditString() const { return getWText(); } + /*virtual*/ void resetPreedit() override; + /*virtual*/ void updatePreedit(const LLWString &preedit_string, + const segment_lengths_t &preedit_segment_lengths, const standouts_t &preedit_standouts, S32 caret_position) override; + /*virtual*/ void markAsPreedit(S32 position, S32 length) override; + /*virtual*/ void getPreeditRange(S32 *position, S32 *length) const override; + /*virtual*/ BOOL getPreeditLocation(S32 query_position, LLCoordGL *coord, LLRect *bounds, LLRect *control) const override; + /*virtual*/ S32 getPreeditFontSize() const override; + /*virtual*/ LLWString getPreeditString() const override { return getWText(); } void setText(const LLStringExplicit &new_text, bool use_size_limit); diff --git a/indra/llui/lltextbase.cpp b/indra/llui/lltextbase.cpp index 8f628b4818..7ccf025a19 100644 --- a/indra/llui/lltextbase.cpp +++ b/indra/llui/lltextbase.cpp @@ -1107,6 +1107,7 @@ void LLTextBase::insertSegment(LLTextSegmentPtr segment_to_insert) needsReflow(reflow_start_index); } +//virtual BOOL LLTextBase::handleMouseDown(S32 x, S32 y, MASK mask) { // handle triple click @@ -1161,6 +1162,7 @@ BOOL LLTextBase::handleMouseDown(S32 x, S32 y, MASK mask) return LLUICtrl::handleMouseDown(x, y, mask); } +//virtual BOOL LLTextBase::handleMouseUp(S32 x, S32 y, MASK mask) { LLTextSegmentPtr cur_segment = getSegmentAtLocalPos(x, y); @@ -1180,6 +1182,7 @@ BOOL LLTextBase::handleMouseUp(S32 x, S32 y, MASK mask) return LLUICtrl::handleMouseUp(x, y, mask); } +//virtual BOOL LLTextBase::handleMiddleMouseDown(S32 x, S32 y, MASK mask) { LLTextSegmentPtr cur_segment = getSegmentAtLocalPos(x, y); @@ -1191,6 +1194,7 @@ BOOL LLTextBase::handleMiddleMouseDown(S32 x, S32 y, MASK mask) return LLUICtrl::handleMiddleMouseDown(x, y, mask); } +//virtual BOOL LLTextBase::handleMiddleMouseUp(S32 x, S32 y, MASK mask) { LLTextSegmentPtr cur_segment = getSegmentAtLocalPos(x, y); @@ -1202,6 +1206,7 @@ BOOL LLTextBase::handleMiddleMouseUp(S32 x, S32 y, MASK mask) return LLUICtrl::handleMiddleMouseUp(x, y, mask); } +//virtual BOOL LLTextBase::handleRightMouseDown(S32 x, S32 y, MASK mask) { LLTextSegmentPtr cur_segment = getSegmentAtLocalPos(x, y); @@ -1213,6 +1218,7 @@ BOOL LLTextBase::handleRightMouseDown(S32 x, S32 y, MASK mask) return LLUICtrl::handleRightMouseDown(x, y, mask); } +//virtual BOOL LLTextBase::handleRightMouseUp(S32 x, S32 y, MASK mask) { LLTextSegmentPtr cur_segment = getSegmentAtLocalPos(x, y); @@ -1224,6 +1230,7 @@ BOOL LLTextBase::handleRightMouseUp(S32 x, S32 y, MASK mask) return LLUICtrl::handleRightMouseUp(x, y, mask); } +//virtual BOOL LLTextBase::handleDoubleClick(S32 x, S32 y, MASK mask) { //Don't start triple click timer if user have clicked on scrollbar @@ -1243,6 +1250,7 @@ BOOL LLTextBase::handleDoubleClick(S32 x, S32 y, MASK mask) return LLUICtrl::handleDoubleClick(x, y, mask); } +//virtual BOOL LLTextBase::handleHover(S32 x, S32 y, MASK mask) { LLTextSegmentPtr cur_segment = getSegmentAtLocalPos(x, y); @@ -1254,6 +1262,7 @@ BOOL LLTextBase::handleHover(S32 x, S32 y, MASK mask) return LLUICtrl::handleHover(x, y, mask); } +//virtual BOOL LLTextBase::handleScrollWheel(S32 x, S32 y, S32 clicks) { LLTextSegmentPtr cur_segment = getSegmentAtLocalPos(x, y); @@ -1265,6 +1274,7 @@ BOOL LLTextBase::handleScrollWheel(S32 x, S32 y, S32 clicks) return LLUICtrl::handleScrollWheel(x, y, clicks); } +//virtual BOOL LLTextBase::handleToolTip(S32 x, S32 y, MASK mask) { LLTextSegmentPtr cur_segment = getSegmentAtLocalPos(x, y); @@ -1276,7 +1286,20 @@ BOOL LLTextBase::handleToolTip(S32 x, S32 y, MASK mask) return LLUICtrl::handleToolTip(x, y, mask); } +//virtual +const std::string LLTextBase::getToolTip() const +{ + if (sDebugUnicode) + { + std::string text = getText(); + std::string tooltip = utf8str_showBytesUTF8(text); + return tooltip; + } + return LLUICtrl::getToolTip(); +} + +//virtual void LLTextBase::reshape(S32 width, S32 height, BOOL called_from_parent) { if (width != getRect().getWidth() || height != getRect().getHeight() || LLView::sForceReshape) @@ -1303,6 +1326,7 @@ void LLTextBase::reshape(S32 width, S32 height, BOOL called_from_parent) } } +//virtual void LLTextBase::draw() { // reflow if needed, on demand diff --git a/indra/llui/lltextbase.h b/indra/llui/lltextbase.h index 37ab798a1d..9d3c54fbee 100644 --- a/indra/llui/lltextbase.h +++ b/indra/llui/lltextbase.h @@ -285,7 +285,7 @@ typedef LLPointer LLTextSegmentPtr; /// as LLTextEditor and LLTextBox. It implements shared functionality /// such as Url highlighting and opening. /// -class LLTextBase +class LLTextBase : public LLUICtrl, protected LLEditMenuHandler, public LLSpellCheckMenuHandler, @@ -354,51 +354,52 @@ public: }; // LLMouseHandler interface - /*virtual*/ BOOL handleMouseDown(S32 x, S32 y, MASK mask); - /*virtual*/ BOOL handleMouseUp(S32 x, S32 y, MASK mask); - /*virtual*/ BOOL handleMiddleMouseDown(S32 x, S32 y, MASK mask); - /*virtual*/ BOOL handleMiddleMouseUp(S32 x, S32 y, MASK mask); - /*virtual*/ BOOL handleRightMouseDown(S32 x, S32 y, MASK mask); - /*virtual*/ BOOL handleRightMouseUp(S32 x, S32 y, MASK mask); - /*virtual*/ BOOL handleDoubleClick(S32 x, S32 y, MASK mask); - /*virtual*/ BOOL handleHover(S32 x, S32 y, MASK mask); - /*virtual*/ BOOL handleScrollWheel(S32 x, S32 y, S32 clicks); - /*virtual*/ BOOL handleToolTip(S32 x, S32 y, MASK mask); + /*virtual*/ BOOL handleMouseDown(S32 x, S32 y, MASK mask) override; + /*virtual*/ BOOL handleMouseUp(S32 x, S32 y, MASK mask) override; + /*virtual*/ BOOL handleMiddleMouseDown(S32 x, S32 y, MASK mask) override; + /*virtual*/ BOOL handleMiddleMouseUp(S32 x, S32 y, MASK mask) override; + /*virtual*/ BOOL handleRightMouseDown(S32 x, S32 y, MASK mask) override; + /*virtual*/ BOOL handleRightMouseUp(S32 x, S32 y, MASK mask) override; + /*virtual*/ BOOL handleDoubleClick(S32 x, S32 y, MASK mask) override; + /*virtual*/ BOOL handleHover(S32 x, S32 y, MASK mask) override; + /*virtual*/ BOOL handleScrollWheel(S32 x, S32 y, S32 clicks) override; + /*virtual*/ BOOL handleToolTip(S32 x, S32 y, MASK mask) override; // LLView interface - /*virtual*/ void reshape(S32 width, S32 height, BOOL called_from_parent = TRUE); - /*virtual*/ void draw(); + /*virtual*/ const std::string getToolTip() const override; + /*virtual*/ void reshape(S32 width, S32 height, BOOL called_from_parent = TRUE) override; + /*virtual*/ void draw() override; // LLUICtrl interface - /*virtual*/ BOOL acceptsTextInput() const { return !mReadOnly; } - /*virtual*/ void setColor( const LLColor4& c ); + /*virtual*/ BOOL acceptsTextInput() const override { return !mReadOnly; } + /*virtual*/ void setColor(const LLColor4& c) override; virtual void setReadOnlyColor(const LLColor4 &c); - virtual void onVisibilityChange( BOOL new_visibility ); + /*virtual*/ void onVisibilityChange(BOOL new_visibility) override; - /*virtual*/ void setValue(const LLSD& value ); - /*virtual*/ LLTextViewModel* getViewModel() const; + /*virtual*/ void setValue(const LLSD& value) override; + /*virtual*/ LLTextViewModel* getViewModel() const override; // LLEditMenuHandler interface - /*virtual*/ BOOL canDeselect() const; - /*virtual*/ void deselect(); + /*virtual*/ BOOL canDeselect() const override; + /*virtual*/ void deselect() override; - virtual void onFocusReceived(); - virtual void onFocusLost(); + virtual void onFocusReceived() override; + virtual void onFocusLost() override; void setParseHTML(bool parse_html) { mParseHTML = parse_html; } // LLSpellCheckMenuHandler overrides - /*virtual*/ bool getSpellCheck() const; + /*virtual*/ bool getSpellCheck() const override; - /*virtual*/ const std::string& getSuggestion(U32 index) const; - /*virtual*/ U32 getSuggestionCount() const; - /*virtual*/ void replaceWithSuggestion(U32 index); + /*virtual*/ const std::string& getSuggestion(U32 index) const override; + /*virtual*/ U32 getSuggestionCount() const override; + /*virtual*/ void replaceWithSuggestion(U32 index) override; - /*virtual*/ void addToDictionary(); - /*virtual*/ bool canAddToDictionary() const; + /*virtual*/ void addToDictionary() override; + /*virtual*/ bool canAddToDictionary() const override; - /*virtual*/ void addToIgnore(); - /*virtual*/ bool canAddToIgnore() const; + /*virtual*/ void addToIgnore() override; + /*virtual*/ bool canAddToIgnore() const override; // Spell checking helper functions std::string getMisspelledWord(U32 pos) const; @@ -432,7 +433,7 @@ public: void appendText(const std::string &new_text, bool prepend_newline, const LLStyle::Params& input_params = LLStyle::Params()); void setLabel(const LLStringExplicit& label); - virtual BOOL setLabelArg(const std::string& key, const LLStringExplicit& text ); + /*virtual*/ BOOL setLabelArg(const std::string& key, const LLStringExplicit& text) override; const std::string& getLabel() { return mLabel.getString(); } const LLWString& getWlabel() { return mLabel.getWString();} @@ -649,7 +650,8 @@ protected: S32 normalizeUri(std::string& uri); protected: - virtual std::string _getSearchText() const + // virtual + std::string _getSearchText() const override { return mLabel.getString() + getToolTip(); } diff --git a/indra/llui/llview.cpp b/indra/llui/llview.cpp index 0afccef735..139eb17efa 100644 --- a/indra/llui/llview.cpp +++ b/indra/llui/llview.cpp @@ -60,6 +60,7 @@ static const S32 LINE_HEIGHT = 15; S32 LLView::sDepth = 0; bool LLView::sDebugRects = false; +bool LLView::sDebugUnicode = false; bool LLView::sIsRectDirty = false; LLRect LLView::sDirtyRect; bool LLView::sDebugRectsShowNames = true; diff --git a/indra/llui/llview.h b/indra/llui/llview.h index b498451dce..6e16d41cba 100644 --- a/indra/llui/llview.h +++ b/indra/llui/llview.h @@ -659,6 +659,9 @@ public: // Draw debug rectangles around widgets to help with alignment and spacing static bool sDebugRects; + // Show hexadecimal byte values of unicode symbols in a tooltip + static bool sDebugUnicode; + static bool sIsRectDirty; static LLRect sDirtyRect; -- cgit v1.2.3