diff options
| -rw-r--r-- | indra/llui/llscrollcontainer.cpp | 23 | ||||
| -rw-r--r-- | indra/llui/llscrollcontainer.h | 4 | ||||
| -rw-r--r-- | indra/llui/llscrollingpanellist.h | 2 | ||||
| -rw-r--r-- | indra/newview/llfloateremojipicker.cpp | 194 | ||||
| -rw-r--r-- | indra/newview/llfloateremojipicker.h | 13 | ||||
| -rw-r--r-- | indra/newview/llviewerwindow.cpp | 1 | ||||
| -rw-r--r-- | indra/newview/skins/default/xui/en/floater_emoji_picker.xml | 1 | 
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"  | 
