diff options
Diffstat (limited to 'indra/llui')
-rw-r--r-- | indra/llui/llmenubutton.cpp | 108 | ||||
-rw-r--r-- | indra/llui/llmenubutton.h | 26 | ||||
-rw-r--r-- | indra/llui/llmenugl.cpp | 205 | ||||
-rw-r--r-- | indra/llui/llmenugl.h | 12 | ||||
-rw-r--r-- | indra/llui/lltextbase.cpp | 2 |
5 files changed, 235 insertions, 118 deletions
diff --git a/indra/llui/llmenubutton.cpp b/indra/llui/llmenubutton.cpp index 3df05f4d3f..c1b5efaa72 100644 --- a/indra/llui/llmenubutton.cpp +++ b/indra/llui/llmenubutton.cpp @@ -45,7 +45,8 @@ LLMenuButton::Params::Params() LLMenuButton::LLMenuButton(const LLMenuButton::Params& p) : LLButton(p), mMenu(NULL), - mMenuVisibleLastFrame(false) + mMenuVisibleLastFrame(false), + mMenuPosition(MP_BOTTOM_LEFT) { std::string menu_filename = p.menu_filename; @@ -57,38 +58,51 @@ LLMenuButton::LLMenuButton(const LLMenuButton::Params& p) llwarns << "Error loading menu_button menu" << llendl; } } + + updateMenuOrigin(); } -void LLMenuButton::toggleMenu() +boost::signals2::connection LLMenuButton::setMouseDownCallback( const mouse_signal_t::slot_type& cb ) { - if(!mMenu) - return; + return LLUICtrl::setMouseDownCallback(cb); +} - if (mMenu->getVisible() || mMenuVisibleLastFrame) - { - mMenu->setVisible(FALSE); - } - else +void LLMenuButton::hideMenu() +{ + if(!mMenu) return; + mMenu->setVisible(FALSE); +} + +void LLMenuButton::setMenu(LLMenuGL* menu, EMenuPosition position /*MP_TOP_LEFT*/) +{ + mMenu = menu; + mMenuPosition = position; +} + +void LLMenuButton::draw() +{ + //we save this off so next frame when we try to close it by + //button click, and it hides menus before we get to it, we know + mMenuVisibleLastFrame = mMenu && mMenu->getVisible(); + + if (mMenuVisibleLastFrame) { - LLRect rect = getRect(); - //mMenu->needsArrange(); //so it recalculates the visible elements - LLMenuGL::showPopup(getParent(), mMenu, rect.mLeft, rect.mBottom); + setForcePressedState(true); } -} + LLButton::draw(); -void LLMenuButton::hideMenu() -{ - if(!mMenu) - return; - mMenu->setVisible(FALSE); + setForcePressedState(false); } - BOOL LLMenuButton::handleKeyHere(KEY key, MASK mask ) { if( KEY_RETURN == key && mask == MASK_NONE && !gKeyboard->getKeyRepeated(key)) { + // *HACK: We emit the mouse down signal to fire the callback bound to the + // menu emerging event before actually displaying the menu. See STORM-263. + LLUICtrl::handleMouseDown(-1, -1, MASK_NONE); + toggleMenu(); return TRUE; } @@ -104,34 +118,52 @@ BOOL LLMenuButton::handleKeyHere(KEY key, MASK mask ) BOOL LLMenuButton::handleMouseDown(S32 x, S32 y, MASK mask) { - if (hasTabStop() && !getIsChrome()) - { - setFocus(TRUE); - } - + LLButton::handleMouseDown(x, y, mask); toggleMenu(); - if (getSoundFlags() & MOUSE_DOWN) - { - make_ui_sound("UISndClick"); - } - return TRUE; } -void LLMenuButton::draw() +void LLMenuButton::toggleMenu() { - //we save this off so next frame when we try to close it by - //button click, and it hides menus before we get to it, we know - mMenuVisibleLastFrame = mMenu && mMenu->getVisible(); - - if (mMenuVisibleLastFrame) + if(!mMenu) return; + + if (mMenu->getVisible() || mMenuVisibleLastFrame) { - setForcePressedState(true); + mMenu->setVisible(FALSE); } + else + { + mMenu->buildDrawLabels(); + mMenu->arrangeAndClear(); + mMenu->updateParent(LLMenuGL::sMenuContainer); - LLButton::draw(); + updateMenuOrigin(); - setForcePressedState(false); + //mMenu->needsArrange(); //so it recalculates the visible elements + LLMenuGL::showPopup(getParent(), mMenu, mX, mY); + } } +void LLMenuButton::updateMenuOrigin() +{ + if (!mMenu) return; + + LLRect rect = getRect(); + + switch (mMenuPosition) + { + case MP_TOP_LEFT: + { + mX = rect.mLeft; + mY = rect.mTop + mMenu->getRect().getHeight(); + break; + } + case MP_BOTTOM_LEFT: + { + mX = rect.mLeft; + mY = rect.mBottom; + break; + } + } +} diff --git a/indra/llui/llmenubutton.h b/indra/llui/llmenubutton.h index 81ca0e047c..81c3592b16 100644 --- a/indra/llui/llmenubutton.h +++ b/indra/llui/llmenubutton.h @@ -42,22 +42,40 @@ public: Optional<std::string> menu_filename; Params(); - }; + }; + + typedef enum e_menu_position + { + MP_TOP_LEFT, + MP_BOTTOM_LEFT + } EMenuPosition; - void toggleMenu(); + boost::signals2::connection setMouseDownCallback( const mouse_signal_t::slot_type& cb ); + /*virtual*/ void draw(); /*virtual*/ BOOL handleMouseDown(S32 x, S32 y, MASK mask); /*virtual*/ BOOL handleKeyHere(KEY key, MASK mask ); + void hideMenu(); + LLMenuGL* getMenu() { return mMenu; } + void setMenu(LLMenuGL* menu, EMenuPosition position = MP_TOP_LEFT); + + void setMenuPosition(EMenuPosition position) { mMenuPosition = position; } protected: friend class LLUICtrlFactory; LLMenuButton(const Params&); + void toggleMenu(); + void updateMenuOrigin(); + private: - LLMenuGL* mMenu; - bool mMenuVisibleLastFrame; + LLMenuGL* mMenu; + bool mMenuVisibleLastFrame; + EMenuPosition mMenuPosition; + S32 mX; + S32 mY; }; diff --git a/indra/llui/llmenugl.cpp b/indra/llui/llmenugl.cpp index 6d590cf54e..a6cf86d9b8 100644 --- a/indra/llui/llmenugl.cpp +++ b/indra/llui/llmenugl.cpp @@ -1848,89 +1848,104 @@ BOOL LLMenuGL::isOpen() } } -void LLMenuGL::scrollItemsUp() + + +bool LLMenuGL::scrollItems(EScrollingDirection direction) { - // Slowing down the items scrolling when arrow button is held + // Slowing down items scrolling when arrow button is held if (mScrollItemsTimer.hasExpired() && NULL != mFirstVisibleItem) { mScrollItemsTimer.setTimerExpirySec(.033f); } else { - return; + return false; } - 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++) + switch (direction) { - if( (*cur_item_iter) == mFirstVisibleItem) + 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++) { - break; + if( (*cur_item_iter) == mFirstVisibleItem) + { + break; + } + if ((*cur_item_iter)->getVisible()) + { + prev_item_iter = cur_item_iter; + } } - if ((*cur_item_iter)->getVisible()) + + if ((*prev_item_iter)->getVisible()) { - prev_item_iter = cur_item_iter; + mFirstVisibleItem = *prev_item_iter; } + break; } - - if ((*prev_item_iter)->getVisible()) - { - mFirstVisibleItem = *prev_item_iter; - } - - mNeedsArrange = TRUE; - arrangeAndClear(); -} - -void LLMenuGL::scrollItemsDown() -{ - // Slowing down the items scrolling when arrow button is held - if (mScrollItemsTimer.hasExpired()) - { - mScrollItemsTimer.setTimerExpirySec(.033f); - } - else - { - return; - } - - 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++) + case SD_DOWN: { - if( (*cur_item_iter) == mFirstVisibleItem) + if (NULL == mFirstVisibleItem) { - break; + mFirstVisibleItem = *mItems.begin(); } - } - item_list_t::iterator next_item_iter; + item_list_t::iterator cur_item_iter; - if (cur_item_iter != mItems.end()) - { - for (next_item_iter = ++cur_item_iter; next_item_iter != mItems.end(); next_item_iter++) + for (cur_item_iter = mItems.begin(); cur_item_iter != mItems.end(); cur_item_iter++) { - if( (*next_item_iter)->getVisible()) + if( (*cur_item_iter) == mFirstVisibleItem) { break; } } - - if (next_item_iter != mItems.end() && - (*next_item_iter)->getVisible()) + + item_list_t::iterator next_item_iter; + + if (cur_item_iter != mItems.end()) { - mFirstVisibleItem = *next_item_iter; + 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(); + + // Advance by mMaxScrollableItems back from the end of the list + // to make the last item visible. + std::advance(first_visible_item_iter, mMaxScrollableItems); + mFirstVisibleItem = *first_visible_item_iter; + break; + } + default: + llwarns << "Unknown scrolling direction: " << direction << llendl; + } + mNeedsArrange = TRUE; arrangeAndClear(); + + return true; } // rearrange the child rects so they fit the shape of the menu. @@ -2162,7 +2177,7 @@ void LLMenuGL::arrange( void ) LLMenuScrollItem::Params item_params; item_params.name(ARROW_UP); item_params.arrow_type(LLMenuScrollItem::ARROW_UP); - item_params.scroll_callback.function(boost::bind(&LLMenuGL::scrollItemsUp, this)); + item_params.scroll_callback.function(boost::bind(&LLMenuGL::scrollItems, this, SD_UP)); mArrowUpItem = LLUICtrlFactory::create<LLMenuScrollItem>(item_params); LLUICtrl::addChild(mArrowUpItem); @@ -2173,7 +2188,7 @@ void LLMenuGL::arrange( void ) LLMenuScrollItem::Params item_params; item_params.name(ARROW_DOWN); item_params.arrow_type(LLMenuScrollItem::ARROW_DOWN); - item_params.scroll_callback.function(boost::bind(&LLMenuGL::scrollItemsDown, this)); + item_params.scroll_callback.function(boost::bind(&LLMenuGL::scrollItems, this, SD_DOWN)); mArrowDownItem = LLUICtrlFactory::create<LLMenuScrollItem>(item_params); LLUICtrl::addChild(mArrowDownItem); @@ -2603,14 +2618,8 @@ LLMenuItemGL* LLMenuGL::highlightNextItem(LLMenuItemGL* cur_item, BOOL skip_disa ((LLFloater*)getParent())->setFocus(TRUE); } - 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) == cur_item) - { - break; - } - } + // Current item position in the items list + item_list_t::iterator cur_item_iter = std::find(mItems.begin(), mItems.end(), cur_item); item_list_t::iterator next_item_iter; if (cur_item_iter == mItems.end()) @@ -2621,9 +2630,37 @@ 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; + } } } @@ -2681,14 +2718,8 @@ LLMenuItemGL* LLMenuGL::highlightPrevItem(LLMenuItemGL* cur_item, BOOL skip_disa ((LLFloater*)getParent())->setFocus(TRUE); } - item_list_t::reverse_iterator cur_item_iter; - for (cur_item_iter = mItems.rbegin(); cur_item_iter != mItems.rend(); ++cur_item_iter) - { - if( (*cur_item_iter) == cur_item) - { - break; - } - } + // Current item reverse position from the end of the list + item_list_t::reverse_iterator cur_item_iter = std::find(mItems.rbegin(), mItems.rend(), cur_item); item_list_t::reverse_iterator prev_item_iter; if (cur_item_iter == mItems.rend()) @@ -2699,9 +2730,37 @@ 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; + } } } @@ -2872,12 +2931,12 @@ BOOL LLMenuGL::handleScrollWheel( S32 x, S32 y, S32 clicks ) if( clicks > 0 ) { while( clicks-- ) - scrollItemsDown(); + scrollItems(SD_DOWN); } else { while( clicks++ ) - scrollItemsUp(); + scrollItems(SD_UP); } return TRUE; diff --git a/indra/llui/llmenugl.h b/indra/llui/llmenugl.h index 19b738312e..35544402f4 100644 --- a/indra/llui/llmenugl.h +++ b/indra/llui/llmenugl.h @@ -397,6 +397,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: LLMenuGL(const LLMenuGL::Params& p); friend class LLUICtrlFactory; @@ -503,8 +512,7 @@ public: S32 getShortcutPad() { return mShortcutPad; } - void scrollItemsUp(); - void scrollItemsDown(); + bool scrollItems(EScrollingDirection direction); BOOL isScrollable() const { return mScrollable; } static class LLMenuHolderGL* sMenuContainer; diff --git a/indra/llui/lltextbase.cpp b/indra/llui/lltextbase.cpp index 9adeddca99..758df418e8 100644 --- a/indra/llui/lltextbase.cpp +++ b/indra/llui/lltextbase.cpp @@ -1622,7 +1622,7 @@ void LLTextBase::appendTextImpl(const std::string &new_text, const LLStyle::Para style_params.fillFrom(getDefaultStyleParams()); S32 part = (S32)LLTextParser::WHOLE; - if(mParseHTML) + if (mParseHTML && !style_params.is_link) // Don't search for URLs inside a link segment (STORM-358). { S32 start=0,end=0; LLUrlMatch match; |