Merge pull request #183 from secondlife/SL-19575a

SL-19575 LLFloaterEmojiPicker - Add filter by category
meow-7.2.2
Callum Linden 2023-04-20 07:19:26 -07:00 committed by GitHub
commit a7eef57c1f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
16 changed files with 370 additions and 110 deletions

View File

@ -357,6 +357,7 @@ public:
static void replaceNonstandardASCII( string_type& string, T replacement );
static void replaceChar( string_type& string, T target, T replacement );
static void replaceString( string_type& string, string_type target, string_type replacement );
static void capitalize(string_type& str);
static BOOL containsNonprintable(const string_type& string);
static void stripNonprintable(string_type& string);
@ -1595,6 +1596,20 @@ void LLStringUtilBase<T>::replaceTabsWithSpaces( string_type& str, size_type spa
str = out_str;
}
//static
template<class T>
void LLStringUtilBase<T>::capitalize(string_type& str)
{
if (str.size())
{
auto last = str[0] = toupper(str[0]);
for (U32 i = 1; i < str.size(); ++i)
{
last = (last == ' ' || last == '-' || last == '_') ? str[i] = toupper(str[i]) : str[i];
}
}
}
//static
template<class T>
BOOL LLStringUtilBase<T>::containsNonprintable(const string_type& string)

View File

@ -68,6 +68,7 @@ LLButton::Params::Params()
label_shadow("label_shadow", true),
auto_resize("auto_resize", false),
use_ellipses("use_ellipses", false),
use_font_color("use_font_color", false),
image_unselected("image_unselected"),
image_selected("image_selected"),
image_hover_selected("image_hover_selected"),
@ -160,6 +161,7 @@ LLButton::LLButton(const LLButton::Params& p)
mDropShadowedText(p.label_shadow),
mAutoResize(p.auto_resize),
mUseEllipses( p.use_ellipses ),
mUseFontColor( p.use_font_color),
mHAlign(p.font_halign),
mLeftHPad(p.pad_left),
mRightHPad(p.pad_right),
@ -960,7 +962,7 @@ void LLButton::draw()
LLFontGL::NORMAL,
mDropShadowedText ? LLFontGL::DROP_SHADOW_SOFT : LLFontGL::NO_SHADOW,
S32_MAX, text_width,
NULL, mUseEllipses);
NULL, mUseEllipses, mUseFontColor);
}
LLUICtrl::draw();
@ -1020,6 +1022,16 @@ BOOL LLButton::toggleState()
return flipped;
}
void LLButton::setLabel( const std::string& label )
{
mUnselectedLabel = mSelectedLabel = label;
}
void LLButton::setLabel( const LLUIString& label )
{
mUnselectedLabel = mSelectedLabel = label;
}
void LLButton::setLabel( const LLStringExplicit& label )
{
setLabelUnselected(label);
@ -1051,14 +1063,7 @@ bool LLButton::labelIsTruncated() const
const LLUIString& LLButton::getCurrentLabel() const
{
if( getToggleState() )
{
return mSelectedLabel;
}
else
{
return mUnselectedLabel;
}
return getToggleState() ? mSelectedLabel : mUnselectedLabel;
}
void LLButton::setImageUnselected(LLPointer<LLUIImage> image)

View File

@ -73,6 +73,7 @@ public:
Optional<bool> label_shadow;
Optional<bool> auto_resize;
Optional<bool> use_ellipses;
Optional<bool> use_font_color;
// images
Optional<LLUIImage*> image_unselected,
@ -174,6 +175,7 @@ public:
void setUnselectedLabelColor( const LLColor4& c ) { mUnselectedLabelColor = c; }
void setSelectedLabelColor( const LLColor4& c ) { mSelectedLabelColor = c; }
void setUseEllipses( BOOL use_ellipses ) { mUseEllipses = use_ellipses; }
void setUseFontColor( BOOL use_font_color) { mUseFontColor = use_font_color; }
boost::signals2::connection setClickedCallback(const CommitCallbackParam& cb);
@ -238,6 +240,8 @@ public:
void autoResize(); // resize with label of current btn state
void resize(LLUIString label); // resize with label input
void setLabel(const std::string& label);
void setLabel(const LLUIString& label);
void setLabel( const LLStringExplicit& label);
virtual BOOL setLabelArg( const std::string& key, const LLStringExplicit& text );
void setLabelUnselected(const LLStringExplicit& label);
@ -353,6 +357,7 @@ protected:
bool mDropShadowedText;
bool mAutoResize;
bool mUseEllipses;
bool mUseFontColor;
bool mBorderEnabled;
bool mFlashing;

View File

@ -175,6 +175,12 @@ LLWString LLEmojiDictionary::findMatchingEmojis(const std::string& needle) const
return result;
}
const LLEmojiDescriptor* LLEmojiDictionary::getDescriptorFromEmoji(llwchar emoji) const
{
const auto it = mEmoji2Descr.find(emoji);
return (mEmoji2Descr.end() != it) ? it->second : nullptr;
}
const LLEmojiDescriptor* LLEmojiDictionary::getDescriptorFromShortCode(const std::string& short_code) const
{
const auto it = mShortCode2Descr.find(short_code);
@ -195,6 +201,10 @@ void LLEmojiDictionary::addEmoji(LLEmojiDescriptor&& descr)
{
mShortCode2Descr.insert(std::make_pair(shortCode, &mEmojis.back()));
}
for (const std::string& category : descr.Categories)
{
mCategory2Descrs[category].push_back(&mEmojis.back());
}
}
// ============================================================================

