From 0f9d2dca38049224d555b725d23008f6e1a6467d Mon Sep 17 00:00:00 2001
From: Andrey Kleshchev <andreykproductengine@lindenlab.com>
Date: Tue, 8 Oct 2024 22:10:50 +0300
Subject: viewer#2270 The "More" button does not close the "Choose emoji"
 floater

---
 indra/llui/llemojihelper.cpp            | 11 +++++++++
 indra/llui/llemojihelper.h              |  7 ++++++
 indra/llui/lltexteditor.cpp             |  8 +++++++
 indra/llui/lltexteditor.h               |  1 +
 indra/newview/llfloaterimsessiontab.cpp | 42 +++++++++++++++++++++++++++++++--
 indra/newview/llfloaterimsessiontab.h   |  5 ++++
 6 files changed, 72 insertions(+), 2 deletions(-)

diff --git a/indra/llui/llemojihelper.cpp b/indra/llui/llemojihelper.cpp
index b9441a9c91..b2c59ce775 100644
--- a/indra/llui/llemojihelper.cpp
+++ b/indra/llui/llemojihelper.cpp
@@ -99,6 +99,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())[0]); }, std::placeholders::_2));
+        mHelperCloseConn = pHelperFloater->setCloseCallback([this](LLUICtrl* ctrl, const LLSD& param) { onCloseHelper(ctrl, param); });
     }
     setHostCtrl(hostctrl_p);
     mEmojiCommitCb = cb;
@@ -148,6 +149,16 @@ void LLEmojiHelper::onCommitEmoji(llwchar emoji)
     }
 }
 
+void LLEmojiHelper::onCloseHelper(LLUICtrl* ctrl, const LLSD& param)
+{
+    mCloseSignal(ctrl, param);
+}
+
+boost::signals2::connection LLEmojiHelper::setCloseCallback(const commit_signal_t::slot_type& cb)
+{
+    return mCloseSignal.connect(cb);
+}
+
 void LLEmojiHelper::setHostCtrl(LLUICtrl* hostctrl_p)
 {
     const LLUICtrl* pCurHostCtrl = mHostHandle.get();
diff --git a/indra/llui/llemojihelper.h b/indra/llui/llemojihelper.h
index 2834b06061..26840eef94 100644
--- a/indra/llui/llemojihelper.h
+++ b/indra/llui/llemojihelper.h
@@ -51,16 +51,23 @@ public:
     // Eventing
     bool handleKey(const LLUICtrl* ctrl_p, KEY key, MASK mask);
     void onCommitEmoji(llwchar emoji);
+    void onCloseHelper(LLUICtrl* ctrl, const LLSD& param);
+
+    typedef boost::signals2::signal<void(LLUICtrl* ctrl, const LLSD& param)> commit_signal_t;
+    boost::signals2::connection setCloseCallback(const commit_signal_t::slot_type& cb);
 
 protected:
     LLUICtrl* getHostCtrl() const { return mHostHandle.get(); }
     void      setHostCtrl(LLUICtrl* hostctrl_p);
 
 private:
+    commit_signal_t mCloseSignal;
+
     LLHandle<LLUICtrl>  mHostHandle;
     LLHandle<LLFloater> mHelperHandle;
     boost::signals2::connection mHostCtrlFocusLostConn;
     boost::signals2::connection mHelperCommitConn;
+    boost::signals2::connection mHelperCloseConn;
     std::function<void(llwchar)> mEmojiCommitCb;
     bool mIsHideDisabled;
 };
diff --git a/indra/llui/lltexteditor.cpp b/indra/llui/lltexteditor.cpp
index ecac800def..088fbe2744 100644
--- a/indra/llui/lltexteditor.cpp
+++ b/indra/llui/lltexteditor.cpp
@@ -1211,6 +1211,14 @@ void LLTextEditor::showEmojiHelper()
     LLEmojiHelper::instance().showHelper(this, cursorRect.mLeft, cursorRect.mTop, LLStringUtil::null, cb);
 }
 
