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/llemojihelper.cpp | 142 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 142 insertions(+) create mode 100644 indra/llui/llemojihelper.cpp (limited to 'indra/llui/llemojihelper.cpp') 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()); })); + } + } +} -- 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 +++++ 1 file changed, 5 insertions(+) (limited to 'indra/llui/llemojihelper.cpp') 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); } -- 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/llemojihelper.cpp') 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 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/llemojihelper.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'indra/llui/llemojihelper.cpp') 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); -- 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/llemojihelper.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'indra/llui/llemojihelper.cpp') 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 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/llemojihelper.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'indra/llui/llemojihelper.cpp') 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); } } -- 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 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'indra/llui/llemojihelper.cpp') 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) -- 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/llemojihelper.cpp') 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 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/llemojihelper.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'indra/llui/llemojihelper.cpp') 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; } -- cgit v1.2.3