summaryrefslogtreecommitdiff
path: root/indra/newview
diff options
context:
space:
mode:
authorAlexander Gavriliuk <alexandrgproductengine@lindenlab.com>2023-07-06 23:48:06 +0200
committerGuru <alexandrgproductengine@lindenlab.com>2023-07-07 00:22:34 +0200
commit9793308a600c1e1ce35ec727ed6341e7668848ea (patch)
tree17d47429881ed210f341695fb83475a488782170 /indra/newview
parent4abecaa04bd003136ed027e3892a2ca13d895936 (diff)
SL-19951 Organize emoji categories in groups
Diffstat (limited to 'indra/newview')
-rw-r--r--indra/newview/app_settings/emoji_groups.xml82
-rw-r--r--indra/newview/llfloateremojipicker.cpp849
-rw-r--r--indra/newview/llfloateremojipicker.h102
-rw-r--r--indra/newview/skins/default/xui/da/emoji_categories.xml59
-rw-r--r--indra/newview/skins/default/xui/de/emoji_categories.xml59
-rw-r--r--indra/newview/skins/default/xui/en/emoji_categories.xml59
-rw-r--r--indra/newview/skins/default/xui/en/floater_emoji_picker.xml33
-rw-r--r--indra/newview/skins/default/xui/es/emoji_categories.xml59
-rw-r--r--indra/newview/skins/default/xui/fr/emoji_categories.xml59
-rw-r--r--indra/newview/skins/default/xui/it/emoji_categories.xml59
-rw-r--r--indra/newview/skins/default/xui/ja/emoji_categories.xml59
-rw-r--r--indra/newview/skins/default/xui/pl/emoji_categories.xml59
-rw-r--r--indra/newview/skins/default/xui/pt/emoji_categories.xml59
-rw-r--r--indra/newview/skins/default/xui/ru/emoji_categories.xml59
-rw-r--r--indra/newview/skins/default/xui/zh/emoji_categories.xml59
15 files changed, 1284 insertions, 431 deletions
diff --git a/indra/newview/app_settings/emoji_groups.xml b/indra/newview/app_settings/emoji_groups.xml
new file mode 100644
index 0000000000..b433927f91
--- /dev/null
+++ b/indra/newview/app_settings/emoji_groups.xml
@@ -0,0 +1,82 @@
+<?xml version="1.0" ?>
+<llsd xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="llsd.xsd">
+ <array>
+ <map>
+ <key>Name</key>
+ <string>all</string>
+ <key>Character</key>
+ <string>🔍</string>
+ </map>
+ <map>
+ <key>Character</key>
+ <string>😀</string>
+ <key>Categories</key>
+ <array>
+ <string>smileys and emotion</string>
+ <string>people and body</string>
+ </array>
+ </map>
+ <map>
+ <key>Character</key>
+ <string>🥬</string>
+ <key>Categories</key>
+ <array>
+ <string>animals and nature</string>
+ </array>
+ </map>
+ <map>
+ <key>Character</key>
+ <string>🍔</string>
+ <key>Categories</key>
+ <array>
+ <string>food and drink</string>
+ </array>
+ </map>
+ <map>
+ <key>Character</key>
+ <string>🛩</string>
+ <key>Categories</key>
+ <array>
+ <string>travel and places</string>
+ </array>
+ </map>
+ <map>
+ <key>Character</key>
+ <string>🏈</string>
+ <key>Categories</key>
+ <array>
+ <string>activities</string>
+ </array>
+ </map>
+ <map>
+ <key>Character</key>
+ <string>💡</string>
+ <key>Categories</key>
+ <array>
+ <string>objects</string>
+ </array>
+ </map>
+ <map>
+ <key>Character</key>
+ <string>⚠</string>
+ <key>Categories</key>
+ <array>
+ <string>symbols</string>
+ </array>
+ </map>
+ <map>
+ <key>Name</key>
+ <string>others</string>
+ <key>Character</key>
+ <string>🌂</string>
+ </map>
+ <map>
+ <key>Name</key>
+ <string>skip</string>
+ <key>Categories</key>
+ <array>
+ <string>components</string>
+ </array>
+ </map>
+ </array>
+</llsd>
diff --git a/indra/newview/llfloateremojipicker.cpp b/indra/newview/llfloateremojipicker.cpp
index f63062f03a..9194a49c45 100644
--- a/indra/newview/llfloateremojipicker.cpp
+++ b/indra/newview/llfloateremojipicker.cpp
@@ -27,6 +27,7 @@
#include "llfloateremojipicker.h"
+#include "llbutton.h"
#include "llcombobox.h"
#include "llemojidictionary.h"
#include "llfloaterreg.h"
@@ -39,179 +40,179 @@
#include "lltextbox.h"
#include "llviewerchat.h"
-std::string LLFloaterEmojiPicker::mSelectedCategory;
-std::string LLFloaterEmojiPicker::mSearchPattern;
+size_t LLFloaterEmojiPicker::sSelectedGroupIndex;
+std::string LLFloaterEmojiPicker::sSearchPattern;
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
- }
+ 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;
+ llwchar mEmoji;
};
class LLEmojiGridRow : public LLScrollingPanel
{
public:
- LLEmojiGridRow(const LLPanel::Params& panel_params,
- const LLScrollingPanelList::Params& list_params)
- : LLScrollingPanel(panel_params)
- , mList(new LLScrollingPanelList(list_params))
- {
- addChild(mList);
- }
+ LLEmojiGridRow(const LLPanel::Params& panel_params,
+ const LLScrollingPanelList::Params& list_params)
+ : LLScrollingPanel(panel_params)
+ , mList(new LLScrollingPanelList(list_params))
+ {
+ addChild(mList);
+ }
- virtual void updatePanel(BOOL allow_modify) override {}
+ virtual void updatePanel(BOOL allow_modify) override {}
public:
- LLScrollingPanelList* mList;
+ LLScrollingPanelList* mList;
};
class LLEmojiGridDivider : public LLScrollingPanel
{
public:
- LLEmojiGridDivider(const LLPanel::Params& panel_params, std::string text)
- : LLScrollingPanel(panel_params)
- , mText(utf8string_to_wstring(text))
- {
- }
-
- virtual void draw() override
- {
- LLScrollingPanel::draw();
-
- F32 x = 4; // padding-left
- F32 y = getRect().getHeight() / 2;
- LLFontGL::getFontSansSerifBold()->render(
- mText, // wstr
- 0, // begin_offset
- x, // x
- y, // y
- LLColor4::white, // color
- LLFontGL::LEFT, // halign
- LLFontGL::VCENTER, // valign
- LLFontGL::NORMAL, // style
- LLFontGL::DROP_SHADOW_SOFT, // shadow
- mText.size(), // max_chars
- S32_MAX, // max_pixels
- nullptr, // right_x
- false, // use_ellipses
- true); // use_color
- }
-
- virtual void updatePanel(BOOL allow_modify) override {}
+ LLEmojiGridDivider(const LLPanel::Params& panel_params, std::string text)
+ : LLScrollingPanel(panel_params)
+ , mText(utf8string_to_wstring(text))
+ {
+ }
+
+ virtual void draw() override
+ {
+ LLScrollingPanel::draw();
+
+ F32 x = 4; // padding-left
+ F32 y = getRect().getHeight() / 2;
+ LLFontGL::getFontSansSerifBold()->render(
+ mText, // wstr
+ 0, // begin_offset
+ x, // x
+ y, // y
+ LLColor4::white, // color
+ LLFontGL::LEFT, // halign
+ LLFontGL::VCENTER, // valign
+ LLFontGL::NORMAL, // style
+ LLFontGL::DROP_SHADOW_SOFT, // shadow
+ mText.size(), // max_chars
+ S32_MAX, // max_pixels
+ nullptr, // right_x
+ false, // use_ellipses
+ true); // use_color
+ }
+
+ virtual void updatePanel(BOOL allow_modify) override {}
private:
- const LLWString mText;
+ const LLWString mText;
};
class LLEmojiGridIcon : public LLScrollingPanel
{
public:
- LLEmojiGridIcon(const LLPanel::Params& panel_params, const LLEmojiDescriptor* descr, std::string category)
- : LLScrollingPanel(panel_params)
- , mEmoji(descr->Character)
- , mText(LLWString(1, mEmoji))
- , mDescr(descr->Name)
- , mCategory(category)
- {
- }
-
- virtual void draw() override
- {
- LLScrollingPanel::draw();
-
- F32 x = getRect().getWidth() / 2;
- F32 y = getRect().getHeight() / 2;
- LLFontGL::getFontEmoji()->render(
- mText, // 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
- }
-
- virtual void updatePanel(BOOL allow_modify) override {}
-
- llwchar getEmoji() const { return mEmoji; }
- LLWString getText() const { return mText; }
- std::string getDescr() const { return mDescr; }
- std::string getCategory() const { return mCategory; }
+ LLEmojiGridIcon(const LLPanel::Params& panel_params, const LLEmojiDescriptor* descr, std::string category)
+ : LLScrollingPanel(panel_params)
+ , mEmoji(descr->Character)
+ , mText(LLWString(1, mEmoji))
+ , mDescr(descr->getShortCodes())
+ , mCategory(category)
+ {
+ }
+
+ virtual void draw() override
+ {
+ LLScrollingPanel::draw();
+
+ F32 x = getRect().getWidth() / 2;
+ F32 y = getRect().getHeight() / 2;
+ LLFontGL::getFontEmoji()->render(
+ mText, // 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
+ }
+
+ virtual void updatePanel(BOOL allow_modify) override {}
+
+ llwchar getEmoji() const { return mEmoji; }
+ LLWString getText() const { return mText; }
+ std::string getDescr() const { return mDescr; }
+ std::string getCategory() const { return mCategory; }
private:
- const llwchar mEmoji;
- const LLWString mText;
- const std::string mDescr;
- const std::string mCategory;
+ const llwchar mEmoji;
+ const LLWString mText;
+ const std::string mDescr;
+ const std::string mCategory;
};
LLFloaterEmojiPicker* LLFloaterEmojiPicker::getInstance()
{
- LLFloaterEmojiPicker* floater = LLFloaterReg::getTypedInstance<LLFloaterEmojiPicker>("emoji_picker");
- if (!floater)
- LL_ERRS() << "Cannot instantiate emoji picker" << LL_ENDL;
- return floater;
+ LLFloaterEmojiPicker* floater = LLFloaterReg::getTypedInstance<LLFloaterEmojiPicker>("emoji_picker");
+ if (!floater)
+ LL_ERRS() << "Cannot instantiate emoji picker" << LL_ENDL;
+ return floater;
}
LLFloaterEmojiPicker* LLFloaterEmojiPicker::showInstance(pick_callback_t pick_callback, close_callback_t close_callback)
{
- LLFloaterEmojiPicker* floater = getInstance();
- floater->show(pick_callback, close_callback);
- return floater;
+ LLFloaterEmojiPicker* floater = getInstance();
+ floater->show(pick_callback, close_callback);
+ return floater;
}
void LLFloaterEmojiPicker::show(pick_callback_t pick_callback, close_callback_t close_callback)
{
- mEmojiPickCallback = pick_callback;
- mFloaterCloseCallback = close_callback;
- openFloater(mKey);
- setFocus(TRUE);
+ mEmojiPickCallback = pick_callback;
+ mFloaterCloseCallback = close_callback;
+ openFloater(mKey);
+ setFocus(TRUE);
}
LLFloaterEmojiPicker::LLFloaterEmojiPicker(const LLSD& key)
@@ -221,313 +222,415 @@ 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);
-
- mCategory = getChild<LLComboBox>("Category");
- mCategory->setCommitCallback([this](LLUICtrl*, const LLSD&) { onCategoryCommit(); });
- const LLEmojiDictionary::cat2descrs_map_t& cat2Descrs = LLEmojiDictionary::instance().getCategory2Descrs();
- mCategory->clearRows();
- for (const LLEmojiDictionary::cat2descrs_item_t& item : cat2Descrs)
- {
- std::string value = item.first;
- std::string name = value;
- LLStringUtil::capitalize(name);
- mCategory->add(name, value);
- }
- mCategory->setSelectedByValue(mSelectedCategory, true);
-
- mSearch = getChild<LLLineEditor>("Search");
- mSearch->setKeystrokeCallback([this](LLLineEditor*, void*) { onSearchKeystroke(); }, NULL);
- mSearch->setFont(LLViewerChat::getChatFont());
- mSearch->setText(mSearchPattern);
-
- mEmojiScroll = getChild<LLScrollContainer>("EmojiGridContainer");
- mEmojiScroll->setMouseEnterCallback([this](LLUICtrl*, const LLSD&) { onGridMouseEnter(); });
- mEmojiScroll->setMouseLeaveCallback([this](LLUICtrl*, const LLSD&) { onGridMouseLeave(); });
-
- mEmojiGrid = getChild<LLScrollingPanelList>("EmojiGrid");
-
- fillEmojiGrid();
-
- return TRUE;
+ // Should be initialized first
+ mPreviewEmoji = getChild<LLButton>("PreviewEmoji");
+ mPreviewEmoji->setClickedCallback([this](LLUICtrl*, const LLSD&) { onPreviewEmojiClick(); });
+
+ mDescription = getChild<LLTextBox>("Description");
+ mDescription->setVisible(FALSE);
+
+ 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);
+
+ mEmojiScroll = getChild<LLScrollContainer>("EmojiGridContainer");
+ mEmojiScroll->setMouseEnterCallback([this](LLUICtrl*, const LLSD&) { onGridMouseEnter(); });
+ mEmojiScroll->setMouseLeaveCallback([this](LLUICtrl*, const LLSD&) { onGridMouseLeave(); });
+
+ mEmojiGrid = getChild<LLScrollingPanelList>("EmojiGrid");
+
+ fillGroups();
+ fillEmojis();
+
+ return TRUE;
}
void LLFloaterEmojiPicker::dirtyRect()
{
- super::dirtyRect();
+ super::dirtyRect();
- if (mEmojiScroll && mEmojiScroll->getRect().getWidth() != mRecentGridWidth)
- {
- fillEmojiGrid();
- }
+ if (mEmojiScroll && mEmojiScroll->getRect().getWidth() != mRecentGridWidth)
+ {
+ moveGroups();
+ fillEmojis(true);
+ }
}
LLFloaterEmojiPicker::~LLFloaterEmojiPicker()
{
- gFocusMgr.releaseFocusIfNeeded( this );
+ gFocusMgr.releaseFocusIfNeeded( this );
+}
+
+void LLFloaterEmojiPicker::fillGroups()
+{
+ LLButton::Params params;
+ params.font = LLFontGL::getFontEmoji();
+ //params.use_font_color = true;
+
+ LLRect rect;
+ rect.mTop = mGroups->getRect().getHeight();
+ rect.mBottom = mBadge->getRect().getHeight();
+
+ const std::vector<LLEmojiGroup>& groups = LLEmojiDictionary::instance().getGroups();
+ for (const LLEmojiGroup& group : groups)
+ {
+ LLButton* button = LLUICtrlFactory::create<LLButton>(params);
+ button->setClickedCallback([this](LLUICtrl* ctrl, const LLSD&) { onGroupButtonClick(ctrl); });
+ button->setMouseEnterCallback([this](LLUICtrl* ctrl, const LLSD&) { onGroupButtonMouseEnter(ctrl); });
+ button->setMouseLeaveCallback([this](LLUICtrl* ctrl, const LLSD&) { onGroupButtonMouseLeave(ctrl); });
+
+ button->setRect(rect);
+
+ LLUIString text;
+ text.insert(0, LLWString(1, group.Character));
+ button->setLabel(text);
+
+ if (mGroupButtons.size() == sSelectedGroupIndex)
+ {
+ button->setToggleState(TRUE);
+ }
+
+ mGroupButtons.push_back(button);
+ mGroups->addChild(button);
+ }
+
+ moveGroups();
+}
+
+void LLFloaterEmojiPicker::moveGroups()
+{
+ const std::vector<LLEmojiGroup>& groups = LLEmojiDictionary::instance().getGroups();
+ if (groups.empty())
+ return;
+
+ int badgeWidth = mGroups->getRect().getWidth() / groups.size();
+ if (badgeWidth == mRecentBadgeWidth)
+ return;
+
+ mRecentBadgeWidth = badgeWidth;
+
+ for (int i = 0; i < mGroupButtons.size(); ++i)
+ {
+ LLRect rect = mGroupButtons[i]->getRect();
+ rect.mLeft = badgeWidth * i;
+ rect.mRight = rect.mLeft + badgeWidth;
+ mGroupButtons[i]->setRect(rect);
+ }
+
+ LLRect rect = mBadge->getRect();
+ rect.mLeft = badgeWidth * sSelectedGroupIndex;
+ rect.mRight = rect.mLeft + badgeWidth;
+ mBadge->setRect(rect);
}
-void LLFloaterEmojiPicker::fillEmojiGrid()
+void LLFloaterEmojiPicker::fillEmojis(bool fromResize)
{
- mRecentGridWidth = mEmojiScroll->getRect().getWidth();
-
- S32 scrollbarSize = mEmojiScroll->getSize();
- if (scrollbarSize < 0)
- {
- static LLUICachedControl<S32> scrollbar_size_control("UIScrollbarSize", 0);
- scrollbarSize = scrollbar_size_control;
- }
-
- const S32 clientWidth = mRecentGridWidth - scrollbarSize - mEmojiScroll->getBorderWidth() * 2;
- const S32 gridPadding = mEmojiGrid->getPadding();
- const S32 iconSpacing = mEmojiGrid->getSpacing();
- const S32 rowWidth = clientWidth - gridPadding * 2;
- const S32 iconSize = 28; // icon width and height
- const S32 maxIcons = llmax(1, (rowWidth + iconSpacing) / (iconSize + iconSpacing));
-
- // Optimization: don't rearrange for different widths with the same maxIcons
- if (maxIcons == mRecentMaxIcons)
- return;
- mRecentMaxIcons = maxIcons;
-
- mHoveredIcon = nullptr;
- mEmojiGrid->clearPanels();
- mPreviewEmoji->setLabel(LLUIString());
-
- if (mEmojiGrid->getRect().getWidth() != clientWidth)
- {
- LLRect rect = mEmojiGrid->getRect();
- rect.mRight = rect.mLeft + clientWidth;
- mEmojiGrid->setRect(rect);
- }
-
- LLPanel::Params row_panel_params;
- row_panel_params.rect = LLRect(0, iconSize, rowWidth, 0);
-
- LLScrollingPanelList::Params row_list_params;
- row_list_params.rect = row_panel_params.rect;
- row_list_params.is_horizontal = TRUE;
- row_list_params.padding = 0;
- row_list_params.spacing = iconSpacing;
-
- LLPanel::Params icon_params;
- LLRect icon_rect(0, iconSize, iconSize, 0);
-
- static const LLColor4 bgcolors[] =
- {
- 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)
- };
-
- static constexpr U32 bgcolorCount = sizeof(bgcolors) / sizeof(*bgcolors);
-
- auto listCategory = [&](std::string category, const std::vector<const LLEmojiDescriptor*>& emojis, bool showDivider)
- {
- int iconIndex = 0;
- LLEmojiGridRow* row = nullptr;
- LLStringUtil::capitalize(category);
- for (const LLEmojiDescriptor* descr : emojis)
- {
- if (mSearchPattern.empty() || matchesPattern(descr))
- {
- // Place a category title if needed
- if (showDivider)
- {
- LLEmojiGridDivider* div = new LLEmojiGridDivider(row_panel_params, category);
- mEmojiGrid->addPanel(div, true);
- showDivider = false;
- }
-
- // Place a new row each (maxIcons) icons
- if (!(iconIndex % maxIcons))
- {
- row = new LLEmojiGridRow(row_panel_params, row_list_params);
- mEmojiGrid->addPanel(row, true);
- }
-
- // Place a new icon to the current row
- LLEmojiGridIcon* icon = new LLEmojiGridIcon(icon_params, descr, 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->setBackgroundOpaque(1);
- icon->setRect(icon_rect);
- row->mList->addPanel(icon, true);
-
- iconIndex++;
- }
- }
- };
-
- const LLEmojiDictionary::cat2descrs_map_t& category2Descr = LLEmojiDictionary::instance().getCategory2Descrs();
- if (mSelectedCategory.empty())
- {
- // List all categories with titles
- for (const LLEmojiDictionary::cat2descrs_item_t& item : category2Descr)
- {
- listCategory(item.first, item.second, TRUE);
- }
- }
- else
- {
- // List one category without title
- const LLEmojiDictionary::cat2descrs_map_t::const_iterator& item = category2Descr.find(mSelectedCategory);
- if (item != category2Descr.end())
- {
- listCategory(mSelectedCategory, item->second, FALSE);
- }
- }
+ mRecentGridWidth = mEmojiScroll->getRect().getWidth();
+
+ S32 scrollbarSize = mEmojiScroll->getSize();
+ if (scrollbarSize < 0)
+ {
+ static LLUICachedControl<S32> scrollbar_size_control("UIScrollbarSize", 0);
+ scrollbarSize = scrollbar_size_control;
+ }
+
+ const S32 clientWidth = mRecentGridWidth - scrollbarSize - mEmojiScroll->getBorderWidth() * 2;
+ const S32 gridPadding = mEmojiGrid->getPadding();
+ const S32 iconSpacing = mEmojiGrid->getSpacing();
+ const S32 rowWidth = clientWidth - gridPadding * 2;
+ const S32 iconSize = 28; // icon width and height
+ const S32 maxIcons = llmax(1, (rowWidth + iconSpacing) / (iconSize + iconSpacing));
+
+ // Optimization: don't rearrange for different widths with the same maxIcons
+ if (fromResize && (maxIcons == mRecentMaxIcons))
+ return;
+
+ mRecentMaxIcons = maxIcons;
+
+ mHoveredIcon = nullptr;
+ mEmojiGrid->clearPanels();
+ mPreviewEmoji->setLabel(LLUIString());
+
+ if (mEmojiGrid->getRect().getWidth() != clientWidth)
+ {
+ LLRect rect = mEmojiGrid->getRect();
+ rect.mRight = rect.mLeft + clientWidth;
+ mEmojiGrid->setRect(rect);
+ }
+
+ LLPanel::Params row_panel_params;
+ row_panel_params.rect = LLRect(0, iconSize, rowWidth, 0);
+
+ LLScrollingPanelList::Params row_list_params;
+ row_list_params.rect = row_panel_params.rect;
+ row_list_params.is_horizontal = TRUE;
+ row_list_params.padding = 0;
+ row_list_params.spacing = iconSpacing;
+
+ LLPanel::Params icon_params;
+ LLRect icon_rect(0, iconSize, iconSize, 0);
+
+ static const LLColor4 bgcolors[] =
+ {
+ 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)
+ };
+
+ static constexpr U32 bgcolorCount = sizeof(bgcolors) / sizeof(*bgcolors);
+
+ auto listCategory = [&](std::string category, const std::vector<const LLEmojiDescriptor*>& emojis)
+ {
+ int iconIndex = 0;
+ bool showDivider = true;
+ LLEmojiGridRow* row = nullptr;
+ LLStringUtil::capitalize(category);
+ for (const LLEmojiDescriptor* descr : emojis)
+ {
+ if (sSearchPattern.empty() || matchesPattern(descr))
+ {
+ // Place a category title if needed
+ if (showDivider)
+ {
+ LLEmojiGridDivider* div = new LLEmojiGridDivider(row_panel_params, category);
+ mEmojiGrid->addPanel(div, true);
+ showDivider = false;
+ }
+
+ // Place a new row each (maxIcons) icons
+ if (!(iconIndex % maxIcons))
+ {
+ row = new LLEmojiGridRow(row_panel_params, row_list_params);
+ mEmojiGrid->addPanel(row, true);
+ }
+
+ // Place a new icon to the current row
+ LLEmojiGridIcon* icon = new LLEmojiGridIcon(icon_params, descr, 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->setBackgroundOpaque(1);
+ icon->setRect(icon_rect);
+ row->mList->addPanel(icon, true);
+
+ iconIndex++;
+ }
+ }
+ };
+
+ const std::vector<LLEmojiGroup>& groups = LLEmojiDictionary::instance().getGroups();
+ const LLEmojiDictionary::cat2descrs_map_t& category2Descr = LLEmojiDictionary::instance().getCategory2Descrs();
+ if (!sSelectedGroupIndex)
+ {
+ // List all groups
+ for (const LLEmojiGroup& group : groups)
+ {
+ // List all categories in group
+ for (const std::string& category : group.Categories)
+ {
+ // List all emojis in category
+ const LLEmojiDictionary::cat2descrs_map_t::const_iterator& item = category2Descr.find(category);
+ if (item != category2Descr.end())
+ {
+ listCategory(category, item->second);
+ }
+ }
+ }
+ }
+ else
+ {
+ // List all categories in the selected group
+ for (const std::string& category : groups[sSelectedGroupIndex].Categories)
+ {
+ // List all emojis in category
+ const LLEmojiDictionary::cat2descrs_map_t::const_iterator& item = category2Descr.find(category);
+ if (item != category2Descr.end())
+ {
+ listCategory(category, item->second);
+ }
+ }
+ }
}
bool LLFloaterEmojiPicker::matchesPattern(const LLEmojiDescriptor* descr)
{
- if (descr->Name.find(mSearchPattern) != std::string::npos)
- return true;
- for (const std::string& shortCode : descr->ShortCodes)
- if (shortCode.find(mSearchPattern) != std::string::npos)
- return true;
- return false;
+ for (const std::string& shortCode : descr->ShortCodes)
+ if (shortCode.find(sSearchPattern) != std::string::npos)
+ return true;
+ return false;
}
-void LLFloaterEmojiPicker::onCategoryCommit()
+void LLFloaterEmojiPicker::onGroupButtonClick(LLUICtrl* ctrl)
{
- mSelectedCategory = mCategory->getSelectedValue().asString();
- mRecentMaxIcons = 0;
- fillEmojiGrid();
+ if (LLButton* button = dynamic_cast<LLButton*>(ctrl))
+ {
+ if (button == mGroupButtons[sSelectedGroupIndex] || button->getToggleState())
+ return;
+
+ auto it = std::find(mGroupButtons.begin(), mGroupButtons.end(), button);
+ if (it == mGroupButtons.end())
+ return;
+
+ mGroupButtons[sSelectedGroupIndex]->setToggleState(FALSE);
+ sSelectedGroupIndex = it - mGroupButtons.begin();
+ mGroupButtons[sSelectedGroupIndex]->setToggleState(TRUE);
+
+ LLRect rect = mBadge->getRect();
+ rect.mLeft = button->getRect().mLeft;
+ rect.mRight = button->getRect().mRight;
+ mBadge->setRect(rect);
+
+ mSearch->setFocus(TRUE);
+
+ fillEmojis();
+ }
}
void LLFloaterEmojiPicker::onSearchKeystroke()
{
- mSearchPattern = mSearch->getText();
- mRecentMaxIcons = 0;
- fillEmojiGrid();
+ sSearchPattern = mSearch->getText();
+ fillEmojis();
}
void LLFloaterEmojiPicker::onPreviewEmojiClick()
{
- if (mEmojiPickCallback)
- {
- if (LLEmojiGridIcon* icon = dynamic_cast<LLEmojiGridIcon*>(mHoveredIcon))
- {
- mEmojiPickCallback(icon->getEmoji());
- }
- }
+ 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);
+ mSearch->setVisible(FALSE);
+ mDescription->setText(LLStringExplicit(""), LLStyle::Params());
+ mDescription->setVisible(TRUE);
}
void LLFloaterEmojiPicker::onGridMouseLeave()
{
- mDescription->setVisible(FALSE);
- mDescription->setText(LLStringExplicit(""), LLStyle::Params());
- mSearch->setVisible(TRUE);
- mSearch->setFocus(TRUE);
+ mDescription->setVisible(FALSE);
+ mDescription->setText(LLStringExplicit(""), LLStyle::Params());
+ mSearch->setVisible(TRUE);
+ mSearch->setFocus(TRUE);
+}
+
+void LLFloaterEmojiPicker::onGroupButtonMouseEnter(LLUICtrl* ctrl)
+{
+ if (LLButton* button = dynamic_cast<LLButton*>(ctrl))
+ {
+ button->setUseFontColor(TRUE);
+ }
+}
+
+void LLFloaterEmojiPicker::onGroupButtonMouseLeave(LLUICtrl* ctrl)
+{
+ if (LLButton* button = dynamic_cast<LLButton*>(ctrl))
+ {
+ button->setUseFontColor(FALSE);
+ }
}
void LLFloaterEmojiPicker::onEmojiMouseEnter(LLUICtrl* ctrl)
{
- if (ctrl)
- {
- if (mHoveredIcon && mHoveredIcon != ctrl)
- {
- unselectGridIcon(mHoveredIcon);
- }
+ if (ctrl)
+ {
+ if (mHoveredIcon && mHoveredIcon != ctrl)
+ {
+ unselectGridIcon(mHoveredIcon);
+ }
- selectGridIcon(ctrl);
+ selectGridIcon(ctrl);
- mHoveredIcon = ctrl;
- }
+ mHoveredIcon = ctrl;
+ }
}
void LLFloaterEmojiPicker::onEmojiMouseLeave(LLUICtrl* ctrl)
{
- if (ctrl)
- {
- if (ctrl == mHoveredIcon)
- {
- unselectGridIcon(ctrl);
- }
- }
+ if (ctrl)
+ {
+ if (ctrl == mHoveredIcon)
+ {
+ unselectGridIcon(ctrl);
+ }
+ }
}
void LLFloaterEmojiPicker::onEmojiMouseClick(LLUICtrl* ctrl, MASK mask)
{
- if (mEmojiPickCallback)
- {
- if (LLEmojiGridIcon* icon = dynamic_cast<LLEmojiGridIcon*>(ctrl))
- {
- mPreviewEmoji->handleAnyMouseClick(0, 0, 0, EMouseClickType::CLICK_LEFT, TRUE);
- mPreviewEmoji->handleAnyMouseClick(0, 0, 0, EMouseClickType::CLICK_LEFT, FALSE);
- if (!(mask & 4))
- {
- closeFloater();
- }
- }
- }
+ if (mEmojiPickCallback)
+ {
+ if (LLEmojiGridIcon* icon = dynamic_cast<LLEmojiGridIcon*>(ctrl))
+ {
+ mPreviewEmoji->handleAnyMouseClick(0, 0, 0, EMouseClickType::CLICK_LEFT, TRUE);
+ mPreviewEmoji->handleAnyMouseClick(0, 0, 0, EMouseClickType::CLICK_LEFT, FALSE);
+ if (!(mask & 4))
+ {
+ closeFloater();
+ }
+ }
+ }
}
void LLFloaterEmojiPicker::selectGridIcon(LLUICtrl* ctrl)
{
- if (LLEmojiGridIcon* icon = dynamic_cast<LLEmojiGridIcon*>(ctrl))
- {
- icon->setBackgroundVisible(TRUE);
+ if (LLEmojiGridIcon* icon = dynamic_cast<LLEmojiGridIcon*>(ctrl))
+ {
+ icon->setBackgroundVisible(TRUE);
- LLUIString text;
- text.insert(0, icon->getText());
- mPreviewEmoji->setLabel(text);
+ LLUIString text;
+ text.insert(0, icon->getText());
+ mPreviewEmoji->setLabel(text);
- std::string descr = icon->getDescr() + "\n" + icon->getCategory();
- mDescription->setText(LLStringExplicit(descr), LLStyle::Params());
- }
+ std::string descr = icon->getDescr() + "\n" + icon->getCategory();
+ mDescription->setText(LLStringExplicit(descr), LLStyle::Params());
+ }
}
void LLFloaterEmojiPicker::unselectGridIcon(LLUICtrl* ctrl)
{
- if (LLEmojiGridIcon* icon = dynamic_cast<LLEmojiGridIcon*>(ctrl))
- {
- icon->setBackgroundVisible(FALSE);
- mPreviewEmoji->setLabel(LLUIString());
- mDescription->setText(LLStringExplicit(""), LLStyle::Params());
- }
+ if (LLEmojiGridIcon* icon = dynamic_cast<LLEmojiGridIcon*>(ctrl))
+ {
+ icon->setBackgroundVisible(FALSE);
+ mPreviewEmoji->setLabel(LLUIString());
+ mDescription->setText(LLStringExplicit(""), LLStyle::Params());
+ }
}
// virtual
BOOL LLFloaterEmojiPicker::handleKeyHere(KEY key, MASK mask)
{
- if (mask == MASK_NONE)
- {
- switch (key)
- {
- case KEY_ESCAPE:
- closeFloater();
- return TRUE;
- }
- }
-
- return LLFloater::handleKeyHere(key, mask);
+ if (mask == MASK_NONE)
+ {
+ switch (key)
+ {
+ case KEY_ESCAPE:
+ closeFloater();
+ return TRUE;
+ }
+ }
+
+ return LLFloater::handleKeyHere(key, mask);
}
// virtual
void LLFloaterEmojiPicker::closeFloater(bool app_quitting)
{
- LLFloater::closeFloater(app_quitting);
- if (mFloaterCloseCallback)
- {
- mFloaterCloseCallback();
- }
+ LLFloater::closeFloater(app_quitting);
+ if (mFloaterCloseCallback)
+ {
+ mFloaterCloseCallback();
+ }
}
diff --git a/indra/newview/llfloateremojipicker.h b/indra/newview/llfloateremojipicker.h
index 300d9a4d4a..7fa6ea46b0 100644
--- a/indra/newview/llfloateremojipicker.h
+++ b/indra/newview/llfloateremojipicker.h
@@ -33,62 +33,70 @@ struct LLEmojiDescriptor;
class LLFloaterEmojiPicker : public LLFloater
{
- using super = LLFloater;
+ using super = LLFloater;
public:
- // The callback function will be called with an emoji char.
- typedef boost::function<void (llwchar)> pick_callback_t;
- typedef boost::function<void ()> close_callback_t;
+ // The callback function will be called with an emoji char.
+ 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(pick_callback_t pick_callback = nullptr, close_callback_t close_callback = nullptr);
+ // Call this to select an emoji.
+ static LLFloaterEmojiPicker* getInstance();
+ static LLFloaterEmojiPicker* showInstance(pick_callback_t pick_callback = nullptr, close_callback_t close_callback = nullptr);
- LLFloaterEmojiPicker(const LLSD& key);
- virtual ~LLFloaterEmojiPicker();
+ LLFloaterEmojiPicker(const LLSD& key);
+ virtual ~LLFloaterEmojiPicker();
- virtual BOOL postBuild() override;
- virtual void dirtyRect() override;
+ virtual BOOL postBuild() override;
+ virtual void dirtyRect() override;
- void show(pick_callback_t pick_callback = nullptr, close_callback_t close_callback = nullptr);
+ void show(pick_callback_t pick_callback = nullptr, close_callback_t close_callback = nullptr);
- virtual void closeFloater(bool app_quitting = false) override;
+ virtual void closeFloater(bool app_quitting = false) override;
private:
- void fillEmojiGrid();
-
- bool matchesPattern(const LLEmojiDescriptor* descr);
-
- void onCategoryCommit();
- void onSearchKeystroke();
- void onPreviewEmojiClick();
- void onGridMouseEnter();
- void onGridMouseLeave();
- void onEmojiMouseEnter(LLUICtrl* ctrl);
- void onEmojiMouseLeave(LLUICtrl* ctrl);
- void onEmojiMouseClick(LLUICtrl* ctrl, MASK mask);
-
- void selectGridIcon(LLUICtrl* ctrl);
- void unselectGridIcon(LLUICtrl* ctrl);
-
- virtual BOOL handleKeyHere(KEY key, MASK mask) override;
-
- class LLComboBox* mCategory { nullptr };
- class LLLineEditor* mSearch { nullptr };
- class LLScrollContainer* mEmojiScroll { nullptr };
- class LLScrollingPanelList* mEmojiGrid { nullptr };
- class LLButton* mPreviewEmoji { nullptr };
- class LLTextBox* mDescription { nullptr };
-
- pick_callback_t mEmojiPickCallback;
- close_callback_t mFloaterCloseCallback;
-
- S32 mRecentGridWidth { 0 };
- S32 mRecentMaxIcons { 0 };
- LLUICtrl* mHoveredIcon { nullptr };
-
- static std::string mSelectedCategory;
- static std::string mSearchPattern;
+ void fillGroups();
+ 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 selectGridIcon(LLUICtrl* ctrl);
+ void unselectGridIcon(LLUICtrl* ctrl);
+
+ virtual BOOL handleKeyHere(KEY key, MASK mask) override;
+
+ class LLPanel* mGroups { nullptr };
+ class LLPanel* mBadge { nullptr };
+ class LLLineEditor* mSearch { nullptr };
+ class LLScrollContainer* mEmojiScroll { nullptr };
+ class LLScrollingPanelList* mEmojiGrid { nullptr };
+ class LLButton* mPreviewEmoji { nullptr };
+ class LLTextBox* mDescription { nullptr };
+
+ pick_callback_t mEmojiPickCallback;
+ close_callback_t mFloaterCloseCallback;
+
+ std::vector<class LLButton*> mGroupButtons;
+
+ S32 mRecentBadgeWidth { 0 };
+ S32 mRecentGridWidth { 0 };
+ S32 mRecentMaxIcons { 0 };
+ LLUICtrl* mHoveredIcon { nullptr };
+
+ static size_t sSelectedGroupIndex;
+ static std::string sSearchPattern;
};
#endif
diff --git a/indra/newview/skins/default/xui/da/emoji_categories.xml b/indra/newview/skins/default/xui/da/emoji_categories.xml
new file mode 100644
index 0000000000..456b18e4e2
--- /dev/null
+++ b/indra/newview/skins/default/xui/da/emoji_categories.xml
@@ -0,0 +1,59 @@
+<?xml version="1.0" ?>
+<llsd xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="llsd.xsd">
+ <array>
+ <map>
+ <key>Name</key>
+ <string>smileys and emotion</string>
+ <key>Category</key>
+ <string>smileys and følelser</string>
+ </map>
+ <map>
+ <key>Name</key>
+ <string>people and body</string>
+ <key>Category</key>
+ <string>mennesker and krop</string>
+ </map>
+ <map>
+ <key>Name</key>
+ <string>components</string>
+ <key>Category</key>
+ <string>komponenter</string>
+ </map>
+ <map>
+ <key>Name</key>
+ <string>animals and nature</string>
+ <key>Category</key>
+ <string>dyr and natur</string>
+ </map>
+ <map>
+ <key>Name</key>
+ <string>food and drink</string>
+ <key>Category</key>
+ <string>mad and drikke</string>
+ </map>
+ <map>
+ <key>Name</key>
+ <string>travel and places</string>
+ <key>Category</key>
+ <string>rejser and steder</string>
+ </map>
+ <map>
+ <key>Name</key>
+ <string>activities</string>
+ <key>Category</key>
+ <string>oplevelser</string>
+ </map>
+ <map>
+ <key>Name</key>
+ <string>objects</string>
+ <key>Category</key>
+ <string>objekter</string>
+ </map>
+ <map>
+ <key>Name</key>
+ <string>symbols</string>
+ <key>Category</key>
+ <string>symboler</string>
+ </map>
+ </array>
+</llsd>
diff --git a/indra/newview/skins/default/xui/de/emoji_categories.xml b/indra/newview/skins/default/xui/de/emoji_categories.xml
new file mode 100644
index 0000000000..ed63d0bac9
--- /dev/null
+++ b/indra/newview/skins/default/xui/de/emoji_categories.xml
@@ -0,0 +1,59 @@
+<?xml version="1.0" ?>
+<llsd xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="llsd.xsd">
+ <array>
+ <map>
+ <key>Name</key>
+ <string>smileys and emotion</string>
+ <key>Category</key>
+ <string>Smileys and Emotionen</string>
+ </map>
+ <map>
+ <key>Name</key>
+ <string>people and body</string>
+ <key>Category</key>
+ <string>Menschen and Körper</string>
+ </map>
+ <map>
+ <key>Name</key>
+ <string>components</string>
+ <key>Category</key>
+ <string>Komponenten</string>
+ </map>
+ <map>
+ <key>Name</key>
+ <string>animals and nature</string>
+ <key>Category</key>
+ <string>Tiere and Natur</string>
+ </map>
+ <map>
+ <key>Name</key>
+ <string>food and drink</string>
+ <key>Category</key>
+ <string>Essen and Trinken</string>
+ </map>
+ <map>
+ <key>Name</key>
+ <string>travel and places</string>
+ <key>Category</key>
+ <string>Reisen and Orte</string>
+ </map>
+ <map>
+ <key>Name</key>
+ <string>activities</string>
+ <key>Category</key>
+ <string>Aktivitäten</string>
+ </map>
+ <map>
+ <key>Name</key>
+ <string>objects</string>
+ <key>Category</key>
+ <string>Gegenstände</string>
+ </map>
+ <map>
+ <key>Name</key>
+ <string>symbols</string>
+ <key>Category</key>
+ <string>Symbole</string>
+ </map>
+ </array>
+</llsd>
diff --git a/indra/newview/skins/default/xui/en/emoji_categories.xml b/indra/newview/skins/default/xui/en/emoji_categories.xml
new file mode 100644
index 0000000000..0315d0c43a
--- /dev/null
+++ b/indra/newview/skins/default/xui/en/emoji_categories.xml
@@ -0,0 +1,59 @@
+<?xml version="1.0" ?>
+<llsd xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="llsd.xsd">
+ <array>
+ <map>
+ <key>Name</key>
+ <string>smileys and emotion</string>
+ <key>Category</key>
+ <string>smileys and emotion</string>
+ </map>
+ <map>
+ <key>Name</key>
+ <string>people and body</string>
+ <key>Category</key>
+ <string>people and body</string>
+ </map>
+ <map>
+ <key>Name</key>
+ <string>components</string>
+ <key>Category</key>
+ <string>components</string>
+ </map>
+ <map>
+ <key>Name</key>
+ <string>animals and nature</string>
+ <key>Category</key>
+ <string>animals and nature</string>
+ </map>
+ <map>
+ <key>Name</key>
+ <string>food and drink</string>
+ <key>Category</key>
+ <string>food and drink</string>
+ </map>
+ <map>
+ <key>Name</key>
+ <string>travel and places</string>
+ <key>Category</key>
+ <string>travel and places</string>
+ </map>
+ <map>
+ <key>Name</key>
+ <string>activities</string>
+ <key>Category</key>
+ <string>activities</string>
+ </map>
+ <map>
+ <key>Name</key>
+ <string>objects</string>
+ <key>Category</key>
+ <string>objects</string>
+ </map>
+ <map>
+ <key>Name</key>
+ <string>symbols</string>
+ <key>Category</key>
+ <string>symbols</string>
+ </map>
+ </array>
+</llsd>
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 2e153933c0..2a534b23b9 100644
--- a/indra/newview/skins/default/xui/en/floater_emoji_picker.xml
+++ b/indra/newview/skins/default/xui/en/floater_emoji_picker.xml
@@ -7,8 +7,9 @@
legacy_header_height="0"
can_resize="true"
layout="topleft"
+ min_width="250"
height="400"
- width="200">
+ width="250">
<line_editor
name="Search"
label="Type to search"
@@ -19,7 +20,7 @@
bottom="14"
left="34"
height="29"
- width="162" />
+ width="212" />
<text
name="Description"
layout="bottomleft"
@@ -28,7 +29,7 @@
bottom="14"
left="42"
height="29"
- width="150" />
+ width="200" />
<button
name="PreviewEmoji"
layout="bottomleft"
@@ -46,7 +47,7 @@
top="25"
left="0"
height="330"
- width="200">
+ width="250">
<scrolling_panel_list
name="EmojiGrid"
layout="topleft"
@@ -55,16 +56,26 @@
spacing="0"
top="0"
left="0"
- width="200"/>
+ width="250"/>
</scroll_container>
- <combo_box
- name="Category"
- label="Choose a category"
+ <panel
+ name="Groups"
layout="topleft"
follows="top|left|right"
- allow_text_entry="true"
top="0"
- left="2"
+ left="0"
height="25"
- width="196" />
+ width="250">
+ <panel
+ name="Badge"
+ layout="bottomleft"
+ follows="bottom|left"
+ background_visible="true"
+ background_opaque="true"
+ bg_opaque_color="FrogGreen"
+ bottom="0"
+ height="2"
+ width="20"
+ />
+ </panel>
</floater>
diff --git a/indra/newview/skins/default/xui/es/emoji_categories.xml b/indra/newview/skins/default/xui/es/emoji_categories.xml
new file mode 100644
index 0000000000..b1b73eba5e
--- /dev/null
+++ b/indra/newview/skins/default/xui/es/emoji_categories.xml
@@ -0,0 +1,59 @@
+<?xml version="1.0" ?>
+<llsd xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="llsd.xsd">
+ <array>
+ <map>
+ <key>Name</key>
+ <string>smileys and emotion</string>
+ <key>Category</key>
+ <string>emoticonos y emoción</string>
+ </map>
+ <map>
+ <key>Name</key>
+ <string>people and body</string>
+ <key>Category</key>
+ <string>personas y cuerpo</string>
+ </map>
+ <map>
+ <key>Name</key>
+ <string>components</string>
+ <key>Category</key>
+ <string>componentes</string>
+ </map>
+ <map>
+ <key>Name</key>
+ <string>animals and nature</string>
+ <key>Category</key>
+ <string>animales y la naturaleza</string>
+ </map>
+ <map>
+ <key>Name</key>
+ <string>food and drink</string>
+ <key>Category</key>
+ <string>comida y bebida</string>
+ </map>
+ <map>
+ <key>Name</key>
+ <string>travel and places</string>
+ <key>Category</key>
+ <string>viajes y lugares</string>
+ </map>
+ <map>
+ <key>Name</key>
+ <string>activities</string>
+ <key>Category</key>
+ <string>actividades</string>
+ </map>
+ <map>
+ <key>Name</key>
+ <string>objects</string>
+ <key>Category</key>
+ <string>objetos</string>
+ </map>
+ <map>
+ <key>Name</key>
+ <string>symbols</string>
+ <key>Category</key>
+ <string>símbolos</string>
+ </map>
+ </array>
+</llsd>
diff --git a/indra/newview/skins/default/xui/fr/emoji_categories.xml b/indra/newview/skins/default/xui/fr/emoji_categories.xml
new file mode 100644
index 0000000000..38dc9cb8f8
--- /dev/null
+++ b/indra/newview/skins/default/xui/fr/emoji_categories.xml
@@ -0,0 +1,59 @@
+<?xml version="1.0" ?>
+<llsd xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="llsd.xsd">
+ <array>
+ <map>
+ <key>Name</key>
+ <string>smileys and emotion</string>
+ <key>Category</key>
+ <string>smileys et émotion</string>
+ </map>
+ <map>
+ <key>Name</key>
+ <string>people and body</string>
+ <key>Category</key>
+ <string>les gens et le corps</string>
+ </map>
+ <map>
+ <key>Name</key>
+ <string>components</string>
+ <key>Category</key>
+ <string>composants</string>
+ </map>
+ <map>
+ <key>Name</key>
+ <string>animals and nature</string>
+ <key>Category</key>
+ <string>animaux et la nature</string>
+ </map>
+ <map>
+ <key>Name</key>
+ <string>food and drink</string>
+ <key>Category</key>
+ <string>nourriture et boissons</string>
+ </map>
+ <map>
+ <key>Name</key>
+ <string>travel and places</string>
+ <key>Category</key>
+ <string>voyages et lieux</string>
+ </map>
+ <map>
+ <key>Name</key>
+ <string>activities</string>
+ <key>Category</key>
+ <string>activités</string>
+ </map>
+ <map>
+ <key>Name</key>
+ <string>objects</string>
+ <key>Category</key>
+ <string>objets</string>
+ </map>
+ <map>
+ <key>Name</key>
+ <string>symbols</string>
+ <key>Category</key>
+ <string>symboles</string>
+ </map>
+ </array>
+</llsd>
diff --git a/indra/newview/skins/default/xui/it/emoji_categories.xml b/indra/newview/skins/default/xui/it/emoji_categories.xml
new file mode 100644
index 0000000000..a4782e60a6
--- /dev/null
+++ b/indra/newview/skins/default/xui/it/emoji_categories.xml
@@ -0,0 +1,59 @@
+<?xml version="1.0" ?>
+<llsd xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="llsd.xsd">
+ <array>
+ <map>
+ <key>Name</key>
+ <string>smileys and emotion</string>
+ <key>Category</key>
+ <string>smileys and emozione</string>
+ </map>
+ <map>
+ <key>Name</key>
+ <string>people and body</string>
+ <key>Category</key>
+ <string>persone e corpo</string>
+ </map>
+ <map>
+ <key>Name</key>
+ <string>components</string>
+ <key>Category</key>
+ <string>componenti</string>
+ </map>
+ <map>
+ <key>Name</key>
+ <string>animals and nature</string>
+ <key>Category</key>
+ <string>animali and natura</string>
+ </map>
+ <map>
+ <key>Name</key>
+ <string>food and drink</string>
+ <key>Category</key>
+ <string>cibo e bevande</string>
+ </map>
+ <map>
+ <key>Name</key>
+ <string>travel and places</string>
+ <key>Category</key>
+ <string>viaggi and luoghi</string>
+ </map>
+ <map>
+ <key>Name</key>
+ <string>activities</string>
+ <key>Category</key>
+ <string>attività</string>
+ </map>
+ <map>
+ <key>Name</key>
+ <string>objects</string>
+ <key>Category</key>
+ <string>oggetti</string>
+ </map>
+ <map>
+ <key>Name</key>
+ <string>symbols</string>
+ <key>Category</key>
+ <string>simboli</string>
+ </map>
+ </array>
+</llsd>
diff --git a/indra/newview/skins/default/xui/ja/emoji_categories.xml b/indra/newview/skins/default/xui/ja/emoji_categories.xml
new file mode 100644
index 0000000000..7750f4ad2e
--- /dev/null
+++ b/indra/newview/skins/default/xui/ja/emoji_categories.xml
@@ -0,0 +1,59 @@
+<?xml version="1.0" ?>
+<llsd xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="llsd.xsd">
+ <array>
+ <map>
+ <key>Name</key>
+ <string>smileys and emotion</string>
+ <key>Category</key>
+ <string>スマイリーと感情</string>
+ </map>
+ <map>
+ <key>Name</key>
+ <string>people and body</string>
+ <key>Category</key>
+ <string>人体</string>
+ </map>
+ <map>
+ <key>Name</key>
+ <string>components</string>
+ <key>Category</key>
+ <string>コンポーネント</string>
+ </map>
+ <map>
+ <key>Name</key>
+ <string>animals and nature</string>
+ <key>Category</key>
+ <string>動物自然</string>
+ </map>
+ <map>
+ <key>Name</key>
+ <string>food and drink</string>
+ <key>Category</key>
+ <string>飲み物・食べ物</string>
+ </map>
+ <map>
+ <key>Name</key>
+ <string>travel and places</string>
+ <key>Category</key>
+ <string>旅行・場所</string>
+ </map>
+ <map>
+ <key>Name</key>
+ <string>activities</string>
+ <key>Category</key>
+ <string>有効化</string>
+ </map>
+ <map>
+ <key>Name</key>
+ <string>objects</string>
+ <key>Category</key>
+ <string>オブジェクト</string>
+ </map>
+ <map>
+ <key>Name</key>
+ <string>symbols</string>
+ <key>Category</key>
+ <string>シンボル</string>
+ </map>
+ </array>
+</llsd>
diff --git a/indra/newview/skins/default/xui/pl/emoji_categories.xml b/indra/newview/skins/default/xui/pl/emoji_categories.xml
new file mode 100644
index 0000000000..9aad7af794
--- /dev/null
+++ b/indra/newview/skins/default/xui/pl/emoji_categories.xml
@@ -0,0 +1,59 @@
+<?xml version="1.0" ?>
+<llsd xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="llsd.xsd">
+ <array>
+ <map>
+ <key>Name</key>
+ <string>smileys and emotion</string>
+ <key>Category</key>
+ <string>buźki and emocje</string>
+ </map>
+ <map>
+ <key>Name</key>
+ <string>people and body</string>
+ <key>Category</key>
+ <string>ludzie and ciało</string>
+ </map>
+ <map>
+ <key>Name</key>
+ <string>components</string>
+ <key>Category</key>
+ <string>składniki</string>
+ </map>
+ <map>
+ <key>Name</key>
+ <string>animals and nature</string>
+ <key>Category</key>
+ <string>zwierzęta and przyroda</string>
+ </map>
+ <map>
+ <key>Name</key>
+ <string>food and drink</string>
+ <key>Category</key>
+ <string>jedzenie i picie</string>
+ </map>
+ <map>
+ <key>Name</key>
+ <string>travel and places</string>
+ <key>Category</key>
+ <string>podróże and miejsca</string>
+ </map>
+ <map>
+ <key>Name</key>
+ <string>activities</string>
+ <key>Category</key>
+ <string>aktywność</string>
+ </map>
+ <map>
+ <key>Name</key>
+ <string>objects</string>
+ <key>Category</key>
+ <string>objekt</string>
+ </map>
+ <map>
+ <key>Name</key>
+ <string>symbols</string>
+ <key>Category</key>
+ <string>symbole</string>
+ </map>
+ </array>
+</llsd>
diff --git a/indra/newview/skins/default/xui/pt/emoji_categories.xml b/indra/newview/skins/default/xui/pt/emoji_categories.xml
new file mode 100644
index 0000000000..887444b957
--- /dev/null
+++ b/indra/newview/skins/default/xui/pt/emoji_categories.xml
@@ -0,0 +1,59 @@
+<?xml version="1.0" ?>
+<llsd xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="llsd.xsd">
+ <array>
+ <map>
+ <key>Name</key>
+ <string>smileys and emotion</string>
+ <key>Category</key>
+ <string>sorrisos e emoção</string>
+ </map>
+ <map>
+ <key>Name</key>
+ <string>people and body</string>
+ <key>Category</key>
+ <string>pessoas e corpo</string>
+ </map>
+ <map>
+ <key>Name</key>
+ <string>components</string>
+ <key>Category</key>
+ <string>componentes</string>
+ </map>
+ <map>
+ <key>Name</key>
+ <string>animals and nature</string>
+ <key>Category</key>
+ <string>animais e natureza</string>
+ </map>
+ <map>
+ <key>Name</key>
+ <string>food and drink</string>
+ <key>Category</key>
+ <string>comida e bebida</string>
+ </map>
+ <map>
+ <key>Name</key>
+ <string>travel and places</string>
+ <key>Category</key>
+ <string>viagens e lugares</string>
+ </map>
+ <map>
+ <key>Name</key>
+ <string>activities</string>
+ <key>Category</key>
+ <string>atividades</string>
+ </map>
+ <map>
+ <key>Name</key>
+ <string>objects</string>
+ <key>Category</key>
+ <string>objetos</string>
+ </map>
+ <map>
+ <key>Name</key>
+ <string>symbols</string>
+ <key>Category</key>
+ <string>símbolos</string>
+ </map>
+ </array>
+</llsd>
diff --git a/indra/newview/skins/default/xui/ru/emoji_categories.xml b/indra/newview/skins/default/xui/ru/emoji_categories.xml
new file mode 100644
index 0000000000..b08f0d8117
--- /dev/null
+++ b/indra/newview/skins/default/xui/ru/emoji_categories.xml
@@ -0,0 +1,59 @@
+<?xml version="1.0" ?>
+<llsd xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="llsd.xsd">
+ <array>
+ <map>
+ <key>Name</key>
+ <string>smileys and emotion</string>
+ <key>Category</key>
+ <string>смайлики и люди</string>
+ </map>
+ <map>
+ <key>Name</key>
+ <string>people and body</string>
+ <key>Category</key>
+ <string>тело людей</string>
+ </map>
+ <map>
+ <key>Name</key>
+ <string>components</string>
+ <key>Category</key>
+ <string>компонент</string>
+ </map>
+ <map>
+ <key>Name</key>
+ <string>animals and nature</string>
+ <key>Category</key>
+ <string>животные и природа</string>
+ </map>
+ <map>
+ <key>Name</key>
+ <string>food and drink</string>
+ <key>Category</key>
+ <string>еда и напитки</string>
+ </map>
+ <map>
+ <key>Name</key>
+ <string>travel and places</string>
+ <key>Category</key>
+ <string>путешествия и местности</string>
+ </map>
+ <map>
+ <key>Name</key>
+ <string>activities</string>
+ <key>Category</key>
+ <string>варианты досуга</string>
+ </map>
+ <map>
+ <key>Name</key>
+ <string>objects</string>
+ <key>Category</key>
+ <string>предметы</string>
+ </map>
+ <map>
+ <key>Name</key>
+ <string>symbols</string>
+ <key>Category</key>
+ <string>символы</string>
+ </map>
+ </array>
+</llsd>
diff --git a/indra/newview/skins/default/xui/zh/emoji_categories.xml b/indra/newview/skins/default/xui/zh/emoji_categories.xml
new file mode 100644
index 0000000000..fbe6165eeb
--- /dev/null
+++ b/indra/newview/skins/default/xui/zh/emoji_categories.xml
@@ -0,0 +1,59 @@
+<?xml version="1.0" ?>
+<llsd xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="llsd.xsd">
+ <array>
+ <map>
+ <key>Name</key>
+ <string>smileys and emotion</string>
+ <key>Category</key>
+ <string>笑脸</string>
+ </map>
+ <map>
+ <key>Name</key>
+ <string>people and body</string>
+ <key>Category</key>
+ <string>人体</string>
+ </map>
+ <map>
+ <key>Name</key>
+ <string>components</string>
+ <key>Category</key>
+ <string>组件</string>
+ </map>
+ <map>
+ <key>Name</key>
+ <string>animals and nature</string>
+ <key>Category</key>
+ <string>野生动物</string>
+ </map>
+ <map>
+ <key>Name</key>
+ <string>food and drink</string>
+ <key>Category</key>
+ <string>食物飲料</string>
+ </map>
+ <map>
+ <key>Name</key>
+ <string>travel and places</string>
+ <key>Category</key>
+ <string>旅遊地點</string>
+ </map>
+ <map>
+ <key>Name</key>
+ <string>activities</string>
+ <key>Category</key>
+ <string>个人活动</string>
+ </map>
+ <map>
+ <key>Name</key>
+ <string>objects</string>
+ <key>Category</key>
+ <string>物件</string>
+ </map>
+ <map>
+ <key>Name</key>
+ <string>symbols</string>
+ <key>Category</key>
+ <string>人的符号</string>
+ </map>
+ </array>
+</llsd>