summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlexander Gavriliuk <alexandrgproductengine@lindenlab.com>2023-11-07 23:13:00 +0100
committerGuru <alexandrgproductengine@lindenlab.com>2023-11-08 11:15:35 +0100
commit716b9af35d0dbc3ba8048a1bcca2c8c8f703bed0 (patch)
tree3cc496a6dd1e810b8ad5fafbb2a3797b2ce20258
parent2e0892e53041f75fc991b77870a4f2f4672fefb1 (diff)
SL-20356 EmojiPicker - Implement arrow keys navigation
-rw-r--r--indra/llui/llscrollcontainer.cpp23
-rw-r--r--indra/llui/llscrollcontainer.h4
-rw-r--r--indra/llui/llscrollingpanellist.h2
-rw-r--r--indra/newview/llfloateremojipicker.cpp194
-rw-r--r--indra/newview/llfloateremojipicker.h13
-rw-r--r--indra/newview/llviewerwindow.cpp1
-rw-r--r--indra/newview/skins/default/xui/en/floater_emoji_picker.xml1
7 files changed, 230 insertions, 8 deletions
diff --git a/indra/llui/llscrollcontainer.cpp b/indra/llui/llscrollcontainer.cpp
index ad32f7186c..22d27b1f2a 100644
--- a/indra/llui/llscrollcontainer.cpp
+++ b/indra/llui/llscrollcontainer.cpp
@@ -70,6 +70,7 @@ LLScrollContainer::Params::Params()
bg_color("color"),
border_visible("border_visible"),
hide_scrollbar("hide_scrollbar"),
+ ignore_arrow_keys("ignore_arrow_keys"),
min_auto_scroll_rate("min_auto_scroll_rate", 100),
max_auto_scroll_rate("max_auto_scroll_rate", 1000),
max_auto_scroll_zone("max_auto_scroll_zone", 16),
@@ -86,6 +87,7 @@ LLScrollContainer::LLScrollContainer(const LLScrollContainer::Params& p)
mBackgroundColor(p.bg_color()),
mIsOpaque(p.is_opaque),
mHideScrollbar(p.hide_scrollbar),
+ mIgnoreArrowKeys(p.ignore_arrow_keys),
mReserveScrollCorner(p.reserve_scroll_corner),
mMinAutoScrollRate(p.min_auto_scroll_rate),
mMaxAutoScrollRate(p.max_auto_scroll_rate),
@@ -204,10 +206,29 @@ void LLScrollContainer::reshape(S32 width, S32 height,
}
}
+// virtual
BOOL LLScrollContainer::handleKeyHere(KEY key, MASK mask)
{
+ if (mIgnoreArrowKeys)
+ {
+ switch(key)
+ {
+ case KEY_LEFT:
+ case KEY_RIGHT:
+ case KEY_UP:
+ case KEY_DOWN:
+ case KEY_PAGE_UP:
+ case KEY_PAGE_DOWN:
+ case KEY_HOME:
+ case KEY_END:
+ return FALSE;
+ default:
+ break;
+ }
+ }
+
// allow scrolled view to handle keystrokes in case it delegated keyboard focus
- // to the scroll container.
+ // to the scroll container.
// NOTE: this should not recurse indefinitely as handleKeyHere
// should not propagate to parent controls, so mScrolledView should *not*
// call LLScrollContainer::handleKeyHere in turn
diff --git a/indra/llui/llscrollcontainer.h b/indra/llui/llscrollcontainer.h
index dacea2a987..79dc70cac9 100644
--- a/indra/llui/llscrollcontainer.h
+++ b/indra/llui/llscrollcontainer.h
@@ -63,7 +63,8 @@ public:
Optional<bool> is_opaque,
reserve_scroll_corner,
border_visible,
- hide_scrollbar;
+ hide_scrollbar,
+ ignore_arrow_keys;
Optional<F32> min_auto_scroll_rate,
max_auto_scroll_rate;
Optional<U32> max_auto_scroll_zone;
@@ -149,6 +150,7 @@ private:
F32 mMaxAutoScrollRate;
U32 mMaxAutoScrollZone;
bool mHideScrollbar;
+ bool mIgnoreArrowKeys;
};
diff --git a/indra/llui/llscrollingpanellist.h b/indra/llui/llscrollingpanellist.h
index 9dc65dabb5..d625039427 100644
--- a/indra/llui/llscrollingpanellist.h
+++ b/indra/llui/llscrollingpanellist.h
@@ -45,7 +45,7 @@ public:
/*
- * A set of panels that are displayed in a vertical sequence inside a scroll container.
+ * A set of panels that are displayed in a sequence inside a scroll container.
*/
class LLScrollingPanelList : public LLUICtrl
{
diff --git a/indra/newview/llfloateremojipicker.cpp b/indra/newview/llfloateremojipicker.cpp
index 10013c907d..45c33728e5 100644
--- a/indra/newview/llfloateremojipicker.cpp
+++ b/indra/newview/llfloateremojipicker.cpp
@@ -399,6 +399,13 @@ void LLFloaterEmojiPicker::moveGroups()
mBadge->setRect(rect);
}
+void LLFloaterEmojiPicker::showPreview(bool show)
+{
+ mPreview->setEmoji(nullptr);
+ mDummy->setVisible(show ? FALSE : TRUE);
+ mPreview->setVisible(show ? TRUE : FALSE);
+}
+
void LLFloaterEmojiPicker::fillEmojis(bool fromResize)
{
mRecentGridWidth = mEmojiScroll->getRect().getWidth();
@@ -423,6 +430,9 @@ void LLFloaterEmojiPicker::fillEmojis(bool fromResize)
mRecentMaxIcons = maxIcons;
+ mFocusedIconRow = 0;
+ mFocusedIconCol = 0;
+ mFocusedIcon = nullptr;
mHoveredIcon = nullptr;
mEmojiGrid->clearPanels();
mPreview->setEmoji(nullptr);
@@ -599,15 +609,17 @@ void LLFloaterEmojiPicker::onFilterChanged()
void LLFloaterEmojiPicker::onGridMouseEnter()
{
- mDummy->setVisible(FALSE);
- mPreview->setEmoji(nullptr);
- mPreview->setVisible(TRUE);
+ LLFocusableElement* focus = gFocusMgr.getKeyboardFocus();
+ if (focus == mEmojiGrid)
+ {
+ exitArrowMode();
+ }
+ showPreview(true);
}
void LLFloaterEmojiPicker::onGridMouseLeave()
{
- mPreview->setVisible(FALSE);
- mDummy->setVisible(TRUE);
+ showPreview(false);
}
void LLFloaterEmojiPicker::onGroupButtonMouseEnter(LLUICtrl* ctrl)
@@ -630,6 +642,13 @@ void LLFloaterEmojiPicker::onEmojiMouseEnter(LLUICtrl* ctrl)
{
if (ctrl)
{
+ LLFocusableElement* focus = gFocusMgr.getKeyboardFocus();
+ if (focus == mEmojiGrid)
+ {
+ exitArrowMode();
+ showPreview(true);
+ }
+
if (mHoveredIcon && mHoveredIcon != ctrl)
{
unselectGridIcon(mHoveredIcon);
@@ -679,6 +698,113 @@ void LLFloaterEmojiPicker::onEmojiMouseUp(LLUICtrl* ctrl)
}
}
+bool LLFloaterEmojiPicker::enterArrowMode()
+{
+ S32 rowCount = mEmojiGrid->getPanelList().size();
+ if (rowCount)
+ {
+ mFocusedIconRow = -1;
+ mFocusedIconCol = 0;
+ if (moveFocusedIconDown())
+ {
+ showPreview(true);
+ mEmojiScroll->goToTop();
+ mEmojiGrid->setFocus(TRUE);
+ return true;
+ }
+ }
+ return false;
+}
+
+void LLFloaterEmojiPicker::exitArrowMode()
+{
+ if (mFocusedIcon)
+ {
+ unselectGridIcon(mFocusedIcon);
+ mFocusedIcon = nullptr;
+ }
+
+ showPreview(false);
+ mEmojiScroll->goToTop();
+ mFocusedIconRow = mFocusedIconCol = 0;
+ mFilter->setFocus(TRUE);
+}
+
+void LLFloaterEmojiPicker::selectFocusedIcon()
+{
+ if (mHoveredIcon)
+ {
+ unselectGridIcon(mHoveredIcon);
+ }
+
+ if (mFocusedIcon)
+ {
+ unselectGridIcon(mFocusedIcon);
+ }
+
+ // Both mFocusedIconRow and mFocusedIconCol should be already verified
+ LLEmojiGridRow* row = (LLEmojiGridRow*)mEmojiGrid->getPanelList()[mFocusedIconRow];
+ mFocusedIcon = row->mList->getPanelList()[mFocusedIconCol];
+ selectGridIcon(mFocusedIcon);
+}
+
+bool LLFloaterEmojiPicker::moveFocusedIconUp()
+{
+ for (S32 i = mFocusedIconRow - 1; i >= 0; --i)
+ {
+ LLScrollingPanel* panel = mEmojiGrid->getPanelList()[i];
+ LLEmojiGridRow* row = dynamic_cast<LLEmojiGridRow*>(panel);
+ if (row && row->mList->getPanelList().size() > mFocusedIconCol)
+ {
+ mEmojiScroll->scrollToShowRect(row->getBoundingRect());
+ mFocusedIconRow = i;
+ selectFocusedIcon();
+ return true;
+ }
+ }
+ return false;
+}
+
+bool LLFloaterEmojiPicker::moveFocusedIconDown()
+{
+ S32 rowCount = mEmojiGrid->getPanelList().size();
+ for (S32 i = mFocusedIconRow + 1; i < rowCount; ++i)
+ {
+ LLScrollingPanel* panel = mEmojiGrid->getPanelList()[i];
+ LLEmojiGridRow* row = dynamic_cast<LLEmojiGridRow*>(panel);
+ if (row && row->mList->getPanelList().size() > mFocusedIconCol)
+ {
+ mEmojiScroll->scrollToShowRect(row->getBoundingRect());
+ mFocusedIconRow = i;
+ selectFocusedIcon();
+ return true;
+ }
+ }
+ return false;
+}
+
+bool LLFloaterEmojiPicker::moveFocusedIconLeft()
+{
+ if (mFocusedIconCol <= 0)
+ return false;
+
+ mFocusedIconCol--;
+ selectFocusedIcon();
+ return true;
+}
+
+bool LLFloaterEmojiPicker::moveFocusedIconRight()
+{
+ LLEmojiGridRow* row = (LLEmojiGridRow*)mEmojiGrid->getPanelList()[mFocusedIconRow];
+ S32 colCount = row->mList->getPanelList().size();
+ if (mFocusedIconCol >= colCount - 1)
+ return false;
+
+ mFocusedIconCol++;
+ selectFocusedIcon();
+ return true;
+}
+
void LLFloaterEmojiPicker::selectGridIcon(LLUICtrl* ctrl)
{
if (LLEmojiGridIcon* icon = dynamic_cast<LLEmojiGridIcon*>(ctrl))
@@ -698,6 +824,64 @@ void LLFloaterEmojiPicker::unselectGridIcon(LLUICtrl* ctrl)
}
// virtual
+BOOL LLFloaterEmojiPicker::handleKey(KEY key, MASK mask, BOOL called_from_parent)
+{
+ if (mask == MASK_NONE)
+ {
+ LLFocusableElement* focus = gFocusMgr.getKeyboardFocus();
+ if (focus == mEmojiGrid)
+ {
+ if (key == KEY_RETURN)
+ {
+ if (mFocusedIcon)
+ {
+ onEmojiMouseDown(mFocusedIcon);
+ onEmojiMouseUp(mFocusedIcon);
+ closeFloater();
+ return TRUE;
+ }
+ }
+ else if (key == KEY_TAB)
+ {
+ exitArrowMode();
+ return TRUE;
+ }
+ else if (key == KEY_UP)
+ {
+ if (!moveFocusedIconUp())
+ exitArrowMode();
+ return TRUE;
+ }
+ else if (key == KEY_DOWN)
+ {
+ if (moveFocusedIconDown())
+ return TRUE;
+ }
+ else if (key == KEY_LEFT)
+ {
+ if (moveFocusedIconLeft())
+ return TRUE;
+ }
+ else if (key == KEY_RIGHT)
+ {
+ if (moveFocusedIconRight())
+ return TRUE;
+ }
+ }
+ else // if (focus != mEmojiGrid)
+ {
+ if (key == KEY_DOWN)
+ {
+ if (enterArrowMode())
+ return TRUE;
+ }
+ }
+ }
+
+ return super::handleKey(key, mask, called_from_parent);
+}
+
+// virtual
BOOL LLFloaterEmojiPicker::handleKeyHere(KEY key, MASK mask)
{
if (mask == MASK_NONE)
diff --git a/indra/newview/llfloateremojipicker.h b/indra/newview/llfloateremojipicker.h
index b8e3190bf3..48f66d7950 100644
--- a/indra/newview/llfloateremojipicker.h
+++ b/indra/newview/llfloateremojipicker.h
@@ -63,6 +63,7 @@ public:
private:
void fillGroups();
void moveGroups();
+ void showPreview(bool show);
void fillEmojis(bool fromResize = false);
void onGroupButtonClick(LLUICtrl* ctrl);
@@ -76,9 +77,18 @@ private:
void onEmojiMouseDown(LLUICtrl* ctrl);
void onEmojiMouseUp(LLUICtrl* ctrl);
+ bool enterArrowMode();
+ void exitArrowMode();
+ void selectFocusedIcon();
+ bool moveFocusedIconUp();
+ bool moveFocusedIconDown();
+ bool moveFocusedIconLeft();
+ bool moveFocusedIconRight();
+
void selectGridIcon(LLUICtrl* ctrl);
void unselectGridIcon(LLUICtrl* ctrl);
+ virtual BOOL handleKey(KEY key, MASK mask, BOOL called_from_parent) override;
virtual BOOL handleKeyHere(KEY key, MASK mask) override;
class LLPanel* mGroups { nullptr };
@@ -97,6 +107,9 @@ private:
S32 mRecentBadgeWidth { 0 };
S32 mRecentGridWidth { 0 };
S32 mRecentMaxIcons { 0 };
+ S32 mFocusedIconRow { 0 };
+ S32 mFocusedIconCol { 0 };
+ LLUICtrl* mFocusedIcon { nullptr };
LLUICtrl* mHoveredIcon { nullptr };
};
diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp
index 39b4075596..ad177cdb85 100644
--- a/indra/newview/llviewerwindow.cpp
+++ b/indra/newview/llviewerwindow.cpp
@@ -3054,6 +3054,7 @@ BOOL LLViewerWindow::handleKey(KEY key, MASK mask)
case KEY_PAGE_UP:
case KEY_PAGE_DOWN:
case KEY_HOME:
+ case KEY_END:
// when chatbar is empty or ArrowKeysAlwaysMove set,
// pass arrow keys on to avatar...
return FALSE;
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 e15c304851..a89d97d8e9 100644
--- a/indra/newview/skins/default/xui/en/floater_emoji_picker.xml
+++ b/indra/newview/skins/default/xui/en/floater_emoji_picker.xml
@@ -25,6 +25,7 @@
name="EmojiGridContainer"
layout="topleft"
follows="all"
+ ignore_arrow_keys="true"
top="50"
left="0"
height="300"