View File

@ -56,20 +56,28 @@ class LLEmojiDictionary : public LLParamSingleton<LLEmojiDictionary>, public LLI
~LLEmojiDictionary() override {};
public:
typedef std::map<llwchar, const LLEmojiDescriptor*> emoji2descr_map_t;
typedef std::map<std::string, const LLEmojiDescriptor*> code2descr_map_t;
typedef std::map<std::string, std::vector<const LLEmojiDescriptor*>> cat2descrs_map_t;
static void initClass();
LLWString findMatchingEmojis(const std::string& needle) const;
const LLEmojiDescriptor* getDescriptorFromEmoji(llwchar emoji) const;
const LLEmojiDescriptor* getDescriptorFromShortCode(const std::string& short_code) const;
std::string getNameFromEmoji(llwchar ch) const;
const std::map<llwchar, const LLEmojiDescriptor*>& getEmoji2Descr() const { return mEmoji2Descr; }
const emoji2descr_map_t& getEmoji2Descr() const { return mEmoji2Descr; }
const code2descr_map_t& getShortCode2Descr() const { return mShortCode2Descr; }
const cat2descrs_map_t& getCategory2Descrs() const { return mCategory2Descrs; }
private:
void addEmoji(LLEmojiDescriptor&& descr);
private:
std::list<LLEmojiDescriptor> mEmojis;
std::map<llwchar, const LLEmojiDescriptor*> mEmoji2Descr;
std::map<std::string, const LLEmojiDescriptor*> mShortCode2Descr;
emoji2descr_map_t mEmoji2Descr;
code2descr_map_t mShortCode2Descr;
cat2descrs_map_t mCategory2Descrs;
};
// ============================================================================

View File

@ -1509,14 +1509,24 @@ BOOL LLFloater::isFrontmost()
&& floater_view->getFrontmost() == this);
}
void LLFloater::addDependentFloater(LLFloater* floaterp, BOOL reposition)
void LLFloater::addDependentFloater(LLFloater* floaterp, BOOL reposition, BOOL resize)
{
mDependents.insert(floaterp->getHandle());
floaterp->mDependeeHandle = getHandle();
if (reposition)
{
floaterp->setRect(gFloaterView->findNeighboringPosition(this, floaterp));
LLRect rect = gFloaterView->findNeighboringPosition(this, floaterp);
if (resize)
{
const LLRect& base = getRect();
if (rect.mTop == base.mTop)
rect.mBottom = base.mBottom;
else if (rect.mLeft == base.mLeft)
rect.mRight = base.mRight;
floaterp->reshape(rect.getWidth(), rect.getHeight(), FALSE);
}
floaterp->setRect(rect);
floaterp->setSnapTarget(getHandle());
}
gFloaterView->adjustToFitScreen(floaterp, FALSE, TRUE);
@ -1527,12 +1537,12 @@ void LLFloater::addDependentFloater(LLFloater* floaterp, BOOL reposition)
}
}
void LLFloater::addDependentFloater(LLHandle<LLFloater> dependent, BOOL reposition)
void LLFloater::addDependentFloater(LLHandle<LLFloater> dependent, BOOL reposition, BOOL resize)
{
LLFloater* dependent_floaterp = dependent.get();
if(dependent_floaterp)
{
addDependentFloater(dependent_floaterp, reposition);
addDependentFloater(dependent_floaterp, reposition, resize);
}
}

