summaryrefslogtreecommitdiff
path: root/indra/llui/llemojihelper.cpp
diff options
context:
space:
mode:
authorKitty Barnett <develop@catznip.com>2022-10-23 16:17:02 +0200
committerKitty Barnett <develop@catznip.com>2022-10-23 16:28:25 +0200
commitdad25bcb1e17e3dc384a9fb35d21b669bc3bbacd (patch)
tree5ed2d1925eaef0b81f31946c9c97d73ca9bb1e02 /indra/llui/llemojihelper.cpp
parentec23b4bc633b853223d8442f60e769d44a25fe2d (diff)
Add the emoji helper class which can be used by text-input controls to provide emoji picker support
Diffstat (limited to 'indra/llui/llemojihelper.cpp')
-rw-r--r--indra/llui/llemojihelper.cpp142
1 files changed, 142 insertions, 0 deletions
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<void(LLWString)> 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()); }));
+ }
+ }
+}