diff options
Diffstat (limited to 'indra/llui/llmenubutton.cpp')
-rwxr-xr-x[-rw-r--r--] | indra/llui/llmenubutton.cpp | 187 |
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(); + } +} |