diff options
| -rw-r--r-- | indra/llcommon/llstring.h | 15 | ||||
| -rw-r--r-- | indra/llui/llbutton.cpp | 23 | ||||
| -rw-r--r-- | indra/llui/llbutton.h | 5 | ||||
| -rw-r--r-- | indra/llui/llemojidictionary.cpp | 10 | ||||
| -rw-r--r-- | indra/llui/llemojidictionary.h | 14 | ||||
| -rw-r--r-- | indra/llui/llfloater.cpp | 18 | ||||
| -rw-r--r-- | indra/llui/llfloater.h | 4 | ||||
| -rw-r--r-- | indra/llui/llscrolllistctrl.cpp | 4 | ||||
| -rw-r--r-- | indra/llui/llscrolllistctrl.h | 30 | ||||
| -rw-r--r-- | indra/newview/llfloateravatarpicker.cpp | 1 | ||||
| -rw-r--r-- | indra/newview/llfloateremojipicker.cpp | 203 | ||||
| -rw-r--r-- | indra/newview/llfloateremojipicker.h | 36 | ||||
| -rw-r--r-- | indra/newview/llfloaterimsessiontab.cpp | 13 | ||||
| -rw-r--r-- | indra/newview/llfloaterimsessiontab.h | 3 | ||||
| -rw-r--r-- | indra/newview/llviewerchat.cpp | 2 | ||||
| -rw-r--r-- | indra/newview/skins/default/xui/en/floater_emoji_picker.xml | 95 | 
16 files changed, 368 insertions, 108 deletions
diff --git a/indra/llcommon/llstring.h b/indra/llcommon/llstring.h index 9afbea9afe..bdb90335e1 100644 --- a/indra/llcommon/llstring.h +++ b/indra/llcommon/llstring.h @@ -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); @@ -1596,6 +1597,20 @@ void LLStringUtilBase<T>::replaceTabsWithSpaces( string_type& str, size_type spa  }  //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)  { diff --git a/indra/llui/llbutton.cpp b/indra/llui/llbutton.cpp index 3354cb2db3..aeeff0b36f 100644 --- a/indra/llui/llbutton.cpp +++ b/indra/llui/llbutton.cpp @@ -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) diff --git a/indra/llui/llbutton.h b/indra/llui/llbutton.h index ccd31e90c0..257159f64f 100644 --- a/indra/llui/llbutton.h +++ b/indra/llui/llbutton.h @@ -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; diff --git a/indra/llui/llemojidictionary.cpp b/indra/llui/llemojidictionary.cpp index b70a9b2e7a..d306407484 100644 --- a/indra/llui/llemojidictionary.cpp +++ b/indra/llui/llemojidictionary.cpp @@ -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()); +	}  }  // ============================================================================ diff --git a/indra/llui/llemojidictionary.h b/indra/llui/llemojidictionary.h index adc22ced58..cbb0ac577d 100644 --- a/indra/llui/llemojidictionary.h +++ b/indra/llui/llemojidictionary.h @@ -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;  };  // ============================================================================ diff --git a/indra/llui/llfloater.cpp b/indra/llui/llfloater.cpp index 346e89a101..98895d56dd 100644 --- a/indra/llui/llfloater.cpp +++ b/indra/llui/llfloater.cpp @@ -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);  	}  } diff --git a/indra/llui/llfloater.h b/indra/llui/llfloater.h index 282f7a80ac..3699629ef8 100644 --- a/indra/llui/llfloater.h +++ b/indra/llui/llfloater.h @@ -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; } diff --git a/indra/llui/llscrolllistctrl.cpp b/indra/llui/llscrolllistctrl.cpp index 2a6e8a6b76..f982dc99e8 100644 --- a/indra/llui/llscrolllistctrl.cpp +++ b/indra/llui/llscrolllistctrl.cpp @@ -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;  	} diff --git a/indra/llui/llscrolllistctrl.h b/indra/llui/llscrolllistctrl.h index 73b4fb036a..326589a329 100644 --- a/indra/llui/llscrolllistctrl.h +++ b/indra/llui/llscrolllistctrl.h @@ -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); diff --git a/indra/newview/llfloateravatarpicker.cpp b/indra/newview/llfloateravatarpicker.cpp index 2422596f60..42ef41017a 100644 --- a/indra/newview/llfloateravatarpicker.cpp +++ b/indra/newview/llfloateravatarpicker.cpp @@ -741,7 +741,6 @@ void LLFloaterAvatarPicker::processResponse(const LLUUID& query_id, const LLSD&  	}  } -//static  void LLFloaterAvatarPicker::editKeystroke(LLLineEditor* caller, void* user_data)  {  	getChildView("Find")->setEnabled(caller->getText().size() > 0); diff --git a/indra/newview/llfloateremojipicker.cpp b/indra/newview/llfloateremojipicker.cpp index a63a9fac4f..5efd2a24c0 100644 --- a/indra/newview/llfloateremojipicker.cpp +++ b/indra/newview/llfloateremojipicker.cpp @@ -27,10 +27,18 @@  #include "llfloateremojipicker.h" +#include "llcombobox.h" +#include "llemojidictionary.h"  #include "llfloaterreg.h" +#include "lllineeditor.h"  #include "llscrolllistctrl.h"  #include "llscrolllistitem.h" -#include "llemojidictionary.h" +#include "lltextbox.h"  +#include "llviewerchat.h"  + +std::string LLFloaterEmojiPicker::mSelectedCategory; +std::string LLFloaterEmojiPicker::mSearchPattern; +int LLFloaterEmojiPicker::mSelectedEmojiIndex;  class LLEmojiScrollListItem : public LLScrollListItem  { @@ -69,17 +77,18 @@ LLFloaterEmojiPicker* LLFloaterEmojiPicker::getInstance()  	return floater;  } -LLFloaterEmojiPicker* LLFloaterEmojiPicker::showInstance(select_callback_t callback) +LLFloaterEmojiPicker* LLFloaterEmojiPicker::showInstance(pick_callback_t pick_callback, close_callback_t close_callback)  {  	LLFloaterEmojiPicker* floater = getInstance();  	if (LLFloaterEmojiPicker* floater = getInstance()) -		floater->show(callback); +		floater->show(pick_callback, close_callback);  	return floater;  } -void LLFloaterEmojiPicker::show(select_callback_t callback) +void LLFloaterEmojiPicker::show(pick_callback_t pick_callback, close_callback_t close_callback)  { -	mSelectCallback = callback; +	mEmojiPickCallback = pick_callback; +	mFloaterCloseCallback = close_callback;  	openFloater(mKey);  	setFocus(TRUE);  } @@ -91,19 +100,41 @@ LLFloaterEmojiPicker::LLFloaterEmojiPicker(const LLSD& key)  BOOL LLFloaterEmojiPicker::postBuild()  { -	if ((mEmojis = getChild<LLScrollListCtrl>("Emojis"))) +	// Should be initialized first +	if ((mPreviewEmoji = getChild<LLButton>("PreviewEmoji")))  	{ -		mEmojis->setDoubleClickCallback(boost::bind(&LLFloaterEmojiPicker::onSelect, this)); - -		mEmojis->clearRows(); +		mPreviewEmoji->setClickedCallback(boost::bind(&LLFloaterEmojiPicker::onPreviewEmojiClick, this)); +	} -		const std::map<llwchar, const LLEmojiDescriptor*>& emoji2Descr = LLEmojiDictionary::instance().getEmoji2Descr(); -		for (const std::pair<const llwchar, const LLEmojiDescriptor*>& it : emoji2Descr) +	if ((mCategory = getChild<LLComboBox>("Category"))) +	{ +		mCategory->setCommitCallback(boost::bind(&LLFloaterEmojiPicker::onCategoryCommit, this)); +		mCategory->setLabel(LLStringExplicit("Choose a category")); +		const auto& cat2Descrs = LLEmojiDictionary::instance().getCategory2Descrs(); +		mCategory->clearRows(); +		for (const auto& item : cat2Descrs)  		{ -			LLScrollListItem::Params params; -			params.columns.add().column("name").value(it.second->Name); -			mEmojis->addRow(new LLEmojiScrollListItem(it.first, params), params); +			std::string value = item.first; +			std::string name = value; +			LLStringUtil::capitalize(name); +			mCategory->add(name, value);  		} +		mCategory->setSelectedByValue(mSelectedCategory, true); +	} + +	if ((mSearch = getChild<LLLineEditor>("Search"))) +	{ +		mSearch->setKeystrokeCallback(boost::bind(&LLFloaterEmojiPicker::onSearchKeystroke, this, _1, _2), NULL); +		mSearch->setLabel(LLStringExplicit("Type to search an emoji")); +		mSearch->setFont(LLViewerChat::getChatFont()); +		mSearch->setText(mSearchPattern); +	} + +	if ((mEmojis = getChild<LLScrollListCtrl>("Emojis"))) +	{ +		mEmojis->setCommitCallback(boost::bind(&LLFloaterEmojiPicker::onEmojiSelect, this)); +		mEmojis->setDoubleClickCallback(boost::bind(&LLFloaterEmojiPicker::onEmojiPick, this)); +		fillEmojis();  	}  	return TRUE; @@ -114,30 +145,152 @@ LLFloaterEmojiPicker::~LLFloaterEmojiPicker()  	gFocusMgr.releaseFocusIfNeeded( this );  } -void LLFloaterEmojiPicker::onSelect() +void LLFloaterEmojiPicker::fillEmojis() +{ +	mEmojis->clearRows(); + +	const auto& emoji2Descr = LLEmojiDictionary::instance().getEmoji2Descr(); +	for (const std::pair<const llwchar, const LLEmojiDescriptor*>& it : emoji2Descr) +	{ +		const LLEmojiDescriptor* descr = it.second; + +		if (!mSelectedCategory.empty() && !matchesCategory(descr)) +			continue; + +		if (!mSearchPattern.empty() && !matchesPattern(descr)) +			continue; + +		LLScrollListItem::Params params; +		params.columns.add().column("name").value(descr->Name); +		mEmojis->addRow(new LLEmojiScrollListItem(it.first, params), params); +	} + +	if (mEmojis->getItemCount()) +	{ +		if (mSelectedEmojiIndex > 0 && mSelectedEmojiIndex < mEmojis->getItemCount()) +			mEmojis->selectNthItem(mSelectedEmojiIndex); +		else +			mEmojis->selectFirstItem(); + +		mEmojis->scrollToShowSelected(); +	} +	else +	{ +		onEmojiEmpty(); +	} +} + +bool LLFloaterEmojiPicker::matchesCategory(const LLEmojiDescriptor* descr) +{ +	return std::find(descr->Categories.begin(), descr->Categories.end(), mSelectedCategory) != descr->Categories.end(); +} + +bool LLFloaterEmojiPicker::matchesPattern(const LLEmojiDescriptor* descr) +{ +	if (descr->Name.find(mSearchPattern) != std::string::npos) +		return true; +	for (auto shortCode : descr->ShortCodes) +		if (shortCode.find(mSearchPattern) != std::string::npos) +			return true; +	for (auto category : descr->Categories) +		if (category.find(mSearchPattern) != std::string::npos) +			return true; +	return false; +} + +void LLFloaterEmojiPicker::onCategoryCommit() +{ +	mSelectedCategory = mCategory->getSelectedValue().asString(); +	mSelectedEmojiIndex = 0; +	fillEmojis(); +} + +void LLFloaterEmojiPicker::onSearchKeystroke(LLLineEditor* caller, void* user_data)  { -	if (mEmojis && mSelectCallback) +	mSearchPattern = mSearch->getText(); +	mSelectedEmojiIndex = 0; +	fillEmojis(); +} + +void LLFloaterEmojiPicker::onPreviewEmojiClick() +{ +	if (mEmojis && mEmojiPickCallback)  	{  		if (LLEmojiScrollListItem* item = dynamic_cast<LLEmojiScrollListItem*>(mEmojis->getFirstSelected()))  		{ -			mSelectCallback(item->getEmoji()); +			mEmojiPickCallback(item->getEmoji());  		}  	}  } -// virtual -BOOL LLFloaterEmojiPicker::handleKeyHere(KEY key, MASK mask) +void LLFloaterEmojiPicker::onEmojiSelect()  { -	if (key == KEY_RETURN && mask == MASK_NONE) +	const LLEmojiScrollListItem* item = dynamic_cast<LLEmojiScrollListItem*>(mEmojis->getFirstSelected()); +	if (item)  	{ -		onSelect(); -		return TRUE; +		mSelectedEmojiIndex = mEmojis->getFirstSelectedIndex(); +		LLUIString text; +		text.insert(0, LLWString(1, item->getEmoji())); +		if (mPreviewEmoji) +			mPreviewEmoji->setLabel(text); +		return;  	} -	else if (key == KEY_ESCAPE && mask == MASK_NONE) + +	onEmojiEmpty(); +} + +void LLFloaterEmojiPicker::onEmojiEmpty() +{ +	mSelectedEmojiIndex = 0; +	if (mPreviewEmoji) +		mPreviewEmoji->setLabel(LLUIString()); +} + +void LLFloaterEmojiPicker::onEmojiPick() +{ +	if (mEmojis && mEmojiPickCallback)  	{ -		closeFloater(); -		return TRUE; +		if (LLEmojiScrollListItem* item = dynamic_cast<LLEmojiScrollListItem*>(mEmojis->getFirstSelected())) +		{ +			mEmojiPickCallback(item->getEmoji()); +			closeFloater(); +		} +	} +} + +// virtual +BOOL LLFloaterEmojiPicker::handleKeyHere(KEY key, MASK mask) +{ +	if (mask == MASK_NONE) +	{ +		switch (key) +		{ +		case KEY_RETURN: +			if (mCategory->hasFocus()) +				break; +			onEmojiPick(); +			return TRUE; +		case KEY_ESCAPE: +			closeFloater(); +			return TRUE; +		case KEY_UP: +			mEmojis->selectPrevItem(); +			mEmojis->scrollToShowSelected(); +			return TRUE; +		case KEY_DOWN: +			mEmojis->selectNextItem(); +			mEmojis->scrollToShowSelected(); +			return TRUE; +		}  	}  	return LLFloater::handleKeyHere(key, mask);  } + +// virtual +void LLFloaterEmojiPicker::closeFloater(bool app_quitting) +{ +	LLFloater::closeFloater(app_quitting); +	if (mFloaterCloseCallback) +		mFloaterCloseCallback(); +} diff --git a/indra/newview/llfloateremojipicker.h b/indra/newview/llfloateremojipicker.h index 9b442064d0..01335bbb5b 100644 --- a/indra/newview/llfloateremojipicker.h +++ b/indra/newview/llfloateremojipicker.h @@ -29,31 +29,53 @@  #include "llfloater.h" +struct LLEmojiDescriptor; +  class LLFloaterEmojiPicker : public LLFloater  {  public:  	// The callback function will be called with an emoji char. -	typedef boost::function<void (llwchar)> select_callback_t; +	typedef boost::function<void (llwchar)> pick_callback_t; +	typedef boost::function<void ()> close_callback_t;  	// Call this to select an emoji.  	static LLFloaterEmojiPicker* getInstance(); -	static LLFloaterEmojiPicker* showInstance(select_callback_t callback); +	static LLFloaterEmojiPicker* showInstance(pick_callback_t pick_callback = nullptr, close_callback_t close_callback = nullptr);  	LLFloaterEmojiPicker(const LLSD& key);  	virtual ~LLFloaterEmojiPicker();  	virtual	BOOL postBuild(); -	void show(select_callback_t callback); +	void show(pick_callback_t pick_callback = nullptr, close_callback_t close_callback = nullptr); + +	virtual void closeFloater(bool app_quitting = false);  private: -	void onSelect(); +	void fillEmojis(); +	bool matchesCategory(const LLEmojiDescriptor* descr); +	bool matchesPattern(const LLEmojiDescriptor* descr); + +	void onCategoryCommit(); +	void onSearchKeystroke(class LLLineEditor* caller, void* user_data); +	void onPreviewEmojiClick(); +	void onEmojiSelect(); +	void onEmojiEmpty(); +	void onEmojiPick();  	virtual BOOL handleKeyHere(KEY key, MASK mask); -	class LLScrollListCtrl* mEmojis; -	select_callback_t mSelectCallback; -	std::string mEmojiName; +	class LLComboBox* mCategory { nullptr }; +	class LLLineEditor* mSearch { nullptr }; +	class LLScrollListCtrl* mEmojis { nullptr }; +	class LLButton* mPreviewEmoji { nullptr }; + +	pick_callback_t mEmojiPickCallback; +	close_callback_t mFloaterCloseCallback; + +	static std::string mSelectedCategory; +	static std::string mSearchPattern; +	static int mSelectedEmojiIndex;  };  #endif diff --git a/indra/newview/llfloaterimsessiontab.cpp b/indra/newview/llfloaterimsessiontab.cpp index 3d9751dd35..0571a0d855 100644 --- a/indra/newview/llfloaterimsessiontab.cpp +++ b/indra/newview/llfloaterimsessiontab.cpp @@ -434,10 +434,12 @@ void LLFloaterIMSessionTab::onEmojiPanelBtnClicked(LLFloaterIMSessionTab* self)  	{  		if (!picker->isShown())  		{ -			picker->show(boost::bind(&LLFloaterIMSessionTab::onEmojiSelected, self, _1)); +			picker->show( +				boost::bind(&LLFloaterIMSessionTab::onEmojiPicked, self, _1), +				boost::bind(&LLFloaterIMSessionTab::onEmojiPickerClosed, self));  			if (LLFloater* root_floater = gFloaterView->getParentFloater(self))  			{ -				root_floater->addDependentFloater(picker); +				root_floater->addDependentFloater(picker, TRUE, TRUE);  			}  		}  		else @@ -447,11 +449,16 @@ void LLFloaterIMSessionTab::onEmojiPanelBtnClicked(LLFloaterIMSessionTab* self)  	}  } -void LLFloaterIMSessionTab::onEmojiSelected(llwchar emoji) +void LLFloaterIMSessionTab::onEmojiPicked(llwchar emoji)  {  	mInputEditor->insertEmoji(emoji);  } +void LLFloaterIMSessionTab::onEmojiPickerClosed() +{ +	mInputEditor->setFocus(TRUE); +} +  std::string LLFloaterIMSessionTab::appendTime()  {  	time_t utc_time; diff --git a/indra/newview/llfloaterimsessiontab.h b/indra/newview/llfloaterimsessiontab.h index cd5065420d..3dcb767aa6 100644 --- a/indra/newview/llfloaterimsessiontab.h +++ b/indra/newview/llfloaterimsessiontab.h @@ -208,7 +208,8 @@ private:  	void onInputEditorClicked();  	static void onEmojiPanelBtnClicked(LLFloaterIMSessionTab* self); -	void onEmojiSelected(llwchar emoji); +	void onEmojiPicked(llwchar emoji); +	void onEmojiPickerClosed();  	bool checkIfTornOff();      bool mIsHostAttached; diff --git a/indra/newview/llviewerchat.cpp b/indra/newview/llviewerchat.cpp index 1c3c547bc1..0d2d62fd77 100644 --- a/indra/newview/llviewerchat.cpp +++ b/indra/newview/llviewerchat.cpp @@ -25,7 +25,7 @@   */  #include "llviewerprecompiledheaders.h" -#include "llviewerchat.h"  +#include "llviewerchat.h"  // newview includes  #include "llagent.h" 	// gAgent		 diff --git a/indra/newview/skins/default/xui/en/floater_emoji_picker.xml b/indra/newview/skins/default/xui/en/floater_emoji_picker.xml index a3e504cc31..831f7b6582 100644 --- a/indra/newview/skins/default/xui/en/floater_emoji_picker.xml +++ b/indra/newview/skins/default/xui/en/floater_emoji_picker.xml @@ -1,39 +1,64 @@  <?xml version="1.0" encoding="utf-8" standalone="yes" ?>  <floater -  name="emojipicker" -  title="CHOOSE EMOJI" -  help_topic="emojipicker" -  positioning="cascading" -  legacy_header_height="10" -  can_resize="false" -  layout="topleft" -  height="419" -  width="200"> -    <panel -      label="Emojis" -      name="EmojiPanel" -      help_topic="emojipicker" +    name="emojipicker" +    title="CHOOSE EMOJI" +    help_topic="emojipicker" +    positioning="cascading" +    legacy_header_height="0" +    can_resize="true" +    layout="topleft" +    height="400" +    width="200"> +  <line_editor +      name="Search" +      layout="bottomleft" +      follows="bottom|left|right" +      text_tentative_color="TextFgTentativeColor" +      max_length_bytes="63" +      left_pad="5" +	  bottom="14" +	  left="34" +      height="29" +      width="162" /> +  <button +	  name="PreviewEmoji" +      layout="bottomleft" +      follows="bottom|left" +	  font="EmojiHuge" +	  use_font_color="true" +	  bottom="14" +	  left="0" +	  height="29" +	  width="29" /> +  <scroll_list +      name="Emojis"        layout="topleft" -      top="4" -      left="2" -      height="410" -      width="196"> -      <scroll_list -        draw_heading="true" -        heading_height="28" -        follows="all" -        layout="topleft" -        name="Emojis" -        sort_column="0" -		height="410"> -        <columns -          label="Look" -          name="look" -          width="40" /> -		<columns -          label="Name" -          name="name" -          width="150" /> -	  </scroll_list> -    </panel> +      follows="all" +      sort_column="0" +	  max_chars="63" +	  commit_on_selection_change="true" +      draw_heading="true" +      heading_height="25" +	  row_padding="0" +	  top="25" +	  height="330" +	  width="200"> +    <columns +        label="Look" +        name="look" +        width="40" /> +	<columns +        label="Name" +        name="name" /> +  </scroll_list> +  <combo_box +      name="Category" +      layout="topleft" +      follows="top|left|right" +	  allow_text_entry="true" +      left_pad="4" +	  top="0" +	  left="4" +      height="27" +      width="192" />  </floater>  | 
