summaryrefslogtreecommitdiff
path: root/indra/llui
diff options
context:
space:
mode:
Diffstat (limited to 'indra/llui')
-rw-r--r--indra/llui/llmenubutton.cpp108
-rw-r--r--indra/llui/llmenubutton.h26
-rw-r--r--indra/llui/llmenugl.cpp205
-rw-r--r--indra/llui/llmenugl.h12
-rw-r--r--indra/llui/lltextbase.cpp2
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;