Merge pull request #183 from secondlife/SL-19575a
SL-19575 LLFloaterEmojiPicker - Add filter by categorymeow-7.2.2
commit
a7eef57c1f
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
};
|
||||
|
||||
// ============================================================================
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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; }
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@
|
|||
*/
|
||||
|
||||
#include "llviewerprecompiledheaders.h"
|
||||
#include "llviewerchat.h"
|
||||
#include "llviewerchat.h"
|
||||
|
||||
// newview includes
|
||||
#include "llagent.h" // gAgent
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
Loading…
Reference in New Issue