summaryrefslogtreecommitdiff
path: root/indra/llui/llmenubutton.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'indra/llui/llmenubutton.cpp')
-rwxr-xr-x[-rw-r--r--]indra/llui/llmenubutton.cpp187
1 files changed, 144 insertions, 43 deletions
diff --git a/indra/llui/llmenubutton.cpp b/indra/llui/llmenubutton.cpp
index 3df05f4d3f..303afcda15 100644..100755
--- a/indra/llui/llmenubutton.cpp
+++ b/indra/llui/llmenubutton.cpp
@@ -29,73 +29,112 @@
#include "llmenubutton.h"
// Linden library includes
-#include "llmenugl.h"
+#include "lltoggleablemenu.h"
#include "llstring.h"
#include "v4color.h"
static LLDefaultChildRegistry::Register<LLMenuButton> r("menu_button");
+void LLMenuButton::MenuPositions::declareValues()
+{
+ declare("topleft", MP_TOP_LEFT);
+ declare("topright", MP_TOP_RIGHT);
+ declare("bottomleft", MP_BOTTOM_LEFT);
+}
LLMenuButton::Params::Params()
-: menu_filename("menu_filename")
+: menu_filename("menu_filename"),
+ position("menu_position", MP_BOTTOM_LEFT)
{
+ addSynonym(position, "position");
}
LLMenuButton::LLMenuButton(const LLMenuButton::Params& p)
: LLButton(p),
- mMenu(NULL),
- mMenuVisibleLastFrame(false)
+ mIsMenuShown(false),
+ mMenuPosition(p.position),
+ mOwnMenu(false)
{
std::string menu_filename = p.menu_filename;
- if (!menu_filename.empty())
+ setMenu(menu_filename, mMenuPosition);
+ updateMenuOrigin();
+}
+
+LLMenuButton::~LLMenuButton()
+{
+ cleanup();
+}
+
+boost::signals2::connection LLMenuButton::setMouseDownCallback( const mouse_signal_t::slot_type& cb )
+{
+ return LLUICtrl::setMouseDownCallback(cb);
+}
+
+void LLMenuButton::hideMenu()
+{
+ LLToggleableMenu* menu = getMenu();
+ if (menu)
{
- mMenu = LLUICtrlFactory::getInstance()->createFromFile<LLMenuGL>(menu_filename, LLMenuGL::sMenuContainer, LLMenuHolderGL::child_registry_t::instance());
- if (!mMenu)
- {
- llwarns << "Error loading menu_button menu" << llendl;
- }
+ menu->setVisible(FALSE);
}
}
-void LLMenuButton::toggleMenu()
+LLToggleableMenu* LLMenuButton::getMenu()
{
- if(!mMenu)
- return;
+ return dynamic_cast<LLToggleableMenu*>(mMenuHandle.get());
+}
- if (mMenu->getVisible() || mMenuVisibleLastFrame)
+void LLMenuButton::setMenu(const std::string& menu_filename, EMenuPosition position /*MP_TOP_LEFT*/)
+{
+ if (menu_filename.empty())
{
- mMenu->setVisible(FALSE);
+ return;
}
- else
+
+ llassert(LLMenuGL::sMenuContainer != NULL);
+ LLToggleableMenu* menu = LLUICtrlFactory::getInstance()->createFromFile<LLToggleableMenu>(menu_filename, LLMenuGL::sMenuContainer, LLMenuHolderGL::child_registry_t::instance());
+ if (!menu)
{
- LLRect rect = getRect();
- //mMenu->needsArrange(); //so it recalculates the visible elements
- LLMenuGL::showPopup(getParent(), mMenu, rect.mLeft, rect.mBottom);
+ LL_WARNS() << "Error loading menu_button menu" << LL_ENDL;
+ return;
}
+
+ setMenu(menu, position, true);
}
+void LLMenuButton::setMenu(LLToggleableMenu* menu, EMenuPosition position /*MP_TOP_LEFT*/, bool take_ownership /*false*/)
+{
+ if (!menu) return;
-void LLMenuButton::hideMenu()
-{
- if(!mMenu)
- return;
- mMenu->setVisible(FALSE);
-}
+ cleanup(); // destroy the previous memnu if we own it
+ mMenuHandle = menu->getHandle();
+ mMenuPosition = position;
+ mOwnMenu = take_ownership;
+
+ menu->setVisibilityChangeCallback(boost::bind(&LLMenuButton::onMenuVisibilityChange, this, _2));
+}
BOOL LLMenuButton::handleKeyHere(KEY key, MASK mask )
{
+ if (!getMenu()) 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 = getMenu();
+ if (menu && menu->getVisible() && key == KEY_ESCAPE && mask == MASK_NONE)
{
- mMenu->setVisible(FALSE);
+ menu->setVisible(FALSE);
return TRUE;
}
@@ -104,34 +143,96 @@ 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)
+ return TRUE;
+}
+
+void LLMenuButton::toggleMenu()
+{
+ if (mValidateSignal && !(*mValidateSignal)(this, LLSD()))
{
- make_ui_sound("UISndClick");
+ return;
}
- return TRUE;
+ LLToggleableMenu* menu = getMenu();
+ 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::draw()
+void LLMenuButton::updateMenuOrigin()
{
- //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)
+ LLToggleableMenu* menu = getMenu();
+ if (!menu) return;
+
+ LLRect rect = getRect();
+
+ switch (mMenuPosition)
{
- setForcePressedState(true);
+ case MP_TOP_LEFT:
+ {
+ mX = rect.mLeft;
+ mY = rect.mTop + menu->getRect().getHeight();
+ break;
+ }
+ case MP_TOP_RIGHT:
+ {
+ const LLRect& menu_rect = menu->getRect();
+ mX = rect.mRight - menu_rect.getWidth();
+ mY = rect.mTop + menu_rect.getHeight();
+ break;
+ }
+ case MP_BOTTOM_LEFT:
+ {
+ mX = rect.mLeft;
+ mY = rect.mBottom;
+ break;
+ }
}
+}
- LLButton::draw();
+void LLMenuButton::onMenuVisibilityChange(const LLSD& param)
+{
+ bool new_visibility = param["visibility"].asBoolean();
+ bool is_closed_by_button_click = param["closed_by_button_click"].asBoolean();
- setForcePressedState(false);
+ // 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;
+ }
}
+void LLMenuButton::cleanup()
+{
+ if (mMenuHandle.get() && mOwnMenu)
+ {
+ mMenuHandle.get()->die();
+ }
+}