diff options
Diffstat (limited to 'indra/llui/llmenubutton.cpp')
-rwxr-xr-x[-rw-r--r--] | indra/llui/llmenubutton.cpp | 223 |
1 files changed, 159 insertions, 64 deletions
diff --git a/indra/llui/llmenubutton.cpp b/indra/llui/llmenubutton.cpp index cdbd17e4dc..303afcda15 100644..100755 --- a/indra/llui/llmenubutton.cpp +++ b/indra/llui/llmenubutton.cpp @@ -2,31 +2,25 @@ * @file llbutton.cpp * @brief LLButton base class * - * $LicenseInfo:firstyear=2001&license=viewergpl$ - * - * Copyright (c) 2001-2009, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -35,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; } @@ -110,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(); + } +} |