From 43e66b57a074eb9926d0f83396dba34164a7dab6 Mon Sep 17 00:00:00 2001 From: Inusaito Sayori Date: Wed, 28 May 2014 21:50:18 -0400 Subject: [PATCH] [UI Overhaul] Scrollable Menus.. just the implementation for now, not actually used. This worked initially(early testing yesterday), but since then it seems not to, either way, implementation part is out of the way, so committing. --- indra/llui/llbutton.cpp | 4 +- indra/llui/llbutton.h | 4 +- indra/llui/llmenugl.cpp | 483 +++++++++++++++++++++++++++++++++++++++- indra/llui/llmenugl.h | 25 ++- 4 files changed, 499 insertions(+), 17 deletions(-) diff --git a/indra/llui/llbutton.cpp b/indra/llui/llbutton.cpp index daa7de213..1b9add0a4 100644 --- a/indra/llui/llbutton.cpp +++ b/indra/llui/llbutton.cpp @@ -272,7 +272,7 @@ void LLButton::onCommit() LLUICtrl::onCommit(); } -/*boost::signals2::connection LLButton::setClickedCallback(const CommitCallbackParam& cb) +boost::signals2::connection LLButton::setClickedCallback(const CommitCallbackParam& cb) { return setClickedCallback(initCommitCallback(cb)); } @@ -287,7 +287,7 @@ boost::signals2::connection LLButton::setMouseUpCallback(const CommitCallbackPar boost::signals2::connection LLButton::setHeldDownCallback(const CommitCallbackParam& cb) { return setHeldDownCallback(initCommitCallback(cb)); -}*/ +} boost::signals2::connection LLButton::setClickedCallback( const commit_signal_t::slot_type& cb ) diff --git a/indra/llui/llbutton.h b/indra/llui/llbutton.h index 219b0dfec..1495740c6 100644 --- a/indra/llui/llbutton.h +++ b/indra/llui/llbutton.h @@ -116,10 +116,10 @@ public: void setSelectedLabelColor( const LLColor4& c ) { mSelectedLabelColor = c; } - /*boost::signals2::connection setClickedCallback(const CommitCallbackParam& cb); + boost::signals2::connection setClickedCallback(const CommitCallbackParam& cb); boost::signals2::connection setMouseDownCallback(const CommitCallbackParam& cb); boost::signals2::connection setMouseUpCallback(const CommitCallbackParam& cb); - boost::signals2::connection setHeldDownCallback(const CommitCallbackParam& cb);*/ + boost::signals2::connection setHeldDownCallback(const CommitCallbackParam& cb); boost::signals2::connection setClickedCallback( const commit_signal_t::slot_type& cb ); // mouse down and up within button boost::signals2::connection setMouseDownCallback( const commit_signal_t::slot_type& cb ); diff --git a/indra/llui/llmenugl.cpp b/indra/llui/llmenugl.cpp index 27df264af..338370e8f 100644 --- a/indra/llui/llmenugl.cpp +++ b/indra/llui/llmenugl.cpp @@ -486,7 +486,7 @@ BOOL LLMenuItemGL::handleMouseDown( S32 x, S32 y, MASK mask) BOOL LLMenuItemGL::handleScrollWheel( S32 x, S32 y, S32 clicks ) { // If the menu is scrollable let it handle the wheel event. - return FALSE;//!getMenu()->isScrollable(); + return !getMenu()->isScrollable(); } void LLMenuItemGL::draw( void ) @@ -1805,6 +1805,117 @@ void LLMenuItemBranchDownGL::draw( void ) setHover(FALSE); } + +class LLMenuScrollItem : public LLMenuItemCallGL +{ +public: + enum EArrowType + { + ARROW_DOWN, + ARROW_UP + }; + struct ArrowTypes : public LLInitParam::TypeValuesHelper + { + static void declareValues() + { + declare("up", ARROW_UP); + declare("down", ARROW_DOWN); + } + }; + + struct Params : public LLInitParam::Block + { + Optional arrow_type; + Optional scroll_callback; + }; + +protected: + LLMenuScrollItem(const Params&); + friend class LLUICtrlFactory; + +public: + /*virtual*/ void draw(); + /*virtual*/ void reshape(S32 width, S32 height, BOOL called_from_parent); + /*virtual*/ void setEnabled(BOOL enabled); + virtual void doIt( void ); + +private: + LLButton* mArrowBtn; +}; + +LLMenuScrollItem::LLMenuScrollItem(const Params& p) +: LLMenuItemCallGL(p.name, NULL/*p*/) +{ + std::string icon; + if (p.arrow_type.isProvided() && p.arrow_type == ARROW_UP) + { + icon = "arrow_up.tga"; + } + else + { + icon = "arrow_down.tga"; + } + + /* Singu TODO: LLButton::Params + LLButton::Params bparams; + + // Disabled the Return key handling by LLMenuScrollItem instead of + // passing the key press to the currently selected menu item. See STORM-385. + bparams.commit_on_return(false); + bparams.mouse_opaque(true); + bparams.scale_image(false); + bparams.click_callback(p.scroll_callback); + bparams.mouse_held_callback(p.scroll_callback); + bparams.follows.flags(FOLLOWS_ALL); + std::string background = "transparent.j2c"; + bparams.image_unselected.name(background); + bparams.image_disabled.name(background); + bparams.image_selected.name(background); + bparams.image_hover_selected.name(background); + bparams.image_disabled_selected.name(background); + bparams.image_hover_unselected.name(background); + bparams.image_overlay.name(icon); + + mArrowBtn = LLUICtrlFactory::create(bparams); + */ + const LLRect rect = getRect(); + const std::string background = "transparent.j2c"; + mArrowBtn = new LLButton("", LLRect(0, 0, rect.getWidth(), rect.getHeight()), background, background, "", NULL); + mArrowBtn->setCommitOnReturn(false); + mArrowBtn->setMouseOpaque(true); + mArrowBtn->setScaleImage(false); + mArrowBtn->setClickedCallback(p.scroll_callback); + mArrowBtn->setHeldDownCallback(p.scroll_callback); + mArrowBtn->setFollows(FOLLOWS_ALL); + mArrowBtn->setImageOverlay(icon); + addChild(mArrowBtn); +} + +/*virtual*/ +void LLMenuScrollItem::draw() +{ + LLUICtrl::draw(); +} + +/*virtual*/ +void LLMenuScrollItem::reshape(S32 width, S32 height, BOOL called_from_parent) +{ + mArrowBtn->reshape(width, height, called_from_parent); + LLView::reshape(width, height, called_from_parent); +} + +/*virtual*/ +void LLMenuScrollItem::setEnabled(BOOL enabled) +{ + mArrowBtn->setEnabled(enabled); + LLView::setEnabled(enabled); +} + +void LLMenuScrollItem::doIt( void ) +{ + LLUICtrl::onCommit(); +} + ///============================================================================ /// Class LLMenuGL ///============================================================================ @@ -1816,10 +1927,12 @@ LLMenuGL::LLMenuGL( const std::string& name, const std::string& label ) : LLUICtrl( name, LLRect(), FALSE), mBackgroundColor( sDefaultBackgroundColor ), mBgVisible( TRUE ), - mHasSelection( FALSE ), + mHasSelection(false), + mHorizontalLayout(false), + mScrollable(mHorizontalLayout ? FALSE : /*p.scrollable*/false), // Scrolling is supported only for vertical layout + mMaxScrollableItems(/*p.max_scrollable_items*/ U32_MAX), mLabel( label ), mDropShadowed( TRUE ), - mHorizontalLayout( FALSE ), mKeepFixedSize( FALSE ), mLastMouseX(0), mLastMouseY(0), @@ -1829,9 +1942,12 @@ LLMenuGL::LLMenuGL( const std::string& name, const std::string& label ) mTearOffItem(NULL), mSpilloverBranch(NULL), mFirstVisibleItem(NULL), + mArrowUpItem(NULL), + mArrowDownItem(NULL), mSpilloverMenu(NULL), mJumpKey(KEY_NONE), mNeedsArrange(FALSE), + mResetScrollPositionOnShow(true), mShortcutPad(ACCEL_PAD_PIXELS) { mFadeTimer.stop(); @@ -1842,10 +1958,12 @@ LLMenuGL::LLMenuGL( const std::string& label) : LLUICtrl( label, LLRect(), FALSE), mBackgroundColor( sDefaultBackgroundColor ), mBgVisible( TRUE ), - mHasSelection( FALSE ), + mHasSelection(false), + mHorizontalLayout(false), + mScrollable(mHorizontalLayout ? FALSE : /*p.scrollable*/false), // Scrolling is supported only for vertical layout + mMaxScrollableItems(/*p.max_scrollable_items*/ U32_MAX), mLabel( label ), mDropShadowed( TRUE ), - mHorizontalLayout( FALSE ), mKeepFixedSize( FALSE ), mLastMouseX(0), mLastMouseY(0), @@ -1856,8 +1974,11 @@ LLMenuGL::LLMenuGL( const std::string& label) mSpilloverBranch(NULL), mSpilloverMenu(NULL), mFirstVisibleItem(NULL), + mArrowUpItem(NULL), + mArrowDownItem(NULL), mJumpKey(KEY_NONE), mNeedsArrange(FALSE), + mResetScrollPositionOnShow(true), mShortcutPad(ACCEL_PAD_PIXELS) { mFadeTimer.stop(); @@ -2361,6 +2482,13 @@ LLView* LLMenuGL::fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *fa menu->parseChildXML(child, parent, factory); } + if (node->hasAttribute("scrollable")) + { + bool b; + node->getAttribute_bool("scrollable", b); + setScrollable(b); + } + if (create_jump_keys) { menu->createJumpKeys(); @@ -2369,6 +2497,117 @@ LLView* LLMenuGL::fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *fa } + +bool LLMenuGL::scrollItems(EScrollingDirection direction) +{ + // Slowing down items scrolling when arrow button is held + if (mScrollItemsTimer.hasExpired() && NULL != mFirstVisibleItem) + { + mScrollItemsTimer.setTimerExpirySec(.033f); + } + else + { + return false; + } + + switch (direction) + { + case SD_UP: + { + item_list_t::iterator cur_item_iter; + item_list_t::iterator prev_item_iter; + for (cur_item_iter = mItems.begin(), prev_item_iter = mItems.begin(); cur_item_iter != mItems.end(); cur_item_iter++) + { + if( (*cur_item_iter) == mFirstVisibleItem) + { + break; + } + if ((*cur_item_iter)->getVisible()) + { + prev_item_iter = cur_item_iter; + } + } + + if ((*prev_item_iter)->getVisible()) + { + mFirstVisibleItem = *prev_item_iter; + } + break; + } + case SD_DOWN: + { + if (NULL == mFirstVisibleItem) + { + mFirstVisibleItem = *mItems.begin(); + } + + item_list_t::iterator cur_item_iter; + + for (cur_item_iter = mItems.begin(); cur_item_iter != mItems.end(); cur_item_iter++) + { + if( (*cur_item_iter) == mFirstVisibleItem) + { + break; + } + } + + item_list_t::iterator next_item_iter; + + if (cur_item_iter != mItems.end()) + { + for (next_item_iter = ++cur_item_iter; next_item_iter != mItems.end(); next_item_iter++) + { + if( (*next_item_iter)->getVisible()) + { + break; + } + } + + if (next_item_iter != mItems.end() && + (*next_item_iter)->getVisible()) + { + mFirstVisibleItem = *next_item_iter; + } + } + break; + } + case SD_BEGIN: + { + mFirstVisibleItem = *mItems.begin(); + break; + } + case SD_END: + { + item_list_t::reverse_iterator first_visible_item_iter = mItems.rend(); + + // Need to scroll through number of actual existing items in menu. + // Otherwise viewer will hang for a time needed to scroll U32_MAX + // times in std::advance(). STORM-659. + size_t nitems = mItems.size(); + U32 scrollable_items = nitems < mMaxScrollableItems ? nitems : mMaxScrollableItems; + + // Advance by mMaxScrollableItems back from the end of the list + // to make the last item visible. + std::advance(first_visible_item_iter, scrollable_items); + mFirstVisibleItem = *first_visible_item_iter; + break; + } + default: + //LL_WARNS() << "Unknown scrolling direction: " << direction << LL_ENDL; + llwarns << "Unknown scrolling direction: " << direction << llendl; + } + + mNeedsArrange = TRUE; + arrangeAndClear(); + + return true; +} + +void LLMenuGL::setScrollable(bool b) +{ + mScrollable = b; +} + // rearrange the child rects so they fit the shape of the menu. void LLMenuGL::arrange( void ) { @@ -2402,9 +2641,10 @@ void LLMenuGL::arrange( void ) // Scrolling support item_list_t::iterator first_visible_item_iter; - //S32 height_before_first_visible_item = -1; - //S32 visible_items_height = 0; - //U32 scrollable_items_cnt = 0; + item_list_t::iterator first_hidden_item_iter = mItems.end(); + S32 height_before_first_visible_item = -1; + S32 visible_items_height = 0; + U32 scrollable_items_cnt = 0; if (mHorizontalLayout) { @@ -2452,15 +2692,16 @@ void LLMenuGL::arrange( void ) else { item_list_t::iterator item_iter; + for (item_iter = mItems.begin(); item_iter != mItems.end(); ++item_iter) { - llassert_always((*item_iter)!=NULL); // do first so LLMenuGLItemCall can call on_visible to determine if visible (*item_iter)->buildDrawLabel(); if ((*item_iter)->getVisible()) { if (!getTornOff() + && !mScrollable && *item_iter != mSpilloverBranch && height + (*item_iter)->getNominalHeight() > max_height - spillover_item_height) { @@ -2476,6 +2717,8 @@ void LLMenuGL::arrange( void ) removeChild(itemp); mSpilloverMenu->addChild(itemp); } + + addChild(mSpilloverBranch); height += mSpilloverBranch->getNominalHeight(); @@ -2489,20 +2732,170 @@ void LLMenuGL::arrange( void ) height += (*item_iter)->getNominalHeight(); width = llmax( width, (*item_iter)->getNominalWidth() ); } + + if (mScrollable) + { + // Determining visible items boundaries + if (NULL == mFirstVisibleItem) + { + mFirstVisibleItem = *item_iter; + } + + if (*item_iter == mFirstVisibleItem) + { + height_before_first_visible_item = height - (*item_iter)->getNominalHeight(); + first_visible_item_iter = item_iter; + scrollable_items_cnt = 0; + } + + if (-1 != height_before_first_visible_item && 0 == visible_items_height && + (++scrollable_items_cnt > mMaxScrollableItems || + height - height_before_first_visible_item > max_height - spillover_item_height * 2 )) + { + first_hidden_item_iter = item_iter; + visible_items_height = height - height_before_first_visible_item - (*item_iter)->getNominalHeight(); + scrollable_items_cnt--; + } + } + } + } + + if (mScrollable) + { + S32 max_items_height = max_height - spillover_item_height * 2; + + if (visible_items_height == 0) + visible_items_height = height - height_before_first_visible_item; + + // Fix mFirstVisibleItem value, if it doesn't allow to display all items, that can fit + if (visible_items_height < max_items_height && scrollable_items_cnt < mMaxScrollableItems) + { + item_list_t::iterator tmp_iter(first_visible_item_iter); + while (visible_items_height < max_items_height && + scrollable_items_cnt < mMaxScrollableItems && + first_visible_item_iter != mItems.begin()) + { + if ((*first_visible_item_iter)->getVisible()) + { + // It keeps visible item, after first_visible_item_iter + tmp_iter = first_visible_item_iter; + } + + first_visible_item_iter--; + + if ((*first_visible_item_iter)->getVisible()) + { + visible_items_height += (*first_visible_item_iter)->getNominalHeight(); + height_before_first_visible_item -= (*first_visible_item_iter)->getNominalHeight(); + scrollable_items_cnt++; + } + } + + // Roll back one item, that doesn't fit + if (visible_items_height > max_items_height) + { + visible_items_height -= (*first_visible_item_iter)->getNominalHeight(); + height_before_first_visible_item += (*first_visible_item_iter)->getNominalHeight(); + scrollable_items_cnt--; + first_visible_item_iter = tmp_iter; + } + if (!(*first_visible_item_iter)->getVisible()) + { + first_visible_item_iter = tmp_iter; + } + + mFirstVisibleItem = *first_visible_item_iter; } } } S32 cur_height = (S32)llmin(max_height, height); + + if (mScrollable && + (height_before_first_visible_item > MENU_ITEM_PADDING || + height_before_first_visible_item + visible_items_height < (S32)height)) + { + // Reserving 2 extra slots for arrow items + cur_height = visible_items_height + spillover_item_height * 2; + } + setRect(LLRect(getRect().mLeft, getRect().mTop, getRect().mLeft + width, getRect().mTop - cur_height)); S32 cur_width = 0; S32 offset = 0; + if (mScrollable) + { + // No space for all items, creating arrow items + if (height_before_first_visible_item > MENU_ITEM_PADDING || + height_before_first_visible_item + visible_items_height < (S32)height) + { + if (NULL == mArrowUpItem) + { + LLMenuScrollItem::Params item_params; + item_params.name(ARROW_UP); + item_params.arrow_type(LLMenuScrollItem::ARROW_UP); + item_params.scroll_callback.function(boost::bind(&LLMenuGL::scrollItems, this, SD_UP)); + + mArrowUpItem = LLUICtrlFactory::create(item_params); + LLUICtrl::addChild(mArrowUpItem); + + } + if (NULL == mArrowDownItem) + { + LLMenuScrollItem::Params item_params; + item_params.name(ARROW_DOWN); + item_params.arrow_type(LLMenuScrollItem::ARROW_DOWN); + item_params.scroll_callback.function(boost::bind(&LLMenuGL::scrollItems, this, SD_DOWN)); + + mArrowDownItem = LLUICtrlFactory::create(item_params); + LLUICtrl::addChild(mArrowDownItem); + } + + LLRect rect; + mArrowUpItem->setRect(rect.setLeftTopAndSize( 0, cur_height, width, mArrowUpItem->getNominalHeight())); + mArrowUpItem->setVisible(TRUE); + mArrowUpItem->setEnabled(height_before_first_visible_item > MENU_ITEM_PADDING); + mArrowUpItem->reshape(width, mArrowUpItem->getNominalHeight()); + mArrowDownItem->setRect(rect.setLeftTopAndSize( 0, mArrowDownItem->getNominalHeight(), width, mArrowDownItem->getNominalHeight())); + mArrowDownItem->setVisible(TRUE); + mArrowDownItem->setEnabled(height_before_first_visible_item + visible_items_height < (S32)height); + mArrowDownItem->reshape(width, mArrowDownItem->getNominalHeight()); + + cur_height -= mArrowUpItem->getNominalHeight(); + + offset = menu_region_rect.mRight; // This moves items behind visible area + } + else + { + if (NULL != mArrowUpItem) + { + mArrowUpItem->setVisible(FALSE); + } + if (NULL != mArrowDownItem) + { + mArrowDownItem->setVisible(FALSE); + } + } + + } + item_list_t::iterator item_iter; for (item_iter = mItems.begin(); item_iter != mItems.end(); ++item_iter) { if ((*item_iter)->getVisible()) { + if (mScrollable) + { + if (item_iter == first_visible_item_iter) + { + offset = 0; + } + else if (item_iter == first_hidden_item_iter) + { + offset = menu_region_rect.mRight; // This moves items behind visible area + } + } + // setup item rect to hold label LLRect rect; if (mHorizontalLayout) @@ -2683,6 +3076,8 @@ void LLMenuGL::empty( void ) mItems.clear(); mFirstVisibleItem = NULL; + mArrowUpItem = NULL; + mArrowDownItem = NULL; deleteAllChildren(); @@ -2899,9 +3294,36 @@ LLMenuItemGL* LLMenuGL::highlightNextItem(LLMenuItemGL* cur_item, BOOL skip_disa next_item_iter = cur_item_iter; next_item_iter++; + // First visible item position in the items list + item_list_t::iterator first_visible_item_iter = std::find(mItems.begin(), mItems.end(), mFirstVisibleItem); + if (next_item_iter == mItems.end()) { next_item_iter = mItems.begin(); + + // If current item is the last in the list, the menu is scrolled to the beginning + // and the first item is highlighted. + if (mScrollable && !scrollItems(SD_BEGIN)) + { + return NULL; + } + } + // If current item is the last visible, the menu is scrolled one item down + // and the next item is highlighted. + else if (mScrollable && + (U32)std::abs(std::distance(first_visible_item_iter, next_item_iter)) >= mMaxScrollableItems) + { + // Call highlightNextItem() recursively only if the menu was successfully scrolled down. + // If scroll timer hasn't expired yet the menu won't be scrolled and calling + // highlightNextItem() will result in an endless recursion. + if (scrollItems(SD_DOWN)) + { + return highlightNextItem(cur_item, skip_disabled); + } + else + { + return NULL; + } } } @@ -2974,9 +3396,36 @@ LLMenuItemGL* LLMenuGL::highlightPrevItem(LLMenuItemGL* cur_item, BOOL skip_disa prev_item_iter = cur_item_iter; prev_item_iter++; + // First visible item reverse position in the items list + item_list_t::reverse_iterator first_visible_item_iter = std::find(mItems.rbegin(), mItems.rend(), mFirstVisibleItem); + if (prev_item_iter == mItems.rend()) { prev_item_iter = mItems.rbegin(); + + // If current item is the first in the list, the menu is scrolled to the end + // and the last item is highlighted. + if (mScrollable && !scrollItems(SD_END)) + { + return NULL; + } + } + // If current item is the first visible, the menu is scrolled one item up + // and the previous item is highlighted. + else if (mScrollable && + std::distance(first_visible_item_iter, cur_item_iter) <= 0) + { + // Call highlightNextItem() only if the menu was successfully scrolled up. + // If scroll timer hasn't expired yet the menu won't be scrolled and calling + // highlightNextItem() will result in an endless recursion. + if (scrollItems(SD_UP)) + { + return highlightPrevItem(cur_item, skip_disabled); + } + else + { + return NULL; + } } } @@ -3141,7 +3590,21 @@ BOOL LLMenuGL::handleHover( S32 x, S32 y, MASK mask ) BOOL LLMenuGL::handleScrollWheel( S32 x, S32 y, S32 clicks ) { - return blockMouseEvent(x, y); + if (!mScrollable) + return blockMouseEvent(x, y); + + if( clicks > 0 ) + { + while( clicks-- ) + scrollItems(SD_DOWN); + } + else + { + while( clicks++ ) + scrollItems(SD_UP); + } + + return TRUE; } void LLMenuGL::draw( void ) diff --git a/indra/llui/llmenugl.h b/indra/llui/llmenugl.h index 9fd6868b7..dd4c40e53 100644 --- a/indra/llui/llmenugl.h +++ b/indra/llui/llmenugl.h @@ -453,6 +453,15 @@ public: static const std::string ARROW_UP; static const std::string ARROW_DOWN; + // for scrollable menus + typedef enum e_scrolling_direction + { + SD_UP = 0, + SD_DOWN = 1, + SD_BEGIN = 2, + SD_END = 3 + } EScrollingDirection; + protected: // let branching menu items use my protected traversal methods friend class LLMenuItemBranchGL; @@ -566,15 +575,18 @@ public: static BOOL getKeyboardMode() { return sKeyboardMode; } S32 getShortcutPad() { return mShortcutPad; } - BOOL isScrollable() const { return FALSE; } + + bool scrollItems(EScrollingDirection direction); + BOOL isScrollable() const { return mScrollable; } + void setScrollable(bool b); static class LLMenuHolderGL* sMenuContainer; - bool isScrollPositionOnShowReset() { return false; } + void resetScrollPositionOnShow(bool reset_scroll_pos) { mResetScrollPositionOnShow = reset_scroll_pos; } + bool isScrollPositionOnShowReset() { return mResetScrollPositionOnShow; } protected: void createSpilloverBranch(); void cleanupSpilloverBranch(); - // Add the menu item to this menu. virtual BOOL append( LLMenuItemGL* item ); BOOL append(LLMenuItemGL* item, LLView* insert_before); @@ -587,6 +599,7 @@ protected: typedef std::list< LLMenuItemGL* > item_list_t; item_list_t mItems; LLMenuItemGL*mFirstVisibleItem; + LLMenuItemGL *mArrowUpItem, *mArrowDownItem; typedef std::map navigation_key_map_t; navigation_key_map_t mJumpKeys; @@ -594,11 +607,15 @@ protected: S32 mLastMouseY; S32 mMouseVelX; S32 mMouseVelY; + U32 mMaxScrollableItems; BOOL mHorizontalLayout; + BOOL mScrollable; BOOL mKeepFixedSize; BOOL mNeedsArrange; private: + + static LLColor4 sDefaultBackgroundColor; static BOOL sKeyboardMode; @@ -609,12 +626,14 @@ private: BOOL mDropShadowed; // Whether to drop shadow bool mHasSelection; LLFrameTimer mFadeTimer; + LLTimer mScrollItemsTimer; BOOL mTornOff; class LLMenuItemTearOffGL* mTearOffItem; class LLMenuItemBranchGL* mSpilloverBranch; LLMenuGL* mSpilloverMenu; KEY mJumpKey; S32 mShortcutPad; + bool mResetScrollPositionOnShow; }; // end class LLMenuGL