summaryrefslogtreecommitdiff
path: root/indra/llui
diff options
context:
space:
mode:
Diffstat (limited to 'indra/llui')
-rw-r--r--indra/llui/llmenubutton.cpp144
-rw-r--r--indra/llui/llmenubutton.h33
-rw-r--r--indra/llui/lltextbase.cpp2
-rw-r--r--indra/llui/lltoggleablemenu.cpp18
-rw-r--r--indra/llui/lltoggleablemenu.h5
-rw-r--r--indra/llui/llurlentry.cpp2
6 files changed, 154 insertions, 50 deletions
diff --git a/indra/llui/llmenubutton.cpp b/indra/llui/llmenubutton.cpp
index 3df05f4d3f..ac568a83e4 100644
--- a/indra/llui/llmenubutton.cpp
+++ b/indra/llui/llmenubutton.cpp
@@ -29,7 +29,7 @@
#include "llmenubutton.h"
// Linden library includes
-#include "llmenugl.h"
+#include "lltoggleablemenu.h"
#include "llstring.h"
#include "v4color.h"
@@ -44,58 +44,77 @@ LLMenuButton::Params::Params()
LLMenuButton::LLMenuButton(const LLMenuButton::Params& p)
: LLButton(p),
- mMenu(NULL),
- mMenuVisibleLastFrame(false)
+ mIsMenuShown(false),
+ mMenuPosition(MP_BOTTOM_LEFT)
{
std::string menu_filename = p.menu_filename;
if (!menu_filename.empty())
{
- mMenu = LLUICtrlFactory::getInstance()->createFromFile<LLMenuGL>(menu_filename, LLMenuGL::sMenuContainer, LLMenuHolderGL::child_registry_t::instance());
- if (!mMenu)
+ LLToggleableMenu* menu = LLUICtrlFactory::getInstance()->createFromFile<LLToggleableMenu>(menu_filename, LLMenuGL::sMenuContainer, LLMenuHolderGL::child_registry_t::instance());
+ if (!menu)
{
llwarns << "Error loading menu_button menu" << llendl;
+ return;
}
+
+ menu->setVisibilityChangeCallback(boost::bind(&LLMenuButton::onMenuVisibilityChange, this, _2));
+
+ mMenuHandle = menu->getHandle();
+
+ 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(mMenuHandle.isDead()) return;
+
+ LLToggleableMenu* menu = dynamic_cast<LLToggleableMenu*>(mMenuHandle.get());
+ if (menu)
{
- LLRect rect = getRect();
- //mMenu->needsArrange(); //so it recalculates the visible elements
- LLMenuGL::showPopup(getParent(), mMenu, rect.mLeft, rect.mBottom);
+ menu->setVisible(FALSE);
}
}
-
-void LLMenuButton::hideMenu()
-{
- if(!mMenu)
- return;
- mMenu->setVisible(FALSE);
+LLToggleableMenu* LLMenuButton::getMenu()
+{
+ return dynamic_cast<LLToggleableMenu*>(mMenuHandle.get());
}
+void LLMenuButton::setMenu(LLToggleableMenu* menu, EMenuPosition position /*MP_TOP_LEFT*/)
+{
+ if (!menu) return;
+
+ mMenuHandle = menu->getHandle();
+ mMenuPosition = position;
+
+ menu->setVisibilityChangeCallback(boost::bind(&LLMenuButton::onMenuVisibilityChange, this, _2));
+}
BOOL LLMenuButton::handleKeyHere(KEY key, MASK mask )
{
+ if (mMenuHandle.isDead()) return FALSE;
+
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;
}
- if (mMenu && mMenu->getVisible() && key == KEY_ESCAPE && mask == MASK_NONE)
+ LLToggleableMenu* menu = dynamic_cast<LLToggleableMenu*>(mMenuHandle.get());
+ if (menu && menu->getVisible() && key == KEY_ESCAPE && mask == MASK_NONE)
{
- mMenu->setVisible(FALSE);
+ menu->setVisible(FALSE);
return TRUE;
}
@@ -104,34 +123,77 @@ 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(mMenuHandle.isDead()) return;
+
+ LLToggleableMenu* menu = dynamic_cast<LLToggleableMenu*>(mMenuHandle.get());
+ if (!menu) return;
+
+ // Store the button rectangle to toggle menu visibility if a mouse event
+ // occurred inside or outside the button rect.
+ menu->setButtonRect(this);
+
+ if (!menu->toggleVisibility() && mIsMenuShown)
+ {
+ setForcePressedState(false);
+ mIsMenuShown = false;
+ }
+ else
{
+ menu->buildDrawLabels();
+ menu->arrangeAndClear();
+ menu->updateParent(LLMenuGL::sMenuContainer);
+
+ updateMenuOrigin();
+
+ LLMenuGL::showPopup(getParent(), menu, mX, mY);
+
setForcePressedState(true);
+ mIsMenuShown = true;
}
+}
+
+void LLMenuButton::updateMenuOrigin()
+{
+ if (mMenuHandle.isDead()) return;
- LLButton::draw();
+ LLRect rect = getRect();
- setForcePressedState(false);
+ switch (mMenuPosition)
+ {
+ case MP_TOP_LEFT:
+ {
+ mX = rect.mLeft;
+ mY = rect.mTop + mMenuHandle.get()->getRect().getHeight();
+ break;
+ }
+ case MP_BOTTOM_LEFT:
+ {
+ mX = rect.mLeft;
+ mY = rect.mBottom;
+ break;
+ }
+ }
}
+void LLMenuButton::onMenuVisibilityChange(const LLSD& param)
+{
+ bool new_visibility = param["visibility"].asBoolean();
+ bool is_closed_by_button_click = param["closed_by_button_click"].asBoolean();
+
+ // Reset the button "pressed" state only if the menu is shown by this particular
+ // menu button (not any other control) and is not being closed by a click on the button.
+ if (!new_visibility && !is_closed_by_button_click && mIsMenuShown)
+ {
+ setForcePressedState(false);
+ mIsMenuShown = false;
+ }
+}
diff --git a/indra/llui/llmenubutton.h b/indra/llui/llmenubutton.h
index 81ca0e047c..9e91b9e99d 100644
--- a/indra/llui/llmenubutton.h
+++ b/indra/llui/llmenubutton.h
@@ -29,7 +29,7 @@
#include "llbutton.h"
-class LLMenuGL;
+class LLToggleableMenu;
class LLMenuButton
: public LLButton
@@ -42,22 +42,41 @@ public:
Optional<std::string> menu_filename;
Params();
- };
+ };
+
+ typedef enum e_menu_position
+ {
+ MP_TOP_LEFT,
+ MP_BOTTOM_LEFT
+ } EMenuPosition;
- void toggleMenu();
- /*virtual*/ void draw();
+ boost::signals2::connection setMouseDownCallback( const mouse_signal_t::slot_type& cb );
+
/*virtual*/ BOOL handleMouseDown(S32 x, S32 y, MASK mask);
/*virtual*/ BOOL handleKeyHere(KEY key, MASK mask );
+
void hideMenu();
- LLMenuGL* getMenu() { return mMenu; }
+
+ LLToggleableMenu* getMenu();
+ void setMenu(LLToggleableMenu* menu, EMenuPosition position = MP_TOP_LEFT);
+
+ void setMenuPosition(EMenuPosition position) { mMenuPosition = position; }
protected:
friend class LLUICtrlFactory;
LLMenuButton(const Params&);
+ void toggleMenu();
+ void updateMenuOrigin();
+
+ void onMenuVisibilityChange(const LLSD& param);
+
private:
- LLMenuGL* mMenu;
- bool mMenuVisibleLastFrame;
+ LLHandle<LLView> mMenuHandle;
+ bool mIsMenuShown;
+ EMenuPosition mMenuPosition;
+ S32 mX;
+ S32 mY;
};
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;
diff --git a/indra/llui/lltoggleablemenu.cpp b/indra/llui/lltoggleablemenu.cpp
index 0eb2dc1387..d29260750f 100644
--- a/indra/llui/lltoggleablemenu.cpp
+++ b/indra/llui/lltoggleablemenu.cpp
@@ -35,10 +35,22 @@ static LLDefaultChildRegistry::Register<LLToggleableMenu> r("toggleable_menu");
LLToggleableMenu::LLToggleableMenu(const LLToggleableMenu::Params& p)
: LLMenuGL(p),
mButtonRect(),
+ mVisibilityChangeSignal(NULL),
mClosedByButtonClick(false)
{
}
+LLToggleableMenu::~LLToggleableMenu()
+{
+ delete mVisibilityChangeSignal;
+}
+
+boost::signals2::connection LLToggleableMenu::setVisibilityChangeCallback(const commit_signal_t::slot_type& cb)
+{
+ if (!mVisibilityChangeSignal) mVisibilityChangeSignal = new commit_signal_t();
+ return mVisibilityChangeSignal->connect(cb);
+}
+
// virtual
void LLToggleableMenu::handleVisibilityChange (BOOL curVisibilityIn)
{
@@ -49,6 +61,12 @@ void LLToggleableMenu::handleVisibilityChange (BOOL curVisibilityIn)
{
mClosedByButtonClick = true;
}
+
+ if (mVisibilityChangeSignal)
+ {
+ (*mVisibilityChangeSignal)(this,
+ LLSD().with("visibility", curVisibilityIn).with("closed_by_button_click", mClosedByButtonClick));
+ }
}
void LLToggleableMenu::setButtonRect(const LLRect& rect, LLView* current_view)
diff --git a/indra/llui/lltoggleablemenu.h b/indra/llui/lltoggleablemenu.h
index f036cdfffb..2094bd776f 100644
--- a/indra/llui/lltoggleablemenu.h
+++ b/indra/llui/lltoggleablemenu.h
@@ -41,6 +41,10 @@ protected:
LLToggleableMenu(const Params&);
friend class LLUICtrlFactory;
public:
+ ~LLToggleableMenu();
+
+ boost::signals2::connection setVisibilityChangeCallback( const commit_signal_t::slot_type& cb );
+
virtual void handleVisibilityChange (BOOL curVisibilityIn);
const LLRect& getButtonRect() const { return mButtonRect; }
@@ -57,6 +61,7 @@ public:
protected:
bool mClosedByButtonClick;
LLRect mButtonRect;
+ commit_signal_t* mVisibilityChangeSignal;
};
#endif // LL_LLTOGGLEABLEMENU_H
diff --git a/indra/llui/llurlentry.cpp b/indra/llui/llurlentry.cpp
index f58c07754f..f49dfec82b 100644
--- a/indra/llui/llurlentry.cpp
+++ b/indra/llui/llurlentry.cpp
@@ -972,7 +972,7 @@ std::string LLUrlEntryWorldMap::getLocation(const std::string &url) const
//
LLUrlEntryNoLink::LLUrlEntryNoLink()
{
- mPattern = boost::regex("<nolink>[^<]*</nolink>",
+ mPattern = boost::regex("<nolink>.*</nolink>",
boost::regex::perl|boost::regex::icase);
}