View File

@ -255,8 +255,8 @@ public:
std::string getShortTitle() const;
virtual void setMinimized(BOOL b);
void moveResizeHandlesToFront();
void addDependentFloater(LLFloater* dependent, BOOL reposition = TRUE);
void addDependentFloater(LLHandle<LLFloater> dependent_handle, BOOL reposition = TRUE);
void addDependentFloater(LLFloater* dependent, BOOL reposition = TRUE, BOOL resize = FALSE);
void addDependentFloater(LLHandle<LLFloater> dependent_handle, BOOL reposition = TRUE, BOOL resize = FALSE);
LLFloater* getDependee() { return (LLFloater*)mDependeeHandle.get(); }
void removeDependentFloater(LLFloater* dependent);
BOOL isMinimized() const { return mMinimized; }

View File

@ -1269,7 +1269,7 @@ BOOL LLScrollListCtrl::selectItemByLabel(const std::string& label, BOOL case_sen
LLScrollListItem* item = getItemByLabel(label, case_sensitive, column);
bool found = NULL != item;
if(found)
if (found)
{
selectItem(item, -1);
}
@ -2747,7 +2747,7 @@ BOOL LLScrollListCtrl::setSort(S32 column_idx, BOOL ascending)
S32 LLScrollListCtrl::getLinesPerPage()
{
//if mPageLines is NOT provided display all item
if(mPageLines)
if (mPageLines)
{
return mPageLines;
}

View File

@ -253,7 +253,7 @@ public:
S32 getItemIndex( LLScrollListItem* item ) const;
S32 getItemIndex( const LLUUID& item_id ) const;
void setCommentText( const std::string& comment_text);
void setCommentText( const std::string& comment_text);
LLScrollListItem* addSeparator(EAddPosition pos);
// "Simple" interface: use this when you're creating a list that contains only unique strings, only
@ -263,7 +263,7 @@ public:
BOOL selectItemByLabel( const std::string& item, BOOL case_sensitive = TRUE, S32 column = 0 ); // FALSE if item not found
BOOL selectItemByPrefix(const std::string& target, BOOL case_sensitive = TRUE, S32 column = -1);
BOOL selectItemByPrefix(const LLWString& target, BOOL case_sensitive = TRUE, S32 column = -1);
LLScrollListItem* getItemByLabel( const std::string& item, BOOL case_sensitive = TRUE, S32 column = 0 );
LLScrollListItem* getItemByLabel(const std::string& item, BOOL case_sensitive = TRUE, S32 column = 0);
const std::string getSelectedItemLabel(S32 column = 0) const;
LLSD getSelectedValue();
@ -322,7 +322,7 @@ public:
virtual S32 getScrollPos() const;
virtual void setScrollPos( S32 pos );
S32 getSearchColumn();
S32 getSearchColumn();
void setSearchColumn(S32 column) { mSearchColumn = column; }
S32 getColumnIndexFromOffset(S32 x);
S32 getColumnOffsetFromIndex(S32 index);
@ -371,13 +371,13 @@ public:
// Used "internally" by the scroll bar.
void onScrollChange( S32 new_pos, LLScrollbar* src );
static void onClickColumn(void *userdata);
static void onClickColumn(void *userdata);
virtual void updateColumns(bool force_update = false);
S32 calcMaxContentWidth();
bool updateColumnWidths();
virtual void updateColumns(bool force_update = false);
S32 calcMaxContentWidth();
bool updateColumnWidths();
void setHeadingHeight(S32 heading_height);
void setHeadingHeight(S32 heading_height);
/**
* Sets max visible lines without scroolbar, if this value equals to 0,
* then display all items.
@ -398,18 +398,20 @@ public:
virtual void deselect();
virtual BOOL canDeselect() const;
void setNumDynamicColumns(S32 num) { mNumDynamicWidthColumns = num; }
void updateStaticColumnWidth(LLScrollListColumn* col, S32 new_width);
S32 getTotalStaticColumnWidth() { return mTotalStaticColumnWidth; }
void setNumDynamicColumns(S32 num) { mNumDynamicWidthColumns = num; }
void updateStaticColumnWidth(LLScrollListColumn* col, S32 new_width);
S32 getTotalStaticColumnWidth() { return mTotalStaticColumnWidth; }
std::string getSortColumnName();
BOOL getSortAscending() { return mSortColumns.empty() ? TRUE : mSortColumns.back().second; }
BOOL hasSortOrder() const;
void clearSortOrder();
void setAlternateSort() { mAlternateSort = true; }
void setAlternateSort() { mAlternateSort = TRUE; }
S32 selectMultiple( uuid_vec_t ids );
void selectPrevItem(BOOL extend_selection = FALSE);
void selectNextItem(BOOL extend_selection = FALSE);
S32 selectMultiple(uuid_vec_t ids);
// conceptually const, but mutates mItemList
void updateSort() const;
// sorts a list without affecting the permanent sort order (so further list insertions can be unsorted, for example)
@ -454,8 +456,6 @@ protected:
void updateLineHeight();
private:
void selectPrevItem(BOOL extend_selection);
void selectNextItem(BOOL extend_selection);
void drawItems();
void updateLineHeightInsert(LLScrollListItem* item);

View File

@ -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);

View File

@ -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()
{
// Should be initialized first
if ((mPreviewEmoji = getChild<LLButton>("PreviewEmoji")))
{
mPreviewEmoji->setClickedCallback(boost::bind(&LLFloaterEmojiPicker::onPreviewEmojiClick, this));
}
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)
{
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->setDoubleClickCallback(boost::bind(&LLFloaterEmojiPicker::onSelect, this));
mEmojis->clearRows();
const std::map<llwchar, const LLEmojiDescriptor*>& emoji2Descr = LLEmojiDictionary::instance().getEmoji2Descr();
for (const std::pair<const llwchar, const LLEmojiDescriptor*>& it : emoji2Descr)
{
LLScrollListItem::Params params;
params.columns.add().column("name").value(it.second->Name);
mEmojis->addRow(new LLEmojiScrollListItem(it.first, params), params);
}
mEmojis->setCommitCallback(boost::bind(&LLFloaterEmojiPicker::onEmojiSelect, this));
mEmojis->setDoubleClickCallback(boost::bind(&LLFloaterEmojiPicker::onEmojiPick, this));
fillEmojis();
}
return TRUE;
@ -114,13 +145,115 @@ LLFloaterEmojiPicker::~LLFloaterEmojiPicker()
gFocusMgr.releaseFocusIfNeeded( this );
}
void LLFloaterEmojiPicker::onSelect()
void LLFloaterEmojiPicker::fillEmojis()
{
if (mEmojis && mSelectCallback)
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)
{
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());
}
}
}
void LLFloaterEmojiPicker::onEmojiSelect()
{
const LLEmojiScrollListItem* item = dynamic_cast<LLEmojiScrollListItem*>(mEmojis->getFirstSelected());
if (item)
{
mSelectedEmojiIndex = mEmojis->getFirstSelectedIndex();
LLUIString text;
text.insert(0, LLWString(1, item->getEmoji()));
if (mPreviewEmoji)
mPreviewEmoji->setLabel(text);
return;
}
onEmojiEmpty();
}
void LLFloaterEmojiPicker::onEmojiEmpty()
{
mSelectedEmojiIndex = 0;
if (mPreviewEmoji)
mPreviewEmoji->setLabel(LLUIString());
}
void LLFloaterEmojiPicker::onEmojiPick()
{
if (mEmojis && mEmojiPickCallback)
{
if (LLEmojiScrollListItem* item = dynamic_cast<LLEmojiScrollListItem*>(mEmojis->getFirstSelected()))
{
mEmojiPickCallback(item->getEmoji());
closeFloater();
}
}
}
@ -128,16 +261,36 @@ void LLFloaterEmojiPicker::onSelect()
// virtual
BOOL LLFloaterEmojiPicker::handleKeyHere(KEY key, MASK mask)
{
if (key == KEY_RETURN && mask == MASK_NONE)
if (mask == MASK_NONE)
{
onSelect();
return TRUE;
}
else if (key == KEY_ESCAPE && mask == MASK_NONE)
{
closeFloater();
return TRUE;
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();
}

View File

@ -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

View File

@ -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;

View File

@ -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;

View File

@ -25,7 +25,7 @@
*/
#include "llviewerprecompiledheaders.h"
#include "llviewerchat.h"
#include "llviewerchat.h"
// newview includes
#include "llagent.h" // gAgent

View File

@ -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>