summaryrefslogtreecommitdiff
path: root/indra/newview/llpanelemojicomplete.cpp
diff options
context:
space:
mode:
authorAlexander Gavriliuk <alexandrgproductengine@lindenlab.com>2023-10-04 22:30:48 +0200
committerAlexander Gavriliuk <alexandrgproductengine@lindenlab.com>2023-10-05 12:10:34 +0200
commit9f8763cae1ccb3577a2cd148ffc5cee564a2df65 (patch)
tree0a9f2bfe2cc449d301821ec1152bc8aeacdd11a4 /indra/newview/llpanelemojicomplete.cpp
parent66aee79e3e9ca9b45e7c61d843caadb8469580e5 (diff)
SL-20402 Emoji Completion floater - use vertical scrollbar when needed
Diffstat (limited to 'indra/newview/llpanelemojicomplete.cpp')
-rw-r--r--indra/newview/llpanelemojicomplete.cpp449
1 files changed, 274 insertions, 175 deletions
diff --git a/indra/newview/llpanelemojicomplete.cpp b/indra/newview/llpanelemojicomplete.cpp
index 732531691b..b03f16899e 100644
--- a/indra/newview/llpanelemojicomplete.cpp
+++ b/indra/newview/llpanelemojicomplete.cpp
@@ -29,10 +29,12 @@
#include "llemojidictionary.h"
#include "llemojihelper.h"
#include "llpanelemojicomplete.h"
+#include "llscrollbar.h"
#include "lluictrlfactory.h"
constexpr U32 MIN_MOUSE_MOVE_DELTA = 4;
constexpr U32 MIN_SHORT_CODE_WIDTH = 100;
+constexpr U32 DEF_PADDING = 8;
// ============================================================================
// LLPanelEmojiComplete
@@ -41,26 +43,35 @@ constexpr U32 MIN_SHORT_CODE_WIDTH = 100;
static LLDefaultChildRegistry::Register<LLPanelEmojiComplete> r("emoji_complete");
LLPanelEmojiComplete::Params::Params()
- : autosize("autosize")
- , noscroll("noscroll")
- , vertical("vertical")
- , max_emoji("max_emoji")
- , padding("padding")
- , selected_image("selected_image")
+ : autosize("autosize")
+ , noscroll("noscroll")
+ , vertical("vertical")
+ , max_visible("max_visible")
+ , padding("padding", DEF_PADDING)
+ , selected_image("selected_image")
{
}
LLPanelEmojiComplete::LLPanelEmojiComplete(const LLPanelEmojiComplete::Params& p)
- : LLUICtrl(p)
- , mAutoSize(p.autosize)
- , mNoScroll(p.noscroll)
- , mVertical(p.vertical)
- , mMaxVisible(p.max_emoji)
- , mPadding(p.padding)
- , mSelectedImage(p.selected_image)
- , mIconFont(LLFontGL::getFontEmojiHuge())
- , mTextFont(LLFontGL::getFontSansSerifBig())
+ : LLUICtrl(p)
+ , mAutoSize(p.autosize)
+ , mNoScroll(p.noscroll)
+ , mVertical(p.vertical)
+ , mMaxVisible(p.max_visible)
+ , mPadding(p.padding)
+ , mSelectedImage(p.selected_image)
+ , mIconFont(LLFontGL::getFontEmojiHuge())
+ , mTextFont(LLFontGL::getFontSansSerifBig())
+ , mScrollbar(nullptr)
{
+ if (mVertical)
+ {
+ LLScrollbar::Params sbparams;
+ sbparams.orientation(LLScrollbar::VERTICAL);
+ sbparams.change_callback([this](S32 index, LLScrollbar*) { onScrollbarChange(index); });
+ mScrollbar = LLUICtrlFactory::create<LLScrollbar>(sbparams);
+ addChild(mScrollbar);
+ }
}
LLPanelEmojiComplete::~LLPanelEmojiComplete()
@@ -69,13 +80,15 @@ LLPanelEmojiComplete::~LLPanelEmojiComplete()
void LLPanelEmojiComplete::draw()
{
+ LLUICtrl::draw();
+
if (mEmojis.empty())
return;
const size_t firstVisibleIdx = mScrollPos;
- const size_t lastVisibleIdx = llmin(mScrollPos + mVisibleEmojis, mEmojis.size()) - 1;
+ const size_t lastVisibleIdx = llmin(mScrollPos + mVisibleEmojis, mTotalEmojis);
- if (mCurSelected >= firstVisibleIdx && mCurSelected <= lastVisibleIdx)
+ if (mCurSelected >= firstVisibleIdx && mCurSelected < lastVisibleIdx)
{
S32 x, y, width, height;
if (mVertical)
@@ -100,7 +113,7 @@ void LLPanelEmojiComplete::draw()
S32 textLeft = mVertical ? mRenderRect.mLeft + mEmojiWidth + mPadding : 0;
S32 textWidth = mVertical ? getRect().getWidth() - textLeft - mPadding : 0;
- for (U32 curIdx = firstVisibleIdx; curIdx <= lastVisibleIdx; curIdx++)
+ for (U32 curIdx = firstVisibleIdx; curIdx < lastVisibleIdx; curIdx++)
{
mIconFont->render(mEmojis, curIdx, iconCenterX, iconCenterY,
LLColor4::white, LLFontGL::HCENTER, LLFontGL::VCENTER, LLFontGL::NORMAL,
@@ -128,100 +141,154 @@ void LLPanelEmojiComplete::draw()
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;
+ if (mScrollbar && mScrollbar->getVisible() && childrenHandleHover(x, y, mask))
+ return TRUE;
+
+ LLVector2 curHover(x, y);
+ if ((mLastHover - curHover).lengthSquared() > MIN_MOUSE_MOVE_DELTA)
+ {
+ size_t index = posToIndex(x, y);
+ if (index < mTotalEmojis)
+ mCurSelected = index;
+ mLastHover = curHover;
+ }
+
+ return TRUE;
}
BOOL LLPanelEmojiComplete::handleKey(KEY key, MASK mask, BOOL called_from_parent)
{
- bool handled = false;
- if (MASK_NONE == mask)
- {
- switch (key)
- {
- case KEY_LEFT:
- case KEY_UP:
- selectPrevious();
- handled = true;
- break;
- case KEY_RIGHT:
- case KEY_DOWN:
- selectNext();
- handled = true;
- break;
- case KEY_RETURN:
- if (!mEmojis.empty())
- {
- onCommit();
- handled = true;
- }
- break;
- }
- }
-
- if (handled)
- {
- return TRUE;
- }
- return LLUICtrl::handleKey(key, mask, called_from_parent);
+ bool handled = false;
+ if (mTotalEmojis && MASK_NONE == mask)
+ {
+ switch (key)
+ {
+ case KEY_HOME:
+ select(0);
+ handled = true;
+ break;
+
+ case KEY_END:
+ select(mTotalEmojis - 1);
+ handled = true;
+ break;
+
+ case KEY_PAGE_DOWN:
+ select(mCurSelected + mVisibleEmojis - 1);
+ handled = true;
+ break;
+
+ case KEY_PAGE_UP:
+ select(mCurSelected - llmin(mCurSelected, mVisibleEmojis + 1));
+ handled = true;
+ break;
+
+ case KEY_LEFT:
+ case KEY_UP:
+ selectPrevious();
+ handled = true;
+ break;
+
+ case KEY_RIGHT:
+ case KEY_DOWN:
+ selectNext();
+ handled = true;
+ break;
+
+ case KEY_RETURN:
+ onCommit();
+ handled = true;
+ break;
+ }
+ }
+
+ if (handled)
+ {
+ return TRUE;
+ }
+
+ return LLUICtrl::handleKey(key, mask, called_from_parent);
}
BOOL LLPanelEmojiComplete::handleMouseDown(S32 x, S32 y, MASK mask)
{
- mCurSelected = posToIndex(x, y);
- mLastHover = LLVector2(x, y);
+ if (mScrollbar && mScrollbar->getVisible() && childrenHandleMouseDown(x, y, mask))
+ return TRUE;
+
+ mCurSelected = posToIndex(x, y);
+ mLastHover = LLVector2(x, y);
- return TRUE;
+ return TRUE;
}
BOOL LLPanelEmojiComplete::handleMouseUp(S32 x, S32 y, MASK mask)
{
- mCurSelected = posToIndex(x, y);
- onCommit();
+ if (mScrollbar && mScrollbar->getVisible() && childrenHandleMouseUp(x, y, mask))
+ return TRUE;
+
+ mCurSelected = posToIndex(x, y);
+ onCommit();
+
+ return TRUE;
+}
+
+BOOL LLPanelEmojiComplete::handleScrollWheel(S32 x, S32 y, S32 clicks)
+{
+ if (mNoScroll)
+ return FALSE;
- return TRUE;
+ if (mScrollbar && mScrollbar->getVisible() && mScrollbar->handleScrollWheel(x, y, clicks))
+ {
+ mCurSelected = posToIndex(x, y);
+ return TRUE;
+ }
+
+ if (mTotalEmojis > mVisibleEmojis)
+ {
+ mScrollPos = llclamp<size_t>(mScrollPos + clicks, 0, mTotalEmojis - mVisibleEmojis);
+ mCurSelected = posToIndex(x, y);
+ return TRUE;
+ }
+
+ return FALSE;
}
void LLPanelEmojiComplete::onCommit()
{
- if (mCurSelected < mEmojis.size())
- {
- LLWString wstr;
- wstr.push_back(mEmojis.at(mCurSelected));
- setValue(wstring_to_utf8str(wstr));
- LLUICtrl::onCommit();
- }
+ if (mCurSelected < mTotalEmojis)
+ {
+ LLWString wstr;
+ wstr.push_back(mEmojis.at(mCurSelected));
+ setValue(wstring_to_utf8str(wstr));
+ LLUICtrl::onCommit();
+ }
}
void LLPanelEmojiComplete::reshape(S32 width, S32 height, BOOL called_from_parent)
{
- LLUICtrl::reshape(width, height, called_from_parent);
- updateConstraints();
+ LLUICtrl::reshape(width, height, called_from_parent);
+ updateConstraints();
}
void LLPanelEmojiComplete::setEmojis(const LLWString& emojis)
{
- mEmojis = emojis;
- mCurSelected = 0;
+ mEmojis = emojis;
+ mTotalEmojis = mEmojis.size();
+ mCurSelected = 0;
- onEmojisChanged();
+ onEmojisChanged();
}
void LLPanelEmojiComplete::setEmojiHint(const std::string& hint)
{
- llwchar curEmoji = (mCurSelected < mEmojis.size()) ? mEmojis.at(mCurSelected) : 0;
+ llwchar curEmoji = mCurSelected < mTotalEmojis ? mEmojis.at(mCurSelected) : 0;
- mEmojis = LLEmojiDictionary::instance().findMatchingEmojis(hint);
- size_t curEmojiIdx = curEmoji ? mEmojis.find(curEmoji) : std::string::npos;
- mCurSelected = (std::string::npos != curEmojiIdx) ? curEmojiIdx : 0;
+ mEmojis = LLEmojiDictionary::instance().findMatchingEmojis(hint);
+ mTotalEmojis = mEmojis.size();
+ size_t curEmojiIdx = curEmoji ? mEmojis.find(curEmoji) : std::string::npos;
+ mCurSelected = std::string::npos != curEmojiIdx ? curEmojiIdx : 0;
- onEmojisChanged();
+ onEmojisChanged();
}
U32 LLPanelEmojiComplete::getMaxShortCodeWidth() const
@@ -246,79 +313,104 @@ U32 LLPanelEmojiComplete::getMaxShortCodeWidth() const
void LLPanelEmojiComplete::onEmojisChanged()
{
- if (mAutoSize)
- {
- mVisibleEmojis = std::min(mEmojis.size(), mMaxVisible);
+ if (mAutoSize)
+ {
+ S32 width, height;
+ mVisibleEmojis = llmin(mTotalEmojis, mMaxVisible);
if (mVertical)
{
U32 maxShortCodeWidth = getMaxShortCodeWidth();
- U32 shortCodeWidth = std::max(maxShortCodeWidth, MIN_SHORT_CODE_WIDTH);
- S32 width = mEmojiWidth + shortCodeWidth + mPadding * 2;
- reshape(width, mVisibleEmojis * mEmojiHeight, false);
+ U32 shortCodeWidth = llmax(maxShortCodeWidth, MIN_SHORT_CODE_WIDTH);
+ width = mEmojiWidth + shortCodeWidth + mPadding * 2;
+ if (!mNoScroll && mVisibleEmojis < mTotalEmojis)
+ {
+ width += mScrollbar->getThickness();
+ }
+ height = mVisibleEmojis * mEmojiHeight;
}
else
{
- S32 height = getRect().getHeight();
- reshape(mVisibleEmojis * mEmojiWidth, height, false);
+ width = mVisibleEmojis * mEmojiWidth;
+ height = getRect().getHeight();
}
- }
- else
- {
- updateConstraints();
- }
+ LLUICtrl::reshape(width, height, false);
+ }
+ else
+ {
+ mVisibleEmojis = mVertical ? getRect().getHeight() / mEmojiHeight : getRect().getWidth() / mEmojiWidth;
+ }
- mScrollPos = llmin(mScrollPos, mEmojis.size());
+ updateConstraints();
+}
+
+void LLPanelEmojiComplete::onScrollbarChange(S32 index)
+{
+ mScrollPos = llclamp<size_t>(index, 0, mTotalEmojis - mVisibleEmojis);
}
size_t LLPanelEmojiComplete::posToIndex(S32 x, S32 y) const
{
- if (mRenderRect.pointInRect(x, y))
- {
- U32 pos = mVertical ? (U32)(mRenderRect.mTop - y) / mEmojiHeight : x / mEmojiWidth;
- return mScrollPos + llmin((size_t)pos, mEmojis.size() - 1);
- }
- return npos;
+ if (mRenderRect.pointInRect(x, y))
+ {
+ U32 pos = mVertical ? (U32)(mRenderRect.mTop - y) / mEmojiHeight : x / mEmojiWidth;
+ return llmin(mScrollPos + pos, mTotalEmojis - 1);
+ }
+ return std::string::npos;
}
void LLPanelEmojiComplete::select(size_t emoji_idx)
{
- mCurSelected = llclamp<size_t>(emoji_idx, 0, mEmojis.size());
- updateScrollPos();
+ mCurSelected = llclamp<size_t>(emoji_idx, 0, mTotalEmojis - 1);
+
+ updateScrollPos();
}
void LLPanelEmojiComplete::selectNext()
{
- select(mCurSelected + 1 < mEmojis.size() ? mCurSelected + 1 : 0);
+ if (!mTotalEmojis)
+ return;
+
+ mCurSelected = (mCurSelected < mTotalEmojis - 1) ? mCurSelected + 1 : 0;
+
+ updateScrollPos();
}
void LLPanelEmojiComplete::selectPrevious()
{
- select(mCurSelected - 1 >= 0 ? mCurSelected - 1 : mEmojis.size() - 1);
+ if (!mTotalEmojis)
+ return;
+
+ mCurSelected = (mCurSelected && mCurSelected < mTotalEmojis) ? mCurSelected - 1 : mTotalEmojis - 1;
+
+ updateScrollPos();
}
void LLPanelEmojiComplete::updateConstraints()
{
mRenderRect = getLocalRect();
- S32 ctrlWidth = mRenderRect.getWidth();
- S32 ctrlHeight = mRenderRect.getHeight();
- mEmojiHeight = mIconFont->getLineHeight() + mPadding * 2;
mEmojiWidth = mIconFont->getWidthF32(u8"\U0001F431") + mPadding * 2;
if (mVertical)
{
- mVisibleEmojis = ctrlHeight / mEmojiHeight;
- mRenderRect.mBottom = mRenderRect.mTop - mVisibleEmojis * mEmojiHeight;
+ mEmojiHeight = mIconFont->getLineHeight() + mPadding * 2;
+ if (!mNoScroll && mVisibleEmojis < mTotalEmojis)
+ {
+ mRenderRect.mRight -= mScrollbar->getThickness();
+ mScrollbar->setDocSize(mTotalEmojis);
+ mScrollbar->setPageSize(mVisibleEmojis);
+ mScrollbar->setOrigin(mRenderRect.mRight, 0);
+ mScrollbar->reshape(mScrollbar->getThickness(), mRenderRect.mTop, TRUE);
+ mScrollbar->setVisible(TRUE);
+ }
+ else
+ {
+ mScrollbar->setVisible(FALSE);
+ }
}
else
{
- mVisibleEmojis = ctrlWidth / mEmojiWidth;
- S32 padding = (ctrlWidth - mVisibleEmojis * mEmojiWidth) / 2;
- mRenderRect.mLeft += padding;
- mRenderRect.mRight -= padding;
- if (mEmojiHeight > ctrlHeight)
- {
- mEmojiHeight = ctrlHeight;
- }
+ mEmojiHeight = mRenderRect.getHeight();
+ mRenderRect.stretch((mRenderRect.getWidth() - mVisibleEmojis * mEmojiWidth) / -2, 0);
}
updateScrollPos();
@@ -326,23 +418,27 @@ void LLPanelEmojiComplete::updateConstraints()
void LLPanelEmojiComplete::updateScrollPos()
{
- const size_t cntEmoji = mEmojis.size();
- if (mNoScroll || 0 == cntEmoji || cntEmoji < mVisibleEmojis || 0 == mCurSelected)
- {
- mScrollPos = 0;
- if (mCurSelected >= mVisibleEmojis)
- {
- mCurSelected = mVisibleEmojis ? mVisibleEmojis - 1 : 0;
- }
- }
- else if (cntEmoji - 1 == mCurSelected)
- {
- mScrollPos = mCurSelected - mVisibleEmojis + 1;
- }
- else
- {
- mScrollPos = mCurSelected - ((float)mCurSelected / (cntEmoji - 2) * (mVisibleEmojis - 2));
- }
+ if (mNoScroll || 0 == mTotalEmojis || mTotalEmojis < mVisibleEmojis || 0 == mCurSelected)
+ {
+ mScrollPos = 0;
+ if (mCurSelected >= mVisibleEmojis)
+ {
+ mCurSelected = mVisibleEmojis ? mVisibleEmojis - 1 : 0;
+ }
+ }
+ else if (mTotalEmojis - 1 == mCurSelected)
+ {
+ mScrollPos = mTotalEmojis - mVisibleEmojis;
+ }
+ else
+ {
+ mScrollPos = mCurSelected - ((float)mCurSelected / (mTotalEmojis - 2) * (mVisibleEmojis - 2));
+ }
+
+ if (mScrollbar && mScrollbar->getVisible())
+ {
+ mScrollbar->setDocPos(mScrollPos);
+ }
}
// ============================================================================
@@ -350,33 +446,33 @@ void LLPanelEmojiComplete::updateScrollPos()
//
LLFloaterEmojiComplete::LLFloaterEmojiComplete(const LLSD& sdKey)
- : LLFloater(sdKey)
+ : LLFloater(sdKey)
{
- // This floater should hover on top of our dependent (with the dependent having the focus)
- setFocusStealsFrontmost(false);
- setAutoFocus(false);
- setBackgroundVisible(false);
- setIsChrome(true);
+ // This floater should hover on top of our dependent (with the dependent having the focus)
+ setFocusStealsFrontmost(false);
+ setAutoFocus(false);
+ setBackgroundVisible(false);
+ setIsChrome(true);
}
BOOL LLFloaterEmojiComplete::handleKey(KEY key, MASK mask, BOOL called_from_parent)
{
- bool handled = false;
- if (MASK_NONE == mask)
- {
- switch (key)
- {
- case KEY_ESCAPE:
- LLEmojiHelper::instance().hideHelper();
- handled = true;
- break;
- }
- }
-
- if (handled)
- return TRUE;
-
- return LLFloater::handleKey(key, mask, called_from_parent);
+ bool handled = false;
+ if (MASK_NONE == mask)
+ {
+ switch (key)
+ {
+ case KEY_ESCAPE:
+ LLEmojiHelper::instance().hideHelper();
+ handled = true;
+ break;
+ }
+ }
+
+ if (handled)
+ return TRUE;
+
+ return LLFloater::handleKey(key, mask, called_from_parent);
}
void LLFloaterEmojiComplete::onOpen(const LLSD& key)
@@ -402,30 +498,33 @@ void LLFloaterEmojiComplete::onOpen(const LLSD& key)
BOOL LLFloaterEmojiComplete::postBuild()
{
- mEmojiCtrl = findChild<LLPanelEmojiComplete>("emoji_complete_ctrl");
- mEmojiCtrl->setCommitCallback(
- std::bind([&](const LLSD& sdValue)
- {
- setValue(sdValue);
- onCommit();
- }, std::placeholders::_2));
- mEmojiCtrlHorz = getRect().getWidth() - mEmojiCtrl->getRect().getWidth();
-
- return LLFloater::postBuild();
+ mEmojiCtrl = findChild<LLPanelEmojiComplete>("emoji_complete_ctrl");
+ mEmojiCtrl->setCommitCallback(
+ [this](LLUICtrl* ctrl, const LLSD& param)
+ {
+ setValue(param);
+ onCommit();
+ });
+
+ mEmojiCtrlHorz = getRect().getWidth() - mEmojiCtrl->getRect().getWidth();
+ mEmojiCtrlVert = getRect().getHeight() - mEmojiCtrl->getRect().getHeight();
+
+ return LLFloater::postBuild();
}
void LLFloaterEmojiComplete::reshape(S32 width, S32 height, BOOL called_from_parent)
{
- if (!called_from_parent)
- {
- LLRect rctFloater = getRect(), rctCtrl = mEmojiCtrl->getRect();
- rctFloater.mRight = rctFloater.mLeft + rctCtrl.getWidth() + mEmojiCtrlHorz;
- setRect(rctFloater);
-
- return;
- }
-
- LLFloater::reshape(width, height, called_from_parent);
+ if (called_from_parent)
+ {
+ LLFloater::reshape(width, height, called_from_parent);
+ }
+ else
+ {
+ LLRect outer(getRect()), inner(mEmojiCtrl->getRect());
+ outer.mRight = outer.mLeft + inner.getWidth() + mEmojiCtrlHorz;
+ outer.mTop = outer.mBottom + inner.getHeight() + mEmojiCtrlVert;
+ setRect(outer);
+ }
}
// ============================================================================