summaryrefslogtreecommitdiff
path: root/indra/newview/llfloateremojipicker.cpp
diff options
context:
space:
mode:
authorCallum Linden <113564339+callumlinden@users.noreply.github.com>2023-04-20 07:19:26 -0700
committerGitHub <noreply@github.com>2023-04-20 07:19:26 -0700
commita7eef57c1f3f8cd0850bd33b99f150d0e20d3e88 (patch)
tree09aeef796ca232ad1856d918c14eba34b3b4165c /indra/newview/llfloateremojipicker.cpp
parentdc5ef88e314d201f8f15be33d3517f45c4af2878 (diff)
parent97b0ba2a6d2596da867043077e32065653d44f6e (diff)
Merge pull request #183 from secondlife/SL-19575a
SL-19575 LLFloaterEmojiPicker - Add filter by category
Diffstat (limited to 'indra/newview/llfloateremojipicker.cpp')
-rw-r--r--indra/newview/llfloateremojipicker.cpp203
1 files changed, 178 insertions, 25 deletions
diff --git a/indra/newview/llfloateremojipicker.cpp b/indra/newview/llfloateremojipicker.cpp
index a63a9fac4f..5efd2a24c0 100644
--- a/indra/newview/llfloateremojipicker.cpp
+++ b/indra/newview/llfloateremojipicker.cpp
@@ -27,10 +27,18 @@
#include "llfloateremojipicker.h"
+#include "llcombobox.h"
+#include "llemojidictionary.h"
#include "llfloaterreg.h"
+#include "lllineeditor.h"
#include "llscrolllistctrl.h"
#include "llscrolllistitem.h"
-#include "llemojidictionary.h"
+#include "lltextbox.h"
+#include "llviewerchat.h"
+
+std::string LLFloaterEmojiPicker::mSelectedCategory;
+std::string LLFloaterEmojiPicker::mSearchPattern;
+int LLFloaterEmojiPicker::mSelectedEmojiIndex;
class LLEmojiScrollListItem : public LLScrollListItem
{
@@ -69,17 +77,18 @@ LLFloaterEmojiPicker* LLFloaterEmojiPicker::getInstance()
return floater;
}
-LLFloaterEmojiPicker* LLFloaterEmojiPicker::showInstance(select_callback_t callback)
+LLFloaterEmojiPicker* LLFloaterEmojiPicker::showInstance(pick_callback_t pick_callback, close_callback_t close_callback)
{
LLFloaterEmojiPicker* floater = getInstance();
if (LLFloaterEmojiPicker* floater = getInstance())
- floater->show(callback);
+ floater->show(pick_callback, close_callback);
return floater;
}
-void LLFloaterEmojiPicker::show(select_callback_t callback)
+void LLFloaterEmojiPicker::show(pick_callback_t pick_callback, close_callback_t close_callback)
{
- mSelectCallback = callback;
+ mEmojiPickCallback = pick_callback;
+ mFloaterCloseCallback = close_callback;
openFloater(mKey);
setFocus(TRUE);
}
@@ -91,19 +100,41 @@ LLFloaterEmojiPicker::LLFloaterEmojiPicker(const LLSD& key)
BOOL LLFloaterEmojiPicker::postBuild()
{
- if ((mEmojis = getChild<LLScrollListCtrl>("Emojis")))
+ // Should be initialized first
+ if ((mPreviewEmoji = getChild<LLButton>("PreviewEmoji")))
{
- mEmojis->setDoubleClickCallback(boost::bind(&LLFloaterEmojiPicker::onSelect, this));
-
- mEmojis->clearRows();
+ mPreviewEmoji->setClickedCallback(boost::bind(&LLFloaterEmojiPicker::onPreviewEmojiClick, this));
+ }
- const std::map<llwchar, const LLEmojiDescriptor*>& emoji2Descr = LLEmojiDictionary::instance().getEmoji2Descr();
- for (const std::pair<const llwchar, const LLEmojiDescriptor*>& it : emoji2Descr)
+ if ((mCategory = getChild<LLComboBox>("Category")))
+ {
+ mCategory->setCommitCallback(boost::bind(&LLFloaterEmojiPicker::onCategoryCommit, this));
+ mCategory->setLabel(LLStringExplicit("Choose a category"));
+ const auto& cat2Descrs = LLEmojiDictionary::instance().getCategory2Descrs();
+ mCategory->clearRows();
+ for (const auto& item : cat2Descrs)
{
- LLScrollListItem::Params params;
- params.columns.add().column("name").value(it.second->Name);
- mEmojis->addRow(new LLEmojiScrollListItem(it.first, params), params);
+ std::string value = item.first;
+ std::string name = value;
+ LLStringUtil::capitalize(name);
+ mCategory->add(name, value);
}
+ mCategory->setSelectedByValue(mSelectedCategory, true);
+ }
+
+ if ((mSearch = getChild<LLLineEditor>("Search")))
+ {
+ mSearch->setKeystrokeCallback(boost::bind(&LLFloaterEmojiPicker::onSearchKeystroke, this, _1, _2), NULL);
+ mSearch->setLabel(LLStringExplicit("Type to search an emoji"));
+ mSearch->setFont(LLViewerChat::getChatFont());
+ mSearch->setText(mSearchPattern);
+ }
+
+ if ((mEmojis = getChild<LLScrollListCtrl>("Emojis")))
+ {
+ mEmojis->setCommitCallback(boost::bind(&LLFloaterEmojiPicker::onEmojiSelect, this));
+ mEmojis->setDoubleClickCallback(boost::bind(&LLFloaterEmojiPicker::onEmojiPick, this));
+ fillEmojis();
}
return TRUE;
@@ -114,30 +145,152 @@ LLFloaterEmojiPicker::~LLFloaterEmojiPicker()
gFocusMgr.releaseFocusIfNeeded( this );
}
-void LLFloaterEmojiPicker::onSelect()
+void LLFloaterEmojiPicker::fillEmojis()
+{
+ mEmojis->clearRows();
+
+ const auto& emoji2Descr = LLEmojiDictionary::instance().getEmoji2Descr();
+ for (const std::pair<const llwchar, const LLEmojiDescriptor*>& it : emoji2Descr)
+ {
+ const LLEmojiDescriptor* descr = it.second;
+
+ if (!mSelectedCategory.empty() && !matchesCategory(descr))
+ continue;
+
+ if (!mSearchPattern.empty() && !matchesPattern(descr))
+ continue;
+
+ LLScrollListItem::Params params;
+ params.columns.add().column("name").value(descr->Name);
+ mEmojis->addRow(new LLEmojiScrollListItem(it.first, params), params);
+ }
+
+ if (mEmojis->getItemCount())
+ {
+ if (mSelectedEmojiIndex > 0 && mSelectedEmojiIndex < mEmojis->getItemCount())
+ mEmojis->selectNthItem(mSelectedEmojiIndex);
+ else
+ mEmojis->selectFirstItem();
+
+ mEmojis->scrollToShowSelected();
+ }
+ else
+ {
+ onEmojiEmpty();
+ }
+}
+
+bool LLFloaterEmojiPicker::matchesCategory(const LLEmojiDescriptor* descr)
+{
+ return std::find(descr->Categories.begin(), descr->Categories.end(), mSelectedCategory) != descr->Categories.end();
+}
+
+bool LLFloaterEmojiPicker::matchesPattern(const LLEmojiDescriptor* descr)
+{
+ if (descr->Name.find(mSearchPattern) != std::string::npos)
+ return true;
+ for (auto shortCode : descr->ShortCodes)
+ if (shortCode.find(mSearchPattern) != std::string::npos)
+ return true;
+ for (auto category : descr->Categories)
+ if (category.find(mSearchPattern) != std::string::npos)
+ return true;
+ return false;
+}
+
+void LLFloaterEmojiPicker::onCategoryCommit()
+{
+ mSelectedCategory = mCategory->getSelectedValue().asString();
+ mSelectedEmojiIndex = 0;
+ fillEmojis();
+}
+
+void LLFloaterEmojiPicker::onSearchKeystroke(LLLineEditor* caller, void* user_data)
{
- if (mEmojis && mSelectCallback)
+ mSearchPattern = mSearch->getText();
+ mSelectedEmojiIndex = 0;
+ fillEmojis();
+}
+
+void LLFloaterEmojiPicker::onPreviewEmojiClick()
+{
+ if (mEmojis && mEmojiPickCallback)
{
if (LLEmojiScrollListItem* item = dynamic_cast<LLEmojiScrollListItem*>(mEmojis->getFirstSelected()))
{
- mSelectCallback(item->getEmoji());
+ mEmojiPickCallback(item->getEmoji());
}
}
}
-// virtual
-BOOL LLFloaterEmojiPicker::handleKeyHere(KEY key, MASK mask)
+void LLFloaterEmojiPicker::onEmojiSelect()
{
- if (key == KEY_RETURN && mask == MASK_NONE)
+ const LLEmojiScrollListItem* item = dynamic_cast<LLEmojiScrollListItem*>(mEmojis->getFirstSelected());
+ if (item)
{
- onSelect();
- return TRUE;
+ mSelectedEmojiIndex = mEmojis->getFirstSelectedIndex();
+ LLUIString text;
+ text.insert(0, LLWString(1, item->getEmoji()));
+ if (mPreviewEmoji)
+ mPreviewEmoji->setLabel(text);
+ return;
}
- else if (key == KEY_ESCAPE && mask == MASK_NONE)
+
+ onEmojiEmpty();
+}
+
+void LLFloaterEmojiPicker::onEmojiEmpty()
+{
+ mSelectedEmojiIndex = 0;
+ if (mPreviewEmoji)
+ mPreviewEmoji->setLabel(LLUIString());
+}
+
+void LLFloaterEmojiPicker::onEmojiPick()
+{
+ if (mEmojis && mEmojiPickCallback)
{
- closeFloater();
- return TRUE;
+ if (LLEmojiScrollListItem* item = dynamic_cast<LLEmojiScrollListItem*>(mEmojis->getFirstSelected()))
+ {
+ mEmojiPickCallback(item->getEmoji());
+ closeFloater();
+ }
+ }
+}
+
+// virtual
+BOOL LLFloaterEmojiPicker::handleKeyHere(KEY key, MASK mask)
+{
+ if (mask == MASK_NONE)
+ {
+ switch (key)
+ {
+ case KEY_RETURN:
+ if (mCategory->hasFocus())
+ break;
+ onEmojiPick();
+ return TRUE;
+ case KEY_ESCAPE:
+ closeFloater();
+ return TRUE;
+ case KEY_UP:
+ mEmojis->selectPrevItem();
+ mEmojis->scrollToShowSelected();
+ return TRUE;
+ case KEY_DOWN:
+ mEmojis->selectNextItem();
+ mEmojis->scrollToShowSelected();
+ return TRUE;
+ }
}
return LLFloater::handleKeyHere(key, mask);
}
+
+// virtual
+void LLFloaterEmojiPicker::closeFloater(bool app_quitting)
+{
+ LLFloater::closeFloater(app_quitting);
+ if (mFloaterCloseCallback)
+ mFloaterCloseCallback();
+}