+void LLTextEditor::hideEmojiHelper()
+{
+    if (mShowEmojiHelper)
+    {
+        LLEmojiHelper::instance().hideHelper(this);
+    }
+}
+
 void LLTextEditor::tryToShowEmojiHelper()
 {
     if (mReadOnly || !mShowEmojiHelper)
diff --git a/indra/llui/lltexteditor.h b/indra/llui/lltexteditor.h
index cedb79bf62..32dd95b8ac 100644
--- a/indra/llui/lltexteditor.h
+++ b/indra/llui/lltexteditor.h
@@ -207,6 +207,7 @@ public:
     bool            getShowContextMenu() const { return mShowContextMenu; }
 
     void            showEmojiHelper();
+    void            hideEmojiHelper();
     void            setShowEmojiHelper(bool show);
     bool            getShowEmojiHelper() const { return mShowEmojiHelper; }
 
diff --git a/indra/newview/llfloaterimsessiontab.cpp b/indra/newview/llfloaterimsessiontab.cpp
index b2f2984c65..6a96dc0c69 100644
--- a/indra/newview/llfloaterimsessiontab.cpp
+++ b/indra/newview/llfloaterimsessiontab.cpp
@@ -39,6 +39,7 @@
 #include "llchicletbar.h"
 #include "lldraghandle.h"
 #include "llemojidictionary.h"
+#include "llemojihelper.h"
 #include "llfloaterreg.h"
 #include "llfloateremojipicker.h"
 #include "llfloaterimsession.h"
@@ -298,6 +299,8 @@ bool LLFloaterIMSessionTab::postBuild()
 
     mEmojiPickerShowBtn = getChild<LLButton>("emoji_picker_show_btn");
     mEmojiPickerShowBtn->setClickedCallback([this](LLUICtrl*, const LLSD&) { onEmojiPickerShowBtnClicked(); });
+    mEmojiPickerShowBtn->setMouseDownCallback([this](LLUICtrl*, const LLSD&) { onEmojiPickerShowBtnDown(); });
+    mEmojiCloseConn = LLEmojiHelper::instance().setCloseCallback([this](LLUICtrl*, const LLSD&) { onEmojiPickerClosed(); });
 
     mGearBtn = getChild<LLButton>("gear_btn");
     mAddBtn = getChild<LLButton>("add_btn");
@@ -526,8 +529,43 @@ void LLFloaterIMSessionTab::onEmojiRecentPanelToggleBtnClicked()
 
 void LLFloaterIMSessionTab::onEmojiPickerShowBtnClicked()
 {
-    mInputEditor->setFocus(true);
-    mInputEditor->showEmojiHelper();
+    if (!mEmojiPickerShowBtn->getToggleState())
+    {
+        mInputEditor->hideEmojiHelper();
+        mInputEditor->setFocus(true);
+        mInputEditor->showEmojiHelper();
+        mEmojiPickerShowBtn->setToggleState(true); // in case hideEmojiHelper closed a visible instance
+    }
+    else
+    {
+        mInputEditor->hideEmojiHelper();
+        mEmojiPickerShowBtn->setToggleState(false);
+    }
+}
+
+void LLFloaterIMSessionTab::onEmojiPickerShowBtnDown()
+{
+    if (mEmojiHelperLastCallbackFrame == LLFrameTimer::getFrameCount())
+    {
+        // Helper gets closed by focus lost event on Down before before onEmojiPickerShowBtnDown
+        // triggers.
+        // If this condition is true, user pressed button and it was 'toggled' during press,
+        // restore 'toggled' state so that button will not reopen helper.
+        mEmojiPickerShowBtn->setToggleState(true);
+    }
+}
+
+void LLFloaterIMSessionTab::onEmojiPickerClosed()
+{
+    if (mEmojiPickerShowBtn->getToggleState())
+    {
+        mEmojiPickerShowBtn->setToggleState(false);
+        // Helper gets closed by focus lost event on Down before onEmojiPickerShowBtnDown
+        // triggers. If mEmojiHelperLastCallbackFrame is set and matches Down, means close
+        // was triggered by user's press.
+        // A bit hacky, but I can't think of a better way to handle this without rewriting helper.
+        mEmojiHelperLastCallbackFrame = LLFrameTimer::getFrameCount();
+    }
 }
 
 void LLFloaterIMSessionTab::initEmojiRecentPanel()
diff --git a/indra/newview/llfloaterimsessiontab.h b/indra/newview/llfloaterimsessiontab.h
index bee5c8c2c4..890c920bbe 100644
--- a/indra/newview/llfloaterimsessiontab.h
+++ b/indra/newview/llfloaterimsessiontab.h
@@ -227,6 +227,8 @@ private:
 
     void onEmojiRecentPanelToggleBtnClicked();
     void onEmojiPickerShowBtnClicked();
+    void onEmojiPickerShowBtnDown();
+    void onEmojiPickerClosed();
     void initEmojiRecentPanel();
     void onEmojiRecentPanelFocusReceived();
     void onEmojiRecentPanelFocusLost();
@@ -241,6 +243,9 @@ private:
     S32 mInputEditorPad;
     S32 mChatLayoutPanelHeight;
     S32 mFloaterHeight;
+
+    boost::signals2::connection mEmojiCloseConn;
+    U32 mEmojiHelperLastCallbackFrame = { 0 };
 };
 
 
-- 
cgit v1.2.3