summaryrefslogtreecommitdiff
path: root/indra/newview
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
parentdc5ef88e314d201f8f15be33d3517f45c4af2878 (diff)
parent97b0ba2a6d2596da867043077e32065653d44f6e (diff)
Merge pull request #183 from secondlife/SL-19575a
SL-19575 LLFloaterEmojiPicker - Add filter by category
Diffstat (limited to 'indra/newview')
-rw-r--r--indra/newview/llfloateravatarpicker.cpp1
-rw-r--r--indra/newview/llfloateremojipicker.cpp203
-rw-r--r--indra/newview/llfloateremojipicker.h36
-rw-r--r--indra/newview/llfloaterimsessiontab.cpp13
-rw-r--r--indra/newview/llfloaterimsessiontab.h3
-rw-r--r--indra/newview/llviewerchat.cpp2
-rw-r--r--indra/newview/skins/default/xui/en/floater_emoji_picker.xml95
7 files changed, 280 insertions, 73 deletions
diff --git a/indra/newview/llfloateravatarpicker.cpp b/indra/newview/llfloateravatarpicker.cpp
index 2422596f60..42ef41017a 100644
--- a/indra/newview/llfloateravatarpicker.cpp
+++ b/indra/newview/llfloateravatarpicker.cpp
@@ -741,7 +741,6 @@ void LLFloaterAvatarPicker::processResponse(const LLUUID& query_id, const LLSD&
}
}
-//static
void LLFloaterAvatarPicker::editKeystroke(LLLineEditor* caller, void* user_data)
{
getChildView("Find")->setEnabled(caller->getText().size() > 0);
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();
+}
diff --git a/indra/newview/llfloateremojipicker.h b/indra/newview/llfloateremojipicker.h
index 9b442064d0..01335bbb5b 100644
--- a/indra/newview/llfloateremojipicker.h
+++ b/indra/newview/llfloateremojipicker.h
@@ -29,31 +29,53 @@
#include "llfloater.h"
+struct LLEmojiDescriptor;
+
class LLFloaterEmojiPicker : public LLFloater
{
public:
// The callback function will be called with an emoji char.
- typedef boost::function<void (llwchar)> select_callback_t;
+ typedef boost::function<void (llwchar)> pick_callback_t;
+ typedef boost::function<void ()> close_callback_t;
// Call this to select an emoji.
static LLFloaterEmojiPicker* getInstance();
- static LLFloaterEmojiPicker* showInstance(select_callback_t callback);
+ static LLFloaterEmojiPicker* showInstance(pick_callback_t pick_callback = nullptr, close_callback_t close_callback = nullptr);
LLFloaterEmojiPicker(const LLSD& key);
virtual ~LLFloaterEmojiPicker();
virtual BOOL postBuild();
- void show(select_callback_t callback);
+ void show(pick_callback_t pick_callback = nullptr, close_callback_t close_callback = nullptr);
+
+ virtual void closeFloater(bool app_quitting = false);
private:
- void onSelect();
+ void fillEmojis();
+ bool matchesCategory(const LLEmojiDescriptor* descr);
+ bool matchesPattern(const LLEmojiDescriptor* descr);
+
+ void onCategoryCommit();
+ void onSearchKeystroke(class LLLineEditor* caller, void* user_data);
+ void onPreviewEmojiClick();
+ void onEmojiSelect();
+ void onEmojiEmpty();
+ void onEmojiPick();
virtual BOOL handleKeyHere(KEY key, MASK mask);
- class LLScrollListCtrl* mEmojis;
- select_callback_t mSelectCallback;
- std::string mEmojiName;
+ class LLComboBox* mCategory { nullptr };
+ class LLLineEditor* mSearch { nullptr };
+ class LLScrollListCtrl* mEmojis { nullptr };
+ class LLButton* mPreviewEmoji { nullptr };
+
+ pick_callback_t mEmojiPickCallback;
+ close_callback_t mFloaterCloseCallback;
+
+ static std::string mSelectedCategory;
+ static std::string mSearchPattern;
+ static int mSelectedEmojiIndex;
};
#endif
diff --git a/indra/newview/llfloaterimsessiontab.cpp b/indra/newview/llfloaterimsessiontab.cpp
index 3d9751dd35..0571a0d855 100644
--- a/indra/newview/llfloaterimsessiontab.cpp
+++ b/indra/newview/llfloaterimsessiontab.cpp
@@ -434,10 +434,12 @@ void LLFloaterIMSessionTab::onEmojiPanelBtnClicked(LLFloaterIMSessionTab* self)
{
if (!picker->isShown())
{
- picker->show(boost::bind(&LLFloaterIMSessionTab::onEmojiSelected, self, _1));
+ picker->show(
+ boost::bind(&LLFloaterIMSessionTab::onEmojiPicked, self, _1),
+ boost::bind(&LLFloaterIMSessionTab::onEmojiPickerClosed, self));
if (LLFloater* root_floater = gFloaterView->getParentFloater(self))
{
- root_floater->addDependentFloater(picker);
+ root_floater->addDependentFloater(picker, TRUE, TRUE);
}
}
else
@@ -447,11 +449,16 @@ void LLFloaterIMSessionTab::onEmojiPanelBtnClicked(LLFloaterIMSessionTab* self)
}
}
-void LLFloaterIMSessionTab::onEmojiSelected(llwchar emoji)
+void LLFloaterIMSessionTab::onEmojiPicked(llwchar emoji)
{
mInputEditor->insertEmoji(emoji);
}
+void LLFloaterIMSessionTab::onEmojiPickerClosed()
+{
+ mInputEditor->setFocus(TRUE);
+}
+
std::string LLFloaterIMSessionTab::appendTime()
{
time_t utc_time;
diff --git a/indra/newview/llfloaterimsessiontab.h b/indra/newview/llfloaterimsessiontab.h
index cd5065420d..3dcb767aa6 100644
--- a/indra/newview/llfloaterimsessiontab.h
+++ b/indra/newview/llfloaterimsessiontab.h
@@ -208,7 +208,8 @@ private:
void onInputEditorClicked();
static void onEmojiPanelBtnClicked(LLFloaterIMSessionTab* self);
- void onEmojiSelected(llwchar emoji);
+ void onEmojiPicked(llwchar emoji);
+ void onEmojiPickerClosed();
bool checkIfTornOff();
bool mIsHostAttached;
diff --git a/indra/newview/llviewerchat.cpp b/indra/newview/llviewerchat.cpp
index 1c3c547bc1..0d2d62fd77 100644
--- a/indra/newview/llviewerchat.cpp
+++ b/indra/newview/llviewerchat.cpp
@@ -25,7 +25,7 @@
*/
#include "llviewerprecompiledheaders.h"
-#include "llviewerchat.h"
+#include "llviewerchat.h"
// newview includes
#include "llagent.h" // gAgent
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 a3e504cc31..831f7b6582 100644
--- a/indra/newview/skins/default/xui/en/floater_emoji_picker.xml
+++ b/indra/newview/skins/default/xui/en/floater_emoji_picker.xml
@@ -1,39 +1,64 @@
<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
<floater
- name="emojipicker"
- title="CHOOSE EMOJI"
- help_topic="emojipicker"
- positioning="cascading"
- legacy_header_height="10"
- can_resize="false"
- layout="topleft"
- height="419"
- width="200">
- <panel
- label="Emojis"
- name="EmojiPanel"
- help_topic="emojipicker"
+ name="emojipicker"
+ title="CHOOSE EMOJI"
+ help_topic="emojipicker"
+ positioning="cascading"
+ legacy_header_height="0"
+ can_resize="true"
+ layout="topleft"
+ height="400"
+ width="200">
+ <line_editor
+ name="Search"
+ layout="bottomleft"
+ follows="bottom|left|right"
+ text_tentative_color="TextFgTentativeColor"
+ max_length_bytes="63"
+ left_pad="5"
+ bottom="14"
+ left="34"
+ height="29"
+ width="162" />
+ <button
+ name="PreviewEmoji"
+ layout="bottomleft"
+ follows="bottom|left"
+ font="EmojiHuge"
+ use_font_color="true"
+ bottom="14"
+ left="0"
+ height="29"
+ width="29" />
+ <scroll_list
+ name="Emojis"
layout="topleft"
- top="4"
- left="2"
- height="410"
- width="196">
- <scroll_list
- draw_heading="true"
- heading_height="28"
- follows="all"
- layout="topleft"
- name="Emojis"
- sort_column="0"
- height="410">
- <columns
- label="Look"
- name="look"
- width="40" />
- <columns
- label="Name"
- name="name"
- width="150" />
- </scroll_list>
- </panel>
+ follows="all"
+ sort_column="0"
+ max_chars="63"
+ commit_on_selection_change="true"
+ draw_heading="true"
+ heading_height="25"
+ row_padding="0"
+ top="25"
+ height="330"
+ width="200">
+ <columns
+ label="Look"
+ name="look"
+ width="40" />
+ <columns
+ label="Name"
+ name="name" />
+ </scroll_list>
+ <combo_box
+ name="Category"
+ layout="topleft"
+ follows="top|left|right"
+ allow_text_entry="true"
+ left_pad="4"
+ top="0"
+ left="4"
+ height="27"
+ width="192" />
</floater>