From 1fe007abef6eeceefb0dc720b4a5ecb4505ede88 Mon Sep 17 00:00:00 2001
From: Alexander Gavriliuk <alexandrgproductengine@lindenlab.com>
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/newview/llfloateremojipicker.cpp             | 286 ++++++++++++---------
 indra/newview/llfloateremojipicker.h               |  11 +-
 indra/newview/llfloaterimnearbychat.cpp            |   5 +-
 .../skins/default/xui/en/floater_emoji_picker.xml  |  32 +--
 4 files changed, 176 insertions(+), 158 deletions(-)

(limited to 'indra/newview')

diff --git a/indra/newview/llfloateremojipicker.cpp b/indra/newview/llfloateremojipicker.cpp
index 08929b05f5..808aca4bf4 100644
--- a/indra/newview/llfloateremojipicker.cpp
+++ b/indra/newview/llfloateremojipicker.cpp
@@ -48,63 +48,18 @@ namespace {
 
 // Floater state related variables
 static U32 sSelectedGroupIndex = 0;
-static std::string sSearchPattern;
+static std::string sFilterPattern;
 static std::list<llwchar> sRecentlyUsed;
 static std::list<std::pair<llwchar, U32>> sFrequentlyUsed;
 
 // State file related values
 static std::string sStateFileName;
 static const std::string sKeySelectedGroupIndex("SelectedGroupIndex");
-static const std::string sKeySearchPattern("SearchPattern");
+static const std::string sKeyFilterPattern("FilterPattern");
 static const std::string sKeyRecentlyUsed("RecentlyUsed");
 static const std::string sKeyFrequentlyUsed("FrequentlyUsed");
 }
 
