diff options
Diffstat (limited to 'indra/newview')
-rw-r--r-- | indra/newview/llfloateravatarpicker.cpp | 1 | ||||
-rw-r--r-- | indra/newview/llfloateremojipicker.cpp | 203 | ||||
-rw-r--r-- | indra/newview/llfloateremojipicker.h | 36 | ||||
-rw-r--r-- | indra/newview/llfloaterimsessiontab.cpp | 13 | ||||
-rw-r--r-- | indra/newview/llfloaterimsessiontab.h | 3 | ||||
-rw-r--r-- | indra/newview/llviewerchat.cpp | 2 | ||||
-rw-r--r-- | indra/newview/skins/default/xui/en/floater_emoji_picker.xml | 95 |
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> |