diff options
| author | Kitty Barnett <develop@catznip.com> | 2022-10-23 16:10:06 +0200 | 
|---|---|---|
| committer | Kitty Barnett <develop@catznip.com> | 2022-10-23 16:28:00 +0200 | 
| commit | d95571cf7cd319e17338bc509d46ab5eab4eb968 (patch) | |
| tree | 4b3e5e79ef6d294affb8ea92384224970208e094 | |
| parent | 8694f055b64eb7ce13897e49afe73c4d3295a29a (diff) | |
Add mini emoji (auto-)complete helper
| -rw-r--r-- | indra/newview/CMakeLists.txt | 2 | ||||
| -rw-r--r-- | indra/newview/llpanelemojicomplete.cpp | 210 | ||||
| -rw-r--r-- | indra/newview/llpanelemojicomplete.h | 99 | ||||
| -rw-r--r-- | indra/newview/llviewerfloaterreg.cpp | 2 | ||||
| -rw-r--r-- | indra/newview/skins/default/xui/en/floater_emoji_complete.xml | 26 | ||||
| -rw-r--r-- | indra/newview/skins/default/xui/en/widgets/emoji_complete.xml | 7 | 
6 files changed, 346 insertions, 0 deletions
diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index 8d902ce618..0bb1814322 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -441,6 +441,7 @@ set(viewer_SOURCE_FILES      llpaneleditsky.cpp      llpaneleditwater.cpp      llpaneleditwearable.cpp +	llpanelemojicomplete.cpp      llpanelenvironment.cpp      llpanelexperiencelisteditor.cpp      llpanelexperiencelog.cpp @@ -1072,6 +1073,7 @@ set(viewer_HEADER_FILES      llpaneleditsky.h      llpaneleditwater.h      llpaneleditwearable.h +	llpanelemojicomplete.h      llpanelenvironment.h      llpanelexperiencelisteditor.h      llpanelexperiencelog.h diff --git a/indra/newview/llpanelemojicomplete.cpp b/indra/newview/llpanelemojicomplete.cpp new file mode 100644 index 0000000000..e1d80b62e2 --- /dev/null +++ b/indra/newview/llpanelemojicomplete.cpp @@ -0,0 +1,210 @@ +/** +* @file llpanelemojicomplete.h +* @brief Header file for LLPanelEmojiComplete +* +* $LicenseInfo:firstyear=2012&license=lgpl$ +* Second Life Viewer Source Code +* Copyright (C) 2011, Linden Research, Inc. +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public +* License as published by the Free Software Foundation; +* version 2.1 of the License only. +* +* This library is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public +* License along with this library; if not, write to the Free Software +* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA +* +* Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA +* $/LicenseInfo$ +*/ + +#include "llviewerprecompiledheaders.h" + +#include "llemojidictionary.h" +#include "llpanelemojicomplete.h" +#include "lluictrlfactory.h" + +constexpr U32 MIN_MOUSE_MOVE_DELTA = 4; + +// ============================================================================ +// LLPanelEmojiComplete +// + +static LLDefaultChildRegistry::Register<LLPanelEmojiComplete> r("emoji_complete"); + +LLPanelEmojiComplete::Params::Params() +	: selected_image("selected_image") +{ +} + +LLPanelEmojiComplete::LLPanelEmojiComplete(const LLPanelEmojiComplete::Params& p) +	: LLUICtrl(p) +	, mSelectedImage(p.selected_image) +{ +	setFont(p.font); +} + +LLPanelEmojiComplete::~LLPanelEmojiComplete() +{ +} + +void LLPanelEmojiComplete::draw() +{ +	if (!mEmojis.empty()) +	{ +		const S32 centerY = mRenderRect.getCenterY(); +		const size_t firstVisibleIdx = mScrollPos, lastVisibleIdx = llmin(mScrollPos + mVisibleEmojis, mEmojis.size()) - 1; + +		if (mCurSelected >= firstVisibleIdx && mCurSelected <= lastVisibleIdx) +		{ +			const S32 emoji_left = mRenderRect.mLeft + (mCurSelected - firstVisibleIdx) * mEmojiWidth; +			const S32 emoji_height = mFont->getLineHeight() + mPadding; +			mSelectedImage->draw(emoji_left, centerY - emoji_height / 2, mEmojiWidth, emoji_height); +		} + +		U32 left = mRenderRect.mLeft + mPadding; +		for (U32 curIdx = firstVisibleIdx; curIdx <= lastVisibleIdx; curIdx++) +		{ +			mFont->render( +				mEmojis, curIdx, +				left, centerY, +				LLColor4::white, LLFontGL::LEFT, LLFontGL::VCENTER, LLFontGL::NORMAL, LLFontGL::DROP_SHADOW_SOFT, +				1, S32_MAX, nullptr, false, true); +			left += mEmojiWidth; +		} +	} +} + +BOOL LLPanelEmojiComplete::handleHover(S32 x, S32 y, MASK mask) +{ +	LLVector2 curHover(x, y); +	if ((mLastHover - curHover).lengthSquared() > MIN_MOUSE_MOVE_DELTA) +	{ +		mCurSelected = posToIndex(x, y); +		mLastHover = curHover; +	} + +	return TRUE; +} + +BOOL LLPanelEmojiComplete::handleKey(KEY key, MASK mask, BOOL called_from_parent) +{ +	if (MASK_NONE == mask) +	{ +		bool handled = false; +		switch (key) +		{ +			case KEY_LEFT: +			case KEY_UP: +				selectPrevious(); +				handled = true; +				break; +			case KEY_RIGHT: +			case KEY_DOWN: +				selectNext(); +				handled = true; +				break; +		} +		return handled; +	} + +	return false; +} + +void LLPanelEmojiComplete::reshape(S32 width, S32 height, BOOL called_from_parent) +{ +	LLUICtrl::reshape(width, height, called_from_parent); +	updateConstraints(); +} + +void LLPanelEmojiComplete::setEmojiHint(const std::string& hint) +{ +	mEmojis = LLEmojiDictionary::instance().findMatchingEmojis(hint); +	mScrollPos = llmin(mScrollPos, mEmojis.size()); +	updateConstraints(); +} + +size_t LLPanelEmojiComplete::posToIndex(S32 x, S32 y) const +{ +	if (mRenderRect.pointInRect(x, y)) +	{ +		return llmin((size_t)x / mEmojiWidth, mEmojis.size() - 1); +	} +	return npos; +} + +void LLPanelEmojiComplete::select(size_t emoji_idx) +{ +	mCurSelected = llclamp<size_t>(emoji_idx, 0, mEmojis.size()); +	updateScrollPos(); +} + +void LLPanelEmojiComplete::selectNext() +{ +	select(mCurSelected + 1 < mEmojis.size() ? mCurSelected + 1 : 0); +} + +void LLPanelEmojiComplete::selectPrevious() +{ +	select(mCurSelected - 1 >= 0 ? mCurSelected - 1 : mEmojis.size() - 1); +} + +void LLPanelEmojiComplete::setFont(const LLFontGL* fontp) +{ +	mFont = fontp; +	updateConstraints(); +} + +void LLPanelEmojiComplete::updateConstraints() +{ +	const S32 ctrlWidth = getLocalRect().getWidth(); + +	mEmojiWidth = mFont->getWidthF32(u8"\U0001F431") + mPadding * 2; +	mVisibleEmojis = ctrlWidth / mEmojiWidth; +	mRenderRect = getLocalRect().stretch((ctrlWidth - mVisibleEmojis * mEmojiWidth) / -2, 0); + +	updateScrollPos(); +} + +void LLPanelEmojiComplete::updateScrollPos() +{ +	const size_t cntEmoji = mEmojis.size(); +	if (0 == cntEmoji || cntEmoji < mVisibleEmojis || 0 == mCurSelected) +	{ +		mScrollPos = 0; +	} +	else if (cntEmoji - 1 == mCurSelected) +	{ +		mScrollPos = mCurSelected - mVisibleEmojis + 1; +	} +	else +	{ +		mScrollPos = mCurSelected - ((float)mCurSelected / (cntEmoji - 2) * (mVisibleEmojis - 2)); +	} +} + +// ============================================================================ +// LLFloaterEmojiComplete +// + +LLFloaterEmojiComplete::LLFloaterEmojiComplete(const LLSD& sdKey) +	: LLFloater(sdKey) +{ +	// This floater should hover on top of our dependent (with the dependent having the focus) +	setFocusStealsFrontmost(false); +	setAutoFocus(false); +	setBackgroundVisible(false); +} + +void LLFloaterEmojiComplete::onOpen(const LLSD& key) +{ +	findChild<LLPanelEmojiComplete>("emoji_complete_ctrl")->setEmojiHint(key["hint"].asString()); +} + +// ============================================================================ diff --git a/indra/newview/llpanelemojicomplete.h b/indra/newview/llpanelemojicomplete.h new file mode 100644 index 0000000000..85b0609ae9 --- /dev/null +++ b/indra/newview/llpanelemojicomplete.h @@ -0,0 +1,99 @@ +/** +* @file llpanelemojicomplete.h +* @brief Header file for LLPanelEmojiComplete +* +* $LicenseInfo:firstyear=2014&license=viewerlgpl$ +* Second Life Viewer Source Code +* Copyright (C) 2014, Linden Research, Inc. +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public +* License as published by the Free Software Foundation; +* version 2.1 of the License only. +* +* This library is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public +* License along with this library; if not, write to the Free Software +* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA +* +* Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA +* $/LicenseInfo$ +*/ + +#pragma once + +#include "llfloater.h" +#include "lluictrl.h" + +// ============================================================================ +// LLPanelEmojiComplete +// + +class LLPanelEmojiComplete : public LLUICtrl +{ +	friend class LLUICtrlFactory; +public: +	struct Params : public LLInitParam::Block<Params, LLUICtrl::Params> +	{ +		Optional<LLUIImage*> selected_image; + +		Params(); +	}; + +protected: +	LLPanelEmojiComplete(const LLPanelEmojiComplete::Params&); +public: +	virtual ~LLPanelEmojiComplete(); + +	void draw() override; +	BOOL handleHover(S32 x, S32 y, MASK mask) override; +	BOOL handleKey(KEY key, MASK mask, BOOL called_from_parent) override; +	void reshape(S32 width, S32 height, BOOL called_from_parent) override; + +public: +	void setEmojiHint(const std::string& hint); +protected: +	size_t posToIndex(S32 x, S32 y) const; +	void select(size_t emoji_idx); +	void selectNext(); +	void selectPrevious(); +	void setFont(const LLFontGL* fontp); +	void updateConstraints(); +	void updateScrollPos(); + +protected: +	static constexpr auto npos = std::numeric_limits<size_t>::max(); + +	const LLFontGL* mFont; +	U16             mEmojiWidth = 0; +	LLUIImagePtr	mSelectedImage; + +	LLWString       mEmojis; +	U16             mVisibleEmojis = 0; +	size_t          mFirstVisible = 0; +	size_t          mScrollPos = 0; +	size_t          mCurSelected = 0; +	LLVector2       mLastHover; + +	S32             mPadding = 8; +	LLRect          mRenderRect; +}; + +// ============================================================================ +// LLFloaterEmojiComplete +// + +class LLFloaterEmojiComplete : public LLFloater +{ +public: +	LLFloaterEmojiComplete(const LLSD& sdKey); + +public: +	void onOpen(const LLSD& key) override; +}; + +// ============================================================================ diff --git a/indra/newview/llviewerfloaterreg.cpp b/indra/newview/llviewerfloaterreg.cpp index 5a05f89758..a54b91030e 100644 --- a/indra/newview/llviewerfloaterreg.cpp +++ b/indra/newview/llviewerfloaterreg.cpp @@ -155,6 +155,7 @@  #include "llfloaterimnearbychat.h"  #include "llpanelblockedlist.h"  #include "llpanelclassified.h" +#include "llpanelemojicomplete.h"  #include "llpreviewanim.h"  #include "llpreviewgesture.h"  #include "llpreviewnotecard.h" @@ -229,6 +230,7 @@ void LLViewerFloaterReg::registerFloaters()  	LLFloaterReg::add("delete_pref_preset", "floater_delete_pref_preset.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterDeletePrefPreset>);  	LLFloaterReg::add("destinations", "floater_destinations.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterDestinations>); +	LLFloaterReg::add("emoji_complete", "floater_emoji_complete.xml", &LLFloaterReg::build<LLFloaterEmojiComplete>);  	LLFloaterReg::add("env_post_process", "floater_post_process.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterPostProcess>);      LLFloaterReg::add("env_fixed_environmentent_water", "floater_fixedenvironment.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterFixedEnvironmentWater>); diff --git a/indra/newview/skins/default/xui/en/floater_emoji_complete.xml b/indra/newview/skins/default/xui/en/floater_emoji_complete.xml new file mode 100644 index 0000000000..eb666bc32c --- /dev/null +++ b/indra/newview/skins/default/xui/en/floater_emoji_complete.xml @@ -0,0 +1,26 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes" ?> +<floater + can_close="false" + can_dock="false" + can_drag_on_left="false" + can_minimize="false" + can_resize="false" + can_tear_off="false" + header_height="0" + layout="topleft" + legacy_header_height="0" + height="40" + single_instance="true" + width="240" + > +    <emoji_complete +     height="30" +     follows="top|left" +     layout="topleft" +     left="5" +     top="5" +     width="230" +     name="emoji_complete_ctrl" +     > +    </emoji_complete> +</floater> diff --git a/indra/newview/skins/default/xui/en/widgets/emoji_complete.xml b/indra/newview/skins/default/xui/en/widgets/emoji_complete.xml new file mode 100644 index 0000000000..f35105ff7e --- /dev/null +++ b/indra/newview/skins/default/xui/en/widgets/emoji_complete.xml @@ -0,0 +1,7 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes" ?> +<emoji_complete +  font="EmojiHuge" +  hover_image="ListItem_Over" +  selected_image="ListItem_Select" +  > +</emoji_complete>  | 