-class LLEmojiScrollListItem : public LLScrollListItem
-{
-public:
-    LLEmojiScrollListItem(const llwchar emoji, const LLScrollListItem::Params& params)
-        : LLScrollListItem(params)
-        , mEmoji(emoji)
-    {
-    }
-
-    llwchar getEmoji() const { return mEmoji; }
-
-    virtual void draw(const LLRect& rect,
-        const LLColor4& fg_color,
-        const LLColor4& hover_color, // highlight/hover selection of whole item or cell
-        const LLColor4& select_color, // highlight/hover selection of whole item or cell
-        const LLColor4& highlight_color, // highlights contents of cells (ex: text)
-        S32 column_padding) override
-    {
-        LLScrollListItem::draw(rect, fg_color, hover_color, select_color, highlight_color, column_padding);
-
-        LLWString wstr(1, mEmoji);
-        S32 width = getColumn(0)->getWidth();
-        F32 x = rect.mLeft + width / 2;
-        F32 y = rect.getCenterY();
-        LLFontGL::getFontEmoji()->render(
-            wstr,                       // wstr
-            0,                          // begin_offset
-            x,                          // x
-            y,                          // y
-            LLColor4::white,            // color
-            LLFontGL::HCENTER,          // halign
-            LLFontGL::VCENTER,          // valign
-            LLFontGL::NORMAL,           // style
-            LLFontGL::DROP_SHADOW_SOFT, // shadow
-            1,                          // max_chars
-            S32_MAX,                    // max_pixels
-            nullptr,                    // right_x
-            false,                      // use_ellipses
-            true);                      // use_color
-    }
-
-private:
-    llwchar mEmoji;
-};
-
 class LLEmojiGridRow : public LLScrollingPanel
 {
 public:
@@ -137,7 +92,7 @@ public:
 
         F32 x = 4; // padding-left
         F32 y = getRect().getHeight() / 2;
-        LLFontGL::getFontSansSerifBold()->render(
+        LLFontGL::getFontSansSerif()->render(
             mText,                      // wstr
             0,                          // begin_offset
             x,                          // x
@@ -168,10 +123,8 @@ public:
         , const LLEmojiDescriptor* descr
         , std::string category)
         : LLScrollingPanel(panel_params)
-        , mEmoji(descr->Character)
-        , mText(LLWString(1, mEmoji))
-        , mDescr(descr->getShortCodes())
-        , mCategory(category)
+        , mDescr(descr)
+        , mText(LLWString(1, descr->Character))
     {
     }
 
@@ -200,16 +153,106 @@ public:
 
     virtual void updatePanel(BOOL allow_modify) override {}
 
-    llwchar getEmoji() const { return mEmoji; }
+    const LLEmojiDescriptor* getDescr() const { return mDescr; }
+    llwchar getEmoji() const { return mDescr->Character; }
     LLWString getText() const { return mText; }
-    std::string getDescr() const { return mDescr; }
-    std::string getCategory() const { return mCategory; }
 
 private:
-    const llwchar mEmoji;
+    const LLEmojiDescriptor* mDescr;
     const LLWString mText;
-    const std::string mDescr;
-    const std::string mCategory;
+};
+
+class LLEmojiPreviewPanel : public LLPanel
+{
+public:
+    LLEmojiPreviewPanel()
+        : LLPanel()
+    {
+    }
+
+    void setEmoji(const LLEmojiDescriptor* descr)
+    {
+        mDescr = descr;
+
+        if (!mDescr)
+            return;
+
+        mEmojiText = LLWString(1, descr->Character);
+    }
+
+    virtual void draw() override
+    {
+        LLPanel::draw();
+
+        if (!mDescr)
+            return;
+
+        S32 clientHeight = getRect().getHeight();
+        S32 clientWidth = getRect().getWidth();
+        S32 iconWidth = clientHeight;
+
+        F32 centerX = 0.5f * iconWidth;
+        F32 centerY = 0.5f * clientHeight;
+        drawIcon(centerX, centerY, iconWidth);
+
+        static LLColor4 defaultColor(0.75f, 0.75f, 0.75f, 1.0f);
+        LLColor4 textColor = LLUIColorTable::instance().getColor("MenuItemEnabledColor", defaultColor);
+        S32 max_pixels = clientWidth - iconWidth;
+        size_t count = mDescr->ShortCodes.size();
+        if (count == 1)
+        {
+            drawName(mDescr->ShortCodes.front(), iconWidth, centerY, max_pixels, textColor);
+        }
+        else if (count > 1)
+        {
+            F32 quarterY = 0.5f * centerY;
+            drawName(mDescr->ShortCodes.front(), iconWidth, centerY + quarterY, max_pixels, textColor);
+            drawName(*++mDescr->ShortCodes.begin(), iconWidth, quarterY, max_pixels, textColor);
+        }
+    }
+
+protected:
+    void drawIcon(F32 x, F32 y, S32 max_pixels)
+    {
+        LLFontGL::getFontEmojiHuge()->render(
+            mEmojiText,                 // wstr
+            0,                          // begin_offset
+            x,                          // x
+            y,                          // y
+            LLColor4::white,            // color
+            LLFontGL::HCENTER,          // halign
+            LLFontGL::VCENTER,          // valign
+            LLFontGL::NORMAL,           // style
+            LLFontGL::DROP_SHADOW_SOFT, // shadow
+            1,                          // max_chars
+            max_pixels,                 // max_pixels
+            nullptr,                    // right_x
+            false,                      // use_ellipses
+            true);                      // use_color
+    }
+
+    void drawName(std::string name, F32 x, F32 y, S32 max_pixels, LLColor4& color)
+    {
+        LLFontGL::getFontEmoji()->renderUTF8(
+            name,                       // wstr
+            0,                          // begin_offset
+            x,                          // x
+            y,                          // y
+            color,                      // color
+            LLFontGL::LEFT,             // halign
+            LLFontGL::VCENTER,          // valign
+            LLFontGL::NORMAL,           // style
+            LLFontGL::DROP_SHADOW_SOFT, // shadow
+            -1,                         // max_chars
+            max_pixels,                 // max_pixels
+            nullptr,                    // right_x
+            true,                       // use_ellipses
+            false);                     // use_color
+    }
+
+private:
+    const LLEmojiDescriptor* mDescr { nullptr };
+    LLWString mEmojiText;
 };
 
 LLFloaterEmojiPicker* LLFloaterEmojiPicker::getInstance()
@@ -244,19 +287,17 @@ LLFloaterEmojiPicker::LLFloaterEmojiPicker(const LLSD& key)
 BOOL LLFloaterEmojiPicker::postBuild()
 {
     // Should be initialized first
-    mPreviewEmoji = getChild<LLButton>("PreviewEmoji");
-    mPreviewEmoji->setClickedCallback([this](LLUICtrl*, const LLSD&) { onPreviewEmojiClick(); });
-
-    mDescription = getChild<LLTextBox>("Description");
-    mDescription->setVisible(FALSE);
+    mPreview = new LLEmojiPreviewPanel();
+    mPreview->setVisible(FALSE);
+    addChild(mPreview);
 
     mGroups = getChild<LLPanel>("Groups");
     mBadge = getChild<LLPanel>("Badge");
 
-    mSearch = getChild<LLLineEditor>("Search");
-    mSearch->setKeystrokeCallback([this](LLLineEditor*, void*) { onSearchKeystroke(); }, NULL);
-    mSearch->setFont(LLViewerChat::getChatFont());
-    mSearch->setText(sSearchPattern);
+    mFilter = getChild<LLLineEditor>("Filter");
+    mFilter->setKeystrokeCallback([this](LLLineEditor*, void*) { onSearchKeystroke(); }, NULL);
+    mFilter->setFont(LLViewerChat::getChatFont());
+    mFilter->setText(sFilterPattern);
 
     mEmojiScroll = getChild<LLScrollContainer>("EmojiGridContainer");
     mEmojiScroll->setMouseEnterCallback([this](LLUICtrl*, const LLSD&) { onGridMouseEnter(); });
@@ -274,6 +315,16 @@ void LLFloaterEmojiPicker::dirtyRect()
 {
     super::dirtyRect();
 
+    if (!mFilter)
+        return;
+
+    const S32 PADDING = 4;
+    LLRect rect(PADDING, mFilter->getRect().mTop, getRect().getWidth() - PADDING * 2, PADDING);
+    if (mPreview->getRect() != rect)
+    {
+        mPreview->setRect(rect);
+    }
+
     if (mEmojiScroll && mEmojiScroll->getRect().getWidth() != mRecentGridWidth)
     {
         moveGroups();
@@ -374,7 +425,7 @@ void LLFloaterEmojiPicker::fillEmojis(bool fromResize)
 
     mHoveredIcon = nullptr;
     mEmojiGrid->clearPanels();
-    mPreviewEmoji->setLabel(LLUIString());
+    mPreview->setEmoji(nullptr);
 
     if (mEmojiGrid->getRect().getWidth() != clientWidth)
     {
@@ -395,18 +446,17 @@ void LLFloaterEmojiPicker::fillEmojis(bool fromResize)
     LLPanel::Params icon_params;
     LLRect icon_rect(0, iconSize, iconSize, 0);
 
-    static const LLColor4 bgcolors[] =
+    static LLColor4 defaultColor(0.75f, 0.75f, 0.75f, 1.0f);
+    LLColor4 bgColor = LLUIColorTable::instance().getColor("MenuItemHighlightBgColor", defaultColor);
+
+    auto matchesPattern = [](const LLEmojiDescriptor* descr) -> bool
     {
-        LLColor4(0.8f, 0.6f, 0.8f, 1.0f),
-        LLColor4(0.8f, 0.8f, 0.4f, 1.0f),
-        LLColor4(0.6f, 0.6f, 0.8f, 1.0f),
-        LLColor4(0.4f, 0.7f, 0.4f, 1.0f),
-        LLColor4(0.5f, 0.7f, 0.9f, 1.0f),
-        LLColor4(0.7f, 0.8f, 0.2f, 1.0f)
+        for (const std::string& shortCode : descr->ShortCodes)
+            if (shortCode.find(sFilterPattern) != std::string::npos)
+                return true;
+        return false;
     };
 
-    static constexpr U32 bgcolorCount = sizeof(bgcolors) / sizeof(*bgcolors);
-
     auto listCategory = [&](std::string category, const std::vector<const LLEmojiDescriptor*>& emojis, int maxRows = 0)
     {
         int rowCount = 0;
@@ -418,9 +468,10 @@ void LLFloaterEmojiPicker::fillEmojis(bool fromResize)
         {
             LLStringUtil::capitalize(category);
         }
+
         for (const LLEmojiDescriptor* descr : emojis)
         {
-            if (sSearchPattern.empty() || matchesPattern(descr))
+            if (sFilterPattern.empty() || matchesPattern(descr))
             {
                 // Place a category title if needed
                 if (showDivider)
@@ -443,8 +494,9 @@ void LLFloaterEmojiPicker::fillEmojis(bool fromResize)
                 LLEmojiGridIcon* icon = new LLEmojiGridIcon(icon_params, descr, mixedFolder ? LLStringUtil::capitalize(descr->Category) : category);
                 icon->setMouseEnterCallback([this](LLUICtrl* ctrl, const LLSD&) { onEmojiMouseEnter(ctrl); });
                 icon->setMouseLeaveCallback([this](LLUICtrl* ctrl, const LLSD&) { onEmojiMouseLeave(ctrl); });
-                icon->setMouseUpCallback([this](LLUICtrl* ctrl, S32, S32, MASK mask) { onEmojiMouseClick(ctrl, mask); });
-                icon->setBackgroundColor(bgcolors[iconIndex % bgcolorCount]);
+                icon->setMouseDownCallback([this](LLUICtrl* ctrl, S32, S32, MASK) { onEmojiMouseDown(ctrl); });
+                icon->setMouseUpCallback([this](LLUICtrl* ctrl, S32, S32, MASK) { onEmojiMouseUp(ctrl); });
+                icon->setBackgroundColor(bgColor);
                 icon->setBackgroundOpaque(1);
                 icon->setRect(icon_rect);
                 row->mList->addPanel(icon, true);
@@ -511,14 +563,6 @@ void LLFloaterEmojiPicker::fillEmojis(bool fromResize)
     }
 }
 
-bool LLFloaterEmojiPicker::matchesPattern(const LLEmojiDescriptor* descr)
-{
-    for (const std::string& shortCode : descr->ShortCodes)
-        if (shortCode.find(sSearchPattern) != std::string::npos)
-            return true;
-    return false;
-}
-
 void LLFloaterEmojiPicker::onGroupButtonClick(LLUICtrl* ctrl)
 {
     if (LLButton* button = dynamic_cast<LLButton*>(ctrl))
@@ -541,7 +585,7 @@ void LLFloaterEmojiPicker::onGroupButtonClick(LLUICtrl* ctrl)
         rect.mRight = button->getRect().mRight;
         mBadge->setRect(rect);
 
-        mSearch->setFocus(TRUE);
+        mFilter->setFocus(TRUE);
 
         fillEmojis();
     }
@@ -549,34 +593,22 @@ void LLFloaterEmojiPicker::onGroupButtonClick(LLUICtrl* ctrl)
 
 void LLFloaterEmojiPicker::onSearchKeystroke()
 {
-    sSearchPattern = mSearch->getText();
+    sFilterPattern = mFilter->getText();
     fillEmojis();
 }
 
-void LLFloaterEmojiPicker::onPreviewEmojiClick()
-{
-    if (mEmojiPickCallback)
-    {
-        if (LLEmojiGridIcon* icon = dynamic_cast<LLEmojiGridIcon*>(mHoveredIcon))
-        {
-            mEmojiPickCallback(icon->getEmoji());
-        }
-    }
-}
-
 void LLFloaterEmojiPicker::onGridMouseEnter()
 {
-    mSearch->setVisible(FALSE);
-    mDescription->setText(LLStringExplicit(""), LLStyle::Params());
-    mDescription->setVisible(TRUE);
+    mFilter->setVisible(FALSE);
+    mPreview->setEmoji(nullptr);
+    mPreview->setVisible(TRUE);
 }
 
 void LLFloaterEmojiPicker::onGridMouseLeave()
 {
-    mDescription->setVisible(FALSE);
-    mDescription->setText(LLStringExplicit(""), LLStyle::Params());
-    mSearch->setVisible(TRUE);
-    mSearch->setFocus(TRUE);
+    mPreview->setVisible(FALSE);
+    mFilter->setVisible(TRUE);
+    mFilter->setFocus(TRUE);
 }
 
 void LLFloaterEmojiPicker::onGroupButtonMouseEnter(LLUICtrl* ctrl)
@@ -621,18 +653,29 @@ void LLFloaterEmojiPicker::onEmojiMouseLeave(LLUICtrl* ctrl)
     }
 }
 
-void LLFloaterEmojiPicker::onEmojiMouseClick(LLUICtrl* ctrl, MASK mask)
+void LLFloaterEmojiPicker::onEmojiMouseDown(LLUICtrl* ctrl)
+{
+    if (getSoundFlags() & MOUSE_DOWN)
+    {
+        make_ui_sound("UISndClick");
+    }
+}
+
+void LLFloaterEmojiPicker::onEmojiMouseUp(LLUICtrl* ctrl)
 {
+    if (getSoundFlags() & MOUSE_UP)
+    {
+        make_ui_sound("UISndClickRelease");
+    }
+
     if (mEmojiPickCallback)
     {
         if (LLEmojiGridIcon* icon = dynamic_cast<LLEmojiGridIcon*>(ctrl))
         {
             onEmojiUsed(icon->getEmoji());
-            mPreviewEmoji->handleAnyMouseClick(0, 0, 0, EMouseClickType::CLICK_LEFT, TRUE);
-            mPreviewEmoji->handleAnyMouseClick(0, 0, 0, EMouseClickType::CLICK_LEFT, FALSE);
-            if (!(mask & 4))
+            if (mEmojiPickCallback)
             {
-                closeFloater();
+                mEmojiPickCallback(icon->getEmoji());
             }
         }
     }
@@ -643,13 +686,7 @@ void LLFloaterEmojiPicker::selectGridIcon(LLUICtrl* ctrl)
     if (LLEmojiGridIcon* icon = dynamic_cast<LLEmojiGridIcon*>(ctrl))
     {
         icon->setBackgroundVisible(TRUE);
-
-        LLUIString text;
-        text.insert(0, icon->getText());
-        mPreviewEmoji->setLabel(text);
-
-        std::string descr = icon->getDescr() + "\n" + icon->getCategory();
-        mDescription->setText(LLStringExplicit(descr), LLStyle::Params());
+        mPreview->setEmoji(icon->getDescr());
     }
 }
 
@@ -658,8 +695,7 @@ void LLFloaterEmojiPicker::unselectGridIcon(LLUICtrl* ctrl)
     if (LLEmojiGridIcon* icon = dynamic_cast<LLEmojiGridIcon*>(ctrl))
     {
         icon->setBackgroundVisible(FALSE);
-        mPreviewEmoji->setLabel(LLUIString());
-        mDescription->setText(LLStringExplicit(""), LLStyle::Params());
+        mPreview->setEmoji(nullptr);
     }
 }
 
@@ -754,7 +790,7 @@ void LLFloaterEmojiPicker::loadState()
 
     sSelectedGroupIndex = state[sKeySelectedGroupIndex].asInteger();
 
-    sSearchPattern = state[sKeySearchPattern].asString();
+    sFilterPattern = state[sKeyFilterPattern].asString();
 
     // Load and parse sRecentlyUsed
     std::string recentlyUsed = state[sKeyRecentlyUsed];
@@ -826,9 +862,9 @@ void LLFloaterEmojiPicker::saveState()
         state[sKeySelectedGroupIndex] = (int)sSelectedGroupIndex;
     }
 
-    if (!sSearchPattern.empty())
+    if (!sFilterPattern.empty())
     {
-        state[sKeySearchPattern] = sSearchPattern;
+        state[sKeyFilterPattern] = sFilterPattern;
     }
 
     if (!sRecentlyUsed.empty())
diff --git a/indra/newview/llfloateremojipicker.h b/indra/newview/llfloateremojipicker.h
index d00391c61f..e4b1216ce6 100644
--- a/indra/newview/llfloateremojipicker.h
+++ b/indra/newview/llfloateremojipicker.h
@@ -59,18 +59,16 @@ private:
     void moveGroups();
     void fillEmojis(bool fromResize = false);
 
-    bool matchesPattern(const LLEmojiDescriptor* descr);
-
     void onGroupButtonClick(LLUICtrl* ctrl);
     void onSearchKeystroke();
-    void onPreviewEmojiClick();
     void onGridMouseEnter();
     void onGridMouseLeave();
     void onGroupButtonMouseEnter(LLUICtrl* ctrl);
     void onGroupButtonMouseLeave(LLUICtrl* ctrl);
     void onEmojiMouseEnter(LLUICtrl* ctrl);
     void onEmojiMouseLeave(LLUICtrl* ctrl);
-    void onEmojiMouseClick(LLUICtrl* ctrl, MASK mask);
+    void onEmojiMouseDown(LLUICtrl* ctrl);
+    void onEmojiMouseUp(LLUICtrl* ctrl);
 
     void selectGridIcon(LLUICtrl* ctrl);
     void unselectGridIcon(LLUICtrl* ctrl);
@@ -83,11 +81,10 @@ private:
 
     class LLPanel* mGroups { nullptr };
     class LLPanel* mBadge { nullptr };
-    class LLLineEditor* mSearch { nullptr };
+    class LLLineEditor* mFilter { nullptr };
     class LLScrollContainer* mEmojiScroll { nullptr };
     class LLScrollingPanelList* mEmojiGrid { nullptr };
-    class LLButton* mPreviewEmoji { nullptr };
-    class LLTextBox* mDescription { nullptr };
+    class LLEmojiPreviewPanel* mPreview { nullptr };
 
     pick_callback_t mEmojiPickCallback;
     close_callback_t mFloaterCloseCallback;
diff --git a/indra/newview/llfloaterimnearbychat.cpp b/indra/newview/llfloaterimnearbychat.cpp
index f1807f1c5b..df780f152a 100644
--- a/indra/newview/llfloaterimnearbychat.cpp
+++ b/indra/newview/llfloaterimnearbychat.cpp
@@ -128,11 +128,12 @@ BOOL LLFloaterIMNearbyChat::postBuild()
 	mInputEditor->setKeystrokeCallback(boost::bind(&LLFloaterIMNearbyChat::onChatBoxKeystroke, this));
 	mInputEditor->setFocusLostCallback(boost::bind(&LLFloaterIMNearbyChat::onChatBoxFocusLost, this));
 	mInputEditor->setFocusReceivedCallback(boost::bind(&LLFloaterIMNearbyChat::onChatBoxFocusReceived, this));
-	mInputEditor->setLabel(LLTrans::getString("NearbyChatTitle"));
+	std::string nearbyChatTitle(LLTrans::getString("NearbyChatTitle"));
+	mInputEditor->setLabel(nearbyChatTitle);
 
 	// Title must be defined BEFORE call to addConversationListItem() because
 	// it is used to show the item's name in the conversations list
-	setTitle(LLTrans::getString("NearbyChatTitle"));
+	setTitle(nearbyChatTitle);
 
 	// obsolete, but may be needed for backward compatibility?
 	gSavedSettings.declareS32("nearbychat_showicons_and_names", 2, "NearByChat header settings", LLControlVariable::PERSIST_NONDFT);
diff --git a/indra/newview/skins/default/xui/en/floater_emoji_picker.xml b/indra/newview/skins/default/xui/en/floater_emoji_picker.xml
index 4b4bf0c5a3..a2a290c306 100644
--- a/indra/newview/skins/default/xui/en/floater_emoji_picker.xml
+++ b/indra/newview/skins/default/xui/en/floater_emoji_picker.xml
@@ -13,42 +13,26 @@
   <floater.string name="title_for_recently_used" value="Recently used"/>
   <floater.string name="title_for_frequently_used" value="Frequently used"/>
   <line_editor
-      name="Search"
-      label="Type to search"
+      name="Filter"
+      label="Start typing to filter"
       layout="bottomleft"
       follows="bottom|left|right"
       text_tentative_color="TextFgTentativeColor"
+      show_label_focused="true"
       max_length_bytes="63"
+      text_pad_right="5"
+      text_pad_left="5"
       bottom="14"
-      left="34"
+      left="10"
       height="29"
-      width="212" />
-  <text
-      name="Description"
-      layout="bottomleft"
-      follows="bottom|left|right"
-      font="SansSerifMedium"
-      bottom="14"
-      left="42"
-      height="29"
-      width="200" />
-  <button
-      name="PreviewEmoji"
-      layout="bottomleft"
-      follows="bottom|left"
-      font="EmojiHuge"
-      use_font_color="true"
-      bottom="14"
-      left="2"
-      height="29"
-      width="29" />
+      width="230" />
   <scroll_container
       name="EmojiGridContainer"
       layout="topleft"
       follows="all"
       top="25"
       left="0"
-      height="330"
+      height="325"
       width="250">
     <scrolling_panel_list
         name="EmojiGrid"
-- 
cgit v1.2.3